badline 0.15.1 → 0.16.1

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 (136) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +55 -0
  3. data/CLAUDE.md +8 -7
  4. data/README.md +128 -9
  5. data/doc/media.md +9 -0
  6. data/doc/pinned-behaviour.md +67 -0
  7. data/doc/snapshot-format.md +215 -18
  8. data/doc/snapshots.md +55 -0
  9. data/lib/badline/c64/common.rb +1 -1
  10. data/lib/badline/chips/crtc/keyed_state.rb +46 -0
  11. data/lib/badline/chips/crtc.rb +163 -0
  12. data/lib/badline/chips/pia/control_lines.rb +138 -0
  13. data/lib/badline/chips/pia/keyed_parts.rb +56 -0
  14. data/lib/badline/chips/pia.rb +138 -0
  15. data/lib/badline/chips/vic/register_log.rb +1 -4
  16. data/lib/badline/core.rb +3 -0
  17. data/lib/badline/drives/ieee_bus.rb +74 -0
  18. data/lib/badline/drives/model1551/cable.rb +5 -2
  19. data/lib/badline/drives/model1551/tia.rb +13 -34
  20. data/lib/badline/drives/model1551.rb +26 -4
  21. data/lib/badline/drives/model2031/ieee_port.rb +133 -0
  22. data/lib/badline/drives/model2031/keyed_state.rb +66 -0
  23. data/lib/badline/drives/model2031/parts.rb +25 -0
  24. data/lib/badline/drives/model2031.rb +92 -0
  25. data/lib/badline/drives.rb +1 -0
  26. data/lib/badline/frontend/app.rb +1 -1
  27. data/lib/badline/frontend/controls.rb +23 -3
  28. data/lib/badline/frontend/gamepads.rb +10 -3
  29. data/lib/badline/frontend/keys.rb +88 -0
  30. data/lib/badline/frontend/media_slots.rb +1 -0
  31. data/lib/badline/frontend/menu/menu_dialogs.rb +2 -1
  32. data/lib/badline/frontend/menu/menu_media.rb +27 -28
  33. data/lib/badline/frontend/menu/menu_pages.rb +24 -2
  34. data/lib/badline/frontend/menu/menu_ports.rb +22 -1
  35. data/lib/badline/frontend/menu/pause_menu.rb +1 -0
  36. data/lib/badline/frontend/pet_keyboard.rb +124 -0
  37. data/lib/badline/frontend/screens.rb +2 -1
  38. data/lib/badline/frontend/timeline.rb +16 -9
  39. data/lib/badline/frontend.rb +1 -0
  40. data/lib/badline/kernal_trap/dos/writes.rb +3 -1
  41. data/lib/badline/kernal_trap/dos.rb +6 -1
  42. data/lib/badline/kernal_trap/frames.rb +117 -0
  43. data/lib/badline/kernal_trap/ieee.rb +151 -0
  44. data/lib/badline/kernal_trap/ieee_layout.rb +113 -0
  45. data/lib/badline/kernal_trap/keyed_state.rb +4 -4
  46. data/lib/badline/kernal_trap/routine.rb +3 -53
  47. data/lib/badline/kernal_trap/serial.rb +4 -102
  48. data/lib/badline/kernal_trap/steps.rb +64 -0
  49. data/lib/badline/kernal_trap.rb +4 -0
  50. data/lib/badline/machine/keyboard_buffer.rb +8 -0
  51. data/lib/badline/machine/settling.rb +1 -1
  52. data/lib/badline/machine.rb +29 -6
  53. data/lib/badline/media/extensions.rb +5 -2
  54. data/lib/badline/media/pet_media.rb +40 -0
  55. data/lib/badline/media/program.rb +14 -2
  56. data/lib/badline/media/true_drive.rb +19 -6
  57. data/lib/badline/media/vic20_media.rb +2 -2
  58. data/lib/badline/media.rb +41 -17
  59. data/lib/badline/options/family.rb +17 -6
  60. data/lib/badline/options/help.rb +23 -3
  61. data/lib/badline/options/table.rb +22 -4
  62. data/lib/badline/options/validation.rb +84 -5
  63. data/lib/badline/options.rb +47 -16
  64. data/lib/badline/pet/bus/expansion.rb +200 -0
  65. data/lib/badline/pet/bus.rb +222 -0
  66. data/lib/badline/pet/canvas.rb +97 -0
  67. data/lib/badline/pet/cassettes.rb +63 -0
  68. data/lib/badline/pet/characters.rb +32 -0
  69. data/lib/badline/pet/cpu.rb +10 -0
  70. data/lib/badline/pet/crtc_video.rb +155 -0
  71. data/lib/badline/pet/discrete_video.rb +83 -0
  72. data/lib/badline/pet/ieee_drive.rb +76 -0
  73. data/lib/badline/pet/ieee_ports.rb +77 -0
  74. data/lib/badline/pet/ieee_traps.rb +80 -0
  75. data/lib/badline/pet/keyboard_ports.rb +74 -0
  76. data/lib/badline/pet/keyed_modules.rb +88 -0
  77. data/lib/badline/pet/keyed_parts.rb +127 -0
  78. data/lib/badline/pet/keyed_state.rb +42 -0
  79. data/lib/badline/pet/model.rb +163 -0
  80. data/lib/badline/pet/rom_sets.rb +89 -0
  81. data/lib/badline/pet/sound.rb +128 -0
  82. data/lib/badline/pet/via.rb +10 -0
  83. data/lib/badline/pet/via_ports.rb +19 -0
  84. data/lib/badline/pet.rb +244 -0
  85. data/lib/badline/plus4/keyed_state.rb +5 -3
  86. data/lib/badline/plus4/tcbm_drive.rb +14 -0
  87. data/lib/badline/plus4.rb +1 -1
  88. data/lib/badline/roms/README +169 -0
  89. data/lib/badline/roms/dos2031.rom +0 -0
  90. data/lib/badline/roms/pet/basic1.rom +0 -0
  91. data/lib/badline/roms/pet/basic2.rom +0 -0
  92. data/lib/badline/roms/pet/basic4.rom +0 -0
  93. data/lib/badline/roms/pet/characters-din.rom +0 -0
  94. data/lib/badline/roms/pet/characters1.rom +0 -0
  95. data/lib/badline/roms/pet/characters2.rom +0 -0
  96. data/lib/badline/roms/pet/editor1.rom +0 -0
  97. data/lib/badline/roms/pet/editor2-b.rom +0 -0
  98. data/lib/badline/roms/pet/editor2-n.rom +0 -0
  99. data/lib/badline/roms/pet/editor4-40-n-50hz.rom +0 -0
  100. data/lib/badline/roms/pet/editor4-40-n-60hz.rom +0 -0
  101. data/lib/badline/roms/pet/editor4-80-b-50hz-0283.rom +0 -0
  102. data/lib/badline/roms/pet/editor4-80-b-50hz-8296.rom +0 -0
  103. data/lib/badline/roms/pet/editor4-80-b-50hz.rom +0 -0
  104. data/lib/badline/roms/pet/editor4-80-b-60hz.rom +0 -0
  105. data/lib/badline/roms/pet/editor4-b.rom +0 -0
  106. data/lib/badline/roms/pet/editor4-n.rom +0 -0
  107. data/lib/badline/roms/pet/kernal1.rom +0 -0
  108. data/lib/badline/roms/pet/kernal2.rom +0 -0
  109. data/lib/badline/roms/pet/kernal4.rom +0 -0
  110. data/lib/badline/snapshot/container.rb +6 -1
  111. data/lib/badline/snapshot/field_doc/markdown.rb +1 -1
  112. data/lib/badline/snapshot/field_doc.rb +17 -3
  113. data/lib/badline/snapshot/image.rb +28 -10
  114. data/lib/badline/snapshot/pet_setup.rb +88 -0
  115. data/lib/badline/snapshot/storage_setup.rb +7 -1
  116. data/lib/badline/snapshot/vice/pet.rb +117 -0
  117. data/lib/badline/snapshot/vice/pet_cpu.rb +67 -0
  118. data/lib/badline/snapshot/vice/pet_crtc.rb +246 -0
  119. data/lib/badline/snapshot/vice/pet_mem.rb +93 -0
  120. data/lib/badline/snapshot/vice/pet_pias.rb +56 -0
  121. data/lib/badline/snapshot/vice/pet_restore.rb +150 -0
  122. data/lib/badline/snapshot/vice/pet_via.rb +164 -0
  123. data/lib/badline/snapshot/vice.rb +1 -0
  124. data/lib/badline/snapshot.rb +9 -5
  125. data/lib/badline/storage/d80_image.rb +48 -0
  126. data/lib/badline/storage/d82_image.rb +21 -0
  127. data/lib/badline/storage/tap.rb +16 -3
  128. data/lib/badline/storage.rb +2 -0
  129. data/lib/badline/support/pet_checkpoint.rb +38 -0
  130. data/lib/badline/timing.rb +5 -4
  131. data/lib/badline/version.rb +1 -1
  132. data/lib/badline/vic20/attachments.rb +7 -2
  133. data/lib/badline/vic20/bus/keyed_state.rb +5 -4
  134. data/lib/badline/vic20/bus.rb +5 -0
  135. data/lib/badline/vic20.rb +1 -1
  136. metadata +70 -1
