diff options
| author | Alasdair Armstrong | 2017-11-30 20:26:49 +0000 |
|---|---|---|
| committer | Alasdair Armstrong | 2017-11-30 20:26:49 +0000 |
| commit | d61eb1760eb48158ca2ebc7eadb75f0d4882c9da (patch) | |
| tree | bdf32238488b46cfc8e047c2fed882b60e11e148 | |
| parent | dd00feacb373defbcfd8c50b9a8381c4a7db7cba (diff) | |
| parent | 16c269d6f26fd69d8788c448b87f4bb479a6ef66 (diff) | |
Merge branch 'master' into experiments
46 files changed, 2743 insertions, 2199 deletions
diff --git a/cheri/cheri_insts.sail b/cheri/cheri_insts.sail index 101414f8..3c1e34bb 100644 --- a/cheri/cheri_insts.sail +++ b/cheri/cheri_insts.sail @@ -32,6 +32,159 @@ (* SUCH DAMAGE. *) (*========================================================================*) +(* Old encodings *) +function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : 0b00000000 : 0b000) = Some(CGetPerm(rd, cb)) +function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : 0b00000000 : 0b001) = Some(CGetType(rd, cb)) +function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : 0b00000000 : 0b010) = Some(CGetBase(rd, cb)) +function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : 0b00000000 : 0b011) = Some(CGetLen(rd, cb)) +function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : 0b00000000 : 0b101) = Some(CGetTag(rd, cb)) +function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : 0b00000000 : 0b110) = Some(CGetSealed(rd, cb)) +function clause decode (0b010010 : 0b00000 : (regno) rd : 0b00000 : 0b00000000 : 0b100) = Some(CGetCause(rd)) + +function clause decode (0b010010 : 0b00110 : 0b000000000000000000000) = Some(CReturn) + +function clause decode (0b010010 : 0b01101 : (regno) rd : (regno) cb : 0b00000000 : 0b010) = Some(CGetOffset(rd, cb)) (* NB encoding does not follow pattern *) +function clause decode (0b010010 : 0b00100 : 0b00000 : 0b00000 : (regno) rt : 0b000 : 0b100) = Some(CSetCause(rt)) +function clause decode (0b010010 : 0b00100 : (regno) cd : (regno) cb : (regno) rt : 0b000 : 0b000) = Some(CAndPerm(cd, cb, rt)) +function clause decode (0b010010 : 0b01100 : (regno) rd : (regno) cb : (regno) ct : 0b000 : 0b000) = Some(CToPtr(rd, cb, ct)) + +function clause decode (0b010010 : 0b01110 : (regno) rd : (regno) cb : (regno) ct : 0b000 : 0b000) = Some(CPtrCmp(rd, cb, ct, CEQ)) +function clause decode (0b010010 : 0b01110 : (regno) rd : (regno) cb : (regno) ct : 0b000 : 0b001) = Some(CPtrCmp(rd, cb, ct, CNE)) +function clause decode (0b010010 : 0b01110 : (regno) rd : (regno) cb : (regno) ct : 0b000 : 0b010) = Some(CPtrCmp(rd, cb, ct, CLT)) +function clause decode (0b010010 : 0b01110 : (regno) rd : (regno) cb : (regno) ct : 0b000 : 0b011) = Some(CPtrCmp(rd, cb, ct, CLE)) +function clause decode (0b010010 : 0b01110 : (regno) rd : (regno) cb : (regno) ct : 0b000 : 0b100) = Some(CPtrCmp(rd, cb, ct, CLTU)) +function clause decode (0b010010 : 0b01110 : (regno) rd : (regno) cb : (regno) ct : 0b000 : 0b101) = Some(CPtrCmp(rd, cb, ct, CLEU)) +function clause decode (0b010010 : 0b01110 : (regno) rd : (regno) cb : (regno) ct : 0b000 : 0b110) = Some(CPtrCmp(rd, cb, ct, CEXEQ)) +function clause decode (0b010010 : 0b01110 : (regno) rd : (regno) cb : (regno) ct : 0b000 : 0b111) = Some(CPtrCmp(rd, cb, ct, CNEXEQ)) +function clause decode (0b010010 : 0b01101 : (regno) cd : (regno) cb : (regno) rt : 0b000 : 0b000) = Some(CIncOffset(cd, cb, rt)) +function clause decode (0b010010 : 0b01101 : (regno) cd : (regno) cb : (regno) rt : 0b000 : 0b001) = Some(CSetOffset(cd, cb, rt)) +function clause decode (0b010010 : 0b00001 : (regno) cd : (regno) cb : (regno) rt : 0b000000) = Some(CSetBounds(cd, cb, rt)) + +function clause decode (0b010010 : 0b00100 : (regno) cd : (regno) cb : 0b00000 : 0b000: 0b101) = Some(CClearTag(cd, cb)) +function clause decode (0b010010 : 0b00100 : (regno) cd : (regno) cb : (regno) rt : 0b000: 0b111) = Some(CFromPtr(cd, cb, rt)) +function clause decode (0b010010 : 0b01011 : (regno) cs : 0b00000 : (regno) rt : 0b000: 0b000) = Some(CCheckPerm(cs, rt)) +function clause decode (0b010010 : 0b01011 : (regno) cs : (regno) cb : 0b00000 : 0b000: 0b001) = Some(CCheckType(cs, cb)) +function clause decode (0b010010 : 0b00010 : (regno) cd : (regno) cs : (regno) ct : 0b000: 0b000) = Some(CSeal(cd, cs, ct)) +function clause decode (0b010010 : 0b00011 : (regno) cd : (regno) cs : (regno) ct : 0b000: 0b000) = Some(CUnseal(cd, cs, ct)) +function clause decode (0b010010 : 0b00111 : (regno) cd : (regno) cb : 0b00000 : 0b000000) = Some(CJALR(cd, cb, true)) (* CJALR *) +function clause decode (0b010010 : 0b01000 : 0b00000 : (regno) cb : 0b00000 : 0b000000) = Some(CJALR(0b00000, cb, false)) (* CJR *) + + +(* +New encodings as per CHERI ISA Appendix B.2. + +NB: Must be careful about order of matching because unused register +fields are re-used as additional function codes. +*) + +(* One arg *) +function clause decode (0b010010 : 0b00000 : (regno) rd : 0b00001 : 0b11111 : 0b111111) = Some(CGetCause(rd)) +function clause decode (0b010010 : 0b00000 : (regno) rs : 0b00010 : 0b11111 : 0b111111) = Some(CSetCause(rs)) +function clause decode (0b010010 : 0b00000 : (regno) cd : 0b00000 : 0b11111 : 0b111111) = Some(CGetPCC(cd)) +function clause decode (0b010010 : 0b00000 : (regno) cb : 0b00011 : 0b11111 : 0b111111) = Some(CJALR(0b00000, cb, false)) (* CJR *) + +(* Two arg *) +function clause decode (0b010010 : 0b00000 : (regno) cs : (regno) rt : 0b01000 : 0b111111) = Some(CCheckPerm(cs, rt)) +function clause decode (0b010010 : 0b00000 : (regno) cs : (regno) cb : 0b01001 : 0b111111) = Some(CCheckType(cs, cb)) +function clause decode (0b010010 : 0b00000 : (regno) cd : (regno) cb : 0b01011 : 0b111111) = Some(CClearTag(cd, cb)) +function clause decode (0b010010 : 0b00000 : (regno) cd : (regno) cs : 0b01010 : 0b111111) = Some(CMOVX(cd, cs, 0b00000, false)) (* CMOVE *) +function clause decode (0b010010 : 0b00000 : (regno) cd : (regno) cb : 0b01100 : 0b111111) = Some(CJALR(cd, cb, true)) (* CJALR *) + +(* Capability Inspection *) +function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : 0b00000 : 0b111111) = Some(CGetPerm(rd, cb)) +function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : 0b00001 : 0b111111) = Some(CGetType(rd, cb)) +function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : 0b00010 : 0b111111) = Some(CGetBase(rd, cb)) +function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : 0b00011 : 0b111111) = Some(CGetLen(rd, cb)) +function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : 0b00100 : 0b111111) = Some(CGetTag(rd, cb)) +function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : 0b00101 : 0b111111) = Some(CGetSealed(rd, cb)) +function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : 0b00110 : 0b111111) = Some(CGetOffset(rd, cb)) +function clause decode (0b010010 : 0b00000 : (regno) cd : (regno) rs : 0b00111 : 0b111111) = Some(CGetPCCSetOffset(cd, rs)) + +(* Three operand *) + +(* Capability Modification *) +function clause decode (0b010010 : 0b00000 : (regno) cd : (regno) cs : (regno) ct : 0b001011) = Some(CSeal(cd, cs, ct)) +function clause decode (0b010010 : 0b00000 : (regno) cd : (regno) cs : (regno) ct : 0b001100) = Some(CUnseal(cd, cs, ct)) +function clause decode (0b010010 : 0b00000 : (regno) cd : (regno) cs : (regno) rt : 0b001101) = Some(CAndPerm(cd, cs, rt)) +function clause decode (0b010010 : 0b00000 : (regno) cd : (regno) cs : (regno) rt : 0b001111) = Some(CSetOffset(cd, cs, rt)) +function clause decode (0b010010 : 0b00000 : (regno) cd : (regno) cs : (regno) rt : 0b001000) = Some(CSetBounds(cd, cs, rt)) +function clause decode (0b010010 : 0b00000 : (regno) cd : (regno) cs : (regno) rt : 0b001001) = Some(CSetBoundsExact(cd, cs, rt)) + + +function clause decode (0b010010 : 0b00000 : (regno) cd : (regno) cb : (regno) rt : 0b010001) = Some(CIncOffset(cd, cb, rt)) +function clause decode (0b010010 : 0b00000 : (regno) cd : (regno) cb : (regno) ct : 0b011101) = Some(CBuildCap(cd, cb, ct)) +function clause decode (0b010010 : 0b00000 : (regno) cd : (regno) cb : (regno) ct : 0b011110) = Some(CCopyType(cd, cb, ct)) +function clause decode (0b010010 : 0b00000 : (regno) cd : (regno) cs : (regno) ct : 0b011111) = Some(CCSeal(cd, cs, ct)) + +(* Pointer Arithmetic *) +function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : (regno) ct : 0b010010) = Some(CToPtr(rd, cb, ct)) +function clause decode (0b010010 : 0b00000 : (regno) cd : (regno) cb : (regno) rs : 0b010011) = Some(CFromPtr(cd, cb, rs)) +function clause decode (0b010010 : 0b00000 : (regno) rt : (regno) cb : (regno) cs : 0b001010) = Some(CSub(rt, cb, cs)) +function clause decode (0b010010 : 0b00000 : (regno) cd : (regno) cs : (regno) rs : 0b011011) = Some(CMOVX(cd, cs, rs, false)) (* CMOVZ *) +function clause decode (0b010010 : 0b00000 : (regno) cd : (regno) cs : (regno) rs : 0b011100) = Some(CMOVX(cd, cs, rs, true)) (* CMOVN *) + +(* Pointer Comparison *) +function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : (regno) cs : 0b010100) = Some(CPtrCmp(rd, cb, cs, CEQ)) +function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : (regno) cs : 0b010101) = Some(CPtrCmp(rd, cb, cs, CNE)) +function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : (regno) cs : 0b010110) = Some(CPtrCmp(rd, cb, cs, CLT)) +function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : (regno) cs : 0b010111) = Some(CPtrCmp(rd, cb, cs, CLE)) +function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : (regno) cs : 0b011000) = Some(CPtrCmp(rd, cb, cs, CLTU)) +function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : (regno) cs : 0b011001) = Some(CPtrCmp(rd, cb, cs, CLEU)) +function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : (regno) cs : 0b011010) = Some(CPtrCmp(rd, cb, cs, CEXEQ)) +function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : (regno) cs : 0b100001) = Some(CPtrCmp(rd, cb, cs, CNEXEQ)) + +function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : (regno) ct : 0b100000) = Some(CTestSubset(rd, cb, ct)) + +function clause decode (0b010010 : 0b01001 : (regno) cd : (bit[16]) imm) = Some(CBX(cd, imm, true)) (* CBTU *) +function clause decode (0b010010 : 0b01010 : (regno) cd : (bit[16]) imm) = Some(CBX(cd, imm, false)) (* CBTS *) +function clause decode (0b010010 : 0b10001 : (regno) cd : (bit[16]) imm) = Some(CBZ(cd, imm, false)) (* CBEZ *) +function clause decode (0b010010 : 0b10010 : (regno) cd : (bit[16]) imm) = Some(CBZ(cd, imm, true)) (* CBNZ *) + +function clause decode (0b010010 : 0b00101 : 0b00000 : 0b00000 : 0b11111111111) = Some(CReturn) +function clause decode (0b010010 : 0b00101 : (regno) cs : (regno) cb : (bit[11]) selector) = Some(CCall(cs, cb, selector)) + +function clause decode (0b010010 : 0b01111 : 0b00000 : (bit[16]) imm) = Some(ClearRegs(GPLo, imm)) +function clause decode (0b010010 : 0b01111 : 0b00001 : (bit[16]) imm) = Some(ClearRegs(GPHi, imm)) +function clause decode (0b010010 : 0b01111 : 0b00010 : (bit[16]) imm) = Some(ClearRegs(CLo, imm)) +function clause decode (0b010010 : 0b01111 : 0b00011 : (bit[16]) imm) = Some(ClearRegs(CHi, imm)) + +function clause decode (0b010010 : 0b10011 : (regno) cd : (regno) cb : (bit[11]) imm) = Some(CIncOffsetImmediate(cd, cb, imm)) +function clause decode (0b010010 : 0b10100 : (regno) cd : (regno) cb : (bit[11]) imm) = Some(CSetBoundsImmediate(cd, cb, imm)) + +function clause decode (0b110010 : (regno) rd : (regno) cb: (regno) rt : (bit[8]) offset : 0b0 : 0b00) = Some(CLoad(rd, cb, rt, offset, false, B, false)) (* CLBU *) +function clause decode (0b110010 : (regno) rd : (regno) cb: (regno) rt : (bit[8]) offset : 0b1 : 0b00) = Some(CLoad(rd, cb, rt, offset, true, B, false)) (* CLB *) +function clause decode (0b110010 : (regno) rd : (regno) cb: (regno) rt : (bit[8]) offset : 0b0 : 0b01) = Some(CLoad(rd, cb, rt, offset, false, H, false)) (* CLHU *) +function clause decode (0b110010 : (regno) rd : (regno) cb: (regno) rt : (bit[8]) offset : 0b1 : 0b01) = Some(CLoad(rd, cb, rt, offset, true, H, false)) (* CLH *) +function clause decode (0b110010 : (regno) rd : (regno) cb: (regno) rt : (bit[8]) offset : 0b0 : 0b10) = Some(CLoad(rd, cb, rt, offset, false, W, false)) (* CLWU *) +function clause decode (0b110010 : (regno) rd : (regno) cb: (regno) rt : (bit[8]) offset : 0b1 : 0b10) = Some(CLoad(rd, cb, rt, offset, true, W, false)) (* CLW *) +function clause decode (0b110010 : (regno) rd : (regno) cb: (regno) rt : (bit[8]) offset : 0b0 : 0b11) = Some(CLoad(rd, cb, rt, offset, false, D, false)) (* CLD *) + +function clause decode (0b010010 : 0b10000 : (regno) rd : (regno) cb : 0b00000001 : 0b0 : 0b00) = Some(CLoad(rd, cb, 0b00000, 0b00000000, false, B, true)) (* CLLBU *) +function clause decode (0b010010 : 0b10000 : (regno) rd : (regno) cb : 0b00000001 : 0b1 : 0b00) = Some(CLoad(rd, cb, 0b00000, 0b00000000, true, B, true)) (* CLLB *) +function clause decode (0b010010 : 0b10000 : (regno) rd : (regno) cb : 0b00000001 : 0b0 : 0b01) = Some(CLoad(rd, cb, 0b00000, 0b00000000, false, H, true)) (* CLLHU *) +function clause decode (0b010010 : 0b10000 : (regno) rd : (regno) cb : 0b00000001 : 0b1 : 0b01) = Some(CLoad(rd, cb, 0b00000, 0b00000000, true, H, true)) (* CLLH *) +function clause decode (0b010010 : 0b10000 : (regno) rd : (regno) cb : 0b00000001 : 0b0 : 0b10) = Some(CLoad(rd, cb, 0b00000, 0b00000000, false, W, true)) (* CLLWU *) +function clause decode (0b010010 : 0b10000 : (regno) rd : (regno) cb : 0b00000001 : 0b1 : 0b10) = Some(CLoad(rd, cb, 0b00000, 0b00000000, true, W, true)) (* CLLW *) +function clause decode (0b010010 : 0b10000 : (regno) rd : (regno) cb : 0b00000001 : 0b0 : 0b11) = Some(CLoad(rd, cb, 0b00000, 0b00000000, false, D, true)) (* CLLD *) + +function clause decode (0b111010 : (regno) rs : (regno) cb: (regno) rt : (bit[8]) offset : 0b0 : 0b00) = Some(CStore(rs, cb, rt, 0b00000, offset, B, false)) (* CSB *) +function clause decode (0b111010 : (regno) rs : (regno) cb: (regno) rt : (bit[8]) offset : 0b0 : 0b01) = Some(CStore(rs, cb, rt, 0b00000, offset, H, false)) (* CSH *) +function clause decode (0b111010 : (regno) rs : (regno) cb: (regno) rt : (bit[8]) offset : 0b0 : 0b10) = Some(CStore(rs, cb, rt, 0b00000, offset, W, false)) (* CSW *) +function clause decode (0b111010 : (regno) rs : (regno) cb: (regno) rt : (bit[8]) offset : 0b0 : 0b11) = Some(CStore(rs, cb, rt, 0b00000, offset, D, false)) (* CSD *) + +function clause decode (0b010010 : 0b10000 : (regno) rs : (regno) cb : (regno) rd : 0b0000 : 0b00) = Some(CStore(rs, cb, 0b00000, rd, 0b00000000, B, true)) (* CSCB *) +function clause decode (0b010010 : 0b10000 : (regno) rs : (regno) cb : (regno) rd : 0b0000 : 0b01) = Some(CStore(rs, cb, 0b00000, rd, 0b00000000, H, true)) (* CSCH *) +function clause decode (0b010010 : 0b10000 : (regno) rs : (regno) cb : (regno) rd : 0b0000 : 0b10) = Some(CStore(rs, cb, 0b00000, rd, 0b00000000, W, true)) (* CSCW *) +function clause decode (0b010010 : 0b10000 : (regno) rs : (regno) cb : (regno) rd : 0b0000 : 0b11) = Some(CStore(rs, cb, 0b00000, rd, 0b00000000, D, true)) (* CSCD *) + +function clause decode (0b111110 : (regno) cs : (regno) cb: (regno) rt : (bit[11]) offset) = Some(CSC(cs, cb, rt, 0b00000, offset, false)) +function clause decode (0b010010 : 0b10000 : (regno) cs : (regno) cb: (regno) rd : 0b00 : 0b0111) = Some(CSC(cs, cb, 0b00000, rd, 0b00000000000, true)) + +function clause decode (0b110110 : (regno) cd : (regno) cb: (regno) rt : (bit[11]) offset) = Some(CLC(cd, cb, rt, offset, false)) +function clause decode (0b010010 : 0b10000 : (regno) cd : (regno) cb: 0b0000000 : 0b1111) = Some(CLC(cd, cb, 0b00000, 0b00000000000, true)) + +function clause decode (0b010010 : 0b00100 : (regno) rt : 0x0006) = Some(C2Dump(rt)) + (* Operations that extract parts of a capability into GPR *) union ast member (regno, regno) CGetPerm @@ -42,15 +195,6 @@ union ast member (regno, regno) CGetTag union ast member (regno, regno) CGetSealed union ast member (regno, regno) CGetOffset -function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : 0b00000000 : 0b000) = Some(CGetPerm(rd, cb)) -function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : 0b00000000 : 0b001) = Some(CGetType(rd, cb)) -function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : 0b00000000 : 0b010) = Some(CGetBase(rd, cb)) -function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : 0b00000000 : 0b011) = Some(CGetLen(rd, cb)) -(* NB CGetCause Handled separately *) -function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : 0b00000000 : 0b101) = Some(CGetTag(rd, cb)) -function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : 0b00000000 : 0b110) = Some(CGetSealed(rd, cb)) -function clause decode (0b010010 : 0b01101 : (regno) rd : (regno) cb : 0b00000000 : 0b010) = Some(CGetOffset(rd, cb)) (* NB encoding does not follow pattern *) - function clause execute (CGetPerm(rd, cb)) = { (* START_CGetPerms *) @@ -141,7 +285,6 @@ function clause execute (CGetSealed(rd, cb)) = } union ast member regno CGetPCC -function clause decode (0b010010 : 0b00000 : (regno) cd : 0b00000 : 0b11111 : 0b111111) = Some(CGetPCC(cd)) function clause execute (CGetPCC(cd)) = { (* START_CGetPCC *) @@ -158,7 +301,6 @@ function clause execute (CGetPCC(cd)) = union ast member (regno, regno) CGetPCCSetOffset -function clause decode (0b010010 : 0b00000 : (regno) cd : (regno) rs : 0b00111 : 0b111111) = Some(CGetPCCSetOffset(cd, rs)) function clause execute (CGetPCCSetOffset(cd, rs)) = { (* START_CGetPCCSetOffset *) @@ -178,7 +320,6 @@ function clause execute (CGetPCCSetOffset(cd, rs)) = (* Get and Set CP2 cause register *) union ast member regno CGetCause -function clause decode (0b010010 : 0b00000 : (regno) rd : 0b00000 : 0b00000000 : 0b100) = Some(CGetCause(rd)) function clause execute (CGetCause(rd)) = { (* START_CGetCause *) @@ -191,7 +332,6 @@ function clause execute (CGetCause(rd)) = } union ast member (regno) CSetCause -function clause decode (0b010010 : 0b00100 : 0b00000 : 0b00000 : (regno) rt : 0b000 : 0b100) = Some(CSetCause(rt)) function clause execute (CSetCause((regno) rt)) = { (* START_CSetCause *) @@ -208,7 +348,6 @@ function clause execute (CSetCause((regno) rt)) = } union ast member regregreg CAndPerm -function clause decode (0b010010 : 0b00100 : (regno) cd : (regno) cb : (regno) rt : 0b000 : 0b000) = Some(CAndPerm(cd, cb, rt)) function clause execute(CAndPerm(cd, cb, rt)) = { (* START_CAndPerm *) @@ -233,7 +372,6 @@ function clause execute(CAndPerm(cd, cb, rt)) = union ast member regregreg CToPtr -function clause decode (0b010010 : 0b01100 : (regno) rd : (regno) cb : (regno) ct : 0b000 : 0b000) = Some(CToPtr(rd, cb, ct)) function clause execute(CToPtr(rd, cb, ct)) = { (* START_CToPtr *) @@ -267,7 +405,6 @@ function clause execute(CToPtr(rd, cb, ct)) = union ast member regregreg CSub -function clause decode (0b010010 : 0b00000 : (regno) rd : (regno) cb : (regno) ct : 0b001010) = Some(CSub(rd, cb, ct)) function clause execute(CSub(rd, cb, ct)) = { (* START_CSub *) @@ -286,15 +423,6 @@ function clause execute(CSub(rd, cb, ct)) = } union ast member (regno, regno, regno, CPtrCmpOp) CPtrCmp -function clause decode (0b010010 : 0b01110 : (regno) rd : (regno) cb : (regno) ct : 0b000 : 0b000) = Some(CPtrCmp(rd, cb, ct, CEQ)) -function clause decode (0b010010 : 0b01110 : (regno) rd : (regno) cb : (regno) ct : 0b000 : 0b001) = Some(CPtrCmp(rd, cb, ct, CNE)) -function clause decode (0b010010 : 0b01110 : (regno) rd : (regno) cb : (regno) ct : 0b000 : 0b010) = Some(CPtrCmp(rd, cb, ct, CLT)) -function clause decode (0b010010 : 0b01110 : (regno) rd : (regno) cb : (regno) ct : 0b000 : 0b011) = Some(CPtrCmp(rd, cb, ct, CLE)) -function clause decode (0b010010 : 0b01110 : (regno) rd : (regno) cb : (regno) ct : 0b000 : 0b100) = Some(CPtrCmp(rd, cb, ct, CLTU)) -function clause decode (0b010010 : 0b01110 : (regno) rd : (regno) cb : (regno) ct : 0b000 : 0b101) = Some(CPtrCmp(rd, cb, ct, CLEU)) -function clause decode (0b010010 : 0b01110 : (regno) rd : (regno) cb : (regno) ct : 0b000 : 0b110) = Some(CPtrCmp(rd, cb, ct, CEXEQ)) -function clause decode (0b010010 : 0b01110 : (regno) rd : (regno) cb : (regno) ct : 0b000 : 0b111) = Some(CPtrCmp(rd, cb, ct, CNEXEQ)) - function clause execute(CPtrCmp(rd, cb, ct, op)) = { (* START_CPtrCmp *) @@ -341,7 +469,6 @@ function clause execute(CPtrCmp(rd, cb, ct, op)) = } union ast member regregreg CIncOffset -function clause decode (0b010010 : 0b01101 : (regno) cd : (regno) cb : (regno) rt : 0b000 : 0b000) = Some(CIncOffset(cd, cb, rt)) function clause execute (CIncOffset(cd, cb, rt)) = { (* START_CIncOffset *) @@ -363,8 +490,29 @@ function clause execute (CIncOffset(cd, cb, rt)) = (* END_CIncOffset *) } +union ast member (regno, regno, bit[11]) CIncOffsetImmediate +function clause execute (CIncOffsetImmediate(cd, cb, imm)) = +{ + (* START_CIncOffsetImmediate *) + checkCP2usable(); + cb_val := readCapReg(cb); + let (bit[64]) imm64 = EXTZ(imm) in + if (register_inaccessible(cd)) then + raise_c2_exception(CapEx_AccessSystemRegsViolation, cd) + else if (register_inaccessible(cb)) then + raise_c2_exception(CapEx_AccessSystemRegsViolation, cb) + else if ((cb_val.tag) & (cb_val.sealed)) then + raise_c2_exception(CapEx_SealViolation, cb) + else + let (success, newCap) = incCapOffset(cb_val, imm64) in + if (success) then + writeCapReg(cd, newCap) + else + writeCapReg(cd, int_to_cap(getCapBase(cb_val) + imm64)) + (* END_CIncOffsetImmediate *) +} + union ast member regregreg CSetOffset -function clause decode (0b010010 : 0b01101 : (regno) cd : (regno) cb : (regno) rt : 0b000 : 0b001) = Some(CSetOffset(cd, cb, rt)) function clause execute (CSetOffset(cd, cb, rt)) = { (* START_CSetOffset *) @@ -387,7 +535,6 @@ function clause execute (CSetOffset(cd, cb, rt)) = } union ast member regregreg CSetBounds -function clause decode (0b010010 : 0b00001 : (regno) cd : (regno) cb : (regno) rt : 0b000000) = Some(CSetBounds(cd, cb, rt)) function clause execute (CSetBounds(cd, cb, rt)) = { (* START_CSetBounds *) @@ -416,9 +563,36 @@ function clause execute (CSetBounds(cd, cb, rt)) = (* END_CSetBounds *) } +union ast member (regno, regno, bit[11]) CSetBoundsImmediate +function clause execute (CSetBoundsImmediate(cd, cb, imm)) = +{ + (* START_CSetBoundsImmedate *) + checkCP2usable(); + cb_val := readCapReg(cb); + immU := unsigned(imm); + cursor := getCapCursor(cb_val); + base := getCapBase(cb_val); + top := getCapTop(cb_val); + newTop := cursor + immU; + if (register_inaccessible(cd)) then + raise_c2_exception(CapEx_AccessSystemRegsViolation, cd) + else if (register_inaccessible(cb)) then + raise_c2_exception(CapEx_AccessSystemRegsViolation, cb) + else if not (cb_val.tag) then + raise_c2_exception(CapEx_TagViolation, cb) + else if (cb_val.sealed) then + raise_c2_exception(CapEx_SealViolation, cb) + else if (cursor < base) then + raise_c2_exception(CapEx_LengthViolation, cb) + else if (newTop > top) then + raise_c2_exception(CapEx_LengthViolation, cb) + else + let (_, newCap) = setCapBounds(cb_val, (bit[64]) cursor, (bit[65]) newTop) in + writeCapReg(cd, newCap) (* ignore exact *) + (* END_CSetBoundsImmediate *) +} union ast member regregreg CSetBoundsExact -function clause decode (0b010010 : 0b00000 : (regno) cd : (regno) cb : (regno) rt : 0b001001) = Some(CSetBoundsExact(cd, cb, rt)) function clause execute (CSetBoundsExact(cd, cb, rt)) = { (* START_CSetBoundsExact *) @@ -451,7 +625,6 @@ function clause execute (CSetBoundsExact(cd, cb, rt)) = } union ast member (regno, regno) CClearTag -function clause decode (0b010010 : 0b00100 : (regno) cd : (regno) cb : 0b00000 : 0b000: 0b101) = Some(CClearTag(cd, cb)) function clause execute (CClearTag(cd, cb)) = { (* START_CClearTag *) @@ -469,9 +642,7 @@ function clause execute (CClearTag(cd, cb)) = } union ast member (regno,regno,regno,bool) CMOVX -function clause decode (0b010010 : 0b00000 : (regno) cd : (regno) cb : (regno) rt : 0b011100) = Some(CMOVX(cd, cb, rt, false)) (* CMOVN *) -function clause decode (0b010010 : 0b00000 : (regno) cd : (regno) cb : (regno) rt : 0b011011) = Some(CMOVX(cd, cb, rt, true)) (* CMOVZ *) -function clause execute (CMOVX(cd, cb, rt, ismovz)) = +function clause execute (CMOVX(cd, cb, rt, ismovn)) = { (* START_CMOVX *) checkCP2usable(); @@ -479,16 +650,12 @@ function clause execute (CMOVX(cd, cb, rt, ismovz)) = raise_c2_exception(CapEx_AccessSystemRegsViolation, cd) else if (register_inaccessible(cb)) then raise_c2_exception(CapEx_AccessSystemRegsViolation, cb) - else if ((rGPR(rt) == 0) ^ ismovz) then + else if ((rGPR(rt) == 0) ^ ismovn) then writeCapReg(cd) := readCapReg(cb); (* END_CMOVX *) } union ast member (ClearRegSet, bit[16]) ClearRegs -function clause decode (0b010010 : 0b01111 : 0b00000 : (bit[16]) imm) = Some(ClearRegs(GPLo, imm)) (* ClearLo *) -function clause decode (0b010010 : 0b01111 : 0b00001 : (bit[16]) imm) = Some(ClearRegs(GPHi, imm)) (* ClearHi *) -function clause decode (0b010010 : 0b01111 : 0b00010 : (bit[16]) imm) = Some(ClearRegs(CLo, imm)) (* CClearLo *) -function clause decode (0b010010 : 0b01111 : 0b00011 : (bit[16]) imm) = Some(ClearRegs(CHi, imm)) (* CClearHi *) function clause execute (ClearRegs(regset, mask)) = { (* START_ClearRegs *) @@ -511,7 +678,6 @@ function clause execute (ClearRegs(regset, mask)) = } union ast member regregreg CFromPtr -function clause decode (0b010010 : 0b00100 : (regno) cd : (regno) cb : (regno) rt : 0b000: 0b111) = Some(CFromPtr(cd, cb, rt)) function clause execute (CFromPtr(cd, cb, rt)) = { (* START_CFromPtr *) @@ -538,7 +704,6 @@ function clause execute (CFromPtr(cd, cb, rt)) = } union ast member regregreg CBuildCap -function clause decode (0b010010 : 0b00000 : (regno) cd : (regno) cb : (regno) ct : 0b011101) = Some(CBuildCap(cd, cb, ct)) function clause execute (CBuildCap(cd, cb, ct)) = { (* START_CBuildCap *) @@ -583,7 +748,6 @@ function clause execute (CBuildCap(cd, cb, ct)) = } union ast member regregreg CCopyType -function clause decode (0b010010 : 0b00000 : (regno) cd : (regno) cb : (regno) ct : 0b011110) = Some(CCopyType(cd, cb, ct)) function clause execute (CCopyType(cd, cb, ct)) = { (* START_CCopyType *) @@ -619,7 +783,6 @@ function clause execute (CCopyType(cd, cb, ct)) = } union ast member (regno, regno) CCheckPerm -function clause decode (0b010010 : 0b01011 : (regno) cs : 0b00000 : (regno) rt : 0b000: 0b000) = Some(CCheckPerm(cs, rt)) function clause execute (CCheckPerm(cs, rt)) = { (* START_CCheckPerm *) @@ -639,7 +802,6 @@ function clause execute (CCheckPerm(cs, rt)) = } union ast member (regno, regno) CCheckType -function clause decode (0b010010 : 0b01011 : (regno) cs : (regno) cb : 0b00000 : 0b000: 0b001) = Some(CCheckType(cs, cb)) function clause execute (CCheckType(cs, cb)) = { (* START_CCheckType *) @@ -665,8 +827,42 @@ function clause execute (CCheckType(cs, cb)) = (* END_CCheckType *) } +union ast member regregreg CTestSubset +function clause execute (CTestSubset(rd, cb, ct)) = +{ + (* START_CTestSubset *) + checkCP2usable(); + cb_val := readCapReg(cb); + ct_val := readCapReg(ct); + ct_top := getCapTop(ct_val); + ct_base := getCapBase(ct_val); + ct_perms := getCapPerms(ct_val); + cb_top := getCapTop(cb_val); + cb_base := getCapBase(cb_val); + cb_perms := getCapPerms(cb_val); + if (register_inaccessible(cb)) then + raise_c2_exception(CapEx_AccessSystemRegsViolation, cb) + else if (register_inaccessible(ct)) then + raise_c2_exception(CapEx_AccessSystemRegsViolation, ct) + else { + (bit[64]) result := EXTZ(if (cb_val.tag != ct_val.tag) then + 0x0 + else if (cb_val.sealed != ct_val.sealed) then + 0x0 + else if (ct_base < cb_base) then + 0x0 + else if (ct_top > cb_top) then + 0x0 + else if ((ct_perms & cb_perms) != cb_perms) then + 0x0 + else + 0x1); + wGPR(rd) := result; + } + (* END_CTestSubset *) +} + union ast member regregreg CSeal -function clause decode (0b010010 : 0b00010 : (regno) cd : (regno) cs : (regno) ct : 0b000: 0b000) = Some(CSeal(cd, cs, ct)) function clause execute (CSeal(cd, cs, ct)) = { (* START_CSeal *) @@ -708,7 +904,6 @@ function clause execute (CSeal(cd, cs, ct)) = } union ast member regregreg CCSeal -function clause decode (0b010010 : 0b00000 : (regno) cd : (regno) cs : (regno) ct : 0b011111) = Some(CCSeal(cd, cs, ct)) function clause execute (CCSeal(cd, cs, ct)) = { (* START_CCSeal *) @@ -750,7 +945,6 @@ function clause execute (CCSeal(cd, cs, ct)) = } union ast member regregreg CUnseal -function clause decode (0b010010 : 0b00011 : (regno) cd : (regno) cs : (regno) ct : 0b000: 0b000) = Some(CUnseal(cd, cs, ct)) function clause execute (CUnseal(cd, cs, ct)) = { (* START_CUnseal *) @@ -790,7 +984,6 @@ function clause execute (CUnseal(cd, cs, ct)) = } union ast member (regno, regno, bit[11]) CCall -function clause decode (0b010010 : 0b00101 : (regno) cs : (regno) cb : (bit[11]) selector) = Some(CCall(cs, cb, selector)) function clause execute (CCall(cs, cb, 0b00000000000)) = (* selector=0 *) { (* Partial implementation of CCall with checks in hardware, but raising a trap to perform trusted stack manipulation *) @@ -865,9 +1058,10 @@ function clause execute (CCall(cs, cb, 0b00000000001)) = (* selector=1 *) sealed=false; otype=0; }) in { - nextPC := (bit[64]) (getCapOffset(cs_val)); - nextPCC := csUnsealed; + delayedPC := (bit[64]) (getCapOffset(cs_val)); delayedPCC := csUnsealed; + branchPending := true; + inCCallDelay := true; C26 := capStructToCapReg({cb_val with sealed=false; otype=0; @@ -877,7 +1071,6 @@ function clause execute (CCall(cs, cb, 0b00000000001)) = (* selector=1 *) } union ast member unit CReturn -function clause decode (0b010010 : 0b00110 : 0b000000000000000000000) = Some(CReturn) function clause execute (CReturn) = { (* START_CReturn *) @@ -887,9 +1080,6 @@ function clause execute (CReturn) = } union ast member (regno, bit[16], bool) CBX -function clause decode (0b010010 : 0b01001 : (regno) cb : (bit[16]) imm) = Some(CBX(cb, imm, true)) (* CBTU *) -function clause decode (0b010010 : 0b01010 : (regno) cb : (bit[16]) imm) = Some(CBX(cb, imm, false)) (* CBTS *) - function clause execute (CBX(cb, imm, invert)) = { (* START_CBx *) @@ -905,9 +1095,23 @@ function clause execute (CBX(cb, imm, invert)) = (* END_CBx *) } +union ast member (regno, bit[16], bool) CBZ +function clause execute (CBZ(cb, imm, invert)) = +{ + (* START_CBz *) + checkCP2usable(); + if (register_inaccessible(cb)) then + raise_c2_exception(CapEx_AccessSystemRegsViolation, cb) + else if (((readCapReg(cb)) == null_cap) ^ invert) then + { + let (bit[64]) offset = (EXTS(imm : 0b00) + 4) in + delayedPC := PC + offset; + branchPending := 1; + } + (* END_CBz *) +} + union ast member (regno, regno, bool) CJALR -function clause decode (0b010010 : 0b00111 : (regno) cd : (regno) cb : 0b00000 : 0b000000) = Some(CJALR(cd, cb, true)) (* CJALR *) -function clause decode (0b010010 : 0b01000 : 0b00000 : (regno) cb : 0b00000 : 0b000000) = Some(CJALR(0b00000, cb, false)) (* CJR *) function clause execute(CJALR(cd, cb, link)) = { (* START_CJALR *) @@ -949,22 +1153,6 @@ function clause execute(CJALR(cd, cb, link)) = } union ast member (regno, regno, regno, bit[8], bool, WordType, bool) CLoad -function clause decode (0b110010 : (regno) rd : (regno) cb: (regno) rt : (bit[8]) offset : 0b0 : 0b00) = Some(CLoad(rd, cb, rt, offset, false, B, false)) (* CLBU *) -function clause decode (0b110010 : (regno) rd : (regno) cb: (regno) rt : (bit[8]) offset : 0b1 : 0b00) = Some(CLoad(rd, cb, rt, offset, true, B, false)) (* CLB *) -function clause decode (0b110010 : (regno) rd : (regno) cb: (regno) rt : (bit[8]) offset : 0b0 : 0b01) = Some(CLoad(rd, cb, rt, offset, false, H, false)) (* CLHU *) -function clause decode (0b110010 : (regno) rd : (regno) cb: (regno) rt : (bit[8]) offset : 0b1 : 0b01) = Some(CLoad(rd, cb, rt, offset, true, H, false)) (* CLH *) -function clause decode (0b110010 : (regno) rd : (regno) cb: (regno) rt : (bit[8]) offset : 0b0 : 0b10) = Some(CLoad(rd, cb, rt, offset, false, W, false)) (* CLWU *) -function clause decode (0b110010 : (regno) rd : (regno) cb: (regno) rt : (bit[8]) offset : 0b1 : 0b10) = Some(CLoad(rd, cb, rt, offset, true, W, false)) (* CLW *) -function clause decode (0b110010 : (regno) rd : (regno) cb: (regno) rt : (bit[8]) offset : 0b0 : 0b11) = Some(CLoad(rd, cb, rt, offset, false, D, false)) (* CLD *) - -function clause decode (0b010010 : 0b10000 : (regno) rd : (regno) cb : 0b00000001 : 0b0 : 0b00) = Some(CLoad(rd, cb, 0b00000, 0b00000000, false, B, true)) (* CLLBU *) -function clause decode (0b010010 : 0b10000 : (regno) rd : (regno) cb : 0b00000001 : 0b1 : 0b00) = Some(CLoad(rd, cb, 0b00000, 0b00000000, true, B, true)) (* CLLB *) -function clause decode (0b010010 : 0b10000 : (regno) rd : (regno) cb : 0b00000001 : 0b0 : 0b01) = Some(CLoad(rd, cb, 0b00000, 0b00000000, false, H, true)) (* CLLHU *) -function clause decode (0b010010 : 0b10000 : (regno) rd : (regno) cb : 0b00000001 : 0b1 : 0b01) = Some(CLoad(rd, cb, 0b00000, 0b00000000, true, H, true)) (* CLLH *) -function clause decode (0b010010 : 0b10000 : (regno) rd : (regno) cb : 0b00000001 : 0b0 : 0b10) = Some(CLoad(rd, cb, 0b00000, 0b00000000, false, W, true)) (* CLLWU *) -function clause decode (0b010010 : 0b10000 : (regno) rd : (regno) cb : 0b00000001 : 0b1 : 0b10) = Some(CLoad(rd, cb, 0b00000, 0b00000000, true, W, true)) (* CLLW *) -function clause decode (0b010010 : 0b10000 : (regno) rd : (regno) cb : 0b00000001 : 0b0 : 0b11) = Some(CLoad(rd, cb, 0b00000, 0b00000000, false, D, true)) (* CLLD *) - function clause execute (CLoad(rd, cb, rt, offset, signext, width, linked)) = { (* START_CLoad *) @@ -1017,15 +1205,6 @@ function clause execute (CLoad(rd, cb, rt, offset, signext, width, linked)) = } union ast member (regno, regno, regno, regno, bit[8], WordType, bool) CStore -function clause decode (0b111010 : (regno) rs : (regno) cb: (regno) rt : (bit[8]) offset : 0b0 : 0b00) = Some(CStore(rs, cb, rt, 0b00000, offset, B, false)) (* CSB *) -function clause decode (0b111010 : (regno) rs : (regno) cb: (regno) rt : (bit[8]) offset : 0b0 : 0b01) = Some(CStore(rs, cb, rt, 0b00000, offset, H, false)) (* CSH *) -function clause decode (0b111010 : (regno) rs : (regno) cb: (regno) rt : (bit[8]) offset : 0b0 : 0b10) = Some(CStore(rs, cb, rt, 0b00000, offset, W, false)) (* CSW *) -function clause decode (0b111010 : (regno) rs : (regno) cb: (regno) rt : (bit[8]) offset : 0b0 : 0b11) = Some(CStore(rs, cb, rt, 0b00000, offset, D, false)) (* CSD *) - -function clause decode (0b010010 : 0b10000 : (regno) rs : (regno) cb : (regno) rd : 0b0000 : 0b00) = Some(CStore(rs, cb, 0b00000, rd, 0b00000000, B, true)) (* CSCB *) -function clause decode (0b010010 : 0b10000 : (regno) rs : (regno) cb : (regno) rd : 0b0000 : 0b01) = Some(CStore(rs, cb, 0b00000, rd, 0b00000000, H, true)) (* CSCH *) -function clause decode (0b010010 : 0b10000 : (regno) rs : (regno) cb : (regno) rd : 0b0000 : 0b10) = Some(CStore(rs, cb, 0b00000, rd, 0b00000000, W, true)) (* CSCW *) -function clause decode (0b010010 : 0b10000 : (regno) rs : (regno) cb : (regno) rd : 0b0000 : 0b11) = Some(CStore(rs, cb, 0b00000, rd, 0b00000000, D, true)) (* CSCD *) function clause execute (CStore(rs, cb, rt, rd, offset, width, conditional)) = { @@ -1084,8 +1263,6 @@ function clause execute (CStore(rs, cb, rt, rd, offset, width, conditional)) = } union ast member (regno, regno, regno, regno, bit[11], bool) CSC -function clause decode (0b111110 : (regno) cs : (regno) cb: (regno) rt : (bit[11]) offset) = Some(CSC(cs, cb, rt, 0b00000, offset, false)) -function clause decode (0b010010 : 0b10000 : (regno) cs : (regno) cb: (regno) rd : 0b00 : 0b0111) = Some(CSC(cs, cb, 0b00000, rd, 0b00000000000, true)) function clause execute (CSC(cs, cb, rt, rd, offset, conditional)) = { (* START_CSC *) @@ -1136,8 +1313,6 @@ function clause execute (CSC(cs, cb, rt, rd, offset, conditional)) = } union ast member (regno, regno, regno, bit[11], bool) CLC -function clause decode (0b110110 : (regno) cd : (regno) cb: (regno) rt : (bit[11]) offset) = Some(CLC(cd, cb, rt, offset, false)) -function clause decode (0b010010 : 0b10000 : (regno) cd : (regno) cb: 0b0000000 : 0b1111) = Some(CLC(cd, cb, 0b00000, 0b00000000000, true)) function clause execute (CLC(cd, cb, rt, offset, linked)) = { (* START_CLC *) @@ -1183,6 +1358,5 @@ function clause execute (CLC(cd, cb, rt, offset, linked)) = } union ast member (regno) C2Dump -function clause decode (0b010010 : 0b00100 : (regno) rt : 0x0006) = Some(C2Dump(rt)) function clause execute (C2Dump (rt)) = () (* Currently a NOP *) diff --git a/cheri/cheri_prelude_128.sail b/cheri/cheri_prelude_128.sail index 5e63221e..cc939f59 100644 --- a/cheri/cheri_prelude_128.sail +++ b/cheri/cheri_prelude_128.sail @@ -84,7 +84,7 @@ let (CapStruct) null_cap = { E = 48; (* encoded as 0 in memory due to xor *) sealed = false; B = 0; - T = 0; + T = 0x10000; otype = 0; address = 0; } @@ -133,7 +133,7 @@ function (bit[11]) getCapHardPerms((CapStruct) cap) = : [cap.permit_execute] : [cap.global]) -function (bit[128]) capStructToMemBits((CapStruct) cap) = +function (bit[128]) capStructToMemBits128((CapStruct) cap) = let (bit[20]) b = if cap.sealed then (cap.B)[19..12] : (cap.otype)[23..12] else cap.B in let (bit[20]) t = if cap.sealed then (cap.T)[19..12] : (cap.otype)[11..0] else cap.T in ( cap.uperms @@ -147,12 +147,24 @@ function (bit[128]) capStructToMemBits((CapStruct) cap) = ) function (CapReg) capStructToCapReg((CapStruct) cap) = - ([cap.tag] : capStructToMemBits(cap)) + ([cap.tag] : capStructToMemBits128(cap)) (* Reverse of above used when reading from memory *) -function (CapReg) memBitsToCapBits((bool) tag, (bit[128]) b) = +function (CapReg) memBitsToCapBits128((bool) tag, (bit[128]) b) = ([tag] : b) +(* When saving/restoring capabilities xor them with bits of null_cap -- + this ensures that canonical null_cap is always all-zeros in memory + even though it may have bits set logically (e.g. length or exponent *) + +let (bit[128]) null_cap_bits = capStructToMemBits128(null_cap) + +function (bit[128]) capStructToMemBits((CapStruct) cap) = + capStructToMemBits128(cap) ^ null_cap_bits + +function (bit[129]) memBitsToCapBits((bool) tag, (bit[128]) b) = + memBitsToCapBits128(tag, b ^ null_cap_bits) + function (bit[31]) getCapPerms((CapStruct) cap) = let (bit[15]) perms = EXTS(getCapHardPerms(cap)) in (* NB access_system copied into 14-11 *) (0x000 (* uperms 30-19 *) @@ -191,23 +203,23 @@ function [|-1:1|] a_top_correction((bit[20]) a_mid, (bit[20]) R, (bit[20]) bound } function uint64 getCapBase((CapStruct) c) = - let ([|45|]) E = min(unsigned(c.E), 45) in + let ([|48|]) E = min(unsigned(c.E), 48) in let (bit[20]) Bc = c.B in let (bit[65]) a = EXTZ(c.address) in let (bit[20]) R = Bc - 0x01000 in (* wraps *) - let (bit[20]) a_mid = a[(E + 19)..E] in + let (bit[20]) a_mid = mask(a >> E) in let correction = a_top_correction(a_mid, R, Bc) in let a_top = a >> (E+20) in let (bit[64]) base = EXTZ((a_top + correction) : Bc) << E in unsigned(base) function CapLen getCapTop ((CapStruct) c) = - let ([|45|]) E = min(unsigned(c.E), 45) in + let ([|45|]) E = min(unsigned(c.E), 48) in let (bit[20]) Bc = c.B in let (bit[20]) T = c.T in let (bit[65]) a = EXTZ(c.address) in let (bit[20]) R = Bc - 0x01000 in (* wraps *) - let (bit[20]) a_mid = a[(E + 19)..E] in + let (bit[20]) a_mid = mask(a >> E) in let correction = a_top_correction(a_mid, R, T) in let a_top = a >> (E+20) in let (bit[65]) top1 = EXTZ((a_top + correction) : T) in diff --git a/cheri/cheri_prelude_256.sail b/cheri/cheri_prelude_256.sail index 7b42020d..988cfe49 100644 --- a/cheri/cheri_prelude_256.sail +++ b/cheri/cheri_prelude_256.sail @@ -86,7 +86,7 @@ let (CapStruct) null_cap = { sealed = false; offset = 0; base = 0; - length = 0; + length = 0xffffffffffffffff; } def Nat cap_size_t = 32 (* cap size in bytes *) @@ -138,7 +138,7 @@ function (bit[31]) getCapPerms((CapStruct) cap) = - this is the same as register format except for the offset, field which is stored as an absolute cursor on CHERI due to uarch optimisation *) -function (bit[256]) capStructToMemBits((CapStruct) cap) = +function (bit[256]) capStructToMemBits256((CapStruct) cap) = ( cap.padding : cap.otype @@ -152,13 +152,25 @@ function (bit[256]) capStructToMemBits((CapStruct) cap) = (* Reverse of above used when reading from memory *) -function (bit[257]) memBitsToCapBits((bool) tag, (bit[256]) b) = +function (bit[257]) memBitsToCapBits256((bool) tag, (bit[256]) b) = ([tag] : b[255..192] : ((bit[64])(b[191..128] - b[127..64])) : b[127..0] ) +(* When saving/restoring capabilities xor them with bits of null_cap -- + this ensures that canonical null_cap is always all-zeros in memory + even though it may have bits set logically (e.g. length or exponent *) + +function (bit[256]) capStructToMemBits((CapStruct) cap) = + let (bit[256]) null_cap_bits = capStructToMemBits256(null_cap) in + capStructToMemBits256(cap) ^ null_cap_bits + +function (bit[257]) memBitsToCapBits((bool) tag, (bit[256]) b) = + let (bit[256]) null_cap_bits = capStructToMemBits256(null_cap) in + memBitsToCapBits256(tag, b ^ null_cap_bits) + function (CapReg) capStructToCapReg((CapStruct) cap) = ( [cap.tag] diff --git a/cheri/cheri_prelude_common.sail b/cheri/cheri_prelude_common.sail index f5fcd095..a2d3b441 100644 --- a/cheri/cheri_prelude_common.sail +++ b/cheri/cheri_prelude_common.sail @@ -45,6 +45,7 @@ scattered function option<ast> decode register CapReg PCC register CapReg nextPCC register CapReg delayedPCC +register (bit[1]) inCCallDelay register CapReg C00 (* aka default data capability, DDC *) register CapReg C01 register CapReg C02 @@ -115,6 +116,7 @@ typedef CapEx = enumerate { CapEx_PermitSealViolation; CapEx_AccessSystemRegsViolation; CapEx_PermitCCallViolation; + CapEx_AccessCCallIDCViolation; } typedef CPtrCmpOp = enumerate { @@ -158,6 +160,7 @@ function (bit[8]) CapExCode((CapEx) ex) = case CapEx_PermitSealViolation -> 0x17 case CapEx_AccessSystemRegsViolation -> 0x18 case CapEx_PermitCCallViolation -> 0x19 + case CapEx_AccessCCallIDCViolation -> 0x1a } typedef CapCauseReg = register bits [15:0] { @@ -204,7 +207,11 @@ function forall Type 'o . 'o raise_c2_exception8((CapEx) capEx, (bit[8]) regnum) } function forall Type 'o . 'o raise_c2_exception((CapEx) capEx, (regno) regnum) = - raise_c2_exception8(capEx, 0b000 : regnum) + let reg8 = 0b000 : regnum in + if ((capEx == CapEx_AccessSystemRegsViolation) & (regnum == 26 (* IDC *))) then + raise_c2_exception8(CapEx_AccessCCallIDCViolation, reg8) + else + raise_c2_exception8(capEx, reg8) function forall Type 'o . 'o raise_c2_exception_noreg((CapEx) capEx) = raise_c2_exception8(capEx, 0xff) @@ -213,7 +220,8 @@ function bool pcc_access_system_regs () = let pcc = capRegToCapStruct(PCC) in (pcc.access_system_regs) -function bool register_inaccessible((regno) r) = +function bool register_inaccessible((regno) r) = + if ((r == 26 (* IDC *)) & ((bool)inCCallDelay)) then true else (* XXX interpreter crash without cast *) let (bool) is_sys_reg = switch(r) { case 0b11011 -> true case 0b11100 -> true diff --git a/etc/regfp.sail b/etc/regfp.sail index fb15310a..cc057f2e 100644 --- a/etc/regfp.sail +++ b/etc/regfp.sail @@ -32,21 +32,31 @@ typedef diafp = const union { typedef read_kind = enumerate { Read_plain; - Read_tag; Read_reserve; Read_acquire; Read_exclusive; Read_exclusive_acquire; - Read_stream + Read_stream; + Read_RISCV_acquire; + Read_RISCV_strong_acquire; + Read_RISCV_reserved; + Read_RISCV_reserved_acquire; + Read_RISCV_reserved_strong_acquire; + Read_X86_locked; } typedef write_kind = enumerate { Write_plain; - Write_tag; Write_conditional; Write_release; Write_exclusive; Write_exclusive_release; + Write_RISCV_release; + Write_RISCV_strong_release; + Write_RISCV_conditional; + Write_RISCV_conditional_release; + Write_RISCV_conditional_strong_release; + Write_X86_locked; } typedef barrier_kind = enumerate { @@ -62,6 +72,13 @@ typedef barrier_kind = enumerate { Barrier_DSB_LD; Barrier_ISB; Barrier_MIPS_SYNC; + Barrier_RISCV_rw_rw; + Barrier_RISCV_r_rw; + Barrier_RISCV_r_r; + Barrier_RISCV_rw_w; + Barrier_RISCV_w_w; + Barrier_RISCV_i; + Barrier_x86_MFENCE; } typedef trans_kind = enumerate { @@ -72,6 +89,7 @@ typedef instruction_kind = const union { (barrier_kind) IK_barrier; (read_kind) IK_mem_read; (write_kind) IK_mem_write; + (read_kind, write_kind) IK_mem_rmw; IK_cond_branch; (trans_kind) IK_trans; IK_simple diff --git a/mips/mips_prelude.sail b/mips/mips_prelude.sail index a4098486..382e4d7f 100644 --- a/mips/mips_prelude.sail +++ b/mips/mips_prelude.sail @@ -472,6 +472,13 @@ function AccessLevel getAccessLevel() = case _ -> User (* behaviour undefined, assume user *) } +function ([|2|]) int_of_accessLevel((AccessLevel)x) = + switch (x) { + case User -> 0 + case Supervisor -> 1 + case Kernel -> 2 + } + function unit checkCP0Access () = { let accessLevel = getAccessLevel() in diff --git a/mips/mips_tlb.sail b/mips/mips_tlb.sail index 2e40deed..d72e0e75 100644 --- a/mips/mips_tlb.sail +++ b/mips/mips_tlb.sail @@ -108,7 +108,7 @@ function (bit[64], bool) TLBTranslateC ((bit[64]) vAddr, (MemAccessType) accessT case 0b01 -> (Supervisor, None) (* xsseg - supervisor mapped *) case 0b00 -> (User, None) (* xuseg - user mapped *) } in - if (((nat)currentAccessLevel) < ((nat)requiredLevel)) then + if ((int_of_accessLevel(currentAccessLevel)) < (int_of_accessLevel(requiredLevel))) then (SignalExceptionBadAddr(if (accessType == StoreData) then AdES else AdEL, vAddr)) else let (pa, c) = switch(addr) { diff --git a/mips/run_embed.ml b/mips/run_embed.ml index 463caffd..1bb6d5f6 100644 --- a/mips/run_embed.ml +++ b/mips/run_embed.ml @@ -219,7 +219,10 @@ module CHERI_model : ISA_model = struct let pc_vaddr = unsigned_big(Cheri_embed._PC) in let npc_addr = add_int_big_int 4 pc_vaddr in let npc_vec = to_vec_dec_big (bi64, npc_addr) in - set_register Cheri_embed._nextPC npc_vec + begin + set_register Cheri_embed._nextPC npc_vec; + set_register Cheri_embed._inCCallDelay (to_vec_dec_int (1, 0)) + end let get_pc () = unsigned_big (Cheri_embed._PC) @@ -250,7 +253,7 @@ module CHERI128_model : ISA_model = struct let start_addr = (to_vec_dec_big (bi64, big_int_of_string "0x9000000040000000")) in set_register Cheri128_embed._nextPC start_addr; set_register_field_bit Cheri128_embed._CP0Status "BEV" Vone; - let initial_cap_val_int = big_int_of_string "0x1fffe0000000800000000000000000000" in (* hex((0x80000 << 64) + (0x7fff << 113) + (1 << 128)) *) + let initial_cap_val_int = big_int_of_string "0x1fffe6000000100000000000000000000" in (* hex((0x10000 << 64) + (48 << 105) + (0x7fff << 113) + (1 << 128)) T=0x10000 E=48 perms=0x7fff tag=1 *) let initial_cap_vec = to_vec_dec ((bi129), initial_cap_val_int) in set_register Cheri128_embed._PCC initial_cap_vec; set_register Cheri128_embed._nextPCC initial_cap_vec; @@ -277,7 +280,10 @@ module CHERI128_model : ISA_model = struct let pc_vaddr = unsigned_big(Cheri128_embed._PC) in let npc_addr = add_int_big_int 4 pc_vaddr in let npc_vec = to_vec_dec_big (bi64, npc_addr) in - set_register Cheri128_embed._nextPC npc_vec + begin + set_register Cheri128_embed._nextPC npc_vec; + set_register Cheri128_embed._inCCallDelay (to_vec_dec_int (1, 0)) + end let get_pc () = unsigned_big (Cheri128_embed._PC) diff --git a/risc-v/Makefile b/risc-v/Makefile index 856a48eb..8449c7c4 100644 --- a/risc-v/Makefile +++ b/risc-v/Makefile @@ -1,13 +1,14 @@ SAIL:=../src/sail.native -SOURCES:=riscv.sail ../etc/regfp.sail riscv_regfp.sail +SOURCES:=riscv_types.sail riscv.sail ../etc/regfp.sail riscv_regfp.sail all: lem_ast shallow lem_ast: $(SOURCES) $(SAIL) - $(SAIL) -lem_ast $(SOURCES) + $(SAIL) -lem_ast $(SOURCES) -o riscv shallow: $(SOURCES) $(SAIL) - $(SAIL) -lem_lib Riscv_extras_embed -lem $(SOURCES) + $(SAIL) -lem_lib Riscv_extras_embed -lem $(SOURCES) -o riscv clean: - rm -f riscv.lem riscv_embed*.lem + rm -f riscv.lem riscv_embed*.lem riscv_toFromInterp.lem + rm -f riscv_type*.lem diff --git a/risc-v/hgen/ast.hgen b/risc-v/hgen/ast.hgen index 8983b5ae..b1968173 100644 --- a/risc-v/hgen/ast.hgen +++ b/risc-v/hgen/ast.hgen @@ -5,9 +5,13 @@ | `RISCVIType of bit12 * reg * reg * riscvIop | `RISCVShiftIop of bit6 * reg * reg * riscvSop | `RISCVRType of reg * reg * reg * riscvRop -| `RISCVLoad of bit12 * reg * reg * bool * wordWidth -| `RISCVStore of bit12 * reg * reg * wordWidth +| `RISCVLoad of bit12 * reg * reg * bool * wordWidth * bool * bool +| `RISCVStore of bit12 * reg * reg * wordWidth * bool * bool | `RISCVADDIW of bit12 * reg * reg | `RISCVSHIFTW of bit5 * reg * reg * riscvSop | `RISCVRTYPEW of reg * reg * reg * riscvRopw | `RISCVFENCE of bit4 * bit4 +| `RISCVFENCEI +| `RISCVLoadRes of bool * bool * reg * wordWidth * reg +| `RISCVStoreCon of bool * bool * reg * reg * wordWidth * reg +| `RISCVAMO of riscvAmoop * bool * bool * reg * reg * wordWidth * reg diff --git a/risc-v/hgen/fold.hgen b/risc-v/hgen/fold.hgen index 03318805..4c51e114 100644 --- a/risc-v/hgen/fold.hgen +++ b/risc-v/hgen/fold.hgen @@ -1,13 +1,16 @@ -| `RISCVThreadStart -> (y_reg, y_sreg) -| `RISCVUTYPE (_, r0, _) -> fold_reg r0 (y_reg, y_sreg) -| `RISCVJAL (_, r0) -> fold_reg r0 (y_reg, y_sreg) -| `RISCVJALR (_, r0, r1) -> fold_reg r0 (fold_reg r1 (y_reg, y_sreg)) -| `RISCVBType (_, r0, r1, _) -> fold_reg r0 (fold_reg r1 (y_reg, y_sreg)) -| `RISCVIType (_, r0, r1, _) -> fold_reg r0 (fold_reg r1 (y_reg, y_sreg)) -| `RISCVShiftIop (_, r0, r1, _) -> fold_reg r0 (fold_reg r1 (y_reg, y_sreg)) -| `RISCVRType (r0, r1, r2, _) -> fold_reg r0 (fold_reg r1 (fold_reg r2 (y_reg, y_sreg))) -| `RISCVLoad (_, r0, r1, _, _) -> fold_reg r0 (fold_reg r1 (y_reg, y_sreg)) -| `RISCVStore (_, r0, r1, _) -> fold_reg r0 (fold_reg r1 (y_reg, y_sreg)) -| `RISCVADDIW (_, r0, r1) -> fold_reg r0 (fold_reg r1 (y_reg, y_sreg)) -| `RISCVSHIFTW (_, r0, r1, _) -> fold_reg r0 (fold_reg r1 (y_reg, y_sreg)) -| `RISCVRTYPEW (r0, r1, r2, _) -> fold_reg r0 (fold_reg r1 (fold_reg r2 (y_reg, y_sreg))) +| `RISCVThreadStart -> (y_reg, y_sreg) +| `RISCVUTYPE (_, r0, _) -> fold_reg r0 (y_reg, y_sreg) +| `RISCVJAL (_, r0) -> fold_reg r0 (y_reg, y_sreg) +| `RISCVJALR (_, r0, r1) -> fold_reg r0 (fold_reg r1 (y_reg, y_sreg)) +| `RISCVBType (_, r0, r1, _) -> fold_reg r0 (fold_reg r1 (y_reg, y_sreg)) +| `RISCVIType (_, r0, r1, _) -> fold_reg r0 (fold_reg r1 (y_reg, y_sreg)) +| `RISCVShiftIop (_, r0, r1, _) -> fold_reg r0 (fold_reg r1 (y_reg, y_sreg)) +| `RISCVRType (r0, r1, r2, _) -> fold_reg r0 (fold_reg r1 (fold_reg r2 (y_reg, y_sreg))) +| `RISCVLoad (_, r0, r1, _, _, _, _) -> fold_reg r0 (fold_reg r1 (y_reg, y_sreg)) +| `RISCVStore (_, r0, r1, _, _, _) -> fold_reg r0 (fold_reg r1 (y_reg, y_sreg)) +| `RISCVADDIW (_, r0, r1) -> fold_reg r0 (fold_reg r1 (y_reg, y_sreg)) +| `RISCVSHIFTW (_, r0, r1, _) -> fold_reg r0 (fold_reg r1 (y_reg, y_sreg)) +| `RISCVRTYPEW (r0, r1, r2, _) -> fold_reg r0 (fold_reg r1 (fold_reg r2 (y_reg, y_sreg))) +| `RISCVLoadRes (_, _, rs1, _, rd) -> fold_reg rs1 (fold_reg rd (y_reg, y_sreg)) +| `RISCVStoreCon (_, _, rs2, rs1, _, rd) -> fold_reg rs2 (fold_reg rs1 (fold_reg rd (y_reg, y_sreg))) +| `RISCVAMO (_, _, _, rs2, rs1, _, rd) -> fold_reg rs2 (fold_reg rs1 (fold_reg rd (y_reg, y_sreg))) diff --git a/risc-v/hgen/herdtools_ast_to_shallow_ast.hgen b/risc-v/hgen/herdtools_ast_to_shallow_ast.hgen index 50026612..07c1d082 100644 --- a/risc-v/hgen/herdtools_ast_to_shallow_ast.hgen +++ b/risc-v/hgen/herdtools_ast_to_shallow_ast.hgen @@ -3,10 +3,10 @@ translate_imm20 "imm" imm, translate_reg "rd" rd, translate_uop op) -| `RISCVJAL(imm, rd) -> JAL0( +| `RISCVJAL(imm, rd) -> RISCV_JAL( translate_imm21 "imm" imm, translate_reg "rd" rd) -| `RISCVJALR(imm, rs, rd) -> JALR0( +| `RISCVJALR(imm, rs, rd) -> RISCV_JALR( translate_imm12 "imm" imm, translate_reg "rs" rd, translate_reg "rd" rd) @@ -30,17 +30,21 @@ translate_reg "rs1" rs1, translate_reg "rd" rd, translate_rop op) -| `RISCVLoad(imm, rs, rd, unsigned, width) -> LOAD( +| `RISCVLoad(imm, rs, rd, unsigned, width, aq, rl) -> LOAD( translate_imm12 "imm" imm, translate_reg "rs" rs, translate_reg "rd" rd, translate_bool "unsigned" unsigned, - translate_wordWidth width) -| `RISCVStore(imm, rs, rd, width) -> STORE ( + translate_wordWidth width, + translate_bool "aq" aq, + translate_bool "rl" rl) +| `RISCVStore(imm, rs, rd, width, aq, rl) -> STORE ( translate_imm12 "imm" imm, translate_reg "rs" rs, translate_reg "rd" rd, - translate_wordWidth width) + translate_wordWidth width, + translate_bool "aq" aq, + translate_bool "rl" rl) | `RISCVADDIW(imm, rs, rd) -> ADDIW( translate_imm12 "imm" imm, translate_reg "rs" rs, @@ -56,5 +60,27 @@ translate_reg "rd" rd, translate_ropw op) | `RISCVFENCE(pred, succ) -> FENCE( - translate_imm4 "pred" pred, - translate_imm4 "succ" succ) + translate_imm4 "pred" pred, + translate_imm4 "succ" succ) +| `RISCVFENCEI -> FENCEI +| `RISCVLoadRes(aq, rl, rs1, width, rd) -> LOADRES( + translate_bool "aq" aq, + translate_bool "rl" rl, + translate_reg "rs1" rs1, + translate_wordWidth width, + translate_reg "rd" rd) +| `RISCVStoreCon(aq, rl, rs2, rs1, width, rd) -> STORECON( + translate_bool "aq" aq, + translate_bool "rl" rl, + translate_reg "rs2" rs2, + translate_reg "rs1" rs1, + translate_wordWidth width, + translate_reg "rd" rd) +| `RISCVAMO (op, aq, rl, rs2, rs1, width, rd) -> AMO( + translate_amoop op, + translate_bool "aq" aq, + translate_bool "rl" rl, + translate_reg "rs2" rs2, + translate_reg "rs1" rs1, + translate_wordWidth width, + translate_reg "rd" rd) diff --git a/risc-v/hgen/herdtools_types_to_shallow_types.hgen b/risc-v/hgen/herdtools_types_to_shallow_types.hgen index 4d8bd87a..e6edd24d 100644 --- a/risc-v/hgen/herdtools_types_to_shallow_types.hgen +++ b/risc-v/hgen/herdtools_types_to_shallow_types.hgen @@ -4,48 +4,59 @@ let translate_reg name value = Sail_values.to_vec0 is_inc (Nat_big_num.of_int 5,Nat_big_num.of_int (reg_to_int value)) let translate_uop op = match op with - | RISCVLUI -> LUI0 - | RISCVAUIPC -> AUIPC + | RISCVLUI -> RISCV_LUI + | RISCVAUIPC -> RISCV_AUIPC let translate_bop op = match op with - | RISCVBEQ -> BEQ0 - | RISCVBNE -> BNE - | RISCVBLT -> BLT - | RISCVBGE -> BGE - | RISCVBLTU -> BLTU - | RISCVBGEU -> BGEU + | RISCVBEQ -> RISCV_BEQ + | RISCVBNE -> RISCV_BNE + | RISCVBLT -> RISCV_BLT + | RISCVBGE -> RISCV_BGE + | RISCVBLTU -> RISCV_BLTU + | RISCVBGEU -> RISCV_BGEU let translate_iop op = match op with - | RISCVADDI -> ADDI0 - | RISCVSLTI -> SLTI0 - | RISCVSLTIU -> SLTIU0 - | RISCVXORI -> XORI0 - | RISCVORI -> ORI0 - | RISCVANDI -> ANDI0 + | RISCVADDI -> RISCV_ADDI + | RISCVSLTI -> RISCV_SLTI + | RISCVSLTIU -> RISCV_SLTIU + | RISCVXORI -> RISCV_XORI + | RISCVORI -> RISCV_ORI + | RISCVANDI -> RISCV_ANDI let translate_sop op = match op with - | RISCVSLLI -> SLLI - | RISCVSRLI -> SRLI - | RISCVSRAI -> SRAI + | RISCVSLLI -> RISCV_SLLI + | RISCVSRLI -> RISCV_SRLI + | RISCVSRAI -> RISCV_SRAI let translate_rop op = match op with - | RISCVADD -> ADD0 - | RISCVSUB -> SUB0 - | RISCVSLL -> SLL0 - | RISCVSLT -> SLT0 - | RISCVSLTU -> SLTU0 - | RISCVXOR -> XOR0 - | RISCVSRL -> SRL0 - | RISCVSRA -> SRA0 - | RISCVOR -> OR0 - | RISCVAND -> AND0 + | RISCVADD -> RISCV_ADD + | RISCVSUB -> RISCV_SUB + | RISCVSLL -> RISCV_SLL + | RISCVSLT -> RISCV_SLT + | RISCVSLTU -> RISCV_SLTU + | RISCVXOR -> RISCV_XOR + | RISCVSRL -> RISCV_SRL + | RISCVSRA -> RISCV_SRA + | RISCVOR -> RISCV_OR + | RISCVAND -> RISCV_AND let translate_ropw op = match op with - | RISCVADDW -> ADDW - | RISCVSUBW -> SUBW - | RISCVSLLW -> SLLW - | RISCVSRLW -> SRLW - | RISCVSRAW -> SRAW + | RISCVADDW -> RISCV_ADDW + | RISCVSUBW -> RISCV_SUBW + | RISCVSLLW -> RISCV_SLLW + | RISCVSRLW -> RISCV_SRLW + | RISCVSRAW -> RISCV_SRAW + +let translate_amoop op = match op with + | RISCVAMOSWAP -> AMOSWAP + | RISCVAMOADD -> AMOADD + | RISCVAMOXOR -> AMOXOR + | RISCVAMOAND -> AMOAND + | RISCVAMOOR -> AMOOR + | RISCVAMOMIN -> AMOMIN + | RISCVAMOMAX -> AMOMAX + | RISCVAMOMINU -> AMOMINU + | RISCVAMOMAXU -> AMOMAXU let translate_wordWidth op = match op with | RISCVBYTE -> BYTE diff --git a/risc-v/hgen/lexer.hgen b/risc-v/hgen/lexer.hgen index 5f2c8326..e42b8a62 100644 --- a/risc-v/hgen/lexer.hgen +++ b/risc-v/hgen/lexer.hgen @@ -33,18 +33,44 @@ "or", RTYPE{op=RISCVOR}; "and", RTYPE{op=RISCVAND}; -"lb", LOAD{unsigned=false; width=RISCVBYTE}; -"lbu", LOAD{unsigned=true; width=RISCVBYTE}; -"lh", LOAD{unsigned=false; width=RISCVHALF}; -"lhu", LOAD{unsigned=true; width=RISCVHALF}; -"lw", LOAD{unsigned=false; width=RISCVWORD}; -"lwu", LOAD{unsigned=true; width=RISCVWORD}; -"ld", LOAD{unsigned=false; width=RISCVDOUBLE}; - -"sb", STORE{width=RISCVBYTE}; -"sh", STORE{width=RISCVHALF}; -"sw", STORE{width=RISCVWORD}; -"sd", STORE{width=RISCVDOUBLE}; +"lb", LOAD{unsigned=false; width=RISCVBYTE; aq=false; rl=false}; +"lbu", LOAD{unsigned=true; width=RISCVBYTE; aq=false; rl=false}; +"lh", LOAD{unsigned=false; width=RISCVHALF; aq=false; rl=false}; +"lhu", LOAD{unsigned=true; width=RISCVHALF; aq=false; rl=false}; +"lw", LOAD{unsigned=false; width=RISCVWORD; aq=false; rl=false}; +"lwu", LOAD{unsigned=true; width=RISCVWORD; aq=false; rl=false}; +"ld", LOAD{unsigned=false; width=RISCVDOUBLE; aq=false; rl=false}; + +"lb.aq", LOAD{unsigned=false; width=RISCVBYTE; aq=true; rl=false}; +"lbu.aq", LOAD{unsigned=true; width=RISCVBYTE; aq=true; rl=false}; +"lh.aq", LOAD{unsigned=false; width=RISCVHALF; aq=true; rl=false}; +"lhu.aq", LOAD{unsigned=true; width=RISCVHALF; aq=true; rl=false}; +"lw.aq", LOAD{unsigned=false; width=RISCVWORD; aq=true; rl=false}; +"lwu.aq", LOAD{unsigned=true; width=RISCVWORD; aq=true; rl=false}; +"ld.aq", LOAD{unsigned=false; width=RISCVDOUBLE; aq=true; rl=false}; + +"lb.aq.rl", LOAD{unsigned=false; width=RISCVBYTE; aq=true; rl=true}; +"lbu.aq.rl", LOAD{unsigned=true; width=RISCVBYTE; aq=true; rl=true}; +"lh.aq.rl", LOAD{unsigned=false; width=RISCVHALF; aq=true; rl=true}; +"lhu.aq.rl", LOAD{unsigned=true; width=RISCVHALF; aq=true; rl=true}; +"lw.aq.rl", LOAD{unsigned=false; width=RISCVWORD; aq=true; rl=true}; +"lwu.aq.rl", LOAD{unsigned=true; width=RISCVWORD; aq=true; rl=true}; +"ld.aq.rl", LOAD{unsigned=false; width=RISCVDOUBLE; aq=true; rl=true}; + +"sb", STORE{width=RISCVBYTE; aq=false; rl=false}; +"sh", STORE{width=RISCVHALF; aq=false; rl=false}; +"sw", STORE{width=RISCVWORD; aq=false; rl=false}; +"sd", STORE{width=RISCVDOUBLE; aq=false; rl=false}; + +"sb.rl", STORE{width=RISCVBYTE; aq=false; rl=true}; +"sh.rl", STORE{width=RISCVHALF; aq=false; rl=true}; +"sw.rl", STORE{width=RISCVWORD; aq=false; rl=true}; +"sd.rl", STORE{width=RISCVDOUBLE; aq=false; rl=true}; + +"sb.aq.rl", STORE{width=RISCVBYTE; aq=true; rl=true}; +"sh.aq.rl", STORE{width=RISCVHALF; aq=true; rl=true}; +"sw.aq.rl", STORE{width=RISCVWORD; aq=true; rl=true}; +"sd.aq.rl", STORE{width=RISCVDOUBLE; aq=true; rl=true}; "addiw", ADDIW (); @@ -62,3 +88,103 @@ "r", FENCEOPTION Fence_R; "w", FENCEOPTION Fence_W; "rw", FENCEOPTION Fence_RW; + +"fence.i", FENCEI (); + +"lr.w", LOADRES {width=RISCVWORD; aq=false; rl=false}; +"lr.w.aq", LOADRES {width=RISCVWORD; aq=true; rl=false}; +"lr.w.aq.rl", LOADRES {width=RISCVWORD; aq=true; rl=true}; +"lr.d", LOADRES {width=RISCVDOUBLE; aq=false; rl=false}; +"lr.d.aq", LOADRES {width=RISCVDOUBLE; aq=true; rl=false}; +"lr.d.aq.rl", LOADRES {width=RISCVDOUBLE; aq=true; rl=true}; + +"sc.w", STORECON {width=RISCVWORD; aq=false; rl=false}; +"sc.w.rl", STORECON {width=RISCVWORD; aq=false; rl=true}; +"sc.w.aq.rl", STORECON {width=RISCVWORD; aq=true; rl=true}; +"sc.d", STORECON {width=RISCVDOUBLE; aq=false; rl=false}; +"sc.d.rl", STORECON {width=RISCVDOUBLE; aq=false; rl=true}; +"sc.d.aq.rl", STORECON {width=RISCVDOUBLE; aq=true; rl=true}; + +"amoswap.w", AMO {width=RISCVWORD; aq=false; rl=false; op=RISCVAMOSWAP}; +"amoadd.w", AMO {width=RISCVWORD; aq=false; rl=false; op=RISCVAMOADD}; +"amoand.w", AMO {width=RISCVWORD; aq=false; rl=false; op=RISCVAMOAND}; +"amoor.w", AMO {width=RISCVWORD; aq=false; rl=false; op=RISCVAMOOR}; +"amoxor.w", AMO {width=RISCVWORD; aq=false; rl=false; op=RISCVAMOXOR}; +"amomax.w", AMO {width=RISCVWORD; aq=false; rl=false; op=RISCVAMOMAX}; +"amomin.w", AMO {width=RISCVWORD; aq=false; rl=false; op=RISCVAMOMIN}; +"amomaxu.w", AMO {width=RISCVWORD; aq=false; rl=false; op=RISCVAMOMAXU}; +"amominu.w", AMO {width=RISCVWORD; aq=false; rl=false; op=RISCVAMOMINU}; + +"amoswap.d", AMO {width=RISCVDOUBLE; aq=false; rl=false; op=RISCVAMOSWAP}; +"amoadd.d", AMO {width=RISCVDOUBLE; aq=false; rl=false; op=RISCVAMOADD}; +"amoand.d", AMO {width=RISCVDOUBLE; aq=false; rl=false; op=RISCVAMOAND}; +"amoor.d", AMO {width=RISCVDOUBLE; aq=false; rl=false; op=RISCVAMOOR}; +"amoxor.d", AMO {width=RISCVDOUBLE; aq=false; rl=false; op=RISCVAMOXOR}; +"amomax.d", AMO {width=RISCVDOUBLE; aq=false; rl=false; op=RISCVAMOMAX}; +"amomin.d", AMO {width=RISCVDOUBLE; aq=false; rl=false; op=RISCVAMOMIN}; +"amomaxu.d", AMO {width=RISCVDOUBLE; aq=false; rl=false; op=RISCVAMOMAXU}; +"amominu.d", AMO {width=RISCVDOUBLE; aq=false; rl=false; op=RISCVAMOMINU}; + +"amoswap.w.aq", AMO {width=RISCVWORD; aq=true; rl=false; op=RISCVAMOSWAP}; +"amoadd.w.aq", AMO {width=RISCVWORD; aq=true; rl=false; op=RISCVAMOADD}; +"amoand.w.aq", AMO {width=RISCVWORD; aq=true; rl=false; op=RISCVAMOAND}; +"amoor.w.aq", AMO {width=RISCVWORD; aq=true; rl=false; op=RISCVAMOOR}; +"amoxor.w.aq", AMO {width=RISCVWORD; aq=true; rl=false; op=RISCVAMOXOR}; +"amomax.w.aq", AMO {width=RISCVWORD; aq=true; rl=false; op=RISCVAMOMAX}; +"amomin.w.aq", AMO {width=RISCVWORD; aq=true; rl=false; op=RISCVAMOMIN}; +"amomaxu.w.aq", AMO {width=RISCVWORD; aq=true; rl=false; op=RISCVAMOMAXU}; +"amominu.w.aq", AMO {width=RISCVWORD; aq=true; rl=false; op=RISCVAMOMINU}; + +"amoswap.d.aq", AMO {width=RISCVDOUBLE; aq=true; rl=false; op=RISCVAMOSWAP}; +"amoadd.d.aq", AMO {width=RISCVDOUBLE; aq=true; rl=false; op=RISCVAMOADD}; +"amoand.d.aq", AMO {width=RISCVDOUBLE; aq=true; rl=false; op=RISCVAMOAND}; +"amoor.d.aq", AMO {width=RISCVDOUBLE; aq=true; rl=false; op=RISCVAMOOR}; +"amoxor.d.aq", AMO {width=RISCVDOUBLE; aq=true; rl=false; op=RISCVAMOXOR}; +"amomax.d.aq", AMO {width=RISCVDOUBLE; aq=true; rl=false; op=RISCVAMOMAX}; +"amomin.d.aq", AMO {width=RISCVDOUBLE; aq=true; rl=false; op=RISCVAMOMIN}; +"amomaxu.d.aq", AMO {width=RISCVDOUBLE; aq=true; rl=false; op=RISCVAMOMAXU}; +"amominu.d.aq", AMO {width=RISCVDOUBLE; aq=true; rl=false; op=RISCVAMOMINU}; + +"amoswap.w.rl", AMO {width=RISCVWORD; aq=false; rl=true; op=RISCVAMOSWAP}; +"amoadd.w.rl", AMO {width=RISCVWORD; aq=false; rl=true; op=RISCVAMOADD}; +"amoand.w.rl", AMO {width=RISCVWORD; aq=false; rl=true; op=RISCVAMOAND}; +"amoor.w.rl", AMO {width=RISCVWORD; aq=false; rl=true; op=RISCVAMOOR}; +"amoxor.w.rl", AMO {width=RISCVWORD; aq=false; rl=true; op=RISCVAMOXOR}; +"amomax.w.rl", AMO {width=RISCVWORD; aq=false; rl=true; op=RISCVAMOMAX}; +"amomin.w.rl", AMO {width=RISCVWORD; aq=false; rl=true; op=RISCVAMOMIN}; +"amomaxu.w.rl", AMO {width=RISCVWORD; aq=false; rl=true; op=RISCVAMOMAXU}; +"amominu.w.rl", AMO {width=RISCVWORD; aq=false; rl=true; op=RISCVAMOMINU}; + +"amoswap.d.rl", AMO {width=RISCVDOUBLE; aq=false; rl=true; op=RISCVAMOSWAP}; +"amoadd.d.rl", AMO {width=RISCVDOUBLE; aq=false; rl=true; op=RISCVAMOADD}; +"amoand.d.rl", AMO {width=RISCVDOUBLE; aq=false; rl=true; op=RISCVAMOAND}; +"amoor.d.rl", AMO {width=RISCVDOUBLE; aq=false; rl=true; op=RISCVAMOOR}; +"amoxor.d.rl", AMO {width=RISCVDOUBLE; aq=false; rl=true; op=RISCVAMOXOR}; +"amomax.d.rl", AMO {width=RISCVDOUBLE; aq=false; rl=true; op=RISCVAMOMAX}; +"amomin.d.rl", AMO {width=RISCVDOUBLE; aq=false; rl=true; op=RISCVAMOMIN}; +"amomaxu.d.rl", AMO {width=RISCVDOUBLE; aq=false; rl=true; op=RISCVAMOMAXU}; +"amominu.d.rl", AMO {width=RISCVDOUBLE; aq=false; rl=true; op=RISCVAMOMINU}; + +"amoswap.w.aq.rl", AMO {width=RISCVWORD; aq=true; rl=true; op=RISCVAMOSWAP}; +"amoadd.w.aq.rl", AMO {width=RISCVWORD; aq=true; rl=true; op=RISCVAMOADD}; +"amoand.w.aq.rl", AMO {width=RISCVWORD; aq=true; rl=true; op=RISCVAMOAND}; +"amoor.w.aq.rl", AMO {width=RISCVWORD; aq=true; rl=true; op=RISCVAMOOR}; +"amoxor.w.aq.rl", AMO {width=RISCVWORD; aq=true; rl=true; op=RISCVAMOXOR}; +"amomax.w.aq.rl", AMO {width=RISCVWORD; aq=true; rl=true; op=RISCVAMOMAX}; +"amomin.w.aq.rl", AMO {width=RISCVWORD; aq=true; rl=true; op=RISCVAMOMIN}; +"amomaxu.w.aq.rl", AMO {width=RISCVWORD; aq=true; rl=true; op=RISCVAMOMAXU}; +"amominu.w.aq.rl", AMO {width=RISCVWORD; aq=true; rl=true; op=RISCVAMOMINU}; + +"amoswap.d.aq.rl", AMO {width=RISCVDOUBLE; aq=true; rl=true; op=RISCVAMOSWAP}; +"amoadd.d.aq.rl", AMO {width=RISCVDOUBLE; aq=true; rl=true; op=RISCVAMOADD}; +"amoand.d.aq.rl", AMO {width=RISCVDOUBLE; aq=true; rl=true; op=RISCVAMOAND}; +"amoor.d.aq.rl", AMO {width=RISCVDOUBLE; aq=true; rl=true; op=RISCVAMOOR}; +"amoxor.d.aq.rl", AMO {width=RISCVDOUBLE; aq=true; rl=true; op=RISCVAMOXOR}; +"amomax.d.aq.rl", AMO {width=RISCVDOUBLE; aq=true; rl=true; op=RISCVAMOMAX}; +"amomin.d.aq.rl", AMO {width=RISCVDOUBLE; aq=true; rl=true; op=RISCVAMOMIN}; +"amomaxu.d.aq.rl", AMO {width=RISCVDOUBLE; aq=true; rl=true; op=RISCVAMOMAXU}; +"amominu.d.aq.rl", AMO {width=RISCVDOUBLE; aq=true; rl=true; op=RISCVAMOMINU}; + +(** pseudo instructions *********************************************) + +"li", LI () diff --git a/risc-v/hgen/map.hgen b/risc-v/hgen/map.hgen index ff14c428..bab5ced8 100644 --- a/risc-v/hgen/map.hgen +++ b/risc-v/hgen/map.hgen @@ -1,12 +1,15 @@ -| `RISCVUTYPE (x, r0, y) -> `RISCVUTYPE (x, map_reg r0, y) -| `RISCVJAL (x, r0) -> `RISCVJAL (x, map_reg r0) -| `RISCVJALR (x, r0, r1) -> `RISCVJALR (x, map_reg r0, map_reg r1) -| `RISCVBType (x, r0, r1, y) -> `RISCVBType (x, map_reg r0, map_reg r1, y) -| `RISCVIType (x, r0, r1, y) -> `RISCVIType (x, map_reg r0, map_reg r1, y) -| `RISCVShiftIop (x, r0, r1, y) -> `RISCVShiftIop (x, map_reg r0, map_reg r1, y) -| `RISCVRType (r0, r1, r2, y) -> `RISCVRType (r0, map_reg r1, map_reg r2, y) -| `RISCVLoad (x, r0, r1, y, z) -> `RISCVLoad (x, map_reg r0, map_reg r1, y, z) -| `RISCVStore (x, r0, r1, y) -> `RISCVStore (x, map_reg r0, map_reg r1, y) -| `RISCVADDIW (x, r0, r1) -> `RISCVADDIW (x, map_reg r0, map_reg r1) -| `RISCVSHIFTW (x, r0, r1, y) -> `RISCVSHIFTW (x, map_reg r0, map_reg r1, y) -| `RISCVRTYPEW (r0, r1, r2, x) -> `RISCVRTYPEW (r0, map_reg r1, map_reg r2, x) +| `RISCVUTYPE (x, r0, y) -> `RISCVUTYPE (x, map_reg r0, y) +| `RISCVJAL (x, r0) -> `RISCVJAL (x, map_reg r0) +| `RISCVJALR (x, r0, r1) -> `RISCVJALR (x, map_reg r0, map_reg r1) +| `RISCVBType (x, r0, r1, y) -> `RISCVBType (x, map_reg r0, map_reg r1, y) +| `RISCVIType (x, r0, r1, y) -> `RISCVIType (x, map_reg r0, map_reg r1, y) +| `RISCVShiftIop (x, r0, r1, y) -> `RISCVShiftIop (x, map_reg r0, map_reg r1, y) +| `RISCVRType (r0, r1, r2, y) -> `RISCVRType (r0, map_reg r1, map_reg r2, y) +| `RISCVLoad (x, r0, r1, y, z, a, b) -> `RISCVLoad (x, map_reg r0, map_reg r1, y, z, a, b) +| `RISCVStore (x, r0, r1, y, z, a) -> `RISCVStore (x, map_reg r0, map_reg r1, y, z, a) +| `RISCVADDIW (x, r0, r1) -> `RISCVADDIW (x, map_reg r0, map_reg r1) +| `RISCVSHIFTW (x, r0, r1, y) -> `RISCVSHIFTW (x, map_reg r0, map_reg r1, y) +| `RISCVRTYPEW (r0, r1, r2, x) -> `RISCVRTYPEW (r0, map_reg r1, map_reg r2, x) +| `RISCVLoadRes (aq, rl, rs1, w, rd) -> `RISCVLoadRes (aq, rl, map_reg rs1, w, map_reg rd) +| `RISCVStoreCon (aq, rl, rs2, rs1, w, rd) -> `RISCVStoreCon (aq, rl, map_reg rs2, map_reg rs1, w, map_reg rd) +| `RISCVAMO (op, aq, rl, rs2, rs1, w, rd) -> `RISCVAMO (op, aq, rl, map_reg rs2, map_reg rs1, w, map_reg rd) diff --git a/risc-v/hgen/parser.hgen b/risc-v/hgen/parser.hgen index 37fd8d8d..210e38fb 100644 --- a/risc-v/hgen/parser.hgen +++ b/risc-v/hgen/parser.hgen @@ -1,36 +1,74 @@ | UTYPE reg COMMA NUM - { `RISCVUTYPE($4, $2, $1.op) } + { (* it's not clear if NUM here should be before or after filling the + lowest 12 bits with zeros, or if it should be signed or unsigned; + currently assuming: NUM does not include the 12 zeros, and is unsigned *) + if not (iskbituimm 20 $4) then failwith "immediate is not 20bit" + else `RISCVUTYPE ($4, $2, $1.op) } | JAL reg COMMA NUM - { `RISCVJAL($4, $2) } + { if not ($4 mod 2 = 0) then failwith "odd offset" + else if not (iskbitsimm 21 $4) then failwith "offset is not 21bit" + else `RISCVJAL ($4, $2) } | JALR reg COMMA reg COMMA NUM - { `RISCVJALR($6, $4, $2) } + { if not (iskbitsimm 12 $6) then failwith "offset is not 12bit" + else `RISCVJALR ($6, $4, $2) } | BTYPE reg COMMA reg COMMA NUM - { `RISCVBType($6, $4, $2, $1.op) } + { if not ($6 mod 2 = 0) then failwith "odd offset" + else if not (iskbitsimm 13 $6) then failwith "offset is not 13bit" + else `RISCVBType ($6, $4, $2, $1.op) } | ITYPE reg COMMA reg COMMA NUM - { `RISCVIType($6, $4, $2, $1.op) } + { if $1.op <> RISCVSLTIU && not (iskbitsimm 12 $6) then failwith "immediate is not 12bit" + else if $1.op = RISCVSLTIU && not (iskbituimm 12 $6) then failwith "unsigned immediate is not 12bit" + else `RISCVIType ($6, $4, $2, $1.op) } +| ADDIW reg COMMA reg COMMA NUM + { if not (iskbitsimm 12 $6) then failwith "immediate is not 12bit" + else `RISCVADDIW ($6, $4, $2) } | SHIFTIOP reg COMMA reg COMMA NUM - { `RISCVShiftIop($6, $4, $2, $1.op) } + { if not (iskbituimm 6 $6) then failwith "unsigned immediate is not 6bit" + else `RISCVShiftIop ($6, $4, $2, $1.op) } +| SHIFTW reg COMMA reg COMMA NUM + { if not (iskbituimm 5 $6) then failwith "unsigned immediate is not 5bit" + else `RISCVSHIFTW ($6, $4, $2, $1.op) } | RTYPE reg COMMA reg COMMA reg { `RISCVRType ($6, $4, $2, $1.op) } | LOAD reg COMMA NUM LPAR reg RPAR - { `RISCVLoad($4, $6, $2, $1.unsigned, $1.width) } + { if not (iskbitsimm 12 $4) then failwith "offset is not 12bit" + else `RISCVLoad ($4, $6, $2, $1.unsigned, $1.width, $1.aq, $1.rl) } | STORE reg COMMA NUM LPAR reg RPAR - { `RISCVStore($4, $2, $6, $1.width) } -| ADDIW reg COMMA reg COMMA NUM - { `RISCVADDIW ($6, $4, $2) } -| SHIFTW reg COMMA reg COMMA NUM - { `RISCVSHIFTW ($6, $4, $2, $1.op) } + { if not (iskbitsimm 12 $4) then failwith "offset is not 12bit" + else `RISCVStore ($4, $2, $6, $1.width, $1.aq, $1.rl) } | RTYPEW reg COMMA reg COMMA reg { `RISCVRTYPEW ($6, $4, $2, $1.op) } | FENCE FENCEOPTION COMMA FENCEOPTION { match ($2, $4) with | (Fence_RW, Fence_RW) -> `RISCVFENCE (0b0011, 0b0011) | (Fence_R, Fence_RW) -> `RISCVFENCE (0b0010, 0b0011) + | (Fence_R, Fence_R) -> `RISCVFENCE (0b0010, 0b0010) | (Fence_RW, Fence_W) -> `RISCVFENCE (0b0011, 0b0001) + | (Fence_W, Fence_W) -> `RISCVFENCE (0b0001, 0b0001) | (Fence_RW, Fence_R) -> failwith "'fence rw,r' is not supported" - | (Fence_R, Fence_R) -> failwith "'fence r,r' is not supported" | (Fence_R, Fence_W) -> failwith "'fence r,w' is not supported" | (Fence_W, Fence_RW) -> failwith "'fence w,rw' is not supported" | (Fence_W, Fence_R) -> failwith "'fence w,r' is not supported" - | (Fence_W, Fence_W) -> failwith "'fence w,w' is not supported" } +| FENCEI + { `RISCVFENCEI } +| LOADRES reg COMMA LPAR reg RPAR + { `RISCVLoadRes ($1.aq, $1.rl, $5, $1.width, $2) } +| LOADRES reg COMMA NUM LPAR reg RPAR + { if $4 <> 0 then failwith "'lr' offset must be 0" else + `RISCVLoadRes ($1.aq, $1.rl, $6, $1.width, $2) } +| STORECON reg COMMA reg COMMA LPAR reg RPAR + { `RISCVStoreCon ($1.aq, $1.rl, $4, $7, $1.width, $2) } +| STORECON reg COMMA reg COMMA NUM LPAR reg RPAR + { if $6 <> 0 then failwith "'sc' offset must be 0" else + `RISCVStoreCon ($1.aq, $1.rl, $4, $8, $1.width, $2) } +| AMO reg COMMA reg COMMA LPAR reg RPAR + { `RISCVAMO ($1.op, $1.aq, $1.rl, $4, $7, $1.width, $2) } +| AMO reg COMMA reg COMMA NUM LPAR reg RPAR + { if $6 <> 0 then failwith "'amo<op>' offset must be 0" else + `RISCVAMO ($1.op, $1.aq, $1.rl, $4, $8, $1.width, $2) } + +/* pseudo-ops */ +| LI reg COMMA NUM + { if not (iskbitsimm 12 $4) then failwith "immediate is not 12bit (li is currently implemented only with small immediate)" + else `RISCVIType ($4, IReg R0, $2, RISCVORI) } diff --git a/risc-v/hgen/pretty.hgen b/risc-v/hgen/pretty.hgen index 1da3ef11..fc1c0000 100644 --- a/risc-v/hgen/pretty.hgen +++ b/risc-v/hgen/pretty.hgen @@ -7,9 +7,24 @@ | `RISCVIType(imm, rs2, rs1, op) -> sprintf "%s %s, %s, %d" (pp_riscv_iop op) (pp_reg rs1) (pp_reg rs2) imm | `RISCVShiftIop(imm, rs, rd, op) -> sprintf "%s %s, %s, %d" (pp_riscv_sop op) (pp_reg rd) (pp_reg rs) imm | `RISCVRType (rs2, rs1, rd, op) -> sprintf "%s %s, %s, %s" (pp_riscv_rop op) (pp_reg rd) (pp_reg rs1) (pp_reg rs2) -| `RISCVLoad(imm, rs, rd, unsigned, width) -> sprintf "%s %s, %d(%s)" (pp_riscv_load_op (unsigned, width)) (pp_reg rd) imm (pp_reg rs) -| `RISCVStore(imm, rs2, rs1, width) -> sprintf "%s %s, %d(%s)" (pp_riscv_store_op width) (pp_reg rs2) imm (pp_reg rs1) + +| `RISCVLoad(imm, rs, rd, unsigned, width, aq, rl) -> + sprintf "%s %s, %d(%s)" (pp_riscv_load_op (unsigned, width, aq, rl)) (pp_reg rd) imm (pp_reg rs) + +| `RISCVStore(imm, rs2, rs1, width, aq, rl) -> + sprintf "%s %s, %d(%s)" (pp_riscv_store_op (width, aq, rl)) (pp_reg rs2) imm (pp_reg rs1) + | `RISCVADDIW(imm, rs, rd) -> sprintf "addiw %s, %s, %d" (pp_reg rd) (pp_reg rs) imm | `RISCVSHIFTW(imm, rs, rd, op) -> sprintf "%s %s, %s, %d" (pp_riscv_sop op) (pp_reg rd) (pp_reg rs) imm | `RISCVRTYPEW(rs2, rs1, rd, op) -> sprintf "%s %s, %s, %s" (pp_riscv_ropw op) (pp_reg rd) (pp_reg rs1) (pp_reg rs2) | `RISCVFENCE(pred, succ) -> sprintf "fence %s, %s" (pp_riscv_fence_option pred) (pp_riscv_fence_option succ) +| `RISCVFENCEI -> sprintf "fence.i" + +| `RISCVLoadRes(aq, rl, rs1, width, rd) -> + sprintf "%s %s, (%s)" (pp_riscv_load_reserved_op (aq, rl, width)) (pp_reg rd) (pp_reg rs1) + +| `RISCVStoreCon(aq, rl, rs2, rs1, width, rd) -> + sprintf "%s %s, %s, (%s)" (pp_riscv_store_conditional_op (aq, rl, width)) (pp_reg rd) (pp_reg rs2) (pp_reg rs1) + +| `RISCVAMO(op, aq, rl, rs2, rs1, width, rd) -> + sprintf "%s %s, %s, (%s)" (pp_riscv_amo_op (op, aq, rl, width)) (pp_reg rd) (pp_reg rs2) (pp_reg rs1) diff --git a/risc-v/hgen/pretty_xml.hgen b/risc-v/hgen/pretty_xml.hgen new file mode 100644 index 00000000..b0306161 --- /dev/null +++ b/risc-v/hgen/pretty_xml.hgen @@ -0,0 +1,137 @@ +| `RISCVThreadStart -> ("op_thread_start", []) + +| `RISCVStopFetching -> ("op_stop_fetching", []) + +| `RISCVUTYPE(imm, rd, op) -> + ("op_U_type", + [ ("op", pp_riscv_uop op); + ("uimm", sprintf "%d" imm); + ("dest", pp_reg rd); + ]) + +| `RISCVJAL(imm, rd) -> + ("op_jal", + [ ("offset", sprintf "%d" imm); + ("dest", pp_reg rd); + ]) + +| `RISCVJALR(imm, rs1, rd) -> + ("op_jalr", + [ ("offset", sprintf "%d" imm); + ("base", pp_reg rs1); + ("dest", pp_reg rd); + ]) + +| `RISCVBType(imm, rs2, rs1, op) -> + ("op_branch", + [ ("op", pp_riscv_bop op); + ("offset", sprintf "%d" imm); + ("src2", pp_reg rs2); + ("src1", pp_reg rs1); + ]) + +| `RISCVIType(imm, rs1, rd, op) -> + ("op_I_type", + [ ("op", pp_riscv_iop op); + ("iimm", sprintf "%d" imm); + ("src", pp_reg rs1); + ("dest", pp_reg rd); + ]) + +| `RISCVShiftIop(imm, rs1, rd, op) -> + ("op_IS_type", + [ ("op", pp_riscv_sop op); + ("shamt", sprintf "%d" imm); + ("src", pp_reg rs1); + ("dest", pp_reg rd); + ]) + +| `RISCVSHIFTW(imm, rs1, rd, op) -> + ("op_ISW_type", + [ ("op", pp_riscv_sop op); + ("shamt", sprintf "%d" imm); + ("src", pp_reg rs1); + ("dest", pp_reg rd); + ]) + +| `RISCVRType (rs2, rs1, rd, op) -> + ("op_R_type", + [ ("op", pp_riscv_rop op); + ("src2", pp_reg rs2); + ("src1", pp_reg rs1); + ("dest", pp_reg rd); + ]) + +| `RISCVLoad(imm, rs1, rd, unsigned, width, aq, rl) -> + ("op_load", + [ ("aq", if aq then "true" else "false"); + ("rl", if rl then "true" else "false"); + ("width", pp_word_width width); + ("unsigned", if unsigned then "true" else "false"); + ("base", pp_reg rs1); + ("offset", sprintf "%d" imm); + ("dest", pp_reg rd); + ]) + +| `RISCVStore(imm, rs2, rs1, width, aq, rl) -> + ("op_store", + [ ("aq", if aq then "true" else "false"); + ("rl", if rl then "true" else "false"); + ("width", pp_word_width width); + ("src", pp_reg rs2); + ("base", pp_reg rs1); + ("offset", sprintf "%d" imm); + ]) + +| `RISCVADDIW(imm, rs1, rd) -> + ("op_addiw", + [ ("iimm", sprintf "%d" imm); + ("src", pp_reg rs1); + ("dest", pp_reg rd); + ]) + +| `RISCVRTYPEW(rs2, rs1, rd, op) -> + ("op_RW_type", + [ ("op", pp_riscv_ropw op); + ("src2", pp_reg rs2); + ("src1", pp_reg rs1); + ("dest", pp_reg rd); + ]) + +| `RISCVFENCE(pred, succ) -> + ("op_fence", + [ ("pred", pp_riscv_fence_option pred); + ("succ", pp_riscv_fence_option succ); + ]) + +| `RISCVFENCEI -> ("op_fence_i", []) + +| `RISCVLoadRes(aq, rl, rs1, width, rd) -> + ("op_lr", + [ ("aq", if aq then "true" else "false"); + ("rl", if rl then "true" else "false"); + ("width", pp_word_width width); + ("addr", pp_reg rs1); + ("dest", pp_reg rd); + ]) + +| `RISCVStoreCon(aq, rl, rs2, rs1, width, rd) -> + ("op_sc", + [ ("aq", if aq then "true" else "false"); + ("rl", if rl then "true" else "false"); + ("width", pp_word_width width); + ("addr", pp_reg rs1); + ("src", pp_reg rs2); + ("dest", pp_reg rd); + ]) + +| `RISCVAMO(op, aq, rl, rs2, rs1, width, rd) -> + ("op_amo", + [ ("op", pp_riscv_amo_op_part op); + ("aq", if aq then "true" else "false"); + ("rl", if rl then "true" else "false"); + ("width", pp_word_width width); + ("src", pp_reg rs2); + ("addr", pp_reg rs1); + ("dest", pp_reg rd); + ]) diff --git a/risc-v/hgen/sail_trans_out.hgen b/risc-v/hgen/sail_trans_out.hgen index dca5bea1..2f9a80f1 100644 --- a/risc-v/hgen/sail_trans_out.hgen +++ b/risc-v/hgen/sail_trans_out.hgen @@ -6,9 +6,18 @@ | ("ITYPE", [imm; rs1; rd; op]) -> `RISCVIType(translate_out_simm12 imm, translate_out_ireg rs1, translate_out_ireg rd, translate_out_iop op) | ("SHIFTIOP", [imm; rs; rd; op]) -> `RISCVShiftIop(translate_out_imm6 imm, translate_out_ireg rs, translate_out_ireg rd, translate_out_sop op) | ("RTYPE", [rs2; rs1; rd; op]) -> `RISCVRType (translate_out_ireg rs2, translate_out_ireg rs1, translate_out_ireg rd, translate_out_rop op) -| ("LOAD", [imm; rs; rd; unsigned; width]) -> `RISCVLoad(translate_out_simm12 imm, translate_out_ireg rs, translate_out_ireg rd, translate_out_bool unsigned, translate_out_wordWidth width) -| ("STORE", [imm; rs; rd; width]) -> `RISCVStore(translate_out_simm12 imm, translate_out_ireg rs, translate_out_ireg rd, translate_out_wordWidth width) +| ("LOAD", [imm; rs; rd; unsigned; width; aq; rl]) + -> `RISCVLoad(translate_out_simm12 imm, translate_out_ireg rs, translate_out_ireg rd, translate_out_bool unsigned, translate_out_wordWidth width, translate_out_bool aq, translate_out_bool rl) +| ("STORE", [imm; rs; rd; width; aq; rl]) + -> `RISCVStore(translate_out_simm12 imm, translate_out_ireg rs, translate_out_ireg rd, translate_out_wordWidth width, translate_out_bool aq, translate_out_bool rl) | ("ADDIW", [imm; rs; rd]) -> `RISCVADDIW(translate_out_simm12 imm, translate_out_ireg rs, translate_out_ireg rd) | ("SHIFTW", [imm; rs; rd; op]) -> `RISCVSHIFTW(translate_out_imm5 imm, translate_out_ireg rs, translate_out_ireg rd, translate_out_sop op) | ("RTYPEW", [rs2; rs1; rd; op]) -> `RISCVRTYPEW(translate_out_ireg rs2, translate_out_ireg rs1, translate_out_ireg rd, translate_out_ropw op) | ("FENCE", [pred; succ]) -> `RISCVFENCE(translate_out_imm4 pred, translate_out_imm4 succ) +| ("FENCEI", []) -> `RISCVFENCEI +| ("LOADRES", [aq; rl; rs1; width; rd]) + -> `RISCVLoadRes(translate_out_bool aq, translate_out_bool rl, translate_out_ireg rs1, translate_out_wordWidth width, translate_out_ireg rd) +| ("STORECON", [aq; rl; rs2; rs1; width; rd]) + -> `RISCVStoreCon(translate_out_bool aq, translate_out_bool rl, translate_out_ireg rs2, translate_out_ireg rs1, translate_out_wordWidth width, translate_out_ireg rd) +| ("AMO", [op; aq; rl; rs2; rs1; width; rd]) + -> `RISCVAMO(translate_out_amoop op, translate_out_bool aq, translate_out_bool rl, translate_out_ireg rs2, translate_out_ireg rs1, translate_out_wordWidth width, translate_out_ireg rd) diff --git a/risc-v/hgen/shallow_ast_to_herdtools_ast.hgen b/risc-v/hgen/shallow_ast_to_herdtools_ast.hgen index 6158ebd7..3025992e 100644 --- a/risc-v/hgen/shallow_ast_to_herdtools_ast.hgen +++ b/risc-v/hgen/shallow_ast_to_herdtools_ast.hgen @@ -1,14 +1,23 @@ | EBREAK -> `RISCVStopFetching | UTYPE( imm, rd, op) -> `RISCVUTYPE(translate_out_simm20 imm, translate_out_ireg rd, translate_out_uop op) -| JAL0( imm, rd) -> `RISCVJAL(translate_out_simm21 imm, translate_out_ireg rd) -| JALR0( imm, rs, rd) -> `RISCVJALR(translate_out_simm12 imm, translate_out_ireg rs, translate_out_ireg rd) +| RISCV_JAL( imm, rd) -> `RISCVJAL(translate_out_simm21 imm, translate_out_ireg rd) +| RISCV_JALR( imm, rs, rd) -> `RISCVJALR(translate_out_simm12 imm, translate_out_ireg rs, translate_out_ireg rd) | BTYPE( imm, rs2, rs1, op) -> `RISCVBType(translate_out_simm13 imm, translate_out_ireg rs2, translate_out_ireg rs1, translate_out_bop op) | ITYPE( imm, rs1, rd, op) -> `RISCVIType(translate_out_simm12 imm, translate_out_ireg rs1, translate_out_ireg rd, translate_out_iop op) | SHIFTIOP( imm, rs, rd, op) -> `RISCVShiftIop(translate_out_imm6 imm, translate_out_ireg rs, translate_out_ireg rd, translate_out_sop op) | RTYPE( rs2, rs1, rd, op) -> `RISCVRType (translate_out_ireg rs2, translate_out_ireg rs1, translate_out_ireg rd, translate_out_rop op) -| LOAD( imm, rs, rd, unsigned, width) -> `RISCVLoad(translate_out_simm12 imm, translate_out_ireg rs, translate_out_ireg rd, translate_out_bool unsigned, translate_out_wordWidth width) -| STORE( imm, rs, rd, width) -> `RISCVStore(translate_out_simm12 imm, translate_out_ireg rs, translate_out_ireg rd, translate_out_wordWidth width) +| LOAD( imm, rs, rd, unsigned, width, aq, rl) + -> `RISCVLoad(translate_out_simm12 imm, translate_out_ireg rs, translate_out_ireg rd, translate_out_bool unsigned, translate_out_wordWidth width, translate_out_bool aq, translate_out_bool rl) +| STORE( imm, rs, rd, width, aq, rl) + -> `RISCVStore(translate_out_simm12 imm, translate_out_ireg rs, translate_out_ireg rd, translate_out_wordWidth width, translate_out_bool aq, translate_out_bool rl) | ADDIW( imm, rs, rd) -> `RISCVADDIW(translate_out_simm12 imm, translate_out_ireg rs, translate_out_ireg rd) | SHIFTW( imm, rs, rd, op) -> `RISCVSHIFTW(translate_out_imm5 imm, translate_out_ireg rs, translate_out_ireg rd, translate_out_sop op) | RTYPEW( rs2, rs1, rd, op) -> `RISCVRTYPEW(translate_out_ireg rs2, translate_out_ireg rs1, translate_out_ireg rd, translate_out_ropw op) | FENCE( pred, succ) -> `RISCVFENCE(translate_out_imm4 pred, translate_out_imm4 succ) +| FENCEI -> `RISCVFENCEI +| LOADRES( aq, rl, rs1, width, rd) + -> `RISCVLoadRes(translate_out_bool aq, translate_out_bool rl, translate_out_ireg rs1, translate_out_wordWidth width, translate_out_ireg rd) +| STORECON( aq, rl, rs2, rs1, width, rd) + -> `RISCVStoreCon(translate_out_bool aq, translate_out_bool rl, translate_out_ireg rs2, translate_out_ireg rs1, translate_out_wordWidth width, translate_out_ireg rd) +| AMO( op, aq, rl, rs2, rs1, width, rd) + -> `RISCVAMO(translate_out_amoop op, translate_out_bool aq, translate_out_bool rl, translate_out_ireg rs2, translate_out_ireg rs1, translate_out_wordWidth width, translate_out_ireg rd) diff --git a/risc-v/hgen/shallow_types_to_herdtools_types.hgen b/risc-v/hgen/shallow_types_to_herdtools_types.hgen index a891d7d0..6b3b7f51 100644 --- a/risc-v/hgen/shallow_types_to_herdtools_types.hgen +++ b/risc-v/hgen/shallow_types_to_herdtools_types.hgen @@ -10,48 +10,59 @@ let translate_out_signed_int inst bits = let translate_out_ireg ireg = IReg (int_to_ireg (translate_out_int ireg)) let translate_out_uop op = match op with - | LUI0 -> RISCVLUI - | AUIPC -> RISCVAUIPC + | RISCV_LUI -> RISCVLUI + | RISCV_AUIPC -> RISCVAUIPC let translate_out_bop op = match op with - | BEQ0 -> RISCVBEQ - | BNE -> RISCVBNE - | BLT -> RISCVBLT - | BGE -> RISCVBGE - | BLTU -> RISCVBLTU - | BGEU -> RISCVBGEU + | RISCV_BEQ -> RISCVBEQ + | RISCV_BNE -> RISCVBNE + | RISCV_BLT -> RISCVBLT + | RISCV_BGE -> RISCVBGE + | RISCV_BLTU -> RISCVBLTU + | RISCV_BGEU -> RISCVBGEU let translate_out_iop op = match op with - | ADDI0 -> RISCVADDI - | SLTI0 -> RISCVSLTI - | SLTIU0 -> RISCVSLTIU - | XORI0 -> RISCVXORI - | ORI0 -> RISCVORI - | ANDI0 -> RISCVANDI + | RISCV_ADDI -> RISCVADDI + | RISCV_SLTI -> RISCVSLTI + | RISCV_SLTIU -> RISCVSLTIU + | RISCV_XORI -> RISCVXORI + | RISCV_ORI -> RISCVORI + | RISCV_ANDI -> RISCVANDI let translate_out_sop op = match op with - | SLLI -> RISCVSLLI - | SRLI -> RISCVSRLI - | SRAI -> RISCVSRAI + | RISCV_SLLI -> RISCVSLLI + | RISCV_SRLI -> RISCVSRLI + | RISCV_SRAI -> RISCVSRAI let translate_out_rop op = match op with - | ADD0 -> RISCVADD - | SUB0 -> RISCVSUB - | SLL0 -> RISCVSLL - | SLT0 -> RISCVSLT - | SLTU0 -> RISCVSLTU - | XOR0 -> RISCVXOR - | SRL0 -> RISCVSRL - | SRA0 -> RISCVSRA - | OR0 -> RISCVOR - | AND0 -> RISCVAND + | RISCV_ADD -> RISCVADD + | RISCV_SUB -> RISCVSUB + | RISCV_SLL -> RISCVSLL + | RISCV_SLT -> RISCVSLT + | RISCV_SLTU -> RISCVSLTU + | RISCV_XOR -> RISCVXOR + | RISCV_SRL -> RISCVSRL + | RISCV_SRA -> RISCVSRA + | RISCV_OR -> RISCVOR + | RISCV_AND -> RISCVAND let translate_out_ropw op = match op with - | ADDW -> RISCVADDW - | SUBW -> RISCVSUBW - | SLLW -> RISCVSLLW - | SRLW -> RISCVSRLW - | SRAW -> RISCVSRAW + | RISCV_ADDW -> RISCVADDW + | RISCV_SUBW -> RISCVSUBW + | RISCV_SLLW -> RISCVSLLW + | RISCV_SRLW -> RISCVSRLW + | RISCV_SRAW -> RISCVSRAW + +let translate_out_amoop op = match op with + | AMOSWAP -> RISCVAMOSWAP + | AMOADD -> RISCVAMOADD + | AMOXOR -> RISCVAMOXOR + | AMOAND -> RISCVAMOAND + | AMOOR -> RISCVAMOOR + | AMOMIN -> RISCVAMOMIN + | AMOMAX -> RISCVAMOMAX + | AMOMINU -> RISCVAMOMINU + | AMOMAXU -> RISCVAMOMAXU let translate_out_wordWidth op = match op with | BYTE -> RISCVBYTE diff --git a/risc-v/hgen/token_types.hgen b/risc-v/hgen/token_types.hgen index 2980b985..f29e318d 100644 --- a/risc-v/hgen/token_types.hgen +++ b/risc-v/hgen/token_types.hgen @@ -5,11 +5,19 @@ type token_BType = {op : riscvBop } type token_IType = {op : riscvIop } type token_ShiftIop = {op : riscvSop } type token_RTYPE = {op : riscvRop } -type token_Load = {unsigned: bool; width : wordWidth } -type token_Store = {width : wordWidth } +type token_Load = {unsigned: bool; width : wordWidth; aq: bool; rl: bool } +type token_Store = {width : wordWidth; aq: bool; rl: bool } type token_ADDIW = unit type token_SHIFTW = {op : riscvSop } type token_RTYPEW = {op : riscvRopw } type token_FENCE = unit +type token_FENCEI = unit +type token_LoadRes = {width : wordWidth; aq: bool; rl: bool } +type token_StoreCon = {width : wordWidth; aq: bool; rl: bool } +type token_AMO = {width : wordWidth; aq: bool; rl: bool; op: riscvAmoop } type token_FENCEOPTION = Fence_R | Fence_W | Fence_RW + +(* pseudo-ops *) + +type token_LI = unit diff --git a/risc-v/hgen/tokens.hgen b/risc-v/hgen/tokens.hgen index f952cf77..f812adbd 100644 --- a/risc-v/hgen/tokens.hgen +++ b/risc-v/hgen/tokens.hgen @@ -12,3 +12,8 @@ %token <RISCVHGenBase.token_RTYPEW> RTYPEW %token <RISCVHGenBase.token_FENCE> FENCE %token <RISCVHGenBase.token_FENCEOPTION> FENCEOPTION +%token <RISCVHGenBase.token_FENCEI> FENCEI +%token <RISCVHGenBase.token_LoadRes> LOADRES +%token <RISCVHGenBase.token_StoreCon> STORECON +%token <RISCVHGenBase.token_AMO> AMO +%token <RISCVHGenBase.token_LI> LI diff --git a/risc-v/hgen/trans_sail.hgen b/risc-v/hgen/trans_sail.hgen index df22d9dc..8b7cbe11 100644 --- a/risc-v/hgen/trans_sail.hgen +++ b/risc-v/hgen/trans_sail.hgen @@ -58,7 +58,7 @@ translate_rop "op" op; ], []) -| `RISCVLoad(imm, rs, rd, unsigned, width) -> +| `RISCVLoad(imm, rs, rd, unsigned, width, aq, rl) -> ("LOAD", [ translate_imm12 "imm" imm; @@ -66,15 +66,19 @@ translate_reg "rd" rd; translate_bool "unsigned" unsigned; translate_width "width" width; + translate_bool "aq" aq; + translate_bool "rl" rl; ], []) -| `RISCVStore(imm, rs2, rs1, width) -> +| `RISCVStore(imm, rs2, rs1, width, aq, rl) -> ("STORE", [ translate_imm12 "imm" imm; translate_reg "rs2" rs2; translate_reg "rs1" rs1; translate_width "width" width; + translate_bool "aq" aq; + translate_bool "rl" rl; ], []) | `RISCVADDIW(imm, rs, rd) -> @@ -110,3 +114,40 @@ translate_imm4 "succ" succ; ], []) +| `RISCVFENCEI -> + ("FENCEI", + [], + []) +| `RISCVLoadRes(aq, rl, rs1, width, rd) -> + ("LOADRES", + [ + translate_bool "aq" aq; + translate_bool "rl" rl; + translate_reg "rs1" rs1; + translate_width "width" width; + translate_reg "rd" rd; + ], + []) +| `RISCVStoreCon(aq, rl, rs2, rs1, width, rd) -> + ("STORECON", + [ + translate_bool "aq" aq; + translate_bool "rl" rl; + translate_reg "rs2" rs2; + translate_reg "rs1" rs1; + translate_width "width" width; + translate_reg "rd" rd; + ], + []) +| `RISCVAMO(op, aq, rl, rs2, rs1, width, rd) -> + ("AMO", + [ + translate_amoop "op" op; + translate_bool "aq" aq; + translate_bool "rl" rl; + translate_reg "rs2" rs2; + translate_reg "rs1" rs1; + translate_width "width" width; + translate_reg "rd" rd; + ], + []) diff --git a/risc-v/hgen/types.hgen b/risc-v/hgen/types.hgen index 87fc9b95..a0b75606 100644 --- a/risc-v/hgen/types.hgen +++ b/risc-v/hgen/types.hgen @@ -99,22 +99,71 @@ type wordWidth = | RISCVWORD | RISCVDOUBLE -let pp_riscv_load_op (unsigned, width) = match (unsigned, width) with - | (false, RISCVBYTE) -> "lb" - | (true, RISCVBYTE) -> "lbu" - | (false, RISCVHALF) -> "lh" - | (true, RISCVHALF) -> "lhu" - | (false, RISCVWORD) -> "lw" - | (true, RISCVWORD) -> "lwu" - | (_, RISCVDOUBLE) -> "ld" - | _ -> failwith "unexpected load op" - -let pp_riscv_store_op width = match width with -| RISCVBYTE -> "sb" -| RISCVHALF -> "sh" -| RISCVWORD -> "sw" -| RISCVDOUBLE -> "sd" -| _ -> failwith "unexpected store op" +let pp_word_width width : string = + begin match width with + | RISCVBYTE -> "b" + | RISCVHALF -> "h" + | RISCVWORD -> "w" + | RISCVDOUBLE -> "d" + end + +let pp_riscv_load_op (unsigned, width, aq, rl) = + "l" ^ + (pp_word_width width) ^ + (if unsigned then "u" else "") ^ + (if aq then ".aq" else "") ^ + (if rl then ".rl" else "") + +let pp_riscv_store_op (width, aq, rl) = + "s" ^ + (pp_word_width width) ^ + (if aq then ".aq" else "") ^ + (if rl then ".rl" else "") + +let pp_riscv_load_reserved_op (aq, rl, width) = + "lr." ^ + (pp_word_width width) ^ + (if aq then ".aq" else "") ^ + (if rl then ".rl" else "") + +let pp_riscv_store_conditional_op (aq, rl, width) = + "sc." ^ + (pp_word_width width) ^ + (if aq then ".aq" else "") ^ + (if rl then ".rl" else "") + +type riscvAmoop = + | RISCVAMOSWAP + | RISCVAMOADD + | RISCVAMOXOR + | RISCVAMOAND + | RISCVAMOOR + | RISCVAMOMIN + | RISCVAMOMAX + | RISCVAMOMINU + | RISCVAMOMAXU + +let pp_riscv_amo_op_part = function + | RISCVAMOSWAP -> "swap" + | RISCVAMOADD -> "add" + | RISCVAMOXOR -> "xor" + | RISCVAMOAND -> "and" + | RISCVAMOOR -> "or" + | RISCVAMOMIN -> "min" + | RISCVAMOMAX -> "max" + | RISCVAMOMINU -> "minu" + | RISCVAMOMAXU -> "maxu" + +let pp_riscv_amo_op (op, aq, rl, width) = + "amo" ^ + pp_riscv_amo_op_part op ^ + begin match width with + | RISCVWORD -> ".w" + | RISCVDOUBLE -> ".d" + | _ -> assert false + end ^ + (if aq then ".aq" else "") ^ + (if rl then ".rl" else "") let pp_riscv_fence_option = function | 0b0011 -> "rw" diff --git a/risc-v/hgen/types_sail_trans_out.hgen b/risc-v/hgen/types_sail_trans_out.hgen index e22110d0..66a2020c 100644 --- a/risc-v/hgen/types_sail_trans_out.hgen +++ b/risc-v/hgen/types_sail_trans_out.hgen @@ -84,3 +84,15 @@ let translate_out_ropw op = match translate_out_enum op with | 3 -> RISCVSRLW | 4 -> RISCVSRAW | _ -> failwith "Unknown ropw in sail translate out" + +let translate_out_amoop op = match translate_out_enum op with +| 0 -> RISCVAMOSWAP +| 1 -> RISCVAMOADD +| 2 -> RISCVAMOXOR +| 3 -> RISCVAMOAND +| 4 -> RISCVAMOOR +| 5 -> RISCVAMOMIN +| 6 -> RISCVAMOMAX +| 7 -> RISCVAMOMINU +| 8 -> RISCVAMOMAXU +| _ -> failwith "Unknown amoop in sail translate out" diff --git a/risc-v/hgen/types_trans_sail.hgen b/risc-v/hgen/types_trans_sail.hgen index 1bf174fa..238c7e5b 100644 --- a/risc-v/hgen/types_trans_sail.hgen +++ b/risc-v/hgen/types_trans_sail.hgen @@ -11,29 +11,47 @@ let translate_enum enum_values name value = (name, Range0 (Some size), IInt.bit_list_of_integer size (Nat_big_num.of_int index)) let translate_uop = translate_enum [RISCVLUI; RISCVAUIPC] + let translate_bop = translate_enum [RISCVBEQ; RISCVBNE; RISCVBLT; RISCVBGE; RISCVBLTU; RISCVBGEU] (* branch ops *) + let translate_iop = translate_enum [RISCVADDI; RISCVSLTI; RISCVSLTIU; RISCVXORI; RISCVORI; RISCVANDI] (* immediate ops *) + let translate_sop = translate_enum [RISCVSLLI; RISCVSRLI; RISCVSRAI] (* shift ops *) + let translate_rop = translate_enum [RISCVADD; RISCVSUB; RISCVSLL; RISCVSLT; RISCVSLTU; RISCVXOR; RISCVSRL; RISCVSRA; RISCVOR; RISCVAND] (* reg-reg ops *) + let translate_ropw = translate_enum [RISCVADDW; RISCVSUBW; RISCVSLLW; RISCVSRLW; RISCVSRAW] (* reg-reg 32-bit ops *) + +let translate_amoop = translate_enum [RISCVAMOSWAP; RISCVAMOADD; RISCVAMOXOR; RISCVAMOAND; RISCVAMOOR; RISCVAMOMIN; RISCVAMOMAX; RISCVAMOMINU; RISCVAMOMAXU] + let translate_width = translate_enum [RISCVBYTE; RISCVHALF; RISCVWORD; RISCVDOUBLE] + let translate_reg name value = (name, Bvector (Some 5), bit_list_of_integer 5 (Nat_big_num.of_int (reg_to_int value))) + let translate_imm21 name value = (name, Bvector (Some 21), bit_list_of_integer 21 (Nat_big_num.of_int value)) + let translate_imm20 name value = (name, Bvector (Some 20), bit_list_of_integer 20 (Nat_big_num.of_int value)) + let translate_imm16 name value = (name, Bvector (Some 16), bit_list_of_integer 16 (Nat_big_num.of_int value)) + let translate_imm13 name value = (name, Bvector (Some 13), bit_list_of_integer 13 (Nat_big_num.of_int value)) + let translate_imm12 name value = (name, Bvector (Some 12), bit_list_of_integer 12 (Nat_big_num.of_int value)) + let translate_imm6 name value = (name, Bvector (Some 6), bit_list_of_integer 6 (Nat_big_num.of_int value)) + let translate_imm5 name value = (name, Bvector (Some 5), bit_list_of_integer 5 (Nat_big_num.of_int value)) + let translate_imm4 name value = (name, Bvector (Some 4), bit_list_of_integer 4 (Nat_big_num.of_int value)) + let translate_bool name value = (name, Bit, [if value then Bitc_one else Bitc_zero]) diff --git a/risc-v/riscv.sail b/risc-v/riscv.sail index 4a80adb0..3d52d111 100644 --- a/risc-v/riscv.sail +++ b/risc-v/riscv.sail @@ -1,317 +1,404 @@ -default Order dec - -typedef regval = bit[64] -typedef regno = bit[5] - -register (regval) x0 -register (regval) x1 -register (regval) x2 -register (regval) x3 -register (regval) x4 -register (regval) x5 -register (regval) x6 -register (regval) x7 -register (regval) x8 -register (regval) x9 -register (regval) x10 -register (regval) x11 -register (regval) x12 -register (regval) x13 -register (regval) x14 -register (regval) x15 -register (regval) x16 -register (regval) x17 -register (regval) x18 -register (regval) x19 -register (regval) x20 -register (regval) x21 -register (regval) x22 -register (regval) x23 -register (regval) x24 -register (regval) x25 -register (regval) x26 -register (regval) x27 -register (regval) x28 -register (regval) x29 -register (regval) x30 -register (regval) x31 - -register (bit[64]) PC -register (bit[64]) nextPC - -let (vector <0, 32, inc, (register<(regval)>)>) GPRs = - [x0, x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19,x20,x21,x22,x23,x24,x25,x26,x27,x28,x29,x30,x31] - -function (regval) rGPR ((regno) r) = - if (r == 0) then - 0 - else - GPRs[r] - -function unit wGPR((regno) r, (regval) v) = - if (r != 0) then - GPRs[r] := v - -function forall 'a. 'a effect { escape } not_implemented((string) message) = -{ - exit message; -} - -val extern forall Nat 'n. ( bit[64] , [|'n|] ) -> (bit[8 * 'n]) effect { rmem } MEMr -val extern forall Nat 'n. ( bit[64] , [|'n|]) -> unit effect { eamem } MEMea -val extern forall Nat 'n. ( bit[64] , [|'n|] , bit[8*'n]) -> unit effect { wmv } MEMval -val extern unit -> unit effect { barr } MEM_fence_rw_rw -val extern unit -> unit effect { barr } MEM_fence_r_rw -val extern unit -> unit effect { barr } MEM_fence_rw_w - -(* Ideally these would be sail builtin *) -function (bit[64]) shift_right_arith64 ((bit[64]) v, (bit[6]) shift) = - let (bit[128]) v128 = EXTS(v) in - (v128 >> shift)[63..0] - -function (bit[32]) shift_right_arith32 ((bit[32]) v, (bit[5]) shift) = - let (bit[64]) v64 = EXTS(v) in - (v64 >> shift)[31..0] - -typedef uop = enumerate {LUI; AUIPC} (* upper immediate ops *) -typedef bop = enumerate {BEQ; BNE; BLT; BGE; BLTU; BGEU} (* branch ops *) -typedef iop = enumerate {ADDI; SLTI; SLTIU; XORI; ORI; ANDI} (* immediate ops *) -typedef sop = enumerate {SLLI; SRLI; SRAI} (* shift ops *) -typedef rop = enumerate {ADD; SUB; SLL; SLT; SLTU; XOR; SRL; SRA; OR; AND} (* reg-reg ops *) -typedef ropw = enumerate {ADDW; SUBW; SLLW; SRLW; SRAW} (* reg-reg 32-bit ops *) - -typedef word_width = enumerate {BYTE; HALF; WORD; DOUBLE} - -scattered function unit execute scattered typedef ast = const union val bit[32] -> option<ast> effect pure decode - scattered function option<ast> decode +scattered function unit execute + +(********************************************************************) union ast member ((bit[20]), regno, uop) UTYPE -function clause decode ((bit[20]) imm : (regno) rd : 0b0110111) = Some(UTYPE(imm, rd, LUI)) -function clause decode ((bit[20]) imm : (regno) rd : 0b0010111) = Some(UTYPE(imm, rd, AUIPC)) +function clause decode ((bit[20]) imm : (regno) rd : 0b0110111) = Some(UTYPE(imm, rd, RISCV_LUI)) +function clause decode ((bit[20]) imm : (regno) rd : 0b0010111) = Some(UTYPE(imm, rd, RISCV_AUIPC)) function clause execute (UTYPE(imm, rd, op)) = let (bit[64]) off = EXTS(imm : 0x000) in let ret = switch (op) { - case LUI -> off - case AUIPC -> PC + off + case RISCV_LUI -> off + case RISCV_AUIPC -> PC + off } in wGPR(rd, ret) -union ast member ((bit[21]), regno) JAL -function clause decode ((bit[20]) imm : (regno) rd : 0b1101111) = Some (JAL(imm[19] : imm[7..0] : imm[8] : imm[18..13] : imm[12..9] : 0b0, rd)) -function clause execute (JAL(imm, rd)) = - let (bit[64]) offset = EXTS(imm) in { - nextPC := PC + offset; - wGPR(rd, PC + 4); - } +(********************************************************************) +union ast member ((bit[21]), regno) RISCV_JAL + +function clause decode ((bit[20]) imm : (regno) rd : 0b1101111) = Some (RISCV_JAL(imm[19] : imm[7..0] : imm[8] : imm[18..13] : imm[12..9] : 0b0, rd)) + +function clause execute (RISCV_JAL(imm, rd)) = { + (bit[64]) pc := PC; + wGPR(rd, pc + 4); + (bit[64]) offset := EXTS(imm); + nextPC := pc + offset; +} + +(********************************************************************) +union ast member((bit[12]), regno, regno) RISCV_JALR -union ast member((bit[12]), regno, regno) JALR function clause decode ((bit[12]) imm : (regno) rs1 : 0b000 : (regno) rd : 0b1100111) = - Some(JALR(imm, rs1, rd)) -function clause execute (JALR(imm, rs1, rd)) = - let (bit[64]) newPC = rGPR(rs1) + EXTS(imm) in { - nextPC := newPC[63..1] : 0b0; - wGPR(rd, PC + 4); - } + Some(RISCV_JALR(imm, rs1, rd)) +function clause execute (RISCV_JALR(imm, rs1, rd)) = { + (* write rd before anything else to prevent unintended strength *) + wGPR(rd, PC + 4); + (bit[64]) newPC := rGPR(rs1) + EXTS(imm); + nextPC := newPC[63..1] : 0b0; +} + +(********************************************************************) union ast member ((bit[13]), regno, regno, bop) BTYPE -function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b000 : (bit[5]) imm5 : 0b1100011) = Some(BTYPE(imm7[6] : imm5[0] : imm7[5..0] : imm5[4..1] : 0b0, rs2, rs1, BEQ)) -function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b001 : (bit[5]) imm5 : 0b1100011) = Some(BTYPE(imm7[6] : imm5[0] : imm7[5..0] : imm5[4..1] : 0b0, rs2, rs1, BNE)) -function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b100 : (bit[5]) imm5 : 0b1100011) = Some(BTYPE(imm7[6] : imm5[0] : imm7[5..0] : imm5[4..1] : 0b0, rs2, rs1, BLT)) -function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b101 : (bit[5]) imm5 : 0b1100011) = Some(BTYPE(imm7[6] : imm5[0] : imm7[5..0] : imm5[4..1] : 0b0, rs2, rs1, BGE)) -function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b110 : (bit[5]) imm5 : 0b1100011) = Some(BTYPE(imm7[6] : imm5[0] : imm7[5..0] : imm5[4..1] : 0b0, rs2, rs1, BLTU)) -function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b111 : (bit[5]) imm5 : 0b1100011) = Some(BTYPE(imm7[6] : imm5[0] : imm7[5..0] : imm5[4..1] : 0b0, rs2, rs1, BGEU)) + +function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b000 : (bit[5]) imm5 : 0b1100011) = + Some(BTYPE(imm7[6] : imm5[0] : imm7[5..0] : imm5[4..1] : 0b0, rs2, rs1, RISCV_BEQ)) +function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b001 : (bit[5]) imm5 : 0b1100011) = + Some(BTYPE(imm7[6] : imm5[0] : imm7[5..0] : imm5[4..1] : 0b0, rs2, rs1, RISCV_BNE)) +function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b100 : (bit[5]) imm5 : 0b1100011) = + Some(BTYPE(imm7[6] : imm5[0] : imm7[5..0] : imm5[4..1] : 0b0, rs2, rs1, RISCV_BLT)) +function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b101 : (bit[5]) imm5 : 0b1100011) = + Some(BTYPE(imm7[6] : imm5[0] : imm7[5..0] : imm5[4..1] : 0b0, rs2, rs1, RISCV_BGE)) +function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b110 : (bit[5]) imm5 : 0b1100011) = + Some(BTYPE(imm7[6] : imm5[0] : imm7[5..0] : imm5[4..1] : 0b0, rs2, rs1, RISCV_BLTU)) +function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b111 : (bit[5]) imm5 : 0b1100011) = + Some(BTYPE(imm7[6] : imm5[0] : imm7[5..0] : imm5[4..1] : 0b0, rs2, rs1, RISCV_BGEU)) function clause execute (BTYPE(imm, rs2, rs1, op)) = let rs1_val = rGPR(rs1) in let rs2_val = rGPR(rs2) in let taken = switch(op) { - case BEQ -> rs1_val == rs2_val - case BNE -> rs1_val != rs2_val - case BLT -> rs1_val <_s rs2_val - case BGE -> rs1_val >=_s rs2_val - case BLTU -> rs1_val <_u rs2_val - case BGEU -> unsigned(rs1_val) >= unsigned(rs2_val) (* XXX sail missing >=_u *) + case RISCV_BEQ -> rs1_val == rs2_val + case RISCV_BNE -> rs1_val != rs2_val + case RISCV_BLT -> rs1_val <_s rs2_val + case RISCV_BGE -> rs1_val >=_s rs2_val + case RISCV_BLTU -> rs1_val <_u rs2_val + case RISCV_BGEU -> unsigned(rs1_val) >= unsigned(rs2_val) (* XXX sail missing >=_u *) } in if (taken) then nextPC := PC + EXTS(imm) +(********************************************************************) union ast member ((bit[12]), regno, regno, iop) ITYPE -function clause decode ((bit[12]) imm : (regno) rs1 : 0b000 : (regno) rd : 0b0010011) = Some(ITYPE(imm, rs1, rd, ADDI)) -function clause decode ((bit[12]) imm : (regno) rs1 : 0b010 : (regno) rd : 0b0010011) = Some(ITYPE(imm, rs1, rd, SLTI)) -function clause decode ((bit[12]) imm : (regno) rs1 : 0b011 : (regno) rd : 0b0010011) = Some(ITYPE(imm, rs1, rd, SLTIU)) -function clause decode ((bit[12]) imm : (regno) rs1 : 0b100 : (regno) rd : 0b0010011) = Some(ITYPE(imm, rs1, rd, XORI)) -function clause decode ((bit[12]) imm : (regno) rs1 : 0b110 : (regno) rd : 0b0010011) = Some(ITYPE(imm, rs1, rd, ORI)) -function clause decode ((bit[12]) imm : (regno) rs1 : 0b111 : (regno) rd : 0b0010011) = Some(ITYPE(imm, rs1, rd, ANDI)) + +function clause decode ((bit[12]) imm : (regno) rs1 : 0b000 : (regno) rd : 0b0010011) = Some(ITYPE(imm, rs1, rd, RISCV_ADDI)) +function clause decode ((bit[12]) imm : (regno) rs1 : 0b010 : (regno) rd : 0b0010011) = Some(ITYPE(imm, rs1, rd, RISCV_SLTI)) +function clause decode ((bit[12]) imm : (regno) rs1 : 0b011 : (regno) rd : 0b0010011) = Some(ITYPE(imm, rs1, rd, RISCV_SLTIU)) +function clause decode ((bit[12]) imm : (regno) rs1 : 0b100 : (regno) rd : 0b0010011) = Some(ITYPE(imm, rs1, rd, RISCV_XORI)) +function clause decode ((bit[12]) imm : (regno) rs1 : 0b110 : (regno) rd : 0b0010011) = Some(ITYPE(imm, rs1, rd, RISCV_ORI)) +function clause decode ((bit[12]) imm : (regno) rs1 : 0b111 : (regno) rd : 0b0010011) = Some(ITYPE(imm, rs1, rd, RISCV_ANDI)) + function clause execute (ITYPE (imm, rs1, rd, op)) = let rs1_val = rGPR(rs1) in let imm64 = (bit[64]) (EXTS(imm)) in let (bit[64]) result = switch(op) { - case ADDI -> rs1_val + imm64 - case SLTI -> EXTZ(rs1_val <_s imm64) - case SLTIU -> EXTZ(rs1_val <_u imm64) - case XORI -> rs1_val ^ imm64 - case ORI -> rs1_val | imm64 - case ANDI -> rs1_val & imm64 + case RISCV_ADDI -> rs1_val + imm64 + case RISCV_SLTI -> EXTZ(rs1_val <_s imm64) + case RISCV_SLTIU -> EXTZ(rs1_val <_u imm64) + case RISCV_XORI -> rs1_val ^ imm64 + case RISCV_ORI -> rs1_val | imm64 + case RISCV_ANDI -> rs1_val & imm64 } in wGPR(rd, result) +(********************************************************************) union ast member ((bit[6]), regno, regno, sop) SHIFTIOP -function clause decode (0b000000 : (bit[6]) shamt : (regno) rs1 : 0b001 : (regno) rd : 0b0010011) = Some(SHIFTIOP(shamt, rs1, rd, SLLI)) -function clause decode (0b000000 : (bit[6]) shamt : (regno) rs1 : 0b101 : (regno) rd : 0b0010011) = Some(SHIFTIOP(shamt, rs1, rd, SRLI)) -function clause decode (0b010000 : (bit[6]) shamt : (regno) rs1 : 0b101 : (regno) rd : 0b0010011) = Some(SHIFTIOP(shamt, rs1, rd, SRAI)) + +function clause decode (0b000000 : (bit[6]) shamt : (regno) rs1 : 0b001 : (regno) rd : 0b0010011) = Some(SHIFTIOP(shamt, rs1, rd, RISCV_SLLI)) +function clause decode (0b000000 : (bit[6]) shamt : (regno) rs1 : 0b101 : (regno) rd : 0b0010011) = Some(SHIFTIOP(shamt, rs1, rd, RISCV_SRLI)) +function clause decode (0b010000 : (bit[6]) shamt : (regno) rs1 : 0b101 : (regno) rd : 0b0010011) = Some(SHIFTIOP(shamt, rs1, rd, RISCV_SRAI)) + function clause execute (SHIFTIOP(shamt, rs1, rd, op)) = let rs1_val = rGPR(rs1) in let result = switch(op) { - case SLLI -> rs1_val >> shamt - case SRLI -> rs1_val << shamt - case SRAI -> shift_right_arith64(rs1_val, shamt) + case RISCV_SLLI -> rs1_val >> shamt + case RISCV_SRLI -> rs1_val << shamt + case RISCV_SRAI -> shift_right_arith64(rs1_val, shamt) } in wGPR(rd, result) +(********************************************************************) union ast member (regno, regno, regno, rop) RTYPE -function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b000 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, ADD)) -function clause decode (0b0100000 : (regno) rs2 : (regno) rs1 : 0b000 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, SUB)) -function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b001 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, SLL)) -function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b010 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, SLT)) -function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b011 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, SLTU)) -function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b100 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, XOR)) -function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b101 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, SRL)) -function clause decode (0b0100000 : (regno) rs2 : (regno) rs1 : 0b101 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, SRA)) -function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b110 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, OR)) -function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b111 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, AND)) + +function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b000 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, RISCV_ADD)) +function clause decode (0b0100000 : (regno) rs2 : (regno) rs1 : 0b000 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, RISCV_SUB)) +function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b001 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, RISCV_SLL)) +function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b010 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, RISCV_SLT)) +function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b011 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, RISCV_SLTU)) +function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b100 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, RISCV_XOR)) +function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b101 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, RISCV_SRL)) +function clause decode (0b0100000 : (regno) rs2 : (regno) rs1 : 0b101 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, RISCV_SRA)) +function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b110 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, RISCV_OR)) +function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b111 : (regno) rd : 0b0110011) = Some(RTYPE(rs2, rs1, rd, RISCV_AND)) + function clause execute (RTYPE(rs2, rs1, rd, op)) = let rs1_val = rGPR(rs1) in let rs2_val = rGPR(rs2) in let (bit[64]) result = switch(op) { - case ADD -> rs1_val + rs2_val - case SUB -> rs1_val - rs2_val - case SLL -> rs1_val << (rs2_val[5..0]) - case SLT -> EXTZ(rs1_val <_s rs2_val) - case SLTU -> EXTZ(rs1_val <_u rs2_val) - case XOR -> rs1_val ^ rs2_val - case SRL -> rs1_val >> (rs2_val[5..0]) - case SRA -> shift_right_arith64(rs1_val, rs2_val[5..0]) - case OR -> rs1_val | rs2_val - case AND -> rs1_val & rs2_val + case RISCV_ADD -> rs1_val + rs2_val + case RISCV_SUB -> rs1_val - rs2_val + case RISCV_SLL -> rs1_val << (rs2_val[5..0]) + case RISCV_SLT -> EXTZ(rs1_val <_s rs2_val) + case RISCV_SLTU -> EXTZ(rs1_val <_u rs2_val) + case RISCV_XOR -> rs1_val ^ rs2_val + case RISCV_SRL -> rs1_val >> (rs2_val[5..0]) + case RISCV_SRA -> shift_right_arith64(rs1_val, rs2_val[5..0]) + case RISCV_OR -> rs1_val | rs2_val + case RISCV_AND -> rs1_val & rs2_val } in wGPR(rd, result) -union ast member ((bit[12]), regno, regno, bool, word_width) LOAD -function clause decode ((bit[12]) imm : (regno) rs1 : 0b000 : (regno) rd : 0b0000011) = Some(LOAD(imm, rs1, rd, false, BYTE)) -function clause decode ((bit[12]) imm : (regno) rs1 : 0b001 : (regno) rd : 0b0000011) = Some(LOAD(imm, rs1, rd, false, HALF)) -function clause decode ((bit[12]) imm : (regno) rs1 : 0b010 : (regno) rd : 0b0000011) = Some(LOAD(imm, rs1, rd, false, WORD)) -function clause decode ((bit[12]) imm : (regno) rs1 : 0b011 : (regno) rd : 0b0000011) = Some(LOAD(imm, rs1, rd, false, DOUBLE)) -function clause decode ((bit[12]) imm : (regno) rs1 : 0b100 : (regno) rd : 0b0000011) = Some(LOAD(imm, rs1, rd, true, BYTE)) -function clause decode ((bit[12]) imm : (regno) rs1 : 0b101 : (regno) rd : 0b0000011) = Some(LOAD(imm, rs1, rd, true, HALF)) -function clause decode ((bit[12]) imm : (regno) rs1 : 0b110 : (regno) rd : 0b0000011) = Some(LOAD(imm, rs1, rd, true, WORD)) -function clause execute(LOAD(imm, rs1, rd, unsigned, width)) = +(********************************************************************) +union ast member ((bit[12]), regno, regno, bool, word_width, bool, bool) LOAD + +function clause decode ((bit[12]) imm : (regno) rs1 : 0b000 : (regno) rd : 0b0000011) = Some(LOAD(imm, rs1, rd, false, BYTE, false, false)) +function clause decode ((bit[12]) imm : (regno) rs1 : 0b001 : (regno) rd : 0b0000011) = Some(LOAD(imm, rs1, rd, false, HALF, false, false)) +function clause decode ((bit[12]) imm : (regno) rs1 : 0b010 : (regno) rd : 0b0000011) = Some(LOAD(imm, rs1, rd, false, WORD, false, false)) +function clause decode ((bit[12]) imm : (regno) rs1 : 0b011 : (regno) rd : 0b0000011) = Some(LOAD(imm, rs1, rd, false, DOUBLE, false, false)) +function clause decode ((bit[12]) imm : (regno) rs1 : 0b100 : (regno) rd : 0b0000011) = Some(LOAD(imm, rs1, rd, true, BYTE, false, false)) +function clause decode ((bit[12]) imm : (regno) rs1 : 0b101 : (regno) rd : 0b0000011) = Some(LOAD(imm, rs1, rd, true, HALF, false, false)) +function clause decode ((bit[12]) imm : (regno) rs1 : 0b110 : (regno) rd : 0b0000011) = Some(LOAD(imm, rs1, rd, true, WORD, false, false)) + +function clause execute(LOAD(imm, rs1, rd, unsigned, width, aq, rl)) = let (bit[64]) addr = rGPR(rs1) + EXTS(imm) in let (bit[64]) result = if unsigned then switch (width) { - case BYTE -> EXTZ(MEMr(addr, 1)) - case HALF -> EXTZ(MEMr(addr, 2)) - case WORD -> EXTZ(MEMr(addr, 4)) - case DOUBLE -> MEMr(addr, 8) + case BYTE -> EXTZ(mem_read(addr, 1, aq, rl, false)) + case HALF -> EXTZ(mem_read(addr, 2, aq, rl, false)) + case WORD -> EXTZ(mem_read(addr, 4, aq, rl, false)) + case DOUBLE -> mem_read(addr, 8, aq, rl, false) } else switch (width) { - case BYTE -> EXTS(MEMr(addr, 1)) - case HALF -> EXTS(MEMr(addr, 2)) - case WORD -> EXTS(MEMr(addr, 4)) - case DOUBLE -> MEMr(addr, 8) + case BYTE -> EXTS(mem_read(addr, 1, aq, rl, false)) + case HALF -> EXTS(mem_read(addr, 2, aq, rl, false)) + case WORD -> EXTS(mem_read(addr, 4, aq, rl, false)) + case DOUBLE -> mem_read(addr, 8, aq, rl, false) } in wGPR(rd, result) -union ast member ((bit[12]), regno, regno, word_width) STORE -function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b000 : (bit[5]) imm5 : 0b0100011) = Some(STORE(imm7 : imm5, rs2, rs1, BYTE)) -function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b001 : (bit[5]) imm5 : 0b0100011) = Some(STORE(imm7 : imm5, rs2, rs1, HALF)) -function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b010 : (bit[5]) imm5 : 0b0100011) = Some(STORE(imm7 : imm5, rs2, rs1, WORD)) -function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b011 : (bit[5]) imm5 : 0b0100011) = Some(STORE(imm7 : imm5, rs2, rs1, DOUBLE)) -function clause execute (STORE(imm, rs2, rs1, width)) = +(********************************************************************) +union ast member ((bit[12]), regno, regno, word_width, bool, bool) STORE + +function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b000 : (bit[5]) imm5 : 0b0100011) = + Some(STORE(imm7 : imm5, rs2, rs1, BYTE, false, false)) +function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b001 : (bit[5]) imm5 : 0b0100011) = + Some(STORE(imm7 : imm5, rs2, rs1, HALF, false, false)) +function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b010 : (bit[5]) imm5 : 0b0100011) = + Some(STORE(imm7 : imm5, rs2, rs1, WORD, false, false)) +function clause decode ((bit[7]) imm7 : (regno) rs2 : (regno) rs1 : 0b011 : (bit[5]) imm5 : 0b0100011) = + Some(STORE(imm7 : imm5, rs2, rs1, DOUBLE, false, false)) + +function clause execute (STORE(imm, rs2, rs1, width, aq, rl)) = let (bit[64]) addr = rGPR(rs1) + EXTS(imm) in { switch (width) { - case BYTE -> MEMea(addr, 1) - case HALF -> MEMea(addr, 2) - case WORD -> MEMea(addr, 4) - case DOUBLE -> MEMea(addr, 8) + case BYTE -> mem_write_ea(addr, 1, aq, rl, false) + case HALF -> mem_write_ea(addr, 2, aq, rl, false) + case WORD -> mem_write_ea(addr, 4, aq, rl, false) + case DOUBLE -> mem_write_ea(addr, 8, aq, rl, false) }; let rs2_val = rGPR(rs2) in switch (width) { - case BYTE -> MEMval(addr, 1, rs2_val[7..0]) - case HALF -> MEMval(addr, 2, rs2_val[15..0]) - case WORD -> MEMval(addr, 4, rs2_val[31..0]) - case DOUBLE -> MEMval(addr, 8, rs2_val) + case BYTE -> mem_write_value(addr, 1, rs2_val[7..0], aq, rl, false) + case HALF -> mem_write_value(addr, 2, rs2_val[15..0], aq, rl, false) + case WORD -> mem_write_value(addr, 4, rs2_val[31..0], aq, rl, false) + case DOUBLE -> mem_write_value(addr, 8, rs2_val, aq, rl, false) } } +(********************************************************************) union ast member ((bit[12]), regno, regno) ADDIW -function clause decode ((bit[12]) imm : (regno) rs1 : 0b000 : (regno) rd : 0b0011011) = Some(ADDIW(imm, rs1, rd)) + +function clause decode ((bit[12]) imm : (regno) rs1 : 0b000 : (regno) rd : 0b0011011) = + Some(ADDIW(imm, rs1, rd)) + function clause execute (ADDIW(imm, rs1, rd)) = let (bit[64]) imm64 = EXTS(imm) in let (bit[64]) result64 = imm64 + rGPR(rs1) in let (bit[64]) result32 = EXTS(result64[31..0]) in wGPR(rd, result32) +(********************************************************************) union ast member ((bit[5]), regno, regno, sop) SHIFTW -function clause decode (0b0000000 : (bit[5]) shamt : (regno) rs1 : 0b001 : (regno) rd : 0b0011011) = Some(SHIFTW(shamt, rs1, rd, SLLI)) -function clause decode (0b0000000 : (bit[5]) shamt : (regno) rs1 : 0b101 : (regno) rd : 0b0011011) = Some(SHIFTW(shamt, rs1, rd, SRLI)) -function clause decode (0b0100000 : (bit[5]) shamt : (regno) rs1 : 0b101 : (regno) rd : 0b0011011) = Some(SHIFTW(shamt, rs1, rd, SRAI)) + +function clause decode (0b0000000 : (bit[5]) shamt : (regno) rs1 : 0b001 : (regno) rd : 0b0011011) = Some(SHIFTW(shamt, rs1, rd, RISCV_SLLI)) +function clause decode (0b0000000 : (bit[5]) shamt : (regno) rs1 : 0b101 : (regno) rd : 0b0011011) = Some(SHIFTW(shamt, rs1, rd, RISCV_SRLI)) +function clause decode (0b0100000 : (bit[5]) shamt : (regno) rs1 : 0b101 : (regno) rd : 0b0011011) = Some(SHIFTW(shamt, rs1, rd, RISCV_SRAI)) + function clause execute (SHIFTW(shamt, rs1, rd, op)) = let rs1_val = (rGPR(rs1))[31..0] in let result = switch(op) { - case SLLI -> rs1_val >> shamt - case SRLI -> rs1_val << shamt - case SRAI -> shift_right_arith32(rs1_val, shamt) + case RISCV_SLLI -> rs1_val >> shamt + case RISCV_SRLI -> rs1_val << shamt + case RISCV_SRAI -> shift_right_arith32(rs1_val, shamt) } in wGPR(rd, EXTS(result)) +(********************************************************************) union ast member (regno, regno, regno, ropw) RTYPEW -function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b000 : (regno) rd : 0b0111011) = Some(RTYPEW(rs2, rs1, rd, ADDW)) -function clause decode (0b0100000 : (regno) rs2 : (regno) rs1 : 0b000 : (regno) rd : 0b0111011) = Some(RTYPEW(rs2, rs1, rd, SUBW)) -function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b001 : (regno) rd : 0b0111011) = Some(RTYPEW(rs2, rs1, rd, SLLW)) -function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b101 : (regno) rd : 0b0111011) = Some(RTYPEW(rs2, rs1, rd, SRLW)) -function clause decode (0b0100000 : (regno) rs2 : (regno) rs1 : 0b101 : (regno) rd : 0b0111011) = Some(RTYPEW(rs2, rs1, rd, SRAW)) + +function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b000 : (regno) rd : 0b0111011) = Some(RTYPEW(rs2, rs1, rd, RISCV_ADDW)) +function clause decode (0b0100000 : (regno) rs2 : (regno) rs1 : 0b000 : (regno) rd : 0b0111011) = Some(RTYPEW(rs2, rs1, rd, RISCV_SUBW)) +function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b001 : (regno) rd : 0b0111011) = Some(RTYPEW(rs2, rs1, rd, RISCV_SLLW)) +function clause decode (0b0000000 : (regno) rs2 : (regno) rs1 : 0b101 : (regno) rd : 0b0111011) = Some(RTYPEW(rs2, rs1, rd, RISCV_SRLW)) +function clause decode (0b0100000 : (regno) rs2 : (regno) rs1 : 0b101 : (regno) rd : 0b0111011) = Some(RTYPEW(rs2, rs1, rd, RISCV_SRAW)) + function clause execute (RTYPEW(rs2, rs1, rd, op)) = let rs1_val = (rGPR(rs1))[31..0] in let rs2_val = (rGPR(rs2))[31..0] in let (bit[32]) result = switch(op) { - case ADDW -> rs1_val + rs2_val - case SUBW -> rs1_val - rs2_val - case SLLW -> rs1_val << (rs2_val[4..0]) - case SRLW -> rs1_val >> (rs2_val[4..0]) - case SRAW -> shift_right_arith32(rs1_val, rs2_val[4..0]) + case RISCV_ADDW -> rs1_val + rs2_val + case RISCV_SUBW -> rs1_val - rs2_val + case RISCV_SLLW -> rs1_val << (rs2_val[4..0]) + case RISCV_SRLW -> rs1_val >> (rs2_val[4..0]) + case RISCV_SRAW -> shift_right_arith32(rs1_val, rs2_val[4..0]) } in wGPR(rd, EXTS(result)) +(********************************************************************) union ast member (bit[4], bit[4]) FENCE + function clause decode (0b0000 : (bit[4]) pred : (bit[4]) succ : 0b00000 : 0b000 : 0b00000 : 0b0001111) = Some(FENCE (pred, succ)) + function clause execute (FENCE(pred, succ)) = { switch(pred, succ) { case (0b0011, 0b0011) -> MEM_fence_rw_rw() case (0b0010, 0b0011) -> MEM_fence_r_rw() + case (0b0010, 0b0010) -> MEM_fence_r_r() case (0b0011, 0b0001) -> MEM_fence_rw_w() + case (0b0001, 0b0001) -> MEM_fence_w_w() case _ -> not_implemented("unsupported fence") } } +(********************************************************************) union ast member unit FENCEI -function clause decode (0b0000 : 0b0000 : 0b0000 : 0b00000 : 0b001 : 0b00000 : 0b0001111) = Some(FENCEI) -function clause execute FENCEI = () (* XXX TODO *) +function clause decode (0b000000000000 : 0b00000 : 0b001 : 0b00000 : 0b0001111) = Some(FENCEI) +function clause execute FENCEI = MEM_fence_i() +(********************************************************************) union ast member unit ECALL function clause decode (0b000000000000 : 0b00000 : 0b000 : 0b00000 : 0b1110011) = Some(ECALL ()) -function clause execute ECALL = () +function clause execute ECALL = not_implemented("ECALL is not implemented") +(********************************************************************) union ast member unit EBREAK function clause decode (0b000000000001 : 0b00000 : 0b000 : 0b00000 : 0b1110011) = Some(EBREAK ()) function clause execute EBREAK = { exit () } +(********************************************************************) +union ast member (bool, bool, regno, word_width, regno) LOADRES + +function clause decode (0b00010 : [aq] : [rl] : 0b00000 : (regno) rs1 : 0b010 : (regno) rd : 0b0101111) = Some(LOADRES(aq, rl, rs1, WORD, rd)) +function clause decode (0b00010 : [aq] : [rl] : 0b00000 : (regno) rs1 : 0b011 : (regno) rd : 0b0101111) = Some(LOADRES(aq, rl, rs1, DOUBLE, rd)) +function clause execute(LOADRES(aq, rl, rs1, width, rd)) = + let (bit[64]) addr = rGPR(rs1) in + let (bit[64]) result = + switch width { + case WORD -> EXTS(mem_read(addr, 4, aq, rl, true)) + case DOUBLE -> mem_read(addr, 8, aq, rl, true) + } in + wGPR(rd, result) + +(********************************************************************) +union ast member (bool, bool, regno, regno, word_width, regno) STORECON + +function clause decode (0b00011 : [aq] : [rl] : (regno) rs2 : (regno) rs1 : 0b010 : (regno) rd : 0b0101111) = + Some(STORECON(aq, rl, rs2, rs1, WORD, rd)) +function clause decode (0b00011 : [aq] : [rl] : (regno) rs2 : (regno) rs1 : 0b011 : (regno) rd : 0b0101111) = + Some(STORECON(aq, rl, rs2, rs1, DOUBLE, rd)) + +function clause execute (STORECON(aq, rl, rs2, rs1, width, rd)) = { + (*(bit)*) status := if speculate_conditional_success() then 0 else 1; + wGPR(rd) := (bit[64]) (EXTZ([status])); + + if status == 1 then () else { + (bit[64]) addr := rGPR(rs1); + switch width { + case WORD -> mem_write_ea(addr, 4, aq, rl, true) + case DOUBLE -> mem_write_ea(addr, 8, aq, rl, true) + }; + rs2_val := rGPR(rs2); + switch width { + case WORD -> mem_write_value(addr, 4, rs2_val[31..0], aq, rl, true) + case DOUBLE -> mem_write_value(addr, 8, rs2_val, aq, rl, true) + }; + }; +} + +(********************************************************************) +union ast member (amoop, bool, bool, regno, regno, word_width, regno) AMO + +function clause decode (0b00001 : [aq] : [rl] : (regno) rs2 : (regno) rs1 : 0b010 : (regno) rd : 0b0101111) = + Some(AMO(AMOSWAP, aq, rl, rs2, rs1, WORD, rd)) +function clause decode (0b00001 : [aq] : [rl] : (regno) rs2 : (regno) rs1 : 0b011 : (regno) rd : 0b0101111) = + Some(AMO(AMOSWAP, aq, rl, rs2, rs1, DOUBLE, rd)) +function clause decode (0b00000 : [aq] : [rl] : (regno) rs2 : (regno) rs1 : 0b010 : (regno) rd : 0b0101111) = + Some(AMO(AMOADD , aq, rl, rs2, rs1, WORD, rd)) +function clause decode (0b00000 : [aq] : [rl] : (regno) rs2 : (regno) rs1 : 0b011 : (regno) rd : 0b0101111) = + Some(AMO(AMOADD , aq, rl, rs2, rs1, DOUBLE, rd)) +function clause decode (0b00100 : [aq] : [rl] : (regno) rs2 : (regno) rs1 : 0b010 : (regno) rd : 0b0101111) = + Some(AMO(AMOXOR , aq, rl, rs2, rs1, WORD, rd)) +function clause decode (0b00100 : [aq] : [rl] : (regno) rs2 : (regno) rs1 : 0b011 : (regno) rd : 0b0101111) = + Some(AMO(AMOXOR , aq, rl, rs2, rs1, DOUBLE, rd)) +function clause decode (0b01100 : [aq] : [rl] : (regno) rs2 : (regno) rs1 : 0b010 : (regno) rd : 0b0101111) = + Some(AMO(AMOAND , aq, rl, rs2, rs1, WORD, rd)) +function clause decode (0b01100 : [aq] : [rl] : (regno) rs2 : (regno) rs1 : 0b011 : (regno) rd : 0b0101111) = + Some(AMO(AMOAND , aq, rl, rs2, rs1, DOUBLE, rd)) +function clause decode (0b01000 : [aq] : [rl] : (regno) rs2 : (regno) rs1 : 0b010 : (regno) rd : 0b0101111) = + Some(AMO(AMOOR , aq, rl, rs2, rs1, WORD, rd)) +function clause decode (0b01000 : [aq] : [rl] : (regno) rs2 : (regno) rs1 : 0b011 : (regno) rd : 0b0101111) = + Some(AMO(AMOOR , aq, rl, rs2, rs1, DOUBLE, rd)) +function clause decode (0b10000 : [aq] : [rl] : (regno) rs2 : (regno) rs1 : 0b010 : (regno) rd : 0b0101111) = + Some(AMO(AMOMIN , aq, rl, rs2, rs1, WORD, rd)) +function clause decode (0b10000 : [aq] : [rl] : (regno) rs2 : (regno) rs1 : 0b011 : (regno) rd : 0b0101111) = + Some(AMO(AMOMIN , aq, rl, rs2, rs1, DOUBLE, rd)) +function clause decode (0b10100 : [aq] : [rl] : (regno) rs2 : (regno) rs1 : 0b010 : (regno) rd : 0b0101111) = + Some(AMO(AMOMAX , aq, rl, rs2, rs1, WORD, rd)) +function clause decode (0b10100 : [aq] : [rl] : (regno) rs2 : (regno) rs1 : 0b011 : (regno) rd : 0b0101111) = + Some(AMO(AMOMAX , aq, rl, rs2, rs1, DOUBLE, rd)) +function clause decode (0b11000 : [aq] : [rl] : (regno) rs2 : (regno) rs1 : 0b010 : (regno) rd : 0b0101111) = + Some(AMO(AMOMINU, aq, rl, rs2, rs1, WORD, rd)) +function clause decode (0b11000 : [aq] : [rl] : (regno) rs2 : (regno) rs1 : 0b011 : (regno) rd : 0b0101111) = + Some(AMO(AMOMINU, aq, rl, rs2, rs1, DOUBLE, rd)) +function clause decode (0b11100 : [aq] : [rl] : (regno) rs2 : (regno) rs1 : 0b010 : (regno) rd : 0b0101111) = + Some(AMO(AMOMAXU, aq, rl, rs2, rs1, WORD, rd)) +function clause decode (0b11100 : [aq] : [rl] : (regno) rs2 : (regno) rs1 : 0b011 : (regno) rd : 0b0101111) = + Some(AMO(AMOMAXU, aq, rl, rs2, rs1, DOUBLE, rd)) + +function clause execute (AMO(op, aq, rl, rs2, rs1, width, rd)) = { + (bit[64]) addr := rGPR(rs1); + + switch (width) { + case WORD -> mem_write_ea(addr, 4, aq & rl, rl, true) + case DOUBLE -> mem_write_ea(addr, 8, aq & rl, rl, true) + }; + + (bit[64]) loaded := + switch (width) { + case WORD -> EXTS(mem_read(addr, 4, aq, aq & rl, true)) + case DOUBLE -> mem_read(addr, 8, aq, aq & rl, true) + }; + wGPR(rd, loaded); + + (bit[64]) rs2_val := rGPR(rs2); + (bit[64]) result := + switch(op) { + case AMOSWAP -> rs2_val + case AMOADD -> rs2_val + loaded + case AMOXOR -> rs2_val ^ loaded + case AMOAND -> rs2_val & loaded + case AMOOR -> rs2_val | loaded + + case AMOMIN -> (bit[64]) (min(signed(rs2_val), signed(loaded))) + case AMOMAX -> (bit[64]) (max(signed(rs2_val), signed(loaded))) + case AMOMINU -> (bit[64]) (min(unsigned(rs2_val), unsigned(loaded))) + case AMOMAXU -> (bit[64]) (max(unsigned(rs2_val), unsigned(loaded))) + }; + + switch (width) { + case WORD -> mem_write_value(addr, 4, result[31..0], aq & rl, rl, true) + case DOUBLE -> mem_write_value(addr, 8, result, aq & rl, rl, true) + }; +} + +(********************************************************************) function clause decode _ = None diff --git a/risc-v/riscv_extras.lem b/risc-v/riscv_extras.lem index aa5d8fb8..30043779 100644 --- a/risc-v/riscv_extras.lem +++ b/risc-v/riscv_extras.lem @@ -32,29 +32,52 @@ let memory_parameter_transformer_option_address _mode v = let read_memory_functions : memory_reads = - [ ("MEMr", (MR Read_plain memory_parameter_transformer)); - ("MEMr_reserve", (MR Read_reserve memory_parameter_transformer)); + [ ("MEMr", (MR Read_plain memory_parameter_transformer)); + ("MEMr_acquire", (MR Read_RISCV_acquire memory_parameter_transformer)); + ("MEMr_strong_acquire", (MR Read_RISCV_strong_acquire memory_parameter_transformer)); + ("MEMr_reserved", (MR Read_RISCV_reserved memory_parameter_transformer)); + ("MEMr_reserved_acquire", (MR Read_RISCV_reserved_acquire memory_parameter_transformer)); + ("MEMr_reserved_strong_acquire", + (MR Read_RISCV_reserved_acquire memory_parameter_transformer)); ] let memory_writes : memory_writes = [] let memory_eas : memory_write_eas = - [ ("MEMea", (MEA Write_plain memory_parameter_transformer)); - ("MEMea_conditional", (MEA Write_conditional memory_parameter_transformer)); + [ ("MEMea", (MEA Write_plain memory_parameter_transformer)); + ("MEMea_release", (MEA Write_RISCV_release memory_parameter_transformer)); + ("MEMea_strong_release", (MEA Write_RISCV_strong_release memory_parameter_transformer)); + ("MEMea_conditional", (MEA Write_RISCV_conditional memory_parameter_transformer)); + ("MEMea_conditional_release", (MEA Write_RISCV_conditional_release memory_parameter_transformer)); + ("MEMea_conditional_strong_release", + (MEA Write_RISCV_conditional_strong_release + memory_parameter_transformer)); ] let memory_vals : memory_write_vals = - [ ("MEMval", (MV memory_parameter_transformer_option_address Nothing)); - ("MEMval_conditional", (MV memory_parameter_transformer_option_address - (Just - (fun (IState interp context) b -> - let bit = Interp_ast.V_lit (L_aux (if b then L_one else L_zero) Interp_ast.Unknown) in - (IState (Interp.add_answer_to_stack interp bit) context))))); + [ ("MEMval", (MV memory_parameter_transformer_option_address Nothing)); + ("MEMval_release", (MV memory_parameter_transformer_option_address Nothing)); + ("MEMval_strong_release", (MV memory_parameter_transformer_option_address Nothing)); + ("MEMval_conditional", (MV memory_parameter_transformer_option_address Nothing)); + ("MEMval_conditional_release",(MV memory_parameter_transformer_option_address Nothing)); + ("MEMval_conditional_strong_release", + (MV memory_parameter_transformer_option_address Nothing)); + ] +let speculate_conditional_success : excl_res = + let f = fun (IState interp context) b -> + let bool_res = Interp_ast.V_lit (L_aux (if b then L_one else L_zero) Interp_ast.Unknown) in + IState (Interp.add_answer_to_stack interp bool_res) context + in + Just ("speculate_conditional_success", (ER (Just f))) + let barrier_functions = [ ("MEM_fence_rw_rw", Barrier_RISCV_rw_rw); ("MEM_fence_r_rw", Barrier_RISCV_r_rw); + ("MEM_fence_r_r", Barrier_RISCV_r_r); ("MEM_fence_rw_w", Barrier_RISCV_rw_w); + ("MEM_fence_w_w", Barrier_RISCV_w_w); + ("MEM_fence_i", Barrier_RISCV_i); ] diff --git a/risc-v/riscv_extras_embed.lem b/risc-v/riscv_extras_embed.lem index 1146d1cd..32110079 100644 --- a/risc-v/riscv_extras_embed.lem +++ b/risc-v/riscv_extras_embed.lem @@ -4,31 +4,66 @@ open import Sail_impl_base open import Sail_values open import Prompt -val MEMr : (vector bitU * integer) -> M (vector bitU) -val MEMr_reserve : (vector bitU * integer) -> M (vector bitU) +val MEMr : (vector bitU * integer) -> M (vector bitU) +val MEMr_acquire : (vector bitU * integer) -> M (vector bitU) +val MEMr_strong_acquire : (vector bitU * integer) -> M (vector bitU) +val MEMr_reserved : (vector bitU * integer) -> M (vector bitU) +val MEMr_reserved_acquire : (vector bitU * integer) -> M (vector bitU) +val MEMr_reserved_strong_acquire : (vector bitU * integer) -> M (vector bitU) -let MEMr (addr,size) = read_mem false Read_plain addr size -let MEMr_reserve (addr,size) = read_mem false Read_reserve addr size +let MEMr (addr,size) = read_mem false Read_plain addr size +let MEMr_acquire (addr,size) = read_mem false Read_RISCV_acquire addr size +let MEMr_strong_acquire (addr,size) = read_mem false Read_RISCV_strong_acquire addr size +let MEMr_reserved (addr,size) = read_mem false Read_RISCV_reserved addr size +let MEMr_reserved_acquire (addr,size) = read_mem false Read_RISCV_reserved_acquire addr size +let MEMr_reserved_strong_acquire (addr,size) + = read_mem false Read_RISCV_reserved_strong_acquire addr size -val MEMea : (vector bitU * integer) -> M unit -val MEMea_conditional : (vector bitU * integer) -> M unit +val MEMea : (vector bitU * integer) -> M unit +val MEMea_release : (vector bitU * integer) -> M unit +val MEMea_strong_release : (vector bitU * integer) -> M unit +val MEMea_conditional : (vector bitU * integer) -> M unit +val MEMea_conditional_release : (vector bitU * integer) -> M unit +val MEMea_conditional_strong_release : (vector bitU * integer) -> M unit -let MEMea (addr,size) = write_mem_ea Write_plain addr size -let MEMea_conditional (addr,size) = write_mem_ea Write_conditional addr size +let MEMea (addr,size) = write_mem_ea Write_plain addr size +let MEMea_release (addr,size) = write_mem_ea Write_RISCV_release addr size +let MEMea_strong_release (addr,size) = write_mem_ea Write_RISCV_strong_release addr size +let MEMea_conditional (addr,size) = write_mem_ea Write_RISCV_conditional addr size +let MEMea_conditional_release (addr,size) = write_mem_ea Write_RISCV_conditional_release addr size +let MEMea_conditional_strong_release (addr,size) + = write_mem_ea Write_RISCV_conditional_strong_release addr size -val MEMval : (vector bitU * integer * vector bitU) -> M unit -val MEMval_conditional : (vector bitU * integer * vector bitU) -> M bitU +val MEMval : (vector bitU * integer * vector bitU) -> M unit +val MEMval_release : (vector bitU * integer * vector bitU) -> M unit +val MEMval_strong_release : (vector bitU * integer * vector bitU) -> M unit +val MEMval_conditional : (vector bitU * integer * vector bitU) -> M unit +val MEMval_conditional_release : (vector bitU * integer * vector bitU) -> M unit +val MEMval_conditional_strong_release : (vector bitU * integer * vector bitU) -> M unit -let MEMval (_,_,v) = write_mem_val v >>= fun _ -> return () -let MEMval_conditional (_,_,v) = write_mem_val v >>= fun b -> return (if b then B1 else B0) +let MEMval (_,_,v) = write_mem_val v >>= fun _ -> return () +let MEMval_release (_,_,v) = write_mem_val v >>= fun _ -> return () +let MEMval_strong_release (_,_,v) = write_mem_val v >>= fun _ -> return () +let MEMval_conditional (_,_,v) = write_mem_val v >>= fun _ -> return () +let MEMval_conditional_release (_,_,v) = write_mem_val v >>= fun _ -> return () +let MEMval_conditional_strong_release (_,_,v) + = write_mem_val v >>= fun _ -> return () + +let speculate_conditional_success () = excl_result () >>= fun b -> return (if b then B1 else B0) val MEM_fence_rw_rw : unit -> M unit val MEM_fence_r_rw : unit -> M unit +val MEM_fence_r_r : unit -> M unit val MEM_fence_rw_w : unit -> M unit +val MEM_fence_w_w : unit -> M unit +val MEM_fence_i : unit -> M unit let MEM_fence_rw_rw () = barrier Barrier_RISCV_rw_rw let MEM_fence_r_rw () = barrier Barrier_RISCV_r_rw +let MEM_fence_r_r () = barrier Barrier_RISCV_r_r let MEM_fence_rw_w () = barrier Barrier_RISCV_rw_w +let MEM_fence_w_w () = barrier Barrier_RISCV_w_w +let MEM_fence_i () = barrier Barrier_RISCV_i let duplicate (bit,len) = let bits = repeat [bit] len in diff --git a/risc-v/riscv_extras_embed_sequential.lem b/risc-v/riscv_extras_embed_sequential.lem index f6709ff7..3c922268 100644 --- a/risc-v/riscv_extras_embed_sequential.lem +++ b/risc-v/riscv_extras_embed_sequential.lem @@ -4,32 +4,66 @@ open import Sail_impl_base open import Sail_values open import State -val MEMr : (vector bitU * integer) -> M (vector bitU) -val MEMr_reserve : (vector bitU * integer) -> M (vector bitU) +val MEMr : (vector bitU * integer) -> M (vector bitU) +val MEMr_acquire : (vector bitU * integer) -> M (vector bitU) +val MEMr_strong_acquire : (vector bitU * integer) -> M (vector bitU) +val MEMr_reserved : (vector bitU * integer) -> M (vector bitU) +val MEMr_reserved_acquire : (vector bitU * integer) -> M (vector bitU) +val MEMr_reserved_strong_acquire : (vector bitU * integer) -> M (vector bitU) -let MEMr (addr,size) = read_mem false Read_plain addr size -let MEMr_reserve (addr,size) = read_mem false Read_reserve addr size +let MEMr (addr,size) = read_mem false Read_plain addr size +let MEMr_acquire (addr,size) = read_mem false Read_RISCV_acquire addr size +let MEMr_strong_acquire (addr,size) = read_mem false Read_RISCV_strong_acquire addr size +let MEMr_reserved (addr,size) = read_mem false Read_RISCV_reserved addr size +let MEMr_reserved_acquire (addr,size) = read_mem false Read_RISCV_reserved_acquire addr size +let MEMr_reserved_strong_acquire (addr,size) + = read_mem false Read_RISCV_reserved_strong_acquire addr size -val MEMea : (vector bitU * integer) -> M unit -val MEMea_conditional : (vector bitU * integer) -> M unit +val MEMea : (vector bitU * integer) -> M unit +val MEMea_release : (vector bitU * integer) -> M unit +val MEMea_strong_release : (vector bitU * integer) -> M unit +val MEMea_conditional : (vector bitU * integer) -> M unit +val MEMea_conditional_release : (vector bitU * integer) -> M unit +val MEMea_conditional_strong_release : (vector bitU * integer) -> M unit -let MEMea (addr,size) = write_mem_ea Write_plain addr size -let MEMea_conditional (addr,size) = write_mem_ea Write_conditional addr size +let MEMea (addr,size) = write_mem_ea Write_plain addr size +let MEMea_release (addr,size) = write_mem_ea Write_RISCV_release addr size +let MEMea_strong_release (addr,size) = write_mem_ea Write_RISCV_strong_release addr size +let MEMea_conditional (addr,size) = write_mem_ea Write_RISCV_conditional addr size +let MEMea_conditional_release (addr,size) = write_mem_ea Write_RISCV_conditional_release addr size +let MEMea_conditional_strong_release (addr,size) + = write_mem_ea Write_RISCV_conditional_strong_release addr size +val MEMval : (vector bitU * integer * vector bitU) -> M unit +val MEMval_release : (vector bitU * integer * vector bitU) -> M unit +val MEMval_strong_release : (vector bitU * integer * vector bitU) -> M unit +val MEMval_conditional : (vector bitU * integer * vector bitU) -> M unit +val MEMval_conditional_release : (vector bitU * integer * vector bitU) -> M unit +val MEMval_conditional_strong_release : (vector bitU * integer * vector bitU) -> M unit -val MEMval : (vector bitU * integer * vector bitU) -> M unit -val MEMval_conditional : (vector bitU * integer * vector bitU) -> M bitU +let MEMval (_,_,v) = write_mem_val v >>= fun _ -> return () +let MEMval_release (_,_,v) = write_mem_val v >>= fun _ -> return () +let MEMval_strong_release (_,_,v) = write_mem_val v >>= fun _ -> return () +let MEMval_conditional (_,_,v) = write_mem_val v >>= fun _ -> return () +let MEMval_conditional_release (_,_,v) = write_mem_val v >>= fun _ -> return () +let MEMval_conditional_strong_release (_,_,v) + = write_mem_val v >>= fun _ -> return () -let MEMval (_,_,v) = write_mem_val v >>= fun _ -> return () -let MEMval_conditional (_,_,v) = write_mem_val v >>= fun b -> return (if b then B1 else B0) +let speculate_conditional_success () = excl_result () >>= fun b -> return (if b then B1 else B0) val MEM_fence_rw_rw : unit -> M unit val MEM_fence_r_rw : unit -> M unit +val MEM_fence_r_r : unit -> M unit val MEM_fence_rw_w : unit -> M unit +val MEM_fence_w_w : unit -> M unit +val MEM_fence_i : unit -> M unit let MEM_fence_rw_rw () = barrier Barrier_RISCV_rw_rw let MEM_fence_r_rw () = barrier Barrier_RISCV_r_rw +let MEM_fence_r_r () = barrier Barrier_RISCV_r_r let MEM_fence_rw_w () = barrier Barrier_RISCV_rw_w +let MEM_fence_w_w () = barrier Barrier_RISCV_w_w +let MEM_fence_i () = barrier Barrier_RISCV_i let duplicate (bit,len) = let bits = repeat [bit] len in diff --git a/risc-v/riscv_regfp.sail b/risc-v/riscv_regfp.sail index 0c7a67d8..dee9cc8e 100644 --- a/risc-v/riscv_regfp.sail +++ b/risc-v/riscv_regfp.sail @@ -20,16 +20,16 @@ function (regfps,regfps,regfps,niafps,diafp,instruction_kind) initial_analysis ( case (UTYPE ( imm, rd, op)) -> { if (rd == 0) then () else oR := RFull(GPRstr[rd]) :: oR; } - case (JAL ( imm, rd)) -> { + case (RISCV_JAL ( imm, rd)) -> { if (rd == 0) then () else oR := RFull(GPRstr[rd]) :: oR; let (bit[64]) offset = EXTS(imm) in Nias := [|| NIAFP_concrete_address (PC + offset) ||] } - case (JALR ( imm, rs, rd)) -> { + case (RISCV_JALR ( imm, rs, rd)) -> { if (rs == 0) then () else iR := RFull(GPRstr[rs]) :: iR; if (rd == 0) then () else oR := RFull(GPRstr[rd]) :: oR; let (bit[64]) offset = EXTS(imm) in - Nias := [|| NIAFP_register (RFull(GPRstr[rs])) ||]; (* XXX this should br rs + offset... *) + Nias := [|| NIAFP_register (RFull(GPRstr[rs])) ||]; } case (BTYPE ( imm, rs2, rs1, op)) -> { if (rs2 == 0) then () else iR := RFull(GPRstr[rs2]) :: iR; @@ -51,17 +51,29 @@ function (regfps,regfps,regfps,niafps,diafp,instruction_kind) initial_analysis ( if (rs1 == 0) then () else iR := RFull(GPRstr[rs1]) :: iR; if (rd == 0) then () else oR := RFull(GPRstr[rd]) :: oR; } - case (LOAD ( imm, rs, rd, unsign, width)) -> { (* XXX "unsigned" causes name conflict in lem shallow embedding... *) + case (LOAD ( imm, rs, rd, unsign, width, aq, rl)) -> { (* XXX "unsigned" causes name conflict in lem shallow embedding... *) if (rs == 0) then () else iR := RFull(GPRstr[rs]) :: iR; if (rd == 0) then () else oR := RFull(GPRstr[rd]) :: oR; aR := iR; - ik := IK_mem_read (Read_plain); + ik := + switch (aq, rl) { + case (false, false) -> IK_mem_read (Read_plain) + case (true, false) -> IK_mem_read (Read_RISCV_acquire) + case (false, true) -> exit "not implemented" + case (true, true) -> IK_mem_read (Read_RISCV_strong_acquire) + }; } - case (STORE( imm, rs2, rs1, width)) -> { + case (STORE( imm, rs2, rs1, width, aq, rl)) -> { if (rs2 == 0) then () else iR := RFull(GPRstr[rs2]) :: iR; if (rs1 == 0) then () else iR := RFull(GPRstr[rs1]) :: iR; if (rs1 == 0) then () else aR := RFull(GPRstr[rs1]) :: aR; - ik := IK_mem_write (Write_plain); + ik := + switch (aq, rl) { + case (false, false) -> IK_mem_write (Write_plain) + case (true, false) -> exit "not implemented" + case (false, true) -> IK_mem_write (Write_RISCV_release) + case (true, true) -> IK_mem_write (Write_RISCV_strong_release) + }; } case (ADDIW ( imm, rs, rd)) -> { if (rs == 0) then () else iR := RFull(GPRstr[rs]) :: iR; @@ -77,7 +89,56 @@ function (regfps,regfps,regfps,niafps,diafp,instruction_kind) initial_analysis ( if (rd == 0) then () else oR := RFull(GPRstr[rd]) :: oR; } case (FENCE(pred, succ)) -> { - ik := IK_barrier (Barrier_MIPS_SYNC); + ik := + switch(pred, succ) { + case (0b0011, 0b0011) -> IK_barrier (Barrier_RISCV_rw_rw) + case (0b0010, 0b0011) -> IK_barrier (Barrier_RISCV_r_rw) + case (0b0010, 0b0010) -> IK_barrier (Barrier_RISCV_r_r) + case (0b0011, 0b0001) -> IK_barrier (Barrier_RISCV_rw_w) + case (0b0001, 0b0001) -> IK_barrier (Barrier_RISCV_w_w) + case _ -> exit "not implemented" + }; + } + case (FENCEI) -> { + ik := IK_barrier (Barrier_RISCV_i); + } + case (LOADRES ( aq, rl, rs1, width, rd)) -> { + if (rs1 == 0) then () else iR := RFull(GPRstr[rs1]) :: iR; + if (rd == 0) then () else oR := RFull(GPRstr[rd]) :: oR; + aR := iR; + ik := switch (aq, rl) { + case (false, false) -> IK_mem_read (Read_RISCV_reserved) + case (true, false) -> IK_mem_read (Read_RISCV_reserved_acquire) + case (false, true) -> exit "not implemented" + case (true, true) -> IK_mem_read (Read_RISCV_reserved_strong_acquire) + }; + } + case (STORECON( aq, rl, rs2, rs1, width, rd)) -> { + if (rs2 == 0) then () else iR := RFull(GPRstr[rs2]) :: iR; + if (rs1 == 0) then () else iR := RFull(GPRstr[rs1]) :: iR; + if (rs1 == 0) then () else aR := RFull(GPRstr[rs1]) :: aR; + if (rd == 0) then () else oR := RFull(GPRstr[rd]) :: oR; + + ik := switch (aq, rl) { + case (false, false) -> IK_mem_write (Write_RISCV_conditional) + case (false, true) -> IK_mem_write (Write_RISCV_conditional_release) + case (true, _) -> exit "not implemented" + }; + } + case (AMO( op, aq, rl, rs2, rs1, width, rd)) -> { + if (rs2 == 0) then () else iR := RFull(GPRstr[rs2]) :: iR; + if (rs1 == 0) then () else iR := RFull(GPRstr[rs1]) :: iR; + if (rs1 == 0) then () else aR := RFull(GPRstr[rs1]) :: aR; + if (rd == 0) then () else oR := RFull(GPRstr[rd]) :: oR; + + ik := switch (aq, rl) { + case (false, false) -> IK_mem_rmw (Read_RISCV_reserved, Write_RISCV_conditional) + case (false, true) -> IK_mem_rmw (Read_RISCV_reserved, Write_RISCV_conditional_release) + case (true, false) -> IK_mem_rmw (Read_RISCV_reserved_acquire, + Write_RISCV_conditional) + case (true, true) -> IK_mem_rmw (Read_RISCV_reserved_strong_acquire, + Write_RISCV_conditional_strong_release) + }; } }; (iR,oR,aR,Nias,Dia,ik) diff --git a/risc-v/riscv_types.sail b/risc-v/riscv_types.sail new file mode 100644 index 00000000..b584ae9b --- /dev/null +++ b/risc-v/riscv_types.sail @@ -0,0 +1,166 @@ +default Order dec + +function forall 'a. 'a effect { escape } not_implemented((string) message) = + exit message + +typedef regval = bit[64] +typedef regno = bit[5] + +(* register (regval) x0 is hard-wired zero *) +register (regval) x1 +register (regval) x2 +register (regval) x3 +register (regval) x4 +register (regval) x5 +register (regval) x6 +register (regval) x7 +register (regval) x8 +register (regval) x9 +register (regval) x10 +register (regval) x11 +register (regval) x12 +register (regval) x13 +register (regval) x14 +register (regval) x15 +register (regval) x16 +register (regval) x17 +register (regval) x18 +register (regval) x19 +register (regval) x20 +register (regval) x21 +register (regval) x22 +register (regval) x23 +register (regval) x24 +register (regval) x25 +register (regval) x26 +register (regval) x27 +register (regval) x28 +register (regval) x29 +register (regval) x30 +register (regval) x31 + +register (bit[64]) PC +register (bit[64]) nextPC + +let (vector <1, 31, inc, (register<(regval)>)>) GPRs = + [ (* x0, *) x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, + x15, x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, + x28, x29, x30, x31 + ] + +function (regval) rGPR ((regno) r) = + if (r == 0) then + 0 + else + GPRs[r] + +function unit wGPR((regno) r, (regval) v) = + if (r != 0) then + GPRs[r] := v + +function unit effect { escape } check_alignment( (bit[64]) addr, (nat) width) = + if (unsigned(addr) mod width != 0) then + exit "misaligned memory access" + +val extern forall Nat 'n. ( bit[64] , [|'n|] ) -> (bit[8 * 'n]) effect { rmem } MEMr +val extern forall Nat 'n. ( bit[64] , [|'n|] ) -> (bit[8 * 'n]) effect { rmem } MEMr_acquire +val extern forall Nat 'n. ( bit[64] , [|'n|] ) -> (bit[8 * 'n]) effect { rmem } MEMr_strong_acquire +val extern forall Nat 'n. ( bit[64] , [|'n|] ) -> (bit[8 * 'n]) effect { rmem } MEMr_reserved +val extern forall Nat 'n. ( bit[64] , [|'n|] ) -> (bit[8 * 'n]) effect { rmem } MEMr_reserved_acquire +val extern forall Nat 'n. ( bit[64] , [|'n|] ) -> (bit[8 * 'n]) effect { rmem } MEMr_reserved_strong_acquire + +function forall Nat 'n. (bit[8 * 'n]) effect { rmem, escape } mem_read( (bit[64]) addr, ([|'n|]) width, (bool) aq, (bool) rl, (bool) res) = +{ + if (aq | res) then + check_alignment(addr, width); + + switch (aq, rl, res) { + case (false, false, false) -> MEMr(addr, width) + case (true, false, false) -> MEMr_acquire(addr, width) + case (false, false, true) -> MEMr_reserved(addr, width) + case (true, false, true) -> MEMr_reserved_acquire(addr, width) + case (false, true, false) -> not_implemented("load.rl is not implemented") + case (true, true, false) -> MEMr_strong_acquire(addr, width) + case (false, true, true) -> not_implemented("lr.rl is not implemented") + case (true, true, true) -> MEMr_reserved_strong_acquire(addr, width) + } +} + +val extern forall Nat 'n. ( bit[64] , [|'n|]) -> unit effect { eamem } MEMea +val extern forall Nat 'n. ( bit[64] , [|'n|]) -> unit effect { eamem } MEMea_release +val extern forall Nat 'n. ( bit[64] , [|'n|]) -> unit effect { eamem } MEMea_strong_release +val extern forall Nat 'n. ( bit[64] , [|'n|]) -> unit effect { eamem } MEMea_conditional +val extern forall Nat 'n. ( bit[64] , [|'n|]) -> unit effect { eamem } MEMea_conditional_release +val extern forall Nat 'n. ( bit[64] , [|'n|]) -> unit effect { eamem } MEMea_conditional_strong_release + +function forall Nat 'n. unit effect { eamem, escape } mem_write_ea( (bit[64]) addr , ([|'n|]) width, (bool) aq, (bool) rl, (bool) con) = +{ + if (rl | con) then + check_alignment(addr, width); + + switch (aq, rl, con) { + case (false, false, false) -> MEMea(addr, width) + case (false, true, false) -> MEMea_release(addr, width) + case (false, false, true) -> MEMea_conditional(addr, width) + case (false, true , true) -> MEMea_conditional_release(addr, width) + case (true, false, false) -> not_implemented("store.aq is not implemented") + case (true, true, false) -> MEMea_strong_release(addr, width) + case (true, false, true) -> not_implemented("sc.aq is not implemented") + case (true, true , true) -> MEMea_conditional_strong_release(addr, width) + } +} + +val extern forall Nat 'n. ( bit[64] , [|'n|] , bit[8*'n]) -> unit effect { wmv } MEMval +val extern forall Nat 'n. ( bit[64] , [|'n|] , bit[8*'n]) -> unit effect { wmv } MEMval_release +val extern forall Nat 'n. ( bit[64] , [|'n|] , bit[8*'n]) -> unit effect { wmv } MEMval_strong_release +val extern forall Nat 'n. ( bit[64] , [|'n|] , bit[8*'n]) -> unit effect { wmv } MEMval_conditional +val extern forall Nat 'n. ( bit[64] , [|'n|] , bit[8*'n]) -> unit effect { wmv } MEMval_conditional_release +val extern forall Nat 'n. ( bit[64] , [|'n|] , bit[8*'n]) -> unit effect { wmv } MEMval_conditional_strong_release + +function forall Nat 'n. unit effect { wmv, escape } mem_write_value( (bit[64]) addr , ([|'n|]) width , (bit[8*'n]) value, (bool) aq, (bool) rl, (bool) con) = +{ + if (rl | con) then + check_alignment(addr, width); + + switch (aq, rl, con) { + case (false, false, false) -> MEMval(addr, width, value) + case (false, true, false) -> MEMval_release(addr, width, value) + case (false, false, true) -> MEMval_conditional(addr, width, value) + case (false, true, true) -> MEMval_conditional_release(addr, width, value) + case (true, false, false) -> not_implemented("store.aq is not implemented") + case (true, true, false) -> MEMval_strong_release(addr, width, value) + case (true, false, true) -> not_implemented("sc.aq is not implemented") + case (true, true, true) -> MEMval_conditional_strong_release(addr, width, value) + } +} + +val extern unit -> bool effect {exmem} speculate_conditional_success + +val extern unit -> unit effect { barr } MEM_fence_rw_rw +val extern unit -> unit effect { barr } MEM_fence_r_rw +val extern unit -> unit effect { barr } MEM_fence_r_r +val extern unit -> unit effect { barr } MEM_fence_rw_w +val extern unit -> unit effect { barr } MEM_fence_w_w +val extern unit -> unit effect { barr } MEM_fence_i + +typedef uop = enumerate {RISCV_LUI; RISCV_AUIPC} (* upper immediate ops *) +typedef bop = enumerate {RISCV_BEQ; RISCV_BNE; RISCV_BLT; RISCV_BGE; RISCV_BLTU; RISCV_BGEU} (* branch ops *) +typedef iop = enumerate {RISCV_ADDI; RISCV_SLTI; RISCV_SLTIU; RISCV_XORI; RISCV_ORI; RISCV_ANDI} (* immediate ops *) +typedef sop = enumerate {RISCV_SLLI; RISCV_SRLI; RISCV_SRAI} (* shift ops *) +typedef rop = enumerate {RISCV_ADD; RISCV_SUB; RISCV_SLL; RISCV_SLT; RISCV_SLTU; RISCV_XOR; RISCV_SRL; RISCV_SRA; RISCV_OR; RISCV_AND} (* reg-reg ops *) +typedef ropw = enumerate {RISCV_ADDW; RISCV_SUBW; RISCV_SLLW; RISCV_SRLW; RISCV_SRAW} (* reg-reg 32-bit ops *) +typedef amoop = enumerate {AMOSWAP; AMOADD; AMOXOR; AMOAND; AMOOR; + AMOMIN; AMOMAX; AMOMINU; AMOMAXU} (* AMO ops *) + +typedef word_width = enumerate {BYTE; HALF; WORD; DOUBLE} + +(********************************************************************) + +(* Ideally these would be sail builtin *) +function (bit[64]) shift_right_arith64 ((bit[64]) v, (bit[6]) shift) = + let (bit[128]) v128 = EXTS(v) in + (v128 >> shift)[63..0] + +function (bit[32]) shift_right_arith32 ((bit[32]) v, (bit[5]) shift) = + let (bit[64]) v64 = EXTS(v) in + (v64 >> shift)[31..0] diff --git a/src/gen_lib/deep_shallow_convert.lem b/src/gen_lib/deep_shallow_convert.lem index 23c34222..76880dbd 100644 --- a/src/gen_lib/deep_shallow_convert.lem +++ b/src/gen_lib/deep_shallow_convert.lem @@ -6,20 +6,20 @@ open import Sail_values class (ToFromInterpValue 'a) - val toInterpValue : 'a -> Interp.value - val fromInterpValue : Interp.value -> 'a + val toInterpValue : 'a -> Interp_ast.value + val fromInterpValue : Interp_ast.value -> 'a end let toInterValueBool = function - | true -> Interp.V_lit (L_aux (L_one) Unknown) - | false -> Interp.V_lit (L_aux (L_zero) Unknown) + | true -> Interp_ast.V_lit (L_aux (L_one) Unknown) + | false -> Interp_ast.V_lit (L_aux (L_zero) Unknown) end let rec fromInterpValueBool v = match v with - | Interp.V_lit (L_aux (L_true) _) -> true - | Interp.V_lit (L_aux (L_false) _) -> false - | Interp.V_lit (L_aux (L_one) _) -> true - | Interp.V_lit (L_aux (L_zero) _) -> false - | Interp.V_tuple [v] -> fromInterpValueBool v + | Interp_ast.V_lit (L_aux (L_one) _) -> true + | Interp_ast.V_lit (L_aux (L_true) _) -> true + | Interp_ast.V_lit (L_aux (L_zero) _) -> false + | Interp_ast.V_lit (L_aux (L_false) _) -> false + | Interp_ast.V_tuple [v] -> fromInterpValueBool v | v -> failwith ("fromInterpValue bool: unexpected value. " ^ Interp.debug_print_value v) end @@ -29,10 +29,10 @@ instance (ToFromInterpValue bool) end -let toInterpValueUnit () = Interp.V_lit (L_aux (L_unit) Unknown) +let toInterpValueUnit () = Interp_ast.V_lit (L_aux (L_unit) Unknown) let rec fromInterpValueUnit v = match v with - | Interp.V_lit (L_aux (L_unit) _) -> () - | Interp.V_tuple [v] -> fromInterpValueUnit v + | Interp_ast.V_lit (L_aux (L_unit) _) -> () + | Interp_ast.V_tuple [v] -> fromInterpValueUnit v | v -> failwith ("fromInterpValue unit: unexpected value. " ^ Interp.debug_print_value v) end @@ -44,8 +44,8 @@ end let toInterpValueInteger i = V_lit (L_aux (L_num i) Unknown) let rec fromInterpValueInteger v = match v with - | Interp.V_lit (L_aux (L_num i) _) -> i - | Interp.V_tuple [v] -> fromInterpValueInteger v + | Interp_ast.V_lit (L_aux (L_num i) _) -> i + | Interp_ast.V_tuple [v] -> fromInterpValueInteger v | v -> failwith ("fromInterpValue integer: unexpected value. " ^ Interp.debug_print_value v) end @@ -57,8 +57,8 @@ end let toInterpValueString s = V_lit (L_aux (L_string s) Unknown) let rec fromInterpValueString v = match v with - | Interp.V_lit (L_aux (L_string s) _) -> s - | Interp.V_tuple [v] -> fromInterpValueString v + | Interp_ast.V_lit (L_aux (L_string s) _) -> s + | Interp_ast.V_tuple [v] -> fromInterpValueString v | v -> failwith ("fromInterpValue integer: unexpected value. " ^ Interp.debug_print_value v) end @@ -69,17 +69,17 @@ end let toInterpValueBitU = function - | I -> Interp.V_lit (L_aux (L_one) Unknown) - | O -> Interp.V_lit (L_aux (L_zero) Unknown) - | Undef -> Interp.V_lit (L_aux (L_undef) Unknown) + | B1 -> Interp_ast.V_lit (L_aux (L_one) Unknown) + | B0 -> Interp_ast.V_lit (L_aux (L_zero) Unknown) + | BU -> Interp_ast.V_lit (L_aux (L_undef) Unknown) end let rec fromInterpValueBitU v = match v with - | Interp.V_lit (L_aux (L_one) _) -> I - | Interp.V_lit (L_aux (L_zero) _) -> O - | Interp.V_lit (L_aux (L_undef) _) -> Undef - | Interp.V_lit (L_aux (L_true) _) -> I - | Interp.V_lit (L_aux (L_false) _) -> O - | Interp.V_tuple [v] -> fromInterpValueBitU v + | Interp_ast.V_lit (L_aux (L_one) _) -> B1 + | Interp_ast.V_lit (L_aux (L_zero) _) -> B0 + | Interp_ast.V_lit (L_aux (L_undef) _) -> BU + | Interp_ast.V_lit (L_aux (L_true) _) -> B1 + | Interp_ast.V_lit (L_aux (L_false) _) -> B0 + | Interp_ast.V_tuple [v] -> fromInterpValueBitU v | v -> failwith ("fromInterpValue bitU: unexpected value. " ^ Interp.debug_print_value v) end @@ -383,29 +383,33 @@ instance forall 'a. ToFromInterpValue 'a => (ToFromInterpValue (maybe 'a)) end -module SI = Interp -module SIA = Interp_ast - - let read_kindToInterpValue = function | Read_plain -> V_ctor (Id_aux (Id "Read_plain") Unknown) (T_id "read_kind") (C_Enum 0) (toInterpValue ()) - | Read_tag -> V_ctor (Id_aux (Id "Read_tag") Unknown) (T_id "read_kind") (C_Enum 1) (toInterpValue ()) - | Read_tag_reserve -> V_ctor (Id_aux (Id "Read_tag_reserve") Unknown) (T_id "read_kind") (C_Enum 1) (toInterpValue ()) - | Read_reserve -> V_ctor (Id_aux (Id "Read_reserve") Unknown) (T_id "read_kind") (C_Enum 2) (toInterpValue ()) - | Read_acquire -> V_ctor (Id_aux (Id "Read_acquire") Unknown) (T_id "read_kind") (C_Enum 3) (toInterpValue ()) - | Read_exclusive -> V_ctor (Id_aux (Id "Read_exclusive") Unknown) (T_id "read_kind") (C_Enum 4) (toInterpValue ()) - | Read_exclusive_acquire -> V_ctor (Id_aux (Id "Read_exclusive_acquire") Unknown) (T_id "read_kind") (C_Enum 5) (toInterpValue ()) - | Read_stream -> V_ctor (Id_aux (Id "Read_stream") Unknown) (T_id "read_kind") (C_Enum 6) (toInterpValue ()) + | Read_reserve -> V_ctor (Id_aux (Id "Read_reserve") Unknown) (T_id "read_kind") (C_Enum 1) (toInterpValue ()) + | Read_acquire -> V_ctor (Id_aux (Id "Read_acquire") Unknown) (T_id "read_kind") (C_Enum 2) (toInterpValue ()) + | Read_exclusive -> V_ctor (Id_aux (Id "Read_exclusive") Unknown) (T_id "read_kind") (C_Enum 3) (toInterpValue ()) + | Read_exclusive_acquire -> V_ctor (Id_aux (Id "Read_exclusive_acquire") Unknown) (T_id "read_kind") (C_Enum 4) (toInterpValue ()) + | Read_stream -> V_ctor (Id_aux (Id "Read_stream") Unknown) (T_id "read_kind") (C_Enum 5) (toInterpValue ()) + | Read_RISCV_acquire -> V_ctor (Id_aux (Id "Read_RISCV_acquire") Unknown) (T_id "read_kind") (C_Enum 6) (toInterpValue ()) + | Read_RISCV_strong_acquire -> V_ctor (Id_aux (Id "Read_RISCV_strong_acquire") Unknown) (T_id "read_kind") (C_Enum 7) (toInterpValue ()) + | Read_RISCV_reserved -> V_ctor (Id_aux (Id "Read_RISCV_reserved") Unknown) (T_id "read_kind") (C_Enum 8) (toInterpValue ()) + | Read_RISCV_reserved_acquire -> V_ctor (Id_aux (Id "Read_RISCV_reserved_acquire") Unknown) (T_id "read_kind") (C_Enum 9) (toInterpValue ()) + | Read_RISCV_reserved_strong_acquire -> V_ctor (Id_aux (Id "Read_RISCV_reserved_strong_acquire") Unknown) (T_id "read_kind") (C_Enum 10) (toInterpValue ()) + | Read_X86_locked -> V_ctor (Id_aux (Id "Read_X86_locked") Unknown) (T_id "read_kind") (C_Enum 11) (toInterpValue ()) end let rec read_kindFromInterpValue v = match v with | V_ctor (Id_aux (Id "Read_plain") _) _ _ v -> Read_plain - | V_ctor (Id_aux (Id "Read_tag") _) _ _ v -> Read_tag - | V_ctor (Id_aux (Id "Read_tag_reserve") _) _ _ v -> Read_tag_reserve | V_ctor (Id_aux (Id "Read_reserve") _) _ _ v -> Read_reserve | V_ctor (Id_aux (Id "Read_acquire") _) _ _ v -> Read_acquire | V_ctor (Id_aux (Id "Read_exclusive") _) _ _ v -> Read_exclusive | V_ctor (Id_aux (Id "Read_exclusive_acquire") _) _ _ v -> Read_exclusive_acquire | V_ctor (Id_aux (Id "Read_stream") _) _ _ v -> Read_stream + | V_ctor (Id_aux (Id "Read_RISCV_acquire") _) _ _ v -> Read_RISCV_acquire + | V_ctor (Id_aux (Id "Read_RISCV_strong_acquire") _) _ _ v -> Read_RISCV_strong_acquire + | V_ctor (Id_aux (Id "Read_RISCV_reserved") _) _ _ v -> Read_RISCV_reserved + | V_ctor (Id_aux (Id "Read_RISCV_reserved_acquire") _) _ _ v -> Read_RISCV_reserved_acquire + | V_ctor (Id_aux (Id "Read_RISCV_reserved_strong_acquire") _) _ _ v -> Read_RISCV_reserved_strong_acquire + | V_ctor (Id_aux (Id "Read_X86_locked") _) _ _ v -> Read_X86_locked | V_tuple [v] -> read_kindFromInterpValue v | v -> failwith ("fromInterpValue read_kind: unexpected value. " ^ Interp.debug_print_value v) @@ -418,21 +422,29 @@ end let write_kindToInterpValue = function | Write_plain -> V_ctor (Id_aux (Id "Write_plain") Unknown) (T_id "write_kind") (C_Enum 0) (toInterpValue ()) - | Write_tag -> V_ctor (Id_aux (Id "Write_tag") Unknown) (T_id "write_kind") (C_Enum 1) (toInterpValue ()) - | Write_tag_conditional -> V_ctor (Id_aux (Id "Write_tag_conditional") Unknown) (T_id "write_kind") (C_Enum 1) (toInterpValue ()) - | Write_conditional -> V_ctor (Id_aux (Id "Write_conditional") Unknown) (T_id "write_kind") (C_Enum 2) (toInterpValue ()) - | Write_release -> V_ctor (Id_aux (Id "Write_release") Unknown) (T_id "write_kind") (C_Enum 3) (toInterpValue ()) - | Write_exclusive -> V_ctor (Id_aux (Id "Write_exclusive") Unknown) (T_id "write_kind") (C_Enum 4) (toInterpValue ()) - | Write_exclusive_release -> V_ctor (Id_aux (Id "Write_exclusive_release") Unknown) (T_id "write_kind") (C_Enum 5) (toInterpValue ()) + | Write_conditional -> V_ctor (Id_aux (Id "Write_conditional") Unknown) (T_id "write_kind") (C_Enum 1) (toInterpValue ()) + | Write_release -> V_ctor (Id_aux (Id "Write_release") Unknown) (T_id "write_kind") (C_Enum 2) (toInterpValue ()) + | Write_exclusive -> V_ctor (Id_aux (Id "Write_exclusive") Unknown) (T_id "write_kind") (C_Enum 3) (toInterpValue ()) + | Write_exclusive_release -> V_ctor (Id_aux (Id "Write_exclusive_release") Unknown) (T_id "write_kind") (C_Enum 4) (toInterpValue ()) + | Write_RISCV_release -> V_ctor (Id_aux (Id "Write_RISCV_release") Unknown) (T_id "write_kind") (C_Enum 5) (toInterpValue ()) + | Write_RISCV_strong_release -> V_ctor (Id_aux (Id "Write_RISCV_strong_release") Unknown) (T_id "write_kind") (C_Enum 6) (toInterpValue ()) + | Write_RISCV_conditional -> V_ctor (Id_aux (Id "Write_RISCV_conditional") Unknown) (T_id "write_kind") (C_Enum 7) (toInterpValue ()) + | Write_RISCV_conditional_release -> V_ctor (Id_aux (Id "Write_RISCV_conditional_release") Unknown) (T_id "write_kind") (C_Enum 8) (toInterpValue ()) + | Write_RISCV_conditional_strong_release -> V_ctor (Id_aux (Id "Write_RISCV_conditional_strong_release") Unknown) (T_id "write_kind") (C_Enum 9) (toInterpValue ()) + | Write_X86_locked -> V_ctor (Id_aux (Id "Write_X86_locked") Unknown) (T_id "write_kind") (C_Enum 10) (toInterpValue ()) end let rec write_kindFromInterpValue v = match v with | V_ctor (Id_aux (Id "Write_plain") _) _ _ v -> Write_plain - | V_ctor (Id_aux (Id "Write_tag") _) _ _ v -> Write_tag - | V_ctor (Id_aux (Id "Write_tag_conditional") _) _ _ v -> Write_tag_conditional | V_ctor (Id_aux (Id "Write_conditional") _) _ _ v -> Write_conditional | V_ctor (Id_aux (Id "Write_release") _) _ _ v -> Write_release | V_ctor (Id_aux (Id "Write_exclusive") _) _ _ v -> Write_exclusive | V_ctor (Id_aux (Id "Write_exclusive_release") _) _ _ v -> Write_exclusive_release + | V_ctor (Id_aux (Id "Write_RISCV_release") _) _ _ v -> Write_RISCV_release + | V_ctor (Id_aux (Id "Write_RISCV_strong_release") _) _ _ v -> Write_RISCV_strong_release + | V_ctor (Id_aux (Id "Write_RISCV_conditional") _) _ _ v -> Write_RISCV_conditional + | V_ctor (Id_aux (Id "Write_RISCV_conditional_release") _) _ _ v -> Write_RISCV_conditional_release + | V_ctor (Id_aux (Id "Write_RISCV_conditional_strong_release") _) _ _ v -> Write_RISCV_conditional_strong_release + | V_ctor (Id_aux (Id "Write_X86_locked") _) _ _ v -> Write_X86_locked | V_tuple [v] -> write_kindFromInterpValue v | v -> failwith ("fromInterpValue write_kind: unexpected value " ^ Interp.debug_print_value v) @@ -455,7 +467,15 @@ let barrier_kindToInterpValue = function | Barrier_DSB_ST -> V_ctor (Id_aux (Id "Barrier_DSB_ST") Unknown) (T_id "barrier_kind") (C_Enum 8) (toInterpValue ()) | Barrier_DSB_LD -> V_ctor (Id_aux (Id "Barrier_DSB_LD") Unknown) (T_id "barrier_kind") (C_Enum 9) (toInterpValue ()) | Barrier_ISB -> V_ctor (Id_aux (Id "Barrier_ISB") Unknown) (T_id "barrier_kind") (C_Enum 10) (toInterpValue ()) - | Barrier_MIPS_SYNC -> V_ctor (Id_aux (Id "Barrier_MIPS_SYNC") Unknown) (T_id "barrier_kind") (C_Enum 11) (toInterpValue ()) + | Barrier_TM_COMMIT -> V_ctor (Id_aux (Id "Barrier_TM_COMMIT") Unknown) (T_id "barrier_kind") (C_Enum 11) (toInterpValue ()) + | Barrier_MIPS_SYNC -> V_ctor (Id_aux (Id "Barrier_MIPS_SYNC") Unknown) (T_id "barrier_kind") (C_Enum 12) (toInterpValue ()) + | Barrier_RISCV_rw_rw -> V_ctor (Id_aux (Id "Barrier_RISCV_rw_rw") Unknown) (T_id "barrier_kind") (C_Enum 13) (toInterpValue ()) + | Barrier_RISCV_r_rw -> V_ctor (Id_aux (Id "Barrier_RISCV_r_rw") Unknown) (T_id "barrier_kind") (C_Enum 14) (toInterpValue ()) + | Barrier_RISCV_r_r -> V_ctor (Id_aux (Id "Barrier_RISCV_r_r") Unknown) (T_id "barrier_kind") (C_Enum 15) (toInterpValue ()) + | Barrier_RISCV_rw_w -> V_ctor (Id_aux (Id "Barrier_RISCV_rw_w") Unknown) (T_id "barrier_kind") (C_Enum 16) (toInterpValue ()) + | Barrier_RISCV_w_w -> V_ctor (Id_aux (Id "Barrier_RISCV_w_w") Unknown) (T_id "barrier_kind") (C_Enum 17) (toInterpValue ()) + | Barrier_RISCV_i -> V_ctor (Id_aux (Id "Barrier_RISCV_i") Unknown) (T_id "barrier_kind") (C_Enum 18) (toInterpValue ()) + | Barrier_x86_MFENCE -> V_ctor (Id_aux (Id "Barrier_x86_MFENCE") Unknown) (T_id "barrier_kind") (C_Enum 19) (toInterpValue ()) end let rec barrier_kindFromInterpValue v = match v with | V_ctor (Id_aux (Id "Barrier_Sync") _) _ _ v -> Barrier_Sync @@ -469,7 +489,15 @@ let rec barrier_kindFromInterpValue v = match v with | V_ctor (Id_aux (Id "Barrier_DSB_ST") _) _ _ v -> Barrier_DSB_ST | V_ctor (Id_aux (Id "Barrier_DSB_LD") _) _ _ v -> Barrier_DSB_LD | V_ctor (Id_aux (Id "Barrier_ISB") _) _ _ v -> Barrier_ISB + | V_ctor (Id_aux (Id "Barrier_TM_COMMIT") _) _ _ v -> Barrier_TM_COMMIT | V_ctor (Id_aux (Id "Barrier_MIPS_SYNC") _) _ _ v -> Barrier_MIPS_SYNC + | V_ctor (Id_aux (Id "Barrier_RISCV_rw_rw") _) _ _ v -> Barrier_RISCV_rw_rw + | V_ctor (Id_aux (Id "Barrier_RISCV_r_rw") _) _ _ v -> Barrier_RISCV_r_rw + | V_ctor (Id_aux (Id "Barrier_RISCV_r_r") _) _ _ v -> Barrier_RISCV_r_r + | V_ctor (Id_aux (Id "Barrier_RISCV_rw_w") _) _ _ v -> Barrier_RISCV_rw_w + | V_ctor (Id_aux (Id "Barrier_RISCV_w_w") _) _ _ v -> Barrier_RISCV_w_w + | V_ctor (Id_aux (Id "Barrier_RISCV_i") _) _ _ v -> Barrier_RISCV_i + | V_ctor (Id_aux (Id "Barrier_x86_MFENCE") _) _ _ v -> Barrier_x86_MFENCE | V_tuple [v] -> barrier_kindFromInterpValue v | v -> failwith ("fromInterpValue barrier_kind: unexpected value. " ^ Interp.debug_print_value v) @@ -480,18 +508,41 @@ instance (ToFromInterpValue barrier_kind) end +let trans_kindToInterpValue = function + | Transaction_start -> V_ctor (Id_aux (Id "Transaction_start") Unknown) (T_id "trans_kind") (C_Enum 0) (toInterpValue ()) + | Transaction_commit -> V_ctor (Id_aux (Id "Transaction_commit") Unknown) (T_id "trans_kind") (C_Enum 1) (toInterpValue ()) + | Transaction_abort -> V_ctor (Id_aux (Id "Transaction_abort") Unknown) (T_id "trans_kind") (C_Enum 2) (toInterpValue ()) + end +let rec trans_kindFromInterpValue v = match v with + | V_ctor (Id_aux (Id "Transaction_start") _) _ _ v -> Transaction_start + | V_ctor (Id_aux (Id "Transaction_commit") _) _ _ v -> Transaction_commit + | V_ctor (Id_aux (Id "Transaction_abort") _) _ _ v -> Transaction_abort + | V_tuple [v] -> trans_kindFromInterpValue v + | v -> failwith ("fromInterpValue trans_kind: unexpected value. " ^ + Interp.debug_print_value v) + end +instance (ToFromInterpValue trans_kind) + let toInterpValue = trans_kindToInterpValue + let fromInterpValue = trans_kindFromInterpValue +end + + let instruction_kindToInterpValue = function | IK_barrier v -> V_ctor (Id_aux (Id "IK_barrier") Unknown) (T_id "instruction_kind") C_Union (toInterpValue v) | IK_mem_read v -> V_ctor (Id_aux (Id "IK_mem_read") Unknown) (T_id "instruction_kind") C_Union (toInterpValue v) | IK_mem_write v -> V_ctor (Id_aux (Id "IK_mem_write") Unknown) (T_id "instruction_kind") C_Union (toInterpValue v) + | IK_mem_rmw v -> V_ctor (Id_aux (Id "IK_mem_rmw") Unknown) (T_id "instruction_kind") C_Union (toInterpValue v) | IK_cond_branch -> V_ctor (Id_aux (Id "IK_cond_branch") Unknown) (T_id "instruction_kind") C_Union (toInterpValue ()) + | IK_trans v -> V_ctor (Id_aux (Id "IK_trans") Unknown) (T_id "instruction_kind") C_Union (toInterpValue v) | IK_simple -> V_ctor (Id_aux (Id "IK_simple") Unknown) (T_id "instruction_kind") C_Union (toInterpValue ()) end let rec instruction_kindFromInterpValue v = match v with | V_ctor (Id_aux (Id "IK_barrier") _) _ _ v -> IK_barrier (fromInterpValue v) | V_ctor (Id_aux (Id "IK_mem_read") _) _ _ v -> IK_mem_read (fromInterpValue v) | V_ctor (Id_aux (Id "IK_mem_write") _) _ _ v -> IK_mem_write (fromInterpValue v) + | V_ctor (Id_aux (Id "IK_mem_rmw") _) _ _ v -> IK_mem_rmw (fromInterpValue v) | V_ctor (Id_aux (Id "IK_cond_branch") _) _ _ v -> IK_cond_branch + | V_ctor (Id_aux (Id "IK_trans") _) _ _ v -> IK_trans (fromInterpValue v) | V_ctor (Id_aux (Id "IK_simple") _) _ _ v -> IK_simple | V_tuple [v] -> instruction_kindFromInterpValue v | v -> failwith ("fromInterpValue instruction_kind: unexpected value. " ^ @@ -503,18 +554,18 @@ instance (ToFromInterpValue instruction_kind) end let regfpToInterpValue = function - | RFull v -> SI.V_ctor (SIA.Id_aux (SIA.Id "RFull") SIA.Unknown) (SIA.T_id "regfp") SI.C_Union (toInterpValue v) - | RSlice v -> SI.V_ctor (SIA.Id_aux (SIA.Id "RSlice") SIA.Unknown) (SIA.T_id "regfp") SI.C_Union (toInterpValue v) - | RSliceBit v -> SI.V_ctor (SIA.Id_aux (SIA.Id "RSliceBit") SIA.Unknown) (SIA.T_id "regfp") SI.C_Union (toInterpValue v) - | RField v -> SI.V_ctor (SIA.Id_aux (SIA.Id "RField") SIA.Unknown) (SIA.T_id "regfp") SI.C_Union (toInterpValue v) + | RFull v -> Interp_ast.V_ctor (Interp_ast.Id_aux (Interp_ast.Id "RFull") Interp_ast.Unknown) (Interp_ast.T_id "regfp") Interp_ast.C_Union (toInterpValue v) + | RSlice v -> Interp_ast.V_ctor (Interp_ast.Id_aux (Interp_ast.Id "RSlice") Interp_ast.Unknown) (Interp_ast.T_id "regfp") Interp_ast.C_Union (toInterpValue v) + | RSliceBit v -> Interp_ast.V_ctor (Interp_ast.Id_aux (Interp_ast.Id "RSliceBit") Interp_ast.Unknown) (Interp_ast.T_id "regfp") Interp_ast.C_Union (toInterpValue v) + | RField v -> Interp_ast.V_ctor (Interp_ast.Id_aux (Interp_ast.Id "RField") Interp_ast.Unknown) (Interp_ast.T_id "regfp") Interp_ast.C_Union (toInterpValue v) end let rec regfpFromInterpValue v = match v with - | SI.V_ctor (SIA.Id_aux (SIA.Id "RFull") _) _ _ v -> RFull (fromInterpValue v) - | SI.V_ctor (SIA.Id_aux (SIA.Id "RSlice") _) _ _ v -> RSlice (fromInterpValue v) - | SI.V_ctor (SIA.Id_aux (SIA.Id "RSliceBit") _) _ _ v -> RSliceBit (fromInterpValue v) - | SI.V_ctor (SIA.Id_aux (SIA.Id "RField") _) _ _ v -> RField (fromInterpValue v) - | SI.V_tuple [v] -> regfpFromInterpValue v + | Interp_ast.V_ctor (Interp_ast.Id_aux (Interp_ast.Id "RFull") _) _ _ v -> RFull (fromInterpValue v) + | Interp_ast.V_ctor (Interp_ast.Id_aux (Interp_ast.Id "RSlice") _) _ _ v -> RSlice (fromInterpValue v) + | Interp_ast.V_ctor (Interp_ast.Id_aux (Interp_ast.Id "RSliceBit") _) _ _ v -> RSliceBit (fromInterpValue v) + | Interp_ast.V_ctor (Interp_ast.Id_aux (Interp_ast.Id "RField") _) _ _ v -> RField (fromInterpValue v) + | Interp_ast.V_tuple [v] -> regfpFromInterpValue v | v -> failwith ("fromInterpValue regfp: unexpected value. " ^ Interp.debug_print_value v) end diff --git a/src/gen_lib/sail_values.ml b/src/gen_lib/sail_values.ml index d160e84a..213acea1 100644 --- a/src/gen_lib/sail_values.ml +++ b/src/gen_lib/sail_values.ml @@ -889,18 +889,25 @@ let shift_op_vec_int op (l,r) = let len = Array.length array in (match op with | "<<" -> - let left = Array.sub array r (len - r) in - let right = Array.make r Vzero in - let result = Array.append left right in - Vvector(result, start, ord) + if (r <= len) then + let left = Array.sub array r (len - r) in + let right = Array.make r Vzero in + let result = Array.append left right in + Vvector(result, start, ord) + else + Vvector(Array.make len Vzero, start, ord) | ">>" -> - let left = Array.make r Vzero in - let right = Array.sub array 0 (len - r) in - let result = Array.append left right in - Vvector(result, start, ord) + if (r <= len) then + let left = Array.make r Vzero in + let right = Array.sub array 0 (len - r) in + let result = Array.append left right in + Vvector(result, start, ord) + else + Vvector(Array.make len Vzero, start, ord) | "<<<" -> - let left = Array.sub array r (len - r) in - let right = Array.sub array 0 r in + let rmod = r mod len in + let left = Array.sub array rmod (len - rmod) in + let right = Array.sub array 0 rmod in let result = Array.append left right in Vvector(result, start, ord) | _ -> assert false) diff --git a/src/gen_lib/state.lem b/src/gen_lib/state.lem index 69b9e301..2fff7344 100644 --- a/src/gen_lib/state.lem +++ b/src/gen_lib/state.lem @@ -79,7 +79,23 @@ let set_reg state reg v = <| state with regstate = reg.write_to state.regstate v |> -val read_mem : forall 'regs 'a 'b. Bitvector 'a, Bitvector 'b => bool -> read_kind -> 'a -> integer -> M 'regs 'b +let is_exclusive = function + | Sail_impl_base.Read_plain -> false + | Sail_impl_base.Read_reserve -> true + | Sail_impl_base.Read_acquire -> false + | Sail_impl_base.Read_exclusive -> true + | Sail_impl_base.Read_exclusive_acquire -> true + | Sail_impl_base.Read_stream -> false + | Sail_impl_base.Read_RISCV_acquire -> false + | Sail_impl_base.Read_RISCV_strong_acquire -> false + | Sail_impl_base.Read_RISCV_reserved -> true + | Sail_impl_base.Read_RISCV_reserved_acquire -> true + | Sail_impl_base.Read_RISCV_reserved_strong_acquire -> true + | Sail_impl_base.Read_X86_locked -> true +end + + +val read_mem : bool -> read_kind -> vector bitU -> integer -> M (vector bitU) let read_mem dir read_kind addr sz state = let addr = unsigned addr in let addrs = range addr (addr+sz-1) in @@ -94,7 +110,7 @@ let read_mem dir read_kind addr sz state = | Sail_impl_base.Read_stream -> false end in - if is_exclusive + if is_exclusive read_kind then [(Left value, <| state with last_exclusive_operation_was_load = true |>)] else [(Left value, state)] @@ -118,7 +134,7 @@ let read_tag dir read_kind addr state = end in (* TODO Should reading a tag set the exclusive flag? *) - if is_exclusive + if is_exclusive read_kind then [(Left tag, <| state with last_exclusive_operation_was_load = true |>)] else [(Left tag, state)] @@ -174,7 +190,23 @@ let reg_deref = read_reg val write_reg : forall 'regs 'a. register_ref 'regs 'a -> 'a -> M 'regs unit let write_reg reg v state = - [(Left (), <| state with regstate = reg.write_to state.regstate v |>)] + [(Left (),<| state with regstate = Map.insert (name_of_reg reg) v state.regstate |>)] +let write_reg_range reg i j v = + read_reg reg >>= fun current_value -> + let new_value = update current_value i j v in + write_reg reg new_value +let write_reg_bit reg i bit = + write_reg_range reg i i (Vector [bit] i (is_inc_of_reg reg)) +let write_reg_field reg regfield = + let (i,j) = register_field_indices reg regfield in + write_reg_range reg i j +let write_reg_bitfield reg regfield = + let (i,_) = register_field_indices reg regfield in + write_reg_bit reg i +let write_reg_field_range reg regfield i j v = + read_reg_field reg regfield >>= fun current_field_value -> + let new_field_value = update current_field_value i j v in + write_reg_field reg regfield new_field_value val update_reg : forall 'regs 'a 'b. register_ref 'regs 'a -> ('a -> 'b -> 'a) -> 'b -> M 'regs unit let update_reg reg f v state = diff --git a/src/lem_interp/interp.lem b/src/lem_interp/interp.lem index 301849cd..cc10b758 100644 --- a/src/lem_interp/interp.lem +++ b/src/lem_interp/interp.lem @@ -1419,8 +1419,8 @@ let rec match_pattern t_level (P_aux p (_, annot)) value_whole = | V_ctor (Id_aux cid _) t ckind v -> if id = cid then (match (pats,detaint v) with - | ([],(V_lit (L_aux L_unit _))) -> (true,true,eenv) - | ([P_aux (P_lit (L_aux L_unit _)) _],(V_lit (L_aux L_unit _))) -> (true,true,eenv) + | ([],(V_lit (L_aux L_unit _))) -> (true,false,eenv) + | ([P_aux (P_lit (L_aux L_unit _)) _],(V_lit (L_aux L_unit _))) -> (true,false,eenv) | ([p],_) -> match_pattern t_level p v | _ -> (false,false,eenv) end) else (false,false,eenv) diff --git a/src/lem_interp/interp_inter_imp.lem b/src/lem_interp/interp_inter_imp.lem index e9533a2a..c982a30a 100644 --- a/src/lem_interp/interp_inter_imp.lem +++ b/src/lem_interp/interp_inter_imp.lem @@ -471,7 +471,7 @@ let translate_address top_level end_flag thunk_name registers address = let (arg,_) = Interp.to_exp int_mode Interp.eenv intern_val in let internal_direction = if direction = D_increasing then Interp_ast.IInc else Interp_ast.IDec in let (address_error,events) = - interp_to_value_helper debug (Just (Opcode bytes)) Ivh_translate val_str ("",[]) internal_direction + interp_to_value_helper debug (Just (Opcode bytes)) Ivh_translate val_str (V_list []) internal_direction registers [] false (fun _ -> Interp.resume int_mode @@ -506,17 +506,16 @@ let intern_instruction direction (name,parms) = Interp_ast.V_ctor (Interp.id_of_string name) (mk_typ_id "ast") Interp_ast.C_Union (Interp_ast.V_tuple (List.map (value_of_instruction_param direction) parms)) -let instruction_analysis top_level end_flag thunk_name regn_to_reg_details registers instruction = +let instruction_analysis top_level end_flag thunk_name regn_to_reg_details registers (instruction : Interp_ast.value) = let (Context top_env direction _ _ _ _ _ _ _ _ _) = top_level in let (Interp.Env _ _ _ _ _ _ _ _ debug) = top_env in let mode = make_mode true false debug in let int_mode = mode.internal_mode in - let intern_val = intern_instruction direction instruction in - let val_str = Interp.string_of_value intern_val in - let (arg,_) = Interp.to_exp int_mode Interp.eenv intern_val in + let val_str = Interp.string_of_value instruction in + let (arg,_) = Interp.to_exp int_mode Interp.eenv instruction in let internal_direction = if direction = D_increasing then Interp_ast.IInc else Interp_ast.IDec in let (analysis_or_error,events) = - interp_to_value_helper debug Nothing Ivh_analysis val_str ("",[]) internal_direction + interp_to_value_helper debug Nothing Ivh_analysis val_str (V_list []) internal_direction registers [] false (fun _ -> Interp.resume int_mode @@ -574,6 +573,33 @@ let instruction_analysis top_level end_flag thunk_name regn_to_reg_details regis | Interp_ast.V_ctor (Id_aux (Id "NIAFP_register") _) _ _ reg -> NIA_register (reg_to_reg_name reg) | _ -> failwith "Register footprint analysis did not return nia of expected type" end in + let readk_to_readk = function + | "Read_plain" -> Read_plain + | "Read_reserve" -> Read_reserve + | "Read_acquire" -> Read_acquire + | "Read_exclusive" -> Read_exclusive + | "Read_exclusive_acquire" -> Read_exclusive_acquire + | "Read_stream" -> Read_stream + | "Read_RISCV_acquire" -> Read_RISCV_acquire + | "Read_RISCV_strong_acquire" -> Read_RISCV_strong_acquire + | "Read_RISCV_reserved" -> Read_RISCV_reserved + | "Read_RISCV_reserved_acquire" -> Read_RISCV_reserved_acquire + | "Read_RISCV_reserved_strong_acquire" -> Read_RISCV_reserved_strong_acquire + | "Read_X86_locked" -> Read_X86_locked + | r -> failwith ("unknown read kind: " ^ r) end in + let writek_to_writek = function + | "Write_plain" -> Write_plain + | "Write_conditional" -> Write_conditional + | "Write_release" -> Write_release + | "Write_exclusive" -> Write_exclusive + | "Write_exclusive_release" -> Write_exclusive_release + | "Write_RISCV_release" -> Write_RISCV_release + | "Write_RISCV_strong_release" -> Write_RISCV_strong_release + | "Write_RISCV_conditional" -> Write_RISCV_conditional + | "Write_RISCV_conditional_release" -> Write_RISCV_conditional_release + | "Write_RISCV_conditional_strong_release" -> Write_RISCV_conditional_strong_release + | "Write_X86_locked" -> Write_X86_locked + | w -> failwith ("unknown write kind: " ^ w) end in let ik_to_ik = function | Interp_ast.V_ctor (Id_aux (Id "IK_barrier") _) _ _ (Interp_ast.V_ctor (Id_aux (Id b) _) _ _ _) -> @@ -589,27 +615,19 @@ let instruction_analysis top_level end_flag thunk_name regn_to_reg_details regis | "Barrier_DSB_ST" -> Barrier_DSB_ST | "Barrier_DSB_LD" -> Barrier_DSB_LD | "Barrier_ISB" -> Barrier_ISB - | "Barrier_MIPS_SYNC" -> Barrier_MIPS_SYNC + | "Barrier_MIPS_SYNC" -> Barrier_MIPS_SYNC + | "Barrier_x86_MFENCE" -> Barrier_x86_MFENCE end) | Interp_ast.V_ctor (Id_aux (Id "IK_mem_read") _) _ _ (Interp_ast.V_ctor (Id_aux (Id r) _) _ _ _) -> - IK_mem_read (match r with - | "Read_plain" -> Read_plain - | "Read_reserve" -> Read_reserve - | "Read_acquire" -> Read_acquire - | "Read_exclusive" -> Read_exclusive - | "Read_exclusive_acquire" -> Read_exclusive_acquire - | "Read_stream" -> Read_stream - end) + IK_mem_read(readk_to_readk r) | Interp_ast.V_ctor (Id_aux (Id "IK_mem_write") _) _ _ (Interp_ast.V_ctor (Id_aux (Id w) _) _ _ _) -> - IK_mem_write (match w with - | "Write_plain" -> Write_plain - | "Write_conditional" -> Write_conditional - | "Write_release" -> Write_release - | "Write_exclusive" -> Write_exclusive - | "Write_exclusive_release" -> Write_exclusive_release - end) + IK_mem_write(writek_to_writek w) + | Interp_ast.V_ctor (Id_aux (Id "IK_mem_rmw") _) _ _ + (Interp_ast.V_tuple [(Interp_ast.V_ctor (Id_aux (Id readk) _) _ _ _) ; + (Interp_ast.V_ctor (Id_aux (Id writek) _) _ _ _)]) -> + IK_mem_rmw(readk_to_readk readk, writek_to_writek writek) | Interp_ast.V_ctor (Id_aux (Id "IK_cond_branch") _) _ _ _ -> IK_cond_branch | Interp_ast.V_ctor (Id_aux (Id "IK_simple") _) _ _ _ -> @@ -681,7 +699,7 @@ let decode_to_instruction top_level registers value : instruction_or_decode_erro let (arg,_) = Interp.to_exp mode Interp.eenv intern_val in let internal_direction = if direction = D_increasing then Interp_ast.IInc else Interp_ast.IDec in let (instr_decoded_error,events) = - interp_to_value_helper debug (Just value) Ivh_decode val_str ("",[]) internal_direction registers [] false + interp_to_value_helper debug (Just value) Ivh_decode val_str (V_list []) internal_direction registers [] false (fun _ -> Interp.resume mode (Interp.Thunk_frame @@ -689,9 +707,9 @@ let decode_to_instruction top_level registers value : instruction_or_decode_erro top_env Interp.eenv (Interp.emem "decode top level") Interp.Top) Nothing) in match (instr_decoded_error) with | Ivh_value instr -> - let instr_external = interp_value_to_instr_external top_level instr in + (* let instr_external = interp_value_to_instr_external top_level instr in*) let (instr_decoded_error,events) = - interp_to_value_helper debug (Just value) Ivh_unsupported val_str instr_external internal_direction + interp_to_value_helper debug (Just value) Ivh_unsupported val_str instr (*instr_external*) internal_direction registers [] false (fun _ -> Interp.resume mode @@ -700,7 +718,7 @@ let decode_to_instruction top_level registers value : instruction_or_decode_erro (Interp_ast.Unknown, Nothing)) top_env Interp.eenv (Interp.emem "decode second top level") Interp.Top) Nothing) in match (instr_decoded_error) with - | Ivh_value _ -> IDE_instr instr_external instr + | Ivh_value _ -> IDE_instr instr (*instr_external*) | Ivh_value_after_exn v -> Assert_extra.failwith "supported_instructions called exit, so support will be needed for that now" | Ivh_error err -> IDE_decode_error err @@ -714,9 +732,9 @@ end let decode_to_istate (top_level:context) registers (value:opcode) : i_state_or_error = let (Context top_env _ _ _ _ _ _ _ _ _ _) = top_level in match decode_to_instruction top_level registers value with - | IDE_instr instr instrv -> + | IDE_instr instr -> let mode = make_interpreter_mode true false in - let (arg,_) = Interp.to_exp mode Interp.eenv instrv in + let (arg,_) = Interp.to_exp mode Interp.eenv instr in Instr instr (IState (Interp.Thunk_frame (E_aux (E_app (Id_aux (Id "execute") Interp_ast.Unknown) [arg]) (Interp_ast.Unknown,Nothing)) @@ -751,11 +769,11 @@ let instr_external_to_interp_value top_level instr = Interp_ast.V_ctor (Interp_ast.Id_aux (Interp_ast.Id name) Interp_ast.Unknown) (mk_typ_id "ast") Interp_ast.C_Union parmsV -val instruction_to_istate : context -> instruction -> instruction_state -let instruction_to_istate (top_level:context) (((name, parms) as instr):instruction) : instruction_state = +val instruction_to_istate : context -> Interp_ast.value -> instruction_state +let instruction_to_istate (top_level:context) (instr:Interp_ast.value) : instruction_state = let mode = make_interpreter_mode true false in let (Context top_env _ _ _ _ _ _ _ _ _ _) = top_level in - let ast_node = fst (Interp.to_exp mode Interp.eenv (instr_external_to_interp_value top_level instr)) in + let ast_node = fst (Interp.to_exp mode Interp.eenv instr) in (IState (Interp.Thunk_frame (E_aux (E_app (Id_aux (Id "execute") Interp_ast.Unknown) [ast_node]) @@ -1093,7 +1111,7 @@ and state_to_outcome_s pp_instruction_state mode state = (fun env -> interp_exhaustive mode.internal_mode.Interp.debug (Just env) state)) ) -val initial_outcome_s_of_instruction : (instruction_state -> unit -> (string * string)) -> context -> interp_mode -> instruction -> Sail_impl_base.outcome_s unit +val initial_outcome_s_of_instruction : (instruction_state -> unit -> (string * string)) -> context -> interp_mode -> Interp_ast.value -> Sail_impl_base.outcome_s unit let initial_outcome_s_of_instruction pp_instruction_state context mode instruction = let state = instruction_to_istate context instruction in state_to_outcome_s pp_instruction_state mode state @@ -1223,136 +1241,13 @@ let nia_address_of_event nia_reg (event: event) : maybe (maybe address) = | _ -> Nothing end -let nias_of_instruction - thread_ism - (nia_address: list (maybe address)) (* Nothing for unknown/undef*) - (regs_in: list reg_name) - (instruction: instruction) - : list nia - = - let (instruction_name, instruction_fields) = instruction in - - let unknown_nia_address = List.elem Nothing nia_address in - - let nias = [NIA_concrete_address addr | forall (addr MEM (List.mapMaybe id nia_address)) | true] in - - (* it's a fact of the Power2.06B instruction pseudocode that in the B and Bc - cases there should be no Unknown values in nia_values, while in the Bclr - and Bcctr cases nia_values will just be Unknown and the semantics should - match the comments in the machineDefTypes definition of nia *) - (* All our other analysis is on the pseudocode directly, which is arguably - pleasingly robust. We could replace the nias pattern match on - instruction_name with something in that style if the exhaustive interpreter - announced register dependencies to register writes (easy) and if it could - check the form of the register writes to LR and CTR matches the - machineDefTypes nia definition *) - match (thread_ism, instruction_name) with - | ("PPCGEN_ism", "B") -> - let () = ensure (not unknown_nia_address) - "unexpected unknown/undefined address in nia_values 1" in - nias - | ("PPCGEN_ism", "Bc") -> - let () = ensure (not unknown_nia_address) - "unexpected unknown/undefined address in nia_values 2" in - NIA_successor :: nias - | ("PPCGEN_ism", "Bclr") -> [ NIA_successor; NIA_LR ] - | ("PPCGEN_ism", "Bcctr") -> [ NIA_successor; NIA_CTR ] - | ("PPCGEN_ism", "Sc") -> - let () = ensure (not unknown_nia_address) - "unexpected unknown/undefined address in nia_values 3" in - match instruction_fields with - | [(_, _, lev)] -> - (* LEV field is 7 bits long, pad it with false at beginning *) - if lev = [Bitc_zero;Bitc_one;Bitc_one;Bitc_one;Bitc_one;Bitc_one;Bitc_one] - (* (Interp_inter_imp.integer_of_byte_list (Interp_inter_imp.to_bytes (false :: bl))) = 63 *) - then [] - else [NIA_successor] - | _ -> [ NIA_successor ] - end - - (* AARch64 label branch (i.e. address must be known) although - these instructions take the address as an offset from PC, in here - we see the absolute address as it was extracted from the micro ops - just before write to PC *) - | ("AArch64HandSail", "BranchImmediate") -> nias - | ("AArch64HandSail", "BranchConditional") -> NIA_successor :: nias - | ("AArch64HandSail", "CompareAndBranch") -> NIA_successor :: nias - | ("AArch64HandSail", "TestBitAndBranch") -> NIA_successor :: nias - - (* AArch64 calculated address branch *) - | ("AArch64HandSail", "BranchRegister") -> - (* do some parsing of the ast fields to figure out which register holds - the branching address i.e. find n in "BR <Xn>". The ast constructor - from armV8.sail: (reg_index,BranchType) BranchRegister; *) - let n_integer = - match instruction_fields with - | [(_, _, n); _] -> integer_of_bit_list n - | _ -> fail - end - in - let () = ensure (0 <= n_integer && n_integer <= 31) - "expected register number from 0 to 31" - in - if n_integer = 31 then - nias (* BR XZR *) - else - (* look for Xn (which we actually call Rn) in regs_in *) - let n_reg = "R" ^ (String_extra.stringFromInteger n_integer) in - [NIA_register r | forall (r MEM regs_in) - | match r with - | (Reg name _ _ _) -> name = n_reg - | _ -> false - end] - - - (** hacky cut-and-paste for AArch64Gen, duplicating code just to see if this suffices *) - - | ("AArch64GenSail", "BranchImmediate") -> nias - | ("AArch64GenSail", "BranchConditional") -> NIA_successor :: nias - | ("AArch64GenSail", "CompareAndBranch") -> NIA_successor :: nias - | ("AArch64GenSail", "TestBitAndBranch") -> NIA_successor :: nias - - (* AArch64 calculated address branch *) - | ("AArch64GenSail", "branch_unconditional_register") -> - (* do some parsing of the ast fields to figure out which register holds - the branching address i.e. find n in "BR <Xn>". The ast constructor - from armV8.sail: (reg_index,BranchType) BranchRegister; *) - let n_integer = - match instruction_fields with - | [(_, _, n); _] -> integer_of_bit_list n - | _ -> fail - end - in - let () = ensure (0 <= n_integer && n_integer <= 31) - "expected register number from 0 to 31" - in - if n_integer = 31 then - nias (* BR XZR *) - else - (* look for Xn (which we actually call Rn) in regs_in *) - let n_reg = "R" ^ (String_extra.stringFromInteger n_integer) in - [NIA_register r | forall (r MEM regs_in) - | match r with - | (Reg name _ _ _) -> name = n_reg - | _ -> false - end] - - (** end of hacky *) - - | ("AArch64LitmusSail", "CtrlDep") -> NIA_successor :: nias - - - | ("MIPS_ism", "B") -> fail - - | (s1,s2) -> - let () = ensure (not unknown_nia_address) - ("unexpected unknown/undefined address in nia_values 4 (\""^s1^"\", \""^s2^"\")") in - [ NIA_successor ] - end - let interp_instruction_analysis + top_level (interp_exhaustive : ((list (reg_name * register_value)) -> list event)) - instruction nia_reg ism environment = + instruction + nia_reg + (nias_function : (list (maybe address) -> list reg_name -> list nia)) + ism environment = let es = interp_exhaustive environment in @@ -1363,7 +1258,7 @@ let interp_instruction_analysis let nia_address = List.mapMaybe (nia_address_of_event nia_reg) es in - let nias = nias_of_instruction ism nia_address regs_in instruction in + let nias = nias_function nia_address regs_in in let dia = DIA_none in (* FIX THIS! *) @@ -1377,6 +1272,41 @@ let interp_instruction_analysis if forall (inst_kind' MEM inst_kinds). inst_kind' = inst_kind then inst_kind + + else if + (forall (inst_kind' MEM (inst_kind :: inst_kinds)). + match inst_kind' with + | IK_mem_read _ -> true + | IK_mem_write _ -> true + | IK_mem_rmw _ -> false + | IK_barrier _ -> false + | IK_cond_branch -> false + | IK_trans _ -> false + | IK_simple -> false + end) && + (exists (inst_kind' MEM (inst_kind :: inst_kinds)). + match inst_kind' with + | IK_mem_read _ -> true + | _ -> false + end) && + (exists (inst_kind' MEM (inst_kind :: inst_kinds)). + match inst_kind' with + | IK_mem_write _ -> true + | _ -> false + end) + then + match + List.partition + (function IK_mem_read _ -> true | _ -> false end) + (inst_kind :: inst_kinds) + with + | ((IK_mem_read r) :: rs, (IK_mem_write w) :: ws) -> + let () = ensure (forall (r' MEM rs). r' = IK_mem_read r) "more than one kind of read" in + let () = ensure (forall (w' MEM ws). w' = IK_mem_write w) "more than one kind of write" in + IK_mem_rmw (r, w) + | _ -> fail + end + (* the TSTART instruction can also be aborted so it will have two kinds of events *) else if (exists (inst_kind' MEM (inst_kind :: inst_kinds)). inst_kind' = IK_trans Transaction_start) && @@ -1385,7 +1315,9 @@ let interp_instruction_analysis || inst_kind' = IK_trans Transaction_abort) then IK_trans Transaction_start - else failwith "multiple instruction kinds" + + else + failwith "multiple instruction kinds" end in (regs_in, regs_out, regs_feeding_address, nias, dia, inst_kind) @@ -1401,29 +1333,29 @@ val print_and_fail_of_inequal : forall 'a. Show 'a => (instruction -> string) -> (string * 'a) -> (string * 'a) -> unit let print_and_fail_if_inequal - (print_endline,pp_instruction,instruction) + (print_endline,instruction) (name1,xs1) (name2,xs2) = if xs1 = xs2 then () else let () = print_endline (name1^": "^show xs1) in let () = print_endline (name2^": "^show xs2) in - failwith (name1^" and "^ name2^" inequal for instruction " ^ pp_instruction instruction) + failwith (name1^" and "^ name2^" inequal for instruction: \n" ^ Interp.string_of_value instruction) let interp_compare_analyses print_endline - pp_instruction (non_pseudo_registers : set reg_name -> set reg_name) context endianness interp_exhaustive - instruction + (instruction : Interp_ast.value) nia_reg + (nias_function : (list (maybe address) -> list reg_name -> list nia)) ism environment analysis_function reg_info = let (regs_in1,regs_out1,regs_feeding_address1,nias1,dia1,inst_kind1) = - interp_instruction_analysis interp_exhaustive instruction nia_reg ism + interp_instruction_analysis context interp_exhaustive instruction nia_reg nias_function ism environment in let (regs_in1S,regs_out1S,regs_feeding_address1S,nias1S) = (Set.fromList regs_in1, @@ -1448,7 +1380,7 @@ let interp_compare_analyses non_pseudo_registers regs_out2S, non_pseudo_registers regs_feeding_address2S) in - let aux = (print_endline,pp_instruction,instruction) in + let aux = (print_endline,instruction) in let () = (print_and_fail_if_inequal aux) ("regs_in exhaustive",regs_in1S) ("regs_in hand",regs_in2S) in diff --git a/src/lem_interp/interp_interface.lem b/src/lem_interp/interp_interface.lem index dcc9f537..07d9e2b3 100644 --- a/src/lem_interp/interp_interface.lem +++ b/src/lem_interp/interp_interface.lem @@ -104,6 +104,10 @@ end and the potential static effects from the funcl clause for this instruction Follows the form of the instruction in instruction_extractor, but populates the parameters with actual values *) + + +type instruction_field_value = list bit + type instruction = (string * list (string * instr_parm_typ * instruction_field_value)) let {coq} instructionEqual i1 i2 = match (i1,i2) with @@ -117,7 +121,7 @@ let inline ~{coq} instructionInequal = unsafe_structural_inequality type v_kind = Bitv | Bytev type decode_error = - | Unsupported_instruction_error of instruction + | Unsupported_instruction_error of Interp_ast.value | Not_an_instruction_error of opcode | Internal_error of string @@ -264,12 +268,12 @@ val initial_instruction_state : context -> string -> list register_value -> inst (* string is a function name, list of value are the parameters to that function *) type instruction_or_decode_error = - | IDE_instr of instruction * Interp_ast.value + | IDE_instr of Interp_ast.value | IDE_decode_error of decode_error (** propose to remove the following type and use the above instead *) type i_state_or_error = - | Instr of instruction * instruction_state + | Instr of Interp_ast.value * instruction_state | Decode_error of decode_error diff --git a/src/lem_interp/run_with_elf.ml b/src/lem_interp/run_with_elf.ml index 2a1783db..98b98a03 100644 --- a/src/lem_interp/run_with_elf.ml +++ b/src/lem_interp/run_with_elf.ml @@ -1198,12 +1198,16 @@ let rec fde_loop count context model mode track_dependencies addr_trans = let opcode = Opcode (get_opcode pc) in let (instruction,istate) = match Interp_inter_imp.decode_to_istate context None opcode with | Instr(instruction,istate) -> - interactf "\n**** Running: %s ****\n" (Printing_functions.instruction_to_string instruction); + let instruction = interp_value_to_instr_external context instruction in + interactf "\n**** Running: %s ****\n" + (Printing_functions.instruction_to_string instruction); (instruction,istate) | Decode_error d -> (match d with - | Interp_interface.Unsupported_instruction_error instr -> - errorf "\n**** Encountered unsupported instruction %s ****\n" (Printing_functions.instruction_to_string instr) + | Interp_interface.Unsupported_instruction_error instruction -> + let instruction = interp_value_to_instr_external context instruction in + errorf "\n**** Encountered unsupported instruction %s ****\n" + (Printing_functions.instruction_to_string instruction) | Interp_interface.Not_an_instruction_error op -> (match op with | Opcode bytes -> diff --git a/src/lem_interp/run_with_elf_cheri.ml b/src/lem_interp/run_with_elf_cheri.ml index e773bf5b..7750c16c 100644 --- a/src/lem_interp/run_with_elf_cheri.ml +++ b/src/lem_interp/run_with_elf_cheri.ml @@ -124,375 +124,13 @@ let register_state_zero register_data rbn : register_value = in register_value_zeros dir width start_index type model = PPC | AArch64 | MIPS -(* -let ppc_register_data_all = [ - (*Pseudo registers*) - ("CIA", (D_increasing, 64, 0)); - ("NIA", (D_increasing, 64, 0)); - ("mode64bit", (D_increasing, 1, 0)); - ("bigendianmode", (D_increasing, 1, 0)); - (* special registers *) - ("CR", (D_increasing, 32, 32)); - ("CTR", (D_increasing, 64, 0 )); - ("LR", (D_increasing, 64, 0 )); - ("XER", (D_increasing, 64, 0 )); - ("VRSAVE",(D_increasing, 32, 32)); - ("FPSCR", (D_increasing, 64, 0 )); - ("VSCR", (D_increasing, 32, 96)); - - (* general purpose registers *) - ("GPR0", (D_increasing, 64, 0 )); - ("GPR1", (D_increasing, 64, 0 )); - ("GPR2", (D_increasing, 64, 0 )); - ("GPR3", (D_increasing, 64, 0 )); - ("GPR4", (D_increasing, 64, 0 )); - ("GPR5", (D_increasing, 64, 0 )); - ("GPR6", (D_increasing, 64, 0 )); - ("GPR7", (D_increasing, 64, 0 )); - ("GPR8", (D_increasing, 64, 0 )); - ("GPR9", (D_increasing, 64, 0 )); - ("GPR10", (D_increasing, 64, 0 )); - ("GPR11", (D_increasing, 64, 0 )); - ("GPR12", (D_increasing, 64, 0 )); - ("GPR13", (D_increasing, 64, 0 )); - ("GPR14", (D_increasing, 64, 0 )); - ("GPR15", (D_increasing, 64, 0 )); - ("GPR16", (D_increasing, 64, 0 )); - ("GPR17", (D_increasing, 64, 0 )); - ("GPR18", (D_increasing, 64, 0 )); - ("GPR19", (D_increasing, 64, 0 )); - ("GPR20", (D_increasing, 64, 0 )); - ("GPR21", (D_increasing, 64, 0 )); - ("GPR22", (D_increasing, 64, 0 )); - ("GPR23", (D_increasing, 64, 0 )); - ("GPR24", (D_increasing, 64, 0 )); - ("GPR25", (D_increasing, 64, 0 )); - ("GPR26", (D_increasing, 64, 0 )); - ("GPR27", (D_increasing, 64, 0 )); - ("GPR28", (D_increasing, 64, 0 )); - ("GPR29", (D_increasing, 64, 0 )); - ("GPR30", (D_increasing, 64, 0 )); - ("GPR31", (D_increasing, 64, 0 )); - (* vector registers *) - ("VR0", (D_increasing, 128, 0 )); - ("VR1", (D_increasing, 128, 0 )); - ("VR2", (D_increasing, 128, 0 )); - ("VR3", (D_increasing, 128, 0 )); - ("VR4", (D_increasing, 128, 0 )); - ("VR5", (D_increasing, 128, 0 )); - ("VR6", (D_increasing, 128, 0 )); - ("VR7", (D_increasing, 128, 0 )); - ("VR8", (D_increasing, 128, 0 )); - ("VR9", (D_increasing, 128, 0 )); - ("VR10", (D_increasing, 128, 0 )); - ("VR11", (D_increasing, 128, 0 )); - ("VR12", (D_increasing, 128, 0 )); - ("VR13", (D_increasing, 128, 0 )); - ("VR14", (D_increasing, 128, 0 )); - ("VR15", (D_increasing, 128, 0 )); - ("VR16", (D_increasing, 128, 0 )); - ("VR17", (D_increasing, 128, 0 )); - ("VR18", (D_increasing, 128, 0 )); - ("VR19", (D_increasing, 128, 0 )); - ("VR20", (D_increasing, 128, 0 )); - ("VR21", (D_increasing, 128, 0 )); - ("VR22", (D_increasing, 128, 0 )); - ("VR23", (D_increasing, 128, 0 )); - ("VR24", (D_increasing, 128, 0 )); - ("VR25", (D_increasing, 128, 0 )); - ("VR26", (D_increasing, 128, 0 )); - ("VR27", (D_increasing, 128, 0 )); - ("VR28", (D_increasing, 128, 0 )); - ("VR29", (D_increasing, 128, 0 )); - ("VR30", (D_increasing, 128, 0 )); - ("VR31", (D_increasing, 128, 0 )); - (* floating-point registers *) - ("FPR0", (D_increasing, 64, 0 )); - ("FPR1", (D_increasing, 64, 0 )); - ("FPR2", (D_increasing, 64, 0 )); - ("FPR3", (D_increasing, 64, 0 )); - ("FPR4", (D_increasing, 64, 0 )); - ("FPR5", (D_increasing, 64, 0 )); - ("FPR6", (D_increasing, 64, 0 )); - ("FPR7", (D_increasing, 64, 0 )); - ("FPR8", (D_increasing, 64, 0 )); - ("FPR9", (D_increasing, 64, 0 )); - ("FPR10", (D_increasing, 64, 0 )); - ("FPR11", (D_increasing, 64, 0 )); - ("FPR12", (D_increasing, 64, 0 )); - ("FPR13", (D_increasing, 64, 0 )); - ("FPR14", (D_increasing, 64, 0 )); - ("FPR15", (D_increasing, 64, 0 )); - ("FPR16", (D_increasing, 64, 0 )); - ("FPR17", (D_increasing, 64, 0 )); - ("FPR18", (D_increasing, 64, 0 )); - ("FPR19", (D_increasing, 64, 0 )); - ("FPR20", (D_increasing, 64, 0 )); - ("FPR21", (D_increasing, 64, 0 )); - ("FPR22", (D_increasing, 64, 0 )); - ("FPR23", (D_increasing, 64, 0 )); - ("FPR24", (D_increasing, 64, 0 )); - ("FPR25", (D_increasing, 64, 0 )); - ("FPR26", (D_increasing, 64, 0 )); - ("FPR27", (D_increasing, 64, 0 )); - ("FPR28", (D_increasing, 64, 0 )); - ("FPR29", (D_increasing, 64, 0 )); - ("FPR30", (D_increasing, 64, 0 )); - ("FPR31", (D_increasing, 64, 0 )); -] - -let initial_stack_and_reg_data_of_PPC_elf_file e_entry all_data_memory = - (* set up initial registers, per 3.4.1 of 64-bit PowerPC ELF Application Binary Interface Supplement 1.9 *) - - let auxiliary_vector_space = Nat_big_num.of_string "17592186042368" (*"0xffffffff800"*) in - (* notionally there should be at least an AT_NULL auxiliary vector entry there, but our examples will never read it *) - - (* take start of stack roughly where running gdb on hello5 on bim says it is*) - let initial_GPR1_stack_pointer = Nat_big_num.of_string "17592186040320" (*"0xffffffff000"*) in - let initial_GPR1_stack_pointer_value = - Sail_impl_base.register_value_of_integer 64 0 Sail_impl_base.D_increasing initial_GPR1_stack_pointer in - (* ELF says we need an initial zero doubleword there *) - let initial_stack_data = - (* the code actually uses the stack, both above and below, so we map a bit more memory*) - (* this is a fairly big but arbitrary chunk *) - (* let initial_stack_data_address = Nat_big_num.sub initial_GPR1_stack_pointer (Nat_big_num.of_int 128) in - [("initial_stack_data", initial_stack_data_address, Lem_list.replicate (128+32) 0 ))] in *) - (* this is the stack memory that test 1938 actually uses *) - [ ("initial_stack_data1", Nat_big_num.sub initial_GPR1_stack_pointer (Nat_big_num.of_int 128), - Lem_list.replicate 8 0 ); - ("initial_stack_data2", Nat_big_num.sub initial_GPR1_stack_pointer (Nat_big_num.of_int 8), - Lem_list.replicate 8 0 ); - ("initial_stack_data3", Nat_big_num.add initial_GPR1_stack_pointer (Nat_big_num.of_int 16), - Lem_list.replicate 8 0 )] in - - (* read TOC from the second field of the function descriptor pointed to by e_entry*) - let initial_GPR2_TOC = - Sail_impl_base.register_value_of_address - (Sail_impl_base.address_of_byte_list - (List.map (fun b -> match b with Some b -> b | None -> failwith "Address had undefined") - (List.map byte_of_byte_lifted - (read_mem all_data_memory - (Nat_big_num.add (Nat_big_num.of_int 8) e_entry) 8)))) - Sail_impl_base.D_increasing in - (* these initial register values are all mandated to be zero, but that's handled by the generic zeroing below - let initial_GPR3_argc = (Nat_big_num.of_int 0) in - let initial_GPR4_argv = (Nat_big_num.of_int 0) in - let initial_GPR5_envp = (Nat_big_num.of_int 0) in - let initial_FPSCR = (Nat_big_num.of_int 0) in - *) - let initial_register_abi_data : (string * Sail_impl_base.register_value) list = - [ ("GPR1", initial_GPR1_stack_pointer_value); - ("GPR2", initial_GPR2_TOC); - (* - ("GPR3", initial_GPR3_argc); - ("GPR4", initial_GPR4_argv); - ("GPR5", initial_GPR5_envp); - ("FPSCR", initial_FPSCR); - *) - ] in - - (initial_stack_data, initial_register_abi_data) - - -let aarch64_reg bit_count name = (name, (D_decreasing, bit_count, bit_count - 1)) - -let aarch64_PC_data = [aarch64_reg 64 "_PC"] - -(* most of the PSTATE fields are aliases to other registers so they - don't appear here *) -let aarch64_PSTATE_data = [ - aarch64_reg 1 "PSTATE_nRW"; - aarch64_reg 1 "PSTATE_E"; - aarch64_reg 5 "PSTATE_M"; -] - -let aarch64_general_purpose_registers_data = [ - aarch64_reg 64 "R0"; - aarch64_reg 64 "R1"; - aarch64_reg 64 "R2"; - aarch64_reg 64 "R3"; - aarch64_reg 64 "R4"; - aarch64_reg 64 "R5"; - aarch64_reg 64 "R6"; - aarch64_reg 64 "R7"; - aarch64_reg 64 "R8"; - aarch64_reg 64 "R9"; - aarch64_reg 64 "R10"; - aarch64_reg 64 "R11"; - aarch64_reg 64 "R12"; - aarch64_reg 64 "R13"; - aarch64_reg 64 "R14"; - aarch64_reg 64 "R15"; - aarch64_reg 64 "R16"; - aarch64_reg 64 "R17"; - aarch64_reg 64 "R18"; - aarch64_reg 64 "R19"; - aarch64_reg 64 "R20"; - aarch64_reg 64 "R21"; - aarch64_reg 64 "R22"; - aarch64_reg 64 "R23"; - aarch64_reg 64 "R24"; - aarch64_reg 64 "R25"; - aarch64_reg 64 "R26"; - aarch64_reg 64 "R27"; - aarch64_reg 64 "R28"; - aarch64_reg 64 "R29"; - aarch64_reg 64 "R30"; -] - -let aarch64_SIMD_registers_data = [ - aarch64_reg 128 "V0"; - aarch64_reg 128 "V1"; - aarch64_reg 128 "V2"; - aarch64_reg 128 "V3"; - aarch64_reg 128 "V4"; - aarch64_reg 128 "V5"; - aarch64_reg 128 "V6"; - aarch64_reg 128 "V7"; - aarch64_reg 128 "V8"; - aarch64_reg 128 "V9"; - aarch64_reg 128 "V10"; - aarch64_reg 128 "V11"; - aarch64_reg 128 "V12"; - aarch64_reg 128 "V13"; - aarch64_reg 128 "V14"; - aarch64_reg 128 "V15"; - aarch64_reg 128 "V16"; - aarch64_reg 128 "V17"; - aarch64_reg 128 "V18"; - aarch64_reg 128 "V19"; - aarch64_reg 128 "V20"; - aarch64_reg 128 "V21"; - aarch64_reg 128 "V22"; - aarch64_reg 128 "V23"; - aarch64_reg 128 "V24"; - aarch64_reg 128 "V25"; - aarch64_reg 128 "V26"; - aarch64_reg 128 "V27"; - aarch64_reg 128 "V28"; - aarch64_reg 128 "V29"; - aarch64_reg 128 "V30"; - aarch64_reg 128 "V31"; -] - -let aarch64_special_purpose_registers_data = [ - aarch64_reg 32 "CurrentEL"; - aarch64_reg 32 "DAIF"; - aarch64_reg 32 "NZCV"; - aarch64_reg 64 "SP_EL0"; - aarch64_reg 64 "SP_EL1"; - aarch64_reg 64 "SP_EL2"; - aarch64_reg 64 "SP_EL3"; - aarch64_reg 32 "SPSel"; - aarch64_reg 32 "SPSR_EL1"; - aarch64_reg 32 "SPSR_EL2"; - aarch64_reg 32 "SPSR_EL3"; - aarch64_reg 64 "ELR_EL1"; - aarch64_reg 64 "ELR_EL2"; - aarch64_reg 64 "ELR_EL3"; -] - -let aarch64_general_system_control_registers_data = [ - aarch64_reg 64 "HCR_EL2"; - aarch64_reg 64 "ID_AA64MMFR0_EL1"; - aarch64_reg 64 "RVBAR_EL1"; - aarch64_reg 64 "RVBAR_EL2"; - aarch64_reg 64 "RVBAR_EL3"; - aarch64_reg 32 "SCR_EL3"; - aarch64_reg 32 "SCTLR_EL1"; - aarch64_reg 32 "SCTLR_EL2"; - aarch64_reg 32 "SCTLR_EL3"; - aarch64_reg 64 "TCR_EL1"; - aarch64_reg 32 "TCR_EL2"; - aarch64_reg 32 "TCR_EL3"; -] - -let aarch64_debug_registers_data = [ - aarch64_reg 32 "DBGPRCR_EL1"; - aarch64_reg 32 "OSDLR_EL1"; -] - -let aarch64_performance_monitors_registers_data = [] -let aarch64_generic_timer_registers_data = [] -let aarch64_generic_interrupt_controller_CPU_interface_registers_data = [] - -let aarch64_external_debug_registers_data = [ - aarch64_reg 32 "EDSCR"; -] - -let aarch32_general_system_control_registers_data = [ - aarch64_reg 32 "SCR"; -] - -let aarch32_debug_registers_data = [ - aarch64_reg 32 "DBGOSDLR"; - aarch64_reg 32 "DBGPRCR"; -] - -let aarch64_register_data_all = - aarch64_PC_data @ - aarch64_PSTATE_data @ - aarch64_general_purpose_registers_data @ - aarch64_SIMD_registers_data @ - aarch64_special_purpose_registers_data @ - aarch64_general_system_control_registers_data @ - aarch64_debug_registers_data @ - aarch64_performance_monitors_registers_data @ - aarch64_generic_timer_registers_data @ - aarch64_generic_interrupt_controller_CPU_interface_registers_data @ - aarch64_external_debug_registers_data @ - aarch32_general_system_control_registers_data @ - aarch32_debug_registers_data - -let initial_stack_and_reg_data_of_AAarch64_elf_file e_entry all_data_memory = - let (reg_SP_EL0_direction, reg_SP_EL0_width, reg_SP_EL0_initial_index) = - List.assoc "SP_EL0" aarch64_register_data_all in - - (* we compiled a small program that prints out SP and run it a few - times on the Nexus9, these are the results: - 0x0000007fe7f903e0 - 0x0000007fdcdbf3f0 - 0x0000007fcbe1ba90 - 0x0000007fcf378280 - 0x0000007fdd54b8d0 - 0x0000007fd961bc10 - 0x0000007ff3be6350 - 0x0000007fd6bf6ef0 - 0x0000007fff7676f0 - 0x0000007ff2c34560 *) - let initial_SP_EL0 = Nat_big_num.of_string "549739036672" (*"0x0000007fff000000"*) in - let initial_SP_EL0_value = - Sail_impl_base.register_value_of_integer - reg_SP_EL0_width - reg_SP_EL0_initial_index - reg_SP_EL0_direction - initial_SP_EL0 - in - - (* ELF says we need an initial zero doubleword there *) - (* the code actually uses the stack, both above and below, so we map a bit more memory*) - let initial_stack_data = - (* this is a fairly big but arbitrary chunk: *) - (* let initial_stack_data_address = Nat_big_num.sub initial_GPR1_stack_pointer (Nat_big_num.of_int 128) in - [("initial_stack_data", initial_stack_data_address, Lem_list.replicate (128+32) 0 ))] in *) - - [ ("initial_stack_data1", Nat_big_num.sub initial_SP_EL0 (Nat_big_num.of_int 16), Lem_list.replicate 8 0); - ("initial_stack_data2", Nat_big_num.sub initial_SP_EL0 (Nat_big_num.of_int 8), Lem_list.replicate 8 0) - ] - in - - let initial_register_abi_data : (string * Sail_impl_base.register_value) list = - [("SP_EL0", initial_SP_EL0_value)] - in - - (initial_stack_data, initial_register_abi_data) -*) let mips_register_data_all = [ (*Pseudo registers*) ("PC", (D_decreasing, 64, 63)); ("branchPending", (D_decreasing, 1, 0)); ("inBranchDelay", (D_decreasing, 1, 0)); + ("inCCallDelay", (D_decreasing, 1, 0)); ("delayedPC", (D_decreasing, 64, 63)); ("nextPC", (D_decreasing, 64, 63)); (* General purpose registers *) @@ -748,50 +386,6 @@ let initial_system_state_of_elf_file name = let (isa_defs, isa_memory_access, isa_externs, isa_model, model_reg_d, startaddr, initial_stack_data, initial_register_abi_data, register_data_all) = match Nat_big_num.to_int e_machine with -(* | 21 (* EM_PPC64 *) -> - let startaddr = - let e_entry = Uint64.of_int64 (Nat_big_num.to_int64 e_entry) in - match Abi_power64.abi_power64_compute_program_entry_point segments e_entry with - | Error.Fail s -> failwith "Failed computing entry point" - | Error.Success s -> Nat_big_num.of_int64 (Uint64.to_int64 s) - in - let (initial_stack_data, initial_register_abi_data) = - initial_stack_and_reg_data_of_PPC_elf_file e_entry !data_mem in - - (Power.defs, - (Power_extras.read_memory_functions,Power_extras.memory_writes,[],[],Power_extras.barrier_functions), - Power_extras.power_externs, - PPC, - D_increasing, - startaddr, - initial_stack_data, - initial_register_abi_data, - ppc_register_data_all) - - | 183 (* EM_AARCH64 *) -> - let startaddr = - let e_entry = Uint64.of_int64 (Nat_big_num.to_int64 e_entry) in - match Abi_aarch64_le.abi_aarch64_le_compute_program_entry_point segments e_entry with - | Error.Fail s -> failwith "Failed computing entry point" - | Error.Success s -> Nat_big_num.of_int64 (Uint64.to_int64 s) - in - - let (initial_stack_data, initial_register_abi_data) = - initial_stack_and_reg_data_of_AAarch64_elf_file e_entry !data_mem in - - (ArmV8.defs, - (ArmV8_extras.aArch64_read_memory_functions, - ArmV8_extras.aArch64_memory_writes, - ArmV8_extras.aArch64_memory_eas, - ArmV8_extras.aArch64_memory_vals, - ArmV8_extras.aArch64_barrier_functions), - [], - AArch64, - D_decreasing, - startaddr, - initial_stack_data, - initial_register_abi_data, - aarch64_register_data_all) *) | 8 (* EM_MIPS *) -> let startaddr = let e_entry = Uint64.of_string (Nat_big_num.to_string e_entry) in @@ -888,50 +482,6 @@ let initial_system_state_of_elf_file name = in - (* Now we examine the rest of the data memory, - removing the footprint of the symbols and chunking it into aligned chunks *) - - let rec remove_symbols_from_data_memory data_mem symbols = - match symbols with - | [] -> data_mem - | (name,address,size,bs)::symbols' -> - let data_mem' = - Mem.filter - (fun a v -> - not (Nat_big_num.greater_equal a address && - Nat_big_num.less a (Nat_big_num.add (Nat_big_num.of_int (List.length bs)) address))) - data_mem in - remove_symbols_from_data_memory data_mem' symbols' in - - let trimmed_data_memory : (Nat_big_num.num * memory_byte) list = - Mem.bindings (remove_symbols_from_data_memory !data_mem symbol_table) in - - (* make sure that's ordered increasingly.... *) - let trimmed_data_memory = - List.sort (fun (a,b) (a',b') -> Nat_big_num.compare a a') trimmed_data_memory in - - let aligned a n = (* a mod n = 0 *) - let n_big = Nat_big_num.of_int n in - Nat_big_num.equal (Nat_big_num.modulus a n_big) ((Nat_big_num.of_int 0)) in - - let isplus a' a n = (* a' = a+n *) - Nat_big_num.equal a' (Nat_big_num.add (Nat_big_num.of_int n) a) in - - let rec chunk_data_memory dm = - match dm with - | (a0,b0)::(a1,b1)::(a2,b2)::(a3,b3)::(a4,b4)::(a5,b5)::(a6,b6)::(a7,b7)::dm' when - (aligned a0 8 && isplus a1 a0 1 && isplus a2 a0 2 && isplus a3 a0 3 && - isplus a4 a0 4 && isplus a5 a0 5 && isplus a6 a0 6 && isplus a7 a0 7) -> - (a0,8,[b0;b1;b2;b3;b4;b5;b6;b7]) :: chunk_data_memory dm' - | (a0,b0)::(a1,b1)::(a2,b2)::(a3,b3)::dm' when - (aligned a0 4 && isplus a1 a0 1 && isplus a2 a0 2 && isplus a3 a0 3) -> - (a0,4,[b0;b1;b2;b3]) :: chunk_data_memory dm' - | (a0,b0)::(a1,b1)::dm' when - (aligned a0 2 && isplus a1 a0 1) -> - (a0,2,[b0;b1]) :: chunk_data_memory dm' - | (a0,b0)::dm' -> - (a0,1,[b0]):: chunk_data_memory dm' - | [] -> [] in let initial_register_state = fun rbn -> @@ -1021,68 +571,10 @@ let stop_condition_met model instr = true | _ -> false) -let is_branch model instruction = - let (name,_,_) = instruction in - match (model , name) with - | (PPC, "B") -> true - | (PPC, "Bc") -> true - | (PPC, "Bclr") -> true - | (PPC, "Bcctr") -> true - | (PPC, _) -> false - | (AArch64, "BranchImmediate") -> true - | (AArch64, "BranchConditional") -> true - | (AArch64, "CompareAndBranch") -> true - | (AArch64, "TestBitAndBranch") -> true - | (AArch64, "BranchRegister") -> true - | (AArch64, _) -> false - | (MIPS, _) -> false (*todo,fill this in*) - let option_int_of_option_integer i = match i with | Some i -> Some (Nat_big_num.to_int i) | None -> None -let set_next_instruction_address model = - match model with - | PPC -> - let cia = Reg.find "CIA" !reg in - let cia_addr = address_of_register_value cia in - (match cia_addr with - | Some cia_addr -> - let nia_addr = add_address_nat cia_addr 4 in - let nia = register_value_of_address nia_addr Sail_impl_base.D_increasing in - reg := Reg.add "NIA" nia !reg - | _ -> failwith "CIA address contains unknown or undefined") - | AArch64 -> - let pc = Reg.find "_PC" !reg in - let pc_addr = address_of_register_value pc in - (match pc_addr with - | Some pc_addr -> - let n_addr = add_address_nat pc_addr 4 in - let n_pc = register_value_of_address n_addr D_decreasing in - reg := Reg.add "_PC" n_pc !reg - | _ -> failwith "_PC address contains unknown or undefined") - | MIPS -> - let pc_addr = address_of_register_value (Reg.find "PC" !reg) in - let branchPending = integer_of_register_value (Reg.find "branchPending" !reg) in - (match (pc_addr, option_int_of_option_integer branchPending) with - | (Some pc_val, Some 0) -> - (* normal -- increment PC *) - let n_addr = add_address_nat pc_val 4 in - let n_pc = register_value_of_address n_addr D_decreasing in - begin - reg := Reg.add "nextPC" n_pc !reg; - reg := Reg.add "inBranchDelay" (register_value_of_integer 1 0 Sail_impl_base.D_decreasing Nat_big_num.zero) !reg; - end - | (Some pc_val, Some 1) -> - (* delay slot -- branch to delayed PC and clear branchPending *) - begin - reg := Reg.add "nextPC" (Reg.find "delayedPC" !reg) !reg; - reg := Reg.add "nextPCC" (Reg.find "delayedPCC" !reg) !reg; - reg := Reg.add "branchPending" (register_value_of_integer 1 0 Sail_impl_base.D_decreasing Nat_big_num.zero) !reg; - reg := Reg.add "inBranchDelay" (register_value_of_integer 1 0 Sail_impl_base.D_decreasing (Nat_big_num.of_int 1)) !reg; - end - | (_, _) -> errorf "PC address contains unknown or undefined"; exit 1) - let add1 = Nat_big_num.add (Nat_big_num.of_int 1) let get_addr_trans_regs _ = @@ -1192,68 +684,10 @@ let rec write_events = function | _ -> failwith "Only register write events expected"); write_events events -let fetch_instruction_opcode_and_update_ia model addr_trans = - match model with - | PPC -> - let cia = Reg.find "CIA" !reg in - let cia_addr = address_of_register_value cia in - (match cia_addr with - | Some cia_addr -> - let cia_a = integer_of_address cia_addr in - let opcode = (get_opcode cia_a) in - begin - reg := Reg.add "CIA" (Reg.find "NIA" !reg) !reg; - Opcode opcode - end - | None -> failwith "CIA address contains unknown or undefined") - | AArch64 -> - let pc = Reg.find "_PC" !reg in - let pc_addr = address_of_register_value pc in - (match pc_addr with - | Some pc_addr -> - let pc_a = integer_of_address pc_addr in - let opcode = (get_opcode pc_a) in - Opcode opcode - | None -> failwith "_PC address contains unknown or undefined") - | MIPS -> - begin - reg := Reg.add "PCC" (Reg.find "nextPCC" !reg) !reg; - let nextPC = Reg.find "nextPC" !reg in - let pc_addr = address_of_register_value nextPC in - (*let unused = interactf "PC: %s\n" (Printing_functions.register_value_to_string nextPC) in*) - (match pc_addr with - | Some pc_addr -> - let pc_a = match addr_trans (get_addr_trans_regs ()) pc_addr with - | Some a, Some events -> write_events (List.rev events); integer_of_address a - | Some a, None -> integer_of_address a - | None, Some events -> - write_events (List.rev events); - let nextPC = Reg.find "nextPC" !reg in - reg := Reg.add "PCC" (Reg.find "nextPCC" !reg) !reg; - let pc_addr = address_of_register_value nextPC in - (match pc_addr with - | Some pc_addr -> - (match addr_trans (get_addr_trans_regs ()) pc_addr with - | Some a, Some events -> write_events (List.rev events); integer_of_address a - | Some a, None -> integer_of_address a - | None, _ -> failwith "Address translation failed twice") - | None -> failwith "no nextPc address") - | _ -> failwith "No address and no events from translate address" - in - let opcode = (get_opcode pc_a) in - begin - reg := Reg.add "PC" (Reg.find "nextPC" !reg) !reg; - Opcode opcode - end - | None -> errorf "nextPC contains unknown or undefined"; exit 1) - end - | _ -> assert false - let get_pc_address = function | MIPS -> Reg.find "PC" !reg | PPC -> Reg.find "CIA" !reg | AArch64 -> Reg.find "_PC" !reg - let option_int_of_reg str = option_int_of_option_integer (integer_of_register_value (Reg.find str !reg)) @@ -1283,6 +717,7 @@ let rec fde_loop count context model mode track_dependencies addr_trans = let npc_addr = add_address_nat pc_val 4 in let npc_reg = register_value_of_address npc_addr Sail_impl_base.D_decreasing in reg := Reg.add "nextPC" npc_reg !reg; + reg := Reg.add "inCCallDelay" (register_value_of_integer 1 0 Sail_impl_base.D_decreasing Nat_big_num.zero) !reg; | Some 1 -> reg := Reg.add "nextPC" (Reg.find "delayedPC" !reg) !reg; reg := Reg.add "nextPCC" (Reg.find "delayedPCC" !reg) !reg; @@ -1290,12 +725,14 @@ let rec fde_loop count context model mode track_dependencies addr_trans = let opcode = Opcode (get_opcode pc) in let (instruction,istate) = match Interp_inter_imp.decode_to_istate context None opcode with | Instr(instruction,istate) -> + let instruction = interp_value_to_instr_external context instruction in interactf "\n**** Running: %s ****\n" (Printing_functions.instruction_to_string instruction); (instruction,istate) | Decode_error d -> (match d with - | Interp_interface.Unsupported_instruction_error instr -> - errorf "\n**** Encountered unsupported instruction %s ****\n" (Printing_functions.instruction_to_string instr) + | Interp_interface.Unsupported_instruction_error instruction -> + let instruction = interp_value_to_instr_external context instruction in + errorf "\n**** Encountered unsupported instruction %s ****\n" (Printing_functions.instruction_to_string instruction) | Interp_interface.Not_an_instruction_error op -> (match op with | Opcode bytes -> diff --git a/src/lem_interp/run_with_elf_cheri128.ml b/src/lem_interp/run_with_elf_cheri128.ml index cd2e7312..6dca80f4 100644 --- a/src/lem_interp/run_with_elf_cheri128.ml +++ b/src/lem_interp/run_with_elf_cheri128.ml @@ -124,375 +124,13 @@ let register_state_zero register_data rbn : register_value = in register_value_zeros dir width start_index type model = PPC | AArch64 | MIPS -(* -let ppc_register_data_all = [ - (*Pseudo registers*) - ("CIA", (D_increasing, 64, 0)); - ("NIA", (D_increasing, 64, 0)); - ("mode64bit", (D_increasing, 1, 0)); - ("bigendianmode", (D_increasing, 1, 0)); - (* special registers *) - ("CR", (D_increasing, 32, 32)); - ("CTR", (D_increasing, 64, 0 )); - ("LR", (D_increasing, 64, 0 )); - ("XER", (D_increasing, 64, 0 )); - ("VRSAVE",(D_increasing, 32, 32)); - ("FPSCR", (D_increasing, 64, 0 )); - ("VSCR", (D_increasing, 32, 96)); - - (* general purpose registers *) - ("GPR0", (D_increasing, 64, 0 )); - ("GPR1", (D_increasing, 64, 0 )); - ("GPR2", (D_increasing, 64, 0 )); - ("GPR3", (D_increasing, 64, 0 )); - ("GPR4", (D_increasing, 64, 0 )); - ("GPR5", (D_increasing, 64, 0 )); - ("GPR6", (D_increasing, 64, 0 )); - ("GPR7", (D_increasing, 64, 0 )); - ("GPR8", (D_increasing, 64, 0 )); - ("GPR9", (D_increasing, 64, 0 )); - ("GPR10", (D_increasing, 64, 0 )); - ("GPR11", (D_increasing, 64, 0 )); - ("GPR12", (D_increasing, 64, 0 )); - ("GPR13", (D_increasing, 64, 0 )); - ("GPR14", (D_increasing, 64, 0 )); - ("GPR15", (D_increasing, 64, 0 )); - ("GPR16", (D_increasing, 64, 0 )); - ("GPR17", (D_increasing, 64, 0 )); - ("GPR18", (D_increasing, 64, 0 )); - ("GPR19", (D_increasing, 64, 0 )); - ("GPR20", (D_increasing, 64, 0 )); - ("GPR21", (D_increasing, 64, 0 )); - ("GPR22", (D_increasing, 64, 0 )); - ("GPR23", (D_increasing, 64, 0 )); - ("GPR24", (D_increasing, 64, 0 )); - ("GPR25", (D_increasing, 64, 0 )); - ("GPR26", (D_increasing, 64, 0 )); - ("GPR27", (D_increasing, 64, 0 )); - ("GPR28", (D_increasing, 64, 0 )); - ("GPR29", (D_increasing, 64, 0 )); - ("GPR30", (D_increasing, 64, 0 )); - ("GPR31", (D_increasing, 64, 0 )); - (* vector registers *) - ("VR0", (D_increasing, 128, 0 )); - ("VR1", (D_increasing, 128, 0 )); - ("VR2", (D_increasing, 128, 0 )); - ("VR3", (D_increasing, 128, 0 )); - ("VR4", (D_increasing, 128, 0 )); - ("VR5", (D_increasing, 128, 0 )); - ("VR6", (D_increasing, 128, 0 )); - ("VR7", (D_increasing, 128, 0 )); - ("VR8", (D_increasing, 128, 0 )); - ("VR9", (D_increasing, 128, 0 )); - ("VR10", (D_increasing, 128, 0 )); - ("VR11", (D_increasing, 128, 0 )); - ("VR12", (D_increasing, 128, 0 )); - ("VR13", (D_increasing, 128, 0 )); - ("VR14", (D_increasing, 128, 0 )); - ("VR15", (D_increasing, 128, 0 )); - ("VR16", (D_increasing, 128, 0 )); - ("VR17", (D_increasing, 128, 0 )); - ("VR18", (D_increasing, 128, 0 )); - ("VR19", (D_increasing, 128, 0 )); - ("VR20", (D_increasing, 128, 0 )); - ("VR21", (D_increasing, 128, 0 )); - ("VR22", (D_increasing, 128, 0 )); - ("VR23", (D_increasing, 128, 0 )); - ("VR24", (D_increasing, 128, 0 )); - ("VR25", (D_increasing, 128, 0 )); - ("VR26", (D_increasing, 128, 0 )); - ("VR27", (D_increasing, 128, 0 )); - ("VR28", (D_increasing, 128, 0 )); - ("VR29", (D_increasing, 128, 0 )); - ("VR30", (D_increasing, 128, 0 )); - ("VR31", (D_increasing, 128, 0 )); - (* floating-point registers *) - ("FPR0", (D_increasing, 64, 0 )); - ("FPR1", (D_increasing, 64, 0 )); - ("FPR2", (D_increasing, 64, 0 )); - ("FPR3", (D_increasing, 64, 0 )); - ("FPR4", (D_increasing, 64, 0 )); - ("FPR5", (D_increasing, 64, 0 )); - ("FPR6", (D_increasing, 64, 0 )); - ("FPR7", (D_increasing, 64, 0 )); - ("FPR8", (D_increasing, 64, 0 )); - ("FPR9", (D_increasing, 64, 0 )); - ("FPR10", (D_increasing, 64, 0 )); - ("FPR11", (D_increasing, 64, 0 )); - ("FPR12", (D_increasing, 64, 0 )); - ("FPR13", (D_increasing, 64, 0 )); - ("FPR14", (D_increasing, 64, 0 )); - ("FPR15", (D_increasing, 64, 0 )); - ("FPR16", (D_increasing, 64, 0 )); - ("FPR17", (D_increasing, 64, 0 )); - ("FPR18", (D_increasing, 64, 0 )); - ("FPR19", (D_increasing, 64, 0 )); - ("FPR20", (D_increasing, 64, 0 )); - ("FPR21", (D_increasing, 64, 0 )); - ("FPR22", (D_increasing, 64, 0 )); - ("FPR23", (D_increasing, 64, 0 )); - ("FPR24", (D_increasing, 64, 0 )); - ("FPR25", (D_increasing, 64, 0 )); - ("FPR26", (D_increasing, 64, 0 )); - ("FPR27", (D_increasing, 64, 0 )); - ("FPR28", (D_increasing, 64, 0 )); - ("FPR29", (D_increasing, 64, 0 )); - ("FPR30", (D_increasing, 64, 0 )); - ("FPR31", (D_increasing, 64, 0 )); -] - -let initial_stack_and_reg_data_of_PPC_elf_file e_entry all_data_memory = - (* set up initial registers, per 3.4.1 of 64-bit PowerPC ELF Application Binary Interface Supplement 1.9 *) - - let auxiliary_vector_space = Nat_big_num.of_string "17592186042368" (*"0xffffffff800"*) in - (* notionally there should be at least an AT_NULL auxiliary vector entry there, but our examples will never read it *) - - (* take start of stack roughly where running gdb on hello5 on bim says it is*) - let initial_GPR1_stack_pointer = Nat_big_num.of_string "17592186040320" (*"0xffffffff000"*) in - let initial_GPR1_stack_pointer_value = - Sail_impl_base.register_value_of_integer 64 0 Sail_impl_base.D_increasing initial_GPR1_stack_pointer in - (* ELF says we need an initial zero doubleword there *) - let initial_stack_data = - (* the code actually uses the stack, both above and below, so we map a bit more memory*) - (* this is a fairly big but arbitrary chunk *) - (* let initial_stack_data_address = Nat_big_num.sub initial_GPR1_stack_pointer (Nat_big_num.of_int 128) in - [("initial_stack_data", initial_stack_data_address, Lem_list.replicate (128+32) 0 ))] in *) - (* this is the stack memory that test 1938 actually uses *) - [ ("initial_stack_data1", Nat_big_num.sub initial_GPR1_stack_pointer (Nat_big_num.of_int 128), - Lem_list.replicate 8 0 ); - ("initial_stack_data2", Nat_big_num.sub initial_GPR1_stack_pointer (Nat_big_num.of_int 8), - Lem_list.replicate 8 0 ); - ("initial_stack_data3", Nat_big_num.add initial_GPR1_stack_pointer (Nat_big_num.of_int 16), - Lem_list.replicate 8 0 )] in - - (* read TOC from the second field of the function descriptor pointed to by e_entry*) - let initial_GPR2_TOC = - Sail_impl_base.register_value_of_address - (Sail_impl_base.address_of_byte_list - (List.map (fun b -> match b with Some b -> b | None -> failwith "Address had undefined") - (List.map byte_of_byte_lifted - (read_mem all_data_memory - (Nat_big_num.add (Nat_big_num.of_int 8) e_entry) 8)))) - Sail_impl_base.D_increasing in - (* these initial register values are all mandated to be zero, but that's handled by the generic zeroing below - let initial_GPR3_argc = (Nat_big_num.of_int 0) in - let initial_GPR4_argv = (Nat_big_num.of_int 0) in - let initial_GPR5_envp = (Nat_big_num.of_int 0) in - let initial_FPSCR = (Nat_big_num.of_int 0) in - *) - let initial_register_abi_data : (string * Sail_impl_base.register_value) list = - [ ("GPR1", initial_GPR1_stack_pointer_value); - ("GPR2", initial_GPR2_TOC); - (* - ("GPR3", initial_GPR3_argc); - ("GPR4", initial_GPR4_argv); - ("GPR5", initial_GPR5_envp); - ("FPSCR", initial_FPSCR); - *) - ] in - - (initial_stack_data, initial_register_abi_data) - - -let aarch64_reg bit_count name = (name, (D_decreasing, bit_count, bit_count - 1)) - -let aarch64_PC_data = [aarch64_reg 64 "_PC"] - -(* most of the PSTATE fields are aliases to other registers so they - don't appear here *) -let aarch64_PSTATE_data = [ - aarch64_reg 1 "PSTATE_nRW"; - aarch64_reg 1 "PSTATE_E"; - aarch64_reg 5 "PSTATE_M"; -] - -let aarch64_general_purpose_registers_data = [ - aarch64_reg 64 "R0"; - aarch64_reg 64 "R1"; - aarch64_reg 64 "R2"; - aarch64_reg 64 "R3"; - aarch64_reg 64 "R4"; - aarch64_reg 64 "R5"; - aarch64_reg 64 "R6"; - aarch64_reg 64 "R7"; - aarch64_reg 64 "R8"; - aarch64_reg 64 "R9"; - aarch64_reg 64 "R10"; - aarch64_reg 64 "R11"; - aarch64_reg 64 "R12"; - aarch64_reg 64 "R13"; - aarch64_reg 64 "R14"; - aarch64_reg 64 "R15"; - aarch64_reg 64 "R16"; - aarch64_reg 64 "R17"; - aarch64_reg 64 "R18"; - aarch64_reg 64 "R19"; - aarch64_reg 64 "R20"; - aarch64_reg 64 "R21"; - aarch64_reg 64 "R22"; - aarch64_reg 64 "R23"; - aarch64_reg 64 "R24"; - aarch64_reg 64 "R25"; - aarch64_reg 64 "R26"; - aarch64_reg 64 "R27"; - aarch64_reg 64 "R28"; - aarch64_reg 64 "R29"; - aarch64_reg 64 "R30"; -] - -let aarch64_SIMD_registers_data = [ - aarch64_reg 128 "V0"; - aarch64_reg 128 "V1"; - aarch64_reg 128 "V2"; - aarch64_reg 128 "V3"; - aarch64_reg 128 "V4"; - aarch64_reg 128 "V5"; - aarch64_reg 128 "V6"; - aarch64_reg 128 "V7"; - aarch64_reg 128 "V8"; - aarch64_reg 128 "V9"; - aarch64_reg 128 "V10"; - aarch64_reg 128 "V11"; - aarch64_reg 128 "V12"; - aarch64_reg 128 "V13"; - aarch64_reg 128 "V14"; - aarch64_reg 128 "V15"; - aarch64_reg 128 "V16"; - aarch64_reg 128 "V17"; - aarch64_reg 128 "V18"; - aarch64_reg 128 "V19"; - aarch64_reg 128 "V20"; - aarch64_reg 128 "V21"; - aarch64_reg 128 "V22"; - aarch64_reg 128 "V23"; - aarch64_reg 128 "V24"; - aarch64_reg 128 "V25"; - aarch64_reg 128 "V26"; - aarch64_reg 128 "V27"; - aarch64_reg 128 "V28"; - aarch64_reg 128 "V29"; - aarch64_reg 128 "V30"; - aarch64_reg 128 "V31"; -] - -let aarch64_special_purpose_registers_data = [ - aarch64_reg 32 "CurrentEL"; - aarch64_reg 32 "DAIF"; - aarch64_reg 32 "NZCV"; - aarch64_reg 64 "SP_EL0"; - aarch64_reg 64 "SP_EL1"; - aarch64_reg 64 "SP_EL2"; - aarch64_reg 64 "SP_EL3"; - aarch64_reg 32 "SPSel"; - aarch64_reg 32 "SPSR_EL1"; - aarch64_reg 32 "SPSR_EL2"; - aarch64_reg 32 "SPSR_EL3"; - aarch64_reg 64 "ELR_EL1"; - aarch64_reg 64 "ELR_EL2"; - aarch64_reg 64 "ELR_EL3"; -] - -let aarch64_general_system_control_registers_data = [ - aarch64_reg 64 "HCR_EL2"; - aarch64_reg 64 "ID_AA64MMFR0_EL1"; - aarch64_reg 64 "RVBAR_EL1"; - aarch64_reg 64 "RVBAR_EL2"; - aarch64_reg 64 "RVBAR_EL3"; - aarch64_reg 32 "SCR_EL3"; - aarch64_reg 32 "SCTLR_EL1"; - aarch64_reg 32 "SCTLR_EL2"; - aarch64_reg 32 "SCTLR_EL3"; - aarch64_reg 64 "TCR_EL1"; - aarch64_reg 32 "TCR_EL2"; - aarch64_reg 32 "TCR_EL3"; -] - -let aarch64_debug_registers_data = [ - aarch64_reg 32 "DBGPRCR_EL1"; - aarch64_reg 32 "OSDLR_EL1"; -] - -let aarch64_performance_monitors_registers_data = [] -let aarch64_generic_timer_registers_data = [] -let aarch64_generic_interrupt_controller_CPU_interface_registers_data = [] - -let aarch64_external_debug_registers_data = [ - aarch64_reg 32 "EDSCR"; -] - -let aarch32_general_system_control_registers_data = [ - aarch64_reg 32 "SCR"; -] - -let aarch32_debug_registers_data = [ - aarch64_reg 32 "DBGOSDLR"; - aarch64_reg 32 "DBGPRCR"; -] - -let aarch64_register_data_all = - aarch64_PC_data @ - aarch64_PSTATE_data @ - aarch64_general_purpose_registers_data @ - aarch64_SIMD_registers_data @ - aarch64_special_purpose_registers_data @ - aarch64_general_system_control_registers_data @ - aarch64_debug_registers_data @ - aarch64_performance_monitors_registers_data @ - aarch64_generic_timer_registers_data @ - aarch64_generic_interrupt_controller_CPU_interface_registers_data @ - aarch64_external_debug_registers_data @ - aarch32_general_system_control_registers_data @ - aarch32_debug_registers_data - -let initial_stack_and_reg_data_of_AAarch64_elf_file e_entry all_data_memory = - let (reg_SP_EL0_direction, reg_SP_EL0_width, reg_SP_EL0_initial_index) = - List.assoc "SP_EL0" aarch64_register_data_all in - - (* we compiled a small program that prints out SP and run it a few - times on the Nexus9, these are the results: - 0x0000007fe7f903e0 - 0x0000007fdcdbf3f0 - 0x0000007fcbe1ba90 - 0x0000007fcf378280 - 0x0000007fdd54b8d0 - 0x0000007fd961bc10 - 0x0000007ff3be6350 - 0x0000007fd6bf6ef0 - 0x0000007fff7676f0 - 0x0000007ff2c34560 *) - let initial_SP_EL0 = Nat_big_num.of_string "549739036672" (*"0x0000007fff000000"*) in - let initial_SP_EL0_value = - Sail_impl_base.register_value_of_integer - reg_SP_EL0_width - reg_SP_EL0_initial_index - reg_SP_EL0_direction - initial_SP_EL0 - in - - (* ELF says we need an initial zero doubleword there *) - (* the code actually uses the stack, both above and below, so we map a bit more memory*) - let initial_stack_data = - (* this is a fairly big but arbitrary chunk: *) - (* let initial_stack_data_address = Nat_big_num.sub initial_GPR1_stack_pointer (Nat_big_num.of_int 128) in - [("initial_stack_data", initial_stack_data_address, Lem_list.replicate (128+32) 0 ))] in *) - - [ ("initial_stack_data1", Nat_big_num.sub initial_SP_EL0 (Nat_big_num.of_int 16), Lem_list.replicate 8 0); - ("initial_stack_data2", Nat_big_num.sub initial_SP_EL0 (Nat_big_num.of_int 8), Lem_list.replicate 8 0) - ] - in - - let initial_register_abi_data : (string * Sail_impl_base.register_value) list = - [("SP_EL0", initial_SP_EL0_value)] - in - - (initial_stack_data, initial_register_abi_data) -*) let mips_register_data_all = [ (*Pseudo registers*) ("PC", (D_decreasing, 64, 63)); ("branchPending", (D_decreasing, 1, 0)); ("inBranchDelay", (D_decreasing, 1, 0)); + ("inCCallDelay", (D_decreasing, 1, 0)); ("delayedPC", (D_decreasing, 64, 63)); ("nextPC", (D_decreasing, 64, 63)); (* General purpose registers *) @@ -665,7 +303,7 @@ let cheri_register_data_all = mips_register_data_all @ [ let initial_stack_and_reg_data_of_MIPS_elf_file e_entry all_data_memory = let initial_stack_data = [] in - let initial_cap_val_int = Nat_big_num.of_string "0x1fffe0000000800000000000000000000" in (* hex((0x80000 << 64) + (0x7fff << 113) + (1 << 128)) *) + let initial_cap_val_int = Nat_big_num.of_string "0x1fffe6000000100000000000000000000" in (* hex((0x10000 << 64) + (48 << 105) + (0x7fff << 113) + (1 << 128)) T=0x10000 E=48 perms=0x7fff tag=1 *) let initial_cap_val_reg = Sail_impl_base.register_value_of_integer 129 128 D_decreasing initial_cap_val_int in let initial_register_abi_data : (string * Sail_impl_base.register_value) list = [ ("CP0Status", Sail_impl_base.register_value_of_integer 32 31 D_decreasing (Nat_big_num.of_string "0x00400000")); @@ -748,50 +386,6 @@ let initial_system_state_of_elf_file name = let (isa_defs, isa_memory_access, isa_externs, isa_model, model_reg_d, startaddr, initial_stack_data, initial_register_abi_data, register_data_all) = match Nat_big_num.to_int e_machine with -(* | 21 (* EM_PPC64 *) -> - let startaddr = - let e_entry = Uint64.of_int64 (Nat_big_num.to_int64 e_entry) in - match Abi_power64.abi_power64_compute_program_entry_point segments e_entry with - | Error.Fail s -> failwith "Failed computing entry point" - | Error.Success s -> Nat_big_num.of_int64 (Uint64.to_int64 s) - in - let (initial_stack_data, initial_register_abi_data) = - initial_stack_and_reg_data_of_PPC_elf_file e_entry !data_mem in - - (Power.defs, - (Power_extras.read_memory_functions,Power_extras.memory_writes,[],[],Power_extras.barrier_functions), - Power_extras.power_externs, - PPC, - D_increasing, - startaddr, - initial_stack_data, - initial_register_abi_data, - ppc_register_data_all) - - | 183 (* EM_AARCH64 *) -> - let startaddr = - let e_entry = Uint64.of_int64 (Nat_big_num.to_int64 e_entry) in - match Abi_aarch64_le.abi_aarch64_le_compute_program_entry_point segments e_entry with - | Error.Fail s -> failwith "Failed computing entry point" - | Error.Success s -> Nat_big_num.of_int64 (Uint64.to_int64 s) - in - - let (initial_stack_data, initial_register_abi_data) = - initial_stack_and_reg_data_of_AAarch64_elf_file e_entry !data_mem in - - (ArmV8.defs, - (ArmV8_extras.aArch64_read_memory_functions, - ArmV8_extras.aArch64_memory_writes, - ArmV8_extras.aArch64_memory_eas, - ArmV8_extras.aArch64_memory_vals, - ArmV8_extras.aArch64_barrier_functions), - [], - AArch64, - D_decreasing, - startaddr, - initial_stack_data, - initial_register_abi_data, - aarch64_register_data_all) *) | 8 (* EM_MIPS *) -> let startaddr = let e_entry = Uint64.of_string (Nat_big_num.to_string e_entry) in @@ -887,52 +481,6 @@ let initial_system_state_of_elf_file name = List.map (fun (name, (binding, fp)) -> (fp, name)) (StringMap.bindings map) in - - (* Now we examine the rest of the data memory, - removing the footprint of the symbols and chunking it into aligned chunks *) - - let rec remove_symbols_from_data_memory data_mem symbols = - match symbols with - | [] -> data_mem - | (name,address,size,bs)::symbols' -> - let data_mem' = - Mem.filter - (fun a v -> - not (Nat_big_num.greater_equal a address && - Nat_big_num.less a (Nat_big_num.add (Nat_big_num.of_int (List.length bs)) address))) - data_mem in - remove_symbols_from_data_memory data_mem' symbols' in - - let trimmed_data_memory : (Nat_big_num.num * memory_byte) list = - Mem.bindings (remove_symbols_from_data_memory !data_mem symbol_table) in - - (* make sure that's ordered increasingly.... *) - let trimmed_data_memory = - List.sort (fun (a,b) (a',b') -> Nat_big_num.compare a a') trimmed_data_memory in - - let aligned a n = (* a mod n = 0 *) - let n_big = Nat_big_num.of_int n in - Nat_big_num.equal (Nat_big_num.modulus a n_big) ((Nat_big_num.of_int 0)) in - - let isplus a' a n = (* a' = a+n *) - Nat_big_num.equal a' (Nat_big_num.add (Nat_big_num.of_int n) a) in - - let rec chunk_data_memory dm = - match dm with - | (a0,b0)::(a1,b1)::(a2,b2)::(a3,b3)::(a4,b4)::(a5,b5)::(a6,b6)::(a7,b7)::dm' when - (aligned a0 8 && isplus a1 a0 1 && isplus a2 a0 2 && isplus a3 a0 3 && - isplus a4 a0 4 && isplus a5 a0 5 && isplus a6 a0 6 && isplus a7 a0 7) -> - (a0,8,[b0;b1;b2;b3;b4;b5;b6;b7]) :: chunk_data_memory dm' - | (a0,b0)::(a1,b1)::(a2,b2)::(a3,b3)::dm' when - (aligned a0 4 && isplus a1 a0 1 && isplus a2 a0 2 && isplus a3 a0 3) -> - (a0,4,[b0;b1;b2;b3]) :: chunk_data_memory dm' - | (a0,b0)::(a1,b1)::dm' when - (aligned a0 2 && isplus a1 a0 1) -> - (a0,2,[b0;b1]) :: chunk_data_memory dm' - | (a0,b0)::dm' -> - (a0,1,[b0]):: chunk_data_memory dm' - | [] -> [] in - let initial_register_state = fun rbn -> try @@ -1021,68 +569,10 @@ let stop_condition_met model instr = true | _ -> false) -let is_branch model instruction = - let (name,_,_) = instruction in - match (model , name) with - | (PPC, "B") -> true - | (PPC, "Bc") -> true - | (PPC, "Bclr") -> true - | (PPC, "Bcctr") -> true - | (PPC, _) -> false - | (AArch64, "BranchImmediate") -> true - | (AArch64, "BranchConditional") -> true - | (AArch64, "CompareAndBranch") -> true - | (AArch64, "TestBitAndBranch") -> true - | (AArch64, "BranchRegister") -> true - | (AArch64, _) -> false - | (MIPS, _) -> false (*todo,fill this in*) - let option_int_of_option_integer i = match i with | Some i -> Some (Nat_big_num.to_int i) | None -> None -let set_next_instruction_address model = - match model with - | PPC -> - let cia = Reg.find "CIA" !reg in - let cia_addr = address_of_register_value cia in - (match cia_addr with - | Some cia_addr -> - let nia_addr = add_address_nat cia_addr 4 in - let nia = register_value_of_address nia_addr Sail_impl_base.D_increasing in - reg := Reg.add "NIA" nia !reg - | _ -> failwith "CIA address contains unknown or undefined") - | AArch64 -> - let pc = Reg.find "_PC" !reg in - let pc_addr = address_of_register_value pc in - (match pc_addr with - | Some pc_addr -> - let n_addr = add_address_nat pc_addr 4 in - let n_pc = register_value_of_address n_addr D_decreasing in - reg := Reg.add "_PC" n_pc !reg - | _ -> failwith "_PC address contains unknown or undefined") - | MIPS -> - let pc_addr = address_of_register_value (Reg.find "PC" !reg) in - let branchPending = integer_of_register_value (Reg.find "branchPending" !reg) in - (match (pc_addr, option_int_of_option_integer branchPending) with - | (Some pc_val, Some 0) -> - (* normal -- increment PC *) - let n_addr = add_address_nat pc_val 4 in - let n_pc = register_value_of_address n_addr D_decreasing in - begin - reg := Reg.add "nextPC" n_pc !reg; - reg := Reg.add "inBranchDelay" (register_value_of_integer 1 0 Sail_impl_base.D_decreasing Nat_big_num.zero) !reg; - end - | (Some pc_val, Some 1) -> - (* delay slot -- branch to delayed PC and clear branchPending *) - begin - reg := Reg.add "nextPC" (Reg.find "delayedPC" !reg) !reg; - reg := Reg.add "nextPCC" (Reg.find "delayedPCC" !reg) !reg; - reg := Reg.add "branchPending" (register_value_of_integer 1 0 Sail_impl_base.D_decreasing Nat_big_num.zero) !reg; - reg := Reg.add "inBranchDelay" (register_value_of_integer 1 0 Sail_impl_base.D_decreasing (Nat_big_num.of_int 1)) !reg; - end - | (_, _) -> errorf "PC address contains unknown or undefined"; exit 1) - let add1 = Nat_big_num.add (Nat_big_num.of_int 1) let get_addr_trans_regs _ = @@ -1192,68 +682,10 @@ let rec write_events = function | _ -> failwith "Only register write events expected"); write_events events -let fetch_instruction_opcode_and_update_ia model addr_trans = - match model with - | PPC -> - let cia = Reg.find "CIA" !reg in - let cia_addr = address_of_register_value cia in - (match cia_addr with - | Some cia_addr -> - let cia_a = integer_of_address cia_addr in - let opcode = (get_opcode cia_a) in - begin - reg := Reg.add "CIA" (Reg.find "NIA" !reg) !reg; - Opcode opcode - end - | None -> failwith "CIA address contains unknown or undefined") - | AArch64 -> - let pc = Reg.find "_PC" !reg in - let pc_addr = address_of_register_value pc in - (match pc_addr with - | Some pc_addr -> - let pc_a = integer_of_address pc_addr in - let opcode = (get_opcode pc_a) in - Opcode opcode - | None -> failwith "_PC address contains unknown or undefined") - | MIPS -> - begin - reg := Reg.add "PCC" (Reg.find "nextPCC" !reg) !reg; - let nextPC = Reg.find "nextPC" !reg in - let pc_addr = address_of_register_value nextPC in - (*let unused = interactf "PC: %s\n" (Printing_functions.register_value_to_string nextPC) in*) - (match pc_addr with - | Some pc_addr -> - let pc_a = match addr_trans (get_addr_trans_regs ()) pc_addr with - | Some a, Some events -> write_events (List.rev events); integer_of_address a - | Some a, None -> integer_of_address a - | None, Some events -> - write_events (List.rev events); - let nextPC = Reg.find "nextPC" !reg in - reg := Reg.add "PCC" (Reg.find "nextPCC" !reg) !reg; - let pc_addr = address_of_register_value nextPC in - (match pc_addr with - | Some pc_addr -> - (match addr_trans (get_addr_trans_regs ()) pc_addr with - | Some a, Some events -> write_events (List.rev events); integer_of_address a - | Some a, None -> integer_of_address a - | None, _ -> failwith "Address translation failed twice") - | None -> failwith "no nextPc address") - | _ -> failwith "No address and no events from translate address" - in - let opcode = (get_opcode pc_a) in - begin - reg := Reg.add "PC" (Reg.find "nextPC" !reg) !reg; - Opcode opcode - end - | None -> errorf "nextPC contains unknown or undefined"; exit 1) - end - | _ -> assert false - let get_pc_address = function | MIPS -> Reg.find "PC" !reg | PPC -> Reg.find "CIA" !reg | AArch64 -> Reg.find "_PC" !reg - let option_int_of_reg str = option_int_of_option_integer (integer_of_register_value (Reg.find str !reg)) @@ -1283,6 +715,7 @@ let rec fde_loop count context model mode track_dependencies addr_trans = let npc_addr = add_address_nat pc_val 4 in let npc_reg = register_value_of_address npc_addr Sail_impl_base.D_decreasing in reg := Reg.add "nextPC" npc_reg !reg; + reg := Reg.add "inCCallDelay" (register_value_of_integer 1 0 Sail_impl_base.D_decreasing Nat_big_num.zero) !reg; | Some 1 -> reg := Reg.add "nextPC" (Reg.find "delayedPC" !reg) !reg; reg := Reg.add "nextPCC" (Reg.find "delayedPCC" !reg) !reg; @@ -1290,12 +723,14 @@ let rec fde_loop count context model mode track_dependencies addr_trans = let opcode = Opcode (get_opcode pc) in let (instruction,istate) = match Interp_inter_imp.decode_to_istate context None opcode with | Instr(instruction,istate) -> + let instruction = interp_value_to_instr_external context instruction in interactf "\n**** Running: %s ****\n" (Printing_functions.instruction_to_string instruction); (instruction,istate) | Decode_error d -> (match d with - | Interp_interface.Unsupported_instruction_error instr -> - errorf "\n**** Encountered unsupported instruction %s ****\n" (Printing_functions.instruction_to_string instr) + | Interp_interface.Unsupported_instruction_error instruction -> + let instruction = interp_value_to_instr_external context instruction in + errorf "\n**** Encountered unsupported instruction %s ****\n" (Printing_functions.instruction_to_string instruction) | Interp_interface.Not_an_instruction_error op -> (match op with | Opcode bytes -> diff --git a/src/lem_interp/sail_impl_base.lem b/src/lem_interp/sail_impl_base.lem index eb2e1a4e..59e86ece 100644 --- a/src/lem_interp/sail_impl_base.lem +++ b/src/lem_interp/sail_impl_base.lem @@ -42,6 +42,29 @@ open import Pervasives_extra + + +class ( EnumerationType 'a ) + val toNat : 'a -> nat +end + + +val enumeration_typeCompare : forall 'a. EnumerationType 'a => 'a -> 'a -> ordering +let ~{ocaml} enumeration_typeCompare e1 e2 = + compare (toNat e1) (toNat e2) +let inline {ocaml} enumeration_typeCompare = defaultCompare + + +default_instance forall 'a. EnumerationType 'a => (Ord 'a) + let compare = enumeration_typeCompare + let (<) r1 r2 = (enumeration_typeCompare r1 r2) = LT + let (<=) r1 r2 = (enumeration_typeCompare r1 r2) <> GT + let (>) r1 r2 = (enumeration_typeCompare r1 r2) = GT + let (>=) r1 r2 = (enumeration_typeCompare r1 r2) <> LT +end + + + (* maybe isn't a member of type Ord - this should be in the Lem standard library*) instance forall 'a. Ord 'a => (Ord (maybe 'a)) let compare = maybeCompare compare @@ -214,6 +237,28 @@ instance (Ord byte) let (>=) = byteGreaterEq end +let ~{ocaml} opcodeCompare (Opcode o1) (Opcode o2) = + compare o1 o2 +let {ocaml} opcodeCompare = defaultCompare + +let ~{ocaml} opcodeLess b1 b2 = opcodeCompare b1 b2 = LT +let ~{ocaml} opcodeLessEq b1 b2 = opcodeCompare b1 b2 <> GT +let ~{ocaml} opcodeGreater b1 b2 = opcodeCompare b1 b2 = GT +let ~{ocaml} opcodeGreaterEq b1 b2 = opcodeCompare b1 b2 <> LT + +let inline {ocaml} opcodeLess = defaultLess +let inline {ocaml} opcodeLessEq = defaultLessEq +let inline {ocaml} opcodeGreater = defaultGreater +let inline {ocaml} opcodeGreaterEq = defaultGreaterEq + +instance (Ord opcode) + let compare = opcodeCompare + let (<) = opcodeLess + let (<=) = opcodeLessEq + let (>) = opcodeGreater + let (>=) = opcodeGreaterEq +end + let addressCompare (Address b1 i1) (Address b2 i2) = compare i1 i2 (* this cannot be defaultCompare for OCaml because addresses contain big ints *) @@ -419,6 +464,8 @@ end (* Data structures for building up instructions *) +(* careful: changes in the read/write/barrier kinds have to be + reflected in deep_shallow_convert *) type read_kind = (* common reads *) | Read_plain @@ -426,6 +473,12 @@ type read_kind = | Read_reserve (* AArch64 reads *) | Read_acquire | Read_exclusive | Read_exclusive_acquire | Read_stream + (* RISC-V reads *) + | Read_RISCV_acquire | Read_RISCV_strong_acquire + | Read_RISCV_reserved | Read_RISCV_reserved_acquire + | Read_RISCV_reserved_strong_acquire + (* x86 reads *) + | Read_X86_locked (* the read part of a lock'd instruction (rmw) *) instance (Show read_kind) let show = function @@ -435,6 +488,12 @@ instance (Show read_kind) | Read_exclusive -> "Read_exclusive" | Read_exclusive_acquire -> "Read_exclusive_acquire" | Read_stream -> "Read_stream" + | Read_RISCV_acquire -> "Read_RISCV_acquire" + | Read_RISCV_strong_acquire -> "Read_RISCV_strong_acquire" + | Read_RISCV_reserved -> "Read_RISCV_reserved" + | Read_RISCV_reserved_acquire -> "Read_RISCV_reserved_acquire" + | Read_RISCV_reserved_strong_acquire -> "Read_RISCV_reserved_strong_acquire" + | Read_X86_locked -> "Read_X86_locked" end end @@ -445,6 +504,12 @@ type write_kind = | Write_conditional (* AArch64 writes *) | Write_release | Write_exclusive | Write_exclusive_release + (* RISC-V *) + | Write_RISCV_release | Write_RISCV_strong_release + | Write_RISCV_conditional | Write_RISCV_conditional_release + | Write_RISCV_conditional_strong_release + (* x86 writes *) + | Write_X86_locked (* the write part of a lock'd instruction (rmw) *) instance (Show write_kind) let show = function @@ -453,6 +518,12 @@ instance (Show write_kind) | Write_release -> "Write_release" | Write_exclusive -> "Write_exclusive" | Write_exclusive_release -> "Write_exclusive_release" + | Write_RISCV_release -> "Write_RISCV_release" + | Write_RISCV_strong_release -> "Write_RISCV_strong_release" + | Write_RISCV_conditional -> "Write_RISCV_conditional" + | Write_RISCV_conditional_release -> "Write_RISCV_conditional_release" + | Write_RISCV_conditional_strong_release -> "Write_RISCV_conditional_strong_release" + | Write_X86_locked -> "Write_X86_locked" end end @@ -468,7 +539,12 @@ type barrier_kind = (* RISC-V barriers *) | Barrier_RISCV_rw_rw | Barrier_RISCV_r_rw + | Barrier_RISCV_r_r | Barrier_RISCV_rw_w + | Barrier_RISCV_w_w + | Barrier_RISCV_i + (* X86 *) + | Barrier_x86_MFENCE instance (Show barrier_kind) @@ -486,6 +562,13 @@ instance (Show barrier_kind) | Barrier_ISB -> "Barrier_ISB" | Barrier_TM_COMMIT -> "Barrier_TM_COMMIT" | Barrier_MIPS_SYNC -> "Barrier_MIPS_SYNC" + | Barrier_RISCV_rw_rw -> "Barrier_RISCV_rw_rw" + | Barrier_RISCV_r_rw -> "Barrier_RISCV_r_rw" + | Barrier_RISCV_r_r -> "Barrier_RISCV_r_r" + | Barrier_RISCV_rw_w -> "Barrier_RISCV_rw_w" + | Barrier_RISCV_w_w -> "Barrier_RISCV_w_w" + | Barrier_RISCV_i -> "Barrier_RISCV_i" + | Barrier_x86_MFENCE -> "Barrier_x86_MFENCE" end end @@ -502,15 +585,15 @@ instance (Show trans_kind) end type instruction_kind = - | IK_barrier of barrier_kind - | IK_mem_read of read_kind + | IK_barrier of barrier_kind + | IK_mem_read of read_kind | IK_mem_write of write_kind -(* SS reinstating cond_branches -at present branches are not distinguished in the instruction_kind; -they just have particular nias (and will be IK_simple *) - | IK_cond_branch -(* | IK_uncond_branch *) - | IK_trans of trans_kind + | IK_mem_rmw of (read_kind * write_kind) + | IK_cond_branch + (* unconditional branches are not distinguished in the instruction_kind; + they just have particular nias (and will be IK_simple *) + (* | IK_uncond_branch *) + | IK_trans of trans_kind | IK_simple @@ -658,6 +741,13 @@ let ~{ocaml} barrier_number = function | Barrier_ISB -> 10 | Barrier_TM_COMMIT -> 11 | Barrier_MIPS_SYNC -> 12 + | Barrier_RISCV_rw_rw -> 13 + | Barrier_RISCV_r_rw -> 14 + | Barrier_RISCV_r_r -> 15 + | Barrier_RISCV_rw_w -> 16 + | Barrier_RISCV_w_w -> 17 + | Barrier_RISCV_i -> 18 + | Barrier_x86_MFENCE -> 19 end let ~{ocaml} barrier_kindCompare bk1 bk2 = @@ -743,21 +833,20 @@ instance (Ord barrier_kind) let (>=) = barrier_kindGreaterEq end - type event = -| E_read_mem of read_kind * address_lifted * nat * maybe (list reg_name) -| E_read_memt of read_kind * address_lifted * nat * maybe (list reg_name) -| E_write_mem of write_kind * address_lifted * nat * maybe (list reg_name) * memory_value * maybe (list reg_name) -| E_write_ea of write_kind * address_lifted * nat * maybe (list reg_name) -| E_excl_res -| E_write_memv of maybe address_lifted * memory_value * maybe (list reg_name) -| E_write_memvt of maybe address_lifted * (bit_lifted * memory_value) * maybe (list reg_name) -| E_barrier of barrier_kind -| E_footprint -| E_read_reg of reg_name -| E_write_reg of reg_name * register_value -| E_escape -| E_error of string + | E_read_mem of read_kind * address_lifted * nat * maybe (list reg_name) + | E_read_memt of read_kind * address_lifted * nat * maybe (list reg_name) + | E_write_mem of write_kind * address_lifted * nat * maybe (list reg_name) * memory_value * maybe (list reg_name) + | E_write_ea of write_kind * address_lifted * nat * maybe (list reg_name) + | E_excl_res + | E_write_memv of maybe address_lifted * memory_value * maybe (list reg_name) + | E_write_memvt of maybe address_lifted * (bit_lifted * memory_value) * maybe (list reg_name) + | E_barrier of barrier_kind + | E_footprint + | E_read_reg of reg_name + | E_write_reg of reg_name * register_value + | E_escape + | E_error of string let eventCompare e1 e2 = diff --git a/src/pretty_print_lem.ml b/src/pretty_print_lem.ml index 2855adbc..ef91c684 100644 --- a/src/pretty_print_lem.ml +++ b/src/pretty_print_lem.ml @@ -1294,9 +1294,9 @@ let doc_typdef_lem sequential mwords (TD_aux(td, (l, annot))) = match td with (concat [string "type"; space; doc_id_lem_type id; space; doc_typquant_items_lem None typq]) ((*doc_typquant_lem typq*) ar_doc) in let make_id pat id = - separate space [string "SIA.Id_aux"; - parens (string "SIA.Id " ^^ string_lit (doc_id id)); - if pat then underscore else string "SIA.Unknown"] in + separate space [string "Interp_ast.Id_aux"; + parens (string "Interp_ast.Id " ^^ string_lit (doc_id id)); + if pat then underscore else string "Interp_ast.Unknown"] in let fromInterpValueF = concat [doc_id_lem_type id;string "FromInterpValue"] in let toInterpValueF = concat [doc_id_lem_type id;string "ToInterpValue"] in let fromInterpValuePP = @@ -1308,18 +1308,18 @@ let doc_typdef_lem sequential mwords (TD_aux(td, (l, annot))) = match td with match tu with | Tu_ty_id (ty,cid) -> (separate space) - [pipe;string "SI.V_ctor";parens (make_id true cid);underscore;underscore;string "v"; + [pipe;string "Interp_ast.V_ctor";parens (make_id true cid);underscore;underscore;string "v"; arrow; doc_id_lem_ctor cid; parens (string "fromInterpValue v")] | Tu_id cid -> (separate space) - [pipe;string "SI.V_ctor";parens (make_id true cid);underscore;underscore;string "v"; + [pipe;string "Interp_ast.V_ctor";parens (make_id true cid);underscore;underscore;string "v"; arrow; doc_id_lem_ctor cid]) ar) ^/^ - ((separate space) [pipe;string "SI.V_tuple [v]";arrow;fromInterpValueF;string "v"]) ^/^ + ((separate space) [pipe;string "Interp_ast.V_tuple [v]";arrow;fromInterpValueF;string "v"]) ^/^ let failmessage = (string_lit @@ -1338,43 +1338,40 @@ let doc_typdef_lem sequential mwords (TD_aux(td, (l, annot))) = match td with | Tu_ty_id (ty,cid) -> (separate space) [pipe;doc_id_lem_ctor cid;string "v";arrow; - string "SI.V_ctor"; + string "Interp_ast.V_ctor"; parens (make_id false cid); - parens (string "SIA.T_id " ^^ string_lit (doc_id id)); - string "SI.C_Union"; + parens (string "Interp_ast.T_id " ^^ string_lit (doc_id id)); + string "Interp_ast.C_Union"; parens (string "toInterpValue v")] | Tu_id cid -> (separate space) [pipe;doc_id_lem_ctor cid;arrow; - string "SI.V_ctor"; + string "Interp_ast.V_ctor"; parens (make_id false cid); - parens (string "SIA.T_id " ^^ string_lit (doc_id id)); - string "SI.C_Union"; + parens (string "Interp_ast.T_id " ^^ string_lit (doc_id id)); + string "Interp_ast.C_Union"; parens (string "toInterpValue ()")]) ar) ^/^ string "end") in let fromToInterpValuePP = + toInterpValuePP ^^ hardline ^^ hardline ^^ + fromInterpValuePP ^^ hardline ^^ hardline ^^ ((prefix 2 1) (concat [string "instance ";parens (string "ToFromInterpValue " ^^ doc_id_lem_type id)]) (concat [string "let toInterpValue = ";toInterpValueF;hardline; string "let fromInterpValue = ";fromInterpValueF])) ^/^ string "end" in - typ_pp ^^ hardline ^^ hardline ^^ - if !print_to_from_interp_value then - toInterpValuePP ^^ hardline ^^ hardline ^^ - fromInterpValuePP ^^ hardline ^^ hardline ^^ - fromToInterpValuePP ^^ hardline - else empty) + (typ_pp ^^ hardline,fromToInterpValuePP ^^ hardline)) | TD_enum(id,nm,enums,_) -> (match id with - | Id_aux ((Id "read_kind"),_) -> empty - | Id_aux ((Id "write_kind"),_) -> empty - | Id_aux ((Id "barrier_kind"),_) -> empty - | Id_aux ((Id "trans_kind"),_) -> empty - | Id_aux ((Id "instruction_kind"),_) -> empty - | Id_aux ((Id "regfp"),_) -> empty - | Id_aux ((Id "niafp"),_) -> empty - | Id_aux ((Id "diafp"),_) -> empty + | Id_aux ((Id "read_kind"),_) -> (empty,empty) + | Id_aux ((Id "write_kind"),_) -> (empty,empty) + | Id_aux ((Id "barrier_kind"),_) -> (empty,empty) + | Id_aux ((Id "trans_kind"),_) -> (empty,empty) + | Id_aux ((Id "instruction_kind"),_) -> (empty,empty) + | Id_aux ((Id "regfp"),_) -> (empty,empty) + | Id_aux ((Id "niafp"),_) -> (empty,empty) + | Id_aux ((Id "diafp"),_) -> (empty,empty) | _ -> let rec range i j = if i > j then [] else i :: (range (i+1) j) in let nats = range 0 in @@ -1385,9 +1382,9 @@ let doc_typdef_lem sequential mwords (TD_aux(td, (l, annot))) = match td with let fromInterpValueF = concat [doc_id_lem_type id;string "FromInterpValue"] in let toInterpValueF = concat [doc_id_lem_type id;string "ToInterpValue"] in let make_id pat id = - separate space [string "SIA.Id_aux"; - parens (string "SIA.Id " ^^ string_lit (doc_id id)); - if pat then underscore else string "SIA.Unknown"] in + separate space [string "Interp_ast.Id_aux"; + parens (string "Interp_ast.Id " ^^ string_lit (doc_id id)); + if pat then underscore else string "Interp_ast.Unknown"] in let fromInterpValuePP = (prefix 2 1) (separate space [string "let rec";fromInterpValueF;string "v";equals;string "match v with"]) @@ -1395,7 +1392,7 @@ let doc_typdef_lem sequential mwords (TD_aux(td, (l, annot))) = match td with ((separate_map (break 1)) (fun (cid) -> (separate space) - [pipe;string "SI.V_ctor";parens (make_id true cid);underscore;underscore;string "v"; + [pipe;string "Interp_ast.V_ctor";parens (make_id true cid);underscore;underscore;string "v"; arrow;doc_id_lem_ctor cid] ) enums @@ -1403,7 +1400,7 @@ let doc_typdef_lem sequential mwords (TD_aux(td, (l, annot))) = match td with ( (align ((prefix 3 1) - (separate space [pipe;string ("SI.V_lit (SIA.L_aux (SIA.L_num n) _)");arrow]) + (separate space [pipe;string ("Interp_ast.V_lit (Interp_ast.L_aux (Interp_ast.L_num n) _)");arrow]) (separate space [string "match";parens(string "natFromInteger n");string "with"] ^/^ ( ((separate_map (break 1)) @@ -1419,7 +1416,7 @@ let doc_typdef_lem sequential mwords (TD_aux(td, (l, annot))) = match td with ) ) ^/^ - ((separate space) [pipe;string "SI.V_tuple [v]";arrow;fromInterpValueF;string "v"]) ^/^ + ((separate space) [pipe;string "Interp_ast.V_tuple [v]";arrow;fromInterpValueF;string "v"]) ^/^ let failmessage = (string_lit @@ -1437,27 +1434,25 @@ let doc_typdef_lem sequential mwords (TD_aux(td, (l, annot))) = match td with (fun (cid,number) -> (separate space) [pipe;doc_id_lem_ctor cid;arrow; - string "SI.V_ctor"; + string "Interp_ast.V_ctor"; parens (make_id false cid); - parens (string "SIA.T_id " ^^ string_lit (doc_id id)); - parens (string ("SI.C_Enum " ^ string_of_int number)); + parens (string "Interp_ast.T_id " ^^ string_lit (doc_id id)); + parens (string ("Interp_ast.C_Enum " ^ string_of_int number)); parens (string "toInterpValue ()")]) (List.combine enums (nats ((List.length enums) - 1)))) ^/^ string "end") in let fromToInterpValuePP = + toInterpValuePP ^^ hardline ^^ hardline ^^ + fromInterpValuePP ^^ hardline ^^ hardline ^^ ((prefix 2 1) (concat [string "instance ";parens (string "ToFromInterpValue " ^^ doc_id_lem_type id)]) (concat [string "let toInterpValue = ";toInterpValueF;hardline; string "let fromInterpValue = ";fromInterpValueF])) ^/^ string "end" in - typ_pp ^^ hardline ^^ hardline ^^ - if !print_to_from_interp_value - then toInterpValuePP ^^ hardline ^^ hardline ^^ - fromInterpValuePP ^^ hardline ^^ hardline ^^ - fromToInterpValuePP ^^ hardline - else empty) + (typ_pp ^^ hardline, + fromToInterpValuePP ^^ hardline)) | TD_register(id,n1,n2,rs) -> - match n1, n2 with + match n1,n2 with | Nexp_aux(Nexp_constant i1,_),Nexp_aux(Nexp_constant i2,_) -> let dir_b = i1 < i2 in let dir = (if dir_b then "true" else "false") in diff --git a/x86/Makefile b/x86/Makefile new file mode 100644 index 00000000..2bc4c1a4 --- /dev/null +++ b/x86/Makefile @@ -0,0 +1,3 @@ +all: + ../src/sail.native -o x86 -lem -lem_lib X86_extras_embed ../etc/regfp.sail x64.sail + ../src/sail.native -o x86 -lem_ast ../etc/regfp.sail x64.sail diff --git a/x86/x64.sail b/x86/x64.sail index 3b25802f..9fa0b838 100644 --- a/x86/x64.sail +++ b/x86/x64.sail @@ -32,14 +32,26 @@ default Order dec val extern forall Type 'a. ('a, list<'a>) -> bool effect pure ismember val extern forall Type 'a. list<'a> -> nat effect pure listlength -val extern forall Nat 'n. (bit['n],[|'n|]) -> bit['n] effect pure ASR -val extern forall Nat 'n. (bit['n],[|'n|]) -> bit['n] effect pure LSR -val extern forall Nat 'n. (bit['n],[|'n|]) -> bit['n] effect pure ROR -val extern forall Nat 'n. (bit['n],[|'n|]) -> bit['n] effect pure ROL -val cast bool -> bit effect pure cast_bool_bit -val cast bit -> int effect pure cast_bit_int -val extern forall Num 'n. int -> bit['n] effect pure cast_int_vec -val extern forall 'n, 'm, 'o, 'n <= 0, 'm <= 'o. [|'n:'m|] -> [|0:'o|] effect pure negative_to_zero + +function (bit[8 ]) ASR8 ((bit[8 ]) v, ([|8 |]) shift) = let v2 = ((bit[16 ]) (EXTS(v))) in (bit[8 ]) (mask(v2 >> shift)) +function (bit[16]) ASR16 ((bit[16]) v, ([|16|]) shift) = let v2 = ((bit[32 ]) (EXTS(v))) in (bit[16]) (mask(v2 >> shift)) +function (bit[32]) ASR32 ((bit[32]) v, ([|32|]) shift) = let v2 = ((bit[64 ]) (EXTS(v))) in (bit[32]) (mask(v2 >> shift)) +function (bit[64]) ASR64 ((bit[64]) v, ([|64|]) shift) = let v2 = ((bit[128]) (EXTS(v))) in (bit[64]) (mask(v2 >> shift)) + +function (bit[8 ]) ROR8 ((bit[8 ]) v, ([|8 |]) shift) = let v2 = ((bit[16 ]) (v:v)) in (bit[8 ]) (mask(v2 >> shift)) +function (bit[16]) ROR16 ((bit[16]) v, ([|16|]) shift) = let v2 = ((bit[32 ]) (v:v)) in (bit[16]) (mask(v2 >> shift)) +function (bit[32]) ROR32 ((bit[32]) v, ([|32|]) shift) = let v2 = ((bit[64 ]) (v:v)) in (bit[32]) (mask(v2 >> shift)) +function (bit[64]) ROR64 ((bit[64]) v, ([|64|]) shift) = let v2 = ((bit[128]) (v:v)) in (bit[64]) (mask(v2 >> shift)) + +function (bit[8 ]) ROL8 ((bit[8 ]) v, ([|8 |]) shift) = let v2 = ((bit[16 ]) (v:v)) in (bit[8 ]) (mask(v2 << shift)) +function (bit[16]) ROL16 ((bit[16]) v, ([|16|]) shift) = let v2 = ((bit[32 ]) (v:v)) in (bit[16]) (mask(v2 << shift)) +function (bit[32]) ROL32 ((bit[32]) v, ([|32|]) shift) = let v2 = ((bit[64 ]) (v:v)) in (bit[32]) (mask(v2 << shift)) +function (bit[64]) ROL64 ((bit[64]) v, ([|64|]) shift) = let v2 = ((bit[128]) (v:v)) in (bit[64]) (mask(v2 << shift)) + +(*val cast bool -> bit effect pure cast_bool_bit +val cast bit -> int effect pure cast_bit_int *) +function forall Nat 'n, Nat 'm, Nat 'o, 'n <= 0, 'm <= 'o. ([|0:'o|]) negative_to_zero (([|'n:'m|]) x) = + if x < 0 then 0 else x typedef byte = bit[8] typedef qword = bit[64] @@ -79,20 +91,31 @@ let (vector<0,16,inc,(register<qword>)>) REG = (* Flags *) -register bit CF -register bit PF -register bit AF -register bit ZF -register bit SF -register bit OF +register bit[1] CF +register bit[1] PF +register bit[1] AF +register bit[1] ZF +register bit[1] SF +register bit[1] OF (* -------------------------------------------------------------------------- Memory -------------------------------------------------------------------------- *) -val extern forall Nat 'n. (qword, [|'n|]) -> (bit[8 * 'n]) effect { rmem } MEM +val extern forall Nat 'n. (qword, [|'n|]) -> (bit[8 * 'n]) effect { rmem } rMEM +val extern forall Nat 'n. (qword, [|'n|]) -> (bit[8 * 'n]) effect { rmem } rMEM_locked +function forall Nat 'n. (bit[8 * 'n]) effect { rmem } rMEMl ((bool) locked, (qword) addr, ([|'n|]) size) = + if locked then rMEM_locked(addr, size) else rMEM(addr, size) + +val extern forall Nat 'n. ( bit[64] , [|'n|]) -> unit effect { eamem } MEMea +val extern forall Nat 'n. ( bit[64] , [|'n|]) -> unit effect { eamem } MEMea_locked +val extern forall Nat 'n. ( bit[64] , [|'n|] , bit[8*'n]) -> unit effect { wmv } MEMval +val extern unit -> unit effect { barr } X86_MFENCE -val extern forall Nat 'n. (qword, [|'n|], bit[8 * 'n]) -> unit effect { wmem } wMEM +function forall Nat 'n. unit effect {eamem, wmv} wMEM ((bool) locked, (qword) addr, ([|'n|]) len, (bit[8 * 'n]) data) = { + if locked then MEMea_locked(addr, len) else MEMea(addr, len); + MEMval(addr, len, data); +} (* -------------------------------------------------------------------------- Helper functions @@ -100,13 +123,21 @@ val extern forall Nat 'n. (qword, [|'n|], bit[8 * 'n]) -> unit effect { wmem } w (* Instruction addressing modes *) -typedef size = const union { +typedef wsize = const union { bool Sz8; unit Sz16; unit Sz32; unit Sz64; } +function ([|8:64|]) size_to_int((wsize) s) = + switch(s) { + case (Sz8(_)) -> 8 + case Sz16 -> 16 + case Sz32 -> 32 + case Sz64 -> 64 + } + typedef base = const union { unit NoBase; unit RipBase; @@ -116,7 +147,7 @@ typedef base = const union { typedef scale_index = (bit[2],regn) typedef rm = const union { - regn Reg; + regn X86_Reg; (option<scale_index>,base,qword) Mem; } @@ -131,64 +162,73 @@ typedef imm_rm = const union { qword Imm; } -typedef monop_name = enumerate { Dec; Inc; Not; Neg } +typedef bit_offset = const union { + (rm, qword) Bit_rm_imm; + (rm, regn) Bit_rm_r; +} + +typedef monop_name = enumerate { X86_Dec; X86_Inc; X86_Not; X86_Neg } typedef binop_name = enumerate { - Add; Or; Adc; Sbb; And; Sub; Xor; Cmp; Rol; Ror; Rcl; Rcr; Shl; Shr; Test; Sar + X86_Add; X86_Or; X86_Adc; X86_Sbb; X86_And; X86_Sub; X86_Xor; X86_Cmp; + X86_Rol; X86_Ror; X86_Rcl; X86_Rcr; X86_Shl; X86_Shr; X86_Test; X86_Sar; } +typedef bitop_name = enumerate { Bts; Btc; Btr } + function binop_name opc_to_binop_name ((bit[4]) opc) = switch opc { - case 0x0 -> Add - case 0x1 -> Or - case 0x2 -> Adc - case 0x3 -> Sbb - case 0x4 -> And - case 0x5 -> Sub - case 0x6 -> Xor - case 0x7 -> Cmp - case 0x8 -> Rol - case 0x9 -> Ror - case 0xa -> Rcl - case 0xb -> Rcr - case 0xc -> Shl - case 0xd -> Shr - case 0xe -> Test - case 0xf -> Sar + case 0x0 -> X86_Add + case 0x1 -> X86_Or + case 0x2 -> X86_Adc + case 0x3 -> X86_Sbb + case 0x4 -> X86_And + case 0x5 -> X86_Sub + case 0x6 -> X86_Xor + case 0x7 -> X86_Cmp + case 0x8 -> X86_Rol + case 0x9 -> X86_Ror + case 0xa -> X86_Rcl + case 0xb -> X86_Rcr + case 0xc -> X86_Shl + case 0xd -> X86_Shr + case 0xe -> X86_Test + case 0xf -> X86_Sar } typedef cond = enumerate { - O; NO; B; NB; E; NE; NA; A; S; NS; P; NP; L; NL; NG; G; ALWAYS + X86_O; X86_NO; X86_B; X86_NB; X86_E; X86_NE; X86_NA; X86_A; X86_S; + X86_NS; X86_P; X86_NP; X86_L; X86_NL; X86_NG; X86_G; X86_ALWAYS; } function cond bv_to_cond ((bit[4]) v) = switch v { - case 0x0 -> O - case 0x1 -> NO - case 0x2 -> B - case 0x3 -> NB - case 0x4 -> E - case 0x5 -> NE - case 0x6 -> NA - case 0x7 -> A - case 0x8 -> S - case 0x9 -> NS - case 0xa -> P - case 0xb -> NP - case 0xc -> L - case 0xd -> NL - case 0xe -> NG - case 0xf -> G + case 0x0 -> X86_O + case 0x1 -> X86_NO + case 0x2 -> X86_B + case 0x3 -> X86_NB + case 0x4 -> X86_E + case 0x5 -> X86_NE + case 0x6 -> X86_NA + case 0x7 -> X86_A + case 0x8 -> X86_S + case 0x9 -> X86_NS + case 0xa -> X86_P + case 0xb -> X86_NP + case 0xc -> X86_L + case 0xd -> X86_NL + case 0xe -> X86_NG + case 0xf -> X86_G } (* Effective addresses *) typedef ea = const union { - (size,qword) Ea_i; - (size,regn) Ea_r; - (size,qword) Ea_m; + (wsize,qword) Ea_i; + (wsize,regn) Ea_r; + (wsize,qword) Ea_m; } function qword ea_index ((option<scale_index>) index) = @@ -208,20 +248,20 @@ function qword ea_base ((base) b) = case (RegBase(b)) -> REG[b] } -function ea ea_rm ((size) sz, (rm) r) = +function ea ea_rm ((wsize) sz, (rm) r) = switch r { - case (Reg(n)) -> Ea_r (sz, n) + case (X86_Reg(n)) -> Ea_r (sz, n) case (Mem(idx, b, d)) -> Ea_m (sz, ea_index(idx) + (qword) (ea_base(b) + d)) } -function ea ea_dest ((size) sz, (dest_src) ds) = +function ea ea_dest ((wsize) sz, (dest_src) ds) = switch ds { case (Rm_i (v, _)) -> ea_rm (sz, v) case (Rm_r (v, _)) -> ea_rm (sz, v) case (R_rm (v, _)) -> Ea_r (sz, v) } -function ea ea_src ((size) sz, (dest_src) ds) = +function ea ea_src ((wsize) sz, (dest_src) ds) = switch ds { case (Rm_i (_, v)) -> Ea_i (sz, v) case (Rm_r (_, v)) -> Ea_r (sz, v) @@ -234,7 +274,7 @@ function ea ea_imm_rm ((imm_rm) i_rm) = case (Imm (v)) -> Ea_i (Sz64, v) } -function qword restrict_size ((size) sz, (qword) imm) = +function qword restrict_size ((wsize) sz, (qword) imm) = switch sz { case (Sz8(_)) -> imm & 0x00000000000000FF case Sz16 -> imm & 0x000000000000FFFF @@ -244,7 +284,7 @@ function qword restrict_size ((size) sz, (qword) imm) = function regn sub4 ((regn) r) = negative_to_zero (r - 4) -function qword effect { rreg, rmem } EA ((ea) e) = +function qword effect { rreg, rmem } EA ((bool) locked, (ea) e) = switch e { case (Ea_i(sz,i)) -> restrict_size(sz,i) case (Ea_r((Sz8(have_rex)),r)) -> @@ -253,62 +293,67 @@ function qword effect { rreg, rmem } EA ((ea) e) = else (REG[sub4 (r)] >> 8) & 0x00000000000000FF case (Ea_r(sz,r)) -> restrict_size(sz, REG[r]) - case (Ea_m((Sz8(_)),a)) -> EXTZ (MEM(a, 1)) - case (Ea_m(Sz16,a)) -> EXTZ (MEM(a, 2)) - case (Ea_m(Sz32,a)) -> EXTZ (MEM(a, 4)) - case (Ea_m(Sz64,a)) -> MEM(a, 8) + case (Ea_m((Sz8(_)),a)) -> EXTZ (rMEMl(locked, a, 1)) + case (Ea_m(Sz16,a)) -> EXTZ (rMEMl(locked, a, 2)) + case (Ea_m(Sz32,a)) -> EXTZ (rMEMl(locked, a, 4)) + case (Ea_m(Sz64,a)) -> rMEMl(locked, a, 8) } -function unit effect { wmem, wreg, escape } wEA ((ea) e, (qword) w) = +function unit effect { wmem, wreg, escape } wEA ((bool) locked, (ea) e, (qword) w) = switch e { case (Ea_i(_,_)) -> exit () case (Ea_r((Sz8(have_rex)),r)) -> if have_rex | r < 4 (* RSP *) | r > 7 (* RDI *) then - { - (qword) regr := REG[r]; - regr[7 .. 0] := w[7 .. 0]; - REG[r] := regr - } + (REG[r])[7 .. 0] := w[7 .. 0] else - { - (qword) regr := REG[sub4(r)]; - regr[15 .. 8] := (vector<15,8,dec,bit>) (adjust_dec(w[7 .. 0])); - REG[sub4(r)] := regr - } - case (Ea_r(Sz16,r)) -> - { - (qword) regr := REG[r]; - regr[15 .. 8] := w[15 .. 8]; - REG[r] := regr - } + (REG[sub4(r)])[15 .. 8] := (vector<15,8,dec,bit>) (w[7 .. 0]) + case (Ea_r(Sz16,r)) ->(REG[r])[15 .. 0] := w[15 .. 0] case (Ea_r(Sz32,r)) -> REG[r] := (qword) (EXTZ (w[31 .. 0])) case (Ea_r(Sz64,r)) -> REG[r] := w - case (Ea_m((Sz8(_)),a)) -> wMEM(a, 1, w[7 .. 0]) - case (Ea_m(Sz16,a)) -> wMEM(a, 2, w[15 .. 0]) - case (Ea_m(Sz32,a)) -> wMEM(a, 4, w[31 .. 0]) - case (Ea_m(Sz64,a)) -> wMEM(a, 8, w) + case (Ea_m((Sz8(_)),a)) -> wMEM(locked, a, 1, w[7 .. 0]) + case (Ea_m(Sz16,a)) -> wMEM(locked, a, 2, w[15 .. 0]) + case (Ea_m(Sz32,a)) -> wMEM(locked, a, 4, w[31 .. 0]) + case (Ea_m(Sz64,a)) -> wMEM(locked, a, 8, w) } -function (ea, qword, qword) read_dest_src_ea ((size) sz, (dest_src) ds) = +function (ea, qword, qword) read_dest_src_ea ((bool) locked, (wsize) sz, (dest_src) ds) = let e = ea_dest (sz, ds) in - (e, EA(e), EA(ea_src(sz, ds))) + (e, EA(locked, e), EA(locked, ea_src(sz, ds))) function qword call_dest_from_ea ((ea) e) = switch e { case (Ea_i(_, i)) -> RIP + i case (Ea_r(_, r)) -> REG[r] - case (Ea_m(_, a)) -> MEM(a, 8) + case (Ea_m(_, a)) -> rMEM(a, 8) } function qword get_ea_address ((ea) e) = switch e { case (Ea_i(_, i)) -> 0x0000000000000000 case (Ea_r(_, r)) -> 0x0000000000000000 - case (Ea_m(_, a)) -> 0x0000000000000000 + case (Ea_m(_, a)) -> a } function unit jump_to_ea ((ea) e) = RIP := call_dest_from_ea(e) +function (ea, nat) bit_offset_ea ((wsize) sz, (bit_offset) bo) = + let s = size_to_int (sz) in + switch bo { + case (Bit_rm_imm (r_m, imm)) -> + let base_ea = ea_rm (sz, r_m) in + switch (base_ea) { + case (Ea_r(_, r)) -> (Ea_r(sz, r), imm mod s) + case (Ea_m(_, a)) -> (Ea_m(sz, a), imm mod s) + } + case (Bit_rm_r (r_m, r)) -> + let base_ea = ea_rm (sz, r_m) in + let offset = REG[r] in + switch (base_ea) { + case (Ea_r(_, r)) -> (Ea_r(sz, r), offset mod s) + case (Ea_m(_, a)) -> (Ea_m(Sz64, a + (offset div 8)), offset mod 64) + } + } + (* EFLAG updates *) function bit byte_parity ((byte) b) = @@ -318,7 +363,7 @@ function bit byte_parity ((byte) b) = (bit) (acc mod 2 == 0) } -function [|64|] size_width ((size) sz) = +function [|64|] size_width ((wsize) sz) = switch sz { case (Sz8(_)) -> 8 case Sz16 -> 16 @@ -326,7 +371,7 @@ function [|64|] size_width ((size) sz) = case Sz64 -> 64 } -function [|63|] size_width_sub1 ((size) sz) = +function [|63|] size_width_sub1 ((wsize) sz) = switch sz { case (Sz8(_)) -> 7 case Sz16 -> 15 @@ -335,16 +380,16 @@ function [|63|] size_width_sub1 ((size) sz) = } (* XXXXX -function bit word_size_msb ((size) sz, (qword) w) = w[size_width(sz) - 1] +function bit word_size_msb ((wsize) sz, (qword) w) = w[size_width(sz) - 1] *) -function bit word_size_msb ((size) sz, (qword) w) = w[size_width_sub1(sz)] +function bit word_size_msb ((wsize) sz, (qword) w) = w[size_width_sub1(sz)] function unit write_PF ((qword) w) = PF := byte_parity (w[7 .. 0]) -function unit write_SF ((size) sz, (qword) w) = SF := word_size_msb (sz, w) +function unit write_SF ((wsize) sz, (qword) w) = SF := word_size_msb (sz, w) -function unit write_ZF ((size) sz, (qword) w) = +function unit write_ZF ((wsize) sz, (qword) w) = ZF := (bit) (switch sz { case (Sz8(_)) -> w[7 .. 0] == 0x00 @@ -353,7 +398,7 @@ function unit write_ZF ((size) sz, (qword) w) = case Sz64 -> w == 0x0000000000000000 }) -function unit write_arith_eflags_except_CF_OF ((size) sz, (qword) w) = +function unit write_arith_eflags_except_CF_OF ((wsize) sz, (qword) w) = { AF := undefined; write_PF(w); @@ -361,14 +406,14 @@ function unit write_arith_eflags_except_CF_OF ((size) sz, (qword) w) = write_ZF(sz, w); } -function unit write_arith_eflags ((size) sz, (qword) w, (bit) c, (bit) x) = +function unit write_arith_eflags ((wsize) sz, (qword) w, (bit) c, (bit) x) = { CF := c; OF := x; write_arith_eflags_except_CF_OF (sz, w) } -function unit write_logical_eflags ((size) sz, (qword) w) = +function unit write_logical_eflags ((wsize) sz, (qword) w) = write_arith_eflags (sz, w, bitzero, bitzero) function unit erase_eflags () = @@ -381,51 +426,48 @@ function unit erase_eflags () = ZF := undefined; } -(* XXXXX *) -function nat power ((nat) x, ([|64|]) y) = undefined +function nat value_width ((wsize) sz) = 2 ** size_width(sz) -function nat value_width ((size) sz) = power (2, size_width(sz)) - -function bit word_signed_overflow_add ((size) sz, (qword) a, (qword) b) = +function bit word_signed_overflow_add ((wsize) sz, (qword) a, (qword) b) = (bit) (word_size_msb (sz, a) == word_size_msb (sz, b) & word_size_msb (sz, a + b) != word_size_msb (sz, a)) -function bit word_signed_overflow_sub ((size) sz, (qword) a, (qword) b) = +function bit word_signed_overflow_sub ((wsize) sz, (qword) a, (qword) b) = (bit) (word_size_msb (sz, a) != word_size_msb (sz, b) & word_size_msb (sz, a - b) != word_size_msb (sz, a)) -function (qword, bit, bit) add_with_carry_out ((size) sz, (qword) a, (qword) b) = +function (qword, bit, bit) add_with_carry_out ((wsize) sz, (qword) a, (qword) b) = (a + b, (bit) ((int) (value_width (sz)) <= unsigned(a) + unsigned(b)), word_signed_overflow_add (sz, a, b)) -function (qword, bit, bit) sub_with_borrow ((size) sz, (qword) a, (qword) b) = +function (qword, bit, bit) sub_with_borrow ((wsize) sz, (qword) a, (qword) b) = (a - b, (bit) (a < b), word_signed_overflow_sub (sz, a, b)) -function unit write_arith_result ((size) sz, (qword) w, (bit) c, (bit) x, (ea) e) = +function unit write_arith_result ((bool) locked, (wsize) sz, (qword) w, (bit) c, (bit) x, (ea) e) = { write_arith_eflags (sz, w, c, x); - wEA (e) := w; + wEA (locked, e) := w; } -function unit write_arith_result_no_CF_OF ((size) sz, (qword) w, (ea) e) = +function unit write_arith_result_no_CF_OF ((bool) locked, (wsize) sz, (qword) w, (ea) e) = { write_arith_eflags_except_CF_OF (sz, w); - wEA (e) := w; + wEA (locked, e) := w; } -function unit write_logical_result ((size) sz, (qword) w, (ea) e) = +function unit write_logical_result ((bool) locked, (wsize) sz, (qword) w, (ea) e) = { write_arith_eflags_except_CF_OF (sz, w); - wEA (e) := w; + wEA (locked, e) := w; } -function unit write_result_erase_eflags ((qword) w, (ea) e) = +function unit write_result_erase_eflags ((bool) locked, (qword) w, (ea) e) = { erase_eflags (); - wEA (e) := w; + wEA (locked, e) := w; } -function qword effect { escape } sign_extension ((qword) w, (size) size1, (size) size2) = +function qword effect { escape } sign_extension ((qword) w, (wsize) size1, (wsize) size2) = { (qword) x := w; switch (size1, size2) { @@ -440,106 +482,106 @@ function qword effect { escape } sign_extension ((qword) w, (size) size1, (size) x; } -function [|64|] mask_shift ((size) sz, (qword) w) = +function [|64|] mask_shift ((wsize) sz, (qword) w) = if sz == Sz64 then w[5 .. 0] else w[4 .. 0] -function qword rol ((size) sz, (qword) a, (qword) b) = +function qword rol ((wsize) sz, (qword) a, (qword) b) = switch sz { - case (Sz8(_)) -> EXTZ (ROL (a[7 .. 0], b[2 .. 0])) - case Sz16 -> EXTZ (ROL (a[15 .. 0], b[3 .. 0])) - case Sz32 -> EXTZ (ROL (a[31 .. 0], b[4 .. 0])) - case Sz64 -> ROL (a, b[5 .. 0]) + case (Sz8(_)) -> EXTZ (ROL8 (a[7 .. 0], b[2 .. 0])) + case Sz16 -> EXTZ (ROL16 (a[15 .. 0], b[3 .. 0])) + case Sz32 -> EXTZ (ROL32 (a[31 .. 0], b[4 .. 0])) + case Sz64 -> ROL64 (a, b[5 .. 0]) } -function qword ror ((size) sz, (qword) a, (qword) b) = +function qword ror ((wsize) sz, (qword) a, (qword) b) = switch sz { - case (Sz8(_)) -> EXTZ (ROR (a[7 .. 0], b[2 .. 0])) - case Sz16 -> EXTZ (ROR (a[15 .. 0], b[3 .. 0])) - case Sz32 -> EXTZ (ROR (a[31 .. 0], b[4 .. 0])) - case Sz64 -> ROR (a, b[5 .. 0]) + case (Sz8(_)) -> EXTZ (ROR8 (a[7 .. 0], b[2 .. 0])) + case Sz16 -> EXTZ (ROR16 (a[15 .. 0], b[3 .. 0])) + case Sz32 -> EXTZ (ROR32 (a[31 .. 0], b[4 .. 0])) + case Sz64 -> ROR64 (a, b[5 .. 0]) } -function qword sar ((size) sz, (qword) a, (qword) b) = +function qword sar ((wsize) sz, (qword) a, (qword) b) = switch sz { - case (Sz8(_)) -> EXTZ (ASR (a[7 .. 0], b[2 .. 0])) - case Sz16 -> EXTZ (ASR (a[15 .. 0], b[3 .. 0])) - case Sz32 -> EXTZ (ASR (a[31 .. 0], b[4 .. 0])) - case Sz64 -> ASR (a, b[5 .. 0]) + case (Sz8(_)) -> EXTZ (ASR8 (a[7 .. 0], b[2 .. 0])) + case Sz16 -> EXTZ (ASR16 (a[15 .. 0], b[3 .. 0])) + case Sz32 -> EXTZ (ASR32 (a[31 .. 0], b[4 .. 0])) + case Sz64 -> ASR64 (a, b[5 .. 0]) } -function unit write_binop ((size) sz, (binop_name) bop, (qword) a, (qword) b, (ea) e) = +function unit write_binop ((bool) locked, (wsize) sz, (binop_name) bop, (qword) a, (qword) b, (ea) e) = switch bop { - case Add -> let (w,c,x) = add_with_carry_out (sz, a, b) in - write_arith_result (sz, w, c, x, e) - case Sub -> let (w,c,x) = sub_with_borrow (sz, a, b) in - write_arith_result (sz, w, c, x, e) - case Cmp -> let (w,c,x) = sub_with_borrow (sz, a, b) in + case X86_Add -> let (w,c,x) = add_with_carry_out (sz, a, b) in + write_arith_result (locked, sz, w, c, x, e) + case X86_Sub -> let (w,c,x) = sub_with_borrow (sz, a, b) in + write_arith_result (locked, sz, w, c, x, e) + case X86_Cmp -> let (w,c,x) = sub_with_borrow (sz, a, b) in write_arith_eflags (sz, w, c, x) - case Test -> write_logical_eflags (sz, a & b) - case And -> write_logical_result (sz, a & b, e) - case Xor -> write_logical_result (sz, a ^ b, e) - case Or -> write_logical_result (sz, a | b, e) - case Rol -> write_result_erase_eflags (rol (sz, a, b), e) - case Ror -> write_result_erase_eflags (ror (sz, a, b), e) - case Sar -> write_result_erase_eflags (sar (sz, a, b), e) - case Shl -> write_result_erase_eflags (a << mask_shift (sz, b), e) - case Shr -> write_result_erase_eflags (a >> mask_shift (sz, b), e) - case Adc -> + case X86_Test -> write_logical_eflags (sz, a & b) + case X86_And -> write_logical_result (locked, sz, a & b, e) (* XXX rmn30 wrong flags? *) + case X86_Xor -> write_logical_result (locked, sz, a ^ b, e) + case X86_Or -> write_logical_result (locked, sz, a | b, e) + case X86_Rol -> write_result_erase_eflags (locked, rol (sz, a, b), e) + case X86_Ror -> write_result_erase_eflags (locked, ror (sz, a, b), e) + case X86_Sar -> write_result_erase_eflags (locked, sar (sz, a, b), e) + case X86_Shl -> write_result_erase_eflags (locked, a << mask_shift (sz, b), e) + case X86_Shr -> write_result_erase_eflags (locked, a >> mask_shift (sz, b), e) + case X86_Adc -> { - let carry = CF in + let carry = (bit) CF in let (qword) result = a + (qword) (b + carry) in { CF := (bit) ((int) (value_width (sz)) <= unsigned(a) + unsigned(b)); OF := undefined; - write_arith_result_no_CF_OF (sz, result, e); + write_arith_result_no_CF_OF (locked, sz, result, e); } } - case Sbb -> + case X86_Sbb -> { - let carry = CF in + let carry = (bit) CF in let (qword) result = a - (qword) (b + carry) in { CF := (bit) (unsigned(a) < unsigned(b) + (int) carry); OF := undefined; - write_arith_result_no_CF_OF (sz, result, e); + write_arith_result_no_CF_OF (locked, sz, result, e); } } case _ -> exit () } -function unit write_monop ((size) sz, (monop_name) mop, (qword) a, (ea) e) = +function unit write_monop ((bool) locked, (wsize) sz, (monop_name) mop, (qword) a, (ea) e) = switch mop { - case Not -> wEA(e) := ~(a) - case Dec -> write_arith_result_no_CF_OF (sz, a - 1, e) - case Inc -> write_arith_result_no_CF_OF (sz, a + 1, e) - case Neg -> { write_arith_result_no_CF_OF (sz, 0 - a, e); - CF := undefined; - } + case X86_Not -> wEA(locked, e) := ~(a) + case X86_Dec -> write_arith_result_no_CF_OF (locked, sz, a - 1, e) + case X86_Inc -> write_arith_result_no_CF_OF (locked, sz, a + 1, e)(* XXX rmn30 should set OF *) + case X86_Neg -> { write_arith_result_no_CF_OF (locked, sz, 0 - a, e); + CF := undefined; + } } function bool read_cond ((cond) c) = switch c { - case A -> ~(CF) & ~(ZF) - case NB -> ~(CF) - case B -> CF - case NA -> CF | (bit) ZF - case E -> ZF - case G -> ~(ZF) & (SF == OF) - case NL -> SF == OF - case L -> SF != OF - case NG -> ZF | SF != OF - case NE -> ~(ZF) - case NO -> ~(OF) - case NP -> ~(PF) - case NS -> ~(SF) - case O -> OF - case P -> PF - case S -> SF - case ALWAYS -> true + case X86_A -> ~(CF) & ~(ZF) + case X86_NB -> ~(CF) + case X86_B -> CF + case X86_NA -> CF | (bit) ZF + case X86_E -> ZF + case X86_G -> ~(ZF) & (SF == OF) + case X86_NL -> SF == OF + case X86_L -> SF != OF + case X86_NG -> ZF | SF != OF + case X86_NE -> ~(ZF) + case X86_NO -> ~(OF) + case X86_NP -> ~(PF) + case X86_NS -> ~(SF) + case X86_O -> OF + case X86_P -> PF + case X86_S -> SF + case X86_ALWAYS -> true } function qword pop_aux () = - let top = MEM(RSP, 8) in + let top = rMEM(RSP, 8) in { RSP := RSP + 8; top; @@ -548,12 +590,12 @@ function qword pop_aux () = function unit push_aux ((qword) w) = { RSP := RSP - 8; - wMEM(RSP, 8) := w; + wMEM(false, RSP, 8) := w; } -function unit pop ((rm) r) = wEA (ea_rm (Sz64,r)) := pop_aux() +function unit pop ((rm) r) = wEA (false, ea_rm (Sz64,r)) := pop_aux() function unit pop_rip () = RIP := pop_aux() -function unit push ((imm_rm) i) = push_aux (EA (ea_imm_rm (i))) +function unit push ((imm_rm) i) = push_aux (EA (false, ea_imm_rm (i))) function unit push_rip () = push_aux (RIP) function unit drop ((qword) i) = if i[7 ..0] != 0 then () else RSP := RSP + i @@ -565,17 +607,36 @@ function unit drop ((qword) i) = if i[7 ..0] != 0 then () else RSP := RSP + i scattered function unit execute scattered typedef ast = const union -val ast -> unit effect {escape, rmem, rreg, undef, wmem, wreg} execute +val ast -> unit effect {escape, rmem, rreg, undef, eamem, wmv, wreg, barr} execute (* ========================================================================== Binop ========================================================================== *) -union ast member (binop_name,size,dest_src) Binop +union ast member (bool,binop_name,wsize,dest_src) Binop + +function clause execute (Binop (locked,bop,sz,ds)) = + let (e, val_dst, val_src) = read_dest_src_ea (locked, sz, ds) in + write_binop (locked, sz, bop, val_dst, val_src, e) + +(* ========================================================================== + Bitop + ========================================================================== *) -function clause execute (Binop (bop,sz,ds)) = - let (e, val_dst, val_src) = read_dest_src_ea (sz, ds) in - write_binop (sz, bop, val_dst, val_src, e) +union ast member (bool,bitop_name,wsize,bit_offset) Bitop + +function clause execute (Bitop (locked,bop,sz,boffset)) = + let (base_ea, offset) = bit_offset_ea (sz, boffset) in { + word := EA(locked, base_ea); + bitval := word[offset]; + word[offset] := switch(bop) { + case Bts -> bitone + case Btc -> (~ (bitval)) + case Btr -> bitzero + }; + CF := bitval; + wEA(locked, base_ea) := word; + } (* ========================================================================== CALL @@ -609,45 +670,58 @@ function clause execute CMC = CF := ~(CF) CMPXCHG ========================================================================== *) -union ast member (size,rm,regn) CMPXCHG +union ast member (bool, wsize,rm,regn) CMPXCHG -function clause execute (CMPXCHG (sz,r,n)) = +function clause execute (CMPXCHG (locked, sz,r,n)) = let src = Ea_r(sz, n) in let acc = Ea_r(sz, 0) in (* RAX *) let dst = ea_rm(sz, r) in - let val_dst = EA(dst) in - let val_acc = EA(src) in + let val_dst = EA(locked, dst) in + let val_acc = EA(false, acc) in { - write_binop (sz, Cmp, val_acc, val_dst, src); + write_binop (locked, sz, X86_Cmp, val_acc, val_dst, src); if val_acc == val_dst then - wEA(dst) := EA (src) - else - wEA(acc) := val_dst; + wEA(locked, dst) := EA (false, src) + else { + wEA(false, acc) := val_dst; + (* write back the original value in dst so that we always + perform locked write after locked read *) + wEA(locked, dst) := val_dst; + } } (* ========================================================================== DIV ========================================================================== *) -union ast member (size,rm) DIV +union ast member (wsize,rm) X86_DIV -function clause execute (DIV (sz,r)) = +function clause execute (X86_DIV (sz,r)) = let w = (int) (value_width(sz)) in let eax = Ea_r(sz, 0) in (* RAX *) let edx = Ea_r(sz, 2) in (* RDX *) - let n = unsigned(EA(edx)) * w + unsigned(EA(eax)) in - let d = unsigned(EA(ea_rm(sz, r))) in + let n = unsigned(EA(false, edx)) * w + unsigned(EA(false, eax)) in + let d = unsigned(EA(false, ea_rm(sz, r))) in let q = n quot d in let m = n mod d in if d == 0 | w < q then exit () else { - wEA(eax) := cast_int_vec(q); - wEA(edx) := cast_int_vec(m); + wEA(false, eax) := (qword) q; + wEA(false, edx) := (qword) m; erase_eflags(); } (* ========================================================================== + HLT -- halt instruction used to end test in RMEM + ========================================================================== *) + +union ast member unit HLT + +function clause execute (HLT) = () + + +(* ========================================================================== Jcc ========================================================================== *) @@ -662,18 +736,18 @@ function clause execute (Jcc (c,i)) = union ast member rm JMP -function clause execute (JMP (r)) = RIP := EA (ea_rm (Sz64, r)) +function clause execute (JMP (r)) = RIP := EA (false, ea_rm (Sz64, r)) (* ========================================================================== LEA ========================================================================== *) -union ast member (size,dest_src) LEA +union ast member (wsize,dest_src) LEA function clause execute (LEA (sz,ds)) = let src = ea_src (sz, ds) in let dst = ea_dest (sz, ds) in - wEA(dst) := get_ea_address (src) + wEA(false, dst) := get_ea_address (src) (* ========================================================================== LEAVE @@ -684,7 +758,7 @@ union ast member unit LEAVE function clause execute LEAVE = { RSP := RBP; - pop (Reg (5)); (* RBP *) + pop (X86_Reg (5)); (* RBP *) } (* ========================================================================== @@ -700,67 +774,76 @@ function clause execute (LOOP (c,i)) = } (* ========================================================================== + MFENCE + ========================================================================== *) + +union ast member unit MFENCE + +function clause execute (MFENCE) = + X86_MFENCE () + +(* ========================================================================== Monop ========================================================================== *) -union ast member (monop_name,size,rm) Monop +union ast member (bool,monop_name,wsize,rm) Monop -function clause execute (Monop (mop,sz,r)) = - let e = ea_rm (sz, r) in write_monop (sz, mop, EA(e), e) +function clause execute (Monop (locked,mop,sz,r)) = + let e = ea_rm (sz, r) in write_monop (locked, sz, mop, EA(locked, e), e) (* ========================================================================== MOV ========================================================================== *) -union ast member (cond,size,dest_src) MOV +union ast member (cond,wsize,dest_src) MOV function clause execute (MOV (c,sz,ds)) = if read_cond (c) then let src = ea_src (sz, ds) in let dst = ea_dest (sz, ds) in - wEA(dst) := EA(src) + wEA(false, dst) := EA(false, src) else () (* ========================================================================== MOVSX ========================================================================== *) -union ast member (size,dest_src,size) MOVSX +union ast member (wsize,dest_src,wsize) MOVSX function clause execute (MOVSX (sz1,ds,sz2)) = let src = ea_src (sz1, ds) in let dst = ea_dest (sz2, ds) in - wEA(dst) := sign_extension (EA(src), sz1, sz2) + wEA(false, dst) := sign_extension (EA(false, src), sz1, sz2) (* ========================================================================== MOVZX ========================================================================== *) -union ast member (size,dest_src,size) MOVZX +union ast member (wsize,dest_src,wsize) MOVZX function clause execute (MOVZX (sz1,ds,sz2)) = let src = ea_src (sz1, ds) in let dst = ea_dest (sz2, ds) in - wEA(dst) := EA(src) + wEA(false, dst) := EA(false, src) (* ========================================================================== MUL ========================================================================== *) -union ast member (size,rm) MUL +union ast member (wsize,rm) X86_MUL -function clause execute (MUL (sz,r)) = +function clause execute (X86_MUL (sz,r)) = let eax = Ea_r (sz, 0) in (* RAX *) - let val_eax = EA(eax) in - let val_src = EA(ea_rm (sz, r)) in + let val_eax = EA(false, eax) in + let val_src = EA(false, ea_rm (sz, r)) in switch sz { - case (Sz8(_)) -> wEA(Ea_r(Sz16,0)) := (val_eax * val_src)[63 .. 0] + case (Sz8(_)) -> wEA(false, Ea_r(Sz16,0)) := (val_eax * val_src)[63 .. 0] case _ -> let m = val_eax * val_src in let edx = Ea_r (sz, 2) in (* RDX *) { - wEA(eax) := m[63 .. 0]; - wEA(edx) := (LSR (m, size_width(sz)))[63 .. 0] + wEA(false, eax) := m[63 .. 0]; + wEA(false, edx) := (m >> size_width(sz))[63 .. 0] } } @@ -807,7 +890,7 @@ function clause execute (RET (i)) = union ast member (cond,bool,rm) SET function clause execute (SET (c,b,r)) = - wEA(ea_rm(Sz8(b),r)) := if read_cond (c) then 1 else 0 + wEA(false, ea_rm(Sz8(b),r)) := if read_cond (c) then 1 else 0 (* ========================================================================== STC @@ -821,32 +904,32 @@ function clause execute STC = CF := true XADD ========================================================================== *) -union ast member (size,rm,regn) XADD +union ast member (bool, wsize,rm,regn) XADD -function clause execute (XADD (sz,r,n)) = +function clause execute (XADD (locked,sz,r,n)) = let src = Ea_r (sz, n) in let dst = ea_rm (sz, r) in - let val_src = EA(src) in - let val_dst = EA(dst) in + let val_src = EA(false, src) in + let val_dst = EA(locked, dst) in { - wEA(src) := val_dst; - write_binop (sz, Add, val_src, val_dst, dst); + wEA(false, src) := val_dst; + write_binop (locked, sz, X86_Add, val_src, val_dst, dst); } (* ========================================================================== XCHG ========================================================================== *) -union ast member (size,rm,regn) XCHG +union ast member (bool,wsize,rm,regn) XCHG -function clause execute (XCHG (sz,r,n)) = +function clause execute (XCHG (locked,sz,r,n)) = let src = Ea_r (sz, n) in let dst = ea_rm (sz, r) in - let val_src = EA(src) in - let val_dst = EA(dst) in + let val_src = EA(false, src) in + let val_dst = EA(locked, dst) in { - wEA(src) := val_dst; - wEA(dst) := val_src; + wEA(false, src) := val_dst; + wEA(locked, dst) := val_src; } end ast @@ -855,7 +938,7 @@ end execute (* -------------------------------------------------------------------------- Decoding -------------------------------------------------------------------------- *) - +(* function (qword,ostream) oimmediate8 ((ostream) strm) = switch strm { case (Some (b :: t)) -> ((qword) (EXTS(b)), Some (t)) @@ -885,20 +968,20 @@ function (qword,ostream) immediate64 ((byte_stream) strm) = case _ -> ((qword) undefined, (ostream) None) } -function (qword, ostream) immediate ((size) sz, (byte_stream) strm) = +function (qword, ostream) immediate ((wsize) sz, (byte_stream) strm) = switch sz { case (Sz8 (_)) -> immediate8 (strm) case Sz16 -> immediate16 (strm) case _ -> immediate32 (strm) } -function (qword, ostream) oimmediate ((size) sz, (ostream) strm) = +function (qword, ostream) oimmediate ((wsize) sz, (ostream) strm) = switch strm { case (Some (s)) -> immediate (sz, s) case None -> ((qword) undefined, (ostream) None) } -function (qword, ostream) full_immediate ((size) sz, (byte_stream) strm) = +function (qword, ostream) full_immediate ((wsize) sz, (byte_stream) strm) = if sz == Sz64 then immediate64 (strm) else immediate (sz, strm) (* - Parse ModR/M and SIB bytes --------------------------------------------- *) @@ -1010,7 +1093,7 @@ function rec option<atuple> read_prefix function option<atuple> read_prefixes ((byte_stream) strm) = read_prefix ([||||], [||||], strm) -function size op_size ((bool) have_rex, (bit[1]) w, (bit[1]) v, (bool) override) = +function wsize op_size ((bool) have_rex, (bit[1]) w, (bit[1]) v, (bool) override) = if v == 1 then Sz8 (have_rex) else if w == 1 then @@ -1225,3 +1308,306 @@ function (byte_stream, ast, nat) decode ((byte_stream) strm) = case _ -> exit () } } + *) + +let (vector <0, 16, inc, string >) GPRstr = + ["RAX","RCX","RDX","RBX","RSP","RBP","RSI","RDI","R8","R9","R10","R11","R12","R13","R14","R15"] + +function (regfps) regfp_base ((base) b) = + switch b { + case NoBase -> [|| ||] + case RipBase -> [|| RFull("RIP") ||] + case (RegBase(b)) -> [|| RFull(GPRstr[b]) ||] + } + +function (regfps) regfp_idx ((option<scale_index>) idx) = + switch idx { + case (None) -> [|| ||] + case (Some(scale, idx)) -> [|| RFull(GPRstr[idx]) ||] + } + +function (bool, regfps, regfps) regfp_rm ((rm) r) = + switch r { + case (X86_Reg(n)) -> + (false, [|| RFull(GPRstr[n]) ||], [|| ||]) + case (Mem(idx, b, d)) -> { + (true, [|| ||], append(regfp_idx(idx), regfp_base(b))) + } + } + +function (instruction_kind, regfps, regfps, regfps) regfp_dest_src ((dest_src) ds) = + switch ds { + case (Rm_i (r_m, i)) -> + let (m,rd,ars) = regfp_rm(r_m) in + (if m then IK_mem_write(Write_plain) else IK_simple, ars, rd, ars) + case (Rm_r (r_m, r)) -> + let (m,rd,ars) = regfp_rm(r_m) in + (if m then IK_mem_write(Write_plain) else IK_simple, RFull(GPRstr[r]) :: ars, rd, ars) + case (R_rm (r, r_m)) -> + let (m,rs,ars) = regfp_rm(r_m) in + (if m then IK_mem_read(Read_plain) else IK_simple, append(rs, ars), [|| RFull(GPRstr[r]) ||], ars) + } + +(* as above but where destination is also a source operand *) +function (instruction_kind, regfps, regfps, regfps) regfp_dest_src_rmw (locked, (dest_src) ds) = + let rk = if locked then Read_X86_locked else Read_plain in + let wk = if locked then Write_X86_locked else Write_plain in + switch ds { + case (Rm_i (r_m, i)) -> + let (m,rds, ars) = regfp_rm(r_m) in + (if m then IK_mem_rmw(rk, wk) else IK_simple, append(rds, ars), rds, ars) + case (Rm_r (r_m, r)) -> + let (m,rds, ars) = regfp_rm(r_m) in + (if m then IK_mem_rmw(rk, wk) else IK_simple, RFull(GPRstr[r]) :: append(rds, ars), rds, ars) + case (R_rm (r, r_m)) -> + let rds = [|| RFull(GPRstr[r]) ||] in + let (m,rs,ars) = regfp_rm(r_m) in + (if m then IK_mem_read(Read_plain) else IK_simple, append(rds, ars), rds, ars) + } + +function (bool, regfps, regfps) regfp_imm_rm ((imm_rm) i_rm) = + switch i_rm { + case (Rm (v)) -> regfp_rm (v) + case (Imm (v)) -> (false, [|| ||], [|| ||]) + } + +let all_flags_but_cf_of = [|| RFull("AF"), RFull("PF"), RFull("SF"), RFull("ZF") ||] +let all_flags = append([|| RFull("CF"), RFull("OF") ||], all_flags_but_cf_of) + +function (regfps) regfp_binop_flags ((binop_name) op) = + switch (op) { + case X86_Add -> all_flags + case X86_Sub -> all_flags + case X86_Cmp -> all_flags + case X86_Test -> all_flags_but_cf_of + case X86_And -> all_flags_but_cf_of + case X86_Xor -> all_flags_but_cf_of + case X86_Or -> all_flags_but_cf_of + case X86_Rol -> all_flags + case X86_Ror -> all_flags + case X86_Sar -> all_flags + case X86_Shl -> all_flags + case X86_Shr -> all_flags + case X86_Adc -> all_flags + case X86_Sbb -> all_flags + } +function (regfps) regfp_cond ((cond) c) = + switch c { + case X86_A -> [|| RFull("CF"), RFull("ZF") ||] + case X86_NB -> [|| RFull("CF") ||] + case X86_B -> [|| RFull("CF") ||] + case X86_NA -> [|| RFull("CF"), RFull("ZF") ||] + case X86_E -> [|| RFull("ZF") ||] + case X86_G -> [|| RFull("ZF"), RFull("SF"), RFull("OF") ||] + case X86_NL -> [|| RFull("SF"), RFull("OF") ||] + case X86_L -> [|| RFull("SF"), RFull("OF") ||] + case X86_NG -> [|| RFull("ZF"), RFull("SF"), RFull("OF") ||] + case X86_NE -> [|| RFull("ZF") ||] + case X86_NO -> [|| RFull("OF") ||] + case X86_NP -> [|| RFull("PF") ||] + case X86_NS -> [|| RFull("SF") ||] + case X86_O -> [|| RFull("OF") ||] + case X86_P -> [|| RFull("PF") ||] + case X86_S -> [|| RFull("SF") ||] + case X86_ALWAYS -> [|| ||] + } + +function (regfps,regfps,regfps,niafps,diafp,instruction_kind) initial_analysis (instr) = { + iR := [|| ||]; + oR := [|| ||]; + aR := [|| ||]; + ik := IK_simple; + Nias := [|| NIAFP_successor ||]; + Dia := DIAFP_none; + switch instr { + case(Binop (locked, binop, sz, ds)) -> { + let flags = regfp_binop_flags (binop) in + let (ik', iRs, oRs, aRs) = regfp_dest_src_rmw(locked, ds) in { + ik := ik'; + iR := append(iRs, iR); + oR := append(flags, append(oRs, oR)); + aR := append(aRs, aR); + } + } + case(Bitop (locked, bitop, sz, bitoff)) -> { + let rk = if locked then Read_X86_locked else Read_plain in + let wk = if locked then Write_X86_locked else Write_plain in + let (ik', iRs, oRs, aRs) = switch(bitoff) { + case (Bit_rm_imm (r_m, imm)) -> + let (m, rs, ars) = regfp_rm(r_m) in + (if m then IK_mem_rmw(rk, wk) else IK_simple, + append(rs, ars), rs, ars) + case (Bit_rm_r (r_m, r)) -> + let rfp = RFull(GPRstr[r]) in + let (m, rs, ars) = regfp_rm(r_m) in + (if m then IK_mem_rmw(rk, wk) else IK_simple, + rfp::append(rs, ars), rs, + if m then (rfp::ars) else ars) (* in memory case r is a third input to address! *) + } in { + ik := ik'; + iR := append(iRs, iR); + oR := RFull("CF")::append(oRs, oR); + aR := append(aRs, aR); + } + } + case(CALL (irm) ) -> + let (m, rs, ars) = regfp_imm_rm (irm) in { + ik := if m then IK_mem_rmw(Read_plain, Write_plain) else IK_mem_write(Write_plain); + iR := RFull("RIP") :: RFull("RSP") :: rs; + oR := RFull("RSP") :: oR; + aR := ars; + Nias := switch irm { + (* XXX register name is not important here -- just indicates we don't know the destination yet. *) + case (Rm (v)) -> NIAFP_register(RFull("RAX")) + case (Imm (v)) -> NIAFP_concrete_address(RIP + v) + } :: Nias; + } + case(CLC ) -> oR := RFull("CF") :: oR + case(CMC ) -> { + iR := RFull("CF") :: iR; + oR := RFull("CF") :: oR; + } + case(CMPXCHG (locked, sz, r_m, reg) ) -> + let rk = if locked then Read_X86_locked else Read_plain in + let wk = if locked then Write_X86_locked else Write_plain in + let (m, rs, aRs) = regfp_rm (r_m) in { + ik := if m then IK_mem_rmw (rk, wk) else IK_simple; + iR := RFull("RAX") :: RFull(GPRstr[reg]) :: append(rs, aRs); + oR := RFull("RAX") :: append(regfp_binop_flags(X86_Cmp), rs); + aR := aRs; + } + case(X86_DIV (sz, r_m) ) -> + let (m, rs, ars) = regfp_rm (r_m) in { + ik := if m then IK_mem_read (Read_plain) else IK_simple; + iR := RFull("RAX") :: RFull("RDX") :: append(rs, ars); + oR := RFull("RAX") :: RFull("RDX") :: append(oR, all_flags); + aR := ars; + } + case(HLT ) -> () + case(Jcc (c, imm64) ) -> + let flags = regfp_cond(c) in { + ik := IK_cond_branch; + iR := RFull("RIP") :: flags; + Nias := NIAFP_concrete_address(RIP + imm64) :: Nias; + } + case(JMP (r_m) ) -> + let (m, rs, ars) = regfp_rm (r_m) in { + ik := if m then IK_mem_read(Read_plain) else IK_simple; + iR := RFull("RIP")::append(rs, ars); + aR := ars; + (* XXX register name is not important here -- just indicates we don't know the destination yet. *) + Nias := NIAFP_register(RFull("RAX")) :: Nias; + } + case(LEA (sz, ds) ) -> + let (_, irs, ors, ars) = regfp_dest_src (ds) in { + iR := irs; + oR := ors; + aR := ars; + } + case(LEAVE ) -> { + ik := IK_mem_read(Read_plain); + iR := RFull("RBP") :: iR; + oR := RFull("RBP") :: RFull("RSP") :: oR; + aR := RFull("RBP") :: aR; + } + case(LOOP (c, imm64) ) -> + let flags = regfp_cond(c) in { + ik := IK_cond_branch; + iR := RFull("RCX") :: flags; + oR := RFull("RCX") :: oR; + Nias := NIAFP_concrete_address(RIP + imm64) :: Nias; + } + case(MFENCE ) -> + ik := IK_barrier (Barrier_x86_MFENCE) + case(Monop (locked, monop, sz, r_m) ) -> + let rk = if locked then Read_X86_locked else Read_plain in + let wk = if locked then Write_X86_locked else Write_plain in + let (m, rds, ars) = regfp_rm(r_m) in { + ik := if m then IK_mem_rmw(rk, wk) else IK_simple; + iR := append(rds, ars); + oR := append(all_flags_but_cf_of, rds); (* XXX fix flags *) + aR := ars; + } + case(MOV (c, sz, ds) ) -> + let (ik', irs, ors, ars) = regfp_dest_src (ds) in + let flags = regfp_cond(c) in + { + ik := ik'; + iR := append(irs, flags); + oR := ors; + aR := ars; + } + case(MOVSX (sz1, ds, sz2) ) -> + let (ik', irs, ors, ars) = regfp_dest_src (ds) in { + ik := ik'; + iR := irs; + oR := ors; + aR := ars; + } + case(MOVZX (sz1, ds, sz2) ) -> + let (ik', irs, ors, ars) = regfp_dest_src (ds) in { + ik := ik'; + iR := irs; + oR := ors; + aR := ars; + } + case(X86_MUL (sz, r_m) ) -> + let (m, rs, ars) = regfp_rm (r_m) in { + ik := if m then IK_mem_read (Read_plain) else IK_simple; + iR := RFull("RAX") :: append(rs, ars); + oR := RFull("RAX") :: RFull("RDX") :: append(oR, all_flags); + aR := ars; + } + case(NOP (_) ) -> () + case(POP (r_m) ) -> + let (m, rd, ars) = regfp_rm (r_m) in { + ik := if m then IK_mem_rmw(Read_plain, Write_plain) else IK_mem_write(Write_plain); + iR := RFull("RSP") :: ars; + oR := RFull("RSP") :: rd; + aR := RFull("RSP") :: ars; + } + case(PUSH (irm) ) -> + let (m, rs, ars) = regfp_imm_rm (irm) in { + ik := if m then IK_mem_rmw(Read_plain, Write_plain) else IK_mem_write(Write_plain); + iR := RFull("RSP") :: append(rs, ars); + oR := RFull("RSP") :: oR; + aR := RFull("RSP") :: ars; + } + case(RET (imm64) ) -> { + ik := IK_mem_read(Read_plain); + iR := RFull("RSP") :: iR; + oR := RFull("RSP") :: oR; + aR := RFull("RSP") :: aR; + (* XXX register name is not important here -- just indicates we don't know the destination yet. *) + Nias := NIAFP_register(RFull("RAX")) :: Nias; + } + case(SET (c, b, r_m) ) -> + let flags = regfp_cond(c) in + let (m, rs, ars) = regfp_rm(r_m) in { + ik := if m then IK_mem_write(Write_plain) else IK_simple; + iR := append(flags, ars); + oR := rs; + aR := ars; + } + case(STC ) -> oR := [|| RFull("CF") ||] + case(XADD (locked, sz, r_m, reg) ) -> + let rk = if locked then Read_X86_locked else Read_plain in + let wk = if locked then Write_X86_locked else Write_plain in + let (m, rs, ars) = regfp_rm(r_m) in { + ik := if m then IK_mem_rmw(rk, wk) else IK_simple; + iR := RFull(GPRstr[reg]) :: append(rs, ars); + oR := RFull(GPRstr[reg]) :: append(rs, all_flags); + aR := ars; + } + case(XCHG (locked, sz, r_m, reg) ) -> + let rk = if locked then Read_X86_locked else Read_plain in + let wk = if locked then Write_X86_locked else Write_plain in + let (m, rs, ars) = regfp_rm(r_m) in { + ik := if m then IK_mem_rmw(rk, wk) else IK_simple; + iR := RFull(GPRstr[reg]) :: append(rs, ars); + oR := RFull(GPRstr[reg]) :: rs; + aR := ars; + } + }; + (iR,oR,aR,Nias,Dia,ik) +} |
