badline 0.15.0 → 0.16.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.
Files changed (155) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +102 -0
  3. data/CLAUDE.md +15 -7
  4. data/README.md +142 -16
  5. data/doc/media.md +19 -0
  6. data/doc/pinned-behaviour.md +67 -0
  7. data/doc/snapshot-format.md +274 -31
  8. data/doc/snapshots.md +14 -0
  9. data/exe/badline-ruby +1 -1
  10. data/lib/badline/audio/machine_player.rb +2 -14
  11. data/lib/badline/c64/common.rb +1 -1
  12. data/lib/badline/c64/true_drives.rb +13 -1
  13. data/lib/badline/c64.rb +6 -0
  14. data/lib/badline/chips/crtc/keyed_state.rb +46 -0
  15. data/lib/badline/chips/crtc.rb +163 -0
  16. data/lib/badline/chips/pia/control_lines.rb +138 -0
  17. data/lib/badline/chips/pia/keyed_parts.rb +56 -0
  18. data/lib/badline/chips/pia.rb +138 -0
  19. data/lib/badline/chips/tia.rb +16 -0
  20. data/lib/badline/core.rb +3 -0
  21. data/lib/badline/drives/datasette/keyed_state.rb +8 -3
  22. data/lib/badline/drives/engine/core.rb +6 -14
  23. data/lib/badline/drives/engine/idle.rb +42 -4
  24. data/lib/badline/drives/engine/idle_cpu.rb +18 -0
  25. data/lib/badline/drives/engine/serial_connection.rb +25 -0
  26. data/lib/badline/drives/engine/sleep.rb +1 -0
  27. data/lib/badline/drives/engine.rb +1 -0
  28. data/lib/badline/drives/ieee_bus.rb +28 -0
  29. data/lib/badline/drives/model1541/byte_ready.rb +19 -3
  30. data/lib/badline/drives/model1541/mechanism.rb +10 -1
  31. data/lib/badline/drives/model1541.rb +1 -0
  32. data/lib/badline/drives/model1551/bus.rb +138 -0
  33. data/lib/badline/drives/model1551/cable.rb +107 -0
  34. data/lib/badline/drives/model1551/cpu.rb +14 -0
  35. data/lib/badline/drives/model1551/keyed_state.rb +65 -0
  36. data/lib/badline/drives/model1551/port.rb +74 -0
  37. data/lib/badline/drives/model1551/tia.rb +71 -0
  38. data/lib/badline/drives/model1551.rb +192 -0
  39. data/lib/badline/drives/model1571.rb +1 -0
  40. data/lib/badline/drives/model1581.rb +1 -0
  41. data/lib/badline/drives.rb +1 -0
  42. data/lib/badline/frontend/app.rb +1 -1
  43. data/lib/badline/frontend/boot.rb +20 -1
  44. data/lib/badline/frontend/controls.rb +23 -3
  45. data/lib/badline/frontend/gamepads.rb +10 -3
  46. data/lib/badline/frontend/keys.rb +88 -0
  47. data/lib/badline/frontend/media_slots.rb +1 -0
  48. data/lib/badline/frontend/menu/menu_dialogs.rb +15 -6
  49. data/lib/badline/frontend/menu/menu_media.rb +96 -19
  50. data/lib/badline/frontend/menu/menu_pages.rb +25 -7
  51. data/lib/badline/frontend/menu/menu_ports.rb +22 -1
  52. data/lib/badline/frontend/menu/pause_menu.rb +1 -0
  53. data/lib/badline/frontend/pet_keyboard.rb +124 -0
  54. data/lib/badline/frontend/player/player_controller.rb +11 -4
  55. data/lib/badline/frontend/screens.rb +2 -1
  56. data/lib/badline/frontend/timeline.rb +16 -9
  57. data/lib/badline/frontend.rb +1 -0
  58. data/lib/badline/kernal_trap/dos/writes.rb +3 -1
  59. data/lib/badline/kernal_trap/dos.rb +6 -1
  60. data/lib/badline/kernal_trap/frames.rb +117 -0
  61. data/lib/badline/kernal_trap/ieee.rb +148 -0
  62. data/lib/badline/kernal_trap/ieee_layout.rb +113 -0
  63. data/lib/badline/kernal_trap/keyed_state.rb +4 -4
  64. data/lib/badline/kernal_trap/routine.rb +3 -53
  65. data/lib/badline/kernal_trap/serial.rb +4 -102
  66. data/lib/badline/kernal_trap/steps.rb +64 -0
  67. data/lib/badline/kernal_trap.rb +4 -0
  68. data/lib/badline/machine/keyboard_buffer.rb +8 -0
  69. data/lib/badline/machine/settling.rb +1 -1
  70. data/lib/badline/machine.rb +37 -11
  71. data/lib/badline/media/extensions.rb +5 -2
  72. data/lib/badline/media/pet_media.rb +40 -0
  73. data/lib/badline/media/program.rb +14 -2
  74. data/lib/badline/media/true_drive.rb +7 -5
  75. data/lib/badline/media/vic20_media.rb +2 -2
  76. data/lib/badline/media.rb +36 -16
  77. data/lib/badline/options/family.rb +17 -6
  78. data/lib/badline/options/help.rb +23 -5
  79. data/lib/badline/options/option.rb +2 -1
  80. data/lib/badline/options/table.rb +28 -4
  81. data/lib/badline/options/validation.rb +117 -14
  82. data/lib/badline/options.rb +65 -21
  83. data/lib/badline/pet/bus/expansion.rb +106 -0
  84. data/lib/badline/pet/bus.rb +204 -0
  85. data/lib/badline/pet/canvas.rb +97 -0
  86. data/lib/badline/pet/cassettes.rb +63 -0
  87. data/lib/badline/pet/characters.rb +26 -0
  88. data/lib/badline/pet/cpu.rb +10 -0
  89. data/lib/badline/pet/crtc_video.rb +142 -0
  90. data/lib/badline/pet/discrete_video.rb +83 -0
  91. data/lib/badline/pet/ieee_ports.rb +66 -0
  92. data/lib/badline/pet/ieee_traps.rb +75 -0
  93. data/lib/badline/pet/keyboard_ports.rb +74 -0
  94. data/lib/badline/pet/keyed_modules.rb +85 -0
  95. data/lib/badline/pet/keyed_parts.rb +123 -0
  96. data/lib/badline/pet/keyed_state.rb +42 -0
  97. data/lib/badline/pet/model.rb +113 -0
  98. data/lib/badline/pet/rom_sets.rb +65 -0
  99. data/lib/badline/pet/sound.rb +128 -0
  100. data/lib/badline/pet/via.rb +10 -0
  101. data/lib/badline/pet/via_ports.rb +19 -0
  102. data/lib/badline/pet.rb +226 -0
  103. data/lib/badline/plus4/acia/frames.rb +55 -0
  104. data/lib/badline/plus4/acia.rb +276 -16
  105. data/lib/badline/plus4/bus.rb +181 -45
  106. data/lib/badline/plus4/keyed_modules.rb +22 -5
  107. data/lib/badline/plus4/keyed_parts.rb +33 -4
  108. data/lib/badline/plus4/keyed_state.rb +10 -5
  109. data/lib/badline/plus4/ram_expansion.rb +145 -0
  110. data/lib/badline/plus4/sid_card.rb +95 -0
  111. data/lib/badline/plus4/sound_mix.rb +51 -0
  112. data/lib/badline/plus4/tcbm_drive.rb +134 -0
  113. data/lib/badline/plus4/user_port.rb +11 -2
  114. data/lib/badline/plus4.rb +104 -22
  115. data/lib/badline/roms/README +146 -0
  116. data/lib/badline/roms/dos1551.rom +0 -0
  117. data/lib/badline/roms/pet/basic1.rom +0 -0
  118. data/lib/badline/roms/pet/basic2.rom +0 -0
  119. data/lib/badline/roms/pet/basic4.rom +0 -0
  120. data/lib/badline/roms/pet/characters1.rom +0 -0
  121. data/lib/badline/roms/pet/characters2.rom +0 -0
  122. data/lib/badline/roms/pet/editor1.rom +0 -0
  123. data/lib/badline/roms/pet/editor2-b.rom +0 -0
  124. data/lib/badline/roms/pet/editor2-n.rom +0 -0
  125. data/lib/badline/roms/pet/editor4-40-n-50hz.rom +0 -0
  126. data/lib/badline/roms/pet/editor4-40-n-60hz.rom +0 -0
  127. data/lib/badline/roms/pet/editor4-80-b-50hz-0283.rom +0 -0
  128. data/lib/badline/roms/pet/editor4-80-b-50hz.rom +0 -0
  129. data/lib/badline/roms/pet/editor4-80-b-60hz.rom +0 -0
  130. data/lib/badline/roms/pet/editor4-b.rom +0 -0
  131. data/lib/badline/roms/pet/editor4-n.rom +0 -0
  132. data/lib/badline/roms/pet/kernal1.rom +0 -0
  133. data/lib/badline/roms/pet/kernal2.rom +0 -0
  134. data/lib/badline/roms/pet/kernal4.rom +0 -0
  135. data/lib/badline/snapshot/container.rb +2 -0
  136. data/lib/badline/snapshot/field_doc/markdown.rb +1 -1
  137. data/lib/badline/snapshot/field_doc.rb +21 -6
  138. data/lib/badline/snapshot/image.rb +14 -7
  139. data/lib/badline/snapshot/pet_setup.rb +71 -0
  140. data/lib/badline/snapshot/plus4_setup.rb +52 -10
  141. data/lib/badline/snapshot/storage_setup.rb +7 -1
  142. data/lib/badline/snapshot.rb +9 -5
  143. data/lib/badline/storage/d80_image.rb +48 -0
  144. data/lib/badline/storage/d82_image.rb +21 -0
  145. data/lib/badline/storage/g64_image.rb +1 -1
  146. data/lib/badline/storage/tap.rb +16 -3
  147. data/lib/badline/storage.rb +2 -0
  148. data/lib/badline/support/pet_checkpoint.rb +38 -0
  149. data/lib/badline/timing.rb +5 -4
  150. data/lib/badline/version.rb +1 -1
  151. data/lib/badline/vic20/attachments.rb +7 -2
  152. data/lib/badline/vic20/bus/keyed_state.rb +5 -4
  153. data/lib/badline/vic20/bus.rb +5 -0
  154. data/lib/badline/vic20.rb +1 -1
  155. metadata +69 -1
