diff options
author | Juan J. Martinez <jjm@usebox.net> | 2023-05-23 16:06:46 +0100 |
---|---|---|
committer | Juan J. Martinez <jjm@usebox.net> | 2023-05-23 16:08:48 +0100 |
commit | c5dd4897e4d7f45108b6955bebf2d4b5f22a3652 (patch) | |
tree | a85d5b933fe2dccf57dd476194a27b0f5d99becd | |
parent | 5584f79fff0fdfc8e4430eea3867c729b82f4152 (diff) | |
download | tr8vm-c5dd4897e4d7f45108b6955bebf2d4b5f22a3652.tar.gz tr8vm-c5dd4897e4d7f45108b6955bebf2d4b5f22a3652.zip |
Add cmpi, cmpd, ldi and ldd
-rw-r--r-- | README.md | 27 | ||||
-rw-r--r-- | tr8as.c | 30 | ||||
-rw-r--r-- | vm.c | 79 |
3 files changed, 133 insertions, 3 deletions
@@ -225,7 +225,8 @@ A label is defined as an ID that ends in `:`. All the instructions are 16-bit, with the exception of `JMP addr` and `CALL addr` that use an extra 16-bit parameter for "addr". All the instructions take -the same time to run, and being 4 MIPS it can fit `66666` instructions in a +the same time to run (with the exception of `cmpi`, `cmpd`, `ldi` and `ldd` +that take extra time), and being 4 MIPS it can fit `66666` instructions in a frame (at 60Hz). There are no 16-bit registers, but they can be implemented with 2 registers, @@ -336,6 +337,16 @@ Load r1 into the stack on top address plus the immediate value. **LD r1, [SP + imm]** Load into r1 the stack value on top address plus the immediate value. +**LDI** +Perform a LD of [a : x] to [b : y], and increments x (and a if x overflows) and +y (and b if x overflows). This instruction takes 4 times longer than a regular +instruction. + +**LDD** +Perform a LD of [a : x] to [b : y], and decrements x (and a if x overflows) +and y (and b if x overflows). This instruction takes 4 times longer than a regular +instruction. + #### Stack **PUSH r1** @@ -415,6 +426,20 @@ Perform a SUB of r1 minus the immediate value without storing the result and only updating the flags. Affected flags: ZF, CF, OF, SF +**CMPI** +Perform a SUB of [a : x] minus [b : y], without storing the result and only +updating the flags. It also increments x (and a if x overflows) and y (and b if x +overflows). The flags are not affected by incrementing a, b, x and y. This +instruction takes 4 times longer than a regular instruction. +Affected flags: ZF, CF, OF, SF + +**CMPD** +Perform a SUB of [a : x] minus [b : y], without storing the result and only +updating the flags. It also decrements x (and a if x overflows) and y (and b if +x overflows). The flags are not affected by decrementing a, b, x and y. This +instruction takes 4 times longer than a regular instruction. +Affected flags: ZF, CF, OF, SF + #### Bit Operations **SHL r1, n** @@ -1007,7 +1007,31 @@ static uint8_t parse_cmp(As *as, char **c) return emit(as, 5, r1, FHL, (r2 << 6)); /* CMP r1, imm */ - return emit(as, 5, r1, 0, imm); + return emit(as, 5, r1, 0, imm); +} + +static uint8_t parse_cmpi(As *as, char **c) +{ + /* CMPI */ + return emit(as, 14, 0, FHH | FHL, 0); +} + +static uint8_t parse_cmpd(As *as, char **c) +{ + /* CMPD */ + return emit(as, 14, 0, FHL, 0); +} + +static uint8_t parse_ldi(As *as, char **c) +{ + /* LDI */ + return emit(as, 14, 0, FHH, 0); +} + +static uint8_t parse_ldd(As *as, char **c) +{ + /* LDD */ + return emit(as, 14, 0, 0, 0); } static uint8_t parse_add(As *as, char **c) @@ -1517,6 +1541,8 @@ static InstParse insts[] = { "port", parse_port }, { "iret", parse_iret }, { "call", parse_call }, + { "cmpi", parse_cmpi }, + { "cmpd", parse_cmpd }, { "xsp", parse_xsp }, { "and", parse_and }, { "cmp", parse_cmp }, @@ -1545,6 +1571,8 @@ static InstParse insts[] = { "scf", parse_scf }, { "sof", parse_sof }, { "cof", parse_cof }, + { "ldi", parse_ldi }, + { "ldd", parse_ldd }, { "or", parse_or }, { "bz", parse_bz }, { "bc", parse_bc }, @@ -453,13 +453,90 @@ uint8_t tr8_eval(Tr8 *vm) } break; + case 14: + if (FHL(instr)) + { + if (FHH(instr)) + { + uint8_t f = 0; + + /* CMPI */ + flags(&vm->f, vm->read_m(ADDR(vm->regs[0], vm->regs[2])) - vm->read_m(ADDR(vm->regs[1], vm->regs[3])), ZF | CF | OF | SF); + + vm->regs[2] = flags(&f, vm->regs[2] + 1, OF); + if (f & OF) + vm->regs[0]++; + + vm->regs[3] = flags(&f, vm->regs[3] + 1, OF); + if (f & OF) + vm->regs[1]++; + + vm->icnt += 3; + } + else + { + uint8_t f = 0; + + /* CMPD */ + flags(&vm->f, vm->read_m(ADDR(vm->regs[0], vm->regs[2])) - vm->read_m(ADDR(vm->regs[1], vm->regs[3])), ZF | CF | OF | SF); + + vm->regs[2] = flags(&f, vm->regs[2] - 1, OF); + if (f & OF) + vm->regs[0]--; + + vm->regs[3] = flags(&f, vm->regs[3] - 1, OF); + if (f & OF) + vm->regs[1]--; + + vm->icnt += 3; + } + } + else + { + if (FHH(instr)) + { + uint8_t f = 0; + + /* LDI */ + vm->write_m(ADDR(vm->regs[1], vm->regs[3]), vm->read_m(ADDR(vm->regs[0], vm->regs[2]))); + + vm->regs[2] = flags(&f, vm->regs[2] + 1, OF); + if (f & OF) + vm->regs[0]++; + + vm->regs[3] = flags(&f, vm->regs[3] + 1, OF); + if (f & OF) + vm->regs[1]++; + + vm->icnt += 3; + } + else + { + uint8_t f = 0; + + /* LDD */ + vm->write_m(ADDR(vm->regs[1], vm->regs[3]), vm->read_m(ADDR(vm->regs[0], vm->regs[2]))); + + vm->regs[2] = flags(&f, vm->regs[2] - 1, OF); + if (f & OF) + vm->regs[0]--; + + vm->regs[3] = flags(&f, vm->regs[3] - 1, OF); + if (f & OF) + vm->regs[1]--; + + vm->icnt += 3; + } + } + break; + default: fprintf(stderr, "*invalid opcode 0x%01x at PC=0x%04x*\n", (instr >> 12), 2 * (vm->pc - 1)); tr8_dump(vm, stderr); return 1; } - if (vm->icnt == INSTR_PER_FRAME) + if (vm->icnt >= INSTR_PER_FRAME) return 1; } } |