Personalcomputer EC1834

SDCC für Z1013, KC85 und Z9001

Hobi's Schnelladetools Turbo4

wav2kcc.exe (für Windows 32-bit)

save.kcc save.wav (für KC85/2, KC85/3 und KC85/4)

%TSAVE
TSAVE4 V4.01 Hobi's Schnellkopierer
Aufruf: AADR EADR (SADR)
 AADR - Anfangsadresse
 EADR - Endadresse (letztes Byte!)
 SADR - (optional) Startadresse
%TSAVE C000 FFFF 0000
Name:DUMP C+E
%_

Da beim SDCC Compiler schnell relative große Dateien herauskommen, allein die printf()-Routine aus der Bibliothek kann bis zu 4 KByte groß sein, ist es wünschenswert das Resultat schnell auf den Rechner zu übertragen. Eine Möglichkeit ist bietet das V24- oder auch USB-Interface. Was ist aber, wenn man keine derartige Hardware hat?
Das Kassetteninterface bietet einen einfachen Zugang zum Rechner. Er ist praktisch überall vorhanden und jeder PC oder Handy kann mit diesem Anschluss zusammenarbeiten.
Der Ansatz das Verfahren zu optimieren beruht auf zwei Ideen. Zum einen werden statt der 2 Perioden bei der original KC-SAVE-Routine, wird nur noch eine halbe Periode pro Bit übertragen und auf der Empfängerseite wird eine Art Gleitkommaarithmetik verwendet (genauer gesagt Ganzzahlbrüche) um die Nullstellen exakter zu berechnen, damit kann man die Abstände genauer messen und die Frequenz erhöhen. Es ist sogar möglich noch bei 22kHz Samplingfrequenz hinreichend genau die Nulldurchgänge den Werten 0 oder 1 zuzuorden.

Die Idee ist generisch und kann leicht auf andere Platformen portiert werden.

Da man auf eine magnetische Speicherung nicht mehr angewiesen ist, gibt es an dieser Stelle keine Beschränkung für die verwendeten Frequenzen mehr. Für die Versuche habe ich den KC85/4 genommen. Das Signal ist klar, stark mit steilen Flanken und fast noch ein ideales Rechtecksignal. Auf der Empfängerseite muss nicht viel nachbearbeitet werden. Einfach einlesen und die Nulldurchgänge bestimmen.

Das ist ein Beispiel für das Signal mit RLA Optimierung. Ein 1-Bit verwendet 50+6*16 Takte, ein 0-Bit 50+4*16 Takte. Das Signal kann man gerade noch auseinanderhalten. Ehrlich gesagt, ich kann hier nicht mehr entscheiden, was lang und was kurz ist ohne nachzumessen. Der Computer kann dies naturgemäß besser.

Das Limit wird eigentlich erst durch die CPU festgelegt, nicht durch das Kabel und nicht durch den Rest der Hardware (zumindest beim Abspeichern). Vom Einstellen des Frequenzzählers bis zum nächsten Interrupt vergehen im ungünstigsten Fall (wenn ein neues Byte vom Speicher gelesen werden muss) 55 Takte (gemessen von (step 3) bis wieder E=8 ist) . Zusammen mit dem Overhead des Interruptaufrufes sind das um die 115 Take pro Bit. Schneller geht es kaum noch - man könnte eventuell ld c,(hl) in den interrupt handler legen und dann aber alle 8 Bits einen Wartezyklus einlegen (bei dem man gleich noch die CRC mit aktualisieren könnte). Dadurch wären noch einmal 24 Taktzyklen einzusparen. Die Obergrenze der Datanrate wäre so bei etwa 90 Takte pro Bit also 1.700.000/(8*90) 2300 Bytes pro Sekunde.
Die aktuelle Version ist hart auf der Kante genäht, jede Störung z.B. Verzögerungen beim Zugriff auf den Bildwiederholspeicher, bringt den Ablauf durcheinander. Um die Routine etwas robuster zugestalten müssen die CTC Konstanten wahrscheinlich von 4/8 auf mind. 6/9 erhöht werden.

RLA Optimierung: Wenn man unbedingt noch etwas herausquetschen will, kann man JP nc,isr_bit noch durch ein 2 RLA ersetzen. Das Bit ist bereits in CF. Dies kann man von unten wieder mit hineinschieben. Leider geht der Trick mit CF nicht zweimal, so dass man statt 8 wie im Original also nur auf 6 CTC-Zyklen bekommt. Damit ist man noch etwa 4 Takte schneller, um den Preis, des schlechteren Frequenzabstandes. Im Histogramm kann man erkennen, dass der Abstand gerade einmal 300 Hz ist. Der Gewinn ist etwa 10%, aber eigentlich nur durch die kürzeren Abstände der 1-bits. Sollte diese Änderung zu viele Probleme verursachen, wird sie Rückgängig gemacht. Sie hat Probleme gemacht und wurde wieder zurückgenommen.

                                    ; clock cycle count before the instruction
                                    ;    CTC counter
