From fe943508069155effb1f2f57930da8ba2f721220 Mon Sep 17 00:00:00 2001 From: Gyorgy Szombathelyi Date: Sun, 9 Oct 2022 18:13:55 +0200 Subject: [PATCH 1/3] Update MiST modules --- common/mist/README.md | 4 +- common/mist/cdda_fifo.v | 107 ++++++++ common/mist/data_io.v | 324 ++++++++++++++++++++++-- common/mist/ide.v | 405 ++++++++++++++++++++++++++++++ common/mist/ide_fifo.v | 86 +++++++ common/mist/mist.qip | 4 + common/mist/mist.vhd | 3 +- common/mist/mist_video.v | 7 +- common/mist/scandoubler.v | 277 ++++++++++++--------- common/mist/sd_card.v | 3 + common/mist/user_io.v | 512 +++++++++++++++++++------------------- 11 files changed, 1335 insertions(+), 397 deletions(-) create mode 100644 common/mist/cdda_fifo.v create mode 100644 common/mist/ide.v create mode 100644 common/mist/ide_fifo.v diff --git a/common/mist/README.md b/common/mist/README.md index 588d54cd..99157a20 100644 --- a/common/mist/README.md +++ b/common/mist/README.md @@ -7,8 +7,10 @@ The modules: - user_io.v - communicating with the IO controller. - data_io.v - handling file uploads from the IO controller. - mist_video.v - a video pipeline, which gives an optional scandoubler, OSD and rgb2ypbpr conversion. -- osd.v, scandoubler.v, rgb2ypbpr.sv, cofi.sv - these are used in mist_video, but can be used separately, too. +- osd.v, scandoubler.v, rgb2ypbpr.v, cofi.sv - these are used in mist_video, but can be used separately, too. - sd_card.v - gives an SPI interface with SD-Card commands towards the IO-Controller, accessing .VHD and other mounted files. +- ide.v, ide_fifo.v - a bridge between a CPU and the data_io module for IDE/ATAPI disks. +- cdda_fifo.v - a module which connects data_io with a DAC for CDDA playback. - dac.vhd - a simple sigma-delta DAC for audio output. - arcade_inputs.v - mostly for arcade-style games, gives access to the joysticks with MAME-style keyboard mapping. - mist.vhd - VHDL component declarations for user_io and mist_video. diff --git a/common/mist/cdda_fifo.v b/common/mist/cdda_fifo.v new file mode 100644 index 00000000..d402930f --- /dev/null +++ b/common/mist/cdda_fifo.v @@ -0,0 +1,107 @@ +// +// cdda_fifo.v +// +// CDDA FIFO for the MiST board +// https://github.com/mist-devel +// +// Copyright (c) 2022 Gyorgy Szombathelyi +// +// This source file 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 3 of the License, or +// (at your option) any later version. +// +// This source file 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, see . +// +/////////////////////////////////////////////////////////////////////// + +module cdda_fifo +( + input clk_sys, + input clk_en, // set to 1 when using the stock data_io + input cen_44100, // 44100 HZ clock enable + input reset, + + // data_io interface + output hdd_cdda_req, + input hdd_cdda_wr, + input [15:0] hdd_data_out, + + // sample output + output reg [15:0] cdda_l, + output reg [15:0] cdda_r +); + +// 4k x 16bit default FIFO size +parameter FIFO_DEPTH = 12; +reg [15:0] fifo[2**FIFO_DEPTH]; +reg [FIFO_DEPTH-1:0] inptr; +reg [FIFO_DEPTH-1:0] outptr; +reg [15:0] fifo_out; + +wire [FIFO_DEPTH:0] fifo_used = inptr >= outptr ? + inptr - outptr : + inptr - outptr + (2'd2**FIFO_DEPTH); + +assign hdd_cdda_req = fifo_used < ((2'd2**FIFO_DEPTH) - 16'd2352); + +always @(posedge clk_sys) begin + if (reset) + inptr <= 0; + else if (clk_en && hdd_cdda_wr) begin + fifo[inptr] <= {hdd_data_out[7:0], hdd_data_out[15:8]}; + inptr <= inptr + 1'd1; + end +end + +always @(posedge clk_sys) fifo_out <= fifo[outptr]; + +reg left = 0; +reg mute = 1; +reg fifo_active = 0; + +always @(posedge clk_sys) begin + if (reset) begin + outptr <= 0; + fifo_active <= 0; + mute <= 1; + left <= 0; + cdda_l <= 0; + cdda_r <= 0; + end else begin + if (cen_44100) begin + if (fifo_used >= 2352) + fifo_active <= 1; + if (outptr + 2'd2 == inptr) + fifo_active <= 0; + if (fifo_active) begin + outptr <= outptr + 1'd1; + left <= 1; + mute <= 0; + end else + mute <= 1; + end + if (left) begin + outptr <= outptr + 1'd1; + left <= 0; + end + + if (mute) begin + cdda_l <= 0; + cdda_r <= 0; + end else begin + if (left) + cdda_l <= fifo_out; + else + cdda_r <= fifo_out; + end + end +end + +endmodule diff --git a/common/mist/data_io.v b/common/mist/data_io.v index 7e14f129..6862f1f4 100644 --- a/common/mist/data_io.v +++ b/common/mist/data_io.v @@ -2,7 +2,7 @@ // data_io.v // // data_io for the MiST board -// http://code.google.com/p/mist-board/ +// https://github.com/mist-devel // // Copyright (c) 2014 Till Harbaum // @@ -30,6 +30,10 @@ module data_io input SPI_DI, inout SPI_DO, + input QCSn, + input QSCK, + input [3:0] QDAT, + input clkref_n, // assert ioctl_wr one cycle after clkref stobe (negative active) // ARM -> FPGA download @@ -43,52 +47,105 @@ module data_io output reg [7:0] ioctl_dout, input [7:0] ioctl_din, output reg [23:0] ioctl_fileext, // file extension - output reg [31:0] ioctl_filesize // file size + output reg [31:0] ioctl_filesize, // file size + + // IDE interface + input hdd_clk, + input hdd_cmd_req, + input hdd_cdda_req, + input hdd_dat_req, + output hdd_cdda_wr, + output hdd_status_wr, + output [2:0] hdd_addr = 0, + output hdd_wr, + + output [15:0] hdd_data_out, + input [15:0] hdd_data_in, + output hdd_data_rd, + output hdd_data_wr, + + // IDE config + output [1:0] hdd0_ena, + output [1:0] hdd1_ena ); parameter START_ADDR = 25'd0; parameter ROM_DIRECT_UPLOAD = 0; +parameter USE_QSPI = 0; +parameter ENABLE_IDE = 0; /////////////////////////////// DOWNLOADING /////////////////////////////// +reg [6:0] sbuf; reg [7:0] data_w; reg [7:0] data_w2 = 0; +reg [7:0] data_w3 = 0; reg [3:0] cnt; +reg [7:0] cmd; +reg [6:0] bytecnt; + reg rclk = 0; reg rclk2 = 0; +reg rclk3 = 0; reg addr_reset = 0; reg downloading_reg = 0; reg uploading_reg = 0; reg reg_do; -localparam DIO_FILE_TX = 8'h53; -localparam DIO_FILE_TX_DAT = 8'h54; -localparam DIO_FILE_INDEX = 8'h55; -localparam DIO_FILE_INFO = 8'h56; -localparam DIO_FILE_RX = 8'h57; -localparam DIO_FILE_RX_DAT = 8'h58; +localparam DIO_FILE_TX = 8'h53; +localparam DIO_FILE_TX_DAT = 8'h54; +localparam DIO_FILE_INDEX = 8'h55; +localparam DIO_FILE_INFO = 8'h56; +localparam DIO_FILE_RX = 8'h57; +localparam DIO_FILE_RX_DAT = 8'h58; + +localparam QSPI_READ = 8'h40; +localparam QSPI_WRITE = 8'h41; + +localparam CMD_IDE_REGS_RD = 8'h80; +localparam CMD_IDE_REGS_WR = 8'h90; +localparam CMD_IDE_DATA_WR = 8'hA0; +localparam CMD_IDE_DATA_RD = 8'hB0; +localparam CMD_IDE_CDDA_RD = 8'hC0; +localparam CMD_IDE_CDDA_WR = 8'hD0; +localparam CMD_IDE_STATUS_WR = 8'hF0; +localparam CMD_IDE_CFG_WR = 8'hFA; assign SPI_DO = reg_do; // data_io has its own SPI interface to the io controller +wire [7:0] cmdcode = { 4'h0, hdd_dat_req, hdd_cmd_req, 2'b00 }; + always@(negedge SPI_SCK or posedge SPI_SS2) begin : SPI_TRANSMITTER reg [7:0] dout_r; if(SPI_SS2) begin reg_do <= 1'bZ; end else begin - if (cnt == 15) dout_r <= ioctl_din; + if (cnt == 0) dout_r <= cmdcode; + if (cnt == 15) begin + case(cmd) + CMD_IDE_REGS_RD, + CMD_IDE_DATA_RD: + dout_r <= bytecnt[0] ? hdd_data_in[7:0] : hdd_data_in[15:8]; + + CMD_IDE_CDDA_RD: + dout_r <= {7'd0, hdd_cdda_req}; + + DIO_FILE_RX_DAT: + dout_r <= ioctl_din; + + default: + dout_r <= 0; + + endcase + end reg_do <= dout_r[~cnt[2:0]]; end end always@(posedge SPI_SCK, posedge SPI_SS2) begin : SPI_RECEIVER - reg [6:0] sbuf; - reg [24:0] addr; - reg [7:0] cmd; - reg [5:0] bytecnt; - if(SPI_SS2) begin bytecnt <= 0; cnt <= 0; @@ -105,6 +162,9 @@ always@(posedge SPI_SCK, posedge SPI_SS2) begin : SPI_RECEIVER if(cnt == 7) cmd <= {sbuf, SPI_DI}; if(cnt == 15) begin + if (~&bytecnt) bytecnt <= bytecnt + 1'd1; + else bytecnt[0] <= ~bytecnt[0]; + case (cmd) // prepare/end transmission DIO_FILE_TX: begin @@ -140,7 +200,6 @@ always@(posedge SPI_SCK, posedge SPI_SS2) begin : SPI_RECEIVER // receiving FAT directory entry (mist-firmware/fat.h - DIRENTRY) DIO_FILE_INFO: begin - bytecnt <= bytecnt + 1'd1; case (bytecnt) 8'h08: ioctl_fileext[23:16] <= {sbuf, SPI_DI}; 8'h09: ioctl_fileext[15: 8] <= {sbuf, SPI_DI}; @@ -157,7 +216,7 @@ always@(posedge SPI_SCK, posedge SPI_SS2) begin : SPI_RECEIVER end // direct SD Card->FPGA transfer -generate if (ROM_DIRECT_UPLOAD == 1) begin +generate if (ROM_DIRECT_UPLOAD || ENABLE_IDE) begin always@(posedge SPI_SCK, posedge SPI_SS4) begin : SPI_DIRECT_RECEIVER reg [6:0] sbuf2; @@ -192,19 +251,50 @@ end end endgenerate +// QSPI receiver +generate if (USE_QSPI) begin + +always@(negedge QSCK, posedge QCSn) begin : QSPI_RECEIVER + reg nibble_lo; + reg cmd_got; + reg cmd_write; + + if (QCSn) begin + cmd_got <= 0; + cmd_write <= 0; + nibble_lo <= 0; + end else begin + nibble_lo <= ~nibble_lo; + if (nibble_lo) begin + data_w3[3:0] <= QDAT; + if (!cmd_got) begin + cmd_got <= 1; + if ({data_w3[7:4], QDAT} == QSPI_WRITE) cmd_write <= 1; + end else begin + if (cmd_write) rclk3 <= ~rclk3; + end + end else + data_w3[7:4] <= QDAT; + end +end +end +endgenerate + always@(posedge clk_sys) begin : DATA_OUT // synchronisers reg rclkD, rclkD2; reg rclk2D, rclk2D2; + reg rclk3D, rclk3D2; reg addr_resetD, addr_resetD2; - reg wr_int, wr_int_direct, rd_int; + reg wr_int, wr_int_direct, wr_int_qspi, rd_int; reg [24:0] addr; reg [31:0] filepos; // bring flags from spi clock domain into core clock domain { rclkD, rclkD2 } <= { rclk, rclkD }; { rclk2D ,rclk2D2 } <= { rclk2, rclk2D }; + { rclk3D ,rclk3D2 } <= { rclk3, rclk3D }; { addr_resetD, addr_resetD2 } <= { addr_reset, addr_resetD }; ioctl_wr <= 0; @@ -224,8 +314,9 @@ always@(posedge clk_sys) begin : DATA_OUT rd_int <= 0; wr_int <= 0; wr_int_direct <= 0; - if (wr_int || wr_int_direct) begin - ioctl_dout <= wr_int ? data_w : data_w2; + wr_int_qspi <= 0; + if (wr_int || wr_int_direct || wr_int_qspi) begin + ioctl_dout <= wr_int ? data_w : wr_int_direct ? data_w2 : data_w3; ioctl_wr <= 1; addr <= addr + 1'd1; ioctl_addr <= addr; @@ -250,10 +341,203 @@ always@(posedge clk_sys) begin : DATA_OUT rd_int <= uploading_reg; end // direct transfer receiver - if (rclk2D ^ rclk2D2 && filepos != ioctl_filesize) begin + if (rclk2D ^ rclk2D2 && filepos != ioctl_filesize && downloading_reg) begin filepos <= filepos + 1'd1; wr_int_direct <= 1; end + // QSPI transfer receiver + if (rclk3D ^ rclk3D2) begin + wr_int_qspi <= downloading_reg; + end + end +// IDE handling +generate if (ENABLE_IDE) begin + +reg [1:0] int_hdd0_ena; +reg [1:0] int_hdd1_ena; +reg int_hdd_cdda_wr; +reg int_hdd_status_wr; +reg [2:0] int_hdd_addr = 0; +reg int_hdd_wr; +reg [15:0] int_hdd_data_out; +reg int_hdd_data_rd; +reg int_hdd_data_wr; + +assign hdd0_ena = int_hdd0_ena; +assign hdd1_ena = int_hdd1_ena; +assign hdd_cdda_wr = int_hdd_cdda_wr; +assign hdd_status_wr = int_hdd_status_wr; +assign hdd_addr = int_hdd_addr; +assign hdd_wr = int_hdd_wr; +assign hdd_data_out = int_hdd_data_out; +assign hdd_data_rd = int_hdd_data_rd; +assign hdd_data_wr = int_hdd_data_wr; + +reg rst0 = 1; +reg rst2 = 1; +reg rclk_ide_stat = 0; +reg rclk_ide_regs_rd = 0; +reg rclk_ide_regs_wr = 0; +reg rclk_ide_wr = 0; +reg rclk_ide_rd = 0; +reg rclk_cdda_wr = 0; +reg [7:0] data_ide; + +always@(posedge SPI_SCK, posedge SPI_SS2) begin : SPI_RECEIVER_IDE + if(SPI_SS2) begin + rst0 <= 1; + end else begin + rst0 <= 0; + + if(cnt == 15) begin + + case (cmd) + //IDE commands + CMD_IDE_CFG_WR: + if (bytecnt == 0) begin + int_hdd0_ena <= {sbuf[0], SPI_DI}; + int_hdd1_ena <= sbuf[2:1]; + end + + CMD_IDE_STATUS_WR: + if (bytecnt == 0) begin + data_ide <= {sbuf, SPI_DI}; + rclk_ide_stat <= ~rclk_ide_stat; + end + + CMD_IDE_REGS_WR: + if (bytecnt >= 8 && bytecnt <= 18 && !bytecnt[0]) begin + data_ide <= {sbuf, SPI_DI}; + rclk_ide_regs_wr <= ~rclk_ide_regs_wr; + end + + CMD_IDE_REGS_RD: + if (bytecnt > 5 && !bytecnt[0]) begin + rclk_ide_regs_rd <= ~rclk_ide_regs_rd; + end + + CMD_IDE_DATA_WR: + if (bytecnt > 4) begin + data_ide <= {sbuf, SPI_DI}; + rclk_ide_wr <= ~rclk_ide_wr; + end + + CMD_IDE_CDDA_WR: + if (bytecnt > 4) begin + data_ide <= {sbuf, SPI_DI}; + rclk_cdda_wr <= ~rclk_cdda_wr; + end + + CMD_IDE_DATA_RD: + if (bytecnt > 3) rclk_ide_rd <= ~rclk_ide_rd; + + endcase + end + end +end + +always@(posedge SPI_SCK, posedge SPI_SS4) begin : SPI_DIRECT_RECEIVER_IDE + if(SPI_SS4) begin + rst2 <= 1; + end else begin + rst2 <= 0; + end +end + +always@(posedge hdd_clk) begin : IDE_OUT + reg loword; + + // synchronisers + reg rclk2D, rclk2D2; + reg rclk_ide_statD, rclk_ide_statD2; + reg rclk_cdda_wrD, rclk_cdda_wrD2; + reg rclk_ide_wrD, rclk_ide_wrD2; + reg rclk_ide_rdD, rclk_ide_rdD2; + reg rclk_ide_regs_wrD, rclk_ide_regs_wrD2; + reg rclk_ide_regs_rdD, rclk_ide_regs_rdD2; + reg rst0D, rst0D2; + reg rst2D, rst2D2; + + // bring flags from spi clock domain into core clock domain + { rclk2D ,rclk2D2 } <= { rclk2, rclk2D }; + { rclk_ide_statD, rclk_ide_statD2 } <= { rclk_ide_stat, rclk_ide_statD }; + { rclk_ide_rdD, rclk_ide_rdD2 } <= { rclk_ide_rd, rclk_ide_rdD }; + { rclk_ide_wrD, rclk_ide_wrD2 } <= { rclk_ide_wr, rclk_ide_wrD }; + { rclk_cdda_wrD, rclk_cdda_wrD2 } <= { rclk_cdda_wr, rclk_cdda_wrD }; + { rclk_ide_regs_rdD, rclk_ide_regs_rdD2 } <= { rclk_ide_regs_rd, rclk_ide_regs_rdD }; + { rclk_ide_regs_wrD, rclk_ide_regs_wrD2 } <= { rclk_ide_regs_wr, rclk_ide_regs_wrD }; + { rst0D, rst0D2 } <= { rst0, rst0D }; + { rst2D, rst2D2 } <= { rst2, rst2D }; + + // IDE receiver + int_hdd_wr <= 0; + int_hdd_status_wr <= 0; + int_hdd_data_wr <= 0; + int_hdd_data_rd <= 0; + int_hdd_cdda_wr <= 0; + + if (rst0D2) int_hdd_addr <= 0; + if (rst0D2 && rst2D2) loword <= 0; + + if (rclk_ide_statD ^ rclk_ide_statD2) begin + int_hdd_status_wr <= 1; + int_hdd_data_out <= {8'h00, data_ide}; + end + if (rclk_ide_rdD ^ rclk_ide_rdD2) begin + loword <= ~loword; + if (loword) + int_hdd_data_rd <= 1; + end + if (rclk_ide_wrD ^ rclk_ide_wrD2) begin + loword <= ~loword; + if (!loword) + int_hdd_data_out[15:8] <= data_ide; + else begin + int_hdd_data_wr <= 1; + int_hdd_data_out[7:0] <= data_ide; + end + end + if (rclk_cdda_wrD ^ rclk_cdda_wrD2) begin + loword <= ~loword; + if (!loword) + int_hdd_data_out[15:8] <= data_ide; + else begin + int_hdd_cdda_wr <= 1; + int_hdd_data_out[7:0] <= data_ide; + end + end + if (rclk2D ^ rclk2D2 && !downloading_reg) begin + loword <= ~loword; + if (!loword) + int_hdd_data_out[15:8] <= data_w2; + else begin + int_hdd_data_wr <= 1; + int_hdd_data_out[7:0] <= data_w2; + end + end + if (rclk_ide_regs_wrD ^ rclk_ide_regs_wrD2) begin + int_hdd_wr <= 1; + int_hdd_data_out <= {8'h00, data_ide}; + int_hdd_addr <= int_hdd_addr + 1'd1; + end + if (rclk_ide_regs_rdD ^ rclk_ide_regs_rdD2) begin + int_hdd_addr <= int_hdd_addr + 1'd1; + end +end +end else begin + assign hdd0_ena = 0; + assign hdd1_ena = 0; + assign hdd_cdda_wr = 0; + assign hdd_status_wr = 0; + assign hdd_addr = 0; + assign hdd_wr = 0; + assign hdd_data_out = 0; + assign hdd_data_rd = 0; + assign hdd_data_wr = 0; +end + +endgenerate + endmodule diff --git a/common/mist/ide.v b/common/mist/ide.v new file mode 100644 index 00000000..393699c4 --- /dev/null +++ b/common/mist/ide.v @@ -0,0 +1,405 @@ +// Copyright 2008, 2009 by Jakub Bednarski +// +// Extracted from Minimig gayle.v +// +// Minimig 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 3 of the License, or +// (at your option) any later version. +// +// Minimig 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, see . +// +// +// +// -- JB -- +// +// 2008-10-06 - initial version +// 2008-10-08 - interrupt controller implemented, kickstart boots +// 2008-10-09 - working identify device command implemented (hdtoolbox detects our drive) +// - read command reads data from hardfile (fixed size and name, only one sector read size supported, workbench sees hardfile partition) +// 2008-10-10 - multiple sector transfer supported: works ok, sequential transfers with direct spi read and 28MHz CPU from 400 to 520 KB/s +// - arm firmare seekfile function very slow: seeking from start to 20MB takes 144 ms (some software improvements required) +// 2008-10-30 - write support added +// 2008-12-31 - added hdd enable +// 2009-05-24 - clean-up & renaming +// 2009-08-11 - hdd_ena enables Master & Slave drives +// 2009-11-18 - changed sector buffer size +// 2010-04-13 - changed sector buffer size +// 2010-08-10 - improved BSY signal handling +// 2022-08-18 - added packet command handling + +module ide +( + input clk, + input clk_en, + input reset, + input [2:0] address_in, + input sel_secondary, + input [15:0] data_in, + output [15:0] data_out, + output data_oe, + input rd, + input hwr, + input lwr, + input sel_ide, + output reg [1:0] intreq, + input [1:0] intreq_ack, // interrupt clear + output nrdy, // fifo is not ready for reading + input [1:0] hdd0_ena, // enables Master & Slave drives on primary channel + input [1:0] hdd1_ena, // enables Master & Slave drives on secondary channel + output fifo_rd, + output fifo_wr, + + // connection to the IO-Controller + output hdd_cmd_req, + output hdd_dat_req, + input [2:0] hdd_addr, + input [15:0] hdd_data_out, + output [15:0] hdd_data_in, + input hdd_wr, + input hdd_status_wr, + input hdd_data_wr, + input hdd_data_rd +); + +localparam VCC = 1'b1; +localparam GND = 1'b0; + +/* +0 Data +1 Error | Feature +2 SectorCount +3 SectorNumber +4 CylinderLow +5 CylinderHigh +6 Device/Head +7 Status | Command + +command class: +PI (PIO In) +PO (PIO Out) +ND (No Data) + +Status: +#6 - DRDY - Drive Ready +#7 - BSY - Busy +#3 - DRQ - Data Request +#0 - ERR - Error +INTRQ - Interrupt Request + +*/ + + +// address decoding signals +wire sel_tfr; // HDD task file registers select +wire sel_fifo; // HDD data port select (FIFO buffer) +wire sel_status /* synthesis keep */; // HDD status register select +wire sel_command /* synthesis keep */;// HDD command register select + +// internal registers +reg block_mark; // IDE multiple block start flag +reg busy; // busy status (command processing state) +reg pio_in; // pio in command type is being processed +reg pio_out; // pio out command type is being processed +reg error; // error status (command processing failed) + +reg [1:0] dev; // drive select (Primary/Secondary, Master/Slave) +wire bsy; // busy +wire drdy; // drive ready +wire drq; // data request +reg drq_d; // data request +wire err; // error +wire [7:0] status; // HDD status + +// FIFO control +wire fifo_reset; +wire [15:0] fifo_data_in; +wire [15:0] fifo_data_out; +wire fifo_full; +wire fifo_empty; +wire fifo_last_out; // last word of a sector is being read +wire fifo_last_in; // last word of a sector is being written + + +// HDD status register +assign status = {bsy,drdy,2'b01,drq,2'b00,err}; + +// packet states +reg [1:0] packet_state; +localparam PACKET_IDLE = 0; +localparam PACKET_WAITCMD = 1; +localparam PACKET_PROCESSCMD = 2; +wire packet_state_change; +reg [12:0] packet_count; +wire packet_in_last; +wire packet_in; +wire packet_out; + +`ifdef IDE_DEBUG +// cmd/status debug +reg [7:0] status_dbg /* synthesis noprune */; +reg [7:0] dbg_ide_cmd /* synthesis noprune */; +reg [2:0] dbg_addr /* synthesis noprune */; +reg dbg_wr /* synthesis noprune */; +reg[15:0] dbg_data_in /* synthesis noprune */; +reg[15:0] dbg_data_out /* synthesis noprune */; + +always @(posedge clk) begin + status_dbg <= status; + if (clk_en) begin + dbg_wr <= 0; + if (sel_command) // set when the CPU writes command register + dbg_ide_cmd <= data_in[15:8]; + if (sel_ide) begin + dbg_addr <= address_in; + dbg_wr <= hwr | lwr; + if (rd) dbg_data_out <= data_out; + if (hwr | lwr) dbg_data_in <= data_in; + end + end +end +`endif + +// HDD status register bits +assign bsy = busy & ~drq; +assign drdy = ~(bsy|drq); +assign err = error; + +// address decoding +assign sel_tfr = sel_ide; +assign sel_status = rd && sel_tfr && address_in==3'b111 ? VCC : GND; +assign sel_command = hwr && sel_tfr && address_in==3'b111 ? VCC : GND; +assign sel_fifo = sel_tfr && address_in==3'b000 ? VCC : GND; + +//===============================================================================================// + +// task file registers +reg [7:0] tfr [7:0]; +wire [2:0] tfr_sel; +wire [7:0] tfr_in; +wire [7:0] tfr_out; +wire tfr_we; + +reg [8:0] sector_count; // sector counter +wire sector_count_dec_in; // decrease sector counter (reads) +wire sector_count_dec_out; // decrease sector counter (writes) + +always @(posedge clk) + if (clk_en) begin + if (hwr && sel_tfr && address_in == 3'b010) begin // sector count register loaded by the host + sector_count <= {1'b0, data_in[15:8]}; + if (data_in[15:8] == 0) sector_count <= 9'd256; + end else if (sector_count_dec_in || sector_count_dec_out) + sector_count <= sector_count - 8'd1; + end + +reg rd_old; +reg wr_old; +reg sel_fifo_old; +always @(posedge clk) + if (clk_en) begin + rd_old <= rd; + wr_old <= hwr & lwr; + sel_fifo_old <= sel_fifo; + end + +assign sector_count_dec_in = pio_in & fifo_last_out & sel_fifo_old & ~rd & rd_old & packet_state == PACKET_IDLE; +assign sector_count_dec_out = pio_out & fifo_last_in & sel_fifo_old & ~hwr & ~lwr & wr_old & packet_state == PACKET_IDLE; + +// task file register control +assign tfr_we = packet_in_last ? 1'b1 : bsy ? hdd_wr : sel_tfr & hwr; +assign tfr_sel = packet_in_last ? 3'd2 : bsy ? hdd_addr : address_in; +assign tfr_in = packet_in_last ? 8'h03: bsy ? hdd_data_out[7:0] : data_in[15:8]; + +// input multiplexer for SPI host +assign hdd_data_in = tfr_sel==0 ? fifo_data_out : {7'h0, dev[1], tfr_out}; + +// task file registers +always @(posedge clk) + if (clk_en) begin + if (tfr_we) + tfr[tfr_sel] <= tfr_in; + end + +assign tfr_out = tfr[tfr_sel]; + +// master/slave drive select +always @(posedge clk) + if (clk_en) begin + if (reset) + dev <= 0; + else if (sel_tfr && address_in==6 && hwr) + dev <= {sel_secondary, data_in[12]}; + end + +assign packet_state_change = busy && hdd_status_wr && hdd_data_out[5]; + +// bytes count in a packet +always @(posedge clk) + if (clk_en) begin + if (reset) + packet_count <= 0; + else if (hdd_wr && hdd_addr == 4) + packet_count[6:0] <= hdd_data_out[7:1]; + else if (hdd_wr && hdd_addr == 5) + packet_count[12:7] <= hdd_data_out[5:0]; + else if (packet_state_change && packet_state == PACKET_IDLE) + packet_count <= 13'd6; // IDLE->WAITCMD transition, expect 6 words of packet command + end + +// status register (write only from SPI host) +// 7 - busy status (write zero to finish command processing: allow host access to task file registers) +// 6 +// 5 +// 4 - intreq (used for writes only) +// 3 - drq enable for pio in (PI) command type +// 2 - drq enable for pio out (PO) command type +// 1 +// 0 - error flag (remember about setting error task file register) + +// command busy status +always @(posedge clk) + if (clk_en) begin + if (reset) + busy <= GND; + else if (hdd_status_wr && hdd_data_out[7] || (sector_count_dec_in && sector_count == 9'h01)) // reset by SPI host (by clearing BSY status bit) + busy <= GND; + else if (sel_command) // set when the CPU writes command register + busy <= VCC; + end + +// IDE interrupt request register +always @(posedge clk) + if (clk_en) begin + drq_d <= drq; + + if (reset) begin + intreq[0] <= GND; + intreq[1] <= GND; + block_mark <= GND; + end else begin + if (busy && hdd_status_wr && hdd_data_out[3]) + block_mark <= VCC; // to handle IDENTIFY + + if (pio_in) begin // reads + if (hdd_status_wr && hdd_data_out[4]) + block_mark <= VCC; + if ((error | (!drq_d & drq)) & block_mark) begin + intreq[dev[1]] <= VCC; + block_mark <= GND; + end + if (packet_in_last) // read the last word from the packet command result + intreq[dev[1]] <= VCC; + end else if (pio_out) begin // writes + if (hdd_status_wr && hdd_data_out[4]) + intreq[dev[1]] <= VCC; + end else if (hdd_status_wr && hdd_data_out[7]) // other command types completed + intreq[dev[1]] <= VCC; + else if (packet_state_change && packet_state == PACKET_IDLE) // ready to accept command packet + intreq[dev[1]] <= VCC; + + if (intreq_ack[0]) intreq[0] <= GND; // cleared by the CPU + if (intreq_ack[1]) intreq[1] <= GND; // cleared by the CPU + + end + end + +// pio in command type +always @(posedge clk) + if (clk_en) begin + if (reset) + pio_in <= GND; + else if (drdy) // reset when processing of the current command ends + pio_in <= GND; + else if (busy && hdd_status_wr && hdd_data_out[3]) // set by SPI host + pio_in <= VCC; + end + +// pio out command type +always @(posedge clk) + if (clk_en) begin + if (reset) + pio_out <= GND; + else if (busy && hdd_status_wr && hdd_data_out[7]) // reset by SPI host when command processing completes + pio_out <= GND; + else if (busy && hdd_status_wr && hdd_data_out[3]) // pio_in set by SPI host (during PACKET processing) + pio_out <= GND; + else if (busy && hdd_status_wr && hdd_data_out[2]) // set by SPI host + pio_out <= VCC; + end + +// packet command state machine +always @(posedge clk) + if (clk_en) begin + if (reset) + packet_state <= PACKET_IDLE; + else if (drdy) // reset when processing of the current command ends + packet_state <= PACKET_IDLE; + else if (packet_state_change) // set by SPI host + packet_state <= packet_state == PACKET_IDLE ? PACKET_WAITCMD : + packet_state == PACKET_WAITCMD ? PACKET_PROCESSCMD : packet_state; + end + +assign drq = (fifo_full & pio_in) | (~fifo_full & pio_out & (sector_count != 0 || packet_out)); // HDD data request status bit + +// error status +always @(posedge clk) + if (clk_en) begin + if (reset) + error <= GND; + else if (sel_command) // reset by the CPU when command register is written + error <= GND; + else if (busy && hdd_status_wr && hdd_data_out[0]) // set by SPI host + error <= VCC; + end + +assign hdd_cmd_req = bsy; // bsy is set when command register is written, tells the SPI host about new command +assign hdd_dat_req = (fifo_full & pio_out); // the FIFO is full so SPI host may read it + +// FIFO in/out multiplexer +assign fifo_reset = reset | sel_command | packet_state_change | packet_in_last; +assign fifo_data_in = pio_in ? hdd_data_out : data_in; +assign fifo_rd = pio_out ? hdd_data_rd : sel_fifo & rd; +assign fifo_wr = pio_in ? hdd_data_wr : sel_fifo & hwr & lwr; + +assign packet_in = packet_state == PACKET_PROCESSCMD && pio_in; +assign packet_out = packet_state == PACKET_WAITCMD || (packet_state == PACKET_PROCESSCMD && pio_out); + +//sector data buffer (FIFO) +ide_fifo SECBUF1 +( + .clk(clk), + .clk_en(clk_en), + .reset(fifo_reset), + .data_in(fifo_data_in), + .data_out(fifo_data_out), + .rd(fifo_rd), + .wr(fifo_wr), + .packet_in(packet_in), + .packet_out(packet_out), + .packet_count(packet_count), + .packet_in_last(packet_in_last), + .full(fifo_full), + .empty(fifo_empty), + .last_out(fifo_last_out), + .last_in(fifo_last_in) +); + +// fifo is not ready for reading +assign nrdy = pio_in & sel_fifo & fifo_empty; + +assign data_oe = (!dev[1] && hdd0_ena[dev[0]]) || (dev[1] && hdd1_ena[dev[0]]); +//data_out multiplexer +assign data_out = sel_fifo && rd ? fifo_data_out : + sel_status ? data_oe ? {status,8'h00} : 16'h00_00 : + sel_tfr && rd ? {tfr_out,8'h00} : 16'h00_00; + +//===============================================================================================// + +endmodule diff --git a/common/mist/ide_fifo.v b/common/mist/ide_fifo.v new file mode 100644 index 00000000..24221efe --- /dev/null +++ b/common/mist/ide_fifo.v @@ -0,0 +1,86 @@ +module ide_fifo +( + input clk, // bus clock + input clk_en, + input reset, // reset + input [15:0] data_in, // data in + output reg [15:0] data_out, // data out + input rd, // read from fifo + input wr, // write to fifo + input packet_in, + input packet_out, + input [12:0] packet_count, + output packet_in_last, // last word is read in packet_in state + output full, // fifo is full + output empty, // fifo is empty + output last_out, // the last word of a sector is being read + output last_in // the last word of a sector is being written +); + +// local signals and registers +reg [15:0] mem [4095:0]; // 16 bit wide fifo memory +reg [12:0] inptr; // fifo input pointer +reg [12:0] outptr; // fifo output pointer +wire empty_rd; // fifo empty flag (set immediately after reading the last word) +reg empty_wr; // fifo empty flag (set one clock after writting the empty fifo) +reg rd_old; +reg wr_old; + +always @(posedge clk) + if (clk_en) begin + rd_old <= rd; + wr_old <= wr; + end + +// main fifo memory (implemented using synchronous block ram) +always @(posedge clk) + if (clk_en) begin + if (wr) + mem[inptr[11:0]] <= data_in; + end + +always @(posedge clk) + if (clk_en) + data_out <= mem[outptr[11:0]]; + +// fifo write pointer control +always @(posedge clk) + if (clk_en) begin + if (reset) + inptr <= 0; + else if (wr_old & ~wr) + inptr <= inptr + 1'd1; + end + +// fifo read pointer control +always @(posedge clk) + if (clk_en) begin + if (reset) + outptr <= 0; + else if (rd_old & ~rd) + outptr <= outptr + 1'd1; + end + +// the empty flag is set immediately after reading the last word from the fifo +assign empty_rd = inptr==outptr ? 1'b1 : 1'b0; + +// after writting empty fifo the empty flag is delayed by one clock to handle ram write delay +always @(posedge clk) + if (clk_en) + empty_wr <= empty_rd; + +assign empty = empty_rd | empty_wr; + +// at least 512 bytes are in FIFO +// this signal is activated when 512th byte is written to the empty fifo +// then it's deactivated when 512th byte is read from the fifo (hysteresis) +// special handlig of packet commands +assign full = (inptr[12:8] != outptr[12:8] && !packet_in && !packet_out) || + (packet_in && inptr == packet_count && inptr != outptr) || + (packet_out && inptr == packet_count /*&& inptr != outptr*/); +assign packet_in_last = packet_in && inptr == packet_count && inptr == outptr && inptr != 0; + +assign last_out = outptr[7:0] == 8'hFF ? 1'b1 : 1'b0; +assign last_in = inptr [7:0] == 8'hFF ? 1'b1 : 1'b0; + +endmodule diff --git a/common/mist/mist.qip b/common/mist/mist.qip index de360210..923b5289 100644 --- a/common/mist/mist.qip +++ b/common/mist/mist.qip @@ -7,4 +7,8 @@ set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) osd.v] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) arcade_inputs.v] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) rgb2ypbpr.v] set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) cofi.sv] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) sd_card.v] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ide.v] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) ide_fifo.v] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) cdda_fifo.v] set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) dac.vhd] diff --git a/common/mist/mist.vhd b/common/mist/mist.vhd index d37c947c..2255c8b7 100644 --- a/common/mist/mist.vhd +++ b/common/mist/mist.vhd @@ -48,6 +48,7 @@ port ( sd_wr : in std_logic_vector(SD_IMAGES-1 downto 0) := (others => '0'); sd_ack : out std_logic; sd_ack_conf : out std_logic; + sd_ack_x : out std_logic_vector(SD_IMAGES-1 downto 0); sd_conf : in std_logic := '0'; sd_sdhc : in std_logic := '1'; img_size : out std_logic_vector(63 downto 0); @@ -99,7 +100,7 @@ port ( SPI_DI : in std_logic; scanlines : in std_logic_vector(1 downto 0); - ce_divider : in std_logic := '0'; + ce_divider : in std_logic_vector(2 downto 0) := "000"; scandoubler_disable : in std_logic; ypbpr : in std_logic; rotate : in std_logic_vector(1 downto 0); diff --git a/common/mist/mist_video.v b/common/mist/mist_video.v index 070ab50b..712b1dff 100644 --- a/common/mist/mist_video.v +++ b/common/mist/mist_video.v @@ -15,8 +15,9 @@ module mist_video // scanlines (00-none 01-25% 10-50% 11-75%) input [1:0] scanlines, - // non-scandoubled pixel clock divider 0 - clk_sys/4, 1 - clk_sys/2 - input ce_divider, + // non-scandoubled pixel clock divider: + // 0 - clk_sys/4, 1 - clk_sys/2, 2 - clk_sys/3, 3 - clk_sys/4, etc + input [2:0] ce_divider, // 0 = HVSync 31KHz, 1 = CSync 15KHz input scandoubler_disable, @@ -59,7 +60,7 @@ wire [5:0] SD_B_O; wire SD_HS_O; wire SD_VS_O; -wire pixel_ena; +wire pixel_ena; scandoubler #(SD_HCNT_WIDTH, COLOR_DEPTH) scandoubler ( diff --git a/common/mist/scandoubler.v b/common/mist/scandoubler.v index c9f0d684..8c54632b 100644 --- a/common/mist/scandoubler.v +++ b/common/mist/scandoubler.v @@ -18,12 +18,25 @@ // TODO: Delay vsync one line +// AMR - generates and output a pixel clock with a reliable phase relationship with +// with the scandoubled hsync pulse. Allows the incoming data to be sampled more +// sparsely, reducing block RAM usage. ce_x1/x2 are replaced with a ce_divider +// which is the largest value the counter will reach before resetting - so 3'111 to +// divide clk_sys by 8, 3'011 to divide by 4, 3'101 to divide by six. + +// Also now has a bypass mode, in which the incoming data will be scaled to the output +// width but otherwise unmodified. Simplifies the rest of the video chain. + + module scandoubler ( // system interface input clk_sys, + input bypass, - input ce_divider, + + // Pixelclock + input [2:0] ce_divider, // 0 - clk_sys/4, 1 - clk_sys/2, 2 - clk_sys/3, 3 - clk_sys/4, etc. output pixel_ena, // scanlines (00-none 01-25% 10-50% 11-75%) @@ -37,41 +50,16 @@ module scandoubler input [COLOR_DEPTH-1:0] b_in, // output interface - output reg hs_out, - output reg vs_out, - output reg [5:0] r_out, - output reg [5:0] g_out, - output reg [5:0] b_out + output hs_out, + output vs_out, + output [5:0] r_out, + output [5:0] g_out, + output [5:0] b_out ); -parameter HCNT_WIDTH = 9; -parameter COLOR_DEPTH = 6; - -// pixel clock divider -reg [1:0] i_div; -reg ce_x1, ce_x2; - -always @(posedge clk_sys) begin - reg last_hs_in; - last_hs_in <= hs_in; - if(last_hs_in & !hs_in) begin - i_div <= 2'b00; - end else begin - i_div <= i_div + 2'd1; - end -end - -always @(*) begin - if (!ce_divider) begin - ce_x1 = (i_div == 2'b01); - ce_x2 = i_div[0]; - end else begin - ce_x1 = i_div[0]; - ce_x2 = 1'b1; - end -end - -assign pixel_ena = bypass ? ce_x1 : ce_x2; +parameter HCNT_WIDTH = 9; // Resolution of scandoubler buffer +parameter COLOR_DEPTH = 6; // Bits per colour to be stored in the buffer +parameter HSCNT_WIDTH = 12; // Resolution of hsync counters // --------------------- create output signals ----------------- // latch everything once more to make it glitch free and apply scanline effect @@ -80,74 +68,85 @@ reg [5:0] r; reg [5:0] g; reg [5:0] b; +wire [5:0] r_o; +wire [5:0] g_o; +wire [5:0] b_o; +reg hs_o; +reg vs_o; + +wire [COLOR_DEPTH*3-1:0] sd_mux = bypass ? {r_in, g_in, b_in} : sd_out; + always @(*) begin if (COLOR_DEPTH == 6) begin - b = sd_out[5:0]; - g = sd_out[11:6]; - r = sd_out[17:12]; + b = sd_mux[5:0]; + g = sd_mux[11:6]; + r = sd_mux[17:12]; end else if (COLOR_DEPTH == 2) begin - b = {3{sd_out[1:0]}}; - g = {3{sd_out[3:2]}}; - r = {3{sd_out[5:4]}}; + b = {3{sd_mux[1:0]}}; + g = {3{sd_mux[3:2]}}; + r = {3{sd_mux[5:4]}}; end else if (COLOR_DEPTH == 1) begin - b = {6{sd_out[0]}}; - g = {6{sd_out[1]}}; - r = {6{sd_out[2]}}; + b = {6{sd_mux[0]}}; + g = {6{sd_mux[1]}}; + r = {6{sd_mux[2]}}; end else begin - b = { sd_out[COLOR_DEPTH-1:0], sd_out[COLOR_DEPTH-1 -:(6-COLOR_DEPTH)] }; - g = { sd_out[COLOR_DEPTH*2-1:COLOR_DEPTH], sd_out[COLOR_DEPTH*2-1 -:(6-COLOR_DEPTH)] }; - r = { sd_out[COLOR_DEPTH*3-1:COLOR_DEPTH*2], sd_out[COLOR_DEPTH*3-1 -:(6-COLOR_DEPTH)] }; + b = { sd_mux[COLOR_DEPTH-1:0], sd_mux[COLOR_DEPTH-1 -:(6-COLOR_DEPTH)] }; + g = { sd_mux[COLOR_DEPTH*2-1:COLOR_DEPTH], sd_mux[COLOR_DEPTH*2-1 -:(6-COLOR_DEPTH)] }; + r = { sd_mux[COLOR_DEPTH*3-1:COLOR_DEPTH*2], sd_mux[COLOR_DEPTH*3-1 -:(6-COLOR_DEPTH)] }; end end + +reg [12:0] r_mul; +reg [12:0] g_mul; +reg [12:0] b_mul; + +wire scanline_bypass = (!scanline) | (!(|scanlines)) | bypass; + +// More subtle variant of the scanlines effect. +// 0 00 -> 1000000 0x40 - bypass / inert mode +// 1 01 -> 0111010 0x3a - 25% +// 2 10 -> 0101110 0x2e - 50% +// 3 11 -> 0011010 0x1a - 75% + +wire [6:0] scanline_coeff = scanline_bypass ? + 7'b1000000 : {~(&scanlines),scanlines[0],1'b1,~scanlines[0],2'b10}; + always @(posedge clk_sys) begin - if(bypass) begin - r_out <= r; - g_out <= g; - b_out <= b; - hs_out <= hs_sd; - vs_out <= vs_sd; - end else if(ce_x2) begin - hs_out <= hs_sd; - vs_out <= vs_sd; + if(ce_x2) begin + hs_o <= hs_sd; + vs_o <= vs_in; // reset scanlines at every new screen - if(vs_out != vs_in) scanline <= 0; + if(vs_o != vs_in) scanline <= 0; // toggle scanlines at begin of every hsync - if(hs_out && !hs_sd) scanline <= !scanline; + if(hs_o && !hs_sd) scanline <= !scanline; - // if no scanlines or not a scanline - if(!scanline || !scanlines) begin - r_out <= r; - g_out <= g; - b_out <= b; - end else begin - case(scanlines) - 1: begin // reduce 25% = 1/2 + 1/4 - r_out <= {1'b0, r[5:1]} + {2'b00, r[5:2] }; - g_out <= {1'b0, g[5:1]} + {2'b00, g[5:2] }; - b_out <= {1'b0, b[5:1]} + {2'b00, b[5:2] }; - end - - 2: begin // reduce 50% = 1/2 - r_out <= {1'b0, r[5:1]}; - g_out <= {1'b0, g[5:1]}; - b_out <= {1'b0, b[5:1]}; - end - - 3: begin // reduce 75% = 1/4 - r_out <= {2'b00, r[5:2]}; - g_out <= {2'b00, g[5:2]}; - b_out <= {2'b00, b[5:2]}; - end - endcase - end + r_mul<=r*scanline_coeff; + g_mul<=g*scanline_coeff; + b_mul<=b*scanline_coeff; end end +assign r_o = r_mul[11:6]; +assign g_o = g_mul[11:6]; +assign b_o = b_mul[11:6]; + + +// Output multiplexing + +assign r_out = bypass ? r : r_o; +assign g_out = bypass ? g : g_o; +assign b_out = bypass ? b : b_o; +assign hs_out = bypass ? hs_in : hs_o; +assign vs_out = bypass ? vs_in : vs_o; + +assign pixel_ena = bypass ? ce_x1 : ce_x2; + + // scan doubler output register -wire [COLOR_DEPTH*3-1:0] sd_out = bypass ? sd_bypass_out : sd_buffer_out; +reg [COLOR_DEPTH*3-1:0] sd_out; // ================================================================== // ======================== the line buffers ======================== @@ -160,70 +159,104 @@ wire [COLOR_DEPTH*3-1:0] sd_out = bypass ? sd_bypass_out : sd_buffer_out; reg line_toggle; // total hsync time (in 16MHz cycles), hs_total reaches 1024 -reg [HCNT_WIDTH-1:0] hs_max; -reg [HCNT_WIDTH-1:0] hs_rise; reg [HCNT_WIDTH-1:0] hcnt; +reg [HSCNT_WIDTH:0] hs_max; +reg [HSCNT_WIDTH:0] hs_rise; +reg [HSCNT_WIDTH:0] synccnt; + +// Input pixel clock, aligned with input sync: +wire[2:0] ce_divider_adj = |ce_divider ? ce_divider : 3'd3; // 0 = clk/4 for compatiblity +reg [2:0] ce_divider_in; +reg [2:0] ce_divider_out; + +reg [2:0] i_div; +wire ce_x1 = (i_div == ce_divider_in); always @(posedge clk_sys) begin reg hsD, vsD; + // Pixel logic on x1 clkena if(ce_x1) begin - hsD <= hs_in; - - // falling edge of hsync indicates start of line - if(hsD && !hs_in) begin - hs_max <= hcnt; - hcnt <= 0; - end else begin - hcnt <= hcnt + 1'd1; - end - - // save position of rising edge - if(!hsD && hs_in) hs_rise <= hcnt; - - vsD <= vs_in; - if(vsD != vs_in) line_toggle <= 0; - - // begin of incoming hsync - if(hsD && !hs_in) line_toggle <= !line_toggle; - + hcnt <= hcnt + 1'd1; sd_buffer[{line_toggle, hcnt}] <= {r_in, g_in, b_in}; end + + // Generate pixel clock + i_div <= i_div + 1'd1; + + if (i_div==ce_divider_adj) i_div <= 3'b000; + + synccnt <= synccnt + 1'd1; + hsD <= hs_in; + if(hsD && !hs_in) begin + // At hsync latch the ce_divider counter limit for the input clock + // and pass the previous input clock limit to the output stage. + // This should give correct output if the pixel clock changes mid-screen. + ce_divider_out <= ce_divider_in; + ce_divider_in <= ce_divider_adj; + hs_max <= {1'b0,synccnt[HSCNT_WIDTH:1]}; + hcnt <= 0; + synccnt <= 0; + i_div <= 3'b000; + end + + // save position of rising edge + if(!hsD && hs_in) hs_rise <= {1'b0,synccnt[HSCNT_WIDTH:1]}; + + // begin of incoming hsync + if(hsD && !hs_in) line_toggle <= !line_toggle; + + vsD <= vs_in; + if(vsD != vs_in) line_toggle <= 0; + end // ================================================================== // ==================== output timing generation ==================== // ================================================================== -reg [COLOR_DEPTH*3-1:0] sd_buffer_out, sd_bypass_out; -reg [HCNT_WIDTH-1:0] sd_hcnt; -reg hs_sd, vs_sd; +reg [HSCNT_WIDTH:0] sd_synccnt; +reg [HCNT_WIDTH-1:0] sd_hcnt; +reg hs_sd; + +// Output pixel clock, aligned with output sync: +reg [2:0] sd_i_div; +wire ce_x2 = (sd_i_div == ce_divider_out) | (sd_i_div == {1'b0,ce_divider_out[2:1]}); // timing generation runs 32 MHz (twice the input signal analysis speed) always @(posedge clk_sys) begin reg hsD; + // Output logic on x2 clkena if(ce_x2) begin - hsD <= hs_in; - // output counter synchronous to input and at twice the rate sd_hcnt <= sd_hcnt + 1'd1; - if(hsD && !hs_in) sd_hcnt <= hs_max; - if(sd_hcnt == hs_max) sd_hcnt <= 0; - - // replicate horizontal sync at twice the speed - if(sd_hcnt == hs_max) hs_sd <= 0; - if(sd_hcnt == hs_rise) hs_sd <= 1; // read data from line sd_buffer - sd_buffer_out <= sd_buffer[{~line_toggle, sd_hcnt}]; - vs_sd <= vs_in; + sd_out <= sd_buffer[{~line_toggle, sd_hcnt}]; end - if(bypass) begin - sd_bypass_out <= {r_in, g_in, b_in}; - hs_sd <= hs_in; - vs_sd <= vs_in; + + // Framing logic on sysclk + sd_synccnt <= sd_synccnt + 1'd1; + hsD <= hs_in; + if(hsD && !hs_in) sd_synccnt <= hs_max; + + if(sd_synccnt == hs_max) begin + sd_synccnt <= 0; + sd_hcnt <= 0; end + + sd_i_div <= sd_i_div + 1'd1; + if (sd_i_div==ce_divider_adj) sd_i_div <= 3'b000; + + // replicate horizontal sync at twice the speed + if(sd_synccnt == 0) begin + hs_sd <= 0; + sd_i_div <= 3'b000; + end + + if(sd_synccnt == hs_rise) hs_sd <= 1; + end endmodule diff --git a/common/mist/sd_card.v b/common/mist/sd_card.v index 0d1ff58d..88fcbb30 100644 --- a/common/mist/sd_card.v +++ b/common/mist/sd_card.v @@ -503,6 +503,9 @@ always@(posedge clk_sys) begin reply_len <= 4'd4; end + // CMD59: CRC_ON_OFF + 8'h7b: reply <= 0; // ok + endcase end end diff --git a/common/mist/user_io.v b/common/mist/user_io.v index 3d283918..05e114dd 100644 --- a/common/mist/user_io.v +++ b/common/mist/user_io.v @@ -2,7 +2,7 @@ // user_io.v // // user_io for the MiST board -// http://code.google.com/p/mist-board/ +// https://github.com/mist-devel // // Copyright (c) 2014 Till Harbaum // @@ -57,14 +57,15 @@ module user_io ( input [31:0] sd_lba, input [SD_IMAGES-1:0] sd_rd, input [SD_IMAGES-1:0] sd_wr, - output reg sd_ack, - output reg sd_ack_conf, + output reg sd_ack = 0, // ack any transfer + output reg sd_ack_conf = 0, + output reg [SD_IMAGES-1:0] sd_ack_x = 0, // ack specific transfer input sd_conf, input sd_sdhc, output reg [7:0] sd_dout, // valid on rising edge of sd_dout_strobe - output reg sd_dout_strobe, + output reg sd_dout_strobe = 0, input [7:0] sd_din, - output reg sd_din_strobe, + output reg sd_din_strobe = 0, output reg [8:0] sd_buff_addr, output reg [SD_IMAGES-1:0] img_mounted, // rising edge if a new image is mounted @@ -72,11 +73,11 @@ module user_io ( // ps2 keyboard/mouse emulation output ps2_kbd_clk, - output reg ps2_kbd_data, + output ps2_kbd_data, input ps2_kbd_clk_i, input ps2_kbd_data_i, output ps2_mouse_clk, - output reg ps2_mouse_data, + output ps2_mouse_data, input ps2_mouse_clk_i, input ps2_mouse_data_i, @@ -86,6 +87,9 @@ module user_io ( output reg [7:0] key_code, // key scan code output reg key_strobe, // key data valid + input [7:0] kbd_out_data, // for Archie + input kbd_out_strobe, + // mouse data output reg [8:0] mouse_x, output reg [8:0] mouse_y, @@ -105,8 +109,10 @@ parameter ROM_DIRECT_UPLOAD=0; // direct upload used for file uploads from the A parameter SD_IMAGES=2; // number of block-access images (max. 4 supported in current firmware) parameter PS2BIDIR=0; // bi-directional PS2 interface parameter FEATURES=0; // requested features from the firmware +parameter ARCHIE=0; localparam W = $clog2(SD_IMAGES); +localparam PS2_FIFO_BITS = 4; reg [6:0] sbuf; reg [7:0] cmd; @@ -123,9 +129,8 @@ assign no_csync = but_sw[6]; assign conf_addr = byte_cnt; -// this variant of user_io is for 8 bit cores (type == a4) only // bit 4 indicates ROM direct upload capability -wire [7:0] core_type = ROM_DIRECT_UPLOAD ? 8'hb4 : 8'ha4; +wire [7:0] core_type = ARCHIE ? 8'ha6 : ROM_DIRECT_UPLOAD ? 8'hb4 : 8'ha4; reg [W:0] drive_sel; always begin @@ -140,9 +145,6 @@ wire [7:0] sd_cmd = { 4'h6, sd_conf, sd_sdhc, sd_wr[drive_sel], sd_rd[drive_sel] wire spi_sck = SPI_CLK; // ---------------- PS2 --------------------- -// 16 byte fifos to store ps2 bytes -localparam PS2_FIFO_BITS = 4; - reg ps2_clk; always @(posedge clk_sys) begin integer cnt; @@ -154,237 +156,44 @@ always @(posedge clk_sys) begin end // keyboard -reg [7:0] ps2_kbd_fifo [(2**PS2_FIFO_BITS)-1:0]; -reg [PS2_FIFO_BITS-1:0] ps2_kbd_wptr; -reg [PS2_FIFO_BITS-1:0] ps2_kbd_rptr; +reg ps2_kbd_tx_strobe; +wire [7:0] ps2_kbd_rx_byte ; +wire ps2_kbd_rx_strobe; +wire ps2_kbd_fifo_ok; -// ps2 transmitter state machine -reg [3:0] ps2_kbd_tx_state; -reg [7:0] ps2_kbd_tx_byte; -reg ps2_kbd_parity; - -// ps2 receiver state machine -reg [3:0] ps2_kbd_rx_state = 0; -reg [1:0] ps2_kbd_rx_start = 0; -reg [7:0] ps2_kbd_rx_byte = 0; -reg ps2_kbd_rx_strobe = 0; - -assign ps2_kbd_clk = ps2_clk || (ps2_kbd_tx_state == 0 && ps2_kbd_rx_state == 0); - -// ps2 transmitter/receiver -// Takes a byte from the FIFO and sends it in a ps2 compliant serial format. -// Sends a command to the IO controller if bidirectional mode is enabled. -always@(posedge clk_sys) begin : ps2_kbd - - reg ps2_clkD; - reg ps2_clk_iD, ps2_dat_iD; - reg ps2_kbd_r_inc; - - // send data - ps2_clkD <= ps2_clk; - if (~ps2_clkD & ps2_clk) begin - ps2_kbd_r_inc <= 1'b0; - - if(ps2_kbd_r_inc) - ps2_kbd_rptr <= ps2_kbd_rptr + 1'd1; - - // transmitter is idle? - if(ps2_kbd_tx_state == 0) begin - ps2_kbd_data <= 1; - // data in fifo present? - if(ps2_kbd_wptr != ps2_kbd_rptr && (ps2_kbd_clk_i | !PS2BIDIR)) begin - // load tx register from fifo - ps2_kbd_tx_byte <= ps2_kbd_fifo[ps2_kbd_rptr]; - ps2_kbd_r_inc <= 1'b1; - - // reset parity - ps2_kbd_parity <= 1'b1; - - // start transmitter - ps2_kbd_tx_state <= 4'd1; - - // put start bit on data line - ps2_kbd_data <= 1'b0; // start bit is 0 - end - end else begin - - // transmission of 8 data bits - if((ps2_kbd_tx_state >= 1)&&(ps2_kbd_tx_state < 9)) begin - ps2_kbd_data <= ps2_kbd_tx_byte[0]; // data bits - ps2_kbd_tx_byte[6:0] <= ps2_kbd_tx_byte[7:1]; // shift down - if(ps2_kbd_tx_byte[0]) - ps2_kbd_parity <= !ps2_kbd_parity; - end - - // transmission of parity - if(ps2_kbd_tx_state == 9) - ps2_kbd_data <= ps2_kbd_parity; - - // transmission of stop bit - if(ps2_kbd_tx_state == 10) - ps2_kbd_data <= 1'b1; // stop bit is 1 - - // advance state machine - if(ps2_kbd_tx_state < 11) - ps2_kbd_tx_state <= ps2_kbd_tx_state + 4'd1; - else - ps2_kbd_tx_state <= 4'd0; - end - end - - if (PS2BIDIR) begin - ps2_clk_iD <= ps2_kbd_clk_i; - ps2_dat_iD <= ps2_kbd_data_i; - - // receive command - case (ps2_kbd_rx_start) - 2'd0: - // first: host pulls down the clock line - if (ps2_clk_iD & ~ps2_kbd_clk_i) ps2_kbd_rx_start <= 1; - 2'd1: - // second: host pulls down the data line, while releasing the clock - if (ps2_dat_iD && !ps2_kbd_data_i) ps2_kbd_rx_start <= 2'd2; - // if it releases the clock without pulling down the data line: goto 0 - else if (ps2_kbd_clk_i) ps2_kbd_rx_start <= 0; - 2'd2: - if (ps2_clkD && ~ps2_clk) begin - ps2_kbd_rx_state <= 4'd1; - ps2_kbd_rx_start <= 0; - end - default: ; - endcase - - // host data is valid after the rising edge of the clock - if(ps2_kbd_rx_state != 0 && ~ps2_clkD && ps2_clk) begin - ps2_kbd_rx_state <= ps2_kbd_rx_state + 1'd1; - if (ps2_kbd_rx_state == 9) ;// parity - else if (ps2_kbd_rx_state == 10) begin - ps2_kbd_data <= 0; // ack the received byte - end else if (ps2_kbd_rx_state == 11) begin - ps2_kbd_rx_state <= 0; - ps2_kbd_rx_strobe <= ~ps2_kbd_rx_strobe; - end else begin - ps2_kbd_rx_byte <= {ps2_kbd_data_i, ps2_kbd_rx_byte[7:1]}; - end - end - end -end +user_io_ps2 #(.PS2_BIDIR(PS2BIDIR), .PS2_FIFO_BITS(4)) ps2_kbd ( + .clk_sys ( clk_sys ), + .ps2_clk ( ps2_clk ), + .ps2_clk_i ( ps2_kbd_clk_i ), + .ps2_clk_o ( ps2_kbd_clk ), + .ps2_data_i ( ps2_kbd_data_i ), + .ps2_data_o ( ps2_kbd_data ), + .ps2_tx_strobe ( ps2_kbd_tx_strobe ), // from IO controller + .ps2_tx_byte ( spi_byte_in ), + .ps2_rx_strobe ( ps2_kbd_rx_strobe ), // to IO controller + .ps2_rx_byte ( ps2_kbd_rx_byte ), + .ps2_fifo_ready( ps2_kbd_fifo_ok ) +); // mouse -reg [7:0] ps2_mouse_fifo [(2**PS2_FIFO_BITS)-1:0]; -reg [PS2_FIFO_BITS-1:0] ps2_mouse_wptr; -reg [PS2_FIFO_BITS-1:0] ps2_mouse_rptr; +reg ps2_mouse_tx_strobe; +wire [7:0] ps2_mouse_rx_byte ; +wire ps2_mouse_rx_strobe; +wire ps2_mouse_fifo_ok; -// ps2 transmitter state machine -reg [3:0] ps2_mouse_tx_state; -reg [7:0] ps2_mouse_tx_byte; -reg ps2_mouse_parity; - -// ps2 receiver state machine -reg [3:0] ps2_mouse_rx_state = 0; -reg [1:0] ps2_mouse_rx_start = 0; -reg [7:0] ps2_mouse_rx_byte = 0; -reg ps2_mouse_rx_strobe = 0; - -assign ps2_mouse_clk = ps2_clk || (ps2_mouse_tx_state == 0 && ps2_mouse_rx_state == 0); - -// ps2 transmitter/receiver -// Takes a byte from the FIFO and sends it in a ps2 compliant serial format. -// Sends a command to the IO controller if bidirectional mode is enabled. -always@(posedge clk_sys) begin : ps2_mouse - reg ps2_clkD; - reg ps2_clk_iD, ps2_dat_iD; - reg ps2_mouse_r_inc; - - ps2_clkD <= ps2_clk; - if (~ps2_clkD & ps2_clk) begin - ps2_mouse_r_inc <= 1'b0; - - if(ps2_mouse_r_inc) - ps2_mouse_rptr <= ps2_mouse_rptr + 1'd1; - - // transmitter is idle? - if(ps2_mouse_tx_state == 0) begin - ps2_mouse_data <= 1; - // data in fifo present? - if(ps2_mouse_wptr != ps2_mouse_rptr && (ps2_mouse_clk_i | !PS2BIDIR)) begin - // load tx register from fifo - ps2_mouse_tx_byte <= ps2_mouse_fifo[ps2_mouse_rptr]; - ps2_mouse_r_inc <= 1'b1; - - // reset parity - ps2_mouse_parity <= 1'b1; - - // start transmitter - ps2_mouse_tx_state <= 4'd1; - - // put start bit on data line - ps2_mouse_data <= 1'b0; // start bit is 0 - end - end else begin - - // transmission of 8 data bits - if((ps2_mouse_tx_state >= 1)&&(ps2_mouse_tx_state < 9)) begin - ps2_mouse_data <= ps2_mouse_tx_byte[0]; // data bits - ps2_mouse_tx_byte[6:0] <= ps2_mouse_tx_byte[7:1]; // shift down - if(ps2_mouse_tx_byte[0]) - ps2_mouse_parity <= !ps2_mouse_parity; - end - - // transmission of parity - if(ps2_mouse_tx_state == 9) - ps2_mouse_data <= ps2_mouse_parity; - - // transmission of stop bit - if(ps2_mouse_tx_state == 10) - ps2_mouse_data <= 1'b1; // stop bit is 1 - - // advance state machine - if(ps2_mouse_tx_state < 11) - ps2_mouse_tx_state <= ps2_mouse_tx_state + 4'd1; - else - ps2_mouse_tx_state <= 4'd0; - end - end - - if (PS2BIDIR) begin - - ps2_clk_iD <= ps2_mouse_clk_i; - ps2_dat_iD <= ps2_mouse_data_i; - - // receive command - case (ps2_mouse_rx_start) - 2'd0: - // first: host pulls down the clock line - if (ps2_clk_iD & ~ps2_mouse_clk_i) ps2_mouse_rx_start <= 1; - 2'd1: - // second: host pulls down the data line, while releasing the clock - if (ps2_dat_iD && !ps2_mouse_data_i) ps2_mouse_rx_start <= 2'd2; - // if it releases the clock without pulling down the data line: goto 0 - else if (ps2_mouse_clk_i) ps2_mouse_rx_start <= 0; - 2'd2: - if (ps2_clkD && ~ps2_clk) begin - ps2_mouse_rx_state <= 4'd1; - ps2_mouse_rx_start <= 0; - end - default: ; - endcase - - // host data is valid after the rising edge of the clock - if(ps2_mouse_rx_state != 0 && ~ps2_clkD && ps2_clk) begin - ps2_mouse_rx_state <= ps2_mouse_rx_state + 1'd1; - if (ps2_mouse_rx_state == 9) ;// parity - else if (ps2_mouse_rx_state == 10) begin - ps2_mouse_data <= 0; // ack the received byte - end else if (ps2_mouse_rx_state == 11) begin - ps2_mouse_rx_state <= 0; - ps2_mouse_rx_strobe <= ~ps2_mouse_rx_strobe; - end else begin - ps2_mouse_rx_byte <= {ps2_mouse_data_i, ps2_mouse_rx_byte[7:1]}; - end - end - end -end +user_io_ps2 #(.PS2_BIDIR(PS2BIDIR), .PS2_FIFO_BITS(3)) ps2_mouse ( + .clk_sys ( clk_sys ), + .ps2_clk ( ps2_clk ), + .ps2_clk_i ( ps2_mouse_clk_i ), + .ps2_clk_o ( ps2_mouse_clk ), + .ps2_data_i ( ps2_mouse_data_i ), + .ps2_data_o ( ps2_mouse_data ), + .ps2_tx_strobe ( ps2_mouse_tx_strobe ), // from IO controller + .ps2_tx_byte ( spi_byte_in ), + .ps2_rx_strobe ( ps2_mouse_rx_strobe ), // to IO controller + .ps2_rx_byte ( ps2_mouse_rx_byte ), + .ps2_fifo_ready( ps2_mouse_fifo_ok ) +); // fifo to receive serial data from core to be forwarded to io controller @@ -446,6 +255,23 @@ always@(negedge spi_sck or posedge SPI_SS_IO) begin : spi_byteout end end +generate if (ARCHIE) begin +reg [7:0] kbd_out_status; +reg [7:0] kbd_out_data_r; +reg kbd_out_data_available = 0; + +always@(negedge spi_sck or posedge SPI_SS_IO) begin : archie_kbd_out + if(SPI_SS_IO == 1) begin + kbd_out_data_r <= 0; + kbd_out_status <= 0; + end else begin + kbd_out_status <= { 4'ha, 3'b000, kbd_out_data_available }; + kbd_out_data_r <= kbd_out_data; + end +end +end +endgenerate + always@(posedge spi_sck or posedge SPI_SS_IO) begin : spi_transmitter reg [31:0] sd_lba_r; reg [W:0] drive_sel_r; @@ -461,6 +287,11 @@ always@(posedge spi_sck or posedge SPI_SS_IO) begin : spi_transmitter spi_byte_out <= 0; case({(!byte_cnt) ? {sbuf, SPI_MOSI} : cmd}) + 8'h04: if (ARCHIE) begin + if(byte_cnt == 0) spi_byte_out <= kbd_out_status; + else spi_byte_out <= kbd_out_data_r; + end + // PS2 keyboard command 8'h0e: if (byte_cnt == 0) begin ps2_kbd_rx_strobeD <= ps2_kbd_rx_strobe; @@ -539,12 +370,14 @@ always @(posedge clk_sys) begin : cmd_block reg spi_receiver_strobeD; reg spi_transfer_endD; reg [7:0] acmd; - reg [7:0] abyte_cnt; // counts bytes + reg [3:0] abyte_cnt; // counts bytes reg [7:0] mouse_flags_r; reg [7:0] mouse_x_r; reg [7:0] mouse_y_r; + reg mouse_fifo_ok; + reg kbd_fifo_ok; reg key_pressed_r; reg key_extended_r; @@ -556,17 +389,46 @@ always @(posedge clk_sys) begin : cmd_block key_strobe <= 0; mouse_strobe <= 0; + ps2_kbd_tx_strobe <= 0; + ps2_mouse_tx_strobe <= 0; + + if(ARCHIE) begin + if (kbd_out_strobe) kbd_out_data_available <= 1; + key_pressed <= 0; + key_extended <= 0; + mouse_x <= 0; + mouse_y <= 0; + mouse_z <= 0; + mouse_flags <= 0; + mouse_idx <= 0; + end if (spi_transfer_end) begin - abyte_cnt <= 8'd0; + abyte_cnt <= 0; + mouse_fifo_ok <= 0; + kbd_fifo_ok <= 0; end else if (spi_receiver_strobeD ^ spi_receiver_strobe) begin if(~&abyte_cnt) - abyte_cnt <= abyte_cnt + 8'd1; + abyte_cnt <= abyte_cnt + 1'd1; if(abyte_cnt == 0) begin acmd <= spi_byte_in; + if (spi_byte_in == 8'h70 || spi_byte_in == 8'h71) + // accept the incoming mouse data only if there's place for the full packet + mouse_fifo_ok <= ps2_mouse_fifo_ok; + if (spi_byte_in == 8'h05) + // accept the incoming keyboard data only if there's place for the full packet + kbd_fifo_ok <= ps2_kbd_fifo_ok; end else begin + if (ARCHIE) begin + if(acmd == 8'h04) kbd_out_data_available <= 0; + if(acmd == 8'h05) begin + key_strobe <= 1; + key_code <= spi_byte_in; + end + end + case(acmd) // buttons and switches 8'h01: but_sw <= spi_byte_in; @@ -575,11 +437,10 @@ always @(posedge clk_sys) begin : cmd_block 8'h62: if (abyte_cnt < 5) joystick_2[(abyte_cnt-1)<<3 +:8] <= spi_byte_in; 8'h63: if (abyte_cnt < 5) joystick_3[(abyte_cnt-1)<<3 +:8] <= spi_byte_in; 8'h64: if (abyte_cnt < 5) joystick_4[(abyte_cnt-1)<<3 +:8] <= spi_byte_in; - 8'h70,8'h71: begin + 8'h70,8'h71: if (!ARCHIE) begin // store incoming ps2 mouse bytes - if (abyte_cnt < 4) begin - ps2_mouse_fifo[ps2_mouse_wptr] <= spi_byte_in; - ps2_mouse_wptr <= ps2_mouse_wptr + 1'd1; + if (abyte_cnt < 4 && mouse_fifo_ok) begin + ps2_mouse_tx_strobe <= 1; end if (abyte_cnt == 1) mouse_flags_r <= spi_byte_in; @@ -595,10 +456,9 @@ always @(posedge clk_sys) begin : cmd_block mouse_strobe <= 1; end end - 8'h05: begin - // store incoming ps2 keyboard bytes - ps2_kbd_fifo[ps2_kbd_wptr] <= spi_byte_in; - ps2_kbd_wptr <= ps2_kbd_wptr + 1'd1; + 8'h05: if (!ARCHIE) begin + // store incoming ps2 keyboard bytes + if (kbd_fifo_ok) ps2_kbd_tx_strobe <= 1; if (abyte_cnt == 1) begin key_extended_r <= 0; key_pressed_r <= 1; @@ -698,6 +558,7 @@ always @(posedge clk_sd) begin : sd_block sd_ack <= 1'b0; sd_ack_conf <= 1'b0; sd_buff_addr <= 0; + if (acmd == 8'h17 || acmd == 8'h18) sd_ack_x <= 0; end else if (spi_receiver_strobeD ^ spi_receiver_strobe) begin if(~&abyte_cnt) @@ -740,9 +601,160 @@ always @(posedge clk_sd) begin : sd_block // send image info 8'h1d: if(abyte_cnt<9) img_size[(abyte_cnt-1)<<3 +:8] <= spi_byte_in; + // data transfer ack + 8'h23: sd_ack_x <= 1'b1 << spi_byte_in; + endcase end end end endmodule + +module user_io_ps2 ( + input clk_sys, + input ps2_clk, + input ps2_clk_i, + output ps2_clk_o, + input ps2_data_i, + output reg ps2_data_o = 1, + input ps2_tx_strobe, // from IO controller + input [7:0] ps2_tx_byte, + output reg ps2_rx_strobe = 0, // to IO controller + output reg [7:0] ps2_rx_byte = 0, + output ps2_fifo_ready +); + +parameter PS2_FIFO_BITS = 4; +parameter PS2_BIDIR = 0; + +reg [7:0] ps2_fifo [(2**PS2_FIFO_BITS)-1:0]; +reg [PS2_FIFO_BITS-1:0] ps2_wptr; +reg [PS2_FIFO_BITS-1:0] ps2_rptr; +wire [PS2_FIFO_BITS:0] ps2_used = ps2_wptr >= ps2_rptr ? + ps2_wptr - ps2_rptr : + ps2_wptr - ps2_rptr + (2'd2**PS2_FIFO_BITS); +wire [PS2_FIFO_BITS:0] ps2_free = (2'd2**PS2_FIFO_BITS) - ps2_used; + +assign ps2_fifo_ready = ps2_free[PS2_FIFO_BITS:2] != 0; // ps2_free > 3 + +// ps2 transmitter state machine +reg [3:0] ps2_tx_state; +reg [7:0] ps2_tx_shift_reg; +reg ps2_parity; + +// ps2 receiver state machine +reg [3:0] ps2_rx_state = 0; +reg [1:0] ps2_rx_start = 0; + +assign ps2_clk_o = ps2_clk || (ps2_tx_state == 0 && ps2_rx_state == 0); + +always@(posedge clk_sys) begin : ps2_fifo_wr + if (ps2_tx_strobe) begin + ps2_fifo[ps2_wptr] <= ps2_tx_byte; + ps2_wptr <= ps2_wptr + 1'd1; + end +end + +// ps2 transmitter/receiver +// Takes a byte from the FIFO and sends it in a ps2 compliant serial format. +// Sends a command to the IO controller if bidirectional mode is enabled. +always@(posedge clk_sys) begin : ps2_txrx + reg ps2_clkD; + reg ps2_clk_iD, ps2_dat_iD; + reg ps2_r_inc; + + ps2_clkD <= ps2_clk; + if (~ps2_clkD & ps2_clk) begin + ps2_r_inc <= 1'b0; + + if(ps2_r_inc) + ps2_rptr <= ps2_rptr + 1'd1; + + // transmitter is idle? + if(ps2_tx_state == 0) begin + ps2_data_o <= 1; + // data in fifo present? + if(ps2_wptr != ps2_rptr && (ps2_clk_i | !PS2_BIDIR)) begin + // load tx register from fifo + ps2_tx_shift_reg <= ps2_fifo[ps2_rptr]; + ps2_r_inc <= 1'b1; + + // reset parity + ps2_parity <= 1'b1; + + // start transmitter + ps2_tx_state <= 4'd1; + + // put start bit on data line + ps2_data_o <= 1'b0; // start bit is 0 + end + end else begin + + // transmission of 8 data bits + if((ps2_tx_state >= 1)&&(ps2_tx_state < 9)) begin + ps2_data_o <= ps2_tx_shift_reg[0]; // data bits + ps2_tx_shift_reg[6:0] <= ps2_tx_shift_reg[7:1]; // shift down + if(ps2_tx_shift_reg[0]) + ps2_parity <= !ps2_parity; + end + + // transmission of parity + if(ps2_tx_state == 9) + ps2_data_o <= ps2_parity; + + // transmission of stop bit + if(ps2_tx_state == 10) + ps2_data_o <= 1'b1; // stop bit is 1 + + // advance state machine + if(ps2_tx_state == 11) + ps2_tx_state <= 4'd0; + else + ps2_tx_state <= ps2_tx_state + 4'd1; + end + end + + if (PS2_BIDIR) begin + + ps2_clk_iD <= ps2_clk_i; + ps2_dat_iD <= ps2_data_i; + + // receive command + case (ps2_rx_start) + 2'd0: + // first: host pulls down the clock line + if (ps2_clk_iD & ~ps2_clk_i) ps2_rx_start <= 1; + 2'd1: + // second: host pulls down the data line, while releasing the clock + if (ps2_dat_iD && !ps2_data_i) ps2_rx_start <= 2'd2; + // if it releases the clock without pulling down the data line: goto 0 + else if (ps2_clk_i) ps2_rx_start <= 0; + 2'd2: + if (ps2_clkD && ~ps2_clk) begin + ps2_rx_state <= 4'd1; + ps2_rx_start <= 0; + end + default: ; + endcase + + // host data is valid after the rising edge of the clock + if(ps2_rx_state != 0 && ~ps2_clkD && ps2_clk) begin + ps2_rx_state <= ps2_rx_state + 1'd1; + if (ps2_rx_state == 9) ;// parity + else if (ps2_rx_state == 10) begin + ps2_data_o <= 0; // ack the received byte + end else if (ps2_rx_state == 11) begin + ps2_rx_state <= 0; + ps2_rx_strobe <= ~ps2_rx_strobe; + end else begin + ps2_rx_byte <= {ps2_data_i, ps2_rx_byte[7:1]}; + end + end + end else begin + ps2_rx_byte <= 0; + ps2_rx_strobe <= 0; + end +end + +endmodule From de3d5e339dbbb5fa4bc4cd0365625f0cc7567711 Mon Sep 17 00:00:00 2001 From: Gyorgy Szombathelyi Date: Sun, 9 Oct 2022 18:14:43 +0200 Subject: [PATCH 2/3] IremM72: add more variants --- Arcade_MiST/IremM72 Hardware/Readme.md | 8 +- .../meta/Air Duel (World, M72 hardware).mra | 74 +++++++++++++++++++ .../Daiku no Gensan (Japan, M84 hardware).mra | 73 ++++++++++++++++++ .../Hammerin' Harry (US, M84 hardware).mra | 21 +++--- 4 files changed, 160 insertions(+), 16 deletions(-) create mode 100644 Arcade_MiST/IremM72 Hardware/meta/Air Duel (World, M72 hardware).mra create mode 100644 Arcade_MiST/IremM72 Hardware/meta/Daiku no Gensan (Japan, M84 hardware).mra diff --git a/Arcade_MiST/IremM72 Hardware/Readme.md b/Arcade_MiST/IremM72 Hardware/Readme.md index 6eab9a76..4938a966 100644 --- a/Arcade_MiST/IremM72 Hardware/Readme.md +++ b/Arcade_MiST/IremM72 Hardware/Readme.md @@ -15,15 +15,15 @@ Implemention of the Irem M72 & M84 arcade hardware (https://www.system16.com/har |[R-Type](https://en.wikipedia.org/wiki/R-Type)|Japan, US, World|| |[Ninja Spirit](https://en.wikipedia.org/wiki/Ninja_Spirit)|Japan|| |[Image Fight](https://en.wikipedia.org/wiki/Image_Fight)|Japan, World|| -|[Gallop - Armed Police Unit](https://en.wikipedia.org/wiki/Armed_Police_Unit_Gallop)|Japan|Emulated MCU| +|[Gallop - Armed Police Unit](https://en.wikipedia.org/wiki/Armed_Police_Unit_Gallop)|Japan|Emulated MCU.| |[Legend of Hero Tonma](https://en.wikipedia.org/wiki/Legend_of_Hero_Tonma)|Japan|| |[Mr. HELI no Daibouken](https://en.wikipedia.org/wiki/Mr._Heli)|Japan|| -|[Air Duel](https://en.wikipedia.org/wiki/Air_Duel)|Japan|Conversion from M81 hardware.| +|[Air Duel](https://en.wikipedia.org/wiki/Air_Duel)|Japan, World|Conversion from M81 hardware.| |[Dragon Breed](https://en.wikipedia.org/wiki/Dragon_Breed)|Japan|Conversion from M81 hardware.| |[X-Multiply](https://en.wikipedia.org/wiki/X_Multiply)|Japan|Conversion from M81 hardware.| -|[Daiku no Gensan](https://en.wikipedia.org/wiki/Hammerin%27_Harry)|Japan|Conversion from M81 hardware. Emulated MCU| +|[Daiku no Gensan](https://en.wikipedia.org/wiki/Hammerin%27_Harry)|Japan|Conversion from M81 hardware. Emulated MCU.| +|[Hammerin' Harry](https://en.wikipedia.org/wiki/Hammerin%27_Harry)|US, Japan|M84 Hardware.| |[R-Type II](https://en.wikipedia.org/wiki/R-Type_II)|Japan,World|M84 hardware.| -|[Hammerin' Harry](https://en.wikipedia.org/wiki/Hammerin%27_Harry)|US|M84 hardware.| **Note:** Emulated MCU is not implemented on MiST (FPGA is full). diff --git a/Arcade_MiST/IremM72 Hardware/meta/Air Duel (World, M72 hardware).mra b/Arcade_MiST/IremM72 Hardware/meta/Air Duel (World, M72 hardware).mra new file mode 100644 index 00000000..1daf315b --- /dev/null +++ b/Arcade_MiST/IremM72 Hardware/meta/Air Duel (World, M72 hardware).mra @@ -0,0 +1,74 @@ + + Air Duel (World, M72 hardware) + 0245 + airduelm72 + airduel + 1990 + Irem + Shooter + IremM72 + vertical (ccw) + + 8-way + 2 + + + + + + + + + + + 01 + + + 09 + + 00 08 00 00 + + + + + + + + + + + 01 08 00 00 + + + + + + + + + 02 08 00 00 + + + + + + + + + 03 08 00 00 + + + + + + + + + 04 00 10 00 + + + + 05 02 00 00 + + + diff --git a/Arcade_MiST/IremM72 Hardware/meta/Daiku no Gensan (Japan, M84 hardware).mra b/Arcade_MiST/IremM72 Hardware/meta/Daiku no Gensan (Japan, M84 hardware).mra new file mode 100644 index 00000000..6484f33d --- /dev/null +++ b/Arcade_MiST/IremM72 Hardware/meta/Daiku no Gensan (Japan, M84 hardware).mra @@ -0,0 +1,73 @@ + + Daiku no Gensan (Japan, M84 hardware) + 0247 + hharry + dkgensan + 1990 + Irem + Platformer + IremM72 + horizontal + + 8-way + 2 + + + + + + + + + + + + + + + + 14 + + 00 08 00 00 + + + + + + + + + + + + + + + + 01 08 00 00 + + + + + + + + + 02 08 00 00 + + + + + + + + + 05 02 00 00 + + + + 08 01 00 00 + + + + diff --git a/Arcade_MiST/IremM72 Hardware/meta/Hammerin' Harry (US, M84 hardware).mra b/Arcade_MiST/IremM72 Hardware/meta/Hammerin' Harry (US, M84 hardware).mra index c9914a43..a63e9a24 100644 --- a/Arcade_MiST/IremM72 Hardware/meta/Hammerin' Harry (US, M84 hardware).mra +++ b/Arcade_MiST/IremM72 Hardware/meta/Hammerin' Harry (US, M84 hardware).mra @@ -12,18 +12,15 @@ 2 - - - - - - - - - - - - + + + + + + + + + From 8f6cf4a669cce79f2bc7854cd638283e99b49505 Mon Sep 17 00:00:00 2001 From: Gyorgy Szombathelyi Date: Sun, 9 Oct 2022 18:15:18 +0200 Subject: [PATCH 3/3] Nichibutsu Galivan: new port ...more like a rewrite than a port --- .../Nichibutsu Galivan Hardware/Galivan.qpf | 31 + .../Nichibutsu Galivan Hardware/Galivan.qsf | 255 +++++++ .../Nichibutsu Galivan Hardware/Galivan.sdc | 134 ++++ .../Nichibutsu Galivan Hardware/LICENSE | 339 +++++++++ .../Nichibutsu Galivan Hardware/Readme.md | 5 + .../Cosmo Police Galivan (12-26-1985).mra | 98 +++ .../meta/Ufo Robo Dangar (4-07-1987).mra | 99 +++ .../rtl/Galivan_MiST.sv | 348 +++++++++ .../rtl/build_id.tcl | 35 + .../Nichibutsu Galivan Hardware/rtl/clk_en.v | 29 + .../Nichibutsu Galivan Hardware/rtl/core.v | 662 ++++++++++++++++++ .../Nichibutsu Galivan Hardware/rtl/dpram.v | 137 ++++ .../Nichibutsu Galivan Hardware/rtl/gfx.v | 327 +++++++++ .../rtl/pll_mist.qip | 4 + .../rtl/pll_mist.vhd | 392 +++++++++++ .../Nichibutsu Galivan Hardware/rtl/sdram.sv | 363 ++++++++++ .../Nichibutsu Galivan Hardware/rtl/spram.sv | 253 +++++++ .../Nichibutsu Galivan Hardware/rtl/video.v | 45 ++ 18 files changed, 3556 insertions(+) create mode 100644 Arcade_MiST/Nichibutsu Galivan Hardware/Galivan.qpf create mode 100644 Arcade_MiST/Nichibutsu Galivan Hardware/Galivan.qsf create mode 100644 Arcade_MiST/Nichibutsu Galivan Hardware/Galivan.sdc create mode 100644 Arcade_MiST/Nichibutsu Galivan Hardware/LICENSE create mode 100644 Arcade_MiST/Nichibutsu Galivan Hardware/Readme.md create mode 100644 Arcade_MiST/Nichibutsu Galivan Hardware/meta/Cosmo Police Galivan (12-26-1985).mra create mode 100644 Arcade_MiST/Nichibutsu Galivan Hardware/meta/Ufo Robo Dangar (4-07-1987).mra create mode 100644 Arcade_MiST/Nichibutsu Galivan Hardware/rtl/Galivan_MiST.sv create mode 100644 Arcade_MiST/Nichibutsu Galivan Hardware/rtl/build_id.tcl create mode 100644 Arcade_MiST/Nichibutsu Galivan Hardware/rtl/clk_en.v create mode 100644 Arcade_MiST/Nichibutsu Galivan Hardware/rtl/core.v create mode 100644 Arcade_MiST/Nichibutsu Galivan Hardware/rtl/dpram.v create mode 100644 Arcade_MiST/Nichibutsu Galivan Hardware/rtl/gfx.v create mode 100644 Arcade_MiST/Nichibutsu Galivan Hardware/rtl/pll_mist.qip create mode 100644 Arcade_MiST/Nichibutsu Galivan Hardware/rtl/pll_mist.vhd create mode 100644 Arcade_MiST/Nichibutsu Galivan Hardware/rtl/sdram.sv create mode 100644 Arcade_MiST/Nichibutsu Galivan Hardware/rtl/spram.sv create mode 100644 Arcade_MiST/Nichibutsu Galivan Hardware/rtl/video.v diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/Galivan.qpf b/Arcade_MiST/Nichibutsu Galivan Hardware/Galivan.qpf new file mode 100644 index 00000000..f3639673 --- /dev/null +++ b/Arcade_MiST/Nichibutsu Galivan Hardware/Galivan.qpf @@ -0,0 +1,31 @@ +# -------------------------------------------------------------------------- # +# +# Copyright (C) 1991-2013 Altera Corporation +# Your use of Altera Corporation's design tools, logic functions +# and other software and tools, and its AMPP partner logic +# functions, and any output files from any of the foregoing +# (including device programming or simulation files), and any +# associated documentation or information are expressly subject +# to the terms and conditions of the Altera Program License +# Subscription Agreement, Altera MegaCore Function License +# Agreement, or other applicable license agreement, including, +# without limitation, that your use is for the sole purpose of +# programming logic devices manufactured by Altera and sold by +# Altera or its authorized distributors. Please refer to the +# applicable agreement for further details. +# +# -------------------------------------------------------------------------- # +# +# Quartus II 64-Bit +# Version 13.1.0 Build 162 10/23/2013 SJ Web Edition +# Date created = 00:21:03 December 03, 2019 +# +# -------------------------------------------------------------------------- # + +QUARTUS_VERSION = "13.1" +DATE = "00:21:03 December 03, 2019" + +# Revisions + +PROJECT_REVISION = "Galivan" + diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/Galivan.qsf b/Arcade_MiST/Nichibutsu Galivan Hardware/Galivan.qsf new file mode 100644 index 00000000..c7b626a0 --- /dev/null +++ b/Arcade_MiST/Nichibutsu Galivan Hardware/Galivan.qsf @@ -0,0 +1,255 @@ +# -------------------------------------------------------------------------- # +# +# Copyright (C) 1991-2014 Altera Corporation +# Your use of Altera Corporation's design tools, logic functions +# and other software and tools, and its AMPP partner logic +# functions, and any output files from any of the foregoing +# (including device programming or simulation files), and any +# associated documentation or information are expressly subject +# to the terms and conditions of the Altera Program License +# Subscription Agreement, Altera MegaCore Function License +# Agreement, or other applicable license agreement, including, +# without limitation, that your use is for the sole purpose of +# programming logic devices manufactured by Altera and sold by +# Altera or its authorized distributors. Please refer to the +# applicable agreement for further details. +# +# -------------------------------------------------------------------------- # +# +# Quartus II 64-Bit +# Version 13.1.4 Build 182 03/12/2014 SJ Full Version +# Date created = 19:54:12 November 22, 2020 +# +# -------------------------------------------------------------------------- # +# +# Notes: +# +# 1) The default values for assignments are stored in the file: +# Galivan_assignment_defaults.qdf +# If this file doesn't exist, see file: +# assignment_defaults.qdf +# +# 2) Altera recommends that you do not modify this file. This +# file is updated automatically by the Quartus II software +# and any changes you make may be lost or overwritten. +# +# -------------------------------------------------------------------------- # + + + +# Project-Wide Assignments +# ======================== +set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files +set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL +set_global_assignment -name LAST_QUARTUS_VERSION 13.1 +set_global_assignment -name PRE_FLOW_SCRIPT_FILE "quartus_sh:rtl/build_id.tcl" + +# Pin & Location Assignments +# ========================== +set_location_assignment PIN_7 -to LED +set_location_assignment PIN_54 -to CLOCK_27 +set_location_assignment PIN_144 -to VGA_R[5] +set_location_assignment PIN_143 -to VGA_R[4] +set_location_assignment PIN_142 -to VGA_R[3] +set_location_assignment PIN_141 -to VGA_R[2] +set_location_assignment PIN_137 -to VGA_R[1] +set_location_assignment PIN_135 -to VGA_R[0] +set_location_assignment PIN_133 -to VGA_B[5] +set_location_assignment PIN_132 -to VGA_B[4] +set_location_assignment PIN_125 -to VGA_B[3] +set_location_assignment PIN_121 -to VGA_B[2] +set_location_assignment PIN_120 -to VGA_B[1] +set_location_assignment PIN_115 -to VGA_B[0] +set_location_assignment PIN_114 -to VGA_G[5] +set_location_assignment PIN_113 -to VGA_G[4] +set_location_assignment PIN_112 -to VGA_G[3] +set_location_assignment PIN_111 -to VGA_G[2] +set_location_assignment PIN_110 -to VGA_G[1] +set_location_assignment PIN_106 -to VGA_G[0] +set_location_assignment PIN_136 -to VGA_VS +set_location_assignment PIN_119 -to VGA_HS +set_location_assignment PIN_65 -to AUDIO_L +set_location_assignment PIN_80 -to AUDIO_R +set_location_assignment PIN_105 -to SPI_DO +set_location_assignment PIN_88 -to SPI_DI +set_location_assignment PIN_126 -to SPI_SCK +set_location_assignment PIN_127 -to SPI_SS2 +set_location_assignment PIN_91 -to SPI_SS3 +set_location_assignment PIN_13 -to CONF_DATA0 +set_location_assignment PIN_49 -to SDRAM_A[0] +set_location_assignment PIN_44 -to SDRAM_A[1] +set_location_assignment PIN_42 -to SDRAM_A[2] +set_location_assignment PIN_39 -to SDRAM_A[3] +set_location_assignment PIN_4 -to SDRAM_A[4] +set_location_assignment PIN_6 -to SDRAM_A[5] +set_location_assignment PIN_8 -to SDRAM_A[6] +set_location_assignment PIN_10 -to SDRAM_A[7] +set_location_assignment PIN_11 -to SDRAM_A[8] +set_location_assignment PIN_28 -to SDRAM_A[9] +set_location_assignment PIN_50 -to SDRAM_A[10] +set_location_assignment PIN_30 -to SDRAM_A[11] +set_location_assignment PIN_32 -to SDRAM_A[12] +set_location_assignment PIN_83 -to SDRAM_DQ[0] +set_location_assignment PIN_79 -to SDRAM_DQ[1] +set_location_assignment PIN_77 -to SDRAM_DQ[2] +set_location_assignment PIN_76 -to SDRAM_DQ[3] +set_location_assignment PIN_72 -to SDRAM_DQ[4] +set_location_assignment PIN_71 -to SDRAM_DQ[5] +set_location_assignment PIN_69 -to SDRAM_DQ[6] +set_location_assignment PIN_68 -to SDRAM_DQ[7] +set_location_assignment PIN_86 -to SDRAM_DQ[8] +set_location_assignment PIN_87 -to SDRAM_DQ[9] +set_location_assignment PIN_98 -to SDRAM_DQ[10] +set_location_assignment PIN_99 -to SDRAM_DQ[11] +set_location_assignment PIN_100 -to SDRAM_DQ[12] +set_location_assignment PIN_101 -to SDRAM_DQ[13] +set_location_assignment PIN_103 -to SDRAM_DQ[14] +set_location_assignment PIN_104 -to SDRAM_DQ[15] +set_location_assignment PIN_58 -to SDRAM_BA[0] +set_location_assignment PIN_51 -to SDRAM_BA[1] +set_location_assignment PIN_85 -to SDRAM_DQMH +set_location_assignment PIN_67 -to SDRAM_DQML +set_location_assignment PIN_60 -to SDRAM_nRAS +set_location_assignment PIN_64 -to SDRAM_nCAS +set_location_assignment PIN_66 -to SDRAM_nWE +set_location_assignment PIN_59 -to SDRAM_nCS +set_location_assignment PIN_33 -to SDRAM_CKE +set_location_assignment PIN_43 -to SDRAM_CLK +set_location_assignment PLL_1 -to "pll:pll|altpll:altpll_component" + +# Classic Timing Assignments +# ========================== +set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0 +set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85 + +# Analysis & Synthesis Assignments +# ================================ +set_global_assignment -name FAMILY "Cyclone III" +set_global_assignment -name TOP_LEVEL_ENTITY Galivan_MiST +set_global_assignment -name DEVICE_FILTER_PIN_COUNT 144 +set_global_assignment -name DEVICE_FILTER_SPEED_GRADE 8 +set_global_assignment -name DEVICE_FILTER_PACKAGE TQFP + +# Fitter Assignments +# ================== +set_global_assignment -name DEVICE EP3C25E144C8 +set_global_assignment -name ENABLE_CONFIGURATION_PINS OFF +set_global_assignment -name ENABLE_NCE_PIN OFF +set_global_assignment -name ENABLE_BOOT_SEL_PIN OFF +set_global_assignment -name CYCLONEIII_CONFIGURATION_SCHEME "PASSIVE SERIAL" +set_global_assignment -name CRC_ERROR_OPEN_DRAIN OFF +set_global_assignment -name FORCE_CONFIGURATION_VCCIO ON +set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "3.3-V LVTTL" +set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION "USE AS REGULAR IO" +set_global_assignment -name RESERVE_DATA0_AFTER_CONFIGURATION "USE AS REGULAR IO" +set_global_assignment -name RESERVE_DATA1_AFTER_CONFIGURATION "USE AS REGULAR IO" +set_global_assignment -name RESERVE_FLASH_NCE_AFTER_CONFIGURATION "USE AS REGULAR IO" +set_global_assignment -name RESERVE_DCLK_AFTER_CONFIGURATION "USE AS REGULAR IO" + +# Assembler Assignments +# ===================== +set_global_assignment -name GENERATE_RBF_FILE ON +set_global_assignment -name USE_CONFIGURATION_DEVICE OFF + +# SignalTap II Assignments +# ======================== +set_global_assignment -name ENABLE_SIGNALTAP OFF +set_global_assignment -name USE_SIGNALTAP_FILE output_files/cpu.stp + +# Power Estimation Assignments +# ============================ +set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "23 MM HEAT SINK WITH 200 LFPM AIRFLOW" +set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)" + +# Advanced I/O Timing Assignments +# =============================== +set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -rise +set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -fall +set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -rise +set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -fall + +# ------------------------------ +# start ENTITY(Galivan_MiST) + + # Pin & Location Assignments + # ========================== + + # Fitter Assignments + # ================== + + # start DESIGN_PARTITION(Top) + # --------------------------- + + # Incremental Compilation Assignments + # =================================== + + # end DESIGN_PARTITION(Top) + # ------------------------- + +# end ENTITY(Galivan_MiST) +# ---------------------------- +set_global_assignment -name SYNTH_TIMING_DRIVEN_SYNTHESIS ON +set_global_assignment -name TIMEQUEST_MULTICORNER_ANALYSIS ON +set_global_assignment -name SMART_RECOMPILE ON +set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top +set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top +set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQ[*] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_A[*] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_BA[0] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_BA[1] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQMH +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQML +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nRAS +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nCAS +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nWE +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nCS +set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[*] +set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ[*] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_A[*] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[*] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_BA[*] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQML +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQMH +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nRAS +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nCAS +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nWE +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nCS +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_CKE +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_CLK +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_R[*] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_G[*] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_B[*] +set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_HS +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 PHYSICAL_SYNTHESIS_REGISTER_RETIMING OFF +set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_DUPLICATION ON +set_global_assignment -name CYCLONEII_OPTIMIZATION_TECHNIQUE SPEED +set_global_assignment -name OPTIMIZE_HOLD_TIMING "ALL PATHS" +set_global_assignment -name OPTIMIZE_MULTI_CORNER_TIMING ON +set_global_assignment -name FITTER_EFFORT "STANDARD FIT" +set_global_assignment -name VERILOG_SHOW_LMF_MAPPING_MESSAGES OFF +set_global_assignment -name VERILOG_MACRO "EXT_ROM=" +set_global_assignment -name FORCE_SYNCH_CLEAR ON +set_global_assignment -name SYSTEMVERILOG_FILE rtl/Galivan_MiST.sv +set_global_assignment -name QIP_FILE rtl/pll_mist.qip +set_global_assignment -name VERILOG_FILE rtl/video.v +set_global_assignment -name SYSTEMVERILOG_FILE rtl/spram.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/sdram.sv +set_global_assignment -name VERILOG_FILE rtl/gfx.v +set_global_assignment -name VERILOG_FILE rtl/dpram.v +set_global_assignment -name VERILOG_FILE rtl/core.v +set_global_assignment -name VERILOG_FILE rtl/clk_en.v +set_global_assignment -name VERILOG_FILE rtl/build_id.v +set_global_assignment -name QIP_FILE ../../common/mist/mist.qip +set_global_assignment -name QIP_FILE ../../common/Sound/jtopl/jt26.qip +set_global_assignment -name QIP_FILE ../../common/CPU/T80/T80.qip +set_global_assignment -name SIGNALTAP_FILE output_files/cpu.stp +set_global_assignment -name SIGNALTAP_FILE output_files/spri.stp +set_global_assignment -name SIGNALTAP_FILE output_files/tx.stp +set_global_assignment -name SIGNALTAP_FILE output_files/sh.stp +set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/Galivan.sdc b/Arcade_MiST/Nichibutsu Galivan Hardware/Galivan.sdc new file mode 100644 index 00000000..4a373c09 --- /dev/null +++ b/Arcade_MiST/Nichibutsu Galivan Hardware/Galivan.sdc @@ -0,0 +1,134 @@ +## Generated SDC file "vectrex_MiST.out.sdc" + +## Copyright (C) 1991-2013 Altera Corporation +## Your use of Altera Corporation's design tools, logic functions +## and other software and tools, and its AMPP partner logic +## functions, and any output files from any of the foregoing +## (including device programming or simulation files), and any +## associated documentation or information are expressly subject +## to the terms and conditions of the Altera Program License +## Subscription Agreement, Altera MegaCore Function License +## Agreement, or other applicable license agreement, including, +## without limitation, that your use is for the sole purpose of +## programming logic devices manufactured by Altera and sold by +## Altera or its authorized distributors. Please refer to the +## applicable agreement for further details. + + +## VENDOR "Altera" +## PROGRAM "Quartus II" +## VERSION "Version 13.1.0 Build 162 10/23/2013 SJ Web Edition" + +## DATE "Sun Jun 24 12:53:00 2018" + +## +## DEVICE "EP3C25E144C8" +## + +# Clock constraints + +# Automatically constrain PLL and other generated clocks +derive_pll_clocks -create_base_clocks + +# Automatically calculate clock uncertainty to jitter and other effects. +derive_clock_uncertainty + +# tsu/th constraints + +# tco constraints + +# tpd constraints + +#************************************************************** +# Time Information +#************************************************************** + +set_time_format -unit ns -decimal_places 3 + + + +#************************************************************** +# Create Clock +#************************************************************** + +create_clock -name {SPI_SCK} -period 41.666 -waveform { 20.8 41.666 } [get_ports {SPI_SCK}] + +set sdram_clk "pll|altpll_component|auto_generated|pll1|clk[0]" +set sys_clk "pll|altpll_component|auto_generated|pll1|clk[1]" +#************************************************************** +# Create Generated Clock +#************************************************************** + + +#************************************************************** +# Set Clock Latency +#************************************************************** + + + +#************************************************************** +# Set Clock Uncertainty +#************************************************************** + +#************************************************************** +# Set Input Delay +#************************************************************** + +set_input_delay -add_delay -clock_fall -clock [get_clocks {CLOCK_27}] 1.000 [get_ports {CLOCK_27}] +set_input_delay -add_delay -clock_fall -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {CONF_DATA0}] +set_input_delay -add_delay -clock_fall -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {SPI_DI}] +set_input_delay -add_delay -clock_fall -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {SPI_SCK}] +set_input_delay -add_delay -clock_fall -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {SPI_SS2}] +set_input_delay -add_delay -clock_fall -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {SPI_SS3}] + +set_input_delay -clock [get_clocks $sdram_clk] -reference_pin [get_ports {SDRAM_CLK}] -max 6.6 [get_ports SDRAM_DQ[*]] +set_input_delay -clock [get_clocks $sdram_clk] -reference_pin [get_ports {SDRAM_CLK}] -min 3.5 [get_ports SDRAM_DQ[*]] + +#************************************************************** +# Set Output Delay +#************************************************************** + +set_output_delay -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {SPI_DO}] +set_output_delay -clock [get_clocks $sys_clk] 1.000 [get_ports {AUDIO_L}] +set_output_delay -clock [get_clocks $sys_clk] 1.000 [get_ports {AUDIO_R}] +set_output_delay -clock [get_clocks $sys_clk] 1.000 [get_ports {LED}] +set_output_delay -clock [get_clocks $sys_clk] 1.000 [get_ports {VGA_*}] + +set_output_delay -clock [get_clocks $sdram_clk] -reference_pin [get_ports {SDRAM_CLK}] -max 1.5 [get_ports {SDRAM_D* SDRAM_A* SDRAM_BA* SDRAM_n* SDRAM_CKE}] +set_output_delay -clock [get_clocks $sdram_clk] -reference_pin [get_ports {SDRAM_CLK}] -min -0.8 [get_ports {SDRAM_D* SDRAM_A* SDRAM_BA* SDRAM_n* SDRAM_CKE}] + +#************************************************************** +# Set Clock Groups +#************************************************************** + +set_clock_groups -asynchronous -group [get_clocks {SPI_SCK}] -group [get_clocks {pll|altpll_component|auto_generated|pll1|clk[*]}] + +#************************************************************** +# Set False Path +#************************************************************** + + + +#************************************************************** +# Set Multicycle Path +#************************************************************** + +set_multicycle_path -to {VGA_*[*]} -setup 2 +set_multicycle_path -to {VGA_*[*]} -hold 1 + +#************************************************************** +# Set Maximum Delay +#************************************************************** + + + +#************************************************************** +# Set Minimum Delay +#************************************************************** + + + +#************************************************************** +# Set Input Transition +#************************************************************** + diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/LICENSE b/Arcade_MiST/Nichibutsu Galivan Hardware/LICENSE new file mode 100644 index 00000000..d159169d --- /dev/null +++ b/Arcade_MiST/Nichibutsu Galivan Hardware/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/Readme.md b/Arcade_MiST/Nichibutsu Galivan Hardware/Readme.md new file mode 100644 index 00000000..148f7524 --- /dev/null +++ b/Arcade_MiST/Nichibutsu Galivan Hardware/Readme.md @@ -0,0 +1,5 @@ +# Cosmo Police Galivan & UFO Robo Dangar + +This core is an emulation of the GV-1412 PCB from Nichibutsu originally by [Pierco](https://github.com/pcornier). Two games are supported: Cosmo Police Galivan & UFO Robo Dangar. Use a vertically oriented CRT for the best gaming experience! + +SDRAM controller/gfx layers rewrite by Gyorgy Szombathelyi diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/meta/Cosmo Police Galivan (12-26-1985).mra b/Arcade_MiST/Nichibutsu Galivan Hardware/meta/Cosmo Police Galivan (12-26-1985).mra new file mode 100644 index 00000000..7a2f80d8 --- /dev/null +++ b/Arcade_MiST/Nichibutsu Galivan Hardware/meta/Cosmo Police Galivan (12-26-1985).mra @@ -0,0 +1,98 @@ + + Cosmo Police Galivan (12/26/1985) + + no + no + + + + + 1985 + Nichibutsu + Platform + + galivan + 0246 + galivan + + + 15kHz + vertical + + + 2 + 8-way + + 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 202108231828 + \ No newline at end of file diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/meta/Ufo Robo Dangar (4-07-1987).mra b/Arcade_MiST/Nichibutsu Galivan Hardware/meta/Ufo Robo Dangar (4-07-1987).mra new file mode 100644 index 00000000..8cbb1ad5 --- /dev/null +++ b/Arcade_MiST/Nichibutsu Galivan Hardware/meta/Ufo Robo Dangar (4-07-1987).mra @@ -0,0 +1,99 @@ + + Ufo Robo Dangar (4/07/1987) + + no + no + + + + + 1985 + Nichibutsu + Platform + + dangar + 0246 + galivan + + + 15kHz + vertical + + + 2 + 8-way + + 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 202108231828 + diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/Galivan_MiST.sv b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/Galivan_MiST.sv new file mode 100644 index 00000000..e6e92cb6 --- /dev/null +++ b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/Galivan_MiST.sv @@ -0,0 +1,348 @@ +module Galivan_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, + output SPI_DO, + input SPI_DI, + input SPI_SS2, + input SPI_SS3, + 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 = { + "GALIVAN;;", + "O2,Rotate Controls,Off,On;", + "O34,Scanlines,Off,25%,50%,75%;", + "O5,Blend,Off,On;", + "O6,Joystick Swap,Off,On;", + "O8,Test mode,Off,On;", + "O1,Pause,Off,On;", + "DIP;", + "T0,Reset;", + "V,v1.00.",`BUILD_DATE +}; + +wire pause = status[1]; +wire rotate = status[2]; +wire [1:0] scanlines = status[4:3]; +wire blend = status[5]; +wire joyswap = status[6]; +wire service = status[8]; + +wire flip; +wire [1:0] orientation = {flip, 1'b1}; + +wire [7:0] j1 = ~{ m_fire1[2], 1'b0, m_fire1[1], m_fire1[0], m_right1, m_left1, m_down1, m_up1 }; +wire [7:0] j2 = ~{ m_fire2[2], 1'b0, m_fire2[1], m_fire2[0], m_right2, m_left2, m_down2, m_up2 }; +wire [7:0] p1 = ~status[23:16]; // dsw1 +wire [7:0] p2 = ~status[31:24]; // dsw2 + +wire [7:0] system = ~{ 3'b000, service, m_coin2, m_coin1, m_two_players, m_one_player }; + +assign LED = ~ioctl_downl; +assign SDRAM_CLK = clk_ram; +assign SDRAM_CKE = 1; + +wire clk_sys, clk_ram, pll_locked; +pll_mist pll( + .inclk0(CLOCK_27), + .c0(clk_ram), + .c1(clk_sys), + .locked(pll_locked) + ); + +wire [31:0] status; +wire [1:0] buttons; +wire [1:0] switches; +wire [19:0] joystick_0; +wire [19:0] joystick_1; +wire scandoublerD; +wire ypbpr; +wire no_csync; +wire [6:0] core_mod; +wire key_strobe; +wire key_pressed; +wire [7:0] key_code; + + +user_io #(.STRLEN(($size(CONF_STR)>>3)))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 ), + .core_mod (core_mod ), + .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] cpu1_rom_addr; +wire [15:0] cpu1_rom_do; +wire cpu1_rom_cs; +wire cpu1_rom_valid; +wire [15:0] cpu2_rom_addr; +wire [15:0] cpu2_rom_do; +wire cpu2_rom_cs; +wire cpu2_rom_valid; + +wire [13:0] gfx1_rom_addr; +wire [15:0] gfx1_rom_do; +wire [16:0] gfx2_rom_addr; +wire [15:0] gfx2_rom_do; +wire [15:0] gfx3_rom_addr; +wire [15:0] gfx3_rom_do; +wire gfx3_rom_ready; + +wire ioctl_downl; +wire ioctl_upl; +wire [7:0] ioctl_index; +wire ioctl_wr; +wire [24:0] ioctl_addr; +wire [7:0] ioctl_din; +wire [7:0] ioctl_dout; + +data_io data_io( + .clk_sys ( clk_sys ), + .SPI_SCK ( SPI_SCK ), + .SPI_SS2 ( SPI_SS2 ), + .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_din ( ioctl_din ), + .ioctl_dout ( ioctl_dout ) +); + +reg port1_req, port2_req; +sdram #(96) sdram( + .*, + .init_n ( pll_locked ), + .clk ( clk_ram ), + + // port1 for main and sound CPU + .port1_req ( port1_req ), + .port1_ack ( ), + .port1_a ( ioctl_addr[23:1] ), + .port1_ds ( {ioctl_addr[0], ~ioctl_addr[0]} ), + .port1_we ( rom_init ), + .port1_d ( {ioctl_dout, ioctl_dout} ), + .port1_q ( ), + + .cpu1_cs ( cpu1_rom_cs ), + .cpu1_addr ( {1'b0, cpu1_rom_addr[15:1]} ), + .cpu1_q ( cpu1_rom_do ), + .cpu1_valid ( cpu1_rom_valid ), + .cpu2_cs ( cpu2_rom_cs ), + .cpu2_addr ( {1'b1, cpu2_rom_addr[15:1]} ), + .cpu2_q ( cpu2_rom_do ), + .cpu2_valid ( cpu2_rom_valid ), + + // port2 for graphics + .port2_req ( port2_req ), + .port2_ack ( ), + .port2_a ( ioctl_addr[23:1] ), + .port2_ds ( {ioctl_addr[0], ~ioctl_addr[0]} ), + .port2_we ( rom_init ), + .port2_d ( {ioctl_dout, ioctl_dout} ), + .port2_q ( ), + + .gfx1_addr ( 27'he000 + gfx1_rom_addr[13:1] ), + .gfx1_q ( gfx1_rom_do ), + .gfx2_addr ( 27'h10000 + gfx2_rom_addr[16:1] ), + .gfx2_q ( gfx2_rom_do ), + .gfx3_addr ( 27'h20000 + gfx3_rom_addr[15:1] ), + .gfx3_q ( gfx3_rom_do ), + .gfx3_ready ( gfx3_rom_ready ) +); + +// ROM download controller +always @(posedge clk_sys) begin + reg ioctl_wr_last = 0; + + ioctl_wr_last <= ioctl_wr; + if (rom_init) begin + if (~ioctl_wr_last && ioctl_wr) begin + port1_req <= ~port1_req; + port2_req <= ~port2_req; + end + end +end + +reg reset = 1; +reg rom_loaded = 0; +always @(posedge clk_sys) begin + reg ioctl_downlD; + ioctl_downlD <= ioctl_downl; + + if (ioctl_downlD & ~ioctl_downl) rom_loaded <= 1; + reset <= status[0] | buttons[1] | ~rom_loaded; +end + + +wire [15:0] sound; +wire HBlank; +wire HSync; +wire VBlank; +wire VSync; +wire [8:0] hcount, vcount; +reg [2:0] vred, vgreen; +reg [1:0] vblue; + +wire ce_pix; + +video video( + .clk ( clk_sys ), + .ce_pix ( ce_pix ), + .hs ( HSync ), + .vs ( VSync ), + .hb ( HBlank ), + .vb ( VBlank ), + .hcount ( hcount ), + .vcount ( vcount ), + .hoffs (), + .voffs () +); + +wire rom_init = ioctl_downl && (ioctl_index==0); +//wire nvram_init = ioctl_downl && (ioctl_index==8'hFF); + +core u_core( + .reset ( reset ), + .clk_sys ( clk_sys ), + .ce_pix ( ce_pix ), + .pause ( pause ), + .j1 ( j1 ), + .j2 ( j2 ), + .p1 ( p1 ), + .p2 ( p2 ), + .system ( system ), + .ioctl_index ( ioctl_index ), + .ioctl_download ( rom_init ), + .ioctl_addr ( ioctl_addr ), + .ioctl_dout ( ioctl_dout ), + .ioctl_wr ( ioctl_wr ), + .hh ( hcount ), + .vv ( vcount ), + .red ( vred ), + .green ( vgreen ), + .blue ( vblue ), + .vs ( VSync ), + .hb ( HBlank ), + .sound ( sound ), + .hflip ( flip ), + .bg_on ( 1'b1 ), + .tx_on ( 1'b1 ), + .sp_on ( 1'b1 ), + .fdiv ( 2'b0 ), + + .cpu1_rom_cs ( cpu1_rom_cs ), + .cpu1_rom_addr ( cpu1_rom_addr ), + .cpu1_rom_q ( cpu1_rom_addr[0] ? cpu1_rom_do[15:8] : cpu1_rom_do[7:0] ), + .cpu1_rom_valid ( cpu1_rom_valid ), + .cpu2_rom_cs ( cpu2_rom_cs ), + .cpu2_rom_addr ( cpu2_rom_addr ), + .cpu2_rom_q ( cpu2_rom_addr[0] ? cpu2_rom_do[15:8] : cpu2_rom_do[7:0] ), + .cpu2_rom_valid ( cpu2_rom_valid ), + + .gfx1_rom_addr ( gfx1_rom_addr ), + .gfx1_rom_q ( gfx1_rom_addr[0] ? gfx1_rom_do[15:8] : gfx1_rom_do[7:0] ), + .gfx2_rom_addr ( gfx2_rom_addr ), + .gfx2_rom_q ( gfx2_rom_addr[0] ? gfx2_rom_do[15:8] : gfx2_rom_do[7:0] ), + .gfx3_rom_addr ( gfx3_rom_addr ), + .gfx3_rom_q ( gfx3_rom_addr[0] ? gfx3_rom_do[15:8] : gfx3_rom_do[7:0] ), + .gfx3_rom_ready ( gfx3_rom_ready ) +); + +wire blankn = !(HBlank | VBlank); + +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 ? vred : 0 ), + .G ( blankn ? vgreen : 0 ), + .B ( blankn ? {vblue, vblue[1]} : 0 ), + .HSync ( HSync ), + .VSync ( VSync ), + .VGA_R ( VGA_R ), + .VGA_G ( VGA_G ), + .VGA_B ( VGA_B ), + .VGA_VS ( VGA_VS ), + .VGA_HS ( VGA_HS ), + .ce_divider ( 1'b0 ), + .rotate ( { orientation[1], rotate } ), + .blend ( blend ), + .scandoubler_disable( scandoublerD ), + .scanlines ( scanlines ), + .ypbpr ( ypbpr ), + .no_csync ( no_csync ) + ); + +wire audio_out; +assign AUDIO_L = audio_out; +assign AUDIO_R = audio_out; + +dac #(.C_bits(16))dac( + .clk_i(clk_sys), + .res_n_i(1'b1), + .dac_i({~sound[15], sound[14:0]}), + .dac_o(audio_out) + ); + +wire m_up1, m_down1, m_left1, m_right1, m_up1B, m_down1B, m_left1B, m_right1B; +wire m_up2, m_down2, m_left2, m_right2, m_up2B, m_down2B, m_left2B, m_right2B; +wire m_tilt, m_coin1, m_coin2, m_coin3, m_coin4, m_one_player, m_two_players, m_three_players, m_four_players; +wire [11:0] m_fire1, m_fire2; + +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 ( orientation ), + .joyswap ( joyswap ), + .oneplayer ( 1'b0 ), + .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_up1B, m_down1B, m_left1B, m_right1B, m_fire1, m_up1, m_down1, m_left1, m_right1} ), + .player2 ( {m_up2B, m_down2B, m_left2B, m_right2B, m_fire2, m_up2, m_down2, m_left2, m_right2} ) +); + +endmodule diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/build_id.tcl b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/build_id.tcl new file mode 100644 index 00000000..938515d8 --- /dev/null +++ b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/build_id.tcl @@ -0,0 +1,35 @@ +# ================================================================================ +# +# Build ID Verilog Module Script +# Jeff Wiencrot - 8/1/2011 +# +# Generates a Verilog module that contains a timestamp, +# from the current build. These values are available from the build_date, build_time, +# physical_address, and host_name output ports of the build_id module in the build_id.v +# Verilog source file. +# +# ================================================================================ + +proc generateBuildID_Verilog {} { + + # Get the timestamp (see: http://www.altera.com/support/examples/tcl/tcl-date-time-stamp.html) + set buildDate [ clock format [ clock seconds ] -format %y%m%d ] + set buildTime [ clock format [ clock seconds ] -format %H%M%S ] + + # Create a Verilog file for output + set outputFileName "rtl/build_id.v" + set outputFile [open $outputFileName "w"] + + # Output the Verilog source + puts $outputFile "`define BUILD_DATE \"$buildDate\"" + puts $outputFile "`define BUILD_TIME \"$buildTime\"" + close $outputFile + + # Send confirmation message to the Messages window + post_message "Generated build identification Verilog module: [pwd]/$outputFileName" + post_message "Date: $buildDate" + post_message "Time: $buildTime" +} + +# Comment out this line to prevent the process from automatically executing when the file is sourced: +generateBuildID_Verilog \ No newline at end of file diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/clk_en.v b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/clk_en.v new file mode 100644 index 00000000..9eaf5b8d --- /dev/null +++ b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/clk_en.v @@ -0,0 +1,29 @@ + +module clk_en #( + parameter DIV=12, + parameter OFFSET=0 +) +( + input ref_clk, + output reg cen, + input [15:0] div, + input [1:0] fdiv +); + +reg [15:0] cnt = OFFSET; +wire [15:0] cmax = div << { fdiv, 1'b0 }; + +always @(posedge ref_clk) begin + if (fdiv != 2'b11) begin + if (cnt == cmax) begin + cnt <= 16'd0; + cen <= 1'b1; + end + else begin + cen <= 1'b0; + cnt <= cnt + 16'd1; + end + end +end + +endmodule diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/core.v b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/core.v new file mode 100644 index 00000000..feafd69a --- /dev/null +++ b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/core.v @@ -0,0 +1,662 @@ +//============================================================================ +// +// Nichibutsu Galivan Hardware +// +// Original by (C) 2022 Pierre Cornier +// Enhanced/optimized by (C) Gyorgy Szombathelyi +// +// 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 core( + input reset, + input clk_sys, + output ce_pix, + input pause, + + input [7:0] j1, + input [7:0] j2, + input [7:0] p1, + input [7:0] p2, + input [7:0] system, + + input [7:0] ioctl_index, + input ioctl_download, + input [26:0] ioctl_addr, + input [15:0] ioctl_dout, + input ioctl_wr, + + + output [2:0] red, + output [2:0] green, + output [1:0] blue, + + output [15:0] sound, + + input [8:0] hh, + input [8:0] vv, + input vs, + input hb, + output hflip, + + input bg_on, + input tx_on, + input sp_on, + + input [1:0] fdiv, + + output cpu1_rom_cs, + output [15:0] cpu1_rom_addr, + input [7:0] cpu1_rom_q, + input cpu1_rom_valid, + output cpu2_rom_cs, + output [15:0] cpu2_rom_addr, + input [7:0] cpu2_rom_q, + input cpu2_rom_valid, + + output [13:0] gfx1_rom_addr, + input [7:0] gfx1_rom_q, + output [16:0] gfx2_rom_addr, + input [7:0] gfx2_rom_q, + output [15:0] gfx3_rom_addr, + input [7:0] gfx3_rom_q, + input gfx3_rom_ready +); + + +/******** CLOCKS ********/ + +wire clk_en_4, clk_en_6, acpu_irq_en; +clk_en mcpu_clk_en(clk_sys, clk_en_6, 16'd7, fdiv); +clk_en acpu_clk_en(clk_sys, clk_en_4, 16'd11); +clk_en acpu_irq_cen(clk_sys, acpu_irq_en, 16'd6400); + +assign ce_pix = clk_en_6; + +/******** MCPU ********/ + +wire [7:0] mcpu_din; +wire [15:0] mcpu_addr; +wire [7:0] mcpu_dout; +wire mcpu_rd_n; +wire mcpu_wr_n; +wire mcpu_m1_n; +wire mcpu_mreq_n; +wire mcpu_iorq_n; +wire mcpu_rfsh_n; +reg mcpu_int_n; + +reg oldvs; +always @(posedge clk_sys) begin + oldvs <= vs; + if (oldvs & ~vs) mcpu_int_n <= 1'b0; + if (~mcpu_iorq_n & ~mcpu_m1_n) mcpu_int_n <= 1'b1; +end + +reg real_pause = 0; +always @(posedge clk_sys) + if (~clk_en_6 & mcpu_mreq_n & mcpu_iorq_n) real_pause <= pause; + + +t80s mcpu( + .reset_n ( ~reset ), + .clk ( clk_sys ), + .cen ( clk_en_6 & (!cpu1_rom_cs | cpu1_rom_valid) & !real_pause ), + .wait_n ( 1'b1 ), + .int_n ( mcpu_int_n ), + .nmi_n ( 1'b1 ), + .busrq_n ( 1'b1 ), + .m1_n ( mcpu_m1_n ), + .mreq_n ( mcpu_mreq_n ), + .iorq_n ( mcpu_iorq_n ), + .rd_n ( mcpu_rd_n ), + .wr_n ( mcpu_wr_n ), + .rfsh_n ( mcpu_rfsh_n ), + .halt_n ( ), + .busak_n ( ), + .A ( mcpu_addr ), + .di ( mcpu_din ), + .do ( mcpu_dout ) +); + +/******** MCPU MEMORY CS ********/ + +wire mcpu_rom1_en = mcpu_iorq_n & ~mcpu_addr[15]; // (mcpu_addr < 16'h8000); +wire mcpu_rom2_en = mcpu_iorq_n & mcpu_addr[15:14] == 2'b10; // ~mcpu_rom1_en & (mcpu_addr < 16'hc000); +wire mcpu_rom_en = mcpu_iorq_n & (mcpu_rom1_en | mcpu_rom2_en); +wire mcpu_bank_en = mcpu_iorq_n & /*mcpu_addr[15:13] == 3'b110; */ ~mcpu_rom_en & (mcpu_addr < 16'he000); +wire mcpu_vram1_en = mcpu_iorq_n & /*mcpu_addr[15:10] == 5'b1101_10; */ ~mcpu_rom_en & mcpu_bank_en & (mcpu_addr >= 16'hd800 && mcpu_addr < 16'hdc00); +wire mcpu_vram2_en = mcpu_iorq_n & /*mcpu_addr[15:10] == 5'b1101_11; */ ~mcpu_rom_en & mcpu_bank_en & (mcpu_addr >= 16'hdc00); +wire mcpu_spr_en = mcpu_iorq_n & ~mcpu_rom_en & ~mcpu_bank_en & (mcpu_addr < 16'he100); +wire mcpu_ram_en = mcpu_iorq_n & ~mcpu_rom_en & ~mcpu_bank_en & ~mcpu_spr_en; + +/******** MCPU MEMORIES ********/ +wire [9:0] gfx_vram_addr; +wire [5:0] gfx_spr_addr; + +wire [7:0] mcpu_rom1_q; +wire [7:0] mcpu_rom2_q; +wire [7:0] mcpu_bank1_q; +wire [7:0] mcpu_bank2_q; +wire [7:0] mcpu_vram1_q; +wire [7:0] mcpu_vram2_q; +wire [7:0] mcpu_spr_q; +wire [31:0] mcpu_spr_qb; +wire [7:0] mcpu_ram_q; + +`ifndef EXT_ROM +wire [7:0] mcpu_rom1_data = ioctl_dout[7:0]; +wire [14:0] mcpu_rom1_addr = ioctl_download ? ioctl_addr : mcpu_addr[14:0]; +wire mcpu_rom1_wren_a = ioctl_download && ioctl_addr < 27'h8000 ? ioctl_wr : 1'b0; +wire [7:0] mcpu_rom2_data = ioctl_dout[7:0]; +wire [14:0] mcpu_rom2_addr = ioctl_download ? ioctl_addr - 27'h8000 : mcpu_addr[14:0]; +wire mcpu_rom2_wren_a = ioctl_download && ioctl_addr >= 27'h8000 && ioctl_addr < 27'hc000 ? ioctl_wr : 1'b0; +wire [7:0] mcpu_bank1_data = ioctl_dout[7:0]; +wire [13:0] mcpu_bank1_addr = ioctl_download ? ioctl_addr - 27'hc000 : mcpu_addr[13:0]; +wire mcpu_bank1_wren_a = ioctl_download && ioctl_addr >= 27'hc000 && ioctl_addr < 27'he000 ? ioctl_wr : 1'b0; +wire [7:0] mcpu_bank2_data = ioctl_dout[7:0]; +wire [13:0] mcpu_bank2_addr = ioctl_download ? ioctl_addr - 27'he000 : mcpu_addr[13:0]; +wire mcpu_bank2_wren_a = ioctl_download && ioctl_addr >= 27'he000 && ioctl_addr < 27'h10000 ? ioctl_wr : 1'b0; + +dpram #(15,8) mcpu_rom1( + .clock ( clk_sys ), + .address_a ( mcpu_rom1_addr ), + .data_a ( mcpu_rom1_data ), + .q_a ( mcpu_rom1_q ), + .rden_a ( 1'b1 ), + .wren_a ( mcpu_rom1_wren_a ) +); + +dpram #(14,8) mcpu_rom2( + .clock ( clk_sys ), + .address_a ( mcpu_rom2_addr ), + .data_a ( mcpu_rom2_data ), + .q_a ( mcpu_rom2_q ), + .rden_a ( 1'b1 ), + .wren_a ( mcpu_rom2_wren_a ) +); + +// 0xc000-0xdfff +dpram #(14,8) mcpu_bank1( + .clock ( clk_sys ), + .address_a ( mcpu_bank1_addr ), + .data_a ( mcpu_bank1_data ), + .q_a ( mcpu_bank1_q ), + .rden_a ( 1'b1 ), + .wren_a ( mcpu_bank1_wren_a ) +); + +// 0xc000-0xdfff +dpram #(14,8) mcpu_bank2( + .clock ( clk_sys ), + .address_a ( mcpu_bank2_addr ), + .data_a ( mcpu_bank2_data ), + .q_a ( mcpu_bank2_q ), + .rden_a ( 1'b1 ), + .wren_a ( mcpu_bank2_wren_a ) +); + +`else +assign mcpu_rom1_q = cpu1_rom_q; +assign mcpu_rom2_q = cpu1_rom_q; +assign mcpu_bank1_q = cpu1_rom_q; +assign mcpu_bank2_q = cpu1_rom_q; +assign cpu1_rom_addr = mcpu_bank_en ? {bank ? 3'b111 : 3'b110, mcpu_addr[12:0]} : mcpu_addr; +assign cpu1_rom_cs = (mcpu_rom_en | mcpu_bank_en) & mcpu_rfsh_n & ~mcpu_mreq_n; +`endif + +// 0xd800-0xdbff (mcpu write only) +dpram #(10,8) mcpu_vram1( + .clock ( clk_sys ), + .address_a ( mcpu_addr[9:0] ), + .address_b ( gfx_vram_addr ), + .data_a ( mcpu_dout ), + .q_b ( mcpu_vram1_q ), + .rden_b ( 1'b1 ), + .wren_a ( ~mcpu_wr_n & mcpu_vram1_en ) +); + +// 0xdc00-0xdfff (mcpu write only) +dpram #(10,8) mcpu_vram2( + .clock ( clk_sys ), + .address_a ( mcpu_addr[9:0] ), + .address_b ( gfx_vram_addr ), + .data_a ( mcpu_dout ), + .q_b ( mcpu_vram2_q ), + .rden_b ( 1'b1 ), + .wren_a ( ~mcpu_wr_n & mcpu_vram2_en ) +); + +// 0xe000-0xe0ff +// SPRAM is managed by the GFX module + +// 0xe100-0xffff +dpram #(13,8) mcpu_ram( + .clock ( clk_sys ), + .address_a ( mcpu_addr[12:0] ), + .data_a ( mcpu_dout ), + .q_a ( mcpu_ram_q ), + .rden_a ( 1'b1 ), + .wren_a ( ~mcpu_wr_n & mcpu_ram_en ) +); + +/******** MCPU I/O ********/ + +reg [7:0] mcpu_io_data; +reg [10:0] scrollx; +reg [10:0] scrolly; +reg [2:0] layers; +reg [7:0] snd_latch; +reg clear_latch; +reg bank; +reg flip; +assign hflip = flip; + +always @(posedge clk_sys) begin + reg [7:0] old_j1; + old_j1 <= j1; + + if (clear_latch) snd_latch <= 8'd0; + if (~mcpu_iorq_n & mcpu_m1_n) begin + case (mcpu_addr[7:0]) + 8'h00: mcpu_io_data <= j1; + 8'h01: mcpu_io_data <= j2; + 8'h02: mcpu_io_data <= system; + 8'h03: mcpu_io_data <= p1; + 8'h04: mcpu_io_data <= p2; + 8'h40: { bank, flip } <= { mcpu_dout[7], mcpu_dout[2] }; + 8'h41: scrollx[7:0] <= mcpu_dout; + 8'h42: { layers, scrollx[10:8] } <= { mcpu_dout[7:5], mcpu_dout[2:0] }; + 8'h43: scrolly[7:0] <= mcpu_dout; + 8'h44: scrolly[10:8] <= mcpu_dout[2:0]; + 8'h45: snd_latch <= { mcpu_dout[6:0], 1'b1 }; + 8'hc0: mcpu_io_data <= 8'h58; + endcase + end + // for scroll layer debug + if (real_pause) begin + if (~j1[0] & old_j1[0]) scrollx <= scrollx - 5'd16; + if (~j1[1] & old_j1[1]) scrollx <= scrollx + 5'd16; + if (~j1[2] & old_j1[2]) scrollx <= scrollx - 1'd1; + if (~j1[3] & old_j1[3]) scrollx <= scrollx + 1'd1; + end +end + +/******** MCPU DATA BUS ********/ + +assign mcpu_din = + ~mcpu_iorq_n ? mcpu_io_data : + mcpu_rom1_en ? mcpu_rom1_q : + mcpu_rom2_en ? mcpu_rom2_q : + mcpu_bank_en & ~bank ? mcpu_bank1_q : + mcpu_bank_en & bank ? mcpu_bank2_q : + mcpu_spr_en ? mcpu_spr_q : + mcpu_ram_en ? mcpu_ram_q : 8'd0; + +/******** ACPU ********/ + +wire [7:0] acpu_din; +wire [15:0] acpu_addr; +wire [7:0] acpu_dout; +wire acpu_rd_n; +wire acpu_wr_n; +wire acpu_m1_n; +wire acpu_mreq_n; +wire acpu_iorq_n; +wire acpu_rfsh_n; +reg acpu_int_n; + +reg old_acpu_irq_en; +always @(posedge clk_sys) begin + old_acpu_irq_en <= acpu_irq_en; + if (~old_acpu_irq_en & acpu_irq_en) acpu_int_n <= 1'b0; + if (~acpu_iorq_n & ~acpu_m1_n) acpu_int_n <= 1'b1; +end + +t80s acpu( + .reset_n ( ~reset ), + .clk ( clk_sys ), + .cen ( clk_en_4 & (!cpu2_rom_cs | cpu2_rom_valid) ), + .wait_n ( 1'b1 ), + .int_n ( acpu_int_n ), + .nmi_n ( 1'b1 ), + .busrq_n ( 1'b1 ), + .m1_n ( acpu_m1_n ), + .mreq_n ( acpu_mreq_n ), + .iorq_n ( acpu_iorq_n ), + .rd_n ( acpu_rd_n ), + .wr_n ( acpu_wr_n ), + .rfsh_n ( acpu_rfsh_n ), + .halt_n ( ), + .busak_n ( ), + .A ( acpu_addr ), + .di ( acpu_din ), + .do ( acpu_dout ) +); + + +/******** ACPU MEMORY CS ********/ + +wire acpu_rom1_en = acpu_iorq_n & ~acpu_addr[15]; // acpu_addr < 16'h8000; +wire acpu_rom2_en = acpu_iorq_n & acpu_addr[15:14] == 2'b10; //~acpu_rom1_en & acpu_addr < 16'hc000; +wire acpu_ram_en = acpu_iorq_n & acpu_addr[15:14] == 2'b11; //~acpu_rom1_en & ~acpu_rom2_en; + +/******** ACPU MEMORIES ********/ +wire [7:0] acpu_ram_q; +wire [7:0] acpu_rom1_q; +wire [7:0] acpu_rom2_q; + +`ifndef EXT_ROM +wire [7:0] acpu_rom_data = ioctl_dout; +wire [15:0] acpu_rom1_addr = ioctl_download ? ioctl_addr - 27'h10000 : acpu_addr; +wire acpu_rom1_wren_a = ioctl_download && ioctl_addr >= 27'h10000 && ioctl_addr < 27'h18000 ? ioctl_wr : 1'b0; +wire [15:0] acpu_rom2_addr = ioctl_download ? ioctl_addr - 27'h18000 : acpu_addr; +wire acpu_rom2_wren_a = ioctl_download && ioctl_addr >= 27'h18000 && ioctl_addr < 27'h1c000 ? ioctl_wr : 1'b0; + +dpram #(15,8) acpu_rom1( + .clock ( clk_sys ), + .address_a ( acpu_rom1_addr ), + .data_a ( acpu_rom_data ), + .q_a ( acpu_rom1_q ), + .rden_a ( 1'b1 ), + .wren_a ( acpu_rom1_wren_a ) +); + +dpram #(14,8) acpu_rom2( + .clock ( clk_sys ), + .address_a ( acpu_rom2_addr ), + .data_a ( acpu_rom_data ), + .q_a ( acpu_rom2_q ), + .rden_a ( 1'b1 ), + .wren_a ( acpu_rom2_wren_a ) +); +`else +assign cpu2_rom_addr = acpu_addr; +assign cpu2_rom_cs = (acpu_rom1_en | acpu_rom2_en) & acpu_rfsh_n & ~acpu_mreq_n; +assign acpu_rom1_q = cpu2_rom_q; +assign acpu_rom2_q = cpu2_rom_q; +`endif + +dpram #(11,8) acpu_ram( + .clock ( clk_sys ), + .address_a ( acpu_addr[10:0] ), + .data_a ( acpu_dout ), + .q_a ( acpu_ram_q ), + .rden_a ( 1'b1 ), + .wren_a ( ~acpu_wr_n & acpu_ram_en ) +); + +/******** ACPU I/O ********/ +reg [7:0] dac1, dac2; +always @(posedge clk_sys) begin + clear_latch <= 1'b0; + if (~acpu_iorq_n & acpu_m1_n & ~acpu_wr_n) begin + case (acpu_addr[7:0]) + 8'h02: dac1 <= acpu_dout; + 8'h03: dac2 <= acpu_dout; + 8'h04: clear_latch <= 1'b1; + default: ; + endcase + end +end +wire snd_latch_cs = ~acpu_iorq_n & acpu_m1_n & acpu_addr[7:0] == 8'h06; + +/******** YM3526 ********/ + +wire ym3526_addr = acpu_addr[0]; +wire ym3526_cs = ~acpu_iorq_n & acpu_m1_n & acpu_addr[7:1] == 0; + +jtopl ym3526( + .rst ( reset ), + .clk ( clk_sys ), + .cen ( clk_en_4 ), + .din ( acpu_dout ), + .addr ( ym3526_addr ), + .cs_n ( ~ym3526_cs ), + .wr_n ( acpu_wr_n ), + .dout ( ), + .irq_n ( ), + .snd ( ym_sound ), + .sample ( ) +); +wire [15:0] ym_sound; +assign sound = ym_sound + {dac1, 5'd0} + {dac2, 5'd0}; + +/******** ACPU DATA BUS ********/ + +assign acpu_din = + snd_latch_cs ? snd_latch : + acpu_ram_en ? acpu_ram_q : + acpu_rom1_en ? acpu_rom1_q : + acpu_rom2_en ? acpu_rom2_q : + 8'hFF; // RST38h - important, as the code mistakenly enables interrupts in IM0 mode + +/********* GFX ********/ + +wire [13:0] gfx1_addr; +wire [16:0] gfx2_addr; +wire [15:0] gfx3_addr; +wire [13:0] gfx4_addr; + +wire [7:0] gfx_rom1_q; +wire [7:0] gfx_rom2_q; +wire [7:0] gfx_rom3_q; +wire [7:0] gfx_rom41_q; +wire [7:0] gfx_rom42_q; + +wire [7:0] gfx_prom_addr; +wire [7:0] gfx_prom4_addr; +wire [7:0] gfx_sprom_addr; + +wire [3:0] prom1_q; +wire [3:0] prom2_q; +wire [3:0] prom3_q; +wire [3:0] prom4_q; +wire [3:0] sprom_q; + +wire [2:0] r; +wire [2:0] g; +wire [1:0] b; + +gfx gfx( + + .clk ( clk_sys ), + .ce_pix ( ce_pix ), + .hh ( hh ), + .vv ( vv ), + + .scrollx ( scrollx ), + .scrolly ( scrolly ), + .layers ( layers ), + + .spram_addr ( mcpu_addr[7:0] ), + .spram_din ( mcpu_dout ), + .spram_dout ( mcpu_spr_q ), + .spram_wr ( ~mcpu_wr_n & mcpu_spr_en ), + + .bg_map_addr ( gfx4_addr ), + .bg_map_data ( gfx_rom41_q ), + .bg_attr_data ( gfx_rom42_q ), + .bg_tile_addr ( gfx2_addr ), + .bg_tile_data ( gfx_rom2_q ), + + .vram_addr ( gfx_vram_addr ), + .vram1_data ( mcpu_vram1_q ), + .vram2_data ( mcpu_vram2_q ), + .tx_tile_addr ( gfx1_addr ), + .tx_tile_data ( gfx_rom1_q ), + + + .spr_gfx_addr ( gfx3_addr ), + .spr_gfx_data ( gfx_rom3_q ), + .spr_gfx_rdy ( gfx3_rom_ready ), + .spr_bnk_addr ( gfx_sprom_addr ), + .spr_bnk_data ( sprom_q ), + .spr_lut_addr ( gfx_prom4_addr ), + .spr_lut_data ( prom4_q ), + + .prom_addr ( gfx_prom_addr ), + .prom1_data ( prom1_q ), + .prom2_data ( prom2_q ), + .prom3_data ( prom3_q ), + + .r ( red ), + .g ( green ), + .b ( blue ), + .h_flip ( flip ), + .v_flip ( flip ), + + .hb ( hb ), + + .bg_on ( bg_on ), + .tx_on ( tx_on ), + .sp_on ( sp_on ) + +); + +/******** GFX ROMs ********/ +wire [7:0] gfx_rom_data = ioctl_dout; + +`ifndef EXT_ROM +wire [13:0] gfx_rom1_addr = ioctl_download ? ioctl_addr - 27'h1c000 : gfx1_addr; +wire gfx_rom1_wren_a = ioctl_download && ioctl_addr >= 27'h1c000 && ioctl_addr < 27'h20000 ? ioctl_wr : 1'b0; +wire [16:0] gfx_rom2_addr = ioctl_download ? ioctl_addr - 27'h20000 : gfx2_addr; +wire gfx_rom2_wren_a = ioctl_download && ioctl_addr >= 27'h20000 && ioctl_addr < 27'h40000 ? ioctl_wr : 1'b0; +wire [15:0] gfx_rom3_addr = ioctl_download ? ioctl_addr - 27'h40000 : gfx3_addr; +wire gfx_rom3_wren_a = ioctl_download && ioctl_addr >= 27'h40000 && ioctl_addr < 27'h50000 ? ioctl_wr : 1'b0; + +dpram #(14,8) gfx_rom1( + .clock ( clk_sys ), + .address_a ( gfx_rom1_addr ), + .data_a ( gfx_rom_data ), + .q_a ( gfx_rom1_q ), + .rden_a ( 1'b1 ), + .wren_a ( gfx_rom1_wren_a ) +); + +dpram #(17,8) gfx_rom2( + .clock ( clk_sys ), + .address_a ( gfx_rom2_addr ), + .data_a ( gfx_rom_data ), + .q_a ( gfx_rom2_q ), + .rden_a ( 1'b1 ), + .wren_a ( gfx_rom2_wren_a ) +); + +dpram #(16,8) gfx_rom3( + .clock ( clk_sys ), + .address_a ( gfx_rom3_addr ), + .data_a ( gfx_rom_data ), + .q_a ( gfx_rom3_q ), + .rden_a ( 1'b1 ), + .wren_a ( gfx_rom3_wren_a ) +); + +`else + +assign gfx1_rom_addr = gfx1_addr; +assign gfx_rom1_q = gfx1_rom_q; +assign gfx2_rom_addr = gfx2_addr; +assign gfx_rom2_q = gfx2_rom_q; +assign gfx3_rom_addr = gfx3_addr; +assign gfx_rom3_q = gfx3_rom_q; + +`endif + +wire [13:0] gfx_rom41_addr = ioctl_download ? ioctl_addr - 27'h50000 : gfx4_addr; +wire gfx_rom41_wren_a = ioctl_download && ioctl_addr >= 27'h50000 && ioctl_addr < 27'h54000 ? ioctl_wr : 1'b0; +wire [13:0] gfx_rom42_addr = ioctl_download ? ioctl_addr - 27'h54000 : gfx4_addr; +wire gfx_rom42_wren_a = ioctl_download && ioctl_addr >= 27'h54000 && ioctl_addr < 27'h58000 ? ioctl_wr : 1'b0; + +dpram #(14,8) gfx_rom41( + .clock ( clk_sys ), + .address_a ( gfx_rom41_addr ), + .data_a ( gfx_rom_data ), + .q_a ( gfx_rom41_q ), + .rden_a ( 1'b1 ), + .wren_a ( gfx_rom41_wren_a ) +); + +dpram #(14,8) gfx_rom42( + .clock ( clk_sys ), + .address_a ( gfx_rom42_addr ), + .data_a ( gfx_rom_data ), + .q_a ( gfx_rom42_q ), + .rden_a ( 1'b1 ), + .wren_a ( gfx_rom42_wren_a ) +); + +/******** COLOR ROMs ********/ + +wire [7:0] prom1_addr = ioctl_download ? ioctl_addr - 27'h58000 : gfx_prom_addr; +wire prom1_wren_a = ioctl_download && ioctl_addr >= 27'h58000 && ioctl_addr < 27'h58100 ? ioctl_wr : 1'b0; +wire [7:0] prom2_addr = ioctl_download ? ioctl_addr - 27'h58100 : gfx_prom_addr; +wire prom2_wren_a = ioctl_download && ioctl_addr >= 27'h58100 && ioctl_addr < 27'h58200 ? ioctl_wr : 1'b0; +wire [7:0] prom3_addr = ioctl_download ? ioctl_addr - 27'h58200 : gfx_prom_addr; +wire prom3_wren_a = ioctl_download && ioctl_addr >= 27'h58200 && ioctl_addr < 27'h58300 ? ioctl_wr : 1'b0; + +wire [7:0] prom4_addr = ioctl_download ? ioctl_addr - 27'h58300 : gfx_prom4_addr; +wire prom4_wren_a = ioctl_download && ioctl_addr >= 27'h58300 && ioctl_addr < 27'h58400 ? ioctl_wr : 1'b0; +wire [7:0] sprom_addr = ioctl_download ? ioctl_addr - 27'h58400 : gfx_sprom_addr; +wire sprom_wren_a = ioctl_download && ioctl_addr >= 27'h58400 && ioctl_addr < 27'h58500 ? ioctl_wr : 1'b0; + +dpram #(8,4) prom1( + .clock ( clk_sys ), + .address_a ( prom1_addr ), + .data_a ( gfx_rom_data ), + .q_a ( prom1_q ), + .rden_a ( 1'b1 ), + .wren_a ( prom1_wren_a ) +); + +dpram #(8,4) prom2( + .clock ( clk_sys ), + .address_a ( prom2_addr ), + .data_a ( gfx_rom_data ), + .q_a ( prom2_q ), + .rden_a ( 1'b1 ), + .wren_a ( prom2_wren_a ) +); + +dpram #(8,4) prom3( + .clock ( clk_sys ), + .address_a ( prom3_addr ), + .data_a ( gfx_rom_data ), + .q_a ( prom3_q ), + .rden_a ( 1'b1 ), + .wren_a ( prom3_wren_a ) +); + +// sprite color lut +dpram #(8,4) slookup( + .clock ( clk_sys ), + .address_a ( prom4_addr ), + .data_a ( gfx_rom_data ), + .q_a ( prom4_q ), + .rden_a ( 1'b1 ), + .wren_a ( prom4_wren_a ) +); + +// sprite color bank info +dpram #(8,4) sprom( + .clock ( clk_sys ), + .address_a ( sprom_addr ), + .data_a ( gfx_rom_data ), + .q_a ( sprom_q ), + .rden_a ( 1'b1 ), + .wren_a ( sprom_wren_a ) +); + +endmodule diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/dpram.v b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/dpram.v new file mode 100644 index 00000000..e5e87fbc --- /dev/null +++ b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/dpram.v @@ -0,0 +1,137 @@ +// megafunction wizard: %RAM: 2-PORT% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: altsyncram + +// ============================================================ +// File Name: dpram.v +// Megafunction Name(s): +// altsyncram +// +// Simulation Library Files(s): +// altera_mf +// ============================================================ +// ************************************************************ +// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +// +// 17.0.0 Build 595 04/25/2017 SJ Lite Edition +// ************************************************************ + + +//Copyright (C) 2017 Intel Corporation. All rights reserved. +//Your use of Intel Corporation's design tools, logic functions +//and other software and tools, and its AMPP partner logic +//functions, and any output files from any of the foregoing +//(including device programming or simulation files), and any +//associated documentation or information are expressly subject +//to the terms and conditions of the Intel Program License +//Subscription Agreement, the Intel Quartus Prime License Agreement, +//the Intel MegaCore Function License Agreement, or other +//applicable license agreement, including, without limitation, +//that your use is for the sole purpose of programming logic +//devices manufactured by Intel and sold by Intel or its +//authorized distributors. Please refer to the applicable +//agreement for further details. + + +// synopsys translate_off +`timescale 1 ps / 1 ps +// synopsys translate_on +module dpram +#( + parameter ADDRWIDTH=12, + parameter DATAWIDTH=8 +) +( + address_a, + address_b, + clock, + data_a, + data_b, + wren_a, + wren_b, + rden_a, + rden_b, + q_a, + q_b); + + input [ADDRWIDTH-1:0] address_a; + input [ADDRWIDTH-1:0] address_b; + input clock; + input [DATAWIDTH-1:0] data_a; + input [DATAWIDTH-1:0] data_b; + input wren_a; + input wren_b; + input rden_a; + input rden_b; + output [DATAWIDTH-1:0] q_a; + output [DATAWIDTH-1:0] q_b; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_off +`endif + tri1 clock; + tri0 wren_a; + tri0 wren_b; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_on +`endif + + wire [DATAWIDTH-1:0] sub_wire0; + wire [DATAWIDTH-1:0] sub_wire1; + wire [DATAWIDTH-1:0] q_a = rden_a ? sub_wire0[DATAWIDTH-1:0] : {DATAWIDTH{1'b0}}; + wire [DATAWIDTH-1:0] q_b = rden_b ? sub_wire1[DATAWIDTH-1:0] : {DATAWIDTH{1'b0}}; + + altsyncram altsyncram_component ( + .address_a (address_a), + .address_b (address_b), + .clock0 (clock), + .data_a (data_a), + .data_b (data_b), + .wren_a (wren_a), + .wren_b (wren_b), + .q_a (sub_wire0), + .q_b (sub_wire1), + .aclr0 (1'b0), + .aclr1 (1'b0), + .addressstall_a (1'b0), + .addressstall_b (1'b0), + .byteena_a (1'b1), + .byteena_b (1'b1), + .clock1 (1'b1), + .clocken0 (1'b1), + .clocken1 (1'b1), + .clocken2 (1'b1), + .clocken3 (1'b1), + .eccstatus (), + .rden_a (1'b1), + .rden_b (1'b1)); + defparam + altsyncram_component.address_reg_b = "CLOCK0", + altsyncram_component.clock_enable_input_a = "BYPASS", + altsyncram_component.clock_enable_input_b = "BYPASS", + altsyncram_component.clock_enable_output_a = "BYPASS", + altsyncram_component.clock_enable_output_b = "BYPASS", + altsyncram_component.indata_reg_b = "CLOCK0", + altsyncram_component.intended_device_family = "Cyclone V", + altsyncram_component.lpm_type = "altsyncram", + altsyncram_component.numwords_a = 2**ADDRWIDTH, + altsyncram_component.numwords_b = 2**ADDRWIDTH, + altsyncram_component.operation_mode = "BIDIR_DUAL_PORT", + altsyncram_component.outdata_aclr_a = "NONE", + altsyncram_component.outdata_aclr_b = "NONE", + altsyncram_component.outdata_reg_a = "CLOCK0", + altsyncram_component.outdata_reg_b = "CLOCK0", + altsyncram_component.power_up_uninitialized = "FALSE", + altsyncram_component.read_during_write_mode_mixed_ports = "DONT_CARE", + altsyncram_component.read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ", + altsyncram_component.read_during_write_mode_port_b = "NEW_DATA_NO_NBE_READ", + altsyncram_component.widthad_a = ADDRWIDTH, + altsyncram_component.widthad_b = ADDRWIDTH, + altsyncram_component.width_a = DATAWIDTH, + altsyncram_component.width_b = DATAWIDTH, + altsyncram_component.width_byteena_a = 1, + altsyncram_component.width_byteena_b = 1, + altsyncram_component.wrcontrol_wraddress_reg_b = "CLOCK0"; + + +endmodule diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/gfx.v b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/gfx.v new file mode 100644 index 00000000..ed0cd099 --- /dev/null +++ b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/gfx.v @@ -0,0 +1,327 @@ +//============================================================================ +// +// Nichibutsu Galivan Hardware +// +// Original by (C) 2022 Pierre Cornier +// Enhanced/optimized by (C) Gyorgy Szombathelyi +// +// 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 gfx( + input clk, + input ce_pix, + + input [8:0] hh, + input [8:0] vv, + + input [10:0] scrollx, + input [10:0] scrolly, + input [2:0] layers, + + // mcpu sprite ram interface + input [7:0] spram_addr, + input [7:0] spram_din, + output reg [7:0] spram_dout, + input spram_wr, + + output reg [13:0] bg_map_addr, + input [7:0] bg_map_data, + input [7:0] bg_attr_data, + + output reg [16:0] bg_tile_addr, + input [7:0] bg_tile_data, + + output reg [10:0] vram_addr, + input [7:0] vram1_data, + input [7:0] vram2_data, + + output reg [13:0] tx_tile_addr, + input [7:0] tx_tile_data, + + output reg [7:0] prom_addr, + input [3:0] prom1_data, + input [3:0] prom2_data, + input [3:0] prom3_data, + + output reg [15:0] spr_gfx_addr, + input [7:0] spr_gfx_data, + input spr_gfx_rdy, + + output reg [7:0] spr_bnk_addr, + input [3:0] spr_bnk_data, + + output reg [7:0] spr_lut_addr, + input [3:0] spr_lut_data, + + output reg [2:0] r, g, + output reg [1:0] b, + + input h_flip, + input v_flip, + + input hb, + + input bg_on, + input tx_on, + input sp_on + +); + +// object RAM +// 4 bytes/sprite +// offset 0 - Y +// offset 1 - code[7:0] +// offset 2 - attr +// offset 3 - X + +reg [7:0] info[255:0]; +reg [7:0] smap[255:0]; // object ram copy + +wire [8:0] vh = v_flip ? {vv[8], ~vv[7:0]} : vv; +wire [8:0] hr = h_flip ? {hh[8], ~hh[7:0]} : hh; + +// line buffers +reg spbuf_wren_a; +reg [8:0] spbuf_addr_a; +reg [5:0] spbuf_data_a; +wire [5:0] spbuf_q_b; +wire [8:0] hr_sp = hr - (h_flip ? -4'd13 : 4'd13); + +dpram #(9,6) spbuf( + .clock ( clk ), + .address_a ( spbuf_addr_a ), + .data_a ( spbuf_data_a ), + .q_a ( ), + .rden_a ( 1'b0 ), + .wren_a ( spbuf_wren_a ), + + .address_b ( { ~vh[0], hr_sp[7:0] } ), + .data_b ( 6'h3f ), + .q_b ( spbuf_q_b ), + .rden_b ( 1'b1 ), + .wren_b ( ce_pix & ~hr_sp[8] ) +); + +// sprite registers + +reg [3:0] sp_next; +reg [3:0] sp_state; +reg [7:0] spri; + +reg [7:0] attr; +reg [8:0] spx; +reg [7:0] spy; +reg [8:0] code; + +wire [7:0] smap_q = smap[spri]; +wire [8:0] spy_next = v_flip ? smap_q - 1'd1 : 8'd239 - smap_q; +wire [7:0] spxa = spx[7:0] - 8'd128; +wire [7:0] sdy = vv - spy; +wire [3:0] sdyf = (!v_flip ^ attr[7]) ? sdy[3:0] : 4'd15 - sdy[3:0]; +reg [3:0] sdx; +wire [3:0] sdxf = attr[6] ? 4'd15 - sdx[3:0] : sdx[3:0]; +wire [3:0] sp_color_code = spr_gfx_data[sdx[0]*4+:4]; + +// bg registers +reg [10:0] scx_reg; +reg [10:0] scy_reg; +reg [7:0] bg_attr_data_d; +reg [7:0] bg_attr_data_d2; +reg [7:0] bg_tile_data_d; +wire [10:0] sh = {h_flip & hr[8], h_flip & hr[8], hr} + scx_reg; +wire [10:0] sv = vh + scy_reg; +wire [3:0] bg_color_code = bg_tile_data_d[sh[0]*4+:4]; + +// txt registers +reg [7:0] vram2_data_d; +reg [7:0] vram2_data_d2; +reg [7:0] tx_tile_data_d; +wire [3:0] tx_color_code = tx_tile_data_d[hr[0]*4+:4]; + +reg color_ok; +reg [3:0] rstate; +reg [3:0] rnext; +reg [5:0] bg, tx; + +reg [7:0] smap_addr; +reg copied; + +// sprite rendering to dual-line buffer +always @(posedge clk) begin + + spram_dout <= info[spram_addr]; + if (spram_wr) info[spram_addr] <= spram_din; + + if (vv == 0 && hh == 0) begin + scx_reg <= scrollx; + scy_reg <= scrolly; + copied = 1'b0; + end + + if (vv > 250 && ~copied) begin + smap[smap_addr] <= info[smap_addr]; + smap_addr <= smap_addr + 8'd1; + if (smap_addr == 8'd255) copied <= 1'b1; + end + + spbuf_wren_a <= 0; + case (sp_state) + + 4'd0: begin + spri <= 8'd0; + sp_state <= (hh == 0 && vv < 256 && sp_on) ? 4'd1 : 4'd0; + end + + 4'd1: begin + spy <= spy_next; // spri=0 + if (vv >= spy_next && vv < (spy_next+16)) begin + // sprite is visible + sp_state <= 4'd2; + spri <= spri + 1'd1; + end + else begin + // not visible, check next or finish + if (spri == 8'd252) sp_state <= 4'd0; + else spri <= spri + 4'd4; + end + end + + 4'd2: begin + code[7:0] <= smap_q; // spri=1 + spri <= spri + 1'd1; + sp_state <= 4'd3; + end + + 4'd3: begin + attr <= smap_q; // spri=2 + spri <= spri + 1'd1; + sp_state <= 4'd4; + end + + 4'd4: begin + spx <= { attr[0], smap_q }; // range is 0-511 visible area is 128-383 (spri=3) + code[8] <= attr[1]; + spri <= spri + 1'd1; + sp_state <= 4'd5; + sdx <= 4'd0; + end + + 4'd5: begin + spr_gfx_addr <= { sdx[1], code, sdyf[3:0], sdx[3:2] }; + spr_bnk_addr <= code[8:2]; +`ifdef EXT_ROM + if (spr_gfx_rdy) sp_state <= 4'd6; +`else + sp_state <= 4'd14; // for internal ROMs only + sp_next <= 4'd6; +`endif + end + + 4'd6: begin + spr_lut_addr <= { spr_bnk_data, sp_color_code }; + sp_state <= 4'd14; + sp_next <= 4'd7; + end + + 4'd7: begin + if (spx+sdxf > 128 && spx+sdxf < 256+128 && spr_lut_data != 4'hf) begin + spbuf_addr_a <= { vh[0], spxa+sdxf }; + spbuf_data_a <= { (spr_lut_data[3] ? spr_bnk_data[3:2] : spr_bnk_data[1:0]), sp_color_code }; + spbuf_wren_a <= 1; + end + + sdx <= sdx + 4'd1; + sp_state <= sdx[0] ? 4'd5 : 4'd6; + if (sdx == 4'd15) begin + sp_state <= spri == 0 ? 4'd0 : 4'd1; + end + end + + 4'd14: sp_state <= 4'd15; + 4'd15: sp_state <= sp_next; + + endcase +end + +// scrolling background layer +always @(posedge clk) begin + if (ce_pix) begin + if(sh[2:0] == (3'b111 ^ {3{h_flip}})) + bg_map_addr <= {sv[10:4], sh[10:4]}; + if(sh[0] ^ h_flip) begin + bg_tile_addr <= { bg_attr_data[1:0], bg_map_data, sv[3:0], ~sh[3], sh[2:1] }; + bg_tile_data_d <= bg_tile_data; + bg_attr_data_d <= bg_attr_data; + bg_attr_data_d2 <= bg_attr_data_d; + end + bg <= { (bg_color_code[3] ? bg_attr_data_d2[6:5] : bg_attr_data_d2[4:3]), bg_color_code }; + end +end + +// text layer +always @(posedge clk) begin + if (ce_pix) begin + if(hh[2:0] == 3'b111) + vram_addr <= { hr[7:3], vh[7:3] }; + if(hh[0]) begin + tx_tile_addr <= { vram2_data[0], vram1_data, vh[2:0], hr[2:1] }; + tx_tile_data_d <= tx_tile_data; + vram2_data_d <= vram2_data; + vram2_data_d2 <= vram2_data_d; + end + tx <= { (tx_color_code[3] ? vram2_data_d2[6:5] : vram2_data_d2[4:3]), tx_color_code }; + end +end + +// display output +always @(posedge clk) begin + if (ce_pix) begin + + color_ok <= 1'b0; + + if (~layers[1]) begin + prom_addr <= { 2'b11, bg }; + color_ok <= 1'b1; + end + + if (spbuf_q_b[3:0] != 4'hf) begin + prom_addr <= { 2'b10, spbuf_q_b }; + color_ok <= 1'b1; + end + + if (~layers[2] && tx[3:0] != 4'hf) begin + prom_addr <= { 2'b00, tx }; + color_ok <= 1'b1; + end + + if (layers[0] && spbuf_q_b[3:0] != 4'hf) begin + prom_addr <= { 2'b10, spbuf_q_b }; + color_ok <= 1'b1; + end + + if (color_ok) begin + r <= prom1_data[3:1]; + g <= prom2_data[3:1]; + b <= prom3_data[3:2]; + end + else begin + { r, g, b } <= 8'd0; + end + end +end + +endmodule diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/pll_mist.qip b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/pll_mist.qip new file mode 100644 index 00000000..d4720390 --- /dev/null +++ b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/pll_mist.qip @@ -0,0 +1,4 @@ +set_global_assignment -name IP_TOOL_NAME "ALTPLL" +set_global_assignment -name IP_TOOL_VERSION "13.1" +set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "pll_mist.vhd"] +set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pll_mist.ppf"] diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/pll_mist.vhd b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/pll_mist.vhd new file mode 100644 index 00000000..76244b2d --- /dev/null +++ b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/pll_mist.vhd @@ -0,0 +1,392 @@ +-- megafunction wizard: %ALTPLL% +-- GENERATION: STANDARD +-- VERSION: WM1.0 +-- MODULE: altpll + +-- ============================================================ +-- File Name: pll_mist.vhd +-- Megafunction Name(s): +-- altpll +-- +-- Simulation Library Files(s): +-- altera_mf +-- ============================================================ +-- ************************************************************ +-- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +-- +-- 13.1.4 Build 182 03/12/2014 SJ Web Edition +-- ************************************************************ + + +--Copyright (C) 1991-2014 Altera Corporation +--Your use of Altera Corporation's design tools, logic functions +--and other software and tools, and its AMPP partner logic +--functions, and any output files from any of the foregoing +--(including device programming or simulation files), and any +--associated documentation or information are expressly subject +--to the terms and conditions of the Altera Program License +--Subscription Agreement, Altera MegaCore Function License +--Agreement, or other applicable license agreement, including, +--without limitation, that your use is for the sole purpose of +--programming logic devices manufactured by Altera and sold by +--Altera or its authorized distributors. Please refer to the +--applicable agreement for further details. + + +LIBRARY ieee; +USE ieee.std_logic_1164.all; + +LIBRARY altera_mf; +USE altera_mf.all; + +ENTITY pll_mist IS + PORT + ( + inclk0 : IN STD_LOGIC := '0'; + c0 : OUT STD_LOGIC ; + c1 : OUT STD_LOGIC ; + locked : OUT STD_LOGIC + ); +END pll_mist; + + +ARCHITECTURE SYN OF pll_mist IS + + SIGNAL sub_wire0 : STD_LOGIC_VECTOR (4 DOWNTO 0); + SIGNAL sub_wire1 : STD_LOGIC ; + SIGNAL sub_wire2 : STD_LOGIC ; + SIGNAL sub_wire3 : STD_LOGIC ; + SIGNAL sub_wire4 : STD_LOGIC ; + SIGNAL sub_wire5 : STD_LOGIC_VECTOR (1 DOWNTO 0); + SIGNAL sub_wire6_bv : BIT_VECTOR (0 DOWNTO 0); + SIGNAL sub_wire6 : STD_LOGIC_VECTOR (0 DOWNTO 0); + + + + COMPONENT altpll + GENERIC ( + bandwidth_type : STRING; + clk0_divide_by : NATURAL; + clk0_duty_cycle : NATURAL; + clk0_multiply_by : NATURAL; + clk0_phase_shift : STRING; + clk1_divide_by : NATURAL; + clk1_duty_cycle : NATURAL; + clk1_multiply_by : NATURAL; + clk1_phase_shift : STRING; + compensate_clock : STRING; + inclk0_input_frequency : NATURAL; + intended_device_family : STRING; + lpm_hint : STRING; + lpm_type : STRING; + operation_mode : STRING; + pll_type : STRING; + port_activeclock : STRING; + port_areset : STRING; + port_clkbad0 : STRING; + port_clkbad1 : STRING; + port_clkloss : STRING; + port_clkswitch : STRING; + port_configupdate : STRING; + port_fbin : STRING; + port_inclk0 : STRING; + port_inclk1 : STRING; + port_locked : STRING; + port_pfdena : STRING; + port_phasecounterselect : STRING; + port_phasedone : STRING; + port_phasestep : STRING; + port_phaseupdown : STRING; + port_pllena : STRING; + port_scanaclr : STRING; + port_scanclk : STRING; + port_scanclkena : STRING; + port_scandata : STRING; + port_scandataout : STRING; + port_scandone : STRING; + port_scanread : STRING; + port_scanwrite : STRING; + port_clk0 : STRING; + port_clk1 : STRING; + port_clk2 : STRING; + port_clk3 : STRING; + port_clk4 : STRING; + port_clk5 : STRING; + port_clkena0 : STRING; + port_clkena1 : STRING; + port_clkena2 : STRING; + port_clkena3 : STRING; + port_clkena4 : STRING; + port_clkena5 : STRING; + port_extclk0 : STRING; + port_extclk1 : STRING; + port_extclk2 : STRING; + port_extclk3 : STRING; + self_reset_on_loss_lock : STRING; + width_clock : NATURAL + ); + PORT ( + clk : OUT STD_LOGIC_VECTOR (4 DOWNTO 0); + inclk : IN STD_LOGIC_VECTOR (1 DOWNTO 0); + locked : OUT STD_LOGIC + ); + END COMPONENT; + +BEGIN + sub_wire6_bv(0 DOWNTO 0) <= "0"; + sub_wire6 <= To_stdlogicvector(sub_wire6_bv); + sub_wire3 <= sub_wire0(0); + sub_wire1 <= sub_wire0(1); + c1 <= sub_wire1; + locked <= sub_wire2; + c0 <= sub_wire3; + sub_wire4 <= inclk0; + sub_wire5 <= sub_wire6(0 DOWNTO 0) & sub_wire4; + + altpll_component : altpll + GENERIC MAP ( + bandwidth_type => "AUTO", + clk0_divide_by => 9, + clk0_duty_cycle => 50, + clk0_multiply_by => 32, + clk0_phase_shift => "0", + clk1_divide_by => 9, + clk1_duty_cycle => 50, + clk1_multiply_by => 16, + clk1_phase_shift => "0", + compensate_clock => "CLK0", + inclk0_input_frequency => 37037, + intended_device_family => "Cyclone III", + lpm_hint => "CBX_MODULE_PREFIX=pll_mist", + lpm_type => "altpll", + operation_mode => "NORMAL", + pll_type => "AUTO", + port_activeclock => "PORT_UNUSED", + port_areset => "PORT_UNUSED", + port_clkbad0 => "PORT_UNUSED", + port_clkbad1 => "PORT_UNUSED", + port_clkloss => "PORT_UNUSED", + port_clkswitch => "PORT_UNUSED", + port_configupdate => "PORT_UNUSED", + port_fbin => "PORT_UNUSED", + port_inclk0 => "PORT_USED", + port_inclk1 => "PORT_UNUSED", + port_locked => "PORT_USED", + port_pfdena => "PORT_UNUSED", + port_phasecounterselect => "PORT_UNUSED", + port_phasedone => "PORT_UNUSED", + port_phasestep => "PORT_UNUSED", + port_phaseupdown => "PORT_UNUSED", + port_pllena => "PORT_UNUSED", + port_scanaclr => "PORT_UNUSED", + port_scanclk => "PORT_UNUSED", + port_scanclkena => "PORT_UNUSED", + port_scandata => "PORT_UNUSED", + port_scandataout => "PORT_UNUSED", + port_scandone => "PORT_UNUSED", + port_scanread => "PORT_UNUSED", + port_scanwrite => "PORT_UNUSED", + port_clk0 => "PORT_USED", + port_clk1 => "PORT_USED", + port_clk2 => "PORT_UNUSED", + port_clk3 => "PORT_UNUSED", + port_clk4 => "PORT_UNUSED", + port_clk5 => "PORT_UNUSED", + port_clkena0 => "PORT_UNUSED", + port_clkena1 => "PORT_UNUSED", + port_clkena2 => "PORT_UNUSED", + port_clkena3 => "PORT_UNUSED", + port_clkena4 => "PORT_UNUSED", + port_clkena5 => "PORT_UNUSED", + port_extclk0 => "PORT_UNUSED", + port_extclk1 => "PORT_UNUSED", + port_extclk2 => "PORT_UNUSED", + port_extclk3 => "PORT_UNUSED", + self_reset_on_loss_lock => "OFF", + width_clock => 5 + ) + PORT MAP ( + inclk => sub_wire5, + clk => sub_wire0, + locked => sub_wire2 + ); + + + +END SYN; + +-- ============================================================ +-- CNX file retrieval info +-- ============================================================ +-- Retrieval info: PRIVATE: ACTIVECLK_CHECK STRING "0" +-- Retrieval info: PRIVATE: BANDWIDTH STRING "1.000" +-- Retrieval info: PRIVATE: BANDWIDTH_FEATURE_ENABLED STRING "1" +-- Retrieval info: PRIVATE: BANDWIDTH_FREQ_UNIT STRING "MHz" +-- Retrieval info: PRIVATE: BANDWIDTH_PRESET STRING "Low" +-- Retrieval info: PRIVATE: BANDWIDTH_USE_AUTO STRING "1" +-- Retrieval info: PRIVATE: BANDWIDTH_USE_PRESET STRING "0" +-- Retrieval info: PRIVATE: CLKBAD_SWITCHOVER_CHECK STRING "0" +-- Retrieval info: PRIVATE: CLKLOSS_CHECK STRING "0" +-- Retrieval info: PRIVATE: CLKSWITCH_CHECK STRING "0" +-- Retrieval info: PRIVATE: CNX_NO_COMPENSATE_RADIO STRING "0" +-- Retrieval info: PRIVATE: CREATE_CLKBAD_CHECK STRING "0" +-- Retrieval info: PRIVATE: CREATE_INCLK1_CHECK STRING "0" +-- Retrieval info: PRIVATE: CUR_DEDICATED_CLK STRING "c0" +-- Retrieval info: PRIVATE: CUR_FBIN_CLK STRING "c0" +-- Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "8" +-- Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "30" +-- Retrieval info: PRIVATE: DIV_FACTOR1 NUMERIC "1" +-- Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000" +-- Retrieval info: PRIVATE: DUTY_CYCLE1 STRING "50.00000000" +-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "96.000000" +-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE1 STRING "48.000000" +-- Retrieval info: PRIVATE: EXPLICIT_SWITCHOVER_COUNTER STRING "0" +-- Retrieval info: PRIVATE: EXT_FEEDBACK_RADIO STRING "0" +-- Retrieval info: PRIVATE: GLOCKED_COUNTER_EDIT_CHANGED STRING "1" +-- Retrieval info: PRIVATE: GLOCKED_FEATURE_ENABLED STRING "0" +-- Retrieval info: PRIVATE: GLOCKED_MODE_CHECK STRING "0" +-- Retrieval info: PRIVATE: GLOCK_COUNTER_EDIT NUMERIC "1048575" +-- Retrieval info: PRIVATE: HAS_MANUAL_SWITCHOVER STRING "1" +-- Retrieval info: PRIVATE: INCLK0_FREQ_EDIT STRING "27.000" +-- Retrieval info: PRIVATE: INCLK0_FREQ_UNIT_COMBO STRING "MHz" +-- Retrieval info: PRIVATE: INCLK1_FREQ_EDIT STRING "100.000" +-- Retrieval info: PRIVATE: INCLK1_FREQ_EDIT_CHANGED STRING "1" +-- Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_CHANGED STRING "1" +-- Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_COMBO STRING "MHz" +-- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone III" +-- Retrieval info: PRIVATE: INT_FEEDBACK__MODE_RADIO STRING "1" +-- Retrieval info: PRIVATE: LOCKED_OUTPUT_CHECK STRING "1" +-- Retrieval info: PRIVATE: LONG_SCAN_RADIO STRING "1" +-- Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE STRING "Not Available" +-- Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE_DIRTY NUMERIC "0" +-- Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT0 STRING "deg" +-- Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT1 STRING "ps" +-- Retrieval info: PRIVATE: MIG_DEVICE_SPEED_GRADE STRING "Any" +-- Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0" +-- Retrieval info: PRIVATE: MIRROR_CLK1 STRING "0" +-- Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "41" +-- Retrieval info: PRIVATE: MULT_FACTOR1 NUMERIC "1" +-- Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1" +-- Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "96.00000000" +-- Retrieval info: PRIVATE: OUTPUT_FREQ1 STRING "48.00000000" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "1" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE1 STRING "1" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT1 STRING "MHz" +-- Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "1" +-- Retrieval info: PRIVATE: PHASE_RECONFIG_INPUTS_CHECK STRING "0" +-- Retrieval info: PRIVATE: PHASE_SHIFT0 STRING "0.00000000" +-- Retrieval info: PRIVATE: PHASE_SHIFT1 STRING "0.00000000" +-- Retrieval info: PRIVATE: PHASE_SHIFT_STEP_ENABLED_CHECK STRING "0" +-- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg" +-- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT1 STRING "ps" +-- Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0" +-- Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "0" +-- Retrieval info: PRIVATE: PLL_AUTOPLL_CHECK NUMERIC "1" +-- Retrieval info: PRIVATE: PLL_ENHPLL_CHECK NUMERIC "0" +-- Retrieval info: PRIVATE: PLL_FASTPLL_CHECK NUMERIC "0" +-- Retrieval info: PRIVATE: PLL_FBMIMIC_CHECK STRING "0" +-- Retrieval info: PRIVATE: PLL_LVDS_PLL_CHECK NUMERIC "0" +-- Retrieval info: PRIVATE: PLL_PFDENA_CHECK STRING "0" +-- Retrieval info: PRIVATE: PLL_TARGET_HARCOPY_CHECK NUMERIC "0" +-- Retrieval info: PRIVATE: PRIMARY_CLK_COMBO STRING "inclk0" +-- Retrieval info: PRIVATE: RECONFIG_FILE STRING "pll_mist.mif" +-- Retrieval info: PRIVATE: SACN_INPUTS_CHECK STRING "0" +-- Retrieval info: PRIVATE: SCAN_FEATURE_ENABLED STRING "1" +-- Retrieval info: PRIVATE: SELF_RESET_LOCK_LOSS STRING "0" +-- Retrieval info: PRIVATE: SHORT_SCAN_RADIO STRING "0" +-- Retrieval info: PRIVATE: SPREAD_FEATURE_ENABLED STRING "0" +-- Retrieval info: PRIVATE: SPREAD_FREQ STRING "50.000" +-- Retrieval info: PRIVATE: SPREAD_FREQ_UNIT STRING "KHz" +-- Retrieval info: PRIVATE: SPREAD_PERCENT STRING "0.500" +-- Retrieval info: PRIVATE: SPREAD_USE STRING "0" +-- Retrieval info: PRIVATE: SRC_SYNCH_COMP_RADIO STRING "0" +-- Retrieval info: PRIVATE: STICKY_CLK0 STRING "1" +-- Retrieval info: PRIVATE: STICKY_CLK1 STRING "1" +-- Retrieval info: PRIVATE: SWITCHOVER_COUNT_EDIT NUMERIC "1" +-- Retrieval info: PRIVATE: SWITCHOVER_FEATURE_ENABLED STRING "1" +-- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" +-- Retrieval info: PRIVATE: USE_CLK0 STRING "1" +-- Retrieval info: PRIVATE: USE_CLK1 STRING "1" +-- Retrieval info: PRIVATE: USE_CLKENA0 STRING "0" +-- Retrieval info: PRIVATE: USE_CLKENA1 STRING "0" +-- Retrieval info: PRIVATE: USE_MIL_SPEED_GRADE NUMERIC "0" +-- Retrieval info: PRIVATE: ZERO_DELAY_RADIO STRING "0" +-- Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +-- Retrieval info: CONSTANT: BANDWIDTH_TYPE STRING "AUTO" +-- Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "9" +-- Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50" +-- Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "32" +-- Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0" +-- Retrieval info: CONSTANT: CLK1_DIVIDE_BY NUMERIC "9" +-- Retrieval info: CONSTANT: CLK1_DUTY_CYCLE NUMERIC "50" +-- Retrieval info: CONSTANT: CLK1_MULTIPLY_BY NUMERIC "16" +-- Retrieval info: CONSTANT: CLK1_PHASE_SHIFT STRING "0" +-- Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK0" +-- Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "37037" +-- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone III" +-- Retrieval info: CONSTANT: LPM_TYPE STRING "altpll" +-- Retrieval info: CONSTANT: OPERATION_MODE STRING "NORMAL" +-- Retrieval info: CONSTANT: PLL_TYPE STRING "AUTO" +-- Retrieval info: CONSTANT: PORT_ACTIVECLOCK STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_ARESET STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CLKBAD0 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CLKBAD1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CLKLOSS STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CLKSWITCH STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CONFIGUPDATE STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_FBIN STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_INCLK0 STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_INCLK1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_LOCKED STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_PFDENA STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PHASECOUNTERSELECT STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PHASEDONE STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PHASESTEP STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PHASEUPDOWN STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PLLENA STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANACLR STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANCLK STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANCLKENA STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANDATA STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANDATAOUT STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANDONE STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANREAD STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANWRITE STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clk0 STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_clk1 STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_clk2 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clk3 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clk4 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clk5 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena0 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena2 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena3 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena4 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena5 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_extclk0 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_extclk1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_extclk2 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_extclk3 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: SELF_RESET_ON_LOSS_LOCK STRING "OFF" +-- Retrieval info: CONSTANT: WIDTH_CLOCK NUMERIC "5" +-- Retrieval info: USED_PORT: @clk 0 0 5 0 OUTPUT_CLK_EXT VCC "@clk[4..0]" +-- Retrieval info: USED_PORT: @inclk 0 0 2 0 INPUT_CLK_EXT VCC "@inclk[1..0]" +-- Retrieval info: USED_PORT: c0 0 0 0 0 OUTPUT_CLK_EXT VCC "c0" +-- Retrieval info: USED_PORT: c1 0 0 0 0 OUTPUT_CLK_EXT VCC "c1" +-- Retrieval info: USED_PORT: inclk0 0 0 0 0 INPUT_CLK_EXT GND "inclk0" +-- Retrieval info: USED_PORT: locked 0 0 0 0 OUTPUT GND "locked" +-- Retrieval info: CONNECT: @inclk 0 0 1 1 GND 0 0 0 0 +-- Retrieval info: CONNECT: @inclk 0 0 1 0 inclk0 0 0 0 0 +-- Retrieval info: CONNECT: c0 0 0 0 0 @clk 0 0 1 0 +-- Retrieval info: CONNECT: c1 0 0 0 0 @clk 0 0 1 1 +-- Retrieval info: CONNECT: locked 0 0 0 0 @locked 0 0 0 0 +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll_mist.vhd TRUE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll_mist.ppf TRUE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll_mist.inc FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll_mist.cmp FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll_mist.bsf FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll_mist_inst.vhd FALSE +-- Retrieval info: LIB_FILE: altera_mf +-- Retrieval info: CBX_MODULE_PREFIX: ON diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/sdram.sv b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/sdram.sv new file mode 100644 index 00000000..65dc05f9 --- /dev/null +++ b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/sdram.sv @@ -0,0 +1,363 @@ +// +// sdram.v +// +// sdram controller implementation for the MiST board +// https://github.com/mist-devel/mist-board +// +// Copyright (c) 2013 Till Harbaum +// Copyright (c) 2019 Gyorgy Szombathelyi +// +// This source file 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 3 of the License, or +// (at your option) any later version. +// +// This source file 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, see . +// + +module sdram ( + + // interface to the MT48LC16M16 chip + inout reg [15:0] SDRAM_DQ, // 16 bit bidirectional data bus + output reg [12:0] SDRAM_A, // 13 bit multiplexed address bus + output reg SDRAM_DQML, // two byte masks + output reg SDRAM_DQMH, // two byte masks + output reg [1:0] SDRAM_BA, // two banks + output SDRAM_nCS, // a single chip select + output SDRAM_nWE, // write enable + output SDRAM_nRAS, // row address select + output SDRAM_nCAS, // columns address select + + // cpu/chipset interface + input init_n, // init signal after FPGA config to initialize RAM + input clk, // sdram clock + + input port1_req, + output reg port1_ack, + input port1_we, + input [23:1] port1_a, + input [1:0] port1_ds, + input [15:0] port1_d, + output reg [15:0] port1_q, + + input cpu1_cs, + input [16:1] cpu1_addr, + output reg [15:0] cpu1_q, + output reg cpu1_valid, + input cpu2_cs, + input [16:1] cpu2_addr, + output reg [15:0] cpu2_q, + output reg cpu2_valid, + + input port2_req, + output reg port2_ack, + input port2_we, + input [23:1] port2_a, + input [1:0] port2_ds, + input [15:0] port2_d, + output reg [15:0] port2_q, + + input [22:1] gfx1_addr, + output reg [15:0] gfx1_q, + input [22:1] gfx2_addr, + output reg [15:0] gfx2_q, + input [22:1] gfx3_addr, + output reg [15:0] gfx3_q, + output gfx3_ready +); +parameter MHZ = 80; // 80 MHz default clock, adjust to calculate the refresh rate correctly + +localparam RASCAS_DELAY = 3'd2; // tRCD=20ns -> 2 cycles@<100MHz +localparam BURST_LENGTH = 3'b000; // 000=1, 001=2, 010=4, 011=8 +localparam ACCESS_TYPE = 1'b0; // 0=sequential, 1=interleaved +localparam CAS_LATENCY = 3'd2; // 2/3 allowed +localparam OP_MODE = 2'b00; // only 00 (standard operation) allowed +localparam NO_WRITE_BURST = 1'b1; // 0= write burst enabled, 1=only single access write + +localparam MODE = { 3'b000, NO_WRITE_BURST, OP_MODE, CAS_LATENCY, ACCESS_TYPE, BURST_LENGTH}; + +// 64ms/8192 rows = 7.8us -> 842 cycles@108MHz +localparam RFRSH_CYCLES = 16'd78*MHZ/10; + +// --------------------------------------------------------------------- +// ------------------------ cycle state machine ------------------------ +// --------------------------------------------------------------------- + +/* + SDRAM state machine for 2 bank interleaved access + 1 word burst, CL2 +cmd issued registered + 0 RAS0 cas1 + 1 ras0 + 2 CAS0 data1 returned + 3 RAS1 cas0 + 4 ras1 + 5 CAS1 data0 returned +*/ + +localparam STATE_RAS0 = 3'd0; // first state in cycle +localparam STATE_RAS1 = 3'd3; // Second ACTIVE command after RAS0 + tRRD (15ns) +localparam STATE_CAS0 = STATE_RAS0 + RASCAS_DELAY; // CAS phase - 2 +localparam STATE_CAS1 = STATE_RAS1 + RASCAS_DELAY; // CAS phase - 5 +localparam STATE_READ0 = 3'd0;// STATE_CAS0 + CAS_LATENCY + 2'd2; +localparam STATE_READ1 = 3'd3; +localparam STATE_LAST = 3'd5; + +reg [2:0] t; + +always @(posedge clk) begin + t <= t + 1'd1; + if (t == STATE_LAST) t <= STATE_RAS0; +end + +// --------------------------------------------------------------------- +// --------------------------- startup/reset --------------------------- +// --------------------------------------------------------------------- + +// wait 1ms (32 8Mhz cycles) after FPGA config is done before going +// into normal operation. Initialize the ram in the last 16 reset cycles (cycles 15-0) +reg [4:0] reset; +reg init = 1'b1; +always @(posedge clk, negedge init_n) begin + if(!init_n) begin + reset <= 5'h1f; + init <= 1'b1; + end else begin + if((t == STATE_LAST) && (reset != 0)) reset <= reset - 5'd1; + init <= !(reset == 0); + end +end + +// --------------------------------------------------------------------- +// ------------------ generate ram control signals --------------------- +// --------------------------------------------------------------------- + +// all possible commands +localparam CMD_INHIBIT = 4'b1111; +localparam CMD_NOP = 4'b0111; +localparam CMD_ACTIVE = 4'b0011; +localparam CMD_READ = 4'b0101; +localparam CMD_WRITE = 4'b0100; +localparam CMD_BURST_TERMINATE = 4'b0110; +localparam CMD_PRECHARGE = 4'b0010; +localparam CMD_AUTO_REFRESH = 4'b0001; +localparam CMD_LOAD_MODE = 4'b0000; + +reg [3:0] sd_cmd; // current command sent to sd ram +reg [15:0] sd_din; +// drive control signals according to current command +assign SDRAM_nCS = sd_cmd[3]; +assign SDRAM_nRAS = sd_cmd[2]; +assign SDRAM_nCAS = sd_cmd[1]; +assign SDRAM_nWE = sd_cmd[0]; + +reg [24:1] addr_latch[2]; +reg [24:1] addr_latch_next[2]; +reg [22:1] addr_last2[4]; +reg [15:0] din_latch[2]; +reg [1:0] oe_latch; +reg [1:0] we_latch; +reg [1:0] ds[2]; + +reg port1_state; +reg port2_state; +reg [1:0] gfx3_ok = 0; +assign gfx3_ready = |gfx3_ok; + +localparam PORT_NONE = 3'd0; +localparam PORT_CPU1 = 3'd1; +localparam PORT_CPU2 = 3'd2; +localparam PORT_GFX1 = 3'd1; +localparam PORT_GFX2 = 3'd2; +localparam PORT_GFX3 = 3'd3; +localparam PORT_REQ = 3'd4; + +reg [2:0] next_port[2]; +reg [2:0] port[2]; +wire oe_next, we_next; +wire [1:0] ds_next; +wire [15:0] din_next; +reg refresh; +reg [10:0] refresh_cnt; +wire need_refresh = (refresh_cnt >= RFRSH_CYCLES); + +// PORT1: bank 0,1 +always @(*) begin + next_port[0] = PORT_NONE; + addr_latch_next[0] = 0; + ds_next = 2'b00; + { oe_next, we_next } = 2'b00; + din_next = 0; + + if (refresh) begin + // nothing + end else if (port1_req ^ port1_state) begin + next_port[0] = PORT_REQ; + addr_latch_next[0] = { 1'b0, port1_a }; + ds_next = port1_ds; + { oe_next, we_next } = { ~port1_we, port1_we }; + din_next = port1_d; + end else if (cpu1_cs & !cpu1_valid) begin + next_port[0] = PORT_CPU1; + addr_latch_next[0] = { 8'd0, cpu1_addr }; + ds_next = 2'b11; + { oe_next, we_next } = { 2'b10 }; + end else if (cpu2_cs & !cpu2_valid) begin + next_port[0] = PORT_CPU2; + addr_latch_next[0] = { 8'd0, cpu2_addr }; + ds_next = 2'b11; + { oe_next, we_next } = { 2'b10 }; + end +end + +// PORT1: bank 2,3 +always @(*) begin + if (port2_req ^ port2_state) begin + next_port[1] = PORT_REQ; + addr_latch_next[1] = { 1'b1, port2_a }; + end else if (gfx1_addr != addr_last2[PORT_GFX1]) begin + next_port[1] = PORT_GFX1; + addr_latch_next[1] = { 2'b10, gfx1_addr }; + end else if (gfx2_addr != addr_last2[PORT_GFX2]) begin + next_port[1] = PORT_GFX2; + addr_latch_next[1] = { 2'b10, gfx2_addr }; + end else if (gfx3_addr != addr_last2[PORT_GFX3]) begin + next_port[1] = PORT_GFX3; + addr_latch_next[1] = { 2'b10, gfx3_addr }; + end else begin + next_port[1] = PORT_NONE; + addr_latch_next[1] = addr_latch[1]; + end +end + +always @(posedge clk) begin + gfx3_ok <= {gfx3_ok[0], 1'b0}; + + // permanently latch ram data to reduce delays + sd_din <= SDRAM_DQ; + SDRAM_DQ <= 16'bZZZZZZZZZZZZZZZZ; + { SDRAM_DQMH, SDRAM_DQML } <= 2'b11; + sd_cmd <= CMD_NOP; // default: idle + refresh_cnt <= refresh_cnt + 1'd1; + + if (!cpu1_cs) cpu1_valid <= 0; + if (!cpu2_cs) cpu2_valid <= 0; + + if(init) begin + // initialization takes place at the end of the reset phase + if(t == STATE_RAS0) begin + + if(reset == 15) begin + sd_cmd <= CMD_PRECHARGE; + SDRAM_A[10] <= 1'b1; // precharge all banks + end + + if(reset == 10 || reset == 8) begin + sd_cmd <= CMD_AUTO_REFRESH; + end + + if(reset == 2) begin + sd_cmd <= CMD_LOAD_MODE; + SDRAM_A <= MODE; + SDRAM_BA <= 2'b00; + end + end + end else begin + // RAS phase + // bank 0,1 + if(t == STATE_RAS0) begin + addr_latch[0] <= addr_latch_next[0]; + port[0] <= next_port[0]; + { oe_latch[0], we_latch[0] } <= { oe_next, we_next }; + ds[0] <= ds_next; + din_latch[0] <= din_next; + if (next_port[0] != PORT_NONE) begin + sd_cmd <= CMD_ACTIVE; + SDRAM_A <= addr_latch_next[0][22:10]; + SDRAM_BA <= addr_latch_next[0][24:23]; + end + if (next_port[0] == PORT_REQ) port1_state <= port1_req; + end + + // bank 2,3 + if(t == STATE_RAS1) begin + refresh <= 1'b0; + addr_latch[1] <= addr_latch_next[1]; + { oe_latch[1], we_latch[1] } <= 2'b00; + port[1] <= next_port[1]; + + if (next_port[1] != PORT_NONE) begin + sd_cmd <= CMD_ACTIVE; + SDRAM_A <= addr_latch_next[1][22:10]; + SDRAM_BA <= addr_latch_next[1][24:23]; + addr_last2[next_port[1]] <= addr_latch_next[1][22:1]; + if (next_port[1] == PORT_REQ) begin + { oe_latch[1], we_latch[1] } <= { ~port1_we, port1_we }; + ds[1] <= port2_ds; + din_latch[1] <= port2_d; + port2_state <= port2_req; + end else begin + { oe_latch[1], we_latch[1] } <= 2'b10; + ds[1] <= 2'b11; + end + end + + if (next_port[1] == PORT_NONE && need_refresh && !we_latch[0] && !oe_latch[0]) begin + refresh <= 1'b1; + refresh_cnt <= 0; + sd_cmd <= CMD_AUTO_REFRESH; + end + end + + // CAS phase + if(t == STATE_CAS0 && (we_latch[0] || oe_latch[0])) begin + sd_cmd <= we_latch[0]?CMD_WRITE:CMD_READ; + { SDRAM_DQMH, SDRAM_DQML } <= ~ds[0]; + if (we_latch[0]) begin + SDRAM_DQ <= din_latch[0]; + port1_ack <= port1_req; + end + SDRAM_A <= { 4'b0010, addr_latch[0][9:1] }; // auto precharge + SDRAM_BA <= addr_latch[0][24:23]; + end + + if(t == STATE_CAS1 && (we_latch[1] || oe_latch[1])) begin + sd_cmd <= we_latch[1]?CMD_WRITE:CMD_READ; + { SDRAM_DQMH, SDRAM_DQML } <= ~ds[1]; + if (we_latch[1]) begin + SDRAM_DQ <= din_latch[1]; + port2_ack <= port2_req; + end + SDRAM_A <= { 4'b0010, addr_latch[1][9:1] }; // auto precharge + SDRAM_BA <= addr_latch[1][24:23]; + end + + // Data returned + if(t == STATE_READ0 && oe_latch[0]) begin + case(port[0]) + PORT_REQ: begin port1_q <= sd_din; port1_ack <= port1_req; end + PORT_CPU1: begin cpu1_q <= sd_din; cpu1_valid <= 1; end + PORT_CPU2: begin cpu2_q <= sd_din; cpu2_valid <= 1; end + default: ; + endcase; + end + + if(t == STATE_READ1 && oe_latch[1]) begin + case(port[1]) + PORT_REQ: port2_q <= sd_din; + PORT_GFX1: gfx1_q <= sd_din; + PORT_GFX2: gfx2_q <= sd_din; + PORT_GFX3: begin gfx3_q <= sd_din; gfx3_ok <= 2'b01; end + default: ; + endcase; + end + end +end + +endmodule diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/spram.sv b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/spram.sv new file mode 100644 index 00000000..0e87a779 --- /dev/null +++ b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/spram.sv @@ -0,0 +1,253 @@ +// megafunction wizard: %RAM: 2-PORT% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: altsyncram + +// ============================================================ +// File Name: spram.v +// Megafunction Name(s): +// altsyncram +// +// Simulation Library Files(s): +// altera_mf +// ============================================================ +// ************************************************************ +// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +// +// 17.0.0 Build 595 04/25/2017 SJ Lite Edition +// ************************************************************ + + +//Copyright (C) 2017 Intel Corporation. All rights reserved. +//Your use of Intel Corporation's design tools, logic functions +//and other software and tools, and its AMPP partner logic +//functions, and any output files from any of the foregoing +//(including device programming or simulation files), and any +//associated documentation or information are expressly subject +//to the terms and conditions of the Intel Program License +//Subscription Agreement, the Intel Quartus Prime License Agreement, +//the Intel MegaCore Function License Agreement, or other +//applicable license agreement, including, without limitation, +//that your use is for the sole purpose of programming logic +//devices manufactured by Intel and sold by Intel or its +//authorized distributors. Please refer to the applicable +//agreement for further details. + + +// synopsys translate_off +`timescale 1 ps / 1 ps +// synopsys translate_on +module spram ( + address_a, + address_b, + clock, + data_a, + data_b, + rden_a, + rden_b, + wren_a, + wren_b, + q_a, + q_b); + + input [7:0] address_a; + input [5:0] address_b; + input clock; + input [7:0] data_a; + input [31:0] data_b; + input rden_a; + input rden_b; + input wren_a; + input wren_b; + output [7:0] q_a; + output [31:0] q_b; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_off +`endif + tri1 clock; + tri1 rden_a; + tri1 rden_b; + tri0 wren_a; + tri0 wren_b; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_on +`endif + + wire [7:0] sub_wire0; + wire [31:0] sub_wire1; + wire [7:0] q_a = sub_wire0[7:0]; + wire [31:0] q_b = sub_wire1[31:0]; + + altsyncram altsyncram_component ( + .address_a (address_a), + .address_b (address_b), + .clock0 (clock), + .data_a (data_a), + .data_b (data_b), + .rden_a (rden_a), + .rden_b (rden_b), + .wren_a (wren_a), + .wren_b (wren_b), + .q_a (sub_wire0), + .q_b (sub_wire1), + .aclr0 (1'b0), + .aclr1 (1'b0), + .addressstall_a (1'b0), + .addressstall_b (1'b0), + .byteena_a (1'b1), + .byteena_b (1'b1), + .clock1 (1'b1), + .clocken0 (1'b1), + .clocken1 (1'b1), + .clocken2 (1'b1), + .clocken3 (1'b1), + .eccstatus ()); + defparam + altsyncram_component.address_reg_b = "CLOCK0", + altsyncram_component.clock_enable_input_a = "BYPASS", + altsyncram_component.clock_enable_input_b = "BYPASS", + altsyncram_component.clock_enable_output_a = "BYPASS", + altsyncram_component.clock_enable_output_b = "BYPASS", + altsyncram_component.indata_reg_b = "CLOCK0", + altsyncram_component.intended_device_family = "Cyclone V", + altsyncram_component.lpm_type = "altsyncram", + altsyncram_component.numwords_a = 256, + altsyncram_component.numwords_b = 64, + altsyncram_component.operation_mode = "BIDIR_DUAL_PORT", + altsyncram_component.outdata_aclr_a = "NONE", + altsyncram_component.outdata_aclr_b = "NONE", + altsyncram_component.outdata_reg_a = "CLOCK0", + altsyncram_component.outdata_reg_b = "CLOCK0", + altsyncram_component.power_up_uninitialized = "FALSE", + altsyncram_component.read_during_write_mode_mixed_ports = "DONT_CARE", + altsyncram_component.read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ", + altsyncram_component.read_during_write_mode_port_b = "NEW_DATA_NO_NBE_READ", + altsyncram_component.widthad_a = 8, + altsyncram_component.widthad_b = 6, + altsyncram_component.width_a = 8, + altsyncram_component.width_b = 32, + altsyncram_component.width_byteena_a = 1, + altsyncram_component.width_byteena_b = 1, + altsyncram_component.wrcontrol_wraddress_reg_b = "CLOCK0"; + + +endmodule + +// ============================================================ +// CNX file retrieval info +// ============================================================ +// Retrieval info: PRIVATE: ADDRESSSTALL_A NUMERIC "0" +// Retrieval info: PRIVATE: ADDRESSSTALL_B NUMERIC "0" +// Retrieval info: PRIVATE: BYTEENA_ACLR_A NUMERIC "0" +// Retrieval info: PRIVATE: BYTEENA_ACLR_B NUMERIC "0" +// Retrieval info: PRIVATE: BYTE_ENABLE_A NUMERIC "0" +// Retrieval info: PRIVATE: BYTE_ENABLE_B NUMERIC "0" +// Retrieval info: PRIVATE: BYTE_SIZE NUMERIC "8" +// Retrieval info: PRIVATE: BlankMemory NUMERIC "1" +// Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_A NUMERIC "0" +// Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_B NUMERIC "0" +// Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_A NUMERIC "0" +// Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_B NUMERIC "0" +// Retrieval info: PRIVATE: CLRdata NUMERIC "0" +// Retrieval info: PRIVATE: CLRq NUMERIC "0" +// Retrieval info: PRIVATE: CLRrdaddress NUMERIC "0" +// Retrieval info: PRIVATE: CLRrren NUMERIC "0" +// Retrieval info: PRIVATE: CLRwraddress NUMERIC "0" +// Retrieval info: PRIVATE: CLRwren NUMERIC "0" +// Retrieval info: PRIVATE: Clock NUMERIC "0" +// Retrieval info: PRIVATE: Clock_A NUMERIC "0" +// Retrieval info: PRIVATE: Clock_B NUMERIC "0" +// Retrieval info: PRIVATE: IMPLEMENT_IN_LES NUMERIC "0" +// Retrieval info: PRIVATE: INDATA_ACLR_B NUMERIC "0" +// Retrieval info: PRIVATE: INDATA_REG_B NUMERIC "1" +// Retrieval info: PRIVATE: INIT_FILE_LAYOUT STRING "PORT_A" +// Retrieval info: PRIVATE: INIT_TO_SIM_X NUMERIC "0" +// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone V" +// Retrieval info: PRIVATE: JTAG_ENABLED NUMERIC "0" +// Retrieval info: PRIVATE: JTAG_ID STRING "NONE" +// Retrieval info: PRIVATE: MAXIMUM_DEPTH NUMERIC "0" +// Retrieval info: PRIVATE: MEMSIZE NUMERIC "1024" +// Retrieval info: PRIVATE: MEM_IN_BITS NUMERIC "0" +// Retrieval info: PRIVATE: MIFfilename STRING "" +// Retrieval info: PRIVATE: OPERATION_MODE NUMERIC "3" +// Retrieval info: PRIVATE: OUTDATA_ACLR_B NUMERIC "0" +// Retrieval info: PRIVATE: OUTDATA_REG_B NUMERIC "1" +// Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0" +// Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_MIXED_PORTS NUMERIC "2" +// Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_PORT_A NUMERIC "3" +// Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_PORT_B NUMERIC "3" +// Retrieval info: PRIVATE: REGdata NUMERIC "1" +// Retrieval info: PRIVATE: REGq NUMERIC "1" +// Retrieval info: PRIVATE: REGrdaddress NUMERIC "0" +// Retrieval info: PRIVATE: REGrren NUMERIC "1" +// Retrieval info: PRIVATE: REGwraddress NUMERIC "1" +// Retrieval info: PRIVATE: REGwren NUMERIC "1" +// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" +// Retrieval info: PRIVATE: USE_DIFF_CLKEN NUMERIC "0" +// Retrieval info: PRIVATE: UseDPRAM NUMERIC "1" +// Retrieval info: PRIVATE: VarWidth NUMERIC "1" +// Retrieval info: PRIVATE: WIDTH_READ_A NUMERIC "8" +// Retrieval info: PRIVATE: WIDTH_READ_B NUMERIC "32" +// Retrieval info: PRIVATE: WIDTH_WRITE_A NUMERIC "8" +// Retrieval info: PRIVATE: WIDTH_WRITE_B NUMERIC "32" +// Retrieval info: PRIVATE: WRADDR_ACLR_B NUMERIC "0" +// Retrieval info: PRIVATE: WRADDR_REG_B NUMERIC "1" +// Retrieval info: PRIVATE: WRCTRL_ACLR_B NUMERIC "0" +// Retrieval info: PRIVATE: enable NUMERIC "0" +// Retrieval info: PRIVATE: rden NUMERIC "1" +// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +// Retrieval info: CONSTANT: ADDRESS_REG_B STRING "CLOCK0" +// Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_A STRING "BYPASS" +// Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_B STRING "BYPASS" +// Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_A STRING "BYPASS" +// Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_B STRING "BYPASS" +// Retrieval info: CONSTANT: INDATA_REG_B STRING "CLOCK0" +// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone V" +// Retrieval info: CONSTANT: LPM_TYPE STRING "altsyncram" +// Retrieval info: CONSTANT: NUMWORDS_A NUMERIC "256" +// Retrieval info: CONSTANT: NUMWORDS_B NUMERIC "64" +// Retrieval info: CONSTANT: OPERATION_MODE STRING "BIDIR_DUAL_PORT" +// Retrieval info: CONSTANT: OUTDATA_ACLR_A STRING "NONE" +// Retrieval info: CONSTANT: OUTDATA_ACLR_B STRING "NONE" +// Retrieval info: CONSTANT: OUTDATA_REG_A STRING "CLOCK0" +// Retrieval info: CONSTANT: OUTDATA_REG_B STRING "CLOCK0" +// Retrieval info: CONSTANT: POWER_UP_UNINITIALIZED STRING "FALSE" +// Retrieval info: CONSTANT: READ_DURING_WRITE_MODE_MIXED_PORTS STRING "DONT_CARE" +// Retrieval info: CONSTANT: READ_DURING_WRITE_MODE_PORT_A STRING "NEW_DATA_NO_NBE_READ" +// Retrieval info: CONSTANT: READ_DURING_WRITE_MODE_PORT_B STRING "NEW_DATA_NO_NBE_READ" +// Retrieval info: CONSTANT: WIDTHAD_A NUMERIC "8" +// Retrieval info: CONSTANT: WIDTHAD_B NUMERIC "6" +// Retrieval info: CONSTANT: WIDTH_A NUMERIC "8" +// Retrieval info: CONSTANT: WIDTH_B NUMERIC "32" +// Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1" +// Retrieval info: CONSTANT: WIDTH_BYTEENA_B NUMERIC "1" +// Retrieval info: CONSTANT: WRCONTROL_WRADDRESS_REG_B STRING "CLOCK0" +// Retrieval info: USED_PORT: address_a 0 0 8 0 INPUT NODEFVAL "address_a[7..0]" +// Retrieval info: USED_PORT: address_b 0 0 6 0 INPUT NODEFVAL "address_b[5..0]" +// Retrieval info: USED_PORT: clock 0 0 0 0 INPUT VCC "clock" +// Retrieval info: USED_PORT: data_a 0 0 8 0 INPUT NODEFVAL "data_a[7..0]" +// Retrieval info: USED_PORT: data_b 0 0 32 0 INPUT NODEFVAL "data_b[31..0]" +// Retrieval info: USED_PORT: q_a 0 0 8 0 OUTPUT NODEFVAL "q_a[7..0]" +// Retrieval info: USED_PORT: q_b 0 0 32 0 OUTPUT NODEFVAL "q_b[31..0]" +// Retrieval info: USED_PORT: rden_a 0 0 0 0 INPUT VCC "rden_a" +// Retrieval info: USED_PORT: rden_b 0 0 0 0 INPUT VCC "rden_b" +// Retrieval info: USED_PORT: wren_a 0 0 0 0 INPUT GND "wren_a" +// Retrieval info: USED_PORT: wren_b 0 0 0 0 INPUT GND "wren_b" +// Retrieval info: CONNECT: @address_a 0 0 8 0 address_a 0 0 8 0 +// Retrieval info: CONNECT: @address_b 0 0 6 0 address_b 0 0 6 0 +// Retrieval info: CONNECT: @clock0 0 0 0 0 clock 0 0 0 0 +// Retrieval info: CONNECT: @data_a 0 0 8 0 data_a 0 0 8 0 +// Retrieval info: CONNECT: @data_b 0 0 32 0 data_b 0 0 32 0 +// Retrieval info: CONNECT: @rden_a 0 0 0 0 rden_a 0 0 0 0 +// Retrieval info: CONNECT: @rden_b 0 0 0 0 rden_b 0 0 0 0 +// Retrieval info: CONNECT: @wren_a 0 0 0 0 wren_a 0 0 0 0 +// Retrieval info: CONNECT: @wren_b 0 0 0 0 wren_b 0 0 0 0 +// Retrieval info: CONNECT: q_a 0 0 8 0 @q_a 0 0 8 0 +// Retrieval info: CONNECT: q_b 0 0 32 0 @q_b 0 0 32 0 +// Retrieval info: GEN_FILE: TYPE_NORMAL spram.v TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL spram.inc FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL spram.cmp FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL spram.bsf FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL spram_inst.v FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL spram_bb.v FALSE +// Retrieval info: LIB_FILE: altera_mf diff --git a/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/video.v b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/video.v new file mode 100644 index 00000000..c84ed36f --- /dev/null +++ b/Arcade_MiST/Nichibutsu Galivan Hardware/rtl/video.v @@ -0,0 +1,45 @@ + +module video( + input clk, + input ce_pix, + output reg hs, + output reg vs, + output reg hb, + output reg vb, + output reg [8:0] hcount, + output reg [8:0] vcount, + output reg frame, + input [3:0] hoffs, + input [3:0] voffs +); + +initial begin + hs <= 1'b1; + vs <= 1'b1; +end + +always @(posedge clk) begin + frame <= 1'b0; + if (ce_pix) begin + hcount <= hcount + 9'd1; + case (hcount) + 16: hb <= 1'b0; + 271: hb <= 1'b1; + (308 - $signed(hoffs)): hs <= 1'b0; + (340 - $signed(hoffs)): hs <= 1'b1; + 383: begin + vcount <= vcount + 9'd1; + hcount <= 9'b0; + case (vcount) + 15: vb <= 1'b0; + 239: vb <= 1'b1; + (249 - $signed(voffs)) : vs <= 1'b0; + (252 - $signed(voffs)) : vs <= 1'b1; + 262: vcount <= 9'd0; + endcase + end + endcase + end +end + +endmodule