Using hw.uarray

I am trying to generate unpacked arrays in Verilog, by trying to use hw.uarray. For example, something as simple as:

hw.module @simple_aggregates_uarray(%a: !hw.uarray<8xi16>) -> (%y: i16) {
    %0 = hw.constant 4 : i3
    %1 = hw.array_get %a[%y] : !hw.uarray<8xi16>
    hw.output %1 : i16
}

However, I get

<stdin>:3:10: error: custom op 'hw.array_get' 'input' must be an ArrayType, but got '!hw.uarray<8xi16>'
    %1 = hw.array_get %a[%y] : !hw.uarray<8xi16>
         ^

It seems like I can’t use hw.uarray in the normal places I could use hw.array (from the tests/ directory, it seems like hw.uarray is only used in inouts?)

Welcome to the CIRCT world!

Yep, you’ve got it - you can only use uarray with inouts. I’d recommend checkout out some of the examples in the testsuite to see working examples, e.g. in test/Conversion/ExportVerilog/hw-dialect.mlir.

-Chris

Thanks Chris!

Is there a specific reason for this restriction? Taking that further, is there a reason that this is a hw concept and not just an option to EmitVerilog?

Is there a specific reason for this restriction?

the main reason is that unpacked arrays are not values in the verilog sense: you can’t pass around copies of something of uarray type. They are intended to be indexed into.

What problem are you running into?

Taking that further, is there a reason that this is a hw concept and not just an option to EmitVerilog?

I’m not sure what you mean here?

-Chris

I think what @setaluri means is that packed vs. unpacked arrays could theoretically be an export verilog style option. I.e. export verilog could use unpacked arrays for every hw.array (if that style is selected) then output the necessary assignments for each element. (I don’t think this makes sense as a style option, if needed I think a pass is more appropriate.)

@setaluri Why do you need unpacked arrays? If you’re not using inout port types, there’s really no reason.

@clattner Didn’t we discuss moving uarray into the sv dialect at some point in the past? Or am I thinking of something else? IIRC, there aren’t any operations in the hw dialect which operate on it.

I think what @setaluri means is that packed vs. unpacked arrays could theoretically be an export verilog style option. I.e. export verilog could use unpacked arrays for every hw.array (if that style is selected) then output the necessary assignments for each element. (I don’t think this makes sense as a style option, if needed I think a pass is more appropriate.)

I mean, that transformation could exist, but why would we want it to? These are conceptually different things, and mean different things to the downstream tools. This isn’t complexity that the IR should paper over, this is inherent to the design the frontend is trying to express.

@clattner Didn’t we discuss moving uarray into the sv dialect at some point in the past? Or am I thinking of something else? IIRC, there aren’t any operations in the hw dialect which operate on it.

Yes, I would prefer that, that is the correct conceptual layering. It just makes some of the predicates in the HW more annoying/complicated to implement, so it hasn’t been worth it.

-Chris

I agree – it’s likely not necessary and indeed a bad idea.

The conceptual difference isn’t intuitively clear in systemverilog – “packed” vs “unpacked” to my ears doesn’t do it. If we’re going to leave it in the hw dialect for practicality reasons, maybe a different name (e.g. hw.ioarray) and some hw level operations which use it are warranted? Tri-state wires (inout) exist in ASIC hardware.

To be clear, I don’t have a strong opinion on this (since FPGAs don’t have tri-state logic) but would like to avoid future confusion.

I think the problem here is that “packed” vs “unpacked” undersells the semantic difference here. Packed arrays are just an abstraction over bags of bits. “unpacked” arrays are a completely different thing (mem inference etc).

The delta isn’t a two letter “un”, the delta is a completely different conceptual landscape.

100% agree. I think we should choose a different term to not repeat that mistake. (Though it’s certainly not a priority and is very likely a distraction at this point.)

@clattner @jdd thanks for the answers. @jdd 's interpretation of my question was correct, but it’s clear to me now that my understanding of the differences between packed and unpacked wasn’t complete.

The reason this came up was trying to get interface-level parity with our old Verilog code generator, which emitted unpacked arrays. Seems to me we need to think about how we’re representing the arrays in the first place.