diff --git a/Arcade_MiST/Konami Gyruss/Gyruss.qsf b/Arcade_MiST/Konami Gyruss/Gyruss.qsf index 88e7856c..58c6e146 100644 --- a/Arcade_MiST/Konami Gyruss/Gyruss.qsf +++ b/Arcade_MiST/Konami Gyruss/Gyruss.qsf @@ -225,6 +225,7 @@ set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_VS set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to AUDIO_L set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to AUDIO_R set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SPI_DO +set_global_assignment -name ALLOW_POWER_UP_DONT_CARE ON set_global_assignment -name SYSTEMVERILOG_FILE rtl/Gyruss_MiST.sv set_global_assignment -name QIP_FILE rtl/pll.qip set_global_assignment -name SYSTEMVERILOG_FILE rtl/Gyruss.sv @@ -234,6 +235,7 @@ set_global_assignment -name VERILOG_FILE rtl/jt49_dcrm2.v set_global_assignment -name VERILOG_FILE rtl/hiscore.v set_global_assignment -name SYSTEMVERILOG_FILE rtl/Gyruss_SND.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/Gyruss_CPU.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/KONAMI1.sv set_global_assignment -name VERILOG_FILE rtl/Filters/gyruss_lpf.v set_global_assignment -name VERILOG_FILE rtl/Filters/gyruss_lpf_medium.v set_global_assignment -name VERILOG_FILE rtl/Filters/gyruss_lpf_light.v @@ -249,5 +251,5 @@ set_global_assignment -name QIP_FILE ../../common/CPU/T80/T80.qip set_global_assignment -name QIP_FILE ../../common/CPU/t48/i8039.qip set_global_assignment -name QIP_FILE ../../common/Sound/JT49/jt49.qip set_global_assignment -name SIGNALTAP_FILE output_files/sndcpu.stp -set_global_assignment -name ALLOW_POWER_UP_DONT_CARE ON +set_global_assignment -name VERILOG_FILE ../../common/CPU/MC6809/mc6809is.v set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file diff --git a/Arcade_MiST/Konami Gyruss/rtl/custom/KONAMI-1/KONAMI1.sv b/Arcade_MiST/Konami Gyruss/rtl/KONAMI1.sv similarity index 100% rename from Arcade_MiST/Konami Gyruss/rtl/custom/KONAMI-1/KONAMI1.sv rename to Arcade_MiST/Konami Gyruss/rtl/KONAMI1.sv diff --git a/Arcade_MiST/Konami Gyruss/rtl/custom/KONAMI-1/mc6809isk.v b/Arcade_MiST/Konami Gyruss/rtl/custom/KONAMI-1/mc6809isk.v deleted file mode 100644 index 18467022..00000000 --- a/Arcade_MiST/Konami Gyruss/rtl/custom/KONAMI-1/mc6809isk.v +++ /dev/null @@ -1,4162 +0,0 @@ -`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) -// Revision 1.0sk - Add direct injection of KONAMI-1 encrypted opcodes (by Ace) -// 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", - parameter IS_KONAMI1="FALSE" -) -( - input CLK, - input fallE_en, - input fallQ_en, - input [7:0] OP, - - 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 - if(IS_KONAMI1=="FALSE") //Modification by Ace: accept opcodes directly for KONAMI-1 CPU - assign MappedInstruction = MapInstruction(D); - else - assign MappedInstruction = MapInstruction(OP); -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]}}; - cc_nxt[CC_N_BIT] = b[7]; - cc_nxt[CC_Z_BIT] = {b == 8'H00}; - 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 - diff --git a/Arcade_MiST/Konami Gyruss/rtl/custom/gyruss_custom.qip b/Arcade_MiST/Konami Gyruss/rtl/custom/gyruss_custom.qip index 67c0410c..0f1fb21f 100644 --- a/Arcade_MiST/Konami Gyruss/rtl/custom/gyruss_custom.qip +++ b/Arcade_MiST/Konami Gyruss/rtl/custom/gyruss_custom.qip @@ -3,5 +3,3 @@ set_global_assignment -name SYSTEMVERILOG_FILE rtl/custom/k083.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/custom/k501.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/custom/k502.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/custom/k503.sv -set_global_assignment -name SYSTEMVERILOG_FILE rtl/custom/KONAMI-1/KONAMI1.sv -set_global_assignment -name VERILOG_FILE rtl/custom/KONAMI-1/mc6809isk.v diff --git a/Arcade_MiST/Konami Jackal/rtl/custom/k005885.sv b/Arcade_MiST/Konami Jackal/rtl/custom/k005885.sv index f49fe4a5..f8dff57a 100644 --- a/Arcade_MiST/Konami Jackal/rtl/custom/k005885.sv +++ b/Arcade_MiST/Konami Jackal/rtl/custom/k005885.sv @@ -4,7 +4,7 @@ // generator // Graphics logic based on the video section of the Green Beret core for // MiSTer by MiSTer-X -// Copyright (C) 2020, 2021 Ace +// Copyright (C) 2020, 2022 Ace // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), @@ -84,17 +84,20 @@ module k005885 //-10: Iron Horse bootleg (10 extra vertical lines resulting in slower VSync, altered screen centering, sprite layer is // offset vertically by 1 line, sprite limit significantly lower than normal) input [1:0] BTLG, - //Extra data outputs for graphics ROMs - output ATR4, //Tilemap attribute bit 4 - output ATR5, //Tilemap attribute bit 5 - + output reg ATR4, //Tilemap attribute bit 4 + output reg ATR5 //Tilemap attribute bit 5 + + `ifdef MISTER_HISCORE //MiSTer high score system I/O (to be used only with Iron Horse) - input [11:0] hs_address, - input [7:0] hs_data_in, - output [7:0] hs_data_out, - input hs_write, - input hs_access + , + input [11:0] hs_address, + input [7:0] hs_data_in, + output [7:0] hs_data_out, + input hs_write_enable, + input hs_access_read, + input hs_access_write + `endif ); //------------------------------------------------------- Signal outputs -------------------------------------------------------// @@ -109,18 +112,19 @@ assign NIOC = ~(~NXCS & (A[13:11] == 3'b001)); assign NRMW = 1; //Output bits 4 and 5 of tilemap attributes for graphics ROM addressing -assign ATR4 = tileram_attrib_D[4]; -assign ATR5 = tileram_attrib_D[5]; - +/* +assign ATR4 = tile_ctrl[2] ? tile_attrib_D[4] : tile0_attrib_D[4]; +assign ATR5 = tile_ctrl[2] ? tile_attrib_D[5] : tile0_attrib_D[5]; +*/ //Data output to CPU assign DBo = (ram_cs & ~NRD) ? ram_Dout: (zram0_cs & ~NRD) ? zram0_Dout: (zram1_cs & ~NRD) ? zram1_Dout: (zram2_cs & ~NRD) ? zram2_Dout: - (tile_attrib_cs & ~NRD) ? tileram_attrib_Dout: - (tile_cs & ~NRD) ? tileram_Dout: - (tile1_attrib_cs & ~NRD) ? tileram1_attrib_Dout: - (tile1_cs & ~NRD) ? tileram1_Dout: + (tile_attrib_cs & ~NRD) ? tile0_attrib_Dout: + (tile_cs & ~NRD) ? tile0_Dout: + (tile1_attrib_cs & ~NRD) ? tile1_attrib_Dout: + (tile1_cs & ~NRD) ? tile1_Dout: (spriteram_cs & ~NRD) ? spriteram_Dout: 8'hFF; @@ -131,12 +135,7 @@ reg [3:0] div = 4'd0; always_ff @(posedge CK49) begin div <= div + 4'd1; end -reg [2:0] n_div = 3'd0; -always_ff @(negedge CK49) begin - n_div <= n_div + 3'd1; -end wire cen_6m = !div[2:0]; -wire n_cen_6m = !n_div; wire cen_3m = !div; assign NCK2 = div[2]; assign H1O = div[3]; @@ -173,7 +172,6 @@ reg [8:0] v_cnt = 9'd0; //rolls over reg hblank = 0; reg vblank = 0; -reg vblank_irq_en = 0; reg frame_odd_even = 0; //Add an extra 10 lines to the vertical counter if a bootleg Iron Horse ROM set is loaded or remove 9 lines from the vertical //counter if a bootleg Jackal ROM set is loaded @@ -206,6 +204,12 @@ always_ff @(posedge CK49) begin vsync_start <= 9'd255; vsync_end <= 9'd262; end + else if(tile_ctrl[2]) begin + hsync_start <= HCTR[3] ? 9'd312 : 9'd320; + hsync_end <= HCTR[3] ? 9'd343 : 9'd351; + vsync_start <= 9'd254; + vsync_end <= 9'd261; + end else begin hsync_start <= HCTR[3] ? 9'd288 : 9'd296; hsync_end <= HCTR[3] ? 9'd319 : 9'd327; @@ -216,29 +220,31 @@ end always_ff @(posedge CK49) begin if(cen_6m) begin case(h_cnt) - 0: begin - vblank_irq_en <= 0; - h_cnt <= h_cnt + 9'd1; - end //HBlank ends two lines earlier than normal on bootleg Jackal PCBs - 11: begin + 10: begin if(BTLG == 2'b01) hblank <= 0; h_cnt <= h_cnt + 9'd1; end - 13: begin + 12: begin if(BTLG != 2'b01) hblank <= 0; h_cnt <= h_cnt + 9'd1; end //Shift the start of HBlank two lines earlier when bootleg Jackal ROMs are loaded - 251: begin - if(BTLG == 2'b01) + 250: begin + if(BTLG == 2'b01 && !tile_ctrl[2]) hblank <= 1; h_cnt <= h_cnt + 9'd1; end - 253: begin - if(BTLG != 2'b01) + 252: begin + if(BTLG != 2'b01 && !tile_ctrl[2]) + hblank <= 1; + h_cnt <= h_cnt + 9'd1; + end + //Shift the start of HBlank 40 lines later when using the wider 280x224 video mode + 292: begin + if(tile_ctrl[2]) hblank <= 1; h_cnt <= h_cnt + 9'd1; end @@ -251,7 +257,6 @@ always_ff @(posedge CK49) begin end 239: begin vblank <= 1; - vblank_irq_en <= 1; frame_odd_even <= ~frame_odd_even; v_cnt <= v_cnt + 9'd1; end @@ -278,43 +283,49 @@ assign NCSY = NHSY ^ NVSY; //------------------------------------------------------------- IRQs -----------------------------------------------------------// +//Edge detection for VBlank and vertical counter bits 4 and 5 for IRQ generation +reg old_vblank, old_vcnt4, old_vcnt5; +always_ff @(posedge CK49) begin + old_vcnt4 <= v_cnt[4]; + old_vcnt5 <= v_cnt[5]; + old_vblank <= vblank; +end + //IRQ (triggers every VBlank) reg vblank_irq = 1; -always_ff @(posedge CK49 or negedge NEXR) begin - if(!NEXR) +always_ff @(posedge CK49) begin + if(!NEXR || !irq_mask) vblank_irq <= 1; - else if(cen_6m) begin - if(!irq_mask) - vblank_irq <= 1; - else if(vblank_irq_en) - vblank_irq <= 0; - end + else if(!old_vblank && vblank) + vblank_irq <= 0; end assign NIRQ = vblank_irq; -//NMI (triggers every 64 scanlines starting from scanline 48) +//NMI (triggers on the falling edge of vertical counter bits 4 or 5 based on the state of tile control register bit 2) reg nmi = 1; -always_ff @(posedge CK49 or negedge NEXR) begin - if(!NEXR) +always_ff @(posedge CK49) begin + if(!NEXR || !nmi_mask) nmi <= 1; - else if(cen_3m) begin - if(!nmi_mask) - nmi <= 1; - else if((v_cnt[7:0] + 9'd16) % 9'd64 == 0) - nmi <= 0; + else begin + if(tile_ctrl[2]) begin + if(old_vcnt4 && !v_cnt[4]) + nmi <= 0; + end + else begin + if(old_vcnt5 && !v_cnt[5]) + nmi <= 0; + end end end assign NNMI = nmi; //FIRQ (triggers every second VBlank) reg firq = 1; -always_ff @(posedge CK49 or negedge NEXR) begin - if(!NEXR) +always_ff @(posedge CK49) begin + if(!NEXR || !firq_mask) firq <= 1; - else if(cen_3m) begin - if(!firq_mask) - firq <= 1; - else if(!frame_odd_even && v_cnt == 9'd239) + else begin + if(frame_odd_even && !old_vblank && vblank) firq <= 0; end end @@ -355,13 +366,9 @@ reg firq_mask = 0; reg flipscreen = 0; //Write to the appropriate register -always_ff @(posedge CK49, negedge NEXR) begin - if(!NEXR) begin - nmi_mask <= 1; - irq_mask <= 1; - firq_mask <= 1; - flipscreen <= 0; - end else if(cen_3m) begin +always_ff @(posedge CK49) begin + reg rightD, leftD, upD; + if(cen_3m) begin if(regs_cs && NRD) case(A[2:0]) 3'b000: scroll_y <= DBi; @@ -446,32 +453,32 @@ wire tile1_attrib_cs = ~NXCS & (A[13:10] == 4'b1010); wire tile1_cs = ~NXCS & (A[13:10] == 4'b1011); wire spriteram_cs = ~NXCS & (A[13:12] == 2'b11); -wire [7:0] tileram_attrib_Dout, tileram_Dout, tileram1_attrib_Dout, tileram1_Dout, spriteram_Dout; -wire [7:0] tileram_attrib_D, tileram_D, tileram1_attrib_D, tileram1_D, spriteram_D; +wire [7:0] tile0_attrib_Dout, tile0_Dout, tile1_attrib_Dout, tile1_Dout, spriteram_Dout; +wire [7:0] tile0_attrib_D, tile0_D, tile1_attrib_D, tile1_D, spriteram_D; //Tilemap layer 0 dpram_dc #(.widthad_a(10)) VRAM_TILEATTRIB0 ( .clock_a(CK49), .address_a(A[9:0]), .data_a(DBi), - .q_a(tileram_attrib_Dout), + .q_a(tile0_attrib_Dout), .wren_a(tile_attrib_cs & NRD), .clock_b(CK49), .address_b(vram_A), - .q_b(tileram_attrib_D) + .q_b(tile0_attrib_D) ); dpram_dc #(.widthad_a(10)) VRAM_TILECODE0 ( .clock_a(CK49), .address_a(A[9:0]), .data_a(DBi), - .q_a(tileram_Dout), + .q_a(tile0_Dout), .wren_a(tile_cs & NRD), .clock_b(CK49), .address_b(vram_A), - .q_b(tileram_D) + .q_b(tile0_D) ); //Tilemap layer 1 dpram_dc #(.widthad_a(10)) VRAM_TILEATTRIB1 @@ -479,118 +486,208 @@ dpram_dc #(.widthad_a(10)) VRAM_TILEATTRIB1 .clock_a(CK49), .address_a(A[9:0]), .data_a(DBi), - .q_a(tileram1_attrib_Dout), + .q_a(tile1_attrib_Dout), .wren_a(tile1_attrib_cs & NRD), .clock_b(CK49), .address_b(vram_A), - .q_b(tileram1_attrib_D) + .q_b(tile1_attrib_D) ); dpram_dc #(.widthad_a(10)) VRAM_TILECODE1 ( .clock_a(CK49), .address_a(A[9:0]), .data_a(DBi), - .q_a(tileram1_Dout), + .q_a(tile1_Dout), .wren_a(tile1_cs & NRD), .clock_b(CK49), .address_b(vram_A), - .q_b(tileram1_D) + .q_b(tile1_D) ); + + +`ifndef MISTER_HISCORE +//Sprites +dpram_dc #(.widthad_a(12)) VRAM_SPR +( + .clock_a(CK49), + .address_a(A[11:0]), + .data_a(DBi), + .q_a(spriteram_Dout), + .wren_a(spriteram_cs & NRD), + + .clock_b(~CK49), + .address_b(spriteram_A), + .q_b(spriteram_D) +); +`else // Hiscore mux (this is only to be used with Iron Horse as its high scores are stored in sprite RAM) -wire [11:0] VRAM_SPR_AD = hs_access ? hs_address : A[11:0]; -wire [7:0] VRAM_SPR_DIN = hs_access ? hs_data_in : DBi; -wire VRAM_SPR_WE = hs_access ? hs_write : (spriteram_cs & NRD); -wire [7:0] VRAM_SPR_DOUT; - -assign hs_data_out = hs_access ? VRAM_SPR_DOUT : 8'h00; -assign spriteram_Dout = hs_access ? 8'h00 : VRAM_SPR_DOUT; - +// - Mirrored sprite RAM used to protect against corruption while retrieving highscore data +wire [11:0] VRAM_SPR_AD = hs_access_write ? hs_address : A[11:0]; +wire [7:0] VRAM_SPR_DIN = hs_access_write ? hs_data_in : DBi; +wire VRAM_SPR_WE = hs_access_write ? hs_write_enable : (spriteram_cs & NRD); //Sprites dpram_dc #(.widthad_a(12)) VRAM_SPR ( .clock_a(CK49), .address_a(VRAM_SPR_AD), .data_a(VRAM_SPR_DIN), - .q_a(VRAM_SPR_DOUT), + .q_a(spriteram_Dout), .wren_a(VRAM_SPR_WE), .clock_b(~CK49), .address_b(spriteram_A), .q_b(spriteram_D) ); +//Sprite RAM shadow for highscore read access +dpram_dc #(.widthad_a(12)) VRAM_SPR_SHADOW +( + .clock_a(CK49), + .address_a(VRAM_SPR_AD), + .data_a(VRAM_SPR_DIN), + .wren_a(VRAM_SPR_WE), + + .clock_b(CK49), + .address_b(hs_address), + .q_b(hs_data_out) +); +`endif //-------------------------------------------------------- Tilemap layer -------------------------------------------------------// -//TODO: The current implementation only handles one of the 005885's two tilemap layers - add logic to handle both layers +//The Konami 005885 contains two tilemap layers. Finalizer - Super Transformation uses the second layer to draw the HUD at the +//top of the screen. Latch tilemap data out of bank 0 or bank 1 of the tilemap section of VRAM based on how far the game has +//drawn the tilemap layer when tile control bit 2 is set, otherwise grab tilemap data from bank 0 of the tilemap section of VRAM +//at all times + +//Loosely based on TimePilot 84's schematics +reg [7:0] tile_attrib_D, tile_D; +wire tile1_en = flipscreen ? h_cnt > 9'd243 : h_cnt < 9'd40; +wire [5:0] tile_hoffset = tile_ctrl[2] ? (~tile1_en ? (flipscreen ? 6'd4 : 6'd32) : 6'd0) : (flipscreen ? 6'd4 : 6'd0); + +always_ff @(posedge CK49) begin + if (cen_6m) begin + if(h_cnt[1:0] == 2'b01) begin // posedge of h_cnt[1] + if(tile_ctrl[2] && tile1_en) begin + tile_D <= tile1_D; + tile_attrib_D <= tile1_attrib_D; + end + else begin + tile_D <= tile0_D; + tile_attrib_D <= tile0_attrib_D; + end + end + end +end //XOR horizontal and vertical counter bits with flipscreen bit wire [8:0] hcnt_x = h_cnt ^ {9{flipscreen}}; wire [8:0] vcnt_x = v_cnt ^ {9{flipscreen}}; //Generate tilemap position by summing the XORed counter bits with their respective scroll registers or ZRAM bank 0 based on -//whether row scroll or column scroll is enabled -wire [8:0] row_scroll = (scroll_ctrl[3:1] == 3'b101) ? zram0_D : {scroll_ctrl[0], scroll_x}; +//whether row scroll or column scroll is enabled (do not allow scrolling when drawing Finalizer - Super Transformation's HUD +//and offset the tilemap layer with this game) +wire [8:0] row_scroll = (tile_ctrl[2] & !flipscreen & tile1_en) ? 9'd0: + (tile_ctrl[2] & flipscreen & tile1_en) ? 9'd28: + (scroll_ctrl[3:1] == 3'b101) ? zram0_D : {scroll_ctrl[0], scroll_x}; wire [8:0] col_scroll = (scroll_ctrl[3:1] == 3'b011) ? zram0_D : scroll_y; -wire [8:0] tilemap_hpos = hcnt_x + row_scroll; +wire [7:2] tilemap_hpos = hcnt_x[7:2] + row_scroll[7:2] - tile_hoffset[5:2] + {!tile_ctrl[2] & !flipscreen, 1'b0}/* synthesis keep */; wire [8:0] tilemap_vpos = vcnt_x + col_scroll; //Address output to tilemap section of VRAM wire [9:0] vram_A = {tilemap_vpos[7:3], tilemap_hpos[7:3]}; //Assign tile index as bits 5 and 6 of tilemap attributes and the tile code -wire [9:0] tile_index = {tileram_attrib_D[7:6], tileram_D}; +wire [9:0] tile_index = {tile_attrib_D[7:6], tile_D} /* synthesis keep */; //XOR tile H/V flip bits with the flipscreen bit -wire tile_hflip = tileram_attrib_D[4]; -wire tile_vflip = tileram_attrib_D[5]; - -//Address output to graphics ROMs -assign R = {tile_ctrl[1:0], tile_index, (tilemap_vpos[2:0] ^ {3{tile_vflip}}), (tilemap_hpos[2] ^ tile_hflip)}; +wire tile_hflip = tile_attrib_D[4]; +wire tile_vflip = tile_attrib_D[5]; //Latch tile data from graphics ROMs, tile colors and tile H flip bit from VRAM on the falling edge of tilemap horizontal position -//bit 1 +//bit 1 (direct for Finalizer) reg [15:0] RD_lat = 16'd0; -reg [3:0] tile_color = 4'd0; -reg tile_hflip_lat = 0; -reg old_tilehpos1; +reg [3:0] tile_color, tile_color_r; +reg tile_hflip_lat, tile_hflip_lat_r; +reg tile_vflip_lat; +reg hpos2_lat; +reg [2:0] yscroll_lat; +reg [1:0] xscroll_lat, xscroll_lat_r, xscroll_lat_rr; + always_ff @(posedge CK49) begin - old_tilehpos1 <= tilemap_hpos[1]; - if(old_tilehpos1 && !tilemap_hpos[1]) begin - tile_color <= tileram_attrib_D[3:0]; - RD_lat <= flipscreen ? {RDL, RDU} : {RDU, RDL}; - tile_hflip_lat <= tileram_attrib_D[4]; + if (cen_6m) begin + if(h_cnt[1:0] == 2'b11) begin // negedge of h_cnt[1] + hpos2_lat <= tilemap_hpos[2]; + xscroll_lat <= row_scroll[1:0]; + xscroll_lat_r <= xscroll_lat; + yscroll_lat <= tilemap_vpos[2:0]; + tile_color <= tile_attrib_D[3:0]; + tile_color_r <= tile_color; + tile_hflip_lat <= tile_hflip; + tile_hflip_lat_r <= tile_hflip_lat; + tile_vflip_lat <= tile_vflip; + //Address output to graphics ROMs + R[15:4] <= {tile_ctrl[1:0], tile_index}; + //Latch graphics ROM output + RD_lat <= {RDU, RDL}; + //Output bits 4 and 5 of tilemap attributes for graphics ROM addressing + ATR4 <= tile_attrib_D[4]; + ATR5 <= tile_attrib_D[5]; + end + xscroll_lat_rr <= xscroll_lat_r; end end +assign R[3:0] = {yscroll_lat[2:0] ^ {3{tile_vflip_lat}}, hpos2_lat ^ tile_hflip_lat}; -//Multiplex graphics ROM data down from 16 bits to 8 using bit 1 of the horizontal position -wire [7:0] RD = (tilemap_hpos[1] ^ tile_hflip_lat) ? RD_lat[7:0] : RD_lat[15:8]; - -//Further multiplex graphics ROM data down from 8 bits to 4 using bit 0 of the horizontal position -wire [3:0] tile_pixel = (tilemap_hpos[0] ^ tile_hflip_lat) ? RD[3:0] : RD[7:4]; - -//Retrieve tilemap select bit from bit 1 of the tile control register XORed with bit 5 of the same register -wire tile_sel = tile_ctrl[1] ^ tile_ctrl[5]; -reg tilemap_en = 0; -always_ff @(posedge CK49) begin - if(n_cen_6m) begin - tilemap_en <= tile_sel; - end +reg [3:0] tile_pixel /* synthesis keep */; +always @(*) begin + case (hcnt_x[1:0] ^ {2{tile_hflip_lat_r}}) + 2'b00: tile_pixel = RD_lat[15:12]; + 2'b01: tile_pixel = RD_lat[11: 8]; + 2'b10: tile_pixel = RD_lat[ 7: 4]; + 2'b11: tile_pixel = RD_lat[ 3: 0]; + default: ; + endcase end //Address output to tilemap LUT PROM -assign VCF = tile_color; +assign VCF = tile_color_r; assign VCB = tile_pixel; -//Shift the tilemap layer left by two lines when the screen is flipped -reg [7:0] tilemap_shift; +// latch pixel data, and generate 4 shifted pixel positions for fine scroll +reg [3:0] pix0, pix1, pix2, pix3; always_ff @(posedge CK49) begin - if(cen_6m) - tilemap_shift <= {VCD, tilemap_shift[7:4]}; + if (cen_6m) begin + pix0 <= VCD; + pix1 <= pix0; + pix2 <= pix1; + pix3 <= pix2; + end end -wire [3:0] tilemap_D = flipscreen ? tilemap_shift[3:0] : VCD; + +// select the appropriate shifted pixel according to scroll value +reg [3:0] tilemap_D /* synthesis keep */; +wire hud_left = !flipscreen && tile_ctrl[2] && h_cnt < 52; +wire hud_right = flipscreen && tile_ctrl[2] && h_cnt > 252; +always @(*) begin + case ({2{flipscreen}} ^ xscroll_lat_rr) + 2'b00: tilemap_D = pix3; + 2'b01: tilemap_D = pix2; + 2'b10: tilemap_D = pix1; + 2'b11: tilemap_D = pix0; + default: ; + endcase + if (hud_left ) tilemap_D = pix3; + if (hud_right) tilemap_D = pix0; +end + +//Retrieve tilemap select bit from bit 1 of the tile control register XORed with bit 5 of the same register +wire tile_sel = tile_ctrl[1] ^ tile_ctrl[5]; +//Prioritize the tilemap layer when using the extended 280x224 mode for Finalizer in the score display area, otherwise give priority +//to sprites +wire tilemap_en = tile_ctrl[2] ? (hud_left | hud_right) : tile_sel; //-------------------------------------------------------- Sprite layer --------------------------------------------------------// @@ -619,18 +716,25 @@ end //Sprite state machine reg [8:0] sprite_index; reg [2:0] sprite_offset; -reg [7:0] sprite_attrib0, sprite_attrib1, sprite_attrib2, sprite_attrib3, sprite_attrib4; reg [2:0] sprite_fsm_state; +reg [11:0] sprite_code; +reg [8:0] sprite_limit; +reg [8:0] sprite_x; +reg [7:0] sprite_y; reg [5:0] sprite_width; -//Bootleg Iron Horse PCBs have a lower-than-normal sprite limit causing noticeable sprite flickering - reduce the sprite limit -//to 32 sprites (0 - 155 in increments of 5) if one such ROM set is loaded (render 96 sprites at once, 0 - 485 in increments of -//5, otherwise) -wire [8:0] sprite_limit = (BTLG == 2'b10) ? 9'd155 : 9'd485; +reg [3:0] sprite_color; +reg [2:0] sprite_size; +reg sprite_hflip, sprite_vflip, sprite_x8_sel, sprite_x8_vram; +wire [8:0] sprite_fsm_reset = tile_ctrl[2] ? 9'd40 : 9'd0; always_ff @(posedge CK49) begin + //Bootleg Iron Horse PCBs have a lower-than-normal sprite limit causing noticeable sprite flickering - reduce the sprite limit + //to 32 sprites (0 - 155 in increments of 5) if one such ROM set is loaded (render 96 sprites at once, 0 - 485 in increments of + //5, otherwise) + sprite_limit <= (BTLG == 2'b10) ? 9'd155 : 9'd485; //Reset the sprite state machine whenever the sprite horizontal postion, and in turn the horziontal counter, returns to 0 //Also hold the sprite state machine in this initial state for the first line while drawing sprites for bootleg Iron Horse //ROM sets to prevent graphical garbage from occurring on the top-most line - if(sprite_hpos == 9'd0 || (BTLG == 2'b10 && (!flipscreen && sprite_vpos <= 9'd80) || (flipscreen && sprite_vpos >= 9'd304))) begin + if(sprite_hpos == sprite_fsm_reset || (BTLG == 2'b10 && (!flipscreen && sprite_vpos <= 9'd80) || (flipscreen && sprite_vpos >= 9'd304))) begin sprite_width <= 0; sprite_index <= 0; sprite_offset <= 3'd4; @@ -640,25 +744,45 @@ always_ff @(posedge CK49) begin case(sprite_fsm_state) 0: /* empty */ ; 1: begin + //If the sprite limit is reached, hold the state machine in an empty state, otherwise latch the sprite H/V flip + //bits, sprite size, bit 8 of the sprite X position and its select bit if(sprite_index > sprite_limit) sprite_fsm_state <= 0; else begin - sprite_attrib4 <= spriteram_D; + sprite_vflip <= spriteram_D[6] ^ ~flipscreen; + sprite_hflip <= spriteram_D[5] ^ flipscreen; + sprite_size <= spriteram_D[4:2]; + sprite_x8_sel <= spriteram_D[1]; + sprite_x8_vram <= spriteram_D[0]; sprite_offset <= 3'd3; sprite_fsm_state <= sprite_fsm_state + 3'd1; end end 2: begin - sprite_attrib3 <= spriteram_D; + //Latch sprite X position and set the 9th bit as either the one latched previously from VRAM or the AND of position + //bits [7:3] based on the state of the select bit + if(sprite_x8_sel) + sprite_x[8] <= sprite_x8_vram ^ flipscreen; + else + sprite_x[8] <= (&spriteram_D[7:3]) ^ flipscreen; + sprite_x[7:0] <= spriteram_D ^ {8{flipscreen}}; sprite_offset <= 3'd2; sprite_fsm_state <= sprite_fsm_state + 3'd1; end 3: begin - //Skip the current sprite if it's inactive, otherwise obtain the sprite Y attribute and continue - //scanning out the rest of the sprite attributes + //Latch sprite Y position + sprite_y <= spriteram_D; + sprite_offset <= 3'd1; + sprite_fsm_state <= sprite_fsm_state + 3'd1; + end + 4: begin + //Skip the current sprite if it's inactive, otherwise latch sprite color and the upper/lower 2 bits of the sprite + //code, and continue scanning out the rest of the sprite attributes if(sprite_active) begin - sprite_attrib2 <= spriteram_D; - sprite_offset <= 3'd1; + sprite_color <= spriteram_D[7:4]; + sprite_code[1:0] <= spriteram_D[3:2]; + sprite_code[11:10] <= spriteram_D[1:0]; + sprite_offset <= 3'd0; sprite_fsm_state <= sprite_fsm_state + 3'd1; end else begin @@ -667,13 +791,9 @@ always_ff @(posedge CK49) begin sprite_fsm_state <= 3'd1; end end - 4: begin - sprite_attrib1 <= spriteram_D; - sprite_offset <= 3'd0; - sprite_fsm_state <= sprite_fsm_state + 3'd1; - end 5: begin - sprite_attrib0 <= spriteram_D; + //Latch bits [9:2] of the sprite code and set up the sprite width based on the sprite size + sprite_code[9:2] <= spriteram_D; sprite_offset <= 3'd4; sprite_index <= sprite_index + 9'd5; case(sprite_size) @@ -681,7 +801,6 @@ always_ff @(posedge CK49) begin 3'b001: sprite_width <= 6'b110000 + (BTLG == 2'b01 && flipscreen); 3'b010: sprite_width <= 6'b111000 + (BTLG == 2'b01 && flipscreen); 3'b011: sprite_width <= 6'b111000 + (BTLG == 2'b01 && flipscreen); - 3'b100: sprite_width <= 6'b100000 + (BTLG == 2'b01 && flipscreen); default: sprite_width <= 6'b100000 + (BTLG == 2'b01 && flipscreen); endcase sprite_fsm_state <= sprite_fsm_state + 3'd1; @@ -705,36 +824,6 @@ always_ff @(posedge CK49) begin endcase end -//Obtain sprite X position from sprite attribute byte 3 - append a 9th bit based on the state of bit 1 sprite attribute byte 4, -//bit 0 of sprite attribute byte 4 if high or the AND of the upper 5 bits of the horizontal position if low -reg sprite_x8; -always_ff @(posedge CK49) begin - if(sprite_attrib4[1]) - sprite_x8 <= sprite_attrib4[0]; - else - sprite_x8 <= &sprite_attrib3[7:3]; -end -wire [8:0] sprite_x = {sprite_x8 ^ flipscreen, sprite_attrib3 ^ {8{flipscreen}}}; - -//If the sprite state machine is in state 3, obtain sprite Y position directly from sprite RAM, otherwise obtain it from -//sprite attribute byte 2 -wire [7:0] sprite_y = (sprite_fsm_state == 3'd3) ? spriteram_D : sprite_attrib2; - -//Sprite flip attributes are stored in bits 5 (horizontal) and 6 (vertical) of sprite attribute byte 4 -//Also XOR these attributes with the flipscreen bit (XOR with the inverse for vertical flip) -wire sprite_hflip = sprite_attrib4[5] ^ flipscreen; -wire sprite_vflip = sprite_attrib4[6] ^ ~flipscreen; - -//Sprite code is sprite attribute byte 0 sandwiched between bits 1 and 0 and bits 3 and 2 of sprite attribute byte 1 -wire [11:0] sprite_code = {sprite_attrib1[1:0], sprite_attrib0, sprite_attrib1[3:2]}; - -//Sprite color is the upper 4 bits of sprite attribute byte 1 -wire [3:0] sprite_color = sprite_attrib1[7:4]; - -//The 005885 supports 5 different sprite sizes: 8x8, 8x16, 16x8, 16x16 and 32x32. Retrieve this attribute from bits [4:2] of -//sprite attribute byte 4 -wire [2:0] sprite_size = sprite_attrib4[4:2]; - //Adjust sprite code based on sprite size wire [11:0] sprite_code_sized = sprite_size == 3'b000 ? {sprite_code[11:2], ly[3], lx[3]}: //16x16 sprite_size == 3'b001 ? {sprite_code[11:1], lx[3]}: //16x8 @@ -780,6 +869,7 @@ reg sprite_bank = 0; reg old_vsync; //Normally, the 005885 latches the sprite bank from bit 3 of the tile control register on the rising edge of VSync, though this causes //jerky scrolling with sprites for bootleg Jackal ROM sets - bypass this latch if such ROM sets are loaded +//Finalizer - Super Transformation only reads sprite information from the lower sprite bank always_ff @(posedge CK49) begin old_vsync <= NVSY; if(!NEXR) @@ -837,7 +927,7 @@ reg [9:0] radr0 = 10'd0; reg [9:0] radr1 = 10'd1; always_ff @(posedge CK49) begin if(cen_6m) - radr0 <= {sprite_lbuff_bank, flipscreen ? sprite_hpos - 9'd225 : sprite_hpos}; + radr0 <= {sprite_lbuff_bank, flipscreen ? sprite_hpos - 9'd225 : tile_ctrl[2] ? sprite_hpos - 9'd40 : sprite_hpos}; end //Sprite line buffer diff --git a/Arcade_MiST/Konami TimePilot84/rtl/TimePilot84_CPU.sv b/Arcade_MiST/Konami TimePilot84/rtl/TimePilot84_CPU.sv index 4c397bdf..f5b30bf7 100644 --- a/Arcade_MiST/Konami TimePilot84/rtl/TimePilot84_CPU.sv +++ b/Arcade_MiST/Konami TimePilot84/rtl/TimePilot84_CPU.sv @@ -140,11 +140,12 @@ end //Konami 082 custom chip - responsible for all video timings wire vblk, h1, h2, h4, h8, h16, h32, h64, h128, n_h256, v1, v2, v4, v8, v16, v32, v64, v128; -wire h1_en, h2_en, h4_en, h8_en, h16_en, h32_en, h64_en, h128_en, n_h256_en; +wire n_h256_en; k082 u6A ( + .reset(1'b1), .clk(clk_49m), - .clk_en(pixel_clk_en), + .cen(pixel_clk_en), .n_vsync(video_vsync), .sync(video_csync), .n_hsync(video_hsync), @@ -160,15 +161,6 @@ k082 u6A .h64(h64), .h128(h128), .n_h256(n_h256), - - .h1_en(h1_en), - .h2_en(h2_en), - .h4_en(h4_en), - .h8_en(h8_en), - .h16_en(h16_en), - .h32_en(h32_en), - .h64_en(h64_en), - .h128_en(h128_en), .n_h256_en(n_h256_en), .v1(v1), diff --git a/Arcade_MiST/Konami TimePilot84/rtl/custom/k082.sv b/Arcade_MiST/Konami TimePilot84/rtl/custom/k082.sv index 169a8ad8..caf95491 100644 --- a/Arcade_MiST/Konami TimePilot84/rtl/custom/k082.sv +++ b/Arcade_MiST/Konami TimePilot84/rtl/custom/k082.sv @@ -2,7 +2,7 @@ // // SystemVerilog implementation of the Konami 082 custom chip, used by // several Konami arcade PCBs to generate video timings -// Copyright (C) 2020 Ace +// Copyright (C) 2020, 2021 Ace // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), @@ -27,7 +27,7 @@ //Chip pinout: /* _____________ _| |_ -VCC |_|1 28|_| VCC +reset |_|1 28|_| VCC _| |_ h1 |_|2 27|_| GND _| |_ @@ -56,60 +56,94 @@ clk |_|13 16|_| vblk GND |_|14 15|_| n_vblk |_____________| -Note: Pins 1, 12 and 27 may control other features of the 082 - these, if any, have not +Note: Pins 12 and 27 may control other features of the 082 - these, if any, have not been modelled yet. */ module k082 ( - input clk, - input clk_en, - output n_vsync, sync, - output n_hsync, //Not exposed on the original chip - output reg vblk = 1, - output n_vblk, - output h1, h2, h4, h8, h16, h32, h64, h128, h256, n_h256, - output v1, v2, v4, v8, v16, v32, v64, v128, - output h1_en, h2_en, h4_en, h8_en, h16_en, h32_en, h64_en, h128_en, h256_en, n_h256_en + input reset, //Active low + input clk, + input cen, //Set to 1 if using this code to replace a real 082 + input [3:0] h_center, v_center, //These inputs are additions for screen centering and don't exist on the actual 082 + output n_vsync, sync, + output n_hsync, //Not exposed on the original chip + output reg vblk = 1, + output n_vblk, + output reg vblk_irq_en = 0, //This is an extra output not present on the real 082 to signal when to + //trigger a VBlank IRQ (signal is active high) + output h1, h2, h4, h8, h16, h32, h64, h128, h256, n_h256, n_h256_en, + output v1, v2, v4, v8, v16, v32, v64, v128 ); +//The horizontal and vertical counters are 9 bits wide - delcare them here reg [8:0] h_cnt = 9'd0; reg [8:0] v_cnt = 9'd0; -always_ff @(posedge clk) if (clk_en) begin - h_cnt <= h_cnt + 9'd1; - case(h_cnt) - 48: begin - v_cnt <= v_cnt + 9'd1; - end - 176: begin - case(v_cnt) - 16: begin - vblk <= 0; - v_cnt <= v_cnt + 9'd1; - end - 271: begin - vblk <= 0; - v_cnt <= v_cnt + 9'd1; - end - 495: begin - vblk <= 1; - v_cnt <= v_cnt + 9'd1; - end - 511: v_cnt <= 9'd248; - default: v_cnt <= v_cnt + 9'd1; - endcase - end - 511: h_cnt <= 9'd128; - default: ; - endcase +//Define the range of values the vertical counter will count between based on the additional vertical center signal +//Shift the screen up by 1 line when horizontal centering shifts the screen left +wire [8:0] vcnt_start = 9'd248 - v_center; +wire [8:0] vcnt_end = 9'd511 - v_center; + +//The horizontal and vertical counters behave as follows at every rising edge of the pixel clock: +//-Start at 0, then count to 511 (both counters increment by 1 when the horizontal counter is set to 48) +//-Horizontal counter resets to 128 for a total of 383 horizontal lines +//-Vertical counter resets to 248 for a total of 263 vertical lines (adjustable with added vertical center signal) +//-Vertical counter increments when the horizontal counter equals 176 +//-VBlank is active when the horizontal counter is between 495 - 511 and 248 - 270 +//Model this behavior here +always_ff @(posedge clk or negedge reset) begin + if(!reset) begin + h_cnt <= 9'd0; + v_cnt <= 9'd0; + end + else if(cen) begin + case(h_cnt) + 48: begin + v_cnt <= v_cnt + 9'd1; + h_cnt <= h_cnt + 9'd1; + end + 176: begin + h_cnt <= h_cnt + 9'd1; + case(v_cnt) + 16: begin + vblk <= 0; + v_cnt <= v_cnt + 9'd1; + end + 271: begin + vblk <= 0; + v_cnt <= v_cnt + 9'd1; + end + 495: begin + vblk <= 1; + vblk_irq_en <= 1; + v_cnt <= v_cnt + 9'd1; + end + vcnt_end: v_cnt <= vcnt_start; + default: v_cnt <= v_cnt + 9'd1; + endcase + end + 177: begin + vblk_irq_en <= 0; + h_cnt <= h_cnt + 9'd1; + end + 511: h_cnt <= 9'd128; + default: h_cnt <= h_cnt + 9'd1; + endcase + end end +//The Konami 082 has both an active low VBlank and an active high VBlank - generate the active low VBlank by inverting +//the active high VBlank generated in the previous sequential block assign n_vblk = ~vblk; -assign n_hsync = ~(h_cnt > 175 && h_cnt < 208); -assign n_vsync = v_cnt[8]; + +//Generate active low HSync, VSync and composite sync +assign n_hsync = h_center[3] ? ~(h_cnt > (182 - h_center[2:0]) && h_cnt < (215 - h_center[2:0])): + ~(h_cnt > (175 - h_center[2:0]) && h_cnt < (208 - h_center[2:0])); +assign n_vsync = h_center[3] ? ~(v_cnt >= vcnt_start + 9'd1 && v_cnt <= vcnt_start + 9'd9) : ~(v_cnt >= vcnt_start && v_cnt <= vcnt_start + 9'd8); assign sync = n_hsync ^ n_vsync; +//Assign the individual horizontal counter bits to their respective outputs (also invert bit 8 of the horizontal counter for H256) assign h1 = h_cnt[0]; assign h2 = h_cnt[1]; assign h4 = h_cnt[2]; @@ -120,18 +154,9 @@ assign h64 = h_cnt[6]; assign h128 = h_cnt[7]; assign h256 = ~h_cnt[8]; assign n_h256 = h_cnt[8]; - -assign h1_en = !h_cnt[0]; -assign h2_en = h_cnt[1:0] == 2'b01; -assign h4_en = h_cnt[2:0] == 3'b011; -assign h8_en = h_cnt[3:0] == 4'b0111; -assign h16_en = h_cnt[4:0] == 5'b01111; -assign h32_en = h_cnt[5:0] == 6'b011111; -assign h64_en = h_cnt[6:0] == 7'b0111111; -assign h128_en = h_cnt[7:0] == 8'b01111111; -assign h256_en = h_cnt[8:0] == 9'b111111111; assign n_h256_en = h_cnt[8:0] == 9'b011111111; +//Assign the individual vertical counter bits to their respective outputs assign v1 = v_cnt[0]; assign v2 = v_cnt[1]; assign v4 = v_cnt[2];