badline 0.12.0 → 0.12.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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/lib/badline/address_bus/saved_state.rb +4 -10
  4. data/lib/badline/address_bus.rb +8 -27
  5. data/lib/badline/audio/bare_player.rb +1 -1
  6. data/lib/badline/c128/bus.rb +13 -35
  7. data/lib/badline/c128/bus_state.rb +5 -5
  8. data/lib/badline/c128.rb +5 -64
  9. data/lib/badline/computer/attachments.rb +16 -45
  10. data/lib/badline/computer/common.rb +34 -0
  11. data/lib/badline/computer/kernal_traps.rb +65 -5
  12. data/lib/badline/computer/true_drives.rb +12 -23
  13. data/lib/badline/computer.rb +5 -68
  14. data/lib/badline/core.rb +2 -2
  15. data/lib/badline/cpu_port.rb +112 -0
  16. data/lib/badline/drive1541/disk.rb +14 -17
  17. data/lib/badline/drive1541/disk_state.rb +7 -15
  18. data/lib/badline/drive1581/wd1772.rb +1 -1
  19. data/lib/badline/frontend/boot.rb +8 -59
  20. data/lib/badline/kernal_trap/{file.rb → file_routine.rb} +1 -1
  21. data/lib/badline/kernal_trap/load.rb +1 -1
  22. data/lib/badline/kernal_trap/save.rb +1 -1
  23. data/lib/badline/kernal_trap.rb +1 -1
  24. data/lib/badline/machine/clocking.rb +50 -0
  25. data/lib/badline/machine.rb +58 -2
  26. data/lib/badline/media/boot_disk.rb +2 -2
  27. data/lib/badline/media/disk_list.rb +3 -3
  28. data/lib/badline/media/disk_set.rb +1 -1
  29. data/lib/badline/media/extensions.rb +33 -0
  30. data/lib/badline/media/program.rb +28 -0
  31. data/lib/badline/media/true_drive.rb +3 -2
  32. data/lib/badline/media/tune.rb +35 -0
  33. data/lib/badline/media/vic20_cartridge.rb +1 -7
  34. data/lib/badline/media/vic20_media.rb +38 -80
  35. data/lib/badline/media.rb +82 -79
  36. data/lib/badline/options/event.rb +3 -1
  37. data/lib/badline/sid.rb +1 -1
  38. data/lib/badline/snapshot/machine_state.rb +9 -1
  39. data/lib/badline/snapshot/state.rb +5 -4
  40. data/lib/badline/snapshot.rb +11 -9
  41. data/lib/badline/storage/d64_image.rb +15 -7
  42. data/lib/badline/storage/disk_image/writing.rb +2 -2
  43. data/lib/badline/storage/disk_image.rb +1 -1
  44. data/lib/badline/storage/host_directory.rb +1 -1
  45. data/lib/badline/storage/t64.rb +1 -1
  46. data/lib/badline/version.rb +1 -1
  47. data/lib/badline/vic/bank.rb +1 -1
  48. data/lib/badline/vic/border_mask.rb +1 -1
  49. data/lib/badline/vic/collisions.rb +1 -1
  50. data/lib/badline/vic/color_patches.rb +1 -1
  51. data/lib/badline/vic/display_state.rb +1 -1
  52. data/lib/badline/vic/graphics_mode.rb +1 -1
  53. data/lib/badline/vic/graphics_shifter.rb +1 -1
  54. data/lib/badline/vic/register_log.rb +1 -1
  55. data/lib/badline/vic/registers.rb +1 -1
  56. data/lib/badline/vic/sequencer.rb +1 -1
  57. data/lib/badline/vic/sequencer_output.rb +1 -1
  58. data/lib/badline/vic/sequencer_state.rb +1 -1
  59. data/lib/badline/vic/sprite/internal_bus.rb +1 -1
  60. data/lib/badline/vic/sprite/saved_state.rb +1 -1
  61. data/lib/badline/vic/sprite/shifter.rb +1 -1
  62. data/lib/badline/vic/sprite/timing.rb +1 -1
  63. data/lib/badline/vic/sprite.rb +1 -1
  64. data/lib/badline/vic/sprites.rb +1 -1
  65. data/lib/badline/vic/sprites_state.rb +1 -1
  66. data/lib/badline/vic.rb +6 -5
  67. data/lib/badline/vic20/attachments.rb +10 -80
  68. data/lib/badline/vic20/saved_state.rb +0 -30
  69. data/lib/badline/vic20.rb +1 -37
  70. metadata +8 -3
  71. data/lib/badline/cycleable.rb +0 -38
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "badline/media/extensions"
4
+
3
5
  module Badline
