1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-04-14 07:29:37 +00:00

Konami custom chip unifications

This commit is contained in:
Gyorgy Szombathelyi
2022-01-02 21:45:05 +01:00
parent 4eea204e63
commit 6084ab1c56
7 changed files with 342 additions and 4397 deletions

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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

View File

@@ -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),

View File

@@ -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];