Skip to content

Commit

Permalink
Merge branch 'llvm:main' into mingzhe-structCreate
Browse files Browse the repository at this point in the history
  • Loading branch information
mingzheTerapines authored Aug 2, 2024
2 parents db8f16b + 20cb546 commit c4ccda7
Show file tree
Hide file tree
Showing 20 changed files with 775 additions and 155 deletions.
2 changes: 1 addition & 1 deletion docs/Dialects/Seq/RationaleSeq.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ Examples of registers:
A register without a reset lowers directly to an always block:

```
always @(posedge clk or [posedge reset]) begin
always @(posedge clk) begin
a <= [%input]
end
```
Expand Down
39 changes: 36 additions & 3 deletions frontends/PyCDE/integration_test/esi_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
import pycde
from pycde import (AppID, Clock, Module, Reset, modparams, generator)
from pycde.bsp import cosim
from pycde.constructs import Wire
from pycde.esi import FuncService, MMIO
from pycde.constructs import Reg, Wire
from pycde.esi import FuncService, MMIO, MMIOReadWriteCmdType
from pycde.types import (Bits, Channel, UInt)
from pycde.behavioral import If, Else, EndIf

import sys

Expand Down Expand Up @@ -48,7 +49,7 @@ def build(ports):

address_chan_wire = Wire(Channel(UInt(32)))
address, address_valid = address_chan_wire.unwrap(1)
response_data = (address.as_uint() + add_amt).as_bits(64)
response_data = (address + add_amt).as_bits(64)
response_chan, response_ready = Channel(Bits(64)).wrap(
response_data, address_valid)

Expand All @@ -58,6 +59,37 @@ def build(ports):
return MMIOClient


class MMIOReadWriteClient(Module):
clk = Clock()
rst = Reset()

@generator
def build(ports):
mmio_read_write_bundle = MMIO.read_write(appid=AppID("mmio_rw_client"))

cmd_chan_wire = Wire(Channel(MMIOReadWriteCmdType))
resp_ready_wire = Wire(Bits(1))
cmd, cmd_valid = cmd_chan_wire.unwrap(resp_ready_wire)

add_amt = Reg(UInt(64),
clk=ports.clk,
rst=ports.rst,
rst_value=0,
ce=cmd_valid & cmd.write & (cmd.offset == 0x8).as_bits())
add_amt.assign(cmd.data.as_uint())
with If(cmd.write):
response_data = Bits(64)(0)
with Else():
response_data = (cmd.offset + add_amt).as_bits(64)
EndIf()
response_chan, response_ready = Channel(Bits(64)).wrap(
response_data, cmd_valid)
resp_ready_wire.assign(response_ready)

cmd_chan = mmio_read_write_bundle.unpack(data=response_chan)['cmd']
cmd_chan_wire.assign(cmd_chan)


class Top(Module):
clk = Clock()
rst = Reset()
Expand All @@ -67,6 +99,7 @@ def construct(ports):
LoopbackInOutAdd7(clk=ports.clk, rst=ports.rst)
for i in range(4, 18, 5):
MMIOClient(i)()
MMIOReadWriteClient(clk=ports.clk, rst=ports.rst)


if __name__ == "__main__":
Expand Down
20 changes: 20 additions & 0 deletions frontends/PyCDE/integration_test/test_software/esi_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,26 @@ def read_offset(mmio_offset: int, offset: int, add_amt: int):
read_offset(mmio_client_14_offset, 0, 14)
read_offset(mmio_client_14_offset, 13, 14)

################################################################################
# MMIOReadWriteClient tests
################################################################################

mmio_rw_client_offset = 262144


def read_offset_check(i: int, add_amt: int):
d = mmio.read(mmio_rw_client_offset + i)
if d == i + 9:
print(f"PASS: read_offset_check({mmio_rw_client_offset} + {i}: {d}")
else:
assert False, f": read_offset_check({mmio_rw_client_offset} + {i}: {d}"


mmio.write(mmio_rw_client_offset + 8, 9)
read_offset_check(0, 9)
read_offset_check(12, 9)
read_offset_check(0x1400, 9)

################################################################################
# Manifest tests
################################################################################
Expand Down
92 changes: 50 additions & 42 deletions frontends/PyCDE/src/pycde/bsp/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ class ChannelMMIO(esi.ServiceImplementation):
clk = Clock()
rst = Input(Bits(1))

read = Input(esi.MMIO.read.type)
cmd = Input(esi.MMIOReadWriteCmdType)