@@ -22,11 +22,11 @@ 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" |
@@ -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,22 +61,34 @@ 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
65
  | `sid_card` | text: none mos6581 mos8580 | Plus/4: "none" |
66
66
  | `tcbm` | bool | Plus/4: false |
67
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" or "pet/editor4-80-b-50hz-8296.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
+ | `jumpers` | text | PET: "" |
75
+ | `vertical_drive` | bool | PET: true |
68
76
 
69
77
  ## BL-RAM
70
78
 
71
- Written by the C64, VIC-20, C128, Plus/4.
79
+ Written by the C64, VIC-20, C128, Plus/4, PET.
72
80
 
73
81
  | Key | Type | Default |
74
82
  | --- | --- | --- |
75
- | `ram` | bytes | C64: 65536 values; VIC-20: 49152 values; C128: 131072 values; Plus/4: 65536 × 0 or 16384 × 0 |
83
+ | `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 |
76
84
  | `bus.low_bank` | int & 0x3 | Plus/4: 0 |
77
85
  | `bus.high_bank` | int & 0x3 | Plus/4: 0 |
78
86
  | `bus.rom_selected` | bool | Plus/4: true |
79
- | `bus.data` | byte | Plus/4: 255 |
87
+ | `bus.data` | byte | Plus/4: 255; PET: 253 |
88
+ | `screen` | bytes | PET: 2048 × 0 or 1024 × 0 or 32768 × 0 |
89
+ | `expansion.control` | byte | PET: 0 |
90
+ | `expansion.ram` | bytes | PET: 65536 × 0 |
91
+ | `expansion.user_port` | int | PET: 7 |
80
92
 
81
93
  ## BL-COLORRAM
82
94
 
@@ -89,14 +101,14 @@ Written by the C64, VIC-20, C128.
89
101
 
90
102
  ## BL-CPU
91
103
 
92
- Written by the C64, C128, Plus/4, VIC-20.
104
+ Written by the C64, C128, Plus/4, VIC-20, PET.
93
105
 
94
106
  | Key | Type | Default |
95
107
  | --- | --- | --- |
96
108
  | `port.ddr` | byte | C64: 0; C128: 0; Plus/4: 0 |
97
109
  | `port.data` | byte | C64: 0; C128: 0; Plus/4: 0 |
98
110
  | `port.floating` | byte | C64: 0; C128: 0 |
99
- | `pc` | word | C64: 64738; VIC-20: 64802; C128: 65341; Plus/4: 65526 |
111
+ | `pc` | word | C64: 64738; VIC-20: 64802; C128: 65341; Plus/4: 65526; PET: 64790 or 64824 |
100
112
  | `sp` | byte | 255 |
101
113
  | `a` | byte | 0 |
102
114
  | `x` | byte | 0 |
@@ -532,6 +544,7 @@ Written by the C64, VIC-20, Plus/4.
532
544
  | `active` | bool | C64: true |
533
545
  | `ram` | bytes | C64: 8192 × 0 |
534
546
  | `ram<N>.data` | bytes | C64: 8192 × 0 |
547
+ | `name` | text | VIC-20: "" |
535
548
  | `roms` | int | VIC-20: 0 |
536
549
  | `rom0.bytes` | bytes | VIC-20: [] |
537
550
  | `rom0.start` | word | VIC-20: 0 |
@@ -542,11 +555,11 @@ Written by the C64, VIC-20, Plus/4.
542
555
 
543
556
  ## BL-TRAPDOS
544
557
 
545
- Written by the C64.
558
+ Written by the C64, PET.
546
559
 
547
560
  | Key | Type | Default |
548
561
  | --- | --- | --- |
549
- | `storage.kind` | text: directory d64 d71 d81 t64 | "directory" |
562
+ | `storage.kind` | text: directory d64 d71 d81 t64 d80 d82 | "directory" |
550
563
  | `storage.path` | text | "" |
551
564
  | `storage.bytes` | bytes | [] |
552
565
  | `storage.read_only` | bool | false |
@@ -562,13 +575,19 @@ Written by the C64.
562
575
  | `status.error` | ints | [] |
563
576
  | `status.bytes` | bytes | [] |
564
577
  | `channels` | ints | [] |
565
- | `serial.listening` | bool | false |
566
- | `serial.talking` | bool | false |
567
- | `serial.listen_channel` | int, optional | absent |
568
- | `serial.talk_channel` | int, optional | absent |
569
- | `serial.frame` | int | 240 |
570
- | `serial.buffer` | bytes | [] |
571
- | `save.saving` | bool | false |
578
+ | `serial.listening` | bool | C64: false |
579
+ | `serial.talking` | bool | C64: false |
580
+ | `serial.listen_channel` | int, optional | C64: absent |
581
+ | `serial.talk_channel` | int, optional | C64: absent |
582
+ | `serial.frame` | int | C64: 240 |
583
+ | `serial.buffer` | bytes | C64: [] |
584
+ | `save.saving` | bool | C64: false |
585
+ | `ieee.listening` | bool | PET: false |
586
+ | `ieee.talking` | bool | PET: false |
587
+ | `ieee.listen_channel` | int, optional | PET: absent |
588
+ | `ieee.talk_channel` | int, optional | PET: absent |
589
+ | `ieee.frame` | int | PET: 240 |
590
+ | `ieee.buffer` | bytes | PET: [] |
572
591
 
573
592
  ## BL-D8
574
593
 
@@ -1243,3 +1262,181 @@ Written by the Plus/4.
1243
1262
  | `ports` | ints | [0, 0, 0] |
1244
1263
  | `directions` | ints | [0, 0, 0] |
1245
1264
  | `inputs` | ints | [255, 3, 192] |
1265
+
1266
+ ## BL-PIA1
1267
+
1268
+ Written by the PET.
1269
+
1270
+ | Key | Type | Default |
1271
+ | --- | --- | --- |
1272
+ | `ora` | byte | 0 |
1273
+ | `orb` | byte | 0 |
1274
+ | `ddra` | byte | 0 |
1275
+ | `ddrb` | byte | 0 |
1276
+ | `ca.control` | int & 0x3f | 0 |
1277
+ | `ca.c1_high` | bool | true |
1278
+ | `ca.c2_high` | bool | true |
1279
+ | `ca.c1_flag` | bool | false |
1280
+ | `ca.c2_flag` | bool | false |
1281
+ | `ca.handshake_low` | bool | false |
1282
+ | `ca.pulse` | int & 0x3 | 0 |
1283
+ | `cb.control` | int & 0x3f | 0 |
1284
+ | `cb.c1_high` | bool | true |
1285
+ | `cb.c2_high` | bool | true |
1286
+ | `cb.c1_flag` | bool | false |
1287
+ | `cb.c2_flag` | bool | false |
1288
+ | `cb.handshake_low` | bool | false |
1289
+ | `cb.pulse` | int & 0x3 | 0 |
1290
+
1291
+ ## BL-PIA2
1292
+
1293
+ Written by the PET.
1294
+
1295
+ | Key | Type | Default |
1296
+ | --- | --- | --- |
1297
+ | `ora` | byte | 0 |
1298
+ | `orb` | byte | 0 |
1299
+ | `ddra` | byte | 0 |
1300
+ | `ddrb` | byte | 0 |
1301
+ | `ca.control` | int & 0x3f | 0 |
1302
+ | `ca.c1_high` | bool | true |
1303
+ | `ca.c2_high` | bool | true |
1304
+ | `ca.c1_flag` | bool | false |
1305
+ | `ca.c2_flag` | bool | false |
1306
+ | `ca.handshake_low` | bool | false |
1307
+ | `ca.pulse` | int & 0x3 | 0 |
1308
+ | `cb.control` | int & 0x3f | 0 |
1309
+ | `cb.c1_high` | bool | true |
1310
+ | `cb.c2_high` | bool | true |
1311
+ | `cb.c1_flag` | bool | false |
1312
+ | `cb.c2_flag` | bool | false |
1313
+ | `cb.handshake_low` | bool | false |
1314
+ | `cb.pulse` | int & 0x3 | 0 |
1315
+
1316
+ ## BL-VIA
1317
+
1318
+ Written by the PET.
1319
+
1320
+ | Key | Type | Default |
1321
+ | --- | --- | --- |
1322
+ | `ora` | byte | 0 |
1323
+ | `orb` | byte | 0 |
1324
+ | `ddra` | byte | 0 |
1325
+ | `ddrb` | byte | 0 |
1326
+ | `latch_a` | byte | 255 |
1327
+ | `latch_b` | byte | 255 |
1328
+ | `acr` | byte | 0 |
1329
+ | `pcr` | byte | 0 |
1330
+ | `pb6_high` | bool | true |
1331
+ | `t<N>.counter` | word | 65535 |
1332
+ | `t1.latch` | word | 65535 |
1333
+ | `t<N>.hold` | bool | false |
1334
+ | `t1.reload` | bool | false |
1335
+ | `t<N>.armed` | bool | false |
1336
+ | `t1.pb7` | bool | true |
1337
+ | `t2.latch_low` | byte | 255 |
1338
+ | `t2.low_reload` | bool | false |
1339
+ | `t2.low_underflowed` | bool | false |
1340
+ | `t2.count_pulses` | bool | false |
1341
+ | `t2.counting_pulses` | bool | false |
1342
+ | `sr.mode` | int & 0x7 | 0 |
1343
+ | `sr.data` | byte | 0 |
1344
+ | `sr.bits` | int | 0 |
1345
+ | `sr.delay` | int | 0 |
1346
+ | `sr.clock` | bool | true |
1347
+ | `sr.cb2` | bool | true |
1348
+ | `sr.cb2_input` | bool | true |
1349
+ | `ifr.flags` | int & 0x7f | 0 |
1350
+ | `ifr.enable` | int & 0x7f | 0 |
1351
+ | `ca.control` | int & 0xf | 0 |
1352
+ | `ca.c1_high` | bool | true |
1353
+ | `ca.c2_high` | bool | true |
1354
+ | `ca.handshake_low` | bool | false |
1355
+ | `ca.pulse` | int | 0 |
1356
+ | `ca.c2_output` | bool | true |
1357
+ | `cb.control` | int & 0xf | 0 |
1358
+ | `cb.c1_high` | bool | true |
1359
+ | `cb.c2_high` | bool | true |
1360
+ | `cb.handshake_low` | bool | false |
1361
+ | `cb.pulse` | int | 0 |
1362
+ | `cb.c2_output` | bool | true |
1363
+
1364
+ ## BL-CRTC
1365
+
1366
+ Written by the PET.
1367
+
1368
+ | Key | Type | Default |
1369
+ | --- | --- | --- |
1370
+ | `registers` | bytes | 18 × 0 |
1371
+ | `selected` | int & 0x1f | 0 |
1372
+ | `column` | byte | 0 |
1373
+ | `since_hsync` | int | 0 |
1374
+ | `line` | int & 0x1f | 0 |
1375
+ | `row` | int & 0x7f | 0 |
1376
+ | `vsync_lines` | int | 16 |
1377
+ | `adjusting` | bool | false |
1378
+ | `row_display` | bool | false |
1379
+ | `column_display` | bool | true |
1380
+ | `row_start` | int & 0x3fff | 0 |
1381
+ | `address` | int & 0x3fff | 0 |
1382
+
1383
+ ## BL-VIDEO
1384
+
1385
+ Written by the PET.
1386
+
1387
+ | Key | Type | Default |
1388
+ | --- | --- | --- |
1389
+ | `displayed` | int | 0 |
1390
+ | `frame_displayed` | int | 0 |
1391
+ | `line_shown` | bool | false |
1392
+ | `y` | int | 136 |
1393
+ | `from_y` | int | 136 |
1394
+ | `to_y` | int | 136 |
1395
+ | `shown_from` | int | 36 |
1396
+ | `shown_to` | int | 37 |
1397
+ | `on_canvas` | bool | true |
1398
+ | `origin` | int | 336 |
1399
+ | `from` | int | 704 |
1400
+ | `to` | int | -704 |
1401
+ | `canvas.dots` | bytes | 192192 × 0 or 83328 × 0 |
1402
+ | `canvas.painted` | ints | 48048 × 0 or 20832 × 0 |
1403
+ | `canvas.span_from` | ints | 273 × 0 or 217 × 0 |
1404
+ | `canvas.span_to` | ints | 273 × 0 or 217 × 0 |
1405
+ | `column` | int | 0 |
1406
+ | `line` | int | 0 |
1407
+
1408
+ ## BL-TAPE1
1409
+
1410
+ Written by the PET.
1411
+
1412
+ | Key | Type | Default |
1413
+ | --- | --- | --- |
1414
+ | `playing` | bool | false |
1415
+ | `motor` | bool | false |
1416
+ | `countdown` | int | 0 |
1417
+ | `recording` | bool | false |
1418
+ | `since` | int | 0 |
1419
+ | `write_high` | bool | true |
1420
+ | `rise_at` | int | 0 |
1421
+ | `low_recorded` | bool | false |
1422
+ | `tape.bytes` | bytes | [] |
1423
+ | `tape.path` | text | "" |
1424
+ | `tape.position` | int | 0 |
1425
+
1426
+ ## BL-TAPE2
1427
+
1428
+ Written by the PET.
1429
+
1430
+ | Key | Type | Default |
1431
+ | --- | --- | --- |
1432
+ | `playing` | bool | false |
1433
+ | `motor` | bool | false |
1434
+ | `countdown` | int | 0 |
1435
+ | `recording` | bool | false |
1436
+ | `since` | int | 0 |
1437
+ | `write_high` | bool | true |
1438
+ | `rise_at` | int | 0 |
1439
+ | `low_recorded` | bool | false |
1440
+ | `tape.bytes` | bytes | [] |
1441
+ | `tape.path` | text | "" |
1442
+ | `tape.position` | int | 0 |
data/doc/snapshots.md CHANGED
@@ -140,6 +140,61 @@ 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, or on an 8296 all 32K from `$8000`,
147
+ an 8096's or 8296's 64K board with its control register and the user
148
+ port lines the 8296's RAM follows, both PIAs, the VIA, the CPU, the
149
+ CRTC on the boards that have one, the picture with where the video is
150
+ in its frame, the tapes in both datasettes with their places on them,
151
+ and the disk or directory device 8 serves through the IEEE-488 traps.
152
+ It restores into a machine of the same model with the same RAM, the
153
+ same editor frame rate, the same ROMs, which come with the model, and
154
+ an 8296's same jumpers. Its file names its machine `PET`, as xpet's do,
155
+ and holds only badline's modules, so xpet doesn't open it unless it is
156
+ saved with `--vice` (see [xpet](#xpet)).
157
+
158
+ ### xpet
159
+
160
+ A PET snapshot saved with `--vice`, or `computer.export_snapshot(path)`,
161
+ also holds xpet's modules for the CPU, the RAM with the screen RAM, or
162
+ an 8296's 32K from `$8000`, an 8096's or 8296's board and its control
163
+ register, the CRTC, both PIAs and the VIA, and the ones xpet 3.10 needs
164
+ to open the file, with nothing open on the file system drive and
165
+ nothing on the user port. The CRTC module carries the discrete boards'
166
+ video too, in xpet's terms. The file says it is in VICE's snapshot
167
+ format 1.0, the only one xpet reads.
168
+
169
+ xpet 3.10 opens those snapshots as long as its model and editor match:
170
+ `-model 2001`, `3032`, `3032B`, `4032`, `8032`, `8096` or `8296`, and
171
+ for a badline editor other than xpet's own, `-editor` naming badline's
172
+ ROM. xpet's 8296 runs the 8032's editor, 901474-04 dated 0283, so an
173
+ 8296 saved for it has to run that editor (`--editor 4-80-b-50hz-0283`),
174
+ and xpet takes the 8296's jumpers from its own settings. It keeps its
175
+ own drives and datasettes and leaves out badline's tapes and disk. Its
176
+ CRTC loses a few lines on opening any snapshot, its own too, so a
177
+ program it runs on from one finds the vertical sync a few hundred
178
+ cycles later than one it ran without stopping.
179
+
180
+ Snapshots xpet saves open in badline through the same modules: the CPU
181
+ at its instruction boundary, the RAM, the screen RAM, an 8096's or
182
+ 8296's board, the CRTC's registers and beam, both PIAs' registers and
183
+ flags, and the VIA's registers, timers and shift register. A program
184
+ badline runs on from xpet's snapshot finds the vertical sync on the
185
+ cycle xpet does, so the two run on alike, cycle for cycle. The picture
186
+ starts again with the next frame. xpet doesn't save its ROMs, which
187
+ keyboard it has or an 8296's jumpers, so the board, the RAM and the
188
+ CRTC's frame build the machine: a 2001, a 3032 for any other discrete
189
+ board, a 4032, an 8032, an 8096 or an 8296 with none of its jumpers
190
+ fitted, at 50 or 60 Hz, and an 8032, 8096 or 8296 whose CRTC lines are
191
+ 64 cycles long runs xpet's own 50 Hz editor, 901474-04 dated 0283. A
192
+ SuperPET's snapshot fails. It reports the modules it leaves out, such
193
+ as the drives, the datasettes and the keyboard, and carries on without
194
+ them. Restored into a running PET, an xpet snapshot fails for a PET
195
+ built another way, such as a 3032B, and otherwise switches the machine
196
+ off and on, keeping its tapes and the disk device 8 serves.
197
+
143
198
  ## VICE
144
199
 
145
200
  Snapshots use VICE's `.vsf` format, and badline's own modules are named
@@ -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)
@@ -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
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "badline/chips/crtc/keyed_state"
4
+
5
+ module Badline
6
+ module Chips
7
+ # The MOS 6545 CRTC, as the later PETs drive their screens with: an
8
+ # address register at even addresses selects one of eighteen registers,
9
+ # which the odd addresses write. Of them only the light pen's, R16 and
10
+ # R17, and the cursor address, R14 and R15, read back; every other read
11
+ # finds 0.
12
+ #
13
+ # Its counters run one character a cycle, and compare with the
14
+ # registers as they stand that cycle, so a write lands from the next
15
+ # character on:
16
+ #
17
+ # - The character counter runs from 0 to R0, then a line ends. The
18
+ # display shows from character 0 until the counter equals R1, and
19
+ # horizontal sync starts where it equals R2. A compare the counter has
20
+ # already passed doesn't happen that line: the display then runs on
21
+ # to the line's end.
22
+ # - The line counter (RA, five bits) counts a character row's lines. A
23
+ # row ends after the line where it equals R9; past R9 it runs on to
24
+ # 31 and wraps.
25
+ # - The row counter (seven bits) counts rows to R4. R5 more lines of
26
+ # vertical adjust follow, then the frame starts again. The display
27
+ # stops at the start of the row the counter equals R6, and comes back
28
+ # at the next frame; vertical sync starts with row R7 and lasts
29
+ # VSYNC_LINES lines.
30
+ # - The memory address (MA, fourteen bits) starts each frame at
31
+ # R12:R13 and counts one a character. Each line starts again from its
32
+ # row's start, which the last line of a row moves on to the address
33
+ # where the counter equals R1.
34
+ #
35
+ # Each displayed character goes to the output's #character with MA, RA
36
+ # and the characters since horizontal sync last started; the output
37
+ # also hears of each #hsync as it starts, each #line_end, the
38
+ # #rows_end where the display stops for the rest of the frame, and each
39
+ # #frame_start.
40
+ class CRTC
41
+ # The bits each register keeps.
42
+ MASKS = [0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xff, 0x1f, 0x7f, 0x1f,
43
+ 0x3f, 0xff, 0x3f, 0xff, 0x3f, 0xff].freeze
44
+
45
+ VSYNC_LINES = 16
46
+
47
+ attr_reader :registers, :column, :line, :row, :address
48
+
49
+ # The characters since horizontal sync last started.
50
+ attr_reader :since_hsync
51
+
52
+ # +registers+ is the register file, which the output may read too.
53
+ def initialize(output, registers: Array.new(MASKS.length, 0))
54
+ @output = output
55
+ @registers = registers
56
+ reset!
57
+ end
58
+
59
+ # The RES pin stops the counters at the start of a frame. The
60
+ # registers keep their values.
61
+ def reset!
62
+ @selected = 0
63
+ @column = 0
64
+ @since_hsync = 0
65
+ @vsync_lines = 0
66
+ start_frame
67
+ end
68
+
69
+ # Whether vertical sync is on.
70
+ def vsync? = @vsync_lines.positive?
71
+
72
+ # Whether the display shows the character the counters are at.
73
+ def display? = @row_display && @column_display
74
+
75
+ def peek(addr)
76
+ return 0 if addr.nobits?(0x01) || @selected < 14 || @selected >= MASKS.length
77
+
78
+ @registers[@selected]
79
+ end
80
+
81
+ def poke(addr, value)
82
+ if addr.nobits?(0x01)
83
+ @selected = value & 0x1f
84
+ elsif @selected < MASKS.length
85
+ @registers[@selected] = value & MASKS[@selected]
86
+ end
87
+ end
88
+
89
+ def cycle!
90
+ regs = @registers
91
+ column = @column
92
+ if column == regs[1]
93
+ @column_display = false
94
+ @row_start = @address if @line == regs[9]
95
+ end
96
+ @output.character(@address, @line, @since_hsync) if @column_display && @row_display
97
+ if column == regs[2]
98
+ @since_hsync = 1
99
+ @output.hsync
100
+ else
101
+ @since_hsync += 1
102
+ end
103
+ @address = (@address + 1) & 0x3fff
104
+ if column == regs[0]
105
+ @column = 0
106
+ end_line
107
+ else
108
+ @column = (column + 1) & 0xff
109
+ end
110
+ end
111
+
112
+ private
113
+
114
+ def end_line
115
+ @output.line_end
116
+ @vsync_lines -= 1 if @vsync_lines.positive?
117
+ @column_display = true
118
+ if @adjusting
119
+ @line += 1
120
+ @line >= @registers[5] ? start_frame : @address = @row_start
121
+ elsif @line == @registers[9]
122
+ end_row
123
+ else
124
+ @line = (@line + 1) & 0x1f
125
+ @address = @row_start
126
+ end
127
+ end
128
+
129
+ def end_row
130
+ @line = 0
131
+ if @row == @registers[4]
132
+ return start_frame if @registers[5].zero?
133
+
134
+ @adjusting = true
135
+ else
136
+ @row = (@row + 1) & 0x7f
137
+ start_row
138
+ end
139
+ @address = @row_start
140
+ end
141
+
142
+ def start_frame
143
+ @line = 0
144
+ @row = 0
145
+ @adjusting = false
146
+ @row_display = true
147
+ @column_display = true
148
+ @row_start = ((@registers[12] << 8) | @registers[13]) & 0x3fff
149
+ @address = @row_start
150
+ start_row
151
+ @output.frame_start
152
+ end
153
+
154
+ def start_row
155
+ if @row == @registers[6] && @row_display
156
+ @row_display = false
157
+ @output.rows_end
158
+ end
159
+ @vsync_lines = VSYNC_LINES if @row == @registers[7]
160
+ end
161
+ end
162
+ end
163
+ end