@@ -22,16 +22,16 @@ key only some of them have names them.
22
22
 
23
23
  ## BL-MACHINE
24
24
 
25
- Written by the C64, VIC-20, C128, Plus/4.
25
+ Written by the C64, VIC-20, C128, Plus/4, PET.
26
26
 
27
27
  | Key | Type | Default |
28
28
  | --- | --- | --- |
29
- | `family` | text: c64 vic20 c128 plus4 | "c64" |
29
+ | `family` | text: c64 vic20 c128 plus4 pet | "c64" |
30
30
  | `region` | text: pal ntsc ntscold drean | C64: "pal" |
31
31
  | `vic_model` | text: mos6569 mos8565 mos8566 mos8564 | C64: "mos6569" |
32
32
  | `cia_model` | text: mos6526 mos6526a | C64: "mos6526" |
33
33
  | `sid_model` | text: mos6581 mos8580 | C64: "mos6581"; C128: "mos6581" |
34
- | `ram_expansion` | text: none plus60k plus256k | C64: "none" |
34
+ | `ram_expansion` | text: none plus60k plus256k | C64: "none"; Plus/4: "none" |
35
35
  | `reu_kb` | int | C64: 0 |
36
36
  | `kernal` | text: c64 sx64 pet64 gs | C64: "c64" |
