Skip to content

Commit d857916

Browse files
feat(river_hdl): add microcode decoding
1 parent 5ae51d0 commit d857916

10 files changed

Lines changed: 745 additions & 275 deletions

File tree

packages/riscv/lib/src/helpers.dart

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,14 @@ class BitRange {
99
int get width => end - start + 1;
1010
int get mask => (1 << width) - 1;
1111

12+
BigInt get bigMask => (BigInt.one << width) - BigInt.one;
13+
1214
int encode(int value) => (value & mask) << start;
1315
int decode(int value) => (value >> start) & mask;
1416

17+
BigInt bigEncode(BigInt value) => (value & bigMask) << start;
18+
BigInt bigDecode(BigInt value) => (value >> start) & bigMask;
19+
1520
@override
1621
String toString() => 'BitRange($start, $end)';
1722
}
@@ -38,6 +43,23 @@ class BitStruct {
3843
return result;
3944
}
4045

46+
Map<String, int> bigDecode(BigInt value) {
47+
final result = <String, int>{};
48+
mapping.forEach((name, range) {
49+
result[name] = range!.bigDecode(value).toInt();
50+
});
51+
return result;
52+
}
53+
54+
BigInt bigEncode(Map<String, int> fields) {
55+
BigInt result = BigInt.zero;
56+
fields.forEach((name, val) {
57+
final range = mapping[name];
58+
result |= range!.bigEncode(BigInt.from(val));
59+
});
60+
return result;
61+
}
62+
4163
int getField(int value, String name) {
4264
final range = mapping[name];
4365
return range!.decode(value);
@@ -58,7 +80,16 @@ class BitStruct {
5880
return encode(map);
5981
}
6082

61-
int get width => mask.bitLength;
83+
int get width {
84+
var i = 0;
85+
mapping.forEach((name, val) {
86+
i = (val.end + 1) > i ? (val.end + 1) : i;
87+
});
88+
return i;
89+
}
90+
91+
@override
92+
String toString() => 'BitStruct($mapping)';
6293
}
6394

