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 MT48LC16M16(SDRModule):
26 technology_timings = _TechnologyTimings(tREFI=64e6/8192,
30 speedgrade_timings = {"default": _SpeedgradeTimings(tRP=20,
36 # for MT48LC16M16-75 part
37 comb += self.cfg.sdr_en.eq(1)
38 comb += self.cfg.sdr_mode_reg.eq(0x033)
39 comb += self.cfg.req_depth.eq(3) # max
40 comb += self.cfg.sdr_tras_d.eq(44) # Active to precharge delay
41 comb += self.cfg.sdr_trp_d.eq(20) # Precharge to active delay
42 comb += self.cfg.sdr_trcd_d.eq(20) # Active to R/W delay
43 comb += self.cfg.sdr_cas.eq(3) # CAS latency
44 comb += self.cfg.sdr_trcar_d.eq(66) # tRFC auto-refresh period
45 comb += self.cfg.sdr_twr_d.eq(15) # clock + 7.5ns
46 comb += self.cfg.sdr_rfsh.eq(0x100)
47 comb += self.cfg.sdr_rfmax.eq(6)
51 class SDRAMConfig(Record
):
52 def __init__(self
, refresh_timer_sz
, refresh_row_count
, name
=None):
53 super().__init
__(name
=name
, layout
=[
54 # configuration parameters, these need to match the SDRAM IC datasheet
55 ('req_depth', 2), # max request accepted
56 ('sdr_en', 1), # Enable SDRAM controller
58 ('sdr_tras_d', 4), # Active to precharge delay
59 ('sdr_trp_d', 4), # Precharge to active delay
60 ('sdr_trcd_d', 4), # Active to R/W delay
61 ('sdr_cas', 3), # SDRAM CAS Latency
62 ('sdr_trcar_d', 4), # Auto-refresh period
63 ('sdr_twr_d', 4), # Write recovery delay
64 ('sdr_rfsh', refresh_timer_sz
),
65 ('sdr_rfmax', refresh_row_count
)
69 class SDRAM(Elaboratable
):
70 """SDRAM controller from opencores, nmigen wrapper. remember to call
71 SDRAM.add_verilog_source.
73 * the SDRAM IC will be accessible over the Wishbone Bus
74 * sdr_* signals must be wired to the IC
75 * cfg parameters must match those listed in the SDRAM IC's datasheet
78 def __init__(self
, bus
=None, features
=None, name
=None,
79 data_width
=32, addr_width
=26,
85 self
.data_width
= data_width
86 self
.sdr_data_width
= sdr_data_width
87 self
.addr_width
= addr_width
88 self
.refresh_timer_sz
= 12
89 self
.refresh_row_count
= 3
91 # set up the wishbone bus
93 features
= frozenset({'cti'})
95 bus
= Interface(addr_width
=addr_width
,
96 data_width
=data_width
,
101 assert len(self
.bus
.dat_r
) == data_width
, \
102 "bus width must be %d" % data_width
104 byte_width
= sdr_data_width
// 8 # for individual byte masks/enables
107 self
.sdram_clk
= Signal() # sdram phy clock
108 self
.sdram_resetn
= Signal(reset_less
=True) # sdram reset (low)
109 self
.sdr_cs_n
= Signal() # chip select
110 self
.sdr_cke
= Signal() # clock-enable
111 self
.sdr_ras_n
= Signal() # read-address strobe
112 self
.sdr_cas_n
= Signal() # cas
113 self
.sdr_we_n
= Signal() # write-enable
114 self
.sdr_dqm
= Signal(byte_width
) # data mask
115 self
.sdr_ba
= Signal(2) # bank enable
116 self
.sdr_addr
= Signal(13) # sdram address, 13 bits
117 # these combine to create a bi-direction inout, sdr_dq
118 # note, each bit of sdr_den_n covers a *byte* of sdr_din/sdr_dout
119 self
.sdr_den_n
= Signal(byte_width
)
120 self
.sdr_din
= Signal(data_width
)
121 self
.sdr_dout
= Signal(data_width
)
123 # configuration parameters, these need to match the SDRAM IC datasheet
124 self
.sdr_init_done
= Signal() # Indicate SDRAM init Done
126 cfg
= SDRAMConfig(self
.refresh_timer_sz
,
127 self
.refresh_row_count
, name
="sdr_cfg")
129 # config and pins resource
134 def add_verilog_source(cls
, verilog_src_dir
, platform
):
135 # add each of the verilog sources, needed for when doing platform.build
136 for fname
in [ './core/sdrc_bank_ctl.v', './core/sdrc_bank_fsm.v',
137 './core/sdrc_bs_convert.v', './core/sdrc_core.v',
138 './core/sdrc_req_gen.v', './core/sdrc_xfr_ctl.v',
139 './core/sdrc_define.v',
140 './lib/async_fifo.v', './lib/sync_fifo.v',
141 './top/sdrc_top.v', './wb2sdrc/wb2sdrc.v',
143 # prepend the src directory to each filename, add its contents
144 fullname
= os
.path
.join(verilog_src_dir
, fname
)
145 with
open(fullname
) as f
:
146 platform
.add_file(fullname
, f
)
148 def elaborate(self
, platform
):
152 # create definition of external verilog 16550 uart here, so that # nmigen understands I/O directions (defined by i_ and o_ prefixes)
156 # clock/reset (use DomainRenamer if needed)
157 'i_wb_clk_i' : ClockSignal(),
158 'i_wb_rst_i' : ResetSignal(),
160 # wishbone bus signals
161 'i_wb_adr_i' : bus
.adr
,
162 'i_wb_dat_i' : bus
.dat_w
,
163 'i_wb_sel_i' : bus
.sel
,
164 'o_wb_dat_o' : bus
.dat_r
,
165 'i_wb_we_i' : bus
.we
,
166 'i_wb_stb_i' : bus
.stb
,
167 'i_wb_cyc_i' : bus
.cyc
,
168 'o_wb_ack_o' : bus
.ack
,
171 'i_sdram_clk' : self
.sdram_clk
,
172 'i_sdram_resetn' : self
.sdram_resetn
,
173 'o_sdr_cs_n' : self
.sdr_cs_n
,
174 'o_sdr_cke' : self
.sdr_cke
,
175 'o_sdr_ras_n' : self
.sdr_ras_n
,
176 'o_sdr_cas_n' : self
.sdr_cas_n
,
177 'o_sdr_we_n' : self
.sdr_we_n
,
178 'o_sdr_dqm' : self
.sdr_dqm
,
179 'o_sdr_ba' : self
.sdr_ba
,
180 'o_sdr_addr' : self
.sdr_addr
,
181 'o_sdr_den_n' : self
.sdr_den_n
,
182 'i_sdr_din' : self
.sdr_din
,
183 'o_sdr_dout' : self
.sdr_dout
,
185 # configuration parameters (from the SDRAM IC datasheet)
186 'o_sdr_init_done' : self
.sdr_init_done
,
187 'i_cfg_req_depth' : self
.cfg
.req_depth
,
188 'i_cfg_sdr_en' : self
.cfg
.sdr_en
,
189 'i_cfg_sdr_mode_reg' : self
.cfg
.sdr_mode_reg
,
190 'i_cfg_sdr_tras_d' : self
.cfg
.sdr_tras_d
,
191 'i_cfg_sdr_trp_d' : self
.cfg
.sdr_trp_d
,
192 'i_cfg_sdr_trcd_d' : self
.cfg
.sdr_trcd_d
,
193 'i_cfg_sdr_cas' : self
.cfg
.sdr_cas
,
194 'i_cfg_sdr_trcar_d' : self
.cfg
.sdr_trcar_d
,
195 'i_cfg_sdr_twr_d' : self
.cfg
.sdr_twr_d
,
196 'i_cfg_sdr_rfsh' : self
.cfg
.sdr_rfsh
,
197 'i_cfg_sdr_rfmax' : self
.cfg
.sdr_rfmax
,
200 'p_APP_AW' : self
.addr_width
, # Application Address Width
201 'p_APP_DW' : self
.data_width
, # Application Data Width
202 'p_APP_BW' : self
.addr_width
//8, # Application Byte Width
203 'p_APP_RW' : 9, # Application Request Width
204 'p_SDR_DW' : self
.sdr_data_width
, # SDR Data Width
205 'p_SDR_BW' : self
.sdr_data_width
//8, # SDR Byte Width
206 'p_dw' : self
.data_width
, # data width
207 'p_tw' : 8, # tag id width
208 'p_bl' : 9, # burst_length_width
210 m
.submodules
['sdrc_top'] = Instance("sdrc_top", **params
)
214 if self
.pins
is not None:
215 comb
+= self
.pins
.tx
.eq(self
.tx_o
)
216 comb
+= self
.rx_i
.eq(self
.pins
.rx
)
221 def create_ilang(dut
, ports
, test_name
):
222 vl
= rtlil
.convert(dut
, name
=test_name
, ports
=ports
)
223 with
open("%s.il" % test_name
, "w") as f
:
226 def create_verilog(dut
, ports
, test_name
):
227 vl
= verilog
.convert(dut
, name
=test_name
, ports
=ports
)
228 with
open("%s.v" % test_name
, "w") as f
:
232 if __name__
== "__main__":
233 sdram
= SDRAM(name
="sdram", data_width
=8)
234 create_ilang(sdram
, [sdram
.bus
.cyc
, sdram
.bus
.stb
, sdram
.bus
.ack
,
235 sdram
.bus
.dat_r
, sdram
.bus
.dat_w
, sdram
.bus
.adr
,
236 sdram
.bus
.we
, sdram
.bus
.sel
,
237 sdram
.sdram_clk
, sdram
.sdram_resetn
,
238 sdram
.sdr_cs_n
, sdram
.sdr_cke
,
239 sdram
.sdr_ras_n
, sdram
.sdr_cas_n
, sdram
.sdr_we_n
,
240 sdram
.sdr_dqm
, sdram
.sdr_ba
, sdram
.sdr_addr
,
241 sdram
.sdr_den_n
, sdram
.sdr_din
, sdram
.sdr_dout
,
242 sdram
.sdr_init_done
, sdram
.cfg
.req_depth
,
243 sdram
.cfg
.sdr_en
, sdram
.cfg
.sdr_mode_reg
,
244 sdram
.cfg
.sdr_tras_d
, sdram
.cfg
.sdr_trp_d
,
245 sdram
.cfg
.sdr_trcd_d
, sdram
.cfg
.sdr_cas
,
246 sdram
.cfg
.sdr_trcar_d
, sdram
.cfg
.sdr_twr_d
,
247 sdram
.cfg
.sdr_rfsh
, sdram
.cfg
.sdr_rfmax
,