Skip to content

Commit 29b22ed

Browse files
committed
Merge branch 'main' into search
2 parents 3c20dde + a9f7615 commit 29b22ed

File tree

1 file changed

+41
-31
lines changed

1 file changed

+41
-31
lines changed

src/lib/loadInstructions.js

Lines changed: 41 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ into an array of single characters, each representing one bit.
2828
Returns null if the string isn’t 16 or 32 bits long.
2929
*/
3030
function parseMatchBits(matchStr) {
31-
if (!matchStr) return null;
32-
if (matchStr.length !== 32 && matchStr.length !== 16) return null;
31+
if (matchStr.length !== 16 && matchStr.length !== 32) {
32+
throw new Error(`Invalid match string length ${len}; expected 16 or 32`);
33+
}
3334
return matchStr.split("");
3435
}
3536

@@ -42,26 +43,21 @@ Each segment defines one contiguous region of bits, and fields can have
4243
multiple disjoint segments (like immediates in S- or B-type instructions).
4344
*/
4445
function parseLocationSegments(loc) {
45-
if (loc === undefined || loc === null) return [];
4646
return String(loc)
4747
.split("|")
4848
.map(part => part.trim())
49-
.filter(Boolean)
5049
.map(part => {
5150
const [hiStr, loStr] = part.split("-").map(n => n.trim());
52-
const hi = parseInt(hiStr, 10);
53-
const lo = loStr !== undefined && loStr !== "" ? parseInt(loStr, 10) : hi;
54-
if (Number.isNaN(hi) || Number.isNaN(lo)) return null;
51+
const hi = parseInt(hiStr);
52+
// If no low end is provided (e.g., "31" or "31-"), treat it as a single-bit range at `hi`.
53+
const lo = loStr !== undefined && loStr !== "" ? parseInt(loStr) : hi;
5554
return {
56-
from: Math.max(hi, lo),
57-
to: Math.min(hi, lo)
55+
from: hi,
56+
to: lo
5857
};
5958
})
60-
.filter(Boolean)
61-
.sort((a, b) => (b.from - a.from) || (b.to - a.to));
6259
}
6360

64-
6561
/*
6662
Extract all variable and constant fields from an instruction definition.
6763
@@ -74,15 +70,19 @@ This function handles both flat encodings and multi-variant encodings
7470
...
7571
]
7672
77-
These field objects describe what appears at each bit position.
73+
These field objects describe what appears at each bit position.
74+
The `kind` property indicates whether the field is a variable (part of the instruction encoding)
75+
or a constant (fixed bits defined by the match pattern).
76+
Segments are included for multi-segment fields such as when the location is non-contiguous.
7877
*/
7978
function computeFields(doc) {
79+
// Some instruction docs don't define an encoding; without match/variables we have no bit layout to emit.
8080
const fields = [];
8181
if (!doc.encoding) return fields;
82-
82+
// Encodings may be a flat object with match string/variables or a map of variants (e.g., { RV32: {...}, RV64: {...} });
8383
let enc = doc.encoding;
8484
if (!enc.match && !enc.variables) {
85-
// pick RV32 first, otherwise first available sub-encoding
85+
// pick RV32 first, otherwise first available sub-encoding (not all instructions have both RV32 and RV64)
8686
const variants = Object.keys(enc); // e.g., ["RV32", "RV64"]
8787
const chosenKey = variants.includes("RV32") ? "RV32" : variants[0];
8888
enc = enc[chosenKey] || {};
@@ -93,8 +93,19 @@ function computeFields(doc) {
9393

9494
// --- Parse variable fields (e.g., rd, rs1, imm) ---
9595
for (const v of vars) {
96-
const segments = parseLocationSegments(v.location);
97-
if (segments.length === 0) continue;
96+
const segments = parseLocationSegments(v.location); //not all variables have multiple locations
97+
98+
// ensure segments are sorted MSB->LSB and non-overlapping
99+
const sorted = [...segments].sort((a, b) => b.from - a.from || b.to - a.to);
100+
for (let i = 1; i < sorted.length; i++) {
101+
const prev = sorted[i - 1];
102+
const curr = sorted[i];
103+
const overlaps = Math.max(prev.to, curr.to) <= Math.min(prev.from, curr.from);
104+
if (overlaps) {
105+
throw new Error(`Overlapping segments for ${v.name}: ${JSON.stringify(segments)}`);
106+
}
107+
}
108+
98109
// Find the overall high/low bits and width
99110
const from = Math.max(...segments.map(s => s.from));
100111
const to = Math.min(...segments.map(s => s.to));
@@ -105,13 +116,17 @@ function computeFields(doc) {
105116
// --- Parse constant bit regions from the match pattern ---
106117
// (bits that are fixed 0/1, not "-")
107118
if (match) {
108-
let bit = match.length - 1;
109-
while (bit >= 0) {
119+
for (let bit = match.length - 1; bit >= 0; bit--) {
120+
if (match[match.length - 1 - bit] === "-") continue;
121+
122+
//For a pattern like "0000000-----000-----0110011", this extracts regions such as:
123+
// "0110011" at bits [6:0]
124+
// "000" at bits [14:12]
125+
// "0000000" at bits [31:25]
110126
const hi = bit;
111127
while (bit >= 0 && match[match.length - 1 - bit] !== "-") bit--;
112128
const lo = bit + 1;
113129
const width = hi - lo + 1;
114-
if (width <= 0) { bit--; continue; }
115130

116131
const bits = match.slice(match.length - 1 - hi, match.length - lo).join("");
117132

@@ -188,23 +203,18 @@ function expandBitfieldFields(fields, totalBits = 32) {
188203

189204
// Expand multi-segment fields into individual entries
190205
for (const field of fields) {
206+
// Most fields are contiguous and don't carry a segments array; fall back to [from..to] so they still render.
191207
const segments = Array.isArray(field.segments) && field.segments.length
192208
? field.segments
193209
: [{ from: field.from, to: field.to }];
194210

195211
for (const seg of segments) {
196-
const hi = seg.from;
197-
const lo = seg.to;
198-
const width = hi - lo + 1;
199-
if (width <= 0) continue;
200-
const label =
201-
segments.length > 1
202-
? `${field.label}`
203-
: field.label;
212+
const width = seg.from - seg.to + 1;
213+
const label = field.label;
204214
expanded.push({
205215
label,
206-
from: hi,
207-
to: lo,
216+
from: seg.from,
217+
to: seg.to,
208218
width,
209219
kind: field.kind
210220
});
@@ -273,7 +283,7 @@ module.exports = function loadInstructions() {
273283
reg: filledFields.map(f => {
274284
let name = f.label;
275285
// Constant fields have their label part before "=" removed (e.g., "funct7=0000000" → "0000000").
276-
if (f.kind === "const" && typeof name === "string") {
286+
if (f.kind === "const") {
277287
const idx = name.indexOf("=");
278288
if (idx !== -1 && idx + 1 < name.length) {
279289
name = name.slice(idx + 1);

0 commit comments

Comments
 (0)