4
6
  class Options
5
7
  # One event of --at or --script: what to do, with its argument, once
@@ -23,7 +25,7 @@ module Badline
23
25
 
24
26
  # What insert takes: disk images, tapes and cartridges, or an .m3u
25
27
  # or .vfl list of disks or a directory to mount as device 8.
26
- INSERTABLE = %w[.d64 .d71 .d81 .g64 .t64 .tap .crt .m3u .vfl].freeze
28
+ INSERTABLE = Media::Extensions.of(%i[disk gcr archive tape cartridge disk_list])
27
29
 
28
30
  attr_reader :frame, :action, :argument
29
31
 
data/lib/badline/sid.rb CHANGED
@@ -119,7 +119,7 @@ module Badline
119
119
  # second, for #drain_samples. `filter_chunk` overrides the one the SID
120
120
  # was built with, for a machine that built its own. `clock_hz` is the
121
121
  # rate the SID's cycles are taken to run at.
122
- def record(rate:, filter_chunk: @filter_chunk, clock_hz: TimeOfDay::CLOCK_HZ)
122
+ def record(rate:, filter_chunk: @filter_chunk, clock_hz: Region::PAL.clock_hz)
123
123
  synthesize!
124
124
  catch_up
125
125
  @filter_chunk = filter_chunk
@@ -19,6 +19,10 @@ module Badline
19
19
  MAJOR = 2
20
20
  MINOR = 0
21
21
 
22
+ # The values a 64-bit integer holds once encode doubles them, which a
23
+ # native build's integers can't exceed.
24
+ VALUES = (-(1 << 62))..((1 << 62) - 1)
25
+
22
26
  module_function
23
27
 
24
28
  def section(state)
@@ -41,7 +45,11 @@ module Badline
41
45
  strings = state.strings
42
46
  numbers = [values.length, strings.length]
43
47
  strings.each { |string| numbers << string.bytesize }
44
- values.each { |value| numbers << (value.negative? ? (-2 * value) - 1 : 2 * value) }
48
+ values.each do |value|
49
+ raise RangeError, "#{value} is too large for a snapshot" unless VALUES.cover?(value)
50
+
51
+ numbers << (value.negative? ? (-2 * value) - 1 : 2 * value)
52
+ end
45
53
  index = numbers.pack("w*")
46
54
  [index.bytesize].pack("V") + index + strings.join
47
55
  end
@@ -16,10 +16,11 @@ module Badline
16
16
  # fails before anything is read into a machine. Layout 3, without the
17
17
  # KERNAL and datasette in the setup, layout 4, without the VIA shift
18
18
  # register's clock delay, layout 5, without the board in the setup,
19
- # layout 6, without the C128's Z80, and layout 7, without a 1581 on the
20
- # serial bus, still read.
21
- SCHEMA = 8
22
- READABLE = [3, 4, 5, 6, 7, SCHEMA].freeze
19
+ # layout 6, without the C128's Z80, layout 7, without a 1581 on the
20
+ # serial bus, and layout 8, with the VIC's unused cycle count and
21
+ # pending-write flag, still read.
22
+ SCHEMA = 9
23
+ READABLE = [3, 4, 5, 6, 7, 8, SCHEMA].freeze
23
24
 
24
25
  attr_reader :values, :strings
25
26
 
@@ -47,23 +47,25 @@ module Badline
47
47
  # applied and left out, yielding a line for each thing left out. A
