@joezilla/8sim 0.10.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/LICENSE +201 -0
- package/README.md +542 -0
- package/dist/8sim.browser.js +4728 -0
- package/dist/bundles/CardBundle.d.ts +83 -0
- package/dist/bundles/CardBundle.d.ts.map +1 -0
- package/dist/bundles/CardBundle.js +41 -0
- package/dist/bundles/CardBundle.js.map +1 -0
- package/dist/bundles/kernels.d.ts +48 -0
- package/dist/bundles/kernels.d.ts.map +1 -0
- package/dist/bundles/kernels.js +132 -0
- package/dist/bundles/kernels.js.map +1 -0
- package/dist/bundles/seed/index.d.ts +24 -0
- package/dist/bundles/seed/index.d.ts.map +1 -0
- package/dist/bundles/seed/index.js +266 -0
- package/dist/bundles/seed/index.js.map +1 -0
- package/dist/bus/Bus.d.ts +21 -0
- package/dist/bus/Bus.d.ts.map +1 -0
- package/dist/bus/Bus.js +62 -0
- package/dist/bus/Bus.js.map +1 -0
- package/dist/bus/BusRegion.d.ts +8 -0
- package/dist/bus/BusRegion.d.ts.map +1 -0
- package/dist/bus/BusRegion.js +8 -0
- package/dist/bus/BusRegion.js.map +1 -0
- package/dist/bus/SnoopBus.d.ts +15 -0
- package/dist/bus/SnoopBus.d.ts.map +1 -0
- package/dist/bus/SnoopBus.js +41 -0
- package/dist/bus/SnoopBus.js.map +1 -0
- package/dist/cards/BankRamCard.d.ts +35 -0
- package/dist/cards/BankRamCard.d.ts.map +1 -0
- package/dist/cards/BankRamCard.js +56 -0
- package/dist/cards/BankRamCard.js.map +1 -0
- package/dist/cards/DazzlerCard.d.ts +42 -0
- package/dist/cards/DazzlerCard.d.ts.map +1 -0
- package/dist/cards/DazzlerCard.js +83 -0
- package/dist/cards/DazzlerCard.js.map +1 -0
- package/dist/cards/DisplaySurface.d.ts +32 -0
- package/dist/cards/DisplaySurface.d.ts.map +1 -0
- package/dist/cards/DisplaySurface.js +11 -0
- package/dist/cards/DisplaySurface.js.map +1 -0
- package/dist/cards/FdcPlusClient.d.ts +35 -0
- package/dist/cards/FdcPlusClient.d.ts.map +1 -0
- package/dist/cards/FdcPlusClient.js +130 -0
- package/dist/cards/FdcPlusClient.js.map +1 -0
- package/dist/cards/ImsaiMioCard.d.ts +36 -0
- package/dist/cards/ImsaiMioCard.d.ts.map +1 -0
- package/dist/cards/ImsaiMioCard.js +48 -0
- package/dist/cards/ImsaiMioCard.js.map +1 -0
- package/dist/cards/ImsaiSioCard.d.ts +19 -0
- package/dist/cards/ImsaiSioCard.d.ts.map +1 -0
- package/dist/cards/ImsaiSioCard.js +54 -0
- package/dist/cards/ImsaiSioCard.js.map +1 -0
- package/dist/cards/KeyboardCard.d.ts +37 -0
- package/dist/cards/KeyboardCard.d.ts.map +1 -0
- package/dist/cards/KeyboardCard.js +79 -0
- package/dist/cards/KeyboardCard.js.map +1 -0
- package/dist/cards/Mc6850Acia.d.ts +68 -0
- package/dist/cards/Mc6850Acia.d.ts.map +1 -0
- package/dist/cards/Mc6850Acia.js +132 -0
- package/dist/cards/Mc6850Acia.js.map +1 -0
- package/dist/cards/Mits2SioCard.d.ts +27 -0
- package/dist/cards/Mits2SioCard.d.ts.map +1 -0
- package/dist/cards/Mits2SioCard.js +36 -0
- package/dist/cards/Mits2SioCard.js.map +1 -0
- package/dist/cards/MitsDcddCard.d.ts +52 -0
- package/dist/cards/MitsDcddCard.d.ts.map +1 -0
- package/dist/cards/MitsDcddCard.js +294 -0
- package/dist/cards/MitsDcddCard.js.map +1 -0
- package/dist/cards/ParallelCard.d.ts +35 -0
- package/dist/cards/ParallelCard.d.ts.map +1 -0
- package/dist/cards/ParallelCard.js +32 -0
- package/dist/cards/ParallelCard.js.map +1 -0
- package/dist/cards/Port8212.d.ts +31 -0
- package/dist/cards/Port8212.d.ts.map +1 -0
- package/dist/cards/Port8212.js +47 -0
- package/dist/cards/Port8212.js.map +1 -0
- package/dist/cards/RtcCard.d.ts +30 -0
- package/dist/cards/RtcCard.d.ts.map +1 -0
- package/dist/cards/RtcCard.js +61 -0
- package/dist/cards/RtcCard.js.map +1 -0
- package/dist/cards/SerialCard.d.ts +31 -0
- package/dist/cards/SerialCard.d.ts.map +1 -0
- package/dist/cards/SerialCard.js +28 -0
- package/dist/cards/SerialCard.js.map +1 -0
- package/dist/cards/Tr1602Uart.d.ts +55 -0
- package/dist/cards/Tr1602Uart.d.ts.map +1 -0
- package/dist/cards/Tr1602Uart.js +102 -0
- package/dist/cards/Tr1602Uart.js.map +1 -0
- package/dist/cards/Usart8251.d.ts +28 -0
- package/dist/cards/Usart8251.d.ts.map +1 -0
- package/dist/cards/Usart8251.js +88 -0
- package/dist/cards/Usart8251.js.map +1 -0
- package/dist/cards/VdmCard.d.ts +27 -0
- package/dist/cards/VdmCard.d.ts.map +1 -0
- package/dist/cards/VdmCard.js +40 -0
- package/dist/cards/VdmCard.js.map +1 -0
- package/dist/clock/ImmediateClock.d.ts +8 -0
- package/dist/clock/ImmediateClock.d.ts.map +1 -0
- package/dist/clock/ImmediateClock.js +13 -0
- package/dist/clock/ImmediateClock.js.map +1 -0
- package/dist/clock/SystemClock.d.ts +45 -0
- package/dist/clock/SystemClock.d.ts.map +1 -0
- package/dist/clock/SystemClock.js +71 -0
- package/dist/clock/SystemClock.js.map +1 -0
- package/dist/cpu/Cpu8080.d.ts +34 -0
- package/dist/cpu/Cpu8080.d.ts.map +1 -0
- package/dist/cpu/Cpu8080.js +126 -0
- package/dist/cpu/Cpu8080.js.map +1 -0
- package/dist/cpu/Decoder.d.ts +12 -0
- package/dist/cpu/Decoder.d.ts.map +1 -0
- package/dist/cpu/Decoder.js +23 -0
- package/dist/cpu/Decoder.js.map +1 -0
- package/dist/cpu/Flags.d.ts +18 -0
- package/dist/cpu/Flags.d.ts.map +1 -0
- package/dist/cpu/Flags.js +33 -0
- package/dist/cpu/Flags.js.map +1 -0
- package/dist/cpu/Registers.d.ts +22 -0
- package/dist/cpu/Registers.d.ts.map +1 -0
- package/dist/cpu/Registers.js +26 -0
- package/dist/cpu/Registers.js.map +1 -0
- package/dist/cpu/instructions/alu.d.ts +3 -0
- package/dist/cpu/instructions/alu.d.ts.map +1 -0
- package/dist/cpu/instructions/alu.js +221 -0
- package/dist/cpu/instructions/alu.js.map +1 -0
- package/dist/cpu/instructions/branch.d.ts +3 -0
- package/dist/cpu/instructions/branch.d.ts.map +1 -0
- package/dist/cpu/instructions/branch.js +117 -0
- package/dist/cpu/instructions/branch.js.map +1 -0
- package/dist/cpu/instructions/control.d.ts +3 -0
- package/dist/cpu/instructions/control.d.ts.map +1 -0
- package/dist/cpu/instructions/control.js +12 -0
- package/dist/cpu/instructions/control.js.map +1 -0
- package/dist/cpu/instructions/data.d.ts +3 -0
- package/dist/cpu/instructions/data.d.ts.map +1 -0
- package/dist/cpu/instructions/data.js +137 -0
- package/dist/cpu/instructions/data.js.map +1 -0
- package/dist/cpu/instructions/io.d.ts +3 -0
- package/dist/cpu/instructions/io.d.ts.map +1 -0
- package/dist/cpu/instructions/io.js +18 -0
- package/dist/cpu/instructions/io.js.map +1 -0
- package/dist/cpu/instructions/logical.d.ts +3 -0
- package/dist/cpu/instructions/logical.d.ts.map +1 -0
- package/dist/cpu/instructions/logical.js +129 -0
- package/dist/cpu/instructions/logical.js.map +1 -0
- package/dist/cpu/instructions/rotate.d.ts +3 -0
- package/dist/cpu/instructions/rotate.d.ts.map +1 -0
- package/dist/cpu/instructions/rotate.js +34 -0
- package/dist/cpu/instructions/rotate.js.map +1 -0
- package/dist/cpu/instructions/stack.d.ts +3 -0
- package/dist/cpu/instructions/stack.d.ts.map +1 -0
- package/dist/cpu/instructions/stack.js +84 -0
- package/dist/cpu/instructions/stack.js.map +1 -0
- package/dist/cpu/status8080.d.ts +33 -0
- package/dist/cpu/status8080.d.ts.map +1 -0
- package/dist/cpu/status8080.js +73 -0
- package/dist/cpu/status8080.js.map +1 -0
- package/dist/cpu/z80/CpuZ80.d.ts +53 -0
- package/dist/cpu/z80/CpuZ80.d.ts.map +1 -0
- package/dist/cpu/z80/CpuZ80.js +168 -0
- package/dist/cpu/z80/CpuZ80.js.map +1 -0
- package/dist/cpu/z80/DecoderZ80.d.ts +26 -0
- package/dist/cpu/z80/DecoderZ80.d.ts.map +1 -0
- package/dist/cpu/z80/DecoderZ80.js +107 -0
- package/dist/cpu/z80/DecoderZ80.js.map +1 -0
- package/dist/cpu/z80/FlagsZ80.d.ts +27 -0
- package/dist/cpu/z80/FlagsZ80.d.ts.map +1 -0
- package/dist/cpu/z80/FlagsZ80.js +47 -0
- package/dist/cpu/z80/FlagsZ80.js.map +1 -0
- package/dist/cpu/z80/RegistersZ80.d.ts +60 -0
- package/dist/cpu/z80/RegistersZ80.d.ts.map +1 -0
- package/dist/cpu/z80/RegistersZ80.js +90 -0
- package/dist/cpu/z80/RegistersZ80.js.map +1 -0
- package/dist/cpu/z80/flagHelpers.d.ts +25 -0
- package/dist/cpu/z80/flagHelpers.d.ts.map +1 -0
- package/dist/cpu/z80/flagHelpers.js +136 -0
- package/dist/cpu/z80/flagHelpers.js.map +1 -0
- package/dist/cpu/z80/instructions/alu16.d.ts +4 -0
- package/dist/cpu/z80/instructions/alu16.d.ts.map +1 -0
- package/dist/cpu/z80/instructions/alu16.js +27 -0
- package/dist/cpu/z80/instructions/alu16.js.map +1 -0
- package/dist/cpu/z80/instructions/alu8.d.ts +4 -0
- package/dist/cpu/z80/instructions/alu8.d.ts.map +1 -0
- package/dist/cpu/z80/instructions/alu8.js +100 -0
- package/dist/cpu/z80/instructions/alu8.js.map +1 -0
- package/dist/cpu/z80/instructions/bits.d.ts +10 -0
- package/dist/cpu/z80/instructions/bits.d.ts.map +1 -0
- package/dist/cpu/z80/instructions/bits.js +164 -0
- package/dist/cpu/z80/instructions/bits.js.map +1 -0
- package/dist/cpu/z80/instructions/block.d.ts +10 -0
- package/dist/cpu/z80/instructions/block.d.ts.map +1 -0
- package/dist/cpu/z80/instructions/block.js +141 -0
- package/dist/cpu/z80/instructions/block.js.map +1 -0
- package/dist/cpu/z80/instructions/control.d.ts +4 -0
- package/dist/cpu/z80/instructions/control.d.ts.map +1 -0
- package/dist/cpu/z80/instructions/control.js +62 -0
- package/dist/cpu/z80/instructions/control.js.map +1 -0
- package/dist/cpu/z80/instructions/ed.d.ts +4 -0
- package/dist/cpu/z80/instructions/ed.d.ts.map +1 -0
- package/dist/cpu/z80/instructions/ed.js +149 -0
- package/dist/cpu/z80/instructions/ed.js.map +1 -0
- package/dist/cpu/z80/instructions/exchange.d.ts +4 -0
- package/dist/cpu/z80/instructions/exchange.d.ts.map +1 -0
- package/dist/cpu/z80/instructions/exchange.js +37 -0
- package/dist/cpu/z80/instructions/exchange.js.map +1 -0
- package/dist/cpu/z80/instructions/io.d.ts +8 -0
- package/dist/cpu/z80/instructions/io.d.ts.map +1 -0
- package/dist/cpu/z80/instructions/io.js +22 -0
- package/dist/cpu/z80/instructions/io.js.map +1 -0
- package/dist/cpu/z80/instructions/jump.d.ts +4 -0
- package/dist/cpu/z80/instructions/jump.d.ts.map +1 -0
- package/dist/cpu/z80/instructions/jump.js +113 -0
- package/dist/cpu/z80/instructions/jump.js.map +1 -0
- package/dist/cpu/z80/instructions/load.d.ts +7 -0
- package/dist/cpu/z80/instructions/load.d.ts.map +1 -0
- package/dist/cpu/z80/instructions/load.js +103 -0
- package/dist/cpu/z80/instructions/load.js.map +1 -0
- package/dist/cpu/z80/instructions/rotate.d.ts +9 -0
- package/dist/cpu/z80/instructions/rotate.d.ts.map +1 -0
- package/dist/cpu/z80/instructions/rotate.js +48 -0
- package/dist/cpu/z80/instructions/rotate.js.map +1 -0
- package/dist/cpu/z80/instructions/stack.d.ts +4 -0
- package/dist/cpu/z80/instructions/stack.d.ts.map +1 -0
- package/dist/cpu/z80/instructions/stack.js +19 -0
- package/dist/cpu/z80/instructions/stack.js.map +1 -0
- package/dist/cpu/z80/regcodes.d.ts +22 -0
- package/dist/cpu/z80/regcodes.d.ts.map +1 -0
- package/dist/cpu/z80/regcodes.js +93 -0
- package/dist/cpu/z80/regcodes.js.map +1 -0
- package/dist/cpu/z80/types.d.ts +59 -0
- package/dist/cpu/z80/types.d.ts.map +1 -0
- package/dist/cpu/z80/types.js +2 -0
- package/dist/cpu/z80/types.js.map +1 -0
- package/dist/cpu/z80/views.d.ts +8 -0
- package/dist/cpu/z80/views.d.ts.map +1 -0
- package/dist/cpu/z80/views.js +40 -0
- package/dist/cpu/z80/views.js.map +1 -0
- package/dist/index.d.ts +67 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/IBus.d.ts +8 -0
- package/dist/interfaces/IBus.d.ts.map +1 -0
- package/dist/interfaces/IBus.js +2 -0
- package/dist/interfaces/IBus.js.map +1 -0
- package/dist/interfaces/IBusObserver.d.ts +7 -0
- package/dist/interfaces/IBusObserver.d.ts.map +1 -0
- package/dist/interfaces/IBusObserver.js +2 -0
- package/dist/interfaces/IBusObserver.js.map +1 -0
- package/dist/interfaces/IClock.d.ts +6 -0
- package/dist/interfaces/IClock.d.ts.map +1 -0
- package/dist/interfaces/IClock.js +2 -0
- package/dist/interfaces/IClock.js.map +1 -0
- package/dist/interfaces/ICpu.d.ts +46 -0
- package/dist/interfaces/ICpu.d.ts.map +1 -0
- package/dist/interfaces/ICpu.js +2 -0
- package/dist/interfaces/ICpu.js.map +1 -0
- package/dist/interfaces/IIODevice.d.ts +7 -0
- package/dist/interfaces/IIODevice.d.ts.map +1 -0
- package/dist/interfaces/IIODevice.js +2 -0
- package/dist/interfaces/IIODevice.js.map +1 -0
- package/dist/interfaces/IInterruptController.d.ts +8 -0
- package/dist/interfaces/IInterruptController.d.ts.map +1 -0
- package/dist/interfaces/IInterruptController.js +2 -0
- package/dist/interfaces/IInterruptController.js.map +1 -0
- package/dist/interfaces/IMemory.d.ts +9 -0
- package/dist/interfaces/IMemory.d.ts.map +1 -0
- package/dist/interfaces/IMemory.js +2 -0
- package/dist/interfaces/IMemory.js.map +1 -0
- package/dist/interfaces/IModule.d.ts +5 -0
- package/dist/interfaces/IModule.d.ts.map +1 -0
- package/dist/interfaces/IModule.js +2 -0
- package/dist/interfaces/IModule.js.map +1 -0
- package/dist/interfaces/IS100Card.d.ts +6 -0
- package/dist/interfaces/IS100Card.d.ts.map +1 -0
- package/dist/interfaces/IS100Card.js +2 -0
- package/dist/interfaces/IS100Card.js.map +1 -0
- package/dist/interfaces/index.d.ts +10 -0
- package/dist/interfaces/index.d.ts.map +1 -0
- package/dist/interfaces/index.js +2 -0
- package/dist/interfaces/index.js.map +1 -0
- package/dist/interrupt/InterruptController.d.ts +13 -0
- package/dist/interrupt/InterruptController.d.ts.map +1 -0
- package/dist/interrupt/InterruptController.js +36 -0
- package/dist/interrupt/InterruptController.js.map +1 -0
- package/dist/io/IoSpace.d.ts +9 -0
- package/dist/io/IoSpace.d.ts.map +1 -0
- package/dist/io/IoSpace.js +30 -0
- package/dist/io/IoSpace.js.map +1 -0
- package/dist/machine/MachineRunner.d.ts +54 -0
- package/dist/machine/MachineRunner.d.ts.map +1 -0
- package/dist/machine/MachineRunner.js +102 -0
- package/dist/machine/MachineRunner.js.map +1 -0
- package/dist/machine/MachineSpec.d.ts +80 -0
- package/dist/machine/MachineSpec.d.ts.map +1 -0
- package/dist/machine/MachineSpec.js +9 -0
- package/dist/machine/MachineSpec.js.map +1 -0
- package/dist/machine/buildMachine.d.ts +19 -0
- package/dist/machine/buildMachine.d.ts.map +1 -0
- package/dist/machine/buildMachine.js +122 -0
- package/dist/machine/buildMachine.js.map +1 -0
- package/dist/memory/MemoryMappedIOAdapter.d.ts +14 -0
- package/dist/memory/MemoryMappedIOAdapter.d.ts.map +1 -0
- package/dist/memory/MemoryMappedIOAdapter.js +23 -0
- package/dist/memory/MemoryMappedIOAdapter.js.map +1 -0
- package/dist/memory/Ram.d.ts +17 -0
- package/dist/memory/Ram.d.ts.map +1 -0
- package/dist/memory/Ram.js +36 -0
- package/dist/memory/Ram.js.map +1 -0
- package/dist/memory/Rom.d.ts +13 -0
- package/dist/memory/Rom.d.ts.map +1 -0
- package/dist/memory/Rom.js +25 -0
- package/dist/memory/Rom.js.map +1 -0
- package/dist/util/bits.d.ts +11 -0
- package/dist/util/bits.d.ts.map +1 -0
- package/dist/util/bits.js +35 -0
- package/dist/util/bits.js.map +1 -0
- package/dist/util/hostConsole.d.ts +2 -0
- package/dist/util/hostConsole.d.ts.map +1 -0
- package/dist/util/hostConsole.js +4 -0
- package/dist/util/hostConsole.js.map +1 -0
- package/package.json +39 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
export class FdcPlusClient {
|
|
2
|
+
ws;
|
|
3
|
+
rxBuf = [];
|
|
4
|
+
rxTotal = 0;
|
|
5
|
+
pending = [];
|
|
6
|
+
// Wire mutex. The protocol is strictly request/response, and WRIT is a
|
|
7
|
+
// multi-frame exchange (header → ack → raw data → status): any frame another
|
|
8
|
+
// op sends mid-exchange is consumed by the server as track data, and the
|
|
9
|
+
// tail of the real payload spills out as garbage commands, permanently
|
|
10
|
+
// desyncing the stream. Null when the wire is idle.
|
|
11
|
+
chainTail = null;
|
|
12
|
+
constructor(ws) {
|
|
13
|
+
this.ws = ws;
|
|
14
|
+
ws.onmessage = (ev) => {
|
|
15
|
+
const chunk = ev.data instanceof ArrayBuffer
|
|
16
|
+
? new Uint8Array(ev.data)
|
|
17
|
+
: ev.data;
|
|
18
|
+
this.rxBuf.push(chunk);
|
|
19
|
+
this.rxTotal += chunk.length;
|
|
20
|
+
this.drain();
|
|
21
|
+
};
|
|
22
|
+
ws.onerror = () => this.rejectAll(new Error('WebSocket error'));
|
|
23
|
+
ws.onclose = () => this.rejectAll(new Error('WebSocket closed'));
|
|
24
|
+
}
|
|
25
|
+
stat(drive, headLoad, track) {
|
|
26
|
+
return this.exchange(() => {
|
|
27
|
+
const p1 = ((headLoad ? 1 : 0) << 8) | (drive & 0xff);
|
|
28
|
+
this.ws.send(this.makeCmd('STAT', p1, track & 0xffff));
|
|
29
|
+
return this.enqueue(8).then(buf => this.parseCmd(buf).p2);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
readTrack(drive, track, length) {
|
|
33
|
+
return this.exchange(() => {
|
|
34
|
+
const p1 = ((drive & 0xf) << 12) | (track & 0xfff);
|
|
35
|
+
this.ws.send(this.makeCmd('READ', p1, length));
|
|
36
|
+
return this.enqueue(length);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
writeTrack(drive, track, data) {
|
|
40
|
+
return this.exchange(() => {
|
|
41
|
+
const p1 = ((drive & 0xf) << 12) | (track & 0xfff);
|
|
42
|
+
this.ws.send(this.makeCmd('WRIT', p1, data.length));
|
|
43
|
+
return this.enqueue(8).then(ackBuf => {
|
|
44
|
+
const ack = this.parseCmd(ackBuf);
|
|
45
|
+
if (ack.p1 !== 0)
|
|
46
|
+
throw new Error(`WRIT rejected: status ${ack.p1}`);
|
|
47
|
+
this.ws.send(data);
|
|
48
|
+
return this.enqueue(8).then(wstaBuf => {
|
|
49
|
+
const wsta = this.parseCmd(wstaBuf);
|
|
50
|
+
if (wsta.p1 !== 0)
|
|
51
|
+
throw new Error(`WSTA error: status ${wsta.p1}`);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Run one full request/response exchange with exclusive use of the wire.
|
|
58
|
+
* Starts synchronously when the wire is idle (device registers depend on the
|
|
59
|
+
* command going out on the same tick); queues behind the in-flight exchange
|
|
60
|
+
* otherwise. A failed exchange never blocks the queue.
|
|
61
|
+
*/
|
|
62
|
+
exchange(op) {
|
|
63
|
+
const run = this.chainTail ? this.chainTail.then(op, op) : op();
|
|
64
|
+
const tail = run.then(() => undefined, () => undefined);
|
|
65
|
+
this.chainTail = tail;
|
|
66
|
+
void tail.then(() => { if (this.chainTail === tail)
|
|
67
|
+
this.chainTail = null; });
|
|
68
|
+
return run;
|
|
69
|
+
}
|
|
70
|
+
makeCmd(mnemonic, p1, p2) {
|
|
71
|
+
const buf = new Uint8Array(8);
|
|
72
|
+
for (let i = 0; i < 4; i++)
|
|
73
|
+
buf[i] = mnemonic.charCodeAt(i) & 0xff;
|
|
74
|
+
buf[4] = p1 & 0xff;
|
|
75
|
+
buf[5] = (p1 >> 8) & 0xff;
|
|
76
|
+
buf[6] = p2 & 0xff;
|
|
77
|
+
buf[7] = (p2 >> 8) & 0xff;
|
|
78
|
+
return buf;
|
|
79
|
+
}
|
|
80
|
+
parseCmd(buf) {
|
|
81
|
+
const cmd = String.fromCharCode(buf[0] ?? 0, buf[1] ?? 0, buf[2] ?? 0, buf[3] ?? 0);
|
|
82
|
+
const p1 = (buf[4] ?? 0) | ((buf[5] ?? 0) << 8);
|
|
83
|
+
const p2 = (buf[6] ?? 0) | ((buf[7] ?? 0) << 8);
|
|
84
|
+
return { cmd, p1, p2 };
|
|
85
|
+
}
|
|
86
|
+
enqueue(bytesExpected) {
|
|
87
|
+
return new Promise((resolve, reject) => {
|
|
88
|
+
this.pending.push({ resolve, reject, bytesExpected });
|
|
89
|
+
this.drain();
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
drain() {
|
|
93
|
+
while (this.pending.length > 0) {
|
|
94
|
+
const head = this.pending[0];
|
|
95
|
+
if (!head || this.rxTotal < head.bytesExpected)
|
|
96
|
+
break;
|
|
97
|
+
this.pending.shift();
|
|
98
|
+
head.resolve(this.collect(head.bytesExpected));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
collect(n) {
|
|
102
|
+
const out = new Uint8Array(n);
|
|
103
|
+
let written = 0;
|
|
104
|
+
while (written < n) {
|
|
105
|
+
const chunk = this.rxBuf[0];
|
|
106
|
+
if (!chunk)
|
|
107
|
+
break;
|
|
108
|
+
const needed = n - written;
|
|
109
|
+
if (chunk.length <= needed) {
|
|
110
|
+
out.set(chunk, written);
|
|
111
|
+
written += chunk.length;
|
|
112
|
+
this.rxBuf.shift();
|
|
113
|
+
this.rxTotal -= chunk.length;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
out.set(chunk.subarray(0, needed), written);
|
|
117
|
+
this.rxBuf[0] = chunk.subarray(needed);
|
|
118
|
+
this.rxTotal -= needed;
|
|
119
|
+
written = n;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return out;
|
|
123
|
+
}
|
|
124
|
+
rejectAll(err) {
|
|
125
|
+
const entries = this.pending.splice(0);
|
|
126
|
+
for (const e of entries)
|
|
127
|
+
e.reject(err);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=FdcPlusClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FdcPlusClient.js","sourceRoot":"","sources":["../../src/cards/FdcPlusClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { IS100Card } from '../interfaces/IS100Card.js';
|
|
2
|
+
import type { Bus } from '../bus/Bus.js';
|
|
3
|
+
import { Tr1602Uart } from './Tr1602Uart.js';
|
|
4
|
+
import { Port8212 } from './Port8212.js';
|
|
5
|
+
export interface MioCardOptions {
|
|
6
|
+
readonly basePort?: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* IMSAI MIO (Multiple Input/Output) S-100 card (1977). A multifunction I/O
|
|
10
|
+
* board combining a TR1602 UART serial port, two 8212 parallel ports, and a
|
|
11
|
+
* board control register, on four consecutive I/O addresses:
|
|
12
|
+
*
|
|
13
|
+
* base+0 Port A — 8212 parallel I/O
|
|
14
|
+
* base+1 Port B — 8212 parallel I/O
|
|
15
|
+
* base+2 serial data (read: RX / write: TX)
|
|
16
|
+
* base+3 serial status (read) / board control (write)
|
|
17
|
+
*
|
|
18
|
+
* The base address is jumper-selectable on real hardware. The default of 0x10
|
|
19
|
+
* places the serial port at 0x12/0x13 (the standard MIO layout). Use
|
|
20
|
+
* `basePort: 0x00` to relocate the serial port to 0x02/0x03 for SIO-2-
|
|
21
|
+
* compatible console duty.
|
|
22
|
+
*
|
|
23
|
+
* Unlike {@link ImsaiSioCard} (Intel 8251), the MIO's TR1602 UART needs no
|
|
24
|
+
* initialization and is always transmit-ready.
|
|
25
|
+
*/
|
|
26
|
+
export declare class ImsaiMioCard implements IS100Card {
|
|
27
|
+
readonly id: string;
|
|
28
|
+
readonly portA: Port8212;
|
|
29
|
+
readonly portB: Port8212;
|
|
30
|
+
readonly uart: Tr1602Uart;
|
|
31
|
+
constructor(id?: string, options?: MioCardOptions);
|
|
32
|
+
attach(bus: Bus): void;
|
|
33
|
+
wireToConsole(): void;
|
|
34
|
+
reset(): void;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=ImsaiMioCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImsaiMioCard.d.ts","sourceRoot":"","sources":["../../src/cards/ImsaiMioCard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGzC,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,YAAa,YAAW,SAAS;IAC5C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;gBAEd,EAAE,SAAQ,EAAE,OAAO,GAAE,cAAmB;IAQpD,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI;IAMtB,aAAa,IAAI,IAAI;IAIrB,KAAK,IAAI,IAAI;CAKd"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Tr1602Uart } from './Tr1602Uart.js';
|
|
2
|
+
import { Port8212 } from './Port8212.js';
|
|
3
|
+
import { writeHostStdout } from '../util/hostConsole.js';
|
|
4
|
+
/**
|
|
5
|
+
* IMSAI MIO (Multiple Input/Output) S-100 card (1977). A multifunction I/O
|
|
6
|
+
* board combining a TR1602 UART serial port, two 8212 parallel ports, and a
|
|
7
|
+
* board control register, on four consecutive I/O addresses:
|
|
8
|
+
*
|
|
9
|
+
* base+0 Port A — 8212 parallel I/O
|
|
10
|
+
* base+1 Port B — 8212 parallel I/O
|
|
11
|
+
* base+2 serial data (read: RX / write: TX)
|
|
12
|
+
* base+3 serial status (read) / board control (write)
|
|
13
|
+
*
|
|
14
|
+
* The base address is jumper-selectable on real hardware. The default of 0x10
|
|
15
|
+
* places the serial port at 0x12/0x13 (the standard MIO layout). Use
|
|
16
|
+
* `basePort: 0x00` to relocate the serial port to 0x02/0x03 for SIO-2-
|
|
17
|
+
* compatible console duty.
|
|
18
|
+
*
|
|
19
|
+
* Unlike {@link ImsaiSioCard} (Intel 8251), the MIO's TR1602 UART needs no
|
|
20
|
+
* initialization and is always transmit-ready.
|
|
21
|
+
*/
|
|
22
|
+
export class ImsaiMioCard {
|
|
23
|
+
id;
|
|
24
|
+
portA;
|
|
25
|
+
portB;
|
|
26
|
+
uart;
|
|
27
|
+
constructor(id = 'mio', options = {}) {
|
|
28
|
+
const base = options.basePort ?? 0x10;
|
|
29
|
+
this.id = id;
|
|
30
|
+
this.portA = new Port8212(`${id}:portA`, base + 0);
|
|
31
|
+
this.portB = new Port8212(`${id}:portB`, base + 1);
|
|
32
|
+
this.uart = new Tr1602Uart(`${id}:uart`, base + 2, base + 3);
|
|
33
|
+
}
|
|
34
|
+
attach(bus) {
|
|
35
|
+
bus.attachIODevice(this.portA);
|
|
36
|
+
bus.attachIODevice(this.portB);
|
|
37
|
+
bus.attachIODevice(this.uart);
|
|
38
|
+
}
|
|
39
|
+
wireToConsole() {
|
|
40
|
+
this.uart.onTransmit((byte) => writeHostStdout(String.fromCharCode(byte & 0x7f)));
|
|
41
|
+
}
|
|
42
|
+
reset() {
|
|
43
|
+
this.portA.reset();
|
|
44
|
+
this.portB.reset();
|
|
45
|
+
this.uart.reset();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=ImsaiMioCard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImsaiMioCard.js","sourceRoot":"","sources":["../../src/cards/ImsaiMioCard.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAMzD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,YAAY;IACd,EAAE,CAAS;IACX,KAAK,CAAW;IAChB,KAAK,CAAW;IAChB,IAAI,CAAa;IAE1B,YAAY,EAAE,GAAG,KAAK,EAAE,UAA0B,EAAE;QAClD,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC;QACtC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,KAAK,GAAG,IAAI,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC;QACnD,IAAI,CAAC,KAAK,GAAG,IAAI,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC;QACnD,IAAI,CAAC,IAAI,GAAG,IAAI,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,CAAC,GAAQ;QACb,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/B,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/B,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAED,aAAa;QACX,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACpF,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;CACF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { IS100Card } from '../interfaces/IS100Card.js';
|
|
2
|
+
import type { Bus } from '../bus/Bus.js';
|
|
3
|
+
import { Usart8251 } from './Usart8251.js';
|
|
4
|
+
export interface SioCardOptions {
|
|
5
|
+
readonly basePortA?: number;
|
|
6
|
+
readonly basePortB?: number;
|
|
7
|
+
readonly boardCtrlPort?: number;
|
|
8
|
+
}
|
|
9
|
+
export declare class ImsaiSioCard implements IS100Card {
|
|
10
|
+
readonly id: string;
|
|
11
|
+
readonly channelA: Usart8251;
|
|
12
|
+
readonly channelB: Usart8251;
|
|
13
|
+
private readonly boardCtrl;
|
|
14
|
+
constructor(id?: string, options?: SioCardOptions);
|
|
15
|
+
attach(bus: Bus): void;
|
|
16
|
+
wireToConsole(): void;
|
|
17
|
+
reset(): void;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=ImsaiSioCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImsaiSioCard.d.ts","sourceRoot":"","sources":["../../src/cards/ImsaiSioCard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAE5D,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAG3C,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAuBD,qBAAa,YAAa,YAAW,SAAS;IAC5C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;gBAE7B,EAAE,SAAS,EAAE,OAAO,GAAE,cAAmB;IAUrD,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI;IAMtB,aAAa,IAAI,IAAI;IAMrB,KAAK,IAAI,IAAI;CAId"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Usart8251 } from './Usart8251.js';
|
|
2
|
+
import { writeHostStdout } from '../util/hostConsole.js';
|
|
3
|
+
class SioBoardCtrl {
|
|
4
|
+
a;
|
|
5
|
+
b;
|
|
6
|
+
id;
|
|
7
|
+
basePorts;
|
|
8
|
+
constructor(id, port, a, b) {
|
|
9
|
+
this.a = a;
|
|
10
|
+
this.b = b;
|
|
11
|
+
this.id = id;
|
|
12
|
+
this.basePorts = [port];
|
|
13
|
+
}
|
|
14
|
+
ioRead(_port) {
|
|
15
|
+
return 0xff;
|
|
16
|
+
}
|
|
17
|
+
ioWrite(_port, value) {
|
|
18
|
+
if ((value & 0x03) !== 0)
|
|
19
|
+
this.a.reset();
|
|
20
|
+
if ((value & 0x0c) !== 0)
|
|
21
|
+
this.b.reset();
|
|
22
|
+
}
|
|
23
|
+
reset() { }
|
|
24
|
+
}
|
|
25
|
+
export class ImsaiSioCard {
|
|
26
|
+
id;
|
|
27
|
+
channelA;
|
|
28
|
+
channelB;
|
|
29
|
+
boardCtrl;
|
|
30
|
+
constructor(id = 'sio2', options = {}) {
|
|
31
|
+
const portA = options.basePortA ?? 0x02;
|
|
32
|
+
const portB = options.basePortB ?? 0x04;
|
|
33
|
+
const ctrlPort = options.boardCtrlPort ?? 0x08;
|
|
34
|
+
this.id = id;
|
|
35
|
+
this.channelA = new Usart8251(`${id}:a`, portA, portA + 1);
|
|
36
|
+
this.channelB = new Usart8251(`${id}:b`, portB, portB + 1);
|
|
37
|
+
this.boardCtrl = new SioBoardCtrl(`${id}:ctrl`, ctrlPort, this.channelA, this.channelB);
|
|
38
|
+
}
|
|
39
|
+
attach(bus) {
|
|
40
|
+
bus.attachIODevice(this.channelA);
|
|
41
|
+
bus.attachIODevice(this.channelB);
|
|
42
|
+
bus.attachIODevice(this.boardCtrl);
|
|
43
|
+
}
|
|
44
|
+
wireToConsole() {
|
|
45
|
+
const write = (byte) => writeHostStdout(String.fromCharCode(byte));
|
|
46
|
+
this.channelA.onTransmit(write);
|
|
47
|
+
this.channelB.onTransmit(write);
|
|
48
|
+
}
|
|
49
|
+
reset() {
|
|
50
|
+
this.channelA.reset();
|
|
51
|
+
this.channelB.reset();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=ImsaiSioCard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImsaiSioCard.js","sourceRoot":"","sources":["../../src/cards/ImsaiSioCard.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAQzD,MAAM,YAAY;IAIuC;IAA+B;IAH7E,EAAE,CAAS;IACX,SAAS,CAAwB;IAE1C,YAAY,EAAU,EAAE,IAAY,EAAmB,CAAY,EAAmB,CAAY;QAA3C,MAAC,GAAD,CAAC,CAAW;QAAmB,MAAC,GAAD,CAAC,CAAW;QAChG,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,SAAS,GAAG,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,MAAM,CAAC,KAAa;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,CAAC,KAAa,EAAE,KAAa;QAClC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;YAAE,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;QACzC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;YAAE,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;IAC3C,CAAC;IAED,KAAK,KAAU,CAAC;CACjB;AAED,MAAM,OAAO,YAAY;IACd,EAAE,CAAS;IACX,QAAQ,CAAY;IACpB,QAAQ,CAAY;IACZ,SAAS,CAAe;IAEzC,YAAY,EAAE,GAAG,MAAM,EAAE,UAA0B,EAAE;QACnD,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC;QACxC,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC;QACxC,MAAM,QAAQ,GAAG,OAAO,CAAC,aAAa,IAAI,IAAI,CAAC;QAC/C,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,QAAQ,GAAG,IAAI,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QAC3D,IAAI,CAAC,QAAQ,GAAG,IAAI,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QAC3D,IAAI,CAAC,SAAS,GAAG,IAAI,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC1F,CAAC;IAED,MAAM,CAAC,GAAQ;QACb,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAClC,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAClC,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACrC,CAAC;IAED,aAAa;QACX,MAAM,KAAK,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;QAC3E,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAChC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IAED,KAAK;QACH,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;CACF"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { IS100Card } from '../interfaces/IS100Card.js';
|
|
2
|
+
import type { Bus } from '../bus/Bus.js';
|
|
3
|
+
/**
|
|
4
|
+
* The host-side surface a keyboard peripheral binds to (Story 5.9). The host
|
|
5
|
+
* (fdcplus-web) drives key presses in from a real keyboard; the guest reads
|
|
6
|
+
* them from the card's data port. This is the input counterpart to
|
|
7
|
+
* {@link SerialCard.channel} / {@link ParallelCard.gpio} / {@link VdmCard.display}.
|
|
8
|
+
*/
|
|
9
|
+
export interface KeyboardPort {
|
|
10
|
+
/** Queue a single key (ASCII/byte) for the guest to read from the data port. */
|
|
11
|
+
press(byte: number): void;
|
|
12
|
+
/** Queue each character of a string — convenience for a host paste. */
|
|
13
|
+
type(text: string): void;
|
|
14
|
+
/** How many keys are waiting to be read. */
|
|
15
|
+
readonly pending: number;
|
|
16
|
+
}
|
|
17
|
+
export interface KeyboardCardOptions {
|
|
18
|
+
readonly dataPort?: number;
|
|
19
|
+
readonly statusPort?: number;
|
|
20
|
+
/** Bits asserted on the status port while a key is waiting (default 0x01). */
|
|
21
|
+
readonly readyMask?: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* A keyboard input card — the general ASCII-keyboard board that authored
|
|
25
|
+
* keyboard cards resolve to (Story 5.9). It exposes a `keyboard` surface so the
|
|
26
|
+
* host wires it to the operator's real keyboard, mirroring how SerialCard
|
|
27
|
+
* exposes `channel` and VdmCard exposes `display`.
|
|
28
|
+
*/
|
|
29
|
+
export declare class KeyboardCard implements IS100Card {
|
|
30
|
+
readonly id: string;
|
|
31
|
+
readonly keyboard: KeyboardPort;
|
|
32
|
+
private readonly dev;
|
|
33
|
+
constructor(id?: string, opts?: KeyboardCardOptions);
|
|
34
|
+
attach(bus: Bus): void;
|
|
35
|
+
reset(): void;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=KeyboardCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KeyboardCard.d.ts","sourceRoot":"","sources":["../../src/cards/KeyboardCard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAE5D,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAGzC;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,gFAAgF;IAChF,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,uEAAuE;IACvE,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,4CAA4C;IAC5C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,8EAA8E;IAC9E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAoDD;;;;;GAKG;AACH,qBAAa,YAAa,YAAW,SAAS;IAC5C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAiB;gBAEzB,EAAE,SAAa,EAAE,IAAI,GAAE,mBAAwB;IAoB3D,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI;IAItB,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { u8 } from '../util/bits.js';
|
|
2
|
+
/**
|
|
3
|
+
* Input-only keyboard port device — a FIFO of key bytes behind a data + status
|
|
4
|
+
* port, the classic parallel-ASCII keyboard interface of a VDM-1 / Dazzler
|
|
5
|
+
* video terminal (no serial line). The guest polls the status port for the
|
|
6
|
+
* ready bit(s), then reads the data port to take the next key (which
|
|
7
|
+
* acknowledges it). Writes are ignored — a keyboard is read-only on the bus.
|
|
8
|
+
*/
|
|
9
|
+
class KeyboardDevice {
|
|
10
|
+
id;
|
|
11
|
+
basePorts;
|
|
12
|
+
dataPort;
|
|
13
|
+
statusPort;
|
|
14
|
+
readyMask;
|
|
15
|
+
queue = [];
|
|
16
|
+
constructor(id, dataPort, statusPort, readyMask) {
|
|
17
|
+
this.id = id;
|
|
18
|
+
this.dataPort = u8(dataPort);
|
|
19
|
+
this.statusPort = u8(statusPort);
|
|
20
|
+
this.readyMask = u8(readyMask);
|
|
21
|
+
// A single-port keyboard (data === status) collapses to one claim; the data
|
|
22
|
+
// read wins the dispatch below so the guest can still take keys.
|
|
23
|
+
this.basePorts =
|
|
24
|
+
this.dataPort === this.statusPort ? [this.dataPort] : [this.dataPort, this.statusPort];
|
|
25
|
+
}
|
|
26
|
+
ioRead(port) {
|
|
27
|
+
const p = u8(port);
|
|
28
|
+
if (p === this.dataPort)
|
|
29
|
+
return this.queue.shift() ?? 0; // take next key, acknowledge
|
|
30
|
+
if (p === this.statusPort)
|
|
31
|
+
return this.queue.length > 0 ? this.readyMask : 0;
|
|
32
|
+
return 0;
|
|
33
|
+
}
|
|
34
|
+
ioWrite() {
|
|
35
|
+
// input-only: a keyboard doesn't respond to CPU writes
|
|
36
|
+
}
|
|
37
|
+
reset() {
|
|
38
|
+
this.queue.length = 0;
|
|
39
|
+
}
|
|
40
|
+
press(byte) {
|
|
41
|
+
this.queue.push(u8(byte));
|
|
42
|
+
}
|
|
43
|
+
get pending() {
|
|
44
|
+
return this.queue.length;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* A keyboard input card — the general ASCII-keyboard board that authored
|
|
49
|
+
* keyboard cards resolve to (Story 5.9). It exposes a `keyboard` surface so the
|
|
50
|
+
* host wires it to the operator's real keyboard, mirroring how SerialCard
|
|
51
|
+
* exposes `channel` and VdmCard exposes `display`.
|
|
52
|
+
*/
|
|
53
|
+
export class KeyboardCard {
|
|
54
|
+
id;
|
|
55
|
+
keyboard;
|
|
56
|
+
dev;
|
|
57
|
+
constructor(id = 'keyboard', opts = {}) {
|
|
58
|
+
this.id = id;
|
|
59
|
+
this.dev = new KeyboardDevice(`${id}:kbd`, opts.dataPort ?? 0x01, opts.statusPort ?? 0x00, opts.readyMask ?? 0x01);
|
|
60
|
+
const dev = this.dev;
|
|
61
|
+
this.keyboard = {
|
|
62
|
+
press: (byte) => dev.press(byte),
|
|
63
|
+
type: (text) => {
|
|
64
|
+
for (let i = 0; i < text.length; i++)
|
|
65
|
+
dev.press(text.charCodeAt(i));
|
|
66
|
+
},
|
|
67
|
+
get pending() {
|
|
68
|
+
return dev.pending;
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
attach(bus) {
|
|
73
|
+
bus.attachIODevice(this.dev);
|
|
74
|
+
}
|
|
75
|
+
reset() {
|
|
76
|
+
this.dev.reset();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=KeyboardCard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KeyboardCard.js","sourceRoot":"","sources":["../../src/cards/KeyboardCard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { IIODevice } from '../interfaces/IIODevice.js';
|
|
2
|
+
type TransmitCallback = (byte: number) => void;
|
|
3
|
+
/**
|
|
4
|
+
* Motorola MC6850 ACIA, as used (×2) on the MITS Altair 88-2SIO board.
|
|
5
|
+
*
|
|
6
|
+
* Occupies two consecutive I/O ports — note the order is the OPPOSITE of the
|
|
7
|
+
* Intel 8251 / TR1602 (which put data at the lower address):
|
|
8
|
+
* statusPort (base+0) — read: status register; write: control register
|
|
9
|
+
* dataPort (base+1) — read: received byte; write: transmit byte
|
|
10
|
+
*
|
|
11
|
+
* Status register:
|
|
12
|
+
* bit0 RDRF — receive data register full (1 = byte available)
|
|
13
|
+
* bit1 TDRE — transmit data register empty (1 = ready to accept a byte)
|
|
14
|
+
* bit2 DCD — data carrier detect (1 = carrier lost)
|
|
15
|
+
* bit3 CTS — clear-to-send input (1 = NOT clear to send)
|
|
16
|
+
* bit4 FE — framing error
|
|
17
|
+
* bit5 OVRN — receiver overrun
|
|
18
|
+
* bit6 PE — parity error
|
|
19
|
+
* bit7 IRQ — interrupt request pending
|
|
20
|
+
*
|
|
21
|
+
* Control register (write):
|
|
22
|
+
* bits1-0 counter divide / master reset (11 = master reset)
|
|
23
|
+
* bits4-2 word select (data bits / parity / stop bits — cosmetic here)
|
|
24
|
+
* bits6-5 transmit control (RTS state + TX interrupt enable)
|
|
25
|
+
* bit7 receive interrupt enable
|
|
26
|
+
*
|
|
27
|
+
* DCD and CTS default to their grounded (active) state — carrier present and
|
|
28
|
+
* clear-to-send — matching a board jumpered for direct terminal use. With DCD
|
|
29
|
+
* lost, RDRF is clamped to 0; with CTS not clear, TDRE is inhibited (the two
|
|
30
|
+
* classic "my 2SIO doesn't work" failure modes).
|
|
31
|
+
*/
|
|
32
|
+
export declare class Mc6850Acia implements IIODevice {
|
|
33
|
+
private readonly statusPort;
|
|
34
|
+
private readonly dataPort;
|
|
35
|
+
readonly id: string;
|
|
36
|
+
readonly basePorts: ReadonlyArray<number>;
|
|
37
|
+
private controlReg;
|
|
38
|
+
private rxQueue;
|
|
39
|
+
private errorFlags;
|
|
40
|
+
private rxIntEnable;
|
|
41
|
+
private txIntEnable;
|
|
42
|
+
private ctsClear;
|
|
43
|
+
private carrierPresent;
|
|
44
|
+
private transmitCb;
|
|
45
|
+
constructor(id: string, statusPort: number, dataPort: number);
|
|
46
|
+
ioRead(port: number): number;
|
|
47
|
+
ioWrite(port: number, value: number): void;
|
|
48
|
+
reset(): void;
|
|
49
|
+
/**
|
|
50
|
+
* Feed a received byte to the ACIA. Sets RDRF; a byte arriving while the
|
|
51
|
+
* previous one has not been read flags an overrun (OVRN).
|
|
52
|
+
*/
|
|
53
|
+
enqueueRx(byte: number): void;
|
|
54
|
+
onTransmit(cb: TransmitCallback): void;
|
|
55
|
+
/** Drive the CTS input: true = clear to send (grounded), false = inhibited. */
|
|
56
|
+
setCts(clear: boolean): void;
|
|
57
|
+
/** Drive the DCD input: true = carrier present (grounded), false = lost. */
|
|
58
|
+
setDcd(carrierPresent: boolean): void;
|
|
59
|
+
/** Inject receive error flags (framing / overrun / parity) for the next read. */
|
|
60
|
+
setErrors(fe: boolean, ovrn: boolean, pe: boolean): void;
|
|
61
|
+
/** Last value written to the control register. */
|
|
62
|
+
get control(): number;
|
|
63
|
+
private writeControl;
|
|
64
|
+
private masterReset;
|
|
65
|
+
private buildStatus;
|
|
66
|
+
}
|
|
67
|
+
export {};
|
|
68
|
+
//# sourceMappingURL=Mc6850Acia.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Mc6850Acia.d.ts","sourceRoot":"","sources":["../../src/cards/Mc6850Acia.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAG5D,KAAK,gBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qBAAa,UAAW,YAAW,SAAS;IAclB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAAU,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAbtF,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAE1C,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,OAAO,CAAgB;IAE/B,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,cAAc,CAAQ;IAC9B,OAAO,CAAC,UAAU,CAA+B;gBAErC,EAAE,EAAE,MAAM,EAAmB,UAAU,EAAE,MAAM,EAAmB,QAAQ,EAAE,MAAM;IAK9F,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAa5B,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAW1C,KAAK,IAAI,IAAI;IAMb;;;OAGG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAO7B,UAAU,CAAC,EAAE,EAAE,gBAAgB,GAAG,IAAI;IAItC,+EAA+E;IAC/E,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAI5B,4EAA4E;IAC5E,MAAM,CAAC,cAAc,EAAE,OAAO,GAAG,IAAI;IAIrC,iFAAiF;IACjF,SAAS,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,GAAG,IAAI;IAIxD,kDAAkD;IAClD,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,WAAW;CAUpB"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { u8 } from '../util/bits.js';
|
|
2
|
+
/**
|
|
3
|
+
* Motorola MC6850 ACIA, as used (×2) on the MITS Altair 88-2SIO board.
|
|
4
|
+
*
|
|
5
|
+
* Occupies two consecutive I/O ports — note the order is the OPPOSITE of the
|
|
6
|
+
* Intel 8251 / TR1602 (which put data at the lower address):
|
|
7
|
+
* statusPort (base+0) — read: status register; write: control register
|
|
8
|
+
* dataPort (base+1) — read: received byte; write: transmit byte
|
|
9
|
+
*
|
|
10
|
+
* Status register:
|
|
11
|
+
* bit0 RDRF — receive data register full (1 = byte available)
|
|
12
|
+
* bit1 TDRE — transmit data register empty (1 = ready to accept a byte)
|
|
13
|
+
* bit2 DCD — data carrier detect (1 = carrier lost)
|
|
14
|
+
* bit3 CTS — clear-to-send input (1 = NOT clear to send)
|
|
15
|
+
* bit4 FE — framing error
|
|
16
|
+
* bit5 OVRN — receiver overrun
|
|
17
|
+
* bit6 PE — parity error
|
|
18
|
+
* bit7 IRQ — interrupt request pending
|
|
19
|
+
*
|
|
20
|
+
* Control register (write):
|
|
21
|
+
* bits1-0 counter divide / master reset (11 = master reset)
|
|
22
|
+
* bits4-2 word select (data bits / parity / stop bits — cosmetic here)
|
|
23
|
+
* bits6-5 transmit control (RTS state + TX interrupt enable)
|
|
24
|
+
* bit7 receive interrupt enable
|
|
25
|
+
*
|
|
26
|
+
* DCD and CTS default to their grounded (active) state — carrier present and
|
|
27
|
+
* clear-to-send — matching a board jumpered for direct terminal use. With DCD
|
|
28
|
+
* lost, RDRF is clamped to 0; with CTS not clear, TDRE is inhibited (the two
|
|
29
|
+
* classic "my 2SIO doesn't work" failure modes).
|
|
30
|
+
*/
|
|
31
|
+
export class Mc6850Acia {
|
|
32
|
+
statusPort;
|
|
33
|
+
dataPort;
|
|
34
|
+
id;
|
|
35
|
+
basePorts;
|
|
36
|
+
controlReg = 0;
|
|
37
|
+
rxQueue = [];
|
|
38
|
+
// bit0=FE, bit1=OVRN, bit2=PE — positioned into status bits 4-6 when read.
|
|
39
|
+
errorFlags = 0;
|
|
40
|
+
rxIntEnable = false;
|
|
41
|
+
txIntEnable = false;
|
|
42
|
+
ctsClear = true; // CTS input grounded → clear to send
|
|
43
|
+
carrierPresent = true; // DCD input grounded → carrier present
|
|
44
|
+
transmitCb;
|
|
45
|
+
constructor(id, statusPort, dataPort) {
|
|
46
|
+
this.statusPort = statusPort;
|
|
47
|
+
this.dataPort = dataPort;
|
|
48
|
+
this.id = id;
|
|
49
|
+
this.basePorts = [statusPort, dataPort];
|
|
50
|
+
}
|
|
51
|
+
ioRead(port) {
|
|
52
|
+
if (port === this.statusPort) {
|
|
53
|
+
return this.buildStatus();
|
|
54
|
+
}
|
|
55
|
+
// Data port read: pull the received byte, clearing RDRF (and overrun once
|
|
56
|
+
// the buffer drains).
|
|
57
|
+
const byte = this.rxQueue.shift();
|
|
58
|
+
if (this.rxQueue.length === 0) {
|
|
59
|
+
this.errorFlags &= ~0x02;
|
|
60
|
+
}
|
|
61
|
+
return byte !== undefined ? byte : 0xff;
|
|
62
|
+
}
|
|
63
|
+
ioWrite(port, value) {
|
|
64
|
+
if (port === this.statusPort) {
|
|
65
|
+
this.writeControl(u8(value));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// Data port write: transmit, unless CTS says the peer is not ready.
|
|
69
|
+
if (this.ctsClear) {
|
|
70
|
+
this.transmitCb?.(u8(value));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
reset() {
|
|
74
|
+
this.masterReset();
|
|
75
|
+
this.controlReg = 0;
|
|
76
|
+
// cts/dcd inputs and transmitCb survive reset — they are host wiring.
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Feed a received byte to the ACIA. Sets RDRF; a byte arriving while the
|
|
80
|
+
* previous one has not been read flags an overrun (OVRN).
|
|
81
|
+
*/
|
|
82
|
+
enqueueRx(byte) {
|
|
83
|
+
if (this.rxQueue.length > 0) {
|
|
84
|
+
this.errorFlags |= 0x02; // OVRN
|
|
85
|
+
}
|
|
86
|
+
this.rxQueue.push(u8(byte));
|
|
87
|
+
}
|
|
88
|
+
onTransmit(cb) {
|
|
89
|
+
this.transmitCb = cb;
|
|
90
|
+
}
|
|
91
|
+
/** Drive the CTS input: true = clear to send (grounded), false = inhibited. */
|
|
92
|
+
setCts(clear) {
|
|
93
|
+
this.ctsClear = clear;
|
|
94
|
+
}
|
|
95
|
+
/** Drive the DCD input: true = carrier present (grounded), false = lost. */
|
|
96
|
+
setDcd(carrierPresent) {
|
|
97
|
+
this.carrierPresent = carrierPresent;
|
|
98
|
+
}
|
|
99
|
+
/** Inject receive error flags (framing / overrun / parity) for the next read. */
|
|
100
|
+
setErrors(fe, ovrn, pe) {
|
|
101
|
+
this.errorFlags = (fe ? 0x01 : 0) | (ovrn ? 0x02 : 0) | (pe ? 0x04 : 0);
|
|
102
|
+
}
|
|
103
|
+
/** Last value written to the control register. */
|
|
104
|
+
get control() {
|
|
105
|
+
return this.controlReg;
|
|
106
|
+
}
|
|
107
|
+
writeControl(value) {
|
|
108
|
+
this.controlReg = value;
|
|
109
|
+
if ((value & 0x03) === 0x03) {
|
|
110
|
+
this.masterReset();
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
this.rxIntEnable = (value & 0x80) !== 0;
|
|
114
|
+
this.txIntEnable = (value & 0x60) === 0x20; // bits 6-5 == 01
|
|
115
|
+
}
|
|
116
|
+
masterReset() {
|
|
117
|
+
this.rxQueue = [];
|
|
118
|
+
this.errorFlags = 0;
|
|
119
|
+
this.rxIntEnable = false;
|
|
120
|
+
this.txIntEnable = false;
|
|
121
|
+
}
|
|
122
|
+
buildStatus() {
|
|
123
|
+
const rdrf = this.rxQueue.length > 0 && this.carrierPresent ? 0x01 : 0;
|
|
124
|
+
const tdre = this.ctsClear ? 0x02 : 0;
|
|
125
|
+
const dcd = this.carrierPresent ? 0 : 0x04;
|
|
126
|
+
const cts = this.ctsClear ? 0 : 0x08;
|
|
127
|
+
const errs = (this.errorFlags & 0x07) << 4; // FE=bit4, OVRN=bit5, PE=bit6
|
|
128
|
+
const irq = (this.rxIntEnable && rdrf !== 0) || (this.txIntEnable && tdre !== 0) ? 0x80 : 0;
|
|
129
|
+
return rdrf | tdre | dcd | cts | errs | irq;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=Mc6850Acia.js.map
|