Skip to content

Commit be7ecf6

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

File tree

10 files changed

+643
-267
lines changed

10 files changed

+643
-267
lines changed

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: 110 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,80 +1042,74 @@ 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-
}),
1071-
);
1066+
type = m['type']!,
1067+
nzfMask = m['nzfMask']!,
1068+
zfMask = m['zfMask']!;
10721069

1073-
OperationDecodePattern copyWith({int? opIndex}) => OperationDecodePattern(
1070+
OperationDecodePattern copyWith({int? opIndex, int? type}) => OperationDecodePattern(
10741071
mask,
10751072
value,
10761073
opIndex ?? this.opIndex,
1077-
nonZeroFields,
1074+
type ?? this.type,
1075+
nzfMask,
1076+
zfMask,
10781077
);
10791078

10801079
Map<String, int> toMap() => {
10811080
'mask': mask,
10821081
'value': value,
10831082
'opIndex': opIndex,
1084-
...nonZeroFields.map((k, _) => MapEntry('nzf$k', 1)),
1083+
'type': type,
1084+
'nzfMask': nzfMask,
1085+
'zfMask': zfMask,
10851086
};
10861087

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

10901091
@override
10911092
String toString() =>
1092-
'OperationDecodePattern($mask, $value, $opIndex, $nonZeroFields)';
1093+
'OperationDecodePattern($mask, $value, $opIndex, $type, $nzfMask, $zfMask)';
10931094

1094-
static BitStruct struct(int opIndexWidth, Map<int, String> fields) {
1095+
static BitStruct struct(int opIndexWidth, int typeWidth, Map<int, String> fields) {
10951096
final mapping = <String, BitRange>{};
10961097
mapping['mask'] = BitRange(0, 31);
10971098
mapping['value'] = BitRange(32, 63);
10981099
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-
1100+
mapping['type'] = BitRange(64 + opIndexWidth, 64 + opIndexWidth + typeWidth - 1);
1101+
mapping['nzfMask'] = BitRange(64 + opIndexWidth + typeWidth, 64 + opIndexWidth + typeWidth + 31);
1102+
mapping['zfMask'] = BitRange(64 + opIndexWidth + typeWidth + 32, 64 + opIndexWidth + typeWidth + 32 + 31);
11081103
return BitStruct(mapping);
11091104
}
11101105

11111106
static OperationDecodePattern decode(
11121107
int opIndexWidth,
1108+
int typeWidth,
11131109
Map<int, String> indices,
1114-
Map<String, BitRange> ranges,
1115-
int value,
1110+
BigInt value,
11161111
) => OperationDecodePattern.map(
1117-
struct(opIndexWidth, indices).decode(value),
1118-
ranges,
1112+
struct(opIndexWidth, typeWidth, indices).bigDecode(value),
11191113
);
11201114
}
11211115

@@ -1162,7 +1156,7 @@ class Operation<T extends InstructionType> {
11621156
return map;
11631157
}
11641158

1165-
OperationDecodePattern decodePattern(int index) {
1159+
OperationDecodePattern decodePattern(int index, Map<String, int> typeMap) {
11661160
var mask = 0;
11671161
var value = 0;
11681162

@@ -1193,32 +1187,31 @@ class Operation<T extends InstructionType> {
11931187

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

1196-
final nz = <String, BitRange>{};
1190+
int nzfMask = 0;
1191+
11971192
for (final f in nonZeroFields) {
11981193
if (!struct.mapping.containsKey(f)) {
11991194
throw '$mnemonic instruction does not have field $f';
12001195
}
12011196

12021197
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;
1198+
nzfMask |= (r.mask << r.start);
12101199
}
12111200

1201+
int zfMask = 0;
1202+
12121203
for (final f in zeroFields) {
12131204
if (!struct.mapping.containsKey(f)) {
12141205
throw '$mnemonic instruction does not have field $f';
12151206
}
12161207

12171208
final r = struct.mapping[f]!;
1218-
mask |= (r.mask << r.start);
1209+
zfMask |= (r.mask << r.start);
12191210
}
12201211

1221-
return OperationDecodePattern(mask, value, index, nz);
1212+
mask |= zfMask;
1213+
1214+
return OperationDecodePattern(mask, value, index, typeMap[Microcode.instrType(this)]!, nzfMask, zfMask);
12221215
}
12231216

12241217
bool _mapMatch(Map<String, int> map) {
@@ -1301,10 +1294,27 @@ class RiscVExtension {
13011294
return null;
13021295
}
13031296

1304-
Iterable<OperationDecodePattern> get decodePattern => operations
1305-
.asMap()
1306-
.entries
1307-
.map((entry) => entry.value.decodePattern(entry.key));
1297+
Map<String, BitStruct> get typeStructs {
1298+
Map<String, BitStruct> result = {};
1299+
for (final op in operations) {
1300+
final t = Microcode.instrType(op);
1301+
if (result.containsKey(t)) continue;
1302+
result[t] = op.struct;
1303+
}
1304+
return result;
1305+
}
1306+
1307+
Map<String, int> get typeMap => Map.fromEntries(typeStructs.entries.indexed.map((e) => MapEntry(e.$2.key, e.$1)));
1308+
1309+
List<OperationDecodePattern> get decodePattern {
1310+
List<OperationDecodePattern> result = [];
1311+
var i = 0;
1312+
for (final op in operations) {
1313+
result.add(op.decodePattern(i, typeMap));
1314+
i += op.microcode.length + 1;
1315+
}
1316+
return result;
1317+
}
13081318

13091319
Map<OperationDecodePattern, Operation<InstructionType>> get decodeMap {
13101320
// NOTE: we probably should loop through the operations and patterns to ensure coherency.
@@ -1348,17 +1358,53 @@ class Microcode {
13481358

13491359
int get patternWidth => OperationDecodePattern.struct(
13501360
opIndices.length.bitLength,
1361+
typeStructs.length.bitLength,
13511362
fieldIndices,
13521363
).width;
13531364

1365+
int get opIndexWidth => decodeLookup.keys
1366+
.fold(0, (a, b) => a > b ? a : b);
1367+
13541368
int opWidth(Mxlen mxlen) => map.values
13551369
.map((op) => op.microcodeWidth(mxlen))
13561370
.fold(0, (a, b) => a > b ? a : b);
13571371

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));
1372+
Map<int, OperationDecodePattern> get decodeLookup {
1373+
Map<int, OperationDecodePattern> result = {};
1374+
var i = 0;
1375+
for (final e in map.entries) {
1376+
result[i] = e.key.copyWith(opIndex: i);
1377+
i += e.value.microcode.length + 1;
1378+
}
1379+
return result;
1380+
}
1381+
1382+
Map<int, Operation<InstructionType>> get execLookup {
1383+
Map<int, Operation<InstructionType>> result = {};
1384+
var i = 0;
1385+
for (final op in map.values) {
1386+
result[i] = op;
1387+
i += op.microcode.length + 1;
1388+
}
1389+
return result;
1390+
}
1391+
1392+
Map<String, BitStruct> get typeStructs {
1393+
Map<String, BitStruct> result = {};
1394+
for (final op in map.values) {
1395+
final t = instrType(op);
1396+
if (result.containsKey(t)) continue;
1397+
result[t] = op.struct;
1398+
}
1399+
return result;
1400+
}
1401+
1402+
Map<String, int> get typeMap => Map.fromEntries(typeStructs.entries.indexed.map((e) => MapEntry(e.$2.key, e.$1)));
1403+
1404+
List<BigInt> get encodedPatterns {
1405+
List<BigInt> result = [];
1406+
for (final pattern in decodeLookup.values) {
1407+
result.add(pattern.encode(opIndices.length.bitLength, typeMap.length.bitLength, fieldIndices));
13621408
}
13631409
return result;
13641410
}
@@ -1480,14 +1526,9 @@ class Microcode {
14801526

14811527
Operation<InstructionType>? lookup(int instr) {
14821528
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) {
1529+
final nzfMatch = entry.key.nzfMask == 0 || (instr & entry.key.nzfMask) != 0;
1530+
final zfMatch = entry.key.zfMask == 0 || (instr & entry.key.zfMask) == 0;
1531+
if ((instr & entry.key.mask) == entry.key.value && nzfMatch && zfMatch) {
14911532
return entry.value;
14921533
}
14931534
}
@@ -1521,11 +1562,13 @@ class Microcode {
15211562
List<RiscVExtension> extensions,
15221563
) {
15231564
final list = <OperationDecodePattern>[];
1565+
var i = 0;
15241566
for (final ext in extensions) {
15251567
final patterns = ext.decodePattern;
15261568

1527-
for (final pattern in patterns) {
1528-
list.add(pattern.copyWith(opIndex: list.length));
1569+
for (final e in patterns.indexed) {
1570+
list.add(e.$2.copyWith(opIndex: i));
1571+
i += ext.operations[e.$1].microcode.length + 1;
15291572
}
15301573
}
15311574
return list;
@@ -1542,4 +1585,9 @@ class Microcode {
15421585
// NOTE: we probably should loop through the operations and patterns to ensure coherency.
15431586
return Map.fromIterables(patterns, operations);
15441587
}
1588+
1589+
static String instrType<T extends InstructionType>(Operation<T> i) {
1590+
final name = i.runtimeType.toString();
1591+
return name.substring(10, name.length - 1);
1592+
}
15451593
}

packages/river/lib/src/river_base.dart

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,42 @@ enum RiverCoreType {
2222
final bool hasCsrs;
2323
}
2424

25+
/// Defines how a segment of the pipeline should be integrated with microcode
26+
enum MicrocodePipelineMode {
27+
/// Contains both microcoded and hard-coded
28+
in_parallel,
29+
30+
/// Contains purely microcoded
31+
standalone,
32+
33+
/// Contains purely hard-coded
34+
none,
35+
}
36+
2537
/// Defines the configuration mode of the microcode
2638
enum MicrocodeMode {
2739
/// No microcode engine
28-
none,
40+
none(),
2941

3042
/// Partial microcode engine
31-
partial,
43+
parallelDecode(onDecoder: MicrocodePipelineMode.in_parallel, onExec: MicrocodePipelineMode.standalone),
44+
45+
/// Partial microcode engine
46+
parallelExec(onDecoder: MicrocodePipelineMode.standalone, onExec: MicrocodePipelineMode.in_parallel),
47+
48+
/// Partial microcode engine
49+
fullParallel(onDecoder: MicrocodePipelineMode.in_parallel, onExec: MicrocodePipelineMode.in_parallel),
3250

3351
/// Full microcode engine
34-
full,
52+
full(onDecoder: MicrocodePipelineMode.standalone, onExec: MicrocodePipelineMode.standalone);
53+
54+
const MicrocodeMode({
55+
this.onDecoder = MicrocodePipelineMode.none,
56+
this.onExec = MicrocodePipelineMode.none,
57+
});
58+
59+
final MicrocodePipelineMode onDecoder;
60+
final MicrocodePipelineMode onExec;
3561
}
3662

3763
/// Method of performing the execution stage of the pipeline

0 commit comments

Comments
 (0)