X-Git-Url: http://git.joshuawise.com/fpgaboy.git/blobdiff_plain/6b4e28281b4fa98272bead1eedeea577e8778169..06ad3a30038ac8ca45dd7b0c34213c0c8335c17c:/GBZ80Core.v?ds=sidebyside diff --git a/GBZ80Core.v b/GBZ80Core.v index 0697295..96e4dcd 100644 --- a/GBZ80Core.v +++ b/GBZ80Core.v @@ -36,12 +36,16 @@ `define INSN_NOP 8'b00000000 `define INSN_RST 8'b11xxx111 `define INSN_RET 8'b110x1001 // 1 = RETI, 0 = RET +`define INSN_RETCC 8'b110xx000 `define INSN_CALL 8'b11001101 `define INSN_CALLCC 8'b110xx100 // Not that call/cc. `define INSN_JP_imm 8'b11000011 `define INSN_JPCC_imm 8'b110xx010 `define INSN_ALU_A 8'b00xxx111 `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_cc_NZ 2'b00 `define INSN_cc_Z 2'b01 @@ -398,18 +402,29 @@ 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 + 1: begin // SPECIAL CASE: cycle does NOT increase linearly with ret! + `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 + `INSN_cc_C: if (~registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end + endcase + rd <= 1; + address <= {registers[`REG_SPH],registers[`REG_SPL]}; + end + 2: begin rd <= 1; address <= {registers[`REG_SPH],registers[`REG_SPL]} + 1; end - 2: begin /* twiddle thumbs */ end - 3: begin + 3: begin /* twiddle thumbs */ end + 4: begin `EXEC_NEWCYCLE; // do NOT increment PC! end @@ -485,6 +500,58 @@ module GBZ80Core( `INSN_JP_HL: begin `EXEC_NEWCYCLE; end + `INSN_JR_imm,`INSN_JRCC_imm: begin + case (cycle) + 0: begin + `EXEC_INC_PC; + `EXEC_NEXTADDR_PCINC; + rd <= 1; + end + 1: begin + `EXEC_INC_PC; + if (opcode[5]) begin // i.e., JP cc,nn + /* We need to check the condition code to bail out. */ + 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 + `INSN_cc_C: if (~registers[`REG_F][4]) begin `EXEC_NEWCYCLE; end + endcase + end + end + 2: begin + `EXEC_NEWCYCLE; + 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 default: $stop; endcase @@ -752,15 +819,17 @@ module GBZ80Core( {registers[`REG_SPH],registers[`REG_SPL]}-2; endcase end - `INSN_RET: begin + `INSN_RET,`INSN_RETCC: begin case (cycle) - 0: begin /* type F */ end - 1: registers[`REG_PCL] <= rdata; - 2: registers[`REG_PCH] <= rdata; - 3: begin + 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; + 3: registers[`REG_PCH] <= rdata; + 4: begin {registers[`REG_SPH],registers[`REG_SPL]} <= {registers[`REG_SPH],registers[`REG_SPL]} + 2; - if (opcode[4]) /* RETI */ + if (opcode[4] && opcode[0]) /* RETI */ ie <= 1; end endcase @@ -792,6 +861,41 @@ module GBZ80Core( {registers[`REG_PCH],registers[`REG_PCL]} <= {registers[`REG_H],registers[`REG_L]}; end + `INSN_JR_imm,`INSN_JRCC_imm: begin + case (cycle) + 0: begin /* type F */ end + 1: tmp <= rdata; + 2: {registers[`REG_PCH],registers[`REG_PCL]} <= + {registers[`REG_PCH],registers[`REG_PCL]} + + {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 default: $stop; endcase