| Posted By
 BSZ on 2025-10-26 13:30:45
| FlexSD firmware for SD2IEC drives, V1.3.0 fw
Continuing the previous topic, a new version of the FlexSD firmware has been released, see project's homepage!
The new version is 1.3.0-fspp0, a snapshot of the current state. It's starting to accumulate too many changes, so it was time to make a package. 
One new feature of this version may be useful for C128 users: a basic KERNAL's "fast serial" support has been added. I have a slightly strange feeling about this, because I'm not the first person to have done this. Of course, I searched the internet beforehand and found two variations on this. One was a forum thread somewhere, one of the users posted about it, that he had made an implementation. However, the topic was quite old, none of the links worked, so I couldn't see that version. I was lucky to find source code for the another version, but unfortunately it was based on a too old sd2iec version and only partially complete. For these reasons I could not use this version either. However, what they both have in common is that neither of them was included in the "factory" sd2iec source tree.
In its current state, the basic communication and the so-called 'burst commands' LOAD are implemented. These are necessary for basic operation. The additional 'burst commands' are currently not implemented! Most of them can only be used for disk units, here they could work for disk images. These may be added later. (They are ready in the source codes found, perhaps they can be adapted from. But I should definitely find programs to test these 'burst' features.)
So far only I have tried this, I hope it works properly! At the moment it only fits in the firmware of drives with 128K program memory! Anyone who has a machine/drive or knows someone who is interested, please test it! 
The other change is that I have started to make my own hardware, which run this firmware, and its additions are included in the source. For now, there is no binary version of this in the package, it will be updated when the final schematic is available (and public).
The new version comes with an updated test suite, which can also be downloaded from the site. Of these, I would highlight the "a-detect" tool: a simple configuration part has been added compared to the previous version, with which the various functions of the SD2IEC drive can be set. Among other things, this (also) enables the fast-serial mode mentioned above. Attention: enable this mode only for C128! If the device is used with more than one type of computer, the 'auto' mode is appropriate. 
Again I have written a lot, the point is:
Everything (source codes, documentation, ...) is available on the project page.
|
|
Posted By
 siz on 2024-09-26 12:17:39
| Re: FlexSD firmware for SD2IEC drives, V1.3.0 fw
Great work! I'm going away for the weekend (tomorrow morning) but after that I'll definitely will give it a try. And I'll dig out one of my C128s too. Perhaps on Sunday but You know me: I'm not great at keeping deadlines. 
|
|
Posted By
 BSZ on 2024-09-27 16:31:59
| Re: FlexSD firmware for SD2IEC drives, V1.3.0 fw
@siz: Thanks in advance! So far I'm the only one who's tried it, it would be nice to see reports from others. But there is no rush. 
I've simplified the website a bit, maybe it's less chaotic. However, even now, this is not good: the information is in too many places. I will also post the basic user information directly on the site. Or I could include it in the downloadable firmware package. I am still thinking about it.
|
|
Posted By
 ytm on 2024-10-02 16:03:28
| Re: FlexSD firmware for SD2IEC drives, V1.3.0 fw
Great news!
I have toyed with using burst commands and fast serial for GEOS disk driver. This branch: https://github.com/ytmytm/geos/blob/feature-drv1571burst/drv/drv1571burst.s has 1571 disk driver which loads sectors with U0,0 and saves with U0,2 commands. The only other command used is inquire: U0,4 to check for disk change. The code is shorter. copied almost exactly from 1571 user's guide, but performance was about the same as the original IEC serial protocol.
If you would like that for testing I can build a boot disk image for you.
|
|
Posted By
 BSZ on 2024-10-03 16:19:53
| Re: FlexSD firmware for SD2IEC drives, V1.3.0 fw
@ttm: Unfortunately, I have not yet encountered the C128 GEOS, I only saw the C64 version from a distance. But... The original version don't use the '71/'81 fast serial transfer? The original sd2iec firmware has GEOS support for two versions. (I haven't tried these yet either.) But these are - by nature - for version C64, version C128 uses different disk routines?
Because of all the above, the purpose of your project is not entirely clear. Have you created a disk drive 'driver' that works for 1571 using only burst commands? Not put any own code to the drive? 
If you would like that for testing I can build a boot disk image for you. If you can simply make a disk image that GEOS can load using only this "no custom code" device driver, I'd appreciate it. I think these block commands are easy to create. (Although sometimes I am surprised. )
Off: this testing part is always problematic. I usually make a test program for the features I add, but I don't have a collection of programs to check the original code. Unfortunately, this fast-serial part is only interesting for C128, and it would be nice if you didn't have to create your own test programs for these functions. However, I don't know of any programs that originally use these functions. For this reason, any little help is greatly appreciated. Of course, this also raises the question: is it worth doing? 
|
|
Posted By
 ytm on 2024-10-03 18:48:33
| Re: FlexSD firmware for SD2IEC drives, V1.3.0 fw
GEOS 128 used the same IEC fastloader as GEOS 64, this is already supported by sd2iec firmware.
The original GEOS 128 didn't use any burst features. All the disk drivers were almost exact copies of those from GEOS 64. They only had to change the code to enable/disable I/O from manipulating $01 into $FF00.
Yes, my 1571 burst disk driver doesn't use any drive code, just U0<0,2,4> commands for block read/write/inquiry. It's much shorter than the original.
I just wanted to check how it would perform comparing to the original fastloader. It turns out the speed is almost the same, so it was not worth pursuing this further, but it's a nice example of block-read and block-write commands.
Here is the boot disk image: https://drive.google.com/file/d/17qJ4FBybRc5i_inv3LSWuR0a5lFjZlhX/view?usp=sharing
And here is the relevant code: https://github.com/ytmytm/geos/blob/feature-drv1571burst/drv/drv1571burst.s
The only interesting parts for you would be next to __ReadBlock / __WriteBlock (around line 913). There is nothing original here, it was mostly lifted from the 1571 User's Guide.
|
|
Posted By
 BSZ on 2024-10-13 12:50:19
| Re: FlexSD firmware for SD2IEC drives, V1.3.0 fw
@ytm: Thank you for your effort and infos! I have saved the disk image. I'll try it sometime in the next few days! (First with a factory 1571 so I know what I'm looking at! ) Then I will see how complicated it is to implement in FlexSD firmware.
Thanks again, I will post developments in the forum.
Edit & Off: I had a little problem with my '71 drive, but this has been solved. I tried the GEOS disk above, it seems to work fine! Now "only" need to implement the necessary commands on the fw side. 
|
|
Posted By
 BSZ on 2025-10-26 14:54:41
| Re: FlexSD firmware for SD2IEC drives, V1.3.0 fw
Status update after one year: 
A new version of the FlexSD firmware (1.3.0-fspp1) has been released, see project's homepage or mirror.
It was a bit difficult to get this far, but here it is at last. Compared to the previous version, the above-mentioned "burst" commands contribute the most. The sector-handling "burst" commands currently only work with D64 + D71 disk images, but D81 disk images will be added later. By the way, this is probably the most pointless development ever. These block commands were primarily designed to enable CP/M to handle MFM disks at the sector level with the drive. However, the firmware can only handle CBM DOS disk images and does not support any MFM disk image formats. This means that CP/M will not yet be operational after this development. (But I don't know if that matters. The C128 is one of the worst choices for running CP/M anyway.)
But at least I have seen that GEOS works as described above:

However... It does not work properly with the current downloadable firmware. (I know the cause of the error, the solution needs to be discussed.) The development involved a lot of debugging, which ultimately revealed an error that may only be new to me. To solve the problem, I had to modify the firmware in a way that I hadn't planned at all. For this reason, it would be worthwhile for many people to test this version. The modification should not cause any problems, but this can only be determined through normal use. This test is, of course, platform-independent: use the device with the new firmware and see if there are any unexpected operational errors that did not occur before.
Here are the downloads: FlexSD 1.3.0-FSPP1 firmware binaries TestCodes 1.3.1 Everything else (source codes, documentation, ...) is available on the project page. (mirror)
I will soon write a "short story" about the progress of the debugging process. Some instructive things came to light, but this is partly off-topic.
|
|
Posted By
 BSZ on 2025-10-27 19:11:16
| Re: FlexSD firmware for SD2IEC drives, V1.3.0 fw
A little Tl;Dr story about development, which is partly off-topic:
I wrote above that it would be nice if I didn't have to create test programs for this topic myself, which is how GEOS128 came about, so thank you again for that! However, even before implementing the "burst" commands, it was decided that I couldn't skip my own tests:
- If something doesn't work, a vague error like "not good" won't suffice; a specific test will be required anyway
- Once a feature has been implemented, it would be good to test it separately
- In fact, these functions are poorly documented that you first need to try/experiment with a factory configuration (C128+1571) to see how these commands work
For this reason, a test program was developed, which can be used to first test the operation of the commands to be implemented in the factory configuration, and then to check the operation of your own implementation. Then, the commands were prepared in the firmware, which (for the most part ) work the same way with D64/D71 disk images as the 1571 works with regular disks. Then I started the GEOS disk image linked above on C128, which "booted up" but then crashed. After several attempts, it crashed each time with a different error...
The most likely cause of the above "random" error may be a data transfer problem (incorrect loading from the drive), so a test specifically designed to check data transfer has been created. Since the operation of "burst" commands is important here, especially sector reading (and writing), the test was as follows:
Both commands have a "notransfer" and a "transferonly" parameter. (These are mutually exclusive, so perhaps there was a better way to solve this... Anyway, they were removed from 1581. ) When writing to a sector, if "transferonly" is activated, the data block is only placed in the drive buffer and no writing takes place. If "notransfer" is activated, the data block in the buffer is written to the disk and no data transfer takes place. The counterpart to this is that when reading a sector, in the case of "notransfer," the block read from the disk is only stored in the drive's memory and is not transferred. With "transferonly," this memory can be retrieved from the drive. The test code sends a block of "random" data to the drive using the "transferonly" parameter for sector writing. Then, using the "transferonly" parameter for sector reading, the previously sent data is returned. The received data is then compared with the sent data. If it matches, it is repeated; if there is a discrepancy, it stops with an error.
This test ran for a few rounds with a 1571, then I tried it with my own FlexSD fw solution, and the result was unexpected. My own implementation ran through many cycles without error, then suddenly communication froze. So apparently there was no error in the data, it simply froze. To find out what might be causing this, I started modifying the data transfer code on the computer side. At first, I made a change that "shouldn't" cause any change. However, the result of the very first test was that even the factory 1571 test freezes! (It runs a few "rounds," but often doesn't even reach 100.)
Since the amendment should not have affected anything, it was necessary to take a step back: we need to understand why this is happening. First, you need to find out what is wrong with the computer's code. Once you know that, you can move on. But here, it first became clear that the rabbit hole is much deeper than I had expected.
In order for the following to make sense, a few basic things need to be explained: there are four wires for communication between the drive and the computer. Two of these are of interest here: CLK and DAT. All of these are at a high level when in an "inactive" state. And both the machine and the drive can pull them down to a low level. But only low, so if "anyone" on the bus pulls the line down, it will be low; no one can "force" it to be high. It will be high if "everyone" turns off the pull low. The other two lines are ATN and SRQ: they work the same way. However, only a computer can pull ATN low; peripherals are (generally) unable to do so. The SRQ is only used here for "fast serial" data transfer, but the programmer never encounters it directly (its level is not visible and cannot be switched "manually"); this is handled by the hardware. In "fast serial" data transfer, the data bits travel in sequence on the DAT (as in normal transfer), while the SRQ takes over the role of the CLK, timing the bits.
The "burst" data transfer itself takes place as follows: first, the computer sends the desired "burst" command to the drive in the usual way (LISTEN, SECOND, burst command+parameters, UNLISTEN). Then, the side receiving the data signals to the sender that "ready for receive" by switching the current level of the CLK line (if it was high, it pulls it low; if it was low, it releases it). (Hardware transfer takes place on the SRQ + DAT lines, which do not require CLK, so CLK freely usable the "ready for receive" signal here.) If the sender detects a change in CLK, it writes the data to be sent to the appropriate register of the peripheral (in this case, a CIA chip on both sides). As for the SRQ+DAT lines that "transfer" the data BYTE from the "hardware" to the other side, the software no longer has any task to perform. The receiver waits for the data to arrive. When it arrives, and the next one receive is ready, it changes the CLK status, and so on.
But back to my "falling" test: after many tests, I concluded that the test code on the side of the machine is fine and is not causing the error. But then what is? One thing is certain: the problem always occurs when reading data from the drive.
This was the original test code: (from memory, I hope I didn't make any mistakes... )
--- C128 code: --- JSR sendburst_rdonly ;Burst command: "Read sector, transfer only" send LDY #$00 cycle: LDA $DD00 EOR #%00010000 ;Toggle CLK drive, ready for new data STA $DD00 LDA #%00001000 ;SD bit waitd: BIT $DC0D ;test SD flag BEQ waitd ;if no new data, wait LDA $DC0C ;Read received BYTE STA ($xx),Y ;Store data INY BNE cycle ;Receive 256 BYTE
-----
The above code is simple: it sends the "burst" sector read command to the drive, then "reverses" the CLK line (indicating to the drive that data reception is ready). Then it waits until the data arrives, reads it from the CIA register, saves it to memory, and then jumps back to CLK inversion for the next piece of data. It does this as many times as it receives BYTEs. This seems to work fine with 1571, but freezes with the SD2IEC implementation. The modification is as follows:
--- C128 code: --- JSR sendburst_rdonly ;Burst command: "Read sector, transfer only" send BIT $DC0D ;Clear flags LDY #$00 cycle: LDA $DD00 ...
-----
The only difference is that the SD flag that has not yet been set is deleted before the first data request. And this causes even the 1571 communication to stop from time to time. 
At first, 1571 DOS became the suspect. This type of "application" that the test performs is unusual, perhaps even faulty...? Studying the DOS ROM sources gave me a clue: when "data transfer only" mode is running, DOS does not disable interrupts during the process described above. (However, it does disable them when reading is involved.) However, upon further examination, this part should not produce such an error (the machine simply waits for the data, but the transfer becomes slower).
The actual error was finally caught by replacing the "random" data sent to and returned from the drive with a "simple number sequence" and placing the received data at the top of the screen. This showed that as long as everything was fine, the expected "smooth number sequence" appeared, but when it froze, the first or first two bytes of the "number sequence" were missing! In other words: somehow, the synchronization falls apart right at the beginning...
And here we have a suspect, but this requires a little explanation. Again... 
During normal data transfer between the machine and the drive, the bus status is such that both the CLK and DAT lines are low between BYTE transmissions. But not just anyway! In this case, the receiving side keeps the DAT line low, while the sending side keeps the CLK line low. If the sender wants to send the next BYTE, it raises the CLK line high. If the receiver is already able to receive the data, it detects the high CLK and releases the DAT. The sender then uses these two lines to "transfer" the BYTE to be sent to the receiver. (Or, in the case of "fast serial" transmission, data is transferred via the SRQ+DAT lines.) At the end, the receiving side pulls the DAT line low (and leaves it there), indicating that it has received the BYTE. (If this does not happen, "?DEVICE NOT PRESENT ERROR." is displayed. ) The sender also ends the transmission with CLK low. Thus, after the BYTE transfer, the bus returns to the "busy but waiting" state, from which the entire previous process started. (When addressing devices, the computer sends data to the drive, so during data transfer, your computer keeps the CLK line low, while the drive keeps the DAT line low.)
In this case, the above process is interesting because the following process still takes place when the "burst" command is transmitted: the LISTEN, SECOND, burstcommand+data, and UNLISTEN bytes are sent to the drive using this method. When addressing the device, the LISTEN, SECOND, and UNLISTEN codes are also sent in this way, with the difference that the ATN is also low.
The command ends with a call to UNLISTEN, and this KERNAL routine has come under suspicion. This is because in the bus's idle state, all lines are high, and sending BYTE still ends with everything low. For this reason, UNLISTEN releases the ATN + CLK line in some way after data transmission to restore the "idle" state on the bus.
Here is the relevant part of the C128 KERNAL ROM source code, but this is largely the case on all machines:
--- C128 KERNAL ROM: --- E526 A9 3F unlsn lda #$3f ;unlisten command E528 48 pha E529 AD 0A1C lda serial (*fs*) E52C 29 7F and #$7f (*fs*) E52E 8D 0A1C sta serial ;reset fast serial flag (*fs*) E531 68 pla E532 20 E343 jsr list1 ;send it & then release all lines ; release all lines E535 20 E4D7 dlabye jsr scatn ;always release atn E538 8A dladlh txa ;delay and then release clock & data E539 A2 0A ldx #10 ;delay approx 60 us E53B CA 10$ dex E53C D0 FD bne 10$ E53E AA tax E53F 20 E545 jsr clkhi E542 4C E557 jmp datahi
-----
What it does is sends the UNLISTEN code ($3F) to the drive ($E532: jsr list1), then releases the ATN line ($E535: jsr scatn). It then waits a "little" ("delay approx 60 us") and releases the CLK. (And DAT too, but that's already been released by the machine.)
Here, there is a "healthy" 60µSec wait between turning off the ATN and CLK line, but... This time can be extended by a DMA line inserted here! (Remember: the screen is turned on!) This time can be waited for on the SD2IEC firmware (in the first version, I waited a healthy 250 µSec...). The 1571 is still busy evaluating the received command, so this shouldn't be a problem...
However, the fact that the beginning of the "burst" communication is lost can be attributed to this. This is because if, after the ATN is released, the drive arrives "too early" for the given "burst" command to check the CLK to see if the next data can be sent, this causes the error... But this can be avoided with a fixed wait. However, there is another problem: traditional data transfer is "time-critical," which means that the machine (and the drive) prohibits interruptions during BYTE transfer. However, interrupts are enabled during the time between BYTEs (when both CLK and DAT are low). (This is why it can work even when the keyboard under loading, for example.) Unfortunately, the serial routines are such that there is SEI before sending and CLI at the end. (Instead of saving + disabling the interrupt at the beginning and restoring its status at the end instead of enabling it permanently.)
This is precisely the problem with the above UNLISTEN: the interrupt is enabled after the code is sent! So, the time between ATN and CLK release can be extended not only by a DMA line (with predictable timing), but also by an interrupt, which makes the CLK release time unpredictable! And that's where the problem lies: if an interrupt occurs between the release of ATN and CLK, the drive "gets there" to process the burst command before CLK is released, sees that CLK is already low (even though it is STILL low), and sends the first BYTE. Then, when UNLISTEN finally gets to the point where it actually releases the CLK line, the already running "burst" command detects that the CLK status has changed again and immediately sends the next BYTE.
So far, so good. If the machine clears the "SD" (Serial Data, data received) flag before the transmission cycle, communication will be disrupted. But how can it remain good if the flag is not cleared? Probably because of the following: the drive sends the first BYTE "prematurely" due to the slippage of the UNLISTEN end. Then, when UNLISTEN releases CLK, the drive sends the next one... However, after releasing CLK, UNLISTEN ends and control is returned to the calling program. At this point, it immediately switches CLK to another state and checks whether any data has arrived. And it has, namely the first BYTE! (The second one is on its way... ) It reads the received data, saves it in memory, and at some point the second BYTE arrives. Then the machine switches CLK again, but the second BYTE is already in the data register, which traveled on the bus under the previous ones... In other words, compared to the machine's CLK switching, the drive is already two BYTEs ahead! If this sequence is not interrupted at the "wrong time" by something, then the whole process can run through with all data in place. The key here is probably that the drive is not "too fast" and does not try to overtake the machine. In contrast, my SD2IEC implementation is faster, and the first data is lost (it runs into the next one).
This story is actually a nice KERNAL bug. Why doesn't this seem to cause any problems? Well, in normal communication, after the device is "unaddressed," the continuation always begins with "addressing," which starts with ATN low. That only happens when UNLISTEN has already ended. This only causes problems if non-traditional communication takes place on the bus after UNLISTEN. This can happen if, for example, the command launched its own program in the drive, which can cause problems on all platforms and with all types of drives. The point is that the code should respond to CLK low at the beginning... The same applies to "burst" commands, which also respond to CLK low after the UNLISTEN code. However, this does not seem to cause any problems here, so what is happening? If the machine-side code does not clear the "SD" flag after the command, then commands whose response contains a status code in the first BYTE, and that code happens to be an error code, will still arrive earlier, but the machine will be able to read them. If it is not an error code, then usually some kind of disk operation precedes the data transfer, which takes "a long time" (even seconds), during which time the interrupt routine on the computer side simply ends... In the above test case, the data comes back immediately after the command is sent, which is many bytes, so this can trigger this state.
The obvious question is: should something be done about this? I would say it wouldn't hurt. This could be fixed by patching the KERNAL on the machine, but for obvious reasons that's not going to happen. However, the programmer can fix it. My UNLISTEN code from the test turned out as follows:
--- C128 code: --- LDA $0A1C AND #%01111111 STA $0A1C LDA #$3F ;UNLISTEN code JSR $E343 ;send SEI JSR $E535 ;continue original UNLISTEN code CLI RTS
-----
At the beginning, the 'bit clear' is the beginning of KERNAL UNLISTEN, then sends the corresponding code on the bus, then disables the interrupt, executes the rest of UNLISTEN by releasing ATN + CLK, then enables the interrupt, and finishes. With this modified UNLISTEN code, the test code described above (which clears the SD flag) ran for hours with 1571, as well as with my own implementation.
This "discovery" will not fix the "army of ready-made programs," plus it does not necessarily cause visible errors in the first place... The reason why this had to be dealt with is because the SD2IEC drive is typically faster than the original 1571, so even with a normal block handling command, the drive may finish before the interrupt end on the machine.
However, if it is not reasonable to expect everyone to rewrite their programs on the machine side, then a solution should be found on the firmware side. I had three ideas for this, one of which I eventually built into the firmware. (The other two are more workarounds than solutions, although the built-in one is too. ) The solution was that after ATN high, the drive also "registers" the CLK high state, so that the parts that are sensitive to this can wait for it. The fact that the drive simply "waits" for CLK high is not desirable for several reasons. This wait can only be inserted after the ATN release, because it may be missed later. (UNLISTEN returns to the caller after the CLK release, which can immediately switch the CLK to low (as planned), resulting in a relatively short high level on the CLK line, which is easy to miss.) But this would cause all command executions to wait for the CLK high, which would somewhat reduce the drive speed. For this reason, an interrupt is now used: after ATN high, an interrupt is enabled on CLK, which handles a flag when the high level arrives. This flag can be checked later at any time by those who need it. Currently, this is used before running "burst" commands and when starting the VCPU, but the question is whether it will be needed elsewhere. With this modification, however, the FlexSD firmware works flawlessly with the original KERNAL UNLISTEN routine, unlike the 1571. (There, waiting for CLK high would be more problematic: it is easy to miss a pulse that is too short, but there is no hardware in the drive for later verification.)
After applying this fix, GEOS can be tested again: the result is roughly the same. That's another round of debugging, I'll write about that soon, but this has already gotten too long.
3 |
|
| |
Copyright © Plus/4 World Team, 2001-2025. Support Plus/4 World on Patreon |