Hardware Design: SIE
Sign in or create your account | Project List | Help
Hardware Design: SIE Git Source Tree
Root/
| 1 | --------------------------------------------------------------------- |
| 2 | -- TITLE: DDR SDRAM Interface |
| 3 | -- AUTHORS: Steve Rhoads (rhoadss@yahoo.com) |
| 4 | -- DATE CREATED: 7/26/07 |
| 5 | -- FILENAME: ddr_ctrl.vhd |
| 6 | -- PROJECT: Plasma CPU core |
| 7 | -- COPYRIGHT: Software placed into the public domain by the author. |
| 8 | -- Software 'as is' without warranty. Author liable for nothing. |
| 9 | -- DESCRIPTION: |
| 10 | -- Double Data Rate Sychronous Dynamic Random Access Memory Interface |
| 11 | -- |
| 12 | -- For: 64 MB = MT46V32M16, 512Mb, 32Mb x 16 (default) |
| 13 | -- ROW = address(25 downto 13) |
| 14 | -- BANK = address(12 downto 11) |
| 15 | -- COL = address(10 downto 2) |
| 16 | -- |
| 17 | -- Changes are needed for 32 MB = MT46V16M16, 256Mb, 16Mb x 16 |
| 18 | -- ROW = address(24 downto 12) -- 25 ignored |
| 19 | -- BANK = address(11 downto 10) |
| 20 | -- COL = address(9 downto 2) --also change ddr_init.c |
| 21 | -- |
| 22 | -- Changes are needed for 128 MB = MT46V64M16, 1Gb, 64Mb x 16 |
| 23 | -- ROW = address(26 downto 14) |
| 24 | -- BANK = address(13 downto 12) |
| 25 | -- COL = address(11 downto 2) --also change ddr_init.c |
| 26 | -- |
| 27 | -- Requires CAS latency=2; burst size=2. |
| 28 | -- Requires clk changes on rising_edge(clk_2x). |
| 29 | -- Requires active, address, byte_we, data_w stable throughout transfer. |
| 30 | -- DLL mode requires 77MHz. Non-DLL mode runs at 25 MHz. |
| 31 | -- |
| 32 | -- cycle_cnt 777777770000111122223333444455556666777777777777 |
| 33 | -- clk_2x --__--__--__--__--__--__--__--__--__--__--__--__ |
| 34 | -- clk ____----____----____----____----____----____---- |
| 35 | -- SD_CLK ----____----____----____----____----____----____ |
| 36 | -- cmd ____write+++WRITE+++____________________________ |
| 37 | -- SD_DQ ~~~~~~~~~~~~~~uuuullllUUUULLLL~~~~~~~~~~~~~~~~~~ |
| 38 | -- |
| 39 | -- cycle_cnt 777777770000111122223333444455556666777777777777 |
| 40 | -- clk_2x --__--__--__--__--__--__--__--__--__--__--__--__ |
| 41 | -- clk ____----____----____----____----____----____---- |
| 42 | -- SD_CLK ----____----____----____----____----____----____ |
| 43 | -- cmd ____read++++________________________read++++____ |
| 44 | -- SD_DQ ~~~~~~~~~~~~~~~~~~~~~~~~uuuullll~~~~~~~~~~~~~~~~ |
| 45 | -- SD_DQnDLL ~~~~~~~~~~~~~~~~~~~~~~~~~~uuuullll~~~~~~~~~~~~~~ |
| 46 | -- pause ____------------------------________------------ |
| 47 | -- |
| 48 | -- Must run DdrInit() to initialize DDR chip. |
| 49 | -- Read Micron DDR SDRAM MT46V32M16 data sheet for more details. |
| 50 | --------------------------------------------------------------------- |
| 51 | library ieee; |
| 52 | use ieee.std_logic_1164.all; |
| 53 | use ieee.std_logic_unsigned.all; |
| 54 | use ieee.std_logic_arith.all; |
| 55 | use work.mlite_pack.all; |
| 56 | |
| 57 | entity ddr_ctrl is |
| 58 | port( |
| 59 | clk : in std_logic; |
| 60 | clk_2x : in std_logic; |
| 61 | reset_in : in std_logic; |
| 62 | |
| 63 | address : in std_logic_vector(25 downto 2); |
| 64 | byte_we : in std_logic_vector(3 downto 0); |
| 65 | data_w : in std_logic_vector(31 downto 0); |
| 66 | data_r : out std_logic_vector(31 downto 0); |
| 67 | active : in std_logic; |
| 68 | no_start : in std_logic; |
| 69 | no_stop : in std_logic; |
| 70 | pause : out std_logic; |
| 71 | |
| 72 | SD_CK_P : out std_logic; --clock_positive |
| 73 | SD_CK_N : out std_logic; --clock_negative |
| 74 | SD_CKE : out std_logic; --clock_enable |
| 75 | |
| 76 | SD_BA : out std_logic_vector(1 downto 0); --bank_address |
| 77 | SD_A : out std_logic_vector(12 downto 0); --address(row or col) |
| 78 | SD_CS : out std_logic; --chip_select |
| 79 | SD_RAS : out std_logic; --row_address_strobe |
| 80 | SD_CAS : out std_logic; --column_address_strobe |
| 81 | SD_WE : out std_logic; --write_enable |
| 82 | |
| 83 | SD_DQ : inout std_logic_vector(15 downto 0); --data |
| 84 | SD_UDM : out std_logic; --upper_byte_enable |
| 85 | SD_UDQS : inout std_logic; --upper_data_strobe |
| 86 | SD_LDM : out std_logic; --low_byte_enable |
| 87 | SD_LDQS : inout std_logic); --low_data_strobe |
| 88 | end; --entity ddr |
| 89 | |
| 90 | architecture logic of ddr_ctrl is |
| 91 | |
| 92 | --Commands for bits RAS & CAS & WE |
| 93 | subtype command_type is std_logic_vector(2 downto 0); |
| 94 | constant COMMAND_LMR : command_type := "000"; |
| 95 | constant COMMAND_AUTO_REFRESH : command_type := "001"; |
| 96 | constant COMMAND_PRECHARGE : command_type := "010"; |
| 97 | constant COMMAND_ACTIVE : command_type := "011"; |
| 98 | constant COMMAND_WRITE : command_type := "100"; |
| 99 | constant COMMAND_READ : command_type := "101"; |
| 100 | constant COMMAND_TERMINATE : command_type := "110"; |
| 101 | constant COMMAND_NOP : command_type := "111"; |
| 102 | |
| 103 | subtype ddr_state_type is std_logic_vector(3 downto 0); |
| 104 | constant STATE_POWER_ON : ddr_state_type := "0000"; |
| 105 | constant STATE_IDLE : ddr_state_type := "0001"; |
| 106 | constant STATE_ROW_ACTIVATE : ddr_state_type := "0010"; |
| 107 | constant STATE_ROW_ACTIVE : ddr_state_type := "0011"; |
| 108 | constant STATE_READ : ddr_state_type := "0100"; |
| 109 | constant STATE_READ2 : ddr_state_type := "0101"; |
| 110 | constant STATE_READ3 : ddr_state_type := "0110"; |
| 111 | constant STATE_PRECHARGE : ddr_state_type := "0111"; |
| 112 | constant STATE_PRECHARGE2 : ddr_state_type := "1000"; |
| 113 | |
| 114 | signal state_prev : ddr_state_type; |
| 115 | signal refresh_cnt : std_logic_vector(7 downto 0); |
| 116 | signal data_write2 : std_logic_vector(47 downto 0); --write pipeline |
| 117 | signal byte_we_reg2 : std_logic_vector(5 downto 0); --write pipeline |
| 118 | signal write_active : std_logic; |
| 119 | signal write_prev : std_logic; |
| 120 | signal cycle_count : std_logic_vector(2 downto 0); --half clocks since op |
| 121 | signal cycle_count2 : std_logic_vector(2 downto 0); --delayed by quarter clock |
| 122 | signal cke_reg : std_logic; |
| 123 | signal clk_p : std_logic; |
| 124 | signal bank_open : std_logic_vector(3 downto 0); |
| 125 | signal data_read : std_logic_vector(31 downto 0); |
| 126 | |
| 127 | begin |
| 128 | ddr_proc: process(clk, clk_p, clk_2x, reset_in, |
| 129 | address, byte_we, data_w, active, no_start, no_stop, |
| 130 | SD_DQ, SD_UDQS, SD_LDQS, |
| 131 | state_prev, refresh_cnt, |
| 132 | byte_we_reg2, data_write2, |
| 133 | cycle_count, cycle_count2, write_prev, |
| 134 | write_active, cke_reg, bank_open, |
| 135 | data_read) |
| 136 | type address_array_type is array(3 downto 0) of std_logic_vector(12 downto 0); |
| 137 | variable address_row : address_array_type; |
| 138 | variable command : std_logic_vector(2 downto 0); --RAS & CAS & WE |
| 139 | variable bank_index : integer; |
| 140 | variable state_current : ddr_state_type; |
| 141 | |
| 142 | begin |
| 143 | |
| 144 | command := COMMAND_NOP; |
| 145 | bank_index := conv_integer(address(12 downto 11)); |
| 146 | state_current := state_prev; |
| 147 | |
| 148 | --DDR state machine to determine state_current and command |
| 149 | case state_prev is |
| 150 | when STATE_POWER_ON => |
| 151 | if active = '1' then |
| 152 | if byte_we /= "0000" then |
| 153 | command := address(6 downto 4); --LMR="000" |
| 154 | else |
| 155 | state_current := STATE_IDLE; --read transistions to STATE_IDLE |
| 156 | end if; |
| 157 | end if; |
| 158 | |
| 159 | when STATE_IDLE => |
| 160 | if refresh_cnt(7) = '1' then |
| 161 | state_current := STATE_PRECHARGE; |
| 162 | command := COMMAND_AUTO_REFRESH; |
| 163 | elsif active = '1' and no_start = '0' then |
| 164 | state_current := STATE_ROW_ACTIVATE; |
| 165 | command := COMMAND_ACTIVE; |
| 166 | end if; |
| 167 | |
| 168 | when STATE_ROW_ACTIVATE => |
| 169 | state_current := STATE_ROW_ACTIVE; |
| 170 | |
| 171 | when STATE_ROW_ACTIVE => |
| 172 | if refresh_cnt(7) = '1' then |
| 173 | if write_prev = '0' then |
| 174 | state_current := STATE_PRECHARGE; |
| 175 | command := COMMAND_PRECHARGE; |
| 176 | end if; |
| 177 | elsif active = '1' and no_start = '0' then |
| 178 | if bank_open(bank_index) = '0' then |
| 179 | state_current := STATE_ROW_ACTIVATE; |
| 180 | command := COMMAND_ACTIVE; |
| 181 | elsif address(25 downto 13) /= address_row(bank_index) then |
| 182 | if write_prev = '0' then |
| 183 | state_current := STATE_PRECHARGE; |
| 184 | command := COMMAND_PRECHARGE; |
| 185 | end if; |
| 186 | else |
| 187 | if byte_we /= "0000" then |
| 188 | command := COMMAND_WRITE; |
| 189 | elsif write_prev = '0' then |
| 190 | state_current := STATE_READ; |
| 191 | command := COMMAND_READ; |
| 192 | end if; |
| 193 | end if; |
| 194 | end if; |
| 195 | |
| 196 | when STATE_READ => |
| 197 | state_current := STATE_READ2; |
| 198 | |
| 199 | when STATE_READ2 => |
| 200 | state_current := STATE_READ3; |
| 201 | |
| 202 | when STATE_READ3 => |
| 203 | if no_stop = '0' then |
| 204 | state_current := STATE_ROW_ACTIVE; |
| 205 | end if; |
| 206 | |
| 207 | when STATE_PRECHARGE => |
| 208 | state_current := STATE_PRECHARGE2; |
| 209 | |
| 210 | when STATE_PRECHARGE2 => |
| 211 | state_current := STATE_IDLE; |
| 212 | |
| 213 | when others => |
| 214 | state_current := STATE_IDLE; |
| 215 | end case; --state_prev |
| 216 | |
| 217 | --rising_edge(clk) domain registers |
| 218 | if reset_in = '1' then |
| 219 | state_prev <= STATE_POWER_ON; |
| 220 | cke_reg <= '0'; |
| 221 | refresh_cnt <= ZERO(7 downto 0); |
| 222 | write_prev <= '0'; |
| 223 | write_active <= '0'; |
| 224 | bank_open <= "0000"; |
| 225 | elsif rising_edge(clk) then |
| 226 | |
| 227 | if active = '1' then |
| 228 | cke_reg <= '1'; |
| 229 | end if; |
| 230 | |
| 231 | if command = COMMAND_WRITE then |
| 232 | write_prev <= '1'; |
| 233 | elsif cycle_count2(2 downto 1) = "11" then |
| 234 | write_prev <= '0'; |
| 235 | end if; |
| 236 | |
| 237 | if command = COMMAND_WRITE then |
| 238 | write_active <= '1'; |
| 239 | elsif cycle_count2 = "100" then |
| 240 | write_active <= '0'; |
| 241 | end if; |
| 242 | |
| 243 | if command = COMMAND_ACTIVE then |
| 244 | bank_open(bank_index) <= '1'; |
| 245 | address_row(bank_index) := address(25 downto 13); |
| 246 | end if; |
| 247 | |
| 248 | if command = COMMAND_PRECHARGE then |
| 249 | bank_open <= "0000"; |
| 250 | end if; |
| 251 | |
| 252 | if command = COMMAND_AUTO_REFRESH then |
| 253 | refresh_cnt <= ZERO(7 downto 0); |
| 254 | else |
| 255 | refresh_cnt <= refresh_cnt + 1; |
| 256 | end if; |
| 257 | |
| 258 | state_prev <= state_current; |
| 259 | |
| 260 | end if; --rising_edge(clk) |
| 261 | |
| 262 | --rising_edge(clk_2x) domain registers |
| 263 | if reset_in = '1' then |
| 264 | cycle_count <= "000"; |
| 265 | elsif rising_edge(clk_2x) then |
| 266 | --Cycle_count |
| 267 | if (command = COMMAND_READ or command = COMMAND_WRITE) and clk = '1' then |
| 268 | cycle_count <= "000"; |
| 269 | elsif cycle_count /= "111" then |
| 270 | cycle_count <= cycle_count + 1; |
| 271 | end if; |
| 272 | |
| 273 | clk_p <= clk; --earlier version of not clk |
| 274 | |
| 275 | --Read data (DLL disabled) |
| 276 | if cycle_count = "100" then |
| 277 | data_read(31 downto 16) <= SD_DQ; --data |
| 278 | elsif cycle_count = "101" then |
| 279 | data_read(15 downto 0) <= SD_DQ; |
| 280 | end if; |
| 281 | end if; |
| 282 | |
| 283 | --falling_edge(clk_2x) domain registers |
| 284 | if reset_in = '1' then |
| 285 | cycle_count2 <= "000"; |
| 286 | data_write2 <= ZERO(15 downto 0) & ZERO; |
| 287 | byte_we_reg2 <= "000000"; |
| 288 | elsif falling_edge(clk_2x) then |
| 289 | cycle_count2 <= cycle_count; |
| 290 | |
| 291 | --Write pipeline |
| 292 | if clk = '0' then |
| 293 | data_write2 <= data_write2(31 downto 16) & data_w; |
| 294 | byte_we_reg2 <= byte_we_reg2(3 downto 2) & byte_we; |
| 295 | else |
| 296 | data_write2(47 downto 16) <= data_write2(31 downto 0); |
| 297 | byte_we_reg2(5 downto 2) <= byte_we_reg2(3 downto 0); |
| 298 | end if; |
| 299 | |
| 300 | --Read data (DLL enabled) |
| 301 | --if cycle_count = "100" then |
| 302 | -- data_read(31 downto 16) <= SD_DQ; --data |
| 303 | --elsif cycle_count = "101" then |
| 304 | -- data_read(15 downto 0) <= SD_DQ; |
| 305 | --end if; |
| 306 | end if; |
| 307 | |
| 308 | data_r <= data_read; |
| 309 | |
| 310 | --Write data |
| 311 | if write_active = '1' then |
| 312 | SD_UDQS <= clk_p; --upper_data_strobe |
| 313 | SD_LDQS <= clk_p; --low_data_strobe |
| 314 | SD_DQ <= data_write2(47 downto 32); --data |
| 315 | SD_UDM <= not byte_we_reg2(5); --upper_byte_enable |
| 316 | SD_LDM <= not byte_we_reg2(4); --low_byte_enable |
| 317 | else |
| 318 | SD_UDQS <= 'Z'; --upper_data_strobe |
| 319 | SD_LDQS <= 'Z'; --low_data_strobe |
| 320 | SD_DQ <= "ZZZZZZZZZZZZZZZZ"; --data |
| 321 | SD_UDM <= 'Z'; |
| 322 | SD_LDM <= 'Z'; |
| 323 | end if; |
| 324 | |
| 325 | --DDR control signals |
| 326 | SD_CK_P <= clk_p; --clock_positive |
| 327 | SD_CK_N <= not clk_p; --clock_negative |
| 328 | SD_CKE <= cke_reg; --clock_enable |
| 329 | |
| 330 | SD_BA <= address(12 downto 11); --bank_address |
| 331 | if command = COMMAND_ACTIVE or state_current = STATE_POWER_ON then |
| 332 | SD_A <= address(25 downto 13); --address row |
| 333 | elsif command = COMMAND_READ or command = COMMAND_WRITE then |
| 334 | SD_A <= "000" & address(10 downto 2) & "0"; --address col |
| 335 | else |
| 336 | SD_A <= "0010000000000"; --PERCHARGE all banks |
| 337 | end if; |
| 338 | |
| 339 | SD_CS <= not cke_reg; --chip_select |
| 340 | SD_RAS <= command(2); --row_address_strobe |
| 341 | SD_CAS <= command(1); --column_address_strobe |
| 342 | SD_WE <= command(0); --write_enable |
| 343 | |
| 344 | if active = '1' and state_current /= STATE_POWER_ON and |
| 345 | command /= COMMAND_WRITE and state_prev /= STATE_READ3 then |
| 346 | pause <= '1'; |
| 347 | else |
| 348 | pause <= '0'; |
| 349 | end if; |
| 350 | |
| 351 | end process; --ddr_proc |
| 352 | |
| 353 | end; --architecture logic |
| 354 | |
| 355 |
Branches:
master
