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