summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--rtl/core/alu/alu.sv14
-rw-r--r--rtl/core/alu/shifter.sv33
-rw-r--r--rtl/core/arm810.sv11
-rw-r--r--rtl/core/cycles.sv116
4 files changed, 132 insertions, 42 deletions
diff --git a/rtl/core/alu/alu.sv b/rtl/core/alu/alu.sv
index 914b40e..f5a0487 100644
--- a/rtl/core/alu/alu.sv
+++ b/rtl/core/alu/alu.sv
@@ -5,7 +5,8 @@ module core_alu
(
input alu_control ctrl,
input logic[W - 1:0] a,
- b,
+ base,
+ input logic[7:0] shift,
input logic c_in,
output logic[W - 1:0] q,
@@ -14,12 +15,21 @@ module core_alu
);
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;
+ logic[W - 1:0] b, 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_shifter #(.W(W)) shifter
+ (
+ .base(base),
+ .shift(shift),
+ .b(b),
+ .c(c_shifter),
+ .*
+ );
+
core_alu_add #(.W(W)) op_add
(
.a(swap_a),
diff --git a/rtl/core/alu/shifter.sv b/rtl/core/alu/shifter.sv
index 3effb2c..4385b41 100644
--- a/rtl/core/alu/shifter.sv
+++ b/rtl/core/alu/shifter.sv
@@ -1,12 +1,35 @@
-module alu_shl
+`include "core/uarch.sv"
+
+module core_alu_shifter
#(parameter W=16)
(
- input logic[W - 1:0] a,
- b,
- output logic[W - 1:0] q,
+ input alu_control ctrl,
+ input logic[W - 1:0] base,
+ input logic[7:0] shift,
+ input logic c_in,
+
+ output logic[W - 1:0] b,
output logic c
);
- assign {c, q} = {1'b0, a} << b;
+ logic [W - 1:0] b_no_c, b_shl, b_shr, b_ror;
+ logic [W:0] sign_mask;
+ logic c_shl, c_shr;
+
+ assign sign_mask = {(W + 1){ctrl.sign_extend & base[W - 1]}};
+ assign {c_shl, b_shl} = {c_in, base} << shift;
+ assign {b_shr, c_shr} = {base, c_in} >> shift | ~(sign_mask >> shift);
+ assign b_ror = b_shr | base << (W - shift);
+
+ assign b = {b_no_c[W - 1] | (ctrl.put_carry & c_in), b_no_c[W - 2:0]};
+ assign c = ctrl.shr | ctrl.ror ? c_shr : c_shl;
+
+ always_comb
+ if(ctrl.ror)
+ b = b_ror;
+ else if(ctrl.shr)
+ b = {b_shr[W - 1] | (ctrl.put_carry & c_in), b_shr[W - 2:0]};
+ else
+ b = b_shl;
endmodule
diff --git a/rtl/core/arm810.sv b/rtl/core/arm810.sv
index d9939fd..b344836 100644
--- a/rtl/core/arm810.sv
+++ b/rtl/core/arm810.sv
@@ -45,11 +45,13 @@ module arm810
.*
);
- reg_num rd;
+ reg_num rd, ra, rb;
logic explicit_branch, writeback, update_flags;
ptr branch_target;
psr_mode reg_mode;
alu_control alu_ctrl;
+ word alu_base;
+ logic[7:0] alu_shift;
core_cycles cycles
(
@@ -70,8 +72,8 @@ module arm810
core_regs regs
(
- .rd_r_a(0), //TODO
- .rd_r_b(0), //TODO
+ .rd_r_a(ra),
+ .rd_r_b(rb),
.rd_mode(reg_mode),
.wr_mode(reg_mode),
.wr_r(rd),
@@ -87,7 +89,8 @@ module arm810
(
.ctrl(alu_ctrl),
.a(rd_value_a),
- .b(rd_value_b),
+ .base(alu_base),
+ .shift(alu_shift),
.c_in(flags.c),
.q(wr_value),
.nzcv(alu_flags),
diff --git a/rtl/core/cycles.sv b/rtl/core/cycles.sv
index 84bbd32..f503188 100644
--- a/rtl/core/cycles.sv
+++ b/rtl/core/cycles.sv
@@ -2,63 +2,116 @@
module core_cycles
(
- input logic clk,
- dec_execute,
- dec_branch,
- dec_writeback,
- dec_update_flags,
- input ptr dec_branch_offset,
- input alu_decode dec_alu,
- input ptr fetch_insn_pc,
+ input logic clk,
+ dec_execute,
+ dec_branch,
+ dec_writeback,
+ dec_update_flags,
+ input ptr dec_branch_offset,
+ input alu_decode dec_alu,
+ input ptr fetch_insn_pc,
+ input word rd_value_b,
output logic stall,
branch,
writeback,
update_flags,
output reg_num rd,
+ ra,
+ rb,
output ptr branch_target,
pc,
pc_visible,
output psr_mode reg_mode,
- output alu_control alu
+ output alu_control alu,
+ output word alu_base,
+ output logic[7:0] alu_shift
);
enum
{
- EXECUTE
+ EXECUTE,
+ RD_SHIFT
} cycle, next_cycle;
+ logic final_writeback, data_snd_is_imm, data_snd_shift_by_reg;
+ logic[5:0] data_shift_imm;
+ logic[7:0] data_imm;
+ word saved_base;
+ reg_num r_shift;
+
assign stall = next_cycle != EXECUTE;
assign pc_visible = pc + 2;
- assign next_cycle = EXECUTE; //TODO
assign reg_mode = `MODE_SVC; //TODO
+ always_comb begin
+ next_cycle = EXECUTE;
+ if((cycle == EXECUTE) & data_snd_shift_by_reg)
+ next_cycle = RD_SHIFT;
+
+ unique case(cycle)
+ RD_SHIFT:
+ alu_base = saved_base;
+
+ default:
+ if(data_snd_is_imm)
+ alu_base = {{24{1'b0}}, data_imm};
+ else
+ alu_base = rd_value_b;
+ endcase
+
+ unique case(cycle)
+ RD_SHIFT: alu_shift = rd_value_b[7:0];
+ default: alu_shift = {2'b00, data_shift_imm};
+ endcase
+ end
+
always_ff @(posedge clk) begin
cycle <= next_cycle;
- if(next_cycle == EXECUTE) begin
- branch <= 0;
- writeback <= 0;
- update_flags <= 0;
- branch_target <= 30'bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
+ unique case(next_cycle)
+ EXECUTE: begin
+ branch <= 0;
+ writeback <= 0;
+ update_flags <= 0;
+ branch_target <= 30'bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;
- if(dec_execute) begin
- branch <= dec_branch;
- writeback <= dec_writeback;
- branch_target <= pc_visible + dec_branch_offset;
+ if(dec_execute) begin
+ branch <= dec_branch;
+ writeback <= dec_writeback & ~dec_alu.snd_shift_by_reg;
+ update_flags <= dec_update_flags;
+ branch_target <= pc_visible + dec_branch_offset;
+
+ data_snd_is_imm <= dec_alu.snd_is_imm;
+ data_snd_shift_by_reg <= dec_alu.snd_shift_by_reg;
+ data_imm <= dec_alu.imm;
+ data_shift_imm <= dec_alu.shift_imm;
+
+ alu.op <= dec_alu.op;
+ alu.shl <= dec_alu.shl;
+ alu.shr <= dec_alu.shr;
+ alu.ror <= dec_alu.ror;
+ alu.put_carry <= dec_alu.put_carry;
+ alu.sign_extend <= dec_alu.sign_extend;
+
+ rd <= dec_alu.rd;
+ ra <= dec_alu.rn;
+ rb <= dec_alu.r_snd;
+ r_shift <= dec_alu.r_shift;
+
+ final_writeback <= dec_writeback;
+ end
+
+ pc <= fetch_insn_pc;
end
- alu.op <= dec_alu.op;
- alu.shl <= dec_alu.shl;
- alu.shr <= dec_alu.shr;
- alu.ror <= dec_alu.ror;
- alu.put_carry <= dec_alu.put_carry;
- alu.sign_extend <= dec_alu.sign_extend;
-
- pc <= fetch_insn_pc;
- rd <= dec_alu.rd;
- update_flags <= dec_update_flags;
- end
+ RD_SHIFT: begin
+ rb <= r_shift;
+ data_snd_shift_by_reg <= 0;
+ saved_base <= rd_value_b;
+ writeback <= final_writeback;
+ end
+ endcase
end
initial begin
@@ -66,6 +119,7 @@ module core_cycles
branch = 1;
writeback = 0;
+ data_snd_shift_by_reg = 0;
branch_target = 30'd0;
pc = 0;
end