aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuan J. Martinez <jjm@usebox.net>2023-05-23 16:06:46 +0100
committerJuan J. Martinez <jjm@usebox.net>2023-05-23 16:08:48 +0100
commitc5dd4897e4d7f45108b6955bebf2d4b5f22a3652 (patch)
treea85d5b933fe2dccf57dd476194a27b0f5d99becd
parent5584f79fff0fdfc8e4430eea3867c729b82f4152 (diff)
downloadtr8vm-c5dd4897e4d7f45108b6955bebf2d4b5f22a3652.tar.gz
tr8vm-c5dd4897e4d7f45108b6955bebf2d4b5f22a3652.zip
Add cmpi, cmpd, ldi and ldd
-rw-r--r--README.md27
-rw-r--r--tr8as.c30
-rw-r--r--vm.c79
3 files changed, 133 insertions, 3 deletions
diff --git a/README.md b/README.md
index f17875a..82eca95 100644
--- a/README.md
+++ b/README.md
@@ -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**
diff --git a/tr8as.c b/tr8as.c
index 40042fd..c09cf48 100644
--- a/tr8as.c
+++ b/tr8as.c
@@ -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 },
diff --git a/vm.c b/vm.c
index 72dec72..43a6ab5 100644
--- a/vm.c
+++ b/vm.c
@@ -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;
}
}