1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-02-11 02:29:55 +00:00
Files
Gehstock.Mist_FPGA/common/CPU/bc6502/bc6502.v
2022-09-14 14:46:07 +02:00

1572 lines
36 KiB
Verilog

/* ===============================================================
(C) 2002 Bird Computer
All rights reserved.
bc6502.v
Version 1.0
You are free to use and modify this code for non-commercial
or evaluation purposes.
If you do modify the code, please state the origin and
note that you have modified the code.
Please read the license agreement (license.html) file.
Generic original 6502 compatible core.
Undoc'd instructions are not supported.
==============================================================-= */
`timescale 1ps / 1ps
`define RESET_VEC 16'hFFFC
`define NMI_VEC 16'hFFFA
`define IRQ_VEC 16'hFFFE
`define BRK_VEC 16'hFFFE
`define SP_RESET 8'hFF // reset value of the stack pointer
`define DECMD_SUPPORT 1
// Don't confuse these with the parameters!
`define DBW 8
`define ABW 16
`define JSR 8'h20
`define JMP 8'h4C
`define JMP_I 8'h6C
`define RTS 8'h60
`define RTI 8'h40
`define PHP 8'h08
`define PHA 8'h48
`define PLP 8'h28
`define PLA 8'h68
`define BRK 8'h00
`define INX 8'hE8
`define DEX 8'hCA
`define INY 8'hC8
`define DEY 8'h88
`define TYA 8'h98
`define TAY 8'ha8
`define TXA 8'h8A
`define TAX 8'hAA
`define TXS 8'h9A
`define TSX 8'hBA
`define ASL_A 8'h0A
`define ASL_Z 8'h06
`define ASL_ZX 8'h16
`define ASL_ABS 8'h0E
`define ASL_AX 8'h1E
`define ROL_A 8'h2A
`define ROL_Z 8'h26
`define ROL_ZX 8'h36
`define ROL_ABS 8'h2E
`define ROL_AX 8'h3e
`define LSR_A 8'h4A
`define LSR_Z 8'h46
`define LSR_ZX 8'h56
`define LSR_ABS 8'h4E
`define LSR_AX 8'h5E
`define ROR_A 8'h6A
`define ROR_Z 8'h66
`define ROR_ZX 8'h76
`define ROR_ABS 8'h6E
`define ROR_AX 8'h7E
`define DEC_Z 8'hC6
`define DEC_ZX 8'hD6
`define DEC_A 8'hCE
`define DEC_AX 8'hDE
`define INC_Z 8'hE6
`define INC_ZX 8'hF6
`define INC_A 8'hEE
`define INC_AX 8'hFE
`define CLD 8'hD8
`define SED 8'hF8
`define CLC 8'h18
`define SEC 8'h38
`define CLI 8'h58
`define SEI 8'h78
`define CLV 8'hB8
`define NOP 8'hEA
// Group0 opcodes
`define GROUP0 2'b00
`define BIT 3'b001
`define STY 3'b100
`define LDY 3'b101
`define CPY 3'b110
`define CPX 3'b111
// Group1 opcodes
`define GROUP1 2'b01
`define ORA 3'b000
`define AND 3'b001
`define EOR 3'b010
`define ADC 3'b011
`define STA 3'b100
`define LDA 3'b101
`define CMP 3'b110
`define SBC 3'b111
// Group2 opcodes
`define GROUP2 2'b10
`define ASL 3'b000
`define ROL 3'b001
`define LSR 3'b010
`define ROR 3'b011
`define STX 3'b100
`define LDX 3'b101
`define DEC 3'b110
`define INC 3'b111
`define BPL 3'b000
`define BMI 3'b001
`define BVC 3'b010
`define BVS 3'b011
`define BCC 3'b100
`define BCS 3'b101
`define BNE 3'b110
`define BEQ 3'b111
`define LDA_I 8'hA9
`define LDA_Z 8'hA5
`define LDA_ZX 8'hB5
`define LDA_IX 8'hA1
`define LDA_IY 8'hB1
`define LDA_A 8'hAD
`define LDA_AX 8'hBD
`define LDA_AY 8'hB9
`define LDY_I 8'hA0
`define LDY_Z 8'hA4
`define LDY_ZX 8'hB4
`define LDY_A 8'hAC
`define LDY_AX 8'hBC
`define CPY_I 8'hC0
`define LDX_I 8'hA2
`define LDX_Z 8'hA6
`define LDX_ZY 8'hB6
`define LDX_A 8'hAE
`define LDX_AY 8'hBE
`define CPX_I 8'hE0
`define STA_Z 8'h85
`define STA_ZX 8'h95
`define STA_IX 8'h81
`define STA_IY 8'h91
`define STA_A 8'h8D
`define STA_AX 8'h9D
`define STA_AY 8'h99
`define STY_Z 8'h84
`define STY_ZX 8'h94
`define STY_A 8'h8C
`define STX_Z 8'h86
`define STX_ZY 8'h96
`define STX_A 8'h8E
module bc6502(reset, clk, nmi, irq, rdy, so, di, dout, rw, ma,
rw_nxt, ma_nxt, sync, state, flags);
parameter ABW = `ABW;
parameter DBW = `DBW;
input reset/*verilator public_flat*/;
input clk;
input nmi; // active high
input irq/*verilator public_flat*/; // active high
input rdy;
input so; // set overflow
input [DBW-1:0] di/*verilator public_flat*/; // data input bus
output [DBW-1:0] dout; // data output bus
reg [DBW-1:0] dout;
output rw;
reg rw;
output [ABW-1:0] ma;
reg [ABW-1:0] ma/*verilator public_flat*/;
// The following two signals can be useful for interfacing
// to synchronous memory by providing values just before the
// clock edge rather than after.
output rw_nxt;
output [ABW-1:0] ma_nxt;
output sync;
// The following two signals are provided mainly for
// debugging.
output [31:0] state; // cpu state
output [4:0] flags;
//-----------------------------------
reg [7:0] cres; // critical reset sequencer
wire creset = cres[7];
reg [DBW-1:0] ir;
reg [DBW-1:0] dil; // data input latch
// Processor Programming Model registers
reg [DBW-1:0] a_reg; // A accumulator
reg [DBW-1:0] x_reg; // X index register
reg [DBW-1:0] y_reg; // Y index register
reg [DBW-1:0] sp_reg; // SP stack pointer
reg [ABW-1:0] pc_reg; // PC program counter
reg nf,vf,bf,df,im,zf,cf; // SR status register
// wire [7:0] sr_reg = {nf,vf,1'b1,bf,df,im,zf,cf};
wire [7:0] sr_reg = {nf,vf,1'b0,bf,df,im,zf,cf};
// tri [DBW-1:0] res; // internal result bus
wire [DBW-1:0] res; // internal result bus
reg [DBW-1:0] tmp; // temp reg needed for some operations
reg [ABW-1:0] pc_nxt;
reg [DBW-1:0] dout_nxt;
reg rw_nxt;
reg prev_nmi; // track previous nmi state for edge detection
wire nmi_edge = nmi & ~prev_nmi;
wire any_int /*verilator public_flat*/ = nmi_edge | (irq & ~im);
// cpu states
wire s_reset;
wire s_reset1;
wire s_reset2;
wire s_reset3;
wire s_nmi1, s_nmi2, s_nmi3, s_nmi4, s_nmi5;
wire s_ld_pch;
wire s_exec;
wire s_branch;
wire s_dataFetch;
wire s_update;
wire s_afterWrite;
wire s_ix1, s_ix2;
wire s_iy1, s_iy2;
wire s_abs1;
wire s_jmpi1;
wire s_jsr1, s_jsr2;
wire s_pul;
wire s_rts1, s_rts2, s_rts3;
wire s_rti1, s_rti2, s_rti3;
wire s_sync;
assign state = {
s_reset, s_reset1, s_reset2, s_reset3,
s_nmi1, s_nmi2, s_nmi3, s_nmi4, s_nmi5,
s_ld_pch,
s_exec,
s_branch,
s_dataFetch,
s_update,
s_afterWrite,
s_ix1, s_ix2,
s_iy1, s_iy2,
s_abs1,
s_jmpi1,
s_jsr1, s_jsr2,
s_pul,
s_rts1, s_rts2, s_rts3,
s_rti1, s_rti2, s_rti3,
s_sync, 1'b0};
assign sync = s_sync;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Instruction Decoding Section
wire [2:0] cond = ir[7:5];
wire branch = ir[4:0]==5'b10000;
reg taken;
assign flags = {nf,zf,cf,vf,taken};
wire jmp = (ir == `JMP);
wire jmpi = (ir == `JMP_I);
wire php = ir==`PHP;
wire pha = ir==`PHA;
wire psh = php|pha;
wire plp = ir==`PLP;
wire pla = ir==`PLA;
wire pul = plp|pla;
wire jsr = ir==`JSR;
wire rts = ir==`RTS;
wire rti = ir==`RTI;
wire brk = ir==`BRK;
wire nop = ir==`NOP;
wire inx = ir==`INX;
wire iny = ir==`INY;
wire dex = ir==`DEX;
wire dey = ir==`DEY;
wire clc = ir==`CLC;
wire cld = ir==`CLD;
wire clv = ir==`CLV;
wire cli = ir==`CLI;
wire sec = ir==`SEC;
wire sed = ir==`SED;
wire sei = ir==`SEI;
wire tay = ir==`TAY;
wire tya = ir==`TYA;
wire tax = ir==`TAX;
wire txa = ir==`TXA;
wire tsx = ir==`TSX;
wire txs = ir==`TXS;
wire ror_a = ir==`ROR_A;
wire lsr_a = ir==`LSR_A;
wire rol_a = ir==`ROL_A;
wire asl_a = ir==`ASL_A;
wire ldx = ir[7:5]==`LDX;
wire stxx= ir[7:5]==`STX;
wire ror = ir[7:5]==`ROR;
wire rol = ir[7:5]==`ROL;
wire lsr = ir[7:5]==`LSR;
wire asl = ir[7:5]==`ASL;
wire inc = ir[7:5]==`INC;
wire dec = ir[7:5]==`DEC;
wire ldy = ir[7:5]==`LDY;
wire styy = ir[7:5]==`STY;
wire cmp = ir[7:5]==`CMP;
wire ldy_i = ir==`LDY_I;
wire cpy_i = ir==`CPY_I;
wire ldx_i = ir==`LDX_I;
wire cpx_i = ir==`CPX_I;
// miscellaneous operations
wire mop = nop | inx | dex | iny | dey |
txa | tax | tya | tay | txs | tsx |
cld | sed | sei | cli | sec | clc | clv |
asl_a | lsr_a | ror_a | rol_a;
// address modes zp:zp,x:zp,y:(zp,x):(zp),y:#:abs:abs,x:abs,y
wire ix = (ir[4:2]==3'b000&&ir[0]==1'b1);
wire zp = (ir[4:2]==3'b001);
wire imm = (ir[4:2]==3'b010&&ir[0]==1'b1) || (ir[7]==1'b1 && ir[4:0]==5'b00000) || ldx_i;
wire abs = (ir[4:2]==3'b011);
wire iy = (ir[4:2]==3'b100&&ir[0]==1'b1);
wire zpy = (ir==`STX_ZY || ir==`LDX_ZY);
wire zpx = (ir[4:2]==3'b101) && !zpy;
wire absy = (ir[4:2]==3'b110 && ir[0]==1'b1) || ir==`LDX_AY;
wire absx = (ir[4:2]==3'b111) && !absy;
wire zpxy = zp|zpx|zpy;
wire absxy = abs|absx|absy;
// sta/stx/sty
wire sta = ir==`STA_Z||ir==`STA_ZX||ir==`STA_IX
||ir==`STA_IY||ir==`STA_A||ir==`STA_AX
||ir==`STA_AY;
wire sty = ir==`STY_Z||ir==`STY_ZX||ir==`STY_A;
wire stx = ir==`STX_Z||ir==`STX_ZY||ir==`STX_A;
wire staxy = sta | stx | sty;
wire grp0 = ir[1:0]==2'b00;
wire grp1 = ir[1:0]==2'b01;
wire grp2 = ir[1:0]==2'b10;
wire grp2m = (asl | rol | lsr | ror | dec | inc) & grp2; // memory ops
wire grp2x = (ldx | stxx) & grp2; // X reg. ops
// When to update the status flags
wire grp0_us = (ir[3:0]==4'h4 || ir[3:0]==4'hC || (ldy_i | cpy_i | cpx_i));
wire grp1_us = grp1;
wire grp2_us = grp2 && ir[3:0]!=4'hA;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Select between A, X, or Y registers
reg [7:0] axy_reg;
always @(a_reg or x_reg or y_reg or stx or sty or tya or txa or
inx or dex or iny or dey or txs)
begin
if (inx|dex|stx|txa|txs)
axy_reg = x_reg;
else if (iny|dey|sty|tya)
axy_reg = y_reg;
else
axy_reg = a_reg;
end
// incrementers / decrementers
// Note: addsub needs inverted carry for subtract!!!
// A separate module is used here to allow the synthesizer
// to make better use of resources.
wire [7:0] axy_addo;
addsub #(8) axy_adder(
.op(dex | dey),
.ci(dex | dey),
.a({1'b0,axy_reg}),
.b(9'h1),
.o(axy_addo),
.co(), .v()
);
wire [7:0] sp_addo;
addsub #(8) spadder(
.op(s_nmi1 | s_nmi2 |
s_jsr1 | s_jsr2 |
(s_sync & any_int) |
(s_exec & (brk|psh))),
.ci(s_nmi1 | s_nmi2 |
s_jsr1 | s_jsr2 |
(s_sync & any_int) |
(s_exec & (brk|psh))),
.a({1'b0,sp_reg}),
.b(9'h1),
.o(sp_addo),
.co(), .v()
);
// these flags are used to merge states together
reg firq, fbrk;
wire nfo0,cfo0,vfo0,zfo0;
wire nfo1,cfo1,vfo1,zfo1;
wire nfo2,cfo2,zfo2;
wire [DBW-1:0] grp0_o;
wire [DBW-1:0] grp1_o;
wire [DBW-1:0] grp2_o;
// datapath processing
dp_group0 grp0_inst(.ir(ir),
.a_reg(a_reg), .x_reg(x_reg), .y_reg(y_reg), .d(dil),
.ni(nf), .vi(vf), .zi(zf), .ci(cf),
.n(nfo0), .v(vfo0), .z(zfo0), .c(cfo0) );
dp_group1 grp1_inst(.ir(ir), .dec(df),
.ni(nf), .vi(vf), .zi(zf), .ci(cf),
.a_reg(a_reg), .d(dil), .o(grp1_o),
.n(nfo1), .v(vfo1), .z(zfo1), .c(cfo1) );
dp_group2 grp2_inst(.ir(ir), .ldx(ldx), .stxx(stxx), .d(dil),
.ci(cf), .ni(nf), .zi(zf),
.c(cfo2), .n(nfo2), .z(zfo2),
.o(grp2_o) );
// inline datapath processing
assign res =
s_exec & (inx|iny)|(dex|dey) ? axy_addo :
s_exec & (tay|tax|txa|tya|txs) ? axy_reg :
s_exec & tsx ? sp_reg :
s_exec & ror_a ? {cf,a_reg[DBW-1:1]} :
s_exec & lsr_a ? {1'b0,a_reg[DBW-1:1]} :
s_exec & rol_a ? {a_reg[DBW-2:0],cf} :
s_exec & asl_a ? {a_reg[DBW-2:0],1'b0} :
s_pul ? di :
s_rti1 ? di :
s_update & (grp0|grp2) ? dil :
s_update & grp1 ? grp1_o :
8'bz;
// control unit
sequencer seq0(
.reset(reset), .creset(creset), .clk(clk), .rdy(rdy),
.any_int(any_int),
.grp0(grp0), .grp1(grp1), .grp2x(grp2x), .grp2m(grp2m),
.brk(brk),
.mop(mop),
.rti(rti), .rts(rts),
.pul(pul), .psh(psh),
.jsr(jsr),
.jmp(jmp), .jmpi(jmpi), .branch(branch), .staxy(staxy),
.ix(ix), .iy(iy), .absxy(absxy), .imm(imm), .zpxy(zpxy),
.s_reset(s_reset), .s_reset1(s_reset1), .s_reset2(s_reset2), .s_reset3(s_reset3),
.s_nmi1(s_nmi1), .s_nmi2(s_nmi2), .s_nmi3(s_nmi3), .s_nmi4(s_nmi4), .s_nmi5(s_nmi5),
.s_ld_pch(s_ld_pch), .s_exec(s_exec), .s_branch(s_branch), .s_dataFetch(s_dataFetch), .s_update(s_update),
.s_afterWrite(s_afterWrite),
.s_ix1(s_ix1), .s_ix2(s_ix2), .s_iy1(s_iy1), .s_iy2(s_iy2),
.s_abs1(s_abs1),
.s_jmpi1(s_jmpi1),
.s_jsr1(s_jsr1), .s_jsr2(s_jsr2),
.s_pul(s_pul),
.s_rts1(s_rts1), .s_rts2(s_rts2), .s_rts3(s_rts3),
.s_rti1(s_rti1), .s_rti2(s_rti2), .s_rti3(s_rti3),
.s_sync(s_sync) );
// Generate critical reset
always @(posedge clk)
if (reset)
cres <= 8'hFF;
else
cres <= {cres[6:0],1'b0};
//-------------------------------------------------------------
// Memory related hardware
//-------------------------------------------------------------
// Determine exception vector address
reg [ABW-1:0] vec;
always @(s_nmi3 or firq or fbrk) begin
if (s_nmi3) begin
if (firq)
vec = `IRQ_VEC;
else if (fbrk)
vec = `BRK_VEC;
else
vec = `NMI_VEC;
end
else
vec = `RESET_VEC;
end
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Select between X, Y, Z registers for memory addressing.
reg [7:0] xyz_reg;
always @(x_reg or y_reg or absx or absy or zpx or zpy or
s_iy2 or ix or s_abs1 or s_exec)
begin
if ((s_abs1 & absx)|(s_exec & (zpx|ix)))
xyz_reg = x_reg;
else if ((s_abs1 &absy)|(s_exec & zpy)|s_iy2)
xyz_reg = y_reg;
else
xyz_reg = 8'h00;
end
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// memory address multiplexing
// Because of the amount of multiplexing on the address bus
// a multiplexor is implemented with a tri-state bus.
// Otherwise a 16 bit 16 to 1 multiplexor would be required
// which uses a lot of resources.
//---
assign ma_nxt =
// ma = vector
(reset | s_reset | s_reset1 | s_nmi3) ? vec :
// ma = ma + 1
(s_reset2 | s_nmi4 | s_jmpi1 | s_ix1 | s_iy1) ? ma + 1 :
// ma = pc + 1
((s_sync & ~any_int) | (s_exec & (absxy | jsr | branch)) | s_rts3) ? pc_reg + 1 :
// ma = tmp
// abs,y must take precedence over abs,x
(s_reset3 | s_nmi5 | s_rti3 | s_rts2 | s_ld_pch |
s_iy2 | s_ix2 | s_abs1 ) ? {{di,tmp}+{8'b0,xyz_reg}} : // abs : abs,x : abs,y : (zp),y
// zero page modes
(s_exec & (zpxy | ix | iy)) ? {8'h00,di + xyz_reg} : // zp : zp,x : zp,y : (zp,x) : (zp),y // all zp modes
// branch instr.
// ma = pc + (sign extend)disp
(s_branch & taken) ? {pc_reg + {{8{tmp[DBW-1]}},tmp}} :
// ma = ma
((s_dataFetch|s_update) & grp2m) ? ma :
// ma = pc
((s_branch & ~taken) | s_pul | s_afterWrite |
(s_exec & (imm | mop)) | ((s_dataFetch|s_update) & (grp0 | grp1 | grp2x)) ) ?
pc_reg :
// all stack modes
((s_exec & (brk|psh)) |
s_nmi1 | s_nmi2 |
s_jsr1 | s_jsr2 |
(s_sync & any_int)) ? { 8'h1, sp_reg } :
((s_exec & (pul|rts|rti)) |
s_rts1 | s_rti1 | s_rti2) ? { 8'h1, sp_addo } :
16'b0;
//-------------------------------------------------------------
//-------------------------------------------------------------
// latch incoming immediate data
always @(posedge clk)
if (reset)
dil <= 8'b0;
else begin
if (rdy) begin
if (s_exec & imm)
dil <= di;
else if (s_dataFetch)
dil <= di;
end
end
// - - - - - - - - - - - - - - - - - - - -
// pc / ma manipulation
always @(s_reset3 or s_rts2 or s_rts3 or s_rti3 or s_nmi5 or
s_exec or s_ld_pch or s_abs1 or
jmp or jsr or s_sync or any_int or
branch or s_branch or s_jsr1 or s_jsr2 or imm or zpxy or
ix or iy or absxy or jmpi or pc_reg or di or tmp or ir or
ma_nxt)
begin
if (
s_rts2 | s_rts3 |
s_rti3 | s_nmi5 |
(s_reset3 | s_ld_pch | (s_abs1 & jmp)) |
(s_sync & ~any_int) |
s_branch |
(s_exec & branch) |
(s_exec & jsr)
)
pc_nxt = ma_nxt;
else if (s_jsr1)
pc_nxt = {di,pc_reg[7:0]};
else if (s_jsr2)
pc_nxt = {pc_reg[15:8],tmp};
else if (
(s_exec & (imm | zpxy | ix | iy | absxy)) |
(s_abs1 & ~(jmp | jmpi)) )
pc_nxt = pc_reg + 16'd1;
else
pc_nxt = pc_reg;
end
always @(posedge clk)
begin
if (reset)
begin
pc_reg <= `RESET_VEC;
ma <= `RESET_VEC;
end
else
if (rdy)
begin
ma <= ma_nxt;
pc_reg <= pc_nxt;
end
end
reg debug_cpu/*verilator public_flat*/;
`ifdef SIMULATION
always @(posedge clk) begin
if (reset == 1'b0 && debug_cpu == 1'b1) begin
$display("POS pc=%x %s ma=%x ir=%x di=%x dil=%x do=%x rw=%x a=%x x=%x y=%x vf=%x if=%x zf=%x nf=%x cf=%x sync=%x irq %x anyint %x im %x", pc_reg, getstatename(ir), ma , ir, di, dil, dout, rw, a_reg, x_reg, y_reg, vf, im, zf, nf, cf, sync, irq, any_int, im);
end
end
function [8*6-1:0] getstatename;
input [7:0] state;
begin
/* verilator lint_off WIDTH */
case(state)
`JSR: getstatename = "JSR";
`JMP: getstatename = "JMP";
`JMP_I: getstatename = "JMP_I";
`RTS: getstatename = "RTS";
`RTI: getstatename = "RTI";
`PHP: getstatename = "PHP";
`PHA: getstatename = "PHA";
`PLP: getstatename = "PLP";
`PLA: getstatename = "PLA";
`BRK: getstatename = "BRK";
`INX: getstatename = "INX";
`DEX: getstatename = "DEX";
`INY: getstatename = "INY";
`DEY: getstatename = "DEY";
`TYA: getstatename = "TYA";
`TAY: getstatename = "TAY";
`TXA: getstatename = "TXA";
`TAX: getstatename = "TAX";
`TXS: getstatename = "TXS";
`TSX: getstatename = "TSX";
`ASL_A: getstatename = "ASL_A";
`ASL_Z: getstatename = "ASL_Z";
// `define ASL_ZX 8'h16
// `define ASL_ABS 8'h0E
// `define ASL_AX 8'h1E
// `define ROL_A 8'h2A
// `define ROL_Z 8'h26
// `define ROL_ZX 8'h36
// `define ROL_ABS 8'h2E
// `define ROL_AX 8'h3e
`LSR_A: getstatename = "LSR_A";
`LSR_Z: getstatename = "LSR_Z";
`LSR_ZX: getstatename = "LSR_ZX";
`LSR_ABS: getstatename = "LSR_ABS";
`LSR_AX: getstatename = "LSR_AX";
// `define ROR_A 8'h6A
// `define ROR_Z 8'h66
// `define ROR_ZX 8'h76
// `define ROR_ABS 8'h6E
// `define ROR_AX 8'h7E
`DEC_Z: getstatename = "DEC_Z";
`DEC_ZX: getstatename = "DEC_ZX";
`DEC_A: getstatename = "DEC_A";
`DEC_AX: getstatename = "DEC_AX";
`INC_Z: getstatename = "INC_Z";
`INC_ZX: getstatename = "INC_ZX";
`INC_A: getstatename = "INC_A";
`INC_AX: getstatename = "INC_AX";
`CLD: getstatename = "CLD";
`SED: getstatename = "SED";
`CLC: getstatename = "CLC";
`SEC: getstatename = "SEC";
`CLI: getstatename = "CLI";
`SEI: getstatename = "SEI";
`CLV: getstatename = "CLV";
`NOP: getstatename = "NOP";
8'h24: getstatename = "BIT_Z";
8'h2c: getstatename = "BIT_A";
// `define STY 3'b100
// `define LDY 3'b101
// `define CPY 3'b110
// `define CPX 3'b111
// // Group1 opcodes
// `define GROUP1 2'b01
// `define ORA 3'b000
8'h29: getstatename = "AND_I";
8'h59: getstatename = "AND_Z";
// `define EOR 3'b010
// `define ADC 3'b011
// `define STA 3'b100
// `define LDA 3'b101
8'hC9: getstatename = "CMP_I";
8'hC5: getstatename = "CMP_Z";
// `define SBC 3'b111
// // Group2 opcodes
// `define GROUP2 2'b10
// `define ASL 3'b000
// `define ROL 3'b001
// `define LSR 3'b010
// `define ROR 3'b011
// `define STX 3'b100
// `define LDX 3'b101
// `define DEC 3'b110
// `define INC 3'b111
8'h10: getstatename = "BPL";
8'h30: getstatename = "BMI";
8'h50: getstatename = "BVC";
8'h70: getstatename = "BVS";
8'h90: getstatename = "BCC";
8'hB0: getstatename = "BCS";
8'hd0: getstatename = "BNE";
8'hf0: getstatename = "BEQ";
`LDA_I: getstatename = "LDA_I";
`LDA_Z: getstatename = "LDA_Z";
`LDA_ZX: getstatename = "LDA_ZX";
`LDA_IX: getstatename = "LDA_IX";
`LDA_IY: getstatename = "LDA_IY";
`LDA_A: getstatename = "LDA_A";
`LDA_AX: getstatename = "LDA_AX";
`LDA_AY: getstatename = "LDA_AY";
`LDY_I: getstatename = "LDY_I";
`LDY_Z: getstatename = "LDY_Z";
`LDY_ZX: getstatename = "LDY_ZX";
`LDY_A: getstatename = "LDY_A";
`LDY_AX: getstatename = "LDY_AX";
`CPY_I: getstatename = "CPY_I";
`LDX_I: getstatename = "LDX_I";
`LDX_Z: getstatename = "LDX_Z";
`LDX_ZY: getstatename = "LDX_ZY";
`LDX_A: getstatename = "LDX_A";
`LDX_AY: getstatename = "LDX_AY";
`CPX_I: getstatename = "CPX_I";
`STA_Z: getstatename = "STA_Z";
`STA_ZX: getstatename = "STA_ZX";
`STA_IX: getstatename = "STA_IX";
`STA_IY: getstatename = "STA_IY";
`STA_A: getstatename = "STA_A";
`STA_AX: getstatename = "STA_AX";
`STA_AY: getstatename = "STA_AY";
`STY_Z: getstatename = "STY_Z";
`STY_ZX: getstatename = "STY_ZX";
`STY_A: getstatename = "STY_A";
`STX_Z: getstatename = "STX_Z";
`STX_ZY: getstatename = "STX_ZY";
`STX_A: getstatename = "STX_A";
default: getstatename = "???";
endcase
/* verilator lint_on WIDTH */
end
endfunction
`endif
// - - - - - - - - - - - - - - - - - - - -
// sp manipulation
// we also reset the other regs here
always @(posedge clk)
if (reset)
sp_reg <= `SP_RESET;
else if (rdy) begin
if (
s_nmi1 | s_nmi2 |
s_jsr1 | s_jsr2 |
(s_sync & any_int) |
(s_exec & (brk|psh|pul|rts|rti)) |
s_rts1 | s_rti1 | s_rti2
)
sp_reg <= sp_addo;
else if (s_exec & txs)
sp_reg <= res;
end
// tmp manipulation
always @(posedge clk)
if (reset)
tmp <= 0;
else if (rdy) begin
if (s_reset2 | s_nmi4 | s_rts1 | s_rti2 |
s_jmpi1 |
s_ix1 | s_iy1 | (s_exec & absxy) |
(s_exec & (jsr | branch))
)
tmp <= di;
end
// rw manipulation - - - - - - - - - - - - - - - - - - - - - -
// Note: the cpu is always either reading or writing to memory,
// it doesn't have any idle cycles. This can be seen from the
// memory address multiplexer, which is always set to a valid
// value.
always @(s_sync or any_int or zpxy or psh or brk or ldx or
staxy or s_exec or ir or s_jsr1 or s_jsr2 or
s_ix2 or
s_iy2 or s_abs1 or
s_nmi1 or s_nmi2 or s_update or grp2m)
begin
if ( (s_sync & any_int) |
(s_exec & zpxy & staxy) |
(s_exec & (brk|psh)) |
s_jsr1 | s_jsr2 |
(staxy & (s_ix2 | s_iy2 | s_abs1)) |
s_nmi1 | s_nmi2 |
(s_update & grp2m) )
rw_nxt = 0;
else
rw_nxt = 1;
end
always @(posedge clk)
if (reset)
rw <= 1;
else if (rdy)
rw <= rw_nxt;
// dout manipulation - - - - - - - - - - - - - - - - - - - - -
always @(s_nmi1 or s_nmi2 or
s_jsr1 or s_jsr2 or pc_reg or sr_reg or
php or pha or staxy or axy_reg or
nf or vf or bf or df or zf or cf or im or brk or
s_exec or zpxy or s_ix2 or s_iy2 or grp2m or
s_abs1 or sta or stx or s_sync or any_int or
s_update or a_reg or x_reg or y_reg or dout or grp2_o)
begin
// Place pc on bus for interrupt, or subroutine call
if ((s_sync & any_int) | (s_exec & brk) | s_jsr1)
dout_nxt = pc_reg[ABW-1:8];
else if (s_nmi1 | s_jsr2)
dout_nxt = pc_reg[7:0];
else if ((staxy & ((s_exec & zpxy) | (s_ix2 | s_iy2 | s_abs1))) |
(s_exec & pha) )
dout_nxt = axy_reg;
else if ((s_exec & php) | s_nmi2)
dout_nxt = sr_reg;
else if (s_update & grp2m)
dout_nxt = grp2_o;
else
dout_nxt = dout;
end
always @(posedge clk)
if (reset)
dout <= 8'b0;
else if (rdy)
dout <= dout_nxt;
// A,X,Y Register loading - - - - - - - - - - - - -
always @(posedge clk) begin
if (reset) begin
a_reg <= 8'b0;
x_reg <= 8'b0;
y_reg <= 8'b0;
end
else begin
if (rdy) begin
if ( (s_exec & (tya | txa | ror_a | lsr_a | rol_a | asl_a)) |
(s_pul & pla) |
(s_update & grp1 & ~cmp) )
a_reg <= res;
if ( (s_exec & (inx | dex | tax | tsx)) |
(s_update & grp2 & ldx) )
x_reg <= res;
if ( (s_exec & (iny | dey | tay)) |
(s_update & grp0 & ldy) )
y_reg <= res;
end
end
end
// Load instruction register - - - - - - - - - - - - - - - - -
// Also track the nmi state for nmi edge detection
always @(posedge clk)
if (reset) begin
ir <= `NOP;
prev_nmi <= 0;
end
else if (s_reset1) begin
ir <= `NOP;
prev_nmi <= 0;
end
else if (rdy & s_sync) begin
ir <= di;
prev_nmi <= nmi;
end
// Evaluate branch condition - - - - - - - - - - - - - - - - -
reg takb;
always @(cond or nf or vf or cf or zf)
begin
case (cond)
`BPL: takb = ~nf;
`BMI: takb = nf;
`BVC: takb = ~vf;
`BVS: takb = vf;
`BCC: takb = ~cf;
`BCS: takb = cf;
`BNE: takb = ~zf;
`BEQ: takb = zf;
endcase
end
// SR flags updating - - - - - - - - - - - - - - - - - - - - -
always @(posedge clk) begin
if (reset) begin
firq <= 0;
vf <= 0;
nf <= 0;
im <= 1;
zf <= 0;
cf <= 0;
df <= 0;
bf <= 0;
end
else if (rdy) begin
if (so)
vf <= 1'b1;
if (s_reset1) begin
firq <= 0;
fbrk <= 0;
cf <= 0;
df <= 0;
nf <= 0;
vf <= 0;
zf <= 0;
im <= 1;
bf <= 0;
end
// NMI / IRQ / BRK ---------------------
if (s_nmi2) begin
bf <= fbrk;
im <= 1;
end
if (s_nmi4) begin
fbrk <= 0;
firq <= 0;
end
// sync indicates the start of an instruction cycle
// when active. we can check for an nmi or irq first
// before proceding with the instruction.
if (s_sync) begin
// irq is level sensitive
if (any_int) begin
// nmi takes precedence
if (~nmi_edge)
firq <= 1;
end
end
else if (s_exec) begin
taken <= takb;
case (ir)
`BRK: fbrk <= 1;
`INX,`DEX,`TAX,`TSX,
`INY,`DEY,`TAY,
`TYA,`TXA:
begin
zf <= res==0;
nf <= res[DBW-1];
end
`CLD: df <= 0;
`SED: df <= 1;
`CLC: cf <= 0;
`SEC: cf <= 1;
`CLI: im <= 0;
`SEI: im <= 1;
`CLV: vf <= 0;
`ROR_A,`LSR_A:
begin
cf <= a_reg[0];
zf <= res==0;
nf <= res[DBW-1];
end
`ROL_A,`ASL_A:
begin
cf <= a_reg[DBW-1];
zf <= res==0;
nf <= res[DBW-1];
end
// eval branch cond.
default: ;
endcase
end
//======================================
// subsequent opcode states
//======================================
if ((s_pul & plp) | s_rti1) begin
nf <= res[7];
vf <= res[6];
bf <= res[4];
df <= res[3];
im <= res[2];
zf <= res[1];
cf <= res[0];
end
if (s_pul & pla) begin
zf <= res==0;
nf <= res[DBW-1];
end
// mega state1
// at this point the fetched op should be incoming
// from d.
// store will already have been done, except for
// memory direct
if (s_update) begin
if (grp0_us) begin
nf <= nfo0;
vf <= vfo0;
cf <= cfo0;
zf <= zfo0;
end
if (grp1_us) begin
nf <= nfo1;
vf <= vfo1;
cf <= cfo1;
zf <= zfo1;
end
if (grp2_us) begin
nf <= nfo2;
cf <= cfo2;
zf <= zfo2;
end
end // `s_update
end // if (rdy)
end
endmodule
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Handle Group 0 opcodes - opcodes with the two lsb = 00
// ------00
// LDY, STY, CPY, CPX, and BIT
module dp_group0(ir,a_reg,x_reg,y_reg,d,ni,vi,zi,ci,n,v,z,c);
parameter DBW = 8;
input [DBW-1:0] ir;
input [DBW-1:0] a_reg;
input [DBW-1:0] x_reg;
input [DBW-1:0] y_reg;
input [DBW-1:0] d;
input ni, vi, zi, ci;
output n, v, z, c;
wire [DBW-1:0] w_bit = a_reg & d;
wire [DBW:0] w_cpy = y_reg - d;
wire [DBW:0] w_cpx = x_reg - d;
reg [DBW-1:0] res;
wire ldy = ir[7:5]==`LDY;
wire cpy = ir[7:5]==`CPY;
wire cpx = ir[7:5]==`CPX;
wire bitt = ir[7:5]==`BIT;
always @(ir or w_cpx or w_cpy or w_bit or d) begin
case (ir[7:5])
`CPX: res = w_cpx[DBW-1:0];
`CPY: res = w_cpy[DBW-1:0];
`BIT: res = w_bit;
default: res = d;
endcase
end
assign n = cpy | cpx | ldy ? res[DBW-1] : bitt ? d[7] : ni;
assign z = cpy | cpx | bitt | ldy ? res==0 : zi;
assign v = bitt ? d[DBW-2] : vi;
assign c = cpy ? ~w_cpy[DBW] : cpx ? ~w_cpx[DBW] : ci;
endmodule
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Handle Group 1 opcodes - opcodes with the two lsb = 01
// ------01
//
module dp_group1(ir,dec,ni,vi,zi,ci,a_reg,d,o,n,v,z,c);
parameter DBW = 8;
input [7:0] ir;
input dec;
input ni, vi, zi, ci;
input [DBW-1:0] a_reg;
input [DBW-1:0] d;
output [DBW-1:0] o;
reg [DBW-1:0] o;
output n, v, z, c;
wire [DBW-1:0] adc_o, sbc_o, cmp_o;
wire adc_c, sbc_c, cmp_c;
wire adc = ir[7:5]==`ADC;
wire sbc = ir[7:5]==`SBC;
wire cmp = ir[7:5]==`CMP;
wire sta = ir[7:5]==`STA;
// alu ops
always @(ir or a_reg or d or adc_o or cmp_o or sbc_o) begin
case(ir[7:5])
`ORA: o = a_reg | d;
`AND: o = a_reg & d;
`EOR: o = a_reg ^ d;
`ADC: o = adc_o;
`STA: o = a_reg;
`LDA: o = d;
`CMP: o = cmp_o;
`SBC: o = sbc_o;
endcase
end
add #(`DECMD_SUPPORT) add0 (.dec(dec), .ci(ci), .a(a_reg), .b(d), .o(adc_o), .c(adc_c) );
// 6502 uses inverted carry on subtract
sub #(`DECMD_SUPPORT) sub0 (.dec(dec), .ci(~ci), .a(a_reg), .b(d), .o(sbc_o), .c(sbc_c) );
wire [DBW:0] cmp_tmp = a_reg - d; // compare
assign cmp_c = cmp_tmp[DBW];
assign cmp_o = cmp_tmp[DBW-1:0];
assign n = sta ? ni : o[DBW-1];
assign z = sta ? zi : o==0;
assign c = adc ? adc_c : sbc ? ~sbc_c : cmp ? ~cmp_c : ci;
assign v = (adc | sbc) ?
// (sbc ^ o[DBW-1] ^ d[DBW-1]) & (~sbc ^ a_reg[DBW-1] ^ d[DBW-1]) : vi;
(o[DBW-1] ^ a_reg[DBW-1]) & (o[DBW-1] ^ d[DBW-1]) : vi;
endmodule
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Handle Group 2 opcodes - opcodes with the two lsb = 10
// ------10
//
module dp_group2(ir,ldx,stxx,d,ci,ni,zi,c,n,z,o);
parameter DBW = 8;
input [7:0] ir;
input ldx;
input stxx;
input [DBW-1:0] d;
input ci, ni, zi;
output c, n, z;
output [DBW-1:0] o;
reg [DBW-1:0] o;
reg sc; // shift carry
wire d_shift = ~ir[7];
/* verilator lint_off LATCH */
always @(ir or d or ci) begin
case(ir[7:5])
`ASL: begin
o = {d[DBW-2:0],1'b0};
sc = d[DBW-1];
end
`ROL: begin
o = {d[DBW-2:0],ci};
sc = d[DBW-1];
end
`LSR: begin
o = {1'b0,d[DBW-1:1]};
sc = d[0];
end
`ROR: begin
o = {ci,d[DBW-1:1]};
sc = d[0];
end
// A store does not affect the flags so the output can
// be set to anything.
`STX: o = d;
// Output needs to be set on a load so the flags can
// be set.
`LDX: o = d;
`DEC: o = d - 8'd1;
`INC: o = d + 8'd1;
default: begin sc = sc; o = o; end
endcase
end
/* verilator lint_on LATCH */
assign c = d_shift ? sc : ci; // cf set only for shifts
assign n = stxx ? ni : o[DBW-1];
assign z = stxx ? zi : o==0;
endmodule
// Yikes!
// If you understand this, you're doing well. It took me
// quite a bit of head scratching. I've basically broken the
// add down into two half adds and adjusted the carry and
// sum based on decimal mode, mimicing the 6502.
// hc2 will only be set in decimal mode if least significant
// nybble is 10 or greater.
module add(dec, ci, a, b, o, c);
parameter dec_support = 1; // indicates whether or not to support decimal mode
input dec;
input ci;
input [7:0] a;
input [7:0] b;
output [7:0] o;
output c;
reg [7:0] o;
reg c;
wire c4, c8;
wire [7:0] dec_sum;
reg [9:0] bin_sum;
nyb_add na0(.dec(dec), .ci(ci), .a(a[3:0]), .b(b[3:0]), .o(dec_sum[3:0]), .c(c4) );
nyb_add na1(.dec(dec), .ci(c4), .a(a[7:4]), .b(b[7:4]), .o(dec_sum[7:4]), .c(c8) );
always @(a or b or ci)
bin_sum = {a,ci} + {b,1'b1};
always @(bin_sum or dec_sum or c8)
if (dec_support) begin
o = dec_sum;
c = c8;
end
else begin
o = bin_sum[8:1];
c = bin_sum[9];
end
endmodule
module nyb_add(dec, ci, a, b, o, c);
input dec; // decimal mode indicator
input ci; // carry in
input [3:0] a;
input [3:0] b;
output [3:0] o;
output c;
// Note: XST does not like assigning to grouped bits on LHS
// which is why all the temps
reg [5:0] tmp1;
reg [4:0] tmp2;
wire hc1 = tmp1[5];
wire hc2 = tmp2[4];
assign c = hc1 | hc2;
wire [3:0] sum = tmp1[4:1];
assign o = tmp2[3:0];
always @(dec or a or b or ci or sum or hc1) begin
tmp1 = {a,ci} + {b,1'b1};
// +6 if in decimal mode and lo nybble > 10
if (sum >= 4'd10)
tmp2 = sum + {1'b0,dec,dec,1'b0};
else
tmp2 = { 1'b0, sum};
end
endmodule
// Subtract is similar to add. In decimal mode, if the subtract
// results in a negative number, then six has to be subtracted
// from the nybble.
module sub(dec, ci, a, b, o, c);
parameter dec_support = 1; // indicates whether or not to support decimal mode
input dec;
input ci;
input [7:0] a;
input [7:0] b;
output [7:0] o;
output c;
reg [7:0] o;
reg c;
wire c4, c8;
wire [7:0] dec_dif;
reg [9:0] bin_dif;
nyb_sub ns0(.dec(dec), .ci(ci), .a(a[3:0]), .b(b[3:0]), .o(dec_dif[3:0]), .c(c4) );
nyb_sub ns1(.dec(dec), .ci(c4), .a(a[7:4]), .b(b[7:4]), .o(dec_dif[7:4]), .c(c8) );
always @(a or b or ci)
bin_dif = {a,~ci} - {b,1'b1};
always @(bin_dif or dec_dif or c8)
if (dec_support) begin
o = dec_dif;
c = c8;
end
else begin
o = bin_dif[8:1];
c = bin_dif[9];
end
endmodule
module nyb_sub(dec, ci, a, b, o, c);
input dec; // decimal mode indicator
input ci; // carry in
input [3:0] a;
input [3:0] b;
output [3:0] o;
output c;
// Note: XST does not like assigning to grouped bits on LHS
// which is why all the temps
reg [5:0] tmp1;
reg [4:0] tmp2;
wire hb1 = tmp1[5];
wire hb2 = tmp2[4];
assign c = hb1 | hb2;
wire [3:0] dif = tmp1[4:1];
assign o = tmp2[3:0];
always @(dec or a or b or ci or dif or hb1) begin
tmp1 = {a,~ci} - {b,1'b1};
// -6 if in decimal mode and lo nybble < 0
tmp2 = dif - {1'b0, hb1 & dec, hb1 & dec, 1'b0};
end
endmodule
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// This module sequences through the states based on previous
// states, the ir value, and some control signals.
// A one hot state machine is used because we have plenty
// of regs and it eases decoding.
module sequencer(reset, creset, clk, rdy,
any_int, grp0, grp1, grp2x, grp2m,
brk,
mop,
rti, rts, pul, psh,
jsr,
jmp, jmpi, branch, staxy, ix, iy, absxy, imm, zpxy,
s_reset, s_reset1, s_reset2, s_reset3,
s_nmi1, s_nmi2, s_nmi3, s_nmi4, s_nmi5,
s_ld_pch, s_exec, s_branch, s_dataFetch, s_update, s_afterWrite,
s_ix1, s_ix2, s_iy1, s_iy2,
s_abs1,
s_jmpi1,
s_jsr1, s_jsr2,
s_pul,
s_rts1, s_rts2, s_rts3,
s_rti1, s_rti2, s_rti3,
s_sync);
input reset;
input creset;
input clk;
input rdy;
input any_int;
input grp0, grp1, grp2x, grp2m;
input brk;
input mop;
input rti;
input rts;
input pul;
input psh;
input jsr;
input jmp;
input jmpi;
input branch;
input staxy;
input ix;
input iy;
input absxy;
input imm;
input zpxy;
output s_reset;
output s_reset1;
output s_reset2;
output s_reset3;
output s_nmi1, s_nmi2, s_nmi3, s_nmi4, s_nmi5;
output s_ld_pch;
output s_exec;
output s_branch;
output s_dataFetch;
output s_update;
output s_afterWrite;
output s_ix1, s_ix2;
output s_iy1, s_iy2;
output s_abs1;
output s_jmpi1;
output s_jsr1, s_jsr2;
output s_pul;
output s_rts1, s_rts2, s_rts3;
output s_rti1, s_rti2, s_rti3;
output s_sync;
reg s_reset;
reg s_reset1;
reg s_reset2;
reg s_reset3;
reg s_nmi1, s_nmi2, s_nmi3, s_nmi4, s_nmi5;
reg s_ld_pch;
reg s_exec;
reg s_branch;
reg s_dataFetch;
reg s_update;
reg s_afterWrite;
reg s_ix1;
reg s_ix2;
reg s_iy1;
reg s_iy2;
reg s_abs1;
reg s_jmpi1;
reg s_jsr1, s_jsr2;
reg s_pul;
reg s_rts1, s_rts2, s_rts3;
reg s_rti1, s_rti2, s_rti3;
reg s_sync;
always @(posedge clk) begin
// put our states in a known condition - none selected
if (reset) begin
s_reset <= 1;
s_reset1 <= 0;
s_reset2 <= 0;
s_reset3 <= 0;
s_nmi1 <= 0;
s_nmi2 <= 0;
s_nmi3 <= 0;
s_nmi4 <= 0;
s_nmi5 <= 0;
s_ld_pch <= 0;
s_exec <= 0;
s_branch <= 0;
s_dataFetch <= 0; // Latch in non-immediate data
s_update <= 0; // Update the machine state
s_afterWrite <= 0; // Switch the address bus back to pc after a write.
s_ix1 <= 0;
s_ix2 <= 0;
s_iy1 <= 0;
s_iy2 <= 0;
s_abs1 <= 0;
s_jmpi1 <= 0;
s_jsr1 <= 0;
s_jsr2 <= 0;
s_pul <= 0;
s_rts1 <= 0;
s_rts2 <= 0;
s_rts3 <= 0;
s_rti1 <= 0;
s_rti2 <= 0;
s_rti3 <= 0;
s_sync <= 0;
end
else if (creset)
s_reset <= 1;
else if (rdy) begin
// advance states
// Only a single state should be active at any one time
// the reset state is actually evaluated here rather
// than at a higher level as it is convenient to do so
if (s_reset)
s_reset <= 0;
s_reset1 <= s_reset;
s_reset2 <= s_reset1;
s_reset3 <= s_reset2;
s_nmi1 <= (s_sync & any_int) | (s_exec & brk);
s_exec <= s_sync & ~any_int;
s_nmi2 <= s_nmi1;
s_nmi3 <= s_nmi2;
s_nmi4 <= s_nmi3;
s_nmi5 <= s_nmi4;
s_sync <= s_reset3 | s_afterWrite | s_ld_pch | s_pul | s_rts3 |
s_rti3 | s_nmi5 |
(s_abs1 & jmp) | s_branch |
(s_update & (grp0 | grp1 | grp2x)) |
(s_exec & mop);
s_branch <= s_exec & branch;
s_rts1 <= s_exec & rts;
s_rts2 <= s_rts1;
s_rts3 <= s_rts2;
s_rti1 <= s_exec & rti;
s_rti2 <= s_rti1;
s_rti3 <= s_rti2;
s_pul <= (s_exec & pul);
s_jsr1 <= (s_exec & jsr);
s_jsr2 <= s_jsr1;
s_jmpi1 <= s_abs1 & jmpi;
s_ld_pch <= s_jmpi1;
s_dataFetch <= ~staxy & (
(s_abs1 & ~(jmp | jmpi)) |
s_ix2 | s_iy2 | (s_exec & zpxy));
s_update <= s_dataFetch | (s_exec & imm);
s_afterWrite <= s_jsr2 |
(s_update & grp2m) |
(s_abs1 & staxy) |
(s_ix2 & staxy) |
(s_iy2 & staxy) |
(s_exec & ((zpxy & staxy) | psh));
s_ix1 <= s_exec & ix;
s_ix2 <= s_ix1;
s_iy1 <= s_exec & iy;
s_iy2 <= s_iy1;
s_abs1 <= s_exec & absxy;
end // if (rdy)
end // always
endmodule