├── regfile.v ├── README.md ├── ab.v ├── alu.v ├── disas.v ├── define.i ├── doc └── sequence.md └── cpu.v /regfile.v: -------------------------------------------------------------------------------- 1 | module regfile( 2 | input clk, 3 | input reg_we, 4 | input [1:0] reg_src, 5 | input [1:0] reg_dst, 6 | input [1:0] reg_idx, 7 | output [7:0] src, 8 | output [7:0] idx, 9 | input [7:0] dst, 10 | output reg [7:0] S, 11 | input txs, 12 | input push, 13 | input pull ); 14 | 15 | `include "define.i" 16 | 17 | /* 18 | * register file 19 | */ 20 | reg [7:0] regs[3:0]; // register file 21 | 22 | /* 23 | * initial values for easy debugging, not required 24 | */ 25 | initial begin 26 | regs[SEL_Z] = 0; // Z register 27 | regs[SEL_X] = 1; // X register 28 | regs[SEL_Y] = 2; // Y register 29 | regs[SEL_A] = 8'h41; // A register 30 | S = 8'hff; // S register 31 | end 32 | 33 | /* 34 | * 1st read port: source register 35 | * 36 | */ 37 | assign src = regs[reg_src]; 38 | 39 | /* 40 | * 2nd read port: index register 41 | */ 42 | assign idx = regs[reg_idx]; 43 | 44 | /* 45 | * write port: destination register. 46 | */ 47 | always @(posedge clk) 48 | if( reg_we ) 49 | regs[reg_dst] <= dst; 50 | 51 | /* 52 | * update stack pointer 53 | */ 54 | always @(posedge clk) 55 | if( txs ) S <= src; 56 | else if( push ) S <= S - 1; 57 | else if( pull ) S <= S + 1; 58 | 59 | endmodule 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # verilog-65C02-fsm 2 | A verilog model of the 65C02 CPU. The code is rewritten from scratch. 3 | 4 | * Assumes synchronous memory 5 | * Uses finite state machine rather than microcode for control 6 | * Designed for simplicity, size and speed 7 | * Reduced cycle count eliminates all unnecessary cycles 8 | 9 | ## Design goals 10 | The main design goal is to provide an easy understand implementation that has good performance 11 | 12 | ## Code 13 | Code is far from complete. Right now it's in a 'proof of concept' stage where the address 14 | generation and ALU are done in a quick and dirty fashion to test some new ideas. Once I'm happy 15 | with the overall design, I can do some optimizations. 16 | 17 | * cpu.v module is the top level. 18 | 19 | Code has been tested with Verilator. 20 | 21 | ## Status 22 | 23 | * All CMOS/NMOS 6502 instructions added (except for NOPs as undefined, Rockwell/WDC extensions) 24 | * Model passes Klaus Dormann's test suite for 6502 (with BCD *disabled*) 25 | * BCD not yet supported 26 | * SYNC, RST supported 27 | * IRQ, RDY, NMI not yet supported 28 | 29 | ### Cycle counts 30 | For purpose of minimizing design and performance improvement, I did not keep the original cycle 31 | count. All of the so-called dead cycles have been removed. 32 | 33 | | Instruction type | Cycles | 34 | | :--------------: | :----: | 35 | | Implied PHx/PLx | 2 | 36 | | RTS | 4 | 37 | | RTI | 5 | 38 | | BRK | 7 | 39 | | Other implied | 1 | 40 | | JMP Absolute | 3 | 41 | | JMP (Indirect) | 5 | 42 | | JSR Absolute | 5 | 43 | | branch | 2 | 44 | | Immediate | 2 | 45 | | Zero page | 3 | 46 | | Zero page, X | 3 | 47 | | Zero page, Y | 3 | 48 | | Absolute | 4 | 49 | | Absolute, X | 4 | 50 | | Absolute, Y | 4 | 51 | | (Zero page) | 5 | 52 | | (Zero page), Y | 5 | 53 | | (Zero page, X) | 5 | 54 | 55 | Add 1 cycle for any read-modify-write. There is no extra cycle for taken branches, page overflows, or for X/Y offset calculations. 56 | 57 | Have fun. 58 | -------------------------------------------------------------------------------- /ab.v: -------------------------------------------------------------------------------- 1 | /* 2 | * Address Bus (and PC) generator 3 | * 4 | * Copyright (C) Arlet Ottens, 2022, 5 | */ 6 | 7 | module ab( 8 | input clk, 9 | input RST, 10 | input [9:0] ab_op, 11 | input [7:0] S, 12 | input [7:0] DI, 13 | input [7:0] DR, 14 | input [7:0] XY, 15 | output [15:0] AB, 16 | output reg [15:0] PC ); 17 | 18 | reg [7:0] ABH; 19 | reg [7:0] ABL; 20 | assign AB = { ABH, ABL }; 21 | 22 | 23 | /* 24 | * ab_hold stores a copy of current address to be used 25 | * later. 26 | */ 27 | reg [15:0] ab_hold; 28 | 29 | always @(posedge clk) 30 | if( ab_op[7] ) 31 | ab_hold = AB; 32 | 33 | /* 34 | * update program counter 35 | */ 36 | always @(posedge clk) 37 | if( RST ) 38 | PC <= 16'hfffc; 39 | else case( ab_op[6:5] ) 40 | 2'b01: PC <= AB + 16'h1; 41 | 2'b10: PC <= 16'hfffa; 42 | 2'b11: PC <= 16'hfffe; 43 | endcase 44 | 45 | /* 46 | * determine base address 47 | */ 48 | reg [15:0] base; 49 | 50 | always @* 51 | case( ab_op[4:3] ) 52 | 2'b00: base = {8'h00, S}; 53 | 2'b01: base = PC; 54 | 2'b10: base = {DI, DR}; 55 | 2'b11: base = ab_hold; 56 | endcase 57 | 58 | /* 59 | * add offset to the base address. We split the address into 60 | * two separate bytes, because sometimes the address should 61 | * wrap within the page, so we can't always let the carry 62 | * go through. 63 | */ 64 | 65 | wire abl_ci = ab_op[0]; // carry input from operation 66 | reg abl_co; // carry output from low byte 67 | 68 | always @* begin 69 | case( ab_op[2:1] ) 70 | 2'b00: {abl_co, ABL} = base[7:0] + 00 + abl_ci; 71 | 2'b01: {abl_co, ABL} = base[7:0] + XY + abl_ci; 72 | 2'b10: {abl_co, ABL} = base[7:0] + DI + abl_ci; 73 | 2'b11: {abl_co, ABL} = XY + DI + abl_ci; 74 | endcase 75 | end 76 | 77 | /* 78 | * carry input for high byte 79 | */ 80 | wire abh_ci = ab_op[9] & abl_co; 81 | 82 | /* 83 | * calculate address high byte 84 | */ 85 | always @* begin 86 | case( ab_op[9:8] ) 87 | 2'b00: ABH = base[15:8] + 8'h00 + abh_ci; // ci = 0 88 | 2'b01: ABH = base[15:8] + 8'h01 + abh_ci; // ci = 0 89 | 2'b10: ABH = base[15:8] + 8'h00 + abh_ci; // ci = abl_ci 90 | 2'b11: ABH = base[15:8] + 8'hff + abh_ci; // ci = abl_ci 91 | endcase 92 | end 93 | 94 | endmodule 95 | -------------------------------------------------------------------------------- /alu.v: -------------------------------------------------------------------------------- 1 | /* 2 | * alu.v 3 | * 4 | * (C) Arlet Ottens, 5 | */ 6 | 7 | module alu( 8 | input [8:0] alu_op, 9 | input [7:0] R, 10 | input [7:0] S, 11 | input [7:0] DI, 12 | input [7:0] DR, 13 | input C, 14 | output reg [7:0] alu_out, 15 | output reg alu_C, 16 | output alu_Z, 17 | output alu_N, 18 | output alu_V ); 19 | 20 | wire shift = alu_op[8]; 21 | wire right = alu_op[7]; 22 | reg [7:0] alu_ai; 23 | reg [7:0] alu_bi; 24 | reg alu_ci; 25 | reg alu_si; 26 | assign alu_Z = !alu_out; 27 | assign alu_N = alu_out[7]; 28 | assign alu_V = alu_ai[7] ^ alu_bi[7] ^ alu_C ^ alu_N; 29 | 30 | always @* begin 31 | 32 | /* 33 | * determine ALU A input. 34 | */ 35 | casez( alu_op[6:4] ) 36 | 3'b0?0: alu_ai = R; // input from register file 37 | 3'b0?1: alu_ai = DR; // input from data bus 38 | 3'b100: alu_ai = R | DR; // ORA between register and memory 39 | 3'b101: alu_ai = R & DR; // AND between register and memory 40 | 3'b110: alu_ai = R ^ DR; // EOR between register and memory 41 | 3'b111: alu_ai = S; // stack pointer (for TSX) 42 | endcase 43 | 44 | /* 45 | * determine ALU B input 46 | */ 47 | casez( alu_op[3:2] ) 48 | 2'b00: alu_bi = 0; // for LDA, logic operations and INC 49 | 2'b01: alu_bi = DR; // for ADC 50 | 2'b10: alu_bi = ~0; // for DEC 51 | 2'b11: alu_bi = ~DR; // for SBC/CMP 52 | endcase 53 | 54 | /* 55 | * determine ALU carry input 56 | */ 57 | casez( alu_op[1:0] ) 58 | 2'b00: alu_ci = 0; // no carry 59 | 2'b01: alu_ci = 1; // carry=1 for INC 60 | 2'b10: alu_ci = C; // for ADC/SBC 61 | 2'b11: alu_ci = 0; // for rotate 62 | endcase 63 | 64 | /* 65 | * add it all up. If we don't need addition, then the B/C inputs 66 | * should be kept at 0. 67 | */ 68 | 69 | {alu_C, alu_out} = alu_ai + alu_bi + alu_ci; 70 | 71 | /* 72 | * determine shift input for rotate instructions 73 | */ 74 | alu_si = C & alu_op[0]; 75 | 76 | /* 77 | * shift/rotate the result if necessary. Note that there's 78 | * a trick to replace alu_out with DI input when shift=0, 79 | * but right=1. This allows ALU bypass for PLA/PLX/PLY. 80 | */ 81 | 82 | if( shift ) 83 | if( right ) 84 | {alu_out, alu_C} = {alu_si, alu_out}; 85 | else 86 | {alu_C, alu_out} = {alu_out, alu_si}; 87 | else if( right ) 88 | alu_out = DI; 89 | end 90 | 91 | endmodule 92 | -------------------------------------------------------------------------------- /disas.v: -------------------------------------------------------------------------------- 1 | module disas( 2 | input [7:0] opcode, 3 | output reg [23:0] mnemonic ); 4 | 5 | always @* 6 | casez( opcode ) 7 | 8'b0000_0000: mnemonic = "BRK"; 8 | 8'b0000_1000: mnemonic = "PHP"; 9 | 8'b0001_0010: mnemonic = "ORA"; 10 | 8'b0011_0010: mnemonic = "AND"; 11 | 8'b0101_0010: mnemonic = "EOR"; 12 | 8'b0111_0010: mnemonic = "ADC"; 13 | 8'b1001_0010: mnemonic = "STA"; 14 | 8'b1011_0010: mnemonic = "LDA"; 15 | 8'b1101_0010: mnemonic = "CMP"; 16 | 8'b1111_0010: mnemonic = "SBC"; 17 | 8'b011?_0100: mnemonic = "STZ"; 18 | 8'b1001_11?0: mnemonic = "STZ"; 19 | 8'b0101_1010: mnemonic = "PHY"; 20 | 8'b1101_1010: mnemonic = "PHX"; 21 | 8'b0111_1010: mnemonic = "PLY"; 22 | 8'b1111_1010: mnemonic = "PLX"; 23 | 8'b000?_??01: mnemonic = "ORA"; 24 | 8'b0001_0000: mnemonic = "BPL"; 25 | 8'b0001_1010: mnemonic = "INA"; 26 | 8'b000?_??10: mnemonic = "ASL"; 27 | 8'b0001_1000: mnemonic = "CLC"; 28 | 8'b0010_0000: mnemonic = "JSR"; 29 | 8'b0010_1000: mnemonic = "PLP"; 30 | 8'b001?_?100: mnemonic = "BIT"; 31 | 8'b1000_1001: mnemonic = "BIT"; 32 | 8'b001?_??01: mnemonic = "AND"; 33 | 8'b0011_0000: mnemonic = "BMI"; 34 | 8'b0011_1010: mnemonic = "DEA"; 35 | 8'b001?_??10: mnemonic = "ROL"; 36 | 8'b0011_1000: mnemonic = "SEC"; 37 | 8'b0100_0000: mnemonic = "RTI"; 38 | 8'b0100_1000: mnemonic = "PHA"; 39 | 8'b010?_??01: mnemonic = "EOR"; 40 | 8'b0101_0000: mnemonic = "BVC"; 41 | 8'b010?_??10: mnemonic = "LSR"; 42 | 8'b0101_1000: mnemonic = "CLI"; 43 | 8'b01??_1100: mnemonic = "JMP"; 44 | 8'b0110_0000: mnemonic = "RTS"; 45 | 8'b0110_1000: mnemonic = "PLA"; 46 | 8'b011?_??01: mnemonic = "ADC"; 47 | 8'b0111_0000: mnemonic = "BVS"; 48 | 8'b011?_??10: mnemonic = "ROR"; 49 | 8'b0111_1000: mnemonic = "SEI"; 50 | 8'b1000_0000: mnemonic = "BRA"; 51 | 8'b1000_1000: mnemonic = "DEY"; 52 | 8'b1000_?100: mnemonic = "STY"; 53 | 8'b1001_0100: mnemonic = "STY"; 54 | 8'b1000_1010: mnemonic = "TXA"; 55 | 8'b1001_0010: mnemonic = "STA"; 56 | 8'b100?_??01: mnemonic = "STA"; 57 | 8'b1001_0000: mnemonic = "BCC"; 58 | 8'b1001_1000: mnemonic = "TYA"; 59 | 8'b1001_1010: mnemonic = "TXS"; 60 | 8'b100?_?110: mnemonic = "STX"; 61 | 8'b1010_0000: mnemonic = "LDY"; 62 | 8'b1010_1000: mnemonic = "TAY"; 63 | 8'b1010_1010: mnemonic = "TAX"; 64 | 8'b101?_??01: mnemonic = "LDA"; 65 | 8'b1011_0000: mnemonic = "BCS"; 66 | 8'b101?_?100: mnemonic = "LDY"; 67 | 8'b1011_1000: mnemonic = "CLV"; 68 | 8'b1011_1010: mnemonic = "TSX"; 69 | 8'b101?_?110: mnemonic = "LDX"; 70 | 8'b1010_0010: mnemonic = "LDX"; 71 | 8'b1100_0000: mnemonic = "CPY"; 72 | 8'b1100_1000: mnemonic = "INY"; 73 | 8'b1100_?100: mnemonic = "CPY"; 74 | 8'b1100_1010: mnemonic = "DEX"; 75 | 8'b110?_??01: mnemonic = "CMP"; 76 | 8'b1101_0000: mnemonic = "BNE"; 77 | 8'b1101_1000: mnemonic = "CLD"; 78 | 8'b110?_?110: mnemonic = "DEC"; 79 | 8'b1110_0000: mnemonic = "CPX"; 80 | 8'b1110_1000: mnemonic = "INX"; 81 | 8'b1110_?100: mnemonic = "CPX"; 82 | 8'b1110_1010: mnemonic = "NOP"; 83 | 8'b111?_??01: mnemonic = "SBC"; 84 | 8'b1111_0000: mnemonic = "BEQ"; 85 | 8'b1111_1000: mnemonic = "SED"; 86 | 8'b111?_?110: mnemonic = "INC"; 87 | 8'b1101_1011: mnemonic = "STP"; 88 | 8'b0000_?100: mnemonic = "TSB"; 89 | 8'b0001_?100: mnemonic = "TRB"; 90 | 91 | default: mnemonic = "___"; 92 | endcase 93 | 94 | endmodule 95 | -------------------------------------------------------------------------------- /define.i: -------------------------------------------------------------------------------- 1 | parameter 2 | SYNC = 5'd0, 3 | IMM0 = 5'd1, 4 | PHA0 = 5'd2, 5 | PLA0 = 5'd3, 6 | ZPG0 = 5'd4, 7 | DATA = 5'd5, 8 | ABS0 = 5'd6, 9 | ABS1 = 5'd7, 10 | BRA0 = 5'd8, 11 | JSR0 = 5'd9, 12 | JSR1 = 5'd10, 13 | JSR2 = 5'd11, 14 | RTS0 = 5'd12, 15 | RTS1 = 5'd13, 16 | RTS2 = 5'd14, 17 | JMP0 = 5'd15, 18 | JMP1 = 5'd16, 19 | IDX0 = 5'd17, 20 | IDX1 = 5'd18, 21 | IDX2 = 5'd19, 22 | BRK0 = 5'd20, 23 | BRK1 = 5'd21, 24 | BRK2 = 5'd22, 25 | BRK3 = 5'd23, 26 | RTI0 = 5'd24, 27 | IND0 = 5'd25, 28 | IND1 = 5'd26, 29 | ZPW0 = 5'd27, 30 | ABW0 = 5'd28, 31 | ABW1 = 5'd29, 32 | RMW0 = 5'd30, 33 | RMW1 = 5'd31; 34 | 35 | parameter 36 | NOP = 2'd00, 37 | LDA = 2'd01, 38 | STA = 2'd10, 39 | RMW = 2'd11; 40 | 41 | parameter 42 | DST__ = 2'bxx, 43 | DST_X = 2'b01, 44 | DST_Y = 2'b10, 45 | DST_A = 2'b11; 46 | 47 | parameter 48 | SRC__ = 2'bxx, 49 | SRC_Z = 2'b00, 50 | SRC_X = 2'b01, 51 | SRC_Y = 2'b10, 52 | SRC_A = 2'b11; 53 | 54 | parameter 55 | SEL_Z = 2'b00, 56 | SEL_X = 2'b01, 57 | SEL_Y = 2'b10, 58 | SEL_A = 2'b11; 59 | 60 | /* 61 | * flag behavior 62 | */ 63 | parameter 64 | FLAG____ = 2'b00, 65 | FLAG_ADD = 2'b01, 66 | FLAG_CMP = 2'b10, 67 | FLAG_BIT = 2'b11; 68 | 69 | /* 70 | * index register bits from control[] vector 71 | */ 72 | parameter 73 | IZ = SEL_Z, 74 | IX = SEL_X, 75 | IY = SEL_Y; 76 | 77 | /* 78 | * index register mask from cycle operation 79 | */ 80 | parameter 81 | IDX___ = 2'b00, // force zero register 82 | IDX_X_ = 2'b01, // only allow X in this cycle 83 | IDX__Y = 2'b10, // only allow Y in this cycle 84 | IDX_XY = 2'b11; // allow both X/Y register 85 | 86 | parameter // SR__A__B__C SR A B C 87 | // ----------------------------------------- 88 | ALU_____ = 9'bxx_xxx_xx_xx, 89 | ALU_REG = 9'b00_000_00_00, // R + 0 + 0 90 | ALU_INCA = 9'b00_000_00_01, // R + 0 + 1 91 | ALU_DECA = 9'b00_000_10_00, // R + -1 + 0 92 | ALU_LDA = 9'b00_001_00_00, // M + 0 + 0 93 | ALU_INCM = 9'b00_001_00_01, // M + 0 + 1 94 | ALU_DECM = 9'b00_001_10_00, // M + -1 + 0 95 | ALU_ADC = 9'b00_000_01_10, // R + M + C 96 | ALU_CMP = 9'b00_000_11_01, // R + ~M + 1 97 | ALU_SBC = 9'b00_000_11_10, // R + ~M + C 98 | ALU_ORA = 9'b00_100_00_00, // R|M + 0 + 0 99 | ALU_AND = 9'b00_101_00_00, // R&M + 0 + 0 100 | ALU_EOR = 9'b00_110_00_00, // R^M + 0 + 0 101 | ALU_TSX = 9'b00_111_00_00, // S + 0 + 0 102 | ALU_PLA = 9'b01_xxx_xx_xx, // DI 103 | ALU_ASLA = 9'b10_000_00_00, // asl( R + 0 + 0) 104 | ALU_ROLA = 9'b10_000_00_11, // rol( R + 0 + 0) 105 | ALU_LSRA = 9'b11_000_00_00, // lsr( R + 0 + 0) 106 | ALU_RORA = 9'b11_000_00_11, // ror( R + 0 + 0) 107 | ALU_ASLM = 9'b10_001_00_00, // asl( M + 0 + 0) 108 | ALU_ROLM = 9'b10_001_00_11, // rol( M + 0 + 0) 109 | ALU_LSRM = 9'b11_001_00_00, // lsr( M + 0 + 0) 110 | ALU_RORM = 9'b11_001_00_11; // ror( M + 0 + 0) 111 | 112 | parameter 113 | // +H h PC BS +X +1 114 | AB_ZPGX = 10'b00_1_00_00_11_0, // AB=DI+XY HOLD 115 | AB_ABSX = 10'b10_1_00_10_01_0, // AB=DIDR+XY HOLD 116 | AB_PUSH = 10'b01_0_00_00_00_0, // AB=S 117 | AB_PULL = 10'b01_0_00_00_00_1, // AB=S+1 118 | AB_HOLD = 10'b10_0_00_11_00_0, // AB=HOLD 119 | AB_NEXT = 10'b10_0_00_11_00_1, // AB=HOLD+1 120 | AB_OPER = 10'b00_0_01_01_00_0, // AB=PC, PC = AB+1 121 | AB_FWRD = 10'b10_0_01_01_10_0, // AB=PC + DI PC = AB+1 122 | AB_JMP1 = 10'b10_0_01_10_00_1, // AB=DIDR+1, PC = AB+1 123 | AB_JMP0 = 10'b10_0_01_10_01_0, // AB=DIDR+XY, PC = AB+1 124 | AB_BACK = 10'b11_0_01_01_10_0, // AB=PC + FF,DI PC = AB+1 125 | AB_NMIV = 10'b01_0_10_00_00_0, // AB=S PC = NMI Vector 126 | AB_IRQV = 10'b01_0_11_00_00_0; // AB=S PC = IRQ Vector 127 | 128 | parameter 129 | WE___ = 2'b00, // read from this memory location 130 | WE_1_ = 2'b01, // write to this memory location 131 | WE_ST = 2'b10; // write only if opcode requires it 132 | 133 | parameter 134 | DR___ = 1'b0, // do not load DR, keep old value 135 | DR_DI = 1'b1; // load DR with DI 136 | 137 | parameter 138 | DO____ = 2'bxx, 139 | DO_ALU = 2'b00, 140 | DO_PCL = 2'b01, 141 | DO_PCH = 2'b10, 142 | DO_PHP = 2'b11; 143 | 144 | parameter 145 | S____ = 2'b00, 146 | S_INC = 2'b01, 147 | S_DEC = 2'b10; 148 | -------------------------------------------------------------------------------- /doc/sequence.md: -------------------------------------------------------------------------------- 1 | Instruction sequences 2 | ===================== 3 | 4 | These are all important instruction sequences used in the model. In these 5 | examples, the code is located at F800 and further. Some examples use the 6 | 'Z' register. This is a register that contains the constant value 0. 7 | 8 | * The value 'AB' is the combinatorial output of the address bus. 9 | 10 | * The 'PC' value is 16 bit register that holds the current program 11 | counter in most cycles, but can be temporarily wrong in some cases. 12 | 13 | * The 'DB' value represents the data bus, and can be either input or 14 | output. When reading from the data bus, the DB value corresponds to 15 | the AB value from the line above, because the memory is synchronous and 16 | takes 1 clock cycle to produce the data. When writing, the AB/DB values 17 | on the same row are used together. If a read cycle is immediately followed 18 | by a write cycle, the read data and write data are valid at the same time. 19 | 20 | * The 'DR' is a data register that can hold a copy of a value seen on the 21 | data bus. This value may be used subsequently in the ALU, for instance 22 | in the LDA instruction, or sometimes it can hold part of the address, 23 | for instance in absolute addressing modes. 24 | 25 | * Whenever a cell in the table is empty, then its value is not relevant. 26 | 27 | All instruction decoding happens in the SYNC state. Instruction execution 28 | starts in the next cycle. Writing results in registers, such as loading 29 | the memory value in A during the LDA instructions always happens in the 30 | SYNC cycle of the next instruction. 31 | 32 | LDA IMM 33 | ------- 34 | 35 | example: LDA #$55, sequence A9 55 36 | 37 | | state | AB | PC | DI | DR | DO | Comment | 38 | |:-----:|:----:|:----:|:--:|:--:|:--:|---------------| 39 | | | F800 | | | | | | 40 | | SYNC | F801 | F801 | A9 | | | | 41 | | IMM0 | F802 | F802 | 55 | | | | 42 | | SYNC | F803 | F803 | | 55 | | store DR in A | 43 | 44 | 45 | LDA ZP 46 | ------ 47 | example: LDA #$12, sequence A5 12. The location $12 48 | contains the value $55 49 | 50 | | state | AB | PC | DI | DR | DO | Comment | 51 | |:-----:|:----:|:----:|:--:|:--:|:--:|---------------| 52 | | | F800 | | | | | | 53 | | SYNC | F801 | F801 | A5 | | | | 54 | | ZPG0 | 0012 | F802 | 12 | | | AB = DB + Z | 55 | | DATA | F802 | F802 | 55 | | | | 56 | | SYNC | F803 | F803 | | 55 | | store DR in A | 57 | 58 | The LDA ZP,X follows the same pattern, but uses +X instead 59 | of +Z in the ZPG0 state. 60 | 61 | LDA ABS 62 | ------- 63 | 64 | example: LDA $1234, sequence AD 34 12. The location $1234 65 | contains the value $55 66 | 67 | | state | AB | PC | DI | DR | DO | Comment | 68 | |:-----:|:----:|:----:|:--:|:--:|:--:|---------------| 69 | | | F800 | | | | | | 70 | | SYNC | F801 | F801 | AD | | | | 71 | | ABS0 | F802 | F802 | 34 | | | | 72 | | ABS1 | 1234 | F803 | 12 | 34 | | AB={DB,DR}+Z | 73 | | DATA | F803 | F803 | 55 | | | | 74 | | SYNC | F804 | F804 | | 55 | | store DR in A | 75 | 76 | The LDA ABS,X/Y instructions follow the same pattern, but use +X or +Y instead of +Z in the ABS1 state. 77 | 78 | LDA (ZP),Y 79 | ---------- 80 | 81 | example: LDA ($14),Y sequence B1 14. The location $14 82 | contains the value $32, location $15 contains $12, and Y=2. 83 | The location $1234 contains $55 84 | 85 | | state | AB | PC | DI | DR | DO | Comment | 86 | |:-----:|:----:|:----:|:--:|:--:|:--:|---------------| 87 | | | F800 | | | | | | 88 | | SYNC | F801 | F801 | B1 | | | | 89 | | IDX0 | 0014 | F802 | 14 | | | AB = DB+Z | 90 | | IDX1 | 0015 | F802 | 32 | | | AB = ABR+1 | 91 | | IDX2 | 1234 | F802 | 12 | 32 | | AB = {DR,DB}+Y | 92 | | DATA | F802 | F802 | 55 | | | AB = PC | 93 | | SYNC | F803 | F803 | | 55 | | store DR in A | 94 | 95 | The LDA (ZP) follows the same sequence, but adds Z register instead of Y in IDX2 state. 96 | The LDA (ZP,X) also follows same sequence, but adds X register instead of Z in IDX0 state 97 | 98 | The ORA, EOR, AND, ADC, SBC, and CMP instructions follow the same patterns, but have a different ALU operation. 99 | 100 | The STA instructions follow the same patterns, but perform a memory write when the effective 101 | address is on the bus in the ZPG0, ABS1, or IDX2 states. 102 | 103 | PHA 104 | --- 105 | example PHA, sequence 48, S=FF, A=55 106 | 107 | | state | AB | PC | DI | DR | DO | Comment | 108 | |:-----:|:----:|:----:|:--:|:--:|:--:|-----------------| 109 | | | F800 | | | | | | 110 | | SYNC | F801 | F801 | 48 | | | | 111 | | PHA0 | 01FF | F802 | | | 55 | write A to {1,S}| 112 | | SYNC | F802 | F802 | | | | AB = PC | 113 | 114 | PLA 115 | --- 116 | example PLA, sequence 48, S=FE 117 | 118 | | state | AB | PC | DI | DR | DO | Comment | 119 | |:-----:|:----:|:----:|:--:|:--:|:--:|----------------| 120 | | | F800 | | | | | | 121 | | SYNC | F801 | F801 | 48 | | | | 122 | | PHA0 | 01FF | F802 | 55 | | | | 123 | | SYNC | F802 | F802 | | 55 | | write 55 to A | 124 | 125 | INC ZP 126 | ------ 127 | example: INC $12, sequence E6 12. The location $12 128 | contains the value $55 129 | 130 | | state | AB | PC | DI | DR | DO | Comment | 131 | |:-----:|:----:|:----:|:--:|:--:|:--:|------------------| 132 | | | F800 | | | | | | 133 | | SYNC | F801 | F801 | E6 | | | | 134 | | ZPG0 | 0012 | F802 | 12 | | | AB = DB + Z | 135 | | DATA | F802 | F802 | 55 | | | load next opcode | 136 | | RDWR | 0012 | F803 | 56 | 55 | | write DR+1 | 137 | | SYNC | F803 | F803 | | | | | 138 | 139 | Note that this instruction interleaves fetching the next *opcode* with writing back the data. 140 | 141 | INC ABS 142 | ------ 143 | example: INC $1234, sequence EE 34 12. The location $1234 144 | contains the value $55 145 | 146 | | state | AB | PC | DI | DR | DO | Comment | 147 | |:-----:|:----:|:----:|:--:|:--:|:--:|------------------| 148 | | | F800 | | | | | | 149 | | SYNC | F801 | F801 | EE | | | | 150 | | ABS0 | F802 | F802 | 34 | | | | 151 | | ABS1 | 1234 | F803 | 12 | 34 | | AB = {DB,DR}+Z | 152 | | DATA | F803 | F803 | 55 | | | load next opcode | 153 | | RDWR | 1234 | F804 |*op*| 55 | 56 | write DR+1 | 154 | | SYNC | F804 | F804 | | | | | 155 | 156 | Just like the INC ZP, this instruction interleaves fetching the next *opcode* with writing back the data. 157 | 158 | INX 159 | --- 160 | example INX, sequence E8. This is a very simple instruction, executed in a single cycle. 161 | All other register implied instructions follow the same pattern, but use a different ALU 162 | operation, and different register file controls. 163 | 164 | | state | AB | PC | DI | DR | DO | Comment | 165 | |:-----:|:----:|:----:|:--:|:--:|:--:|------------------| 166 | | | F800 | | | | | | 167 | | SYNC | F801 | F801 | E8 | | | write ALU to X | 168 | | SYNC | F802 | F802 | | | | | 169 | 170 | 171 | BRA 172 | --- 173 | example BCS followed by BCC with C=0, sequence B0 FE 90 FC 174 | 175 | | state | AB | PC | DI | DR | DO | Comment | 176 | |:-----:|:----:|:----:|:--:|:--:|:--:|---------------------| 177 | | | F800 | | | | | | 178 | | SYNC | F801 | F801 | B0 | | | | 179 | | BRA0 | F802 | F802 | FE | | | AB = PC | 180 | | SYNC | F803 | F803 | 90 | | | | 181 | | BRA0 | F800 | F804 | FC | | | AB = PC+{FF,DB} | 182 | 183 | JMP 184 | --- 185 | example JMP to $1234, sequence 4C 34 12 186 | 187 | | state | AB | PC | DI | DR | DO | Comment | 188 | |:-----:|:----:|:----:|:--:|:--:|:--:|------------------| 189 | | | F800 | | | | | | 190 | | SYNC | F801 | F801 | 4C | | | | 191 | | JMP0 | F802 | F802 | 34 | | | | 192 | | JMP1 | 1234 | F803 | 12 | 34 | | AB = {DB,DR} | 193 | | SYNC | 1235 | 1235 | | | | | 194 | 195 | JSR 196 | --- 197 | 198 | example JSR to $1234, sequence 20 34 12 199 | 200 | | state | AB | PC | DI | DR | DO | Comment | 201 | |:-----:|:----:|:----:|:--:|:--:|:--:|--------------------| 202 | | | F800 | | | | | | 203 | | SYNC | F801 | F801 | 20 | | | | 204 | | JSR0 | 01FF | F802 | 34 | | F8 | write PCH to {1,S} | 205 | | JSR1 | 01FE | F802 | | 34 | 02 | write PCL to {1,S} | 206 | | JSR2 | F802 | F802 | | 34 | | | 207 | | JSR3 | 1234 | F802 | 12 | 34 | | AB = {DB,DR} | 208 | | SYNC | 1235 | 1235 | | | | | 209 | 210 | Note that the first operand byte (34) is read in the SYNC state, but 211 | only becomes available on the DI bus the next cycle, when the PCH value 212 | is written to the stack. 213 | 214 | 215 | -------------------------------------------------------------------------------- /cpu.v: -------------------------------------------------------------------------------- 1 | /* 2 | * verilog model of 65C02 CPU. 3 | * 4 | * (C) Arlet Ottens, 5 | * 6 | */ 7 | 8 | module cpu( 9 | input clk, // CPU clock 10 | input RST, // RST signal 11 | output [15:0] AB, // address bus (combinatorial) 12 | output sync, // start of new instruction 13 | input [7:0] DI, // data bus input 14 | output reg [7:0] DO, // data bus output 15 | output WE, // write enable 16 | input IRQ, // interrupt request 17 | input NMI, // non-maskable interrupt request 18 | input RDY, // Ready signal. Pauses CPU when RDY=0 19 | input debug ); // debug for simulation 20 | 21 | wire [15:0] PC; // program counter 22 | 23 | reg [7:0] DR; // data register, registered DI 24 | wire [7:0] IR; // instruction register 25 | 26 | wire B = 1; 27 | reg N, V, D, I, Z, C; // processor status flags 28 | wire [7:0] P = { N, V, 1'b1, B, D, I, Z, C }; 29 | 30 | wire alu_C, alu_Z, alu_V, alu_N; 31 | wire [7:0] alu_out; 32 | 33 | `include "define.i" 34 | 35 | /* 36 | * control bits 37 | */ 38 | 39 | reg [4:0] state; 40 | wire [4:0] init_state; 41 | assign sync = (state == SYNC); 42 | reg [18:0] control; 43 | 44 | wire [1:0] ins_type = control[18:17]; 45 | 46 | wire adc_sbc = (ins_type == FLAG_ADD); 47 | wire cmp = (ins_type == FLAG_CMP); 48 | wire bit_isn = (ins_type == FLAG_BIT); 49 | 50 | // special instructions 51 | reg clc, sec, cld, sed, cli, sei, clv, plp, php, rti, txs; 52 | 53 | wire store = control[16]; 54 | wire load = control[15]; 55 | 56 | wire [8:0] alu_op = control[10:2]; 57 | wire shift = alu_op[8]; 58 | reg [3:0] cond_code; 59 | reg cond; 60 | 61 | // control bits per cycle 62 | reg [18:0] bus_op; 63 | wire [9:0] ab_op = bus_op[9:0]; 64 | wire [1:0] we_op = bus_op[11:10]; 65 | wire dr_di = bus_op[12]; 66 | wire [1:0] do_op = bus_op[14:13]; 67 | wire push = bus_op[18]; 68 | wire pull = bus_op[17]; 69 | 70 | wire [7:0] S; // stack pointer register 71 | wire [7:0] R; // register from regfile to ALU 72 | wire [7:0] XY; // index register from regfile to AB 73 | 74 | 75 | regfile regfile( 76 | .clk(clk), 77 | .reg_idx(control[1:0] & bus_op[16:15]), 78 | .reg_src(control[14:13]), 79 | .reg_dst(control[12:11]), 80 | .reg_we(load & ~store & sync), 81 | .src(R), 82 | .idx(XY), 83 | .dst(alu_out), 84 | .S(S), 85 | .txs(txs), 86 | .push(push), 87 | .pull(pull) ); 88 | 89 | /* 90 | * ALU 91 | */ 92 | alu alu( 93 | .C(C), 94 | .S(S), 95 | .R(R), 96 | .DR(DR), 97 | .DI(DI), 98 | .alu_out(alu_out), 99 | .alu_op(alu_op), 100 | .alu_C(alu_C), 101 | .alu_Z(alu_Z), 102 | .alu_N(alu_N), 103 | .alu_V(alu_V) ); 104 | 105 | 106 | /* 107 | * address bus 108 | */ 109 | ab ab( 110 | .clk(clk), 111 | .RST(RST), 112 | .ab_op(ab_op), 113 | .S(S), 114 | .DI(DI), 115 | .DR(DR), 116 | .XY(XY), 117 | .AB(AB), 118 | .PC(PC) ); 119 | 120 | /* 121 | * write enable 122 | * 123 | * we_op[0] is always write 124 | * we_op[1] is write when 'store' is set. 125 | */ 126 | assign WE = we_op[0] | (we_op[1] & store); 127 | 128 | /* 129 | * Data register 130 | */ 131 | always @(posedge clk) 132 | if( dr_di ) 133 | DR <= DI; 134 | 135 | /* 136 | * data output 137 | */ 138 | always @* 139 | case( do_op ) 140 | DO_ALU: DO = alu_out; 141 | DO_PHP: DO = php ? P : alu_out; 142 | DO_PCL: DO = PC[7:0]; 143 | DO_PCH: DO = PC[15:8]; 144 | endcase 145 | 146 | /* 147 | * flags update 148 | */ 149 | 150 | /* 151 | * negative flag 152 | */ 153 | always @(posedge clk) 154 | case( state ) 155 | RTS0: if( rti ) N <= DI[7]; 156 | SYNC: if( plp ) N <= DI[7]; 157 | else if( bit_isn ) N <= DR[7]; 158 | else if( load | cmp ) N <= alu_N; 159 | endcase 160 | 161 | 162 | /* 163 | * overflow flag 164 | */ 165 | always @(posedge clk) 166 | case( state ) 167 | RTS0: if( rti ) V <= DI[6]; 168 | SYNC: if( plp ) V <= DI[6]; 169 | else if( clv ) V <= 0; 170 | else if( bit_isn ) V <= DR[6]; 171 | else if( adc_sbc ) V <= alu_V; 172 | endcase 173 | 174 | /* 175 | * decimal flag 176 | */ 177 | always @(posedge clk) 178 | case( state ) 179 | RTS0: if( rti ) D <= DI[3]; 180 | SYNC: if( plp ) D <= DI[3]; 181 | else if( cld ) D <= 0; 182 | else if( sed ) D <= 1; 183 | endcase 184 | 185 | /* 186 | * interrupt flag 187 | */ 188 | always @(posedge clk) 189 | case( state ) 190 | BRK3: I <= 1; 191 | RTS0: if( rti ) I <= DI[2]; 192 | SYNC: if( plp ) I <= DI[2]; 193 | else if( cli ) I <= 0; 194 | else if( sei ) I <= 1; 195 | endcase 196 | 197 | /* 198 | * zero flag 199 | */ 200 | always @(posedge clk) 201 | case( state ) 202 | RTS0: if( rti ) Z <= DI[1]; 203 | SYNC: if( plp ) Z <= DI[1]; 204 | else if( load | cmp | bit_isn ) Z <= alu_Z; 205 | endcase 206 | 207 | /* 208 | * carry flag 209 | */ 210 | always @(posedge clk) 211 | case( state ) 212 | RTS0: if( rti ) C <= DI[0]; 213 | SYNC: if( plp ) C <= DI[0]; 214 | else if( clc ) C <= 0; 215 | else if( sec ) C <= 1; 216 | else if( cmp | shift | adc_sbc ) C <= alu_C; 217 | endcase 218 | 219 | /* 220 | * DI hold register, holds the DI value containing the 221 | * next opcode for a couple of instructions where the 222 | * opcode is fetched during instruction execution. 223 | */ 224 | 225 | reg [8:0] DIHOLD = {9'h1ea}; 226 | 227 | always @(posedge clk) 228 | case( state ) 229 | PLA0: DIHOLD <= {1'b1, DI}; 230 | PHA0: DIHOLD <= {1'b1, DI}; 231 | RMW1: DIHOLD <= {1'b1, DI}; 232 | default: DIHOLD <= {1'b0, DI}; 233 | endcase 234 | 235 | assign IR = DIHOLD[8] ? DIHOLD[7:0] : DI; 236 | 237 | /* 238 | * condition code 239 | */ 240 | always @(posedge clk) 241 | cond_code <= IR[7:4]; 242 | 243 | always @* 244 | casez( cond_code ) 245 | 4'b000?: cond = ~N; 246 | 4'b001?: cond = N; 247 | 4'b010?: cond = ~V; 248 | 4'b011?: cond = V; 249 | 4'b1000: cond = 1; 250 | 4'b1001: cond = ~C; 251 | 4'b101?: cond = C; 252 | 4'b110?: cond = ~Z; 253 | 4'b111?: cond = Z; 254 | endcase 255 | 256 | /* 257 | * state machine. In the SYNC state, we decode the current 258 | * opcode, and then move to 'init_state'. From there, we follow 259 | * a sequence of cycles until we get back to the SYNC state for 260 | * the next opcode. 261 | */ 262 | always @(posedge clk) 263 | if( RST ) 264 | state <= BRK3; 265 | else case( state ) 266 | SYNC: state <= init_state; 267 | ABS0: state <= ABS1; 268 | ABS1: state <= DATA; 269 | ABW0: state <= ABW1; 270 | ABW1: state <= RMW0; 271 | BRA0: state <= SYNC; 272 | BRK0: state <= BRK1; 273 | BRK1: state <= BRK2; 274 | BRK2: state <= BRK3; 275 | BRK3: state <= JMP0; 276 | DATA: state <= SYNC; 277 | IDX0: state <= IDX1; 278 | IDX1: state <= IDX2; 279 | IDX2: state <= DATA; 280 | IMM0: state <= SYNC; 281 | IND0: state <= IND1; 282 | IND1: state <= JMP0; 283 | JMP0: state <= JMP1; 284 | JMP1: state <= SYNC; 285 | JSR0: state <= JSR1; 286 | JSR1: state <= JSR2; 287 | JSR2: state <= JMP1; 288 | PHA0: state <= SYNC; 289 | PLA0: state <= SYNC; 290 | RMW0: state <= RMW1; 291 | RMW1: state <= SYNC; 292 | RTI0: state <= RTS0; 293 | RTS0: state <= RTS1; 294 | RTS1: state <= RTS2; 295 | RTS2: state <= SYNC; 296 | ZPG0: state <= DATA; 297 | ZPW0: state <= RMW0; 298 | endcase 299 | 300 | /* 301 | * decode vector 302 | */ 303 | reg [23:0] decode; 304 | 305 | assign init_state = decode[4:0]; 306 | 307 | 308 | /* 309 | * control logic to determine operations per cycle 310 | */ 311 | always @* 312 | case( state ) 313 | ABS0: bus_op = { S____, IDX___, DO____, DR_DI, WE___, AB_OPER }; 314 | ABS1: bus_op = { S____, IDX_XY, DO_ALU, DR___, WE_ST, AB_ABSX }; 315 | ABW0: bus_op = { S____, IDX___, DO____, DR_DI, WE___, AB_OPER }; 316 | ABW1: bus_op = { S____, IDX_XY, DO____, DR___, WE___, AB_ABSX }; 317 | BRA0: if( cond & DI[7] ) bus_op = { S____, IDX___, DO____, DR___, WE___, AB_BACK }; 318 | else if( cond ) bus_op = { S____, IDX___, DO____, DR___, WE___, AB_FWRD }; 319 | else bus_op = { S____, IDX___, DO____, DR___, WE___, AB_OPER }; 320 | BRK0: bus_op = { S_DEC, IDX___, DO_PCH, DR___, WE_1_, AB_PUSH }; 321 | BRK1: bus_op = { S_DEC, IDX___, DO_PCL, DR___, WE_1_, AB_PUSH }; 322 | BRK2: bus_op = { S_DEC, IDX___, DO_PHP, DR___, WE_1_, AB_IRQV }; 323 | BRK3: bus_op = { S____, IDX___, DO____, DR___, WE___, AB_OPER }; 324 | DATA: bus_op = { S____, IDX___, DO____, DR_DI, WE___, AB_OPER }; 325 | IDX0: bus_op = { S____, IDX_X_, DO____, DR_DI, WE___, AB_ZPGX }; 326 | IDX1: bus_op = { S____, IDX___, DO____, DR_DI, WE___, AB_NEXT }; 327 | IDX2: bus_op = { S____, IDX__Y, DO_ALU, DR___, WE_ST, AB_ABSX }; 328 | IMM0: bus_op = { S____, IDX___, DO____, DR_DI, WE___, AB_OPER }; 329 | IND0: bus_op = { S____, IDX___, DO____, DR_DI, WE___, AB_OPER }; 330 | IND1: bus_op = { S____, IDX_X_, DO____, DR___, WE___, AB_JMP0 }; 331 | JMP0: bus_op = { S____, IDX___, DO____, DR_DI, WE___, AB_OPER }; 332 | JMP1: bus_op = { S____, IDX___, DO____, DR___, WE___, AB_JMP0 }; 333 | JSR0: bus_op = { S_DEC, IDX___, DO_PCH, DR_DI, WE_1_, AB_PUSH }; 334 | JSR1: bus_op = { S_DEC, IDX___, DO_PCL, DR___, WE_1_, AB_PUSH }; 335 | JSR2: bus_op = { S____, IDX___, DO____, DR___, WE___, AB_OPER }; 336 | PHA0: bus_op = { S_DEC, IDX___, DO_PHP, DR___, WE_1_, AB_PUSH }; 337 | PLA0: bus_op = { S_INC, IDX___, DO____, DR_DI, WE___, AB_PULL }; 338 | RMW0: bus_op = { S____, IDX___, DO____, DR_DI, WE___, AB_OPER }; 339 | RMW1: bus_op = { S____, IDX___, DO_ALU, DR___, WE_1_, AB_HOLD }; 340 | RTI0: bus_op = { S_INC, IDX___, DO____, DR___, WE___, AB_PULL }; 341 | RTS0: bus_op = { S_INC, IDX___, DO____, DR___, WE___, AB_PULL }; 342 | RTS1: bus_op = { S_INC, IDX___, DO____, DR_DI, WE___, AB_PULL }; 343 | RTS2: if( rti ) bus_op = { S____, IDX___, DO____, DR___, WE___, AB_JMP0 }; 344 | else bus_op = { S____, IDX___, DO____, DR___, WE___, AB_JMP1 }; 345 | SYNC: bus_op = { S____, IDX___, DO____, DR___, WE___, AB_OPER }; 346 | ZPG0: bus_op = { S____, IDX_XY, DO_ALU, DR___, WE_ST, AB_ZPGX }; 347 | ZPW0: bus_op = { S____, IDX_XY, DO____, DR___, WE___, AB_ZPGX }; 348 | endcase 349 | 350 | /* 351 | * control vector 352 | */ 353 | always @(posedge clk) 354 | if( sync ) begin 355 | control <= decode[23:5]; 356 | clc <= (IR == 8'h18); 357 | sec <= (IR == 8'h38); 358 | cld <= (IR == 8'hD8); 359 | sed <= (IR == 8'hF8); 360 | cli <= (IR == 8'h58); 361 | sei <= (IR == 8'h78); 362 | rti <= (IR == 8'h40); 363 | clv <= (IR == 8'hB8); 364 | php <= (IR == 8'h08) || (IR == 8'h00); 365 | plp <= (IR == 8'h28); 366 | txs <= (IR == 8'h9A); 367 | end 368 | 369 | /* 370 | * decode vector 371 | */ 372 | always @* 373 | case( IR ) 374 | // type L/S SRC DST ALU YX MODE 375 | 8'h6D: decode = { FLAG_ADD, LDA, SRC_A, DST_A, ALU_ADC , IZ, ABS0 }; // ADC ABS 376 | 8'h7D: decode = { FLAG_ADD, LDA, SRC_A, DST_A, ALU_ADC , IX, ABS0 }; // ADC ABS,X 377 | 8'h79: decode = { FLAG_ADD, LDA, SRC_A, DST_A, ALU_ADC , IY, ABS0 }; // ADC ABS,Y 378 | 8'h69: decode = { FLAG_ADD, LDA, SRC_A, DST_A, ALU_ADC , IZ, IMM0 }; // ADC #IMM 379 | 8'h65: decode = { FLAG_ADD, LDA, SRC_A, DST_A, ALU_ADC , IZ, ZPG0 }; // ADC ZP 380 | 8'h72: decode = { FLAG_ADD, LDA, SRC_A, DST_A, ALU_ADC , IZ, IDX0 }; // ADC (ZP) 381 | 8'h61: decode = { FLAG_ADD, LDA, SRC_A, DST_A, ALU_ADC , IX, IDX0 }; // ADC (ZP,X) 382 | 8'h75: decode = { FLAG_ADD, LDA, SRC_A, DST_A, ALU_ADC , IX, ZPG0 }; // ADC ZP,X 383 | 8'h71: decode = { FLAG_ADD, LDA, SRC_A, DST_A, ALU_ADC , IY, IDX0 }; // ADC (ZP),Y 384 | 385 | 8'hED: decode = { FLAG_ADD, LDA, SRC_A, DST_A, ALU_SBC , IZ, ABS0 }; // SBC ABS 386 | 8'hFD: decode = { FLAG_ADD, LDA, SRC_A, DST_A, ALU_SBC , IX, ABS0 }; // SBC ABS,X 387 | 8'hF9: decode = { FLAG_ADD, LDA, SRC_A, DST_A, ALU_SBC , IY, ABS0 }; // SBC ABS,Y 388 | 8'hE9: decode = { FLAG_ADD, LDA, SRC_A, DST_A, ALU_SBC , IZ, IMM0 }; // SBC #IMM 389 | 8'hE5: decode = { FLAG_ADD, LDA, SRC_A, DST_A, ALU_SBC , IZ, ZPG0 }; // SBC ZP 390 | 8'hF2: decode = { FLAG_ADD, LDA, SRC_A, DST_A, ALU_SBC , IZ, IDX0 }; // SBC (ZP) 391 | 8'hE1: decode = { FLAG_ADD, LDA, SRC_A, DST_A, ALU_SBC , IX, IDX0 }; // SBC (ZP,X) 392 | 8'hF5: decode = { FLAG_ADD, LDA, SRC_A, DST_A, ALU_SBC , IX, ZPG0 }; // SBC ZP,X 393 | 8'hF1: decode = { FLAG_ADD, LDA, SRC_A, DST_A, ALU_SBC , IY, IDX0 }; // SBC (ZP),Y 394 | 395 | 8'h2D: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_AND , IZ, ABS0 }; // AND ABS 396 | 8'h3D: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_AND , IX, ABS0 }; // AND ABS,X 397 | 8'h39: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_AND , IY, ABS0 }; // AND ABS,Y 398 | 8'h29: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_AND , IZ, IMM0 }; // AND #IMM 399 | 8'h25: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_AND , IZ, ZPG0 }; // AND ZP 400 | 8'h32: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_AND , IZ, IDX0 }; // AND (ZP) 401 | 8'h21: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_AND , IX, IDX0 }; // AND (ZP,X) 402 | 8'h35: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_AND , IX, ZPG0 }; // AND ZP,X 403 | 8'h31: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_AND , IY, IDX0 }; // AND (ZP),Y 404 | 405 | 8'h0D: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_ORA , IZ, ABS0 }; // ORA ABS 406 | 8'h1D: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_ORA , IX, ABS0 }; // ORA ABS,X 407 | 8'h19: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_ORA , IY, ABS0 }; // ORA ABS,Y 408 | 8'h09: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_ORA , IZ, IMM0 }; // ORA #IMM 409 | 8'h05: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_ORA , IZ, ZPG0 }; // ORA ZP 410 | 8'h12: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_ORA , IZ, IDX0 }; // ORA (ZP) 411 | 8'h01: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_ORA , IX, IDX0 }; // ORA (ZP,X) 412 | 8'h15: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_ORA , IX, ZPG0 }; // ORA ZP,X 413 | 8'h11: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_ORA , IY, IDX0 }; // ORA (ZP),Y 414 | 415 | 8'hAD: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_LDA , IZ, ABS0 }; // LDA ABS 416 | 8'hBD: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_LDA , IX, ABS0 }; // LDA ABS,X 417 | 8'hB9: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_LDA , IY, ABS0 }; // LDA ABS,Y 418 | 8'hA9: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_LDA , IZ, IMM0 }; // LDA #IMM 419 | 8'hA5: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_LDA , IZ, ZPG0 }; // LDA ZP 420 | 8'hB2: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_LDA , IZ, IDX0 }; // LDA (ZP) 421 | 8'hA1: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_LDA , IX, IDX0 }; // LDA (ZP,X) 422 | 8'hB5: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_LDA , IX, ZPG0 }; // LDA ZP,X 423 | 8'hB1: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_LDA , IY, IDX0 }; // LDA (ZP),Y 424 | 425 | 8'hCD: decode = { FLAG_CMP, NOP, SRC_A, DST__, ALU_CMP , IZ, ABS0 }; // CMP ABS 426 | 8'hDD: decode = { FLAG_CMP, NOP, SRC_A, DST__, ALU_CMP , IX, ABS0 }; // CMP ABS,X 427 | 8'hD9: decode = { FLAG_CMP, NOP, SRC_A, DST__, ALU_CMP , IY, ABS0 }; // CMP ABS,Y 428 | 8'hC9: decode = { FLAG_CMP, NOP, SRC_A, DST__, ALU_CMP , IZ, IMM0 }; // CMP #IMM 429 | 8'hC5: decode = { FLAG_CMP, NOP, SRC_A, DST__, ALU_CMP , IZ, ZPG0 }; // CMP ZP 430 | 8'hD2: decode = { FLAG_CMP, NOP, SRC_A, DST__, ALU_CMP , IZ, IDX0 }; // CMP (ZP) 431 | 8'hC1: decode = { FLAG_CMP, NOP, SRC_A, DST__, ALU_CMP , IX, IDX0 }; // CMP (ZP,X) 432 | 8'hD5: decode = { FLAG_CMP, NOP, SRC_A, DST__, ALU_CMP , IX, ZPG0 }; // CMP ZP,X 433 | 8'hD1: decode = { FLAG_CMP, NOP, SRC_A, DST__, ALU_CMP , IY, IDX0 }; // CMP (ZP),Y 434 | 435 | 8'h4D: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_EOR , IZ, ABS0 }; // EOR ABS 436 | 8'h5D: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_EOR , IX, ABS0 }; // EOR ABS,X 437 | 8'h59: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_EOR , IY, ABS0 }; // EOR ABS,Y 438 | 8'h49: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_EOR , IZ, IMM0 }; // EOR #IMM 439 | 8'h45: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_EOR , IZ, ZPG0 }; // EOR ZP 440 | 8'h52: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_EOR , IZ, IDX0 }; // EOR (ZP) 441 | 8'h41: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_EOR , IX, IDX0 }; // EOR (ZP,X) 442 | 8'h55: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_EOR , IX, ZPG0 }; // EOR ZP,X 443 | 8'h51: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_EOR , IY, IDX0 }; // EOR (ZP),Y 444 | 445 | 8'h8D: decode = { FLAG____, STA, SRC_A, DST__, ALU_REG , IZ, ABS0 }; // STA ABS 446 | 8'h9D: decode = { FLAG____, STA, SRC_A, DST__, ALU_REG , IX, ABS0 }; // STA ABS,X 447 | 8'h99: decode = { FLAG____, STA, SRC_A, DST__, ALU_REG , IY, ABS0 }; // STA ABS,Y 448 | 8'h85: decode = { FLAG____, STA, SRC_A, DST__, ALU_REG , IZ, ZPG0 }; // STA ZP 449 | 8'h92: decode = { FLAG____, STA, SRC_A, DST__, ALU_REG , IZ, IDX0 }; // STA (ZP) 450 | 8'h81: decode = { FLAG____, STA, SRC_A, DST__, ALU_REG , IX, IDX0 }; // STA (ZP,X) 451 | 8'h95: decode = { FLAG____, STA, SRC_A, DST__, ALU_REG , IX, ZPG0 }; // STA ZP,X 452 | 8'h91: decode = { FLAG____, STA, SRC_A, DST__, ALU_REG , IY, IDX0 }; // STA (ZP),Y 453 | 454 | 8'h0A: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_ASLA, IZ, SYNC }; // ASL A 455 | 8'h4A: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_LSRA, IZ, SYNC }; // LSR A 456 | 8'h2A: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_ROLA, IZ, SYNC }; // ROL A 457 | 8'h6A: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_RORA, IZ, SYNC }; // ROR A 458 | 459 | 8'h0E: decode = { FLAG____, RMW, SRC__, DST__, ALU_ASLM, IZ, ABW0 }; // ASL ABS 460 | 8'h1E: decode = { FLAG____, RMW, SRC__, DST__, ALU_ASLM, IX, ABW0 }; // ASL ABS,X 461 | 8'h06: decode = { FLAG____, RMW, SRC__, DST__, ALU_ASLM, IZ, ZPW0 }; // ASL ZP 462 | 8'h16: decode = { FLAG____, RMW, SRC__, DST__, ALU_ASLM, IX, ZPW0 }; // ASL ZP,X 463 | 464 | 8'h4E: decode = { FLAG____, RMW, SRC__, DST__, ALU_LSRM, IZ, ABW0 }; // LSR ABS 465 | 8'h5E: decode = { FLAG____, RMW, SRC__, DST__, ALU_LSRM, IX, ABW0 }; // LSR ABS,X 466 | 8'h46: decode = { FLAG____, RMW, SRC__, DST__, ALU_LSRM, IZ, ZPW0 }; // LSR ZP 467 | 8'h56: decode = { FLAG____, RMW, SRC__, DST__, ALU_LSRM, IX, ZPW0 }; // LSR ZP,X 468 | 469 | 8'h2E: decode = { FLAG____, RMW, SRC__, DST__, ALU_ROLM, IZ, ABW0 }; // ROL ABS 470 | 8'h3E: decode = { FLAG____, RMW, SRC__, DST__, ALU_ROLM, IX, ABW0 }; // ROL ABS,X 471 | 8'h26: decode = { FLAG____, RMW, SRC__, DST__, ALU_ROLM, IZ, ZPW0 }; // ROL ZP 472 | 8'h36: decode = { FLAG____, RMW, SRC__, DST__, ALU_ROLM, IX, ZPW0 }; // ROL ZP,X 473 | 474 | 8'h6E: decode = { FLAG____, RMW, SRC__, DST__, ALU_RORM, IZ, ABW0 }; // ROR ABS 475 | 8'h7E: decode = { FLAG____, RMW, SRC__, DST__, ALU_RORM, IX, ABW0 }; // ROR ABS,X 476 | 8'h66: decode = { FLAG____, RMW, SRC__, DST__, ALU_RORM, IZ, ZPW0 }; // ROR ZP 477 | 8'h76: decode = { FLAG____, RMW, SRC__, DST__, ALU_RORM, IX, ZPW0 }; // ROR ZP,X 478 | 479 | 8'h90: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IZ, BRA0 }; // BCC 480 | 8'hB0: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IZ, BRA0 }; // BCS 481 | 8'hF0: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IZ, BRA0 }; // BEQ 482 | 8'h30: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IZ, BRA0 }; // BMI 483 | 8'hD0: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IZ, BRA0 }; // BNE 484 | 8'h10: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IZ, BRA0 }; // BPL 485 | 8'h80: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IZ, BRA0 }; // BRA 486 | 8'h50: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IZ, BRA0 }; // BVC 487 | 8'h70: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IZ, BRA0 }; // BVS 488 | 489 | 8'h2C: decode = { FLAG_BIT, NOP, SRC_A, DST__, ALU_AND , IZ, ABS0 }; // BIT ABS 490 | 8'h3C: decode = { FLAG_BIT, NOP, SRC_A, DST__, ALU_AND , IX, ABS0 }; // BIT ABS,X 491 | 8'h89: decode = { FLAG_BIT, NOP, SRC_A, DST__, ALU_AND , IZ, IMM0 }; // BIT #IMM 492 | 8'h24: decode = { FLAG_BIT, NOP, SRC_A, DST__, ALU_AND , IZ, ZPG0 }; // BIT ZP 493 | 8'h34: decode = { FLAG_BIT, NOP, SRC_A, DST__, ALU_AND , IX, ZPG0 }; // BIT ZP,X 494 | 495 | 8'h18: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IZ, SYNC }; // CLC 496 | 8'hD8: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IZ, SYNC }; // CLD 497 | 8'h58: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IZ, SYNC }; // CLI 498 | 8'hB8: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IZ, SYNC }; // CLV 499 | 8'h38: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IZ, SYNC }; // SEC 500 | 8'hF8: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IZ, SYNC }; // SED 501 | 8'h78: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IZ, SYNC }; // SEI 502 | 8'hEA: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IZ, SYNC }; // NOP 503 | 504 | 8'hEC: decode = { FLAG_CMP, NOP, SRC_X, DST__, ALU_CMP , IZ, ABS0 }; // CPX ABS 505 | 8'hE0: decode = { FLAG_CMP, NOP, SRC_X, DST__, ALU_CMP , IZ, IMM0 }; // CPX #IMM 506 | 8'hE4: decode = { FLAG_CMP, NOP, SRC_X, DST__, ALU_CMP , IZ, ZPG0 }; // CPX ZP 507 | 8'hCC: decode = { FLAG_CMP, NOP, SRC_Y, DST__, ALU_CMP , IZ, ABS0 }; // CPY ABS 508 | 8'hC0: decode = { FLAG_CMP, NOP, SRC_Y, DST__, ALU_CMP , IZ, IMM0 }; // CPY #IMM 509 | 8'hC4: decode = { FLAG_CMP, NOP, SRC_Y, DST__, ALU_CMP , IZ, ZPG0 }; // CPY ZP 510 | 511 | 8'hCE: decode = { FLAG____, RMW, SRC__, DST__, ALU_DECM, IZ, ABW0 }; // DEC ABS 512 | 8'hDE: decode = { FLAG____, RMW, SRC__, DST__, ALU_DECM, IX, ABW0 }; // DEC ABS,X 513 | 8'hC6: decode = { FLAG____, RMW, SRC__, DST__, ALU_DECM, IZ, ZPW0 }; // DEC ZP 514 | 8'hD6: decode = { FLAG____, RMW, SRC__, DST__, ALU_DECM, IX, ZPW0 }; // DEC ZP,X 515 | 516 | 8'hEE: decode = { FLAG____, RMW, SRC__, DST__, ALU_INCM, IZ, ABW0 }; // INC ABS 517 | 8'hFE: decode = { FLAG____, RMW, SRC__, DST__, ALU_INCM, IX, ABW0 }; // INC ABS,X 518 | 8'hE6: decode = { FLAG____, RMW, SRC__, DST__, ALU_INCM, IZ, ZPW0 }; // INC ZP 519 | 8'hF6: decode = { FLAG____, RMW, SRC__, DST__, ALU_INCM, IX, ZPW0 }; // INC ZP,X 520 | 521 | 8'h3A: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_DECA, IZ, SYNC }; // DEA 522 | 8'hCA: decode = { FLAG____, LDA, SRC_X, DST_X, ALU_DECA, IZ, SYNC }; // DEX 523 | 8'h88: decode = { FLAG____, LDA, SRC_Y, DST_Y, ALU_DECA, IZ, SYNC }; // DEY 524 | 8'h1A: decode = { FLAG____, LDA, SRC_A, DST_A, ALU_INCA, IZ, SYNC }; // INA 525 | 8'hE8: decode = { FLAG____, LDA, SRC_X, DST_X, ALU_INCA, IZ, SYNC }; // INX 526 | 8'hC8: decode = { FLAG____, LDA, SRC_Y, DST_Y, ALU_INCA, IZ, SYNC }; // INY 527 | 8'hAA: decode = { FLAG____, LDA, SRC_A, DST_X, ALU_REG , IZ, SYNC }; // TAX 528 | 8'hA8: decode = { FLAG____, LDA, SRC_A, DST_Y, ALU_REG , IZ, SYNC }; // TAY 529 | 8'hBA: decode = { FLAG____, LDA, SRC__, DST_X, ALU_TSX , IZ, SYNC }; // TSX 530 | 8'h8A: decode = { FLAG____, LDA, SRC_X, DST_A, ALU_REG , IZ, SYNC }; // TXA 531 | 8'h9A: decode = { FLAG____, NOP, SRC_X, DST__, ALU_REG , IZ, SYNC }; // TXS 532 | 8'h98: decode = { FLAG____, LDA, SRC_Y, DST_A, ALU_REG , IZ, SYNC }; // TYA 533 | 534 | 8'h00: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IZ, BRK0 }; // BRK 535 | 8'h4C: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IZ, JMP0 }; // JMP ABS 536 | 8'h6C: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IZ, IND0 }; // JMP (IDX) 537 | 8'h7C: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IX, IND0 }; // JMP (IDX,X) 538 | 8'h20: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IZ, JSR0 }; // JSR ABS 539 | 8'h40: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IZ, RTI0 }; // RTI 540 | 8'h60: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IZ, RTS0 }; // RTS 541 | 542 | 8'hAE: decode = { FLAG____, LDA, SRC__, DST_X, ALU_LDA , IZ, ABS0 }; // LDX ABS 543 | 8'hBE: decode = { FLAG____, LDA, SRC__, DST_X, ALU_LDA , IY, ABS0 }; // LDX ABS,Y 544 | 8'hA2: decode = { FLAG____, LDA, SRC__, DST_X, ALU_LDA , IZ, IMM0 }; // LDX #IMM 545 | 8'hA6: decode = { FLAG____, LDA, SRC__, DST_X, ALU_LDA , IZ, ZPG0 }; // LDX ZP 546 | 8'hB6: decode = { FLAG____, LDA, SRC__, DST_X, ALU_LDA , IY, ZPG0 }; // LDX ZP,Y 547 | 8'hAC: decode = { FLAG____, LDA, SRC__, DST_Y, ALU_LDA , IZ, ABS0 }; // LDY ABS 548 | 8'hBC: decode = { FLAG____, LDA, SRC__, DST_Y, ALU_LDA , IX, ABS0 }; // LDY ABS,X 549 | 8'hA0: decode = { FLAG____, LDA, SRC__, DST_Y, ALU_LDA , IZ, IMM0 }; // LDY #IMM 550 | 8'hA4: decode = { FLAG____, LDA, SRC__, DST_Y, ALU_LDA , IZ, ZPG0 }; // LDY ZP 551 | 8'hB4: decode = { FLAG____, LDA, SRC__, DST_Y, ALU_LDA , IX, ZPG0 }; // LDY ZP,X 552 | 553 | 8'h48: decode = { FLAG____, NOP, SRC_A, DST__, ALU_REG , IZ, PHA0 }; // PHA 554 | 8'hDA: decode = { FLAG____, NOP, SRC_X, DST__, ALU_REG , IZ, PHA0 }; // PHX 555 | 8'h5A: decode = { FLAG____, NOP, SRC_Y, DST__, ALU_REG , IZ, PHA0 }; // PHY 556 | 8'h68: decode = { FLAG____, LDA, SRC__, DST_A, ALU_PLA , IZ, PLA0 }; // PLA 557 | 8'hFA: decode = { FLAG____, LDA, SRC__, DST_X, ALU_PLA , IZ, PLA0 }; // PLX 558 | 8'h7A: decode = { FLAG____, LDA, SRC__, DST_Y, ALU_PLA , IZ, PLA0 }; // PLY 559 | 8'h08: decode = { FLAG____, NOP, SRC__, DST__, ALU_REG , IZ, PHA0 }; // PHP 560 | 8'h28: decode = { FLAG____, NOP, SRC__, DST__, ALU_____, IZ, PLA0 }; // PLP 561 | 562 | 8'h8E: decode = { FLAG____, STA, SRC_X, DST__, ALU_REG , IZ, ABS0 }; // STX ABS 563 | 8'h86: decode = { FLAG____, STA, SRC_X, DST__, ALU_REG , IZ, ZPG0 }; // STX ZP 564 | 8'h96: decode = { FLAG____, STA, SRC_X, DST__, ALU_REG , IY, ZPG0 }; // STX ZP,Y 565 | 8'h8C: decode = { FLAG____, STA, SRC_Y, DST__, ALU_REG , IZ, ABS0 }; // STY ABS 566 | 8'h84: decode = { FLAG____, STA, SRC_Y, DST__, ALU_REG , IZ, ZPG0 }; // STY ZP 567 | 8'h94: decode = { FLAG____, STA, SRC_Y, DST__, ALU_REG , IX, ZPG0 }; // STY ZP,X 568 | 569 | 8'h9C: decode = { FLAG____, STA, SRC_Z, DST__, ALU_REG , IZ, ABS0 }; // STZ ABS 570 | 8'h9E: decode = { FLAG____, STA, SRC_Z, DST__, ALU_REG , IX, ABS0 }; // STZ ABS,X 571 | 8'h64: decode = { FLAG____, STA, SRC_Z, DST__, ALU_REG , IZ, ZPG0 }; // STZ ZP 572 | 8'h74: decode = { FLAG____, STA, SRC_Z, DST__, ALU_REG , IX, ZPG0 }; // STZ ZP,X 573 | 574 | /* TBD */ 575 | 8'h1C: decode = { 25'b00_0_00_00_00_000000000_00, ABS0 }; // TRB ABS 576 | 8'h14: decode = { 25'b00_0_00_00_00_000000000_00, ZPG0 }; // TRB ZP 577 | 8'h0C: decode = { 25'b00_0_00_00_00_000000000_00, ABS0 }; // TSB ABS 578 | 8'h04: decode = { 25'b00_0_00_00_00_000000000_00, ZPG0 }; // TSB ZP 579 | default: decode = { 25'bxx_x_xx_xx_xx_xxxxxxxxx_xx, SYNC }; 580 | endcase 581 | /* 582 | ***************************************************************************** 583 | * debug section 584 | ***************************************************************************** 585 | */ 586 | 587 | `ifdef SIM 588 | 589 | reg [39:0] statename; 590 | always @* 591 | case( state ) 592 | SYNC: statename = "SYNC"; 593 | IMM0: statename = "IMM0"; 594 | PHA0: statename = "PHA0"; 595 | PLA0: statename = "PLA0"; 596 | ZPG0: statename = "ZPG0"; 597 | ZPW0: statename = "ZPW0"; 598 | DATA: statename = "DATA"; 599 | ABS0: statename = "ABS0"; 600 | ABS1: statename = "ABS1"; 601 | ABW0: statename = "ABW0"; 602 | ABW1: statename = "ABW1"; 603 | BRA0: statename = "BRA0"; 604 | IND0: statename = "IND0"; 605 | IND1: statename = "IND1"; 606 | JMP0: statename = "JMP0"; 607 | JMP1: statename = "JMP1"; 608 | JSR0: statename = "JSR0"; 609 | JSR1: statename = "JSR1"; 610 | JSR2: statename = "JSR2"; 611 | RTS0: statename = "RTS0"; 612 | RTS1: statename = "RTS1"; 613 | RTS2: statename = "RTS2"; 614 | IDX0: statename = "IDX0"; 615 | IDX1: statename = "IDX1"; 616 | IDX2: statename = "IDX2"; 617 | RMW0: statename = "RMW0"; 618 | RMW1: statename = "RMW1"; 619 | BRK0: statename = "BRK0"; 620 | BRK1: statename = "BRK1"; 621 | BRK2: statename = "BRK2"; 622 | BRK3: statename = "BRK3"; 623 | RTI0: statename = "RTI0"; 624 | default : statename = "?"; 625 | endcase 626 | 627 | reg [7:0] opcode; 628 | reg [23:0] mnemonic; 629 | 630 | always @( posedge clk ) 631 | if( sync ) 632 | opcode <= IR; 633 | 634 | /* 635 | * disassembler translates binary opcode into 3 letter mnemonic 636 | */ 637 | disas disas( 638 | .opcode(opcode), 639 | .mnemonic(mnemonic) ); 640 | 641 | integer cycle; 642 | always @( posedge clk ) 643 | cycle <= cycle + 1; 644 | 645 | wire [7:0] R_ = RST ? "R" : "-"; 646 | wire [7:0] B_ = B ? "B" : "-"; 647 | wire [7:0] C_ = C ? "C" : "-"; 648 | wire [7:0] D_ = D ? "D" : "-"; 649 | wire [7:0] I_ = I ? "I" : "-"; 650 | wire [7:0] N_ = N ? "N" : "-"; 651 | wire [7:0] V_ = V ? "V" : "-"; 652 | wire [7:0] Z_ = Z ? "Z" : "-"; 653 | 654 | wire [7:0] X = regfile.regs[SEL_X]; 655 | wire [7:0] Y = regfile.regs[SEL_Y]; 656 | wire [7:0] A = regfile.regs[SEL_A]; 657 | 658 | always @( posedge clk ) begin 659 | if( !debug || cycle < 100000 || cycle[10:0] == 0 ) 660 | $display( "%4d %s %s %s PC:%h AB:%h DI:%h DO:%h DR:%h IR:%h WE:%d ALU:%h S:%02x A:%h X:%h Y:%h R:%h P:%s%s%s%s%s%s", 661 | cycle, R_, mnemonic, statename, PC, AB, DI, DO, DR, IR, WE, alu_out, S, A, X, Y, R, N_, V_, D_, I_, Z_, C_ ); 662 | // end simulation on STP instruction 663 | if( opcode == 8'hdb ) 664 | $finish( ); 665 | end 666 | `endif 667 | 668 | endmodule 669 | --------------------------------------------------------------------------------