37
37
  | `datasette` | bool | C64: true |
@@ -49,7 +49,7 @@ Written by the C64, VIC-20, C128, Plus/4.
49
49
  | `ram` | text: unexpanded 3k 8k 16k 24k 32k all | VIC-20: "unexpanded" |
50
50
  | `bus.data` | byte | VIC-20: 253; C128: 255 |
51
51
  | `bus.video_data` | byte | VIC-20: 0 |
52
- | `model` | text: c128 c128ntsc c128dcr c128dcrntsc | C128: "c128"; Plus/4: "plus4" |
52
+ | `model` | text: c128 c128ntsc c128dcr c128dcrntsc | C128: "c128"; Plus/4: "plus4"; PET: "8032" |
53
53
  | `mode` | text: c64 c128 | C128: "c64" |
54
54
  | `bus.address` | word | C128: 65533 |
55
55
  | `clock_bits` | int | C128: 0 |
@@ -61,20 +61,32 @@ Written by the C64, VIC-20, C128, Plus/4.
61
61
  | `host.typist.code` | int, optional | C128: absent |
62
62
  | `host.typist.wait` | int | C128: 0 |
63
63
  | `host.typist.typing` | bool | C128: false |
64
- | `ram_kb` | int | Plus/4: 64 or 16 |
64
+ | `ram_kb` | int | Plus/4: 64 or 16; PET: 32 or 8 |
65
+ | `sid_card` | text: none mos6581 mos8580 | Plus/4: "none" |
65
66
  | `tcbm` | bool | Plus/4: false |
67
+ | `sid_card_address` | int | Plus/4: 64832 |
68
+ | `host.true_drive_model` | text: 1541 1551 | Plus/4: "1551" |
69
+ | `refresh_hz` | int | PET: 50 or 60 |
70
+ | `rom.basic` | text | PET: "pet/basic4.rom" or "pet/basic1.rom" |
71
+ | `rom.editor` | text | PET: "pet/editor4-80-b-50hz.rom" or "pet/editor1.rom" |
72
+ | `rom.kernal` | text | PET: "pet/kernal4.rom" or "pet/kernal1.rom" |
73
+ | `rom.characters` | text | PET: "pet/characters2.rom" or "pet/characters1.rom" |
74
+ | `vertical_drive` | bool | PET: true |
66
75
 
67
76
  ## BL-RAM
68
77
 
69
- Written by the C64, VIC-20, C128, Plus/4.
78
+ Written by the C64, VIC-20, C128, Plus/4, PET.
70
79
 
71
80
  | Key | Type | Default |
72
81
  | --- | --- | --- |
73
- | `ram` | bytes | C64: 65536 values; VIC-20: 49152 values; C128: 131072 values; Plus/4: 65536 × 0 or 16384 × 0 |
82
+ | `ram` | bytes | C64: 65536 values; VIC-20: 49152 values; C128: 131072 values; Plus/4: 65536 × 0 or 16384 × 0; PET: 32768 × 0 or 8192 × 0 |
74
83
  | `bus.low_bank` | int & 0x3 | Plus/4: 0 |
75
84
  | `bus.high_bank` | int & 0x3 | Plus/4: 0 |
76
85
  | `bus.rom_selected` | bool | Plus/4: true |
77
- | `bus.data` | byte | Plus/4: 255 |
86
+ | `bus.data` | byte | Plus/4: 255; PET: 253 |
87
+ | `screen` | bytes | PET: 2048 × 0 or 1024 × 0 |
88
+ | `expansion.control` | byte | PET: 0 |
89
+ | `expansion.ram` | bytes | PET: 65536 × 0 |
78
90
 
79
91
  ## BL-COLORRAM
80
92
 
@@ -87,14 +99,14 @@ Written by the C64, VIC-20, C128.
87
99
 
88
100
  ## BL-CPU
89
101
 
90
- Written by the C64, C128, Plus/4, VIC-20.
102
+ Written by the C64, C128, Plus/4, VIC-20, PET.
91
103
 
92
104
  | Key | Type | Default |
93
105
  | --- | --- | --- |
94
106
  | `port.ddr` | byte | C64: 0; C128: 0; Plus/4: 0 |
95
107
  | `port.data` | byte | C64: 0; C128: 0; Plus/4: 0 |
96
108
  | `port.floating` | byte | C64: 0; C128: 0 |
97
- | `pc` | word | C64: 64738; VIC-20: 64802; C128: 65341; Plus/4: 65526 |
109
+ | `pc` | word | C64: 64738; VIC-20: 64802; C128: 65341; Plus/4: 65526; PET: 64790 or 64824 |
98
110
  | `sp` | byte | 255 |
99
111
  | `a` | byte | 0 |
100
112
  | `x` | byte | 0 |
@@ -376,7 +388,7 @@ Written by the C64, C128.
376
388
 
377
389
  ## BL-SID
378
390
 
