Tuesday, 16 March 2021

Fixing initial problems discovered by DevKit owners

We now have 100 DevKits in the hands of their new owners, or very much on the way in the post. One of the purposes of this is to help us find and shake down bugs in the MEGA65... which have indeed started to flow in. So here is a summary of what we have fixed, and also some new things that have been implemented.

(Most of this was written several weeks ago, but I have had a busy patch returning to work, and getting ready to teach, so the draft has sat here for a while, almost finished. So I'm finally squeezing this out now that I have surfaced briefly for air.)

1. VIC-IV Raster Re-Write Buffer & Full-Colour Text Mode Bugs

There were several bugs identified in the VIC-IV's full-colour text mode and Raster Re-write Buffer (RRB) logic, which I have fixed.  

This includes using colour $FF in Full-Colour Text Mode, which now correctly uses the colour from colour RAM. If the VIC-IV has extended attributes mode set, then the colour is only 4-bit, but you have the VIC-III extended attributes, such as blink and underline available. If extended attribute mode is not set, then you instead have all 8 bits of colour RAM to select any colour from the palette.

2. Floppy Drive Was Not Working

People also reported that the internal floppy drive wasn't working:  First, when you configure it to be used, it seems to still use the SD card. Second, when you do select it from the freeze menu, it gives drive not ready or hangs when trying to read disks.

So to investigate, I have gone back to an earlier bitstream that is known to work with the internal drive.  I wanted to start here, firstly to make sure that the internal drive in my R3 system works.  Anton tested and found that commit 989d598 on the 138-hdmi-audio-27mhz branch was the last working commit for the internal floppy.

The only challenge right now, is I can't easily find any of the 1581-formatted disks I know I have hanging around the place.  I have found one little cache of disks, but the first disk I tried has the directory track erased, probably from a couple of years ago when there was a bug that had the write enable line set instead of cleared. So I can't easily test loading from that disk.  The second disk I found has the same problem.

Now, as I went through the disks, I used the magnetic flux histogram display to see when I had disks with valid data. Doing this, I made the chance discovery that HD disks are reading fine, just with the expected 1/2 distance between the flux inversions.  So I tried setting the floppy bitrate to double the DD rate to match the HD rate, and voila, I was able to read sectors from a PC formatted 1.44MB floppy disk (or is it an FD2000 disk? I don't have a PC to confirm). Either way, reading data from HD disks works.  A lovely side-discovery, but not particularly helpful to my current challenge. Also, we don't yet have an HD aware DOS for the MEGA65.

So back to my little cache of disks, and it looks like I don't have any that have valid directory tracks.  And as I don't have an old DOS PC hanging around, nor do we have write support on the MEGA65 floppy controller yet, I don't have a great way to debug this as easily as I would like.  I can at least test that the latest bitstream version shows the same behaviour, though.

Ok, so I have loaded the latest bitstream, and the first thing I notice, is that it doesn't seem to be enabling the floppy motor.  Well, the DOS doesn't, but if I write the correct value to $D080, the motor does go.  Nonetheless, a curious thing.  Okay, when I try to use the floppy test programme to display the histogram data, the motor doesn't start.  But if I clear $D080 and then write $60 to it again to start the motor and select the drive, it does start, and I start getting sectors being read. Once the motor is going, the disks read.  

So this is good progress: The problem is most likely that the motor gets stopped for some reason, or the motor start signal is otherwise ignored. 

Next challenge is that my oscilloscope is 700km away, so I can't probe the floppy pins to see if the drive thinks it should stop because of some invalid combination of signals, or whether the VHDL has some change in it that stops the motor.  I know that the drives can stop themselves, because I accidentally discovered this when toggling the /DENSITY select line, and noticed the motor stops until you release the /MOTOR and /SELECTA lines, and then assert them.

Around the time of the commit that corresponds to when this problem started, I plumbed the "drive B" control signals onto the floppy interface. So I am suspecting that this might be all interelated somehow. But again, the drive activates and spins when I write $60 to $D080.  So there must be some funny sequence in the that the DOS in the ROM does, that is upsetting things. Again, not sure if this relates to other signals on the floppy interface being twiddled and upsetting the drive, or if it is being cancelled by some internal logic in the floppy controller.

Yup -- that's the problem: The ROM toggles bit 2 to work around some bug in the real C65's floppy controller. The MEGA65's floppy controller has a different bug that causes the currently selected drive to sometimes not be considered, instead using the previously selected drive.  This combined to cause the MEGA65 to think that the ROM DOS was de-selecting the drive when it was actually selecting it.  The fix required changing only a couple of lines.

3. Floppy/SD Card Select Was Not Working In MEGA65 Configure Utility

The other problem with the floppy, was that selecting to use the internal drive in the MEGA65 Configure programme from the utility menu has no effect: It always uses the SD card. But configuring it until next reset using the freeze menu does work.  Here I suspect the problem is that we are setting the wrong register bits in the hypervisor when it applies the settings, as the drive selection logic did change a while back... Except that it all looks like its correct: Byte four of the config sector gets $01 when set to use the real drive.  The code in the Hypervisor stores that into $D6A1, and it seems that nothing else touches that register... except mounting D81 disk images.  That's almost certainly the problem: We need to NOT mount D81 disk images if we have set $D6A1 to use the internal drive.

4. ASW Instruction Did Not Set Carry Flag

Totally unrelated, someone else also discovered a bug in the ASW instruction, where bit 15 of the operand was not being copied into the C flag.

5. Q-Family Instructions Would Mess Up Following Instructions

On the topic of CPU bugs, we also discovered that the Q family of instructions that use the A,X,Y and Z registers together as a virtual 32-bit register were causing trouble: The flag to write 32-bits of data was not being cleared in these instructions, so all following normal instructions would keep writing multiple bytes, until a single-cycle instruction was encountered. Needless to say this caused various forms of hilarity when a couple of developers tried to use the Q instructions.  A big thank you has to go to mdf200 for working out various clues as to the cause of this problem, including realising that single-cycle instructions were implicated. 

6. Freeze Menu Bugs

Then we had some bugs with the freeze menu not resetting certain VIC-IV registers, resulting in a garbled freeze menu display. 

7. 16-Colour Sprite Mode Glitches Fixed

16-colour sprites had a problem where transparent pixels were only transparent if there were no other sprites behind them. If there was another sprite behind, then Weird Things(tm) would happen.

8. MEGA65 Defaults to PAL if no valid configuration sector is found

Previously it would default to NTSC for better monitor compatibility, but the MEGA65 Configure routine would show that it was set to the default setting of PAL.  This inconsistency was very confusing, and has now been fixed through the introduction of default-to-PAL, and a once-only on-boarding screen that appears in NTSC to allow users to select their preferred video mode.

The Freeze Menu now follows the choice of PAL or NTSC, instead of always being NTSC, which avoids the annoying "resyncing monitor" behaviour that would previously occur. 

9. Fix the use of alternate palettes in Full-Colour Text Mode (FCM)

The logic for switching palettes was fault, and has been fixed.

10. Audio DMA can now interrupt normal DMA operations

This makes it possible to use the DMAgic controller while play DMA-based audio, without causing problems for the audio playback.

New Features

There were also a few small improvements:

1. You can now trigger raster interrupts based on the horizontal raster beam position. Should be handy for horizontal sprite multiplexing.

2. The colour RAM contents is now used in 16-colour text mode (where each pixel is represented by a nybl, and the characters are thus 16 pixels wide) to provide the upper four bits of the colour of each pixel, with the nybl from the character data providing the lower four bits. 

3. The Raster-Rewrite Buffer (RRB) now provides a mechanism to do smooth vertical positioning of characters by setting the trim-pixel values during a GOTOX token. Those bits instead get read as a a Y offset for Full-Colour Mode characters, effectively adding 8 x value to the address. This removes the single annoying limitation that the RRB suffered previously, in terms of using it to display moving sprite-like objects.

4. Various improvements to the MEGA65 Configure programme.

5. Bitplanes can now use memory other than in banks 0 and 1, although they must all still reside in the same 128KB region, that must be aligned on a 128KB boundary. This is to allow a modified BASIC 10 ROM to support 256 colour screens while still having close to 128KB of RAM available for BASIC programmes and variables.

6. The Raster-Rewrite Buffer (RRB) now supports more effective controls for placing sprites in front of, behind, or between layers of graphics rendered using the RRB.

7. The MEGA65 now has an option to enable "CRT scanline emulation" via bit 5 of $D054. The on-boarding process now asks users if they would like this enabled. The result feels much more like using an original C65:

8. The dip-switches on the main board can now be read from the MEGA65. They are connected to the MAX10 FPGA, not the main FPGA.  This was a bit of work to get happening.  My wandering notes as I went through this process follow.

We have only 3 lines to connect the two FPGAs for normal communications.  One of those by default is used to communicate the reset button status from the MAX10 to the main FPGA (like the dipswitches, it too is connected to the MAX10).   That said, we can do a bit of skull-duggery to use it as a 3rd communications line.  

In theory, we can also use the FPGA_DONE pin of the main FPGA to communicate to the MAX10 FPGA. I had wanted to do this, but for some reason, I don't seem to be able to control it, even though I have put the right stuff into the VHDL to do so.  This is a bummer, because with four lines, I could do a nice high-speed link between the two FPGAs with TX, RX, CLOCK and SYNC.  This would allow low-latency control of the 12-pin J21 header (also connected to the MAX10), as well as reading the dip switches.  The reason we need to provide clock information, is that the clock speed of the MAX10 when using its internal oscillator is quite unstable: It can be anywhere between 55MHz and 116MHz according to the data-sheet. This means that a simple UART won't work, because the apparent baud rate will vary by a factor of two -- and UARTs would have to be much slower, anyway.

So we have just three lines. We could still do an SPI-like protocol, as at least that way we can still get higher speed.  But we don't need a lot of the complexity of SPI.  But having an explicit clock will make it much easier to do, so we probably can't avoid using one of the three lines for that.  We can at a small cost add a sync mechanism into the clock. As we know some reasonable bounds for the difference in clocks of the two FPGAs, we can create a mechanism where the clock from the Xilinx FPGA is used to drive the receiver logic, but then also be separately be monitored by some logic clocked by the MAX10's internal clock to detect if the clock doesn't tick for a certain period of time, that it signals a sync.

As not everyone will have an Arrow programmer on hand to update their MAX10 bitstream, I will also implement a backward compatibility check, where we check for the old behaviour of the reset signal from the MAX10 FPGA.  

So we have things working with the new MAX10 programme and new bitstreams, including the reset button, and reading the MAX10 programme version.  However, if we use an old bitstream with the new MAX10 programme, it gets held in reset. So we need a solution for that. 

In the MAX10 code, the line previously called FPGA_RESET_N, i.e., and active-low reset out signal from the MAX10 to the main FPGA, is now the XILINX_SYNC output from the main FPGA into the MAX10. That is, its direction has reversed, which makes backward compatibility a bit of a pain to achieve.  We are now also using XILINX_TX (transmit from main FPGA into the MAX10) and XILINX_RX (transmit from the MAX10 into the main FPGA).  Thus the better way to have this protocol, would be to swap the XILINX_SYNC and XILINX_RX lines, so that when an old main FPGA bitstream meets a new MAX10 programme, the MAX10 is still sending on the line that the main FPGA expects to see the reset signal.  Thus if we don't see the clock signal from the Xilinx FPGA, the MAX10 programme can go back to the old behaviour of having the FPGA_RESET_N signal (which will now be the XILINX_RX signal) follow the state of the reset button.

So the three pairs of signals we have between the Xilinx and MAX10 FPGAs are, together with their signal names from the current bitstream builds for each, that have the old reset button protocol working with old MEGA65 bitstreams:

Xilinx K16 (MAX10_RX) -> MAX10 L11 (XILINX_SYNC)

Xilinx L16 (RESET_FROM_MAX10) -> MAX10 K11 (XILINX_TX)

Xilinx M13 (MAX10_TX) -> MAX10 J9 (XILINX_RX)

The XILINX_RX signal on the MAX10 must be correct, because this is the pin on which the old reset button protocol operates, and we know that this is working.

So this means we probably have the MAX10 L11 and K11 signals switched. So we should have it instead like this:

Xilinx K16 (MAX10_RX) -> MAX10 K11 (XILINX_TX)

Xilinx L16 (RESET_FROM_MAX10) -> MAX10 L11 (XILINX_SYNC)

Xilinx M13 (MAX10_TX) -> MAX10 J9 (XILINX_RX)

Swapping those at least gets the protocol running again, based on the MAX10's LEDs. However, neither the reset button nor the MAX10 version data is visible on the MEGA65 core, so something must still be messed up.

So it looks like we should instead switch K16 and M13 on the MEGA65 side, because the max10_rx and max10_tx signals are actually backwardly labelled. 

Indeed, fixing that fixed it, and it now works as expected. So that one's done, now, too.

Next stop was to make it possible to enable/disable digital audio on the digital video output.  This is because some DVI monitors don't display a picture if HDMI-style audio is provided. So we have disabled this by default.