48
48
  # snapshot that fails leaves the machine as it was.
49
49
  def restore(computer, path, &) = read(path).restore(computer, &)
50
+
51
+ # A machine's snapshots as .vsf files. Computer, Vic20 and C128 each
52
+ # include it.
53
+ module Files
54
+ def save_snapshot(path) = Snapshot.save(self, path)
55
+
56
+ def restore_snapshot(path, &) = Snapshot.restore(self, path, &)
57
+ end
50
58
  end
51
59
 
52
60
  class Computer
53
- def save_snapshot(path) = Snapshot.save(self, path)
54
-
55
- def restore_snapshot(path, &) = Snapshot.restore(self, path, &)
61
+ include Snapshot::Files
56
62
  end
57
63
 
58
64
  class Vic20
59
- def save_snapshot(path) = Snapshot.save(self, path)
60
-
61
- def restore_snapshot(path, &) = Snapshot.restore(self, path, &)
65
+ include Snapshot::Files
62
66
  end
63
67
 
64
68
  class C128
65
- def save_snapshot(path) = Snapshot.save(self, path)
66
-
67
- def restore_snapshot(path, &) = Snapshot.restore(self, path, &)
69
+ include Snapshot::Files
68
70
  end
69
71
  end
@@ -20,15 +20,23 @@ module Badline
20
20
  # The sides of a disk the image's tracks fill.
21
21
  def sides = 1
22
22
 
23
- def sectors_in(track)
24
- case track
25
- when 1..17 then 21
26
- when 18..24 then 19
27
- when 25..30 then 18
28
- else 17
29
- end
23
+ # The last track of each of the 1541's speed zones but the innermost,
24
+ # from the outermost, zone 3, in: tracks 1-17, 18-24 and 25-30, and
25
+ # zone 0 from 31 on.
26
+ ZONE_LAST_TRACKS = [17, 24, 30].freeze
27
+
28
+ # The sectors a track holds in each zone, by its number.
29
+ ZONE_SECTORS = [17, 18, 19, 21].freeze
30
+
31
+ # The speed zone a track is written in, 3 for the outermost.
32
+ def self.zone(track)
33
+ zone = 3
34
+ zone -= 1 while zone.positive? && track > ZONE_LAST_TRACKS[3 - zone]
35
+ zone
30
36
  end
31
37
 
38
+ def sectors_in(track) = ZONE_SECTORS[D64Image.zone(track)]
39
+
32
40
  private
33
41
 
34
42
  def error_tables = ERROR_TABLES
@@ -11,7 +11,7 @@ module Badline
11
11
  module Writing
12
12
  # Whether the disk takes writes: the image wasn't opened read-only
13
13
  # and the host file takes them.
14
- def writable? = !read_only? && ::File.writable?(@path)
14
+ def writable? = !read_only? && File.writable?(@path)
15
15
 
16
16
  # Writes a new file, or with `replace` writes over the one of the
17
17
  # same name in its directory entry. A name already on the disk
@@ -87,7 +87,7 @@ module Badline
87
87
  saved = [@bytes.dup, @errors&.dup]
88
88
  begin
89
89
  yield
90
- ::File.binwrite(@path, (@bytes + @errors.to_a).pack("C*"))
90
+ File.binwrite(@path, (@bytes + @errors.to_a).pack("C*"))
91
91
  rescue WriteError, SystemCallError => e
92
92
  @bytes, @errors = saved
93
93
  raise e.is_a?(WriteError) ? e : WriteError.new(WriteError::WRITE_PROTECT_ON)
@@ -46,7 +46,7 @@ module Badline
46
46
  # path, whether it is write-protected, and its bytes with the error
47
47
  # table after them.
48
48
  def save_setup(out)
49
- out.int(storage_kind).string(::File.expand_path(@path)).boolean(@read_only).blob(@bytes + @errors.to_a)
49
+ out.int(storage_kind).string(File.expand_path(@path)).boolean(@read_only).blob(@bytes + @errors.to_a)
50
50
  end
51
51
 
