beebem-windows
beebem-windows copied to clipboard
OPUS DDOS 3.45 usually not writing last byte of track
When using OSWORD &7F or OSFILE, the last byte of every(+) track written to disk is 00 when using Opus DDOS 3.45, although logging shows the correct values are sent to the FDC.
The same is not true when using Acorn DFS 2.26.
I can't see anything different in the order that FDC registers are read/written during successes and failures so I'm guessing it's timing related.
(+) If I perform these OSBYTE &7F calls:
- write track 77 with 10 sectors
- read 10 sectors back from track 77 (and compare)
- write track 78 with 10 sectors
- read 10 sectors back from track 78 (and compare)
- write track 79 with 10 sectors
- read 10 sectors back from track 79 (and compare)
tracks 77 and 78 writes a zero as the last byte on the track (disk image file shows that either 00 has been written or nothing was) and track 79 is correct when it's read back.
I've tried this with BeebEm versions as far back as 4.03 and it's the same.
I've also tried reducing and increasing the delay in DDOS between writing the last byte to the data register and sending the Force Interrupt command, but no change.
I'm happy to go and hunt down the relevant bit(s) of code in the FDC emulation; just wondering whether someone might (1) already be looking at this or (2) have a bit of insight into where/why this might be happening. I can see there are a couple of Opus-related comments in disc1770.cpp.
Thanks :)
Thanks Sam. I'm not aware of anyone looking at this, so any help you can give would be very welcome!
Quick update: Acorn DFS 2.26 performs multiple sector writes one at a time rather than all in one go, whereas DDOS writes them all in one operation.
When I take NMILock out of the equation during the 1770 poll function, the issue disappears on DDOS 3.45 (and a test program I wrote based on the datasheet). DDOS (and me) sends the ForceInterrupt command inside the NMI routine. Now to work out why it was being tested in the poll function in the first place.
@chrisn does a list of DFS* and a test Beeb program exist that the 1770 emulation has previously been tested with? I'm fine writing the program to give the FDC a workout, so maybe just a list of FS ROMs/versions? Everything seems fine with Opus DDOS 3.45, Acorn DFS 2.26 and ADFS 1.33.
When I take NMILock out of the equation during the 1770 poll function, the issue disappears on DDOS 3.45 (and a test program I wrote based on the datasheet). DDOS (and me) sends the ForceInterrupt command inside the NMI routine. Now to work out why it was being tested in the poll function in the first place.
This change was introduced in BeebEm 1.4 (see diff in disc1770.cpp), at the same time as Force Interrupt was implemented, although I don't know why (I haven't studied the 1770 emulation).
Hmmm. I saw the last change to that line was a very long time ago and felt sure I'd seen DDOS working since then. It would seem not. It does suggest it may have been added for a specific scenario, possibly related to Force Interrupt and/or Read Address. I'll write a program to put raw FDC access, OSWORD & all the other FS related OS* calls through their paces and run it against a large-ish selection of (A)DFS/machine type combinations then. I'll report back.
Actually, before I do that, NMILock appears to be related to the 6502 not attempting to re-enter the NMI routine whilst an existing one is running (haven't got the datasheet for 6502 open but I'm pretty certain NMIs aren't detected while one is being processed). The FDC has no idea what was going on with the internal state of the 6502, so I don't think it should be in the 1770 code at all. What do you think?
A further thought on that is that a WD1770PH 02-02 variant could be clocked at 16MHz to allow it to read/write HD floppy disks, although it was incredibly tight fitting a NMI handler in that wasn't too long in terms of CPU cycles. Perhaps it was related to an attempt to get that working? Are there any DFS's that claim to support HD floppies that you're aware of?
I still think I need to write a program to test Read Address, though. I haven't explicitly tried that, although I can't think of a reason it would be any different to a Read Sector command in terms of the timing of the DFS telling the FDC to stop sending data - there's plenty of time during the 'gap' following (or even before) the ID CRC to send Force Interrupt before the next byte fully appears under the head and the FDC starts prodding the NMI pin again.
Actually, before I do that, NMILock appears to be related to the 6502 not attempting to re-enter the NMI routine whilst an existing one is running (haven't got the datasheet for 6502 open but I'm pretty certain NMIs aren't detected while one is being processed).
Reading this and this, I'm not sure if that's true. The NMILock
variable has been in BeebEm since the very beginning, but I don't know why it's there. Other emulators (B-Em and JSBeeb) don't have a similar lock.
Timing diagram confirms that - a NMI can interrupt a NMI. Didn't know that - I guess there's usually only one NMI source in a lot of cases so unlikely to occur. :)
So shall we take the NMILock part out of the 1770 code? (probably not worth raising a PR for that - it's one line of code being changed). It doesn't really belong in an external chip's code.
I'm looking more deeply into the Read Address command now because DDOS isn't trying to switch densities when the initial SD Read Address command fails, where it does on a physical machine. It'd be good to get both of these aspects of the FDC working closer to 100%.
I might remove the NMILock altogether in my local copy and see if anything breaks. I wonder if we need to add timing before which a second NMI won't be recognised.
I've just done a quick test with Watford DDFS 1.54T from here, which seems to work if you select the Watford.dll FDC. Maybe we should distribute this ROM with BeebEm.
A set of tests would be really helpful, thanks for looking into this!
I might remove the NMILock altogether in my local copy and see if anything breaks.
Opus DDOS 3.45 seems OK with the NMILock removed, but Watford DDFS 1.54T doesn't like it (*CAT hangs and produces no output).
You said 1.54T worked with the Watford board selected before. Sure you had the right board selected during that last test? General behaviour I've seen with non-Acorn DFS's is to hang with the wrong board in.
Yes, in both cases I had Watford.dll selected. The first test was before I removed NMILock and it worked OK, and it hangs after removing NMILock.
Ok. I'll have a look at what it's trying to do, NMI code first. Assuming Shift+Break did the same? That FS is DD only, isn't it?
Yes, Shift+Break hangs in the same way. The DDFS I guess supports both SD and DD disks, although I only have SD images to test with. *CAT on a .ssd file reports "Single density".
Ah. Sounding similar to DDOS then. Do you know whether 1.54T uses 16 or 18 sectors in DD?
Assuming this is the correct manual (it's the only one I've found so far), it's 18 sectors per track.
Ok. Cool. Thank you. That will all give me some good pointers for analysing the code. It'll be something small that we haven't thought of, I'm sure :)
I hope so! This isn't an area I've looked at before, so I'm learning as we go.
When I removed NMILock from the 1770 code, 1.54T hangs. It's waiting for the contents of &1036 to have bit 0 clear. The NMI routine sets ?&1036 to ?FDC_STATUS_REGISTER most of the time, but when the byte counter reaches zero it sets ?&1036 to zero and then has a pause before sending the Force Interrupt command. In the emulation, during that pause, the next sector's byte is triggering another NMI, so when Force Interrupt is performed the value has been overwritten with ?FDC_STATUS_REGISTER again (including bit 0 indicating a busy status). When I slow the disc revolution time down a bit (1400000 instead of 500000) it takes a while but it does catalogue the disc.
So what I think is going on is that the Read Sector command isn't waiting long enough between sectors before sending the next sector's bytes. On a real machine, there's a gap between sectors (all the 4E bytes and the 00s, the ID, ID CRC, DAM etc.) so the NMI routine pause is nowhere near long enough to cause a problem - it wouldn't be interrupted by the next sector's data.
So, when I set LoadingCycles to (BYTE_TIME * 80) (for now) when it's a multi sector read and the last byte in the sector has been transferred, and change the disc revolution time back to 500000, it seems to be working. I'll do a lot more testing of this - and actually count how many bytes the datasheet says are the minimum between sectors.
Sorting out the Write Sector command is going to be a bit more tricky. At the moment it looks like it's going to need a bit or re-ordering because it writes a byte to disc and, if the command had the multi-sector flag set, immediately raises another interrupt, which is not correct; at the end of the sector it should wait for the gap time again before asking the CPU for the next byte.
I'm going to have to pause with this for the rest of the day. It's going kinda ok, but there are inconsistencies with whether or not it will write to the disc and let the NMI routine realise. I have successfully formatted a few discs, but it's about a 50% failure rate too, so I need to have a think about how that could be in a software emulation. There shouldn't be anything else interfering so maybe it's related to the Read Address command that's going wrong in Opus DDOS and DDFS is getting itself into a bit of a tizz, not realising it already knows the density of the disc/drive in question..
What disc image format are you using for DDOS/DDFS discs? Here are some links to related discussions:
- https://stardot.org.uk/forums/viewtopic.php?t=20187
- https://stardot.org.uk/forums/viewtopic.php?t=11924
- https://stardot.org.uk/forums/viewtopic.php?t=5821
I haven't settled on one yet. At the moment I've just copy/paste/modify the ADFS bits and told it the relevant numbers for 18 sectors instead of 16 and called it OPUS instead of ADFS.
I've now read those all to completion. I think it's a wider conversation for standardising what BeebEm uses internally and for other formats it could load/save (and import/export to/from). It would be nice to get all of that side of things into separate areas (VS filter folders) so that a disc format would have a standard interface (a bit like the DDOS/DDFS board DLLs - but hopefully not DLLs for a few number and boolean definitions) and importers/exporters would have their own place in the solution structure too. I guess that's another point for discussion. Maybe a Zoom call or two might happen? Things are generally solved faster when people speak instead of typing :)
Someone's working on a new format for load/save so it would be good to get them involved in the discussion because whatever is decided would/could have a big impact on future development, when, say, DeveloperX invents some amazing format that the whole emulation scene decided to use. It may or may not be important for them atm, but we should keep an eye on who's announced what for new file format support.
Consensus seems now to be for HFE as preferred format, at least for reading. Supporting this in BeebEm is likely to require rewriting the 1770 and 8271 emulation. I'd like to look at that separately though, and for now stick with an SSD like format.
It would be SO good to make all the DD fans happy with a disc format everyone agrees on. Let's do that.