badline 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +167 -0
- data/CLAUDE.md +217 -0
- data/CODE_OF_CONDUCT.md +92 -0
- data/CONTRIBUTING.md +51 -0
- data/README.md +224 -31
- data/doc/pinned-behaviour.md +1117 -0
- data/exe/badline +22 -2
- data/exe/badline-sid +34 -0
- data/lib/badline/address_bus.rb +88 -23
- data/lib/badline/audio/aiff.rb +36 -0
- data/lib/badline/audio/bare_player.rb +129 -0
- data/lib/badline/audio/cli.rb +133 -0
- data/lib/badline/audio/console.rb +75 -0
- data/lib/badline/audio/jukebox.rb +82 -0
- data/lib/badline/audio/machine_player.rb +57 -0
- data/lib/badline/audio/options.rb +137 -0
- data/lib/badline/audio/pcm_writer.rb +57 -0
- data/lib/badline/audio/playback.rb +108 -0
- data/lib/badline/audio/renderer.rb +85 -0
- data/lib/badline/audio/sdl_sink.rb +102 -0
- data/lib/badline/audio/wav.rb +23 -0
- data/lib/badline/audio.rb +14 -0
- data/lib/badline/cartridge/action_replay.rb +111 -0
- data/lib/badline/cartridge/atomic_power.rb +24 -0
- data/lib/badline/cartridge/bank.rb +81 -0
- data/lib/badline/cartridge/comal80.rb +48 -0
- data/lib/badline/cartridge/dinamic.rb +34 -0
- data/lib/badline/cartridge/easy_flash.rb +122 -0
- data/lib/badline/cartridge/epyx_fastload.rb +71 -0
- data/lib/badline/cartridge/final_cartridge3.rb +77 -0
- data/lib/badline/cartridge/flash.rb +265 -0
- data/lib/badline/cartridge/freezer.rb +31 -0
- data/lib/badline/cartridge/fun_play.rb +38 -0
- data/lib/badline/cartridge/g_mod2.rb +62 -0
- data/lib/badline/cartridge/game_system.rb +40 -0
- data/lib/badline/cartridge/kcs_power.rb +72 -0
- data/lib/badline/cartridge/mach5.rb +34 -0
- data/lib/badline/cartridge/magic_desk.rb +6 -3
- data/lib/badline/cartridge/ocean.rb +11 -12
- data/lib/badline/cartridge/pagefox.rb +56 -0
- data/lib/badline/cartridge/retro_replay.rb +276 -0
- data/lib/badline/cartridge/rex_utility.rb +33 -0
- data/lib/badline/cartridge/rgcd.rb +48 -0
- data/lib/badline/cartridge/simons_basic.rb +40 -0
- data/lib/badline/cartridge/standard.rb +3 -19
- data/lib/badline/cartridge/super_games.rb +36 -0
- data/lib/badline/cartridge/westermann.rb +34 -0
- data/lib/badline/cartridge/zaxxon.rb +50 -0
- data/lib/badline/cartridge.rb +131 -15
- data/lib/badline/cia/interrupt_register.rb +88 -0
- data/lib/badline/cia/serial.rb +219 -0
- data/lib/badline/cia/timer.rb +43 -31
- data/lib/badline/cia.rb +109 -74
- data/lib/badline/color_memory.rb +14 -5
- data/lib/badline/computer.rb +68 -8
- data/lib/badline/control_ports.rb +54 -9
- data/lib/badline/cpu/addressing.rb +131 -0
- data/lib/badline/cpu/microcode.rb +171 -0
- data/lib/badline/cpu/operations.rb +88 -0
- data/lib/badline/cpu/stack_operations.rb +82 -0
- data/lib/badline/cpu.rb +108 -167
- data/lib/badline/cycleable.rb +3 -0
- data/lib/badline/datasette.rb +81 -0
- data/lib/badline/debug_register.rb +28 -0
- data/lib/badline/gui/application.rb +79 -18
- data/lib/badline/gui/gamepads.rb +97 -0
- data/lib/badline/gui/joy_map.rb +15 -7
- data/lib/badline/gui.rb +1 -0
- data/lib/badline/input/mouse1351.rb +41 -0
- data/lib/badline/input/paddles.rb +36 -0
- data/lib/badline/input.rb +4 -0
- data/lib/badline/instruction_set/arithmetic.rb +16 -21
- data/lib/badline/instruction_set/bitwise.rb +17 -22
- data/lib/badline/instruction_set/branch.rb +20 -19
- data/lib/badline/instruction_set/flag.rb +7 -7
- data/lib/badline/instruction_set/illegal.rb +14 -22
- data/lib/badline/instruction_set/inc_dec.rb +8 -10
- data/lib/badline/instruction_set/stack.rb +5 -57
- data/lib/badline/instruction_set/transfer.rb +9 -9
- data/lib/badline/instruction_set.rb +9 -31
- data/lib/badline/interrupts.rb +104 -0
- data/lib/badline/joystick.rb +9 -9
- data/lib/badline/kernal_trap/channel.rb +33 -0
- data/lib/badline/kernal_trap/drive.rb +239 -0
- data/lib/badline/kernal_trap/file.rb +4 -24
- data/lib/badline/kernal_trap/load.rb +2 -2
- data/lib/badline/kernal_trap/routine.rb +34 -0
- data/lib/badline/kernal_trap/save.rb +1 -1
- data/lib/badline/kernal_trap/serial.rb +139 -0
- data/lib/badline/kernal_trap.rb +4 -0
- data/lib/badline/keyboard.rb +40 -16
- data/lib/badline/media.rb +48 -10
- data/lib/badline/roms/eapi/LICENSE.md +15 -0
- data/lib/badline/roms/eapi/README +41 -0
- data/lib/badline/roms/eapi/eapi-am29f040-14 +0 -0
- data/lib/badline/sid/decimator.rb +46 -0
- data/lib/badline/sid/envelope.rb +232 -0
- data/lib/badline/sid/filter.rb +213 -0
- data/lib/badline/sid/voice.rb +61 -0
- data/lib/badline/sid/waveform/combined.rb +126 -0
- data/lib/badline/sid/waveform/fast_forward.rb +105 -0
- data/lib/badline/sid/waveform/noise_writeback.rb +82 -0
- data/lib/badline/sid/waveform.rb +289 -0
- data/lib/badline/sid.rb +274 -7
- data/lib/badline/status.rb +32 -27
- data/lib/badline/storage/crt_file.rb +18 -2
- data/lib/badline/storage/disk_image.rb +52 -5
- data/lib/badline/storage/host_directory.rb +18 -4
- data/lib/badline/storage/sid_file.rb +274 -0
- data/lib/badline/storage/song_lengths.rb +65 -0
- data/lib/badline/storage/t64.rb +67 -0
- data/lib/badline/storage/tap.rb +68 -0
- data/lib/badline/storage.rb +19 -0
- data/lib/badline/time_of_day.rb +105 -52
- data/lib/badline/version.rb +1 -1
- data/lib/badline/vic/bank.rb +14 -6
- data/lib/badline/vic/border_mask.rb +76 -0
- data/lib/badline/vic/collisions.rb +104 -0
- data/lib/badline/vic/color_patches.rb +33 -0
- data/lib/badline/vic/display_state.rb +92 -29
- data/lib/badline/vic/graphics_mode.rb +78 -53
- data/lib/badline/vic/graphics_shifter.rb +140 -0
- data/lib/badline/vic/register_log.rb +63 -0
- data/lib/badline/vic/registers.rb +3 -0
- data/lib/badline/vic/sequencer.rb +163 -137
- data/lib/badline/vic/sequencer_output.rb +116 -0
- data/lib/badline/vic/sprite/internal_bus.rb +49 -0
- data/lib/badline/vic/sprite/shifter.rb +129 -0
- data/lib/badline/vic/sprite.rb +275 -65
- data/lib/badline/vic/sprites.rb +220 -58
- data/lib/badline/vic.rb +373 -49
- data/lib/badline.rb +5 -0
- data/vendor/.gitkeep +0 -0
- metadata +103 -4
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
class Cartridge
|
|
5
|
+
# Retro Replay: an Am29F010 flash chip of two 64K halves, each eight 8K
|
|
6
|
+
# ROM banks, and four 8K RAM banks, with the Action Replay's register at
|
|
7
|
+
# $DE00 and an extended one at $DE01. The Nordic Replay (subtype 1) adds
|
|
8
|
+
# the Nordic Power configuration. The clock port isn't there.
|
|
9
|
+
#
|
|
10
|
+
# CRT banks 0-7 are the chip's upper half and banks 8-15 its lower half.
|
|
11
|
+
# The cartridge runs from the upper half, or from the lower one with the
|
|
12
|
+
# bank jumper set.
|
|
13
|
+
#
|
|
14
|
+
# $DE00 writes:
|
|
15
|
+
# bit 0 pulls GAME low
|
|
16
|
+
# bit 1 releases EXROM
|
|
17
|
+
# bit 2 switches the registers off until the next freeze or reset
|
|
18
|
+
# bits 3-4,7 bank
|
|
19
|
+
# bit 5 RAM instead of ROM
|
|
20
|
+
# bit 6 acknowledges a freeze: until then the cartridge stays in
|
|
21
|
+
# Ultimax mode with nothing at ROML
|
|
22
|
+
#
|
|
23
|
+
# $DE01 writes the bank again, and once only AllowBank (bit 1), which
|
|
24
|
+
# banks the RAM in I/O as well, NoFreeze (bit 2) and the REU-compatible
|
|
25
|
+
# map (bit 6), which moves the I/O RAM from I/O 2 to I/O 1 above $DE01.
|
|
26
|
+
# $DE00 and $DE01 read back the bank, the write-once bits and the freeze
|
|
27
|
+
# button.
|
|
28
|
+
#
|
|
29
|
+
# The VIC sees Ultimax mode only from a freeze to the next $DE00 write.
|
|
30
|
+
#
|
|
31
|
+
# The RAM at ROML takes writes only in Ultimax mode, except on the Nordic
|
|
32
|
+
# Replay. With RAM and only EXROM released ($22) the Retro Replay maps
|
|
33
|
+
# nothing at ROML and keeps the RAM in I/O, and the Nordic Replay maps
|
|
34
|
+
# the ROM at ROML and the RAM at ROMH, as the Nordic Power does. Frozen
|
|
35
|
+
# in that configuration, the Nordic Replay maps the RAM at $A000.
|
|
36
|
+
#
|
|
37
|
+
# The flash jumper puts the cartridge in flash mode, which starts with
|
|
38
|
+
# the cartridge switched off ($02) and has no freeze. $DE00 selects 8K
|
|
39
|
+
# mode unless it switches the cartridge off, and writes to ROML reach
|
|
40
|
+
# the flash, and the C64's RAM underneath, or the RAM when selected.
|
|
41
|
+
# $DE01 isn't write-once and has no REU-compatible map, and with the
|
|
42
|
+
# bank jumper set its bit 5 clear selects the other half of the flash,
|
|
43
|
+
# until the next $DE00 write. $DE00 reads the flash jumper in bit 0 and
|
|
44
|
+
# the half in bit 5.
|
|
45
|
+
class RetroReplay < Cartridge
|
|
46
|
+
include Freezer
|
|
47
|
+
|
|
48
|
+
CONTROL_MODES = %i[rom8k rom16k off ultimax].freeze
|
|
49
|
+
IO1_PAGE = 0x1e00
|
|
50
|
+
IO2_PAGE = 0x1f00
|
|
51
|
+
|
|
52
|
+
attr_reader :flash
|
|
53
|
+
|
|
54
|
+
def initialize(crt, flash_jumper: false, bank_jumper: false)
|
|
55
|
+
@nordic = crt.subtype == 1
|
|
56
|
+
@flash_jumper = flash_jumper
|
|
57
|
+
@bank_jumper = bank_jumper
|
|
58
|
+
super(crt)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def clock=(clock)
|
|
62
|
+
super
|
|
63
|
+
@flash.clock = clock
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def connect(ram:, open_bus:)
|
|
67
|
+
super
|
|
68
|
+
@through.each { |b| b.backing = ram }
|
|
69
|
+
configure
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def readable_io_pages
|
|
73
|
+
[0xde, 0xdf]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def peek(addr)
|
|
77
|
+
return open_bus(addr) unless @active
|
|
78
|
+
|
|
79
|
+
addr < 0xdf00 ? io1_peek(addr) : io2_peek(addr)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def poke(addr, value)
|
|
83
|
+
return unless @active
|
|
84
|
+
|
|
85
|
+
low = addr & 0xff
|
|
86
|
+
if addr >= 0xdf00
|
|
87
|
+
io_ram[IO2_PAGE | low] = value if io_ram_writable?(!@reu_mapping)
|
|
88
|
+
elsif low > 1
|
|
89
|
+
io_ram[IO1_PAGE | low] = value if io_ram_writable?(@reu_mapping)
|
|
90
|
+
else
|
|
91
|
+
low.zero? ? control(value) : extended_control(value)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def phi1_ultimax?
|
|
96
|
+
@phi1_ultimax
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def ultimax_a000
|
|
100
|
+
@isolated[ram_view_bank] if @nordic && @ram_at_a000 && @frozen
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Reset leaves the write-once bits of $DE01 as they are.
|
|
104
|
+
def reset
|
|
105
|
+
@active = true
|
|
106
|
+
@frozen = false
|
|
107
|
+
self.nmi = false
|
|
108
|
+
control(@flash_jumper ? 0x02 : 0x00)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def freeze!
|
|
112
|
+
@active = @frozen = @phi1_ultimax = true
|
|
113
|
+
@ram_enabled = false
|
|
114
|
+
@bank = 0
|
|
115
|
+
@config = :ultimax
|
|
116
|
+
configure
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
private
|
|
120
|
+
|
|
121
|
+
def freeze_allowed?
|
|
122
|
+
!@no_freeze && !@flash_jumper
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def status
|
|
126
|
+
((@bank & 0x03) << 3) | ((@bank & 0x04) << 5) | ((@bank & 0x08) << 2) | (@flash_jumper ? 0x01 : 0) |
|
|
127
|
+
(@allow_bank ? 0x02 : 0) | (button_pressed? ? 0x04 : 0) | (@reu_mapping ? 0x40 : 0)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def io1_peek(addr)
|
|
131
|
+
return status if (addr & 0xff) < 2
|
|
132
|
+
return open_bus(addr) unless @reu_mapping && !@frozen
|
|
133
|
+
|
|
134
|
+
io_window(addr, IO1_PAGE)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def io2_peek(addr)
|
|
138
|
+
return open_bus(addr) if @reu_mapping || @frozen
|
|
139
|
+
|
|
140
|
+
io_window(addr, IO2_PAGE)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# The I/O RAM when selected, otherwise the ROM, which 16K and Ultimax
|
|
144
|
+
# mode leave out.
|
|
145
|
+
def io_window(addr, page)
|
|
146
|
+
if @ram_enabled || @ram_at_a000
|
|
147
|
+
io_ram[page | (addr & 0xff)]
|
|
148
|
+
elsif @config == :rom8k || @config == :off
|
|
149
|
+
@rom.peek(addr)
|
|
150
|
+
else
|
|
151
|
+
open_bus(addr)
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def io_ram
|
|
156
|
+
@ram_data[ram_view_bank]
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def io_ram_writable?(window)
|
|
160
|
+
window && !@frozen && (@ram_enabled || (@nordic && @ram_at_a000))
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def ram_view_bank
|
|
164
|
+
@allow_bank ? @bank & 0x03 : 0
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def control(value)
|
|
168
|
+
value = flash_mode_control(value)
|
|
169
|
+
@bank = bank_bits(value)
|
|
170
|
+
@phi1_ultimax = false
|
|
171
|
+
@config = CONTROL_MODES[value & 0x03]
|
|
172
|
+
@ram_at_a000 = (value & 0x67) == 0x22
|
|
173
|
+
if @nordic && @ram_at_a000
|
|
174
|
+
@config = :rom16k
|
|
175
|
+
@ram_enabled = false
|
|
176
|
+
else
|
|
177
|
+
acknowledge_freeze if value.anybits?(0x40)
|
|
178
|
+
@ram_enabled = value.anybits?(0x20)
|
|
179
|
+
@config = :off if @ram_at_a000
|
|
180
|
+
end
|
|
181
|
+
@config = :ultimax if @frozen
|
|
182
|
+
configure
|
|
183
|
+
@active = false if value.anybits?(0x04)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Flash mode leaves 8K mode only to switch the cartridge off.
|
|
187
|
+
def flash_mode_control(value)
|
|
188
|
+
return value unless @flash_jumper && (value & 0x03) != 0x02
|
|
189
|
+
|
|
190
|
+
value & ~0x03
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def acknowledge_freeze
|
|
194
|
+
@frozen = false
|
|
195
|
+
self.nmi = false
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def extended_control(value)
|
|
199
|
+
unless @write_once
|
|
200
|
+
@allow_bank = value.anybits?(0x02)
|
|
201
|
+
@no_freeze = value.anybits?(0x04)
|
|
202
|
+
@reu_mapping = value.anybits?(0x40) && !@flash_jumper
|
|
203
|
+
@write_once = !@flash_jumper
|
|
204
|
+
end
|
|
205
|
+
@bank = bank_bits(value)
|
|
206
|
+
@bank |= 0x08 if @flash_jumper && @bank_jumper && value.nobits?(0x20)
|
|
207
|
+
configure
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def bank_bits(value)
|
|
211
|
+
((value >> 3) & 0x03) | ((value >> 5) & 0x04)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def configure
|
|
215
|
+
self.mode = @config
|
|
216
|
+
@rom = flash_window(@bank)
|
|
217
|
+
@roml = roml_window
|
|
218
|
+
@romh = romh_window
|
|
219
|
+
changed!
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def roml_window
|
|
223
|
+
nothing = @open_bus || EMPTY_BANK
|
|
224
|
+
return @ram_enabled ? WriteOnlyRAM.new(@ram_data[@bank & 0x03], nothing) : nothing if @frozen
|
|
225
|
+
return ram_window(@bank & 0x03) if @ram_enabled
|
|
226
|
+
return flash_writes if (@nordic && @ram_at_a000) || @config != :rom16k
|
|
227
|
+
|
|
228
|
+
nothing
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# A RAM bank over the flash window takes writes for the chip and the
|
|
232
|
+
# C64's RAM alike.
|
|
233
|
+
def flash_writes
|
|
234
|
+
return @rom unless @flash_jumper
|
|
235
|
+
|
|
236
|
+
RAMBank.new(@rom).tap { |window| window.backing = @ram }
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def ram_window(number)
|
|
240
|
+
if @config == :ultimax || @flash_jumper
|
|
241
|
+
@isolated[number]
|
|
242
|
+
else
|
|
243
|
+
(@nordic ? @through : @readers)[number]
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def romh_window
|
|
248
|
+
nordic_ram = @nordic && @ram_at_a000
|
|
249
|
+
return @isolated[ram_view_bank] if nordic_ram && !@frozen
|
|
250
|
+
return @rom if @allow_bank || !(@ram_enabled || nordic_ram)
|
|
251
|
+
|
|
252
|
+
flash_window(@bank & ~0x03)
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
def flash_window(number)
|
|
256
|
+
@flash.window((@bank_jumper ? 0 : 0x10000) + (number * BANK_SIZE))
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def install_chips(chips)
|
|
260
|
+
data = Array.new(0x20000, 0xff)
|
|
261
|
+
chips.each do |chip|
|
|
262
|
+
bytes = chip.data.first(BANK_SIZE)
|
|
263
|
+
data[((chip.bank & 0x0f) ^ 0x08) * BANK_SIZE, bytes.length] = bytes
|
|
264
|
+
end
|
|
265
|
+
@flash = Flash.new(data, model: Flash::AM29F010)
|
|
266
|
+
@flash.on_change { configure }
|
|
267
|
+
@ram_data = Array.new(4) { Array.new(BANK_SIZE, 0) }
|
|
268
|
+
@through = @ram_data.map { |data| RAMBank.new(data) }
|
|
269
|
+
@isolated = @ram_data.map { |data| RAMBank.new(data) }
|
|
270
|
+
@readers = @ram_data.map { |data| RAMReader.new(data) }
|
|
271
|
+
@allow_bank = @no_freeze = @reu_mapping = @write_once = false
|
|
272
|
+
reset
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
class Cartridge
|
|
5
|
+
# 8K. Reading $DF00-$DFBF switches the ROM out, reading $DFC0-$DFFF
|
|
6
|
+
# switches it back in.
|
|
7
|
+
class RexUtility < Cartridge
|
|
8
|
+
def readable_io_pages
|
|
9
|
+
[0xdf]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def peek(addr)
|
|
13
|
+
if addr >= 0xdf00
|
|
14
|
+
self.mode = (addr & 0xff) < 0xc0 ? :off : :rom8k
|
|
15
|
+
changed!
|
|
16
|
+
end
|
|
17
|
+
open_bus(addr)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def reset
|
|
21
|
+
self.mode = :rom8k
|
|
22
|
+
changed!
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def install_chips(chips)
|
|
28
|
+
@roml = banks_from(chips).first.compact.first
|
|
29
|
+
reset
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
class Cartridge
|
|
5
|
+
# RGCD: up to eight 8K banks. A write to I/O 1 selects the bank from the
|
|
6
|
+
# low bits, and bit 3 switches the ROM out until reset. The Hucky board
|
|
7
|
+
# (subtype 1) inverts the bank bits and decodes only as many as it has
|
|
8
|
+
# banks.
|
|
9
|
+
class RGCD < Cartridge
|
|
10
|
+
def initialize(crt)
|
|
11
|
+
@hucky = crt.subtype == 1
|
|
12
|
+
super
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def poke(addr, value)
|
|
16
|
+
return if addr > 0xdeff || @disabled
|
|
17
|
+
|
|
18
|
+
select(value)
|
|
19
|
+
changed!
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def reset
|
|
23
|
+
@disabled = false
|
|
24
|
+
self.mode = :rom8k
|
|
25
|
+
select(0)
|
|
26
|
+
changed!
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def select(value)
|
|
32
|
+
value ^= 0x07 if @hucky
|
|
33
|
+
if value.anybits?(0x08)
|
|
34
|
+
@disabled = true
|
|
35
|
+
self.mode = :off
|
|
36
|
+
else
|
|
37
|
+
@roml = bank(@banks, value & @bank_mask)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def install_chips(chips)
|
|
42
|
+
@banks = banks_from(chips).first
|
|
43
|
+
@bank_mask = @hucky ? @banks.length - 1 : 0x07
|
|
44
|
+
reset
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
class Cartridge
|
|
5
|
+
# 16K. Reading I/O 1 switches ROMH out (8K mode), writing it switches
|
|
6
|
+
# ROMH back in.
|
|
7
|
+
class SimonsBasic < Cartridge
|
|
8
|
+
def readable_io_pages
|
|
9
|
+
[0xde]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def peek(addr)
|
|
13
|
+
select_mode(:rom8k) if addr < 0xdf00
|
|
14
|
+
open_bus(addr)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def poke(addr, _value)
|
|
18
|
+
select_mode(:rom16k) if addr < 0xdf00
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def reset
|
|
22
|
+
select_mode(:rom16k)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def select_mode(mode)
|
|
28
|
+
self.mode = mode
|
|
29
|
+
changed!
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def install_chips(chips)
|
|
33
|
+
roml, romh = banks_from(chips)
|
|
34
|
+
@roml = roml.first
|
|
35
|
+
@romh = romh.first
|
|
36
|
+
reset
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -6,25 +6,9 @@ module Badline
|
|
|
6
6
|
private
|
|
7
7
|
|
|
8
8
|
def install_chips(chips)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def install_chip(chip)
|
|
13
|
-
if chip.address >= ULTIMAX_ROMH_START
|
|
14
|
-
@romh = rom_bank(chip.data, ULTIMAX_ROMH_START)
|
|
15
|
-
elsif chip.address >= ROMH_START
|
|
16
|
-
@romh = rom_bank(chip.data, ROMH_START)
|
|
17
|
-
elsif chip.data.length > BANK_SIZE
|
|
18
|
-
install_split_chip(chip)
|
|
19
|
-
else
|
|
20
|
-
@roml = rom_bank(chip.data, ROML_START)
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def install_split_chip(chip)
|
|
25
|
-
# A single 16K chip at $8000 spans both ROML and ROMH.
|
|
26
|
-
@roml = rom_bank(chip.data[0, BANK_SIZE], ROML_START)
|
|
27
|
-
@romh = rom_bank(chip.data[BANK_SIZE, BANK_SIZE], ROMH_START)
|
|
9
|
+
roml, romh = banks_from(chips)
|
|
10
|
+
@roml = roml.compact.first
|
|
11
|
+
@romh = romh.compact.first
|
|
28
12
|
end
|
|
29
13
|
end
|
|
30
14
|
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
class Cartridge
|
|
5
|
+
# Super Games: four 16K banks. A write to I/O 2 selects the bank from bits
|
|
6
|
+
# 0-1, switches the ROM out with bit 2, and with bit 3 locks the register
|
|
7
|
+
# until reset.
|
|
8
|
+
class SuperGames < Cartridge
|
|
9
|
+
def poke(addr, value)
|
|
10
|
+
return if addr < 0xdf00 || @locked
|
|
11
|
+
|
|
12
|
+
select(value)
|
|
13
|
+
changed!
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def reset
|
|
17
|
+
select(0)
|
|
18
|
+
changed!
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def select(value)
|
|
24
|
+
@roml = bank(@roml_banks, value & 0x03)
|
|
25
|
+
@romh = bank(@romh_banks, value & 0x03)
|
|
26
|
+
self.mode = value.anybits?(0x04) ? :off : :rom16k
|
|
27
|
+
@locked = value.anybits?(0x08)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def install_chips(chips)
|
|
31
|
+
@roml_banks, @romh_banks = banks_from(chips)
|
|
32
|
+
reset
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
class Cartridge
|
|
5
|
+
# 16K. Reading I/O 2 switches ROMH out (8K mode) until reset.
|
|
6
|
+
class Westermann < Cartridge
|
|
7
|
+
def readable_io_pages
|
|
8
|
+
[0xdf]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def peek(addr)
|
|
12
|
+
if addr >= 0xdf00
|
|
13
|
+
self.mode = :rom8k
|
|
14
|
+
changed!
|
|
15
|
+
end
|
|
16
|
+
open_bus(addr)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def reset
|
|
20
|
+
self.mode = :rom16k
|
|
21
|
+
changed!
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def install_chips(chips)
|
|
27
|
+
roml, romh = banks_from(chips)
|
|
28
|
+
@roml = roml.first
|
|
29
|
+
@romh = romh.first
|
|
30
|
+
reset
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
class Cartridge
|
|
5
|
+
# Zaxxon / Super Zaxxon: 16K mode with a 4K ROML mirrored across
|
|
6
|
+
# $8000-$9FFF and two 8K ROMH banks. A read through ROML selects the
|
|
7
|
+
# ROMH bank: $8000-$8FFF the first, $9000-$9FFF the second.
|
|
8
|
+
class Zaxxon < Cartridge
|
|
9
|
+
class Low
|
|
10
|
+
def initialize(rom, high)
|
|
11
|
+
@rom = rom
|
|
12
|
+
@high = high
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def peek(addr)
|
|
16
|
+
@high.select(addr[12])
|
|
17
|
+
@rom.peek(addr)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class High
|
|
22
|
+
def initialize(banks)
|
|
23
|
+
@banks = banks
|
|
24
|
+
select(0)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def select(number)
|
|
28
|
+
@bank = @banks[number] || EMPTY_BANK
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def peek(addr)
|
|
32
|
+
@bank.peek(addr)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def reset
|
|
37
|
+
@romh.select(0)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def install_chips(chips)
|
|
43
|
+
roml, romh = banks_from(chips)
|
|
44
|
+
@romh = High.new(romh)
|
|
45
|
+
@roml = Low.new(roml.first || EMPTY_BANK, @romh)
|
|
46
|
+
self.mode = :rom16k
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|