52
52
  # A LOAD reads only PRG files. An OPEN names the type it wants, or
@@ -19,7 +19,7 @@ module Badline
19
19
 
20
20
  # What Storage.reopen needs to open the directory again.
21
21
  def save_setup(out)
22
- out.int(HOST_DIRECTORY).string(::File.expand_path(@path))
22
+ out.int(HOST_DIRECTORY).string(File.expand_path(@path))
23
23
  end
24
24
 
25
25
  def read_file(name, **)
@@ -26,7 +26,7 @@ module Badline
26
26
  # What Storage.reopen needs to open the archive again: its path and
27
27
  # its bytes.
28
28
  def save_setup(out)
29
- out.int(T64_ARCHIVE).string(::File.expand_path(@path)).blob(@bytes)
29
+ out.int(T64_ARCHIVE).string(File.expand_path(@path)).blob(@bytes)
30
30
  end
31
31
 
32
32
  def read_file(name, **)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- VERSION = "0.12.0"
4
+ VERSION = "0.12.1"
5
5
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class VIC < Cycleable
4
+ class VIC
5
5
  # The 16K window the VIC sees into RAM, selected by CIA2 $DD00, in the
6
6
  # bank a +256K picks for it. Character
7
7
  # ROM shadows $1000-$1FFF in banks 0 and 2.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class VIC < Cycleable
4
+ class VIC
5
5
  # Border coverage per 8-pixel group, tracked as the sequencer outputs
6
6
  # a line.
7
7
  #
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class VIC < Cycleable
4
+ class VIC
5
5
  # = Sprite collisions
6
6
  #
7
7
  # The $D01E/$D01F latches and the per-pixel sprite coverage that feeds
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class VIC < Cycleable
4
+ class VIC
5
5
  # A mid-line color register write becomes visible one pixel into the
6
6
  # column emitted the cycle after the write. That emit paints the whole
7
7
  # column with the new color, so the boundary pixel is patched back to
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class VIC < Cycleable
4
+ class VIC
5
5
  # = VIC-II display state
6
6
  #
7
7
  # The bad line condition, the video counters it drives, and the DMA it
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class VIC < Cycleable
4
+ class VIC
5
5
  module GraphicsMode
6
6
  # Foreground masks depend only on the data byte, so each byte maps to a
7
7
  # precomputed frozen pattern shared by reference instead of being
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class VIC < Cycleable
4
+ class VIC
5
5
  # The graphics shift register, pixel by pixel, for the groups where a
6
6
  # mode or XSCROLL change lands (VICE x64sc `draw_graphics`). The
7
7
  # sequencer paints whole bytes everywhere else, which comes to the same
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class VIC < Cycleable
4
+ class VIC
5
5
  # Mid-line writes to the sprite registers, keyed by the pixel at which
6
6
  # they become visible. Compositing replays the line through the log, so
7
7
  # each pixel is drawn with the register values that were in effect when
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class VIC < Cycleable
4
+ class VIC
5
5
  # = VIC-II Registers
6
6
  #
7
7
  # == Sprite positions
@@ -8,7 +8,7 @@ require "badline/vic/sequencer_output"
8
8
  require "badline/vic/sequencer_state"
9
9
 
10
10
  module Badline
11
- class VIC < Cycleable
11
+ class VIC
12
12
  # = VIC-II Sequencer
13
13
  #
14
14
  # Turns fetched graphics data into output pixels.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class VIC < Cycleable
4
+ class VIC
5
5
  class Sequencer
6
6
  # Writes a column's 8-pixel group into the line buffers, through the
7
7
  # main border flip-flop and XSCROLL.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class VIC < Cycleable
4
+ class VIC
5
5
  class Sequencer
6
6
  # The sequencer's save_state and load_state.
7
7
  module SavedState
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class VIC < Cycleable
4
+ class VIC
5
5
  class Sprite
6
6
  # = InternalBus
7
7
  #
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class VIC < Cycleable
4
+ class VIC
5
5
  class Sprite
6
6
  # The sprite's save_state and load_state.
