Implement LD ($FF00+C), A
This commit is contained in:
parent
b1b2055db9
commit
49ce1631b3
@ -35,6 +35,7 @@ module control (
|
|||||||
);
|
);
|
||||||
|
|
||||||
logic nreset_r;
|
logic nreset_r;
|
||||||
|
logic halted_r;
|
||||||
|
|
||||||
logic state_we;
|
logic state_we;
|
||||||
state_t state_r;
|
state_t state_r;
|
||||||
@ -89,6 +90,13 @@ module control (
|
|||||||
nreset_r <= nreset_i;
|
nreset_r <= nreset_i;
|
||||||
end
|
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(state_r, state_next, state_we, ST0_ADDR);
|
||||||
`DEF_FF(pc_r, pc_next, pc_we, '0);
|
`DEF_FF(pc_r, pc_next, pc_we, '0);
|
||||||
`DEF_FF(sp_r, sp_next, sp_we, '0);
|
`DEF_FF(sp_r, sp_next, sp_we, '0);
|
||||||
@ -97,7 +105,7 @@ module control (
|
|||||||
`DEF_FF(operand0_r, operand0_next, operand0_we, '0);
|
`DEF_FF(operand0_r, operand0_next, operand0_we, '0);
|
||||||
`DEF_FF(operand1_r, operand1_next, operand1_we, '0);
|
`DEF_FF(operand1_r, operand1_next, operand1_we, '0);
|
||||||
|
|
||||||
assign pc_we = (nreset_r & pc_incr & ~is_undef) | branch_taken;
|
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}) :
|
assign pc_next = (branch_taken & pc_src == PC_SRC_OPERAND8) ? (pc_r + {{8{operand0_r[7]}}, operand0_r}) :
|
||||||
(pc_r + 16'b1);
|
(pc_r + 16'b1);
|
||||||
|
|
||||||
@ -115,7 +123,7 @@ module control (
|
|||||||
assign operand1_we = (state_r == ST3_DEC);
|
assign operand1_we = (state_r == ST3_DEC);
|
||||||
assign operand1_next = rdata_i;
|
assign operand1_next = rdata_i;
|
||||||
|
|
||||||
assign state_we = nreset_r & ~is_undef;
|
assign state_we = nreset_r & ~is_undef & ~halted_r;
|
||||||
always_comb begin
|
always_comb begin
|
||||||
case (state_r)
|
case (state_r)
|
||||||
ST0_ADDR: state_next = ST1_DEC;
|
ST0_ADDR: state_next = ST1_DEC;
|
||||||
|
@ -120,8 +120,9 @@ module cpu (
|
|||||||
assign reg16_wdata = (op_src == OP_SRC_OPERAND16) ? operand16 : alu_out16;
|
assign reg16_wdata = (op_src == OP_SRC_OPERAND16) ? operand16 : alu_out16;
|
||||||
assign reg16_rselect2 = reg16_wselect;
|
assign reg16_rselect2 = reg16_wselect;
|
||||||
|
|
||||||
assign address_o = (adr_src == ADR_SRC_HL) ? hl :
|
assign address_o = (adr_src == ADR_SRC_HL) ? hl :
|
||||||
pc;
|
(adr_src == ADR_SRC_REG8) ? {8'hFF, reg8_rdata} :
|
||||||
|
pc;
|
||||||
assign wdata_o = (op_dest == OP_DEST_MEMORY) ? alu_operand :
|
assign wdata_o = (op_dest == OP_DEST_MEMORY) ? alu_operand :
|
||||||
rega; // ldi/ldd hl, a use the normal control paths for HL
|
rega; // ldi/ldd hl, a use the normal control paths for HL
|
||||||
|
|
||||||
|
@ -79,7 +79,8 @@ package cpu_pkg;
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ADR_SRC_PC,
|
ADR_SRC_PC,
|
||||||
ADR_SRC_HL
|
ADR_SRC_HL,
|
||||||
|
ADR_SRC_REG8 // extended with FF
|
||||||
} adr_src_t;
|
} adr_src_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -43,6 +43,7 @@ module decode (
|
|||||||
logic is_cb;
|
logic is_cb;
|
||||||
logic is_ld_a_nn;
|
logic is_ld_a_nn;
|
||||||
logic is_ld_r_nn;
|
logic is_ld_r_nn;
|
||||||
|
logic is_ldh_c_a;
|
||||||
logic is_ld_rr_nnnn;
|
logic is_ld_rr_nnnn;
|
||||||
logic is_ld_sp_nnnn;
|
logic is_ld_sp_nnnn;
|
||||||
logic is_ldd_hl_a;
|
logic is_ldd_hl_a;
|
||||||
@ -66,20 +67,22 @@ module decode (
|
|||||||
assign is_ld_rr_nnnn = (dec_x == 2'h0) & (dec_z == 3'h1) & ~dec_q & (dec_p != 2'h3);
|
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_ld_sp_nnnn = (dec_x == 2'h0) & (dec_z == 3'h1) & ~dec_q & (dec_p == 2'h3);
|
||||||
assign is_ldd_hl_a = (dec_x == 2'h0) & (dec_z == 3'h2) & ~dec_q & (dec_p == 2'h3);
|
assign is_ldd_hl_a = (dec_x == 2'h0) & (dec_z == 3'h2) & ~dec_q & (dec_p == 2'h3);
|
||||||
|
assign is_ldh_c_a = instr0_i == 8'hE2;
|
||||||
|
|
||||||
assign is_alu_a_r = (dec_x == 3'h2);
|
assign is_alu_a_r = (dec_x == 3'h2);
|
||||||
assign is_bit_n_r = (is_cb & instr1_i[7:6] == 2'h1);
|
assign is_bit_n_r = (is_cb & instr1_i[7:6] == 2'h1);
|
||||||
|
|
||||||
assign is_jr_cc_n = (dec_x == 2'h0) & (dec_z == 2'h0) & dec_y[2];
|
assign is_jr_cc_n = (dec_x == 2'h0) & (dec_z == 2'h0) & dec_y[2];
|
||||||
|
|
||||||
assign reg8_src = is_cb ? reg8_t'(instr1_i[2:0]) :
|
assign reg8_src = is_cb ? reg8_t'(instr1_i[2:0]) :
|
||||||
reg8_t'(dec_z);
|
is_ldh_c_a ? REG8_C :
|
||||||
|
reg8_t'(dec_z);
|
||||||
assign reg8_dest = reg8_t'(dec_y);
|
assign reg8_dest = reg8_t'(dec_y);
|
||||||
|
|
||||||
assign need_instr1_o = is_ld_sp_nnnn | is_ld_rr_nnnn | is_cb | is_jr_cc_n | is_ld_r_nn;
|
assign need_instr1_o = is_ld_sp_nnnn | is_ld_rr_nnnn | is_cb | is_jr_cc_n | is_ld_r_nn;
|
||||||
assign need_instr2_o = is_ld_sp_nnnn | is_ld_rr_nnnn;
|
assign need_instr2_o = is_ld_sp_nnnn | is_ld_rr_nnnn;
|
||||||
|
|
||||||
assign undef_o = ~(is_ld_sp_nnnn | is_ld_rr_nnnn | is_alu_a_r | is_ldd_hl_a | is_bit_n_r | is_jr_cc_n | is_ld_r_nn);
|
assign undef_o = ~(is_ld_sp_nnnn | is_ld_rr_nnnn | is_alu_a_r | is_ldd_hl_a | is_bit_n_r | is_jr_cc_n | is_ld_r_nn | is_ldh_c_a);
|
||||||
|
|
||||||
assign sp_we_o = is_ld_sp_nnnn & (state_i == ST4_EXEC);
|
assign sp_we_o = is_ld_sp_nnnn & (state_i == ST4_EXEC);
|
||||||
|
|
||||||
@ -91,6 +94,7 @@ module decode (
|
|||||||
assign op_dest_o = (is_ld_r_nn & reg8_dest == REG8_PHL) ? OP_DEST_MEMORY :
|
assign op_dest_o = (is_ld_r_nn & reg8_dest == REG8_PHL) ? OP_DEST_MEMORY :
|
||||||
is_ld_a_nn ? OP_DEST_A :
|
is_ld_a_nn ? OP_DEST_A :
|
||||||
is_ld_r_nn ? OP_DEST_REG8 :
|
is_ld_r_nn ? OP_DEST_REG8 :
|
||||||
|
is_ldh_c_a ? OP_DEST_MEMORY :
|
||||||
is_ld_rr_nnnn ? OP_DEST_REG16 :
|
is_ld_rr_nnnn ? OP_DEST_REG16 :
|
||||||
is_ldd_hl_a ? OP_DEST_REG16 :
|
is_ldd_hl_a ? OP_DEST_REG16 :
|
||||||
op_dest_t'('X);
|
op_dest_t'('X);
|
||||||
@ -98,6 +102,7 @@ module decode (
|
|||||||
assign op_src_o = (is_alu_a_r & reg8_src == REG8_A) ? OP_SRC_A :
|
assign op_src_o = (is_alu_a_r & reg8_src == REG8_A) ? OP_SRC_A :
|
||||||
(is_alu_a_r & reg8_src != REG8_A) ? OP_SRC_REG8 :
|
(is_alu_a_r & reg8_src != REG8_A) ? OP_SRC_REG8 :
|
||||||
is_ld_r_nn ? OP_SRC_OPERAND8 :
|
is_ld_r_nn ? OP_SRC_OPERAND8 :
|
||||||
|
is_ldh_c_a ? OP_SRC_A :
|
||||||
is_ld_rr_nnnn ? OP_SRC_OPERAND16 :
|
is_ld_rr_nnnn ? OP_SRC_OPERAND16 :
|
||||||
is_ldd_hl_a ? OP_SRC_REG16 :
|
is_ldd_hl_a ? OP_SRC_REG16 :
|
||||||
is_bit_n_r ? OP_SRC_REG8 :
|
is_bit_n_r ? OP_SRC_REG8 :
|
||||||
@ -111,12 +116,13 @@ module decode (
|
|||||||
assign pc_src_o = is_jr_cc_n ? PC_SRC_OPERAND8 :
|
assign pc_src_o = is_jr_cc_n ? PC_SRC_OPERAND8 :
|
||||||
PC_SRC_SEQ;
|
PC_SRC_SEQ;
|
||||||
|
|
||||||
assign adr_src_o = is_ldd_hl_a ? ADR_SRC_HL :
|
assign adr_src_o = is_ldd_hl_a ? ADR_SRC_HL :
|
||||||
(is_ld_r_nn & reg8_dest == REG8_PHL) ? ADR_SRC_HL :
|
(is_ld_r_nn & reg8_dest == REG8_PHL) ? ADR_SRC_HL :
|
||||||
|
is_ldh_c_a ? ADR_SRC_REG8 :
|
||||||
ADR_SRC_PC;
|
ADR_SRC_PC;
|
||||||
|
|
||||||
assign cc_o = cc_t'(dec_y[1:0]);
|
assign cc_o = cc_t'(dec_y[1:0]);
|
||||||
|
|
||||||
assign memory_we_o = is_ldd_hl_a | (is_ld_r_nn & reg8_dest == REG8_PHL);
|
assign memory_we_o = is_ldd_hl_a | is_ldh_c_a | (is_ld_r_nn & reg8_dest == REG8_PHL);
|
||||||
|
|
||||||
endmodule : decode
|
endmodule : decode
|
||||||
|
@ -3,14 +3,18 @@ module gb (
|
|||||||
input logic nreset_i
|
input logic nreset_i
|
||||||
);
|
);
|
||||||
|
|
||||||
|
logic we;
|
||||||
logic [15:0] address;
|
logic [15:0] address;
|
||||||
logic [ 7:0] rdata;
|
logic [ 7:0] rdata;
|
||||||
|
logic [ 7:0] wdata;
|
||||||
|
|
||||||
cpu cpu_inst (
|
cpu cpu_inst (
|
||||||
.clk_i (clk_i),
|
.clk_i (clk_i),
|
||||||
.nreset_i (nreset_i),
|
.nreset_i (nreset_i),
|
||||||
.address_o(address),
|
.address_o(address),
|
||||||
.rdata_i (rdata)
|
.rdata_i (rdata),
|
||||||
|
.we_o (we),
|
||||||
|
.wdata_o (wdata)
|
||||||
);
|
);
|
||||||
|
|
||||||
rom #(
|
rom #(
|
||||||
|
@ -15,18 +15,31 @@ module tb_top ();
|
|||||||
|
|
||||||
// Testbench code
|
// Testbench code
|
||||||
logic instr_undef;
|
logic instr_undef;
|
||||||
|
logic halted;
|
||||||
logic [15:0] last_pc;
|
logic [15:0] last_pc;
|
||||||
logic [ 7:0] last_opcode;
|
logic [ 7:0] last_opcode;
|
||||||
|
|
||||||
|
logic we;
|
||||||
|
logic [15:0] address;
|
||||||
|
logic [ 7:0] wdata;
|
||||||
|
|
||||||
|
assign halted = gb_inst.cpu_inst.control_inst.halted_r;
|
||||||
assign instr_undef = gb_inst.cpu_inst.control_inst.is_undef;
|
assign instr_undef = gb_inst.cpu_inst.control_inst.is_undef;
|
||||||
assign last_pc = gb_inst.cpu_inst.control_inst.instr_pc_r;
|
assign last_pc = gb_inst.cpu_inst.control_inst.instr_pc_r;
|
||||||
assign last_opcode = gb_inst.cpu_inst.control_inst.instr_r;
|
assign last_opcode = gb_inst.cpu_inst.control_inst.instr_r;
|
||||||
|
|
||||||
|
assign we = gb_inst.we;
|
||||||
|
assign address = gb_inst.address;
|
||||||
|
assign wdata = gb_inst.wdata;
|
||||||
|
|
||||||
always @(posedge clk) begin
|
always @(posedge clk) begin
|
||||||
if (nreset && instr_undef) begin
|
if (nreset && instr_undef & ~halted) begin
|
||||||
$info($sformatf("[%t] %X: Undefined opcode %X", $time(), last_pc, last_opcode));
|
$display($sformatf("[%t] %X: Undefined opcode %X", $time(), last_pc, last_opcode));
|
||||||
$fatal(0);
|
$fatal(0);
|
||||||
end
|
end
|
||||||
|
if (nreset && we) begin
|
||||||
|
$display($sformatf("[%t] Write: [%X] <= %X", $time(), address, wdata));
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
endmodule : tb_top
|
endmodule : tb_top
|
||||||
|
Loading…
Reference in New Issue
Block a user