svgb/rtl/cpu/ctrl.sv

181 lines
4.1 KiB
Systemverilog

`include "cpu_pkg.svh"
import cpu_pkg::*;
module ctrl (
input logic clk,
input logic nreset,
input logic [ 7:0] rdata_i,
output logic instr_valid_o,
output logic [ 7:0] instr_o [2:0],
output logic pc_we_o, // update PC always
output logic pc_we_cc_o, // update PC conditionally
output pc_src_t pc_src_o,
output cc_t cc_o,
output reg8_t reg8_src_o,
output reg8_t reg8_dest_o,
output reg16_t reg16_sel_o,
output alu_ctrl_t alu_ctrl_o,
output logic alu16_inc_o,
output logic alu16_dec_o,
output addr_src_t addr_src_o,
output bus_ctrl_t bus_x_ctrl_o,
output bus_ctrl_t bus_y_ctrl_o,
output bus16_ctrl_t bus_p_ctrl_o,
output bus16_ctrl_t bus_q_ctrl_o
);
typedef enum {
ST_RESET,
ST_ADDR,
ST_FETCH0,
ST_FETCH1,
ST_FETCH2,
ST_EXEC1,
ST_EXEC2,
ST_EXEC3
} state_t;
logic halt;
logic instr_undef;
logic halted_r;
logic state_en;
state_t state_r;
state_t state_next;
logic state_ex;
logic instr_we [2:0];
logic [ 7:0] instr_r [2:0];
logic [ 7:0] instr [2:0];
logic req_instr1;
logic req_instr2;
logic req_ex2;
logic req_ex3;
addr_src_t instr_addr_src;
logic is_ex1;
logic is_ex2;
logic is_ex3;
logic incr_pc;
logic idec_pc_we;
logic idec_pc_we_cc;
pc_src_t idec_pc_src;
idec idec_inst (
.instr_i (instr),
.is_ex1_i (is_ex1),
.is_ex2_i (is_ex2),
.is_ex3_i (is_ex3),
.req_instr1_o (req_instr1),
.req_instr2_o (req_instr2),
.req_ex2_o (req_ex2),
.req_ex3_o (req_ex3),
.reg8_src_o (reg8_src_o),
.reg8_dest_o (reg8_dest_o),
.reg16_sel_o (reg16_sel_o),
.bus_x_ctrl_o (bus_x_ctrl_o),
.bus_y_ctrl_o (bus_y_ctrl_o),
.bus_p_ctrl_o (bus_p_ctrl_o),
.bus_q_ctrl_o (bus_q_ctrl_o),
.alu_ctrl_o (alu_ctrl_o),
.alu16_inc_o (alu16_inc_o),
.alu16_dec_o (alu16_dec_o),
.addr_src_o (instr_addr_src),
.pc_we_o (idec_pc_we),
.pc_we_cc_o (idec_pc_we_cc),
.cc_o (cc_o),
.pc_src_o (idec_pc_src),
.instr_undef_o (instr_undef)
);
assign is_ex1 = state_r == ST_EXEC1;
assign is_ex2 = state_r == ST_EXEC2;
assign is_ex3 = state_r == ST_EXEC3;
assign halt = instr_undef & is_ex1;
assign state_en = ~halted_r;
always_ff @(posedge clk or negedge nreset) begin
if (!nreset)
state_r <= ST_RESET;
else if (state_en)
state_r <= state_next;
end
always_ff @(posedge clk or negedge nreset) begin
if (!nreset)
halted_r <= 1'b0;
else if (halt)
halted_r <= 1'b1;
end
generate for (genvar i = 0; i < 3; i++) begin : gen_instr_r
always_ff @(posedge clk or negedge nreset) begin
if (!nreset)
instr_r[i] <= 8'h0;
else if (instr_we[i])
instr_r[i] <= rdata_i;
end
end endgenerate
assign instr_we[0] = (state_r == ST_FETCH0);
assign instr_we[1] = (state_r == ST_FETCH1);
assign instr_we[2] = (state_r == ST_FETCH2);
always_comb begin
case (state_r)
ST_RESET: state_next = ST_ADDR;
ST_ADDR: state_next = ST_FETCH0;
ST_FETCH0: state_next = req_instr1 ? ST_FETCH1 : ST_EXEC1;
ST_FETCH1: state_next = req_instr2 ? ST_FETCH2 : ST_EXEC1;
ST_FETCH2: state_next = ST_EXEC1;
ST_EXEC1: state_next = req_ex2 ? ST_EXEC2 : ST_ADDR;
ST_EXEC2: state_next = req_ex3 ? ST_EXEC3 : ST_ADDR;
ST_EXEC3: state_next = ST_ADDR;
endcase
end
assign state_ex = is_ex1 | is_ex2 | is_ex3;
assign incr_pc = (state_r == ST_ADDR) |
(state_r == ST_FETCH0 & req_instr1) |
(state_r == ST_FETCH1 & req_instr2);
assign pc_we_o = state_ex ? idec_pc_we : incr_pc;
assign pc_we_cc_o = state_ex & idec_pc_we_cc;
assign pc_src_o = state_ex ? idec_pc_src : PC_SRC_INC;
assign instr_valid_o = state_ex & ~instr_undef;
assign instr[0] = (state_r == ST_FETCH0) ? rdata_i : instr_r[0];
assign instr[1] = (state_r == ST_FETCH1) ? rdata_i : instr_r[1];
assign instr[2] = (state_r == ST_FETCH2) ? rdata_i : instr_r[2];
assign instr_o = instr;
assign addr_src_o = state_ex ? instr_addr_src : ADDR_SRC_PC;
endmodule : ctrl