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