@specy/risc-v 3.4.1 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +177 -17
- package/dist/index.d.ts +177 -17
- package/dist/index.js +4885 -4199
- package/dist/index.mjs +4885 -4199
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -291,7 +291,18 @@ declare enum BackStepAction {
|
|
|
291
291
|
* Members mirror the core's `BackStepper.Action` by position, because the core reports an
|
|
292
292
|
* action as that enum's ordinal. Append here; never insert.
|
|
293
293
|
*/
|
|
294
|
-
CONTROL_AND_STATUS_COUNTERS_DECREMENT = 11
|
|
294
|
+
CONTROL_AND_STATUS_COUNTERS_DECREMENT = 11,
|
|
295
|
+
/**
|
|
296
|
+
* Restores one control and status register the way the host's setter wrote it, through the
|
|
297
|
+
* register's own value: a linked register writes the register it aliases, a read only counter
|
|
298
|
+
* is written anyway. Only a Poke records this, and only inside its own entry.
|
|
299
|
+
*/
|
|
300
|
+
CONTROL_AND_STATUS_REGISTER_POKE_RESTORE = 12,
|
|
301
|
+
/**
|
|
302
|
+
* A whole Poke: every value one `beginPoke`/`endPoke` transaction wrote, restored together.
|
|
303
|
+
* A Poke is a single back step, so it takes one slot of the undo size whatever it wrote.
|
|
304
|
+
*/
|
|
305
|
+
POKE = 13
|
|
295
306
|
}
|
|
296
307
|
/**
|
|
297
308
|
* Represents a back step in the simulation undo stack.
|
|
@@ -306,14 +317,119 @@ interface JsBackStep {
|
|
|
306
317
|
*/
|
|
307
318
|
readonly param1: number;
|
|
308
319
|
/**
|
|
309
|
-
* Information about the action
|
|
320
|
+
* Information about the action. A 64 bit value is truncated to 32 bits here, as it always has
|
|
321
|
+
* been; read `oldValue` for the whole of it.
|
|
310
322
|
*/
|
|
311
323
|
readonly param2: number;
|
|
312
324
|
/**
|
|
313
|
-
* The
|
|
325
|
+
* The value this step replaced, as the simulator saw it at the write, whole and untruncated.
|
|
326
|
+
*
|
|
327
|
+
* Every value of this target is 64 bits wide, which no JS number holds, so it is a **signed
|
|
328
|
+
* decimal string**, the shape `JsPokeRegisterWrite` and `getRegistersValuesLong` already use:
|
|
329
|
+
* read it with `BigInt(step.oldValue)`, and with `BigInt.asUintN(64, BigInt(step.oldValue))`
|
|
330
|
+
* for the unsigned form.
|
|
331
|
+
*
|
|
332
|
+
* - `REGISTER_RESTORE`, `FLOATING_POINT_REGISTER_RESTORE`,
|
|
333
|
+
* `CONTROL_AND_STATUS_REGISTER_RESTORE`, `CONTROL_AND_STATUS_REGISTER_BACKDOOR`: the whole
|
|
334
|
+
* register before the write.
|
|
335
|
+
* - `MEMORY_RESTORE_RAW_WORD`, `MEMORY_RESTORE_WORD`, `MEMORY_RESTORE_DOUBLE_WORD`,
|
|
336
|
+
* `MEMORY_RESTORE_HALF`, `MEMORY_RESTORE_BYTE`: the bytes the write replaced, at the width it
|
|
337
|
+
* was made, in the low order bits.
|
|
338
|
+
* - `PC_RESTORE`: the address the restore puts back - the same value as `param1`, which is
|
|
339
|
+
* where this action has always kept it, its `param2` being unused and 0.
|
|
340
|
+
* - `'0'` for `CONTROL_AND_STATUS_COUNTERS_DECREMENT`, `DO_NOTHING` and `POKE`, which replace
|
|
341
|
+
* no single value; a Poke reports both sides of everything it wrote through its own `writes`.
|
|
342
|
+
*/
|
|
343
|
+
readonly oldValue: string;
|
|
344
|
+
/**
|
|
345
|
+
* The value the write left, beside the `oldValue` it replaced, taken at the store: a register
|
|
346
|
+
* write reports the whole register after it, a memory write the bytes it left at the width it
|
|
347
|
+
* was made, and `PC_RESTORE` the address the instruction set. Same encoding as `oldValue`.
|
|
348
|
+
*
|
|
349
|
+
* `CONTROL_AND_STATUS_REGISTER_BACKDOOR` is the simulator sampling the wall clock into `time`
|
|
350
|
+
* rather than a program writing a register, but it is a write all the same and reports the
|
|
351
|
+
* millisecond reading it stored. `'0'` for `CONTROL_AND_STATUS_COUNTERS_DECREMENT` and
|
|
352
|
+
* `DO_NOTHING`, which write no value of their own, and for `POKE`, whose `writes` carry both
|
|
353
|
+
* sides already.
|
|
354
|
+
*/
|
|
355
|
+
readonly newValue: string;
|
|
356
|
+
/**
|
|
357
|
+
* The program counter value before the action, or -1 for an action that belongs to no
|
|
358
|
+
* instruction: a Poke, or a host write made before anything ran.
|
|
314
359
|
*/
|
|
315
360
|
readonly pc: number;
|
|
361
|
+
/**
|
|
362
|
+
* Whether this step is a whole Poke rather than one effect of an instruction. It is the
|
|
363
|
+
* discriminator this list needs, since a Poke and a pre-run host write both carry `pc` -1.
|
|
364
|
+
*/
|
|
365
|
+
readonly isPoke: boolean;
|
|
316
366
|
}
|
|
367
|
+
/**
|
|
368
|
+
* One value a Poke changed: a register, named the way this package's getters spell it, or a run of
|
|
369
|
+
* consecutive memory bytes. `old` is what the simulator held when the write happened and `new` what
|
|
370
|
+
* it held when the Poke was closed, so a value written twice inside one Poke reports its final
|
|
371
|
+
* state.
|
|
372
|
+
*/
|
|
373
|
+
type JsPokeWrite = JsPokeRegisterWrite | JsPokeMemoryWrite;
|
|
374
|
+
/**
|
|
375
|
+
* A register a Poke wrote. `name` is the register's own name, as this package spells it: a key of
|
|
376
|
+
* `RISCVRegisters` (`t0`), an entry of `RISCV_FLOATING_POINT_REGISTERS` (`ft0`) or one of
|
|
377
|
+
* `RISCV_CSR_REGISTERS` (`fcsr`) - the file it belongs to is the file that name is in.
|
|
378
|
+
*
|
|
379
|
+
* Every register here is 64 bits wide, which no JS number holds, so both values are **signed
|
|
380
|
+
* decimal strings**, the shape `getRegisterValueLong` and `getRegistersValuesLong` already use:
|
|
381
|
+
* read them with `BigInt(write.old)`, and with `BigInt.asUintN(64, BigInt(write.old))` for the
|
|
382
|
+
* unsigned form that `highLowToBigint` returns for the same register.
|
|
383
|
+
*/
|
|
384
|
+
type JsPokeRegisterWrite = {
|
|
385
|
+
readonly type: 'register';
|
|
386
|
+
readonly name: string;
|
|
387
|
+
readonly old: string;
|
|
388
|
+
readonly new: string;
|
|
389
|
+
};
|
|
390
|
+
/**
|
|
391
|
+
* A run of consecutive memory bytes a Poke wrote, `address` being the first one, unsigned, and the
|
|
392
|
+
* two arrays holding one byte (0 to 255) per address. A Poke that writes addresses that are not
|
|
393
|
+
* adjacent reports one of these per run, by ascending address. Unlike `readMemoryBytes`, these are
|
|
394
|
+
* ordinary JS arrays.
|
|
395
|
+
*/
|
|
396
|
+
type JsPokeMemoryWrite = {
|
|
397
|
+
readonly type: 'memory';
|
|
398
|
+
readonly address: number;
|
|
399
|
+
readonly old: number[];
|
|
400
|
+
readonly new: number[];
|
|
401
|
+
};
|
|
402
|
+
/**
|
|
403
|
+
* One entry of the undo history: everything a single `undo()` reverts, which is either one executed
|
|
404
|
+
* instruction or one Poke. Entries, their back steps and their writes are ordinary objects with own
|
|
405
|
+
* properties, so a whole history can be cloned, serialized or deep-compared as it comes.
|
|
406
|
+
*/
|
|
407
|
+
type JsUndoGroup = JsInstructionUndoGroup | JsPokeUndoGroup;
|
|
408
|
+
/**
|
|
409
|
+
* One executed instruction, at the address `pc`, with every back step it recorded: the values it
|
|
410
|
+
* overwrote, and the `cycle`/`instret` decrement every instruction pushes on top of them.
|
|
411
|
+
*/
|
|
412
|
+
type JsInstructionUndoGroup = {
|
|
413
|
+
readonly kind: 'instruction';
|
|
414
|
+
readonly pc: number;
|
|
415
|
+
/** The instruction's back steps, newest first. */
|
|
416
|
+
readonly steps: JsBackStep[];
|
|
417
|
+
/** Always empty: only a Poke reports writes. */
|
|
418
|
+
readonly writes: readonly [];
|
|
419
|
+
};
|
|
420
|
+
/**
|
|
421
|
+
* One Poke: register or memory values written by the host between two instructions, recorded as a
|
|
422
|
+
* step of its own. It belongs to no instruction, so `pc` is -1 and undoing it restores exactly what
|
|
423
|
+
* `writes` lists, leaving the program counter, the counters, the call stack and everything else
|
|
424
|
+
* alone.
|
|
425
|
+
*/
|
|
426
|
+
type JsPokeUndoGroup = {
|
|
427
|
+
readonly kind: 'poke';
|
|
428
|
+
readonly pc: -1;
|
|
429
|
+
/** The single back step the Poke is: one slot of the history, whatever the Poke wrote. */
|
|
430
|
+
readonly steps: [JsBackStep];
|
|
431
|
+
readonly writes: JsPokeWrite[];
|
|
432
|
+
};
|
|
317
433
|
declare enum RISCVRegisters {
|
|
318
434
|
zero = 0,
|
|
319
435
|
ra = 1,
|
|
@@ -406,7 +522,8 @@ interface JsRiscV {
|
|
|
406
522
|
*/
|
|
407
523
|
setUndoSize(size: number): void;
|
|
408
524
|
/**
|
|
409
|
-
* Undoes the last instruction executed
|
|
525
|
+
* Undoes the newest entry of the history: the last instruction executed, or the last Poke made,
|
|
526
|
+
* whichever is on top. Undoing a Poke restores every value it wrote and touches nothing else.
|
|
410
527
|
*/
|
|
411
528
|
undo(): void;
|
|
412
529
|
/**
|
|
@@ -532,10 +649,10 @@ interface JsRiscV {
|
|
|
532
649
|
*/
|
|
533
650
|
getFloatingPointRegistersValues(): Int32Array;
|
|
534
651
|
/**
|
|
535
|
-
* Sets one floating point register
|
|
536
|
-
* presetting a register from the host is not something the program did.
|
|
537
|
-
*
|
|
538
|
-
* what you mean.
|
|
652
|
+
* Sets one floating point register. Outside a Poke the write is direct: no undo entry is
|
|
653
|
+
* recorded, because presetting a register from the host is not something the program did.
|
|
654
|
+
* Inside a Poke it joins the open transaction. Split the value with `bigintToHighLow`, and
|
|
655
|
+
* NaN-box a single yourself (`0xFFFFFFFFn << 32n | bits`) if that is what you mean.
|
|
539
656
|
* @param index Position in `RISCV_FLOATING_POINT_REGISTERS`. Must be a whole number from 0 to
|
|
540
657
|
* 31; anything else throws.
|
|
541
658
|
*/
|
|
@@ -549,18 +666,55 @@ interface JsRiscV {
|
|
|
549
666
|
*/
|
|
550
667
|
getControlAndStatusRegistersValues(): Int32Array;
|
|
551
668
|
/**
|
|
552
|
-
* Sets one control and status register
|
|
553
|
-
* Writing `fflags` or `frm` updates `fcsr`,
|
|
554
|
-
* here even though the program cannot write
|
|
669
|
+
* Sets one control and status register. Outside a Poke the write is direct and records no undo
|
|
670
|
+
* entry; inside a Poke it joins the open transaction. Writing `fflags` or `frm` updates `fcsr`,
|
|
671
|
+
* and writing a counter such as `cycle` is allowed here even though the program cannot write
|
|
672
|
+
* it - so a counter is pokeable, and undoing that Poke puts the counter back.
|
|
555
673
|
* @param index Position in `RISCV_CSR_REGISTERS`. Must be a whole number from 0 to 16;
|
|
556
674
|
* anything else throws.
|
|
557
675
|
*/
|
|
558
676
|
setControlAndStatusRegisterValue(index: number, high: number, low: number): void;
|
|
559
677
|
/**
|
|
560
|
-
* Gets the undo stack.
|
|
678
|
+
* Gets the undo stack, one element per back step, newest first. An instruction usually occupies
|
|
679
|
+
* several of them - it records the values it overwrote and the counter decrement - while a Poke
|
|
680
|
+
* is exactly one, the element with `isPoke` set, whatever it wrote. Use `getUndoGroups` to read
|
|
681
|
+
* the history the way `undo()` pops it, one entry per instruction or Poke.
|
|
682
|
+
*
|
|
683
|
+
* Every step that restores a value reports both sides of the write it undoes, as `oldValue` and
|
|
684
|
+
* `newValue`.
|
|
561
685
|
* @returns An array of `JsBackStep` objects representing the history of the simulation.
|
|
562
686
|
*/
|
|
563
687
|
getUndoStack(): JsBackStep[];
|
|
688
|
+
/**
|
|
689
|
+
* Gets the undo history grouped the way `undo()` pops it: one entry per executed instruction or
|
|
690
|
+
* per Poke, newest first, each carrying the back steps it is made of, every one of which
|
|
691
|
+
* reports both sides of the write it undoes as `oldValue` and `newValue`. A Poke entry also
|
|
692
|
+
* carries what it changed, with the old and the new value of each write.
|
|
693
|
+
*/
|
|
694
|
+
getUndoGroups(): JsUndoGroup[];
|
|
695
|
+
/**
|
|
696
|
+
* Opens a Poke: a register or memory value changed by the host between two instructions,
|
|
697
|
+
* recorded in this history as a step of its own.
|
|
698
|
+
*
|
|
699
|
+
* Until `endPoke` the setters - `setRegisterValue`, `setFloatingPointRegisterValue`,
|
|
700
|
+
* `setControlAndStatusRegisterValue` and `setMemoryBytes` - journal what they write into the
|
|
701
|
+
* open transaction, however many of them are called, and `endPoke` records the lot as one
|
|
702
|
+
* history entry that one `undo()` reverts and that takes one slot of the undo size, whether it
|
|
703
|
+
* wrote one byte or a hundred. Outside a transaction the same setters stay direct and record
|
|
704
|
+
* nothing, which is what presetting state needs.
|
|
705
|
+
*
|
|
706
|
+
* Throws if a Poke is already open, or if a `step`/`simulate*` call is still in flight.
|
|
707
|
+
*/
|
|
708
|
+
beginPoke(): void;
|
|
709
|
+
/**
|
|
710
|
+
* Closes the open Poke.
|
|
711
|
+
* @returns True if it recorded one history entry, false if nothing changed - or if undo is
|
|
712
|
+
* disabled or its size is 0, in which case the writes stand but cannot be undone.
|
|
713
|
+
* Throws if no Poke is open.
|
|
714
|
+
*/
|
|
715
|
+
endPoke(): boolean;
|
|
716
|
+
/** Whether a Poke is open, so that the setters journal rather than writing straight through. */
|
|
717
|
+
pokeOpen(): boolean;
|
|
564
718
|
/**
|
|
565
719
|
* Reads a sequence of bytes from memory.
|
|
566
720
|
*
|
|
@@ -574,9 +728,13 @@ interface JsRiscV {
|
|
|
574
728
|
/**
|
|
575
729
|
* Writes a sequence of bytes to memory.
|
|
576
730
|
*
|
|
577
|
-
* Unlike `readMemoryBytes`, this writes the way the program does
|
|
578
|
-
* and
|
|
579
|
-
*
|
|
731
|
+
* Unlike `readMemoryBytes`, this writes the way the program does, so write observers are
|
|
732
|
+
* notified and a memory mapped display repaints. It records no undo step of its own: a host
|
|
733
|
+
* write is not an instruction, and recording it would make the next `undo()` revert it together
|
|
734
|
+
* with the instruction that ran before it. Inside a Poke the same write joins the open
|
|
735
|
+
* transaction instead, and a byte already holding the value written is skipped entirely.
|
|
736
|
+
*
|
|
737
|
+
* Use `setPeripheralWord` for a device keeping its own register up to date.
|
|
580
738
|
* @param address The starting memory address.
|
|
581
739
|
* @param bytes An array of bytes to write to memory.
|
|
582
740
|
*/
|
|
@@ -636,7 +794,9 @@ interface JsRiscV {
|
|
|
636
794
|
*/
|
|
637
795
|
getNextStatement(): JsProgramStatement;
|
|
638
796
|
/**
|
|
639
|
-
* Sets the value of a register.
|
|
797
|
+
* Sets the value of a register. Outside a Poke the write is direct: it records no undo step.
|
|
798
|
+
* Inside a Poke it joins the open transaction, except for `zero`, which holds no value and so
|
|
799
|
+
* is left alone.
|
|
640
800
|
* @param register The name of the register.
|
|
641
801
|
* @param value The value to set the register to.
|
|
642
802
|
*/
|
|
@@ -669,4 +829,4 @@ declare function bigintToHighLow(value: bigint): [high: number, low: number];
|
|
|
669
829
|
*/
|
|
670
830
|
declare function highLowToBigint(high: number, low: number): bigint;
|
|
671
831
|
|
|
672
|
-
export { BackStepAction, ConfirmResult, type CsrRegisterName, DialogType, type FloatingPointRegisterName, type HandlerMap, type HandlerMapFns, type JsBackStep, type JsInstruction, type JsInstructionToken, type JsProgramStatement, type JsRiscV, type JsRiscVStackFrame, type MemoryAccessObserver, type MemoryObserverHandle, type MemoryWriteObserver, RISCV, type RISCVAssembleError, type RISCVAssembleResult, RISCVRegisters, type RISCVSourceLocation, type RISCVSourceSet, RISCV_CSR_REGISTERS, RISCV_FLOATING_POINT_REGISTERS, RISCV_REGISTERS, type RegisterName, type RiscvTokenizedLine, StopReason, bigintToHighLow, highLowToBigint, makeRiscVFromFiles, registerHandlers, unimplementedHandler };
|
|
832
|
+
export { BackStepAction, ConfirmResult, type CsrRegisterName, DialogType, type FloatingPointRegisterName, type HandlerMap, type HandlerMapFns, type JsBackStep, type JsInstruction, type JsInstructionToken, type JsInstructionUndoGroup, type JsPokeMemoryWrite, type JsPokeRegisterWrite, type JsPokeUndoGroup, type JsPokeWrite, type JsProgramStatement, type JsRiscV, type JsRiscVStackFrame, type JsUndoGroup, type MemoryAccessObserver, type MemoryObserverHandle, type MemoryWriteObserver, RISCV, type RISCVAssembleError, type RISCVAssembleResult, RISCVRegisters, type RISCVSourceLocation, type RISCVSourceSet, RISCV_CSR_REGISTERS, RISCV_FLOATING_POINT_REGISTERS, RISCV_REGISTERS, type RegisterName, type RiscvTokenizedLine, StopReason, bigintToHighLow, highLowToBigint, makeRiscVFromFiles, registerHandlers, unimplementedHandler };
|
package/dist/index.d.ts
CHANGED
|
@@ -291,7 +291,18 @@ declare enum BackStepAction {
|
|
|
291
291
|
* Members mirror the core's `BackStepper.Action` by position, because the core reports an
|
|
292
292
|
* action as that enum's ordinal. Append here; never insert.
|
|
293
293
|
*/
|
|
294
|
-
CONTROL_AND_STATUS_COUNTERS_DECREMENT = 11
|
|
294
|
+
CONTROL_AND_STATUS_COUNTERS_DECREMENT = 11,
|
|
295
|
+
/**
|
|
296
|
+
* Restores one control and status register the way the host's setter wrote it, through the
|
|
297
|
+
* register's own value: a linked register writes the register it aliases, a read only counter
|
|
298
|
+
* is written anyway. Only a Poke records this, and only inside its own entry.
|
|
299
|
+
*/
|
|
300
|
+
CONTROL_AND_STATUS_REGISTER_POKE_RESTORE = 12,
|
|
301
|
+
/**
|
|
302
|
+
* A whole Poke: every value one `beginPoke`/`endPoke` transaction wrote, restored together.
|
|
303
|
+
* A Poke is a single back step, so it takes one slot of the undo size whatever it wrote.
|
|
304
|
+
*/
|
|
305
|
+
POKE = 13
|
|
295
306
|
}
|
|
296
307
|
/**
|
|
297
308
|
* Represents a back step in the simulation undo stack.
|
|
@@ -306,14 +317,119 @@ interface JsBackStep {
|
|
|
306
317
|
*/
|
|
307
318
|
readonly param1: number;
|
|
308
319
|
/**
|
|
309
|
-
* Information about the action
|
|
320
|
+
* Information about the action. A 64 bit value is truncated to 32 bits here, as it always has
|
|
321
|
+
* been; read `oldValue` for the whole of it.
|
|
310
322
|
*/
|
|
311
323
|
readonly param2: number;
|
|
312
324
|
/**
|
|
313
|
-
* The
|
|
325
|
+
* The value this step replaced, as the simulator saw it at the write, whole and untruncated.
|
|
326
|
+
*
|
|
327
|
+
* Every value of this target is 64 bits wide, which no JS number holds, so it is a **signed
|
|
328
|
+
* decimal string**, the shape `JsPokeRegisterWrite` and `getRegistersValuesLong` already use:
|
|
329
|
+
* read it with `BigInt(step.oldValue)`, and with `BigInt.asUintN(64, BigInt(step.oldValue))`
|
|
330
|
+
* for the unsigned form.
|
|
331
|
+
*
|
|
332
|
+
* - `REGISTER_RESTORE`, `FLOATING_POINT_REGISTER_RESTORE`,
|
|
333
|
+
* `CONTROL_AND_STATUS_REGISTER_RESTORE`, `CONTROL_AND_STATUS_REGISTER_BACKDOOR`: the whole
|
|
334
|
+
* register before the write.
|
|
335
|
+
* - `MEMORY_RESTORE_RAW_WORD`, `MEMORY_RESTORE_WORD`, `MEMORY_RESTORE_DOUBLE_WORD`,
|
|
336
|
+
* `MEMORY_RESTORE_HALF`, `MEMORY_RESTORE_BYTE`: the bytes the write replaced, at the width it
|
|
337
|
+
* was made, in the low order bits.
|
|
338
|
+
* - `PC_RESTORE`: the address the restore puts back - the same value as `param1`, which is
|
|
339
|
+
* where this action has always kept it, its `param2` being unused and 0.
|
|
340
|
+
* - `'0'` for `CONTROL_AND_STATUS_COUNTERS_DECREMENT`, `DO_NOTHING` and `POKE`, which replace
|
|
341
|
+
* no single value; a Poke reports both sides of everything it wrote through its own `writes`.
|
|
342
|
+
*/
|
|
343
|
+
readonly oldValue: string;
|
|
344
|
+
/**
|
|
345
|
+
* The value the write left, beside the `oldValue` it replaced, taken at the store: a register
|
|
346
|
+
* write reports the whole register after it, a memory write the bytes it left at the width it
|
|
347
|
+
* was made, and `PC_RESTORE` the address the instruction set. Same encoding as `oldValue`.
|
|
348
|
+
*
|
|
349
|
+
* `CONTROL_AND_STATUS_REGISTER_BACKDOOR` is the simulator sampling the wall clock into `time`
|
|
350
|
+
* rather than a program writing a register, but it is a write all the same and reports the
|
|
351
|
+
* millisecond reading it stored. `'0'` for `CONTROL_AND_STATUS_COUNTERS_DECREMENT` and
|
|
352
|
+
* `DO_NOTHING`, which write no value of their own, and for `POKE`, whose `writes` carry both
|
|
353
|
+
* sides already.
|
|
354
|
+
*/
|
|
355
|
+
readonly newValue: string;
|
|
356
|
+
/**
|
|
357
|
+
* The program counter value before the action, or -1 for an action that belongs to no
|
|
358
|
+
* instruction: a Poke, or a host write made before anything ran.
|
|
314
359
|
*/
|
|
315
360
|
readonly pc: number;
|
|
361
|
+
/**
|
|
362
|
+
* Whether this step is a whole Poke rather than one effect of an instruction. It is the
|
|
363
|
+
* discriminator this list needs, since a Poke and a pre-run host write both carry `pc` -1.
|
|
364
|
+
*/
|
|
365
|
+
readonly isPoke: boolean;
|
|
316
366
|
}
|
|
367
|
+
/**
|
|
368
|
+
* One value a Poke changed: a register, named the way this package's getters spell it, or a run of
|
|
369
|
+
* consecutive memory bytes. `old` is what the simulator held when the write happened and `new` what
|
|
370
|
+
* it held when the Poke was closed, so a value written twice inside one Poke reports its final
|
|
371
|
+
* state.
|
|
372
|
+
*/
|
|
373
|
+
type JsPokeWrite = JsPokeRegisterWrite | JsPokeMemoryWrite;
|
|
374
|
+
/**
|
|
375
|
+
* A register a Poke wrote. `name` is the register's own name, as this package spells it: a key of
|
|
376
|
+
* `RISCVRegisters` (`t0`), an entry of `RISCV_FLOATING_POINT_REGISTERS` (`ft0`) or one of
|
|
377
|
+
* `RISCV_CSR_REGISTERS` (`fcsr`) - the file it belongs to is the file that name is in.
|
|
378
|
+
*
|
|
379
|
+
* Every register here is 64 bits wide, which no JS number holds, so both values are **signed
|
|
380
|
+
* decimal strings**, the shape `getRegisterValueLong` and `getRegistersValuesLong` already use:
|
|
381
|
+
* read them with `BigInt(write.old)`, and with `BigInt.asUintN(64, BigInt(write.old))` for the
|
|
382
|
+
* unsigned form that `highLowToBigint` returns for the same register.
|
|
383
|
+
*/
|
|
384
|
+
type JsPokeRegisterWrite = {
|
|
385
|
+
readonly type: 'register';
|
|
386
|
+
readonly name: string;
|
|
387
|
+
readonly old: string;
|
|
388
|
+
readonly new: string;
|
|
389
|
+
};
|
|
390
|
+
/**
|
|
391
|
+
* A run of consecutive memory bytes a Poke wrote, `address` being the first one, unsigned, and the
|
|
392
|
+
* two arrays holding one byte (0 to 255) per address. A Poke that writes addresses that are not
|
|
393
|
+
* adjacent reports one of these per run, by ascending address. Unlike `readMemoryBytes`, these are
|
|
394
|
+
* ordinary JS arrays.
|
|
395
|
+
*/
|
|
396
|
+
type JsPokeMemoryWrite = {
|
|
397
|
+
readonly type: 'memory';
|
|
398
|
+
readonly address: number;
|
|
399
|
+
readonly old: number[];
|
|
400
|
+
readonly new: number[];
|
|
401
|
+
};
|
|
402
|
+
/**
|
|
403
|
+
* One entry of the undo history: everything a single `undo()` reverts, which is either one executed
|
|
404
|
+
* instruction or one Poke. Entries, their back steps and their writes are ordinary objects with own
|
|
405
|
+
* properties, so a whole history can be cloned, serialized or deep-compared as it comes.
|
|
406
|
+
*/
|
|
407
|
+
type JsUndoGroup = JsInstructionUndoGroup | JsPokeUndoGroup;
|
|
408
|
+
/**
|
|
409
|
+
* One executed instruction, at the address `pc`, with every back step it recorded: the values it
|
|
410
|
+
* overwrote, and the `cycle`/`instret` decrement every instruction pushes on top of them.
|
|
411
|
+
*/
|
|
412
|
+
type JsInstructionUndoGroup = {
|
|
413
|
+
readonly kind: 'instruction';
|
|
414
|
+
readonly pc: number;
|
|
415
|
+
/** The instruction's back steps, newest first. */
|
|
416
|
+
readonly steps: JsBackStep[];
|
|
417
|
+
/** Always empty: only a Poke reports writes. */
|
|
418
|
+
readonly writes: readonly [];
|
|
419
|
+
};
|
|
420
|
+
/**
|
|
421
|
+
* One Poke: register or memory values written by the host between two instructions, recorded as a
|
|
422
|
+
* step of its own. It belongs to no instruction, so `pc` is -1 and undoing it restores exactly what
|
|
423
|
+
* `writes` lists, leaving the program counter, the counters, the call stack and everything else
|
|
424
|
+
* alone.
|
|
425
|
+
*/
|
|
426
|
+
type JsPokeUndoGroup = {
|
|
427
|
+
readonly kind: 'poke';
|
|
428
|
+
readonly pc: -1;
|
|
429
|
+
/** The single back step the Poke is: one slot of the history, whatever the Poke wrote. */
|
|
430
|
+
readonly steps: [JsBackStep];
|
|
431
|
+
readonly writes: JsPokeWrite[];
|
|
432
|
+
};
|
|
317
433
|
declare enum RISCVRegisters {
|
|
318
434
|
zero = 0,
|
|
319
435
|
ra = 1,
|
|
@@ -406,7 +522,8 @@ interface JsRiscV {
|
|
|
406
522
|
*/
|
|
407
523
|
setUndoSize(size: number): void;
|
|
408
524
|
/**
|
|
409
|
-
* Undoes the last instruction executed
|
|
525
|
+
* Undoes the newest entry of the history: the last instruction executed, or the last Poke made,
|
|
526
|
+
* whichever is on top. Undoing a Poke restores every value it wrote and touches nothing else.
|
|
410
527
|
*/
|
|
411
528
|
undo(): void;
|
|
412
529
|
/**
|
|
@@ -532,10 +649,10 @@ interface JsRiscV {
|
|
|
532
649
|
*/
|
|
533
650
|
getFloatingPointRegistersValues(): Int32Array;
|
|
534
651
|
/**
|
|
535
|
-
* Sets one floating point register
|
|
536
|
-
* presetting a register from the host is not something the program did.
|
|
537
|
-
*
|
|
538
|
-
* what you mean.
|
|
652
|
+
* Sets one floating point register. Outside a Poke the write is direct: no undo entry is
|
|
653
|
+
* recorded, because presetting a register from the host is not something the program did.
|
|
654
|
+
* Inside a Poke it joins the open transaction. Split the value with `bigintToHighLow`, and
|
|
655
|
+
* NaN-box a single yourself (`0xFFFFFFFFn << 32n | bits`) if that is what you mean.
|
|
539
656
|
* @param index Position in `RISCV_FLOATING_POINT_REGISTERS`. Must be a whole number from 0 to
|
|
540
657
|
* 31; anything else throws.
|
|
541
658
|
*/
|
|
@@ -549,18 +666,55 @@ interface JsRiscV {
|
|
|
549
666
|
*/
|
|
550
667
|
getControlAndStatusRegistersValues(): Int32Array;
|
|
551
668
|
/**
|
|
552
|
-
* Sets one control and status register
|
|
553
|
-
* Writing `fflags` or `frm` updates `fcsr`,
|
|
554
|
-
* here even though the program cannot write
|
|
669
|
+
* Sets one control and status register. Outside a Poke the write is direct and records no undo
|
|
670
|
+
* entry; inside a Poke it joins the open transaction. Writing `fflags` or `frm` updates `fcsr`,
|
|
671
|
+
* and writing a counter such as `cycle` is allowed here even though the program cannot write
|
|
672
|
+
* it - so a counter is pokeable, and undoing that Poke puts the counter back.
|
|
555
673
|
* @param index Position in `RISCV_CSR_REGISTERS`. Must be a whole number from 0 to 16;
|
|
556
674
|
* anything else throws.
|
|
557
675
|
*/
|
|
558
676
|
setControlAndStatusRegisterValue(index: number, high: number, low: number): void;
|
|
559
677
|
/**
|
|
560
|
-
* Gets the undo stack.
|
|
678
|
+
* Gets the undo stack, one element per back step, newest first. An instruction usually occupies
|
|
679
|
+
* several of them - it records the values it overwrote and the counter decrement - while a Poke
|
|
680
|
+
* is exactly one, the element with `isPoke` set, whatever it wrote. Use `getUndoGroups` to read
|
|
681
|
+
* the history the way `undo()` pops it, one entry per instruction or Poke.
|
|
682
|
+
*
|
|
683
|
+
* Every step that restores a value reports both sides of the write it undoes, as `oldValue` and
|
|
684
|
+
* `newValue`.
|
|
561
685
|
* @returns An array of `JsBackStep` objects representing the history of the simulation.
|
|
562
686
|
*/
|
|
563
687
|
getUndoStack(): JsBackStep[];
|
|
688
|
+
/**
|
|
689
|
+
* Gets the undo history grouped the way `undo()` pops it: one entry per executed instruction or
|
|
690
|
+
* per Poke, newest first, each carrying the back steps it is made of, every one of which
|
|
691
|
+
* reports both sides of the write it undoes as `oldValue` and `newValue`. A Poke entry also
|
|
692
|
+
* carries what it changed, with the old and the new value of each write.
|
|
693
|
+
*/
|
|
694
|
+
getUndoGroups(): JsUndoGroup[];
|
|
695
|
+
/**
|
|
696
|
+
* Opens a Poke: a register or memory value changed by the host between two instructions,
|
|
697
|
+
* recorded in this history as a step of its own.
|
|
698
|
+
*
|
|
699
|
+
* Until `endPoke` the setters - `setRegisterValue`, `setFloatingPointRegisterValue`,
|
|
700
|
+
* `setControlAndStatusRegisterValue` and `setMemoryBytes` - journal what they write into the
|
|
701
|
+
* open transaction, however many of them are called, and `endPoke` records the lot as one
|
|
702
|
+
* history entry that one `undo()` reverts and that takes one slot of the undo size, whether it
|
|
703
|
+
* wrote one byte or a hundred. Outside a transaction the same setters stay direct and record
|
|
704
|
+
* nothing, which is what presetting state needs.
|
|
705
|
+
*
|
|
706
|
+
* Throws if a Poke is already open, or if a `step`/`simulate*` call is still in flight.
|
|
707
|
+
*/
|
|
708
|
+
beginPoke(): void;
|
|
709
|
+
/**
|
|
710
|
+
* Closes the open Poke.
|
|
711
|
+
* @returns True if it recorded one history entry, false if nothing changed - or if undo is
|
|
712
|
+
* disabled or its size is 0, in which case the writes stand but cannot be undone.
|
|
713
|
+
* Throws if no Poke is open.
|
|
714
|
+
*/
|
|
715
|
+
endPoke(): boolean;
|
|
716
|
+
/** Whether a Poke is open, so that the setters journal rather than writing straight through. */
|
|
717
|
+
pokeOpen(): boolean;
|
|
564
718
|
/**
|
|
565
719
|
* Reads a sequence of bytes from memory.
|
|
566
720
|
*
|
|
@@ -574,9 +728,13 @@ interface JsRiscV {
|
|
|
574
728
|
/**
|
|
575
729
|
* Writes a sequence of bytes to memory.
|
|
576
730
|
*
|
|
577
|
-
* Unlike `readMemoryBytes`, this writes the way the program does
|
|
578
|
-
* and
|
|
579
|
-
*
|
|
731
|
+
* Unlike `readMemoryBytes`, this writes the way the program does, so write observers are
|
|
732
|
+
* notified and a memory mapped display repaints. It records no undo step of its own: a host
|
|
733
|
+
* write is not an instruction, and recording it would make the next `undo()` revert it together
|
|
734
|
+
* with the instruction that ran before it. Inside a Poke the same write joins the open
|
|
735
|
+
* transaction instead, and a byte already holding the value written is skipped entirely.
|
|
736
|
+
*
|
|
737
|
+
* Use `setPeripheralWord` for a device keeping its own register up to date.
|
|
580
738
|
* @param address The starting memory address.
|
|
581
739
|
* @param bytes An array of bytes to write to memory.
|
|
582
740
|
*/
|
|
@@ -636,7 +794,9 @@ interface JsRiscV {
|
|
|
636
794
|
*/
|
|
637
795
|
getNextStatement(): JsProgramStatement;
|
|
638
796
|
/**
|
|
639
|
-
* Sets the value of a register.
|
|
797
|
+
* Sets the value of a register. Outside a Poke the write is direct: it records no undo step.
|
|
798
|
+
* Inside a Poke it joins the open transaction, except for `zero`, which holds no value and so
|
|
799
|
+
* is left alone.
|
|
640
800
|
* @param register The name of the register.
|
|
641
801
|
* @param value The value to set the register to.
|
|
642
802
|
*/
|
|
@@ -669,4 +829,4 @@ declare function bigintToHighLow(value: bigint): [high: number, low: number];
|
|
|
669
829
|
*/
|
|
670
830
|
declare function highLowToBigint(high: number, low: number): bigint;
|
|
671
831
|
|
|
672
|
-
export { BackStepAction, ConfirmResult, type CsrRegisterName, DialogType, type FloatingPointRegisterName, type HandlerMap, type HandlerMapFns, type JsBackStep, type JsInstruction, type JsInstructionToken, type JsProgramStatement, type JsRiscV, type JsRiscVStackFrame, type MemoryAccessObserver, type MemoryObserverHandle, type MemoryWriteObserver, RISCV, type RISCVAssembleError, type RISCVAssembleResult, RISCVRegisters, type RISCVSourceLocation, type RISCVSourceSet, RISCV_CSR_REGISTERS, RISCV_FLOATING_POINT_REGISTERS, RISCV_REGISTERS, type RegisterName, type RiscvTokenizedLine, StopReason, bigintToHighLow, highLowToBigint, makeRiscVFromFiles, registerHandlers, unimplementedHandler };
|
|
832
|
+
export { BackStepAction, ConfirmResult, type CsrRegisterName, DialogType, type FloatingPointRegisterName, type HandlerMap, type HandlerMapFns, type JsBackStep, type JsInstruction, type JsInstructionToken, type JsInstructionUndoGroup, type JsPokeMemoryWrite, type JsPokeRegisterWrite, type JsPokeUndoGroup, type JsPokeWrite, type JsProgramStatement, type JsRiscV, type JsRiscVStackFrame, type JsUndoGroup, type MemoryAccessObserver, type MemoryObserverHandle, type MemoryWriteObserver, RISCV, type RISCVAssembleError, type RISCVAssembleResult, RISCVRegisters, type RISCVSourceLocation, type RISCVSourceSet, RISCV_CSR_REGISTERS, RISCV_FLOATING_POINT_REGISTERS, RISCV_REGISTERS, type RegisterName, type RiscvTokenizedLine, StopReason, bigintToHighLow, highLowToBigint, makeRiscVFromFiles, registerHandlers, unimplementedHandler };
|