@specy/risc-v 3.6.2 → 4.0.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.ts CHANGED
@@ -1,20 +1,113 @@
1
+ type AssemblerProfile = 'rars' | 'gnu-compiler-v1';
2
+ /**
3
+ * GNU compiler assembly members and the index naming the member that defines each global. A Build
4
+ * pulls a member only to resolve a global the program uses and does not define, as ld pulls members
5
+ * out of an archive, and keeps pulling for the globals those members use in turn. Members are always
6
+ * assembled with the `gnu-compiler-v1` profile, whatever profile the program uses, and their paths
7
+ * never meet the program's Files.
8
+ */
9
+ type RuntimeLibrary = {
10
+ /** Canonical member path to its source. */
11
+ members: Record<string, string>;
12
+ /** Global symbol to the path of the member defining it. */
13
+ index: Record<string, string>;
14
+ /**
15
+ * Globals the library supplies even to a weak reference, which otherwise pulls no member: GCC
16
+ * refers to `__cxa_pure_virtual` weakly from every abstract class's vtable.
17
+ */
18
+ resolveWeak?: string[];
19
+ };
20
+ type AssemblyOptions = {
21
+ assemblerProfile?: AssemblerProfile;
22
+ /**
23
+ * The global execution starts at instead of `main`. The link must define it, and with a library
24
+ * it pulls its own member, as ld's entry symbol does: `_start` brings in a library's startup code.
25
+ */
26
+ entrySymbol?: string;
27
+ /** Libraries searched in order: the first one whose index names a symbol supplies it. */
28
+ libraries?: RuntimeLibrary[];
29
+ };
30
+ /** The globals one GNU compiler unit defines and the ones it uses without defining. */
31
+ type GnuUnitSymbols = {
32
+ /** Globals the unit defines, strong or weak. */
33
+ defined: string[];
34
+ /** The defined globals that are weak. */
35
+ weak: string[];
36
+ /** Globals the unit uses without defining, other than weak references, which pull nothing. */
37
+ references: string[];
38
+ /** Why the unit could not be parsed; empty when it parsed. */
39
+ errors: string[];
40
+ };
1
41
  type JsInstructionToken = {
2
42
  /** One-based column in the processed source line. */
3
43
  sourceColumn: number;
4
44
  value: string;
5
45
  type: string;
6
46
  };
47
+ /**
48
+ * Why a run call (`step`, `simulate`, `simulateWithLimit`, `simulateWithBreakpoints`,
49
+ * `simulateWithBreakpointsAndLimit`) stopped. The same enum, with the same values, as
50
+ * `@specy/mips`'s.
51
+ */
7
52
  declare enum StopReason {
8
- NONE = -1,// no simulation has run yet
53
+ /** No run call has stopped since the program was initialized; only `getStopReason` reports it. */
54
+ NONE = -1,
55
+ /** A breakpoint address or an `ebreak` was reached. */
9
56
  BREAKPOINT = 0,
57
+ /** Never returned: a runtime failure rejects the run call with a `RuntimeError` instead. */
10
58
  EXCEPTION = 1,
11
- MAX_STEPS = 2,// includes step mode (where maxSteps is 1)
59
+ /** The instruction limit was reached, which is what a single `step()` ends on. */
60
+ MAX_STEPS = 2,
61
+ /** An exit service (10 or 93) ran, or the program had already exited and nothing ran. */
12
62
  NORMAL_TERMINATION = 3,
13
- CLIFF_TERMINATION = 4,// run off bottom of program
63
+ /** The program ran off the end of its code: there is no statement at the program counter. */
64
+ CLIFF_TERMINATION = 4,
65
+ /** Not reachable through this package. */
14
66
  PAUSE = 5,
67
+ /** Not reachable through this package. */
15
68
  STOP = 6
16
69
  }