7
7
  module SavedState
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class VIC < Cycleable
4
+ class VIC
5
5
  class Sprite
6
6
  # The X comparator and the 24-bit shift register behind it: where a
7
7
  # line fires the sprite, and the pixels each firing shifts out.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class VIC < Cycleable
4
+ class VIC
5
5
  class Sprite
6
6
  # = Timing
7
7
  #
@@ -6,7 +6,7 @@ require "badline/vic/sprite/saved_state"
6
6
  require "badline/vic/sprite/timing"
7
7
 
8
8
  module Badline
9
- class VIC < Cycleable
9
+ class VIC
10
10
  # = Sprite
11
11
  #
12
12
  # The DMA/display state machine and the pixel sequencer for one sprite.
@@ -6,7 +6,7 @@ require "badline/vic/sprite"
6
6
  require "badline/vic/sprites_state"
7
7
 
8
8
  module Badline
9
- class VIC < Cycleable
9
+ class VIC
10
10
  class Sprites
11
11
  include SavedState
12
12
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Badline
4
- class VIC < Cycleable
4
+ class VIC
5
5
  class Sprites
6
6
  # The sprites' save_state and load_state.
7
7
  module SavedState
data/lib/badline/vic.rb CHANGED
@@ -7,7 +7,7 @@ require "badline/vic/sequencer"
7
7
  require "badline/vic/sprites"
8
8
 
9
9
  module Badline
10
- class VIC < Cycleable
10
+ class VIC
11
11
  include Addressable
12
12
  include IntegerHelper
13
13
 
@@ -145,7 +145,6 @@ module Badline
145
145
  @render = true
146
146
 
147
147
  power_on!
148
- super()
149
148
  end
150
149
 
151
150
  # The VIC has no reset pin, so only a power cycle brings back the
@@ -192,7 +191,7 @@ module Badline
192
191
  # a front end repaints.
193
192
  def save_state(out)
194
193
  out.marker("VIC")
195
- out.int(@column).int(@rasterline).int(@cycles).boolean(@pending_write)
194
+ out.int(@column).int(@rasterline)
196
195
  out.int(@g_tick).ints(@g_kind).int(@g_kept_char).int(@g_kept_color).boolean(@g_display)
197
196
  out.int(@fetch_d011).boolean(@lp_triggered).boolean(@lp_low).boolean(@raster_match)
198
197
  out.int(@vic_bank.lines)
@@ -469,8 +468,10 @@ module Badline
469
468
  def load_beam(input)
470
469
  @column = input.int
471
470
  @rasterline = @output_line = input.int
472
- @cycles = input.int
473
- @pending_write = input.boolean?
471
+ if input.schema < 9
472
+ input.int
473
+ input.boolean?
474
+ end
474
475
  @g_tick = input.int
475
476
  input.ints_into(@g_kind)
476
477
  @g_kept_char = input.int
@@ -3,10 +3,12 @@
3
3
  module Badline
4
4
  class Vic20
5
5
  # What plugs into the VIC-20 besides its chips: cartridge ROM in the
6
- # expansion blocks, the disk device 8 serves through the KERNAL traps,
7
- # and a true 1541 or 1581 on the serial bus.
6
+ # expansion blocks, the disk device 8 serves through the KERNAL traps
7
+ # (Computer::KernalTraps), and a true 1541 or 1581 on the serial bus
8
+ # (Computer::TrueDrives).
8
9
  module Attachments
9
- include Drive1581::Slot
10
+ include Computer::TrueDrives
11
+ include Computer::KernalTraps
10
12
 
11
13
  # The cycle by which a 1541 switched on with the machine has run its
12
14
  # DOS's reset, the RAM test and the ROM checksum, and waits on the
@@ -27,90 +29,18 @@ module Badline
27
29
  power_cycle!
28
30
  end
29
31
 