379
- Written by the C64, C128.
391
+ Written by the C64, C128, Plus/4.
380
392
 
381
393
  | Key | Type | Default |
382
394
  | --- | --- | --- |
@@ -424,6 +436,9 @@ Written by the C64, VIC-20, C128, Plus/4.
424
436
  | `playing` | bool | false |
425
437
  | `motor` | bool | false |
426
438
  | `countdown` | int | 0 |
439
+ | `recording` | bool | false |
440
+ | `since` | int | 0 |
441
+ | `write_high` | bool | C64: false; VIC-20: true; C128: false; Plus/4: true |
427
442
  | `rise_at` | int | 0 |
428
443
  | `low_recorded` | bool | false |
429
444
  | `tape.bytes` | bytes | [] |
@@ -432,13 +447,16 @@ Written by the C64, VIC-20, C128, Plus/4.
432
447
 
433
448
  ## BL-RAMEXP
434
449
 
435
- Written by the C64.
450
+ Written by the C64, Plus/4.
436
451
 
437
452
  | Key | Type | Default |
438
453
  | --- | --- | --- |
439
- | `d100` | byte | 0 |
440
- | `locked` | bool | false |
441
- | `bank<N>` | bytes | 65536 × 0 |
454
+ | `d100` | byte | C64: 0 |
455
+ | `locked` | bool | C64: false |
456
+ | `bank<N>` | bytes | C64: 65536 × 0 |
457
+ | `control` | byte | Plus/4: 255 |
458
+ | `csory_latch` | byte | Plus/4: 0 |
459
+ | `ram` | bytes | Plus/4: 196608 × 0 |
442
460
 
443
461
  ## BL-REU
444
462
 
@@ -524,6 +542,7 @@ Written by the C64, VIC-20, Plus/4.
524
542
  | `active` | bool | C64: true |
525
543
  | `ram` | bytes | C64: 8192 × 0 |
526
544
  | `ram<N>.data` | bytes | C64: 8192 × 0 |
545
+ | `name` | text | VIC-20: "" |
527
546
  | `roms` | int | VIC-20: 0 |
528
547
  | `rom0.bytes` | bytes | VIC-20: [] |
529
548
  | `rom0.start` | word | VIC-20: 0 |
@@ -534,11 +553,11 @@ Written by the C64, VIC-20, Plus/4.
534
553
 
535
554
  ## BL-TRAPDOS
536
555
 
537
- Written by the C64.
556
+ Written by the C64, PET.
538
557
 
539
558
  | Key | Type | Default |
540
559
  | --- | --- | --- |
541
- | `storage.kind` | text: directory d64 d71 d81 t64 | "directory" |
560
+ | `storage.kind` | text: directory d64 d71 d81 t64 d80 d82 | "directory" |
542
561
  | `storage.path` | text | "" |
543
562
  | `storage.bytes` | bytes | [] |
544
563
  | `storage.read_only` | bool | false |
@@ -554,13 +573,19 @@ Written by the C64.
554
573
  | `status.error` | ints | [] |
555
574
  | `status.bytes` | bytes | [] |
556
575
  | `channels` | ints | [] |
557
- | `serial.listening` | bool | false |
558
- | `serial.talking` | bool | false |
559
- | `serial.listen_channel` | int, optional | absent |
560
- | `serial.talk_channel` | int, optional | absent |
561
- | `serial.frame` | int | 240 |
562
- | `serial.buffer` | bytes | [] |
563
- | `save.saving` | bool | false |
576
+ | `serial.listening` | bool | C64: false |
577
+ | `serial.talking` | bool | C64: false |
578
+ | `serial.listen_channel` | int, optional | C64: absent |
579
+ | `serial.talk_channel` | int, optional | C64: absent |
580
+ | `serial.frame` | int | C64: 240 |
581
+ | `serial.buffer` | bytes | C64: [] |
582
+ | `save.saving` | bool | C64: false |
583
+ | `ieee.listening` | bool | PET: false |
584
+ | `ieee.talking` | bool | PET: false |
585
+ | `ieee.listen_channel` | int, optional | PET: absent |
586
+ | `ieee.talk_channel` | int, optional | PET: absent |
587
+ | `ieee.frame` | int | PET: 240 |
588
+ | `ieee.buffer` | bytes | PET: [] |
564
589
 
565
590
  ## BL-D8
566
591
 
@@ -568,12 +593,14 @@ Written by the C64, C128, Plus/4.
568
593
 
569
594
  | Key | Type | Default |
570
595
  | --- | --- | --- |
571
- | `model` | text: 1541 1571 1581 | C64: "1541" or "1581"; C128: "1541" or "1571"; Plus/4: "1541" |
596
+ | `model` | text: 1541 1551 1571 1581 | C64: "1541" or "1581"; C128: "1541" or "1571"; Plus/4: "1541" or "1551" |
572
597
  | `phase` | int | 0 |
573
598
  | `cycles` | int | 0 |
574
599
  | `so_pending` | bool | false |
575
600
  | `serial.host` | int | C64: 255; C128: 255; Plus/4: 0 |
576
601
  | `atn` | bool | C64: true |
602
+ | `irq_timer` | int | Plus/4: 16660 |
603
+ | `latched_byte` | byte | Plus/4: 0 |
577
604
 
578
605
  ## BL-D8-RAM
579
606
 
@@ -581,7 +608,7 @@ Written by the C64, C128, Plus/4.
581
608
 
582
609
  | Key | Type | Default |
583
610
  | --- | --- | --- |