# Amount of register space each client gets. This is a GIANT HACK and needs to
# be replaced by parameterizable services.
Expand All @@ -140,70 +140,75 @@ class ChannelMMIO(esi.ServiceImplementation):

@generator
def generate(ports, bundles: esi._ServiceGeneratorBundles):
read_table, write_table, manifest_loc = ChannelMMIO.build_table(
ports, bundles)
ChannelMMIO.build_read(ports, manifest_loc, read_table)
ChannelMMIO.build_write(ports, write_table)
table, manifest_loc = ChannelMMIO.build_table(bundles)
ChannelMMIO.build_read(ports, manifest_loc, table)
return True

@staticmethod
def build_table(
ports, bundles
) -> Tuple[Dict[int, AssignableSignal], Dict[int, AssignableSignal], int]:
def build_table(bundles) -> Tuple[Dict[int, AssignableSignal], int]:
"""Build a table of read and write addresses to BundleSignals."""
offset = ChannelMMIO.initial_offset
read_table: Dict[int, AssignableSignal] = {}
write_table: Dict[int, AssignableSignal] = {}
table: Dict[int, AssignableSignal] = {}
for bundle in bundles.to_client_reqs:
if bundle.port == 'read':
read_table[offset] = bundle
bundle.add_record({"offset": offset})
table[offset] = bundle
bundle.add_record({"offset": offset, "type": "ro"})
offset += ChannelMMIO.RegisterSpace
elif bundle.port == 'read_write':
table[offset] = bundle
bundle.add_record({"offset": offset, "type": "rw"})
offset += ChannelMMIO.RegisterSpace
else:
assert False, "Unrecognized port name."

manifest_loc = offset
return read_table, write_table, manifest_loc
return table, manifest_loc

@staticmethod
def build_read(ports, manifest_loc: int, read_table: Dict[int,
AssignableSignal]):
def build_read(ports, manifest_loc: int, table: Dict[int, AssignableSignal]):
"""Builds the read side of the MMIO service."""

# Instantiate the header and manifest ROM. Fill in the read_table with
# bundle wires to be assigned identically to the other MMIO clients.
header_bundle_wire = Wire(esi.MMIO.read.type)
read_table[0] = header_bundle_wire
table[0] = header_bundle_wire
HeaderMMIO(manifest_loc)(clk=ports.clk,
rst=ports.rst,
read=header_bundle_wire)

mani_bundle_wire = Wire(esi.MMIO.read.type)
read_table[manifest_loc] = mani_bundle_wire
table[manifest_loc] = mani_bundle_wire
ESI_Manifest_ROM_Wrapper(clk=ports.clk, read=mani_bundle_wire)

# Unpack the read bundle.
# Unpack the cmd bundle.
data_resp_channel = Wire(Channel(esi.MMIODataType))
counted_output = Wire(Channel(esi.MMIODataType))
read_addr_channel = ports.read.unpack(data=counted_output)["offset"]
cmd_channel = ports.cmd.unpack(data=counted_output)["cmd"]
counted_output.assign(data_resp_channel)

# Get the selection index and the address to hand off to the clients.
sel_bits, client_address_chan = ChannelMMIO.build_addr_read(
read_addr_channel)
sel_bits, client_cmd_chan = ChannelMMIO.build_addr_read(cmd_channel)

# Build the demux/mux and assign the results of each appropriately.
read_clients_clog2 = clog2(len(read_table))
client_addr_channels = esi.ChannelDemux(
read_clients_clog2 = clog2(len(table))
client_cmd_channels = esi.ChannelDemux(
sel=sel_bits.pad_or_truncate(read_clients_clog2),
input=client_address_chan,
num_outs=len(read_table))
input=client_cmd_chan,
num_outs=len(table))
client_data_channels = []
for (idx, offset) in enumerate(sorted(read_table.keys())):
bundle, bundle_froms = esi.MMIO.read.type.pack(
offset=client_addr_channels[idx])
for (idx, offset) in enumerate(sorted(table.keys())):
bundle_wire = table[offset]
bundle_type = bundle_wire.type
if bundle_type == esi.MMIO.read.type:
offset = client_cmd_channels[idx].transform(lambda cmd: cmd.offset)
bundle, bundle_froms = esi.MMIO.read.type.pack(offset=offset)
elif bundle_type == esi.MMIO.read_write.type:
bundle, bundle_froms = esi.MMIO.read_write.type.pack(
cmd=client_cmd_channels[idx])
else:
assert False, "Unrecognized bundle type."
bundle_wire.assign(bundle)
client_data_channels.append(bundle_froms["data"])
read_table[offset].assign(bundle)
resp_channel = esi.ChannelMux(client_data_channels)
data_resp_channel.assign(resp_channel)

