q3k 2022-08-02 23:55:59 +02:00
parent a9765a005b
commit 06c5fc95b0
6 changed files with 589 additions and 0 deletions

0
Module.manifest Normal file
View File

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<language_definitions>
<language processor="LANAI"
endian="big"
size="32"
variant="default"
version="3.0"
slafile="lanai3.sla"
processorspec="lanai3.pspec"
id="Lanai:BE:32:default">
<description>Lanai v3.0</description>
<compiler name="default" spec="lanai3.cspec" id="default"/>
</language>
</language_definitions>

View File

@ -0,0 +1,5 @@
<opinions>
<constraint loader="Executable and Linking Format (ELF)" compilerSpecID="default">
<constraint primary="244" processor="Lanai" endian="big" size="32" />
</constraint>
</opinions>

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<compiler_spec>
<data_organization>
<pointer_size value="4"/>
<float_size value="4" />
<double_size value="8" />
<long_double_size value="8" />
<size_alignment_map>
<entry size="1" alignment="1" />
<entry size="2" alignment="2" />
<entry size="4" alignment="4" />
<entry size="8" alignment="8" />
</size_alignment_map>
</data_organization>
<stackpointer register="sp" space="ram"/>
<funcptr align="2"/>
<spacebase name="fp" register="fp" space="ram"/>
<global>
<range space="ram"/>
<range space="register" first="0x2000" last="0x237f"/>
</global>
<default_proto>
<prototype name="__stdcall" extrapop="4" stackshift="4">
<input>
<pentry minsize="1" maxsize="500" align="4">
<addr offset="4" space="stack"/>
</pentry>
</input>
<output>
<pentry minsize="1" maxsize="4">
<register name="rv"/>
</pentry>
<pentry minsize="5" maxsize="8">
<addr space="join" piece1="r9" piece2="rv"/>
</pentry>
</output>
<unaffected>
<register name="sp"/>
<register name="fp"/>
</unaffected>
</prototype>
</default_proto>
</compiler_spec>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<processor_spec>
<programcounter register="pc"/>
</processor_spec>

View File

