examples: Make frequency a parameter
[gram.git] / examples / soc.py
1 # This file is Copyright (c) 2020 LambdaConcept <contact@lambdaconcept.com>
2
3 from nmigen import *
4 from nmigen.lib.cdc import ResetSynchronizer
5 from nmigen_soc import wishbone, memory
6
7 from lambdasoc.cpu.minerva import MinervaCPU
8 from lambdasoc.periph.intc import GenericInterruptController
9 from lambdasoc.periph.serial import AsyncSerialPeripheral
10 from lambdasoc.periph.sram import SRAMPeripheral
11 from lambdasoc.periph.timer import TimerPeripheral
12 from lambdasoc.periph import Peripheral
13 from lambdasoc.soc.base import SoC
14
15 from gram.core import gramCore
16 from gram.phy.ecp5ddrphy import ECP5DDRPHY
17 from gram.modules import MT41K256M16
18 from gram.frontend.wishbone import gramWishbone
19
20 from nmigen_boards.ecpix5 import *
21 from uartbridge import UARTBridge
22 from crg import *
23
24 class DDR3SoC(SoC, Elaboratable):
25 def __init__(self, *,
26 uart_pins, ddr_pins,
27 ddrphy_addr, dramcore_addr,
28 ddr_addr):
29 self._arbiter = wishbone.Arbiter(addr_width=30, data_width=32, granularity=8,
30 features={"cti", "bte"})
31 self._decoder = wishbone.Decoder(addr_width=30, data_width=32, granularity=8,
32 features={"cti", "bte"})
33
34 freq = 100e6
35
36 self.crg = ECPIX5CRG()
37
38 self.cpu = MinervaCPU(reset_address=0)
39 self._arbiter.add(self.cpu.ibus)
40 self._arbiter.add(self.cpu.dbus)
41 self.intc = GenericInterruptController(width=len(self.cpu.ip))
42
43 self.rom = SRAMPeripheral(size=4096, writable=False)
44 with open("firmware/main.bin", "rb") as f:
45 words = iter(lambda: f.read(self.cpu.data_width // 8), b'')
46 bios = [int.from_bytes(w, self.cpu.byteorder) for w in words]
47 self.rom.init = bios
48 self._decoder.add(self.rom.bus, addr=0)
49
50 self.ram = SRAMPeripheral(size=4096)
51 self._decoder.add(self.ram.bus, addr=0x1000)
52
53 self.uart = AsyncSerialPeripheral(divisor=int(freq//115200), pins=uart_pins)
54 self._decoder.add(self.uart.bus, addr=0x2000)
55
56
57 self.ddrphy = DomainRenamer("dramsync")(ECP5DDRPHY(ddr_pins))
58 self._decoder.add(self.ddrphy.bus, addr=ddrphy_addr)
59
60 ddrmodule = MT41K256M16(freq, "1:2")
61
62 self.dramcore = DomainRenamer("dramsync")(gramCore(
63 phy=self.ddrphy,
64 geom_settings=ddrmodule.geom_settings,
65 timing_settings=ddrmodule.timing_settings,
66 clk_freq=freq))
67 self._decoder.add(self.dramcore.bus, addr=dramcore_addr)
68
69 self.drambone = DomainRenamer("dramsync")(gramWishbone(self.dramcore))
70 self._decoder.add(self.drambone.bus, addr=ddr_addr)
71
72 self.memory_map = self._decoder.bus.memory_map
73
74 self.clk_freq = freq
75
76 def elaborate(self, platform):
77 m = Module()
78
79 m.submodules.sysclk = self.crg
80
81 m.submodules.rom = self.rom
82 m.submodules.ram = self.ram
83 m.submodules.uart = self.uart
84 m.submodules.intc = self.intc
85 m.submodules.cpu = self.cpu
86 m.submodules.arbiter = self._arbiter
87 m.submodules.decoder = self._decoder
88 m.submodules.ddrphy = self.ddrphy
89 m.submodules.dramcore = self.dramcore
90 m.submodules.drambone = self.drambone
91
92 m.d.comb += [
93 self._arbiter.bus.connect(self._decoder.bus),
94 self.cpu.ip.eq(self.intc.ip),
95 ]
96
97 return m
98
99
100 if __name__ == "__main__":
101 platform = ECPIX585Platform()
102
103 ddr_pins = platform.request("ddr3", 0, dir={"dq":"-", "dqs":"-"},
104 xdr={"clk":4, "a":4, "ba":4, "clk_en":4, "odt":4, "ras":4, "cas":4, "we":4})
105 uart_pins = platform.request("uart", 0)
106
107 soc = DDR3SoC(ddrphy_addr=0x00008000, dramcore_addr=0x00009000,
108 ddr_addr=0x10000000, ddr_pins=ddr_pins, uart_pins=uart_pins)
109
110 platform.build(soc, do_program=True)