Closed ryandesign closed 6 months ago
CPU would ordinarily place the values from the input data latch and adder hold registers ($C050) on the address bus but because that's a soft switch not mapped to actual memory it somehow skips that step, leaving the address bus set to its previous value ($402).
Probably the CPU does not in fact skip setting up the address bus, but instead somehow the address bus does not influence the data bus for soft-switch addresses.
I don't have a real Apple II plus available for testing. It is possible that behavior differs between a II plus and a IIe. Don Lancaster describes this in his book Enhancing Your Apple II and IIe Volume 2, Enhancement 13, The Vaporlock:
Page 206:
8AFF: 166 ; The FIX2+ routine provides one extra
8AFF: 166 ; delay cycle to adjust for screen switching
8AFF: 166 ; differences between the IIe and II+.
Page 208:
8BAB:A9 06 265 FIX2+ LDA #IDBYTE ; ADD ONE EXTRA CYCLE ONLY ON
8BAD:CD B3 FB 266 CMP VERSION ; THE II+ TO EQUALIZE ON-SCREEN
8BB0:D0 00 8BB2 267 BNE SHOW ; DISPLAY MODE SWITCHING
8BB2:2C 20 C0 269 SHOW BIT SNIFF ; OPTIONAL MODE CHANGES GO HERE
The implementation error here is that:
The quick-hack fix is to modify line 745 of AppleII.cpp so that its section reads:
if(isReadOperation(operation) && address != 0xc000) {
update_video();
*value = video_.get_last_read_value(cycles_since_video_update_);
}
i.e. add an update_video
. Then, as if by magic:
The real fix will be marginally more involved, either:
DeferredQueuePerformer
and maintaining a temporary copy of Switches
within VideoBase::get_last_read_value
; oroffset
as an argument to get_last_read_value
and proceeding as if it were 0
.I'll try to figure out whether the whole lookahead thing is actually saving any real costs in order to pick a route. Quite possibly it's not.
I noticed this problem as I begin to write a program to automate the testing of emulator behavior with regard to the Apple II floating bus and vertical blanking.
On my real unenhanced Apple IIe if I am in text mode and the hires switch is on and the mixed switch is off and I switch to graphics mode while loading a byte from the floating bus:
then the first byte that got loaded into the X register is a byte from the text screen that was being displayed and the second byte that got loaded into the Y register is a byte from the hires screen that is now being displayed.
Virtual ][ 11.4 and OpenEmulator 1.1.1-202203110628 get it wrong: their floating bus switches to the new video mode too soon: both bytes are taken from the hires screen.
Clock Signal 23.10.29 (plus the fix for #1196 applied) gets it wrong the other way: its floating bus switches to the new video mode too late: both bytes are from the text screen. In fact I have to delay for thousands of cycles after switching video modes before Clock Signal's floating bus returns data from the new video mode.
Here is the source of my sample program that demonstrates the problem.
```asm ; SPDX-FileCopyrightText: © 2023 Ryan Carsten SchmidtYou can poke it into memory by entering the monitor with:
and then pasting this in:
Run it with the monitor command:
It shows and clears the text screen, fills $1400-$1800 (the area scanned by the Apple II/II+ floating bus during horizontal blanking when page 1 of text or lores graphics are shown) with $42, fills $2000-$4000 (hires page 1) with $7F, then shows the hires screen by loading a byte from $C050 into X, loads another byte from $C050 into Y, then switches back to text mode, prints the hex values of X and Y, and waits for a keypress before doing it all again.
The real Apple IIe usually prints
A0 7F
. A0 is a space with the high bit set (what the text screen is filled with) and 7F is what we filled the hires screen with. Instead of A0 it might print a value from the screen holes.OpenEmulator and Virtual ][ print
7F 7F
.Clock Signal emulating a IIe prints
A0 A0
. Emulating a II/II+, we would often see 42 instead of A0. Instead of A0 or 42 we might see other bytes from the screen holes.If you change the condition at
@here:
frombeq
($F0) tobne
($D0) with the monitor command:then a substantial delay of 17,093 cycles (approximately the duration of one complete frame, which would be 17,030 cycles) is introduced after switching to graphics mode and before reading the second floating bus byte, which seems to be a long enough delay to fix the problem.
You can experiment with different delay values by changing the value at
@delay:
for example to reduce it from 80 ($50) to 40 ($28):With that delay, some of the time I am getting
A0 7F
(correct) and some of the timeA0 A0
(switching too late). (The scaling of the delay value is quadratic, not linear.)The real Apple IIe's behavior makes sense to me based on my limited understanding of how the 6502 works and how the Apple II uses it. The 6502 talks to the RAM for one half of every cycle and the video hardware talks to RAM the other half of every cycle. The load immediate instructions take four cycles. If we begin in text mode, mixed off, hires on, and assume that video hardware is beginning to scan the first pixel of the visible screen, and we consider an instruction like
ldx $C050
executing at memory location $1047, then the sequence of events as I understand it is: