Author Archives: Marcel

Microdrive mystery

Martyn Hill, while testing his brand new Tetroid SuperGoldCard clone, has discovered a strange bug where his QL crashed when he was loading a _scr file into the QL’s screen memory. It works fine without the SuperGoldCard. A lot of theories were put forward, like:

  • It’s a problem with the SuperGoldCard: turns out it works fine when QDOS or a very early Minerva version is used instead
  • It’s connected to the memory timing of the screen area: turns out is also happens in fast memory
  • It’s connected to the 68020 processor: turns out is also happens on the 68000 processor
  • The SuperGoldCard patches are wrong: I’ve analyzed all the patches and they all look fine. In fact the patch code is identical to Minerva’s code except for the timing loops. Still, it appeared to work with earlier versions of the patches, which makes it weird again.

Personally I couldn’t care less if Microdrives work or not and the fact that this bug was not discovered for so long strongly implies that most other people also don’t use Microdrives with SGC systems anymore. Still I have trouble resisting a good puzzle so I had a look. And then another one. And then ten more because this was a very elusive bug.

The problem is that not only is the bug located in ROM locations that are hard to debug anyway, the MDV code is so time critical that it’s impossible to step through the code. So how can one debug this? Hardware to the rescue! The SuperGoldCard very conveniently has a parallel port on board that can be accessed very simply by the software. By connecting a logic analyzer to all 8 data lines and sprinkling output commandos throughout the MDV code I can get a live trace of what the code is doing or output the contents of registers byte-by-byte.

In hindsight I should have found the problem much earlier because of the symptoms, but that’s easy to say after you know what’s going wrong. Let’s make a little quiz, here’s the code part with the problem and you can try to spot the bug:

        move.w  #blksize,d0     full block normally (512)
        cmp.b   lstblok(a0),d7  is it the last file block?
        bne.s   not_last        no - copy to end of it
        move.w  lstbyte(a0),d0  get the number of bytes in last block
not_last
        lsl.w   #blkbits-1,d7
        add.l   d7,d7           is it the first file block?
        lea     -md_deend(a1,d7.l),a5 where to put data normally
        bne.s   not_frst
        moveq   #md_deend,d1    yes - move on past the file header
        add.l   d1,a4
        add.l   d1,a5
        sub.w   d1,d0           copy fewer bytes
not_frst
        ror.l   #2,d0           long words, and save odd byte count
        bcc.s   unbf_dbr        carry means there is an odd word to do
        move.w  (a4)+,(a5)+     if so, do it
        bra.s   unbf_dbr
unbf_lop
        move.l  (a4)+,(a5)+     move a long word
unbf_dbr
        dbra    d0,unbf_lop
        add.l   d0,d0           see if there's an odd byte to go
        bpl.s   notabyte
        move.b  (a4)+,(a5)+     if so, do it
notabyte

Keep in mind that the code is not generally broken, it sometimes works! The problem also appears for the first block, so you can pretty much ignore the special handling of the last block. Found it? I’ll wait…

.

.

.

.

.

The “ror.l #2,d0” is a pretty clever way to both divide the register by 4 (because the copy loop does long words) while still remembering the odd bytes that also need to be copied. But it relies on one thing: that bits 16 and 17 of the register are zero. These bits are shifted into the lower 16-bits and are then used by the dbra instruction, which means that if they are set instead of copying 128 long words it will copy at least 16384. Talk about a buffer overflow!

You should now also see why it sometimes works. Remember earlier that I wrote “In fact the [MDV] patch code is identical to Minerva’s code except for the timing loops.”. The timing code in the original Minerva ROM is hidden behind a macro but in the end looks like this:

; For delays 5 to 19ยตs
        moveq #([us]*15-38)/4,d0        four byte sequence
        ror.l  d0,d0 

; For delays 21 to 309ยตs
        moveq   #([us]*15-50)/36,d0     six byte sequence
        dbra    d0,*

; ... etc, other variants are similar

For the (S)GC this is exchanged by loops like this:

        move.w  gmt_fgap,d0              ; 2800 us
        dbra    d0,*

I guess everybody can see the difference now, the original code clears the upper word of D0 and the replacement code does not. And as it happens the upper word is $FFFF from an earlier call to md_slave. All in all a very subtle difference, hard to spot by just looking at the code.

The solution I chose is it to exchange the “move.w #blksize,d0” line with “move.l”. That adds two bytes (every byte is precious in Minerva, there are not many left!), but this is the minimum I can get away with without relying on side effects of outside code, which is how this bug was introduced in the first place.

