Files
Genesis_MiSTer/rtl/system.sv
2022-06-26 05:27:47 +08:00

1466 lines
32 KiB
Systemverilog

// Copyright (c) 2010 Gregory Estrade (greg@torlus.com)
// Copyright (c) 2018 Sorgelig
//
// All rights reserved
//
// Redistribution and use in source and synthezised forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// Redistributions in synthesized form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// Neither the name of the author nor the names of other contributors may
// be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Please report bugs to the author, but before you do so, please
// make sure that this is not a derivative work and that
// you have the latest version of this file.
module system
(
input RESET_N,
input MCLK,
input [1:0] LPF_MODE,
input ENABLE_FM,
input ENABLE_PSG,
output [15:0] DAC_LDATA,
output [15:0] DAC_RDATA,
input LOADING,
input PAL,
input EXPORT,
input FAST_FIFO,
input SRAM_QUIRK,
input SRAM00_QUIRK,
input EEPROM_QUIRK,
input NORAM_QUIRK,
input PIER_QUIRK,
input SVP_QUIRK,
input FMBUSY_QUIRK,
input SCHAN_QUIRK,
input [1:0] TURBO,
input GG_RESET,
input GG_EN,
input [128:0] GG_CODE,
output GG_AVAILABLE,
input [14:0] BRAM_A,
input [15:0] BRAM_DI,
output [15:0] BRAM_DO,
input BRAM_WE,
output BRAM_CHANGE,
output [3:0] RED,
output [3:0] GREEN,
output [3:0] BLUE,
output VS,
output HS,
output HBL,
output VBL,
output CE_PIX,
input BORDER,
input CRAM_DOTS,
output INTERLACE,
output FIELD,
output [1:0] RESOLUTION,
input J3BUT,
input [11:0] JOY_1,
input [11:0] JOY_2,
input [11:0] JOY_3,
input [11:0] JOY_4,
input [11:0] JOY_5,
input [2:0] MULTITAP,
input [24:0] MOUSE,
input [2:0] MOUSE_OPT,
input GUN_OPT,
input GUN_TYPE,
input GUN_SENSOR,
input GUN_A,
input GUN_B,
input GUN_C,
input GUN_START,
input [7:0] SERJOYSTICK_IN,
output [7:0] SERJOYSTICK_OUT,
input [1:0] SER_OPT,
input [24:1] ROMSZ,
output [24:1] ROM_ADDR,
input [15:0] ROM_DATA,
output [15:0] ROM_WDATA,
output reg ROM_WE,
output [1:0] ROM_BE,
output reg ROM_REQ,
input ROM_ACK,
output [24:1] ROM_ADDR2,
input [15:0] ROM_DATA2,
output ROM_REQ2,
input ROM_ACK2,
input EN_HIFI_PCM,
input LADDER,
input OBJ_LIMIT_HIGH,
output TRANSP_DETECT,
//debug
input PAUSE_EN,
input BGA_EN,
input BGB_EN,
input SPR_EN,
output [23:0] DBG_M68K_A,
output [23:0] DBG_VBUS_A
);
reg reset;
reg hard_reset;
always @(posedge MCLK) if(M68K_CLKENn) begin
reset <= ~RESET_N | LOADING;
hard_reset <= LOADING;
end
//--------------------------------------------------------------
// CLOCK ENABLERS
//--------------------------------------------------------------
wire M68K_CLKEN = M68K_CLKENp;
reg M68K_CLKENp, M68K_CLKENn;
reg Z80_CLKENp, Z80_CLKENn, PSG_CLKEN;
reg FM_CLKEN;
always @(negedge MCLK) begin
reg [3:0] FCLKCNT = 0;
reg [3:0] VCLKCNT = 0;
reg [3:0] ZCLKCNT = 0;
reg [3:0] PCLKCNT = 0;
reg [3:0] VCLKMAX = 0;
reg [3:0] VCLKMID = 0;
if(~RESET_N | LOADING) begin
VCLKCNT <= 0;
PCLKCNT <= 0;
FCLKCNT <= 0;
Z80_CLKENp <= 1;
Z80_CLKENn <= 1;
PSG_CLKEN <= 1;
M68K_CLKENp <= 1;
M68K_CLKENn <= 1;
VCLKMAX = 6;
VCLKMID = 3;
end
else begin
Z80_CLKENn <= 0;
ZCLKCNT <= ZCLKCNT + 1'b1;
if (ZCLKCNT == 14) begin
ZCLKCNT <= 0;
Z80_CLKENn <= ~PAUSE_EN;
end
Z80_CLKENp <= 0;
if (ZCLKCNT == 7) begin
Z80_CLKENp <= ~PAUSE_EN;
end
PSG_CLKEN <= 0;
PCLKCNT <= PCLKCNT + 1'b1;
if (PCLKCNT == 14) begin
PCLKCNT <= 0;
PSG_CLKEN <= ~PAUSE_EN;
end
M68K_CLKENp <= 0;
VCLKCNT <= VCLKCNT + 1'b1;
if (VCLKCNT == VCLKMAX) begin
VCLKCNT <= 0;
M68K_CLKENp <= ~PAUSE_EN;
VCLKMAX <= (TURBO == 2) ? 4'd1 : (TURBO == 1) ? 4'd3 : 4'd6;
VCLKMID <= (TURBO == 2) ? 4'd0 : (TURBO == 1) ? 4'd1 : 4'd3;
end
M68K_CLKENn <= 0;
if (VCLKCNT == VCLKMID) begin
M68K_CLKENn <= ~PAUSE_EN;
end
FM_CLKEN <= 0;
FCLKCNT <= FCLKCNT + 1'b1;
if (FCLKCNT == 6) begin
FCLKCNT <= 0;
FM_CLKEN <= ~PAUSE_EN;
end
end
end
reg [16:1] ram_rst_a;
always @(posedge MCLK) ram_rst_a <= ram_rst_a + LOADING;
//--------------------------------------------------------------
// CPU 68000
//--------------------------------------------------------------
wire [23:1] M68K_A;
wire [15:0] M68K_DO;
wire M68K_AS_N;
wire M68K_UDS_N;
wire M68K_LDS_N;
wire M68K_RNW;
wire [2:0] M68K_FC;
wire M68K_BG_N;
wire M68K_BR_N;
wire M68K_BGACK_N;
reg [2:0] M68K_IPL_N;
always @(posedge MCLK) begin
reg old_as;
reg [1:0] scnt;
if(reset) M68K_IPL_N <= 3'b111;
else if (M68K_CLKEN) begin
old_as <= M68K_AS_N;
scnt <= scnt + 1'd1;
if(~M68K_AS_N) scnt <= 0;
if((~old_as & M68K_AS_N) || &scnt) begin
if (M68K_VINT) M68K_IPL_N <= 3'b001;
else if (M68K_HINT) M68K_IPL_N <= 3'b011;
else if (M68K_EXINT) M68K_IPL_N <= 3'b101;
else M68K_IPL_N <= 3'b111;
end
end
end
wire M68K_INTACK = &M68K_FC;
assign M68K_BR_N = VBUS_BR_N & Z80_BR_N;
assign M68K_BGACK_N = VBUS_BGACK_N & Z80_BGACK_N;
fx68k M68K
(
.clk(MCLK),
.extReset(reset),
.pwrUp(hard_reset),
.enPhi1(M68K_CLKENp),
.enPhi2(M68K_CLKENn),
.eRWn(M68K_RNW),
.ASn(M68K_AS_N),
.UDSn(M68K_UDS_N),
.LDSn(M68K_LDS_N),
.FC0(M68K_FC[0]),
.FC1(M68K_FC[1]),
.FC2(M68K_FC[2]),
.BGn(M68K_BG_N),
.BRn(M68K_BR_N),
.BGACKn(M68K_BGACK_N),
.HALTn(1),
.DTACKn(M68K_MBUS_DTACK_N),
.VPAn(~M68K_INTACK),
.BERRn(1),
.IPL0n(M68K_IPL_N[0]),
.IPL1n(M68K_IPL_N[1]),
.IPL2n(M68K_IPL_N[2]),
.iEdb(genie_data),
.oEdb(M68K_DO),
.eab(M68K_A)
);
assign DBG_M68K_A = {M68K_A,1'b0};
assign DBG_VBUS_A = {VBUS_A,1'b0};
//--------------------------------------------------------------
// CHEAT CODES
//--------------------------------------------------------------
wire [15:0] genie_data;
CODES #(.ADDR_WIDTH(24), .DATA_WIDTH(16), .BIG_ENDIAN(1)) codes
(
.clk(MCLK),
.reset(LOADING | GG_RESET),
.enable(~GG_EN),
.code(GG_CODE),
.available(GG_AVAILABLE),
.addr_in({M68K_A[23:1], 1'b0}),
.data_in(M68K_MBUS_D),
.data_out(genie_data)
);
//--------------------------------------------------------------
// VDP + PSG
//--------------------------------------------------------------
reg VDP_SEL;
wire [15:0] VDP_DO;
wire VDP_DTACK_N;
wire [23:1] VBUS_A;
wire VBUS_SEL;
wire VBUS_BR_N;
wire VBUS_BGACK_N;
wire M68K_EXINT;
wire M68K_HINT;
wire M68K_VINT;
wire Z80_VINT;
wire vram_req;
wire vram_we_u = vram_we & ~vram_u_n;
wire vram_we_l = vram_we & ~vram_l_n;
wire vram_we;
wire vram_u_n;
wire vram_l_n;
wire [15:1] vram_a;
wire [15:0] vram_d;
wire [15:0] vram_q1, vram_q2;
wire vram32_req;
wire [15:1] vram32_a;
wire [31:0] vram32_q;
dpram #(14) vram_l1
(
.clock(MCLK),
.address_a(vram_a[15:2]),
.data_a(vram_d[7:0]),
.wren_a(vram_we_l & (vram_ack ^ vram_req) & ~vram_a[1]),
.q_a(vram_q1[7:0]),
.address_b(LOADING ? ram_rst_a[14:1] : vram32_a[15:2]),
.wren_b(LOADING),
.q_b(vram32_q[7:0])
);
dpram #(14) vram_u1
(
.clock(MCLK),
.address_a(vram_a[15:2]),
.data_a(vram_d[15:8]),
.wren_a(vram_we_u & (vram_ack ^ vram_req) & ~vram_a[1]),
.q_a(vram_q1[15:8]),
.address_b(LOADING ? ram_rst_a[14:1] : vram32_a[15:2]),
.wren_b(LOADING),
.q_b(vram32_q[15:8])
);
dpram #(14) vram_l2
(
.clock(MCLK),
.address_a(vram_a[15:2]),
.data_a(vram_d[7:0]),
.wren_a(vram_we_l & (vram_ack ^ vram_req) & vram_a[1]),
.q_a(vram_q2[7:0]),
.address_b(LOADING ? ram_rst_a[14:1] : vram32_a[15:2]),
.wren_b(LOADING),
.q_b(vram32_q[23:16])
);
dpram #(14) vram_u2
(
.clock(MCLK),
.address_a(vram_a[15:2]),
.data_a(vram_d[15:8]),
.wren_a(vram_we_u & (vram_ack ^ vram_req) & vram_a[1]),
.q_a(vram_q2[15:8]),
.address_b(LOADING ? ram_rst_a[14:1] : vram32_a[15:2]),
.wren_b(LOADING),
.q_b(vram32_q[31:24])
);
reg vram_ack;
always @(posedge MCLK) vram_ack <= vram_req;
reg vram32_ack;
always @(posedge MCLK) vram32_ack <= vram32_req;
wire VDP_hs, VDP_vs;
assign HS = ~VDP_hs;
assign VS = ~VDP_vs;
wire HL;
vdp vdp
(
.RST_n(~hard_reset),
.CLK(MCLK),
.SEL(VDP_SEL),
.A({MBUS_A[4:1], 1'b0}),
.RNW(MBUS_RNW),
.DI(MBUS_DO),
.DO(VDP_DO),
.DTACK_n(VDP_DTACK_N),
.VRAM_req(vram_req),
.VRAM_ack(vram_ack),
.VRAM_we(vram_we),
.VRAM_u_n(vram_u_n),
.VRAM_l_n(vram_l_n),
.VRAM_a(vram_a),
.VRAM_d(vram_d),
.VRAM_q(vram_a[1] ? vram_q2 : vram_q1),
.VRAM32_req(vram32_req),
.VRAM32_ack(vram32_ack),
.VRAM32_a(vram32_a),
.VRAM32_q(vram32_q),
.EXINT(M68K_EXINT),
.HL(HL),
.HINT(M68K_HINT),
.VINT_TG68(M68K_VINT),
.INTACK(M68K_INTACK),
.VINT_T80(Z80_VINT),
.VBUS_addr(VBUS_A),
.VBUS_data(VDP_MBUS_D),
.VBUS_sel(VBUS_SEL),
.VBUS_dtack_n(VDP_MBUS_DTACK_N),
.BG_N(M68K_BG_N),
.BR_N(VBUS_BR_N),
.BGACK_N(VBUS_BGACK_N),
.VRAM_SPEED(~(FAST_FIFO|TURBO)),
.VSCROLL_BUG(0),
.BORDER_EN(BORDER),
.CRAM_DOTS(CRAM_DOTS),
.SVP_QUIRK(SVP_QUIRK),
.OBJ_LIMIT_HIGH_EN(OBJ_LIMIT_HIGH),
.FIELD_OUT(FIELD),
.INTERLACE(INTERLACE),
.RESOLUTION(RESOLUTION),
.PAL(PAL),
.R(RED),
.G(GREEN),
.B(BLUE),
.HS(VDP_hs),
.VS(VDP_vs),
.CE_PIX(CE_PIX),
.HBL(HBL),
.VBL(VBL),
.TRANSP_DETECT(TRANSP_DETECT),
.BGA_EN(BGA_EN),
.BGB_EN(BGB_EN),
.SPR_EN(SPR_EN)
);
// PSG 0x10-0x17 in VDP space
wire signed [10:0] PSG_SND;
jt89 psg
(
.rst(reset),
.clk(MCLK),
.clk_en(PSG_CLKEN),
.wr_n(MBUS_RNW | ~VDP_SEL | ~MBUS_A[4] | MBUS_A[3]),
.din(MBUS_DO[15:8]),
.sound(PSG_SND)
);
//--------------------------------------------------------------
// Gamepads
//--------------------------------------------------------------
reg IO_SEL;
wire [7:0] IO_DO;
wire IO_DTACK_N;
reg JCART_SEL;
wire [15:0] JCART_DO;
wire JCART_DTACK_N;
multitap multitap
(
.RESET(hard_reset),
.CLK(MCLK),
.CE(M68K_CLKEN),
.J3BUT(J3BUT),
.P1_UP(~JOY_1[3]),
.P1_DOWN(~JOY_1[2]),
.P1_LEFT(~JOY_1[1]),
.P1_RIGHT(~JOY_1[0]),
.P1_A(~JOY_1[4]),
.P1_B(~JOY_1[5]),
.P1_C(~JOY_1[6]),
.P1_START(~JOY_1[7]),
.P1_MODE(~JOY_1[8]),
.P1_X(~JOY_1[9]),
.P1_Y(~JOY_1[10]),
.P1_Z(~JOY_1[11]),
.P2_UP(~JOY_2[3]),
.P2_DOWN(~JOY_2[2]),
.P2_LEFT(~JOY_2[1]),
.P2_RIGHT(~JOY_2[0]),
.P2_A(~JOY_2[4]),
.P2_B(~JOY_2[5]),
.P2_C(~JOY_2[6]),
.P2_START(~JOY_2[7]),
.P2_MODE(~JOY_2[8]),
.P2_X(~JOY_2[9]),
.P2_Y(~JOY_2[10]),
.P2_Z(~JOY_2[11]),
.P3_UP(~JOY_3[3]),
.P3_DOWN(~JOY_3[2]),
.P3_LEFT(~JOY_3[1]),
.P3_RIGHT(~JOY_3[0]),
.P3_A(~JOY_3[4]),
.P3_B(~JOY_3[5]),
.P3_C(~JOY_3[6]),
.P3_START(~JOY_3[7]),
.P3_MODE(~JOY_3[8]),
.P3_X(~JOY_3[9]),
.P3_Y(~JOY_3[10]),
.P3_Z(~JOY_3[11]),
.P4_UP(~JOY_4[3]),
.P4_DOWN(~JOY_4[2]),
.P4_LEFT(~JOY_4[1]),
.P4_RIGHT(~JOY_4[0]),
.P4_A(~JOY_4[4]),
.P4_B(~JOY_4[5]),
.P4_C(~JOY_4[6]),
.P4_START(~JOY_4[7]),
.P4_MODE(~JOY_4[8]),
.P4_X(~JOY_4[9]),
.P4_Y(~JOY_4[10]),
.P4_Z(~JOY_4[11]),
.P5_UP(~JOY_5[3]),
.P5_DOWN(~JOY_5[2]),
.P5_LEFT(~JOY_5[1]),
.P5_RIGHT(~JOY_5[0]),
.P5_A(~JOY_5[4]),
.P5_B(~JOY_5[5]),
.P5_C(~JOY_5[6]),
.P5_START(~JOY_5[7]),
.P5_MODE(~JOY_5[8]),
.P5_X(~JOY_5[9]),
.P5_Y(~JOY_5[10]),
.P5_Z(~JOY_5[11]),
.FOURWAY_EN(MULTITAP == 1),
.TEAMPLAYER_EN({MULTITAP == 3,MULTITAP == 2}),
.MOUSE(MOUSE),
.MOUSE_OPT(MOUSE_OPT),
.GUN_OPT(GUN_OPT),
.GUN_TYPE(GUN_TYPE),
.GUN_SENSOR(GUN_SENSOR),
.GUN_A(GUN_A),
.GUN_B(GUN_B),
.GUN_C(GUN_C),
.GUN_START(GUN_START),
.SERJOYSTICK_IN(SERJOYSTICK_IN),
.SERJOYSTICK_OUT(SERJOYSTICK_OUT),
.SER_OPT(SER_OPT),
.PAL(PAL),
.EXPORT(EXPORT),
.SEL(IO_SEL),
.A(MBUS_A[4:1]),
.RNW(MBUS_RNW),
.DI(MBUS_DO[7:0]),
.DO(IO_DO),
.DTACK_N(IO_DTACK_N),
.HL(HL),
.JCART_SEL(JCART_SEL),
.JCART_DO(JCART_DO),
.JCART_DTACK_N(JCART_DTACK_N)
);
//-----------------------------------------------------------------------
// ROM
//-----------------------------------------------------------------------
assign ROM_ADDR = BANK_ROM ? {BANK_REG[MBUS_A[21:19]], MBUS_A[18:1]} : MBUS_A;
assign ROM_BE = ~{MBUS_UDS_N, MBUS_LDS_N};
assign ROM_WDATA = MBUS_DO;
//-----------------------------------------------------------------------
// 64KB SRAM / 128KB SVP DRAM
//-----------------------------------------------------------------------
reg SRAM_SEL;
wire [15:0] sram_addr;
wire [7:0] sram_di;
wire sram_wren;
always_comb begin
if (PIER_QUIRK) begin
sram_addr = {4'b0000, m95_addr};
sram_di = m95_di;
sram_wren = m95_rnw;
end else begin
sram_addr = MBUS_A[16:1];
sram_di = MBUS_DO[7:0];
sram_wren = SRAM_SEL & ~MBUS_RNW;
end
end
dpram_dif #(17,8,16,16) sram
(
.clock(MCLK),
.address_a(sram_addr),
.data_a(sram_di),
.wren_a(sram_wren & ~SVP_QUIRK),
.q_a(sram_q),
.address_b(LOADING ? ram_rst_a : SVP_QUIRK ? SVP_DRAM_A : BRAM_A),
// Initializes SRAM to 0x0 for Sonic 1 Remastered, all other games have SRAM initialized to 0xFF
.data_b(LOADING ? (SRAM00_QUIRK ? 16'h0000 : 16'hFFFF) : SVP_QUIRK ? SVP_DRAM_DO : BRAM_DI),
.wren_b(LOADING | SVP_DRAM_WE | BRAM_WE),
.q_b(BRAM_DO)
);
wire [7:0] sram_q;
assign BRAM_CHANGE = sram_wren;
//-----------------------------------------------------------------------
// EEPROM Handling
//-----------------------------------------------------------------------
reg ep_si, m95_so, ep_sck, ep_hold, ep_cs;
wire [7:0] m95_di, m95_q;
wire [11:0] m95_addr;
wire m95_rnw;
STM95XXX pier_eeprom
(
.clk(MCLK),
.enable(PIER_QUIRK),
.so(m95_so),
.si(ep_si),
.sck(ep_sck),
.hold_n(ep_hold),
.cs_n(ep_cs),
.wp_n(1'b1),
.ram_addr(m95_addr),
.ram_q(sram_q),
.ram_di(m95_di),
.ram_RnW(m95_rnw)
);
//-----------------------------------------------------------------------
// SVP
//-----------------------------------------------------------------------
reg SVP_SEL;
wire [15:0] SVP_DO;
wire SVP_DTACK_N;
wire [15:0] SVP_DRAM_A;
wire [15:0] SVP_DRAM_DO;
wire SVP_DRAM_WE;
wire [15:0] SVP_DRAM_DI = BRAM_DO;
reg SVP_CLKEN;
always @(posedge MCLK) SVP_CLKEN <= ~reset & ~SVP_CLKEN;
SVP svp
(
.CLK(MCLK),
.CE(SVP_CLKEN),
.RST_N(~reset & SVP_QUIRK),
.ENABLE(1),
.BUS_A(MBUS_A[23:1]),
.BUS_DO(SVP_DO),
.BUS_DI(MBUS_DO),
.BUS_SEL(SVP_SEL),
.BUS_RNW(MBUS_RNW),
.BUS_DTACK_N(SVP_DTACK_N),
.DMA_ACTIVE(VBUS_SEL),
.ROM_A(ROM_ADDR2),
.ROM_DI(ROM_DATA2),
.ROM_REQ(ROM_REQ2),
.ROM_ACK(ROM_ACK2),
.DRAM_A(SVP_DRAM_A),
.DRAM_DI(SVP_DRAM_DI),
.DRAM_DO(SVP_DRAM_DO),
.DRAM_WE(SVP_DRAM_WE)
);
//-----------------------------------------------------------------------
// 68K RAM
//-----------------------------------------------------------------------
reg RAM_SEL;
dpram #(15) ram68k_u
(
.clock(MCLK),
.address_a(MBUS_A[15:1]),
.data_a(MBUS_DO[15:8]),
.wren_a(RAM_SEL & ~MBUS_RNW & ~MBUS_UDS_N),
.q_a(ram68k_q[15:8]),
.address_b(ram_rst_a[15:1]),
.wren_b(LOADING)
);
dpram #(15) ram68k_l
(
.clock(MCLK),
.address_a(MBUS_A[15:1]),
.data_a(MBUS_DO[7:0]),
.wren_a(RAM_SEL & ~MBUS_RNW & ~MBUS_LDS_N),
.q_a(ram68k_q[7:0]),
.address_b(ram_rst_a[15:1]),
.wren_b(LOADING)
);
wire [15:0] ram68k_q;
//-----------------------------------------------------------------------
// MBUS Handling
//-----------------------------------------------------------------------
reg M68K_MBUS_DTACK_N;
reg Z80_MBUS_DTACK_N;
reg VDP_MBUS_DTACK_N;
reg [15:0] M68K_MBUS_D;
reg [7:0] Z80_MBUS_D;
reg [15:0] VDP_MBUS_D;
reg [23:1] MBUS_A;
reg [15:0] MBUS_DO;
reg MBUS_RNW;
reg MBUS_UDS_N;
reg MBUS_LDS_N;
reg [15:0] NO_DATA;
reg [4:0] BANK_REG[0:7];
reg BANK_ROM;
reg BANK_SRAM;
reg [3:0] mstate;
reg [1:0] msrc;
localparam MSRC_NONE = 0,
MSRC_M68K = 1,
MSRC_Z80 = 2,
MSRC_VDP = 3;
localparam MBUS_IDLE = 0,
MBUS_SELECT = 1,
MBUS_RAM_READ = 2,
MBUS_ROM_READ = 3,
MBUS_ROM_WRITE = 4,
MBUS_VDP_READ = 5,
MBUS_IO_READ = 6,
MBUS_JCRT_READ = 7,
MBUS_SRAM_READ = 8,
MBUS_ZBUS_PRE = 9,
MBUS_ZBUS_WS = 10,
MBUS_ZBUS_READ = 11,
MBUS_SVP_READ = 12,
MBUS_REFRESH = 13,
MBUS_FINISH = 14,
MBUS_Z80_PREREAD = 15;
always @(posedge MCLK) begin
reg [15:0] data;
reg [3:0] pier_count;
reg [8:0] refresh_timer;
reg rfs_pend;
reg [1:0] rfs_wait;
reg [1:0] cycle_cnt;
if (reset) begin
M68K_MBUS_DTACK_N <= 1;
Z80_MBUS_DTACK_N <= 1;
VDP_MBUS_DTACK_N <= 1;
VDP_SEL <= 0;
IO_SEL <= 0;
SVP_SEL <= 0;
ZBUS_SEL <= 0;
BANK_ROM <= 0;
BANK_SRAM <= 0;
mstate <= MBUS_IDLE;
pier_count <= 0;
MBUS_RNW <= 1;
NO_DATA <= 'h4E71;
BANK_REG <= '{0,1,2,3,4,5,6,7};
end
else begin
/*
refresh_timer <= refresh_timer + 1'd1;
if (refresh_timer == 'h17F) begin
refresh_timer <= 0;
rfs_pend <= 1;
end
*/
if (M68K_CLKENp) begin
if (cycle_cnt) cycle_cnt = cycle_cnt - 1'd1;
end
if (M68K_AS_N) M68K_MBUS_DTACK_N <= 1;
if (~Z80_IO) Z80_MBUS_DTACK_N <= 1;
if (~VBUS_SEL) VDP_MBUS_DTACK_N <= 1;
case(mstate)
MBUS_IDLE:
begin
CTRL_SEL <= 0;
SRAM_SEL <= 0;
RAM_SEL <= 0;
MBUS_RNW <= 1;
MBUS_UDS_N <= 1;
MBUS_LDS_N <= 1;
/*if (rfs_pend) begin
rfs_pend <= 0;
mstate <= MBUS_REFRESH;
end
else*/ if (!M68K_AS_N && M68K_MBUS_DTACK_N) begin
msrc <= MSRC_M68K;
MBUS_A <= M68K_A[23:1];
data <= NO_DATA;
MBUS_DO <= M68K_DO;
MBUS_RNW <= M68K_RNW;
mstate <= MBUS_SELECT;
end
else if (VBUS_SEL && VDP_MBUS_DTACK_N) begin
msrc <= MSRC_VDP;
MBUS_A <= VBUS_A;
data <= NO_DATA;
MBUS_DO <= 0;
mstate <= MBUS_SELECT;
//rfs_pend <= 0;
//refresh_timer <= 0;
end
else if (Z80_IO && !Z80_ZBUS && Z80_MBUS_DTACK_N && !Z80_BGACK_N && Z80_BR_N) begin
msrc <= MSRC_Z80;
MBUS_A <= Z80_A[15] ? {BAR[23:15],Z80_A[14:1]} : {16'hC000, Z80_A[7:1]};
data <= 16'hFFFF;
MBUS_DO <= {Z80_DO,Z80_DO};
MBUS_RNW <= Z80_WR_N;
mstate <= MBUS_Z80_PREREAD;
cycle_cnt <= 2'd1;
end
end
MBUS_Z80_PREREAD:
begin
if (!cycle_cnt) begin
mstate <= MBUS_SELECT;
cycle_cnt <= 2'd1;
end
end
MBUS_SELECT:
begin
//NO DEVICE (usually lockup on real HW)
mstate <= MBUS_FINISH;
if (MBUS_A[23:20]<'hA || (msrc == MSRC_Z80 && MBUS_A[23:20]<'hE && ROMSZ[24:20]>='hA)) begin
//ROM: 000000-9FFFFF (A00000-DFFFFF)
if (BANK_SRAM && MBUS_A[23:21] == 1) begin
// 200000-3FFFFF SRAM overrides ROM when bank is selected
SRAM_SEL <= 1;
mstate <= MBUS_SRAM_READ;
end
else if (PIER_QUIRK && ({MBUS_A,1'b0} == 'h0015E6 || {MBUS_A,1'b0} == 'h0015E8)) begin
if (pier_count < 'h6) begin
pier_count <= pier_count + 1'h1;
data <= MBUS_A[1] ? 16'h0 : 16'h0010;
end else begin
data <= MBUS_A[1] ? 16'h0001 : 16'h8010;
end
end
else if (EEPROM_QUIRK && {MBUS_A,1'b0} == 'h200000) begin
data <= 0;
mstate <= MBUS_FINISH;
end
else if ((SRAM_QUIRK | SRAM00_QUIRK) && {MBUS_A,1'b0} == 'h200000) begin
SRAM_SEL <= 1;
mstate <= MBUS_SRAM_READ;
end
else if(SVP_QUIRK && MBUS_A[23:20] == 3) begin
// 300000-37FFFF (+mirrors) SVP DRAM
// 390000-39FFFF SVP DRAM cell arrange 1
// 3A0000-3AFFFF SVP DRAM cell arrange 2
SVP_SEL <= 1;
mstate <= MBUS_SVP_READ;
end
else if (SCHAN_QUIRK && ~MBUS_RNW && (MBUS_A < 'h400000)) begin
mstate <= MBUS_ROM_WRITE;
end
else if (MBUS_A < ROMSZ) begin
if (SVP_QUIRK && msrc == MSRC_VDP) MBUS_A <= MBUS_A - 1'd1;
ROM_WE <= 0;
ROM_REQ <= ~ROM_ACK;
mstate <= MBUS_ROM_READ;
end
else if ((MULTITAP == 4) && ({MBUS_A,1'b0} == 'h3FFFFE || {MBUS_A,1'b0} == 'h38FFFE)) begin
JCART_SEL <= 1;
mstate <= MBUS_JCRT_READ;
end
else if(MBUS_A[23:21] == 1 && ~&MBUS_A[20:19] && ~NORAM_QUIRK) begin
// 200000-37FFFF
SRAM_SEL <= 1;
mstate <= MBUS_SRAM_READ;
end
else begin
data <= 0;
mstate <= MBUS_FINISH;
end
end
//ZBUS: A00000-A07FFF (A08000-A0FFFF)
else if(MBUS_A[23:16] == 'hA0) mstate <= !Z80_BUSRQ_N ? MBUS_ZBUS_PRE : MBUS_FINISH;
//I/O: A10000-A1001F (+mirrors)
else if(MBUS_A[23:5] == {16'hA100, 3'b000}) begin
IO_SEL <= 1;
mstate <= MBUS_IO_READ;
end
//CTL: A11100, A11200
else if(MBUS_A[23:12] == 12'hA11 && !MBUS_A[7:1]) begin
CTRL_SEL <= 1;
data <= CTRL_DO;
mstate <= MBUS_FINISH;
end
// BANK Register A13XXX
else if (MBUS_A[23:8] == 'hA130) begin
if (~MBUS_RNW) begin
if (ROMSZ > 'h200000) begin // SSF2/Pier Solar ROM banking
if (MBUS_A[3:1]) begin
BANK_ROM <= 1;
if (~PIER_QUIRK) begin // SSF2
BANK_REG[MBUS_A[3:1]] <= MBUS_DO[4:0];
end
else if (MBUS_A[3:1] == 4) begin // Pier EEPROM
{ep_cs, ep_hold , ep_sck, ep_si} <= MBUS_DO[3:0];
end
else if (~MBUS_A[3]) begin // Pier Banks
BANK_REG[{1'b1,MBUS_A[2:1]}] <= MBUS_DO[3:0];
end
end
else if (~PIER_QUIRK) begin // SRAM control only in the first register on SSF2 mapper
BANK_SRAM <= {MBUS_DO[0]};
end
end else begin
BANK_SRAM <= {MBUS_DO[0]};
end
end else if (PIER_QUIRK && MBUS_A[3:1] == 'h5) begin
data <= {15'h7FFF, m95_so};
end
mstate <= MBUS_FINISH;
end
//SVP: A15000-A5000F
else if(MBUS_A[23:4] == 20'hA1500) begin
SVP_SEL <= 1;
mstate <= MBUS_SVP_READ;
end
//VDP: C00000-C0001F (+mirrors)
else if(MBUS_A[23:21] == 3'b110 && !MBUS_A[18:16] && !MBUS_A[7:5]) begin
VDP_SEL <= 1;
mstate <= MBUS_VDP_READ;
end
//RAM: E00000-FFFFFF
else if(&MBUS_A[23:21]) begin
RAM_SEL <= 1;
mstate <= MBUS_RAM_READ;
end
end
MBUS_ZBUS_PRE:
case(msrc)
MSRC_M68K:
if(M68K_AS_N | (~M68K_UDS_N | ~M68K_LDS_N)) begin
MBUS_UDS_N <= M68K_UDS_N;
MBUS_LDS_N <= M68K_LDS_N;
ZBUS_SEL <= 1;
mstate <= MBUS_RNW ? MBUS_ZBUS_WS : MBUS_ZBUS_READ;
end
MSRC_Z80:
begin
MBUS_UDS_N <= Z80_A[0];
MBUS_LDS_N <= ~Z80_A[0];
ZBUS_SEL <= 1;
mstate <= MBUS_ZBUS_READ;
end
MSRC_VDP:
begin
MBUS_UDS_N <= 0;
MBUS_LDS_N <= 0;
ZBUS_SEL <= 1;
mstate <= MBUS_ZBUS_READ;
end
endcase
MBUS_ZBUS_WS:
begin
if (M68K_CLKENp) begin
mstate <= MBUS_ZBUS_READ;
end
end
MBUS_ZBUS_READ:
begin
if(~MBUS_ZBUS_DTACK_N) begin
ZBUS_SEL <= 0;
data <= {MBUS_ZBUS_D, MBUS_ZBUS_D};
mstate <= MBUS_FINISH;
end
end
MBUS_RAM_READ:
begin
data <= ram68k_q;
if(msrc == MSRC_M68K) NO_DATA <= ram68k_q;
mstate <= MBUS_FINISH;
end
MBUS_ROM_WRITE:
case(msrc)
MSRC_M68K:
if(M68K_AS_N | (~M68K_UDS_N | ~M68K_LDS_N)) begin
MBUS_UDS_N <= M68K_UDS_N;
MBUS_LDS_N <= M68K_LDS_N;
ROM_WE <= 1;
ROM_REQ <= ~ROM_ACK;
mstate <= MBUS_ROM_READ;
end
MSRC_Z80:
begin
MBUS_UDS_N <= Z80_A[0];
MBUS_LDS_N <= ~Z80_A[0];
ROM_WE <= 1;
ROM_REQ <= ~ROM_ACK;
mstate <= MBUS_ROM_READ;
end
endcase
MBUS_ROM_READ:
if (ROM_REQ == ROM_ACK) begin
data <= ROM_DATA;
if(msrc == MSRC_M68K) NO_DATA <= ROM_DATA;
if (msrc != MSRC_Z80 || !cycle_cnt)
mstate <= MBUS_FINISH;
end
MBUS_SRAM_READ:
begin
data <= {sram_q,sram_q};
if(msrc == MSRC_M68K) NO_DATA <= {sram_q,sram_q};
SRAM_SEL <= 0;
mstate <= MBUS_FINISH;
end
MBUS_VDP_READ:
if (~VDP_DTACK_N) begin
VDP_SEL <= 0;
data <= VDP_DO;
if(MBUS_A[4:2] == 1) data[15:10] <= NO_DATA[15:10]; //unused status bits
else if(MBUS_A[4]) data <= NO_DATA; // PSG/debug registers
mstate <= MBUS_FINISH;
end
MBUS_IO_READ:
if(~IO_DTACK_N) begin
IO_SEL <= 0;
data <= {IO_DO, IO_DO};
mstate <= MBUS_FINISH;
end
MBUS_JCRT_READ:
if(~JCART_DTACK_N) begin
JCART_SEL <= 0;
data <= JCART_DO & 16'h3F7F;
mstate <= MBUS_FINISH;
end
MBUS_SVP_READ:
if(~SVP_DTACK_N) begin
SVP_SEL <= 0;
data <= SVP_DO;
mstate <= MBUS_FINISH;
end
MBUS_REFRESH:
if (M68K_CLKENp) begin
rfs_wait <= rfs_wait + 1'd1;
if (rfs_wait == 1) begin
rfs_wait <= 0;
mstate <= MBUS_IDLE;
end
end
MBUS_FINISH:
begin
case(msrc)
MSRC_M68K:
begin
M68K_MBUS_D <= data;
M68K_MBUS_DTACK_N <= 0;
if((M68K_AS_N | MBUS_RNW | ~M68K_UDS_N | ~M68K_LDS_N)) begin
MBUS_UDS_N <= M68K_UDS_N;
MBUS_LDS_N <= M68K_LDS_N;
mstate <= MBUS_IDLE;
end
end
MSRC_Z80:
begin
if (Z80_CLKENp) begin
Z80_MBUS_D <= Z80_A[0] ? data[7:0] : data[15:8];
Z80_MBUS_DTACK_N <= 0;
MBUS_UDS_N <= Z80_A[0];
MBUS_LDS_N <= ~Z80_A[0];
mstate <= MBUS_IDLE;
end
end
MSRC_VDP:
begin
VDP_MBUS_D <= data;
VDP_MBUS_DTACK_N <= 0;
mstate <= MBUS_IDLE;
end
endcase
end
endcase
end
end
//--------------------------------------------------------------
// CPU Z80
//--------------------------------------------------------------
reg Z80_RESET_N;
reg Z80_BUSRQ_N;
wire Z80_BUSAK_N;
wire Z80_MREQ_N;
wire Z80_RD_N;
wire Z80_WR_N;
wire [15:0] Z80_A;
wire [7:0] Z80_DO;
wire Z80_IO = ~Z80_MREQ_N & (~Z80_RD_N | ~Z80_WR_N);
T80s #(.T2Write(1)) Z80
//T80pa Z80
(
.RESET_n(Z80_RESET_N),
.CLK(MCLK),
// .CEN_p(Z80_CLKENp),
// .CEN_n(Z80_CLKENn),
.CEN(Z80_CLKENn),
.BUSRQ_n(Z80_BUSRQ_N),
.BUSAK_n(Z80_BUSAK_N),
.WAIT_n(~Z80_MBUS_DTACK_N | ~Z80_ZBUS_DTACK_N | ~Z80_IO),
.INT_n(~Z80_VINT),
.MREQ_n(Z80_MREQ_N),
.RD_n(Z80_RD_N),
.WR_n(Z80_WR_N),
.A(Z80_A),
.DI((~Z80_MBUS_DTACK_N) ? Z80_MBUS_D : Z80_ZBUS_D),
.DO(Z80_DO)
);
wire CTRL_F = (MBUS_A[11:8] == 1) ? Z80_BUSAK_N : (MBUS_A[11:8] == 2) ? Z80_RESET_N : NO_DATA[8];
wire [15:0] CTRL_DO = {NO_DATA[15:9], CTRL_F, NO_DATA[7:0]};
reg CTRL_SEL;
always @(posedge MCLK) begin
if (reset) begin
Z80_BUSRQ_N <= 1;
Z80_RESET_N <= 0;
end
else if(CTRL_SEL & ~MBUS_RNW & ~MBUS_UDS_N) begin
if (MBUS_A[11:8] == 1) Z80_BUSRQ_N <= ~MBUS_DO[8];
if (MBUS_A[11:8] == 2) Z80_RESET_N <= MBUS_DO[8];
end
end
//-----------------------------------------------------------------------
// ZBUS Handling
//-----------------------------------------------------------------------
// Z80: 0000-7EFF
// 68000: A00000-A07FFF (A08000-A0FFFF)
wire Z80_ZBUS = ~Z80_A[15] && ~&Z80_A[14:8];
wire ZBUS_NO_BUSY = ZBUS_A[14] && ~|ZBUS_A[13:2] && |ZBUS_A[1:0] && FMBUSY_QUIRK;
reg ZBUS_SEL;
reg [14:0] ZBUS_A;
reg ZBUS_WE;
reg [7:0] ZBUS_DO;
wire [7:0] ZBUS_DI = ZRAM_SEL ? ZRAM_DO : (FM_SEL ? (ZBUS_NO_BUSY ? {1'b0, FM_DO[6:0]} : FM_DO) : 8'hFF);
reg [7:0] MBUS_ZBUS_D;
reg [7:0] Z80_ZBUS_D;
reg MBUS_ZBUS_DTACK_N;
reg Z80_ZBUS_DTACK_N;
reg Z80_BR_N;
reg Z80_BGACK_N;
wire Z80_ZBUS_SEL = Z80_ZBUS & Z80_IO;
wire ZBUS_FREE = ~Z80_BUSRQ_N & Z80_RESET_N;
wire Z80_MBUS_SEL = Z80_IO & ~Z80_ZBUS;
// RAM 0000-1FFF (2000-3FFF)
wire ZRAM_SEL = ~ZBUS_A[14];
wire [7:0] ZRAM_DO;
dpram #(13) ramZ80
(
.clock(MCLK),
.address_a(ZBUS_A[12:0]),
.data_a(ZBUS_DO),
.wren_a(ZBUS_WE & ZRAM_SEL),
.q_a(ZRAM_DO)
);
always @(posedge MCLK) begin
reg [1:0] zstate;
reg [1:0] zsrc;
reg Z80_BGACK_DIS;
localparam ZSRC_MBUS = 0,
ZSRC_Z80 = 1;
localparam ZBUS_IDLE = 0,
ZBUS_READ = 1,
ZBUS_FINISH = 2;
ZBUS_WE <= 0;
if (reset) begin
MBUS_ZBUS_DTACK_N <= 1;
Z80_ZBUS_DTACK_N <= 1;
zstate <= ZBUS_IDLE;
Z80_BR_N <= 1;
Z80_BGACK_N <= 1;
Z80_BGACK_DIS <= 0;
end
else begin
if (~ZBUS_SEL) MBUS_ZBUS_DTACK_N <= 1;
if (~Z80_ZBUS_SEL) Z80_ZBUS_DTACK_N <= 1;
case (zstate)
ZBUS_IDLE:
begin
if (Z80_RD_N) Z80_ZBUS_D <= 8'hFF;
if (ZBUS_SEL & MBUS_ZBUS_DTACK_N) begin
ZBUS_A <= {MBUS_A[14:1], MBUS_UDS_N};
ZBUS_DO <= (~MBUS_UDS_N) ? MBUS_DO[15:8] : MBUS_DO[7:0];
ZBUS_WE <= ~MBUS_RNW & ZBUS_FREE;
zsrc <= ZSRC_MBUS;
zstate <= ZBUS_READ;
end
else if (Z80_ZBUS_SEL & Z80_ZBUS_DTACK_N) begin
ZBUS_A <= Z80_A[14:0];
ZBUS_DO <= Z80_DO;
ZBUS_WE <= ~Z80_WR_N;
zsrc <= ZSRC_Z80;
zstate <= ZBUS_READ;
end
end
ZBUS_READ:
zstate <= ZBUS_FINISH;
ZBUS_FINISH:
begin
case(zsrc)
ZSRC_MBUS:
begin
MBUS_ZBUS_D <= ZBUS_FREE ? ZBUS_DI : 8'hFF;
MBUS_ZBUS_DTACK_N <= 0;
end
ZSRC_Z80:
begin
Z80_ZBUS_D <= ZBUS_DI;
Z80_ZBUS_DTACK_N <= 0;
end
endcase
zstate <= ZBUS_IDLE;
end
endcase
if (Z80_MBUS_SEL && Z80_BR_N && Z80_BGACK_N && VBUS_BR_N && VBUS_BGACK_N && M68K_CLKENp) begin
Z80_BR_N <= 0;
end
else if (!Z80_BR_N && !M68K_BG_N && M68K_AS_N && M68K_CLKENn) begin
Z80_BGACK_N <= 0;
end
else if (!Z80_BGACK_N && !Z80_BR_N && !M68K_BG_N && M68K_CLKENp) begin
Z80_BR_N <= 1;
end
else if (!Z80_BGACK_DIS && !Z80_BGACK_N && Z80_BR_N && !Z80_MBUS_SEL && M68K_CLKENn) begin
Z80_BGACK_DIS <= 1;
end
else if (!Z80_BGACK_N && Z80_BGACK_DIS && M68K_CLKENn) begin
Z80_BGACK_N <= 1;
Z80_BGACK_DIS <= 0;
end
end
end
//-----------------------------------------------------------------------
// Z80 BANK REGISTER
//-----------------------------------------------------------------------
// 6000-60FF
wire BANK_SEL = ZBUS_A[14:8] == 7'h60;
reg [23:15] BAR;
always @(posedge MCLK) begin
if (reset) BAR <= 0;
else if (BANK_SEL & ZBUS_WE) BAR <= {ZBUS_DO[0], BAR[23:16]};
end
//--------------------------------------------------------------
// YM2612
//--------------------------------------------------------------
// 4000-4003 (4000-5FFF)
wire FM_SEL = ZBUS_A[14:13] == 2'b10;
wire [7:0] FM_DO;
wire signed [15:0] FM_right;
wire signed [15:0] FM_left;
wire signed [15:0] FM_LPF_right;
wire signed [15:0] FM_LPF_left;
wire signed [15:0] PRE_LPF_L;
wire signed [15:0] PRE_LPF_R;
jt12 fm
(
.rst(~Z80_RESET_N),
.clk(MCLK),
.cen(FM_CLKEN),
.cs_n(0),
.addr(ZBUS_A[1:0]),
.wr_n(~(FM_SEL & ZBUS_WE)),
.din(ZBUS_DO),
.dout(FM_DO),
.en_hifi_pcm( EN_HIFI_PCM ),
.ladder(LADDER),
.snd_left(FM_left),
.snd_right(FM_right)
);
wire signed [15:0] fm_adjust_l = (FM_left << 4) + (FM_left << 2) + (FM_left << 1) + (FM_left >>> 2);
wire signed [15:0] fm_adjust_r = (FM_right << 4) + (FM_right << 2) + (FM_right << 1) + (FM_right >>> 2);
genesis_fm_lpf fm_lpf_l
(
.clk(MCLK),
.reset(reset),
.in(fm_adjust_l),
.out(FM_LPF_left)
);
genesis_fm_lpf fm_lpf_r
(
.clk(MCLK),
.reset(reset),
.in(fm_adjust_r),
.out(FM_LPF_right)
);
wire signed [15:0] fm_select_l = ((LPF_MODE == 2'b01) ? FM_LPF_left : fm_adjust_l);
wire signed [15:0] fm_select_r = ((LPF_MODE == 2'b01) ? FM_LPF_right : fm_adjust_r);
wire signed [10:0] psg_adjust = PSG_SND - (PSG_SND >>> 5);
jt12_genmix genmix
(
.rst(reset),
.clk(MCLK),
.fm_left(fm_select_l),
.fm_right(fm_select_r),
.psg_snd(psg_adjust),
.fm_en(ENABLE_FM),
.psg_en(ENABLE_PSG),
.snd_left(PRE_LPF_L),
.snd_right(PRE_LPF_R)
);
genesis_lpf lpf_right
(
.clk(MCLK),
.reset(reset),
.lpf_mode(LPF_MODE[1:0]),
.in(PRE_LPF_R),
.out(DAC_RDATA)
);
genesis_lpf lpf_left
(
.clk(MCLK),
.reset(reset),
.lpf_mode(LPF_MODE[1:0]),
.in(PRE_LPF_L),
.out(DAC_LDATA)
);
endmodule