70
+ /**
71
+ * What a `RuntimeError` was:
72
+ * - `exception`: a RISC-V exception the program had no trap handler for: a misaligned or faulting
73
+ * access, an illegal instruction, an instruction fetch outside the program.
74
+ * - `syscall`: an ecall refused its service number, arguments or input, such as "invalid integer
75
+ * input (syscall 5)" or "invalid or unimplemented syscall service: 99".
76
+ * - `handler`: a host handler or memory observer threw, rejected or broke its contract; its `cause`
77
+ * is what it threw or rejected with.
78
+ * - `internal`: the simulator itself failed.
79
+ */
80
+ type RuntimeErrorKind = 'exception' | 'syscall' | 'handler' | 'internal';
81
+ /**
82
+ * The error a run call rejects with when the program fails at runtime: an `Error` named
83
+ * `RuntimeError` with typed fields, so that a host never parses its text. Any other rejection,
84
+ * such as a run call on a program that did not assemble, is the plain error it is.
85
+ */
86
+ interface RuntimeError extends Error {
87
+ readonly name: 'RuntimeError';
88
+ readonly kind: RuntimeErrorKind;
89
+ /**
90
+ * The address of the instruction that failed, or of the program counter that could not be
91
+ * fetched, as a signed 32 bit int like `JsProgramStatement.address`.
92
+ */
93
+ readonly address: number;
94
+ /** The failing statement's source file, or null when there is no statement. */
95
+ readonly sourcePath: string | null;
96
+ /** The failing statement's one-based line in `sourcePath`, or null. */
97
+ readonly line: number | null;
98
+ /**
99
+ * RARS's own words, without the location: "Runtime exception at 0x00400004: invalid or
100
+ * unimplemented syscall service: 99", "Handler readInt did not return a string".
101
+ */
102
+ readonly message: string;
103
+ /** For a `handler` failure, what the handler threw or rejected with. */
104
+ readonly cause?: unknown;
105
+ }
106
+ /** Whether a run call's rejection is a typed `RuntimeError`. */
107
+ declare function isRuntimeError(error: unknown): error is RuntimeError;
108
+ /** The kind of message dialog syscall 55 asks for; any other value of a1 asks for a plain message. */
17
109
  declare enum DialogType {
110
+ PLAIN_MESSAGE = -1,
18
111
  ERROR_MESSAGE = 0,
19
112
  INFORMATION_MESSAGE = 1,
20
113
  WARNING_MESSAGE = 2,
@@ -25,97 +118,114 @@ declare enum ConfirmResult {
25
118
  NO = 1,
26
119
  CANCEL = 2
27
120
  }
121
+ /**
122
+ * The handlers a program's syscalls reach the outside world through, each as its arguments and its
123
+ * answer. The syscalls own each service's semantics, as RARS defines them: they format what they
124
+ * print and parse what they read, so a handler only moves text and bytes. Bytes cross as plain
125
+ * arrays of numbers from 0 to 255.
126
+ */
28
127
  type HandlerMap = {
128
+ /**
129
+ * Syscall 1024: open a file, with `flags` 0 to read and 1 to write, `append` set for flags 9. The
130
+ * path is the program's string decoded from UTF-8. Answer with the new file descriptor, or -1
131
+ * when the file cannot be opened.
132
+ */
29
133
  openFile: {
30
134
  in: [filename: string, flags: number, append: boolean];
31
135
  out: number;
32
136
  };
137
+ /** Syscall 57: close a file descriptor that `openFile` returned. */
33
138
  closeFile: {
34
139
  in: [fileDescriptor: number];
35
140
  out: void;
36
141
  };
142
+ /**
143
+ * Syscall 64 on a file descriptor that `openFile` returned: write the bytes. Answer with the
144
+ * number of bytes written, or -1 when the write failed; the program receives it in a0.
145
+ */
37
146
  writeFile: {
38
147
  in: [fileDescriptor: number, buffer: number[]];
39
- out: void;
148
+ out: number;
40
149
  };
150
+ /**
151
+ * Syscall 63 on a file descriptor that `openFile` returned: read at most `length` bytes. Answer
152
+ * with `[count, bytes]`, where a count of 0 is the end of the file and -1 a failed read.
153
+ */
41
154
  readFile: {
42
- in: [fileDescriptor: number, destination: number[], length: number];
43
- out: [readOrEof: number, buffer: number[]];
155
+ in: [fileDescriptor: number, length: number];
156
+ out: [count: number, buffer: number[]];
44
157
  };
158
+ /**
159
+ * Syscall 50: a Yes, No and Cancel question. Cancel reaches the program as 2. Every dialog's
160
+ * message is the program's string at a0, decoded from UTF-8.
161
+ */
45
162
  confirm: {
46
163
  in: [message: string];
47
164
  out: ConfirmResult;
48
165
  };
166
+ /**
167
+ * Syscalls 51 to 54: ask for a line of text. Answer with the text, or null when the user cancels,
168
+ * which the program receives as status -2. The syscall parses the text itself, as RARS does;
169
+ * 54 stores it as UTF-8, measuring the buffer in bytes.
170
+ */
49
171
  inputDialog: {
50
172
  in: [message: string];
51
- out: string;
173
+ out: string | null;
52
174
  };
175
+ /** Syscalls 55, 56 and 58 to 60: show a message. The program waits until the handler settles. */
53
176
  outputDialog: {
54
177
  in: [message: string, type: DialogType];
55
178
  out: void;
56
179
  };
57
- askDouble: {
58
- in: [message: string];
59
- out: number;
60
- };
61
- askFloat: {
62
- in: [message: string];
63
- out: number;
64
- };
65
- askInt: {
66
- in: [message: string];
67
- out: number;
68
- };
69
- askString: {
70
- in: [message: string];
71
- out: string;
72
- };
73
- readDouble: {
180
+ /**
181
+ * Syscall 5: the line typed. The syscall trims it and parses it as Java's `Integer.parseInt`
182
+ * does; anything else stops the program with "invalid integer input (syscall 5)".
183
+ */
184
+ readInt: {
74
185
  in: [];
75
- out: number;
186
+ out: string;
76
187
  };
188
+ /**
189
+ * Syscall 6: the line typed. The syscall trims it and parses it as Java's `Float.parseFloat`
190
+ * does; anything else stops the program with "invalid float input (syscall 6)".
191
+ */
77
192
  readFloat: {
78
193
  in: [];
79
- out: number;
194
+ out: string;
80
195
  };
81
- readInt: {
196
+ /**
197
+ * Syscall 7: the line typed. The syscall trims it and parses it as Java's `Double.parseDouble`
198
+ * does; anything else stops the program with "invalid double input (syscall 7)".
199
+ */
200
+ readDouble: {
82
201
  in: [];
83
- out: number;
202
+ out: string;
84
203
  };
204
+ /**
205
+ * Syscall 8: the line typed. The syscall stores it as UTF-8, as RARS does: at most the buffer's
206
+ * length less one characters, then at most that many bytes of them, so a character can be cut
207
+ * where the buffer ends.
208
+ */
85
209
  readString: {
86
210
  in: [];
87
211
  out: string;
88
212
  };
213
+ /**
214
+ * Syscall 12: the character typed, Enter as `"\n"`. The syscall takes the first UTF-16 unit of the
215
+ * answer, as RARS does (`é` reads as 233, an emoji as its high surrogate); an empty answer stops
216
+ * the program with "invalid char input (syscall 12)".
217
+ */
89
218
  readChar: {
90
219
  in: [];
91
220
  out: string;
92
221
  };
93
- logLine: {
94
- in: [message: string];
95
- out: void;
96
- };
97
- log: {
98
- in: [message: string];
99
- out: void;
100
- };
101
- printChar: {
102
- in: [c: string];
103
- out: void;
104
- };
105
- printDouble: {
106
- in: [d: number];
107
- out: void;
108
- };
109
- printFloat: {
110
- in: [f: number];
111
- out: void;
112
- };
113
- printInt: {
114
- in: [i: number];
115
- out: void;
116
- };
222
+ /**
223
+ * Program output: the text every print syscall (1 to 4, 11 and 34 to 36) formats, exactly as
224
+ * RARS prints it on Java 21, so a float prints `1.0` and `1.0E-5`. Print string (4) decodes the
225
+ * string from UTF-8; print char (11) prints the character numbered by the low byte of a0.
226
+ */
117
227
  printString: {
118
- in: [l: string];
228
+ in: [text: string];
119
229
  out: void;
120
230
  };
121
231
  /**
@@ -127,26 +237,56 @@ type HandlerMap = {
127
237
  out: void;
128
238
  };
129
239
  /**
130
- * Syscall 30: the program time in milliseconds, split by the syscall into a0 (low word) and
131
- * a1 (high word). Answer with `Date.now()` for a live run, or with a virtual clock for a
132
- * scripted one, so that elapsed-time output stays reproducible.
240
+ * Syscall 30, and every instruction that reads the `time` CSR (or `timeh`, its upper half on
241
+ * RV32): the program time in milliseconds. The syscall splits it into a0 (low word) and a1 (high
242
+ * word). Answer with `Date.now()` for a live run, or with a virtual clock for a scripted one, so
243
+ * that elapsed-time output stays reproducible.
133
244
  */
134
245
  time: {
135
246
  in: [];
136
247
  out: number;
137
248
  };
249
+ /**
250
+ * A read of standard input (descriptor 0): answer with the bytes left over from the current
251
+ * line or else one new line, at most `length` of them, as `[count, bytes]`. A count of 0 is end
252
+ * of input and -1 a failed read. Return a promise to wait for the user.
253
+ */
138
254
  stdIn: {
139
- in: [buffer: number[], length: number];
140
- out: void;
255
+ in: [length: number];
256
+ out: [count: number, buffer: number[]];
257
+ };
258
+ /**
259
+ * Syscall 62 (lseek): move an open file's position. `whence` is 0 from the start, 1 from the
260
+ * current position, 2 from the end. Answer with the new position, or -1 when the seek fails.
261
+ */
262
+ seekFile: {
263
+ in: [fileDescriptor: number, offset: number, whence: number];
264
+ out: number;
141
265
  };
266
+ /** Syscall 64 on descriptor 1: the bytes written to standard output. */
142
267
  stdOut: {
143
268
  in: [buffer: number[]];
144
269
  out: void;
145
270
  };
271
+ /** Syscall 64 on descriptor 2: the bytes written to standard error. */
146
272
  stdErr: {
147
273
  in: [buffer: number[]];
148
274
  out: void;
149
275
  };
276
+ /**
277
+ * Syscalls 41 to 44, on the first use of a generator the program has not seeded with service
278
+ * 40: the seed it starts from, as `new java.util.Random(seed)` takes it, a whole number from 0
279
+ * to 2^48 - 1 (every seed a Java long can hold scrambles to the state one of these does).
280
+ * `index` is the generator's number from a0. Answer with host randomness for a live run, or
281
+ * with a fixed seed for a scripted one, so that a Testcase gets the same numbers every time.
282
+ *
283
+ * Optional: without it a generator starts from host randomness, as in RARS. The generators
284
+ * implement `java.util.Random` exactly, so a seeded program prints the numbers RARS prints.
285
+ */
286
+ randomSeed: {
287
+ in: [index: number];
288
+ out: number;
289
+ };
150
290
  };
151
291
  /**
152
292
  * Notified after a write anywhere in an observed address range.
@@ -211,8 +351,14 @@ type RISCVAssembleResult = {
211
351
  hasWarnings: boolean;
212
352
  };
213
353
  declare class RISCV {
354
+ static readonly assemblerProfiles: readonly AssemblerProfile[];
214
355
  static makeRiscVFromFiles: typeof makeRiscVFromFiles;
215
356
  static initializeRISCV: typeof initializeRISCV;
357
+ /**
358
+ * The globals one `gnu-compiler-v1` unit defines and uses, without laying it out or touching
359
+ * memory, for building a library index. Uses the current width, so call `setIs64Bit` first.
360
+ */
361
+ static analyzeGnuUnit(path: string, source: string): GnuUnitSymbols;
216
362
  static getInstructionSet(): JsInstruction[];
217
363
  static setIs64Bit(is64Bit: boolean): void;
218
364
  static is64Bit(): boolean;
@@ -302,12 +448,26 @@ declare enum BackStepAction {
302
448
  * A whole Poke: every value one `beginPoke`/`endPoke` transaction wrote, restored together.
303
449
  * A Poke is a single back step, so it takes one slot of the undo size whatever it wrote.
304
450
  */
305
- POKE = 13
451
+ POKE = 13,
452
+ /**
453
+ * An exit service (10 or 93): undoing it leaves the program running on the ecall again.
454
+ * `param1` is 1 if the program had already exited (never, as nothing runs after an exit),
455
+ * `oldValue` the exit code it replaced and `newValue` the code the exit set.
456
+ */
457
+ EXIT_RESTORE = 14,
458
+ /**
459
+ * A random service (40 to 44) advanced or reseeded generator `param1`: undoing it puts the
460
+ * generator back, so that stepping the service again draws the same number. The generator's
461
+ * state is the simulator's own, so `param2`, `oldValue` and `newValue` are 0.
462
+ */
463
+ RANDOM_STREAM_RESTORE = 15
306
464
  }
307
465
  /**
308
466
  * Represents a back step in the simulation undo stack.
309
467
  */
310
468
  interface JsBackStep {
469
+ /** Opaque decimal identity, unique across Undo, initialize and reassembly in this module. */
470
+ readonly serial: string;
311
471
  /**
312
472
  * The action performed (e.g., register write, memory write).
313
473
  */
@@ -337,8 +497,10 @@ interface JsBackStep {
337
497
  * was made, in the low order bits.
338
498
  * - `PC_RESTORE`: the address the restore puts back - the same value as `param1`, which is
339
499
  * where this action has always kept it, its `param2` being unused and 0.
500
+ * - `EXIT_RESTORE`: the exit code the exit replaced.
340
501
  * - `'0'` for `CONTROL_AND_STATUS_COUNTERS_DECREMENT`, `DO_NOTHING` and `POKE`, which replace
341
502
  * no single value; a Poke reports both sides of everything it wrote through its own `writes`.
503
+ * Also for `RANDOM_STREAM_RESTORE`, whose generator state is the simulator's own.
342
504
  */
343
505
  readonly oldValue: string;
344
506
  /**
@@ -348,9 +510,9 @@ interface JsBackStep {
348
510
  *
349
511
  * `CONTROL_AND_STATUS_REGISTER_BACKDOOR` is the simulator sampling the wall clock into `time`
350
512
  * 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.
513
+ * millisecond reading it stored. `EXIT_RESTORE` reports the exit code the exit set. `'0'` for
514
+ * `CONTROL_AND_STATUS_COUNTERS_DECREMENT` and `DO_NOTHING`, which write no value of their own,
515
+ * for `POKE`, whose `writes` carry both sides already, and for `RANDOM_STREAM_RESTORE`.
354
516
  */
355
517
  readonly newValue: string;
356
518
  /**
@@ -410,6 +572,8 @@ type JsUndoGroup = JsInstructionUndoGroup | JsPokeUndoGroup;
410
572
  * overwrote, and the `cycle`/`instret` decrement every instruction pushes on top of them.
411
573
  */
412
574
  type JsInstructionUndoGroup = {
575
+ /** Opaque decimal identity, unique across Undo, initialize and reassembly in this module. */
576
+ readonly serial: string;
413
577
  readonly kind: 'instruction';
414
578
  readonly pc: number;
415
579
  /** The instruction's back steps, newest first. */
@@ -424,6 +588,8 @@ type JsInstructionUndoGroup = {
424
588
  * alone.
425
589
  */
426
590
  type JsPokeUndoGroup = {
591
+ /** Opaque decimal identity, unique across Undo, initialize and reassembly in this module. */
592
+ readonly serial: string;
427
593
  readonly kind: 'poke';
428
594
  readonly pc: -1;
429
595
  /** The single back step the Poke is: one slot of the history, whatever the Poke wrote. */
@@ -487,8 +653,13 @@ type HandlerName = keyof HandlerMap;
487
653
  * user, reading a file, awaiting a worker) without blocking the event loop. If the promise
488
654
  * rejects, the pending `step`/`simulate*` call rejects too.
489
655
  */
656
+ type HandlerFn<K extends HandlerName> = (...args: HandlerMap[K]['in']) => HandlerMap[K]['out'] | Promise<HandlerMap[K]['out']>;
657
+ /** The handlers a host may leave out: the simulator then does what RARS does on its own. */
658
+ type OptionalHandlerName = 'randomSeed';
490
659
  type HandlerMapFns = {
491
- [K in HandlerName]: (...args: HandlerMap[K]['in']) => HandlerMap[K]['out'] | Promise<HandlerMap[K]['out']>;
660
+ [K in Exclude<HandlerName, OptionalHandlerName>]: HandlerFn<K>;
661
+ } & {
662
+ [K in OptionalHandlerName]?: HandlerFn<K>;
492
663
  };
493
664
  declare function registerHandlers(riscv: JsRiscV, handlers: HandlerMapFns): void;
494
665
  declare function unimplementedHandler(name: HandlerName): () => never;
@@ -501,23 +672,39 @@ interface JsRiscV {
501
672
  */
502
673
  assemble(): RISCVAssembleResult;
503
674
  /**
504
- * Initializes the simulator.
675
+ * Initializes the simulator for a new run: the registers, the program counter, and the state
676
+ * of the run - not exited, exit code 0, no stop reason, and the random generators forgotten, so
677
+ * that each starts from a new seed on its first use. Assembling leaves the run state alone.
505
678
  * @param startAtMain If true, starts execution at the 'main' label. Otherwise, starts at the first instruction.
506
679
  */
507
680
  initialize(startAtMain: boolean): void;
508
681
  /**
509
- * Gets the current stop reason.
682
+ * Why the last run call stopped: `NONE` when none has since the program was initialized, and
683
+ * `EXCEPTION` after one rejected with a `RuntimeError`. Undo does not change it; read
684
+ * `terminated` for whether the program can run.
510
685
  */
511
686
  getStopReason(): StopReason;
687
+ /**
688
+ * The program's exit code: exit2's (93) operand once it has run, 0 otherwise - after exit (10),
689
+ * after running off the end, while the program runs. `initialize` resets it to 0, and undoing
690
+ * the exit puts back the code before it.
691
+ */
692
+ readonly exitCode: number;
512
693
  /**
513
694
  * Executes a single instruction.
514
695
  *
515
- * The promise settles on a microtask unless an IO handler returned a promise, in which case
516
- * it settles once that handler and the rest of the instruction have finished.
696
+ * Resolves to why it stopped: `MAX_STEPS` normally, `NORMAL_TERMINATION` for an exit,
697
+ * `CLIFF_TERMINATION` when the instruction was the program's last (or there was none to run),
698
+ * `BREAKPOINT` for an `ebreak`. A program that has exited runs nothing more and resolves to
699
+ * `NORMAL_TERMINATION` again. Rejects with a `RuntimeError` when the program fails. The
700
+ * promise settles on a microtask unless an IO handler returned a promise, in which case it
701
+ * settles once that handler and the rest of the instruction have finished.
517
702
  */
518
703
  step(): Promise<StopReason>;
519
704
  /**
520
- * Sets the size of the undo stack, must be called before assembling the program.
705
+ * Sets the maximum raw restore slots, before assembly. A Poke uses one slot; instructions
706
+ * use one slot per restore. Oldest instructions are evicted whole. An instruction larger
707
+ * than the capacity is discarded whole. Zero retains no history; negative sizes throw.
521
708
  * @param size
522
709
  */
523
710
  setUndoSize(size: number): void;
@@ -556,32 +743,47 @@ interface JsRiscV {
556
743
  * @returns The label at the given address, or null if no label is found.
557
744
  */
558
745
  getLabelAtAddress(address: number): string | null;
746
+ /** Address of a defined label/alias, or -1 if absent. Requires successful assembly. */
747
+ getAddressOfLabel(label: string): number;
748
+ /**
749
+ * Where the program's heap, and so the first block sbrk (9) hands out, starts. RARS's heap base,
750
+ * 0x10040000, unless the program is a `gnu-compiler-v1` Build whose static data (`.data`,
751
+ * `.rodata`, `.bss`, common symbols) reaches past it: then the heap starts at the first 4 KiB page
752
+ * after static data, where ld and a kernel put the break. A RARS-dialect program keeps the heap
753
+ * base whatever its size, as RARS does. Requires successful assembly; `initialize` empties the
754
+ * heap again.
755
+ */
756
+ getHeapStart(): number;
559
757
  /**
560
758
  * Sets whether the undo feature is enabled.
561
759
  * @param enabled True to enable the undo feature, false to disable it.
562
760
  */
563
761
  setUndoEnabled(enabled: boolean): void;
564
762
  /**
565
- * Simulates until the stop condition is met. it might be a breakpoint, exception, etc...
763
+ * Simulates until the program stops: an exit, running off the end, an `ebreak`, or a failure,
764
+ * which rejects with a `RuntimeError`.
566
765
  */
567
766
  simulate(): Promise<StopReason>;
568
767
  /**
569
768
  * Simulates the program for a limited number of instructions.
570
769
  * @param limit The maximum number of instructions to execute.
571
- * @returns A promise resolving to the reason the simulation stopped.
770
+ * @returns A promise resolving to the reason the simulation stopped (`MAX_STEPS` when the
771
+ * limit did), rejecting with a `RuntimeError` when the program fails.
572
772
  */
573
773
  simulateWithLimit(limit: number): Promise<StopReason>;
574
774
  /**
575
775
  * Simulates the program until a breakpoint is reached.
576
776
  * @param breakpoints An array of memory addresses where the simulation should pause.
577
- * @returns A promise resolving to the reason the simulation stopped.
777
+ * @returns A promise resolving to the reason the simulation stopped, rejecting with a
778
+ * `RuntimeError` when the program fails.
578
779
  */
579
780
  simulateWithBreakpoints(breakpoints: number[]): Promise<StopReason>;
580
781
  /**
581
782
  * Simulates the program with both breakpoints and a limit.
582
783
  * @param breakpoints An array of memory addresses where the simulation should pause.
583
784
  * @param limit The maximum number of instructions to execute.
584
- * @returns A promise resolving to the reason the simulation stopped.
785
+ * @returns A promise resolving to the reason the simulation stopped, rejecting with a
786
+ * `RuntimeError` when the program fails.
585
787
  */
586
788
  simulateWithBreakpointsAndLimit(breakpoints: number[], limit: number): Promise<StopReason>;
587
789
  /**
@@ -597,11 +799,12 @@ interface JsRiscV {
597
799
  */
598
800
  getRegisterValueLong(register: RegisterName): string;
599
801
  /**
600
- * Registers a handler function for a specific event or condition.
802
+ * Registers a handler function for a specific event or condition. Handlers are shared by every
803
+ * `JsRiscV` instance. An optional handler (`randomSeed`) is removed by registering `undefined`.
601
804
  * @param name The name of the event or condition.
602
805
  * @param handler The handler function to be called when the event occurs. The function signature depends on the event name.
603
806
  */
604
- registerHandler<T extends HandlerName>(name: T, handler: (...args: HandlerMap[T]['in']) => HandlerMap[T]['out'] | Promise<HandlerMap[T]['out']>): void;
807
+ registerHandler<T extends HandlerName>(name: T, handler: HandlerFn<T> | (T extends OptionalHandlerName ? undefined : never)): void;
605
808
  /**
606
809
  * Gets the current value of the stack pointer.
607
810
  * @returns The value of the stack pointer.
@@ -692,6 +895,24 @@ interface JsRiscV {
692
895
  * carries what it changed, with the old and the new value of each write.
693
896
  */
694
897
  getUndoGroups(): JsUndoGroup[];
898
+ /**
899
+ * The current dynamic instruction's serial, or null outside execution. Read it inside a host
900
+ * handler to journal an effect under the same identity its eventual Undo group carries. It
901
+ * remains stable while an async handler waits. Failures and exits have identities too.
902
+ * Serials are allocated even with Undo disabled; such runs retain no groups. Treat the decimal
903
+ * string as opaque (or compare with BigInt), never convert it to a JS number. Serials never
904
+ * rewind or alias after Undo, initialize or reassembly; initialize clears retained history.
905
+ */
906
+ getCurrentInstructionSerial(): string | null;
907
+ /**
908
+ * The newest `max` entries of `getUndoGroups`, read from the top of the history without
909
+ * grouping the rest of it: what a panel showing the latest steps of a large history wants.
910
+ */
911
+ getUndoGroupsUpTo(max: number): JsUndoGroup[];
912
+ /** `max` entries of `getUndoGroups` after the newest `skip`, which are counted but never built. */
913
+ getUndoGroupsRange(skip: number, max: number): JsUndoGroup[];
914
+ /** How many entries `undo()` can still pop, counted the way `getUndoGroups` groups them. */
915
+ getUndoDepth(): number;
695
916
  /**
696
917
  * Opens a Poke: a register or memory value changed by the host between two instructions,
697
918
  * recorded in this history as a step of its own.
@@ -790,9 +1011,10 @@ interface JsRiscV {
790
1011
  countMemoryObservers(): number;
791
1012
  /**
792
1013
  * Gets the next statement to be executed.
793
- * @returns The next `JsProgramStatement`.
1014
+ * @returns The next `JsProgramStatement`, or null once the program has ended (`terminated`):
1015
+ * after an exit the statement that follows the ecall is not one the program will run.
794
1016
  */
795
- getNextStatement(): JsProgramStatement;
1017
+ getNextStatement(): JsProgramStatement | null;
796
1018
  /**
797
1019
  * Sets the value of a register. Outside a Poke the write is direct: it records no undo step.
798
1020
  * Inside a Poke it joins the open transaction, except for `zero`, which holds no value and so
@@ -802,10 +1024,12 @@ interface JsRiscV {
802
1024
  */
803
1025
  setRegisterValue(register: RegisterName, high: number, low: number): void;
804
1026
  /**
805
- * Checks if the simulation has terminated.
806
- * @returns True if the simulation has terminated, false otherwise.
1027
+ * Whether the program has ended, read from its state rather than from the last run call, so
1028
+ * that it is right after `undo()` too: an exit service has run, or there is no statement at
1029
+ * the program counter because execution ran off the end. It is true as soon as the last
1030
+ * instruction has run. A runtime failure does not set it: the run call's rejection reports it.
807
1031
  */
808
- terminated: boolean;
1032
+ readonly terminated: boolean;
809
1033
  }
810
1034
  /**
811
1035
  * Creates a RISC-V simulator from a virtual source tree and its entry file.
@@ -814,9 +1038,10 @@ interface JsRiscV {
814
1038
  * snapshotted by this call; only the entry file and files reached through `.include` are assembled.
815
1039
  * @param files Source text keyed by canonical source path.
816
1040
  * @param entryFile Canonical path of the file from which include expansion starts.
1041
+ * @param options The assembler profile, the entry symbol and the libraries to link; see `AssemblyOptions`.
817
1042
  * @returns A new `JsRiscV` object.
818
1043
  */
819
- declare function makeRiscVFromFiles(files: RISCVSourceSet, entryFile: string): JsRiscV;
1044
+ declare function makeRiscVFromFiles(files: RISCVSourceSet, entryFile: string, options?: AssemblyOptions): JsRiscV;
820
1045
  /**
821
1046
  * Initializes the RISCV simulator.
822
1047
  */
@@ -829,4 +1054,4 @@ declare function bigintToHighLow(value: bigint): [high: number, low: number];
829
1054
  */
830
1055
  declare function highLowToBigint(high: number, low: number): bigint;
831
1056
 
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 };
1057
+ export { type AssemblerProfile, type AssemblyOptions, BackStepAction, ConfirmResult, type CsrRegisterName, DialogType, type FloatingPointRegisterName, type GnuUnitSymbols, 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, type OptionalHandlerName, RISCV, type RISCVAssembleError, type RISCVAssembleResult, RISCVRegisters, type RISCVSourceLocation, type RISCVSourceSet, RISCV_CSR_REGISTERS, RISCV_FLOATING_POINT_REGISTERS, RISCV_REGISTERS, type RegisterName, type RiscvTokenizedLine, type RuntimeError, type RuntimeErrorKind, type RuntimeLibrary, StopReason, bigintToHighLow, highLowToBigint, isRuntimeError, makeRiscVFromFiles, registerHandlers, unimplementedHandler };