badline 0.10.0 → 0.11.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 (78) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -0
  3. data/CLAUDE.md +5 -3
  4. data/README.md +60 -5
  5. data/doc/library.md +15 -1
  6. data/doc/pinned-behaviour.md +75 -0
  7. data/doc/snapshots.md +19 -3
  8. data/lib/badline/address_bus/fittings.rb +38 -0
  9. data/lib/badline/address_bus/pla.rb +38 -21
  10. data/lib/badline/address_bus/roms.rb +12 -5
  11. data/lib/badline/address_bus.rb +20 -2
  12. data/lib/badline/c128/banks.rb +35 -0
  13. data/lib/badline/c128/bus.rb +347 -0
  14. data/lib/badline/c128/bus_state.rb +53 -0
  15. data/lib/badline/c128/color_lines.rb +39 -0
  16. data/lib/badline/c128/cpu.rb +10 -0
  17. data/lib/badline/c128/keys.rb +35 -0
  18. data/lib/badline/c128/mmu.rb +182 -0
  19. data/lib/badline/c128/mmu_pages.rb +105 -0
  20. data/lib/badline/c128/model.rb +39 -0
  21. data/lib/badline/c128/modes.rb +48 -0
  22. data/lib/badline/c128/saved_state.rb +120 -0
  23. data/lib/badline/c128/vdc/memory.rb +54 -0
  24. data/lib/badline/c128/vdc/painter.rb +143 -0
  25. data/lib/badline/c128/vdc/raster.rb +97 -0
  26. data/lib/badline/c128/vdc/window.rb +215 -0
  27. data/lib/badline/c128/vdc.rb +268 -0
  28. data/lib/badline/c128.rb +320 -0
  29. data/lib/badline/chrout_trap.rb +3 -0
  30. data/lib/badline/computer/attachments.rb +4 -13
  31. data/lib/badline/computer/kernal_traps.rb +29 -0
  32. data/lib/badline/computer.rb +13 -8
  33. data/lib/badline/frontend/app.rb +34 -21
  34. data/lib/badline/frontend/boot.rb +31 -1
  35. data/lib/badline/frontend/controls.rb +11 -0
  36. data/lib/badline/frontend/keys.rb +28 -1
  37. data/lib/badline/frontend/machine_window.rb +16 -13
  38. data/lib/badline/frontend/menu_pages.rb +6 -1
  39. data/lib/badline/frontend/menu_ports.rb +1 -1
  40. data/lib/badline/frontend/pause_menu.rb +1 -0
  41. data/lib/badline/frontend/screen.rb +33 -8
  42. data/lib/badline/frontend/screens.rb +90 -0
  43. data/lib/badline/frontend/timeline.rb +15 -4
  44. data/lib/badline/frontend.rb +1 -0
  45. data/lib/badline/kernal_trap/file.rb +1 -1
  46. data/lib/badline/kernal_trap/layout.rb +58 -8
  47. data/lib/badline/kernal_trap/load.rb +1 -1
  48. data/lib/badline/kernal_trap/save.rb +1 -1
  49. data/lib/badline/kernal_trap/serial.rb +5 -0
  50. data/lib/badline/keyboard.rb +12 -1
  51. data/lib/badline/machine.rb +16 -7
  52. data/lib/badline/media.rb +8 -6
  53. data/lib/badline/model.rb +29 -12
  54. data/lib/badline/options/event.rb +5 -1
  55. data/lib/badline/options/family.rb +52 -0
  56. data/lib/badline/options/help.rb +5 -1
  57. data/lib/badline/options/table.rb +8 -2
  58. data/lib/badline/options/validation.rb +14 -1
  59. data/lib/badline/options.rb +20 -19
  60. data/lib/badline/roms/README +51 -0
  61. data/lib/badline/roms/c128/basic.rom +0 -0
  62. data/lib/badline/roms/c128/character.rom +0 -0
  63. data/lib/badline/roms/c128/kernal.rom +0 -0
  64. data/lib/badline/roms/c64gs.rom +0 -0
  65. data/lib/badline/roms/kernal-pet64.rom +0 -0
  66. data/lib/badline/snapshot/container.rb +2 -0
  67. data/lib/badline/snapshot/image.rb +14 -0
  68. data/lib/badline/snapshot/setup.rb +15 -10
  69. data/lib/badline/snapshot/state.rb +5 -4
  70. data/lib/badline/snapshot/vice.rb +2 -1
  71. data/lib/badline/snapshot.rb +9 -2
  72. data/lib/badline/version.rb +1 -1
  73. data/lib/badline/vic/bank.rb +2 -1
  74. data/lib/badline/vic/display_state.rb +12 -0
  75. data/lib/badline/vic/registers.rb +3 -0
  76. data/lib/badline/vic.rb +124 -9
  77. data/lib/badline.rb +1 -0
  78. metadata +27 -1
