| Assembler-Beispiele für 80C166-Controller
|
|
Das Prinzip des Programms:
Jede Millisekunde wird von Timer 3 ein Interrupt ausgelöst. In der ISR werden unterschiedliche
Zähler-Variablen aktualisiert (1, 10, 100, 1000 ms) und Zeit-Variablen bis auf 0 dekrementiert.
Damit stehen eine Vielzahl unterschiedlicher "Software-Timer" zu Verfügung.
Dieses Programm kann mit einem ASCII-Terminal-Programm kommunizieren. Die Kommunikation erfolgt über die
asynchrone serielle Schnittstelle des 80C166 mit 9600 Baud, 8 Bit, ohne Parität.
Alle ankommenden Bytes lösen einen Interrupt aus und werden von der ISR in einem Empfangs-Ring-Puffer
abgelegt. Von dort können sie "bei Gelegenheit" entnommen und weiter verarbeitet werden.
Ausgabe-Bytes werden in einem Sende-Ring-Puffer abgelegt. Alle 0,93 ms wird in der ISR
überprüft, ob Bytes zum Versenden abgelegt wurden und ggf. an die USART übergeben.
|
| Include-Datei "BAS_DEF.A66"
|
|
$NOPAGING
$PL (68)
$PW (132)
$TABS (8)
$NOCASE
$MOD166
$SEGMENTED
; =============================================================
; Register-Bänke
; =============================================================
REG_Mon REGDEF R0-R15 ; Registerbank für Monitor-Programm
REG_1ms REGDEF R0-R15 ; Registerbank für 1 ms-Interrupt
; =============================================================
; Port-Adressen (Decoder) von 3$8000h - 3$B800h
; =============================================================
A_IO EQU 3$8000h
CS0 EQU 3$8000h
CS1 EQU 3$8800h
CS2 EQU 3$9000h
CS3 EQU 3$9800h
CS4 EQU 3$A000h
CS5 EQU 3$A800h
WatchDog EQU 3$B000h ; WatchDog
UhrPort EQU 3$B800h ; Uhrenbaustein RTC 27241
; =============================================================
; Deklarationen
; =============================================================
SSKDEF 1 ; 128 Word Stacksize
BOS EQU 0FC00h ; Bottom of Stack
TOS EQU 0FB00h ; Top of Stack
SPAdr EQU BOS-2 ; Stackpointer-Adresse
TrapAdr EQU 0FA00h ; Puffer-Adresse für HW-Traps
VN_Sio EQU 21h ; (T1) Sio-Interrupt
VN_1ms EQU 23h ; (T3) 1 ms-Interrupt
VN_TxD EQU 2Ah ; TxD-Interrupt
VN_RxD EQU 2Bh ; RxD-Interrupt
LenRxD EQU 508 ; Länge RxD-Puffer
LenTxD EQU 1300 ; Länge TxD-Puffer
WaitEEP EQU 6 ; ms Wartezeit nach EEPROM-Write
Lf EQU 10 ; LineFeed
Cr EQU 13 ; Return
Lz EQU 32 ; Leerzeichen
Dip1 EQU P3.4 ; Dip-Schalter
Dip2 EQU P3.5
Dip3 EQU P3.6
Dip4 EQU P3.7
|
| Variablen-Datei "BAS_VAR.A66"
|
|
$INCLUDE (BAS_DEF.A66)
; #############################################################
S_BIT SECTION DATA BITADDRESSABLE PUBLIC
| ; ---------------------------------------------------------------
; Bereich für MONitor-Daten
; ---------------------------------------------------------------
| MONBANK DSW 16 ; FD00 Registerbank für MON166
PrgRegBank DSW 24 ; FD20 Registerbank des Monitor-Hauptprogramms
| ; ---------------------------------------------------------------
; Bereich fuer User-Bits
; ---------------------------------------------------------------
| PUBLIC FLG_DIV
PUBLIC F_Init, F_OK
FLG_DIV DSW 1 ; Bitadressierbares Word
F_Init BIT FLG_DIV.0
F_OK BIT FLG_DIV.15
S_BIT ENDS
; #############################################################
S_VAR SECTION DATA PUBLIC
| ; ---------------------------------------------------------------
; Bereich fuer User-Variablen
; ---------------------------------------------------------------
| PUBLIC ZLR_1, ZLR_10, ZLR_100, ZLR_1S
ZLR_1 DSW 1 ; Incrementierer 1 ms
ZLR_10 DSW 1 ; Decrementierer 10 ms
ZLR_100 DSW 1 ; Decrementierer 100 ms
ZLR_1S DSW 1 ; Decrementierer 1 Sek
PUBLIC TIM_1, TIM_10, TIM_100, TIM_1S
TIM_1 DSW 1 ; 1 ms-Timer
TIM_10 DSW 1 ; 10 ms-Timer
TIM_100 DSW 1 ; 100 ms-Timer
TIM_1S DSW 1 ; 1 Sek-Timer
PUBLIC ZLR_Inp
ZLR_Inp DSW 1 ; Zähler von Eingang 1 / 2
PUBLIC EINGP1, AUSGP1
EINGP1 DSW 1 ; Aktueller Zustand der Eingänge
AUSGP1 DSW 1 ; Soll-Zustand der Ausgänge
PUBLIC PNT_RXD, POS_RXD, PUF_RXD
PNT_RXD DSW 1 ; RxD Pointer Empfangs-Daten
POS_RXD DSW 1 ; RxD Position Empfangs-Daten
PUF_RXD DSB LenRxD ; RxD Puffer
EVEN
PUBLIC PNT_TXD, POS_TXD, PUF_TXD
PNT_TXD DSW 1 ; TxD Pointer Sende-Daten
POS_TXD DSW 1 ; TxD Position Sende-Daten
PUF_TXD DSB LenTxD ; TxD Puffer
EVEN
S_VAR ENDS
END
|
| Hauptprogramm-Datei "BASIS.A66"
|
|
; =============================================================
; .... Programm-Beschreibung
; =============================================================
$TITLE ("Titel des Programms")
$INCLUDE (BAS_DEF.A66)
NAME BASIS
PUBLIC SendStr, SendChr, SendCrLf
PUBLIC SendNibl, SendWord
PUBLIC Tim_1ms
EXTERN InitTrap :near, InitInt :near, InitIntVect:near
; #############################################################
S_BIT SECTION DATA BITADDRESSABLE PUBLIC
; ---------------------------------------------------------------
; Externe Bits
; ---------------------------------------------------------------
EXTERN FLG_DIV :word
EXTERN F_Init :bit
EXTERN F_OK :bit
S_BIT ENDS
; #############################################################
S_VAR SECTION DATA PUBLIC
; ---------------------------------------------------------------
; Externe Variablen
; ---------------------------------------------------------------
EXTERN ZLR_1 :word, ZLR_10 :word, ZLR_100 :word, ZLR_1S :word
EXTERN TIM_1 :word, TIM_10 :word, TIM_100 :word, TIM_1S :word
EXTERN ZLR_Inp :word
EXTERN EINGP1 :word, AUSGP1 :word
EXTERN PNT_RXD :word, POS_RXD :word, PUF_RXD :byte
EXTERN PNT_TXD :word, POS_TXD :word, PUF_TXD :byte
S_VAR ENDS
; #############################################################
PAGE3 DGROUP SYSTEM, S_BIT, S_VAR
ASSUME DPP0:NOTHING
ASSUME DPP1:NOTHING
ASSUME DPP2:NOTHING
ASSUME DPP3:PAGE3
; #############################################################
|
S_COD SECTION CODE PUBLIC
P_INI PROC NEAR
| DISWDT ; Watchdog abschalten
MOV DPP0,#0 ; Page 0 = 0$0000h - 0$3FFFh
MOV DPP1,#1 ; Page 1 = 0$4000h - 0$7FFFh
MOV DPP2,#2 ; Page 2 = 0$8000h - 0$BFFFh
MOV DPP3,#3 ; Page 3 = 0$C000h - 0$FA00h
; und System-Speicher
MOV STKUN,#BOS ; Stack-Untergrenze setzen
MOV STKOV,#TOS ; Stack-Obergrenze setzen
MOV SP,#SPAdr ; Stack-Pointer setzen
; -------------------------------------
; SYSCON Register
; -------------------------------------
BSET P3.12 ; BHE mit 1 vorbesetzen
BSET DP3.12 ; BHE = Ausgang
BSET P3.13 ; WRITE mit 1 vorbesetzen
BSET DP3.13 ; WRITE = Ausgang
;; BSET DP3.15 ; P3.15 = 1 = Ausgang CLK
BFLDL SYSCON,#0001$1111b,#0010$1110b
; BTYP 00|| | | 00|| | | = xx
; MTTC 0| | | 1| | | = 1 (no Delay)
; RWDC 1 | | 0 | | = 0 (disabled)
; MCTC 1111 1110 = 1110 (1 WS)
BFLDH SYSCON,#0111$1011b,#0010$0000b
; STKSZ 11| |||| 01| |||| = 01 (128 Word)
; RDYEN 1 |||| 0 |||| = 0 (aus)
; SGTDIS 0||| 0||| = x
; BUSACT 0|| 0|| = x
; BYTDIS 1| 0| = 0 (enabled)
; CLKEN 1 0 = 0 (disabled)
; -------------------------------------
; BUSCON1 Register
; Initialisierung für EEPROM und I/O im Segment 3
; mit 3 Wait-States = 250 ns
; -------------------------------------
MOV ADDRSEL1,#000000$1100000$011b
; Beginn 11----- ||| Ab Adr. 3$xxxx
; Länge 011 64 kB
; Ab Adresse 3$0000h 64kB mit n Wait-States
MOV BUSCON1,SYSCON
BFLDL BUSCON1,#0011$1111b,#0010$1100b
; BTYP 00|| | | 00|| | | = xx
; MTTC1 1| | | 1| | | = 1 (no Delay)
; RWDC1 1 | | 0 | | = 0 (disabled)
; MCTC 1111 1100 = 1100 (3 WS)
BFLDH BUSCON1,#0001$0110b,#0000$0100b
;(STKSZ) 00| |||| 00| |||| = xx
; RDYEN1 1 |||| 0 |||| = 0 (disabled)
;(SGTDIS) 0||| 0||| = x
; BUSACT1 1|| 1|| = 1 (enabled)
; ALECTL1 1| 0| = 0 (disabled)
;(CLKEN) 0 0 = x
; -------------------------------------
; Port 3
; P3.0 = T0IN E 0 15a Eingang T0
; P3.1 = T6OUT A 1 15bc Ausgang T6
; P3.2 = CAPIN E 0 14a Eingang CAP
; P3.3 = T3OUT A 1 14bc Ausgang T3
; P3.4 = T3EUD E 0 13a Dip-Switch 1
; P3.5 = T4IN E 0 13bc Dip-Switch 2
; P3.6 = T3IN E 0 12a Dip-Switch 3
; P3.7 = T2IN E 0 12bc Dip-Switch 4
;*P3.8 = TXD1 A x Mon 2bc TxD Monitor
;*P3.9 = RXD1 E x Mon 3bc RxD Monitor
; P3.10= TXD0 A 1 5bc TxD Programm
; P3.11= RXD0 E 0 6bc RxD Programm
;*P3.12= BHE# A x Sys BHE# (ist bereits gesetzt)
;*P3.13= WR# A x Sys WR# (ist bereits gesetzt)
;*P3.14= READY# E ? Sys READY#
;*P3.15= CLK A ? Sys 10bc (20 MHz)
; -------------------------------------
OR P3, #0000$0100$0000$1010b ; Port 3 vorbesetzen
OR DP3,#0000$0100$0000$1010b ; 1 = Ausgang / 0 = Eingang
; -------------------------------------
; Port 2
; P2.0 = CC0 E 0 20a Eingang 1
; P2.1 = CC1 E 0 20bc Eingang 2
; P2.2 = CC2 E 0 19a Eingang 3
; P2.3 = CC3 E 0 19bc Eingang 4
; P2.4 = CC4 E 0 18a Eingang 5
; P2.5 = CC5 E 0 18bc Eingang 6
; P2.6 = CC6 E 0 17a Eingang 7
; P2.7 = CC7 E 0 17bc Eingang 8
; P2.8 = CC8 E 0 16a Eingang 9
; P2.9 = CC9 E 0 16bc Eingang 10
; P2.10= CC10 E 0 8bc SCLK (bidir)
; P2.11= CC11 E 0 (6a) CTS0
;*P2.12= CC12 E 0 Mon (3a) CTS1
; P2.13= BREQ# A 1 10a Ausgang
; P2.14= HLDA# A 1 11bc Ausgang
; P2.15= HOLD# A 1 11a Ausgang
; -------------------------------------
MOV P2, #1110$0000$0000$0000b ; Port 2 vorbesetzen
MOV DP2,#1110$0000$0000$0000b ; 1 = Ausgang / 0 = Eingang
; -------------------------------------
; Port 1
; P1.0 = A0 A 1 31a Ausgang 1
; P1.1 = A1 A 1 31bc Ausgang 2
; P1.2 = A2 A 1 30a Ausgang 3
; P1.3 = A3 A 1 30bc Ausgang 4
; P1.4 = A4 A 1 29a Ausgang 5
; P1.5 = A5 A 1 29bc Ausgang 6
; P1.6 = A6 A 1 28a Ausgang 7
; P1.7 = A7 A 1 28bc Ausgang 8
; P1.8 = A8 A 1 27a Ausgang 9
; P1.9 = A9 A 1 27bc Ausgang 10
; P1.10= A10 E 0 8bc SDAT (bidir.)
; P1.11= A11 A 1 (5bc) RTS0
;*P1.12= A12 A 1 Mon (2a) RTS1
; P1.13= A13 A 1 74HC123
; P1.14= A14 E 0 EEPROM Ready 1
; P1.15= A15 E 0 EEPROM Ready 2
; -------------------------------------
MOV P1, #0010$1011$1111$1111b ; Port 1 vorbesetzen
MOV DP1,#0010$1011$1111$1111b ; 1 = Ausgang / 0 = Eingang
; -------------------------------------
; SIO 0 initialisieren
; (SIO 1 wird vom Monitor-Programm benutzt)
; -------------------------------------
MOV S0BG,#0040h ; = 9615 Baud
MOV S0CON,#10000000$00010001b
; | ||001 Asynchron 8 Bit
; | |0 1 Stopbit
; | 1 Empfang ein
; 1 Baudrate-Generator ein
BSET S0TIR ; Sendepuffer leer
; .... Weitere Initialisierungen
JMP FAR ProgAnf ; Programm auf SEG X
P_INI ENDP
; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
P_COD PROC NEAR
| ; =============================================================
; Haupt-Programm
; =============================================================
| ProgAnf: EINIT ; RSTOUT# = 1 (ROM-Spiegelung aus)
CALL InitRam ; Init Variablen
CALL InitTrap ; Init Hardware-Traps
CALL InitIntVect ; Init Interrupt-Vektoren
CALL InitInt ; Init Interrupts
; .... weitere Initialisierungen
; -------------------------------------
; Interrupts starten
; -------------------------------------
BCLR T1IR ; Sio-Request rücksetzen
BSET T1IE ; Sio-Interrupt freigeben
BSET T1R ; Timer 1 starten
BCLR T3IR ; 1 ms-Request rücksetzen
BSET T3IE ; 1 ms-Interrupt freigeben
BSET T3R ; Timer 3 starten
NOP
BSET IEN ; Alle Interrupts zulassen
; RxD-Interrupt
MOV S0RIC,#00000000$00$0001$11b ; mit Priorität 1.3
BCLR S0RIR ; RxD-Request rücksetzen
BSET S0RIE ; RxD-Interrupt freigeben
| ; =============================================================
; Haupt-Programm Schleife
; =============================================================
| ProgLoop: MOV R1,PNT_RXD ; Byte empfangen ?
CMP R1,POS_RXD
JMP cc_Z,ProgLoop1 ; ... nein
MOVB RL0,[R1+#PUF_RXD] ; Byte laden
CMPI1 R1,#LenRxD-1 ; Offset + 1 = Ende ?
JMP cc_NZ,Ausw_RxD1 ; ... nein
MOV R1,#0 ; Wieder bei 0 beginnen
Ausw_RxD1: MOV PNT_RXD,R1 ; Neuen Offset speichern
; .... Byte auswerten
ProgLoop1:
; .... Zeitunkritische Anwender-Routinen
JMP ProgLoop ; Zum Schleifen-Anfang
| ; =============================================================
; Variablen initialisieren
; =============================================================
| InitRam: SCXT R1,#1 ; R1=1
MOV FLG_DIV,ZEROS
MOV ZLR_1,ZEROS ; Zähler setzen
MOV ZLR_10,R1
MOV ZLR_100,R1
MOV ZLR_1S,R1
MOV TIM_1,ZEROS ; Timer löschen
MOV TIM_10,ZEROS
MOV TIM_100,ZEROS
MOV TIM_1S,ZEROS
MOV PNT_RXD,ZEROS ; Zeiger löschen
MOV POS_RXD,ZEROS
MOV PNT_TXD,ZEROS
MOV POS_TXD,ZEROS
MOV ZLR_Inp,ZEROS ; Zähler löschen
MOV AUSGP1,ZEROS ; Alle Ausgänge aus
POP R1
RET
| ; =============================================================
; Word / Byte / Nibl als Hex-Zahl ausgeben
; Eingang: R0 Wert
; =============================================================
| SendWord: PUSH R0
MOVB RL0,RH0 ; High-Byte ausgeben
CALL SendByte
POP R0 ; Low-Byte ausgeben
| ; -----------------------------------------------
| SendByte: PUSH R0
SHR R0,#4 ; Bits 4...7
CALL SendNibl
POP R0 ; Bits 0...3
| ; -----------------------------------------------
| SendNibl: PUSH R0
ANDB RL0,#0Fh ; Bits 0...3 maskieren
ADDB RL0,#'0' ; + ASCII-0
CMPB RL0,#'9' ; 0...9 ?
JMP cc_ULE,SendNibl1 ; ... ja
ADDB RL0,#7 ; = A...F
SendNibl1: CALL SendChr
POP R0
RET
| ; =============================================================
; String an SIO ausgeben (Stringende = 0)
; Eingang: R2/R3 PP Stringadresse
; Ausgang: R2/R3 PP + Len String
; =============================================================
| SendStr: PUSH DPP0
PUSH R0
MOV DPP0,R3 ; DPP0 setzen
SendStr1: MOVB RL0,[R2+] ; Byte laden; String-Ende ?
JMP cc_Z,SendStrE ; ... ja
CALL SendChr ; Byte ausgeben
JMP SendStr1
SendStrE: POP R0
POP DPP0
RET
| ; =============================================================
; Byte ausgeben
; =============================================================
| SendChr: PUSH R1
MOV R1,PNT_TXD ; Pointer laden
MOVB [R1+#PUF_TXD],RL0 ; Byte ablegen
CMPI1 R1,#LenTxD-1 ; Puffer-Ende ?
JMP cc_NZ,SendChr9 ; ... nein
MOV R1,#0 ; Mit 0 beginnen
SendChr9: MOV PNT_TXD,R1 ; Pointer speichern
POP R1
RET
| ; =============================================================
; Return und Linefeed ausgeben
; =============================================================
| SendCrLf: PUSH R0
MOVB RL0,#Cr ; Return laden
CALL SendChr ; und ausgeben
MOVB RL0,#Lf ; LineFeed laden
JMP SendChrX ; und ausgeben
| ; =============================================================
; 1 Leerzeichen ausgeben
; =============================================================
| SendLz: PUSH R0
MOVB RL0,#Lz ; Leerzeichen laden
; - - - - - - - - - - - - - - - - - - - - - - - -
SendChrX: CALL SendChr ; und ausgeben
POP R0
RET
; *************************************************************
; TIMER-ROUTINEN
; *************************************************************
| ; =============================================================
; Timer 1 ms
; =============================================================
| Tim_1ms: SUB ZLR_1,ONES ; 1 ms-Zähler + 1
ADD ZLR_10,ONES ; 10 ms-Zähler - 1 abgelaufen ?
CALL cc_Z,Tim_10ms ; ... ja
MOV R2,#POF TblTim1 ; R2/R3 = Tabellen-Adresse
MOV R3,#PAG TblTim1
CALL DecTimer ; Timer testen / decrementieren
MOV R0,P2 ; Eingänge aktualisieren
AND R0,#000000$1111111111b
MOV EINGP1,R0
MOV R0,AUSGP1 ; Ausgänge aktualisieren
CPL R0 ; Ein = 0 / Aus = 1 (Reset-Zustand)
AND R0,#000000$1111111111b
MOV R1,P1 ; Port-Zustand laden
AND R1,#111111$0000000000b
OR R1,R0
MOV P1,R1 ; Ausgänge neu setzen
; .... Weitere Befehle
RET
| ; =============================================================
; Timer 10 ms
; =============================================================
| Tim_10ms: MOV R0,#10 ; 10 ms-Zähler neu laden
MOV ZLR_10,R0
ADD ZLR_100,ONES ; 100 ms-Zähler - 1 abgelaufen ?
CALL cc_Z,Tim_100ms ; ... ja
MOV R2,#POF TblTim10 ; R2/R3 = Tabellen-Adresse
MOV R3,#PAG TblTim10
CALL DecTimer ; Timer testen / decrementieren
; .... Weitere Befehle
RET
| ; =============================================================
; Timer 100 ms
; =============================================================
| Tim_100ms: MOV R0,#10 ; 100 ms-Zähler neu laden
MOV ZLR_100,R0
ADD ZLR_1S,ONES ; 1 Sek-Zähler - 1 abgelaufen ?
CALL cc_Z,Tim_1Sek ; ... ja
MOV R2,#POF TblTim100 ; R2/R3 = Tabellen-Adresse
MOV R3,#PAG TblTim100
CALL DecTimer ; Timer testen / decrementieren
; .... Weitere Befehle
; -------------------------------------
; Hardware-WatchDog rücksetzen
; -------------------------------------
MOV DPP1,#PAG A_IO
NOP ; Pipeline-Delay
MOV DPP1:POF WatchDog,R0
RET
| ; =============================================================
; Timer 1 Sek
; =============================================================
| Tim_1Sek: MOV R0,#10 ; 1 Sek-Zähler neu laden
MOV ZLR_1S,R0
MOV R2,#POF TblTim1Sek ; R2/R3 = Tabellen-Adresse
MOV R3,#PAG TblTim1Sek
CALL DecTimer ; Timer testen / decrementieren
; .... Weitere Befehle
RET
| ; =============================================================
; Timer-Variablen decrementieren und bei Erreichen
; von 0 evtl. Routine aufrufen
; Eingang: R2/R3 PP Tabellen-Adresse
; Tabelle: Routinen-Adr., DPP3:Timer-Adr.
; =============================================================
| DecTimer: MOV DPP0,R3 ; DPP0 setzen
NOP ; Pipeline-Delay
DecTimer1: MOV R4,[R2+] ; R4 = Routinen-Adresse
JMP cc_Z,DecTimerR ; ... Tabellen-Ende
MOV R1,[R2+] ; R1 = Timer-Adr
MOV R0,[R1] ; R0 = Timer-Wert = 0 ?
JMP cc_Z,DecTimer1 ; ... ja
SUB R0,#1 ; Timer-Wert - 1
MOV [R1],R0 ; und speichern; jetzt auf 0 ?
JMP cc_NZ,DecTimer1 ; ... nein
CMP R4,ONES ; Gültige Adresse ?
JMP cc_Z,DecTimer1 ; ... nein
PUSH R2
PUSH DPP0
CALL cc_UC,[R4] ; Routine aufrufen
POP DPP0
POP R2
JMP DecTimer1
DecTimerR: RET
P_COD ENDP
S_COD ENDS
| ; #############################################################
S_TXT SECTION DATA PUBLIC
| ; -----------------------------------------------
; Texte für User
; -----------------------------------------------
Text1 DB 'Dieses ist Text 1', 0
Text2 DB 'Dieses ist Text 2', 0
Text3 DB 'Dieses ist Text 3', 0
EVEN
S_TXT ENDS
| ; #############################################################
S_TBL SECTION DATA PUBLIC
| ; -----------------------------------------------
; Tabellen für Timer
; Ist eine Routinen-Adresse angegeben, wird Diese bei
; erreichen von 0 ausgeführt.
; -----------------------------------------------
TblTim1:
DW -1, SOF TIM_1
DW 0
TblTim10:
DW -1, SOF TIM_10
;;DW Routine, SOF TIM_xxx ; Beispiel
DW 0
TblTim100:
DW -1, SOF TIM_100
DW 0
TblTim1Sek:
DW -1, SOF TIM_1S
DW 0
S_TBL ENDS
; #############################################################
END
|
| Interrupt-Datei "BAS_INT.A66"
|
|
$INCLUDE (BAS_DEF.A66)
PUBLIC InitTrap, InitInt, InitIntVect
EXTERN SendStr :near, SendChr :near, SendCrLf :near
EXTERN SendNibl :near, SendWord :near
EXTERN Tim_1ms :near
; #############################################################
S_BIT SECTION DATA BITADDRESSABLE PUBLIC
; ---------------------------------------------------------------
; Externe Bits
; ---------------------------------------------------------------
EXTERN FLG_DIV :word
S_BIT ENDS
; #############################################################
S_VAR SECTION DATA PUBLIC
; ---------------------------------------------------------------
; Externe Variablen
; ---------------------------------------------------------------
EXTERN ZLR_Inp :word
EXTERN POS_RXD :word, PNT_RXD :word, PUF_RXD :byte
EXTERN POS_TXD :word, PNT_TXD :word, PUF_TXD :byte
S_VAR ENDS
; #############################################################
PAGE3 DGROUP SYSTEM, S_BIT, S_VAR
ASSUME DPP0:NOTHING
ASSUME DPP1:NOTHING
ASSUME DPP2:NOTHING
ASSUME DPP3:PAGE3
S_COD SECTION CODE PUBLIC
P_TRAP PROC NEAR
| ; =============================================================
; Interrupt-Vektoren 10h bis 29h initialisieren
; =============================================================
| InitIntVect: MOV R0,#10h ; 1. Vektor (CC0INT)
MOV R1,#SOF Int_Fehl ; Adr Fehler-Interrupt
MOV R2,#SEG Int_Fehl
InitIntVect1: CALL SetIntVect
CMPI1 R0,#29h ; Alles initialisiert ?
JMP cc_NZ,InitIntVect1 ; ... nein
RET
| ; =============================================================
; Interrupt-Vektor setzen
; Eingang: R0 Vektor-Nr. (0...7Fh)
; R1 SOF Adresse Int-Routine
; R2 SEG Adresse Int-Routine
; Ausgang: R0 Nächste Vektor-Adresse
; =============================================================
| SetIntVect: PUSH R0
PUSH R2
SCXT DPP0,#0 ; DPP0 auf Page 0 setzen
SHL R0,#2 ; Vektor-Nummer * 4
MOVB RH2,RL2 ; SEG-Adr. Bit 7..0 => 15..8
MOVB RL2,#0FAh ; Befehl "JMPS SegNr,..."
MOV [R0],R2 ; Befehl eintragen
ADD R0,#2
MOV [R0],R1 ; Int-Adresse eintragen
POP DPP0
POP R2
POP R0
RET
| ; =============================================================
; Service-Adressen für Interrupts setzen
; =============================================================
| IR_Inp1 EQU CC0IR
IE_Inp1 EQU CC0IE
VN_Inp1 EQU 10h
IR_Inp2 EQU CC1IR
IE_Inp2 EQU CC1IE
VN_Inp2 EQU 11h
InitInt: PUSH R8
SCXT DPP0,#PAG TblInitInt
MOV R8,#POF TblInitInt
InitInt1: MOV R0,[R8+] ; R0=Vektor-Nummer
JMP cc_Z,InitInt2 ; ... Tabellen-Ende
MOV R1,[R8+] ; R1=SOF Adress
MOV R2,[R8+] ; R2=SEG Adress
CALL SetIntVect ; Vektor setzen
JMP InitInt1
InitInt2:
; -------------------------------------
; CC0 für Interrupt Eingang 1 mit steigender Flanke
; CC1 für Interrupt Eingang 2 mit fallender Flanke
; -------------------------------------
; 3 2 1 0 ; Capture bei:
MOV CCM0, #0000$0000$0010$0001b ; 0001 = steigende Flanke
; 7 6 5 4 ; 0010 = fallende Flanke
MOV CCM1, #0000$0000$0000$0000b ; 0011 = beide Flanken
;11 10 9 8 ; 0100 = COMPARE-Mode 0
MOV CCM2, #0000$0000$0000$0000b
;15 14 13 12
MOV CCM3, #0000$0000$0000$0000b
MOV CC0IC,#00000000$01$1100$11b ; mit Priorität 12.3
MOV CC1IC,#00000000$01$1101$11b ; mit Priorität 13.3
; 01 ; enabled
; -------------------------------------
; Timer T1 für SIO initialisieren
; T1 = 40 MHz : 64 : 580 = 1077 Hz = 0,93 ms
; -------------------------------------
; T1 T0
MOV T01CON,#00000$010$00000$000b
; | | 000 = T0 Teiler 16
; 010 = T1 Teiler 64
MOV T1,#-580
MOV T1REL,#-580 ; = SIO Reload-Wert
MOV T1IC, #00000000$00$1001$11b ; mit Priorität 9.3
; -------------------------------------
; Timer T3 für 1 ms-Interrupt
; T3 = 40 MHz : 64 : 625 = 1000 Hz = 1 ms
; -------------------------------------
MOV T3CON,#00000$010100$00$010b
; ||| || 010 = Teiler 64
; ||| 00 = Timer-Funktion
; |01 = T3UD Abwärts zählen
; 1 = T3OE Toggle an P3.3
MOV T3,#625 ; = 1 ms
MOV T3IC, #00000000$00$1000$11b ; mit Priorität 8.3
; -------------------------------------
; Timer T4 als Reload-Register für T3
; -------------------------------------
MOV T4CON,#00000000$00$100$111b
; || | | 111 = Reload bei Toggle T3OTL
; || 100 = Reload-Funktion
; 00 = Timer deaktiviert
MOV T4,#625 ; 1 ms Reload-Wert
POP DPP0
POP R8
RET
| ; =============================================================
; Initialisierung Hardware-Traps
; =============================================================
| InitTrap: PUSH R0
PUSH R1
PUSH R2
; -------------------------------------
; Stack-Overflow-Trap
; -------------------------------------
MOV R0,#04h ; STKOF
MOV R1,#SOF IntSTKO
MOV R2,#SEG IntSTKO
CALL SetIntVect
; -------------------------------------
; Stack-Underflow-Trap
; -------------------------------------
MOV R0,#06h ; STKUF
MOV R1,#SOF IntSTKU
MOV R2,#SEG IntSTKU
CALL SetIntVect
; -------------------------------------
; Traps Klasse B
; -------------------------------------
MOV R0,#0Ah ; Trap Klasse B
MOV R1,#SOF IntTRAPB
MOV R2,#SEG IntTRAPB
CALL SetIntVect
POP R2
POP R1
POP R0
RET
| ; TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
; TRAPS
; TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
| IntSTKO: MOV SP,#SPAdr ; STACK-POINTER
BCLR STKOF
SCXT R2,#POF TxtSTKO ; Stack Überlauf
SCXT R3,#PAG TxtSTKO
JMP IntTRAPx
IntSTKU: MOV SP,#SPAdr ; STACK-POINTER
BCLR STKUF
SCXT R2,#POF TxtSTKU ; Stack Unterlauf
SCXT R3,#PAG TxtSTKU
JMP IntTRAPx
IntTRAPB: MOV DPP3:POF TrapAdr,R0 ; Save R0
POP R0 ; Get InstructionPointer
MOV DPP3:POF TrapAdr+0Eh,R0
POP R0 ; Get CodeSegmentPointer
MOV DPP3:POF TrapAdr+0Ch,R0
POP R0 ; Get ProgramStatusWord
MOV DPP3:POF TrapAdr+0Ah,R0
MOV R0,DPP3:POF TrapAdr ; Restore R0
PUSH R2
PUSH R3
JBC UNDOPC,IntTRAP7
JBC PRTFLT,IntTRAP3
JBC ILLOPA,IntTRAP2
JBC ILLINA,IntTRAP1
JBC ILLBUS,IntTRAP0
JMP IntTRAPx
IntTRAP7: MOV R2,#POF TxtUO ; Undefinierter Opcode
MOV R3,#PAG TxtUO
JMP IntTRAPx
IntTRAP3: MOV R2,#POF TxtGB ; Geschützter Befehl
MOV R3,#PAG TxtGB
JMP IntTRAPx
IntTRAP2: MOV R2,#POF TxtFWZ ; Falscher Wort-Zufgriff
MOV R3,#PAG TxtFWZ
JMP IntTRAPx
IntTRAP1: MOV R2,#POF TxtFBZ ; Falscher Befehls-Zugriff
MOV R3,#PAG TxtFBZ
JMP IntTRAPx
IntTRAP0: MOV R2,#POF TxtVBZ ; Verbotener Bus-Zugriff
MOV R3,#PAG TxtVBZ
; - - - - - - - - - - - - - - - - - - - - - - - -
IntTRAPx: PUSH R0
BCLR T3R ; Timer 3 stoppen
BCLR T3IE ; 1 ms-Interrupt sperren
MOV PSW,#0
BSET IEN ; Alle Interrupts freigeben
CALL SendStr
MOVB RL0,#' '
CALL SendChr
MOVB RL0,#'('
CALL SendChr
MOV R0,DPP3:POF TrapAdr+0Ch ; CSP anzeigen
CALL SendNibl
MOV R0,DPP3:POF TrapAdr+0Eh ; IP anzeigen
CALL SendWord
MOVB RL0,#'h'
CALL SendChr
MOVB RL0,#')'
CALL SendChr
CALL SendCrLf ; Return / LinFeed senden
POP R0
POP R3
POP R2
IntTRAPx1: JMP IntTRAPx1
P_TRAP ENDP
| ; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
; INTERRUPT-SERVICE-ROUTINEN
; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
| Int_Fehl PROC INTERRUPT = 7Fh
RET
Int_Fehl ENDP
| ; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
; 1 ms-Interrupt
; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
| Int_1ms PROC INTERRUPT = VN_1ms USING REG_1ms
SCXT CP,#REG_1ms ; Register-Bank 1ms
SCXT MDC,#0 ; Mul/Div-Register retten
NOP ; Pipeline-Delay !!!
PUSH MDH
PUSH MDL
MOV R0,FLG_DIV ; Diverse Flags
PUSH R0 ; retten
PUSH DPP0 ; DPP0 retten
PUSH DPP1 ; DPP1 retten
SCXT DPP2,#PAG A_IO ; DPP2 retten und setzen
CALL Tim_1ms ; Unterroutine aufrufen
POP DPP2 ; DPP2 zurück
POP DPP1 ; DPP1 zurück
POP DPP0 ; DPP0 zurück
POP R0 ; Diverse Flags
MOV FLG_DIV,R0 ; zurück
POP MDL ; Mul/Div-Register zurück
POP MDH
POP MDC
POP CP ; Register-Bank zurück
RET
Int_1ms ENDP
| ; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
; Bei steigender Flanke an Eingang 1 Zähler + 1
; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
| Int_Inp1 PROC INTERRUPT = VN_Inp1
SUB ZLR_Inp,ONES ; Zähler + 1
Int_Inp1 ENDP
| ; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
; Bei fallender Flanke an Eingang 2 Zähler - 1
; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
| Int_Inp2 PROC INTERRUPT = VN_Inp2
ADD ZLR_Inp,ONES ; Zähler - 1
Int_Inp2 ENDP
| ; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
; Serielles Senden
; Werte aus einem Ringpuffer auslesen.
; Eingang: POS_TXD = Offset für Ringpuffer
; Ausgang: POS_TXD + 1
; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
| Int_Sio PROC INTERRUPT = VN_Sio ; T1
PUSH R0
PUSH R1
MOV R1,POS_TXD
CMP R1,PNT_TXD ; Pointer verändert ?
JMP cc_Z,Int_Sio9 ; ... nein
JNB S0TIR,Int_Sio9 ; ... nicht bereit zum Senden
MOVB RL0,[R1+#PUF_TXD] ; Byte laden
MOVB S0TBUF,RL0 ; und senden
BCLR S0TIR
CMPI1 R1,#LenTxD-1 ; Puffer-Ende erreicht ?
JMP cc_NZ,Int_Sio5 ; ... nein
MOV R1,#0 ; Wieder bei 0 beginnen
Int_Sio5: MOV POS_TXD,R1 ; Neuen Offset speichern
Int_Sio9: POP R1
POP R0
RET
Int_Sio ENDP
| ; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
; Serieller Empfang
; Werte werden in einem Ringpuffer abgelegt.
; Eingang: POS_RXD = Offset für Ringpuffer
; Ausgang: POS_RXD + 1
; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
| Int_RxD PROC INTERRUPT = VN_RxD
PUSH R0
MOVB RL0,S0RBUF ; Byte laden
BCLR S0RIR ; Interrupt-Request löschen
ORB RL0,RL0 ; Byte = 0 ?
JMP cc_Z,Int_RxDE ; ... ja: nicht speichern
CMPB RL0,ONES ; Byte = 0FFh ?
JMP cc_Z,Int_RxDE ; ... ja: nicht speichern
PUSH R1
MOV R1,POS_RXD ; R1 = Puffer-Offset
MOVB [R1+#PUF_RXD],RL0 ; Byte speichern
CMPI1 R1,#LenRxD-1 ; Offset + 1 = Ende ?
JMP cc_NZ,Int_RxD1 ; ... nein
MOV R1,#0 ; Wieder bei 0 beginnen
Int_RxD1: MOV POS_RXD,R1 ; Neuen Offset speichern
POP R1
Int_RxDE: POP R0
RET
Int_RxD ENDP
; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
; Serielles Senden (Wird von Int_Sio übernommen)
; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Int_TxD PROC INTERRUPT = VN_TxD
RET
Int_TxD ENDP
S_COD ENDS
| ; #############################################################
S_TXT SECTION DATA PUBLIC
| ; -----------------------------------------------
; Texte für System-Fehler
; -----------------------------------------------
TxtSTKO DB 'Stack-Ueberlauf', 0
TxtSTKU DB 'Stack-Unterlauf', 0
TxtUO DB 'Undefinierter Opcode', 0
TxtGB DB 'Geschuetzter Befehl', 0
TxtFWZ DB 'Falscher Wort-Zugriff', 0
TxtFBZ DB 'Falscher Befehls-Zugriff', 0
TxtVBZ DB 'Verbotener Bus-Zugriff', 0
EVEN
S_TXT ENDS
| ; #############################################################
S_TBL SECTION DATA PUBLIC
| ; -----------------------------------------------
; Tabelle für Interrupt-Vektoren
; -----------------------------------------------
TblInitInt:
DW VN_Sio, SOF Int_Sio, SEG Int_Sio
DW VN_TxD, SOF Int_TxD, SEG Int_TxD
DW VN_RxD, SOF Int_RxD, SEG Int_RxD
DW VN_1ms, SOF Int_1ms, SEG Int_1ms
DW VN_Inp1, SOF Int_Inp1, SEG Int_Inp1
DW VN_Inp2, SOF Int_Inp2, SEG Int_Inp2
DW 0
S_TBL ENDS
; #############################################################
END
|
basis.obj, bas_int.obj, bas_var.obj TO basis.abs
SECTIONS ( S_COD (0x01000),
& S_TXT (0x02000),
& S_TBL (0x03000),
& S_VAR (0x0C000) )
IXREF
|
|