`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