svgb/rtl/cpu/control.sv

221 lines
7.0 KiB
Systemverilog

`include "cpu_pkg.svh"
import cpu_pkg::*;
module control (
input logic clk_i,
input logic nreset_i,
input logic [ 7:0] rdata_i,
input logic [ 7:0] f_i,
output state_t state_o,
output logic [15:0] pc_o,
output logic [15:0] sp_o,
output logic instr_valid_o,
output logic instr_undef_o,
output logic [ 7:0] operand8_o,
output logic [15:0] operand16_o,
output logic alu_op_valid_o,
output alu_op_t alu_op_o,
output logic reg_write_alu_o,
output logic rot_op_valid_o,
output rot_op_t rot_op_o,
output op_src_t op_src_o,
output op_dest_t op_dest_o,
output reg8_t reg8_dest_o,
output reg8_t reg8_src_o,
output alu16_op_t alu16_op_o,
output reg16_t reg16_src_o,
output reg16_t reg16_dest_o,
output logic memory_we_o,
output adr_src_t adr_src_o
);
logic nreset_r;
logic halted_r;
logic state_we;
state_t state_r;
state_t state_next;
logic pc_we;
logic [15:0] pc_r;
logic [15:0] pc_next;
logic sp_we;
logic [15:0] sp_r;
logic [15:0] sp_next;
logic instr_pc_we;
logic [15:0] instr_pc_r;
logic [15:0] instr_pc_next;
logic instr_we;
logic [ 7:0] instr_r;
logic [ 7:0] instr_next;
logic operand0_we;
logic [ 7:0] operand0_r;
logic [ 7:0] operand0_next;
logic operand1_we;
logic [ 7:0] operand1_r;
logic [ 7:0] operand1_next;
logic [ 7:0] decoder_instr0_selected;
logic [ 7:0] decoder_instr1_selected;
logic [ 7:0] decoder_instr2_selected;
logic decoder_need_instr1;
logic decoder_need_instr2;
logic decoder_is_multicycle;
logic decoder_is_undef;
logic decoder_alu_op_valid;
logic decoder_rot_op_valid;
logic decoder_memory_we;
adr_src_t decoder_adr_src;
logic decoder_sp_we;
logic is_undef;
logic pc_incr;
logic instr_valid;
logic branch_taken;
logic branch_cc_true;
logic branch_always;
sp_src_t sp_src;
pc_src_t pc_src;
cc_t cc;
always_ff @(posedge clk_i) begin
nreset_r <= nreset_i;
end
always_ff @(posedge clk_i or negedge nreset_i) begin
if (~nreset_i)
halted_r <= 1'b0;
else if (is_undef)
halted_r <= halted_r | is_undef;
end
`DEF_FF(state_r, state_next, state_we, ST0_ADDR);
`DEF_FF(pc_r, pc_next, pc_we, '0);
`DEF_FF(sp_r, sp_next, sp_we, '0);
`DEF_FF(instr_pc_r, instr_pc_next, instr_pc_we, '0);
`DEF_FF(instr_r, instr_next, instr_we, '0);
`DEF_FF(operand0_r, operand0_next, operand0_we, '0);
`DEF_FF(operand1_r, operand1_next, operand1_we, '0);
assign pc_we = (nreset_r & ~is_undef & ~halted_r) & (pc_incr | branch_taken);
assign pc_next = (branch_taken & pc_src == PC_SRC_OPERAND8) ? (pc_r + {{8{operand0_r[7]}}, operand0_r}) :
(branch_taken & pc_src == PC_SRC_OPERAND16) ? {operand1_r, operand0_r} :
(pc_r + 16'b1);
assign sp_we = instr_valid & decoder_sp_we;
assign sp_next = (sp_src == SP_SRC_OPERAND16) ? {operand1_r, operand0_r} :
(sp_src == SP_SRC_INC) ? (sp_r + 16'h01) :
(sp_src == SP_SRC_DEC) ? (sp_r + 16'hFFFF) :
'0;
assign instr_we = (state_r == ST1_DEC);
assign instr_next = rdata_i;
assign instr_pc_we = (state_r == ST0_ADDR);
assign instr_pc_next = pc_r;
assign operand0_we = (state_r == ST2_DEC);
assign operand0_next = rdata_i;
assign operand1_we = (state_r == ST3_DEC);
assign operand1_next = rdata_i;
assign state_we = nreset_r & ~is_undef & ~halted_r;
always_comb begin
case (state_r)
ST0_ADDR: state_next = ST1_DEC;
ST1_DEC: state_next = decoder_need_instr1 ? ST2_DEC : ST2_EXEC;
ST2_EXEC: state_next = decoder_is_multicycle ? ST3_EXEC : ST0_ADDR;
ST2_DEC: state_next = decoder_need_instr2 ? ST3_DEC : ST3_EXEC;
ST3_DEC: state_next = ST4_EXEC;
ST3_EXEC: state_next = ST0_ADDR;
ST4_EXEC: state_next = decoder_is_multicycle ? ST5_EXEC : ST0_ADDR;
ST5_EXEC: state_next = ST0_ADDR;
endcase
end
decode decode_inst (
.instr0_i (decoder_instr0_selected),
.instr1_i (decoder_instr1_selected),
.instr2_i (decoder_instr2_selected),
.state_i (state_r),
.need_instr1_o (decoder_need_instr1),
.need_instr2_o (decoder_need_instr2),
.is_multicycle_o(decoder_is_multicycle),
.undef_o (decoder_is_undef),
.sp_we_o (decoder_sp_we),
.sp_src_o (sp_src),
.alu_op_valid_o(decoder_alu_op_valid),
.alu_op_o (alu_op_o),
.reg_write_alu_o(reg_write_alu_o),
.rot_op_valid_o(decoder_rot_op_valid),
.rot_op_o (rot_op_o),
.op_src_o (op_src_o),
.op_dest_o (op_dest_o),
.reg8_dest_o (reg8_dest_o),
.reg8_src_o (reg8_src_o),
.alu16_op_o (alu16_op_o),
.reg16_src_o (reg16_src_o),
.reg16_dest_o (reg16_dest_o),
.memory_we_o (decoder_memory_we),
.adr_src_o (decoder_adr_src),
.branch_always_o(branch_always),
.cc_o (cc),
.pc_src_o (pc_src)
);
assign decoder_instr0_selected = (state_r == ST1_DEC) ? rdata_i : instr_r;
assign decoder_instr1_selected = (state_r == ST2_DEC) ? rdata_i : operand0_r;
assign decoder_instr2_selected = (state_r == ST3_DEC) ? rdata_i : operand1_r;
assign is_undef = instr_valid & decoder_is_undef;
assign instr_valid = (state_r == ST2_EXEC | state_r == ST3_EXEC | state_r == ST4_EXEC | state_r == ST5_EXEC);
assign alu_op_valid_o = decoder_alu_op_valid & instr_valid;
assign rot_op_valid_o = decoder_rot_op_valid & instr_valid;
assign pc_incr = (state_r == ST0_ADDR) | (state_r == ST1_DEC & decoder_need_instr1) | (state_r == ST2_DEC & decoder_need_instr2);
assign branch_taken = instr_valid & (pc_src != PC_SRC_SEQ) & (branch_cc_true | branch_always);
assign branch_cc_true = ((cc == CC_NZ) & ~f_i[7]) |
((cc == CC_Z) & f_i[7]) |
((cc == CC_NC) & ~f_i[4]) |
((cc == CC_C) & f_i[4]);
assign state_o = state_r;
assign pc_o = pc_r;
assign sp_o = sp_r;
assign instr_valid_o = instr_valid;
assign instr_undef_o = is_undef;
assign operand8_o = operand0_r;
assign operand16_o = {operand1_r, operand0_r};
assign memory_we_o = instr_valid & decoder_memory_we;
assign adr_src_o = instr_valid ? decoder_adr_src :
ADR_SRC_PC;
endmodule : control