14 `define FLAG_Z 8'b10000000
 
  15 `define FLAG_N 8'b01000000
 
  16 `define FLAG_H 8'b00100000
 
  17 `define FLAG_C 8'b00010000
 
  19 `define STATE_FETCH                     2'h0
 
  20 `define STATE_DECODE                    2'h1
 
  21 `define STATE_EXECUTE           2'h2
 
  22 `define STATE_WRITEBACK         2'h3
 
  24 `define INSN_LD_reg_imm8        8'b00xxx110
 
  25 `define INSN_HALT                               8'b01110110
 
  26 `define INSN_LD_HL_reg          8'b01110xxx
 
  27 `define INSN_LD_reg_HL          8'b01xxx110
 
  28 `define INSN_LD_reg_reg         8'b01xxxxxx
 
  29 `define INSN_LD_reg_imm16       8'b00xx0001
 
  30 `define INSN_LD_SP_HL           8'b11111001
 
  31 `define INSN_PUSH_reg           8'b11xx0101
 
  32 `define INSN_POP_reg            8'b11xx0001
 
  33 `define INSN_reg_A              3'b111
 
  34 `define INSN_reg_B              3'b000
 
  35 `define INSN_reg_C              3'b001
 
  36 `define INSN_reg_D              3'b010
 
  37 `define INSN_reg_E              3'b011
 
  38 `define INSN_reg_H              3'b100
 
  39 `define INSN_reg_L              3'b101
 
  40 `define INSN_reg_dHL    3'b110
 
  41 `define INSN_reg16_BC   2'b00
 
  42 `define INSN_reg16_DE   2'b01
 
  43 `define INSN_reg16_HL   2'b10
 
  44 `define INSN_reg16_SP   2'b11
 
  45 `define INSN_stack_AF   2'b11
 
  46 `define INSN_stack_BC   2'b00
 
  47 `define INSN_stack_DE   2'b01
 
  48 `define INSN_stack_HL   2'b10
 
  51         output reg [15:0] busaddress,   /* BUS_* is latched on STATE_FETCH. */
 
  53         output reg buswr, output reg busrd);
 
  55         reg [1:0] state = 0;                                    /* State within this bus cycle (see STATE_*). */
 
  56         reg [2:0] cycle = 0;                                    /* Cycle for instructions. */
 
  58         reg [7:0] registers[11:0];
 
  60         reg [15:0] address;                             /* Address for the next bus operation. */
 
  62         reg [7:0] opcode;                               /* Opcode from the current machine cycle. */
 
  64         reg [7:0] rdata, wdata;         /* Read data from this bus cycle, or write data for the next. */
 
  65         reg rd = 1, wr = 0, newcycle = 1;
 
  67         reg [7:0] tmp;                                  /* Generic temporary reg. */
 
  70         assign busdata = buswr ? buswdata : 8'bzzzzzzzz;
 
  93                                 busaddress <= {registers[`REG_PCH], registers[`REG_PCL]};
 
  95                                 busaddress <= address;
 
  98                         state <= `STATE_DECODE;
 
 107                                 if (rd) rdata <= busdata;
 
 112                         address <= 16'bxxxxxxxxxxxxxxxx;        // Make it obvious if something of type has happened.
 
 113                         wdata <= 8'bxxxxxxxx;
 
 114                         state <= `STATE_EXECUTE;
 
 116                 `STATE_EXECUTE: begin
 
 117 `define EXEC_INC_PC \
 
 118         {registers[`REG_PCH], registers[`REG_PCL]} <= {registers[`REG_PCH], registers[`REG_PCL]} + 1
 
 119 `define EXEC_NEXTADDR_PCINC \
 
 120         address <= {registers[`REG_PCH], registers[`REG_PCL]} + 1
 
 121 `define EXEC_NEWCYCLE \
 
 122         newcycle <= 1; rd <= 1; wr <= 0
 
 124                         `INSN_LD_reg_imm8: begin
 
 128                                                 `EXEC_NEXTADDR_PCINC;
 
 133                                                 if (opcode[5:3] == `INSN_reg_dHL) begin
 
 134                                                         address <= {registers[`REG_H], registers[`REG_L]};
 
 149                                 /* XXX Interrupts needed for HALT. */
 
 151                         `INSN_LD_HL_reg: begin
 
 155                                                 `INSN_reg_A:    begin wdata <= registers[`REG_A]; end
 
 156                                                 `INSN_reg_B:    begin wdata <= registers[`REG_B]; end
 
 157                                                 `INSN_reg_C:    begin wdata <= registers[`REG_C]; end
 
 158                                                 `INSN_reg_D:    begin wdata <= registers[`REG_D]; end
 
 159                                                 `INSN_reg_E:    begin wdata <= registers[`REG_E]; end
 
 160                                                 `INSN_reg_H:    begin wdata <= registers[`REG_H]; end
 
 161                                                 `INSN_reg_L:    begin wdata <= registers[`REG_L]; end
 
 163                                                 address <= {registers[`REG_H], registers[`REG_L]};
 
 172                         `INSN_LD_reg_HL: begin
 
 175                                                 address <= {registers[`REG_H], registers[`REG_L]};
 
 185                         `INSN_LD_reg_reg: begin
 
 189                                 `INSN_reg_A:    begin tmp <= registers[`REG_A]; end
 
 190                                 `INSN_reg_B:    begin tmp <= registers[`REG_B]; end
 
 191                                 `INSN_reg_C:    begin tmp <= registers[`REG_C]; end
 
 192                                 `INSN_reg_D:    begin tmp <= registers[`REG_D]; end
 
 193                                 `INSN_reg_E:    begin tmp <= registers[`REG_E]; end
 
 194                                 `INSN_reg_H:    begin tmp <= registers[`REG_H]; end
 
 195                                 `INSN_reg_L:    begin tmp <= registers[`REG_L]; end
 
 198                         `INSN_LD_reg_imm16: begin
 
 202                                                 `EXEC_NEXTADDR_PCINC;
 
 206                                                 `EXEC_NEXTADDR_PCINC;
 
 209                                 2: begin `EXEC_NEWCYCLE; end
 
 212                         `INSN_LD_SP_HL: begin
 
 215                                                 tmp <= registers[`REG_H];
 
 220                                                 tmp <= registers[`REG_L];
 
 224                         `INSN_PUSH_reg: begin   /* PUSH is 16 cycles! */
 
 228                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]}-1;
 
 230                                                 `INSN_stack_AF: wdata <= registers[`REG_A];
 
 231                                                 `INSN_stack_BC: wdata <= registers[`REG_B];
 
 232                                                 `INSN_stack_DE: wdata <= registers[`REG_D];
 
 233                                                 `INSN_stack_HL: wdata <= registers[`REG_H];
 
 238                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]}-1;
 
 240                                                 `INSN_stack_AF: wdata <= registers[`REG_F];
 
 241                                                 `INSN_stack_BC: wdata <= registers[`REG_C];
 
 242                                                 `INSN_stack_DE: wdata <= registers[`REG_E];
 
 243                                                 `INSN_stack_HL: wdata <= registers[`REG_L];
 
 246                                 2:      begin /* TWIDDLE OUR FUCKING THUMBS! */ end
 
 253                         `INSN_POP_reg: begin    /* POP is 12 cycles! */
 
 257                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]};
 
 261                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]};
 
 272                         state <= `STATE_WRITEBACK;
 
 274                 `STATE_WRITEBACK: begin
 
 279                                 1: case (opcode[5:3])
 
 280                                         `INSN_reg_A:    begin registers[`REG_A] <= rdata; cycle <= 0; end
 
 281                                         `INSN_reg_B:    begin registers[`REG_B] <= rdata; cycle <= 0; end
 
 282                                         `INSN_reg_C:    begin registers[`REG_C] <= rdata; cycle <= 0; end
 
 283                                         `INSN_reg_D:    begin registers[`REG_D] <= rdata; cycle <= 0; end
 
 284                                         `INSN_reg_E:    begin registers[`REG_E] <= rdata; cycle <= 0; end
 
 285                                         `INSN_reg_H:    begin registers[`REG_H] <= rdata; cycle <= 0; end
 
 286                                         `INSN_reg_L:    begin registers[`REG_L] <= rdata; cycle <= 0; end
 
 287                                         `INSN_reg_dHL:  cycle <= 2;
 
 292                                 /* Nothing needs happen here. */
 
 293                                 /* XXX Interrupts needed for HALT. */
 
 295                         `INSN_LD_HL_reg: begin
 
 301                         `INSN_LD_reg_HL: begin
 
 306                                                 `INSN_reg_A:    begin registers[`REG_A] <= tmp; end
 
 307                                                 `INSN_reg_B:    begin registers[`REG_B] <= tmp; end
 
 308                                                 `INSN_reg_C:    begin registers[`REG_C] <= tmp; end
 
 309                                                 `INSN_reg_D:    begin registers[`REG_D] <= tmp; end
 
 310                                                 `INSN_reg_E:    begin registers[`REG_E] <= tmp; end
 
 311                                                 `INSN_reg_H:    begin registers[`REG_H] <= tmp; end
 
 312                                                 `INSN_reg_L:    begin registers[`REG_L] <= tmp; end
 
 318                         `INSN_LD_reg_reg: begin
 
 320                                 `INSN_reg_A:    begin registers[`REG_A] <= tmp; end
 
 321                                 `INSN_reg_B:    begin registers[`REG_B] <= tmp; end
 
 322                                 `INSN_reg_C:    begin registers[`REG_C] <= tmp; end
 
 323                                 `INSN_reg_D:    begin registers[`REG_D] <= tmp; end
 
 324                                 `INSN_reg_E:    begin registers[`REG_E] <= tmp; end
 
 325                                 `INSN_reg_H:    begin registers[`REG_H] <= tmp; end
 
 326                                 `INSN_reg_L:    begin registers[`REG_L] <= tmp; end
 
 329                         `INSN_LD_reg_imm16: begin
 
 334                                                 `INSN_reg16_BC: registers[`REG_C] <= rdata;
 
 335                                                 `INSN_reg16_DE: registers[`REG_E] <= rdata;
 
 336                                                 `INSN_reg16_HL: registers[`REG_L] <= rdata;
 
 337                                                 `INSN_reg16_SP: registers[`REG_SPL] <= rdata;
 
 343                                                 `INSN_reg16_BC: registers[`REG_B] <= rdata;
 
 344                                                 `INSN_reg16_DE: registers[`REG_D] <= rdata;
 
 345                                                 `INSN_reg16_HL: registers[`REG_H] <= rdata;
 
 346                                                 `INSN_reg16_SP: registers[`REG_SPH] <= rdata;
 
 352                         `INSN_LD_SP_HL: begin
 
 356                                                 registers[`REG_SPH] <= tmp;
 
 360                                                 registers[`REG_SPL] <= tmp;
 
 364                         `INSN_PUSH_reg: begin   /* PUSH is 16 cycles! */
 
 367                                                 {registers[`REG_SPH],registers[`REG_SPL]} <=
 
 368                                                         {registers[`REG_SPH],registers[`REG_SPL]} - 1;
 
 372                                                 {registers[`REG_SPH],registers[`REG_SPL]} <=
 
 373                                                         {registers[`REG_SPH],registers[`REG_SPL]} - 1;
 
 380                         `INSN_POP_reg: begin    /* POP is 12 cycles! */
 
 384                                                 {registers[`REG_SPH],registers[`REG_SPL]} <=
 
 385                                                         {registers[`REG_SPH],registers[`REG_SPL]} + 1;
 
 389                                                 `INSN_stack_AF: registers[`REG_F] <= rdata;
 
 390                                                 `INSN_stack_BC: registers[`REG_C] <= rdata;
 
 391                                                 `INSN_stack_DE: registers[`REG_E] <= rdata;
 
 392                                                 `INSN_stack_HL: registers[`REG_L] <= rdata;
 
 394                                                 {registers[`REG_SPH],registers[`REG_SPL]} <=
 
 395                                                         {registers[`REG_SPH],registers[`REG_SPL]} + 1;
 
 400                                                 `INSN_stack_AF: registers[`REG_A] <= rdata;
 
 401                                                 `INSN_stack_BC: registers[`REG_B] <= rdata;
 
 402                                                 `INSN_stack_DE: registers[`REG_D] <= rdata;
 
 403                                                 `INSN_stack_HL: registers[`REG_H] <= rdata;
 
 410                         state <= `STATE_FETCH;
 
 421         reg [7:0] rom [2047:0];
 
 423         initial $readmemh("rom.hex", rom);
 
 424         always #10 clk <= ~clk;
 
 431         assign data = rd ? rom[addr] : 8'bzzzzzzzz;