2e313ce7b5cb4aae794cb63bb04411f7042efab0
[ls2.git] / src / ls2.py
1 # Copyright (c) 2020 LambdaConcept <contact@lambdaconcept.com>
2 # Copyright (c) 2021 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
3 # Copyright (C) 2022 Raptor Engineering, LLC <support@raptorengineering.com>
4 #
5 # Based on code from LambaConcept, from the gram example which is BSD-2-License
6 # https://github.com/jeanthom/gram/tree/master/examples
7 #
8 # Modifications for the Libre-SOC Project funded by NLnet and NGI POINTER
9 # under EU Grants 871528 and 957073, under the LGPLv3+ License
10
11 from nmigen import (Module, Elaboratable, DomainRenamer, Record,
12 Signal, Cat, Const, ClockSignal, ResetSignal,
13 )
14 from nmigen.build.dsl import Attrs
15 from nmigen.cli import verilog
16 from nmigen.lib.cdc import ResetSynchronizer
17 from nmigen_soc import wishbone, memory
18 from nmigen_soc.memory import MemoryMap
19 from nmigen.utils import log2_int
20 from nmigen_boards.resources.interface import UARTResource
21 from nmigen_stdio.serial import AsyncSerial
22
23 # HyperRAM
24 from nmigen_boards.resources.memory import HyperRAMResource
25 from lambdasoc.periph.hyperram import HyperRAM, HyperRAMPads, HyperRAMPHY
26
27 from lambdasoc.periph.event import IRQLine
28 from lambdasoc.periph.intc import GenericInterruptController
29 from lambdasoc.periph.sram import SRAMPeripheral
30 from lambdasoc.periph.timer import TimerPeripheral
31 from lambdasoc.periph import Peripheral
32 from lambdasoc.soc.base import SoC
33 from soc.bus.uart_16550 import UART16550 # opencores 16550 uart
34 from soc.bus.tercel import Tercel # SPI XIP master
35 from soc.bus.opencores_ethmac import EthMAC # OpenCores 10/100 Ethernet MAC
36 from soc.bus.external_core import ExternalCore # external libresoc/microwatt
37 from soc.bus.wb_downconvert import WishboneDownConvert
38 from soc.bus.wb_async import WBAsyncBridge
39 from soc.bus.syscon import MicrowattSYSCON
40 from soc.interrupts.xics import XICS_ICP, XICS_ICS
41
42 # DDR3
43 from gram.common import (PhySettings, get_cl_cw, get_sys_latency,
44 get_sys_phases,)
45 from gram.core import gramCore
46 from gram.phy.ecp5ddrphy import ECP5DDRPHY
47 from gram.phy.fakephy import FakePHY, SDRAM_VERBOSE_STD, SDRAM_VERBOSE_DBG
48 from gram.modules import MT41K256M16, MT41K64M16
49 from gram.frontend.wishbone import gramWishbone
50
51 # SPI / Ethernet MAC
52 from nmigen.build import Resource
53 from nmigen.build import Subsignal
54 from nmigen.build import Pins
55
56 # Board (and simulation) platforms
57 from nmigen_boards.versa_ecp5 import VersaECP5Platform
58 from nmigen_boards.versa_ecp5 import VersaECP5Platform85 # custom board
59 from nmigen_boards.ulx3s import ULX3S_85F_Platform
60 from nmigen_boards.arty_a7 import ArtyA7_100Platform
61 from nmigen_boards.test.blinky import Blinky
62 from nmigen_boards.orangecrab_r0_2 import OrangeCrabR0_2_85k_Platform
63 from icarusversa import IcarusVersaPlatform
64 # Clock-Reset Generator (works for all ECP5 platforms)
65 from ecp5_crg import ECP5CRG
66 from arty_crg import ArtyA7CRG
67
68 import sys
69 import os
70
71 def sim_ddr3_settings(clk_freq=100e6):
72 tck = 2/(2*2*clk_freq)
73 nphases = 2
74 databits = 16
75 nranks = 1
76 addressbits = 14
77 bankbits = 3
78 cl, cwl = get_cl_cw("DDR3", tck)
79 cl_sys_latency = get_sys_latency(nphases, cl)
80 cwl_sys_latency = get_sys_latency(nphases, cwl)
81 rdcmdphase, rdphase = get_sys_phases(nphases, cl_sys_latency, cl)
82 wrcmdphase, wrphase = get_sys_phases(nphases, cwl_sys_latency, cwl)
83 return PhySettings(
84 phytype="ECP5DDRPHY",
85 memtype="DDR3",
86 databits=databits,
87 dfi_databits=4*databits,
88 nranks=nranks,
89 nphases=nphases,
90 rdphase=rdphase,
91 wrphase=wrphase,
92 rdcmdphase=rdcmdphase,
93 wrcmdphase=wrcmdphase,
94 cl=cl,
95 cwl=cwl,
96 read_latency=2 + cl_sys_latency + 2 + log2_int(4//nphases) + 4,
97 write_latency=cwl_sys_latency
98 )
99
100
101 class WB64to32Convert(Elaboratable):
102 """Microwatt IO wishbone slave 64->32 bits converter
103
104 For timing reasons, this adds a one cycle latch on the way both
105 in and out. This relaxes timing and routing pressure on the "main"
106 memory bus by moving all simple IOs to a slower 32-bit bus.
107
108 This implementation is rather dumb at the moment, no stash buffer,
109 so we stall whenever that latch is busy. This can be improved.
110 """
111 def __init__(self, master, slave):
112 self.master = master
113 self.slave = slave
114
115 def elaborate(self, platform):
116 m = Module()
117 comb, sync = m.d.comb, m.d.sync
118 master, slave = self.master, self.slave
119
120 has_top = Signal()
121 has_top_r = Signal()
122 has_bot = Signal()
123
124 with m.FSM() as fsm:
125 with m.State("IDLE"):
126 # Clear ACK (and has_top_r) in case it was set
127 sync += master.ack.eq(0)
128 sync += has_top_r.eq(0)
129
130 # Do we have a cycle ?
131 with m.If(master.cyc & master.stb):
132 # Stall master until we are done, we are't (yet) pipelining
133 # this, it's all slow IOs.
134 sync += master.stall.eq(1)
135
136 # Start cycle downstream
137 sync += slave.cyc.eq(1)
138 sync += slave.stb.eq(1)
139
140 # Do we have a top word and/or a bottom word ?
141 comb += has_top.eq(master.sel[4:].bool())
142 comb += has_bot.eq(master.sel[:4].bool())
143 # record the has_top flag for the next FSM state
144 sync += has_top_r.eq(has_top)
145
146 # Copy write enable to IO out, copy address as well,
147 # LSB is set later based on HI/LO
148 sync += slave.we.eq(master.we)
149 sync += slave.adr.eq(Cat(0, master.adr))
150
151 # If we have a bottom word, handle it first, otherwise
152 # send the top word down. XXX Split the actual mux out
153 # and only generate a control signal.
154 with m.If(has_bot):
155 with m.If(master.we):
156 sync += slave.dat_w.eq(master.dat_w[:32])
157 sync += slave.sel.eq(master.sel[:4])
158
159 # Wait for ack on BOTTOM half
160 m.next = "WAIT_ACK_BOT"
161
162 with m.Else():
163 with m.If(master.we):
164 sync += slave.dat_w.eq(master.dat_w[32:])
165 sync += slave.sel.eq(master.sel[4:])
166
167 # Bump LSB of address
168 sync += slave.adr[0].eq(1)
169
170 # Wait for ack on TOP half
171 m.next = "WAIT_ACK_TOP"
172
173
174 with m.State("WAIT_ACK_BOT"):
175 # If we aren't stalled by the device, clear stb
176 if hasattr(slave, "stall"):
177 with m.If(~slave.stall):
178 sync += slave.stb.eq(0)
179
180 # Handle ack
181 with m.If(slave.ack):
182 # If it's a read, latch the data
183 with m.If(~slave.we):
184 sync += master.dat_r[:32].eq(slave.dat_r)
185
186 # Do we have a "top" part as well ?
187 with m.If(has_top_r):
188 # Latch data & sel
189 with m.If(master.we):
190 sync += slave.dat_w.eq(master.dat_w[32:])
191 sync += slave.sel.eq(master.sel[4:])
192
193 # Bump address and set STB
194 sync += slave.adr[0].eq(1)
195 sync += slave.stb.eq(1)
196
197 # Wait for new ack
198 m.next = "WAIT_ACK_TOP"
199
200 with m.Else():
201 # We are done, ack up, clear cyc downstram
202 sync += slave.cyc.eq(0)
203 sync += slave.stb.eq(0)
204
205 # And ack & unstall upstream
206 sync += master.ack.eq(1)
207 if hasattr(master , "stall"):
208 sync += master.stall.eq(0)
209
210 # Wait for next one
211 m.next = "IDLE"
212
213 with m.State("WAIT_ACK_TOP"):
214 # If we aren't stalled by the device, clear stb
215 if hasattr(slave, "stall"):
216 with m.If(~slave.stall):
217 sync += slave.stb.eq(0)
218
219 # Handle ack
220 with m.If(slave.ack):
221 # If it's a read, latch the data
222 with m.If(~slave.we):
223 sync += master.dat_r[32:].eq(slave.dat_r)
224
225 # We are done, ack up, clear cyc downstram
226 sync += slave.cyc.eq(0)
227 sync += slave.stb.eq(0)
228
229 # And ack & unstall upstream
230 sync += master.ack.eq(1)
231 if hasattr(master, "stall"):
232 sync += master.stall.eq(0)
233
234 # Wait for next one
235 m.next = "IDLE"
236
237 return m
238
239
240 class DDR3SoC(SoC, Elaboratable):
241 def __init__(self, *,
242 fpga,
243 dram_cls=None,
244 uart_pins=None, spi_0_pins=None, ethmac_0_pins=None,
245 ddr_pins=None, ddrphy_addr=None,
246 dramcore_addr=None, ddr_addr=None,
247 fw_addr=0x0000_0000, firmware=None,
248 uart_addr=None, uart_irqno=0,
249 spi0_addr=None, spi0_cfg_addr=None,
250 eth0_cfg_addr=None, eth0_irqno=None,
251 hyperram_addr=None,
252 hyperram_pins=None,
253 xics_icp_addr=None, xics_ics_addr=None,
254 clk_freq=50e6,
255 dram_clk_freq=None,
256 add_cpu=True):
257
258 # wishbone routing is as follows:
259 #
260 # SoC
261 # +--+--+
262 # | |
263 # ibus dbus
264 # | |
265 # +--+--+
266 # |
267 # 64to32DownCvt
268 # |
269 # arbiter------------------------------------------------------+
270 # | |
271 # +---decoder----+--------+---------------+-------------+--------+ |
272 # | | | | | | | |
273 # | | | WBAsyncBridge | | | |
274 # | | | | | | | |
275 # uart XICS CSRs DRAM XIP SPI HyperRAM EthMAC
276
277 # set up wishbone bus arbiter and decoder. arbiter routes,
278 # decoder maps local-relative addressed satellites to global addresses
279 self._arbiter = wishbone.Arbiter(addr_width=30, data_width=32,
280 granularity=8,
281 features={"cti", "bte", "stall"})
282 self._decoder = wishbone.Decoder(addr_width=30, data_width=32,
283 granularity=8,
284 features={"cti", "bte", "stall"})
285
286 # default firmware name
287 if firmware is None:
288 firmware = "firmware/main.bin"
289
290 # set up clock request generator
291 pod_bits = 25
292 sync_bits = 26
293 need_bridge=False
294 if fpga in ['versa_ecp5', 'versa_ecp5_85', 'isim', 'ulx3s',
295 'orangecrab', 'rcs_arctic_tern_bmc_card']:
296 if fpga in ['isim']:
297 pod_bits = 5
298 sync_bits = 6
299 if fpga in ['orangecrab', 'rcs_arctic_tern_bmc_card']:
300 need_bridge=True
301 self.crg = ECP5CRG(clk_freq, dram_clk_freq=dram_clk_freq,
302 pod_bits=pod_bits, sync_bits=sync_bits,
303 need_bridge=need_bridge)
304 if fpga in ['arty_a7']:
305 self.crg = ArtyA7CRG(clk_freq)
306
307 self.dram_clk_freq = dram_clk_freq
308 if self.dram_clk_freq is None:
309 self.dram_clk_freq = clk_freq
310
311 # set up CPU, with 64-to-32-bit downconverters, and a delayed Reset
312 if add_cpu:
313 self.cpu = ExternalCore(name="ext_core")
314
315 cvtdbus = wishbone.Interface(addr_width=30, data_width=32,
316 granularity=8, features={'stall'})
317 cvtibus = wishbone.Interface(addr_width=30, data_width=32,
318 granularity=8, features={'stall'})
319 self.dbusdowncvt = WB64to32Convert(self.cpu.dbus, cvtdbus)
320 self.ibusdowncvt = WB64to32Convert(self.cpu.ibus, cvtibus)
321 self._arbiter.add(cvtibus) # I-Cache Master
322 self._arbiter.add(cvtdbus) # D-Cache Master. TODO JTAG master
323 self.cvtibus = cvtibus
324 self.cvtdbus = cvtdbus
325
326 # CPU interrupt controller, needs stall to be added, also
327 # compat with wishbone.Interface
328 self.intc = GenericInterruptController(width=len(self.cpu.irq))
329 self.xics_icp = icp = XICS_ICP()
330 self.xics_ics = ics = XICS_ICS()
331 self.int_level_i = self.xics_ics.int_level_i
332
333 self.pbus = pbus = wishbone.Interface(name="xics_icp_bus",
334 addr_width=6, data_width=32,
335 granularity=8, features={'stall'})
336 self.sbus = sbus = wishbone.Interface(name="xics_ics_bus",
337 addr_width=10, data_width=32,
338 granularity=8, features={'stall'})
339 pmap = MemoryMap(addr_width=8, data_width=8, name="icp_map")
340 pbus.memory_map = pmap
341 self._decoder.add(pbus, addr=xics_icp_addr) # ICP addr
342
343 smap = MemoryMap(addr_width=12, data_width=8, name="ics_map")
344 sbus.memory_map = smap
345 self._decoder.add(sbus, addr=xics_ics_addr) # ICP addr
346
347
348 # SRAM (but actually a ROM, for firmware)
349 if fw_addr is not None:
350 print ("fw at address %x" % fw_addr)
351 sram_width = 32
352 self.bootmem = SRAMPeripheral(size=0x8000, data_width=sram_width,
353 writable=True)
354 if firmware is not None:
355 with open(firmware, "rb") as f:
356 words = iter(lambda: f.read(sram_width // 8), b'')
357 bios = [int.from_bytes(w, "little") for w in words]
358 self.bootmem.init = bios
359 self._decoder.add(self.bootmem.bus, addr=fw_addr) # ROM at fw_addr
360
361 # System Configuration info
362 # offset executable ELF payload at 6 megabyte offset (2<<20)
363 spi_offset = 2<<20 if (spi_0_pins is not None) else None
364 dram_offset = ddr_addr if (ddr_pins is not None) else None
365 self.syscon = MicrowattSYSCON(sys_clk_freq=clk_freq,
366 mem_clk_freq=self.dram_clk_freq,
367 has_uart=(uart_pins is not None),
368 spi_offset=spi_offset,
369 dram_addr=dram_offset)
370 self._decoder.add(self.syscon.bus, addr=0xc0000000) # at 0xc000_0000
371
372 if False:
373 # SRAM (read-writeable BRAM)
374 self.ram = SRAMPeripheral(size=4096)
375 self._decoder.add(self.ram.bus, addr=0x8000000) # at 0x8000_0000
376
377 # UART at 0xC000_2000, convert 32-bit bus down to 8-bit in an odd way
378 if uart_pins is not None:
379 # sigh actual UART in microwatt is 8-bit
380 self.uart_irq = IRQLine()
381 self.uart = UART16550(data_width=8, pins=uart_pins,
382 features={'stall'},
383 irq=self.uart_irq)
384 # but (see soc.vhdl) 8-bit regs are addressed at 32-bit locations
385 # strictly speaking this is a nmigen-soc "sparse" arrangement
386 # which should be handled by MemoryMap, but needs investigation
387 cvtuartbus = wishbone.Interface(addr_width=5, data_width=32,
388 granularity=8,
389 features={'stall'})
390 umap = MemoryMap(addr_width=7, data_width=8, name="uart_map")
391 cvtuartbus.memory_map = umap
392 self._decoder.add(cvtuartbus, addr=uart_addr) # 16550 UART addr
393 self.cvtuartbus = cvtuartbus
394 self.intc.add_irq(self.uart.irq, index=uart_irqno)
395
396 # SDRAM module using opencores sdr_ctrl
397 """
398 class MT48LC16M16(SDRModule):
399 # geometry
400 nbanks = 4
401 nrows = 8192
402 ncols = 512
403 # timings
404 technology_timings = _TechnologyTimings(tREFI=64e6/8192,
405 tWTR=(2, None),
406 tCCD=(1, None),
407 tRRD=(None, 15))
408 speedgrade_timings = {"default": _SpeedgradeTimings(tRP=20,
409 tRCD=20,
410 tWR=15,
411 tRFC=(None, 66),
412 tFAW=None,
413 tRAS=44)}
414 """
415
416 # DRAM Module. first, create the (triple) modules:
417 # * DDR PHY
418 # * gram Core: presents PHY with a DFI Interface
419 # * gram Bone (aka gram-with-wishbone) connects wishbone to DFI
420 # from there it gets a little complicated because of supporting
421 # several options: simulation, synchronous, and asynchronous clocks.
422 # dram_clk_freq can *never* be set equal to clk_freq, if it is,
423 # it's assumed to be synchronous, and the dram Domains need renaming
424
425 if ddr_pins is not None: # or fpga == 'sim':
426 ddrmodule = dram_cls(self.dram_clk_freq, "1:2") # match DDR3 P/N
427
428 # remap both the sync domain (wherever it occurs) and
429 # the sync2x domain, if dram frequency is specified and
430 # not equal to the core clock
431 drs = None
432 if dram_clk_freq is not None or fpga == 'sim':
433 drs = lambda x: x
434 else:
435 drs = DomainRenamer({"sync": "dramsync",
436 "sync2x": "dramsync2x"})
437
438 features = set()
439 if dram_clk_freq is None:
440 features.add("stall")
441
442 # create the PHY (fake one for sim)
443 if fpga == 'sim':
444 settings = sim_ddr3_settings(self.dram_clk_freq)
445 self.ddrphy = FakePHY(module=ddrmodule,
446 settings=settings,
447 verbosity=SDRAM_VERBOSE_DBG,
448 clk_freq=self.dram_clk_freq)
449 else:
450 self.ddrphy = drs(ECP5DDRPHY(ddr_pins,
451 #features=features,
452 sys_clk_freq=self.dram_clk_freq))
453
454 # create the core (bridge from PHY to DFI)
455 dramcore = gramCore(phy=self.ddrphy,
456 geom_settings=ddrmodule.geom_settings,
457 timing_settings=ddrmodule.timing_settings,
458 #features=features,
459 clk_freq=self.dram_clk_freq)
460 self.dramcore = drs(dramcore)
461
462 # create the wishbone presentation (wishbone to DFI)
463 drambone = gramWishbone(dramcore, features=features)
464 self.drambone = drs(drambone)
465
466 # this is the case where sys_clk === dram_clk. no ASync Bridge
467 # needed, so just let the phy core and wb-dfi be connected
468 # directly to WB decoder. both are running in "sync" domain
469 # (because of the DomainRenamer, above)
470
471 if ddr_pins is not None and dram_clk_freq is None:
472 self.ddrphy_bus = self.ddrphy.bus
473 self.dramcore_bus = self.dramcore.bus
474 self.drambone_bus = self.drambone.bus
475
476 # this covers the case where sys_clk != dram_clk: three separate
477 # ASync Bridges are constructed (!) and the interface that's to
478 # be wired to the WB decoder is the async bus because that's running
479 # in the "sync" domain.
480
481 if ddr_pins is not None and dram_clk_freq is not None:
482 # Set up Wishbone asynchronous bridge
483 pabus = wishbone.Interface(addr_width=self.ddrphy.bus.addr_width,
484 data_width=self.ddrphy.bus.data_width,
485 granularity=self.ddrphy.bus.granularity,
486 features={'stall'})
487 self.ddrphy_bus = pabus
488 self.ddrphy_bus.memory_map = self.ddrphy.bus.memory_map
489
490 pabr = WBAsyncBridge(master_bus=self.ddrphy_bus,
491 slave_bus=self.ddrphy.bus,
492 master_clock_domain=None,
493 slave_clock_domain="dramsync",
494 address_width=self.ddrphy.bus.addr_width,
495 data_width=self.ddrphy.bus.data_width,
496 granularity=self.ddrphy.bus.granularity)
497 self.ddrphy_async_br = pabr
498
499 # Set up Wishbone asynchronous bridge
500 dab = wishbone.Interface(addr_width=self.dramcore.bus.addr_width,
501 data_width=self.dramcore.bus.data_width,
502 granularity=self.dramcore.bus.granularity,
503 features={'stall'})
504 self.dramcore_bus = dab
505 self.dramcore_bus.memory_map = self.dramcore.bus.memory_map
506
507 dac = WBAsyncBridge(master_bus=self.dramcore_bus,
508 slave_bus=self.dramcore.bus,
509 master_clock_domain=None,
510 slave_clock_domain="dramsync",
511 address_width=self.dramcore.bus.addr_width,
512 data_width=self.dramcore.bus.data_width,
513 granularity=self.dramcore.bus.granularity)
514 self.dramcore_async_br = dac
515
516 # Set up Wishbone asynchronous bridge
517 bab = wishbone.Interface(addr_width=self.drambone.bus.addr_width,
518 data_width=self.drambone.bus.data_width,
519 granularity=self.drambone.bus.granularity,
520 features={'stall'})
521 self.drambone_bus = bab
522 self.drambone_bus.memory_map = self.drambone.bus.memory_map
523
524 bab = WBAsyncBridge(master_bus=self.drambone_bus,
525 slave_bus=self.drambone.bus,
526 master_clock_domain=None,
527 slave_clock_domain="dramsync",
528 address_width=self.drambone.bus.addr_width,
529 data_width=self.drambone.bus.data_width,
530 granularity=self.drambone.bus.granularity)
531 self.drambone_async_br = bab
532
533 if ddr_pins is not None:
534 # Add wishbone decoders
535 self._decoder.add(self.dramcore_bus, addr=dramcore_addr)
536 self._decoder.add(self.drambone_bus, addr=ddr_addr)
537 self._decoder.add(self.ddrphy_bus, addr=ddrphy_addr)
538
539 # additional SRAM at address if DRAM is not also at 0x0
540 # (TODO, check Flash, and HyperRAM as well)
541 if ((ddr_pins is None or ddr_addr != 0x0) and fw_addr != 0 and
542 hyperram_addr[0] != 0x0):
543 print ("SRAM 0x8000 at address 0x0")
544 sram_width = 32
545 self.sram = SRAMPeripheral(size=0x8000,
546 data_width=sram_width,
547 writable=True)
548 self._decoder.add(self.sram.bus, addr=0x0) # RAM at 0x0
549
550 # SPI controller
551 if spi_0_pins is not None and fpga in ['sim',
552 'isim',
553 'rcs_arctic_tern_bmc_card',
554 'orangecrab',
555 'versa_ecp5',
556 'versa_ecp5_85',
557 'arty_a7']:
558 # The Lattice ECP5 devices require special handling on the
559 # dedicated SPI clock line, which is shared with the internal
560 # SPI controller used for FPGA bitstream loading.
561 spi0_is_lattice_ecp5_clk = False
562 if fpga in ['versa_ecp5',
563 'versa_ecp5_85',
564 'rcs_arctic_tern_bmc_card',
565 'orangecrab',
566 'isim']:
567 spi0_is_lattice_ecp5_clk = True
568
569 # Tercel contains two independent Wishbone regions, a
570 # configuration region and the direct API access region,
571 # Set the SPI 0 access region to 16MB, as the FPGA
572 # bitstream Flash device is unlikely to be larger than this.
573 # The main SPI Flash (SPI 1) should be set to at
574 # least 28 bits (256MB) to allow the use of large 4BA devices.
575 self.spi0 = Tercel(data_width=32, spi_region_addr_width=24,
576 adr_offset=spi0_addr,
577 features={'stall'},
578 clk_freq=clk_freq,
579 pins=spi_0_pins,
580 lattice_ecp5_usrmclk=spi0_is_lattice_ecp5_clk)
581 self._decoder.add(self.spi0.bus, addr=spi0_addr)
582 self._decoder.add(self.spi0.cfg_bus, addr=spi0_cfg_addr)
583
584 # Ethernet MAC
585 if ethmac_0_pins is not None and fpga in ['versa_ecp5',
586 'versa_ecp5_85',
587 'isim']:
588 self.eth_irq = IRQLine()
589 # The OpenCores Ethernet MAC contains two independent Wishbone
590 # interfaces, a slave (configuration) interface and a master (DMA)
591 # interface.
592 self.eth0 = EthMAC(pins=ethmac_0_pins, irq=self.eth_irq)
593 self._arbiter.add(self.eth0.master_bus)
594 self._decoder.add(self.eth0.slave_bus, addr=eth0_cfg_addr)
595 self.intc.add_irq(self.eth0.irq, index=eth0_irqno)
596
597 # HyperRAM modules *plural*. Assumes using a Quad PMOD by Piotr
598 # Esden, sold by 1bitsquared, only doing one CS_N enable at the
599 # moment
600 self.hyperram = []
601 for i, (pins, hraddr) in enumerate(zip(hyperram_pins, hyperram_addr)):
602 hr = HyperRAM(io=pins, phy_kls=HyperRAMPHY,
603 name="hyperram%d" % i,
604 features={'stall'},
605 latency=7) # Winbond W956D8MBYA
606 self._decoder.add(hr.bus, addr=hraddr)
607 self.hyperram.append(hr)
608
609 self.memory_map = self._decoder.bus.memory_map
610
611 self.clk_freq = clk_freq
612 self.fpga = fpga
613
614 def elaborate(self, platform):
615 m = Module()
616 comb, sync = m.d.comb, m.d.sync
617
618 # add the peripherals and clock-reset-generator
619 if platform is not None and hasattr(self, "crg"):
620 m.submodules.sysclk = self.crg
621
622 if hasattr(self, "sram"):
623 m.submodules.sram = self.sram
624 if hasattr(self, "bootmem"):
625 m.submodules.bootmem = self.bootmem
626 m.submodules.syscon = self.syscon
627 if hasattr(self, "ram"):
628 m.submodules.ram = self.ram
629 if hasattr(self, "uart"):
630 m.submodules.uart = self.uart
631 comb += self.uart.cts_i.eq(1)
632 comb += self.uart.dsr_i.eq(1)
633 comb += self.uart.ri_i.eq(0)
634 comb += self.uart.dcd_i.eq(1)
635 # sigh connect up the wishbone bus manually to deal with
636 # the mis-match on the data. nmigen-soc "sparse" MemoryMap
637 # should be able to deal with this. TODO, investigate
638 uartbus = self.uart.bus
639 comb += uartbus.adr.eq(self.cvtuartbus.adr)
640 comb += uartbus.stb.eq(self.cvtuartbus.stb)
641 comb += uartbus.cyc.eq(self.cvtuartbus.cyc)
642 comb += uartbus.sel.eq(self.cvtuartbus.sel)
643 comb += uartbus.we.eq(self.cvtuartbus.we)
644 comb += uartbus.dat_w.eq(self.cvtuartbus.dat_w) # drops 8..31
645 comb += self.cvtuartbus.dat_r.eq(uartbus.dat_r) # drops 8..31
646 comb += self.cvtuartbus.ack.eq(uartbus.ack)
647 # aaand with the WB4-pipeline-to-WB3-classic mismatch, sigh
648 comb += uartbus.stall.eq(uartbus.cyc & ~uartbus.ack)
649 comb += self.cvtuartbus.stall.eq(uartbus.stall)
650 if hasattr(self, "cpu"):
651 m.submodules.intc = self.intc
652 m.submodules.extcore = self.cpu
653 m.submodules.dbuscvt = self.dbusdowncvt
654 m.submodules.ibuscvt = self.ibusdowncvt
655
656 m.submodules.arbiter = self._arbiter
657 m.submodules.decoder = self._decoder
658 if hasattr(self, "ddrphy"):
659 m.submodules.ddrphy = self.ddrphy
660 m.submodules.dramcore = self.dramcore
661 m.submodules.drambone = drambone = self.drambone
662
663 # add async wishbone bridges
664 if hasattr(self, "ddrphy_async_br"):
665 m.submodules.ddrphy_async_br = self.ddrphy_async_br
666 if hasattr(self, "dramcore_async_br"):
667 m.submodules.dramcore_async_br = self.dramcore_async_br
668 if hasattr(self, "drambone_async_br"):
669 m.submodules.drambone_async_br = self.drambone_async_br
670
671 # grrr, same problem with WB async bridge: not WB4-pipe compliant
672 dab = self.ddrphy_bus
673 if hasattr(dab, "stall"):
674 comb += dab.stall.eq(dab.cyc & ~dab.ack)
675 dab = self.dramcore_bus
676 if hasattr(dab, "stall"):
677 comb += dab.stall.eq(dab.cyc & ~dab.ack)
678 dab = self.drambone_bus
679 comb += dab.stall.eq(dab.cyc & ~dab.ack)
680
681 # add wb async bridge verilog source. assumes directory structure
682 # where bridge has been checked out in a common subdirectory with:
683 # git clone https://github.com/alexforencich/verilog-wishbone.git
684 # git checkout d1fa24a0
685 verilog_wishbone = "../../verilog-wishbone/rtl"
686 pth = os.path.split(__file__)[0]
687 pth = os.path.join(pth, verilog_wishbone)
688 fname = os.path.abspath(pth)
689 print (fname)
690 if hasattr(self, "ddrphy_async_br"):
691 self.dramcore_async_br.add_verilog_source(fname, platform)
692 if hasattr(self, "drambone_async_br"):
693 self.drambone_async_br.add_verilog_source(fname, platform)
694
695 # add hyperram module
696 for i, hr in enumerate(self.hyperram):
697 m.submodules["hyperram%d" % i] = hr
698 # grrr, same problem with hyperram: not WB4-pipe compliant
699 comb += hr.bus.stall.eq(hr.bus.cyc & ~hr.bus.ack)
700 # reset
701 if self.fpga == 'arty_a7':
702 comb += hr.phy.rst_n.eq(ResetSignal())
703
704 # add blinky lights so we know FPGA is alive
705 if platform is not None:
706 m.submodules.blinky = Blinky()
707
708 # connect the arbiter (of wishbone masters)
709 # to the decoder (addressing wishbone slaves)
710 comb += self._arbiter.bus.connect(self._decoder.bus)
711
712 if hasattr(self, "cpu"):
713 m.submodules.xics_icp = icp = self.xics_icp
714 m.submodules.xics_ics = ics = self.xics_ics
715 comb += icp.ics_i.eq(ics.icp_o) # connect ICS to ICP
716 comb += self.cpu.irq.eq(icp.core_irq_o) # connect ICP to core
717
718 # wire up the CPU interrupts from the GenericInterrupt
719 comb += self.int_level_i.eq(self.intc.ip)
720
721 # grrr
722 comb += self.pbus.stall.eq(self.pbus.cyc & ~self.pbus.ack)
723 comb += self.sbus.stall.eq(self.sbus.cyc & ~self.sbus.ack)
724
725 # and also wire up make_wb_layout() to wishbone.Interface.
726 # really, XICS_ICS and XICS_ICP both need to be converted
727 # to use wishbone.Interface and this all goes
728 comb += icp.bus.adr.eq(self.pbus.adr)
729 comb += icp.bus.dat_w.eq(self.pbus.dat_w)
730 comb += icp.bus.cyc.eq(self.pbus.cyc)
731 comb += icp.bus.stb.eq(self.pbus.stb)
732 comb += icp.bus.we.eq(self.pbus.we)
733 comb += self.pbus.ack.eq(icp.bus.ack)
734 comb += self.pbus.dat_r.eq(icp.bus.dat_r)
735 comb += ics.bus.adr.eq(self.sbus.adr)
736 comb += ics.bus.dat_w.eq(self.sbus.dat_w)
737 comb += ics.bus.cyc.eq(self.sbus.cyc)
738 comb += ics.bus.stb.eq(self.sbus.stb)
739 comb += ics.bus.we.eq(self.sbus.we)
740 comb += self.sbus.ack.eq(ics.bus.ack)
741 comb += self.sbus.dat_r.eq(ics.bus.dat_r)
742
743 if platform is None:
744 return m
745
746 # add uart16550 verilog source. assumes a directory
747 # structure where ls2 has been checked out in a common
748 # subdirectory as:
749 # git clone https://github.com/freecores/uart16550
750 opencores_16550 = "../../uart16550/rtl/verilog"
751 pth = os.path.split(__file__)[0]
752 pth = os.path.join(pth, opencores_16550)
753 fname = os.path.abspath(pth)
754 print (fname)
755 self.uart.add_verilog_source(fname, platform)
756
757 if hasattr(self, "spi0"):
758 # add spi submodule
759 m.submodules.spi0 = spi = self.spi0
760 # gonna drive me nuts, this.
761 comb += spi.bus.stall.eq(spi.bus.cyc & ~spi.bus.ack)
762 comb += spi.cfg_bus.stall.eq(spi.cfg_bus.cyc & ~spi.cfg_bus.ack)
763
764 # add Tercel verilog source. assumes a directory structure where
765 # microwatt has been checked out in a common subdirectory with:
766 # git clone https://git.libre-soc.org/git/microwatt.git tercel-qspi
767 # git checkout 882ace781e4
768 raptor_tercel = "../../tercel-qspi/tercel"
769 pth = os.path.split(__file__)[0]
770 pth = os.path.join(pth, raptor_tercel)
771 fname = os.path.abspath(pth)
772 print (fname)
773 self.spi0.add_verilog_source(fname, platform)
774
775 if hasattr(self, "eth0"):
776 # add ethernet submodule
777 m.submodules.eth0 = ethmac = self.eth0
778
779 # add EthMAC verilog source. assumes a directory
780 # structure where the opencores ethmac has been checked out
781 # in a common subdirectory as:
782 # git clone https://github.com/freecores/ethmac
783 opencores_ethmac = "../../ethmac/rtl/verilog"
784 pth = os.path.split(__file__)[0]
785 pth = os.path.join(pth, opencores_ethmac)
786 fname = os.path.abspath(pth)
787 print (fname)
788 self.eth0.add_verilog_source(fname, platform)
789
790 # add the main core
791 pth = os.path.split(__file__)[0]
792 pth = os.path.join(pth, '../external_core_top.v')
793 fname = os.path.abspath(pth)
794 with open(fname) as f:
795 platform.add_file(fname, f)
796
797 return m
798
799 def ports(self):
800 # puzzlingly the only IO ports needed are peripheral pins,
801 # and at the moment that's just UART tx/rx.
802 ports = []
803 ports += [self.uart.tx_o, self.uart.rx_i]
804 for hr in self.hyperram:
805 ports += list(hr.ports())
806 if hasattr(self, "ddrphy"):
807 if hasattr(self.ddrphy, "pads"): # real PHY
808 ports += list(self.ddrphy.pads.fields.values())
809 else: # FakePHY, get at the dfii pads, stops deletion of nets
810 for phase in self.dramcore.dfii.master.phases:
811 print ("dfi master", phase)
812 ports += list(phase.fields.values())
813 for phase in self.dramcore.dfii.slave.phases:
814 print ("dfi master", phase)
815 ports += list(phase.fields.values())
816 for phase in self.dramcore.dfii._inti.phases:
817 print ("dfi master", phase)
818 ports += list(phase.fields.values())
819 ports += [ClockSignal(), ResetSignal()]
820 return ports
821
822 def build_platform(fpga, firmware):
823
824 # create a platform selected from the toolchain.
825 platform_kls = {'versa_ecp5': VersaECP5Platform,
826 'versa_ecp5_85': VersaECP5Platform85,
827 'ulx3s': ULX3S_85F_Platform,
828 'orangecrab': OrangeCrabR0_2_85k_Platform,
829 'arty_a7': ArtyA7_100Platform,
830 'isim': IcarusVersaPlatform,
831 'rcs_arctic_tern_bmc_card':None, #TODO
832 'sim': None,
833 }[fpga]
834 toolchain = {'arty_a7': "yosys_nextpnr",
835 'versa_ecp5': 'Trellis',
836 'versa_ecp5_85': 'Trellis',
837 'orangecrab': 'Trellis',
838 'isim': 'Trellis',
839 'ulx3s': 'Trellis',
840 'rcs_arctic_tern_bmc_card': 'Trellis',
841 'sim': None,
842 }.get(fpga, None)
843 dram_cls = {'arty_a7': None,
844 'versa_ecp5': MT41K64M16,
845 'versa_ecp5_85': MT41K64M16,
846 'orangecrab': MT41K64M16,
847 #'versa_ecp5': MT41K256M16,
848 'ulx3s': None,
849 'rcs_arctic_tern_bmc_card': None, # TODO
850 'sim': MT41K256M16,
851 'isim': MT41K64M16,
852 }.get(fpga, None)
853 if platform_kls is not None:
854 platform = platform_kls(toolchain=toolchain)
855 if fpga == 'versa_ecp5_85':
856 platform.speed = "7" # HACK. speed grade 7, sigh
857 else:
858 platform = None
859
860 print ("platform", fpga, firmware, platform)
861
862 # set clock frequency
863 clk_freq = 70e6
864 dram_clk_freq = None
865 if fpga == 'sim':
866 clk_freq = 100e6
867 dram_clk_freq = clk_freq
868 if fpga == 'isim':
869 clk_freq = 50e6 # below 50 mhz, stops DRAM being enabled
870 #dram_clk_freq = clk_freq
871 dram_clk_freq = 100e6
872 if fpga == 'versa_ecp5':
873 clk_freq = 50e6 # crank right down to timing threshold
874 #dram_clk_freq = 55e6
875 if fpga == 'versa_ecp5_85':
876 # 50MHz works. 100MHz works. 55MHz does NOT work.
877 # Stick with multiples of 50MHz...
878 clk_freq = 50e6
879 dram_clk_freq = 100e6
880 if fpga == 'arty_a7':
881 clk_freq = 27.0e6 # urrr "working" with the QSPI core (25 mhz does not)
882 if fpga == 'ulx3s':
883 clk_freq = 40.0e6
884 if fpga == 'orangecrab':
885 clk_freq = 50e6
886
887 # merge dram_clk_freq with clk_freq if the same
888 if clk_freq == dram_clk_freq:
889 dram_clk_freq = None
890
891 # see if dram can be enabled
892 enable_dram = False
893 if dram_clk_freq is not None and dram_clk_freq >= 50e6:
894 enable_dram = True
895 if dram_clk_freq is None and clk_freq >= 50e6:
896 enable_dram = True
897
898 # select a firmware address
899 fw_addr = None
900 if firmware is not None:
901 fw_addr = 0xff00_0000 # firmware at HI address, now
902
903 print ("fpga", fpga, "firmware", firmware)
904
905 # get UART resource pins
906 if platform is not None:
907 if fpga=="orangecrab":
908 # assumes an FT232 USB-UART soldered onto these two pins.
909 orangecrab_uart = UARTResource(0, rx="M18", tx="N17")
910 platform.add_resources([orangecrab_uart])
911
912 uart_pins = platform.request("uart", 0)
913 else:
914 uart_pins = Record([('tx', 1), ('rx', 1)], name="uart_0")
915
916 # get DDR resource pins, disable if clock frequency is below 50 mhz for now
917 ddr_pins = None
918 if (enable_dram and platform is not None and
919 fpga in ['versa_ecp5', 'versa_ecp5_85', 'isim',
920 'orangecrab']): # not yet 'arty_a7',
921 ddr_pins = platform.request("ddr3", 0,
922 dir={"dq":"-", "dqs":"-"},
923 xdr={"rst": 4, "clk":4, "a":4,
924 "ba":4, "clk_en":4,
925 "odt":4, "ras":4, "cas":4, "we":4,
926 "cs": 4})
927 print ("ddr pins", ddr_pins)
928
929 # Get SPI resource pins
930 spi_0_pins = None
931 if False and platform is not None and \
932 fpga in ['versa_ecp5', 'versa_ecp5_85', 'isim']:
933 # Override here to get FlashResource out of the way and enable Tercel
934 # direct access to the SPI flash.
935 # each pin needs a separate direction control
936 spi_0_ios = [
937 Resource("spi_0", 0,
938 Subsignal("dq0", Pins("W2", dir="io")),
939 Subsignal("dq1", Pins("V2", dir="io")),
940 Subsignal("dq2", Pins("Y2", dir="io")),
941 Subsignal("dq3", Pins("W1", dir="io")),
942 Subsignal("cs_n", Pins("R2", dir="o")),
943 Attrs(PULLMODE="NONE", DRIVE="4", IO_TYPE="LVCMOS33"))
944 ]
945 platform.add_resources(spi_0_ios)
946 spi_0_pins = platform.request("spi_0", 0, dir={"cs_n":"o"},
947 xdr={"dq0":1, "dq1": 1,
948 "dq2":1, "dq3": 1,
949 "cs_n":0})
950
951 if platform is not None and \
952 fpga in ['arty_a7']:
953 # each pin needs a separate direction control
954 spi_0_ios = [
955 Resource("spi_0", 0,
956 Subsignal("dq0", Pins("K17", dir="io")),
957 Subsignal("dq1", Pins("K18", dir="io")),
958 Subsignal("dq2", Pins("L14", dir="io")),
959 Subsignal("dq3", Pins("M14", dir="io")),
960 Subsignal("cs_n", Pins("L13", dir="o")),
961 Subsignal("clk", Pins("L16", dir="o")),
962 Attrs(PULLMODE="NONE", DRIVE="4", IO_TYPE="LVCMOS33"))
963 ]
964 platform.add_resources(spi_0_ios)
965 spi_0_pins = platform.request("spi_0", 0)
966
967 orangecrab_enable_spi = False
968 if orangecrab_enable_spi and platform is not None and \
969 fpga in ['orangecrab']:
970 # spi_flash_mosi <= spi_sdat_o(0) when spi_sdat_oe(0) = '1' else 'Z';
971 # spi_flash_miso <= spi_sdat_o(1) when spi_sdat_oe(1) = '1' else 'Z';
972 # spi_flash_wp_n <= spi_sdat_o(2) when spi_sdat_oe(2) = '1' else 'Z';
973 # spi_flash_hold_n <= spi_sdat_o(3) when spi_sdat_oe(3) = '1' else 'Z';
974 # cs_n="U17", clk="U16", miso="T18", mosi="U18", wp_n="R18", hold_n="N18"
975 # each pin needs a separate direction control
976 spi_0_ios = [
977 Resource("spi_0", 0,
978 Subsignal("dq0", Pins("U18", dir="io")), #mosi
979 Subsignal("dq1", Pins("T18", dir="io")), #miso
980 Subsignal("dq2", Pins("R18", dir="io")), #wp_n
981 Subsignal("dq3", Pins("N18", dir="io")), #hold_n
982 # We use USRMCLK instead for clk
983 # todo: read docs
984 Subsignal("cs_n", Pins("U17", dir="o")),
985 # Subsignal("clk", Pins("U16", dir="o")),
986 Attrs(PULLMODE="NONE", DRIVE="4", IO_TYPE="LVCMOS33"))
987 ]
988 platform.add_resources(spi_0_ios)
989 spi_0_pins = platform.request("spi_0", 0, dir={"cs_n":"o"},
990 xdr={"dq0":1, "dq1": 1,
991 "dq2":1, "dq3": 1,
992 "cs_n":0})
993
994 print ("spiflash pins", spi_0_pins)
995
996 # Get Ethernet RMII resource pins
997 ethmac_0_pins = None
998 if False and platform is not None and \
999 fpga in ['versa_ecp5', 'versa_ecp5_85', 'isim']:
1000 # Mainly on X3 connector, MDIO on X4 due to lack of pins
1001 ethmac_0_ios = [
1002 Resource("ethmac_0", 0,
1003 Subsignal("mtx_clk", Pins("B19", dir="i")),
1004 Subsignal("mtxd", Pins("B12 B9 E6 D6", dir="o")),
1005 Subsignal("mtxen", Pins("E7", dir="o")),
1006 Subsignal("mtxerr", Pins("D7", dir="o")),
1007 Subsignal("mrx_clk", Pins("B11", dir="i")),
1008 Subsignal("mrxd", Pins("B6 E9 D9 B8", dir="i")),
1009 Subsignal("mrxdv", Pins("C8", dir="i")),
1010 Subsignal("mrxerr", Pins("D8", dir="i")),
1011 Subsignal("mcoll", Pins("E8", dir="i")),
1012 Subsignal("mcrs", Pins("C7", dir="i")),
1013 Subsignal("mdc", Pins("B18", dir="o")),
1014 Subsignal("md", Pins("A18", dir="io")),
1015 Attrs(PULLMODE="NONE", DRIVE="8", SLEWRATE="FAST",
1016 IO_TYPE="LVCMOS33"))
1017 ]
1018 platform.add_resources(ethmac_0_ios)
1019 ethmac_0_pins = platform.request("ethmac_0", 0,
1020 dir={"mtx_clk":"i", "mtxd":"o",
1021 "mtxen":"o",
1022 "mtxerr":"o", "mrx_clk":"i",
1023 "mrxd":"i",
1024 "mrxdv":"i", "mrxerr":"i",
1025 "mcoll":"i",
1026 "mcrs":"i", "mdc":"o", "md":"io"},
1027 xdr={"mtx_clk": 0, "mtxd": 0,
1028 "mtxen": 0,
1029 "mtxerr": 0, "mrx_clk": 0,
1030 "mrxd": 0,
1031 "mrxdv": 0, "mrxerr": 0,
1032 "mcoll": 0,
1033 "mcrs": 0, "mdc": 0, "md": 0})
1034 print ("ethmac pins", ethmac_0_pins)
1035
1036 # Get HyperRAM pins
1037 hyperram_pins = []
1038 hyperram_addr = [0xa000_0000]
1039 if platform is None:
1040 hyperram_pins = [HyperRAMPads()]
1041 elif fpga in ['isim']:
1042 hyperram_ios = HyperRAMResource(0, cs_n="B13",
1043 dq="E14 C10 B10 E12 D12 A9 D11 D14",
1044 rwds="C14", rst_n="E13", ck_p="D13",
1045 attrs=Attrs(IO_TYPE="LVCMOS33"))
1046 platform.add_resources(hyperram_ios)
1047 hyperram_pins = [platform.request("hyperram")]
1048 print ("isim a7 hyperram", hyperram_ios)
1049 # Digilent Arty A7-100t
1050 elif platform is not None and fpga in ['arty_a7']:
1051 hyperram_ios = HyperRAMResource(0, cs_n="B11 B18 G13 D13",
1052 dq="E15 E16 D15 C15 J15 K15 J18 J17",
1053 rwds="K16", rst_n="A18", ck_p="A11",
1054 # ck_n="D12" - for later (DDR)
1055 attrs=Attrs(IOSTANDARD="LVCMOS33"))
1056 platform.add_resources(hyperram_ios)
1057 hyperram_ios = HyperRAMResource(1, cs_n="V12 V14 U12 U14",
1058 dq="D4 D3 F4 F3 G2 H2 D2 E2",
1059 rwds="U13", rst_n="T13", ck_p="V10",
1060 # ck_n="V11" - for later (DDR)
1061 attrs=Attrs(IOSTANDARD="LVCMOS33"))
1062 platform.add_resources(hyperram_ios)
1063 hyperram_pins = [platform.request("hyperram", 0),
1064 platform.request("hyperram", 1)]
1065 print ("arty a7 hyperram", hyperram_ios)
1066 hyperram_addr=[0x0000_0000, # HYPERRAM_BASE1
1067 0x0200_0000] # HYPERRAM_BASE2
1068 # VERSA ECP5
1069 elif False and platform is not None and fpga in \
1070 ['versa_ecp5', 'versa_ecp5_85']:
1071 hyperram_ios = HyperRAMResource(0, cs_n="B13",
1072 dq="E14 C10 B10 E12 D12 A9 D11 D14",
1073 rwds="C14", rst_n="E13", ck_p="D13",
1074 attrs=Attrs(IO_TYPE="LVCMOS33"))
1075 platform.add_resources(hyperram_ios)
1076 hyperram_pins = [platform.request("hyperram")]
1077 print ("versa ecp5 hyperram", hyperram_ios)
1078 print ("hyperram pins", hyperram_pins)
1079
1080 # set up the SOC
1081 soc = DDR3SoC(fpga=fpga, dram_cls=dram_cls,
1082 # check microwatt_soc.h for these
1083 ddrphy_addr=0xfff00000, # DRAM_INIT_BASE, PHY address
1084 dramcore_addr=0xc8000000, # DRAM_CTRL_BASE
1085 ddr_addr=0x00000000, # DRAM_BASE
1086 spi0_addr=0xf0000000, # SPI0_BASE
1087 spi0_cfg_addr=0xc0006000, # SPI0_CTRL_BASE
1088 eth0_cfg_addr=0xc000c000, # ETH0_CTRL_BASE (4k)
1089 eth0_irqno=1, # ETH0_IRQ number (match microwatt)
1090 hyperram_addr=hyperram_addr, # determined above
1091 fw_addr=fw_addr,
1092 #fw_addr=None,
1093 ddr_pins=ddr_pins,
1094 uart_pins=uart_pins,
1095 uart_irqno=0, # UART_IRQ number (match microwatt)
1096 uart_addr=0xc0002000, # UART0_ADDR
1097 spi_0_pins=spi_0_pins,
1098 ethmac_0_pins=ethmac_0_pins,
1099 hyperram_pins=hyperram_pins,
1100 firmware=firmware,
1101 xics_icp_addr=0xc000_4000, # XICS_ICP_BASE
1102 xics_ics_addr=0xc000_5000, # XICS_ICS_BASE
1103 clk_freq=clk_freq,
1104 dram_clk_freq=dram_clk_freq,
1105 add_cpu=True)
1106
1107 if toolchain == 'Trellis':
1108 # add -abc9 option to yosys synth_ecp5
1109 os.environ['NMIGEN_synth_opts'] = '-abc9' # optimize for speed
1110 # os.environ['NMIGEN_synth_opts'] = '-nowidelut' # optimize for size
1111 # os.environ['NMIGEN_synth_opts'] = '-abc9 -nowidelut' # conflicting goals
1112
1113 if toolchain == 'yosys_nextpnr':
1114 # add --seed 2 to arty a7 compile-time options
1115 freq = clk_freq/1e6
1116 os.environ['NMIGEN_nextpnr_opts'] = '--seed 3 --freq %.1f' % freq
1117 os.environ['NMIGEN_nextpnr_opts'] += ' --timing-allow-fail'
1118
1119 if platform is not None:
1120 # build and upload it
1121 if fpga == 'isim':
1122 platform.build(soc, do_program=False,
1123 do_build=True, build_dir="build_simsoc")
1124 else:
1125 platform.build(soc, do_program=True)
1126 else:
1127 # for now, generate verilog
1128 vl = verilog.convert(soc, ports=soc.ports())
1129 with open("ls2.v", "w") as f:
1130 f.write(vl)
1131
1132
1133 # urrr this gets exec()d by the build process without arguments
1134 # which screws up. use the arty_a7_ls2.py etc. with no arguments
1135 if __name__ == '__main__':
1136 fpga = None
1137 firmware = None
1138 if len(sys.argv) >= 2:
1139 fpga = sys.argv[1]
1140 if len(sys.argv) >= 3:
1141 firmware = sys.argv[2]
1142 build_platform(fpga, firmware)