Skip to content

Commit 7d7fe67

Browse files
committed
Implement configurable radix.
1 parent de28e8a commit 7d7fe67

File tree

7 files changed

+149
-26
lines changed

7 files changed

+149
-26
lines changed

example/.vscode/settings.json

+10-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,14 @@
22
"rtlDebugger.command": [
33
"${workspaceFolder}/design_sim"
44
],
5-
"rtlDebugger.watchList": []
5+
"rtlDebugger.watchList": [
6+
{
7+
"id": "data"
8+
}
9+
],
10+
"rtlDebugger.variableOptions": {
11+
"data": {
12+
"radix": 16
13+
}
14+
}
615
}

package.json

+62-3
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,17 @@
5959
"default": "Verilog",
6060
"markdownDescription": "Specifies the display format for variables."
6161
},
62+
"rtlDebugger.variableOptions": {
63+
"type": "object",
64+
"patternProperties": {
65+
"": {
66+
"type": "object",
67+
"properties": {
68+
"radix": "number"
69+
}
70+
}
71+
}
72+
},
6273
"rtlDebugger.watchList": {
6374
"type": "array",
6475
"items": {
@@ -117,6 +128,26 @@
117128
"title": "Step Backward",
118129
"icon": "$(debug-step-back)"
119130
},
131+
{
132+
"command": "rtlDebugger.setRadix.2",
133+
"category": "RTL Debugger",
134+
"title": "Use Radix 2"
135+
},
136+
{
137+
"command": "rtlDebugger.setRadix.8",
138+
"category": "RTL Debugger",
139+
"title": "Use Radix 8"
140+
},
141+
{
142+
"command": "rtlDebugger.setRadix.10",
143+
"category": "RTL Debugger",
144+
"title": "Use Radix 10"
145+
},
146+
{
147+
"command": "rtlDebugger.setRadix.16",
148+
"category": "RTL Debugger",
149+
"title": "Use Radix 16"
150+
},
120151
{
121152
"command": "rtlDebugger.watchVariable",
122153
"category": "RTL Debugger",
@@ -223,18 +254,46 @@
223254
}
224255
],
225256
"view/item/context": [
257+
{
258+
"submenu": "rtlDebugger.setRadix",
259+
"when": "view == rtlDebugger.sidebar && viewItem =~ /canSetRadix/"
260+
},
226261
{
227262
"command": "rtlDebugger.watchVariable",
228-
"when": "view == rtlDebugger.sidebar && viewItem == canWatch",
263+
"when": "view == rtlDebugger.sidebar && viewItem =~ /canWatch/",
229264
"group": "inline"
230265
},
231266
{
232267
"command": "rtlDebugger.unWatchVariable",
233-
"when": "view == rtlDebugger.sidebar && viewItem == inWatchList",
268+
"when": "view == rtlDebugger.sidebar && viewItem =~ /inWatchList/",
234269
"group": "inline"
235270
}
271+
],
272+
"rtlDebugger.setRadix": [
273+
{
274+
"command": "rtlDebugger.setRadix.2",
275+
"group": "radix@2"
276+
},
277+
{
278+
"command": "rtlDebugger.setRadix.8",
279+
"group": "radix@8"
280+
},
281+
{
282+
"command": "rtlDebugger.setRadix.10",
283+
"group": "radix@10"
284+
},
285+
{
286+
"command": "rtlDebugger.setRadix.16",
287+
"group": "radix@16"
288+
}
236289
]
237-
}
290+
},
291+
"submenus": [
292+
{
293+
"id": "rtlDebugger.setRadix",
294+
"label": "Radix"
295+
}
296+
]
238297
},
239298
"scripts": {
240299
"lint": "eslint --fix",

src/debug/options.ts

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import * as vscode from 'vscode';
2+
3+
export interface IVariableOptions {
4+
radix?: 2 | 8 | 10 | 16
5+
}
6+
7+
export interface IVariableOptionStore {
8+
get(id: string): IVariableOptions;
9+
set(id: string, options: IVariableOptions): void;
10+
update(id: string, options: IVariableOptions): void;
11+
}
12+
13+
export const globalVariableOptions: IVariableOptionStore = {
14+
get(id: string): IVariableOptions {
15+
const optionStore: {[id: string]: IVariableOptions} =
16+
vscode.workspace.getConfiguration('rtlDebugger').get('variableOptions') || {};
17+
return optionStore[id] || {};
18+
},
19+
20+
set(id: string, options: IVariableOptions): void {
21+
const optionStore: {[id: string]: IVariableOptions} =
22+
vscode.workspace.getConfiguration('rtlDebugger').get('variableOptions') || {};
23+
optionStore[id] = options;
24+
vscode.workspace.getConfiguration('rtlDebugger').update('variableOptions', optionStore);
25+
},
26+
27+
update(id: string, addedOptions: IVariableOptions): void {
28+
const options = Object.fromEntries(Object.entries(this.get(id)));
29+
Object.assign(options, addedOptions);
30+
this.set(id, options);
31+
}
32+
};

src/debug/watch.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export interface IWatchList {
1515
onDidChange(callback: (items: IWatchItem[]) => any): vscode.Disposable;
1616
}
1717

18-
export const watchList: IWatchList = {
18+
export const globalWatchList: IWatchList = {
1919
get(): IWatchItem[] {
2020
return vscode.workspace.getConfiguration('rtlDebugger').get('watchList') || [];
2121
},
@@ -37,7 +37,7 @@ export const watchList: IWatchList = {
3737
onDidChange(callback: (items: IWatchItem[]) => any): vscode.Disposable {
3838
return vscode.workspace.onDidChangeConfiguration((event) => {
3939
if (event.affectsConfiguration('rtlDebugger.watchList')) {
40-
callback(watchList.get());
40+
callback(globalWatchList.get());
4141
}
4242
});
4343
},

src/extension.ts

+13-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import * as vscode from 'vscode';
2-
import { watchList } from './debug/watch';
2+
import { globalWatchList } from './debug/watch';
33
import { CXXRTLDebugger } from './debugger';
44
import * as sidebar from './ui/sidebar';
55
import { inputTime } from './ui/input';
6+
import { globalVariableOptions } from './debug/options';
67

78
export function activate(context: vscode.ExtensionContext) {
89
const rtlDebugger = new CXXRTLDebugger();
@@ -50,10 +51,19 @@ export function activate(context: vscode.ExtensionContext) {
5051
context.subscriptions.push(vscode.commands.registerCommand('rtlDebugger.stepForward', () =>
5152
rtlDebugger.session!.stepForward()));
5253

54+
context.subscriptions.push(vscode.commands.registerCommand('rtlDebugger.setRadix.2', (treeItem) =>
55+
globalVariableOptions.update(treeItem.designation.variable.cxxrtlIdentifier, { radix: 2 })));
56+
context.subscriptions.push(vscode.commands.registerCommand('rtlDebugger.setRadix.8', (treeItem) =>
57+
globalVariableOptions.update(treeItem.designation.variable.cxxrtlIdentifier, { radix: 8 })));
58+
context.subscriptions.push(vscode.commands.registerCommand('rtlDebugger.setRadix.10', (treeItem) =>
59+
globalVariableOptions.update(treeItem.designation.variable.cxxrtlIdentifier, { radix: 10 })));
60+
context.subscriptions.push(vscode.commands.registerCommand('rtlDebugger.setRadix.16', (treeItem) =>
61+
globalVariableOptions.update(treeItem.designation.variable.cxxrtlIdentifier, { radix: 16 })));
62+
5363
context.subscriptions.push(vscode.commands.registerCommand('rtlDebugger.watchVariable', (treeItem) =>
54-
watchList.append(treeItem.getWatchItem())));
64+
globalWatchList.append(treeItem.getWatchItem())));
5565
context.subscriptions.push(vscode.commands.registerCommand('rtlDebugger.unWatchVariable', (treeItem) =>
56-
watchList.remove(treeItem.metadata.index)));
66+
globalWatchList.remove(treeItem.metadata.index)));
5767

5868
// For an unknown reason, the `vscode.open` command (which does the exact same thing) ignores the options.
5969
context.subscriptions.push(vscode.commands.registerCommand('rtlDebugger.openDocument',

src/model/styling.ts

+15-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as vscode from 'vscode';
22

33
import { MemoryVariable, ScalarVariable, Variable } from './variable';
4+
import { globalVariableOptions } from '../debug/options';
45

56
export enum DisplayStyle {
67
Python = 'Python',
@@ -65,26 +66,35 @@ export function* memoryRowIndices(variable: MemoryVariable): Generator<number> {
6566
}
6667
}
6768

68-
export function variableValue(style: DisplayStyle, variable: Variable, value: bigint | undefined, base: 2 | 8 | 10 | 16 = 10): string {
69+
export function variableValue(style: DisplayStyle, variable: Variable, value: bigint | undefined, radix?: 2 | 8 | 10 | 16): string {
6970
if (value === undefined) {
7071
return '...';
71-
} else if (variable.width === 1) {
72+
}
73+
74+
// There is a bug in CXXRTL that occasionally causes out-of-bounds bits to be set.
75+
// Ideally it should be fixed there, but for now let's work around it here, for usability.
76+
value &= (1n << BigInt(variable.width)) - 1n;
77+
78+
if (variable.width === 1) {
7279
return value.toString();
7380
} else {
81+
if (radix === undefined) {
82+
radix = globalVariableOptions.get(variable.cxxrtlIdentifier).radix ?? 10;
83+
}
7484
switch (style) {
7585
case DisplayStyle.Python:
76-
switch (base) {
86+
switch (radix) {
7787
case 2: return `0b${value.toString(2)}`;
7888
case 8: return `0o${value.toString(8)}`;
7989
case 10: return value.toString(10);
8090
case 16: return `0x${value.toString(16)}`;
8191
}
8292

8393
case DisplayStyle.Verilog:
84-
return `${base}'${value.toString(base)}`;
94+
return `${radix}'${value.toString(radix)}`;
8595

8696
case DisplayStyle.VHDL:
87-
switch (base) {
97+
switch (radix) {
8898
case 2: return `B"${value.toString(2)}"`;
8999
case 8: return `O"${value.toString(8)}"`;
90100
case 10: return value.toString(10);

src/ui/sidebar.ts

+15-12
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { DisplayStyle, variableDescription, variableBitIndices, memoryRowIndices
66
import { CXXRTLDebugger } from '../debugger';
77
import { Observer } from '../debug/observer';
88
import { Designation, MemoryRangeDesignation, MemoryRowDesignation, ScalarDesignation } from '../model/sample';
9-
import { IWatchItem, watchList } from '../debug/watch';
9+
import { IWatchItem, globalWatchList } from '../debug/watch';
1010
import { Session } from '../debug/session';
1111

1212
abstract class TreeItem {
@@ -37,7 +37,7 @@ class BitTreeItem extends TreeItem {
3737
provider: TreeDataProvider,
3838
readonly designation: ScalarDesignation | MemoryRowDesignation,
3939
readonly bitIndex: number,
40-
readonly contextValue?: string,
40+
readonly contextValue: string = '',
4141
) {
4242
super(provider);
4343
}
@@ -81,7 +81,7 @@ class ScalarTreeItem extends TreeItem {
8181
constructor(
8282
provider: TreeDataProvider,
8383
readonly designation: ScalarDesignation | MemoryRowDesignation,
84-
readonly contextValue?: string,
84+
readonly contextValue: string = '',
8585
) {
8686
super(provider);
8787
}
@@ -127,7 +127,7 @@ class ArrayTreeItem extends TreeItem {
127127
constructor(
128128
provider: TreeDataProvider,
129129
readonly designation: MemoryRangeDesignation,
130-
readonly contextValue?: string,
130+
readonly contextValue: string = '',
131131
) {
132132
super(provider);
133133
}
@@ -197,10 +197,11 @@ class ScopeTreeItem extends TreeItem {
197197
}
198198
for (const variable of await this.scope.variables) {
199199
if (variable instanceof ScalarVariable) {
200-
children.push(new ScalarTreeItem(this.provider, variable.designation(), 'canWatch'));
200+
children.push(new ScalarTreeItem(this.provider, variable.designation(),
201+
variable.width > 1 ? 'canWatch|canSetRadix' : 'canWatch'));
201202
}
202203
if (variable instanceof MemoryVariable) {
203-
children.push(new ArrayTreeItem(this.provider, variable.designation(), 'canWatch'));
204+
children.push(new ArrayTreeItem(this.provider, variable.designation(), 'canWatch|canSetRadix'));
204205
}
205206
}
206207
return children;
@@ -215,7 +216,7 @@ class WatchTreeItem extends TreeItem {
215216
}
216217

217218
override async getTreeItem(): Promise<vscode.TreeItem> {
218-
if (watchList.get().length > 0) {
219+
if (globalWatchList.get().length > 0) {
219220
return new vscode.TreeItem('Watch', vscode.TreeItemCollapsibleState.Expanded);
220221
} else {
221222
return new vscode.TreeItem('Watch (empty)');
@@ -224,7 +225,7 @@ class WatchTreeItem extends TreeItem {
224225

225226
override async getChildren(): Promise<TreeItem[]> {
226227
const children = [];
227-
for (const [index, watchItem] of watchList.get().entries()) {
228+
for (const [index, watchItem] of globalWatchList.get().entries()) {
228229
const variable = await this.provider.getVariable(watchItem.id);
229230
if (variable === null) {
230231
continue;
@@ -241,10 +242,11 @@ class WatchTreeItem extends TreeItem {
241242
}
242243
let treeItem;
243244
if (designation instanceof MemoryRangeDesignation) {
244-
treeItem = new ArrayTreeItem(this.provider, designation, 'inWatchList');
245+
treeItem = new ArrayTreeItem(this.provider, designation, 'inWatchList|canSetRadix');
245246
} else if (designation instanceof ScalarDesignation || designation instanceof MemoryRowDesignation) {
246247
if (watchItem.bit === undefined) {
247-
treeItem = new ScalarTreeItem(this.provider, designation, 'inWatchList');
248+
treeItem = new ScalarTreeItem(this.provider, designation,
249+
designation.variable.width > 1 ? 'inWatchList|canSetRadix' : 'inWatchList');
248250
} else {
249251
treeItem = new BitTreeItem(this.provider, designation, watchItem.bit, 'inWatchList');
250252
}
@@ -269,7 +271,8 @@ export class TreeDataProvider implements vscode.TreeDataProvider<TreeItem> {
269271

270272
constructor(rtlDebugger: CXXRTLDebugger) {
271273
vscode.workspace.onDidChangeConfiguration((event) => {
272-
if (event.affectsConfiguration('rtlDebugger.displayStyle')) {
274+
if (event.affectsConfiguration('rtlDebugger.displayStyle') ||
275+
event.affectsConfiguration('rtlDebugger.variableOptions')) {
273276
this._onDidChangeTreeData.fire(null);
274277
}
275278
});
@@ -287,7 +290,7 @@ export class TreeDataProvider implements vscode.TreeDataProvider<TreeItem> {
287290
}
288291
this._onDidChangeTreeData.fire(null);
289292
});
290-
watchList.onDidChange((_items) => {
293+
globalWatchList.onDidChange((_items) => {
291294
if (this.watchTreeItem !== null) {
292295
this._onDidChangeTreeData.fire(this.watchTreeItem);
293296
}

0 commit comments

Comments
 (0)