; 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