1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-01-13 15:17:55 +00:00
2020-12-20 16:31:04 +01:00

388 lines
11 KiB
Systemverilog

//============================================================================
// Arcade: Spy Hunter by DarFPGA
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//============================================================================
module SpyHunter_MiST(
output LED,
output [5:0] VGA_R,
output [5:0] VGA_G,
output [5:0] VGA_B,
output VGA_HS,
output VGA_VS,
output AUDIO_L,
output AUDIO_R,
input SPI_SCK,
inout SPI_DO,
input SPI_DI,
input SPI_SS2,
input SPI_SS3,
input SPI_SS4,
input CONF_DATA0,
input CLOCK_27,
output [12:0] SDRAM_A,
inout [15:0] SDRAM_DQ,
output SDRAM_DQML,
output SDRAM_DQMH,
output SDRAM_nWE,
output SDRAM_nCAS,
output SDRAM_nRAS,
output SDRAM_nCS,
output [1:0] SDRAM_BA,
output SDRAM_CLK,
output SDRAM_CKE
);
`include "rtl/build_id.v"
localparam CONF_STR = {
"SPYHUNT;;",
"O2,Rotate Controls,Off,On;",
"O5,Blend,Off,On;",
"O6,Service,Off,On;",
"O8,Demo Sounds,Off,On;",
"O9,Show Lamps,Off,On;",
"R2048,Save NVRAM;",
"T0,Reset;",
"V,v1.1.",`BUILD_DATE
};
wire rotate = status[2];
wire blend = status[5];
wire service = status[6];
wire demosnd = status[8];
wire lamps = status[9];
assign LED = ~ioctl_downl;
assign SDRAM_CLK = clk_mem;
assign SDRAM_CKE = 1;
wire clk_sys, clk_mem;
wire pll_locked;
pll_mist pll(
.inclk0(CLOCK_27),
.areset(0),
.c0(clk_sys),
.c1(clk_mem),
.locked(pll_locked)
);
wire [31:0] status;
wire [1:0] buttons;
wire [1:0] switches;
wire [15:0] joystick_0;
wire [15:0] joystick_1;
wire scandoublerD;
wire ypbpr;
wire no_csync;
wire key_pressed;
wire [7:0] key_code;
wire key_strobe;
user_io #(
.STRLEN(($size(CONF_STR)>>3)),
.ROM_DIRECT_UPLOAD(1'b1))
user_io(
.clk_sys (clk_sys ),
.conf_str (CONF_STR ),
.SPI_CLK (SPI_SCK ),
.SPI_SS_IO (CONF_DATA0 ),
.SPI_MISO (SPI_DO ),
.SPI_MOSI (SPI_DI ),
.buttons (buttons ),
.switches (switches ),
.scandoubler_disable (scandoublerD ),
.ypbpr (ypbpr ),
.no_csync (no_csync ),
.key_strobe (key_strobe ),
.key_pressed (key_pressed ),
.key_code (key_code ),
.joystick_0 (joystick_0 ),
.joystick_1 (joystick_1 ),
.status (status )
);
wire [15:0] rom_addr;
wire [15:0] rom_do;
wire [12:0] snd_addr;
wire [15:0] snd_do;
wire [14:1] csd_addr;
wire [15:0] csd_do;
wire [14:0] sp_addr;
wire [31:0] sp_do;
wire ioctl_downl;
wire ioctl_upl;
wire [7:0] ioctl_index;
wire ioctl_wr;
wire [24:0] ioctl_addr;
wire [7:0] ioctl_dout;
wire [7:0] ioctl_din;
data_io #(
.ROM_DIRECT_UPLOAD(1'b1))
data_io(
.clk_sys ( clk_sys ),
.SPI_SCK ( SPI_SCK ),
.SPI_SS2 ( SPI_SS2 ),
.SPI_SS4 ( SPI_SS4 ),
.SPI_DI ( SPI_DI ),
.SPI_DO ( SPI_DO ),
.ioctl_download( ioctl_downl ),
.ioctl_upload ( ioctl_upl ),
.ioctl_index ( ioctl_index ),
.ioctl_wr ( ioctl_wr ),
.ioctl_addr ( ioctl_addr ),
.ioctl_dout ( ioctl_dout ),
.ioctl_din ( ioctl_din )
);
// ROM structure:
// 0000 - DFFF - Main ROM (8 bit)
// E000 - FFFF - Super Sound board ROM (8 bit)
// 10000 - 17FFF - CSD ROM (16 bit)
// 18000 - 37FFF - Sprite ROMs (32 bit)
// 38000 - 3FFFF - BG
// 40000 - 40FFF - Char
// spy-hunter_cpu_pg0_2-9-84.6d spy-hunter_cpu_pg1_2-9-84.7d spy-hunter_cpu_pg2_2-9-84.8d spy-hunter_cpu_pg3_2-9-84.9d spy-hunter_cpu_pg4_2-9-84.10d spy-hunter_cpu_pg5_2-9-84.11d
// spy-hunter_snd_0_sd_11-18-83.a7 spy-hunter_snd_1_sd_11-18-83.a8
// spy-hunter_cs_deluxe_u17_b_11-18-83.u17 spy-hunter_cs_deluxe_u18_d_11-18-83.u18 spy-hunter_cs_deluxe_u7_a_11-18-83.u7 spy-hunter_cs_deluxe_u8_c_11-18-83.u8
// spy-hunter_video_1fg_11-18-83.a7 spy-hunter_video_0fg_11-18-83.a8 spy-hunter_video_3fg_11-18-83.a5 spy-hunter_video_2fg_11-18-83.a6 spy-hunter_video_5fg_11-18-83.a3 spy-hunter_video_4fg_11-18-83.a4 spy-hunter_video_7fg_11-18-83.a1 spy-hunter_video_6fg_11-18-83.a2
// spy-hunter_cpu_bg0_11-18-83.3a spy-hunter_cpu_bg1_11-18-83.4a spy-hunter_cpu_bg2_11-18-83.5a spy-hunter_cpu_bg3_11-18-83.6a
// spy-hunter_cpu_alpha-n_11-18-83
wire [24:0] rom_ioctl_addr = ~ioctl_addr[16] ? ioctl_addr : // 8 bit ROMs
{ioctl_addr[24:16], ioctl_addr[15], ioctl_addr[13:0], ioctl_addr[14]}; // 16 bit ROM
wire [24:0] sp_ioctl_addr = ioctl_addr - 17'h18000;
reg port1_req, port2_req;
sdram sdram(
.*,
.init_n ( pll_locked ),
.clk ( clk_mem ),
// port1 used for main + sound CPUs
.port1_req ( port1_req ),
.port1_ack ( ),
.port1_a ( rom_ioctl_addr[23:1] ),
.port1_ds ( {rom_ioctl_addr[0], ~rom_ioctl_addr[0]} ),
.port1_we ( ioctl_downl ),
.port1_d ( {ioctl_dout, ioctl_dout} ),
.port1_q ( ),
.cpu1_addr ( ioctl_downl ? 16'hffff : {1'b0, rom_addr[15:1]} ),
.cpu1_q ( rom_do ),
// need higher priority for CSD
.cpu2_addr ( ioctl_downl ? 16'hffff : (16'h8000 + csd_addr[14:1]) ),
.cpu2_q ( csd_do ),
.cpu3_addr ( ioctl_downl ? 16'hffff : (16'h7000 + snd_addr[12:1]) ),
.cpu3_q ( snd_do ),
// port2 for sprite graphics
.port2_req ( port2_req ),
.port2_ack ( ),
.port2_a ( {sp_ioctl_addr[23:17], sp_ioctl_addr[14:0], sp_ioctl_addr[16]} ), // merge sprite roms to 32-bit wide words
.port2_ds ( {sp_ioctl_addr[15], ~sp_ioctl_addr[15]} ),
.port2_we ( ioctl_downl ),
.port2_d ( {ioctl_dout, ioctl_dout} ),
.port2_q ( ),
.sp_addr ( ioctl_downl ? 15'h7fff : sp_addr ),
.sp_q ( sp_do )
);
// ROM download controller
always @(posedge clk_sys) begin
reg ioctl_wr_last = 0;
ioctl_wr_last <= ioctl_wr;
if (ioctl_downl) begin
if (~ioctl_wr_last && ioctl_wr && ioctl_index == 0) begin
port1_req <= ~port1_req;
port2_req <= ~port2_req;
end
end
end
// reset signal generation
reg reset = 1;
reg rom_loaded = 0;
always @(posedge clk_sys) begin
reg ioctl_downlD;
reg [15:0] reset_count;
ioctl_downlD <= ioctl_downl;
// generate a second reset signal - needed for some reason
if (status[0] | buttons[1] | ~rom_loaded) reset_count <= 16'hffff;
else if (reset_count != 0) reset_count <= reset_count - 1'd1;
if (ioctl_downlD & ~ioctl_downl) rom_loaded <= 1;
reset <= status[0] | buttons[1] | ~rom_loaded | (reset_count == 16'h0001);
end
wire [15:0] audio_l, audio_r;
wire [9:0] csd_audio;
wire hs, vs, cs;
wire blankn;
wire [2:0] g, r, b;
spy_hunter_control spy_hunter_control(
.clock_40(clk_sys),
.reset(reset),
.vsync(vs),
.gas_plus(m_up),
.gas_minus(m_down),
.steering_plus(m_right),
.steering_minus(m_left),
.steering(steering),
.gas(gas)
);
spy_hunter spy_hunter(
.clock_40(clk_sys),
.reset(reset),
.video_r(r),
.video_g(g),
.video_b(b),
.video_blankn(blankn),
.video_hs(hs),
.video_vs(vs),
.video_csync(cs),
.tv15Khz_mode(scandoublerD),
.separate_audio(1'b1),
.audio_out_l(audio_l),
.audio_out_r(audio_r),
.csd_audio_out(csd_audio),
.coin1(m_coin1),
.coin2(m_coin2),
.shift(shift_state),
.oil(oil),
.missile(missile),
.van(van),
.smoke(smoke),
.gun(gun),
.steering(steering),
.gas(gas),
.timer(1),
.show_lamps(lamps),
.demo_sound(demosnd),
.service(service),
.cpu_rom_addr ( rom_addr ),
.cpu_rom_do ( rom_addr[0] ? rom_do[15:8] : rom_do[7:0] ),
.snd_rom_addr ( snd_addr ),
.snd_rom_do ( snd_addr[0] ? snd_do[15:8] : snd_do[7:0] ),
.csd_rom_addr ( csd_addr ),
.csd_rom_do ( csd_do ),
.sp_addr ( sp_addr ),
.sp_graphx32_do ( sp_do ),
.dl_addr ( ioctl_addr[18:0]),
.dl_data ( ioctl_dout ),
.dl_wr ( ioctl_wr && ioctl_index == 0 ),
.up_data ( ioctl_din ),
.cmos_wr ( ioctl_wr && ioctl_index == 8'hff )
);
wire vs_out;
wire hs_out;
assign VGA_HS = (~no_csync & scandoublerD & ~ypbpr)? cs : hs_out;
assign VGA_VS = (~no_csync & scandoublerD & ~ypbpr)? 1'b1 : vs_out;
mist_video #(.COLOR_DEPTH(3), .SD_HCNT_WIDTH(10)) mist_video(
.clk_sys ( clk_sys ),
.SPI_SCK ( SPI_SCK ),
.SPI_SS3 ( SPI_SS3 ),
.SPI_DI ( SPI_DI ),
.R ( blankn ? r : 0 ),
.G ( blankn ? g : 0 ),
.B ( blankn ? b : 0 ),
.HSync ( hs ),
.VSync ( vs ),
.VGA_R ( VGA_R ),
.VGA_G ( VGA_G ),
.VGA_B ( VGA_B ),
.VGA_VS ( vs_out ),
.VGA_HS ( hs_out ),
.rotate ( { 1'b1, rotate } ),
.ce_divider ( 1 ),
.blend ( blend ),
.scandoubler_disable(1),//scandoublerD ),
.no_csync ( 1'b1 ),
.ypbpr ( ypbpr )
);
dac #(
.C_bits(16))
dac_l(
.clk_i(clk_sys),
.res_n_i(1),
.dac_i(audio_l + { csd_audio, 5'd0 }),
.dac_o(AUDIO_L)
);
dac #(
.C_bits(16))
dac_r(
.clk_i(clk_sys),
.res_n_i(1),
.dac_i(audio_r + { csd_audio, 5'd0 }),
.dac_o(AUDIO_R)
);
wire [7:0] steering;
wire [7:0] gas;
wire gun = m_fireA;
wire missile = m_fireB;
wire shift = m_fireC;
wire van = m_fireD | btn_van;
wire oil = m_fireE;
wire smoke = m_fireF;
reg shift_state;
input_toggle gearbox(clk_sys, m_coin1 | m_coin2, shift, shift_state);
wire m_up, m_down, m_left, m_right, m_fireA, m_fireB, m_fireC, m_fireD, m_fireE, m_fireF;
wire m_up2, m_down2, m_left2, m_right2, m_fire2A, m_fire2B, m_fire2C, m_fire2D, m_fire2E, m_fire2F;
wire m_tilt, m_coin1, m_coin2, m_coin3, m_coin4, m_one_player, m_two_players, m_three_players, m_four_players;
arcade_inputs inputs (
.clk ( clk_sys ),
.key_strobe ( key_strobe ),
.key_pressed ( key_pressed ),
.key_code ( key_code ),
.joystick_0 ( joystick_0 ),
.joystick_1 ( joystick_1 ),
.rotate ( rotate ),
.orientation ( 2'b11 ),
.joyswap ( 1'b0 ),
.oneplayer ( 1'b1 ),
.controls ( {m_tilt, m_coin4, m_coin3, m_coin2, m_coin1, m_four_players, m_three_players, m_two_players, m_one_player} ),
.player1 ( {m_fireF, m_fireE, m_fireD, m_fireC, m_fireB, m_fireA, m_up, m_down, m_left, m_right} ),
.player2 ( {m_fire2F, m_fire2E, m_fire2D, m_fire2C, m_fire2B, m_fire2A, m_up2, m_down2, m_left2, m_right2} )
);
reg btn_van = 0;
always @(posedge clk_sys) begin
if(key_strobe) begin
case(key_code)
'h0D: btn_van <= key_pressed; // TAB
endcase
end
end
endmodule