From b060f7b614f5c0a3112786f51161bc0c9f6f145f Mon Sep 17 00:00:00 2001 From: "Korbel, Max" Date: Mon, 1 Dec 2025 11:14:47 -0800 Subject: [PATCH] Add an accessor for the parent port reference of a slice port reference --- lib/src/references/slice_port_reference.dart | 33 ++++++++ test/port_access_test.dart | 84 ++++++++++++++++++-- 2 files changed, 109 insertions(+), 8 deletions(-) diff --git a/lib/src/references/slice_port_reference.dart b/lib/src/references/slice_port_reference.dart index 10a3605..021de2a 100644 --- a/lib/src/references/slice_port_reference.dart +++ b/lib/src/references/slice_port_reference.dart @@ -586,4 +586,37 @@ class SlicePortReference extends PortReference { sliceUpperIndex: newUpperIndex, ); } + + /// The parent [PortReference] of this [SlicePortReference], with slicing or + /// the least significant dimension removed. + /// + /// For example, if this reference is `myPort[2][3:1]`, the parent reference + /// would be `myPort[2]`. If the reference is `myPort[7:0]`, the parent + /// reference would be `myPort`. If the reference is `myPort[3][2][1]`, the + /// parent reference would be `myPort[3][2]`. + /// + /// If there are no slices or dimension accesses left, then `null` is + /// returned. + PortReference? get parentPortReference { + final List? newDimensionAccess; + + if (hasSlicing) { + newDimensionAccess = dimensionAccess; + } else if (dimensionAccess != null && dimensionAccess!.isNotEmpty) { + newDimensionAccess = + dimensionAccess!.sublist(0, dimensionAccess!.length - 1); + } else { + return null; + } + + if (newDimensionAccess != null && newDimensionAccess.isNotEmpty) { + return SlicePortReference( + module, + portName, + dimensionAccess: newDimensionAccess, + ); + } else { + return StandardPortReference(module, portName); + } + } } diff --git a/test/port_access_test.dart b/test/port_access_test.dart index bba18ab..21771b6 100644 --- a/test/port_access_test.dart +++ b/test/port_access_test.dart @@ -358,18 +358,86 @@ void main() { expect(dutDst.input('a').value, LogicValue.of('1111zzzz')); }); - void testInoutResult(PortReference pInEx, PortReference pOutEx, - PortExample inEx, PortExample outEx) { - pInEx.port.put(inEx.putVal); - expect(pOutEx.port.value, outEx.checkVal); + group('parent port reference of slice port reference', () { + test('one dimension, one slice', () { + final mod = BridgeModule('mod') + ..createArrayPort( + 'myPort', + PortDirection.input, + dimensions: [4], + elementWidth: 8, + ); + final p = mod.port('myPort[2][2:1]') as SlicePortReference; + final expected = mod.port('myPort[2]'); + expect(p.parentPortReference, expected); + }); - pInEx.port.put(LogicValue.filled(pInEx.port.width, LogicValue.z)); + test('no dimensions, one slice', () { + final mod = BridgeModule('mod')..addInput('myPort', null, width: 8); + final p = mod.port('myPort[6:3]') as SlicePortReference; + final expected = mod.port('myPort'); + expect(p.parentPortReference, expected); + }); - pOutEx.port.put(outEx.putVal); - expect(pInEx.port.value, inEx.checkVal); - } + test('multiple dimensions, one slice', () { + final mod = BridgeModule('mod') + ..createArrayPort( + 'myPort', + PortDirection.input, + dimensions: [4, 3], + elementWidth: 8, + ); + final p = mod.port('myPort[2][1][5:2]') as SlicePortReference; + final expected = mod.port('myPort[2][1]'); + expect(p.parentPortReference, expected); + }); + + test('multiple dimensions, no slice', () { + final mod = BridgeModule('mod') + ..createArrayPort( + 'myPort', + PortDirection.input, + dimensions: [4, 3], + elementWidth: 8, + ); + final p = mod.port('myPort[2][1]') as SlicePortReference; + final expected = mod.port('myPort[2]'); + expect(p.parentPortReference, expected); + }); + + test('one dimension, no slice', () { + final mod = BridgeModule('mod') + ..createArrayPort( + 'myPort', + PortDirection.input, + dimensions: [4], + elementWidth: 8, + ); + final p = mod.port('myPort[2]') as SlicePortReference; + final expected = mod.port('myPort'); + expect(p.parentPortReference, expected); + }); + + test('no dimensions, no slice - should return null', () { + final mod = BridgeModule('mod')..addInput('myPort', null, width: 8); + final p = SlicePortReference(mod, 'myPort'); + + expect(p.parentPortReference, isNull); + }); + }); group('connections', () { + void testInoutResult(PortReference pInEx, PortReference pOutEx, + PortExample inEx, PortExample outEx) { + pInEx.port.put(inEx.putVal); + expect(pOutEx.port.value, outEx.checkVal); + + pInEx.port.put(LogicValue.filled(pInEx.port.width, LogicValue.z)); + + pOutEx.port.put(outEx.putVal); + expect(pInEx.port.value, inEx.checkVal); + } + final connType = Function(PortExample outEx, PortExample inEx)>{ 'port to port': (outEx, inEx) async {