Files
8bitworkshop/test/cli/testvic20.js
T
Steven Hugg 9aa2490dba vic20: fix the text window geometry
The VIC-I draws a fixed 22x23 character window, centered in the picture.
The emulator used the VIC-II's display window registers, so the window was
placed at a garbage offset: the first character column was clipped in half
and the whole picture was shifted 24 pixels to the right to hide it.

- the new emulator core (chips) centers the window and takes its vertical
  position from the ROM, so NTSC and PAL ROMs both work
- the 24 pixel video shift is gone
- the platform loads res/vic20/vic20.bios (a real ROM set) when it is
  available, and falls back to the stub BIOS otherwise
- a regression test checks the geometry of the rendered frame
2026-10-22 11:11:09 +02:00

96 lines
4.3 KiB
JavaScript

var assert = require('assert');
var { loadPlatform } = require('../../gen/tools/emutarget.js');
/*
A tiny cartridge that programs the VIC-I and draws two characters, so
that the text window can be checked.
The cartridge file has a 2 byte load address, then the cold and warm
start vectors, then the "A0CBM" signature; the code is loaded at $A009:
$A009 A9 1B LDA #$1B ; bg color white, border color cyan
$A00B 8D 0F 90 STA $900F
$A00D A9 19 LDA #$19 ; upper border = raster line 25
$A00F 8D 01 90 STA $9001
$A011 A9 F0 LDA #$F0 ; screen pointer A13..A10
$A013 8D 05 90 STA $9005
$A015 A9 96 LDA #$96 ; screen pointer A9
$A017 8D 02 90 STA $9002
$A019 A9 00 LDA #$00 ; clear the screen page
$A01B A2 00 LDX #$00
$A01D 9D 00 1E STA $1E00,X
$A020 9D 00 1F STA $1F00,X
$A023 E8 INX
$A024 D0 F7 BNE $A01D
$A026 A9 06 LDA #$06 ; clear the color RAM, blue
$A028 A2 00 LDX #$00
$A02A 9D 00 96 STA $9600,X
$A02D E8 INX
$A02E E0 28 CPX #$28
$A030 D0 F8 BNE $A02A
$A032 A9 48 LDA #'H'
$A034 8D 00 1E STA $1E00
$A037 A9 49 LDA #'I'
$A039 8D 01 1E STA $1E01
$A03C 4C 40 A0 JMP $A040
$A03F 00
$A040 4C 40 A0 JMP $A040
*/
var CART = [
0x00, 0xA0, 0x09, 0xA0, 0x09, 0xA0, 0x41, 0x30, 0xC3, 0xC2, 0xCD, 0xA9,
0x1B, 0x8D, 0x0F, 0x90, 0xA9, 0x19, 0x8D, 0x01, 0x90, 0xA9, 0xF0, 0x8D,
0x05, 0x90, 0xA9, 0x96, 0x8D, 0x02, 0x90, 0xA9, 0x00, 0xA2, 0x00, 0x9D,
0x00, 0x1E, 0x9D, 0x00, 0x1F, 0xE8, 0xD0, 0xF7, 0xA9, 0x06, 0xA2, 0x00,
0x9D, 0x00, 0x96, 0xE8, 0xE0, 0x28, 0xD0, 0xF8, 0xA9, 0x48, 0x8D, 0x00,
0x1E, 0xA9, 0x49, 0x8D, 0x01, 0x1E, 0x4C, 0x40, 0xA0,
];
var CYAN = 0xFFFFF04D;
describe('VIC-20 video', function () {
it('should draw the 22 column text window centered in the frame', async function () {
this.timeout(60000);
var target = await loadPlatform('vic20');
await target.start();
var video = target.getVideo();
assert.equal(video.width, 232);
assert.equal(video.height, 272);
// load the cartridge that programs the VIC
await target.loadROM(new Uint8Array(CART), 'cart.bin');
// run until the cartridge has set up the screen (with a real KERNAL
// this takes a moment, with the stub BIOS it is immediate)
var color = function () { return -1; };
for (var i = 0; i < 300; i++) {
target.advanceFrame();
video = target.getVideo();
var px = video.pixels;
color = function (x, y) { return px[y * video.width + x]; };
if (color(0, 100) == CYAN) break;
}
assert.equal(color(0, 100), CYAN, 'the cartridge screen did not appear');
// the cartridge sets the colors before the window position, so let
// a few more frames pass before the picture is checked
for (var i = 0; i < 5; i++) {
target.advanceFrame();
}
video = target.getVideo();
var px = video.pixels;
color = function (x, y) { return px[y * video.width + x]; };
// the text window is 22 columns (176 pixels) wide and centered, so
// there are 28 pixels of border color on either side. The pixels
// inside the window are the background color or a character, but
// never the border color.
assert.equal(color(0, 100), CYAN, 'left border');
assert.equal(color(27, 100), CYAN, 'left border');
assert.notEqual(color(28, 100), CYAN, 'first text column');
assert.notEqual(color(203, 100), CYAN, 'last text column');
assert.equal(color(204, 100), CYAN, 'right border');
assert.equal(color(231, 100), CYAN, 'right border');
// the window is 23 rows (184 lines) tall, starting at raster line 25
assert.equal(color(100, 25), CYAN, 'above the text window');
assert.notEqual(color(100, 26), CYAN, 'first text row');
assert.notEqual(color(100, 209), CYAN, 'last text row');
assert.equal(color(100, 210), CYAN, 'below the text window');
});
});