584
- | `data` | byte | C64: 234 or 175; C128: 234; Plus/4: 234 |
611
+ | `data` | byte | C64: 234 or 175; C128: 234; Plus/4: 234 or 233 |
585
612
  | `ram` | bytes | C64: 2048 × 0 or 8192 × 0; C128: 2048 × 0; Plus/4: 2048 × 0 |
586
613
 
587
614
  ## BL-D8-VIA1
@@ -686,7 +713,7 @@ Written by the C64, C128, Plus/4.
686
713
 
687
714
  | Key | Type | Default |
688
715
  | --- | --- | --- |
689
- | `pc` | word | C64: 60064 or 44836; C128: 60064; Plus/4: 60064 |
716
+ | `pc` | word | C64: 60064 or 44836; C128: 60064; Plus/4: 60064 or 59829 |
690
717
  | `sp` | byte | 255 |
691
718
  | `a` | byte | 0 |
692
719
  | `x` | byte | 0 |
@@ -727,10 +754,10 @@ Written by the C64, C128, Plus/4.
727
754
 
728
755
  | Key | Type | Default |
729
756
  | --- | --- | --- |
730
- | `half_track` | int | C64: 35; C128: 37; Plus/4: 35 |
757
+ | `half_track` | int | C64: 35; C128: 37; Plus/4: 35 or 36 |
731
758
  | `slip` | int & 0x3 | C64: 0; C128: 2; Plus/4: 0 |
732
759
  | `side` | int | C64: 0 or 1; C128: 85; Plus/4: 0 |
733
- | `zone` | int & 0x3 | 3 |
760
+ | `zone` | int & 0x3 | C64: 3; C128: 3; Plus/4: 3 or 0 |
734
761
  | `time` | int | 0 |
735
762
  | `read_clock_in` | int | 2097152 |
736
763
  | `clocks` | int | 0 |
@@ -738,8 +765,8 @@ Written by the C64, C128, Plus/4.
738
765
  | `ones` | int | 0 |
739
766
  | `bits` | int | 0 |
740
767
  | `write_shift` | int | 0 |
741
- | `motor` | bool | C64: true or false; C128: true; Plus/4: true |
742
- | `led` | bool | true |
768
+ | `motor` | bool | C64: true or false; C128: true; Plus/4: true or false |
769
+ | `led` | bool | C64: true; C128: true; Plus/4: true or false |
743
770
  | `sync` | bool | false |
744
771
  | `byte_ready` | bool | false |
745
772
  | `byte_latched` | bool | false |
@@ -1175,6 +1202,15 @@ Written by the Plus/4.
1175
1202
  | --- | --- | --- |
1176
1203
  | `command` | byte | 0 |
1177
1204
  | `control` | byte | 0 |
1205
+ | `errors` | int & 0x7 | 0 |
1206
+ | `receiver_full` | bool | false |
1207
+ | `transmitter_empty` | bool | true |
1208
+ | `irq` | bool | false |
1209
+ | `receive_data` | byte | 0 |
1210
+ | `transmit_data` | byte | 0 |
1211
+ | `shifting` | int | -1 |
1212
+ | `transmit_remainder` | int | 0 |
1213
+ | `transmit_at` | int, optional | absent |
1178
1214
 
1179
1215
  ## BL-TIA1
1180
1216
 
@@ -1195,3 +1231,210 @@ Written by the Plus/4.
1195
1231
  | `ports` | ints | [0, 0, 0] |
1196
1232
  | `directions` | ints | [0, 0, 0] |
1197
1233
  | `inputs` | ints | [0, 0, 0] |
