diff options
Diffstat (limited to '')
| -rw-r--r-- | rtl/core/alu/add.sv | 20 | ||||
| -rw-r--r-- | rtl/core/alu/alu.sv | 139 | ||||
| -rw-r--r-- | rtl/core/alu/and.sv | 12 | ||||
| -rw-r--r-- | rtl/core/alu/orr.sv | 12 | ||||
| -rw-r--r-- | rtl/core/alu/shifter.sv | 12 | ||||
| -rw-r--r-- | rtl/core/alu/xor.sv | 12 |
6 files changed, 207 insertions, 0 deletions
diff --git a/rtl/core/alu/add.sv b/rtl/core/alu/add.sv new file mode 100644 index 0000000..12bd237 --- /dev/null +++ b/rtl/core/alu/add.sv @@ -0,0 +1,20 @@ +module core_alu_add +#(parameter W=16) +( + input logic[W - 1:0] a, + b, + c_in, + + output logic[W - 1:0] q, + output logic c, + v +); + + logic sgn_a, sgn_b, sgn_q; + assign {sgn_a, sgn_b, sgn_q} = {a[W - 1], b[W - 1], q[W - 1]}; + + //TODO: No sirve el carry + assign {c, q} = {1'b0, a} + {1'b0, b} + {1'b0, c_in}; + assign v = (sgn_a ~^ sgn_b) & (sgn_a ^ sgn_q); + +endmodule diff --git a/rtl/core/alu/alu.sv b/rtl/core/alu/alu.sv new file mode 100644 index 0000000..4d0a9cc --- /dev/null +++ b/rtl/core/alu/alu.sv @@ -0,0 +1,139 @@ +`include "core/psr.sv" +`include "core/uarch.sv" + +module core_alu +#(parameter W=16) +( + input alu_op op, + input logic[W - 1:0] a, + b, + input logic c_in, + + output logic[W - 1:0] q, + output psr_flags nzcv, + output logic v_valid +); + + logic c, v, swap, sub, and_not, c_shifter, c_add, v_add; + logic[W - 1:0] swap_a, swap_b, neg_b, c_in_add, q_add, q_and, q_orr, q_xor; + + assign swap_a = swap ? b : a; + assign swap_b = swap ? a : b; + assign neg_b = -swap_b; + + core_alu_add #(.W(W)) op_add + ( + .a(swap_a), + .b(sub ? neg_b : swap_b), + .c_in(c_in_add), + .q(q_add), + .c(c_add), + .v(v_add), + .* + ); + + core_alu_and #(.W(W)) op_and + ( + .b(and_not ? ~b : b), + .q(q_and), + .* + ); + + core_alu_orr #(.W(W)) op_orr + ( + .q(q_orr), + .* + ); + + core_alu_xor #(.W(W)) op_xor + ( + .q(q_xor), + .* + ); + + always_comb begin + unique case(op) + `ALU_ADD, `ALU_ADC, `ALU_CMN, `ALU_CMP, `ALU_SUB, `ALU_SBC: + swap = 0; + + `ALU_RSB, `ALU_RSC: + swap = 1; + + default: + swap = 1'bx; + endcase + + unique case(op) + `ALU_ADD, `ALU_CMN, `ALU_ADC: + sub = 0; + + `ALU_SUB, `ALU_CMP, `ALU_SBC, `ALU_RSB, `ALU_RSC: + sub = 1; + + default: + sub = 1'bx; + endcase + + unique case(op) + `ALU_ADD, `ALU_CMN, `ALU_CMP, `ALU_SUB, `ALU_RSB: + c_in_add = 0; + + `ALU_ADC: + c_in_add = {{(W - 1){1'b0}}, c_in}; + + `ALU_SBC, `ALU_RSC: + c_in_add = {{(W - 1){~c_in}}, ~c_in}; + + default: + c_in_add = {W{1'bx}}; + endcase + + unique case(op) + `ALU_AND, `ALU_TST: + and_not = 0; + + `ALU_BIC: + and_not = 1; + + default: + and_not = 1'bx; + endcase + + unique case(op) + `ALU_SUB, `ALU_RSB, `ALU_ADD, `ALU_ADC, `ALU_SBC, `ALU_RSC, `ALU_CMP, `ALU_CMN: + q = q_add; + + `ALU_AND, `ALU_TST, `ALU_BIC: + q = q_and; + + `ALU_EOR, `ALU_TEQ: + q = q_xor; + + `ALU_ORR: + q = q_orr; + + `ALU_MOV: + q = b; + + `ALU_MVN: + q = neg_b; + endcase + + unique case(op) + `ALU_AND, `ALU_EOR, `ALU_TST, `ALU_TEQ, `ALU_ORR, `ALU_MOV, `ALU_BIC, `ALU_MVN: begin + c = c_shifter; + v = 1'bx; + v_valid = 0; + end + + `ALU_SUB, `ALU_RSB, `ALU_ADD, `ALU_ADC, `ALU_SBC, `ALU_RSC, `ALU_CMP, `ALU_CMN: begin + c = c_add; + v = v_add; + v_valid = 1; + end + endcase + end + + assign nzcv = {q[W - 1], ~|q, c, v}; + +endmodule diff --git a/rtl/core/alu/and.sv b/rtl/core/alu/and.sv new file mode 100644 index 0000000..d119f24 --- /dev/null +++ b/rtl/core/alu/and.sv @@ -0,0 +1,12 @@ +module core_alu_and +#(parameter W=16) +( + input logic[W - 1:0] a, + b, + + output logic[W - 1:0] q +); + + assign q = a & b; + +endmodule diff --git a/rtl/core/alu/orr.sv b/rtl/core/alu/orr.sv new file mode 100644 index 0000000..1ee87c2 --- /dev/null +++ b/rtl/core/alu/orr.sv @@ -0,0 +1,12 @@ +module core_alu_orr +#(parameter W=16) +( + input logic[W - 1:0] a, + b, + + output logic[W - 1:0] q +); + + assign q = a | b; + +endmodule diff --git a/rtl/core/alu/shifter.sv b/rtl/core/alu/shifter.sv new file mode 100644 index 0000000..3effb2c --- /dev/null +++ b/rtl/core/alu/shifter.sv @@ -0,0 +1,12 @@ +module alu_shl +#(parameter W=16) +( + input logic[W - 1:0] a, + b, + output logic[W - 1:0] q, + output logic c +); + + assign {c, q} = {1'b0, a} << b; + +endmodule diff --git a/rtl/core/alu/xor.sv b/rtl/core/alu/xor.sv new file mode 100644 index 0000000..f55dfc2 --- /dev/null +++ b/rtl/core/alu/xor.sv @@ -0,0 +1,12 @@ +module core_alu_xor +#(parameter W=16) +( + input logic[W - 1:0] a, + b, + + output logic[W - 1:0] q +); + + assign q = a ^ b; + +endmodule |
