old-computer-simulator

godot game
git clone git://git.evenfri.pw/old-computer-simulator.git
Log | Files | Refs

main.c (8508B)


      1 #include "emu.h"
      2 
      3 static void set_zsp(emu_t *e, uint8_t res) {
      4   FLAG_PUT(e, F_Z, res == 0);
      5   FLAG_PUT(e, F_S, (res & 0x80) != 0);
      6   FLAG_PUT(e, F_P, parity_even(res));
      7 }
      8 
      9 uint8_t emu_set(emu_t *e, uint8_t r, uint8_t v) {
     10   switch (r) {
     11     case REG_A: e->a = v; break;
     12     case REG_B: e->b = v; break;
     13     case REG_C: e->c = v; break;
     14     case REG_D: e->d = v; break;
     15     case REG_E: e->e = v; break;
     16     case REG_H: e->h = v; break;
     17     case REG_L: e->l = v; break;
     18     case REG_M: 
     19       {
     20         uint16_t hl = ((uint16_t)e->h << 8) | e->l;
     21         e->mem[hl] = v;
     22         break;
     23       }
     24     default: return 0;
     25   }
     26   return 0;
     27 }
     28 
     29 uint8_t emu_get(emu_t *e, uint8_t r) {
     30   switch (r) {
     31     case REG_A: return e->a;
     32     case REG_B: return e->b;
     33     case REG_C: return e->c;
     34     case REG_D: return e->d;
     35     case REG_E: return e->e;
     36     case REG_H: return e->h;
     37     case REG_L: return e->l;
     38     case REG_M: 
     39       {
     40         uint16_t hl = ((uint16_t)e->h << 8) | e->l;
     41         return e->mem[hl];
     42       }
     43     default: return 0;
     44   }
     45 }
     46 
     47 int emu_execute(emu_t *e, uint8_t i) {
     48   uint8_t part1 = (i >> 6) & 0x03;  
     49   uint8_t dst = (i >> 3) & 0x07;    
     50   uint8_t src = i & 0x07;           
     51 
     52   switch (part1) {
     53     case OP_MV:
     54       /* 01110110: hlt */
     55       if (dst == REG_M && src == REG_M) {
     56         return 1;
     57       }
     58       emu_set(e, dst, emu_get(e, src));
     59       e->pc += 1;
     60       break;
     61 
     62     case OP_ZZ: 
     63       {
     64         if (src == 0b110) {
     65           /* mvi r, data */
     66           emu_set(e, dst, e->mem[e->pc + 1]);
     67           e->pc += 2;
     68         } else if (src == OP_INC) {
     69           /* inr r */
     70           uint8_t old = emu_get(e, dst);
     71           uint8_t val = old + 1;
     72           FLAG_PUT(e, F_AC, ((old & 0x0F) + 1 > 0x0F));
     73           emu_set(e, dst, val);
     74           set_zsp(e, val);
     75           e->pc += 1;
     76         } else if (src == OP_DEC) {
     77           /* dcr r */
     78           uint8_t old = emu_get(e, dst);
     79           uint8_t val = old - 1;
     80           FLAG_PUT(e, F_AC, ((old & 0x0F) - 1 < 0));
     81           emu_set(e, dst, val);
     82           set_zsp(e, val);
     83           e->pc += 1;
     84         } else if (src == 0b010 && (dst == REG_A || dst == REG_M)) {
     85           /* lda / sta */
     86           uint16_t addr = (uint16_t)e->mem[e->pc + 1] |
     87             ((uint16_t)e->mem[e->pc + 2] << 8);
     88           if (dst == REG_A) {
     89             e->a = e->mem[addr];
     90           } else if (dst == REG_M) {
     91             e->mem[addr] = e->a;
     92           }
     93           e->pc += 3;
     94         } else {
     95           e->pc += 1;
     96         }
     97         break;
     98       }
     99 
    100     case OP_ALU:
    101       {
    102         uint8_t alu_op = dst;
    103         uint8_t val = emu_get(e, src);
    104         uint8_t a = e->a;
    105 
    106         switch (alu_op) {
    107           case OP_ALU_ADD: 
    108             {
    109               uint16_t res = (uint16_t)a + val;
    110               e->a = (uint8_t)res;
    111               FLAG_PUT(e, F_CY, res > 0xFF);
    112               FLAG_PUT(e, F_AC, ((a & 0x0F) + (val & 0x0F) > 0x0F));
    113               set_zsp(e, e->a);
    114               break;
    115             }
    116           case OP_ALU_ADC:
    117             {
    118               uint8_t cy = FLAG_GET(e, F_CY);
    119               uint16_t res = (uint16_t)a + val + cy;
    120               e->a = (uint8_t)res;
    121               FLAG_PUT(e, F_CY, res > 0xFF);
    122               FLAG_PUT(e, F_AC, ((a & 0x0F) + (val & 0x0F) + cy > 0x0F));
    123               set_zsp(e, e->a);
    124               break;
    125             }
    126           case OP_ALU_SUB: 
    127             {
    128               int16_t res = (int16_t)a - val;
    129               e->a = (uint8_t)res;
    130               FLAG_PUT(e, F_CY, res < 0);
    131               FLAG_PUT(e, F_AC, ((a & 0x0F) - (val & 0x0F) < 0));
    132               set_zsp(e, e->a);
    133               break;
    134             }
    135           case OP_ALU_SBB:
    136             {
    137               uint8_t cy = FLAG_GET(e, F_CY);
    138               int16_t res = (int16_t)a - val - cy;
    139               e->a = (uint8_t)res;
    140               FLAG_PUT(e, F_CY, res < 0);
    141               FLAG_PUT(e, F_AC, ((a & 0x0F) - (val & 0x0F) - cy < 0));
    142               set_zsp(e, e->a);
    143               break;
    144             }
    145           case OP_ALU_ANA:
    146             {
    147               e->a &= val;
    148               FLAG_PUT(e, F_CY, 0);
    149               FLAG_PUT(e, F_AC, ((a | val) & 0x08) != 0);
    150               set_zsp(e, e->a);
    151               break;
    152             }
    153           case OP_ALU_XRA:
    154             {
    155               e->a ^= val;
    156               FLAG_PUT(e, F_CY, 0);
    157               FLAG_PUT(e, F_AC, 0);
    158               set_zsp(e, e->a);
    159               break;
    160             }
    161           case OP_ALU_ORA:
    162             {
    163               e->a |= val;
    164               FLAG_PUT(e, F_CY, 0);
    165               FLAG_PUT(e, F_AC, 0);
    166               set_zsp(e, e->a);
    167               break;
    168             }
    169           case OP_ALU_CMP: 
    170             {
    171               int16_t res = (int16_t)a - val;
    172               FLAG_PUT(e, F_CY, res < 0);
    173               FLAG_PUT(e, F_AC, ((a & 0x0F) - (val & 0x0F) < 0));
    174               set_zsp(e, (uint8_t)res);
    175               break;
    176             }
    177         }
    178         e->pc += 1;
    179         break;
    180       }
    181 
    182     case OP_OO:
    183       {
    184         if (src == REG_M) {
    185           /* immediate alu */
    186           uint8_t imm = e->mem[e->pc + 1];
    187           uint8_t alu_op = dst;
    188           uint8_t a = e->a;
    189 
    190           switch (alu_op) {
    191             case OP_ALU_ADD: /* adi */
    192               {
    193                 uint16_t res = (uint16_t)a + imm;
    194                 e->a = (uint8_t)res;
    195                 FLAG_PUT(e, F_CY, res > 0xFF);
    196                 FLAG_PUT(e, F_AC, ((a & 0x0F) + (imm & 0x0F) > 0x0F));
    197                 set_zsp(e, e->a);
    198                 break;
    199               }
    200             case OP_ALU_SUB: /* sui */
    201               {
    202                 int16_t res = (int16_t)a - imm;
    203                 e->a = (uint8_t)res;
    204                 FLAG_PUT(e, F_CY, res < 0);
    205                 FLAG_PUT(e, F_AC, ((a & 0x0F) - (imm & 0x0F) < 0));
    206                 set_zsp(e, e->a);
    207                 break;
    208               }
    209             case OP_ALU_CMP: /* cpi */
    210               {
    211                 int16_t res = (int16_t)a - imm;
    212                 FLAG_PUT(e, F_CY, res < 0);
    213                 FLAG_PUT(e, F_AC, ((a & 0x0F) - (imm & 0x0F) < 0));
    214                 set_zsp(e, (uint8_t)res);
    215                 break;
    216               }
    217           }
    218           e->pc += 2;
    219         } else if (src == OP_JMP) {
    220           /* jmp */
    221           uint16_t addr = (uint16_t)e->mem[e->pc + 1] |
    222             ((uint16_t)e->mem[e->pc + 2] << 8);
    223           e->pc = addr;
    224         } else if (src == OP_J) {
    225           /* conditional jumps */
    226           bool jump = false;
    227           switch (dst) {
    228             case 0b000: jump = (FLAG_GET(e, F_Z) == 0); break; /* JNZ */
    229             case 0b001: jump = (FLAG_GET(e, F_Z) != 0); break; /* JZ */
    230             case 0b010: jump = (FLAG_GET(e, F_CY) == 0); break;/* JNC */
    231             case 0b011: jump = (FLAG_GET(e, F_CY) != 0); break;/* JC */
    232             case 0b100: jump = (FLAG_GET(e, F_P) == 0); break; /* JPO */
    233             case 0b101: jump = (FLAG_GET(e, F_P) != 0); break; /* JPE */
    234             case 0b110: jump = (FLAG_GET(e, F_S) == 0); break; /* JP */
    235             case 0b111: jump = (FLAG_GET(e, F_S) != 0); break; /* JM */
    236           }
    237 
    238           if (jump) {
    239             uint16_t addr = (uint16_t)e->mem[e->pc + 1] |
    240               ((uint16_t)e->mem[e->pc + 2] << 8);
    241             e->pc = addr;
    242           } else {
    243             e->pc += 3;
    244           }
    245         } else {
    246           e->pc += 1;
    247         }
    248         break;
    249       }
    250 
    251     default:
    252       return 1;
    253   }
    254   return 0;
    255 }
    256 
    257 void emu_start(emu_t *e) {
    258   int running = 1;
    259   e->pc = 0;
    260 
    261   while (running) {
    262     uint8_t instr = e->mem[e->pc];
    263     int res = emu_execute(e, instr);
    264     if (res != 0) break;
    265   }
    266 }
    267 
    268 EXPORT emu_t* emu_create(void) {
    269   emu_t *e = (emu_t*)calloc(1, sizeof(emu_t));
    270   return e;
    271 }
    272 
    273 EXPORT void emu_destroy(emu_t *e) {
    274   if (e) {
    275     free(e);
    276   }
    277 }
    278 
    279 EXPORT int emu_load_program(emu_t *e, const char *filename) {
    280   if (!e || !filename) return -1;
    281 
    282   FILE *f = fopen(filename, "rb");
    283   if (!f) return -1;
    284 
    285   size_t n = fread(e->mem, 1, MEMORY_SIZE, f);
    286   fclose(f);
    287 
    288   return (n > 0) ? 0 : -1;
    289 }
    290 
    291 EXPORT int emu_step(emu_t *e) {
    292   if (!e) return 1;
    293   uint8_t instr = e->mem[e->pc];
    294   return emu_execute(e, instr);
    295 }
    296 
    297 EXPORT int emu_get_pc(emu_t *e) {
    298   return e ? (int)e->pc : 0;
    299 }
    300 
    301 EXPORT void emu_set_pc(emu_t *e, int pc) {
    302   if (e) {
    303     e->pc = (uint16_t)pc;
    304   }
    305 }
    306 
    307 EXPORT void emu_mem_write(emu_t *e, uint16_t addr, byte val) {
    308   if (e) {
    309     e->mem[addr] = val;
    310   }
    311 }
    312 
    313 EXPORT byte emu_mem_read(emu_t *e, uint16_t addr) {
    314   return e ? e->mem[addr] : 0;
    315 }
    316 
    317 EXPORT byte emu_get_reg(emu_t *e, byte c) {
    318   return e ? emu_get(e, c) : 0;
    319 }