From 8ddd6976969f35172afe7e4855ed1857f7f88739 Mon Sep 17 00:00:00 2001 From: Catherine Date: Tue, 8 Oct 2024 18:43:13 +0000 Subject: [PATCH] Implement configurable radix. --- example/.vscode/settings.json | 11 +++++- package.json | 65 +++++++++++++++++++++++++++++++++-- src/debug/watch.ts | 4 +-- src/extension.ts | 16 +++++++-- src/model/styling.ts | 20 ++++++++--- src/ui/sidebar.ts | 27 ++++++++------- 6 files changed, 117 insertions(+), 26 deletions(-) diff --git a/example/.vscode/settings.json b/example/.vscode/settings.json index 5ba2a58..1a3a5e6 100644 --- a/example/.vscode/settings.json +++ b/example/.vscode/settings.json @@ -2,5 +2,14 @@ "rtlDebugger.command": [ "${workspaceFolder}/design_sim" ], - "rtlDebugger.watchList": [] + "rtlDebugger.watchList": [ + { + "id": "data" + } + ], + "rtlDebugger.variableOptions": { + "data": { + "radix": 16 + } + } } diff --git a/package.json b/package.json index 8eed0d4..ad43ffd 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,17 @@ "default": "Verilog", "markdownDescription": "Specifies the display format for variables." }, + "rtlDebugger.variableOptions": { + "type": "object", + "patternProperties": { + "": { + "type": "object", + "properties": { + "radix": "number" + } + } + } + }, "rtlDebugger.watchList": { "type": "array", "items": { @@ -117,6 +128,26 @@ "title": "Step Backward", "icon": "$(debug-step-back)" }, + { + "command": "rtlDebugger.setRadix.2", + "category": "RTL Debugger", + "title": "Use Radix 2" + }, + { + "command": "rtlDebugger.setRadix.8", + "category": "RTL Debugger", + "title": "Use Radix 8" + }, + { + "command": "rtlDebugger.setRadix.10", + "category": "RTL Debugger", + "title": "Use Radix 10" + }, + { + "command": "rtlDebugger.setRadix.16", + "category": "RTL Debugger", + "title": "Use Radix 16" + }, { "command": "rtlDebugger.watchVariable", "category": "RTL Debugger", @@ -223,18 +254,46 @@ } ], "view/item/context": [ + { + "submenu": "rtlDebugger.setRadix", + "when": "view == rtlDebugger.sidebar && viewItem =~ /canSetRadix/" + }, { "command": "rtlDebugger.watchVariable", - "when": "view == rtlDebugger.sidebar && viewItem == canWatch", + "when": "view == rtlDebugger.sidebar && viewItem =~ /canWatch/", "group": "inline" }, { "command": "rtlDebugger.unWatchVariable", - "when": "view == rtlDebugger.sidebar && viewItem == inWatchList", + "when": "view == rtlDebugger.sidebar && viewItem =~ /inWatchList/", "group": "inline" } + ], + "rtlDebugger.setRadix": [ + { + "command": "rtlDebugger.setRadix.2", + "group": "radix@2" + }, + { + "command": "rtlDebugger.setRadix.8", + "group": "radix@8" + }, + { + "command": "rtlDebugger.setRadix.10", + "group": "radix@10" + }, + { + "command": "rtlDebugger.setRadix.16", + "group": "radix@16" + } ] - } + }, + "submenus": [ + { + "id": "rtlDebugger.setRadix", + "label": "Radix" + } + ] }, "scripts": { "lint": "eslint --fix", diff --git a/src/debug/watch.ts b/src/debug/watch.ts index b5afecc..914bd72 100644 --- a/src/debug/watch.ts +++ b/src/debug/watch.ts @@ -15,7 +15,7 @@ export interface IWatchList { onDidChange(callback: (items: IWatchItem[]) => any): vscode.Disposable; } -export const watchList: IWatchList = { +export const globalWatchList: IWatchList = { get(): IWatchItem[] { return vscode.workspace.getConfiguration('rtlDebugger').get('watchList') || []; }, @@ -37,7 +37,7 @@ export const watchList: IWatchList = { onDidChange(callback: (items: IWatchItem[]) => any): vscode.Disposable { return vscode.workspace.onDidChangeConfiguration((event) => { if (event.affectsConfiguration('rtlDebugger.watchList')) { - callback(watchList.get()); + callback(globalWatchList.get()); } }); }, diff --git a/src/extension.ts b/src/extension.ts index fa11155..7f60ffd 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,8 +1,9 @@ import * as vscode from 'vscode'; -import { watchList } from './debug/watch'; +import { globalWatchList } from './debug/watch'; import { CXXRTLDebugger } from './debugger'; import * as sidebar from './ui/sidebar'; import { inputTime } from './ui/input'; +import { globalVariableOptions } from './debug/options'; export function activate(context: vscode.ExtensionContext) { const rtlDebugger = new CXXRTLDebugger(); @@ -50,10 +51,19 @@ export function activate(context: vscode.ExtensionContext) { context.subscriptions.push(vscode.commands.registerCommand('rtlDebugger.stepForward', () => rtlDebugger.session!.stepForward())); + context.subscriptions.push(vscode.commands.registerCommand('rtlDebugger.setRadix.2', (treeItem) => + globalVariableOptions.update(treeItem.designation.variable.cxxrtlIdentifier, { radix: 2 }))); + context.subscriptions.push(vscode.commands.registerCommand('rtlDebugger.setRadix.8', (treeItem) => + globalVariableOptions.update(treeItem.designation.variable.cxxrtlIdentifier, { radix: 8 }))); + context.subscriptions.push(vscode.commands.registerCommand('rtlDebugger.setRadix.10', (treeItem) => + globalVariableOptions.update(treeItem.designation.variable.cxxrtlIdentifier, { radix: 10 }))); + context.subscriptions.push(vscode.commands.registerCommand('rtlDebugger.setRadix.16', (treeItem) => + globalVariableOptions.update(treeItem.designation.variable.cxxrtlIdentifier, { radix: 16 }))); + context.subscriptions.push(vscode.commands.registerCommand('rtlDebugger.watchVariable', (treeItem) => - watchList.append(treeItem.getWatchItem()))); + globalWatchList.append(treeItem.getWatchItem()))); context.subscriptions.push(vscode.commands.registerCommand('rtlDebugger.unWatchVariable', (treeItem) => - watchList.remove(treeItem.metadata.index))); + globalWatchList.remove(treeItem.metadata.index))); // For an unknown reason, the `vscode.open` command (which does the exact same thing) ignores the options. context.subscriptions.push(vscode.commands.registerCommand('rtlDebugger.openDocument', diff --git a/src/model/styling.ts b/src/model/styling.ts index 8477165..7f9e5dc 100644 --- a/src/model/styling.ts +++ b/src/model/styling.ts @@ -1,6 +1,7 @@ import * as vscode from 'vscode'; import { MemoryVariable, ScalarVariable, Variable } from './variable'; +import { globalVariableOptions } from '../debug/options'; export enum DisplayStyle { Python = 'Python', @@ -65,15 +66,24 @@ export function* memoryRowIndices(variable: MemoryVariable): Generator { } } -export function variableValue(style: DisplayStyle, variable: Variable, value: bigint | undefined, base: 2 | 8 | 10 | 16 = 10): string { +export function variableValue(style: DisplayStyle, variable: Variable, value: bigint | undefined, radix?: 2 | 8 | 10 | 16): string { if (value === undefined) { return '...'; - } else if (variable.width === 1) { + } + + // There is a bug in CXXRTL that occasionally causes out-of-bounds bits to be set. + // Ideally it should be fixed there, but for now let's work around it here, for usability. + value &= (1n << BigInt(variable.width)) - 1n; + + if (variable.width === 1) { return value.toString(); } else { + if (radix === undefined) { + radix = globalVariableOptions.get(variable.cxxrtlIdentifier).radix ?? 10; + } switch (style) { case DisplayStyle.Python: - switch (base) { + switch (radix) { case 2: return `0b${value.toString(2)}`; case 8: return `0o${value.toString(8)}`; case 10: return value.toString(10); @@ -81,10 +91,10 @@ export function variableValue(style: DisplayStyle, variable: Variable, value: bi } case DisplayStyle.Verilog: - return `${base}'${value.toString(base)}`; + return `${radix}'${value.toString(radix)}`; case DisplayStyle.VHDL: - switch (base) { + switch (radix) { case 2: return `B"${value.toString(2)}"`; case 8: return `O"${value.toString(8)}"`; case 10: return value.toString(10); diff --git a/src/ui/sidebar.ts b/src/ui/sidebar.ts index 28f9b7d..79d4820 100644 --- a/src/ui/sidebar.ts +++ b/src/ui/sidebar.ts @@ -6,7 +6,7 @@ import { DisplayStyle, variableDescription, variableBitIndices, memoryRowIndices import { CXXRTLDebugger } from '../debugger'; import { Observer } from '../debug/observer'; import { Designation, MemoryRangeDesignation, MemoryRowDesignation, ScalarDesignation } from '../model/sample'; -import { IWatchItem, watchList } from '../debug/watch'; +import { IWatchItem, globalWatchList } from '../debug/watch'; import { Session } from '../debug/session'; abstract class TreeItem { @@ -37,7 +37,7 @@ class BitTreeItem extends TreeItem { provider: TreeDataProvider, readonly designation: ScalarDesignation | MemoryRowDesignation, readonly bitIndex: number, - readonly contextValue?: string, + readonly contextValue: string = '', ) { super(provider); } @@ -81,7 +81,7 @@ class ScalarTreeItem extends TreeItem { constructor( provider: TreeDataProvider, readonly designation: ScalarDesignation | MemoryRowDesignation, - readonly contextValue?: string, + readonly contextValue: string = '', ) { super(provider); } @@ -127,7 +127,7 @@ class ArrayTreeItem extends TreeItem { constructor( provider: TreeDataProvider, readonly designation: MemoryRangeDesignation, - readonly contextValue?: string, + readonly contextValue: string = '', ) { super(provider); } @@ -197,10 +197,11 @@ class ScopeTreeItem extends TreeItem { } for (const variable of await this.scope.variables) { if (variable instanceof ScalarVariable) { - children.push(new ScalarTreeItem(this.provider, variable.designation(), 'canWatch')); + children.push(new ScalarTreeItem(this.provider, variable.designation(), + variable.width > 1 ? 'canWatch|canSetRadix' : 'canWatch')); } if (variable instanceof MemoryVariable) { - children.push(new ArrayTreeItem(this.provider, variable.designation(), 'canWatch')); + children.push(new ArrayTreeItem(this.provider, variable.designation(), 'canWatch|canSetRadix')); } } return children; @@ -215,7 +216,7 @@ class WatchTreeItem extends TreeItem { } override async getTreeItem(): Promise { - if (watchList.get().length > 0) { + if (globalWatchList.get().length > 0) { return new vscode.TreeItem('Watch', vscode.TreeItemCollapsibleState.Expanded); } else { return new vscode.TreeItem('Watch (empty)'); @@ -224,7 +225,7 @@ class WatchTreeItem extends TreeItem { override async getChildren(): Promise { const children = []; - for (const [index, watchItem] of watchList.get().entries()) { + for (const [index, watchItem] of globalWatchList.get().entries()) { const variable = await this.provider.getVariable(watchItem.id); if (variable === null) { continue; @@ -241,10 +242,11 @@ class WatchTreeItem extends TreeItem { } let treeItem; if (designation instanceof MemoryRangeDesignation) { - treeItem = new ArrayTreeItem(this.provider, designation, 'inWatchList'); + treeItem = new ArrayTreeItem(this.provider, designation, 'inWatchList|canSetRadix'); } else if (designation instanceof ScalarDesignation || designation instanceof MemoryRowDesignation) { if (watchItem.bit === undefined) { - treeItem = new ScalarTreeItem(this.provider, designation, 'inWatchList'); + treeItem = new ScalarTreeItem(this.provider, designation, + designation.variable.width > 1 ? 'inWatchList|canSetRadix' : 'inWatchList'); } else { treeItem = new BitTreeItem(this.provider, designation, watchItem.bit, 'inWatchList'); } @@ -269,7 +271,8 @@ export class TreeDataProvider implements vscode.TreeDataProvider { constructor(rtlDebugger: CXXRTLDebugger) { vscode.workspace.onDidChangeConfiguration((event) => { - if (event.affectsConfiguration('rtlDebugger.displayStyle')) { + if (event.affectsConfiguration('rtlDebugger.displayStyle') || + event.affectsConfiguration('rtlDebugger.variableOptions')) { this._onDidChangeTreeData.fire(null); } }); @@ -287,7 +290,7 @@ export class TreeDataProvider implements vscode.TreeDataProvider { } this._onDidChangeTreeData.fire(null); }); - watchList.onDidChange((_items) => { + globalWatchList.onDidChange((_items) => { if (this.watchTreeItem !== null) { this._onDidChangeTreeData.fire(this.watchTreeItem); }