CIRCT 23.0.0git
Loading...
Searching...
No Matches
loopback.py
Go to the documentation of this file.
1# REQUIRES: esi-cosim, esi-runtime, rtl-sim
2# RUN: rm -rf %t
3# RUN: mkdir %t && cd %t
4
5# Build the system.
6# RUN: %PYTHON% %s %t 2>&1
7
8# Query against the manifest.
9# RUN: esiquery trace w:%t/esi_system_manifest.json info | FileCheck %s --check-prefix=QUERY-INFO
10# RUN: esiquery trace w:%t/esi_system_manifest.json hier | FileCheck %s --check-prefix=QUERY-HIER
11
12# Run a cosimulation with a python test driver.
13# RUN: esi-cosim.py --source %t -- %PYTHON% %S/test_software/loopback.py cosim env
14
15# Test C++ header generation against the manifest file.
16# Use the shared CMake build to compile the C++ test against generated headers.
17# RUN: %PYTHON% -m esiaccel.codegen --file %t/esi_system_manifest.json --output-dir %t/include/loopback/
18# RUN: cmake -S %S/test_software -B %t/loopback-build -DLOOPBACK_GENERATED_DIR=%t/include -DESI_RUNTIME_ROOT=%ESI_RUNTIME_PATH%
19# RUN: cmake --build %t/loopback-build --target loopback_test
20# RUN: esi-cosim.py --source %t -- %t/loopback-build/loopback_test cosim env | FileCheck %s --check-prefix=CPP-TEST
21# RUN: FileCheck %s --check-prefix=LOOPBACK-H --input-file %t/include/loopback/LoopbackIP.h
22
23# Test C++ header generation from the live accelerator.
24# The generated headers are still required to build the C++ test executable.
25# RUN: esi-cosim.py --source %t -- %PYTHON% -m esiaccel.codegen --platform cosim --connection env --output-dir %t/include/loopback/
26# RUN: cmake -S %S/test_software -B %t/loopback-build -DLOOPBACK_GENERATED_DIR=%t/include -DESI_RUNTIME_ROOT=%ESI_RUNTIME_PATH%
27# RUN: cmake --build %t/loopback-build --target loopback_test
28# RUN: esi-cosim.py --source %t -- %t/loopback-build/loopback_test cosim env | FileCheck %s --check-prefix=CPP-TEST
29
30import sys
31
32from pycde import (AppID, Clock, Module, Reset, Signal, System, generator)
33from pycde.bsp import get_bsp
34from pycde.common import Constant
35from pycde.constructs import Wire
36from pycde.module import Metadata
37from pycde.signals import Struct
38from pycde.types import (Bits, Bundle, BundledChannel, Channel,
39 ChannelDirection, SInt, TypeAlias, UInt)
40from pycde import esi
41
42SendI8 = Bundle([BundledChannel("send", ChannelDirection.FROM, Bits(8))])
43RecvI8 = Bundle([BundledChannel("recv", ChannelDirection.TO, Bits(8))])
44SendI0 = Bundle([BundledChannel("send", ChannelDirection.FROM, Bits(0))])
45RecvI0 = Bundle([BundledChannel("recv", ChannelDirection.TO, Bits(0))])
46
47
48@esi.ServiceDecl
50 Send = SendI8
51 Recv = RecvI8
52
53
54@esi.ServiceDecl
56 Send = SendI0
57 Recv = RecvI0
58
59
60class Loopback(Module):
61 clk = Clock()
62
63 metadata = Metadata(
64 name="LoopbackIP",
65 version="v0.0",
66 summary="IP which simply echos bytes",
67 misc={"foo": 1},
68 )
69
70 depth = Constant(UInt(32), 5)
71
72 @generator
73 def construct(ports):
74 data_in_bundle = HostComms.Recv(AppID("loopback_tohw"))
75 data_in = data_in_bundle.unpack()["recv"]
76
77 data_out_bundle = HostComms.Send(AppID("loopback_fromhw"))
78 data_out_bundle.unpack(send=data_in)
79
80 send_bundle = MyService.Recv(AppID("mysvc_recv"))
81 send_chan = send_bundle.unpack()["recv"]
82 sendi0_bundle = MyService.Send(AppID("mysvc_send"))
83 sendi0_bundle.unpack(send=send_chan)
84
85
86class ArgStruct(Struct):
87 a: UInt(16)
88 b: SInt(8)
89
90
91class ResultStruct(Struct):
92 x: SInt(8)
93 y: SInt(8)
94
95
96class OddInner(Struct):
97 p: UInt(8)
98 q: SInt(8)
99 r: UInt(8) * 2
100
101
102class OddStruct(Struct):
103 a: UInt(12)
104 b: SInt(7)
105 inner: OddInner
106
107
108class LoopbackStruct(Module):
109
110 @generator
111 def construct(ports):
112 result_wire = Wire(Channel(ResultStruct))
113 args = esi.FuncService.get_call_chans(AppID("structFunc"),
114 arg_type=ArgStruct,
115 result=result_wire)
116
117 ready = Wire(Bits(1))
118 arg_data, valid = args.unwrap(ready)
119 b_val = arg_data["b"]
120 b_plus_one = (b_val + SInt(8)(1)).as_sint(8)
121 result = ResultStruct(x=b_plus_one, y=b_val)
122 result_chan, result_ready = Channel(ResultStruct).wrap(result, valid)
123 ready.assign(result_ready)
124 result_wire.assign(result_chan)
125
126
127class LoopbackOddStruct(Module):
128
129 @generator
130 def construct(ports):
131 result_wire = Wire(Channel(OddStruct))
132 args = esi.FuncService.get_call_chans(AppID("oddStructFunc"),
133 arg_type=OddStruct,
134 result=result_wire)
135
136 ready = Wire(Bits(1))
137 arg_data, valid = args.unwrap(ready)
138 a_val = (arg_data["a"] + UInt(12)(1)).as_uint(12)
139 b_val = (arg_data["b"] + SInt(7)(-3)).as_sint(7)
140 inner = arg_data["inner"]
141 p_val = (inner["p"] + UInt(8)(5)).as_uint(8)
142 q_val = (inner["q"] + SInt(8)(2)).as_sint(8)
143 r0_val = (inner["r"][0] + UInt(8)(1)).as_uint(8)
144 r1_val = (inner["r"][1] + UInt(8)(2)).as_uint(8)
145 result = OddStruct(a=a_val,
146 b=b_val,
147 inner=OddInner(p=p_val, q=q_val, r=[r0_val, r1_val]))
148 result_chan, result_ready = Channel(OddStruct).wrap(result, valid)
149 ready.assign(result_ready)
150 result_wire.assign(result_chan)
151
152
153ArgArray = SInt(8) * 1
154ResultArray = TypeAlias(SInt(8) * 2, "ResultArray")
155
156
157class LoopbackArray(Module):
158
159 @generator
160 def construct(ports):
161 result_wire = Wire(Channel(ResultArray))
162 args = esi.FuncService.get_call_chans(AppID("arrayFunc"),
163 arg_type=ArgArray,
164 result=result_wire)
165
166 ready = Wire(Bits(1))
167 arg_data, valid = args.unwrap(ready)
168 elem = arg_data[0]
169 elem_plus_one = (elem + SInt(8)(1)).as_sint(8)
170 # ArrayCreate reverses element order; provide reversed list to match MLIR.
171 result_array = ResultArray([elem, elem_plus_one])
172 result_chan, result_ready = Channel(ResultArray).wrap(result_array, valid)
173 ready.assign(result_ready)
174 result_wire.assign(result_chan)
175
176
177MemA = esi.DeclareRandomAccessMemory(Bits(64), 20, name="MemA")
178
179
180class MemoryAccess1(Module):
181 clk = Clock()
182 rst = Reset()
183
184 @generator
185 def construct(ports):
186 MemA.instantiate_builtin(appid=AppID("mem"),
187 builtin="sv_mem",
188 result_types=[],
189 inputs=[ports.clk, ports.rst])
190
191 write_bundle = MemA.write(AppID("internal_write"))
192 write_req_type = MemA.write.type.req
193 write_req, _ = write_req_type.wrap(
194 {
195 "address": UInt(MemA.address_width)(0),
196 "data": Bits(64)(0)
197 },
198 Bits(1)(0))
199 write_bundle.unpack(req=write_req)
200
201
202class CallableFunc1(Module):
203
204 @generator
205 def construct(ports):
206 result_wire = Wire(Channel(UInt(16)))
207 args = esi.FuncService.get_call_chans(AppID("func1"),
208 arg_type=UInt(16),
209 result=result_wire)
210
211 ready = Wire(Bits(1))
212 _, valid = args.unwrap(ready)
213 result_chan, result_ready = Channel(UInt(16)).wrap(UInt(16)(0), valid)
214 ready.assign(result_ready)
215 result_wire.assign(result_chan)
216
217
218class LoopbackSInt4(Module):
219 """Loopback a si4 value: returns the input unchanged."""
220
221 @generator
222 def construct(ports):
223 result_wire = Wire(Channel(SInt(4)))
224 args = esi.FuncService.get_call_chans(AppID("sint4Func"),
225 arg_type=SInt(4),
226 result=result_wire)
227
228 ready = Wire(Bits(1))
229 arg_data, valid = args.unwrap(ready)
230 result_chan, result_ready = Channel(SInt(4)).wrap(arg_data, valid)
231 ready.assign(result_ready)
232 result_wire.assign(result_chan)
233
234
235class Top(Module):
236 clk = Clock()
237 rst = Reset()
238
239 @generator
240 def construct(ports):
241 Loopback(clk=ports.clk, appid=AppID("loopback_inst", 0))
242 Loopback(clk=ports.clk, appid=AppID("loopback_inst", 1))
243 MemoryAccess1(clk=ports.clk, rst=ports.rst)
249
250
251if __name__ == "__main__":
252 bsp = get_bsp(sys.argv[2] if len(sys.argv) > 2 else None)
253 s = System(bsp(Top), name="Loopback", output_directory=sys.argv[1])
254 s.compile()
255 s.package()
256
257# CPP-TEST: depth: 0x5
258# CPP-TEST: loopback i8 ok: 0x5a
259# CPP-TEST: struct func ok: b=-7 x=-6 y=-7
260# CPP-TEST: odd struct func ok: a=2749 b=-20 p=10 q=-5 r0=4 r1=6
261# CPP-TEST: array func ok: -3 -2
262
263# QUERY-INFO: API version: 0
264# QUERY-INFO: ********************************
265# QUERY-INFO: * Module information
266# QUERY-INFO: ********************************
267# QUERY-INFO: - LoopbackIP v0.0
268# QUERY-INFO: IP which simply echos bytes
269# QUERY-INFO: Constants:
270# QUERY-INFO: depth: 5
271# QUERY-INFO: Extra metadata:
272# QUERY-INFO: foo: 1
273
274# QUERY-HIER: ********************************
275# QUERY-HIER: * Design hierarchy
276# QUERY-HIER: ********************************
277# QUERY-HIER: * Instance: {{.*}}
278# QUERY-HIER: * Ports:
279# QUERY-HIER: func1: function uint16(uint16)
280# QUERY-HIER: structFunc: function ResultStruct(ArgStruct)
281# QUERY-HIER: arrayFunc: function ResultArray(sint8[1])
282# QUERY-HIER: * Children:
283# QUERY-HIER: * Instance: loopback_inst[0]
284# QUERY-HIER: * Ports:
285# QUERY-HIER: loopback_tohw:
286# QUERY-HIER: recv: bits8
287# QUERY-HIER: loopback_fromhw:
288# QUERY-HIER: send: bits8
289# QUERY-HIER: mysvc_recv:
290# QUERY-HIER: recv: void
291# QUERY-HIER: mysvc_send:
292# QUERY-HIER: send: void
293# QUERY-HIER: * Instance: loopback_inst[1]
294# QUERY-HIER: * Ports:
295# QUERY-HIER: loopback_tohw:
296# QUERY-HIER: recv: bits8
297# QUERY-HIER: loopback_fromhw:
298# QUERY-HIER: send: bits8
299# QUERY-HIER: mysvc_recv:
300# QUERY-HIER: recv: void
301# QUERY-HIER: mysvc_send:
302# QUERY-HIER: send: void
303
304# LOOPBACK-H: /// Generated header for esi_system module LoopbackIP.
305# LOOPBACK-H-NEXT: #pragma once
306# LOOPBACK-H-NEXT: #include "types.h"
307# LOOPBACK-H-LABEL: namespace esi_system {
308# LOOPBACK-H-LABEL: class LoopbackIP {
309# LOOPBACK-H-NEXT: public:
310# LOOPBACK-H-NEXT: static constexpr uint32_t depth = 0x5;
311# LOOPBACK-H-NEXT: };
312# LOOPBACK-H-NEXT: } // namespace esi_system
return wrap(CMemoryType::get(unwrap(ctx), baseType, numElements))
construct(ports)
Definition loopback.py:240