diff --git a/riscv/src/compiler.rs b/riscv/src/compiler.rs index 8e116d312..fa55d0f5f 100644 --- a/riscv/src/compiler.rs +++ b/riscv/src/compiler.rs @@ -67,12 +67,12 @@ impl Architecture for RiscvArchitecture { fn instruction_ends_control_flow(instr: &str) -> bool { match instr { "li" | "lui" | "la" | "mv" | "add" | "addi" | "sub" | "neg" | "mul" | "mulhu" - | "divu" | "remu" | "xor" | "xori" | "and" | "andi" | "or" | "ori" | "not" | "slli" - | "sll" | "srli" | "srl" | "srai" | "seqz" | "snez" | "slt" | "slti" | "sltu" - | "sltiu" | "sgtz" | "beq" | "beqz" | "bgeu" | "bltu" | "blt" | "bge" | "bltz" - | "blez" | "bgtz" | "bgez" | "bne" | "bnez" | "jal" | "jalr" | "call" | "ecall" - | "ebreak" | "lw" | "lb" | "lbu" | "lh" | "lhu" | "sw" | "sh" | "sb" | "nop" - | "fence" | "fence.i" | "amoadd.w" | "amoadd.w.aq" | "amoadd.w.rl" + | "mulhsu" | "divu" | "remu" | "xor" | "xori" | "and" | "andi" | "or" | "ori" + | "not" | "slli" | "sll" | "srli" | "srl" | "srai" | "seqz" | "snez" | "slt" + | "slti" | "sltu" | "sltiu" | "sgtz" | "beq" | "beqz" | "bgeu" | "bltu" | "blt" + | "bge" | "bltz" | "blez" | "bgtz" | "bgez" | "bne" | "bnez" | "jal" | "jalr" + | "call" | "ecall" | "ebreak" | "lw" | "lb" | "lbu" | "lh" | "lhu" | "sw" | "sh" + | "sb" | "nop" | "fence" | "fence.i" | "amoadd.w" | "amoadd.w.aq" | "amoadd.w.rl" | "amoadd.w.aqrl" | "lr.w" | "lr.w.aq" | "lr.w.rl" | "lr.w.aqrl" | "sc.w" | "sc.w.aq" | "sc.w.rl" | "sc.w.aqrl" => false, "j" | "jr" | "tail" | "ret" | "unimp" => true, @@ -904,6 +904,27 @@ fn process_instruction(instr: &str, args: &[Argument]) -> Vec { let (rd, r1, r2) = rrr(args); only_if_no_write_to_zero(format!("tmp1, {rd} <== mul({r1}, {r2});"), rd) } + "mulhsu" => { + let (rd, r1, r2) = rrr(args); + only_if_no_write_to_zero_vec( + vec![ + format!("tmp1 <== to_signed({r1});"), + // tmp2 is 1 if tmp1 is non-negative + "tmp2 <== is_positive(tmp1 + 1);".into(), + // If negative, convert to positive + "skip_if_zero 0, tmp2;".into(), + "tmp1 <=X= 0 - tmp1;".into(), + format!("tmp1, {rd} <== mul(tmp1, {r2});"), + // If was negative before, convert back to negative + "skip_if_zero (1-tmp2), 2;".into(), + "tmp1 <== is_equal_zero(tmp1);".into(), + // If the lower bits are zero, return the two's complement, + // otherwise return one's complement. + format!("{rd} <== wrap_signed(-{rd} - 1 + tmp1);"), + ], + rd, + ) + } "divu" => { let (rd, r1, r2) = rrr(args); only_if_no_write_to_zero(format!("{rd}, tmp1 <== divremu({r1}, {r2});"), rd) diff --git a/riscv/tests/instruction_tests/generated/mulhsu.S b/riscv/tests/instruction_tests/generated/mulhsu.S new file mode 100644 index 000000000..e64d4b1cc --- /dev/null +++ b/riscv/tests/instruction_tests/generated/mulhsu.S @@ -0,0 +1,151 @@ +# 0 "sources/mulhsu.S" +# 0 "" +# 0 "" +# 1 "/usr/include/stdc-predef.h" 1 3 4 +# 0 "" 2 +# 1 "sources/mulhsu.S" +# See LICENSE for license details. + +#***************************************************************************** +# mulhsu.S +#----------------------------------------------------------------------------- + +# Test mulhsu instruction. + + +# 1 "sources/riscv_test.h" 1 +# 11 "sources/mulhsu.S" 2 +# 1 "sources/test_macros.h" 1 + + + + + + +#----------------------------------------------------------------------- +# Helper macros +#----------------------------------------------------------------------- +# 20 "sources/test_macros.h" +# We use a macro hack to simpify code generation for various numbers +# of bubble cycles. +# 36 "sources/test_macros.h" +#----------------------------------------------------------------------- +# RV64UI MACROS +#----------------------------------------------------------------------- + +#----------------------------------------------------------------------- +# Tests for instructions with immediate operand +#----------------------------------------------------------------------- +# 92 "sources/test_macros.h" +#----------------------------------------------------------------------- +# Tests for vector config instructions +#----------------------------------------------------------------------- +# 120 "sources/test_macros.h" +#----------------------------------------------------------------------- +# Tests for an instruction with register operands +#----------------------------------------------------------------------- +# 148 "sources/test_macros.h" +#----------------------------------------------------------------------- +# Tests for an instruction with register-register operands +#----------------------------------------------------------------------- +# 242 "sources/test_macros.h" +#----------------------------------------------------------------------- +# Test memory instructions +#----------------------------------------------------------------------- +# 319 "sources/test_macros.h" +#----------------------------------------------------------------------- +# Test branch instructions +#----------------------------------------------------------------------- +# 404 "sources/test_macros.h" +#----------------------------------------------------------------------- +# Test jump instructions +#----------------------------------------------------------------------- +# 433 "sources/test_macros.h" +#----------------------------------------------------------------------- +# RV64UF MACROS +#----------------------------------------------------------------------- + +#----------------------------------------------------------------------- +# Tests floating-point instructions +#----------------------------------------------------------------------- +# 569 "sources/test_macros.h" +#----------------------------------------------------------------------- +# Pass and fail code (assumes test num is in x28) +#----------------------------------------------------------------------- +# 581 "sources/test_macros.h" +#----------------------------------------------------------------------- +# Test data section +#----------------------------------------------------------------------- +# 12 "sources/mulhsu.S" 2 + + +.globl __runtime_start; __runtime_start: + + #------------------------------------------------------------- + # Arithmetic tests + #------------------------------------------------------------- + + test_2: li x10, 2; ebreak; li x1, 0x00000000; li x2, 0x00000000; mulhsu x3, x1, x2;; li x29, 0x00000000; li x28, 2; bne x3, x29, fail;; + test_3: li x10, 3; ebreak; li x1, 0x00000001; li x2, 0x00000001; mulhsu x3, x1, x2;; li x29, 0x00000000; li x28, 3; bne x3, x29, fail;; + test_4: li x10, 4; ebreak; li x1, 0x00000003; li x2, 0x00000007; mulhsu x3, x1, x2;; li x29, 0x00000000; li x28, 4; bne x3, x29, fail;; + + test_5: li x10, 5; ebreak; li x1, 0x00000000; li x2, 0xffff8000; mulhsu x3, x1, x2;; li x29, 0x00000000; li x28, 5; bne x3, x29, fail;; + test_6: li x10, 6; ebreak; li x1, 0x80000000; li x2, 0x00000000; mulhsu x3, x1, x2;; li x29, 0x00000000; li x28, 6; bne x3, x29, fail;; + test_7: li x10, 7; ebreak; li x1, 0x80000000; li x2, 0xffff8000; mulhsu x3, x1, x2;; li x29, 0x80004000; li x28, 7; bne x3, x29, fail;; + + test_30: li x10, 30; ebreak; li x1, 0xaaaaaaab; li x2, 0x0002fe7d; mulhsu x3, x1, x2;; li x29, 0xffff0081; li x28, 30; bne x3, x29, fail;; + test_31: li x10, 31; ebreak; li x1, 0x0002fe7d; li x2, 0xaaaaaaab; mulhsu x3, x1, x2;; li x29, 0x0001fefe; li x28, 31; bne x3, x29, fail;; + + test_32: li x10, 32; ebreak; li x1, 0xff000000; li x2, 0xff000000; mulhsu x3, x1, x2;; li x29, 0xff010000; li x28, 32; bne x3, x29, fail;; + + test_33: li x10, 33; ebreak; li x1, 0xffffffff; li x2, 0xffffffff; mulhsu x3, x1, x2;; li x29, 0xffffffff; li x28, 33; bne x3, x29, fail;; + test_34: li x10, 34; ebreak; li x1, 0xffffffff; li x2, 0x00000001; mulhsu x3, x1, x2;; li x29, 0xffffffff; li x28, 34; bne x3, x29, fail;; + test_35: li x10, 35; ebreak; li x1, 0x00000001; li x2, 0xffffffff; mulhsu x3, x1, x2;; li x29, 0x00000000; li x28, 35; bne x3, x29, fail;; + + #------------------------------------------------------------- + # Source/Destination tests + #------------------------------------------------------------- + + test_8: li x10, 8; ebreak; li x1, 13<<20; li x2, 11<<20; mulhsu x1, x1, x2;; li x29, 36608; li x28, 8; bne x1, x29, fail;; + test_9: li x10, 9; ebreak; li x1, 14<<20; li x2, 11<<20; mulhsu x2, x1, x2;; li x29, 39424; li x28, 9; bne x2, x29, fail;; + test_10: li x10, 10; ebreak; li x1, 13<<20; mulhsu x1, x1, x1;; li x29, 43264; li x28, 10; bne x1, x29, fail;; + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + test_11: li x10, 11; ebreak; li x4, 0; test_11_l1: li x1, 13<<20; li x2, 11<<20; mulhsu x3, x1, x2; addi x6, x3, 0; addi x4, x4, 1; li x5, 2; bne x4, x5, test_11_l1; li x29, 36608; li x28, 11; bne x6, x29, fail;; + test_12: li x10, 12; ebreak; li x4, 0; test_12_l1: li x1, 14<<20; li x2, 11<<20; mulhsu x3, x1, x2; nop; addi x6, x3, 0; addi x4, x4, 1; li x5, 2; bne x4, x5, test_12_l1; li x29, 39424; li x28, 12; bne x6, x29, fail;; + test_13: li x10, 13; ebreak; li x4, 0; test_13_l1: li x1, 15<<20; li x2, 11<<20; mulhsu x3, x1, x2; nop; nop; addi x6, x3, 0; addi x4, x4, 1; li x5, 2; bne x4, x5, test_13_l1; li x29, 42240; li x28, 13; bne x6, x29, fail;; + + test_14: li x10, 14; ebreak; li x4, 0; test_14_l1: li x1, 13<<20; li x2, 11<<20; mulhsu x3, x1, x2; addi x4, x4, 1; li x5, 2; bne x4, x5, test_14_l1; li x29, 36608; li x28, 14; bne x3, x29, fail;; + test_15: li x10, 15; ebreak; li x4, 0; test_15_l1: li x1, 14<<20; li x2, 11<<20; nop; mulhsu x3, x1, x2; addi x4, x4, 1; li x5, 2; bne x4, x5, test_15_l1; li x29, 39424; li x28, 15; bne x3, x29, fail;; + test_16: li x10, 16; ebreak; li x4, 0; test_16_l1: li x1, 15<<20; li x2, 11<<20; nop; nop; mulhsu x3, x1, x2; addi x4, x4, 1; li x5, 2; bne x4, x5, test_16_l1; li x29, 42240; li x28, 16; bne x3, x29, fail;; + test_17: li x10, 17; ebreak; li x4, 0; test_17_l1: li x1, 13<<20; nop; li x2, 11<<20; mulhsu x3, x1, x2; addi x4, x4, 1; li x5, 2; bne x4, x5, test_17_l1; li x29, 36608; li x28, 17; bne x3, x29, fail;; + test_18: li x10, 18; ebreak; li x4, 0; test_18_l1: li x1, 14<<20; nop; li x2, 11<<20; nop; mulhsu x3, x1, x2; addi x4, x4, 1; li x5, 2; bne x4, x5, test_18_l1; li x29, 39424; li x28, 18; bne x3, x29, fail;; + test_19: li x10, 19; ebreak; li x4, 0; test_19_l1: li x1, 15<<20; nop; nop; li x2, 11<<20; mulhsu x3, x1, x2; addi x4, x4, 1; li x5, 2; bne x4, x5, test_19_l1; li x29, 42240; li x28, 19; bne x3, x29, fail;; + + test_20: li x10, 20; ebreak; li x4, 0; test_20_l1: li x2, 11<<20; li x1, 13<<20; mulhsu x3, x1, x2; addi x4, x4, 1; li x5, 2; bne x4, x5, test_20_l1; li x29, 36608; li x28, 20; bne x3, x29, fail;; + test_21: li x10, 21; ebreak; li x4, 0; test_21_l1: li x2, 11<<20; li x1, 14<<20; nop; mulhsu x3, x1, x2; addi x4, x4, 1; li x5, 2; bne x4, x5, test_21_l1; li x29, 39424; li x28, 21; bne x3, x29, fail;; + test_22: li x10, 22; ebreak; li x4, 0; test_22_l1: li x2, 11<<20; li x1, 15<<20; nop; nop; mulhsu x3, x1, x2; addi x4, x4, 1; li x5, 2; bne x4, x5, test_22_l1; li x29, 42240; li x28, 22; bne x3, x29, fail;; + test_23: li x10, 23; ebreak; li x4, 0; test_23_l1: li x2, 11<<20; nop; li x1, 13<<20; mulhsu x3, x1, x2; addi x4, x4, 1; li x5, 2; bne x4, x5, test_23_l1; li x29, 36608; li x28, 23; bne x3, x29, fail;; + test_24: li x10, 24; ebreak; li x4, 0; test_24_l1: li x2, 11<<20; nop; li x1, 14<<20; nop; mulhsu x3, x1, x2; addi x4, x4, 1; li x5, 2; bne x4, x5, test_24_l1; li x29, 39424; li x28, 24; bne x3, x29, fail;; + test_25: li x10, 25; ebreak; li x4, 0; test_25_l1: li x2, 11<<20; nop; nop; li x1, 15<<20; mulhsu x3, x1, x2; addi x4, x4, 1; li x5, 2; bne x4, x5, test_25_l1; li x29, 42240; li x28, 25; bne x3, x29, fail;; + + test_26: li x10, 26; ebreak; li x1, 31<<26; mulhsu x2, x0, x1;; li x29, 0; li x28, 26; bne x2, x29, fail;; + test_27: li x10, 27; ebreak; li x1, 32<<26; mulhsu x2, x1, x0;; li x29, 0; li x28, 27; bne x2, x29, fail;; + test_28: li x10, 28; ebreak; mulhsu x1, x0, x0;; li x29, 0; li x28, 28; bne x1, x29, fail;; + test_29: li x10, 29; ebreak; li x1, 33<<20; li x2, 34<<20; mulhsu x0, x1, x2;; li x29, 0; li x28, 29; bne x0, x29, fail;; + + + + bne x0, x28, pass; fail: unimp;; pass: ___pass: j ___pass; + + + + .data +.balign 4; + + + + diff --git a/riscv/tests/instruction_tests/sources/mulhsu.S b/riscv/tests/instruction_tests/sources/mulhsu.S new file mode 100644 index 000000000..28b369099 --- /dev/null +++ b/riscv/tests/instruction_tests/sources/mulhsu.S @@ -0,0 +1,83 @@ +# See LICENSE for license details. + +#***************************************************************************** +# mulhsu.S +#----------------------------------------------------------------------------- +# +# Test mulhsu instruction. +# + +#include "riscv_test.h" +#include "test_macros.h" + +RVTEST_RV32U +RVTEST_CODE_BEGIN + + #------------------------------------------------------------- + # Arithmetic tests + #------------------------------------------------------------- + + TEST_RR_OP( 2, mulhsu, 0x00000000, 0x00000000, 0x00000000 ); + TEST_RR_OP( 3, mulhsu, 0x00000000, 0x00000001, 0x00000001 ); + TEST_RR_OP( 4, mulhsu, 0x00000000, 0x00000003, 0x00000007 ); + + TEST_RR_OP( 5, mulhsu, 0x00000000, 0x00000000, 0xffff8000 ); + TEST_RR_OP( 6, mulhsu, 0x00000000, 0x80000000, 0x00000000 ); + TEST_RR_OP( 7, mulhsu, 0x80004000, 0x80000000, 0xffff8000 ); + + TEST_RR_OP(30, mulhsu, 0xffff0081, 0xaaaaaaab, 0x0002fe7d ); + TEST_RR_OP(31, mulhsu, 0x0001fefe, 0x0002fe7d, 0xaaaaaaab ); + + TEST_RR_OP(32, mulhsu, 0xff010000, 0xff000000, 0xff000000 ); + + TEST_RR_OP(33, mulhsu, 0xffffffff, 0xffffffff, 0xffffffff ); + TEST_RR_OP(34, mulhsu, 0xffffffff, 0xffffffff, 0x00000001 ); + TEST_RR_OP(35, mulhsu, 0x00000000, 0x00000001, 0xffffffff ); + + #------------------------------------------------------------- + # Source/Destination tests + #------------------------------------------------------------- + + TEST_RR_SRC1_EQ_DEST( 8, mulhsu, 36608, 13<<20, 11<<20 ); + TEST_RR_SRC2_EQ_DEST( 9, mulhsu, 39424, 14<<20, 11<<20 ); + TEST_RR_SRC12_EQ_DEST( 10, mulhsu, 43264, 13<<20 ); + + #------------------------------------------------------------- + # Bypassing tests + #------------------------------------------------------------- + + TEST_RR_DEST_BYPASS( 11, 0, mulhsu, 36608, 13<<20, 11<<20 ); + TEST_RR_DEST_BYPASS( 12, 1, mulhsu, 39424, 14<<20, 11<<20 ); + TEST_RR_DEST_BYPASS( 13, 2, mulhsu, 42240, 15<<20, 11<<20 ); + + TEST_RR_SRC12_BYPASS( 14, 0, 0, mulhsu, 36608, 13<<20, 11<<20 ); + TEST_RR_SRC12_BYPASS( 15, 0, 1, mulhsu, 39424, 14<<20, 11<<20 ); + TEST_RR_SRC12_BYPASS( 16, 0, 2, mulhsu, 42240, 15<<20, 11<<20 ); + TEST_RR_SRC12_BYPASS( 17, 1, 0, mulhsu, 36608, 13<<20, 11<<20 ); + TEST_RR_SRC12_BYPASS( 18, 1, 1, mulhsu, 39424, 14<<20, 11<<20 ); + TEST_RR_SRC12_BYPASS( 19, 2, 0, mulhsu, 42240, 15<<20, 11<<20 ); + + TEST_RR_SRC21_BYPASS( 20, 0, 0, mulhsu, 36608, 13<<20, 11<<20 ); + TEST_RR_SRC21_BYPASS( 21, 0, 1, mulhsu, 39424, 14<<20, 11<<20 ); + TEST_RR_SRC21_BYPASS( 22, 0, 2, mulhsu, 42240, 15<<20, 11<<20 ); + TEST_RR_SRC21_BYPASS( 23, 1, 0, mulhsu, 36608, 13<<20, 11<<20 ); + TEST_RR_SRC21_BYPASS( 24, 1, 1, mulhsu, 39424, 14<<20, 11<<20 ); + TEST_RR_SRC21_BYPASS( 25, 2, 0, mulhsu, 42240, 15<<20, 11<<20 ); + + TEST_RR_ZEROSRC1( 26, mulhsu, 0, 31<<26 ); + TEST_RR_ZEROSRC2( 27, mulhsu, 0, 32<<26 ); + TEST_RR_ZEROSRC12( 28, mulhsu, 0 ); + TEST_RR_ZERODEST( 29, mulhsu, 33<<20, 34<<20 ); + + + + TEST_PASSFAIL + +RVTEST_CODE_END + + .data +RVTEST_DATA_BEGIN + + TEST_DATA + +RVTEST_DATA_END