mirror of https://github.com/llvm/circt.git
[ESI] Make RAM delarations' addresses unsigned (#8658)
Using signless ints as the address was just wrong. It was probably done to avoid incomplete lowerings, which have been addressed. Changes RAM declaration addresses to use unsigned integer types throughout the ESI dialect and its tests, updating both the code generator and expected outputs. - Switch address ports to unsigned (uiN) in MLIR tests and service definitions. - Update service port generation and SystemVerilog memory instantiation to use unsigned address types, inserting bitcasts to signless for indexing. - Adjust PyCDE front end and software integration tests to use UInt addressing.
This commit is contained in:
parent
137b13de04
commit
8c1865c5a9
|
@ -36,7 +36,7 @@ assert dummy_info is not None
|
|||
|
||||
|
||||
def read(addr: int) -> bytearray:
|
||||
mem_read_addr.write([addr])
|
||||
mem_read_addr.write(addr)
|
||||
resp = cast(bytearray, mem_read_data.read())
|
||||
print(f"resp: {resp}")
|
||||
return resp
|
||||
|
@ -45,7 +45,7 @@ def read(addr: int) -> bytearray:
|
|||
# The contents of address 3 are continuously updated to the contents of address
|
||||
# 2 by the accelerator.
|
||||
data = bytearray([random.randint(0, 2**8 - 1) for _ in range(8)])
|
||||
mem_write.write({"address": [2], "data": data})
|
||||
mem_write.write({"address": 2, "data": data})
|
||||
resp = read(2)
|
||||
try_count = 0
|
||||
|
||||
|
@ -64,6 +64,6 @@ assert resp == data
|
|||
# Check this by writing to address 3 and reading from it. Shouldn't have
|
||||
# changed.
|
||||
zeros = bytearray([0] * 8)
|
||||
mem_write.write({"address": [3], "data": zeros})
|
||||
mem_write.write({"address": 3, "data": zeros})
|
||||
resp = read(3)
|
||||
assert resp == data
|
||||
|
|
|
@ -465,7 +465,7 @@ def DeclareRandomAccessMemory(inner_type: Type,
|
|||
class DeclareRandomAccessMemory(ServiceDecl):
|
||||
__name__ = name
|
||||
address_width = (depth - 1).bit_length()
|
||||
address_type = Bits(address_width)
|
||||
address_type = UInt(address_width)
|
||||
write_struct = StructType([('address', address_type), ('data', inner_type)])
|
||||
|
||||
read = Bundle([
|
||||
|
|
|
@ -366,11 +366,11 @@ def Writer(type):
|
|||
|
||||
# CHECK: hw.module @Ram1(in %clk : !seq.clock, in %rst : i1)
|
||||
# CHECK: esi.service.instance #esi.appid<"ram"> svc @ram impl as "sv"(%clk, %rst) : (!seq.clock, i1) -> ()
|
||||
# CHECK: [[WR:%.+]] = esi.service.req <@ram::@write>(#esi.appid<"ram_writer"[0]>) : !esi.bundle<[!esi.channel<!hw.struct<address: i3, data: i32>> from "req", !esi.channel<i0> to "ack"]>
|
||||
# CHECK: [[WR:%.+]] = esi.service.req <@ram::@write>(#esi.appid<"ram_writer"[0]>) : !esi.bundle<[!esi.channel<!hw.struct<address: ui3, data: i32>> from "req", !esi.channel<i0> to "ack"]>
|
||||
# CHECK: %rawOutput, %valid = esi.unwrap.vr %req, %ready : !hw.struct<address: ui3, data: ui32>
|
||||
# CHECK: [[CASTED:%.+]] = hw.bitcast %rawOutput : (!hw.struct<address: ui3, data: ui32>) -> !hw.struct<address: i3, data: i32>
|
||||
# CHECK: %chanOutput, %ready = esi.wrap.vr [[CASTED]], %valid : !hw.struct<address: i3, data: i32>
|
||||
# CHECK: %ack = esi.bundle.unpack %chanOutput from [[WR]] : !esi.bundle<[!esi.channel<!hw.struct<address: i3, data: i32>> from "req", !esi.channel<i0> to "ack"]>
|
||||
# CHECK: [[CASTED:%.+]] = hw.bitcast %rawOutput : (!hw.struct<address: ui3, data: ui32>) -> !hw.struct<address: ui3, data: i32>
|
||||
# CHECK: %chanOutput, %ready = esi.wrap.vr [[CASTED]], %valid : !hw.struct<address: ui3, data: i32>
|
||||
# CHECK: %ack = esi.bundle.unpack %chanOutput from [[WR]] : !esi.bundle<[!esi.channel<!hw.struct<address: ui3, data: i32>> from "req", !esi.channel<i0> to "ack"]>
|
||||
# CHECK: %bundle, %req = esi.bundle.pack %ack : !esi.bundle<[!esi.channel<!hw.struct<address: ui3, data: ui32>> from "req", !esi.channel<i0> to "ack"]>
|
||||
# CHECK: hw.instance "Writer" sym @Writer @Writer(clk: %clk: !seq.clock, rst: %rst: i1, cmd: %bundle: !esi.bundle<[!esi.channel<!hw.struct<address: ui3, data: ui32>> from "req", !esi.channel<i0> to "ack"]>) -> ()
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ hw.module @LoopbackArray() {
|
|||
}
|
||||
|
||||
esi.mem.ram @MemA i64 x 20
|
||||
!write = !hw.struct<address: i5, data: i64>
|
||||
!write = !hw.struct<address: ui5, data: i64>
|
||||
!writeBundle = !esi.bundle<[!esi.channel<!write> from "req", !esi.channel<i0> to "ack"]>
|
||||
|
||||
hw.module @MemoryAccess1(in %clk : !seq.clock, in %rst : i1) {
|
||||
|
|
|
@ -271,8 +271,11 @@ instantiateSystemVerilogMemory(ServiceImplementReqOp implReq,
|
|||
// Unwrap the requested address and read from that memory location.
|
||||
auto addressUnwrap =
|
||||
b.create<UnwrapValidReadyOp>(toServer, dataChannel.getReady());
|
||||
Value memLoc =
|
||||
b.create<sv::ArrayIndexInOutOp>(mem, addressUnwrap.getRawOutput());
|
||||
Value unsignedAddress = addressUnwrap.getRawOutput();
|
||||
Value signlessAddress = b.create<hw::BitcastOp>(
|
||||
b.getIntegerType(llvm::Log2_64_Ceil(ramDecl.getDepth())),
|
||||
unsignedAddress);
|
||||
Value memLoc = b.create<sv::ArrayIndexInOutOp>(mem, signlessAddress);
|
||||
auto readData = b.create<sv::ReadInOutOp>(memLoc);
|
||||
|
||||
// Set the data on the response.
|
||||
|
@ -294,7 +297,10 @@ instantiateSystemVerilogMemory(ServiceImplementReqOp implReq,
|
|||
Value a = address, d = data; // So the lambda can capture.
|
||||
// If we're told to go, do the write.
|
||||
b.create<sv::IfOp>(go, [&] {
|
||||
Value memLoc = b.create<sv::ArrayIndexInOutOp>(mem, a);
|
||||
Value signlessAddress = b.create<hw::BitcastOp>(
|
||||
b.getIntegerType(llvm::Log2_64_Ceil(ramDecl.getDepth())), a);
|
||||
Value memLoc =
|
||||
b.create<sv::ArrayIndexInOutOp>(mem, signlessAddress);
|
||||
b.create<sv::PAssignOp>(memLoc, d);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -39,7 +39,9 @@ static ServicePortInfo createReqResp(StringAttr sym, Twine name,
|
|||
|
||||
ServicePortInfo RandomAccessMemoryDeclOp::writePortInfo() {
|
||||
auto *ctxt = getContext();
|
||||
auto addressType = IntegerType::get(ctxt, llvm::Log2_64_Ceil(getDepth()));
|
||||
auto addressType =
|
||||
IntegerType::get(ctxt, llvm::Log2_64_Ceil(getDepth()),
|
||||
IntegerType::SignednessSemantics::Unsigned);
|
||||
|
||||
// Write port
|
||||
hw::StructType writeType = hw::StructType::get(
|
||||
|
@ -53,7 +55,9 @@ ServicePortInfo RandomAccessMemoryDeclOp::writePortInfo() {
|
|||
|
||||
ServicePortInfo RandomAccessMemoryDeclOp::readPortInfo() {
|
||||
auto *ctxt = getContext();
|
||||
auto addressType = IntegerType::get(ctxt, llvm::Log2_64_Ceil(getDepth()));
|
||||
auto addressType =
|
||||
IntegerType::get(ctxt, llvm::Log2_64_Ceil(getDepth()),
|
||||
IntegerType::SignednessSemantics::Unsigned);
|
||||
|
||||
return createReqResp(getSymNameAttr(), "read", "address", addressType, "data",
|
||||
getInnerType());
|
||||
|
|
|
@ -121,22 +121,24 @@ esi.pure_module @LoopbackCosimPure {
|
|||
}
|
||||
|
||||
// CONN-LABEL: esi.mem.ram @MemA i64 x 20
|
||||
// CONN-LABEL: hw.module @MemoryAccess1(in %clk : !seq.clock, in %rst : i1, in %write : !esi.channel<!hw.struct<address: i5, data: i64>>, in %readAddress : !esi.channel<i5>, out readData : !esi.channel<i64>, out writeDone : !esi.channel<i0>) {
|
||||
// CONN-LABEL: hw.module @MemoryAccess1(in %clk : !seq.clock, in %rst : i1, in %write : !esi.channel<!hw.struct<address: ui5, data: i64>>, in %readAddress : !esi.channel<ui5>, out readData : !esi.channel<i64>, out writeDone : !esi.channel<i0>) {
|
||||
// CONN: %MemA = sv.reg : !hw.inout<uarray<20xi64>>
|
||||
// CONN: %chanOutput, %ready = esi.wrap.vr %c0_i0, %write_done : i0
|
||||
// CONN: %rawOutput, %valid = esi.unwrap.vr %write, %ready : !hw.struct<address: i5, data: i64>
|
||||
// CONN: %address = hw.struct_extract %rawOutput["address"] : !hw.struct<address: i5, data: i64>
|
||||
// CONN: %data = hw.struct_extract %rawOutput["data"] : !hw.struct<address: i5, data: i64>
|
||||
// CONN: %rawOutput, %valid = esi.unwrap.vr %write, %ready : !hw.struct<address: ui5, data: i64>
|
||||
// CONN: %address = hw.struct_extract %rawOutput["address"] : !hw.struct<address: ui5, data: i64>
|
||||
// CONN: %data = hw.struct_extract %rawOutput["data"] : !hw.struct<address: ui5, data: i64>
|
||||
// CONN: %[[ANDVR:.*]] = comb.and %valid, %ready {sv.namehint = "write_go"} : i1
|
||||
// CONN: %write_done = seq.compreg sym @write_done %[[ANDVR]], %clk reset %rst, %false : i1
|
||||
// CONN: %chanOutput_0, %ready_1 = esi.wrap.vr %[[MEMREAD:.*]], %valid_3 : i64
|
||||
// CONN: %rawOutput_2, %valid_3 = esi.unwrap.vr %readAddress, %ready_1 : i5
|
||||
// CONN: %[[MEMREADIO:.*]] = sv.array_index_inout %MemA[%rawOutput_2] : !hw.inout<uarray<20xi64>>, i5
|
||||
// CONN: %rawOutput_2, %valid_3 = esi.unwrap.vr %readAddress, %ready_1 : ui5
|
||||
// CONN: %[[ADDR:.*]] = hw.bitcast %rawOutput_2 : (ui5) -> i5
|
||||
// CONN: %[[MEMREADIO:.*]] = sv.array_index_inout %MemA[%[[ADDR]]] : !hw.inout<uarray<20xi64>>, i5
|
||||
// CONN: %[[MEMREAD]] = sv.read_inout %[[MEMREADIO]] : !hw.inout<i64>
|
||||
// CONN: %[[CLOCK:.+]] = seq.from_clock %clk
|
||||
// CONN: sv.alwaysff(posedge %[[CLOCK]]) {
|
||||
// CONN: sv.if %[[ANDVR]] {
|
||||
// CONN: %[[ARRIDX:.*]] = sv.array_index_inout %MemA[%address] : !hw.inout<uarray<20xi64>>, i5
|
||||
// CONN: %[[ADDR:.*]] = hw.bitcast %address : (ui5) -> i5
|
||||
// CONN: %[[ARRIDX:.*]] = sv.array_index_inout %MemA[%[[ADDR]]] : !hw.inout<uarray<20xi64>>, i5
|
||||
// CONN: sv.passign %[[ARRIDX]], %data : i64
|
||||
// CONN: }
|
||||
// CONN: }(syncreset : posedge %rst) {
|
||||
|
@ -144,11 +146,11 @@ esi.pure_module @LoopbackCosimPure {
|
|||
// CONN: hw.output %chanOutput_0, %chanOutput : !esi.channel<i64>, !esi.channel<i0>
|
||||
|
||||
esi.mem.ram @MemA i64 x 20
|
||||
!write = !hw.struct<address: i5, data: i64>
|
||||
!write = !hw.struct<address: ui5, data: i64>
|
||||
!writeBundle = !esi.bundle<[!esi.channel<!write> from "req", !esi.channel<i0> to "ack"]>
|
||||
!readBundle = !esi.bundle<[!esi.channel<i5> from "address", !esi.channel<i64> to "data"]>
|
||||
!readBundle = !esi.bundle<[!esi.channel<ui5> from "address", !esi.channel<i64> to "data"]>
|
||||
|
||||
hw.module @MemoryAccess1(in %clk : !seq.clock, in %rst : i1, in %write : !esi.channel<!write>, in %readAddress : !esi.channel<i5>, out readData : !esi.channel<i64>, out writeDone : !esi.channel<i0>) {
|
||||
hw.module @MemoryAccess1(in %clk : !seq.clock, in %rst : i1, in %write : !esi.channel<!write>, in %readAddress : !esi.channel<ui5>, out readData : !esi.channel<i64>, out writeDone : !esi.channel<i0>) {
|
||||
esi.service.instance #esi.appid<"mem"> svc @MemA impl as "sv_mem" (%clk, %rst) : (!seq.clock, i1) -> ()
|
||||
%writeBundle = esi.service.req <@MemA::@write> (#esi.appid<"write">) : !writeBundle
|
||||
%done = esi.bundle.unpack %write from %writeBundle : !writeBundle
|
||||
|
@ -158,11 +160,11 @@ hw.module @MemoryAccess1(in %clk : !seq.clock, in %rst : i1, in %write : !esi.ch
|
|||
hw.output %readData, %done : !esi.channel<i64>, !esi.channel<i0>
|
||||
}
|
||||
|
||||
// CONN-LABEL: hw.module @MemoryAccess2Read(in %clk : !seq.clock, in %rst : i1, in %write : !esi.channel<!hw.struct<address: i5, data: i64>>, in %readAddress : !esi.channel<i5>, in %readAddress2 : !esi.channel<i5>, out readData : !esi.channel<i64>, out readData2 : !esi.channel<i64>, out writeDone : !esi.channel<i0>) {
|
||||
// CONN-LABEL: hw.module @MemoryAccess2Read(in %clk : !seq.clock, in %rst : i1, in %write : !esi.channel<!hw.struct<address: ui5, data: i64>>, in %readAddress : !esi.channel<ui5>, in %readAddress2 : !esi.channel<ui5>, out readData : !esi.channel<i64>, out readData2 : !esi.channel<i64>, out writeDone : !esi.channel<i0>) {
|
||||
// CONN: %MemA = sv.reg : !hw.inout<uarray<20xi64>>
|
||||
// CONN: hw.output %chanOutput_0, %chanOutput_4, %chanOutput : !esi.channel<i64>, !esi.channel<i64>, !esi.channel<i0>
|
||||
|
||||
hw.module @MemoryAccess2Read(in %clk: !seq.clock, in %rst: i1, in %write: !esi.channel<!write>, in %readAddress: !esi.channel<i5>, in %readAddress2: !esi.channel<i5>, out readData: !esi.channel<i64>, out readData2: !esi.channel<i64>, out writeDone: !esi.channel<i0>) {
|
||||
hw.module @MemoryAccess2Read(in %clk: !seq.clock, in %rst: i1, in %write: !esi.channel<!write>, in %readAddress: !esi.channel<ui5>, in %readAddress2: !esi.channel<ui5>, out readData: !esi.channel<i64>, out readData2: !esi.channel<i64>, out writeDone: !esi.channel<i0>) {
|
||||
esi.service.instance #esi.appid<"mem"> svc @MemA impl as "sv_mem" (%clk, %rst) : (!seq.clock, i1) -> ()
|
||||
|
||||
%writeBundle = esi.service.req <@MemA::@write> (#esi.appid<"write">) : !writeBundle
|
||||
|
|
|
@ -27,10 +27,10 @@
|
|||
// CHECK-SAME: in %reset : i1,
|
||||
// CHECK-SAME: out out0 : !esi.channel<i0>
|
||||
// CHECK-SAME: ) {
|
||||
//CHECK-NEXT: [[B0:%.+]] = esi.service.req <@mem::@read>(#esi.appid<"load"[1]>) : !esi.bundle<[!esi.channel<i4> from "address", !esi.channel<i32> to "data"]>
|
||||
//CHECK-NEXT: %data = esi.bundle.unpack %main.mem_ld0.addr from [[B0]] : !esi.bundle<[!esi.channel<i4> from "address", !esi.channel<i32> to "data"]>
|
||||
//CHECK-NEXT: [[B1:%.+]] = esi.service.req <@mem::@write>(#esi.appid<"store"[2]>) : !esi.bundle<[!esi.channel<!hw.struct<address: i4, data: i32>> from "req", !esi.channel<i0> to "ack"]>
|
||||
//CHECK-NEXT: %ack = esi.bundle.unpack %main.mem_st0 from [[B1]] : !esi.bundle<[!esi.channel<!hw.struct<address: i4, data: i32>> from "req", !esi.channel<i0> to "ack"]>
|
||||
//CHECK-NEXT: [[B0:%.+]] = esi.service.req <@mem::@read>(#esi.appid<"load"[1]>) : !esi.bundle<[!esi.channel<ui4> from "address", !esi.channel<i32> to "data"]>
|
||||
//CHECK-NEXT: %data = esi.bundle.unpack %main.mem_ld0.addr from [[B0]] : !esi.bundle<[!esi.channel<ui4> from "address", !esi.channel<i32> to "data"]>
|
||||
//CHECK-NEXT: [[B1:%.+]] = esi.service.req <@mem::@write>(#esi.appid<"store"[2]>) : !esi.bundle<[!esi.channel<!hw.struct<address: ui4, data: i32>> from "req", !esi.channel<i0> to "ack"]>
|
||||
//CHECK-NEXT: %ack = esi.bundle.unpack %main.mem_st0 from [[B1]] : !esi.bundle<[!esi.channel<!hw.struct<address: ui4, data: i32>> from "req", !esi.channel<i0> to "ack"]>
|
||||
//CHECK-NEXT: %main.out0, %main.mem_ld0.addr, %main.mem_st0 = hw.instance "main" @__main_hw(arg0: %arg0: !esi.channel<i64>, arg1: %arg1: !esi.channel<i64>, v: %v: !esi.channel<i32>, mem_ld0.data: %data: !esi.channel<i32>, mem_st0.done: %ack: !esi.channel<i0>, argCtrl: %argCtrl: !esi.channel<i0>, clock: %clock: !seq.clock, reset: %reset: i1) -> (out0: !esi.channel<i0>, mem_ld0.addr: !esi.channel<i4>, mem_st0: !esi.channel<!hw.struct<address: i4, data: i32>>)
|
||||
//CHECK-NEXT: hw.output %main.out0 : !esi.channel<i0>
|
||||
//CHECK-NEXT: }
|
||||
|
|
Loading…
Reference in New Issue