Expand All @@ -218,18 +223,21 @@ def build_addr_read(
# change to support more flexibility in addressing. Not clear if what we're
# doing now it sufficient or not.

addr_ready_wire = Wire(Bits(1))
addr, addr_valid = read_addr_chan.unwrap(addr_ready_wire)
addr = addr.as_bits()
cmd_ready_wire = Wire(Bits(1))
cmd, cmd_valid = read_addr_chan.unwrap(cmd_ready_wire)
sel_bits = NamedWire(Bits(32 - ChannelMMIO.RegisterSpaceBits), "sel_bits")
sel_bits.assign(addr[ChannelMMIO.RegisterSpaceBits:])
client_addr = NamedWire(Bits(32), "client_addr")
client_addr.assign(addr & Bits(32)(ChannelMMIO.AddressMask))
client_addr_chan, client_addr_ready = Channel(UInt(32)).wrap(
client_addr.as_uint(), addr_valid)
addr_ready_wire.assign(client_addr_ready)
sel_bits.assign(cmd.offset.as_bits()[ChannelMMIO.RegisterSpaceBits:])
client_cmd = NamedWire(esi.MMIOReadWriteCmdType, "client_cmd")
client_cmd.assign(
esi.MMIOReadWriteCmdType({
"write":
cmd.write,
"offset": (cmd.offset.as_bits() &
Bits(32)(ChannelMMIO.AddressMask)).as_uint(),
"data":
cmd.data
}))
client_addr_chan, client_addr_ready = Channel(
esi.MMIOReadWriteCmdType).wrap(client_cmd, cmd_valid)
cmd_ready_wire.assign(client_addr_ready)
return sel_bits, client_addr_chan

def build_write(self, bundles):
# TODO: this.
pass
6 changes: 3 additions & 3 deletions frontends/PyCDE/src/pycde/bsp/cosim.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@ class ESI_Cosim_UserTopWrapper(Module):
def build(ports):
user_module(clk=ports.clk, rst=ports.rst)

mmio_read = esi.FuncService.get_coerced(esi.AppID("__cosim_mmio_read"),
esi.MMIO.read.type)
mmio_read_write = esi.FuncService.get_coerced(
esi.AppID("__cosim_mmio_read_write"), esi.MMIO.read_write.type)
ChannelMMIO(esi.MMIO,
appid=esi.AppID("__cosim_mmio"),
clk=ports.clk,
rst=ports.rst,
read=mmio_read)
cmd=mmio_read_write)

class ESI_Cosim_Top(Module):
clk = Clock()
Expand Down
12 changes: 11 additions & 1 deletion frontends/PyCDE/src/pycde/esi.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from .support import get_user_loc
from .system import System
from .types import (Bits, Bundle, BundledChannel, Channel, ChannelDirection,
Type, UInt, types, _FromCirctType)
StructType, Type, UInt, types, _FromCirctType)

from .circt import ir
from .circt.dialects import esi as raw_esi, hw, msft
Expand Down Expand Up @@ -469,6 +469,11 @@ def param(name: str, type: Type = None):


MMIODataType = Bits(64)
MMIOReadWriteCmdType = StructType([
("write", Bits(1)),
("offset", UInt(32)),
("data", MMIODataType),
])


@ServiceDecl
Expand All @@ -482,6 +487,11 @@ class MMIO:
BundledChannel("data", ChannelDirection.FROM, MMIODataType)
])

read_write = Bundle([
BundledChannel("cmd", ChannelDirection.TO, MMIOReadWriteCmdType),
BundledChannel("data", ChannelDirection.FROM, MMIODataType)
])

@staticmethod
def _op(sym_name: ir.StringAttr):
return raw_esi.MMIOServiceDeclOp(sym_name)
Expand Down
15 changes: 15 additions & 0 deletions include/circt/Dialect/Moore/MooreOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,21 @@ def NamedConstantOp : MooreOp<"named_constant", [
}];
}

def StringConstantOp : MooreOp<"string_constant", [Pure, ConstantLike]> {
let summary = "Produce a constant string value";
let description = [{
Produces a constant value of string type.

Example:
```mlir
%0 = moore.string "hello world"
```
}];
let arguments = (ins StrAttr:$value);
let results = (outs IntType:$result);
let assemblyFormat = "$value attr-dict `:` type($result)";
}

def ConversionOp : MooreOp<"conversion", [Pure]> {
let summary = "A type conversion";
let description = [{
Expand Down
Loading

0 comments on commit c4ccda7

Please sign in to comment.