CIRCT 24.0.0git
Loading...
Searching...
No Matches
hostmem_read.py
Go to the documentation of this file.
1# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
2# See https://llvm.org/LICENSE.txt for license information.
3# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
5# Hardware for the HostMem multiple-outstanding-read cosim test. One DUT per
6# element width in ELEMENT_WIDTHS, each a host-driven `read_list` client:
7#
8# * `req` (from_host): {address, length (elements)} read requests, forwarded
9# straight to the `read_list` request channel.
10# * `gate` (from_host): bit 0 opens (1) or closes (0) the response side. While
11# closed, no response element is consumed, so every request the BSP accepts
12# stays in flight inside the read processor.
13# * `resp` (to_host): every response element with its `last` flag, for the
14# host to check data, element counts and burst framing.
15# * `accepted` (telemetry): number of read requests accepted by the BSP.
16#
17# Usage: hostmem_read.py <output_dir> <max_outstanding_reads> [hostmem_width]
18
19import sys
20
21from pycde import AppID, Clock, Module, Reset, System, generator
22from pycde import esi
23from pycde.constructs import Counter, Mux, Reg, Wire
24from pycde.types import Bits, Channel, StructType, UInt
25
26from esiaccel.bsp.cosim import CosimBSP
27
28# Narrower than the 64-bit cosim HostMem word (sub-word, non-dividing and
29# dividing) and wider than it (non-multiple), so several read gearboxes are
30# exercised.
31ELEMENT_WIDTHS = [24, 32, 96]
32
33ReqType = StructType([("address", UInt(64)), ("length", UInt(32))])
34
35
36def HostMemReadDut(width: int):
37
38 # Byte-aligned fields keep the host-side struct decoding simple.
39 RespType = StructType([("data", UInt(width)), ("last", UInt(8))])
40
42 module_name = f"HostMemReadDut_{width}"
43 clk = Clock()
44 rst = Reset()
45
46 @generator
47 def build(ports):
48 clk, rst = ports.clk, ports.rst
49
50 host_req = esi.ChannelService.from_host(AppID("req"), ReqType)
51 burst_req_type = esi.HostMem.read_req_burst_type(32)
52 req = host_req.transform(lambda r: burst_req_type({
53 "address": r.address,
54 "tag": UInt(8)(0),
55 "length": r.length,
56 }))
57 req_xact, _ = req.snoop_xact()
58 accepted = Counter(32)(clk=clk,
59 rst=rst,
60 clear=Bits(1)(0),
61 increment=req_xact)
62 esi.Telemetry.report_signal(clk, rst, AppID("accepted"), accepted.out)
63
64 gate_in = esi.ChannelService.from_host(AppID("gate"), UInt(8))
65 gate_data, gate_valid = gate_in.unwrap(Bits(1)(1))
66 gate_open = Reg(Bits(1), clk=clk, rst=rst, rst_value=0, name="gate_open")
67 gate_open.assign(Mux(gate_valid, gate_open, gate_data.as_bits()[0]))
68
69 resp = esi.HostMem.read_list(appid=AppID("host"),
70 req=req,
71 element_type=Bits(width),
72 num_items=1)
73 resp_ready = Wire(Bits(1))
74 frame, resp_valid = resp.unwrap(resp_ready)
75 frame = frame.unwrap()
76 out, out_ready = Channel(RespType).wrap(
77 RespType({
78 "data": frame["data"][0].as_uint(),
79 "last": frame["last"].as_uint(8),
80 }), resp_valid & gate_open)
81 resp_ready.assign(out_ready & gate_open)
82 esi.ChannelService.to_host(AppID("resp"), out)
83
84 return HostMemReadDut
85
86
87def SingleReadDut(width: int):
88
89 class SingleReadDut(Module):
90 clk = Clock()
91 rst = Reset()
92
93 @generator
94 def build(ports):
95 address = esi.ChannelService.from_host(AppID("req"), UInt(64))
96 req = address.transform(lambda addr: esi.HostMem.ReadReqType({
97 "address": addr,
98 "tag": 0,
99 }))
100 resp = esi.HostMem.read(AppID("host"), req, Bits(width))
101 esi.ChannelService.to_host(
102 AppID("resp"),
103 resp.transform(lambda r: r.data.as_uint((width + 7) // 8 * 8)))
104
105 return SingleReadDut
106
107
108def Top(bus_width: int):
109
110 class Top(Module):
111 clk = Clock()
112 rst = Reset()
113
114 @generator
115 def build(ports):
116 for w in ELEMENT_WIDTHS:
117 HostMemReadDut(w)(clk=ports.clk,
118 rst=ports.rst,
119 appid=AppID("rd", w),
120 instance_name=f"rd_{w}")
121 for w in [13, bus_width, bus_width + 24, 16384]:
122 SingleReadDut(w)(clk=ports.clk, rst=ports.rst, appid=AppID("single", w))
123
124 return Top
125
126
127if __name__ == "__main__":
128 max_outstanding = int(sys.argv[2])
129 bus_width = int(sys.argv[3]) if len(sys.argv) > 3 else 64
130 s = System(CosimBSP(Top(bus_width),
131 max_outstanding_reads=max_outstanding,
132 hostmem_width=bus_width),
133 name="HostMemRead",
134 output_directory=sys.argv[1])
135 s.compile()
136 s.package()
return wrap(CMemoryType::get(unwrap(ctx), baseType, numElements))
HostMemReadDut(int width)
Top(int bus_width)
SingleReadDut(int width)