1234
+
1235
+ ## BL-D8-PORT
1236
+
1237
+ Written by the Plus/4.
1238
+
1239
+ | Key | Type | Default |
1240
+ | --- | --- | --- |
1241
+ | `ddr` | byte | 0 |
1242
+ | `data` | byte | 0 |
1243
+
1244
+ ## BL-D8-TIA
1245
+
1246
+ Written by the Plus/4.
1247
+
1248
+ | Key | Type | Default |
1249
+ | --- | --- | --- |
1250
+ | `ports` | ints | [0, 0, 0] |
1251
+ | `directions` | ints | [0, 0, 0] |
1252
+ | `inputs` | ints | [255, 255, 255] |
1253
+
1254
+ ## BL-D8-HOSTTIA
1255
+
1256
+ Written by the Plus/4.
1257
+
1258
+ | Key | Type | Default |
1259
+ | --- | --- | --- |
1260
+ | `ports` | ints | [0, 0, 0] |
1261
+ | `directions` | ints | [0, 0, 0] |
1262
+ | `inputs` | ints | [255, 3, 192] |
1263
+
1264
+ ## BL-PIA1
1265
+
1266
+ Written by the PET.
1267
+
1268
+ | Key | Type | Default |
1269
+ | --- | --- | --- |
1270
+ | `ora` | byte | 0 |
1271
+ | `orb` | byte | 0 |
1272
+ | `ddra` | byte | 0 |
1273
+ | `ddrb` | byte | 0 |
1274
+ | `ca.control` | int & 0x3f | 0 |
1275
+ | `ca.c1_high` | bool | true |
1276
+ | `ca.c2_high` | bool | true |
1277
+ | `ca.c1_flag` | bool | false |
1278
+ | `ca.c2_flag` | bool | false |
1279
+ | `ca.handshake_low` | bool | false |
1280
+ | `ca.pulse` | int & 0x3 | 0 |
1281
+ | `cb.control` | int & 0x3f | 0 |
1282
+ | `cb.c1_high` | bool | true |
1283
+ | `cb.c2_high` | bool | true |
1284
+ | `cb.c1_flag` | bool | false |
1285
+ | `cb.c2_flag` | bool | false |
1286
+ | `cb.handshake_low` | bool | false |
1287
+ | `cb.pulse` | int & 0x3 | 0 |
1288
+
1289
+ ## BL-PIA2
1290
+
1291
+ Written by the PET.
1292
+
1293
+ | Key | Type | Default |
1294
+ | --- | --- | --- |
1295
+ | `ora` | byte | 0 |
1296
+ | `orb` | byte | 0 |
1297
+ | `ddra` | byte | 0 |
1298
+ | `ddrb` | byte | 0 |
1299
+ | `ca.control` | int & 0x3f | 0 |
1300
+ | `ca.c1_high` | bool | true |
1301
+ | `ca.c2_high` | bool | true |
1302
+ | `ca.c1_flag` | bool | false |
1303
+ | `ca.c2_flag` | bool | false |
1304
+ | `ca.handshake_low` | bool | false |
1305
+ | `ca.pulse` | int & 0x3 | 0 |
1306
+ | `cb.control` | int & 0x3f | 0 |
1307
+ | `cb.c1_high` | bool | true |
1308
+ | `cb.c2_high` | bool | true |
1309
+ | `cb.c1_flag` | bool | false |
1310
+ | `cb.c2_flag` | bool | false |
1311
+ | `cb.handshake_low` | bool | false |
1312
+ | `cb.pulse` | int & 0x3 | 0 |
1313
+
1314
+ ## BL-VIA
1315
+
1316
+ Written by the PET.
1317
+
1318
+ | Key | Type | Default |
1319
+ | --- | --- | --- |
1320
+ | `ora` | byte | 0 |
1321
+ | `orb` | byte | 0 |
1322
+ | `ddra` | byte | 0 |
1323
+ | `ddrb` | byte | 0 |
1324
+ | `latch_a` | byte | 255 |
1325
+ | `latch_b` | byte | 255 |
1326
+ | `acr` | byte | 0 |
1327
+ | `pcr` | byte | 0 |
1328
+ | `pb6_high` | bool | true |
1329
+ | `t<N>.counter` | word | 65535 |
1330
+ | `t1.latch` | word | 65535 |
1331
+ | `t<N>.hold` | bool | false |
1332
+ | `t1.reload` | bool | false |
1333
+ | `t<N>.armed` | bool | false |
1334
+ | `t1.pb7` | bool | true |
1335
+ | `t2.latch_low` | byte | 255 |
1336
+ | `t2.low_reload` | bool | false |
1337
+ | `t2.low_underflowed` | bool | false |
1338
+ | `t2.count_pulses` | bool | false |
1339
+ | `t2.counting_pulses` | bool | false |
1340
+ | `sr.mode` | int & 0x7 | 0 |
1341
+ | `sr.data` | byte | 0 |
1342
+ | `sr.bits` | int | 0 |
1343
+ | `sr.delay` | int | 0 |
1344
+ | `sr.clock` | bool | true |
1345
+ | `sr.cb2` | bool | true |
1346
+ | `sr.cb2_input` | bool | true |
1347
+ | `ifr.flags` | int & 0x7f | 0 |
1348
+ | `ifr.enable` | int & 0x7f | 0 |
1349
+ | `ca.control` | int & 0xf | 0 |
1350
+ | `ca.c1_high` | bool | true |
1351
+ | `ca.c2_high` | bool | true |
1352
+ | `ca.handshake_low` | bool | false |
1353
+ | `ca.pulse` | int | 0 |
1354
+ | `ca.c2_output` | bool | true |
1355
+ | `cb.control` | int & 0xf | 0 |
1356
+ | `cb.c1_high` | bool | true |
1357
+ | `cb.c2_high` | bool | true |
1358
+ | `cb.handshake_low` | bool | false |
1359
+ | `cb.pulse` | int | 0 |
1360
+ | `cb.c2_output` | bool | true |
1361
+
1362
+ ## BL-CRTC
1363
+
1364
+ Written by the PET.
1365
+
1366
+ | Key | Type | Default |
1367
+ | --- | --- | --- |
1368
+ | `registers` | bytes | 18 × 0 |
1369
+ | `selected` | int & 0x1f | 0 |
1370
+ | `column` | byte | 0 |
1371
+ | `since_hsync` | int | 0 |
1372
+ | `line` | int & 0x1f | 0 |
1373
+ | `row` | int & 0x7f | 0 |
1374
+ | `vsync_lines` | int | 16 |
1375
+ | `adjusting` | bool | false |
1376
+ | `row_display` | bool | false |
1377
+ | `column_display` | bool | true |
1378
+ | `row_start` | int & 0x3fff | 0 |
1379
+ | `address` | int & 0x3fff | 0 |
1380
+
1381
+ ## BL-VIDEO
1382
+
1383
+ Written by the PET.
1384
+
1385
+ | Key | Type | Default |
1386
+ | --- | --- | --- |
1387
+ | `displayed` | int | 0 |
1388
+ | `frame_displayed` | int | 0 |
1389
+ | `line_shown` | bool | false |
1390
+ | `y` | int | 136 |
1391
+ | `from_y` | int | 136 |
1392
+ | `to_y` | int | 136 |
1393
+ | `shown_from` | int | 36 |
1394
+ | `shown_to` | int | 37 |
1395
+ | `on_canvas` | bool | true |
1396
+ | `origin` | int | 336 |
1397
+ | `from` | int | 704 |
1398
+ | `to` | int | -704 |
1399
+ | `canvas.dots` | bytes | 192192 × 0 or 83328 × 0 |
1400
+ | `canvas.painted` | ints | 48048 × 0 or 20832 × 0 |
1401
+ | `canvas.span_from` | ints | 273 × 0 or 217 × 0 |
1402
+ | `canvas.span_to` | ints | 273 × 0 or 217 × 0 |
1403
+ | `column` | int | 0 |
1404
+ | `line` | int | 0 |
1405
+
1406
+ ## BL-TAPE1
1407
+
1408
+ Written by the PET.
1409
+
1410
+ | Key | Type | Default |
1411
+ | --- | --- | --- |
1412
+ | `playing` | bool | false |
1413
+ | `motor` | bool | false |
1414
+ | `countdown` | int | 0 |
1415
+ | `recording` | bool | false |
1416
+ | `since` | int | 0 |
1417
+ | `write_high` | bool | true |
1418
+ | `rise_at` | int | 0 |
1419
+ | `low_recorded` | bool | false |
1420
+ | `tape.bytes` | bytes | [] |
1421
+ | `tape.path` | text | "" |
1422
+ | `tape.position` | int | 0 |
1423
+
1424
+ ## BL-TAPE2
1425
+
1426
+ Written by the PET.
1427
+
1428
+ | Key | Type | Default |
1429
+ | --- | --- | --- |
1430
+ | `playing` | bool | false |
1431
+ | `motor` | bool | false |
1432
+ | `countdown` | int | 0 |
1433
+ | `recording` | bool | false |
1434
+ | `since` | int | 0 |
1435
+ | `write_high` | bool | true |
1436
+ | `rise_at` | int | 0 |
1437
+ | `low_recorded` | bool | false |
1438
+ | `tape.bytes` | bytes | [] |
1439
+ | `tape.path` | text | "" |
1440
+ | `tape.position` | int | 0 |
data/doc/snapshots.md CHANGED
@@ -140,6 +140,20 @@ KERNAL and function ROMs come with the model. Its file names its machine
140
140
  doesn't open it, and badline doesn't open xplus4's. `--vice` and