data/lib/badline/vic.rb CHANGED
@@ -24,9 +24,29 @@ module Badline
24
24
  0x8a8a8a, 0xb3ec91, 0x867ade, 0xb3b3b3
25
25
  ].freeze
26
26
 
27
+ # The sixteen colours' luminances, out of 32, as Philip Timmermann
28
+ # (Pepto) measured them on the 6569.
29
+ LUMINANCES = [0, 32, 10, 20, 12, 16, 8, 24, 12, 8, 16, 10, 15, 24, 15, 20].freeze
30
+
31
+ # The sixteen colours on a green monochrome monitor, which shows only
32
+ # their luminance, as the PET 64's does.
33
+ GREEN_PALETTE = LUMINANCES.map do |luminance|
34
+ green = luminance * 255 / 32
35
+ ((green / 4) << 16) | (green << 8) | (green / 4)
36
+ end.freeze
37
+
27
38
  attr_reader :display, :width, :height, :vic_bank, :column,
28
39
  :rasterline, :dirty_lines, :model, :region
29
40
 
41
+ # The RGB colours #display's palette indices stand for: PALETTE, or
42
+ # GREEN_PALETTE on a monochrome monitor.
43
+ attr_accessor :palette
44
+
45
+ # The line of #display the beam draws, which is the raster line unless
46
+ # the VIC-IIe's TEST bit has moved the raster counter on since the
47
+ # last vertical sync (#test_step!).
48
+ attr_reader :output_line
49
+
30
50
  # The parts a VICE snapshot reads and sets.
31
51
  attr_reader :registers, :display_state, :sequencer, :sprites, :character_buffer, :color_buffer,
32
52
  :fetch_d011
@@ -71,6 +91,11 @@ module Badline
71
91
  HOOK_DISPLAY = 16
72
92
  HOOK_LAST = 32
73
93
 
94
+ # The vertical sync starts this many lines into the vertical blank,
95
+ # and lasts VSYNC_LINES.
96
+ VSYNC_DELAY = 3
97
+ VSYNC_LINES = 3
98
+
74
99
  # On the 6569 the DMA compares fall in columns 53 and 54 and the
75
100
  # display compare in column 57. A region whose sprite fetches run later
76
101
  # moves them with the fetches (Region::Profile#sprite_cycle).
@@ -94,6 +119,7 @@ module Badline
94
119
  @iie = %i[mos8566 mos8564].include?(model)
95
120
  @core = model == :mos6569 ? :mos6569 : :mos8565
96
121
  @region = region
122
+ @palette = PALETTE
97
123
  @lightpen_extra = @core == :mos8565 ? 1 : 2
98
124
  @grey_dots = @core == :mos8565
99
125
  @delayed_fetch = @core == :mos8565
@@ -109,6 +135,7 @@ module Badline
109
135
  @height = region.lines_per_frame
110
136
  @last_column = @columns_per_line - 1
111
137
  @last_line = @height - 1
138
+ @vsync_line = region.vblank[0] + VSYNC_DELAY
112
139
  layout_columns
113
140
  @blank_columns = Array.new(@columns_per_line) { |column| Region.blanked?(column, region.hblank) }.freeze
114
141
  @blank_lines = Array.new(@height) { |line| Region.blanked?(line, region.vblank) }.freeze
@@ -137,6 +164,7 @@ module Badline
137
164
 
138
165
  @column = 0
139
166
  @rasterline = 0
167
+ @output_line = 0
140
168
 
