commit cdca6e1e444eaf821349faee056e759171f9edff
parent 4c7cc46d8197325c815e08cd6bdc0b06c52f15f6
Author: Virgil Dupras <hsoft@hardcoded.net>
Date: Sat, 1 Apr 2023 14:20:39 -0400
hal: add &) operand modifier
Diffstat:
4 files changed, 72 insertions(+), 23 deletions(-)
diff --git a/fs/comp/c/expr.fs b/fs/comp/c/expr.fs
@@ -75,12 +75,12 @@ struct[ Result
CONST of = arg i) endof
CDECL of =
dup cdecl dup CDecl :halop ( self cdecl halop )
- swap CDecl :reference? if A>) lea, A*) then ( self halop )
+ swap CDecl :reference? if A>) lea, A&) then ( self halop )
swap :nb) endof
PS of = arg PSP+) endof
- REF of = target :hal# A>) lea, A*) endof
+ REF of = target :hal# A>) lea, A&) endof
DEREF of =
- dup target dup :isW? if :release W*) else :hal# then ( self halop )
+ dup target dup :isW? if :release W&) else :hal# then ( self halop )
A>) @, A) swap :nb) endof
abort" :hal# error" endcase ;
: :hal$ dup :hal# swap :release ;
diff --git a/fs/doc/hal.txt b/fs/doc/hal.txt
@@ -11,7 +11,7 @@ A) -- op
PSP) -- op
RSP) -- op
m) addr -- op
-+) op disp -- op
++) op disp -- op Can be applied multiple times
Maximum displacement in Low HAL: 8-bit
@@ -62,10 +62,11 @@ The "high" layer of the HAL is provided by the assembler.
Operand words:
i)
-W*) Direct W register operand
-A*) Direct A register operand
+W&) Direct W register operand
+A&) Direct A register operand
A>) A register is the destination (instead of W)
<>) Direction of the operation is inverted
+&) Reference to operand (see below)
Branching and conditions:
@@ -88,3 +89,20 @@ Width-aware compiler words:
%, op --
<<, op --
>>, op --
+
+### &) operand modifier
+
+The &) word takes an input operand and returns its reference counterpart. For
+example, m) becomes i), W) becomes W*), etc. This also works with displacements.
+For example, "RSP) 4 +) &)" yields an operand that points to RSP+4.
+
+This operand might not be adressable directly by the host CPU. In that case, the
+HAL operator will compile two instructions. For example, "RSP) 4 +) &) +," under
+i386 would yield "bx sp 4 +) lea, ax bx add,". Only RSP) and PSP) can be
+referenced with displacement.
+
+The "&)" word never writes instructions directly, only operator words. The
+"lea," above wouldn't be written when "&)" is called, but when "+," is.
+
+If the &) word is called with an operand that can't be referenced, this word has
+no effect. For example "W&) &)" is the same as "W&)".
diff --git a/fs/tests/asm/hal.fs b/fs/tests/asm/hal.fs
@@ -153,11 +153,11 @@ code test15 ( n n -- n )
nip, exit,
$42 4 test15 $420 #eq
-\ test W*), A*) and A>)
+\ test W&), A&) and A>)
code test16 ( a b -- n ) \ a + b*b
PSP) A>) @, nip,
- W*) *,
- A*) +,
+ W&) *,
+ A&) +,
exit,
4 5 test16 29 #eq
@@ -169,4 +169,14 @@ code test17 ( n -- )
exit,
42 test17 foo @ $1234 42 + #eq
+
+\ test &). this returns item "idx" from PSP
+code test18 ( ... idx -- n )
+ 2 <<n, PSP) &) +, W) @,
+ exit,
+
+42 12 123 0 test18 123 #eq
+1 test18 12 #eq
+2 test18 42 #eq
+2drop drop
testend
diff --git a/posix/vm.c b/posix/vm.c
@@ -4,8 +4,8 @@ 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)
+b2:0 type 0=W 1=A 2=PSP 3=RSP 4=memory/immediate
+b3 has disp? (type "memory" always has disp)
b4 direct register mode (AREG, WREG)?
b5 A dst?
b6 invert?
@@ -51,13 +51,15 @@ no assembler to complete the HAL to "full" level later. It's all in there.
// Fake memory location to refer to the registers directly
#define WREG 0x8000000
#define AREG 0x8000001
+#define PSPREG 0x8000002
+#define RSPREG 0x8000003
+#define TREG 0x8000004
#define OPW 0
#define OPA 1
#define OPPSP 2
#define OPRSP 3
#define OPMEM 4
-#define OPIMM 5
#define OPHASDISP 0x08
#define OPDIRECT 0x10
#define OPADEST 0x20
@@ -88,6 +90,7 @@ struct VM {
dword PC; // when PC >= MEMSZ, machine is halted
dword W; // W is PS top
dword A;
+ dword T; // tmp register. not directly addressable
byte Z;
byte C;
byte SC; // signed C
@@ -119,6 +122,9 @@ static dword gdr(dword addr) {
switch(addr) {
case WREG: return vm.W;
case AREG: return vm.A;
+ case PSPREG: return vm.PSP;
+ case RSPREG: return vm.RSP;
+ case TREG: return vm.T;
default: return gd(addr);
}
}
@@ -131,6 +137,8 @@ static void sdr(dword addr, dword d) {
switch(addr) {
case WREG: vm.W = d; break;
case AREG: vm.A = d; break;
+ case PSPREG: vm.PSP = d; break;
+ case RSPREG: vm.RSP = d; break;
default: sd(addr, d);
}
}
@@ -183,7 +191,8 @@ 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 >> 12)&0xf)); }
+static dword hbankget(dword operand) {
+ return operand&OPHASDISP ? gd(hbankaddr((operand >> 12)&0xf)) : 0; }
static dword hbankset(dword operand, dword val) {
byte idx = (++vm.hbankidx) % HBANKCNT;
sd(hbankaddr(idx), val);
@@ -295,19 +304,27 @@ static void readop() {
opdget = def_opdget; opdset = def_opdset;
opsget = def_opsget; opsset = def_opsset;
}
- opdst = &vm.W;
- opaddr = 0;
+ opdst = op & OPADEST ? &vm.A : &vm.W;
switch (op & 0x17) {
case OPW: opaddr = vm.W; break;
case OPW|OPDIRECT: opaddr = WREG; break;
case OPA: opaddr = vm.A; break;
case OPA|OPDIRECT: opaddr = AREG; break;
case OPPSP: opaddr = vm.PSP; break;
+ case OPPSP|OPDIRECT: opaddr = PSPREG; break;
case OPRSP: opaddr = vm.RSP; break;
- case OPIMM: opaddr = vm.PC; vm.PC += 4; return;
+ case OPRSP|OPDIRECT: opaddr = RSPREG; break;
+ case OPMEM: opaddr = gpc(); return;
+ case OPMEM|OPDIRECT: opaddr = vm.PC; vm.PC += 4; return;
+ default:
+ printf("Invalid HAL operand %x\n", op);
+ vmabort();
+ }
+ if (op & OPHASDISP) {
+ if (op & OPDIRECT) {
+ vm.T = gdr(opaddr) + gpc(); opaddr = TREG;
+ } else { opaddr += gpc(); }
}
- if (op & OPHASDISP) opaddr += gpc();
- if (op & OPADEST) opdst = &vm.A;
}
static void _wfetch() { readop(); opdset(opsget()); }
static void _wswap() { readop(); dword n; n = opsget(); opsset(opdget()); opdset(n); }
@@ -355,7 +372,10 @@ static void MAYBEKEY() {
static void MAKEMEM() { vm.W = hbankset(OPHASDISP|OPMEM, vm.W); }
// operand n -- operand
static void ADDDISP() {
- dword by = ppop(); if (by) vm.W = hbankset(vm.W, by)|OPHASDISP; }
+ dword by = ppop(); if (by) {
+ vm.W = hbankset(vm.W, hbankget(vm.W)+by)|OPHASDISP;
+ }
+}
static void MAYBEWORD() { // 0x30
dword c, a;
@@ -941,7 +961,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("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);
@@ -990,20 +1010,21 @@ static void buildsysdict() {
entry("branch!"); storewr(); retwr();
entry("yield"); compileop(0x07); retwr(); makeimm();
entry(";"); compileop(0x02); cwrite(0x3d); retwr(); makeimm();
- entry("i)"); callwr(find("m)")); cwrite(0x0c); /* W+n */ dwrite(1); retwr();
entry("*"); binopwr(0x02, OPPSP); nipwr(); retwr();
entry("and"); binopwr(0x08, OPPSP); nipwr(); retwr();
entry("or"); binopwr(0x09, OPPSP); nipwr(); retwr();
entry("xor"); binopwr(0x0a, OPPSP); nipwr(); retwr();
entry("lshift"); wopwr(0x12 /* @! */, OPPSP); binopwr(0x05, OPPSP); nipwr(); retwr();
entry("rshift"); wopwr(0x12 /* @! */, OPPSP); binopwr(0x06, OPPSP); nipwr(); retwr();
- entry("<<n,"); callwr(find("i)")); callwr(find("<<,")); retwr();
- 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();
entry("<>)"); litwr(OPINVERT); callwr(find("xor")); retwr();
+ entry("&)"); litwr(OPDIRECT); callwr(find("or")); retwr();
+ entry("i)"); callwr(find("m)")); callwr(find("&)")); retwr();
entry("!,"); callwr(find("<>)")); callwr(find("@,")); retwr();
+ entry("<<n,"); callwr(find("i)")); callwr(find("<<,")); retwr();
+ entry(">>n,"); callwr(find("i)")); callwr(find(">>,")); retwr();
entry("dup,");
litwr(0xfffffffc); callwr(find("ps+,"));
callwr(find("PSP)")); callwr(find("!,")); retwr();