diff --git a/arch/inst/A/amoadd.d.yaml b/arch/inst/A/amoadd.d.yaml index 6f15b392f8..e3a32f25b5 100644 --- a/arch/inst/A/amoadd.d.yaml +++ b/arch/inst/A/amoadd.d.yaml @@ -135,4 +135,98 @@ amoadd.d: } } + + + + 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 bc3527a35f..9e77dfc985 100644 --- a/arch/inst/A/amoadd.w.yaml +++ b/arch/inst/A/amoadd.w.yaml @@ -134,4 +134,98 @@ amoadd.w: } } + + + + 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 b2a7b4414f..17612756ca 100644 --- a/arch/inst/A/amoand.d.yaml +++ b/arch/inst/A/amoand.d.yaml @@ -135,4 +135,98 @@ amoand.d: } } + + + + 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 98a656da9a..3f4dc1c126 100644 --- a/arch/inst/A/amoand.w.yaml +++ b/arch/inst/A/amoand.w.yaml @@ -134,4 +134,98 @@ amoand.w: } } + + + + 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 f5099364b1..5fa5e1a0e9 100644 --- a/arch/inst/A/amomax.d.yaml +++ b/arch/inst/A/amomax.d.yaml @@ -135,4 +135,98 @@ amomax.d: } } + + + + 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 ab505d5e91..1ef3fd3a0a 100644 --- a/arch/inst/A/amomax.w.yaml +++ b/arch/inst/A/amomax.w.yaml @@ -134,4 +134,98 @@ amomax.w: } } + + + + 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 038e2e25e6..a6b0a1c3a2 100644 --- a/arch/inst/A/amomaxu.d.yaml +++ b/arch/inst/A/amomaxu.d.yaml @@ -134,4 +134,98 @@ amomaxu.d: } } + + + + 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 ccd3628f91..3d8ff3f38b 100644 --- a/arch/inst/A/amomaxu.w.yaml +++ b/arch/inst/A/amomaxu.w.yaml @@ -134,4 +134,98 @@ amomaxu.w: } } + + + + 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 8c384ce9da..d526fb4237 100644 --- a/arch/inst/A/amomin.d.yaml +++ b/arch/inst/A/amomin.d.yaml @@ -135,4 +135,98 @@ amomin.d: } } + + + + 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 b41f4f6d3c..5cae94ff17 100644 --- a/arch/inst/A/amomin.w.yaml +++ b/arch/inst/A/amomin.w.yaml @@ -134,4 +134,98 @@ amomin.w: } } + + + + 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 ac9632879d..ae3ca62544 100644 --- a/arch/inst/A/amominu.d.yaml +++ b/arch/inst/A/amominu.d.yaml @@ -135,4 +135,98 @@ amominu.d: } } + + + + 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 79d01e6608..c30420551a 100644 --- a/arch/inst/A/amominu.w.yaml +++ b/arch/inst/A/amominu.w.yaml @@ -134,4 +134,98 @@ amominu.w: } } + + + + 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 392309d263..17f7393dd7 100644 --- a/arch/inst/A/amoor.d.yaml +++ b/arch/inst/A/amoor.d.yaml @@ -135,4 +135,98 @@ amoor.d: } } + + + + 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 7e33efcdbd..8da1177dbf 100644 --- a/arch/inst/A/amoor.w.yaml +++ b/arch/inst/A/amoor.w.yaml @@ -134,4 +134,98 @@ amoor.w: } } + + + + 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 da4ba161af..5f7fffb550 100644 --- a/arch/inst/A/amoswap.d.yaml +++ b/arch/inst/A/amoswap.d.yaml @@ -134,4 +134,98 @@ amoswap.d: } } + + + + 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 059ee723a3..34e25a927b 100644 --- a/arch/inst/A/amoswap.w.yaml +++ b/arch/inst/A/amoswap.w.yaml @@ -133,4 +133,98 @@ amoswap.w: } } + + + + 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 e83878605b..75f70cc1a1 100644 --- a/arch/inst/A/amoxor.d.yaml +++ b/arch/inst/A/amoxor.d.yaml @@ -135,4 +135,98 @@ amoxor.d: } } + + + + 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 eeedce2a5f..5f8f3d26b6 100644 --- a/arch/inst/A/amoxor.w.yaml +++ b/arch/inst/A/amoxor.w.yaml @@ -134,4 +134,98 @@ amoxor.w: } } + + + + 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 372344e622..f1a43c89ee 100644 --- a/arch/inst/A/lr.d.yaml +++ b/arch/inst/A/lr.d.yaml @@ -134,4 +134,50 @@ lr.d: } } + + + + 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 268c965967..8ec8453160 100644 --- a/arch/inst/A/lr.w.yaml +++ b/arch/inst/A/lr.w.yaml @@ -142,4 +142,50 @@ lr.w: } } + + + + 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 ed47ed9969..3c7d96e67e 100644 --- a/arch/inst/A/sc.d.yaml +++ b/arch/inst/A/sc.d.yaml @@ -226,4 +226,84 @@ sc.d: } } + + + + 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 783be010b6..dcabced5f9 100644 --- a/arch/inst/A/sc.w.yaml +++ b/arch/inst/A/sc.w.yaml @@ -232,4 +232,84 @@ sc.w: } } + + + + 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 f69a9642e8..dc8a91ab03 100644 --- a/arch/inst/B/add.uw.yaml +++ b/arch/inst/B/add.uw.yaml @@ -50,4 +50,22 @@ add.uw: RETIRE_SUCCESS } + + + + 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 c65690a031..029412ff27 100644 --- a/arch/inst/B/andn.yaml +++ b/arch/inst/B/andn.yaml @@ -55,4 +55,30 @@ andn: RETIRE_SUCCESS } + + + + 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 c670ca6720..96781ea2be 100644 --- a/arch/inst/B/bclr.yaml +++ b/arch/inst/B/bclr.yaml @@ -49,4 +49,24 @@ bclr: RETIRE_SUCCESS } + + + + 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 797519e715..adce4ab2f6 100644 --- a/arch/inst/B/bclri.yaml +++ b/arch/inst/B/bclri.yaml @@ -59,4 +59,23 @@ bclri: RETIRE_SUCCESS } + + + + 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 f0a8a94f68..2e4f42142f 100644 --- a/arch/inst/B/bext.yaml +++ b/arch/inst/B/bext.yaml @@ -49,4 +49,24 @@ bext: RETIRE_SUCCESS } + + + + 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 af5cad1acd..71e8d11223 100644 --- a/arch/inst/B/bexti.yaml +++ b/arch/inst/B/bexti.yaml @@ -59,4 +59,23 @@ bexti: RETIRE_SUCCESS } + + + + 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 922850af7d..94b24c7812 100644 --- a/arch/inst/B/binv.yaml +++ b/arch/inst/B/binv.yaml @@ -49,4 +49,24 @@ binv: RETIRE_SUCCESS } + + + + 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 e2ac22973c..cf9f6434b7 100644 --- a/arch/inst/B/binvi.yaml +++ b/arch/inst/B/binvi.yaml @@ -59,4 +59,23 @@ binvi: RETIRE_SUCCESS } + + + + 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 fd92e5056e..f2eb0d51ee 100644 --- a/arch/inst/B/bset.yaml +++ b/arch/inst/B/bset.yaml @@ -49,4 +49,24 @@ bset: RETIRE_SUCCESS } + + + + 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 c13cdd5860..039aed7a0f 100644 --- a/arch/inst/B/bseti.yaml +++ b/arch/inst/B/bseti.yaml @@ -59,4 +59,23 @@ bseti: RETIRE_SUCCESS } + + + + 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 28f7225486..6584dbf8a2 100644 --- a/arch/inst/B/clmul.yaml +++ b/arch/inst/B/clmul.yaml @@ -52,4 +52,18 @@ clmul: RETIRE_SUCCESS } + + + + 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 3685cd9a8a..25e6cd691d 100644 --- a/arch/inst/B/clmulh.yaml +++ b/arch/inst/B/clmulh.yaml @@ -52,4 +52,18 @@ clmulh: RETIRE_SUCCESS } + + + + 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 7cdcb7db9c..83f2f09b9b 100644 --- a/arch/inst/B/clmulr.yaml +++ b/arch/inst/B/clmulr.yaml @@ -51,4 +51,18 @@ clmulr: RETIRE_SUCCESS } + + + + 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 95a9c3e01e..0f439781db 100644 --- a/arch/inst/B/clz.yaml +++ b/arch/inst/B/clz.yaml @@ -44,4 +44,20 @@ clz: RETIRE_SUCCESS } + + + + 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 ab95cc2a01..ae5b07c91f 100644 --- a/arch/inst/B/clzw.yaml +++ b/arch/inst/B/clzw.yaml @@ -44,4 +44,20 @@ clzw: RETIRE_SUCCESS } + + + + 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 b3e92149b9..3511dc1bcc 100644 --- a/arch/inst/B/cpop.yaml +++ b/arch/inst/B/cpop.yaml @@ -59,4 +59,17 @@ cpop: RETIRE_SUCCESS } + + + + 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 a23cd07a4a..20a842dddd 100644 --- a/arch/inst/B/cpopw.yaml +++ b/arch/inst/B/cpopw.yaml @@ -60,4 +60,17 @@ cpopw: RETIRE_SUCCESS } + + + + 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 80ed80e432..5aafdda0af 100644 --- a/arch/inst/B/ctz.yaml +++ b/arch/inst/B/ctz.yaml @@ -45,4 +45,20 @@ ctz: RETIRE_SUCCESS } + + + + 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 8d035b58ea..d68b216b3c 100644 --- a/arch/inst/B/ctzw.yaml +++ b/arch/inst/B/ctzw.yaml @@ -46,4 +46,20 @@ ctzw: RETIRE_SUCCESS } + + + + 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 60ec56bf70..3aebd065c0 100644 --- a/arch/inst/B/max.yaml +++ b/arch/inst/B/max.yaml @@ -61,4 +61,30 @@ max: RETIRE_SUCCESS } + + + + 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 93a9298bc9..d8d3af4e5e 100644 --- a/arch/inst/B/maxu.yaml +++ b/arch/inst/B/maxu.yaml @@ -53,4 +53,30 @@ maxu: RETIRE_SUCCESS } + + + + 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 7bd38063a0..5885af9b4a 100644 --- a/arch/inst/B/min.yaml +++ b/arch/inst/B/min.yaml @@ -53,4 +53,30 @@ min: RETIRE_SUCCESS } + + + + 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 074f2c00cd..963080d6ab 100644 --- a/arch/inst/B/minu.yaml +++ b/arch/inst/B/minu.yaml @@ -53,4 +53,30 @@ minu: RETIRE_SUCCESS } + + + + 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 e33395d253..7d888a4b6d 100644 --- a/arch/inst/B/orc.b.yaml +++ b/arch/inst/B/orc.b.yaml @@ -49,4 +49,19 @@ orc.b: RETIRE_SUCCESS } + + + + 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 851c43e587..d9b1c03053 100644 --- a/arch/inst/B/orn.yaml +++ b/arch/inst/B/orn.yaml @@ -54,4 +54,30 @@ orn: RETIRE_SUCCESS } + + + + 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 020e8f6d4f..0d5b23d534 100644 --- a/arch/inst/B/rev8.yaml +++ b/arch/inst/B/rev8.yaml @@ -65,4 +65,17 @@ rev8: RETIRE_SUCCESS } + + + + 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 f0bd6323cc..e2148b7f2c 100644 --- a/arch/inst/B/rol.yaml +++ b/arch/inst/B/rol.yaml @@ -56,4 +56,30 @@ rol: RETIRE_SUCCESS } + + + + 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 9c163ef7ac..c9df59d632 100644 --- a/arch/inst/B/rolw.yaml +++ b/arch/inst/B/rolw.yaml @@ -50,4 +50,19 @@ rolw: RETIRE_SUCCESS } + + + + 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 226c461265..958d4e9b3b 100644 --- a/arch/inst/B/ror.yaml +++ b/arch/inst/B/ror.yaml @@ -56,4 +56,30 @@ ror: RETIRE_SUCCESS } + + + + 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 76e8e05691..51c0766677 100644 --- a/arch/inst/B/rori.yaml +++ b/arch/inst/B/rori.yaml @@ -54,4 +54,17 @@ rori: RETIRE_SUCCESS } + + + + 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 341df9ece7..c437420a5f 100644 --- a/arch/inst/B/roriw.yaml +++ b/arch/inst/B/roriw.yaml @@ -45,4 +45,15 @@ roriw: RETIRE_SUCCESS } + + + + 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 02e6949f06..7730dab58f 100644 --- a/arch/inst/B/rorw.yaml +++ b/arch/inst/B/rorw.yaml @@ -50,4 +50,19 @@ rorw: RETIRE_SUCCESS } + + + + 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 ec3281ae29..be6b9c5755 100644 --- a/arch/inst/B/sext.b.yaml +++ b/arch/inst/B/sext.b.yaml @@ -45,4 +45,19 @@ sext.b: RETIRE_SUCCESS } + + + + 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 825056864b..1b2f6fc49d 100644 --- a/arch/inst/B/sext.h.yaml +++ b/arch/inst/B/sext.h.yaml @@ -45,4 +45,19 @@ sext.h: RETIRE_SUCCESS } + + + + 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 483d6cebad..8436d1a90b 100644 --- a/arch/inst/B/sh1add.uw.yaml +++ b/arch/inst/B/sh1add.uw.yaml @@ -48,4 +48,22 @@ sh1add.uw: RETIRE_SUCCESS } + + + + 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 f489bc6f94..207de32ea2 100644 --- a/arch/inst/B/sh1add.yaml +++ b/arch/inst/B/sh1add.yaml @@ -44,4 +44,21 @@ sh1add: RETIRE_SUCCESS } + + + + 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 eb305926f5..0676b3f6d3 100644 --- a/arch/inst/B/sh2add.uw.yaml +++ b/arch/inst/B/sh2add.uw.yaml @@ -48,4 +48,22 @@ sh2add.uw: RETIRE_SUCCESS } + + + + 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 81247ffc12..beb8e8a5aa 100644 --- a/arch/inst/B/sh2add.yaml +++ b/arch/inst/B/sh2add.yaml @@ -44,4 +44,21 @@ sh2add: RETIRE_SUCCESS } + + + + 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 a0a69d41d8..8a2ca3f3ba 100644 --- a/arch/inst/B/sh3add.uw.yaml +++ b/arch/inst/B/sh3add.uw.yaml @@ -48,4 +48,22 @@ sh3add.uw: RETIRE_SUCCESS } + + + + 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 4e0236c8d7..57996faafb 100644 --- a/arch/inst/B/sh3add.yaml +++ b/arch/inst/B/sh3add.yaml @@ -44,4 +44,21 @@ sh3add: RETIRE_SUCCESS } + + + + 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 e2161473d8..c0109055da 100644 --- a/arch/inst/B/slli.uw.yaml +++ b/arch/inst/B/slli.uw.yaml @@ -43,4 +43,15 @@ slli.uw: RETIRE_SUCCESS } + + + + 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 470abf087c..d3bd0972bb 100644 --- a/arch/inst/B/xnor.yaml +++ b/arch/inst/B/xnor.yaml @@ -54,4 +54,30 @@ xnor: RETIRE_SUCCESS } + + + + 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 501d790adb..28ff37096a 100644 --- a/arch/inst/B/zext.h.yaml +++ b/arch/inst/B/zext.h.yaml @@ -56,4 +56,19 @@ zext.h: RETIRE_SUCCESS } + + + + 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 79b1867392..1a9a31f42c 100644 --- a/arch/inst/F/fadd.s.yaml +++ b/arch/inst/F/fadd.s.yaml @@ -28,6 +28,30 @@ fadd.s: + 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 + } + } + } + + + + sail(): | { let rs1_val_32b = F_or_X_S(rs1); diff --git a/arch/inst/F/fclass.s.yaml b/arch/inst/F/fclass.s.yaml index 467c35d6d8..c772e34369 100644 --- a/arch/inst/F/fclass.s.yaml +++ b/arch/inst/F/fclass.s.yaml @@ -82,4 +82,15 @@ fclass.s: RETIRE_SUCCESS } + + + + 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 f14bb8e550..2a8ec53142 100644 --- a/arch/inst/F/fcvt.l.s.yaml +++ b/arch/inst/F/fcvt.l.s.yaml @@ -27,6 +27,26 @@ fcvt.l.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 + } + } + } + + + + sail(): | { assert(sizeof(xlen) >= 64); diff --git a/arch/inst/F/fcvt.lu.s.yaml b/arch/inst/F/fcvt.lu.s.yaml index 155594ac87..5c0c60665e 100644 --- a/arch/inst/F/fcvt.lu.s.yaml +++ b/arch/inst/F/fcvt.lu.s.yaml @@ -27,6 +27,26 @@ fcvt.lu.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 + } + } + } + + + + sail(): | { assert(sizeof(xlen) >= 64); diff --git a/arch/inst/F/fcvt.s.l.yaml b/arch/inst/F/fcvt.s.l.yaml index 14e43e1020..9a41e41cee 100644 --- a/arch/inst/F/fcvt.s.l.yaml +++ b/arch/inst/F/fcvt.s.l.yaml @@ -27,6 +27,26 @@ fcvt.s.l: + 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 + } + } + } + + + + sail(): | { assert(sizeof(xlen) >= 64); diff --git a/arch/inst/F/fcvt.s.lu.yaml b/arch/inst/F/fcvt.s.lu.yaml index 74b54bd586..9e1bd3c696 100644 --- a/arch/inst/F/fcvt.s.lu.yaml +++ b/arch/inst/F/fcvt.s.lu.yaml @@ -27,6 +27,26 @@ fcvt.s.lu: + 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 + } + } + } + + + + sail(): | { assert(sizeof(xlen) >= 64); diff --git a/arch/inst/F/fcvt.s.w.yaml b/arch/inst/F/fcvt.s.w.yaml index ea7186884d..4dbb1291e0 100644 --- a/arch/inst/F/fcvt.s.w.yaml +++ b/arch/inst/F/fcvt.s.w.yaml @@ -51,6 +51,26 @@ fcvt.s.w: + 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 + } + } + } + + + + sail(): | { assert(sizeof(xlen) >= 64); diff --git a/arch/inst/F/fcvt.s.wu.yaml b/arch/inst/F/fcvt.s.wu.yaml index ad7999c4c3..4d5b8c8f88 100644 --- a/arch/inst/F/fcvt.s.wu.yaml +++ b/arch/inst/F/fcvt.s.wu.yaml @@ -26,6 +26,26 @@ fcvt.s.wu: + 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 + } + } + } + + + + sail(): | { assert(sizeof(xlen) >= 64); diff --git a/arch/inst/F/fcvt.w.s.yaml b/arch/inst/F/fcvt.w.s.yaml index 6df307f7f2..62f28c3af7 100644 --- a/arch/inst/F/fcvt.w.s.yaml +++ b/arch/inst/F/fcvt.w.s.yaml @@ -81,6 +81,26 @@ 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 + } + } + } + + + + sail(): | { assert(sizeof(xlen) >= 64); diff --git a/arch/inst/F/fcvt.wu.s.yaml b/arch/inst/F/fcvt.wu.s.yaml index b050c1a6d5..30cdc68716 100644 --- a/arch/inst/F/fcvt.wu.s.yaml +++ b/arch/inst/F/fcvt.wu.s.yaml @@ -26,6 +26,26 @@ fcvt.wu.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 + } + } + } + + + + sail(): | { assert(sizeof(xlen) >= 64); diff --git a/arch/inst/F/fdiv.s.yaml b/arch/inst/F/fdiv.s.yaml index af35a4eabb..ba9d7e8d37 100644 --- a/arch/inst/F/fdiv.s.yaml +++ b/arch/inst/F/fdiv.s.yaml @@ -28,6 +28,30 @@ fdiv.s: + 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 + } + } + } + + + + sail(): | { let rs1_val_32b = F_or_X_S(rs1); diff --git a/arch/inst/F/feq.s.yaml b/arch/inst/F/feq.s.yaml index ba0ea8b779..9030a6d16f 100644 --- a/arch/inst/F/feq.s.yaml +++ b/arch/inst/F/feq.s.yaml @@ -59,4 +59,20 @@ feq.s: RETIRE_SUCCESS } + + + + 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 7a94aac007..29a8b87f17 100644 --- a/arch/inst/F/fle.s.yaml +++ b/arch/inst/F/fle.s.yaml @@ -60,4 +60,20 @@ fle.s: RETIRE_SUCCESS } + + + + 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 07d5c68278..d88723a673 100644 --- a/arch/inst/F/fleq.s.yaml +++ b/arch/inst/F/fleq.s.yaml @@ -26,6 +26,22 @@ fleq.s: + 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 + } + + + + sail(): | { let rs1_val_S = F_S(rs1); diff --git a/arch/inst/F/fli.s.yaml b/arch/inst/F/fli.s.yaml index 712dee35f4..104ff6461f 100644 --- a/arch/inst/F/fli.s.yaml +++ b/arch/inst/F/fli.s.yaml @@ -24,6 +24,49 @@ fli.s: + 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 + } + + + + sail(): | { let bits : bits(32) = match constantidx { diff --git a/arch/inst/F/flt.s.yaml b/arch/inst/F/flt.s.yaml index 812f29e2c5..664bf15bdd 100644 --- a/arch/inst/F/flt.s.yaml +++ b/arch/inst/F/flt.s.yaml @@ -49,6 +49,22 @@ 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 + } + + + + sail(): | { let rs1_val_S = F_or_X_S(rs1); diff --git a/arch/inst/F/fltq.s.yaml b/arch/inst/F/fltq.s.yaml index 46de307845..06b7d3643b 100644 --- a/arch/inst/F/fltq.s.yaml +++ b/arch/inst/F/fltq.s.yaml @@ -26,6 +26,22 @@ fltq.s: + 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 + } + + + + sail(): | { let rs1_val_S = F_S(rs1); diff --git a/arch/inst/F/flw.yaml b/arch/inst/F/flw.yaml index b688709586..acdb98e873 100644 --- a/arch/inst/F/flw.yaml +++ b/arch/inst/F/flw.yaml @@ -69,4 +69,36 @@ flw: } } + + + + 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 f720cebe8a..e4e1bbceea 100644 --- a/arch/inst/F/fmadd.s.yaml +++ b/arch/inst/F/fmadd.s.yaml @@ -30,6 +30,32 @@ fmadd.s: + 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 + } + } + } + + + + sail(): | { let rs1_val_32b = F_or_X_S(rs1); diff --git a/arch/inst/F/fmax.s.yaml b/arch/inst/F/fmax.s.yaml index 02c25e264d..1847dbb3ff 100644 --- a/arch/inst/F/fmax.s.yaml +++ b/arch/inst/F/fmax.s.yaml @@ -26,6 +26,22 @@ fmax.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 + } + + + + sail(): | { let rs1_val_S = F_or_X_S(rs1); diff --git a/arch/inst/F/fmaxm.s.yaml b/arch/inst/F/fmaxm.s.yaml index ad9e1a61a3..dde8135017 100644 --- a/arch/inst/F/fmaxm.s.yaml +++ b/arch/inst/F/fmaxm.s.yaml @@ -26,6 +26,28 @@ fmaxm.s: + 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 + } + + + + sail(): | { let rs1_val_S = F_S(rs1); diff --git a/arch/inst/F/fmin.s.yaml b/arch/inst/F/fmin.s.yaml index 1670434a08..99d46d86bf 100644 --- a/arch/inst/F/fmin.s.yaml +++ b/arch/inst/F/fmin.s.yaml @@ -26,6 +26,22 @@ fmin.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 + } + + + + sail(): | { let rs1_val_S = F_or_X_S(rs1); diff --git a/arch/inst/F/fminm.s.yaml b/arch/inst/F/fminm.s.yaml index 62fff22d14..ff19aeb713 100644 --- a/arch/inst/F/fminm.s.yaml +++ b/arch/inst/F/fminm.s.yaml @@ -26,6 +26,28 @@ fminm.s: + 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 + } + + + + sail(): | { let rs1_val_S = F_S(rs1); diff --git a/arch/inst/F/fmsub.s.yaml b/arch/inst/F/fmsub.s.yaml index f49703d625..90be8eb14d 100644 --- a/arch/inst/F/fmsub.s.yaml +++ b/arch/inst/F/fmsub.s.yaml @@ -30,6 +30,32 @@ fmsub.s: + 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 + } + } + } + + + + sail(): | { let rs1_val_32b = F_or_X_S(rs1); diff --git a/arch/inst/F/fmul.s.yaml b/arch/inst/F/fmul.s.yaml index 0fdddd9b30..567f6fa968 100644 --- a/arch/inst/F/fmul.s.yaml +++ b/arch/inst/F/fmul.s.yaml @@ -28,6 +28,30 @@ fmul.s: + 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 + } + } + } + + + + sail(): | { let rs1_val_32b = F_or_X_S(rs1); diff --git a/arch/inst/F/fmv.w.x.yaml b/arch/inst/F/fmv.w.x.yaml index e783244d8b..f8d0e78743 100644 --- a/arch/inst/F/fmv.w.x.yaml +++ b/arch/inst/F/fmv.w.x.yaml @@ -45,4 +45,15 @@ fmv.w.x: RETIRE_SUCCESS } + + + + 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 71a3af0d82..8391eae542 100644 --- a/arch/inst/F/fmv.x.w.yaml +++ b/arch/inst/F/fmv.x.w.yaml @@ -39,4 +39,15 @@ fmv.x.w: RETIRE_SUCCESS } + + + + 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 b4d329a7f5..d7931bdb63 100644 --- a/arch/inst/F/fnmadd.s.yaml +++ b/arch/inst/F/fnmadd.s.yaml @@ -30,6 +30,32 @@ fnmadd.s: + 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 + } + } + } + + + + sail(): | { let rs1_val_32b = F_or_X_S(rs1); diff --git a/arch/inst/F/fnmsub.s.yaml b/arch/inst/F/fnmsub.s.yaml index 83ad862f09..4e4677a8cc 100644 --- a/arch/inst/F/fnmsub.s.yaml +++ b/arch/inst/F/fnmsub.s.yaml @@ -30,6 +30,32 @@ fnmsub.s: + 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 + } + } + } + + + + sail(): | { let rs1_val_32b = F_or_X_S(rs1); diff --git a/arch/inst/F/fround.s.yaml b/arch/inst/F/fround.s.yaml index bb31e8f45c..2e09814588 100644 --- a/arch/inst/F/fround.s.yaml +++ b/arch/inst/F/fround.s.yaml @@ -26,6 +26,26 @@ fround.s: + 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 + } + } + } + + + + sail(): | { let rs1_val_S = F_S(rs1); diff --git a/arch/inst/F/froundnx.s.yaml b/arch/inst/F/froundnx.s.yaml index 2970eb0032..9da0a63b90 100644 --- a/arch/inst/F/froundnx.s.yaml +++ b/arch/inst/F/froundnx.s.yaml @@ -26,6 +26,26 @@ froundnx.s: + 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 + } + } + } + + + + sail(): | { let rs1_val_S = F_S(rs1); diff --git a/arch/inst/F/fsgnj.s.yaml b/arch/inst/F/fsgnj.s.yaml index db5cb07635..385b47bebc 100644 --- a/arch/inst/F/fsgnj.s.yaml +++ b/arch/inst/F/fsgnj.s.yaml @@ -56,4 +56,20 @@ fsgnj.s: RETIRE_SUCCESS } + + + + 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 d387948b44..92843466d7 100644 --- a/arch/inst/F/fsgnjn.s.yaml +++ b/arch/inst/F/fsgnjn.s.yaml @@ -55,4 +55,20 @@ fsgnjn.s: RETIRE_SUCCESS } + + + + 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 5c7a51f46b..59b7aa779d 100644 --- a/arch/inst/F/fsgnjx.s.yaml +++ b/arch/inst/F/fsgnjx.s.yaml @@ -54,4 +54,20 @@ fsgnjx.s: RETIRE_SUCCESS } + + + + 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 959175cec1..5fd0e4da32 100644 --- a/arch/inst/F/fsqrt.s.yaml +++ b/arch/inst/F/fsqrt.s.yaml @@ -26,6 +26,26 @@ fsqrt.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 + } + } + } + + + + sail(): | { assert(sizeof(xlen) >= 64); diff --git a/arch/inst/F/fsub.s.yaml b/arch/inst/F/fsub.s.yaml index b3dba5bb6d..36ddcde5a9 100644 --- a/arch/inst/F/fsub.s.yaml +++ b/arch/inst/F/fsub.s.yaml @@ -28,6 +28,30 @@ fsub.s: + 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 + } + } + } + + + + sail(): | { let rs1_val_32b = F_or_X_S(rs1); diff --git a/arch/inst/F/fsw.yaml b/arch/inst/F/fsw.yaml index 1edd09aeb4..b2b2d514a6 100644 --- a/arch/inst/F/fsw.yaml +++ b/arch/inst/F/fsw.yaml @@ -72,4 +72,46 @@ fsw: } } + + + + 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 1a2c84ba0e..923a1a0264 100644 --- a/arch/inst/I/add.yaml +++ b/arch/inst/I/add.yaml @@ -52,4 +52,33 @@ add: RETIRE_SUCCESS } + + + + 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 4c60b8dbcf..57288e9f15 100644 --- a/arch/inst/I/addi.yaml +++ b/arch/inst/I/addi.yaml @@ -40,4 +40,23 @@ addi: RETIRE_SUCCESS } + + + + 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 c59921d00a..59262bdc22 100644 --- a/arch/inst/I/addiw.yaml +++ b/arch/inst/I/addiw.yaml @@ -34,4 +34,14 @@ addiw: RETIRE_SUCCESS } + + + + 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 5b6d0012df..4f3dc835e7 100644 --- a/arch/inst/I/addw.yaml +++ b/arch/inst/I/addw.yaml @@ -45,4 +45,22 @@ addw: RETIRE_SUCCESS } + + + + 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 7507597abf..34215edbc7 100644 --- a/arch/inst/I/and.yaml +++ b/arch/inst/I/and.yaml @@ -50,4 +50,33 @@ and: RETIRE_SUCCESS } + + + + 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 a4115c957d..9661085688 100644 --- a/arch/inst/I/andi.yaml +++ b/arch/inst/I/andi.yaml @@ -40,4 +40,23 @@ andi: RETIRE_SUCCESS } + + + + 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 6fccca45b3..b5d4576049 100644 --- a/arch/inst/I/auipc.yaml +++ b/arch/inst/I/auipc.yaml @@ -34,4 +34,18 @@ auipc: RETIRE_SUCCESS } + + + + 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 da03ec17d4..510b8e5bdd 100644 --- a/arch/inst/I/beq.yaml +++ b/arch/inst/I/beq.yaml @@ -66,4 +66,40 @@ beq: } else RETIRE_SUCCESS } + + + + 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 7244ea39d8..473fba3985 100644 --- a/arch/inst/I/bge.yaml +++ b/arch/inst/I/bge.yaml @@ -67,4 +67,40 @@ bge: } else RETIRE_SUCCESS } + + + + 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 47607d0f25..d8e6b87946 100644 --- a/arch/inst/I/bgeu.yaml +++ b/arch/inst/I/bgeu.yaml @@ -67,4 +67,40 @@ bgeu: } else RETIRE_SUCCESS } + + + + 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 e598bddcea..5f9231a3ed 100644 --- a/arch/inst/I/blt.yaml +++ b/arch/inst/I/blt.yaml @@ -67,4 +67,40 @@ blt: } else RETIRE_SUCCESS } + + + + 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 ce3a616920..72fde3ef00 100644 --- a/arch/inst/I/bltu.yaml +++ b/arch/inst/I/bltu.yaml @@ -67,4 +67,40 @@ bltu: } else RETIRE_SUCCESS } + + + + 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 73c71211d4..44a2bd40db 100644 --- a/arch/inst/I/bne.yaml +++ b/arch/inst/I/bne.yaml @@ -67,4 +67,40 @@ bne: } else RETIRE_SUCCESS } + + + + 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 5e7424b6fe..33e0be2e6c 100644 --- a/arch/inst/I/ebreak.yaml +++ b/arch/inst/I/ebreak.yaml @@ -39,4 +39,13 @@ ebreak: RETIRE_FAIL } + + + + 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 36c4848614..647e6004e6 100644 --- a/arch/inst/I/ecall.yaml +++ b/arch/inst/I/ecall.yaml @@ -70,4 +70,21 @@ ecall: RETIRE_FAIL } + + + + 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 40cc6bc7d6..a070409f71 100644 --- a/arch/inst/I/fence.yaml +++ b/arch/inst/I/fence.yaml @@ -235,4 +235,34 @@ fence: RETIRE_SUCCESS } + + + + 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 45922de5b1..67c786635c 100644 --- a/arch/inst/I/jal.yaml +++ b/arch/inst/I/jal.yaml @@ -53,4 +53,31 @@ jal: } } + + + + 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 5b82ee320c..c158b47389 100644 --- a/arch/inst/I/jalr.yaml +++ b/arch/inst/I/jalr.yaml @@ -59,4 +59,36 @@ jalr: } } + + + + 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 1929ca61c5..7c6fdbebfb 100644 --- a/arch/inst/I/lb.yaml +++ b/arch/inst/I/lb.yaml @@ -57,4 +57,35 @@ lb: } } + + + + 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 f427a51216..97ea975fff 100644 --- a/arch/inst/I/lbu.yaml +++ b/arch/inst/I/lbu.yaml @@ -57,4 +57,35 @@ lbu: } } + + + + 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 e5715ca5d7..da4e60602f 100644 --- a/arch/inst/I/ld.yaml +++ b/arch/inst/I/ld.yaml @@ -57,4 +57,35 @@ ld: } } + + + + 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 e4170512b7..dc11630e75 100644 --- a/arch/inst/I/lh.yaml +++ b/arch/inst/I/lh.yaml @@ -57,4 +57,35 @@ lh: } } + + + + 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 373d8e3580..c67a2a5ce0 100644 --- a/arch/inst/I/lhu.yaml +++ b/arch/inst/I/lhu.yaml @@ -57,4 +57,35 @@ lhu: } } + + + + 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 9c5894936b..c21bd90385 100644 --- a/arch/inst/I/lui.yaml +++ b/arch/inst/I/lui.yaml @@ -34,4 +34,18 @@ lui: RETIRE_SUCCESS } + + + + 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 c5f698acca..294a234dbd 100644 --- a/arch/inst/I/lw.yaml +++ b/arch/inst/I/lw.yaml @@ -57,4 +57,35 @@ lw: } } + + + + 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 f636c508b2..14e622f1e7 100644 --- a/arch/inst/I/lwu.yaml +++ b/arch/inst/I/lwu.yaml @@ -58,4 +58,35 @@ lwu: } } + + + + 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 421d5f1487..9f2244f125 100644 --- a/arch/inst/I/mret.yaml +++ b/arch/inst/I/mret.yaml @@ -41,4 +41,19 @@ mret: } } + + + + 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 81694ccea2..445c3de3d3 100644 --- a/arch/inst/I/or.yaml +++ b/arch/inst/I/or.yaml @@ -50,4 +50,33 @@ or: RETIRE_SUCCESS } + + + + 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 3c53d1c6f4..47460748ce 100644 --- a/arch/inst/I/ori.yaml +++ b/arch/inst/I/ori.yaml @@ -65,4 +65,23 @@ ori: RETIRE_SUCCESS } + + + + 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 55fe9e8e00..7afd14682a 100644 --- a/arch/inst/I/sb.yaml +++ b/arch/inst/I/sb.yaml @@ -71,4 +71,50 @@ sb: } } + + + + 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 192bfa1caa..24a7af2bc6 100644 --- a/arch/inst/I/sd.yaml +++ b/arch/inst/I/sd.yaml @@ -73,4 +73,50 @@ sd: } } + + + + 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 59b6537449..c6dde3fa94 100644 --- a/arch/inst/I/sh.yaml +++ b/arch/inst/I/sh.yaml @@ -71,4 +71,50 @@ sh: } } + + + + 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 3ba787e048..c9845a2658 100644 --- a/arch/inst/I/sll.yaml +++ b/arch/inst/I/sll.yaml @@ -56,4 +56,33 @@ sll: RETIRE_SUCCESS } + + + + 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 caa9b5ba7d..edb37ecc40 100644 --- a/arch/inst/I/slli.yaml +++ b/arch/inst/I/slli.yaml @@ -55,4 +55,26 @@ slli: RETIRE_SUCCESS } + + + + 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 0dd58e94b9..e31d4805f6 100644 --- a/arch/inst/I/slliw.yaml +++ b/arch/inst/I/slliw.yaml @@ -39,4 +39,19 @@ slliw: RETIRE_SUCCESS } + + + + 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 8853862bf3..b5300b2a7f 100644 --- a/arch/inst/I/sllw.yaml +++ b/arch/inst/I/sllw.yaml @@ -41,4 +41,22 @@ sllw: RETIRE_SUCCESS } + + + + 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 4ebe38012b..e09368f4d2 100644 --- a/arch/inst/I/slt.yaml +++ b/arch/inst/I/slt.yaml @@ -56,4 +56,33 @@ slt: RETIRE_SUCCESS } + + + + 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 6c932b89b5..69d6b2c3b5 100644 --- a/arch/inst/I/slti.yaml +++ b/arch/inst/I/slti.yaml @@ -43,4 +43,23 @@ slti: RETIRE_SUCCESS } + + + + 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 59e109de84..3ad4165c53 100644 --- a/arch/inst/I/sltiu.yaml +++ b/arch/inst/I/sltiu.yaml @@ -47,4 +47,23 @@ sltiu: RETIRE_SUCCESS } + + + + 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 2c1d5db987..ea3e4294d6 100644 --- a/arch/inst/I/sltu.yaml +++ b/arch/inst/I/sltu.yaml @@ -53,4 +53,33 @@ sltu: RETIRE_SUCCESS } + + + + 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 09aeb8d263..40b942abad 100644 --- a/arch/inst/I/sra.yaml +++ b/arch/inst/I/sra.yaml @@ -56,4 +56,33 @@ sra: RETIRE_SUCCESS } + + + + 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 98211da0ef..326c5fb54c 100644 --- a/arch/inst/I/srai.yaml +++ b/arch/inst/I/srai.yaml @@ -57,4 +57,26 @@ srai: RETIRE_SUCCESS } + + + + 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 ba8115ce7b..f57627ec4c 100644 --- a/arch/inst/I/sraiw.yaml +++ b/arch/inst/I/sraiw.yaml @@ -42,4 +42,19 @@ sraiw: RETIRE_SUCCESS } + + + + 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 5c49924c01..37be00d6ab 100644 --- a/arch/inst/I/sraw.yaml +++ b/arch/inst/I/sraw.yaml @@ -44,4 +44,22 @@ sraw: RETIRE_SUCCESS } + + + + 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 61f7135f42..ce2ba434dc 100644 --- a/arch/inst/I/srl.yaml +++ b/arch/inst/I/srl.yaml @@ -56,4 +56,33 @@ srl: RETIRE_SUCCESS } + + + + 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 b0125f5ad2..286580a84d 100644 --- a/arch/inst/I/srli.yaml +++ b/arch/inst/I/srli.yaml @@ -54,4 +54,26 @@ srli: RETIRE_SUCCESS } + + + + 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 b8e480c7c3..4dacfb1a5a 100644 --- a/arch/inst/I/srliw.yaml +++ b/arch/inst/I/srliw.yaml @@ -41,4 +41,19 @@ srliw: RETIRE_SUCCESS } + + + + 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 b47f5440e8..43967f0ebd 100644 --- a/arch/inst/I/srlw.yaml +++ b/arch/inst/I/srlw.yaml @@ -41,4 +41,22 @@ srlw: RETIRE_SUCCESS } + + + + 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 8a1190ee5b..0677ab2296 100644 --- a/arch/inst/I/sub.yaml +++ b/arch/inst/I/sub.yaml @@ -53,4 +53,33 @@ sub: RETIRE_SUCCESS } + + + + 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 3e7e17a1ad..192eae6829 100644 --- a/arch/inst/I/subw.yaml +++ b/arch/inst/I/subw.yaml @@ -43,4 +43,22 @@ subw: RETIRE_SUCCESS } + + + + 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 c1e22cd027..f6cc7e6a7b 100644 --- a/arch/inst/I/sw.yaml +++ b/arch/inst/I/sw.yaml @@ -71,4 +71,50 @@ sw: } } + + + + 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 23b350e941..a19e368f5d 100644 --- a/arch/inst/I/wfi.yaml +++ b/arch/inst/I/wfi.yaml @@ -120,4 +120,16 @@ wfi: User => { handle_illegal(); RETIRE_FAIL } } + + + + 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 a13b09b884..6fc52bcf00 100644 --- a/arch/inst/I/xor.yaml +++ b/arch/inst/I/xor.yaml @@ -50,4 +50,33 @@ xor: RETIRE_SUCCESS } + + + + 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 400f35500d..768158fbde 100644 --- a/arch/inst/I/xori.yaml +++ b/arch/inst/I/xori.yaml @@ -40,4 +40,23 @@ xori: RETIRE_SUCCESS } + + + + 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 50c51e3591..4e28d2c6a6 100644 --- a/arch/inst/M/div.yaml +++ b/arch/inst/M/div.yaml @@ -67,4 +67,25 @@ div: } } + + + + 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 5c2a4b3a9f..7fe7b798b8 100644 --- a/arch/inst/M/divu.yaml +++ b/arch/inst/M/divu.yaml @@ -59,4 +59,25 @@ divu: } } + + + + 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 ffb32ff19c..7925737a3c 100644 --- a/arch/inst/M/divuw.yaml +++ b/arch/inst/M/divuw.yaml @@ -65,4 +65,25 @@ divuw: } } + + + + 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 39b0dad17a..66e3a01451 100644 --- a/arch/inst/M/divw.yaml +++ b/arch/inst/M/divw.yaml @@ -74,4 +74,25 @@ divw: } } + + + + 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 e383b5ac88..30be656313 100644 --- a/arch/inst/M/mul.yaml +++ b/arch/inst/M/mul.yaml @@ -63,4 +63,26 @@ mul: } } + + + + 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 27e10ee35c..cd557a4f81 100644 --- a/arch/inst/M/mulh.yaml +++ b/arch/inst/M/mulh.yaml @@ -68,4 +68,26 @@ mulh: } } + + + + 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 98fc2d34ac..1eab01c0d0 100644 --- a/arch/inst/M/mulhsu.yaml +++ b/arch/inst/M/mulhsu.yaml @@ -64,4 +64,26 @@ mulhsu: } } + + + + 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 4e37ff076e..0e156c83a5 100644 --- a/arch/inst/M/mulhu.yaml +++ b/arch/inst/M/mulhu.yaml @@ -63,4 +63,26 @@ mulhu: } } + + + + 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 6385fa3a67..83cc94cf0e 100644 --- a/arch/inst/M/mulw.yaml +++ b/arch/inst/M/mulw.yaml @@ -65,4 +65,25 @@ mulw: } } + + + + 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 d49e5f23f8..7a07f03d38 100644 --- a/arch/inst/M/rem.yaml +++ b/arch/inst/M/rem.yaml @@ -64,4 +64,24 @@ rem: } } + + + + 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 a95b4f3a8d..f7370f08a9 100644 --- a/arch/inst/M/remu.yaml +++ b/arch/inst/M/remu.yaml @@ -54,4 +54,24 @@ remu: } } + + + + 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 f1da0a607c..81bcf227f8 100644 --- a/arch/inst/M/remuw.yaml +++ b/arch/inst/M/remuw.yaml @@ -66,4 +66,24 @@ remuw: } } + + + + 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 6aff5716f3..bcd757dba6 100644 --- a/arch/inst/M/remw.yaml +++ b/arch/inst/M/remw.yaml @@ -70,4 +70,24 @@ remw: } } + + + + 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 3e1c159955..35cbe3c80b 100644 --- a/arch/inst/S/sfence.vma.yaml +++ b/arch/inst/S/sfence.vma.yaml @@ -320,4 +320,22 @@ sfence.vma: } } + + + + 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 f4e4bf5aaf..27f2b003b6 100644 --- a/arch/inst/S/sret.yaml +++ b/arch/inst/S/sret.yaml @@ -142,4 +142,24 @@ sret: } } + + + + 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/V/vaadd.vv.yaml b/arch/inst/V/vaadd.vv.yaml index ee4b1b9470..b7533143d7 100644 --- a/arch/inst/V/vaadd.vv.yaml +++ b/arch/inst/V/vaadd.vv.yaml @@ -25,3 +25,85 @@ vaadd.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVV_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), 0), + MVV_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), SEW), + MVV_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(vs1_val[i]), SEW), + MVV_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(vs1_val[i]), SEW), + MVV_VDIVU => { + let q : int = if unsigned(vs1_val[i]) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i])); + to_bits(SEW, q) + }, + MVV_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(vs1_val[i]) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(vs1_val[i])); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVV_VREMU => { + let r : int = if unsigned(vs1_val[i]) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i])); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVV_VREM => { + let r : int = if signed(vs1_val[i]) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(vs1_val[i])); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vaadd.vx.yaml b/arch/inst/V/vaadd.vx.yaml index 577651b52f..c62c2da70e 100644 --- a/arch/inst/V/vaadd.vx.yaml +++ b/arch/inst/V/vaadd.vx.yaml @@ -25,3 +25,94 @@ vaadd.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVX_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VSLIDE1UP => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + MVX_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + }, + MVX_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), 0), + MVX_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), SEW), + MVX_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VDIVU => { + let q : int = if unsigned(rs1_val) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(rs1_val)); + to_bits(SEW, q) + }, + MVX_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(rs1_val) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVX_VREMU => { + let r : int = if unsigned(rs1_val) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned (rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVX_VREM => { + let r : int = if signed(rs1_val) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vaaddu.vv.yaml b/arch/inst/V/vaaddu.vv.yaml index b5358fa7af..70d747182b 100644 --- a/arch/inst/V/vaaddu.vv.yaml +++ b/arch/inst/V/vaaddu.vv.yaml @@ -25,3 +25,85 @@ vaaddu.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVV_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), 0), + MVV_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), SEW), + MVV_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(vs1_val[i]), SEW), + MVV_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(vs1_val[i]), SEW), + MVV_VDIVU => { + let q : int = if unsigned(vs1_val[i]) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i])); + to_bits(SEW, q) + }, + MVV_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(vs1_val[i]) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(vs1_val[i])); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVV_VREMU => { + let r : int = if unsigned(vs1_val[i]) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i])); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVV_VREM => { + let r : int = if signed(vs1_val[i]) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(vs1_val[i])); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vaaddu.vx.yaml b/arch/inst/V/vaaddu.vx.yaml index 5914f064bc..60b3433352 100644 --- a/arch/inst/V/vaaddu.vx.yaml +++ b/arch/inst/V/vaaddu.vx.yaml @@ -25,3 +25,94 @@ vaaddu.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVX_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VSLIDE1UP => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + MVX_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + }, + MVX_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), 0), + MVX_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), SEW), + MVX_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VDIVU => { + let q : int = if unsigned(rs1_val) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(rs1_val)); + to_bits(SEW, q) + }, + MVX_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(rs1_val) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVX_VREMU => { + let r : int = if unsigned(rs1_val) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned (rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVX_VREM => { + let r : int = if signed(rs1_val) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vadc.vim.yaml b/arch/inst/V/vadc.vim.yaml index ccf27eb7f8..a1b3464d12 100644 --- a/arch/inst/V/vadc.vim.yaml +++ b/arch/inst/V/vadc.vim.yaml @@ -23,3 +23,46 @@ vadc.vim: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_masked(vd) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + /* for bypassing normal masking in init_masked_result */ + vec_trues : vector('n, dec, bool) = undefined; + foreach (i from 0 to (num_elem - 1)) { + vec_trues[i] = true + }; + + let vm_val : vector('n, dec, bool) = read_vmask_carry(num_elem, 0b0, 0b00000); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vec_trues); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VIMS_VADC => to_bits(SEW, unsigned(vs2_val[i]) + unsigned(imm_val) + unsigned(bool_to_bits(vm_val[i]))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vadc.vvm.yaml b/arch/inst/V/vadc.vvm.yaml index a19537f499..fbad144d55 100644 --- a/arch/inst/V/vadc.vvm.yaml +++ b/arch/inst/V/vadc.vvm.yaml @@ -23,3 +23,47 @@ vadc.vvm: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_masked(vd) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + /* for bypassing normal masking in init_masked_result */ + vec_trues : vector('n, dec, bool) = undefined; + foreach (i from 0 to (num_elem - 1)) { + vec_trues[i] = true + }; + + let vm_val : vector('n, dec, bool) = read_vmask_carry(num_elem, 0b0, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vec_trues); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VVMS_VADC => to_bits(SEW, unsigned(vs2_val[i]) + unsigned(vs1_val[i]) + unsigned(bool_to_bits(vm_val[i]))), + VVMS_VSBC => to_bits(SEW, unsigned(vs2_val[i]) - unsigned(vs1_val[i]) - unsigned(bool_to_bits(vm_val[i]))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vadc.vxm.yaml b/arch/inst/V/vadc.vxm.yaml index 6a62651946..e4cfaaaaae 100644 --- a/arch/inst/V/vadc.vxm.yaml +++ b/arch/inst/V/vadc.vxm.yaml @@ -23,3 +23,47 @@ vadc.vxm: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_masked(vd) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + /* for bypassing normal masking in init_masked_result */ + vec_trues : vector('n, dec, bool) = undefined; + foreach (i from 0 to (num_elem - 1)) { + vec_trues[i] = true + }; + + let vm_val : vector('n, dec, bool) = read_vmask_carry(num_elem, 0b0, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vec_trues); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VXMS_VADC => to_bits(SEW, unsigned(vs2_val[i]) + unsigned(rs1_val) + unsigned(bool_to_bits(vm_val[i]))), + VXMS_VSBC => to_bits(SEW, unsigned(vs2_val[i]) - unsigned(rs1_val) - unsigned(bool_to_bits(vm_val[i]))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vadd.vi.yaml b/arch/inst/V/vadd.vi.yaml index e965428930..c4f9878d96 100644 --- a/arch/inst/V/vadd.vi.yaml +++ b/arch/inst/V/vadd.vi.yaml @@ -25,3 +25,70 @@ vadd.vi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VI_VADD => vs2_val[i] + imm_val, + VI_VRSUB => imm_val - vs2_val[i], + VI_VAND => vs2_val[i] & imm_val, + VI_VOR => vs2_val[i] | imm_val, + VI_VXOR => vs2_val[i] ^ imm_val, + VI_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, imm_val) ), + VI_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, imm_val) ), + VI_VSLL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + vs2_val[i] << shift_amount + }, + VI_VSRL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + vs2_val[i] >> shift_amount + }, + VI_VSRA => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VI_VSSRL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VI_VSSRA => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vadd.vv.yaml b/arch/inst/V/vadd.vv.yaml index ffc2f20de8..9de3395926 100644 --- a/arch/inst/V/vadd.vv.yaml +++ b/arch/inst/V/vadd.vv.yaml @@ -25,3 +25,103 @@ vadd.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VV_VADD => vs2_val[i] + vs1_val[i], + VV_VSUB => vs2_val[i] - vs1_val[i], + VV_VAND => vs2_val[i] & vs1_val[i], + VV_VOR => vs2_val[i] | vs1_val[i], + VV_VXOR => vs2_val[i] ^ vs1_val[i], + VV_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i])), + VV_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i])), + VV_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(vs1_val[i]) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i])) + }, + VV_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i])), + VV_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(vs1_val[i])); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VV_VSLL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] << shift_amount + }, + VV_VSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] >> shift_amount + }, + VV_VSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VV_VSSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VV_VSSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VV_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VRGATHER => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let idx = unsigned(vs1_val[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + }, + VV_VRGATHEREI16 => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + /* vrgatherei16.vv uses SEW/LMUL for the data in vs2 but EEW=16 and EMUL = (16/SEW)*LMUL for the indices in vs1 */ + let vs1_new : vector('n, dec, bits(16)) = read_vreg(num_elem, 16, 4 + LMUL_pow - SEW_pow, vs1); + let idx = unsigned(vs1_new[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vadd.vx.yaml b/arch/inst/V/vadd.vx.yaml index ca6d226087..f76479869c 100644 --- a/arch/inst/V/vadd.vx.yaml +++ b/arch/inst/V/vadd.vx.yaml @@ -25,3 +25,86 @@ vadd.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VX_VADD => vs2_val[i] + rs1_val, + VX_VSUB => vs2_val[i] - rs1_val, + VX_VRSUB => rs1_val - vs2_val[i], + VX_VAND => vs2_val[i] & rs1_val, + VX_VOR => vs2_val[i] | rs1_val, + VX_VXOR => vs2_val[i] ^ rs1_val, + VX_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val) ), + VX_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val) ), + VX_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(rs1_val) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val) ) + }, + VX_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val) ), + VX_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(rs1_val)); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VX_VSLL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] << shift_amount + }, + VX_VSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] >> shift_amount + }, + VX_VSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VX_VSSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VX_VSSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VX_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(rs1_val))), + VX_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(rs1_val))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vand.vi.yaml b/arch/inst/V/vand.vi.yaml index 0271c97675..e29e07bef4 100644 --- a/arch/inst/V/vand.vi.yaml +++ b/arch/inst/V/vand.vi.yaml @@ -25,3 +25,70 @@ vand.vi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VI_VADD => vs2_val[i] + imm_val, + VI_VRSUB => imm_val - vs2_val[i], + VI_VAND => vs2_val[i] & imm_val, + VI_VOR => vs2_val[i] | imm_val, + VI_VXOR => vs2_val[i] ^ imm_val, + VI_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, imm_val) ), + VI_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, imm_val) ), + VI_VSLL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + vs2_val[i] << shift_amount + }, + VI_VSRL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + vs2_val[i] >> shift_amount + }, + VI_VSRA => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VI_VSSRL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VI_VSSRA => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vand.vv.yaml b/arch/inst/V/vand.vv.yaml index 9698a45092..b20ec626e6 100644 --- a/arch/inst/V/vand.vv.yaml +++ b/arch/inst/V/vand.vv.yaml @@ -25,3 +25,103 @@ vand.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VV_VADD => vs2_val[i] + vs1_val[i], + VV_VSUB => vs2_val[i] - vs1_val[i], + VV_VAND => vs2_val[i] & vs1_val[i], + VV_VOR => vs2_val[i] | vs1_val[i], + VV_VXOR => vs2_val[i] ^ vs1_val[i], + VV_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i])), + VV_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i])), + VV_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(vs1_val[i]) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i])) + }, + VV_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i])), + VV_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(vs1_val[i])); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VV_VSLL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] << shift_amount + }, + VV_VSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] >> shift_amount + }, + VV_VSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VV_VSSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VV_VSSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VV_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VRGATHER => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let idx = unsigned(vs1_val[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + }, + VV_VRGATHEREI16 => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + /* vrgatherei16.vv uses SEW/LMUL for the data in vs2 but EEW=16 and EMUL = (16/SEW)*LMUL for the indices in vs1 */ + let vs1_new : vector('n, dec, bits(16)) = read_vreg(num_elem, 16, 4 + LMUL_pow - SEW_pow, vs1); + let idx = unsigned(vs1_new[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vand.vx.yaml b/arch/inst/V/vand.vx.yaml index 3907bad30f..6cdae6f34e 100644 --- a/arch/inst/V/vand.vx.yaml +++ b/arch/inst/V/vand.vx.yaml @@ -25,3 +25,86 @@ vand.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VX_VADD => vs2_val[i] + rs1_val, + VX_VSUB => vs2_val[i] - rs1_val, + VX_VRSUB => rs1_val - vs2_val[i], + VX_VAND => vs2_val[i] & rs1_val, + VX_VOR => vs2_val[i] | rs1_val, + VX_VXOR => vs2_val[i] ^ rs1_val, + VX_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val) ), + VX_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val) ), + VX_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(rs1_val) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val) ) + }, + VX_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val) ), + VX_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(rs1_val)); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VX_VSLL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] << shift_amount + }, + VX_VSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] >> shift_amount + }, + VX_VSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VX_VSSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VX_VSSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VX_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(rs1_val))), + VX_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(rs1_val))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vasub.vv.yaml b/arch/inst/V/vasub.vv.yaml index 35f1d49f6c..06cb3c8ddd 100644 --- a/arch/inst/V/vasub.vv.yaml +++ b/arch/inst/V/vasub.vv.yaml @@ -25,3 +25,85 @@ vasub.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVV_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), 0), + MVV_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), SEW), + MVV_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(vs1_val[i]), SEW), + MVV_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(vs1_val[i]), SEW), + MVV_VDIVU => { + let q : int = if unsigned(vs1_val[i]) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i])); + to_bits(SEW, q) + }, + MVV_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(vs1_val[i]) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(vs1_val[i])); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVV_VREMU => { + let r : int = if unsigned(vs1_val[i]) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i])); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVV_VREM => { + let r : int = if signed(vs1_val[i]) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(vs1_val[i])); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vasub.vx.yaml b/arch/inst/V/vasub.vx.yaml index 2765e26b03..42ec9db667 100644 --- a/arch/inst/V/vasub.vx.yaml +++ b/arch/inst/V/vasub.vx.yaml @@ -25,3 +25,94 @@ vasub.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVX_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VSLIDE1UP => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + MVX_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + }, + MVX_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), 0), + MVX_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), SEW), + MVX_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VDIVU => { + let q : int = if unsigned(rs1_val) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(rs1_val)); + to_bits(SEW, q) + }, + MVX_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(rs1_val) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVX_VREMU => { + let r : int = if unsigned(rs1_val) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned (rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVX_VREM => { + let r : int = if signed(rs1_val) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vasubu.vv.yaml b/arch/inst/V/vasubu.vv.yaml index d8db85a31a..123783b1a4 100644 --- a/arch/inst/V/vasubu.vv.yaml +++ b/arch/inst/V/vasubu.vv.yaml @@ -25,3 +25,85 @@ vasubu.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVV_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), 0), + MVV_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), SEW), + MVV_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(vs1_val[i]), SEW), + MVV_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(vs1_val[i]), SEW), + MVV_VDIVU => { + let q : int = if unsigned(vs1_val[i]) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i])); + to_bits(SEW, q) + }, + MVV_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(vs1_val[i]) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(vs1_val[i])); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVV_VREMU => { + let r : int = if unsigned(vs1_val[i]) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i])); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVV_VREM => { + let r : int = if signed(vs1_val[i]) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(vs1_val[i])); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vasubu.vx.yaml b/arch/inst/V/vasubu.vx.yaml index 497806f41c..9261db5222 100644 --- a/arch/inst/V/vasubu.vx.yaml +++ b/arch/inst/V/vasubu.vx.yaml @@ -25,3 +25,94 @@ vasubu.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVX_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VSLIDE1UP => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + MVX_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + }, + MVX_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), 0), + MVX_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), SEW), + MVX_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VDIVU => { + let q : int = if unsigned(rs1_val) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(rs1_val)); + to_bits(SEW, q) + }, + MVX_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(rs1_val) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVX_VREMU => { + let r : int = if unsigned(rs1_val) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned (rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVX_VREM => { + let r : int = if signed(rs1_val) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vcompress.vm.yaml b/arch/inst/V/vcompress.vm.yaml index d11fffb816..08c77eb8f2 100644 --- a/arch/inst/V/vcompress.vm.yaml +++ b/arch/inst/V/vcompress.vm.yaml @@ -23,3 +23,56 @@ vcompress.vm: data_independent_timing: false operation(): | + + + + sail(): | + { + let start_element = get_start_element(); + let end_element = get_end_element(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + /* vcompress should always be executed with a vstart of 0 */ + if start_element != 0 | vs1 == vd | vs2 == vd | illegal_vd_unmasked() + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vs1_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + + /* body elements */ + vd_idx : nat = 0; + foreach (i from 0 to (num_elem - 1)) { + if i <= end_element then { + if vs1_val[i] then { + let 'p = vd_idx; + assert('p < 'n); + result['p] = vs2_val[i]; + vd_idx = vd_idx + 1; + } + } + }; + /* tail elements */ + if vd_idx < num_elem then { + let tail_ag : agtype = get_vtype_vta(); + let 'p = vd_idx; + foreach (i from 'p to (num_elem - 1)) { + result[i] = match tail_ag { + UNDISTURBED => vd_val[i], + AGNOSTIC => vd_val[i] /* TODO: configuration support */ + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vdiv.vv.yaml b/arch/inst/V/vdiv.vv.yaml index a728596742..c06bfccbdd 100644 --- a/arch/inst/V/vdiv.vv.yaml +++ b/arch/inst/V/vdiv.vv.yaml @@ -25,3 +25,85 @@ vdiv.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVV_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), 0), + MVV_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), SEW), + MVV_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(vs1_val[i]), SEW), + MVV_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(vs1_val[i]), SEW), + MVV_VDIVU => { + let q : int = if unsigned(vs1_val[i]) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i])); + to_bits(SEW, q) + }, + MVV_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(vs1_val[i]) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(vs1_val[i])); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVV_VREMU => { + let r : int = if unsigned(vs1_val[i]) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i])); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVV_VREM => { + let r : int = if signed(vs1_val[i]) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(vs1_val[i])); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vdiv.vx.yaml b/arch/inst/V/vdiv.vx.yaml index 418d0975ee..2ed12950c2 100644 --- a/arch/inst/V/vdiv.vx.yaml +++ b/arch/inst/V/vdiv.vx.yaml @@ -25,3 +25,94 @@ vdiv.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVX_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VSLIDE1UP => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + MVX_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + }, + MVX_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), 0), + MVX_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), SEW), + MVX_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VDIVU => { + let q : int = if unsigned(rs1_val) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(rs1_val)); + to_bits(SEW, q) + }, + MVX_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(rs1_val) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVX_VREMU => { + let r : int = if unsigned(rs1_val) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned (rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVX_VREM => { + let r : int = if signed(rs1_val) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vdivu.vv.yaml b/arch/inst/V/vdivu.vv.yaml index 4a83a55471..edbe82ffe1 100644 --- a/arch/inst/V/vdivu.vv.yaml +++ b/arch/inst/V/vdivu.vv.yaml @@ -25,3 +25,85 @@ vdivu.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVV_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), 0), + MVV_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), SEW), + MVV_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(vs1_val[i]), SEW), + MVV_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(vs1_val[i]), SEW), + MVV_VDIVU => { + let q : int = if unsigned(vs1_val[i]) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i])); + to_bits(SEW, q) + }, + MVV_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(vs1_val[i]) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(vs1_val[i])); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVV_VREMU => { + let r : int = if unsigned(vs1_val[i]) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i])); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVV_VREM => { + let r : int = if signed(vs1_val[i]) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(vs1_val[i])); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vdivu.vx.yaml b/arch/inst/V/vdivu.vx.yaml index 889d2b0038..374bb63e24 100644 --- a/arch/inst/V/vdivu.vx.yaml +++ b/arch/inst/V/vdivu.vx.yaml @@ -25,3 +25,94 @@ vdivu.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVX_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VSLIDE1UP => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + MVX_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + }, + MVX_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), 0), + MVX_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), SEW), + MVX_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VDIVU => { + let q : int = if unsigned(rs1_val) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(rs1_val)); + to_bits(SEW, q) + }, + MVX_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(rs1_val) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVX_VREMU => { + let r : int = if unsigned(rs1_val) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned (rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVX_VREM => { + let r : int = if signed(rs1_val) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfadd.vf.yaml b/arch/inst/V/vfadd.vf.yaml index da2071209b..bdb0373804 100644 --- a/arch/inst/V/vfadd.vf.yaml +++ b/arch/inst/V/vfadd.vf.yaml @@ -25,3 +25,61 @@ vfadd.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VF_VADD => fp_add(rm_3b, vs2_val[i], rs1_val), + VF_VSUB => fp_sub(rm_3b, vs2_val[i], rs1_val), + VF_VRSUB => fp_sub(rm_3b, rs1_val, vs2_val[i]), + VF_VMIN => fp_min(vs2_val[i], rs1_val), + VF_VMAX => fp_max(vs2_val[i], rs1_val), + VF_VMUL => fp_mul(rm_3b, vs2_val[i], rs1_val), + VF_VDIV => fp_div(rm_3b, vs2_val[i], rs1_val), + VF_VRDIV => fp_div(rm_3b, rs1_val, vs2_val[i]), + VF_VSGNJ => [rs1_val['m - 1]] @ vs2_val[i][('m - 2)..0], + VF_VSGNJN => (0b1 ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSGNJX => ([vs2_val[i]['m - 1]] ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSLIDE1UP => { + if vs2 == vd then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + VF_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfadd.vv.yaml b/arch/inst/V/vfadd.vv.yaml index 88379d30f2..1652ef809d 100644 --- a/arch/inst/V/vfadd.vv.yaml +++ b/arch/inst/V/vfadd.vv.yaml @@ -25,3 +25,50 @@ vfadd.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FVV_VADD => fp_add(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VSUB => fp_sub(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VMIN => fp_min(vs2_val[i], vs1_val[i]), + FVV_VMAX => fp_max(vs2_val[i], vs1_val[i]), + FVV_VMUL => fp_mul(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VDIV => fp_div(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VSGNJ => [vs1_val[i]['m - 1]] @ vs2_val[i][('m - 2)..0], + FVV_VSGNJN => (0b1 ^ [vs1_val[i]['m - 1]]) @ vs2_val[i][('m - 2)..0], + FVV_VSGNJX => ([vs2_val[i]['m - 1]] ^ [vs1_val[i]['m - 1]]) @ vs2_val[i][('m - 2)..0] + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfclass.v.yaml b/arch/inst/V/vfclass.v.yaml index a9404f26f1..2ef28967e7 100644 --- a/arch/inst/V/vfclass.v.yaml +++ b/arch/inst/V/vfclass.v.yaml @@ -23,3 +23,68 @@ vfclass.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfunary1 { + FVV_VSQRT => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16Sqrt(rm_3b, vs2_val[i]), + 32 => riscv_f32Sqrt(rm_3b, vs2_val[i]), + 64 => riscv_f64Sqrt(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FVV_VRSQRT7 => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16Rsqrte7(rm_3b, vs2_val[i]), + 32 => riscv_f32Rsqrte7(rm_3b, vs2_val[i]), + 64 => riscv_f64Rsqrte7(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FVV_VREC7 => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16Recip7(rm_3b, vs2_val[i]), + 32 => riscv_f32Recip7(rm_3b, vs2_val[i]), + 64 => riscv_f64Recip7(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FVV_VCLASS => fp_class(vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfcvt.f.x.v.yaml b/arch/inst/V/vfcvt.f.x.v.yaml index 8936b872f9..d67cf22e91 100644 --- a/arch/inst/V/vfcvt.f.x.v.yaml +++ b/arch/inst/V/vfcvt.f.x.v.yaml @@ -23,3 +23,93 @@ vfcvt.f.x.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfunary0 { + FV_CVT_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16ToUi16(rm_3b, vs2_val[i]), + 32 => riscv_f32ToUi32(rm_3b, vs2_val[i]), + 64 => riscv_f64ToUi64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16ToI16(rm_3b, vs2_val[i]), + 32 => riscv_f32ToI32(rm_3b, vs2_val[i]), + 64 => riscv_f64ToI64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_F_XU => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_ui32ToF16(rm_3b, zero_extend(vs2_val[i])), + 32 => riscv_ui32ToF32(rm_3b, vs2_val[i]), + 64 => riscv_ui64ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_F_X => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_i32ToF16(rm_3b, sign_extend(vs2_val[i])), + 32 => riscv_i32ToF32(rm_3b, vs2_val[i]), + 64 => riscv_i64ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_RTZ_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16ToUi16(0b001, vs2_val[i]), + 32 => riscv_f32ToUi32(0b001, vs2_val[i]), + 64 => riscv_f64ToUi64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_RTZ_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16ToI16(0b001, vs2_val[i]), + 32 => riscv_f32ToI32(0b001, vs2_val[i]), + 64 => riscv_f64ToI64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfcvt.f.xu.v.yaml b/arch/inst/V/vfcvt.f.xu.v.yaml index c59d8093d9..62925a6c1d 100644 --- a/arch/inst/V/vfcvt.f.xu.v.yaml +++ b/arch/inst/V/vfcvt.f.xu.v.yaml @@ -23,3 +23,93 @@ vfcvt.f.xu.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfunary0 { + FV_CVT_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16ToUi16(rm_3b, vs2_val[i]), + 32 => riscv_f32ToUi32(rm_3b, vs2_val[i]), + 64 => riscv_f64ToUi64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16ToI16(rm_3b, vs2_val[i]), + 32 => riscv_f32ToI32(rm_3b, vs2_val[i]), + 64 => riscv_f64ToI64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_F_XU => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_ui32ToF16(rm_3b, zero_extend(vs2_val[i])), + 32 => riscv_ui32ToF32(rm_3b, vs2_val[i]), + 64 => riscv_ui64ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_F_X => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_i32ToF16(rm_3b, sign_extend(vs2_val[i])), + 32 => riscv_i32ToF32(rm_3b, vs2_val[i]), + 64 => riscv_i64ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_RTZ_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16ToUi16(0b001, vs2_val[i]), + 32 => riscv_f32ToUi32(0b001, vs2_val[i]), + 64 => riscv_f64ToUi64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_RTZ_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16ToI16(0b001, vs2_val[i]), + 32 => riscv_f32ToI32(0b001, vs2_val[i]), + 64 => riscv_f64ToI64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfcvt.rtz.x.f.v.yaml b/arch/inst/V/vfcvt.rtz.x.f.v.yaml index b42c5ab2dc..cc6326783b 100644 --- a/arch/inst/V/vfcvt.rtz.x.f.v.yaml +++ b/arch/inst/V/vfcvt.rtz.x.f.v.yaml @@ -23,3 +23,93 @@ vfcvt.rtz.x.f.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfunary0 { + FV_CVT_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16ToUi16(rm_3b, vs2_val[i]), + 32 => riscv_f32ToUi32(rm_3b, vs2_val[i]), + 64 => riscv_f64ToUi64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16ToI16(rm_3b, vs2_val[i]), + 32 => riscv_f32ToI32(rm_3b, vs2_val[i]), + 64 => riscv_f64ToI64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_F_XU => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_ui32ToF16(rm_3b, zero_extend(vs2_val[i])), + 32 => riscv_ui32ToF32(rm_3b, vs2_val[i]), + 64 => riscv_ui64ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_F_X => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_i32ToF16(rm_3b, sign_extend(vs2_val[i])), + 32 => riscv_i32ToF32(rm_3b, vs2_val[i]), + 64 => riscv_i64ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_RTZ_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16ToUi16(0b001, vs2_val[i]), + 32 => riscv_f32ToUi32(0b001, vs2_val[i]), + 64 => riscv_f64ToUi64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_RTZ_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16ToI16(0b001, vs2_val[i]), + 32 => riscv_f32ToI32(0b001, vs2_val[i]), + 64 => riscv_f64ToI64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfcvt.rtz.xu.f.v.yaml b/arch/inst/V/vfcvt.rtz.xu.f.v.yaml index 9d7d0323da..ccca0719ef 100644 --- a/arch/inst/V/vfcvt.rtz.xu.f.v.yaml +++ b/arch/inst/V/vfcvt.rtz.xu.f.v.yaml @@ -23,3 +23,93 @@ vfcvt.rtz.xu.f.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfunary0 { + FV_CVT_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16ToUi16(rm_3b, vs2_val[i]), + 32 => riscv_f32ToUi32(rm_3b, vs2_val[i]), + 64 => riscv_f64ToUi64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16ToI16(rm_3b, vs2_val[i]), + 32 => riscv_f32ToI32(rm_3b, vs2_val[i]), + 64 => riscv_f64ToI64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_F_XU => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_ui32ToF16(rm_3b, zero_extend(vs2_val[i])), + 32 => riscv_ui32ToF32(rm_3b, vs2_val[i]), + 64 => riscv_ui64ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_F_X => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_i32ToF16(rm_3b, sign_extend(vs2_val[i])), + 32 => riscv_i32ToF32(rm_3b, vs2_val[i]), + 64 => riscv_i64ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_RTZ_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16ToUi16(0b001, vs2_val[i]), + 32 => riscv_f32ToUi32(0b001, vs2_val[i]), + 64 => riscv_f64ToUi64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_RTZ_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16ToI16(0b001, vs2_val[i]), + 32 => riscv_f32ToI32(0b001, vs2_val[i]), + 64 => riscv_f64ToI64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfcvt.x.f.v.yaml b/arch/inst/V/vfcvt.x.f.v.yaml index 727f2c52ac..5b14948192 100644 --- a/arch/inst/V/vfcvt.x.f.v.yaml +++ b/arch/inst/V/vfcvt.x.f.v.yaml @@ -23,3 +23,93 @@ vfcvt.x.f.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfunary0 { + FV_CVT_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16ToUi16(rm_3b, vs2_val[i]), + 32 => riscv_f32ToUi32(rm_3b, vs2_val[i]), + 64 => riscv_f64ToUi64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16ToI16(rm_3b, vs2_val[i]), + 32 => riscv_f32ToI32(rm_3b, vs2_val[i]), + 64 => riscv_f64ToI64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_F_XU => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_ui32ToF16(rm_3b, zero_extend(vs2_val[i])), + 32 => riscv_ui32ToF32(rm_3b, vs2_val[i]), + 64 => riscv_ui64ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_F_X => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_i32ToF16(rm_3b, sign_extend(vs2_val[i])), + 32 => riscv_i32ToF32(rm_3b, vs2_val[i]), + 64 => riscv_i64ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_RTZ_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16ToUi16(0b001, vs2_val[i]), + 32 => riscv_f32ToUi32(0b001, vs2_val[i]), + 64 => riscv_f64ToUi64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_RTZ_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16ToI16(0b001, vs2_val[i]), + 32 => riscv_f32ToI32(0b001, vs2_val[i]), + 64 => riscv_f64ToI64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfcvt.xu.f.v.yaml b/arch/inst/V/vfcvt.xu.f.v.yaml index a09d0409a7..ae6b9647c1 100644 --- a/arch/inst/V/vfcvt.xu.f.v.yaml +++ b/arch/inst/V/vfcvt.xu.f.v.yaml @@ -23,3 +23,93 @@ vfcvt.xu.f.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfunary0 { + FV_CVT_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16ToUi16(rm_3b, vs2_val[i]), + 32 => riscv_f32ToUi32(rm_3b, vs2_val[i]), + 64 => riscv_f64ToUi64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16ToI16(rm_3b, vs2_val[i]), + 32 => riscv_f32ToI32(rm_3b, vs2_val[i]), + 64 => riscv_f64ToI64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_F_XU => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_ui32ToF16(rm_3b, zero_extend(vs2_val[i])), + 32 => riscv_ui32ToF32(rm_3b, vs2_val[i]), + 64 => riscv_ui64ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_F_X => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_i32ToF16(rm_3b, sign_extend(vs2_val[i])), + 32 => riscv_i32ToF32(rm_3b, vs2_val[i]), + 64 => riscv_i64ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_RTZ_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16ToUi16(0b001, vs2_val[i]), + 32 => riscv_f32ToUi32(0b001, vs2_val[i]), + 64 => riscv_f64ToUi64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FV_CVT_RTZ_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16ToI16(0b001, vs2_val[i]), + 32 => riscv_f32ToI32(0b001, vs2_val[i]), + 64 => riscv_f64ToI64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfdiv.vf.yaml b/arch/inst/V/vfdiv.vf.yaml index a98e8ac17e..0c37c99f6a 100644 --- a/arch/inst/V/vfdiv.vf.yaml +++ b/arch/inst/V/vfdiv.vf.yaml @@ -25,3 +25,61 @@ vfdiv.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VF_VADD => fp_add(rm_3b, vs2_val[i], rs1_val), + VF_VSUB => fp_sub(rm_3b, vs2_val[i], rs1_val), + VF_VRSUB => fp_sub(rm_3b, rs1_val, vs2_val[i]), + VF_VMIN => fp_min(vs2_val[i], rs1_val), + VF_VMAX => fp_max(vs2_val[i], rs1_val), + VF_VMUL => fp_mul(rm_3b, vs2_val[i], rs1_val), + VF_VDIV => fp_div(rm_3b, vs2_val[i], rs1_val), + VF_VRDIV => fp_div(rm_3b, rs1_val, vs2_val[i]), + VF_VSGNJ => [rs1_val['m - 1]] @ vs2_val[i][('m - 2)..0], + VF_VSGNJN => (0b1 ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSGNJX => ([vs2_val[i]['m - 1]] ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSLIDE1UP => { + if vs2 == vd then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + VF_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfdiv.vv.yaml b/arch/inst/V/vfdiv.vv.yaml index c12319a677..2e91f2a3f2 100644 --- a/arch/inst/V/vfdiv.vv.yaml +++ b/arch/inst/V/vfdiv.vv.yaml @@ -25,3 +25,50 @@ vfdiv.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FVV_VADD => fp_add(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VSUB => fp_sub(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VMIN => fp_min(vs2_val[i], vs1_val[i]), + FVV_VMAX => fp_max(vs2_val[i], vs1_val[i]), + FVV_VMUL => fp_mul(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VDIV => fp_div(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VSGNJ => [vs1_val[i]['m - 1]] @ vs2_val[i][('m - 2)..0], + FVV_VSGNJN => (0b1 ^ [vs1_val[i]['m - 1]]) @ vs2_val[i][('m - 2)..0], + FVV_VSGNJX => ([vs2_val[i]['m - 1]] ^ [vs1_val[i]['m - 1]]) @ vs2_val[i][('m - 2)..0] + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfirst.m.yaml b/arch/inst/V/vfirst.m.yaml index 1fe75448ae..9199f55ee4 100644 --- a/arch/inst/V/vfirst.m.yaml +++ b/arch/inst/V/vfirst.m.yaml @@ -23,3 +23,37 @@ vfirst.m: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = unsigned(vlenb) * 8; + + if illegal_vd_unmasked() | not(assert_vstart(0)) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vs2); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, 0, vs2_val, vm_val); + + index : int = -1; + foreach (i from 0 to (num_elem - 1)) { + if index == -1 then { + if mask[i] & vs2_val[i] then index = i; + }; + }; + + X(rd) = to_bits(sizeof(xlen), index); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfmacc.vf.yaml b/arch/inst/V/vfmacc.vf.yaml index 848081c16d..68e5df409b 100644 --- a/arch/inst/V/vfmacc.vf.yaml +++ b/arch/inst/V/vfmacc.vf.yaml @@ -25,3 +25,49 @@ vfmacc.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VF_VMACC => fp_muladd(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VNMACC => fp_nmulsub(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VMSAC => fp_mulsub(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VNMSAC => fp_nmuladd(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VMADD => fp_muladd(rm_3b, rs1_val, vd_val[i], vs2_val[i]), + VF_VNMADD => fp_nmulsub(rm_3b, rs1_val, vd_val[i], vs2_val[i]), + VF_VMSUB => fp_mulsub(rm_3b, rs1_val, vd_val[i], vs2_val[i]), + VF_VNMSUB => fp_nmuladd(rm_3b, rs1_val, vd_val[i], vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfmacc.vv.yaml b/arch/inst/V/vfmacc.vv.yaml index 299f98cd63..5d6803e30d 100644 --- a/arch/inst/V/vfmacc.vv.yaml +++ b/arch/inst/V/vfmacc.vv.yaml @@ -25,3 +25,49 @@ vfmacc.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FVV_VMACC => fp_muladd(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VNMACC => fp_nmulsub(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VMSAC => fp_mulsub(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VNMSAC => fp_nmuladd(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VMADD => fp_muladd(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]), + FVV_VNMADD => fp_nmulsub(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]), + FVV_VMSUB => fp_mulsub(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]), + FVV_VNMSUB => fp_nmuladd(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfmadd.vf.yaml b/arch/inst/V/vfmadd.vf.yaml index 4b6bdf7fce..3376968fd7 100644 --- a/arch/inst/V/vfmadd.vf.yaml +++ b/arch/inst/V/vfmadd.vf.yaml @@ -25,3 +25,49 @@ vfmadd.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VF_VMACC => fp_muladd(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VNMACC => fp_nmulsub(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VMSAC => fp_mulsub(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VNMSAC => fp_nmuladd(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VMADD => fp_muladd(rm_3b, rs1_val, vd_val[i], vs2_val[i]), + VF_VNMADD => fp_nmulsub(rm_3b, rs1_val, vd_val[i], vs2_val[i]), + VF_VMSUB => fp_mulsub(rm_3b, rs1_val, vd_val[i], vs2_val[i]), + VF_VNMSUB => fp_nmuladd(rm_3b, rs1_val, vd_val[i], vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfmadd.vv.yaml b/arch/inst/V/vfmadd.vv.yaml index c84e6a000e..f304a8dc8b 100644 --- a/arch/inst/V/vfmadd.vv.yaml +++ b/arch/inst/V/vfmadd.vv.yaml @@ -25,3 +25,49 @@ vfmadd.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FVV_VMACC => fp_muladd(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VNMACC => fp_nmulsub(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VMSAC => fp_mulsub(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VNMSAC => fp_nmuladd(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VMADD => fp_muladd(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]), + FVV_VNMADD => fp_nmulsub(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]), + FVV_VMSUB => fp_mulsub(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]), + FVV_VNMSUB => fp_nmuladd(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfmax.vf.yaml b/arch/inst/V/vfmax.vf.yaml index d0aa05b4fd..ad23bb3df2 100644 --- a/arch/inst/V/vfmax.vf.yaml +++ b/arch/inst/V/vfmax.vf.yaml @@ -25,3 +25,61 @@ vfmax.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VF_VADD => fp_add(rm_3b, vs2_val[i], rs1_val), + VF_VSUB => fp_sub(rm_3b, vs2_val[i], rs1_val), + VF_VRSUB => fp_sub(rm_3b, rs1_val, vs2_val[i]), + VF_VMIN => fp_min(vs2_val[i], rs1_val), + VF_VMAX => fp_max(vs2_val[i], rs1_val), + VF_VMUL => fp_mul(rm_3b, vs2_val[i], rs1_val), + VF_VDIV => fp_div(rm_3b, vs2_val[i], rs1_val), + VF_VRDIV => fp_div(rm_3b, rs1_val, vs2_val[i]), + VF_VSGNJ => [rs1_val['m - 1]] @ vs2_val[i][('m - 2)..0], + VF_VSGNJN => (0b1 ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSGNJX => ([vs2_val[i]['m - 1]] ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSLIDE1UP => { + if vs2 == vd then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + VF_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfmax.vv.yaml b/arch/inst/V/vfmax.vv.yaml index 261be352c2..7f1a603e33 100644 --- a/arch/inst/V/vfmax.vv.yaml +++ b/arch/inst/V/vfmax.vv.yaml @@ -25,3 +25,50 @@ vfmax.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FVV_VADD => fp_add(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VSUB => fp_sub(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VMIN => fp_min(vs2_val[i], vs1_val[i]), + FVV_VMAX => fp_max(vs2_val[i], vs1_val[i]), + FVV_VMUL => fp_mul(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VDIV => fp_div(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VSGNJ => [vs1_val[i]['m - 1]] @ vs2_val[i][('m - 2)..0], + FVV_VSGNJN => (0b1 ^ [vs1_val[i]['m - 1]]) @ vs2_val[i][('m - 2)..0], + FVV_VSGNJX => ([vs2_val[i]['m - 1]] ^ [vs1_val[i]['m - 1]]) @ vs2_val[i][('m - 2)..0] + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfmerge.vfm.yaml b/arch/inst/V/vfmerge.vfm.yaml index b8534396bf..3a81e546ab 100644 --- a/arch/inst/V/vfmerge.vfm.yaml +++ b/arch/inst/V/vfmerge.vfm.yaml @@ -23,3 +23,49 @@ vfmerge.vfm: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let start_element = get_start_element(); + let end_element = get_end_element(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); /* max(VLMAX,VLEN/SEW)) */ + let real_num_elem = if LMUL_pow >= 0 then num_elem else num_elem / (0 - LMUL_pow); /* VLMAX */ + + if illegal_fp_vd_masked(vd, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + + let tail_ag : agtype = get_vtype_vta(); + foreach (i from 0 to (num_elem - 1)) { + if i < start_element then { + result[i] = vd_val[i] + } else if i > end_element | i >= real_num_elem then { + result[i] = match tail_ag { + UNDISTURBED => vd_val[i], + AGNOSTIC => vd_val[i] /* TODO: configuration support */ + } + } else { + /* the merge operates on all body elements */ + result[i] = if vm_val[i] then rs1_val else vs2_val[i] + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfmin.vf.yaml b/arch/inst/V/vfmin.vf.yaml index e4c0cdf7a3..278929ab07 100644 --- a/arch/inst/V/vfmin.vf.yaml +++ b/arch/inst/V/vfmin.vf.yaml @@ -25,3 +25,61 @@ vfmin.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VF_VADD => fp_add(rm_3b, vs2_val[i], rs1_val), + VF_VSUB => fp_sub(rm_3b, vs2_val[i], rs1_val), + VF_VRSUB => fp_sub(rm_3b, rs1_val, vs2_val[i]), + VF_VMIN => fp_min(vs2_val[i], rs1_val), + VF_VMAX => fp_max(vs2_val[i], rs1_val), + VF_VMUL => fp_mul(rm_3b, vs2_val[i], rs1_val), + VF_VDIV => fp_div(rm_3b, vs2_val[i], rs1_val), + VF_VRDIV => fp_div(rm_3b, rs1_val, vs2_val[i]), + VF_VSGNJ => [rs1_val['m - 1]] @ vs2_val[i][('m - 2)..0], + VF_VSGNJN => (0b1 ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSGNJX => ([vs2_val[i]['m - 1]] ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSLIDE1UP => { + if vs2 == vd then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + VF_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfmin.vv.yaml b/arch/inst/V/vfmin.vv.yaml index e11c72c856..687e6d1618 100644 --- a/arch/inst/V/vfmin.vv.yaml +++ b/arch/inst/V/vfmin.vv.yaml @@ -25,3 +25,50 @@ vfmin.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FVV_VADD => fp_add(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VSUB => fp_sub(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VMIN => fp_min(vs2_val[i], vs1_val[i]), + FVV_VMAX => fp_max(vs2_val[i], vs1_val[i]), + FVV_VMUL => fp_mul(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VDIV => fp_div(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VSGNJ => [vs1_val[i]['m - 1]] @ vs2_val[i][('m - 2)..0], + FVV_VSGNJN => (0b1 ^ [vs1_val[i]['m - 1]]) @ vs2_val[i][('m - 2)..0], + FVV_VSGNJX => ([vs2_val[i]['m - 1]] ^ [vs1_val[i]['m - 1]]) @ vs2_val[i][('m - 2)..0] + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfmsac.vf.yaml b/arch/inst/V/vfmsac.vf.yaml index fe0a143f65..226d827284 100644 --- a/arch/inst/V/vfmsac.vf.yaml +++ b/arch/inst/V/vfmsac.vf.yaml @@ -25,3 +25,49 @@ vfmsac.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VF_VMACC => fp_muladd(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VNMACC => fp_nmulsub(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VMSAC => fp_mulsub(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VNMSAC => fp_nmuladd(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VMADD => fp_muladd(rm_3b, rs1_val, vd_val[i], vs2_val[i]), + VF_VNMADD => fp_nmulsub(rm_3b, rs1_val, vd_val[i], vs2_val[i]), + VF_VMSUB => fp_mulsub(rm_3b, rs1_val, vd_val[i], vs2_val[i]), + VF_VNMSUB => fp_nmuladd(rm_3b, rs1_val, vd_val[i], vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfmsac.vv.yaml b/arch/inst/V/vfmsac.vv.yaml index 9c9c73181b..ac5d34c072 100644 --- a/arch/inst/V/vfmsac.vv.yaml +++ b/arch/inst/V/vfmsac.vv.yaml @@ -25,3 +25,49 @@ vfmsac.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FVV_VMACC => fp_muladd(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VNMACC => fp_nmulsub(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VMSAC => fp_mulsub(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VNMSAC => fp_nmuladd(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VMADD => fp_muladd(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]), + FVV_VNMADD => fp_nmulsub(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]), + FVV_VMSUB => fp_mulsub(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]), + FVV_VNMSUB => fp_nmuladd(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfmsub.vf.yaml b/arch/inst/V/vfmsub.vf.yaml index 50d17c5c4e..4e17f4db7a 100644 --- a/arch/inst/V/vfmsub.vf.yaml +++ b/arch/inst/V/vfmsub.vf.yaml @@ -25,3 +25,49 @@ vfmsub.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VF_VMACC => fp_muladd(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VNMACC => fp_nmulsub(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VMSAC => fp_mulsub(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VNMSAC => fp_nmuladd(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VMADD => fp_muladd(rm_3b, rs1_val, vd_val[i], vs2_val[i]), + VF_VNMADD => fp_nmulsub(rm_3b, rs1_val, vd_val[i], vs2_val[i]), + VF_VMSUB => fp_mulsub(rm_3b, rs1_val, vd_val[i], vs2_val[i]), + VF_VNMSUB => fp_nmuladd(rm_3b, rs1_val, vd_val[i], vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfmsub.vv.yaml b/arch/inst/V/vfmsub.vv.yaml index 861d7e2066..e78a49eaa4 100644 --- a/arch/inst/V/vfmsub.vv.yaml +++ b/arch/inst/V/vfmsub.vv.yaml @@ -25,3 +25,49 @@ vfmsub.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FVV_VMACC => fp_muladd(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VNMACC => fp_nmulsub(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VMSAC => fp_mulsub(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VNMSAC => fp_nmuladd(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VMADD => fp_muladd(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]), + FVV_VNMADD => fp_nmulsub(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]), + FVV_VMSUB => fp_mulsub(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]), + FVV_VNMSUB => fp_nmuladd(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfmul.vf.yaml b/arch/inst/V/vfmul.vf.yaml index 19291c302d..b628af0b2a 100644 --- a/arch/inst/V/vfmul.vf.yaml +++ b/arch/inst/V/vfmul.vf.yaml @@ -25,3 +25,61 @@ vfmul.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VF_VADD => fp_add(rm_3b, vs2_val[i], rs1_val), + VF_VSUB => fp_sub(rm_3b, vs2_val[i], rs1_val), + VF_VRSUB => fp_sub(rm_3b, rs1_val, vs2_val[i]), + VF_VMIN => fp_min(vs2_val[i], rs1_val), + VF_VMAX => fp_max(vs2_val[i], rs1_val), + VF_VMUL => fp_mul(rm_3b, vs2_val[i], rs1_val), + VF_VDIV => fp_div(rm_3b, vs2_val[i], rs1_val), + VF_VRDIV => fp_div(rm_3b, rs1_val, vs2_val[i]), + VF_VSGNJ => [rs1_val['m - 1]] @ vs2_val[i][('m - 2)..0], + VF_VSGNJN => (0b1 ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSGNJX => ([vs2_val[i]['m - 1]] ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSLIDE1UP => { + if vs2 == vd then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + VF_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfmul.vv.yaml b/arch/inst/V/vfmul.vv.yaml index ecaf3f31bb..fe34f5b4d7 100644 --- a/arch/inst/V/vfmul.vv.yaml +++ b/arch/inst/V/vfmul.vv.yaml @@ -25,3 +25,50 @@ vfmul.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FVV_VADD => fp_add(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VSUB => fp_sub(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VMIN => fp_min(vs2_val[i], vs1_val[i]), + FVV_VMAX => fp_max(vs2_val[i], vs1_val[i]), + FVV_VMUL => fp_mul(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VDIV => fp_div(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VSGNJ => [vs1_val[i]['m - 1]] @ vs2_val[i][('m - 2)..0], + FVV_VSGNJN => (0b1 ^ [vs1_val[i]['m - 1]]) @ vs2_val[i][('m - 2)..0], + FVV_VSGNJX => ([vs2_val[i]['m - 1]] ^ [vs1_val[i]['m - 1]]) @ vs2_val[i][('m - 2)..0] + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfmv.f.s.yaml b/arch/inst/V/vfmv.f.s.yaml index dfe9cdce26..3071666c77 100644 --- a/arch/inst/V/vfmv.f.s.yaml +++ b/arch/inst/V/vfmv.f.s.yaml @@ -21,3 +21,31 @@ vfmv.f.s: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let num_elem = get_num_elem(0, SEW); + + if illegal_fp_vd_unmasked(SEW, rm_3b) | SEW > sizeof(flen) + then { handle_illegal(); return RETIRE_FAIL }; + assert(num_elem > 0 & SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, 0, vs2); + match 'm { + 16 => F_H(rd) = vs2_val[0], + 32 => F_S(rd) = vs2_val[0], + 64 => F_D(rd) = vs2_val[0] + }; + vstart = zeros(); + + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfmv.s.f.yaml b/arch/inst/V/vfmv.s.f.yaml index 5f9970c1e2..277fb79dfc 100644 --- a/arch/inst/V/vfmv.s.f.yaml +++ b/arch/inst/V/vfmv.s.f.yaml @@ -21,3 +21,44 @@ vfmv.s.f: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let num_elem = get_num_elem(0, SEW); + + if illegal_fp_vd_unmasked(SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(num_elem > 0 & SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, 0b1, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, 0, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, 0, vd_val, vm_val); + + /* one body element */ + if mask[0] then result[0] = rs1_val; + + /* others treated as tail elements */ + let tail_ag : agtype = get_vtype_vta(); + foreach (i from 1 to (num_elem - 1)) { + result[i] = match tail_ag { + UNDISTURBED => vd_val[i], + AGNOSTIC => vd_val[i] /* TODO: configuration support */ + } + }; + + write_vreg(num_elem, SEW, 0, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfmv.v.f.yaml b/arch/inst/V/vfmv.v.f.yaml index 45f79d9180..30d48a07db 100644 --- a/arch/inst/V/vfmv.v.f.yaml +++ b/arch/inst/V/vfmv.v.f.yaml @@ -21,3 +21,37 @@ vfmv.v.f: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_vd_unmasked(SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, 0b1, 0b00000); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then result[i] = rs1_val + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfncvt.f.f.w.yaml b/arch/inst/V/vfncvt.f.f.w.yaml index 0c236d977c..472d85bcc5 100644 --- a/arch/inst/V/vfncvt.f.f.w.yaml +++ b/arch/inst/V/vfncvt.f.f.w.yaml @@ -23,3 +23,116 @@ vfncvt.f.f.w: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfnunary0 { + FNV_CVT_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToUi8(rm_3b, vs2_val[i]), + 16 => riscv_f32ToUi16(rm_3b, vs2_val[i]), + 32 => riscv_f64ToUi32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToI8(rm_3b, vs2_val[i]), + 16 => riscv_f32ToI16(rm_3b, vs2_val[i]), + 32 => riscv_f64ToI32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_F_XU => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_ui32ToF16(rm_3b, vs2_val[i]), + 32 => riscv_ui64ToF32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_F_X => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_i32ToF16(rm_3b, vs2_val[i]), + 32 => riscv_i64ToF32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_F_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f32ToF16(rm_3b, vs2_val[i]), + 32 => riscv_f64ToF32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_ROD_F_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f32ToF16(0b110, vs2_val[i]), + 32 => riscv_f64ToF32(0b110, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_RTZ_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToUi8(0b001, vs2_val[i]), + 16 => riscv_f32ToUi16(0b001, vs2_val[i]), + 32 => riscv_f64ToUi32(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_RTZ_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToI8(0b001, vs2_val[i]), + 16 => riscv_f32ToI16(0b001, vs2_val[i]), + 32 => riscv_f64ToI32(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfncvt.f.x.w.yaml b/arch/inst/V/vfncvt.f.x.w.yaml index 90eaf5def6..3402fdca6a 100644 --- a/arch/inst/V/vfncvt.f.x.w.yaml +++ b/arch/inst/V/vfncvt.f.x.w.yaml @@ -23,3 +23,116 @@ vfncvt.f.x.w: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfnunary0 { + FNV_CVT_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToUi8(rm_3b, vs2_val[i]), + 16 => riscv_f32ToUi16(rm_3b, vs2_val[i]), + 32 => riscv_f64ToUi32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToI8(rm_3b, vs2_val[i]), + 16 => riscv_f32ToI16(rm_3b, vs2_val[i]), + 32 => riscv_f64ToI32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_F_XU => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_ui32ToF16(rm_3b, vs2_val[i]), + 32 => riscv_ui64ToF32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_F_X => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_i32ToF16(rm_3b, vs2_val[i]), + 32 => riscv_i64ToF32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_F_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f32ToF16(rm_3b, vs2_val[i]), + 32 => riscv_f64ToF32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_ROD_F_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f32ToF16(0b110, vs2_val[i]), + 32 => riscv_f64ToF32(0b110, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_RTZ_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToUi8(0b001, vs2_val[i]), + 16 => riscv_f32ToUi16(0b001, vs2_val[i]), + 32 => riscv_f64ToUi32(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_RTZ_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToI8(0b001, vs2_val[i]), + 16 => riscv_f32ToI16(0b001, vs2_val[i]), + 32 => riscv_f64ToI32(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfncvt.f.xu.w.yaml b/arch/inst/V/vfncvt.f.xu.w.yaml index 481c156aa7..e8abd6fced 100644 --- a/arch/inst/V/vfncvt.f.xu.w.yaml +++ b/arch/inst/V/vfncvt.f.xu.w.yaml @@ -23,3 +23,116 @@ vfncvt.f.xu.w: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfnunary0 { + FNV_CVT_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToUi8(rm_3b, vs2_val[i]), + 16 => riscv_f32ToUi16(rm_3b, vs2_val[i]), + 32 => riscv_f64ToUi32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToI8(rm_3b, vs2_val[i]), + 16 => riscv_f32ToI16(rm_3b, vs2_val[i]), + 32 => riscv_f64ToI32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_F_XU => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_ui32ToF16(rm_3b, vs2_val[i]), + 32 => riscv_ui64ToF32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_F_X => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_i32ToF16(rm_3b, vs2_val[i]), + 32 => riscv_i64ToF32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_F_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f32ToF16(rm_3b, vs2_val[i]), + 32 => riscv_f64ToF32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_ROD_F_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f32ToF16(0b110, vs2_val[i]), + 32 => riscv_f64ToF32(0b110, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_RTZ_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToUi8(0b001, vs2_val[i]), + 16 => riscv_f32ToUi16(0b001, vs2_val[i]), + 32 => riscv_f64ToUi32(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_RTZ_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToI8(0b001, vs2_val[i]), + 16 => riscv_f32ToI16(0b001, vs2_val[i]), + 32 => riscv_f64ToI32(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfncvt.rod.f.f.w.yaml b/arch/inst/V/vfncvt.rod.f.f.w.yaml index b50a30bec4..9870cdbfbd 100644 --- a/arch/inst/V/vfncvt.rod.f.f.w.yaml +++ b/arch/inst/V/vfncvt.rod.f.f.w.yaml @@ -23,3 +23,116 @@ vfncvt.rod.f.f.w: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfnunary0 { + FNV_CVT_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToUi8(rm_3b, vs2_val[i]), + 16 => riscv_f32ToUi16(rm_3b, vs2_val[i]), + 32 => riscv_f64ToUi32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToI8(rm_3b, vs2_val[i]), + 16 => riscv_f32ToI16(rm_3b, vs2_val[i]), + 32 => riscv_f64ToI32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_F_XU => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_ui32ToF16(rm_3b, vs2_val[i]), + 32 => riscv_ui64ToF32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_F_X => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_i32ToF16(rm_3b, vs2_val[i]), + 32 => riscv_i64ToF32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_F_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f32ToF16(rm_3b, vs2_val[i]), + 32 => riscv_f64ToF32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_ROD_F_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f32ToF16(0b110, vs2_val[i]), + 32 => riscv_f64ToF32(0b110, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_RTZ_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToUi8(0b001, vs2_val[i]), + 16 => riscv_f32ToUi16(0b001, vs2_val[i]), + 32 => riscv_f64ToUi32(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_RTZ_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToI8(0b001, vs2_val[i]), + 16 => riscv_f32ToI16(0b001, vs2_val[i]), + 32 => riscv_f64ToI32(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfncvt.rtz.x.f.w.yaml b/arch/inst/V/vfncvt.rtz.x.f.w.yaml index d9cea28166..4ceb29ba6c 100644 --- a/arch/inst/V/vfncvt.rtz.x.f.w.yaml +++ b/arch/inst/V/vfncvt.rtz.x.f.w.yaml @@ -23,3 +23,116 @@ vfncvt.rtz.x.f.w: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfnunary0 { + FNV_CVT_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToUi8(rm_3b, vs2_val[i]), + 16 => riscv_f32ToUi16(rm_3b, vs2_val[i]), + 32 => riscv_f64ToUi32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToI8(rm_3b, vs2_val[i]), + 16 => riscv_f32ToI16(rm_3b, vs2_val[i]), + 32 => riscv_f64ToI32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_F_XU => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_ui32ToF16(rm_3b, vs2_val[i]), + 32 => riscv_ui64ToF32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_F_X => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_i32ToF16(rm_3b, vs2_val[i]), + 32 => riscv_i64ToF32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_F_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f32ToF16(rm_3b, vs2_val[i]), + 32 => riscv_f64ToF32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_ROD_F_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f32ToF16(0b110, vs2_val[i]), + 32 => riscv_f64ToF32(0b110, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_RTZ_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToUi8(0b001, vs2_val[i]), + 16 => riscv_f32ToUi16(0b001, vs2_val[i]), + 32 => riscv_f64ToUi32(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_RTZ_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToI8(0b001, vs2_val[i]), + 16 => riscv_f32ToI16(0b001, vs2_val[i]), + 32 => riscv_f64ToI32(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfncvt.rtz.xu.f.w.yaml b/arch/inst/V/vfncvt.rtz.xu.f.w.yaml index 3a48205ff4..a25996ab11 100644 --- a/arch/inst/V/vfncvt.rtz.xu.f.w.yaml +++ b/arch/inst/V/vfncvt.rtz.xu.f.w.yaml @@ -23,3 +23,116 @@ vfncvt.rtz.xu.f.w: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfnunary0 { + FNV_CVT_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToUi8(rm_3b, vs2_val[i]), + 16 => riscv_f32ToUi16(rm_3b, vs2_val[i]), + 32 => riscv_f64ToUi32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToI8(rm_3b, vs2_val[i]), + 16 => riscv_f32ToI16(rm_3b, vs2_val[i]), + 32 => riscv_f64ToI32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_F_XU => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_ui32ToF16(rm_3b, vs2_val[i]), + 32 => riscv_ui64ToF32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_F_X => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_i32ToF16(rm_3b, vs2_val[i]), + 32 => riscv_i64ToF32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_F_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f32ToF16(rm_3b, vs2_val[i]), + 32 => riscv_f64ToF32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_ROD_F_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f32ToF16(0b110, vs2_val[i]), + 32 => riscv_f64ToF32(0b110, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_RTZ_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToUi8(0b001, vs2_val[i]), + 16 => riscv_f32ToUi16(0b001, vs2_val[i]), + 32 => riscv_f64ToUi32(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_RTZ_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToI8(0b001, vs2_val[i]), + 16 => riscv_f32ToI16(0b001, vs2_val[i]), + 32 => riscv_f64ToI32(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfncvt.x.f.w.yaml b/arch/inst/V/vfncvt.x.f.w.yaml index b34d2010d0..b68d0807c8 100644 --- a/arch/inst/V/vfncvt.x.f.w.yaml +++ b/arch/inst/V/vfncvt.x.f.w.yaml @@ -23,3 +23,116 @@ vfncvt.x.f.w: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfnunary0 { + FNV_CVT_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToUi8(rm_3b, vs2_val[i]), + 16 => riscv_f32ToUi16(rm_3b, vs2_val[i]), + 32 => riscv_f64ToUi32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToI8(rm_3b, vs2_val[i]), + 16 => riscv_f32ToI16(rm_3b, vs2_val[i]), + 32 => riscv_f64ToI32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_F_XU => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_ui32ToF16(rm_3b, vs2_val[i]), + 32 => riscv_ui64ToF32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_F_X => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_i32ToF16(rm_3b, vs2_val[i]), + 32 => riscv_i64ToF32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_F_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f32ToF16(rm_3b, vs2_val[i]), + 32 => riscv_f64ToF32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_ROD_F_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f32ToF16(0b110, vs2_val[i]), + 32 => riscv_f64ToF32(0b110, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_RTZ_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToUi8(0b001, vs2_val[i]), + 16 => riscv_f32ToUi16(0b001, vs2_val[i]), + 32 => riscv_f64ToUi32(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_RTZ_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToI8(0b001, vs2_val[i]), + 16 => riscv_f32ToI16(0b001, vs2_val[i]), + 32 => riscv_f64ToI32(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfncvt.xu.f.w.yaml b/arch/inst/V/vfncvt.xu.f.w.yaml index bdb7ff9333..17851a4281 100644 --- a/arch/inst/V/vfncvt.xu.f.w.yaml +++ b/arch/inst/V/vfncvt.xu.f.w.yaml @@ -23,3 +23,116 @@ vfncvt.xu.f.w: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfnunary0 { + FNV_CVT_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToUi8(rm_3b, vs2_val[i]), + 16 => riscv_f32ToUi16(rm_3b, vs2_val[i]), + 32 => riscv_f64ToUi32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToI8(rm_3b, vs2_val[i]), + 16 => riscv_f32ToI16(rm_3b, vs2_val[i]), + 32 => riscv_f64ToI32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_F_XU => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_ui32ToF16(rm_3b, vs2_val[i]), + 32 => riscv_ui64ToF32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_F_X => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_i32ToF16(rm_3b, vs2_val[i]), + 32 => riscv_i64ToF32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_F_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f32ToF16(rm_3b, vs2_val[i]), + 32 => riscv_f64ToF32(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_ROD_F_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f32ToF16(0b110, vs2_val[i]), + 32 => riscv_f64ToF32(0b110, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_RTZ_XU_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToUi8(0b001, vs2_val[i]), + 16 => riscv_f32ToUi16(0b001, vs2_val[i]), + 32 => riscv_f64ToUi32(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FNV_CVT_RTZ_X_F => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 8 => riscv_f16ToI8(0b001, vs2_val[i]), + 16 => riscv_f32ToI16(0b001, vs2_val[i]), + 32 => riscv_f64ToI32(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfnmacc.vf.yaml b/arch/inst/V/vfnmacc.vf.yaml index fe8f90e763..2a95d27f36 100644 --- a/arch/inst/V/vfnmacc.vf.yaml +++ b/arch/inst/V/vfnmacc.vf.yaml @@ -25,3 +25,49 @@ vfnmacc.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VF_VMACC => fp_muladd(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VNMACC => fp_nmulsub(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VMSAC => fp_mulsub(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VNMSAC => fp_nmuladd(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VMADD => fp_muladd(rm_3b, rs1_val, vd_val[i], vs2_val[i]), + VF_VNMADD => fp_nmulsub(rm_3b, rs1_val, vd_val[i], vs2_val[i]), + VF_VMSUB => fp_mulsub(rm_3b, rs1_val, vd_val[i], vs2_val[i]), + VF_VNMSUB => fp_nmuladd(rm_3b, rs1_val, vd_val[i], vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfnmacc.vv.yaml b/arch/inst/V/vfnmacc.vv.yaml index 6cf80a8454..6c1b7c59d3 100644 --- a/arch/inst/V/vfnmacc.vv.yaml +++ b/arch/inst/V/vfnmacc.vv.yaml @@ -25,3 +25,49 @@ vfnmacc.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FVV_VMACC => fp_muladd(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VNMACC => fp_nmulsub(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VMSAC => fp_mulsub(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VNMSAC => fp_nmuladd(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VMADD => fp_muladd(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]), + FVV_VNMADD => fp_nmulsub(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]), + FVV_VMSUB => fp_mulsub(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]), + FVV_VNMSUB => fp_nmuladd(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfnmadd.vf.yaml b/arch/inst/V/vfnmadd.vf.yaml index f38e836f25..98ef7293cd 100644 --- a/arch/inst/V/vfnmadd.vf.yaml +++ b/arch/inst/V/vfnmadd.vf.yaml @@ -25,3 +25,49 @@ vfnmadd.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VF_VMACC => fp_muladd(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VNMACC => fp_nmulsub(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VMSAC => fp_mulsub(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VNMSAC => fp_nmuladd(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VMADD => fp_muladd(rm_3b, rs1_val, vd_val[i], vs2_val[i]), + VF_VNMADD => fp_nmulsub(rm_3b, rs1_val, vd_val[i], vs2_val[i]), + VF_VMSUB => fp_mulsub(rm_3b, rs1_val, vd_val[i], vs2_val[i]), + VF_VNMSUB => fp_nmuladd(rm_3b, rs1_val, vd_val[i], vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfnmadd.vv.yaml b/arch/inst/V/vfnmadd.vv.yaml index d064222260..d65226d9db 100644 --- a/arch/inst/V/vfnmadd.vv.yaml +++ b/arch/inst/V/vfnmadd.vv.yaml @@ -25,3 +25,49 @@ vfnmadd.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FVV_VMACC => fp_muladd(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VNMACC => fp_nmulsub(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VMSAC => fp_mulsub(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VNMSAC => fp_nmuladd(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VMADD => fp_muladd(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]), + FVV_VNMADD => fp_nmulsub(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]), + FVV_VMSUB => fp_mulsub(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]), + FVV_VNMSUB => fp_nmuladd(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfnmsac.vf.yaml b/arch/inst/V/vfnmsac.vf.yaml index 2329421041..8f1f772f7a 100644 --- a/arch/inst/V/vfnmsac.vf.yaml +++ b/arch/inst/V/vfnmsac.vf.yaml @@ -25,3 +25,49 @@ vfnmsac.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VF_VMACC => fp_muladd(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VNMACC => fp_nmulsub(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VMSAC => fp_mulsub(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VNMSAC => fp_nmuladd(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VMADD => fp_muladd(rm_3b, rs1_val, vd_val[i], vs2_val[i]), + VF_VNMADD => fp_nmulsub(rm_3b, rs1_val, vd_val[i], vs2_val[i]), + VF_VMSUB => fp_mulsub(rm_3b, rs1_val, vd_val[i], vs2_val[i]), + VF_VNMSUB => fp_nmuladd(rm_3b, rs1_val, vd_val[i], vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfnmsac.vv.yaml b/arch/inst/V/vfnmsac.vv.yaml index 0572a64fa5..34b3c427e7 100644 --- a/arch/inst/V/vfnmsac.vv.yaml +++ b/arch/inst/V/vfnmsac.vv.yaml @@ -25,3 +25,49 @@ vfnmsac.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FVV_VMACC => fp_muladd(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VNMACC => fp_nmulsub(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VMSAC => fp_mulsub(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VNMSAC => fp_nmuladd(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VMADD => fp_muladd(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]), + FVV_VNMADD => fp_nmulsub(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]), + FVV_VMSUB => fp_mulsub(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]), + FVV_VNMSUB => fp_nmuladd(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfnmsub.vf.yaml b/arch/inst/V/vfnmsub.vf.yaml index c5cebdddf2..1e0eba053b 100644 --- a/arch/inst/V/vfnmsub.vf.yaml +++ b/arch/inst/V/vfnmsub.vf.yaml @@ -25,3 +25,49 @@ vfnmsub.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VF_VMACC => fp_muladd(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VNMACC => fp_nmulsub(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VMSAC => fp_mulsub(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VNMSAC => fp_nmuladd(rm_3b, rs1_val, vs2_val[i], vd_val[i]), + VF_VMADD => fp_muladd(rm_3b, rs1_val, vd_val[i], vs2_val[i]), + VF_VNMADD => fp_nmulsub(rm_3b, rs1_val, vd_val[i], vs2_val[i]), + VF_VMSUB => fp_mulsub(rm_3b, rs1_val, vd_val[i], vs2_val[i]), + VF_VNMSUB => fp_nmuladd(rm_3b, rs1_val, vd_val[i], vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfnmsub.vv.yaml b/arch/inst/V/vfnmsub.vv.yaml index ca66af64fa..ef07500191 100644 --- a/arch/inst/V/vfnmsub.vv.yaml +++ b/arch/inst/V/vfnmsub.vv.yaml @@ -25,3 +25,49 @@ vfnmsub.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FVV_VMACC => fp_muladd(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VNMACC => fp_nmulsub(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VMSAC => fp_mulsub(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VNMSAC => fp_nmuladd(rm_3b, vs1_val[i], vs2_val[i], vd_val[i]), + FVV_VMADD => fp_muladd(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]), + FVV_VNMADD => fp_nmulsub(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]), + FVV_VMSUB => fp_mulsub(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]), + FVV_VNMSUB => fp_nmuladd(rm_3b, vs1_val[i], vd_val[i], vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfrdiv.vf.yaml b/arch/inst/V/vfrdiv.vf.yaml index 7baf01f175..a4c21768f4 100644 --- a/arch/inst/V/vfrdiv.vf.yaml +++ b/arch/inst/V/vfrdiv.vf.yaml @@ -25,3 +25,61 @@ vfrdiv.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VF_VADD => fp_add(rm_3b, vs2_val[i], rs1_val), + VF_VSUB => fp_sub(rm_3b, vs2_val[i], rs1_val), + VF_VRSUB => fp_sub(rm_3b, rs1_val, vs2_val[i]), + VF_VMIN => fp_min(vs2_val[i], rs1_val), + VF_VMAX => fp_max(vs2_val[i], rs1_val), + VF_VMUL => fp_mul(rm_3b, vs2_val[i], rs1_val), + VF_VDIV => fp_div(rm_3b, vs2_val[i], rs1_val), + VF_VRDIV => fp_div(rm_3b, rs1_val, vs2_val[i]), + VF_VSGNJ => [rs1_val['m - 1]] @ vs2_val[i][('m - 2)..0], + VF_VSGNJN => (0b1 ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSGNJX => ([vs2_val[i]['m - 1]] ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSLIDE1UP => { + if vs2 == vd then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + VF_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfrec7.v.yaml b/arch/inst/V/vfrec7.v.yaml index 9cfe950d1f..bd0f9ba98f 100644 --- a/arch/inst/V/vfrec7.v.yaml +++ b/arch/inst/V/vfrec7.v.yaml @@ -23,3 +23,68 @@ vfrec7.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfunary1 { + FVV_VSQRT => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16Sqrt(rm_3b, vs2_val[i]), + 32 => riscv_f32Sqrt(rm_3b, vs2_val[i]), + 64 => riscv_f64Sqrt(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FVV_VRSQRT7 => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16Rsqrte7(rm_3b, vs2_val[i]), + 32 => riscv_f32Rsqrte7(rm_3b, vs2_val[i]), + 64 => riscv_f64Rsqrte7(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FVV_VREC7 => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16Recip7(rm_3b, vs2_val[i]), + 32 => riscv_f32Recip7(rm_3b, vs2_val[i]), + 64 => riscv_f64Recip7(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FVV_VCLASS => fp_class(vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfredmax.vs.yaml b/arch/inst/V/vfredmax.vs.yaml index c33e9b886f..43bb68772d 100644 --- a/arch/inst/V/vfredmax.vs.yaml +++ b/arch/inst/V/vfredmax.vs.yaml @@ -25,3 +25,19 @@ vfredmax.vs: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem_vs = get_num_elem(LMUL_pow, SEW); + + if funct6 == FVV_VFWREDOSUM | funct6 == FVV_VFWREDUSUM then + process_rfvv_widen(funct6, vm, vs2, vs1, vd, num_elem_vs, SEW, LMUL_pow) + else + process_rfvv_single(funct6, vm, vs2, vs1, vd, num_elem_vs, SEW, LMUL_pow) + } + + \ No newline at end of file diff --git a/arch/inst/V/vfredmin.vs.yaml b/arch/inst/V/vfredmin.vs.yaml index a5e952a227..1e9a6b5326 100644 --- a/arch/inst/V/vfredmin.vs.yaml +++ b/arch/inst/V/vfredmin.vs.yaml @@ -25,3 +25,19 @@ vfredmin.vs: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem_vs = get_num_elem(LMUL_pow, SEW); + + if funct6 == FVV_VFWREDOSUM | funct6 == FVV_VFWREDUSUM then + process_rfvv_widen(funct6, vm, vs2, vs1, vd, num_elem_vs, SEW, LMUL_pow) + else + process_rfvv_single(funct6, vm, vs2, vs1, vd, num_elem_vs, SEW, LMUL_pow) + } + + \ No newline at end of file diff --git a/arch/inst/V/vfredosum.vs.yaml b/arch/inst/V/vfredosum.vs.yaml index 92a657cffd..8f50e26ba2 100644 --- a/arch/inst/V/vfredosum.vs.yaml +++ b/arch/inst/V/vfredosum.vs.yaml @@ -25,3 +25,19 @@ vfredosum.vs: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem_vs = get_num_elem(LMUL_pow, SEW); + + if funct6 == FVV_VFWREDOSUM | funct6 == FVV_VFWREDUSUM then + process_rfvv_widen(funct6, vm, vs2, vs1, vd, num_elem_vs, SEW, LMUL_pow) + else + process_rfvv_single(funct6, vm, vs2, vs1, vd, num_elem_vs, SEW, LMUL_pow) + } + + \ No newline at end of file diff --git a/arch/inst/V/vfredusum.vs.yaml b/arch/inst/V/vfredusum.vs.yaml index 27594be77c..4ed77f9857 100644 --- a/arch/inst/V/vfredusum.vs.yaml +++ b/arch/inst/V/vfredusum.vs.yaml @@ -25,3 +25,19 @@ vfredusum.vs: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem_vs = get_num_elem(LMUL_pow, SEW); + + if funct6 == FVV_VFWREDOSUM | funct6 == FVV_VFWREDUSUM then + process_rfvv_widen(funct6, vm, vs2, vs1, vd, num_elem_vs, SEW, LMUL_pow) + else + process_rfvv_single(funct6, vm, vs2, vs1, vd, num_elem_vs, SEW, LMUL_pow) + } + + \ No newline at end of file diff --git a/arch/inst/V/vfrsqrt7.v.yaml b/arch/inst/V/vfrsqrt7.v.yaml index 4ad9088864..6d2e9cbcb4 100644 --- a/arch/inst/V/vfrsqrt7.v.yaml +++ b/arch/inst/V/vfrsqrt7.v.yaml @@ -23,3 +23,68 @@ vfrsqrt7.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfunary1 { + FVV_VSQRT => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16Sqrt(rm_3b, vs2_val[i]), + 32 => riscv_f32Sqrt(rm_3b, vs2_val[i]), + 64 => riscv_f64Sqrt(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FVV_VRSQRT7 => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16Rsqrte7(rm_3b, vs2_val[i]), + 32 => riscv_f32Rsqrte7(rm_3b, vs2_val[i]), + 64 => riscv_f64Rsqrte7(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FVV_VREC7 => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16Recip7(rm_3b, vs2_val[i]), + 32 => riscv_f32Recip7(rm_3b, vs2_val[i]), + 64 => riscv_f64Recip7(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FVV_VCLASS => fp_class(vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfrsub.vf.yaml b/arch/inst/V/vfrsub.vf.yaml index cc3922ea28..03b57ee68e 100644 --- a/arch/inst/V/vfrsub.vf.yaml +++ b/arch/inst/V/vfrsub.vf.yaml @@ -25,3 +25,61 @@ vfrsub.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VF_VADD => fp_add(rm_3b, vs2_val[i], rs1_val), + VF_VSUB => fp_sub(rm_3b, vs2_val[i], rs1_val), + VF_VRSUB => fp_sub(rm_3b, rs1_val, vs2_val[i]), + VF_VMIN => fp_min(vs2_val[i], rs1_val), + VF_VMAX => fp_max(vs2_val[i], rs1_val), + VF_VMUL => fp_mul(rm_3b, vs2_val[i], rs1_val), + VF_VDIV => fp_div(rm_3b, vs2_val[i], rs1_val), + VF_VRDIV => fp_div(rm_3b, rs1_val, vs2_val[i]), + VF_VSGNJ => [rs1_val['m - 1]] @ vs2_val[i][('m - 2)..0], + VF_VSGNJN => (0b1 ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSGNJX => ([vs2_val[i]['m - 1]] ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSLIDE1UP => { + if vs2 == vd then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + VF_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfsgnj.vf.yaml b/arch/inst/V/vfsgnj.vf.yaml index 6f9d6dcc09..aa412fa06f 100644 --- a/arch/inst/V/vfsgnj.vf.yaml +++ b/arch/inst/V/vfsgnj.vf.yaml @@ -25,3 +25,61 @@ vfsgnj.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VF_VADD => fp_add(rm_3b, vs2_val[i], rs1_val), + VF_VSUB => fp_sub(rm_3b, vs2_val[i], rs1_val), + VF_VRSUB => fp_sub(rm_3b, rs1_val, vs2_val[i]), + VF_VMIN => fp_min(vs2_val[i], rs1_val), + VF_VMAX => fp_max(vs2_val[i], rs1_val), + VF_VMUL => fp_mul(rm_3b, vs2_val[i], rs1_val), + VF_VDIV => fp_div(rm_3b, vs2_val[i], rs1_val), + VF_VRDIV => fp_div(rm_3b, rs1_val, vs2_val[i]), + VF_VSGNJ => [rs1_val['m - 1]] @ vs2_val[i][('m - 2)..0], + VF_VSGNJN => (0b1 ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSGNJX => ([vs2_val[i]['m - 1]] ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSLIDE1UP => { + if vs2 == vd then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + VF_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfsgnj.vv.yaml b/arch/inst/V/vfsgnj.vv.yaml index a9cdefe0ee..3cb6886fa4 100644 --- a/arch/inst/V/vfsgnj.vv.yaml +++ b/arch/inst/V/vfsgnj.vv.yaml @@ -25,3 +25,50 @@ vfsgnj.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FVV_VADD => fp_add(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VSUB => fp_sub(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VMIN => fp_min(vs2_val[i], vs1_val[i]), + FVV_VMAX => fp_max(vs2_val[i], vs1_val[i]), + FVV_VMUL => fp_mul(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VDIV => fp_div(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VSGNJ => [vs1_val[i]['m - 1]] @ vs2_val[i][('m - 2)..0], + FVV_VSGNJN => (0b1 ^ [vs1_val[i]['m - 1]]) @ vs2_val[i][('m - 2)..0], + FVV_VSGNJX => ([vs2_val[i]['m - 1]] ^ [vs1_val[i]['m - 1]]) @ vs2_val[i][('m - 2)..0] + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfsgnjn.vf.yaml b/arch/inst/V/vfsgnjn.vf.yaml index c7a9da43fc..1f71c02c5a 100644 --- a/arch/inst/V/vfsgnjn.vf.yaml +++ b/arch/inst/V/vfsgnjn.vf.yaml @@ -25,3 +25,61 @@ vfsgnjn.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VF_VADD => fp_add(rm_3b, vs2_val[i], rs1_val), + VF_VSUB => fp_sub(rm_3b, vs2_val[i], rs1_val), + VF_VRSUB => fp_sub(rm_3b, rs1_val, vs2_val[i]), + VF_VMIN => fp_min(vs2_val[i], rs1_val), + VF_VMAX => fp_max(vs2_val[i], rs1_val), + VF_VMUL => fp_mul(rm_3b, vs2_val[i], rs1_val), + VF_VDIV => fp_div(rm_3b, vs2_val[i], rs1_val), + VF_VRDIV => fp_div(rm_3b, rs1_val, vs2_val[i]), + VF_VSGNJ => [rs1_val['m - 1]] @ vs2_val[i][('m - 2)..0], + VF_VSGNJN => (0b1 ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSGNJX => ([vs2_val[i]['m - 1]] ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSLIDE1UP => { + if vs2 == vd then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + VF_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfsgnjn.vv.yaml b/arch/inst/V/vfsgnjn.vv.yaml index 8050a5d679..cecb072336 100644 --- a/arch/inst/V/vfsgnjn.vv.yaml +++ b/arch/inst/V/vfsgnjn.vv.yaml @@ -25,3 +25,50 @@ vfsgnjn.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FVV_VADD => fp_add(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VSUB => fp_sub(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VMIN => fp_min(vs2_val[i], vs1_val[i]), + FVV_VMAX => fp_max(vs2_val[i], vs1_val[i]), + FVV_VMUL => fp_mul(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VDIV => fp_div(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VSGNJ => [vs1_val[i]['m - 1]] @ vs2_val[i][('m - 2)..0], + FVV_VSGNJN => (0b1 ^ [vs1_val[i]['m - 1]]) @ vs2_val[i][('m - 2)..0], + FVV_VSGNJX => ([vs2_val[i]['m - 1]] ^ [vs1_val[i]['m - 1]]) @ vs2_val[i][('m - 2)..0] + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfsgnjx.vf.yaml b/arch/inst/V/vfsgnjx.vf.yaml index 00447e9a3e..7cdab97852 100644 --- a/arch/inst/V/vfsgnjx.vf.yaml +++ b/arch/inst/V/vfsgnjx.vf.yaml @@ -25,3 +25,61 @@ vfsgnjx.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VF_VADD => fp_add(rm_3b, vs2_val[i], rs1_val), + VF_VSUB => fp_sub(rm_3b, vs2_val[i], rs1_val), + VF_VRSUB => fp_sub(rm_3b, rs1_val, vs2_val[i]), + VF_VMIN => fp_min(vs2_val[i], rs1_val), + VF_VMAX => fp_max(vs2_val[i], rs1_val), + VF_VMUL => fp_mul(rm_3b, vs2_val[i], rs1_val), + VF_VDIV => fp_div(rm_3b, vs2_val[i], rs1_val), + VF_VRDIV => fp_div(rm_3b, rs1_val, vs2_val[i]), + VF_VSGNJ => [rs1_val['m - 1]] @ vs2_val[i][('m - 2)..0], + VF_VSGNJN => (0b1 ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSGNJX => ([vs2_val[i]['m - 1]] ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSLIDE1UP => { + if vs2 == vd then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + VF_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfsgnjx.vv.yaml b/arch/inst/V/vfsgnjx.vv.yaml index cf120d653b..041fd01260 100644 --- a/arch/inst/V/vfsgnjx.vv.yaml +++ b/arch/inst/V/vfsgnjx.vv.yaml @@ -25,3 +25,50 @@ vfsgnjx.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FVV_VADD => fp_add(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VSUB => fp_sub(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VMIN => fp_min(vs2_val[i], vs1_val[i]), + FVV_VMAX => fp_max(vs2_val[i], vs1_val[i]), + FVV_VMUL => fp_mul(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VDIV => fp_div(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VSGNJ => [vs1_val[i]['m - 1]] @ vs2_val[i][('m - 2)..0], + FVV_VSGNJN => (0b1 ^ [vs1_val[i]['m - 1]]) @ vs2_val[i][('m - 2)..0], + FVV_VSGNJX => ([vs2_val[i]['m - 1]] ^ [vs1_val[i]['m - 1]]) @ vs2_val[i][('m - 2)..0] + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfslide1down.vf.yaml b/arch/inst/V/vfslide1down.vf.yaml index 64ceb7919d..6f54214e88 100644 --- a/arch/inst/V/vfslide1down.vf.yaml +++ b/arch/inst/V/vfslide1down.vf.yaml @@ -25,3 +25,61 @@ vfslide1down.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VF_VADD => fp_add(rm_3b, vs2_val[i], rs1_val), + VF_VSUB => fp_sub(rm_3b, vs2_val[i], rs1_val), + VF_VRSUB => fp_sub(rm_3b, rs1_val, vs2_val[i]), + VF_VMIN => fp_min(vs2_val[i], rs1_val), + VF_VMAX => fp_max(vs2_val[i], rs1_val), + VF_VMUL => fp_mul(rm_3b, vs2_val[i], rs1_val), + VF_VDIV => fp_div(rm_3b, vs2_val[i], rs1_val), + VF_VRDIV => fp_div(rm_3b, rs1_val, vs2_val[i]), + VF_VSGNJ => [rs1_val['m - 1]] @ vs2_val[i][('m - 2)..0], + VF_VSGNJN => (0b1 ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSGNJX => ([vs2_val[i]['m - 1]] ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSLIDE1UP => { + if vs2 == vd then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + VF_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfslide1up.vf.yaml b/arch/inst/V/vfslide1up.vf.yaml index 4b69edb6fd..991c6f8b0c 100644 --- a/arch/inst/V/vfslide1up.vf.yaml +++ b/arch/inst/V/vfslide1up.vf.yaml @@ -25,3 +25,61 @@ vfslide1up.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VF_VADD => fp_add(rm_3b, vs2_val[i], rs1_val), + VF_VSUB => fp_sub(rm_3b, vs2_val[i], rs1_val), + VF_VRSUB => fp_sub(rm_3b, rs1_val, vs2_val[i]), + VF_VMIN => fp_min(vs2_val[i], rs1_val), + VF_VMAX => fp_max(vs2_val[i], rs1_val), + VF_VMUL => fp_mul(rm_3b, vs2_val[i], rs1_val), + VF_VDIV => fp_div(rm_3b, vs2_val[i], rs1_val), + VF_VRDIV => fp_div(rm_3b, rs1_val, vs2_val[i]), + VF_VSGNJ => [rs1_val['m - 1]] @ vs2_val[i][('m - 2)..0], + VF_VSGNJN => (0b1 ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSGNJX => ([vs2_val[i]['m - 1]] ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSLIDE1UP => { + if vs2 == vd then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + VF_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfsqrt.v.yaml b/arch/inst/V/vfsqrt.v.yaml index 0b3a165932..b99ea4ac0e 100644 --- a/arch/inst/V/vfsqrt.v.yaml +++ b/arch/inst/V/vfsqrt.v.yaml @@ -23,3 +23,68 @@ vfsqrt.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfunary1 { + FVV_VSQRT => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16Sqrt(rm_3b, vs2_val[i]), + 32 => riscv_f32Sqrt(rm_3b, vs2_val[i]), + 64 => riscv_f64Sqrt(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FVV_VRSQRT7 => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16Rsqrte7(rm_3b, vs2_val[i]), + 32 => riscv_f32Rsqrte7(rm_3b, vs2_val[i]), + 64 => riscv_f64Rsqrte7(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FVV_VREC7 => { + let (fflags, elem) : (bits_fflags, bits('m)) = match 'm { + 16 => riscv_f16Recip7(rm_3b, vs2_val[i]), + 32 => riscv_f32Recip7(rm_3b, vs2_val[i]), + 64 => riscv_f64Recip7(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FVV_VCLASS => fp_class(vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfsub.vf.yaml b/arch/inst/V/vfsub.vf.yaml index 0b46b0e109..834f59c418 100644 --- a/arch/inst/V/vfsub.vf.yaml +++ b/arch/inst/V/vfsub.vf.yaml @@ -25,3 +25,61 @@ vfsub.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VF_VADD => fp_add(rm_3b, vs2_val[i], rs1_val), + VF_VSUB => fp_sub(rm_3b, vs2_val[i], rs1_val), + VF_VRSUB => fp_sub(rm_3b, rs1_val, vs2_val[i]), + VF_VMIN => fp_min(vs2_val[i], rs1_val), + VF_VMAX => fp_max(vs2_val[i], rs1_val), + VF_VMUL => fp_mul(rm_3b, vs2_val[i], rs1_val), + VF_VDIV => fp_div(rm_3b, vs2_val[i], rs1_val), + VF_VRDIV => fp_div(rm_3b, rs1_val, vs2_val[i]), + VF_VSGNJ => [rs1_val['m - 1]] @ vs2_val[i][('m - 2)..0], + VF_VSGNJN => (0b1 ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSGNJX => ([vs2_val[i]['m - 1]] ^ [rs1_val['m - 1]]) @ vs2_val[i][('m - 2)..0], + VF_VSLIDE1UP => { + if vs2 == vd then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + VF_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfsub.vv.yaml b/arch/inst/V/vfsub.vv.yaml index 8df44fcfff..f9ac5b4a67 100644 --- a/arch/inst/V/vfsub.vv.yaml +++ b/arch/inst/V/vfsub.vv.yaml @@ -25,3 +25,50 @@ vfsub.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_normal(vd, vm, SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FVV_VADD => fp_add(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VSUB => fp_sub(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VMIN => fp_min(vs2_val[i], vs1_val[i]), + FVV_VMAX => fp_max(vs2_val[i], vs1_val[i]), + FVV_VMUL => fp_mul(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VDIV => fp_div(rm_3b, vs2_val[i], vs1_val[i]), + FVV_VSGNJ => [vs1_val[i]['m - 1]] @ vs2_val[i][('m - 2)..0], + FVV_VSGNJN => (0b1 ^ [vs1_val[i]['m - 1]]) @ vs2_val[i][('m - 2)..0], + FVV_VSGNJX => ([vs2_val[i]['m - 1]] ^ [vs1_val[i]['m - 1]]) @ vs2_val[i][('m - 2)..0] + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwadd.vf.yaml b/arch/inst/V/vfwadd.vf.yaml index 2ab38c0c71..79ad6a9ba6 100644 --- a/arch/inst/V/vfwadd.vf.yaml +++ b/arch/inst/V/vfwadd.vf.yaml @@ -25,3 +25,49 @@ vfwadd.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 16 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FWVF_VADD => fp_add(rm_3b, fp_widen(vs2_val[i]), fp_widen(rs1_val)), + FWVF_VSUB => fp_sub(rm_3b, fp_widen(vs2_val[i]), fp_widen(rs1_val)), + FWVF_VMUL => fp_mul(rm_3b, fp_widen(vs2_val[i]), fp_widen(rs1_val)) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwadd.vv.yaml b/arch/inst/V/vfwadd.vv.yaml index e207eab969..f50ec3e4a2 100644 --- a/arch/inst/V/vfwadd.vv.yaml +++ b/arch/inst/V/vfwadd.vv.yaml @@ -25,3 +25,50 @@ vfwadd.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 16 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FWVV_VADD => fp_add(rm_3b, fp_widen(vs2_val[i]), fp_widen(vs1_val[i])), + FWVV_VSUB => fp_sub(rm_3b, fp_widen(vs2_val[i]), fp_widen(vs1_val[i])), + FWVV_VMUL => fp_mul(rm_3b, fp_widen(vs2_val[i]), fp_widen(vs1_val[i])) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwadd.wf.yaml b/arch/inst/V/vfwadd.wf.yaml index a8f06dd042..78d5d9969f 100644 --- a/arch/inst/V/vfwadd.wf.yaml +++ b/arch/inst/V/vfwadd.wf.yaml @@ -25,3 +25,47 @@ vfwadd.wf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 16 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FWF_VADD => fp_add(rm_3b, vs2_val[i], fp_widen(rs1_val)), + FWF_VSUB => fp_sub(rm_3b, vs2_val[i], fp_widen(rs1_val)) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwadd.wv.yaml b/arch/inst/V/vfwadd.wv.yaml index 6d4f9f6a49..22db63d4f1 100644 --- a/arch/inst/V/vfwadd.wv.yaml +++ b/arch/inst/V/vfwadd.wv.yaml @@ -25,3 +25,48 @@ vfwadd.wv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 16 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FWV_VADD => fp_add(rm_3b, vs2_val[i], fp_widen(vs1_val[i])), + FWV_VSUB => fp_sub(rm_3b, vs2_val[i], fp_widen(vs1_val[i])) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwcvt.f.f.v.yaml b/arch/inst/V/vfwcvt.f.f.v.yaml index 11d76c44ea..a277c8de45 100644 --- a/arch/inst/V/vfwcvt.f.f.v.yaml +++ b/arch/inst/V/vfwcvt.f.f.v.yaml @@ -23,3 +23,108 @@ vfwcvt.f.f.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 8 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfwunary0 { + FWV_CVT_XU_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToUi32(rm_3b, vs2_val[i]), + 32 => riscv_f32ToUi64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_X_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToI32(rm_3b, vs2_val[i]), + 32 => riscv_f32ToI64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_F_XU => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => riscv_ui32ToF16(rm_3b, zero_extend(vs2_val[i])), + 16 => riscv_ui32ToF32(rm_3b, zero_extend(vs2_val[i])), + 32 => riscv_ui32ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_F_X => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => riscv_i32ToF16(rm_3b, sign_extend(vs2_val[i])), + 16 => riscv_i32ToF32(rm_3b, sign_extend(vs2_val[i])), + 32 => riscv_i32ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_F_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToF32(rm_3b, vs2_val[i]), + 32 => riscv_f32ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_RTZ_XU_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToUi32(0b001, vs2_val[i]), + 32 => riscv_f32ToUi64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_RTZ_X_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToI32(0b001, vs2_val[i]), + 32 => riscv_f32ToI64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + } + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwcvt.f.x.v.yaml b/arch/inst/V/vfwcvt.f.x.v.yaml index c4e018a55e..9390f80503 100644 --- a/arch/inst/V/vfwcvt.f.x.v.yaml +++ b/arch/inst/V/vfwcvt.f.x.v.yaml @@ -23,3 +23,108 @@ vfwcvt.f.x.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 8 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfwunary0 { + FWV_CVT_XU_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToUi32(rm_3b, vs2_val[i]), + 32 => riscv_f32ToUi64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_X_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToI32(rm_3b, vs2_val[i]), + 32 => riscv_f32ToI64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_F_XU => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => riscv_ui32ToF16(rm_3b, zero_extend(vs2_val[i])), + 16 => riscv_ui32ToF32(rm_3b, zero_extend(vs2_val[i])), + 32 => riscv_ui32ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_F_X => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => riscv_i32ToF16(rm_3b, sign_extend(vs2_val[i])), + 16 => riscv_i32ToF32(rm_3b, sign_extend(vs2_val[i])), + 32 => riscv_i32ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_F_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToF32(rm_3b, vs2_val[i]), + 32 => riscv_f32ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_RTZ_XU_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToUi32(0b001, vs2_val[i]), + 32 => riscv_f32ToUi64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_RTZ_X_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToI32(0b001, vs2_val[i]), + 32 => riscv_f32ToI64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + } + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwcvt.f.xu.v.yaml b/arch/inst/V/vfwcvt.f.xu.v.yaml index f23427b551..73c7f06be8 100644 --- a/arch/inst/V/vfwcvt.f.xu.v.yaml +++ b/arch/inst/V/vfwcvt.f.xu.v.yaml @@ -23,3 +23,108 @@ vfwcvt.f.xu.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 8 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfwunary0 { + FWV_CVT_XU_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToUi32(rm_3b, vs2_val[i]), + 32 => riscv_f32ToUi64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_X_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToI32(rm_3b, vs2_val[i]), + 32 => riscv_f32ToI64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_F_XU => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => riscv_ui32ToF16(rm_3b, zero_extend(vs2_val[i])), + 16 => riscv_ui32ToF32(rm_3b, zero_extend(vs2_val[i])), + 32 => riscv_ui32ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_F_X => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => riscv_i32ToF16(rm_3b, sign_extend(vs2_val[i])), + 16 => riscv_i32ToF32(rm_3b, sign_extend(vs2_val[i])), + 32 => riscv_i32ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_F_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToF32(rm_3b, vs2_val[i]), + 32 => riscv_f32ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_RTZ_XU_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToUi32(0b001, vs2_val[i]), + 32 => riscv_f32ToUi64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_RTZ_X_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToI32(0b001, vs2_val[i]), + 32 => riscv_f32ToI64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + } + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwcvt.rtz.x.f.v.yaml b/arch/inst/V/vfwcvt.rtz.x.f.v.yaml index 8b26dd3631..5eb9a02e26 100644 --- a/arch/inst/V/vfwcvt.rtz.x.f.v.yaml +++ b/arch/inst/V/vfwcvt.rtz.x.f.v.yaml @@ -23,3 +23,108 @@ vfwcvt.rtz.x.f.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 8 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfwunary0 { + FWV_CVT_XU_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToUi32(rm_3b, vs2_val[i]), + 32 => riscv_f32ToUi64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_X_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToI32(rm_3b, vs2_val[i]), + 32 => riscv_f32ToI64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_F_XU => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => riscv_ui32ToF16(rm_3b, zero_extend(vs2_val[i])), + 16 => riscv_ui32ToF32(rm_3b, zero_extend(vs2_val[i])), + 32 => riscv_ui32ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_F_X => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => riscv_i32ToF16(rm_3b, sign_extend(vs2_val[i])), + 16 => riscv_i32ToF32(rm_3b, sign_extend(vs2_val[i])), + 32 => riscv_i32ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_F_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToF32(rm_3b, vs2_val[i]), + 32 => riscv_f32ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_RTZ_XU_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToUi32(0b001, vs2_val[i]), + 32 => riscv_f32ToUi64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_RTZ_X_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToI32(0b001, vs2_val[i]), + 32 => riscv_f32ToI64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + } + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwcvt.rtz.xu.f.v.yaml b/arch/inst/V/vfwcvt.rtz.xu.f.v.yaml index 57f14cd53c..888ae2401a 100644 --- a/arch/inst/V/vfwcvt.rtz.xu.f.v.yaml +++ b/arch/inst/V/vfwcvt.rtz.xu.f.v.yaml @@ -23,3 +23,108 @@ vfwcvt.rtz.xu.f.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 8 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfwunary0 { + FWV_CVT_XU_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToUi32(rm_3b, vs2_val[i]), + 32 => riscv_f32ToUi64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_X_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToI32(rm_3b, vs2_val[i]), + 32 => riscv_f32ToI64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_F_XU => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => riscv_ui32ToF16(rm_3b, zero_extend(vs2_val[i])), + 16 => riscv_ui32ToF32(rm_3b, zero_extend(vs2_val[i])), + 32 => riscv_ui32ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_F_X => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => riscv_i32ToF16(rm_3b, sign_extend(vs2_val[i])), + 16 => riscv_i32ToF32(rm_3b, sign_extend(vs2_val[i])), + 32 => riscv_i32ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_F_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToF32(rm_3b, vs2_val[i]), + 32 => riscv_f32ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_RTZ_XU_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToUi32(0b001, vs2_val[i]), + 32 => riscv_f32ToUi64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_RTZ_X_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToI32(0b001, vs2_val[i]), + 32 => riscv_f32ToI64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + } + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwcvt.x.f.v.yaml b/arch/inst/V/vfwcvt.x.f.v.yaml index 7fd01569e3..c13cbcbdd6 100644 --- a/arch/inst/V/vfwcvt.x.f.v.yaml +++ b/arch/inst/V/vfwcvt.x.f.v.yaml @@ -23,3 +23,108 @@ vfwcvt.x.f.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 8 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfwunary0 { + FWV_CVT_XU_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToUi32(rm_3b, vs2_val[i]), + 32 => riscv_f32ToUi64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_X_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToI32(rm_3b, vs2_val[i]), + 32 => riscv_f32ToI64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_F_XU => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => riscv_ui32ToF16(rm_3b, zero_extend(vs2_val[i])), + 16 => riscv_ui32ToF32(rm_3b, zero_extend(vs2_val[i])), + 32 => riscv_ui32ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_F_X => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => riscv_i32ToF16(rm_3b, sign_extend(vs2_val[i])), + 16 => riscv_i32ToF32(rm_3b, sign_extend(vs2_val[i])), + 32 => riscv_i32ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_F_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToF32(rm_3b, vs2_val[i]), + 32 => riscv_f32ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_RTZ_XU_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToUi32(0b001, vs2_val[i]), + 32 => riscv_f32ToUi64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_RTZ_X_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToI32(0b001, vs2_val[i]), + 32 => riscv_f32ToI64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + } + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwcvt.xu.f.v.yaml b/arch/inst/V/vfwcvt.xu.f.v.yaml index 9fbed76068..494879e621 100644 --- a/arch/inst/V/vfwcvt.xu.f.v.yaml +++ b/arch/inst/V/vfwcvt.xu.f.v.yaml @@ -23,3 +23,108 @@ vfwcvt.xu.f.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 8 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match vfwunary0 { + FWV_CVT_XU_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToUi32(rm_3b, vs2_val[i]), + 32 => riscv_f32ToUi64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_X_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToI32(rm_3b, vs2_val[i]), + 32 => riscv_f32ToI64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_F_XU => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => riscv_ui32ToF16(rm_3b, zero_extend(vs2_val[i])), + 16 => riscv_ui32ToF32(rm_3b, zero_extend(vs2_val[i])), + 32 => riscv_ui32ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_F_X => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => riscv_i32ToF16(rm_3b, sign_extend(vs2_val[i])), + 16 => riscv_i32ToF32(rm_3b, sign_extend(vs2_val[i])), + 32 => riscv_i32ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_F_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToF32(rm_3b, vs2_val[i]), + 32 => riscv_f32ToF64(rm_3b, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_RTZ_XU_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToUi32(0b001, vs2_val[i]), + 32 => riscv_f32ToUi64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + }, + FWV_CVT_RTZ_X_F => { + let (fflags, elem) : (bits_fflags, bits('o)) = match 'm { + 8 => { handle_illegal(); return RETIRE_FAIL }, + 16 => riscv_f16ToI32(0b001, vs2_val[i]), + 32 => riscv_f32ToI64(0b001, vs2_val[i]) + }; + accrue_fflags(fflags); + elem + } + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwmacc.vf.yaml b/arch/inst/V/vfwmacc.vf.yaml index b72a09764b..a609c62825 100644 --- a/arch/inst/V/vfwmacc.vf.yaml +++ b/arch/inst/V/vfwmacc.vf.yaml @@ -25,3 +25,50 @@ vfwmacc.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 16 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FWVF_VMACC => fp_muladd(rm_3b, fp_widen(rs1_val), fp_widen(vs2_val[i]), vd_val[i]), + FWVF_VNMACC => fp_nmulsub(rm_3b, fp_widen(rs1_val), fp_widen(vs2_val[i]), vd_val[i]), + FWVF_VMSAC => fp_mulsub(rm_3b, fp_widen(rs1_val), fp_widen(vs2_val[i]), vd_val[i]), + FWVF_VNMSAC => fp_nmuladd(rm_3b, fp_widen(rs1_val), fp_widen(vs2_val[i]), vd_val[i]) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwmacc.vv.yaml b/arch/inst/V/vfwmacc.vv.yaml index 3b3954345f..4f1dd9ecad 100644 --- a/arch/inst/V/vfwmacc.vv.yaml +++ b/arch/inst/V/vfwmacc.vv.yaml @@ -25,3 +25,51 @@ vfwmacc.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 16 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FWVV_VMACC => fp_muladd(rm_3b, fp_widen(vs1_val[i]), fp_widen(vs2_val[i]), vd_val[i]), + FWVV_VNMACC => fp_nmulsub(rm_3b, fp_widen(vs1_val[i]), fp_widen(vs2_val[i]), vd_val[i]), + FWVV_VMSAC => fp_mulsub(rm_3b, fp_widen(vs1_val[i]), fp_widen(vs2_val[i]), vd_val[i]), + FWVV_VNMSAC => fp_nmuladd(rm_3b, fp_widen(vs1_val[i]), fp_widen(vs2_val[i]), vd_val[i]) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwmsac.vf.yaml b/arch/inst/V/vfwmsac.vf.yaml index 07ffd407e4..881af1e829 100644 --- a/arch/inst/V/vfwmsac.vf.yaml +++ b/arch/inst/V/vfwmsac.vf.yaml @@ -25,3 +25,50 @@ vfwmsac.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 16 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FWVF_VMACC => fp_muladd(rm_3b, fp_widen(rs1_val), fp_widen(vs2_val[i]), vd_val[i]), + FWVF_VNMACC => fp_nmulsub(rm_3b, fp_widen(rs1_val), fp_widen(vs2_val[i]), vd_val[i]), + FWVF_VMSAC => fp_mulsub(rm_3b, fp_widen(rs1_val), fp_widen(vs2_val[i]), vd_val[i]), + FWVF_VNMSAC => fp_nmuladd(rm_3b, fp_widen(rs1_val), fp_widen(vs2_val[i]), vd_val[i]) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwmsac.vv.yaml b/arch/inst/V/vfwmsac.vv.yaml index 8a180f5721..543e48d565 100644 --- a/arch/inst/V/vfwmsac.vv.yaml +++ b/arch/inst/V/vfwmsac.vv.yaml @@ -25,3 +25,51 @@ vfwmsac.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 16 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FWVV_VMACC => fp_muladd(rm_3b, fp_widen(vs1_val[i]), fp_widen(vs2_val[i]), vd_val[i]), + FWVV_VNMACC => fp_nmulsub(rm_3b, fp_widen(vs1_val[i]), fp_widen(vs2_val[i]), vd_val[i]), + FWVV_VMSAC => fp_mulsub(rm_3b, fp_widen(vs1_val[i]), fp_widen(vs2_val[i]), vd_val[i]), + FWVV_VNMSAC => fp_nmuladd(rm_3b, fp_widen(vs1_val[i]), fp_widen(vs2_val[i]), vd_val[i]) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwmul.vf.yaml b/arch/inst/V/vfwmul.vf.yaml index 619687bd09..b60450643b 100644 --- a/arch/inst/V/vfwmul.vf.yaml +++ b/arch/inst/V/vfwmul.vf.yaml @@ -25,3 +25,49 @@ vfwmul.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 16 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FWVF_VADD => fp_add(rm_3b, fp_widen(vs2_val[i]), fp_widen(rs1_val)), + FWVF_VSUB => fp_sub(rm_3b, fp_widen(vs2_val[i]), fp_widen(rs1_val)), + FWVF_VMUL => fp_mul(rm_3b, fp_widen(vs2_val[i]), fp_widen(rs1_val)) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwmul.vv.yaml b/arch/inst/V/vfwmul.vv.yaml index bd3c16fd07..7ee8a0bc31 100644 --- a/arch/inst/V/vfwmul.vv.yaml +++ b/arch/inst/V/vfwmul.vv.yaml @@ -25,3 +25,50 @@ vfwmul.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 16 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FWVV_VADD => fp_add(rm_3b, fp_widen(vs2_val[i]), fp_widen(vs1_val[i])), + FWVV_VSUB => fp_sub(rm_3b, fp_widen(vs2_val[i]), fp_widen(vs1_val[i])), + FWVV_VMUL => fp_mul(rm_3b, fp_widen(vs2_val[i]), fp_widen(vs1_val[i])) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwnmacc.vf.yaml b/arch/inst/V/vfwnmacc.vf.yaml index e77323e73d..e046e240a3 100644 --- a/arch/inst/V/vfwnmacc.vf.yaml +++ b/arch/inst/V/vfwnmacc.vf.yaml @@ -25,3 +25,50 @@ vfwnmacc.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 16 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FWVF_VMACC => fp_muladd(rm_3b, fp_widen(rs1_val), fp_widen(vs2_val[i]), vd_val[i]), + FWVF_VNMACC => fp_nmulsub(rm_3b, fp_widen(rs1_val), fp_widen(vs2_val[i]), vd_val[i]), + FWVF_VMSAC => fp_mulsub(rm_3b, fp_widen(rs1_val), fp_widen(vs2_val[i]), vd_val[i]), + FWVF_VNMSAC => fp_nmuladd(rm_3b, fp_widen(rs1_val), fp_widen(vs2_val[i]), vd_val[i]) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwnmacc.vv.yaml b/arch/inst/V/vfwnmacc.vv.yaml index 9ea5907b2a..b571cbbe55 100644 --- a/arch/inst/V/vfwnmacc.vv.yaml +++ b/arch/inst/V/vfwnmacc.vv.yaml @@ -25,3 +25,51 @@ vfwnmacc.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 16 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FWVV_VMACC => fp_muladd(rm_3b, fp_widen(vs1_val[i]), fp_widen(vs2_val[i]), vd_val[i]), + FWVV_VNMACC => fp_nmulsub(rm_3b, fp_widen(vs1_val[i]), fp_widen(vs2_val[i]), vd_val[i]), + FWVV_VMSAC => fp_mulsub(rm_3b, fp_widen(vs1_val[i]), fp_widen(vs2_val[i]), vd_val[i]), + FWVV_VNMSAC => fp_nmuladd(rm_3b, fp_widen(vs1_val[i]), fp_widen(vs2_val[i]), vd_val[i]) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwnmsac.vf.yaml b/arch/inst/V/vfwnmsac.vf.yaml index 6f9ac1ba75..45f6ef052c 100644 --- a/arch/inst/V/vfwnmsac.vf.yaml +++ b/arch/inst/V/vfwnmsac.vf.yaml @@ -25,3 +25,50 @@ vfwnmsac.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 16 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FWVF_VMACC => fp_muladd(rm_3b, fp_widen(rs1_val), fp_widen(vs2_val[i]), vd_val[i]), + FWVF_VNMACC => fp_nmulsub(rm_3b, fp_widen(rs1_val), fp_widen(vs2_val[i]), vd_val[i]), + FWVF_VMSAC => fp_mulsub(rm_3b, fp_widen(rs1_val), fp_widen(vs2_val[i]), vd_val[i]), + FWVF_VNMSAC => fp_nmuladd(rm_3b, fp_widen(rs1_val), fp_widen(vs2_val[i]), vd_val[i]) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwnmsac.vv.yaml b/arch/inst/V/vfwnmsac.vv.yaml index 69b7ec48cc..869687f1ca 100644 --- a/arch/inst/V/vfwnmsac.vv.yaml +++ b/arch/inst/V/vfwnmsac.vv.yaml @@ -25,3 +25,51 @@ vfwnmsac.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 16 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FWVV_VMACC => fp_muladd(rm_3b, fp_widen(vs1_val[i]), fp_widen(vs2_val[i]), vd_val[i]), + FWVV_VNMACC => fp_nmulsub(rm_3b, fp_widen(vs1_val[i]), fp_widen(vs2_val[i]), vd_val[i]), + FWVV_VMSAC => fp_mulsub(rm_3b, fp_widen(vs1_val[i]), fp_widen(vs2_val[i]), vd_val[i]), + FWVV_VNMSAC => fp_nmuladd(rm_3b, fp_widen(vs1_val[i]), fp_widen(vs2_val[i]), vd_val[i]) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwredosum.vs.yaml b/arch/inst/V/vfwredosum.vs.yaml index 90977566dc..de96d140ea 100644 --- a/arch/inst/V/vfwredosum.vs.yaml +++ b/arch/inst/V/vfwredosum.vs.yaml @@ -25,3 +25,19 @@ vfwredosum.vs: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem_vs = get_num_elem(LMUL_pow, SEW); + + if funct6 == FVV_VFWREDOSUM | funct6 == FVV_VFWREDUSUM then + process_rfvv_widen(funct6, vm, vs2, vs1, vd, num_elem_vs, SEW, LMUL_pow) + else + process_rfvv_single(funct6, vm, vs2, vs1, vd, num_elem_vs, SEW, LMUL_pow) + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwredusum.vs.yaml b/arch/inst/V/vfwredusum.vs.yaml index 260f07d653..2369716e29 100644 --- a/arch/inst/V/vfwredusum.vs.yaml +++ b/arch/inst/V/vfwredusum.vs.yaml @@ -25,3 +25,19 @@ vfwredusum.vs: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem_vs = get_num_elem(LMUL_pow, SEW); + + if funct6 == FVV_VFWREDOSUM | funct6 == FVV_VFWREDUSUM then + process_rfvv_widen(funct6, vm, vs2, vs1, vd, num_elem_vs, SEW, LMUL_pow) + else + process_rfvv_single(funct6, vm, vs2, vs1, vd, num_elem_vs, SEW, LMUL_pow) + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwsub.vf.yaml b/arch/inst/V/vfwsub.vf.yaml index 13f17b7561..d114fc5325 100644 --- a/arch/inst/V/vfwsub.vf.yaml +++ b/arch/inst/V/vfwsub.vf.yaml @@ -25,3 +25,49 @@ vfwsub.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 16 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FWVF_VADD => fp_add(rm_3b, fp_widen(vs2_val[i]), fp_widen(rs1_val)), + FWVF_VSUB => fp_sub(rm_3b, fp_widen(vs2_val[i]), fp_widen(rs1_val)), + FWVF_VMUL => fp_mul(rm_3b, fp_widen(vs2_val[i]), fp_widen(rs1_val)) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwsub.vv.yaml b/arch/inst/V/vfwsub.vv.yaml index c5465c6c94..11ab418e20 100644 --- a/arch/inst/V/vfwsub.vv.yaml +++ b/arch/inst/V/vfwsub.vv.yaml @@ -25,3 +25,50 @@ vfwsub.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 16 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FWVV_VADD => fp_add(rm_3b, fp_widen(vs2_val[i]), fp_widen(vs1_val[i])), + FWVV_VSUB => fp_sub(rm_3b, fp_widen(vs2_val[i]), fp_widen(vs1_val[i])), + FWVV_VMUL => fp_mul(rm_3b, fp_widen(vs2_val[i]), fp_widen(vs1_val[i])) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwsub.wf.yaml b/arch/inst/V/vfwsub.wf.yaml index eea2a4a6f7..709a2f1d50 100644 --- a/arch/inst/V/vfwsub.wf.yaml +++ b/arch/inst/V/vfwsub.wf.yaml @@ -25,3 +25,47 @@ vfwsub.wf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 16 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FWF_VADD => fp_add(rm_3b, vs2_val[i], fp_widen(rs1_val)), + FWF_VSUB => fp_sub(rm_3b, vs2_val[i], fp_widen(rs1_val)) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vfwsub.wv.yaml b/arch/inst/V/vfwsub.wv.yaml index 12bd81d576..9b892adf34 100644 --- a/arch/inst/V/vfwsub.wv.yaml +++ b/arch/inst/V/vfwsub.wv.yaml @@ -25,3 +25,48 @@ vfwsub.wv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_fp_variable_width(vd, vm, SEW, rm_3b, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW >= 16 & SEW_widen <= 64); + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + FWV_VADD => fp_add(rm_3b, vs2_val[i], fp_widen(vs1_val[i])), + FWV_VSUB => fp_sub(rm_3b, vs2_val[i], fp_widen(vs1_val[i])) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vid.v.yaml b/arch/inst/V/vid.v.yaml index 90818ac4e5..21e678852c 100644 --- a/arch/inst/V/vid.v.yaml +++ b/arch/inst/V/vid.v.yaml @@ -21,3 +21,34 @@ vid.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then result[i] = to_bits(SEW, i) + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/viota.m.yaml b/arch/inst/V/viota.m.yaml index e71f73f9b8..991de765e7 100644 --- a/arch/inst/V/viota.m.yaml +++ b/arch/inst/V/viota.m.yaml @@ -23,3 +23,40 @@ viota.m: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) | not(assert_vstart(0)) | vd == vs2 + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + sum : int = 0; + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = to_bits(SEW, sum); + if vs2_val[i] then sum = sum + 1 + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vle16.v.yaml b/arch/inst/V/vle16.v.yaml index 5d082010fd..7df0efe2e2 100644 --- a/arch/inst/V/vle16.v.yaml +++ b/arch/inst/V/vle16.v.yaml @@ -25,3 +25,23 @@ vle16.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let load_width_bytes = vlewidth_bytesnumber(width); + let EEW = load_width_bytes * 8; + let EEW_pow = vlewidth_pow(width); + let SEW_pow = get_sew_pow(); + let LMUL_pow = get_lmul_pow(); + let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow; + let num_elem = get_num_elem(EMUL_pow, EEW); /* # of element of each register group */ + let nf_int = nfields_int(nf); + + if illegal_load(vd, vm, nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vlseg(nf_int, vm, vd, load_width_bytes, rs1, EMUL_pow, num_elem) + } + + \ No newline at end of file diff --git a/arch/inst/V/vle16ff.v.yaml b/arch/inst/V/vle16ff.v.yaml index bf4aad0b17..4963b0bfea 100644 --- a/arch/inst/V/vle16ff.v.yaml +++ b/arch/inst/V/vle16ff.v.yaml @@ -25,3 +25,23 @@ vle16ff.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let load_width_bytes = vlewidth_bytesnumber(width); + let EEW = load_width_bytes * 8; + let EEW_pow = vlewidth_pow(width); + let SEW_pow = get_sew_pow(); + let LMUL_pow = get_lmul_pow(); + let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow; + let num_elem = get_num_elem(EMUL_pow, EEW); + let nf_int = nfields_int(nf); + + if illegal_load(vd, vm, nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vlsegff(nf_int, vm, vd, load_width_bytes, rs1, EMUL_pow, num_elem) + } + + \ No newline at end of file diff --git a/arch/inst/V/vle32.v.yaml b/arch/inst/V/vle32.v.yaml index 8a65ba9fa8..83bca92d82 100644 --- a/arch/inst/V/vle32.v.yaml +++ b/arch/inst/V/vle32.v.yaml @@ -25,3 +25,23 @@ vle32.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let load_width_bytes = vlewidth_bytesnumber(width); + let EEW = load_width_bytes * 8; + let EEW_pow = vlewidth_pow(width); + let SEW_pow = get_sew_pow(); + let LMUL_pow = get_lmul_pow(); + let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow; + let num_elem = get_num_elem(EMUL_pow, EEW); /* # of element of each register group */ + let nf_int = nfields_int(nf); + + if illegal_load(vd, vm, nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vlseg(nf_int, vm, vd, load_width_bytes, rs1, EMUL_pow, num_elem) + } + + \ No newline at end of file diff --git a/arch/inst/V/vle32ff.v.yaml b/arch/inst/V/vle32ff.v.yaml index 6ba83d8327..22edda6ee1 100644 --- a/arch/inst/V/vle32ff.v.yaml +++ b/arch/inst/V/vle32ff.v.yaml @@ -25,3 +25,23 @@ vle32ff.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let load_width_bytes = vlewidth_bytesnumber(width); + let EEW = load_width_bytes * 8; + let EEW_pow = vlewidth_pow(width); + let SEW_pow = get_sew_pow(); + let LMUL_pow = get_lmul_pow(); + let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow; + let num_elem = get_num_elem(EMUL_pow, EEW); + let nf_int = nfields_int(nf); + + if illegal_load(vd, vm, nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vlsegff(nf_int, vm, vd, load_width_bytes, rs1, EMUL_pow, num_elem) + } + + \ No newline at end of file diff --git a/arch/inst/V/vle64.v.yaml b/arch/inst/V/vle64.v.yaml index 46eab350c7..24f7700e8b 100644 --- a/arch/inst/V/vle64.v.yaml +++ b/arch/inst/V/vle64.v.yaml @@ -25,3 +25,23 @@ vle64.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let load_width_bytes = vlewidth_bytesnumber(width); + let EEW = load_width_bytes * 8; + let EEW_pow = vlewidth_pow(width); + let SEW_pow = get_sew_pow(); + let LMUL_pow = get_lmul_pow(); + let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow; + let num_elem = get_num_elem(EMUL_pow, EEW); /* # of element of each register group */ + let nf_int = nfields_int(nf); + + if illegal_load(vd, vm, nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vlseg(nf_int, vm, vd, load_width_bytes, rs1, EMUL_pow, num_elem) + } + + \ No newline at end of file diff --git a/arch/inst/V/vle64ff.v.yaml b/arch/inst/V/vle64ff.v.yaml index 164c822494..b64121b66e 100644 --- a/arch/inst/V/vle64ff.v.yaml +++ b/arch/inst/V/vle64ff.v.yaml @@ -25,3 +25,23 @@ vle64ff.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let load_width_bytes = vlewidth_bytesnumber(width); + let EEW = load_width_bytes * 8; + let EEW_pow = vlewidth_pow(width); + let SEW_pow = get_sew_pow(); + let LMUL_pow = get_lmul_pow(); + let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow; + let num_elem = get_num_elem(EMUL_pow, EEW); + let nf_int = nfields_int(nf); + + if illegal_load(vd, vm, nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vlsegff(nf_int, vm, vd, load_width_bytes, rs1, EMUL_pow, num_elem) + } + + \ No newline at end of file diff --git a/arch/inst/V/vle8.v.yaml b/arch/inst/V/vle8.v.yaml index db5720a240..67939025cc 100644 --- a/arch/inst/V/vle8.v.yaml +++ b/arch/inst/V/vle8.v.yaml @@ -25,3 +25,23 @@ vle8.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let load_width_bytes = vlewidth_bytesnumber(width); + let EEW = load_width_bytes * 8; + let EEW_pow = vlewidth_pow(width); + let SEW_pow = get_sew_pow(); + let LMUL_pow = get_lmul_pow(); + let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow; + let num_elem = get_num_elem(EMUL_pow, EEW); /* # of element of each register group */ + let nf_int = nfields_int(nf); + + if illegal_load(vd, vm, nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vlseg(nf_int, vm, vd, load_width_bytes, rs1, EMUL_pow, num_elem) + } + + \ No newline at end of file diff --git a/arch/inst/V/vle8ff.v.yaml b/arch/inst/V/vle8ff.v.yaml index 11833948f9..74203f0444 100644 --- a/arch/inst/V/vle8ff.v.yaml +++ b/arch/inst/V/vle8ff.v.yaml @@ -25,3 +25,23 @@ vle8ff.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let load_width_bytes = vlewidth_bytesnumber(width); + let EEW = load_width_bytes * 8; + let EEW_pow = vlewidth_pow(width); + let SEW_pow = get_sew_pow(); + let LMUL_pow = get_lmul_pow(); + let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow; + let num_elem = get_num_elem(EMUL_pow, EEW); + let nf_int = nfields_int(nf); + + if illegal_load(vd, vm, nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vlsegff(nf_int, vm, vd, load_width_bytes, rs1, EMUL_pow, num_elem) + } + + \ No newline at end of file diff --git a/arch/inst/V/vlm.v.yaml b/arch/inst/V/vlm.v.yaml index fd42c710f0..39b8607aeb 100644 --- a/arch/inst/V/vlm.v.yaml +++ b/arch/inst/V/vlm.v.yaml @@ -21,3 +21,21 @@ vlm.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let EEW = 8; + let EMUL_pow = 0; + let vl_val = unsigned(vl); + let evl : int = if vl_val % 8 == 0 then vl_val / 8 else vl_val / 8 + 1; /* the effective vector length is evl=ceil(vl/8) */ + let num_elem = get_num_elem(EMUL_pow, EEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + assert(evl >= 0); + process_vm(vd_or_vs3, rs1, num_elem, evl, op) + } + + \ No newline at end of file diff --git a/arch/inst/V/vloxei16.v.yaml b/arch/inst/V/vloxei16.v.yaml index 251b0f2c09..03d659425a 100644 --- a/arch/inst/V/vloxei16.v.yaml +++ b/arch/inst/V/vloxei16.v.yaml @@ -27,3 +27,23 @@ vloxei16.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let EEW_index_pow = vlewidth_pow(width); + let EEW_index_bytes = vlewidth_bytesnumber(width); + let EEW_data_pow = get_sew_pow(); + let EEW_data_bytes = get_sew_bytes(); + let EMUL_data_pow = get_lmul_pow(); + let EMUL_index_pow = EEW_index_pow - EEW_data_pow + EMUL_data_pow; + let num_elem = get_num_elem(EMUL_data_pow, EEW_data_bytes * 8); + let nf_int = nfields_int(nf); + + if illegal_indexed_load(vd, vm, nf_int, EEW_index_bytes * 8, EMUL_index_pow, EMUL_data_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vlxseg(nf_int, vm, vd, EEW_index_bytes, EEW_data_bytes, EMUL_index_pow, EMUL_data_pow, rs1, vs2, num_elem, 3) + } + + \ No newline at end of file diff --git a/arch/inst/V/vloxei32.v.yaml b/arch/inst/V/vloxei32.v.yaml index 91a9605d16..49609abc94 100644 --- a/arch/inst/V/vloxei32.v.yaml +++ b/arch/inst/V/vloxei32.v.yaml @@ -27,3 +27,23 @@ vloxei32.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let EEW_index_pow = vlewidth_pow(width); + let EEW_index_bytes = vlewidth_bytesnumber(width); + let EEW_data_pow = get_sew_pow(); + let EEW_data_bytes = get_sew_bytes(); + let EMUL_data_pow = get_lmul_pow(); + let EMUL_index_pow = EEW_index_pow - EEW_data_pow + EMUL_data_pow; + let num_elem = get_num_elem(EMUL_data_pow, EEW_data_bytes * 8); + let nf_int = nfields_int(nf); + + if illegal_indexed_load(vd, vm, nf_int, EEW_index_bytes * 8, EMUL_index_pow, EMUL_data_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vlxseg(nf_int, vm, vd, EEW_index_bytes, EEW_data_bytes, EMUL_index_pow, EMUL_data_pow, rs1, vs2, num_elem, 3) + } + + \ No newline at end of file diff --git a/arch/inst/V/vloxei64.v.yaml b/arch/inst/V/vloxei64.v.yaml index fea3a5a3ce..efca5aee11 100644 --- a/arch/inst/V/vloxei64.v.yaml +++ b/arch/inst/V/vloxei64.v.yaml @@ -27,3 +27,23 @@ vloxei64.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let EEW_index_pow = vlewidth_pow(width); + let EEW_index_bytes = vlewidth_bytesnumber(width); + let EEW_data_pow = get_sew_pow(); + let EEW_data_bytes = get_sew_bytes(); + let EMUL_data_pow = get_lmul_pow(); + let EMUL_index_pow = EEW_index_pow - EEW_data_pow + EMUL_data_pow; + let num_elem = get_num_elem(EMUL_data_pow, EEW_data_bytes * 8); + let nf_int = nfields_int(nf); + + if illegal_indexed_load(vd, vm, nf_int, EEW_index_bytes * 8, EMUL_index_pow, EMUL_data_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vlxseg(nf_int, vm, vd, EEW_index_bytes, EEW_data_bytes, EMUL_index_pow, EMUL_data_pow, rs1, vs2, num_elem, 3) + } + + \ No newline at end of file diff --git a/arch/inst/V/vloxei8.v.yaml b/arch/inst/V/vloxei8.v.yaml index 0cff00e149..034629bac6 100644 --- a/arch/inst/V/vloxei8.v.yaml +++ b/arch/inst/V/vloxei8.v.yaml @@ -27,3 +27,23 @@ vloxei8.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let EEW_index_pow = vlewidth_pow(width); + let EEW_index_bytes = vlewidth_bytesnumber(width); + let EEW_data_pow = get_sew_pow(); + let EEW_data_bytes = get_sew_bytes(); + let EMUL_data_pow = get_lmul_pow(); + let EMUL_index_pow = EEW_index_pow - EEW_data_pow + EMUL_data_pow; + let num_elem = get_num_elem(EMUL_data_pow, EEW_data_bytes * 8); + let nf_int = nfields_int(nf); + + if illegal_indexed_load(vd, vm, nf_int, EEW_index_bytes * 8, EMUL_index_pow, EMUL_data_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vlxseg(nf_int, vm, vd, EEW_index_bytes, EEW_data_bytes, EMUL_index_pow, EMUL_data_pow, rs1, vs2, num_elem, 3) + } + + \ No newline at end of file diff --git a/arch/inst/V/vlse16.v.yaml b/arch/inst/V/vlse16.v.yaml index 59c5f7d0e4..1d2854d11e 100644 --- a/arch/inst/V/vlse16.v.yaml +++ b/arch/inst/V/vlse16.v.yaml @@ -27,3 +27,23 @@ vlse16.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let load_width_bytes = vlewidth_bytesnumber(width); + let EEW = load_width_bytes * 8; + let EEW_pow = vlewidth_pow(width); + let SEW_pow = get_sew_pow(); + let LMUL_pow = get_lmul_pow(); + let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow; + let num_elem = get_num_elem(EMUL_pow, EEW); + let nf_int = nfields_int(nf); + + if illegal_load(vd, vm, nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vlsseg(nf_int, vm, vd, load_width_bytes, rs1, rs2, EMUL_pow, num_elem) + } + + \ No newline at end of file diff --git a/arch/inst/V/vlse32.v.yaml b/arch/inst/V/vlse32.v.yaml index 7f4b919943..d965503c6b 100644 --- a/arch/inst/V/vlse32.v.yaml +++ b/arch/inst/V/vlse32.v.yaml @@ -27,3 +27,23 @@ vlse32.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let load_width_bytes = vlewidth_bytesnumber(width); + let EEW = load_width_bytes * 8; + let EEW_pow = vlewidth_pow(width); + let SEW_pow = get_sew_pow(); + let LMUL_pow = get_lmul_pow(); + let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow; + let num_elem = get_num_elem(EMUL_pow, EEW); + let nf_int = nfields_int(nf); + + if illegal_load(vd, vm, nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vlsseg(nf_int, vm, vd, load_width_bytes, rs1, rs2, EMUL_pow, num_elem) + } + + \ No newline at end of file diff --git a/arch/inst/V/vlse64.v.yaml b/arch/inst/V/vlse64.v.yaml index b7e44000a3..eec1c5d517 100644 --- a/arch/inst/V/vlse64.v.yaml +++ b/arch/inst/V/vlse64.v.yaml @@ -27,3 +27,23 @@ vlse64.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let load_width_bytes = vlewidth_bytesnumber(width); + let EEW = load_width_bytes * 8; + let EEW_pow = vlewidth_pow(width); + let SEW_pow = get_sew_pow(); + let LMUL_pow = get_lmul_pow(); + let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow; + let num_elem = get_num_elem(EMUL_pow, EEW); + let nf_int = nfields_int(nf); + + if illegal_load(vd, vm, nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vlsseg(nf_int, vm, vd, load_width_bytes, rs1, rs2, EMUL_pow, num_elem) + } + + \ No newline at end of file diff --git a/arch/inst/V/vlse8.v.yaml b/arch/inst/V/vlse8.v.yaml index 9e1504718c..bad18af84d 100644 --- a/arch/inst/V/vlse8.v.yaml +++ b/arch/inst/V/vlse8.v.yaml @@ -27,3 +27,23 @@ vlse8.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let load_width_bytes = vlewidth_bytesnumber(width); + let EEW = load_width_bytes * 8; + let EEW_pow = vlewidth_pow(width); + let SEW_pow = get_sew_pow(); + let LMUL_pow = get_lmul_pow(); + let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow; + let num_elem = get_num_elem(EMUL_pow, EEW); + let nf_int = nfields_int(nf); + + if illegal_load(vd, vm, nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vlsseg(nf_int, vm, vd, load_width_bytes, rs1, rs2, EMUL_pow, num_elem) + } + + \ No newline at end of file diff --git a/arch/inst/V/vluxei16.v.yaml b/arch/inst/V/vluxei16.v.yaml index a13b5b239c..88f2cbc386 100644 --- a/arch/inst/V/vluxei16.v.yaml +++ b/arch/inst/V/vluxei16.v.yaml @@ -27,3 +27,23 @@ vluxei16.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let EEW_index_pow = vlewidth_pow(width); + let EEW_index_bytes = vlewidth_bytesnumber(width); + let EEW_data_pow = get_sew_pow(); + let EEW_data_bytes = get_sew_bytes(); + let EMUL_data_pow = get_lmul_pow(); + let EMUL_index_pow = EEW_index_pow - EEW_data_pow + EMUL_data_pow; + let num_elem = get_num_elem(EMUL_data_pow, EEW_data_bytes * 8); + let nf_int = nfields_int(nf); + + if illegal_indexed_load(vd, vm, nf_int, EEW_index_bytes * 8, EMUL_index_pow, EMUL_data_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vlxseg(nf_int, vm, vd, EEW_index_bytes, EEW_data_bytes, EMUL_index_pow, EMUL_data_pow, rs1, vs2, num_elem, 1) + } + + \ No newline at end of file diff --git a/arch/inst/V/vluxei32.v.yaml b/arch/inst/V/vluxei32.v.yaml index a0826fc585..2680bbd74e 100644 --- a/arch/inst/V/vluxei32.v.yaml +++ b/arch/inst/V/vluxei32.v.yaml @@ -27,3 +27,23 @@ vluxei32.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let EEW_index_pow = vlewidth_pow(width); + let EEW_index_bytes = vlewidth_bytesnumber(width); + let EEW_data_pow = get_sew_pow(); + let EEW_data_bytes = get_sew_bytes(); + let EMUL_data_pow = get_lmul_pow(); + let EMUL_index_pow = EEW_index_pow - EEW_data_pow + EMUL_data_pow; + let num_elem = get_num_elem(EMUL_data_pow, EEW_data_bytes * 8); + let nf_int = nfields_int(nf); + + if illegal_indexed_load(vd, vm, nf_int, EEW_index_bytes * 8, EMUL_index_pow, EMUL_data_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vlxseg(nf_int, vm, vd, EEW_index_bytes, EEW_data_bytes, EMUL_index_pow, EMUL_data_pow, rs1, vs2, num_elem, 1) + } + + \ No newline at end of file diff --git a/arch/inst/V/vluxei64.v.yaml b/arch/inst/V/vluxei64.v.yaml index ec50a78229..581cb22dbe 100644 --- a/arch/inst/V/vluxei64.v.yaml +++ b/arch/inst/V/vluxei64.v.yaml @@ -27,3 +27,23 @@ vluxei64.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let EEW_index_pow = vlewidth_pow(width); + let EEW_index_bytes = vlewidth_bytesnumber(width); + let EEW_data_pow = get_sew_pow(); + let EEW_data_bytes = get_sew_bytes(); + let EMUL_data_pow = get_lmul_pow(); + let EMUL_index_pow = EEW_index_pow - EEW_data_pow + EMUL_data_pow; + let num_elem = get_num_elem(EMUL_data_pow, EEW_data_bytes * 8); + let nf_int = nfields_int(nf); + + if illegal_indexed_load(vd, vm, nf_int, EEW_index_bytes * 8, EMUL_index_pow, EMUL_data_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vlxseg(nf_int, vm, vd, EEW_index_bytes, EEW_data_bytes, EMUL_index_pow, EMUL_data_pow, rs1, vs2, num_elem, 1) + } + + \ No newline at end of file diff --git a/arch/inst/V/vluxei8.v.yaml b/arch/inst/V/vluxei8.v.yaml index 75fcf421dd..c309309523 100644 --- a/arch/inst/V/vluxei8.v.yaml +++ b/arch/inst/V/vluxei8.v.yaml @@ -27,3 +27,23 @@ vluxei8.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let EEW_index_pow = vlewidth_pow(width); + let EEW_index_bytes = vlewidth_bytesnumber(width); + let EEW_data_pow = get_sew_pow(); + let EEW_data_bytes = get_sew_bytes(); + let EMUL_data_pow = get_lmul_pow(); + let EMUL_index_pow = EEW_index_pow - EEW_data_pow + EMUL_data_pow; + let num_elem = get_num_elem(EMUL_data_pow, EEW_data_bytes * 8); + let nf_int = nfields_int(nf); + + if illegal_indexed_load(vd, vm, nf_int, EEW_index_bytes * 8, EMUL_index_pow, EMUL_data_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vlxseg(nf_int, vm, vd, EEW_index_bytes, EEW_data_bytes, EMUL_index_pow, EMUL_data_pow, rs1, vs2, num_elem, 1) + } + + \ No newline at end of file diff --git a/arch/inst/V/vmacc.vv.yaml b/arch/inst/V/vmacc.vv.yaml index 6e807d3250..706f61c677 100644 --- a/arch/inst/V/vmacc.vv.yaml +++ b/arch/inst/V/vmacc.vv.yaml @@ -25,3 +25,43 @@ vmacc.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVV_VMACC => get_slice_int(SEW, signed(vs1_val[i]) * signed(vs2_val[i]), 0) + vd_val[i], + MVV_VNMSAC => vd_val[i] - get_slice_int(SEW, signed(vs1_val[i]) * signed(vs2_val[i]), 0), + MVV_VMADD => get_slice_int(SEW, signed(vs1_val[i]) * signed(vd_val[i]), 0) + vs2_val[i], + MVV_VNMSUB => vs2_val[i] - get_slice_int(SEW, signed(vs1_val[i]) * signed(vd_val[i]), 0) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmacc.vx.yaml b/arch/inst/V/vmacc.vx.yaml index f663ccf33c..ac68422583 100644 --- a/arch/inst/V/vmacc.vx.yaml +++ b/arch/inst/V/vmacc.vx.yaml @@ -25,3 +25,43 @@ vmacc.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVX_VMACC => get_slice_int(SEW, signed(rs1_val) * signed(vs2_val[i]), 0) + vd_val[i], + MVX_VNMSAC => vd_val[i] - get_slice_int(SEW, signed(rs1_val) * signed(vs2_val[i]), 0), + MVX_VMADD => get_slice_int(SEW, signed(rs1_val) * signed(vd_val[i]), 0) + vs2_val[i], + MVX_VNMSUB => vs2_val[i] - get_slice_int(SEW, signed(rs1_val) * signed(vd_val[i]), 0) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmadc.vi.yaml b/arch/inst/V/vmadc.vi.yaml index 4b21bdcd42..ec950016b7 100644 --- a/arch/inst/V/vmadc.vi.yaml +++ b/arch/inst/V/vmadc.vi.yaml @@ -23,3 +23,40 @@ vmadc.vi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_carry(num_elem, SEW, LMUL_pow, vd_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VIMC_VMADC => unsigned(vs2_val[i]) + unsigned(imm_val) > 2 ^ SEW - 1 + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmadc.vim.yaml b/arch/inst/V/vmadc.vim.yaml index 5dc463f884..11d890fabf 100644 --- a/arch/inst/V/vmadc.vim.yaml +++ b/arch/inst/V/vmadc.vim.yaml @@ -23,3 +23,41 @@ vmadc.vim: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask_carry(num_elem, 0b0, 0b00000); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_carry(num_elem, SEW, LMUL_pow, vd_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VIM_VMADC => unsigned(vs2_val[i]) + unsigned(imm_val) + unsigned(bool_to_bits(vm_val[i])) > 2 ^ SEW - 1 + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmadc.vv.yaml b/arch/inst/V/vmadc.vv.yaml index e12ee6ef34..ffff089723 100644 --- a/arch/inst/V/vmadc.vv.yaml +++ b/arch/inst/V/vmadc.vv.yaml @@ -23,3 +23,41 @@ vmadc.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_carry(num_elem, SEW, LMUL_pow, vd_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VVMC_VMADC => unsigned(vs2_val[i]) + unsigned(vs1_val[i]) > 2 ^ SEW - 1, + VVMC_VMSBC => unsigned(vs2_val[i]) - unsigned(vs1_val[i]) < 0 + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmadc.vvm.yaml b/arch/inst/V/vmadc.vvm.yaml index e01e4db47f..443eefa49d 100644 --- a/arch/inst/V/vmadc.vvm.yaml +++ b/arch/inst/V/vmadc.vvm.yaml @@ -23,3 +23,42 @@ vmadc.vvm: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask_carry(num_elem, 0b0, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_carry(num_elem, SEW, LMUL_pow, vd_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VVM_VMADC => unsigned(vs2_val[i]) + unsigned(vs1_val[i]) + unsigned(bool_to_bits(vm_val[i])) > 2 ^ SEW - 1, + VVM_VMSBC => unsigned(vs2_val[i]) - unsigned(vs1_val[i]) - unsigned(bool_to_bits(vm_val[i])) < 0 + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmadc.vx.yaml b/arch/inst/V/vmadc.vx.yaml index b7b34f1739..342a32f11c 100644 --- a/arch/inst/V/vmadc.vx.yaml +++ b/arch/inst/V/vmadc.vx.yaml @@ -23,3 +23,41 @@ vmadc.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_carry(num_elem, SEW, LMUL_pow, vd_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VXMC_VMADC => unsigned(vs2_val[i]) + unsigned(rs1_val) > 2 ^ SEW - 1, + VXMC_VMSBC => unsigned(vs2_val[i]) - unsigned(rs1_val) < 0 + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmadc.vxm.yaml b/arch/inst/V/vmadc.vxm.yaml index 3dfcf2f95e..b8df482ef6 100644 --- a/arch/inst/V/vmadc.vxm.yaml +++ b/arch/inst/V/vmadc.vxm.yaml @@ -23,3 +23,42 @@ vmadc.vxm: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask_carry(num_elem, 0b0, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_carry(num_elem, SEW, LMUL_pow, vd_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VXM_VMADC => unsigned(vs2_val[i]) + unsigned(rs1_val) + unsigned(bool_to_bits(vm_val[i])) > 2 ^ SEW - 1, + VXM_VMSBC => unsigned(vs2_val[i]) - unsigned(rs1_val) - unsigned(bool_to_bits(vm_val[i])) < 0 + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmadd.vv.yaml b/arch/inst/V/vmadd.vv.yaml index c5e6834c28..1c9e13db46 100644 --- a/arch/inst/V/vmadd.vv.yaml +++ b/arch/inst/V/vmadd.vv.yaml @@ -25,3 +25,43 @@ vmadd.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVV_VMACC => get_slice_int(SEW, signed(vs1_val[i]) * signed(vs2_val[i]), 0) + vd_val[i], + MVV_VNMSAC => vd_val[i] - get_slice_int(SEW, signed(vs1_val[i]) * signed(vs2_val[i]), 0), + MVV_VMADD => get_slice_int(SEW, signed(vs1_val[i]) * signed(vd_val[i]), 0) + vs2_val[i], + MVV_VNMSUB => vs2_val[i] - get_slice_int(SEW, signed(vs1_val[i]) * signed(vd_val[i]), 0) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmadd.vx.yaml b/arch/inst/V/vmadd.vx.yaml index 886e01b809..4a5e163d11 100644 --- a/arch/inst/V/vmadd.vx.yaml +++ b/arch/inst/V/vmadd.vx.yaml @@ -25,3 +25,43 @@ vmadd.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVX_VMACC => get_slice_int(SEW, signed(rs1_val) * signed(vs2_val[i]), 0) + vd_val[i], + MVX_VNMSAC => vd_val[i] - get_slice_int(SEW, signed(rs1_val) * signed(vs2_val[i]), 0), + MVX_VMADD => get_slice_int(SEW, signed(rs1_val) * signed(vd_val[i]), 0) + vs2_val[i], + MVX_VNMSUB => vs2_val[i] - get_slice_int(SEW, signed(rs1_val) * signed(vd_val[i]), 0) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmand.mm.yaml b/arch/inst/V/vmand.mm.yaml index 0215320c30..468341df55 100644 --- a/arch/inst/V/vmand.mm.yaml +++ b/arch/inst/V/vmand.mm.yaml @@ -23,3 +23,46 @@ vmand.mm: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = unsigned(vlenb) * 8; + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vs1_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vs1); + let vs2_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_carry(num_elem, SEW, 0, vd_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MM_VMAND => vs2_val[i] & vs1_val[i], + MM_VMNAND => not(vs2_val[i] & vs1_val[i]), + MM_VMANDNOT => vs2_val[i] & not(vs1_val[i]), + MM_VMXOR => vs2_val[i] != vs1_val[i], + MM_VMOR => vs2_val[i] | vs1_val[i], + MM_VMNOR => not(vs2_val[i] | vs1_val[i]), + MM_VMORNOT => vs2_val[i] | not(vs1_val[i]), + MM_VMXNOR => vs2_val[i] == vs1_val[i] + } + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmax.vv.yaml b/arch/inst/V/vmax.vv.yaml index c11e80b774..d08f9a2b3c 100644 --- a/arch/inst/V/vmax.vv.yaml +++ b/arch/inst/V/vmax.vv.yaml @@ -25,3 +25,103 @@ vmax.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VV_VADD => vs2_val[i] + vs1_val[i], + VV_VSUB => vs2_val[i] - vs1_val[i], + VV_VAND => vs2_val[i] & vs1_val[i], + VV_VOR => vs2_val[i] | vs1_val[i], + VV_VXOR => vs2_val[i] ^ vs1_val[i], + VV_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i])), + VV_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i])), + VV_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(vs1_val[i]) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i])) + }, + VV_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i])), + VV_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(vs1_val[i])); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VV_VSLL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] << shift_amount + }, + VV_VSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] >> shift_amount + }, + VV_VSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VV_VSSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VV_VSSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VV_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VRGATHER => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let idx = unsigned(vs1_val[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + }, + VV_VRGATHEREI16 => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + /* vrgatherei16.vv uses SEW/LMUL for the data in vs2 but EEW=16 and EMUL = (16/SEW)*LMUL for the indices in vs1 */ + let vs1_new : vector('n, dec, bits(16)) = read_vreg(num_elem, 16, 4 + LMUL_pow - SEW_pow, vs1); + let idx = unsigned(vs1_new[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmax.vx.yaml b/arch/inst/V/vmax.vx.yaml index 4c45d4b42e..b190f6c46a 100644 --- a/arch/inst/V/vmax.vx.yaml +++ b/arch/inst/V/vmax.vx.yaml @@ -25,3 +25,86 @@ vmax.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VX_VADD => vs2_val[i] + rs1_val, + VX_VSUB => vs2_val[i] - rs1_val, + VX_VRSUB => rs1_val - vs2_val[i], + VX_VAND => vs2_val[i] & rs1_val, + VX_VOR => vs2_val[i] | rs1_val, + VX_VXOR => vs2_val[i] ^ rs1_val, + VX_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val) ), + VX_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val) ), + VX_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(rs1_val) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val) ) + }, + VX_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val) ), + VX_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(rs1_val)); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VX_VSLL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] << shift_amount + }, + VX_VSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] >> shift_amount + }, + VX_VSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VX_VSSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VX_VSSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VX_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(rs1_val))), + VX_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(rs1_val))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmaxu.vv.yaml b/arch/inst/V/vmaxu.vv.yaml index ad68df9e03..fb79c70301 100644 --- a/arch/inst/V/vmaxu.vv.yaml +++ b/arch/inst/V/vmaxu.vv.yaml @@ -25,3 +25,103 @@ vmaxu.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VV_VADD => vs2_val[i] + vs1_val[i], + VV_VSUB => vs2_val[i] - vs1_val[i], + VV_VAND => vs2_val[i] & vs1_val[i], + VV_VOR => vs2_val[i] | vs1_val[i], + VV_VXOR => vs2_val[i] ^ vs1_val[i], + VV_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i])), + VV_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i])), + VV_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(vs1_val[i]) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i])) + }, + VV_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i])), + VV_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(vs1_val[i])); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VV_VSLL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] << shift_amount + }, + VV_VSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] >> shift_amount + }, + VV_VSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VV_VSSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VV_VSSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VV_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VRGATHER => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let idx = unsigned(vs1_val[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + }, + VV_VRGATHEREI16 => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + /* vrgatherei16.vv uses SEW/LMUL for the data in vs2 but EEW=16 and EMUL = (16/SEW)*LMUL for the indices in vs1 */ + let vs1_new : vector('n, dec, bits(16)) = read_vreg(num_elem, 16, 4 + LMUL_pow - SEW_pow, vs1); + let idx = unsigned(vs1_new[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmaxu.vx.yaml b/arch/inst/V/vmaxu.vx.yaml index cdf4fb76c4..1b5c3bfeb9 100644 --- a/arch/inst/V/vmaxu.vx.yaml +++ b/arch/inst/V/vmaxu.vx.yaml @@ -25,3 +25,86 @@ vmaxu.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VX_VADD => vs2_val[i] + rs1_val, + VX_VSUB => vs2_val[i] - rs1_val, + VX_VRSUB => rs1_val - vs2_val[i], + VX_VAND => vs2_val[i] & rs1_val, + VX_VOR => vs2_val[i] | rs1_val, + VX_VXOR => vs2_val[i] ^ rs1_val, + VX_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val) ), + VX_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val) ), + VX_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(rs1_val) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val) ) + }, + VX_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val) ), + VX_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(rs1_val)); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VX_VSLL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] << shift_amount + }, + VX_VSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] >> shift_amount + }, + VX_VSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VX_VSSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VX_VSSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VX_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(rs1_val))), + VX_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(rs1_val))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmerge.vim.yaml b/arch/inst/V/vmerge.vim.yaml index d637e48690..15f48e3893 100644 --- a/arch/inst/V/vmerge.vim.yaml +++ b/arch/inst/V/vmerge.vim.yaml @@ -23,3 +23,47 @@ vmerge.vim: data_independent_timing: false operation(): | + + + + sail(): | + { + let start_element = get_start_element(); + let end_element = get_end_element(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); /* max(VLMAX,VLEN/SEW)) */ + let real_num_elem = if LMUL_pow >= 0 then num_elem else num_elem / (0 - LMUL_pow); /* VLMAX */ + + if illegal_vd_masked(vd) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, 0b00000); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + + let tail_ag : agtype = get_vtype_vta(); + foreach (i from 0 to (num_elem - 1)) { + if i < start_element then { + result[i] = vd_val[i] + } else if i > end_element | i >= real_num_elem then { + result[i] = match tail_ag { + UNDISTURBED => vd_val[i], + AGNOSTIC => vd_val[i] /* TODO: configuration support */ + } + } else { + /* the merge operates on all body elements */ + result[i] = if vm_val[i] then imm_val else vs2_val[i] + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmerge.vvm.yaml b/arch/inst/V/vmerge.vvm.yaml index d735668a3d..f8c977d1fc 100644 --- a/arch/inst/V/vmerge.vvm.yaml +++ b/arch/inst/V/vmerge.vvm.yaml @@ -23,3 +23,47 @@ vmerge.vvm: data_independent_timing: false operation(): | + + + + sail(): | + { + let start_element = get_start_element(); + let end_element = get_end_element(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); /* max(VLMAX,VLEN/SEW)) */ + let real_num_elem = if LMUL_pow >= 0 then num_elem else num_elem / (0 - LMUL_pow); /* VLMAX */ + + if illegal_vd_masked(vd) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + + let tail_ag : agtype = get_vtype_vta(); + foreach (i from 0 to (num_elem - 1)) { + if i < start_element then { + result[i] = vd_val[i] + } else if i > end_element | i >= real_num_elem then { + result[i] = match tail_ag { + UNDISTURBED => vd_val[i], + AGNOSTIC => vd_val[i] /* TODO: configuration support */ + } + } else { + /* the merge operates on all body elements */ + result[i] = if vm_val[i] then vs1_val[i] else vs2_val[i] + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmerge.vxm.yaml b/arch/inst/V/vmerge.vxm.yaml index b6df393e2a..0a14ea8541 100644 --- a/arch/inst/V/vmerge.vxm.yaml +++ b/arch/inst/V/vmerge.vxm.yaml @@ -23,3 +23,47 @@ vmerge.vxm: data_independent_timing: false operation(): | + + + + sail(): | + { + let start_element = get_start_element(); + let end_element = get_end_element(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); /* max(VLMAX,VLEN/SEW)) */ + let real_num_elem = if LMUL_pow >= 0 then num_elem else num_elem / (0 - LMUL_pow); /* VLMAX */ + + if illegal_vd_masked(vd) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + + let tail_ag : agtype = get_vtype_vta(); + foreach (i from 0 to (num_elem - 1)) { + if i < start_element then { + result[i] = vd_val[i] + } else if i > end_element | i >= real_num_elem then { + result[i] = match tail_ag { + UNDISTURBED => vd_val[i], + AGNOSTIC => vd_val[i] /* TODO: configuration support */ + } + } else { + /* the merge operates on all body elements */ + result[i] = if vm_val[i] then rs1_val else vs2_val[i] + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmfeq.vf.yaml b/arch/inst/V/vmfeq.vf.yaml index a1b8c519b0..dbc0d43833 100644 --- a/arch/inst/V/vmfeq.vf.yaml +++ b/arch/inst/V/vmfeq.vf.yaml @@ -25,3 +25,48 @@ vmfeq.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_vd_unmasked(SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VFM_VMFEQ => fp_eq(vs2_val[i], rs1_val), + VFM_VMFNE => ~(fp_eq(vs2_val[i], rs1_val)), + VFM_VMFLE => fp_le(vs2_val[i], rs1_val), + VFM_VMFLT => fp_lt(vs2_val[i], rs1_val), + VFM_VMFGE => fp_ge(vs2_val[i], rs1_val), + VFM_VMFGT => fp_gt(vs2_val[i], rs1_val) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmfeq.vv.yaml b/arch/inst/V/vmfeq.vv.yaml index a51e3aa8a7..4072b65a63 100644 --- a/arch/inst/V/vmfeq.vv.yaml +++ b/arch/inst/V/vmfeq.vv.yaml @@ -25,3 +25,46 @@ vmfeq.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_vd_unmasked(SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + FVVM_VMFEQ => fp_eq(vs2_val[i], vs1_val[i]), + FVVM_VMFNE => ~(fp_eq(vs2_val[i], vs1_val[i])), + FVVM_VMFLE => fp_le(vs2_val[i], vs1_val[i]), + FVVM_VMFLT => fp_lt(vs2_val[i], vs1_val[i]) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmfge.vf.yaml b/arch/inst/V/vmfge.vf.yaml index a49ac0b2d1..6534a6bb8a 100644 --- a/arch/inst/V/vmfge.vf.yaml +++ b/arch/inst/V/vmfge.vf.yaml @@ -25,3 +25,48 @@ vmfge.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_vd_unmasked(SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VFM_VMFEQ => fp_eq(vs2_val[i], rs1_val), + VFM_VMFNE => ~(fp_eq(vs2_val[i], rs1_val)), + VFM_VMFLE => fp_le(vs2_val[i], rs1_val), + VFM_VMFLT => fp_lt(vs2_val[i], rs1_val), + VFM_VMFGE => fp_ge(vs2_val[i], rs1_val), + VFM_VMFGT => fp_gt(vs2_val[i], rs1_val) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmfgt.vf.yaml b/arch/inst/V/vmfgt.vf.yaml index 68b684025e..e996136333 100644 --- a/arch/inst/V/vmfgt.vf.yaml +++ b/arch/inst/V/vmfgt.vf.yaml @@ -25,3 +25,48 @@ vmfgt.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_vd_unmasked(SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VFM_VMFEQ => fp_eq(vs2_val[i], rs1_val), + VFM_VMFNE => ~(fp_eq(vs2_val[i], rs1_val)), + VFM_VMFLE => fp_le(vs2_val[i], rs1_val), + VFM_VMFLT => fp_lt(vs2_val[i], rs1_val), + VFM_VMFGE => fp_ge(vs2_val[i], rs1_val), + VFM_VMFGT => fp_gt(vs2_val[i], rs1_val) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmfle.vf.yaml b/arch/inst/V/vmfle.vf.yaml index fa113d9220..65344a65bf 100644 --- a/arch/inst/V/vmfle.vf.yaml +++ b/arch/inst/V/vmfle.vf.yaml @@ -25,3 +25,48 @@ vmfle.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_vd_unmasked(SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VFM_VMFEQ => fp_eq(vs2_val[i], rs1_val), + VFM_VMFNE => ~(fp_eq(vs2_val[i], rs1_val)), + VFM_VMFLE => fp_le(vs2_val[i], rs1_val), + VFM_VMFLT => fp_lt(vs2_val[i], rs1_val), + VFM_VMFGE => fp_ge(vs2_val[i], rs1_val), + VFM_VMFGT => fp_gt(vs2_val[i], rs1_val) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmfle.vv.yaml b/arch/inst/V/vmfle.vv.yaml index b195bde9f7..1bdcdea2e9 100644 --- a/arch/inst/V/vmfle.vv.yaml +++ b/arch/inst/V/vmfle.vv.yaml @@ -25,3 +25,46 @@ vmfle.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_vd_unmasked(SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + FVVM_VMFEQ => fp_eq(vs2_val[i], vs1_val[i]), + FVVM_VMFNE => ~(fp_eq(vs2_val[i], vs1_val[i])), + FVVM_VMFLE => fp_le(vs2_val[i], vs1_val[i]), + FVVM_VMFLT => fp_lt(vs2_val[i], vs1_val[i]) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmflt.vf.yaml b/arch/inst/V/vmflt.vf.yaml index 4e4e548d55..8a4c8a94bb 100644 --- a/arch/inst/V/vmflt.vf.yaml +++ b/arch/inst/V/vmflt.vf.yaml @@ -25,3 +25,48 @@ vmflt.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_vd_unmasked(SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VFM_VMFEQ => fp_eq(vs2_val[i], rs1_val), + VFM_VMFNE => ~(fp_eq(vs2_val[i], rs1_val)), + VFM_VMFLE => fp_le(vs2_val[i], rs1_val), + VFM_VMFLT => fp_lt(vs2_val[i], rs1_val), + VFM_VMFGE => fp_ge(vs2_val[i], rs1_val), + VFM_VMFGT => fp_gt(vs2_val[i], rs1_val) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmflt.vv.yaml b/arch/inst/V/vmflt.vv.yaml index f32cdc87d4..aaf35ddf1c 100644 --- a/arch/inst/V/vmflt.vv.yaml +++ b/arch/inst/V/vmflt.vv.yaml @@ -25,3 +25,46 @@ vmflt.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_vd_unmasked(SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + FVVM_VMFEQ => fp_eq(vs2_val[i], vs1_val[i]), + FVVM_VMFNE => ~(fp_eq(vs2_val[i], vs1_val[i])), + FVVM_VMFLE => fp_le(vs2_val[i], vs1_val[i]), + FVVM_VMFLT => fp_lt(vs2_val[i], vs1_val[i]) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmfne.vf.yaml b/arch/inst/V/vmfne.vf.yaml index 6131882293..e9717ec821 100644 --- a/arch/inst/V/vmfne.vf.yaml +++ b/arch/inst/V/vmfne.vf.yaml @@ -25,3 +25,48 @@ vmfne.vf: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_vd_unmasked(SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar_fp(rs1, 'm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VFM_VMFEQ => fp_eq(vs2_val[i], rs1_val), + VFM_VMFNE => ~(fp_eq(vs2_val[i], rs1_val)), + VFM_VMFLE => fp_le(vs2_val[i], rs1_val), + VFM_VMFLT => fp_lt(vs2_val[i], rs1_val), + VFM_VMFGE => fp_ge(vs2_val[i], rs1_val), + VFM_VMFGT => fp_gt(vs2_val[i], rs1_val) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmfne.vv.yaml b/arch/inst/V/vmfne.vv.yaml index 1eac9884ef..1d2c139a9b 100644 --- a/arch/inst/V/vmfne.vv.yaml +++ b/arch/inst/V/vmfne.vv.yaml @@ -25,3 +25,46 @@ vmfne.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let rm_3b = fcsr.FRM(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_fp_vd_unmasked(SEW, rm_3b) then { handle_illegal(); return RETIRE_FAIL }; + assert(SEW != 8); + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + FVVM_VMFEQ => fp_eq(vs2_val[i], vs1_val[i]), + FVVM_VMFNE => ~(fp_eq(vs2_val[i], vs1_val[i])), + FVVM_VMFLE => fp_le(vs2_val[i], vs1_val[i]), + FVVM_VMFLT => fp_lt(vs2_val[i], vs1_val[i]) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmin.vv.yaml b/arch/inst/V/vmin.vv.yaml index 5654b1ca09..f5fff3d663 100644 --- a/arch/inst/V/vmin.vv.yaml +++ b/arch/inst/V/vmin.vv.yaml @@ -25,3 +25,103 @@ vmin.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VV_VADD => vs2_val[i] + vs1_val[i], + VV_VSUB => vs2_val[i] - vs1_val[i], + VV_VAND => vs2_val[i] & vs1_val[i], + VV_VOR => vs2_val[i] | vs1_val[i], + VV_VXOR => vs2_val[i] ^ vs1_val[i], + VV_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i])), + VV_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i])), + VV_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(vs1_val[i]) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i])) + }, + VV_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i])), + VV_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(vs1_val[i])); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VV_VSLL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] << shift_amount + }, + VV_VSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] >> shift_amount + }, + VV_VSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VV_VSSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VV_VSSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VV_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VRGATHER => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let idx = unsigned(vs1_val[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + }, + VV_VRGATHEREI16 => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + /* vrgatherei16.vv uses SEW/LMUL for the data in vs2 but EEW=16 and EMUL = (16/SEW)*LMUL for the indices in vs1 */ + let vs1_new : vector('n, dec, bits(16)) = read_vreg(num_elem, 16, 4 + LMUL_pow - SEW_pow, vs1); + let idx = unsigned(vs1_new[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmin.vx.yaml b/arch/inst/V/vmin.vx.yaml index d847ebb42c..ecf1f1c5a0 100644 --- a/arch/inst/V/vmin.vx.yaml +++ b/arch/inst/V/vmin.vx.yaml @@ -25,3 +25,86 @@ vmin.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VX_VADD => vs2_val[i] + rs1_val, + VX_VSUB => vs2_val[i] - rs1_val, + VX_VRSUB => rs1_val - vs2_val[i], + VX_VAND => vs2_val[i] & rs1_val, + VX_VOR => vs2_val[i] | rs1_val, + VX_VXOR => vs2_val[i] ^ rs1_val, + VX_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val) ), + VX_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val) ), + VX_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(rs1_val) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val) ) + }, + VX_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val) ), + VX_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(rs1_val)); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VX_VSLL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] << shift_amount + }, + VX_VSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] >> shift_amount + }, + VX_VSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VX_VSSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VX_VSSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VX_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(rs1_val))), + VX_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(rs1_val))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vminu.vv.yaml b/arch/inst/V/vminu.vv.yaml index 54984c354e..99c8898abd 100644 --- a/arch/inst/V/vminu.vv.yaml +++ b/arch/inst/V/vminu.vv.yaml @@ -25,3 +25,103 @@ vminu.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VV_VADD => vs2_val[i] + vs1_val[i], + VV_VSUB => vs2_val[i] - vs1_val[i], + VV_VAND => vs2_val[i] & vs1_val[i], + VV_VOR => vs2_val[i] | vs1_val[i], + VV_VXOR => vs2_val[i] ^ vs1_val[i], + VV_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i])), + VV_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i])), + VV_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(vs1_val[i]) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i])) + }, + VV_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i])), + VV_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(vs1_val[i])); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VV_VSLL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] << shift_amount + }, + VV_VSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] >> shift_amount + }, + VV_VSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VV_VSSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VV_VSSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VV_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VRGATHER => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let idx = unsigned(vs1_val[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + }, + VV_VRGATHEREI16 => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + /* vrgatherei16.vv uses SEW/LMUL for the data in vs2 but EEW=16 and EMUL = (16/SEW)*LMUL for the indices in vs1 */ + let vs1_new : vector('n, dec, bits(16)) = read_vreg(num_elem, 16, 4 + LMUL_pow - SEW_pow, vs1); + let idx = unsigned(vs1_new[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vminu.vx.yaml b/arch/inst/V/vminu.vx.yaml index cbcb418cba..f985fd7482 100644 --- a/arch/inst/V/vminu.vx.yaml +++ b/arch/inst/V/vminu.vx.yaml @@ -25,3 +25,86 @@ vminu.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VX_VADD => vs2_val[i] + rs1_val, + VX_VSUB => vs2_val[i] - rs1_val, + VX_VRSUB => rs1_val - vs2_val[i], + VX_VAND => vs2_val[i] & rs1_val, + VX_VOR => vs2_val[i] | rs1_val, + VX_VXOR => vs2_val[i] ^ rs1_val, + VX_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val) ), + VX_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val) ), + VX_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(rs1_val) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val) ) + }, + VX_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val) ), + VX_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(rs1_val)); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VX_VSLL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] << shift_amount + }, + VX_VSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] >> shift_amount + }, + VX_VSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VX_VSSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VX_VSSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VX_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(rs1_val))), + VX_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(rs1_val))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmnand.mm.yaml b/arch/inst/V/vmnand.mm.yaml index 258d36acfb..a7332e81c9 100644 --- a/arch/inst/V/vmnand.mm.yaml +++ b/arch/inst/V/vmnand.mm.yaml @@ -23,3 +23,46 @@ vmnand.mm: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = unsigned(vlenb) * 8; + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vs1_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vs1); + let vs2_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_carry(num_elem, SEW, 0, vd_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MM_VMAND => vs2_val[i] & vs1_val[i], + MM_VMNAND => not(vs2_val[i] & vs1_val[i]), + MM_VMANDNOT => vs2_val[i] & not(vs1_val[i]), + MM_VMXOR => vs2_val[i] != vs1_val[i], + MM_VMOR => vs2_val[i] | vs1_val[i], + MM_VMNOR => not(vs2_val[i] | vs1_val[i]), + MM_VMORNOT => vs2_val[i] | not(vs1_val[i]), + MM_VMXNOR => vs2_val[i] == vs1_val[i] + } + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmnor.mm.yaml b/arch/inst/V/vmnor.mm.yaml index 32f64abc8a..fa053e69c6 100644 --- a/arch/inst/V/vmnor.mm.yaml +++ b/arch/inst/V/vmnor.mm.yaml @@ -23,3 +23,46 @@ vmnor.mm: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = unsigned(vlenb) * 8; + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vs1_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vs1); + let vs2_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_carry(num_elem, SEW, 0, vd_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MM_VMAND => vs2_val[i] & vs1_val[i], + MM_VMNAND => not(vs2_val[i] & vs1_val[i]), + MM_VMANDNOT => vs2_val[i] & not(vs1_val[i]), + MM_VMXOR => vs2_val[i] != vs1_val[i], + MM_VMOR => vs2_val[i] | vs1_val[i], + MM_VMNOR => not(vs2_val[i] | vs1_val[i]), + MM_VMORNOT => vs2_val[i] | not(vs1_val[i]), + MM_VMXNOR => vs2_val[i] == vs1_val[i] + } + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmor.mm.yaml b/arch/inst/V/vmor.mm.yaml index 2e21351341..c0900fa968 100644 --- a/arch/inst/V/vmor.mm.yaml +++ b/arch/inst/V/vmor.mm.yaml @@ -23,3 +23,46 @@ vmor.mm: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = unsigned(vlenb) * 8; + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vs1_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vs1); + let vs2_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_carry(num_elem, SEW, 0, vd_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MM_VMAND => vs2_val[i] & vs1_val[i], + MM_VMNAND => not(vs2_val[i] & vs1_val[i]), + MM_VMANDNOT => vs2_val[i] & not(vs1_val[i]), + MM_VMXOR => vs2_val[i] != vs1_val[i], + MM_VMOR => vs2_val[i] | vs1_val[i], + MM_VMNOR => not(vs2_val[i] | vs1_val[i]), + MM_VMORNOT => vs2_val[i] | not(vs1_val[i]), + MM_VMXNOR => vs2_val[i] == vs1_val[i] + } + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmsbc.vv.yaml b/arch/inst/V/vmsbc.vv.yaml index b09cfba3dc..b1754abb2a 100644 --- a/arch/inst/V/vmsbc.vv.yaml +++ b/arch/inst/V/vmsbc.vv.yaml @@ -23,3 +23,41 @@ vmsbc.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_carry(num_elem, SEW, LMUL_pow, vd_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VVMC_VMADC => unsigned(vs2_val[i]) + unsigned(vs1_val[i]) > 2 ^ SEW - 1, + VVMC_VMSBC => unsigned(vs2_val[i]) - unsigned(vs1_val[i]) < 0 + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmsbc.vvm.yaml b/arch/inst/V/vmsbc.vvm.yaml index 9e821e86bb..4184b967b5 100644 --- a/arch/inst/V/vmsbc.vvm.yaml +++ b/arch/inst/V/vmsbc.vvm.yaml @@ -23,3 +23,42 @@ vmsbc.vvm: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask_carry(num_elem, 0b0, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_carry(num_elem, SEW, LMUL_pow, vd_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VVM_VMADC => unsigned(vs2_val[i]) + unsigned(vs1_val[i]) + unsigned(bool_to_bits(vm_val[i])) > 2 ^ SEW - 1, + VVM_VMSBC => unsigned(vs2_val[i]) - unsigned(vs1_val[i]) - unsigned(bool_to_bits(vm_val[i])) < 0 + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmsbc.vx.yaml b/arch/inst/V/vmsbc.vx.yaml index a0cea382c2..6a1e1dd544 100644 --- a/arch/inst/V/vmsbc.vx.yaml +++ b/arch/inst/V/vmsbc.vx.yaml @@ -23,3 +23,41 @@ vmsbc.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_carry(num_elem, SEW, LMUL_pow, vd_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VXMC_VMADC => unsigned(vs2_val[i]) + unsigned(rs1_val) > 2 ^ SEW - 1, + VXMC_VMSBC => unsigned(vs2_val[i]) - unsigned(rs1_val) < 0 + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmsbc.vxm.yaml b/arch/inst/V/vmsbc.vxm.yaml index 9d535f80fb..e8c4aeee00 100644 --- a/arch/inst/V/vmsbc.vxm.yaml +++ b/arch/inst/V/vmsbc.vxm.yaml @@ -23,3 +23,42 @@ vmsbc.vxm: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask_carry(num_elem, 0b0, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_carry(num_elem, SEW, LMUL_pow, vd_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VXM_VMADC => unsigned(vs2_val[i]) + unsigned(rs1_val) + unsigned(bool_to_bits(vm_val[i])) > 2 ^ SEW - 1, + VXM_VMSBC => unsigned(vs2_val[i]) - unsigned(rs1_val) - unsigned(bool_to_bits(vm_val[i])) < 0 + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmsbf.m.yaml b/arch/inst/V/vmsbf.m.yaml index e7750f04e7..ec15c3a715 100644 --- a/arch/inst/V/vmsbf.m.yaml +++ b/arch/inst/V/vmsbf.m.yaml @@ -23,3 +23,40 @@ vmsbf.m: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = unsigned(vlenb) * 8; + + if illegal_normal(vd, vm) | not(assert_vstart(0)) | vd == vs2 + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, 0, vd_val, vm_val); + + found_elem : bool = false; + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + if vs2_val[i] then found_elem = true; + result[i] = if found_elem then false else true + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmseq.vi.yaml b/arch/inst/V/vmseq.vi.yaml index c8a602c6c6..d59bb33b33 100644 --- a/arch/inst/V/vmseq.vi.yaml +++ b/arch/inst/V/vmseq.vi.yaml @@ -25,3 +25,46 @@ vmseq.vi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VICMP_VMSEQ => vs2_val[i] == imm_val, + VICMP_VMSNE => vs2_val[i] != imm_val, + VICMP_VMSLEU => unsigned(vs2_val[i]) <= unsigned(imm_val), + VICMP_VMSLE => signed(vs2_val[i]) <= signed(imm_val), + VICMP_VMSGTU => unsigned(vs2_val[i]) > unsigned(imm_val), + VICMP_VMSGT => signed(vs2_val[i]) > signed(imm_val) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmseq.vv.yaml b/arch/inst/V/vmseq.vv.yaml index 80bbc72beb..1b32fb961c 100644 --- a/arch/inst/V/vmseq.vv.yaml +++ b/arch/inst/V/vmseq.vv.yaml @@ -25,3 +25,46 @@ vmseq.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VVCMP_VMSEQ => vs2_val[i] == vs1_val[i], + VVCMP_VMSNE => vs2_val[i] != vs1_val[i], + VVCMP_VMSLTU => unsigned(vs2_val[i]) < unsigned(vs1_val[i]), + VVCMP_VMSLT => signed(vs2_val[i]) < signed(vs1_val[i]), + VVCMP_VMSLEU => unsigned(vs2_val[i]) <= unsigned(vs1_val[i]), + VVCMP_VMSLE => signed(vs2_val[i]) <= signed(vs1_val[i]) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmseq.vx.yaml b/arch/inst/V/vmseq.vx.yaml index de42274d25..a12dea1ed2 100644 --- a/arch/inst/V/vmseq.vx.yaml +++ b/arch/inst/V/vmseq.vx.yaml @@ -25,3 +25,48 @@ vmseq.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VXCMP_VMSEQ => vs2_val[i] == rs1_val, + VXCMP_VMSNE => vs2_val[i] != rs1_val, + VXCMP_VMSLTU => unsigned(vs2_val[i]) < unsigned(rs1_val), + VXCMP_VMSLT => signed(vs2_val[i]) < signed(rs1_val), + VXCMP_VMSLEU => unsigned(vs2_val[i]) <= unsigned(rs1_val), + VXCMP_VMSLE => signed(vs2_val[i]) <= signed(rs1_val), + VXCMP_VMSGTU => unsigned(vs2_val[i]) > unsigned(rs1_val), + VXCMP_VMSGT => signed(vs2_val[i]) > signed(rs1_val) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmsgt.vi.yaml b/arch/inst/V/vmsgt.vi.yaml index f8be1a055b..bee4909589 100644 --- a/arch/inst/V/vmsgt.vi.yaml +++ b/arch/inst/V/vmsgt.vi.yaml @@ -25,3 +25,46 @@ vmsgt.vi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VICMP_VMSEQ => vs2_val[i] == imm_val, + VICMP_VMSNE => vs2_val[i] != imm_val, + VICMP_VMSLEU => unsigned(vs2_val[i]) <= unsigned(imm_val), + VICMP_VMSLE => signed(vs2_val[i]) <= signed(imm_val), + VICMP_VMSGTU => unsigned(vs2_val[i]) > unsigned(imm_val), + VICMP_VMSGT => signed(vs2_val[i]) > signed(imm_val) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmsgt.vx.yaml b/arch/inst/V/vmsgt.vx.yaml index a2c5b35b4a..97162b28d2 100644 --- a/arch/inst/V/vmsgt.vx.yaml +++ b/arch/inst/V/vmsgt.vx.yaml @@ -25,3 +25,48 @@ vmsgt.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VXCMP_VMSEQ => vs2_val[i] == rs1_val, + VXCMP_VMSNE => vs2_val[i] != rs1_val, + VXCMP_VMSLTU => unsigned(vs2_val[i]) < unsigned(rs1_val), + VXCMP_VMSLT => signed(vs2_val[i]) < signed(rs1_val), + VXCMP_VMSLEU => unsigned(vs2_val[i]) <= unsigned(rs1_val), + VXCMP_VMSLE => signed(vs2_val[i]) <= signed(rs1_val), + VXCMP_VMSGTU => unsigned(vs2_val[i]) > unsigned(rs1_val), + VXCMP_VMSGT => signed(vs2_val[i]) > signed(rs1_val) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmsgtu.vi.yaml b/arch/inst/V/vmsgtu.vi.yaml index 22629d07eb..00facedbfb 100644 --- a/arch/inst/V/vmsgtu.vi.yaml +++ b/arch/inst/V/vmsgtu.vi.yaml @@ -25,3 +25,46 @@ vmsgtu.vi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VICMP_VMSEQ => vs2_val[i] == imm_val, + VICMP_VMSNE => vs2_val[i] != imm_val, + VICMP_VMSLEU => unsigned(vs2_val[i]) <= unsigned(imm_val), + VICMP_VMSLE => signed(vs2_val[i]) <= signed(imm_val), + VICMP_VMSGTU => unsigned(vs2_val[i]) > unsigned(imm_val), + VICMP_VMSGT => signed(vs2_val[i]) > signed(imm_val) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmsgtu.vx.yaml b/arch/inst/V/vmsgtu.vx.yaml index 66795c86ed..e604954320 100644 --- a/arch/inst/V/vmsgtu.vx.yaml +++ b/arch/inst/V/vmsgtu.vx.yaml @@ -25,3 +25,48 @@ vmsgtu.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VXCMP_VMSEQ => vs2_val[i] == rs1_val, + VXCMP_VMSNE => vs2_val[i] != rs1_val, + VXCMP_VMSLTU => unsigned(vs2_val[i]) < unsigned(rs1_val), + VXCMP_VMSLT => signed(vs2_val[i]) < signed(rs1_val), + VXCMP_VMSLEU => unsigned(vs2_val[i]) <= unsigned(rs1_val), + VXCMP_VMSLE => signed(vs2_val[i]) <= signed(rs1_val), + VXCMP_VMSGTU => unsigned(vs2_val[i]) > unsigned(rs1_val), + VXCMP_VMSGT => signed(vs2_val[i]) > signed(rs1_val) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmsif.m.yaml b/arch/inst/V/vmsif.m.yaml index 78ca09e4f6..ab9310303c 100644 --- a/arch/inst/V/vmsif.m.yaml +++ b/arch/inst/V/vmsif.m.yaml @@ -23,3 +23,40 @@ vmsif.m: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = unsigned(vlenb) * 8; + + if illegal_normal(vd, vm) | not(assert_vstart(0)) | vd == vs2 + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, 0, vd_val, vm_val); + + found_elem : bool = false; + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = if found_elem then false else true; + if vs2_val[i] then found_elem = true + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmsle.vi.yaml b/arch/inst/V/vmsle.vi.yaml index 679dbd6c2e..aba08fed93 100644 --- a/arch/inst/V/vmsle.vi.yaml +++ b/arch/inst/V/vmsle.vi.yaml @@ -25,3 +25,46 @@ vmsle.vi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VICMP_VMSEQ => vs2_val[i] == imm_val, + VICMP_VMSNE => vs2_val[i] != imm_val, + VICMP_VMSLEU => unsigned(vs2_val[i]) <= unsigned(imm_val), + VICMP_VMSLE => signed(vs2_val[i]) <= signed(imm_val), + VICMP_VMSGTU => unsigned(vs2_val[i]) > unsigned(imm_val), + VICMP_VMSGT => signed(vs2_val[i]) > signed(imm_val) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmsle.vv.yaml b/arch/inst/V/vmsle.vv.yaml index 795714dea6..fbdfbb98e1 100644 --- a/arch/inst/V/vmsle.vv.yaml +++ b/arch/inst/V/vmsle.vv.yaml @@ -25,3 +25,46 @@ vmsle.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VVCMP_VMSEQ => vs2_val[i] == vs1_val[i], + VVCMP_VMSNE => vs2_val[i] != vs1_val[i], + VVCMP_VMSLTU => unsigned(vs2_val[i]) < unsigned(vs1_val[i]), + VVCMP_VMSLT => signed(vs2_val[i]) < signed(vs1_val[i]), + VVCMP_VMSLEU => unsigned(vs2_val[i]) <= unsigned(vs1_val[i]), + VVCMP_VMSLE => signed(vs2_val[i]) <= signed(vs1_val[i]) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmsle.vx.yaml b/arch/inst/V/vmsle.vx.yaml index c235c11876..38cf4c89be 100644 --- a/arch/inst/V/vmsle.vx.yaml +++ b/arch/inst/V/vmsle.vx.yaml @@ -25,3 +25,48 @@ vmsle.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VXCMP_VMSEQ => vs2_val[i] == rs1_val, + VXCMP_VMSNE => vs2_val[i] != rs1_val, + VXCMP_VMSLTU => unsigned(vs2_val[i]) < unsigned(rs1_val), + VXCMP_VMSLT => signed(vs2_val[i]) < signed(rs1_val), + VXCMP_VMSLEU => unsigned(vs2_val[i]) <= unsigned(rs1_val), + VXCMP_VMSLE => signed(vs2_val[i]) <= signed(rs1_val), + VXCMP_VMSGTU => unsigned(vs2_val[i]) > unsigned(rs1_val), + VXCMP_VMSGT => signed(vs2_val[i]) > signed(rs1_val) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmsleu.vi.yaml b/arch/inst/V/vmsleu.vi.yaml index 94e01f2bc3..61361314f1 100644 --- a/arch/inst/V/vmsleu.vi.yaml +++ b/arch/inst/V/vmsleu.vi.yaml @@ -25,3 +25,46 @@ vmsleu.vi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VICMP_VMSEQ => vs2_val[i] == imm_val, + VICMP_VMSNE => vs2_val[i] != imm_val, + VICMP_VMSLEU => unsigned(vs2_val[i]) <= unsigned(imm_val), + VICMP_VMSLE => signed(vs2_val[i]) <= signed(imm_val), + VICMP_VMSGTU => unsigned(vs2_val[i]) > unsigned(imm_val), + VICMP_VMSGT => signed(vs2_val[i]) > signed(imm_val) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmsleu.vv.yaml b/arch/inst/V/vmsleu.vv.yaml index 73c263c413..81c3ccee20 100644 --- a/arch/inst/V/vmsleu.vv.yaml +++ b/arch/inst/V/vmsleu.vv.yaml @@ -25,3 +25,46 @@ vmsleu.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VVCMP_VMSEQ => vs2_val[i] == vs1_val[i], + VVCMP_VMSNE => vs2_val[i] != vs1_val[i], + VVCMP_VMSLTU => unsigned(vs2_val[i]) < unsigned(vs1_val[i]), + VVCMP_VMSLT => signed(vs2_val[i]) < signed(vs1_val[i]), + VVCMP_VMSLEU => unsigned(vs2_val[i]) <= unsigned(vs1_val[i]), + VVCMP_VMSLE => signed(vs2_val[i]) <= signed(vs1_val[i]) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmsleu.vx.yaml b/arch/inst/V/vmsleu.vx.yaml index 0d02c39ab2..83cb327432 100644 --- a/arch/inst/V/vmsleu.vx.yaml +++ b/arch/inst/V/vmsleu.vx.yaml @@ -25,3 +25,48 @@ vmsleu.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VXCMP_VMSEQ => vs2_val[i] == rs1_val, + VXCMP_VMSNE => vs2_val[i] != rs1_val, + VXCMP_VMSLTU => unsigned(vs2_val[i]) < unsigned(rs1_val), + VXCMP_VMSLT => signed(vs2_val[i]) < signed(rs1_val), + VXCMP_VMSLEU => unsigned(vs2_val[i]) <= unsigned(rs1_val), + VXCMP_VMSLE => signed(vs2_val[i]) <= signed(rs1_val), + VXCMP_VMSGTU => unsigned(vs2_val[i]) > unsigned(rs1_val), + VXCMP_VMSGT => signed(vs2_val[i]) > signed(rs1_val) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmslt.vv.yaml b/arch/inst/V/vmslt.vv.yaml index 9d02205570..83549f535c 100644 --- a/arch/inst/V/vmslt.vv.yaml +++ b/arch/inst/V/vmslt.vv.yaml @@ -25,3 +25,46 @@ vmslt.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VVCMP_VMSEQ => vs2_val[i] == vs1_val[i], + VVCMP_VMSNE => vs2_val[i] != vs1_val[i], + VVCMP_VMSLTU => unsigned(vs2_val[i]) < unsigned(vs1_val[i]), + VVCMP_VMSLT => signed(vs2_val[i]) < signed(vs1_val[i]), + VVCMP_VMSLEU => unsigned(vs2_val[i]) <= unsigned(vs1_val[i]), + VVCMP_VMSLE => signed(vs2_val[i]) <= signed(vs1_val[i]) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmslt.vx.yaml b/arch/inst/V/vmslt.vx.yaml index ec71bf806c..cc327acb1b 100644 --- a/arch/inst/V/vmslt.vx.yaml +++ b/arch/inst/V/vmslt.vx.yaml @@ -25,3 +25,48 @@ vmslt.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VXCMP_VMSEQ => vs2_val[i] == rs1_val, + VXCMP_VMSNE => vs2_val[i] != rs1_val, + VXCMP_VMSLTU => unsigned(vs2_val[i]) < unsigned(rs1_val), + VXCMP_VMSLT => signed(vs2_val[i]) < signed(rs1_val), + VXCMP_VMSLEU => unsigned(vs2_val[i]) <= unsigned(rs1_val), + VXCMP_VMSLE => signed(vs2_val[i]) <= signed(rs1_val), + VXCMP_VMSGTU => unsigned(vs2_val[i]) > unsigned(rs1_val), + VXCMP_VMSGT => signed(vs2_val[i]) > signed(rs1_val) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmsltu.vv.yaml b/arch/inst/V/vmsltu.vv.yaml index 86bca96025..b55421b2ec 100644 --- a/arch/inst/V/vmsltu.vv.yaml +++ b/arch/inst/V/vmsltu.vv.yaml @@ -25,3 +25,46 @@ vmsltu.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VVCMP_VMSEQ => vs2_val[i] == vs1_val[i], + VVCMP_VMSNE => vs2_val[i] != vs1_val[i], + VVCMP_VMSLTU => unsigned(vs2_val[i]) < unsigned(vs1_val[i]), + VVCMP_VMSLT => signed(vs2_val[i]) < signed(vs1_val[i]), + VVCMP_VMSLEU => unsigned(vs2_val[i]) <= unsigned(vs1_val[i]), + VVCMP_VMSLE => signed(vs2_val[i]) <= signed(vs1_val[i]) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmsltu.vx.yaml b/arch/inst/V/vmsltu.vx.yaml index 57b2ded82e..fcdf46db34 100644 --- a/arch/inst/V/vmsltu.vx.yaml +++ b/arch/inst/V/vmsltu.vx.yaml @@ -25,3 +25,48 @@ vmsltu.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VXCMP_VMSEQ => vs2_val[i] == rs1_val, + VXCMP_VMSNE => vs2_val[i] != rs1_val, + VXCMP_VMSLTU => unsigned(vs2_val[i]) < unsigned(rs1_val), + VXCMP_VMSLT => signed(vs2_val[i]) < signed(rs1_val), + VXCMP_VMSLEU => unsigned(vs2_val[i]) <= unsigned(rs1_val), + VXCMP_VMSLE => signed(vs2_val[i]) <= signed(rs1_val), + VXCMP_VMSGTU => unsigned(vs2_val[i]) > unsigned(rs1_val), + VXCMP_VMSGT => signed(vs2_val[i]) > signed(rs1_val) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmsne.vi.yaml b/arch/inst/V/vmsne.vi.yaml index 2961f894d7..d6f0f68bbd 100644 --- a/arch/inst/V/vmsne.vi.yaml +++ b/arch/inst/V/vmsne.vi.yaml @@ -25,3 +25,46 @@ vmsne.vi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VICMP_VMSEQ => vs2_val[i] == imm_val, + VICMP_VMSNE => vs2_val[i] != imm_val, + VICMP_VMSLEU => unsigned(vs2_val[i]) <= unsigned(imm_val), + VICMP_VMSLE => signed(vs2_val[i]) <= signed(imm_val), + VICMP_VMSGTU => unsigned(vs2_val[i]) > unsigned(imm_val), + VICMP_VMSGT => signed(vs2_val[i]) > signed(imm_val) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmsne.vv.yaml b/arch/inst/V/vmsne.vv.yaml index e7de64dc6b..5b6609cf78 100644 --- a/arch/inst/V/vmsne.vv.yaml +++ b/arch/inst/V/vmsne.vv.yaml @@ -25,3 +25,46 @@ vmsne.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VVCMP_VMSEQ => vs2_val[i] == vs1_val[i], + VVCMP_VMSNE => vs2_val[i] != vs1_val[i], + VVCMP_VMSLTU => unsigned(vs2_val[i]) < unsigned(vs1_val[i]), + VVCMP_VMSLT => signed(vs2_val[i]) < signed(vs1_val[i]), + VVCMP_VMSLEU => unsigned(vs2_val[i]) <= unsigned(vs1_val[i]), + VVCMP_VMSLE => signed(vs2_val[i]) <= signed(vs1_val[i]) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmsne.vx.yaml b/arch/inst/V/vmsne.vx.yaml index 4daf4978a1..06e16bf7f9 100644 --- a/arch/inst/V/vmsne.vx.yaml +++ b/arch/inst/V/vmsne.vx.yaml @@ -25,3 +25,48 @@ vmsne.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let res : bool = match funct6 { + VXCMP_VMSEQ => vs2_val[i] == rs1_val, + VXCMP_VMSNE => vs2_val[i] != rs1_val, + VXCMP_VMSLTU => unsigned(vs2_val[i]) < unsigned(rs1_val), + VXCMP_VMSLT => signed(vs2_val[i]) < signed(rs1_val), + VXCMP_VMSLEU => unsigned(vs2_val[i]) <= unsigned(rs1_val), + VXCMP_VMSLE => signed(vs2_val[i]) <= signed(rs1_val), + VXCMP_VMSGTU => unsigned(vs2_val[i]) > unsigned(rs1_val), + VXCMP_VMSGT => signed(vs2_val[i]) > signed(rs1_val) + }; + result[i] = res + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmsof.m.yaml b/arch/inst/V/vmsof.m.yaml index 557b2aec42..a2856b1a40 100644 --- a/arch/inst/V/vmsof.m.yaml +++ b/arch/inst/V/vmsof.m.yaml @@ -23,3 +23,44 @@ vmsof.m: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = unsigned(vlenb) * 8; + + if illegal_normal(vd, vm) | not(assert_vstart(0)) | vd == vs2 + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs2_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_cmp(num_elem, SEW, 0, vd_val, vm_val); + + found_elem : bool = false; + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + if vs2_val[i] & not(found_elem) then { + result[i] = true; + found_elem = true + } else { + result[i] = false + } + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmul.vv.yaml b/arch/inst/V/vmul.vv.yaml index 6fb513658d..4b3fa3b2f7 100644 --- a/arch/inst/V/vmul.vv.yaml +++ b/arch/inst/V/vmul.vv.yaml @@ -25,3 +25,85 @@ vmul.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVV_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), 0), + MVV_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), SEW), + MVV_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(vs1_val[i]), SEW), + MVV_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(vs1_val[i]), SEW), + MVV_VDIVU => { + let q : int = if unsigned(vs1_val[i]) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i])); + to_bits(SEW, q) + }, + MVV_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(vs1_val[i]) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(vs1_val[i])); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVV_VREMU => { + let r : int = if unsigned(vs1_val[i]) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i])); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVV_VREM => { + let r : int = if signed(vs1_val[i]) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(vs1_val[i])); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmul.vx.yaml b/arch/inst/V/vmul.vx.yaml index eafe8b5d21..3873090bf5 100644 --- a/arch/inst/V/vmul.vx.yaml +++ b/arch/inst/V/vmul.vx.yaml @@ -25,3 +25,94 @@ vmul.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVX_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VSLIDE1UP => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + MVX_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + }, + MVX_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), 0), + MVX_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), SEW), + MVX_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VDIVU => { + let q : int = if unsigned(rs1_val) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(rs1_val)); + to_bits(SEW, q) + }, + MVX_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(rs1_val) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVX_VREMU => { + let r : int = if unsigned(rs1_val) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned (rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVX_VREM => { + let r : int = if signed(rs1_val) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmulh.vv.yaml b/arch/inst/V/vmulh.vv.yaml index 6e64f395f6..d87b08e6db 100644 --- a/arch/inst/V/vmulh.vv.yaml +++ b/arch/inst/V/vmulh.vv.yaml @@ -25,3 +25,85 @@ vmulh.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVV_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), 0), + MVV_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), SEW), + MVV_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(vs1_val[i]), SEW), + MVV_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(vs1_val[i]), SEW), + MVV_VDIVU => { + let q : int = if unsigned(vs1_val[i]) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i])); + to_bits(SEW, q) + }, + MVV_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(vs1_val[i]) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(vs1_val[i])); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVV_VREMU => { + let r : int = if unsigned(vs1_val[i]) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i])); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVV_VREM => { + let r : int = if signed(vs1_val[i]) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(vs1_val[i])); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmulh.vx.yaml b/arch/inst/V/vmulh.vx.yaml index b4556a8a99..a17f3505ad 100644 --- a/arch/inst/V/vmulh.vx.yaml +++ b/arch/inst/V/vmulh.vx.yaml @@ -25,3 +25,94 @@ vmulh.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVX_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VSLIDE1UP => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + MVX_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + }, + MVX_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), 0), + MVX_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), SEW), + MVX_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VDIVU => { + let q : int = if unsigned(rs1_val) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(rs1_val)); + to_bits(SEW, q) + }, + MVX_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(rs1_val) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVX_VREMU => { + let r : int = if unsigned(rs1_val) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned (rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVX_VREM => { + let r : int = if signed(rs1_val) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmulhsu.vv.yaml b/arch/inst/V/vmulhsu.vv.yaml index 9cf431e076..711ee22542 100644 --- a/arch/inst/V/vmulhsu.vv.yaml +++ b/arch/inst/V/vmulhsu.vv.yaml @@ -25,3 +25,85 @@ vmulhsu.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVV_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), 0), + MVV_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), SEW), + MVV_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(vs1_val[i]), SEW), + MVV_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(vs1_val[i]), SEW), + MVV_VDIVU => { + let q : int = if unsigned(vs1_val[i]) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i])); + to_bits(SEW, q) + }, + MVV_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(vs1_val[i]) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(vs1_val[i])); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVV_VREMU => { + let r : int = if unsigned(vs1_val[i]) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i])); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVV_VREM => { + let r : int = if signed(vs1_val[i]) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(vs1_val[i])); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmulhsu.vx.yaml b/arch/inst/V/vmulhsu.vx.yaml index 4a699eb0a2..0b6a12c397 100644 --- a/arch/inst/V/vmulhsu.vx.yaml +++ b/arch/inst/V/vmulhsu.vx.yaml @@ -25,3 +25,94 @@ vmulhsu.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVX_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VSLIDE1UP => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + MVX_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + }, + MVX_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), 0), + MVX_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), SEW), + MVX_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VDIVU => { + let q : int = if unsigned(rs1_val) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(rs1_val)); + to_bits(SEW, q) + }, + MVX_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(rs1_val) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVX_VREMU => { + let r : int = if unsigned(rs1_val) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned (rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVX_VREM => { + let r : int = if signed(rs1_val) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmulhu.vv.yaml b/arch/inst/V/vmulhu.vv.yaml index 77fa0fbac8..37863f11da 100644 --- a/arch/inst/V/vmulhu.vv.yaml +++ b/arch/inst/V/vmulhu.vv.yaml @@ -25,3 +25,85 @@ vmulhu.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVV_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), 0), + MVV_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), SEW), + MVV_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(vs1_val[i]), SEW), + MVV_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(vs1_val[i]), SEW), + MVV_VDIVU => { + let q : int = if unsigned(vs1_val[i]) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i])); + to_bits(SEW, q) + }, + MVV_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(vs1_val[i]) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(vs1_val[i])); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVV_VREMU => { + let r : int = if unsigned(vs1_val[i]) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i])); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVV_VREM => { + let r : int = if signed(vs1_val[i]) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(vs1_val[i])); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmulhu.vx.yaml b/arch/inst/V/vmulhu.vx.yaml index 7d570bdee5..aa3469a8fe 100644 --- a/arch/inst/V/vmulhu.vx.yaml +++ b/arch/inst/V/vmulhu.vx.yaml @@ -25,3 +25,94 @@ vmulhu.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVX_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VSLIDE1UP => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + MVX_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + }, + MVX_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), 0), + MVX_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), SEW), + MVX_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VDIVU => { + let q : int = if unsigned(rs1_val) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(rs1_val)); + to_bits(SEW, q) + }, + MVX_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(rs1_val) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVX_VREMU => { + let r : int = if unsigned(rs1_val) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned (rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVX_VREM => { + let r : int = if signed(rs1_val) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmv.s.x.yaml b/arch/inst/V/vmv.s.x.yaml index f2de8a25f3..61d3d121ab 100644 --- a/arch/inst/V/vmv.s.x.yaml +++ b/arch/inst/V/vmv.s.x.yaml @@ -21,3 +21,43 @@ vmv.s.x: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let num_elem = get_num_elem(0, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + assert(num_elem > 0); + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, 0b1, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, 'm); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, 0, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, 0, vd_val, vm_val); + + /* one body element */ + if mask[0] then result[0] = rs1_val; + + /* others treated as tail elements */ + let tail_ag : agtype = get_vtype_vta(); + foreach (i from 1 to (num_elem - 1)) { + result[i] = match tail_ag { + UNDISTURBED => vd_val[i], + AGNOSTIC => vd_val[i] /* TODO: configuration support */ + } + }; + + write_vreg(num_elem, SEW, 0, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmv.v.i.yaml b/arch/inst/V/vmv.v.i.yaml index 9644164d00..723ff51132 100644 --- a/arch/inst/V/vmv.v.i.yaml +++ b/arch/inst/V/vmv.v.i.yaml @@ -21,3 +21,35 @@ vmv.v.i: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, 0b1, 0b00000); + let imm_val : bits('m) = sign_extend(simm); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then result[i] = imm_val + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmv.v.v.yaml b/arch/inst/V/vmv.v.v.yaml index 81949c27ff..61d9db630a 100644 --- a/arch/inst/V/vmv.v.v.yaml +++ b/arch/inst/V/vmv.v.v.yaml @@ -21,3 +21,35 @@ vmv.v.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, 0b1, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then result[i] = vs1_val[i] + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmv.v.x.yaml b/arch/inst/V/vmv.v.x.yaml index 89ec7dbc6d..5f052814ac 100644 --- a/arch/inst/V/vmv.v.x.yaml +++ b/arch/inst/V/vmv.v.x.yaml @@ -21,3 +21,35 @@ vmv.v.x: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let rs1_val : bits('m) = get_scalar(rs1, 'm); + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, 0b1, 0b00000); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then result[i] = rs1_val + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmv.x.s.yaml b/arch/inst/V/vmv.x.s.yaml index 11b76da129..1fa4cc26bc 100644 --- a/arch/inst/V/vmv.x.s.yaml +++ b/arch/inst/V/vmv.x.s.yaml @@ -21,3 +21,27 @@ vmv.x.s: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let num_elem = get_num_elem(0, SEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + assert(num_elem > 0); + let 'n = num_elem; + let 'm = SEW; + + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, 0, vs2); + X(rd) = if sizeof(xlen) < SEW then slice(vs2_val[0], 0, sizeof(xlen)) + else if sizeof(xlen) > SEW then sign_extend(vs2_val[0]) + else vs2_val[0]; + vstart = zeros(); + + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmv1r.v.yaml b/arch/inst/V/vmv1r.v.yaml index 1f1eccf9b0..a74368bae0 100644 --- a/arch/inst/V/vmv1r.v.yaml +++ b/arch/inst/V/vmv1r.v.yaml @@ -21,3 +21,35 @@ vmv1r.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let start_element = get_start_element(); + let SEW = get_sew(); + let imm_val = unsigned(zero_extend(sizeof(xlen), simm)); + let EMUL = imm_val + 1; + + if not(EMUL == 1 | EMUL == 2 | EMUL == 4 | EMUL == 8) then { handle_illegal(); return RETIRE_FAIL }; + + let EMUL_pow = log2(EMUL); + let num_elem = get_num_elem(EMUL_pow, SEW); + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, 0b1, 0b00000); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, EMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, EMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + + foreach (i from 0 to (num_elem - 1)) { + result[i] = if i < start_element then vd_val[i] else vs2_val[i] + }; + + write_vreg(num_elem, SEW, EMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmv2r.v.yaml b/arch/inst/V/vmv2r.v.yaml index 6e6a392296..0d918a83cb 100644 --- a/arch/inst/V/vmv2r.v.yaml +++ b/arch/inst/V/vmv2r.v.yaml @@ -21,3 +21,35 @@ vmv2r.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let start_element = get_start_element(); + let SEW = get_sew(); + let imm_val = unsigned(zero_extend(sizeof(xlen), simm)); + let EMUL = imm_val + 1; + + if not(EMUL == 1 | EMUL == 2 | EMUL == 4 | EMUL == 8) then { handle_illegal(); return RETIRE_FAIL }; + + let EMUL_pow = log2(EMUL); + let num_elem = get_num_elem(EMUL_pow, SEW); + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, 0b1, 0b00000); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, EMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, EMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + + foreach (i from 0 to (num_elem - 1)) { + result[i] = if i < start_element then vd_val[i] else vs2_val[i] + }; + + write_vreg(num_elem, SEW, EMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmv4r.v.yaml b/arch/inst/V/vmv4r.v.yaml index c13c77c45b..1a8ac2a11d 100644 --- a/arch/inst/V/vmv4r.v.yaml +++ b/arch/inst/V/vmv4r.v.yaml @@ -21,3 +21,35 @@ vmv4r.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let start_element = get_start_element(); + let SEW = get_sew(); + let imm_val = unsigned(zero_extend(sizeof(xlen), simm)); + let EMUL = imm_val + 1; + + if not(EMUL == 1 | EMUL == 2 | EMUL == 4 | EMUL == 8) then { handle_illegal(); return RETIRE_FAIL }; + + let EMUL_pow = log2(EMUL); + let num_elem = get_num_elem(EMUL_pow, SEW); + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, 0b1, 0b00000); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, EMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, EMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + + foreach (i from 0 to (num_elem - 1)) { + result[i] = if i < start_element then vd_val[i] else vs2_val[i] + }; + + write_vreg(num_elem, SEW, EMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmv8r.v.yaml b/arch/inst/V/vmv8r.v.yaml index 45853b9e4f..842f70850a 100644 --- a/arch/inst/V/vmv8r.v.yaml +++ b/arch/inst/V/vmv8r.v.yaml @@ -21,3 +21,35 @@ vmv8r.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let start_element = get_start_element(); + let SEW = get_sew(); + let imm_val = unsigned(zero_extend(sizeof(xlen), simm)); + let EMUL = imm_val + 1; + + if not(EMUL == 1 | EMUL == 2 | EMUL == 4 | EMUL == 8) then { handle_illegal(); return RETIRE_FAIL }; + + let EMUL_pow = log2(EMUL); + let num_elem = get_num_elem(EMUL_pow, SEW); + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, 0b1, 0b00000); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, EMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, EMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + + foreach (i from 0 to (num_elem - 1)) { + result[i] = if i < start_element then vd_val[i] else vs2_val[i] + }; + + write_vreg(num_elem, SEW, EMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmxnor.mm.yaml b/arch/inst/V/vmxnor.mm.yaml index 000daae4cd..277019b7f3 100644 --- a/arch/inst/V/vmxnor.mm.yaml +++ b/arch/inst/V/vmxnor.mm.yaml @@ -23,3 +23,46 @@ vmxnor.mm: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = unsigned(vlenb) * 8; + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vs1_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vs1); + let vs2_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_carry(num_elem, SEW, 0, vd_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MM_VMAND => vs2_val[i] & vs1_val[i], + MM_VMNAND => not(vs2_val[i] & vs1_val[i]), + MM_VMANDNOT => vs2_val[i] & not(vs1_val[i]), + MM_VMXOR => vs2_val[i] != vs1_val[i], + MM_VMOR => vs2_val[i] | vs1_val[i], + MM_VMNOR => not(vs2_val[i] | vs1_val[i]), + MM_VMORNOT => vs2_val[i] | not(vs1_val[i]), + MM_VMXNOR => vs2_val[i] == vs1_val[i] + } + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vmxor.mm.yaml b/arch/inst/V/vmxor.mm.yaml index b3d63e253a..61a2fbdbc3 100644 --- a/arch/inst/V/vmxor.mm.yaml +++ b/arch/inst/V/vmxor.mm.yaml @@ -23,3 +23,46 @@ vmxor.mm: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = unsigned(vlenb) * 8; + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vs1_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vs1); + let vs2_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vs2); + let vd_val : vector('n, dec, bool) = read_vmask(num_elem, 0b0, vd); + result : vector('n, dec, bool) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result_carry(num_elem, SEW, 0, vd_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MM_VMAND => vs2_val[i] & vs1_val[i], + MM_VMNAND => not(vs2_val[i] & vs1_val[i]), + MM_VMANDNOT => vs2_val[i] & not(vs1_val[i]), + MM_VMXOR => vs2_val[i] != vs1_val[i], + MM_VMOR => vs2_val[i] | vs1_val[i], + MM_VMNOR => not(vs2_val[i] | vs1_val[i]), + MM_VMORNOT => vs2_val[i] | not(vs1_val[i]), + MM_VMXNOR => vs2_val[i] == vs1_val[i] + } + } + }; + + write_vmask(num_elem, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vnclip.wi.yaml b/arch/inst/V/vnclip.wi.yaml index 27a0e2efce..6aa71810dd 100644 --- a/arch/inst/V/vnclip.wi.yaml +++ b/arch/inst/V/vnclip.wi.yaml @@ -25,3 +25,56 @@ vnclip.wi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + assert(SEW_widen <= 64); + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let shift_amount = get_shift_amount(imm_val, SEW_widen); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + result[i] = match funct6 { + NI_VNCLIPU => { + let result_wide = (vs2_val[i] >> shift_amount) + zero_extend('o, rounding_incr); + unsigned_saturation('m, result_wide) + }, + NI_VNCLIP => { + let v_double : bits('m * 4) = sign_extend(vs2_val[i]); + let result_wide = slice(v_double >> shift_amount, 0, 'o) + zero_extend('o, rounding_incr); + signed_saturation('m, result_wide) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vnclip.wv.yaml b/arch/inst/V/vnclip.wv.yaml index 6a0ccb5ba3..57e4903bef 100644 --- a/arch/inst/V/vnclip.wv.yaml +++ b/arch/inst/V/vnclip.wv.yaml @@ -25,3 +25,56 @@ vnclip.wv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + assert(SEW_widen <= 64); + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let shift_amount = get_shift_amount(vs1_val[i], SEW_widen); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + result[i] = match funct6 { + NV_VNCLIPU => { + let result_wide = (vs2_val[i] >> shift_amount) + zero_extend('o, rounding_incr); + unsigned_saturation('m, result_wide); + }, + NV_VNCLIP => { + let v_double : bits('m * 4) = sign_extend(vs2_val[i]); + let result_wide = slice(v_double >> shift_amount, 0, 'o) + zero_extend('o, rounding_incr); + signed_saturation('m, result_wide); + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vnclip.wx.yaml b/arch/inst/V/vnclip.wx.yaml index f05a049b5b..0f7d96d000 100644 --- a/arch/inst/V/vnclip.wx.yaml +++ b/arch/inst/V/vnclip.wx.yaml @@ -25,3 +25,56 @@ vnclip.wx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + assert(SEW_widen <= 64); + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let shift_amount = get_shift_amount(rs1_val, SEW_widen); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + result[i] = match funct6 { + NX_VNCLIPU => { + let result_wide = (vs2_val[i] >> shift_amount) + zero_extend('o, rounding_incr); + unsigned_saturation('m, result_wide) + }, + NX_VNCLIP => { + let v_double : bits('m * 4) = sign_extend(vs2_val[i]); + let result_wide = slice(v_double >> shift_amount, 0, 'o) + zero_extend('o, rounding_incr); + signed_saturation('m, result_wide) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vnclipu.wi.yaml b/arch/inst/V/vnclipu.wi.yaml index 98b5ec564d..383cdcda43 100644 --- a/arch/inst/V/vnclipu.wi.yaml +++ b/arch/inst/V/vnclipu.wi.yaml @@ -25,3 +25,56 @@ vnclipu.wi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + assert(SEW_widen <= 64); + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let shift_amount = get_shift_amount(imm_val, SEW_widen); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + result[i] = match funct6 { + NI_VNCLIPU => { + let result_wide = (vs2_val[i] >> shift_amount) + zero_extend('o, rounding_incr); + unsigned_saturation('m, result_wide) + }, + NI_VNCLIP => { + let v_double : bits('m * 4) = sign_extend(vs2_val[i]); + let result_wide = slice(v_double >> shift_amount, 0, 'o) + zero_extend('o, rounding_incr); + signed_saturation('m, result_wide) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vnclipu.wv.yaml b/arch/inst/V/vnclipu.wv.yaml index 3a9a781930..2dd7ca37a3 100644 --- a/arch/inst/V/vnclipu.wv.yaml +++ b/arch/inst/V/vnclipu.wv.yaml @@ -25,3 +25,56 @@ vnclipu.wv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + assert(SEW_widen <= 64); + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let shift_amount = get_shift_amount(vs1_val[i], SEW_widen); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + result[i] = match funct6 { + NV_VNCLIPU => { + let result_wide = (vs2_val[i] >> shift_amount) + zero_extend('o, rounding_incr); + unsigned_saturation('m, result_wide); + }, + NV_VNCLIP => { + let v_double : bits('m * 4) = sign_extend(vs2_val[i]); + let result_wide = slice(v_double >> shift_amount, 0, 'o) + zero_extend('o, rounding_incr); + signed_saturation('m, result_wide); + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vnclipu.wx.yaml b/arch/inst/V/vnclipu.wx.yaml index d45a132e69..663fcb09fc 100644 --- a/arch/inst/V/vnclipu.wx.yaml +++ b/arch/inst/V/vnclipu.wx.yaml @@ -25,3 +25,56 @@ vnclipu.wx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + assert(SEW_widen <= 64); + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + let shift_amount = get_shift_amount(rs1_val, SEW_widen); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + result[i] = match funct6 { + NX_VNCLIPU => { + let result_wide = (vs2_val[i] >> shift_amount) + zero_extend('o, rounding_incr); + unsigned_saturation('m, result_wide) + }, + NX_VNCLIP => { + let v_double : bits('m * 4) = sign_extend(vs2_val[i]); + let result_wide = slice(v_double >> shift_amount, 0, 'o) + zero_extend('o, rounding_incr); + signed_saturation('m, result_wide) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vnmsac.vv.yaml b/arch/inst/V/vnmsac.vv.yaml index 7b953c6334..7b0fea34ae 100644 --- a/arch/inst/V/vnmsac.vv.yaml +++ b/arch/inst/V/vnmsac.vv.yaml @@ -25,3 +25,43 @@ vnmsac.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVV_VMACC => get_slice_int(SEW, signed(vs1_val[i]) * signed(vs2_val[i]), 0) + vd_val[i], + MVV_VNMSAC => vd_val[i] - get_slice_int(SEW, signed(vs1_val[i]) * signed(vs2_val[i]), 0), + MVV_VMADD => get_slice_int(SEW, signed(vs1_val[i]) * signed(vd_val[i]), 0) + vs2_val[i], + MVV_VNMSUB => vs2_val[i] - get_slice_int(SEW, signed(vs1_val[i]) * signed(vd_val[i]), 0) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vnmsac.vx.yaml b/arch/inst/V/vnmsac.vx.yaml index ca63e5db1f..54eeead203 100644 --- a/arch/inst/V/vnmsac.vx.yaml +++ b/arch/inst/V/vnmsac.vx.yaml @@ -25,3 +25,43 @@ vnmsac.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVX_VMACC => get_slice_int(SEW, signed(rs1_val) * signed(vs2_val[i]), 0) + vd_val[i], + MVX_VNMSAC => vd_val[i] - get_slice_int(SEW, signed(rs1_val) * signed(vs2_val[i]), 0), + MVX_VMADD => get_slice_int(SEW, signed(rs1_val) * signed(vd_val[i]), 0) + vs2_val[i], + MVX_VNMSUB => vs2_val[i] - get_slice_int(SEW, signed(rs1_val) * signed(vd_val[i]), 0) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vnmsub.vv.yaml b/arch/inst/V/vnmsub.vv.yaml index a952abcc29..53f280b460 100644 --- a/arch/inst/V/vnmsub.vv.yaml +++ b/arch/inst/V/vnmsub.vv.yaml @@ -25,3 +25,43 @@ vnmsub.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVV_VMACC => get_slice_int(SEW, signed(vs1_val[i]) * signed(vs2_val[i]), 0) + vd_val[i], + MVV_VNMSAC => vd_val[i] - get_slice_int(SEW, signed(vs1_val[i]) * signed(vs2_val[i]), 0), + MVV_VMADD => get_slice_int(SEW, signed(vs1_val[i]) * signed(vd_val[i]), 0) + vs2_val[i], + MVV_VNMSUB => vs2_val[i] - get_slice_int(SEW, signed(vs1_val[i]) * signed(vd_val[i]), 0) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vnmsub.vx.yaml b/arch/inst/V/vnmsub.vx.yaml index 21a0b6366c..927704a037 100644 --- a/arch/inst/V/vnmsub.vx.yaml +++ b/arch/inst/V/vnmsub.vx.yaml @@ -25,3 +25,43 @@ vnmsub.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVX_VMACC => get_slice_int(SEW, signed(rs1_val) * signed(vs2_val[i]), 0) + vd_val[i], + MVX_VNMSAC => vd_val[i] - get_slice_int(SEW, signed(rs1_val) * signed(vs2_val[i]), 0), + MVX_VMADD => get_slice_int(SEW, signed(rs1_val) * signed(vd_val[i]), 0) + vs2_val[i], + MVX_VNMSUB => vs2_val[i] - get_slice_int(SEW, signed(rs1_val) * signed(vd_val[i]), 0) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vnsra.wi.yaml b/arch/inst/V/vnsra.wi.yaml index e3adad78a2..9e7627cf16 100644 --- a/arch/inst/V/vnsra.wi.yaml +++ b/arch/inst/V/vnsra.wi.yaml @@ -25,3 +25,55 @@ vnsra.wi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + assert(SEW_widen <= 64); + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + NIS_VNSRL => { + let shift_amount = get_shift_amount(imm_val, SEW_widen); + slice(vs2_val[i] >> shift_amount, 0, SEW) + }, + NIS_VNSRA => { + let shift_amount = get_shift_amount(imm_val, SEW_widen); + let v_double : bits('o * 2) = sign_extend(vs2_val[i]); + let arith_shifted : bits('o) = slice(v_double >> shift_amount, 0, SEW_widen); + slice(arith_shifted, 0, SEW) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vnsra.wv.yaml b/arch/inst/V/vnsra.wv.yaml index f8b56532e9..e51d5c171e 100644 --- a/arch/inst/V/vnsra.wv.yaml +++ b/arch/inst/V/vnsra.wv.yaml @@ -25,3 +25,55 @@ vnsra.wv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + assert(SEW_widen <= 64); + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + NVS_VNSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW_widen); + slice(vs2_val[i] >> shift_amount, 0, SEW) + }, + NVS_VNSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW_widen); + let v_double : bits('o * 2) = sign_extend(vs2_val[i]); + let arith_shifted : bits('o) = slice(v_double >> shift_amount, 0, SEW_widen); + slice(arith_shifted, 0, SEW) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vnsra.wx.yaml b/arch/inst/V/vnsra.wx.yaml index 223d3664ed..4c36210f91 100644 --- a/arch/inst/V/vnsra.wx.yaml +++ b/arch/inst/V/vnsra.wx.yaml @@ -25,3 +25,55 @@ vnsra.wx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + assert(SEW_widen <= 64); + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + NXS_VNSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW_widen); + slice(vs2_val[i] >> shift_amount, 0, SEW) + }, + NXS_VNSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW_widen); + let v_double : bits('o * 2) = sign_extend(vs2_val[i]); + let arith_shifted : bits('o) = slice(v_double >> shift_amount, 0, SEW_widen); + slice(arith_shifted, 0, SEW) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vnsrl.wi.yaml b/arch/inst/V/vnsrl.wi.yaml index 6021a11705..0b064e18e9 100644 --- a/arch/inst/V/vnsrl.wi.yaml +++ b/arch/inst/V/vnsrl.wi.yaml @@ -25,3 +25,55 @@ vnsrl.wi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + assert(SEW_widen <= 64); + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + NIS_VNSRL => { + let shift_amount = get_shift_amount(imm_val, SEW_widen); + slice(vs2_val[i] >> shift_amount, 0, SEW) + }, + NIS_VNSRA => { + let shift_amount = get_shift_amount(imm_val, SEW_widen); + let v_double : bits('o * 2) = sign_extend(vs2_val[i]); + let arith_shifted : bits('o) = slice(v_double >> shift_amount, 0, SEW_widen); + slice(arith_shifted, 0, SEW) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vnsrl.wv.yaml b/arch/inst/V/vnsrl.wv.yaml index d7486c8e42..a2fe0f6788 100644 --- a/arch/inst/V/vnsrl.wv.yaml +++ b/arch/inst/V/vnsrl.wv.yaml @@ -25,3 +25,55 @@ vnsrl.wv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + assert(SEW_widen <= 64); + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + NVS_VNSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW_widen); + slice(vs2_val[i] >> shift_amount, 0, SEW) + }, + NVS_VNSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW_widen); + let v_double : bits('o * 2) = sign_extend(vs2_val[i]); + let arith_shifted : bits('o) = slice(v_double >> shift_amount, 0, SEW_widen); + slice(arith_shifted, 0, SEW) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vnsrl.wx.yaml b/arch/inst/V/vnsrl.wx.yaml index 3e5705614e..77705fadd8 100644 --- a/arch/inst/V/vnsrl.wx.yaml +++ b/arch/inst/V/vnsrl.wx.yaml @@ -25,3 +25,55 @@ vnsrl.wx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_widen, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + assert(SEW_widen <= 64); + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + NXS_VNSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW_widen); + slice(vs2_val[i] >> shift_amount, 0, SEW) + }, + NXS_VNSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW_widen); + let v_double : bits('o * 2) = sign_extend(vs2_val[i]); + let arith_shifted : bits('o) = slice(v_double >> shift_amount, 0, SEW_widen); + slice(arith_shifted, 0, SEW) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vor.vi.yaml b/arch/inst/V/vor.vi.yaml index a99c2309d7..788df2e01b 100644 --- a/arch/inst/V/vor.vi.yaml +++ b/arch/inst/V/vor.vi.yaml @@ -25,3 +25,70 @@ vor.vi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VI_VADD => vs2_val[i] + imm_val, + VI_VRSUB => imm_val - vs2_val[i], + VI_VAND => vs2_val[i] & imm_val, + VI_VOR => vs2_val[i] | imm_val, + VI_VXOR => vs2_val[i] ^ imm_val, + VI_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, imm_val) ), + VI_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, imm_val) ), + VI_VSLL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + vs2_val[i] << shift_amount + }, + VI_VSRL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + vs2_val[i] >> shift_amount + }, + VI_VSRA => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VI_VSSRL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VI_VSSRA => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vor.vv.yaml b/arch/inst/V/vor.vv.yaml index ed60935bcd..16233ed7e4 100644 --- a/arch/inst/V/vor.vv.yaml +++ b/arch/inst/V/vor.vv.yaml @@ -25,3 +25,103 @@ vor.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VV_VADD => vs2_val[i] + vs1_val[i], + VV_VSUB => vs2_val[i] - vs1_val[i], + VV_VAND => vs2_val[i] & vs1_val[i], + VV_VOR => vs2_val[i] | vs1_val[i], + VV_VXOR => vs2_val[i] ^ vs1_val[i], + VV_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i])), + VV_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i])), + VV_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(vs1_val[i]) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i])) + }, + VV_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i])), + VV_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(vs1_val[i])); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VV_VSLL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] << shift_amount + }, + VV_VSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] >> shift_amount + }, + VV_VSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VV_VSSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VV_VSSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VV_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VRGATHER => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let idx = unsigned(vs1_val[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + }, + VV_VRGATHEREI16 => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + /* vrgatherei16.vv uses SEW/LMUL for the data in vs2 but EEW=16 and EMUL = (16/SEW)*LMUL for the indices in vs1 */ + let vs1_new : vector('n, dec, bits(16)) = read_vreg(num_elem, 16, 4 + LMUL_pow - SEW_pow, vs1); + let idx = unsigned(vs1_new[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vor.vx.yaml b/arch/inst/V/vor.vx.yaml index ae5d1f0306..d970c818a4 100644 --- a/arch/inst/V/vor.vx.yaml +++ b/arch/inst/V/vor.vx.yaml @@ -25,3 +25,86 @@ vor.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VX_VADD => vs2_val[i] + rs1_val, + VX_VSUB => vs2_val[i] - rs1_val, + VX_VRSUB => rs1_val - vs2_val[i], + VX_VAND => vs2_val[i] & rs1_val, + VX_VOR => vs2_val[i] | rs1_val, + VX_VXOR => vs2_val[i] ^ rs1_val, + VX_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val) ), + VX_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val) ), + VX_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(rs1_val) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val) ) + }, + VX_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val) ), + VX_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(rs1_val)); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VX_VSLL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] << shift_amount + }, + VX_VSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] >> shift_amount + }, + VX_VSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VX_VSSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VX_VSSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VX_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(rs1_val))), + VX_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(rs1_val))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vredand.vs.yaml b/arch/inst/V/vredand.vs.yaml index 169c95bfc8..ec56615672 100644 --- a/arch/inst/V/vredand.vs.yaml +++ b/arch/inst/V/vredand.vs.yaml @@ -25,3 +25,50 @@ vredand.vs: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem_vs = get_num_elem(LMUL_pow, SEW); + let num_elem_vd = get_num_elem(0, SEW); /* vd regardless of LMUL setting */ + + if illegal_reduction() then { handle_illegal(); return RETIRE_FAIL }; + + if unsigned(vl) == 0 then return RETIRE_SUCCESS; /* if vl=0, no operation is performed */ + + let 'n = num_elem_vs; + let 'd = num_elem_vd; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem_vs, vm, 0b00000); + let vd_val : vector('d, dec, bits('m)) = read_vreg(num_elem_vd, SEW, 0, vd); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem_vs, SEW, LMUL_pow, vs2); + let mask : vector('n, dec, bool) = init_masked_source(num_elem_vs, LMUL_pow, vm_val); + + sum : bits('m) = read_single_element(SEW, 0, vs1); /* vs1 regardless of LMUL setting */ + foreach (i from 0 to (num_elem_vs - 1)) { + if mask[i] then { + sum = match funct6 { + MVV_VREDSUM => sum + vs2_val[i], + MVV_VREDAND => sum & vs2_val[i], + MVV_VREDOR => sum | vs2_val[i], + MVV_VREDXOR => sum ^ vs2_val[i], + MVV_VREDMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(sum))), + MVV_VREDMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(sum))), + MVV_VREDMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(sum))), + MVV_VREDMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(sum))) + } + } + }; + + write_single_element(SEW, 0, vd, sum); + /* other elements in vd are treated as tail elements, currently remain unchanged */ + /* TODO: configuration support for agnostic behavior */ + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vredmax.vs.yaml b/arch/inst/V/vredmax.vs.yaml index 0e45e5c8d3..a139de5055 100644 --- a/arch/inst/V/vredmax.vs.yaml +++ b/arch/inst/V/vredmax.vs.yaml @@ -25,3 +25,50 @@ vredmax.vs: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem_vs = get_num_elem(LMUL_pow, SEW); + let num_elem_vd = get_num_elem(0, SEW); /* vd regardless of LMUL setting */ + + if illegal_reduction() then { handle_illegal(); return RETIRE_FAIL }; + + if unsigned(vl) == 0 then return RETIRE_SUCCESS; /* if vl=0, no operation is performed */ + + let 'n = num_elem_vs; + let 'd = num_elem_vd; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem_vs, vm, 0b00000); + let vd_val : vector('d, dec, bits('m)) = read_vreg(num_elem_vd, SEW, 0, vd); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem_vs, SEW, LMUL_pow, vs2); + let mask : vector('n, dec, bool) = init_masked_source(num_elem_vs, LMUL_pow, vm_val); + + sum : bits('m) = read_single_element(SEW, 0, vs1); /* vs1 regardless of LMUL setting */ + foreach (i from 0 to (num_elem_vs - 1)) { + if mask[i] then { + sum = match funct6 { + MVV_VREDSUM => sum + vs2_val[i], + MVV_VREDAND => sum & vs2_val[i], + MVV_VREDOR => sum | vs2_val[i], + MVV_VREDXOR => sum ^ vs2_val[i], + MVV_VREDMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(sum))), + MVV_VREDMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(sum))), + MVV_VREDMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(sum))), + MVV_VREDMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(sum))) + } + } + }; + + write_single_element(SEW, 0, vd, sum); + /* other elements in vd are treated as tail elements, currently remain unchanged */ + /* TODO: configuration support for agnostic behavior */ + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vredmaxu.vs.yaml b/arch/inst/V/vredmaxu.vs.yaml index d26252a7e4..d9e4400f3b 100644 --- a/arch/inst/V/vredmaxu.vs.yaml +++ b/arch/inst/V/vredmaxu.vs.yaml @@ -25,3 +25,50 @@ vredmaxu.vs: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem_vs = get_num_elem(LMUL_pow, SEW); + let num_elem_vd = get_num_elem(0, SEW); /* vd regardless of LMUL setting */ + + if illegal_reduction() then { handle_illegal(); return RETIRE_FAIL }; + + if unsigned(vl) == 0 then return RETIRE_SUCCESS; /* if vl=0, no operation is performed */ + + let 'n = num_elem_vs; + let 'd = num_elem_vd; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem_vs, vm, 0b00000); + let vd_val : vector('d, dec, bits('m)) = read_vreg(num_elem_vd, SEW, 0, vd); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem_vs, SEW, LMUL_pow, vs2); + let mask : vector('n, dec, bool) = init_masked_source(num_elem_vs, LMUL_pow, vm_val); + + sum : bits('m) = read_single_element(SEW, 0, vs1); /* vs1 regardless of LMUL setting */ + foreach (i from 0 to (num_elem_vs - 1)) { + if mask[i] then { + sum = match funct6 { + MVV_VREDSUM => sum + vs2_val[i], + MVV_VREDAND => sum & vs2_val[i], + MVV_VREDOR => sum | vs2_val[i], + MVV_VREDXOR => sum ^ vs2_val[i], + MVV_VREDMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(sum))), + MVV_VREDMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(sum))), + MVV_VREDMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(sum))), + MVV_VREDMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(sum))) + } + } + }; + + write_single_element(SEW, 0, vd, sum); + /* other elements in vd are treated as tail elements, currently remain unchanged */ + /* TODO: configuration support for agnostic behavior */ + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vredmin.vs.yaml b/arch/inst/V/vredmin.vs.yaml index 048b45c6a9..7be16c4358 100644 --- a/arch/inst/V/vredmin.vs.yaml +++ b/arch/inst/V/vredmin.vs.yaml @@ -25,3 +25,50 @@ vredmin.vs: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem_vs = get_num_elem(LMUL_pow, SEW); + let num_elem_vd = get_num_elem(0, SEW); /* vd regardless of LMUL setting */ + + if illegal_reduction() then { handle_illegal(); return RETIRE_FAIL }; + + if unsigned(vl) == 0 then return RETIRE_SUCCESS; /* if vl=0, no operation is performed */ + + let 'n = num_elem_vs; + let 'd = num_elem_vd; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem_vs, vm, 0b00000); + let vd_val : vector('d, dec, bits('m)) = read_vreg(num_elem_vd, SEW, 0, vd); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem_vs, SEW, LMUL_pow, vs2); + let mask : vector('n, dec, bool) = init_masked_source(num_elem_vs, LMUL_pow, vm_val); + + sum : bits('m) = read_single_element(SEW, 0, vs1); /* vs1 regardless of LMUL setting */ + foreach (i from 0 to (num_elem_vs - 1)) { + if mask[i] then { + sum = match funct6 { + MVV_VREDSUM => sum + vs2_val[i], + MVV_VREDAND => sum & vs2_val[i], + MVV_VREDOR => sum | vs2_val[i], + MVV_VREDXOR => sum ^ vs2_val[i], + MVV_VREDMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(sum))), + MVV_VREDMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(sum))), + MVV_VREDMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(sum))), + MVV_VREDMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(sum))) + } + } + }; + + write_single_element(SEW, 0, vd, sum); + /* other elements in vd are treated as tail elements, currently remain unchanged */ + /* TODO: configuration support for agnostic behavior */ + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vredminu.vs.yaml b/arch/inst/V/vredminu.vs.yaml index 236a1cb95e..23b2eff3d4 100644 --- a/arch/inst/V/vredminu.vs.yaml +++ b/arch/inst/V/vredminu.vs.yaml @@ -25,3 +25,50 @@ vredminu.vs: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem_vs = get_num_elem(LMUL_pow, SEW); + let num_elem_vd = get_num_elem(0, SEW); /* vd regardless of LMUL setting */ + + if illegal_reduction() then { handle_illegal(); return RETIRE_FAIL }; + + if unsigned(vl) == 0 then return RETIRE_SUCCESS; /* if vl=0, no operation is performed */ + + let 'n = num_elem_vs; + let 'd = num_elem_vd; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem_vs, vm, 0b00000); + let vd_val : vector('d, dec, bits('m)) = read_vreg(num_elem_vd, SEW, 0, vd); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem_vs, SEW, LMUL_pow, vs2); + let mask : vector('n, dec, bool) = init_masked_source(num_elem_vs, LMUL_pow, vm_val); + + sum : bits('m) = read_single_element(SEW, 0, vs1); /* vs1 regardless of LMUL setting */ + foreach (i from 0 to (num_elem_vs - 1)) { + if mask[i] then { + sum = match funct6 { + MVV_VREDSUM => sum + vs2_val[i], + MVV_VREDAND => sum & vs2_val[i], + MVV_VREDOR => sum | vs2_val[i], + MVV_VREDXOR => sum ^ vs2_val[i], + MVV_VREDMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(sum))), + MVV_VREDMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(sum))), + MVV_VREDMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(sum))), + MVV_VREDMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(sum))) + } + } + }; + + write_single_element(SEW, 0, vd, sum); + /* other elements in vd are treated as tail elements, currently remain unchanged */ + /* TODO: configuration support for agnostic behavior */ + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vredor.vs.yaml b/arch/inst/V/vredor.vs.yaml index 7f59be950c..a5832b5f63 100644 --- a/arch/inst/V/vredor.vs.yaml +++ b/arch/inst/V/vredor.vs.yaml @@ -25,3 +25,50 @@ vredor.vs: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem_vs = get_num_elem(LMUL_pow, SEW); + let num_elem_vd = get_num_elem(0, SEW); /* vd regardless of LMUL setting */ + + if illegal_reduction() then { handle_illegal(); return RETIRE_FAIL }; + + if unsigned(vl) == 0 then return RETIRE_SUCCESS; /* if vl=0, no operation is performed */ + + let 'n = num_elem_vs; + let 'd = num_elem_vd; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem_vs, vm, 0b00000); + let vd_val : vector('d, dec, bits('m)) = read_vreg(num_elem_vd, SEW, 0, vd); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem_vs, SEW, LMUL_pow, vs2); + let mask : vector('n, dec, bool) = init_masked_source(num_elem_vs, LMUL_pow, vm_val); + + sum : bits('m) = read_single_element(SEW, 0, vs1); /* vs1 regardless of LMUL setting */ + foreach (i from 0 to (num_elem_vs - 1)) { + if mask[i] then { + sum = match funct6 { + MVV_VREDSUM => sum + vs2_val[i], + MVV_VREDAND => sum & vs2_val[i], + MVV_VREDOR => sum | vs2_val[i], + MVV_VREDXOR => sum ^ vs2_val[i], + MVV_VREDMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(sum))), + MVV_VREDMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(sum))), + MVV_VREDMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(sum))), + MVV_VREDMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(sum))) + } + } + }; + + write_single_element(SEW, 0, vd, sum); + /* other elements in vd are treated as tail elements, currently remain unchanged */ + /* TODO: configuration support for agnostic behavior */ + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vredsum.vs.yaml b/arch/inst/V/vredsum.vs.yaml index 8a7a5ce434..03828a588d 100644 --- a/arch/inst/V/vredsum.vs.yaml +++ b/arch/inst/V/vredsum.vs.yaml @@ -25,3 +25,50 @@ vredsum.vs: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem_vs = get_num_elem(LMUL_pow, SEW); + let num_elem_vd = get_num_elem(0, SEW); /* vd regardless of LMUL setting */ + + if illegal_reduction() then { handle_illegal(); return RETIRE_FAIL }; + + if unsigned(vl) == 0 then return RETIRE_SUCCESS; /* if vl=0, no operation is performed */ + + let 'n = num_elem_vs; + let 'd = num_elem_vd; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem_vs, vm, 0b00000); + let vd_val : vector('d, dec, bits('m)) = read_vreg(num_elem_vd, SEW, 0, vd); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem_vs, SEW, LMUL_pow, vs2); + let mask : vector('n, dec, bool) = init_masked_source(num_elem_vs, LMUL_pow, vm_val); + + sum : bits('m) = read_single_element(SEW, 0, vs1); /* vs1 regardless of LMUL setting */ + foreach (i from 0 to (num_elem_vs - 1)) { + if mask[i] then { + sum = match funct6 { + MVV_VREDSUM => sum + vs2_val[i], + MVV_VREDAND => sum & vs2_val[i], + MVV_VREDOR => sum | vs2_val[i], + MVV_VREDXOR => sum ^ vs2_val[i], + MVV_VREDMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(sum))), + MVV_VREDMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(sum))), + MVV_VREDMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(sum))), + MVV_VREDMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(sum))) + } + } + }; + + write_single_element(SEW, 0, vd, sum); + /* other elements in vd are treated as tail elements, currently remain unchanged */ + /* TODO: configuration support for agnostic behavior */ + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vredxor.vs.yaml b/arch/inst/V/vredxor.vs.yaml index 75cda0d57c..84ac9e70a0 100644 --- a/arch/inst/V/vredxor.vs.yaml +++ b/arch/inst/V/vredxor.vs.yaml @@ -25,3 +25,50 @@ vredxor.vs: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem_vs = get_num_elem(LMUL_pow, SEW); + let num_elem_vd = get_num_elem(0, SEW); /* vd regardless of LMUL setting */ + + if illegal_reduction() then { handle_illegal(); return RETIRE_FAIL }; + + if unsigned(vl) == 0 then return RETIRE_SUCCESS; /* if vl=0, no operation is performed */ + + let 'n = num_elem_vs; + let 'd = num_elem_vd; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem_vs, vm, 0b00000); + let vd_val : vector('d, dec, bits('m)) = read_vreg(num_elem_vd, SEW, 0, vd); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem_vs, SEW, LMUL_pow, vs2); + let mask : vector('n, dec, bool) = init_masked_source(num_elem_vs, LMUL_pow, vm_val); + + sum : bits('m) = read_single_element(SEW, 0, vs1); /* vs1 regardless of LMUL setting */ + foreach (i from 0 to (num_elem_vs - 1)) { + if mask[i] then { + sum = match funct6 { + MVV_VREDSUM => sum + vs2_val[i], + MVV_VREDAND => sum & vs2_val[i], + MVV_VREDOR => sum | vs2_val[i], + MVV_VREDXOR => sum ^ vs2_val[i], + MVV_VREDMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(sum))), + MVV_VREDMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(sum))), + MVV_VREDMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(sum))), + MVV_VREDMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(sum))) + } + } + }; + + write_single_element(SEW, 0, vd, sum); + /* other elements in vd are treated as tail elements, currently remain unchanged */ + /* TODO: configuration support for agnostic behavior */ + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vrem.vv.yaml b/arch/inst/V/vrem.vv.yaml index 32bb4e0d12..0607022733 100644 --- a/arch/inst/V/vrem.vv.yaml +++ b/arch/inst/V/vrem.vv.yaml @@ -25,3 +25,85 @@ vrem.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVV_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), 0), + MVV_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), SEW), + MVV_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(vs1_val[i]), SEW), + MVV_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(vs1_val[i]), SEW), + MVV_VDIVU => { + let q : int = if unsigned(vs1_val[i]) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i])); + to_bits(SEW, q) + }, + MVV_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(vs1_val[i]) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(vs1_val[i])); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVV_VREMU => { + let r : int = if unsigned(vs1_val[i]) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i])); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVV_VREM => { + let r : int = if signed(vs1_val[i]) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(vs1_val[i])); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vrem.vx.yaml b/arch/inst/V/vrem.vx.yaml index 6fb75aff8d..d445e27aa5 100644 --- a/arch/inst/V/vrem.vx.yaml +++ b/arch/inst/V/vrem.vx.yaml @@ -25,3 +25,94 @@ vrem.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVX_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VSLIDE1UP => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + MVX_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + }, + MVX_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), 0), + MVX_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), SEW), + MVX_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VDIVU => { + let q : int = if unsigned(rs1_val) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(rs1_val)); + to_bits(SEW, q) + }, + MVX_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(rs1_val) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVX_VREMU => { + let r : int = if unsigned(rs1_val) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned (rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVX_VREM => { + let r : int = if signed(rs1_val) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vremu.vv.yaml b/arch/inst/V/vremu.vv.yaml index 679ec6dba8..c2cb577f4a 100644 --- a/arch/inst/V/vremu.vv.yaml +++ b/arch/inst/V/vremu.vv.yaml @@ -25,3 +25,85 @@ vremu.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVV_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i]); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVV_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), 0), + MVV_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(vs1_val[i]), SEW), + MVV_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(vs1_val[i]), SEW), + MVV_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(vs1_val[i]), SEW), + MVV_VDIVU => { + let q : int = if unsigned(vs1_val[i]) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i])); + to_bits(SEW, q) + }, + MVV_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(vs1_val[i]) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(vs1_val[i])); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVV_VREMU => { + let r : int = if unsigned(vs1_val[i]) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned(vs1_val[i])); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVV_VREM => { + let r : int = if signed(vs1_val[i]) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(vs1_val[i])); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vremu.vx.yaml b/arch/inst/V/vremu.vx.yaml index 8d3e0a672c..8e3e772a68 100644 --- a/arch/inst/V/vremu.vx.yaml +++ b/arch/inst/V/vremu.vx.yaml @@ -25,3 +25,94 @@ vremu.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVX_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VSLIDE1UP => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + MVX_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + }, + MVX_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), 0), + MVX_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), SEW), + MVX_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VDIVU => { + let q : int = if unsigned(rs1_val) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(rs1_val)); + to_bits(SEW, q) + }, + MVX_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(rs1_val) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVX_VREMU => { + let r : int = if unsigned(rs1_val) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned (rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVX_VREM => { + let r : int = if signed(rs1_val) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vrgather.vi.yaml b/arch/inst/V/vrgather.vi.yaml index e5cdf736cd..098219871d 100644 --- a/arch/inst/V/vrgather.vi.yaml +++ b/arch/inst/V/vrgather.vi.yaml @@ -25,3 +25,56 @@ vrgather.vi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let imm_val : nat = unsigned(zero_extend(sizeof(xlen), simm)); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VI_VSLIDEUP => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + if i >= imm_val then vs2_val[i - imm_val] else vd_val[i] + }, + VI_VSLIDEDOWN => { + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX > 0 & VLMAX <= 'n); + if i + imm_val < VLMAX then vs2_val[i + imm_val] else zeros() + }, + VI_VRGATHER => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX > 0 & VLMAX <= 'n); + if imm_val < VLMAX then vs2_val[imm_val] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vrgather.vv.yaml b/arch/inst/V/vrgather.vv.yaml index 58430d1c2b..f7a2f802a4 100644 --- a/arch/inst/V/vrgather.vv.yaml +++ b/arch/inst/V/vrgather.vv.yaml @@ -25,3 +25,103 @@ vrgather.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VV_VADD => vs2_val[i] + vs1_val[i], + VV_VSUB => vs2_val[i] - vs1_val[i], + VV_VAND => vs2_val[i] & vs1_val[i], + VV_VOR => vs2_val[i] | vs1_val[i], + VV_VXOR => vs2_val[i] ^ vs1_val[i], + VV_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i])), + VV_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i])), + VV_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(vs1_val[i]) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i])) + }, + VV_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i])), + VV_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(vs1_val[i])); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VV_VSLL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] << shift_amount + }, + VV_VSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] >> shift_amount + }, + VV_VSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VV_VSSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VV_VSSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VV_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VRGATHER => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let idx = unsigned(vs1_val[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + }, + VV_VRGATHEREI16 => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + /* vrgatherei16.vv uses SEW/LMUL for the data in vs2 but EEW=16 and EMUL = (16/SEW)*LMUL for the indices in vs1 */ + let vs1_new : vector('n, dec, bits(16)) = read_vreg(num_elem, 16, 4 + LMUL_pow - SEW_pow, vs1); + let idx = unsigned(vs1_new[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vrgather.vx.yaml b/arch/inst/V/vrgather.vx.yaml index 4c7796b9c6..f84f5128ac 100644 --- a/arch/inst/V/vrgather.vx.yaml +++ b/arch/inst/V/vrgather.vx.yaml @@ -25,3 +25,56 @@ vrgather.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : nat = unsigned(X(rs1)); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VX_VSLIDEUP => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + if i >= rs1_val then vs2_val[i - rs1_val] else vd_val[i] + }, + VX_VSLIDEDOWN => { + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX > 0 & VLMAX <= 'n); + if i + rs1_val < VLMAX then vs2_val[i + rs1_val] else zeros() + }, + VX_VRGATHER => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX > 0 & VLMAX <= 'n); + if rs1_val < VLMAX then vs2_val[rs1_val] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vrgatherei16.vv.yaml b/arch/inst/V/vrgatherei16.vv.yaml index 9016c9bde1..bdfa182986 100644 --- a/arch/inst/V/vrgatherei16.vv.yaml +++ b/arch/inst/V/vrgatherei16.vv.yaml @@ -25,3 +25,103 @@ vrgatherei16.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VV_VADD => vs2_val[i] + vs1_val[i], + VV_VSUB => vs2_val[i] - vs1_val[i], + VV_VAND => vs2_val[i] & vs1_val[i], + VV_VOR => vs2_val[i] | vs1_val[i], + VV_VXOR => vs2_val[i] ^ vs1_val[i], + VV_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i])), + VV_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i])), + VV_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(vs1_val[i]) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i])) + }, + VV_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i])), + VV_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(vs1_val[i])); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VV_VSLL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] << shift_amount + }, + VV_VSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] >> shift_amount + }, + VV_VSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VV_VSSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VV_VSSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VV_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VRGATHER => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let idx = unsigned(vs1_val[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + }, + VV_VRGATHEREI16 => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + /* vrgatherei16.vv uses SEW/LMUL for the data in vs2 but EEW=16 and EMUL = (16/SEW)*LMUL for the indices in vs1 */ + let vs1_new : vector('n, dec, bits(16)) = read_vreg(num_elem, 16, 4 + LMUL_pow - SEW_pow, vs1); + let idx = unsigned(vs1_new[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vrsub.vi.yaml b/arch/inst/V/vrsub.vi.yaml index e63aa59dce..80da62cdd1 100644 --- a/arch/inst/V/vrsub.vi.yaml +++ b/arch/inst/V/vrsub.vi.yaml @@ -25,3 +25,70 @@ vrsub.vi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VI_VADD => vs2_val[i] + imm_val, + VI_VRSUB => imm_val - vs2_val[i], + VI_VAND => vs2_val[i] & imm_val, + VI_VOR => vs2_val[i] | imm_val, + VI_VXOR => vs2_val[i] ^ imm_val, + VI_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, imm_val) ), + VI_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, imm_val) ), + VI_VSLL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + vs2_val[i] << shift_amount + }, + VI_VSRL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + vs2_val[i] >> shift_amount + }, + VI_VSRA => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VI_VSSRL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VI_VSSRA => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vrsub.vx.yaml b/arch/inst/V/vrsub.vx.yaml index 4e52ae1d95..1aa11f6a4f 100644 --- a/arch/inst/V/vrsub.vx.yaml +++ b/arch/inst/V/vrsub.vx.yaml @@ -25,3 +25,86 @@ vrsub.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VX_VADD => vs2_val[i] + rs1_val, + VX_VSUB => vs2_val[i] - rs1_val, + VX_VRSUB => rs1_val - vs2_val[i], + VX_VAND => vs2_val[i] & rs1_val, + VX_VOR => vs2_val[i] | rs1_val, + VX_VXOR => vs2_val[i] ^ rs1_val, + VX_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val) ), + VX_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val) ), + VX_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(rs1_val) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val) ) + }, + VX_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val) ), + VX_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(rs1_val)); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VX_VSLL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] << shift_amount + }, + VX_VSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] >> shift_amount + }, + VX_VSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VX_VSSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VX_VSSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VX_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(rs1_val))), + VX_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(rs1_val))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsadd.vi.yaml b/arch/inst/V/vsadd.vi.yaml index b35549212d..cc27ee2d04 100644 --- a/arch/inst/V/vsadd.vi.yaml +++ b/arch/inst/V/vsadd.vi.yaml @@ -25,3 +25,70 @@ vsadd.vi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VI_VADD => vs2_val[i] + imm_val, + VI_VRSUB => imm_val - vs2_val[i], + VI_VAND => vs2_val[i] & imm_val, + VI_VOR => vs2_val[i] | imm_val, + VI_VXOR => vs2_val[i] ^ imm_val, + VI_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, imm_val) ), + VI_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, imm_val) ), + VI_VSLL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + vs2_val[i] << shift_amount + }, + VI_VSRL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + vs2_val[i] >> shift_amount + }, + VI_VSRA => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VI_VSSRL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VI_VSSRA => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsadd.vv.yaml b/arch/inst/V/vsadd.vv.yaml index 1e56392bdd..c3dd3509ee 100644 --- a/arch/inst/V/vsadd.vv.yaml +++ b/arch/inst/V/vsadd.vv.yaml @@ -25,3 +25,103 @@ vsadd.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VV_VADD => vs2_val[i] + vs1_val[i], + VV_VSUB => vs2_val[i] - vs1_val[i], + VV_VAND => vs2_val[i] & vs1_val[i], + VV_VOR => vs2_val[i] | vs1_val[i], + VV_VXOR => vs2_val[i] ^ vs1_val[i], + VV_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i])), + VV_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i])), + VV_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(vs1_val[i]) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i])) + }, + VV_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i])), + VV_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(vs1_val[i])); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VV_VSLL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] << shift_amount + }, + VV_VSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] >> shift_amount + }, + VV_VSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VV_VSSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VV_VSSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VV_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VRGATHER => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let idx = unsigned(vs1_val[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + }, + VV_VRGATHEREI16 => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + /* vrgatherei16.vv uses SEW/LMUL for the data in vs2 but EEW=16 and EMUL = (16/SEW)*LMUL for the indices in vs1 */ + let vs1_new : vector('n, dec, bits(16)) = read_vreg(num_elem, 16, 4 + LMUL_pow - SEW_pow, vs1); + let idx = unsigned(vs1_new[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsadd.vx.yaml b/arch/inst/V/vsadd.vx.yaml index f8cad95dc4..db5dc0585d 100644 --- a/arch/inst/V/vsadd.vx.yaml +++ b/arch/inst/V/vsadd.vx.yaml @@ -25,3 +25,86 @@ vsadd.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VX_VADD => vs2_val[i] + rs1_val, + VX_VSUB => vs2_val[i] - rs1_val, + VX_VRSUB => rs1_val - vs2_val[i], + VX_VAND => vs2_val[i] & rs1_val, + VX_VOR => vs2_val[i] | rs1_val, + VX_VXOR => vs2_val[i] ^ rs1_val, + VX_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val) ), + VX_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val) ), + VX_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(rs1_val) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val) ) + }, + VX_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val) ), + VX_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(rs1_val)); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VX_VSLL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] << shift_amount + }, + VX_VSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] >> shift_amount + }, + VX_VSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VX_VSSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VX_VSSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VX_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(rs1_val))), + VX_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(rs1_val))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsaddu.vi.yaml b/arch/inst/V/vsaddu.vi.yaml index 2a05b36bba..1ba58a7bae 100644 --- a/arch/inst/V/vsaddu.vi.yaml +++ b/arch/inst/V/vsaddu.vi.yaml @@ -25,3 +25,70 @@ vsaddu.vi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VI_VADD => vs2_val[i] + imm_val, + VI_VRSUB => imm_val - vs2_val[i], + VI_VAND => vs2_val[i] & imm_val, + VI_VOR => vs2_val[i] | imm_val, + VI_VXOR => vs2_val[i] ^ imm_val, + VI_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, imm_val) ), + VI_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, imm_val) ), + VI_VSLL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + vs2_val[i] << shift_amount + }, + VI_VSRL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + vs2_val[i] >> shift_amount + }, + VI_VSRA => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VI_VSSRL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VI_VSSRA => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsaddu.vv.yaml b/arch/inst/V/vsaddu.vv.yaml index 72ae0fd838..213958446e 100644 --- a/arch/inst/V/vsaddu.vv.yaml +++ b/arch/inst/V/vsaddu.vv.yaml @@ -25,3 +25,103 @@ vsaddu.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VV_VADD => vs2_val[i] + vs1_val[i], + VV_VSUB => vs2_val[i] - vs1_val[i], + VV_VAND => vs2_val[i] & vs1_val[i], + VV_VOR => vs2_val[i] | vs1_val[i], + VV_VXOR => vs2_val[i] ^ vs1_val[i], + VV_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i])), + VV_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i])), + VV_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(vs1_val[i]) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i])) + }, + VV_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i])), + VV_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(vs1_val[i])); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VV_VSLL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] << shift_amount + }, + VV_VSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] >> shift_amount + }, + VV_VSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VV_VSSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VV_VSSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VV_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VRGATHER => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let idx = unsigned(vs1_val[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + }, + VV_VRGATHEREI16 => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + /* vrgatherei16.vv uses SEW/LMUL for the data in vs2 but EEW=16 and EMUL = (16/SEW)*LMUL for the indices in vs1 */ + let vs1_new : vector('n, dec, bits(16)) = read_vreg(num_elem, 16, 4 + LMUL_pow - SEW_pow, vs1); + let idx = unsigned(vs1_new[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsaddu.vx.yaml b/arch/inst/V/vsaddu.vx.yaml index f51ac854f2..6ff0377e22 100644 --- a/arch/inst/V/vsaddu.vx.yaml +++ b/arch/inst/V/vsaddu.vx.yaml @@ -25,3 +25,86 @@ vsaddu.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VX_VADD => vs2_val[i] + rs1_val, + VX_VSUB => vs2_val[i] - rs1_val, + VX_VRSUB => rs1_val - vs2_val[i], + VX_VAND => vs2_val[i] & rs1_val, + VX_VOR => vs2_val[i] | rs1_val, + VX_VXOR => vs2_val[i] ^ rs1_val, + VX_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val) ), + VX_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val) ), + VX_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(rs1_val) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val) ) + }, + VX_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val) ), + VX_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(rs1_val)); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VX_VSLL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] << shift_amount + }, + VX_VSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] >> shift_amount + }, + VX_VSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VX_VSSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VX_VSSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VX_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(rs1_val))), + VX_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(rs1_val))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsbc.vvm.yaml b/arch/inst/V/vsbc.vvm.yaml index 9bd8653f35..3c4ac1b5f3 100644 --- a/arch/inst/V/vsbc.vvm.yaml +++ b/arch/inst/V/vsbc.vvm.yaml @@ -23,3 +23,47 @@ vsbc.vvm: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_masked(vd) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + /* for bypassing normal masking in init_masked_result */ + vec_trues : vector('n, dec, bool) = undefined; + foreach (i from 0 to (num_elem - 1)) { + vec_trues[i] = true + }; + + let vm_val : vector('n, dec, bool) = read_vmask_carry(num_elem, 0b0, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vec_trues); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VVMS_VADC => to_bits(SEW, unsigned(vs2_val[i]) + unsigned(vs1_val[i]) + unsigned(bool_to_bits(vm_val[i]))), + VVMS_VSBC => to_bits(SEW, unsigned(vs2_val[i]) - unsigned(vs1_val[i]) - unsigned(bool_to_bits(vm_val[i]))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsbc.vxm.yaml b/arch/inst/V/vsbc.vxm.yaml index a0d40f3812..4e9c0a4a80 100644 --- a/arch/inst/V/vsbc.vxm.yaml +++ b/arch/inst/V/vsbc.vxm.yaml @@ -23,3 +23,47 @@ vsbc.vxm: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_vd_masked(vd) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + /* for bypassing normal masking in init_masked_result */ + vec_trues : vector('n, dec, bool) = undefined; + foreach (i from 0 to (num_elem - 1)) { + vec_trues[i] = true + }; + + let vm_val : vector('n, dec, bool) = read_vmask_carry(num_elem, 0b0, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vec_trues); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VXMS_VADC => to_bits(SEW, unsigned(vs2_val[i]) + unsigned(rs1_val) + unsigned(bool_to_bits(vm_val[i]))), + VXMS_VSBC => to_bits(SEW, unsigned(vs2_val[i]) - unsigned(rs1_val) - unsigned(bool_to_bits(vm_val[i]))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vse16.v.yaml b/arch/inst/V/vse16.v.yaml index 05c1bba8aa..b3326668fe 100644 --- a/arch/inst/V/vse16.v.yaml +++ b/arch/inst/V/vse16.v.yaml @@ -25,3 +25,23 @@ vse16.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let load_width_bytes = vlewidth_bytesnumber(width); + let EEW = load_width_bytes * 8; + let EEW_pow = vlewidth_pow(width); + let SEW_pow = get_sew_pow(); + let LMUL_pow = get_lmul_pow(); + let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow; + let num_elem = get_num_elem(EMUL_pow, EEW); + let nf_int = nfields_int(nf); + + if illegal_store(nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vsseg(nf_int, vm, vs3, load_width_bytes, rs1, EMUL_pow, num_elem) + } + + \ No newline at end of file diff --git a/arch/inst/V/vse32.v.yaml b/arch/inst/V/vse32.v.yaml index f7d6dc7ffd..ab90ec0f70 100644 --- a/arch/inst/V/vse32.v.yaml +++ b/arch/inst/V/vse32.v.yaml @@ -25,3 +25,23 @@ vse32.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let load_width_bytes = vlewidth_bytesnumber(width); + let EEW = load_width_bytes * 8; + let EEW_pow = vlewidth_pow(width); + let SEW_pow = get_sew_pow(); + let LMUL_pow = get_lmul_pow(); + let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow; + let num_elem = get_num_elem(EMUL_pow, EEW); + let nf_int = nfields_int(nf); + + if illegal_store(nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vsseg(nf_int, vm, vs3, load_width_bytes, rs1, EMUL_pow, num_elem) + } + + \ No newline at end of file diff --git a/arch/inst/V/vse64.v.yaml b/arch/inst/V/vse64.v.yaml index 09835d967b..ead1ee36cc 100644 --- a/arch/inst/V/vse64.v.yaml +++ b/arch/inst/V/vse64.v.yaml @@ -25,3 +25,23 @@ vse64.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let load_width_bytes = vlewidth_bytesnumber(width); + let EEW = load_width_bytes * 8; + let EEW_pow = vlewidth_pow(width); + let SEW_pow = get_sew_pow(); + let LMUL_pow = get_lmul_pow(); + let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow; + let num_elem = get_num_elem(EMUL_pow, EEW); + let nf_int = nfields_int(nf); + + if illegal_store(nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vsseg(nf_int, vm, vs3, load_width_bytes, rs1, EMUL_pow, num_elem) + } + + \ No newline at end of file diff --git a/arch/inst/V/vse8.v.yaml b/arch/inst/V/vse8.v.yaml index 5a85fbf121..ef7e9e9241 100644 --- a/arch/inst/V/vse8.v.yaml +++ b/arch/inst/V/vse8.v.yaml @@ -25,3 +25,23 @@ vse8.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let load_width_bytes = vlewidth_bytesnumber(width); + let EEW = load_width_bytes * 8; + let EEW_pow = vlewidth_pow(width); + let SEW_pow = get_sew_pow(); + let LMUL_pow = get_lmul_pow(); + let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow; + let num_elem = get_num_elem(EMUL_pow, EEW); + let nf_int = nfields_int(nf); + + if illegal_store(nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vsseg(nf_int, vm, vs3, load_width_bytes, rs1, EMUL_pow, num_elem) + } + + \ No newline at end of file diff --git a/arch/inst/V/vsetivli.yaml b/arch/inst/V/vsetivli.yaml index 4ee0370c1e..1e62eded55 100644 --- a/arch/inst/V/vsetivli.yaml +++ b/arch/inst/V/vsetivli.yaml @@ -23,3 +23,52 @@ vsetivli: data_independent_timing: false operation(): | + + + + sail(): | + { + let VLEN_pow = get_vlen_pow(); + let ELEN_pow = get_elen_pow(); + let LMUL_pow_ori = get_lmul_pow(); + let SEW_pow_ori = get_sew_pow(); + let ratio_pow_ori = SEW_pow_ori - LMUL_pow_ori; + + /* set vtype */ + vtype->bits() = 0b0 @ zeros(sizeof(xlen) - 9) @ ma @ ta @ sew @ lmul; + + /* check legal SEW and LMUL and calculate VLMAX */ + let LMUL_pow_new = get_lmul_pow(); + let SEW_pow_new = get_sew_pow(); + if SEW_pow_new > LMUL_pow_new + ELEN_pow then { + /* Note: Implementations can set vill or trap if the vtype setting is not supported. + * TODO: configuration support for both solutions + */ + vtype->bits() = 0b1 @ zeros(sizeof(xlen) - 1); /* set vtype.vill */ + vl = zeros(); + print_reg("CSR vtype <- " ^ BitStr(vtype.bits())); + print_reg("CSR vl <- " ^ BitStr(vl)); + return RETIRE_SUCCESS + }; + let VLMAX = int_power(2, VLEN_pow + LMUL_pow_new - SEW_pow_new); + let AVL = unsigned(uimm); /* AVL is encoded as 5-bit zero-extended imm in the rs1 field */ + + /* set vl according to VLMAX and AVL */ + vl = if AVL <= VLMAX then to_bits(sizeof(xlen), AVL) + else if AVL < 2 * VLMAX then to_bits(sizeof(xlen), (AVL + 1) / 2) + else to_bits(sizeof(xlen), VLMAX); + /* Note: ceil(AVL / 2) <= vl <= VLMAX when VLMAX < AVL < (2 * VLMAX) + * TODO: configuration support for either using ceil(AVL / 2) or VLMAX + */ + X(rd) = vl; + print_reg("CSR vtype <- " ^ BitStr(vtype.bits())); + print_reg("CSR vl <- " ^ BitStr(vl)); + + /* reset vstart to 0 */ + vstart = zeros(); + print_reg("CSR vstart <- " ^ BitStr(vstart)); + + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsetvli.yaml b/arch/inst/V/vsetvli.yaml index 4711c8cfeb..8279debf7e 100644 --- a/arch/inst/V/vsetvli.yaml +++ b/arch/inst/V/vsetvli.yaml @@ -23,3 +23,150 @@ vsetvli: data_independent_timing: false operation(): | + + + + sail(): | + { + let VLEN_pow = get_vlen_pow(); + let ELEN_pow = get_elen_pow(); + let LMUL_pow_ori = get_lmul_pow(); + let SEW_pow_ori = get_sew_pow(); + let ratio_pow_ori = SEW_pow_ori - LMUL_pow_ori; + + /* set vtype */ + match op { + VSETVLI => { + vtype->bits() = 0b0 @ zeros(sizeof(xlen) - 9) @ ma @ ta @ sew @ lmul + }, + VSETVL => { + let rs2 : regidx = sew[1 .. 0] @ lmul; + vtype->bits() = X(rs2) + } + }; + + /* check legal SEW and LMUL and calculate VLMAX */ + let LMUL_pow_new = get_lmul_pow(); + let SEW_pow_new = get_sew_pow(); + if SEW_pow_new > LMUL_pow_new + ELEN_pow then { + /* Note: Implementations can set vill or trap if the vtype setting is not supported. + * TODO: configuration support for both solutions + */ + vtype->bits() = 0b1 @ zeros(sizeof(xlen) - 1); /* set vtype.vill */ + vl = zeros(); + print_reg("CSR vtype <- " ^ BitStr(vtype.bits())); + print_reg("CSR vl <- " ^ BitStr(vl)); + return RETIRE_SUCCESS + }; + let VLMAX = int_power(2, VLEN_pow + LMUL_pow_new - SEW_pow_new); + + /* set vl according to VLMAX and AVL */ + if (rs1 != 0b00000) then { /* normal stripmining */ + let rs1_val = X(rs1); + let AVL = unsigned(rs1_val); + vl = if AVL <= VLMAX then to_bits(sizeof(xlen), AVL) + else if AVL < 2 * VLMAX then to_bits(sizeof(xlen), (AVL + 1) / 2) + else to_bits(sizeof(xlen), VLMAX); + /* Note: ceil(AVL / 2) <= vl <= VLMAX when VLMAX < AVL < (2 * VLMAX) + * TODO: configuration support for either using ceil(AVL / 2) or VLMAX + */ + X(rd) = vl; + } else if (rd != 0b00000) then { /* set vl to VLMAX */ + let AVL = unsigned(ones(sizeof(xlen))); + vl = to_bits(sizeof(xlen), VLMAX); + X(rd) = vl; + } else { /* keep existing vl */ + let AVL = unsigned(vl); + let ratio_pow_new = SEW_pow_new - LMUL_pow_new; + if (ratio_pow_new != ratio_pow_ori) then { + /* Note: Implementations can set vill or trap if the vtype setting is not supported. + * TODO: configuration support for both solutions + */ + vtype->bits() = 0b1 @ zeros(sizeof(xlen) - 1); /* set vtype.vill */ + vl = zeros(); + } + }; + print_reg("CSR vtype <- " ^ BitStr(vtype.bits())); + print_reg("CSR vl <- " ^ BitStr(vl)); + + /* reset vstart to 0 */ + vstart = zeros(); + print_reg("CSR vstart <- " ^ BitStr(vstart)); + + RETIRE_SUCCESS + } + + + + + sail(): | + { + let VLEN_pow = get_vlen_pow(); + let ELEN_pow = get_elen_pow(); + let LMUL_pow_ori = get_lmul_pow(); + let SEW_pow_ori = get_sew_pow(); + let ratio_pow_ori = SEW_pow_ori - LMUL_pow_ori; + + /* set vtype */ + match op { + VSETVLI => { + vtype->bits() = 0b0 @ zeros(sizeof(xlen) - 9) @ ma @ ta @ sew @ lmul + }, + VSETVL => { + let rs2 : regidx = sew[1 .. 0] @ lmul; + vtype->bits() = X(rs2) + } + }; + + /* check legal SEW and LMUL and calculate VLMAX */ + let LMUL_pow_new = get_lmul_pow(); + let SEW_pow_new = get_sew_pow(); + if SEW_pow_new > LMUL_pow_new + ELEN_pow then { + /* Note: Implementations can set vill or trap if the vtype setting is not supported. + * TODO: configuration support for both solutions + */ + vtype->bits() = 0b1 @ zeros(sizeof(xlen) - 1); /* set vtype.vill */ + vl = zeros(); + print_reg("CSR vtype <- " ^ BitStr(vtype.bits())); + print_reg("CSR vl <- " ^ BitStr(vl)); + return RETIRE_SUCCESS + }; + let VLMAX = int_power(2, VLEN_pow + LMUL_pow_new - SEW_pow_new); + + /* set vl according to VLMAX and AVL */ + if (rs1 != 0b00000) then { /* normal stripmining */ + let rs1_val = X(rs1); + let AVL = unsigned(rs1_val); + vl = if AVL <= VLMAX then to_bits(sizeof(xlen), AVL) + else if AVL < 2 * VLMAX then to_bits(sizeof(xlen), (AVL + 1) / 2) + else to_bits(sizeof(xlen), VLMAX); + /* Note: ceil(AVL / 2) <= vl <= VLMAX when VLMAX < AVL < (2 * VLMAX) + * TODO: configuration support for either using ceil(AVL / 2) or VLMAX + */ + X(rd) = vl; + } else if (rd != 0b00000) then { /* set vl to VLMAX */ + let AVL = unsigned(ones(sizeof(xlen))); + vl = to_bits(sizeof(xlen), VLMAX); + X(rd) = vl; + } else { /* keep existing vl */ + let AVL = unsigned(vl); + let ratio_pow_new = SEW_pow_new - LMUL_pow_new; + if (ratio_pow_new != ratio_pow_ori) then { + /* Note: Implementations can set vill or trap if the vtype setting is not supported. + * TODO: configuration support for both solutions + */ + vtype->bits() = 0b1 @ zeros(sizeof(xlen) - 1); /* set vtype.vill */ + vl = zeros(); + } + }; + print_reg("CSR vtype <- " ^ BitStr(vtype.bits())); + print_reg("CSR vl <- " ^ BitStr(vl)); + + /* reset vstart to 0 */ + vstart = zeros(); + print_reg("CSR vstart <- " ^ BitStr(vstart)); + + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsext.vf2.yaml b/arch/inst/V/vsext.vf2.yaml index 953e95f00e..8fb3f171db 100644 --- a/arch/inst/V/vsext.vf2.yaml +++ b/arch/inst/V/vsext.vf2.yaml @@ -23,3 +23,46 @@ vsext.vf2: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_half = SEW / 2; + let LMUL_pow_half = LMUL_pow - 1; + + if illegal_variable_width(vd, vm, SEW_half, LMUL_pow_half) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_half, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_half; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_half, LMUL_pow_half, vs2); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + assert(SEW > SEW_half); + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VEXT2_ZVF2 => zero_extend(vs2_val[i]), + VEXT2_SVF2 => sign_extend(vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsext.vf4.yaml b/arch/inst/V/vsext.vf4.yaml index 2742da9f0c..16400dd5ed 100644 --- a/arch/inst/V/vsext.vf4.yaml +++ b/arch/inst/V/vsext.vf4.yaml @@ -23,3 +23,46 @@ vsext.vf4: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_quart = SEW / 4; + let LMUL_pow_quart = LMUL_pow - 2; + + if illegal_variable_width(vd, vm, SEW_quart, LMUL_pow_quart) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_quart, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_quart; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_quart, LMUL_pow_quart, vs2); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + assert(SEW > SEW_quart); + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VEXT4_ZVF4 => zero_extend(vs2_val[i]), + VEXT4_SVF4 => sign_extend(vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsext.vf8.yaml b/arch/inst/V/vsext.vf8.yaml index 21ab254a16..38cbc1b710 100644 --- a/arch/inst/V/vsext.vf8.yaml +++ b/arch/inst/V/vsext.vf8.yaml @@ -23,3 +23,46 @@ vsext.vf8: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_eighth = SEW / 8; + let LMUL_pow_eighth = LMUL_pow - 3; + + if illegal_variable_width(vd, vm, SEW_eighth, LMUL_pow_eighth) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_eighth, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_eighth; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_eighth, LMUL_pow_eighth, vs2); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + assert(SEW > SEW_eighth); + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VEXT8_ZVF8 => zero_extend(vs2_val[i]), + VEXT8_SVF8 => sign_extend(vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vslide1down.vx.yaml b/arch/inst/V/vslide1down.vx.yaml index 23246157f3..c712fed9b4 100644 --- a/arch/inst/V/vslide1down.vx.yaml +++ b/arch/inst/V/vslide1down.vx.yaml @@ -25,3 +25,94 @@ vslide1down.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVX_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VSLIDE1UP => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + MVX_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + }, + MVX_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), 0), + MVX_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), SEW), + MVX_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VDIVU => { + let q : int = if unsigned(rs1_val) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(rs1_val)); + to_bits(SEW, q) + }, + MVX_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(rs1_val) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVX_VREMU => { + let r : int = if unsigned(rs1_val) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned (rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVX_VREM => { + let r : int = if signed(rs1_val) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vslide1up.vx.yaml b/arch/inst/V/vslide1up.vx.yaml index a0a4ed3ba8..bb5566fd42 100644 --- a/arch/inst/V/vslide1up.vx.yaml +++ b/arch/inst/V/vslide1up.vx.yaml @@ -25,3 +25,94 @@ vslide1up.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + MVX_VAADDU => { + let result_add = zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VAADD => { + let result_add = sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_add, 1); + slice(result_add >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUBU => { + let result_sub = zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VASUB => { + let result_sub = sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val); + let rounding_incr = get_fixed_rounding_incr(result_sub, 1); + slice(result_sub >> 1, 0, 'm) + zero_extend('m, rounding_incr) + }, + MVX_VSLIDE1UP => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + if i == 0 then rs1_val else vs2_val[i - 1] + }, + MVX_VSLIDE1DOWN => { + let last_elem = get_end_element(); + assert(last_elem < num_elem); + if i < last_elem then vs2_val[i + 1] else rs1_val + }, + MVX_VMUL => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), 0), + MVX_VMULH => get_slice_int(SEW, signed(vs2_val[i]) * signed(rs1_val), SEW), + MVX_VMULHU => get_slice_int(SEW, unsigned(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VMULHSU => get_slice_int(SEW, signed(vs2_val[i]) * unsigned(rs1_val), SEW), + MVX_VDIVU => { + let q : int = if unsigned(rs1_val) == 0 then -1 else quot_round_zero(unsigned(vs2_val[i]), unsigned(rs1_val)); + to_bits(SEW, q) + }, + MVX_VDIV => { + let elem_max : int = 2 ^ (SEW - 1) - 1; + let elem_min : int = 0 - 2 ^ (SEW - 1); + let q : int = if signed(rs1_val) == 0 then -1 else quot_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* check for signed overflow */ + let q' : int = if q > elem_max then elem_min else q; + to_bits(SEW, q') + }, + MVX_VREMU => { + let r : int = if unsigned(rs1_val) == 0 then unsigned(vs2_val[i]) else rem_round_zero(unsigned(vs2_val[i]), unsigned (rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + }, + MVX_VREM => { + let r : int = if signed(rs1_val) == 0 then signed(vs2_val[i]) else rem_round_zero(signed(vs2_val[i]), signed(rs1_val)); + /* signed overflow case returns zero naturally as required due to -1 divisor */ + to_bits(SEW, r) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vslidedown.vi.yaml b/arch/inst/V/vslidedown.vi.yaml index df5b692cdd..0cb1ca8a1a 100644 --- a/arch/inst/V/vslidedown.vi.yaml +++ b/arch/inst/V/vslidedown.vi.yaml @@ -25,3 +25,56 @@ vslidedown.vi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let imm_val : nat = unsigned(zero_extend(sizeof(xlen), simm)); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VI_VSLIDEUP => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + if i >= imm_val then vs2_val[i - imm_val] else vd_val[i] + }, + VI_VSLIDEDOWN => { + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX > 0 & VLMAX <= 'n); + if i + imm_val < VLMAX then vs2_val[i + imm_val] else zeros() + }, + VI_VRGATHER => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX > 0 & VLMAX <= 'n); + if imm_val < VLMAX then vs2_val[imm_val] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vslidedown.vx.yaml b/arch/inst/V/vslidedown.vx.yaml index 99783c088c..615de29e2d 100644 --- a/arch/inst/V/vslidedown.vx.yaml +++ b/arch/inst/V/vslidedown.vx.yaml @@ -25,3 +25,56 @@ vslidedown.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : nat = unsigned(X(rs1)); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VX_VSLIDEUP => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + if i >= rs1_val then vs2_val[i - rs1_val] else vd_val[i] + }, + VX_VSLIDEDOWN => { + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX > 0 & VLMAX <= 'n); + if i + rs1_val < VLMAX then vs2_val[i + rs1_val] else zeros() + }, + VX_VRGATHER => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX > 0 & VLMAX <= 'n); + if rs1_val < VLMAX then vs2_val[rs1_val] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vslideup.vi.yaml b/arch/inst/V/vslideup.vi.yaml index 6402e0bcff..20ecb7f102 100644 --- a/arch/inst/V/vslideup.vi.yaml +++ b/arch/inst/V/vslideup.vi.yaml @@ -25,3 +25,56 @@ vslideup.vi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let imm_val : nat = unsigned(zero_extend(sizeof(xlen), simm)); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VI_VSLIDEUP => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + if i >= imm_val then vs2_val[i - imm_val] else vd_val[i] + }, + VI_VSLIDEDOWN => { + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX > 0 & VLMAX <= 'n); + if i + imm_val < VLMAX then vs2_val[i + imm_val] else zeros() + }, + VI_VRGATHER => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX > 0 & VLMAX <= 'n); + if imm_val < VLMAX then vs2_val[imm_val] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vslideup.vx.yaml b/arch/inst/V/vslideup.vx.yaml index 5d1648d71d..4ae8d2240c 100644 --- a/arch/inst/V/vslideup.vx.yaml +++ b/arch/inst/V/vslideup.vx.yaml @@ -25,3 +25,56 @@ vslideup.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : nat = unsigned(X(rs1)); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VX_VSLIDEUP => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + if i >= rs1_val then vs2_val[i - rs1_val] else vd_val[i] + }, + VX_VSLIDEDOWN => { + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX > 0 & VLMAX <= 'n); + if i + rs1_val < VLMAX then vs2_val[i + rs1_val] else zeros() + }, + VX_VRGATHER => { + if (vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX > 0 & VLMAX <= 'n); + if rs1_val < VLMAX then vs2_val[rs1_val] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsll.vi.yaml b/arch/inst/V/vsll.vi.yaml index 065d75e7ab..1730c7dd10 100644 --- a/arch/inst/V/vsll.vi.yaml +++ b/arch/inst/V/vsll.vi.yaml @@ -25,3 +25,70 @@ vsll.vi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VI_VADD => vs2_val[i] + imm_val, + VI_VRSUB => imm_val - vs2_val[i], + VI_VAND => vs2_val[i] & imm_val, + VI_VOR => vs2_val[i] | imm_val, + VI_VXOR => vs2_val[i] ^ imm_val, + VI_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, imm_val) ), + VI_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, imm_val) ), + VI_VSLL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + vs2_val[i] << shift_amount + }, + VI_VSRL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + vs2_val[i] >> shift_amount + }, + VI_VSRA => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VI_VSSRL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VI_VSSRA => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsll.vv.yaml b/arch/inst/V/vsll.vv.yaml index 7aae99d2c9..b9bdfa4b60 100644 --- a/arch/inst/V/vsll.vv.yaml +++ b/arch/inst/V/vsll.vv.yaml @@ -25,3 +25,103 @@ vsll.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VV_VADD => vs2_val[i] + vs1_val[i], + VV_VSUB => vs2_val[i] - vs1_val[i], + VV_VAND => vs2_val[i] & vs1_val[i], + VV_VOR => vs2_val[i] | vs1_val[i], + VV_VXOR => vs2_val[i] ^ vs1_val[i], + VV_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i])), + VV_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i])), + VV_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(vs1_val[i]) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i])) + }, + VV_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i])), + VV_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(vs1_val[i])); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VV_VSLL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] << shift_amount + }, + VV_VSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] >> shift_amount + }, + VV_VSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VV_VSSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VV_VSSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VV_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VRGATHER => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let idx = unsigned(vs1_val[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + }, + VV_VRGATHEREI16 => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + /* vrgatherei16.vv uses SEW/LMUL for the data in vs2 but EEW=16 and EMUL = (16/SEW)*LMUL for the indices in vs1 */ + let vs1_new : vector('n, dec, bits(16)) = read_vreg(num_elem, 16, 4 + LMUL_pow - SEW_pow, vs1); + let idx = unsigned(vs1_new[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsll.vx.yaml b/arch/inst/V/vsll.vx.yaml index 8d6a519fb8..c1e1441362 100644 --- a/arch/inst/V/vsll.vx.yaml +++ b/arch/inst/V/vsll.vx.yaml @@ -25,3 +25,86 @@ vsll.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VX_VADD => vs2_val[i] + rs1_val, + VX_VSUB => vs2_val[i] - rs1_val, + VX_VRSUB => rs1_val - vs2_val[i], + VX_VAND => vs2_val[i] & rs1_val, + VX_VOR => vs2_val[i] | rs1_val, + VX_VXOR => vs2_val[i] ^ rs1_val, + VX_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val) ), + VX_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val) ), + VX_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(rs1_val) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val) ) + }, + VX_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val) ), + VX_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(rs1_val)); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VX_VSLL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] << shift_amount + }, + VX_VSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] >> shift_amount + }, + VX_VSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VX_VSSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VX_VSSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VX_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(rs1_val))), + VX_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(rs1_val))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsm.v.yaml b/arch/inst/V/vsm.v.yaml index f1c666c422..5da29c8f15 100644 --- a/arch/inst/V/vsm.v.yaml +++ b/arch/inst/V/vsm.v.yaml @@ -21,3 +21,21 @@ vsm.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let EEW = 8; + let EMUL_pow = 0; + let vl_val = unsigned(vl); + let evl : int = if vl_val % 8 == 0 then vl_val / 8 else vl_val / 8 + 1; /* the effective vector length is evl=ceil(vl/8) */ + let num_elem = get_num_elem(EMUL_pow, EEW); + + if illegal_vd_unmasked() then { handle_illegal(); return RETIRE_FAIL }; + + assert(evl >= 0); + process_vm(vd_or_vs3, rs1, num_elem, evl, op) + } + + \ No newline at end of file diff --git a/arch/inst/V/vsmul.vv.yaml b/arch/inst/V/vsmul.vv.yaml index 9513f95032..805431682f 100644 --- a/arch/inst/V/vsmul.vv.yaml +++ b/arch/inst/V/vsmul.vv.yaml @@ -25,3 +25,103 @@ vsmul.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VV_VADD => vs2_val[i] + vs1_val[i], + VV_VSUB => vs2_val[i] - vs1_val[i], + VV_VAND => vs2_val[i] & vs1_val[i], + VV_VOR => vs2_val[i] | vs1_val[i], + VV_VXOR => vs2_val[i] ^ vs1_val[i], + VV_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i])), + VV_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i])), + VV_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(vs1_val[i]) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i])) + }, + VV_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i])), + VV_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(vs1_val[i])); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VV_VSLL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] << shift_amount + }, + VV_VSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] >> shift_amount + }, + VV_VSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VV_VSSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VV_VSSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VV_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VRGATHER => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let idx = unsigned(vs1_val[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + }, + VV_VRGATHEREI16 => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + /* vrgatherei16.vv uses SEW/LMUL for the data in vs2 but EEW=16 and EMUL = (16/SEW)*LMUL for the indices in vs1 */ + let vs1_new : vector('n, dec, bits(16)) = read_vreg(num_elem, 16, 4 + LMUL_pow - SEW_pow, vs1); + let idx = unsigned(vs1_new[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsmul.vx.yaml b/arch/inst/V/vsmul.vx.yaml index 4f2cebb7b7..9db63d4257 100644 --- a/arch/inst/V/vsmul.vx.yaml +++ b/arch/inst/V/vsmul.vx.yaml @@ -25,3 +25,86 @@ vsmul.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VX_VADD => vs2_val[i] + rs1_val, + VX_VSUB => vs2_val[i] - rs1_val, + VX_VRSUB => rs1_val - vs2_val[i], + VX_VAND => vs2_val[i] & rs1_val, + VX_VOR => vs2_val[i] | rs1_val, + VX_VXOR => vs2_val[i] ^ rs1_val, + VX_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val) ), + VX_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val) ), + VX_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(rs1_val) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val) ) + }, + VX_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val) ), + VX_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(rs1_val)); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VX_VSLL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] << shift_amount + }, + VX_VSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] >> shift_amount + }, + VX_VSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VX_VSSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VX_VSSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VX_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(rs1_val))), + VX_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(rs1_val))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsoxei16.v.yaml b/arch/inst/V/vsoxei16.v.yaml index 9062408b31..3da70901b8 100644 --- a/arch/inst/V/vsoxei16.v.yaml +++ b/arch/inst/V/vsoxei16.v.yaml @@ -27,3 +27,23 @@ vsoxei16.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let EEW_index_pow = vlewidth_pow(width); + let EEW_index_bytes = vlewidth_bytesnumber(width); + let EEW_data_pow = get_sew_pow(); + let EEW_data_bytes = get_sew_bytes(); + let EMUL_data_pow = get_lmul_pow(); + let EMUL_index_pow = EEW_index_pow - EEW_data_pow + EMUL_data_pow; + let num_elem = get_num_elem(EMUL_data_pow, EEW_data_bytes * 8); /* number of data and indices are the same */ + let nf_int = nfields_int(nf); + + if illegal_indexed_store(nf_int, EEW_index_bytes * 8, EMUL_index_pow, EMUL_data_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vsxseg(nf_int, vm, vs3, EEW_index_bytes, EEW_data_bytes, EMUL_index_pow, EMUL_data_pow, rs1, vs2, num_elem, 1) + } + + \ No newline at end of file diff --git a/arch/inst/V/vsoxei32.v.yaml b/arch/inst/V/vsoxei32.v.yaml index 65cac60cd3..51624e2308 100644 --- a/arch/inst/V/vsoxei32.v.yaml +++ b/arch/inst/V/vsoxei32.v.yaml @@ -27,3 +27,23 @@ vsoxei32.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let EEW_index_pow = vlewidth_pow(width); + let EEW_index_bytes = vlewidth_bytesnumber(width); + let EEW_data_pow = get_sew_pow(); + let EEW_data_bytes = get_sew_bytes(); + let EMUL_data_pow = get_lmul_pow(); + let EMUL_index_pow = EEW_index_pow - EEW_data_pow + EMUL_data_pow; + let num_elem = get_num_elem(EMUL_data_pow, EEW_data_bytes * 8); /* number of data and indices are the same */ + let nf_int = nfields_int(nf); + + if illegal_indexed_store(nf_int, EEW_index_bytes * 8, EMUL_index_pow, EMUL_data_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vsxseg(nf_int, vm, vs3, EEW_index_bytes, EEW_data_bytes, EMUL_index_pow, EMUL_data_pow, rs1, vs2, num_elem, 1) + } + + \ No newline at end of file diff --git a/arch/inst/V/vsoxei64.v.yaml b/arch/inst/V/vsoxei64.v.yaml index a7e93dc64a..c11018025a 100644 --- a/arch/inst/V/vsoxei64.v.yaml +++ b/arch/inst/V/vsoxei64.v.yaml @@ -27,3 +27,23 @@ vsoxei64.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let EEW_index_pow = vlewidth_pow(width); + let EEW_index_bytes = vlewidth_bytesnumber(width); + let EEW_data_pow = get_sew_pow(); + let EEW_data_bytes = get_sew_bytes(); + let EMUL_data_pow = get_lmul_pow(); + let EMUL_index_pow = EEW_index_pow - EEW_data_pow + EMUL_data_pow; + let num_elem = get_num_elem(EMUL_data_pow, EEW_data_bytes * 8); /* number of data and indices are the same */ + let nf_int = nfields_int(nf); + + if illegal_indexed_store(nf_int, EEW_index_bytes * 8, EMUL_index_pow, EMUL_data_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vsxseg(nf_int, vm, vs3, EEW_index_bytes, EEW_data_bytes, EMUL_index_pow, EMUL_data_pow, rs1, vs2, num_elem, 1) + } + + \ No newline at end of file diff --git a/arch/inst/V/vsoxei8.v.yaml b/arch/inst/V/vsoxei8.v.yaml index 908d5542b7..8d2a615829 100644 --- a/arch/inst/V/vsoxei8.v.yaml +++ b/arch/inst/V/vsoxei8.v.yaml @@ -27,3 +27,23 @@ vsoxei8.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let EEW_index_pow = vlewidth_pow(width); + let EEW_index_bytes = vlewidth_bytesnumber(width); + let EEW_data_pow = get_sew_pow(); + let EEW_data_bytes = get_sew_bytes(); + let EMUL_data_pow = get_lmul_pow(); + let EMUL_index_pow = EEW_index_pow - EEW_data_pow + EMUL_data_pow; + let num_elem = get_num_elem(EMUL_data_pow, EEW_data_bytes * 8); /* number of data and indices are the same */ + let nf_int = nfields_int(nf); + + if illegal_indexed_store(nf_int, EEW_index_bytes * 8, EMUL_index_pow, EMUL_data_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vsxseg(nf_int, vm, vs3, EEW_index_bytes, EEW_data_bytes, EMUL_index_pow, EMUL_data_pow, rs1, vs2, num_elem, 1) + } + + \ No newline at end of file diff --git a/arch/inst/V/vsra.vi.yaml b/arch/inst/V/vsra.vi.yaml index a5fd9074f2..2265a49ec0 100644 --- a/arch/inst/V/vsra.vi.yaml +++ b/arch/inst/V/vsra.vi.yaml @@ -25,3 +25,70 @@ vsra.vi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VI_VADD => vs2_val[i] + imm_val, + VI_VRSUB => imm_val - vs2_val[i], + VI_VAND => vs2_val[i] & imm_val, + VI_VOR => vs2_val[i] | imm_val, + VI_VXOR => vs2_val[i] ^ imm_val, + VI_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, imm_val) ), + VI_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, imm_val) ), + VI_VSLL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + vs2_val[i] << shift_amount + }, + VI_VSRL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + vs2_val[i] >> shift_amount + }, + VI_VSRA => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VI_VSSRL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VI_VSSRA => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsra.vv.yaml b/arch/inst/V/vsra.vv.yaml index f8f7f186b4..8a19ab5a38 100644 --- a/arch/inst/V/vsra.vv.yaml +++ b/arch/inst/V/vsra.vv.yaml @@ -25,3 +25,103 @@ vsra.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VV_VADD => vs2_val[i] + vs1_val[i], + VV_VSUB => vs2_val[i] - vs1_val[i], + VV_VAND => vs2_val[i] & vs1_val[i], + VV_VOR => vs2_val[i] | vs1_val[i], + VV_VXOR => vs2_val[i] ^ vs1_val[i], + VV_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i])), + VV_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i])), + VV_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(vs1_val[i]) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i])) + }, + VV_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i])), + VV_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(vs1_val[i])); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VV_VSLL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] << shift_amount + }, + VV_VSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] >> shift_amount + }, + VV_VSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VV_VSSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VV_VSSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VV_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VRGATHER => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let idx = unsigned(vs1_val[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + }, + VV_VRGATHEREI16 => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + /* vrgatherei16.vv uses SEW/LMUL for the data in vs2 but EEW=16 and EMUL = (16/SEW)*LMUL for the indices in vs1 */ + let vs1_new : vector('n, dec, bits(16)) = read_vreg(num_elem, 16, 4 + LMUL_pow - SEW_pow, vs1); + let idx = unsigned(vs1_new[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsra.vx.yaml b/arch/inst/V/vsra.vx.yaml index 7b19bfe360..8a301ac021 100644 --- a/arch/inst/V/vsra.vx.yaml +++ b/arch/inst/V/vsra.vx.yaml @@ -25,3 +25,86 @@ vsra.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VX_VADD => vs2_val[i] + rs1_val, + VX_VSUB => vs2_val[i] - rs1_val, + VX_VRSUB => rs1_val - vs2_val[i], + VX_VAND => vs2_val[i] & rs1_val, + VX_VOR => vs2_val[i] | rs1_val, + VX_VXOR => vs2_val[i] ^ rs1_val, + VX_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val) ), + VX_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val) ), + VX_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(rs1_val) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val) ) + }, + VX_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val) ), + VX_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(rs1_val)); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VX_VSLL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] << shift_amount + }, + VX_VSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] >> shift_amount + }, + VX_VSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VX_VSSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VX_VSSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VX_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(rs1_val))), + VX_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(rs1_val))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsrl.vi.yaml b/arch/inst/V/vsrl.vi.yaml index 25080ed9c4..2d23c4d3b8 100644 --- a/arch/inst/V/vsrl.vi.yaml +++ b/arch/inst/V/vsrl.vi.yaml @@ -25,3 +25,70 @@ vsrl.vi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VI_VADD => vs2_val[i] + imm_val, + VI_VRSUB => imm_val - vs2_val[i], + VI_VAND => vs2_val[i] & imm_val, + VI_VOR => vs2_val[i] | imm_val, + VI_VXOR => vs2_val[i] ^ imm_val, + VI_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, imm_val) ), + VI_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, imm_val) ), + VI_VSLL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + vs2_val[i] << shift_amount + }, + VI_VSRL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + vs2_val[i] >> shift_amount + }, + VI_VSRA => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VI_VSSRL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VI_VSSRA => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsrl.vv.yaml b/arch/inst/V/vsrl.vv.yaml index cd5d09f232..7aaa049382 100644 --- a/arch/inst/V/vsrl.vv.yaml +++ b/arch/inst/V/vsrl.vv.yaml @@ -25,3 +25,103 @@ vsrl.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VV_VADD => vs2_val[i] + vs1_val[i], + VV_VSUB => vs2_val[i] - vs1_val[i], + VV_VAND => vs2_val[i] & vs1_val[i], + VV_VOR => vs2_val[i] | vs1_val[i], + VV_VXOR => vs2_val[i] ^ vs1_val[i], + VV_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i])), + VV_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i])), + VV_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(vs1_val[i]) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i])) + }, + VV_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i])), + VV_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(vs1_val[i])); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VV_VSLL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] << shift_amount + }, + VV_VSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] >> shift_amount + }, + VV_VSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VV_VSSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VV_VSSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VV_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VRGATHER => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let idx = unsigned(vs1_val[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + }, + VV_VRGATHEREI16 => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + /* vrgatherei16.vv uses SEW/LMUL for the data in vs2 but EEW=16 and EMUL = (16/SEW)*LMUL for the indices in vs1 */ + let vs1_new : vector('n, dec, bits(16)) = read_vreg(num_elem, 16, 4 + LMUL_pow - SEW_pow, vs1); + let idx = unsigned(vs1_new[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsrl.vx.yaml b/arch/inst/V/vsrl.vx.yaml index 3cc383a5ef..b788358eee 100644 --- a/arch/inst/V/vsrl.vx.yaml +++ b/arch/inst/V/vsrl.vx.yaml @@ -25,3 +25,86 @@ vsrl.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VX_VADD => vs2_val[i] + rs1_val, + VX_VSUB => vs2_val[i] - rs1_val, + VX_VRSUB => rs1_val - vs2_val[i], + VX_VAND => vs2_val[i] & rs1_val, + VX_VOR => vs2_val[i] | rs1_val, + VX_VXOR => vs2_val[i] ^ rs1_val, + VX_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val) ), + VX_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val) ), + VX_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(rs1_val) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val) ) + }, + VX_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val) ), + VX_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(rs1_val)); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VX_VSLL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] << shift_amount + }, + VX_VSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] >> shift_amount + }, + VX_VSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VX_VSSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VX_VSSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VX_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(rs1_val))), + VX_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(rs1_val))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsse16.v.yaml b/arch/inst/V/vsse16.v.yaml index e39e4dac52..e25f2a15bd 100644 --- a/arch/inst/V/vsse16.v.yaml +++ b/arch/inst/V/vsse16.v.yaml @@ -27,3 +27,23 @@ vsse16.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let load_width_bytes = vlewidth_bytesnumber(width); + let EEW = load_width_bytes * 8; + let EEW_pow = vlewidth_pow(width); + let SEW_pow = get_sew_pow(); + let LMUL_pow = get_lmul_pow(); + let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow; + let num_elem = get_num_elem(EMUL_pow, EEW); + let nf_int = nfields_int(nf); + + if illegal_store(nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vssseg(nf_int, vm, vs3, load_width_bytes, rs1, rs2, EMUL_pow, num_elem) + } + + \ No newline at end of file diff --git a/arch/inst/V/vsse32.v.yaml b/arch/inst/V/vsse32.v.yaml index eba592d29e..48b732758b 100644 --- a/arch/inst/V/vsse32.v.yaml +++ b/arch/inst/V/vsse32.v.yaml @@ -27,3 +27,23 @@ vsse32.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let load_width_bytes = vlewidth_bytesnumber(width); + let EEW = load_width_bytes * 8; + let EEW_pow = vlewidth_pow(width); + let SEW_pow = get_sew_pow(); + let LMUL_pow = get_lmul_pow(); + let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow; + let num_elem = get_num_elem(EMUL_pow, EEW); + let nf_int = nfields_int(nf); + + if illegal_store(nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vssseg(nf_int, vm, vs3, load_width_bytes, rs1, rs2, EMUL_pow, num_elem) + } + + \ No newline at end of file diff --git a/arch/inst/V/vsse64.v.yaml b/arch/inst/V/vsse64.v.yaml index aa84390e97..6d1cb0f9f9 100644 --- a/arch/inst/V/vsse64.v.yaml +++ b/arch/inst/V/vsse64.v.yaml @@ -27,3 +27,23 @@ vsse64.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let load_width_bytes = vlewidth_bytesnumber(width); + let EEW = load_width_bytes * 8; + let EEW_pow = vlewidth_pow(width); + let SEW_pow = get_sew_pow(); + let LMUL_pow = get_lmul_pow(); + let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow; + let num_elem = get_num_elem(EMUL_pow, EEW); + let nf_int = nfields_int(nf); + + if illegal_store(nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vssseg(nf_int, vm, vs3, load_width_bytes, rs1, rs2, EMUL_pow, num_elem) + } + + \ No newline at end of file diff --git a/arch/inst/V/vsse8.v.yaml b/arch/inst/V/vsse8.v.yaml index 305e6e575b..af130dbfaf 100644 --- a/arch/inst/V/vsse8.v.yaml +++ b/arch/inst/V/vsse8.v.yaml @@ -27,3 +27,23 @@ vsse8.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let load_width_bytes = vlewidth_bytesnumber(width); + let EEW = load_width_bytes * 8; + let EEW_pow = vlewidth_pow(width); + let SEW_pow = get_sew_pow(); + let LMUL_pow = get_lmul_pow(); + let EMUL_pow = EEW_pow - SEW_pow + LMUL_pow; + let num_elem = get_num_elem(EMUL_pow, EEW); + let nf_int = nfields_int(nf); + + if illegal_store(nf_int, EEW, EMUL_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vssseg(nf_int, vm, vs3, load_width_bytes, rs1, rs2, EMUL_pow, num_elem) + } + + \ No newline at end of file diff --git a/arch/inst/V/vssra.vi.yaml b/arch/inst/V/vssra.vi.yaml index 401fdaeaa3..e6fc4b837e 100644 --- a/arch/inst/V/vssra.vi.yaml +++ b/arch/inst/V/vssra.vi.yaml @@ -25,3 +25,70 @@ vssra.vi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VI_VADD => vs2_val[i] + imm_val, + VI_VRSUB => imm_val - vs2_val[i], + VI_VAND => vs2_val[i] & imm_val, + VI_VOR => vs2_val[i] | imm_val, + VI_VXOR => vs2_val[i] ^ imm_val, + VI_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, imm_val) ), + VI_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, imm_val) ), + VI_VSLL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + vs2_val[i] << shift_amount + }, + VI_VSRL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + vs2_val[i] >> shift_amount + }, + VI_VSRA => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VI_VSSRL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VI_VSSRA => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vssra.vv.yaml b/arch/inst/V/vssra.vv.yaml index 24e3bb4b7a..c38ea24f34 100644 --- a/arch/inst/V/vssra.vv.yaml +++ b/arch/inst/V/vssra.vv.yaml @@ -25,3 +25,103 @@ vssra.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VV_VADD => vs2_val[i] + vs1_val[i], + VV_VSUB => vs2_val[i] - vs1_val[i], + VV_VAND => vs2_val[i] & vs1_val[i], + VV_VOR => vs2_val[i] | vs1_val[i], + VV_VXOR => vs2_val[i] ^ vs1_val[i], + VV_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i])), + VV_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i])), + VV_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(vs1_val[i]) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i])) + }, + VV_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i])), + VV_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(vs1_val[i])); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VV_VSLL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] << shift_amount + }, + VV_VSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] >> shift_amount + }, + VV_VSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VV_VSSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VV_VSSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VV_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VRGATHER => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let idx = unsigned(vs1_val[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + }, + VV_VRGATHEREI16 => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + /* vrgatherei16.vv uses SEW/LMUL for the data in vs2 but EEW=16 and EMUL = (16/SEW)*LMUL for the indices in vs1 */ + let vs1_new : vector('n, dec, bits(16)) = read_vreg(num_elem, 16, 4 + LMUL_pow - SEW_pow, vs1); + let idx = unsigned(vs1_new[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vssra.vx.yaml b/arch/inst/V/vssra.vx.yaml index 57b4ef2d13..6b9153b754 100644 --- a/arch/inst/V/vssra.vx.yaml +++ b/arch/inst/V/vssra.vx.yaml @@ -25,3 +25,86 @@ vssra.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VX_VADD => vs2_val[i] + rs1_val, + VX_VSUB => vs2_val[i] - rs1_val, + VX_VRSUB => rs1_val - vs2_val[i], + VX_VAND => vs2_val[i] & rs1_val, + VX_VOR => vs2_val[i] | rs1_val, + VX_VXOR => vs2_val[i] ^ rs1_val, + VX_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val) ), + VX_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val) ), + VX_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(rs1_val) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val) ) + }, + VX_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val) ), + VX_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(rs1_val)); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VX_VSLL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] << shift_amount + }, + VX_VSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] >> shift_amount + }, + VX_VSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VX_VSSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VX_VSSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VX_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(rs1_val))), + VX_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(rs1_val))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vssrl.vi.yaml b/arch/inst/V/vssrl.vi.yaml index 26972408ef..2b3220447b 100644 --- a/arch/inst/V/vssrl.vi.yaml +++ b/arch/inst/V/vssrl.vi.yaml @@ -25,3 +25,70 @@ vssrl.vi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VI_VADD => vs2_val[i] + imm_val, + VI_VRSUB => imm_val - vs2_val[i], + VI_VAND => vs2_val[i] & imm_val, + VI_VOR => vs2_val[i] | imm_val, + VI_VXOR => vs2_val[i] ^ imm_val, + VI_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, imm_val) ), + VI_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, imm_val) ), + VI_VSLL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + vs2_val[i] << shift_amount + }, + VI_VSRL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + vs2_val[i] >> shift_amount + }, + VI_VSRA => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VI_VSSRL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VI_VSSRA => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vssrl.vv.yaml b/arch/inst/V/vssrl.vv.yaml index 5c391d4f9b..d8ac0e5207 100644 --- a/arch/inst/V/vssrl.vv.yaml +++ b/arch/inst/V/vssrl.vv.yaml @@ -25,3 +25,103 @@ vssrl.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VV_VADD => vs2_val[i] + vs1_val[i], + VV_VSUB => vs2_val[i] - vs1_val[i], + VV_VAND => vs2_val[i] & vs1_val[i], + VV_VOR => vs2_val[i] | vs1_val[i], + VV_VXOR => vs2_val[i] ^ vs1_val[i], + VV_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i])), + VV_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i])), + VV_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(vs1_val[i]) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i])) + }, + VV_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i])), + VV_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(vs1_val[i])); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VV_VSLL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] << shift_amount + }, + VV_VSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] >> shift_amount + }, + VV_VSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VV_VSSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VV_VSSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VV_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VRGATHER => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let idx = unsigned(vs1_val[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + }, + VV_VRGATHEREI16 => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + /* vrgatherei16.vv uses SEW/LMUL for the data in vs2 but EEW=16 and EMUL = (16/SEW)*LMUL for the indices in vs1 */ + let vs1_new : vector('n, dec, bits(16)) = read_vreg(num_elem, 16, 4 + LMUL_pow - SEW_pow, vs1); + let idx = unsigned(vs1_new[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vssrl.vx.yaml b/arch/inst/V/vssrl.vx.yaml index 9d34499d95..a61b6916da 100644 --- a/arch/inst/V/vssrl.vx.yaml +++ b/arch/inst/V/vssrl.vx.yaml @@ -25,3 +25,86 @@ vssrl.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VX_VADD => vs2_val[i] + rs1_val, + VX_VSUB => vs2_val[i] - rs1_val, + VX_VRSUB => rs1_val - vs2_val[i], + VX_VAND => vs2_val[i] & rs1_val, + VX_VOR => vs2_val[i] | rs1_val, + VX_VXOR => vs2_val[i] ^ rs1_val, + VX_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val) ), + VX_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val) ), + VX_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(rs1_val) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val) ) + }, + VX_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val) ), + VX_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(rs1_val)); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VX_VSLL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] << shift_amount + }, + VX_VSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] >> shift_amount + }, + VX_VSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VX_VSSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VX_VSSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VX_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(rs1_val))), + VX_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(rs1_val))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vssub.vv.yaml b/arch/inst/V/vssub.vv.yaml index 1880ef6813..cc5414087f 100644 --- a/arch/inst/V/vssub.vv.yaml +++ b/arch/inst/V/vssub.vv.yaml @@ -25,3 +25,103 @@ vssub.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VV_VADD => vs2_val[i] + vs1_val[i], + VV_VSUB => vs2_val[i] - vs1_val[i], + VV_VAND => vs2_val[i] & vs1_val[i], + VV_VOR => vs2_val[i] | vs1_val[i], + VV_VXOR => vs2_val[i] ^ vs1_val[i], + VV_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i])), + VV_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i])), + VV_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(vs1_val[i]) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i])) + }, + VV_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i])), + VV_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(vs1_val[i])); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VV_VSLL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] << shift_amount + }, + VV_VSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] >> shift_amount + }, + VV_VSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VV_VSSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VV_VSSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VV_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VRGATHER => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let idx = unsigned(vs1_val[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + }, + VV_VRGATHEREI16 => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + /* vrgatherei16.vv uses SEW/LMUL for the data in vs2 but EEW=16 and EMUL = (16/SEW)*LMUL for the indices in vs1 */ + let vs1_new : vector('n, dec, bits(16)) = read_vreg(num_elem, 16, 4 + LMUL_pow - SEW_pow, vs1); + let idx = unsigned(vs1_new[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vssub.vx.yaml b/arch/inst/V/vssub.vx.yaml index bbc2d056ef..cdf5489041 100644 --- a/arch/inst/V/vssub.vx.yaml +++ b/arch/inst/V/vssub.vx.yaml @@ -25,3 +25,86 @@ vssub.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VX_VADD => vs2_val[i] + rs1_val, + VX_VSUB => vs2_val[i] - rs1_val, + VX_VRSUB => rs1_val - vs2_val[i], + VX_VAND => vs2_val[i] & rs1_val, + VX_VOR => vs2_val[i] | rs1_val, + VX_VXOR => vs2_val[i] ^ rs1_val, + VX_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val) ), + VX_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val) ), + VX_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(rs1_val) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val) ) + }, + VX_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val) ), + VX_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(rs1_val)); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VX_VSLL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] << shift_amount + }, + VX_VSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] >> shift_amount + }, + VX_VSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VX_VSSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VX_VSSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VX_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(rs1_val))), + VX_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(rs1_val))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vssubu.vv.yaml b/arch/inst/V/vssubu.vv.yaml index 7d6a80b7fe..66b9135bdd 100644 --- a/arch/inst/V/vssubu.vv.yaml +++ b/arch/inst/V/vssubu.vv.yaml @@ -25,3 +25,103 @@ vssubu.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VV_VADD => vs2_val[i] + vs1_val[i], + VV_VSUB => vs2_val[i] - vs1_val[i], + VV_VAND => vs2_val[i] & vs1_val[i], + VV_VOR => vs2_val[i] | vs1_val[i], + VV_VXOR => vs2_val[i] ^ vs1_val[i], + VV_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i])), + VV_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i])), + VV_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(vs1_val[i]) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i])) + }, + VV_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i])), + VV_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(vs1_val[i])); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VV_VSLL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] << shift_amount + }, + VV_VSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] >> shift_amount + }, + VV_VSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VV_VSSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VV_VSSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VV_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VRGATHER => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let idx = unsigned(vs1_val[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + }, + VV_VRGATHEREI16 => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + /* vrgatherei16.vv uses SEW/LMUL for the data in vs2 but EEW=16 and EMUL = (16/SEW)*LMUL for the indices in vs1 */ + let vs1_new : vector('n, dec, bits(16)) = read_vreg(num_elem, 16, 4 + LMUL_pow - SEW_pow, vs1); + let idx = unsigned(vs1_new[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vssubu.vx.yaml b/arch/inst/V/vssubu.vx.yaml index 936df5168f..2bf9501c4b 100644 --- a/arch/inst/V/vssubu.vx.yaml +++ b/arch/inst/V/vssubu.vx.yaml @@ -25,3 +25,86 @@ vssubu.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VX_VADD => vs2_val[i] + rs1_val, + VX_VSUB => vs2_val[i] - rs1_val, + VX_VRSUB => rs1_val - vs2_val[i], + VX_VAND => vs2_val[i] & rs1_val, + VX_VOR => vs2_val[i] | rs1_val, + VX_VXOR => vs2_val[i] ^ rs1_val, + VX_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val) ), + VX_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val) ), + VX_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(rs1_val) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val) ) + }, + VX_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val) ), + VX_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(rs1_val)); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VX_VSLL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] << shift_amount + }, + VX_VSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] >> shift_amount + }, + VX_VSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VX_VSSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VX_VSSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VX_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(rs1_val))), + VX_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(rs1_val))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsub.vv.yaml b/arch/inst/V/vsub.vv.yaml index 815a526de9..fabeb4f4c3 100644 --- a/arch/inst/V/vsub.vv.yaml +++ b/arch/inst/V/vsub.vv.yaml @@ -25,3 +25,103 @@ vsub.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VV_VADD => vs2_val[i] + vs1_val[i], + VV_VSUB => vs2_val[i] - vs1_val[i], + VV_VAND => vs2_val[i] & vs1_val[i], + VV_VOR => vs2_val[i] | vs1_val[i], + VV_VXOR => vs2_val[i] ^ vs1_val[i], + VV_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i])), + VV_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i])), + VV_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(vs1_val[i]) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i])) + }, + VV_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i])), + VV_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(vs1_val[i])); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VV_VSLL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] << shift_amount + }, + VV_VSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] >> shift_amount + }, + VV_VSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VV_VSSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VV_VSSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VV_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VRGATHER => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let idx = unsigned(vs1_val[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + }, + VV_VRGATHEREI16 => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + /* vrgatherei16.vv uses SEW/LMUL for the data in vs2 but EEW=16 and EMUL = (16/SEW)*LMUL for the indices in vs1 */ + let vs1_new : vector('n, dec, bits(16)) = read_vreg(num_elem, 16, 4 + LMUL_pow - SEW_pow, vs1); + let idx = unsigned(vs1_new[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsub.vx.yaml b/arch/inst/V/vsub.vx.yaml index 3344124d4c..be71c99ae8 100644 --- a/arch/inst/V/vsub.vx.yaml +++ b/arch/inst/V/vsub.vx.yaml @@ -25,3 +25,86 @@ vsub.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VX_VADD => vs2_val[i] + rs1_val, + VX_VSUB => vs2_val[i] - rs1_val, + VX_VRSUB => rs1_val - vs2_val[i], + VX_VAND => vs2_val[i] & rs1_val, + VX_VOR => vs2_val[i] | rs1_val, + VX_VXOR => vs2_val[i] ^ rs1_val, + VX_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val) ), + VX_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val) ), + VX_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(rs1_val) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val) ) + }, + VX_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val) ), + VX_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(rs1_val)); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VX_VSLL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] << shift_amount + }, + VX_VSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] >> shift_amount + }, + VX_VSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VX_VSSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VX_VSSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VX_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(rs1_val))), + VX_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(rs1_val))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vsuxei16.v.yaml b/arch/inst/V/vsuxei16.v.yaml index 3680ec3f28..07e3bcba68 100644 --- a/arch/inst/V/vsuxei16.v.yaml +++ b/arch/inst/V/vsuxei16.v.yaml @@ -27,3 +27,23 @@ vsuxei16.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let EEW_index_pow = vlewidth_pow(width); + let EEW_index_bytes = vlewidth_bytesnumber(width); + let EEW_data_pow = get_sew_pow(); + let EEW_data_bytes = get_sew_bytes(); + let EMUL_data_pow = get_lmul_pow(); + let EMUL_index_pow = EEW_index_pow - EEW_data_pow + EMUL_data_pow; + let num_elem = get_num_elem(EMUL_data_pow, EEW_data_bytes * 8); /* number of data and indices are the same */ + let nf_int = nfields_int(nf); + + if illegal_indexed_store(nf_int, EEW_index_bytes * 8, EMUL_index_pow, EMUL_data_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vsxseg(nf_int, vm, vs3, EEW_index_bytes, EEW_data_bytes, EMUL_index_pow, EMUL_data_pow, rs1, vs2, num_elem, 1) + } + + \ No newline at end of file diff --git a/arch/inst/V/vsuxei32.v.yaml b/arch/inst/V/vsuxei32.v.yaml index 0e6075ab0e..195dd4f276 100644 --- a/arch/inst/V/vsuxei32.v.yaml +++ b/arch/inst/V/vsuxei32.v.yaml @@ -27,3 +27,23 @@ vsuxei32.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let EEW_index_pow = vlewidth_pow(width); + let EEW_index_bytes = vlewidth_bytesnumber(width); + let EEW_data_pow = get_sew_pow(); + let EEW_data_bytes = get_sew_bytes(); + let EMUL_data_pow = get_lmul_pow(); + let EMUL_index_pow = EEW_index_pow - EEW_data_pow + EMUL_data_pow; + let num_elem = get_num_elem(EMUL_data_pow, EEW_data_bytes * 8); /* number of data and indices are the same */ + let nf_int = nfields_int(nf); + + if illegal_indexed_store(nf_int, EEW_index_bytes * 8, EMUL_index_pow, EMUL_data_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vsxseg(nf_int, vm, vs3, EEW_index_bytes, EEW_data_bytes, EMUL_index_pow, EMUL_data_pow, rs1, vs2, num_elem, 1) + } + + \ No newline at end of file diff --git a/arch/inst/V/vsuxei64.v.yaml b/arch/inst/V/vsuxei64.v.yaml index 15c847264f..20cfdb758e 100644 --- a/arch/inst/V/vsuxei64.v.yaml +++ b/arch/inst/V/vsuxei64.v.yaml @@ -27,3 +27,23 @@ vsuxei64.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let EEW_index_pow = vlewidth_pow(width); + let EEW_index_bytes = vlewidth_bytesnumber(width); + let EEW_data_pow = get_sew_pow(); + let EEW_data_bytes = get_sew_bytes(); + let EMUL_data_pow = get_lmul_pow(); + let EMUL_index_pow = EEW_index_pow - EEW_data_pow + EMUL_data_pow; + let num_elem = get_num_elem(EMUL_data_pow, EEW_data_bytes * 8); /* number of data and indices are the same */ + let nf_int = nfields_int(nf); + + if illegal_indexed_store(nf_int, EEW_index_bytes * 8, EMUL_index_pow, EMUL_data_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vsxseg(nf_int, vm, vs3, EEW_index_bytes, EEW_data_bytes, EMUL_index_pow, EMUL_data_pow, rs1, vs2, num_elem, 1) + } + + \ No newline at end of file diff --git a/arch/inst/V/vsuxei8.v.yaml b/arch/inst/V/vsuxei8.v.yaml index 3392ca8d75..dce4069854 100644 --- a/arch/inst/V/vsuxei8.v.yaml +++ b/arch/inst/V/vsuxei8.v.yaml @@ -27,3 +27,23 @@ vsuxei8.v: data_independent_timing: false operation(): | + + + + sail(): | + { + let EEW_index_pow = vlewidth_pow(width); + let EEW_index_bytes = vlewidth_bytesnumber(width); + let EEW_data_pow = get_sew_pow(); + let EEW_data_bytes = get_sew_bytes(); + let EMUL_data_pow = get_lmul_pow(); + let EMUL_index_pow = EEW_index_pow - EEW_data_pow + EMUL_data_pow; + let num_elem = get_num_elem(EMUL_data_pow, EEW_data_bytes * 8); /* number of data and indices are the same */ + let nf_int = nfields_int(nf); + + if illegal_indexed_store(nf_int, EEW_index_bytes * 8, EMUL_index_pow, EMUL_data_pow) then { handle_illegal(); return RETIRE_FAIL }; + + process_vsxseg(nf_int, vm, vs3, EEW_index_bytes, EEW_data_bytes, EMUL_index_pow, EMUL_data_pow, rs1, vs2, num_elem, 1) + } + + \ No newline at end of file diff --git a/arch/inst/V/vwadd.vv.yaml b/arch/inst/V/vwadd.vv.yaml index ba67f925c2..8e1b7a8cfd 100644 --- a/arch/inst/V/vwadd.vv.yaml +++ b/arch/inst/V/vwadd.vv.yaml @@ -25,3 +25,52 @@ vwadd.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WVV_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(vs1_val[i])), + WVV_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(vs1_val[i])), + WVV_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(vs1_val[i])), + WVV_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(vs1_val[i])), + WVV_VWMUL => to_bits(SEW_widen, signed(vs2_val[i]) * signed(vs1_val[i])), + WVV_VWMULU => to_bits(SEW_widen, unsigned(vs2_val[i]) * unsigned(vs1_val[i])), + WVV_VWMULSU => to_bits(SEW_widen, signed(vs2_val[i]) * unsigned(vs1_val[i])) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwadd.vx.yaml b/arch/inst/V/vwadd.vx.yaml index dfb799a9d5..dd7a787dde 100644 --- a/arch/inst/V/vwadd.vx.yaml +++ b/arch/inst/V/vwadd.vx.yaml @@ -25,3 +25,51 @@ vwadd.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WVX_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(rs1_val)), + WVX_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(rs1_val)), + WVX_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(rs1_val)), + WVX_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(rs1_val)), + WVX_VWMUL => to_bits(SEW_widen, signed(vs2_val[i]) * signed(rs1_val)), + WVX_VWMULU => to_bits(SEW_widen, unsigned(vs2_val[i]) * unsigned(rs1_val)), + WVX_VWMULSU => to_bits(SEW_widen, signed(vs2_val[i]) * unsigned(rs1_val)) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwadd.wv.yaml b/arch/inst/V/vwadd.wv.yaml index 0124597c73..30e3eb951d 100644 --- a/arch/inst/V/vwadd.wv.yaml +++ b/arch/inst/V/vwadd.wv.yaml @@ -25,3 +25,48 @@ vwadd.wv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WV_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(vs1_val[i])), + WV_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(vs1_val[i])), + WV_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(vs1_val[i])), + WV_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(vs1_val[i])) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwadd.wx.yaml b/arch/inst/V/vwadd.wx.yaml index d43d3ce2d2..7c1b0b5d9d 100644 --- a/arch/inst/V/vwadd.wx.yaml +++ b/arch/inst/V/vwadd.wx.yaml @@ -25,3 +25,47 @@ vwadd.wx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WX_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(rs1_val)), + WX_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(rs1_val)), + WX_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(rs1_val)), + WX_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(rs1_val)) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwaddu.vv.yaml b/arch/inst/V/vwaddu.vv.yaml index aaf3d5066a..4482949c52 100644 --- a/arch/inst/V/vwaddu.vv.yaml +++ b/arch/inst/V/vwaddu.vv.yaml @@ -25,3 +25,52 @@ vwaddu.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WVV_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(vs1_val[i])), + WVV_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(vs1_val[i])), + WVV_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(vs1_val[i])), + WVV_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(vs1_val[i])), + WVV_VWMUL => to_bits(SEW_widen, signed(vs2_val[i]) * signed(vs1_val[i])), + WVV_VWMULU => to_bits(SEW_widen, unsigned(vs2_val[i]) * unsigned(vs1_val[i])), + WVV_VWMULSU => to_bits(SEW_widen, signed(vs2_val[i]) * unsigned(vs1_val[i])) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwaddu.vx.yaml b/arch/inst/V/vwaddu.vx.yaml index 2ff6a48ea3..8e5e95798a 100644 --- a/arch/inst/V/vwaddu.vx.yaml +++ b/arch/inst/V/vwaddu.vx.yaml @@ -25,3 +25,51 @@ vwaddu.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WVX_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(rs1_val)), + WVX_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(rs1_val)), + WVX_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(rs1_val)), + WVX_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(rs1_val)), + WVX_VWMUL => to_bits(SEW_widen, signed(vs2_val[i]) * signed(rs1_val)), + WVX_VWMULU => to_bits(SEW_widen, unsigned(vs2_val[i]) * unsigned(rs1_val)), + WVX_VWMULSU => to_bits(SEW_widen, signed(vs2_val[i]) * unsigned(rs1_val)) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwaddu.wv.yaml b/arch/inst/V/vwaddu.wv.yaml index 38e5723de4..b03e45e83b 100644 --- a/arch/inst/V/vwaddu.wv.yaml +++ b/arch/inst/V/vwaddu.wv.yaml @@ -25,3 +25,48 @@ vwaddu.wv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WV_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(vs1_val[i])), + WV_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(vs1_val[i])), + WV_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(vs1_val[i])), + WV_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(vs1_val[i])) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwaddu.wx.yaml b/arch/inst/V/vwaddu.wx.yaml index 65e5cac5e1..a08ac63cb0 100644 --- a/arch/inst/V/vwaddu.wx.yaml +++ b/arch/inst/V/vwaddu.wx.yaml @@ -25,3 +25,47 @@ vwaddu.wx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WX_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(rs1_val)), + WX_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(rs1_val)), + WX_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(rs1_val)), + WX_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(rs1_val)) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwmacc.vv.yaml b/arch/inst/V/vwmacc.vv.yaml index 4ef2679da1..24bde114be 100644 --- a/arch/inst/V/vwmacc.vv.yaml +++ b/arch/inst/V/vwmacc.vv.yaml @@ -25,3 +25,48 @@ vwmacc.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WMVV_VWMACC => to_bits(SEW_widen, signed(vs1_val[i]) * signed(vs2_val[i])) + vd_val[i], + WMVV_VWMACCU => to_bits(SEW_widen, unsigned(vs1_val[i]) * unsigned(vs2_val[i])) + vd_val[i], + WMVV_VWMACCSU => to_bits(SEW_widen, signed(vs1_val[i]) * unsigned(vs2_val[i]))+ vd_val[i] + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwmacc.vx.yaml b/arch/inst/V/vwmacc.vx.yaml index d16df42e9a..60e0c0932f 100644 --- a/arch/inst/V/vwmacc.vx.yaml +++ b/arch/inst/V/vwmacc.vx.yaml @@ -25,3 +25,48 @@ vwmacc.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WMVX_VWMACCU => (to_bits(SEW_widen, unsigned(rs1_val) * unsigned(vs2_val[i]) )) + vd_val[i], + WMVX_VWMACC => (to_bits(SEW_widen, signed(rs1_val) * signed(vs2_val[i]) )) + vd_val[i], + WMVX_VWMACCUS => (to_bits(SEW_widen, unsigned(rs1_val) * signed(vs2_val[i]) ))+ vd_val[i], + WMVX_VWMACCSU => (to_bits(SEW_widen, signed(rs1_val) * unsigned(vs2_val[i]) ))+ vd_val[i] + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwmaccsu.vv.yaml b/arch/inst/V/vwmaccsu.vv.yaml index 1b74a78b36..4f4c998962 100644 --- a/arch/inst/V/vwmaccsu.vv.yaml +++ b/arch/inst/V/vwmaccsu.vv.yaml @@ -25,3 +25,48 @@ vwmaccsu.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WMVV_VWMACC => to_bits(SEW_widen, signed(vs1_val[i]) * signed(vs2_val[i])) + vd_val[i], + WMVV_VWMACCU => to_bits(SEW_widen, unsigned(vs1_val[i]) * unsigned(vs2_val[i])) + vd_val[i], + WMVV_VWMACCSU => to_bits(SEW_widen, signed(vs1_val[i]) * unsigned(vs2_val[i]))+ vd_val[i] + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwmaccsu.vx.yaml b/arch/inst/V/vwmaccsu.vx.yaml index 607ca3dca8..d75326a2bc 100644 --- a/arch/inst/V/vwmaccsu.vx.yaml +++ b/arch/inst/V/vwmaccsu.vx.yaml @@ -25,3 +25,48 @@ vwmaccsu.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WMVX_VWMACCU => (to_bits(SEW_widen, unsigned(rs1_val) * unsigned(vs2_val[i]) )) + vd_val[i], + WMVX_VWMACC => (to_bits(SEW_widen, signed(rs1_val) * signed(vs2_val[i]) )) + vd_val[i], + WMVX_VWMACCUS => (to_bits(SEW_widen, unsigned(rs1_val) * signed(vs2_val[i]) ))+ vd_val[i], + WMVX_VWMACCSU => (to_bits(SEW_widen, signed(rs1_val) * unsigned(vs2_val[i]) ))+ vd_val[i] + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwmaccu.vv.yaml b/arch/inst/V/vwmaccu.vv.yaml index b79dec7ecb..3768505240 100644 --- a/arch/inst/V/vwmaccu.vv.yaml +++ b/arch/inst/V/vwmaccu.vv.yaml @@ -25,3 +25,48 @@ vwmaccu.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WMVV_VWMACC => to_bits(SEW_widen, signed(vs1_val[i]) * signed(vs2_val[i])) + vd_val[i], + WMVV_VWMACCU => to_bits(SEW_widen, unsigned(vs1_val[i]) * unsigned(vs2_val[i])) + vd_val[i], + WMVV_VWMACCSU => to_bits(SEW_widen, signed(vs1_val[i]) * unsigned(vs2_val[i]))+ vd_val[i] + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwmaccu.vx.yaml b/arch/inst/V/vwmaccu.vx.yaml index ab49797a15..ecc080ba2e 100644 --- a/arch/inst/V/vwmaccu.vx.yaml +++ b/arch/inst/V/vwmaccu.vx.yaml @@ -25,3 +25,48 @@ vwmaccu.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WMVX_VWMACCU => (to_bits(SEW_widen, unsigned(rs1_val) * unsigned(vs2_val[i]) )) + vd_val[i], + WMVX_VWMACC => (to_bits(SEW_widen, signed(rs1_val) * signed(vs2_val[i]) )) + vd_val[i], + WMVX_VWMACCUS => (to_bits(SEW_widen, unsigned(rs1_val) * signed(vs2_val[i]) ))+ vd_val[i], + WMVX_VWMACCSU => (to_bits(SEW_widen, signed(rs1_val) * unsigned(vs2_val[i]) ))+ vd_val[i] + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwmaccus.vx.yaml b/arch/inst/V/vwmaccus.vx.yaml index d132ee6084..eeaa643403 100644 --- a/arch/inst/V/vwmaccus.vx.yaml +++ b/arch/inst/V/vwmaccus.vx.yaml @@ -25,3 +25,48 @@ vwmaccus.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WMVX_VWMACCU => (to_bits(SEW_widen, unsigned(rs1_val) * unsigned(vs2_val[i]) )) + vd_val[i], + WMVX_VWMACC => (to_bits(SEW_widen, signed(rs1_val) * signed(vs2_val[i]) )) + vd_val[i], + WMVX_VWMACCUS => (to_bits(SEW_widen, unsigned(rs1_val) * signed(vs2_val[i]) ))+ vd_val[i], + WMVX_VWMACCSU => (to_bits(SEW_widen, signed(rs1_val) * unsigned(vs2_val[i]) ))+ vd_val[i] + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwmul.vv.yaml b/arch/inst/V/vwmul.vv.yaml index 07352802b1..bdd7f476d2 100644 --- a/arch/inst/V/vwmul.vv.yaml +++ b/arch/inst/V/vwmul.vv.yaml @@ -25,3 +25,52 @@ vwmul.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WVV_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(vs1_val[i])), + WVV_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(vs1_val[i])), + WVV_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(vs1_val[i])), + WVV_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(vs1_val[i])), + WVV_VWMUL => to_bits(SEW_widen, signed(vs2_val[i]) * signed(vs1_val[i])), + WVV_VWMULU => to_bits(SEW_widen, unsigned(vs2_val[i]) * unsigned(vs1_val[i])), + WVV_VWMULSU => to_bits(SEW_widen, signed(vs2_val[i]) * unsigned(vs1_val[i])) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwmul.vx.yaml b/arch/inst/V/vwmul.vx.yaml index a83627b54b..341138dd32 100644 --- a/arch/inst/V/vwmul.vx.yaml +++ b/arch/inst/V/vwmul.vx.yaml @@ -25,3 +25,51 @@ vwmul.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WVX_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(rs1_val)), + WVX_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(rs1_val)), + WVX_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(rs1_val)), + WVX_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(rs1_val)), + WVX_VWMUL => to_bits(SEW_widen, signed(vs2_val[i]) * signed(rs1_val)), + WVX_VWMULU => to_bits(SEW_widen, unsigned(vs2_val[i]) * unsigned(rs1_val)), + WVX_VWMULSU => to_bits(SEW_widen, signed(vs2_val[i]) * unsigned(rs1_val)) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwmulsu.vv.yaml b/arch/inst/V/vwmulsu.vv.yaml index ae144ced9c..300d934dd7 100644 --- a/arch/inst/V/vwmulsu.vv.yaml +++ b/arch/inst/V/vwmulsu.vv.yaml @@ -25,3 +25,52 @@ vwmulsu.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WVV_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(vs1_val[i])), + WVV_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(vs1_val[i])), + WVV_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(vs1_val[i])), + WVV_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(vs1_val[i])), + WVV_VWMUL => to_bits(SEW_widen, signed(vs2_val[i]) * signed(vs1_val[i])), + WVV_VWMULU => to_bits(SEW_widen, unsigned(vs2_val[i]) * unsigned(vs1_val[i])), + WVV_VWMULSU => to_bits(SEW_widen, signed(vs2_val[i]) * unsigned(vs1_val[i])) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwmulsu.vx.yaml b/arch/inst/V/vwmulsu.vx.yaml index 7948fff303..a65c44d50e 100644 --- a/arch/inst/V/vwmulsu.vx.yaml +++ b/arch/inst/V/vwmulsu.vx.yaml @@ -25,3 +25,51 @@ vwmulsu.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WVX_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(rs1_val)), + WVX_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(rs1_val)), + WVX_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(rs1_val)), + WVX_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(rs1_val)), + WVX_VWMUL => to_bits(SEW_widen, signed(vs2_val[i]) * signed(rs1_val)), + WVX_VWMULU => to_bits(SEW_widen, unsigned(vs2_val[i]) * unsigned(rs1_val)), + WVX_VWMULSU => to_bits(SEW_widen, signed(vs2_val[i]) * unsigned(rs1_val)) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwmulu.vv.yaml b/arch/inst/V/vwmulu.vv.yaml index 9de65c29f9..7a8b3b5276 100644 --- a/arch/inst/V/vwmulu.vv.yaml +++ b/arch/inst/V/vwmulu.vv.yaml @@ -25,3 +25,52 @@ vwmulu.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WVV_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(vs1_val[i])), + WVV_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(vs1_val[i])), + WVV_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(vs1_val[i])), + WVV_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(vs1_val[i])), + WVV_VWMUL => to_bits(SEW_widen, signed(vs2_val[i]) * signed(vs1_val[i])), + WVV_VWMULU => to_bits(SEW_widen, unsigned(vs2_val[i]) * unsigned(vs1_val[i])), + WVV_VWMULSU => to_bits(SEW_widen, signed(vs2_val[i]) * unsigned(vs1_val[i])) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwmulu.vx.yaml b/arch/inst/V/vwmulu.vx.yaml index 9b9122c4d1..d7002afb36 100644 --- a/arch/inst/V/vwmulu.vx.yaml +++ b/arch/inst/V/vwmulu.vx.yaml @@ -25,3 +25,51 @@ vwmulu.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WVX_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(rs1_val)), + WVX_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(rs1_val)), + WVX_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(rs1_val)), + WVX_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(rs1_val)), + WVX_VWMUL => to_bits(SEW_widen, signed(vs2_val[i]) * signed(rs1_val)), + WVX_VWMULU => to_bits(SEW_widen, unsigned(vs2_val[i]) * unsigned(rs1_val)), + WVX_VWMULSU => to_bits(SEW_widen, signed(vs2_val[i]) * unsigned(rs1_val)) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwredsum.vs.yaml b/arch/inst/V/vwredsum.vs.yaml index 5a8a223027..53b2b9176b 100644 --- a/arch/inst/V/vwredsum.vs.yaml +++ b/arch/inst/V/vwredsum.vs.yaml @@ -25,3 +25,48 @@ vwredsum.vs: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + let num_elem_vs = get_num_elem(LMUL_pow, SEW); + let num_elem_vd = get_num_elem(0, SEW_widen); /* vd regardless of LMUL setting */ + + if illegal_reduction_widen(SEW_widen, LMUL_pow_widen) then { handle_illegal(); return RETIRE_FAIL }; + + if unsigned(vl) == 0 then return RETIRE_SUCCESS; /* if vl=0, no operation is performed */ + + let 'n = num_elem_vs; + let 'd = num_elem_vd; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem_vs, vm, 0b00000); + let vd_val : vector('d, dec, bits('o)) = read_vreg(num_elem_vd, SEW_widen, 0, vd); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem_vs, SEW, LMUL_pow, vs2); + let mask : vector('n, dec, bool) = init_masked_source(num_elem_vs, LMUL_pow, vm_val); + + sum : bits('o) = read_single_element(SEW_widen, 0, vs1); /* vs1 regardless of LMUL setting */ + foreach (i from 0 to (num_elem_vs - 1)) { + if mask[i] then { + let elem : bits('o) = match funct6 { + IVV_VWREDSUMU => to_bits(SEW_widen, unsigned(vs2_val[i])), + IVV_VWREDSUM => to_bits(SEW_widen, signed(vs2_val[i])) + }; + sum = sum + elem + } + }; + + write_single_element(SEW_widen, 0, vd, sum); + /* other elements in vd are treated as tail elements, currently remain unchanged */ + /* TODO: configuration support for agnostic behavior */ + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwredsumu.vs.yaml b/arch/inst/V/vwredsumu.vs.yaml index a3146483fa..fc5bbb5edc 100644 --- a/arch/inst/V/vwredsumu.vs.yaml +++ b/arch/inst/V/vwredsumu.vs.yaml @@ -25,3 +25,48 @@ vwredsumu.vs: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + let num_elem_vs = get_num_elem(LMUL_pow, SEW); + let num_elem_vd = get_num_elem(0, SEW_widen); /* vd regardless of LMUL setting */ + + if illegal_reduction_widen(SEW_widen, LMUL_pow_widen) then { handle_illegal(); return RETIRE_FAIL }; + + if unsigned(vl) == 0 then return RETIRE_SUCCESS; /* if vl=0, no operation is performed */ + + let 'n = num_elem_vs; + let 'd = num_elem_vd; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem_vs, vm, 0b00000); + let vd_val : vector('d, dec, bits('o)) = read_vreg(num_elem_vd, SEW_widen, 0, vd); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem_vs, SEW, LMUL_pow, vs2); + let mask : vector('n, dec, bool) = init_masked_source(num_elem_vs, LMUL_pow, vm_val); + + sum : bits('o) = read_single_element(SEW_widen, 0, vs1); /* vs1 regardless of LMUL setting */ + foreach (i from 0 to (num_elem_vs - 1)) { + if mask[i] then { + let elem : bits('o) = match funct6 { + IVV_VWREDSUMU => to_bits(SEW_widen, unsigned(vs2_val[i])), + IVV_VWREDSUM => to_bits(SEW_widen, signed(vs2_val[i])) + }; + sum = sum + elem + } + }; + + write_single_element(SEW_widen, 0, vd, sum); + /* other elements in vd are treated as tail elements, currently remain unchanged */ + /* TODO: configuration support for agnostic behavior */ + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwsub.vv.yaml b/arch/inst/V/vwsub.vv.yaml index f052a059d7..81d3ee13ef 100644 --- a/arch/inst/V/vwsub.vv.yaml +++ b/arch/inst/V/vwsub.vv.yaml @@ -25,3 +25,52 @@ vwsub.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WVV_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(vs1_val[i])), + WVV_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(vs1_val[i])), + WVV_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(vs1_val[i])), + WVV_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(vs1_val[i])), + WVV_VWMUL => to_bits(SEW_widen, signed(vs2_val[i]) * signed(vs1_val[i])), + WVV_VWMULU => to_bits(SEW_widen, unsigned(vs2_val[i]) * unsigned(vs1_val[i])), + WVV_VWMULSU => to_bits(SEW_widen, signed(vs2_val[i]) * unsigned(vs1_val[i])) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwsub.vx.yaml b/arch/inst/V/vwsub.vx.yaml index 80602aac75..ef60087ff2 100644 --- a/arch/inst/V/vwsub.vx.yaml +++ b/arch/inst/V/vwsub.vx.yaml @@ -25,3 +25,51 @@ vwsub.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WVX_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(rs1_val)), + WVX_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(rs1_val)), + WVX_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(rs1_val)), + WVX_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(rs1_val)), + WVX_VWMUL => to_bits(SEW_widen, signed(vs2_val[i]) * signed(rs1_val)), + WVX_VWMULU => to_bits(SEW_widen, unsigned(vs2_val[i]) * unsigned(rs1_val)), + WVX_VWMULSU => to_bits(SEW_widen, signed(vs2_val[i]) * unsigned(rs1_val)) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwsub.wv.yaml b/arch/inst/V/vwsub.wv.yaml index 82a1b661e8..0fd993451d 100644 --- a/arch/inst/V/vwsub.wv.yaml +++ b/arch/inst/V/vwsub.wv.yaml @@ -25,3 +25,48 @@ vwsub.wv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WV_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(vs1_val[i])), + WV_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(vs1_val[i])), + WV_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(vs1_val[i])), + WV_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(vs1_val[i])) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwsub.wx.yaml b/arch/inst/V/vwsub.wx.yaml index d65e89fd9e..710c4562b8 100644 --- a/arch/inst/V/vwsub.wx.yaml +++ b/arch/inst/V/vwsub.wx.yaml @@ -25,3 +25,47 @@ vwsub.wx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WX_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(rs1_val)), + WX_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(rs1_val)), + WX_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(rs1_val)), + WX_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(rs1_val)) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwsubu.vv.yaml b/arch/inst/V/vwsubu.vv.yaml index c45f087227..04b6b1ac48 100644 --- a/arch/inst/V/vwsubu.vv.yaml +++ b/arch/inst/V/vwsubu.vv.yaml @@ -25,3 +25,52 @@ vwsubu.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WVV_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(vs1_val[i])), + WVV_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(vs1_val[i])), + WVV_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(vs1_val[i])), + WVV_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(vs1_val[i])), + WVV_VWMUL => to_bits(SEW_widen, signed(vs2_val[i]) * signed(vs1_val[i])), + WVV_VWMULU => to_bits(SEW_widen, unsigned(vs2_val[i]) * unsigned(vs1_val[i])), + WVV_VWMULSU => to_bits(SEW_widen, signed(vs2_val[i]) * unsigned(vs1_val[i])) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwsubu.vx.yaml b/arch/inst/V/vwsubu.vx.yaml index 28077ff1fd..a9b3c699fd 100644 --- a/arch/inst/V/vwsubu.vx.yaml +++ b/arch/inst/V/vwsubu.vx.yaml @@ -25,3 +25,51 @@ vwsubu.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs2, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WVX_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(rs1_val)), + WVX_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(rs1_val)), + WVX_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(rs1_val)), + WVX_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(rs1_val)), + WVX_VWMUL => to_bits(SEW_widen, signed(vs2_val[i]) * signed(rs1_val)), + WVX_VWMULU => to_bits(SEW_widen, unsigned(vs2_val[i]) * unsigned(rs1_val)), + WVX_VWMULSU => to_bits(SEW_widen, signed(vs2_val[i]) * unsigned(rs1_val)) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwsubu.wv.yaml b/arch/inst/V/vwsubu.wv.yaml index 52e7e62c49..f34fb40efd 100644 --- a/arch/inst/V/vwsubu.wv.yaml +++ b/arch/inst/V/vwsubu.wv.yaml @@ -25,3 +25,48 @@ vwsubu.wv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) | + not(valid_reg_overlap(vs1, vd, LMUL_pow, LMUL_pow_widen)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WV_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(vs1_val[i])), + WV_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(vs1_val[i])), + WV_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(vs1_val[i])), + WV_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(vs1_val[i])) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vwsubu.wx.yaml b/arch/inst/V/vwsubu.wx.yaml index c71c852904..564d4df861 100644 --- a/arch/inst/V/vwsubu.wx.yaml +++ b/arch/inst/V/vwsubu.wx.yaml @@ -25,3 +25,47 @@ vwsubu.wx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_widen = SEW * 2; + let LMUL_pow_widen = LMUL_pow + 1; + + if illegal_variable_width(vd, vm, SEW_widen, LMUL_pow_widen) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_widen; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_widen, LMUL_pow_widen, vs2); + result : vector('n, dec, bits('o)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW_widen, LMUL_pow_widen, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + WX_VADD => to_bits(SEW_widen, signed(vs2_val[i]) + signed(rs1_val)), + WX_VSUB => to_bits(SEW_widen, signed(vs2_val[i]) - signed(rs1_val)), + WX_VADDU => to_bits(SEW_widen, unsigned(vs2_val[i]) + unsigned(rs1_val)), + WX_VSUBU => to_bits(SEW_widen, unsigned(vs2_val[i]) - unsigned(rs1_val)) + } + } + }; + + write_vreg(num_elem, SEW_widen, LMUL_pow_widen, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vxor.vi.yaml b/arch/inst/V/vxor.vi.yaml index 89dc09f706..c552c2872a 100644 --- a/arch/inst/V/vxor.vi.yaml +++ b/arch/inst/V/vxor.vi.yaml @@ -25,3 +25,70 @@ vxor.vi: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let imm_val : bits('m) = sign_extend(simm); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VI_VADD => vs2_val[i] + imm_val, + VI_VRSUB => imm_val - vs2_val[i], + VI_VAND => vs2_val[i] & imm_val, + VI_VOR => vs2_val[i] | imm_val, + VI_VXOR => vs2_val[i] ^ imm_val, + VI_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, imm_val) ), + VI_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, imm_val) ), + VI_VSLL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + vs2_val[i] << shift_amount + }, + VI_VSRL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + vs2_val[i] >> shift_amount + }, + VI_VSRA => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VI_VSSRL => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VI_VSSRA => { + let shift_amount = get_shift_amount(zero_extend('m, simm), SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vxor.vv.yaml b/arch/inst/V/vxor.vv.yaml index 4f266770f9..b7c008f029 100644 --- a/arch/inst/V/vxor.vv.yaml +++ b/arch/inst/V/vxor.vv.yaml @@ -25,3 +25,103 @@ vxor.vv: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW_pow = get_sew_pow(); + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let VLEN_pow = get_vlen_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vs1_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs1); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VV_VADD => vs2_val[i] + vs1_val[i], + VV_VSUB => vs2_val[i] - vs1_val[i], + VV_VAND => vs2_val[i] & vs1_val[i], + VV_VOR => vs2_val[i] | vs1_val[i], + VV_VXOR => vs2_val[i] ^ vs1_val[i], + VV_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, vs1_val[i])), + VV_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, vs1_val[i])), + VV_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(vs1_val[i]) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, vs1_val[i])) + }, + VV_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, vs1_val[i])), + VV_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(vs1_val[i])); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VV_VSLL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] << shift_amount + }, + VV_VSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + vs2_val[i] >> shift_amount + }, + VV_VSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VV_VSSRL => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VV_VSSRA => { + let shift_amount = get_shift_amount(vs1_val[i], SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VV_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(vs1_val[i]))), + VV_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(vs1_val[i]))), + VV_VRGATHER => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + let idx = unsigned(vs1_val[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + }, + VV_VRGATHEREI16 => { + if (vs1 == vd | vs2 == vd) then { handle_illegal(); return RETIRE_FAIL }; + /* vrgatherei16.vv uses SEW/LMUL for the data in vs2 but EEW=16 and EMUL = (16/SEW)*LMUL for the indices in vs1 */ + let vs1_new : vector('n, dec, bits(16)) = read_vreg(num_elem, 16, 4 + LMUL_pow - SEW_pow, vs1); + let idx = unsigned(vs1_new[i]); + let VLMAX = int_power(2, LMUL_pow + VLEN_pow - SEW_pow); + assert(VLMAX <= 'n); + if idx < VLMAX then vs2_val[idx] else zeros() + } + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vxor.vx.yaml b/arch/inst/V/vxor.vx.yaml index 63d86263bb..25a62e254c 100644 --- a/arch/inst/V/vxor.vx.yaml +++ b/arch/inst/V/vxor.vx.yaml @@ -25,3 +25,86 @@ vxor.vx: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + + if illegal_normal(vd, vm) then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let rs1_val : bits('m) = get_scalar(rs1, SEW); + let vs2_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vs2); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VX_VADD => vs2_val[i] + rs1_val, + VX_VSUB => vs2_val[i] - rs1_val, + VX_VRSUB => rs1_val - vs2_val[i], + VX_VAND => vs2_val[i] & rs1_val, + VX_VOR => vs2_val[i] | rs1_val, + VX_VXOR => vs2_val[i] ^ rs1_val, + VX_VSADDU => unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) + zero_extend('m + 1, rs1_val) ), + VX_VSADD => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) + sign_extend('m + 1, rs1_val) ), + VX_VSSUBU => { + if unsigned(vs2_val[i]) < unsigned(rs1_val) then zeros() + else unsigned_saturation('m, zero_extend('m + 1, vs2_val[i]) - zero_extend('m + 1, rs1_val) ) + }, + VX_VSSUB => signed_saturation('m, sign_extend('m + 1, vs2_val[i]) - sign_extend('m + 1, rs1_val) ), + VX_VSMUL => { + let result_mul = to_bits('m * 2, signed(vs2_val[i]) * signed(rs1_val)); + let rounding_incr = get_fixed_rounding_incr(result_mul, 'm - 1); + let result_wide = (result_mul >> ('m - 1)) + zero_extend('m * 2, rounding_incr); + signed_saturation('m, result_wide['m..0]) + }, + VX_VSLL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] << shift_amount + }, + VX_VSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + vs2_val[i] >> shift_amount + }, + VX_VSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + }, + VX_VSSRL => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + (vs2_val[i] >> shift_amount) + zero_extend('m, rounding_incr) + }, + VX_VSSRA => { + let shift_amount = get_shift_amount(rs1_val, SEW); + let rounding_incr = get_fixed_rounding_incr(vs2_val[i], shift_amount); + let v_double : bits('m * 2) = sign_extend(vs2_val[i]); + slice(v_double >> shift_amount, 0, SEW) + zero_extend('m, rounding_incr) + }, + VX_VMINU => to_bits(SEW, min(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMIN => to_bits(SEW, min(signed(vs2_val[i]), signed(rs1_val))), + VX_VMAXU => to_bits(SEW, max(unsigned(vs2_val[i]), unsigned(rs1_val))), + VX_VMAX => to_bits(SEW, max(signed(vs2_val[i]), signed(rs1_val))) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vzext.vf2.yaml b/arch/inst/V/vzext.vf2.yaml index 4018a36fef..65aa0deec3 100644 --- a/arch/inst/V/vzext.vf2.yaml +++ b/arch/inst/V/vzext.vf2.yaml @@ -23,3 +23,46 @@ vzext.vf2: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_half = SEW / 2; + let LMUL_pow_half = LMUL_pow - 1; + + if illegal_variable_width(vd, vm, SEW_half, LMUL_pow_half) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_half, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_half; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_half, LMUL_pow_half, vs2); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + assert(SEW > SEW_half); + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VEXT2_ZVF2 => zero_extend(vs2_val[i]), + VEXT2_SVF2 => sign_extend(vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vzext.vf4.yaml b/arch/inst/V/vzext.vf4.yaml index 5b10065e82..4ae4120d09 100644 --- a/arch/inst/V/vzext.vf4.yaml +++ b/arch/inst/V/vzext.vf4.yaml @@ -23,3 +23,46 @@ vzext.vf4: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_quart = SEW / 4; + let LMUL_pow_quart = LMUL_pow - 2; + + if illegal_variable_width(vd, vm, SEW_quart, LMUL_pow_quart) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_quart, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_quart; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_quart, LMUL_pow_quart, vs2); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + assert(SEW > SEW_quart); + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VEXT4_ZVF4 => zero_extend(vs2_val[i]), + VEXT4_SVF4 => sign_extend(vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/V/vzext.vf8.yaml b/arch/inst/V/vzext.vf8.yaml index f2c63a3e93..584373a9c2 100644 --- a/arch/inst/V/vzext.vf8.yaml +++ b/arch/inst/V/vzext.vf8.yaml @@ -23,3 +23,46 @@ vzext.vf8: data_independent_timing: false operation(): | + + + + sail(): | + { + let SEW = get_sew(); + let LMUL_pow = get_lmul_pow(); + let num_elem = get_num_elem(LMUL_pow, SEW); + let SEW_eighth = SEW / 8; + let LMUL_pow_eighth = LMUL_pow - 3; + + if illegal_variable_width(vd, vm, SEW_eighth, LMUL_pow_eighth) | + not(valid_reg_overlap(vs2, vd, LMUL_pow_eighth, LMUL_pow)) + then { handle_illegal(); return RETIRE_FAIL }; + + let 'n = num_elem; + let 'm = SEW; + let 'o = SEW_eighth; + + let vm_val : vector('n, dec, bool) = read_vmask(num_elem, vm, 0b00000); + let vd_val : vector('n, dec, bits('m)) = read_vreg(num_elem, SEW, LMUL_pow, vd); + let vs2_val : vector('n, dec, bits('o)) = read_vreg(num_elem, SEW_eighth, LMUL_pow_eighth, vs2); + result : vector('n, dec, bits('m)) = undefined; + mask : vector('n, dec, bool) = undefined; + + (result, mask) = init_masked_result(num_elem, SEW, LMUL_pow, vd_val, vm_val); + + assert(SEW > SEW_eighth); + foreach (i from 0 to (num_elem - 1)) { + if mask[i] then { + result[i] = match funct6 { + VEXT8_ZVF8 => zero_extend(vs2_val[i]), + VEXT8_SVF8 => sign_extend(vs2_val[i]) + } + } + }; + + write_vreg(num_elem, SEW, LMUL_pow, vd, result); + vstart = zeros(); + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/Zabha/amoadd.b.yaml b/arch/inst/Zabha/amoadd.b.yaml index be1295e590..4e0c46d6b4 100644 --- a/arch/inst/Zabha/amoadd.b.yaml +++ b/arch/inst/Zabha/amoadd.b.yaml @@ -27,3 +27,98 @@ amoadd.b: data_independent_timing: false operation(): | + + + + 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/Zabha/amoadd.h.yaml b/arch/inst/Zabha/amoadd.h.yaml index d7d94d5bdd..eaecfc8b3e 100644 --- a/arch/inst/Zabha/amoadd.h.yaml +++ b/arch/inst/Zabha/amoadd.h.yaml @@ -27,3 +27,98 @@ amoadd.h: data_independent_timing: false operation(): | + + + + 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/Zabha/amoand.b.yaml b/arch/inst/Zabha/amoand.b.yaml index 89c08f3597..2fe971a45d 100644 --- a/arch/inst/Zabha/amoand.b.yaml +++ b/arch/inst/Zabha/amoand.b.yaml @@ -27,3 +27,98 @@ amoand.b: data_independent_timing: false operation(): | + + + + 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/Zabha/amoand.h.yaml b/arch/inst/Zabha/amoand.h.yaml index 50c5da98f6..0d45a5e3a8 100644 --- a/arch/inst/Zabha/amoand.h.yaml +++ b/arch/inst/Zabha/amoand.h.yaml @@ -27,3 +27,98 @@ amoand.h: data_independent_timing: false operation(): | + + + + 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/Zabha/amomax.b.yaml b/arch/inst/Zabha/amomax.b.yaml index fb8fcfe927..ab0271dbe0 100644 --- a/arch/inst/Zabha/amomax.b.yaml +++ b/arch/inst/Zabha/amomax.b.yaml @@ -27,3 +27,98 @@ amomax.b: data_independent_timing: false operation(): | + + + + 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/Zabha/amomax.h.yaml b/arch/inst/Zabha/amomax.h.yaml index 5c524412d7..5fbdd9fab2 100644 --- a/arch/inst/Zabha/amomax.h.yaml +++ b/arch/inst/Zabha/amomax.h.yaml @@ -27,3 +27,98 @@ amomax.h: data_independent_timing: false operation(): | + + + + 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/Zabha/amomaxu.b.yaml b/arch/inst/Zabha/amomaxu.b.yaml index a37190fa2c..c8b5fe2679 100644 --- a/arch/inst/Zabha/amomaxu.b.yaml +++ b/arch/inst/Zabha/amomaxu.b.yaml @@ -27,3 +27,98 @@ amomaxu.b: data_independent_timing: false operation(): | + + + + 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/Zabha/amomaxu.h.yaml b/arch/inst/Zabha/amomaxu.h.yaml index f73ad60473..b3206cbe30 100644 --- a/arch/inst/Zabha/amomaxu.h.yaml +++ b/arch/inst/Zabha/amomaxu.h.yaml @@ -27,3 +27,98 @@ amomaxu.h: data_independent_timing: false operation(): | + + + + 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/Zabha/amomin.b.yaml b/arch/inst/Zabha/amomin.b.yaml index 68285f5cce..ee1ab2fcd8 100644 --- a/arch/inst/Zabha/amomin.b.yaml +++ b/arch/inst/Zabha/amomin.b.yaml @@ -27,3 +27,98 @@ amomin.b: data_independent_timing: false operation(): | + + + + 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/Zabha/amomin.h.yaml b/arch/inst/Zabha/amomin.h.yaml index 6f1c3d97ed..b9d58d2513 100644 --- a/arch/inst/Zabha/amomin.h.yaml +++ b/arch/inst/Zabha/amomin.h.yaml @@ -27,3 +27,98 @@ amomin.h: data_independent_timing: false operation(): | + + + + 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/Zabha/amominu.b.yaml b/arch/inst/Zabha/amominu.b.yaml index 19e9f0391e..cea2e1b6f8 100644 --- a/arch/inst/Zabha/amominu.b.yaml +++ b/arch/inst/Zabha/amominu.b.yaml @@ -27,3 +27,98 @@ amominu.b: data_independent_timing: false operation(): | + + + + 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/Zabha/amominu.h.yaml b/arch/inst/Zabha/amominu.h.yaml index 6e89ec8397..e4adb78a75 100644 --- a/arch/inst/Zabha/amominu.h.yaml +++ b/arch/inst/Zabha/amominu.h.yaml @@ -27,3 +27,98 @@ amominu.h: data_independent_timing: false operation(): | + + + + 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/Zabha/amoor.b.yaml b/arch/inst/Zabha/amoor.b.yaml index 9f853d7abd..1c899e42a7 100644 --- a/arch/inst/Zabha/amoor.b.yaml +++ b/arch/inst/Zabha/amoor.b.yaml @@ -27,3 +27,98 @@ amoor.b: data_independent_timing: false operation(): | + + + + 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/Zabha/amoor.h.yaml b/arch/inst/Zabha/amoor.h.yaml index bf9581bb6f..adc4226d6c 100644 --- a/arch/inst/Zabha/amoor.h.yaml +++ b/arch/inst/Zabha/amoor.h.yaml @@ -27,3 +27,98 @@ amoor.h: data_independent_timing: false operation(): | + + + + 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/Zabha/amoswap.b.yaml b/arch/inst/Zabha/amoswap.b.yaml index e4ffe826db..f5404270bc 100644 --- a/arch/inst/Zabha/amoswap.b.yaml +++ b/arch/inst/Zabha/amoswap.b.yaml @@ -27,3 +27,98 @@ amoswap.b: data_independent_timing: false operation(): | + + + + 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/Zabha/amoswap.h.yaml b/arch/inst/Zabha/amoswap.h.yaml index d82e2a040c..bede3da587 100644 --- a/arch/inst/Zabha/amoswap.h.yaml +++ b/arch/inst/Zabha/amoswap.h.yaml @@ -27,3 +27,98 @@ amoswap.h: data_independent_timing: false operation(): | + + + + 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/Zabha/amoxor.b.yaml b/arch/inst/Zabha/amoxor.b.yaml index 6f921749e0..8ec5bae68f 100644 --- a/arch/inst/Zabha/amoxor.b.yaml +++ b/arch/inst/Zabha/amoxor.b.yaml @@ -27,3 +27,98 @@ amoxor.b: data_independent_timing: false operation(): | + + + + 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/Zabha/amoxor.h.yaml b/arch/inst/Zabha/amoxor.h.yaml index 1ddf350079..e4cbe9240a 100644 --- a/arch/inst/Zabha/amoxor.h.yaml +++ b/arch/inst/Zabha/amoxor.h.yaml @@ -27,3 +27,98 @@ amoxor.h: data_independent_timing: false operation(): | + + + + 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/Zalasr/lb.aq.yaml b/arch/inst/Zalasr/lb.aq.yaml index 681799ceb2..6a616c7ab3 100644 --- a/arch/inst/Zalasr/lb.aq.yaml +++ b/arch/inst/Zalasr/lb.aq.yaml @@ -23,3 +23,35 @@ lb.aq: data_independent_timing: false operation(): | + + + + 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/Zalasr/ld.aq.yaml b/arch/inst/Zalasr/ld.aq.yaml index 77a3aa251e..6bba1cab99 100644 --- a/arch/inst/Zalasr/ld.aq.yaml +++ b/arch/inst/Zalasr/ld.aq.yaml @@ -23,3 +23,35 @@ ld.aq: data_independent_timing: false operation(): | + + + + 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/Zalasr/lh.aq.yaml b/arch/inst/Zalasr/lh.aq.yaml index d5b965aa3b..6de5df42c3 100644 --- a/arch/inst/Zalasr/lh.aq.yaml +++ b/arch/inst/Zalasr/lh.aq.yaml @@ -23,3 +23,35 @@ lh.aq: data_independent_timing: false operation(): | + + + + 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/Zalasr/lw.aq.yaml b/arch/inst/Zalasr/lw.aq.yaml index 8c892f48d3..f11af45872 100644 --- a/arch/inst/Zalasr/lw.aq.yaml +++ b/arch/inst/Zalasr/lw.aq.yaml @@ -23,3 +23,35 @@ lw.aq: data_independent_timing: false operation(): | + + + + 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/Zalasr/sb.rl.yaml b/arch/inst/Zalasr/sb.rl.yaml index a5137831e6..526d291f5c 100644 --- a/arch/inst/Zalasr/sb.rl.yaml +++ b/arch/inst/Zalasr/sb.rl.yaml @@ -23,3 +23,50 @@ sb.rl: data_independent_timing: false operation(): | + + + + 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/Zalasr/sd.rl.yaml b/arch/inst/Zalasr/sd.rl.yaml index 11b317089e..0f737532e0 100644 --- a/arch/inst/Zalasr/sd.rl.yaml +++ b/arch/inst/Zalasr/sd.rl.yaml @@ -23,3 +23,50 @@ sd.rl: data_independent_timing: false operation(): | + + + + 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/Zalasr/sh.rl.yaml b/arch/inst/Zalasr/sh.rl.yaml index c0f9169bc4..0063569432 100644 --- a/arch/inst/Zalasr/sh.rl.yaml +++ b/arch/inst/Zalasr/sh.rl.yaml @@ -23,3 +23,50 @@ sh.rl: data_independent_timing: false operation(): | + + + + 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/Zalasr/sw.rl.yaml b/arch/inst/Zalasr/sw.rl.yaml index df2e49871a..0f8ddfe17e 100644 --- a/arch/inst/Zalasr/sw.rl.yaml +++ b/arch/inst/Zalasr/sw.rl.yaml @@ -23,3 +23,50 @@ sw.rl: data_independent_timing: false operation(): | + + + + 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/Zfh/fcvt.h.s.yaml b/arch/inst/Zfh/fcvt.h.s.yaml index 91662f6e74..6c7f976ba8 100644 --- a/arch/inst/Zfh/fcvt.h.s.yaml +++ b/arch/inst/Zfh/fcvt.h.s.yaml @@ -82,4 +82,24 @@ fcvt.h.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_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 e71a4e5da7..af59f1b7ac 100644 --- a/arch/inst/Zfh/fcvt.s.h.yaml +++ b/arch/inst/Zfh/fcvt.s.h.yaml @@ -79,4 +79,24 @@ fcvt.s.h: } } + + + + 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 0e94b04b84..67a77dc794 100644 --- a/arch/inst/Zfh/flh.yaml +++ b/arch/inst/Zfh/flh.yaml @@ -68,4 +68,36 @@ flh: } } + + + + 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 4fa6c87634..26afffd64d 100644 --- a/arch/inst/Zfh/fmv.h.x.yaml +++ b/arch/inst/Zfh/fmv.h.x.yaml @@ -39,4 +39,15 @@ fmv.h.x: RETIRE_SUCCESS } + + + + 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 2c2c2f4a92..cc1149496a 100644 --- a/arch/inst/Zfh/fmv.x.h.yaml +++ b/arch/inst/Zfh/fmv.x.h.yaml @@ -41,4 +41,15 @@ fmv.x.h: RETIRE_SUCCESS } + + + + 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 42b6823ae9..0ebc924ce5 100644 --- a/arch/inst/Zfh/fsh.yaml +++ b/arch/inst/Zfh/fsh.yaml @@ -79,4 +79,46 @@ fsh: } } + + + + 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/Zicond/czero.eqz.yaml b/arch/inst/Zicond/czero.eqz.yaml index c5184d76a4..d00a583b0d 100644 --- a/arch/inst/Zicond/czero.eqz.yaml +++ b/arch/inst/Zicond/czero.eqz.yaml @@ -23,3 +23,17 @@ czero.eqz: data_independent_timing: false operation(): | + + + + sail(): | + { + let value = X(rs1); + let condition = X(rs2); + let result : xlenbits = if (condition != zeros()) then zeros() + else value; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/Zicond/czero.nez.yaml b/arch/inst/Zicond/czero.nez.yaml index 4b0b1efa9e..b296be735c 100644 --- a/arch/inst/Zicond/czero.nez.yaml +++ b/arch/inst/Zicond/czero.nez.yaml @@ -23,3 +23,17 @@ czero.nez: data_independent_timing: false operation(): | + + + + sail(): | + { + let value = X(rs1); + let condition = X(rs2); + let result : xlenbits = if (condition != zeros()) then zeros() + else value; + X(rd) = result; + RETIRE_SUCCESS + } + + \ No newline at end of file diff --git a/arch/inst/Zicsr/csrrs.yaml b/arch/inst/Zicsr/csrrs.yaml index 677ec279a0..1bb9b5d980 100644 --- a/arch/inst/Zicsr/csrrs.yaml +++ b/arch/inst/Zicsr/csrrs.yaml @@ -67,4 +67,33 @@ csrrs: } } + + + + 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 891b136d78..1a76e18c98 100644 --- a/arch/inst/Zicsr/csrrw.yaml +++ b/arch/inst/Zicsr/csrrw.yaml @@ -63,4 +63,33 @@ csrrw: } } + + + + 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 23d18155cd..0dba8f39de 100644 --- a/arch/inst/Zicsr/csrrwi.yaml +++ b/arch/inst/Zicsr/csrrwi.yaml @@ -63,4 +63,33 @@ csrrwi: } } + + + + 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 70ebc4e328..e00c067f18 100644 --- a/arch/inst/Zifencei/fence.i.yaml +++ b/arch/inst/Zifencei/fence.i.yaml @@ -52,3 +52,10 @@ fence.i: sail(): | { /* __barrier(Barrier_RISCV_i); */ RETIRE_SUCCESS } + + + + sail(): | + { /* __barrier(Barrier_RISCV_i); */ RETIRE_SUCCESS } + + \ No newline at end of file