3 # SPDX-License-Identifier: LGPLv3+
4 # Copyright (C) 2022 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
5 # Sponsored by NLnet and NGI POINTER under EU Grants 871528 and 957073
6 # Part of the Libre-SOC Project.
8 # this is a wrapper around the opencores verilog uart16550 module
10 from nmigen
import (Elaboratable
, Cat
, Module
, Signal
, ClockSignal
, Instance
,
13 from nmigen_soc
.wishbone
.bus
import Interface
14 from nmigen
.cli
import rtlil
, verilog
17 __all__
= ["SDRAM", "SDRAMConfig"]
20 class SDRAMConfig(Record
):
21 def __init__(self
, refresh_timer_sz
, refresh_row_count
, name
=None):
22 super().__init
__(name
=name
, layout
=[
23 # configuration parameters, these need to match the SDRAM IC datasheet
24 ('req_depth', 2), # max request accepted
25 ('sdr_en', 1), # Enable SDRAM controller
27 ('sdr_tras_d', 4), # Active to precharge delay
28 ('sdr_trp_d', 4), # Precharge to active delay
29 ('sdr_trcd_d', 4), # Active to R/W delay
30 ('sdr_cas', 3), # SDRAM CAS Latency
31 ('sdr_trcar_d', 4), # Auto-refresh period
32 ('sdr_twr_d', 4), # Write recovery delay
33 ('sdr_rfsh', refresh_timer_sz
),
34 ('sdr_rfmax', refresh_row_count
)
38 class SDRAM(Elaboratable
):
39 """SDRAM controller from opencores, nmigen wrapper. remember to call
40 SDRAM.add_verilog_source.
42 * the SDRAM IC will be accessible over the Wishbone Bus
43 * sdr_* signals must be wired to the IC
44 * cfg parameters must match those listed in the SDRAM IC's datasheet
47 def __init__(self
, bus
=None, features
=None, name
=None,
48 data_width
=32, addr_width
=26,
54 self
.data_width
= data_width
55 self
.sdr_data_width
= sdr_data_width
56 self
.addr_width
= addr_width
57 self
.refresh_timer_sz
= 12
58 self
.refresh_row_count
= 3
60 # set up the wishbone bus
62 features
= frozenset({'cti'})
64 bus
= Interface(addr_width
=addr_width
,
65 data_width
=data_width
,
70 assert len(self
.bus
.dat_r
) == data_width
, \
71 "bus width must be %d" % data_width
73 byte_width
= sdr_data_width
// 8 # for individual byte masks/enables
76 self
.sdram_clk
= Signal() # sdram phy clock
77 self
.sdram_resetn
= Signal(reset_less
=True) # sdram reset (low)
78 self
.sdr_cs_n
= Signal() # chip select
79 self
.sdr_cke
= Signal() # clock-enable
80 self
.sdr_ras_n
= Signal() # read-address strobe
81 self
.sdr_cas_n
= Signal() # cas
82 self
.sdr_we_n
= Signal() # write-enable
83 self
.sdr_dqm
= Signal(byte_width
) # data mask
84 self
.sdr_ba
= Signal(2) # bank enable
85 self
.sdr_addr
= Signal(13) # sdram address, 13 bits
86 # these combine to create a bi-direction inout, sdr_dq
87 # note, each bit of sdr_den_n covers a *byte* of sdr_din/sdr_dout
88 self
.sdr_den_n
= Signal(byte_width
)
89 self
.sdr_din
= Signal(data_width
)
90 self
.sdr_dout
= Signal(data_width
)
92 # configuration parameters, these need to match the SDRAM IC datasheet
93 self
.sdr_init_done
= Signal() # Indicate SDRAM init Done
95 cfg
= SDRAMConfig(self
.refresh_timer_sz
,
96 self
.refresh_row_count
, name
="sdr_cfg")
98 # config and pins resource
103 def add_verilog_source(cls
, verilog_src_dir
, platform
):
104 # add each of the verilog sources, needed for when doing platform.build
105 for fname
in [ './core/sdrc_bank_ctl.v', './core/sdrc_bank_fsm.v',
106 './core/sdrc_bs_convert.v', './core/sdrc_core.v',
107 './core/sdrc_req_gen.v', './core/sdrc_xfr_ctl.v',
108 './core/sdrc_define.v',
109 './lib/async_fifo.v', './lib/sync_fifo.v',
110 './top/sdrc_top.v', './wb2sdrc/wb2sdrc.v',
112 # prepend the src directory to each filename, add its contents
113 fullname
= os
.path
.join(verilog_src_dir
, fname
)
114 with
open(fullname
) as f
:
115 platform
.add_file(fullname
, f
)
117 def elaborate(self
, platform
):
121 # create definition of external verilog 16550 uart here, so that # nmigen understands I/O directions (defined by i_ and o_ prefixes)
125 # clock/reset (use DomainRenamer if needed)
126 'i_wb_clk_i' : ClockSignal(),
127 'i_wb_rst_i' : ResetSignal(),
129 # wishbone bus signals
130 'i_wb_adr_i' : bus
.adr
,
131 'i_wb_dat_i' : bus
.dat_w
,
132 'i_wb_sel_i' : bus
.sel
,
133 'o_wb_dat_o' : bus
.dat_r
,
134 'i_wb_we_i' : bus
.we
,
135 'i_wb_stb_i' : bus
.stb
,
136 'i_wb_cyc_i' : bus
.cyc
,
137 'o_wb_ack_o' : bus
.ack
,
140 'i_sdram_clk' : self
.sdram_clk
,
141 'i_sdram_resetn' : self
.sdram_resetn
,
142 'o_sdr_cs_n' : self
.sdr_cs_n
,
143 'o_sdr_cke' : self
.sdr_cke
,
144 'o_sdr_ras_n' : self
.sdr_ras_n
,
145 'o_sdr_cas_n' : self
.sdr_cas_n
,
146 'o_sdr_we_n' : self
.sdr_we_n
,
147 'o_sdr_dqm' : self
.sdr_dqm
,
148 'o_sdr_ba' : self
.sdr_ba
,
149 'o_sdr_addr' : self
.sdr_addr
,
150 'o_sdr_den_n' : self
.sdr_den_n
,
151 'i_sdr_din' : self
.sdr_din
,
152 'o_sdr_dout' : self
.sdr_dout
,
154 # configuration parameters (from the SDRAM IC datasheet)
155 'o_sdr_init_done' : self
.sdr_init_done
,
156 'i_cfg_req_depth' : self
.cfg
.req_depth
,
157 'i_cfg_sdr_en' : self
.cfg
.sdr_en
,
158 'i_cfg_sdr_mode_reg' : self
.cfg
.sdr_mode_reg
,
159 'i_cfg_sdr_tras_d' : self
.cfg
.sdr_tras_d
,
160 'i_cfg_sdr_trp_d' : self
.cfg
.sdr_trp_d
,
161 'i_cfg_sdr_trcd_d' : self
.cfg
.sdr_trcd_d
,
162 'i_cfg_sdr_cas' : self
.cfg
.sdr_cas
,
163 'i_cfg_sdr_trcar_d' : self
.cfg
.sdr_trcar_d
,
164 'i_cfg_sdr_twr_d' : self
.cfg
.sdr_twr_d
,
165 'i_cfg_sdr_rfsh' : self
.cfg
.sdr_rfsh
,
166 'i_cfg_sdr_rfmax' : self
.cfg
.sdr_rfmax
,
169 'p_APP_AW' : self
.addr_width
, # Application Address Width
170 'p_APP_DW' : self
.data_width
, # Application Data Width
171 'p_APP_BW' : self
.addr_width
//8, # Application Byte Width
172 'p_APP_RW' : 9, # Application Request Width
173 'p_SDR_DW' : self
.sdr_data_width
, # SDR Data Width
174 'p_SDR_BW' : self
.sdr_data_width
//8, # SDR Byte Width
175 'p_dw' : self
.data_width
, # data width
176 'p_tw' : 8, # tag id width
177 'p_bl' : 9, # burst_length_width
179 m
.submodules
['sdrc_top'] = Instance("sdrc_top", **params
)
183 if self
.pins
is not None:
184 comb
+= self
.pins
.tx
.eq(self
.tx_o
)
185 comb
+= self
.rx_i
.eq(self
.pins
.rx
)
190 def create_ilang(dut
, ports
, test_name
):
191 vl
= rtlil
.convert(dut
, name
=test_name
, ports
=ports
)
192 with
open("%s.il" % test_name
, "w") as f
:
195 def create_verilog(dut
, ports
, test_name
):
196 vl
= verilog
.convert(dut
, name
=test_name
, ports
=ports
)
197 with
open("%s.v" % test_name
, "w") as f
:
201 if __name__
== "__main__":
202 sdram
= SDRAM(name
="sdram", data_width
=8)
203 create_ilang(sdram
, [sdram
.bus
.cyc
, sdram
.bus
.stb
, sdram
.bus
.ack
,
204 sdram
.bus
.dat_r
, sdram
.bus
.dat_w
, sdram
.bus
.adr
,
205 sdram
.bus
.we
, sdram
.bus
.sel
,
206 sdram
.sdram_clk
, sdram
.sdram_resetn
,
207 sdram
.sdr_cs_n
, sdram
.sdr_cke
,
208 sdram
.sdr_ras_n
, sdram
.sdr_cas_n
, sdram
.sdr_we_n
,
209 sdram
.sdr_dqm
, sdram
.sdr_ba
, sdram
.sdr_addr
,
210 sdram
.sdr_den_n
, sdram
.sdr_din
, sdram
.sdr_dout
,
211 sdram
.sdr_init_done
, sdram
.cfg
.req_depth
,
212 sdram
.cfg
.sdr_en
, sdram
.cfg
.sdr_mode_reg
,
213 sdram
.cfg
.sdr_tras_d
, sdram
.cfg
.sdr_trp_d
,
214 sdram
.cfg
.sdr_trcd_d
, sdram
.cfg
.sdr_cas
,
215 sdram
.cfg
.sdr_trcar_d
, sdram
.cfg
.sdr_twr_d
,
216 sdram
.cfg
.sdr_rfsh
, sdram
.cfg
.sdr_rfmax
,