141
169
  @character_buffer = Array.new(40, 0)
142
170
  @color_buffer = Array.new(40, 0)
@@ -153,11 +181,13 @@ module Badline
153
181
  @lp_triggered = false
154
182
  @lp_low = false
155
183
  @raster_match = false
184
+ @test_wrap = false
156
185
  end
157
186
 
158
187
  # Everything the VIC holds between cycles: the beam, the fetch and
159
188
  # g-access pipeline, the light pen and raster latches, the finished
160
- # lines, the registers and the display, sequencer and sprite logic.
189
+ # lines, on the VIC-IIe the display line and the TEST bit's wrap, the
190
+ # registers and the display, sequencer and sprite logic.
161
191
  # Whether it renders is the host's, and every line comes back dirty so
162
192
  # a front end repaints.
163
193
  def save_state(out)
@@ -168,6 +198,7 @@ module Badline
168
198
  out.int(@vic_bank.lines)
169
199
  out.blob(@character_buffer).blob(@color_buffer).booleans(@sprite_ba)
170
200
  @lines.each { |line| out.blob(line) }
201
+ out.int(@output_line).boolean(@test_wrap) if @iie
171
202
  @registers.save_state(out)
172
203
  @display_state.save_state(out)
173
204
  @sequencer.save_state(out)
@@ -179,6 +210,7 @@ module Badline
179
210
  load_beam(input)
180
211
  load_buffers(input)
181
212
  load_lines(input)
213
+ load_test_state(input) if @iie
182
214
  @registers.load_state(input)
183
215
  @display_state.load_state(input)
184
216
  @sequencer.load_state(input)
@@ -202,6 +234,7 @@ module Badline
202
234
  if @column == @columns_per_line
203
235
  finish_line!
204
236
  @column = 0
237
+ step_output_line
205
238
  @rasterline = @rasterline == @last_line ? 0 : @rasterline + 1
206
239
  check_raster_irq!(@rasterline.zero? ? @last_line : @rasterline)
207
240
  end
@@ -239,6 +272,57 @@ module Badline
239
272
  def fast? = @registers.fast?
240
273
  def test? = @registers.test?
241
274
 
275
+ # $D030's FAST and TEST bits as bits 0 and 1, which the C128 reads once
276
+ # a cycle.
277
+ def clock_bits = @registers.clock_bits
278
+
279
+ # Whether the cycle just run was one of the five refresh cycles, Bauer's
280
+ # 11-15, whose phi1 half the VIC keeps in the VIC-IIe's FAST mode.
281
+ # @column has already advanced, so it is the Bauer cycle less one.
282
+ def refresh_cycle? = @column.between?(10, 14)
283
+
284
+ # In the VIC-IIe's FAST mode the 8502 drives the bus in both halves of
285
+ # the cycle, and the VIC's accesses in the cycle just run latched what
286
+ # it put there. The g-access, or the idle access, took the byte of
287
+ # phi1. A c-access took the byte of phi2 as one made before AEC does
288
+ # (#fetch_character_data!): $ff for the video matrix, unless the CPU
289
+ # was reading or writing the VIC's own registers, and the byte's low
290
+ # nibble for colour. AEC can't follow BA down while the CPU runs at
291
+ # 2 MHz, so on a bad line it falls three cycles after FAST mode ends.
292
+ def take_cpu_bus(phi1, phi2, register_access)
293
+ slot = @g_tick
294
+ @g_data[slot] = phi1 unless @g_kind[slot] == G_BLANK
295
+ display_state = @display_state
296
+ display_state.keep_bus(@column)
297
+ return unless display_state.fetching?(@column.zero? ? @last_column : @column - 1)
298
+
299
+ vmli = display_state.vmli
300
+ @character_buffer[vmli] = register_access ? phi2 : 0xff
301
+ @color_buffer[vmli] = phi2 & 0x0f
302
+ end
303
+
304
+ # The VIC-IIe's TEST bit clocks the raster counter in every cycle, and
305
+ # the C128 calls this ahead of each cycle the bit is set in. The line's
306
+ # last cycle, whose own step it falls in with, adds nothing more. The
307
+ # counter takes two steps from the frame's last line to line 0, as line
308
+ # 0 reads the last line for its first cycle.
309
+ def test_step!
310
+ return if @column == @last_column
311
+
312
+ if @rasterline == @last_line
313
+ @test_wrap = !@test_wrap
314
+ return if @test_wrap
315
+
316
+ @rasterline = 0
317
+ @display_state.new_frame
318
+ else
319
+ @test_wrap = false
320
+ @rasterline += 1
321
+ end
322
+ @display_state.raster_step(@rasterline)
323
+ check_raster_irq!
324
+ end
325
+
242
326
  def peek(addr)
