openemulator / libemulation

An accurate, portable emulator of legacy computer systems.
http://openemulator.github.io/
Other
45 stars 18 forks source link

Apple //e vertical blanking period too short #45

Open ryandesign opened 12 months ago

ryandesign commented 12 months ago

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. ```asm ; SPDX-FileCopyrightText: © 2023 Ryan Carsten Schmidt ; 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 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 commented 12 months ago

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