mirror of
https://github.com/MiSTer-devel/Arcade-Tecmo_MiSTer.git
synced 2026-05-24 03:02:54 +00:00
417 lines
11 KiB
Systemverilog
417 lines
11 KiB
Systemverilog
// __ __ __ __ __ __
|
|
// /\ "-.\ \ /\ \/\ \ /\ \ /\ \
|
|
// \ \ \-. \ \ \ \_\ \ \ \ \____ \ \ \____
|
|
// \ \_\\"\_\ \ \_____\ \ \_____\ \ \_____\
|
|
// \/_/ \/_/ \/_____/ \/_____/ \/_____/
|
|
// ______ ______ __ ______ ______ ______
|
|
// /\ __ \ /\ == \ /\ \ /\ ___\ /\ ___\ /\__ _\
|
|
// \ \ \/\ \ \ \ __< _\_\ \ \ \ __\ \ \ \____ \/_/\ \/
|
|
// \ \_____\ \ \_____\ /\_____\ \ \_____\ \ \_____\ \ \_\
|
|
// \/_____/ \/_____/ \/_____/ \/_____/ \/_____/ \/_/
|
|
//
|
|
// https://joshbassett.info
|
|
// https://twitter.com/nullobject
|
|
// https://github.com/nullobject
|
|
//
|
|
// Copyright (c) 2020 Josh Bassett
|
|
//
|
|
// 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.
|
|
|
|
module emu
|
|
(
|
|
//Master input clock
|
|
input CLK_50M,
|
|
|
|
//Async reset from top-level module.
|
|
//Can be used as initial reset.
|
|
input RESET,
|
|
|
|
//Must be passed to hps_io module
|
|
inout [45:0] HPS_BUS,
|
|
|
|
//Base video clock. Usually equals to CLK_SYS.
|
|
output VGA_CLK,
|
|
|
|
//Multiple resolutions are supported using different VGA_CE rates.
|
|
//Must be based on CLK_VIDEO
|
|
output VGA_CE,
|
|
|
|
output [7:0] VGA_R,
|
|
output [7:0] VGA_G,
|
|
output [7:0] VGA_B,
|
|
output VGA_HS,
|
|
output VGA_VS,
|
|
output VGA_DE, // = ~(VBlank | HBlank)
|
|
output VGA_F1,
|
|
|
|
//Base video clock. Usually equals to CLK_SYS.
|
|
output HDMI_CLK,
|
|
|
|
//Multiple resolutions are supported using different HDMI_CE rates.
|
|
//Must be based on CLK_VIDEO
|
|
output HDMI_CE,
|
|
|
|
output [7:0] HDMI_R,
|
|
output [7:0] HDMI_G,
|
|
output [7:0] HDMI_B,
|
|
output HDMI_HS,
|
|
output HDMI_VS,
|
|
output HDMI_DE, // = ~(VBlank | HBlank)
|
|
output [1:0] HDMI_SL, // scanlines fx
|
|
|
|
//Video aspect ratio for HDMI. Most retro systems have ratio 4:3.
|
|
output [7:0] HDMI_ARX,
|
|
output [7:0] HDMI_ARY,
|
|
|
|
output LED_USER, // 1 - ON, 0 - OFF.
|
|
|
|
// b[1]: 0 - LED status is system status OR'd with b[0]
|
|
// 1 - LED status is controled solely by b[0]
|
|
// hint: supply 2'b00 to let the system control the LED.
|
|
output [1:0] LED_POWER,
|
|
output [1:0] LED_DISK,
|
|
|
|
output [15:0] AUDIO_L,
|
|
output [15:0] AUDIO_R,
|
|
output AUDIO_S, // 1 - signed audio samples, 0 - unsigned
|
|
|
|
//SDRAM interface with lower latency
|
|
output SDRAM_CLK,
|
|
output SDRAM_CKE,
|
|
output [12:0] SDRAM_A,
|
|
output [1:0] SDRAM_BA,
|
|
inout [15:0] SDRAM_DQ,
|
|
output SDRAM_DQML,
|
|
output SDRAM_DQMH,
|
|
output SDRAM_nCS,
|
|
output SDRAM_nCAS,
|
|
output SDRAM_nRAS,
|
|
output SDRAM_nWE,
|
|
|
|
// Open-drain User port.
|
|
// 0 - D+/RX
|
|
// 1 - D-/TX
|
|
// 2..6 - USR2..USR6
|
|
// Set USER_OUT to 1 to read from USER_IN.
|
|
input [6:0] USER_IN,
|
|
output [6:0] USER_OUT
|
|
);
|
|
|
|
assign VGA_F1 = 0;
|
|
|
|
assign AUDIO_S = 1;
|
|
assign AUDIO_R = AUDIO_L;
|
|
|
|
assign LED_DISK = 0;
|
|
assign LED_POWER = 0;
|
|
|
|
assign HDMI_ARX = status[1] ? 8'd16 : status[2] ? 8'd3 : 8'd4;
|
|
assign HDMI_ARY = status[1] ? 8'd9 : status[2] ? 8'd4 : 8'd3;
|
|
|
|
assign SDRAM_CLK = clk_sdram;
|
|
|
|
`include "build_id.v"
|
|
localparam CONF_STR = {
|
|
"A.Tecmo;;",
|
|
"O1,Aspect Ratio,Original,Wide;",
|
|
"O2,Orientation,Horz,Vert;",
|
|
"O3,Flip Screen,Off,On;",
|
|
"O46,Scandoubler Fx,None,HQ2x,CRT 25%,CRT 50%,CRT 75%;",
|
|
"O7,Debug,Off,On;",
|
|
"-;",
|
|
"DIP;",
|
|
"-;",
|
|
"R0,Reset;",
|
|
"J1,B0,B1,B2,Start,Coin,Pause;",
|
|
"V,v",`BUILD_DATE
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// CLOCKS
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
wire clk_sys, clk_sdram;
|
|
wire locked;
|
|
|
|
pll pll
|
|
(
|
|
.refclk(CLK_50M),
|
|
.outclk_0(clk_sys),
|
|
.outclk_1(clk_sdram),
|
|
.locked(locked)
|
|
);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// HPS IO
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
wire [1:0] buttons;
|
|
wire [31:0] status;
|
|
wire forced_scandoubler;
|
|
wire [21:0] gamma_bus;
|
|
wire direct_video;
|
|
|
|
wire [24:0] ioctl_addr;
|
|
wire [7:0] ioctl_data;
|
|
wire ioctl_wr;
|
|
wire ioctl_download;
|
|
wire [7:0] ioctl_index;
|
|
|
|
wire [10:0] ps2_key;
|
|
|
|
wire [9:0] joystick_0, joystick_1;
|
|
|
|
hps_io #(.STRLEN($size(CONF_STR)>>3)) hps_io
|
|
(
|
|
.clk_sys(clk_sys),
|
|
.HPS_BUS(HPS_BUS),
|
|
|
|
.conf_str(CONF_STR),
|
|
|
|
.buttons(buttons),
|
|
.status(status),
|
|
.status_menumask(direct_video),
|
|
.forced_scandoubler(forced_scandoubler),
|
|
.gamma_bus(gamma_bus),
|
|
.direct_video(direct_video),
|
|
|
|
.ioctl_addr(ioctl_addr),
|
|
.ioctl_dout(ioctl_data),
|
|
.ioctl_wr(ioctl_wr),
|
|
.ioctl_download(ioctl_download),
|
|
.ioctl_index(ioctl_index),
|
|
|
|
.joystick_0(joystick_0),
|
|
.joystick_1(joystick_1),
|
|
|
|
.ps2_key(ps2_key)
|
|
);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// VIDEO
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
wire ce_pix;
|
|
wire [3:0] r, g, b;
|
|
wire hsync, vsync;
|
|
wire hblank, vblank;
|
|
wire no_rotate = ~status[2] & ~direct_video;
|
|
|
|
arcade_video #(256, 224, 12) arcade_video
|
|
(
|
|
.*,
|
|
|
|
// clock
|
|
.clk_video(clk_sys),
|
|
.ce_pix(ce_pix),
|
|
|
|
// video
|
|
.RGB_in({r, g, b}),
|
|
.HBlank(hblank),
|
|
.VBlank(vblank),
|
|
.HSync(hsync),
|
|
.VSync(vsync),
|
|
|
|
// rotate/aspect
|
|
.no_rotate(no_rotate),
|
|
.rotate_ccw(0),
|
|
.fx(status[6:4])
|
|
);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// SDRAM
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
wire [22:0] sdram_addr;
|
|
wire [31:0] sdram_data;
|
|
wire sdram_we;
|
|
wire sdram_req;
|
|
wire sdram_ack;
|
|
wire sdram_valid;
|
|
wire [31:0] sdram_q;
|
|
|
|
sdram #(.CLK_FREQ(96.0)) sdram
|
|
(
|
|
.reset(~locked),
|
|
.clk(clk_sys),
|
|
|
|
// controller interface
|
|
.addr(sdram_addr),
|
|
.data(sdram_data),
|
|
.we(sdram_we),
|
|
.req(sdram_req),
|
|
.ack(sdram_ack),
|
|
.valid(sdram_valid),
|
|
.q(sdram_q),
|
|
|
|
// SDRAM interface
|
|
.sdram_a(SDRAM_A),
|
|
.sdram_ba(SDRAM_BA),
|
|
.sdram_dq(SDRAM_DQ),
|
|
.sdram_cke(SDRAM_CKE),
|
|
.sdram_cs_n(SDRAM_nCS),
|
|
.sdram_ras_n(SDRAM_nRAS),
|
|
.sdram_cas_n(SDRAM_nCAS),
|
|
.sdram_we_n(SDRAM_nWE),
|
|
.sdram_dqml(SDRAM_DQML),
|
|
.sdram_dqmh(SDRAM_DQMH)
|
|
);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// CONTROLS
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
wire pressed = ps2_key[9];
|
|
wire [7:0] code = ps2_key[7:0];
|
|
|
|
reg key_left = 0;
|
|
reg key_right = 0;
|
|
reg key_down = 0;
|
|
reg key_up = 0;
|
|
reg key_ctrl = 0;
|
|
reg key_alt = 0;
|
|
reg key_space = 0;
|
|
reg key_1 = 0;
|
|
reg key_2 = 0;
|
|
reg key_5 = 0;
|
|
reg key_6 = 0;
|
|
reg key_a = 0;
|
|
reg key_s = 0;
|
|
reg key_q = 0;
|
|
reg key_r = 0;
|
|
reg key_f = 0;
|
|
reg key_d = 0;
|
|
reg key_g = 0;
|
|
reg key_p = 0;
|
|
|
|
always @(posedge clk_sys) begin
|
|
reg old_state;
|
|
old_state <= ps2_key[10];
|
|
|
|
if (old_state != ps2_key[10]) begin
|
|
case (code)
|
|
'h75: key_up <= pressed;
|
|
'h72: key_down <= pressed;
|
|
'h6B: key_left <= pressed;
|
|
'h74: key_right <= pressed;
|
|
'h14: key_ctrl <= pressed;
|
|
'h11: key_alt <= pressed;
|
|
'h29: key_space <= pressed;
|
|
'h16: key_1 <= pressed;
|
|
'h1E: key_2 <= pressed;
|
|
'h2E: key_5 <= pressed;
|
|
'h36: key_6 <= pressed;
|
|
'h1C: key_a <= pressed;
|
|
'h1B: key_s <= pressed;
|
|
'h15: key_q <= pressed;
|
|
'h2D: key_r <= pressed;
|
|
'h2B: key_f <= pressed;
|
|
'h23: key_d <= pressed;
|
|
'h34: key_g <= pressed;
|
|
'h4d: key_p <= pressed;
|
|
endcase
|
|
end
|
|
end
|
|
|
|
wire player_1_up = key_up | joystick_0[3];
|
|
wire player_1_down = key_down | joystick_0[2];
|
|
wire player_1_left = key_left | joystick_0[1];
|
|
wire player_1_right = key_right | joystick_0[0];
|
|
wire player_1_button_1 = key_ctrl | joystick_0[4];
|
|
wire player_1_button_2 = key_alt | joystick_0[5];
|
|
wire player_1_button_3 = key_space | joystick_0[6];
|
|
wire player_1_start = key_1 | joystick_0[7];
|
|
wire player_1_coin = key_5 | joystick_0[8];
|
|
wire player_1_pause = key_p | joystick_0[9];
|
|
wire player_2_up = key_r | joystick_1[3];
|
|
wire player_2_down = key_f | joystick_1[2];
|
|
wire player_2_left = key_d | joystick_1[1];
|
|
wire player_2_right = key_g | joystick_1[0];
|
|
wire player_2_button_1 = key_a | joystick_1[4];
|
|
wire player_2_button_2 = key_s | joystick_1[5];
|
|
wire player_2_button_3 = key_q | joystick_1[6];
|
|
wire player_2_start = key_2 | joystick_1[7];
|
|
wire player_2_coin = key_6 | joystick_1[8];
|
|
wire player_2_pause = joystick_0[9];
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// GAME
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
wire reset = RESET | status[0] | buttons[1];
|
|
reg [7:0] sw[8];
|
|
reg [3:0] game_index = 0;
|
|
|
|
always @(posedge clk_sys) begin
|
|
// set game index
|
|
if (ioctl_wr && (ioctl_index == 1)) game_index <= ioctl_data[3:0];
|
|
|
|
// set DIP switches
|
|
if (ioctl_wr && (ioctl_index == 254) && !ioctl_addr[24:3]) sw[ioctl_addr[2:0]] <= ioctl_data;
|
|
end
|
|
|
|
tecmo #(.CLK_FREQ(96.0)) tecmo
|
|
(
|
|
.reset(reset),
|
|
|
|
.clk(clk_sys),
|
|
.cen_6(ce_pix),
|
|
|
|
.debug(status[7]),
|
|
.flip(status[3]),
|
|
|
|
.joy_1({player_1_up, player_1_down, player_1_right, player_1_left}),
|
|
.joy_2({player_2_up, player_2_down, player_2_right, player_2_left}),
|
|
.buttons_1({2'b0, player_1_button_3, player_1_button_2, player_1_button_1}),
|
|
.buttons_2({2'b0, player_2_button_3, player_2_button_2, player_2_button_1}),
|
|
.sys({player_1_coin, player_2_coin, player_1_start, player_2_start}),
|
|
.pause(player_1_pause | player_2_pause),
|
|
|
|
.dip_1(sw[0]),
|
|
.dip_2(sw[1]),
|
|
|
|
.sdram_addr(sdram_addr),
|
|
.sdram_data(sdram_data),
|
|
.sdram_we(sdram_we),
|
|
.sdram_req(sdram_req),
|
|
.sdram_ack(sdram_ack),
|
|
.sdram_valid(sdram_valid),
|
|
.sdram_q(sdram_q),
|
|
|
|
.ioctl_addr(ioctl_addr[19:0]),
|
|
.ioctl_data(ioctl_data),
|
|
.ioctl_wr(ioctl_wr && !ioctl_index),
|
|
.ioctl_download(ioctl_download && !ioctl_index),
|
|
|
|
.game_index(game_index),
|
|
|
|
.hsync(hsync),
|
|
.vsync(vsync),
|
|
.hblank(hblank),
|
|
.vblank(vblank),
|
|
|
|
.r(r),
|
|
.g(g),
|
|
.b(b),
|
|
|
|
.audio(AUDIO_L)
|
|
);
|
|
|
|
endmodule
|