diff --git a/arch/inst/Zcmp/cm.mva01s.yaml b/arch/inst/Zcmp/cm.mva01s.yaml new file mode 100644 index 000000000..47078f179 --- /dev/null +++ b/arch/inst/Zcmp/cm.mva01s.yaml @@ -0,0 +1,33 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +$schema: "inst_schema.json#" +kind: instruction +name: cm.mva01s +long_name: Move two s0-s7 registers into a0-a1 +description: | + This instruction moves r1s' into a0 and r2s' into a1. The execution is atomic, so it is not possible to observe state where only one of a0 or a1 have been updated. + The encoding uses sreg number specifiers instead of xreg number specifiers to save encoding space. The mapping between them is specified in the pseudo-code below. +definedBy: + anyOf: + - Zcmp +assembly: r1s, r2s +encoding: + match: 101011---11---10 + variables: + - name: r1s + location: 9-7 + - name: r2s + location: 4-2 +access: + s: always + u: always + vs: always + vu: always +operation(): | + if (implemented?(ExtensionName::Zcmp) && (CSR[misa].C == 1'b0)) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + XReg xreg1 = (r1s[2:1]>0) ? {1,0,r1s[2:0]} : {0,1,r1s[2:0]}; + XReg xreg2 = (r2s[2:1]>0) ? {1,0,r2s[2:0]} : {0,1,r2s[2:0]}; + X[10] = X[xreg1]; + X[11] = X[xreg2]; diff --git a/arch/inst/Zcmp/cm.mvsa01.yaml b/arch/inst/Zcmp/cm.mvsa01.yaml new file mode 100644 index 000000000..083242fb6 --- /dev/null +++ b/arch/inst/Zcmp/cm.mvsa01.yaml @@ -0,0 +1,35 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +$schema: "inst_schema.json#" +kind: instruction +name: cm.mvsa01 +long_name: Move a0-a1 into two registers of s0-s7 +description: | + This instruction moves a0 into r1s' and a1 into r2s'. r1s' and r2s' must be different. + The execution is atomic, so it is not possible to observe state where only one of r1s' or r2s' has been updated. + The encoding uses sreg number specifiers instead of xreg number specifiers to save encoding space. + The mapping between them is specified in the pseudo-code below. +definedBy: + anyOf: + - Zcmp +assembly: r1s, r2s +encoding: + match: 101011---01---10 + variables: + - name: r1s + location: 9-7 + - name: r2s + location: 4-2 +access: + s: always + u: always + vs: always + vu: always +operation(): | + if (implemented?(ExtensionName::Zcmp) && (CSR[misa].C == 1'b0)) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + XReg xreg1 = (r1s[2:1]>0) ? {1,0,r1s[2:0]} : {0,1,r1s[2:0]}; + XReg xreg2 = (r2s[2:1]>0) ? {1,0,r2s[2:0]} : {0,1,r2s[2:0]}; + X[xreg1] = X[10]; + X[xreg2] = X[11]; diff --git a/arch/inst/Zcmp/cm.pop.yaml b/arch/inst/Zcmp/cm.pop.yaml new file mode 100644 index 000000000..8063822a0 --- /dev/null +++ b/arch/inst/Zcmp/cm.pop.yaml @@ -0,0 +1,83 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +$schema: "inst_schema.json#" +kind: instruction +name: cm.pop +long_name: Destroy function call stack frame +description: | + Destroy stack frame: load `ra` and 0 to 12 saved registers from the stack frame, deallocate the stack frame. + This instruction pops (loads) the registers in `reg_list` from stack memory, and then adjusts the stack pointer by `stack_adj`. + + Restrictions on stack_adj: + + * it must be enough to store all of the listed registers + * it must be a multiple of 16 (bytes): + ** for RV32 the allowed values are: 16, 32, 48, 64, 80, 96, 112 + ** for RV64 the allowed values are: 16, 32, 48, 64, 80, 96, 112, 128, 144, 160 +definedBy: + anyOf: + - Zcmp +assembly: reg_list, stack_adj +encoding: + match: 10111010------10 + variables: + - name: rlist + location: 7-4 + not: [0, 1, 2, 3] + - name: spimm + location: 3-2 + left_shift: 4 +access: + s: always + u: always + vs: always + vu: always +operation(): | + if (implemented?(ExtensionName::Zcmp) && (CSR[misa].C == 1'b0)) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + XReg size = xlen(); + XReg nreg = (rlist == 15) ? 13 : (rlist - 3); + XReg stack_aligned_adj = (nreg * 4 + 15) & ~0xF; + XReg virtual_address_sp = X[2]; + XReg virtual_address_new_sp = virtual_address_sp + stack_aligned_adj + spimm; + XReg virtual_address_base = virtual_address_new_sp - (nreg * size); + + X[ 1] = read_memory_xlen(virtual_address_base + 0*size, $encoding); + if (nreg > 1) { + X[ 8] = read_memory_xlen(virtual_address_base + 1*size, $encoding); + } + if (nreg > 2) { + X[ 9] = read_memory_xlen(virtual_address_base + 2*size, $encoding); + } + if (nreg > 3) { + X[18] = read_memory_xlen(virtual_address_base + 3*size, $encoding); + } + if (nreg > 4) { + X[19] = read_memory_xlen(virtual_address_base + 4*size, $encoding); + } + if (nreg > 5) { + X[20] = read_memory_xlen(virtual_address_base + 5*size, $encoding); + } + if (nreg > 6) { + X[21] = read_memory_xlen(virtual_address_base + 6*size, $encoding); + } + if (nreg > 7) { + X[22] = read_memory_xlen(virtual_address_base + 7*size, $encoding); + } + if (nreg > 8) { + X[23] = read_memory_xlen(virtual_address_base + 8*size, $encoding); + } + if (nreg > 9) { + X[24] = read_memory_xlen(virtual_address_base + 9*size, $encoding); + } + if (nreg > 10) { + X[25] = read_memory_xlen(virtual_address_base + 10*size, $encoding); + } + if (nreg > 11) { + X[26] = read_memory_xlen(virtual_address_base + 11*size, $encoding); + X[27] = read_memory_xlen(virtual_address_base + 12*size, $encoding); + } + + X[2] = virtual_address_new_sp; diff --git a/arch/inst/Zcmp/cm.popret.yaml b/arch/inst/Zcmp/cm.popret.yaml new file mode 100644 index 000000000..77f63bcac --- /dev/null +++ b/arch/inst/Zcmp/cm.popret.yaml @@ -0,0 +1,84 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +$schema: "inst_schema.json#" +kind: instruction +name: cm.popret +long_name: Destroy function call stack frame and return to `ra`. +description: | + Destroy stack frame: load `ra` and 0 to 12 saved registers from the stack frame, deallocate the stack frame, return to `ra`. + This instruction pops (loads) the registers in `reg_list` from stack memory, and then adjusts the stack pointer by `stack_adj` and then return to `ra`. + + Restrictions on stack_adj: + + * it must be enough to store all of the listed registers + * it must be a multiple of 16 (bytes): + ** for RV32 the allowed values are: 16, 32, 48, 64, 80, 96, 112 + ** for RV64 the allowed values are: 16, 32, 48, 64, 80, 96, 112, 128, 144, 160 +definedBy: + anyOf: + - Zcmp +assembly: reg_list, stack_adj +encoding: + match: 10111110------10 + variables: + - name: rlist + location: 7-4 + not: [0, 1, 2, 3] + - name: spimm + location: 3-2 + left_shift: 4 +access: + s: always + u: always + vs: always + vu: always +operation(): | + if (implemented?(ExtensionName::Zcmp) && (CSR[misa].C == 1'b0)) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + XReg size = xlen(); + XReg nreg = (rlist == 15) ? 13 : (rlist - 3); + XReg stack_aligned_adj = (nreg * 4 + 15) & ~0xF; + XReg virtual_address_sp = X[2]; + XReg virtual_address_new_sp = virtual_address_sp + stack_aligned_adj + spimm; + XReg virtual_address_base = virtual_address_new_sp - (nreg * size); + + X[ 1] = read_memory_xlen(virtual_address_base + 0*size, $encoding); + if (nreg > 1) { + X[ 8] = read_memory_xlen(virtual_address_base + 1*size, $encoding); + } + if (nreg > 2) { + X[ 9] = read_memory_xlen(virtual_address_base + 2*size, $encoding); + } + if (nreg > 3) { + X[18] = read_memory_xlen(virtual_address_base + 3*size, $encoding); + } + if (nreg > 4) { + X[19] = read_memory_xlen(virtual_address_base + 4*size, $encoding); + } + if (nreg > 5) { + X[20] = read_memory_xlen(virtual_address_base + 5*size, $encoding); + } + if (nreg > 6) { + X[21] = read_memory_xlen(virtual_address_base + 6*size, $encoding); + } + if (nreg > 7) { + X[22] = read_memory_xlen(virtual_address_base + 7*size, $encoding); + } + if (nreg > 8) { + X[23] = read_memory_xlen(virtual_address_base + 8*size, $encoding); + } + if (nreg > 9) { + X[24] = read_memory_xlen(virtual_address_base + 9*size, $encoding); + } + if (nreg > 10) { + X[25] = read_memory_xlen(virtual_address_base + 10*size, $encoding); + } + if (nreg > 11) { + X[26] = read_memory_xlen(virtual_address_base + 11*size, $encoding); + X[27] = read_memory_xlen(virtual_address_base + 12*size, $encoding); + } + + X[2] = virtual_address_new_sp; + jump(X[1]); diff --git a/arch/inst/Zcmp/cm.popretz.yaml b/arch/inst/Zcmp/cm.popretz.yaml new file mode 100644 index 000000000..d38ccde53 --- /dev/null +++ b/arch/inst/Zcmp/cm.popretz.yaml @@ -0,0 +1,85 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +$schema: "inst_schema.json#" +kind: instruction +name: cm.popretz +long_name: Destroy function call stack frame, move zero to `a0` and return to `ra`. +description: | + Destroy stack frame: load `ra` and 0 to 12 saved registers from the stack frame, deallocate the stack frame, move zero to `a0`, return to `ra`. + This instruction pops (loads) the registers in `reg_list` from stack memory, and then adjusts the stack pointer by `stack_adj`, move zero to `a0` and then return to `ra`. + + Restrictions on stack_adj: + + * it must be enough to store all of the listed registers + * it must be a multiple of 16 (bytes): + ** for RV32 the allowed values are: 16, 32, 48, 64, 80, 96, 112 + ** for RV64 the allowed values are: 16, 32, 48, 64, 80, 96, 112, 128, 144, 160 +definedBy: + anyOf: + - Zcmp +assembly: reg_list, stack_adj +encoding: + match: 10111100------10 + variables: + - name: rlist + location: 7-4 + not: [0, 1, 2, 3] + - name: spimm + location: 3-2 + left_shift: 4 +access: + s: always + u: always + vs: always + vu: always +operation(): | + if (implemented?(ExtensionName::Zcmp) && (CSR[misa].C == 1'b0)) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + XReg size = xlen(); + XReg nreg = (rlist == 15) ? 13 : (rlist - 3); + XReg stack_aligned_adj = (nreg * 4 + 15) & ~0xF; + XReg virtual_address_sp = X[2]; + XReg virtual_address_new_sp = virtual_address_sp + stack_aligned_adj + spimm; + XReg virtual_address_base = virtual_address_new_sp - (nreg * size); + + X[ 1] = read_memory_xlen(virtual_address_base + 0*size, $encoding); + if (nreg > 1) { + X[ 8] = read_memory_xlen(virtual_address_base + 1*size, $encoding); + } + if (nreg > 2) { + X[ 9] = read_memory_xlen(virtual_address_base + 2*size, $encoding); + } + if (nreg > 3) { + X[18] = read_memory_xlen(virtual_address_base + 3*size, $encoding); + } + if (nreg > 4) { + X[19] = read_memory_xlen(virtual_address_base + 4*size, $encoding); + } + if (nreg > 5) { + X[20] = read_memory_xlen(virtual_address_base + 5*size, $encoding); + } + if (nreg > 6) { + X[21] = read_memory_xlen(virtual_address_base + 6*size, $encoding); + } + if (nreg > 7) { + X[22] = read_memory_xlen(virtual_address_base + 7*size, $encoding); + } + if (nreg > 8) { + X[23] = read_memory_xlen(virtual_address_base + 8*size, $encoding); + } + if (nreg > 9) { + X[24] = read_memory_xlen(virtual_address_base + 9*size, $encoding); + } + if (nreg > 10) { + X[25] = read_memory_xlen(virtual_address_base + 10*size, $encoding); + } + if (nreg > 11) { + X[26] = read_memory_xlen(virtual_address_base + 11*size, $encoding); + X[27] = read_memory_xlen(virtual_address_base + 12*size, $encoding); + } + + X[2] = virtual_address_new_sp; + X[10] = 0; + jump(X[1]); diff --git a/arch/inst/Zcmp/cm.push.yaml b/arch/inst/Zcmp/cm.push.yaml new file mode 100644 index 000000000..dd9b840cf --- /dev/null +++ b/arch/inst/Zcmp/cm.push.yaml @@ -0,0 +1,84 @@ +# yaml-language-server: $schema=../../../schemas/inst_schema.json + +$schema: "inst_schema.json#" +kind: instruction +name: cm.push +long_name: Create function call stack frame +description: | + Create stack frame: store `ra` and 0 to 12 saved registers to the stack frame, optionally allocate additional stack space. + This instruction pushes (stores) the registers in `reg_list` to the memory below the stack pointer, + and then creates the stack frame by decrementing the stack pointer by `stack_adj`. + + Restrictions on stack_adj: + + * it must be enough to store all of the listed registers + * it must be a multiple of 16 (bytes): + ** for RV32 the allowed values are: 16, 32, 48, 64, 80, 96, 112 + ** for RV64 the allowed values are: 16, 32, 48, 64, 80, 96, 112, 128, 144, 160 +definedBy: + anyOf: + - Zcmp +assembly: reg_list, -stack_adj +encoding: + match: 10111000------10 + variables: + - name: rlist + location: 7-4 + not: [0, 1, 2, 3] + - name: spimm + location: 3-2 + left_shift: 4 +access: + s: always + u: always + vs: always + vu: always +operation(): | + if (implemented?(ExtensionName::Zcmp) && (CSR[misa].C == 1'b0)) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + XReg size = xlen(); + XReg nreg = (rlist == 15) ? 13 : (rlist - 3); + XReg stack_aligned_adj = (nreg * 4 + 15) & ~0xF; + XReg virtual_address_sp = X[2]; + XReg virtual_address_new_sp = virtual_address_sp - stack_aligned_adj - spimm; + XReg virtual_address_base = virtual_address_sp - (nreg * size); + + write_memory_xlen(virtual_address_base + 0*size, X[ 1], $encoding); + if (nreg > 1) { + write_memory_xlen(virtual_address_base + 1*size, X[ 8], $encoding); + } + if (nreg > 2) { + write_memory_xlen(virtual_address_base + 2*size, X[ 9], $encoding); + } + if (nreg > 3) { + write_memory_xlen(virtual_address_base + 3*size, X[18], $encoding); + } + if (nreg > 4) { + write_memory_xlen(virtual_address_base + 4*size, X[19], $encoding); + } + if (nreg > 5) { + write_memory_xlen(virtual_address_base + 5*size, X[20], $encoding); + } + if (nreg > 6) { + write_memory_xlen(virtual_address_base + 6*size, X[21], $encoding); + } + if (nreg > 7) { + write_memory_xlen(virtual_address_base + 7*size, X[22], $encoding); + } + if (nreg > 8) { + write_memory_xlen(virtual_address_base + 8*size, X[23], $encoding); + } + if (nreg > 9) { + write_memory_xlen(virtual_address_base + 9*size, X[24], $encoding); + } + if (nreg > 10) { + write_memory_xlen(virtual_address_base + 10*size, X[25], $encoding); + } + if (nreg > 11) { + write_memory_xlen(virtual_address_base + 11*size, X[26], $encoding); + write_memory_xlen(virtual_address_base + 12*size, X[27], $encoding); + } + + X[2] = virtual_address_new_sp; diff --git a/arch/isa/globals.isa b/arch/isa/globals.isa index 99517ba26..c5aab8005 100644 --- a/arch/isa/globals.isa +++ b/arch/isa/globals.isa @@ -2477,6 +2477,30 @@ function read_memory { } } +function read_memory_xlen { + returns Bits + arguments + XReg virtual_address, + Bits encoding # the encoding of an instruction causing this access, or 0 if a fetch + description { + Read from virtual memory XLEN bits using a known aligned address. + } + body { + TranslationResult result; + + if (CSR[misa].S == 1) { + result = translate(virtual_address, MemoryOperation::Read, effective_ldst_mode(), encoding); + } else { + result.paddr = virtual_address; + } + + # may raise an exception + access_check(result.paddr, XLEN, virtual_address, MemoryOperation::Read, ExceptionCode::LoadAccessFault, effective_ldst_mode()); + + return read_physical_memory(result.paddr); + } +} + # hart-global state to track the local reservation set Boolean reservation_set_valid = false; XReg reservation_set_address; @@ -2798,6 +2822,28 @@ function write_memory { } } +function write_memory_xlen { + arguments + XReg virtual_address, + Bits value, + Bits encoding # encoding of the instruction causing this access + description { + Write to virtual memory XLEN bits using a known aligned address. + } + body { + XReg physical_address; + + physical_address = (CSR[misa].S == 1) + ? translate(virtual_address, MemoryOperation::Write, effective_ldst_mode(), encoding).paddr + : virtual_address; + + # may raise an exception + access_check(physical_address, XLEN, virtual_address, MemoryOperation::Write, ExceptionCode::StoreAmoAccessFault, effective_ldst_mode()); + + write_physical_memory(physical_address, value); + } +} + function mstatus_sd_has_known_reset { returns Boolean