home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Hacker Chronicles 2
/
HACKER2.BIN
/
540.TNL1.MAC
< prev
next >
Wrap
Text File
|
1988-05-12
|
96KB
|
2,019 lines
; ***********************************************************************
; * *
; * *
; * ***** ***** *
; * ***** ***** *
; * ***** ***** *
; * ***** ***** *
; * *************** *************** *
; * ***************** ***************** *
; * *************** *************** *
; * ***** ***** The Net. *
; * ***** ***** Portable. Compatible. *
; * ***** ***** Public Domain. *
; * ***** ***** By NORD><LINK. *
; * *
; * *
; * *
; * TNL1.MAC - Z80 Level 1, Hardwareanpassungen, Interrupts *
; * *
; * angelegt: DC4OX *
; * modifiziert: *
; * *
; ***********************************************************************
;
; Achtung : Hier wird mit "Crosslink" ausschliesslich die Verbindung
; zweier TNC's ueber die RS232-Schnittstelle bezeichnet.
; Somit wird der RS232-Kanal zwischen 2 TNC's als
; "Crosslink-Kanal" bezeichnet, der Modem-Kanal als
; "HDLC-Kanal".
;
; =======================================================================
;
; Equates
;
; =======================================================================
;
; benutzte "Magic Number" zum RAM-Test Warmstart/Kaltstart
;
MAGIC equ 4D5Ah
;
; Hardware-I/O-Ports
;
SIADAT equ 0 ; SIO Kanal A (HDLC) Data
SIACTL equ 1 ; SIO Kanal A (HDLC) Control
SIBDAT equ 2 ; SIO Kanal B (RS232) Data
SIBCTL equ 3 ; SIO Kanal B (RS232) Control
;
; niedrigste RAM-Speicherstelle
;
RAMBOT equ 8000h
;
; ASCII-Kontrollzeichen
;
ASTX equ 02h ; ASCII Start of Text = Control B
AETX equ 03h ; ASCII End of Text = Control C
ADLE equ 10h ; ASCII Data Link Escape = Control P
ACAN equ 18h ; ASCII Cancel = Control X
AESC equ 1Bh ; ASCII Escape
;
; Hostterminal FIFO-Groessen
;
HORXFL equ 256 ; RX FIFO Laenge
HOTXFL equ 256 ; TX FIFO Laenge
; =======================================================================
;
; Arbeitsspeicher
;
; =======================================================================
dseg
RAMVEC: ds 16 ; Interrupt Vektor im RAM
;
; Hostkanal, SIO Kanal B, RS232-Schnittstelle,
; wenn Hostterminal angeschlossen
;
HORXCC: ds 2 ; RX "character count" Anzahl Zeichen
HORXFI: ds HORXFL ; RX "fifo" FIFO-Ringspeicher
HORXIP: ds 2 ; RX "input pointer" Eingangszeiger
HORXOP: ds 2 ; RX "output pointer" Ausgangszeiger
HOTXCC: ds 2 ; TX "character count" Anzahl Zeichen
HOTXFI: ds HOTXFL ; TX "fifo" FIFO-Ringspeicher
HOTXIP: ds 2 ; TX "input pointer" Eingangszeiger
HOTXOP: ds 2 ; TX "output pointer" Ausgangszeiger
;
; SIO Kanal B, RS232-Schnittstelle
;
SIBWR5: ds 1 ; Sicherung WR5, Tx-Modus
SIBRR0: ds 1 ; Sicherung RR0, Status
;
; Crosslink, SIO Kanal B, RS232-Schnittstelle,
; wenn TNC im Crosslink betrieben
;
CRXSTA: ds 1 ; RX "state"
; 0 - RX inaktiv
; 1 - RX aktiv, innerhalb Frame
; 2 - RX aktiv, letztes Zeichen war DLE, naechstes
; wird nicht interpretiert (STX/ETX/DLE)
; 3 - Frameende, naechstes Zeichen ist Checksum
CRXFCS: ds 1 ; RX "frame checksum" (8 Bit, Summe modulo 256)
CTXSTA: ds 1 ; TX "state"
; 0 - TX inaktiv
; 1 - nachdem Port frei wird (DTR high)
; (ASync-)WAIT-Sendesequenz eineiten
; 2 - nachdem Port frei wird (DTR high)
; Nicht-(Async-)WAIT-Sendesequenz einleiten
; 3 - (Async-)WAIT abwarten
; 4 - Vorlauftraeger (CTS low) gesetzt,
; 2,5 msec warten
; 5 - TX aktiv, innerhalb Frame
; (vor ETX/Checksumme)
; 6 - TX aktiv, Frameende, ETX gesendet,
; weitere Frames vorhanden
; 7 - TX aktiv, Frameende, ETX gesendet,
; keine weiteren Frames vorhanden
; 8 - TX aktiv, Frameende, Checksumme gesendet,
; weitere Frames vorhanden
; 9 - TX aktiv, Frameende, Checksumme gesendet,
; keine weiteren Frames vorhanden
; 10 - wie 9, vorletztes Zeichen aus internem
; SIO-FIFO gesendet
; 11 - wie 9, letztes Zeichen aus internem
; SIO-FIFO gesendet
CTXFCS: ds 1 ; TX "frame checksum" (8 Bit, Summe modulo 256)
CTXCSA: ds 1 ; TX "character save" fuer Zeichen mit DLE-Vorlauf
;
; HDLC-Kanal, SIO Kanal A, PR-Modemschnittstelle
;
SIAWR5: ds 1 ; Sicherung WR5, Tx-Modus
SIARR0: ds 1 ; Sicherung RR0, Status
HRXSTA: ds 1 ; RX "state"
; 0 - RX ausserhalb Frame
; 1 - RX innerhalb Frame
HRXLCH: ds 1 ; RX "last character" 1-Zeichen-FIFO, Zeichen erst
; gueltig, wenn Nicht-Frameende-Status von SIO
HTXSTA: ds 1 ; TX "state"
; 0 - TX inaktiv
; 1 - nachdem Port frei wird (DCD low)
; WAIT-Sendesequenz einleiten
; 2 - nachdem Port frei wird (DCD low)
; Nicht-WAIT-Sendesequenz einleiten
; 3 - WAIT warten
; 4 - TX aktiv, PTT, TXDELAY abwarten
; 5 - TX aktiv, innerhalb Frame Datenbytes
; 6 - TX aktiv, letztes Datenbyte fuer Frame
; gesendet, weitere Frames vorhanden
; 7 - TX aktiv, letztes Datenbyte fuer Frame
; gesendet, keine weiteren Frames vorhanden
; (mit 6 oder 7 laeuft TX in den TX-Underrun/
; EoM-Interrupt, naechster TX-Buffer-Empty-
; Interrupt : 1. CRC-Byte hat SIO verlassen)
; 8 - TX aktiv, CRC verlaesst SIO
; 9 - TX aktiv, Frameendeflag verlaesst SIO
; 10 - TX aktiv, Frameendeflag hat SIO komplett
; verlassen
;
; Zaehler
;
TICDIV: ds 1 ; Zaehler bis 12, 1200Hz Interrupts -> 10msec
HTXWAI: ds 1 ; 10msec HDLC-TX-Wartezaehler (WAIT/TXDELAY)
CTXWAI: ds 1 ; 1200Hz Crosslink-TX-Wartezaehler (Async-WAIT)
;
; Sonstiges
;
DEICNT: ds 1 ; Interrupt Verbietungsstufe
RAMTOP: ds 2 ; oberste verfuegbare RAM-Speicherstelle
URAND: ds 2 ; (fuer random(), damit Gleichverteilung)
; =======================================================================
;
; Code
;
; =======================================================================
cseg
; +---------------------------------------------------------------------+
; | |
; | Reset-Einsprungsvektor, RST-Vektoren. |
; | |
; +---------------------------------------------------------------------+
public reset?
extrn ?inc ; aus CRUNTIME
extrn ?sxt
extrn ?gf
extrn ?g
extrn ?sn
extrn ?addhl
extrn ?loc
reset?: jp L1INIT ; Resetvektor
db 0,0,0,0,0
jp ?inc ; RST08 (HL):=(HL)+1, 16 Bit
db 0,0,0,0,0
jp ?sxt ; RST10 HL:=A sign extension
db 0,0,0,0,0
jp ?gf ; RST18 HL:=(BC)
db 0,0,0,0,0
jp ?g ; RST20 HL:=(HL)
db 0,0,0,0,0
jp ?sn ; RST28 HL:=!HL
db 0,0,0,0,0
jp ?addhl ; RST30 Offset auf HL addieren
db 0,0,0,0,0
jp ?loc ; RST38 Locals laden/loeschen
; +---------------------------------------------------------------------+
; | |
; | Default-Parameter. |
; | |
; +---------------------------------------------------------------------+
public defCAL?, defIDE?, defDES?, defWQU?, defCH0?, defCH1?
public defOBC?, defOBB?, defBRI?, defTLI?, defTTO?, defTTR?
public defTAC?, defTBS?, defTWI?, defCON?, defNOA?, defPER?
public defSLO?, defRAK?, defMAF?, defL2T?, defLT2?, defLT3?
public defRPA?, defVAL?, defBEA?, defCQ?, defDPA?, defXFP?
public defESC?, defTp?, defPWD?, defINF?
defCAL?: db 'NO1DE ', 60h ; Call des TNC
defIDE?: db 'THENET' ; Ident des TNC
defDES?: dw 50 ; Laenge der Destination Liste
defWQU?: dw 1 ; minimale Qualitaet fuer Autoupdate
defCH0?: dw 100 ; HDLC Kanal Qualitaet
defCH1?: dw 255 ; RS232 Kanal Qualitaet
defOBC?: dw 6 ; Anfangswert Knotenlebensdauer
defOBB?: dw 5 ; Restlebensdauer fuer Rundspruch
defBRI?: dw 1800 ; Rundspruchintervall
defTLI?: dw 10 ; Anfangswert Paketlebensdauer
defTTO?: dw 300 ; Timeout in Level3
defTTR?: dw 2 ; Versuche in Level3
defTAC?: dw 6 ; Level3 Wartezeit bis ACK
defTBS?: dw 180 ; Level3 Busy Wartezeit
defTWI?: dw 4 ; Fenstergroesse in Level3
defCON?: dw 4 ; gebufferte Frames je Verbindung
defNOA?: dw 900 ; no-activity-timeout
defPER?: dw 64 ; Entschlossenheit fuer Sendung frei
defSLO?: dw 10 ; Zeitschlitzbreite
defRAK?: dw 5 ; Level2, Timer1
defMAF?: dw 2 ; Level2, Fenstergroesse
defL2T?: dw 10 ; Level2, Versuche
defLT2?: dw 100 ; Level2, Timer2
defLT3?: dw 18000 ; Level2, Timer3
defRPA?: dw 0 ; Level2 Digipeating Freigabe
defVAL?: dw 1 ; Calls pruefen
defBEA?: dw 2 ; Bakenmodus
defCQ?: dw 1 ; CQ-Ruf erlaubt j/n
defDPA?: db 0 ; Full-Duplex j/n
defXFP?: db 0 ; Flags in den Pausen
defESC?: db 01Bh ; Befehlseinleitungszeichen (Host)
defTp?: db 30 ; Senderverzoegerung
defPWD?: db 'ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789 '
db 'ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789 ',0 ; Passwort
defINF?: db 'SOFTWARE VON NORD><LINK - SOFTWARE VON'
db ' NORD><LINK - SOFTWARE VON NORD><LINK ',0 ; Infotext
; +---------------------------------------------------------------------+
; | |
; | SIO (HDLC, RS232) Initialisierungstabellen. |
; | |
; +---------------------------------------------------------------------+
;
; Mit "Pin" ist immer der SIO-Pin gemeint.
; Mit "Modemstecker" ist der RS232-Stecker gemeint - "Modem" in diesem
; Zusammenhang bezieht sich auf die Signalbezeichung, der TNC wird ja
; bei Anschluss an einen Rechner oder an ein Terminal als "Modem"
; betrieben.
;
;
; SIO Kanal B, RS232 (Hostterminal oder Crosslink)
;
SIBINI: db 018h ; WR 0 : Channel Reset
db 2 ; WR 2 :
db 000h ; Interrupt Vector (Page-Anfang)
db 4 ; WR 4 :
db 044h ; /16 Clock, 1 Stopbit, kein Parity
db 5 ; WR 5 :
SIBIW5: db 0EAh ; Tx 8 Bit, Tx Enable, Pin /DTR low,
; Pin /RTS low -> Modemstecker CTS high
db 3 ; WR 3 :
db 0C1h ; Rx 8 Bit, Rx Enable
db 1 ; WR 1 :
db 01Fh ; Interrupt on all Rx Character, Status
; affects Vector, Tx Interrupt Enable,
; External/Status Interrupt Enable
db 010h ; WR 0 : Reset External/Status Interrupts
SIBIEN:
;
; SIO Kanal A, HDLC (Packet-Radio-Modem)
;
SIAINI: db 018h ; WR 0 : Channel Reset
db 4 ; WR 4 :
db 020h ; /1 Clock, SDLC Mode (01111110 Flag),
; Sync Modes Enable
db 5 ; WR 5 :
SIAIW5: db 0E1h ; Tx 8 Bit, CCITT CRC, Tx CRC Enable,
; Pin /DTR low, Pin /RTS high -> PTT aus
db 3 ; WR 3 :
SIAIW3: db 0D9h ; Rx 8 Bit, Hunt Phase, Rx CRC Enable,
; Rx Enable
db 7 ; WR 7 :
db 07Eh ; 01111110 Flag
db 1 ; WR 1 :
db 01Bh ; Interrupt on all Rx Character,
; Tx Interrupt Enable,
; External/Status Interrupt Enable
db 010h ; WR 0 : Reset External/Status Interrupts
SIAIEN:
; +---------------------------------------------------------------------+
; | |
; | Interrupt-Vektor-Tabelle (wird ins RAM uebertragen). |
; | |
; +---------------------------------------------------------------------+
ROMVEC: dw SIBTBE ; SIO B (RS232) Tx Buffer Empty
dw SIBESC ; SIO B (RS232) External/Status Change
dw SIBRCA ; SIO B (RS232) Rx Character Available
dw SIBSRC ; SIO B (RS232) Special Receive Condition
dw SIATBE ; SIO A (HDLC) Tx Buffer Empty
dw SIAESC ; SIO A (HDLC) External/Status Change
dw SIARCA ; SIO A (HDLC) Rx Character Available
dw SIASRC ; SIO A (HDLC) Special Receive Condition
ROMVEN:
; +---------------------------------------------------------------------+
; | |
; | Level 1 Initialisierung nach einem Reset. |
; | |
; | - Kaltstart : Speicherausbau feststellen |
; | - Stack setzen |
; | - SIO initialisieren |
; | - Level 1 Variable setzen |
; | - Interrupts initialisieren |
; | - Interrupts erlauben |
; | - Sprung ins Hauptprogramm |
; | |
; +---------------------------------------------------------------------+
external mainf? ; C Hauptprogramm
external magicn? ; im Hauptprogramm definierte Variable
external stack? ; Stack im Hauptprogramm definiert
L1INIT: di ; Interrupts verbieten fuer Initialisierung
ld HL,(magicn?) ; RAM ok = Warmstart, d.h.
ld DE,MAGIC ; Magic Number noch
or A ; unveraendert,
sbc HL,DE ; wie ins RAM geschrieben ?
jr Z,L1INI2 ; ja - RAM-Bestueckung nicht testen
ld HL,RAMBOT+3FFFh ; nein - Ende RAM bei 16kB
ld DE,RAMBOT+7FFFh ; Ende RAM bei 32kB
xor A ; 0
ld (HL),A ; in beide moegliche
ld (DE),A ; RAM-Enden
dec (HL) ; oberes RAM-Ende = 0FFh
ld A,(DE) ; hat sich unteres RAM-Ende geaendert ?
or A ; (16kB-Bestueckung -> Spiegelung)
jr NZ,L1INI1 ; ja - es sind nur 16kB
inc A ; A = 1
ld (DE),A ; an unteres RAM-Ende
inc (HL) ; 0 an oberes RAM-Ende, auch gespiegelt ?
jr NZ,L1INI1 ; ja - andere Hardware, aber auch nur 16kB
ex DE,HL ; nein - 32kB RAM
L1INI1: ld (RAMTOP),HL ; oberste RAM-Speicherstelle merken
L1INI2: ld SP,stack?+1 ; Stack setzen
im 2 ; Interruptmode 2 = Vektorinterrupts
ld A,RAMBOT>>8 ; Interrupt Vektor Page = RAM Anfang
ld I,A
ld HL,ROMVEC ; Interrupt-Vektor vom ROM
ld DE,RAMVEC ; ins RAM
ld BC,ROMVEN-ROMVEC ; laden
ldir
ld HL,SIBINI ; SIO B (RS232) initialisieren
ld BC,SIBCTL|((SIBIEN-SIBINI)<<8)
otir
in A,(SIBCTL) ; SIO B initialen Status holen
ld (SIBRR0),A ; und merken
ld A,(SIBIW5) ; SIO B initialen Tx-Modus holen
ld (SIBWR5),A ; und merken
ld HL,SIAINI ; SIO A (HDLC) initialisieren
ld BC,SIACTL|((SIAIEN-SIAINI)<<8)
otir
in A,(SIACTL) ; SIO A initialen Status holen
ld (SIARR0),A ; und merken
ld A,(SIAIW5) ; SIO A initialen Tx-Modus holen
ld (SIAWR5),A ; und merken
call HOINIT ; Host-FiFo's initialisieren
xor A ; A = 0
ld (CRXSTA),A ; Crosslink RX inaktiv
ld (CTXSTA),A ; Crosslink TX inaktiv
ld (HRXSTA),A ; HDLC RX ausserhalb Frame
ld (HTXSTA),A ; HDLC TX inaktiv
ld (TICDIV),A ; 1200Hz Zaehler starten
ld (HTXWAI),A ; HDLC Wartetimer inaktiv
ld (CTXWAI),A ; Crosslink Wartetimer inaktiv
ld (DEICNT),A ; keine Interrupt-Verbietungsstufe
jp mainf? ; ab ins Hauptprogramm
; +---------------------------------------------------------------------+
; | |
; | C : BOOLEAN ishget() "is host get" |
; | |
; | TRUE - (HL=1, Z=0) Hostterminal an RS232 angeschlossen und |
; | Zeichen vom Terminal vorhanden (in RX-FIFO) |
; | |
; | FALSE - (HL=0, Z=1) Hostterminal nicht an RS232 angeschlossen |
; | oder kein Zeichen von Terminal vorhanden (in RX-FIFO) |
; | |
; | A benutzt, HL Returnwert. |
; | |
; +---------------------------------------------------------------------+
public ishget?
ishget?: call ishost? ; Hostterminal an RS232 ?
ret Z ; nein - dann nie frei (FALSE zurueck)
ld HL,(HORXCC) ; Zeichenzaehler Host-FIFO RX = 0 ?
ld A,H
or L
ret Z ; ja - FALSE zurueck
ld HL,1 ; nein - TRUE zurueck
ret
; +---------------------------------------------------------------------+
; | |
; | C : hgetc() "host get character" |
; | |
; | Zeichen von Hostterminal holen, falls angeschlossen und Zeichen da. |
; | Falls kein Hostterminal angeschlossen, ASCII Cancel zurueckgeben. |
; | Falls kein Zeichen da, warten auf Zeichen. |
; | |
; | A, DE benutzt, HL Returnwert. |
; | |
; +---------------------------------------------------------------------+
public hgetc?
hgetc?: call ishost? ; Hostterminal an RS232 ?
ld A,ACAN ; nein - ASCII CAN = "bisherige Eingabe
jr Z,hgetc2 ; Loeschen" zurueck
call ishget? ; ja - Zeichen vom Hostterminal da ?
jr Z,hgetc? ; nein - auf Zeichen warten
di ; ja - keine Ints (kein Zeigerzugriff)
ld HL,(HORXCC) ; RX-FIFO Zeichenzaehler - 1
dec HL
ld (HORXCC),HL
ld HL,(HORXOP) ; Output-Zeiger
ld A,(HL) ; Zeichen aus FIFO holen
inc HL ; Zeiger auf naechstes Zeichen
ex DE,HL
ld HL,HORXFI+HORXFL-1 ; Zeiger > letzte FIFO-Stelle, d.h.
or A ; "FIFO Wrap Around" ?
sbc HL,DE
jr NC,hgetc1 ; nein -
ld DE,HORXFI ; ja - Zeiger wieder auf FIFO-Anfang
hgetc1: ld (HORXOP),DE ; Zeiger abspeichern
ei ; Interrupt wieder frei
hgetc2: ld L,A ; Zeichen C-like zurueck = return(chr)
ld H,0
or A
ret ; das war's
; +---------------------------------------------------------------------+
; | |
; | C : BOOLEAN ishput() "is host put" |
; | |
; | TRUE - (HL=1, Z=0) Hostterminal an RS232 angeschlossen und es |
; | koennen Zeichen gesendet werden an Hostterminal |
; | (TX-FIFO leer) |
; | |
; | FALSE - (HL=0, Z=1) Hostterminal nicht an RS232 angeschlossen |
; | oder es duerfen keine Zeichen gesendet werden an |
; | Hostterminal (TX-FIFO nicht leer) |
; | |
; | A benutzt, HL Returnwert. |
; | |
; +---------------------------------------------------------------------+
public ishput?
ishput?: call ishost? ; Hostterminal an RS232 ?
ret Z ; nein - immer voll (FALSE zurueck)
ld HL,(HOTXCC) ; Zeichenzaehler Host-FIFO TX = 0 ?
ld A,H
or L
ret Z ; ja - FALSE zurueck
ld HL,1 ; nein - TRUE zurueck
ret
; +---------------------------------------------------------------------+
; | |
; | C : VOID hputc(chr) char chr; "host put character" |
; | |
; | Falls kein Hostterminal an RS232 angeschlossen, Zeichen chr |
; | vergessen und Rueckgabe. Sonst Zeichen chr in den Hostterminal- |
; | TX-FIFO schreiben, ggf. warten bis Platz im TX-FIFO. |
; | Falls TX-FIFO leer war, wird der Interrupt-Zeichensender wieder |
; | ange-"kickt". |
; | |
; | A, HL, DE benutzt. |
; | |
; +---------------------------------------------------------------------+
public hputc?
hputc?: call ishost? ; Hostterminal an RS232 ?
ret Z ; nein - Zeichen vergessen, Rueckgabe
ld HL,(HOTXCC) ; ja - TX-FIFO voll ?
ld DE,HOTXFL
or A
sbc HL,DE
jr NC,hputc? ; ja - warten bis Platz im TX-FIFO
ld HL,2 ; nein - Zeichen als C-Parameter vom Stack
add HL,SP ; holen
ld A,(HL)
di ; keine Ints (keine Zeigerzugriffe)
ld HL,(HOTXCC) ; TX-FIFO Zeichenzaehler + 1
inc HL
ld (HOTXCC),HL
ld HL,(HOTXIP) ; Zeiger auf naechste freie Stelle im TX-FIFO
ld (HL),A ; Zeichen in TX-FIFO eintragen
inc HL ; Zeiger auf naechste freie Stelle
ex DE,HL
ld HL,HOTXFI+HOTXFL-1 ; Zeiger > letzte FIFO-Stelle, d.h.
or A ; "FIFO Wrap Around" ?
sbc HL,DE
jr NC,hputc1 ; nein -
ld DE,HOTXFI ; ja - Zeiger wieder auf FIFO-Anfang
hputc1: ld (HOTXIP),DE ; Zeiger abspeichern
in A,(SIBCTL) ; SIO Kanal B (RS232) Tx-Buffer leer ?
bit 2,A
call NZ,HTXFCO ; ja - naechstes Zeichen aus TX-FIFO
; senden (falls sich kein Zeichen
; mehr im TX-FIFO befand, wird
; hiermit der Interrupt-Sender wieder
; ange-"kickt")
ei ; Interrupts wieder frei
ret ; das war's
; +---------------------------------------------------------------------+
; | |
; | C : VOID kicktx(port) unsigned port; |
; | |
; | port = 0 : HDLC-Port (Modem) |
; | = 1 : Crosslink-Port (RS232) |
; | |
; | Sender an-"kicken", d.h. wenn Kanal frei ist, Sendezyklus |
; | einleiten, wenn Sender am Frameende des letzten Frames, dann |
; | Sender mitteilen, dass noch weitere Frames folgen. |
; | |
; | A, DE, HL benutzt. |
; | |
; +---------------------------------------------------------------------+
extrn Dpar? ; 1 = Vollduplex an
public kicktx?
kicktx?: push BC ; C Stackframe-Pointer
push IX ; sichern
ld HL,6 ; Zeiger auf C-Uebergabe-Parameter
add HL,SP
ld A,(HL) ; Parameter LSB holen, Portnummer
or A ; Kommando fuer Crosslink-Port ?
jr NZ,kickt3 ; ja -
ld HL,HTXSTA ; nein - HDLC-Port
ld A,(HL) ; HDLC-Sender inaktiv ?
or A
jr Z,kickt1 ; ja -
cp 7 ; nein - "in Frame(ende), weitere folgen" ?
jr C,kickt9 ; ja - TX muss nicht ange-"kickt" werden
ld (HL),6 ; nein - "in Frameende, weitere folgen" !
jr Z,kickt9 ; wenn nur "in Frameende" war, reicht das
ld A,08h ; sonst SIO Kanal A (HDLC) "Send Abort" um
out (SIACTL),A ; Flagwirklichzueende-Checkframe zu beenden
jr kickt9 ; das war's
kickt1: ld A,(Dpar?) ; Vollduplexbetrieb ?
or A
jr NZ,kickt2 ; ja - keine DCD-Abfrage
ld A,(SIARR0) ; HDLC-Sender inaktiv, DCD (high, "1") ?
bit 3,A
jr Z,kickt2
inc (HL) ; ja - Sendezyklus einleiten, wenn kein
jr kickt9 ; DCD mehr anliegt (TX-State = 1/2)
kickt2: ld A,1 ; nein - sofort Sendezyklus einleiten
call HTXINI ; (TX-State = 3)
jr kickt9 ; das war's
kickt3: call ishost? ; Hostterminal angeschlossen ?
jr NZ,kickt8 ; ja - alle Crosslink-Frames wegwerfen
ld HL,CTXSTA ; nein - Crosslink-Sender inaktiv ?
ld A,(HL)
or A
jr Z,kickt6 ; ja -
cp 10 ; nein - (vor-)letztes Zeichen im Sender ?
jr NC,kickt5 ; ja - direkt neues Frame beginnen
cp 7 ; nein - TX-State 7 der 9, "Frameende,
jr Z,kickt4 ; keine weiteren folgen" ?
cp 9
jr NZ,kickt9 ; nein - da eh weitere folgen, nix noetig
kickt4: dec (HL) ; ja - es reicht, dem Sender mitzuteilen,
jr kickt9 ; "weitere folgen" (7/9 -> 6/8)
kickt5: call CTXSTX ; neues Crosslink-Frame mit ASCII STX
jr kickt9 ; beginnen
kickt6: ld A,(SIBRR0) ; Crosslink-Sender inaktiv, Modemstecker DTR
bit 5,A ; high = 1 = Pin /CTS low, d.h. Kanal frei ?
jr NZ,kickt7
inc (HL) ; nein - TX-State = 1/2 "Sendezyklus
jr kickt9 ; einleiten, wenn Kanal frei wird"
kickt7: ld A,1 ; ja - Crosslink-Sender aktivieren
call CTXINI ; (TX-State 1 -> 3)
jr kickt9 ; das war's
kickt8: ld HL,8101h ; Kommando an Crosslink-TX-Buffer :
call GETSRV ; "alle Frames wegwerfen"
kickt9: pop IX ; C Stackframe-Pointer
pop BC ; restaurieren
ret ; das war's endgueltig
; +---------------------------------------------------------------------+
; | |
; | C : VOID pushtx() |
; | |
; | Wenn HDLC-Sender auf Abfall von DCD wartet, sofort auf Sendung |
; | gehen (wird gebraucht zur Vermeidung eines Deadlocks bei |
; | Umschaltung in den Vollduplex-Betrieb). |
; | |
; | A, DE, HL benutzt. |
; | |
; +---------------------------------------------------------------------+
public pushtx?
pushtx?: push BC ; C Stackframe-Pointer
push IX ; sichern
ld HL,HTXSTA ; (HL setzen fuer HTXINI)
ld A,(HL) ; TX-State = 1 oder 2, "nachdem Port frei
or A ; wird, senden" ?
jr Z,pusht1
cp 3
call C,HTXINI ; ja - dann Sender sofort hochfahren
pusht1: pop IX ; C Stackframe-Pointer
pop BC ; restaurieren
ret ; das war's
; +---------------------------------------------------------------------+
; | |
; | "SIO channel B Tx Buffer Empty" - Interruptservice |
; | |
; | RS232 SIO TX-Buffer leer, entweder (Hostterminal angeschlossen) |
; | Zeichen aus Hostterminal-FIFO falls nicht leer senden oder |
; | (Crosslink an RS232) Zeichen aus Frame senden, Frameendebehandlung, |
; | DLE-Stuffing. |
; | |
; | |
; | Crosslink-Frameformat : |
; | |
; | +-----+--------- ------+-----+-----+ |
; | | STX | info ... | ETX | FCS | |
; | +-----+--------- ------+-----+-----+ |
; | 02h | 03h 8 Bit Frame Checksumme, |
; | | nur ueber info, ohne 1. |
; | | DLE bei "Stuffing" |
; | | |
; | +---> Infobytes, STX in info wird zu DLE STX DLE = 10h |
; | ETX " DLE ETX |
; | DLE " DLE DLE |
; | |
; +---------------------------------------------------------------------+
SIBTBE: push AF ; Register sichern
push BC
push DE
push HL
push IX
ld A,28h ; SIO Kanal B (RS232) Reset Tx Int Pending
out (SIBCTL),A
call ishost? ; Hostterminal an RS232 angeschlossen ?
jr NZ,SIBT11 ; ja -
ld HL,CTXSTA ; nein - Crosslink-Kanal
ld A,(HL) ; Crosslink-TX-State :
sub 5
jr Z,SIBT4 ; 5: innerhalb Frame
jr C,SIBT12 ; 0: letztes Zeichen aus SIO -> nix tun
dec A
jr Z,SIBT3 ; 6: Frameende, noch weitere, ETX gesendet
dec A
jr Z,SIBT3 ; 7: Frameende, keine weiteren, ETX gesendet
dec A
jr Z,SIBT2 ; 8: Frameende, noch weitere, FCS gesendet
dec A
jr Z,SIBT1 ; 9: Frameende, keine weiteren, FCS gesendet
dec A
jr Z,SIBT1 ; 10: Sendungsende, vorletztes Zeichen fertig
ld (HL),0 ; 11: Sendungsende, letztes Zeichen fertig,
call CCOFF ; TX inaktiv, Crosslink-"Traeger"
jr SIBT12 ; abschalten, das war's
SIBT1: inc (HL) ; 9/10 -> 10/11, Zaehler fuer Frameende-
jr SIBT10 ; Feststellung, 00h als Dummy an RS232
SIBT2: call CTXSTX ; Frameende, noch weitere : neues Frame
jr SIBT12 ; beginnen, das war's
SIBT3: inc (HL) ; Frameende, ETX gesendet : TX-State wie
inc (HL) ; vorher, aber "FCS gesendet"
ld A,(CTXFCS) ; Frame-Checksumme
jr SIBT10 ; aussenden
SIBT4: ld HL,CTXCSA ; kommt jetzt STX/ETX/DLE nach DLE ?
ld A,(HL)
or A
jr Z,SIBT5
ld (HL),0 ; ja - "nach DLE"-Buffer loeschen
jr SIBT9 ; und Zeichen aus Buffer aussenden
SIBT5: ld HL,0100h ; nein - Kommando : "naechstes Zeichen aus
call GETSRV ; TX-Crosslink-Buffer holen" ausfuehren
ld A,L ; Frame zuende ?
bit 7,H
jr Z,SIBT7 ; nein - normales Zeichen
ld HL,CTXSTA ; ja - TX-State "Frameende, weitere folgen"
inc (HL)
bit 0,A ; noch weitere Frames vorhanden ?
jr Z,SIBT6
inc (HL) ; nein - TX-State "Frameende, keine weiteren"
SIBT6: ld A,AETX ; Frame mit ETX beenden
jr SIBT10
SIBT7: cp ASTX ; auszusendendes Zeichen STX/ETX/DLE ?
jr Z,SIBT8
cp AETX
jr Z,SIBT8
cp ADLE
jr NZ,SIBT9
SIBT8: ld (CTXCSA),A ; ja - entsprechendes Zeichen merken
ld A,ADLE ; und DLE aussenden
jr SIBT10
SIBT9: ld C,A ; nein - Zeichen merken
ld HL,CTXFCS ; Checksumme := Checksumme + Zeichen
add A,(HL)
ld (HL),A
ld A,C ; Zeichen restaurieren und senden
SIBT10: out (SIBDAT),A ; Zeichen an SIO ausgeben
jr SIBT12 ; das war's
SIBT11: call HTXFCO ; Zeichen aus Hostterminal-Buffer an RS232
SIBT12: pop IX ; Register restaurieren
pop HL
pop DE
pop BC
pop AF
ei ; Interrupts wieder erlauben
reti ; das war's
; +---------------------------------------------------------------------+
; | |
; | "SIO channel B External Status Change" - Interruptservice |
; | |
; | RS232 DCD Wechsel |
; | DCD ist das Crosslink/Hostterminal-Signal. Ein Wechsel bedeutet |
; | Umschaltung von Hostterminal auf Crosslink oder umgekehrt. Es |
; | werden alle Buffer, FIFO's und Variable fuer Crosslink und |
; | Hostterminal initialisiert. Noch nicht verarbeitete Inhalte |
; | werden weggeworfen. Ggf. wird der Crosslink-"Vorlauftraeger" |
; | abgeschaltet. |
; | |
; | SIO Pin /CTS = RS232 Modemstecker DTR Wechsel |
; | Dies ist das Crosslink-Kanal-"DCD". Ein Wechsel bedeutet den |
; | Wechsel von einem freien auf einen belegten Kanal oder umgekehrt. |
; | Geschieht ein Wechsel von besetzt auf frei und der Sender wartete |
; | auf freien Kanal, dann wird entsprechend die Sendesequenz |
; | aktiviert ("Vorlauftraeger" oder "Async"-WAIT"). |
; | Geschieht ein Wechsel von frei auf besetzt und der Sender befand |
; | sich im "Async"-WAIT Warten oder im "Vorlauftraeger", dann wird |
; | die Sendesequenz abgebrochen und wieder auf Warten auf freien |
; | Kanal gesetzt, ggf. wird der Crosslink-"Vorlauftraeger" |
; | abgeschaltet. |
; | |
; | 1200 Hz SIO Pin SYNC Flanken |
; | Dies ist der grundlegende Timer-Interrupt. Hieraus wird der |
; | System-10-msec-Takt abgeleitet. Der Systemtimer wird aufgerufen |
; | und die Senderwartevariablen werden verwaltet. Bei Ablauf wird |
; | entsprechend der Sendesequenz verfahren. |
; | |
; +---------------------------------------------------------------------+
external timer? ; C Systemtimer (10 msec)
SIBESC: push AF ; Register sichern
push BC
push DE
push HL
push IX
in A,(SIBCTL) ; Status SIO Kanal B (RS232) holen
ld B,A ; und merken
ld A,10H ; Reset External/Status Interrupts
out (SIBCTL),A
ld HL,SIBRR0
ld A,(HL) ; alter Status
ld (HL),B ; neuen Status merken
xor B
ld C,A ; C = was hat sich geaendert
bit 3,C ; Abfrage DCD-Wechsel-Interrupt
jr Z,SIBE1
;
; DCD hat sich geaendert
;
push BC ; Status/Statusaenderung merken
call HOINIT ; Hostterminal-FIFO's loeschen,
; Crosslink-"Traeger" aus
ld BC,8101h ; aktive Crosslink-TX-Buffer in
call PUTSRV ; "Gesendet"-Liste einhaengen
ld HL,8101h ; aktive Crosslink-RX-Buffer
call GETSRV ; auf den Muell werfen
xor A ; Crosslink RX/TX Variable resetten
ld (CRXSTA),A
ld (CTXSTA),A
ld (CTXWAI),A
pop BC ; Status/Statusaenderung restaurieren
SIBE1: bit 5,C ; Abfrage CTS-Wechsel-Interrupt
jr Z,SIBE5
;
; Pin /CTS = Modemstecker DTR hat sich geaendert
; (Crosslink-"Traeger" Input)
;
push BC ; Status/Statusaenderung merken
ld HL,CTXSTA
ld A,(HL) ; Pin /CTS low = Modemstecker DTR high =
bit 5,B ; Crosslink-Kanal frei zur Sendung ?
jr Z,SIBE2 ; nein - ging also von frei auf besetzt
or A ; ja - Crosslink-TX inaktiv ?
jr Z,SIBE4 ; ja - nix weiter tun
cp 3 ; nein - auf "Kanal frei" wartend ?
jr NC,SIBE4 ; nein - TX muss nicht aktiviert werden
call CTXINI ; ja - Crosslink-Sendesequenz aktivieren
jr SIBE4
SIBE2: sub 3 ; Crosslink-Kanal frei -> besetzt,
jr Z,SIBE3 ; "Async"-WAIT Wartezustand (State 3)
dec A ; oder Crosslink-"Vorlauftraeger" (State 4) ?
jr NZ,SIBE4 ; nein - nix weiter tun
SIBE3: ld (CTXWAI),A ; ja - Wartezaehler inaktivieren ( = 0),
dec (HL) ; TX-Wartezustand wieder auf Zustand
dec (HL) ; vor Warten/"Vorlauftraeger"
bit 1,(HL) ; war es "Vorlauftraeger" (4-2=2) ?
call NZ,CCOFF ; ja - diesen abschalten
SIBE4: pop BC ; Status/Statusaenderung restaurieren
SIBE5: bit 4,C ; Abfrage SYNC-Flanken-Interrupt
jr Z,SIBE9
;
; Flanke am Pin SYNC = 1200 Hz Interrupt
;
ld HL,CTXWAI ; Crosslink TX-Wartezaehler inaktiv ?
ld A,(HL)
or A
jr Z,SIBE7 ; ja -
dec (HL) ; nein - abgelaufen ?
jr NZ,SIBE7 ; nein -
ld HL,CTXSTA ; ja - war es "Vorlauftraeger" (State 4) ?
ld A,(HL)
cp 4
jr Z,SIBE6
inc (HL) ; nein - war "Async"-WAIT, ab jetzt 2,5 msec
call CTXPRE ; Crosslink-"Vorlauftraeger" (State 4)
jr SIBE7
SIBE6: call CTXSTX ; ja - Frame beginnen
SIBE7: ld HL,TICDIV ; 1200 Hz -> 10 msec Teiler abgelaufen ?
inc (HL)
ld A,(HL)
cp 12
jr C,SIBE9 ; nein - dann war's das
;
; alle 10 msec :
;
ld (HL),0 ; ja - Teiler neu aktivieren
call timer? ; 10 msec Ticker im Hauptprogamm
ld HL,HTXWAI ; HDLC-TX-Wartezaehler aktiv ?
ld A,(HL)
or A
jr Z,SIBE9 ; nein - dann war's das
dec (HL) ; ja - abgelaufen ?
jr NZ,SIBE9 ; nein - dann war's das
ld HL,HTXSTA ; ja - in TXDELAY ?
ld A,(HL)
cp 4
jr Z,SIBE8 ; ja - Frame beginnen
dec A ; nein - TX-Statezaehler fuer HTXINI
dec A ; korrigieren und Sender
call HTXINI ; hochfahren
jr SIBE9
SIBE8: inc (HL)
call HTXSOF ; ja - Frame beginnen
SIBE9: pop IX ; Register restaurieren
pop HL
pop DE
pop BC
pop AF
ei ; Interrupts wieder erlauben
reti ; das war's
; +---------------------------------------------------------------------+
; | |
; | "SIO channel B Rx Character Available" - Interruptservice |
; | |
; | RS232 SIO RX Zeichen da, entweder (Hostterminal angeschlossen) |
; | Zeichen in den Hostterminal-FIFO schreiben falls nicht voll, oder |
; | (Crosslink an RS232) Zeichen in Crosslink-Buffer schreiben, |
; | Frameendebehandlung, DLE-Stuffing. |
; | |
; +---------------------------------------------------------------------+
SIBRCA: push AF ; Register sichern
push BC
push DE
push HL
push IX
in A,(SIBDAT) ; Zeichen von RS232 holen
ld C,A
call ishost? ; Hostterminal angeschlossen ?
jr NZ,SIBR8 ; ja -
;
; Crosslink an RS232
;
ld HL,CRXSTA ; nein - Crosslink
ld A,(HL) ; Crosslink-RX-State :
or A
jr Z,SIBR1 ; 0: RX inaktiv
dec A
jr Z,SIBR3 ; 1: RX aktiv, innerhalb Frame
dec A
jr Z,SIBR5 ; 2: RX aktiv, letztes Zeichen war DLE
ld (HL),0 ; 3: Frameende, Checksumme kommt, (3 -> 0)
ld A,(CRXFCS) ; RX Checksumme ok ?
cp C
ld BC,8100h ; (Befehl "Crosslink-RX-Buffer in RX-Liste")
jr Z,SIBR7 ; ja - Frame ok, in RX-Liste einhaengen
inc C ; (Befehl "Crosslink-RX-Buffer auf Muell)
jr SIBR7 ; nein - Framebuffer auf den Muell werfen
SIBR1: ld A,C ; RX inaktiv,
cp ASTX ; Zeichen = Frameanfang (STX) ?
jr NZ,SIBR10 ; nein - dann war's das
inc (HL) ; ja - RX-State "RX innerhalb Frame" (1)
SIBR2: xor A ; RX-Checksumme loeschen
ld (CRXFCS),A
ld BC,8101h ; neuen Crosslink-RX-Buffer beginnen
jr SIBR7 ; das war's
SIBR3: ld A,C ; RX aktiv, innerhalb Frame,
cp ASTX ; Zeichen = Frameanfang (STX) ?
jr Z,SIBR2 ; ja - RX resetten, neues Frame
cp ADLE ; Zeichen DLE ?
jr Z,SIBR4 ; ja - RX-State "letztes Zeichen DLE" (2)
cp AETX ; nein - Zeichen = Frameende (ETX) ?
jr NZ,SIBR6 ; nein - normales Info-Zeichen
inc (HL) ; ja - RX-State "Checksumme kommt" (3)
SIBR4: inc (HL)
jr SIBR10 ; das war's
SIBR5: dec (HL) ; letztes Zeichen war DLE, naechstes Zeichen
; (STX/ETX/DLE) ist Info, RX-State 2 -> 1
SIBR6: ld HL,CRXFCS ; Info-Zeichen
ld A,(HL) ; auf Checksumme
add A,C ; addieren
ld (HL),A
ld B,0001h ; und in Crosslink-RX-Buffer
SIBR7: call PUTSRV ; Crosslink-RX-Buffer-Verwaltung
jr SIBR10 ; das war's
;
; Hostterminal an RS232
;
SIBR8: ld HL,HORXFL ; noch Platz im RX-Hostterminal-FIFO, d.h.
ld DE,(HORXCC) ; Zeichenzaehler + 1 <= FIFO-Laenge ?
inc DE
or A
sbc HL,DE
jr C,SIBR10 ; nein - Zeichen vergessen
ld (HORXCC),DE ; ja - Zeichenzaehler + 1 abspeichern
ld HL,(HORXIP) ; Zeiger auf naechste freie Stelle
ld (HL),C ; Zeichen in den FIFO einschreiben
inc HL ; Zeiger auf naechste Stelle
ex DE,HL
ld HL,HORXFI+HORXFL-1 ; Zeiger > letzte FIFO-Stelle, d.h.
or A ; "FIFO Wrap Around" ?
sbc HL,DE
jr NC,SIBR9 ; nein -
ld DE,HORXFI ; ja - Zeiger auf FIFO-Anfang
SIBR9: ld (HORXIP),DE ; Zeiger abspeichern
SIBR10: pop IX ; Register restaurieren
pop HL
pop DE
pop BC
pop AF
ei ; Interrupts wieder erlauben
reti ; das war's
; +---------------------------------------------------------------------+
; | |
; | "SIO channel B Special Receive Condition" - Interruptservice |
; | |
; | RS232-Fehlerbedingung ruecksetzen. Nicht auswerten - Fehler ist |
; | Fehler und im Kommunikationsablauf passiert nix (Crosslink-Frame |
; | ist eh kaputt, und wen interessierts am Hostterminal, w a s |
; | passiert ist). |
; | |
; +---------------------------------------------------------------------+
SIBSRC: push AF ; benutztes Register sichern
ld A,30h ; SIO Kanal B (RS232) Error Reset
out (SIBCTL),A ; (Achselzucken. Kann ja nix passieren.)
pop AF ; benutztes Register restaurieren
ei ; Interrupts wieder erlauben
reti ; das war's
; +---------------------------------------------------------------------+
; | |
; | "SIO channel A Tx Buffer Empty" - Interruptservice |
; | |
; | HDLC SIO TX-Buffer leer, naechstes Zeichen aus HDLC-TX-Framebuffer |
; | holen und senden, wenn innerhalb Frame. Bei Frameende ohne Zeichen- |
; | ausgabe in den Underrun/EoM-Interrupt laufen lassen. |
; | Nach einem Underrun/EoM-Interrupt entweder neues Frame beginnen |
; | (es sind noch weitere vorhanden) oder Dummyframe zur Feststellung |
; | des Endes des vorherigen Frames beginnen (keine weiteren mehr |
; | vorhanden). Nachdem ueber das Dummyframe Ende (Flag von vorherigem |
; | Frame hat SIO verlassen) des vorherigen Frames festgestellt wurde, |
; | Sender abschalten. |
; | |
; +---------------------------------------------------------------------+
extrn xFpar? ; 1 = Flags in Pausen senden, 0 sonst
SIATBE: push AF ; Register sichern
push BC
push DE
push HL
push IX
ld A,28h ; SIO Kanal A (HDLC) Reset TX Int Pending
out (SIACTL),A
ld HL,HTXSTA ; HDLC-TX innerhalb Frame Datenbytes ?
ld A,(HL)
sub 5
jr NZ,SIAT1 ; nein -
ld L,A ; ja - Zeichen aus HDLC-TX-Framebuffer
ld H,A ; (HL=0) holen in HL
call GETSRV
ld A,L ; Zeichen in A
bit 7,H ; Frame zueende ?
jr Z,SIAT4 ; nein - Zeichen an HDLC-Port ausgeben
ld HL,HTXSTA ; ja - TX-State "Frameende, weitere folgen"
inc (HL)
bit 0,A ; folgen noch weitere Frames ?
jr Z,SIAT5 ; ja - dann war's das (ab in Underrum/EoM)
inc (HL) ; nein - TX-State "Frameende, keine weiteren"
jr SIAT5 ; das war's dann (ab in Underrun/EoM)
SIAT1: dec A ; TX-State 6 "Frameende, weitere folgen" ?
jr NZ,SIAT2
dec (HL) ; ja - TX-State 6 -> 5, "Innerhalb Frame",
call HTXSOF ; neues Frame beginnen
jr SIAT5 ; das war's
SIAT2: dec A ; nein - TX-State :
jr Z,SIAT3 ; 7: 1. CRC-Byte gesendet, TX-State 7 -> 8,
; Dummyframe zur Feststellung des
; sicheren Endes des vorherigen Frames
; mit 00h beginnen
dec A
jr Z,SIAT3 ; 8: CRC verlaesst SIO, TX-State 8 -> 9,
; 00h an Dummyframe
dec A
jr Z,SIAT3 ; 9: Flag verlaesst SIO, TX-State 9 -> 10,
; 00h an Dummyframe
dec A
jr NZ,SIAT5 ; <5: -> ignorieren (Dummyframeende)
ld (HL),A ; 10: Flag komplett gesendet,
; TX-State 10 -> 0, Sender abschalten
ld A,5 ; Pin /RTS high = Ptt aus, TX Disable
out (SIACTL),A
ld HL,SIAWR5
res 1,(HL)
ld A,(xFpar?) ; ( Flags in Pausen ein ? )
or A
jr NZ,SIAT2a ; ( ja - SIO-TX eingeschaltet lassen )
res 3,(HL) ; ( nein - SIO-TX ausschalten )
SIAT2a: ld A,(HL)
out (SIACTL),A ; neuen Sendemodus merken
ld A,(Dpar?) ; Vollduplex an ?
or A
call Z,HRXRES ; nein - HDLC-RX resetten = einschalten
jr SIAT5 ; das war's
SIAT3: inc (HL) ; naechster TX-State
SIAT4: out (SIADAT),A ; Zeichen an SIO
SIAT5: pop IX ; Register restaurieren
pop HL
pop DE
pop BC
pop AF
ei ; Interrupts wieder erlauben
reti ; das war's
; +---------------------------------------------------------------------+
; | |
; | "SIO channel A External Status Change" - Interruptservice |
; | |
; | Falls Sender aus und Frameabort empfangen, HDLC-RX resetten, gerade |
; | aktives Frame auf den Muell. |
; | |
; | Falls HDLC-TX-Underrun, Frame Abort senden und Frame noch einmal |
; | senden. |
; | |
; | Falls DCD von an auf aus gewechselt hat und sich Sender in Zustand |
; | "nach DCD aus leite Sendesequenz oder WAIT-Warten ein" befindet, |
; | die naechste Sequenz entsprechend einleiten. |
; | |
; | Falls DCD von aus auf an gewechselt hat und sich der Sender in |
; | WAIT-Warte-Sequenz befindet, dann WAIT-Warten abbrechen und nach |
; | naechstem Wechsel an auf aus wieder neu von vorne. |
; | |
; +---------------------------------------------------------------------+
SIAESC: push AF ; Register sichern
push BC
push DE
push HL
push IX
in A,(SIACTL) ; neuen Status holen
ld B,A ; B = neuer Status
ld A,10h ; SIO Kanal A (HDLC) Reset External/Status
out (SIACTL),A ; Interrupts
ld HL,SIARR0
ld A,(HL) ; alten Status holen
ld (HL),B ; neuen Status merken
xor B ; C = was hat sich geaendert ?
ld C,A
ld HL,HTXSTA ; TX innerhalb Frame Datenbytes ?
ld A,(HL)
cp 5
jr NZ,SIAE1 ; nein -
bit 6,B ; ja - TX-Underrun ?
jr Z,SIAE1 ; nein - war wohl DCD-Wechsel
push AF
push BC
push HL
ld A,08h ; ja - Programm nicht schnell genug, Frame
out (SIACTL),A ; "ordentlich" mit Abort beenden,
ld (HL),6 ; TX-State "letztes Byte aus Frame
; gesendet, weitere Frames folgen",
ld HL,8000h ; aktuellen HDLC-TX-Framebuffer
call GETSRV ; "rewinden" = Frame gleich noch
pop HL ; einmal probieren
pop BC
pop AF
SIAE1: bit 3,C ; hat DCD gewechselt ?
jr Z,SIAE4 ; nein - dann kann es RX Abort sein
push BC ; Status sichern
bit 3,B ; DCD angegangen ?
jr NZ,SIAE2 ; ja -
or A ; nein - DCD ausgegangen - Sender inaktiv ?
jr Z,SIAE3 ; ja - DCD-Wechsel ignorieren
cp 3 ; nein - TX-State 1 oder 2,
; "TX-Sequenz bei DCD aus einleiten" ?
jr NC,SIAE3 ; nein - DCD-Wechsel ignorieren
call HTXINI ; ja - Sendesequenz einleiten
jr SIAE3
SIAE2: cp 3 ; DCD angegangen, waehrend "WAIT abwarten" ?
jr NZ,SIAE3 ; nein - DCD-Wechsel ignorieren
ld A,(Dpar?) ; ja - Vollduplex an ?
or A
jr NZ,SIAE3 ; ja - DCD ignorieren
ld (HL),1 ; nein - Spiel von vorn, TX-State "nachdem
; DCD aus WAIT-Sequenz einleiten",
xor A ; Wartezaehler inaktivieren
ld (HTXWAI),A
SIAE3: pop BC ; Status restaurieren
SIAE4: bit 7,C ; hat HDLC RX ein Abort empfangen ?
call NZ,HRXRE1 ; ja - eingeschalteten Empfaenger resetten
SIAE5: pop IX ; Register restaurieren
pop HL
pop DE
pop BC
pop AF
ei ; Interrupts wieder erlauben
reti ; das war's
; +---------------------------------------------------------------------+
; | |
; | "SIO channel A Rx Character Available" - Interruptservice |
; | |
; | Zeichen aus HDLC-Kanal ist angekommen. Ist es das erste Zeichen |
; | eines neuen Frames, dann neuen Framebuffer anlegen, Zeichen merken. |
; | Sonst Zeichen merken und vorheriges Zeichen in den Framebuffer |
; | schreiben (vorheriges Zeichen, damit nicht vor dem Anzeigen des |
; | Frameendes CRC-Byte in den Buffer geraet). Bei zu langem Frame |
; | RX resetten und Frame wegwerfen. |
; | |
; +---------------------------------------------------------------------+
SIARCA: push AF ; Register sichern
push BC
push DE
push HL
push IX
in A,(SIADAT) ; Zeichen holen SIO Kanal A (HDLC)
ld HL,HRXSTA ; RX-State = 1, d.h. "Innerhalb Frame" ?
inc (HL)
dec (HL)
jr NZ,SIAR1
inc (HL) ; nein - "Ausserhalb" -> "Innerhalb Frame"
ld (HRXLCH),A ; Zeichen im 1-Zeichen-FIFO merken
ld BC,8001h ; neuer HDLC-RX-Buffer
call PUTSRV
jr SIAR2 ; das war's
SIAR1: ld HL,HRXLCH ; ja - "Innerhalb Frame",
ld C,(HL) ; altes Zeichen gueltige Info
ld (HL),A ; neues altes Zeichen
ld B,0000h ; gueltiges Zeichen in den
call PUTSRV ; HDLC-RX-Buffer schreiben
dec L ; Fehler dabei, d.h. Frame zu lang ?
call Z,HRXRES ; ja -> HDLC-RX Reset, Frame wegwerfen
SIAR2: pop IX ; Register restaurieren
pop HL
pop DE
pop BC
pop AF
ei ; Interrupts wieder erlauben
reti ; das war's
; +---------------------------------------------------------------------+
; | |
; | "SIO channel A Special Receive Condition" - Interruptservice |
; | |
; | Bei richtigem Frameende (CRC ok, kein Overrun, volle Bytes) wird |
; | Frame in die HDLC-RX-Frameliste eingehaengt, sonst wird das |
; | aktuelle Frame weggeworden. |
; | |
; +---------------------------------------------------------------------+
SIASRC: push AF ; Register sichern
push BC
push DE
push HL
push IX
ld A,1 ; SIO Kanal A (HDLC) RR1 = Fehlerstatus holen
out (SIACTL),A
in A,(SIACTL)
ld B,A ; Fehlerstatus sichern
ld A,30h ; SIO Kanal A (HDLC) Error Reset
out (SIACTL),A
ld A,B ; Fehlerstatus restaurieren
ld BC,8001h ; "aktiven HDLC-RX-Framebuffer auf den Muell"
bit 5,A ; RX Overrun ?
jr NZ,SIAS1 ; ja - Frame wegwerfen
bit 7,A ; End of Frame ?
jr Z,SIAS2 ; nein - nix tun (war "All Sent")
bit 6,A ; CRC Fehler ?
jr NZ,SIAS1 ; ja - Frame wegwerfen
and 0Eh ; nein - war Frame modulo 8 Bit und letztes
; gueltiges Zeichen vorletztes
; Zeichen (letztes in Buffer) ?
cp 6
jr NZ,SIAS1 ; nein - Frame wegwerfen
dec C ; ja - Frame ok, in HDLC-RX-Liste haengen
SIAS1: call HRXNEW ; Bufferkommando ausfuehren, Frame zuende
SIAS2: pop IX ; Register restaurieren
pop HL
pop DE
pop BC
pop AF
ei ; Interrupts wieder erlauben
reti ; das war's
; +---------------------------------------------------------------------+
; | |
; | "Hostterminal TX FIFO character out" |
; | |
; | Wenn noch Zeichen im Hostterminal-TX-FIFO, dann Zeichen aus diesem |
; | FIFO holen und an RS232 ausgeben. |
; | |
; | A, DE, HL bentzt. |
; | |
; +---------------------------------------------------------------------+
HTXFCO: ld HL,(HOTXCC) ; Zeichen in TX-FIFO ?
ld A,H
or L
ret Z ; nein - nix tun
dec HL ; ja - TX-FIFO Zeichenzaehler - 1
ld (HOTXCC),HL
ld HL,(HOTXOP) ; Zeiger auf Zeichen
ld A,(HL) ; Zeichen holen
out (SIBDAT),A ; an SIO Kanal B (RS232) ausgeben
inc HL ; Zeiger auf naechstes Zeichen
ex DE,HL
ld HL,HOTXFI+HOTXFL-1 ; Zeiger > letzte FIFO-Stelle, d.h.
or A ; "FIFO Wrap Around" ?
sbc HL,DE
jr NC,HTXFC1 ; nein -
ld DE,HOTXFI ; ja - Zeiger wieder auf FIFO-Anfang
HTXFC1: ld (HOTXOP),DE ; Zeiger abspeichern
ret ; das war's
; +---------------------------------------------------------------------+
; | |
; | CTXINI "Crosslink TX initialize" |
; | Sender initialisieren, ggf. mit "Async"-WAIT. |
; | A = 1 -> Sender mit "Async"-WAIT initialiseren |
; | A = 2 -> Sender ohne "Async"-WAIT initialisieren, gleich zu |
; | CTXPRE |
; | |
; | CTXPRE "Crosslink TX preset" |
; | 2,5 msec Crosslink-"Vorlauftraeger" setzen. |
; | |
; | CTXSTX "Crosslink TX start of text" |
; | Crosslinkframe beginnen mit ASCII Start of Text. |
; | |
; | A, DE, HL benutzt. |
; | |
; +---------------------------------------------------------------------+
CTXINI: inc A ; naechster Sendestatus 1/2 -> 3/4
inc A
ld HL,CTXSTA
ld (HL),A
cp 4 ; erstes Frame zu digipeatendes Frame ?
jr Z,CTXPRE ; nein - kein "Async"-WAIT
call random? ; ja - "Async"-WAIT beachten
and 1Fh ; 3 < A < 32 = 2,5 msec ... 25 msec
or 03h ; (1200Hz/3 ... 1200Hz/32)
ld (CTXWAI),A
ret
CTXPRE: ld A,5 ; 2,5 msec Crosslink-"Vorlauftraeger" setzen
out (SIBCTL),A
ld HL,SIBWR5
res 1,(HL) ; "/RTS high after TX empty" -> /RTS high
ld A,(HL) ; = Modemstecker CTS low
out (SIBCTL),A ; = Crosslink-"Traeger" ein
ld A,3 ; 2,5 msec (1200Hz/3)
ld (CTXWAI),A
ret ; das war's
CTXSTX: ld (HL),5 ; Sendestatus "Innerhalb Crosslink-Frame"
xor A
ld (CTXFCS),A ; Sende-Framechecksumme initialisieren
ld (CTXCSA),A ; "kein STX/ETX/DLE innerhalb Frame"
ld A,ASTX ; Frame beginnt mit ASCII STX,
out (SIBDAT),A ; Interruptsender an-"kicken"
ret ; das war's
; +---------------------------------------------------------------------+
; | |
; | HOINIT "Host initialize" |
; | Alle Hostterminal-FIFO's (RX und TX) resetten, Crosslink- |
; | "Traeger" ausschalten. |
; | |
; | CCOFF "Crosslink carrier off" |
; | Crosslink-"Traeger" ausschalten = Pin /RTS low = Modemstecker |
; | CTS high. |
; | |
; | A, HL benutzt. |
; | |
; +---------------------------------------------------------------------+
HOINIT: ld HL,0
ld (HORXCC),HL ; alle Hostterminal-FIFO's resetten
ld (HOTXCC),HL
ld HL,HORXFI
ld (HORXIP),HL
ld (HORXOP),HL
ld HL,HOTXFI
ld (HOTXIP),HL
ld (HOTXOP),HL
CCOFF: ld A,5 ; SIO Kanal B (RS232)
out (SIBCTL),A
ld HL,SIBWR5 ; Pin /RTS low = Modemstecker CTS high
set 1,(HL) ; = Crosslink-"Traeger aus"
ld A,(HL)
out (SIBCTL),A
ret
; +---------------------------------------------------------------------+
; | |
; | HTXINI "HDLC TX initialize" |
; | Sender initialisieren, ggf. mit WAIT. |
; | A = 1 -> Sender mit WAIT initialiseren |
; | A = 2 -> Sender ohne WAIT initialisieren, gleich zu HTXKUP |
; | |
; | HTXKUP "HDLC TX key up" |
; | HDLC RX abschalten, Sender einschalten, PTT ein, TXDELAY starten. |
; | |
; | HTXSOF "HDLC TX start of frame" |
; | Zeichen aus TX-Framebuffer holen und mit diesem Zeichen neues |
; | Frame beginnen. |
; | |
; | A, DE, HL benutzt. |
; | |
; +---------------------------------------------------------------------+
extrn Wpar? ; WAIT-Parameter in 10 msec
extrn Ppar? ; P-Persistenz-Wert
extrn Tpar? ; TXDELAY-Parameter in 10 msec
HTXINI: inc A ; naechster Sendestatus 1/2 -> 3/4
inc A
ld (HL),A
cp 4 ; erstes Frame zu digipeatendes Frame ?
jr Z,HTXKUP ; ja - kein WAIT beachten
ld A,(Dpar?) ; nein - Vollduplexbetrieb ?
or A
jr NZ,HTXIN1 ; ja - Sender sofort hochfahren
push HL ; nein - (Zeiger auf HTXSTA sichern)
call random? ; Zufallszahl <= P-Persistenz-Wert ?
ld A,(Ppar?)
cp L
pop HL ; (Zeiger auf HTXSTA wiedereinsetzen)
jr NC,HTXIN1 ; ja - Sender hochfahren
ld A,(Wpar?) ; nein - Slottime abwarten
ld (HTXWAI),A
or A ; falls Slottime = 0 gleich weiter
ret NZ
HTXIN1: inc (HL) ; TX-State 3 -> 4
HTXKUP: ld A,(Dpar?) ; Vollduplexbetrieb ?
or A
jr NZ,HTXKU0
ld A,3 ; nein - "RX disable" = HDLC-Empfaenger
out (SIACTL),A ; abschalten
ld A,(SIAIW3)
res 0,A
out (SIACTL),A
HTXKU0: ld A,5 ; "TX enable", Pin /RTS low =
out (SIACTL),A ; HDLC-Sender einschalten, PTT ein
ld HL,SIAWR5
set 3,(HL)
set 1,(HL)
ld A,(HL)
out (SIACTL),A ; (geaenderten Sende-Modus merken)
ld A,(Tpar?) ; TXDELAY in Wartezaehler
ld (HTXWAI),A
or A ; TXDELAY-Parameter > 0 ?
ret NZ ; ja - TXDELAY abwarten
ld HL,HTXSTA ; nein - kein TXDELAY (TX State = 5)
inc (HL)
HTXSOF: ld HL,0 ; "Zeichen holen aus HDLC-TX-Framebuffer"
call GETSRV ; Zeichen holen in L
ld A,80h ; "Reset HDLC TX CRC Generator"
out (SIACTL),A
ld A,L ; Zeichen ausgeben, erstes Zeichen in Frame,
out (SIADAT),A ; dadurch Interrupt-Sender ange-"kickt"
ld A,0C0h ; "Reset HDLC TX Underrun/EoM Latch",
out (SIACTL),A ; damit Frameende erkannt werden kann
ret ; das war's
; +---------------------------------------------------------------------+
; | |
; | "get service" |
; | |
; | l1get-Aufruf mit HL als Parameter, Ergebnis in HL zurueck. |
; | Auch von innerhalb Interruptroutinen aufrufbar, da Interrupt- |
; | verbietungsstufe beibehalten wird, o h n e ggf. ein EI bei |
; | l1get-Aufruf auszuloesen. |
; | |
; | l1get ist die TX-Buffer-Verwaltung, Zeichen holen, Kommandos zur |
; | Bufferbehandlung, Meldungen zum Bufferzustand. |
; | |
; | A, DE benutzt. |
; | |
; +---------------------------------------------------------------------+
external l1get? ; C TX-Buffer-Verwaltung
GETSRV: push HL ; Aufrufparameter fuer C-Routine l1get
ld HL,DEICNT ; zu fruehes EI durch l1get verhindern
inc (HL)
call l1get? ; C-Routine l1get ausfuehren
ex DE,HL ; Ergebnis von l1get in DE
ld HL,DEICNT ; wieder alte Interrupt-Verbietungsstufe
dec (HL)
ex DE,HL ; Ergebnis von l1get in HL
pop DE ; Stack korrigieren (l1get Parameter)
ret ; das war's
; +---------------------------------------------------------------------+
; | |
; | HRXRES "HDLC RX Reset" |
; | HDLC RX neu anfangen lassen, SIO und Buffer initialisieren. |
; | |
; | HRXRE1 |
; | Wie HRXRES, aber SIO in Ruhe lassen, nur Buffer initialisieren. |
; | |
; | HRXNEW "HDLC RX New" |
; | Wie PUTSRV, am Frameende. Restzeichen aus SIO entfernen, |
; | Empfangsstatus initialiseren fuer naechstes Frame. |
; | |
; | PUTSRV "put service" |
; | l1put-Aufruf mit BC als Parameter, Ergebnis in HL zurueck. |
; | Auch von innerhalb Interruptroutinen aufrufbar, da Interrupt- |
; | verbietungsstufe beibehalten wird, o h n e ggf. ein EI bei |
; | l1get-Aufruf auszuloesen. |
; | |
; | l1put ist die RX-Buffer-Verwaltung, Zeichen schreiben, Kommandos |
; | zur Bufferbehandlung, Meldungen zum Bufferzustand. |
; | |
; | A, BC, DE benutzt. |
; | |
; +---------------------------------------------------------------------+
external l1put? ; C RX-Buffer-Verwaltung
HRXRES: ld A,03h ; SIO Kanal A, RX CRC enable, CRC enable,
out (SIACTL),A ; Hunt Phase (initiales WR3)
ld A,(SIAIW3)
out (SIACTL),A
HRXRE1: ld BC,8001H ; aktiven RX-Framebuffer auf den Muell,
; wenn nicht leer, sonst neuen beginnen
HRXNEW: in A,(SIADAT) ; Zeichen aus HDLC-Kanal holen und vergessen
xor A ; HDLC RX-State : "RX ausserhalb Frame"
ld (HRXSTA),A
PUTSRV: push BC ; Aufrufparameter fuer l1put
ld HL,DEICNT ; zu fruehes EI durch l1put verhindern
inc (HL)
call l1put? ; C-Routine l1put ausfuehren
ex DE,HL ; l1put-Returnwert merken
ld HL,DEICNT ; wieder alte Interrupt-Verbietungsstufe
dec (HL)
ex DE,HL ; l1put-Returnwert restaurieren
pop BC ; Stack korrigieren (l1put Parameter)
ret ; das war's
; +---------------------------------------------------------------------+
; | |
; | C : BOOLEAN iscd(port) unsigned port; "is carrier detect" |
; | |
; | Test, ob Port (Kanal) mit Nummer port belegt ist (d.h. nicht |
; | gesendet werden darf). |
; | |
; | port = 0 : HDLC Modemport |
; | = 1 : RS232 Crosslinkport |
; | |
; | |
; | TRUE - (HL=1, Z=0) Kanal ist belegt |
; | |
; | FALSE - (HL=0, Z=1) Kanal ist frei (oder Vollduplex-HDLC) |
; | |
; | |
; | A benutzt, HL Returnwert. |
; | |
; +---------------------------------------------------------------------+
public iscd?
iscd?: ld HL,2 ; Portnummer als 16-Bit-C-Parameter vom
add HL,SP ; Stack holen
ld A,(HL)
ld HL,0 ; default Returnwert FALSE
dec A ; Crosslink-Port (RS232), d.h. 1 ?
jr NZ,iscd2 ; nein -
;
; Crosslink-Port
;
ld A,(SIBRR0) ; ja - SIO Kanal B Status holen
and 00100000b ; Pin /CTS low = Modem DTR high ("1") ?
jr NZ,iscd1
inc A ; nein - H=1, Z=0, TRUE zurueck
ld L,A ; (Kanal belegt)
ret
iscd1: xor A ; ja - H=0, Z=1, FALSE zurueck
ret ; (Kanal frei)
;
; HDLC-Port
;
iscd2: ld A,(Dpar?) ; Vollduplexbetrieb ?
dec A
ret Z ; ja - Z = 1, A = 0, HL = 0, FALSE
ld A,(SIARR0) ; SIO Kanal A Status holen
bit 3,A ; SIO Kanal A DCD an ?
ret Z ; nein - FALSE zurueck (Kanal frei)
inc HL ; ja - TRUE zurueck (Kanal belegt)
ret
; +---------------------------------------------------------------------+
; | |
; | C : BOOLEAN ishost() "is host terminal" |
; | |
; | Rueckgabe : TRUE, HL = 1, Z = 0 - Hostterminal an RS232 |
; | FALSE, HL = 0, Z = 1 - Crosslink an RS232 |
; | |
; | A benutzt. |
; | |
; +---------------------------------------------------------------------+
public ishost?
ishost?: ld HL,0 ; Rueckgabe-Preset FALSE
ld A,(SIBRR0) ; DCD an RS232 (SIO Kanal B) ?
and 00001000b
ret Z ; nein - FALSE zurueck (Crosslink)
inc HL ; ja - TRUE zurueck (Hostterminal)
ret ; das war's
; +---------------------------------------------------------------------+
; | |
; | C : char *minmem() "minimum memory" |
; | |
; | Niedrigste nutzbare RAM-Freispeicherstelle in HL zurueck, |
; | Test auf 0 fuer C-Kompatibilitaet. |
; | |
; | A benutzt. |
; | |
; +---------------------------------------------------------------------+
public minmem?
external fremem? ; erste Speicherstelle Freispeicher
minmem?: ld HL,fremem? ; niedrigste nutzbare RAM-Freispeicherstelle
ld A,H ; als C-Funktionswert zurueck
or L
ret ; das war's
; +---------------------------------------------------------------------+
; | |
; | C : char *maxmem() "maximum memory" |
; | |
; | Hoechste nutzbare RAM-Freispeicherstelle in HL zurueck, |
; | Test auf 0 fuer C-Kompatibilitaet. |
; | |
; | A benutzt. |
; | |
; +---------------------------------------------------------------------+
public maxmem?
maxmem?: ld HL,(RAMTOP) ; hoechste nutzbare RAM-Freispeicherstelle
ld A,H ; als C-Funktionswert zurueck
or L
ret ; das war's
; +---------------------------------------------------------------------+
; | |
; | C : VOID DIinc() "disable interrupt increment" |
; | |
; | Interrupts verbieten, Verbietungsstufe erhoehen. |
; | |
; | |
; | HL benutzt. |
; | |
; +---------------------------------------------------------------------+
public DIinc?
DIinc?: di ; Interrupts verbieten
ld HL,DEICNT ; auf die naechste Verbietungsstufe
inc (HL)
ret ; das war's
; +---------------------------------------------------------------------+
; | |
; | C : VOID decEI() "decrement enable interrupt" |
; | |
; | Verbietungsstufe erniedrigen, wenn dann gleich 0, Interrupts |
; | wieder erlauben. |
; | |
; | HL benutzt. |
; | |
; +---------------------------------------------------------------------+
public decEI?
decEI?: ld HL,DEICNT ; Verbietungsstufe - 1
dec (HL) ; Erlaubnis erreicht ?
ret NZ ; nein - dann war's das
ei ; ja - Interrupts wieder erlauben
ret ; das war's
; +---------------------------------------------------------------------+
; | |
; | C : BOOLEAN CONled(on) BOOLEAN on; "CONNECT-LED" |
; | |
; | Ein- oder Ausschalten der CONNECT-LED. |
; | |
; | Parameter : on = TRUE, 1 -> LED anschalten |
; | on = FALSE, 0 -> LED ausschalten |
; | |
; | A, HL benutzt. |
; | |
; +---------------------------------------------------------------------+
public CONled?
CONled?: di ; Int's duerfen nicht dazwischenfunken
ld A,5 ; /DTR-Pin = LED-Ausgang wird ueber SIO
out (SIBCTL),A ; Register 5 angesteuert
ld HL,2 ; Zeiger auf Parameter
add HL,SP
ld A,(HL) ; Parameter low Byte holen
rrca ; Bit 0 -> Bit 7
xor 80h ; Bit 0-6 loeschen, Bit 7 invertieren
ld HL,SIBWR5
res 7,(HL) ; SIO B /DTR Pin entsprechend Parameter
or (HL) ; (on = TRUE -> Pin /DTR low -> LED ein)
ld (HL),A
out (SIBCTL),A ; selbiges auch merken
ei ; Interrupts wieder erlauben
ret ; das war's
; +---------------------------------------------------------------------+
; | |
; | C : BOOLEAN STAled(on) BOOLEAN on; "STATUS-LED" |
; | |
; | Ein- oder Ausschalten der STATUS-LED. |
; | |
; | Parameter : on = TRUE, 1 -> LED anschalten |
; | on = FALSE, 0 -> LED ausschalten |
; | |
; | A, HL benutzt. |
; | |
; +---------------------------------------------------------------------+
public STAled?
STAled?: di ; Int's duerfen nicht dazwischenfunken
ld A,5 ; /DTR-Pin = LED-Ausgang wird ueber SIO
out (SIACTL),A ; Register 5 angesteuert
ld HL,2 ; Zeiger auf Parameter
add HL,SP
ld A,(HL) ; Parameter low Byte holen
rrca ; Bit 0 -> Bit 7
xor 80h ; Bit 0-6 loeschen, Bit 7 invertieren
ld HL,SIAWR5
res 7,(HL) ; SIO A /DTR Pin entsprechend Parameter
or (HL) ; (on = TRUE -> Pin /DTR low -> LED ein)
ld (HL),A
out (SIACTL),A ; selbiges auch merken
ei ; Interrupts wieder erlauben
ret ; das war's
; +---------------------------------------------------------------------+
; | |
; | C : VOID srand() |
; | |
; | Zufallszahlengenerator initialisieren. |
; | |
; +---------------------------------------------------------------------+
public srand?
srand?: ld A,R ; 0 <= A <=127 (oder 128 <= A <= 255)
ld L,A ; URAND = A
ld H,0
ld (URAND),HL
ret
; +---------------------------------------------------------------------+
; | |
; | C : unsigned random() |
; | |
; | 8-Bit Quasi-Zufallszahl (0..255) holen in A und HL. |
; | |
; +---------------------------------------------------------------------+
public random?
random?: ld HL,(URAND) ; URAND rueckgekoppelt linksschieben
ld A,H ; (Zweck: Gleichverteilung random())
and 01100000b
jp PO,rand1
scf
rand1: adc HL,HL
ld (URAND),HL
ld A,R ; 0 <= A <=127 (oder 128 <= A <= 255)
add A,A ; 0 <= A <= 254, gerade
inc A ; 1 <= A <= 255, ungerade
xor L ; 0 <= A <= 255
ld L,A ; HL = A
ld H,0 ; (nur LSB signifikant)
ret ; das war's
end