Apple //e vertical blanking period too short
I've been writing an Apple II program that synchronizes its drawing to the screen refresh using the vertical blanking flag and I thought I saw a problem with the way that OpenEmulator was handling the vertical blanking interval so I wrote a program to confirm it.
The Apple II has 192 displayed lines of raster (during which time, on an Apple IIe, memory location $C019 (RDVBLBAR) is negative) and 70 invisible lines of raster during the vertical blanking interval (during which time $C019 is positive). Each line of raster, both visible and invisible, takes 65 cycles.
My test program waits for the vertical blanking interval to begin and then repeatedly samples memory location $C019 every 65 cycles, counting how long the vertical blanking period and the display period each are, storing the results in memory where they can be inspected later.
Here's my test program's source code.
; SPDX-FileCopyrightText: © 2023 Ryan Carsten Schmidt <https://github.com/ryandesign>
; SPDX-License-Identifier: MIT
A1L = $3C ;general purpose A1 register low byte
A1H = $3D ;general purpose A1 register high byte
RDVBLBAR = $C019 ;vertical blanking flag
TXTSET = $C051 ;text
IDBYTE1 = $FBB3 ;machine identification byte 1
IDBYTE2 = $FBC0 ;machine identification byte 2
WAIT = $FCA8 ;delay at least 1/2(26+27A+5A^2) cycles
IDROUTINE = $FE1F ;machine identification routine
MONZ = $FF69 ;monitor warm start without bell
DATA = $1000 ;generated data start address
.proc main
bit TXTSET ;show text
sec ;set carry before identification routine
jsr IDROUTINE ;run machine identification routine
bcc @end ;if carry was cleared it's a IIgs
lda IDBYTE1 ;load machine ID byte 1
cmp #6 ;check for IIe or better
bne @end ;it's a II, II+, or III in II+ emulation
lda IDBYTE2 ;load machine ID byte 2
beq @end ;it's a IIc or IIc+
lda #<DATA ;load data start address low byte
sta A1L ;store in A1L
lda #>DATA ;load data start address high byte
sta A1H ;store in A1H
ldy #0 ;loop counter
@loop1: bit RDVBLBAR ;wait for the vertical blanking
bpl @loop1 ; interval to end
@loop2: bit RDVBLBAR ;wait for the vertical blanking
bmi @loop2 ; interval to begin
lda #0 ;2
bpl @start ;3
@a: tax ;2 |54 |65
inx ;2 |(55 last time)|
lda #1 ;2 | |
jsr WAIT ;29 | |
txa ;2 | |
nop ;2 | |
nop ;2 | |
@start: bit RDVBLBAR ;4 | |
php ;3 | |
plp ;4 | |
bmi @b ;2+1 if taken | |
; |
nop ;2 |11 |
nop ;2 | |
nop ;2 | |
nop ;2 | |
bpl @a ;3 | |
@b: sta (A1L),Y ;6 |10
lda #0 ;2 |
iny ;2 |
@c: tax ;2 |51 |65
inx ;2 |(52 last time)|
lda #1 ;2 | |
jsr WAIT ;29 | |
txa ;2 | |
nop ;2 | |
nop ;2 | |
bit RDVBLBAR ;4 | |
nop ;2 | |
nop ;2 | |
bpl @d ;2+1 if taken | |
; |
nop ;2 |14 |
nop ;2 | |
php ;3 | |
plp ;4 | |
bmi @c ;3 | |
@d: sta (A1L),Y ;6 |13
lda #0 ;2 |(12 last time)
iny ;2 |
bne @a ;2+1 if taken |
@end: jmp MONZ ;go to monitor
.endproc
You can poke my program into memory by entering the monitor:
CALL -151
and then pasting this in:
300:2C 51 C0 38 20 1F FE 90 5E AD
:B3 FB C9 06 D0 57 AD C0 FB F0 52 A9
:00 85 3C A9 10 85 3D A0 00 2C 19 C0
:10 FB 2C 19 C0 30 FB A9 00 10 0A AA
:E8 A9 01 20 A8 FC 8A EA EA 2C 19 C0
:08 28 30 06 EA EA EA EA 10 E9 91 3C
:A9 00 C8 AA E8 A9 01 20 A8 FC 8A EA
:EA 2C 19 C0 EA EA 10 06 EA EA 08 28
:30 E9 91 3C A9 00 C8 D0 C6 4C 69 FF
Run the program by calling its starting address:
300G
After two seconds, 256 bytes starting at $1000 will be filled with data. To show the first screenful of that data, type:
1000.10B7
This is the result on my real Apple //e:
1000- 46 C0 46 C0 46 C0 46 C0
1008- 46 C0 46 C0 46 C0 46 C0
1010- 46 C0 46 C0 46 C0 46 C0
1018- 46 C0 46 C0 46 C0 46 C0
1020- 46 C0 46 C0 46 C0 46 C0
1028- 46 C0 46 C0 46 C0 46 C0
1030- 46 C0 46 C0 46 C0 46 C0
1038- 46 C0 46 C0 46 C0 46 C0
1040- 46 C0 46 C0 46 C0 46 C0
1048- 46 C0 46 C0 46 C0 46 C0
1050- 46 C0 46 C0 46 C0 46 C0
1058- 46 C0 46 C0 46 C0 46 C0
1060- 46 C0 46 C0 46 C0 46 C0
1068- 46 C0 46 C0 46 C0 46 C0
1070- 46 C0 46 C0 46 C0 46 C0
1078- 46 C0 46 C0 46 C0 46 C0
1080- 46 C0 46 C0 46 C0 46 C0
1088- 46 C0 46 C0 46 C0 46 C0
1090- 46 C0 46 C0 46 C0 46 C0
1098- 46 C0 46 C0 46 C0 46 C0
10A0- 46 C0 46 C0 46 C0 46 C0
10A8- 46 C0 46 C0 46 C0 46 C0
10B0- 46 C0 46 C0 46 C0 46 C0
This is correct. It shows a vertical blanking period of $46 (70) lines followed by a display period of $C0 (192) lines, followed by another vbl period, etc. This is also what I get in Virtual ][ 11.4, Clock Signal 23.09.10, and MAME 0.259.
But here is the result I get in OpenEmulator 1.1.1-202203110628:
1000- 20 E6 20 E6 20 E6 20 E6
1008- 20 E6 20 E6 20 E6 20 E6
1010- 20 E6 20 E6 20 E6 20 E6
1018- 20 E6 20 E6 20 E6 20 E6
1020- 20 E6 20 E6 20 E6 20 E6
1028- 20 E6 20 E6 20 E6 20 E6
1030- 20 E6 20 E6 20 E6 20 E6
1038- 20 E6 20 E6 20 E6 20 E6
1040- 20 E6 20 E6 20 E6 20 E6
1048- 20 E6 20 E6 20 E6 20 E6
1050- 20 E6 20 E6 20 E6 20 E6
1058- 20 E6 20 E6 20 E6 20 E6
1060- 20 E6 20 E6 20 E6 20 E6
1068- 20 E6 20 E6 20 E6 20 E6
1070- 20 E6 20 E6 20 E6 20 E6
1078- 20 E6 20 E6 20 E6 20 E6
1080- 20 E6 20 E6 20 E6 20 E6
1088- 20 E6 20 E6 20 E6 20 E6
1090- 20 E6 20 E6 20 E6 20 E6
1098- 20 E6 20 E6 20 E6 20 E6
10A0- 20 E6 20 E6 20 E6 20 E6
10A8- 20 E6 20 E6 20 E6 20 E6
10B0- 20 E6 20 E6 20 E6 20 E6
Its vertical blanking period is too short at only $20 (32) lines followed by a display period that is too long at $E6 (230) lines.
You can exit the monitor and return to BASIC by typing Control-C followed by Return.
@zellyn I see you are the one who added Apple //e support to OpenEmulator (thank you!); would you have any idea where to look to fix this issue?