periph.serial: add PHY as parameter, in order to use a blackbox.
[lambdasoc.git] / examples / sdram_soc.py
1 import argparse
2
3 from nmigen import *
4 from nmigen.build import *
5 from nmigen_soc import wishbone
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.sdram import SDRAMPeripheral
13 from lambdasoc.soc.cpu import CPUSoC
14
15 from lambdasoc.cores import litedram
16
17
18 __all__ = ["SDRAMSoC"]
19
20
21 class SDRAMSoC(CPUSoC, Elaboratable):
22 def __init__(self, *, reset_addr, clk_freq,
23 rom_addr, rom_size,
24 ram_addr, ram_size,
25 uart_addr, uart_divisor, uart_pins,
26 timer_addr, timer_width,
27 sdram_addr, sdram_core, sdram_cache_size):
28 self._arbiter = wishbone.Arbiter(addr_width=30, data_width=32, granularity=8,
29 features={"cti", "bte"})
30 self._decoder = wishbone.Decoder(addr_width=30, data_width=32, granularity=8,
31 features={"cti", "bte"})
32
33 self.cpu = MinervaCPU(
34 reset_address=reset_addr,
35 with_icache=True, icache_nlines=64, icache_nwords=4, icache_nways=1,
36 icache_base=sdram_addr, icache_limit=sdram_addr + sdram_core.size,
37 with_dcache=True, dcache_nlines=64, dcache_nwords=4, dcache_nways=1,
38 dcache_base=sdram_addr, dcache_limit=sdram_addr + sdram_core.size,
39 with_muldiv=True,
40 )
41 self._arbiter.add(self.cpu.ibus)
42 self._arbiter.add(self.cpu.dbus)
43
44 self.rom = SRAMPeripheral(size=rom_size, writable=False)
45 self._decoder.add(self.rom.bus, addr=rom_addr)
46
47 self.ram = SRAMPeripheral(size=ram_size)
48 self._decoder.add(self.ram.bus, addr=ram_addr)
49
50 self.sdram = SDRAMPeripheral(core=sdram_core, cache_size=sdram_cache_size)
51 self._decoder.add(self.sdram.bus, addr=sdram_addr)
52
53 self.uart = AsyncSerialPeripheral(divisor=uart_divisor, pins=uart_pins)
54 self._decoder.add(self.uart.bus, addr=uart_addr)
55
56 self.timer = TimerPeripheral(width=timer_width)
57 self._decoder.add(self.timer.bus, addr=timer_addr)
58
59 self.intc = GenericInterruptController(width=len(self.cpu.ip))
60 self.intc.add_irq(self.timer.irq, 0)
61 self.intc.add_irq(self.uart .irq, 1)
62
63 self.memory_map = self._decoder.bus.memory_map
64
65 self.clk_freq = clk_freq
66
67 def elaborate(self, platform):
68 m = Module()
69
70 m.domains += [
71 ClockDomain("litedram_input"),
72 ClockDomain("litedram_user"),
73 ClockDomain("sync"),
74 ]
75
76 m.d.comb += [
77 ClockSignal("litedram_input").eq(platform.request("clk100", 0).i),
78
79 ClockSignal("sync").eq(ClockSignal("litedram_user")),
80 ResetSignal("sync").eq(ResetSignal("litedram_user")),
81 ]
82
83 m.submodules.arbiter = self._arbiter
84 m.submodules.cpu = self.cpu
85
86 m.submodules.decoder = self._decoder
87 m.submodules.rom = self.rom
88 m.submodules.ram = self.ram
89 m.submodules.sdram = self.sdram
90 m.submodules.uart = self.uart
91 m.submodules.timer = self.timer
92 m.submodules.intc = self.intc
93
94 m.d.comb += [
95 self._arbiter.bus.connect(self._decoder.bus),
96 self.cpu.ip.eq(self.intc.ip),
97 ]
98
99 return m
100
101
102 if __name__ == "__main__":
103 parser = argparse.ArgumentParser()
104 parser.add_argument("--platform", type=str,
105 choices=("arty_a7", "ecpix5_85"),
106 help="target platform")
107 parser.add_argument("--baudrate", type=int,
108 default=9600,
109 help="UART baudrate (default: 9600)")
110 parser.add_argument("--build-dir", type=str,
111 default="build",
112 help="local build directory (default: 'build')")
113 args = parser.parse_args()
114
115 if args.platform == "arty_a7":
116 from nmigen_boards.arty_a7 import ArtyA7_35Platform
117 platform = ArtyA7_35Platform()
118 litedram_cfg = litedram.Artix7Config(
119 memtype = "DDR3",
120 speedgrade = "-1",
121 cmd_latency = 0,
122 module_name = "MT41K128M16",
123 module_bytes = 2,
124 module_ranks = 1,
125 rtt_nom = 60,
126 rtt_wr = 60,
127 ron = 34,
128 input_clk_freq = int(100e6),
129 user_clk_freq = int(100e6),
130 iodelay_clk_freq = int(200e6),
131 )
132 elif args.platform == "ecpix5_85":
133 from nmigen_boards.ecpix5 import ECPIX585Platform
134 platform = ECPIX585Platform()
135 litedram_cfg = litedram.ECP5Config(
136 memtype = "DDR3",
137 module_name = "MT41K256M16",
138 module_bytes = 2,
139 module_ranks = 1,
140 input_clk_freq = int(100e6),
141 user_clk_freq = int(70e6),
142 init_clk_freq = int(25e6),
143 )
144 else:
145 assert False
146
147 litedram_pins = litedram_cfg.request_pins(platform, "ddr3", 0)
148 litedram_core = litedram.Core(litedram_cfg, pins=litedram_pins)
149
150 litedram_builder = litedram.Builder()
151 litedram_build_dir = f"{args.build_dir}/litedram"
152 litedram_products = litedram_core.build(litedram_builder, build_dir=litedram_build_dir)
153
154 litedram_core_v = f"{litedram_core.name}/{litedram_core.name}.v"
155 platform.add_file(litedram_core_v, litedram_products.get(litedram_core_v, mode="t"))
156
157 soc = SDRAMSoC(
158 reset_addr=0x30000000, clk_freq=litedram_cfg.user_clk_freq,
159 uart_addr=0x00005000, uart_divisor=int(litedram_cfg.user_clk_freq // args.baudrate),
160 uart_pins=platform.request("uart", 0),
161 timer_addr=0x00006000, timer_width=32,
162
163 rom_addr=0x30000000, rom_size=0x8000,
164 ram_addr=0x30008000, ram_size=0x1000,
165 sdram_addr=0x40000000, sdram_core=litedram_core, sdram_cache_size=8192,
166 )
167
168 soc.build(build_dir=f"{args.build_dir}/soc", litedram_dir=litedram_build_dir, do_init=True)
169
170 platform.build(soc, build_dir=args.build_dir, do_program=True)