diff --git a/Arcade_MiST/Midway MCR 1/Kickman_MiST/Kickman.sdc b/Arcade_MiST/Midway MCR 1/Kickman_MiST/Kickman.sdc index fca44902..4f80488a 100644 --- a/Arcade_MiST/Midway MCR 1/Kickman_MiST/Kickman.sdc +++ b/Arcade_MiST/Midway MCR 1/Kickman_MiST/Kickman.sdc @@ -87,8 +87,8 @@ set_input_delay -clock [get_clocks {pll|altpll_component|auto_generated|pll1|clk #************************************************************** 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 {pll|altpll_component|auto_generated|pll1|clk[1]}] 1.000 [get_ports {AUDIO_L}] -set_output_delay -add_delay -clock_fall -clock [get_clocks {pll|altpll_component|auto_generated|pll1|clk[1]}] 1.000 [get_ports {AUDIO_R}] +set_output_delay -add_delay -clock_fall -clock [get_clocks {pll|altpll_component|auto_generated|pll1|clk[0]}] 1.000 [get_ports {AUDIO_L}] +set_output_delay -add_delay -clock_fall -clock [get_clocks {pll|altpll_component|auto_generated|pll1|clk[0]}] 1.000 [get_ports {AUDIO_R}] set_output_delay -add_delay -clock_fall -clock [get_clocks {pll|altpll_component|auto_generated|pll1|clk[0]}] 1.000 [get_ports {LED}] set_output_delay -add_delay -clock_fall -clock [get_clocks {pll|altpll_component|auto_generated|pll1|clk[0]}] 1.000 [get_ports {VGA_*}] @@ -116,9 +116,6 @@ 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 {pll|altpll_component|auto_generated|pll1|clk[0]}] -to [get_clocks {pll|altpll_component|auto_generated|pll1|clk[1]}] -setup 2 -set_multicycle_path -from [get_clocks {pll|altpll_component|auto_generated|pll1|clk[0]}] -to [get_clocks {pll|altpll_component|auto_generated|pll1|clk[1]}] -hold 1 - #************************************************************** # Set Maximum Delay #************************************************************** diff --git a/Arcade_MiST/Midway MCR 1/Kickman_MiST/README.txt b/Arcade_MiST/Midway MCR 1/Kickman_MiST/README.txt index 8370a324..72ce28a1 100644 --- a/Arcade_MiST/Midway MCR 1/Kickman_MiST/README.txt +++ b/Arcade_MiST/Midway MCR 1/Kickman_MiST/README.txt @@ -4,6 +4,10 @@ -- 3 November 2019 -- -- VGA Only +-- KICKMAN.ROM file : Main ROM + Sound ROM +-- 1200-a-ur.b3 + 1300-b-ur.b4 + 1400-c-ur.b5 + 1500-d-ur.d4 + 1600-e-ur.d5 + 1700-f-ur.d6 + +-- 4200-a.a7 + 4300-b.a8 + 4400-c.a9 + 4500-d.a10 + --------------------------------------------------------------------------------- -- DE10_lite Top level for Kick (Midway MCR) by Dar (darfpga@aol.fr) (19/10/2019) -- http://darfpga.blogspot.fr diff --git a/Arcade_MiST/Midway MCR 1/Kickman_MiST/Release/KICKMAN.ROM b/Arcade_MiST/Midway MCR 1/Kickman_MiST/Release/KICKMAN.ROM index 8fc0d5fe..9ecbd5b6 100644 Binary files a/Arcade_MiST/Midway MCR 1/Kickman_MiST/Release/KICKMAN.ROM and b/Arcade_MiST/Midway MCR 1/Kickman_MiST/Release/KICKMAN.ROM differ diff --git a/Arcade_MiST/Midway MCR 1/Kickman_MiST/rtl/Kickman_MiST.sv b/Arcade_MiST/Midway MCR 1/Kickman_MiST/rtl/Kickman_MiST.sv index 7f7eab8b..54eff27a 100644 --- a/Arcade_MiST/Midway MCR 1/Kickman_MiST/rtl/Kickman_MiST.sv +++ b/Arcade_MiST/Midway MCR 1/Kickman_MiST/rtl/Kickman_MiST.sv @@ -59,6 +59,7 @@ localparam CONF_STR = { assign LED = ~ioctl_downl; assign SDRAM_CLK = clk_sys; +assign SDRAM_CKE = 1; wire clk_sys; wire pll_locked; @@ -83,6 +84,9 @@ wire [3:0] g, r, b; wire [14:0] rom_addr; wire [15:0] rom_do; wire rom_rd; +wire [13:0] snd_addr; +wire [15:0] snd_do; +wire snd_rd; wire ioctl_downl; wire [7:0] ioctl_index; wire ioctl_wr; @@ -100,20 +104,57 @@ data_io data_io( .ioctl_addr ( ioctl_addr ), .ioctl_dout ( ioctl_dout ) ); - -sdram cart( + +reg port1_req, port2_req; +sdram sdram( .*, - .init ( ~pll_locked ), + .init_n ( pll_locked ), .clk ( clk_sys ), - .wtbt ( 2'b00 ), - .dout ( rom_do ), - .din ( {ioctl_dout, ioctl_dout} ), - .addr ( ioctl_downl ? ioctl_addr : rom_addr ), - .we ( ioctl_downl & ioctl_wr ), - .rd ( !ioctl_downl & rom_rd), - .ready() + + // port1 used for main CPU + .port1_req ( port1_req ), + .port1_ack (), + .port1_a ( ioctl_downl ? ioctl_addr[23:1] : rom_addr[14:1] ), + .port1_ds ( ioctl_downl ? {ioctl_addr[0], ~ioctl_addr[0]} : 2'b11 ), + .port1_we ( ioctl_downl ), + .port1_d ( {ioctl_dout, ioctl_dout} ), + .port1_q ( rom_do ), + + // port2 for sound board + .port2_req ( port2_req ), + .port2_ack (), + .port2_a ( ioctl_downl ? ioctl_addr[23:1] - 16'h3000 : snd_addr[13:1] ), + .port2_ds ( ioctl_downl ? {ioctl_addr[0], ~ioctl_addr[0]} : 2'b11 ), + .port2_we ( ioctl_downl ), + .port2_d ( {ioctl_dout, ioctl_dout} ), + .port2_q ( snd_do ) ); +always @(posedge clk_sys) begin + reg [14:1] rom_addr_last; + reg [13:1] snd_addr_last; + reg ioctl_wr_last = 0; + + ioctl_wr_last <= ioctl_wr; + if (ioctl_downl) begin + snd_addr_last <= 13'h1fff; + rom_addr_last <= 14'h3fff; + if (~ioctl_wr_last && ioctl_wr) begin + port1_req <= ~port1_req; + port2_req <= ~port2_req; + end + end else begin + if (rom_rd && rom_addr_last != rom_addr[14:1]) begin + rom_addr_last <= rom_addr[14:1]; + port1_req <= ~port1_req; + end + if (snd_rd && snd_addr_last != snd_addr[13:1]) begin + snd_addr_last <= snd_addr[13:1]; + port2_req <= ~port2_req; + end + end +end + reg reset = 1; reg rom_loaded = 0; always @(posedge clk_sys) begin @@ -146,8 +187,11 @@ kick kick( .btn_left(m_left), .btn_right(m_right), .cpu_rom_addr ( rom_addr ), - .cpu_rom_do ( rom_do[7:0] ), - .cpu_rom_rd ( rom_rd ) + .cpu_rom_do ( rom_addr[0] ? rom_do[15:8] : rom_do[7:0] ), + .cpu_rom_rd ( rom_rd ), + .snd_rom_addr ( snd_addr ), + .snd_rom_do ( snd_addr[0] ? snd_do[15:8] : snd_do[7:0] ), + .snd_rom_rd ( snd_rd ) ); mist_video #(.COLOR_DEPTH(4), .SD_HCNT_WIDTH(10)) mist_video( diff --git a/Arcade_MiST/Midway MCR 1/Kickman_MiST/rtl/kick.vhd b/Arcade_MiST/Midway MCR 1/Kickman_MiST/rtl/kick.vhd index e6579dd5..e7474216 100644 --- a/Arcade_MiST/Midway MCR 1/Kickman_MiST/rtl/kick.vhd +++ b/Arcade_MiST/Midway MCR 1/Kickman_MiST/rtl/kick.vhd @@ -171,7 +171,11 @@ port( dbg_cpu_addr : out std_logic_vector(15 downto 0); cpu_rom_addr : out std_logic_vector(14 downto 0); cpu_rom_do : in std_logic_vector(7 downto 0); - cpu_rom_rd : out std_logic + cpu_rom_rd : out std_logic; + + snd_rom_addr : out std_logic_vector(13 downto 0); + snd_rom_do : in std_logic_vector(7 downto 0); + snd_rom_rd : out std_logic ); end kick; @@ -744,7 +748,7 @@ port map( ); cpu_rom_addr <= cpu_addr(14 downto 0); -cpu_rom_rd <= '1' when cpu_mreq_n = '0' and cpu_addr(15 downto 12) < X"7" else '0'; +cpu_rom_rd <= '1' when cpu_mreq_n = '0' and cpu_rd_n = '0' and cpu_addr(15 downto 12) < X"7" else '0'; -- working RAM 0x7000-0x77FF wram : entity work.gen_ram @@ -880,6 +884,10 @@ port map( audio_out_l => audio_out_l, audio_out_r => audio_out_r, + cpu_rom_addr => snd_rom_addr, + cpu_rom_do => snd_rom_do, + cpu_rom_rd => snd_rom_rd, + dbg_cpu_addr => open --dbg_cpu_addr ); diff --git a/Arcade_MiST/Midway MCR 1/Kickman_MiST/rtl/kick_sound_board.vhd b/Arcade_MiST/Midway MCR 1/Kickman_MiST/rtl/kick_sound_board.vhd index bccea4eb..ca00dc07 100644 --- a/Arcade_MiST/Midway MCR 1/Kickman_MiST/rtl/kick_sound_board.vhd +++ b/Arcade_MiST/Midway MCR 1/Kickman_MiST/rtl/kick_sound_board.vhd @@ -71,7 +71,11 @@ port( audio_out_l : out std_logic_vector(15 downto 0); audio_out_r : out std_logic_vector(15 downto 0); - + + cpu_rom_addr : out std_logic_vector(13 downto 0); + cpu_rom_do : in std_logic_vector(7 downto 0); + cpu_rom_rd : out std_logic; + dbg_cpu_addr : out std_logic_vector(15 downto 0) ); end kick_sound_board; @@ -98,7 +102,7 @@ architecture struct of kick_sound_board is signal cpu_irq_n : std_logic; signal cpu_m1_n : std_logic; - signal cpu_rom_do : std_logic_vector( 7 downto 0); +-- signal cpu_rom_do : std_logic_vector( 7 downto 0); signal wram_we : std_logic; signal wram_do : std_logic_vector( 7 downto 0); @@ -430,12 +434,15 @@ port map( ); -- cpu program ROM 0x0000-0x3FFF -rom_cpu : entity work.kick_sound_cpu -port map( - clk => clock_sndn, - addr => cpu_addr(13 downto 0), - data => cpu_rom_do -); +cpu_rom_addr <= cpu_addr(13 downto 0); +cpu_rom_rd <= '1' when cpu_mreq_n = '0' and cpu_rd_n = '0' and cpu_addr(15 downto 14) = "00" else '0'; -- 0x0000-0x3FFF + +--rom_cpu : entity work.kick_sound_cpu +--port map( +-- clk => clock_sndn, +-- addr => cpu_addr(13 downto 0), +-- data => cpu_rom_do +--); -- working RAM 0x8000-0x83FF wram : entity work.gen_ram diff --git a/Arcade_MiST/Midway MCR 1/Kickman_MiST/rtl/pll_mist.ppf b/Arcade_MiST/Midway MCR 1/Kickman_MiST/rtl/pll_mist.ppf new file mode 100644 index 00000000..fc447489 --- /dev/null +++ b/Arcade_MiST/Midway MCR 1/Kickman_MiST/rtl/pll_mist.ppf @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Arcade_MiST/Midway MCR 1/Kickman_MiST/rtl/sdram.sv b/Arcade_MiST/Midway MCR 1/Kickman_MiST/rtl/sdram.sv index 8f927d05..24cfd9ee 100644 --- a/Arcade_MiST/Midway MCR 1/Kickman_MiST/rtl/sdram.sv +++ b/Arcade_MiST/Midway MCR 1/Kickman_MiST/rtl/sdram.sv @@ -1,79 +1,126 @@ // // sdram.v // -// Static RAM controller implementation using SDRAM MT48LC16M16A2 +// sdram controller implementation for the MiST board +// https://github.com/mist-devel/mist-board +// +// Copyright (c) 2013 Till Harbaum +// Copyright (c) 2019 Gyorgy Szombathelyi // -// Copyright (c) 2015,2016 Sorgelig -// -// Some parts of SDRAM code used from project: -// http://hamsterworks.co.nz/mediawiki/index.php/Simple_SDRAM_Controller -// -// 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 +// 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 . -// -// ------------------------------------------ -// -// v2.1 - Add universal 8/16 bit mode. +// along with this program. If not, see . // -module sdram -( - input init, // reset to initialize RAM - input clk, // clock ~100MHz - // - // SDRAM_* - signals 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, // - 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 - output SDRAM_CKE, // clock enable - // - input [1:0] wtbt, // 16bit mode: bit1 - write high byte, bit0 - write low byte, - // 8bit mode: 2'b00 - use addr[0] to decide which byte to write - // Ignored while reading. - // - input [24:0] addr, // 25 bit address for 8bit mode. addr[0] = 0 for 16bit mode for correct operations. - output [15:0] dout, // data output to cpu - input [15:0] din, // data input from cpu - input we, // cpu requests write - input rd, // cpu requests read - output reg ready // dout is valid. Ready to accept new read/write. +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 [15:0] port1_q, + + 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 [15:0] port2_q ); -assign SDRAM_nCS = command[3]; -assign SDRAM_nRAS = command[2]; -assign SDRAM_nCAS = command[1]; -assign SDRAM_nWE = command[0]; -assign SDRAM_CKE = cke; +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 -// no burst configured -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 for < 100MHz, 3 for >100MHz -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}; +localparam MODE = { 3'b000, NO_WRITE_BURST, OP_MODE, CAS_LATENCY, ACCESS_TYPE, BURST_LENGTH}; -localparam sdram_startup_cycles= 14'd12100;// 100us, plus a little more, @ 100MHz -localparam cycles_per_refresh = 14'd186; // (64000*36)/8192-1 Calc'd as (64ms @ 36MHz)/8192 rose -localparam startup_refresh_max = 14'b11111111111111; +// 64ms/8192 rows = 7.8us -> 842 cycles@108MHz +localparam RFRSH_CYCLES = 10'd842; -// SDRAM commands +// --------------------------------------------------------------------- +// ------------------------ 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 - 3 +localparam STATE_CAS1 = STATE_RAS1 + RASCAS_DELAY; // CAS phase - 5 +localparam STATE_READ0 = STATE_CAS0 + CAS_LATENCY + 1'd1; // 7 +localparam STATE_READ1 = 3'd2; +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; @@ -84,171 +131,149 @@ localparam CMD_PRECHARGE = 4'b0010; localparam CMD_AUTO_REFRESH = 4'b0001; localparam CMD_LOAD_MODE = 4'b0000; -reg [13:0] refresh_count = startup_refresh_max - sdram_startup_cycles; -reg [3:0] command = CMD_INHIBIT; -reg cke = 0; -reg [24:0] save_addr; -reg [15:0] data; +reg [3:0] sd_cmd; // current command sent to sd ram -assign dout = save_addr[0] ? {data[7:0], data[15:8]} : {data[15:8], data[7:0]}; -typedef enum -{ - STATE_STARTUP, - STATE_OPEN_1, - STATE_WRITE, - STATE_READ, - STATE_IDLE, STATE_IDLE_1, STATE_IDLE_2, STATE_IDLE_3, - STATE_IDLE_4, STATE_IDLE_5, STATE_IDLE_6, STATE_IDLE_7 -} state_t; +// 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]; -state_t state = STATE_STARTUP; +reg [24:1] addr_latch[2]; +reg [24:1] addr_latch_next[2]; +reg [15:0] din_latch[2]; +reg [1:0] oe_latch; +reg [1:0] we_latch; +reg [1:0] ds[2]; + +localparam PORT_NONE = 1'b0; +localparam PORT_REQ = 1'b1; + +reg next_port[2]; + +reg refresh; +reg [10:0] refresh_cnt; +wire need_refresh = (refresh_cnt >= RFRSH_CYCLES); + +// PORT1: bank 0,1 +always @(*) begin + if (port1_req ^ port1_ack) begin + next_port[0] = PORT_REQ; + addr_latch_next[0] = { 1'b0, port1_a }; + end else begin + next_port[0] = PORT_NONE; + addr_latch_next[0] = addr_latch[0]; + end +end + +// PORT1: bank 2,3 +always @(*) begin + if ((port2_req ^ port2_ack) && !refresh) begin + next_port[1] = PORT_REQ; + addr_latch_next[1] = { 1'b1, port2_a }; + end else begin + next_port[1] = PORT_NONE; + addr_latch_next[1] = addr_latch[1]; + end +end always @(posedge clk) begin - reg old_we, old_rd; - reg [CAS_LATENCY:0] data_ready_delay; - reg [15:0] new_data; - reg [1:0] new_wtbt; - reg new_we; - reg new_rd; - reg save_we = 1; - - - command <= CMD_NOP; - refresh_count <= refresh_count+1'b1; - - data_ready_delay <= {1'b0, data_ready_delay[CAS_LATENCY:1]}; - - if(data_ready_delay[0]) data <= SDRAM_DQ; - - case(state) - STATE_STARTUP: begin - //------------------------------------------------------------------------ - //-- This is the initial startup state, where we wait for at least 100us - //-- before starting the start sequence - //-- - //-- The initialisation is sequence is - //-- * de-assert SDRAM_CKE - //-- * 100us wait, - //-- * assert SDRAM_CKE - //-- * wait at least one cycle, - //-- * PRECHARGE - //-- * wait 2 cycles - //-- * REFRESH, - //-- * tREF wait - //-- * REFRESH, - //-- * tREF wait - //-- * LOAD_MODE_REG - //-- * 2 cycles wait - //------------------------------------------------------------------------ - cke <= 1; - SDRAM_DQ <= 16'bZZZZZZZZZZZZZZZZ; - SDRAM_DQML <= 1; - SDRAM_DQMH <= 1; - SDRAM_A <= 0; - SDRAM_BA <= 0; - - // All the commands during the startup are NOPS, except these - if(refresh_count == startup_refresh_max-31) begin - // ensure all rows are closed - command <= CMD_PRECHARGE; - SDRAM_A[10] <= 1; // all banks - SDRAM_BA <= 2'b00; - end else if (refresh_count == startup_refresh_max-23) begin - // these refreshes need to be at least tREF (66ns) apart - command <= CMD_AUTO_REFRESH; - end else if (refresh_count == startup_refresh_max-15) - command <= CMD_AUTO_REFRESH; - else if (refresh_count == startup_refresh_max-7) begin - // Now load the mode register - command <= CMD_LOAD_MODE; - SDRAM_A <= MODE; - end - - //------------------------------------------------------ - //-- if startup is complete then go into idle mode, - //-- get prepared to accept a new command, and schedule - //-- the first refresh cycle - //------------------------------------------------------ - if(!refresh_count) begin - state <= STATE_IDLE; - ready <= 1; - refresh_count <= 0; - end - end - - STATE_IDLE_7: state <= STATE_IDLE_6; - STATE_IDLE_6: state <= STATE_IDLE_5; - STATE_IDLE_5: state <= STATE_IDLE_4; - STATE_IDLE_4: state <= STATE_IDLE_3; - STATE_IDLE_3: state <= STATE_IDLE_2; - STATE_IDLE_2: state <= STATE_IDLE_1; - STATE_IDLE_1: begin - SDRAM_DQ <= 16'bZZZZZZZZZZZZZZZZ; - state <= STATE_IDLE; - // mask possible refresh to reduce colliding. - if(refresh_count > cycles_per_refresh) begin - //------------------------------------------------------------------------ - //-- Start the refresh cycle. - //-- This tasks tRFC (66ns), so 2 idle cycles are needed @ 36MHz - //------------------------------------------------------------------------ - state <= STATE_IDLE_2; - command <= CMD_AUTO_REFRESH; - refresh_count <= refresh_count - cycles_per_refresh + 1'd1; - end - end - - STATE_IDLE: begin - // Priority is to issue a refresh if one is outstanding - if(refresh_count > (cycles_per_refresh<<1)) state <= STATE_IDLE_1; - else if(new_rd | new_we) begin - new_we <= 0; - new_rd <= 0; - save_addr<= addr; - save_we <= new_we; - state <= STATE_OPEN_1; - command <= CMD_ACTIVE; - SDRAM_A <= addr[13:1]; - SDRAM_BA <= addr[24:23]; - end - end - - // ACTIVE-to-READ or WRITE delay >20ns (1 cycle @ 36 MHz)(-75) - STATE_OPEN_1: begin - SDRAM_A <= {4'b0010, save_addr[22:14]}; - SDRAM_DQML <= save_we & (new_wtbt ? ~new_wtbt[0] : save_addr[0]); - SDRAM_DQMH <= save_we & (new_wtbt ? ~new_wtbt[1] : ~save_addr[0]); - state <= save_we ? STATE_WRITE : STATE_READ; - end - - STATE_READ: begin - state <= STATE_IDLE_5; - command <= CMD_READ; - SDRAM_DQ <= 16'bZZZZZZZZZZZZZZZZ; - - // Schedule reading the data values off the bus - data_ready_delay[CAS_LATENCY] <= 1; - end - - STATE_WRITE: begin - state <= STATE_IDLE_5; - command <= CMD_WRITE; - SDRAM_DQ <= new_wtbt ? new_data : {new_data[7:0], new_data[7:0]}; - ready <= 1; - end - endcase + // permanently latch ram data to reduce delays + SDRAM_DQ <= 16'bZZZZZZZZZZZZZZZZ; + { SDRAM_DQMH, SDRAM_DQML } <= 2'b11; + sd_cmd <= CMD_NOP; // default: idle + refresh_cnt <= refresh_cnt + 1'd1; if(init) begin - state <= STATE_STARTUP; - refresh_count <= startup_refresh_max - sdram_startup_cycles; + // 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]; + { oe_latch[0], we_latch[0] } <= 2'b00; + 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]; + { oe_latch[0], we_latch[0] } <= { ~port1_we, port1_we }; + ds[0] <= port1_ds; + din_latch[0] <= port1_d; + end + 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; + 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]; + { oe_latch[1], we_latch[1] } <= { ~port1_we, port1_we }; + ds[1] <= port2_ds; + din_latch[1] <= port2_d; + 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 + port1_q <= SDRAM_DQ; + port1_ack <= port1_req; + end + if(t == STATE_READ1 && oe_latch[1]) begin + port2_q <= SDRAM_DQ; + port2_ack <= port2_req; + end end - - old_we <= we; - old_rd <= rd; - if(we & ~old_we) {ready, new_we, new_data, new_wtbt} <= {1'b0, 1'b1, din, wtbt}; - else - if((rd & ~old_rd) || (rd & old_rd & (save_addr != addr))) {ready, new_rd} <= {1'b0, 1'b1}; - end endmodule