;------------------------------------------------------------------------------ ; Zakladne rutiny pre ovladanie PMD 32-SD. ; ; Pri prisposobovani je potrebne nastavit bazovu adresu 8255 - symbol PIO_A, ; a zvolit adresu kodu a premennych - symboly PROG a VARS. ; Konstanty pre Timeouty su pocitane pre instrukcie 8080 na 2 MHz. ; Pre port na Z80 a pravdeodobne aj s inym taktom, je potrebne tieto konstanty ; zodpovedajuco prepocitat. ;------------------------------------------------------------------------------ CPU 8080 ;------------------------------------------------------------------------------ ; definicia adries portov 8255 PIO_A PORT 0 ; bazova adresa 8255 PIO_B PORT PIO_A+1 PIO_C PORT PIO_A+2 PIO_CW PORT PIO_A+3 PROG EQU 0 ; adresa ovladaca VARS EQU 1000 ; adresa premennych v RAM! ;------------------------------------------------------------------------------ ; premenne v RAM ORG VARS Dma DS 2 ; adresa pre zapis/citanie sektora Drive DS 1 ; cislo mechaniky - 0 az 3 Sector DS 1 ; sektor - podla formatu disku 0 az 63 Track DS 1 ; stopa - podla formatu disku 0 az 255 ;------------------------------------------------------------------------------ ; samotny ovladac ORG PROG ;------------------------------------------------------------------------------ ; Povoli prerusenie pre vstup na porte A ; I: - ; O: povolene prerusenie pre vstup bytu ; M: A ;------------------------------------------------------------------------------ EnaByteIn: MVI A,09h ; 1->C4 povolenie prerusovacieho signalu INTRA pre vstup A OUT PIO_CW MVI A,0Ch ; 0->C6 zakazanie prerusovacieho signalu INTRA pre vystup A OUT PIO_CW RET ;------------------------------------------------------------------------------ ; Povoli prerusenie pre vystup portu A ; I: - ; O: povolene prerusenie pre vystup bytu ; M: A ;------------------------------------------------------------------------------ EnaByteOut: MVI A,08h ; 0->C4 zakazanie prerusovacieho signalu INTRA pre vstup A OUT PIO_CW MVI A,0Dh ; 1->C6 povolenie prerusovacieho signalu INTRA pre vystup A OUT PIO_CW RET ;------------------------------------------------------------------------------ ; Zisti, ci je nastavene INTRA. Na INTRA sa caka zvoleny cas. ; INTRA=1, ak je platny byte na vstupe, alebo bol precitany byte z vystupu. ; I: Pri volani od IsIntraD DE=timeout ; O: CY=1 - timeout ; CY=0 - OK ; M: CY, DE ;------------------------------------------------------------------------------ IsIntra: LXI D,205 ; timeout asi 5ms IsIntraD: PUSH PSW ; uloz AF IsIntra2: IN PIO_C ; zisti stav INTRA ANI 8 JNZ IsIntra3 ; ak je INTRA=1, skoc dopredu DCX D MOV A,D ORA E JNZ IsIntra2 ; a ak nie je nulove, vrat sa do slucky POP PSW ; doslo k timeoutu, obnov AF STC ; nastav CY ako priznak chyby RET IsIntra3: POP PSW ORA A ; vynuluj CY RET ;------------------------------------------------------------------------------ ; Precita byte z PMD 32 a zaroven modifikuje CRC. ; I: B=priebežné CRC ; O: CY=1 - chyba ; CY=0 - A=C=precitany byte, B=modifikovane CRC ; M: AF, BC ;------------------------------------------------------------------------------ ReadByte: PUSH D ; DE na zasobnik CALL IsIntra ; je platny byte na vstupe? POP D ; obnov DE RC ; nie, vrat sa s chybou IN PIO_A ; precitaj byte MOV C,A ; odloz si ho do C XRA B ; modifikuj CRC MOV B,A ; a uloz ho naspat do B MOV A,C ; vrat nacitany byte do A RET ;------------------------------------------------------------------------------ ; Posle povel do PMD 32. Pred poslanim povelu sa najprv preveri, ci na zbernici ; nahodou nie je prezentacny byte. ; I: A=povel ; O: CY=1 - chyba ; CY=0 - OK, B=A=modifikovane CRC ; M: AF, B ;------------------------------------------------------------------------------ SendCommand: MOV B,A ; uloz posielany byte do B PUSH B ; BC, DE na zasobnik PUSH D CALL IsPresent ; zisti, ci je na zbernici prezentacny byte 0AAh ; ak ano, odosli naspat prezentacny byte POP D POP B ; obnov DE, BC RC ; vrat sa, ak doslo ku chybe MOV A,B ; vrat posielany byte do A MVI B,0 ; vynuluj CRC ; pokracuj dalej ;------------------------------------------------------------------------------ ; Posle byte do PMD 32 a modifikuje priebezne CRC. ; I: A=posielany byte, B=priebezne CRC ; O: CY=1 - chyba ; CY=0 - OK, B=A=modifikovane CRC ; M: AF, B ;------------------------------------------------------------------------------ SendByte: PUSH D ; DE na zasobnik CALL IsIntra ; zisti, ci je volny vystup POP D ; obnov DE RC ; vrat sa, ak doslo ku timeoutu OUT PIO_A ; posli byte na vystup XRA B ; modofikuj CRC MOV B,A ; a uloz ho naspat do B RET ;------------------------------------------------------------------------------ ; Zisti, ci na zbernici nie je nahodou prezentacny byte 0AAh, ktory poslala ; disketova jednotka po navrate do "idle" stavu, kedy cakala na povel. ; I: - ; O: CY=1 - chyba ; CY=0 - OK ; M: AF, DE ;------------------------------------------------------------------------------ IsPresent: CALL EnaByteIn ; povol prerusenie pre vstup CALL WaitQ ; male zdrzanie asi 90 us IN PIO_C ANI 8 ; je platny byte na vstupe? JZ EnaByteOut ; ak nie, vrat sa cez povolenie prerusenia pre vystup IsPresent5: CALL EnaByteIn ; povol prerusenie pre vstup IsPresent4: IN PIO_A ; precitaj byte zo vstupu CPI 0AAh ; ak je to prezentacny byte 0AAh JZ IsPresent2 ; skoc poslat prezentacny byte 0AAh na vystup LXI D,5000 ; timeout asi 125 ms CALL IsIntraD ; cakaj na byte RC ; timeout, vrat sa JMP IsPresent4 ; ano, skoc precitat byte zo vstupu IsPresent2: CALL WaitQ ; male zdrzanie asi 90 us CALL EnaByteOut ; povol prerusenie pre vystup MVI A,0AAh ; posli na vystup prezentacny byte 0AAh OUT PIO_A LXI D,5000 ; timeout asi 125 ms CALL IsIntraD ; cakaj na byte JC IsPresent5 ; ak nebol prezentacny byte prijaty, skoc otestovat vstup RET ; bol prijaty prezentacny byte, vrat sa s vynulovanym CY ;------------------------------------------------------------------------------ ; Kratke zdrzanie ; I: - ; O: kratke zdrzanie asi 90 us ; M: AF ;------------------------------------------------------------------------------ WaitQ: MVI A,20 WaitQ1: DCR A JNZ WaitQ1 RET ;------------------------------------------------------------------------------ ; Zisti, ci je pripojena PMD 32 a ci odpoveda prezentacnym bytom. ; I: - ; O: CY=1 - chyba, timeout, PMD 32 neodpoveda prezentacnym bytom ; M: AF, DE, B ;------------------------------------------------------------------------------ CheckDevice: MVI A,0C4h ; inicializuj GPIO 8255 OUT PIO_CW ; SK A: MOD 2, A-IN/OUT, SK B: MOD 1, B-OUT CALL EnaByteIn ; povol prerusenie pre vstup LXI D,10000 ; timeout asi 250 ms CALL IsIntraD ; cakaj na byte RC ; timeout, vrat sa IN PIO_A ; precitaj prijaty byte CPI 0AAh ; je to prezentacny byte 0AAh ? STC ; nastav CY ako priznak chyby RNZ ; nie je to prezentacny byte 0AAh, vrat sa s CY CALL EnaByteOut ; povol prerusenie pre vystup MVI A,0AAh ; posli ako odpoved prezentacny byte 0AAh JMP SendByte ;------------------------------------------------------------------------------ ; Posle CRC na vystup a pocka na ACK a vysledok povelu. ; I: B=aktualne CRC ; O: CY=1 - chyba ; CY=0 - OK, A=vysledok povelu ; M: AF, BC, DE ;------------------------------------------------------------------------------ SndCrcRdAckErr: MOV A,B ; posielane CRC do A CALL SendByte ; posli na vystup RC ; vrat sa, ak doslo ku chybe ReadAckErr: CALL EnaByteIn ; povol prerusenie na vstupe CALL ReadByte ; precitaj byte zo vstupu RC ; vrat sa, ak doslo ku chybe CPI 33h ; bolo prijate byte ACK? STC ; nastav chybovy priznak RNZ ; vrat sa s chybou, ak to nebolo ACK WaitErrT15: LXI D,3000 ; timeout asi 15,5 sec WaitErrT: PUSH D ; DE na zasobnik CALL IsIntra ; je platny byte na vstupe? POP D ; obnov DE JNC ReadByte ; ak ano, skoc ho precitat DCX D ; zniz pocitadlo timeoutu MOV A,D ; a testuj ho na nulu ORA E JNZ WaitErrT ; ak nie je nulovy, skoc do slucky STC ; nastav priznak chyby RET ;------------------------------------------------------------------------------ ; Odosle CRC a caka na potvrdenie. Otestuje chybovy kod na nulu. ; I: B=posielane CRC ; O: CY=1 - chyba ; CY=0 - OK ; M: AF, BC, DE ;------------------------------------------------------------------------------ SndCrcRdAck: CALL SndCrcRdAckErr ; posli CRC a cakaj ACK a vysledok povelu RC ; vrat sa, ak doslo ku chybe JMP ReadCheckCrc2 ; ak bol druhy byte skutocne 0, je to OK ;------------------------------------------------------------------------------ ; Precita byte zo vstupu, predstavujuci CRC ; I: - ; O: CY=1 - chyba CRC alebo timeout ; CY=0 - CRC OK ; M: AF, BC ;------------------------------------------------------------------------------ ReadCheckCrc: CALL ReadByte ; precitaj CRC zo vstupu RC ; vrat sa, ak doslo ku chybe MOV A,B ; skontroluj CRC ReadCheckCrc2: ORA A RZ ; OK STC ; nastav priznak chyby RET ;------------------------------------------------------------------------------ ; Posle do PMD 32 cislo sektoru vratane cisla disku a cislo stopy. ; vstup: cislo sektoru, disku a stopy na adresach Drive, Sector, Track ; B=priebezne CRC ; vystup: CY = 1 - chyba ; CY = 0 - OK, B = A = modifikovane CRC ; meni: AF, BC ;------------------------------------------------------------------------------ SendSectorTrack: LDA Drive ; cislo disku transformuj do 7. a 6. bitu ORA A ; disk A: ? JZ SendSectorTrack2 ; ano, skoc MVI C,0C0H ; transformovana hodnota pre disk D: XRI 3 ; invertuj (prehod) bity cisla disku JZ SendSectorTrack3 ; je to disk D: ? ano, skoc RRC ; pre disky B: a C: posun cislo do hornych bitov RRC SendSectorTrack2: ; C bude obsahovat transformovanu hodnotu cisla disku MOV C,A ; C -> 00h=A: 80h=B: 40h=C: 0C0h=D: SendSectorTrack3: LDA Sector ; vezmi cislo sektora 0 az N (N je max. 63) ANI 03FH ; -> nemusi byt, ak sa zabezpeci povoleny rozsah ORA C ; do hornych bitov pridaj cislo disku CALL SendByte ; posli cislo disku a sektora RC ; navrat s CY=1 pri chybe LDA Track ; cislo stopy 0 az N (N je max. 255) JMP SendByte ; posli stopu ;------------------------------------------------------------------------------ ; Posle povel "B" a precita BOOT. Vzdy je to z jednotky A: ; |-------------------------|------|-------------------------| ; | PMD 85-3 | smer | PMD 32 | ; |-------------------------|------|-------------------------| ; | "B" | ---> | | ; | CRC | ---> | | ; | | <--- | ACK ERR | ; | | <--- | 128 bytov dat | ; | | <--- | CRC | ; |-------------------------|------|-------------------------| ; ACK = 33h; v pripade nejakej chyby je to NAK = 99h ; ERR = 00h, ak prebehol povel v poriadku, ina hodnota znamena chybu ; vstup: cielova adresa na adrese Dma ; vystup: CY = 1 - chyba timeout, CRC ; CY = 0 - OK ; meni: vsetky ;------------------------------------------------------------------------------ ReadBoot: MVI A,'B' ; povel "B" - precitaj BOOT CALL SendCommand ; odosli na vystup JMP ReadSectorB ;------------------------------------------------------------------------------ ; Povel "Q" - precitanie sektora z disku. ; |-------------------------|------|-------------------------| ; | PMD 85-3 | smer | PMD 32 | ; |-------------------------|------|-------------------------| ; | "Q" | ---> | | ; | cislo disku a sektora | ---> | | ; | cislo stopy | ---> | | ; | CRC | ---> | | ; | | <--- | ACK ERR | ; | | <--- | 128 bytov dat | ; | | <--- | CRC | ; |-------------------------|------|-------------------------| ; ACK = 33h; v pripade nejakej chyby je to NAK = 99h ; ERR = 00h, ak prebehol povel v poriadku, ina hodnota znamena chybu ; vstup: cislo sektoru, disku a stopy na adresach Drive, Sector, Track ; cielova adresa na adrese Dma ; vystup: CY = 1 - chyba timeout, CRC ; CY = 0 - OK ; meni: vsetky ;------------------------------------------------------------------------------ ReadSector: MVI A,'Q' ; povel "Q" - precitaj sektor CALL SendCommand ; odosli na vystup RC ; vrat sa, ak doslo ku chybe CALL SendSectorTrack ; posli stopu a sektor ReadSectorB: RC ; vrat sa, ak doslo ku chybe CALL SndCrcRdAck ; posli CRC a pockaj na potvrdenie RC ; vrat sa, ak doslo ku chybe MVI B,0 ; vynuluj CRC MVI D,128 ; nastav pocitadlo LHLD Dma ; do HL adresa pamati ReadSector2: CALL ReadByte ; precitaj byte RC ; vrat sa, ak doslo ku chybe MOV M,A ; uloz byte do pamati INX H ; posun ukazatel DCR D ; zniz pocitadlo prijimanych bytov JNZ ReadSector2 ; ak neboli prijate vsetky, vrat sa do slucky JMP ReadCheckCrc ; skoc precitat CRC ;------------------------------------------------------------------------------ ; Povel "T" - zapise sektor na disk. ; |-------------------------|------|-------------------------| ; | PMD 85-3 | smer | PMD 32 | ; |-------------------------|------|-------------------------| ; | "T" | ---> | | ; | cislo sektora | ---> | | ; | cislo stopy | ---> | | ; | 128 bytov dat | ---> | | ; | CRC | ---> | | ; | | <--- | ACK ERR | ; |-------------------------|------|-------------------------| ; ACK = 33h; v pripade nejakej chyby je to NAK = 99h ; ERR = 00h, ak prebehol povel v poriadku, ina hodnota znamena chybu ; vstup: cislo sektoru, disku a stopy na adresach Drive, Sector, Track ; zdrojova adresa na adrese Dma ; vystup: CY = 1 - chyba timeout, CRC ; CY = 0 - OK ; meni: vsetky ;------------------------------------------------------------------------------ WriteSector: MVI A,'T' ; povel "T" - zapis sektor CALL SendCommand ; odosli na vystup RC ; vrat sa, ak doslo ku chybe CALL SendSectorTrack ; posli stopu a sektor RC ; vrat sa, ak doslo ku chybe MVI D,128 ; nastav pocitadlo LHLD Dma ; do HL adresa pamati WriteSector2: MOV A,M ; byte z pamati CALL SendByte ; odosli RC ; vrat sa, ak doslo ku chybe INX H ; posun ukazatel DCR D ; zniz pocitadlo bytov JNZ WriteSector2 ; opakuj pre vsetkych 128 bytov JMP SndCrcRdAck ; odosli CRC a cakaj na potvrdenie ;------------------------------------------------------------------------------ END ;------------------------------------------------------------------------------