1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-02-18 21:36:55 +00:00

Delete garbage

This commit is contained in:
Gyorgy Szombathelyi
2023-04-06 02:00:32 +02:00
parent e868013e34
commit 9eae085e83

View File

@@ -1,911 +0,0 @@
//============================================================================
//
// SystemVerilog implementation of the Konami 005885 custom tilemap
// generator
// Graphics logic based on the video section of the Green Beret core for
// MiSTer by MiSTer-X
// 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"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
//============================================================================
//Note: This model of the 005885 cannot be used as-is to replace an original 005885.
module k005885
(
input CK49, //49.152MHz clock input
output NCK2, //6.144MHz clock output
output H1O, //3.072MHz clock output
output NCPE, //E clock for MC6809E
output NCPQ, //Q clock for MC6809E
output NEQ, //AND of E and Q clocks for MC6809E
input NRD, //Read enable (active low)
output NRES, //Reset passthrough
input [13:0] A, //Address bus from CPU
input [7:0] DBi, //Data bus input from CPU
output [7:0] DBo, //Data output to CPU
output [3:0] VCF, //Color address to tilemap LUT PROM
output [3:0] VCB, //Tile index to tilemap LUT PROM
input [3:0] VCD, //Data input from tilemap LUT PROM
output [3:0] OCF, //Color address to sprite LUT PROM
output [3:0] OCB, //Sprite index to sprite LUT PROM
input [3:0] OCD, //Data input from sprite LUT PROM
output [4:0] COL, //Color data output from color mixer
input NEXR, //Reset input (active low)
input NXCS, //Chip select (active low)
output NCSY, //Composite sync (active low)
output NHSY, //HSync (active low) - Not exposed on the original chip
output NVSY, //VSync (active low)
output HBLK, //HBlank (active high) - Not exposed on the original chip
output VBLK, //VBlank (active high) - Not exposed on the original chip
input NBUE, //Unknown
output NFIR, //Fast IRQ (FIRQ) output for MC6809E
output NIRQ, //IRQ output for MC6809E (VBlank IRQ)
output NNMI, //Non-maskable IRQ (NMI) for MC6809E
output NIOC, //Inverse of address line A11 for external address decoding logic
output NRMW,
//Split I/O for tile and sprite data
output [15:0] R, //Address output to graphics ROMs (tiles)
input [7:0] RDU, //Upper 8 bits of graphics ROM data (tiles)
input [7:0] RDL, //Lower 8 bits of graphics ROM data (tiles)
output [15:0] S, //Address output to graphics ROMs (sprites)
input [7:0] SDU, //Upper 8 bits of graphics ROM data (sprites)
input [7:0] SDL, //Lower 8 bits of graphics ROM data (sprites)
//Extra inputs for screen centering (alters HSync and VSync timing to reposition the video output)
input [3:0] HCTR, VCTR,
//Special flag for reconfiguring the chip to mimic the anomalies found on bootlegs of games that use the 005885
//Valid values:
//-00: Original behavior
//-01: Jackal bootleg (faster video timings, missing 4 lines from the video signal, misplaced HBlank, altered screen
// centering, sprite layer is missing one line per sprite, sprite layer is misplaced by one line when the screen is
// flipped)
//-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
//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
);
//------------------------------------------------------- Signal outputs -------------------------------------------------------//
//Reset line passthrough
assign NRES = NEXR;
//Generate NIOC output (active low)
assign NIOC = ~(~NXCS & (A[13:11] == 3'b001));
//TODO: The timing of the NRMW output is currently unknown - set to 1 for now
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];
//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:
(spriteram_cs & ~NRD) ? spriteram_Dout:
8'hFF;
//------------------------------------------------------- Clock division -------------------------------------------------------//
//Divide the incoming 49.152MHz clock to 6.144MHz and 3.072MHz
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];
//The MC6809E requires two identical clocks with a 90-degree offset - assign these here
reg mc6809e_E = 0;
reg mc6809e_Q = 0;
always_ff @(posedge CK49) begin
reg [1:0] clk_phase = 0;
if(cen_6m) begin
clk_phase <= clk_phase + 1'd1;
case(clk_phase)
2'b00: mc6809e_E <= 0;
2'b01: mc6809e_Q <= 1;
2'b10: mc6809e_E <= 1;
2'b11: mc6809e_Q <= 0;
endcase
end
end
assign NCPQ = mc6809e_Q;
assign NCPE = mc6809e_E;
//Output NEQ combines NCPE and NCPQ together via an AND gate - assign this here
assign NEQ = NCPE & NCPQ;
//-------------------------------------------------------- Video timings -------------------------------------------------------//
//The 005885's video output has 384 horziontal lines and 262 vertical lines with an active resolution of 240x224. Declare both
//counters as 9-bit registers.
reg [8:0] h_cnt = 9'd0;
reg [8:0] v_cnt = 9'd0;
//Increment horizontal counter on every falling edge of the pixel clock and increment vertical counter when horizontal counter
//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
reg [8:0] vcnt_end = 0;
always_ff @(posedge CK49) begin
if(cen_6m) begin
if(BTLG == 2'b01)
vcnt_end <= 9'd252;
else if(BTLG == 2'b10)
vcnt_end <= 9'd271;
else
vcnt_end <= 9'd261;
end
end
//Reposition HSync and VSync if a bootleg Iron Horse or Jackal ROM set is loaded
reg [8:0] hsync_start = 9'd0;
reg [8:0] hsync_end = 9'd0;
reg [8:0] vsync_start = 9'd0;
reg [8:0] vsync_end = 9'd0;
always_ff @(posedge CK49) begin
if(BTLG == 2'b01) begin
hsync_start <= HCTR[3] ? 9'd287 : 9'd295;
hsync_end <= HCTR[3] ? 9'd318 : 9'd326;
vsync_start <= 9'd244;
vsync_end <= 9'd251;
end
else if(BTLG == 2'b10) begin
hsync_start <= HCTR[3] ? 9'd290 : 9'd310;
hsync_end <= HCTR[3] ? 9'd321 : 9'd341;
vsync_start <= 9'd255;
vsync_end <= 9'd262;
end
else begin
hsync_start <= HCTR[3] ? 9'd288 : 9'd296;
hsync_end <= HCTR[3] ? 9'd319 : 9'd327;
vsync_start <= 9'd254;
vsync_end <= 9'd261;
end
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
if(BTLG == 2'b01)
hblank <= 0;
h_cnt <= h_cnt + 9'd1;
end
13: 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)
hblank <= 1;
h_cnt <= h_cnt + 9'd1;
end
253: begin
if(BTLG != 2'b01)
hblank <= 1;
h_cnt <= h_cnt + 9'd1;
end
383: begin
h_cnt <= 0;
case(v_cnt)
15: begin
vblank <= 0;
v_cnt <= v_cnt + 9'd1;
end
239: begin
vblank <= 1;
vblank_irq_en <= 1;
frame_odd_even <= ~frame_odd_even;
v_cnt <= v_cnt + 9'd1;
end
vcnt_end: begin
v_cnt <= 9'd0;
end
default: v_cnt <= v_cnt + 9'd1;
endcase
end
default: h_cnt <= h_cnt + 9'd1;
endcase
end
end
//Output HBlank and VBlank (both active high)
assign HBLK = hblank;
assign VBLK = vblank;
//Generate horizontal sync and vertical sync (both active low)
assign NHSY = HCTR[3] ? ~(h_cnt >= hsync_start - ~HCTR[2:0] && h_cnt <= hsync_end - ~HCTR[2:0]):
~(h_cnt >= hsync_start + HCTR[2:0] && h_cnt <= hsync_end + HCTR[2:0]);
assign NVSY = ~(v_cnt >= vsync_start - VCTR && v_cnt <= vsync_end - VCTR);
assign NCSY = NHSY ^ NVSY;
//------------------------------------------------------------- IRQs -----------------------------------------------------------//
//IRQ (triggers every VBlank)
reg vblank_irq = 1;
always_ff @(posedge CK49 or negedge NEXR) begin
if(!NEXR)
vblank_irq <= 1;
else if(cen_6m) begin
if(!irq_mask)
vblank_irq <= 1;
else if(vblank_irq_en)
vblank_irq <= 0;
end
end
assign NIRQ = vblank_irq;
//NMI (triggers every 64 scanlines starting from scanline 48)
reg nmi = 1;
always_ff @(posedge CK49 or negedge NEXR) begin
if(!NEXR)
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;
end
end
assign NNMI = nmi;
//FIRQ (triggers every second VBlank)
reg firq = 1;
always_ff @(posedge CK49 or negedge NEXR) begin
if(!NEXR)
firq <= 1;
else if(cen_3m) begin
if(!firq_mask)
firq <= 1;
else if(!frame_odd_even && v_cnt == 9'd239)
firq <= 0;
end
end
assign NFIR = firq;
//----------------------------------------------------- Internal registers -----------------------------------------------------//
//The 005885 has five 8-bit registers set up as follows according to information in konamiic.txt found in MAME's source code:
/*
control registers
000: scroll y
001: scroll x (low 8 bits)
002: -------x scroll x (high bit)
----xxx- row/colscroll control
000 = solid scroll (finalizr, ddribble bg)
100 = solid scroll (jackal)
001 = ? (ddribble fg)
011 = colscroll (jackal high scores)
101 = rowscroll (ironhors, jackal map)
003: ------xx high bits of the tile code
-----x-- unknown (finalizr)
----x--- selects sprite buffer (and makes a copy to a private buffer?)
--x----- unknown (ironhors)
-x------ unknown (ironhors)
x------- unknown (ironhors, jackal)
004: -------x nmi enable
------x- irq enable
-----x-- firq enable
----x--- flip screen
*/
wire regs_cs = ~NXCS & (A[13:11] == 2'b00) & (A[6:3] == 4'd0);
reg [7:0] scroll_y, scroll_x, scroll_ctrl, tile_ctrl;
reg nmi_mask = 0;
reg irq_mask = 0;
reg firq_mask = 0;
reg flipscreen = 0;
//Write to the appropriate register
always_ff @(posedge CK49) begin
if(cen_3m) begin
if(regs_cs && NRD)
case(A[2:0])
3'b000: scroll_y <= DBi;
3'b001: scroll_x <= DBi;
3'b010: scroll_ctrl <= DBi;
3'b011: tile_ctrl <= DBi;
3'b100: begin
nmi_mask <= DBi[0];
irq_mask <= DBi[1];
firq_mask <= DBi[2];
flipscreen <= DBi[3];
end
default;
endcase
end
end
//--------------------------------------------------------- Unknown RAM --------------------------------------------------------//
wire ram_cs = ~NXCS & (A >= 14'h0005 && A <= 14'h001F);
wire [7:0] ram_Dout;
spram #(8, 5) RAM
(
.clk(CK49),
.we(ram_cs & NRD),
.addr(A[4:0]),
.data(DBi),
.q(ram_Dout)
);
//-------------------------------------------------------- Internal ZRAM -------------------------------------------------------//
wire zram0_cs = ~NXCS & (A >= 16'h0020 && A <= 16'h003F);
wire zram1_cs = ~NXCS & (A >= 16'h0040 && A <= 16'h005F);
wire zram2_cs = ~NXCS & (A >= 16'h0060 && A <= 16'h00DF);
//The 005885 addresses ZRAM with either horizontal or vertical position bits depending on whether its scroll mode is set to
//line scroll or column scroll - use vertical position bits for line scroll and horizontal position bits for column scroll,
//otherwise don't address it
wire [4:0] zram_A = (scroll_ctrl[3:1] == 3'b101) ? tilemap_vpos[7:3]:
(scroll_ctrl[3:1] == 3'b011) ? tilemap_hpos[7:3]:
5'h00;
wire [7:0] zram0_D, zram1_D, zram2_D, zram0_Dout, zram1_Dout, zram2_Dout;
dpram_dc #(.widthad_a(5)) ZRAM0
(
.clock_a(CK49),
.address_a(A[4:0]),
.data_a(DBi),
.q_a(zram0_Dout),
.wren_a(zram0_cs & NRD),
.clock_b(CK49),
.address_b(zram_A),
.q_b(zram0_D)
);
spram #(8, 5) ZRAM1
(
.clk(CK49),
.we(zram1_cs & NRD),
.addr(A[4:0]),
.data(DBi),
.q(zram1_Dout)
);
spram #(8, 5) ZRAM2
(
.clk(CK49),
.we(zram2_cs & NRD),
.addr(A[4:0]),
.data(DBi),
.q(zram2_Dout)
);
//------------------------------------------------------------ VRAM ------------------------------------------------------------//
//VRAM is external to the 005885 and combines multiple banks into a single 8KB RAM chip for tile attributes and data (two layers),
//and two sprite banks. For simplicity, this RAM has been made internal to the 005885 implementation and split into its
//constituent components.
wire tile_attrib_cs = ~NXCS & (A[13:10] == 4'b1000);
wire tile_cs = ~NXCS & (A[13:10] == 4'b1001);
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;
//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),
.wren_a(tile_attrib_cs & NRD),
.clock_b(CK49),
.address_b(vram_A),
.q_b(tileram_attrib_D)
);
dpram_dc #(.widthad_a(10)) VRAM_TILECODE0
(
.clock_a(CK49),
.address_a(A[9:0]),
.data_a(DBi),
.q_a(tileram_Dout),
.wren_a(tile_cs & NRD),
.clock_b(CK49),
.address_b(vram_A),
.q_b(tileram_D)
);
//Tilemap layer 1
dpram_dc #(.widthad_a(10)) VRAM_TILEATTRIB1
(
.clock_a(CK49),
.address_a(A[9:0]),
.data_a(DBi),
.q_a(tileram1_attrib_Dout),
.wren_a(tile1_attrib_cs & NRD),
.clock_b(CK49),
.address_b(vram_A),
.q_b(tileram1_attrib_D)
);
dpram_dc #(.widthad_a(10)) VRAM_TILECODE1
(
.clock_a(CK49),
.address_a(A[9:0]),
.data_a(DBi),
.q_a(tileram1_Dout),
.wren_a(tile1_cs & NRD),
.clock_b(CK49),
.address_b(vram_A),
.q_b(tileram1_D)
);
// 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;
//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),
.wren_a(VRAM_SPR_WE),
.clock_b(~CK49),
.address_b(spriteram_A),
.q_b(spriteram_D)
);
//-------------------------------------------------------- Tilemap layer -------------------------------------------------------//
//TODO: The current implementation only handles one of the 005885's two tilemap layers - add logic to handle both layers
//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};
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 [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};
//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)};
//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
reg [15:0] RD_lat = 16'd0;
reg [3:0] tile_color = 4'd0;
reg tile_hflip_lat = 0;
reg old_tilehpos1;
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];
end
end
//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
end
//Address output to tilemap LUT PROM
assign VCF = tile_color;
assign VCB = tile_pixel;
//Shift the tilemap layer left by two lines when the screen is flipped
reg [7:0] tilemap_shift;
always_ff @(posedge CK49) begin
if(cen_6m)
tilemap_shift <= {VCD, tilemap_shift[7:4]};
end
wire [3:0] tilemap_D = flipscreen ? tilemap_shift[3:0] : VCD;
//-------------------------------------------------------- Sprite layer --------------------------------------------------------//
//The following code is an adaptation of the sprite renderer from MiSTer-X's Green Beret core tweaked for the 005885's sprite format
reg [8:0] sprite_hpos = 9'd0;
reg [8:0] sprite_vpos = 9'd0;
always_ff @(posedge CK49) begin
if(cen_6m) begin
sprite_hpos <= h_cnt;
//If a bootleg Iron Horse ROM set is loaded, apply a vertical offset of 65 lines (66 when flipped) to recreate the
//bootleg hardware's 1-line downward vertical offset between the sprite and tilemap layers, otherwise apply a
//vertical offset of 66 lines (65 lines when flipped)
if(BTLG == 2'b10)
if(flipscreen)
sprite_vpos <= v_cnt + 9'd66;
else
sprite_vpos <= v_cnt + 9'd65;
else
if(flipscreen)
sprite_vpos <= v_cnt + 9'd65;
else
sprite_vpos <= v_cnt + 9'd66;
end
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 [5:0] sprite_width;
reg [15:0] sprite_rom_addr;
//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] waitstate;
always_ff @(posedge CK49) begin
//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
sprite_width <= 0;
sprite_index <= 0;
sprite_offset <= 3'd4;
sprite_fsm_state <= 1;
waitstate <= 0;
end
else
case(sprite_fsm_state)
0: /* empty */ ;
1: begin
waitstate <= 0;
if(sprite_index > sprite_limit)
sprite_fsm_state <= 0;
else begin
sprite_attrib4 <= spriteram_D;
sprite_offset <= 3'd3;
sprite_fsm_state <= sprite_fsm_state + 3'd1;
end
end
2: begin
sprite_attrib3 <= spriteram_D;
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
if(sprite_active) begin
sprite_attrib2 <= spriteram_D;
sprite_offset <= 3'd1;
sprite_fsm_state <= sprite_fsm_state + 3'd1;
end
else begin
sprite_index <= sprite_index + 9'd5;
sprite_offset <= 3'd4;
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;
sprite_offset <= 3'd4;
sprite_index <= sprite_index + 9'd5;
case(sprite_size)
3'b000: sprite_width <= 6'b110000 + (BTLG == 2'b01 && flipscreen);
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;
waitstate <= 4'd14;
end
6: if (waitstate == 0) begin
//Skip the last line of a sprite if a bootleg Jackal ROM set is loaded (the hardware on such bootlegs fails
//to render the last line of sprites), otherwise write sprites as normal
if(BTLG == 2'b01 && !flipscreen)
if(sprite_width == 6'b111110)
sprite_width <= sprite_width + 6'd2;
else
sprite_width <= sprite_width + 6'd1;
else
sprite_width <= sprite_width + 6'd1;
if (sprite_width[1:0] == 2'b11) waitstate <= 4'd14;
sprite_fsm_state <= wre ? sprite_fsm_state : 3'd1;
end
else begin
sprite_rom_addr <= {sprite_code_sized, ly[2:0], lx[2]};
waitstate <= waitstate - 1'd1;
end
default:;
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_fsm_state == 5 ? spriteram_D : 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
sprite_size == 3'b010 ? {sprite_code[11:2], ly[3], sprite_code[0]}: //8x16
sprite_size == 3'b011 ? sprite_code: //8x8
{sprite_code[11:2] + {ly[4], lx[4]}, ly[3], lx[3]}; //32x32
//Subtract vertical sprite position from sprite Y parameter to obtain sprite height
wire [8:0] sprite_height = {(sprite_y[7:4] == 4'hF), sprite_y ^ {8{flipscreen}}} - sprite_vpos;
//Set when a sprite is active depending on whether it is 8, 16 or 32 pixels tall
reg sprite_active;
always @(*) begin
case(sprite_size)
3'b000: sprite_active = (sprite_height[8:7] == 2'b11) & (sprite_height[6] ^ ~flipscreen) & (sprite_height[5] ^ flipscreen)
& (sprite_height[4] ^ flipscreen);
3'b001: sprite_active = (sprite_height[8:7] == 2'b11) & (sprite_height[6] ^ ~flipscreen) & (sprite_height[5] ^ flipscreen)
& (sprite_height[4] ^ flipscreen) & (sprite_height[3] ^ flipscreen);
3'b010: sprite_active = (sprite_height[8:7] == 2'b11) & (sprite_height[6] ^ ~flipscreen) & (sprite_height[5] ^ flipscreen)
& (sprite_height[4] ^ flipscreen);
3'b011: sprite_active = (sprite_height[8:7] == 2'b11) & (sprite_height[6] ^ ~flipscreen) & (sprite_height[5] ^ flipscreen)
& (sprite_height[4] ^ flipscreen) & (sprite_height[3] ^ flipscreen);
3'b100: sprite_active = (sprite_height[8:7] == 2'b11) & (sprite_height[6] ^ ~flipscreen) & (sprite_height[5] ^ flipscreen);
default: sprite_active = (sprite_height[8:7] == 2'b11) & (sprite_height[6] ^ ~flipscreen) & (sprite_height[5] ^ flipscreen);
endcase
end
wire [4:0] lx = sprite_width[4:0] ^ {5{sprite_hflip}};
wire [4:0] ly = sprite_height[4:0] ^ {5{sprite_vflip}};
//Assign address outputs to sprite ROMs
assign S = sprite_rom_addr;
//Multiplex sprite ROM data down from 16 bits to 8 using bit 1 of the horizontal position
wire [7:0] SD = lx[1] ? SDL : SDU;
//Further multiplex sprite ROM data down from 8 bits to 4 using bit 0 of the horizontal position
wire [3:0] sprite_pixel = lx[0] ? SD[3:0] : SD[7:4];
//Sum the sprite index with the sprite offset and address sprite RAM with it along with tile control register bit 3
wire [8:0] sprite_address = (sprite_index + sprite_offset);
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
always_ff @(posedge CK49) begin
old_vsync <= NVSY;
if(!NEXR)
sprite_bank <= 0;
else if(!old_vsync && NVSY)
sprite_bank <= tile_ctrl[3];
end
wire [11:0] spriteram_A = {(BTLG == 2'b01) ? tile_ctrl[3] : sprite_bank, 2'b00, sprite_address};
//Address output to sprite LUT PROM
assign OCF = sprite_color;
assign OCB = sprite_pixel;
//----------------------------------------------------- Sprite line buffer -----------------------------------------------------//
//The sprite line buffer is external to the 005885 and consists of two 4464 DRAM chips. For simplicity, both the logic for the
//sprite line buffer and the sprite line buffer itself are internal to the 005885 implementation.
//Enable writing to sprite line buffer when bit 5 of the sprite width is 1
wire wre = sprite_width[5];
//Set sprite line buffer bank as bit 0 of the sprite vertical position
wire sprite_lbuff_bank = sprite_vpos[0];
//Sum sprite X position with the following bits of the sprite width to address the sprite line buffer based on sprite size:
//32 pixels wide: bits [4:0]
//16 pixels wide: bits [3:0]
//8 pixels wide: bits [2:0]
//XOR the upper bits for screen flipping on 16 pixel and 8 pixel wide sprites
reg [4:0] final_sprite_width;
always @(*) begin
case(sprite_size)
3'b000: final_sprite_width <= {sprite_width[4] ^ ~flipscreen, sprite_width[3:0]};
3'b001: final_sprite_width <= {sprite_width[4] ^ ~flipscreen, sprite_width[3:0]};
3'b010: final_sprite_width <= {sprite_width[4:3] ^ {2{~flipscreen}}, sprite_width[2:0]};
3'b011: final_sprite_width <= {sprite_width[4:3] ^ {2{~flipscreen}}, sprite_width[2:0]};
3'b100: final_sprite_width <= sprite_width[4:0];
default: final_sprite_width <= sprite_width[4:0];
endcase
end
wire [8:0] wpx = sprite_x + final_sprite_width;
//Generate sprite line buffer write addresses
reg [9:0] lbuff_A;
reg lbuff_we;
always_ff @(posedge CK49) begin
lbuff_A <= {~sprite_lbuff_bank, wpx};
lbuff_we <= wre & (waitstate == 0);
//lbuff_Din <= OCD;
end
//Latch sprite LUT PROM data on the falling edge of the main clock
wire [3:0] lbuff_Din = OCD;
//always_ff @(negedge CK49) begin
// lbuff_Din <= OCD;
//end
//Generate read address for sprite line buffer on the rising edge of the pixel clock (apply a -225 offset when the screen
//is flipped)
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};
end
//Sprite line buffer
wire [3:0] lbuff_Dout;
dpram_dc #(.widthad_a(10)) LBUFF
(
.clock_a(CK49),
.address_a(lbuff_A),
.data_a({4'd0, lbuff_Din}),
.wren_a(lbuff_we & (lbuff_Din != 0)),
.clock_b(CK49),
.address_b(radr0),
.data_b(8'h0),
.wren_b(radr0 == radr1),
.q_b({4'bZZZZ, lbuff_Dout})
);
//Latch sprite data from the sprite line buffer
wire lbuff_read_en = (div[2:0] == 3'b100);
reg [3:0] lbuff_read = 4'd0;
always_ff @(posedge CK49) begin
if(lbuff_read_en) begin
if(radr0 != radr1)
lbuff_read <= lbuff_Dout;
radr1 <= radr0;
end
end
//Delay sprite layer by 2 horizontal lines (1 line if a bootleg Jackal ROM set is loaded and the screen is flipped)
reg [7:0] sprite_dly = 8'd0;
always_ff @(posedge CK49) begin
if(cen_6m) begin
if(BTLG == 2'b01 && flipscreen)
sprite_dly <= {4'd0, lbuff_read};
else
sprite_dly <= {lbuff_read, sprite_dly[7:4]};
end
end
//Jackal bootlegs fail to render the last two vertical lines of the sprite layer - model this behavior here
wire [3:0] sprite_D = (BTLG == 2'b01 && ((h_cnt >= 244 && ~flipscreen) || (h_cnt >= 248 && flipscreen))) ? 4'd0 : sprite_dly[3:0];
//--------------------------------------------------------- Color mixer --------------------------------------------------------//
//Multiplex tile and sprite data, then output the final result
wire tile_sprite_sel = (tilemap_en | ~(|sprite_D));
wire [3:0] tile_sprite_D = tile_sprite_sel ? tilemap_D : sprite_D;
//Latch and output pixel data
reg [4:0] pixel_D;
always_ff @(posedge CK49) begin
if(cen_6m)
pixel_D <= {tile_sprite_sel, tile_sprite_D};
end
assign COL = (BTLG == 2'b01 && ((h_cnt >= 247 && ~flipscreen) || (h_cnt <= 14 && flipscreen))) ||
(BTLG == 2'b10 && ((h_cnt <= 20 && ~flipscreen) || ((h_cnt <= 18 || h_cnt >= 251) && flipscreen))) ? 5'd0 : pixel_D;
//The above condition blacks out the last 4 lines on the right side of the screen (left when flipped) when a bootleg Jackal ROM set
//is loaded and blacks out the left-most 8 lines (7 when flipped plus an extra 2 lines on the right side) when a bootleg Iron Horse
//ROM set is loaded - this simulates the earlier-than-normal start of HBlank for Jackal bootlegs and later-than-normal end of
//HBlank for Iron Horse bootlegs while maintaining the usual 240x224 display area
endmodule