#include "nemu.h"
#include <stdlib.h>
#include <time.h>

CPU_state cpu;

const char *regsl[] = {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"};
const char *regsw[] = {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"};
const char *regsb[] = {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"};

struct rcpu_bootstrap_check {
  static_assert(sizeof(rtlreg_t) == sizeof(uint32_t));
  static_assert(sizeof(vaddr_t) == sizeof(uint32_t));

  rcpu_bootstrap_check() {
    /* https://www.agner.org/optimize/calling_conventions.pdf
      Direction flag
      The rules for the direction flag is the same in all systems. The direction flag 
      is cleared by default. If the direction flag is set, then it must be cleared again
      before any call or return. Some compilers and subroutine libraries rely on the 
      direction flag always being clear (Microsoft, Watcom, Digital Mars) while other 
      systems use the double-safe strategy of always leaving the direction flag cleared, 
      but not relying on receiving it cleared (Borland, Gnu).
    */
    cpu_eflags::get<cpu_eflags::DF>() = false;
    printf("R-CPU bootstrap %s finished.\n", __FILE__);
  }
};
rcpu_bootstrap_check rcpu_bootstrap_check_instance;

void reg_test() {
  srand(time(0));
  uint32_t sample[8];
  uint32_t eip_sample = rand();
  cpu.eip = eip_sample;

  int i;
  for (i = R_EAX; i <= R_EDI; i ++) {
    sample[i] = rand();
    reg_l(i) = sample[i];
    assert(reg_w(i) == (sample[i] & 0xffff));
  }

  assert(reg_b(R_AL) == (sample[R_EAX] & 0xff));
  assert(reg_b(R_AH) == ((sample[R_EAX] >> 8) & 0xff));
  assert(reg_b(R_BL) == (sample[R_EBX] & 0xff));
  assert(reg_b(R_BH) == ((sample[R_EBX] >> 8) & 0xff));
  assert(reg_b(R_CL) == (sample[R_ECX] & 0xff));
  assert(reg_b(R_CH) == ((sample[R_ECX] >> 8) & 0xff));
  assert(reg_b(R_DL) == (sample[R_EDX] & 0xff));
  assert(reg_b(R_DH) == ((sample[R_EDX] >> 8) & 0xff));

  assert(sample[R_EAX] == cpu.eax);
  assert(sample[R_ECX] == cpu.ecx);
  assert(sample[R_EDX] == cpu.edx);
  assert(sample[R_EBX] == cpu.ebx);
  assert(sample[R_ESP] == cpu.esp);
  assert(sample[R_EBP] == cpu.ebp);
  assert(sample[R_ESI] == cpu.esi);
  assert(sample[R_EDI] == cpu.edi);

  assert(eip_sample == cpu.eip);
}