6495
int signExtend(int value, int bits) {

packages/riscv/lib/src/ops.dart

Lines changed: 145 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,80 +1042,88 @@ class ReadCsrMicroOp extends MicroOp {
10421042
BitStruct({'funct': MicroOp.functRange, 'source': const BitRange(5, 8)});
10431043
}
10441044

1045-
/// ---------------------------------------------------------------------------
1046-
/// Operation / RiscVExtension / Microcode
1047-
/// ---------------------------------------------------------------------------
1048-
10491045
class OperationDecodePattern {
10501046
final int mask;
10511047
final int value;
10521048
final int opIndex;
1053-
final Map<String, BitRange> nonZeroFields;
1049+
final int type;
1050+
final int nzfMask;
1051+
final int zfMask;
10541052

10551053
const OperationDecodePattern(
10561054
this.mask,
10571055
this.value,
10581056
this.opIndex,
1059-
this.nonZeroFields,
1057+
this.type,
1058+
this.nzfMask,
1059+
this.zfMask,
10601060
);
10611061

1062-
OperationDecodePattern.map(Map<String, int> m, Map<String, BitRange> fields)
1062+
OperationDecodePattern.map(Map<String, int> m)
10631063
: mask = m['mask']!,
10641064
value = m['value']!,
10651065
opIndex = m['opIndex']!,
1066-
nonZeroFields = Map.fromEntries(
1067-
m.entries.where((e) => e.key.startsWith('nzf')).map((e) {
1068-
final key = e.key.substring(3);
1069-
return MapEntry(key, fields[key]!);
1070-
}),
1066+
type = m['type']!,
1067+
nzfMask = m['nzfMask']!,
1068+
zfMask = m['zfMask']!;
1069+
1070+
OperationDecodePattern copyWith({int? opIndex, int? type}) =>
1071+
OperationDecodePattern(
1072+
mask,
1073+
value,
1074+
opIndex ?? this.opIndex,
1075+
type ?? this.type,
1076+
nzfMask,
1077+
zfMask,
10711078
);
10721079

1073-
OperationDecodePattern copyWith({int? opIndex}) => OperationDecodePattern(
1074-
mask,
1075-
value,
1076-
opIndex ?? this.opIndex,
1077-
nonZeroFields,
1078-
);
1079-
10801080
Map<String, int> toMap() => {
10811081
'mask': mask,
10821082
'value': value,
10831083
'opIndex': opIndex,
1084-
...nonZeroFields.map((k, _) => MapEntry('nzf$k', 1)),
1084+
'type': type,
1085+
'nzfMask': nzfMask,
1086+
'zfMask': zfMask,
10851087
};
10861088

1087-
int encode(int opIndexWidth, Map<int, String> fields) =>
1088-
struct(opIndexWidth, fields).encode(toMap());
1089+
BigInt encode(int opIndexWidth, int typeWidth, Map<int, String> fields) =>
1090+
struct(opIndexWidth, typeWidth, fields).bigEncode(toMap());
10891091

10901092
@override
10911093
String toString() =>
1092-
'OperationDecodePattern($mask, $value, $opIndex, $nonZeroFields)';
1094+
'OperationDecodePattern($mask, $value, $opIndex, $type, $nzfMask, $zfMask)';
10931095

1094-
static BitStruct struct(int opIndexWidth, Map<int, String> fields) {
1096+
static BitStruct struct(
1097+
int opIndexWidth,
1098+
int typeWidth,
1099+
Map<int, String> fields,
1100+
) {
10951101
final mapping = <String, BitRange>{};
10961102
mapping['mask'] = BitRange(0, 31);
10971103
mapping['value'] = BitRange(32, 63);
10981104
mapping['opIndex'] = BitRange(64, 64 + opIndexWidth - 1);
1099-
1100-
var offset = 64 + opIndexWidth;
1101-
1102-
final sortedFields = fields.entries.toList()
1103-
..sort((a, b) => a.key.compareTo(b.key));
1104-
for (final field in sortedFields) {
1105-
mapping['nzf${field.key}'] = BitRange.single(offset++);
1106-
}
1107-
1105+
mapping['type'] = BitRange(
1106+
64 + opIndexWidth,
1107+
64 + opIndexWidth + typeWidth - 1,
1108+
);
1109+
mapping['nzfMask'] = BitRange(
1110+
64 + opIndexWidth + typeWidth,
1111+
64 + opIndexWidth + typeWidth + 31,
1112+
);
1113+
mapping['zfMask'] = BitRange(
1114+
64 + opIndexWidth + typeWidth + 32,
1115+
64 + opIndexWidth + typeWidth + 32 + 31,
1116+
);
11081117
return BitStruct(mapping);
11091118
}
11101119

11111120
static OperationDecodePattern decode(
11121121
int opIndexWidth,
1122+
int typeWidth,
11131123
Map<int, String> indices,
1114-
Map<String, BitRange> ranges,
1115-
int value,
1124+
BigInt value,
11161125
) => OperationDecodePattern.map(
1117-
struct(opIndexWidth, indices).decode(value),
1118-
ranges,
1126+
struct(opIndexWidth, typeWidth, indices).bigDecode(value),
11191127
);
11201128
}
11211129

@@ -1162,7 +1170,7 @@ class Operation<T extends InstructionType> {
11621170
return map;
11631171
}
11641172

1165-
OperationDecodePattern decodePattern(int index) {
1173+
OperationDecodePattern decodePattern(int index, Map<String, int> typeMap) {
11661174
var mask = 0;
11671175
var value = 0;
11681176

@@ -1193,32 +1201,38 @@ class Operation<T extends InstructionType> {
11931201

11941202
if (funct12 != null) bind(struct.mapping['funct12']!, funct12);
11951203

1196-
final nz = <String, BitRange>{};
1204+
int nzfMask = 0;
1205+
11971206
for (final f in nonZeroFields) {
11981207
if (!struct.mapping.containsKey(f)) {
11991208
throw '$mnemonic instruction does not have field $f';
12001209
}
12011210

12021211
final r = struct.mapping[f]!;
1203-
1204-
final shiftedMask = r.mask << r.start;
1205-
mask |= shiftedMask;
1206-
1207-
final lsbBit = 1 << r.start;
1208-
value |= lsbBit;
1209-
nz[f] = r;
1212+
nzfMask |= (r.mask << r.start);
12101213
}
12111214

1215+
int zfMask = 0;
1216+
12121217
for (final f in zeroFields) {
12131218
if (!struct.mapping.containsKey(f)) {
12141219
throw '$mnemonic instruction does not have field $f';
12151220
}
12161221

12171222
final r = struct.mapping[f]!;
1218-
mask |= (r.mask << r.start);
1223+
zfMask |= (r.mask << r.start);
12191224
}
12201225

1221-
return OperationDecodePattern(mask, value, index, nz);
1226+
mask |= zfMask;
1227+
1228+
return OperationDecodePattern(
1229+
mask,
1230+
value,
1231+
index,
1232+
typeMap[Microcode.instrType(this)]!,
1233+
nzfMask,
1234+
zfMask,
1235+
);
12221236
}
12231237

12241238
bool _mapMatch(Map<String, int> map) {
@@ -1301,10 +1315,29 @@ class RiscVExtension {
13011315
return null;
13021316
}
13031317

1304-
Iterable<OperationDecodePattern> get decodePattern => operations
1305-
.asMap()
1306-
.entries
1307-
.map((entry) => entry.value.decodePattern(entry.key));
1318+
Map<String, BitStruct> get typeStructs {
1319+
Map<String, BitStruct> result = {};
1320+
for (final op in operations) {
1321+
final t = Microcode.instrType(op);
1322+
if (result.containsKey(t)) continue;
1323+
result[t] = op.struct;
1324+
}
1325+
return result;
1326+
}
1327+
1328+
Map<String, int> get typeMap => Map.fromEntries(
1329+
typeStructs.entries.indexed.map((e) => MapEntry(e.$2.key, e.$1)),
1330+
);
1331+
1332+
List<OperationDecodePattern> get decodePattern {
1333+
List<OperationDecodePattern> result = [];
1334+
var i = 0;
1335+
for (final op in operations) {
1336+
result.add(op.decodePattern(i, typeMap));
1337+
i += op.microcode.length + 1;
1338+
}
1339+
return result;
1340+
}
13081341

13091342
Map<OperationDecodePattern, Operation<InstructionType>> get decodeMap {
13101343
// NOTE: we probably should loop through the operations and patterns to ensure coherency.
@@ -1348,17 +1381,60 @@ class Microcode {
13481381

13491382
int get patternWidth => OperationDecodePattern.struct(
13501383
opIndices.length.bitLength,
1384+
typeStructs.length.bitLength,
13511385
fieldIndices,
13521386
).width;
13531387

1388+
int get opIndexWidth => decodeLookup.keys.fold(0, (a, b) => a > b ? a : b);
1389+
13541390
int opWidth(Mxlen mxlen) => map.values
13551391
.map((op) => op.microcodeWidth(mxlen))
13561392
.fold(0, (a, b) => a > b ? a : b);
13571393

1358-
List<int> get encodedPatterns {
1359-
List<int> result = [];
1360-
for (final pattern in map.keys) {
1361-
result.add(pattern.encode(opIndices.length.bitLength, fieldIndices));
1394+
Map<int, OperationDecodePattern> get decodeLookup {
1395+
Map<int, OperationDecodePattern> result = {};
1396+
var i = 0;
1397+
for (final e in map.entries) {
1398+
result[i] = e.key.copyWith(opIndex: i);
1399+
i += e.value.microcode.length + 1;
1400+
}
1401+
return result;
1402+
}
1403+
1404+
Map<int, Operation<InstructionType>> get execLookup {
1405+
Map<int, Operation<InstructionType>> result = {};
1406+
var i = 0;
1407+
for (final op in map.values) {
1408+
result[i] = op;
1409+
i += op.microcode.length + 1;
1410+
}
1411+
return result;
1412+
}
1413+
1414+
Map<String, BitStruct> get typeStructs {
1415+
Map<String, BitStruct> result = {};
1416+
for (final op in map.values) {
1417+
final t = instrType(op);
1418+
if (result.containsKey(t)) continue;
1419+
result[t] = op.struct;
1420+
}
1421+
return result;
1422+
}
1423+
1424+
Map<String, int> get typeMap => Map.fromEntries(
1425+
typeStructs.entries.indexed.map((e) => MapEntry(e.$2.key, e.$1)),
1426+
);
1427+
1428+
List<BigInt> get encodedPatterns {
1429+
List<BigInt> result = [];
1430+
for (final pattern in decodeLookup.values) {
1431+
result.add(
1432+
pattern.encode(
1433+
opIndices.length.bitLength,
1434+
typeMap.length.bitLength,
1435+
fieldIndices,
1436+
),
1437+
);
13621438
}
13631439
return result;
13641440
}
@@ -1480,14 +1556,10 @@ class Microcode {
14801556

14811557
Operation<InstructionType>? lookup(int instr) {
14821558
for (final entry in map.entries) {
1483-
final decoded = entry.value.struct.decode(instr);
1484-
1485-
for (final field in entry.key.nonZeroFields.keys) {
1486-
decoded[field] = 1;
1487-
}
1488-
1489-
final temp = entry.value.struct.encode(decoded);
1490-
if ((temp & entry.key.mask) == entry.key.value) {
1559+
final nzfMatch =
1560+
entry.key.nzfMask == 0 || (instr & entry.key.nzfMask) != 0;
1561+
final zfMatch = entry.key.zfMask == 0 || (instr & entry.key.zfMask) == 0;
1562+
if ((instr & entry.key.mask) == entry.key.value && nzfMatch && zfMatch) {
14911563
return entry.value;
14921564
}
14931565
}
@@ -1521,11 +1593,13 @@ class Microcode {
15211593
List<RiscVExtension> extensions,
15221594
) {
15231595
final list = <OperationDecodePattern>[];
1596+
var i = 0;
15241597
for (final ext in extensions) {
15251598
final patterns = ext.decodePattern;
15261599

1527-
for (final pattern in patterns) {
1528-
list.add(pattern.copyWith(opIndex: list.length));
1600+
for (final e in patterns.indexed) {
1601+
list.add(e.$2.copyWith(opIndex: i));
1602+
i += ext.operations[e.$1].microcode.length + 1;
15291603
}
15301604
}
15311605
return list;
@@ -1542,4 +1616,9 @@ class Microcode {
15421616
// NOTE: we probably should loop through the operations and patterns to ensure coherency.
15431617
return Map.fromIterables(patterns, operations);
15441618
}
1619+
1620+
static String instrType<T extends InstructionType>(Operation<T> i) {
1621+
final name = i.runtimeType.toString();
1622+
return name.substring(10, name.length - 1);
1623+
}
15451624
}

0 commit comments

Comments
 (0)