commit 8194bdf05578dc66b765369179a59acc5ca62477
parent 8ba07a647b5a53edfab0cc524fca20271dd7ff93
Author: Virgil Dupras <hsoft@hardcoded.net>
Date: Thu, 23 Mar 2023 08:51:26 -0400
hal: add W*) A*) and A>) "high" operands
They should help with what's coming...
Diffstat:
3 files changed, 116 insertions(+), 73 deletions(-)
diff --git a/fs/doc/hal.txt b/fs/doc/hal.txt
@@ -62,6 +62,9 @@ The "high" layer of the HAL is provided by the assembler.
Operand words:
i)
+W*) Direct W register operand
+A*) Direct A register operand
+A>) A reigter is the destination (instead of W)
Branching and conditions:
diff --git a/fs/tests/asm/hal.fs b/fs/tests/asm/hal.fs
@@ -152,4 +152,14 @@ code test15 ( n n -- n )
PSP) <<,
nip, exit,
$42 4 test15 $420 #eq
+
+\ test W*), A*) and A>)
+code test16 ( a b -- n ) \ a + b*b
+ PSP) A>) @, nip,
+ W*) *,
+ A*) +,
+ exit,
+
+4 5 test16 29 #eq
+
testend
diff --git a/posix/vm.c b/posix/vm.c
@@ -4,11 +4,15 @@ The VM is little endian, has a read-only file system and is pretty slow. It's
enough, however, to generate native binary images for any supported target.
HAL argument structure:
-b2:0 type 0=W 1=A 2=PSP 3=RSP 4=memory 5=immediate
-b3 has disp? (type "memory" and "immediate" always have disp)
-b7:4 number bank id
-b8 16b?
-b9 8b?
+b2:0 type 0=W 1=A 2=PSP 3=RSP 4=memory 5=immediate
+b3 has disp? (type "memory" and "immediate" always have disp)
+b4 direct register mode (AREG, WREG)?
+b5 A dst?
+b7:6 unused
+b8 16b?
+b9 8b?
+b11:10 unused
+b15:12 number bank id
Full HAL: Unlike regular kernels, this VM contains the full HAL because it has
no assembler to complete the HAL to "full" level later. It's all in there.
@@ -43,6 +47,10 @@ no assembler to complete the HAL to "full" level later. It's all in there.
#define IOBUFSZ 0x200
#define IOBUF (HBANK-IOBUFSZ)
+// Fake memory location to refer to the registers directly
+#define WREG 0x8000000
+#define AREG 0x8000001
+
#define OPW 0
#define OPA 1
#define OPPSP 2
@@ -50,6 +58,8 @@ no assembler to complete the HAL to "full" level later. It's all in there.
#define OPMEM 4
#define OPIMM 5
#define OPHASDISP 0x08
+#define OPDIRECT 0x10
+#define OPADEST 0x20
#define OP16B 0x100
#define OP8B 0x200
// Condition structure: b6:0 condition ID b7 invert
@@ -72,6 +82,7 @@ struct VM {
dword PC; // when PC >= MEMSZ, machine is halted
dword W; // W is PS top
dword A;
+ dword *dst;
byte Z;
byte C;
byte compiling;
@@ -98,11 +109,25 @@ static dword memchk(dword a) {
static byte gb(dword addr) { return vm.mem[memchk(addr)]; }
static word gw(dword addr) { return gb(addr) | (gb(addr+1)<<8); }
static dword gd(dword addr) { return gw(addr) | (gw(addr+2)<<16); }
+static dword gdr(dword addr) {
+ switch(addr) {
+ case WREG: return vm.W;
+ case AREG: return vm.A;
+ default: return gd(addr);
+ }
+}
static dword gpc() { dword n = gd(vm.PC); vm.PC += 4; return n; }
static byte gpcb() { dword n = gb(vm.PC); vm.PC++; return n; }
static void sb(dword addr, byte b) { vm.mem[memchk(addr)] = b; }
static void sw(dword addr, word w) { sb(addr, w); sb(addr+1, w>>8); }
static void sd(dword addr, dword d) { sw(addr, d); sw(addr+2, d>>16); }
+static void sdr(dword addr, dword d) {
+ switch(addr) {
+ case WREG: vm.W = d; break;
+ case AREG: vm.A = d; break;
+ default: sd(addr, d);
+ }
+}
static dword pnip() { dword n = gd(vm.PSP); vm.PSP += 4; return n; }
static dword ppop() { dword n = vm.W; vm.W = gd(vm.PSP); vm.PSP += 4; return n; }
static void ppush(dword n) { vm.PSP -= 4; sd(vm.PSP, vm.W); vm.W = n; }
@@ -152,18 +177,18 @@ static void dwrite(dword d) {
allot(4);
}
static dword hbankaddr(byte idx) { return HBANK+((idx%HBANKCNT)*4); }
-static dword hbankget(dword operand) { return gd(hbankaddr((operand >> 4)&0xf)); }
+static dword hbankget(dword operand) { return gd(hbankaddr((operand >> 12)&0xf)); }
static dword hbankset(dword operand, dword val) {
byte idx = (++vm.hbankidx) % HBANKCNT;
sd(hbankaddr(idx), val);
- return operand | (idx << 4);
+ return operand | (idx << 12);
}
static void retwr() { cwrite(0x02); }
static void psaddwr(dword n) { cwrite(0x08); dwrite(n); }
static void wopwr(byte opcode, dword operand) {
opcode += (operand&(OP8B|OP16B)) >> 5;
- cwrite(opcode); cwrite(operand&0xf);
+ cwrite(opcode); cwrite(operand);
if (operand&OPHASDISP) dwrite(hbankget(operand));
}
static void wfetchwr(dword op) { wopwr(0x10, op); }
@@ -228,46 +253,51 @@ static void WSWAPA() { dword n = vm.A; vm.A = vm.W; vm.W = n; }
static dword readop() {
byte op = gpcb();
+ vm.dst = &vm.W;
dword addr = 0;
- switch (op & 7) {
+ switch (op & 0x17) {
case OPW: addr = vm.W; break;
+ case OPW|OPDIRECT: addr = WREG; break;
case OPA: addr = vm.A; break;
+ case OPA|OPDIRECT: addr = AREG; break;
case OPPSP: addr = vm.PSP; break;
case OPRSP: addr = vm.RSP; break;
case OPIMM: addr = vm.PC; vm.PC += 4; return addr;
}
if (op & OPHASDISP) addr += gpc();
+ if (op & OPADEST) vm.dst = &vm.A;
return addr;
}
-static void WFETCH() { vm.W = gd(readop()); } // 0x10
-static void WSTORE() { sd(readop(), vm.W); }
-static void WSWAP() { dword a, n; a = readop(); n = gd(a); sd(a, vm.W); vm.W = n; }
-static void MADDN() { dword a = readop(); dword n=gpc(); n += gd(a); sd(a, n); vm.Z = n == 0; }
+#define GETA dword a = readop()
+static void WFETCH() { GETA; *vm.dst = gdr(a); } // 0x10
+static void WSTORE() { GETA; sdr(a, *vm.dst); }
+static void WSWAP() { GETA; dword n; n = gdr(a); sdr(a, *vm.dst); *vm.dst = n; }
+static void MADDN() { GETA; dword n=gpc(); n += gdr(a); sdr(a, n); vm.Z = n == 0; }
static void WCMP() {
- dword n = gd(readop()); vm.Z = n == vm.W; vm.C = vm.W < n; }
-static void WIFETCH() { vm.W = gd(gd(readop())); }
-static void WISTORE() { sd(gd(readop()), vm.W); }
-static void WADD() { vm.W += gd(readop()); vm.Z = vm.W == 0; }
-
-static void WFETCH16() { vm.W = gw(readop()); } // 0x18
-static void WSTORE16() { sw(readop(), vm.W); }
-static void WSWAP16() { dword a, n; a = readop(); n = gw(a); sw(a, vm.W); vm.W = n; }
-static void MADDN16() { dword a = readop(); dword n=gpc(); n += gw(a); sw(a, n); vm.Z = (n&0xffff) == 0; }
-static void WCMP16() { vm.Z = gw(readop()) == (vm.W & 0xffff); }
-static void WIFETCH16() { vm.W = gw(gd(readop())); }
-static void WISTORE16() { sw(gd(readop()), vm.W); }
-static void WADD16() { vm.W += gw(readop()); vm.Z = vm.W == 0; }
-
-static void WFETCH8() { vm.W = gb(readop()); } // 0x20
-static void WSTORE8() { sb(readop(), vm.W); }
-static void WSWAP8() { dword a, n; a = readop(); n = gb(a); sb(a, vm.W); vm.W = n; }
-static void MADDN8() { dword a = readop(); dword n=gpc(); n += gb(a); sb(a, n); vm.Z = (n&0xff) == 0; }
-static void WCMP8() { vm.Z = gb(readop()) == (vm.W & 0xff); }
-static void WIFETCH8() { vm.W = gb(gd(readop())); }
-static void WISTORE8() { sb(gd(readop()), vm.W); }
-static void WADD8() { vm.W += gb(readop()); vm.Z = vm.W == 0; }
-
-static void WLEA() { vm.W = readop(); } // 0x28
+ GETA; dword n = gdr(a); vm.Z = n == *vm.dst; vm.C = *vm.dst < n; }
+static void WIFETCH() { GETA; *vm.dst = gd(gdr(a)); }
+static void WISTORE() { GETA; sdr(gdr(a), *vm.dst); }
+static void WADD() { GETA; *vm.dst += gdr(a); vm.Z = *vm.dst == 0; }
+
+static void WFETCH16() { GETA; *vm.dst = gw(a); } // 0x18
+static void WSTORE16() { GETA; sw(a, *vm.dst); }
+static void WSWAP16() { GETA; dword n; n = gw(a); sw(a, *vm.dst); *vm.dst = n; }
+static void MADDN16() { GETA; dword n=gpc(); n += gw(a); sw(a, n); vm.Z = (n&0xffff) == 0; }
+static void WCMP16() { GETA; vm.Z = gw(a) == (*vm.dst & 0xffff); }
+static void WIFETCH16() { GETA; *vm.dst = gw(gdr(a)); }
+static void WISTORE16() { GETA; sw(gdr(a), *vm.dst); }
+static void WADD16() { GETA; *vm.dst += gw(a); vm.Z = *vm.dst == 0; }
+
+static void WFETCH8() { GETA; *vm.dst = gb(a); } // 0x20
+static void WSTORE8() { GETA; sb(a, *vm.dst); }
+static void WSWAP8() { GETA; dword n; n = gb(a); sb(a, *vm.dst); *vm.dst = n; }
+static void MADDN8() { GETA; dword n=gpc(); n += gb(a); sb(a, n); vm.Z = (n&0xff) == 0; }
+static void WCMP8() { GETA; vm.Z = gb(a) == (*vm.dst & 0xff); }
+static void WIFETCH8() { GETA; *vm.dst = gb(gdr(a)); }
+static void WISTORE8() { GETA; sb(gdr(a), *vm.dst); }
+static void WADD8() { GETA; *vm.dst += gb(a); vm.Z = *vm.dst == 0; }
+
+static void WLEA() { GETA; *vm.dst = a; } // 0x28
static void BOOTRD() { ppush(fgetc(fp)); }
static void STDOUT() { dword c = ppop(); write(STDOUT_FILENO, &c, 1); }
// ( -- c? f )
@@ -277,8 +307,6 @@ static void MAYBEKEY() {
ppush(c); ppush(1);
} else { ppush(0); }
}
-// operand -- n
-static void HBANKGET() { vm.W = hbankget(vm.W); }
// n -- operand
static void MAKEMEM() { vm.W = hbankset(OPHASDISP|OPMEM, vm.W); }
// operand n -- operand
@@ -492,38 +520,38 @@ static void WCHECKZ() { vm.Z = !vm.W; }
static void STOREC() { vm.W = checkcond(gpcb()); }
static void ACHECKZ() { vm.Z = !vm.A; }
-static void WSUB() { vm.W -= gd(readop()); } // 0x68
-static void WMUL() { vm.W *= gd(readop()); }
-static void WDIV() { vm.W /= gd(readop()); }
-static void WMOD() { vm.W %= gd(readop()); }
-static void WSHL() { vm.W <<= gd(readop()); }
-static void WSHR() { vm.W >>= gd(readop()); }
-
-static void WSUB16() { vm.W -= gw(readop()); } // 0x70
-static void WMUL16() { vm.W *= gw(readop()); }
-static void WDIV16() { vm.W /= gw(readop()); }
-static void WMOD16() { vm.W %= gw(readop()); }
-static void WSHL16() { vm.W <<= gw(readop()); }
-static void WSHR16() { vm.W >>= gw(readop()); }
-
-static void WSUB8() { vm.W -= gb(readop()); } // 0x78
-static void WMUL8() { vm.W *= gb(readop()); }
-static void WDIV8() { vm.W /= gb(readop()); }
-static void WMOD8() { vm.W %= gb(readop()); }
-static void WSHL8() { vm.W <<= gb(readop()); }
-static void WSHR8() { vm.W >>= gb(readop()); }
-
-static void WAND() { vm.W &= gd(readop()); } // 0x80
-static void WOR() { vm.W |= gd(readop()); }
-static void WXOR() { vm.W ^= gd(readop()); }
-
-static void WAND16() { vm.W &= gw(readop()); } // 0x88
-static void WOR16() { vm.W |= gw(readop()); }
-static void WXOR16() { vm.W ^= gw(readop()); }
-
-static void WAND8() { vm.W &= gb(readop()); } // 0x90
-static void WOR8() { vm.W |= gb(readop()); }
-static void WXOR8() { vm.W ^= gb(readop()); }
+static void WSUB() { GETA; *vm.dst -= gdr(a); } // 0x68
+static void WMUL() { GETA; *vm.dst *= gdr(a); }
+static void WDIV() { GETA; *vm.dst /= gdr(a); }
+static void WMOD() { GETA; *vm.dst %= gdr(a); }
+static void WSHL() { GETA; *vm.dst <<= gdr(a); }
+static void WSHR() { GETA; *vm.dst >>= gdr(a); }
+
+static void WSUB16() { GETA; *vm.dst -= gw(a); } // 0x70
+static void WMUL16() { GETA; *vm.dst *= gw(a); }
+static void WDIV16() { GETA; *vm.dst /= gw(a); }
+static void WMOD16() { GETA; *vm.dst %= gw(a); }
+static void WSHL16() { GETA; *vm.dst <<= gw(a); }
+static void WSHR16() { GETA; *vm.dst >>= gw(a); }
+
+static void WSUB8() { GETA; *vm.dst -= gb(a); } // 0x78
+static void WMUL8() { GETA; *vm.dst *= gb(a); }
+static void WDIV8() { GETA; *vm.dst /= gb(a); }
+static void WMOD8() { GETA; *vm.dst %= gb(a); }
+static void WSHL8() { GETA; *vm.dst <<= gb(a); }
+static void WSHR8() { GETA; *vm.dst >>= gb(a); }
+
+static void WAND() { GETA; *vm.dst &= gdr(a); } // 0x80
+static void WOR() { GETA; *vm.dst |= gdr(a); }
+static void WXOR() { GETA; *vm.dst ^= gdr(a); }
+
+static void WAND16() { GETA; *vm.dst &= gw(a); } // 0x88
+static void WOR16() { GETA; *vm.dst |= gw(a); }
+static void WXOR16() { GETA; *vm.dst ^= gw(a); }
+
+static void WAND8() { GETA; *vm.dst &= gb(a); } // 0x90
+static void WOR8() { GETA; *vm.dst |= gb(a); }
+static void WXOR8() { GETA; *vm.dst ^= gb(a); }
/* Filesystem
At POSIX level, we don't have access to the underlying FS structure such as
@@ -809,7 +837,7 @@ static void (*ops[OPCNT])() = {
WFETCH, WSTORE, WSWAP, MADDN, WCMP, WIFETCH, WISTORE, WADD,
WFETCH16, WSTORE16, WSWAP16, MADDN16, WCMP16, WIFETCH16, WISTORE16, WADD16,
WFETCH8, WSTORE8, WSWAP8, MADDN8, WCMP8, WIFETCH8, WISTORE8, WADD8,
- WLEA, BOOTRD, STDOUT, MAYBEKEY, HBANKGET, MAKEMEM, ADDDISP, NULL,
+ WLEA, BOOTRD, STDOUT, MAYBEKEY, NULL, MAKEMEM, ADDDISP, NULL,
MAYBEWORD, WORD, PARSE, FIND, WNF, FINDMOD, NULL, NULL,
STACKCHK, COMPWORD, RUNWORD, COMPILING, STARTCOMP, STOPCOMP, RSADDWR, COMPOP,
ALIGN4, ENTRY, CODE, CODE16, CODE8, NULL, NULL, NULL,
@@ -859,7 +887,7 @@ static void compileop(byte op) { litwr(op); cwritewr(); }
// Names for simple word-to-code mappings
static char *opnames[OPCNT-0x28] = {
- NULL, "boot<", "(emit)", "(key?)", "@)", "m)", "+)", NULL,
+ NULL, "boot<", "(emit)", "(key?)", NULL, "m)", "+)", NULL,
"maybeword", "word", "parse", "find", "(wnf)", "findmod", NULL, NULL,
"stack?", "compword", "runword", "compiling", "]", NULL, "rs+,", NULL,
"align4", "entry", "code", "code16b", "code8b", NULL, NULL, NULL,
@@ -897,6 +925,7 @@ static void buildsysdict() {
sysconst("nextmeta", NEXTMETA);
sysconst("[rcnt]", _RCNT_);
sysconst("W)", OPW); sysconst("A)", OPA);
+ sysconst("W*)", OPW|OPDIRECT); sysconst("A*)", OPA|OPDIRECT);
sysconst("PSP)", OPPSP); sysconst("RSP)", OPRSP);
sysconst("Z)", CONDZ); sysconst("NZ)", CONDNZ);
sysconst("C)", CONDC); sysconst("NC)", CONDNC);
@@ -959,6 +988,7 @@ static void buildsysdict() {
entry(">>n,"); callwr(find("i)")); callwr(find(">>,")); retwr();
entry("16b)"); litwr(OP16B); callwr(find("or")); retwr();
entry("8b)"); litwr(OP8B); callwr(find("or")); retwr();
+ entry("A>)"); litwr(OPADEST); callwr(find("or")); retwr();
sysalias("in<", "boot<");
sysalias("rtype", "byefail");
sysalias("abort", "byefail");