| Proof of concept: Alchemist |
| Jueves, 27 de Septiembre de 2007 00:00 |
|
There is a project for developing a set of utilities for handling ultra-loads for some vintage machines. Its name is OTLA. One of the key components of this technology is the well-known ultraload maker, k7zx, from "decicoder". An ultra-load is a routine that is capable of loading programs at a very high speed. This is now possible because of audio sources nowdays are mucho more reliable than the good old tape recorder. Even with a cheap built-in motherboard sound card, a PC can feed a very good quality signal to the "EAR" audio socket of a Spectrum. This, combined with a clever programming to push the machine at its limits, allows moving from a bare 1500 bps to 15.000 bps and beyond. I did some tests feeding a digital signal directly to the ULA, bypassing the input circuit. Then I realized that I have indeed a digital input without that circuit, hence, without distorsion or band limit: the joystick. I haven't been the first to use the joystick for high loading purposes. Back ago, Codemasters released a CD with a game compilation. The compilation included a special cable designed to plug in on the joystick connector, for accepting signals from the CD player. Jose Leandro, from "El trastero del Spectrum" did a very good analysis of the cable adapter. My approach is very different from Codemaster's. They used one bit for data and another one for a clock. My PoC uses four data bits (one nibble) for data transfer, and the fifth for clock. Besides, to increase the speed, I accept data at both the raising and the falling edge of the clock signal; much more similar to the way a DDR memory handles its clock. For this PoC, I've used a very simple setup: a development board, from Silicon Labs, based upon the C8051F120. I've chosen this chip for this test only because it has plenty of flash memory (128K). Enough for storing a complete 48K Spectrum program. This way, I don't need to read the data from a external device, like a SD card, thus, simplifying this test. The F120 has up to eight data ports, 8 bit each one. I only need one data port; bits 0 to 4. Bit 0 will be the clock signal, and bits 1 to 4 will carry one nibble from the microcontroller to the Spectrum. Wiring has to be made so bit 1 from the microcontroller becomes bit 1 when reading the joystick port in the Spectrum. THE ROUTINE To syncronize both the ZX Spectrum and the microcontroller, we always start with clock low. The Spectrum will wait until a low condition is detected on the clock bit. Then, for every byte transmitted, the microcontroller puts the high nibble on bits 1-4 and raises clock. The Spectrum detects the raising edge and stores the nibble in memory, then waits for a falling edge on clock. Microcontroller puts low nibble and then pulls down the clock line. The Spectrum detects this condition again, and combines the high nibble in memory with the low nibble just read, with a single RLD instruction. There's no feedback from the Spectrum to the microcontroller, so the microcontroller operates sincronously, and the Spectrum has to be faster than the microcontroller for not missing edges. In fact, being clock-driven, there's no need for time constants, as cassette routines need. This means that the speed limit is imposed solely by the Spectrum routine. The microcontroller can feed data at any speed, to the maximum imposed by this routine, which is about 125 T-states for byte. That means 28000 bytes per second, or 218 kbps. The practical limit I have reached is around 180 kbps The loading rutine is shown here. It's the same routine I've used in the v1.2 firmware of the PS/2 Adapter. I use it for loading the keyboard test routine. It's very short and it's relocatable. It can even work in the lower 16K, if we reduce the loading speed at the microcontroller.
UltraCarga proc
di
ld bc,0effeh
ld a,1
out (c),a ;Border blue, to signal that we're awaiting for a start pulse (low)
Esperaun0Inicial: in a,(c)
rrca
jr c,Esperaun0Inicial
BucBytes:
EsperaFlancoSubida: in a,(c) ;12
rrca ;4
jr nc,EsperaFlancoSubida ;12
ld (hl),a ;Store in memory the high nibble received 7
out (c),a ;Fancy border colors, to keep the tradition 12
EsperaFlancoBajada: in a,(c) ;12
rrca ;4
jr c,EsperaFlancoBajada ;12
rld ;Combine high nibble in memry with low nibble received 18
inc hl ;6
dec de ;6
ld a,d ;4
or e ;4
jr nz,BucBytes ;12
ld a,7
out (c),a
ei
ret
endp
For my test, I've chosen Alchemist. This game has a loading screen (6912 bytes) plus a 32K data block, with all the code and gfx. A standard speed BASIC loader loads and execute the ultraloader routine, which in turn calls the routine shown here twice: to load the screen and to load the game itself. The result can be viewed in the following video: |
