badline 0.2.1 → 0.4.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/.claude/hooks/session-start.sh +57 -0
- data/.claude/settings.json +14 -0
- data/CHANGELOG.md +107 -0
- data/CLAUDE.md +51 -16
- data/CONTRIBUTING.md +95 -3
- data/README.md +119 -51
- data/SECURITY.md +9 -0
- data/doc/pinned-behaviour.md +293 -39
- data/exe/badline-ruby +59 -0
- data/lib/badline/address_bus.rb +28 -14
- data/lib/badline/addressable.rb +1 -1
- data/lib/badline/audio/aiff.rb +8 -3
- data/lib/badline/audio/bare_player.rb +20 -3
- data/lib/badline/audio/cli.rb +17 -12
- data/lib/badline/audio/console.rb +12 -58
- data/lib/badline/audio/machine_player.rb +9 -6
- data/lib/badline/audio/playback.rb +3 -0
- data/lib/badline/audio/renderer.rb +3 -3
- data/lib/badline/audio/sdl_sink.rb +20 -52
- data/lib/badline/audio/stream.rb +117 -0
- data/lib/badline/audio/terminal.rb +90 -0
- data/lib/badline/audio.rb +3 -2
- data/lib/badline/cartridge/easy_flash.rb +6 -2
- data/lib/badline/cartridge/epyx_fastload.rb +1 -1
- data/lib/badline/cartridge/geo_ram.rb +63 -0
- data/lib/badline/cartridge/mach5.rb +1 -1
- data/lib/badline/cartridge/magic_desk.rb +5 -1
- data/lib/badline/cartridge/ocean.rb +5 -2
- data/lib/badline/cartridge/rex_utility.rb +1 -1
- data/lib/badline/cartridge/rgcd.rb +1 -1
- data/lib/badline/cartridge/simons_basic.rb +2 -2
- data/lib/badline/cartridge/westermann.rb +2 -2
- data/lib/badline/cartridge.rb +9 -0
- data/lib/badline/checkpoint.rb +98 -0
- data/lib/badline/cia/interrupt_register.rb +34 -10
- data/lib/badline/cia.rb +19 -10
- data/lib/badline/color_memory.rb +2 -2
- data/lib/badline/computer.rb +34 -14
- data/lib/badline/cpu.rb +2 -2
- data/lib/badline/gui/application.rb +70 -26
- data/lib/badline/gui/gamepads.rb +22 -22
- data/lib/badline/gui/joy_map.rb +1 -1
- data/lib/badline/gui/key_map.rb +6 -1
- data/lib/badline/gui/pane.rb +7 -6
- data/lib/badline/gui/screen_pane.rb +9 -13
- data/lib/badline/gui/window.rb +35 -20
- data/lib/badline/gui.rb +1 -1
- data/lib/badline/input/mouse1351.rb +21 -6
- data/lib/badline/input/paddles.rb +11 -6
- data/lib/badline/kernal_trap/channel.rb +102 -7
- data/lib/badline/kernal_trap/drive/block_commands.rb +108 -0
- data/lib/badline/kernal_trap/drive/channels.rb +53 -0
- data/lib/badline/kernal_trap/drive/memory.rb +109 -0
- data/lib/badline/kernal_trap/drive/parameters.rb +28 -0
- data/lib/badline/kernal_trap/drive/status.rb +3 -0
- data/lib/badline/kernal_trap/drive/write_file.rb +41 -0
- data/lib/badline/kernal_trap/drive/writes.rb +92 -0
- data/lib/badline/kernal_trap/drive.rb +109 -131
- data/lib/badline/kernal_trap/file.rb +6 -14
- data/lib/badline/kernal_trap/load.rb +6 -0
- data/lib/badline/kernal_trap/save.rb +13 -7
- data/lib/badline/keyboard.rb +19 -3
- data/lib/badline/media.rb +44 -13
- data/lib/badline/memory.rb +2 -2
- data/lib/badline/options.rb +209 -0
- data/lib/badline/ram_expansion/banking.rb +30 -0
- data/lib/badline/ram_expansion/plus256k.rb +38 -0
- data/lib/badline/ram_expansion/plus60k.rb +31 -0
- data/lib/badline/ram_expansion/unexpanded.rb +22 -0
- data/lib/badline/ram_expansion.rb +21 -0
- data/lib/badline/region.rb +51 -0
- data/lib/badline/rom.rb +14 -5
- data/lib/badline/sdl/events.rb +47 -0
- data/lib/badline/sdl/functions.rb +73 -0
- data/lib/badline/sdl.rb +67 -0
- data/lib/badline/sid/catch_up.rb +110 -0
- data/lib/badline/sid/decimator.rb +6 -1
- data/lib/badline/sid/filter.rb +5 -5
- data/lib/badline/sid/waveform/fast_forward.rb +10 -10
- data/lib/badline/sid/waveform/noise_writeback.rb +32 -14
- data/lib/badline/sid/waveform.rb +8 -8
- data/lib/badline/sid.rb +19 -93
- data/lib/badline/storage/d64_image.rb +10 -0
- data/lib/badline/storage/d71_image.rb +12 -0
- data/lib/badline/storage/d81_image.rb +9 -0
- data/lib/badline/storage/disk_image/bam.rb +111 -0
- data/lib/badline/storage/disk_image/directory.rb +79 -0
- data/lib/badline/storage/disk_image/writing.rb +110 -0
- data/lib/badline/storage/disk_image.rb +49 -4
- data/lib/badline/storage/host_directory.rb +17 -4
- data/lib/badline/storage/sid_file.rb +36 -2
- data/lib/badline/storage.rb +18 -1
- data/lib/badline/time_of_day.rb +11 -2
- data/lib/badline/version.rb +1 -1
- data/lib/badline/via/control_lines.rb +104 -0
- data/lib/badline/via/interrupt_register.rb +58 -0
- data/lib/badline/via/shift_register.rb +135 -0
- data/lib/badline/via/timer1.rb +82 -0
- data/lib/badline/via/timer2.rb +84 -0
- data/lib/badline/via.rb +262 -0
- data/lib/badline/vic/bank.rb +4 -3
- data/lib/badline/vic/color_patches.rb +6 -3
- data/lib/badline/vic/display_state.rb +4 -0
- data/lib/badline/vic/graphics_shifter.rb +49 -8
- data/lib/badline/vic/registers.rb +19 -27
- data/lib/badline/vic/sequencer.rb +18 -18
- data/lib/badline/vic/sequencer_output.rb +4 -4
- data/lib/badline/vic/sprite/internal_bus.rb +4 -0
- data/lib/badline/vic/sprite/shifter.rb +25 -3
- data/lib/badline/vic/sprite.rb +5 -4
- data/lib/badline/vic/sprites.rb +8 -3
- data/lib/badline/vic.rb +98 -46
- data/lib/badline.rb +5 -0
- data/packaging/homebrew/badline.rb +34 -0
- metadata +37 -20
- data/exe/badline +0 -75
- data/exe/badline-sid +0 -34
- data/lib/badline/audio/options.rb +0 -137
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2c5aff63e93f3b5e40dfee64086b8e633e0a523d5c82403f0c64270701dc701b
|
|
4
|
+
data.tar.gz: 5e1b663ccbc425e672bfd569360740f6d9dd7911a2747e8ca8e86d4575d5aba2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a4cf2f04c4ad639baf9c03ef4d1140aaa6cda90b8f4d2468950f87018072aeb98610a2c268f871a9c211b9b893a10a0d65a7ee242fbfaf9979e0356b6e3df4b5
|
|
7
|
+
data.tar.gz: 0a74de512d21d0cbb905b3c8b0851dfd76ab501333a878fa7a9abcc8f104b688b25b8ee9ee651e8ba990cde98202237eaa408c491d8e8fce1b4cd2b85e38bb3a
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Prepares a Claude Code on the web container to run `bundle exec rubocop`
|
|
3
|
+
# and `bundle exec rspec`. The regression suites need vendor/ and aren't set
|
|
4
|
+
# up here.
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
if [ "${CLAUDE_CODE_REMOTE:-}" != "true" ]; then
|
|
8
|
+
exit 0
|
|
9
|
+
fi
|
|
10
|
+
|
|
11
|
+
cd "${CLAUDE_PROJECT_DIR:-$(dirname "$0")/../..}"
|
|
12
|
+
|
|
13
|
+
# The SDL specs open libSDL2 through Fiddle, so only the runtime library is
|
|
14
|
+
# needed, as in CI.
|
|
15
|
+
if ! ldconfig -p | grep 'libSDL2-2\.0\.so\.0' >/dev/null; then
|
|
16
|
+
export DEBIAN_FRONTEND=noninteractive
|
|
17
|
+
apt-get update -qq
|
|
18
|
+
apt-get install -y -qq libsdl2-2.0-0 >/dev/null
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
# The image ships Ruby 3.3 and an rbenv. Install the newest Ruby 4.0.x, as
|
|
22
|
+
# CI's ruby-version "4.0" picks, from the prebuilt binaries setup-ruby uses,
|
|
23
|
+
# unless a 4.0 is installed already.
|
|
24
|
+
export RBENV_ROOT=/opt/rbenv
|
|
25
|
+
export PATH="$RBENV_ROOT/bin:$RBENV_ROOT/shims:$PATH"
|
|
26
|
+
ruby_version=$(rbenv versions --bare | grep -E '^4\.0\.[0-9]+$' | sort -V | tail -1 || true)
|
|
27
|
+
if [ -z "$ruby_version" ]; then
|
|
28
|
+
ruby_version=$(curl -fsSL https://raw.githubusercontent.com/ruby/setup-ruby/master/ruby-builder-versions.json |
|
|
29
|
+
ruby -rjson -e 'puts JSON.parse($stdin.read)["ruby"].grep(/\A4\.0\.\d+\z/).max_by { Gem::Version.new(_1) }')
|
|
30
|
+
# The binaries only run from the prefix they were built with, so unpack
|
|
31
|
+
# there and link it into rbenv.
|
|
32
|
+
. /etc/os-release
|
|
33
|
+
prefix="/opt/hostedtoolcache/Ruby/$ruby_version/x64"
|
|
34
|
+
mkdir -p "$prefix"
|
|
35
|
+
if curl -fsSL "https://github.com/ruby/ruby-builder/releases/download/ruby-$ruby_version/ruby-$ruby_version-ubuntu-$VERSION_ID-x64.tar.gz" |
|
|
36
|
+
tar -xz -C "$prefix" --strip-components=1; then
|
|
37
|
+
ln -sfn "$prefix" "$RBENV_ROOT/versions/$ruby_version"
|
|
38
|
+
else
|
|
39
|
+
# No binary for this Ubuntu release: build from source, which takes minutes.
|
|
40
|
+
rm -rf "$prefix"
|
|
41
|
+
git -C "$RBENV_ROOT/plugins/ruby-build" pull --ff-only -q || true
|
|
42
|
+
MAKE_OPTS="-j$(nproc)" rbenv install --skip-existing "$ruby_version"
|
|
43
|
+
fi
|
|
44
|
+
fi
|
|
45
|
+
rbenv global "$ruby_version"
|
|
46
|
+
rbenv rehash
|
|
47
|
+
|
|
48
|
+
# Put rbenv's shims ahead of /usr/local/bin/ruby for the session.
|
|
49
|
+
if [ -n "${CLAUDE_ENV_FILE:-}" ]; then
|
|
50
|
+
{
|
|
51
|
+
echo "export RBENV_ROOT=$RBENV_ROOT"
|
|
52
|
+
echo "export PATH=\"$RBENV_ROOT/bin:$RBENV_ROOT/shims:\$PATH\""
|
|
53
|
+
} >> "$CLAUDE_ENV_FILE"
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
# Bundler switches to the version Gemfile.lock was bundled with.
|
|
57
|
+
bundle install --jobs "$(nproc)"
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,112 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.4.0](https://github.com/elektronaut/badline/compare/v0.3.0...v0.4.0) (2026-09-28)
|
|
4
|
+
|
|
5
|
+
### Upgrading
|
|
6
|
+
|
|
7
|
+
* The gem's executable is now `badline-ruby`. The name `badline` now belongs to the native build, which installs with `brew install elektronaut/tap/badline` on macOS.
|
|
8
|
+
* `badline-sid` is gone. Play a tune with `badline-ruby --headless tune.sid` (or `badline --headless tune.sid`), and render one with `--audio-out out.wav`.
|
|
9
|
+
|
|
10
|
+
### ⚠ BREAKING CHANGES
|
|
11
|
+
|
|
12
|
+
* the `badline-sid` executable is gone. Use `badline-ruby --headless tune.sid` to play a tune and `badline-ruby tune.sid --audio-out out.wav` to render one. badline-sid's `-o`/`--output` option and positional output file became `--audio-out`, which has no short form. Badline::Audio::Options is now Badline::Options.
|
|
13
|
+
* the gem's `badline` executable is now `badline-ruby`. There is no `badline` shim.
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* add a Homebrew formula for the native badline ([33c2e98](https://github.com/elektronaut/badline/commit/33c2e983a12275195383e33230137d461b1a9fd0))
|
|
18
|
+
* add mouse and paddle input to the native window ([f468c21](https://github.com/elektronaut/badline/commit/f468c2189b3b213561516a39ec0ffcedcb8c5b89))
|
|
19
|
+
* emulate GEO-RAM and run the testbench geo512k rows ([9a5395f](https://github.com/elektronaut/badline/commit/9a5395fd34ad42d21e08a3b498038850d790f253)), closes [#239](https://github.com/elektronaut/badline/issues/239)
|
|
20
|
+
* emulate the +60K and +256K RAM expansions ([9d60488](https://github.com/elektronaut/badline/commit/9d60488d01bd33c9d090f75f4765931f21911247)), closes [#240](https://github.com/elektronaut/badline/issues/240)
|
|
21
|
+
* fold badline-sid into badline-ruby ([443d155](https://github.com/elektronaut/badline/commit/443d1559bb5253d58f5378e7e212beda5b734bda))
|
|
22
|
+
* give the native badline badline-ruby's command-line options ([bd2ec0d](https://github.com/elektronaut/badline/commit/bd2ec0da269a95eccb37198dd3e03faf84651396))
|
|
23
|
+
* headless .sid options for the native badline ([4354e80](https://github.com/elektronaut/badline/commit/4354e80e5b61da9148a2077d1e0557ea23a833df))
|
|
24
|
+
* make the Spinel window the native badline executable ([54e8e71](https://github.com/elektronaut/badline/commit/54e8e7151e5ced11e536da6baaf779af7f4eae16))
|
|
25
|
+
* model the 6526A CIA ([18a2012](https://github.com/elektronaut/badline/commit/18a201253c4612bb2ae821e544c9e6f3a6e1fb8c))
|
|
26
|
+
* model the 8565 VIC-II ([e81b7fb](https://github.com/elektronaut/badline/commit/e81b7fb7053c8cca1b94dda66cda3357d2984aa1))
|
|
27
|
+
* mount disk images read-only ([c35b808](https://github.com/elektronaut/badline/commit/c35b80852da7ebcf92cbf7de9478d62ba9197602))
|
|
28
|
+
* pace the native window by vsync ([1fa4661](https://github.com/elektronaut/badline/commit/1fa4661b480cba2a79772096ee32327098719f1b))
|
|
29
|
+
* pack the native badline with spin pack (rake native:pack) ([1d2288b](https://github.com/elektronaut/badline/commit/1d2288bd4f9c6589a35a0f99f8f1b0baeaa8e69a))
|
|
30
|
+
* read SDL game controllers in the native window ([a80403c](https://github.com/elektronaut/badline/commit/a80403cefa5b75f4edbf9157631ff5eac9c234f9))
|
|
31
|
+
* rename the executable to badline-ruby ([6050d9d](https://github.com/elektronaut/badline/commit/6050d9db2376ada76af5068b1e9703162adb90b3))
|
|
32
|
+
* replace ruby-sdl2 with a Fiddle binding to libSDL2 ([f3a4b84](https://github.com/elektronaut/badline/commit/f3a4b8429330efaf2abfe2592e1df2fd0791a9ee)), closes [#253](https://github.com/elektronaut/badline/issues/253)
|
|
33
|
+
* run the C64/ and general/ testbench rows as testbench-general ([53316c0](https://github.com/elektronaut/badline/commit/53316c03cd87e9e72d92ff8a6a9e13b6d0eae807))
|
|
34
|
+
* run the Lorenz chain on a Spinel build with rake spinel:lorenz ([955d722](https://github.com/elektronaut/badline/commit/955d722a06865f6a704f14570d7b246963317551))
|
|
35
|
+
* run the SID testprogs on a Spinel build with rake spinel:sidtests ([ecff9ba](https://github.com/elektronaut/badline/commit/ecff9bafa8b3621454e540d92707c0c139c7f7fd))
|
|
36
|
+
* run the testbench suites on a Spinel build with rake spinel:testbench ([083911a](https://github.com/elektronaut/badline/commit/083911af7194c56992f529f67c4bf101a44fb450))
|
|
37
|
+
* turn sound on by default in the native badline ([c4f65cf](https://github.com/elektronaut/badline/commit/c4f65cfa73fcad49399226f238b8b5b46799ed30))
|
|
38
|
+
* type RESTORE, ↑, ← and cursor up/left from the host keyboard ([74623e3](https://github.com/elektronaut/badline/commit/74623e346d4ccad26f779d3f0c9f0c11426b96c3)), closes [#234](https://github.com/elektronaut/badline/issues/234)
|
|
39
|
+
* write to disk images and swap them at runtime ([a6eebf5](https://github.com/elektronaut/badline/commit/a6eebf5e304186c8512e5cda4f6514a92ac64395)), closes [#233](https://github.com/elektronaut/badline/issues/233)
|
|
40
|
+
|
|
41
|
+
### Bug Fixes
|
|
42
|
+
|
|
43
|
+
* end a testbench run on the cycle the test writes its exit code ([58aa8c5](https://github.com/elektronaut/badline/commit/58aa8c52e639945a78cac40330e15a686081d8ec))
|
|
44
|
+
* keep pixel 0 black out of an invalid mode into hi-res text on the 8565 ([5a6ff96](https://github.com/elektronaut/badline/commit/5a6ff96192455b9f3ca9fd8904aa9bb4760e99cc))
|
|
45
|
+
* leave a PRG's end address in $AE/$AF on autostart ([d76ed18](https://github.com/elektronaut/badline/commit/d76ed1840850045ac7a1c1d3dc5c6d5d99685fdd))
|
|
46
|
+
* leave the VIC's phi1 byte in the RAM under the CPU port ([55fc2f5](https://github.com/elektronaut/badline/commit/55fc2f52cd0d0a0edeb56cde140e67fb1ab50077))
|
|
47
|
+
* make the mouse speed independent of the window size ([5cbabbf](https://github.com/elektronaut/badline/commit/5cbabbfade4e53c8aae265f2493466419ef67958)), closes [#280](https://github.com/elektronaut/badline/issues/280)
|
|
48
|
+
* make the VIC's collision registers read-only ([141526c](https://github.com/elektronaut/badline/commit/141526ce755bf47582a25e2c209cdc950ff81f0b))
|
|
49
|
+
* name the release tag in the native --version ([5654433](https://github.com/elektronaut/badline/commit/56544334b43ed992d0d54215a99a7be50fa74240))
|
|
50
|
+
* read unused bits of $D016 and $D018 as 1 ([00a816b](https://github.com/elektronaut/badline/commit/00a816b9bdbe88c7f838f941b2ef2dc5cd7db075)), closes [#237](https://github.com/elektronaut/badline/issues/237)
|
|
51
|
+
* say SDL2 is missing instead of raising from badline-ruby ([0f5ec9c](https://github.com/elektronaut/badline/commit/0f5ec9c7fabfa922ecb4c87339ba3ccc0f09bca0))
|
|
52
|
+
* SID test bit writeback for noiselfsrinit, F->8 and the 8580's C->F ([bdb063f](https://github.com/elektronaut/badline/commit/bdb063f1aba3f1714e26bc3e8301adf9bc33fb3e)), closes [#238](https://github.com/elektronaut/badline/issues/238)
|
|
53
|
+
* suggest the SDL2 runtime package when badline-ruby can't find it ([44a3375](https://github.com/elektronaut/badline/commit/44a3375973aafc0ec7aba672609517dd6571f85c))
|
|
54
|
+
* **vic:** read the idle byte at $38ff where a DMA delay starts ([f3892aa](https://github.com/elektronaut/badline/commit/f3892aa0ac45fbc493bccd0f5980dfe7fc659848)), closes [#235](https://github.com/elektronaut/badline/issues/235)
|
|
55
|
+
|
|
56
|
+
### Performance Improvements
|
|
57
|
+
|
|
58
|
+
* **vic:** check the DMA-delay idle byte only when display state opens ([8d9b777](https://github.com/elektronaut/badline/commit/8d9b777b3554ed4d6bef67ac41c0a344c3b0a35b))
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
## [0.3.0](https://github.com/elektronaut/badline/compare/v0.2.1...v0.3.0) (2026-09-24)
|
|
62
|
+
|
|
63
|
+
Sound is the headline: `badline --sound` plays the SID in the emulator window and paces emulation to the audio device. It is off by default, because the emulator still runs below real time on CRuby and the sound stutters there. This release also brings the virtual drive closer to a real 1541 (buffer channels in drive RAM, DOS command parsing, the BAM in buffer 4, `LOAD"*"`), cartridge banking fixes, and `Badline::Checkpoint` with `bin/machine_diff` for checking that a change leaves emulation alone.
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
### Features
|
|
68
|
+
|
|
69
|
+
* add Badline::Checkpoint, a per-component digest of machine state ([183e164](https://github.com/elektronaut/badline/commit/183e16438b4b1bfae5c16b10f29f2b08d0a6b297))
|
|
70
|
+
* add bin/machine_diff, a differential run harness ([58f695a](https://github.com/elektronaut/badline/commit/58f695a32096fe61d7395fcec9a76d8d84b5e440))
|
|
71
|
+
* load ROMs from a configurable Badline.rom_path ([4fa12c8](https://github.com/elektronaut/badline/commit/4fa12c8e55004eebe0b1a14e80f03713306e3acf))
|
|
72
|
+
* pace the window to the audio device while sound plays ([031b001](https://github.com/elektronaut/badline/commit/031b00196ee9a881740047c726231ffc0400d03d))
|
|
73
|
+
* play the SID in the emulator window with --sound ([4cbd211](https://github.com/elektronaut/badline/commit/4cbd211ca986834e3d8fcbafdabc5586c87ec950))
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
### Bug Fixes
|
|
77
|
+
|
|
78
|
+
* answer a buffer channel's first read with its buffer number ([851e0d2](https://github.com/elektronaut/badline/commit/851e0d2bb71db51cc36607da90b4f7891b32bced))
|
|
79
|
+
* bank BASIC out for PSID routines whose image reaches under it ([9c5bf57](https://github.com/elektronaut/badline/commit/9c5bf57646ca8de8687679accdca26ac4dd68931))
|
|
80
|
+
* bank sparse and odd-sized cartridge images like the hardware ([1560f63](https://github.com/elektronaut/badline/commit/1560f63678a254bfa53e8915c35851dab00dc27b))
|
|
81
|
+
* drop the carriage return that ends a file name, as the 1541 does ([3ca3d51](https://github.com/elektronaut/badline/commit/3ca3d518808cf87ab0e14a3b312e972883fc4699))
|
|
82
|
+
* fail a block write at the block it names ([4b9664c](https://github.com/elektronaut/badline/commit/4b9664ca02bd0026334ffee01d4f6a5cfc354f73))
|
|
83
|
+
* fail an append open on a write-protected disk ([b5c7baf](https://github.com/elektronaut/badline/commit/b5c7bafed7f189c3e7a0074d27f0b76e8ffb3b56))
|
|
84
|
+
* fail an unreadable host file with a READ ERROR ([8b3d8f4](https://github.com/elektronaut/badline/commit/8b3d8f4eeae28a4ef61ef72e76dcfc02cefb738f))
|
|
85
|
+
* fill a buffer channel with the bytes written to it ([36c3660](https://github.com/elektronaut/badline/commit/36c3660e1c170ea058b80d3a0b10ec019aa84058))
|
|
86
|
+
* give single-bank mappers erased ROM when the image has no chip ([07e5bf3](https://github.com/elektronaut/badline/commit/07e5bf39b26e022f814c99b0d9226cecf3114400))
|
|
87
|
+
* ignore whatever follows a star in a DOS file name ([b2f8831](https://github.com/elektronaut/badline/commit/b2f8831b193e496d19c03388fe0613b9f9c9abb3))
|
|
88
|
+
* keep the drive's buffer channels in its RAM ([9efefe4](https://github.com/elektronaut/badline/commit/9efefe44520067db27496ea2af85468228c6579f))
|
|
89
|
+
* keep the drive's RAM when the disk changes ([2c07d0e](https://github.com/elektronaut/badline/commit/2c07d0eb73120dfe1eda69a5fc8ad43a31d83ef2))
|
|
90
|
+
* leave secondary address $60 in $B9 after a trapped LOAD ([d7366a8](https://github.com/elektronaut/badline/commit/d7366a8aaf0fe13d239035178751fc8f783d7a30))
|
|
91
|
+
* mask Ocean and Magic Desk bank selection to the ROM size ([e6d36a0](https://github.com/elektronaut/badline/commit/e6d36a004583d18e225e4bb5cfccdd69380d523e))
|
|
92
|
+
* play NTSC PSID tunes on an NTSC clock on the bare rig ([006e04b](https://github.com/elektronaut/badline/commit/006e04b03985ef5d2fe57bab6c862bbe97d65f50))
|
|
93
|
+
* read DOS command parameters the way the 1541 does ([db5b4fc](https://github.com/elektronaut/badline/commit/db5b4fc06b82f5423453ee988d30f407a8565ed1))
|
|
94
|
+
* read open bus from a cartridge's empty ROM socket ([fee013d](https://github.com/elektronaut/badline/commit/fee013dcff2a062b75713b268422171e79a50375))
|
|
95
|
+
* read the BAM into buffer 4 when the drive initializes a disk ([c1320a5](https://github.com/elektronaut/badline/commit/c1320a5d2f7d9fcd24e800fcacaf07ba8b07b889))
|
|
96
|
+
* reopen the last loaded file on a LOAD of "*" ([64b3991](https://github.com/elektronaut/badline/commit/64b3991b9e1c91190e9b47e44238b93e0ea74850))
|
|
97
|
+
* report host SAVE and read failures on the drive's error channel ([039b6da](https://github.com/elektronaut/badline/commit/039b6da1779397e56ebf6cc25effe656ca85c1f6))
|
|
98
|
+
* reset the drive with the machine, as the serial bus's RESET line does ([4044db6](https://github.com/elektronaut/badline/commit/4044db6ae1bd241381c2d7651cf2a44b1ae8a61a))
|
|
99
|
+
* RUN BASIC RSID tunes instead of calling their first byte ([d9a51c2](https://github.com/elektronaut/badline/commit/d9a51c2eebd5092e97da576c438a647079458e78))
|
|
100
|
+
* show a BMM falling out of multicolour bitmap or ECM+BMM at pixel 5 ([988a0c6](https://github.com/elektronaut/badline/commit/988a0c60e40c720e8e1cd7acf0506107902a1ccb))
|
|
101
|
+
* **vic:** power on with every register zero, as VICE does ([d5bf757](https://github.com/elektronaut/badline/commit/d5bf75756d2edfdf3b6bf40214615262b79958a6))
|
|
102
|
+
* wrap a buffer channel's reads back to its second byte, as the DOS does ([9c9f0ed](https://github.com/elektronaut/badline/commit/9c9f0edb7b92b580bb2cb71668e5fa07fa8e3bd9))
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
### Performance Improvements
|
|
106
|
+
|
|
107
|
+
* cut the SID's per-span catch-up overhead ([f50ede8](https://github.com/elektronaut/badline/commit/f50ede8472389c28c1dde70909794ef69ae77238))
|
|
108
|
+
* type the hot core for Spinel with RBS seeds ([90d31b0](https://github.com/elektronaut/badline/commit/90d31b02331982e216284f2ac533f5a6aa934bf9))
|
|
109
|
+
|
|
3
110
|
## [0.2.1](https://github.com/elektronaut/badline/compare/v0.2.0...v0.2.1) (2026-09-23)
|
|
4
111
|
|
|
5
112
|
|
data/CLAUDE.md
CHANGED
|
@@ -18,18 +18,22 @@ live in subdirectories:
|
|
|
18
18
|
modes, border and register timing
|
|
19
19
|
- **CIA**: `cia.rb` and `cia/` (timers, serial), plus `time_of_day.rb`
|
|
20
20
|
- **SID**: `sid.rb` and `sid/`. `audio/` plays and renders tunes for
|
|
21
|
-
`
|
|
21
|
+
`badline-ruby --headless` and `--audio-out`
|
|
22
22
|
- **Media and host I/O**: `storage/` (disk, tape and cartridge image
|
|
23
23
|
formats), `cartridge/` (mappers), `kernal_trap/` (the LOAD/SAVE and IEC
|
|
24
24
|
traps that stand in for a drive), `media.rb` (attach and autostart),
|
|
25
25
|
`datasette.rb`, and `gui/` and `input/` (SDL front end, controllers)
|
|
26
|
+
- **Native**: `native/` holds the native `badline`, the core compiled with
|
|
27
|
+
Spinel in an SDL2 window (`rake native:build`, `native/README.md`).
|
|
28
|
+
`spinel/` holds the Spinel test harnesses
|
|
26
29
|
|
|
27
30
|
Timing-critical code lives in `cpu`, `interrupts`, `vic`, `cia` and `sid` and
|
|
28
31
|
in the order `Computer#cycle!` clocks them. Changes there move the test
|
|
29
32
|
suites below. `gui/` changes move none of them.
|
|
30
33
|
|
|
31
34
|
Namespaced groups live in `lib/badline/<namespace>/`, with a sibling
|
|
32
|
-
`lib/badline/<namespace>.rb` that requires the members
|
|
35
|
+
`lib/badline/<namespace>.rb` that requires the members, directly or through
|
|
36
|
+
other members. `lib/badline.rb`
|
|
33
37
|
requires only the namespace file.
|
|
34
38
|
|
|
35
39
|
### Oracles
|
|
@@ -52,9 +56,15 @@ timer test takes about 25 minutes.
|
|
|
52
56
|
where that time goes. `test/baselines/README.md`
|
|
53
57
|
documents the baseline format, the suites and how rows are compared.
|
|
54
58
|
|
|
59
|
+
`bin/machine_diff <scenario|media> --against <rev>` checks that a change
|
|
60
|
+
leaves emulation alone. It runs the scenario on this tree and on `<rev>`'s
|
|
61
|
+
`lib/` side by side, digests the CPU, RAM, VIC, CIAs and SID every million
|
|
62
|
+
cycles, and names the first component that differs. Use it for refactors
|
|
63
|
+
and speed work.
|
|
64
|
+
|
|
55
65
|
## Driving the emulator headlessly
|
|
56
66
|
|
|
57
|
-
`exe/badline <media>` opens the SDL window, which is no use for checking
|
|
67
|
+
`exe/badline-ruby <media>` opens the SDL window, which is no use for checking
|
|
58
68
|
work. Drive a `Badline::Computer` from Ruby instead, as the `bin/` runners do:
|
|
59
69
|
|
|
60
70
|
```ruby
|
|
@@ -113,11 +123,12 @@ worktree and owns a different set of files.
|
|
|
113
123
|
|
|
114
124
|
- `rake vendor:checkout` fetches SingleStepTests and VICE-testprogs into
|
|
115
125
|
`vendor/`
|
|
116
|
-
- `bundle exec rspec`: line coverage is about
|
|
126
|
+
- `bundle exec rspec`: line coverage is about 97%. `spec/spec_helper.rb`
|
|
117
127
|
fails a whole-suite run (every spec file, no filters) below 90%, while
|
|
118
128
|
single-file and filtered runs skip the floor. `:slow` specs are excluded
|
|
119
129
|
by default: run them with `bundle exec rspec --tag slow`
|
|
120
|
-
- `rake test`: SingleStepTests
|
|
130
|
+
- `rake test`: SingleStepTests, plus the Minitest tests for the regression
|
|
131
|
+
runners in `test/`. Run it for any CPU change
|
|
121
132
|
|
|
122
133
|
The headless suites are expensive. `bin/testbench` forks over 4 shards by
|
|
123
134
|
default. `SHARDS=N rake regression:<suite>` or `bin/testbench --shards N`
|
|
@@ -125,7 +136,7 @@ overrides that, capped by the core count, but keep the default, because
|
|
|
125
136
|
other worktrees share the machine. Whole runs at 4 shards on an M-series
|
|
126
137
|
laptop take 15 min for `testbench` (`VICII/`), 11 for `testbench-cia`, 1 for
|
|
127
138
|
`testbench-interrupts`, 37 for `testbench-irqdma`, 11 for
|
|
128
|
-
`testbench-cpu` and
|
|
139
|
+
`testbench-cpu`, 2 for `testbench-carts` and 10 for `testbench-expansions`. `sid` takes about 12 min. `lorenz` chains itself and takes
|
|
129
140
|
about 2.5 h on CI whole. `rake regression:lorenz-1` to `lorenz-4` run it as
|
|
130
141
|
four stretches of about 40 min each, and they can run side by side.
|
|
131
142
|
`test/baselines/README.md` has the full table. A killed `bin/testbench` run
|
|
@@ -158,17 +169,23 @@ the rows your change can't reach tell you nothing about it.
|
|
|
158
169
|
nightly run. It also runs from the Actions tab on demand. It never runs
|
|
159
170
|
on push or on pull requests, so one verdict can cover a day's merges.
|
|
160
171
|
The `testbench-*` and `sid-8580` suites run from the Actions tab on
|
|
161
|
-
demand
|
|
172
|
+
demand. The Spinel workflow runs the Spinel suites on pull requests
|
|
173
|
+
that touch emulation, harness or build paths. Its jobs aren't required
|
|
174
|
+
checks yet, and the CRuby Regression nightly runs as before
|
|
162
175
|
- The one exception is a change whose reach you can't bound to a set of
|
|
163
176
|
filters, such as reordering `Computer#cycle!` or changing the LOAD trap
|
|
164
177
|
every suite loads through. Ask before running a full suite for it, and
|
|
165
178
|
don't start one on your own judgement
|
|
166
179
|
|
|
167
|
-
Pick the filters from the suites your change can move: VIC → `testbench
|
|
180
|
+
Pick the filters from the suites your change can move: VIC → `testbench`,
|
|
181
|
+
plus `testbench-vicii-new` (`bin/testbench --vicii-new`, the 8565) for
|
|
182
|
+
anything the VIC model reaches;
|
|
168
183
|
CPU, interrupts or timing → the matching `testbench-*` suite, plus
|
|
169
184
|
`rake test` for CPU; CIA → the slow CIA specs first, then the matching
|
|
170
|
-
`testbench-cia` rows
|
|
171
|
-
|
|
185
|
+
`testbench-cia` rows, plus `testbench-cia-new` (`bin/testbench --cia-new`,
|
|
186
|
+
the 6526A) for anything the interrupt register or the CIA model reaches; cartridge mappers, banking or power-on state →
|
|
187
|
+
`testbench-carts`, plus `testbench-expansions` for banking; GEO-RAM, +60K
|
|
188
|
+
or +256K → `testbench-expansions`; SID → `sid`, plus `sid-8580` for anything the 8580
|
|
172
189
|
model reaches (`bin/sidtests --sid 8580`). Lorenz isn't a per-change check:
|
|
173
190
|
its full chain runs nightly, and the planner assigns any row it moves. The
|
|
174
191
|
exception is code whose rule in `doc/pinned-behaviour.md` names Lorenz
|
|
@@ -201,17 +218,35 @@ you change code a pinned rule governs, re-derive the rule against its test
|
|
|
201
218
|
and update the doc if the rule moves. A green suite alone isn't enough,
|
|
202
219
|
because the suite can stay green while the rule breaks.
|
|
203
220
|
|
|
221
|
+
## Issues and pull requests
|
|
222
|
+
|
|
223
|
+
Before filing an issue or opening a pull request, read CONTRIBUTING.md and follow it. Use the exact headings from its skeletons. Report only what you observed or verified, and don't include hypotheses about causes. Open an issue before writing non-trivial code; only changes with one obvious fix (typos, broken links, clear-cut fixes) go straight to a pull request.
|
|
224
|
+
|
|
225
|
+
### Working from issues
|
|
226
|
+
|
|
227
|
+
Open issues are agreed work. An agent told to pick issues works this way:
|
|
228
|
+
|
|
229
|
+
- Pick an open issue without the `in-progress` label whose dependencies
|
|
230
|
+
(named in its body) have merged. Add the label and a comment saying you've
|
|
231
|
+
taken it before you start
|
|
232
|
+
- Work in a worktree from `origin/main` as described under *Working in
|
|
233
|
+
parallel*. The issue's text is your brief. If it turns out wrong or
|
|
234
|
+
blocked, comment on the issue and stop rather than widening the scope
|
|
235
|
+
- Open one pull request per issue with `Closes #N` in its body, and run
|
|
236
|
+
only the rows your change can reach. Picking an issue is permission to
|
|
237
|
+
commit, push and open that pull request
|
|
238
|
+
- Never merge, and never enable auto-merge. The planner session reviews
|
|
239
|
+
every pull request, answers through PR reviews, and merges
|
|
240
|
+
- Fix review findings on the same branch. If you drop an issue, remove
|
|
241
|
+
the label and say why in a comment
|
|
242
|
+
|
|
204
243
|
## Git
|
|
205
244
|
|
|
206
|
-
- **Don't stage, commit, push or open a PR** unless your task says so in
|
|
207
|
-
those words. Wanting a PR, a finished feature or green CI doesn't count
|
|
208
|
-
as permission. Finish the work, report what changed, and stop. A dirty
|
|
209
|
-
tree is the expected end state
|
|
210
245
|
- Hunks are staged by hand during review, so a partially staged file is
|
|
211
246
|
deliberate. Use `git diff HEAD` to see everything
|
|
212
247
|
- Commit messages use Conventional Commits (`feat:`, `fix:`, `chore:`, …).
|
|
213
248
|
release-please derives version bumps and the changelog from the prefixes
|
|
214
249
|
- No `Co-Authored-By` or `Claude-Session` trailers, even where `git log`
|
|
215
250
|
shows them
|
|
216
|
-
-
|
|
217
|
-
|
|
251
|
+
- Open pull requests against `main`, from a branch cut from `origin/main`
|
|
252
|
+
(see above): `gh pr create --base main`
|
data/CONTRIBUTING.md
CHANGED
|
@@ -1,16 +1,58 @@
|
|
|
1
1
|
# Contributing
|
|
2
2
|
|
|
3
|
+
This guide covers bug reports, feature requests, and pull requests. It applies to everyone, including AI agents filing on someone's behalf.
|
|
4
|
+
|
|
5
|
+
In the GitHub web interface, issue forms guide you through the structure. If you file through the API or the `gh` CLI, the forms are bypassed: copy the matching skeleton from [Skeletons](#skeletons) and keep the headings exactly as written.
|
|
6
|
+
|
|
3
7
|
Bug reports and pull requests are welcome on
|
|
4
8
|
[GitHub](https://github.com/elektronaut/badline). Everyone participating
|
|
5
9
|
is expected to follow the [code of conduct](CODE_OF_CONDUCT.md).
|
|
6
10
|
|
|
11
|
+
## Principles
|
|
12
|
+
|
|
13
|
+
### For all issues and pull requests
|
|
14
|
+
|
|
15
|
+
**Report only what you observed or verified.** Whoever investigates, human or agent, anchors on the claims in a report. Unverified claims cost more time than they save.
|
|
16
|
+
|
|
17
|
+
**No hypotheses about causes.** Diagnosis is the maintainers' job. They add theories as comments, where the author shows how much weight to give them. Speculation in a report misleads everyone who reads it.
|
|
18
|
+
|
|
19
|
+
**Keep it short.** Length hides the useful information. A long report usually means two reports, or padding.
|
|
20
|
+
|
|
21
|
+
**One concern per issue or pull request.** Mixed concerns can't be tracked, reviewed, or reverted independently.
|
|
22
|
+
|
|
23
|
+
**Use the exact headings.** Maintainers and their tools rely on them to process reports.
|
|
24
|
+
|
|
25
|
+
### Bug reports
|
|
26
|
+
|
|
27
|
+
**Minimal, numbered steps you actually ran.** A reproduction nobody has run is speculation too.
|
|
28
|
+
|
|
29
|
+
**Raw output, not a paraphrase.** The details that matter are the ones a summary drops.
|
|
30
|
+
|
|
31
|
+
**Ruled out: negative results only.** "Still happens with caching disabled" narrows the search without steering it.
|
|
32
|
+
|
|
33
|
+
### Feature requests
|
|
34
|
+
|
|
35
|
+
**Problem before solution.** A proposed solution constrains the design before anyone familiar with the code has weighed in.
|
|
36
|
+
|
|
37
|
+
### Pull requests
|
|
38
|
+
|
|
39
|
+
**Open an issue before writing non-trivial code.** Code is cheap to write; choosing the right change is the expensive part. An issue lets maintainers weigh in on the approach before anything is built, while an unsolicited implementation anchors the discussion on one solution. Open a pull request directly only when there's one obvious way to make the change: typos, broken links, or a clear-cut fix. Reporting those costs more than fixing them. They don't need the template; a one-line description is ideal.
|
|
40
|
+
|
|
41
|
+
**Describe what changed, not what it might fix.** The diff shows how. Broad claims steer reviewers the same way hypotheses steer investigators.
|
|
42
|
+
|
|
43
|
+
### Security
|
|
44
|
+
|
|
45
|
+
**Never report vulnerabilities publicly.** Report them privately as described in [SECURITY.md](SECURITY.md).
|
|
46
|
+
|
|
7
47
|
## Getting started
|
|
8
48
|
|
|
9
|
-
Badline needs SDL2, which is available from most package
|
|
49
|
+
Badline needs the SDL2 library, which is available from most package
|
|
50
|
+
managers. Building the native `badline` also needs the SDL2 headers
|
|
51
|
+
(`libsdl2-dev` on Debian/Ubuntu); see [native/README.md](native/README.md).
|
|
10
52
|
|
|
11
53
|
```sh
|
|
12
54
|
brew install sdl2 # macOS
|
|
13
|
-
apt install libsdl2-
|
|
55
|
+
apt install libsdl2-2.0-0 # Debian/Ubuntu
|
|
14
56
|
```
|
|
15
57
|
|
|
16
58
|
Install the dependencies and run the specs:
|
|
@@ -40,7 +82,7 @@ Check style before pushing:
|
|
|
40
82
|
bundle exec rubocop
|
|
41
83
|
```
|
|
42
84
|
|
|
43
|
-
##
|
|
85
|
+
## Tests and commits
|
|
44
86
|
|
|
45
87
|
- Add tests for any behavior you change.
|
|
46
88
|
- Write commit messages using
|
|
@@ -49,3 +91,53 @@ bundle exec rubocop
|
|
|
49
91
|
`fix:` prefixes decide what ends up in the next release.
|
|
50
92
|
- Leave the version and `CHANGELOG.md` alone. Both are updated
|
|
51
93
|
automatically when a release is cut.
|
|
94
|
+
|
|
95
|
+
## Skeletons
|
|
96
|
+
|
|
97
|
+
Leave out optional sections you have nothing for.
|
|
98
|
+
|
|
99
|
+
### Bug report
|
|
100
|
+
|
|
101
|
+
```markdown
|
|
102
|
+
### Expected behavior
|
|
103
|
+
|
|
104
|
+
<!-- What should happen. -->
|
|
105
|
+
|
|
106
|
+
### Actual behavior
|
|
107
|
+
|
|
108
|
+
<!-- What happened instead, as observed. Include the error message, if any. -->
|
|
109
|
+
|
|
110
|
+
### Steps to reproduce
|
|
111
|
+
|
|
112
|
+
1.
|
|
113
|
+
2.
|
|
114
|
+
3.
|
|
115
|
+
|
|
116
|
+
### Error output
|
|
117
|
+
|
|
118
|
+
<!-- Optional. Raw stack trace or log lines in a code block. -->
|
|
119
|
+
|
|
120
|
+
### Ruled out
|
|
121
|
+
|
|
122
|
+
<!-- Optional. Negative results only, e.g. "Still happens with caching disabled." -->
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Feature request
|
|
126
|
+
|
|
127
|
+
```markdown
|
|
128
|
+
### Problem
|
|
129
|
+
|
|
130
|
+
<!-- What you're trying to do, and what's blocking you. -->
|
|
131
|
+
|
|
132
|
+
### Current workaround
|
|
133
|
+
|
|
134
|
+
<!-- Optional. How you get around it today, if at all. -->
|
|
135
|
+
|
|
136
|
+
### Proposed solution
|
|
137
|
+
|
|
138
|
+
<!-- Optional, and brief. -->
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Pull request
|
|
142
|
+
|
|
143
|
+
See [.github/pull_request_template.md](.github/pull_request_template.md).
|