📄 sdramcntl.vhd
字号:
-- this insures the clock is stable before enabling the SDRAM
-- it also insures a clean startup if the SDRAM is currently in self-refresh mode
cke_x <= NO;
end if;
status <= "0001";
-----------------------------------------------------------
-- precharge all SDRAM banks after power-on initialization
-----------------------------------------------------------
when INITPCHG =>
cmd_x <= PCHG_CMD;
sAddr_x(CMDBIT_POS) <= ALL_BANKS; -- precharge all banks
timer_x <= RP_CYCLES; -- set timer for precharge operation duration
rfshCntr_x <= RFSH_OPS; -- set counter for refresh ops needed after precharge
state_x <= INITRFSH;
status <= "0010";
-----------------------------------------------------------
-- refresh the SDRAM a number of times after initial precharge
-----------------------------------------------------------
when INITRFSH =>
cmd_x <= RFSH_CMD;
timer_x <= RFC_CYCLES; -- set timer to refresh operation duration
rfshCntr_x <= rfshCntr_r - 1; -- decrement refresh operation counter
if rfshCntr_r = 1 then
state_x <= INITSETMODE; -- set the SDRAM mode once all refresh ops are done
end if;
status <= "0011";
-----------------------------------------------------------
-- set the mode register of the SDRAM
-----------------------------------------------------------
when INITSETMODE =>
cmd_x <= MODE_CMD;
sAddr_x <= (others=>'0'); sAddr_x(MODE'range) <= MODE; -- output mode register bits on the SDRAM address bits timer_x <= MODE_CYCLES; -- set timer for mode setting operation duration
state_x <= RW;
status <= "0100";
-----------------------------------------------------------
-- process read/write/refresh operations after initialization is done
-----------------------------------------------------------
when RW =>
-----------------------------------------------------------
-- highest priority operation: row refresh
-- do a refresh operation if the refresh counter is non-zero
-----------------------------------------------------------
if rfshCntr_r /= 0 then
-- wait for any row activations, writes or reads to finish before doing a precharge
if (activateInProgress = NO) and (wrInProgress = NO) and (rdInProgress = NO) then
cmd_x <= PCHG_CMD; -- initiate precharge of the SDRAM
sAddr_x(CMDBIT_POS) <= ALL_BANKS; -- precharge all banks
timer_x <= RP_CYCLES; -- set timer for this operation
activeFlag_x <= (others => NO); -- all rows are inactive after a precharge operation
state_x <= REFRESHROW; -- refresh the SDRAM after the precharge
end if;
status <= "0101";
-----------------------------------------------------------
-- do a host-initiated read operation
-----------------------------------------------------------
elsif rd = YES then
-- Wait one clock cycle if the bank address has just changed and each bank has its own active row.
-- This gives extra time for the row activation circuitry.
if (ba_x = ba_r) or (MULTIPLE_ACTIVE_ROWS = false) then
-- activate a new row if the current read is outside the active row or bank
if doActivate = YES then
-- activate new row only if all previous activations, writes, reads are done
if (activateInProgress = NO) and (wrInProgress = NO) and (rdInProgress = NO) then
cmd_x <= PCHG_CMD; -- initiate precharge of the SDRAM
sAddr_x(CMDBIT_POS) <= ONE_BANK; -- precharge this bank
timer_x <= RP_CYCLES; -- set timer for this operation
activeFlag_x(bankIndex) <= NO; -- rows in this bank are inactive after a precharge operation
state_x <= ACTIVATE; -- activate the new row after the precharge is done
end if;
-- read from the currently active row if no previous read operation
-- is in progress or if pipeline reads are enabled
-- we can always initiate a read even if a write is already in progress
elsif (rdInProgress = NO) or PIPE_EN then
cmd_x <= READ_CMD; -- initiate a read of the SDRAM
-- insert a flag into the pipeline shift register that will exit the end
-- of the shift register when the data from the SDRAM is available
rdPipeline_x <= READ & rdPipeline_r(rdPipeline_r'high downto 1);
opBegun_x <= YES; -- tell the host the requested operation has begun
end if;
end if;
status <= "0110";
-----------------------------------------------------------
-- do a host-initiated write operation
-----------------------------------------------------------
elsif wr = YES then
-- Wait one clock cycle if the bank address has just changed and each bank has its own active row.
-- This gives extra time for the row activation circuitry.
if (ba_x = ba_r) or (MULTIPLE_ACTIVE_ROWS = false) then
-- activate a new row if the current write is outside the active row or bank
if doActivate = YES then
-- activate new row only if all previous activations, writes, reads are done
if (activateInProgress = NO) and (wrInProgress = NO) and (rdInProgress = NO) then
cmd_x <= PCHG_CMD; -- initiate precharge of the SDRAM
sAddr_x(CMDBIT_POS) <= ONE_BANK; -- precharge this bank
timer_x <= RP_CYCLES; -- set timer for this operation
activeFlag_x(bankIndex) <= NO; -- rows in this bank are inactive after a precharge operation
state_x <= ACTIVATE; -- activate the new row after the precharge is done
end if;
-- write to the currently active row if no previous read operations are in progress
elsif rdInProgress = NO then
cmd_x <= WRITE_CMD; -- initiate the write operation
sDataDir_x <= OUTPUT; -- turn on drivers to send data to SDRAM
-- set timer so precharge doesn't occur too soon after write operation
wrTimer_x <= WR_CYCLES;
-- insert a flag into the 1-bit pipeline shift register that will exit on the
-- next cycle. The write into SDRAM is not actually done by that time, but
-- this doesn't matter to the host
wrPipeline_x(0) <= WRITE;
opBegun_x <= YES; -- tell the host the requested operation has begun
end if;
end if;
status <= "0111";
-----------------------------------------------------------
-- do a host-initiated self-refresh operation
-----------------------------------------------------------
elsif doSelfRfsh = YES then
-- wait until all previous activations, writes, reads are done
if (activateInProgress = NO) and (wrInProgress = NO) and (rdInProgress = NO) then
cmd_x <= PCHG_CMD; -- initiate precharge of the SDRAM
sAddr_x(CMDBIT_POS) <= ALL_BANKS; -- precharge all banks
timer_x <= RP_CYCLES; -- set timer for this operation
activeFlag_x <= (others => NO); -- all rows are inactive after a precharge operation
state_x <= SELFREFRESH; -- self-refresh the SDRAM after the precharge
end if;
status <= "1000";
-----------------------------------------------------------
-- no operation
-----------------------------------------------------------
else
state_x <= RW; -- continue to look for SDRAM operations to execute
status <= "1001";
end if;
-----------------------------------------------------------
-- activate a row of the SDRAM
-----------------------------------------------------------
when ACTIVATE =>
cmd_x <= ACTIVE_CMD;
sAddr_x <= (others => '0'); -- output the address for the row to be activated
sAddr_x(row'range) <= row;
activeBank_x <= bank;
activeRow_x(bankIndex) <= row; -- store the new active SDRAM row address
activeFlag_x(bankIndex) <= YES; -- the SDRAM is now active
rasTimer_x <= RAS_CYCLES; -- minimum time before another precharge can occur
timer_x <= RCD_CYCLES; -- minimum time before a read/write operation can occur
state_x <= RW; -- return to do read/write operation that initiated this activation
status <= "1010";
-----------------------------------------------------------
-- refresh a row of the SDRAM
-----------------------------------------------------------
when REFRESHROW =>
cmd_x <= RFSH_CMD;
timer_x <= RFC_CYCLES; -- refresh operation interval
rfshCntr_x <= rfshCntr_r - 1; -- decrement the number of needed row refreshes
state_x <= RW; -- process more SDRAM operations after refresh is done
status <= "1011";
-----------------------------------------------------------
-- place the SDRAM into self-refresh and keep it there until further notice
-----------------------------------------------------------
when SELFREFRESH =>
if (doSelfRfsh = YES) or (lock = NO) then
-- keep the SDRAM in self-refresh mode as long as requested and until there is a stable clock
cmd_x <= RFSH_CMD; -- output the refresh command; this is only needed on the first clock cycle
cke_x <= NO; -- disable the SDRAM clock
else
-- else exit self-refresh mode and start processing read and write operations
cke_x <= YES; -- restart the SDRAM clock
rfshCntr_x <= 0; -- no refreshes are needed immediately after leaving self-refresh
activeFlag_x <= (others => NO); -- self-refresh deactivates all rows
timer_x <= XSR_CYCLES; -- wait this long until read and write operations can resume
state_x <= RW;
end if;
status <= "1100";
-----------------------------------------------------------
-- unknown state
-----------------------------------------------------------
when others =>
state_x <= INITWAIT; -- reset state if in erroneous state
status <= "1101";
end case;
end if;
end process combinatorial;
-----------------------------------------------------------
-- update registers on the appropriate clock edge
-----------------------------------------------------------
update : process(rst, clk)
begin
if rst = YES then
-- asynchronous reset
state_r <= INITWAIT;
activeFlag_r <= (others => NO);
rfshCntr_r <= 0;
timer_r <= 0;
refTimer_r <= REF_CYCLES;
rasTimer_r <= 0;
wrTimer_r <= 0;
nopCntr_r <= 0;
opBegun_r <= NO;
rdPipeline_r <= (others => '0');
wrPipeline_r <= (others => '0');
cke_r <= NO;
cmd_r <= NOP_CMD;
ba_r <= (others => '0');
sAddr_r <= (others => '0');
sData_r <= (others => '0');
sDataDir_r <= INPUT;
hDOut_r <= (others => '0');
elsif rising_edge(clk) then
state_r <= state_x;
activeBank_r <= activeBank_x;
activeRow_r <= activeRow_x;
activeFlag_r <= activeFlag_x;
rfshCntr_r <= rfshCntr_x;
timer_r <= timer_x;
refTimer_r <= refTimer_x;
rasTimer_r <= rasTimer_x;
wrTimer_r <= wrTimer_x;
nopCntr_r <= nopCntr_x;
opBegun_r <= opBegun_x;
rdPipeline_r <= rdPipeline_x;
wrPipeline_r <= wrPipeline_x;
cke_r <= cke_x;
cmd_r <= cmd_x;
ba_r <= ba_x;
sAddr_r <= sAddr_x;
sData_r <= sData_x;
sDataDir_r <= sDataDir_x;
hDOut_r <= hDOut_x;
end if;
-- the register that gets data from the SDRAM and holds it for the host
-- is clocked on the opposite edge. We don't use this register if IN_PHASE=TRUE.
if rst = YES then
hDOutOppPhase_r <= (others => '0');
elsif falling_edge(clk) then
hDOutOppPhase_r <= hDOutOppPhase_x;
end if;
end process update;
end arch;
--------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -