mirror of
https://github.com/MiSTer-devel/CDi_MiSTer.git
synced 2026-06-14 03:04:32 +00:00
- Remount is allowed without reset, when the CD wasn't read yet during power cycle - Allows changing a disc with multi disc titles after application induced eject - Added debug option to allow replacing the image during operation - Also fixed tray close on image mount
1090 lines
36 KiB
Systemverilog
1090 lines
36 KiB
Systemverilog
`timescale 1 ns / 1 ns
|
|
|
|
//============================================================================
|
|
//
|
|
// This program is free software; you can redistribute it and/or modify it
|
|
// under the terms of the GNU General Public License as published by the Free
|
|
// Software Foundation; either version 2 of the License, or (at your option)
|
|
// any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
// more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License along
|
|
// with this program; if not, write to the Free Software Foundation, Inc.,
|
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
//
|
|
//============================================================================
|
|
|
|
module emu (
|
|
//Master input clock
|
|
input CLK_50M,
|
|
|
|
//Async reset from top-level module.
|
|
//Can be used as initial reset.
|
|
input RESET,
|
|
|
|
//Must be passed to hps_io module
|
|
inout [48:0] HPS_BUS,
|
|
|
|
//Base video clock. Usually equals to CLK_SYS.
|
|
output CLK_VIDEO,
|
|
|
|
//Multiple resolutions are supported using different CE_PIXEL rates.
|
|
//Must be based on CLK_VIDEO
|
|
output CE_PIXEL,
|
|
|
|
//Video aspect ratio for HDMI. Most retro systems have ratio 4:3.
|
|
//if VIDEO_ARX[12] or VIDEO_ARY[12] is set then [11:0] contains scaled size instead of aspect ratio.
|
|
output [12:0] VIDEO_ARX,
|
|
output [12:0] VIDEO_ARY,
|
|
|
|
output [7:0] VGA_R,
|
|
output [7:0] VGA_G,
|
|
output [7:0] VGA_B,
|
|
output VGA_HS,
|
|
output VGA_VS,
|
|
output VGA_DE, // = ~(VBlank | HBlank)
|
|
output VGA_F1,
|
|
output [1:0] VGA_SL,
|
|
output VGA_SCALER, // Force VGA scaler
|
|
output VGA_DISABLE, // analog out is off
|
|
|
|
input [11:0] HDMI_WIDTH,
|
|
input [11:0] HDMI_HEIGHT,
|
|
output HDMI_FREEZE,
|
|
output HDMI_BLACKOUT,
|
|
output HDMI_BOB_DEINT,
|
|
|
|
`ifdef MISTER_FB
|
|
// Use framebuffer in DDRAM
|
|
// FB_FORMAT:
|
|
// [2:0] : 011=8bpp(palette) 100=16bpp 101=24bpp 110=32bpp
|
|
// [3] : 0=16bits 565 1=16bits 1555
|
|
// [4] : 0=RGB 1=BGR (for 16/24/32 modes)
|
|
//
|
|
// FB_STRIDE either 0 (rounded to 256 bytes) or multiple of pixel size (in bytes)
|
|
output FB_EN,
|
|
output [ 4:0] FB_FORMAT,
|
|
output [11:0] FB_WIDTH,
|
|
output [11:0] FB_HEIGHT,
|
|
output [31:0] FB_BASE,
|
|
output [13:0] FB_STRIDE,
|
|
input FB_VBL,
|
|
input FB_LL,
|
|
output FB_FORCE_BLANK,
|
|
|
|
`ifdef MISTER_FB_PALETTE
|
|
// Palette control for 8bit modes.
|
|
// Ignored for other video modes.
|
|
output FB_PAL_CLK,
|
|
output [ 7:0] FB_PAL_ADDR,
|
|
output [23:0] FB_PAL_DOUT,
|
|
input [23:0] FB_PAL_DIN,
|
|
output FB_PAL_WR,
|
|
`endif
|
|
`endif
|
|
|
|
output LED_USER, // 1 - ON, 0 - OFF.
|
|
|
|
// b[1]: 0 - LED status is system status OR'd with b[0]
|
|
// 1 - LED status is controled solely by b[0]
|
|
// hint: supply 2'b00 to let the system control the LED.
|
|
output [1:0] LED_POWER,
|
|
output [1:0] LED_DISK,
|
|
|
|
// I/O board button press simulation (active high)
|
|
// b[1]: user button
|
|
// b[0]: osd button
|
|
output [1:0] BUTTONS,
|
|
|
|
input CLK_AUDIO, // 24.576 MHz
|
|
output [15:0] AUDIO_L,
|
|
output [15:0] AUDIO_R,
|
|
output AUDIO_S, // 1 - signed audio samples, 0 - unsigned
|
|
output [ 1:0] AUDIO_MIX, // 0 - no mix, 1 - 25%, 2 - 50%, 3 - 100% (mono)
|
|
|
|
//ADC
|
|
inout [3:0] ADC_BUS,
|
|
|
|
//SD-SPI
|
|
output SD_SCK,
|
|
output SD_MOSI,
|
|
input SD_MISO,
|
|
output SD_CS,
|
|
input SD_CD,
|
|
|
|
//High latency DDR3 RAM interface
|
|
//Use for non-critical time purposes
|
|
output DDRAM_CLK, // any clock, no restrictions. Typically main core clock
|
|
`ifndef VERILATOR
|
|
input DDRAM_BUSY, // every read and write request is only accepted in a cycle where busy is low
|
|
output [7:0] DDRAM_BURSTCNT, // amount of words to be written/read. Maximum is 128
|
|
output [28:0] DDRAM_ADDR, // starting address for read/write. In case of burst, the addresses will internally count up
|
|
input [63:0] DDRAM_DOUT, // data coming from (burst) read
|
|
input DDRAM_DOUT_READY, // high for 1 clock cycle for every 64 bit dataword requested via (burst) read request
|
|
output DDRAM_RD, // request read at DDRAM_ADDR and DDRAM_BURSTCNT length
|
|
output [63:0] DDRAM_DIN, // data word to be written
|
|
output [7:0] DDRAM_BE, // byte enable for each of the 8 bytes in DDRAM_DIN, only used for writing. (1=write, 0=ignore)
|
|
output DDRAM_WE, // request write at DDRAM_ADDR with DDRAM_DIN data and DDRAM_BE mask
|
|
`endif
|
|
|
|
//SDRAM interface with lower latency
|
|
output SDRAM_CLK,
|
|
output SDRAM_CKE,
|
|
output [12:0] SDRAM_A,
|
|
output [ 1:0] SDRAM_BA,
|
|
`ifndef VERILATOR
|
|
inout [15:0] SDRAM_DQ,
|
|
`endif
|
|
output SDRAM_DQML,
|
|
output SDRAM_DQMH,
|
|
output SDRAM_nCS,
|
|
output SDRAM_nCAS,
|
|
output SDRAM_nRAS,
|
|
output SDRAM_nWE,
|
|
|
|
`ifdef MISTER_DUAL_SDRAM
|
|
//Secondary SDRAM
|
|
//Set all output SDRAM_* signals to Z ASAP if SDRAM2_EN is 0
|
|
input SDRAM2_EN,
|
|
output SDRAM2_CLK,
|
|
output [12:0] SDRAM2_A,
|
|
output [ 1:0] SDRAM2_BA,
|
|
inout [15:0] SDRAM2_DQ,
|
|
output SDRAM2_nCS,
|
|
output SDRAM2_nCAS,
|
|
output SDRAM2_nRAS,
|
|
output SDRAM2_nWE,
|
|
`endif
|
|
|
|
input UART_CTS,
|
|
output UART_RTS,
|
|
input UART_RXD,
|
|
output UART_TXD,
|
|
output UART_DTR,
|
|
input UART_DSR,
|
|
|
|
// Open-drain User port.
|
|
// 0 - D+/RX
|
|
// 1 - D-/TX
|
|
// 2..6 - USR2..USR6
|
|
// Set USER_OUT to 1 to read from USER_IN.
|
|
input [6:0] USER_IN,
|
|
output [6:0] USER_OUT,
|
|
|
|
input OSD_STATUS
|
|
);
|
|
|
|
///////// Default values for ports not used in this core /////////
|
|
|
|
`ifdef VERILATOR
|
|
bit [15:0] SDRAM_DQ_in;
|
|
bit [15:0] SDRAM_DQ_out;
|
|
`endif
|
|
|
|
assign ADC_BUS = 'Z;
|
|
assign USER_OUT = '1;
|
|
assign {UART_RTS, UART_DTR} = 0;
|
|
assign {SD_SCK, SD_MOSI, SD_CS} = 'Z;
|
|
`ifdef VERILATOR
|
|
assign {SDRAM_A, SDRAM_BA, SDRAM_CLK, SDRAM_CKE, SDRAM_DQML, SDRAM_DQMH, SDRAM_nWE, SDRAM_nCAS, SDRAM_nRAS, SDRAM_nCS} = 'Z;
|
|
`else
|
|
assign {SDRAM_DQ, SDRAM_A, SDRAM_BA, SDRAM_CLK, SDRAM_CKE, SDRAM_DQML, SDRAM_DQMH, SDRAM_nWE, SDRAM_nCAS, SDRAM_nRAS, SDRAM_nCS} = 'Z;
|
|
`endif
|
|
|
|
assign VGA_SL = 0;
|
|
assign VGA_SCALER = 0;
|
|
assign VGA_DISABLE = 0;
|
|
assign HDMI_FREEZE = 0;
|
|
assign HDMI_BLACKOUT = 0;
|
|
assign HDMI_BOB_DEINT = 0;
|
|
|
|
assign AUDIO_S = 1;
|
|
assign AUDIO_MIX = 0;
|
|
|
|
assign LED_DISK = 0;
|
|
assign LED_POWER = 0;
|
|
assign BUTTONS = 0;
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
`include "build_id.v"
|
|
localparam CONF_STR = {
|
|
"CD-i;UART115200;",
|
|
"-;",
|
|
"S0,CUECHD,Load CD;",
|
|
"-;",
|
|
|
|
"P1,Audio & Video;",
|
|
"P1O[4],Video Region,PAL,NTSC;",
|
|
"P1O[33:32],Aspect ratio,Original,Full Screen,[ARC1],[ARC2];",
|
|
"P1O[35:34],Scale,Normal,V-Integer,Narrower HV-Integer,Wider HV-Integer;",
|
|
"P1O[39],Vertical Crop,Off,On(270);",
|
|
"P1O[10:9],RGB Scale,0-255,16-235,16-255;",
|
|
|
|
"P2,Debug Options;",
|
|
"P2-;",
|
|
"P2F1,ROM,Replace Boot ROM;",
|
|
"P2O[2],Disable Audio Att.,No,Yes;",
|
|
"P2O[3],UART Fake Space,No,Yes;",
|
|
"P2O[7:6],Force Video Plane,Original,A,B,DVC;",
|
|
"P2O[12],SERVO Audio CD,No,Yes;",
|
|
"P2O[17],Disable VCD pixel clock,No,Yes;",
|
|
"P2O[18],Activate VCD filter,Yes,No;",
|
|
"P2O[19],CD image live update,No,Yes;",
|
|
|
|
"P3,Hardware Config;",
|
|
"P3-;",
|
|
"P3O[15],Ports, P1 Front + UART Back, P1 Back + P2 Front;",
|
|
"P3O[5],Overclock input device,No,Yes;",
|
|
"P3O[13],Disable VMPEG DVC,No,Yes;",
|
|
"P3-;",
|
|
"P3-,(U) = unsafe, experimental;",
|
|
"P3O[16],Fast CD Seek,No,Yes(U);",
|
|
"P3O[11],CPU Turbo,No,Yes(U);",
|
|
"P3O[8],NvRAM live update,No,Yes(U);",
|
|
|
|
"-;",
|
|
"O[21:19],Pointer Speed,22ER9021 N,22ER9021 II,RV 8701,22ER9021 I;",
|
|
"O[14],Autoplay,Yes,No;",
|
|
"-;",
|
|
"T[0],Reset;",
|
|
"R[0],Reset and close OSD;",
|
|
"v,0;", // [optional] config version 0-99.
|
|
// If CONF_STR options are changed in incompatible way, then change version number too,
|
|
"J1,B1,B2,B1+B2;",
|
|
"jn,B,A,Y;",
|
|
// so all options will get default values on first start.
|
|
"I,",
|
|
"NvRAM saved;",
|
|
"V,v",
|
|
`BUILD_DATE
|
|
};
|
|
|
|
wire forced_scandoubler;
|
|
wire [ 1:0] buttons;
|
|
wire [127:0] status;
|
|
|
|
wire [ 10:0] ps2_key;
|
|
|
|
wire [ 15:0] JOY0 /*verilator public_flat_rw*/;
|
|
wire [ 15:0] JOY1 /*verilator public_flat_rw*/;
|
|
wire [ 15:0] JOY0_ANALOG /*verilator public_flat_rw*/;
|
|
wire [ 15:0] JOY1_ANALOG /*verilator public_flat_rw*/;
|
|
|
|
wire [ 24:0] MOUSE /*verilator public_flat_rw*/;
|
|
|
|
wire ioctl_download /*verilator public_flat_rw*/;
|
|
wire ioctl_wr /*verilator public_flat_rw*/;
|
|
wire [ 24:0] ioctl_addr /*verilator public_flat_rw*/;
|
|
wire [ 15:0] ioctl_dout /*verilator public_flat_rw*/;
|
|
wire [ 15:0] ioctl_index /*verilator public_flat_rw*/;
|
|
wire ioctl_wait /*verilator public_flat_rw*/ = 0;
|
|
|
|
wire clk_sys /*verilator public_flat_rw*/;
|
|
wire clk_audio /*verilator public_flat_rw*/;
|
|
wire clk_mpeg /*verilator public_flat_rw*/;
|
|
|
|
wire [ 31:0] cd_hps_lba;
|
|
wire cd_hps_req /*verilator public_flat_rd*/;
|
|
wire cd_hps_ack /*verilator public_flat_rw*/;
|
|
wire cd_media_change /*verilator public_flat_rw*/;
|
|
|
|
wire nvram_hps_ack /*verilator public_flat_rw*/;
|
|
bit nvram_hps_wr;
|
|
bit nvram_hps_rd /*verilator public_flat_rd*/;
|
|
bit [ 15:0] nvram_hps_din /*verilator public_flat_rd*/;
|
|
wire nvram_media_change /*verilator public_flat_rw*/;
|
|
|
|
wire [ 7:0] sd_buff_addr /*verilator public_flat_rw*/;
|
|
wire sd_buff_wr /*verilator public_flat_rw*/;
|
|
wire [ 15:0] sd_buff_dout /*verilator public_flat_rw*/;
|
|
|
|
wire img_readonly;
|
|
wire [ 63:0] img_size /*verilator public_flat_rw*/;
|
|
|
|
wire [ 15:0] status_menumask = 0;
|
|
|
|
bit info_req;
|
|
bit [ 7:0] info;
|
|
|
|
wire [ 64:0] hps_rtc;
|
|
|
|
// To reduce to a single clock cycle
|
|
bit cd_media_change_q;
|
|
bit nvram_media_change_q;
|
|
|
|
// Flag which becomes active for some time when an NvRAM image is mounted
|
|
wire nvram_img_mount = nvram_media_change && !nvram_media_change_q && img_size != 0;
|
|
// Flag which becomes active for some time when an NvRAM image is mounted
|
|
wire cd_img_mount = cd_media_change && !cd_media_change_q && img_size != 0;
|
|
|
|
always_ff @(posedge clk_sys) begin
|
|
cd_media_change_q <= cd_media_change;
|
|
nvram_media_change_q <= nvram_media_change;
|
|
end
|
|
|
|
`ifndef VERILATOR
|
|
hps_io #(
|
|
.CONF_STR(CONF_STR),
|
|
.WIDE(1),
|
|
.BLKSZ(6), // NvRAM of 8kB size as block size
|
|
.VDNUM(2)
|
|
) hps_io (
|
|
.clk_sys (clk_sys),
|
|
.HPS_BUS (HPS_BUS),
|
|
.EXT_BUS (),
|
|
.gamma_bus(),
|
|
|
|
.forced_scandoubler(forced_scandoubler),
|
|
|
|
.buttons(buttons),
|
|
.status(status),
|
|
.status_menumask(status_menumask),
|
|
|
|
.info_req(info_req),
|
|
.info(info),
|
|
|
|
.ioctl_download(ioctl_download),
|
|
.ioctl_index(ioctl_index),
|
|
.ioctl_wr(ioctl_wr),
|
|
.ioctl_addr(ioctl_addr),
|
|
.ioctl_dout(ioctl_dout),
|
|
.ioctl_wait(ioctl_wait),
|
|
|
|
.sd_lba('{cd_hps_lba, 0}),
|
|
.sd_blk_cnt('{0, 0}),
|
|
.sd_rd({nvram_hps_rd, cd_hps_req && cd_img_mounted}),
|
|
.sd_wr({nvram_hps_wr, 1'b0}),
|
|
.sd_ack({nvram_hps_ack, cd_hps_ack}),
|
|
.sd_buff_addr(sd_buff_addr),
|
|
.sd_buff_dout(sd_buff_dout),
|
|
.sd_buff_din('{0, nvram_hps_din}),
|
|
.sd_buff_wr(sd_buff_wr),
|
|
|
|
.img_mounted({nvram_media_change, cd_media_change}),
|
|
.img_readonly(img_readonly),
|
|
.img_size(img_size),
|
|
|
|
.ps2_key(ps2_key),
|
|
|
|
.ps2_mouse(MOUSE),
|
|
|
|
.joystick_l_analog_0(JOY0_ANALOG),
|
|
.joystick_l_analog_1(JOY1_ANALOG),
|
|
.joystick_0(JOY0),
|
|
.joystick_1(JOY1),
|
|
.RTC(hps_rtc)
|
|
);
|
|
|
|
wire [1:0] ar = status[33:32];
|
|
wire vcrop_en = status[39];
|
|
|
|
video_freak video_freak (
|
|
.*,
|
|
.VGA_DE_IN(~(HBlank | VBlank)),
|
|
.ARX((!ar) ? 13'd4 : (13'(ar) - 13'd1)),
|
|
.ARY((!ar) ? 13'd3 : 13'd0),
|
|
.CROP_SIZE(vcrop_en ? 10'd270 : 10'd0),
|
|
.CROP_OFF(0),
|
|
.SCALE(status[35:34])
|
|
);
|
|
|
|
`endif
|
|
|
|
/////////////////////// CLOCKS ///////////////////////////////
|
|
|
|
`ifndef VERILATOR
|
|
pll pll (
|
|
.refclk(CLK_50M),
|
|
.rst(0),
|
|
.outclk_0(clk_sys), // 30 MHz
|
|
.outclk_1(clk_audio), // 22.2264 MHz
|
|
.outclk_2(clk_mpeg) // 90 MHz
|
|
);
|
|
`endif
|
|
|
|
wire [24:0] sdram_addr;
|
|
wire sdram_rd;
|
|
wire sdram_wr;
|
|
wire sdram_word;
|
|
wire [15:0] sdram_din;
|
|
wire [15:0] sdram_dout;
|
|
wire sdram_busy;
|
|
wire sdram_burst;
|
|
wire sdram_refresh;
|
|
wire sdram_burstdata_valid;
|
|
wire sdram_init_done;
|
|
|
|
bit prepare_sdram;
|
|
bit [24:0] prepare_sdram_addr;
|
|
bit [15:0] prepare_sdram_din;
|
|
bit prepare_sdram_wr;
|
|
bit prepare_sdram_refresh;
|
|
bit prepare_sdram_rd;
|
|
|
|
bit cditop_reset = 1;
|
|
|
|
// 1MB of RAM to zero, 512k 16 bit words
|
|
// The highest bit 20 is only used for detection that the process was finished
|
|
bit [20:1] ram_zero_adr = 0;
|
|
|
|
// Zeroing of RAM currently disabled. Seems to be not required.
|
|
wire ram_zero_done = 1;
|
|
//wire ram_zero_done = ram_zero_adr[20];
|
|
|
|
`ifdef VERILATOR
|
|
bit ram_zero_done_q = 0;
|
|
always_ff @(posedge clk_sys) begin
|
|
ram_zero_done_q <= ram_zero_done;
|
|
|
|
if (ram_zero_done && !ram_zero_done_q) $display("RAM Zeroed");
|
|
end
|
|
`endif
|
|
|
|
typedef enum bit [3:0] {
|
|
ROM_DOWNLOAD, // most important
|
|
RAM_ZERO, // bulk afterwards
|
|
REFRESH,
|
|
IDLE
|
|
} e_arbit_target;
|
|
|
|
e_arbit_target sdram_owner;
|
|
e_arbit_target sdram_owner_q;
|
|
e_arbit_target sdram_owner_next;
|
|
|
|
bit ioctl_sdram_wr_latch /*verilator public_flat_rw*/ = 0;
|
|
|
|
// boot0.rom represented as ioctl_index==16h'0000
|
|
// boot1.rom represented as ioctl_index==16h'0040
|
|
// boot2.rom represented as ioctl_index==16h'0080
|
|
wire ioctl_maincpu_rom_wr = ioctl_wr && ioctl_index[7:6] == 2'b00;
|
|
wire ioctl_slave_worm_wr = ioctl_wr && ioctl_index[7:6] == 2'b01;
|
|
wire ioctl_vmpega_worm_wr = ioctl_wr && ioctl_index[7:6] == 2'b10;
|
|
|
|
bit ioctl_slave_worm_wr_q = 0;
|
|
|
|
// We get 16 bit data from Main. The second 8 bit is stored here while writing the first
|
|
bit [ 7:0] slave_worm_second_data = 0;
|
|
|
|
// Signals to write the "Write once read many" memory of the slave
|
|
bit [12:0] slave_worm_adr = 0;
|
|
bit [ 7:0] slave_worm_data = 0;
|
|
bit slave_worm_wr;
|
|
|
|
// Signals to manipulate the NvRAM from the Linux side
|
|
bit [12:0] nvram_backup_restore_adr;
|
|
bit [15:0] nvram_restore_data_temp;
|
|
wire [ 7:0] nvram_restore_data;
|
|
wire [ 7:0] nvram_backup_data;
|
|
bit nvram_restore_write;
|
|
wire nvram_cpu_changed;
|
|
bit nvram_allow_cpu_access;
|
|
|
|
assign nvram_restore_data = nvram_backup_restore_adr[0] ? nvram_restore_data_temp[15:8] : nvram_restore_data_temp[7:0];
|
|
|
|
always_ff @(posedge clk_sys) begin
|
|
ioctl_slave_worm_wr_q <= ioctl_slave_worm_wr;
|
|
slave_worm_wr <= ioctl_slave_worm_wr_q || ioctl_slave_worm_wr;
|
|
|
|
if (ioctl_slave_worm_wr) begin
|
|
// Lower byte first
|
|
slave_worm_adr <= ioctl_addr[12:0];
|
|
slave_worm_data <= ioctl_dout[7:0];
|
|
slave_worm_second_data <= ioctl_dout[15:8];
|
|
end else begin
|
|
// Afterwards the upper byte
|
|
slave_worm_data <= slave_worm_second_data;
|
|
slave_worm_adr[0] <= 1;
|
|
end
|
|
end
|
|
|
|
|
|
always_comb begin
|
|
sdram_owner_next = IDLE;
|
|
|
|
if (prepare_sdram) begin
|
|
sdram_owner_next = REFRESH;
|
|
|
|
if (!ram_zero_done) sdram_owner_next = RAM_ZERO;
|
|
if (ioctl_sdram_wr_latch) sdram_owner_next = ROM_DOWNLOAD;
|
|
end
|
|
|
|
if (sdram_busy) sdram_owner = sdram_owner_q;
|
|
else sdram_owner = sdram_owner_next;
|
|
end
|
|
|
|
bit sdram_busy_q = 0;
|
|
|
|
always_comb begin
|
|
prepare_sdram_din = 0;
|
|
prepare_sdram_wr = 0;
|
|
prepare_sdram_addr = {4'b0000, ram_zero_adr, 1'b0};
|
|
prepare_sdram_rd = 0;
|
|
prepare_sdram_refresh = 0;
|
|
|
|
case (sdram_owner)
|
|
ROM_DOWNLOAD: begin
|
|
prepare_sdram_din = {ioctl_dout[7:0], ioctl_dout[15:8]};
|
|
prepare_sdram_addr = {5'b00100, ioctl_index[7], ioctl_addr[18:1], 1'b0};
|
|
prepare_sdram_wr = 1;
|
|
end
|
|
RAM_ZERO: begin
|
|
if (!sdram_busy_q) prepare_sdram_wr = 1;
|
|
end
|
|
REFRESH: begin
|
|
prepare_sdram_rd = 1;
|
|
prepare_sdram_refresh = 1;
|
|
end
|
|
default: begin
|
|
end
|
|
endcase
|
|
|
|
if (sdram_busy) begin
|
|
prepare_sdram_rd = 0;
|
|
prepare_sdram_wr = 0;
|
|
end
|
|
end
|
|
|
|
bit ioctl_download_q = 0;
|
|
bit ioctl_wr_overflow = 0;
|
|
|
|
always_ff @(posedge clk_sys) begin
|
|
if (ioctl_sdram_wr_latch && ioctl_wr) ioctl_wr_overflow <= 1;
|
|
|
|
if (ioctl_maincpu_rom_wr || ioctl_vmpega_worm_wr) begin
|
|
ioctl_sdram_wr_latch <= 1;
|
|
end
|
|
|
|
ioctl_download_q <= ioctl_download;
|
|
sdram_busy_q <= sdram_busy;
|
|
|
|
if (!ioctl_download_q && ioctl_download) begin
|
|
// Use positive edge of ioctl_download as reset
|
|
sdram_owner_q <= RAM_ZERO;
|
|
ram_zero_adr <= 0;
|
|
end else begin
|
|
sdram_owner_q <= sdram_owner;
|
|
|
|
if (sdram_owner_q == RAM_ZERO && sdram_busy_q && !sdram_busy)
|
|
ram_zero_adr <= ram_zero_adr + 1;
|
|
|
|
if (sdram_owner == ROM_DOWNLOAD && sdram_busy_q && !sdram_busy)
|
|
ioctl_sdram_wr_latch <= 0;
|
|
end
|
|
end
|
|
|
|
// Latch which is set, when CD reading was performed at least once
|
|
// If set, we must perform a reset when changing the disc
|
|
// If not set, we can change the image even with a closed tray while keeping the machine running
|
|
bit cd_hps_req_during_power_cycle;
|
|
|
|
assign prepare_sdram = cditop_reset;
|
|
always_ff @(posedge clk_sys) begin
|
|
cditop_reset <= RESET || status[0] || buttons[1] || ioctl_download || !ram_zero_done ||
|
|
(nvram_img_mount && enable_reset_on_nvram_img_mount) ||
|
|
(cd_img_mount && cd_hps_req_during_power_cycle && tray_is_closed && enable_reset_on_cd_img_mount);
|
|
|
|
if (cditop_reset) cd_hps_req_during_power_cycle <= 0;
|
|
else if (cd_hps_req) cd_hps_req_during_power_cycle <= 1;
|
|
end
|
|
|
|
sdram sdram (
|
|
.*,
|
|
.init(0), //~clock_locked),
|
|
.clk(clk_sys),
|
|
|
|
.addr(prepare_sdram ? prepare_sdram_addr : sdram_addr),
|
|
.din(prepare_sdram ? prepare_sdram_din : sdram_din),
|
|
.dout(sdram_dout),
|
|
.rd(prepare_sdram ? prepare_sdram_rd : sdram_rd),
|
|
.wr(prepare_sdram ? prepare_sdram_wr : sdram_wr),
|
|
.word(prepare_sdram ? 1'b1 : sdram_word),
|
|
.busy(sdram_busy),
|
|
.refresh(prepare_sdram ? prepare_sdram_refresh : sdram_refresh),
|
|
.burst(prepare_sdram ? 1'b0 : sdram_burst),
|
|
.burstdata_valid(sdram_burstdata_valid)
|
|
);
|
|
|
|
`ifdef VERILATOR
|
|
// DDR3 simulation
|
|
bit [63:0] ddram[16777216/8] /*verilator public_flat_rd*/;
|
|
|
|
int ddr_latencycnt;
|
|
bit [7:0] ddr_words_to_prove;
|
|
bit [28:0] ddr_addr;
|
|
|
|
bit DDRAM_BUSY; // every read and write request is only accepted in a cycle where busy is low
|
|
wire [7:0] DDRAM_BURSTCNT; // amount of words to be written/read. Maximum is 128
|
|
wire [28:0] DDRAM_ADDR; // starting address for read/write. In case of burst; the addresses will internally count up
|
|
bit [63:0] DDRAM_DOUT; // data coming from (burst) read
|
|
bit DDRAM_DOUT_READY; // high for 1 clock cycle for every 64 bit dataword requested via (burst) read request
|
|
wire DDRAM_RD; // request read at DDRAM_ADDR and DDRAM_BURSTCNT length
|
|
wire [63:0] DDRAM_DIN; // data word to be written
|
|
wire [7:0] DDRAM_BE; // byte enable for each of the 8 bytes in DDRAM_DIN; only used for writing. (1=write; 0=ignore)
|
|
wire DDRAM_WE; // request write at DDRAM_ADDR with DDRAM_DIN data and DDRAM_BE mask
|
|
|
|
always_ff @(posedge DDRAM_CLK) begin
|
|
DDRAM_DOUT_READY <= 0;
|
|
|
|
if (DDRAM_WE && !DDRAM_BUSY) begin
|
|
assert (DDRAM_ADDR[21] == 0);
|
|
ddram[DDRAM_ADDR[20:0]] <= DDRAM_DIN;
|
|
//$display("Write at %x %x",DDRAM_ADDR, DDRAM_DIN);
|
|
end
|
|
|
|
if (DDRAM_RD && !DDRAM_BUSY) begin
|
|
ddr_latencycnt <= 13;
|
|
ddr_words_to_prove <= DDRAM_BURSTCNT;
|
|
ddr_addr <= DDRAM_ADDR;
|
|
DDRAM_BUSY <= 1;
|
|
end
|
|
|
|
if (DDRAM_BUSY) begin
|
|
if (ddr_latencycnt > 0) ddr_latencycnt <= ddr_latencycnt - 1;
|
|
else begin
|
|
DDRAM_DOUT <= ddram[ddr_addr[20:0]];
|
|
ddr_addr <= ddr_addr + 1;
|
|
DDRAM_DOUT_READY <= 1;
|
|
ddr_words_to_prove <= ddr_words_to_prove - 1;
|
|
if (ddr_words_to_prove == 1) DDRAM_BUSY <= 0;
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
// SDRAM simulation
|
|
|
|
bit [15:0] rom[262144] /*verilator public_flat_rw*/;
|
|
bit [15:0] vmpega_rom[65536] /*verilator public_flat_rw*/;
|
|
bit [15:0] ram[2097152] /*verilator public_flat_rw*/;
|
|
bit [22:0] sdram_real_addr;
|
|
initial begin
|
|
$readmemh("cdi200.mem", rom);
|
|
$readmemh("vmpega.mem", vmpega_rom);
|
|
//$readmemh("ramdump.mem", ram);
|
|
end
|
|
|
|
bit [3:0] burstindex = 0;
|
|
wire [22:0] burstwrap_corrected_address = {
|
|
sdram_real_addr[22:2], sdram_real_addr[1:0] + burstindex[1:0]
|
|
};
|
|
|
|
always_comb begin
|
|
SDRAM_DQ_in = 0;
|
|
|
|
case (sdram_real_addr[21:18])
|
|
4'b1000: SDRAM_DQ_in = rom[burstwrap_corrected_address[17:0]];
|
|
4'b1001: SDRAM_DQ_in = vmpega_rom[burstwrap_corrected_address[15:0]];
|
|
default: SDRAM_DQ_in = ram[burstwrap_corrected_address[20:0]];
|
|
endcase
|
|
end
|
|
|
|
bit SDRAM_nWE_q;
|
|
bit SDRAM_DQMH_q;
|
|
bit SDRAM_DQML_q;
|
|
|
|
always_ff @(posedge clk_sys) begin
|
|
SDRAM_nWE_q <= SDRAM_nWE;
|
|
SDRAM_DQMH_q <= SDRAM_DQMH;
|
|
SDRAM_DQML_q <= SDRAM_DQML;
|
|
|
|
if (!SDRAM_nRAS) sdram_real_addr[21:9] <= SDRAM_A;
|
|
if (!SDRAM_nCAS) sdram_real_addr[8:0] <= SDRAM_A[8:0];
|
|
|
|
if (!SDRAM_nCAS) burstindex <= 0;
|
|
else if (burstindex < 4) burstindex <= burstindex + 1;
|
|
|
|
case (sdram_real_addr[21:18])
|
|
4'b1000: begin
|
|
if (!SDRAM_nWE_q && !SDRAM_DQMH_q)
|
|
rom[burstwrap_corrected_address[17:0]][15:8] <= SDRAM_DQ_out[15:8];
|
|
if (!SDRAM_nWE_q && !SDRAM_DQML_q)
|
|
rom[burstwrap_corrected_address[17:0]][7:0] <= SDRAM_DQ_out[7:0];
|
|
end
|
|
4'b1001: begin
|
|
if (!SDRAM_nWE_q && !SDRAM_DQMH_q)
|
|
vmpega_rom[burstwrap_corrected_address[15:0]][15:8] <= SDRAM_DQ_out[15:8];
|
|
if (!SDRAM_nWE_q && !SDRAM_DQML_q)
|
|
vmpega_rom[burstwrap_corrected_address[15:0]][7:0] <= SDRAM_DQ_out[7:0];
|
|
end
|
|
default: begin
|
|
if (!SDRAM_nWE_q && !SDRAM_DQMH_q)
|
|
ram[burstwrap_corrected_address[20:0]][15:8] <= SDRAM_DQ_out[15:8];
|
|
if (!SDRAM_nWE_q && !SDRAM_DQML_q)
|
|
ram[burstwrap_corrected_address[20:0]][7:0] <= SDRAM_DQ_out[7:0];
|
|
end
|
|
endcase
|
|
end
|
|
`endif
|
|
|
|
`ifdef VERILATOR
|
|
bit debug_uart_fake_space /*verilator public_flat_rw*/;
|
|
bit tvmode_ntsc /*verilator public_flat_rw*/;
|
|
wire overclock_pointing_device = 1;
|
|
wire [1:0] debug_force_video_plane = 0;
|
|
wire enable_reset_on_nvram_img_mount = 0;
|
|
wire enable_reset_on_cd_img_mount = 0;
|
|
wire [1:0] debug_limited_to_full = 0;
|
|
wire audio_cd_in_tray = 0;
|
|
wire config_disable_cpu_starve = 1;
|
|
wire config_auto_play /*verilator public_flat_rw*/ = 1;
|
|
bit config_disable_vmpeg = 0;
|
|
wire config_first_player_back_port = 0;
|
|
wire config_disable_seek_time = 1;
|
|
wire debug_disable_vcd_clock = 0;
|
|
wire debug_activate_vcd_filter = 1;
|
|
wire [2:0] pointing_dev_speed = 0;
|
|
`else
|
|
// Status seems to be all zero after reset
|
|
// Should be considered for defining the default
|
|
wire debug_uart_fake_space = status[3];
|
|
wire tvmode_ntsc = status[4];
|
|
wire overclock_pointing_device = status[5];
|
|
wire [1:0] debug_force_video_plane = status[7:6];
|
|
wire enable_reset_on_nvram_img_mount = !status[8];
|
|
wire enable_reset_on_cd_img_mount = !status[19];
|
|
wire [1:0] debug_limited_to_full = status[10:9];
|
|
wire config_disable_cpu_starve = status[11];
|
|
wire audio_cd_in_tray = status[12];
|
|
bit config_disable_vmpeg = 0;
|
|
wire config_auto_play = !status[14];
|
|
wire config_first_player_back_port = status[15];
|
|
wire config_disable_seek_time = status[16];
|
|
wire debug_disable_vcd_clock = status[17];
|
|
wire debug_activate_vcd_filter = !status[18];
|
|
wire [2:0] pointing_dev_speed = status[21:19];
|
|
|
|
always_ff @(posedge clk_sys) begin
|
|
// only change during resets
|
|
if (cditop_reset) config_disable_vmpeg <= status[13];
|
|
end
|
|
`endif
|
|
|
|
wire HBlank;
|
|
wire HSync;
|
|
wire VBlank;
|
|
wire VSync;
|
|
wire ce_pix;
|
|
wire [7:0] r /*verilator public_flat_rd*/;
|
|
wire [7:0] g /*verilator public_flat_rd*/;
|
|
wire [7:0] b /*verilator public_flat_rd*/;
|
|
|
|
bytestream slave_serial_out ();
|
|
bytestream slave_serial_in ();
|
|
wire slave_rts;
|
|
|
|
bytestream scc68070_bypass_serial_out ();
|
|
bytestream scc68070_bypass_serial_in ();
|
|
wire scc68070_rts;
|
|
|
|
// "INPUT" port at the front of a CDI 210/05
|
|
pointing_device pointing_dev_front (
|
|
.clk(clk_sys),
|
|
.mister_joystick(config_first_player_back_port ? JOY1 : JOY0),
|
|
.mister_joystick_analog(config_first_player_back_port ? JOY1_ANALOG : JOY0_ANALOG),
|
|
.mister_mouse(config_first_player_back_port ? 0 : MOUSE),
|
|
.rts(slave_rts),
|
|
.serial_out(slave_serial_in),
|
|
.overclock(overclock_pointing_device),
|
|
.speed_setting(pointing_dev_speed)
|
|
);
|
|
|
|
// ""INPUT 2" port at the back of a CDI 210/05
|
|
pointing_device pointing_dev_back (
|
|
.clk(clk_sys),
|
|
.mister_joystick(config_first_player_back_port ? JOY0 : JOY1),
|
|
.mister_joystick_analog(config_first_player_back_port ? JOY0_ANALOG : JOY1_ANALOG),
|
|
.mister_mouse(config_first_player_back_port ? MOUSE : 0),
|
|
.rts(config_first_player_back_port ? scc68070_rts : 1'b1),
|
|
.serial_out(scc68070_bypass_serial_in),
|
|
.overclock(overclock_pointing_device),
|
|
.speed_setting(pointing_dev_speed)
|
|
);
|
|
|
|
wire cd_sector_tick;
|
|
wire cd_sector_delivered;
|
|
wire [31:0] cd_seek_lba;
|
|
wire cd_seek_lba_valid;
|
|
wire [15:0] cd_data;
|
|
wire cd_data_valid;
|
|
wire cd_stop_sector_delivery;
|
|
|
|
hps_cd_sector_cache hps_cd_sector_cache (
|
|
.clk(clk_sys),
|
|
.reset(cditop_reset),
|
|
.cd_hps_req(cd_hps_req),
|
|
.cd_hps_lba(cd_hps_lba),
|
|
.cd_hps_ack(cd_hps_ack),
|
|
.cd_hps_data_valid(sd_buff_wr && cd_hps_ack),
|
|
// MiSTer uses little endian on linux. Swap over to big endian
|
|
// to actually fit the way the 68k wants it
|
|
.cd_hps_data({sd_buff_dout[7:0], sd_buff_dout[15:8]}),
|
|
|
|
// Interface to CDi
|
|
.cd_data_valid(cd_data_valid),
|
|
.cd_data(cd_data),
|
|
.seek_lba(cd_seek_lba),
|
|
.stop_sector_delivery(cd_stop_sector_delivery),
|
|
.seek_lba_valid(cd_seek_lba_valid),
|
|
.sector_tick(cd_sector_tick),
|
|
.sector_delivered(cd_sector_delivered),
|
|
|
|
.config_disable_seek_time
|
|
);
|
|
|
|
wire fail_not_enough_words;
|
|
wire fail_too_much_data;
|
|
wire debug_irq_hangup;
|
|
|
|
// TODO requires connection and testing with real photo diode
|
|
wire rc_eye /*verilator public_flat_rw*/;
|
|
|
|
ddr_if ddr_host ();
|
|
|
|
assign DDRAM_CLK = clk_mpeg;
|
|
assign DDRAM_ADDR = ddr_host.addr;
|
|
assign DDRAM_BE = ddr_host.byteenable;
|
|
assign DDRAM_WE = ddr_host.write;
|
|
assign DDRAM_RD = ddr_host.read;
|
|
assign DDRAM_DIN = ddr_host.wdata;
|
|
assign DDRAM_BURSTCNT = ddr_host.burstcnt;
|
|
assign ddr_host.rdata = DDRAM_DOUT;
|
|
assign ddr_host.rdata_ready = DDRAM_DOUT_READY;
|
|
assign ddr_host.busy = DDRAM_BUSY;
|
|
|
|
rgb888_s cdi_video_out;
|
|
assign {r, g, b} = {cdi_video_out.r, cdi_video_out.g, cdi_video_out.b};
|
|
|
|
cditop cditop (
|
|
.clk30(clk_sys),
|
|
.clk_audio(clk_audio),
|
|
.clk_mpeg(clk_mpeg),
|
|
.external_reset(cditop_reset),
|
|
|
|
.tvmode_pal(!tvmode_ntsc),
|
|
.debug_uart_fake_space,
|
|
.debug_disable_vcd_clock,
|
|
.debug_activate_vcd_filter,
|
|
.debug_force_video_plane,
|
|
.debug_limited_to_full,
|
|
.audio_cd_in_tray,
|
|
.debug_disable_audio_attenuation(status[2]),
|
|
|
|
.ce_pix(ce_pix),
|
|
|
|
.HBlank(HBlank),
|
|
.HSync (HSync),
|
|
.VBlank(VBlank),
|
|
.VSync (VSync),
|
|
.vga_f1(VGA_F1),
|
|
|
|
.vidout(cdi_video_out),
|
|
|
|
.sdram_addr(sdram_addr),
|
|
.sdram_rd(sdram_rd),
|
|
.sdram_wr(sdram_wr),
|
|
.sdram_word(sdram_word),
|
|
.sdram_din(sdram_din),
|
|
.sdram_dout(sdram_dout),
|
|
.sdram_busy(sdram_busy),
|
|
.sdram_refresh(sdram_refresh),
|
|
.sdram_burst,
|
|
.sdram_burstdata_valid,
|
|
.scc68_uart_tx(UART_TXD),
|
|
.scc68_uart_rx(UART_RXD),
|
|
|
|
.ddrif(ddr_host),
|
|
|
|
.slave_worm_adr (slave_worm_adr),
|
|
.slave_worm_data(slave_worm_data),
|
|
.slave_worm_wr (slave_worm_wr),
|
|
|
|
.nvram_backup_restore_adr(nvram_backup_restore_adr),
|
|
.nvram_restore_data(nvram_restore_data),
|
|
.nvram_backup_data(nvram_backup_data),
|
|
.nvram_restore_write(nvram_restore_write),
|
|
.nvram_cpu_changed(nvram_cpu_changed),
|
|
.nvram_allow_cpu_access(nvram_allow_cpu_access),
|
|
|
|
.slave_serial_in(slave_serial_in),
|
|
.slave_serial_out(slave_serial_out),
|
|
.slave_rts(slave_rts),
|
|
|
|
.scc68070_bypass_serial_in(scc68070_bypass_serial_in),
|
|
.scc68070_bypass_serial_out(scc68070_bypass_serial_out),
|
|
.scc68070_rts(scc68070_rts),
|
|
|
|
.rc_eye(rc_eye),
|
|
|
|
.cd_seek_lba(cd_seek_lba),
|
|
.cd_seek_lba_valid(cd_seek_lba_valid),
|
|
.cd_stop_sector_delivery(cd_stop_sector_delivery),
|
|
.cd_data_valid(cd_data_valid),
|
|
.cd_data(cd_data),
|
|
.cd_sector_tick(cd_sector_tick),
|
|
.cd_sector_delivered(cd_sector_delivered),
|
|
|
|
.cd_img_mount (cd_img_mount),
|
|
.cd_img_mounted(cd_img_mounted),
|
|
.tray_is_closed,
|
|
|
|
.audio_left (AUDIO_L),
|
|
.audio_right(AUDIO_R),
|
|
|
|
.fail_not_enough_words(fail_not_enough_words),
|
|
.fail_too_much_data(fail_too_much_data),
|
|
.config_disable_cpu_starve,
|
|
.config_auto_play,
|
|
.config_disable_vmpeg(config_disable_vmpeg),
|
|
|
|
.hps_rtc(hps_rtc)
|
|
);
|
|
|
|
|
|
assign CLK_VIDEO = clk_sys;
|
|
assign CE_PIXEL = ce_pix;
|
|
`ifdef VERILATOR
|
|
// when the videofreak is not used.
|
|
assign VGA_DE = ~(HBlank | VBlank);
|
|
`endif
|
|
assign VGA_HS = HSync;
|
|
assign VGA_VS = VSync;
|
|
assign VGA_R = r;
|
|
assign VGA_G = g;
|
|
assign VGA_B = b;
|
|
|
|
// ----- NvRAM Backup and Restore Handling -----
|
|
|
|
// If set, a backup of NvRAM shall be performed as the content has changed.
|
|
// Will be reset, as soon as a backup operation has begun
|
|
// to allow yet another backup operation after the current one
|
|
// to ensure the latest state on the SD card
|
|
bit nvram_backup_pending = 0;
|
|
|
|
// Make the USER LED indicate that we need to perform a backup
|
|
assign LED_USER = nvram_backup_pending;
|
|
|
|
enum bit [3:0] {
|
|
NVRAM_IDLE,
|
|
NVRAM_WAIT_FOR_ACK,
|
|
NVRAM_BACKUP0,
|
|
NVRAM_BACKUP1,
|
|
NVRAM_BACKUP2,
|
|
NVRAM_BACKUP3,
|
|
NVRAM_RESTORE0,
|
|
NVRAM_RESTORE1,
|
|
NVRAM_RESTORE2
|
|
} nvram_state;
|
|
|
|
// Used to notice a change of the address
|
|
bit sd_buff_addr_q;
|
|
|
|
// Is set, if NvRAM image is mounted and usable
|
|
bit nvram_img_mounted = 0;
|
|
|
|
// Is set, if CD image is mounted and usable
|
|
bit cd_img_mounted = 0;
|
|
|
|
wire tray_is_closed;
|
|
|
|
// Used to detect changes of OSD_STATUS
|
|
bit OSD_STATUS_q;
|
|
|
|
always_ff @(posedge clk_sys) begin
|
|
info <= 0;
|
|
info_req <= 0;
|
|
sd_buff_addr_q <= sd_buff_addr[0];
|
|
nvram_restore_write <= 0;
|
|
OSD_STATUS_q <= OSD_STATUS;
|
|
|
|
if (nvram_media_change) nvram_img_mounted <= (img_size != 0);
|
|
if (cd_media_change) cd_img_mounted <= (img_size != 0);
|
|
|
|
if (cditop_reset) begin
|
|
nvram_backup_pending <= 0;
|
|
end else if (nvram_cpu_changed && nvram_img_mounted) begin
|
|
nvram_backup_pending <= 1;
|
|
end
|
|
|
|
if (nvram_hps_ack) begin
|
|
nvram_hps_wr <= 0;
|
|
nvram_hps_rd <= 0;
|
|
end
|
|
|
|
case (nvram_state)
|
|
NVRAM_IDLE: begin
|
|
nvram_allow_cpu_access <= 1;
|
|
nvram_backup_restore_adr <= 0;
|
|
|
|
if (nvram_img_mount) begin
|
|
// NvRAM image mounted? Then restore that to NvRAM!
|
|
nvram_hps_rd <= 1;
|
|
nvram_state <= NVRAM_WAIT_FOR_ACK;
|
|
nvram_allow_cpu_access <= 0;
|
|
end else if (nvram_backup_pending && OSD_STATUS && !OSD_STATUS_q) begin
|
|
// NvRAM has changed? And OSD was just opened? Well, then make a backup!
|
|
nvram_backup_pending <= 0;
|
|
nvram_hps_wr <= 1;
|
|
nvram_state <= NVRAM_WAIT_FOR_ACK;
|
|
nvram_allow_cpu_access <= 0;
|
|
end
|
|
end
|
|
NVRAM_WAIT_FOR_ACK: begin
|
|
if (nvram_hps_ack) begin
|
|
if (nvram_hps_rd) nvram_state <= NVRAM_RESTORE0;
|
|
if (nvram_hps_wr) nvram_state <= NVRAM_BACKUP0;
|
|
end
|
|
end
|
|
NVRAM_BACKUP0: begin
|
|
nvram_backup_restore_adr <= nvram_backup_restore_adr + 1;
|
|
nvram_state <= NVRAM_BACKUP1;
|
|
end
|
|
NVRAM_BACKUP1: begin
|
|
nvram_hps_din[7:0] <= nvram_backup_data;
|
|
nvram_backup_restore_adr <= nvram_backup_restore_adr + 1;
|
|
nvram_state <= NVRAM_BACKUP2;
|
|
end
|
|
NVRAM_BACKUP2: begin
|
|
nvram_hps_din[15:8] <= nvram_backup_data;
|
|
nvram_state <= NVRAM_BACKUP3;
|
|
end
|
|
NVRAM_BACKUP3: begin
|
|
if (sd_buff_addr_q != sd_buff_addr[0]) begin
|
|
nvram_state <= NVRAM_BACKUP1;
|
|
nvram_backup_restore_adr <= nvram_backup_restore_adr + 1;
|
|
end
|
|
if (!nvram_hps_ack) nvram_state <= NVRAM_IDLE;
|
|
end
|
|
|
|
NVRAM_RESTORE0: begin
|
|
if (sd_buff_wr) begin
|
|
nvram_restore_data_temp <= sd_buff_dout;
|
|
nvram_restore_write <= 1;
|
|
nvram_state <= NVRAM_RESTORE1;
|
|
end
|
|
|
|
if (!nvram_hps_ack) begin
|
|
nvram_state <= NVRAM_IDLE;
|
|
nvram_allow_cpu_access <= 1;
|
|
end
|
|
end
|
|
NVRAM_RESTORE1: begin
|
|
nvram_restore_write <= 1;
|
|
nvram_backup_restore_adr <= nvram_backup_restore_adr + 1;
|
|
nvram_state <= NVRAM_RESTORE2;
|
|
end
|
|
NVRAM_RESTORE2: begin
|
|
nvram_backup_restore_adr <= nvram_backup_restore_adr + 1;
|
|
nvram_state <= NVRAM_RESTORE0;
|
|
end
|
|
|
|
default: nvram_state <= NVRAM_IDLE;
|
|
endcase
|
|
end
|
|
|
|
endmodule
|