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 esiaccel.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
42from esiaccel.esitester import SerialCoordTranslator
43
44SendI8 = Bundle([BundledChannel("send", ChannelDirection.FROM, Bits(8))])
45RecvI8 = Bundle([BundledChannel("recv", ChannelDirection.TO, Bits(8))])
46SendI0 = Bundle([BundledChannel("send", ChannelDirection.FROM, Bits(0))])
47RecvI0 = Bundle([BundledChannel("recv", ChannelDirection.TO, Bits(0))])
48
49
50@esi.ServiceDecl
52 Send = SendI8
53 Recv = RecvI8
54
55
56@esi.ServiceDecl
58 Send = SendI0
59 Recv = RecvI0
60
61
62class Loopback(Module):
63 clk = Clock()
64
65 metadata = Metadata(
66 name="LoopbackIP",
67 version="v0.0",
68 summary="IP which simply echos bytes",
69 misc={"foo": 1},
70 )
71
72 depth = Constant(UInt(32), 5)
73
74 @generator
75 def construct(ports):
76 data_in_bundle = HostComms.Recv(AppID("loopback_tohw"))
77 data_in = data_in_bundle.unpack()["recv"]
78
79 data_out_bundle = HostComms.Send(AppID("loopback_fromhw"))
80 data_out_bundle.unpack(send=data_in)
81
82 send_bundle = MyService.Recv(AppID("mysvc_recv"))
83 send_chan = send_bundle.unpack()["recv"]
84 sendi0_bundle = MyService.Send(AppID("mysvc_send"))
85 sendi0_bundle.unpack(send=send_chan)
86
87
88class ArgStruct(Struct):
89 a: UInt(16)
90 b: SInt(8)
91
92
93class ResultStruct(Struct):
94 x: SInt(8)
95 y: SInt(8)
96
97
98class OddInner(Struct):
99 p: UInt(8)
100 q: SInt(8)
101 r: UInt(8) * 2
102
103
104class OddStruct(Struct):
105 a: UInt(12)
106 b: SInt(7)
107 inner: OddInner
108
109
110class LoopbackStruct(Module):
111
112 @generator
113 def construct(ports):
114 result_wire = Wire(Channel(ResultStruct))
115 args = esi.FuncService.get_call_chans(AppID("structFunc"),
116 arg_type=ArgStruct,
117 result=result_wire)
118
119 ready = Wire(Bits(1))
120 arg_data, valid = args.unwrap(ready)
121 b_val = arg_data["b"]
122 b_plus_one = (b_val + SInt(8)(1)).as_sint(8)
123 result = ResultStruct(x=b_plus_one, y=b_val)
124 result_chan, result_ready = Channel(ResultStruct).wrap(result, valid)
125 ready.assign(result_ready)
126 result_wire.assign(result_chan)
127
128
129class LoopbackOddStruct(Module):
130
131 @generator
132 def construct(ports):
133 result_wire = Wire(Channel(OddStruct))
134 args = esi.FuncService.get_call_chans(AppID("oddStructFunc"),
135 arg_type=OddStruct,
136 result=result_wire)
137
138 ready = Wire(Bits(1))
139 arg_data, valid = args.unwrap(ready)
140 a_val = (arg_data["a"] + UInt(12)(1)).as_uint(12)
141 b_val = (arg_data["b"] + SInt(7)(-3)).as_sint(7)
142 inner = arg_data["inner"]
143 p_val = (inner["p"] + UInt(8)(5)).as_uint(8)
144 q_val = (inner["q"] + SInt(8)(2)).as_sint(8)
145 r0_val = (inner["r"][0] + UInt(8)(1)).as_uint(8)
146 r1_val = (inner["r"][1] + UInt(8)(2)).as_uint(8)
147 result = OddStruct(a=a_val,
148 b=b_val,
149 inner=OddInner(p=p_val, q=q_val, r=[r0_val, r1_val]))
150 result_chan, result_ready = Channel(OddStruct).wrap(result, valid)
151 ready.assign(result_ready)
152 result_wire.assign(result_chan)
153
154
155ArgArray = SInt(8) * 1
156ResultArray = TypeAlias(SInt(8) * 2, "ResultArray")
157
158
159class LoopbackArray(Module):
160
161 @generator
162 def construct(ports):
163 result_wire = Wire(Channel(ResultArray))
164 args = esi.FuncService.get_call_chans(AppID("arrayFunc"),
165 arg_type=ArgArray,
166 result=result_wire)
167
168 ready = Wire(Bits(1))
169 arg_data, valid = args.unwrap(ready)
170 elem = arg_data[0]
171 elem_plus_one = (elem + SInt(8)(1)).as_sint(8)
172 # ArrayCreate reverses element order; provide reversed list to match MLIR.
173 result_array = ResultArray([elem, elem_plus_one])
174 result_chan, result_ready = Channel(ResultArray).wrap(result_array, valid)
175 ready.assign(result_ready)
176 result_wire.assign(result_chan)
177
178
179MemA = esi.DeclareRandomAccessMemory(Bits(64), 20, name="MemA")
180
181
182class MemoryAccess1(Module):
183 clk = Clock()
184 rst = Reset()
185
186 @generator
187 def construct(ports):
188 MemA.instantiate_builtin(appid=AppID("mem"),
189 builtin="sv_mem",
190 result_types=[],
191 inputs=[ports.clk, ports.rst])
192
193 write_bundle = MemA.write(AppID("internal_write"))
194 write_req_type = MemA.write.type.req
195 write_req, _ = write_req_type.wrap(
196 {
197 "address": UInt(MemA.address_width)(0),
198 "data": Bits(64)(0)
199 },
200 Bits(1)(0))
201 write_bundle.unpack(req=write_req)
202
203
204class CallableFunc1(Module):
205
206 @generator
207 def construct(ports):
208 result_wire = Wire(Channel(UInt(16)))
209 args = esi.FuncService.get_call_chans(AppID("func1"),
210 arg_type=UInt(16),
211 result=result_wire)
212
213 ready = Wire(Bits(1))
214 _, valid = args.unwrap(ready)
215 result_chan, result_ready = Channel(UInt(16)).wrap(UInt(16)(0), valid)
216 ready.assign(result_ready)
217 result_wire.assign(result_chan)
218
219
220class LoopbackSInt4(Module):
221 """Loopback a si4 value: returns the input unchanged."""
222
223 @generator
224 def construct(ports):
225 result_wire = Wire(Channel(SInt(4)))
226 args = esi.FuncService.get_call_chans(AppID("sint4Func"),
227 arg_type=SInt(4),
228 result=result_wire)
229
230 ready = Wire(Bits(1))
231 arg_data, valid = args.unwrap(ready)
232 result_chan, result_ready = Channel(SInt(4)).wrap(arg_data, valid)
233 ready.assign(result_ready)
234 result_wire.assign(result_chan)
235
236
237class Top(Module):
238 clk = Clock()
239 rst = Reset()
240
241 @generator
242 def construct(ports):
243 Loopback(clk=ports.clk, appid=AppID("loopback_inst", 0))
244 Loopback(clk=ports.clk, appid=AppID("loopback_inst", 1))
245 MemoryAccess1(clk=ports.clk, rst=ports.rst)
252 clk=ports.clk,
253 rst=ports.rst,
254 instance_name="coord_translator_serial",
255 appid=AppID("coord_translator_serial"),
256 )
257
258
259if __name__ == "__main__":
260 bsp = get_bsp(sys.argv[2] if len(sys.argv) > 2 else None)
261 s = System(bsp(Top), name="Loopback", output_directory=sys.argv[1])
262 s.compile()
263 s.package()
264
265# CPP-TEST: depth: 0x5
266# CPP-TEST: loopback i8 ok: 0x5a
267# CPP-TEST: struct func ok: b=-7 x=-6 y=-7
268# CPP-TEST: odd struct func ok: a=2749 b=-20 p=10 q=-5 r0=4 r1=6
269# CPP-TEST: array func ok: -3 -2
270
271# QUERY-INFO: API version: 0
272# QUERY-INFO: ********************************
273# QUERY-INFO: * Module information
274# QUERY-INFO: ********************************
275# QUERY-INFO: - LoopbackIP v0.0
276# QUERY-INFO: IP which simply echos bytes
277# QUERY-INFO: Constants:
278# QUERY-INFO: depth: 5
279# QUERY-INFO: Extra metadata:
280# QUERY-INFO: foo: 1
281
282# QUERY-HIER: ********************************
283# QUERY-HIER: * Design hierarchy
284# QUERY-HIER: ********************************
285# QUERY-HIER: * Instance: {{.*}}
286# QUERY-HIER: * Ports:
287# QUERY-HIER: func1: function uint16(uint16)
288# QUERY-HIER: structFunc: function ResultStruct(ArgStruct)
289# QUERY-HIER: arrayFunc: function ResultArray(sint8[1])
290# QUERY-HIER: * Children:
291# QUERY-HIER: * Instance: loopback_inst[0]
292# QUERY-HIER: * Ports:
293# QUERY-HIER: loopback_tohw:
294# QUERY-HIER: recv: bits8
295# QUERY-HIER: loopback_fromhw:
296# QUERY-HIER: send: bits8
297# QUERY-HIER: mysvc_recv:
298# QUERY-HIER: recv: void
299# QUERY-HIER: mysvc_send:
300# QUERY-HIER: send: void
301# QUERY-HIER: * Instance: loopback_inst[1]
302# QUERY-HIER: * Ports:
303# QUERY-HIER: loopback_tohw:
304# QUERY-HIER: recv: bits8
305# QUERY-HIER: loopback_fromhw:
306# QUERY-HIER: send: bits8
307# QUERY-HIER: mysvc_recv:
308# QUERY-HIER: recv: void
309# QUERY-HIER: mysvc_send:
310# QUERY-HIER: send: void
311
312# LOOPBACK-H: /// Generated header for esi_system module LoopbackIP.
313# LOOPBACK-H-NEXT: #pragma once
314# LOOPBACK-H-NEXT: #include "types.h"
315# LOOPBACK-H-LABEL: namespace esi_system {
316# LOOPBACK-H-LABEL: class LoopbackIP {
317# LOOPBACK-H-NEXT: public:
318# LOOPBACK-H-NEXT: static constexpr uint32_t depth = 0x5;
319# LOOPBACK-H-NEXT: };
320# LOOPBACK-H-NEXT: } // namespace esi_system
return wrap(CMemoryType::get(unwrap(ctx), baseType, numElements))
construct(ports)
Definition loopback.py:242