b90913d1ce704fa69aa65839c986bdea330295fa
[soc.git] / src / soc / bus / external_core.py
1 #!/usr/bin/env python3
2 #
3 # SPDX-License-Identifier: LGPLv3+
4 # Copyright (C) 2022 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
5 # Sponsored by NLnet and NGI POINTER under EU Grants 871528 and 957073
6 # Part of the Libre-SOC Project.
7 #
8 # this is a wrapper around the opencores verilog core16550 module
9
10 from nmigen import (Elaboratable, Cat, Module, Signal, ClockSignal, Instance,
11 ResetSignal, Const)
12 from nmigen.cli import rtlil, verilog
13
14 from soc.debug.dmi import DMIInterface
15 from nmigen_soc.wishbone.bus import Interface
16 import os
17
18 __all__ = ["ExternalCore"]
19
20
21 class ExternalCore(Elaboratable):
22 """External Core verilog wrapper for microwatt and libre-soc
23 (actually, anything prepared to map to the Signals defined below)
24 remember to call ExternalCore.add_verilog_source
25 """
26
27 def __init__(self, ibus=None, dbus=None, features=None, name=None):
28
29 # set up the icache wishbone bus
30 if features is None:
31 features = frozenset(("stall",))
32 if ibus is None:
33 ibus = Interface(addr_width=32,
34 data_width=64,
35 features=features,
36 granularity=8,
37 name="core_ibus")
38 if dbus is None:
39 dbus = Interface(addr_width=32,
40 data_width=64,
41 features=features,
42 granularity=8,
43 name="core_dbus")
44 self.dmi = DMIInterface(name="dmi")
45 self.ibus = ibus
46 self.dbus = dbus
47
48 assert len(self.ibus.dat_r) == 64, "bus width must be 64"
49 assert len(self.dbus.dat_r) == 64, "bus width must be 64"
50
51 # IRQ for data buffer receive/xmit
52 self.irq = Signal()
53
54 # debug monitoring signals
55 self.nia = Signal(64)
56 self.nia_req = Signal()
57 self.msr = Signal(64)
58 self.ldst_addr = Signal(64)
59 self.ldst_req = Signal()
60
61 # alternative reset and termination indicator
62 self.alt_reset = Signal()
63 self.terminated_o = Signal()
64
65 @classmethod
66 def add_verilog_source(cls, verilog_src_dir, platform):
67 # add each of the verilog sources, needed for when doing platform.build
68 for fname in ['external_core_top.v',
69 ]:
70 # prepend the src directory to each filename, add its contents
71 fullname = os.path.join(verilog_src_dir, fname)
72 with open(fullname) as f:
73 platform.add_file(fullname, f)
74
75 def elaborate(self, platform):
76 m = Module()
77 comb = m.d.comb
78
79 # create definition of external core here, so that
80 # nmigen understands I/O directions (defined by i_ and o_ prefixes)
81 ibus, dbus, dmi = self.ibus, self.dbus, self.dmi
82
83 # sigh, microwatt wishbone address is borked, it contains the 3 LSBs
84 ibus_adr = Signal(32)
85 dbus_adr = Signal(32)
86 m.d.comb += ibus.adr.eq(ibus_adr[3:])
87 m.d.comb += dbus.adr.eq(dbus_adr[3:])
88
89 kwargs = {
90 # clock/reset signals
91 'i_clk': ClockSignal(),
92 'i_rst': ResetSignal(),
93 # DMI interface
94 'i_dmi_addr': dmi.addr_i,
95 'i_dmi_req': dmi.req_i,
96 'i_dmi_wr': dmi.we_i,
97 'i_dmi_din': dmi.din,
98 'o_dmi_dout': dmi.dout,
99 'o_dmi_ack': dmi.ack_o,
100 # debug/monitor signals
101 'o_nia': self.nia,
102 'o_nia_req': self.nia_req,
103 'o_msr_o': self.msr,
104 'o_ldst_addr': self.ldst_addr,
105 'o_ldst_req': self.ldst_req,
106 'i_alt_reset': self.alt_reset,
107 'o_terminated_out': self.terminated_o,
108 # wishbone instruction bus
109 'o_wishbone_insn_out.adr': ibus_adr,
110 'o_wishbone_insn_out.dat': ibus.dat_w,
111 'o_wishbone_insn_out.sel': ibus.sel,
112 'o_wishbone_insn_out.cyc': ibus.cyc,
113 'o_wishbone_insn_out.stb': ibus.stb,
114 'o_wishbone_insn_out.we': ibus.we,
115 'i_wishbone_insn_in.dat': ibus.dat_r,
116 'i_wishbone_insn_in.ack': ibus.ack,
117 'i_wishbone_insn_in.stall': ibus.stall,
118 # wishbone data bus
119 'o_wishbone_data_out.adr': dbus_adr,
120 'o_wishbone_data_out.dat': dbus.dat_w,
121 'o_wishbone_data_out.sel': dbus.sel,
122 'o_wishbone_data_out.cyc': dbus.cyc,
123 'o_wishbone_data_out.stb': dbus.stb,
124 'o_wishbone_data_out.we': dbus.we,
125 'i_wishbone_data_in.dat': dbus.dat_r,
126 'i_wishbone_data_in.ack': dbus.ack,
127 'i_wishbone_data_in.stall': dbus.stall,
128 # external interrupt request
129 'i_ext_irq': self.irq,
130 }
131 core = Instance("external_core_top", **kwargs)
132 m.submodules['core_top'] = core
133
134 return m
135
136
137 def create_ilang(dut, ports, test_name):
138 vl = rtlil.convert(dut, name=test_name, ports=ports)
139 with open("%s.il" % test_name, "w") as f:
140 f.write(vl)
141
142 def create_verilog(dut, ports, test_name):
143 vl = verilog.convert(dut, name=test_name, ports=ports)
144 with open("%s.v" % test_name, "w") as f:
145 f.write(vl)
146
147
148 if __name__ == "__main__":
149 core = ExternalCore(name="core")
150 create_ilang(core, [
151 core.ibus.cyc, core.ibus.stb, core.ibus.ack,
152 core.ibus.dat_r, core.ibus.dat_w, core.ibus.adr,
153 core.ibus.we, core.ibus.sel, core.ibus.stall,
154 core.dbus.cyc, core.dbus.stb, core.dbus.ack,
155 core.dbus.dat_r, core.dbus.dat_w, core.dbus.adr,
156 core.dbus.we, core.dbus.sel,
157 core.irq, core.alt_reset, core.terminated_o,
158 core.msr, core.nia, core.nia_req,
159 core.ldst_addr, core.ldst_req,
160 core.dmi.addr_i, core.dmi.req_i, core.dmi.we_i,
161 core.dmi.din, core.dmi.dout, core.dmi.ack_o,
162 ], "core_0")
163