X-Git-Url: http://git.joshuawise.com/fpgaboy.git/blobdiff_plain/611e4a90d4f4c5b5e2cadde0da57639bfbaca6a8..318331120b0bd48a06902e70a63b4f536a85de5f:/GBZ80Core.v diff --git a/GBZ80Core.v b/GBZ80Core.v index cd7f4d1..57c22d2 100644 --- a/GBZ80Core.v +++ b/GBZ80Core.v @@ -45,6 +45,10 @@ `define INSN_JP_HL 8'b11101001 `define INSN_JR_imm 8'b00011000 `define INSN_JRCC_imm 8'b001xx000 +`define INSN_INCDEC16 8'b00xxx011 +`define INSN_VOP_INTR 8'b11111100 // 0xFC is grabbed by the fetch if there is an interrupt pending. +`define INSN_DI 8'b11110011 +`define INSN_EI 8'b11111011 `define INSN_cc_NZ 2'b00 `define INSN_cc_Z 2'b01 @@ -86,9 +90,10 @@ module GBZ80Core( input clk, - output reg [15:0] busaddress, /* BUS_* is latched on STATE_FETCH. */ + output reg [15:0] busaddress = 0, /* BUS_* is latched on STATE_FETCH. */ inout [7:0] busdata, - output reg buswr, output reg busrd); + output reg buswr = 0, output reg busrd = 0, + input irq, input [7:0] jaddr); reg [1:0] state = 0; /* State within this bus cycle (see STATE_*). */ reg [2:0] cycle = 0; /* Cycle for instructions. */ @@ -107,7 +112,7 @@ module GBZ80Core( reg [7:0] buswdata; assign busdata = buswr ? buswdata : 8'bzzzzzzzz; - reg ie = 0; + reg ie = 0, iedelay = 0; initial begin registers[ 0] <= 0; @@ -128,6 +133,10 @@ module GBZ80Core( newcycle <= 1; state <= 0; cycle <= 0; + busrd <= 0; + buswr <= 0; + busaddress <= 0; + iedelay <= 0; end always @(posedge clk) @@ -148,7 +157,10 @@ module GBZ80Core( end `STATE_DECODE: begin if (newcycle) begin - opcode <= busdata; + if (ie && irq) + opcode <= `INSN_VOP_INTR; + else + opcode <= busdata; rdata <= busdata; newcycle <= 0; cycle <= 0; @@ -156,6 +168,10 @@ module GBZ80Core( if (rd) rdata <= busdata; cycle <= cycle + 1; end + if (iedelay) begin + ie <= 1; + iedelay <= 0; + end buswr <= 0; busrd <= 0; wr <= 0; @@ -401,17 +417,15 @@ module GBZ80Core( end endcase end - `INSN_RET: begin + `INSN_RET,`INSN_RETCC: begin case (cycle) 0: begin rd <= 1; address <= {registers[`REG_SPH],registers[`REG_SPL]}; end 1: begin // SPECIAL CASE: cycle does NOT increase linearly with ret! - `EXEC_INC_PC; - if (opcode != `INSN_RETCC) - $stop; - case (opcode[4:3]) // cycle 1 is skipped if we are not retcc + `EXEC_INC_PC; // cycle 1 is skipped if we are not retcc + case (opcode[4:3]) `INSN_cc_NZ: if (registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end `INSN_cc_Z: if (~registers[`REG_F][7]) begin `EXEC_NEWCYCLE; end `INSN_cc_NC: if (registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end @@ -525,6 +539,59 @@ module GBZ80Core( end endcase end + `INSN_INCDEC16: begin + case (cycle) + 0: begin + case (opcode[5:4]) + `INSN_reg16_BC: begin + tmp <= registers[`REG_B]; + tmp2 <= registers[`REG_C]; + end + `INSN_reg16_DE: begin + tmp <= registers[`REG_D]; + tmp2 <= registers[`REG_E]; + end + `INSN_reg16_HL: begin + tmp <= registers[`REG_H]; + tmp2 <= registers[`REG_L]; + end + `INSN_reg16_SP: begin + tmp <= registers[`REG_SPH]; + tmp2 <= registers[`REG_SPL]; + end + endcase + end + 1: begin + `EXEC_INC_PC; + `EXEC_NEWCYCLE; + end + endcase + end + `INSN_VOP_INTR: begin + case (cycle) + 0: begin + address <= {registers[`REG_SPH],registers[`REG_SPL]} - 1; + wdata <= registers[`REG_PCH]; + wr <= 1; + end + 1: begin + address <= {registers[`REG_SPH],registers[`REG_SPL]} - 2; + wdata <= registers[`REG_PCL]; + wr <= 1; + end + 2: begin + `EXEC_NEWCYCLE; + end + endcase + end + `INSN_DI: begin + `EXEC_NEWCYCLE; + `EXEC_INC_PC; + end + `INSN_EI: begin + `EXEC_NEWCYCLE; + `EXEC_INC_PC; + end default: $stop; endcase @@ -794,7 +861,7 @@ module GBZ80Core( end `INSN_RET,`INSN_RETCC: begin case (cycle) - 0: if (opcode != `INSN_RETCC) + 0: if (opcode[0]) // i.e., not RETCC cycle <= 1; // Skip cycle 1; it gets incremented on the next round. 1: begin /* Nothing need happen here. */ end 2: registers[`REG_PCL] <= rdata; @@ -802,7 +869,7 @@ module GBZ80Core( 4: begin {registers[`REG_SPH],registers[`REG_SPL]} <= {registers[`REG_SPH],registers[`REG_SPL]} + 2; - if (opcode[4] && (opcode != `INSN_RETCC)) /* RETI */ + if (opcode[4] && opcode[0]) /* RETI */ ie <= 1; end endcase @@ -843,6 +910,46 @@ module GBZ80Core( {tmp[7]?8'hFF:8'h00,tmp}; endcase end + `INSN_INCDEC16: begin + case (cycle) + 0: {tmp,tmp2} <= {tmp,tmp2} + + (opcode[3] ? 16'hFFFF : 16'h0001); + 1: begin + case (opcode[5:4]) + `INSN_reg16_BC: begin + registers[`REG_B] <= tmp; + registers[`REG_C] <= tmp2; + end + `INSN_reg16_DE: begin + registers[`REG_D] <= tmp; + registers[`REG_E] <= tmp2; + end + `INSN_reg16_HL: begin + registers[`REG_H] <= tmp; + registers[`REG_L] <= tmp2; + end + `INSN_reg16_SP: begin + registers[`REG_SPH] <= tmp; + registers[`REG_SPL] <= tmp2; + end + endcase + end + endcase + end + `INSN_VOP_INTR: begin + case (cycle) + 0: begin end + 1: {registers[`REG_SPH],registers[`REG_SPL]} + <= {registers[`REG_SPH],registers[`REG_SPL]} - 2; + 2: begin + ie <= 0; + {registers[`REG_PCH],registers[`REG_PCL]} <= + {8'b0,jaddr}; + end + endcase + end + `INSN_DI: ie <= 0; + `INSN_EI: iedelay <= 1; default: $stop; endcase