133df974bac22211ec945e320032385ea1a77f8f
[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)
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
78 # create definition of external core here, so that
79 # nmigen understands I/O directions (defined by i_ and o_ prefixes)
80 ibus, dbus, dmi = self.ibus, self.dbus, self.dmi
81 kwargs = {
82 # clock/reset signals
83 'i_clk': ClockSignal(),
84 'i_rst': ResetSignal(),
85 # DMI interface
86 'i_dmi_addr': dmi.addr_i,
87 'i_dmi_req': dmi.req_i,
88 'i_dmi_wr': dmi.we_i,
89 'i_dmi_din': dmi.din,
90 'o_dmi_dout': dmi.dout,
91 'o_dmi_ack': dmi.ack_o,
92 # debug/monitor signals
93 'o_nia': self.nia,
94 'o_nia_req': self.nia_req,
95 'o_msr_o': self.msr,
96 'o_ldst_addr': self.ldst_addr,
97 'o_ldst_req': self.ldst_req,
98 'i_alt_reset': self.alt_reset,
99 'o_terminated_out': self.terminated_o,
100 # wishbone instruction bus
101 'o_wishbone_insn_out.adr': ibus.adr,
102 'o_wishbone_insn_out.dat': ibus.dat_w,
103 'o_wishbone_insn_out.sel': ibus.sel,
104 'o_wishbone_insn_out.cyc': ibus.cyc,
105 'o_wishbone_insn_out.stb': ibus.stb,
106 'o_wishbone_insn_out.we': ibus.we,
107 'i_wishbone_insn_in.dat': ibus.dat_r,
108 'i_wishbone_insn_in.ack': ibus.ack,
109 'i_wishbone_insn_in.stall': ibus.stall,
110 # wishbone data bus
111 'o_wishbone_data_out.adr': dbus.adr,
112 'o_wishbone_data_out.dat': dbus.dat_w,
113 'o_wishbone_data_out.sel': dbus.sel,
114 'o_wishbone_data_out.cyc': dbus.cyc,
115 'o_wishbone_data_out.stb': dbus.stb,
116 'o_wishbone_data_out.we': dbus.we,
117 'i_wishbone_data_in.dat': dbus.dat_r,
118 'i_wishbone_data_in.ack': dbus.ack,
119 'i_wishbone_data_in.stall': dbus.stall,
120 # external interrupt request
121 'i_ext_irq': self.irq,
122 }
123 core = Instance("external_core_top", **kwargs)
124 m.submodules['core_top'] = core
125
126 return m
127
128
129 def create_ilang(dut, ports, test_name):
130 vl = rtlil.convert(dut, name=test_name, ports=ports)
131 with open("%s.il" % test_name, "w") as f:
132 f.write(vl)
133
134 def create_verilog(dut, ports, test_name):
135 vl = verilog.convert(dut, name=test_name, ports=ports)
136 with open("%s.v" % test_name, "w") as f:
137 f.write(vl)
138
139
140 if __name__ == "__main__":
141 core = ExternalCore(name="core")
142 create_ilang(core, [
143 core.ibus.cyc, core.ibus.stb, core.ibus.ack,
144 core.ibus.dat_r, core.ibus.dat_w, core.ibus.adr,
145 core.ibus.we, core.ibus.sel, core.ibus.stall,
146 core.dbus.cyc, core.dbus.stb, core.dbus.ack,
147 core.dbus.dat_r, core.dbus.dat_w, core.dbus.adr,
148 core.dbus.we, core.dbus.sel,
149 core.irq, core.alt_reset, core.terminated_o,
150 core.msr, core.nia, core.nia_req,
151 core.ldst_addr, core.ldst_req,
152 core.dmi.addr_i, core.dmi.req_i, core.dmi.we_i,
153 core.dmi.din, core.dmi.dout, core.dmi.ack_o,
154 ], "core_0")
155