243
327
  i = offset_of(addr) % (2**6)
244
328
  case i
@@ -347,7 +431,7 @@ module Badline
347
431
 
348
432
  # Puts the beam at the start of `line`.
349
433
  def restore_line(line)
350
- @rasterline = line
434
+ @rasterline = @output_line = line
351
435
  @column = 0
352
436
  end
353
437
 
@@ -380,13 +464,11 @@ module Badline
380
464
  @dirty_lines.fill(false)
381
465
  end
382
466
 
383
- def palette = PALETTE
384
-
385
467
  private
386
468
 
387
469
  def load_beam(input)
388
470
  @column = input.int
389
- @rasterline = input.int
471
+ @rasterline = @output_line = input.int
390
472
  @cycles = input.int
391
473
  @pending_write = input.boolean?
392
474
  @g_tick = input.int
@@ -407,6 +489,13 @@ module Badline
407
489
  input.booleans_into(@sprite_ba)
408
490
  end
409
491
 
492
+ # The VIC-IIe's display line and TEST wrap, which only its TEST bit
493
+ # moves off the raster line.
494
+ def load_test_state(input)
495
+ @output_line = input.int
496
+ @test_wrap = input.boolean?
497
+ end
498
+
410
499
  # The display is the finished lines one after another.
411
500
  def load_lines(input)
412
501
  @lines.each_with_index do |line, number|
@@ -649,7 +738,7 @@ module Badline
649
738
  # or not there is a line to draw — then composite the active sprites
650
739
  # over the finished background and copy the line into the frame display.
651
740
  def finish_line!
652
- return @sprites.finish_line(nil, @sequencer.fg) if vblank? || !@render
741
+ return finish_blank_line if vblank? || !@render
653
742
 
654
743
  composite = @sprites.active?
655
744
  @sequencer.apply_color_patches
@@ -658,12 +747,38 @@ module Badline
658
747
  @sequencer.apply_border if composite
659
748
 
660
749
  colors = @sequencer.colors
661
- line = @lines[@rasterline]
750
+ output_line = @output_line
751
+ line = @lines[output_line]
662
752
  return if line == colors
663
753
 
664
754
  line[0, @width] = colors
665
- @display[@rasterline * @width, @width] = colors
666
- @dirty_lines[@rasterline] = true
755
+ @display[output_line * @width, @width] = colors
756
+ @dirty_lines[output_line] = true
757
+ end
758
+
759
+ # A blanked line paints nothing, and is never shown unless the TEST
760
+ # bit has moved the beam off the raster line, where it shows black.
761
+ def finish_blank_line
762
+ @sprites.finish_line(nil, @sequencer.fg)
763
+ return if @output_line == @rasterline || !@render
764
+
765
+ line = @output_line
766
+ @lines[line].fill(0)
767
+ @display.fill(0, line * @width, @width)
768
+ @dirty_lines[line] = true
769
+ end
770
+
771
+ # The display line the beam draws next follows the one before it, and
772
+ # a line that ends in the vertical sync puts it back on the raster
773
+ # line. Only the VIC-IIe's TEST bit moves the raster counter on between
774
+ # the two, so the lines it skips shift the picture up until the next
775
+ # sync.
776
+ def step_output_line
777
+ @output_line = if @rasterline.between?(@vsync_line, @vsync_line + VSYNC_LINES - 1)
778
+ @rasterline + 1
779
+ else
780
+ @output_line == @last_line ? 0 : @output_line + 1
781
+ end
667
782
  end
668
783
 
669
784
  def video_matrix(index)
