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