30
- # Puts the storage in device 8. Mounting again swaps the disk at any
31
- # point while the machine runs: the drive keeps its RAM and its
32
- # status.
33
- def mount(storage)
34
- return @drive.insert(storage) if @drive
35
-
36
- @drive = KernalTrap::Drive.new(storage)
37
- layout = KernalTrap::VIC20_LAYOUT
38
- load_trap = KernalTrap::Load.new(cpu:, bus:, layout:, drive: @drive)
39
- cpu.install_trap(layout.load) { load_trap.call }
40
- @serial_trap = KernalTrap::Serial.new(cpu:, bus:, layout:, drive: @drive, device: serial_trap_device).install
41
- save_trap = @save_trap = KernalTrap::Save.new(cpu:, bus:, layout:, drive: @drive)
42
- cpu.install_trap(layout.save) { save_trap.call }
43
- end
44
-
45
- # Takes device 8's mounted storage out, and with it the LOAD, SAVE and
46
- # serial traps, so the KERNAL's routines go out over the serial bus.
47
- # Mounting again starts a new drive, with its RAM cleared.
48
- def unmount
49
- return unless @drive
32
+ private
50
33
 
51
- cpu.remove_trap(KernalTrap::VIC20_LAYOUT.load)
52
- cpu.remove_trap(KernalTrap::VIC20_LAYOUT.save)
53
- @serial_trap.uninstall
54
- @serial_trap = nil
55
- @save_trap = nil
56
- @drive = nil
57
- end
34
+ # The VIC-20's KERNAL, which the traps stand in for.
35
+ def trap_layout = KernalTrap::VIC20_LAYOUT
58
36
 
59
- # Whether device 8 serves a disk or directory through the traps.
60
- def mounted? = !@drive.nil?
37
+ def trap_bus = @bus
61
38
 
62
- # Plugs in a Drive1541, which then runs alongside the VIC-20 on its own
63
- # clock and talks to it over the serial bus. The serial traps stop
64
- # answering the drive's device number, so the KERNAL's TALK, LISTEN
65
- # and byte transfers reach the drive. The LOAD and SAVE traps stay,
66
- # and still serve a mounted image.
67
- #
68
39
  # A drive that powers on with the machine takes longer to boot than
69
40
  # the KERNAL, and doesn't answer the bus until it has, so the
70
41
  # machine's on_init handlers wait for it too.
71
- def attach_drive1541(drive)
42
+ def drive1541_attached
72
43
  @init_threshold = [@init_threshold, DRIVE_BOOT_CYCLES].max if @cycles < @init_threshold
73
- @iec_bus.detach(@drive1541) if @drive1541
74
- drive.host_clock_hz = timing.clock_hz
75
- @drive1541 = drive
76
- drive.connect(@iec_bus)
77
- @serial_trap&.device = serial_trap_device
78
- end
79
-
80
- # The true drive on the serial bus: the Drive1581 ahead of the
81
- # Drive1541, or nil.
82
- def true_drive = @drive1581 || @drive1541
83
-
84
- # Plugs a Drive1541 in as device 8, in place of a 1581 there, and
85
- # returns it.
86
- def plug_true_drive
87
- detach_drive1581 if drive1581_on_device8?
88
- Drive1541.new.tap { |drive| attach_drive1541(drive) }
89
- end
90
-
91
- # Unplugs the Drive1541, leaving the serial bus with nothing on it.
92
- def detach_drive1541
93
- return unless @drive1541
94
-
95
- @iec_bus.detach(@drive1541)
96
- @drive1541 = nil
97
- @serial_trap&.device = serial_trap_device
98
- end
99
-
100
- # Records what the KERNAL prints through CHROUT (ChroutTrap).
101
- def capture_output
102
- @capture_output ||= ChroutTrap.new(cpu:, bus:, layout: KernalTrap::VIC20_LAYOUT).tap do |trap|
103
- cpu.install_trap(ChroutTrap::ADDRESS) { trap.call }
104
- end
105
- end
106
-
107
- private
108
-
109
- # The device number the serial traps answer: device 8, unless a true
110
- # drive is on the bus as device 8.
111
- def serial_trap_device
112
- device = KernalTrap::Routine::DEVICE
113
- @drive1541&.device == device || drive1581_on_device8? ? nil : device
114
44
  end