@ -0,0 +1,519 @@
define endian=big; define alignment=4;
define space ram type=ram_space size=4 default;
define space register type=register_space size=4;
define register offset=0 size=4 [
r0 r1 pc r3 sp fp r5 r7
rv r9 rr1 rr2 r12 r13 r14 rca
r16 r17 r18 r19 r20 r21 r22 r23
r24 r25 r26 r27 r28 r29 r30 r31
];
define token instr(32)
opcode0 = (31, 31)
opcode123 = (28, 30)
opcode012 = (29, 31)
opcode3 = (28, 28)
opcode = (28, 31)
# BR: condition codes
brddd = (25, 27)
brscc = (24, 24)
rd = (23, 27)
slmsb = (18, 22)
rs1 = (18, 22)
# RI: set flags
f = (17, 17)
# RM: increment rs1
p = (17, 17)
# RI: shift by 16
h = (16, 16)
# RM: add constant to rs1
q = (16, 16)
# RR: condition codes
rri = (16, 16)
# SL(S/I): operation
slop = (16,17)
slop1 = (17,17)
slop3 = (15,17)
rs2 = (11, 15)
# RI: immediate & immediate sign
immsign = (15, 15)
imm = (0, 15)
splsys = (13, 14)
splsse = (12, 13)
splspq = (10, 11)
# RR: operation
bbb = (8, 10)
# RR: special operation
jjjjj = (3, 7)
jmpdstrel = (2, 15)
jmpdst = (2, 24)
# BR: condition codes
brrel = (1,1)
# RR: condition codes
rrddd = (0, 2)
bri = (0, 0)
splsimmsign = (9, 9)
splsimm = (0, 9)
;
define register offset=0x100 size=32 [
callproc
];
define register offset=0x180 size=1 [
zf # zero
nf # negative
vf # overflow
cf # carry
# pseudoflags
gepf # greater than or equal
ltpf # less than
gtpf # greater than
lepf # less than or equal
];
define register offset=0x200 size=4 [
flagy
flaga
flagb
];
define context callproc
callrca = (0, 0) noflow
;
attach variables [ rd rs1 rs2 ] [
r0 r1 pc r3 sp fp r5 r7
rv r9 rr1 rr2 r12 r13 r14 rca
r16 r17 r18 r19 r20 r21 r22 r23
r24 r25 r26 r27 r28 r29 r30 r31
];
rs1val: rs1 is rs1 { export rs1; }
rs1val: rs1 is rs1 & rs1=0 { export 0:4; }
rs1val: rs1 is rs1 & rs1=1 { export 0xffffffff:4; }
rs1val: rs1 is rs1 & rs1=2 { local tmp:4=inst_start; export tmp; }
rs2val: rs2 is rs2 { export rs2; }
rs2val: rs2 is rs2 & rs2=0 { export 0:4; }
rs2val: rs2 is rs2 & rs2=1 { export 0xffffffff:4; }
rs2val: rs2 is rs2 & rs2=2 { local tmp:4=inst_start; export tmp; }
# RI (Register Immediate) instructions
with : opcode0=0 {
# why is this needed?
val: is epsilon { export 0:4; }
flags: is val & f=0 { export val; }
flags: ".f" is val & f=1 {
zf = (val == 0);
nf = (val s< 0);
vf = 0;
cf = 0;
gepf = !nf;
ltpf = nf;
gtpf = !zf & gepf;
lepf = zf | ltpf;
export val;
}
immval: imm is imm & h=0 {
local res:4 = zext(imm:2);
export res;
}
immval: shifted is imm & h=1 [ shifted = imm << 16; ] {
local res:4 = zext(imm:2) << 16;
export res;
}
# ADD
with : opcode123=0b000 {
val: is rs1val & immval { local res:4 = rs1val + immval; export res; }
flags: ".f" is f=1 & val & rs1val & immval {
zf = (val == 0);
nf = (val s< 0);
vf = scarry(rs1val, immval);
cf = carry(rs1val, immval);
gepf = (nf & vf) | (!nf & !vf);
ltpf = nf != vf;
gtpf = !zf & gepf;
lepf = zf | ltpf;
export val;
}
op: "add" is epsilon { }
# mov
with : rs1=0 {
op: "mov" is epsilon { }
operands: immval, %rd is immval & rd {}
}
}
# SUB
with : opcode123=0b010 {
val: is rs1val & immval { local res:4 = rs1val - immval; export res; }
flags: ".f" is f=1 & val & rs1val & immval {
zf = (val == 0);
nf = (val s< 0);
vf = scarry(rs1val, immval);
cf = !(rs1val < immval);
gepf = rs1val s>= immval;
ltpf = rs1val s< immval;
gtpf = rs1val s> immval;
lepf = rs1val s<= immval;
export val;
}
op: "sub" is epsilon { }
}
# AND
with : opcode123=0b100 {
val: is rs1val & immval { local res:4 = rs1val & immval; export res; }
op: "and" is epsilon { }
immval: imm is imm & h=0 {
local res:4 = zext(imm:2) | 0xffff0000;
export res;
}
immval: shifted is imm & h=1 [ shifted = imm << 16; ] {
local res:4 = (zext(imm:2) << 16) | 0xffff;
export res;
}
}
# OR
with : opcode123=0b101 {
val: is rs1val & immval { local res:4 = rs1val | immval; export res; }
op: "or" is epsilon { }
}
# XOR
with : opcode123=0b110 {
val: is rs1val & immval { local res:4 = rs1val ^ immval; export res; }
op: "xor" is epsilon { }
}
# SHIFT (untested)
with : opcode123=0b111 {
shiftnum: imm is imm {
local res:4 = sext(imm:2);
export res;
}
val: is rs1val & shiftnum & immsign=0 { local res:4 = rs1val << shiftnum; export res; }
val: is rs1val & shiftnum & h=0 & immsign=1 { local res:4 = rs1val >> -shiftnum; export res; }
val: is rs1val & shiftnum & h=1 & immsign=1 { local res:4 = rs1val s>> -shiftnum; export res; }
op: "sh" is h=0 { }
op: "sha" is h=1 { }
operands: %rs1val, shiftnum, %rd is rs1val & shiftnum & rd {
build shiftnum;
}
}
operands: %rs1val, immval, %rd is rs1val & immval & rd {
build immval;
}
:^op^flags operands is op & operands & rd & flags {
build operands;
build flags;
rd = flags;
}
:nop is rd=0 & f=0 { }
}
# RR (Register Register) instructions
with : opcode=0b1100 {
rrcond: is rrddd=0b000 & rri=0 { }
rrcond: ".f" is rrddd=0b000 & rri=1 { goto inst_next; }
# a.k.k. HI
rrcond: ".ugt" is rrddd=0b001 & rri=0 { if (!(cf & !zf)) goto inst_next; }
# a.k.a. LS
rrcond: ".ule" is rrddd=0b010 & rri=1 { if (!(!cf | zf)) goto inst_next; }
# a.k.a. CC
rrcond: ".ult" is rrddd=0b010 & rri=0 { if(cf) goto inst_next; }
# a.k.a. CS
rrcond: ".uge" is rrddd=0b011 & rri=1 { if (!cf) goto inst_next; }
flags: is val & f=0 { export val; }
flags: ".f" is val & f=1 {
zf = (val == 0);
nf = (val s< 0);
vf = 0;
cf = 0;
gepf = !nf;
ltpf = nf;
gtpf = !zf & gepf;
lepf = zf | ltpf;
export val;
}
# ADD
with : bbb=0b000 {
val: is rs1val & rs2val { local res:4 = rs1val + rs2val; export res; }
flags: ".f" is f=1 & val & rs1val & rs2val {
zf = (val == 0);
nf = (val s< 0);
vf = scarry(rs1val, rs2val);
cf = carry(rs1val, rs2val);
export val;
}
op: "add" is epsilon { }
# mov
with : rs2=0 {
op: "mov" is epsilon { }
operands: %rs1val, %rd is rs1val & rd {}
}
}
# SUB
with : bbb=0b010 {
val: is rs1val & rs2val { local res:4 = rs1val - rs2val; export res; }
flags: ".f" is f=1 & val & rs1val & rs2val {
zf = (val == 0);
nf = (val s< 0);
vf = scarry(rs1val, rs2val);
cf = !(rs1val < rs2val);
gepf = rs1val s>= rs2val;
ltpf = rs1val s< rs2val;
gtpf = rs1val s> rs2val;
lepf = rs1val s<= rs2val;
export val;
}
op: "sub" is epsilon { }
}
# AND
with : bbb=0b100 {
val: is rs1val & rs2val { local res:4 = rs1val & rs2val; export res; }
op: "and" is epsilon { }
}
# OR
with : bbb=0b101 {
val: is rs1val & rs2val { local res:4 = rs1val | rs2val; export res; }
op: "or" is epsilon { }
}
# XOR
with : bbb=0b110 {
val: is rs1val & rs2val { local res:4 = rs1val ^ rs2val; export res; }
op: "xor" is epsilon { }
}
# SHIFT (untested)
with : bbb=0b111 {
val: is rs1val & rs2val { local res:4 = rs1val << rs2val; export res; }
op: "sh" is epsilon { }
}
operands: %rs1val, %rs2val, %rd is rs1val & rs2val & rd {}
:^op^rrcond operands is op & operands & rd & rrcond & flags {
build rrcond;
build flags;
rd = flags;
}
:^op^rrcond operands is op & operands & rd & rrcond & flags & rd=2 {
build rrcond;
build flags;
delayslot(4);
goto [flags];
}
:nop is rd=0 & f=0 { }
}
# RM (Register Memory) instructions
with : opcode012=0b100 {
immsigned: imm is immsign=0 & imm { local v:4 = sext(imm:2); export v; }
immsigned: -val is immsign=1 & imm [ val=(imm^0xffff)+1; ] { local v:4 = sext(imm:2); export v; }
stdst: [%rs1val] is rs1val & imm=0 & p=0 & q=0 {
export rs1val;
}
stdst: immsigned[%rs1val] is rs1val & immsigned & p=1 & q=0 {
local v:4 = rs1val+immsigned; export v;
}
stdst: [--%rs1val] is rs1 & rs1val & imm=0xfffc & p=1 & q=1 {
rs1 = rs1val - 4;
local v:4 = rs1; export v;
}
stdst: [++%rs1val] is rs1 & rs1val & imm=0x0004 & p=1 & q=1 {
rs1 = rs1val + 4;
local v:4 = rs1val; export v;
}
stdst: [%rs1val++] is rs1 & rs1val & imm=0x0004 & p=0 & q=1 {
local v:4 = rs1;
rs1 = rs1val + 4;
export v;
}
# Stores
with : opcode3=1 {
:st %rd, stdst is rd & stdst {
*stdst = rd;
}
push: is rs1=4 & imm=0xfffc & p=1 & q=1 {}
:st %rd, stdst ! "call" is rd & stdst & rd=15 & push [ callrca=1; globalset(inst_next, callrca); ] {
*stdst = rd;
}
}
# Loads
with : opcode3=0 {
:ld stdst, %rd is rd & stdst {
rd = *stdst;
}
:ld stdst, %rd ! "return" is rd & rd=2 & stdst {
local v:4 = *stdst;
delayslot(8);
return [v];
}
}
}
# SCC (Conditional Set) instructions
with : opcode=0b1110 & brscc=0 & brrel=1 {
bcond: "t" is brddd=0b000 & bri=0 { local c:1 = 1; export c; }
bcond: "f" is brddd=0b000 & bri=1 { local c:1 = 0; export c; }
bcond: "ugt" is brddd=0b001 & bri=0 { local c:1 = (cf & !zf); export c; }
bcond: "ule" is brddd=0b001 & bri=1 { local c:1 = (!cf | zf); export c; }
bcond: "ult" is brddd=0b010 & bri=0 { local c:1 = !cf; export c; }
bcond: "uge" is brddd=0b010 & bri=1 { local c:1 = cf; export c; }
bcond: "ne" is brddd=0b011 & bri=0 { local c:1 = !zf; export c; }
bcond: "eq" is brddd=0b011 & bri=1 { local c:1 = zf; export c; }
bcond: "pl" is brddd=0b101 & bri=0 { local c:1 = !nf; export c; }
bcond: "mi" is brddd=0b101 & bri=1 { local c:1 = nf; export c; }
bcond: "ge" is brddd=0b110 & bri=0 { local c:1 = gepf; export c; }
bcond: "lt" is brddd=0b110 & bri=1 { local c:1 = ltpf; export c; }
bcond: "gt" is brddd=0b111 & bri=0 { local c:1 = gtpf; export c; }
bcond: "le" is brddd=0b111 & bri=1 { local c:1 = lepf; export c; }
:s^bcond is bcond & rs1 {
rs1 = zext(bcond);
}
}
# BR (Conditional Branch) instructions
with : opcode=0b1110 {
bcond: "t" is brddd=0b000 & bri=0 { local c:1 = 1; export c; }
bcond: "f" is brddd=0b000 & bri=1 { local c:1 = 0; export c; }
bcond: "ugt" is brddd=0b001 & bri=0 { local c:1 = (cf & !zf); export c; }
bcond: "ule" is brddd=0b001 & bri=1 { local c:1 = (!cf | zf); export c; }
bcond: "ult" is brddd=0b010 & bri=0 { local c:1 = !cf; export c; }
bcond: "uge" is brddd=0b010 & bri=1 { local c:1 = cf; export c; }
bcond: "ne" is brddd=0b011 & bri=0 { local c:1 = !zf; export c; }
bcond: "eq" is brddd=0b011 & bri=1 { local c:1 = zf; export c; }
bcond: "pl" is brddd=0b101 & bri=0 { local c:1 = !nf; export c; }
bcond: "mi" is brddd=0b101 & bri=1 { local c:1 = nf; export c; }
bcond: "ge" is brddd=0b110 & bri=0 { local c:1 = gepf; export c; }
bcond: "lt" is brddd=0b110 & bri=1 { local c:1 = ltpf; export c; }
bcond: "gt" is brddd=0b111 & bri=0 { local c:1 = gtpf; export c; }
bcond: "le" is brddd=0b111 & bri=1 { local c:1 = lepf; export c; }
reloc: target is jmpdst & brrel=0 [ target=(jmpdst<<2); ] { export *[ram]:4 target; }
reloc: %rs1val+rel is jmpdstrel & rs1val & brrel=1 & brscc=1 [ rel=(jmpdstrel<<2); ] { local target:4=(jmpdstrel<<2)+rs1val; export *[ram]:4 target; }
:b^bcond reloc ! "loop" is reloc & bcond & callrca=0 & brrel=1 & brscc=1 & jmpdstrel=0 & rs1=2 {
delayslot(4);
goto inst_start;
}
:b^bcond reloc is reloc & bcond & callrca=0 {
delayslot(4);
if (bcond) goto reloc;
}
:b^bcond target ! "call" is bcond & jmpdst & callrca=1 [ target = (jmpdst << 2); ] {
delayslot(4);
local to:4 = zext(jmpdst:4 << 2);
if (!bcond) goto <skip>;
call [to];
<skip>
}
}
# SLI (Special Load Immediate) instructions
with : opcode=0b1111 & slop=0b10 {
:mov const, %rd is rd & slmsb & imm [
const=(slmsb<<16)|(imm);
] {
rd = (slmsb << 16) | (imm);
}
:mov const, %rd ! "call" is rd & slmsb & imm & rd=15 [
const=(slmsb<<16)|(imm);
callrca=1; globalset(inst_next, callrca);
] {
rd = (slmsb << 16) | (imm);
}
}
# SLS (Special Load/Store) instructions
with : opcode=0b1111 & slop1=0 {
with : slop=0b00 {
src: [addr] is slmsb & imm [
addr=(slmsb<<16)|(imm&0xfffc);
] { local v:4 = addr; export v; }
:ld src, %rd is rd & src {
rd = *src;
}
:ld src, %rd is rd & src & rd=2 {
delayslot(8);
goto [src];
}
}
:st %rd, [addr] is slop=0b01 & slmsb & imm & rd [ addr=(slmsb<<16)|(imm&0xfffc); ] {
*addr:4 = rd;
}
}
# SPLS (Special Part-Word Load/Store) (SPLS)
with : opcode=0b1111 & slop3=0b110 {
immsigned: splsimm is splsimmsign=0 & splsimm { local v:4 = sext(splsimm:2); export v; }
immsigned: -val is splsimmsign=1 & splsimm [ val=(splsimm^0x3ff)+1; ] { local v:4 = sext(splsimm:2); export v; }
stdst: [%rs1] is rs1 & splsimm=0 & splspq=0b00 {
export rs1;
}
stdst: immsigned[%rs1] is rs1 & immsigned & splspq=0b10 {
local v:4 = rs1+immsigned; export v;
}
stdst: [--%rs1] is rs1 & splsimm=0x3ff & splspq=0b11 {
rs1 = rs1 - 1;
local v:4 = rs1; export v;
}
stdst: [++%rs1] is rs1 & splsimm=0x001 & splspq=0b11 {
rs1 = rs1 + 1;
local v:4 = rs1; export v;
}
stdst: [%rs1++] is rs1 & splsimm=0x001 & splspq=0b01 {
local v:4 = rs1;
rs1 = rs1 + 1;
export v;
}
:uld.b stdst, %rd is splsys=0b10 & splsse=0b01 & rd & stdst {
local b:1 = *stdst;
local v:4 = zext(b);
rd = v;
}
:uld.h stdst, %rd is splsys=0b00 & splsse=0b01 & rd & stdst {
local b:2 = *stdst;
local v:4 = zext(b);
rd = v;
}
:ld.b stdst, %rd is splsys=0b10 & splsse=0b00 & rd & stdst {
local b:1 = *stdst;
local v:4 = zext(b);
rd = v;
}
:ld.h stdst, %rd is splsys=0b00 & splsse=0b00 & rd & stdst {
local b:2 = *stdst;
local v:4 = zext(b);
rd = v;
}
:st.b %rd, stdst is splsys=0b11 & splsse=0b10 & rd & stdst {
*stdst = rd[0,8];
}
:st.h %rd, stdst is splsys=0b01 & splsse=0b10 & rd & stdst {
*stdst = rd[0,16];
}
}