diff --git a/cpu_65c02.v b/cpu_65c02.v index a0f0c73..2e313fb 100644 --- a/cpu_65c02.v +++ b/cpu_65c02.v @@ -1,22 +1,22 @@ /* * verilog model of 65C02 CPU. * - * Based on original 6502 "Arlet 6502 Core" by Arlet Ottens - * + * Based on original 6502 "Arlet 6502 Core" by Arlet Ottens + * * (C) Arlet Ottens, * * Feel free to use this code in any project (commercial or not), as long as you - * keep this message, and the copyright notice. This code is provided "as is", + * keep this message, and the copyright notice. This code is provided "as is", * without any warranties of any kind. - * + * * Support for 65C02 instructions and addressing modes by David Banks and Ed Spittles * * (C) 2016 David Banks and Ed Spittles - * + * * Feel free to use this code in any project (commercial or not), as long as you - * keep this message, and the copyright notice. This code is provided "as is", + * keep this message, and the copyright notice. This code is provided "as is", * without any warranties of any kind. - * + * */ /* @@ -32,7 +32,7 @@ * Two things were needed to correctly implement 65C02 NOPs * 1. Ensure the microcode state machine uses an appropriate addressing mode for the opcode length * 2. Ensure there are no side-effects (e.g. register updates, memory stores, etc) - * + * * If IMPLEMENT_NOPS is defined, the state machine is modified accordingly. */ @@ -50,7 +50,7 @@ module cpu_65c02( clk, reset, AB, DI, DO, WE, IRQ, NMI, RDY ); -input clk; // CPU clock +input clk; // CPU clock input reset; // reset signal output reg [15:0] AB; // address bus input [7:0] DI; // data in, read bus @@ -58,13 +58,13 @@ output [7:0] DO; // data out, write bus output WE; // write enable input IRQ; // interrupt request input NMI; // non-maskable interrupt request -input RDY; // Ready signal. Pauses CPU when RDY=0 +input RDY; // Ready signal. Pauses CPU when RDY=0 /* * internal signals */ -reg [15:0] PC; // Program Counter +reg [15:0] PC; // Program Counter reg [7:0] ABL; // Address Bus Register LSB reg [7:0] ABH; // Address Bus Register MSB wire [7:0] ADD; // Adder Hold Register (registered in ALU) @@ -73,7 +73,7 @@ reg [7:0] DIHOLD; // Hold for Data In reg DIHOLD_valid; // wire [7:0] DIMUX; // -reg [7:0] IRHOLD; // Hold for Instruction register +reg [7:0] IRHOLD; // Hold for Instruction register reg IRHOLD_valid; // Valid instruction in IRHOLD reg [7:0] AXYS[3:0]; // A, X, Y and S register file @@ -96,11 +96,11 @@ reg [7:0] AI; // ALU Input A reg [7:0] BI; // ALU Input B wire [7:0] DI; // Data In wire [7:0] IR; // Instruction register -reg [7:0] DO; // Data Out +reg [7:0] DO; // Data Out wire [7:0] AO; // ALU output after BCD adjustment reg WE; // Write Enable reg CI; // Carry In -wire CO; // Carry Out +wire CO; // Carry Out wire [7:0] PCH = PC[15:8]; wire [7:0] PCL = PC[7:0]; @@ -109,10 +109,10 @@ reg NMI_edge = 0; // captured NMI edge reg [1:0] regsel; // Select A, X, Y or S register wire [7:0] regfile = AXYS[regsel]; // Selected register output -parameter +parameter SEL_A = 2'd0, SEL_S = 2'd1, - SEL_X = 2'd2, + SEL_X = 2'd2, SEL_Y = 2'd3; /* @@ -123,8 +123,8 @@ parameter `ifdef SIM wire [7:0] A = AXYS[SEL_A]; // Accumulator wire [7:0] X = AXYS[SEL_X]; // X register -wire [7:0] Y = AXYS[SEL_Y]; // Y register -wire [7:0] S = AXYS[SEL_S]; // Stack pointer +wire [7:0] Y = AXYS[SEL_Y]; // Y register +wire [7:0] S = AXYS[SEL_S]; // Stack pointer `endif wire [7:0] P = { N, V, 2'b11, D, I, Z, C }; @@ -140,15 +140,15 @@ reg [5:0] state; */ reg PC_inc; // Increment PC -reg [15:0] PC_temp; // intermediate value of PC +reg [15:0] PC_temp; // intermediate value of PC reg [1:0] src_reg; // source register index reg [1:0] dst_reg; // destination register index -reg index_y; // if set, then Y is index reg rather than X +reg index_y; // if set, then Y is index reg rather than X reg load_reg; // loading a register (A, X, Y, S) in this instruction reg inc; // increment -reg write_back; // set if memory is read/modified/written +reg write_back; // set if memory is read/modified/written reg load_only; // LDA/LDX/LDY instruction reg store; // doing store (STA/STX/STY) reg adc_sbc; // doing ADC/SBC @@ -158,14 +158,14 @@ reg rotate; // doing rotate (no shift) reg backwards; // backwards branch reg cond_true; // branch condition is true reg [3:0] cond_code; // condition code bits from instruction -reg shift_right; // Instruction ALU shift/rotate right +reg shift_right; // Instruction ALU shift/rotate right reg alu_shift_right; // Current cycle shift right enable reg [3:0] op; // Main ALU operation for instruction -reg [3:0] alu_op; // Current cycle ALU operation -reg adc_bcd; // ALU should do BCD style carry +reg [3:0] alu_op; // Current cycle ALU operation +reg adc_bcd; // ALU should do BCD style carry reg adj_bcd; // results should be BCD adjusted -/* +/* * some flip flops to remember we're doing special instructions. These * get loaded at the DECODE state, and used later */ @@ -175,14 +175,14 @@ reg txb_ins; // doing TSB/TRB instruction reg bit_ins; // doing BIT instruction reg bit_ins_nv; // doing BIT instruction that will update the n and v flags (i.e. not BIT imm) reg plp; // doing PLP instruction -reg php; // doing PHP instruction +reg php; // doing PHP instruction reg clc; // clear carry reg sec; // set carry reg cld; // clear decimal reg sed; // set decimal reg cli; // clear interrupt reg sei; // set interrupt -reg clv; // clear overflow +reg clv; // clear overflow reg brk; // doing BRK reg res; // in reset @@ -204,17 +204,17 @@ parameter * Microcode state machine. Basically, every addressing mode has its own * path through the state machine. Additional information, such as the * operation, source and destination registers are decoded in parallel, and - * kept in separate flops. + * kept in separate flops. */ -parameter - ABS0 = 6'd0, // ABS - fetch LSB +parameter + ABS0 = 6'd0, // ABS - fetch LSB ABS1 = 6'd1, // ABS - fetch MSB ABSX0 = 6'd2, // ABS, X - fetch LSB and send to ALU (+X) ABSX1 = 6'd3, // ABS, X - fetch MSB and send to ALU (+Carry) ABSX2 = 6'd4, // ABS, X - Wait for ALU (only if needed) BRA0 = 6'd5, // Branch - fetch offset and send to ALU (+PC[7:0]) - BRA1 = 6'd6, // Branch - fetch opcode, and send PC[15:8] to ALU + BRA1 = 6'd6, // Branch - fetch opcode, and send PC[15:8] to ALU BRA2 = 6'd7, // Branch - fetch opcode (if page boundary crossed) BRK0 = 6'd8, // BRK/IRQ - push PCH, send S to ALU (-1) BRK1 = 6'd9, // BRK/IRQ - push PCL, send S to ALU (-1) @@ -225,9 +225,9 @@ parameter INDX0 = 6'd14, // (ZP,X) - fetch ZP address, and send to ALU (+X) INDX1 = 6'd15, // (ZP,X) - fetch LSB at ZP+X, calculate ZP+X+1 INDX2 = 6'd16, // (ZP,X) - fetch MSB at ZP+X+1 - INDX3 = 6'd17, // (ZP,X) - fetch data + INDX3 = 6'd17, // (ZP,X) - fetch data INDY0 = 6'd18, // (ZP),Y - fetch ZP address, and send ZP to ALU (+1) - INDY1 = 6'd19, // (ZP),Y - fetch at ZP+1, and send LSB to ALU (+Y) + INDY1 = 6'd19, // (ZP),Y - fetch at ZP+1, and send LSB to ALU (+Y) INDY2 = 6'd20, // (ZP),Y - fetch data, and send MSB to ALU (+Carry) INDY3 = 6'd21, // (ZP),Y) - fetch data (if page boundary crossed) JMP0 = 6'd22, // JMP - fetch PCL and hold @@ -246,15 +246,15 @@ parameter READ = 6'd35, // Read memory for read/modify/write (INC, DEC, shift) REG = 6'd36, // Read register for reg-reg transfers RTI0 = 6'd37, // RTI - send S to ALU (+1) - RTI1 = 6'd38, // RTI - read P from stack + RTI1 = 6'd38, // RTI - read P from stack RTI2 = 6'd39, // RTI - read PCL from stack RTI3 = 6'd40, // RTI - read PCH from stack RTI4 = 6'd41, // RTI - read PCH from stack RTS0 = 6'd42, // RTS - send S to ALU (+1) - RTS1 = 6'd43, // RTS - read PCL from stack - RTS2 = 6'd44, // RTS - write PCL to ALU, read PCH + RTS1 = 6'd43, // RTS - read PCL from stack + RTS2 = 6'd44, // RTS - write PCL to ALU, read PCH RTS3 = 6'd45, // RTS - load PC and increment - WRITE = 6'd46, // Write memory for read/modify/write + WRITE = 6'd46, // Write memory for read/modify/write ZP0 = 6'd47, // Z-page - fetch ZP address ZPX0 = 6'd48, // ZP, X - fetch ZP, and send to ALU (+X) ZPX1 = 6'd49, // ZP, X - load from memory @@ -326,7 +326,7 @@ always @* JMPIX0: statename = "JMPIX0"; JMPIX1: statename = "JMPIX1"; JMPIX2: statename = "JMPIX2"; - + endcase //always @( PC ) @@ -352,15 +352,15 @@ always @* JMPI1, JMPIX1, JSR3, - RTS3, + RTS3, RTI4: PC_temp = { DIMUX, ADD }; - + BRA1: PC_temp = { ABH, ADD }; JMPIX2, BRA2: PC_temp = { ADD, PCL }; - BRK2: PC_temp = res ? 16'hfffc : + BRK2: PC_temp = res ? 16'hfffc : NMI_edge ? 16'hfffa : 16'hfffe; default: PC_temp = PC; @@ -396,15 +396,15 @@ always @* default: PC_inc = 0; endcase -/* +/* * Set new PC */ -always @(posedge clk) +always @(posedge clk) if( RDY ) PC <= PC_temp + PC_inc; /* - * Address Generator + * Address Generator */ parameter @@ -444,7 +444,7 @@ always @* RTI2, RTI3, BRK2: AB = { STACKPAGE, ADD }; - + INDY1, INDX1, ZPX1, @@ -466,7 +466,7 @@ always @* * source of the address, such as the ALU or DI. */ always @(posedge clk) - if( state != PUSH0 && state != PUSH1 && RDY && + if( state != PUSH0 && state != PUSH1 && RDY && state != PULL0 && state != PULL1 && state != PULL2 ) begin ABL <= AB[7:0]; @@ -474,7 +474,7 @@ always @(posedge clk) end /* - * Data Out MUX + * Data Out MUX */ always @* case( state ) @@ -529,8 +529,8 @@ always @* case( state ) DECODE: write_register = load_reg & ~plp; - PULL1, - RTS2, + PULL1, + RTS2, RTI3, BRK3, JSR0, @@ -590,7 +590,7 @@ assign AN1 = AN; assign AZ1 = AZ; `endif - + /* * write to a register. Usually this is the (BCD corrected) output of the * ALU, but in case of the JSR0 we use the S register to temporarily store @@ -603,10 +603,10 @@ always @(posedge clk) /* * register select logic. This determines which of the A, X, Y or - * S registers will be accessed. + * S registers will be accessed. */ -always @* +always @* case( state ) INDY1, INDX0, @@ -615,7 +615,7 @@ always @* ABSX0 : regsel = index_y ? SEL_Y : SEL_X; - DECODE : regsel = dst_reg; + DECODE : regsel = dst_reg; BRK0, BRK3, @@ -628,8 +628,8 @@ always @* RTI3, RTS0, RTS2 : regsel = SEL_S; - - default: regsel = src_reg; + + default: regsel = src_reg; endcase /* @@ -659,10 +659,10 @@ always @* case( state ) READ: alu_op = op; - BRA1: alu_op = backwards ? OP_SUB : OP_ADD; + BRA1: alu_op = backwards ? OP_SUB : OP_ADD; FETCH, - REG : alu_op = op; + REG : alu_op = op; DECODE, ABS1: alu_op = 1'bx; @@ -688,15 +688,15 @@ always @* alu_shift_right = 0; /* - * Sign extend branch offset. + * Sign extend branch offset. */ always @(posedge clk) if( RDY ) backwards <= DIMUX[7]; -/* - * ALU A Input MUX +/* + * ALU A Input MUX */ always @* @@ -727,7 +727,7 @@ always @* BRA0, READ: AI = DIMUX; - BRA1: AI = ABH; // don't use PCH in case we're + BRA1: AI = ABH; // don't use PCH in case we're FETCH: AI = load_only ? 0 : regfile; @@ -757,7 +757,7 @@ always @* BRK0, BRK1, BRK2, - PUSH0, + PUSH0, PUSH1, PULL0, RTS0: BI = 8'h00; @@ -790,8 +790,8 @@ always @* REG: CI = rotate ? C : shift ? 0 : inc; - FETCH: CI = rotate ? C : - compare ? 1 : + FETCH: CI = rotate ? C : + compare ? 1 : (shift | load_only) ? 0 : C; PULL0, @@ -801,7 +801,7 @@ always @* RTS0, RTS1, INDY0, - INDX1: CI = 1; + INDX1: CI = 1; default: CI = 0; endcase @@ -815,7 +815,7 @@ always @* * Update C flag when doing ADC/SBC, shift/rotate, compare */ always @(posedge clk ) - if( shift && state == WRITE ) + if( shift && state == WRITE ) C <= CO; else if( state == RTI2 ) C <= DIMUX[0]; @@ -832,15 +832,15 @@ always @(posedge clk ) /* * Special Z flag got TRB/TSB - */ -always @(posedge clk) + */ +always @(posedge clk) AZ2 <= ~|(AI & regfile); /* * Update Z, N flags when writing A, X, Y, Memory, or when doing compare */ -always @(posedge clk) +always @(posedge clk) if( state == WRITE) Z <= txb_ins ? AZ2 : AZ1; else if( state == RTI2 ) @@ -883,7 +883,7 @@ always @(posedge clk) /* * Update D flag */ -always @(posedge clk ) +always @(posedge clk ) if( state == RTI2 ) D <= DIMUX[3]; else if( state == DECODE ) begin @@ -896,7 +896,7 @@ always @(posedge clk ) * Update V flag */ always @(posedge clk ) - if( state == RTI2 ) + if( state == RTI2 ) V <= DIMUX[6]; else if( state == DECODE ) begin if( adc_sbc ) V <= AV; @@ -939,8 +939,8 @@ assign IR = (IRQ & ~I) | NMI_edge ? 8'h00 : IRHOLD_valid ? IRHOLD : DIMUX; //assign DIMUX = ~RDY1 ? DIHOLD : DI; - -assign DIMUX = DI; + +assign DIMUX = DI; /* * Microcode state machine @@ -949,7 +949,7 @@ always @(posedge clk or posedge reset) if( reset ) state <= BRK0; else if( RDY ) case( state ) - DECODE : + DECODE : casex ( IR ) // TODO Review for simplifications as in verilog the first matching case has priority 8'b0000_0000: state <= BRK0; @@ -957,23 +957,23 @@ always @(posedge clk or posedge reset) 8'b0010_1100: state <= ABS0; // BIT abs 8'b1001_1100: state <= ABS0; // STZ abs 8'b000x_1100: state <= ABS0; // TSB/TRB - 8'b0100_0000: state <= RTI0; // + 8'b0100_0000: state <= RTI0; // 8'b0100_1100: state <= JMP0; 8'b0110_0000: state <= RTS0; 8'b0110_1100: state <= JMPI0; 8'b0111_1100: state <= JMPIX0; -`ifdef IMPLEMENT_NOPS +`ifdef IMPLEMENT_NOPS 8'bxxxx_xx11: state <= REG; // (NOP1: 3/7/B/F column) 8'bxxx0_0010: state <= FETCH; // (NOP2: 2 column, 4 column handled correctly below) 8'bx1x1_1100: state <= ABS0; // (NOP3: C column) `endif 8'b0x00_1000: state <= PUSH0; 8'b0x10_1000: state <= PULL0; - 8'b0xx1_1000: state <= REG; // CLC, SEC, CLI, SEI + 8'b0xx1_1000: state <= REG; // CLC, SEC, CLI, SEI 8'b11x0_00x0: state <= FETCH; // IMM 8'b1x10_00x0: state <= FETCH; // IMM 8'b1xx0_1100: state <= ABS0; // X/Y abs - 8'b1xxx_1000: state <= REG; // DEY, TYA, ... + 8'b1xxx_1000: state <= REG; // DEY, TYA, ... 8'bxxx0_0001: state <= INDX0; 8'bxxx1_0010: state <= IND0; // (ZP) odd 2 column 8'b000x_0100: state <= ZP0; // TSB/TRB @@ -1028,18 +1028,18 @@ always @(posedge clk or posedge reset) FETCH : state <= DECODE; REG : state <= DECODE; - + PUSH0 : state <= PUSH1; PUSH1 : state <= DECODE; PULL0 : state <= PULL1; - PULL1 : state <= PULL2; + PULL1 : state <= PULL2; PULL2 : state <= DECODE; JSR0 : state <= JSR1; JSR1 : state <= JSR2; JSR2 : state <= JSR3; - JSR3 : state <= FETCH; + JSR3 : state <= FETCH; RTI0 : state <= RTI1; RTI1 : state <= RTI2; @@ -1057,7 +1057,7 @@ always @(posedge clk or posedge reset) BRA2 : state <= DECODE; JMP0 : state <= JMP1; - JMP1 : state <= DECODE; + JMP1 : state <= DECODE; JMPI0 : state <= JMPI1; JMPI1 : state <= JMP0; @@ -1087,7 +1087,7 @@ always @(posedge clk) 8'b0xxx_1010, // ASLA, INCA, ROLA, DECA, LSRA, PHY, RORA, PLY 8'b0xxx_xx01, // ORA, AND, EOR, ADC 8'b100x_10x0, // DEY, TYA, TXA, TXS - 8'b1010_xxx0, // LDA/LDX/LDY + 8'b1010_xxx0, // LDA/LDX/LDY 8'b1011_1010, // TSX 8'b1011_x1x0, // LDX/LDY 8'b1100_1010, // DEX @@ -1127,15 +1127,15 @@ always @(posedge clk) always @(posedge clk) if( state == DECODE && RDY ) casex( IR ) - 8'b1011_1010: // TSX - src_reg <= SEL_S; + 8'b1011_1010: // TSX + src_reg <= SEL_S; 8'b100x_x110, // STX 8'b100x_1x10, // TXA, TXS 8'b1110_xx00, // INX, CPX 8'b1101_1010, // PHX 8'b1100_1010: // DEX - src_reg <= SEL_X; + src_reg <= SEL_X; 8'b100x_x100, // STY 8'b1001_1000, // TYA @@ -1147,7 +1147,7 @@ always @(posedge clk) default: src_reg <= SEL_A; endcase -always @(posedge clk) +always @(posedge clk) if( state == DECODE && RDY ) casex( IR ) 8'bxxx1_0001, // INDY @@ -1178,7 +1178,7 @@ always @(posedge clk ) casex( IR ) // DMB: Checked for 65C02 NOP collisions 8'b0xxx_x110, // ASL, ROL, LSR, ROR 8'b000x_x100, // TSB/TRB - 8'b11xx_x110: // DEC/INC + 8'b11xx_x110: // DEC/INC write_back <= 1; default: write_back <= 0; @@ -1197,7 +1197,7 @@ always @(posedge clk ) if( state == DECODE && RDY ) casex( IR ) 8'b0001_1010, // INCA - 8'b111x_x110, // INC + 8'b111x_x110, // INC 8'b11x0_1000: // INX, INY inc <= 1; @@ -1240,7 +1240,7 @@ always @(posedge clk ) 8'b1101_0010, // CMP (zp) 8'b11x0_0x00, // CPX, CPY (imm/zp) 8'b11x0_1100, // CPX, CPY (abs) - 8'b110x_xx01: // CMP + 8'b110x_xx01: // CMP compare <= 1; default: compare <= 0; @@ -1253,17 +1253,17 @@ always @(posedge clk ) 8'b01xx_1x10: // ROR, LSR shift_right <= 1; - default: shift_right <= 0; + default: shift_right <= 0; endcase always @(posedge clk ) if( state == DECODE && RDY ) casex( IR ) 8'b0x10_1010, // ROL A, ROR A - 8'b0x1x_x110: // ROR, ROL + 8'b0x1x_x110: // ROR, ROL rotate <= 1; - default: rotate <= 0; + default: rotate <= 0; endcase always @(posedge clk ) @@ -1290,8 +1290,8 @@ always @(posedge clk ) 8'b11x1_0010, // CMP, SBC (zp) 8'b0011_1010, // DEC A 8'b1000_1000, // DEY - 8'b1100_1010, // DEX - 8'b110x_x110, // DEC + 8'b1100_1010, // DEX + 8'b110x_x110, // DEC 8'b11xx_xx01, // CMP, SBC 8'b11x0_0x00, // CPX, CPY (imm, zpg) 8'b11x0_1100: op <= OP_SUB; @@ -1301,8 +1301,8 @@ always @(posedge clk ) 8'b010x_xx01, // EOR 8'b00xx_xx01: // ORA, AND op <= { 2'b11, IR[6:5] }; - - default: op <= OP_ADD; + + default: op <= OP_ADD; endcase always @(posedge clk )