summaryrefslogtreecommitdiff
path: root/rtl/core/control
diff options
context:
space:
mode:
Diffstat (limited to 'rtl/core/control')
-rw-r--r--rtl/core/control/control.sv279
-rw-r--r--rtl/core/control/ldst/pop.sv56
2 files changed, 335 insertions, 0 deletions
diff --git a/rtl/core/control/control.sv b/rtl/core/control/control.sv
new file mode 100644
index 0000000..398c8c7
--- /dev/null
+++ b/rtl/core/control/control.sv
@@ -0,0 +1,279 @@
+`include "core/uarch.sv"
+
+module core_control
+(
+ input logic clk,
+ dec_execute,
+ dec_conditional,
+ dec_branch,
+ dec_writeback,
+ dec_update_flags,
+ input ptr dec_branch_offset,
+ input snd_decode dec_snd,
+ input data_decode dec_data,
+ input ldst_decode dec_ldst,
+ input ptr fetch_insn_pc,
+ input psr_flags flags,
+ input word rd_value_a,
+ rd_value_b,
+ q_alu,
+ q_shifter,
+ input logic c_shifter,
+ mem_ready,
+ input word mem_data_rd,
+
+ output logic stall,
+ branch,
+ writeback,
+ update_flags,
+ c_in,
+ output reg_num rd,
+ ra,
+ rb,
+ output ptr branch_target,
+ pc_visible,
+ output psr_mode reg_mode,
+ output alu_op alu,
+ output word alu_a,
+ alu_b,
+ wr_value,
+ output shifter_control shifter,
+ output logic[7:0] shifter_shift,
+ output ptr mem_addr,
+ output word mem_data_wr,
+ output logic mem_start,
+ mem_write
+);
+
+ enum
+ {
+ ISSUE,
+ RD_INDIRECT_SHIFT,
+ WITH_SHIFT,
+ TRANSFER,
+ BASE_WRITEBACK
+ } cycle, next_cycle;
+
+ logic bubble, next_bubble, final_writeback, final_update_flags,
+ ldst, ldst_pre, ldst_increment, ldst_writeback, pop_valid,
+ data_snd_is_imm, data_snd_shift_by_reg, trivial_shift;
+
+ logic[5:0] data_shift_imm;
+ logic[11:0] data_imm;
+ word saved_base, mem_offset;
+ reg_num r_shift, final_rd, popped_upper, popped_lower, popped;
+ reg_list mem_regs, next_regs_upper, next_regs_lower;
+ ptr pc, next_pc_visible;
+
+ assign stall = next_cycle != ISSUE || next_bubble;
+ assign reg_mode = `MODE_SVC; //TODO
+ assign trivial_shift = shifter_shift == 0;
+ assign mem_data_wr = rd_value_b;
+ assign popped = ldst_increment ? popped_lower : popped_upper;
+ assign next_pc_visible = fetch_insn_pc + 2;
+
+ assign next_bubble =
+ ((dec_update_flags || dec_conditional) && (final_update_flags || update_flags))
+ || (final_writeback && (final_rd == dec_data.rn || final_rd == dec_snd.r));
+
+ core_control_ldst_pop ldst_pop
+ (
+ .regs(mem_regs),
+ .valid(pop_valid),
+ .next_upper(next_regs_upper),
+ .next_lower(next_regs_lower),
+ .pop_upper(popped_upper),
+ .pop_lower(popped_lower)
+ );
+
+ always_comb begin
+ unique case(cycle)
+ RD_INDIRECT_SHIFT: shifter_shift = rd_value_b[7:0];
+ default: shifter_shift = {2'b00, data_shift_imm};
+ endcase
+
+ next_cycle = ISSUE;
+
+ unique case(cycle)
+ ISSUE:
+ if(data_snd_shift_by_reg)
+ next_cycle = RD_INDIRECT_SHIFT;
+ else if(~trivial_shift)
+ next_cycle = WITH_SHIFT;
+
+ RD_INDIRECT_SHIFT:
+ if(~trivial_shift)
+ next_cycle = WITH_SHIFT;
+
+ TRANSFER:
+ if(!mem_ready || pop_valid)
+ next_cycle = TRANSFER;
+ else if(ldst_writeback)
+ next_cycle = BASE_WRITEBACK;
+
+ default: ;
+ endcase
+
+ if(bubble)
+ next_cycle = ISSUE;
+ else if(next_cycle == ISSUE && ldst)
+ next_cycle = TRANSFER;
+
+ unique case(cycle)
+ TRANSFER: alu_a = saved_base;
+ default: alu_a = rd_value_a;
+ endcase
+
+ unique case(cycle)
+ RD_INDIRECT_SHIFT, WITH_SHIFT:
+ alu_b = saved_base;
+
+ TRANSFER:
+ alu_b = mem_offset;
+
+ default:
+ if(data_snd_is_imm)
+ alu_b = {{20{1'b0}}, data_imm};
+ else
+ alu_b = rd_value_b;
+ endcase
+ end
+
+ always_ff @(posedge clk) begin
+ cycle <= next_cycle;
+ bubble <= 0;
+ branch <= 0;
+ writeback <= 0;
+ update_flags <= 0;
+
+ unique case(cycle)
+ TRANSFER: wr_value <= mem_data_rd;
+ BASE_WRITEBACK: wr_value <= saved_base;
+ default: wr_value <= q_alu;
+ endcase
+
+ unique case(next_cycle)
+ ISSUE: begin
+ final_writeback <= 0;
+ final_update_flags <= 0;
+
+ bubble <= next_bubble;
+
+ if(dec_execute & ~next_bubble) begin
+ branch <= dec_branch;
+ branch_target <= next_pc_visible + dec_branch_offset;
+
+ alu <= dec_data.op;
+ ra <= dec_data.rn;
+
+ data_snd_is_imm <= dec_snd.is_imm;
+ data_snd_shift_by_reg <= dec_snd.shift_by_reg;
+ data_imm <= dec_snd.imm;
+ data_shift_imm <= dec_snd.shift_imm;
+
+ shifter.shr <= dec_snd.shr;
+ shifter.ror <= dec_snd.ror;
+ shifter.put_carry <= dec_snd.put_carry;
+ shifter.sign_extend <= dec_snd.sign_extend;
+
+ rb <= dec_snd.r;
+ r_shift <= dec_snd.r_shift;
+ c_in <= flags.c;
+
+ // TODO: dec_ldst.unprivileged/user_regs
+ // TODO: byte/halfword sizes
+ ldst <= dec_ldst.enable;
+ ldst_pre <= dec_ldst.pre_indexed;
+ ldst_increment <= dec_ldst.increment;
+ ldst_writeback <= dec_ldst.writeback;
+
+ mem_regs <= dec_ldst.regs;
+ mem_write <= !dec_ldst.load;
+
+ final_rd <= dec_data.rd;
+ final_writeback <= dec_writeback;
+ final_update_flags <= dec_update_flags;
+ end
+
+ update_flags <= final_update_flags;
+ writeback <= final_writeback;
+ rd <= final_rd;
+ pc <= fetch_insn_pc;
+ pc_visible <= next_pc_visible;
+ end
+
+ RD_INDIRECT_SHIFT: begin
+ rb <= r_shift;
+ data_snd_shift_by_reg <= 0;
+ saved_base <= rd_value_b;
+ end
+
+ WITH_SHIFT: begin
+ c_in <= c_shifter;
+ saved_base <= q_shifter;
+ end
+
+ TRANSFER: begin
+ if(cycle != TRANSFER) begin
+ ldst <= 0;
+ mem_offset <= alu_b;
+ end
+
+ if(mem_ready) begin
+ wr_value <= mem_data_rd;
+ writeback <= !mem_write;
+ end
+
+ if(cycle != TRANSFER || mem_ready) begin
+ mem_regs <= ldst_increment ? next_regs_lower : next_regs_upper;
+ mem_addr <= ldst_pre ? q_alu[31:2] : alu_a[31:2];
+ saved_base <= q_alu;
+
+ if(pop_valid) begin
+ rd <= popped;
+ rb <= popped;
+ end else
+ rb <= final_rd; // Viene de dec_ldst.rd
+ end
+
+ mem_start <= cycle != TRANSFER || (mem_ready && pop_valid);
+ end
+
+ BASE_WRITEBACK: begin
+ rd <= final_rd;
+ wr_value <= mem_data_rd;
+ writeback <= !mem_write;
+ final_rd <= ra;
+ end
+ endcase
+ end
+
+ initial begin
+ cycle = ISSUE;
+ bubble = 0;
+
+ pc = 0;
+ pc_visible = 2;
+
+ c_in = 0;
+ branch = 1;
+ writeback = 0;
+ branch_target = 30'd0;
+ data_snd_shift_by_reg = 0;
+
+ ldst = 0;
+ ldst_pre = 0;
+ ldst_writeback = 0;
+ ldst_increment = 0;
+
+ mem_addr = 30'b0;
+ mem_write = 0;
+ mem_start = 0;
+ mem_regs = 16'b0;
+ mem_offset = 0;
+
+ final_rd = 0;
+ final_writeback = 0;
+ end
+
+endmodule
diff --git a/rtl/core/control/ldst/pop.sv b/rtl/core/control/ldst/pop.sv
new file mode 100644
index 0000000..64dc04d
--- /dev/null
+++ b/rtl/core/control/ldst/pop.sv
@@ -0,0 +1,56 @@
+`include "core/uarch.sv"
+
+module core_control_ldst_pop
+(
+ input reg_list regs,
+
+ output logic valid,
+ output reg_list next_upper,
+ next_lower,
+ output reg_num pop_upper,
+ pop_lower
+);
+
+ assign valid = regs != 16'b0;
+
+ always_comb begin
+ unique casez(regs)
+ 16'b???????????????1: begin pop_lower = 4'h0; next_lower = {regs[15:1], 1'b0}; end
+ 16'b??????????????10: begin pop_lower = 4'h1; next_lower = {regs[15:2], 2'b0}; end
+ 16'b?????????????100: begin pop_lower = 4'h2; next_lower = {regs[15:3], 3'b0}; end
+ 16'b????????????1000: begin pop_lower = 4'h3; next_lower = {regs[15:4], 4'b0}; end
+ 16'b???????????10000: begin pop_lower = 4'h4; next_lower = {regs[15:5], 5'b0}; end
+ 16'b??????????100000: begin pop_lower = 4'h5; next_lower = {regs[15:6], 6'b0}; end
+ 16'b?????????1000000: begin pop_lower = 4'h6; next_lower = {regs[15:7], 7'b0}; end
+ 16'b????????10000000: begin pop_lower = 4'h7; next_lower = {regs[15:8], 8'b0}; end
+ 16'b???????100000000: begin pop_lower = 4'h8; next_lower = {regs[15:9], 9'b0}; end
+ 16'b??????1000000000: begin pop_lower = 4'h9; next_lower = {regs[15:10], 10'b0}; end
+ 16'b?????10000000000: begin pop_lower = 4'ha; next_lower = {regs[15:11], 11'b0}; end
+ 16'b????100000000000: begin pop_lower = 4'hb; next_lower = {regs[15:12], 12'b0}; end
+ 16'b???1000000000000: begin pop_lower = 4'hc; next_lower = {regs[15:13], 13'b0}; end
+ 16'b??10000000000000: begin pop_lower = 4'hd; next_lower = {regs[15:14], 14'b0}; end
+ 16'b?100000000000000: begin pop_lower = 4'he; next_lower = {regs[15], 15'b0}; end
+ default: begin pop_lower = 4'hf; next_lower = 16'b0; end
+ endcase
+
+ unique casez(regs)
+ 16'b1???????????????: begin pop_upper = 4'hf; next_upper = { 1'b0, regs[14:0]}; end
+ 16'b01??????????????: begin pop_upper = 4'he; next_upper = { 2'b0, regs[13:0]}; end
+ 16'b001?????????????: begin pop_upper = 4'hd; next_upper = { 3'b0, regs[12:0]}; end
+ 16'b0001????????????: begin pop_upper = 4'hc; next_upper = { 4'b0, regs[11:0]}; end
+ 16'b00001???????????: begin pop_upper = 4'hb; next_upper = { 5'b0, regs[10:0]}; end
+ 16'b000001??????????: begin pop_upper = 4'ha; next_upper = { 6'b0, regs[9:0]}; end
+ 16'b0000001?????????: begin pop_upper = 4'h9; next_upper = { 7'b0, regs[8:0]}; end
+ 16'b00000001????????: begin pop_upper = 4'h8; next_upper = { 8'b0, regs[7:0]}; end
+ 16'b000000001???????: begin pop_upper = 4'h7; next_upper = { 9'b0, regs[6:0]}; end
+ 16'b0000000001??????: begin pop_upper = 4'h6; next_upper = {10'b0, regs[5:0]}; end
+ 16'b00000000001?????: begin pop_upper = 4'h5; next_upper = {11'b0, regs[4:0]}; end
+ 16'b000000000001????: begin pop_upper = 4'h4; next_upper = {12'b0, regs[3:0]}; end
+ 16'b0000000000001???: begin pop_upper = 4'h3; next_upper = {13'b0, regs[2:0]}; end
+ 16'b00000000000001??: begin pop_upper = 4'h2; next_upper = {14'b0, regs[1:0]}; end
+ 16'b000000000000001?: begin pop_upper = 4'h1; next_upper = {15'b0, regs[0]}; end
+ default: begin pop_upper = 4'h0; next_upper = 16'b0; end
+ endcase
+ end
+
+endmodule