diff --git a/arch/inst/A/amoadd.d.yaml b/arch/inst/A/amoadd.d.yaml index c3c3c7296..6f15b392f 100644 --- a/arch/inst/A/amoadd.d.yaml +++ b/arch/inst/A/amoadd.d.yaml @@ -41,3 +41,98 @@ amoadd.d: XReg virtual_address = X[rs1]; X[rd] = amo<64>(virtual_address, X[rs2], AmoOperation::Add, aq, rl, $encoding); + + + + sail(): | + { + if extension("A") then { + /* Get the address, X(rs1) (no offset). + * Some extensions perform additional checks on address validity. + */ + match ext_data_get_addr(rs1, zeros(), ReadWrite(Data, Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => { + match translateAddr(vaddr, ReadWrite(Data, Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => { + let eares : MemoryOpResult(unit) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_ea(addr, 1, aq & rl, rl, true), + (HALF, _) => mem_write_ea(addr, 2, aq & rl, rl, true), + (WORD, _) => mem_write_ea(addr, 4, aq & rl, rl, true), + (DOUBLE, 64) => mem_write_ea(addr, 8, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + let is_unsigned : bool = match op { + AMOMINU => true, + AMOMAXU => true, + _ => false + }; + let rs2_val : xlenbits = match width { + BYTE => if is_unsigned then zero_extend(X(rs2)[7..0]) else sign_extend(X(rs2)[7..0]), + HALF => if is_unsigned then zero_extend(X(rs2)[15..0]) else sign_extend(X(rs2)[15..0]), + WORD => if is_unsigned then zero_extend(X(rs2)[31..0]) else sign_extend(X(rs2)[31..0]), + DOUBLE => X(rs2) + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + let mval : MemoryOpResult(xlenbits) = match (width, sizeof(xlen)) { + (BYTE, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 1, aq, aq & rl, true)), + (HALF, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 2, aq, aq & rl, true)), + (WORD, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 4, aq, aq & rl, true)), + (DOUBLE, 64) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 8, aq, aq & rl, true)), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (mval) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(loaded) => { + let result : xlenbits = + match op { + AMOSWAP => rs2_val, + AMOADD => rs2_val + loaded, + AMOXOR => rs2_val ^ loaded, + AMOAND => rs2_val & loaded, + AMOOR => rs2_val | loaded, + + /* These operations convert bitvectors to integer values using [un]signed, + * and back using to_bits(). + */ + AMOMIN => to_bits(sizeof(xlen), min(signed(rs2_val), signed(loaded))), + AMOMAX => to_bits(sizeof(xlen), max(signed(rs2_val), signed(loaded))), + AMOMINU => to_bits(sizeof(xlen), min(unsigned(rs2_val), unsigned(loaded))), + AMOMAXU => to_bits(sizeof(xlen), max(unsigned(rs2_val), unsigned(loaded))) + }; + let rval : xlenbits = match width { + BYTE => sign_extend(loaded[7..0]), + HALF => sign_extend(loaded[15..0]), + WORD => sign_extend(loaded[31..0]), + DOUBLE => loaded + }; + let wval : MemoryOpResult(bool) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_value(addr, 1, result[7..0], aq & rl, rl, true), + (HALF, _) => mem_write_value(addr, 2, result[15..0], aq & rl, rl, true), + (WORD, _) => mem_write_value(addr, 4, result[31..0], aq & rl, rl, true), + (DOUBLE, 64) => mem_write_value(addr, 8, result, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (wval) { + MemValue(true) => { X(rd) = rval; RETIRE_SUCCESS }, + MemValue(false) => { internal_error(__FILE__, __LINE__, "AMO got false from mem_write_value") }, + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } + } + } + } + } + } + } + } + } + } + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/A/amoadd.w.yaml b/arch/inst/A/amoadd.w.yaml index cdcaeb9b7..bc3527a35 100644 --- a/arch/inst/A/amoadd.w.yaml +++ b/arch/inst/A/amoadd.w.yaml @@ -40,3 +40,98 @@ amoadd.w: XReg virtual_address = X[rs1]; X[rd] = amo<32>(virtual_address, X[rs2][31:0], AmoOperation::Add, aq, rl, $encoding); + + + + sail(): | + { + if extension("A") then { + /* Get the address, X(rs1) (no offset). + * Some extensions perform additional checks on address validity. + */ + match ext_data_get_addr(rs1, zeros(), ReadWrite(Data, Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => { + match translateAddr(vaddr, ReadWrite(Data, Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => { + let eares : MemoryOpResult(unit) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_ea(addr, 1, aq & rl, rl, true), + (HALF, _) => mem_write_ea(addr, 2, aq & rl, rl, true), + (WORD, _) => mem_write_ea(addr, 4, aq & rl, rl, true), + (DOUBLE, 64) => mem_write_ea(addr, 8, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + let is_unsigned : bool = match op { + AMOMINU => true, + AMOMAXU => true, + _ => false + }; + let rs2_val : xlenbits = match width { + BYTE => if is_unsigned then zero_extend(X(rs2)[7..0]) else sign_extend(X(rs2)[7..0]), + HALF => if is_unsigned then zero_extend(X(rs2)[15..0]) else sign_extend(X(rs2)[15..0]), + WORD => if is_unsigned then zero_extend(X(rs2)[31..0]) else sign_extend(X(rs2)[31..0]), + DOUBLE => X(rs2) + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + let mval : MemoryOpResult(xlenbits) = match (width, sizeof(xlen)) { + (BYTE, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 1, aq, aq & rl, true)), + (HALF, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 2, aq, aq & rl, true)), + (WORD, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 4, aq, aq & rl, true)), + (DOUBLE, 64) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 8, aq, aq & rl, true)), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (mval) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(loaded) => { + let result : xlenbits = + match op { + AMOSWAP => rs2_val, + AMOADD => rs2_val + loaded, + AMOXOR => rs2_val ^ loaded, + AMOAND => rs2_val & loaded, + AMOOR => rs2_val | loaded, + + /* These operations convert bitvectors to integer values using [un]signed, + * and back using to_bits(). + */ + AMOMIN => to_bits(sizeof(xlen), min(signed(rs2_val), signed(loaded))), + AMOMAX => to_bits(sizeof(xlen), max(signed(rs2_val), signed(loaded))), + AMOMINU => to_bits(sizeof(xlen), min(unsigned(rs2_val), unsigned(loaded))), + AMOMAXU => to_bits(sizeof(xlen), max(unsigned(rs2_val), unsigned(loaded))) + }; + let rval : xlenbits = match width { + BYTE => sign_extend(loaded[7..0]), + HALF => sign_extend(loaded[15..0]), + WORD => sign_extend(loaded[31..0]), + DOUBLE => loaded + }; + let wval : MemoryOpResult(bool) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_value(addr, 1, result[7..0], aq & rl, rl, true), + (HALF, _) => mem_write_value(addr, 2, result[15..0], aq & rl, rl, true), + (WORD, _) => mem_write_value(addr, 4, result[31..0], aq & rl, rl, true), + (DOUBLE, 64) => mem_write_value(addr, 8, result, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (wval) { + MemValue(true) => { X(rd) = rval; RETIRE_SUCCESS }, + MemValue(false) => { internal_error(__FILE__, __LINE__, "AMO got false from mem_write_value") }, + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } + } + } + } + } + } + } + } + } + } + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/A/amoand.d.yaml b/arch/inst/A/amoand.d.yaml index 4f7a09a8d..b2a7b4414 100644 --- a/arch/inst/A/amoand.d.yaml +++ b/arch/inst/A/amoand.d.yaml @@ -41,3 +41,98 @@ amoand.d: XReg virtual_address = X[rs1]; X[rd] = amo<64>(virtual_address, X[rs2], AmoOperation::And, aq, rl, $encoding); + + + + sail(): | + { + if extension("A") then { + /* Get the address, X(rs1) (no offset). + * Some extensions perform additional checks on address validity. + */ + match ext_data_get_addr(rs1, zeros(), ReadWrite(Data, Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => { + match translateAddr(vaddr, ReadWrite(Data, Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => { + let eares : MemoryOpResult(unit) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_ea(addr, 1, aq & rl, rl, true), + (HALF, _) => mem_write_ea(addr, 2, aq & rl, rl, true), + (WORD, _) => mem_write_ea(addr, 4, aq & rl, rl, true), + (DOUBLE, 64) => mem_write_ea(addr, 8, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + let is_unsigned : bool = match op { + AMOMINU => true, + AMOMAXU => true, + _ => false + }; + let rs2_val : xlenbits = match width { + BYTE => if is_unsigned then zero_extend(X(rs2)[7..0]) else sign_extend(X(rs2)[7..0]), + HALF => if is_unsigned then zero_extend(X(rs2)[15..0]) else sign_extend(X(rs2)[15..0]), + WORD => if is_unsigned then zero_extend(X(rs2)[31..0]) else sign_extend(X(rs2)[31..0]), + DOUBLE => X(rs2) + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + let mval : MemoryOpResult(xlenbits) = match (width, sizeof(xlen)) { + (BYTE, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 1, aq, aq & rl, true)), + (HALF, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 2, aq, aq & rl, true)), + (WORD, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 4, aq, aq & rl, true)), + (DOUBLE, 64) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 8, aq, aq & rl, true)), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (mval) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(loaded) => { + let result : xlenbits = + match op { + AMOSWAP => rs2_val, + AMOADD => rs2_val + loaded, + AMOXOR => rs2_val ^ loaded, + AMOAND => rs2_val & loaded, + AMOOR => rs2_val | loaded, + + /* These operations convert bitvectors to integer values using [un]signed, + * and back using to_bits(). + */ + AMOMIN => to_bits(sizeof(xlen), min(signed(rs2_val), signed(loaded))), + AMOMAX => to_bits(sizeof(xlen), max(signed(rs2_val), signed(loaded))), + AMOMINU => to_bits(sizeof(xlen), min(unsigned(rs2_val), unsigned(loaded))), + AMOMAXU => to_bits(sizeof(xlen), max(unsigned(rs2_val), unsigned(loaded))) + }; + let rval : xlenbits = match width { + BYTE => sign_extend(loaded[7..0]), + HALF => sign_extend(loaded[15..0]), + WORD => sign_extend(loaded[31..0]), + DOUBLE => loaded + }; + let wval : MemoryOpResult(bool) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_value(addr, 1, result[7..0], aq & rl, rl, true), + (HALF, _) => mem_write_value(addr, 2, result[15..0], aq & rl, rl, true), + (WORD, _) => mem_write_value(addr, 4, result[31..0], aq & rl, rl, true), + (DOUBLE, 64) => mem_write_value(addr, 8, result, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (wval) { + MemValue(true) => { X(rd) = rval; RETIRE_SUCCESS }, + MemValue(false) => { internal_error(__FILE__, __LINE__, "AMO got false from mem_write_value") }, + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } + } + } + } + } + } + } + } + } + } + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/A/amoand.w.yaml b/arch/inst/A/amoand.w.yaml index c6650eb97..98a656da9 100644 --- a/arch/inst/A/amoand.w.yaml +++ b/arch/inst/A/amoand.w.yaml @@ -40,3 +40,98 @@ amoand.w: XReg virtual_address = X[rs1]; X[rd] = amo<32>(virtual_address, X[rs2][31:0], AmoOperation::And, aq, rl, $encoding); + + + + sail(): | + { + if extension("A") then { + /* Get the address, X(rs1) (no offset). + * Some extensions perform additional checks on address validity. + */ + match ext_data_get_addr(rs1, zeros(), ReadWrite(Data, Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => { + match translateAddr(vaddr, ReadWrite(Data, Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => { + let eares : MemoryOpResult(unit) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_ea(addr, 1, aq & rl, rl, true), + (HALF, _) => mem_write_ea(addr, 2, aq & rl, rl, true), + (WORD, _) => mem_write_ea(addr, 4, aq & rl, rl, true), + (DOUBLE, 64) => mem_write_ea(addr, 8, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + let is_unsigned : bool = match op { + AMOMINU => true, + AMOMAXU => true, + _ => false + }; + let rs2_val : xlenbits = match width { + BYTE => if is_unsigned then zero_extend(X(rs2)[7..0]) else sign_extend(X(rs2)[7..0]), + HALF => if is_unsigned then zero_extend(X(rs2)[15..0]) else sign_extend(X(rs2)[15..0]), + WORD => if is_unsigned then zero_extend(X(rs2)[31..0]) else sign_extend(X(rs2)[31..0]), + DOUBLE => X(rs2) + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + let mval : MemoryOpResult(xlenbits) = match (width, sizeof(xlen)) { + (BYTE, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 1, aq, aq & rl, true)), + (HALF, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 2, aq, aq & rl, true)), + (WORD, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 4, aq, aq & rl, true)), + (DOUBLE, 64) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 8, aq, aq & rl, true)), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (mval) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(loaded) => { + let result : xlenbits = + match op { + AMOSWAP => rs2_val, + AMOADD => rs2_val + loaded, + AMOXOR => rs2_val ^ loaded, + AMOAND => rs2_val & loaded, + AMOOR => rs2_val | loaded, + + /* These operations convert bitvectors to integer values using [un]signed, + * and back using to_bits(). + */ + AMOMIN => to_bits(sizeof(xlen), min(signed(rs2_val), signed(loaded))), + AMOMAX => to_bits(sizeof(xlen), max(signed(rs2_val), signed(loaded))), + AMOMINU => to_bits(sizeof(xlen), min(unsigned(rs2_val), unsigned(loaded))), + AMOMAXU => to_bits(sizeof(xlen), max(unsigned(rs2_val), unsigned(loaded))) + }; + let rval : xlenbits = match width { + BYTE => sign_extend(loaded[7..0]), + HALF => sign_extend(loaded[15..0]), + WORD => sign_extend(loaded[31..0]), + DOUBLE => loaded + }; + let wval : MemoryOpResult(bool) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_value(addr, 1, result[7..0], aq & rl, rl, true), + (HALF, _) => mem_write_value(addr, 2, result[15..0], aq & rl, rl, true), + (WORD, _) => mem_write_value(addr, 4, result[31..0], aq & rl, rl, true), + (DOUBLE, 64) => mem_write_value(addr, 8, result, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (wval) { + MemValue(true) => { X(rd) = rval; RETIRE_SUCCESS }, + MemValue(false) => { internal_error(__FILE__, __LINE__, "AMO got false from mem_write_value") }, + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } + } + } + } + } + } + } + } + } + } + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/A/amomax.d.yaml b/arch/inst/A/amomax.d.yaml index cb22bbd68..f5099364b 100644 --- a/arch/inst/A/amomax.d.yaml +++ b/arch/inst/A/amomax.d.yaml @@ -41,3 +41,98 @@ amomax.d: XReg virtual_address = X[rs1]; X[rd] = amo<64>(virtual_address, X[rs2], AmoOperation::Max, aq, rl, $encoding); + + + + sail(): | + { + if extension("A") then { + /* Get the address, X(rs1) (no offset). + * Some extensions perform additional checks on address validity. + */ + match ext_data_get_addr(rs1, zeros(), ReadWrite(Data, Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => { + match translateAddr(vaddr, ReadWrite(Data, Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => { + let eares : MemoryOpResult(unit) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_ea(addr, 1, aq & rl, rl, true), + (HALF, _) => mem_write_ea(addr, 2, aq & rl, rl, true), + (WORD, _) => mem_write_ea(addr, 4, aq & rl, rl, true), + (DOUBLE, 64) => mem_write_ea(addr, 8, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + let is_unsigned : bool = match op { + AMOMINU => true, + AMOMAXU => true, + _ => false + }; + let rs2_val : xlenbits = match width { + BYTE => if is_unsigned then zero_extend(X(rs2)[7..0]) else sign_extend(X(rs2)[7..0]), + HALF => if is_unsigned then zero_extend(X(rs2)[15..0]) else sign_extend(X(rs2)[15..0]), + WORD => if is_unsigned then zero_extend(X(rs2)[31..0]) else sign_extend(X(rs2)[31..0]), + DOUBLE => X(rs2) + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + let mval : MemoryOpResult(xlenbits) = match (width, sizeof(xlen)) { + (BYTE, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 1, aq, aq & rl, true)), + (HALF, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 2, aq, aq & rl, true)), + (WORD, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 4, aq, aq & rl, true)), + (DOUBLE, 64) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 8, aq, aq & rl, true)), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (mval) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(loaded) => { + let result : xlenbits = + match op { + AMOSWAP => rs2_val, + AMOADD => rs2_val + loaded, + AMOXOR => rs2_val ^ loaded, + AMOAND => rs2_val & loaded, + AMOOR => rs2_val | loaded, + + /* These operations convert bitvectors to integer values using [un]signed, + * and back using to_bits(). + */ + AMOMIN => to_bits(sizeof(xlen), min(signed(rs2_val), signed(loaded))), + AMOMAX => to_bits(sizeof(xlen), max(signed(rs2_val), signed(loaded))), + AMOMINU => to_bits(sizeof(xlen), min(unsigned(rs2_val), unsigned(loaded))), + AMOMAXU => to_bits(sizeof(xlen), max(unsigned(rs2_val), unsigned(loaded))) + }; + let rval : xlenbits = match width { + BYTE => sign_extend(loaded[7..0]), + HALF => sign_extend(loaded[15..0]), + WORD => sign_extend(loaded[31..0]), + DOUBLE => loaded + }; + let wval : MemoryOpResult(bool) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_value(addr, 1, result[7..0], aq & rl, rl, true), + (HALF, _) => mem_write_value(addr, 2, result[15..0], aq & rl, rl, true), + (WORD, _) => mem_write_value(addr, 4, result[31..0], aq & rl, rl, true), + (DOUBLE, 64) => mem_write_value(addr, 8, result, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (wval) { + MemValue(true) => { X(rd) = rval; RETIRE_SUCCESS }, + MemValue(false) => { internal_error(__FILE__, __LINE__, "AMO got false from mem_write_value") }, + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } + } + } + } + } + } + } + } + } + } + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/A/amomax.w.yaml b/arch/inst/A/amomax.w.yaml index b1ece79ca..ab505d5e9 100644 --- a/arch/inst/A/amomax.w.yaml +++ b/arch/inst/A/amomax.w.yaml @@ -40,3 +40,98 @@ amomax.w: XReg virtual_address = X[rs1]; X[rd] = amo<32>(virtual_address, X[rs2][31:0], AmoOperation::Max, aq, rl, $encoding); + + + + sail(): | + { + if extension("A") then { + /* Get the address, X(rs1) (no offset). + * Some extensions perform additional checks on address validity. + */ + match ext_data_get_addr(rs1, zeros(), ReadWrite(Data, Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => { + match translateAddr(vaddr, ReadWrite(Data, Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => { + let eares : MemoryOpResult(unit) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_ea(addr, 1, aq & rl, rl, true), + (HALF, _) => mem_write_ea(addr, 2, aq & rl, rl, true), + (WORD, _) => mem_write_ea(addr, 4, aq & rl, rl, true), + (DOUBLE, 64) => mem_write_ea(addr, 8, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + let is_unsigned : bool = match op { + AMOMINU => true, + AMOMAXU => true, + _ => false + }; + let rs2_val : xlenbits = match width { + BYTE => if is_unsigned then zero_extend(X(rs2)[7..0]) else sign_extend(X(rs2)[7..0]), + HALF => if is_unsigned then zero_extend(X(rs2)[15..0]) else sign_extend(X(rs2)[15..0]), + WORD => if is_unsigned then zero_extend(X(rs2)[31..0]) else sign_extend(X(rs2)[31..0]), + DOUBLE => X(rs2) + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + let mval : MemoryOpResult(xlenbits) = match (width, sizeof(xlen)) { + (BYTE, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 1, aq, aq & rl, true)), + (HALF, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 2, aq, aq & rl, true)), + (WORD, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 4, aq, aq & rl, true)), + (DOUBLE, 64) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 8, aq, aq & rl, true)), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (mval) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(loaded) => { + let result : xlenbits = + match op { + AMOSWAP => rs2_val, + AMOADD => rs2_val + loaded, + AMOXOR => rs2_val ^ loaded, + AMOAND => rs2_val & loaded, + AMOOR => rs2_val | loaded, + + /* These operations convert bitvectors to integer values using [un]signed, + * and back using to_bits(). + */ + AMOMIN => to_bits(sizeof(xlen), min(signed(rs2_val), signed(loaded))), + AMOMAX => to_bits(sizeof(xlen), max(signed(rs2_val), signed(loaded))), + AMOMINU => to_bits(sizeof(xlen), min(unsigned(rs2_val), unsigned(loaded))), + AMOMAXU => to_bits(sizeof(xlen), max(unsigned(rs2_val), unsigned(loaded))) + }; + let rval : xlenbits = match width { + BYTE => sign_extend(loaded[7..0]), + HALF => sign_extend(loaded[15..0]), + WORD => sign_extend(loaded[31..0]), + DOUBLE => loaded + }; + let wval : MemoryOpResult(bool) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_value(addr, 1, result[7..0], aq & rl, rl, true), + (HALF, _) => mem_write_value(addr, 2, result[15..0], aq & rl, rl, true), + (WORD, _) => mem_write_value(addr, 4, result[31..0], aq & rl, rl, true), + (DOUBLE, 64) => mem_write_value(addr, 8, result, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (wval) { + MemValue(true) => { X(rd) = rval; RETIRE_SUCCESS }, + MemValue(false) => { internal_error(__FILE__, __LINE__, "AMO got false from mem_write_value") }, + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } + } + } + } + } + } + } + } + } + } + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/A/amomaxu.d.yaml b/arch/inst/A/amomaxu.d.yaml index e6ae5d0de..038e2e25e 100644 --- a/arch/inst/A/amomaxu.d.yaml +++ b/arch/inst/A/amomaxu.d.yaml @@ -40,3 +40,98 @@ amomaxu.d: XReg virtual_address = X[rs1]; X[rd] = amo<64>(virtual_address, X[rs2], AmoOperation::Maxu, aq, rl, $encoding); + + + + sail(): | + { + if extension("A") then { + /* Get the address, X(rs1) (no offset). + * Some extensions perform additional checks on address validity. + */ + match ext_data_get_addr(rs1, zeros(), ReadWrite(Data, Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => { + match translateAddr(vaddr, ReadWrite(Data, Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => { + let eares : MemoryOpResult(unit) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_ea(addr, 1, aq & rl, rl, true), + (HALF, _) => mem_write_ea(addr, 2, aq & rl, rl, true), + (WORD, _) => mem_write_ea(addr, 4, aq & rl, rl, true), + (DOUBLE, 64) => mem_write_ea(addr, 8, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + let is_unsigned : bool = match op { + AMOMINU => true, + AMOMAXU => true, + _ => false + }; + let rs2_val : xlenbits = match width { + BYTE => if is_unsigned then zero_extend(X(rs2)[7..0]) else sign_extend(X(rs2)[7..0]), + HALF => if is_unsigned then zero_extend(X(rs2)[15..0]) else sign_extend(X(rs2)[15..0]), + WORD => if is_unsigned then zero_extend(X(rs2)[31..0]) else sign_extend(X(rs2)[31..0]), + DOUBLE => X(rs2) + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + let mval : MemoryOpResult(xlenbits) = match (width, sizeof(xlen)) { + (BYTE, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 1, aq, aq & rl, true)), + (HALF, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 2, aq, aq & rl, true)), + (WORD, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 4, aq, aq & rl, true)), + (DOUBLE, 64) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 8, aq, aq & rl, true)), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (mval) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(loaded) => { + let result : xlenbits = + match op { + AMOSWAP => rs2_val, + AMOADD => rs2_val + loaded, + AMOXOR => rs2_val ^ loaded, + AMOAND => rs2_val & loaded, + AMOOR => rs2_val | loaded, + + /* These operations convert bitvectors to integer values using [un]signed, + * and back using to_bits(). + */ + AMOMIN => to_bits(sizeof(xlen), min(signed(rs2_val), signed(loaded))), + AMOMAX => to_bits(sizeof(xlen), max(signed(rs2_val), signed(loaded))), + AMOMINU => to_bits(sizeof(xlen), min(unsigned(rs2_val), unsigned(loaded))), + AMOMAXU => to_bits(sizeof(xlen), max(unsigned(rs2_val), unsigned(loaded))) + }; + let rval : xlenbits = match width { + BYTE => sign_extend(loaded[7..0]), + HALF => sign_extend(loaded[15..0]), + WORD => sign_extend(loaded[31..0]), + DOUBLE => loaded + }; + let wval : MemoryOpResult(bool) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_value(addr, 1, result[7..0], aq & rl, rl, true), + (HALF, _) => mem_write_value(addr, 2, result[15..0], aq & rl, rl, true), + (WORD, _) => mem_write_value(addr, 4, result[31..0], aq & rl, rl, true), + (DOUBLE, 64) => mem_write_value(addr, 8, result, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (wval) { + MemValue(true) => { X(rd) = rval; RETIRE_SUCCESS }, + MemValue(false) => { internal_error(__FILE__, __LINE__, "AMO got false from mem_write_value") }, + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } + } + } + } + } + } + } + } + } + } + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/A/amomaxu.w.yaml b/arch/inst/A/amomaxu.w.yaml index 7f28e3f82..ccd3628f9 100644 --- a/arch/inst/A/amomaxu.w.yaml +++ b/arch/inst/A/amomaxu.w.yaml @@ -40,3 +40,98 @@ amomaxu.w: XReg virtual_address = X[rs1]; X[rd] = amo<32>(virtual_address, X[rs2][31:0], AmoOperation::Maxu, aq, rl, $encoding); + + + + sail(): | + { + if extension("A") then { + /* Get the address, X(rs1) (no offset). + * Some extensions perform additional checks on address validity. + */ + match ext_data_get_addr(rs1, zeros(), ReadWrite(Data, Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => { + match translateAddr(vaddr, ReadWrite(Data, Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => { + let eares : MemoryOpResult(unit) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_ea(addr, 1, aq & rl, rl, true), + (HALF, _) => mem_write_ea(addr, 2, aq & rl, rl, true), + (WORD, _) => mem_write_ea(addr, 4, aq & rl, rl, true), + (DOUBLE, 64) => mem_write_ea(addr, 8, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + let is_unsigned : bool = match op { + AMOMINU => true, + AMOMAXU => true, + _ => false + }; + let rs2_val : xlenbits = match width { + BYTE => if is_unsigned then zero_extend(X(rs2)[7..0]) else sign_extend(X(rs2)[7..0]), + HALF => if is_unsigned then zero_extend(X(rs2)[15..0]) else sign_extend(X(rs2)[15..0]), + WORD => if is_unsigned then zero_extend(X(rs2)[31..0]) else sign_extend(X(rs2)[31..0]), + DOUBLE => X(rs2) + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + let mval : MemoryOpResult(xlenbits) = match (width, sizeof(xlen)) { + (BYTE, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 1, aq, aq & rl, true)), + (HALF, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 2, aq, aq & rl, true)), + (WORD, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 4, aq, aq & rl, true)), + (DOUBLE, 64) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 8, aq, aq & rl, true)), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (mval) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(loaded) => { + let result : xlenbits = + match op { + AMOSWAP => rs2_val, + AMOADD => rs2_val + loaded, + AMOXOR => rs2_val ^ loaded, + AMOAND => rs2_val & loaded, + AMOOR => rs2_val | loaded, + + /* These operations convert bitvectors to integer values using [un]signed, + * and back using to_bits(). + */ + AMOMIN => to_bits(sizeof(xlen), min(signed(rs2_val), signed(loaded))), + AMOMAX => to_bits(sizeof(xlen), max(signed(rs2_val), signed(loaded))), + AMOMINU => to_bits(sizeof(xlen), min(unsigned(rs2_val), unsigned(loaded))), + AMOMAXU => to_bits(sizeof(xlen), max(unsigned(rs2_val), unsigned(loaded))) + }; + let rval : xlenbits = match width { + BYTE => sign_extend(loaded[7..0]), + HALF => sign_extend(loaded[15..0]), + WORD => sign_extend(loaded[31..0]), + DOUBLE => loaded + }; + let wval : MemoryOpResult(bool) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_value(addr, 1, result[7..0], aq & rl, rl, true), + (HALF, _) => mem_write_value(addr, 2, result[15..0], aq & rl, rl, true), + (WORD, _) => mem_write_value(addr, 4, result[31..0], aq & rl, rl, true), + (DOUBLE, 64) => mem_write_value(addr, 8, result, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (wval) { + MemValue(true) => { X(rd) = rval; RETIRE_SUCCESS }, + MemValue(false) => { internal_error(__FILE__, __LINE__, "AMO got false from mem_write_value") }, + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } + } + } + } + } + } + } + } + } + } + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/A/amomin.d.yaml b/arch/inst/A/amomin.d.yaml index 6d08737d3..8c384ce9d 100644 --- a/arch/inst/A/amomin.d.yaml +++ b/arch/inst/A/amomin.d.yaml @@ -41,3 +41,98 @@ amomin.d: XReg virtual_address = X[rs1]; X[rd] = amo<64>(virtual_address, X[rs2], AmoOperation::Min, aq, rl, $encoding); + + + + sail(): | + { + if extension("A") then { + /* Get the address, X(rs1) (no offset). + * Some extensions perform additional checks on address validity. + */ + match ext_data_get_addr(rs1, zeros(), ReadWrite(Data, Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => { + match translateAddr(vaddr, ReadWrite(Data, Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => { + let eares : MemoryOpResult(unit) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_ea(addr, 1, aq & rl, rl, true), + (HALF, _) => mem_write_ea(addr, 2, aq & rl, rl, true), + (WORD, _) => mem_write_ea(addr, 4, aq & rl, rl, true), + (DOUBLE, 64) => mem_write_ea(addr, 8, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + let is_unsigned : bool = match op { + AMOMINU => true, + AMOMAXU => true, + _ => false + }; + let rs2_val : xlenbits = match width { + BYTE => if is_unsigned then zero_extend(X(rs2)[7..0]) else sign_extend(X(rs2)[7..0]), + HALF => if is_unsigned then zero_extend(X(rs2)[15..0]) else sign_extend(X(rs2)[15..0]), + WORD => if is_unsigned then zero_extend(X(rs2)[31..0]) else sign_extend(X(rs2)[31..0]), + DOUBLE => X(rs2) + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + let mval : MemoryOpResult(xlenbits) = match (width, sizeof(xlen)) { + (BYTE, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 1, aq, aq & rl, true)), + (HALF, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 2, aq, aq & rl, true)), + (WORD, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 4, aq, aq & rl, true)), + (DOUBLE, 64) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 8, aq, aq & rl, true)), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (mval) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(loaded) => { + let result : xlenbits = + match op { + AMOSWAP => rs2_val, + AMOADD => rs2_val + loaded, + AMOXOR => rs2_val ^ loaded, + AMOAND => rs2_val & loaded, + AMOOR => rs2_val | loaded, + + /* These operations convert bitvectors to integer values using [un]signed, + * and back using to_bits(). + */ + AMOMIN => to_bits(sizeof(xlen), min(signed(rs2_val), signed(loaded))), + AMOMAX => to_bits(sizeof(xlen), max(signed(rs2_val), signed(loaded))), + AMOMINU => to_bits(sizeof(xlen), min(unsigned(rs2_val), unsigned(loaded))), + AMOMAXU => to_bits(sizeof(xlen), max(unsigned(rs2_val), unsigned(loaded))) + }; + let rval : xlenbits = match width { + BYTE => sign_extend(loaded[7..0]), + HALF => sign_extend(loaded[15..0]), + WORD => sign_extend(loaded[31..0]), + DOUBLE => loaded + }; + let wval : MemoryOpResult(bool) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_value(addr, 1, result[7..0], aq & rl, rl, true), + (HALF, _) => mem_write_value(addr, 2, result[15..0], aq & rl, rl, true), + (WORD, _) => mem_write_value(addr, 4, result[31..0], aq & rl, rl, true), + (DOUBLE, 64) => mem_write_value(addr, 8, result, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (wval) { + MemValue(true) => { X(rd) = rval; RETIRE_SUCCESS }, + MemValue(false) => { internal_error(__FILE__, __LINE__, "AMO got false from mem_write_value") }, + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } + } + } + } + } + } + } + } + } + } + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/A/amomin.w.yaml b/arch/inst/A/amomin.w.yaml index dfbff3c11..b41f4f6d3 100644 --- a/arch/inst/A/amomin.w.yaml +++ b/arch/inst/A/amomin.w.yaml @@ -40,3 +40,98 @@ amomin.w: XReg virtual_address = X[rs1]; X[rd] = amo<32>(virtual_address, X[rs2][31:0], AmoOperation::Min, aq, rl, $encoding); + + + + sail(): | + { + if extension("A") then { + /* Get the address, X(rs1) (no offset). + * Some extensions perform additional checks on address validity. + */ + match ext_data_get_addr(rs1, zeros(), ReadWrite(Data, Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => { + match translateAddr(vaddr, ReadWrite(Data, Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => { + let eares : MemoryOpResult(unit) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_ea(addr, 1, aq & rl, rl, true), + (HALF, _) => mem_write_ea(addr, 2, aq & rl, rl, true), + (WORD, _) => mem_write_ea(addr, 4, aq & rl, rl, true), + (DOUBLE, 64) => mem_write_ea(addr, 8, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + let is_unsigned : bool = match op { + AMOMINU => true, + AMOMAXU => true, + _ => false + }; + let rs2_val : xlenbits = match width { + BYTE => if is_unsigned then zero_extend(X(rs2)[7..0]) else sign_extend(X(rs2)[7..0]), + HALF => if is_unsigned then zero_extend(X(rs2)[15..0]) else sign_extend(X(rs2)[15..0]), + WORD => if is_unsigned then zero_extend(X(rs2)[31..0]) else sign_extend(X(rs2)[31..0]), + DOUBLE => X(rs2) + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + let mval : MemoryOpResult(xlenbits) = match (width, sizeof(xlen)) { + (BYTE, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 1, aq, aq & rl, true)), + (HALF, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 2, aq, aq & rl, true)), + (WORD, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 4, aq, aq & rl, true)), + (DOUBLE, 64) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 8, aq, aq & rl, true)), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (mval) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(loaded) => { + let result : xlenbits = + match op { + AMOSWAP => rs2_val, + AMOADD => rs2_val + loaded, + AMOXOR => rs2_val ^ loaded, + AMOAND => rs2_val & loaded, + AMOOR => rs2_val | loaded, + + /* These operations convert bitvectors to integer values using [un]signed, + * and back using to_bits(). + */ + AMOMIN => to_bits(sizeof(xlen), min(signed(rs2_val), signed(loaded))), + AMOMAX => to_bits(sizeof(xlen), max(signed(rs2_val), signed(loaded))), + AMOMINU => to_bits(sizeof(xlen), min(unsigned(rs2_val), unsigned(loaded))), + AMOMAXU => to_bits(sizeof(xlen), max(unsigned(rs2_val), unsigned(loaded))) + }; + let rval : xlenbits = match width { + BYTE => sign_extend(loaded[7..0]), + HALF => sign_extend(loaded[15..0]), + WORD => sign_extend(loaded[31..0]), + DOUBLE => loaded + }; + let wval : MemoryOpResult(bool) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_value(addr, 1, result[7..0], aq & rl, rl, true), + (HALF, _) => mem_write_value(addr, 2, result[15..0], aq & rl, rl, true), + (WORD, _) => mem_write_value(addr, 4, result[31..0], aq & rl, rl, true), + (DOUBLE, 64) => mem_write_value(addr, 8, result, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (wval) { + MemValue(true) => { X(rd) = rval; RETIRE_SUCCESS }, + MemValue(false) => { internal_error(__FILE__, __LINE__, "AMO got false from mem_write_value") }, + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } + } + } + } + } + } + } + } + } + } + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/A/amominu.d.yaml b/arch/inst/A/amominu.d.yaml index c0499c83b..ac9632879 100644 --- a/arch/inst/A/amominu.d.yaml +++ b/arch/inst/A/amominu.d.yaml @@ -41,3 +41,98 @@ amominu.d: XReg virtual_address = X[rs1]; X[rd] = amo<64>(virtual_address, X[rs2], AmoOperation::Minu, aq, rl, $encoding); + + + + sail(): | + { + if extension("A") then { + /* Get the address, X(rs1) (no offset). + * Some extensions perform additional checks on address validity. + */ + match ext_data_get_addr(rs1, zeros(), ReadWrite(Data, Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => { + match translateAddr(vaddr, ReadWrite(Data, Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => { + let eares : MemoryOpResult(unit) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_ea(addr, 1, aq & rl, rl, true), + (HALF, _) => mem_write_ea(addr, 2, aq & rl, rl, true), + (WORD, _) => mem_write_ea(addr, 4, aq & rl, rl, true), + (DOUBLE, 64) => mem_write_ea(addr, 8, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + let is_unsigned : bool = match op { + AMOMINU => true, + AMOMAXU => true, + _ => false + }; + let rs2_val : xlenbits = match width { + BYTE => if is_unsigned then zero_extend(X(rs2)[7..0]) else sign_extend(X(rs2)[7..0]), + HALF => if is_unsigned then zero_extend(X(rs2)[15..0]) else sign_extend(X(rs2)[15..0]), + WORD => if is_unsigned then zero_extend(X(rs2)[31..0]) else sign_extend(X(rs2)[31..0]), + DOUBLE => X(rs2) + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + let mval : MemoryOpResult(xlenbits) = match (width, sizeof(xlen)) { + (BYTE, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 1, aq, aq & rl, true)), + (HALF, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 2, aq, aq & rl, true)), + (WORD, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 4, aq, aq & rl, true)), + (DOUBLE, 64) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 8, aq, aq & rl, true)), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (mval) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(loaded) => { + let result : xlenbits = + match op { + AMOSWAP => rs2_val, + AMOADD => rs2_val + loaded, + AMOXOR => rs2_val ^ loaded, + AMOAND => rs2_val & loaded, + AMOOR => rs2_val | loaded, + + /* These operations convert bitvectors to integer values using [un]signed, + * and back using to_bits(). + */ + AMOMIN => to_bits(sizeof(xlen), min(signed(rs2_val), signed(loaded))), + AMOMAX => to_bits(sizeof(xlen), max(signed(rs2_val), signed(loaded))), + AMOMINU => to_bits(sizeof(xlen), min(unsigned(rs2_val), unsigned(loaded))), + AMOMAXU => to_bits(sizeof(xlen), max(unsigned(rs2_val), unsigned(loaded))) + }; + let rval : xlenbits = match width { + BYTE => sign_extend(loaded[7..0]), + HALF => sign_extend(loaded[15..0]), + WORD => sign_extend(loaded[31..0]), + DOUBLE => loaded + }; + let wval : MemoryOpResult(bool) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_value(addr, 1, result[7..0], aq & rl, rl, true), + (HALF, _) => mem_write_value(addr, 2, result[15..0], aq & rl, rl, true), + (WORD, _) => mem_write_value(addr, 4, result[31..0], aq & rl, rl, true), + (DOUBLE, 64) => mem_write_value(addr, 8, result, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (wval) { + MemValue(true) => { X(rd) = rval; RETIRE_SUCCESS }, + MemValue(false) => { internal_error(__FILE__, __LINE__, "AMO got false from mem_write_value") }, + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } + } + } + } + } + } + } + } + } + } + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/A/amominu.w.yaml b/arch/inst/A/amominu.w.yaml index c12c3a597..79d01e660 100644 --- a/arch/inst/A/amominu.w.yaml +++ b/arch/inst/A/amominu.w.yaml @@ -40,3 +40,98 @@ amominu.w: XReg virtual_address = X[rs1]; X[rd] = amo<32>(virtual_address, X[rs2][31:0], AmoOperation::Minu, aq, rl, $encoding); + + + + sail(): | + { + if extension("A") then { + /* Get the address, X(rs1) (no offset). + * Some extensions perform additional checks on address validity. + */ + match ext_data_get_addr(rs1, zeros(), ReadWrite(Data, Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => { + match translateAddr(vaddr, ReadWrite(Data, Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => { + let eares : MemoryOpResult(unit) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_ea(addr, 1, aq & rl, rl, true), + (HALF, _) => mem_write_ea(addr, 2, aq & rl, rl, true), + (WORD, _) => mem_write_ea(addr, 4, aq & rl, rl, true), + (DOUBLE, 64) => mem_write_ea(addr, 8, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + let is_unsigned : bool = match op { + AMOMINU => true, + AMOMAXU => true, + _ => false + }; + let rs2_val : xlenbits = match width { + BYTE => if is_unsigned then zero_extend(X(rs2)[7..0]) else sign_extend(X(rs2)[7..0]), + HALF => if is_unsigned then zero_extend(X(rs2)[15..0]) else sign_extend(X(rs2)[15..0]), + WORD => if is_unsigned then zero_extend(X(rs2)[31..0]) else sign_extend(X(rs2)[31..0]), + DOUBLE => X(rs2) + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + let mval : MemoryOpResult(xlenbits) = match (width, sizeof(xlen)) { + (BYTE, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 1, aq, aq & rl, true)), + (HALF, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 2, aq, aq & rl, true)), + (WORD, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 4, aq, aq & rl, true)), + (DOUBLE, 64) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 8, aq, aq & rl, true)), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (mval) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(loaded) => { + let result : xlenbits = + match op { + AMOSWAP => rs2_val, + AMOADD => rs2_val + loaded, + AMOXOR => rs2_val ^ loaded, + AMOAND => rs2_val & loaded, + AMOOR => rs2_val | loaded, + + /* These operations convert bitvectors to integer values using [un]signed, + * and back using to_bits(). + */ + AMOMIN => to_bits(sizeof(xlen), min(signed(rs2_val), signed(loaded))), + AMOMAX => to_bits(sizeof(xlen), max(signed(rs2_val), signed(loaded))), + AMOMINU => to_bits(sizeof(xlen), min(unsigned(rs2_val), unsigned(loaded))), + AMOMAXU => to_bits(sizeof(xlen), max(unsigned(rs2_val), unsigned(loaded))) + }; + let rval : xlenbits = match width { + BYTE => sign_extend(loaded[7..0]), + HALF => sign_extend(loaded[15..0]), + WORD => sign_extend(loaded[31..0]), + DOUBLE => loaded + }; + let wval : MemoryOpResult(bool) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_value(addr, 1, result[7..0], aq & rl, rl, true), + (HALF, _) => mem_write_value(addr, 2, result[15..0], aq & rl, rl, true), + (WORD, _) => mem_write_value(addr, 4, result[31..0], aq & rl, rl, true), + (DOUBLE, 64) => mem_write_value(addr, 8, result, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (wval) { + MemValue(true) => { X(rd) = rval; RETIRE_SUCCESS }, + MemValue(false) => { internal_error(__FILE__, __LINE__, "AMO got false from mem_write_value") }, + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } + } + } + } + } + } + } + } + } + } + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/A/amoor.d.yaml b/arch/inst/A/amoor.d.yaml index f9e18cbf7..392309d26 100644 --- a/arch/inst/A/amoor.d.yaml +++ b/arch/inst/A/amoor.d.yaml @@ -41,3 +41,98 @@ amoor.d: XReg virtual_address = X[rs1]; X[rd] = amo<64>(virtual_address, X[rs2], AmoOperation::Or, aq, rl, $encoding); + + + + sail(): | + { + if extension("A") then { + /* Get the address, X(rs1) (no offset). + * Some extensions perform additional checks on address validity. + */ + match ext_data_get_addr(rs1, zeros(), ReadWrite(Data, Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => { + match translateAddr(vaddr, ReadWrite(Data, Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => { + let eares : MemoryOpResult(unit) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_ea(addr, 1, aq & rl, rl, true), + (HALF, _) => mem_write_ea(addr, 2, aq & rl, rl, true), + (WORD, _) => mem_write_ea(addr, 4, aq & rl, rl, true), + (DOUBLE, 64) => mem_write_ea(addr, 8, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + let is_unsigned : bool = match op { + AMOMINU => true, + AMOMAXU => true, + _ => false + }; + let rs2_val : xlenbits = match width { + BYTE => if is_unsigned then zero_extend(X(rs2)[7..0]) else sign_extend(X(rs2)[7..0]), + HALF => if is_unsigned then zero_extend(X(rs2)[15..0]) else sign_extend(X(rs2)[15..0]), + WORD => if is_unsigned then zero_extend(X(rs2)[31..0]) else sign_extend(X(rs2)[31..0]), + DOUBLE => X(rs2) + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + let mval : MemoryOpResult(xlenbits) = match (width, sizeof(xlen)) { + (BYTE, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 1, aq, aq & rl, true)), + (HALF, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 2, aq, aq & rl, true)), + (WORD, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 4, aq, aq & rl, true)), + (DOUBLE, 64) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 8, aq, aq & rl, true)), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (mval) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(loaded) => { + let result : xlenbits = + match op { + AMOSWAP => rs2_val, + AMOADD => rs2_val + loaded, + AMOXOR => rs2_val ^ loaded, + AMOAND => rs2_val & loaded, + AMOOR => rs2_val | loaded, + + /* These operations convert bitvectors to integer values using [un]signed, + * and back using to_bits(). + */ + AMOMIN => to_bits(sizeof(xlen), min(signed(rs2_val), signed(loaded))), + AMOMAX => to_bits(sizeof(xlen), max(signed(rs2_val), signed(loaded))), + AMOMINU => to_bits(sizeof(xlen), min(unsigned(rs2_val), unsigned(loaded))), + AMOMAXU => to_bits(sizeof(xlen), max(unsigned(rs2_val), unsigned(loaded))) + }; + let rval : xlenbits = match width { + BYTE => sign_extend(loaded[7..0]), + HALF => sign_extend(loaded[15..0]), + WORD => sign_extend(loaded[31..0]), + DOUBLE => loaded + }; + let wval : MemoryOpResult(bool) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_value(addr, 1, result[7..0], aq & rl, rl, true), + (HALF, _) => mem_write_value(addr, 2, result[15..0], aq & rl, rl, true), + (WORD, _) => mem_write_value(addr, 4, result[31..0], aq & rl, rl, true), + (DOUBLE, 64) => mem_write_value(addr, 8, result, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (wval) { + MemValue(true) => { X(rd) = rval; RETIRE_SUCCESS }, + MemValue(false) => { internal_error(__FILE__, __LINE__, "AMO got false from mem_write_value") }, + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } + } + } + } + } + } + } + } + } + } + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/A/amoor.w.yaml b/arch/inst/A/amoor.w.yaml index 030a8553c..7e33efcdb 100644 --- a/arch/inst/A/amoor.w.yaml +++ b/arch/inst/A/amoor.w.yaml @@ -40,3 +40,98 @@ amoor.w: XReg virtual_address = X[rs1]; X[rd] = amo<32>(virtual_address, X[rs2][31:0], AmoOperation::Or, aq, rl, $encoding); + + + + sail(): | + { + if extension("A") then { + /* Get the address, X(rs1) (no offset). + * Some extensions perform additional checks on address validity. + */ + match ext_data_get_addr(rs1, zeros(), ReadWrite(Data, Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => { + match translateAddr(vaddr, ReadWrite(Data, Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => { + let eares : MemoryOpResult(unit) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_ea(addr, 1, aq & rl, rl, true), + (HALF, _) => mem_write_ea(addr, 2, aq & rl, rl, true), + (WORD, _) => mem_write_ea(addr, 4, aq & rl, rl, true), + (DOUBLE, 64) => mem_write_ea(addr, 8, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + let is_unsigned : bool = match op { + AMOMINU => true, + AMOMAXU => true, + _ => false + }; + let rs2_val : xlenbits = match width { + BYTE => if is_unsigned then zero_extend(X(rs2)[7..0]) else sign_extend(X(rs2)[7..0]), + HALF => if is_unsigned then zero_extend(X(rs2)[15..0]) else sign_extend(X(rs2)[15..0]), + WORD => if is_unsigned then zero_extend(X(rs2)[31..0]) else sign_extend(X(rs2)[31..0]), + DOUBLE => X(rs2) + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + let mval : MemoryOpResult(xlenbits) = match (width, sizeof(xlen)) { + (BYTE, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 1, aq, aq & rl, true)), + (HALF, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 2, aq, aq & rl, true)), + (WORD, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 4, aq, aq & rl, true)), + (DOUBLE, 64) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 8, aq, aq & rl, true)), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (mval) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(loaded) => { + let result : xlenbits = + match op { + AMOSWAP => rs2_val, + AMOADD => rs2_val + loaded, + AMOXOR => rs2_val ^ loaded, + AMOAND => rs2_val & loaded, + AMOOR => rs2_val | loaded, + + /* These operations convert bitvectors to integer values using [un]signed, + * and back using to_bits(). + */ + AMOMIN => to_bits(sizeof(xlen), min(signed(rs2_val), signed(loaded))), + AMOMAX => to_bits(sizeof(xlen), max(signed(rs2_val), signed(loaded))), + AMOMINU => to_bits(sizeof(xlen), min(unsigned(rs2_val), unsigned(loaded))), + AMOMAXU => to_bits(sizeof(xlen), max(unsigned(rs2_val), unsigned(loaded))) + }; + let rval : xlenbits = match width { + BYTE => sign_extend(loaded[7..0]), + HALF => sign_extend(loaded[15..0]), + WORD => sign_extend(loaded[31..0]), + DOUBLE => loaded + }; + let wval : MemoryOpResult(bool) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_value(addr, 1, result[7..0], aq & rl, rl, true), + (HALF, _) => mem_write_value(addr, 2, result[15..0], aq & rl, rl, true), + (WORD, _) => mem_write_value(addr, 4, result[31..0], aq & rl, rl, true), + (DOUBLE, 64) => mem_write_value(addr, 8, result, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (wval) { + MemValue(true) => { X(rd) = rval; RETIRE_SUCCESS }, + MemValue(false) => { internal_error(__FILE__, __LINE__, "AMO got false from mem_write_value") }, + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } + } + } + } + } + } + } + } + } + } + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/A/amoswap.d.yaml b/arch/inst/A/amoswap.d.yaml index b42504b73..da4ba161a 100644 --- a/arch/inst/A/amoswap.d.yaml +++ b/arch/inst/A/amoswap.d.yaml @@ -40,3 +40,98 @@ amoswap.d: XReg virtual_address = X[rs1]; X[rd] = amo<64>(virtual_address, X[rs2], AmoOperation::Swap, aq, rl, $encoding); + + + + sail(): | + { + if extension("A") then { + /* Get the address, X(rs1) (no offset). + * Some extensions perform additional checks on address validity. + */ + match ext_data_get_addr(rs1, zeros(), ReadWrite(Data, Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => { + match translateAddr(vaddr, ReadWrite(Data, Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => { + let eares : MemoryOpResult(unit) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_ea(addr, 1, aq & rl, rl, true), + (HALF, _) => mem_write_ea(addr, 2, aq & rl, rl, true), + (WORD, _) => mem_write_ea(addr, 4, aq & rl, rl, true), + (DOUBLE, 64) => mem_write_ea(addr, 8, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + let is_unsigned : bool = match op { + AMOMINU => true, + AMOMAXU => true, + _ => false + }; + let rs2_val : xlenbits = match width { + BYTE => if is_unsigned then zero_extend(X(rs2)[7..0]) else sign_extend(X(rs2)[7..0]), + HALF => if is_unsigned then zero_extend(X(rs2)[15..0]) else sign_extend(X(rs2)[15..0]), + WORD => if is_unsigned then zero_extend(X(rs2)[31..0]) else sign_extend(X(rs2)[31..0]), + DOUBLE => X(rs2) + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + let mval : MemoryOpResult(xlenbits) = match (width, sizeof(xlen)) { + (BYTE, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 1, aq, aq & rl, true)), + (HALF, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 2, aq, aq & rl, true)), + (WORD, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 4, aq, aq & rl, true)), + (DOUBLE, 64) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 8, aq, aq & rl, true)), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (mval) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(loaded) => { + let result : xlenbits = + match op { + AMOSWAP => rs2_val, + AMOADD => rs2_val + loaded, + AMOXOR => rs2_val ^ loaded, + AMOAND => rs2_val & loaded, + AMOOR => rs2_val | loaded, + + /* These operations convert bitvectors to integer values using [un]signed, + * and back using to_bits(). + */ + AMOMIN => to_bits(sizeof(xlen), min(signed(rs2_val), signed(loaded))), + AMOMAX => to_bits(sizeof(xlen), max(signed(rs2_val), signed(loaded))), + AMOMINU => to_bits(sizeof(xlen), min(unsigned(rs2_val), unsigned(loaded))), + AMOMAXU => to_bits(sizeof(xlen), max(unsigned(rs2_val), unsigned(loaded))) + }; + let rval : xlenbits = match width { + BYTE => sign_extend(loaded[7..0]), + HALF => sign_extend(loaded[15..0]), + WORD => sign_extend(loaded[31..0]), + DOUBLE => loaded + }; + let wval : MemoryOpResult(bool) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_value(addr, 1, result[7..0], aq & rl, rl, true), + (HALF, _) => mem_write_value(addr, 2, result[15..0], aq & rl, rl, true), + (WORD, _) => mem_write_value(addr, 4, result[31..0], aq & rl, rl, true), + (DOUBLE, 64) => mem_write_value(addr, 8, result, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (wval) { + MemValue(true) => { X(rd) = rval; RETIRE_SUCCESS }, + MemValue(false) => { internal_error(__FILE__, __LINE__, "AMO got false from mem_write_value") }, + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } + } + } + } + } + } + } + } + } + } + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/A/amoswap.w.yaml b/arch/inst/A/amoswap.w.yaml index 7bdacf259..059ee723a 100644 --- a/arch/inst/A/amoswap.w.yaml +++ b/arch/inst/A/amoswap.w.yaml @@ -39,3 +39,98 @@ amoswap.w: XReg virtual_address = X[rs1]; X[rd] = amo<32>(virtual_address, X[rs2][31:0], AmoOperation::Swap, aq, rl, $encoding); + + + + sail(): | + { + if extension("A") then { + /* Get the address, X(rs1) (no offset). + * Some extensions perform additional checks on address validity. + */ + match ext_data_get_addr(rs1, zeros(), ReadWrite(Data, Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => { + match translateAddr(vaddr, ReadWrite(Data, Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => { + let eares : MemoryOpResult(unit) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_ea(addr, 1, aq & rl, rl, true), + (HALF, _) => mem_write_ea(addr, 2, aq & rl, rl, true), + (WORD, _) => mem_write_ea(addr, 4, aq & rl, rl, true), + (DOUBLE, 64) => mem_write_ea(addr, 8, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + let is_unsigned : bool = match op { + AMOMINU => true, + AMOMAXU => true, + _ => false + }; + let rs2_val : xlenbits = match width { + BYTE => if is_unsigned then zero_extend(X(rs2)[7..0]) else sign_extend(X(rs2)[7..0]), + HALF => if is_unsigned then zero_extend(X(rs2)[15..0]) else sign_extend(X(rs2)[15..0]), + WORD => if is_unsigned then zero_extend(X(rs2)[31..0]) else sign_extend(X(rs2)[31..0]), + DOUBLE => X(rs2) + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + let mval : MemoryOpResult(xlenbits) = match (width, sizeof(xlen)) { + (BYTE, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 1, aq, aq & rl, true)), + (HALF, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 2, aq, aq & rl, true)), + (WORD, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 4, aq, aq & rl, true)), + (DOUBLE, 64) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 8, aq, aq & rl, true)), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (mval) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(loaded) => { + let result : xlenbits = + match op { + AMOSWAP => rs2_val, + AMOADD => rs2_val + loaded, + AMOXOR => rs2_val ^ loaded, + AMOAND => rs2_val & loaded, + AMOOR => rs2_val | loaded, + + /* These operations convert bitvectors to integer values using [un]signed, + * and back using to_bits(). + */ + AMOMIN => to_bits(sizeof(xlen), min(signed(rs2_val), signed(loaded))), + AMOMAX => to_bits(sizeof(xlen), max(signed(rs2_val), signed(loaded))), + AMOMINU => to_bits(sizeof(xlen), min(unsigned(rs2_val), unsigned(loaded))), + AMOMAXU => to_bits(sizeof(xlen), max(unsigned(rs2_val), unsigned(loaded))) + }; + let rval : xlenbits = match width { + BYTE => sign_extend(loaded[7..0]), + HALF => sign_extend(loaded[15..0]), + WORD => sign_extend(loaded[31..0]), + DOUBLE => loaded + }; + let wval : MemoryOpResult(bool) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_value(addr, 1, result[7..0], aq & rl, rl, true), + (HALF, _) => mem_write_value(addr, 2, result[15..0], aq & rl, rl, true), + (WORD, _) => mem_write_value(addr, 4, result[31..0], aq & rl, rl, true), + (DOUBLE, 64) => mem_write_value(addr, 8, result, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (wval) { + MemValue(true) => { X(rd) = rval; RETIRE_SUCCESS }, + MemValue(false) => { internal_error(__FILE__, __LINE__, "AMO got false from mem_write_value") }, + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } + } + } + } + } + } + } + } + } + } + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/A/amoxor.d.yaml b/arch/inst/A/amoxor.d.yaml index f85a0f08c..e83878605 100644 --- a/arch/inst/A/amoxor.d.yaml +++ b/arch/inst/A/amoxor.d.yaml @@ -41,3 +41,98 @@ amoxor.d: XReg virtual_address = X[rs1]; X[rd] = amo<64>(virtual_address, X[rs2], AmoOperation::Xor, aq, rl, $encoding); + + + + sail(): | + { + if extension("A") then { + /* Get the address, X(rs1) (no offset). + * Some extensions perform additional checks on address validity. + */ + match ext_data_get_addr(rs1, zeros(), ReadWrite(Data, Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => { + match translateAddr(vaddr, ReadWrite(Data, Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => { + let eares : MemoryOpResult(unit) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_ea(addr, 1, aq & rl, rl, true), + (HALF, _) => mem_write_ea(addr, 2, aq & rl, rl, true), + (WORD, _) => mem_write_ea(addr, 4, aq & rl, rl, true), + (DOUBLE, 64) => mem_write_ea(addr, 8, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + let is_unsigned : bool = match op { + AMOMINU => true, + AMOMAXU => true, + _ => false + }; + let rs2_val : xlenbits = match width { + BYTE => if is_unsigned then zero_extend(X(rs2)[7..0]) else sign_extend(X(rs2)[7..0]), + HALF => if is_unsigned then zero_extend(X(rs2)[15..0]) else sign_extend(X(rs2)[15..0]), + WORD => if is_unsigned then zero_extend(X(rs2)[31..0]) else sign_extend(X(rs2)[31..0]), + DOUBLE => X(rs2) + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + let mval : MemoryOpResult(xlenbits) = match (width, sizeof(xlen)) { + (BYTE, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 1, aq, aq & rl, true)), + (HALF, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 2, aq, aq & rl, true)), + (WORD, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 4, aq, aq & rl, true)), + (DOUBLE, 64) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 8, aq, aq & rl, true)), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (mval) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(loaded) => { + let result : xlenbits = + match op { + AMOSWAP => rs2_val, + AMOADD => rs2_val + loaded, + AMOXOR => rs2_val ^ loaded, + AMOAND => rs2_val & loaded, + AMOOR => rs2_val | loaded, + + /* These operations convert bitvectors to integer values using [un]signed, + * and back using to_bits(). + */ + AMOMIN => to_bits(sizeof(xlen), min(signed(rs2_val), signed(loaded))), + AMOMAX => to_bits(sizeof(xlen), max(signed(rs2_val), signed(loaded))), + AMOMINU => to_bits(sizeof(xlen), min(unsigned(rs2_val), unsigned(loaded))), + AMOMAXU => to_bits(sizeof(xlen), max(unsigned(rs2_val), unsigned(loaded))) + }; + let rval : xlenbits = match width { + BYTE => sign_extend(loaded[7..0]), + HALF => sign_extend(loaded[15..0]), + WORD => sign_extend(loaded[31..0]), + DOUBLE => loaded + }; + let wval : MemoryOpResult(bool) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_value(addr, 1, result[7..0], aq & rl, rl, true), + (HALF, _) => mem_write_value(addr, 2, result[15..0], aq & rl, rl, true), + (WORD, _) => mem_write_value(addr, 4, result[31..0], aq & rl, rl, true), + (DOUBLE, 64) => mem_write_value(addr, 8, result, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (wval) { + MemValue(true) => { X(rd) = rval; RETIRE_SUCCESS }, + MemValue(false) => { internal_error(__FILE__, __LINE__, "AMO got false from mem_write_value") }, + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } + } + } + } + } + } + } + } + } + } + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/A/amoxor.w.yaml b/arch/inst/A/amoxor.w.yaml index 4d998ff2d..eeedce2a5 100644 --- a/arch/inst/A/amoxor.w.yaml +++ b/arch/inst/A/amoxor.w.yaml @@ -40,3 +40,98 @@ amoxor.w: XReg virtual_address = X[rs1]; X[rd] = amo<32>(virtual_address, X[rs2][31:0], AmoOperation::Xor, aq, rl, $encoding); + + + + sail(): | + { + if extension("A") then { + /* Get the address, X(rs1) (no offset). + * Some extensions perform additional checks on address validity. + */ + match ext_data_get_addr(rs1, zeros(), ReadWrite(Data, Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => { + match translateAddr(vaddr, ReadWrite(Data, Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => { + let eares : MemoryOpResult(unit) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_ea(addr, 1, aq & rl, rl, true), + (HALF, _) => mem_write_ea(addr, 2, aq & rl, rl, true), + (WORD, _) => mem_write_ea(addr, 4, aq & rl, rl, true), + (DOUBLE, 64) => mem_write_ea(addr, 8, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + let is_unsigned : bool = match op { + AMOMINU => true, + AMOMAXU => true, + _ => false + }; + let rs2_val : xlenbits = match width { + BYTE => if is_unsigned then zero_extend(X(rs2)[7..0]) else sign_extend(X(rs2)[7..0]), + HALF => if is_unsigned then zero_extend(X(rs2)[15..0]) else sign_extend(X(rs2)[15..0]), + WORD => if is_unsigned then zero_extend(X(rs2)[31..0]) else sign_extend(X(rs2)[31..0]), + DOUBLE => X(rs2) + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + let mval : MemoryOpResult(xlenbits) = match (width, sizeof(xlen)) { + (BYTE, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 1, aq, aq & rl, true)), + (HALF, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 2, aq, aq & rl, true)), + (WORD, _) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 4, aq, aq & rl, true)), + (DOUBLE, 64) => extend_value(is_unsigned, mem_read(ReadWrite(Data, Data), addr, 8, aq, aq & rl, true)), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (mval) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(loaded) => { + let result : xlenbits = + match op { + AMOSWAP => rs2_val, + AMOADD => rs2_val + loaded, + AMOXOR => rs2_val ^ loaded, + AMOAND => rs2_val & loaded, + AMOOR => rs2_val | loaded, + + /* These operations convert bitvectors to integer values using [un]signed, + * and back using to_bits(). + */ + AMOMIN => to_bits(sizeof(xlen), min(signed(rs2_val), signed(loaded))), + AMOMAX => to_bits(sizeof(xlen), max(signed(rs2_val), signed(loaded))), + AMOMINU => to_bits(sizeof(xlen), min(unsigned(rs2_val), unsigned(loaded))), + AMOMAXU => to_bits(sizeof(xlen), max(unsigned(rs2_val), unsigned(loaded))) + }; + let rval : xlenbits = match width { + BYTE => sign_extend(loaded[7..0]), + HALF => sign_extend(loaded[15..0]), + WORD => sign_extend(loaded[31..0]), + DOUBLE => loaded + }; + let wval : MemoryOpResult(bool) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_value(addr, 1, result[7..0], aq & rl, rl, true), + (HALF, _) => mem_write_value(addr, 2, result[15..0], aq & rl, rl, true), + (WORD, _) => mem_write_value(addr, 4, result[31..0], aq & rl, rl, true), + (DOUBLE, 64) => mem_write_value(addr, 8, result, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + }; + match (wval) { + MemValue(true) => { X(rd) = rval; RETIRE_SUCCESS }, + MemValue(false) => { internal_error(__FILE__, __LINE__, "AMO got false from mem_write_value") }, + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } + } + } + } + } + } + } + } + } + } + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/A/lr.d.yaml b/arch/inst/A/lr.d.yaml index 328e94f00..372344e62 100644 --- a/arch/inst/A/lr.d.yaml +++ b/arch/inst/A/lr.d.yaml @@ -88,3 +88,50 @@ lr.d: } X[rd] = load_reserved<32>(virtual_address, aq, rl, $encoding); + + + + sail(): | + { + if extension("A") then { + /* Get the address, X(rs1) (no offset). + * Extensions might perform additional checks on address validity. + */ + match ext_data_get_addr(rs1, zeros(), Read(Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => { + let aligned : bool = + /* BYTE and HALF would only occur due to invalid decodes, but it doesn't hurt + * to treat them as valid here; otherwise we'd need to throw an internal_error. + */ + match width { + BYTE => true, + HALF => vaddr[0..0] == 0b0, + WORD => vaddr[1..0] == 0b00, + DOUBLE => vaddr[2..0] == 0b000 + }; + /* "LR faults like a normal load, even though it's in the AMO major opcode space." + * - Andrew Waterman, isa-dev, 10 Jul 2018. + */ + if not(aligned) + then { handle_mem_exception(vaddr, E_Load_Addr_Align()); RETIRE_FAIL } + else match translateAddr(vaddr, Read(Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => + match (width, sizeof(xlen)) { + (BYTE, _) => process_loadres(rd, vaddr, mem_read(Read(Data), addr, 1, aq, aq & rl, true), false), + (HALF, _) => process_loadres(rd, vaddr, mem_read(Read(Data), addr, 2, aq, aq & rl, true), false), + (WORD, _) => process_loadres(rd, vaddr, mem_read(Read(Data), addr, 4, aq, aq & rl, true), false), + (DOUBLE, 64) => process_loadres(rd, vaddr, mem_read(Read(Data), addr, 8, aq, aq & rl, true), false), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + } + } + } + } + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/A/lr.w.yaml b/arch/inst/A/lr.w.yaml index b1bfdcda2..268c96596 100644 --- a/arch/inst/A/lr.w.yaml +++ b/arch/inst/A/lr.w.yaml @@ -96,3 +96,50 @@ lr.w: } else { X[rd] = sext(load_value[31:0], 32); } + + + + sail(): | + { + if extension("A") then { + /* Get the address, X(rs1) (no offset). + * Extensions might perform additional checks on address validity. + */ + match ext_data_get_addr(rs1, zeros(), Read(Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => { + let aligned : bool = + /* BYTE and HALF would only occur due to invalid decodes, but it doesn't hurt + * to treat them as valid here; otherwise we'd need to throw an internal_error. + */ + match width { + BYTE => true, + HALF => vaddr[0..0] == 0b0, + WORD => vaddr[1..0] == 0b00, + DOUBLE => vaddr[2..0] == 0b000 + }; + /* "LR faults like a normal load, even though it's in the AMO major opcode space." + * - Andrew Waterman, isa-dev, 10 Jul 2018. + */ + if not(aligned) + then { handle_mem_exception(vaddr, E_Load_Addr_Align()); RETIRE_FAIL } + else match translateAddr(vaddr, Read(Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => + match (width, sizeof(xlen)) { + (BYTE, _) => process_loadres(rd, vaddr, mem_read(Read(Data), addr, 1, aq, aq & rl, true), false), + (HALF, _) => process_loadres(rd, vaddr, mem_read(Read(Data), addr, 2, aq, aq & rl, true), false), + (WORD, _) => process_loadres(rd, vaddr, mem_read(Read(Data), addr, 4, aq, aq & rl, true), false), + (DOUBLE, 64) => process_loadres(rd, vaddr, mem_read(Read(Data), addr, 8, aq, aq & rl, true), false), + _ => internal_error(__FILE__, __LINE__, "Unexpected AMO width") + } + } + } + } + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/A/sc.d.yaml b/arch/inst/A/sc.d.yaml index 76467de4b..ed47ed996 100644 --- a/arch/inst/A/sc.d.yaml +++ b/arch/inst/A/sc.d.yaml @@ -146,3 +146,84 @@ sc.d: Boolean success = store_conditional<64>(virtual_address, value, aq, rl, $encoding); X[rd] = success ? 0 : 1; + + + + sail(): | + { + if speculate_conditional () == false then { + /* should only happen in rmem + * rmem: allow SC to fail very early + */ + X(rd) = zero_extend(0b1); RETIRE_SUCCESS + } else { + if extension("A") then { + /* normal non-rmem case + * rmem: SC is allowed to succeed (but might fail later) + */ + /* Get the address, X(rs1) (no offset). + * Extensions might perform additional checks on address validity. + */ + match ext_data_get_addr(rs1, zeros(), Write(Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => { + let aligned : bool = + /* BYTE and HALF would only occur due to invalid decodes, but it doesn't hurt + * to treat them as valid here; otherwise we'd need to throw an internal_error. + */ + match width { + BYTE => true, + HALF => vaddr[0..0] == 0b0, + WORD => vaddr[1..0] == 0b00, + DOUBLE => vaddr[2..0] == 0b000 + }; + if not(aligned) + then { handle_mem_exception(vaddr, E_SAMO_Addr_Align()); RETIRE_FAIL } + else { + if match_reservation(vaddr) == false then { + /* cannot happen in rmem */ + X(rd) = zero_extend(0b1); cancel_reservation(); RETIRE_SUCCESS + } else { + match translateAddr(vaddr, Write(Data)) { /* Write and ReadWrite are equivalent here: + * both result in a SAMO exception */ + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => { + let eares : MemoryOpResult(unit) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_ea(addr, 1, aq & rl, rl, true), + (HALF, _) => mem_write_ea(addr, 2, aq & rl, rl, true), + (WORD, _) => mem_write_ea(addr, 4, aq & rl, rl, true), + (DOUBLE, 64) => mem_write_ea(addr, 8, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "STORECON expected word or double") + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + rs2_val = X(rs2); + let res : MemoryOpResult(bool) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_value(addr, 1, rs2_val[7..0], aq & rl, rl, true), + (HALF, _) => mem_write_value(addr, 2, rs2_val[15..0], aq & rl, rl, true), + (WORD, _) => mem_write_value(addr, 4, rs2_val[31..0], aq & rl, rl, true), + (DOUBLE, 64) => mem_write_value(addr, 8, rs2_val, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "STORECON expected word or double") + }; + match (res) { + MemValue(true) => { X(rd) = zero_extend(0b0); cancel_reservation(); RETIRE_SUCCESS }, + MemValue(false) => { X(rd) = zero_extend(0b1); cancel_reservation(); RETIRE_SUCCESS }, + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } + } + } + } + } + } + } + } + } + } + } else { + handle_illegal(); + RETIRE_FAIL + } + } + } + + \ No newline at end of file diff --git a/arch/inst/A/sc.w.yaml b/arch/inst/A/sc.w.yaml index cc2937177..783be010b 100644 --- a/arch/inst/A/sc.w.yaml +++ b/arch/inst/A/sc.w.yaml @@ -152,3 +152,84 @@ sc.w: Boolean success = store_conditional<32>(virtual_address, value, aq, rl, $encoding); X[rd] = success ? 0 : 1; + + + + sail(): | + { + if speculate_conditional () == false then { + /* should only happen in rmem + * rmem: allow SC to fail very early + */ + X(rd) = zero_extend(0b1); RETIRE_SUCCESS + } else { + if extension("A") then { + /* normal non-rmem case + * rmem: SC is allowed to succeed (but might fail later) + */ + /* Get the address, X(rs1) (no offset). + * Extensions might perform additional checks on address validity. + */ + match ext_data_get_addr(rs1, zeros(), Write(Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => { + let aligned : bool = + /* BYTE and HALF would only occur due to invalid decodes, but it doesn't hurt + * to treat them as valid here; otherwise we'd need to throw an internal_error. + */ + match width { + BYTE => true, + HALF => vaddr[0..0] == 0b0, + WORD => vaddr[1..0] == 0b00, + DOUBLE => vaddr[2..0] == 0b000 + }; + if not(aligned) + then { handle_mem_exception(vaddr, E_SAMO_Addr_Align()); RETIRE_FAIL } + else { + if match_reservation(vaddr) == false then { + /* cannot happen in rmem */ + X(rd) = zero_extend(0b1); cancel_reservation(); RETIRE_SUCCESS + } else { + match translateAddr(vaddr, Write(Data)) { /* Write and ReadWrite are equivalent here: + * both result in a SAMO exception */ + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => { + let eares : MemoryOpResult(unit) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_ea(addr, 1, aq & rl, rl, true), + (HALF, _) => mem_write_ea(addr, 2, aq & rl, rl, true), + (WORD, _) => mem_write_ea(addr, 4, aq & rl, rl, true), + (DOUBLE, 64) => mem_write_ea(addr, 8, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "STORECON expected word or double") + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + rs2_val = X(rs2); + let res : MemoryOpResult(bool) = match (width, sizeof(xlen)) { + (BYTE, _) => mem_write_value(addr, 1, rs2_val[7..0], aq & rl, rl, true), + (HALF, _) => mem_write_value(addr, 2, rs2_val[15..0], aq & rl, rl, true), + (WORD, _) => mem_write_value(addr, 4, rs2_val[31..0], aq & rl, rl, true), + (DOUBLE, 64) => mem_write_value(addr, 8, rs2_val, aq & rl, rl, true), + _ => internal_error(__FILE__, __LINE__, "STORECON expected word or double") + }; + match (res) { + MemValue(true) => { X(rd) = zero_extend(0b0); cancel_reservation(); RETIRE_SUCCESS }, + MemValue(false) => { X(rd) = zero_extend(0b1); cancel_reservation(); RETIRE_SUCCESS }, + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } + } + } + } + } + } + } + } + } + } + } else { + handle_illegal(); + RETIRE_FAIL + } + } + } + + \ No newline at end of file diff --git a/arch/inst/B/add.uw.yaml b/arch/inst/B/add.uw.yaml index 8efc88373..f69a9642e 100644 --- a/arch/inst/B/add.uw.yaml +++ b/arch/inst/B/add.uw.yaml @@ -32,3 +32,22 @@ add.uw: } X[rd] = X[rs2] + X[rs1][31:0]; + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let shamt : bits(2) = match op { + RISCV_ADDUW => 0b00, + RISCV_SH1ADDUW => 0b01, + RISCV_SH2ADDUW => 0b10, + RISCV_SH3ADDUW => 0b11 + }; + let result : xlenbits = (zero_extend(rs1_val[31..0]) << shamt) + rs2_val; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/andn.yaml b/arch/inst/B/andn.yaml index 89aba3d19..c65690a03 100644 --- a/arch/inst/B/andn.yaml +++ b/arch/inst/B/andn.yaml @@ -29,3 +29,30 @@ andn: } X[rd] = X[rs2] & ~X[rs1]; + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let result : xlenbits = match op { + RISCV_ANDN => rs1_val & ~(rs2_val), + RISCV_ORN => rs1_val | ~(rs2_val), + RISCV_XNOR => ~(rs1_val ^ rs2_val), + RISCV_MAX => to_bits(sizeof(xlen), max(signed(rs1_val), signed(rs2_val))), + RISCV_MAXU => to_bits(sizeof(xlen), max(unsigned(rs1_val), unsigned(rs2_val))), + RISCV_MIN => to_bits(sizeof(xlen), min(signed(rs1_val), signed(rs2_val))), + RISCV_MINU => to_bits(sizeof(xlen), min(unsigned(rs1_val), unsigned(rs2_val))), + RISCV_ROL => if sizeof(xlen) == 32 + then rs1_val <<< rs2_val[4..0] + else rs1_val <<< rs2_val[5..0], + RISCV_ROR => if sizeof(xlen) == 32 + then rs1_val >>> rs2_val[4..0] + else rs1_val >>> rs2_val[5..0] + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/bclr.yaml b/arch/inst/B/bclr.yaml index 4020c6680..c670ca672 100644 --- a/arch/inst/B/bclr.yaml +++ b/arch/inst/B/bclr.yaml @@ -29,3 +29,24 @@ bclr: XReg index = X[rs2] & (xlen() - 1); X[rd] = X[rs1] & ~(1 << index); + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let mask : xlenbits = if sizeof(xlen) == 32 + then zero_extend(0b1) << rs2_val[4..0] + else zero_extend(0b1) << rs2_val[5..0]; + let result : xlenbits = match op { + RISCV_BCLR => rs1_val & ~(mask), + RISCV_BEXT => zero_extend(bool_to_bits((rs1_val & mask) != zeros())), + RISCV_BINV => rs1_val ^ mask, + RISCV_BSET => rs1_val | mask + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/bclri.yaml b/arch/inst/B/bclri.yaml index dd0eaa28b..797519e71 100644 --- a/arch/inst/B/bclri.yaml +++ b/arch/inst/B/bclri.yaml @@ -40,3 +40,23 @@ bclri: XReg index = shamt & (xlen() - 1); X[rd] = X[rs1] & ~(1 << index); + + + + sail(): | + { + let rs1_val = X(rs1); + let mask : xlenbits = if sizeof(xlen) == 32 + then zero_extend(0b1) << shamt[4..0] + else zero_extend(0b1) << shamt; + let result : xlenbits = match op { + RISCV_BCLRI => rs1_val & ~(mask), + RISCV_BEXTI => zero_extend(bool_to_bits((rs1_val & mask) != zeros())), + RISCV_BINVI => rs1_val ^ mask, + RISCV_BSETI => rs1_val | mask + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/bext.yaml b/arch/inst/B/bext.yaml index 00f7a7d70..f0a8a94f6 100644 --- a/arch/inst/B/bext.yaml +++ b/arch/inst/B/bext.yaml @@ -29,3 +29,24 @@ bext: XReg index = X[rs2] & (xlen() - 1); X[rd] = (X[rs1] >> index) & 1; + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let mask : xlenbits = if sizeof(xlen) == 32 + then zero_extend(0b1) << rs2_val[4..0] + else zero_extend(0b1) << rs2_val[5..0]; + let result : xlenbits = match op { + RISCV_BCLR => rs1_val & ~(mask), + RISCV_BEXT => zero_extend(bool_to_bits((rs1_val & mask) != zeros())), + RISCV_BINV => rs1_val ^ mask, + RISCV_BSET => rs1_val | mask + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/bexti.yaml b/arch/inst/B/bexti.yaml index ffbea8ded..af5cad1ac 100644 --- a/arch/inst/B/bexti.yaml +++ b/arch/inst/B/bexti.yaml @@ -40,3 +40,23 @@ bexti: XReg index = shamt & (xlen() - 1); X[rd] = (X[rs1] >> index) & 1; + + + + sail(): | + { + let rs1_val = X(rs1); + let mask : xlenbits = if sizeof(xlen) == 32 + then zero_extend(0b1) << shamt[4..0] + else zero_extend(0b1) << shamt; + let result : xlenbits = match op { + RISCV_BCLRI => rs1_val & ~(mask), + RISCV_BEXTI => zero_extend(bool_to_bits((rs1_val & mask) != zeros())), + RISCV_BINVI => rs1_val ^ mask, + RISCV_BSETI => rs1_val | mask + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/binv.yaml b/arch/inst/B/binv.yaml index b99b4494e..922850af7 100644 --- a/arch/inst/B/binv.yaml +++ b/arch/inst/B/binv.yaml @@ -29,3 +29,24 @@ binv: XReg index = X[rs2] & (xlen() - 1); X[rd] = X[rs1] ^ (1 << index); + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let mask : xlenbits = if sizeof(xlen) == 32 + then zero_extend(0b1) << rs2_val[4..0] + else zero_extend(0b1) << rs2_val[5..0]; + let result : xlenbits = match op { + RISCV_BCLR => rs1_val & ~(mask), + RISCV_BEXT => zero_extend(bool_to_bits((rs1_val & mask) != zeros())), + RISCV_BINV => rs1_val ^ mask, + RISCV_BSET => rs1_val | mask + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/binvi.yaml b/arch/inst/B/binvi.yaml index 40f64b54f..e2ac22973 100644 --- a/arch/inst/B/binvi.yaml +++ b/arch/inst/B/binvi.yaml @@ -40,3 +40,23 @@ binvi: XReg index = shamt & (xlen() - 1); X[rd] = X[rs1] ^ (1 << index); + + + + sail(): | + { + let rs1_val = X(rs1); + let mask : xlenbits = if sizeof(xlen) == 32 + then zero_extend(0b1) << shamt[4..0] + else zero_extend(0b1) << shamt; + let result : xlenbits = match op { + RISCV_BCLRI => rs1_val & ~(mask), + RISCV_BEXTI => zero_extend(bool_to_bits((rs1_val & mask) != zeros())), + RISCV_BINVI => rs1_val ^ mask, + RISCV_BSETI => rs1_val | mask + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/bset.yaml b/arch/inst/B/bset.yaml index 0541506cf..fd92e5056 100644 --- a/arch/inst/B/bset.yaml +++ b/arch/inst/B/bset.yaml @@ -29,3 +29,24 @@ bset: XReg index = X[rs2] & (xlen() - 1); X[rd] = X[rs1] | (1 << index); + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let mask : xlenbits = if sizeof(xlen) == 32 + then zero_extend(0b1) << rs2_val[4..0] + else zero_extend(0b1) << rs2_val[5..0]; + let result : xlenbits = match op { + RISCV_BCLR => rs1_val & ~(mask), + RISCV_BEXT => zero_extend(bool_to_bits((rs1_val & mask) != zeros())), + RISCV_BINV => rs1_val ^ mask, + RISCV_BSET => rs1_val | mask + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/bseti.yaml b/arch/inst/B/bseti.yaml index 53612487b..c13cdd586 100644 --- a/arch/inst/B/bseti.yaml +++ b/arch/inst/B/bseti.yaml @@ -40,3 +40,23 @@ bseti: XReg index = shamt & (xlen() - 1); X[rd] = X[rs1] | (1 << index); + + + + sail(): | + { + let rs1_val = X(rs1); + let mask : xlenbits = if sizeof(xlen) == 32 + then zero_extend(0b1) << shamt[4..0] + else zero_extend(0b1) << shamt; + let result : xlenbits = match op { + RISCV_BCLRI => rs1_val & ~(mask), + RISCV_BEXTI => zero_extend(bool_to_bits((rs1_val & mask) != zeros())), + RISCV_BINVI => rs1_val ^ mask, + RISCV_BSETI => rs1_val | mask + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/clmul.yaml b/arch/inst/B/clmul.yaml index 209f5160a..28f722548 100644 --- a/arch/inst/B/clmul.yaml +++ b/arch/inst/B/clmul.yaml @@ -38,3 +38,18 @@ clmul: } X[rd] = output; + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + result : xlenbits = zeros(); + foreach (i from 0 to (xlen_val - 1)) + if rs2_val[i] == bitone then result = result ^ (rs1_val << i); + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/clmulh.yaml b/arch/inst/B/clmulh.yaml index 7514310d1..3685cd9a8 100644 --- a/arch/inst/B/clmulh.yaml +++ b/arch/inst/B/clmulh.yaml @@ -38,3 +38,18 @@ clmulh: } X[rd] = output; + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + result : xlenbits = zeros(); + foreach (i from 0 to (xlen_val - 1)) + if rs2_val[i] == bitone then result = result ^ (rs1_val >> (xlen_val - i)); + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/clmulr.yaml b/arch/inst/B/clmulr.yaml index 1ce97c1cc..7cdcb7db9 100644 --- a/arch/inst/B/clmulr.yaml +++ b/arch/inst/B/clmulr.yaml @@ -37,3 +37,18 @@ clmulr: } X[rd] = output; + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + result : xlenbits = zeros(); + foreach (i from 0 to (xlen_val - 1)) + if rs2_val[i] == bitone then result = result ^ (rs1_val >> (xlen_val - i - 1)); + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/clz.yaml b/arch/inst/B/clz.yaml index 103c145de..95a9c3e01 100644 --- a/arch/inst/B/clz.yaml +++ b/arch/inst/B/clz.yaml @@ -28,3 +28,20 @@ clz: } X[rd] = (xlen() - 1) - $signed(highest_set_bit(X[rs1])); + + + + sail(): | + { + let rs1_val = X(rs1); + result : nat = 0; + done : bool = false; + foreach (i from (sizeof(xlen) - 1) downto 0) + if not(done) then if rs1_val[i] == bitzero + then result = result + 1 + else done = true; + X(rd) = to_bits(sizeof(xlen), result); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/clzw.yaml b/arch/inst/B/clzw.yaml index 6cdfe2867..ab95cc2a0 100644 --- a/arch/inst/B/clzw.yaml +++ b/arch/inst/B/clzw.yaml @@ -28,3 +28,20 @@ clzw: } X[rd] = 31 - $signed(highest_set_bit(X[rs1][31:0])); + + + + sail(): | + { + let rs1_val = X(rs1); + result : nat = 0; + done : bool = false; + foreach (i from 31 downto 0) + if not(done) then if rs1_val[i] == bitzero + then result = result + 1 + else done = true; + X(rd) = to_bits(sizeof(xlen), result); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/cpop.yaml b/arch/inst/B/cpop.yaml index 42aabf1cd..b3e92149b 100644 --- a/arch/inst/B/cpop.yaml +++ b/arch/inst/B/cpop.yaml @@ -46,3 +46,17 @@ cpop: } X[rd] = bitcount; + + + + sail(): | + { + let rs1_val = X(rs1); + result : nat = 0; + foreach (i from 0 to (xlen_val - 1)) + if rs1_val[i] == bitone then result = result + 1; + X(rd) = to_bits(sizeof(xlen), result); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/cpopw.yaml b/arch/inst/B/cpopw.yaml index ad2d69465..a23cd07a4 100644 --- a/arch/inst/B/cpopw.yaml +++ b/arch/inst/B/cpopw.yaml @@ -47,3 +47,17 @@ cpopw: } X[rd] = bitcount; + + + + sail(): | + { + let rs1_val = X(rs1); + result : nat = 0; + foreach (i from 0 to 31) + if rs1_val[i] == bitone then result = result + 1; + X(rd) = to_bits(sizeof(xlen), result); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/ctz.yaml b/arch/inst/B/ctz.yaml index 71fb076eb..80ed80e43 100644 --- a/arch/inst/B/ctz.yaml +++ b/arch/inst/B/ctz.yaml @@ -29,3 +29,20 @@ ctz: } X[rd] = (xlen() - 1) - $signed(lowest_set_bit(X[rs1])); + + + + sail(): | + { + let rs1_val = X(rs1); + result : nat = 0; + done : bool = false; + foreach (i from 0 to (sizeof(xlen) - 1)) + if not(done) then if rs1_val[i] == bitzero + then result = result + 1 + else done = true; + X(rd) = to_bits(sizeof(xlen), result); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/ctzw.yaml b/arch/inst/B/ctzw.yaml index 65317c67d..8d035b58e 100644 --- a/arch/inst/B/ctzw.yaml +++ b/arch/inst/B/ctzw.yaml @@ -30,3 +30,20 @@ ctzw: } X[rd] = (xlen() - 1) - $signed(lowest_set_bit(X[rs1][31:0])); + + + + sail(): | + { + let rs1_val = X(rs1); + result : nat = 0; + done : bool = false; + foreach (i from 0 to 31) + if not(done) then if rs1_val[i] == bitzero + then result = result + 1 + else done = true; + X(rd) = to_bits(sizeof(xlen), result); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/max.yaml b/arch/inst/B/max.yaml index 37aff18ec..60ec56bf7 100644 --- a/arch/inst/B/max.yaml +++ b/arch/inst/B/max.yaml @@ -35,3 +35,30 @@ max: } X[rd] = ($signed(X[rs1]) > $signed(X[rs2])) ? X[rs1] : X[rs2]; + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let result : xlenbits = match op { + RISCV_ANDN => rs1_val & ~(rs2_val), + RISCV_ORN => rs1_val | ~(rs2_val), + RISCV_XNOR => ~(rs1_val ^ rs2_val), + RISCV_MAX => to_bits(sizeof(xlen), max(signed(rs1_val), signed(rs2_val))), + RISCV_MAXU => to_bits(sizeof(xlen), max(unsigned(rs1_val), unsigned(rs2_val))), + RISCV_MIN => to_bits(sizeof(xlen), min(signed(rs1_val), signed(rs2_val))), + RISCV_MINU => to_bits(sizeof(xlen), min(unsigned(rs1_val), unsigned(rs2_val))), + RISCV_ROL => if sizeof(xlen) == 32 + then rs1_val <<< rs2_val[4..0] + else rs1_val <<< rs2_val[5..0], + RISCV_ROR => if sizeof(xlen) == 32 + then rs1_val >>> rs2_val[4..0] + else rs1_val >>> rs2_val[5..0] + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/maxu.yaml b/arch/inst/B/maxu.yaml index d8097c752..93a9298bc 100644 --- a/arch/inst/B/maxu.yaml +++ b/arch/inst/B/maxu.yaml @@ -27,3 +27,30 @@ maxu: } X[rd] = (X[rs1] > X[rs2]) ? X[rs1] : X[rs2]; + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let result : xlenbits = match op { + RISCV_ANDN => rs1_val & ~(rs2_val), + RISCV_ORN => rs1_val | ~(rs2_val), + RISCV_XNOR => ~(rs1_val ^ rs2_val), + RISCV_MAX => to_bits(sizeof(xlen), max(signed(rs1_val), signed(rs2_val))), + RISCV_MAXU => to_bits(sizeof(xlen), max(unsigned(rs1_val), unsigned(rs2_val))), + RISCV_MIN => to_bits(sizeof(xlen), min(signed(rs1_val), signed(rs2_val))), + RISCV_MINU => to_bits(sizeof(xlen), min(unsigned(rs1_val), unsigned(rs2_val))), + RISCV_ROL => if sizeof(xlen) == 32 + then rs1_val <<< rs2_val[4..0] + else rs1_val <<< rs2_val[5..0], + RISCV_ROR => if sizeof(xlen) == 32 + then rs1_val >>> rs2_val[4..0] + else rs1_val >>> rs2_val[5..0] + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/min.yaml b/arch/inst/B/min.yaml index f92101212..7bd38063a 100644 --- a/arch/inst/B/min.yaml +++ b/arch/inst/B/min.yaml @@ -27,3 +27,30 @@ min: } X[rd] = ($signed(X[rs1]) < $signed(X[rs2])) ? X[rs1] : X[rs2]; + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let result : xlenbits = match op { + RISCV_ANDN => rs1_val & ~(rs2_val), + RISCV_ORN => rs1_val | ~(rs2_val), + RISCV_XNOR => ~(rs1_val ^ rs2_val), + RISCV_MAX => to_bits(sizeof(xlen), max(signed(rs1_val), signed(rs2_val))), + RISCV_MAXU => to_bits(sizeof(xlen), max(unsigned(rs1_val), unsigned(rs2_val))), + RISCV_MIN => to_bits(sizeof(xlen), min(signed(rs1_val), signed(rs2_val))), + RISCV_MINU => to_bits(sizeof(xlen), min(unsigned(rs1_val), unsigned(rs2_val))), + RISCV_ROL => if sizeof(xlen) == 32 + then rs1_val <<< rs2_val[4..0] + else rs1_val <<< rs2_val[5..0], + RISCV_ROR => if sizeof(xlen) == 32 + then rs1_val >>> rs2_val[4..0] + else rs1_val >>> rs2_val[5..0] + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/minu.yaml b/arch/inst/B/minu.yaml index f5ecfd939..074f2c00c 100644 --- a/arch/inst/B/minu.yaml +++ b/arch/inst/B/minu.yaml @@ -27,3 +27,30 @@ minu: } X[rd] = (X[rs1] < X[rs2]) ? X[rs1] : X[rs2]; + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let result : xlenbits = match op { + RISCV_ANDN => rs1_val & ~(rs2_val), + RISCV_ORN => rs1_val | ~(rs2_val), + RISCV_XNOR => ~(rs1_val ^ rs2_val), + RISCV_MAX => to_bits(sizeof(xlen), max(signed(rs1_val), signed(rs2_val))), + RISCV_MAXU => to_bits(sizeof(xlen), max(unsigned(rs1_val), unsigned(rs2_val))), + RISCV_MIN => to_bits(sizeof(xlen), min(signed(rs1_val), signed(rs2_val))), + RISCV_MINU => to_bits(sizeof(xlen), min(unsigned(rs1_val), unsigned(rs2_val))), + RISCV_ROL => if sizeof(xlen) == 32 + then rs1_val <<< rs2_val[4..0] + else rs1_val <<< rs2_val[5..0], + RISCV_ROR => if sizeof(xlen) == 32 + then rs1_val >>> rs2_val[4..0] + else rs1_val >>> rs2_val[5..0] + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/orc.b.yaml b/arch/inst/B/orc.b.yaml index bbdee65af..e33395d25 100644 --- a/arch/inst/B/orc.b.yaml +++ b/arch/inst/B/orc.b.yaml @@ -34,3 +34,19 @@ orc.b: } X[rd] = output; + + + + sail(): | + { + let rs1_val = X(rs1); + result : xlenbits = zeros(); + foreach (i from 0 to (sizeof(xlen) - 8) by 8) + result[(i + 7) .. i] = if rs1_val[(i + 7) .. i] == zeros() + then 0x00 + else 0xFF; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/orn.yaml b/arch/inst/B/orn.yaml index 92421851d..851c43e58 100644 --- a/arch/inst/B/orn.yaml +++ b/arch/inst/B/orn.yaml @@ -28,3 +28,30 @@ orn: } X[rd] = X[rs1] | ~X[rs2]; + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let result : xlenbits = match op { + RISCV_ANDN => rs1_val & ~(rs2_val), + RISCV_ORN => rs1_val | ~(rs2_val), + RISCV_XNOR => ~(rs1_val ^ rs2_val), + RISCV_MAX => to_bits(sizeof(xlen), max(signed(rs1_val), signed(rs2_val))), + RISCV_MAXU => to_bits(sizeof(xlen), max(unsigned(rs1_val), unsigned(rs2_val))), + RISCV_MIN => to_bits(sizeof(xlen), min(signed(rs1_val), signed(rs2_val))), + RISCV_MINU => to_bits(sizeof(xlen), min(unsigned(rs1_val), unsigned(rs2_val))), + RISCV_ROL => if sizeof(xlen) == 32 + then rs1_val <<< rs2_val[4..0] + else rs1_val <<< rs2_val[5..0], + RISCV_ROR => if sizeof(xlen) == 32 + then rs1_val >>> rs2_val[4..0] + else rs1_val >>> rs2_val[5..0] + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/rev8.yaml b/arch/inst/B/rev8.yaml index 37954e750..020e8f6d4 100644 --- a/arch/inst/B/rev8.yaml +++ b/arch/inst/B/rev8.yaml @@ -52,3 +52,17 @@ rev8: } X[rd] = output; + + + + sail(): | + { + let rs1_val = X(rs1); + result : xlenbits = zeros(); + foreach (i from 0 to (sizeof(xlen) - 8) by 8) + result[(i + 7) .. i] = rs1_val[(sizeof(xlen) - i - 1) .. (sizeof(xlen) - i - 8)]; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/rol.yaml b/arch/inst/B/rol.yaml index 708c59028..f0bd6323c 100644 --- a/arch/inst/B/rol.yaml +++ b/arch/inst/B/rol.yaml @@ -30,3 +30,30 @@ rol: XReg shamt = (xlen() == 32) ? X[rs2][4:0] : X[rs2][5:0]; X[rd] = (X[rs1] << shamt) | (X[rs1] >> (xlen() - shamt)); + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let result : xlenbits = match op { + RISCV_ANDN => rs1_val & ~(rs2_val), + RISCV_ORN => rs1_val | ~(rs2_val), + RISCV_XNOR => ~(rs1_val ^ rs2_val), + RISCV_MAX => to_bits(sizeof(xlen), max(signed(rs1_val), signed(rs2_val))), + RISCV_MAXU => to_bits(sizeof(xlen), max(unsigned(rs1_val), unsigned(rs2_val))), + RISCV_MIN => to_bits(sizeof(xlen), min(signed(rs1_val), signed(rs2_val))), + RISCV_MINU => to_bits(sizeof(xlen), min(unsigned(rs1_val), unsigned(rs2_val))), + RISCV_ROL => if sizeof(xlen) == 32 + then rs1_val <<< rs2_val[4..0] + else rs1_val <<< rs2_val[5..0], + RISCV_ROR => if sizeof(xlen) == 32 + then rs1_val >>> rs2_val[4..0] + else rs1_val >>> rs2_val[5..0] + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/rolw.yaml b/arch/inst/B/rolw.yaml index fdcb72f1e..9c163ef7a 100644 --- a/arch/inst/B/rolw.yaml +++ b/arch/inst/B/rolw.yaml @@ -35,3 +35,19 @@ rolw: XReg unextended_result = (rs1_word << shamt) | (rs1_word >> (32 - shamt)); X[rd] = {{32{unextended_result[31]}}, unextended_result}; + + + + sail(): | + { + let rs1_val = (X(rs1))[31..0]; + let shamt = (X(rs2))[4..0]; + let result : bits(32) = match op { + RISCV_ROLW => rs1_val <<< shamt, + RISCV_RORW => rs1_val >>> shamt + }; + X(rd) = sign_extend(result); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/ror.yaml b/arch/inst/B/ror.yaml index 3960aea81..226c46126 100644 --- a/arch/inst/B/ror.yaml +++ b/arch/inst/B/ror.yaml @@ -30,3 +30,30 @@ ror: XReg shamt = (xlen() == 32) ? X[rs2][4:0] : X[rs2][5:0]; X[rd] = (X[rs1] >> shamt) | (X[rs1] << (xlen() - shamt)); + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let result : xlenbits = match op { + RISCV_ANDN => rs1_val & ~(rs2_val), + RISCV_ORN => rs1_val | ~(rs2_val), + RISCV_XNOR => ~(rs1_val ^ rs2_val), + RISCV_MAX => to_bits(sizeof(xlen), max(signed(rs1_val), signed(rs2_val))), + RISCV_MAXU => to_bits(sizeof(xlen), max(unsigned(rs1_val), unsigned(rs2_val))), + RISCV_MIN => to_bits(sizeof(xlen), min(signed(rs1_val), signed(rs2_val))), + RISCV_MINU => to_bits(sizeof(xlen), min(unsigned(rs1_val), unsigned(rs2_val))), + RISCV_ROL => if sizeof(xlen) == 32 + then rs1_val <<< rs2_val[4..0] + else rs1_val <<< rs2_val[5..0], + RISCV_ROR => if sizeof(xlen) == 32 + then rs1_val >>> rs2_val[4..0] + else rs1_val >>> rs2_val[5..0] + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/rori.yaml b/arch/inst/B/rori.yaml index 3ab97a3ba..76e8e0569 100644 --- a/arch/inst/B/rori.yaml +++ b/arch/inst/B/rori.yaml @@ -41,3 +41,17 @@ rori: XReg shamt = (xlen() == 32) ? shamt[4:0] : shamt[5:0]; X[rd] = (X[rs1] >> shamt) | (X[rs1] << (xlen() - shamt)); + + + + sail(): | + { + let rs1_val = X(rs1); + let result : xlenbits = if sizeof(xlen) == 32 + then rs1_val >>> shamt[4..0] + else rs1_val >>> shamt; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/roriw.yaml b/arch/inst/B/roriw.yaml index 5fec787cf..341df9ece 100644 --- a/arch/inst/B/roriw.yaml +++ b/arch/inst/B/roriw.yaml @@ -34,3 +34,15 @@ roriw: XReg unextended_result = (X[rs1] >> shamt) | (X[rs1] << (32 - shamt)); X[rd] = {{32{unextended_result[31]}}, unextended_result}; + + + + sail(): | + { + let rs1_val = (X(rs1))[31..0]; + let result : xlenbits = sign_extend(rs1_val >>> shamt); + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/rorw.yaml b/arch/inst/B/rorw.yaml index 030599414..02e6949f0 100644 --- a/arch/inst/B/rorw.yaml +++ b/arch/inst/B/rorw.yaml @@ -35,3 +35,19 @@ rorw: XReg unextended_result = (X[rs1] >> shamt) | (X[rs1] << (32 - shamt)); X[rd] = {{32{unextended_result[31]}}, unextended_result}; + + + + sail(): | + { + let rs1_val = (X(rs1))[31..0]; + let shamt = (X(rs2))[4..0]; + let result : bits(32) = match op { + RISCV_ROLW => rs1_val <<< shamt, + RISCV_RORW => rs1_val >>> shamt + }; + X(rd) = sign_extend(result); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/sext.b.yaml b/arch/inst/B/sext.b.yaml index 10a1c1cfc..ec3281ae2 100644 --- a/arch/inst/B/sext.b.yaml +++ b/arch/inst/B/sext.b.yaml @@ -30,3 +30,19 @@ sext.b: } else if (xlen() == 64) { X[rd] = {{56{X[rs1][7]}}, X[rs1][7:0]}; } + + + + sail(): | + { + let rs1_val = X(rs1); + let result : xlenbits = match op { + RISCV_SEXTB => sign_extend(rs1_val[7..0]), + RISCV_SEXTH => sign_extend(rs1_val[15..0]), + RISCV_ZEXTH => zero_extend(rs1_val[15..0]) + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/sext.h.yaml b/arch/inst/B/sext.h.yaml index faacc333e..825056864 100644 --- a/arch/inst/B/sext.h.yaml +++ b/arch/inst/B/sext.h.yaml @@ -30,3 +30,19 @@ sext.h: } else if (xlen() == 64) { X[rd] = {{48{X[rs1][15]}}, X[rs1][15:0]}; } + + + + sail(): | + { + let rs1_val = X(rs1); + let result : xlenbits = match op { + RISCV_SEXTB => sign_extend(rs1_val[7..0]), + RISCV_SEXTH => sign_extend(rs1_val[15..0]), + RISCV_ZEXTH => zero_extend(rs1_val[15..0]) + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/sh1add.uw.yaml b/arch/inst/B/sh1add.uw.yaml index 363dff17e..483d6ceba 100644 --- a/arch/inst/B/sh1add.uw.yaml +++ b/arch/inst/B/sh1add.uw.yaml @@ -30,3 +30,22 @@ sh1add.uw: } X[rd] = X[rs2] + (X[rs1][31:0] << 1); + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let shamt : bits(2) = match op { + RISCV_ADDUW => 0b00, + RISCV_SH1ADDUW => 0b01, + RISCV_SH2ADDUW => 0b10, + RISCV_SH3ADDUW => 0b11 + }; + let result : xlenbits = (zero_extend(rs1_val[31..0]) << shamt) + rs2_val; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/sh1add.yaml b/arch/inst/B/sh1add.yaml index 6e48e5018..f489bc6f9 100644 --- a/arch/inst/B/sh1add.yaml +++ b/arch/inst/B/sh1add.yaml @@ -27,3 +27,21 @@ sh1add: } X[rd] = X[rs2] + (X[rs1] << 1); + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let shamt : bits(2) = match op { + RISCV_SH1ADD => 0b01, + RISCV_SH2ADD => 0b10, + RISCV_SH3ADD => 0b11 + }; + let result : xlenbits = (rs1_val << shamt) + rs2_val; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/sh2add.uw.yaml b/arch/inst/B/sh2add.uw.yaml index 4c4ca92e9..eb305926f 100644 --- a/arch/inst/B/sh2add.uw.yaml +++ b/arch/inst/B/sh2add.uw.yaml @@ -30,3 +30,22 @@ sh2add.uw: } X[rd] = X[rs2] + (X[rs1][31:0] << 2); + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let shamt : bits(2) = match op { + RISCV_ADDUW => 0b00, + RISCV_SH1ADDUW => 0b01, + RISCV_SH2ADDUW => 0b10, + RISCV_SH3ADDUW => 0b11 + }; + let result : xlenbits = (zero_extend(rs1_val[31..0]) << shamt) + rs2_val; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/sh2add.yaml b/arch/inst/B/sh2add.yaml index 5d77ac4a0..81247ffc1 100644 --- a/arch/inst/B/sh2add.yaml +++ b/arch/inst/B/sh2add.yaml @@ -27,3 +27,21 @@ sh2add: } X[rd] = X[rs2] + (X[rs1] << 2); + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let shamt : bits(2) = match op { + RISCV_SH1ADD => 0b01, + RISCV_SH2ADD => 0b10, + RISCV_SH3ADD => 0b11 + }; + let result : xlenbits = (rs1_val << shamt) + rs2_val; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/sh3add.uw.yaml b/arch/inst/B/sh3add.uw.yaml index e62efe392..a0a69d41d 100644 --- a/arch/inst/B/sh3add.uw.yaml +++ b/arch/inst/B/sh3add.uw.yaml @@ -30,3 +30,22 @@ sh3add.uw: } X[rd] = X[rs2] + (X[rs1][31:0] << 3); + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let shamt : bits(2) = match op { + RISCV_ADDUW => 0b00, + RISCV_SH1ADDUW => 0b01, + RISCV_SH2ADDUW => 0b10, + RISCV_SH3ADDUW => 0b11 + }; + let result : xlenbits = (zero_extend(rs1_val[31..0]) << shamt) + rs2_val; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/sh3add.yaml b/arch/inst/B/sh3add.yaml index a5feb1b2a..4e0236c8d 100644 --- a/arch/inst/B/sh3add.yaml +++ b/arch/inst/B/sh3add.yaml @@ -27,3 +27,21 @@ sh3add: } X[rd] = X[rs2] + (X[rs1] << 3); + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let shamt : bits(2) = match op { + RISCV_SH1ADD => 0b01, + RISCV_SH2ADD => 0b10, + RISCV_SH3ADD => 0b11 + }; + let result : xlenbits = (rs1_val << shamt) + rs2_val; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/slli.uw.yaml b/arch/inst/B/slli.uw.yaml index ffa16f562..e2161473d 100644 --- a/arch/inst/B/slli.uw.yaml +++ b/arch/inst/B/slli.uw.yaml @@ -32,3 +32,15 @@ slli.uw: } X[rd] = X[rs1][31:0] << shamt; + + + + sail(): | + { + let rs1_val = X(rs1); + let result : xlenbits = zero_extend(rs1_val[31..0]) << shamt; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/xnor.yaml b/arch/inst/B/xnor.yaml index 59fffacc3..470abf087 100644 --- a/arch/inst/B/xnor.yaml +++ b/arch/inst/B/xnor.yaml @@ -28,3 +28,30 @@ xnor: } X[rd] = ~(X[rs1] ^ X[rs2]); + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let result : xlenbits = match op { + RISCV_ANDN => rs1_val & ~(rs2_val), + RISCV_ORN => rs1_val | ~(rs2_val), + RISCV_XNOR => ~(rs1_val ^ rs2_val), + RISCV_MAX => to_bits(sizeof(xlen), max(signed(rs1_val), signed(rs2_val))), + RISCV_MAXU => to_bits(sizeof(xlen), max(unsigned(rs1_val), unsigned(rs2_val))), + RISCV_MIN => to_bits(sizeof(xlen), min(signed(rs1_val), signed(rs2_val))), + RISCV_MINU => to_bits(sizeof(xlen), min(unsigned(rs1_val), unsigned(rs2_val))), + RISCV_ROL => if sizeof(xlen) == 32 + then rs1_val <<< rs2_val[4..0] + else rs1_val <<< rs2_val[5..0], + RISCV_ROR => if sizeof(xlen) == 32 + then rs1_val >>> rs2_val[4..0] + else rs1_val >>> rs2_val[5..0] + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/B/zext.h.yaml b/arch/inst/B/zext.h.yaml index a5c801e89..501d790ad 100644 --- a/arch/inst/B/zext.h.yaml +++ b/arch/inst/B/zext.h.yaml @@ -41,3 +41,19 @@ zext.h: } X[rd] = X[rs1][15:0]; + + + + sail(): | + { + let rs1_val = X(rs1); + let result : xlenbits = match op { + RISCV_SEXTB => sign_extend(rs1_val[7..0]), + RISCV_SEXTH => sign_extend(rs1_val[15..0]), + RISCV_ZEXTH => zero_extend(rs1_val[15..0]) + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/F/fadd.s.yaml b/arch/inst/F/fadd.s.yaml index 4c459cb37..79b186739 100644 --- a/arch/inst/F/fadd.s.yaml +++ b/arch/inst/F/fadd.s.yaml @@ -25,3 +25,28 @@ fadd.s: data_independent_timing: true operation(): | + + + + sail(): | + { + let rs1_val_32b = F_or_X_S(rs1); + let rs2_val_32b = F_or_X_S(rs2); + match (select_instr_or_fcsr_rm (rm)) { + None() => { handle_illegal(); RETIRE_FAIL }, + Some(rm') => { + let rm_3b = encdec_rounding_mode(rm'); + let (fflags, rd_val_32b) : (bits(5), bits(32)) = match op { + FADD_S => riscv_f32Add (rm_3b, rs1_val_32b, rs2_val_32b), + FSUB_S => riscv_f32Sub (rm_3b, rs1_val_32b, rs2_val_32b), + FMUL_S => riscv_f32Mul (rm_3b, rs1_val_32b, rs2_val_32b), + FDIV_S => riscv_f32Div (rm_3b, rs1_val_32b, rs2_val_32b) + }; + accrue_fflags(fflags); + F_or_X_S(rd) = rd_val_32b; + RETIRE_SUCCESS + } + } + } + + \ No newline at end of file diff --git a/arch/inst/F/fclass.s.yaml b/arch/inst/F/fclass.s.yaml index c484a11fe..467c35d6d 100644 --- a/arch/inst/F/fclass.s.yaml +++ b/arch/inst/F/fclass.s.yaml @@ -71,3 +71,15 @@ fclass.s: assert(is_sp_quiet_nan?(sp_value), "Unexpected SP value"); X[rd] = 1 << 9; } + + + + sail(): | + { + let rs1_val_X = X(rs1); + let rd_val_S = rs1_val_X [31..0]; + F(rd) = nan_box (rd_val_S); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/F/fcvt.l.s.yaml b/arch/inst/F/fcvt.l.s.yaml index af2b59123..f14bb8e55 100644 --- a/arch/inst/F/fcvt.l.s.yaml +++ b/arch/inst/F/fcvt.l.s.yaml @@ -24,3 +24,24 @@ fcvt.l.s: data_independent_timing: true operation(): | + + + + sail(): | + { + assert(sizeof(xlen) >= 64); + let rs1_val_LU = X(rs1)[63..0]; + match (select_instr_or_fcsr_rm (rm)) { + None() => { handle_illegal(); RETIRE_FAIL }, + Some(rm') => { + let rm_3b = encdec_rounding_mode(rm'); + let (fflags, rd_val_S) = riscv_ui64ToF32 (rm_3b, rs1_val_LU); + + accrue_fflags(fflags); + F_or_X_S(rd) = rd_val_S; + RETIRE_SUCCESS + } + } + } + + \ No newline at end of file diff --git a/arch/inst/F/fcvt.lu.s.yaml b/arch/inst/F/fcvt.lu.s.yaml index d11be70f7..155594ac8 100644 --- a/arch/inst/F/fcvt.lu.s.yaml +++ b/arch/inst/F/fcvt.lu.s.yaml @@ -24,3 +24,24 @@ fcvt.lu.s: data_independent_timing: true operation(): | + + + + sail(): | + { + assert(sizeof(xlen) >= 64); + let rs1_val_LU = X(rs1)[63..0]; + match (select_instr_or_fcsr_rm (rm)) { + None() => { handle_illegal(); RETIRE_FAIL }, + Some(rm') => { + let rm_3b = encdec_rounding_mode(rm'); + let (fflags, rd_val_S) = riscv_ui64ToF32 (rm_3b, rs1_val_LU); + + accrue_fflags(fflags); + F_or_X_S(rd) = rd_val_S; + RETIRE_SUCCESS + } + } + } + + \ No newline at end of file diff --git a/arch/inst/F/fcvt.s.l.yaml b/arch/inst/F/fcvt.s.l.yaml index e23c2deee..14e43e102 100644 --- a/arch/inst/F/fcvt.s.l.yaml +++ b/arch/inst/F/fcvt.s.l.yaml @@ -24,3 +24,24 @@ fcvt.s.l: data_independent_timing: true operation(): | + + + + sail(): | + { + assert(sizeof(xlen) >= 64); + let rs1_val_LU = X(rs1)[63..0]; + match (select_instr_or_fcsr_rm (rm)) { + None() => { handle_illegal(); RETIRE_FAIL }, + Some(rm') => { + let rm_3b = encdec_rounding_mode(rm'); + let (fflags, rd_val_S) = riscv_ui64ToF32 (rm_3b, rs1_val_LU); + + accrue_fflags(fflags); + F_or_X_S(rd) = rd_val_S; + RETIRE_SUCCESS + } + } + } + + \ No newline at end of file diff --git a/arch/inst/F/fcvt.s.lu.yaml b/arch/inst/F/fcvt.s.lu.yaml index a323d1b27..74b54bd58 100644 --- a/arch/inst/F/fcvt.s.lu.yaml +++ b/arch/inst/F/fcvt.s.lu.yaml @@ -24,3 +24,24 @@ fcvt.s.lu: data_independent_timing: true operation(): | + + + + sail(): | + { + assert(sizeof(xlen) >= 64); + let rs1_val_LU = X(rs1)[63..0]; + match (select_instr_or_fcsr_rm (rm)) { + None() => { handle_illegal(); RETIRE_FAIL }, + Some(rm') => { + let rm_3b = encdec_rounding_mode(rm'); + let (fflags, rd_val_S) = riscv_ui64ToF32 (rm_3b, rs1_val_LU); + + accrue_fflags(fflags); + F_or_X_S(rd) = rd_val_S; + RETIRE_SUCCESS + } + } + } + + \ No newline at end of file diff --git a/arch/inst/F/fcvt.s.w.yaml b/arch/inst/F/fcvt.s.w.yaml index 85a1d85a4..ea7186884 100644 --- a/arch/inst/F/fcvt.s.w.yaml +++ b/arch/inst/F/fcvt.s.w.yaml @@ -48,3 +48,24 @@ fcvt.s.w: mark_f_state_dirty(); + + + + sail(): | + { + assert(sizeof(xlen) >= 64); + let rs1_val_LU = X(rs1)[63..0]; + match (select_instr_or_fcsr_rm (rm)) { + None() => { handle_illegal(); RETIRE_FAIL }, + Some(rm') => { + let rm_3b = encdec_rounding_mode(rm'); + let (fflags, rd_val_S) = riscv_ui64ToF32 (rm_3b, rs1_val_LU); + + accrue_fflags(fflags); + F_or_X_S(rd) = rd_val_S; + RETIRE_SUCCESS + } + } + } + + \ No newline at end of file diff --git a/arch/inst/F/fcvt.s.wu.yaml b/arch/inst/F/fcvt.s.wu.yaml index 451db4ab1..ad7999c4c 100644 --- a/arch/inst/F/fcvt.s.wu.yaml +++ b/arch/inst/F/fcvt.s.wu.yaml @@ -23,3 +23,24 @@ fcvt.s.wu: data_independent_timing: true operation(): | + + + + sail(): | + { + assert(sizeof(xlen) >= 64); + let rs1_val_LU = X(rs1)[63..0]; + match (select_instr_or_fcsr_rm (rm)) { + None() => { handle_illegal(); RETIRE_FAIL }, + Some(rm') => { + let rm_3b = encdec_rounding_mode(rm'); + let (fflags, rd_val_S) = riscv_ui64ToF32 (rm_3b, rs1_val_LU); + + accrue_fflags(fflags); + F_or_X_S(rd) = rd_val_S; + RETIRE_SUCCESS + } + } + } + + \ No newline at end of file diff --git a/arch/inst/F/fcvt.w.s.yaml b/arch/inst/F/fcvt.w.s.yaml index 5ffb38e79..6df307f7f 100644 --- a/arch/inst/F/fcvt.w.s.yaml +++ b/arch/inst/F/fcvt.w.s.yaml @@ -78,3 +78,24 @@ fcvt.w.s: } + + + + sail(): | + { + assert(sizeof(xlen) >= 64); + let rs1_val_LU = X(rs1)[63..0]; + match (select_instr_or_fcsr_rm (rm)) { + None() => { handle_illegal(); RETIRE_FAIL }, + Some(rm') => { + let rm_3b = encdec_rounding_mode(rm'); + let (fflags, rd_val_S) = riscv_ui64ToF32 (rm_3b, rs1_val_LU); + + accrue_fflags(fflags); + F_or_X_S(rd) = rd_val_S; + RETIRE_SUCCESS + } + } + } + + \ No newline at end of file diff --git a/arch/inst/F/fcvt.wu.s.yaml b/arch/inst/F/fcvt.wu.s.yaml index 3ced43a23..b050c1a6d 100644 --- a/arch/inst/F/fcvt.wu.s.yaml +++ b/arch/inst/F/fcvt.wu.s.yaml @@ -23,3 +23,24 @@ fcvt.wu.s: data_independent_timing: true operation(): | + + + + sail(): | + { + assert(sizeof(xlen) >= 64); + let rs1_val_LU = X(rs1)[63..0]; + match (select_instr_or_fcsr_rm (rm)) { + None() => { handle_illegal(); RETIRE_FAIL }, + Some(rm') => { + let rm_3b = encdec_rounding_mode(rm'); + let (fflags, rd_val_S) = riscv_ui64ToF32 (rm_3b, rs1_val_LU); + + accrue_fflags(fflags); + F_or_X_S(rd) = rd_val_S; + RETIRE_SUCCESS + } + } + } + + \ No newline at end of file diff --git a/arch/inst/F/fdiv.s.yaml b/arch/inst/F/fdiv.s.yaml index 43e135eaf..af35a4eab 100644 --- a/arch/inst/F/fdiv.s.yaml +++ b/arch/inst/F/fdiv.s.yaml @@ -25,3 +25,28 @@ fdiv.s: data_independent_timing: true operation(): | + + + + sail(): | + { + let rs1_val_32b = F_or_X_S(rs1); + let rs2_val_32b = F_or_X_S(rs2); + match (select_instr_or_fcsr_rm (rm)) { + None() => { handle_illegal(); RETIRE_FAIL }, + Some(rm') => { + let rm_3b = encdec_rounding_mode(rm'); + let (fflags, rd_val_32b) : (bits(5), bits(32)) = match op { + FADD_S => riscv_f32Add (rm_3b, rs1_val_32b, rs2_val_32b), + FSUB_S => riscv_f32Sub (rm_3b, rs1_val_32b, rs2_val_32b), + FMUL_S => riscv_f32Mul (rm_3b, rs1_val_32b, rs2_val_32b), + FDIV_S => riscv_f32Div (rm_3b, rs1_val_32b, rs2_val_32b) + }; + accrue_fflags(fflags); + F_or_X_S(rd) = rd_val_32b; + RETIRE_SUCCESS + } + } + } + + \ No newline at end of file diff --git a/arch/inst/F/feq.s.yaml b/arch/inst/F/feq.s.yaml index 4239a5c07..ba0ea8b77 100644 --- a/arch/inst/F/feq.s.yaml +++ b/arch/inst/F/feq.s.yaml @@ -43,3 +43,20 @@ feq.s: || ((sp_value_a | sp_value_b)[30:0] == 0) # pos 0 is equal to neg zero ) ? 1 : 0; } + + + + sail(): | + { + let rs1_val_S = F_or_X_S(rs1); + let rs2_val_S = F_or_X_S(rs2); + + let (fflags, rd_val) : (bits_fflags, bool) = + riscv_f32Le (rs1_val_S, rs2_val_S); + + accrue_fflags(fflags); + X(rd) = zero_extend(bool_to_bits(rd_val)); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/F/fle.s.yaml b/arch/inst/F/fle.s.yaml index c692a679c..7a94aac00 100644 --- a/arch/inst/F/fle.s.yaml +++ b/arch/inst/F/fle.s.yaml @@ -44,3 +44,20 @@ fle.s: || ((sp_value_a | sp_value_b)[30:0] == 0) # pos 0 is equal to neg zero ) ? 1 : 0; } + + + + sail(): | + { + let rs1_val_S = F_or_X_S(rs1); + let rs2_val_S = F_or_X_S(rs2); + + let (fflags, rd_val) : (bits_fflags, bool) = + riscv_f32Le (rs1_val_S, rs2_val_S); + + accrue_fflags(fflags); + X(rd) = zero_extend(bool_to_bits(rd_val)); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/F/fleq.s.yaml b/arch/inst/F/fleq.s.yaml index fa42d83df..07d5c6827 100644 --- a/arch/inst/F/fleq.s.yaml +++ b/arch/inst/F/fleq.s.yaml @@ -23,3 +23,20 @@ fleq.s: data_independent_timing: true operation(): | + + + + sail(): | + { + let rs1_val_S = F_S(rs1); + let rs2_val_S = F_S(rs2); + + let (fflags, rd_val) : (bits_fflags, bool) = + riscv_f32Le_quiet (rs1_val_S, rs2_val_S); + + accrue_fflags(fflags); + X(rd) = zero_extend(bool_to_bits(rd_val)); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/F/fli.s.yaml b/arch/inst/F/fli.s.yaml index e85e01315..712dee35f 100644 --- a/arch/inst/F/fli.s.yaml +++ b/arch/inst/F/fli.s.yaml @@ -21,3 +21,47 @@ fli.s: data_independent_timing: true operation(): | + + + + sail(): | + { + let bits : bits(32) = match constantidx { + 0b00000 => { 0xbf800000 }, /* -1.0 */ + 0b00001 => { 0x00800000 }, /* minimum positive normal */ + 0b00010 => { 0x37800000 }, /* 1.0 * 2^-16 */ + 0b00011 => { 0x38000000 }, /* 1.0 * 2^-15 */ + 0b00100 => { 0x3b800000 }, /* 1.0 * 2^-8 */ + 0b00101 => { 0x3c000000 }, /* 1.0 * 2^-7 */ + 0b00110 => { 0x3d800000 }, /* 1.0 * 2^-4 */ + 0b00111 => { 0x3e000000 }, /* 1.0 * 2^-3 */ + 0b01000 => { 0x3e800000 }, /* 0.25 */ + 0b01001 => { 0x3ea00000 }, /* 0.3125 */ + 0b01010 => { 0x3ec00000 }, /* 0.375 */ + 0b01011 => { 0x3ee00000 }, /* 0.4375 */ + 0b01100 => { 0x3f000000 }, /* 0.5 */ + 0b01101 => { 0x3f200000 }, /* 0.625 */ + 0b01110 => { 0x3f400000 }, /* 0.75 */ + 0b01111 => { 0x3f600000 }, /* 0.875 */ + 0b10000 => { 0x3f800000 }, /* 1.0 */ + 0b10001 => { 0x3fa00000 }, /* 1.25 */ + 0b10010 => { 0x3fc00000 }, /* 1.5 */ + 0b10011 => { 0x3fe00000 }, /* 1.75 */ + 0b10100 => { 0x40000000 }, /* 2.0 */ + 0b10101 => { 0x40200000 }, /* 2.5 */ + 0b10110 => { 0x40400000 }, /* 3 */ + 0b10111 => { 0x40800000 }, /* 4 */ + 0b11000 => { 0x41000000 }, /* 8 */ + 0b11001 => { 0x41800000 }, /* 16 */ + 0b11010 => { 0x43000000 }, /* 2^7 */ + 0b11011 => { 0x43800000 }, /* 2^8 */ + 0b11100 => { 0x47000000 }, /* 2^15 */ + 0b11101 => { 0x47800000 }, /* 2^16 */ + 0b11110 => { 0x7f800000 }, /* +inf */ + 0b11111 => { canonical_NaN_S() }, + }; + F_S(rd) = bits; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/F/flt.s.yaml b/arch/inst/F/flt.s.yaml index 0a2d7a5da..812f29e2c 100644 --- a/arch/inst/F/flt.s.yaml +++ b/arch/inst/F/flt.s.yaml @@ -46,3 +46,20 @@ flt.s: } + + + + sail(): | + { + let rs1_val_S = F_or_X_S(rs1); + let rs2_val_S = F_or_X_S(rs2); + + let (fflags, rd_val) : (bits_fflags, bool) = + riscv_f32Le (rs1_val_S, rs2_val_S); + + accrue_fflags(fflags); + X(rd) = zero_extend(bool_to_bits(rd_val)); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/F/fltq.s.yaml b/arch/inst/F/fltq.s.yaml index ce447071b..46de30784 100644 --- a/arch/inst/F/fltq.s.yaml +++ b/arch/inst/F/fltq.s.yaml @@ -23,3 +23,20 @@ fltq.s: data_independent_timing: true operation(): | + + + + sail(): | + { + let rs1_val_S = F_S(rs1); + let rs2_val_S = F_S(rs2); + + let (fflags, rd_val) : (bits_fflags, bool) = + riscv_f32Lt_quiet (rs1_val_S, rs2_val_S); + + accrue_fflags(fflags); + X(rd) = zero_extend(bool_to_bits(rd_val)); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/F/flw.yaml b/arch/inst/F/flw.yaml index c4932d6bd..b68870958 100644 --- a/arch/inst/F/flw.yaml +++ b/arch/inst/F/flw.yaml @@ -37,4 +37,36 @@ flw: f[fd] = sp_value; } - mark_f_state_dirty(); \ No newline at end of file + mark_f_state_dirty(); + + + sail(): | + { + let offset : xlenbits = sign_extend(imm); + /* Get the address, X(rs1) + offset. + Some extensions perform additional checks on address validity. */ + match ext_data_get_addr(rs1, offset, Read(Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => + if check_misaligned(vaddr, width) + then { handle_mem_exception(vaddr, E_Load_Addr_Align()); RETIRE_FAIL } + else match translateAddr(vaddr, Read(Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => { + let (aq, rl, res) = (false, false, false); + match (width) { + BYTE => { handle_illegal(); RETIRE_FAIL }, + HALF => + process_fload16(rd, vaddr, mem_read(Read(Data), addr, 2, aq, rl, res)), + WORD => + process_fload32(rd, vaddr, mem_read(Read(Data), addr, 4, aq, rl, res)), + DOUBLE if sizeof(flen) >= 64 => + process_fload64(rd, vaddr, mem_read(Read(Data), addr, 8, aq, rl, res)), + _ => report_invalid_width(__FILE__, __LINE__, width, "floating point load"), + } + } + } + } + } + + \ No newline at end of file diff --git a/arch/inst/F/fmadd.s.yaml b/arch/inst/F/fmadd.s.yaml index 468f00381..f720cebe8 100644 --- a/arch/inst/F/fmadd.s.yaml +++ b/arch/inst/F/fmadd.s.yaml @@ -27,3 +27,30 @@ fmadd.s: data_independent_timing: true operation(): | + + + + sail(): | + { + let rs1_val_32b = F_or_X_S(rs1); + let rs2_val_32b = F_or_X_S(rs2); + let rs3_val_32b = F_or_X_S(rs3); + match (select_instr_or_fcsr_rm (rm)) { + None() => { handle_illegal(); RETIRE_FAIL }, + Some(rm') => { + let rm_3b = encdec_rounding_mode(rm'); + let (fflags, rd_val_32b) : (bits(5), bits(32)) = + match op { + FMADD_S => riscv_f32MulAdd (rm_3b, rs1_val_32b, rs2_val_32b, rs3_val_32b), + FMSUB_S => riscv_f32MulAdd (rm_3b, rs1_val_32b, rs2_val_32b, negate_S (rs3_val_32b)), + FNMSUB_S => riscv_f32MulAdd (rm_3b, negate_S (rs1_val_32b), rs2_val_32b, rs3_val_32b), + FNMADD_S => riscv_f32MulAdd (rm_3b, negate_S (rs1_val_32b), rs2_val_32b, negate_S (rs3_val_32b)) + }; + accrue_fflags(fflags); + F_or_X_S(rd) = rd_val_32b; + RETIRE_SUCCESS + } + } + } + + \ No newline at end of file diff --git a/arch/inst/F/fmax.s.yaml b/arch/inst/F/fmax.s.yaml index a0b00dcab..02c25e264 100644 --- a/arch/inst/F/fmax.s.yaml +++ b/arch/inst/F/fmax.s.yaml @@ -23,3 +23,20 @@ fmax.s: data_independent_timing: true operation(): | + + + + sail(): | + { + let rs1_val_S = F_or_X_S(rs1); + let rs2_val_S = F_or_X_S(rs2); + + let (fflags, rd_val) : (bits_fflags, bool) = + riscv_f32Le (rs1_val_S, rs2_val_S); + + accrue_fflags(fflags); + X(rd) = zero_extend(bool_to_bits(rd_val)); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/F/fmaxm.s.yaml b/arch/inst/F/fmaxm.s.yaml index c7d75640c..ad9e1a61a 100644 --- a/arch/inst/F/fmaxm.s.yaml +++ b/arch/inst/F/fmaxm.s.yaml @@ -23,3 +23,26 @@ fmaxm.s: data_independent_timing: true operation(): | + + + + sail(): | + { + let rs1_val_S = F_S(rs1); + let rs2_val_S = F_S(rs2); + + let is_quiet = true; + let (rs2_lt_rs1, fflags) = fle_S (rs2_val_S, rs1_val_S, is_quiet); + + let rd_val_S = if (f_is_NaN_S(rs1_val_S) | f_is_NaN_S(rs2_val_S)) then canonical_NaN_S() + else if (f_is_neg_zero_S(rs1_val_S) & f_is_pos_zero_S(rs2_val_S)) then rs2_val_S + else if (f_is_neg_zero_S(rs2_val_S) & f_is_pos_zero_S(rs1_val_S)) then rs1_val_S + else if rs2_lt_rs1 then rs1_val_S + else /* (not rs2_lt_rs1) */ rs2_val_S; + + accrue_fflags(fflags); + F_S(rd) = rd_val_S; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/F/fmin.s.yaml b/arch/inst/F/fmin.s.yaml index 21689e351..1670434a0 100644 --- a/arch/inst/F/fmin.s.yaml +++ b/arch/inst/F/fmin.s.yaml @@ -23,3 +23,20 @@ fmin.s: data_independent_timing: true operation(): | + + + + sail(): | + { + let rs1_val_S = F_or_X_S(rs1); + let rs2_val_S = F_or_X_S(rs2); + + let (fflags, rd_val) : (bits_fflags, bool) = + riscv_f32Le (rs1_val_S, rs2_val_S); + + accrue_fflags(fflags); + X(rd) = zero_extend(bool_to_bits(rd_val)); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/F/fminm.s.yaml b/arch/inst/F/fminm.s.yaml index 0cd64b1fd..62fff22d1 100644 --- a/arch/inst/F/fminm.s.yaml +++ b/arch/inst/F/fminm.s.yaml @@ -23,3 +23,26 @@ fminm.s: data_independent_timing: true operation(): | + + + + sail(): | + { + let rs1_val_S = F_S(rs1); + let rs2_val_S = F_S(rs2); + + let is_quiet = true; + let (rs1_lt_rs2, fflags) = fle_S (rs1_val_S, rs2_val_S, is_quiet); + + let rd_val_S = if (f_is_NaN_S(rs1_val_S) | f_is_NaN_S(rs2_val_S)) then canonical_NaN_S() + else if (f_is_neg_zero_S(rs1_val_S) & f_is_pos_zero_S(rs2_val_S)) then rs1_val_S + else if (f_is_neg_zero_S(rs2_val_S) & f_is_pos_zero_S(rs1_val_S)) then rs2_val_S + else if rs1_lt_rs2 then rs1_val_S + else /* (not rs1_lt_rs2) */ rs2_val_S; + + accrue_fflags(fflags); + F_S(rd) = rd_val_S; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/F/fmsub.s.yaml b/arch/inst/F/fmsub.s.yaml index ea8467473..f49703d62 100644 --- a/arch/inst/F/fmsub.s.yaml +++ b/arch/inst/F/fmsub.s.yaml @@ -27,3 +27,30 @@ fmsub.s: data_independent_timing: true operation(): | + + + + sail(): | + { + let rs1_val_32b = F_or_X_S(rs1); + let rs2_val_32b = F_or_X_S(rs2); + let rs3_val_32b = F_or_X_S(rs3); + match (select_instr_or_fcsr_rm (rm)) { + None() => { handle_illegal(); RETIRE_FAIL }, + Some(rm') => { + let rm_3b = encdec_rounding_mode(rm'); + let (fflags, rd_val_32b) : (bits(5), bits(32)) = + match op { + FMADD_S => riscv_f32MulAdd (rm_3b, rs1_val_32b, rs2_val_32b, rs3_val_32b), + FMSUB_S => riscv_f32MulAdd (rm_3b, rs1_val_32b, rs2_val_32b, negate_S (rs3_val_32b)), + FNMSUB_S => riscv_f32MulAdd (rm_3b, negate_S (rs1_val_32b), rs2_val_32b, rs3_val_32b), + FNMADD_S => riscv_f32MulAdd (rm_3b, negate_S (rs1_val_32b), rs2_val_32b, negate_S (rs3_val_32b)) + }; + accrue_fflags(fflags); + F_or_X_S(rd) = rd_val_32b; + RETIRE_SUCCESS + } + } + } + + \ No newline at end of file diff --git a/arch/inst/F/fmul.s.yaml b/arch/inst/F/fmul.s.yaml index 114850654..0fdddd9b3 100644 --- a/arch/inst/F/fmul.s.yaml +++ b/arch/inst/F/fmul.s.yaml @@ -25,3 +25,28 @@ fmul.s: data_independent_timing: true operation(): | + + + + sail(): | + { + let rs1_val_32b = F_or_X_S(rs1); + let rs2_val_32b = F_or_X_S(rs2); + match (select_instr_or_fcsr_rm (rm)) { + None() => { handle_illegal(); RETIRE_FAIL }, + Some(rm') => { + let rm_3b = encdec_rounding_mode(rm'); + let (fflags, rd_val_32b) : (bits(5), bits(32)) = match op { + FADD_S => riscv_f32Add (rm_3b, rs1_val_32b, rs2_val_32b), + FSUB_S => riscv_f32Sub (rm_3b, rs1_val_32b, rs2_val_32b), + FMUL_S => riscv_f32Mul (rm_3b, rs1_val_32b, rs2_val_32b), + FDIV_S => riscv_f32Div (rm_3b, rs1_val_32b, rs2_val_32b) + }; + accrue_fflags(fflags); + F_or_X_S(rd) = rd_val_32b; + RETIRE_SUCCESS + } + } + } + + \ No newline at end of file diff --git a/arch/inst/F/fmv.w.x.yaml b/arch/inst/F/fmv.w.x.yaml index 68bb11107..e783244d8 100644 --- a/arch/inst/F/fmv.w.x.yaml +++ b/arch/inst/F/fmv.w.x.yaml @@ -34,3 +34,15 @@ fmv.w.x: } mark_f_state_dirty(); + + + + sail(): | + { + let rs1_val_X = X(rs1); + let rd_val_S = rs1_val_X [31..0]; + F(rd) = nan_box (rd_val_S); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/F/fmv.x.w.yaml b/arch/inst/F/fmv.x.w.yaml index a57eb0658..71a3af0d8 100644 --- a/arch/inst/F/fmv.x.w.yaml +++ b/arch/inst/F/fmv.x.w.yaml @@ -28,3 +28,15 @@ fmv.x.w: check_f_ok($encoding); X[rd] = sext(f[fs1][31:0], 32); + + + + sail(): | + { + let rs1_val_X = X(rs1); + let rd_val_S = rs1_val_X [31..0]; + F(rd) = nan_box (rd_val_S); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/F/fnmadd.s.yaml b/arch/inst/F/fnmadd.s.yaml index d009f4de0..b4d329a7f 100644 --- a/arch/inst/F/fnmadd.s.yaml +++ b/arch/inst/F/fnmadd.s.yaml @@ -27,3 +27,30 @@ fnmadd.s: data_independent_timing: true operation(): | + + + + sail(): | + { + let rs1_val_32b = F_or_X_S(rs1); + let rs2_val_32b = F_or_X_S(rs2); + let rs3_val_32b = F_or_X_S(rs3); + match (select_instr_or_fcsr_rm (rm)) { + None() => { handle_illegal(); RETIRE_FAIL }, + Some(rm') => { + let rm_3b = encdec_rounding_mode(rm'); + let (fflags, rd_val_32b) : (bits(5), bits(32)) = + match op { + FMADD_S => riscv_f32MulAdd (rm_3b, rs1_val_32b, rs2_val_32b, rs3_val_32b), + FMSUB_S => riscv_f32MulAdd (rm_3b, rs1_val_32b, rs2_val_32b, negate_S (rs3_val_32b)), + FNMSUB_S => riscv_f32MulAdd (rm_3b, negate_S (rs1_val_32b), rs2_val_32b, rs3_val_32b), + FNMADD_S => riscv_f32MulAdd (rm_3b, negate_S (rs1_val_32b), rs2_val_32b, negate_S (rs3_val_32b)) + }; + accrue_fflags(fflags); + F_or_X_S(rd) = rd_val_32b; + RETIRE_SUCCESS + } + } + } + + \ No newline at end of file diff --git a/arch/inst/F/fnmsub.s.yaml b/arch/inst/F/fnmsub.s.yaml index ec75b319e..83ad862f0 100644 --- a/arch/inst/F/fnmsub.s.yaml +++ b/arch/inst/F/fnmsub.s.yaml @@ -27,3 +27,30 @@ fnmsub.s: data_independent_timing: true operation(): | + + + + sail(): | + { + let rs1_val_32b = F_or_X_S(rs1); + let rs2_val_32b = F_or_X_S(rs2); + let rs3_val_32b = F_or_X_S(rs3); + match (select_instr_or_fcsr_rm (rm)) { + None() => { handle_illegal(); RETIRE_FAIL }, + Some(rm') => { + let rm_3b = encdec_rounding_mode(rm'); + let (fflags, rd_val_32b) : (bits(5), bits(32)) = + match op { + FMADD_S => riscv_f32MulAdd (rm_3b, rs1_val_32b, rs2_val_32b, rs3_val_32b), + FMSUB_S => riscv_f32MulAdd (rm_3b, rs1_val_32b, rs2_val_32b, negate_S (rs3_val_32b)), + FNMSUB_S => riscv_f32MulAdd (rm_3b, negate_S (rs1_val_32b), rs2_val_32b, rs3_val_32b), + FNMADD_S => riscv_f32MulAdd (rm_3b, negate_S (rs1_val_32b), rs2_val_32b, negate_S (rs3_val_32b)) + }; + accrue_fflags(fflags); + F_or_X_S(rd) = rd_val_32b; + RETIRE_SUCCESS + } + } + } + + \ No newline at end of file diff --git a/arch/inst/F/fround.s.yaml b/arch/inst/F/fround.s.yaml index 75e67bb74..bb31e8f45 100644 --- a/arch/inst/F/fround.s.yaml +++ b/arch/inst/F/fround.s.yaml @@ -23,3 +23,24 @@ fround.s: data_independent_timing: true operation(): | + + + + sail(): | + { + let rs1_val_S = F_S(rs1); + + match (select_instr_or_fcsr_rm(rm)) { + None() => { handle_illegal(); RETIRE_FAIL }, + Some(rm') => { + let rm_3b = encdec_rounding_mode(rm'); + let (fflags, rd_val_S) = riscv_f32roundToInt(rm_3b, rs1_val_S, false); + + accrue_fflags(fflags); + F_S(rd) = rd_val_S; + RETIRE_SUCCESS + } + } + } + + \ No newline at end of file diff --git a/arch/inst/F/froundnx.s.yaml b/arch/inst/F/froundnx.s.yaml index 09e739fc1..2970eb003 100644 --- a/arch/inst/F/froundnx.s.yaml +++ b/arch/inst/F/froundnx.s.yaml @@ -23,3 +23,24 @@ froundnx.s: data_independent_timing: true operation(): | + + + + sail(): | + { + let rs1_val_S = F_S(rs1); + + match (select_instr_or_fcsr_rm(rm)) { + None() => { handle_illegal(); RETIRE_FAIL }, + Some(rm') => { + let rm_3b = encdec_rounding_mode(rm'); + let (fflags, rd_val_S) = riscv_f32roundToInt(rm_3b, rs1_val_S, true); + + accrue_fflags(fflags); + F_S(rd) = rd_val_S; + RETIRE_SUCCESS + } + } + } + + \ No newline at end of file diff --git a/arch/inst/F/fsgnj.s.yaml b/arch/inst/F/fsgnj.s.yaml index cfb1d0def..db5cb0763 100644 --- a/arch/inst/F/fsgnj.s.yaml +++ b/arch/inst/F/fsgnj.s.yaml @@ -40,3 +40,20 @@ fsgnj.s: } mark_f_state_dirty(); + + + + sail(): | + { + let rs1_val_S = F_or_X_S(rs1); + let rs2_val_S = F_or_X_S(rs2); + + let (fflags, rd_val) : (bits_fflags, bool) = + riscv_f32Le (rs1_val_S, rs2_val_S); + + accrue_fflags(fflags); + X(rd) = zero_extend(bool_to_bits(rd_val)); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/F/fsgnjn.s.yaml b/arch/inst/F/fsgnjn.s.yaml index 6baa35d88..d387948b4 100644 --- a/arch/inst/F/fsgnjn.s.yaml +++ b/arch/inst/F/fsgnjn.s.yaml @@ -39,3 +39,20 @@ fsgnjn.s: } mark_f_state_dirty(); + + + + sail(): | + { + let rs1_val_S = F_or_X_S(rs1); + let rs2_val_S = F_or_X_S(rs2); + + let (fflags, rd_val) : (bits_fflags, bool) = + riscv_f32Le (rs1_val_S, rs2_val_S); + + accrue_fflags(fflags); + X(rd) = zero_extend(bool_to_bits(rd_val)); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/F/fsgnjx.s.yaml b/arch/inst/F/fsgnjx.s.yaml index 7a27be68c..5c7a51f46 100644 --- a/arch/inst/F/fsgnjx.s.yaml +++ b/arch/inst/F/fsgnjx.s.yaml @@ -38,3 +38,20 @@ fsgnjx.s: } mark_f_state_dirty(); + + + + sail(): | + { + let rs1_val_S = F_or_X_S(rs1); + let rs2_val_S = F_or_X_S(rs2); + + let (fflags, rd_val) : (bits_fflags, bool) = + riscv_f32Le (rs1_val_S, rs2_val_S); + + accrue_fflags(fflags); + X(rd) = zero_extend(bool_to_bits(rd_val)); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/F/fsqrt.s.yaml b/arch/inst/F/fsqrt.s.yaml index 3a623b289..959175cec 100644 --- a/arch/inst/F/fsqrt.s.yaml +++ b/arch/inst/F/fsqrt.s.yaml @@ -23,3 +23,24 @@ fsqrt.s: data_independent_timing: true operation(): | + + + + sail(): | + { + assert(sizeof(xlen) >= 64); + let rs1_val_LU = X(rs1)[63..0]; + match (select_instr_or_fcsr_rm (rm)) { + None() => { handle_illegal(); RETIRE_FAIL }, + Some(rm') => { + let rm_3b = encdec_rounding_mode(rm'); + let (fflags, rd_val_S) = riscv_ui64ToF32 (rm_3b, rs1_val_LU); + + accrue_fflags(fflags); + F_or_X_S(rd) = rd_val_S; + RETIRE_SUCCESS + } + } + } + + \ No newline at end of file diff --git a/arch/inst/F/fsub.s.yaml b/arch/inst/F/fsub.s.yaml index 691fda24b..b3dba5bb6 100644 --- a/arch/inst/F/fsub.s.yaml +++ b/arch/inst/F/fsub.s.yaml @@ -25,3 +25,28 @@ fsub.s: data_independent_timing: true operation(): | + + + + sail(): | + { + let rs1_val_32b = F_or_X_S(rs1); + let rs2_val_32b = F_or_X_S(rs2); + match (select_instr_or_fcsr_rm (rm)) { + None() => { handle_illegal(); RETIRE_FAIL }, + Some(rm') => { + let rm_3b = encdec_rounding_mode(rm'); + let (fflags, rd_val_32b) : (bits(5), bits(32)) = match op { + FADD_S => riscv_f32Add (rm_3b, rs1_val_32b, rs2_val_32b), + FSUB_S => riscv_f32Sub (rm_3b, rs1_val_32b, rs2_val_32b), + FMUL_S => riscv_f32Mul (rm_3b, rs1_val_32b, rs2_val_32b), + FDIV_S => riscv_f32Div (rm_3b, rs1_val_32b, rs2_val_32b) + }; + accrue_fflags(fflags); + F_or_X_S(rd) = rd_val_32b; + RETIRE_SUCCESS + } + } + } + + \ No newline at end of file diff --git a/arch/inst/F/fsw.yaml b/arch/inst/F/fsw.yaml index d5983548b..1edd09aeb 100644 --- a/arch/inst/F/fsw.yaml +++ b/arch/inst/F/fsw.yaml @@ -30,3 +30,46 @@ fsw: XReg virtual_address = X[rs1] + $signed(imm); write_memory<32>(virtual_address, f[fs2][31:0], $encoding); + + + + sail(): | + { + let offset : xlenbits = sign_extend(imm); + let (aq, rl, con) = (false, false, false); + /* Get the address, X(rs1) + offset. + Some extensions perform additional checks on address validity. */ + match ext_data_get_addr(rs1, offset, Write(Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => + if check_misaligned(vaddr, width) + then { handle_mem_exception(vaddr, E_SAMO_Addr_Align()); RETIRE_FAIL } + else match translateAddr(vaddr, Write(Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => { + let eares : MemoryOpResult(unit) = match width { + BYTE => MemValue () /* bogus placeholder for illegal size */, + HALF => mem_write_ea(addr, 2, aq, rl, false), + WORD => mem_write_ea(addr, 4, aq, rl, false), + DOUBLE => mem_write_ea(addr, 8, aq, rl, false) + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + let rs2_val = F(rs2); + match (width) { + BYTE => { handle_illegal(); RETIRE_FAIL }, + HALF => process_fstore (vaddr, mem_write_value(addr, 2, rs2_val[15..0], aq, rl, con)), + WORD => process_fstore (vaddr, mem_write_value(addr, 4, rs2_val[31..0], aq, rl, con)), + DOUBLE if sizeof(flen) >= 64 => + process_fstore (vaddr, mem_write_value(addr, 8, rs2_val, aq, rl, con)), + _ => report_invalid_width(__FILE__, __LINE__, width, "floating point store"), + }; + } + } + } + } + } + } + + \ No newline at end of file diff --git a/arch/inst/I/add.yaml b/arch/inst/I/add.yaml index 8c7c55a0f..1a2c84ba0 100644 --- a/arch/inst/I/add.yaml +++ b/arch/inst/I/add.yaml @@ -23,3 +23,33 @@ add: vu: always data_independent_timing: true operation(): X[rd] = X[rs1] + X[rs2]; + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let result : xlenbits = match op { + RISCV_ADD => rs1_val + rs2_val, + RISCV_SLT => zero_extend(bool_to_bits(rs1_val <_s rs2_val)), + RISCV_SLTU => zero_extend(bool_to_bits(rs1_val <_u rs2_val)), + RISCV_AND => rs1_val & rs2_val, + RISCV_OR => rs1_val | rs2_val, + RISCV_XOR => rs1_val ^ rs2_val, + RISCV_SLL => if sizeof(xlen) == 32 + then rs1_val << (rs2_val[4..0]) + else rs1_val << (rs2_val[5..0]), + RISCV_SRL => if sizeof(xlen) == 32 + then rs1_val >> (rs2_val[4..0]) + else rs1_val >> (rs2_val[5..0]), + RISCV_SUB => rs1_val - rs2_val, + RISCV_SRA => if sizeof(xlen) == 32 + then shift_right_arith32(rs1_val, rs2_val[4..0]) + else shift_right_arith64(rs1_val, rs2_val[5..0]) + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/addi.yaml b/arch/inst/I/addi.yaml index c15f124db..4c60b8dbc 100644 --- a/arch/inst/I/addi.yaml +++ b/arch/inst/I/addi.yaml @@ -21,3 +21,23 @@ addi: vu: always data_independent_timing: true operation(): X[rd] = X[rs1] + imm; + + + + sail(): | + { + let rs1_val = X(rs1); + let immext : xlenbits = sign_extend(imm); + let result : xlenbits = match op { + RISCV_ADDI => rs1_val + immext, + RISCV_SLTI => zero_extend(bool_to_bits(rs1_val <_s immext)), + RISCV_SLTIU => zero_extend(bool_to_bits(rs1_val <_u immext)), + RISCV_ANDI => rs1_val & immext, + RISCV_ORI => rs1_val | immext, + RISCV_XORI => rs1_val ^ immext + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/addiw.yaml b/arch/inst/I/addiw.yaml index c9c1119a7..c59921d00 100644 --- a/arch/inst/I/addiw.yaml +++ b/arch/inst/I/addiw.yaml @@ -24,3 +24,14 @@ addiw: operation(): | XReg operand = sext(X[rs1], 31); X[rd] = sext(operand + imm, 31); + + + + sail(): | + { + let result : xlenbits = sign_extend(imm) + X(rs1); + X(rd) = sign_extend(result[31..0]); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/addw.yaml b/arch/inst/I/addw.yaml index 2f70a76d1..5b6d0012d 100644 --- a/arch/inst/I/addw.yaml +++ b/arch/inst/I/addw.yaml @@ -27,3 +27,22 @@ addw: XReg operand1 = sext(X[rs1], 31); XReg operand2 = sext(X[rs2], 31); X[rd] = sext(operand1 + operand2, 31); + + + + sail(): | + { + let rs1_val = (X(rs1))[31..0]; + let rs2_val = (X(rs2))[31..0]; + let result : bits(32) = match op { + RISCV_ADDW => rs1_val + rs2_val, + RISCV_SUBW => rs1_val - rs2_val, + RISCV_SLLW => rs1_val << (rs2_val[4..0]), + RISCV_SRLW => rs1_val >> (rs2_val[4..0]), + RISCV_SRAW => shift_right_arith32(rs1_val, rs2_val[4..0]) + }; + X(rd) = sign_extend(result); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/and.yaml b/arch/inst/I/and.yaml index d3f8251fd..7507597ab 100644 --- a/arch/inst/I/and.yaml +++ b/arch/inst/I/and.yaml @@ -21,3 +21,33 @@ and: vu: always data_independent_timing: true operation(): X[rd] = X[rs1] & X[rs2]; + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let result : xlenbits = match op { + RISCV_ADD => rs1_val + rs2_val, + RISCV_SLT => zero_extend(bool_to_bits(rs1_val <_s rs2_val)), + RISCV_SLTU => zero_extend(bool_to_bits(rs1_val <_u rs2_val)), + RISCV_AND => rs1_val & rs2_val, + RISCV_OR => rs1_val | rs2_val, + RISCV_XOR => rs1_val ^ rs2_val, + RISCV_SLL => if sizeof(xlen) == 32 + then rs1_val << (rs2_val[4..0]) + else rs1_val << (rs2_val[5..0]), + RISCV_SRL => if sizeof(xlen) == 32 + then rs1_val >> (rs2_val[4..0]) + else rs1_val >> (rs2_val[5..0]), + RISCV_SUB => rs1_val - rs2_val, + RISCV_SRA => if sizeof(xlen) == 32 + then shift_right_arith32(rs1_val, rs2_val[4..0]) + else shift_right_arith64(rs1_val, rs2_val[5..0]) + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/andi.yaml b/arch/inst/I/andi.yaml index 396ade3b5..a4115c957 100644 --- a/arch/inst/I/andi.yaml +++ b/arch/inst/I/andi.yaml @@ -21,3 +21,23 @@ andi: vu: always data_independent_timing: true operation(): X[rd] = X[rs1] & imm; + + + + sail(): | + { + let rs1_val = X(rs1); + let immext : xlenbits = sign_extend(imm); + let result : xlenbits = match op { + RISCV_ADDI => rs1_val + immext, + RISCV_SLTI => zero_extend(bool_to_bits(rs1_val <_s immext)), + RISCV_SLTIU => zero_extend(bool_to_bits(rs1_val <_u immext)), + RISCV_ANDI => rs1_val & immext, + RISCV_ORI => rs1_val | immext, + RISCV_XORI => rs1_val ^ immext + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/auipc.yaml b/arch/inst/I/auipc.yaml index b5d75f040..6fccca45b 100644 --- a/arch/inst/I/auipc.yaml +++ b/arch/inst/I/auipc.yaml @@ -20,3 +20,18 @@ auipc: vu: always data_independent_timing: true operation(): X[rd] = $pc + imm; + + + + sail(): | + { + let off : xlenbits = sign_extend(imm @ 0x000); + let ret : xlenbits = match op { + RISCV_LUI => off, + RISCV_AUIPC => get_arch_pc() + off + }; + X(rd) = ret; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/beq.yaml b/arch/inst/I/beq.yaml index 8dd5c8a1b..da03ec17d 100644 --- a/arch/inst/I/beq.yaml +++ b/arch/inst/I/beq.yaml @@ -30,4 +30,40 @@ beq: if (lhs == rhs) { jump_halfword($pc + imm); - } \ No newline at end of file + } + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let taken : bool = match op { + RISCV_BEQ => rs1_val == rs2_val, + RISCV_BNE => rs1_val != rs2_val, + RISCV_BLT => rs1_val <_s rs2_val, + RISCV_BGE => rs1_val >=_s rs2_val, + RISCV_BLTU => rs1_val <_u rs2_val, + RISCV_BGEU => rs1_val >=_u rs2_val + }; + let t : xlenbits = PC + sign_extend(imm); + if taken then { + /* Extensions get the first checks on the prospective target address. */ + match ext_control_check_pc(t) { + Ext_ControlAddr_Error(e) => { + ext_handle_control_check_error(e); + RETIRE_FAIL + }, + Ext_ControlAddr_OK(target) => { + if bit_to_bool(target[1]) & not(extension("C")) then { + handle_mem_exception(target, E_Fetch_Addr_Align()); + RETIRE_FAIL; + } else { + set_next_pc(target); + RETIRE_SUCCESS + } + } + } + } else RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/bge.yaml b/arch/inst/I/bge.yaml index 7b7c6bf7a..7244ea39d 100644 --- a/arch/inst/I/bge.yaml +++ b/arch/inst/I/bge.yaml @@ -31,4 +31,40 @@ bge: if ($signed(lhs) >= $signed(rhs)) { jump_halfword($pc + imm); } - \ No newline at end of file + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let taken : bool = match op { + RISCV_BEQ => rs1_val == rs2_val, + RISCV_BNE => rs1_val != rs2_val, + RISCV_BLT => rs1_val <_s rs2_val, + RISCV_BGE => rs1_val >=_s rs2_val, + RISCV_BLTU => rs1_val <_u rs2_val, + RISCV_BGEU => rs1_val >=_u rs2_val + }; + let t : xlenbits = PC + sign_extend(imm); + if taken then { + /* Extensions get the first checks on the prospective target address. */ + match ext_control_check_pc(t) { + Ext_ControlAddr_Error(e) => { + ext_handle_control_check_error(e); + RETIRE_FAIL + }, + Ext_ControlAddr_OK(target) => { + if bit_to_bool(target[1]) & not(extension("C")) then { + handle_mem_exception(target, E_Fetch_Addr_Align()); + RETIRE_FAIL; + } else { + set_next_pc(target); + RETIRE_SUCCESS + } + } + } + } else RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/bgeu.yaml b/arch/inst/I/bgeu.yaml index 2a37476dd..47607d0f2 100644 --- a/arch/inst/I/bgeu.yaml +++ b/arch/inst/I/bgeu.yaml @@ -31,4 +31,40 @@ bgeu: if (lhs >= rhs) { jump_halfword($pc + imm); } - \ No newline at end of file + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let taken : bool = match op { + RISCV_BEQ => rs1_val == rs2_val, + RISCV_BNE => rs1_val != rs2_val, + RISCV_BLT => rs1_val <_s rs2_val, + RISCV_BGE => rs1_val >=_s rs2_val, + RISCV_BLTU => rs1_val <_u rs2_val, + RISCV_BGEU => rs1_val >=_u rs2_val + }; + let t : xlenbits = PC + sign_extend(imm); + if taken then { + /* Extensions get the first checks on the prospective target address. */ + match ext_control_check_pc(t) { + Ext_ControlAddr_Error(e) => { + ext_handle_control_check_error(e); + RETIRE_FAIL + }, + Ext_ControlAddr_OK(target) => { + if bit_to_bool(target[1]) & not(extension("C")) then { + handle_mem_exception(target, E_Fetch_Addr_Align()); + RETIRE_FAIL; + } else { + set_next_pc(target); + RETIRE_SUCCESS + } + } + } + } else RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/blt.yaml b/arch/inst/I/blt.yaml index aa0cbe34b..e598bddce 100644 --- a/arch/inst/I/blt.yaml +++ b/arch/inst/I/blt.yaml @@ -31,4 +31,40 @@ blt: if ($signed(lhs) < $signed(rhs)) { jump_halfword($pc + imm); } - \ No newline at end of file + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let taken : bool = match op { + RISCV_BEQ => rs1_val == rs2_val, + RISCV_BNE => rs1_val != rs2_val, + RISCV_BLT => rs1_val <_s rs2_val, + RISCV_BGE => rs1_val >=_s rs2_val, + RISCV_BLTU => rs1_val <_u rs2_val, + RISCV_BGEU => rs1_val >=_u rs2_val + }; + let t : xlenbits = PC + sign_extend(imm); + if taken then { + /* Extensions get the first checks on the prospective target address. */ + match ext_control_check_pc(t) { + Ext_ControlAddr_Error(e) => { + ext_handle_control_check_error(e); + RETIRE_FAIL + }, + Ext_ControlAddr_OK(target) => { + if bit_to_bool(target[1]) & not(extension("C")) then { + handle_mem_exception(target, E_Fetch_Addr_Align()); + RETIRE_FAIL; + } else { + set_next_pc(target); + RETIRE_SUCCESS + } + } + } + } else RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/bltu.yaml b/arch/inst/I/bltu.yaml index ccac6e6af..ce3a61692 100644 --- a/arch/inst/I/bltu.yaml +++ b/arch/inst/I/bltu.yaml @@ -31,4 +31,40 @@ bltu: if (lhs < rhs) { jump_halfword($pc + imm); } - \ No newline at end of file + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let taken : bool = match op { + RISCV_BEQ => rs1_val == rs2_val, + RISCV_BNE => rs1_val != rs2_val, + RISCV_BLT => rs1_val <_s rs2_val, + RISCV_BGE => rs1_val >=_s rs2_val, + RISCV_BLTU => rs1_val <_u rs2_val, + RISCV_BGEU => rs1_val >=_u rs2_val + }; + let t : xlenbits = PC + sign_extend(imm); + if taken then { + /* Extensions get the first checks on the prospective target address. */ + match ext_control_check_pc(t) { + Ext_ControlAddr_Error(e) => { + ext_handle_control_check_error(e); + RETIRE_FAIL + }, + Ext_ControlAddr_OK(target) => { + if bit_to_bool(target[1]) & not(extension("C")) then { + handle_mem_exception(target, E_Fetch_Addr_Align()); + RETIRE_FAIL; + } else { + set_next_pc(target); + RETIRE_SUCCESS + } + } + } + } else RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/bne.yaml b/arch/inst/I/bne.yaml index 46e264d56..73c71211d 100644 --- a/arch/inst/I/bne.yaml +++ b/arch/inst/I/bne.yaml @@ -31,4 +31,40 @@ bne: if (lhs != rhs) { jump_halfword($pc + imm); } - \ No newline at end of file + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let taken : bool = match op { + RISCV_BEQ => rs1_val == rs2_val, + RISCV_BNE => rs1_val != rs2_val, + RISCV_BLT => rs1_val <_s rs2_val, + RISCV_BGE => rs1_val >=_s rs2_val, + RISCV_BLTU => rs1_val <_u rs2_val, + RISCV_BGEU => rs1_val >=_u rs2_val + }; + let t : xlenbits = PC + sign_extend(imm); + if taken then { + /* Extensions get the first checks on the prospective target address. */ + match ext_control_check_pc(t) { + Ext_ControlAddr_Error(e) => { + ext_handle_control_check_error(e); + RETIRE_FAIL + }, + Ext_ControlAddr_OK(target) => { + if bit_to_bool(target[1]) & not(extension("C")) then { + handle_mem_exception(target, E_Fetch_Addr_Align()); + RETIRE_FAIL; + } else { + set_next_pc(target); + RETIRE_SUCCESS + } + } + } + } else RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/ebreak.yaml b/arch/inst/I/ebreak.yaml index b73611865..5e7424b6f 100644 --- a/arch/inst/I/ebreak.yaml +++ b/arch/inst/I/ebreak.yaml @@ -30,3 +30,13 @@ ebreak: } else { eei_ebreak(); } + + + + sail(): | + { + handle_mem_exception(PC, E_Breakpoint()); + RETIRE_FAIL + } + + \ No newline at end of file diff --git a/arch/inst/I/ecall.yaml b/arch/inst/I/ecall.yaml index a61b4e2a4..36c484861 100644 --- a/arch/inst/I/ecall.yaml +++ b/arch/inst/I/ecall.yaml @@ -53,3 +53,21 @@ ecall: eei_ecall_from_vs(); } } + + + + sail(): | + { + let t : sync_exception = + struct { trap = match (cur_privilege) { + User => E_U_EnvCall(), + Supervisor => E_S_EnvCall(), + Machine => E_M_EnvCall() + }, + excinfo = (None() : option(xlenbits)), + ext = None() }; + set_next_pc(exception_handler(cur_privilege, CTL_TRAP(t), PC)); + RETIRE_FAIL + } + + \ No newline at end of file diff --git a/arch/inst/I/fence.yaml b/arch/inst/I/fence.yaml index ec93c38cd..40cc6bc7d 100644 --- a/arch/inst/I/fence.yaml +++ b/arch/inst/I/fence.yaml @@ -205,3 +205,34 @@ fence: to: fence.tso - when: (pred == 1) && (succ == 0) && (fm == 0) && (rd == 0) && (rs1 == 0) to: pause + + + + sail(): | + { + // If the FIOM bit in menvcfg/senvcfg is set then the I/O bits can imply R/W. + let fiom = is_fiom_active(); + let pred = effective_fence_set(pred, fiom); + let succ = effective_fence_set(succ, fiom); + + match (pred, succ) { + (_ : bits(2) @ 0b11, _ : bits(2) @ 0b11) => __barrier(Barrier_RISCV_rw_rw()), + (_ : bits(2) @ 0b10, _ : bits(2) @ 0b11) => __barrier(Barrier_RISCV_r_rw()), + (_ : bits(2) @ 0b10, _ : bits(2) @ 0b10) => __barrier(Barrier_RISCV_r_r()), + (_ : bits(2) @ 0b11, _ : bits(2) @ 0b01) => __barrier(Barrier_RISCV_rw_w()), + (_ : bits(2) @ 0b01, _ : bits(2) @ 0b01) => __barrier(Barrier_RISCV_w_w()), + (_ : bits(2) @ 0b01, _ : bits(2) @ 0b11) => __barrier(Barrier_RISCV_w_rw()), + (_ : bits(2) @ 0b11, _ : bits(2) @ 0b10) => __barrier(Barrier_RISCV_rw_r()), + (_ : bits(2) @ 0b10, _ : bits(2) @ 0b01) => __barrier(Barrier_RISCV_r_w()), + (_ : bits(2) @ 0b01, _ : bits(2) @ 0b10) => __barrier(Barrier_RISCV_w_r()), + + (_ : bits(4) , _ : bits(2) @ 0b00) => (), + (_ : bits(2) @ 0b00, _ : bits(4) ) => (), + + _ => { print("FIXME: unsupported fence"); + () } + }; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/jal.yaml b/arch/inst/I/jal.yaml index 19628b710..45922de5b 100644 --- a/arch/inst/I/jal.yaml +++ b/arch/inst/I/jal.yaml @@ -26,3 +26,31 @@ jal: jump_halfword($pc + imm); X[rd] = retrun_addr; + + + + sail(): | + { + let t : xlenbits = PC + sign_extend(imm); + /* Extensions get the first checks on the prospective target address. */ + match ext_control_check_pc(t) { + Ext_ControlAddr_Error(e) => { + ext_handle_control_check_error(e); + RETIRE_FAIL + }, + Ext_ControlAddr_OK(target) => { + /* Perform standard alignment check */ + if bit_to_bool(target[1]) & not(extension("C")) + then { + handle_mem_exception(target, E_Fetch_Addr_Align()); + RETIRE_FAIL + } else { + X(rd) = get_next_pc(); + set_next_pc(target); + RETIRE_SUCCESS + } + } + } + } + + \ No newline at end of file diff --git a/arch/inst/I/jalr.yaml b/arch/inst/I/jalr.yaml index 9cf474398..5b82ee320 100644 --- a/arch/inst/I/jalr.yaml +++ b/arch/inst/I/jalr.yaml @@ -27,3 +27,36 @@ jalr: jump(X[rs1] + imm); X[rd] = returnaddr; + + + + sail(): | + { + /* For the sequential model, the memory-model definition doesn't work directly + * if rs1 = rd. We would effectively have to keep a regfile for reads and another for + * writes, and swap on instruction completion. This could perhaps be optimized in + * some manner, but for now, we just keep a reordered definition to improve simulator + * performance. + */ + let t : xlenbits = X(rs1) + sign_extend(imm); + /* Extensions get the first checks on the prospective target address. */ + match ext_control_check_addr(t) { + Ext_ControlAddr_Error(e) => { + ext_handle_control_check_error(e); + RETIRE_FAIL + }, + Ext_ControlAddr_OK(addr) => { + let target = [addr with 0 = bitzero]; /* clear addr[0] */ + if bit_to_bool(target[1]) & not(extension("C")) then { + handle_mem_exception(target, E_Fetch_Addr_Align()); + RETIRE_FAIL + } else { + X(rd) = get_next_pc(); + set_next_pc(target); + RETIRE_SUCCESS + } + } + } + } + + \ No newline at end of file diff --git a/arch/inst/I/lb.yaml b/arch/inst/I/lb.yaml index 4e49635d9..1929ca61c 100644 --- a/arch/inst/I/lb.yaml +++ b/arch/inst/I/lb.yaml @@ -26,3 +26,35 @@ lb: XReg virtual_address = X[rs1] + imm; X[rd] = sext(read_memory<8>(virtual_address, $encoding), 8); + + + + sail(): | + { + let offset : xlenbits = sign_extend(imm); + /* Get the address, X(rs1) + offset. + Some extensions perform additional checks on address validity. */ + match ext_data_get_addr(rs1, offset, Read(Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => + if check_misaligned(vaddr, width) + then { handle_mem_exception(vaddr, E_Load_Addr_Align()); RETIRE_FAIL } + else match translateAddr(vaddr, Read(Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(paddr, _) => + match (width) { + BYTE => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 1, aq, rl, false), is_unsigned), + HALF => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 2, aq, rl, false), is_unsigned), + WORD => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 4, aq, rl, false), is_unsigned), + DOUBLE if sizeof(xlen) >= 64 => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 8, aq, rl, false), is_unsigned), + _ => report_invalid_width(__FILE__, __LINE__, width, "load") + } + } + } + } + + \ No newline at end of file diff --git a/arch/inst/I/lbu.yaml b/arch/inst/I/lbu.yaml index bdb303a89..f427a5121 100644 --- a/arch/inst/I/lbu.yaml +++ b/arch/inst/I/lbu.yaml @@ -26,3 +26,35 @@ lbu: XReg virtual_address = X[rs1] + imm; X[rd] = read_memory<8>(virtual_address, $encoding); + + + + sail(): | + { + let offset : xlenbits = sign_extend(imm); + /* Get the address, X(rs1) + offset. + Some extensions perform additional checks on address validity. */ + match ext_data_get_addr(rs1, offset, Read(Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => + if check_misaligned(vaddr, width) + then { handle_mem_exception(vaddr, E_Load_Addr_Align()); RETIRE_FAIL } + else match translateAddr(vaddr, Read(Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(paddr, _) => + match (width) { + BYTE => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 1, aq, rl, false), is_unsigned), + HALF => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 2, aq, rl, false), is_unsigned), + WORD => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 4, aq, rl, false), is_unsigned), + DOUBLE if sizeof(xlen) >= 64 => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 8, aq, rl, false), is_unsigned), + _ => report_invalid_width(__FILE__, __LINE__, width, "load") + } + } + } + } + + \ No newline at end of file diff --git a/arch/inst/I/ld.yaml b/arch/inst/I/ld.yaml index 8cedaff15..e5715ca5d 100644 --- a/arch/inst/I/ld.yaml +++ b/arch/inst/I/ld.yaml @@ -26,3 +26,35 @@ ld: XReg virtual_address = X[rs1] + imm; X[rd] = read_memory<64>(virtual_address, $encoding); + + + + sail(): | + { + let offset : xlenbits = sign_extend(imm); + /* Get the address, X(rs1) + offset. + Some extensions perform additional checks on address validity. */ + match ext_data_get_addr(rs1, offset, Read(Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => + if check_misaligned(vaddr, width) + then { handle_mem_exception(vaddr, E_Load_Addr_Align()); RETIRE_FAIL } + else match translateAddr(vaddr, Read(Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(paddr, _) => + match (width) { + BYTE => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 1, aq, rl, false), is_unsigned), + HALF => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 2, aq, rl, false), is_unsigned), + WORD => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 4, aq, rl, false), is_unsigned), + DOUBLE if sizeof(xlen) >= 64 => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 8, aq, rl, false), is_unsigned), + _ => report_invalid_width(__FILE__, __LINE__, width, "load") + } + } + } + } + + \ No newline at end of file diff --git a/arch/inst/I/lh.yaml b/arch/inst/I/lh.yaml index d59266e51..e4170512b 100644 --- a/arch/inst/I/lh.yaml +++ b/arch/inst/I/lh.yaml @@ -26,3 +26,35 @@ lh: XReg virtual_address = X[rs1] + imm; X[rd] = sext(read_memory<16>(virtual_address, $encoding), 16); + + + + sail(): | + { + let offset : xlenbits = sign_extend(imm); + /* Get the address, X(rs1) + offset. + Some extensions perform additional checks on address validity. */ + match ext_data_get_addr(rs1, offset, Read(Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => + if check_misaligned(vaddr, width) + then { handle_mem_exception(vaddr, E_Load_Addr_Align()); RETIRE_FAIL } + else match translateAddr(vaddr, Read(Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(paddr, _) => + match (width) { + BYTE => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 1, aq, rl, false), is_unsigned), + HALF => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 2, aq, rl, false), is_unsigned), + WORD => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 4, aq, rl, false), is_unsigned), + DOUBLE if sizeof(xlen) >= 64 => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 8, aq, rl, false), is_unsigned), + _ => report_invalid_width(__FILE__, __LINE__, width, "load") + } + } + } + } + + \ No newline at end of file diff --git a/arch/inst/I/lhu.yaml b/arch/inst/I/lhu.yaml index cc56c9abf..373d8e358 100644 --- a/arch/inst/I/lhu.yaml +++ b/arch/inst/I/lhu.yaml @@ -26,3 +26,35 @@ lhu: XReg virtual_address = X[rs1] + imm; X[rd] = read_memory<16>(virtual_address, $encoding); + + + + sail(): | + { + let offset : xlenbits = sign_extend(imm); + /* Get the address, X(rs1) + offset. + Some extensions perform additional checks on address validity. */ + match ext_data_get_addr(rs1, offset, Read(Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => + if check_misaligned(vaddr, width) + then { handle_mem_exception(vaddr, E_Load_Addr_Align()); RETIRE_FAIL } + else match translateAddr(vaddr, Read(Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(paddr, _) => + match (width) { + BYTE => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 1, aq, rl, false), is_unsigned), + HALF => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 2, aq, rl, false), is_unsigned), + WORD => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 4, aq, rl, false), is_unsigned), + DOUBLE if sizeof(xlen) >= 64 => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 8, aq, rl, false), is_unsigned), + _ => report_invalid_width(__FILE__, __LINE__, width, "load") + } + } + } + } + + \ No newline at end of file diff --git a/arch/inst/I/lui.yaml b/arch/inst/I/lui.yaml index 28ea165c5..9c5894936 100644 --- a/arch/inst/I/lui.yaml +++ b/arch/inst/I/lui.yaml @@ -20,3 +20,18 @@ lui: vu: always data_independent_timing: true operation(): X[rd] = imm; + + + + sail(): | + { + let off : xlenbits = sign_extend(imm @ 0x000); + let ret : xlenbits = match op { + RISCV_LUI => off, + RISCV_AUIPC => get_arch_pc() + off + }; + X(rd) = ret; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/lw.yaml b/arch/inst/I/lw.yaml index ed72e7bb3..c5f698acc 100644 --- a/arch/inst/I/lw.yaml +++ b/arch/inst/I/lw.yaml @@ -26,3 +26,35 @@ lw: XReg virtual_address = X[rs1] + imm; X[rd] = read_memory<32>(virtual_address, $encoding); + + + + sail(): | + { + let offset : xlenbits = sign_extend(imm); + /* Get the address, X(rs1) + offset. + Some extensions perform additional checks on address validity. */ + match ext_data_get_addr(rs1, offset, Read(Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => + if check_misaligned(vaddr, width) + then { handle_mem_exception(vaddr, E_Load_Addr_Align()); RETIRE_FAIL } + else match translateAddr(vaddr, Read(Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(paddr, _) => + match (width) { + BYTE => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 1, aq, rl, false), is_unsigned), + HALF => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 2, aq, rl, false), is_unsigned), + WORD => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 4, aq, rl, false), is_unsigned), + DOUBLE if sizeof(xlen) >= 64 => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 8, aq, rl, false), is_unsigned), + _ => report_invalid_width(__FILE__, __LINE__, width, "load") + } + } + } + } + + \ No newline at end of file diff --git a/arch/inst/I/lwu.yaml b/arch/inst/I/lwu.yaml index dd179342e..f636c508b 100644 --- a/arch/inst/I/lwu.yaml +++ b/arch/inst/I/lwu.yaml @@ -27,3 +27,35 @@ lwu: XReg virtual_address = X[rs1] + imm; X[rd] = read_memory<32>(virtual_address, $encoding); + + + + sail(): | + { + let offset : xlenbits = sign_extend(imm); + /* Get the address, X(rs1) + offset. + Some extensions perform additional checks on address validity. */ + match ext_data_get_addr(rs1, offset, Read(Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => + if check_misaligned(vaddr, width) + then { handle_mem_exception(vaddr, E_Load_Addr_Align()); RETIRE_FAIL } + else match translateAddr(vaddr, Read(Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(paddr, _) => + match (width) { + BYTE => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 1, aq, rl, false), is_unsigned), + HALF => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 2, aq, rl, false), is_unsigned), + WORD => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 4, aq, rl, false), is_unsigned), + DOUBLE if sizeof(xlen) >= 64 => + process_load(rd, vaddr, mem_read(Read(Data), paddr, 8, aq, rl, false), is_unsigned), + _ => report_invalid_width(__FILE__, __LINE__, width, "load") + } + } + } + } + + \ No newline at end of file diff --git a/arch/inst/I/mret.yaml b/arch/inst/I/mret.yaml index 9640223f6..421d5f148 100644 --- a/arch/inst/I/mret.yaml +++ b/arch/inst/I/mret.yaml @@ -26,3 +26,19 @@ mret: } CSR[mstatus].MPP = implemented?(ExtensionName::U) ? 2'b00 : 2'b11; $pc = $bits(CSR[mepc]); + + + + sail(): | + { + if cur_privilege != Machine + then { handle_illegal(); RETIRE_FAIL } + else if not(ext_check_xret_priv (Machine)) + then { ext_fail_xret_priv(); RETIRE_FAIL } + else { + set_next_pc(exception_handler(cur_privilege, CTL_MRET(), PC)); + RETIRE_SUCCESS + } + } + + \ No newline at end of file diff --git a/arch/inst/I/or.yaml b/arch/inst/I/or.yaml index 2b8896dc6..81694ccea 100644 --- a/arch/inst/I/or.yaml +++ b/arch/inst/I/or.yaml @@ -21,3 +21,33 @@ or: vu: always data_independent_timing: true operation(): X[rd] = X[rs1] | X[rs2]; + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let result : xlenbits = match op { + RISCV_ADD => rs1_val + rs2_val, + RISCV_SLT => zero_extend(bool_to_bits(rs1_val <_s rs2_val)), + RISCV_SLTU => zero_extend(bool_to_bits(rs1_val <_u rs2_val)), + RISCV_AND => rs1_val & rs2_val, + RISCV_OR => rs1_val | rs2_val, + RISCV_XOR => rs1_val ^ rs2_val, + RISCV_SLL => if sizeof(xlen) == 32 + then rs1_val << (rs2_val[4..0]) + else rs1_val << (rs2_val[5..0]), + RISCV_SRL => if sizeof(xlen) == 32 + then rs1_val >> (rs2_val[4..0]) + else rs1_val >> (rs2_val[5..0]), + RISCV_SUB => rs1_val - rs2_val, + RISCV_SRA => if sizeof(xlen) == 32 + then shift_right_arith32(rs1_val, rs2_val[4..0]) + else shift_right_arith64(rs1_val, rs2_val[5..0]) + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/ori.yaml b/arch/inst/I/ori.yaml index 2a7ebec69..3c53d1c6f 100644 --- a/arch/inst/I/ori.yaml +++ b/arch/inst/I/ori.yaml @@ -46,3 +46,23 @@ ori: to: prefetch.r offset - when: (rd == 0) && (imm[4:0] == 3) to: prefetch.w offset + + + + sail(): | + { + let rs1_val = X(rs1); + let immext : xlenbits = sign_extend(imm); + let result : xlenbits = match op { + RISCV_ADDI => rs1_val + immext, + RISCV_SLTI => zero_extend(bool_to_bits(rs1_val <_s immext)), + RISCV_SLTIU => zero_extend(bool_to_bits(rs1_val <_u immext)), + RISCV_ANDI => rs1_val & immext, + RISCV_ORI => rs1_val | immext, + RISCV_XORI => rs1_val ^ immext + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/sb.yaml b/arch/inst/I/sb.yaml index aa2c1dcf4..55fe9e8e0 100644 --- a/arch/inst/I/sb.yaml +++ b/arch/inst/I/sb.yaml @@ -25,3 +25,50 @@ sb: XReg virtual_address = X[rs1] + imm; write_memory<8>(virtual_address, X[rs2][7:0], $encoding); + + + + sail(): | + { + let offset : xlenbits = sign_extend(imm); + /* Get the address, X(rs1) + offset. + Some extensions perform additional checks on address validity. */ + match ext_data_get_addr(rs1, offset, Write(Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => + if check_misaligned(vaddr, width) + then { handle_mem_exception(vaddr, E_SAMO_Addr_Align()); RETIRE_FAIL } + else match translateAddr(vaddr, Write(Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(paddr, _) => { + let eares : MemoryOpResult(unit) = match width { + BYTE => mem_write_ea(paddr, 1, aq, rl, false), + HALF => mem_write_ea(paddr, 2, aq, rl, false), + WORD => mem_write_ea(paddr, 4, aq, rl, false), + DOUBLE => mem_write_ea(paddr, 8, aq, rl, false) + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + let rs2_val = X(rs2); + let res : MemoryOpResult(bool) = match (width) { + BYTE => mem_write_value(paddr, 1, rs2_val[7..0], aq, rl, false), + HALF => mem_write_value(paddr, 2, rs2_val[15..0], aq, rl, false), + WORD => mem_write_value(paddr, 4, rs2_val[31..0], aq, rl, false), + DOUBLE if sizeof(xlen) >= 64 + => mem_write_value(paddr, 8, rs2_val, aq, rl, false), + _ => report_invalid_width(__FILE__, __LINE__, width, "store"), + }; + match (res) { + MemValue(true) => RETIRE_SUCCESS, + MemValue(false) => internal_error(__FILE__, __LINE__, "store got false from mem_write_value"), + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } + } + } + } + } + } + } + } + + \ No newline at end of file diff --git a/arch/inst/I/sd.yaml b/arch/inst/I/sd.yaml index fe67324e2..192bfa1ca 100644 --- a/arch/inst/I/sd.yaml +++ b/arch/inst/I/sd.yaml @@ -27,3 +27,50 @@ sd: XReg virtual_address = X[rs1] + imm; write_memory<64>(virtual_address, X[rs2], $encoding); + + + + sail(): | + { + let offset : xlenbits = sign_extend(imm); + /* Get the address, X(rs1) + offset. + Some extensions perform additional checks on address validity. */ + match ext_data_get_addr(rs1, offset, Write(Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => + if check_misaligned(vaddr, width) + then { handle_mem_exception(vaddr, E_SAMO_Addr_Align()); RETIRE_FAIL } + else match translateAddr(vaddr, Write(Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(paddr, _) => { + let eares : MemoryOpResult(unit) = match width { + BYTE => mem_write_ea(paddr, 1, aq, rl, false), + HALF => mem_write_ea(paddr, 2, aq, rl, false), + WORD => mem_write_ea(paddr, 4, aq, rl, false), + DOUBLE => mem_write_ea(paddr, 8, aq, rl, false) + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + let rs2_val = X(rs2); + let res : MemoryOpResult(bool) = match (width) { + BYTE => mem_write_value(paddr, 1, rs2_val[7..0], aq, rl, false), + HALF => mem_write_value(paddr, 2, rs2_val[15..0], aq, rl, false), + WORD => mem_write_value(paddr, 4, rs2_val[31..0], aq, rl, false), + DOUBLE if sizeof(xlen) >= 64 + => mem_write_value(paddr, 8, rs2_val, aq, rl, false), + _ => report_invalid_width(__FILE__, __LINE__, width, "store"), + }; + match (res) { + MemValue(true) => RETIRE_SUCCESS, + MemValue(false) => internal_error(__FILE__, __LINE__, "store got false from mem_write_value"), + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } + } + } + } + } + } + } + } + + \ No newline at end of file diff --git a/arch/inst/I/sh.yaml b/arch/inst/I/sh.yaml index 813676201..59b653744 100644 --- a/arch/inst/I/sh.yaml +++ b/arch/inst/I/sh.yaml @@ -25,3 +25,50 @@ sh: XReg virtual_address = X[rs1] + imm; write_memory<16>(virtual_address, X[rs2][15:0], $encoding); + + + + sail(): | + { + let offset : xlenbits = sign_extend(imm); + /* Get the address, X(rs1) + offset. + Some extensions perform additional checks on address validity. */ + match ext_data_get_addr(rs1, offset, Write(Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => + if check_misaligned(vaddr, width) + then { handle_mem_exception(vaddr, E_SAMO_Addr_Align()); RETIRE_FAIL } + else match translateAddr(vaddr, Write(Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(paddr, _) => { + let eares : MemoryOpResult(unit) = match width { + BYTE => mem_write_ea(paddr, 1, aq, rl, false), + HALF => mem_write_ea(paddr, 2, aq, rl, false), + WORD => mem_write_ea(paddr, 4, aq, rl, false), + DOUBLE => mem_write_ea(paddr, 8, aq, rl, false) + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + let rs2_val = X(rs2); + let res : MemoryOpResult(bool) = match (width) { + BYTE => mem_write_value(paddr, 1, rs2_val[7..0], aq, rl, false), + HALF => mem_write_value(paddr, 2, rs2_val[15..0], aq, rl, false), + WORD => mem_write_value(paddr, 4, rs2_val[31..0], aq, rl, false), + DOUBLE if sizeof(xlen) >= 64 + => mem_write_value(paddr, 8, rs2_val, aq, rl, false), + _ => report_invalid_width(__FILE__, __LINE__, width, "store"), + }; + match (res) { + MemValue(true) => RETIRE_SUCCESS, + MemValue(false) => internal_error(__FILE__, __LINE__, "store got false from mem_write_value"), + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } + } + } + } + } + } + } + } + + \ No newline at end of file diff --git a/arch/inst/I/sll.yaml b/arch/inst/I/sll.yaml index 0b06fc40d..3ba787e04 100644 --- a/arch/inst/I/sll.yaml +++ b/arch/inst/I/sll.yaml @@ -27,3 +27,33 @@ sll: } else { X[rd] = X[rs1] << X[rs2][4:0]; } + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let result : xlenbits = match op { + RISCV_ADD => rs1_val + rs2_val, + RISCV_SLT => zero_extend(bool_to_bits(rs1_val <_s rs2_val)), + RISCV_SLTU => zero_extend(bool_to_bits(rs1_val <_u rs2_val)), + RISCV_AND => rs1_val & rs2_val, + RISCV_OR => rs1_val | rs2_val, + RISCV_XOR => rs1_val ^ rs2_val, + RISCV_SLL => if sizeof(xlen) == 32 + then rs1_val << (rs2_val[4..0]) + else rs1_val << (rs2_val[5..0]), + RISCV_SRL => if sizeof(xlen) == 32 + then rs1_val >> (rs2_val[4..0]) + else rs1_val >> (rs2_val[5..0]), + RISCV_SUB => rs1_val - rs2_val, + RISCV_SRA => if sizeof(xlen) == 32 + then shift_right_arith32(rs1_val, rs2_val[4..0]) + else shift_right_arith64(rs1_val, rs2_val[5..0]) + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/slli.yaml b/arch/inst/I/slli.yaml index bca10c224..caa9b5ba7 100644 --- a/arch/inst/I/slli.yaml +++ b/arch/inst/I/slli.yaml @@ -33,3 +33,26 @@ slli: operation(): | # shamt is between 0-(XLEN-1) X[rd] = X[rs1] << shamt; + + + + sail(): | + { + let rs1_val = X(rs1); + /* the decoder guard should ensure that shamt[5] = 0 for RV32 */ + let result : xlenbits = match op { + RISCV_SLLI => if sizeof(xlen) == 32 + then rs1_val << shamt[4..0] + else rs1_val << shamt, + RISCV_SRLI => if sizeof(xlen) == 32 + then rs1_val >> shamt[4..0] + else rs1_val >> shamt, + RISCV_SRAI => if sizeof(xlen) == 32 + then shift_right_arith32(rs1_val, shamt[4..0]) + else shift_right_arith64(rs1_val, shamt) + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/slliw.yaml b/arch/inst/I/slliw.yaml index 7401f0a82..0dd58e94b 100644 --- a/arch/inst/I/slliw.yaml +++ b/arch/inst/I/slliw.yaml @@ -24,3 +24,19 @@ slliw: operation(): | # shamt is between 0-32 X[rd] = sext(X[rs1] << shamt, 31); + + + + sail(): | + { + let rs1_val = (X(rs1))[31..0]; + let result : bits(32) = match op { + RISCV_SLLIW => rs1_val << shamt, + RISCV_SRLIW => rs1_val >> shamt, + RISCV_SRAIW => shift_right_arith32(rs1_val, shamt) + }; + X(rd) = sign_extend(result); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/sllw.yaml b/arch/inst/I/sllw.yaml index d44bac990..8853862bf 100644 --- a/arch/inst/I/sllw.yaml +++ b/arch/inst/I/sllw.yaml @@ -23,3 +23,22 @@ sllw: vu: always data_independent_timing: true operation(): X[rd] = sext(X[rs1] << X[rs2][4:0], 31); + + + + sail(): | + { + let rs1_val = (X(rs1))[31..0]; + let rs2_val = (X(rs2))[31..0]; + let result : bits(32) = match op { + RISCV_ADDW => rs1_val + rs2_val, + RISCV_SUBW => rs1_val - rs2_val, + RISCV_SLLW => rs1_val << (rs2_val[4..0]), + RISCV_SRLW => rs1_val >> (rs2_val[4..0]), + RISCV_SRAW => shift_right_arith32(rs1_val, rs2_val[4..0]) + }; + X(rd) = sign_extend(result); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/slt.yaml b/arch/inst/I/slt.yaml index 44f076170..4ebe38012 100644 --- a/arch/inst/I/slt.yaml +++ b/arch/inst/I/slt.yaml @@ -27,3 +27,33 @@ slt: XReg src2 = X[rs2]; X[rd] = ($signed(src1) < $signed(src2)) ? '1 : '0; + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let result : xlenbits = match op { + RISCV_ADD => rs1_val + rs2_val, + RISCV_SLT => zero_extend(bool_to_bits(rs1_val <_s rs2_val)), + RISCV_SLTU => zero_extend(bool_to_bits(rs1_val <_u rs2_val)), + RISCV_AND => rs1_val & rs2_val, + RISCV_OR => rs1_val | rs2_val, + RISCV_XOR => rs1_val ^ rs2_val, + RISCV_SLL => if sizeof(xlen) == 32 + then rs1_val << (rs2_val[4..0]) + else rs1_val << (rs2_val[5..0]), + RISCV_SRL => if sizeof(xlen) == 32 + then rs1_val >> (rs2_val[4..0]) + else rs1_val >> (rs2_val[5..0]), + RISCV_SUB => rs1_val - rs2_val, + RISCV_SRA => if sizeof(xlen) == 32 + then shift_right_arith32(rs1_val, rs2_val[4..0]) + else shift_right_arith64(rs1_val, rs2_val[5..0]) + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/slti.yaml b/arch/inst/I/slti.yaml index ebad4e988..6c932b89b 100644 --- a/arch/inst/I/slti.yaml +++ b/arch/inst/I/slti.yaml @@ -24,3 +24,23 @@ slti: data_independent_timing: true operation(): | X[rd] = ($signed(X[rs1]) < $signed(imm)) ? '1 : '0; + + + + sail(): | + { + let rs1_val = X(rs1); + let immext : xlenbits = sign_extend(imm); + let result : xlenbits = match op { + RISCV_ADDI => rs1_val + immext, + RISCV_SLTI => zero_extend(bool_to_bits(rs1_val <_s immext)), + RISCV_SLTIU => zero_extend(bool_to_bits(rs1_val <_u immext)), + RISCV_ANDI => rs1_val & immext, + RISCV_ORI => rs1_val | immext, + RISCV_XORI => rs1_val ^ immext + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/sltiu.yaml b/arch/inst/I/sltiu.yaml index fc59e29b7..59e109de8 100644 --- a/arch/inst/I/sltiu.yaml +++ b/arch/inst/I/sltiu.yaml @@ -28,3 +28,23 @@ sltiu: data_independent_timing: true operation(): | X[rd] = (X[rs1] < imm) ? 1 : 0; + + + + sail(): | + { + let rs1_val = X(rs1); + let immext : xlenbits = sign_extend(imm); + let result : xlenbits = match op { + RISCV_ADDI => rs1_val + immext, + RISCV_SLTI => zero_extend(bool_to_bits(rs1_val <_s immext)), + RISCV_SLTIU => zero_extend(bool_to_bits(rs1_val <_u immext)), + RISCV_ANDI => rs1_val & immext, + RISCV_ORI => rs1_val | immext, + RISCV_XORI => rs1_val ^ immext + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/sltu.yaml b/arch/inst/I/sltu.yaml index dfac7dac0..2c1d5db98 100644 --- a/arch/inst/I/sltu.yaml +++ b/arch/inst/I/sltu.yaml @@ -24,3 +24,33 @@ sltu: data_independent_timing: true operation(): | X[rd] = (X[rs1] < X[rs2]) ? 1 : 0; + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let result : xlenbits = match op { + RISCV_ADD => rs1_val + rs2_val, + RISCV_SLT => zero_extend(bool_to_bits(rs1_val <_s rs2_val)), + RISCV_SLTU => zero_extend(bool_to_bits(rs1_val <_u rs2_val)), + RISCV_AND => rs1_val & rs2_val, + RISCV_OR => rs1_val | rs2_val, + RISCV_XOR => rs1_val ^ rs2_val, + RISCV_SLL => if sizeof(xlen) == 32 + then rs1_val << (rs2_val[4..0]) + else rs1_val << (rs2_val[5..0]), + RISCV_SRL => if sizeof(xlen) == 32 + then rs1_val >> (rs2_val[4..0]) + else rs1_val >> (rs2_val[5..0]), + RISCV_SUB => rs1_val - rs2_val, + RISCV_SRA => if sizeof(xlen) == 32 + then shift_right_arith32(rs1_val, rs2_val[4..0]) + else shift_right_arith64(rs1_val, rs2_val[5..0]) + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/sra.yaml b/arch/inst/I/sra.yaml index 7e42b1dc6..09aeb8d26 100644 --- a/arch/inst/I/sra.yaml +++ b/arch/inst/I/sra.yaml @@ -27,3 +27,33 @@ sra: } else { X[rd] = X[rs1] >>> X[rs2][4:0]; } + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let result : xlenbits = match op { + RISCV_ADD => rs1_val + rs2_val, + RISCV_SLT => zero_extend(bool_to_bits(rs1_val <_s rs2_val)), + RISCV_SLTU => zero_extend(bool_to_bits(rs1_val <_u rs2_val)), + RISCV_AND => rs1_val & rs2_val, + RISCV_OR => rs1_val | rs2_val, + RISCV_XOR => rs1_val ^ rs2_val, + RISCV_SLL => if sizeof(xlen) == 32 + then rs1_val << (rs2_val[4..0]) + else rs1_val << (rs2_val[5..0]), + RISCV_SRL => if sizeof(xlen) == 32 + then rs1_val >> (rs2_val[4..0]) + else rs1_val >> (rs2_val[5..0]), + RISCV_SUB => rs1_val - rs2_val, + RISCV_SRA => if sizeof(xlen) == 32 + then shift_right_arith32(rs1_val, rs2_val[4..0]) + else shift_right_arith64(rs1_val, rs2_val[5..0]) + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/srai.yaml b/arch/inst/I/srai.yaml index 4e33fa7cf..98211da0e 100644 --- a/arch/inst/I/srai.yaml +++ b/arch/inst/I/srai.yaml @@ -35,3 +35,26 @@ srai: operation(): | # shamt is between 0-63 X[rd] = X[rs1] >>> shamt; + + + + sail(): | + { + let rs1_val = X(rs1); + /* the decoder guard should ensure that shamt[5] = 0 for RV32 */ + let result : xlenbits = match op { + RISCV_SLLI => if sizeof(xlen) == 32 + then rs1_val << shamt[4..0] + else rs1_val << shamt, + RISCV_SRLI => if sizeof(xlen) == 32 + then rs1_val >> shamt[4..0] + else rs1_val >> shamt, + RISCV_SRAI => if sizeof(xlen) == 32 + then shift_right_arith32(rs1_val, shamt[4..0]) + else shift_right_arith64(rs1_val, shamt) + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/sraiw.yaml b/arch/inst/I/sraiw.yaml index 40b277367..ba8115ce7 100644 --- a/arch/inst/I/sraiw.yaml +++ b/arch/inst/I/sraiw.yaml @@ -27,3 +27,19 @@ sraiw: # shamt is between 0-32 XReg operand = sext(X[rs1], 31); X[rd] = sext(operand >>> shamt, 31); + + + + sail(): | + { + let rs1_val = (X(rs1))[31..0]; + let result : bits(32) = match op { + RISCV_SLLIW => rs1_val << shamt, + RISCV_SRLIW => rs1_val >> shamt, + RISCV_SRAIW => shift_right_arith32(rs1_val, shamt) + }; + X(rd) = sign_extend(result); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/sraw.yaml b/arch/inst/I/sraw.yaml index f50febc21..5c49924c0 100644 --- a/arch/inst/I/sraw.yaml +++ b/arch/inst/I/sraw.yaml @@ -26,3 +26,22 @@ sraw: XReg operand1 = sext(X[rs1], 31); X[rd] = sext(operand1 >>> X[rs2][4:0], 31); + + + + sail(): | + { + let rs1_val = (X(rs1))[31..0]; + let rs2_val = (X(rs2))[31..0]; + let result : bits(32) = match op { + RISCV_ADDW => rs1_val + rs2_val, + RISCV_SUBW => rs1_val - rs2_val, + RISCV_SLLW => rs1_val << (rs2_val[4..0]), + RISCV_SRLW => rs1_val >> (rs2_val[4..0]), + RISCV_SRAW => shift_right_arith32(rs1_val, rs2_val[4..0]) + }; + X(rd) = sign_extend(result); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/srl.yaml b/arch/inst/I/srl.yaml index 4a995c2c4..61f7135f4 100644 --- a/arch/inst/I/srl.yaml +++ b/arch/inst/I/srl.yaml @@ -27,3 +27,33 @@ srl: } else { X[rd] = X[rs1] >> X[rs2][4:0]; } + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let result : xlenbits = match op { + RISCV_ADD => rs1_val + rs2_val, + RISCV_SLT => zero_extend(bool_to_bits(rs1_val <_s rs2_val)), + RISCV_SLTU => zero_extend(bool_to_bits(rs1_val <_u rs2_val)), + RISCV_AND => rs1_val & rs2_val, + RISCV_OR => rs1_val | rs2_val, + RISCV_XOR => rs1_val ^ rs2_val, + RISCV_SLL => if sizeof(xlen) == 32 + then rs1_val << (rs2_val[4..0]) + else rs1_val << (rs2_val[5..0]), + RISCV_SRL => if sizeof(xlen) == 32 + then rs1_val >> (rs2_val[4..0]) + else rs1_val >> (rs2_val[5..0]), + RISCV_SUB => rs1_val - rs2_val, + RISCV_SRA => if sizeof(xlen) == 32 + then shift_right_arith32(rs1_val, rs2_val[4..0]) + else shift_right_arith64(rs1_val, rs2_val[5..0]) + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/srli.yaml b/arch/inst/I/srli.yaml index d9b6c7475..b0125f5ad 100644 --- a/arch/inst/I/srli.yaml +++ b/arch/inst/I/srli.yaml @@ -32,3 +32,26 @@ srli: operation(): | # shamt is between 0-63 X[rd] = X[rs1] >> shamt; + + + + sail(): | + { + let rs1_val = X(rs1); + /* the decoder guard should ensure that shamt[5] = 0 for RV32 */ + let result : xlenbits = match op { + RISCV_SLLI => if sizeof(xlen) == 32 + then rs1_val << shamt[4..0] + else rs1_val << shamt, + RISCV_SRLI => if sizeof(xlen) == 32 + then rs1_val >> shamt[4..0] + else rs1_val >> shamt, + RISCV_SRAI => if sizeof(xlen) == 32 + then shift_right_arith32(rs1_val, shamt[4..0]) + else shift_right_arith64(rs1_val, shamt) + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/srliw.yaml b/arch/inst/I/srliw.yaml index 9bd346086..b8e480c7c 100644 --- a/arch/inst/I/srliw.yaml +++ b/arch/inst/I/srliw.yaml @@ -26,3 +26,19 @@ srliw: XReg operand = X[rs1][31:0]; X[rd] = sext(operand >> shamt, 31); + + + + sail(): | + { + let rs1_val = (X(rs1))[31..0]; + let result : bits(32) = match op { + RISCV_SLLIW => rs1_val << shamt, + RISCV_SRLIW => rs1_val >> shamt, + RISCV_SRAIW => shift_right_arith32(rs1_val, shamt) + }; + X(rd) = sign_extend(result); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/srlw.yaml b/arch/inst/I/srlw.yaml index 9f34a12c9..b47f5440e 100644 --- a/arch/inst/I/srlw.yaml +++ b/arch/inst/I/srlw.yaml @@ -23,3 +23,22 @@ srlw: vu: always data_independent_timing: true operation(): X[rd] = sext(X[rs1][31:0] >> X[rs2][4:0], 31); + + + + sail(): | + { + let rs1_val = (X(rs1))[31..0]; + let rs2_val = (X(rs2))[31..0]; + let result : bits(32) = match op { + RISCV_ADDW => rs1_val + rs2_val, + RISCV_SUBW => rs1_val - rs2_val, + RISCV_SLLW => rs1_val << (rs2_val[4..0]), + RISCV_SRLW => rs1_val >> (rs2_val[4..0]), + RISCV_SRAW => shift_right_arith32(rs1_val, rs2_val[4..0]) + }; + X(rd) = sign_extend(result); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/sub.yaml b/arch/inst/I/sub.yaml index da77dfb67..8a1190ee5 100644 --- a/arch/inst/I/sub.yaml +++ b/arch/inst/I/sub.yaml @@ -24,3 +24,33 @@ sub: XReg t0 = X[rs1]; XReg t1 = X[rs2]; X[rd] = t0 - t1; + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let result : xlenbits = match op { + RISCV_ADD => rs1_val + rs2_val, + RISCV_SLT => zero_extend(bool_to_bits(rs1_val <_s rs2_val)), + RISCV_SLTU => zero_extend(bool_to_bits(rs1_val <_u rs2_val)), + RISCV_AND => rs1_val & rs2_val, + RISCV_OR => rs1_val | rs2_val, + RISCV_XOR => rs1_val ^ rs2_val, + RISCV_SLL => if sizeof(xlen) == 32 + then rs1_val << (rs2_val[4..0]) + else rs1_val << (rs2_val[5..0]), + RISCV_SRL => if sizeof(xlen) == 32 + then rs1_val >> (rs2_val[4..0]) + else rs1_val >> (rs2_val[5..0]), + RISCV_SUB => rs1_val - rs2_val, + RISCV_SRA => if sizeof(xlen) == 32 + then shift_right_arith32(rs1_val, rs2_val[4..0]) + else shift_right_arith64(rs1_val, rs2_val[5..0]) + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/subw.yaml b/arch/inst/I/subw.yaml index 7358a02e7..3e7e17a1a 100644 --- a/arch/inst/I/subw.yaml +++ b/arch/inst/I/subw.yaml @@ -25,3 +25,22 @@ subw: Bits<32> t0 = X[rs1][31:0]; Bits<32> t1 = X[rs2][31:0]; X[rd] = sext(t0 - t1, 31); + + + + sail(): | + { + let rs1_val = (X(rs1))[31..0]; + let rs2_val = (X(rs2))[31..0]; + let result : bits(32) = match op { + RISCV_ADDW => rs1_val + rs2_val, + RISCV_SUBW => rs1_val - rs2_val, + RISCV_SLLW => rs1_val << (rs2_val[4..0]), + RISCV_SRLW => rs1_val >> (rs2_val[4..0]), + RISCV_SRAW => shift_right_arith32(rs1_val, rs2_val[4..0]) + }; + X(rd) = sign_extend(result); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/sw.yaml b/arch/inst/I/sw.yaml index 6d7f656f3..c1e22cd02 100644 --- a/arch/inst/I/sw.yaml +++ b/arch/inst/I/sw.yaml @@ -25,3 +25,50 @@ sw: XReg virtual_address = X[rs1] + imm; write_memory<32>(virtual_address, X[rs2][31:0], $encoding); + + + + sail(): | + { + let offset : xlenbits = sign_extend(imm); + /* Get the address, X(rs1) + offset. + Some extensions perform additional checks on address validity. */ + match ext_data_get_addr(rs1, offset, Write(Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => + if check_misaligned(vaddr, width) + then { handle_mem_exception(vaddr, E_SAMO_Addr_Align()); RETIRE_FAIL } + else match translateAddr(vaddr, Write(Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(paddr, _) => { + let eares : MemoryOpResult(unit) = match width { + BYTE => mem_write_ea(paddr, 1, aq, rl, false), + HALF => mem_write_ea(paddr, 2, aq, rl, false), + WORD => mem_write_ea(paddr, 4, aq, rl, false), + DOUBLE => mem_write_ea(paddr, 8, aq, rl, false) + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + let rs2_val = X(rs2); + let res : MemoryOpResult(bool) = match (width) { + BYTE => mem_write_value(paddr, 1, rs2_val[7..0], aq, rl, false), + HALF => mem_write_value(paddr, 2, rs2_val[15..0], aq, rl, false), + WORD => mem_write_value(paddr, 4, rs2_val[31..0], aq, rl, false), + DOUBLE if sizeof(xlen) >= 64 + => mem_write_value(paddr, 8, rs2_val, aq, rl, false), + _ => report_invalid_width(__FILE__, __LINE__, width, "store"), + }; + match (res) { + MemValue(true) => RETIRE_SUCCESS, + MemValue(false) => internal_error(__FILE__, __LINE__, "store got false from mem_write_value"), + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } + } + } + } + } + } + } + } + + \ No newline at end of file diff --git a/arch/inst/I/wfi.yaml b/arch/inst/I/wfi.yaml index e62ab8cd5..23b350e94 100644 --- a/arch/inst/I/wfi.yaml +++ b/arch/inst/I/wfi.yaml @@ -108,3 +108,16 @@ wfi: # passed, so now do the wait wfi(); + + + + sail(): | + match cur_privilege { + Machine => { platform_wfi(); RETIRE_SUCCESS }, + Supervisor => if mstatus.TW() == 0b1 + then { handle_illegal(); RETIRE_FAIL } + else { platform_wfi(); RETIRE_SUCCESS }, + User => { handle_illegal(); RETIRE_FAIL } + } + + \ No newline at end of file diff --git a/arch/inst/I/xor.yaml b/arch/inst/I/xor.yaml index a2c997665..a13b09b88 100644 --- a/arch/inst/I/xor.yaml +++ b/arch/inst/I/xor.yaml @@ -21,3 +21,33 @@ xor: vu: always data_independent_timing: true operation(): X[rd] = X[rs1] ^ X[rs2]; + + + + sail(): | + { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let result : xlenbits = match op { + RISCV_ADD => rs1_val + rs2_val, + RISCV_SLT => zero_extend(bool_to_bits(rs1_val <_s rs2_val)), + RISCV_SLTU => zero_extend(bool_to_bits(rs1_val <_u rs2_val)), + RISCV_AND => rs1_val & rs2_val, + RISCV_OR => rs1_val | rs2_val, + RISCV_XOR => rs1_val ^ rs2_val, + RISCV_SLL => if sizeof(xlen) == 32 + then rs1_val << (rs2_val[4..0]) + else rs1_val << (rs2_val[5..0]), + RISCV_SRL => if sizeof(xlen) == 32 + then rs1_val >> (rs2_val[4..0]) + else rs1_val >> (rs2_val[5..0]), + RISCV_SUB => rs1_val - rs2_val, + RISCV_SRA => if sizeof(xlen) == 32 + then shift_right_arith32(rs1_val, rs2_val[4..0]) + else shift_right_arith64(rs1_val, rs2_val[5..0]) + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/I/xori.yaml b/arch/inst/I/xori.yaml index 0b757b035..400f35500 100644 --- a/arch/inst/I/xori.yaml +++ b/arch/inst/I/xori.yaml @@ -21,3 +21,23 @@ xori: vu: always data_independent_timing: true operation(): X[rd] = X[rs1] ^ imm; + + + + sail(): | + { + let rs1_val = X(rs1); + let immext : xlenbits = sign_extend(imm); + let result : xlenbits = match op { + RISCV_ADDI => rs1_val + immext, + RISCV_SLTI => zero_extend(bool_to_bits(rs1_val <_s immext)), + RISCV_SLTIU => zero_extend(bool_to_bits(rs1_val <_u immext)), + RISCV_ANDI => rs1_val & immext, + RISCV_ORI => rs1_val | immext, + RISCV_XORI => rs1_val ^ immext + }; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/M/div.yaml b/arch/inst/M/div.yaml index 5db3ec9c1..50c51e359 100644 --- a/arch/inst/M/div.yaml +++ b/arch/inst/M/div.yaml @@ -46,4 +46,25 @@ div: } else { # no special case, just divide X[rd] = $signed(src1) / $signed(src2); - } \ No newline at end of file + } + + + sail(): | + { + if extension("M") then { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let rs1_int : int = if s then signed(rs1_val) else unsigned(rs1_val); + let rs2_int : int = if s then signed(rs2_val) else unsigned(rs2_val); + let q : int = if rs2_int == 0 then -1 else quot_round_zero(rs1_int, rs2_int); + /* check for signed overflow */ + let q': int = if s & q > xlen_max_signed then xlen_min_signed else q; + X(rd) = to_bits(sizeof(xlen), q'); + RETIRE_SUCCESS + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/M/divu.yaml b/arch/inst/M/divu.yaml index 6c995676f..5c2a4b3a9 100644 --- a/arch/inst/M/divu.yaml +++ b/arch/inst/M/divu.yaml @@ -38,4 +38,25 @@ divu: X[rd] = {XLEN{1'b1}}; } else { X[rd] = src1 / src2; - } \ No newline at end of file + } + + + sail(): | + { + if extension("M") then { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let rs1_int : int = if s then signed(rs1_val) else unsigned(rs1_val); + let rs2_int : int = if s then signed(rs2_val) else unsigned(rs2_val); + let q : int = if rs2_int == 0 then -1 else quot_round_zero(rs1_int, rs2_int); + /* check for signed overflow */ + let q': int = if s & q > xlen_max_signed then xlen_min_signed else q; + X(rd) = to_bits(sizeof(xlen), q'); + RETIRE_SUCCESS + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/M/divuw.yaml b/arch/inst/M/divuw.yaml index 18d5e0124..ffb32ff19 100644 --- a/arch/inst/M/divuw.yaml +++ b/arch/inst/M/divuw.yaml @@ -44,3 +44,25 @@ divuw: X[rd] = {{32{sign_bit}}, result}; } + + + + sail(): | + { + if extension("M") then { + let rs1_val = X(rs1)[31..0]; + let rs2_val = X(rs2)[31..0]; + let rs1_int : int = if s then signed(rs1_val) else unsigned(rs1_val); + let rs2_int : int = if s then signed(rs2_val) else unsigned(rs2_val); + let q : int = if rs2_int == 0 then -1 else quot_round_zero(rs1_int, rs2_int); + /* check for signed overflow */ + let q': int = if s & q > (2 ^ 31 - 1) then (0 - 2^31) else q; + X(rd) = sign_extend(to_bits(32, q')); + RETIRE_SUCCESS + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/M/divw.yaml b/arch/inst/M/divw.yaml index 277df8c6d..39b0dad17 100644 --- a/arch/inst/M/divw.yaml +++ b/arch/inst/M/divw.yaml @@ -53,3 +53,25 @@ divw: X[rd] = {{32{sign_bit}}, result}; } + + + + sail(): | + { + if extension("M") then { + let rs1_val = X(rs1)[31..0]; + let rs2_val = X(rs2)[31..0]; + let rs1_int : int = if s then signed(rs1_val) else unsigned(rs1_val); + let rs2_int : int = if s then signed(rs2_val) else unsigned(rs2_val); + let q : int = if rs2_int == 0 then -1 else quot_round_zero(rs1_int, rs2_int); + /* check for signed overflow */ + let q': int = if s & q > (2 ^ 31 - 1) then (0 - 2^31) else q; + X(rd) = sign_extend(to_bits(32, q')); + RETIRE_SUCCESS + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/M/mul.yaml b/arch/inst/M/mul.yaml index 02c608584..e383b5ac8 100644 --- a/arch/inst/M/mul.yaml +++ b/arch/inst/M/mul.yaml @@ -41,4 +41,26 @@ mul: XReg src1 = X[rs1]; XReg src2 = X[rs2]; - X[rd] = (src1 * src2)[XLEN-1:0]; \ No newline at end of file + X[rd] = (src1 * src2)[XLEN-1:0]; + + + sail(): | + { + if extension("M") | haveZmmul() then { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let rs1_int : int = if signed1 then signed(rs1_val) else unsigned(rs1_val); + let rs2_int : int = if signed2 then signed(rs2_val) else unsigned(rs2_val); + let result_wide = to_bits(2 * sizeof(xlen), rs1_int * rs2_int); + let result = if high + then result_wide[(2 * sizeof(xlen) - 1) .. sizeof(xlen)] + else result_wide[(sizeof(xlen) - 1) .. 0]; + X(rd) = result; + RETIRE_SUCCESS + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/M/mulh.yaml b/arch/inst/M/mulh.yaml index 2e97db046..27e10ee35 100644 --- a/arch/inst/M/mulh.yaml +++ b/arch/inst/M/mulh.yaml @@ -46,3 +46,26 @@ mulh: # grab the high half of the result, and put it in rd X[rd] = (src1 * src2)[(xlen()*8'd2)-1:xlen()]; + + + + sail(): | + { + if extension("M") | haveZmmul() then { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let rs1_int : int = if signed1 then signed(rs1_val) else unsigned(rs1_val); + let rs2_int : int = if signed2 then signed(rs2_val) else unsigned(rs2_val); + let result_wide = to_bits(2 * sizeof(xlen), rs1_int * rs2_int); + let result = if high + then result_wide[(2 * sizeof(xlen) - 1) .. sizeof(xlen)] + else result_wide[(sizeof(xlen) - 1) .. 0]; + X(rd) = result; + RETIRE_SUCCESS + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/M/mulhsu.yaml b/arch/inst/M/mulhsu.yaml index 80b4da7a3..98fc2d34a 100644 --- a/arch/inst/M/mulhsu.yaml +++ b/arch/inst/M/mulhsu.yaml @@ -42,4 +42,26 @@ mulhsu: Bits src1 = {{XLEN{rs1_sign_bit}}, X[rs1]}; Bits src2 = {{XLEN{1'b0}}, X[rs2]}; - X[rd] = (src1 * src2)[(XLEN*8'd2)-1:XLEN]; \ No newline at end of file + X[rd] = (src1 * src2)[(XLEN*8'd2)-1:XLEN]; + + + sail(): | + { + if extension("M") | haveZmmul() then { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let rs1_int : int = if signed1 then signed(rs1_val) else unsigned(rs1_val); + let rs2_int : int = if signed2 then signed(rs2_val) else unsigned(rs2_val); + let result_wide = to_bits(2 * sizeof(xlen), rs1_int * rs2_int); + let result = if high + then result_wide[(2 * sizeof(xlen) - 1) .. sizeof(xlen)] + else result_wide[(sizeof(xlen) - 1) .. 0]; + X(rd) = result; + RETIRE_SUCCESS + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/M/mulhu.yaml b/arch/inst/M/mulhu.yaml index cf80a29d3..4e37ff076 100644 --- a/arch/inst/M/mulhu.yaml +++ b/arch/inst/M/mulhu.yaml @@ -41,4 +41,26 @@ mulhu: Bits src1 = {{XLEN{1'b0}}, X[rs1]}; Bits src2 = {{XLEN{1'b0}}, X[rs2]}; - X[rd] = (src1 * src2)[(XLEN*8'd2)-1:XLEN]; \ No newline at end of file + X[rd] = (src1 * src2)[(XLEN*8'd2)-1:XLEN]; + + + sail(): | + { + if extension("M") | haveZmmul() then { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let rs1_int : int = if signed1 then signed(rs1_val) else unsigned(rs1_val); + let rs2_int : int = if signed2 then signed(rs2_val) else unsigned(rs2_val); + let result_wide = to_bits(2 * sizeof(xlen), rs1_int * rs2_int); + let result = if high + then result_wide[(2 * sizeof(xlen) - 1) .. sizeof(xlen)] + else result_wide[(sizeof(xlen) - 1) .. 0]; + X(rd) = result; + RETIRE_SUCCESS + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/M/mulw.yaml b/arch/inst/M/mulw.yaml index 4ef1e6b56..6385fa3a6 100644 --- a/arch/inst/M/mulw.yaml +++ b/arch/inst/M/mulw.yaml @@ -44,3 +44,25 @@ mulw: # return the sign-extended result X[rd] = {{32{sign_bit}}, result}; + + + + sail(): | + { + if extension("M") | haveZmmul() then { + let rs1_val = X(rs1)[31..0]; + let rs2_val = X(rs2)[31..0]; + let rs1_int : int = signed(rs1_val); + let rs2_int : int = signed(rs2_val); + /* to_bits requires expansion to 64 bits followed by truncation */ + let result32 = to_bits(64, rs1_int * rs2_int)[31..0]; + let result : xlenbits = sign_extend(result32); + X(rd) = result; + RETIRE_SUCCESS + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/M/rem.yaml b/arch/inst/M/rem.yaml index cbcdc2e1a..d49e5f23f 100644 --- a/arch/inst/M/rem.yaml +++ b/arch/inst/M/rem.yaml @@ -44,4 +44,24 @@ rem: } else { X[rd] = $signed(src1) % $signed(src2); - } \ No newline at end of file + } + + + sail(): | + { + if extension("M") then { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let rs1_int : int = if s then signed(rs1_val) else unsigned(rs1_val); + let rs2_int : int = if s then signed(rs2_val) else unsigned(rs2_val); + let r : int = if rs2_int == 0 then rs1_int else rem_round_zero(rs1_int, rs2_int); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + X(rd) = to_bits(sizeof(xlen), r); + RETIRE_SUCCESS + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/M/remu.yaml b/arch/inst/M/remu.yaml index 471adc3e4..a95b4f3a8 100644 --- a/arch/inst/M/remu.yaml +++ b/arch/inst/M/remu.yaml @@ -34,4 +34,24 @@ remu: X[rd] = src1; } else { X[rd] = src1 % src2; - } \ No newline at end of file + } + + + sail(): | + { + if extension("M") then { + let rs1_val = X(rs1); + let rs2_val = X(rs2); + let rs1_int : int = if s then signed(rs1_val) else unsigned(rs1_val); + let rs2_int : int = if s then signed(rs2_val) else unsigned(rs2_val); + let r : int = if rs2_int == 0 then rs1_int else rem_round_zero(rs1_int, rs2_int); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + X(rd) = to_bits(sizeof(xlen), r); + RETIRE_SUCCESS + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/M/remuw.yaml b/arch/inst/M/remuw.yaml index da10066c7..f1da0a607 100644 --- a/arch/inst/M/remuw.yaml +++ b/arch/inst/M/remuw.yaml @@ -46,3 +46,24 @@ remuw: X[rd] = {{32{sign_bit}}, result}; } + + + + sail(): | + { + if extension("M") then { + let rs1_val = X(rs1)[31..0]; + let rs2_val = X(rs2)[31..0]; + let rs1_int : int = if s then signed(rs1_val) else unsigned(rs1_val); + let rs2_int : int = if s then signed(rs2_val) else unsigned(rs2_val); + let r : int = if rs2_int == 0 then rs1_int else rem_round_zero(rs1_int, rs2_int); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + X(rd) = sign_extend(to_bits(32, r)); + RETIRE_SUCCESS + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/M/remw.yaml b/arch/inst/M/remw.yaml index 60dd83ea4..6aff5716f 100644 --- a/arch/inst/M/remw.yaml +++ b/arch/inst/M/remw.yaml @@ -50,4 +50,24 @@ remw: Bits<1> sign_bit = result[31]; X[rd] = {{32{sign_bit}}, result}; - } \ No newline at end of file + } + + + sail(): | + { + if extension("M") then { + let rs1_val = X(rs1)[31..0]; + let rs2_val = X(rs2)[31..0]; + let rs1_int : int = if s then signed(rs1_val) else unsigned(rs1_val); + let rs2_int : int = if s then signed(rs2_val) else unsigned(rs2_val); + let r : int = if rs2_int == 0 then rs1_int else rem_round_zero(rs1_int, rs2_int); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + X(rd) = sign_extend(to_bits(32, r)); + RETIRE_SUCCESS + } else { + handle_illegal(); + RETIRE_FAIL + } + } + + \ No newline at end of file diff --git a/arch/inst/S/sfence.vma.yaml b/arch/inst/S/sfence.vma.yaml index a3f1583c4..3e1c15995 100644 --- a/arch/inst/S/sfence.vma.yaml +++ b/arch/inst/S/sfence.vma.yaml @@ -302,3 +302,22 @@ sfence.vma: } # else, silently do nothing } + + + + sail(): | + { + let addr : option(xlenbits) = if rs1 == 0b00000 then None() else Some(X(rs1)); + let asid : option(xlenbits) = if rs2 == 0b00000 then None() else Some(X(rs2)); + match cur_privilege { + User => { handle_illegal(); RETIRE_FAIL }, + Supervisor => match (architecture(get_mstatus_SXL(mstatus)), mstatus.TVM()) { + (Some(_), 0b1) => { handle_illegal(); RETIRE_FAIL }, + (Some(_), 0b0) => { flush_TLB(asid, addr); RETIRE_SUCCESS }, + (_, _) => internal_error(__FILE__, __LINE__, "unimplemented sfence architecture") + }, + Machine => { flush_TLB(asid, addr); RETIRE_SUCCESS } + } + } + + \ No newline at end of file diff --git a/arch/inst/S/sret.yaml b/arch/inst/S/sret.yaml index 7c8dfde20..f4e4bf5aa 100644 --- a/arch/inst/S/sret.yaml +++ b/arch/inst/S/sret.yaml @@ -122,4 +122,24 @@ sret: CSR[vsstatus].SIE = CSR[vsstatus].SPIE; CSR[vsstatus].SPIE = 1; $pc = $bits(CSR[vsepc]); - } \ No newline at end of file + } + + + sail(): | + { + let sret_illegal : bool = match cur_privilege { + User => true, + Supervisor => not(haveSupMode ()) | mstatus.TSR() == 0b1, + Machine => not(haveSupMode ()) + }; + if sret_illegal + then { handle_illegal(); RETIRE_FAIL } + else if not(ext_check_xret_priv (Supervisor)) + then { ext_fail_xret_priv(); RETIRE_FAIL } + else { + set_next_pc(exception_handler(cur_privilege, CTL_SRET(), PC)); + RETIRE_SUCCESS + } + } + + \ No newline at end of file diff --git a/arch/inst/Zfh/fcvt.h.s.yaml b/arch/inst/Zfh/fcvt.h.s.yaml index a347f194c..91662f6e7 100644 --- a/arch/inst/Zfh/fcvt.h.s.yaml +++ b/arch/inst/Zfh/fcvt.h.s.yaml @@ -62,3 +62,24 @@ fcvt.h.s: } mark_f_state_dirty(); + + + + sail(): | + { + assert(sizeof(xlen) >= 64); + let rs1_val_LU = X(rs1)[63..0]; + match (select_instr_or_fcsr_rm (rm)) { + None() => { handle_illegal(); RETIRE_FAIL }, + Some(rm') => { + let rm_3b = encdec_rounding_mode(rm'); + let (fflags, rd_val_H) = riscv_ui64ToF16 (rm_3b, rs1_val_LU); + + accrue_fflags(fflags); + F_or_X_H(rd) = rd_val_H; + RETIRE_SUCCESS + } + } + } + + \ No newline at end of file diff --git a/arch/inst/Zfh/fcvt.s.h.yaml b/arch/inst/Zfh/fcvt.s.h.yaml index 471596c82..e71a4e5da 100644 --- a/arch/inst/Zfh/fcvt.s.h.yaml +++ b/arch/inst/Zfh/fcvt.s.h.yaml @@ -59,3 +59,24 @@ fcvt.s.h: } mark_f_state_dirty(); + + + + sail(): | + { + assert(sizeof(xlen) >= 64); + let rs1_val_LU = X(rs1)[63..0]; + match (select_instr_or_fcsr_rm (rm)) { + None() => { handle_illegal(); RETIRE_FAIL }, + Some(rm') => { + let rm_3b = encdec_rounding_mode(rm'); + let (fflags, rd_val_H) = riscv_ui64ToF16 (rm_3b, rs1_val_LU); + + accrue_fflags(fflags); + F_or_X_H(rd) = rd_val_H; + RETIRE_SUCCESS + } + } + } + + \ No newline at end of file diff --git a/arch/inst/Zfh/flh.yaml b/arch/inst/Zfh/flh.yaml index d8d1fd79b..0e94b04b8 100644 --- a/arch/inst/Zfh/flh.yaml +++ b/arch/inst/Zfh/flh.yaml @@ -36,3 +36,36 @@ flh: f[fd] = nan_box<16, FLEN>(hp_value); mark_f_state_dirty(); + + + + sail(): | + { + let offset : xlenbits = sign_extend(imm); + /* Get the address, X(rs1) + offset. + Some extensions perform additional checks on address validity. */ + match ext_data_get_addr(rs1, offset, Read(Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => + if check_misaligned(vaddr, width) + then { handle_mem_exception(vaddr, E_Load_Addr_Align()); RETIRE_FAIL } + else match translateAddr(vaddr, Read(Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => { + let (aq, rl, res) = (false, false, false); + match (width) { + BYTE => { handle_illegal(); RETIRE_FAIL }, + HALF => + process_fload16(rd, vaddr, mem_read(Read(Data), addr, 2, aq, rl, res)), + WORD => + process_fload32(rd, vaddr, mem_read(Read(Data), addr, 4, aq, rl, res)), + DOUBLE if sizeof(flen) >= 64 => + process_fload64(rd, vaddr, mem_read(Read(Data), addr, 8, aq, rl, res)), + _ => report_invalid_width(__FILE__, __LINE__, width, "floating point load"), + } + } + } + } + } + + \ No newline at end of file diff --git a/arch/inst/Zfh/fmv.h.x.yaml b/arch/inst/Zfh/fmv.h.x.yaml index 43b019538..4fa6c8763 100644 --- a/arch/inst/Zfh/fmv.h.x.yaml +++ b/arch/inst/Zfh/fmv.h.x.yaml @@ -28,4 +28,15 @@ fmv.h.x: f[fd] = nan_box<16, FLEN>(hp_value); - mark_f_state_dirty(); \ No newline at end of file + mark_f_state_dirty(); + + + sail(): | + { + let rs1_val_X = X(rs1); + let rd_val_H = rs1_val_X [15..0]; + F(rd) = nan_box (rd_val_H); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/Zfh/fmv.x.h.yaml b/arch/inst/Zfh/fmv.x.h.yaml index 77d0314b2..2c2c2f4a9 100644 --- a/arch/inst/Zfh/fmv.x.h.yaml +++ b/arch/inst/Zfh/fmv.x.h.yaml @@ -30,3 +30,15 @@ fmv.x.h: check_f_ok($encoding); X[rd] = sext(f[fs1][15:0], 16); + + + + sail(): | + { + let rs1_val_X = X(rs1); + let rd_val_H = rs1_val_X [15..0]; + F(rd) = nan_box (rd_val_H); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/Zfh/fsh.yaml b/arch/inst/Zfh/fsh.yaml index 1a9e974f2..42b6823ae 100644 --- a/arch/inst/Zfh/fsh.yaml +++ b/arch/inst/Zfh/fsh.yaml @@ -37,3 +37,46 @@ fsh: Bits<16> hp_value = f[fs2][15:0]; write_memory<16>(virtual_address, hp_value, $encoding); + + + + sail(): | + { + let offset : xlenbits = sign_extend(imm); + let (aq, rl, con) = (false, false, false); + /* Get the address, X(rs1) + offset. + Some extensions perform additional checks on address validity. */ + match ext_data_get_addr(rs1, offset, Write(Data), width) { + Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, + Ext_DataAddr_OK(vaddr) => + if check_misaligned(vaddr, width) + then { handle_mem_exception(vaddr, E_SAMO_Addr_Align()); RETIRE_FAIL } + else match translateAddr(vaddr, Write(Data)) { + TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + TR_Address(addr, _) => { + let eares : MemoryOpResult(unit) = match width { + BYTE => MemValue () /* bogus placeholder for illegal size */, + HALF => mem_write_ea(addr, 2, aq, rl, false), + WORD => mem_write_ea(addr, 4, aq, rl, false), + DOUBLE => mem_write_ea(addr, 8, aq, rl, false) + }; + match (eares) { + MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, + MemValue(_) => { + let rs2_val = F(rs2); + match (width) { + BYTE => { handle_illegal(); RETIRE_FAIL }, + HALF => process_fstore (vaddr, mem_write_value(addr, 2, rs2_val[15..0], aq, rl, con)), + WORD => process_fstore (vaddr, mem_write_value(addr, 4, rs2_val[31..0], aq, rl, con)), + DOUBLE if sizeof(flen) >= 64 => + process_fstore (vaddr, mem_write_value(addr, 8, rs2_val, aq, rl, con)), + _ => report_invalid_width(__FILE__, __LINE__, width, "floating point store"), + }; + } + } + } + } + } + } + + \ No newline at end of file diff --git a/arch/inst/Zicsr/csrrs.yaml b/arch/inst/Zicsr/csrrs.yaml index cac45c2c3..677ec279a 100644 --- a/arch/inst/Zicsr/csrrs.yaml +++ b/arch/inst/Zicsr/csrrs.yaml @@ -38,3 +38,33 @@ csrrs: CSR[csr].sw_write(initial_csr_value | mask); X[rd] = initial_csr_value; + + + + sail(): | + { + let rs1_val : xlenbits = if is_imm then zero_extend(rs1) else X(rs1); + let isWrite : bool = match op { + CSRRW => true, + _ => if is_imm then unsigned(rs1_val) != 0 else unsigned(rs1) != 0 + }; + if not(check_CSR(csr, cur_privilege, isWrite)) + then { handle_illegal(); RETIRE_FAIL } + else if not(ext_check_CSR(csr, cur_privilege, isWrite)) + then { ext_check_CSR_fail(); RETIRE_FAIL } + else { + let csr_val = readCSR(csr); /* could have side-effects, so technically shouldn't perform for CSRW[I] with rd == 0 */ + if isWrite then { + let new_val : xlenbits = match op { + CSRRW => rs1_val, + CSRRS => csr_val | rs1_val, + CSRRC => csr_val & ~(rs1_val) + }; + writeCSR(csr, new_val) + }; + X(rd) = csr_val; + RETIRE_SUCCESS + } + } + + \ No newline at end of file diff --git a/arch/inst/Zicsr/csrrw.yaml b/arch/inst/Zicsr/csrrw.yaml index 30e2efb29..891b136d7 100644 --- a/arch/inst/Zicsr/csrrw.yaml +++ b/arch/inst/Zicsr/csrrw.yaml @@ -34,3 +34,33 @@ csrrw: # writes the value in X[rs1] to the CSR, # performing any WARL transformations first CSR[csr].sw_write(X[rs1]); + + + + sail(): | + { + let rs1_val : xlenbits = if is_imm then zero_extend(rs1) else X(rs1); + let isWrite : bool = match op { + CSRRW => true, + _ => if is_imm then unsigned(rs1_val) != 0 else unsigned(rs1) != 0 + }; + if not(check_CSR(csr, cur_privilege, isWrite)) + then { handle_illegal(); RETIRE_FAIL } + else if not(ext_check_CSR(csr, cur_privilege, isWrite)) + then { ext_check_CSR_fail(); RETIRE_FAIL } + else { + let csr_val = readCSR(csr); /* could have side-effects, so technically shouldn't perform for CSRW[I] with rd == 0 */ + if isWrite then { + let new_val : xlenbits = match op { + CSRRW => rs1_val, + CSRRS => csr_val | rs1_val, + CSRRC => csr_val & ~(rs1_val) + }; + writeCSR(csr, new_val) + }; + X(rd) = csr_val; + RETIRE_SUCCESS + } + } + + \ No newline at end of file diff --git a/arch/inst/Zicsr/csrrwi.yaml b/arch/inst/Zicsr/csrrwi.yaml index f0b87c423..23d18155c 100644 --- a/arch/inst/Zicsr/csrrwi.yaml +++ b/arch/inst/Zicsr/csrrwi.yaml @@ -34,3 +34,33 @@ csrrwi: # writes the zero-extended immediate to the CSR, # performing any WARL transformations first CSR[csr].sw_write({{XLEN-5{1'b0}}, imm}); + + + + sail(): | + { + let rs1_val : xlenbits = if is_imm then zero_extend(rs1) else X(rs1); + let isWrite : bool = match op { + CSRRW => true, + _ => if is_imm then unsigned(rs1_val) != 0 else unsigned(rs1) != 0 + }; + if not(check_CSR(csr, cur_privilege, isWrite)) + then { handle_illegal(); RETIRE_FAIL } + else if not(ext_check_CSR(csr, cur_privilege, isWrite)) + then { ext_check_CSR_fail(); RETIRE_FAIL } + else { + let csr_val = readCSR(csr); /* could have side-effects, so technically shouldn't perform for CSRW[I] with rd == 0 */ + if isWrite then { + let new_val : xlenbits = match op { + CSRRW => rs1_val, + CSRRS => csr_val | rs1_val, + CSRRC => csr_val & ~(rs1_val) + }; + writeCSR(csr, new_val) + }; + X(rd) = csr_val; + RETIRE_SUCCESS + } + } + + \ No newline at end of file diff --git a/arch/inst/Zifencei/fence.i.yaml b/arch/inst/Zifencei/fence.i.yaml index 8277481ee..9d0e10037 100644 --- a/arch/inst/Zifencei/fence.i.yaml +++ b/arch/inst/Zifencei/fence.i.yaml @@ -41,3 +41,10 @@ fence.i: vu: always operation(): | ifence(); + + + + sail(): | + { /* __barrier(Barrier_RISCV_i); */ RETIRE_SUCCESS } + + \ No newline at end of file diff --git a/backends/manual/templates/instruction.adoc.erb b/backends/manual/templates/instruction.adoc.erb index 3e8d92715..5debd937a 100644 --- a/backends/manual/templates/instruction.adoc.erb +++ b/backends/manual/templates/instruction.adoc.erb @@ -121,13 +121,27 @@ RV64:: == Execution +[tabs] +==== <%- if inst.key?("operation()") -%> +IDL:: ++ [source,idl,subs="specialchars,macros"] ---- <%= inst.operation_ast(inst.arch_def.symtab).gen_adoc %> ---- <%- end -%> +<%- if inst.key?("sail()") -%> +Sail:: ++ +[source,sail] +---- +<%= inst["sail()"] %> +---- +<%- end -%> +==== + <% exception_list = inst.reachable_exceptions_str(inst.arch_def.symtab, 64) -%> <%- unless exception_list.empty? -%> == Exceptions @@ -138,4 +152,5 @@ This instruction may result in the following synchronous exceptions: * <%= etype %> <%- end -%> -<%- end -%> \ No newline at end of file +<%- end -%> + diff --git a/schemas/inst_schema.json b/schemas/inst_schema.json index ce7fa67ce..abcd4487c 100644 --- a/schemas/inst_schema.json +++ b/schemas/inst_schema.json @@ -177,7 +177,11 @@ }, "operation()": { "type": "string", - "description": "Functional description of the instruction using ISA language" + "description": "Functional description of the instruction using IDL language" + }, + "sail()": { + "type": "string", + "description": "Functional description of the instruction using Sail" }, "assembly": { "type": "string",