sort out sdr and sdmmc OE pad drive, no longer one signal
[libresoc-litex.git] / libresoc / core.py
1 import os
2
3 from migen import ClockSignal, ResetSignal, Signal, Instance, Cat
4
5 from litex.soc.interconnect import wishbone as wb
6 from litex.soc.cores.cpu import CPU
7
8 from soc.config.pinouts import get_pinspecs
9 from soc.debug.jtag import Pins
10 from c4m.nmigen.jtag.tap import IOType
11
12 from libresoc.ls180 import io
13 from litex.build.generic_platform import ConstraintManager
14
15
16 CPU_VARIANTS = ["standard", "standard32", "standardjtag",
17 "standardjtagtestgpio", "ls180", "ls180sram4k",
18 "ls180nopll",
19 "standardjtagnoirq"]
20
21
22 def make_wb_bus(prefix, obj, simple=False):
23 res = {}
24 outpins = ['stb', 'cyc', 'we', 'adr', 'dat_w', 'sel']
25 if not simple:
26 outpins += ['cti', 'bte']
27 for o in outpins:
28 res['o_%s__%s' % (prefix, o)] = getattr(obj, o)
29 for i in ['ack', 'err', 'dat_r']:
30 res['i_%s__%s' % (prefix, i)] = getattr(obj, i)
31 return res
32
33 def make_wb_slave(prefix, obj, simple=False):
34 res = {}
35 inpins = ['stb', 'cyc', 'we', 'adr', 'dat_w', 'sel']
36 if not simple:
37 inpins += ['cti', 'bte']
38 for i in inpins:
39 res['i_%s__%s' % (prefix, i)] = getattr(obj, i)
40 for o in ['ack', 'err', 'dat_r']:
41 res['o_%s__%s' % (prefix, o)] = getattr(obj, o)
42 return res
43
44 def make_pad(res, dirn, name, suffix, cpup, iop):
45 cpud, iod = ('i', 'o') if dirn else ('o', 'i')
46 cname = '%s_%s__core__%s' % (cpud, name, suffix)
47 pname = '%s_%s__pad__%s' % (iod, name, suffix)
48 print ("make pad", name, dirn, cpud, iod, cname, pname, suffix, cpup, iop)
49 res[cname], res[pname] = cpup, iop
50
51 def get_field(rec, name):
52 for f in rec.layout:
53 f = f[0]
54 print ("get_field", f, name)
55 for f in rec.layout:
56 f = f[0]
57 if f.endswith(name):
58 return getattr(rec, f)
59
60
61 def make_jtag_ioconn(res, pin, cpupads, iopads):
62 (fn, pin, iotype, pin_name, scan_idx) = pin
63 #serial_tx__core__o, serial_rx__pad__i,
64 # special-case sdram_clock
65 #if pin == 'clock' and fn == 'sdr':
66 # cpu = cpupads['sdram_clock']
67 # io = iopads['sdram_clock']
68 #else:
69 # cpu = cpupads[fn]
70 # io = iopads[fn]
71 cpu = cpupads[fn]
72 io = iopads[fn]
73 print ("make_jtag_ioconn", scan_idx)
74 print ("cpupads", cpupads)
75 print ("iopads", iopads)
76 print ("pin", fn, pin, iotype, pin_name)
77 print ("cpu fn", cpu)
78 print ("io fn", io)
79 name = "%s_%s" % (fn, pin)
80 print ("name", name)
81 sigs = []
82
83 if iotype in (IOType.In, IOType.Out):
84 ps = pin.split("_")
85 #if pin == 'clock' and fn == 'sdr':
86 # cpup = cpu
87 # iop = io
88 if len(ps) == 2 and ps[-1].isdigit():
89 pin, idx = ps
90 idx = int(idx)
91 print ("ps split", pin, idx)
92 cpup = getattr(cpu, pin)[idx]
93 iop = getattr(io, pin)[idx]
94 elif pin.isdigit() and fn != 'eint':
95 idx = int(pin)
96 print ("digit", idx)
97 cpup = cpu[idx]
98 iop = io[idx]
99 else:
100 print ("attr", cpu)
101 cpup = getattr(cpu, pin)
102 iop = getattr(io, pin)
103
104 if iotype == IOType.Out:
105 # output from the pad is routed through C4M JTAG and so
106 # is an *INPUT* into core. ls180soc connects this to "real" peripheral
107 make_pad(res, True, name, "o", cpup, iop)
108
109 elif iotype == IOType.In:
110 # input to the pad is routed through C4M JTAG and so
111 # is an *OUTPUT* into core. ls180soc connects this to "real" peripheral
112 make_pad(res, False, name, "i", cpup, iop)
113
114 elif iotype == IOType.InTriOut:
115 if fn == 'gpio': # sigh decode GPIO special-case
116 idx = int(pin[1:])
117 oe_idx = idx
118 pfx = ''
119 elif fn.startswith('sd') and pin.startswith('data'):
120 idx = int(pin[-1])
121 oe_idx = idx
122 pfx = pin[:-1]+"_"
123 elif fn == 'sdr':
124 idx = int(pin.split('_')[-1])
125 oe_idx = idx
126 pfx = pin.split('_')[0]+"_"
127 else:
128 idx = 0
129 oe_idx = 0
130 pfx = pin+"_"
131 print ("gpio tri", fn, pin, iotype, pin_name, scan_idx, idx)
132 # i pads
133 cpup, iop = get_field(cpu, pfx+"i")[idx], \
134 get_field(io, pfx+"i")[idx]
135 make_pad(res, False, name, "i", cpup, iop)
136 # o pads
137 cpup, iop = get_field(cpu, pfx+"o")[idx], \
138 get_field(io, pfx+"o")[idx]
139 make_pad(res, True, name, "o", cpup, iop)
140 # oe pads
141 cpup, iop = get_field(cpu, pfx+"oe")[oe_idx], \
142 get_field(io, pfx+"oe")[oe_idx]
143 make_pad(res, True, name, "oe", cpup, iop)
144
145 if iotype in (IOType.In, IOType.InTriOut):
146 sigs.append(("i", 1))
147 if iotype in (IOType.Out, IOType.TriOut, IOType.InTriOut):
148 sigs.append(("o", 1))
149 if iotype in (IOType.TriOut, IOType.InTriOut):
150 sigs.append(("oe", 1))
151
152
153 class LibreSoC(CPU):
154 name = "libre_soc"
155 human_name = "Libre-SoC"
156 variants = CPU_VARIANTS
157 endianness = "little"
158 gcc_triple = ("powerpc64le-linux", "powerpc64le-linux-gnu")
159 linker_output_format = "elf64-powerpcle"
160 nop = "nop"
161 io_regions = {0xc0000000: 0x10000000} # origin, length
162
163 @property
164 def mem_map(self):
165 return {"csr": 0xc0000000}
166
167 @property
168 def gcc_flags(self):
169 flags = "-m64 "
170 flags += "-mabi=elfv2 "
171 flags += "-msoft-float "
172 flags += "-mno-string "
173 flags += "-mno-multiple "
174 flags += "-mno-vsx "
175 flags += "-mno-altivec "
176 flags += "-mlittle-endian "
177 flags += "-mstrict-align "
178 flags += "-fno-stack-protector "
179 flags += "-mcmodel=small "
180 flags += "-D__microwatt__ "
181 return flags
182
183 def __init__(self, platform, variant="standard"):
184 self.platform = platform
185 self.variant = variant
186 self.reset = Signal()
187
188 irq_en = "noirq" not in variant
189
190 if irq_en:
191 self.interrupt = Signal(16)
192
193 if variant == "standard32":
194 self.data_width = 32
195 self.dbus = dbus = wb.Interface(data_width=32, adr_width=30)
196 else:
197 self.dbus = dbus = wb.Interface(data_width=64, adr_width=29)
198 self.data_width = 64
199 self.ibus = ibus = wb.Interface(data_width=64, adr_width=29)
200
201 self.xics_icp = icp = wb.Interface(data_width=32, adr_width=30)
202 self.xics_ics = ics = wb.Interface(data_width=32, adr_width=30)
203
204 jtag_en = ('jtag' in variant) or ('ls180' in variant)
205
206 if "testgpio" in variant:
207 self.simple_gpio = gpio = wb.Interface(data_width=32, adr_width=30)
208 if jtag_en:
209 self.jtag_wb = jtag_wb = wb.Interface(data_width=64, adr_width=29)
210
211 self.srams = srams = []
212 if "sram4k" in variant:
213 for i in range(4):
214 srams.append(wb.Interface(data_width=64, adr_width=29))
215
216 self.periph_buses = [ibus, dbus]
217 self.memory_buses = []
218
219 if jtag_en:
220 self.periph_buses.append(jtag_wb)
221 self.jtag_tck = Signal(1)
222 self.jtag_tms = Signal(1)
223 self.jtag_tdi = Signal(1)
224 self.jtag_tdo = Signal(1)
225 else:
226 self.dmi_addr = Signal(4)
227 self.dmi_din = Signal(64)
228 self.dmi_dout = Signal(64)
229 self.dmi_wr = Signal(1)
230 self.dmi_ack = Signal(1)
231 self.dmi_req = Signal(1)
232
233 # # #
234
235 self.cpu_params = dict(
236 # Clock / Reset
237 i_clk = ClockSignal(),
238 i_rst = ResetSignal() | self.reset,
239
240 # Monitoring / Debugging
241 i_pc_i = 0,
242 i_pc_i_ok = 0,
243 i_core_bigendian_i = 0, # Signal(),
244 o_busy_o = Signal(), # not connected
245 o_memerr_o = Signal(), # not connected
246 o_pc_o = Signal(64), # not connected
247 )
248
249 if irq_en:
250 # interrupts
251 self.cpu_params['i_int_level_i'] = self.interrupt
252
253 if jtag_en:
254 self.cpu_params.update(dict(
255 # JTAG Debug bus
256 o_TAP_bus__tdo = self.jtag_tdo,
257 i_TAP_bus__tdi = self.jtag_tdi,
258 i_TAP_bus__tms = self.jtag_tms,
259 i_TAP_bus__tck = self.jtag_tck,
260 ))
261 else:
262 self.cpu_params.update(dict(
263 # DMI Debug bus
264 i_dmi_addr_i = self.dmi_addr,
265 i_dmi_din = self.dmi_din,
266 o_dmi_dout = self.dmi_dout,
267 i_dmi_req_i = self.dmi_req,
268 i_dmi_we_i = self.dmi_wr,
269 o_dmi_ack_o = self.dmi_ack,
270 ))
271
272 # add clock select, pll output
273 if "ls180" in variant and "pll" not in variant:
274 self.pll_18_o = Signal()
275 self.clk_sel = Signal(2)
276 self.pll_lck_o = Signal()
277 self.cpu_params['i_clk_sel_i'] = self.clk_sel
278 self.cpu_params['o_pll_18_o'] = self.pll_18_o
279 self.cpu_params['o_pll_lck_o'] = self.pll_lck_o
280
281 # add wishbone buses to cpu params
282 self.cpu_params.update(make_wb_bus("ibus", ibus, True))
283 self.cpu_params.update(make_wb_bus("dbus", dbus, True))
284 self.cpu_params.update(make_wb_slave("ics_wb", ics, True))
285 self.cpu_params.update(make_wb_slave("icp_wb", icp, True))
286 if "testgpio" in variant:
287 self.cpu_params.update(make_wb_slave("gpio_wb", gpio))
288 if jtag_en:
289 self.cpu_params.update(make_wb_bus("jtag_wb", jtag_wb, simple=True))
290 if "sram4k" in variant:
291 for i, sram in enumerate(srams):
292 self.cpu_params.update(make_wb_slave("sram4k_%d_wb" % i,
293 sram, simple=True))
294
295 # and set ibus advanced tags to zero (disable)
296 self.cpu_params['i_ibus__cti'] = 0
297 self.cpu_params['i_ibus__bte'] = 0
298 self.cpu_params['i_dbus__cti'] = 0
299 self.cpu_params['i_dbus__bte'] = 0
300
301 if "ls180" in variant:
302 # urr yuk. have to expose iopads / pins from core to litex
303 # then back again. cut _some_ of that out by connecting
304 self.padresources = io()
305 self.pad_cm = ConstraintManager(self.padresources, [])
306 self.cpupads = {}
307 iopads = {}
308 litexmap = {}
309 subset = {'uart', 'mtwi', 'eint', 'mspi0',
310 'sdr'}
311 subset.add('gpio')
312 #subset.add('pwm')
313 #subset.add('mspi1')
314 #subset.add('sd0')
315 for periph in subset:
316 origperiph = periph
317 num = None
318 if periph[-1].isdigit():
319 periph, num = periph[:-1], int(periph[-1])
320 print ("periph request", periph, num)
321 if periph == 'mspi':
322 if num == 0:
323 periph, num = 'spimaster', None
324 else:
325 periph, num = 'spisdcard', None
326 elif periph == 'sdr':
327 periph = 'sdram'
328 elif periph == 'mtwi':
329 periph = 'i2c'
330 elif periph == 'sd':
331 periph, num = 'sdcard', None
332 litexmap[origperiph] = (periph, num)
333 self.cpupads[origperiph] = self.pad_cm.request(periph, num)
334 iopads[origperiph] = platform.request(periph, num)
335 #if periph == 'sdram':
336 # # special-case sdram clock
337 # ck = self.pad_cm.request("sdram_clock")
338 # self.cpupads['sdram_clock'] = ck
339 # ck = platform.request("sdram_clock")
340 # iopads['sdram_clock'] = ck
341
342 pinset = get_pinspecs(subset=subset)
343 p = Pins(pinset)
344 for pin in list(p):
345 make_jtag_ioconn(self.cpu_params, pin, self.cpupads, iopads)
346
347 # add verilog sources
348 self.add_sources(platform)
349
350 def set_reset_address(self, reset_address):
351 assert not hasattr(self, "reset_address")
352 self.reset_address = reset_address
353 assert reset_address == 0x00000000
354
355 @staticmethod
356 def add_sources(platform):
357 cdir = os.path.dirname(__file__)
358 platform.add_source(os.path.join(cdir, "libresoc.v"))
359
360 def do_finalize(self):
361 self.specials += Instance("test_issuer", **self.cpu_params)
362