115
45
 
116
46
  # A 1581 plugged in, as a 1541 does, holds the machine's on_init
@@ -105,27 +105,6 @@ module Badline
105
105
 
106
106
  private
107
107
 
108
- # The disk device 8 serves through the traps, with its channels.
109
- def save_trap_drive(out)
110
- out.boolean(!@drive.nil?)
111
- return unless @drive
112
-
113
- @drive.save_state(out)
114
- @serial_trap.save_state(out)
115
- @save_trap.save_state(out)
116
- end
117
-
118
- def load_trap_drive(input)
119
- return unmount unless input.boolean?
120
-
121
- storage = Storage.reopen(input)
122
- unmount
123
- mount(storage)
124
- @drive.load_state(input)
125
- @serial_trap.load_state(input)
126
- @save_trap.load_state(input)
127
- end
128
-
129
108
  # A true 1541 on the serial bus, with its device number.
130
109
  def save_drive1541(out)
131
110
  out.boolean(!@drive1541.nil?)
@@ -135,15 +114,6 @@ module Badline
135
114
  @drive1541.save_state(out)
136
115
  end
137
116
 
138
- def load_drive1541(input)
139
- return detach_drive1541 unless input.boolean?
140
-
141
- device = input.int
142
- detach_drive1541 if @drive1541 && @drive1541.device != device
143
- attach_drive1541(Drive1541.new(device:)) unless @drive1541
144
- @drive1541.load_state(input)
145
- end
146
-
147
117
  def check_ram(ram)
148
118
  return if ram == @ram_configuration
149
119
 
data/lib/badline/vic20.rb CHANGED
@@ -23,6 +23,7 @@ module Badline
23
23
  class Vic20
24
24
  include IntegerHelper
25
25
  include KeyboardBuffer
26
+ include Machine::Clocking
26
27
  include Attachments
27
28
  include PortWiring
28
29
  include SavedState
@@ -33,10 +34,6 @@ module Badline
33
34
  # The RAM expansion it was built with, a key of Bus::RAM_CONFIGURATIONS.
34
35
  attr_reader :ram_configuration
35
36
 
36
- # The path of the disk or directory device 8 serves through the traps
37
- # (Attachments), or an empty one.
38
- def mounted_path = @drive.nil? ? "" : @drive.path
39
-
40
37
  def ram = @bus.ram
41
38
 
42
39
  def family = :vic20
@@ -100,31 +97,6 @@ module Badline
100
97
  @cycles += 1
101
98
  end
102
99
 
103
- # Runs `count` cycles, one #cycle! after another.
104
- def run_cycles(count)
105
- i = 0
106
- while i < count
107
- cycle!
108
- i += 1
109
- end
110
- end
111
-
112
- # Runs cycles until the block returns true or the cycle count passes
113
- # `limit`, checking before each cycle.
114
- def run_until(limit)
115
- cycle! until yield || @cycles > limit
116
- end
117
-
118
- # Runs the block once the KERNAL has booted (see init_threshold), or
119
- # now if it has.
120
- def on_init(&block)
121
- if @cycles < @init_threshold
122
- @init_handlers << block
123
- else
124
- block.call
125
- end
126
- end
127
-
128
100
  # The chip whose #display a front end shows.
129
101
  def video = @vic
130
102
 
@@ -192,10 +164,6 @@ module Badline
192
164
  reset!
193
165
  end
194
166
 
195
- def inspect
196
- "#<#{self.class.name} cycles=#{@cycles} cpu=(#{@cpu.inspect})>"
197
- end
198
-
199
167
  private
200
168
 
201
169
  # The cycle by which the KERNAL has booted and BASIC printed READY,
@@ -215,9 +183,5 @@ module Badline
215
183
  @cpu.nmi = true if nmi && !@nmi_asserted
216
184
  @nmi_asserted = nmi
217
185
  end
218
-
219
- def handle_init
220
- @init_handlers.each(&:call)
221
- end
222
186
  end
223
187
  end