svgb/rtl/cpu/idec.sv
Koray Yanik fda176d3b5 Complete rewrite from scratch, bootstrap WIP
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.
2023-10-01 23:00:56 +01:00

348 lines
18 KiB
Systemverilog

`include "cpu_pkg.svh"
import cpu_pkg::*;
module idec (
input logic [7:0] instr_i[2:0],
input logic is_ex1_i,
input logic is_ex2_i,
input logic is_ex3_i,
output logic req_instr1_o,
output logic req_instr2_o,
output logic req_ex2_o,
output logic req_ex3_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,
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 logic pc_we_o,
output logic pc_we_cc_o,
output cc_t cc_o,
output pc_src_t pc_src_o,
output logic instr_undef_o
);
logic [1:0] dec_x;
logic [2:0] dec_y;
logic [2:0] dec_z;
logic [1:0] dec_p;
logic dec_q;
logic is_alu_a_r;
logic is_alu_a_n;
logic is_ld_sp_nnnn;
logic is_ld_rr_nnnn;
logic is_ld_pnnnn_a;
logic is_ldd_hl_a;
logic is_ldi_hl_a;
logic is_ldd_a_hl;
logic is_ldi_a_hl;
logic is_cb;
logic is_ld_r_r;
logic is_ld_r_n;
logic is_ldh_c_a;
logic is_ldh_n_a;
logic is_ldh_a_n;
logic is_ld_rr_a;
logic is_ld_a_pbc;
logic is_ld_a_pde;
logic is_ld_a_nn;
logic is_bit_n_r;
logic is_shift_r;
logic is_rla;
logic is_inc_r;
logic is_dec_r;
logic is_jr_cc_nn;
logic is_jr_nn;
logic is_call_nn;
logic is_ret;
logic is_push_rr;
logic is_pop_rr;
logic is_inc_rr;
logic is_dec_rr;
reg8_t reg8_src;
reg8_t reg8_dest;
reg16_t reg16_sel;
assign req_instr1_o = is_ld_sp_nnnn | is_ld_rr_nnnn | is_call_nn | is_ld_pnnnn_a | is_cb | is_jr_nn | is_jr_cc_nn | is_ld_r_n | is_ldh_n_a | is_ldh_a_n | is_alu_a_n;
assign req_instr2_o = is_ld_sp_nnnn | is_ld_rr_nnnn | is_call_nn | is_ld_pnnnn_a;
assign req_ex2_o = is_call_nn | is_ret | is_push_rr | is_pop_rr | ((is_ld_r_r | is_alu_a_r) & (reg8_src == REG8_PHL));
assign req_ex3_o = is_ret | is_pop_rr;
assign dec_x = instr_i[0][7:6];
assign dec_y = instr_i[0][5:3];
assign dec_z = instr_i[0][2:0];
assign dec_p = instr_i[0][5:4];
assign dec_q = instr_i[0][3];
assign is_jr_nn = instr_i[0] == 8'h18;
assign is_cb = instr_i[0] == 8'hCB;
assign is_call_nn = instr_i[0] == 8'hCD;
assign is_ret = instr_i[0] == 8'hC9;
assign is_ldh_c_a = instr_i[0] == 8'hE2;
assign is_ldh_n_a = instr_i[0] == 8'hE0;
assign is_ldh_a_n = instr_i[0] == 8'hF0;
assign is_ld_pnnnn_a = instr_i[0] == 8'hEA;
assign is_jr_cc_nn = (dec_x == 2'h0) & (dec_z == 2'h0) & dec_y[2];
assign is_ld_rr_nnnn = (dec_x == 2'h0) & (dec_z == 3'h1) & ~dec_q & (dec_p != 2'h3);
assign is_ld_sp_nnnn = (dec_x == 2'h0) & (dec_z == 3'h1) & ~dec_q & (dec_p == 2'h3);
assign is_ldi_hl_a = (dec_x == 2'h0) & (dec_z == 3'h2) & ~dec_q & (dec_p == 2'h2);
assign is_ldd_hl_a = (dec_x == 2'h0) & (dec_z == 3'h2) & ~dec_q & (dec_p == 2'h3);
assign is_ld_a_pbc = (dec_x == 2'h0) & (dec_z == 3'h2) & dec_q & (dec_p == 2'h0);
assign is_ld_a_pde = (dec_x == 2'h0) & (dec_z == 3'h2) & dec_q & (dec_p == 2'h1);
assign is_ldi_a_hl = (dec_x == 2'h0) & (dec_z == 3'h2) & dec_q & (dec_p == 2'h2);
assign is_ldd_a_hl = (dec_x == 2'h0) & (dec_z == 3'h2) & dec_q & (dec_p == 2'h3);
assign is_inc_rr = (dec_x == 2'h0) & (dec_z == 3'h3) & ~dec_q;
assign is_dec_rr = (dec_x == 2'h0) & (dec_z == 3'h3) & dec_q;
assign is_inc_r = (dec_x == 2'h0) & (dec_z == 3'h4);
assign is_dec_r = (dec_x == 2'h0) & (dec_z == 3'h5);
assign is_ld_r_n = (dec_x == 2'h0) & (dec_z == 3'h6);
assign is_ld_rr_a = '0;
assign is_rla = (dec_x == 3'h0) & (dec_z == 3'h7) & (dec_y == 3'h2);
assign is_ld_r_r = (dec_x == 2'h1) & ((dec_z != 3'h6) | (dec_y != 3'h6));
assign is_alu_a_r = (dec_x == 2'h2);
assign is_pop_rr = (dec_x == 2'h3) & (dec_z == 3'h1) & ~dec_q;
assign is_push_rr = (dec_x == 2'h3) & (dec_z == 3'h5) & ~dec_q;
assign is_alu_a_n = (dec_x == 2'h3) & (dec_z == 3'h6);
assign is_bit_n_r = (is_cb & instr_i[1][7:6] == 2'h1);
assign is_shift_r = (is_cb & instr_i[1][7:6] == 2'h0) | is_rla;
assign bus_x_ctrl_o.src = (is_ld_sp_nnnn ) ? BUS_SRC_OPERAND8_H :
(is_ld_rr_nnnn ) ? BUS_SRC_OPERAND8_H :
(is_ld_pnnnn_a ) ? BUS_SRC_A :
(is_ldd_hl_a ) ? BUS_SRC_A :
(is_ldi_hl_a ) ? BUS_SRC_A :
(is_ldh_c_a ) ? BUS_SRC_A :
(is_ldh_n_a ) ? BUS_SRC_A :
(is_ldh_a_n ) ? BUS_SRC_MEM :
(is_alu_a_r & (reg8_src == REG8_A )) ? BUS_SRC_A :
(is_alu_a_r & (reg8_src == REG8_PHL)) ? BUS_SRC_MEM :
(is_alu_a_r ) ? BUS_SRC_REG8 :
(is_alu_a_n ) ? BUS_SRC_OPERAND8_L :
(is_bit_n_r & (reg8_src == REG8_A )) ? BUS_SRC_A :
(is_bit_n_r & (reg8_src != REG8_A )) ? BUS_SRC_REG8 :
(is_ld_r_n ) ? BUS_SRC_OPERAND8_L :
(is_inc_r ) ? BUS_SRC_REG8 :
(is_dec_r ) ? BUS_SRC_REG8 :
(is_ld_r_r & (reg8_src == REG8_A )) ? BUS_SRC_A :
(is_ld_r_r & (reg8_src == REG8_PHL)) ? BUS_SRC_MEM :
(is_ld_r_r ) ? BUS_SRC_REG8 :
(is_ld_a_pbc ) ? BUS_SRC_MEM :
(is_ld_a_pde ) ? BUS_SRC_MEM :
(is_call_nn & ~is_ex2_i ) ? BUS_SRC_PC_L :
(is_call_nn & is_ex2_i ) ? BUS_SRC_PC_H :
(is_push_rr & ~is_ex2_i ) ? BUS_SRC_REG16_L :
(is_push_rr & is_ex2_i ) ? BUS_SRC_REG16_H :
(is_pop_rr ) ? BUS_SRC_MEM :
(is_ret ) ? BUS_SRC_MEM :
(is_shift_r & (reg8_src == REG8_A )) ? BUS_SRC_A :
(is_shift_r & (reg8_src != REG8_A )) ? BUS_SRC_REG8 :
BUS_SRC_MEM;
assign bus_x_ctrl_o.dst = is_ld_sp_nnnn ? BUS_DST_SP_H :
is_ld_rr_nnnn ? BUS_DST_REG16_H :
is_ld_pnnnn_a ? BUS_DST_MEM :
is_ldd_hl_a ? BUS_DST_MEM :
is_ldi_hl_a ? BUS_DST_MEM :
is_ldh_c_a ? BUS_DST_MEM :
is_ldh_n_a ? BUS_DST_MEM :
is_ldh_a_n ? BUS_DST_ALU :
is_alu_a_r ? BUS_DST_ALU :
is_alu_a_n ? BUS_DST_ALU :
is_bit_n_r ? BUS_DST_ALU :
is_inc_r ? BUS_DST_ALU :
is_dec_r ? BUS_DST_ALU :
is_ld_a_pbc ? BUS_DST_ALU :
is_ld_a_pde ? BUS_DST_ALU :
is_call_nn ? BUS_DST_MEM :
is_push_rr ? BUS_DST_MEM :
is_pop_rr & is_ex2_i ? BUS_DST_REG16_H :
is_pop_rr & is_ex3_i ? BUS_DST_REG16_L :
is_ret & is_ex2_i ? BUS_DST_PC_H :
is_ret & is_ex3_i ? BUS_DST_PC_L :
(is_ld_r_n & (reg8_dest == REG8_A )) ? BUS_DST_ALU :
(is_ld_r_n & (reg8_dest != REG8_A )) ? BUS_DST_REG8 :
(is_ld_r_r & (reg8_dest == REG8_A )) ? BUS_DST_ALU :
(is_ld_r_r & (reg8_dest == REG8_PHL)) ? BUS_DST_MEM :
(is_ld_r_r ) ? BUS_DST_REG8 :
(is_shift_r ) ? BUS_DST_ALU :
BUS_DST_SP_H;
assign bus_x_ctrl_o.wen =
is_ld_sp_nnnn | is_ld_rr_nnnn | is_alu_a_n | is_ldd_hl_a |
is_ldi_hl_a | is_bit_n_r | is_ld_r_n | is_ldh_c_a | is_ldh_n_a | is_ldh_a_n |
is_call_nn | is_ret | is_push_rr | (is_pop_rr & (is_ex2_i | is_ex3_i)) |
(is_ret & (is_ex2_i | is_ex3_i)) | is_shift_r | is_inc_r | is_dec_r | is_ld_pnnnn_a |
(is_ld_r_r & (reg8_src != REG8_PHL)) |
(is_ld_r_r & (reg8_src == REG8_PHL) & is_ex2_i) |
(is_alu_a_r & (reg8_src != REG8_PHL)) |
(is_alu_a_r & (reg8_src == REG8_PHL) & is_ex2_i);
assign bus_y_ctrl_o.src = is_ld_sp_nnnn ? BUS_SRC_OPERAND8_L :
is_ld_rr_nnnn ? BUS_SRC_OPERAND8_L :
is_inc_r ? BUS_SRC_ALU :
is_dec_r ? BUS_SRC_ALU :
is_shift_r ? BUS_SRC_ALU :
is_pop_rr & is_ex2_i ? BUS_SRC_REG16_L :
is_pop_rr & is_ex3_i ? BUS_SRC_REG16_H :
is_ret & is_ex2_i ? BUS_SRC_PC_L :
is_ret & is_ex3_i ? BUS_SRC_PC_H :
BUS_SRC_MEM;
assign bus_y_ctrl_o.dst = is_ld_sp_nnnn ? BUS_DST_SP_L :
is_ld_rr_nnnn ? BUS_DST_REG16_L :
is_inc_r ? BUS_DST_REG8 :
is_dec_r ? BUS_DST_REG8 :
is_shift_r ? BUS_DST_REG8 :
is_pop_rr & is_ex2_i ? BUS_DST_REG16_L :
is_pop_rr & is_ex3_i ? BUS_DST_REG16_H :
is_ret & is_ex2_i ? BUS_DST_PC_L :
is_ret & is_ex3_i ? BUS_DST_PC_H :
BUS_DST_REG8;
assign bus_y_ctrl_o.wen = is_ld_sp_nnnn | is_ld_rr_nnnn | (is_inc_r & reg8_dest != REG8_A) | (is_shift_r & reg8_dest != REG8_A) | (is_dec_r & reg8_dest != REG8_A) | (is_pop_rr & (is_ex2_i | is_ex3_i)) | (is_ret & (is_ex2_i | is_ex3_i));
assign bus_p_ctrl_o.src = is_ldd_hl_a ? BUS16_SRC_REG16 :
is_ldi_hl_a ? BUS16_SRC_REG16 :
is_call_nn ? BUS16_SRC_SP :
is_ret ? BUS16_SRC_SP :
is_push_rr ? BUS16_SRC_SP :
is_pop_rr ? BUS16_SRC_SP :
is_inc_rr & (reg16_sel == REG16_SP_AF) ? BUS16_SRC_SP :
is_inc_rr & (reg16_sel != REG16_SP_AF) ? BUS16_SRC_REG16 :
is_dec_rr & (reg16_sel == REG16_SP_AF) ? BUS16_SRC_SP :
is_dec_rr & (reg16_sel != REG16_SP_AF) ? BUS16_SRC_REG16 :
BUS16_SRC_REG16;
assign bus_p_ctrl_o.dst = BUS16_DST_ALU16;
assign bus_p_ctrl_o.wen = is_ldd_hl_a | is_ldi_hl_a | is_call_nn | is_ret | is_push_rr | is_pop_rr | is_inc_rr | is_dec_rr;
assign bus_q_ctrl_o.src = BUS16_SRC_ALU16;
assign bus_q_ctrl_o.dst = is_ldd_hl_a ? BUS16_DST_REG16 :
is_ldi_hl_a ? BUS16_DST_REG16 :
is_call_nn ? BUS16_DST_SP :
is_ret ? BUS16_DST_SP :
is_push_rr ? BUS16_DST_SP :
is_pop_rr ? BUS16_DST_SP :
is_inc_rr & (reg16_sel == REG16_SP_AF) ? BUS16_DST_SP :
is_inc_rr & (reg16_sel != REG16_SP_AF) ? BUS16_DST_REG16 :
is_dec_rr & (reg16_sel == REG16_SP_AF) ? BUS16_DST_SP :
is_dec_rr & (reg16_sel != REG16_SP_AF) ? BUS16_DST_REG16 :
BUS16_DST_REG16;
assign bus_q_ctrl_o.wen = is_ldd_hl_a | is_ldi_hl_a | is_call_nn | (is_ret & (is_ex1_i | is_ex2_i)) | is_push_rr | (is_pop_rr & (is_ex1_i | is_ex2_i)) | is_inc_rr | is_dec_rr;
assign reg8_src = is_ldh_c_a ? REG8_C :
is_rla ? REG8_A :
is_inc_r ? reg8_dest :
is_dec_r ? reg8_dest :
is_cb ? reg8_t'(instr_i[1][2:0]) :
reg8_t'(dec_z);
assign reg8_dest = is_rla ? REG8_A :
is_cb ? reg8_t'(instr_i[1][2:0]) :
reg8_t'(dec_y);
assign reg16_sel = is_ldd_hl_a ? REG16_HL :
is_ldi_hl_a ? REG16_HL :
is_ld_r_r & ((reg8_src == REG8_PHL) | (reg8_dest == REG8_PHL)) ? REG16_HL :
is_alu_a_r & (reg8_src == REG8_PHL) ? REG16_HL :
is_ld_a_pbc ? REG16_BC :
is_ld_a_pde ? REG16_DE :
reg16_t'(dec_p);
assign reg8_src_o = reg8_src;
assign reg8_dest_o = reg8_dest;
assign reg16_sel_o = reg16_sel;
assign alu_ctrl_o.alu_op_valid =
is_alu_a_n |
(is_alu_a_r & (reg8_src != REG8_PHL)) |
(is_alu_a_r & (reg8_src == REG8_PHL) & is_ex2_i);
assign alu_ctrl_o.alu_op = alu_op_t'(dec_y);
assign alu_ctrl_o.shift_op_valid = is_shift_r;
assign alu_ctrl_o.shift_op = is_rla ? SHIFT_OP_RL :
shift_op_t'(instr_i[1][5:3]);
assign alu_ctrl_o.bsr_op_valid = is_bit_n_r;
assign alu_ctrl_o.bsr_op.b = is_bit_n_r;
assign alu_ctrl_o.bsr_op.s = '0;
assign alu_ctrl_o.bsr_op.r = '0;
assign alu_ctrl_o.bsr_op.operand = instr_i[1][5:3];
assign alu_ctrl_o.incdec_op_valid = is_inc_r | is_dec_r;
assign alu_ctrl_o.incdec_op.inc = is_inc_r;
assign alu_ctrl_o.incdec_op.dec = is_dec_r;
assign alu_ctrl_o.incdec_op.dst_a = reg8_dest == REG8_A;
assign alu_ctrl_o.update_a =
is_alu_a_n |
(is_alu_a_r & (reg8_src != REG8_PHL)) |
(is_alu_a_r & (reg8_src == REG8_PHL) & is_ex2_i) |
(is_ld_r_n & (reg8_dest == REG8_A)) | (is_ld_r_r & (reg8_dest == REG8_A)) |
(is_inc_r & (reg8_dest == REG8_A)) | (is_dec_r & (reg8_dest == REG8_A)) |
is_ld_a_pbc | is_ld_a_pde | (is_shift_r & (reg8_dest == REG8_A)) |
is_ldh_a_n;
assign alu_ctrl_o.update_f = is_alu_a_n | is_bit_n_r | is_inc_r | is_dec_r | is_shift_r |
(is_alu_a_r & (reg8_src != REG8_PHL)) |
(is_alu_a_r & (reg8_src == REG8_PHL) & is_ex2_i);
assign alu16_inc_o = is_ldi_hl_a | is_ret | is_pop_rr | is_inc_rr;
assign alu16_dec_o = is_ldd_hl_a | is_call_nn | is_push_rr | is_dec_rr;
assign pc_we_o = is_call_nn | (is_ret & (is_ex2_i | is_ex3_i)) | is_jr_nn;
assign pc_we_cc_o = is_jr_cc_nn;
assign cc_o = cc_t'(dec_y[1:0]);
assign pc_src_o = is_ret ? PC_SRC_BUS :
is_call_nn ? PC_SRC_OPERAND16 :
PC_SRC_OPERAND8;
assign addr_src_o = is_ldd_hl_a ? ADDR_SRC_REG16 :
is_ldi_hl_a ? ADDR_SRC_REG16 :
is_ld_a_pbc ? ADDR_SRC_REG16 :
is_ld_a_pde ? ADDR_SRC_REG16 :
is_ldh_c_a ? ADDR_SRC_REG8 :
is_ldh_n_a ? ADDR_SRC_OPERAND8 :
is_ldh_a_n ? ADDR_SRC_OPERAND8 :
is_call_nn ? ADDR_SRC_SP :
is_ret & is_ex3_i ? ADDR_SRC_BUS_P :
is_ret ? ADDR_SRC_BUS_Q :
is_push_rr ? ADDR_SRC_SP :
is_pop_rr & is_ex3_i ? ADDR_SRC_BUS_P :
is_pop_rr ? ADDR_SRC_BUS_Q :
is_ld_r_r & ((reg8_src == REG8_PHL) | (reg8_dest == REG8_PHL)) ? ADDR_SRC_REG16 :
is_alu_a_r & (reg8_src == REG8_PHL) ? ADDR_SRC_REG16 :
is_ld_pnnnn_a ? ADDR_SRC_OPERAND16:
ADDR_SRC_PC;
assign instr_undef_o = ~(
is_ld_sp_nnnn | is_alu_a_r | is_alu_a_n | is_ld_rr_nnnn | is_ldd_hl_a | is_ldi_hl_a |
is_bit_n_r | is_jr_nn | is_jr_cc_nn | is_ld_r_n | is_ldh_c_a | is_inc_r | is_dec_r | is_ld_r_r |
is_ldh_n_a | is_ldh_a_n | is_ld_a_pbc | is_ld_a_pde | is_call_nn | is_push_rr | is_pop_rr |
(is_shift_r & (instr_i[1][5:3] == 3'h02)) | is_rla | is_inc_rr | is_dec_rr | is_ret |
is_ld_pnnnn_a);
endmodule : idec