141
141
  `computer.export_snapshot(path)` refuse a Plus/4.
142
142
 
143
+ ## The PET
144
+
145
+ Every PET and CBM model saves and restores the same way. A snapshot of
146
+ one holds its RAM, the screen RAM, an 8096's 64K board with its control
147
+ register, both PIAs, the VIA, the CPU, the CRTC on the boards that have
148
+ one, the picture with where the video is in its frame, the tapes in both
149
+ datasettes with their places on them, and the disk or directory device 8
150
+ serves through the IEEE-488 traps. It restores into a machine of the same
151
+ model with the same RAM, the same editor frame rate and the same ROMs,
152
+ which come with the model. Its file names its machine `PET`, as xpet's
153
+ do, and holds only badline's modules, so xpet doesn't open it, and
154
+ badline doesn't open xpet's. `--vice` and
155
+ `computer.export_snapshot(path)` refuse a PET.
156
+
143
157
  ## VICE
144
158
 
145
159
  Snapshots use VICE's `.vsf` format, and badline's own modules are named
data/exe/badline-ruby CHANGED
@@ -39,7 +39,7 @@ if options.headless?
39
39
  console = if options.player_window?
40
40
  lambda do |input:, output:|
41
41
  load_sdl
42
- Badline::Frontend::PlayerController.new(input:, output:)
42
+ Badline::Frontend::PlayerController.new(input:, output:, frames: options.frames)
43
43
  end
44
44
  else
45
45
  Badline::Audio::Console.method(:new)
@@ -19,8 +19,6 @@ module Badline
19
19
  @subtune = subtune || tune.start_subtune
20
20
  @computer = C64.new(sid_model: sid_models[0])
21
21
  @stereo = Stereo.new(@computer.address_bus, tune, sid_models)
22
- @extras = @stereo.extras
23
- @multi = !@extras.empty?
24
22
  region = @computer.region
25
23
  @frame_cycles = region.cycles_per_line * region.lines_per_frame
26
24
  @injected = false
@@ -30,7 +28,7 @@ module Badline
30
28
  def start
31
29
  @computer.on_init { inject }
32
30
  @computer.cpu.install_trap(@tune.entry_address) { begin_playing }
33
- step until @started || @computer.cycles > START_LIMIT
31
+ @computer.cycle! until @started || @computer.cycles > START_LIMIT
34
32
  end
35
33
 
36
34
  attr_reader :stereo
@@ -56,23 +54,13 @@ module Badline
56
54
  # Returns the cycles advanced.
57
55
  def frame(budget, &)
58
56
  cycles = [budget, @frame_cycles].min
59
- if @multi
60
- cycles.times { step }
61
- else
62
- cycles.times { @computer.cycle! }
63
- end
57
+ cycles.times { @computer.cycle! }
64
58
  @stereo.mix(&)
65
59
  cycles
66
60
  end
67
61
 
68
62
  private
69
63
 
70
- # The extra SIDs clock ahead of the CPU, as the machine's own does.
71
- def step
72
- @extras.each(&:cycle!) if @multi
73
- @computer.cycle!
74
- end
75
-
76
64
  def inject
77
65
  @computer.ram.write(@tune.load_address, @tune.data)
78
66
  @tune.boot_memory(subtune: @subtune).each { |address, bytes| @computer.ram.write(address, bytes) }
@@ -10,7 +10,7 @@ module Badline
10
10
  def timing
11
11
  region = address_bus.region
12
12
  Timing.new(clock_hz: region.clock_hz, cycles_per_line: region.cycles_per_line,
13
- lines_per_frame: region.lines_per_frame, crop: region.crop, pixel_width: 1)
13
+ lines_per_frame: region.lines_per_frame, crop: region.crop, pixel_width: 1, dots: 1)
14
14
  end
