diff --git a/cMIPS/bin/build.sh b/cMIPS/bin/build.sh index d372760297fd6d9cc3f2fa1598419f88ccb08fc8..8b766acb3b22e622219a41dcb6650a876bb28d46 100755 --- a/cMIPS/bin/build.sh +++ b/cMIPS/bin/build.sh @@ -66,7 +66,7 @@ simulator=tb_cmips pkg="packageWires.vhd packageMemory.vhd packageExcp.vhd" -src="aux.vhd altera.vhd macnica.vhd memory.vhd cache.vhd instrcache.vhd ram.vhd rom.vhd units.vhd io.vhd uart.vhd fpu.vhd pipestages.vhd exception.vhd core.vhd tb_cMIPS.vhd" +src="aux.vhd altera.vhd macnica.vhd memory.vhd cache.vhd instrcache.vhd sdram.vhd ram.vhd rom.vhd units.vhd io.vhd uart.vhd fpu.vhd pipestages.vhd exception.vhd core.vhd tb_cMIPS.vhd" # build simulator #ghdl --clean diff --git a/cMIPS/vhdl/sdram.vhd b/cMIPS/vhdl/sdram.vhd index 0e0ec2fa1cc9b24695e74e816fe7367ce1372952..f768f41bfa8ff321153e837ea5c4b9da5cdb933d 100644 --- a/cMIPS/vhdl/sdram.vhd +++ b/cMIPS/vhdl/sdram.vhd @@ -33,12 +33,12 @@ use work.p_wires.all; use work.p_memory.all; entity SDRAM_controller is - port (rst : in std_logic; -- FPGA reset - clk : in std_logic; -- 100MHz clock + port (rst : in std_logic; -- FPGA reset (=0) + clk2x : in std_logic; -- 100MHz clock - hcs : in std_logic; -- host side chip select - rdy : in std_logic; -- tell CPU to wait - wr : in std_logic; -- host side write enable + hcs : in std_logic; -- host side chip select (=0) + rdy : in std_logic; -- tell CPU to wait (=0) + wr : in std_logic; -- host side write enable (=0) bsel : in reg4; -- byte select haddr : in reg26; -- host side address hDinp : in reg32; -- host side data input @@ -54,16 +54,60 @@ entity SDRAM_controller is ba0 : out std_logic; -- ram side bank select 0 ba1 : out std_logic; -- ram side bank select 1 saddr : out reg12; -- ram side address - sdata :inout reg16); -- ram side data + sdata : inout reg16); -- ram side data - type sdram_cmd is (cmd_NOP, cmd_PALL, cmd_ARF, cmd_LMR, cmd_ACT, - cmd_RD, cmd_WR, cmd_invalid); + constant REFRESH_doit : integer := 704; -- force a refresh every 704 cycles + + subtype cmd_index is integer range 0 to 13; -end entity SDRAM_controller; + constant cDSL : cmd_index := 0; + constant cNOP : cmd_index := 1; + constant cBST : cmd_index := 2; + constant cRD : cmd_index := 3; + constant cRDA : cmd_index := 4; + constant cWR : cmd_index := 5; + constant cWRA : cmd_index := 6; + constant cACT : cmd_index := 7; + constant cPRE : cmd_index := 8; + constant cPALL : cmd_index := 9; + constant cREF : cmd_index := 10; + constant cSELF : cmd_index := 11; + constant cMRS : cmd_index := 12; + constant cinv : cmd_index := 13; + + type t_cmd_type is record + cmd: cmd_index; + cs: std_logic; + ras: std_logic; + cas: std_logic; + we: std_logic; + a10: std_logic; + end record; + type t_cmd_mem is array (0 to 12) of t_cmd_type; + + +end entity SDRAM_controller; architecture simple of SDRAM_controller is + constant cmd_table : t_cmd_mem := ( -- page 9 + -- cmd cs ras cas we a10 + (cDSL, '1','1','1','1','1'), -- DESL device deselect + (cNOP, '0','1','1','1','1'), -- NOP no operation + (cBST, '0','1','1','0','1'), -- BST burst stop + (cRD, '0','1','0','1','0'), -- RD read + (cRDA, '0','1','0','1','1'), -- RDA read with auto precharge + (cWR, '0','1','0','0','0'), -- WR write + (cWRA, '0','1','0','0','1'), -- WR write with auto precharge + (cACT, '0','0','1','1','1'), -- ACT bank activate + (cPRE, '0','0','1','0','0'), -- PRE precharge selected bank + (cPALL,'0','0','1','0','1'), -- PALL precharge all banks + (cREF, '0','0','0','1','1'), -- REF CBR auto-refresh + (cSELF,'0','0','0','1','1'), -- SELF self-refresh + (cMRS, '0','0','0','0','0') -- MRS mode register set +); + component registerN is generic (NUM_BITS: integer; INIT_VAL: std_logic_vector); port(clk, rst, ld: in std_logic; @@ -71,52 +115,318 @@ architecture simple of SDRAM_controller is Q: out std_logic_vector); end component registerN; - signal reset_done, same_row : boolean := FALSE; + -- state machine + type ctrl_state is + (st_noreset, -- 0 + st_in0, st_in1, st_ipre, st_in2, -- 4 + st_aref1, st_1n0, st_1n1, st_1n2, st_1n3, st_1n4, st_1n5, -- 11 + st_aref2, st_2n0, st_2n1, st_2n2, st_2n3, st_2n4, st_2n5, -- 18 + st_aref3, st_3n0, st_3n1, st_3n2, st_3n3, st_3n4, st_3n5, -- 25 + st_aref4, st_4n0, st_4n1, st_4n2, st_4n3, st_4n4, st_4n5, -- 32 + st_lmr, st_ln0, st_ln1, -- 35 + st_pall, st_pn0, st_pn1, -- 38 + st_refr, st_rn0, st_rn1, st_rn2, st_rn3, st_rn4, st_rn5, -- 45 + st_idle2, -- 46 + st_act, st_an0, st_an1, -- 49 + st_rdcol, st_rdn0, st_rd_done, -- 52 + st_wrcol, -- 53 + st_idle); -- 54 + + signal curr_st, next_st : ctrl_state; + signal ctrl_dbg_st : integer; -- for debugging only + + signal reset_done, same_row, do_refresh, refresh_done : boolean := FALSE; + signal is_accs, is_rd, is_wr : boolean := FALSE; signal addr : reg26; - signal last_row : reg13; + signal row_bits, last_row : reg13; signal col_bits : reg10; signal rwo_bits : reg13; + signal ld_old : std_logic; + signal command : t_cmd_type; + signal doit : cmd_index; begin -- simple - + command <= cmd_table(doit); + scs <= command.cs; + ras <= command.ras; + cas <= command.cas; + we <= command.we; + + saddr(10) <= addr(10) when command.cmd = cACT else + command.a10; + U_address: registerN generic map (26, b"00"&x"000000") - port map (clk, rst, hcs, haddr, addr); + port map (clk2x, rst, hcs, haddr, addr); row_bits <= addr(23 downto 11); col_bits <= addr(10 downto 1); ba0 <= addr(24); ba1 <= addr(25); + - U_last_row: registerN generic map (13, '0'&x"000") - port map (clk, rst, active, haddr(23 downto 11), last_row); + ld_old <= hcs and not(BOOL2SL(same_row)); + U_last_row: registerN generic map (13, '1'&x"fff") + port map (clk2x, rst, ld_old, haddr(23 downto 11), last_row); + same_row <= (last_row = row_bits) and (command.cmd /= cPALL); + + -- this state machine contols the SDRAM interface ----------------------- + U_CTRL_st_reg: process(rst,clk2x) + begin + if rst = '0' then + curr_st <= st_noreset; + elsif rising_edge(clk2x) then + curr_st <= next_st; + end if; + end process U_CTRL_st_reg; ---------------------------------------------- + + ctrl_dbg_st <= integer(ctrl_state'pos(curr_st)); -- for debugging + + + U_CTRL_st_transitions: process(curr_st, reset_done, do_refresh, ------- + same_row, is_accs, is_rd, is_wr) + begin + case curr_st is + + -- WAIT FOR POWER-ON RESET TO COMPLETE + when st_noreset => -- 0 + if reset_done then + next_st <= st_in0; + else + next_st <= st_noreset; + end if; + -- INITIALIZATION SEQUENCE + when st_in0 => -- 1 nop + next_st <= st_in1; + when st_in1 => -- 2 nop + next_st <= st_ipre; + when st_ipre => -- 3 precharge all banks + next_st <= st_in2; + when st_in2 => -- 4 nop + next_st <= st_aref1; + when st_aref1 => -- 5 auto refresh 1 + 60ns delay + next_st <= st_1n0; + when st_1n0 => -- 6 nop + next_st <= st_1n1; + when st_1n1 => -- 7 nop + next_st <= st_1n2; + when st_1n2 => -- 8 nop + next_st <= st_1n3; + when st_1n3 => -- 9 nop + next_st <= st_1n4; + when st_1n4 => -- 10 nop + next_st <= st_1n5; + when st_1n5 => -- 11 nop + next_st <= st_aref2; + + when st_aref2 => -- 12 auto refresh 2 + 60ns delay + next_st <= st_2n0; + when st_2n0 => -- 13 nop + next_st <= st_2n1; + when st_2n1 => -- 14 nop + next_st <= st_2n2; + when st_2n2 => -- 15 nop + next_st <= st_2n3; + when st_2n3 => -- 16 nop + next_st <= st_2n4; + when st_2n4 => -- 17 nop + next_st <= st_2n5; + when st_2n5 => -- 18 nop + next_st <= st_aref3; + + when st_aref3 => -- 19 auto refresh 3 + 60ns delay + next_st <= st_3n0; + when st_3n0 => -- 20 nop + next_st <= st_3n1; + when st_3n1 => -- 21 nop + next_st <= st_3n2; + when st_3n2 => -- 22 nop + next_st <= st_3n3; + when st_3n3 => -- 23 nop + next_st <= st_3n4; + when st_3n4 => -- 24 nop + next_st <= st_3n5; + when st_3n5 => -- 25 nop + next_st <= st_aref4; + + when st_aref4 => -- 26 auto refresh 4 + 60ns delay + next_st <= st_4n0; + when st_4n0 => -- 27 nop + next_st <= st_4n1; + when st_4n1 => -- 28 nop + next_st <= st_4n2; + when st_4n2 => -- 29 nop + next_st <= st_4n3; + when st_4n3 => -- 30 nop + next_st <= st_4n4; + when st_4n4 => -- 31 nop + next_st <= st_4n5; + when st_4n5 => -- 32 nop + next_st <= st_lmr; + + when st_lmr => -- 33 load mode register + 2 nops + next_st <= st_ln0; + when st_ln0 => -- 34 nop + next_st <= st_ln1; + when st_ln1 => -- 35 nop + next_st <= st_idle; + -- AUTO-REFRESH SEQUENCE + when st_pall => -- 36 precharge all banks + 2 nops + next_st <= st_pn0; + when st_pn0 => -- 37 nop + next_st <= st_pn1; + when st_pn1 => -- 38 nop + next_st <= st_refr; + + when st_refr => -- 39 auto refresh + 60ns delay + next_st <= st_rn0; + when st_rn0 => -- 40 nop + next_st <= st_rn1; + when st_rn1 => -- 41 nop + next_st <= st_rn2; + when st_rn2 => -- 42 nop + next_st <= st_rn3; + when st_rn3 => -- 43 nop + next_st <= st_rn4; + when st_rn4 => -- 44 nop + next_st <= st_rn5; + when st_rn5 => -- 45 nop; sameRow was cleared + next_st <= st_idle2; + + when st_idle2 => -- 46 + if is_accs then -- is post-refresh access, activate row + next_st <= st_act; + else + next_st <= st_idle2; + end if; + + -- ACTIVATE NEW ROW + when st_act => -- 47 activate row + 2 nops + next_st <= st_an0; + when st_an0 => -- 48 nop + next_st <= st_an1; + when st_an1 => -- 49 nop + if is_rd then + next_st <= st_rdcol; -- access is a read, set column + else + next_st <= st_wrcol; -- access is a write, set column + end if; + + -- READ FROM COLUMN + when st_rdcol => -- 50 set column for RD + 2 nops + next_st <= st_rdn0; + when st_rdn0 => -- 51 nop + next_st <= st_rd_done; + when st_rd_done => -- 52 nop + if do_refresh then + next_st <= st_pall; -- go to refresh sequence + else + next_st <= st_idle; -- wait for next access to same row + end if; + + -- WRITE TO COLUMN + when st_wrcol => -- 53 set column for WR + if do_refresh then + next_st <= st_pall; -- go to refresh sequence + else + next_st <= st_idle; -- wait for next access to same row + end if; + + when st_idle => -- 54 + if is_accs and not(same_row) then + next_st <= st_act; + elsif is_rd then + next_st <= st_rdcol; + elsif is_wr then + next_st <= st_rdcol; + else + next_st <= st_idle; + end if; + when others => + assert false report "CTRL stateMachine broken" + & integer'image(ctrl_state'pos(curr_st)) severity failure; + end case; + end process U_CTRL_st_transitions; ------------------------------------ + U_CTRL_outputs: process(curr_st) ------------------------------ + begin + case curr_st is + when st_rdcol => + doit <= cRD; -- read from column + + when st_wrcol => + doit <= cWR; -- write to column + + when st_ipre | st_pall => + doit <= cPALL; -- precharge all banks - -- purpose: wait for 100us after reset - U_rst_100us: process (clk2x,rst) - variable cnt : integer := 0; - begin -- process clk2x + when st_aref1 | st_aref2 | st_aref3 | st_aref4 => + doit <= cREF; -- auto-refresh + + when st_lmr => + doit <= cMRS; -- load mode register + + when st_act => + doit <= cACT; -- activate row + + when others => + doit <= cNOP; + end case; + end process U_CTRL_outputs; ------------------------------------------- + + + + + + + -- do a refresh in less than 7,8us (8192 in 64ms @ 100MHz) + U_do_refresh: process (rst, clk2x, refresh_done) + variable cnt : integer range 0 to 1023:= 0; + begin if rst = '0' then + do_refresh <= FALSE; cnt := 0; - reset_done <= FALSE; - elsif rising_edge(clk) then - cnt := cnt + 1; - if cnt = 10000 then -- 100us elapsed - reset_done <= TRUE; - wait; + elsif rising_edge(clk2x) then + if cnt > REFRESH_doit then + if refresh_done then + do_refresh <= FALSE; + cnt := 0; + else + do_refresh <= TRUE; -- add some hysteresis + cnt := cnt + 1; -- to accomodate slow commands + end if; + else + do_refresh <= FALSE; + cnt := cnt + 1; end if; end if; - end process clk2x; + end process U_do_refresh; + + + -- do wait for 100us after reset + U_rst_100us: process + variable cnt : integer range 0 to 16383:= 0; + begin -- process clk2x + reset_done <= FALSE; + wait until rst = '1'; + cnt := 0; + wait until rising_edge(clk2x); + cnt := cnt + 1; + if cnt = 10000 then -- 100us elapsed + reset_done <= TRUE; + wait; + end if; + end process U_rst_100us; end simple; - +-- --------------------------------------------------------------------- diff --git a/cMIPS/vhdl/tb_cMIPS.vhd b/cMIPS/vhdl/tb_cMIPS.vhd index 982bacb25a4a871e5da62e99f2ff13090fb3649f..6f1919f8c8057eceaae2ff01f0fe66a3f4618f85 100644 --- a/cMIPS/vhdl/tb_cMIPS.vhd +++ b/cMIPS/vhdl/tb_cMIPS.vhd @@ -287,6 +287,29 @@ architecture TB of tb_cMIPS is dump_ram : in std_logic); end component fpga_RAM; + component SDRAM_controller is + port (rst : in std_logic; -- FPGA reset (=0) + clk2x : in std_logic; -- 100MHz clock + hcs : in std_logic; -- host side chip select (=0) + rdy : in std_logic; -- tell CPU to wait (=0) + wr : in std_logic; -- host side write enable (=0) + bsel : in reg4; -- byte select + haddr : in reg26; -- host side address + hDinp : in reg32; -- host side data input + hDout : out reg32; -- host side data output + cke : out std_logic; -- ram side clock enable + scs : out std_logic; -- ram side chip select + ras : out std_logic; -- ram side RAS + cas : out std_logic; -- ram side CAS + we : out std_logic; -- ram side write enable + dqm0 : out std_logic; -- ram side byte0 output enable + dqm1 : out std_logic; -- ram side byte0 output enable + ba0 : out std_logic; -- ram side bank select 0 + ba1 : out std_logic; -- ram side bank select 1 + saddr : out reg12; -- ram side address + sdata : inout reg16); -- ram side data + end component SDRAM_controller; + component fake_I_CACHE is port (rst : in std_logic; clk4x : in std_logic; @@ -477,6 +500,27 @@ architecture TB of tb_cMIPS is signal LCD_DATA : std_logic_vector(7 downto 0); -- LCD data bus signal LCD_RS, LCD_RW, LCD_EN, LCD_BLON : std_logic; -- LCD control signal uart_txd, uart_rxd, uart_rts, uart_cts, uart_irq : std_logic; + + + signal hcs : std_logic; -- host side chip select (=0) + signal sdram_rdy : std_logic; -- host side chip select (=0) + signal haddr : reg26; -- host side address + signal hDinp : reg32; -- host side data input + signal hDout : reg32; -- host side data output + signal sdcke : std_logic; -- ram side clock enable + signal sdscs : std_logic; -- ram side chip select + signal sdras : std_logic; -- ram side RAS + signal sdcas : std_logic; -- ram side CAS + signal sdwe : std_logic; -- ram side write enable + signal sddqm0 : std_logic; -- ram side byte0 output enable + signal sddqm1 : std_logic; -- ram side byte0 output enable + signal sdba0 : std_logic; -- ram side bank select 0 + signal sdba1 : std_logic; -- ram side bank select 1 + signal sdaddr : reg12; -- ram side address + signal sddata : reg16; -- ram side data + + + begin -- TB @@ -587,6 +631,10 @@ begin -- TB mem_addr, datram_out, datram_inp, mem_xfer, dump_ram); + U_SDRAM_controller : SDRAM_controller port map + (rst, clk,hcs,sdram_rdy,wr,cpu_xfer,haddr,hDinp,hDout, + sdcke,sdscs,sdras,sdcas,sdwe,sddqm0,sddqm1,sdba0,sdba1,sdaddr,sddata); + U_to_stdout: to_stdout port map (rst,clk, io_stdout_sel, wr, cpu_data);