ed3a94eab87ab851bbc4d31cee949ea2d3c8fc80
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
20 class SDRAM(Elaboratable
):
21 """SDRAM controller from opencores, nmigen wrapper. remember to call
22 SDRAM.add_verilog_source.
24 * the SDRAM IC will be accessible over the Wishbone Bus
25 * sdr_* signals must be wired to the IC
26 * cfg_* parameters must match those listed in the SDRAM IC's datasheet
29 def __init__(self
, bus
=None, features
=None, name
=None,
30 data_width
=32, addr_width
=26,
35 self
.data_width
= data_width
36 self
.sdr_data_width
= sdr_data_width
37 self
.addr_width
= addr_width
38 self
.refresh_timer_sz
= 12
39 self
.refresh_row_count
= 3
41 # set up the wishbone bus
43 features
= frozenset({'cti'})
45 bus
= Interface(addr_width
=addr_width
,
46 data_width
=data_width
,
51 assert len(self
.bus
.dat_r
) == data_width
, \
52 "bus width must be %d" % data_width
54 byte_width
= sdr_data_width
// 8 # for individual byte masks/enables
57 self
.sdram_clk
= Signal() # sdram phy clock
58 self
.sdram_resetn
= Signal(reset_less
=True) # sdram reset (low)
59 self
.sdr_cs_n
= Signal() # chip select
60 self
.sdr_cke
= Signal() # clock-enable
61 self
.sdr_ras_n
= Signal() # read-address strobe
62 self
.sdr_cas_n
= Signal() # cas
63 self
.sdr_we_n
= Signal() # write-enable
64 self
.sdr_dqm
= Signal(byte_width
) # data mask
65 self
.sdr_ba
= Signal(2) # bank enable
66 self
.sdr_addr
= Signal(13) # sdram address, 13 bits
67 # these combine to create a bi-direction inout, sdr_dq
68 # note, each bit of sdr_den_n covers a *byte* of sdr_din/sdr_dout
69 self
.sdr_den_n
= Signal(byte_width
)
70 self
.sdr_din
= Signal(data_width
)
71 self
.sdr_dout
= Signal(data_width
)
73 # configuration parameters, these need to match the SDRAM IC datasheet
74 self
.sdr_init_done
= Signal() # Indicate SDRAM init Done
75 self
.cfg_req_depth
= Signal(2) # max request accepted
76 self
.cfg_sdr_en
= Signal() # Enable SDRAM controller
77 self
.cfg_sdr_mode_reg
= Signal(13)
78 self
.cfg_sdr_tras_d
= Signal(4) # Active to precharge delay
79 self
.cfg_sdr_trp_d
= Signal(4) # Precharge to active delay
80 self
.cfg_sdr_trcd_d
= Signal(4) # Active to R/W delay
81 self
.cfg_sdr_cas
= Signal(3) # SDRAM CAS Latency
82 self
.cfg_sdr_trcar_d
= Signal(4) # Auto-refresh period
83 self
.cfg_sdr_twr_d
= Signal(4) # Write recovery delay
84 self
.cfg_sdr_rfsh
= Signal(self
.refresh_timer_sz
)
85 self
.cfg_sdr_rfmax
= Signal(self
.refresh_row_count
)
91 def add_verilog_source(cls
, verilog_src_dir
, platform
):
92 # add each of the verilog sources, needed for when doing platform.build
93 for fname
in [ './core/sdrc_bank_ctl.v', './core/sdrc_bank_fsm.v',
94 './core/sdrc_bs_convert.v', './core/sdrc_core.v',
95 './core/sdrc_req_gen.v', './core/sdrc_xfr_ctl.v',
96 './core/sdrc_define.v',
97 './lib/async_fifo.v', './lib/sync_fifo.v',
98 './top/sdrc_top.v', './wb2sdrc/wb2sdrc.v',
100 # prepend the src directory to each filename, add its contents
101 fullname
= os
.path
.join(verilog_src_dir
, fname
)
102 with
open(fullname
) as f
:
103 platform
.add_file(fullname
, f
)
105 def elaborate(self
, platform
):
109 # create definition of external verilog 16550 uart here, so that # nmigen understands I/O directions (defined by i_ and o_ prefixes)
113 # clock/reset (use DomainRenamer if needed)
114 'i_wb_clk_i' : ClockSignal(),
115 'i_wb_rst_i' : ResetSignal(),
117 # wishbone bus signals
118 'i_wb_adr_i' : bus
.adr
,
119 'i_wb_dat_i' : bus
.dat_w
,
120 'i_wb_sel_i' : bus
.sel
,
121 'o_wb_dat_o' : bus
.dat_r
,
122 'i_wb_we_i' : bus
.we
,
123 'i_wb_stb_i' : bus
.stb
,
124 'i_wb_cyc_i' : bus
.cyc
,
125 'o_wb_ack_o' : bus
.ack
,
128 'i_sdram_clk' : self
.sdram_clk
,
129 'i_sdram_resetn' : self
.sdram_resetn
,
130 'o_sdr_cs_n' : self
.sdr_cs_n
,
131 'o_sdr_cke' : self
.sdr_cke
,
132 'o_sdr_ras_n' : self
.sdr_ras_n
,
133 'o_sdr_cas_n' : self
.sdr_cas_n
,
134 'o_sdr_we_n' : self
.sdr_we_n
,
135 'o_sdr_dqm' : self
.sdr_dqm
,
136 'o_sdr_ba' : self
.sdr_ba
,
137 'o_sdr_addr' : self
.sdr_addr
,
138 'o_sdr_den_n' : self
.sdr_den_n
,
139 'i_sdr_din' : self
.sdr_din
,
140 'o_sdr_dout' : self
.sdr_dout
,
142 # configuration parameters (from the SDRAM IC datasheet)
143 'o_sdr_init_done' : self
.sdr_init_done
,
144 'i_cfg_req_depth' : self
.cfg_req_depth
,
145 'i_cfg_sdr_en' : self
.cfg_sdr_en
,
146 'i_cfg_sdr_mode_reg' : self
.cfg_sdr_mode_reg
,
147 'i_cfg_sdr_tras_d' : self
.cfg_sdr_tras_d
,
148 'i_cfg_sdr_trp_d' : self
.cfg_sdr_trp_d
,
149 'i_cfg_sdr_trcd_d' : self
.cfg_sdr_trcd_d
,
150 'i_cfg_sdr_cas' : self
.cfg_sdr_cas
,
151 'i_cfg_sdr_trcar_d' : self
.cfg_sdr_trcar_d
,
152 'i_cfg_sdr_twr_d' : self
.cfg_sdr_twr_d
,
153 'i_cfg_sdr_rfsh' : self
.cfg_sdr_rfsh
,
154 'i_cfg_sdr_rfmax' : self
.cfg_sdr_rfmax
,
157 'p_APP_AW' : self
.addr_width
, # Application Address Width
158 'p_APP_DW' : self
.data_width
, # Application Data Width
159 'p_APP_BW' : self
.addr_width
//8, # Application Byte Width
160 'p_APP_RW' : 9, # Application Request Width
161 'p_SDR_DW' : self
.sdr_data_width
, # SDR Data Width
162 'p_SDR_BW' : self
.sdr_data_width
//8, # SDR Byte Width
163 'p_dw' : self
.data_width
, # data width
164 'p_tw' : 8, # tag id width
165 'p_bl' : 9, # burst_length_width
167 m
.submodules
['sdrc_top'] = Instance("sdrc_top", **params
)
171 if self
.pins
is not None:
172 comb
+= self
.pins
.tx
.eq(self
.tx_o
)
173 comb
+= self
.rx_i
.eq(self
.pins
.rx
)
178 def create_ilang(dut
, ports
, test_name
):
179 vl
= rtlil
.convert(dut
, name
=test_name
, ports
=ports
)
180 with
open("%s.il" % test_name
, "w") as f
:
183 def create_verilog(dut
, ports
, test_name
):
184 vl
= verilog
.convert(dut
, name
=test_name
, ports
=ports
)
185 with
open("%s.v" % test_name
, "w") as f
:
189 if __name__
== "__main__":
190 sdram
= SDRAM(name
="sdram", data_width
=8)
191 create_ilang(sdram
, [sdram
.bus
.cyc
, sdram
.bus
.stb
, sdram
.bus
.ack
,
192 sdram
.bus
.dat_r
, sdram
.bus
.dat_w
, sdram
.bus
.adr
,
193 sdram
.bus
.we
, sdram
.bus
.sel
,
194 sdram
.sdram_clk
, sdram
.sdram_resetn
,
195 sdram
.sdr_cs_n
, sdram
.sdr_cke
,
196 sdram
.sdr_ras_n
, sdram
.sdr_cas_n
, sdram
.sdr_we_n
,
197 sdram
.sdr_dqm
, sdram
.sdr_ba
, sdram
.sdr_addr
,
198 sdram
.sdr_den_n
, sdram
.sdr_din
, sdram
.sdr_dout
,
199 sdram
.sdr_init_done
, sdram
.cfg_req_depth
,
200 sdram
.cfg_sdr_en
, sdram
.cfg_sdr_mode_reg
,
201 sdram
.cfg_sdr_tras_d
, sdram
.cfg_sdr_trp_d
,
202 sdram
.cfg_sdr_trcd_d
, sdram
.cfg_sdr_cas
,
203 sdram
.cfg_sdr_trcar_d
, sdram
.cfg_sdr_twr_d
,
204 sdram
.cfg_sdr_rfsh
, sdram
.cfg_sdr_rfmax
,