Koray Yanik
fda176d3b5
Rewrite to use several bus multiplexers, resulting into a less messy microarchitecture (hopefully). Some more room for cleanup though... Supports every instruction from the bootstrap rom, more or less. LY hacked at 0x90 to progress through vsync instantly. No cartridge is present yet, so we will always fail checksum test and lock up.
282 lines
9.2 KiB
Systemverilog
282 lines
9.2 KiB
Systemverilog
`include "cpu_pkg.svh"
|
|
|
|
import cpu_pkg::*;
|
|
|
|
module cpu (
|
|
input logic clk,
|
|
input logic nreset,
|
|
|
|
output logic [15:0] addr_o,
|
|
input logic [ 7:0] rdata_i,
|
|
output logic we_o,
|
|
output logic [ 7:0] wdata_o
|
|
);
|
|
|
|
|
|
logic instr_valid;
|
|
logic [ 7:0] instr[2:0];
|
|
|
|
logic incr_pc;
|
|
logic pc_we;
|
|
logic [15:0] pc_r;
|
|
logic [15:0] pc_next;
|
|
logic [15:0] pc_bus;
|
|
|
|
cc_t ctrl_cc;
|
|
logic ctrl_pc_we;
|
|
logic ctrl_pc_we_cc;
|
|
pc_src_t ctrl_pc_src;
|
|
|
|
logic [ 1:0] sp_we;
|
|
logic [15:0] sp_r;
|
|
logic [15:0] sp_next;
|
|
|
|
reg8_t reg8_rsel;
|
|
reg8_t reg8_wsel;
|
|
logic reg8_we;
|
|
logic [7:0] reg8_wdata;
|
|
logic [7:0] reg8_rdata;
|
|
|
|
reg16_t reg16_sel;
|
|
logic reg16_we;
|
|
logic [15:0] reg16_wdata;
|
|
logic [15:0] reg16_rdata;
|
|
|
|
addr_src_t addr_src;
|
|
|
|
logic [ 7:0] reg_a;
|
|
logic [ 7:0] reg_f;
|
|
|
|
logic alu_update_a;
|
|
logic alu_update_f;
|
|
alu_ctrl_t ctrl_alu_ctrl;
|
|
alu_ctrl_t alu_ctrl;
|
|
logic [ 7:0] alu_operand_in;
|
|
logic [ 7:0] alu_operand_out;
|
|
|
|
logic alu16_en;
|
|
logic [15:0] alu16_in;
|
|
logic [15:0] alu16_out;
|
|
logic alu16_inc;
|
|
logic alu16_dec;
|
|
|
|
bus_ctrl_t bus_x_ctrl;
|
|
bus_ctrl_t bus_y_ctrl;
|
|
bus16_ctrl_t bus_p_ctrl;
|
|
bus16_ctrl_t bus_q_ctrl;
|
|
logic [ 7:0] bus_x;
|
|
logic [ 7:0] bus_y;
|
|
logic [15:0] bus_p;
|
|
logic [15:0] bus_q;
|
|
|
|
logic cc_true;
|
|
|
|
always_ff @(posedge clk or negedge nreset) begin
|
|
if (!nreset)
|
|
pc_r <= '0;
|
|
else if (pc_we)
|
|
pc_r <= pc_next;
|
|
end
|
|
|
|
assign pc_we = ctrl_pc_we | (ctrl_pc_we_cc & cc_true);
|
|
|
|
assign pc_next = (ctrl_pc_src == PC_SRC_OPERAND8 ) ? (pc_r + {{8{instr[1][7]}}, instr[1]}) :
|
|
(ctrl_pc_src == PC_SRC_OPERAND16) ? {instr[2], instr[1]} :
|
|
(ctrl_pc_src == PC_SRC_BUS) ? pc_bus :
|
|
pc_r + 16'h01;
|
|
|
|
assign cc_true = ((ctrl_cc == CC_NZ) & ~reg_f[7]) |
|
|
((ctrl_cc == CC_Z) & reg_f[7]) |
|
|
((ctrl_cc == CC_NC) & ~reg_f[4]) |
|
|
((ctrl_cc == CC_C) & reg_f[4]);
|
|
|
|
assign pc_bus[15:8] = ({8{bus_x_ctrl.dst == BUS_DST_PC_H}} & bus_x) |
|
|
({8{bus_y_ctrl.dst == BUS_DST_PC_H}} & bus_y);
|
|
|
|
assign pc_bus[ 7:0] = ({8{bus_x_ctrl.dst == BUS_DST_PC_L}} & bus_x) |
|
|
({8{bus_y_ctrl.dst == BUS_DST_PC_L}} & bus_y);
|
|
|
|
always_ff @(posedge clk or negedge nreset) begin
|
|
if (!nreset)
|
|
sp_r[15:0] <= '0;
|
|
else if (sp_we[1])
|
|
sp_r[15:0] <= sp_next;
|
|
end
|
|
always_ff @(posedge clk or negedge nreset) begin
|
|
if (!nreset)
|
|
sp_r[ 7:0] <= '0;
|
|
else if (sp_we[0])
|
|
sp_r[ 7:0] <= sp_next;
|
|
end
|
|
|
|
assign sp_we[1] = instr_valid & (
|
|
(bus_x_ctrl.wen & (bus_x_ctrl.dst == BUS_DST_SP_H)) |
|
|
(bus_y_ctrl.wen & (bus_y_ctrl.dst == BUS_DST_SP_H)) |
|
|
(bus_p_ctrl.wen & (bus_p_ctrl.dst == BUS16_DST_SP)) |
|
|
(bus_q_ctrl.wen & (bus_q_ctrl.dst == BUS16_DST_SP)));
|
|
|
|
assign sp_we[0] = instr_valid & (
|
|
(bus_x_ctrl.wen & (bus_x_ctrl.dst == BUS_DST_SP_L)) |
|
|
(bus_y_ctrl.wen & (bus_y_ctrl.dst == BUS_DST_SP_L)) |
|
|
(bus_p_ctrl.wen & (bus_p_ctrl.dst == BUS16_DST_SP)) |
|
|
(bus_q_ctrl.wen & (bus_q_ctrl.dst == BUS16_DST_SP)));
|
|
|
|
assign sp_next[15:8] = ({8{bus_x_ctrl.dst == BUS_DST_SP_H}} & bus_x) |
|
|
({8{bus_y_ctrl.dst == BUS_DST_SP_H}} & bus_y) |
|
|
({8{bus_p_ctrl.dst == BUS16_DST_SP}} & bus_p[15:8]) |
|
|
({8{bus_q_ctrl.dst == BUS16_DST_SP}} & bus_q[15:8]);
|
|
assign sp_next[ 7:0] = ({8{bus_x_ctrl.dst == BUS_DST_SP_L}} & bus_x) |
|
|
({8{bus_y_ctrl.dst == BUS_DST_SP_L}} & bus_y) |
|
|
({8{bus_p_ctrl.dst == BUS16_DST_SP}} & bus_p[ 7:0]) |
|
|
({8{bus_q_ctrl.dst == BUS16_DST_SP}} & bus_q[ 7:0]);
|
|
|
|
ctrl ctrl_inst (
|
|
.clk (clk),
|
|
.nreset (nreset),
|
|
|
|
.rdata_i (rdata_i),
|
|
|
|
.instr_valid_o(instr_valid),
|
|
.instr_o (instr),
|
|
|
|
.pc_we_o (ctrl_pc_we),
|
|
.pc_we_cc_o (ctrl_pc_we_cc),
|
|
.pc_src_o (ctrl_pc_src),
|
|
.cc_o (ctrl_cc),
|
|
|
|
.reg8_src_o (reg8_rsel),
|
|
.reg8_dest_o (reg8_wsel),
|
|
.reg16_sel_o (reg16_sel),
|
|
|
|
.alu_ctrl_o (ctrl_alu_ctrl),
|
|
|
|
.addr_src_o (addr_src),
|
|
|
|
.alu16_inc_o (alu16_inc),
|
|
.alu16_dec_o (alu16_dec),
|
|
|
|
.bus_x_ctrl_o (bus_x_ctrl),
|
|
.bus_y_ctrl_o (bus_y_ctrl),
|
|
.bus_p_ctrl_o (bus_p_ctrl),
|
|
.bus_q_ctrl_o (bus_q_ctrl)
|
|
);
|
|
|
|
|
|
regbank regbank_inst (
|
|
.clk (clk),
|
|
.nreset (nreset),
|
|
|
|
|
|
.reg16_wselect_i (reg16_sel),
|
|
.reg16_rselect_i (reg16_sel),
|
|
.reg16_we_i (reg16_we),
|
|
.reg16_wdata_i (reg16_wdata),
|
|
.reg16_rdata_o (reg16_rdata),
|
|
|
|
.reg8_wselect_i (reg8_wsel),
|
|
.reg8_we_i (reg8_we),
|
|
.reg8_wdata_i (reg8_wdata),
|
|
.reg8_rselect_i (reg8_rsel),
|
|
.reg8_rdata_o (reg8_rdata)
|
|
);
|
|
|
|
assign reg8_we = instr_valid & (
|
|
(bus_x_ctrl.wen & (bus_x_ctrl.dst == BUS_DST_REG8)) |
|
|
(bus_y_ctrl.wen & (bus_y_ctrl.dst == BUS_DST_REG8)));
|
|
|
|
assign reg8_wdata = ({8{bus_x_ctrl.dst == BUS_DST_REG8}} & bus_x) |
|
|
({8{bus_y_ctrl.dst == BUS_DST_REG8}} & bus_y);
|
|
|
|
assign reg16_we =
|
|
instr_valid & (
|
|
(bus_x_ctrl.wen & (bus_x_ctrl.dst == BUS_DST_REG16_H | bus_x_ctrl.dst == BUS_DST_REG16_L)) |
|
|
(bus_y_ctrl.wen & (bus_y_ctrl.dst == BUS_DST_REG16_H | bus_y_ctrl.dst == BUS_DST_REG16_L)) |
|
|
(bus_p_ctrl.wen & (bus_p_ctrl.dst == BUS16_DST_REG16)) |
|
|
(bus_q_ctrl.wen & (bus_q_ctrl.dst == BUS16_DST_REG16)));
|
|
|
|
assign reg16_wdata[15:8] = ({8{bus_x_ctrl.dst == BUS_DST_REG16_H}} & bus_x) |
|
|
({8{bus_y_ctrl.dst == BUS_DST_REG16_H}} & bus_y) |
|
|
({8{bus_p_ctrl.dst == BUS16_DST_REG16}} & bus_p[15:8]) |
|
|
({8{bus_q_ctrl.dst == BUS16_DST_REG16}} & bus_q[15:8]);
|
|
assign reg16_wdata[ 7:0] = ({8{bus_x_ctrl.dst == BUS_DST_REG16_L}} & bus_x) |
|
|
({8{bus_y_ctrl.dst == BUS_DST_REG16_L}} & bus_y) |
|
|
({8{bus_p_ctrl.dst == BUS16_DST_REG16}} & bus_p[ 7:0]) |
|
|
({8{bus_q_ctrl.dst == BUS16_DST_REG16}} & bus_q[ 7:0]);
|
|
|
|
alu alu_inst (
|
|
.clk (clk),
|
|
.nreset (nreset),
|
|
|
|
.alu_ctrl_i (alu_ctrl),
|
|
|
|
.operand_in_i (alu_operand_in),
|
|
.operand_out_o(alu_operand_out),
|
|
|
|
.reg_a_o (reg_a),
|
|
.reg_f_o (reg_f)
|
|
);
|
|
|
|
always_comb begin
|
|
alu_ctrl = ctrl_alu_ctrl;
|
|
alu_ctrl.update_a = instr_valid & alu_ctrl.update_a;
|
|
alu_ctrl.update_f = instr_valid & alu_ctrl.update_f;
|
|
end
|
|
|
|
assign alu_operand_in = ({8{bus_x_ctrl.dst == BUS_DST_ALU}} & bus_x) |
|
|
({8{bus_y_ctrl.dst == BUS_DST_ALU}} & bus_y);
|
|
|
|
alu16 alu16_inst (
|
|
.operand_in_i (alu16_in),
|
|
.operand_out_o(alu16_out),
|
|
.increment_i (alu16_inc),
|
|
.decrement_i (alu16_dec)
|
|
);
|
|
assign alu16_en = alu16_inc | alu16_dec;
|
|
|
|
assign alu16_in = ({16{bus_p_ctrl.dst == BUS16_DST_ALU16}} & bus_p) |
|
|
({16{bus_q_ctrl.dst == BUS16_DST_ALU16}} & bus_q);
|
|
|
|
assign addr_o = ({16{addr_src == ADDR_SRC_PC }} & pc_r ) |
|
|
({16{addr_src == ADDR_SRC_SP }} & sp_r ) |
|
|
({16{addr_src == ADDR_SRC_REG16 }} & reg16_rdata) |
|
|
({16{addr_src == ADDR_SRC_REG8 }} & { 8'hFF, reg8_rdata}) |
|
|
({16{addr_src == ADDR_SRC_BUS_P }} & bus_p ) |
|
|
({16{addr_src == ADDR_SRC_BUS_Q }} & bus_q ) |
|
|
({16{addr_src == ADDR_SRC_OPERAND8 }} & { 8'hFF, instr[1] }) |
|
|
({16{addr_src == ADDR_SRC_OPERAND16}} & {instr[2], instr[1] });
|
|
|
|
assign we_o = instr_valid & (
|
|
(bus_x_ctrl.wen & bus_x_ctrl.dst == BUS_DST_MEM) |
|
|
(bus_y_ctrl.wen & bus_y_ctrl.dst == BUS_DST_MEM));
|
|
|
|
assign wdata_o = ({8{bus_x_ctrl.dst == BUS_DST_MEM}} & bus_x) |
|
|
({8{bus_y_ctrl.dst == BUS_DST_MEM}} & bus_y);
|
|
|
|
`define INST_BUS(x) \
|
|
assign bus_``x = ({8{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS_SRC_OPERAND8_H)}} & instr[2]) | \
|
|
({8{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS_SRC_OPERAND8_L)}} & instr[1]) | \
|
|
({8{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS_SRC_REG8 )}} & reg8_rdata) | \
|
|
({8{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS_SRC_A )}} & reg_a) | \
|
|
({8{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS_SRC_PC_H )}} & pc_r[15:8]) | \
|
|
({8{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS_SRC_PC_L )}} & pc_r[ 7:0]) | \
|
|
({8{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS_SRC_REG16_H )}} & reg16_rdata[15:8]) | \
|
|
({8{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS_SRC_REG16_L )}} & reg16_rdata[ 7:0]) | \
|
|
({8{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS_SRC_MEM )}} & rdata_i ) | \
|
|
({8{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS_SRC_ALU )}} & alu_operand_out);
|
|
|
|
`INST_BUS(x);
|
|
`INST_BUS(y);
|
|
|
|
`undef INST_BUS
|
|
|
|
`define INST_BUS16(x) \
|
|
assign bus_``x = ({16{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS16_SRC_REG16)}} & reg16_rdata) | \
|
|
({16{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS16_SRC_ALU16)}} & alu16_out ) | \
|
|
({16{bus_``x``_ctrl.wen & (bus_``x``_ctrl.src == BUS16_SRC_SP )}} & sp_r);
|
|
|
|
`INST_BUS16(p);
|
|
`INST_BUS16(q);
|
|
|
|
`undef INST_BUS16
|
|
|
|
endmodule : cpu |