aboutsummaryrefslogtreecommitdiffgithub
path: root/packages/novice-web/novice-web/components/GuiDebugger.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'packages/novice-web/novice-web/components/GuiDebugger.tsx')
-rw-r--r--packages/novice-web/novice-web/components/GuiDebugger.tsx122
1 files changed, 99 insertions, 23 deletions
diff --git a/packages/novice-web/novice-web/components/GuiDebugger.tsx b/packages/novice-web/novice-web/components/GuiDebugger.tsx
index f0e6fb3..9894281 100644
--- a/packages/novice-web/novice-web/components/GuiDebugger.tsx
+++ b/packages/novice-web/novice-web/components/GuiDebugger.tsx
@@ -1,11 +1,15 @@
import { FullMachineState, getIsa, Isa, fmtHex, Symbols, BaseSymbols } from 'novice';
import * as React from 'react';
import { VariableSizeGrid as Grid } from 'react-window';
-import { FrontendMessage, WorkerMessage } from '../worker/proto';
+import { AssemblerFrontendMessage, AssemblerWorkerMessage } from '../workers/assembler';
+import { DebuggerFrontendMessage, DebuggerWorkerMessage } from '../workers/debugger';
+import { AssembleForm } from './AssembleForm';
export interface GuiDebuggerProps {
- workerBundleUrl: string;
+ debuggerWorkerBundleUrl: string;
+ assemblerWorkerBundleUrl: string;
isaName: string;
+ initialAssemblyCode: string;
}
export interface GuiDebuggerState {
@@ -16,7 +20,8 @@ export class GuiDebugger extends React.Component<GuiDebuggerProps,
GuiDebuggerState> {
private isa: Isa;
private symbols: Symbols;
- private worker: Worker;
+ private debuggerWorker: Worker;
+ private assemblerWorker: Worker;
constructor(props: GuiDebuggerProps) {
super(props);
@@ -27,10 +32,20 @@ export class GuiDebugger extends React.Component<GuiDebuggerProps,
state: this.isa.initMachineState(),
};
- (this.worker = new Worker(this.props.workerBundleUrl)).onerror =
- this.onError.bind(this);
- this.worker.onmessage = this.onMessage.bind(this);
- this.postMessage({ kind: 'reset', isa: this.props.isaName });
+ this.onError = this.onError.bind(this);
+ this.onDebuggerMessage = this.onDebuggerMessage.bind(this);
+ this.onAssemblerMessage = this.onAssemblerMessage.bind(this);
+ this.handleAssembleRequest = this.handleAssembleRequest.bind(this);
+ this.handleStepRequest = this.handleStepRequest.bind(this);
+ this.handleUnstepRequest = this.handleUnstepRequest.bind(this);
+ this.handleContinueRequest = this.handleContinueRequest.bind(this);
+
+ this.debuggerWorker = this.loadWorkerBundle(this.props.debuggerWorkerBundleUrl,
+ this.onDebuggerMessage);
+ this.assemblerWorker = this.loadWorkerBundle(this.props.assemblerWorkerBundleUrl,
+ this.onAssemblerMessage);
+
+ this.postDebuggerMessage({ kind: 'reset', isa: this.props.isaName });
}
public componentDidUpdate(prevProps: GuiDebuggerProps) {
@@ -38,17 +53,15 @@ export class GuiDebugger extends React.Component<GuiDebuggerProps,
if (prevProps.isaName !== this.props.isaName) {
this.isa = getIsa(this.props.isaName);
this.setState({ state: this.isa.initMachineState() });
- this.postMessage({ kind: 'reset', isa: this.props.isaName });
+ this.postDebuggerMessage({ kind: 'reset', isa: this.props.isaName });
}
}
- public onError(err: ErrorEvent) {
+ private onError(err: ErrorEvent) {
console.log(err);
}
- public onMessage(event: MessageEvent) {
- const msg: WorkerMessage = event.data;
-
+ private onDebuggerMessage(msg: DebuggerWorkerMessage) {
switch (msg.kind) {
case 'updates':
const [state, _] = this.isa.stateApplyUpdates(
@@ -66,9 +79,28 @@ export class GuiDebugger extends React.Component<GuiDebuggerProps,
}
}
+ private onAssemblerMessage(msg: AssemblerWorkerMessage) {
+ switch (msg.kind) {
+ case 'assembly-finished':
+ const sections = msg.sections;
+ this.postDebuggerMessage({ kind: 'load-sections', sections });
+ break;
+
+ case 'assembly-error':
+ const errorMessage = msg.errorMessage;
+ console.error('assembly error in frontend', errorMessage);
+ break;
+
+ default:
+ const __: never = msg;
+ }
+ }
+
public render() {
- const cols = [80, 80, 80, 200];
+ const rowHeight = 20;
+ const cols = [20, 80, 80, 80, 200];
const colVal: ((addr: number) => string)[] = [
+ addr => (this.state.state.pc == addr)? '►' : '',
addr => this.fmtAddr(addr),
addr => this.fmtWord(this.isa.stateLoad(this.state.state, addr)),
addr => this.isa.stateLoad(this.state.state, addr).toString(10),
@@ -84,18 +116,62 @@ export class GuiDebugger extends React.Component<GuiDebuggerProps,
</div>
);
- return (<Grid
- columnCount={cols.length}
- columnWidth={i => cols[i]}
- rowCount={Math.pow(2, this.isa.spec.mem.space)}
- rowHeight={i => 20}
- width={cols.reduce((acc, cur) => acc + cur) + 32}
- height={600}
- >{cell}</Grid>);
+ return (
+ <div className='gui-wrapper'>
+ <div className='memory-view'>
+ <Grid columnCount={cols.length}
+ columnWidth={i => cols[i]}
+ rowCount={Math.pow(2, this.isa.spec.mem.space)}
+ rowHeight={i => rowHeight}
+ width={cols.reduce((acc, cur) => acc + cur) + 32}
+ height={600}
+ initialScrollTop={this.state.state.pc * rowHeight}>{cell}</Grid>
+ </div>
+ <AssembleForm initialAssemblyCode={this.props.initialAssemblyCode}
+ handleAssembleRequest={this.handleAssembleRequest}
+ handleStepRequest={this.handleStepRequest}
+ handleUnstepRequest={this.handleUnstepRequest}
+ handleContinueRequest={this.handleContinueRequest} />
+ </div>
+ );
+ }
+
+ private loadWorkerBundle<WorkerMessageType>(workerBundleUrl: string,
+ onMessage: (msg: WorkerMessageType) => void): Worker {
+ const worker = new Worker(workerBundleUrl);
+ worker.onerror = this.onError;
+ worker.onmessage = (e: MessageEvent) => {
+ const msg: WorkerMessageType = e.data;
+ onMessage(msg);
+ };
+ return worker;
+ }
+
+ private postDebuggerMessage(msg: DebuggerFrontendMessage): void {
+ this.debuggerWorker.postMessage(msg);
+ }
+
+ private postAssemblerMessage(msg: AssemblerFrontendMessage): void {
+ this.assemblerWorker.postMessage(msg);
+ }
+
+ private handleAssembleRequest(assemblyCode: string): void {
+ // TODO: it's a hack to assume isa name == assembler config name
+ this.postAssemblerMessage({ kind: 'assemble',
+ configName: this.props.isaName,
+ assemblyCode });
+ }
+
+ private handleStepRequest(): void {
+ this.postDebuggerMessage({ kind: 'step' });
+ }
+
+ private handleUnstepRequest(): void {
+ this.postDebuggerMessage({ kind: 'unstep' });
}
- private postMessage(msg: FrontendMessage): void {
- this.worker.postMessage(msg);
+ private handleContinueRequest(): void {
+ this.postDebuggerMessage({ kind: 'run' });
}
private fmtAddr(addr: number): string {