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_LDH_AC                     8'b111x0010     // Either LDH A,(C) or LDH (C),A
 
  34 `define INSN_LDx_AHL                    8'b001xx010     // LDD/LDI A,(HL) / (HL),A
 
  35 `define INSN_ALU8                               8'b10xxxxxx     // 10 xxx yyy
 
  36 `define INSN_NOP                                8'b00000000
 
  37 `define INSN_RST                                8'b11xxx111
 
  38 `define INSN_RET                                8'b110x1001     // 1 = RETI, 0 = RET
 
  39 `define INSN_CALL                               8'b11001101
 
  41 `define INSN_reg_A              3'b111
 
  42 `define INSN_reg_B              3'b000
 
  43 `define INSN_reg_C              3'b001
 
  44 `define INSN_reg_D              3'b010
 
  45 `define INSN_reg_E              3'b011
 
  46 `define INSN_reg_H              3'b100
 
  47 `define INSN_reg_L              3'b101
 
  48 `define INSN_reg_dHL    3'b110
 
  49 `define INSN_reg16_BC   2'b00
 
  50 `define INSN_reg16_DE   2'b01
 
  51 `define INSN_reg16_HL   2'b10
 
  52 `define INSN_reg16_SP   2'b11
 
  53 `define INSN_stack_AF   2'b11
 
  54 `define INSN_stack_BC   2'b00
 
  55 `define INSN_stack_DE   2'b01
 
  56 `define INSN_stack_HL   2'b10
 
  57 `define INSN_alu_ADD            3'b000
 
  58 `define INSN_alu_ADC            3'b001
 
  59 `define INSN_alu_SUB            3'b010
 
  60 `define INSN_alu_SBC            3'b011
 
  61 `define INSN_alu_AND            3'b100
 
  62 `define INSN_alu_XOR            3'b101
 
  63 `define INSN_alu_OR             3'b110
 
  64 `define INSN_alu_CP             3'b111          // Oh lawd, is dat some CP?
 
  68         output reg [15:0] busaddress,   /* BUS_* is latched on STATE_FETCH. */
 
  70         output reg buswr, output reg busrd);
 
  72         reg [1:0] state = 0;                                    /* State within this bus cycle (see STATE_*). */
 
  73         reg [2:0] cycle = 0;                                    /* Cycle for instructions. */
 
  75         reg [7:0] registers[11:0];
 
  77         reg [15:0] address;                             /* Address for the next bus operation. */
 
  79         reg [7:0] opcode;                               /* Opcode from the current machine cycle. */
 
  81         reg [7:0] rdata, wdata;         /* Read data from this bus cycle, or write data for the next. */
 
  82         reg rd = 1, wr = 0, newcycle = 1;
 
  84         reg [7:0] tmp, tmp2;                    /* Generic temporary regs. */
 
  87         assign busdata = buswr ? buswdata : 8'bzzzzzzzz;
 
 106         always @(posedge clk)
 
 112                                 busaddress <= {registers[`REG_PCH], registers[`REG_PCL]};
 
 114                                 busaddress <= address;
 
 117                         state <= `STATE_DECODE;
 
 126                                 if (rd) rdata <= busdata;
 
 131                         address <= 16'bxxxxxxxxxxxxxxxx;        // Make it obvious if something of type has happened.
 
 132                         wdata <= 8'bxxxxxxxx;
 
 133                         state <= `STATE_EXECUTE;
 
 135                 `STATE_EXECUTE: begin
 
 136 `define EXEC_INC_PC \
 
 137         {registers[`REG_PCH], registers[`REG_PCL]} <= {registers[`REG_PCH], registers[`REG_PCL]} + 1
 
 138 `define EXEC_NEXTADDR_PCINC \
 
 139         address <= {registers[`REG_PCH], registers[`REG_PCL]} + 1
 
 140 `define EXEC_NEWCYCLE \
 
 141         newcycle <= 1; rd <= 1; wr <= 0
 
 143                         `INSN_LD_reg_imm8: begin
 
 147                                                 `EXEC_NEXTADDR_PCINC;
 
 152                                                 if (opcode[5:3] == `INSN_reg_dHL) begin
 
 153                                                         address <= {registers[`REG_H], registers[`REG_L]};
 
 168                                 /* XXX Interrupts needed for HALT. */
 
 170                         `INSN_LD_HL_reg: begin
 
 174                                                 `INSN_reg_A:    wdata <= registers[`REG_A];
 
 175                                                 `INSN_reg_B:    wdata <= registers[`REG_B];
 
 176                                                 `INSN_reg_C:    wdata <= registers[`REG_C];
 
 177                                                 `INSN_reg_D:    wdata <= registers[`REG_D];
 
 178                                                 `INSN_reg_E:    wdata <= registers[`REG_E];
 
 179                                                 `INSN_reg_H:    wdata <= registers[`REG_H];
 
 180                                                 `INSN_reg_L:    wdata <= registers[`REG_L];
 
 182                                                 address <= {registers[`REG_H], registers[`REG_L]};
 
 191                         `INSN_LD_reg_HL: begin
 
 194                                                 address <= {registers[`REG_H], registers[`REG_L]};
 
 204                         `INSN_LD_reg_reg: begin
 
 208                                 `INSN_reg_A:    tmp <= registers[`REG_A];
 
 209                                 `INSN_reg_B:    tmp <= registers[`REG_B];
 
 210                                 `INSN_reg_C:    tmp <= registers[`REG_C];
 
 211                                 `INSN_reg_D:    tmp <= registers[`REG_D];
 
 212                                 `INSN_reg_E:    tmp <= registers[`REG_E];
 
 213                                 `INSN_reg_H:    tmp <= registers[`REG_H];
 
 214                                 `INSN_reg_L:    tmp <= registers[`REG_L];
 
 217                         `INSN_LD_reg_imm16: begin
 
 221                                                 `EXEC_NEXTADDR_PCINC;
 
 225                                                 `EXEC_NEXTADDR_PCINC;
 
 228                                 2: begin `EXEC_NEWCYCLE; end
 
 231                         `INSN_LD_SP_HL: begin
 
 234                                                 tmp <= registers[`REG_H];
 
 239                                                 tmp <= registers[`REG_L];
 
 243                         `INSN_PUSH_reg: begin   /* PUSH is 16 cycles! */
 
 247                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]}-1;
 
 249                                                 `INSN_stack_AF: wdata <= registers[`REG_A];
 
 250                                                 `INSN_stack_BC: wdata <= registers[`REG_B];
 
 251                                                 `INSN_stack_DE: wdata <= registers[`REG_D];
 
 252                                                 `INSN_stack_HL: wdata <= registers[`REG_H];
 
 257                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]}-1;
 
 259                                                 `INSN_stack_AF: wdata <= registers[`REG_F];
 
 260                                                 `INSN_stack_BC: wdata <= registers[`REG_C];
 
 261                                                 `INSN_stack_DE: wdata <= registers[`REG_E];
 
 262                                                 `INSN_stack_HL: wdata <= registers[`REG_L];
 
 265                                 2:      begin /* TWIDDLE OUR FUCKING THUMBS! */ end
 
 272                         `INSN_POP_reg: begin    /* POP is 12 cycles! */
 
 276                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]};
 
 280                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]};
 
 291                                                 address <= {8'hFF,registers[`REG_C]};
 
 292                                                 if (opcode[4]) begin    // LD A,(C)
 
 296                                                         wdata <= registers[`REG_A];
 
 308                                                 address <= {registers[`REG_H],registers[`REG_L]};
 
 309                                                 if (opcode[3]) begin    // LDx A, (HL)
 
 313                                                         wdata <= registers[`REG_A];
 
 323                                 if ((opcode[2:0] == `INSN_reg_dHL) && (cycle == 0)) begin
 
 324                                         // fffffffff fuck your shit, read from (HL) :(
 
 326                                         address <= {registers[`REG_H], registers[`REG_L]};
 
 331                                         `INSN_reg_A:    tmp <= registers[`REG_A];
 
 332                                         `INSN_reg_B:    tmp <= registers[`REG_B];
 
 333                                         `INSN_reg_C:    tmp <= registers[`REG_C];
 
 334                                         `INSN_reg_D:    tmp <= registers[`REG_D];
 
 335                                         `INSN_reg_E:    tmp <= registers[`REG_E];
 
 336                                         `INSN_reg_H:    tmp <= registers[`REG_H];
 
 337                                         `INSN_reg_L:    tmp <= registers[`REG_L];
 
 338                                         `INSN_reg_dHL:  tmp <= rdata;
 
 349                                                 `EXEC_INC_PC;           // This goes FIRST in RST
 
 353                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]}-1;
 
 354                                                 wdata <= registers[`REG_PCH];
 
 358                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]}-2;
 
 359                                                 wdata <= registers[`REG_PCL];
 
 363                                                 {registers[`REG_PCH],registers[`REG_PCL]} <=
 
 364                                                         {10'b0,opcode[5:3],3'b0};
 
 372                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]};
 
 376                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]} + 1;
 
 378                                 2:      begin /* twiddle thumbs */ end
 
 381                                                 // do NOT increment PC!
 
 389                                                 `EXEC_NEXTADDR_PCINC;
 
 394                                                 `EXEC_NEXTADDR_PCINC;
 
 398                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]} - 1;
 
 399                                                 wdata <= registers[`REG_PCH];
 
 403                                                 address <= {registers[`REG_SPH],registers[`REG_SPL]} - 2;
 
 404                                                 wdata <= registers[`REG_PCL];
 
 407                                 4:      begin /* nothing happens on the bus next cycle! */ end
 
 409                                                 `EXEC_NEWCYCLE; /* do NOT increment the PC */
 
 416                         state <= `STATE_WRITEBACK;
 
 418                 `STATE_WRITEBACK: begin
 
 423                                 1:      case (opcode[5:3])
 
 424                                         `INSN_reg_A:    begin registers[`REG_A] <= rdata; cycle <= 0; end
 
 425                                         `INSN_reg_B:    begin registers[`REG_B] <= rdata; cycle <= 0; end
 
 426                                         `INSN_reg_C:    begin registers[`REG_C] <= rdata; cycle <= 0; end
 
 427                                         `INSN_reg_D:    begin registers[`REG_D] <= rdata; cycle <= 0; end
 
 428                                         `INSN_reg_E:    begin registers[`REG_E] <= rdata; cycle <= 0; end
 
 429                                         `INSN_reg_H:    begin registers[`REG_H] <= rdata; cycle <= 0; end
 
 430                                         `INSN_reg_L:    begin registers[`REG_L] <= rdata; cycle <= 0; end
 
 431                                         `INSN_reg_dHL:  cycle <= 2;
 
 436                                 /* Nothing needs happen here. */
 
 437                                 /* XXX Interrupts needed for HALT. */
 
 439                         `INSN_LD_HL_reg: begin
 
 445                         `INSN_LD_reg_HL: begin
 
 450                                                 `INSN_reg_A:    registers[`REG_A] <= tmp;
 
 451                                                 `INSN_reg_B:    registers[`REG_B] <= tmp;
 
 452                                                 `INSN_reg_C:    registers[`REG_C] <= tmp;
 
 453                                                 `INSN_reg_D:    registers[`REG_D] <= tmp;
 
 454                                                 `INSN_reg_E:    registers[`REG_E] <= tmp;
 
 455                                                 `INSN_reg_H:    registers[`REG_H] <= tmp;
 
 456                                                 `INSN_reg_L:    registers[`REG_L] <= tmp;
 
 462                         `INSN_LD_reg_reg: begin
 
 464                                 `INSN_reg_A:    registers[`REG_A] <= tmp;
 
 465                                 `INSN_reg_B:    registers[`REG_B] <= tmp;
 
 466                                 `INSN_reg_C:    registers[`REG_C] <= tmp;
 
 467                                 `INSN_reg_D:    registers[`REG_D] <= tmp;
 
 468                                 `INSN_reg_E:    registers[`REG_E] <= tmp;
 
 469                                 `INSN_reg_H:    registers[`REG_H] <= tmp;
 
 470                                 `INSN_reg_L:    registers[`REG_L] <= tmp;
 
 473                         `INSN_LD_reg_imm16: begin
 
 478                                                 `INSN_reg16_BC: registers[`REG_C] <= rdata;
 
 479                                                 `INSN_reg16_DE: registers[`REG_E] <= rdata;
 
 480                                                 `INSN_reg16_HL: registers[`REG_L] <= rdata;
 
 481                                                 `INSN_reg16_SP: registers[`REG_SPL] <= rdata;
 
 487                                                 `INSN_reg16_BC: registers[`REG_B] <= rdata;
 
 488                                                 `INSN_reg16_DE: registers[`REG_D] <= rdata;
 
 489                                                 `INSN_reg16_HL: registers[`REG_H] <= rdata;
 
 490                                                 `INSN_reg16_SP: registers[`REG_SPH] <= rdata;
 
 496                         `INSN_LD_SP_HL: begin
 
 500                                                 registers[`REG_SPH] <= tmp;
 
 504                                                 registers[`REG_SPL] <= tmp;
 
 508                         `INSN_PUSH_reg: begin   /* PUSH is 16 cycles! */
 
 511                                                 {registers[`REG_SPH],registers[`REG_SPL]} <=
 
 512                                                         {registers[`REG_SPH],registers[`REG_SPL]} - 1;
 
 516                                                 {registers[`REG_SPH],registers[`REG_SPL]} <=
 
 517                                                         {registers[`REG_SPH],registers[`REG_SPL]} - 1;
 
 524                         `INSN_POP_reg: begin    /* POP is 12 cycles! */
 
 528                                                 {registers[`REG_SPH],registers[`REG_SPL]} <=
 
 529                                                         {registers[`REG_SPH],registers[`REG_SPL]} + 1;
 
 533                                                 `INSN_stack_AF: registers[`REG_F] <= rdata;
 
 534                                                 `INSN_stack_BC: registers[`REG_C] <= rdata;
 
 535                                                 `INSN_stack_DE: registers[`REG_E] <= rdata;
 
 536                                                 `INSN_stack_HL: registers[`REG_L] <= rdata;
 
 538                                                 {registers[`REG_SPH],registers[`REG_SPL]} <=
 
 539                                                         {registers[`REG_SPH],registers[`REG_SPL]} + 1;
 
 544                                                 `INSN_stack_AF: registers[`REG_A] <= rdata;
 
 545                                                 `INSN_stack_BC: registers[`REG_B] <= rdata;
 
 546                                                 `INSN_stack_DE: registers[`REG_D] <= rdata;
 
 547                                                 `INSN_stack_HL: registers[`REG_H] <= rdata;
 
 559                                                         registers[`REG_A] <= rdata;
 
 569                                                         registers[`REG_A] <= rdata;
 
 570                                                 {registers[`REG_H],registers[`REG_L]} <=
 
 571                                                         opcode[4] ? // if set, LDD, else LDI
 
 572                                                         ({registers[`REG_H],registers[`REG_L]} - 1) :
 
 573                                                         ({registers[`REG_H],registers[`REG_L]} + 1);
 
 578                                 if ((opcode[2:0] == `INSN_reg_dHL) && (cycle == 0)) begin
 
 579                                         /* Sit on our asses. */
 
 581                                 end else begin          /* Actually do the computation! */
 
 585                                                         registers[`REG_A] + tmp;
 
 587                                                         { /* Z */ ((registers[`REG_A] + tmp) == 0) ? 1'b1 : 1'b0,
 
 589                                                           /* H */ (({1'b0,registers[`REG_A][3:0]} + {1'b0,tmp[3:0]}) >> 4 == 1) ? 1'b1 : 1'b0,
 
 590                                                           /* C */ (({1'b0,registers[`REG_A]} + {1'b0,tmp}) >> 8 == 1) ? 1'b1 : 1'b0,
 
 591                                                           registers[`REG_F][3:0]
 
 596                                                         registers[`REG_A] + tmp + {7'b0,registers[`REG_F][4]};
 
 598                                                         { /* Z */ ((registers[`REG_A] + tmp + {7'b0,registers[`REG_F][4]}) == 0) ? 1'b1 : 1'b0,
 
 600                                                           /* H */ (({1'b0,registers[`REG_A][3:0]} + {1'b0,tmp[3:0]} + {4'b0,registers[`REG_F][4]}) >> 4 == 1) ? 1'b1 : 1'b0,
 
 601                                                           /* C */ (({1'b0,registers[`REG_A]} + {1'b0,tmp} + {8'b0,registers[`REG_F][4]}) >> 8 == 1) ? 1'b1 : 1'b0,
 
 602                                                           registers[`REG_F][3:0]
 
 607                                                         registers[`REG_A] & tmp;
 
 609                                                         { /* Z */ ((registers[`REG_A] & tmp) == 0) ? 1'b1 : 1'b0,
 
 611                                                           registers[`REG_F][3:0]
 
 616                                                         registers[`REG_A] | tmp;
 
 618                                                         { /* Z */ ((registers[`REG_A] | tmp) == 0) ? 1'b1 : 1'b0,
 
 620                                                           registers[`REG_F][3:0]
 
 625                                                         registers[`REG_A] ^ tmp;
 
 627                                                         { /* Z */ ((registers[`REG_A] ^ tmp) == 0) ? 1'b1 : 1'b0,
 
 629                                                           registers[`REG_F][3:0]
 
 637                         `INSN_NOP: begin /* NOP! */ end
 
 645                                                 {registers[`REG_SPH],registers[`REG_SPL]} <=
 
 646                                                         {registers[`REG_SPH],registers[`REG_SPL]}-2;
 
 655                                                 registers[`REG_PCL] <= rdata;
 
 659                                                 registers[`REG_PCH] <= rdata;
 
 663                                                 {registers[`REG_SPH],registers[`REG_SPL]} <=
 
 664                                                         {registers[`REG_SPH],registers[`REG_SPL]} + 2;
 
 665                                                 if (opcode[4])  /* RETI */
 
 675                                                 tmp <= rdata;   // tmp contains newpcl
 
 679                                                 tmp2 <= rdata;  // tmp2 contains newpch
 
 683                                                 registers[`REG_PCH] <= tmp2;
 
 687                                                 registers[`REG_PCL] <= tmp;
 
 690                                                 {registers[`REG_SPH],registers[`REG_SPL]} <=
 
 691                                                         {registers[`REG_SPH],registers[`REG_SPL]} - 2;
 
 699                         state <= `STATE_FETCH;
 
 706         input [15:0] address,
 
 710         reg [7:0] rom [2047:0];
 
 711         initial $readmemh("rom.hex", rom);
 
 713         wire decode = address[15:13] == 0;
 
 716         assign data = (rd && decode) ? odata : 8'bzzzzzzzz;
 
 721                         odata <= rom[address];
 
 726         input [15:0] address,
 
 730         reg [7:0] ram [8191:0];
 
 732         wire decode = (address >= 16'hC000) && (address < 16'hFE00);
 
 735         assign data = (rd && decode) ? odata : 8'bzzzzzzzz;
 
 740                         odata <= ram[address];
 
 741                 else if (decode && wr)
 
 742                         ram[address] <= idata;
 
 752         always #10 clk <= ~clk;