; REM Ins{nd av Anders Franz`n <5258>    1985-08-22 22.53.32
; NYA KOMMANDON P] ABC80
; ----------------------
;
; Detta {r ett assemblerprogram som l{nkar in n}gra nya kommandon p}
; ABC80. Det {r avsett f|r dem som vill skapa egna kommandon eller helt
; enkelt tycker att det vore roligt att veta hur man g|r. Programmet
; placeras p} h|ga adresser i minnet s} det passar b}de f|r 16K och 32K.
; Dessutom spelar det ingen roll vilken checksumma datorn har, det
; k{nner programmet sj{lv av. Programmet g}r {ven att k|ra om man bara
; har kassettspelare eller om man dessutom har flexskiveenhet. Rutinen
; startas mha CALL(61440) fr}n BASIC, dvs anrop av START.
;
;
;
; Om man anropar en subrutin i assembler m}ste datorn veta vart den
; ska ta v{gen n{r subrutinen {r utf|rd. D} instruktionen CALL exekveras
; placerar Z80 adressen till instruktionen efter CALL'et p} stacken.
; D} en subrutin {r klar g|rs retur till adressen p} stacken.
;
; Det kan liknas vid en irrf{rd i en labyrint. Vid varje v{gsk{l skriver
; vi upp v}rt v{gval, antingen v{nster eller h|ger, p} en lista. Med tiden
; v{xer listan ned}t och vi blir tr|tta och vill g} hem. Hur vet vi hur
; vi ska g}? Jo, vi l{ser bara listan underifr}n och med ledning av detta
; vet vi hur vi ska sv{nga. Antag att vi l{gger oss ner och sover d}
; vi kommit halvv{gs hem. Antag vidare att n}gon kommer och {ndrar i
; listan, byter ut ett h|ger mot ett v{nster! Detta medf|r naturligtvis
; att vi g}r vilse n{r vi vaknar. Genom att {ndra p} listan kan man f}
; oss att g} en annan v{g.
;
; Ett s{tt att l{nka in nya kommandon i ABC80 {r att anv{nda interupt.
; N{r datorn ligger i sina loopar i ROM och v{ntar p} kommandon kan vi
; f} processorn att hoppa till en egen rutin d} en rad {r inmatad genom
; att l}ta en ny interuptrutin {ndra returadresserna p} stacken. Vi
; {ndrar den adress som medf|r retur tillbaka till komandotolkningen
; i ROM s} att den ist{llet pekar p} en egen rutin. Denna rutin kan
; sedan tolka v}ra kommandon p} ett godtyckligt s{tt.
;
; F|r att f|rst} det hela m}ste vi veta hur BASIC-tolken jobbar.
; Den anropar till att b|rja med en rutin som l{ser in en rad fr}n
; tangentbordet. Denna subrutin anropar i sin tur en snutt som v{ntar
; p} att en tangent ska tryckas ned. Snutten ligger och loopar {nda
; tills en flagga s{tts. Flaggan s{tts av en interuptrutin s} fort en
; tangent trycks ned. Det betyder att f|ljande 16-bitars tal kan ligga
; p} stacken d} interuptrutinen arbetar:
;
;                      240   Returadress d} "l{s en rad" exekverats.
;                       IX   Register som "l{s en rad" sparar p} stacken.
;                      700   Returadress d} "v{nta p} tangenttryck" {r utf|rt.
;                    ok{nd   Returadress d} interupt {r f{rdigbehandlat.
;                       AF   Register AF som vi sparar i interuptrutinen.
;                       HL   Register HL som vi sparar i interuptrutinen.
;  hit pekar SP --->    DE   Register DE som vi sparar i interuptrutinen.
;  (stackpekaren)
;
; Naturligtvis kommer andra v{rden att ligga p} stacken om vi t ex
; just nu k|r ett BASIC-program. Allra f|rst i interuptrutinen
; k{nner vi d{rf|r av om datorn jobbar med BASIC-program eller om
; den v{ntar p} kommando. Dessutom kontrollerar vi att den f|rsta
; returadressen {r 240. Om ett program k|rs just nu eller adressen
; {r felaktig forts{tter vi i BASIC-tolkens interuptrutin.
;
; N{r man anv{nder interuptrutiner programmeras ett chips i datorn
; som kallas PIO. Det m}ste veta n{r och hur det ska agera. En vektor
; {r en adress som pekar ut tv} bytes i minnet. Dessa bytes inneh}ller
; adressen till interuptrutinen. Vi skickar den l}ga byten av vektorn
; till PIO och den h|ga byten till CPU'ns I-register. BASIC-tolken
; har redan programmerat PIO'n med v{rdet 52. Detta v{rde utnyttjas
; {ven av kassettrutinerna s} det l}ter vi vara of|r{ndrat. Det enda
; vi beh|ver g|ra {r allts} att l}ta I-registret f} den h|ga byten av
; vektorn.
;
;
         ORG  61440          ; Placera programmet p} l{mplig plats.
;
START    LD   HL,START       ; Adress till programmets b|rjan.
         LD   (65063),HL     ; S{nk v{rdet p} stackpekaren, vi
                             ; reserverar h{rigenom arean som
                             ; detta program ligger i.
         LD   HL,VEKTOR      ; Adress till nya interuptvektorer.
         LD   A,H            ; H|ga byten i adressen
         LD   I,A            ; till CPU'ns I-register.
         LD   HL,TEXT1       ; Adress till text att skriva.
         LD   BC,TEXT2-TEXT1 ; L{ngd p} texten att skriva.
         CALL 11             ; Skriv en liten inledningstext genom att
                             ; anropa en subrutin i ROM.
         JP   198            ; Hoppa till ROM och v{nta p} kommando.
;
;
         ORG  61440+52       ; Observera att l}ga byten {r 52.
;
VEKTOR   DEFW INTERUPT       ; Adress till interuptrutin f|r tangentbordet.
         DEFW 5:148          ; Adress till interuptrutin f|r kassettl{sning.
;
TEXT1    DEFB 13,10
         DEFM "MINIHJ[LPARE   ABC-klubben 1985-08-21"
         DEFB 13,10,13
TEXT2    EQU  $
;
;
; H{r kommer nu den nya interuptrutinen som exekveras varje g}ng
; en tangent trycks ned p} tangentbordet.
;
INTERUPT PUSH AF             ; Spara A-registret p} stacken.
         LD   A,(IY+14)      ; [r datorn i RUN-mode,
         AND  A              ; dvs exekveras ett BASIC-program just nu?
         JP   Z,799          ; Ja, forts{tt is}fall i ROM.
;
; Datorn ligger just nu, n{r interuptet intr{ffat, i en slinga som l{ser
; in en rad fr}n tangentbordet. D{r v{ntar den p} interupt, dvs tangent-
; tryck, {nda tills dess hela raden {r inmatad och RETURN tryckts ned.
;
         PUSH HL             ; Spara register.
         PUSH DE
         INP  56             ; L{s av tangentbordsporten.
         AND  127            ; Sl{ck paritetsbiten (bit 7).
         CP   12             ; CTRL-L?
         JR   Z,INT1         ; Ja, hoppa och t|m bildsk{rmen.
         CP   9              ; H|gerpil?
         JR   NZ,INT2        ; Nej, hoppa.
;
; H{r f|ljer en specialfiness. Om datorn v{ntar p} att vi ska knappa in
; f|rsta tecknet i en rad och finner att vi trycker p} h|gerpil, visas
; den senast inmatade raden igen som nu kan editeras. Mycket praktiskt
; d} man skrivit in en l}ng rad men som visar sig vara felaktig. ABC80
; f}r s}lunda en finess som finns p} ABC800!
;
         LD   A,B            ; [r detta det f|rsta tecknet som datorn
         CP   C              ; f}r in till raden?
         JR   NZ,INT2        ; Nej, hoppa.
;
; Om ABC80 ligger och v{ntar p} att vi ska skriva in ett kommando
; har register BC f|ljande v{rde d} interuptrutinen anropas:
;   C  Max antal tecken kvar att mata in p} raden.
;   B  Max antal tecken totalt i rad att mata in (=120).
; Om inget tecken {r inmatat till raden {r C=B. Tack vare detta kan
; vi enkelt kolla om ett tecken {r det f|rsta p} raden.
;
         LD   HL,(253:251)   ; ED-kommandot sparar h{r adress till rad
                             ; som ska editeras, tag denna adress.
         LD   A,(HL)         ; Tag f|rsta tecknet i rad att editera.
         CP   13             ; [r raden tom, dvs {r f|rsta tecknet RETURN?
         JR   NZ,INT2        ; Nej, editering p}g}r. Hoppa!
         LD   HL,BUFFERT     ; Adressen till specialbuffer.
         CP   (HL)           ; [r bufferten tom?
         JR   Z,INT2         ; Ja, hoppa.
         LD   (253:251),HL   ; Texten i specialbufferten kommer att editeras.
         PUSH BC             ; Spara register som anv{nds av "mata in rad".
         PUSH HL             ; Tag tecken i specialbufferten.
         LD   A,13           ; ASCII-kod f|r RETURN.
         LD   BC,120         ; Specialbufferten {r 120 tecken l}ng.
         CPIR                ; Leta slutet p} raden, hittar alltid CR.
         LD   (HL),10        ; L{gg ner "Line Feed" sist i raden.
         LD   A,121
         SUB  C              ; Ber{kna l{ngden p} texten i specialbufferten.
         LD   C,A
         POP  HL             ; Adress till specialbufferten.
         CALL 11             ; Skriv ut texten att editera p} sk{rmen.
         EX   DE,HL          ; HL=adress i bildminnet f|rst p} n{sta rad.
         SET  7,(HL)         ; T{nd mark|ren!!!
         POP  BC             ; ]terst{ll registret som "mata in rad" anv{nder.
         POP  DE             ; ]terst{ll DE-registret.
         POP  AF             ; ]terst{ll inte HL, HL pekar p} aktuell adress
                             ; i bildminnet s} att mark|ren sl{cks d} n{sta
                             ; tangent tryckts ned.
         POP  AF             ; ]terst{ll A-registret.
         EI                  ; Till}t interupt igen.
         RETI                ; Retur fr}n interuptet.
;
; Jaha, h{r slutar specialfinessen med h|gerpil. Nu f|ljer en rutin
; som t|mmer bildsk{rmen om CTRL-L tryckts ned. Detta sker endast
; om mark|ren st}r i kolumn noll, dvs vi har ej b|rjat skriva in
; n}gon rad. Det vore ju pinsamt om sk{rmen rensades d} vi hunnit
; halvv{gs i en programrad!
;
INT1     LD   A,B            ; Har vi skrivit in n}gra andra tecken p}
         CP   C              ; raden?
         PUSH IX             ; Spara register.
         CALL Z,630          ; Nej, t|m bildsk{rmen, rutinen finns i ROM.
         POP  IX             ; ]terst{ll register.
;
; Nu ska vi kontrollera vad returadressen p} stacken har f|r v{rde.
; Vi vet precis var den ska ligga i f|rh}llande till stackpekaren SP,
; n{mligen 6 heltal upp vilket {r detsamma som tolv bytes.
;
INT2     LD   HL,12          ; Nu ska vi kolla om den f|rsta returadressen
         ADD  HL,SP          ; {r okey. L}t HL peka p} r{tt st{lle i stacken.
         LD   DE,240         ; Den h{r adressen b|r ligga d{r.
         CALL TEST           ; Kolla om adressen {r riktig.
         LD   DE,CMD         ; Ny returadress till v}r kommandoavtolkning.
         JR   Z,INT4         ; Hoppa om adressen var riktig.
;
; Om vi anv{nt oss av ED-kommandot men vill skriva in ett nytt kommando
; utan att editera {r returadressen en annan. Kolla om ED anv{nts och
; byt is}fall ut returadressen mot en som medf|r hopp till en ny ED-snutt.
;
         LD   DE,10:217      ; Om ED anv{nts b|r denna adress ha anv{nts.
         LD   A,(DE)         ; B{st att kolla vad som finns i ROM h{r,
         CP   33             ; denna adress {r lite olika beroende p}
         JR   Z,INT3         ; datorns checksumma. Hoppa om checksumma 9913.
                             ; Notera att checksumman 10042 {r identisk med
                             ; 9913 fr}nsett en byte men den {r ointressant
                             ; i detta fall.
         LD   DE,10:215      ; Denna adress anv{nds om checksumman {r 11273.
INT3     CALL TEST           ; Kontrollera om returadressen {r fr}n ED.
         JR   NZ,INT5        ; Nej, hoppa. Tolken var n}gon annanstans
                             ; eller s} har vi redan {ndrat den!
         LD   DE,ED          ; Adress till v}r egen ED-rutin.
INT4     LD   (HL),E         ; L{gg ner den nya returadressen i stacken.
         INC  HL             ; (H{r sker allts} det som hela detta program
         LD   (HL),D         ; bygger p}, att lura tolken!)
INT5     POP  DE             ; ]terst{ll n}gra register.
         POP  HL
         JP   3:31           ; Forts{tt i ROM. D{r l{ses vilken tangent
                             ; som tryckts ned av, och tangentflaggan s{tts.
;
TEST     LD   A,(HL)         ; Tag l}g byte i adressen p} stacken.
         CP   E              ; J{mf|r med vad det b|r vara.
         RET  NZ             ; Retur om olika med Z-flaggan satt.
         INC  HL
         LD   A,(HL)         ; Tag h|g byte i adressen p} stacken.
         DEC  HL             ; ]terst{ll HL.
         CP   D              ; Kolla om ocks} h|ga byten {r lika.
         RET                 ; Om olika {r Z-flaggan satt.
;
; Det var allt som har med interupt att g|ra. Det som har utr{ttats
; just nu {r allts} att en returadress p} stacken har f|r{ndrats. N{r
; vi har matat en rad p} tangentbordet avslutad med CR kommer retur
; att ske till kommandoavtolkningsrutinerna nedan som tolkar raden.
;
; H{r kommer rutinen som utf|rs d} vi editerat klart en rad. Den
; }terst{ller stacken som ED anv{nt sig av. Om vi allts} skriver
; "ED 10" och return f}r vi upp rad 10 klar att editeras. Nu skriver
; vi ett kommando ist{llet f|r att editera raden varvid vi hamnar
; i denna rutin.
;
ED       LD   HL,0:128       ; ED-kommandot har reserverat 128 bytes p}
         ADD  HL,SP          ; stacken.
         POP  DE             ; Adress till radbufferten.
         LD   SP,HL          ; ]terst{ll stacken i skick som innan ED.
         EX   DE,HL          ; HL pekar p} radbufferten.
         JR   CMD2           ; Forts{tt i nya kommandoavtolkningen.
;
;
; H{r b|rjar kommandoavtolkningen. Raden som vi knappat in ligger nu i
; en radbuffert n}gonstans i RAM. Innan BASIC-tolken anropar rutinen
; "l{s in rad" sparar den adressen till radbufferten p} stacken. Om
; vi g|r POP HL kommer adressen d{rf|r att hamna i HL. Om den inmatade
; raden {r tom hoppar vi till ROM f|r att h{mta en ny.
;
CMD      CALL 3:62           ; ]terst{ll CTRL-C-flaggan.
         POP  HL             ; HL pekar p} radbufferten.
CMD2     PUSH HL             ; Spara adressen.
         RST  32             ; Skippa eventuella mellanslag, A=f|rsta tecknet.
         EX   (SP),HL        ; HL pekar p} radbuffert, spara adress till tkn.
         CP   13             ; [r den inmatade raden tom?
         JP   Z,219          ; Ja, hoppa till ROM och h{mta en ny.
;
; Nu sparar vi raden i v}r specialbuffert.  Det g|r vi f|r att kunna ta
; fram den igen f|r editering d} vi trycker p} h|gerpil. En tom rad
; t|mmer allts} inte specialbufferten!
;
         LD   DE,BUFFERT     ; Adress till v}r specialbuffert.
         LD   BC,120         ; Raden {r 120 tecken l}ng.
         LDIR                ; Spara inmatad rad i specialbuffert.
;
; Det finns en rutin i ROM som letar efter ord i en tabell. Tabellen
; ska se ut s} h{r:
;
;    128,ORD1,129,ORD2,...  ..255
;
; Orden }tskiljs med en byte d{r bit 7 {r satt. Tabellens slut markeras
; med en byte 255. Om ordet }terfinns placeras v{rdet p} byten f|re ordet
; i A-registret. Om ORD1 hittats f}r A s}lunda v{rdet 128. Med hj{lp av
; detta v{rde kan en annan rutin leta fram en adress i en tabell och
; hoppa till den adressen.
;
         POP  HL             ; Adress till bufferten.
         LD   DE,CMDTAB      ; Adress till v}r egen kommandotabell.
         CALL 68             ; Leta inmatat kommando i tabellen.
         JP   NZ,249         ; Hoppa om kommandot ej finns i tabellen,
                             ; i ROM kollas d} om det {r ett annat kommando.
         LD   BC,204         ; Adress att g|ra retur till efter kommadot.
         PUSH BC             ; L{gg returadressen p} stacken.
         LD   DE,JPTAB       ; Tabell med adresser till v}ra kommandon.
         JP   314            ; I ROM finns en rutin som hoppar till den
                             ; adress som motsvarar det kommando som
                             ; hittats i kommandotabellen.
;
CMDTAB   DEFB 128            ; H{r {r tabellen med v}ra nya kommandon.
         DEFM "EXIT"         ; Maximalt f}r 127 kommandon plats i tabellen.
         DEFB 129
         DEFM "^"            ; Observera att det {r samma "kod" f|r
         DEFB 129            ; gement och versalt "^", de har ju samma
         DEFM "~"            ; funktion.
         DEFB 130
         DEFM "RAM"
         DEFM 255            ; Slut p} tabellen.

JPTAB    DEFW 0              ; EXIT medf|r hopp till adress noll, dvs RESET.
         DEFW LIST           ; Adress till listrutinen.
         DEFW RAM            ; Adress till RAM-kommandot.
;
;
; LIST-rutinen g|r att vi bara beh|ver skriva "^" f|r att lista programmet.
; B}de gement och versalt "^" ligger i kommandotabellen d{rf|r att
; BASIC-tolken inte kan skilja p} dessa. Endast 15 programrader visas
; p} sk{rmen innan tolken v{ntar p} tangenttryck. Detta medf|r att
; de f|rsta programraderna aldrig f|rsvinner i bildsk{rmens |vre {nde.
;
LIST     LD   IX,-16         ; Reservera 16 bytes p} stacken, det {r
         ADD  IX,SP          ; precis vad som sker i ROM-LIST-rutinen.
         LD   SP,IX
         LD   (IX+0),15      ; Scrolla ej s} att |versta raderna f|rsvinner.
         LD   A,(2811)       ; Kontrollera datorns checksumma.
         CP   221
         JP   Z,2811         ; Hoppa om checksumma 11273.
         JP   2809           ; Hoppa om checksumma 9913.
;
;
; RAM {r ett kommando som skriver ut hur stort BASIC-programmet som
; finns i minnet {r, hur stor plats variablerna tar samt hur mycket
; ledigt utrymme som finns kvar.
;
RAM      LD   HL,RAM1        ; Adress till text att skriva.
         LD   BC,RAM2-RAM1   ; L{ngd p} text att skriva.
         CALL 11             ; Skriv text p} bildsk{rmen.
         LD   HL,(65054)     ; V{rde p} EOFA, adress till programmets slut.
         LD   DE,(65052)     ; V{rde p} BOFA, adress till programmet.
         CALL SKRIVDIF       ; Skriv ut programmets storlek.
         LD   HL,RAM2
         LD   BC,RAM3-RAM2
         CALL 11             ; Skriv text p} sk{rmen.
         LD   HL,(65056)     ; V{rde p} HEAP, h{r tar variablerna slut.
         LD   DE,(65054)     ; V{rde p} EOFA, adress till programmets slut.
         INC  DE             ; Pekar p} variabelutrymmet.
         CALL SKRIVDIF       ; Skriv ut variablernas minnesutrymme.
         LD   HL,RAM3
         LD   BC,RAM4-RAM3
         CALL 11             ; Skriv text.
         LD   HL,(65063)     ; V{rde p} STACK, h{r slutar anv{ndbart RAM-minne.
         LD   DE,(65056)     ; V{rde p} HEAP, h{r tar variablerna slut.
         CALL SKRIVDIF       ; Skriv ut hur mycket ledigt minne som finns.
         LD   HL,RAM4
         LD   BC,RAM5-RAM4
         CALL 11             ; Skriv text.
         RET
;
RAM1     DEFB 13,10                  ; H{r ligger textrader som g|r
         DEFM "MINNE     BYTES"      ; att detta visas p} sk{rmen om
         DEFB 13,10                  ; vi skriver in kommandot RAM:
         DEFM "==============="      ;
         DEFB 13,10                  ; MINNE     BYTES
         DEFM "PROGRAM   "           ; ===============
RAM2     DEFB 13,10                  ; PROGRAM   0
         DEFM "VARIABLER "           ; VARIABLER 0
RAM3     DEFB 13,10                  ; LEDIGT    16000
         DEFM "LEDIGT    "           ; ===============
RAM4     DEFB 13,10                  ;
         DEFM "==============="
         DEFB 13,10
RAM5     EQU  $
;
; SKRIVDIF {r en subrutin som skriver ut skillnaden mellan talet
; HL och talet DE p} bildsk{rmen.
;
SKRIVDIF AND  A
         SBC  HL,DE
         EX   DE,HL          ; DE {r nu talet att skriva.
         LD   HL,-10         ; Reservera tio bytes p} stacken.
         ADD  HL,SP
         LD   SP,HL
         EX   DE,HL          ; HL {r talet igen.
         LD   A,(9031)       ; Kolla datorns checksumma.
         CP   221
         JP   Z,9031         ; Hoppa om checksumma 11273.
         JP   9029           ; Hoppa om checksumma 9913.
;
;
; H{r ligger den specialbuffert d{r vi sparar varje inmatad rad.
;
BUFFERT  DEFB 13             ; Plats f|r v}r specialbuffert. Ett CR ligger
         DEFS 120            ; f|rst efter initieringen.
;
;
;
; Sammanfattningsvis kan s{gas att kommandon best}ende av ord tolkas
; i en speciell tolkningsrutin efter det att vi lurat BASIC-tolken att
; hoppa dit. Kommandon som n}s med ett tryck p} en CTRL-tangent bearbetas
