1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-01-19 09:18:02 +00:00

Merge pull request #105 from gyurco/cmossave

NVRAM save for MCR/Defender/Robotron cores
This commit is contained in:
Marcel 2020-12-20 20:36:14 +01:00 committed by GitHub
commit 916bf8bee4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 270 additions and 103 deletions

View File

@ -16,6 +16,11 @@
-- Copy the ROM files to the root of the SD Card.
--
-- MRA utilty: https://github.com/sebdel/mra-tools-c
--
-- Some games are storing settings/high scores in a non-volatile RAM. It can be saved to
-- the SD Card with the "Save NVRAM" option in the OSD menu. It'll be restored when
-- the core is loaded next time.
--
---------------------------------------------------------------------------------
-- DE10_lite Top level for Satan Hollow (Midway MCR) by Dar (darfpga@aol.fr) (19/10/2019)
-- http://darfpga.blogspot.fr

View File

@ -52,13 +52,14 @@ module MCR2_MiST(
wire [6:0] core_mod;
localparam CONF_STR = {
`CORE_NAME,";ROM;",
`CORE_NAME,";;",
"O2,Rotate Controls,Off,On;",
"O5,Blend,Off,On;",
"O6,Swap Joysticks,Off,On;",
"O4,Spinner speed,Low,High;",
"DIP;",
"O7,Service,Off,On;",
"R2048,Save NVRAM;",
"T0,Reset;",
"V,v2.0.",`BUILD_DATE
};
@ -202,10 +203,12 @@ wire [15:0] rom_do;
wire [13:0] snd_addr;
wire [15:0] snd_do;
wire ioctl_downl;
wire ioctl_upl;
wire [7:0] ioctl_index;
wire ioctl_wr;
wire [24:0] ioctl_addr;
wire [7:0] ioctl_dout;
wire [7:0] ioctl_din;
/* ROM structure
00000 - 0BFFF 48k CPU1
@ -219,11 +222,14 @@ data_io data_io(
.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_dout ( ioctl_dout )
.ioctl_dout ( ioctl_dout ),
.ioctl_din ( ioctl_din )
);
reg port1_req, port2_req;
sdram sdram(
@ -261,7 +267,7 @@ always @(posedge clk_sys) begin
ioctl_wr_last <= ioctl_wr;
if (ioctl_downl) begin
if (~ioctl_wr_last && ioctl_wr) begin
if (~ioctl_wr_last && ioctl_wr && ioctl_index == 0) begin
port1_req <= ~port1_req;
port2_req <= ~port2_req;
end
@ -310,8 +316,10 @@ satans_hollow satans_hollow(
.snd_rom_do ( snd_addr[0] ? snd_do[15:8] : snd_do[7:0] ),
.dl_addr ( ioctl_addr[16:0]),
.dl_wr ( ioctl_wr ),
.dl_data ( ioctl_dout )
.dl_wr ( ioctl_wr && ioctl_index == 0 ),
.dl_data ( ioctl_dout ),
.up_data ( ioctl_din ),
.cmos_wr ( ioctl_wr && ioctl_index == 8'hff )
);
wire vs_out;

View File

@ -169,7 +169,9 @@ port(
dl_addr : in std_logic_vector(16 downto 0);
dl_wr : in std_logic;
dl_data : in std_logic_vector( 7 downto 0)
dl_data : in std_logic_vector( 7 downto 0);
up_data : out std_logic_vector(7 downto 0);
cmos_wr : in std_logic
);
end satans_hollow;
@ -673,14 +675,19 @@ cpu_rom_addr <= cpu_addr(15 downto 0);
cpu_rom_rd <= '1' when cpu_mreq_n = '0' and cpu_rd_n = '0' and cpu_addr(15 downto 12) < X"C" else '0';
-- working RAM 0xC000-0xC7FF + mirroring adresses
wram : entity work.cmos_ram
wram : entity work.dpram
generic map( dWidth => 8, aWidth => 11)
port map(
clk => clock_vidn,
we => wram_we,
addr => cpu_addr(10 downto 0),
d => cpu_do,
q => wram_do
clk_a => clock_vidn,
addr_a => cpu_addr(10 downto 0),
d_a => cpu_do,
we_a => wram_we,
q_a => wram_do,
clk_b => clock_vid,
we_b => cmos_wr,
addr_b => dl_addr(10 downto 0),
d_b => dl_data,
q_b => up_data
);
-- video RAM 0xE800-0xEFFF + mirroring adresses

View File

@ -71,6 +71,10 @@ Copy the ROM files to the root of the SD Card.
MRA utilty: https://github.com/sebdel/mra-tools-c
Some games are storing settings/high scores in a non-volatile RAM. It can be saved to
the SD Card with the "Save NVRAM" option in the OSD menu. It'll be restored when
the core is loaded next time.
Based on Darfpga's work:
---------------------------------------------------------------------------------
-- DE10_lite Top level for Timber (Midway MCR) by Dar (darfpga@aol.fr) (22/11/2019)

View File

@ -54,12 +54,13 @@ module MCR3_MiST(
wire [6:0] core_mod;
localparam CONF_STR = {
`CORE_NAME,";ROM;",
`CORE_NAME,";;",
"O2,Rotate Controls,Off,On;",
"O5,Blend,Off,On;",
"O6,Swap Joystick,Off,On;",
"DIP;",
"O7,Service,Off,On;",
"R2048,Save NVRAM;",
"T0,Reset;",
"V,v1.1.",`BUILD_DATE
};
@ -220,10 +221,12 @@ user_io(
);
wire ioctl_downl;
wire ioctl_upl;
wire [7:0] ioctl_index;
wire ioctl_wr;
wire [24:0] ioctl_addr;
wire [7:0] ioctl_dout;
wire [7:0] ioctl_din;
/*
ROM structure:
@ -249,10 +252,12 @@ data_io #(.ROM_DIRECT_UPLOAD(1)) data_io(
.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_dout ( ioctl_dout )
.ioctl_dout ( ioctl_dout ),
.ioctl_din ( ioctl_din )
);
wire [15:0] rom_addr;
@ -328,7 +333,7 @@ always @(posedge clk_sys) begin
ioctl_wr_last <= ioctl_wr;
if (ioctl_downl) begin
if (~ioctl_wr_last && ioctl_wr) begin
if (~ioctl_wr_last && ioctl_wr && ioctl_index == 0) begin
port1_req <= ~port1_req;
port2_req <= ~port2_req;
end
@ -397,9 +402,11 @@ mcr3 mcr3 (
.sp_addr ( sp_addr ),
.sp_graphx32_do ( sp_do ),
.dl_addr(ioctl_addr-gfx1_offset),
.dl_data(ioctl_dout),
.dl_wr(ioctl_wr)
.dl_addr ( ioctl_addr-(ioctl_index == 0 ? gfx1_offset : 0) ),
.dl_data ( ioctl_dout ),
.dl_wr ( ioctl_wr && ioctl_index == 0 ),
.up_data ( ioctl_din ),
.cmos_wr ( ioctl_wr && ioctl_index == 8'hff )
);
wire vs_out;

View File

@ -174,7 +174,9 @@ port(
-- internal ROM download
dl_addr : in std_logic_vector(18 downto 0);
dl_data : in std_logic_vector(7 downto 0);
dl_wr : in std_logic
dl_wr : in std_logic;
up_data : out std_logic_vector(7 downto 0);
cmos_wr : in std_logic
);
end mcr3;
@ -741,14 +743,19 @@ begin
end process;
-- working RAM 0xE000-0xE7FF
wram : entity work.cmos_ram
wram : entity work.dpram
generic map( dWidth => 8, aWidth => 11)
port map(
clk => clock_vidn,
we => wram_we,
addr => cpu_addr(10 downto 0),
d => cpu_do,
q => wram_do
clk_a => clock_vidn,
addr_a => cpu_addr(10 downto 0),
d_a => cpu_do,
we_a => wram_we,
q_a => wram_do,
clk_b => clock_vid,
we_b => cmos_wr,
addr_b => dl_addr(10 downto 0),
d_b => dl_data,
q_b => up_data
);
-- video RAM 0xF000-0xF7FF

View File

@ -23,7 +23,10 @@ C SPACE : Shift
X Z : Oil
Y X : Smoke
-- The settings in the service mode can be preserved by choosing the "Save NVRAM"
-- option in the OSD menu. It'll be saved to a .RAM file, and restored when the core
-- is loaded.
--
---------------------------------------------------------------------------------
-- DE10_lite Top level for Spy hunter (Midway MCR) by Dar (darfpga@aol.fr) (06/12/2019)
-- http://darfpga.blogspot.fr

View File

@ -41,7 +41,7 @@
# ========================
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 LAST_QUARTUS_VERSION "13.1 SP4.26"
set_global_assignment -name PRE_FLOW_SCRIPT_FILE "quartus_sh:rtl/build_id.tcl"
# Pin & Location Assignments
@ -214,7 +214,7 @@ 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_global_assignment -name ENABLE_SIGNALTAP OFF
set_global_assignment -name USE_SIGNALTAP_FILE output_files/csd.stp
set_global_assignment -name USE_SIGNALTAP_FILE output_files/cmos.stp
set_global_assignment -name CYCLONEII_OPTIMIZATION_TECHNIQUE SPEED
set_global_assignment -name SYNTH_TIMING_DRIVEN_SYNTHESIS ON
set_global_assignment -name OPTIMIZE_HOLD_TIMING "ALL PATHS"
@ -241,4 +241,6 @@ set_global_assignment -name QIP_FILE ../../../common/CPU/T80/T80.qip
set_global_assignment -name VHDL_FILE ../../../common/Sound/ym2149/vol_table_array.vhd
set_global_assignment -name VHDL_FILE ../../../common/Sound/ym2149/YM2149.vhd
set_global_assignment -name QIP_FILE ../../../common/mist/mist.qip
set_global_assignment -name SIGNALTAP_FILE output_files/cmos.stp
set_location_assignment PIN_90 -to SPI_SS4
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

View File

@ -88,11 +88,11 @@ set_input_delay -clock [get_clocks $sdram_clk] -reference_pin [get_ports {SDRAM_
# Set Output Delay
#**************************************************************
set_output_delay -add_delay -clock_fall -clock [get_clocks {SPI_SCK}] 1.000 [get_ports {SPI_DO}]
set_output_delay -add_delay -clock_fall -clock [get_clocks $sys_clk] 1.000 [get_ports {AUDIO_L}]
set_output_delay -add_delay -clock_fall -clock [get_clocks $sys_clk] 1.000 [get_ports {AUDIO_R}]
set_output_delay -add_delay -clock_fall -clock [get_clocks $sys_clk] 1.000 [get_ports {LED}]
set_output_delay -add_delay -clock_fall -clock [get_clocks $sys_clk] 1.000 [get_ports {VGA_*}]
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}]
@ -116,6 +116,9 @@ set_clock_groups -asynchronous -group [get_clocks {SPI_SCK}] -group [get_clocks
set_multicycle_path -to {VGA_*[*]} -setup 2
set_multicycle_path -to {VGA_*[*]} -hold 1
set_multicycle_path -from [get_clocks $sys_clk] -to [get_clocks $sdram_clk] -setup 2
set_multicycle_path -from [get_clocks $sys_clk] -to [get_clocks $sdram_clk] -hold 1
#**************************************************************
# Set Maximum Delay
#**************************************************************

View File

@ -26,10 +26,11 @@ module SpyHunter_MiST(
output AUDIO_L,
output AUDIO_R,
input SPI_SCK,
output SPI_DO,
inout SPI_DO,
input SPI_DI,
input SPI_SS2,
input SPI_SS3,
input SPI_SS4,
input CONF_DATA0,
input CLOCK_27,
output [12:0] SDRAM_A,
@ -54,6 +55,7 @@ localparam CONF_STR = {
"O6,Service,Off,On;",
"O8,Demo Sounds,Off,On;",
"O9,Show Lamps,Off,On;",
"R2048,Save NVRAM;",
"T0,Reset;",
"V,v1.1.",`BUILD_DATE
};
@ -91,7 +93,8 @@ wire [7:0] key_code;
wire key_strobe;
user_io #(
.STRLEN(($size(CONF_STR)>>3)))
.STRLEN(($size(CONF_STR)>>3)),
.ROM_DIRECT_UPLOAD(1'b1))
user_io(
.clk_sys (clk_sys ),
.conf_str (CONF_STR ),
@ -121,21 +124,29 @@ wire [15:0] csd_do;
wire [14:0] sp_addr;
wire [31:0] sp_do;
wire ioctl_downl;
wire ioctl_upl;
wire [7:0] ioctl_index;
wire ioctl_wr;
wire [24:0] ioctl_addr;
wire [7:0] ioctl_dout;
wire [7:0] ioctl_din;
data_io data_io(
data_io #(
.ROM_DIRECT_UPLOAD(1'b1))
data_io(
.clk_sys ( clk_sys ),
.SPI_SCK ( SPI_SCK ),
.SPI_SS2 ( SPI_SS2 ),
.SPI_SS4 ( SPI_SS4 ),
.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_dout ( ioctl_dout )
.ioctl_dout ( ioctl_dout ),
.ioctl_din ( ioctl_din )
);
// ROM structure:
@ -200,7 +211,7 @@ always @(posedge clk_sys) begin
ioctl_wr_last <= ioctl_wr;
if (ioctl_downl) begin
if (~ioctl_wr_last && ioctl_wr) begin
if (~ioctl_wr_last && ioctl_wr && ioctl_index == 0) begin
port1_req <= ~port1_req;
port2_req <= ~port2_req;
end
@ -281,7 +292,9 @@ spy_hunter spy_hunter(
.sp_graphx32_do ( sp_do ),
.dl_addr ( ioctl_addr[18:0]),
.dl_data ( ioctl_dout ),
.dl_wr ( ioctl_wr )
.dl_wr ( ioctl_wr && ioctl_index == 0 ),
.up_data ( ioctl_din ),
.cmos_wr ( ioctl_wr && ioctl_index == 8'hff )
);
wire vs_out;

View File

@ -185,6 +185,8 @@ port(
dl_addr : in std_logic_vector(18 downto 0);
dl_data : in std_logic_vector(7 downto 0);
dl_wr : in std_logic;
up_data : out std_logic_vector(7 downto 0);
cmos_wr : in std_logic;
dbg_cpu_addr : out std_logic_vector(15 downto 0)
);
@ -938,14 +940,19 @@ port map (
--);
-- working RAM F000-F7FF 2Ko
wram : entity work.cmos_ram
wram : entity work.dpram
generic map( dWidth => 8, aWidth => 11)
port map(
clk => clock_vidn,
we => wram_we,
addr => cpu_addr(10 downto 0),
d => cpu_do,
q => wram_do
clk_a => clock_vidn,
addr_a => cpu_addr(10 downto 0),
d_a => cpu_do,
we_a => wram_we,
q_a => wram_do,
clk_b => clock_vid,
we_b => cmos_wr,
addr_b => dl_addr(10 downto 0),
d_b => dl_data,
q_b => up_data
);
-- char RAM E800-EBFF 1Ko + mirroring 0400

View File

@ -13,6 +13,10 @@
--
-- MRA utility: https://github.com/sebdel/mra-tools-c/
--
-- Defender stores its settings and the high score table in a non-volatile RAM.
-- It can be saved to the SD Card with the "Save NVRAM" OSD option, and it'll
-- be restored next time the core is loaded.
--
---------------------------------------------------------------------------------
-- A simulation model of Williams 6809 hardware
-- by Dar (darfpga@aol.fr)

View File

@ -37,11 +37,12 @@ module Defender_MiST(
`define CORE_NAME "DEFENDER"
localparam CONF_STR = {
`CORE_NAME,";ROM;",
`CORE_NAME,";;",
"O2,Rotate Controls,Off,On;",
"O34,Scanlines,Off,25%,50%,75%;",
"O5,Blend,Off,On;",
"DIP;",
"R256,Save NVRAM;",
"T0,Reset;",
"V,v1.2.",`BUILD_DATE
};
@ -185,10 +186,12 @@ user_io(
);
wire ioctl_downl;
wire ioctl_upl;
wire [7:0] ioctl_index;
wire ioctl_wr;
wire [24:0] ioctl_addr;
wire [7:0] ioctl_dout;
wire [7:0] ioctl_din;
/*
ROM Structure:
@ -201,11 +204,14 @@ data_io data_io (
.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_dout ( ioctl_dout )
.ioctl_dout ( ioctl_dout ),
.ioctl_din ( ioctl_din )
);
reg port1_req, port2_req;
@ -252,7 +258,7 @@ always @(posedge clk_sys) begin
reg snd_vma_r, snd_vma_r2;
ioctl_wr_last <= ioctl_wr;
if (ioctl_downl) begin
if (ioctl_downl && ioctl_index == 0) begin
if (~ioctl_wr_last && ioctl_wr) begin
port1_req <= ~port1_req;
port2_req <= ~port2_req;
@ -306,7 +312,9 @@ defender defender (
.dl_clock ( clk_sys ),
.dl_addr ( ioctl_addr[15:0] ),
.dl_data ( ioctl_dout ),
.dl_wr ( ioctl_wr )
.dl_wr ( ioctl_wr && ioctl_index == 0 ),
.up_data ( ioctl_din ),
.cmos_wr ( ioctl_wr && ioctl_index == 8'hff )
);
mist_video #(.COLOR_DEPTH(3), .SD_HCNT_WIDTH(11)) mist_video(

View File

@ -153,7 +153,9 @@ port(
dl_clock : in std_logic;
dl_addr : in std_logic_vector(15 downto 0);
dl_data : in std_logic_vector( 7 downto 0);
dl_wr : in std_logic
dl_wr : in std_logic;
up_data : out std_logic_vector(7 downto 0);
cmos_wr : in std_logic
);
end defender;
@ -567,14 +569,19 @@ port map(
);
-- cmos ram
cmos_ram : entity work.defender_cmos_ram
cmos_ram : entity work.dpram
generic map( dWidth => 4, aWidth => 8)
port map(
clk => clock_6,
we => cmos_we,
addr => cpu_addr(7 downto 0),
d => cpu_do(3 downto 0),
q => cmos_do
clk_a => clock_6,
we_a => cmos_we,
addr_a => cpu_addr(7 downto 0),
d_a => cpu_do(3 downto 0),
q_a => cmos_do,
clk_b => dl_clock,
we_b => cmos_wr,
addr_b => dl_addr(7 downto 0),
d_b => dl_data(3 downto 0),
q_b => up_data(3 downto 0)
);
-- cpu to video addr decoder

View File

@ -19,7 +19,8 @@ Usage:
Note: the MRA files contains a dump of the CMOS RAM. It will be included in the generated ROM file.
Change it for permanent settings (search for the format online). It's possible to change these values
inside the core, with turning on "Auto-up" switch, and activate the "Advance" trigger in the OSD.
inside the core, with turning on "Auto-up" switch, and activate the "Advance" trigger in the OSD. Then
it's possible to save these settings and high scores into a RAM file via the "Save NVRAM" OSD item.
Refer to the arcade's user manual for further info.

View File

@ -42,13 +42,14 @@ module RobotronFPGA_MiST(
`define CORE_NAME "ROBOTRON"
localparam CONF_STR = {
`CORE_NAME,";ROM;",
`CORE_NAME,";;",
"O2,Rotate Controls,Off,On;",
"O34,Scanlines,Off,25%,50%,75%;",
"O5,Blend,Off,On;",
"O6,Swap Joysticks,Off,On;",
"O7,Auto up,Off,On;",
"T8,Advance;",
"R1024,Save NVRAM;",
"T0,Reset;",
"V,v1.0.",`BUILD_DATE
};
@ -263,10 +264,12 @@ user_io(
);
wire ioctl_downl;
wire ioctl_upl;
wire [7:0] ioctl_index;
wire ioctl_wr;
wire [24:0] ioctl_addr;
wire [7:0] ioctl_dout;
wire [7:0] ioctl_din;
/*
ROM Structure:
@ -282,14 +285,18 @@ data_io data_io (
.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_dout ( ioctl_dout )
.ioctl_dout ( ioctl_dout ),
.ioctl_din ( ioctl_din )
);
reg port1_req;
wire [15:0] port1_do;
wire [23:1] mem_addr;
wire [15:0] mem_do;
wire [15:0] mem_di;
@ -316,7 +323,7 @@ sdram #(.MHZ(96)) sdram(
.port1_ds ( 2'b11 ),
.port1_we ( ioctl_downl ),
.port1_d ( {ioctl_dout[7:4], ioctl_dout[7:4], ioctl_dout[3:0], ioctl_dout[3:0]} ),
.port1_q ( ),
.port1_q ( port1_do ),
// CPU/video access
.cpu1_addr ( ioctl_downl ? 17'h1ffff : sdram_addr ),
@ -333,12 +340,18 @@ sdram #(.MHZ(96)) sdram(
wire [17:1] sdram_addr = ~romcs ? {1'b0, mem_addr[16], ~mem_addr[16] & mem_addr[15], mem_addr[14:1]} : { 1'b1, mem_addr[16:1] };
// IOCTL address to SDRAM address:
// D000-D3FF -> 1CC00-1CFFF (CMOS), otherwise direct mapping
// D000-D3FF (ROM) or 000-3FFF (RAM) -> 1CC00-1CFFF (CMOS), otherwise direct mapping
wire [22:0] downl_addr = (ioctl_addr[22:10] == { 7'h0, 4'hD, 2'b00 }) ? { 1'b1, 4'hC, 2'b11, ioctl_addr[9:0] } : ioctl_addr[22:0];
wire [22:0] downl_addr =
((ioctl_index == 0 && ioctl_addr[22:10] == { 7'h0, 4'hD, 2'b00 }) || ioctl_index == 8'hff) ? { 1'b1, 4'hC, 2'b11, ioctl_addr[9:0] } :
ioctl_addr[22:0];
assign ioctl_din = { port1_do[11:8], port1_do[3:0] };
always @(posedge clk_mem) begin
reg ioctl_wr_last = 0;
reg [9:0] cmos_addr;
reg ioctl_upl_d;
ioctl_wr_last <= ioctl_wr;
if (ioctl_downl) begin
@ -346,6 +359,14 @@ always @(posedge clk_mem) begin
port1_req <= ~port1_req;
end
end
ioctl_upl_d <= ioctl_upl;
cmos_addr <= ioctl_addr[9:0];
if (ioctl_upl) begin
if (cmos_addr != ioctl_addr[9:0] || !ioctl_upl_d) begin
port1_req <= ~port1_req;
end
end
end
reg reset = 1;
@ -378,7 +399,8 @@ robotron_soc robotron_soc (
.blitter_sc2 ( blitter_sc2 ),
.sinistar ( sinistar ),
.speedball ( speedball ),
.speedball ( speedball ),
.pause ( ioctl_upl ),
.BTN ( BTN ),
.SIN_FIRE ( ~m_fireA & ~m_fire2A ),
.SIN_BOMB ( ~m_fireB & ~m_fire2B ),
@ -403,7 +425,7 @@ robotron_soc robotron_soc (
.dl_clock ( clk_mem ),
.dl_addr ( ioctl_addr[16:0] ),
.dl_data ( ioctl_dout ),
.dl_wr ( ioctl_wr )
.dl_wr ( ioctl_wr && ioctl_index == 0 )
);
mist_video #(.COLOR_DEPTH(3), .SD_HCNT_WIDTH(11)) mist_video(

View File

@ -40,6 +40,7 @@ entity robotron_cpu is
blitter_sc2 : in std_logic;
sinistar : in std_logic;
speedball : in std_logic;
pause : in std_logic;
-- MC6809 signals
A : in std_logic_vector(15 downto 0);
Dout : in std_logic_vector(7 downto 0);
@ -1017,7 +1018,7 @@ begin
-- on Q falling edge. Present once per processor clock,
-- on Q rising edge -- just because.
RESET_N <= not mpu_reset;
HALT_N <= not mpu_halt;
HALT_N <= not (mpu_halt or pause);
IRQ_N <= not mpu_irq;
FIRQ_N <= not mpu_firq;
NMI_N <= not mpu_nmi;

View File

@ -35,6 +35,7 @@ entity robotron_soc is
port (
clock : in std_logic; -- 12MHz
clock_snd : in std_logic; -- 0.89MHz
pause : in std_logic;
-- Cellular RAM / StrataFlash
MemOE : out std_logic;
@ -172,6 +173,7 @@ port map (
blitter_sc2 => blitter_sc2,
sinistar => sinistar,
speedball => speedball,
pause => pause,
A => cpu_a,
Dout => cpu_dout,
Din => cpu_din,

View File

@ -28,18 +28,20 @@ module data_io
input SPI_SS2,
input SPI_SS4,
input SPI_DI,
input SPI_DO, // yes, SPI_DO is input when SS4 active
inout SPI_DO,
input clkref_n, // assert ioctl_wr one cycle after clkref stobe (negative active)
// ARM -> FPGA download
output reg ioctl_download = 0, // signal indicating an active download
output reg ioctl_upload = 0, // signal indicating an active upload
output reg [7:0] ioctl_index, // menu index used to upload the file ([7:6] - extension index, [5:0] - menu index)
// Note: this is also set for user_io mounts.
// Valid when ioctl_download = 1 or when img_mounted strobe is active in user_io.
output reg ioctl_wr, // strobe indicating ioctl_dout valid
output reg [24:0] ioctl_addr,
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
);
@ -51,23 +53,41 @@ parameter ROM_DIRECT_UPLOAD = 0;
reg [7:0] data_w;
reg [7:0] data_w2 = 0;
reg [3:0] cnt;
reg rclk = 0;
reg rclk2 = 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;
assign SPI_DO = reg_do;
// data_io has its own SPI interface to the io controller
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;
reg_do <= dout_r[~cnt[2:0]];
end
end
always@(posedge SPI_SCK, posedge SPI_SS2) begin : SPI_RECEIVER
reg [6:0] sbuf;
reg [7:0] cmd;
reg [3:0] cnt;
reg [5:0] bytecnt;
reg [24:0] addr;
reg [7:0] cmd;
reg [5:0] bytecnt;
if(SPI_SS2) begin
bytecnt <= 0;
@ -84,37 +104,53 @@ always@(posedge SPI_SCK, posedge SPI_SS2) begin : SPI_RECEIVER
// finished command byte
if(cnt == 7) cmd <= {sbuf, SPI_DI};
// prepare/end transmission
if((cmd == DIO_FILE_TX) && (cnt == 15)) begin
// prepare
if(SPI_DI) begin
addr_reset <= ~addr_reset;
downloading_reg <= 1;
end else begin
downloading_reg <= 0;
if(cnt == 15) begin
case (cmd)
// prepare/end transmission
DIO_FILE_TX: begin
// prepare
if(SPI_DI) begin
addr_reset <= ~addr_reset;
downloading_reg <= 1;
end else begin
downloading_reg <= 0;
end
end
end
// command 0x54: UIO_FILE_TX
if((cmd == DIO_FILE_TX_DAT) && (cnt == 15)) begin
data_w <= {sbuf, SPI_DI};
rclk <= ~rclk;
end
DIO_FILE_RX: begin
// prepare
if(SPI_DI) begin
addr_reset <= ~addr_reset;
uploading_reg <= 1;
end else begin
uploading_reg <= 0;
end
end
// expose file (menu) index
if((cmd == DIO_FILE_INDEX) && (cnt == 15)) ioctl_index <= {sbuf, SPI_DI};
// command 0x57: DIO_FILE_RX_DAT
// command 0x54: DIO_FILE_TX_DAT
DIO_FILE_RX_DAT,
DIO_FILE_TX_DAT: begin
data_w <= {sbuf, SPI_DI};
rclk <= ~rclk;
end
// receiving FAT directory entry (mist-firmware/fat.h - DIRENTRY)
if((cmd == DIO_FILE_INFO) && (cnt == 15)) 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};
8'h0A: ioctl_fileext[ 7: 0] <= {sbuf, SPI_DI};
8'h1C: ioctl_filesize[ 7: 0] <= {sbuf, SPI_DI};
8'h1D: ioctl_filesize[15: 8] <= {sbuf, SPI_DI};
8'h1E: ioctl_filesize[23:16] <= {sbuf, SPI_DI};
8'h1F: ioctl_filesize[31:24] <= {sbuf, SPI_DI};
// expose file (menu) index
DIO_FILE_INDEX: ioctl_index <= {sbuf, SPI_DI};
// 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};
8'h0A: ioctl_fileext[ 7: 0] <= {sbuf, SPI_DI};
8'h1C: ioctl_filesize[ 7: 0] <= {sbuf, SPI_DI};
8'h1D: ioctl_filesize[15: 8] <= {sbuf, SPI_DI};
8'h1E: ioctl_filesize[23:16] <= {sbuf, SPI_DI};
8'h1F: ioctl_filesize[31:24] <= {sbuf, SPI_DI};
endcase
end
endcase
end
end
@ -162,7 +198,7 @@ always@(posedge clk_sys) begin : DATA_OUT
reg rclk2D, rclk2D2;
reg addr_resetD, addr_resetD2;
reg wr_int, wr_int_direct;
reg wr_int, wr_int_direct, rd_int;
reg [24:0] addr;
reg [31:0] filepos;
@ -179,7 +215,13 @@ always@(posedge clk_sys) begin : DATA_OUT
wr_int_direct <= 0;
end
if (!uploading_reg) begin
ioctl_upload <= 0;
rd_int <= 0;
end
if (~clkref_n) begin
rd_int <= 0;
wr_int <= 0;
wr_int_direct <= 0;
if (wr_int || wr_int_direct) begin
@ -188,17 +230,26 @@ always@(posedge clk_sys) begin : DATA_OUT
addr <= addr + 1'd1;
ioctl_addr <= addr;
end
if (rd_int) begin
ioctl_addr <= ioctl_addr + 1'd1;
end
end
// detect transfer start from the SPI receiver
if(addr_resetD ^ addr_resetD2) begin
addr <= START_ADDR;
ioctl_addr <= START_ADDR;
filepos <= 0;
ioctl_download <= 1;
ioctl_download <= downloading_reg;
ioctl_upload <= uploading_reg;
end
// detect new byte from the SPI receiver
if (rclkD ^ rclkD2) wr_int <= 1;
if (rclkD ^ rclkD2) begin
wr_int <= downloading_reg;
rd_int <= uploading_reg;
end
// direct transfer receiver
if (rclk2D ^ rclk2D2 && filepos != ioctl_filesize) begin
filepos <= filepos + 1'd1;
wr_int_direct <= 1;

View File

@ -30,7 +30,7 @@ port (
joystick_4 : out std_logic_vector(31 downto 0);
joystick_analog_0 : out std_logic_vector(15 downto 0);
joystick_analog_1 : out std_logic_vector(15 downto 0);
status : out std_logic_vector(31 downto 0);
status : out std_logic_vector(63 downto 0);
switches : out std_logic_vector(1 downto 0);
buttons : out std_logic_vector(1 downto 0);
scandoubler_disable : out std_logic;

View File

@ -47,8 +47,11 @@ module user_io #(parameter STRLEN=0, parameter PS2DIV=100, parameter ROM_DIRECT_
output scandoubler_disable,
output ypbpr,
output no_csync,
output reg [31:0] status,
output reg [63:0] status,
output reg [6:0] core_mod, // core variant, sent before the config string is requested
// RTC data from IO controller
// sec, min, hour, date, month, year, day (BCD)
output reg [63:0] rtc,
// connection to sd card emulation
input [31:0] sd_lba,
@ -497,12 +500,14 @@ always @(posedge clk_sys) begin : cmd_block
8'h15: status <= spi_byte_in;
// status, 32bit version
8'h1e: if(abyte_cnt<5) status[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
// status, 64bit version
8'h1e: if(abyte_cnt<9) status[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
// core variant
8'h21: core_mod <= spi_byte_in[6:0];
// RTC
8'h22: if(abyte_cnt<9) rtc[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
endcase
end
end