1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-02-24 07:52:14 +00:00
Files
Gehstock.Mist_FPGA/common/CPU/MC6809/mc6809is.v
2019-07-22 23:42:05 +02:00

4155 lines
124 KiB
Verilog

`timescale 1ns / 1ns
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer: Greg Miller
// Copyright (c) 2016, Greg Miller
//
// Create Date: 14:26:59 08/13/2016
// Design Name:
// Module Name: mc6809
// Project Name: Cycle-Accurate 6809 Core
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies: Intended to be standalone Vanilla Verilog.
//
// Revision:
// Revision 1.0 - Initial Release
// Revision 1.0s - Sinchronous version (by Sorgelig)
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
//
// The 6809 has incomplete instruction decoding. A collection of instructions, if met, end up actually behaving like
// a binary-adjacent neighbor.
//
// The soft core permits three different behaviors for this situation, controlled by the instantiation parameter
// ILLEGAL_INSTRUCTIONS
//
// "GHOST" - Mimic the 6809's incomplete decoding. This is as similar to a hard 6809 as is practical. [DEFAULT]
//
// "STOP" - Cause the soft core to cease execution, placing $DEAD on the address bus and R/W to 'read'. Interrupts,
// bus control (/HALT, /DMABREQ), etc. are ignored. The core intentionally seizes in this instance.
// (Frankly, this is useful when making changes to the core and you have a logic analyzer connected.)
//
// "IGNORE"- Cause the soft core to merely ignore illegal instructions. It will consider them 1-byte instructions and
// attempt to fetch and run an exception 1 byte later.
//
module mc6809is
#(
parameter ILLEGAL_INSTRUCTIONS="GHOST"
)
(
input CLK,
input fallE_en,
input fallQ_en,
input [7:0] D,
output [7:0] DOut,
output [15:0] ADDR,
output RnW,
output BS,
output BA,
input nIRQ,
input nFIRQ,
input nNMI,
output AVMA,
output BUSY,
output LIC,
input nHALT,
input nRESET,
input nDMABREQ,
output [111:0] RegData
);
reg [7:0] DOutput;
assign DOut = DOutput;
reg RnWOut; // Combinatorial
reg rLIC;
assign LIC = rLIC;
reg rAVMA;
assign AVMA = rAVMA;
reg rBUSY;
assign BUSY = rBUSY;
// Bus control
// BS BA
// 0 0 normal (CPU running, CPU is master)
// 0 1 Interrupt Ack
// 1 0 Sync Ack
// 1 1 CPU has gone high-Z on A, D, R/W
//
assign RnW = RnWOut;
/////////////////////////////////////////////////
// Vectors
`define RESET_VECTOR 16'HFFFE
`define NMI_VECTOR 16'HFFFC
`define SWI_VECTOR 16'HFFFA
`define IRQ_VECTOR 16'HFFF8
`define FIRQ_VECTOR 16'HFFF6
`define SWI2_VECTOR 16'HFFF4
`define SWI3_VECTOR 16'HFFF2
`define Reserved_VECTOR 16'HFFF0
//////////////////////////////////////////////////////
// Latched registers
//
// The last-latched copy.
reg [7:0] a;
reg [7:0] b;
reg [15:0] x;
reg [15:0] y;
reg [15:0] u;
reg [15:0] s;
reg [15:0] pc;
reg [7:0] dp;
reg [7:0] cc;
reg [15:0] tmp;
reg [15:0] addr;
reg [15:0] ea;
// Debug ability to export register contents
assign RegData[7:0] = a;
assign RegData[15:8] = b;
assign RegData[31:16] = x;
assign RegData[47:32] = y;
assign RegData[63:48] = s;
assign RegData[79:64] = u;
assign RegData[87:80] = cc;
assign RegData[95:88] = dp;
assign RegData[111:96] = pc;
// The values as being calculated
reg [7:0] a_nxt;
reg [7:0] b_nxt;
reg [15:0] x_nxt;
reg [15:0] y_nxt;
reg [15:0] u_nxt;
reg [15:0] s_nxt;
reg [15:0] pc_nxt;
reg [7:0] dp_nxt;
reg [7:0] cc_nxt;
reg [15:0] addr_nxt;
reg [15:0] ea_nxt;
reg [15:0] tmp_nxt;
reg BS_nxt;
reg BA_nxt;
// for ADDR, BS/BA, assign them to the flops
assign BS = BS_nxt;
assign BA = BA_nxt;
assign ADDR=addr_nxt;
localparam CC_E= 8'H80;
localparam CC_F= 8'H40;
localparam CC_H= 8'H20;
localparam CC_I= 8'H10;
localparam CC_N= 8'H08;
localparam CC_Z= 8'H04;
localparam CC_V= 8'H02;
localparam CC_C= 8'H01;
localparam CC_E_BIT= 3'd7;
localparam CC_F_BIT= 3'd6;
localparam CC_H_BIT= 3'd5;
localparam CC_I_BIT= 3'd4;
localparam CC_N_BIT= 3'd3;
localparam CC_Z_BIT= 3'd2;
localparam CC_V_BIT= 3'd1;
localparam CC_C_BIT= 3'd0;
// Convenience calculations
reg [15:0] pc_p1;
reg [15:0] pc_p2;
reg [15:0] pc_p3;
reg [15:0] s_p1;
reg [15:0] s_m1;
reg [15:0] u_p1;
reg [15:0] u_m1;
reg [15:0] addr_p1;
reg [15:0] ea_p1;
//////////////////////////////////////////////////////
// NMI Mask
//
// NMI is supposed to be masked - despite the name - until the 6809 loads a value into S.
// Frankly, I'm cheating slightly. If someone does a LDS #$0, it won't disable the mask. Pretty much anything else
// that changes the value of S from the default (which is currently $0) will clear the mask. A reset will set the mask again.
reg NMIMask;
reg NMILatched;
reg NMISample;
reg NMISample2;
reg NMIClear;
reg NMIClear_nxt;
wire wNMIClear = NMIClear;
reg IRQLatched;
reg IRQSample;
reg IRQSample2;
reg FIRQLatched;
reg FIRQSample;
reg FIRQSample2;
reg HALTLatched;
reg HALTSample;
reg HALTSample2;
reg DMABREQLatched;
reg DMABREQSample;
reg DMABREQSample2;
// Interrupt types
localparam INTTYPE_NMI = 3'H0 ;
localparam INTTYPE_IRQ = 3'H1 ;
localparam INTTYPE_FIRQ = 3'H2 ;
localparam INTTYPE_SWI = 3'H3 ;
localparam INTTYPE_SWI2 = 3'H4 ;
localparam INTTYPE_SWI3 = 3'H5 ;
reg [2:0] IntType;
reg [2:0] IntType_nxt;
//////////////////////////////////////////////////////
// Instruction Fetch Details
//
reg InstPage2;
reg InstPage3;
reg InstPage2_nxt;
reg InstPage3_nxt;
reg [7:0] Inst1;
reg [7:0] Inst2;
reg [7:0] Inst3;
reg [7:0] Inst1_nxt;
reg [7:0] Inst2_nxt;
reg [7:0] Inst3_nxt;
localparam CPUSTATE_RESET = 7'd0;
localparam CPUSTATE_RESET0 = 7'd1;
localparam CPUSTATE_RESET2 = 7'd3;
localparam CPUSTATE_FETCH_I1 = 7'd4;
localparam CPUSTATE_FETCH_I1V2 = 7'd5;
localparam CPUSTATE_FETCH_I2 = 7'd8;
localparam CPUSTATE_LBRA_OFFSETLOW = 7'd17;
localparam CPUSTATE_LBRA_DONTCARE = 7'd18;
localparam CPUSTATE_LBRA_DONTCARE2 = 7'd19;
localparam CPUSTATE_BRA_DONTCARE = 7'd20;
localparam CPUSTATE_BSR_DONTCARE1 = 7'd21;
localparam CPUSTATE_BSR_DONTCARE2 = 7'd22;
localparam CPUSTATE_BSR_RETURNLOW = 7'd23;
localparam CPUSTATE_BSR_RETURNHIGH = 7'd24;
localparam CPUSTATE_TFR_DONTCARE1 = 7'd26;
localparam CPUSTATE_TFR_DONTCARE2 = 7'd27;
localparam CPUSTATE_TFR_DONTCARE3 = 7'd28;
localparam CPUSTATE_TFR_DONTCARE4 = 7'd29;
localparam CPUSTATE_EXG_DONTCARE1 = 7'd30;
localparam CPUSTATE_EXG_DONTCARE2 = 7'd31;
localparam CPUSTATE_EXG_DONTCARE3 = 7'd32;
localparam CPUSTATE_EXG_DONTCARE4 = 7'd33;
localparam CPUSTATE_EXG_DONTCARE5 = 7'd34;
localparam CPUSTATE_EXG_DONTCARE6 = 7'd35;
localparam CPUSTATE_ABX_DONTCARE = 7'd36;
localparam CPUSTATE_RTS_HI = 7'd38;
localparam CPUSTATE_RTS_LO = 7'd39;
localparam CPUSTATE_RTS_DONTCARE2 = 7'd40;
localparam CPUSTATE_16IMM_LO = 7'd41;
localparam CPUSTATE_ALU16_DONTCARE = 7'd42;
localparam CPUSTATE_DIRECT_DONTCARE = 7'd43;
localparam CPUSTATE_ALU_EA = 7'd44;
localparam CPUSTATE_ALU_DONTCARE = 7'd46;
localparam CPUSTATE_ALU_WRITEBACK = 7'd47;
localparam CPUSTATE_LD16_LO = 7'd48;
localparam CPUSTATE_ST16_LO = 7'd49;
localparam CPUSTATE_ALU16_LO = 7'd50;
localparam CPUSTATE_JSR_DONTCARE = 7'd53;
localparam CPUSTATE_JSR_RETLO = 7'd54;
localparam CPUSTATE_JSR_RETHI = 7'd55;
localparam CPUSTATE_EXTENDED_ADDRLO = 7'd56;
localparam CPUSTATE_EXTENDED_DONTCARE = 7'd57;
localparam CPUSTATE_INDEXED_BASE = 7'd58;
localparam CPUSTATE_IDX_DONTCARE3 = 7'd60;
localparam CPUSTATE_IDX_OFFSET_LO = 7'd61;
localparam CPUSTATE_IDX_16OFFSET_LO = 7'd62;
localparam CPUSTATE_IDX_16OFF_DONTCARE0= 7'd63;
localparam CPUSTATE_IDX_16OFF_DONTCARE1= 7'd64;
localparam CPUSTATE_IDX_16OFF_DONTCARE2= 7'd65;
localparam CPUSTATE_IDX_16OFF_DONTCARE3= 7'd66;
localparam CPUSTATE_IDX_DOFF_DONTCARE1 = 7'd68;
localparam CPUSTATE_IDX_DOFF_DONTCARE2 = 7'd69;
localparam CPUSTATE_IDX_DOFF_DONTCARE3 = 7'd70;
localparam CPUSTATE_IDX_PC16OFF_DONTCARE = 7'd71;
localparam CPUSTATE_IDX_EXTIND_LO = 7'd72;
localparam CPUSTATE_IDX_EXTIND_DONTCARE = 7'd73;
localparam CPUSTATE_INDIRECT_HI = 7'd74;
localparam CPUSTATE_INDIRECT_LO = 7'd75;
localparam CPUSTATE_INDIRECT_DONTCARE = 7'd76;
localparam CPUSTATE_MUL_ACTION = 7'd77;
localparam CPUSTATE_PSH_DONTCARE1 = 7'd80;
localparam CPUSTATE_PSH_DONTCARE2 = 7'd81;
localparam CPUSTATE_PSH_DONTCARE3 = 7'd82;
localparam CPUSTATE_PSH_ACTION = 7'd83;
localparam CPUSTATE_PUL_DONTCARE1 = 7'd84;
localparam CPUSTATE_PUL_DONTCARE2 = 7'd85;
localparam CPUSTATE_PUL_ACTION = 7'd86;
localparam CPUSTATE_NMI_START = 7'd87;
localparam CPUSTATE_IRQ_DONTCARE = 7'd88;
localparam CPUSTATE_IRQ_START = 7'd89;
localparam CPUSTATE_IRQ_DONTCARE2 = 7'd90;
localparam CPUSTATE_IRQ_VECTOR_HI = 7'd91;
localparam CPUSTATE_IRQ_VECTOR_LO = 7'd92;
localparam CPUSTATE_FIRQ_START = 7'd93;
localparam CPUSTATE_CC_DONTCARE = 7'd94;
localparam CPUSTATE_SWI_START = 7'd95;
localparam CPUSTATE_TST_DONTCARE1 = 7'd96;
localparam CPUSTATE_TST_DONTCARE2 = 7'd97;
localparam CPUSTATE_DEBUG = 7'd98;
localparam CPUSTATE_16IMM_DONTCARE = 7'd99;
localparam CPUSTATE_HALTED = 7'd100;
localparam CPUSTATE_HALT_EXIT2 = 7'd102;
localparam CPUSTATE_STOP = 7'd105;
localparam CPUSTATE_STOP2 = 7'd106;
localparam CPUSTATE_STOP3 = 7'd107;
localparam CPUSTATE_CWAI = 7'd108;
localparam CPUSTATE_CWAI_DONTCARE1 = 7'd109;
localparam CPUSTATE_CWAI_POST = 7'd110;
localparam CPUSTATE_DMABREQ = 7'd111;
localparam CPUSTATE_DMABREQ_EXIT = 7'd112;
localparam CPUSTATE_SYNC = 7'd113;
localparam CPUSTATE_SYNC_EXIT = 7'd114;
localparam CPUSTATE_INT_DONTCARE = 7'd115;
reg [6:0] CpuState = CPUSTATE_RESET;
reg [6:0] CpuState_nxt = CPUSTATE_RESET;
reg [6:0] NextState = CPUSTATE_RESET;
reg [6:0] NextState_nxt = CPUSTATE_RESET;
wire [6:0] PostIllegalState;
// If we encounter something like an illegal addressing mode (an index mode that's illegal for instance)
// What state should we go to?
generate
if (ILLEGAL_INSTRUCTIONS=="STOP")
begin : postillegal
assign PostIllegalState = CPUSTATE_STOP;
end
else
begin
assign PostIllegalState = CPUSTATE_FETCH_I1;
end
endgenerate
///////////////////////////////////////////////////////////////////////
//
// MapInstruction - Considering how the core was instantiated, this
// will either directly return D[7:0] *or* remap values from D[7:0]
// that relate to undefined instructions in the 6809 to the instructions
// that the 6809 actually executed when these were encountered, due to
// incomplete decoding.
//
// NEG, COM, LSR, DEC - these four instructions, in Direct, Inherent (A or B)
// Indexed, or Extended addressing do not actually decode bit 0 on the instruction.
// Thus, for instance, a $51 encountered will be executed as a $50, which is a NEGB.
//
// Specifically, the input is an instruction; if it matches an unknown instruction that the
// 6809 is known to ghost to another instruction, the output of the function
// is the the instruction that actually gets executed. Otherwise, the output is the
// input.
function [7:0] MapInstruction(input [7:0] i);
reg [3:0] topnyb;
reg [3:0] btmnyb;
reg [7:0] newinst;
begin
newinst = i;
topnyb = i[7:4];
btmnyb = i[3:0];
if ( (topnyb == 4'H0) ||
(topnyb == 4'H4) ||
(topnyb == 4'H5) ||
(topnyb == 4'H6) ||
(topnyb == 4'H7)
)
begin
if (btmnyb == 4'H1)
newinst = {topnyb, 4'H0};
if (btmnyb == 4'H2)
newinst = {topnyb, 4'H3};
if (btmnyb == 4'H5)
newinst = {topnyb, 4'H4};
if (btmnyb == 4'HB)
newinst = {topnyb, 4'HA};
end
MapInstruction = newinst;
end
endfunction
wire [7:0] MappedInstruction;
generate
if (ILLEGAL_INSTRUCTIONS=="GHOST")
begin : ghost
assign MappedInstruction = MapInstruction(D);
end
else
begin
assign MappedInstruction = D;
end
endgenerate
///////////////////////////////////////////////////////////////////////
function IllegalInstruction(input [7:0] i);
reg [3:0] hi;
reg [3:0] lo;
reg illegal;
begin
illegal = 1'b0;
hi = i[7:4];
lo = i[3:0];
if ( (hi == 4'H0) || (hi == 4'H4) || (hi == 4'H5) || (hi == 4'H6) || (hi == 4'H7) )
begin
if ( (lo == 4'H1) || (lo == 4'H2) || (lo == 4'H5) || (lo == 4'HB) )
illegal = 1'b1;
if (lo == 4'HE)
if ( (hi == 4'H4) || (hi == 4'H5) )
illegal = 1'b1;
end
if (hi == 4'H3)
begin
if ( (lo == 4'H8) || (lo == 4'HE) )
illegal = 1'b1;
end
if (hi == 4'H1)
begin
if ( (lo == 4'H4) || (lo == 4'H5) || (lo == 4'H8) || (lo == 4'HB) )
illegal = 1'b1;
end
if ( (hi == 4'H8) || (hi == 4'HC) )
begin
if ( (lo == 4'H7) || (lo == 4'HF) )
illegal = 1'b1;
if ( lo == 4'HD )
if (hi == 4'HC)
illegal = 1'b1;
end
IllegalInstruction = illegal;
end
endfunction
wire IsIllegalInstruction;
generate
if (ILLEGAL_INSTRUCTIONS=="GHOST")
begin : never_illegal
assign IsIllegalInstruction = 1'b0;
end
else
begin
assign IsIllegalInstruction = IllegalInstruction(Inst1);
end
endgenerate
wire [6:0] IllegalInstructionState;
generate
if (ILLEGAL_INSTRUCTIONS=="IGNORE")
begin : illegal_state
assign IllegalInstructionState = CPUSTATE_FETCH_I1;
end
else if (ILLEGAL_INSTRUCTIONS=="STOP")
begin
assign IllegalInstructionState = CPUSTATE_STOP;
end
else
begin
assign IllegalInstructionState = 7'd0;
end
endgenerate
///////////////////////////////////////////////////////////////////////
always @(posedge CLK)
begin
reg old_sample;
old_sample <= NMISample2;
if (wNMIClear == 1) NMILatched <= 1;
else if(old_sample & ~NMISample2) NMILatched <= NMIMask;
end
//
// The 6809 specs say that the CPU control signals are sampled on the falling edge of Q.
// It also says that the interrupts require 1 cycle of synchronization time.
// That's vague, as it doesn't say where "1 cycle" starts or ends. Starting from the
// falling edge of Q, the next cycle notices an assertion. From checking a hard 6809 on
// an analyzer, what they really mean is that it's sampled on the falling edge of Q,
// but there's a one cycle delay from the falling edge of E (0.25 clocks from the falling edge of Q
// where the signals were sampled) before it can be noticed.
// So, SIGNALSample is the latched value at the falling edge of Q
// SIGNALSample2 is the latched value at the falling edge of E (0.25 clocks after the line above)
// SIGNALLatched is the latched value at the falling edge of E (1 cycle after the line above)
//
// /HALT and /DMABREQ are delayed one cycle less than interrupts. The 6809 specs infer these details,
// but don't list the point-of-reference they're written from (for instance, they say that an interrupt requires
// a cycle for synchronization; however, it isn't clear whether that's from the falling Q to the next falling Q,
// a complete intermediate cycle, the falling E to the next falling E, etc.) - which, in the end, required an
// analyzer on the 6809 to determine how many cycles before a new instruction an interrupt (or /HALT & /DMABREQ)
// had to be asserted to be noted instead of the next instruction running start to finish.
//
always @(posedge CLK)
begin
if(fallQ_en) begin
NMISample <= nNMI;
IRQSample <= nIRQ;
FIRQSample <= nFIRQ;
HALTSample <= nHALT;
DMABREQSample <= nDMABREQ;
end
end
reg rnRESET=0; // The latched version of /RESET, useful 1 clock after it's latched
always @(posedge CLK)
begin
if(fallE_en) begin
rnRESET <= nRESET;
NMISample2 <= NMISample;
IRQSample2 <= IRQSample;
IRQLatched <= IRQSample2;
FIRQSample2 <= FIRQSample;
FIRQLatched <= FIRQSample2;
HALTSample2 <= HALTSample;
HALTLatched <= HALTSample2;
DMABREQSample2 <= DMABREQSample;
DMABREQLatched <= DMABREQSample2;
if (rnRESET == 1)
begin
CpuState <= CpuState_nxt;
// Don't interpret this next item as "The Next State"; it's a special case 'after this
// generic state, go to this programmable state', so that a single state
// can be shared for many tasks. [Specifically, the stack push/pull code, which is used
// for PSH, PUL, Interrupts, RTI, etc.
NextState <= NextState_nxt;
// CPU registers latch from the combinatorial circuit
a <= a_nxt;
b <= b_nxt;
x <= x_nxt;
y <= y_nxt;
s <= s_nxt;
u <= u_nxt;
cc <= cc_nxt;
dp <= dp_nxt;
pc <= pc_nxt;
tmp <= tmp_nxt;
addr <= addr_nxt;
ea <= ea_nxt;
InstPage2 <= InstPage2_nxt;
InstPage3 <= InstPage3_nxt;
Inst1 <= Inst1_nxt;
Inst2 <= Inst2_nxt;
Inst3 <= Inst3_nxt;
NMIClear <= NMIClear_nxt;
IntType <= IntType_nxt;
// Once S changes at all (default is '0'), release the NMI Mask.
if (s != s_nxt) NMIMask <= 1'b0;
end
else
begin
CpuState <= CPUSTATE_RESET;
NMIMask <= 1'b1; // Mask NMI until S is loaded.
NMIClear <= 1'b0; // Mark us as not having serviced NMI
end
end
end
/////////////////////////////////////////////////////////////////
// Decode the Index byte
localparam IDX_REG_X = 3'd0;
localparam IDX_REG_Y = 3'd1;
localparam IDX_REG_U = 3'd2;
localparam IDX_REG_S = 3'd3;
localparam IDX_REG_PC = 3'd4;
localparam IDX_MODE_POSTINC1 = 4'd0;
localparam IDX_MODE_POSTINC2 = 4'd1;
localparam IDX_MODE_PREDEC1 = 4'd2;
localparam IDX_MODE_PREDEC2 = 4'd3;
localparam IDX_MODE_NOOFFSET = 4'd4;
localparam IDX_MODE_B_OFFSET = 4'd5;
localparam IDX_MODE_A_OFFSET = 4'd6;
localparam IDX_MODE_5BIT_OFFSET= 4'd7; // Special case, not bit pattern 7; the offset sits in the bit pattern
localparam IDX_MODE_8BIT_OFFSET= 4'd8;
localparam IDX_MODE_16BIT_OFFSET = 4'd9;
localparam IDX_MODE_D_OFFSET = 4'd11;
localparam IDX_MODE_8BIT_OFFSET_PC = 4'd12;
localparam IDX_MODE_16BIT_OFFSET_PC= 4'd13;
localparam IDX_MODE_EXTENDED_INDIRECT = 4'd15;
// Return:
// Register base [3 bits]
// Indirect [1 bit]
// Mode [4 bits]
function [7:0] IndexDecode(input [7:0] postbyte);
reg [2:0] regnum;
reg indirect;
reg [3:0] mode;
begin
indirect = 0;
mode = 0;
if (postbyte[7] == 0) // 5-bit
begin
mode = IDX_MODE_5BIT_OFFSET;
end
else
begin
mode = postbyte[3:0];
indirect = postbyte[4];
end
if ((mode != IDX_MODE_8BIT_OFFSET_PC) && (mode != IDX_MODE_16BIT_OFFSET_PC))
regnum[2:0] = postbyte[6:5];
else
regnum[2:0] = IDX_REG_PC;
IndexDecode = {indirect, mode, regnum};
end
endfunction
wire [3:0] IndexedMode;
wire IndexedIndirect;
wire [2:0] IndexedRegister;
assign {IndexedIndirect, IndexedMode, IndexedRegister} = IndexDecode(Inst2);
/////////////////////////////////////////////////////////////////
// Is this a JMP instruction? (irrespective of addressing mode)
function IsJMP(input [7:0] inst);
reg [3:0] hi;
reg [3:0] lo;
begin
hi = inst[7:4];
lo = inst[3:0];
IsJMP = 0;
if ((hi == 4'H0) || (hi == 4'H6) || (hi == 4'H7))
if (lo == 4'HE)
IsJMP = 1;
end
endfunction
///////////////////////////////////////////////////////////////////
// Is this an 8-bit Store?
localparam ST8_REG_A = 1'b0;
localparam ST8_REG_B = 1'b1;
function [1:0] IsST8(input [7:0] inst);
reg regnum;
reg IsStore;
begin
IsStore = 1'b0;
regnum = 1'b1;
if ( (Inst1 == 8'H97) || (Inst1 == 8'HA7) || (Inst1 == 8'HB7) )
begin
IsStore = 1'b1;
regnum = 1'b0;
end
else if ( (Inst1 == 8'HD7) || (Inst1 == 8'HE7) || (Inst1 == 8'HF7) )
begin
IsStore = 1'b1;
regnum = 1'b1;
end
IsST8 = {IsStore, regnum};
end
endfunction
wire IsStore8;
wire Store8RegisterNum;
assign {IsStore8, Store8RegisterNum} = IsST8(Inst1);
/////////////////////////////////////////////////////////////////
// Is this a 16-bit Store?
localparam ST16_REG_X = 3'd0;
localparam ST16_REG_Y = 3'd1;
localparam ST16_REG_U = 3'd2;
localparam ST16_REG_S = 3'd3;
localparam ST16_REG_D = 3'd4;
function [3:0] IsST16(input [7:0] inst);
reg [3:0] hi;
reg [3:0] lo;
reg [2:0] regnum;
reg IsStore;
begin
hi = inst[7:4];
lo = inst[3:0];
IsStore = 1'b0;
regnum = 3'b111;
if ((inst == 8'H9F) || (inst == 8'HAF) || (inst == 8'HBF))
begin
IsStore = 1;
if (~InstPage2)
regnum = ST16_REG_X;
else
regnum = ST16_REG_Y;
end
else if ((inst == 8'HDF) || (inst == 8'HEF) || (inst == 8'HFF))
begin
IsStore = 1;
if (~InstPage2)
regnum = ST16_REG_U;
else
regnum = ST16_REG_S;
end
else if ((inst == 8'HDD) || (inst == 8'HED) || (inst == 8'HFD))
begin
IsStore = 1;
regnum = ST16_REG_D;
end
IsST16 = {IsStore, regnum};
end
endfunction
wire IsStore16;
wire [2:0] StoreRegisterNum;
assign {IsStore16, StoreRegisterNum} = IsST16(Inst1);
/////////////////////////////////////////////////////////////////
// Is this a special Immediate mode instruction, ala
// PSH, PUL, EXG, TFR, ANDCC, ORCC
function IsSpecialImm(input [7:0] inst);
reg is;
reg [3:0] hi;
reg [3:0] lo;
begin
hi = inst[7:4];
lo = inst[3:0];
is = 0;
if (hi == 4'H1)
begin
if ( (lo == 4'HA) || (lo == 4'HC) || (lo == 4'HE) || (lo == 4'HF) ) // ORCC, ANDCC, EXG, TFR
is = 1;
end
else if (hi == 4'H3)
begin
if ( (lo >= 4'H3) && (lo <= 4'H7) ) // PSHS, PULS, PSHU, PULU
is = 1;
end
else
is = 0;
IsSpecialImm = is;
end
endfunction
wire IsSpecialImmediate = IsSpecialImm(Inst1);
/////////////////////////////////////////////////////////////////
// Is this a one-byte instruction? [The 6809 reads 2 bytes for every instruction, minimum (it can read more). On a one-byte, we have to ensure that we haven't skipped the PC ahead.
function IsOneByteInstruction(input [7:0] inst);
reg is;
reg [3:0] hi;
reg [3:0] lo;
begin
hi = inst[7:4];
lo = inst[3:0];
is = 1'b0;
if ( (hi == 4'H4) || (hi == 4'H5) )
is = 1'b1;
else if ( hi == 4'H1)
begin
if ( (lo == 4'H2) || (lo == 4'H3) || (lo == 4'H9) || (lo == 4'HD) )
is = 1'b1;
end
else if (hi == 4'H3)
begin
if ( (lo >= 4'H9) && (lo != 4'HC) )
is = 1'b1;
end
else
is = 1'b0;
IsOneByteInstruction = is;
end
endfunction
/////////////////////////////////////////////////////////////////
// ALU16 - Simpler than the 8 bit ALU
localparam ALU16_REG_X = 3'd0;
localparam ALU16_REG_Y = 3'd1;
localparam ALU16_REG_U = 3'd2;
localparam ALU16_REG_S = 3'd3;
localparam ALU16_REG_D = 3'd4;
function [2:0] ALU16RegFromInst(input Page2, input Page3, input [7:0] inst);
reg [2:0] srcreg;
begin
srcreg = 3'b111; // default
casex ({Page2, Page3, inst}) // Note pattern for the matching below
10'b1010xx0011: // 1083, 1093, 10A3, 10B3 CMPD
srcreg = ALU16_REG_D;
10'b1010xx1100: // 108C, 109C, 10AC, 10BC CMPY
srcreg = ALU16_REG_Y;
10'b0110xx0011: // 1183, 1193, 11A3, 11B3 CMPU
srcreg = ALU16_REG_U;
10'b0110xx1100: // 118C, 119C, 11AC, 11BC CMPS
srcreg = ALU16_REG_S;
10'b0010xx1100: // 8C,9C,AC,BC CMPX
srcreg = ALU16_REG_X;
10'b0011xx0011: // C3, D3, E3, F3 ADDD
srcreg = ALU16_REG_D;
10'b0011xx1100: // CC, DC, EC, FC LDD
srcreg = ALU16_REG_D;
10'b0010xx1110: // 8E LDX, 9E LDX, AE LDX, BE LDX
srcreg = ALU16_REG_X;
10'b0011xx1110: // CE LDU, DE LDU, EE LDU, FE LDU
srcreg = ALU16_REG_U;
10'b1010xx1110: // 108E LDY, 109E LDY, 10AE LDY, 10BE LDY
srcreg = ALU16_REG_Y;
10'b1011xx1110: // 10CE LDS, 10DE LDS, 10EE LDS, 10FE LDS
srcreg = ALU16_REG_S;
10'b0010xx0011: // 83, 93, A3, B3 SUBD
srcreg = ALU16_REG_D;
10'H03A: // 3A ABX
srcreg = ALU16_REG_X;
10'H030: // 30 LEAX
srcreg = ALU16_REG_X;
10'H031: // 31 LEAY
srcreg = ALU16_REG_Y;
10'H032: // 32 LEAS
srcreg = ALU16_REG_S;
10'H033: // 32 LEAU
srcreg = ALU16_REG_U;
default:
srcreg = 3'b111;
endcase
ALU16RegFromInst = srcreg;
end
endfunction
wire [2:0] ALU16Reg = ALU16RegFromInst(InstPage2, InstPage3, Inst1);
localparam ALUOP16_SUB = 3'H0;
localparam ALUOP16_ADD = 3'H1;
localparam ALUOP16_LD = 3'H2;
localparam ALUOP16_CMP = 3'H3;
localparam ALUOP16_LEA = 3'H4;
localparam ALUOP16_INVALID = 3'H7;
function [3:0] ALU16OpFromInst(input Page2, input Page3, input [7:0] inst);
reg [2:0] aluop;
reg writeback;
begin
aluop = 3'b111;
writeback = 1'b1;
casex ({Page2, Page3, inst})
10'b1010xx0011: // 1083, 1093, 10A3, 10B3 CMPD
begin
aluop = ALUOP16_CMP;
writeback = 1'b0;
end
10'b1010xx1100: // 108C, 109C, 10AC, 10BC CMPY
begin
aluop = ALUOP16_CMP;
writeback = 1'b0;
end
10'b0110xx0011: // 1183, 1193, 11A3, 11B3 CMPU
begin
aluop = ALUOP16_CMP;
writeback = 1'b0;
end
10'b0110xx1100: // 118C, 119C, 11AC, 11BC CMPS
begin
aluop = ALUOP16_CMP;
writeback = 1'b0;
end
10'b0010xx1100: // 8C,9C,AC,BC CMPX
begin
aluop = ALUOP16_CMP;
writeback = 1'b0;
end
10'b0011xx0011: // C3, D3, E3, F3 ADDD
aluop = ALUOP16_ADD;
10'b0011xx1100: // CC, DC, EC, FC LDD
aluop = ALUOP16_LD;
10'b001xxx1110: // 8E LDX, 9E LDX, AE LDX, BE LDX, CE LDU, DE LDU, EE LDU, FE LDU
aluop = ALUOP16_LD;
10'b101xxx1110: // 108E LDY, 109E LDY, 10AE LDY, 10BE LDY, 10CE LDS, 10DE LDS, 10EE LDS, 10FE LDS
aluop = ALUOP16_LD;
10'b0010xx0011: // 83, 93, A3, B3 SUBD
aluop = ALUOP16_SUB;
10'H03A: // 3A ABX
aluop = ALUOP16_ADD;
10'b00001100xx: // $30-$33, LEAX, LEAY, LEAS, LEAU
aluop = ALUOP16_LEA;
default:
aluop = ALUOP16_INVALID;
endcase
ALU16OpFromInst = {writeback, aluop};
end
endfunction
wire ALU16OpWriteback;
wire [2:0] ALU16Opcode;
assign {ALU16OpWriteback, ALU16Opcode} = ALU16OpFromInst(InstPage2, InstPage3, Inst1);
wire IsALU16Opcode = (ALU16Opcode != 3'b111);
function [23:0] ALU16Inst(input [2:0] operation16, input [15:0] a_arg, input [15:0] b_arg, input [7:0] cc_arg);
reg [7:0] cc_out;
reg [15:0] ALUFn;
reg carry;
reg borrow;
begin
cc_out = cc_arg;
case (operation16)
ALUOP16_ADD:
begin
{cc_out[CC_C_BIT], ALUFn} = {1'b0, a_arg} + b_arg;
cc_out[CC_V_BIT] = (a_arg[15] & b_arg[15] & ~ALUFn[15]) | (~a_arg[15] & ~b_arg[15] & ALUFn[15]);
end
ALUOP16_SUB:
begin
{cc_out[CC_C_BIT], ALUFn} = {1'b0, a_arg} - {1'b0, b_arg};
cc_out[CC_V_BIT] = (a_arg[15] & ~b_arg[15] & ~ALUFn[15]) | (~a_arg[15] & b_arg[15] & ALUFn[15]);
end
ALUOP16_LD:
begin
ALUFn = b_arg;
cc_out[CC_V_BIT] = 1'b0;
end
ALUOP16_CMP:
begin
{cc_out[CC_C_BIT], ALUFn} = {1'b0, a_arg} - {1'b0, b_arg};
cc_out[CC_V_BIT] = (a_arg[15] & ~b_arg[15] & ~ALUFn[15]) | (~a_arg[15] & b_arg[15] & ALUFn[15]);
end
ALUOP16_LEA:
begin
ALUFn = a_arg;
end
default:
ALUFn = 16'H0000;
endcase
cc_out[CC_Z_BIT] = (ALUFn[15:0] == 16'H0000);
if (operation16 != ALUOP16_LEA)
cc_out[CC_N_BIT] = ALUFn[15];
ALU16Inst = {cc_out, ALUFn};
end
endfunction
reg [2:0] ALU16_OP;
reg [15:0] ALU16_A;
reg [15:0] ALU16_B;
reg [7:0] ALU16_CC;
// Top 8 bits == CC, bottom 8 bits = output value
wire [23:0] ALU16 = ALU16Inst(ALU16_OP, ALU16_A, ALU16_B, ALU16_CC);
/////////////////////////////////////////////////////////////////
// ALU
// The ops are organized from the 4 low-order bits of the instructions for the first set of ops, then 16-31 are the second set - even though bit 4 isn't representative.
localparam ALUOP_NEG = 5'd0;
localparam ALUOP_COM = 5'd3;
localparam ALUOP_LSR = 5'd4;
localparam ALUOP_ROR = 5'd6;
localparam ALUOP_ASR = 5'd7;
localparam ALUOP_ASL = 5'd8;
localparam ALUOP_LSL = 5'd8;
localparam ALUOP_ROL = 5'd9;
localparam ALUOP_DEC = 5'd10;
localparam ALUOP_INC = 5'd12;
localparam ALUOP_TST = 5'd13;
localparam ALUOP_CLR = 5'd15;
localparam ALUOP_SUB = 5'd16;
localparam ALUOP_CMP = 5'd17;
localparam ALUOP_SBC = 5'd18;
localparam ALUOP_AND = 5'd20;
localparam ALUOP_BIT = 5'd21;
localparam ALUOP_LD = 5'd22;
localparam ALUOP_EOR = 5'd24;
localparam ALUOP_ADC = 5'd25;
localparam ALUOP_OR = 5'd26;
localparam ALUOP_ADD = 5'd27;
function [5:0] ALUOpFromInst(input [7:0] inst);
reg [4:0] op;
reg writeback;
begin
// Okay, this turned out to be simpler than I expected ...
op = {inst[7], inst[3:0]};
case (op)
ALUOP_CMP:
writeback = 0;
ALUOP_TST:
writeback = 0;
ALUOP_BIT:
writeback = 0;
default:
writeback = 1;
endcase
ALUOpFromInst = {writeback, op};
end
endfunction
wire [4:0] ALU8Op;
wire ALU8Writeback;
assign {ALU8Writeback, ALU8Op} = ALUOpFromInst(Inst1);
reg [7:0] ALU_A;
reg [7:0] ALU_B;
reg [7:0] ALU_CC;
reg [4:0] ALU_OP;
function [15:0] ALUInst(input [4:0] operation, input [7:0] a_arg, input [7:0] b_arg, input [7:0] cc_arg);
reg [7:0] cc_out;
reg [7:0] ALUFn;
reg borrow;
begin
cc_out = cc_arg;
case (operation)
ALUOP_NEG:
begin
ALUFn = ~a_arg + 1'b1;
cc_out[CC_C_BIT] = (ALUFn != 8'H00);
cc_out[CC_V_BIT] = (a_arg == 8'H80);
end
ALUOP_LSL:
begin
{cc_out[CC_C_BIT], ALUFn} = {a_arg, 1'b0};
cc_out[CC_V_BIT] = a_arg[7] ^ a_arg[6];
end
ALUOP_LSR:
begin
{ALUFn, cc_out[CC_C_BIT]} = {1'b0, a_arg};
end
ALUOP_ASR:
begin
{ALUFn, cc_out[CC_C_BIT]} = {a_arg[7], a_arg};
end
ALUOP_ROL:
begin
{cc_out[CC_C_BIT], ALUFn} = {a_arg, cc_arg[CC_C_BIT]};
cc_out[CC_V_BIT] = a_arg[7] ^ a_arg[6];
end
ALUOP_ROR:
begin
{ALUFn, cc_out[CC_C_BIT]} = {cc_arg[CC_C_BIT], a_arg};
end
ALUOP_OR:
begin
ALUFn = (a_arg | b_arg);
cc_out[CC_V_BIT] = 0;
end
ALUOP_ADD:
begin
{cc_out[CC_C_BIT], ALUFn} = {1'b0, a_arg} + {1'b0, b_arg};
cc_out[CC_V_BIT] = (a_arg[7] & b_arg[7] & ~ALUFn[7]) | (~a_arg[7] & ~b_arg[7] & ALUFn[7]);
cc_out[CC_H_BIT] = a_arg[4] ^ b_arg[4] ^ ALUFn[4];
end
ALUOP_SUB:
begin
{cc_out[CC_C_BIT], ALUFn} = {1'b0, a_arg} - {1'b0, b_arg};
cc_out[CC_V_BIT] = (a_arg[7] & ~b_arg[7] & ~ALUFn[7]) | (~a_arg[7] & b_arg[7] & ALUFn[7]);
end
ALUOP_AND:
begin
ALUFn = (a_arg & b_arg);
cc_out[CC_V_BIT] = 0;
end
ALUOP_BIT:
begin
ALUFn = (a_arg & b_arg);
cc_out[CC_V_BIT] = 0;
end
ALUOP_EOR:
begin
ALUFn = (a_arg ^ b_arg);
cc_out[CC_V_BIT] = 0;
end
ALUOP_CMP:
begin
{cc_out[CC_C_BIT], ALUFn} = {1'b0, a_arg} - {1'b0, b_arg};
cc_out[CC_V_BIT] = (a_arg[7] & ~b_arg[7] & ~ALUFn[7]) | (~a_arg[7] & b_arg[7] & ALUFn[7]);
end
ALUOP_COM:
begin
ALUFn = ~a_arg;
cc_out[CC_V_BIT] = 0;
cc_out[CC_C_BIT] = 1;
end
ALUOP_ADC:
begin
{cc_out[CC_C_BIT], ALUFn} = {1'b0, a_arg} + {1'b0, b_arg} + cc_arg[CC_C_BIT];
cc_out[CC_V_BIT] = (a_arg[7] & b_arg[7] & ~ALUFn[7]) | (~a_arg[7] & ~b_arg[7] & ALUFn[7]);
cc_out[CC_H_BIT] = a_arg[4] ^ b_arg[4] ^ ALUFn[4];
end
ALUOP_LD:
begin
ALUFn = b_arg;
cc_out[CC_V_BIT] = 0;
end
ALUOP_INC:
begin
ALUFn = a_arg + 1'b1;
cc_out[CC_V_BIT] = (~a_arg[7] & ALUFn[7]);
end
ALUOP_DEC:
begin
ALUFn = a_arg - 1'b1;
cc_out[CC_V_BIT] = (a_arg[7] & ~ALUFn[7]);
end
ALUOP_CLR:
begin
ALUFn = 0;
cc_out[CC_V_BIT] = 0;
cc_out[CC_C_BIT] = 0;
end
ALUOP_TST:
begin
ALUFn = a_arg;
cc_out[CC_V_BIT] = 0;
end
ALUOP_SBC:
begin
{cc_out[CC_C_BIT], ALUFn} = {1'b0, a_arg} - {1'b0, b_arg} - cc_arg[CC_C_BIT];
cc_out[CC_V_BIT] = (a_arg[7] & ~b_arg[7] & ~ALUFn[7]) | (~a_arg[7] & b_arg[7] & ALUFn[7]);
end
default:
ALUFn = 0;
endcase
cc_out[CC_N_BIT] = ALUFn[7];
cc_out[CC_Z_BIT] = !ALUFn;
ALUInst = {cc_out[7:0], ALUFn};
end
endfunction
// Top 8 bits == CC, bottom 8 bits = output value
wire [15:0] ALU = ALUInst(ALU_OP, ALU_A, ALU_B, ALU_CC);
////////////////////////////////////////////////////////////
localparam TYPE_INHERENT = 3'd0;
localparam TYPE_IMMEDIATE = 3'd1;
localparam TYPE_DIRECT = 3'd2;
localparam TYPE_RELATIVE = 3'd3;
localparam TYPE_INDEXED = 3'd4;
localparam TYPE_EXTENDED = 3'd5;
localparam TYPE_INVALID = 3'd7;
// Function to decode the addressing mode the instruction uses
function [2:0] addressing_mode_type(input [7:0] inst);
begin
casex (inst)
8'b0000???? : addressing_mode_type = TYPE_DIRECT;
8'b0001???? :
begin
casex (inst[3:0])
4'b0010:
addressing_mode_type = TYPE_INHERENT;
4'b0011:
addressing_mode_type = TYPE_INHERENT;
4'b1001:
addressing_mode_type = TYPE_INHERENT;
4'b1101:
addressing_mode_type = TYPE_INHERENT;
4'b0110:
addressing_mode_type = TYPE_RELATIVE;
4'b0111:
addressing_mode_type = TYPE_RELATIVE;
4'b1010:
addressing_mode_type = TYPE_IMMEDIATE;
4'b1100:
addressing_mode_type = TYPE_IMMEDIATE;
4'b1110:
addressing_mode_type = TYPE_IMMEDIATE;
4'b1111:
addressing_mode_type = TYPE_IMMEDIATE;
default:
addressing_mode_type = TYPE_INVALID;
endcase
end
8'b0010????: addressing_mode_type = TYPE_RELATIVE;
8'b0011????:
begin
casex(inst[3:0])
4'b00??:
addressing_mode_type = TYPE_INDEXED;
4'b01??:
addressing_mode_type = TYPE_IMMEDIATE;
4'b1001:
addressing_mode_type = TYPE_INHERENT;
4'b101?:
addressing_mode_type = TYPE_INHERENT;
4'b1100:
addressing_mode_type = TYPE_INHERENT;
4'b1101:
addressing_mode_type = TYPE_INHERENT;
4'b1111:
addressing_mode_type = TYPE_INHERENT;
default:
addressing_mode_type = TYPE_INVALID;
endcase
end
8'b010?????: addressing_mode_type = TYPE_INHERENT;
8'b0110????: addressing_mode_type = TYPE_INDEXED;
8'b0111????: addressing_mode_type = TYPE_EXTENDED;
8'b1000????:
begin
casex (inst[3:0])
4'b0111: addressing_mode_type = TYPE_INVALID;
4'b1111: addressing_mode_type = TYPE_INVALID;
4'b1101: addressing_mode_type = TYPE_RELATIVE;
default: addressing_mode_type = TYPE_IMMEDIATE;
endcase
end
8'b1001????: addressing_mode_type = TYPE_DIRECT;
8'b1010????: addressing_mode_type = TYPE_INDEXED;
8'b1011????: addressing_mode_type = TYPE_EXTENDED;
8'b1100????: addressing_mode_type = TYPE_IMMEDIATE;
8'b1101????: addressing_mode_type = TYPE_DIRECT;
8'b1110????: addressing_mode_type = TYPE_INDEXED;
8'b1111????: addressing_mode_type = TYPE_EXTENDED;
endcase
end
endfunction
wire [2:0] AddrModeType = addressing_mode_type(Inst1);
//////////////////////////////////////////////////
// Individual opcodes that are the top of a column of states.
localparam OPCODE_INH_ABX = 8'H3A;
localparam OPCODE_INH_RTS = 8'H39;
localparam OPCODE_INH_RTI = 8'H3B;
localparam OPCODE_INH_CWAI = 8'H3C;
localparam OPCODE_INH_MUL = 8'H3D;
localparam OPCODE_INH_SWI = 8'H3F;
localparam OPCODE_INH_SEX = 8'H1D;
localparam OPCODE_INH_NOP = 8'H12;
localparam OPCODE_INH_SYNC = 8'H13;
localparam OPCODE_INH_DAA = 8'H19;
localparam OPCODE_IMM_ORCC = 8'H1A;
localparam OPCODE_IMM_ANDCC = 8'H1C;
localparam OPCODE_IMM_EXG = 8'H1E;
localparam OPCODE_IMM_TFR = 8'H1F;
localparam OPCODE_IMM_PSHS = 8'H34;
localparam OPCODE_IMM_PULS = 8'H35;
localparam OPCODE_IMM_PSHU = 8'H36;
localparam OPCODE_IMM_PULU = 8'H37;
localparam OPCODE_IMM_SUBD = 8'H83;
localparam OPCODE_IMM_CMPX = 8'H8C;
localparam OPCODE_IMM_LDX = 8'H8E;
localparam OPCODE_IMM_ADDD = 8'HC3;
localparam OPCODE_IMM_LDD = 8'HCC;
localparam OPCODE_IMM_LDU = 8'HCE;
localparam OPCODE_IMM_CMPD = 8'H83; // Page2
localparam OPCODE_IMM_CMPY = 8'H8C; // Page2
localparam OPCODE_IMM_LDY = 8'H8E; // Page2
localparam OPCODE_IMM_LDS = 8'HCE; // Page2
localparam OPCODE_IMM_CMPU = 8'H83; // Page3
localparam OPCODE_IMM_CMPS = 8'H8C; // Page3
localparam EXGTFR_REG_D = 4'H0;
localparam EXGTFR_REG_X = 4'H1;
localparam EXGTFR_REG_Y = 4'H2;
localparam EXGTFR_REG_U = 4'H3;
localparam EXGTFR_REG_S = 4'H4;
localparam EXGTFR_REG_PC = 4'H5;
localparam EXGTFR_REG_A = 4'H8;
localparam EXGTFR_REG_B = 4'H9;
localparam EXGTFR_REG_CC = 4'HA;
localparam EXGTFR_REG_DP = 4'HB;
function IsALU8Set0(input [7:0] instr);
reg result;
reg [3:0] hi;
reg [3:0] lo;
begin
hi = instr[7:4];
lo = instr[3:0];
if ( (hi == 4'H0) || (hi == 4'H4) || (hi == 4'H5) || (hi == 4'H6) || (hi == 4'H7) )
begin
if ( (lo != 4'H1) && (lo != 4'H2) && (lo != 4'H5) && (lo != 4'HB) && (lo != 4'HE) ) // permit NEG, COM, LSR, ROR, ASR, ASL/LSL, ROL, DEC, INC, TST, CLR
result = 1;
else
result = 0;
end
else
result = 0;
IsALU8Set0 = result;
end
endfunction
function IsALU8Set1(input [7:0] instr);
reg result;
reg [3:0] hi;
reg [3:0] lo;
begin
hi = instr[7:4];
lo = instr[3:0];
if ( (hi >= 4'H8) )
begin
if ( (lo <= 4'HB) && (lo != 4'H3) && (lo != 4'H7) ) // 8-bit SUB, CMP, SBC, AND, BIT, LD, EOR, ADC, OR, ADD
result = 1;
else
result = 0;
end
else
result = 0;
IsALU8Set1 = result;
end
endfunction
// Determine if the instruction is performing an 8-bit op (ALU only)
function ALU8BitOp(input [7:0] instr);
begin
ALU8BitOp = IsALU8Set0(instr) | IsALU8Set1(instr);
end
endfunction
wire Is8BitInst = ALU8BitOp(Inst1);
function IsRegA(input [7:0] instr);
reg result;
reg [3:0] hi;
begin
hi = instr[7:4];
if ((hi == 4'H4) || (hi == 4'H8) || (hi == 4'H9) || (hi == 4'HA) || (hi == 4'HB) )
result = 1;
else
result = 0;
IsRegA = result;
end
endfunction
wire IsTargetRegA = IsRegA(Inst1);
//
//
// Decode
// 00-0F = DIRECT
// 10-1F = INHERENT, RELATIVE, IMMEDIATE
// 20-2F = RELATIVE
// 30-3F = INDEXED, IMMEDIATE (pus, pul), INHERENT
// 40-4F = INHERENT
// 50-5F = INHERENT
// 60-6F = INDEXED
// 70-7F = EXTENDED
// 80-8F = IMMEDIATE, RELATIVE (BSR)
// 90-9F = DIRECT
// A0-AF = INDEXED
// B0-BF = EXTENDED
// C0-CF = IMMEDIATE
// D0-DF = DIRECT
// E0-EF = INDEXED
// F0-FF = EXTENDED
// DIRECT; 00-0F, 90-9F, D0-DF
// INHERENT; 10-1F (12, 13, 19, 1D), 30-3F (39-3F), 40-4F, 50-5F,
// RELATIVE: 10-1F (16, 17), 20-2F, 80-8F (8D)
// IMMEDIATE: 10-1F (1A, 1C, 1E, 1F), 30-3F (34-37), 80-8F (80-8C, 8E), C0-CF
// INDEXED: 60-6F, A0-AF, E0-EF
// EXTENDED: 70-7F, B0-Bf, F0-FF
localparam INST_LBRA = 8'H16; // always -- shitty numbering, damnit
localparam INST_LBSR = 8'H17; //
localparam INST_BRA = 8'H20; // always
localparam INST_BRN = 8'H21; // never
localparam INST_BHI = 8'H22; // CC.Z = 0 && CC.C = 0
localparam INST_BLS = 8'H23; // CC.Z != 0 && CC.C != 0
localparam INST_BCC = 8'H24; // CC.C = 0
localparam INST_BHS = 8'H24; // same as BCC
localparam INST_BCS = 8'H25; // CC.C = 1
localparam INST_BLO = 8'H25; // same as BCS
localparam INST_BNE = 8'H26; // CC.Z = 0
localparam INST_BEQ = 8'H27; // CC.Z = 1
localparam INST_BVC = 8'H28; // V = 1
localparam INST_BVS = 8'H29; // V = 0
localparam INST_BPL = 8'H2A; // CC.N = 0
localparam INST_BMI = 8'H2B; // CC.N = 1
localparam INST_BGE = 8'H2C; // CC.N = CC.V
localparam INST_BLT = 8'H2D; // CC.N != CC.V
localparam INST_BGT = 8'H2E; // CC.N = CC.V && CC.Z = 0
localparam INST_BLE = 8'H2F; // CC.N != CC.V && CC.Z = 1
localparam INST_BSR = 8'H8D; // always
localparam NYB_BRA = 4'H0; // always
localparam NYB_BRN = 4'H1; // never
localparam NYB_BHI = 4'H2; // CC.Z = 0 && CC.C = 0
localparam NYB_BLS = 4'H3; // CC.Z != 0 && CC.C != 0
localparam NYB_BCC = 4'H4; // CC.C = 0
localparam NYB_BHS = 4'H4; // same as BCC
localparam NYB_BCS = 4'H5; // CC.C = 1
localparam NYB_BLO = 4'H5; // same as BCS
localparam NYB_BNE = 4'H6; // CC.Z = 0
localparam NYB_BEQ = 4'H7; // CC.Z = 1
localparam NYB_BVC = 4'H8; // V = 0
localparam NYB_BVS = 4'H9; // V = 1
localparam NYB_BPL = 4'HA; // CC.N = 0
localparam NYB_BMI = 4'HB; // CC.N = 1
localparam NYB_BGE = 4'HC; // CC.N = CC.V
localparam NYB_BLT = 4'HD; // CC.N != CC.V
localparam NYB_BGT = 4'HE; // CC.N = CC.V && CC.Z = 0
localparam NYB_BLE = 4'HF; // CC.N != CC.V && CC.Z = 1
function take_branch(input [7:0] Inst1, input [7:0] cc);
begin
take_branch = 0; //default
if ( (Inst1 == INST_BSR) || (Inst1 == INST_LBSR) || (Inst1 == INST_LBRA) )
take_branch = 1;
else
case (Inst1[3:0])
NYB_BRA:
take_branch = 1;
NYB_BRN:
take_branch = 0;
NYB_BHI:
if ( ( cc[CC_Z_BIT] | cc[CC_C_BIT] ) == 0)
take_branch = 1;
NYB_BLS:
if ( cc[CC_Z_BIT] | cc[CC_C_BIT] )
take_branch = 1;
NYB_BCC:
if ( cc[CC_C_BIT] == 0 )
take_branch = 1;
NYB_BCS:
if ( cc[CC_C_BIT] == 1 )
take_branch = 1;
NYB_BNE:
if ( cc[CC_Z_BIT] == 0 )
take_branch = 1;
NYB_BEQ:
if ( cc[CC_Z_BIT] == 1 )
take_branch = 1;
NYB_BVC:
if ( cc[CC_V_BIT] == 0)
take_branch = 1;
NYB_BVS:
if ( cc[CC_V_BIT] == 1)
take_branch = 1;
NYB_BPL:
if ( cc[CC_N_BIT] == 0 )
take_branch = 1;
NYB_BMI:
if (cc[CC_N_BIT] == 1)
take_branch = 1;
NYB_BGE:
if ((cc[CC_N_BIT] ^ cc[CC_V_BIT]) == 0)
take_branch = 1;
NYB_BLT:
if ((cc[CC_N_BIT] ^ cc[CC_V_BIT]) == 1)
take_branch = 1;
NYB_BGT:
if ( ((cc[CC_N_BIT] ^ cc[CC_V_BIT]) == 0) & (cc[CC_Z_BIT] == 0) )
take_branch = 1;
NYB_BLE:
if ( ((cc[CC_N_BIT] ^ cc[CC_V_BIT]) == 1) | (cc[CC_Z_BIT] == 1) )
take_branch = 1;
endcase
end
endfunction
wire TakeBranch = take_branch(Inst1, cc);
/////////////////////////////////////////////////////////////////////
// Convenience function for knowing the contents for TFR, EXG
function [15:0] EXGTFRRegister(input [3:0] regid);
begin
case (regid)
EXGTFR_REG_D:
EXGTFRRegister = {a, b};
EXGTFR_REG_X:
EXGTFRRegister = x;
EXGTFR_REG_Y:
EXGTFRRegister = y;
EXGTFR_REG_U:
EXGTFRRegister = u;
EXGTFR_REG_S:
EXGTFRRegister = s;
EXGTFR_REG_PC:
EXGTFRRegister = pc_p1; // For both EXG and TFR, this is used on the 2nd byte in the instruction's cycle. The PC intended to transfer is actually the next byte.
EXGTFR_REG_DP:
EXGTFRRegister = {8'HFF, dp};
EXGTFR_REG_A:
EXGTFRRegister = {8'HFF, a};
EXGTFR_REG_B:
EXGTFRRegister = {8'HFF, b};
EXGTFR_REG_CC:
EXGTFRRegister = {8'HFF, cc};
default:
EXGTFRRegister = 16'H0;
endcase
end
endfunction
wire [15:0] EXGTFRRegA = EXGTFRRegister(D[7:4]);
wire [15:0] EXGTFRRegB = EXGTFRRegister(D[3:0]);
// CPU state machine
always @(*)
begin
rLIC = 1'b0;
rAVMA = 1'b1;
rBUSY = 1'b0;
addr_nxt = 16'HFFFF;
pc_p1 = (pc+16'H1);
pc_p2 = (pc+16'H2);
pc_p3 = (pc+16'H3);
s_p1 = (s+16'H1);
s_m1 = (s-16'H1);
u_p1 = (u+16'H1);
u_m1 = (u-16'H1);
addr_p1 = (addr+16'H1);
ea_p1 = (ea+16'H1);
BS_nxt = 1'b0;
BA_nxt = 1'b0;
// These may be overridden below, but the "next" version by default should be
// the last latched version.
IntType_nxt = IntType;
NMIClear_nxt = NMIClear;
NextState_nxt = NextState;
a_nxt = a;
b_nxt = b;
x_nxt = x;
y_nxt = y;
s_nxt = s;
u_nxt = u;
cc_nxt = cc;
dp_nxt = dp;
pc_nxt = pc;
tmp_nxt = tmp;
ea_nxt = ea;
ALU_A = 8'H00;
ALU_B = 8'H00;
ALU_CC = 8'H00;
ALU_OP = 5'H00;
ALU16_OP = 3'H0;
ALU16_A = 16'H0000;
ALU16_B = 16'H0000;
ALU16_CC = 8'H00;
DOutput = 8'H00;
RnWOut = 1'b1; // read
Inst1_nxt = Inst1;
Inst2_nxt = Inst2;
Inst3_nxt = Inst3;
InstPage2_nxt = InstPage2;
InstPage3_nxt = InstPage3;
CpuState_nxt = CpuState;
case (CpuState)
CPUSTATE_RESET:
begin
addr_nxt = 16'HFFFF;
a_nxt = 0;
b_nxt = 0;
x_nxt = 0;
y_nxt = 0;
s_nxt = 16'HFFFD; // Take care about removing the reset of S. There's logic depending on the delta between s and s_nxt to clear NMIMask.
u_nxt = 0;
cc_nxt = CC_F | CC_I; // reset disables interrupts
dp_nxt = 0;
ea_nxt = 16'HFFFF;
RnWOut = 1; // read
rLIC = 1'b0; // Instruction incomplete
NMIClear_nxt= 1'b0;
IntType_nxt = 3'b111;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_RESET0;
end
CPUSTATE_RESET0:
begin
addr_nxt = `RESET_VECTOR;
rBUSY = 1'b1;
pc_nxt[15:8] = D[7:0];
BS_nxt = 1'b1; // ACK RESET
rAVMA = 1'b1;
rLIC = 1'b1;
CpuState_nxt = CPUSTATE_RESET2;
end
CPUSTATE_RESET2:
begin
addr_nxt = addr_p1;
BS_nxt = 1'b1; // ACK RESET
pc_nxt[7:0] = D[7:0];
rAVMA = 1'b1;
rLIC = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
CPUSTATE_FETCH_I1:
begin
if (~DMABREQLatched)
begin
addr_nxt = pc;
RnWOut = 1'b1;
rAVMA = 1'b0;
tmp_nxt = {tmp[15:4], 4'b1111};
BS_nxt = 1'b1;
BA_nxt = 1'b1;
rLIC = 1'b1;
CpuState_nxt = CPUSTATE_DMABREQ;
end
else if (~HALTLatched)
begin
addr_nxt = pc;
RnWOut = 1'b1;
rAVMA = 1'b0;
BS_nxt = 1'b1;
BA_nxt = 1'b1;
rLIC = 1'b1;
CpuState_nxt = CPUSTATE_HALTED;
end
else // not halting, run the inst byte fetch
begin
addr_nxt = pc; // Set the address bus for the next instruction, first byte
pc_nxt = pc_p1;
RnWOut = 1; // Set for a READ
Inst1_nxt = MappedInstruction;
InstPage2_nxt = 0;
InstPage3_nxt = 0;
// New instruction fetch; service interrupts pending
if (NMILatched == 0)
begin
pc_nxt = pc;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_NMI_START;
end
else if ((FIRQLatched == 0) && (cc[CC_F_BIT] == 0))
begin
pc_nxt = pc;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FIRQ_START;
end
else if ((IRQLatched == 0) && (cc[CC_I_BIT] == 0))
begin
pc_nxt = pc;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_IRQ_START;
end
// The actual 1st byte checks
else if (Inst1_nxt == 8'H10) // Page 2 Note, like the 6809, $10 $10 $10 $10 has the same effect as a single $10.
begin
InstPage2_nxt = 1;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1V2;
end
else if (Inst1_nxt == 8'H11) // Page 3
begin
InstPage3_nxt = 1;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1V2;
end
else
begin
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I2;
end
end // if not halting
end
CPUSTATE_FETCH_I1V2:
begin
addr_nxt = pc; // Set the address bus for the next instruction, first byte
pc_nxt = pc_p1;
RnWOut = 1; // Set for a READ
Inst1_nxt = MappedInstruction;
if (Inst1_nxt == 8'H10) // Page 2 Note, like the 6809, $10 $10 $10 $10 has the same effect as a single $10.
begin
if (InstPage3 == 0) // $11 $11 $11 $11 ... $11 $10 still = Page 3
InstPage2_nxt = 1;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1V2;
end
else if (Inst1_nxt == 8'H11) // Page 3
begin
if (InstPage2 == 0) // $10 $10 ... $10 $11 still = Page 2
InstPage3_nxt = 1;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1V2;
end
else
begin
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I2;
end
end
CPUSTATE_FETCH_I2: // We've fetched the first byte. If a $10 or $11 (page select), mark those flags and fetch the next byte as instruction byte 1.
begin
addr_nxt = addr_p1; // Address bus++
pc_nxt = pc_p1;
Inst2_nxt = D[7:0];
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
if (IsIllegalInstruction) // Skip illegal instructions
begin
rAVMA = 1'b1;
CpuState_nxt = IllegalInstructionState;
rLIC = 1'b1;
end
else
begin
// First byte Decode for this stage
case (AddrModeType)
TYPE_INDEXED:
begin
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_INDEXED_BASE;
end
TYPE_EXTENDED:
begin
ea_nxt[15:8] = Inst2_nxt;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_EXTENDED_ADDRLO;
end
TYPE_DIRECT:
begin
ea_nxt = {dp, Inst2_nxt};
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_DIRECT_DONTCARE;
end
TYPE_INHERENT:
begin
if (Inst1 == OPCODE_INH_NOP)
begin
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
else if (Inst1 == OPCODE_INH_DAA) // Bcd lunacy
begin
if ( ((cc[CC_C_BIT]) || (a[7:4] > 4'H9)) ||
((a[7:4] > 4'H8) && (a[3:0] > 4'H9)) )
tmp_nxt[7:4] = 4'H6;
else
tmp_nxt[7:4] = 4'H0;
if ((cc[CC_H_BIT]) || (a[3:0] > 4'H9))
tmp_nxt[3:0] = 4'H6;
else
tmp_nxt[3:0] = 4'H0;
// DAA handles carry in the weirdest way.
// If it's already set, it remains set, even if carry-out is 0.
// If it wasn't set, but the output of the operation is set, carry-out gets set.
{tmp_nxt[8], a_nxt} = {1'b0, a} + tmp_nxt[7:0];
cc_nxt[CC_C_BIT] = cc_nxt[CC_C_BIT] | tmp_nxt[8];
cc_nxt[CC_N_BIT] = a_nxt[7];
cc_nxt[CC_Z_BIT] = (a_nxt == 8'H00);
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
else if (Inst1 == OPCODE_INH_SYNC)
begin
CpuState_nxt = CPUSTATE_SYNC;
rLIC = 1'b1;
rAVMA = 1'b0;
end
else if (Inst1 == OPCODE_INH_MUL)
begin
tmp_nxt = 16'H0000;
ea_nxt[15:8] = 8'H00;
ea_nxt[7:0] = a;
a_nxt = 8;
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_MUL_ACTION;
end
else if (Inst1 == OPCODE_INH_RTS)
begin
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_RTS_HI;
end
else if (Inst1 == OPCODE_INH_RTI)
begin
rAVMA = 1'b1;
tmp_nxt = 16'H1001; // Set tmp[12] to indicate an RTI being processed, and at least pull CC.
CpuState_nxt = CPUSTATE_PUL_ACTION;
NextState_nxt = CPUSTATE_FETCH_I1;
end
else if (Inst1 == OPCODE_INH_SWI)
begin
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_SWI_START;
end
else if (Inst1 == OPCODE_INH_CWAI)
begin
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_CWAI;
end
else if (Inst1 == OPCODE_INH_SEX)
begin
a_nxt = {8{b[7]}};
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
else if (Inst1 == OPCODE_INH_ABX)
begin
x_nxt = x + b;
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_ABX_DONTCARE;
end
else
begin
ALU_OP = ALU8Op;
if (IsTargetRegA)
ALU_A = a;
else
ALU_A = b;
ALU_B = 0;
ALU_CC = cc;
cc_nxt = ALU[15:8];
if (ALU8Writeback)
begin
if (IsTargetRegA)
a_nxt = ALU[7:0];
else
b_nxt = ALU[7:0];
end
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
if (IsOneByteInstruction(Inst1)) // This check is probably superfluous. Every inherent instruction is 1 byte on the 6809.
pc_nxt = pc; // The 6809 auto-reads 2 bytes for every instruction. :( Adjust by not incrementing PC on the 2nd byte read.
end
TYPE_IMMEDIATE:
begin
if (IsSpecialImmediate)
begin
if (Inst1 == OPCODE_IMM_ANDCC)
begin
pc_nxt = pc_p1;
cc_nxt = cc & D; //cc_nxt & Inst2_nxt;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_CC_DONTCARE;
end
else if (Inst1 == OPCODE_IMM_ORCC)
begin
pc_nxt = pc_p1;
cc_nxt = cc | D; //cc_nxt | Inst2_nxt;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_CC_DONTCARE;
end
else if ( (Inst1 == OPCODE_IMM_PSHS) | (Inst1 == OPCODE_IMM_PSHU) )
begin
pc_nxt = pc_p1;
tmp_nxt[15] = 1'b0;
tmp_nxt[14] = Inst1[1]; // Mark whether to save to U or S.
tmp_nxt[13] = 1'b0; // Not pushing due to an interrupt.
tmp_nxt[13:8] = 6'H00;
tmp_nxt[7:0] = Inst2_nxt;
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_PSH_DONTCARE1;
NextState_nxt = CPUSTATE_FETCH_I1;
end
else if ( (Inst1 == OPCODE_IMM_PULS) | (Inst1 == OPCODE_IMM_PULU) )
begin
pc_nxt = pc_p1;
tmp_nxt[15] = 1'b0;
tmp_nxt[14] = Inst1[1]; // S (0) or U (1) stack in use.
tmp_nxt[13:8] = 6'H00;
tmp_nxt[7:0] = Inst2_nxt;
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_PUL_DONTCARE1;
NextState_nxt = CPUSTATE_FETCH_I1;
end
else if (Inst1 == OPCODE_IMM_TFR)
begin
// The second byte lists the registers; Top nybble is reg #1, bottom is reg #2.
case (Inst2_nxt[3:0])
EXGTFR_REG_D:
{a_nxt,b_nxt} = EXGTFRRegA;
EXGTFR_REG_X:
x_nxt = EXGTFRRegA;
EXGTFR_REG_Y:
y_nxt = EXGTFRRegA;
EXGTFR_REG_U:
u_nxt = EXGTFRRegA;
EXGTFR_REG_S:
s_nxt = EXGTFRRegA;
EXGTFR_REG_PC:
pc_nxt = EXGTFRRegA;
EXGTFR_REG_DP:
dp_nxt = EXGTFRRegA[7:0];
EXGTFR_REG_A:
a_nxt = EXGTFRRegA[7:0];
EXGTFR_REG_B:
b_nxt = EXGTFRRegA[7:0];
EXGTFR_REG_CC:
cc_nxt = EXGTFRRegA[7:0];
default:
begin
end
endcase
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_TFR_DONTCARE1;
end
else if (Inst1 == OPCODE_IMM_EXG)
begin
// The second byte lists the registers; Top nybble is reg #1, bottom is reg #2.
case (Inst2_nxt[7:4])
EXGTFR_REG_D:
{a_nxt,b_nxt} = EXGTFRRegB;
EXGTFR_REG_X:
x_nxt = EXGTFRRegB;
EXGTFR_REG_Y:
y_nxt = EXGTFRRegB;
EXGTFR_REG_U:
u_nxt = EXGTFRRegB;
EXGTFR_REG_S:
s_nxt = EXGTFRRegB;
EXGTFR_REG_PC:
pc_nxt = EXGTFRRegB;
EXGTFR_REG_DP:
dp_nxt = EXGTFRRegB[7:0];
EXGTFR_REG_A:
a_nxt = EXGTFRRegB[7:0];
EXGTFR_REG_B:
b_nxt = EXGTFRRegB[7:0];
EXGTFR_REG_CC:
cc_nxt = EXGTFRRegB[7:0];
default:
begin
end
endcase
case (Inst2_nxt[3:0])
EXGTFR_REG_D:
{a_nxt,b_nxt} = EXGTFRRegA;
EXGTFR_REG_X:
x_nxt = EXGTFRRegA;
EXGTFR_REG_Y:
y_nxt = EXGTFRRegA;
EXGTFR_REG_U:
u_nxt = EXGTFRRegA;
EXGTFR_REG_S:
s_nxt = EXGTFRRegA;
EXGTFR_REG_PC:
pc_nxt = EXGTFRRegA;
EXGTFR_REG_DP:
dp_nxt = EXGTFRRegA[7:0];
EXGTFR_REG_A:
a_nxt = EXGTFRRegA[7:0];
EXGTFR_REG_B:
b_nxt = EXGTFRRegA[7:0];
EXGTFR_REG_CC:
cc_nxt = EXGTFRRegA[7:0];
default:
begin
end
endcase
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_EXG_DONTCARE1;
end
end
// Determine if this is an 8-bit ALU operation.
else if (Is8BitInst)
begin
ALU_OP = ALU8Op;
if (IsTargetRegA)
ALU_A = a;
else
ALU_A = b;
ALU_B = Inst2_nxt;
ALU_CC = cc;
cc_nxt = ALU[15:8];
if (ALU8Writeback)
begin
if (IsTargetRegA)
a_nxt = ALU[7:0];
else
b_nxt = ALU[7:0];
end
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
else // Then it must be a 16 bit instruction
begin
// 83 SUBD
// 8C CMPX
// 8E LDX
// C3 ADDD
// CC LDD
// CE LDU
// 108E CMPD
// 108C CMPY
// 108E LDY
// 10CE LDS
// 1183 CMPU
// 118C CMPS
// Wow, they were just stuffing them in willy-nilly ...
// LD* 16 bit immediate
if (IsALU16Opcode)
begin
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_16IMM_LO;
end
// there's a dead zone here; I need an else to take us back to CPUSTATE_FETCHI1 if we want to ignore illegal instructions, to CPUSTATE_DEAD if we want to catch them.
end
end
TYPE_RELATIVE:
begin
// Is this a LB** or a B**?
// If InstPage2 is set, it's a long branch; if clear, a normal branch.
if ( (InstPage2) || (Inst1 == INST_LBRA) || (Inst1 == INST_LBSR) )
begin
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_LBRA_OFFSETLOW;
end
else
begin
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_BRA_DONTCARE;
end
end
default:
begin
CpuState_nxt = CPUSTATE_FETCH_I1;
end
endcase
end
end
CPUSTATE_LBRA_OFFSETLOW:
begin
addr_nxt = pc;
pc_nxt = pc_p1;
Inst3_nxt = D[7:0];
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_LBRA_DONTCARE;
end
CPUSTATE_LBRA_DONTCARE:
begin
addr_nxt = 16'HFFFF;
if ( TakeBranch )
begin
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_LBRA_DONTCARE2;
end
else
begin
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
end
CPUSTATE_BRA_DONTCARE:
begin
addr_nxt = 16'HFFFF;
tmp_nxt = pc;
if (TakeBranch)
begin
pc_nxt = pc + { {8{Inst2[7]}}, Inst2[7:0]}; // Sign-extend the 8 bit offset to 16.
if (Inst1 == INST_BSR)
begin
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_BSR_DONTCARE1;
end
else
begin
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
end
else
begin
rLIC = 1'b1;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
end
CPUSTATE_LBRA_DONTCARE2:
begin
tmp_nxt= pc;
addr_nxt = 16'HFFFF;
// Take branch
pc_nxt = pc + {Inst2[7:0], Inst3[7:0]};
if (Inst1 == INST_LBSR)
begin
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_BSR_DONTCARE1;
end
else
begin
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
end
CPUSTATE_BSR_DONTCARE1:
begin
addr_nxt = pc;
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_BSR_DONTCARE2;
end
CPUSTATE_BSR_DONTCARE2:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_BSR_RETURNLOW;
end
CPUSTATE_BSR_RETURNLOW:
begin
addr_nxt = s_m1;
s_nxt = s_m1;
DOutput[7:0] = tmp[7:0];
RnWOut = 0;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_BSR_RETURNHIGH;
end
CPUSTATE_BSR_RETURNHIGH:
begin
addr_nxt = s_m1;
s_nxt = s_m1;
DOutput[7:0] = tmp[15:8];
RnWOut = 0;
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1; // after this, RnWOut must go to 1, and the bus needs the PC placed on it.
end
CPUSTATE_TFR_DONTCARE1:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_TFR_DONTCARE2;
end
CPUSTATE_TFR_DONTCARE2:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_TFR_DONTCARE3;
end
CPUSTATE_TFR_DONTCARE3:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_TFR_DONTCARE4;
end
CPUSTATE_TFR_DONTCARE4:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b1;
rLIC = 1'b1; // Instruction done!
CpuState_nxt = CPUSTATE_FETCH_I1;
end
CPUSTATE_EXG_DONTCARE1:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_EXG_DONTCARE2;
end
CPUSTATE_EXG_DONTCARE2:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_EXG_DONTCARE3;
end
CPUSTATE_EXG_DONTCARE3:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_EXG_DONTCARE4;
end
CPUSTATE_EXG_DONTCARE4:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_EXG_DONTCARE5;
end
CPUSTATE_EXG_DONTCARE5:
begin
rAVMA = 1'b0;
addr_nxt = 16'HFFFF;
CpuState_nxt = CPUSTATE_EXG_DONTCARE6;
end
CPUSTATE_EXG_DONTCARE6:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b1;
rLIC = 1'b1; // Instruction done!
CpuState_nxt = CPUSTATE_FETCH_I1;
end
CPUSTATE_ABX_DONTCARE:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b1;
rLIC = 1'b1; // Instruction done!
CpuState_nxt = CPUSTATE_FETCH_I1;
end
CPUSTATE_RTS_HI:
begin
addr_nxt = s;
s_nxt = s_p1;
pc_nxt[15:8] = D[7:0];
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_RTS_LO;
end
CPUSTATE_RTS_LO:
begin
addr_nxt = s;
s_nxt = s_p1;
pc_nxt[7:0] = D[7:0];
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_RTS_DONTCARE2;
end
CPUSTATE_RTS_DONTCARE2:
begin
addr_nxt = 16'HFFFF;
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
CPUSTATE_16IMM_LO:
begin
addr_nxt = pc;
pc_nxt = pc_p1;
ALU16_OP = ALU16Opcode;
ALU16_CC = cc;
ALU16_B = {Inst2, D[7:0]};
case (ALU16Reg)
ALU16_REG_X:
ALU16_A = x;
ALU16_REG_D:
ALU16_A = {a, b};
ALU16_REG_Y:
ALU16_A = y;
ALU16_REG_U:
ALU16_A = u;
ALU16_REG_S:
ALU16_A = s;
default:
ALU16_A = 16'H0;
endcase
if (ALU16OpWriteback)
begin
case (ALU16Reg)
ALU16_REG_X:
{cc_nxt, x_nxt} = ALU16;
ALU16_REG_D:
{cc_nxt, a_nxt, b_nxt} = ALU16;
ALU16_REG_Y:
{cc_nxt, y_nxt} = ALU16;
ALU16_REG_U:
{cc_nxt, u_nxt} = ALU16;
ALU16_REG_S:
{cc_nxt, s_nxt} = ALU16;
default:
begin
end
endcase
end
else
cc_nxt = ALU16[23:16];
if (ALU16_OP == ALUOP16_LD)
begin
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
else
begin
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_16IMM_DONTCARE;
end
end
CPUSTATE_DIRECT_DONTCARE:
begin
addr_nxt = 16'HFFFF;
if (IsJMP(Inst1))
begin
pc_nxt = ea;
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
else
begin
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_ALU_EA;
end
end
CPUSTATE_ALU_EA:
begin
// Is Figure 18/5 Column 2? JMP (not Immediate Mode)
// This actually isn't done here. All checks passing in to ALU_EA should check for a JMP; FIXME EVERYWHERE
// Is Figure 18/5 Column 8? TST (not immediate mode)
// THIS IS BURIED IN THE COLUMN 3 section with comparisons to ALUOP_TST.
// Is Figure 18/5 Column 3?
if (IsALU8Set1(Inst1))
begin
addr_nxt = ea;
ALU_OP = ALU8Op;
ALU_B = D[7:0];
ALU_CC = cc;
if (IsTargetRegA)
ALU_A = a;
else
ALU_A = b;
cc_nxt = ALU[15:8];
if ( (ALU8Writeback) )
begin
if (IsTargetRegA)
a_nxt = ALU[7:0];
else
b_nxt = ALU[7:0];
end
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
// Is Figure 18/5 Column 4? (Store, 8 bits)
else if (IsStore8)
begin
addr_nxt = ea;
RnWOut = 0; // write
ALU_OP = ALUOP_LD; // load has the same CC characteristics as store
ALU_A = 8'H00;
ALU_CC = cc;
case (Store8RegisterNum)
ST8_REG_A:
begin
DOutput = a;
ALU_B = a;
end
ST8_REG_B:
begin
DOutput = b;
ALU_B = b;
end
endcase
cc_nxt = ALU[15:8];
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
// Is Figure 18/5 Column 5? (Load, 16 bits)
else if (IsALU16Opcode & (ALU16Opcode == ALUOP16_LD))
begin
addr_nxt = ea;
ea_nxt = ea_p1;
case (ALU16Reg)
ALU16_REG_X:
x_nxt[15:8] = D[7:0];
ALU16_REG_D:
a_nxt = D[7:0];
ALU16_REG_Y:
y_nxt[15:8] = D[7:0];
ALU16_REG_S:
s_nxt[15:8] = D[7:0];
ALU16_REG_U:
u_nxt[15:8] = D[7:0];
default:
begin
end
endcase
rAVMA = 1'b1;
rBUSY = 1'b1;
CpuState_nxt = CPUSTATE_LD16_LO;
end
// Is Figure 18/5 Column 6? (Store, 16 bits)
else if (IsStore16)
begin
addr_nxt = ea;
ea_nxt = ea_p1;
ALU16_OP = ALUOP16_LD; // LD and ST have the same CC characteristics
ALU16_CC = cc;
ALU16_A = 8'H00;
case (StoreRegisterNum)
ST16_REG_X:
begin
DOutput[7:0] = x[15:8];
ALU16_B = x;
end
ST16_REG_Y:
begin
DOutput[7:0] = y[15:8];
ALU16_B = y;
end
ST16_REG_U:
begin
DOutput[7:0] = u[15:8];
ALU16_B = u;
end
ST16_REG_S:
begin
DOutput[7:0] = s[15:8];
ALU16_B = s;
end
ST16_REG_D:
begin
DOutput[7:0] = a[7:0];
ALU16_B = {a,b};
end
default:
begin
end
endcase
cc_nxt = ALU16[23:16];
RnWOut = 0; // Write
rAVMA = 1'b1;
rBUSY = 1'b1;
CpuState_nxt = CPUSTATE_ST16_LO;
end
// Is Figure 18/5 Column 7?
else if (IsALU8Set0(Inst1))
begin
// These are registerless instructions, ala
// ASL, ASR, CLR, COM, DEC, INC, (LSL), LSR, NEG, ROL, ROR
// and TST (special!)
// They require READ, Modify (the operation above), WRITE. Between the Read and the Write cycles, there's actually a /VMA
// cycle where the 6809 likely did the operation. We'll include a /VMA cycle for accuracy, but we'll do the work primarily in the first cycle.
addr_nxt = ea;
ALU_OP = ALU8Op;
ALU_A = D[7:0];
ALU_CC = cc;
tmp_nxt[15:8] = cc; // for debug only
tmp_nxt[7:0] = ALU[7:0];
cc_nxt = ALU[15:8];
if (ALU8Op == ALUOP_TST)
begin
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_TST_DONTCARE1;
end
else
begin
rAVMA = 1'b0;
rBUSY = 1'b1;
CpuState_nxt = CPUSTATE_ALU_DONTCARE;
end
end
// Is Figure 18/5 Column 8? TST
// NOTE:
// THIS IS BURIED IN THE COLUMN 3 section with comparisons to ALUOP_TST. [Directly above.]
// Is Figure 18/5 Column 9? (16-bit ALU ops, non-load)
else if (IsALU16Opcode && (ALU16Opcode != ALUOP16_LD) && ((Inst1 < 8'H30) || (Inst1 > 8'H33)) ) // 30-33 = LEAX, LEAY, LEAS, LEAU; don't include them here.
begin
addr_nxt = ea;
ea_nxt = ea_p1;
tmp_nxt[15:8] = D[7:0];
rAVMA = 1'b1;
rBUSY = 1'b1;
CpuState_nxt = CPUSTATE_ALU16_LO;
end
// Is Figure 18/5 Column 10? JSR (not Immediate Mode)
else if ((Inst1 == 8'H9D) || (Inst1 == 8'HAD) || (Inst1 == 8'HBD)) // JSR
begin
pc_nxt = ea;
addr_nxt = ea;
tmp_nxt = pc;
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_JSR_DONTCARE;
end
// Is Figure 18/5 Column 11? LEA(X,Y,S,U)
else if ((Inst1 >= 8'H30) && (Inst1<= 8'H33))
begin
addr_nxt = 16'HFFFF; // Ack, actually a valid cycle, this isn't a dontcare (/VMA) cycle!
ALU16_OP = ALU16Opcode;
ALU16_CC = cc;
ALU16_A = ea;
case (ALU16Reg)
ALU16_REG_X:
{cc_nxt, x_nxt} = ALU16;
ALU16_REG_Y:
{cc_nxt, y_nxt} = ALU16;
ALU16_REG_U:
u_nxt = ALU16[15:0];
ALU16_REG_S:
s_nxt = ALU16[15:0];
default:
begin
end
endcase
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
end
CPUSTATE_ALU_DONTCARE:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b1;
rBUSY = 1'b1; // We do nothing here, but on the real 6809, they did the modify phase here. :|
CpuState_nxt = CPUSTATE_ALU_WRITEBACK;
end
CPUSTATE_ALU_WRITEBACK:
begin
addr_nxt = ea;
RnWOut = 0; // Write
DOutput = tmp[7:0];
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
CPUSTATE_LD16_LO:
begin
addr_nxt = ea;
case (ALU16Reg)
ALU16_REG_X:
begin
x_nxt[7:0] = D[7:0];
ALU16_B[15:8] = x[15:8];
end
ALU16_REG_D:
begin
b_nxt = D[7:0];
ALU16_B[15:8] = a;
end
ALU16_REG_Y:
begin
y_nxt[7:0] = D[7:0];
ALU16_B[15:8] = y[15:8];
end
ALU16_REG_S:
begin
s_nxt[7:0] = D[7:0];
ALU16_B[15:8] = s[15:8];
end
ALU16_REG_U:
begin
u_nxt[7:0] = D[7:0];
ALU16_B[15:8] = u[15:8];
end
default:
begin
end
endcase
ALU16_OP = ALU16Opcode;
ALU16_CC = cc;
ALU16_A = 8'H00;
ALU16_B[7:0] = D[7:0];
cc_nxt = ALU16[23:16];
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
CPUSTATE_ST16_LO:
begin
addr_nxt = ea;
ea_nxt = ea_p1;
case (StoreRegisterNum)
ST16_REG_X:
DOutput[7:0] = x[7:0];
ST16_REG_Y:
DOutput[7:0] = y[7:0];
ST16_REG_U:
DOutput[7:0] = u[7:0];
ST16_REG_S:
DOutput[7:0] = s[7:0];
ST16_REG_D:
DOutput[7:0] = b[7:0];
default:
begin
end
endcase
RnWOut = 0; // write
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
CPUSTATE_ALU16_LO:
begin
addr_nxt = ea;
ALU16_OP = ALU16Opcode;
ALU16_CC = cc;
ALU16_B = {tmp[15:8], D[7:0]};
case (ALU16Reg)
ALU16_REG_X:
ALU16_A = x;
ALU16_REG_D:
ALU16_A = {a, b};
ALU16_REG_Y:
ALU16_A = y;
ALU16_REG_S:
ALU16_A = s;
ALU16_REG_U:
ALU16_A = u;
default:
ALU16_A = 16'H0;
endcase
if (ALU16OpWriteback)
begin
case (ALU16Reg)
ALU16_REG_X:
{cc_nxt, x_nxt} = ALU16;
ALU16_REG_D:
{cc_nxt, a_nxt, b_nxt} = ALU16;
ALU16_REG_Y:
{cc_nxt, y_nxt} = ALU16;
ALU16_REG_U:
{cc_nxt, u_nxt} = ALU16;
ALU16_REG_S:
{cc_nxt, s_nxt} = ALU16;
default:
begin
end
endcase
end
else
cc_nxt = ALU16[23:16];
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_ALU16_DONTCARE;
end
CPUSTATE_ALU16_DONTCARE:
begin
addr_nxt = 16'HFFFF;
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
CPUSTATE_JSR_DONTCARE:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_JSR_RETLO;
end
CPUSTATE_JSR_RETLO:
begin
addr_nxt = s_m1;
s_nxt = s_m1;
RnWOut = 0;
DOutput = tmp[7:0];
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_JSR_RETHI;
end
CPUSTATE_JSR_RETHI:
begin
addr_nxt = s_m1;
s_nxt = s_m1;
RnWOut = 0;
DOutput = tmp[15:8];
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
CPUSTATE_EXTENDED_ADDRLO:
begin
addr_nxt = pc;
pc_nxt = pc_p1;
ea_nxt[7:0] = D[7:0];
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_EXTENDED_DONTCARE;
end
CPUSTATE_EXTENDED_DONTCARE:
begin
addr_nxt = 16'HFFFF;
if (IsJMP(Inst1))
begin
pc_nxt = ea;
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
else
begin
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_ALU_EA;
end
end
CPUSTATE_INDEXED_BASE:
begin
addr_nxt = pc;
Inst3_nxt = D[7:0];
case (IndexedRegister)
IDX_REG_X:
ALU16_A = x;
IDX_REG_Y:
ALU16_A = y;
IDX_REG_U:
ALU16_A = u;
IDX_REG_S:
ALU16_A = s;
IDX_REG_PC:
ALU16_A = pc_p1;
default:
ALU16_A = 16'H0;
endcase
ALU16_OP = ALUOP16_ADD;
case (IndexedMode)
IDX_MODE_NOOFFSET:
begin
case (IndexedRegister)
IDX_REG_X:
ea_nxt = x;
IDX_REG_Y:
ea_nxt = y;
IDX_REG_U:
ea_nxt = u;
IDX_REG_S:
ea_nxt = s;
default:
ea_nxt = 16'H0;
endcase
if (IndexedIndirect)
begin
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_INDIRECT_HI;
end
else
begin
if (IsJMP(Inst1))
begin
pc_nxt = ea_nxt;
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
else
begin
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_ALU_EA;
end
end
end
IDX_MODE_5BIT_OFFSET:
begin
// The offset is the bottom 5 bits of the Index Postbyte, which is Inst2 here.
// We'll sign-extend it to 16 bits.
ALU16_B = { {11{Inst2[4]}}, Inst2[4:0] };
ea_nxt = ALU16[15:0];
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_IDX_DONTCARE3;
end
IDX_MODE_8BIT_OFFSET_PC:
begin
ALU16_B = { {8{D[7]}}, D[7:0] };
pc_nxt = pc_p1;
ea_nxt = ALU16[15:0];
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_IDX_DONTCARE3;
end
IDX_MODE_8BIT_OFFSET:
begin
ALU16_B = { {8{D[7]}}, D[7:0] };
pc_nxt = pc_p1;
ea_nxt = ALU16[15:0];
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_IDX_DONTCARE3;
end
IDX_MODE_A_OFFSET:
begin
ALU16_B = { {8{a[7]}}, a[7:0] };
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_IDX_DONTCARE3;
ea_nxt = ALU16[15:0];
end
IDX_MODE_B_OFFSET:
begin
ALU16_B = { {8{b[7]}}, b[7:0] };
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_IDX_DONTCARE3;
ea_nxt = ALU16[15:0];
end
IDX_MODE_D_OFFSET:
begin
ALU16_B = {a, b};
ea_nxt = ALU16[15:0];
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_IDX_DOFF_DONTCARE1;
end
IDX_MODE_POSTINC1:
begin
ALU16_B = 16'H1;
ea_nxt = ALU16_A;
case (IndexedRegister)
IDX_REG_X:
x_nxt = ALU16[15:0];
IDX_REG_Y:
y_nxt = ALU16[15:0];
IDX_REG_U:
u_nxt = ALU16[15:0];
IDX_REG_S:
s_nxt = ALU16[15:0];
default:
begin
end
endcase
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_IDX_16OFF_DONTCARE2;
end
IDX_MODE_POSTINC2:
begin
ALU16_B = 16'H2;
ea_nxt = ALU16_A;
case (IndexedRegister)
IDX_REG_X:
x_nxt = ALU16[15:0];
IDX_REG_Y:
y_nxt = ALU16[15:0];
IDX_REG_U:
u_nxt = ALU16[15:0];
IDX_REG_S:
s_nxt = ALU16[15:0];
default:
begin
end
endcase
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_IDX_16OFF_DONTCARE0;
end
IDX_MODE_PREDEC1:
begin
ALU16_B = 16'HFFFF; // -1
case (IndexedRegister)
IDX_REG_X:
x_nxt = ALU16[15:0];
IDX_REG_Y:
y_nxt = ALU16[15:0];
IDX_REG_U:
u_nxt = ALU16[15:0];
IDX_REG_S:
s_nxt = ALU16[15:0];
default:
begin
end
endcase
ea_nxt = ALU16[15:0];
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_IDX_16OFF_DONTCARE2;
end
IDX_MODE_PREDEC2:
begin
ALU16_B = 16'HFFFE; // -2
case (IndexedRegister)
IDX_REG_X:
x_nxt = ALU16[15:0];
IDX_REG_Y:
y_nxt = ALU16[15:0];
IDX_REG_U:
u_nxt = ALU16[15:0];
IDX_REG_S:
s_nxt = ALU16[15:0];
default:
begin
end
endcase
ea_nxt = ALU16[15:0];
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_IDX_16OFF_DONTCARE0;
end
IDX_MODE_16BIT_OFFSET_PC:
begin
tmp_nxt[15:8] = D[7:0];
pc_nxt = pc_p1;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_IDX_16OFFSET_LO;
end
IDX_MODE_16BIT_OFFSET:
begin
tmp_nxt[15:8] = D[7:0];
pc_nxt = pc_p1;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_IDX_16OFFSET_LO;
end
IDX_MODE_EXTENDED_INDIRECT:
begin
ea_nxt[15:8] = D[7:0];
pc_nxt = pc_p1;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_IDX_EXTIND_LO;
end
default:
begin
rLIC = 1'b1;
CpuState_nxt = PostIllegalState;
end
endcase
end
CPUSTATE_IDX_OFFSET_LO:
begin
tmp_nxt[7:0] = D[7:0];
addr_nxt = pc;
pc_nxt = pc_p1;
ALU16_B = tmp_nxt;
case (IndexedRegister)
IDX_REG_X:
ALU16_A = x;
IDX_REG_Y:
ALU16_A = y;
IDX_REG_U:
ALU16_A = u;
IDX_REG_S:
ALU16_A = s;
IDX_REG_PC:
ALU16_A = pc;
default:
ALU16_A = 16'H0;
endcase
ALU16_OP = ALUOP16_ADD;
ea_nxt = ALU16[15:0];
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_IDX_16OFF_DONTCARE1;
end
CPUSTATE_IDX_DONTCARE3:
begin
addr_nxt = 16'HFFFF;
if (IndexedIndirect)
begin
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_INDIRECT_HI;
end
else
begin
if (IsJMP(Inst1))
begin
pc_nxt = ea;
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
else
begin
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_ALU_EA;
end
end
end
CPUSTATE_IDX_16OFFSET_LO:
begin
addr_nxt = pc;
pc_nxt = pc_p1;
case (IndexedRegister)
IDX_REG_X:
ALU16_A = x;
IDX_REG_Y:
ALU16_A = y;
IDX_REG_U:
ALU16_A = u;
IDX_REG_S:
ALU16_A = s;
IDX_REG_PC:
ALU16_A = pc_nxt; // Whups; tricky; not part of the actual pattern
default:
ALU16_A = x; // Default to something
endcase
ALU16_OP = ALUOP16_ADD;
ALU16_B = {tmp[15:8], D[7:0]};
ea_nxt = ALU16[15:0];
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_IDX_16OFF_DONTCARE1;
end
CPUSTATE_IDX_16OFF_DONTCARE1:
begin
addr_nxt = pc;
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_IDX_16OFF_DONTCARE2;
end
CPUSTATE_IDX_16OFF_DONTCARE0:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_IDX_16OFF_DONTCARE2;
end
CPUSTATE_IDX_16OFF_DONTCARE2:
begin
addr_nxt = 16'HFFFF;
if (IndexedRegister == IDX_REG_PC)
begin
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_IDX_PC16OFF_DONTCARE;
end
else
begin
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_IDX_16OFF_DONTCARE3;
end
end
CPUSTATE_IDX_PC16OFF_DONTCARE:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_IDX_16OFF_DONTCARE3;
end
CPUSTATE_IDX_16OFF_DONTCARE3:
begin
addr_nxt = 16'HFFFF;
if (IndexedIndirect)
begin
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_INDIRECT_HI;
end
else
begin
if (IsJMP(Inst1))
begin
pc_nxt = ea;
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
else
begin
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_ALU_EA;
end
end
end
CPUSTATE_IDX_DOFF_DONTCARE1:
begin
addr_nxt = pc_p1;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_IDX_DOFF_DONTCARE2;
end
CPUSTATE_IDX_DOFF_DONTCARE2:
begin
addr_nxt = pc_p2;
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_IDX_16OFF_DONTCARE2;
end
CPUSTATE_IDX_DOFF_DONTCARE3:
begin
addr_nxt = pc_p3;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_IDX_DOFF_DONTCARE2;
end
CPUSTATE_IDX_EXTIND_LO:
begin
ea_nxt[7:0] = D[7:0];
addr_nxt = pc;
pc_nxt = pc_p1;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_IDX_EXTIND_DONTCARE;
end
CPUSTATE_IDX_EXTIND_DONTCARE:
begin
addr_nxt = pc;
if (IndexedIndirect)
begin
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_INDIRECT_HI;
end
else
begin
if (IsJMP(Inst1))
begin
pc_nxt = ea;
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
else
begin
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_ALU_EA;
end
end
end
CPUSTATE_INDIRECT_HI:
begin
addr_nxt = ea;
tmp_nxt[15:8] = D[7:0];
rAVMA = 1'b1;
rBUSY = 1'b1;
CpuState_nxt = CPUSTATE_INDIRECT_LO;
end
CPUSTATE_INDIRECT_LO:
begin
addr_nxt = ea_p1;
ea_nxt[15:8] = tmp_nxt[15:8];
ea_nxt[7:0] = D[7:0];
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_INDIRECT_DONTCARE;
end
CPUSTATE_INDIRECT_DONTCARE:
begin
addr_nxt = 16'HFFFF;
if (IsJMP(Inst1))
begin
pc_nxt = ea;
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
else
begin
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_ALU_EA;
end
end
CPUSTATE_MUL_ACTION:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b0;
// tmp = result
// ea = additor (the shifted multiplicand)
// a = counter
// b is the multiplier (which gets shifted right)
if (a != 8'H00)
begin
if (b[0])
begin
tmp_nxt = tmp + ea;
end
ea_nxt = {ea[14:0], 1'b0};
b_nxt = {1'b0, b[7:1]};
a_nxt = a - 8'H1;
end
else
begin
{a_nxt, b_nxt} = tmp;
cc_nxt[CC_Z_BIT] = (tmp == 0);
cc_nxt[CC_C_BIT] = tmp[7];
rLIC = 1'b1; // Instruction done!
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
end
CPUSTATE_PSH_DONTCARE1:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_PSH_DONTCARE2;
end
CPUSTATE_PSH_DONTCARE2:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_PSH_DONTCARE3;
end
CPUSTATE_PSH_DONTCARE3:
begin
addr_nxt = (Inst1[1]) ? u : s;
CpuState_nxt = CPUSTATE_PSH_ACTION;
end
CPUSTATE_PSH_ACTION:
begin
rAVMA = 1'b1;
if (tmp[7] & ~(tmp[15])) // PC_LO
begin
addr_nxt = (tmp[14]) ? u_m1 : s_m1;
if (tmp[14])
u_nxt = u_m1;
else
s_nxt = s_m1;
DOutput = pc[7:0];
RnWOut = 1'b0; // write
tmp_nxt[15] = 1'b1;
end
else if (tmp[7] & (tmp[15])) // PC_HI
begin
addr_nxt = (tmp[14]) ? u_m1 : s_m1;
if (tmp[14])
u_nxt = u_m1;
else
s_nxt = s_m1;
DOutput = pc[15:8];
RnWOut = 1'b0; // write
tmp_nxt[7] = 1'b0;
tmp_nxt[15] = 1'b0;
end
else if (tmp[6] & ~(tmp[15])) // U/S_LO
begin
addr_nxt = (tmp[14]) ? u_m1 : s_m1;
if (tmp[14])
u_nxt = u_m1;
else
s_nxt = s_m1;
DOutput = (tmp[14]) ? s[7:0] : u[7:0];
RnWOut = 1'b0; // write
tmp_nxt[15] = 1'b1;
end
else if (tmp[6] & (tmp[15])) // U/S_HI
begin
addr_nxt = (tmp[14]) ? u_m1 : s_m1;
if (tmp[14])
u_nxt = u_m1;
else
s_nxt = s_m1;
DOutput = (tmp[14]) ? s[15:8] : u[15:8];
RnWOut = 1'b0; // write
tmp_nxt[6] = 1'b0;
tmp_nxt[15] = 1'b0;
end
else if (tmp[5] & ~(tmp[15])) // Y_LO
begin
addr_nxt = (tmp[14]) ? u_m1 : s_m1;
if (tmp[14])
u_nxt = u_m1;
else
s_nxt = s_m1;
DOutput = y[7:0];
RnWOut = 1'b0; // write
tmp_nxt[15] = 1'b1;
end
else if (tmp[5] & (tmp[15])) // Y_HI
begin
addr_nxt = (tmp[14]) ? u_m1 : s_m1;
if (tmp[14])
u_nxt = u_m1;
else
s_nxt = s_m1;
DOutput = y[15:8];
RnWOut = 1'b0; // write
tmp_nxt[5] = 1'b0;
tmp_nxt[15] = 1'b0;
end
else if (tmp[4] & ~(tmp[15])) // X_LO
begin
addr_nxt = (tmp[14]) ? u_m1 : s_m1;
if (tmp[14])
u_nxt = u_m1;
else
s_nxt = s_m1;
DOutput = x[7:0];
RnWOut = 1'b0; // write
tmp_nxt[15] = 1'b1;
end
else if (tmp[4] & (tmp[15])) // X_HI
begin
addr_nxt = (tmp[14]) ? u_m1 : s_m1;
if (tmp[14])
u_nxt = u_m1;
else
s_nxt = s_m1;
DOutput = x[15:8];
RnWOut = 1'b0; // write
tmp_nxt[4] = 1'b0;
tmp_nxt[15] = 1'b0;
end
else if (tmp[3]) // DP
begin
addr_nxt = (tmp[14]) ? u_m1 : s_m1;
if (tmp[14])
u_nxt = u_m1;
else
s_nxt = s_m1;
DOutput = dp;
RnWOut = 1'b0; // write
tmp_nxt[3] = 1'b0;
end
else if (tmp[2]) // B
begin
addr_nxt = (tmp[14]) ? u_m1 : s_m1;
if (tmp[14])
u_nxt = u_m1;
else
s_nxt = s_m1;
DOutput = b;
RnWOut = 1'b0; // write
tmp_nxt[2] = 1'b0;
end
else if (tmp[1]) // A
begin
addr_nxt = (tmp[14]) ? u_m1 : s_m1;
if (tmp[14])
u_nxt = u_m1;
else
s_nxt = s_m1;
DOutput = a;
RnWOut = 1'b0; // write
tmp_nxt[1] = 1'b0;
end
else if (tmp[0]) // CC
begin
addr_nxt = (tmp[14]) ? u_m1 : s_m1;
if (tmp[14])
u_nxt = u_m1;
else
s_nxt = s_m1;
DOutput = cc;
RnWOut = 1'b0; // write
tmp_nxt[0] = 1'b0;
end
if (tmp[13]) // Then we're pushing for an IRQ, and LIC is supposed to be set.
rLIC = 1'b1;
if (tmp_nxt[7:0] == 8'H00)
begin
if (NextState == CPUSTATE_FETCH_I1)
begin
rAVMA = 1'b1;
rLIC = 1'b1;
end
else
rAVMA = 1'b0;
CpuState_nxt = NextState;
end
end
CPUSTATE_PUL_DONTCARE1:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_PUL_DONTCARE2;
end
CPUSTATE_PUL_DONTCARE2:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_PUL_ACTION;
end
CPUSTATE_PUL_ACTION:
begin
rAVMA = 1'b1;
if (tmp[0]) // CC
begin
addr_nxt = (tmp[14]) ? u : s;
if (tmp[14])
u_nxt = u_p1;
else
s_nxt = s_p1;
cc_nxt = D[7:0];
if (tmp[12] == 1'b1) // This pull is from an RTI, the E flag comes from the retrieved CC, and set the tmp_nxt accordingly, indicating what other registers to retrieve
begin
if (D[CC_E_BIT])
tmp_nxt[7:0] = 8'HFE; // Retrieve all registers (ENTIRE) [CC is already retrieved]
else
tmp_nxt[7:0] = 8'H80; // Retrieve PC and CC [CC is already retrieved]
end
else
tmp_nxt[0] = 1'b0;
end
else if (tmp[1]) // A
begin
addr_nxt = (tmp[14]) ? u : s;
if (tmp[14])
u_nxt = u_p1;
else
s_nxt = s_p1;
a_nxt = D[7:0];
tmp_nxt[1] = 1'b0;
end
else if (tmp[2]) // B
begin
addr_nxt = (tmp[14]) ? u : s;
if (tmp[14])
u_nxt = u_p1;
else
s_nxt = s_p1;
b_nxt = D[7:0];
tmp_nxt[2] = 1'b0;
end
else if (tmp[3]) // DP
begin
addr_nxt = (tmp[14]) ? u : s;
if (tmp[14])
u_nxt = u_p1;
else
s_nxt = s_p1;
dp_nxt = D[7:0];
tmp_nxt[3] = 1'b0;
end
else if (tmp[4] & (~tmp[15])) // X_HI
begin
addr_nxt = (tmp[14]) ? u : s;
if (tmp[14])
u_nxt = u_p1;
else
s_nxt = s_p1;
x_nxt[15:8] = D[7:0];
tmp_nxt[15] = 1'b1;
end
else if (tmp[4] & tmp[15]) // X_LO
begin
addr_nxt = (tmp[14]) ? u : s;
if (tmp[14])
u_nxt = u_p1;
else
s_nxt = s_p1;
x_nxt[7:0] = D[7:0];
tmp_nxt[4] = 1'b0;
tmp_nxt[15] = 1'b0;
end
else if (tmp[5] & (~tmp[15])) // Y_HI
begin
addr_nxt = (tmp[14]) ? u : s;
if (tmp[14])
u_nxt = u_p1;
else
s_nxt = s_p1;
y_nxt[15:8] = D[7:0];
tmp_nxt[15] = 1'b1;
end
else if (tmp[5] & tmp[15]) // Y_LO
begin
addr_nxt = (tmp[14]) ? u : s;
if (tmp[14])
u_nxt = u_p1;
else
s_nxt = s_p1;
y_nxt[7:0] = D[7:0];
tmp_nxt[5] = 1'b0;
tmp_nxt[15] = 1'b0;
end
else if (tmp[6] & (~tmp[15])) // U/S_HI
begin
addr_nxt = (tmp[14]) ? u : s;
if (tmp[14])
u_nxt = u_p1;
else
s_nxt = s_p1;
if (tmp[14])
s_nxt[15:8] = D[7:0];
else
u_nxt[15:8] = D[7:0];
tmp_nxt[15] = 1'b1;
end
else if (tmp[6] & tmp[15]) // U/S_LO
begin
addr_nxt = (tmp[14]) ? u : s;
if (tmp[14])
u_nxt = u_p1;
else
s_nxt = s_p1;
if (tmp[14])
s_nxt[7:0] = D[7:0];
else
u_nxt[7:0] = D[7:0];
tmp_nxt[6] = 1'b0;
tmp_nxt[15] = 1'b0;
end
else if (tmp[7] & (~tmp[15])) // PC_HI
begin
addr_nxt = (tmp[14]) ? u : s;
if (tmp[14])
u_nxt = u_p1;
else
s_nxt = s_p1;
pc_nxt[15:8] = D[7:0];
tmp_nxt[15] = 1'b1;
end
else if (tmp[7] & tmp[15]) // PC_LO
begin
addr_nxt = (tmp[14]) ? u : s;
if (tmp[14])
u_nxt = u_p1;
else
s_nxt = s_p1;
pc_nxt[7:0] = D[7:0];
tmp_nxt[7] = 1'b0;
tmp_nxt[15] = 1'b0;
end
else
begin
addr_nxt = (tmp[14]) ? u : s;
if (NextState == CPUSTATE_FETCH_I1)
begin
rAVMA = 1'b1;
rLIC = 1'b1;
end
else
rAVMA = 1'b0;
CpuState_nxt = NextState;
end
end
CPUSTATE_NMI_START:
begin
NMIClear_nxt = 1'b1;
addr_nxt = pc;
// tmp stands as the bits to push to the stack
tmp_nxt = 16'H20FF; // Save to the S stack, PC, U, Y, X, DP, B, A, CC; set LIC on every push
NextState_nxt = CPUSTATE_IRQ_DONTCARE2;
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_IRQ_DONTCARE;
IntType_nxt = INTTYPE_NMI;
cc_nxt[CC_E_BIT] = 1'b1;
end
CPUSTATE_IRQ_START:
begin
addr_nxt = pc;
tmp_nxt = 16'H20FF; // Save to the S stack, PC, U, Y, X, DP, B, A, CC; set LIC on every push
NextState_nxt = CPUSTATE_IRQ_DONTCARE2;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_IRQ_DONTCARE;
IntType_nxt = INTTYPE_IRQ;
cc_nxt[CC_E_BIT] = 1'b1;
end
CPUSTATE_FIRQ_START:
begin
addr_nxt = pc;
tmp_nxt = 16'H2081; // Save to the S stack, PC, CC; set LIC on every push
NextState_nxt = CPUSTATE_IRQ_DONTCARE2;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_IRQ_DONTCARE;
IntType_nxt = INTTYPE_FIRQ;
cc_nxt[CC_E_BIT] = 1'b0;
end
CPUSTATE_SWI_START:
begin
addr_nxt = pc;
tmp_nxt = 16'H00FF; // Save to the S stack, PC, U, Y, X, DP, B, A, CC
NextState_nxt = CPUSTATE_IRQ_DONTCARE2;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_IRQ_DONTCARE;
if (InstPage3)
IntType_nxt = INTTYPE_SWI3;
if (InstPage2)
IntType_nxt = INTTYPE_SWI2;
else
IntType_nxt = INTTYPE_SWI;
cc_nxt[CC_E_BIT] = 1'b1;
end
CPUSTATE_IRQ_DONTCARE:
begin
NMIClear_nxt = 1'b0;
addr_nxt = 16'HFFFF;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_PSH_ACTION;
end
CPUSTATE_IRQ_DONTCARE2:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_IRQ_VECTOR_HI;
rLIC = 1'b1;
end
CPUSTATE_IRQ_VECTOR_HI:
begin
case (IntType)
INTTYPE_NMI:
begin
addr_nxt = `NMI_VECTOR;
BS_nxt = 1'b1; // ACK Interrupt
end
INTTYPE_IRQ:
begin
addr_nxt = `IRQ_VECTOR;
BS_nxt = 1'b1; // ACK Interrupt
end
INTTYPE_SWI:
begin
addr_nxt = `SWI_VECTOR;
end
INTTYPE_FIRQ:
begin
addr_nxt = `FIRQ_VECTOR;
BS_nxt = 1'b1; // ACK Interrupt
end
INTTYPE_SWI2:
begin
addr_nxt = `SWI2_VECTOR;
end
INTTYPE_SWI3:
begin
addr_nxt = `SWI3_VECTOR;
end
default: // make the default an IRQ, even though it really should never happen
begin
addr_nxt = `IRQ_VECTOR;
BS_nxt = 1'b1; // ACK Interrupt
end
endcase
pc_nxt[15:8] = D[7:0];
rAVMA = 1'b1;
rBUSY = 1'b1;
rLIC = 1'b1;
CpuState_nxt = CPUSTATE_IRQ_VECTOR_LO;
end
CPUSTATE_IRQ_VECTOR_LO:
begin
case (IntType)
INTTYPE_NMI:
begin
addr_nxt = `NMI_VECTOR+16'H1;
cc_nxt[CC_I_BIT] = 1'b1;
cc_nxt[CC_F_BIT] = 1'b1;
BS_nxt = 1'b1; // ACK Interrupt
end
INTTYPE_IRQ:
begin
addr_nxt = `IRQ_VECTOR+16'H1;
cc_nxt[CC_I_BIT] = 1'b1;
BS_nxt = 1'b1; // ACK Interrupt
end
INTTYPE_SWI:
begin
addr_nxt = `SWI_VECTOR+16'H1;
cc_nxt[CC_F_BIT] = 1'b1;
cc_nxt[CC_I_BIT] = 1'b1;
rLIC = 1'b1;
end
INTTYPE_FIRQ:
begin
addr_nxt = `FIRQ_VECTOR+16'H1;
cc_nxt[CC_F_BIT] = 1'b1;
cc_nxt[CC_I_BIT] = 1'b1;
BS_nxt = 1'b1; // ACK Interrupt
end
INTTYPE_SWI2:
begin
addr_nxt = `SWI2_VECTOR+16'H1;
rLIC = 1'b1;
end
INTTYPE_SWI3:
begin
addr_nxt = `SWI3_VECTOR+16'H1;
rLIC = 1'b1;
end
default:
begin
end
endcase
pc_nxt[7:0] = D[7:0];
rAVMA = 1'b1;
rLIC = 1'b1;
CpuState_nxt = CPUSTATE_INT_DONTCARE;
end
CPUSTATE_INT_DONTCARE:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b1;
rLIC = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
CPUSTATE_CC_DONTCARE:
begin
addr_nxt = pc;
rLIC = 1'b1;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
CPUSTATE_TST_DONTCARE1:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_TST_DONTCARE2;
end
CPUSTATE_TST_DONTCARE2:
begin
addr_nxt = 16'HFFFF;
rLIC = 1'b1;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
CPUSTATE_DEBUG:
begin
addr_nxt = tmp;
rLIC = 1'b1;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
CPUSTATE_16IMM_DONTCARE:
begin
addr_nxt = 16'HFFFF;
rLIC = 1'b1;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
CPUSTATE_SYNC:
begin
addr_nxt = 16'HFFFF;
BA_nxt = 1'b1;
rLIC = 1'b1;
rAVMA = 1'b0;
if (~(NMILatched & FIRQLatched & IRQLatched))
begin
CpuState_nxt = CPUSTATE_SYNC_EXIT;
end
end
CPUSTATE_SYNC_EXIT:
begin
addr_nxt = 16'HFFFF;
BA_nxt = 1'b1;
rLIC = 1'b1;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
CPUSTATE_DMABREQ:
begin
rAVMA = 1'b0;
addr_nxt = 16'HFFFF;
BS_nxt = 1'b1;
BA_nxt = 1'b1;
rLIC = 1'b1;
tmp_nxt[3:0] = tmp[3:0] - 1'b1;
if ( (tmp[3:0] == 4'H0) | (DMABREQSample2) )
begin
CpuState_nxt = CPUSTATE_DMABREQ_EXIT;
end
end
CPUSTATE_DMABREQ_EXIT:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
CPUSTATE_HALTED:
begin
rAVMA = 1'b0;
addr_nxt = 16'HFFFF;
BS_nxt = 1'b1;
BA_nxt = 1'b1;
rLIC = 1'b1;
if (HALTSample2)
begin
CpuState_nxt = CPUSTATE_HALT_EXIT2;
end
end
CPUSTATE_HALT_EXIT2:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_FETCH_I1;
end
CPUSTATE_STOP:
begin
addr_nxt = 16'HDEAD;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_STOP2;
end
CPUSTATE_STOP2:
begin
addr_nxt = pc;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_STOP3;
end
CPUSTATE_STOP3:
begin
addr_nxt = 16'H0000; //{Inst1, Inst2};
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_STOP;
end
// The otherwise critically useful Figure 18 in the 6809 datasheet contains an error;
// it lists that CWAI has a tri-stated bus while it waits for an interrupt.
// That is not true. SYNC tristates the bus, as do things like /HALT and /DMABREQ.
// CWAI does not. It waits with /VMA cycles on the bus until an interrupt occurs.
// The implementation here fits with the 6809 Programming Manual and other Motorola
// sources, not with that typo in Figure 18.
CPUSTATE_CWAI:
begin
addr_nxt = pc;
cc_nxt = {1'b1, (cc[6:0] & Inst2[6:0])}; // Set E flag, AND CC with CWAI argument
tmp_nxt = 16'H00FF; // Save to the S stack, PC, U, Y, X, DP, B, A, CC
NextState_nxt = CPUSTATE_CWAI_POST;
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_CWAI_DONTCARE1;
end
CPUSTATE_CWAI_DONTCARE1:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b1;
CpuState_nxt = CPUSTATE_PSH_ACTION;
end
CPUSTATE_CWAI_POST:
begin
addr_nxt = 16'HFFFF;
rAVMA = 1'b0;
CpuState_nxt = CPUSTATE_CWAI_POST;
// Wait for an interrupt
if (NMILatched == 0)
begin
rAVMA = 1'b1;
IntType_nxt = INTTYPE_NMI;
cc_nxt[CC_F_BIT] = 1'b1;
cc_nxt[CC_I_BIT] = 1'b1;
CpuState_nxt = CPUSTATE_IRQ_VECTOR_HI;
end
else if ((FIRQLatched == 0) && (cc[CC_F_BIT] == 0))
begin
rAVMA = 1'b1;
cc_nxt[CC_F_BIT] = 1'b1;
cc_nxt[CC_I_BIT] = 1'b1;
IntType_nxt = INTTYPE_FIRQ;
CpuState_nxt = CPUSTATE_IRQ_VECTOR_HI;
end
else if ((IRQLatched == 0) && (cc[CC_I_BIT] == 0))
begin
rAVMA = 1'b1;
cc_nxt[CC_I_BIT] = 1'b1;
IntType_nxt = INTTYPE_IRQ;
CpuState_nxt = CPUSTATE_IRQ_VECTOR_HI;
end
end
default: // Picky darned Verilog.
begin
CpuState_nxt = PostIllegalState;
end
endcase
end
endmodule