15
15
 
16
16
  def load_prg(data)
@@ -9,7 +9,7 @@ module Badline
9
9
  include Drives::Model1581::Slot
10
10
 
11
11
  # The true drive models a snapshot names.
12
- DRIVE_MODELS = %w[1541 1571 1581].freeze
12
+ DRIVE_MODELS = %w[1541 1551 1571 1581].freeze
13
13
 
14
14
  # Plugs in a Drives::Model1541, which then runs alongside the machine on its
15
15
  # own clock and talks to it over the serial bus. The serial traps stop
@@ -44,6 +44,7 @@ module Badline
44
44
  drive1581 = @drive1581
45
45
  drive1581&.save_modules(sections, "BL-D#{drive1581.device}")
46
46
  save_drive1571_modules(sections)
47
+ save_drive1551_modules(sections)
47
48
  sections
48
49
  end
49
50
 
@@ -63,6 +64,7 @@ module Badline
63
64
  detach_drive1541 unless models.include?("1541")
64
65
  detach_drive1581 unless models.include?("1581")
65
66
  detach_drive1571 unless models.include?("1571")
67
+ detach_drive1551 unless models.include?("1551")
66
68
  end
67
69
 
68
70
  # Unplugs the Drives::Model1541, leaving the serial bus with nothing on it.
@@ -91,6 +93,7 @@ module Badline
91
93
  case model
92
94
  when "1581" then load_drive1581_modules(modules, input, device)
93
95
  when "1571" then load_drive1571_modules(modules, input, device)
96
+ when "1551" then load_drive1551_modules(modules, input, device)
94
97
  else load_drive1541_modules(modules, input, device)
95
98
  end
96
99
  end
@@ -115,6 +118,15 @@ module Badline
115
118
  end
116
119
 
117
120
  def detach_drive1571 = nil
121
+
122
+ # The 264 series' 1551, which only the Plus/4 has (Plus4::TCBMDrive).
123
+ def save_drive1551_modules(sections) = sections
124
+
125
+ def load_drive1551_modules(_modules, input, _device)
126
+ input.adjust("a 1551 doesn't plug into this machine, left out")
127
+ end
128
+
129
+ def detach_drive1551 = nil
118
130
  end
119
131
  end
120
132
  end
data/lib/badline/c64.rb CHANGED
@@ -68,6 +68,7 @@ module Badline
68
68
  @cia1 = @address_bus.cia1
69
69
  @cia2 = @address_bus.cia2
70
70
  @sid = @address_bus.sid
71
+ @extra_sids = @address_bus.extra_sids
71
72
  @datasette = @address_bus.datasette
72
73
  @cycles = 0
73
74
  @nmi_asserted = false
@@ -100,6 +101,7 @@ module Badline
100
101
  @cia1.cycle!
101
102
  @cia2.cycle!
102
103
  @sid.cycle!
104
+ clock_extra_sids unless @extra_sids.empty?
103
105
  @datasette.cycle!
104
106
 
105
107
  @cpu.irq = @cia1.interrupted? || @vic.interrupted? || @reu_irq
@@ -202,6 +204,10 @@ module Badline
202
204
  reu
203
205
  end
204
206
 
207
+ # The SIDs fitted past the first, which clock ahead of the CPU as the
208
+ # first does.
209
+ def clock_extra_sids = @extra_sids.each(&:cycle!)
210
+
205
211
  # BA halts the CPU on a read cycle, and so does an REU holding the bus
206
212
  # for a transfer.
207
213
  def clock_cpu
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Badline
4
+ module Chips
5
+ class CRTC
6
+ # The CRTC's fields in a keyed snapshot module (Snapshot::Keyed): the
7
+ # registers, the one selected, and the counters: the character, the
8
+ # characters since horizontal sync, the line, the row, the lines of
9
+ # vertical sync left, whether the frame is in its vertical adjust,
10
+ # whether the row and the character show, and the memory address with
11
+ # the row's start. The output restores its own state.
12
+ module KeyedState
13
+ def save_fields(out)
14
+ out.bytes("registers", @registers).int("selected", @selected).int("column", @column)
15
+ out.int("since_hsync", @since_hsync).int("line", @line).int("row", @row).int("vsync_lines", @vsync_lines)
16
+ out.bool("adjusting", @adjusting).bool("row_display", @row_display).bool("column_display", @column_display)
17
+ out.int("row_start", @row_start).int("address", @address)
18
+ end
19
+
20
+ def load_fields(input)
21
+ input.bytes_into("registers", @registers)
22
+ MASKS.each_with_index { |mask, index| @registers[index] &= mask }
23
+ @selected = input.masked("selected", @selected, 0x1f)
24
+ @column = input.byte("column", @column)
25
+ @since_hsync = input.int("since_hsync", @since_hsync)
26
+ @line = input.masked("line", @line, 0x1f)
27
+ @row = input.masked("row", @row, 0x7f)
28
+ @vsync_lines = input.int("vsync_lines", @vsync_lines)
29
+ load_flag_fields(input)
30
+ @row_start = input.masked("row_start", @row_start, 0x3fff)
31
+ @address = input.masked("address", @address, 0x3fff)
32
+ end
33
+
34
+ private
35
+
36
+ def load_flag_fields(input)
37
+ @adjusting = input.bool("adjusting", @adjusting)
38
+ @row_display = input.bool("row_display", @row_display)
39
+ @column_display = input.bool("column_display", @column_display)
40
+ end
41
+ end
42
+
43
+ include KeyedState
44
+ end
45
+ end
46
+ end