data/lib/badline.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "badline/core"
4
+ require "badline/c128"
4
5
  require "badline/options"
5
6
  require "badline/data_path"
6
7
  require "badline/snapshot"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: badline
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Inge Jørgensen
@@ -50,6 +50,7 @@ files:
50
50
  - lib/badline.rb
51
51
  - lib/badline/address_bus.rb
52
52
  - lib/badline/address_bus/extra_sids.rb
53
+ - lib/badline/address_bus/fittings.rb
53
54
  - lib/badline/address_bus/pla.rb
54
55
  - lib/badline/address_bus/roms.rb
55
56
  - lib/badline/address_bus/saved_state.rb
@@ -70,6 +71,23 @@ files:
70
71
  - lib/badline/audio/stereo.rb
71
72
  - lib/badline/audio/terminal.rb
72
73
  - lib/badline/audio/wav.rb
74
+ - lib/badline/c128.rb
75
+ - lib/badline/c128/banks.rb
76
+ - lib/badline/c128/bus.rb
77
+ - lib/badline/c128/bus_state.rb
78
+ - lib/badline/c128/color_lines.rb
79
+ - lib/badline/c128/cpu.rb
80
+ - lib/badline/c128/keys.rb
81
+ - lib/badline/c128/mmu.rb
82
+ - lib/badline/c128/mmu_pages.rb
83
+ - lib/badline/c128/model.rb
84
+ - lib/badline/c128/modes.rb
85
+ - lib/badline/c128/saved_state.rb
86
+ - lib/badline/c128/vdc.rb
87
+ - lib/badline/c128/vdc/memory.rb
88
+ - lib/badline/c128/vdc/painter.rb
89
+ - lib/badline/c128/vdc/raster.rb
90
+ - lib/badline/c128/vdc/window.rb
73
91
  - lib/badline/cartridge.rb
74
92
  - lib/badline/cartridge/action_replay.rb
75
93
  - lib/badline/cartridge/atomic_power.rb
@@ -108,6 +126,7 @@ files:
108
126
  - lib/badline/color_memory.rb
109
127
  - lib/badline/computer.rb
110
128
  - lib/badline/computer/attachments.rb
129
+ - lib/badline/computer/kernal_traps.rb
111
130
  - lib/badline/computer/saved_state.rb
112
131
  - lib/badline/control_ports.rb
113
132
  - lib/badline/core.rb
@@ -173,6 +192,7 @@ files:
173
192
  - lib/badline/frontend/player_window.rb
174
193
  - lib/badline/frontend/scope.rb
175
194
  - lib/badline/frontend/screen.rb
195
+ - lib/badline/frontend/screens.rb
176
196
  - lib/badline/frontend/screenshot.rb
177
197
  - lib/badline/frontend/sid_history.rb
178
198
  - lib/badline/frontend/sid_view.rb
@@ -228,6 +248,7 @@ files:
228
248
  - lib/badline/model.rb
229
249
  - lib/badline/options.rb
230
250
  - lib/badline/options/event.rb
251
+ - lib/badline/options/family.rb
231
252
  - lib/badline/options/help.rb
232
253
  - lib/badline/options/option.rb
233
254
  - lib/badline/options/table.rb
@@ -247,11 +268,16 @@ files:
247
268
  - lib/badline/rom.rb
248
269
  - lib/badline/roms/README
249
270
  - lib/badline/roms/basic.rom
271
+ - lib/badline/roms/c128/basic.rom
272
+ - lib/badline/roms/c128/character.rom
273
+ - lib/badline/roms/c128/kernal.rom
274
+ - lib/badline/roms/c64gs.rom
250
275
  - lib/badline/roms/character.rom
251
276
  - lib/badline/roms/dos1541.rom
252
277
  - lib/badline/roms/eapi/LICENSE.md
253
278
  - lib/badline/roms/eapi/README
254
279
  - lib/badline/roms/eapi/eapi-am29f040-14
280
+ - lib/badline/roms/kernal-pet64.rom
255
281
  - lib/badline/roms/kernal-sx64.rom
256
282
  - lib/badline/roms/kernal.rom
257
283
  - lib/badline/roms/vic20/basic.rom