I was expecting issues with the core on at least a few games that others had run into problems with. Specifically Joe Blade and Southern Belle and, well, expectations met :(
Whilst investigating issues with Joe Blade I happened on a short test program on the stardot forum. This highlighted differences between my core and the Electron in the way TX Empty and RX Full comm mode interrupts can fire.
It appears the Electron has cases where “TX Empty” and “RX Full” can trigger outside of their respective INPUT and OUTPUT comm modes. Dave has written a couple of short programs that test this, one of which is (I’ve added comments):
10 @%=4 20 FOR I=0 TO 1 30 FOR A=0 TO 6 STEP 2 40 B=?&FE00 ; B isr contents (FE00) 50 ?&FE07=&B0+A ; contents of FE07 = 0xB0 (mode 6 + caps on,motor off, read mode) ; +A = 0,2,4,6 for read,sound,write,n/a modes. 60 C=?&FE00 ; C = isr content 70 ?&FE04=65 ; 65 to cas data (also clears TX Empty) 80 D=?&FE00 ; D = isr content 90 FORJ=0 TO 1000:NEXT 100 E=?&FE00 ; E = isr content 110 PRINT~A,~B,~C,~D,~E ; hexidecimal print 120 NEXT 130 NEXT
On a real acorn this produces:
>OLD >RUN 0 80 80 80 80 2 80 80 80 B0 4 B0 B0 80 B0 6 B0 B0 80 80 0 80 80 80 80 2 80 80 80 B0 4 B0 B0 80 B0 6 B0 B0 80 80
However when I ran it even with a “working” load and save implementation the output was very different. The reason is my implementation uses independent state machines for read and write that had separate states for high tone detect, start bit, 8 data bits, stop bit and so on. After the electron ULA schematics were released, it was clear the real ULA handles it quite differently.
Without going into details, the Electron’s ULA (Ferranti based anyway) uses a single counter that is shared between INPUT, OUTPUT and SOUND mode. This means even if I/O is not active and the Electron is just outputting sound, the counter can hit the “magic” numbers enough times to trigger TX Empty or RX Full interrupts.
After a complete rewrite of the cassette I/O code to more closely resemble the ULA schematics my core now fully matches the output of the original Electron, on this test at least.
There’s still an issue lurking and that’s if you load the program and skip the soft-reset before running.
An Electron will output a slight variation on the above, but still have “B0” in it. My core has “A0” unless you do a soft reset. B0 means both TX and RD interrupts are set, whilst A0 means only the TX Interrupt is set. Whilst I know why my core is doing this, I’ve yet to determine why a real Electron does not also exhibit this behavior.
I’ve gone over the ULA schematics multiple times and cannot see why a real Electron is able to trigger RD Full after loading when a “1” bit (either the stop bit or the subsequent high tone) should be present in CDATA once loading stops which should prevent the counter from coming out of reset. I’m missing something but what remains a mystery for now.
Why is this a problem? Well, for the game “Southern Belle”, if the RD Full interrupt does not assert after loading completes, the game will remain at a blank screen forever. As a workaround I’ve cleared CDATA once the motor stops. This enables RD Full to trigger shortly after and Southern Belle to run. It’s a kludge but until I understand why a real Electron behaves differently, it will have to do.
Sound uses the same shared counter as cassette I/O, which is why you can’t play tunes whilst loading. Anytime the counter wraps it is reset to the last value that was loaded into it. In addition, each time a wrap occurs, two flip flops are toggled. The second of those is routed to an output pin producing a square wave, the frequency of which varies depending on the last loaded counter value.
The AUG1 notes the shared register should produce frequencies according to
With the above implemented, writing 0 or 255 to the shared counter register should (according to the AUG) produce a 62.5kHz or 244Hz square wave and indeed it does. What doesn’t work as written, is when you use the information in the User Guide and the Basic SOUND command to create a middle C tone, the frequency output is almost double what it should be.
Perhaps the AUG is wrong? If it is however, the schematics are equally wrong as they suggest the same implementation as I have and the same output range. Maybe the User Guide is wrong? Maybe I’ve misread the schematics and I’m wrong?
I’ve reached an impasse on this and ordered an Electron in the hope probing the hardware will help bring about an a-ha moment.
Modulo the sound bug, the core is now feature complete but that does not mean I’m by any means finished.
The OSD needs to support a tape display counter as well as ffwd/rwnd to make cassette usage a little more convenient. Joe Blade has a graphical glitch as does firetrack (I expect more game testing will highlight other issues too), most likely a problem with RTC interrupt timing.
With the newly released ULA schematics there’s also potential to improve the accuracy of other parts of the ULA implementation, assuming I can decipher them. The four sheets related to cassette I/O have proven tricky enough.
Finally, the Electron had expansion hardware, from a joystick port to floppy drive and more. There’s ample FPGA capacity remaining to consider providing support for at least some of those.
AUG - Advanced User Guide ↩︎