As this is the second fix from me for Minerva 1.98 I will have to think about how to mark these modified Minerva versions as increasing the version number is a no-go unfortunately. 1.99 is the last number we can use in theory before running into extended compatibility problems and I’m not even sure about this, 1.98 is still a safer choice.

Anyway, I hope this was interesting to read, leave a comment if you want. I will soon release a fixed binary version.

(Super)GoldCard boot sequence

The last few days I’ve spent way too much time analyzing the (Super)GoldCard boot ROM. The sources supplied along with SMSQ/E are only sparsely commented disassembly that was basically impossible to read. It irked me to no end that I didn’t understand the code and finally I did something about it. The process had a strange fascination like putting together a 10000 piece puzzle

Anyway, let’s begin. The ROM consists of three parts:

AddressNameContents
$0000-$7FFFGOLDFLP + RAM + TK2
$8000-$BFFFPATCHPatches + Basic extensions + PAR + network + DEV
$C000-$FFFFBOOTBoot/patch engine

GoldCard

On the Gold Card the memory map on boot looks like this:

AddressContents
$0000-$BFFFQDOS (read), RAM (write)
$C000-$FFFFBOOT section of GC ROM
$10000-$17FFF
RAM
$18000-$1BFFFQL hardware registers
$1C000-$1C0FFGoldCard hardware registers
$1C100-$1FFFFRAM
$20000-$3FFFF128kb RAM (including VRAM)
$40000-$4FFFFComplete GC ROM

QDOS boots normally, finds 128kb of RAM (because of the ROM) and executes the GC BOOT code at address $C000. This in turn initialises the hardware, copies and patches QDOS to RAM, copies parts of the GC ROM to RAM and finally issues another reset. This is why on the GoldCard the QL always boots two times.

Fun-fact: the GoldCard can boot without any firmware ROM, this makes it somewhat possible to inspect the above memory layout live.

 After boot the memory map looks like this:

AddressContents
$0000-$BFFFPatched QDOS in RAM, write protected
$C000-$FFFFROM port extension
$10000-$17FFF
GOLD section of the GC ROM
$18000-$1BFFFQL hardware registers
$1C000-$1C0FFGoldCard hardware registers
$1C100-$1C1FFGoldCard firmware variables
$1C200-$1FFFFPATCH section of GC ROM
$20000-$1FFFFF1920kb RAM (including VRAM)

SuperGoldCard

On the SuperGoldCard the memory map on boot looks a bit differently:

AddressContents
$00000-$0FFFFSGC ROM (read), RAM (write)
$10000-$17FFF
RAM
$18000-$1BFFFQL hardware registers
$1C000-$1C0FFSuperGoldCard hardware registers
$1C100-$1FFFFRAM
$20000-$3FFFF128kb RAM (including VRAM)
$40000-$4FFFFComplete SGC ROM (again)
$50000-$3FFFFFRAM
$400000-$40FFFFQDOS ROM

In this case the SGC ROM doubles as the boot ROM and gets executed immediately. This is why the SGC does not need to double-boot. Again QDOS is copied and patched and parts of the SGC ROM are copied, too. Unlike with the GC, the copies of the SGC ROM are write protected.

AddressContents
$0000-$BFFFPatched QDOS in RAM, write protected
$C000-$FFFFROM port extension
$10000-$17FFF
GOLD section of the GC ROM, write protected
$18000-$1BFFFQL hardware registers
$1C000-$1C0FFSuperGoldCard hardware registers
$1C100-$1C1FFSuperGoldCard firmware variables
$1C200-$1FFFFPATCH section of SGC ROM, write protected
$20000-$27FFFVRAM1, writes are mirrored to QL hardware
$28000-$2FFFFVRAM2, writes are only mirrored if SCR2 is enabled
$30000-$3FFFFFRAM
$400000-$40FFFFQDOS ROM
$4C0000-$4FFFFFExtended I/O area

Configuration

The (Super)GoldCard does not have any kind of RAM that survives without power but still can store a bit of configuration like if F1 should be automatically pressed on boot. Well, how can this be? This was some mayor kind of “heureka” effect while analyzing the code. The cards contain a realtime clock chip that does not possess any additional RAM either, but it has a register that controls the interrupt line. The interrupt is never used on the golden cards, so the firmware just (ab-)uses the 4-bits available to store the configuration! Really clever.

Patches

The topic of what kind of patching the cards do on boot is almost mythical and was basically the reason I started this in the first place. All patches have been decoded and commented and everybody can look at them now (download below). There are a few patches that remove the most common bugs from the original QDOS ROM and a lot more that are applied to every ROM including Minerva. In some cases bugs in Minerva have been patched, but in these cases they have also been fixed in Minerva, so they usually don’t get applied anymore. One huge part is replacement of the MDV, network and I2C code, as these are all very timing critical.

Most remaining patches are exclusive to SGC because of the added code cache handling and the difference in exception frames of the 68020 to the 68000. Also there is an emulator for the “MOVE SR,x” instruction that became privileged on later processors.

The Masterpiece

Quite many of the patches actually alter QDOS for use with a graphics card with more resolution. At first I thought this was somehow connected to the Aurora and wondered why the condition for their activation apparently could never be true. But then I saw that Aurora’s VRAM starts at $4C0000 and the patches are all for VRAM that starts at $4E0000. The only explanation is that this is all for Miracle Systems never release Masterpiece graphics card. They must have been pretty well along the development path if these patches all made their way into the default ROM already. It even goes so far as to patch PTR_GEN after it is loaded.

The interesting thing about this is that the patches could easily be altered to work with the Aurora. As I don’t own an Aurora this is not for me to do, however.

The code

Finally here is the source code for all to see. For this version it was important to me that the result is bit-identical to the original source code, even though I had a strong urge to to change some code along the way… The result is not completely bit-identical to the GC2.49 ROM, but mostly because the utility libraries have changed. I have verified that the patches are exactly the same.

I will also submit the changes to Wolfgang to incorporate back into the SMSQ/E source code.

(Super)GoldCard boot source code

QL-SD teaser

The QL-SD driver seems to be finished (note that it currently doesn’t work with the MiST FPGA board, but there are no more known problems with either the original QL hardware or the MiSTer FPGA machine).

Now the boring part has begun, which means hours of reading tax related stuff (selling stuff internationally is hard!), writing/updating the manual, preparing an order page, preparing shipping labels, etc. I really don’t enjoy this part of the process.

Anyway, as a short teaser, the hardware does exist now in some quantities:

I will probably open the order page publicly starting September, after my holiday.

QDOS: To LRESPR or not

Update: the old code had a bug if the EXE was made resident using the HOT_RES keyword (thanks to Jan Bredenbeek for pointing it out), updated code below.

Today I’ve had a short discussion about creating a QDOS executable that can both be LRESPRed (to install a thing) and EXecuted (to, erm, execute it). One important detail is that LRESPR must only work in the main BASIC, as otherwise the system will crash once the daughter BASIC is terminated. There are several ways to do it, but I’d like to share mine:

base    bra.s   start
        nop
        nop
        dc.w    $4AFB
        dc.w    4
        dc.b    'Test'

start
; Trick: on an EXE call a6 must point to either a BRA ($60) or JMP ($4E).
; both have bit 6 set ($40). On Basic a6 points to the MSB of sb_buffb.
; Bit 6 will never be set as long as QLs have less than 1GB of RAM ๐Ÿ™‚
        btst    #6,(a6)
        beq.s   lrespr                  ; Definitely LRESPR
        cmp.w   #$4afb,6(a6)            ; This check is somewhat optional...
        beq.s   job_start               ; but in case QLs ever have >1GB... ๐Ÿ™‚

lrespr
        moveq   #sms.info,d0
        trap    #1
        tst.l   d1                      ; Job ID = main BASIC
        beq.s   basic_start

; LRESPRed from daughter SBASIC/MultiBasic
        moveq   #err.nimp,d0
        rts

; LRESPred from main BASIC
basic_start
;       ...
        moveq   #0,d0
        rts

; EXECed as normal job
job_start
;       ...

QL-SD, QL-microSD and (S)GC battery

QL-SD

So, a short update on QL-SD, I have spent another few hundred Euros on parts and everything has arrived except the package with the SD-card connectors, which seem to be lost in the mail. These are needed for the double-SD adapters, which I expect will be pretty popular. Instead of waiting for them to show up I have ordered another batch of 100 connectors elsewhere which should hopefully arrive in 1-2 weeks.

QL-microSD

Urs was interested in the micro-SD variant that I have hacked together previously and initially I didn’t want to produce them. But then I wanted to try out another CAD package, KiCad, and this project seemed like a good way to start with it. I haven’t obsessed about this as much as I did on the MDV board and again I ordered the whole batch without having a prototype first, so if it works I have lots of microSD adapters to offer and if it doesn’t fit in the end I have not ๐Ÿ˜‰ But again I have a good feeling about this. These boards, too, should arrive in 1-2 weeks. Here’s a sneak preview:

(S)GC battery

Finally, this is apparently something everybody who ever built QL hardware will produce as some point: a replacement for the SAFT 40LF220 battery. In my case I just wanted to test another PCB service as they had a good offer going and as I finally got myself my own SuperGoldCard (donated by Jochen Hassler, thank you soooooo much) I needed a new battery solution anyway. The only difficult thing was my inner perfectionist rebelling against just using some wire for the four contacts, so I actually spent a few hours sourcing perfectly milled pins for them:

These can be ordered along with a QL-SD for a small price when I’m eventually ready for sale.

QL-SD update

Just a slight update before I go on holiday for a week. The design of the MDV adapter board has been finalized and I already have the PCBs here:

The board can be built into four different configurations of which I will probably offer two:

  1. Single slot drive using a ready-made daughter board soldered onto the MDV board:
  2. Double drive where one slot is soldered directly onto the MDV board and the other is on a daughter board stacked on top of it.

    The initial plan was that the upper slot is by default “WIN1” and the lower slot “WIN2”. But turns out the card in the lower slow is difficult to change when the upper slot is occupied, so I think it makes more sense to have a permanent “WIN1” in the lower slot and use the upper slot for data exchange. In any case, there are simple jumpers on the board so the final decision can be made by the user, no soldering necessary.

The other variants are fall-backs that I added in case the two versions above made problems because when ordering 50 boards without having a prototype first it’s good to have some options. Looks like I don’t need them, though.

A few parts are still on their way from China and a few more parts I need to order from the US after my holiday. I have bought 300 LEDs from China and initially I was very happy with them, but compared to brand-name LEDs they are a bit more “spotty” and less diffuse/homogeneous, so I won’t use them after all. Which also means that the colors are not yet defined, if you’ve got anything against amber/red then speak up now or forever hold your peace ๐Ÿ˜‰

Speaking of LEDs, I have added some solder pads where one can connect external LEDs (in one case I wired the original MDV LED to it). This is for the tinkerers and not used by default.

So, the project is still moving along, stay tuned.

Cueshell – The definitive file manager for the QL

24 years ago Albin Hessler released his file manager Cueshell into the world. It was and still is one of the most advanced programs for the Pointer Environment ever written, featuring a Multiple Document Interface (smaller directory windows within the larger application window) and drag&drop file management. Managing large directory trees became incredibly easy and I still use it very frequently. It was truly way ahead of its time and this might have been its problem, as commercially I think it wasn’t as successful as hoped. Some people might remember that we did a special QPC+Cueshell promotion bundle in the early days to help adoption, but I don’t know how well those did.

Some 13 year ago I made a feebly attempt to update it to the new WMAN2 system palette, but because visually it was so advanced and non-standard I never truly managed to do a version that would do it justice, so I still use the 4-colour version. It has aged quite well however:

A few days ago I asked Albin if he could provide me with the latest manuals etc so I could release it for free and he readily agreed. The manual, too, turned out to be very beautiful, with many screen shots and illustrations. So today I present to you the latest version Cueshell v2.14, I hope you take some time to check it out because it really deserves it.

Cueshell 2.14
Cueshell manuals

QL-SD news

(Summary at the end if you’re not interested in the details)

Some people know that I’ve been working for quite some time on making the QL-SD work with the late Stuart Honeyball’s masterpieces, the GoldCard and the SuperGoldCard. And I seem to have succeeded, but the way to success took a lot more time than I anticipated. A mix of simultaneous problems in the hardware connections, bus signals, driver software and CPLD chip made for quite a difficult debugging experience. Small changes in the CPLD code that should not have any logical impact made the thing not work anymore at all, etc. Hardware is weird! Good thing I don’t have hair anymore anyway.

But now that the problems appear to be solved there is no supply of new QL-SDs to spread the joy! Dave mentioned he’s working on an external version, but I quite like the internal ones and quite frankly after all this work I didn’t mind the idea of generating at least some small revenue for my time for a change. So two weeks ago I decided to have a go myself and designed a new replacement board that is a bit easier to manufacture than the originals but other than that very similar. I ordered a batch of 50 gold plated PCBs on the good faith that they will simply work and yesterday DHL express delivered the precious cargo:

I soldered one prototype and, surprise surprise, it worked flawlessly from the get-go! Pure adrenaline ๐Ÿ˜‰ The second board, made with lead-free solder this time, was a bit more stubborn but eventually succumbed to my superior solder skills (just kidding). Here’s a sneak peek:

Connoisseurs will notice that I’ve used bigger traces and components on the PCB to make it easier to produce, the space is there after all. What I haven’t finalized yet is the design of the MDV daughter board, which is really trivial but I wanted to wait if my main board worked before I invested even more money! Also Iย had the idea to provide a dual-card board and even made a working prototype out of my existing QL-SD adapter:

QL-SD dual card adapterQL-SD dual card adapter

What I didn’t anticipate were the small rails holding down the MDVs in the top of the case, so the whole thing almost but doesn’t quite fit. I’m thinking about lowering the main PCB to be flush with the screw-posts but I’m not sure how mechanically sound this would be and if it’s really worth the trouble. Tell me if you’re interested! I also tried a completely different approach, but that was more a thing done in jest, using an existing ventilation hole in the QL case (that sticker was actually put onto my QL about 28 years ago ๐Ÿ™‚ ):

TL;DR

  • QL-SD works great now with GoldCard INGOT 5 including Tetroid clone (I think INGOT 6 already worked before) and SuperGoldCard. The original hardware only needs an update of the CPLD code for this. I will probably provide an update service for a fee, tell me if you’re interested.
  • I have submitted my fixes and changes to the driver to Wolfgang (thanks again Wolfgang, without his driver I wouldn’t have started my quest!), he said he will check them out soon.
  • I started producing a new batch of QL-SDs, though hand soldering them is a bit tedious and I will have to see if I can speed up the process. Price has yet to be determined.
  • I created a prototype dual-card adapter, but mechanically it’s not sound yet and even if these problems are overcome it might be difficult to produce. Anybody interested in this? It is 100% compatible with the original QL-SD, of course.

So, tell me if you’re interested or have any other comment.

Debugging Minerva

Martyn Hill recently discovered a bug in later versions of Minerva, but couldn’t quite pin it down. I thought it might be nice to write up a little tutorial about how I try to tackle these kind of problems.

The most important thing of course is being able to reproduce the problem, which was the hard part here as I haven’t had any networked QLs for 20 years. I didn’t remember any of the commands and devices used and somehow one ULA died along the way, which didn’t exactly help matters. But in the end I got it going and yeah, I could get it to crash:

QL1:
  NET 1
  SBYTES neto_2,131072,32768

QL2 (the one that will crash):
  NET 2
  LBYTES neti_1,131072

The “LBYTES” never returns here. The first thing to do in these cases is loading QMON and simply activating it

LRESPR flp1_qmon
qmon
Qmon> g

This way we will ideally break into the debugger if anything fishy happens. So, try the repro again and bingo:

Excuse the quality, at this point I didn’t know I will be writing about this, I made the picture just in case I need any data from it later in the process! Two things will look odd for people experienced in QMON, the “__000000” and the “MULS.L”. The first prefix “__” is an extension that displays addresses relative to the job base, which makes debugging jobs so much easier. In this case the JOB is SuperBasic, which has a start address of 0, so we’re actually at the absolute address 0 here. “MULS.L” is a 68020 instruction and now I can be glad I did this on a BBQL because this way the crash happened as early as possible. I think both the job-relative and the 68020 features were added to QMON by me some 15 years ago and were probably never released, but it doesn’t matter for this exercise.

The next step is to look at the stack, hence the “d2 (a7)”. There we see “00000D28”, which could potentially be a ROM address. In this case I have assembled Minerva myself so I have the corresponding _MAP file ready, which is invaluable when debugging assembler code:

SECTION   00000C9C  00000D78                                            IO_SERIO

          00000C9C  00000D78  SRC_MINERVA_IO_SERIO
                    00000CA8    IO_SERIO
                    00000CAA    IO_RELIO

This looks legit, so we open the source file “io_serio_asm” and also have a look into DISA to check which instruction exactly is there

Bingo, there is a jump instruction directly in front of it, so we’re at the right place. We look for it in the source code

callit
        movem.l d4-d5/a1/a4,-(sp) save our registers
        jsr     (a4)            call the test/fetch/send routine
        movem.l (sp)+,d4-d5/a1/a4 restore our registers
tstret
        tst.l   d0              ensure set ccr before returning
        rts

It jumps to a4 and, referencing the picture above, a4 is 0. We can also see the contents of the saved registers on the stack “0000000F” for D4, “00000000” for d5, “000b6568” for a1 and again “00000000” for a4. The next long word is “00000d52” which again looks like an address, so where are we coming from? Again, looking it up in DISA and then searching the instruction sequence in the source we end up at the label “headr1”

headr1
        bsr.s   io_pend         see if there is a byte available yet
        bne.s   setd1           if not, or there's a problem, return updated
        not.b   d1              check the value of the waiting byte
        bne.s   err_bp          error if it isn't $ff

Ah, so we were calling io_pend, let’s look at this code

io_pend
*        moveq   #0,d0           test routine is the first element
        bsr.s   vectest         set up test routine address
        bra.s   callit          go do it

Lau commented out the “moveq” because he thinks d0 is 0 here anyway. We have a look at “vectest”

vectest
        exg     a4,d0
        btst    #0,d0           test lsb of address register
        exg     a4,d0
        beq.s   vecrel          if zero, go do relative vector
        move.l  -1(a4,d0.w),a4  pick up serio's absolute vector
        rts
vecrel
        add.w   (a4),a4         add relio's relative vector to get absolute
        rts

where we see that D0 is used as an index but should be the same going out as going into the function. No we have a look at theย QMON screenshot and see that D0 is actually “00000058”! So the assumption that it would be “0” doesn’t hold and this explains our crash. We include the “moveq” in the source code, reassemble and burn the EPROM and yes, it doesn’t crash anymore. Happy days ๐Ÿ™‚

The whole process maybe took 10 minutes, it was actually a pretty straight forward. For sure it took a lot longer to write it up ๐Ÿ˜‰ I know Martin has been working at this for quite a bit, so I thought I’d share my method in the hopes that more people can find and fix these kind of bugs in the future.

For everybody who is not at home assembling Minerva I have added an English and German version with the fix here:

Minerva 1.98 with I/O fix (English/German)

Clonetastic: QL-SD clone working with GoldCard clone

Every since I got my QL-SD interface I was annoyed with the driver support, especially on the PC side. I didn’t manage to fill the SD card without destroying the image one way or another. Then came Wolfgang Lenerz awesome QLWA compatible driver and now it works like a charm.

But only on my original QL, the QL-SD always had problems with the (Super)GoldCards of the world and especially with my Tetroid GoldCard clone, where it didn’t work at all. The general assumption was that the QL lines are too noisy and the chip employed on the QL-SD too fast so that all sort of trouble happens. To check for this I started building a QL-SD clone (thanks to Peter Graf for open-sourcing the hardware!) using a slightly older Xilinx XC9572XL architecture. But before I could finish that I finally did some measurements myself and found something interesting concerning my GoldCard:

When the ROM area is accessed the CPU puts the address on the bus and the motherboard generates the ROMOE (ROM Output Enable) signal. This is fed to the ROM chip, which in turn outputs the data for the address on the data bus. When the data read is finished, ROMOE is disabled again, the ROM stops driving the data bus and then the next address is put onto the address bus. Pretty simple. But now let’s look at this on the GoldCard, upper signal is ROMOE, lower signal is A0:

ROMOE/A0 signals

ROMOE/A0 signals

One can clearly see that the address line A0 begins to change even though ROMOE at this time is still high! This doesn’t harm much when accessing a ROM, it would just output some garbage which will be ignored anyway, but with QL-SD it’s a bit more complicated. This illegal state can trigger actions in the interface that were not requested by the software, especially when the driver code is executed from the ROM, too, as then obviously there are many more accesses to the ROM area. This also explains why some people apparently had more luck getting it to work when the driver was purely executed from RAM. Anyway, this can be fixed fairly easily. Problem is, I don’t have a Lattice programmer to change QL-SD, though one is on its way from China right now. But I did have my clone, so I worked with that:

Looks pretty wild, right? But what can I say, despite the long lines and everything, once my changes to the Verilog code were uploaded to the chip the interface began to work, without a single fault so far, even when the driver is executed from the ROM. With the original Verilog code my clone didn’t work at all, so it’s definitely not just the different chip.

Next step is waiting for my Lattice programmer to arrive (apparently today it was put onto an Airplane) and to reprogram the original hardware. I’m fairly confident that this will work, too, at least for the GoldCard. So far I still was not able to acquire a SuperGoldCard :-(, so I cannot tell in how far this would help there, too. Stay tuned!