Closed leonbottou closed 6 years ago
This is... fantastic.
"the MIG RESET line is tied to both the /IOSEL line and the A14 ROM line which selects the alternate 16KB ROM bank"
Nice catch! I should have seen that.
I would like to chat, either via email or you can often find me at irc.a2central.com in the #a2c.chat channel.
If I'm interpreting your message correctly, your email is your firstname at lastname dot org?
Also, I can address this comment in your MIG commentary:
"According to some sources, the MIG was designed to allow a 1Mhz 65c02 to keep up with the 3.5" drive timing requirements. Although the self-incrementing bank register might help a bit, I remain unconvinced. "
It's not necessarily the IWM timing that needs to be addressed by the MIG. A 1 MHz 6502 can successfully read a 3.5" disk, but remember the data bytes are coming in every 16 cycles, and an unindexed read or write takes 4 cycles, an indexed read or write takes 5.
Here's part of ProDOS 2.0.3's read routine, pretty standard:
LDY #$AA
LDA #0
RDATA1 STA WTEMP ; (3 cycles) use zpage for checksum keeping.
RD4 LDX $C0EC ; (4 cycles) warning: self modified.
BPL RD4 ; (2 cycles if not taken)
LDA DNIBL,X ; (4 cycles, no page cross)
STA NBUF2-$AA,Y ; (5 cycles) save the two-bit groups in nbuf.
EOR WTEMP ; (3 cycles) update checksum.
INY ; (2 cycles) BUMP to next nbuf position.
BNE RDATA1 ; (3 cycles, no page cross) loop for all $56 two-bit groups.
LDY #$AA ;now read directly into user buffer.
BNE RD5 ;branch always taken!!!
The routine must: read the byte, denibbilize, store in the buffer, and update the checksum. Note the that it takes 26 cycles to do all that, leaving 6 cycles to spare for the IWM in "slow" mode for the Disk II. So that's not going to happen for the IWM in "fast" mode for the 3.5" disk using the same code.
To get raw data off of a 3.5" disk, code might do the following for Y bytes of data:
R1: LDA Q6L ; 4 cycles
BPL R1 ; 2 if not taken
STA BUF,Y ; 5 cycles, store in reverse order
DEY ; 2 cycles
BNE R1 ; 3 cycles
That's 16 cycles to read something that comes in every 16 cycles, no room for error. So we probably have to buffer the full sector's raw data somewhere. But where do we do it? Can't really write it to main or aux RAM, because existing code might be using it.
That's where the MIG RAM comes in... it's got enough room to buffer the entire sector. Examining the MIG RAM's contents seems to bear this out.
I've been meaning to disassemble and the 3.5" code in the IIc Plus, but I haven't really had the time.
Yes my email is firstname at lastname dot org .
I am afraid I never used IRC...
I can see your point about the timing. Clearly there is no way to denibblize on the fly. Also your solution does not exactly work because one needs to read more than the 256 bytes accessible by STA BUF,Y. So one needs to do something like
R1 LDA Q6L ; 4 cycles
BPL R1 ; 2 cycles when not taken
STA BUF1,Y ; 5 cycles
R2 LDA Q6L ; here with 5 cycles to spare
BPL R2
STA BUF2,Y
INY ; eat 2 additional cycles
R3 LDA Q6L
BPL R3
STA BUF3-1,Y
CPY #whatever ; eat 2 additional cycles
R4 LDA Q6L
BPL R4
STA BUF4-1,Y
BCC R1 ; eat 3 additional cycles
The trick is to spread the loop increment, test, and branch on multiple reads.I have seen this technique used in the ROM code. That said I agree that there is not obvious memory to do this and that we cannot do indirect addressing (we need a fixed buffer). So yes the MIG memory is certainly convenient for this.
Paradoxically, for my project, the trickiest part was to transparently remap the three drives managed by the MIG to the two apple35 drives simulated by kegs. I also spend a lot of time understanding what each of the external drives (the apple3.5 and the smartport ones) have to do to daisy chain properly. The apple35 need to do quite a bit of logic, that is
Meanwhile the Unidrives have to process messages when the stepper phases are in opposition. But since they don't know about 3.5SEL, they can respond when one is trying to access an nonexistent second Apple3.5 on the daisy chain. Fortunately this only happens when the firmware establishes the list of existing devices on the daisy-chained bus (so that they can be careful.) When the phases are in opposition, the last Unidrive has to de-assert the outgoing DR1ENB and DR2ENB in order to avoid triggering the 5.25 drives. I've read that a Unidrive knows that it is last by sensing the outgoing HDSEL line (this is signal that propagates in the reverse direction from the one that comes from the motherboard). They must conflict somewhere in the chain...
My example was contrived, I did not mean to imply the IIc Plus ROM was doing exactly that.
The ROM uses a lot of unrolled accesses to do reads. I’ve been engaged in disassembling it over the past year as I have had time available. It’s been slow-going as it’s less fun than building new things. :-)
Thanks for the explanation.
Leon, I have updated the README.md for ROM 5X to reference your universal emulators and subsequent changes to MAME that fix the Apple IIc Plus emulation there.
I'm closing this as an issue just to check the box. Thanks again for your insight!
I hacked Kegs (a 2gs emulator) to work with essentially all kinds of apple2 roms. As you can guess, the Apple IIc+ was the most difficult to get to work. I found your project while researching the MIG chip. I can now run the rom5 firmware and read/write the (simulated) apple3.5drives of the 2gs. I just tried your ROM5x and it seems to work fine. At this point I haven't yet implemented the ACIA --kegs simulates a z8530-- and the accelerator support is the one provided by Kegs (a 8Mhz ZipGS). See (https://github.com/leonbottou/kegs-universal) for the hacked kegs. The MIG simulation is near line 200 in moremem.c.
Sorry for making this an issue. I could not find another way to reach you. In case you want details, my email address is myfirstname>@<mylastname.org