From 683352ce030923bdef3cf4fe90d6cb73f4f74529 Mon Sep 17 00:00:00 2001 From: Alejandro Soto Date: Wed, 16 Nov 2022 16:46:52 -0600 Subject: Implement psr read/write logic --- conspiracion.qsf | 1 + rtl/core/arm810.sv | 6 +--- rtl/core/control/control.sv | 20 +++++++++++-- rtl/core/control/cycles.sv | 13 +++++++-- rtl/core/control/issue.sv | 9 ++++-- rtl/core/control/psr.sv | 56 +++++++++++++++++++++++++++++++++++++ rtl/core/control/select.sv | 5 +--- rtl/core/control/stall.sv | 7 +++-- rtl/core/control/writeback.sv | 3 ++ rtl/core/decode/decode.sv | 7 +++-- rtl/core/decode/isa.sv | 2 +- rtl/core/decode/mux.sv | 13 ++++++--- rtl/core/psr.sv | 65 ++++++++++++++++++++++++++++--------------- rtl/core/uarch.sv | 6 ++-- tb/sim/modeswitch.S | 3 +- tb/sim/modeswitch.py | 11 ++++++-- 16 files changed, 173 insertions(+), 54 deletions(-) create mode 100644 rtl/core/control/psr.sv diff --git a/conspiracion.qsf b/conspiracion.qsf index c6f0f9f..a8f62ac 100644 --- a/conspiracion.qsf +++ b/conspiracion.qsf @@ -209,6 +209,7 @@ set_global_assignment -name SYSTEMVERILOG_FILE rtl/core/control/mul.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/core/control/ldst/ldst.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/core/control/ldst/pop.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/core/control/ldst/sizes.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/core/control/psr.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/core/control/select.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/core/control/stall.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/core/control/writeback.sv diff --git a/rtl/core/arm810.sv b/rtl/core/arm810.sv index 7fbb895..89a2a68 100644 --- a/rtl/core/arm810.sv +++ b/rtl/core/arm810.sv @@ -76,16 +76,12 @@ module arm810 .* ); - word psr_rd, psr_wr; + word cpsr_rd, spsr_rd, psr_wr; logic psr_write, psr_saved, update_flags, psr_wr_flags, psr_wr_control; psr_mode mode; psr_flags flags; psr_intmask intmask; - //TODO - assign psr_write = 0; - assign psr_saved = 0; - core_psr psr ( .mask(intmask), diff --git a/rtl/core/control/control.sv b/rtl/core/control/control.sv index 82aad33..9f398dc 100644 --- a/rtl/core/control/control.sv +++ b/rtl/core/control/control.sv @@ -8,9 +8,12 @@ module core_control input insn_decode dec, input ptr insn_pc, + input psr_mode mode, input psr_flags flags, alu_flags, - input word rd_value_a, + input word cpsr_rd, + spsr_rd, + rd_value_a, rd_value_b, q_alu, q_shifter, @@ -57,7 +60,12 @@ module core_control mul_long, mul_start, mul_signed, - coproc + coproc, + psr_saved, + psr_write, + psr_wr_flags, + psr_wr_control, + output word psr_wr ); ctrl_cycle cycle, next_cycle; @@ -118,6 +126,14 @@ module core_control .* ); + word psr_wb; + logic psr, final_psr_write, final_restore_spsr; + + core_control_psr ctrl_psr + ( + .* + ); + logic final_writeback, final_update_flags; reg_num final_rd; diff --git a/rtl/core/control/cycles.sv b/rtl/core/control/cycles.sv index ca47f10..b7a7829 100644 --- a/rtl/core/control/cycles.sv +++ b/rtl/core/control/cycles.sv @@ -6,6 +6,7 @@ module core_control_cycles rst_n, halt, mul, + psr, ldst, bubble, exception, @@ -39,7 +40,8 @@ module core_control_cycles EXCEPTION, MUL, MUL_ACC_LD, - MUL_HI_WB + MUL_HI_WB, + PSR } state, next_state; // TODO: debe estar escrito de tal forma que Quartus infiera una FSM @@ -53,6 +55,7 @@ module core_control_cycles assign cycle.mul = state == MUL; assign cycle.mul_acc_ld = state == MUL_ACC_LD; assign cycle.mul_hi_wb = state == MUL_HI_WB; + assign cycle.psr = state == PSR; assign next_cycle.issue = next_state == ISSUE; assign next_cycle.rd_indirect_shift = next_state == RD_INDIRECT_SHIFT; @@ -63,6 +66,7 @@ module core_control_cycles assign next_cycle.mul = next_state == MUL; assign next_cycle.mul_acc_ld = next_state == MUL_ACC_LD; assign next_cycle.mul_hi_wb = next_state == MUL_HI_WB; + assign next_cycle.psr = next_state == PSR; always_comb begin next_state = ISSUE; @@ -109,8 +113,11 @@ module core_control_cycles if(bubble) next_state = ISSUE; - else if(next_state == ISSUE && ldst) begin - next_state = TRANSFER; + else if(next_state == ISSUE) begin + if(ldst) + next_state = TRANSFER; + else if(psr) + next_state = PSR; end end diff --git a/rtl/core/control/issue.sv b/rtl/core/control/issue.sv index d124a0d..ffdf250 100644 --- a/rtl/core/control/issue.sv +++ b/rtl/core/control/issue.sv @@ -23,7 +23,10 @@ module core_control_issue next_pc_visible ); - assign issue = next_cycle.issue && dec.ctrl.execute && !next_bubble && !halt; + logic valid; + + assign valid = !next_bubble && !halt; + assign issue = next_cycle.issue && dec.ctrl.execute && valid; assign next_pc_visible = insn_pc + 2; always_ff @(posedge clk or negedge rst_n) @@ -32,14 +35,14 @@ module core_control_issue undefined <= 0; pc_visible <= 2; end else if(next_cycle.issue) begin - if(issue) begin + if(valid) begin undefined <= dec.ctrl.undefined; `ifdef VERILATOR if(dec.ctrl.undefined) $display("[core] undefined insn: [0x%08x] %08x", insn_pc << 2, insn); - end `endif + end pc <= insn_pc; pc_visible <= next_pc_visible; diff --git a/rtl/core/control/psr.sv b/rtl/core/control/psr.sv new file mode 100644 index 0000000..758b730 --- /dev/null +++ b/rtl/core/control/psr.sv @@ -0,0 +1,56 @@ +`include "core/uarch.sv" + +module core_control_psr +( + input logic clk, + rst_n, + + input insn_decode dec, + input word cpsr_rd, + spsr_rd, + alu_b, + input psr_mode mode, + + input ctrl_cycle next_cycle, + input logic issue, + + output logic psr, + psr_saved, + psr_write, + psr_wr_flags, + psr_wr_control, + final_psr_write, + final_restore_spsr, + output word psr_wb, + psr_wr, + output psr_mode reg_mode +); + + assign psr_wb = psr_saved ? spsr_rd : cpsr_rd; + assign psr_wr = final_restore_spsr ? spsr_rd : alu_b; + assign psr_write = next_cycle.issue && (final_psr_write || final_restore_spsr); + + //TODO: casos donde esto no es cierto + assign reg_mode = mode; + + always_ff @(posedge clk or negedge rst_n) + if(!rst_n) begin + psr <= 0; + psr_saved <= 0; + psr_wr_flags <= 0; + psr_wr_control <= 0; + + final_psr_write <= 0; + final_restore_spsr <= 0; + end else if(next_cycle.issue) begin + psr <= issue && dec.ctrl.psr; + psr_saved <= dec.psr.saved; + psr_wr_flags <= dec.psr.wr_flags; + psr_wr_control <= dec.psr.wr_control; + + final_psr_write <= issue && dec.psr.write; + final_restore_spsr <= issue && dec.psr.restore_spsr; + end else if(next_cycle.psr) + psr <= 0; + +endmodule diff --git a/rtl/core/control/select.sv b/rtl/core/control/select.sv index 3cc0ca5..1ea2c31 100644 --- a/rtl/core/control/select.sv +++ b/rtl/core/control/select.sv @@ -17,14 +17,11 @@ module core_control_select mul_r_add_hi, output reg_num ra, - rb, - output psr_mode reg_mode + rb ); reg_num r_shift, last_ra, last_rb; - assign reg_mode = `MODE_SVC; //TODO - always_comb begin ra = last_ra; rb = last_rb; diff --git a/rtl/core/control/stall.sv b/rtl/core/control/stall.sv index d2c4de8..085f11e 100644 --- a/rtl/core/control/stall.sv +++ b/rtl/core/control/stall.sv @@ -10,6 +10,8 @@ module core_control_stall input ctrl_cycle next_cycle, input logic final_update_flags, + final_restore_spsr, + final_psr_write, final_writeback, input reg_num final_rd, @@ -19,13 +21,14 @@ module core_control_stall next_bubble ); - logic pc_rd_hazard, pc_wr_hazard, rn_pc_hazard, snd_pc_hazard, flags_hazard; + logic pc_rd_hazard, pc_wr_hazard, rn_pc_hazard, snd_pc_hazard, psr_hazard, flags_hazard; assign stall = !next_cycle.issue || next_bubble || halt; assign halted = halt && !next_bubble; - assign next_bubble = pc_rd_hazard || pc_wr_hazard || flags_hazard; + assign next_bubble = pc_rd_hazard || pc_wr_hazard || flags_hazard || psr_hazard; //FIXME: pc_rd_hazard no debería definirse sin final_writeback? + assign psr_hazard = final_psr_write || final_restore_spsr; assign pc_rd_hazard = final_writeback && (rn_pc_hazard || snd_pc_hazard); assign pc_wr_hazard = final_writeback && final_rd == `R15; assign rn_pc_hazard = dec.data.uses_rn && dec.data.rn == `R15; diff --git a/rtl/core/control/writeback.sv b/rtl/core/control/writeback.sv index f28e9a9..824d867 100644 --- a/rtl/core/control/writeback.sv +++ b/rtl/core/control/writeback.sv @@ -18,6 +18,7 @@ module core_control_writeback next_cycle, input word saved_base, vector, + psr_wb, input reg_num ra, popped, mul_r_add_hi, @@ -65,6 +66,8 @@ module core_control_writeback wr_value = saved_base; else if(cycle.mul || cycle.mul_hi_wb) wr_value = mul_q_lo; + else if(cycle.psr) + wr_value = psr_wb; else // Ruta combinacional larga wr_value = q_alu; diff --git a/rtl/core/decode/decode.sv b/rtl/core/decode/decode.sv index 7d666f3..f16db9a 100644 --- a/rtl/core/decode/decode.sv +++ b/rtl/core/decode/decode.sv @@ -27,6 +27,7 @@ module core_decode assign dec.coproc = dec_coproc; assign dec_ctrl.mul = mul; + assign dec_ctrl.psr = psr; assign dec_ctrl.ldst = ldst; assign dec_ctrl.branch = branch; assign dec_ctrl.coproc = coproc; @@ -35,7 +36,7 @@ module core_decode assign dec_ctrl.undefined = undefined; assign dec_ctrl.conditional = conditional; - assign dec_psr.saved = spsr; + assign dec_psr.saved = psr_saved; assign dec_psr.write = psr_write; assign dec_psr.wr_flags = psr_wr_flags; assign dec_psr.wr_control = psr_wr_control; @@ -43,8 +44,8 @@ module core_decode assign dec_psr.restore_spsr = restore_spsr; logic execute, undefined, conditional, writeback, update_flags, - restore_spsr, branch, ldst, mul, coproc, spsr, psr_write, - psr_wr_flags, psr_wr_control; + restore_spsr, branch, ldst, mul, psr, coproc, psr_saved, + psr_write, psr_wr_flags, psr_wr_control; core_decode_mux mux ( diff --git a/rtl/core/decode/isa.sv b/rtl/core/decode/isa.sv index 4f2578d..1273a8b 100644 --- a/rtl/core/decode/isa.sv +++ b/rtl/core/decode/isa.sv @@ -194,7 +194,7 @@ `define GROUP_MSR 28'b0_0_?_1_0_?_1_0_????_1111_0000_0000_???? -`define FIELD_MRS_R [24] +`define FIELD_MRS_R [22] `define FIELD_MRS_RD [15:12] `define FIELD_MSR_I [25] `define FIELD_MSR_R [22] diff --git a/rtl/core/decode/mux.sv b/rtl/core/decode/mux.sv index e8d930e..51fe14b 100644 --- a/rtl/core/decode/mux.sv +++ b/rtl/core/decode/mux.sv @@ -55,8 +55,9 @@ module core_decode_mux branch, ldst, mul, + psr, coproc, - spsr, + psr_saved, psr_write, psr_wr_flags, psr_wr_control, @@ -78,7 +79,8 @@ module core_decode_mux conditional = 0; restore_spsr = 0; - spsr = 0; + psr = 0; + psr_saved = 0; psr_write = 0; update_flags = 0; psr_wr_flags = 1; @@ -189,7 +191,8 @@ module core_decode_mux dec_data.rd = mrs_rd; dec_data.uses_rn = 0; - spsr = mrs_spsr; + psr = 1; + psr_saved = mrs_spsr; writeback = 1; conditional = 1; end @@ -201,9 +204,10 @@ module core_decode_mux snd_ror_if_imm = 1; snd_shift_by_reg_if_reg = 0; - spsr = msr_spsr; + psr = 1; dec_snd = snd; psr_write = 1; + psr_saved = msr_spsr; conditional = 1; psr_wr_flags = msr_fields.f; psr_wr_control = msr_fields.c; @@ -233,6 +237,7 @@ module core_decode_mux execute = 0; mul = 1'bx; + psr = 1'bx; ldst = 1'bx; branch = 1'bx; coproc = 1'bx; diff --git a/rtl/core/psr.sv b/rtl/core/psr.sv index ac672ed..c1fe0fd 100644 --- a/rtl/core/psr.sv +++ b/rtl/core/psr.sv @@ -16,7 +16,8 @@ module core_psr output psr_flags flags, output psr_intmask mask, output psr_mode mode, - output word psr_rd + output word cpsr_rd, + spsr_rd ); typedef struct packed @@ -42,7 +43,7 @@ module core_psr psr_mode m; } psr_word; - psr_word rd_word, wr_word; + psr_word cpsr_word /*verilator public*/, spsr_word, wr_word; psr_flags next_flags; psr_state cpsr, spsr, spsr_svc, spsr_abt, spsr_und, spsr_irq, spsr_fiq, wr_state, wr_clean; @@ -50,34 +51,46 @@ module core_psr assign mode = cpsr.mode; assign mask = cpsr.mask; assign flags = cpsr.flags; - assign psr_rd = rd_word; assign wr_word = psr_wr; + assign cpsr_rd = cpsr_word; + assign spsr_rd = spsr_word; assign {wr_state.flags, wr_state.mask, wr_state.mode} = {wr_word.nzcv, wr_word.if_, wr_word.m}; `ifdef VERILATOR - psr_word cpsr_word /*verilator public*/, - spsr_svc_word /*verilator public*/, + psr_word spsr_svc_word /*verilator public*/, spsr_abt_word /*verilator public*/, spsr_und_word /*verilator public*/, spsr_fiq_word /*verilator public*/, spsr_irq_word /*verilator public*/; - assign {cpsr_word.nzcv, cpsr_word.if_, cpsr_word.m} = {cpsr.flags, cpsr.mask, cpsr.mode}; + always_comb begin + spsr_svc_word = {$bits(spsr_svc_word){1'b0}}; + spsr_abt_word = {$bits(spsr_abt_word){1'b0}}; + spsr_und_word = {$bits(spsr_und_word){1'b0}}; + spsr_irq_word = {$bits(spsr_irq_word){1'b0}}; + spsr_fiq_word = {$bits(spsr_fiq_word){1'b0}}; + + spsr_svc_word.a = 1; + spsr_abt_word.a = 1; + spsr_und_word.a = 1; + spsr_irq_word.a = 1; + spsr_fiq_word.a = 1; - assign {spsr_svc_word.nzcv, spsr_svc_word.if_, spsr_svc_word.m} - = {spsr_svc.flags, spsr_svc.mask, spsr_svc.mode}; + {spsr_svc_word.nzcv, spsr_svc_word.if_, spsr_svc_word.m} + = {spsr_svc.flags, spsr_svc.mask, spsr_svc.mode}; - assign {spsr_abt_word.nzcv, spsr_abt_word.if_, spsr_abt_word.m} - = {spsr_abt.flags, spsr_abt.mask, spsr_abt.mode}; + {spsr_abt_word.nzcv, spsr_abt_word.if_, spsr_abt_word.m} + = {spsr_abt.flags, spsr_abt.mask, spsr_abt.mode}; - assign {spsr_und_word.nzcv, spsr_und_word.if_, spsr_und_word.m} - = {spsr_und.flags, spsr_und.mask, spsr_und.mode}; + {spsr_und_word.nzcv, spsr_und_word.if_, spsr_und_word.m} + = {spsr_und.flags, spsr_und.mask, spsr_und.mode}; - assign {spsr_irq_word.nzcv, spsr_irq_word.if_, spsr_irq_word.m} - = {spsr_irq.flags, spsr_irq.mask, spsr_irq.mode}; + {spsr_irq_word.nzcv, spsr_irq_word.if_, spsr_irq_word.m} + = {spsr_irq.flags, spsr_irq.mask, spsr_irq.mode}; - assign {spsr_fiq_word.nzcv, spsr_fiq_word.if_, spsr_fiq_word.m} - = {spsr_fiq.flags, spsr_fiq.mask, spsr_fiq.mode}; + {spsr_fiq_word.nzcv, spsr_fiq_word.if_, spsr_fiq_word.m} + = {spsr_fiq.flags, spsr_fiq.mask, spsr_fiq.mode}; + end `endif always_comb begin @@ -85,13 +98,21 @@ module core_psr if(!alu_v_valid) next_flags.v = flags.v; - rd_word = {$bits(rd_word){1'b0}}; - rd_word.a = 1; + unique case(mode) + `MODE_SVC: spsr = spsr_svc; + `MODE_ABT: spsr = spsr_abt; + `MODE_UND: spsr = spsr_und; + `MODE_IRQ: spsr = spsr_irq; + `MODE_FIQ: spsr = spsr_fiq; + default: spsr = cpsr; + endcase + + cpsr_word = {$bits(cpsr_word){1'b0}}; + spsr_word = {$bits(spsr_word){1'b0}}; + {cpsr_word.a, spsr_word.a} = 2'b11; - if(saved) - {rd_word.nzcv, rd_word.if_, rd_word.m} = {spsr.flags, spsr.mask, spsr.mode}; - else - {rd_word.nzcv, rd_word.if_, rd_word.m} = {flags, mask, mode}; + {cpsr_word.nzcv, cpsr_word.if_, cpsr_word.m} = {flags, mask, mode}; + {spsr_word.nzcv, spsr_word.if_, spsr_word.m} = {spsr.flags, spsr.mask, spsr.mode}; wr_clean = wr_state; unique case(wr_state.mode) diff --git a/rtl/core/uarch.sv b/rtl/core/uarch.sv index e089e35..3aff072 100644 --- a/rtl/core/uarch.sv +++ b/rtl/core/uarch.sv @@ -86,7 +86,8 @@ typedef struct packed branch, coproc, ldst, - mul; + mul, + psr; } ctrl_decode; typedef struct packed @@ -194,7 +195,8 @@ typedef struct packed exception, mul, mul_acc_ld, - mul_hi_wb; + mul_hi_wb, + psr; } ctrl_cycle; typedef struct packed diff --git a/tb/sim/modeswitch.S b/tb/sim/modeswitch.S index c04f8a3..52908de 100644 --- a/tb/sim/modeswitch.S +++ b/tb/sim/modeswitch.S @@ -1,5 +1,6 @@ .global reset reset: + mov r6, lr mrs r0, cpsr udf mrs r2, cpsr @@ -12,7 +13,7 @@ reset: nop msr cpsr_fxc, r0 msr spsr_fxc, r0 - mov pc, lr + mov pc, r6 .global undefined undefined: diff --git a/tb/sim/modeswitch.py b/tb/sim/modeswitch.py index 6919f2e..6c8cd79 100644 --- a/tb/sim/modeswitch.py +++ b/tb/sim/modeswitch.py @@ -1,3 +1,10 @@ def final(): - #TODO - assert_reg(r0, -1) + assert_reg(r0, 0x0000_01d3) + assert_reg(r1, 0x0000_01d3) + assert_reg(r2, 0x0000_01d3) + assert_reg(r3, 0x0000_0010) + assert_reg(r4, 0x0000_0110) + assert_reg(r5, 0x4000_0110) + assert_reg(cpsr, 0x0000_0110) + assert_reg(r13_svc, 0x2000_0000) + assert_reg(r13_und, 0x0000_01db) -- cgit v1.2.3