Files
SNES_MiSTer/SNES.sv
2026-04-18 13:39:16 +08:00

1592 lines
38 KiB
Systemverilog

//============================================================================
// SNES for MiSTer
// Copyright (C) 2017-2019 Srg320
// Copyright (C) 2018-2019 Sorgelig
//
// 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 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 [48:0] HPS_BUS,
//Base video clock. Usually equals to CLK_SYS.
output CLK_VIDEO,
//Multiple resolutions are supported using different CE_PIXEL rates.
//Must be based on CLK_VIDEO
output CE_PIXEL,
//Video aspect ratio for HDMI. Most retro systems have ratio 4:3.
//if VIDEO_ARX[12] or VIDEO_ARY[12] is set then [11:0] contains scaled size instead of aspect ratio.
output [12:0] VIDEO_ARX,
output [12:0] VIDEO_ARY,
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,
output [1:0] VGA_SL,
output VGA_SCALER, // Force VGA scaler
output VGA_DISABLE, // analog out is off
input [11:0] HDMI_WIDTH,
input [11:0] HDMI_HEIGHT,
output HDMI_FREEZE,
output HDMI_BLACKOUT,
output HDMI_BOB_DEINT,
`ifdef MISTER_FB
// Use framebuffer in DDRAM
// FB_FORMAT:
// [2:0] : 011=8bpp(palette) 100=16bpp 101=24bpp 110=32bpp
// [3] : 0=16bits 565 1=16bits 1555
// [4] : 0=RGB 1=BGR (for 16/24/32 modes)
//
// FB_STRIDE either 0 (rounded to 256 bytes) or multiple of pixel size (in bytes)
output FB_EN,
output [4:0] FB_FORMAT,
output [11:0] FB_WIDTH,
output [11:0] FB_HEIGHT,
output [31:0] FB_BASE,
output [13:0] FB_STRIDE,
input FB_VBL,
input FB_LL,
output FB_FORCE_BLANK,
`ifdef MISTER_FB_PALETTE
// Palette control for 8bit modes.
// Ignored for other video modes.
output FB_PAL_CLK,
output [7:0] FB_PAL_ADDR,
output [23:0] FB_PAL_DOUT,
input [23:0] FB_PAL_DIN,
output FB_PAL_WR,
`endif
`endif
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,
// I/O board button press simulation (active high)
// b[1]: user button
// b[0]: osd button
output [1:0] BUTTONS,
input CLK_AUDIO, // 24.576 MHz
output [15:0] AUDIO_L,
output [15:0] AUDIO_R,
output AUDIO_S, // 1 - signed audio samples, 0 - unsigned
output [1:0] AUDIO_MIX, // 0 - no mix, 1 - 25%, 2 - 50%, 3 - 100% (mono)
//ADC
inout [3:0] ADC_BUS,
//SD-SPI
output SD_SCK,
output SD_MOSI,
input SD_MISO,
output SD_CS,
input SD_CD,
//High latency DDR3 RAM interface
//Use for non-critical time purposes
output DDRAM_CLK,
input DDRAM_BUSY,
output [7:0] DDRAM_BURSTCNT,
output [28:0] DDRAM_ADDR,
input [63:0] DDRAM_DOUT,
input DDRAM_DOUT_READY,
output DDRAM_RD,
output [63:0] DDRAM_DIN,
output [7:0] DDRAM_BE,
output DDRAM_WE,
//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,
`ifdef MISTER_DUAL_SDRAM
//Secondary SDRAM
//Set all output SDRAM_* signals to Z ASAP if SDRAM2_EN is 0
input SDRAM2_EN,
output SDRAM2_CLK,
output [12:0] SDRAM2_A,
output [1:0] SDRAM2_BA,
inout [15:0] SDRAM2_DQ,
output SDRAM2_nCS,
output SDRAM2_nCAS,
output SDRAM2_nRAS,
output SDRAM2_nWE,
`endif
input UART_CTS,
output UART_RTS,
input UART_RXD,
output UART_TXD,
output UART_DTR,
input UART_DSR,
// 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,
input OSD_STATUS
);
assign ADC_BUS = 'Z;
assign AUDIO_S = 1;
assign AUDIO_MIX = status[20:19];
assign LED_USER = cart_download | ssbin_download | spc_download | (status[23] & bk_pending);
assign LED_DISK = 0;
assign LED_POWER = 0;
assign BUTTONS = osd_btn;
assign VGA_SCALER= 0;
assign VGA_DISABLE = 0;
assign HDMI_FREEZE = 0;
assign HDMI_BLACKOUT = 0;
assign HDMI_BOB_DEINT = 0;
assign {SD_SCK, SD_MOSI, SD_CS} = 'Z;
wire [1:0] ar = status[33:32];
wire vcrop_en = status[39];
wire [3:0] vcopt = status[38:35];
reg en216p;
reg [4:0] voff;
always @(posedge CLK_VIDEO) begin
en216p <= ((HDMI_WIDTH == 1920) && (HDMI_HEIGHT == 1080) && !forced_scandoubler && !scale);
voff <= (vcopt < 6) ? {vcopt,1'b0} : ({vcopt,1'b0} - 5'd24);
end
wire vga_de;
video_freak video_freak
(
.*,
.VGA_DE_IN(vga_de),
.ARX((!ar) ? (V224_MODE ? 12'd64 : 12'd2048) : (ar - 1'd1)),
.ARY((!ar) ? (V224_MODE ? 12'd49 : 12'd1673) : 12'd0),
.CROP_SIZE((en216p & vcrop_en) ? 10'd216 : 10'd0),
.CROP_OFF(voff),
.SCALE(status[41:40])
);
/////////////////////// CLOCK/RESET ///////////////////////////////////
wire clock_locked;
wire clk_mem;
wire clk_sys;
pll pll
(
.refclk(CLK_50M),
.rst(0),
.outclk_0(clk_mem),
.outclk_1(CLK_VIDEO),
.outclk_2(clk_sys),
.reconfig_to_pll(reconfig_to_pll),
.reconfig_from_pll(reconfig_from_pll),
.locked(clock_locked)
);
wire [63:0] reconfig_to_pll;
wire [63:0] reconfig_from_pll;
wire cfg_waitrequest;
reg cfg_write;
reg [5:0] cfg_address;
reg [31:0] cfg_data;
pll_cfg pll_cfg
(
.mgmt_clk(CLK_50M),
.mgmt_reset(0),
.mgmt_waitrequest(cfg_waitrequest),
.mgmt_read(0),
.mgmt_readdata(),
.mgmt_write(cfg_write),
.mgmt_address(cfg_address),
.mgmt_writedata(cfg_data),
.reconfig_to_pll(reconfig_to_pll),
.reconfig_from_pll(reconfig_from_pll)
);
always @(posedge CLK_50M) begin
reg pald = 0, pald2 = 0;
reg [2:0] state = 0;
pald <= PAL;
pald2 <= pald;
cfg_write <= 0;
if(pald2 != pald) state <= 1;
if(!cfg_waitrequest) begin
if(state) state<=state+1'd1;
case(state)
1: begin
cfg_address <= 0;
cfg_data <= 0;
cfg_write <= 1;
end
3: begin
cfg_address <= 7;
cfg_data <= pald2 ? 2201376898 : 2537930535;
cfg_write <= 1;
end
5: begin
cfg_address <= 2;
cfg_data <= 0;
cfg_write <= 1;
end
endcase
end
end
wire reset = RESET | buttons[1] | status[0] | cart_download | spc_download | bk_loading | clearing_ram | msu_data_download;
//////////////////////////// HPS I/O //////////////////////////////////
// Status Bit Map:
// 0 1 2 3 4 5 6
// 01234567890123456789012345678901 23456789012345678901234567890123
// 0123456789ABCDEFGHIJKLMNOPQRSTUV 0123456789ABCDEFGHIJKLMNOPQRSTUV
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXX XXXXXXXX
`include "build_id.v"
parameter CONF_STR = {
"SNES;SS3F800000:100000,UART31250,MIDI;",
"FS1,SFCSMCBINBS ;",
"FS4,SPC;",
"-;",
"O[50],Save state to SD,On,Off;",
"O[52:51],Savestate Slot,1,2,3,4;",
"d6R[47],Save state (Alt-F1);",
"d6R[48],Load state (F1);",
"-;",
"OEF,Video Region,Auto,NTSC,PAL;",
"O13,ROM Header,Auto,No Header,LoROM,HiROM,ExHiROM;",
"-;",
"C,Cheats;",
"H2OO,Cheats Enabled,Yes,No;",
"-;",
"D0RC,Load Backup RAM;",
"D0RD,Save Backup RAM;",
"D0ON,Autosave,Off,On;",
"D0-;",
"P1,Audio & Video;",
"P1-;",
"P1o01,Aspect Ratio,Original,Full Screen,[ARC1],[ARC2];",
"P1O9B,Scandoubler Fx,None,HQ2x,CRT 25%,CRT 50%,CRT 75%;",
"P1-;",
"d5P1o7,Vertical Crop,Disabled,216p(5x);",
"d5P1o36,Crop Offset,0,2,4,8,10,12,-12,-10,-8,-6,-4,-2;",
"P1o89,Scale,Normal,V-Integer,Narrower HV-Integer,Wider HV-Integer;",
"P1oA,Force 256px,Off,On;",
"P1-;",
"P1OG,Pseudo Transparency,Blend,Off;",
"P1-;",
"P1OJK,Stereo Mix,None,25%,50%,100%;",
"P2,Input Options;",
"P2-;",
"P2O7,Swap Joysticks,No,Yes;",
"P2O8,SNAC,No,Yes;",
"P2O[53],State Ld/Sv,Start+Up/Down,Up/Down;",
"P2-;",
"P2oB,Miracle Piano,No,Yes;",
"P2OH,Multitap,Disabled,Port2;",
"P2O56,Mouse,None,Port1,Port2;",
"P2-;",
"P2OPQ,Super Scope,Disabled,Joy1,Joy2,Mouse;",
"D4P2OR,Super Scope Btn,Joy,Mouse;",
"D4P2OST,Cross,Small,Big,None;",
"D4P2o2,Gun Type,Super Scope,Justifier;",
"P3,Hardware;",
"P3-;",
"D1P3OI,SuperFX Speed,Normal,Turbo;",
"D1P3oE,SuperFX FastROM,Yes,No;",
"D3P3O4,CPU Speed,Normal,Turbo;",
"P3OU,Audio clock,Typical,Real;",
"P3OV,Sufami Cart swapping,No,Yes;",
"P3oMP,Competition Cart time,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18;",
"P3-;",
"P3OLM,Initial WRAM,9966(SNES2),00FF(SNES1),55(SD2SNES),FF;",
"P3oCD,Initial ARAM,9966(SNES2),00FF(SNES1),55(SD2SNES),FF;",
"-;",
"R0,Reset;",
"J1,A(SS Fire),B(SS Cursor),X(SS TurboSw),Y(SS Pause),LT(SS Cursor),RT(SS Fire),Select,Start,SaveState;",
"I,",
"Slot=DPAD|Save/Load=Pause+DPAD,",
"Active Slot 1,",
"Active Slot 2,",
"Active Slot 3,",
"Active Slot 4,",
"Save to state 1,",
"Restore state 1,",
"Save to state 2,",
"Restore state 2,",
"Save to state 3,",
"Restore state 3,",
"Save to state 4,",
"Restore state 4;",
"V,v",`BUILD_DATE
};
wire [1:0] buttons;
wire [63:0] status;
wire [15:0] status_menumask = {ss_allow ,en216p, !GUN_MODE, ~turbo_allow, ~gg_available, ~GSU_ACTIVE, ~bk_ena};
wire forced_scandoubler;
reg [31:0] sd_lba;
reg sd_rd = 0;
reg sd_wr = 0;
wire sd_ack;
wire [7:0] sd_buff_addr;
wire [15:0] sd_buff_dout;
wire [15:0] sd_buff_din;
wire sd_buff_wr;
wire img_mounted;
wire img_readonly;
wire [63:0] img_size;
wire ioctl_download;
wire [24:0] ioctl_addr;
wire [15:0] ioctl_dout;
wire ioctl_wr;
wire [7:0] ioctl_index;
wire [12:0] joy0,joy1,joy2,joy3,joy4;
wire [24:0] ps2_mouse;
wire [10:0] ps2_key;
wire [15:0] joystick1_rumble;
wire [7:0] joy0_x,joy0_y,joy1_x,joy1_y;
reg [7:0] uart_mode;
wire [64:0] RTC;
wire [21:0] gamma_bus;
hps_io #(.CONF_STR(CONF_STR), .WIDE(1)) hps_io
(
.clk_sys(clk_sys),
.HPS_BUS(HPS_BUS),
.buttons(buttons),
.forced_scandoubler(forced_scandoubler),
.new_vmode(new_vmode),
.joystick_l_analog_0({joy0_y, joy0_x}),
.joystick_l_analog_1({joy1_y, joy1_x}),
.joystick_0(joy0),
.joystick_1(joy1),
.joystick_2(joy2),
.joystick_3(joy3),
.joystick_4(joy4),
.joystick_0_rumble(status[8] ? 16'h0000 : joystick1_rumble),
.ps2_mouse(ps2_mouse),
.ps2_key(ps2_key),
.status(status),
.status_menumask(status_menumask),
.status_in(cart_download ? {status[63:53], ss_slot, status[50:5],1'b0,status[3:0]} : {status[63:53], ss_slot, status[50:32],1'b0,status[30:0]}),
.status_set(cart_download | status0_fall | ss_status),
.info_req(ss_info_req),
.info(ss_info),
.ioctl_addr(ioctl_addr),
.ioctl_dout(ioctl_dout),
.ioctl_wr(ioctl_wr),
.ioctl_download(ioctl_download),
.ioctl_index(ioctl_index),
.sd_lba('{sd_lba}),
.sd_rd(sd_rd),
.sd_wr(sd_wr),
.sd_ack(sd_ack),
.sd_buff_addr(sd_buff_addr),
.sd_buff_dout(sd_buff_dout),
.sd_buff_din('{sd_buff_din}),
.sd_buff_wr(sd_buff_wr),
.img_mounted(img_mounted),
.img_readonly(img_readonly),
.img_size(img_size),
.uart_mode(uart_mode),
.RTC(RTC),
.gamma_bus(gamma_bus),
.EXT_BUS(EXT_BUS)
);
wire GUN_BTN = status[27];
wire [1:0] GUN_MODE = status[26:25];
wire GUN_TYPE = status[34];
wire GSU_TURBO = status[18];
wire GSU_FASTROM = ~status[46];
wire SUFAMI_SWAP = status[31];
wire [3:0] CC_TIME = status[57:54];
wire BLEND = ~status[16];
wire [1:0] mouse_mode = status[6:5];
wire joy_swap = status[7] | piano;
wire [2:0] LHRom_type = status[3:1];
wire code_index = &ioctl_index;
wire code_download = ioctl_download & code_index;
wire cart_download = ioctl_download & ((ioctl_index[5:0] == 6'h01) | (ioctl_index[7:0] == 0));
wire spc_download = ioctl_download & ioctl_index[5:0] == 6'h04;
wire msu_audio_download = ioctl_download & ioctl_index[5:0] == 6'h02;
wire msu_data_download = ioctl_download & ioctl_index[5:0] == 6'h03;
wire ssbin_download = ioctl_download & ((ioctl_index[5:0] == 6'h00) & (ioctl_index[7:6] == 2'd1));
reg new_vmode;
always @(posedge clk_sys) begin
reg old_pal;
int to;
if(~reset) begin
old_pal <= PAL;
if(old_pal != PAL) to <= 2000000;
end
if(to) begin
to <= to - 1;
if(to == 1) new_vmode <= ~new_vmode;
end
end
////////////////////////// ROM DETECT /////////////////////////////////
reg PAL;
reg [7:0] rom_type;
reg [23:0] rom_mask, ram_mask;
reg [3:0] ram_size;
always @(posedge clk_sys) begin
reg [3:0] rom_size;
reg rom_region = 0;
if (cart_download) begin
if(ioctl_wr) begin
if (ioctl_addr == 0) begin
rom_size <= 4'hC;
ram_size <= 4'h0;
if(!LHRom_type && ioctl_dout[7:0]) {ram_size,rom_size} <= ioctl_dout[7:0];
case(LHRom_type)
1: rom_type <= 0;
2: rom_type <= 0;
3: rom_type <= 1;
4: rom_type <= 2;
default: rom_type <= ioctl_dout[15:8];
endcase
end
if (ioctl_addr == 2) begin
rom_region <= ioctl_dout[8];
end
if(LHRom_type == 2) begin
if(ioctl_addr == ('h7FD6+'h200)) rom_size <= ioctl_dout[11:8];
if(ioctl_addr == ('h7FD8+'h200)) ram_size <= ioctl_dout[3:0];
end
else if(LHRom_type == 3) begin
if(ioctl_addr == ('hFFD6+'h200)) rom_size <= ioctl_dout[11:8];
if(ioctl_addr == ('hFFD8+'h200)) ram_size <= ioctl_dout[3:0];
end
else if(LHRom_type == 4) begin
if(ioctl_addr == ('h40FFD6+'h200)) rom_size <= ioctl_dout[11:8];
if(ioctl_addr == ('h40FFD8+'h200)) ram_size <= ioctl_dout[3:0];
end
rom_mask <= (24'd1024 << rom_size) - 1'd1;
ram_mask <= ram_size ? (24'd1024 << ram_size) - 1'd1 : 24'd0;
end
end
else begin
PAL <= (!status[15:14]) ? rom_region : status[15];
end
end
reg spc_mode = 0;
always @(posedge clk_sys) begin
if(ioctl_wr) begin
spc_mode <= spc_download;
end
end
reg osd_btn = 0;
reg status0_fall = 0;
always @(posedge clk_sys) begin
integer timeout = 0;
reg has_bootrom = 0;
reg last_rst = 0;
reg old_status0;
if (RESET) last_rst <= 0;
if (status[0]) last_rst <= 1;
if (cart_download) has_bootrom <= 1;
if(last_rst & ~status[0]) begin
osd_btn <= 0;
if(timeout < 24000000) begin
timeout <= timeout + 1;
osd_btn <= ~has_bootrom;
end
end
old_status0 <= status[0];
status0_fall <= old_status0 & ~status[0];
end
//////////////////////////// SYSTEM ///////////////////////////////////
wire GSU_ACTIVE;
wire turbo_allow;
wire SNES_SYSCLKR_CE,SNES_SYSCLKF_CE;
wire SNES_REFRESH;
wire ss_avail;
wire ss_ddr_ack, ss_ddr_req, ss_ddr_we;
wire [63:0] ss_ddr_dout, ss_ddr_din;
wire [21:3] ss_ddr_addr;
wire [ 7:0] ss_ddr_be;
reg [15:0] main_audio_l;
reg [15:0] main_audio_r;
main main
(
.RESET_N(RESET_N),
.MCLK(clk_sys), // 21.47727 / 21.28137
.ACLK(clk_sys),
.GSU_ACTIVE(GSU_ACTIVE),
.GSU_TURBO(GSU_TURBO),
.GSU_FASTROM(GSU_FASTROM),
.SUFAMI_SWAP(SUFAMI_SWAP),
.CC_DIP({4'b0001,CC_TIME}),
.SYSCLKR_CE(SNES_SYSCLKR_CE),
.SYSCLKF_CE(SNES_SYSCLKF_CE),
.REFRESH(SNES_REFRESH),
.ROM_TYPE(rom_type),
.ROM_MASK(rom_mask),
.RAM_MASK(ram_mask),
.RAM_SIZE(ram_size),
.PAL(PAL),
.BLEND(BLEND),
.ROM_ADDR(ROM_ADDR),
.ROM_D(ROM_D),
.ROM_Q(ROM_Q),
.ROM_OE_N(ROM_OE_N),
.ROM_WE_N(ROM_WE_N),
.ROM_WORD(ROM_WORD),
.BSRAM_ADDR(BSRAM_ADDR),
.BSRAM_D(BSRAM_D),
.BSRAM_Q(BSRAM_Q),
.BSRAM_CE_N(BSRAM_CE_N),
.BSRAM_OE_N(BSRAM_OE_N),
.BSRAM_WE_N(BSRAM_WE_N),
.WRAM_ADDR(WRAM_ADDR),
.WRAM_D(WRAM_D),
.WRAM_Q(WRAM_Q),
.WRAM_CE_N(WRAM_CE_N),
.WRAM_OE_N(WRAM_OE_N),
.WRAM_WE_N(WRAM_WE_N),
.VRAM1_ADDR(VRAM1_ADDR),
.VRAM1_DI(VRAM1_Q),
.VRAM1_DO(VRAM1_D),
.VRAM1_WE_N(VRAM1_WE_N),
.VRAM2_ADDR(VRAM2_ADDR),
.VRAM2_DI(VRAM2_Q),
.VRAM2_DO(VRAM2_D),
.VRAM2_WE_N(VRAM2_WE_N),
.VRAM_OE_N(VRAM_OE_N),
.ARAM_ADDR(ARAM_ADDR),
.ARAM_D(ARAM_D),
.ARAM_Q(ARAM_Q),
.ARAM_CE_N(ARAM_CE_N),
.ARAM_WE_N(ARAM_WE_N),
.R(R_out),
.G(G_out),
.B(B_out),
.FIELD(FIELD),
.INTERLACE(INTERLACE),
.HIGH_RES(HIGH_RES),
.V224_MODE(V224_MODE),
.DOTCLK(DOTCLK_out),
.HBLANKn(HBlank_out),
.VBLANKn(VBlank_out),
.HSYNC(HSYNC_out),
.VSYNC(VSYNC_out),
.JOY1_DI(JOY1_DI),
.JOY2_DI(GUN_MODE ? LG_DO : JOY2_DI),
.JOY_STRB(JOY_STRB),
.JOY1_CLK(JOY1_CLK),
.JOY2_CLK(JOY2_CLK),
.JOY1_P6(JOY1_P6),
.JOY2_P6(JOY2_P6),
.JOY2_P6_in(JOY2_P6_DI),
.SNI_JOY(SNI_JOY),
.EXT_RTC(RTC),
.GG_EN(status[24]),
.GG_CODE(gg_code),
.GG_RESET((code_download && ioctl_wr && !ioctl_addr) || cart_download),
.GG_AVAILABLE(gg_available),
.SPC_MODE(spc_mode),
.IO_ADDR(ioctl_addr[16:0]),
.IO_DAT(ioctl_dout),
.IO_WR(spc_download & ioctl_wr),
.TURBO(status[4] & turbo_allow),
.TURBO_ALLOW(turbo_allow),
.DSP_FREQ(status[30]),
`ifdef DEBUG
.DBG_BG_EN(DBG_BG_EN),
.DBG_CPU_EN(DBG_CPU_EN),
`else
.DBG_BG_EN(5'b11111),
.DBG_CPU_EN(1'b1),
`endif
// MSU register handling
.MSU_TRACK_NUM(msu_track_num),
.MSU_TRACK_REQUEST(msu_track_request),
.MSU_TRACK_MOUNTING(msu_track_mounting),
.MSU_TRACK_MISSING(msu_track_missing),
.MSU_VOLUME(msu_volume),
.MSU_AUDIO_REPEAT(msu_audio_repeat),
.MSU_AUDIO_RESUME(msu_audio_resume),
.MSU_AUDIO_STOP(msu_audio_stop),
.MSU_AUDIO_PLAYING(msu_audio_playing),
.MSU_AUDIO_SECTOR(msu_audio_sector),
.MSU_RESUME_SECTOR(msu_resume_sector),
.MSU_DATA_ADDR(msu_data_addr),
.MSU_DATA(msu_data),
.MSU_DATA_ACK(msu_data_ack),
.MSU_DATA_SEEK(msu_data_seek),
.MSU_DATA_REQ(msu_data_req),
.MSU_ENABLE(msu_enable),
.SS_SAVE(ss_save),
.SS_TOSD(~status[50]),
.SS_LOAD(ss_load),
.SS_SLOT(ss_slot),
.SS_AVAIL(ss_avail),
.SS_DDR_DI(ss_ddr_dout),
.SS_DDR_ACK(ss_ddr_ack),
.SS_DDR_DO(ss_ddr_din),
.SS_DDR_ADDR(ss_ddr_addr),
.SS_DDR_WE(ss_ddr_we),
.SS_DDR_BE(ss_ddr_be),
.SS_DDR_REQ(ss_ddr_req),
.AUDIO_L(main_audio_l),
.AUDIO_R(main_audio_r)
);
assign AUDIO_L = audio_l;
assign AUDIO_R = audio_r;
reg RESET_N = 0;
reg RESET_REFRESH = 0;
always @(posedge clk_sys) begin
reg [1:0] div;
div <= div + 1'd1;
RESET_REFRESH <= !div;
if (div == 2) RESET_N <= ~reset;
end
//////////////////////////// CODES ///////////////////////////////////
reg [128:0] gg_code;
wire gg_available;
// Code layout:
// {clock bit, code flags, 32'b address, 32'b compare, 32'b replace}
// 128 127:96 95:64 63:32 31:0
// Integer values are in BIG endian byte order, so it up to the loader
// or generator of the code to re-arrange them correctly.
always_ff @(posedge clk_sys) begin
gg_code[128] <= 0;
if (code_download & ioctl_wr) begin
case (ioctl_addr[3:0])
0: gg_code[111:96] <= ioctl_dout; // Flags Bottom Word
2: gg_code[127:112] <= ioctl_dout; // Flags Top Word
4: gg_code[79:64] <= ioctl_dout; // Address Bottom Word
6: gg_code[95:80] <= ioctl_dout; // Address Top Word
8: gg_code[47:32] <= ioctl_dout; // Compare Bottom Word
10: gg_code[63:48] <= ioctl_dout; // Compare top Word
12: gg_code[15:0] <= ioctl_dout; // Replace Bottom Word
14: begin
gg_code[31:16] <= ioctl_dout; // Replace Top Word
gg_code[128] <= 1; // Clock it in
end
endcase
end
end
//////////////////////////// MEMORY ///////////////////////////////////
reg [17:0] mem_fill_addr;
reg clearing_ram = 0;
reg mem_fill_wait;
always @(posedge clk_sys) begin
if(~old_downloading & cart_download)
clearing_ram <= 1'b1;
if (&mem_fill_addr) clearing_ram <= 0;
if (clearing_ram) begin
mem_fill_wait <= ~mem_fill_wait;
if (mem_fill_wait)
mem_fill_addr <= mem_fill_addr + 1'b1;
end else begin
mem_fill_addr <= 0;
mem_fill_wait <= 0;
end
end
wire mem_fill_we = clearing_ram & ~mem_fill_wait;
reg [7:0] wram_fill_data;
always @* begin
case(status[22:21])
0: wram_fill_data = (mem_fill_addr[8] ^ mem_fill_addr[2]) ? 8'h66 : 8'h99;
1: wram_fill_data = (mem_fill_addr[9] ^ mem_fill_addr[0]) ? 8'hFF : 8'h00;
2: wram_fill_data = 8'h55;
3: wram_fill_data = 8'hFF;
endcase
end
reg [7:0] aram_fill_data;
always @* begin
case(status[45:44])
0: aram_fill_data = (mem_fill_addr[8] ^ mem_fill_addr[2]) ? 8'h66 : 8'h99;
1: aram_fill_data = (mem_fill_addr[9] ^ mem_fill_addr[0]) ? 8'hFF : 8'h00;
2: aram_fill_data = 8'h55;
3: aram_fill_data = 8'hFF;
endcase
end
wire[23:0] ROM_ADDR;
wire ROM_OE_N;
wire ROM_WE_N;
wire ROM_WORD;
wire[15:0] ROM_D;
wire[15:0] ROM_Q;
wire[16:0] WRAM_ADDR;
wire WRAM_CE_N;
wire WRAM_OE_N;
wire WRAM_WE_N;
wire [7:0] WRAM_Q, WRAM_D;
wire[24:0] SDRAM_SNI_ADDR;
wire[7:0] SDRAM_SNI_DATA;
wire[7:0] SDRAM_SNI_Q;
wire SDRAM_SNI_RD;
wire SDRAM_SNI_WR;
wire SDRAM_SNI_READY;
wire[24:0] cart_addr_download = ioctl_addr-10'd512;
wire[23:0] ssbin_addr_download = { 8'hFF, ioctl_addr[15:0] };
wire[23:0] addr_download = ssbin_download ? ssbin_addr_download : cart_addr_download[23:0];
wire sdram_download = cart_download | ssbin_download;
reg [23:0] sdram_download_addr;
reg [15:0] sdram_download_data;
reg sdram_download_wr;
reg sdram_download_en;
always @(posedge clk_mem) begin
sdram_download_addr <= addr_download;
sdram_download_data <= ioctl_dout;
sdram_download_wr <= ioctl_wr;
sdram_download_en <= sdram_download;
end
reg READ_PULSE;
always @(posedge clk_sys)
READ_PULSE <= SNES_SYSCLKR_CE;
wire [15:0] sdr_dout1, sdr_sni_dout;
sdram sdram
(
.SDRAM_CLK(SDRAM_CLK),
.SDRAM_A(SDRAM_A),
.SDRAM_BA(SDRAM_BA),
.SDRAM_DQ(SDRAM_DQ),
.SDRAM_DQML(SDRAM_DQML),
.SDRAM_DQMH(SDRAM_DQMH),
.SDRAM_nCS(SDRAM_nCS),
.SDRAM_nWE(SDRAM_nWE),
.SDRAM_nRAS(SDRAM_nRAS),
.SDRAM_nCAS(SDRAM_nCAS),
.SDRAM_CKE(SDRAM_CKE),
.init(0), //~clock_locked),
.clk(clk_mem),
.addr0(sdram_download_en ? sdram_download_addr : ROM_ADDR),
.din0(sdram_download_en ? sdram_download_data : ROM_D),
.dout0(ROM_Q),
.rd0(sdram_download_en ? 1'b0 : !RESET_N ? RESET_REFRESH : ~ROM_OE_N),
.wr0(sdram_download_en ? sdram_download_wr : ~ROM_WE_N),
.word0(sdram_download_en | ROM_WORD),
.addr1(clearing_ram ? {7'b0000000,mem_fill_addr} : {7'b0000000,WRAM_ADDR}),
.din1(clearing_ram ? {8'h00,wram_fill_data} : {8'h00,WRAM_D}),
.dout1(sdr_dout1),
.rd1(clearing_ram ? 1'b0 : ~WRAM_CE_N & ~WRAM_OE_N & READ_PULSE),
.wr1(clearing_ram ? mem_fill_we : ~WRAM_CE_N & ~WRAM_WE_N & SNES_SYSCLKF_CE),
.rfs1(clearing_ram ? 1'b0 : !RESET_N ? RESET_REFRESH : SNES_REFRESH),
.word1(0),
.sni_addr(SDRAM_SNI_ADDR),
.sni_din({8'h00,SDRAM_SNI_DATA}),
.sni_dout(sdr_sni_dout),
.sni_rd_req(SDRAM_SNI_RD),
.sni_wr_req(SDRAM_SNI_WR),
.sni_ready(SDRAM_SNI_READY),
.sni_word(0)
);
assign WRAM_Q = sdr_dout1[7:0];
assign SDRAM_SNI_Q = sdr_sni_dout[7:0];
wire VRAM_OE_N;
reg VRAM_OE_N_DELAYED;
always @(posedge clk_sys)
VRAM_OE_N_DELAYED <= VRAM_OE_N;
wire [15:0] VRAM1_ADDR;
wire VRAM1_WE_N;
wire [7:0] VRAM1_D;
wire [7:0] vram1_q;
dpram #(15) vram1
(
.clock(clk_sys),
.address_a(VRAM1_ADDR[14:0]),
.data_a(VRAM1_D),
.wren_a(~VRAM1_WE_N),
.q_a(vram1_q),
// clear the RAM on loading
.address_b(mem_fill_addr[14:0]),
.wren_b(mem_fill_we)
);
wire [7:0] VRAM1_Q = !VRAM_OE_N && !VRAM_OE_N_DELAYED ? vram1_q : '1;
wire [15:0] VRAM2_ADDR;
wire VRAM2_WE_N;
wire [7:0] VRAM2_D;
wire [7:0] vram2_q;
dpram #(15) vram2
(
.clock(clk_sys),
.address_a(VRAM2_ADDR[14:0]),
.data_a(VRAM2_D),
.wren_a(~VRAM2_WE_N),
.q_a(vram2_q),
// clear the RAM on loading
.address_b(mem_fill_addr[14:0]),
.wren_b(mem_fill_we)
);
wire [7:0] VRAM2_Q = !VRAM_OE_N && !VRAM_OE_N_DELAYED ? vram2_q : '1;
wire [15:0] ARAM_ADDR;
wire ARAM_CE_N;
wire ARAM_WE_N;
wire [7:0] ARAM_Q, ARAM_D;
dpram_dif #(16,8,15,16) aram
(
.clock(clk_sys),
.address_a(ARAM_ADDR),
.data_a(ARAM_D),
.wren_a(~ARAM_CE_N & ~ARAM_WE_N),
.q_A(ARAM_Q),
// clear the RAM on loading
.address_b(spc_download ? addr_download[15:1] : mem_fill_addr[15:1]),
.data_b(spc_download ? ioctl_dout : {2{aram_fill_data}}),
.wren_b(spc_download ? ioctl_wr : mem_fill_we)
);
localparam BSRAM_BITS = 18; // 256Kbyte
wire [19:0] BSRAM_ADDR;
wire BSRAM_CE_N;
wire BSRAM_OE_N, BSRAM_WE_N;
wire [7:0] BSRAM_Q, BSRAM_D;
wire [19:0] BSRAM_SNI_ADDR;
wire BSRAM_SNI_WR;
wire [7:0] BSRAM_SNI_D;
wire BSRAM_SNI_READY = BSRAM_CE_N | (BSRAM_OE_N & BSRAM_WE_N);
dpram_dif #(BSRAM_BITS,8,BSRAM_BITS-1,16) bsram
(
.clock(clk_sys),
//Thrash the BSRAM upon ROM loading
.address_a(clearing_ram ? mem_fill_addr[BSRAM_BITS-1:0] : BSRAM_SNI_READY ? BSRAM_SNI_ADDR : BSRAM_ADDR[BSRAM_BITS-1:0]),
.data_a(clearing_ram ? 8'hFF : BSRAM_SNI_READY ? BSRAM_SNI_D : BSRAM_D),
.wren_a(clearing_ram ? mem_fill_we : BSRAM_SNI_READY ? BSRAM_SNI_WR : ~BSRAM_WE_N),
.q_a(BSRAM_Q),
.address_b({sd_lba[BSRAM_BITS-10:0],sd_buff_addr}),
.data_b(sd_buff_dout),
.wren_b(sd_buff_wr & sd_ack),
.q_b(sd_buff_din)
);
//////////////////////////// VIDEO ////////////////////////////////////
wire [7:0] R_out,G_out,B_out;
wire HSYNC_out;
wire VSYNC_out;
wire HBlank_out;
wire VBlank_out;
wire DOTCLK_out;
always @(posedge clk_sys) begin
DOTCLK <= DOTCLK_out;
if(DOTCLK ^ DOTCLK_out) begin
R <= R_out;
G <= G_out;
B <= B_out;
HSYNC <= HSYNC_out;
VSYNC <= VSYNC_out;
HBlank <= ~HBlank_out;
VBlank <= ~VBlank_out;
end
end
reg [7:0] R,G,B;
wire FIELD,INTERLACE;
reg HSync, HSYNC;
reg VSync, VSYNC;
reg HBlank;
reg VBlank;
wire HIGH_RES,V224_MODE;
reg DOTCLK;
reg interlace;
reg ce_pix;
always @(posedge CLK_VIDEO) begin
reg [2:0] pcnt;
reg old_vsync;
reg tmp_hres, frame_hres;
reg old_dotclk;
if(~HBlank & ~VBlank) tmp_hres <= tmp_hres | HIGH_RES;
old_vsync <= VSync;
if(~old_vsync & VSync) begin
frame_hres <= (tmp_hres | ~scandoubler) & ~status[42];
tmp_hres <= 0;
interlace <= INTERLACE;
end
pcnt <= pcnt + 1'd1;
old_dotclk <= DOTCLK;
if(~old_dotclk & DOTCLK & ~HBlank & ~VBlank) pcnt <= 1;
ce_pix <= !pcnt[1:0] & (frame_hres | ~pcnt[2]);
if(pcnt==3) {HSync, VSync} <= {HSYNC, VSYNC};
end
assign VGA_F1 = interlace & FIELD;
assign VGA_SL = {~interlace,~interlace}&sl[1:0];
wire [2:0] scale = status[11:9];
wire [2:0] sl = scale ? scale - 1'd1 : 3'd0;
wire scandoubler = ~interlace && (scale || forced_scandoubler);
video_mixer #(.LINE_LENGTH(520), .GAMMA(1)) video_mixer
(
.*,
.hq2x(scale==1),
.freeze_sync(),
.VGA_DE(vga_de),
.R((LG_TARGET && GUN_MODE && (!status[29] | LG_T)) ? {8{LG_TARGET[0]}} : R),
.G((LG_TARGET && GUN_MODE && (!status[29] | LG_T)) ? {8{LG_TARGET[1]}} : G),
.B((LG_TARGET && GUN_MODE && (!status[29] | LG_T)) ? {8{LG_TARGET[2]}} : B)
);
//////////////////////////// I/O PORTS ////////////////////////////////
assign {UART_RTS, UART_DTR} = 1;
wire piano = status[43] & (uart_mode == 3);
reg last_piano = 1'b0;
always @(posedge clk_sys) last_piano <= piano;
reg piano_tdata_i;
reg sni_tdata_i;
wire [15:0] piano_data_i;
wire [15:0] sni_data_i;
wire [15:0] data_o;
wire rbf;
wire txint;
wire rxint;
uart uart(
.clk(clk_sys),
.reset(reset || (piano ^ last_piano)),
.midi_speed_sel(piano),
.tdata_i(piano ? piano_tdata_i : sni_tdata_i),
.data_i(piano ? piano_data_i : sni_data_i),
.data_o(data_o),
.uartbrk(1'b0),//reset),
.rbfmirror(rbf),
.txint(txint),
.rxint(rxint),
.txd(UART_TXD),
.rxd(UART_RXD)
);
wire piano_joypad_do;
miraclepiano miracle(
.clk(clk_sys),
.reset(reset || !piano),
.strobe(JOY_STRB),
.joypad_o(piano_joypad_do),
.joypad_clock(JOY1_CLK),
.txint(txint),
.rxint(rxint),
.tdata_i(piano_tdata_i),
.tdata_m(piano_data_i),
.rdata_m(data_o)
);
wire [63:0] SNI_JOY;
sni sni(
.clk(clk_sys),
.reset(reset || uart_mode != 6),
.vblank(VBlank),
.sdram_addr(SDRAM_SNI_ADDR),
.sdram_data(SDRAM_SNI_DATA),
.sdram_q(SDRAM_SNI_Q),
.sdram_rd_req(SDRAM_SNI_RD),
.sdram_wr_req(SDRAM_SNI_WR),
.sdram_ready(SDRAM_SNI_READY),
.bsram_addr(BSRAM_SNI_ADDR),
.bsram_q(BSRAM_Q),
.bsram_wr(BSRAM_SNI_WR),
.bsram_data(BSRAM_SNI_D),
.bsram_ready(BSRAM_SNI_READY),
.joypad(SNI_JOY),
.rbf(rbf),
.txint(txint),
.rxint(rxint),
.tdata_i(sni_tdata_i),
.tdata_m(sni_data_i),
.rdata_m(data_o)
);
wire [1:0] JOY1_DO = piano ? {1'b1,piano_joypad_do} : JOY1_DO_t;
wire JOY_STRB;
wire [1:0] JOY1_DO_t;
wire JOY1_CLK;
wire JOY1_P6;
ioport port1
(
.CLK(clk_sys),
.PORT_LATCH(JOY_STRB),
.PORT_CLK(JOY1_CLK),
.PORT_P6(JOY1_P6),
.PORT_DO(JOY1_DO_t),
.JOYSTICK1((joy_swap ^ raw_serial) ? joy1 : joy0),
.JOYSTICK1_RUMBLE(joystick1_rumble),
.MOUSE(ps2_mouse),
.MOUSE_EN(mouse_mode[0])
);
wire [1:0] JOY2_DO;
wire JOY2_CLK;
wire JOY2_P6;
ioport port2
(
.CLK(clk_sys),
.MULTITAP(status[17]),
.PORT_LATCH(JOY_STRB),
.PORT_CLK(JOY2_CLK),
.PORT_P6(JOY2_P6),
.PORT_DO(JOY2_DO),
.JOYSTICK1((joy_swap ^ raw_serial) ? joy0 : joy1),
.JOYSTICK2(joy2),
.JOYSTICK3(joy3),
.JOYSTICK4(joy4),
.MOUSE(ps2_mouse),
.MOUSE_EN(mouse_mode[1])
);
wire LG_P6_out;
wire [1:0] LG_DO;
wire [2:0] LG_TARGET;
wire LG_T = ((GUN_MODE[0]&joy0[6]) | (GUN_MODE[1]&joy1[6])); // always from joysticks
lightgun lightgun
(
.CLK(clk_sys),
.RESET(reset),
.MOUSE(ps2_mouse),
.MOUSE_XY(&GUN_MODE),
.JOY_X(GUN_MODE[0] ? joy0_x : joy1_x),
.JOY_Y(GUN_MODE[0] ? joy0_y : joy1_y),
.F(GUN_BTN ? ps2_mouse[0] : ((GUN_MODE[0]&(joy0[4]|joy0[9]) | (GUN_MODE[1]&(joy1[4]|joy1[9]))))),
.C(GUN_BTN ? ps2_mouse[1] : ((GUN_MODE[0]&(joy0[5]|joy0[8]) | (GUN_MODE[1]&(joy1[5]|joy0[8]))))),
.T(LG_T), // always from joysticks
.P(ps2_mouse[2] | ((GUN_MODE[0]&joy0[7]) | (GUN_MODE[1]&joy1[7]))), // always from joysticks and mouse
.HDE(~HBlank),
.VDE(~VBlank),
.CLKPIX(DOTCLK),
.TARGET(LG_TARGET),
.SIZE(status[28]),
.GUN_TYPE(GUN_TYPE),
.PORT_LATCH(JOY_STRB),
.PORT_CLK(JOY2_CLK),
.PORT_P6(LG_P6_out),
.PORT_DO(LG_DO)
);
// 1 [oooo|ooo) 7 - 1:+5V 2:Clk 3:Strobe 4:D0 5:D1 6: I/O 7:Gnd
// Indexes:
// IDXDIR Function USBPIN
// 0 OUT Strobe D+
// 1 OUT Clk (P1) D-
// 2 IN D1 TX-
// 3 OUT CLK (P2) GND_d
// 4 BI I/O RX+
// 5 IN P1D0 RX-
// 6 IN P2D0 TX+
wire raw_serial = status[8];
reg snac_p2 = 0;
assign USER_OUT[2] = 1'b1;
assign USER_OUT[5] = 1'b1;
assign USER_OUT[6] = 1'b1;
// JOYX_DO[0] is P4, JOYX_DO[1] is P5
wire [1:0] JOY1_DI;
wire [1:0] JOY2_DI;
wire JOY2_P6_DI;
always @(posedge clk_sys) begin
if (raw_serial) begin
if (~USER_IN[6])
snac_p2 <= 1;
end else begin
snac_p2 <= 0;
end
end
always_comb begin
if (raw_serial) begin
USER_OUT[0] = JOY_STRB;
USER_OUT[1] = joy_swap ? ~JOY2_CLK : ~JOY1_CLK;
USER_OUT[3] = joy_swap ? ~JOY1_CLK : ~JOY2_CLK;
if (snac_p2) begin
USER_OUT[4] = joy_swap ? JOY1_P6 : JOY2_P6;
JOY1_DI = joy_swap ? {1'b1, USER_IN[6]} : {1'b1, USER_IN[5]};
JOY2_DI = joy_swap ? {USER_IN[2], USER_IN[5]} : {USER_IN[2], USER_IN[6]};
JOY2_P6_DI = USER_IN[4];
end else begin
USER_OUT[4] = joy_swap ? JOY2_P6 : JOY1_P6;
JOY1_DI = joy_swap ? JOY1_DO : {USER_IN[2], USER_IN[5]};
JOY2_DI = joy_swap ? {USER_IN[2], USER_IN[5]} : JOY2_DO;
JOY2_P6_DI = joy_swap ? USER_IN[4] : (LG_P6_out | !GUN_MODE);
end
end else begin
USER_OUT[0] = 1'b1;
USER_OUT[1] = 1'b1;
USER_OUT[3] = 1'b1;
USER_OUT[4] = 1'b1;
JOY1_DI = JOY1_DO;
JOY2_DI = JOY2_DO;
JOY2_P6_DI = (LG_P6_out | !GUN_MODE);
end
end
///////////////////////// STATE SAVE/LOAD /////////////////////////////
wire bk_save_write = ~BSRAM_CE_N & ~BSRAM_WE_N;
reg bk_pending;
always @(posedge clk_sys) begin
if (bk_ena && ~OSD_STATUS && bk_save_write)
bk_pending <= 1'b1;
else if (bk_state | ~bk_ena)
bk_pending <= 1'b0;
end
reg bk_ena = 0;
reg old_downloading = 0;
reg cart_ready = 0;
reg ssbin_ready = 0;
always @(posedge clk_sys) begin
old_downloading <= cart_download;
if(~old_downloading & cart_download) bk_ena <= 0;
if(old_downloading & ~cart_download) cart_ready <= 1;
if (ssbin_download) ssbin_ready <= 1;
//Save file always mounted in the end of downloading state.
if(cart_download && img_mounted && !img_readonly) bk_ena <= |ram_mask;
end
wire bk_load = status[12];
wire bk_save = status[13] | (bk_pending & OSD_STATUS && status[23]);
reg bk_loading = 0;
reg bk_state = 0;
wire [31:0] sd_lba_end = rom_type[7:4] == 4'h2 && rom_type[3] ? {ram_mask[23:9],1'b1} : ram_mask[23:9];//For Sufami with B cart, it's double size
always @(posedge clk_sys) begin
reg old_load = 0, old_save = 0, old_ack;
old_load <= bk_load & bk_ena;
old_save <= bk_save & bk_ena;
old_ack <= sd_ack;
if(~old_ack & sd_ack) {sd_rd, sd_wr} <= 0;
if(!bk_state) begin
if((~old_load & bk_load) | (~old_save & bk_save)) begin
bk_state <= 1;
bk_loading <= bk_load;
sd_lba <= 0;
sd_rd <= bk_load;
sd_wr <= ~bk_load;
end
if(old_downloading & ~cart_download & |img_size & bk_ena) begin
bk_state <= 1;
bk_loading <= 1;
sd_lba <= 0;
sd_rd <= 1;
sd_wr <= 0;
end
end else begin
if(old_ack & ~sd_ack) begin
if(sd_lba >= sd_lba_end) begin
bk_loading <= 0;
bk_state <= 0;
end else begin
sd_lba <= sd_lba + 1'd1;
sd_rd <= bk_loading;
sd_wr <= ~bk_loading;
end
end
end
end
//debug
`ifdef DEBUG
reg [4:0] DBG_BG_EN = '1;
reg DBG_CPU_EN = 1;
wire pressed = ps2_key[9];
wire [8:0] code = ps2_key[8:0];
always @(posedge clk_sys) begin
reg old_state = 0;
old_state <= ps2_key[10];
if((ps2_key[10] != old_state) && pressed) begin
casex(code)
'h005: begin DBG_BG_EN[0] <= ~DBG_BG_EN[0]; end // F1
'h006: begin DBG_BG_EN[1] <= ~DBG_BG_EN[1]; end // F2
'h004: begin DBG_BG_EN[2] <= ~DBG_BG_EN[2]; end // F3
'h00C: begin DBG_BG_EN[3] <= ~DBG_BG_EN[3]; end // F4
'h003: begin DBG_BG_EN[4] <= ~DBG_BG_EN[4]; end // F5
'h177: begin DBG_CPU_EN <= ~DBG_CPU_EN; end // Pause
endcase
end
end
`endif
/////////////////////////// MSU1 ///////////////////////////////////
wire msu_enable;
// EXT bus is used to communicate with the HPS for MSU functionality
wire [35:0] EXT_BUS;
hps_ext hps_ext
(
.reset(reset),
.clk_sys(clk_sys),
.EXT_BUS(EXT_BUS),
.msu_enable(msu_enable),
.msu_track_mounting(msu_track_mounting),
.msu_track_missing(msu_track_missing),
.msu_track_num(msu_track_num),
.msu_track_request(msu_track_request),
.msu_audio_size(msu_audio_size),
.msu_audio_ack(msu_audio_ack),
.msu_audio_req(msu_audio_req),
.msu_audio_seek(msu_audio_seek),
.msu_audio_sector(msu_audio_sector),
.msu_audio_download(msu_audio_download),
.msu_data_base(msu_data_base)
);
wire msu_track_mounting;
wire msu_track_missing;
wire [15:0] msu_track_num;
wire msu_track_request;
wire [31:0] msu_audio_size;
wire [7:0] msu_volume;
wire msu_audio_repeat;
wire msu_audio_playing;
wire msu_audio_stop;
wire msu_audio_resume;
wire msu_audio_ack;
wire msu_audio_req;
wire msu_audio_seek;
wire [21:0] msu_audio_sector;
wire [21:0] msu_resume_sector;
wire [15:0] msu_l;
wire [15:0] msu_r;
msu_audio msu_audio
(
.reset(reset),
.clk(clk_sys),
.clk_rate(PAL ? 21281370 : 21477270),
.ctl_volume(msu_volume),
.ctl_stop(msu_audio_stop),
.ctl_play(msu_audio_playing),
.ctl_resume(msu_audio_resume),
.ctl_repeat(msu_audio_repeat),
.track_size(msu_audio_size),
.track_processing(msu_track_missing | msu_track_mounting | msu_track_request),
.audio_download(msu_audio_download),
.audio_data(ioctl_dout),
.audio_data_wr(ioctl_wr),
.audio_ack(msu_audio_ack),
.audio_sector(msu_audio_sector),
.audio_req(msu_audio_req),
.audio_seek(msu_audio_seek),
.resume_sector(msu_resume_sector),
.audio_l(msu_l),
.audio_r(msu_r)
);
reg [15:0] audio_l, audio_r;
always @(posedge clk_sys) begin
reg [16:0] mix_l, mix_r;
mix_l = $signed({main_audio_l[15], main_audio_l}) + $signed({msu_l[15], msu_l});
mix_r = $signed({main_audio_r[15], main_audio_r}) + $signed({msu_r[15], msu_r});
audio_l <= (^mix_l[16:15]) ? {mix_l[16], {15{mix_l[15]}}} : mix_l[15:0];
audio_r <= (^mix_r[16:15]) ? {mix_r[16], {15{mix_r[15]}}} : mix_r[15:0];
end
wire [31:0] msu_data_addr;
wire [7:0] msu_data;
wire msu_data_ack;
wire msu_data_seek;
wire msu_data_req;
wire [31:0] msu_data_base;
wire [31:3] msu_ram_addr;
wire msu_ram_req;
wire msu_ram_ack;
wire [63:0] msu_ram_dout;
assign DDRAM_CLK = clk_mem;
msu_data_store msu_data_store
(
.clk_sys(clk_sys),
.base_addr(msu_data_base),
.rd_next(msu_data_req),
.rd_seek(msu_data_seek),
.rd_seek_done(msu_data_ack),
.rd_addr(msu_data_addr),
.ram_addr(msu_ram_addr),
.ram_req(msu_ram_req),
.ram_ack(msu_ram_ack),
.ram_din(msu_ram_dout),
.rd_dout(msu_data)
);
ddram ddram
(
.DDRAM_CLK(DDRAM_CLK),
.DDRAM_BUSY(DDRAM_BUSY),
.DDRAM_BURSTCNT(DDRAM_BURSTCNT),
.DDRAM_ADDR(DDRAM_ADDR),
.DDRAM_DOUT(DDRAM_DOUT),
.DDRAM_DOUT_READY(DDRAM_DOUT_READY),
.DDRAM_RD(DDRAM_RD),
.DDRAM_DIN(DDRAM_DIN),
.DDRAM_BE(DDRAM_BE),
.DDRAM_WE(DDRAM_WE),
.cache_rst(~RESET_N),
.rdaddr({11'b0011_1111_10, ss_ddr_addr[21:3]}), // Save states at $3F80.0000
.dout(ss_ddr_dout),
.rom_din(ss_ddr_din),
.rom_be(ss_ddr_be),
.rom_we(ss_ddr_we),
.rom_req(ss_ddr_req),
.rom_ack(ss_ddr_ack),
.rdaddr2(msu_ram_addr), // MSU is at $2060.0000-3F7F.FFFF
.dout2(msu_ram_dout),
.rd_req2(msu_ram_req),
.rd_ack2(msu_ram_ack)
);
// saving with keyboard/OSD/gamepad
wire [1:0] ss_slot;
wire [7:0] ss_info;
wire ss_save, ss_load, ss_info_req;
wire ss_status;
wire ss_allow = ss_avail & cart_ready & ssbin_ready;
wire ss_joy_start = joy0[11] | status[53];
savestate_ui #(.INFO_TIMEOUT_BITS(25)) savestate_ui
(
.clk (clk_sys ),
.ps2_key (ps2_key[10:0] ),
.allow_ss (ss_allow ),
.joySS (joy0[12] ),
.joyRight (joy0[0] ),
.joyLeft (joy0[1] ),
.joyDown (joy0[2] ),
.joyUp (joy0[3] ),
.joyStart (ss_joy_start ),
.joyRewind (0 ),
.rewindEnable (0 ),
.status_slot (status[52:51] ),
.OSD_saveload (status[48:47] ),
.ss_save (ss_save ),
.ss_load (ss_load ),
.ss_info_req (ss_info_req ),
.ss_info (ss_info ),
.statusUpdate (ss_status ),
.selected_slot (ss_slot )
);
endmodule