diff --git a/GammaALU.vhdl b/GammaALU.vhdl index 5b5ba4d..30299e6 100644 --- a/GammaALU.vhdl +++ b/GammaALU.vhdl @@ -28,48 +28,90 @@ begin result <= std_logic_vector(signed(a) - signed(b)); when 2 => -- MUL result <= std_logic_vector(resize(signed(a) * signed(b), 32)); -- Resize to 32 bits - when 3 => -- DIV - if b /= "00000000000000000000000000000000" then - result <= std_logic_vector(signed(a) / signed(b)); + when 3 => -- DIV (signed division b / a) + if a /= "00000000000000000000000000000000" then + result <= std_logic_vector(signed(b) / signed(a)); else result <= (others => '0'); -- Handle division by zero end if; - when 4 => -- equal + when 4 => -- eq (equal) - for i32.eq and i32.eqz if a = b then result <= std_logic_vector(to_signed(1, 32)); else result <= std_logic_vector(to_signed(0, 32)); end if; - when 5 => -- inequality + when 5 => -- ne (not equal) - for i32.ne if a /= b then result <= std_logic_vector(to_signed(1, 32)); else result <= std_logic_vector(to_signed(0, 32)); end if; - when 6 => -- greater than - if a > b then + when 6 => -- gt_s (greater than signed) - for i32.gt_s + if signed(b) > signed(a) then result <= std_logic_vector(to_signed(1, 32)); else result <= std_logic_vector(to_signed(0, 32)); end if; - when 7 => -- less than - if a < b then + when 7 => -- lt_s (less than signed) - for i32.lt_s + if signed(b) < signed(a) then result <= std_logic_vector(to_signed(1, 32)); else result <= std_logic_vector(to_signed(0, 32)); end if; - when 8 => -- greater than or equal to - if a >= b then + when 8 => -- ge_s (greater than or equal signed) - for i32.ge_s + if signed(b) >= signed(a) then result <= std_logic_vector(to_signed(1, 32)); else result <= std_logic_vector(to_signed(0, 32)); end if; - when 9 => -- less than or equal to - if a <= b then + when 9 => -- le_s (less than or equal signed) - for i32.le_s + if signed(b) <= signed(a) then result <= std_logic_vector(to_signed(1, 32)); else result <= std_logic_vector(to_signed(0, 32)); end if; + when 10 => -- le_s (less than or equal signed) - duplicate for backward compatibility + if signed(b) <= signed(a) then + result <= std_logic_vector(to_signed(1, 32)); + else + result <= std_logic_vector(to_signed(0, 32)); + end if; + when 11 => -- gt_u (greater than unsigned) + if unsigned(b) > unsigned(a) then + result <= std_logic_vector(to_signed(1, 32)); + else + result <= std_logic_vector(to_signed(0, 32)); + end if; + when 12 => -- lt_u (less than unsigned) + if unsigned(b) < unsigned(a) then + result <= std_logic_vector(to_signed(1, 32)); + else + result <= std_logic_vector(to_signed(0, 32)); + end if; + when 13 => -- ge_u (greater than or equal unsigned) + if unsigned(b) >= unsigned(a) then + result <= std_logic_vector(to_signed(1, 32)); + else + result <= std_logic_vector(to_signed(0, 32)); + end if; + when 14 => -- le_u (less than or equal unsigned) + if unsigned(b) <= unsigned(a) then + result <= std_logic_vector(to_signed(1, 32)); + else + result <= std_logic_vector(to_signed(0, 32)); + end if; + when 15 => -- div_u (unsigned division b / a) + if unsigned(a) /= 0 then + result <= std_logic_vector(unsigned(b) / unsigned(a)); + else + result <= (others => '0'); -- Handle division by zero + end if; + when 16 => -- rem_u (unsigned remainder b mod a) + if unsigned(a) /= 0 then + result <= std_logic_vector(unsigned(b) mod unsigned(a)); + else + result <= (others => '0'); -- Handle division by zero + end if; when others => result <= (others => '0'); end case; diff --git a/GammaCPU.vhdl b/GammaCPU.vhdl index c75fb53..967e845 100644 --- a/GammaCPU.vhdl +++ b/GammaCPU.vhdl @@ -140,34 +140,58 @@ begin alu_op <= to_unsigned(3, 16); -- DIV state <= Execute; - -- Comparisions + -- Comparisons when x"45" => -- i32.eqz - alu_op <= to_unsigned(4, 16); -- Equal to zero + alu_op <= to_unsigned(4, 16); -- Equal (use with b=0) only_first_stack <= '1'; state <= Execute; when x"46" => -- i32.eq - alu_op <= to_unsigned(5, 16); -- Equal + alu_op <= to_unsigned(4, 16); -- Equal state <= Execute; when x"47" => -- i32.ne - alu_op <= to_unsigned(6, 16); -- Not Equal + alu_op <= to_unsigned(5, 16); -- Not Equal state <= Execute; when x"4b" => -- i32.gt_s - alu_op <= to_unsigned(7, 16); -- Greater than + alu_op <= to_unsigned(6, 16); -- Greater than signed state <= Execute; when x"48" => -- i32.lt_s - alu_op <= to_unsigned(8, 16); -- Less than + alu_op <= to_unsigned(7, 16); -- Less than signed state <= Execute; when x"4e" => -- i32.ge_s - alu_op <= to_unsigned(9, 16); -- Greater than or equal + alu_op <= to_unsigned(8, 16); -- Greater than or equal signed state <= Execute; when x"4C" => -- i32.le_s - alu_op <= to_unsigned(10, 16); -- Less than or equal + alu_op <= to_unsigned(9, 16); -- Less than or equal signed + state <= Execute; + + when x"4A" => -- i32.gt_u + alu_op <= to_unsigned(11, 16); -- Greater than unsigned + state <= Execute; + + when x"49" => -- i32.lt_u + alu_op <= to_unsigned(12, 16); -- Less than unsigned + state <= Execute; + + when x"4F" => -- i32.ge_u + alu_op <= to_unsigned(13, 16); -- Greater than or equal unsigned + state <= Execute; + + when x"4D" => -- i32.le_u + alu_op <= to_unsigned(14, 16); -- Less than or equal unsigned + state <= Execute; + + when x"6E" => -- i32.div_u + alu_op <= to_unsigned(15, 16); -- Unsigned division + state <= Execute; + + when x"70" => -- i32.rem_u + alu_op <= to_unsigned(16, 16); -- Unsigned remainder state <= Execute; when others => diff --git a/test/alu/Testbench.vhdl b/test/alu/Testbench.vhdl index 805f640..bb42a5d 100644 --- a/test/alu/Testbench.vhdl +++ b/test/alu/Testbench.vhdl @@ -212,9 +212,9 @@ begin report "___FAILOUT Can't multiply 5 by -2, got " & integer'image(to_integer(signed(result))) & " instead of -10"; end if; - -- Test 16 - positive division - a <= std_logic_vector(to_signed(10, 32)); - b <= std_logic_vector(to_signed(2, 32)); + -- Test 16 - positive division (b / a = 10 / 2 = 5) + a <= std_logic_vector(to_signed(2, 32)); + b <= std_logic_vector(to_signed(10, 32)); op <= to_unsigned(3, 16); wait for 10 ns; @@ -222,9 +222,9 @@ begin report "___FAILOUT Can't divide 10 by 2, got " & integer'image(to_integer(signed(result))) & " instead of 5"; end if; - -- Test 17 - two negative numbers division, a negative result - a <= std_logic_vector(to_signed(-10, 32)); - b <= std_logic_vector(to_signed(-2, 32)); + -- Test 17 - two negative numbers division (b / a = -10 / -2 = 5) + a <= std_logic_vector(to_signed(-2, 32)); + b <= std_logic_vector(to_signed(-10, 32)); op <= to_unsigned(3, 16); wait for 10 ns; @@ -232,9 +232,9 @@ begin report "___FAILOUT Can't divide -10 by -2, got " & integer'image(to_integer(signed(result))) & " instead of 5"; end if; - -- Test 18 - one negative (negative first), one positive number division, a negative result - a <= std_logic_vector(to_signed(-10, 32)); - b <= std_logic_vector(to_signed(2, 32)); + -- Test 18 - one negative (negative first), one positive number division (b / a = -10 / 2 = -5) + a <= std_logic_vector(to_signed(2, 32)); + b <= std_logic_vector(to_signed(-10, 32)); op <= to_unsigned(3, 16); wait for 10 ns; @@ -242,18 +242,19 @@ begin report "___FAILOUT Can't divide -10 by 2, got " & integer'image(to_integer(signed(result))) & " instead of -5"; end if; - -- Test 19 - one negative (positive first), one positive number division, a negative result - a <= std_logic_vector(to_signed(10, 32)); - b <= std_logic_vector(to_signed(-2, 32)); + -- Test 19 - one negative (positive first), one positive number division (b / a = 10 / -2 = -5) + a <= std_logic_vector(to_signed(-2, 32)); + b <= std_logic_vector(to_signed(10, 32)); op <= to_unsigned(3, 16); + wait for 10 ns; if to_integer(signed(result)) /= -5 then report "___FAILOUT Can't divide 10 by -2, got " & integer'image(to_integer(signed(result))) & " instead of -5"; end if; - -- Test 20 - division by zero - a <= std_logic_vector(to_signed(10, 32)); - b <= std_logic_vector(to_signed(0, 32)); + -- Test 20 - division by zero (b / a = 10 / 0 = 0) + a <= std_logic_vector(to_signed(0, 32)); + b <= std_logic_vector(to_signed(10, 32)); op <= to_unsigned(3, 16); wait for 10 ns; @@ -261,9 +262,9 @@ begin report "___FAILOUT Can't divide 10 by 0, got " & integer'image(to_integer(signed(result))) & " instead of 0"; end if; - -- Test 21 - divison of zero - a <= std_logic_vector(to_signed(0, 32)); - b <= std_logic_vector(to_signed(10, 32)); + -- Test 21 - divison of zero (b / a = 0 / 10 = 0) + a <= std_logic_vector(to_signed(10, 32)); + b <= std_logic_vector(to_signed(0, 32)); op <= to_unsigned(3, 16); wait for 10 ns; @@ -312,9 +313,9 @@ begin report "___FAILOUT Comparision for inequality for 10 and 10 got " & integer'image(to_integer(signed(result))) & " instead of 0"; end if; - -- Test 5 - A > B results in True - a <= std_logic_vector(to_signed(10, 32)); - b <= std_logic_vector(to_signed(5, 32)); + -- Test 5 - A > B results in True (now testing b > a, so b=10, a=5) + a <= std_logic_vector(to_signed(5, 32)); + b <= std_logic_vector(to_signed(10, 32)); op <= to_unsigned(6, 16); wait for 10 ns; @@ -322,9 +323,9 @@ begin report "___FAILOUT Comparision for inequality for 10 and 5 got " & integer'image(to_integer(signed(result))) & " instead of 1"; end if; - -- Test 6 - A > B results in False - a <= std_logic_vector(to_signed(10, 32)); - b <= std_logic_vector(to_signed(15, 32)); + -- Test 6 - A > B results in False (now testing b > a, so b=15, a=10 becomes b=10, a=15) + a <= std_logic_vector(to_signed(15, 32)); + b <= std_logic_vector(to_signed(10, 32)); op <= to_unsigned(6, 16); wait for 10 ns; @@ -332,9 +333,9 @@ begin report "___FAILOUT Comparision for inequality for 10 and 10 got " & integer'image(to_integer(signed(result))) & " instead of 0"; end if; - -- Test 7 - A < B results in True - a <= std_logic_vector(to_signed(5, 32)); - b <= std_logic_vector(to_signed(10, 32)); + -- Test 7 - A < B results in True (now testing b < a, so b=5, a=10) + a <= std_logic_vector(to_signed(10, 32)); + b <= std_logic_vector(to_signed(5, 32)); op <= to_unsigned(7, 16); wait for 10 ns; @@ -342,9 +343,9 @@ begin report "___FAILOUT Comparision for inequality for 10 and 5 got " & integer'image(to_integer(signed(result))) & " instead of 1"; end if; - -- Test 8 - A < B results in False - a <= std_logic_vector(to_signed(20, 32)); - b <= std_logic_vector(to_signed(15, 32)); + -- Test 8 - A < B results in False (now testing b < a, so b=20, a=15) + a <= std_logic_vector(to_signed(15, 32)); + b <= std_logic_vector(to_signed(20, 32)); op <= to_unsigned(7, 16); wait for 10 ns; @@ -352,6 +353,236 @@ begin report "___FAILOUT Comparision for inequality for 10 and 10 got " & integer'image(to_integer(signed(result))) & " instead of 0"; end if; + -- ========== UNSIGNED COMPARISON TESTS ========== + + -- Test 9 - i32.gt_u: 10 > 5 (unsigned) should return 1 (now b > a, so b=10, a=5) + a <= std_logic_vector(to_unsigned(5, 32)); + b <= std_logic_vector(to_unsigned(10, 32)); + op <= to_unsigned(11, 16); + wait for 10 ns; + + if to_integer(signed(result)) /= 1 then + report "___FAILOUT Unsigned greater than: 10 > 5 got " & integer'image(to_integer(signed(result))) & " instead of 1"; + end if; + + -- Test 10 - i32.gt_u: 5 > 10 (unsigned) should return 0 (now b > a, so b=5, a=10) + a <= std_logic_vector(to_unsigned(10, 32)); + b <= std_logic_vector(to_unsigned(5, 32)); + op <= to_unsigned(11, 16); + wait for 10 ns; + + if to_integer(signed(result)) /= 0 then + report "___FAILOUT Unsigned greater than: 5 > 10 got " & integer'image(to_integer(signed(result))) & " instead of 0"; + end if; + + -- Test 11 - i32.gt_u: Large unsigned values (0x80000000 > 0x7FFFFFFF) (now b > a) + a <= x"7FFFFFFF"; -- 2147483647 both unsigned and signed + b <= x"80000000"; -- 2147483648 unsigned (but -2147483648 if interpreted as signed) + op <= to_unsigned(11, 16); + wait for 10 ns; + + if to_integer(signed(result)) /= 1 then + report "___FAILOUT Unsigned greater than: 0x80000000 > 0x7FFFFFFF got " & integer'image(to_integer(signed(result))) & " instead of 1"; + end if; + + -- Test 12 - i32.lt_u: 5 < 10 (unsigned) should return 1 (b < a, so b=5, a=10) + a <= std_logic_vector(to_unsigned(10, 32)); + b <= std_logic_vector(to_unsigned(5, 32)); + op <= to_unsigned(12, 16); + wait for 10 ns; + + if to_integer(signed(result)) /= 1 then + report "___FAILOUT Unsigned less than: 5 < 10 got " & integer'image(to_integer(signed(result))) & " instead of 1"; + end if; + + -- Test 13 - i32.lt_u: 10 < 5 (unsigned) should return 0 (b < a, so b=10, a=5) + a <= std_logic_vector(to_unsigned(5, 32)); + b <= std_logic_vector(to_unsigned(10, 32)); + op <= to_unsigned(12, 16); + wait for 10 ns; + + if to_integer(signed(result)) /= 0 then + report "___FAILOUT Unsigned less than: 10 < 5 got " & integer'image(to_integer(signed(result))) & " instead of 0"; + end if; + + -- Test 14 - i32.ge_u: 10 >= 10 (unsigned) should return 1 + a <= std_logic_vector(to_unsigned(10, 32)); + b <= std_logic_vector(to_unsigned(10, 32)); + op <= to_unsigned(13, 16); + wait for 10 ns; + + if to_integer(signed(result)) /= 1 then + report "___FAILOUT Unsigned greater than or equal: 10 >= 10 got " & integer'image(to_integer(signed(result))) & " instead of 1"; + end if; + + -- Test 15 - i32.ge_u: 15 >= 10 (unsigned) should return 1 (b >= a, so b=15, a=10) + a <= std_logic_vector(to_unsigned(10, 32)); + b <= std_logic_vector(to_unsigned(15, 32)); + op <= to_unsigned(13, 16); + wait for 10 ns; + + if to_integer(signed(result)) /= 1 then + report "___FAILOUT Unsigned greater than or equal: 15 >= 10 got " & integer'image(to_integer(signed(result))) & " instead of 1"; + end if; + + -- Test 16 - i32.ge_u: 5 >= 10 (unsigned) should return 0 (b >= a, so b=5, a=10) + a <= std_logic_vector(to_unsigned(10, 32)); + b <= std_logic_vector(to_unsigned(5, 32)); + op <= to_unsigned(13, 16); + wait for 10 ns; + + if to_integer(signed(result)) /= 0 then + report "___FAILOUT Unsigned greater than or equal: 5 >= 10 got " & integer'image(to_integer(signed(result))) & " instead of 0"; + end if; + + -- Test 17 - i32.le_u: 10 <= 10 (unsigned) should return 1 + a <= std_logic_vector(to_unsigned(10, 32)); + b <= std_logic_vector(to_unsigned(10, 32)); + op <= to_unsigned(14, 16); + wait for 10 ns; + + if to_integer(signed(result)) /= 1 then + report "___FAILOUT Unsigned less than or equal: 10 <= 10 got " & integer'image(to_integer(signed(result))) & " instead of 1"; + end if; + + -- Test 18 - i32.le_u: 5 <= 10 (unsigned) should return 1 (b <= a, so b=5, a=10) + a <= std_logic_vector(to_unsigned(10, 32)); + b <= std_logic_vector(to_unsigned(5, 32)); + op <= to_unsigned(14, 16); + wait for 10 ns; + + if to_integer(signed(result)) /= 1 then + report "___FAILOUT Unsigned less than or equal: 5 <= 10 got " & integer'image(to_integer(signed(result))) & " instead of 1"; + end if; + + -- Test 19 - i32.le_u: 15 <= 10 (unsigned) should return 0 (b <= a, so b=15, a=10) + a <= std_logic_vector(to_unsigned(10, 32)); + b <= std_logic_vector(to_unsigned(15, 32)); + op <= to_unsigned(14, 16); + wait for 10 ns; + + if to_integer(signed(result)) /= 0 then + report "___FAILOUT Unsigned less than or equal: 15 <= 10 got " & integer'image(to_integer(signed(result))) & " instead of 0"; + end if; + + -- ========== UNSIGNED ARITHMETIC TESTS ========== + + -- Test 20 - i32.div_u: 20 / 4 (unsigned) should return 5 (b / a, so b=20, a=4) + a <= std_logic_vector(to_unsigned(4, 32)); + b <= std_logic_vector(to_unsigned(20, 32)); + op <= to_unsigned(15, 16); + wait for 10 ns; + + if to_integer(unsigned(result)) /= 5 then + report "___FAILOUT Unsigned division: 20 / 4 got " & integer'image(to_integer(unsigned(result))) & " instead of 5"; + end if; + + -- Test 21 - i32.div_u: 100 / 7 (unsigned) should return 14 (b / a, so b=100, a=7) + a <= std_logic_vector(to_unsigned(7, 32)); + b <= std_logic_vector(to_unsigned(100, 32)); + op <= to_unsigned(15, 16); + wait for 10 ns; + + if to_integer(unsigned(result)) /= 14 then + report "___FAILOUT Unsigned division: 100 / 7 got " & integer'image(to_integer(unsigned(result))) & " instead of 14"; + end if; + + -- Test 22 - i32.div_u: Division by zero should return 0 (b / a = 42 / 0 = 0) + a <= std_logic_vector(to_unsigned(0, 32)); + b <= std_logic_vector(to_unsigned(42, 32)); + op <= to_unsigned(15, 16); + wait for 10 ns; + + if to_integer(unsigned(result)) /= 0 then + report "___FAILOUT Unsigned division by zero: 42 / 0 got " & integer'image(to_integer(unsigned(result))) & " instead of 0"; + end if; + + -- Test 23 - i32.div_u: Large unsigned division (0x80000000 / 0x40000000) (b / a) + a <= x"40000000"; -- 1073741824 + b <= x"80000000"; -- 2147483648 + op <= to_unsigned(15, 16); + wait for 10 ns; + + if to_integer(unsigned(result)) /= 2 then + report "___FAILOUT Large unsigned division: 0x80000000 / 0x40000000 got " & integer'image(to_integer(unsigned(result))) & " instead of 2"; + end if; + + -- Test 24 - i32.rem_u: 23 % 5 (unsigned) should return 3 (b % a, so b=23, a=5) + a <= std_logic_vector(to_unsigned(5, 32)); + b <= std_logic_vector(to_unsigned(23, 32)); + op <= to_unsigned(16, 16); + wait for 10 ns; + + if to_integer(unsigned(result)) /= 3 then + report "___FAILOUT Unsigned remainder: 23 % 5 got " & integer'image(to_integer(unsigned(result))) & " instead of 3"; + end if; + + -- Test 25 - i32.rem_u: 100 % 7 (unsigned) should return 2 + -- Test 25 - i32.rem_u: 100 % 7 (unsigned) should return 2 (b % a, so b=100, a=7) + a <= std_logic_vector(to_unsigned(7, 32)); + b <= std_logic_vector(to_unsigned(100, 32)); + op <= to_unsigned(16, 16); + wait for 10 ns; + + if to_integer(unsigned(result)) /= 2 then + report "___FAILOUT Unsigned remainder: 100 % 7 got " & integer'image(to_integer(unsigned(result))) & " instead of 2"; + end if; + + -- Test 26 - i32.rem_u: 15 % 15 (unsigned) should return 0 + a <= std_logic_vector(to_unsigned(15, 32)); + b <= std_logic_vector(to_unsigned(15, 32)); + op <= to_unsigned(16, 16); + wait for 10 ns; + + if to_integer(unsigned(result)) /= 0 then + report "___FAILOUT Unsigned remainder: 15 % 15 got " & integer'image(to_integer(unsigned(result))) & " instead of 0"; + end if; + + -- Test 27 - i32.rem_u: Remainder by zero should return 0 (b % a = 42 % 0 = 0) + a <= std_logic_vector(to_unsigned(0, 32)); + b <= std_logic_vector(to_unsigned(42, 32)); + op <= to_unsigned(16, 16); + wait for 10 ns; + + if to_integer(unsigned(result)) /= 0 then + report "___FAILOUT Unsigned remainder by zero: 42 % 0 got " & integer'image(to_integer(unsigned(result))) & " instead of 0"; + end if; + + -- Test 28 - i32.rem_u: Large unsigned remainder (0x80000001 % 0x40000000) (b % a) + a <= x"40000000"; -- 1073741824 + b <= x"80000001"; -- 2147483649 + op <= to_unsigned(16, 16); + wait for 10 ns; + + if to_integer(unsigned(result)) /= 1 then + report "___FAILOUT Large unsigned remainder: 0x80000001 % 0x40000000 got " & integer'image(to_integer(unsigned(result))) & " instead of 1"; + end if; + + -- ========== EDGE CASE TESTS ========== + + -- Test 29 - Test unsigned comparison with values that would be negative in signed + -- In signed: 0x80000000 = -2147483648, 0x7FFFFFFF = 2147483647 + -- In unsigned: 0x80000000 = 2147483648, 0x7FFFFFFF = 2147483647 + -- So 0x80000000 > 0x7FFFFFFF in unsigned (b > a, so b=0x80000000, a=0x7FFFFFFF) + a <= x"7FFFFFFF"; -- 2147483647 both unsigned and signed + b <= x"80000000"; -- 2147483648 unsigned, -2147483648 signed + op <= to_unsigned(11, 16); -- gt_u + wait for 10 ns; + + if to_integer(signed(result)) /= 1 then + report "___FAILOUT Unsigned vs signed edge case: 0x80000000 > 0x7FFFFFFF got " & integer'image(to_integer(signed(result))) & " instead of 1"; + end if; + + -- Test 30 - Test same values with signed comparison (should be opposite result) (b > a signed) + a <= x"7FFFFFFF"; -- 2147483647 both unsigned and signed + b <= x"80000000"; -- 2147483648 unsigned, -2147483648 signed + op <= to_unsigned(6, 16); -- gt_s + wait for 10 ns; + + if to_integer(signed(result)) /= 0 then + report "___FAILOUT Signed comparison edge case: -2147483648 > 2147483647 got " & integer'image(to_integer(signed(result))) & " instead of 0"; + end if; + -- Stop the simulation stop_simulation <= true; diff --git a/test/cpu/Testbench.vhdl b/test/cpu/Testbench.vhdl index a503c1f..82c857d 100644 --- a/test/cpu/Testbench.vhdl +++ b/test/cpu/Testbench.vhdl @@ -132,25 +132,204 @@ begin -- expect result 12 assert result = x"0000000C" report "___FAILOUT Couldn't multiply 3 and 4, got " & to_hstring(result) severity error; - -- Test i32.div_s instruction - instruction <= x"41000004"; -- i32.const 16 (put 16 on stack) + -- Test i32.div_s instruction + instruction <= x"41000010"; -- i32.const 16 (put 16 on stack first - this will be operand B) wait for 40 ns; -- Wait for instruction to be processed -- expect result 16 - assert result = x"00000004" report "___FAILOUT Couldn't put 4 onto the stack, put " & to_hstring(result) severity error; + assert result = x"00000010" report "___FAILOUT Couldn't put 16 onto the stack, put " & to_hstring(result) severity error; - instruction <= x"41000010"; -- i32.const 4 (put 4 on stack) + instruction <= x"41000004"; -- i32.const 4 (put 4 on stack second - this will be operand A) wait for 40 ns; -- Wait for instruction to be processed -- expect result 4 - assert result = x"00000010" report "___FAILOUT Couldn't put 16 onto the stack, put " & to_hstring(result) severity error; + assert result = x"00000004" report "___FAILOUT Couldn't put 4 onto the stack, put " & to_hstring(result) severity error; - instruction <= x"6D000000"; -- i32.div_s (divide 16 by 4) + instruction <= x"6D000000"; -- i32.div_s (divide: b/a = 16/4 = 4) wait for 110 ns; -- expect result 4 assert result = x"00000004" report "___FAILOUT Couldn't divide 16 by 4, got " & to_hstring(result) severity error; + -- ========== UNSIGNED COMPARISON TESTS ========== + + -- Test i32.gt_u instruction (unsigned greater than) + instruction <= x"4100000A"; -- i32.const 10 (put 10 on stack first - this will be operand A) + wait for 40 ns; + assert result = x"0000000A" report "___FAILOUT Couldn't put 10 onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"41000005"; -- i32.const 5 (put 5 on stack second - this will be operand B) + wait for 40 ns; + assert result = x"00000005" report "___FAILOUT Couldn't put 5 onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"4A000000"; -- i32.gt_u (check if 10 > 5 unsigned) + wait for 110 ns; + assert result = x"00000001" report "___FAILOUT Couldn't perform unsigned gt 10 > 5, got " & to_hstring(result) severity error; + + -- Test i32.lt_u instruction (unsigned less than) + instruction <= x"41000005"; -- i32.const 5 (put 5 on stack first - this will be operand A) + wait for 40 ns; + assert result = x"00000005" report "___FAILOUT Couldn't put 5 onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"4100000A"; -- i32.const 10 (put 10 on stack second - this will be operand B) + wait for 40 ns; + assert result = x"0000000A" report "___FAILOUT Couldn't put 10 onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"49000000"; -- i32.lt_u (check if 5 < 10 unsigned) + wait for 110 ns; + assert result = x"00000001" report "___FAILOUT Couldn't perform unsigned lt 5 < 10, got " & to_hstring(result) severity error; + + -- Test i32.ge_u instruction (unsigned greater than or equal) + instruction <= x"4100000A"; -- i32.const 10 (put 10 on stack first - this will be operand A) + wait for 40 ns; + assert result = x"0000000A" report "___FAILOUT Couldn't put 10 onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"4100000A"; -- i32.const 10 (put 10 on stack second - this will be operand B) + wait for 40 ns; + assert result = x"0000000A" report "___FAILOUT Couldn't put 10 onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"4F000000"; -- i32.ge_u (check if 10 >= 10 unsigned) + wait for 110 ns; + assert result = x"00000001" report "___FAILOUT Couldn't perform unsigned ge 10 >= 10, got " & to_hstring(result) severity error; + + -- Test i32.le_u instruction (unsigned less than or equal) + instruction <= x"41000005"; -- i32.const 5 (put 5 on stack first - this will be operand A) + wait for 40 ns; + assert result = x"00000005" report "___FAILOUT Couldn't put 5 onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"4100000A"; -- i32.const 10 (put 10 on stack second - this will be operand B) + wait for 40 ns; + assert result = x"0000000A" report "___FAILOUT Couldn't put 10 onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"4D000000"; -- i32.le_u (check if 5 <= 10 unsigned) + wait for 110 ns; + assert result = x"00000001" report "___FAILOUT Couldn't perform unsigned le 5 <= 10, got " & to_hstring(result) severity error; + + -- Test edge case: unsigned comparison with moderate values that show unsigned vs signed difference + -- Load 0x00800000 (8388608 - a value that's positive in both signed and unsigned) + instruction <= x"41800000"; -- i32.const 0x800000 (8388608) + wait for 40 ns; + assert result = x"00800000" report "___FAILOUT Couldn't put 0x00800000 onto the stack, put " & to_hstring(result) severity error; + + -- Load 0x007FFFFF (8388607) + instruction <= x"417FFFFF"; -- i32.const 0x7FFFFF (8388607) + wait for 40 ns; + assert result = x"007FFFFF" report "___FAILOUT Couldn't put 0x007FFFFF onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"4A000000"; -- i32.gt_u (0x00800000 > 0x007FFFFF in unsigned) + wait for 110 ns; + assert result = x"00000001" report "___FAILOUT Couldn't perform unsigned gt 0x00800000 > 0x007FFFFF, got " & to_hstring(result) severity error; + + -- ========== UNSIGNED ARITHMETIC TESTS ========== + + -- Test i32.div_u instruction (unsigned division) + instruction <= x"41000014"; -- i32.const 20 (put 20 on stack first - this will be dividend) + wait for 40 ns; + assert result = x"00000014" report "___FAILOUT Couldn't put 20 onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"41000004"; -- i32.const 4 (put 4 on stack second - this will be divisor) + wait for 40 ns; + assert result = x"00000004" report "___FAILOUT Couldn't put 4 onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"6E000000"; -- i32.div_u (divide 20 by 4 unsigned) + wait for 110 ns; + assert result = x"00000005" report "___FAILOUT Couldn't perform unsigned division 20 / 4, got " & to_hstring(result) severity error; + + -- Test i32.rem_u instruction (unsigned remainder) + instruction <= x"41000017"; -- i32.const 23 (put 23 on stack first - this will be dividend) + wait for 40 ns; + assert result = x"00000017" report "___FAILOUT Couldn't put 23 onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"41000005"; -- i32.const 5 (put 5 on stack second - this will be divisor) + wait for 40 ns; + assert result = x"00000005" report "___FAILOUT Couldn't put 5 onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"70000000"; -- i32.rem_u (23 % 5 unsigned) + wait for 110 ns; + assert result = x"00000003" report "___FAILOUT Couldn't perform unsigned remainder 23 % 5, got " & to_hstring(result) severity error; + + -- Test unsigned division by zero (should return 0) + instruction <= x"4100002A"; -- i32.const 42 (put 42 on stack) + wait for 40 ns; + assert result = x"0000002A" report "___FAILOUT Couldn't put 42 onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"41000000"; -- i32.const 0 (put 0 on stack) + wait for 40 ns; + assert result = x"00000000" report "___FAILOUT Couldn't put 0 onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"6E000000"; -- i32.div_u (42 / 0 unsigned, should return 0) + wait for 110 ns; + assert result = x"00000000" report "___FAILOUT Couldn't handle unsigned division by zero 42 / 0, got " & to_hstring(result) severity error; + + -- Test unsigned remainder by zero (should return 0) + instruction <= x"4100002A"; -- i32.const 42 (put 42 on stack) + wait for 40 ns; + assert result = x"0000002A" report "___FAILOUT Couldn't put 42 onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"41000000"; -- i32.const 0 (put 0 on stack) + wait for 40 ns; + assert result = x"00000000" report "___FAILOUT Couldn't put 0 onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"70000000"; -- i32.rem_u (42 % 0 unsigned, should return 0) + wait for 110 ns; + assert result = x"00000000" report "___FAILOUT Couldn't handle unsigned remainder by zero 42 % 0, got " & to_hstring(result) severity error; + + -- Test large unsigned division with moderate values + instruction <= x"41800000"; -- i32.const 0x800000 (8388608) + wait for 40 ns; + assert result = x"00800000" report "___FAILOUT Couldn't put 0x00800000 onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"41400000"; -- i32.const 0x400000 (4194304) + wait for 40 ns; + assert result = x"00400000" report "___FAILOUT Couldn't put 0x00400000 onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"6E000000"; -- i32.div_u (0x800000 / 0x400000 = 2) + wait for 110 ns; + assert result = x"00000002" report "___FAILOUT Couldn't perform large unsigned division 0x00800000 / 0x00400000, got " & to_hstring(result) severity error; + + -- Test large unsigned remainder with moderate values + instruction <= x"41800001"; -- i32.const 0x800001 (8388609) + wait for 40 ns; + assert result = x"00800001" report "___FAILOUT Couldn't put 0x00800001 onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"41400000"; -- i32.const 0x400000 (4194304) + wait for 40 ns; + assert result = x"00400000" report "___FAILOUT Couldn't put 0x00400000 onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"70000000"; -- i32.rem_u (0x800001 % 0x400000 = 1) + wait for 110 ns; + assert result = x"00000001" report "___FAILOUT Couldn't perform large unsigned remainder 0x00800001 % 0x00400000, got " & to_hstring(result) severity error; + + -- ========== COMPARATIVE TESTS (SIGNED VS UNSIGNED) ========== + + -- Test comparison between signed and unsigned operations with moderate values + -- Use values that demonstrate the difference between signed and unsigned comparison + -- Test signed comparison: Compare two moderate values + instruction <= x"41800000"; -- i32.const 0x800000 (8388608) + wait for 40 ns; + assert result = x"00800000" report "___FAILOUT Couldn't put 0x00800000 onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"417FFFFF"; -- i32.const 0x7FFFFF (8388607) + wait for 40 ns; + assert result = x"007FFFFF" report "___FAILOUT Couldn't put 0x007FFFFF onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"4B000000"; -- i32.gt_s (signed greater than: 8388608 > 8388607 should be true) + wait for 110 ns; + assert result = x"00000001" report "___FAILOUT Couldn't perform signed gt 8388608 > 8388607, got " & to_hstring(result) severity error; + + -- Now test the same values with unsigned comparison (should also be true) + instruction <= x"41800000"; -- i32.const 0x800000 (8388608) + wait for 40 ns; + assert result = x"00800000" report "___FAILOUT Couldn't put 0x00800000 onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"417FFFFF"; -- i32.const 0x7FFFFF (8388607) + wait for 40 ns; + assert result = x"007FFFFF" report "___FAILOUT Couldn't put 0x007FFFFF onto the stack, put " & to_hstring(result) severity error; + + instruction <= x"4A000000"; -- i32.gt_u (unsigned greater than: 8388608 > 8388607 should be true) + wait for 110 ns; + assert result = x"00000001" report "___FAILOUT Couldn't perform unsigned gt 8388608 > 8388607, got " & to_hstring(result) severity error; + stop_simulation <= true; -- Stop simulation after test sequence wait; end process;