Skip to content

Commit

Permalink
[PyCDE/ESI] Add hostmem write API
Browse files Browse the repository at this point in the history
  • Loading branch information
teqdruid committed Jan 8, 2025
1 parent 405b6b8 commit 7f4dd46
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 5 deletions.
43 changes: 42 additions & 1 deletion frontends/PyCDE/src/pycde/esi.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from .module import (generator, modparams, Module, ModuleLikeBuilderBase,
PortProxyBase)
from .signals import (BitsSignal, BundleSignal, ChannelSignal, Signal,
_FromCirctValue)
_FromCirctValue, UIntSignal)
from .support import optional_dict_to_dict_attr, get_user_loc
from .system import System
from .types import (Any, Bits, Bundle, BundledChannel, Channel,
Expand Down Expand Up @@ -519,9 +519,50 @@ class _HostMem(ServiceDecl):
("tag", UInt(8)),
])

WriteReqType = StructType([
("address", UInt(64)),
("tag", UInt(8)),
("data", Any()),
])

def __init__(self):
super().__init__(self.__class__)

def wrap_write_req(self, address: UIntSignal, data: Type, tag: UIntSignal,
valid: BitsSignal) -> Tuple[ChannelSignal, BitsSignal]:
"""Create the proper channel type for a write request and use it to wrap the
given request arguments. Returns the Channel signal and a ready bit."""
inner_type = StructType([
("address", UInt(64)),
("tag", UInt(8)),
("data", data.type),
])
return Channel(inner_type).wrap(
inner_type({
"address": address,
"tag": tag,
"data": data,
}), valid)

def write(self, appid: AppID, req: ChannelSignal) -> ChannelSignal:
"""Create a write request to the host memory out of a request channel."""
self._materialize_service_decl()

write_bundle_type = Bundle([
BundledChannel("req", ChannelDirection.FROM, _HostMem.WriteReqType),
BundledChannel("ackTag", ChannelDirection.TO, UInt(8))
])

bundle = cast(
BundleSignal,
_FromCirctValue(
raw_esi.RequestConnectionOp(
write_bundle_type._type,
hw.InnerRefAttr.get(self.symbol, ir.StringAttr.get("write")),
appid._appid).toClient))
resp = bundle.unpack(req=req)['ackTag']
return resp

# Create a read request to the host memory out of a request channel and return
# the response channel with the specified data type.
def read(self, appid: AppID, req: ChannelSignal,
Expand Down
20 changes: 16 additions & 4 deletions frontends/PyCDE/test/test_esi.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,8 +302,14 @@ def build(ports):
# CHECK-NEXT: [[R2:%.+]] = hwarith.constant 0 : ui8
# CHECK-NEXT: [[R3:%.+]] = hw.struct_create ([[R0]], [[R2]]) : !hw.struct<address: ui64, tag: ui8>
# CHECK-NEXT: %chanOutput, %ready = esi.wrap.vr [[R3]], %false : !hw.struct<address: ui64, tag: ui8>
# CHECK-NEXT: [[R1:%.+]] = esi.service.req <@_HostMem::@read>(#esi.appid<"host_mem_req">) : !esi.bundle<[!esi.channel<!hw.struct<address: ui64, tag: ui8>> from "req", !esi.channel<!hw.struct<tag: ui8, data: ui256>> to "resp"]>
# CHECK-NEXT: [[R1:%.+]] = esi.service.req <@_HostMem::@read>(#esi.appid<"host_mem_read_req">) : !esi.bundle<[!esi.channel<!hw.struct<address: ui64, tag: ui8>> from "req", !esi.channel<!hw.struct<tag: ui8, data: ui256>> to "resp"]>
# CHECK-NEXT: %resp = esi.bundle.unpack %chanOutput from [[R1]] : !esi.bundle<[!esi.channel<!hw.struct<address: ui64, tag: ui8>> from "req", !esi.channel<!hw.struct<tag: ui8, data: ui256>> to "resp"]>
# CHECK-NEXT: [[R4:%.+]] = hwarith.constant 0 : ui8
# CHECK-NEXT: [[R5:%.+]] = hwarith.constant 0 : ui256
# CHECK-NEXT: [[R6:%.+]] = hw.struct_create ([[R0]], [[R4]], [[R5]]) : !hw.struct<address: ui64, tag: ui8, data: ui256>
# CHECK-NEXT: %chanOutput_0, %ready_1 = esi.wrap.vr [[R6]], %false : !hw.struct<address: ui64, tag: ui8, data: ui256>
# CHECK-NEXT: [[R7:%.+]] = esi.service.req <@_HostMem::@write>(#esi.appid<"host_mem_write_req">) : !esi.bundle<[!esi.channel<!hw.struct<address: ui64, tag: ui8, data: !esi.any>> from "req", !esi.channel<ui8> to "ackTag"]>
# CHECK-NEXT: %ackTag = esi.bundle.unpack %chanOutput_0 from [[R7]] : !esi.bundle<[!esi.channel<!hw.struct<address: ui64, tag: ui8, data: !esi.any>> from "req", !esi.channel<ui8> to "ackTag"]>
# CHECK: esi.service.std.hostmem @_HostMem
@unittestmodule(esi_sys=True)
class HostMemReq(Module):
Expand All @@ -313,12 +319,18 @@ def build(ports):
u64 = UInt(64)(0)
c1 = Bits(1)(0)

address, _ = Channel(esi.HostMem.ReadReqType).wrap(
read_address, _ = Channel(esi.HostMem.ReadReqType).wrap(
esi.HostMem.ReadReqType({
"tag": 0,
"address": u64
}), c1)

_ = HostMem.read(appid=AppID("host_mem_req"),
req=address,
_ = HostMem.read(appid=AppID("host_mem_read_req"),
req=read_address,
data_type=UInt(256))

write_req, _ = esi.HostMem.wrap_write_req(tag=UInt(8)(0),
data=UInt(256)(0),
address=u64,
valid=c1)
_ = HostMem.write(appid=AppID("host_mem_write_req"), req=write_req)
4 changes: 4 additions & 0 deletions lib/Bindings/Python/support.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ def type_to_pytype(t) -> ir.Type:
return esi.ChannelType(t)
except ValueError:
pass
try:
return esi.AnyType(t)
except ValueError:
pass
try:
return esi.BundleType(t)
except ValueError:
Expand Down

0 comments on commit 7f4dd46

Please sign in to comment.