+ `INSN_LD_SP_HL: begin
+ case (cycle)
+ 0: begin
+ tmp <= registers[`REG_H];
+ end
+ 1: begin
+ `EXEC_NEWCYCLE;
+ `EXEC_INC_PC;
+ tmp <= registers[`REG_L];
+ end
+ endcase
+ end
+ `INSN_PUSH_reg: begin /* PUSH is 16 cycles! */
+ case (cycle)
+ 0: begin
+ wr <= 1;
+ address <= {registers[`REG_SPH],registers[`REG_SPL]}-1;
+ case (opcode[5:4])
+ `INSN_stack_AF: wdata <= registers[`REG_A];
+ `INSN_stack_BC: wdata <= registers[`REG_B];
+ `INSN_stack_DE: wdata <= registers[`REG_D];
+ `INSN_stack_HL: wdata <= registers[`REG_H];
+ endcase
+ end
+ 1: begin
+ wr <= 1;
+ address <= {registers[`REG_SPH],registers[`REG_SPL]}-1;
+ case (opcode[5:4])
+ `INSN_stack_AF: wdata <= registers[`REG_F];
+ `INSN_stack_BC: wdata <= registers[`REG_C];
+ `INSN_stack_DE: wdata <= registers[`REG_E];
+ `INSN_stack_HL: wdata <= registers[`REG_L];
+ endcase
+ end
+ 2: begin /* Twiddle thumbs. */ end
+ 3: begin
+ `EXEC_NEWCYCLE;
+ `EXEC_INC_PC;
+ end
+ endcase
+ end
+ `INSN_POP_reg: begin /* POP is 12 cycles! */
+ case (cycle)
+ 0: begin
+ rd <= 1;
+ address <= {registers[`REG_SPH],registers[`REG_SPL]};
+ end
+ 1: begin
+ rd <= 1;
+ address <= {registers[`REG_SPH],registers[`REG_SPL]};
+ end
+ 2: begin
+ `EXEC_NEWCYCLE;
+ `EXEC_INC_PC;
+ end
+ endcase
+ end
+ `INSN_LDH_AC: begin
+ case (cycle)
+ 0: begin
+ address <= {8'hFF,registers[`REG_C]};
+ if (opcode[4]) begin // LD A,(C)
+ rd <= 1;
+ end else begin
+ wr <= 1;
+ wdata <= registers[`REG_A];
+ end
+ end
+ 1: begin
+ `EXEC_NEWCYCLE;
+ `EXEC_INC_PC;
+ end
+ endcase
+ end
+ `INSN_LDx_AHL: begin
+ case (cycle)
+ 0: begin
+ address <= {registers[`REG_H],registers[`REG_L]};
+ if (opcode[3]) begin // LDx A, (HL)
+ rd <= 1;
+ end else begin
+ wr <= 1;
+ wdata <= registers[`REG_A];
+ end
+ end
+ 1: begin
+ `EXEC_NEWCYCLE;
+ `EXEC_INC_PC;
+ end
+ endcase
+ end
+ `INSN_ALU8: begin
+ if ((opcode[2:0] == `INSN_reg_dHL) && (cycle == 0)) begin
+ // fffffffff fuck your shit, read from (HL) :(
+ rd <= 1;
+ address <= {registers[`REG_H], registers[`REG_L]};
+ end else begin
+ `EXEC_NEWCYCLE;
+ `EXEC_INC_PC;
+ case (opcode[2:0])
+ `INSN_reg_A: tmp <= registers[`REG_A];
+ `INSN_reg_B: tmp <= registers[`REG_B];
+ `INSN_reg_C: tmp <= registers[`REG_C];
+ `INSN_reg_D: tmp <= registers[`REG_D];
+ `INSN_reg_E: tmp <= registers[`REG_E];
+ `INSN_reg_H: tmp <= registers[`REG_H];
+ `INSN_reg_L: tmp <= registers[`REG_L];
+ `INSN_reg_dHL: tmp <= rdata;
+ endcase
+ end
+ end
+ `INSN_ALU_A: begin
+ `EXEC_NEWCYCLE;
+ `EXEC_INC_PC;
+ end
+ `INSN_NOP: begin
+ `EXEC_NEWCYCLE;
+ `EXEC_INC_PC;
+ end
+ `INSN_RST: begin
+ case (cycle)
+ 0: begin
+ `EXEC_INC_PC; // This goes FIRST in RST
+ end
+ 1: begin
+ wr <= 1;
+ address <= {registers[`REG_SPH],registers[`REG_SPL]}-1;
+ wdata <= registers[`REG_PCH];
+ end
+ 2: begin
+ wr <= 1;
+ address <= {registers[`REG_SPH],registers[`REG_SPL]}-2;
+ wdata <= registers[`REG_PCL];
+ end
+ 3: begin
+ `EXEC_NEWCYCLE;
+ {registers[`REG_PCH],registers[`REG_PCL]} <=
+ {10'b0,opcode[5:3],3'b0};
+ end
+ endcase
+ end
+ `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; // 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
+ 3: begin /* twiddle thumbs */ end
+ 4: begin
+ `EXEC_NEWCYCLE;
+ // do NOT increment PC!
+ end
+ endcase
+ end
+ `INSN_CALL,`INSN_CALLCC: begin
+ case (cycle)
+ 0: begin
+ `EXEC_INC_PC;
+ `EXEC_NEXTADDR_PCINC;
+ rd <= 1;
+ end
+ 1: begin
+ `EXEC_INC_PC;
+ `EXEC_NEXTADDR_PCINC;
+ rd <= 1;
+ end
+ 2: begin
+ `EXEC_INC_PC;
+ if (!opcode[0]) // i.e., is callcc
+ /* 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
+ 3: begin
+ address <= {registers[`REG_SPH],registers[`REG_SPL]} - 1;
+ wdata <= registers[`REG_PCH];
+ wr <= 1;
+ end
+ 4: begin
+ address <= {registers[`REG_SPH],registers[`REG_SPL]} - 2;
+ wdata <= registers[`REG_PCL];
+ wr <= 1;
+ end
+ 5: begin
+ `EXEC_NEWCYCLE; /* do NOT increment the PC */
+ end
+ endcase
+ end
+ `INSN_JP_imm,`INSN_JPCC_imm: begin
+ case (cycle)
+ 0: begin
+ `EXEC_INC_PC;
+ `EXEC_NEXTADDR_PCINC;
+ rd <= 1;
+ end
+ 1: begin
+ `EXEC_INC_PC;
+ `EXEC_NEXTADDR_PCINC;
+ rd <= 1;
+ end
+ 2: begin
+ `EXEC_INC_PC;
+ if (!opcode[0]) 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
+ 3: begin
+ `EXEC_NEWCYCLE;
+ end
+ endcase
+ end
+ `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;