Added arithmetic and logical vhdl functions
[calu.git] / cpu / src / alu_pkg.vhd
diff --git a/cpu/src/alu_pkg.vhd b/cpu/src/alu_pkg.vhd
new file mode 100755 (executable)
index 0000000..a125674
--- /dev/null
@@ -0,0 +1,154 @@
+library IEEE;\r
+\r
+use IEEE.std_logic_1164.all;\r
+use IEEE.numeric_std.all;\r
+\r
+use work.common_pkg.all;\r
+--use work.core_extension.all;\r
+\r
+\r
+package alu_pkg is\r
+       \r
+       type status_rec is record\r
+               zero : std_logic;\r
+               oflo : std_logic;\r
+               sign : std_logic;\r
+               carry : std_logic;\r
+       end record;\r
+       \r
+       subtype status_t is byte_t;\r
+       type alu_interal_rec is record\r
+               \r
+       end record alu_internal_rec;\r
+       \r
+       type alu_result_rec is record\r
+               result : gp_register_t;\r
+               result_addr : gp_addr_t;\r
+               \r
+               status : status_rec;\r
+               stackpointer : gp_register_t;\r
+\r
+               alu_jmp : std_logic;\r
+               brpr_bit : std_logic;\r
+               reg_op : std_logic;\r
+               mem_op  : std_logic;\r
+               \r
+               hw_op   : std_logic;\r
+               byte_op : std_logic;\r
+               sign_xt : std_logic;\r
+               \r
+       end record alu_result_rec;\r
+       \r
+       constant SHIFT_WIDTH : integer := log2c(gp_register_t'length);\r
+       \r
+       function add_oflo(l_neg, r_neg, res_neg : std_logic) return std_logic;\r
+       function addsub_op(left_operand, right_operand : gp_register_t; sub : std_logic; alu_result : alu_result_rec) return alu_result_rec;\r
+       \r
+       function and_op(left_operand, right_operand : gp_register_t; alu_result : alu_result_rec) return alu_result_rec;\r
+       function or_op(left_operand, right_operand : gp_register_t; alu_result : alu_result_rec) return alu_result_rec;\r
+       function xor_op(left_operand, right_operand : gp_register_t; alu_result : alu_result_rec) return alu_result_rec;\r
+       \r
+       function shift_op(left_operand, right_operand : gp_register_t; arith,sleft,carry : std_logic ;alu_result : alu_result_rec) return alu_result_rec;\r
+       \r
+       \r
+end package alu_pkg;\r
+\r
+package body alu_pkg is\r
+\r
+       function add_oflo(l_neg, r_neg , res_neg: std_logic) return std_logic is\r
+       begin\r
+               return (l_neg AND r_neg AND not(res_neg)) OR \r
+                               (not(l_neg) AND not(r_neg) AND res_neg);\r
+       end function add_oflo;\r
+       \r
+       function addsub_op(left_operand, right_operand : gp_register_t; sub, addc : std_logic; alu_result : alu_result_rec) return alu_result_rec is\r
+               variable alu_result_out : alu_result_rec;\r
+               variable complement             : gp_register_t;\r
+               variable carry_res              : unsigned(gp_register_t'length downto 0);\r
+               variable tmp_right_operand : unsigned(gp_register_t'length downto 0);\r
+               variable oflo1, oflo2, l_neg, r_neg : std_logic;\r
+               variable addcarry               : unsigned(carry_res'range);\r
+       begin\r
+               alu_result_out := alu_result;\r
+               \r
+               addcarry := (others =>'0');\r
+               addcarry(0) := unsigned(alu_result.status.carry and addc);\r
+               \r
+               complement := inc(not(right_operand));\r
+               l_neg := left_operand(gp_register_t'high);\r
+               \r
+               carry_res := unsigned('0' & left_operand)+addcarry;\r
+               oflo1 := add_oflo(l_neg,'0',std_logic_vector(carry_res)(gp_register_t'high));\r
+               \r
+               if sub = '1' then\r
+                       tmp_right_operand := unsigned('0' & complement);\r
+               else\r
+                       tmp_right_operand := unsigned('0' & right_operand);\r
+               end if;\r
+               \r
+               l_neg := std_logic_vector(carry_res)(gp_register_t'high);\r
+               r_neg := std_logic_vector(tmp_right_operand)(gp_register_t'high);\r
+               \r
+               carry_res := carry_res + tmp_right_operand;\r
+               oflo2 := add_oflo(l_neg,r_neg,std_logic_vector(carry_res)(gp_register_t'high));\r
+               \r
+\r
+               alu_result_out.result := std_logic_vector(carry_res)(gp_register_t'range);\r
+               alu_result_out.status.carry := std_logic_vector(carry_res)(carry_res'high);\r
+               \r
+               \r
+               alu_result_out.status.carry := oflo1 or oflo2;\r
+               \r
+               --sign will be set globally.\r
+               --zero will be set globally.\r
+               \r
+               return alu_result_out;\r
+       end function addsub_op;\r
+       \r
+       function and_op(left_operand, right_operand : gp_register_t; alu_result : alu_result_rec) return alu_result_rec is\r
+               variable alu_result_out : alu_result_rec;\r
+       begin\r
+               alu_result_out := alu_result;\r
+               alu_result_out.result := left_operand and right_operand;\r
+       end function and_op;\r
+       \r
+       function or_op(left_operand, right_operand : gp_register_t; alu_result : alu_result_rec) return alu_result_rec is\r
+               variable alu_result_out : alu_result_rec;\r
+       begin\r
+               alu_result_out := alu_result;\r
+               alu_result_out.result := left_operand or right_operand;\r
+       end function or_op;\r
+       \r
+       function xor_op(left_operand, right_operand : gp_register_t; alu_result : alu_result_rec) return alu_result_rec is\r
+               variable alu_result_out : alu_result_rec;\r
+       begin\r
+               alu_result_out := alu_result;\r
+               alu_result_out.result := left_operand xor right_operand;\r
+       end function xor_op;\r
+       \r
+       function shift_op(left_operand, right_operand : gp_register_t; arith,rs,carry : std_logic ;alu_result : alu_result_rec) return alu_result_rec is\r
+               variable alu_result_out : alu_result_rec;\r
+               variable tmp_shift : bit_vector(gp_register_t'length+1 downto 0);\r
+               variable tmp_sb : std_logic;\r
+       begin\r
+               alu_result_out := alu_result;\r
+               \r
+               if rs = '1' then\r
+                       tmp_sb := (carry and alu_result.status.carry and not(arith)) or (arith and left_operand(gp_register_t'high));\r
+                       tmp_shift := bit_vector(tmp_sb & left_operand & alu_result.status.carry);\r
+                       tmp_shift := tmp_shift sra to_integer(unsigned(right_operand)(SHIFT_WIDTH-1 downto 0));\r
+                       \r
+                       alu_result_out.status.carry := std_logic_vector(tmp_shift)(0);\r
+               else\r
+                       tmp_sb := (carry and alu_result.status.carry and not(arith));\r
+                       tmp_shift :=  bit_vector(alu_result.status.carry & left_operand & tmp_sb);\r
+                       tmp_shift :=  tmp_shift sla to_integer(unsigned(right_operand)(SHIFT_WIDTH-1 downto 0));\r
+                       \r
+                       alu_result_out.status.carry := std_logic_vector(tmp_shift)(tmp_shift'high);\r
+               end if;\r
+               \r
+               alu_result_out.result := std_logic_vector(tmp_shift)(gp_register_t'length downto 1);\r
+               \r
+       end function shift_op;\r
+\r
+end package body alu_pkg;\r