181 lines
4.1 KiB
Systemverilog
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
|