next_byte:                          ;        prescaler
        ld      c,(hl)              ; 42 2.4. 7.16 [91] - step(5) and fetch another byte
        inc     hl                  ; 49 1.4. 0.16 [98]
        ld      e,#0x08             ; 55 1.4.10.16 [104] - here we can allow the interrupt again -which is by some strange coincidence still
                                    ;                within the 4x16 timer boundary
        or      e                   ;             [111] that is the end of the critical section, actually we could have moved th EI to here
wait:
        jr      nz,wait             ; 22   [71]   [115]  - step (1) the code will be interrupted by the timer here
        djnz    next_byte           ; 29   [78]          - step (4) return from interrupt
...


isr_ctc::
        ld      a,d                 ; [ 0] step (2) we land here
        out     (PORT_CTC+1),a      ; [ 4]
        rlc     c                   ; [15]
        ;ld      a,#BIT_0           ;
        ;jr      nc,isr_bit         ; originally we "copy" the CF into BIT 3  
        ;add     a                  ; 
        ld      a,#BIT_0/4          ; [23] we can do similar with 4 clock cycles less
        rla                         ; [30]
        rla                         ; [34]
isr_bit:                            
        out     (PORT_CTC+1),a      ; [38]
        dec     e                   ; 0 cycles since timer started / [49] cycles from start isr_ctc (step 3)
                                    ;   after 49 cycles (or 53 in case of using jr nc,...) the counter is ready for a restart 
                                    ; which in our case is 4x16 cycles - so count carefully from now on
        ei                          ; 4  4.4.13.16 [53]
        reti                        ; 8  4.4. 9.16 [57]
                                    ; 22 3.4.11.16 [71]

Verteilung der Nulldurchgänge bei der RLA Version

112   4480 <  4520 :      0   0.00%
113   4520 <  4560 :      0   0.00%
114   4560 <  4600 :      0   0.00%
115   4600 <  4640 :      0   0.00%
116   4640 <  4680 :      0   0.00%
117   4680 <  4720 :      0   0.00%
118   4720 <  4760 :      0   0.00%
119   4760 <  4800 :      6   0.00%
120   4800 <  4840 :     64   0.05%
121   4840 <  4880 :    150   0.11%
122   4880 <  4920 :    348   0.26%
123   4920 <  4960 :   1060   0.79%
124   4960 <  5000 :   2294   1.70%
125   5000 <  5040 :   2318   1.72%
126   5040 <  5080 :   9146   6.79%
127   5080 <  5120 :  13756  10.21%
128   5120 <  5160 :   5286   3.92%
129   5160 <  5200 :   5402   4.01%
130   5200 <  5240 :  12238   9.09%
131   5240 <  5280 :   8908   6.61%
132   5280 <  5320 :   1952   1.45%
133   5320 <  5360 :    636   0.47%
134   5360 <  5400 :    390   0.29%
135   5400 <  5440 :    150   0.11%
136   5440 <  5480 :     56   0.04%
137   5480 <  5520 :      0   0.00%
138   5520 <  5560 :      0   0.00%
139   5560 <  5600 :      0   0.00%
140   5600 <  5640 :      0   0.00%
141   5640 <  5680 :      0   0.00%
142   5680 <  5720 :      1   0.00%
143   5720 <  5760 :      0   0.00%
144   5760 <  5800 :      0   0.00%
145   5800 <  5840 :     10   0.01%
146   5840 <  5880 :     44   0.03%
147   5880 <  5920 :    140   0.10%
148   5920 <  5960 :    262   0.19%
149   5960 <  6000 :    482   0.36%
150   6000 <  6040 :   1092   0.81%
151   6040 <  6080 :   1962   1.46%
152   6080 <  6120 :   3258   2.42%
153   6120 <  6160 :   5906   4.38%
154   6160 <  6200 :   8078   6.00%
155   6200 <  6240 :   6186   4.59%
156   6240 <  6280 :   2882   2.14%
157   6280 <  6320 :   3980   2.95%
158   6320 <  6360 :   8528   6.33%
159   6360 <  6400 :  11802   8.76%
160   6400 <  6440 :   8804   6.54%
161   6440 <  6480 :   4240   3.15%
162   6480 <  6520 :   1276   0.95%
163   6520 <  6560 :    660   0.49%
164   6560 <  6600 :    400   0.30%
165   6600 <  6640 :    284   0.21%
166   6640 <  6680 :    106   0.08%
167   6680 <  6720 :     26   0.02%
168   6720 <  6760 :      2   0.00%
169   6760 <  6800 :      0   0.00%
170   6800 <  6840 :      0   0.00%
171   6840 <  6880 :      0   0.00%
172   6880 <  6920 :      0   0.00%
173   6920 <  6960 :      0   0.00%
174   6960 <  7000 :      0   0.00%