jsbeeb 1.22.4 → 1.24.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/README.md +2 -2
- package/package.json +16 -11
- package/src/6502.js +39 -42
- package/src/6502.opcodes.js +198 -123
- package/src/6847.js +4 -5
- package/src/6847_fontdata.js +0 -2
- package/src/acia.js +2 -3
- package/src/app/app.js +0 -1
- package/src/app/args.js +0 -2
- package/src/app/electron.js +4 -6
- package/src/app-bench.js +1 -3
- package/src/archive.js +243 -0
- package/src/basic-loader.js +0 -7
- package/src/basic-tokenise.js +19 -6
- package/src/bbc-palette.js +0 -2
- package/src/bbcdiscs.js +0 -2
- package/src/bem-snapshot.js +1 -3
- package/src/binary.js +175 -0
- package/src/cmos.js +0 -2
- package/src/ddnoise.js +0 -1
- package/src/debounce.js +7 -0
- package/src/disc-surface.js +0 -2
- package/src/disc.js +10 -9
- package/src/fake6502.js +7 -23
- package/src/fdc.js +9 -51
- package/src/filestore.js +10 -17
- package/src/hex.js +38 -0
- package/src/index.js +11 -0
- package/src/intel-fdc.js +18 -20
- package/src/jsbeeb.css +33 -0
- package/src/{utils_atom.js → keymap-atom.js} +2 -18
- package/src/{utils.js → keymap.js} +47 -610
- package/src/loader.js +63 -0
- package/src/machine-session.js +37 -177
- package/src/machine-spec.js +59 -0
- package/src/main.js +69 -184
- package/src/media-resolver.js +68 -0
- package/src/mmc.js +3 -2
- package/src/models.js +40 -4
- package/src/music5000.js +0 -2
- package/src/ppia.js +3 -4
- package/src/printer.js +7 -14
- package/src/relaynoise.js +0 -1
- package/src/rewind.js +0 -2
- package/src/sample-player.js +2 -3
- package/src/serial.js +0 -2
- package/src/snapshot-helpers.js +0 -2
- package/src/snapshot.js +0 -2
- package/src/soundchip.js +1 -1
- package/src/state-utils.js +0 -2
- package/src/sth.js +2 -4
- package/src/tapes.js +10 -4
- package/src/teletext.js +2 -3
- package/src/teletext_adaptor.js +2 -4
- package/src/teletext_data.js +0 -2
- package/src/test-machine.js +307 -0
- package/src/touchscreen.js +2 -4
- package/src/tube.js +5 -6
- package/src/typist.js +103 -0
- package/src/uef-snapshot.js +0 -2
- package/src/url-params.js +4 -5
- package/src/vdu-capture.js +113 -0
- package/src/via.js +3 -4
- package/src/video-filters/pal-composite.js +0 -2
- package/src/video-filters/passthrough-filter.js +0 -2
- package/src/video-filters/pixel-grid.js +0 -2
- package/src/video-filters/shader-program.js +0 -2
- package/src/video-filters/xbr-filter.js +0 -2
- package/src/video.js +12 -11
- package/src/wd-fdc.js +20 -20
- package/src/web/analogue-inputs.js +6 -8
- package/src/web/analytics.js +13 -0
- package/src/web/audio-handler.js +2 -2
- package/src/{audio-utils.js → web/audio-utils.js} +0 -2
- package/src/web/autoboot.js +10 -13
- package/src/{canvas.js → web/canvas.js} +4 -5
- package/src/web/config.js +42 -72
- package/src/web/console-surface.js +25 -0
- package/src/web/debug.js +8 -49
- package/src/web/disc-visualiser.js +0 -2
- package/src/web/display.js +21 -4
- package/src/{dom-utils.js → web/dom-utils.js} +1 -11
- package/src/web/drives.js +1 -1
- package/src/web/emulation-loop.js +54 -33
- package/src/web/front-panel.js +13 -12
- package/src/{gamepads.js → web/gamepads.js} +2 -6
- package/src/web/google-drive-picker.js +14 -9
- package/src/{google-drive.js → web/google-drive.js} +9 -10
- package/src/web/hfe-picker.js +5 -4
- package/src/web/icons.js +42 -0
- package/src/web/keyboard-setup.js +29 -40
- package/src/{keyboard.js → web/keyboard.js} +18 -119
- package/src/web/layout.js +4 -0
- package/src/web/local-disc.js +44 -0
- package/src/web/machine.js +27 -20
- package/src/web/media-loader.js +38 -147
- package/src/{microphone-input.js → web/microphone-input.js} +1 -1
- package/src/web/modals.js +6 -9
- package/src/web/page-actions.js +88 -0
- package/src/web/quick-settings.js +16 -15
- package/src/web/reporting.js +0 -7
- package/src/{rewind-thumbnail.js → web/rewind-thumbnail.js} +0 -2
- package/src/web/rewind-ui.js +29 -29
- package/src/web/run-controls.js +39 -0
- package/src/web/settings.js +64 -135
- package/src/web/snapshot-ui.js +10 -16
- package/src/{speech-output.js → web/speech-output.js} +0 -2
- package/src/web/sth-picker.js +9 -7
- package/src/web/url-state.js +20 -6
- package/src/econet/L3FS.dat +0 -0
- package/src/econet/scsi.dat +0 -0
- package/tests/test-machine.js +0 -609
package/src/6502.opcodes.js
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
const hexword = utils.hexword;
|
|
5
|
-
const hexbyte = utils.hexbyte;
|
|
6
|
-
const signExtend = utils.signExtend;
|
|
1
|
+
import { signExtend } from "./binary.js";
|
|
2
|
+
import { hexbyte, hexword } from "./hex.js";
|
|
7
3
|
|
|
8
4
|
function rotate(left, logical) {
|
|
9
5
|
const lines = [];
|
|
@@ -525,254 +521,269 @@ function getOp(op, arg) {
|
|
|
525
521
|
throw new Error(`Unrecognised operation '${op}'`);
|
|
526
522
|
}
|
|
527
523
|
|
|
528
|
-
|
|
524
|
+
// Undocumented opcodes carry a leading "*", as 6502 listings conventionally show them.
|
|
525
|
+
function splitUndocumented(markedOpcodes) {
|
|
526
|
+
const opcodes = {};
|
|
527
|
+
const undocumented = new Set();
|
|
528
|
+
for (const [op, text] of Object.entries(markedOpcodes)) {
|
|
529
|
+
if (text.startsWith("*")) {
|
|
530
|
+
undocumented.add(Number(op));
|
|
531
|
+
opcodes[op] = text.slice(1);
|
|
532
|
+
} else {
|
|
533
|
+
opcodes[op] = text;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
return { opcodes, undocumented };
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
const { opcodes: opcodes6502, undocumented: undocumented6502 } = splitUndocumented({
|
|
529
540
|
0x00: "BRK",
|
|
530
541
|
0x01: "ORA (,x)",
|
|
531
|
-
0x03: "SLO (,x)",
|
|
532
|
-
0x04: "NOP zp",
|
|
542
|
+
0x03: "*SLO (,x)",
|
|
543
|
+
0x04: "*NOP zp",
|
|
533
544
|
0x05: "ORA zp",
|
|
534
545
|
0x06: "ASL zp",
|
|
535
|
-
0x07: "SLO zp",
|
|
546
|
+
0x07: "*SLO zp",
|
|
536
547
|
0x08: "PHP",
|
|
537
548
|
0x09: "ORA imm",
|
|
538
549
|
0x0a: "ASL A",
|
|
539
|
-
0x0b: "ANC imm",
|
|
540
|
-
0x0c: "NOP abs",
|
|
550
|
+
0x0b: "*ANC imm",
|
|
551
|
+
0x0c: "*NOP abs",
|
|
541
552
|
0x0d: "ORA abs",
|
|
542
553
|
0x0e: "ASL abs",
|
|
543
|
-
0x0f: "SLO abs",
|
|
554
|
+
0x0f: "*SLO abs",
|
|
544
555
|
0x10: "BPL branch",
|
|
545
556
|
0x11: "ORA (),y",
|
|
546
|
-
0x13: "SLO (),y",
|
|
547
|
-
0x14: "NOP zp,x",
|
|
557
|
+
0x13: "*SLO (),y",
|
|
558
|
+
0x14: "*NOP zp,x",
|
|
548
559
|
0x15: "ORA zp,x",
|
|
549
560
|
0x16: "ASL zp,x",
|
|
550
|
-
0x17: "SLO zp,x",
|
|
561
|
+
0x17: "*SLO zp,x",
|
|
551
562
|
0x18: "CLC",
|
|
552
563
|
0x19: "ORA abs,y",
|
|
553
|
-
0x1a: "NOP",
|
|
554
|
-
0x1b: "SLO abs,y",
|
|
555
|
-
0x1c: "NOP abs,x",
|
|
564
|
+
0x1a: "*NOP",
|
|
565
|
+
0x1b: "*SLO abs,y",
|
|
566
|
+
0x1c: "*NOP abs,x",
|
|
556
567
|
0x1d: "ORA abs,x",
|
|
557
568
|
0x1e: "ASL abs,x",
|
|
558
|
-
0x1f: "SLO abs,x",
|
|
569
|
+
0x1f: "*SLO abs,x",
|
|
559
570
|
0x20: "JSR abs",
|
|
560
571
|
0x21: "AND (,x)",
|
|
561
|
-
0x23: "RLA (,x)",
|
|
572
|
+
0x23: "*RLA (,x)",
|
|
562
573
|
0x24: "BIT zp",
|
|
563
574
|
0x25: "AND zp",
|
|
564
575
|
0x26: "ROL zp",
|
|
565
|
-
0x27: "RLA zp",
|
|
576
|
+
0x27: "*RLA zp",
|
|
566
577
|
0x28: "PLP",
|
|
567
578
|
0x29: "AND imm",
|
|
568
579
|
0x2a: "ROL A",
|
|
569
|
-
0x2b: "ANC imm",
|
|
580
|
+
0x2b: "*ANC imm",
|
|
570
581
|
0x2c: "BIT abs",
|
|
571
582
|
0x2d: "AND abs",
|
|
572
583
|
0x2e: "ROL abs",
|
|
573
|
-
0x2f: "RLA abs",
|
|
584
|
+
0x2f: "*RLA abs",
|
|
574
585
|
0x30: "BMI branch",
|
|
575
586
|
0x31: "AND (),y",
|
|
576
|
-
0x33: "RLA (),y",
|
|
577
|
-
0x34: "NOP zp,x",
|
|
587
|
+
0x33: "*RLA (),y",
|
|
588
|
+
0x34: "*NOP zp,x",
|
|
578
589
|
0x35: "AND zp,x",
|
|
579
590
|
0x36: "ROL zp,x",
|
|
580
|
-
0x37: "RLA zp,x",
|
|
591
|
+
0x37: "*RLA zp,x",
|
|
581
592
|
0x38: "SEC",
|
|
582
593
|
0x39: "AND abs,y",
|
|
583
|
-
0x3a: "NOP",
|
|
584
|
-
0x3b: "RLA abs,y",
|
|
585
|
-
0x3c: "NOP abs,x",
|
|
594
|
+
0x3a: "*NOP",
|
|
595
|
+
0x3b: "*RLA abs,y",
|
|
596
|
+
0x3c: "*NOP abs,x",
|
|
586
597
|
0x3d: "AND abs,x",
|
|
587
598
|
0x3e: "ROL abs,x",
|
|
588
|
-
0x3f: "RLA abs,x",
|
|
599
|
+
0x3f: "*RLA abs,x",
|
|
589
600
|
0x40: "RTI",
|
|
590
601
|
0x41: "EOR (,x)",
|
|
591
|
-
0x43: "SRE (,x)",
|
|
592
|
-
0x44: "NOP zp",
|
|
602
|
+
0x43: "*SRE (,x)",
|
|
603
|
+
0x44: "*NOP zp",
|
|
593
604
|
0x45: "EOR zp",
|
|
594
605
|
0x46: "LSR zp",
|
|
595
|
-
0x47: "SRE zp",
|
|
606
|
+
0x47: "*SRE zp",
|
|
596
607
|
0x48: "PHA",
|
|
597
608
|
0x49: "EOR imm",
|
|
598
609
|
0x4a: "LSR A",
|
|
599
|
-
0x4b: "ASR imm",
|
|
610
|
+
0x4b: "*ASR imm",
|
|
600
611
|
0x4c: "JMP abs",
|
|
601
612
|
0x4d: "EOR abs",
|
|
602
613
|
0x4e: "LSR abs",
|
|
603
|
-
0x4f: "SRE abs",
|
|
614
|
+
0x4f: "*SRE abs",
|
|
604
615
|
0x50: "BVC branch",
|
|
605
616
|
0x51: "EOR (),y",
|
|
606
|
-
0x53: "SRE (),y",
|
|
607
|
-
0x54: "NOP zp,x",
|
|
617
|
+
0x53: "*SRE (),y",
|
|
618
|
+
0x54: "*NOP zp,x",
|
|
608
619
|
0x55: "EOR zp,x",
|
|
609
620
|
0x56: "LSR zp,x",
|
|
610
|
-
0x57: "SRE zp,x",
|
|
621
|
+
0x57: "*SRE zp,x",
|
|
611
622
|
0x58: "CLI",
|
|
612
623
|
0x59: "EOR abs,y",
|
|
613
|
-
0x5a: "NOP",
|
|
614
|
-
0x5b: "SRE abs,y",
|
|
615
|
-
0x5c: "NOP abs,x",
|
|
624
|
+
0x5a: "*NOP",
|
|
625
|
+
0x5b: "*SRE abs,y",
|
|
626
|
+
0x5c: "*NOP abs,x",
|
|
616
627
|
0x5d: "EOR abs,x",
|
|
617
628
|
0x5e: "LSR abs,x",
|
|
618
|
-
0x5f: "SRE abs,x",
|
|
629
|
+
0x5f: "*SRE abs,x",
|
|
619
630
|
0x60: "RTS",
|
|
620
631
|
0x61: "ADC (,x)",
|
|
621
|
-
0x63: "RRA (,x)",
|
|
622
|
-
0x64: "NOP zp",
|
|
632
|
+
0x63: "*RRA (,x)",
|
|
633
|
+
0x64: "*NOP zp",
|
|
623
634
|
0x65: "ADC zp",
|
|
624
635
|
0x66: "ROR zp",
|
|
625
|
-
0x67: "RRA zp",
|
|
636
|
+
0x67: "*RRA zp",
|
|
626
637
|
0x68: "PLA",
|
|
627
638
|
0x69: "ADC imm",
|
|
628
639
|
0x6a: "ROR A",
|
|
629
|
-
0x6b: "ARR imm",
|
|
640
|
+
0x6b: "*ARR imm",
|
|
630
641
|
0x6c: "JMP (abs)",
|
|
631
642
|
0x6d: "ADC abs",
|
|
632
643
|
0x6e: "ROR abs",
|
|
633
|
-
0x6f: "RRA abs",
|
|
644
|
+
0x6f: "*RRA abs",
|
|
634
645
|
0x70: "BVS branch",
|
|
635
646
|
0x71: "ADC (),y",
|
|
636
|
-
0x73: "RRA (),y",
|
|
637
|
-
0x74: "NOP zp,x",
|
|
647
|
+
0x73: "*RRA (),y",
|
|
648
|
+
0x74: "*NOP zp,x",
|
|
638
649
|
0x75: "ADC zp,x",
|
|
639
650
|
0x76: "ROR zp,x",
|
|
640
|
-
0x77: "RRA zp,x",
|
|
651
|
+
0x77: "*RRA zp,x",
|
|
641
652
|
0x78: "SEI",
|
|
642
653
|
0x79: "ADC abs,y",
|
|
643
|
-
0x7a: "NOP",
|
|
644
|
-
0x7b: "RRA abs,y",
|
|
645
|
-
0x7c: "NOP abs,x",
|
|
654
|
+
0x7a: "*NOP",
|
|
655
|
+
0x7b: "*RRA abs,y",
|
|
656
|
+
0x7c: "*NOP abs,x",
|
|
646
657
|
0x7d: "ADC abs,x",
|
|
647
658
|
0x7e: "ROR abs,x",
|
|
648
|
-
0x7f: "RRA abs,x",
|
|
649
|
-
0x80: "NOP imm",
|
|
659
|
+
0x7f: "*RRA abs,x",
|
|
660
|
+
0x80: "*NOP imm",
|
|
650
661
|
0x81: "STA (,x)",
|
|
651
|
-
0x82: "NOP imm",
|
|
652
|
-
0x83: "SAX (,x)",
|
|
662
|
+
0x82: "*NOP imm",
|
|
663
|
+
0x83: "*SAX (,x)",
|
|
653
664
|
0x84: "STY zp",
|
|
654
665
|
0x85: "STA zp",
|
|
655
666
|
0x86: "STX zp",
|
|
656
|
-
0x87: "SAX zp",
|
|
667
|
+
0x87: "*SAX zp",
|
|
657
668
|
0x88: "DEY",
|
|
658
|
-
0x89: "NOP imm",
|
|
669
|
+
0x89: "*NOP imm",
|
|
659
670
|
0x8a: "TXA",
|
|
660
|
-
0x8b: "ANE imm",
|
|
671
|
+
0x8b: "*ANE imm",
|
|
661
672
|
0x8c: "STY abs",
|
|
662
673
|
0x8d: "STA abs",
|
|
663
674
|
0x8e: "STX abs",
|
|
664
|
-
0x8f: "SAX abs",
|
|
675
|
+
0x8f: "*SAX abs",
|
|
665
676
|
0x90: "BCC branch",
|
|
666
677
|
0x91: "STA (),y",
|
|
667
|
-
0x93: "SHA (),y",
|
|
678
|
+
0x93: "*SHA (),y",
|
|
668
679
|
0x94: "STY zp,x",
|
|
669
680
|
0x95: "STA zp,x",
|
|
670
681
|
0x96: "STX zp,y",
|
|
671
|
-
0x97: "SAX zp,y",
|
|
682
|
+
0x97: "*SAX zp,y",
|
|
672
683
|
0x98: "TYA",
|
|
673
684
|
0x99: "STA abs,y",
|
|
674
685
|
0x9a: "TXS",
|
|
675
|
-
0x9b: "SHS abs,y",
|
|
676
|
-
0x9c: "SHY abs,x",
|
|
686
|
+
0x9b: "*SHS abs,y",
|
|
687
|
+
0x9c: "*SHY abs,x",
|
|
677
688
|
0x9d: "STA abs,x",
|
|
678
|
-
0x9e: "SHX abs,y",
|
|
679
|
-
0x9f: "SHA abs,y",
|
|
689
|
+
0x9e: "*SHX abs,y",
|
|
690
|
+
0x9f: "*SHA abs,y",
|
|
680
691
|
0xa0: "LDY imm",
|
|
681
692
|
0xa1: "LDA (,x)",
|
|
682
693
|
0xa2: "LDX imm",
|
|
683
|
-
0xa3: "LAX (,x)",
|
|
694
|
+
0xa3: "*LAX (,x)",
|
|
684
695
|
0xa4: "LDY zp",
|
|
685
696
|
0xa5: "LDA zp",
|
|
686
697
|
0xa6: "LDX zp",
|
|
687
|
-
0xa7: "LAX zp",
|
|
698
|
+
0xa7: "*LAX zp",
|
|
688
699
|
0xa8: "TAY",
|
|
689
700
|
0xa9: "LDA imm",
|
|
690
701
|
0xaa: "TAX",
|
|
691
|
-
0xab: "LXA imm",
|
|
702
|
+
0xab: "*LXA imm",
|
|
692
703
|
0xac: "LDY abs",
|
|
693
704
|
0xad: "LDA abs",
|
|
694
705
|
0xae: "LDX abs",
|
|
695
|
-
0xaf: "LAX abs",
|
|
706
|
+
0xaf: "*LAX abs",
|
|
696
707
|
0xb0: "BCS branch",
|
|
697
708
|
0xb1: "LDA (),y",
|
|
698
|
-
0xb3: "LAX (),y",
|
|
709
|
+
0xb3: "*LAX (),y",
|
|
699
710
|
0xb4: "LDY zp,x",
|
|
700
711
|
0xb5: "LDA zp,x",
|
|
701
712
|
0xb6: "LDX zp,y",
|
|
702
|
-
0xb7: "LAX zp,y",
|
|
713
|
+
0xb7: "*LAX zp,y",
|
|
703
714
|
0xb8: "CLV",
|
|
704
715
|
0xb9: "LDA abs,y",
|
|
705
716
|
0xba: "TSX",
|
|
706
|
-
0xbb: "LAS abs,y",
|
|
717
|
+
0xbb: "*LAS abs,y",
|
|
707
718
|
0xbc: "LDY abs,x",
|
|
708
719
|
0xbd: "LDA abs,x",
|
|
709
720
|
0xbe: "LDX abs,y",
|
|
710
|
-
0xbf: "LAX abs,y",
|
|
721
|
+
0xbf: "*LAX abs,y",
|
|
711
722
|
0xc0: "CPY imm",
|
|
712
723
|
0xc1: "CMP (,x)",
|
|
713
|
-
0xc2: "NOP imm",
|
|
714
|
-
0xc3: "DCP (,x)",
|
|
724
|
+
0xc2: "*NOP imm",
|
|
725
|
+
0xc3: "*DCP (,x)",
|
|
715
726
|
0xc4: "CPY zp",
|
|
716
727
|
0xc5: "CMP zp",
|
|
717
728
|
0xc6: "DEC zp",
|
|
718
|
-
0xc7: "DCP zp",
|
|
729
|
+
0xc7: "*DCP zp",
|
|
719
730
|
0xc8: "INY",
|
|
720
731
|
0xc9: "CMP imm",
|
|
721
732
|
0xca: "DEX",
|
|
722
|
-
0xcb: "SBX imm",
|
|
733
|
+
0xcb: "*SBX imm",
|
|
723
734
|
0xcc: "CPY abs",
|
|
724
735
|
0xcd: "CMP abs",
|
|
725
736
|
0xce: "DEC abs",
|
|
726
|
-
0xcf: "DCP abs",
|
|
737
|
+
0xcf: "*DCP abs",
|
|
727
738
|
0xd0: "BNE branch",
|
|
728
739
|
0xd1: "CMP (),y",
|
|
729
|
-
0xd3: "DCP (),y",
|
|
730
|
-
0xd4: "NOP zp,x",
|
|
740
|
+
0xd3: "*DCP (),y",
|
|
741
|
+
0xd4: "*NOP zp,x",
|
|
731
742
|
0xd5: "CMP zp,x",
|
|
732
743
|
0xd6: "DEC zp,x",
|
|
733
|
-
0xd7: "DCP zp,x",
|
|
744
|
+
0xd7: "*DCP zp,x",
|
|
734
745
|
0xd8: "CLD",
|
|
735
746
|
0xd9: "CMP abs,y",
|
|
736
|
-
0xda: "NOP",
|
|
737
|
-
0xdb: "DCP abs,y",
|
|
738
|
-
0xdc: "NOP abs,x",
|
|
747
|
+
0xda: "*NOP",
|
|
748
|
+
0xdb: "*DCP abs,y",
|
|
749
|
+
0xdc: "*NOP abs,x",
|
|
739
750
|
0xdd: "CMP abs,x",
|
|
740
751
|
0xde: "DEC abs,x",
|
|
741
|
-
0xdf: "DCP abs,x",
|
|
752
|
+
0xdf: "*DCP abs,x",
|
|
742
753
|
0xe0: "CPX imm",
|
|
743
754
|
0xe1: "SBC (,x)",
|
|
744
|
-
0xe2: "NOP imm",
|
|
745
|
-
0xe3: "ISB (,x)",
|
|
755
|
+
0xe2: "*NOP imm",
|
|
756
|
+
0xe3: "*ISB (,x)",
|
|
746
757
|
0xe4: "CPX zp",
|
|
747
758
|
0xe5: "SBC zp",
|
|
748
759
|
0xe6: "INC zp",
|
|
749
|
-
0xe7: "ISB zp",
|
|
760
|
+
0xe7: "*ISB zp",
|
|
750
761
|
0xe8: "INX",
|
|
751
762
|
0xe9: "SBC imm",
|
|
752
763
|
0xea: "NOP",
|
|
753
|
-
0xeb: "SBC imm",
|
|
764
|
+
0xeb: "*SBC imm",
|
|
754
765
|
0xec: "CPX abs",
|
|
755
766
|
0xed: "SBC abs",
|
|
756
767
|
0xee: "INC abs",
|
|
757
|
-
0xef: "ISB abs",
|
|
768
|
+
0xef: "*ISB abs",
|
|
758
769
|
0xf0: "BEQ branch",
|
|
759
770
|
0xf1: "SBC (),y",
|
|
760
|
-
0xf3: "ISB (),y",
|
|
761
|
-
0xf4: "NOP
|
|
771
|
+
0xf3: "*ISB (),y",
|
|
772
|
+
0xf4: "*NOP zp,x",
|
|
762
773
|
0xf5: "SBC zp,x",
|
|
763
774
|
0xf6: "INC zp,x",
|
|
764
|
-
0xf7: "ISB zp,x",
|
|
775
|
+
0xf7: "*ISB zp,x",
|
|
765
776
|
0xf8: "SED",
|
|
766
777
|
0xf9: "SBC abs,y",
|
|
767
|
-
0xfa: "NOP",
|
|
768
|
-
0xfb: "ISB abs,y",
|
|
769
|
-
0xfc: "NOP abs,x",
|
|
778
|
+
0xfa: "*NOP",
|
|
779
|
+
0xfb: "*ISB abs,y",
|
|
780
|
+
0xfc: "*NOP abs,x",
|
|
770
781
|
0xfd: "SBC abs,x",
|
|
771
782
|
0xfe: "INC abs,x",
|
|
772
|
-
0xff: "ISB abs,x",
|
|
773
|
-
};
|
|
783
|
+
0xff: "*ISB abs,x",
|
|
784
|
+
});
|
|
774
785
|
|
|
775
|
-
const opcodes65c12 = {
|
|
786
|
+
const { opcodes: opcodes65c12, undocumented: undocumented65c12 } = splitUndocumented({
|
|
776
787
|
0x00: "BRK",
|
|
777
788
|
0x01: "ORA (,x)",
|
|
778
789
|
0x04: "TSB zp",
|
|
@@ -952,9 +963,9 @@ const opcodes65c12 = {
|
|
|
952
963
|
0xfa: "PLX",
|
|
953
964
|
0xfd: "SBC abs,x",
|
|
954
965
|
0xfe: "INC abs,x",
|
|
955
|
-
};
|
|
966
|
+
});
|
|
956
967
|
|
|
957
|
-
const opcodes65c02 = {
|
|
968
|
+
const { opcodes: opcodes65c02, undocumented: undocumented65c02 } = splitUndocumented({
|
|
958
969
|
...opcodes65c12,
|
|
959
970
|
0x07: "RMB0 zp",
|
|
960
971
|
0x17: "RMB1 zp",
|
|
@@ -988,12 +999,20 @@ const opcodes65c02 = {
|
|
|
988
999
|
0xdf: "BBS5 zp,branch",
|
|
989
1000
|
0xef: "BBS6 zp,branch",
|
|
990
1001
|
0xff: "BBS7 zp,branch",
|
|
991
|
-
};
|
|
1002
|
+
});
|
|
1003
|
+
|
|
1004
|
+
const PrevInstructionWindow = 64;
|
|
992
1005
|
|
|
993
1006
|
class Disassemble6502 {
|
|
994
|
-
constructor(cpu, opcodes) {
|
|
1007
|
+
constructor(cpu, opcodes, undocumented) {
|
|
995
1008
|
this.cpu = cpu;
|
|
996
1009
|
this.opcodes = opcodes;
|
|
1010
|
+
this.undocumented = undocumented;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
isDocumented(addr) {
|
|
1014
|
+
const op = this.cpu.peekmem(addr);
|
|
1015
|
+
return op in this.opcodes && !this.undocumented.has(op);
|
|
997
1016
|
}
|
|
998
1017
|
|
|
999
1018
|
disassemble(addr, plain) {
|
|
@@ -1003,13 +1022,15 @@ class Disassemble6502 {
|
|
|
1003
1022
|
formatAddr = hexword;
|
|
1004
1023
|
formatJumpAddr = hexword;
|
|
1005
1024
|
}
|
|
1006
|
-
const
|
|
1025
|
+
const opcodeByte = this.cpu.peekmem(addr);
|
|
1026
|
+
const opcode = this.opcodes[opcodeByte];
|
|
1007
1027
|
if (!opcode) {
|
|
1008
1028
|
return ["???", addr + 1];
|
|
1009
1029
|
}
|
|
1010
|
-
const
|
|
1030
|
+
const [mnemonic, ...rest] = opcode.split(" ");
|
|
1031
|
+
const split = [(this.undocumented.has(opcodeByte) ? "*" : "") + mnemonic, ...rest];
|
|
1011
1032
|
if (!split[1]) {
|
|
1012
|
-
return [
|
|
1033
|
+
return [split[0], addr + 1];
|
|
1013
1034
|
}
|
|
1014
1035
|
let param = split[1] || "";
|
|
1015
1036
|
let suffix = "";
|
|
@@ -1034,18 +1055,26 @@ class Disassemble6502 {
|
|
|
1034
1055
|
}
|
|
1035
1056
|
case "zp":
|
|
1036
1057
|
return [`${split[0]} $${hexbyte(this.cpu.peekmem(addr + 1))}${suffix}`, addr + 2];
|
|
1058
|
+
case "zp,branch": {
|
|
1059
|
+
const destAddr = addr + signExtend(this.cpu.peekmem(addr + 2)) + 3;
|
|
1060
|
+
return [
|
|
1061
|
+
`${split[0]} $${hexbyte(this.cpu.peekmem(addr + 1))}, $${formatJumpAddr(destAddr)}`,
|
|
1062
|
+
addr + 3,
|
|
1063
|
+
destAddr,
|
|
1064
|
+
];
|
|
1065
|
+
}
|
|
1037
1066
|
case "(,x)":
|
|
1038
1067
|
return [`${split[0]} ($${hexbyte(this.cpu.peekmem(addr + 1))}, X)${suffix}`, addr + 2];
|
|
1039
1068
|
case "()": {
|
|
1040
1069
|
const zp = this.cpu.peekmem(addr + 1);
|
|
1041
1070
|
const destAddr = this.cpu.peekmem(zp) | (this.cpu.peekmem(zp + 1) << 8);
|
|
1042
|
-
return [`${split[0]} ($${hexbyte(zp)})${suffix} ; $${
|
|
1071
|
+
return [`${split[0]} ($${hexbyte(zp)})${suffix} ; $${hexword(destAddr)}${suffix2}`, addr + 2];
|
|
1043
1072
|
}
|
|
1044
1073
|
case "(abs)": {
|
|
1045
1074
|
const destAddr = this.cpu.peekmem(addr + 1) | (this.cpu.peekmem(addr + 2) << 8);
|
|
1046
1075
|
const indDest = this.cpu.peekmem(destAddr) | (this.cpu.peekmem(destAddr + 1) << 8);
|
|
1047
1076
|
return [
|
|
1048
|
-
`${split[0]} ($${formatJumpAddr(destAddr)})${suffix} ; $${
|
|
1077
|
+
`${split[0]} ($${formatJumpAddr(destAddr)})${suffix} ; $${hexword(indDest)}${suffix2}`,
|
|
1049
1078
|
addr + 3,
|
|
1050
1079
|
indDest,
|
|
1051
1080
|
];
|
|
@@ -1056,11 +1085,60 @@ class Disassemble6502 {
|
|
|
1056
1085
|
return [`${split[0]} ($${formatJumpAddr(destAddr)},x)${suffix}`, addr + 3, indDest];
|
|
1057
1086
|
}
|
|
1058
1087
|
}
|
|
1059
|
-
return [
|
|
1088
|
+
return [split.join(" "), addr + 1];
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
nextInstruction(address) {
|
|
1092
|
+
return this.disassemble(address)[1] & 0xffff;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
/**
|
|
1096
|
+
* Guesses the address of the instruction before the given one by scoring
|
|
1097
|
+
* each run of instructions in the preceding window that lands exactly on
|
|
1098
|
+
* it: a point per "common" instruction (loads, stores, branches, compares,
|
|
1099
|
+
* arithmetic and carry-set/clear that avoid unusual indexing modes) and a
|
|
1100
|
+
* large boost for a run that passes through pc. Runs through undocumented
|
|
1101
|
+
* opcodes are discarded. The highest-scoring run's last instruction wins;
|
|
1102
|
+
* any run beats none, since a wrong parse resynchronises within a few
|
|
1103
|
+
* instructions and so nearly always shares the true stream's last one.
|
|
1104
|
+
* Good test cases:
|
|
1105
|
+
* Repton 2 @ 2cbb
|
|
1106
|
+
* MOS @ cfc8, and the unrolled STA abs,X screen clear @ cc63
|
|
1107
|
+
* also, just starting from the back of ROM and going up...
|
|
1108
|
+
*/
|
|
1109
|
+
prevInstruction(address, pc) {
|
|
1110
|
+
const commonInstructions =
|
|
1111
|
+
/(RTS|B..|JMP|JSR|LD[AXY]|ST[AXY]|TA[XY]|T[XY]A|AD[DC]|SUB|SBC|CLC|SEC|CMP|EOR|ORA|AND|INC|DEC).*/;
|
|
1112
|
+
const uncommonInstructions = /.*,\s*([XY]|X\))$/;
|
|
1113
|
+
|
|
1114
|
+
address &= 0xffff;
|
|
1115
|
+
let bestAddr = address - 1;
|
|
1116
|
+
let bestScore = -1;
|
|
1117
|
+
for (let startingPoint = address - PrevInstructionWindow; startingPoint !== address; startingPoint++) {
|
|
1118
|
+
let score = 0;
|
|
1119
|
+
let addr = startingPoint & 0xffff;
|
|
1120
|
+
while (addr < address) {
|
|
1121
|
+
if (!this.isDocumented(addr)) break;
|
|
1122
|
+
const result = this.disassemble(addr);
|
|
1123
|
+
if (addr === pc) score += 10;
|
|
1124
|
+
if (result[0].match(commonInstructions) && !result[0].match(uncommonInstructions)) {
|
|
1125
|
+
score++;
|
|
1126
|
+
}
|
|
1127
|
+
if (result[1] === address) {
|
|
1128
|
+
if (score > bestScore) {
|
|
1129
|
+
bestScore = score;
|
|
1130
|
+
bestAddr = addr;
|
|
1131
|
+
}
|
|
1132
|
+
break;
|
|
1133
|
+
}
|
|
1134
|
+
addr = result[1];
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
return bestAddr & 0xffff;
|
|
1060
1138
|
}
|
|
1061
1139
|
}
|
|
1062
1140
|
|
|
1063
|
-
function makeCpuFunctions(cpu, opcodes, is65c12, cycleAccurate = true) {
|
|
1141
|
+
function makeCpuFunctions(cpu, opcodes, undocumented, is65c12, cycleAccurate = true) {
|
|
1064
1142
|
function getInstruction(opcodeString, needsReg) {
|
|
1065
1143
|
const split = opcodeString.split(" ");
|
|
1066
1144
|
const opcode = split[0];
|
|
@@ -1097,7 +1175,6 @@ function makeCpuFunctions(cpu, opcodes, is65c12, cycleAccurate = true) {
|
|
|
1097
1175
|
return ig.render();
|
|
1098
1176
|
|
|
1099
1177
|
case "zp":
|
|
1100
|
-
case "zpx": // Seems to be enough to keep tests happy, but needs investigation.
|
|
1101
1178
|
case "zp,x":
|
|
1102
1179
|
case "zp,y":
|
|
1103
1180
|
if (arg === "zp") {
|
|
@@ -1309,12 +1386,10 @@ function makeCpuFunctions(cpu, opcodes, is65c12, cycleAccurate = true) {
|
|
|
1309
1386
|
indent +
|
|
1310
1387
|
[
|
|
1311
1388
|
'"use strict";',
|
|
1312
|
-
`// ${
|
|
1389
|
+
`// ${hexbyte(opcodeNum)} - ${opcode}
|
|
1313
1390
|
`,
|
|
1314
1391
|
].concat(
|
|
1315
|
-
opcode
|
|
1316
|
-
? getInstruction(opcode, !!needsReg)
|
|
1317
|
-
: [`this.invalidOpcode(cpu, 0x${utils.hexbyte(opcodeNum)});`],
|
|
1392
|
+
opcode ? getInstruction(opcode, !!needsReg) : [`this.invalidOpcode(cpu, 0x${hexbyte(opcodeNum)});`],
|
|
1318
1393
|
).join(`
|
|
1319
1394
|
${indent}`)
|
|
1320
1395
|
);
|
|
@@ -1327,7 +1402,7 @@ ${indent}`)
|
|
|
1327
1402
|
const funcs = [];
|
|
1328
1403
|
for (let opcodeNum = 0; opcodeNum < 256; ++opcodeNum) {
|
|
1329
1404
|
const opcodeFunc = new Function("cpu", getIndentedSource(" ", opcodeNum, true));
|
|
1330
|
-
let funcName = `exec_${
|
|
1405
|
+
let funcName = `exec_${hexbyte(opcodeNum)}_`;
|
|
1331
1406
|
if (opcodes[opcodeNum]) {
|
|
1332
1407
|
const instrName = opcodes[opcodeNum]
|
|
1333
1408
|
.replace("()", "ind")
|
|
@@ -1409,7 +1484,7 @@ ${indent}`)
|
|
|
1409
1484
|
Runner.prototype.run = generate6502JumpTable();
|
|
1410
1485
|
|
|
1411
1486
|
return {
|
|
1412
|
-
disassembler: new Disassemble6502(cpu, opcodes),
|
|
1487
|
+
disassembler: new Disassemble6502(cpu, opcodes, undocumented),
|
|
1413
1488
|
runInstruction: new Runner(),
|
|
1414
1489
|
opcodes: opcodes,
|
|
1415
1490
|
getInstruction: getInstruction,
|
|
@@ -1417,13 +1492,13 @@ ${indent}`)
|
|
|
1417
1492
|
}
|
|
1418
1493
|
|
|
1419
1494
|
export function Cpu6502(cpu, { cycleAccurate = true } = {}) {
|
|
1420
|
-
return makeCpuFunctions(cpu, opcodes6502, false, cycleAccurate);
|
|
1495
|
+
return makeCpuFunctions(cpu, opcodes6502, undocumented6502, false, cycleAccurate);
|
|
1421
1496
|
}
|
|
1422
1497
|
|
|
1423
1498
|
export function Cpu65c12(cpu, { cycleAccurate = true } = {}) {
|
|
1424
|
-
return makeCpuFunctions(cpu, opcodes65c12, true, cycleAccurate);
|
|
1499
|
+
return makeCpuFunctions(cpu, opcodes65c12, undocumented65c12, true, cycleAccurate);
|
|
1425
1500
|
}
|
|
1426
1501
|
|
|
1427
1502
|
export function Cpu65c02(cpu, { cycleAccurate = true } = {}) {
|
|
1428
|
-
return makeCpuFunctions(cpu, opcodes65c02, true, cycleAccurate);
|
|
1503
|
+
return makeCpuFunctions(cpu, opcodes65c02, undocumented65c02, true, cycleAccurate);
|
|
1429
1504
|
}
|
package/src/6847.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
import * as utils from "./utils.js";
|
|
3
1
|
import * as fontData from "./6847_fontdata.js";
|
|
4
2
|
import { encodeLineGrid } from "./video-filters/pixel-grid.js";
|
|
3
|
+
import { makeFast32 } from "./binary.js";
|
|
5
4
|
|
|
6
5
|
const VDISPENABLE = 1 << 0,
|
|
7
6
|
HDISPENABLE = 1 << 1,
|
|
@@ -114,7 +113,7 @@ const MODE_AG = 0x10; // graphics mode
|
|
|
114
113
|
|
|
115
114
|
// The MC6847 datasheet specifies 3.579545 MHz, but 3.638004 is used here as an
|
|
116
115
|
// empirical correction to align VSync/interrupt timing with the CPU clock.
|
|
117
|
-
// TODO
|
|
116
|
+
// TODO(#1067) revisit once full integration is testable.
|
|
118
117
|
const VdgClockMhz = 3.638004;
|
|
119
118
|
|
|
120
119
|
export class Video6847 {
|
|
@@ -127,7 +126,7 @@ export class Video6847 {
|
|
|
127
126
|
|
|
128
127
|
// 8 colours (alpha on MSB)
|
|
129
128
|
//
|
|
130
|
-
this.collook =
|
|
129
|
+
this.collook = makeFast32(
|
|
131
130
|
new Uint32Array([
|
|
132
131
|
0xff000000, // #00000000, // black
|
|
133
132
|
0xff03b91e, // #00ff00, // green
|
|
@@ -496,7 +495,7 @@ export class Video6847 {
|
|
|
496
495
|
// Render data depending on display enable state.
|
|
497
496
|
if (this.bitmapX >= 0 && this.bitmapX < 1024 && this.bitmapY < 625) {
|
|
498
497
|
{
|
|
499
|
-
// TODO
|
|
498
|
+
// TODO(#1067) Add in the INTEXT modifiers to mode (if necessary)
|
|
500
499
|
// blit into the fb32 buffer which is painted by VIDEO
|
|
501
500
|
const textMode = (mode & MODE_AG) === 0; // 0x10 is the AG bit
|
|
502
501
|
this.recordLineGrid(textMode);
|
package/src/6847_fontdata.js
CHANGED
package/src/acia.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
// Some info:
|
|
3
2
|
// http://www.playvectrex.com/designit/lecture/UP12.HTM
|
|
4
3
|
// https://books.google.com/books?id=wUecAQAAQBAJ&pg=PA431&lpg=PA431&dq=acia+tdre&source=bl&ots=mp-yF-mK-P&sig=e6aXkFRfiIOb57WZmrvdIGsCooI&hl=en&sa=X&ei=0g2fVdDyFIXT-QG8-JD4BA&ved=0CCwQ6AEwAw#v=onepage&q=acia%20tdre&f=false
|
|
@@ -52,7 +51,7 @@ export class Acia extends EventTarget {
|
|
|
52
51
|
}
|
|
53
52
|
|
|
54
53
|
reset() {
|
|
55
|
-
// TODO
|
|
54
|
+
// TODO(#1064) testing on a real beeb seems to suggest that reset also
|
|
56
55
|
// clears CR bits (i.e. things stop working until CR is rewritten
|
|
57
56
|
// with sane value). This disagrees with the datasheet.
|
|
58
57
|
// CTS and DTD are based on external inputs so leave them alone.
|
|
@@ -199,7 +198,7 @@ export class Acia extends EventTarget {
|
|
|
199
198
|
byte |= 0;
|
|
200
199
|
if (this.sr & 0x01) {
|
|
201
200
|
// Overrun.
|
|
202
|
-
// TODO
|
|
201
|
+
// TODO(#1064) this doesn't match the datasheet:
|
|
203
202
|
// "The Overrun does not occur in the Status Register until the
|
|
204
203
|
// valid character prior to Overrun has been read."
|
|
205
204
|
this.sr |= 0xa0;
|
package/src/app/app.js
CHANGED