libemulation icon indicating copy to clipboard operation
libemulation copied to clipboard

Apple //e vertical blanking period too short

Open ryandesign opened this issue 2 years ago • 1 comments

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.

ryandesign avatar Oct 21 '23 08:10 ryandesign

@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?

ryandesign avatar Oct 21 '23 19:10 ryandesign