;------------------------------------------- ; ; VERSIONE PER MONITOR MULTIFIRMWARE ; ; Converte i data-mark della traccia 11 della directory ; Legge la directory attuale e la riscrive con il data-mark indicato da dmark ; ; Per creare un file immagine scrivibile con un PC utilizzare data-mark = 0F8h (operazione 2 del menù) ; Per convertire un floppy scritto da PC in un floppy leggibile dallo Z80-NE utilizzare data-mark = 0FAh (operazione 1 del menù) ; I data-mark 0FBh (ottenibili con il comando A8 del controller) sono quelli delle tracce normali (non la directory) ; ; Il programma funziona con l'interfaccia video vecchia e nuova, ed ha input/output con la tastiera vecchia e nuova ; ; Allocato a F000h per monitor multifirmware ;------------------------------------------- .include "jump.inc" ; Indirizzi working area dmark .equ 0000h ; contiene il comando per scrivere il data-mark: FA (A9)=directory - FB (A8)=altre tracce status .equ 0001h ; contiene lo status di ritorno - 00=ok drive .equ 0002h ; contiene il drive da utilizzare buffer .equ 0003h ; inizio del buffer di lettura/scrittura vidvn .equ 0004h ; se vale 00h si opera sul video vecchio, se vale 01h si opera sul video nuovo .org 0F000h init: di ld hl,45EDh ; disabilita i tasti BREAK ld (0066h),hl ld hl,0ebffh ; cerca dove posizionare lo SP prima di EC00 sp1: ld a,(hl) cpl ld (hl),a cp (hl) jr z,sp3 sp2: dec hl jr sp1 sp3: cpl ld (hl),a cp (hl) jr nz,sp2 dec hl ; lo SP deve avere almeno una locazione di ram scrivibile dopo di lui, altrimenti EX (SP),HL non funziona ld sp,hl call lf0a5 ; inizializza i registri del SY6545 ed i PIO della scheda video nuova call checv ; imposta il registro B' che indica se esiste la scheda video vecchia ld a,20h ; spegne il cursore sul video nuovo call cursor call clrmvn ; azzera l'area messaggio sul video vecchio e nuovo xor a out (0d6h),a ; Deseleziona tutti i drives out (0d0h),a ; ferma il motore (e sgancia la testina) init1: ld hl,5000h ; HL serve per uscire dal loop in caso di timeout wait: ex (sp),hl ; ritardo ex (sp),hl in a,(0d0h) ; controlla se ha rilevato un index mark o un data request bit 1,a jr z,vid ld a,0d0h ; se ha rilevato un index mark o un data request invia un force interrupt per terminare il comando in corso out (0d0h),a dec hl ; gestisce l'eventuale timeout ld a,h or l jr nz,wait ; se non è in timeout allora looppa ;------------------------------------------- vid: call inivn ; pulisce il video vecchio e nuovo fino all'area messaggio esclusa ld hl,tabds1 ; visualizza il menù sui display call vdisp ld hl,menu1 ; visualizza il menù a video call vis ; al ritorno DE contiene la posizione del cursore sul video vecchio ld a,81h ; visualizza il cursore sul video vecchio call waitv ; attende la ritraccia sul video vecchio ld (de),a xor a ; accende il cursore sul video nuovo call cursor tast0a: call inp ; input da tastiera cp 03h ; se è stato premuto 3 -> fine programma jp z,0f800h cp 01h ; controlla se è stato premuto 1 jr nz,tast0b push af ld a,0A9h ; data-mark FA = comando A9 ld (dmark),a jr tast0c tast0b: cp 02h ; controlla se è stato premuto 2 jr nz,tast0a push af ld a,0ABh ; data-mark F8 = comando AB ld (dmark),a tast0c: ld a,20h ; spegne il cursore sul video nuovo call cursor pop af add a,030h ; visualizza il numero digitato nella posizione calcolata per il cursore call waitv ; attende la ritraccia sul video vecchio ld (de),a ; sul video vecchio call writen ; e sul video nuovo call clrmvn ; cancella l'eventuale messaggio sul video vecchio e nuovo ld hl,tabds2 ; visualizza la richiesta per la scelta del drive sui display call vdisp ld hl,menu2 ; visualizza la richiesta per la scelta del drive a video call vis ; DE contiene la posizione del cursore ld a,81h ; visualizza il cursore sul video vecchio call waitv ; attende la ritraccia sul video vecchio ld (de),a xor a ; accende il cursore sul video nuovo call cursor tast1a: call inp ; input da tastiera cp 00h ; controlla se è stato premuto un tasto tra 0 e 3 jr c,tast1a cp 04h jr nc,tast1a push af ; visualizza il numero digitato nella posizione calcolata per il cursore add a,030h call waitv ; attende la ritraccia sul video vecchio ld (de),a ; scrive sul video vecchio call writen ; e sul video nuovo pop af ld hl,tabdrv ; calcola il byte per accedere al drive in base al numero digitato ld e,a xor a ld d,a add hl,de ld a,(hl) ld (drive),a ; salva il drive da utilizzare ld hl,tabds3 ; visualizza la richiesta di RETURN sui display call vdisp ld hl,menu3 ; visualizza la richiesta di RETURN a video call vis ld a,81h ; visualizza il cursore sul video vecchio. Sul video nuovo è già acceso call waitv ; attende la ritraccia sul video vecchio ld (de),a tast2a: call inp cp 10h jr nz,tast2a ld hl,tabds4 ; visualizza il messaggio ATTENDERE sui display call vdisp ld a,20h ; cancella il cursore sul video vecchio call waitv ; attende la ritraccia sul video vecchio ld (de),a call cursor ; spegne il cursore sul video nuovo ld hl,menu4 call vis ; visualizza "operazione in corso" ld hl,buffer ; init area di memoria ld de,buffer+1 ld (hl),00h ld bc,07ffh ldir xor a ; init valori di ritorno cpl ld (status),a loop0: ld a,(drive) ; seleziona il drive out (0d6h),a ld b,5h ; invia 5 volte (?!?) il comando di restore accendendo il motore loop1: ld a,0bh out (0d0h),a ex (sp),hl ex (sp),hl djnz loop1 loop2: in a,(0d0h) ; aspetta che si sia posizionata la testina sulla traccia 0 bit 0,a jr nz,loop2 ld d,11h ; imposta la traccia della directory ld b,00h ; imposta operazione=lettura call rwtrk ; legge la traccia jr z,loop3 ; se tutto ok prosegue con la scrittura ld hl,tabds6 ; se c'è stato un errore visualizza il messaggio sui display call vdisp ld hl,menu6 ; e a video, quindi ed esce call vis jr fine1 loop3: ld a,(dmark) ; imposta il comando di scrittura per il data-mark richiesto ld c,a ld b,01h ; imposta operazione=scrittura call rwtrk ; scrive la traccia jr z,fine ; se tutto ok esce ld hl,tabds7 ; se c'è stato un errore visualizza il messaggio sui display call vdisp ld hl,menu7 ; e a video, quindi esce call vis jr fine1 fine: ld hl,tabds5 ; visualizza messaggio operazione completata sui display call vdisp ld hl,menu5 ; e a video call vis fine1: xor a ; deseleziona i drives out (0d6h),a out (0d0h),a ; ferma il motore (e sgancia la testina) ld hl,0ffffh ; fa un ritardo per permettere di vedere il messaggio sui display fine2: dec hl ld a,h or l jr nz,fine2 jp init1 ;----------------------------------- ; legge/scrive una intera traccia rwtrk: ld e,00h ; primo settore della traccia ld hl,buffer ; locazione di inizio del buffer di lettura/scrittura rwtrk1: call rwsec ; esegue la lettura/scrittura del settore jr nz,rwtrk2 ; se c'è stato un errore esce inc e ; incrementa il numero di settore da leggere/scrivere ld a,e cp 0ah jr nz,rwtrk1 rwtrk2: ret ;----------------------------------- ; legge/scrive un settore rwsec: ld a,e ; carica il registro di settore con E out (0d2h),a ld a,d ; carica il registro di traccia con D out (0d7h),a ld a,01ah ; effettua la seek out (0d0h),a ex (sp),hl ex (sp),hl rw1: in a,(0d0h) ; aspetta che la seek termini rrca jr c,rw1 ld a,b ; se "oper" non è 00 va a fare un write sector cp 00h jr nz,wrsec ld a,88h ; altrimenti effettua un "read sector" out (0d0h),a push bc pop bc jr rd3 rd2: bit 0,a ; controlla se è busy jr z,finerw rd3: in a,(0d0h) ; controlla se il DRQ è attivo bit 1,a jr z,rd2 in a,(0d7h) ; legge il "data register" e lo scrive nella locazione puntata da HL ld (hl),a inc hl jr rd3 wrsec: ld a,c ; carica il tipo di comando write da eseguire out (0d0h),a push bc pop bc jr wr3 wr2: bit 0,a ; controlla se è busy jr z,finerw wr3: in a,(0d0h) ; controlla se il DRQ è attivo bit 1,a jr z,wr2 ld a,(hl) ; scrive il "data register" con la locazione puntata da HL out (0d7h),a inc hl jr wr3 finerw: ld (status),a ; salva lo status di ritorno in a,(0d0h) ; legge lo status register and 1ch ret z ; se non ci sono errori ritorna ld a,0d0h ; altrimenti invia un "force interrupt" out (0d0h),a ret ; e poi ritorna ;------------------------------------------------------ ; pulizia sul video vecchio e nuovo fino a prima dell'area messaggi inivn: push af push hl push de push bc ld bc,0000h ; prima riga da cancellare (riga 0, colonna 0) ld hl,(menu4) ; ultima riga+1 da cancellare (prima riga area messaggi, colonna 0) ld d,l ld e,00h inivn1: ld hl,clrmsg+2 ; punta al messaggio da visualizzare (riga di blank) push bc push de call vis1 ; visualizza la riga pop de pop bc inc b ; controlla se ci sono altre righe da cancellare ld a,b cp d jr nz,inivn1 ; se ce ne sono looppa pop bc pop de pop hl pop af ret ;------------------------------------------------------ ; pulizia sul video vecchio e nuovo dall'area messaggi fino alla fine clrmvn: push af push hl push de push bc ld hl,(menu4) ; prima riga da cancellare (riga area messaggi, colonna 0) ld b,l ld c,00h ld de,01000h ; ultima riga+1 da cancellare (riga 010h, colonna 0) jr inivn1 ;------------------------------------------------------ ; Subroutine per la visualizzazione del menù sul video vecchio e nuovo vis: ld b,(hl) ; mette in BC il numero di riga/colonna presente nelle locazioni puntate da HL e HL+1 inc hl ld c,(hl) ; numero colonna inc hl vis1: call visv ; visualizza sul video vecchio. Al ritorno DE contiene la posizione del cursore sul video vecchio push de call visn ; visualizza sul video nuovo pop de ret ;------------------------------------------------------ ; Subroutine per la visualizzazione del menù sul video vecchio. ; Ritorna la posizione del cursore in DE visv: push af push bc push hl visv1: call vloc1 ; calcola in DE l'indirizzo del video vecchio in base alla riga/colonna indicata da BC visv2: ld a,(hl) ; recupera il carattere da scrivere call waitv ; attende la ritraccia del video vecchio ld (de),a ; visualizza il carattere sul video vecchio inc de inc hl xor a ; controlla se il prossimo carattere è 00h cp (hl) jr nz,visv2 inc hl cpl ; se si, controlla se il prossimo carattere è 0ffh cp (hl) ; se si esce da loop, altrimenti carica la successiva prima posizione e looppa jr z,visv3 ld b,(hl) ; mette in BC il numero di riga/colonna presente nelle locazioni puntate da HL e HL+1 inc hl ld c,(hl) ; numero colonna inc hl jr visv1 visv3: inc hl ; calcola in DE l'indirizzo del cursore in base alla riga/colonna nella locazione puntata da HL e HL+1 call vloc pop hl pop bc pop af ret ;------------------------------------------------------ ; Subroutine per la visualizzazione del menù sul video nuovo ; Ritorna la posizione del cursore in DE visn: push af push bc push hl visn1: call nloc1 ; calcola in DE l'indirizzo del video nuovo in base alla riga/colonna indicata da BC push hl push de pop hl call lf06e ; carica in R18 e R19 l'indirizzo (HL) del carattere da visualizzare pop hl visn2: ld a,(hl) ; recupera il carattere da scrivere call writen ; attende la ritraccia e visualizza il carattere sul video nuovo inc hl xor a ; controlla se il prossimo carattere è 00h cp (hl) jr nz,visn2 inc hl cpl ; controlla se il prossimo carattere è 0ffh cp (hl) ; se si esce dal loop, altrimenti carica la successiva prima posizione e looppa jr z,visn3 ld b,(hl) ; mette in BC il numero di riga/colonna presente nelle locazioni puntate da HL e HL+1 inc hl ld c,(hl) ; numero colonna inc hl jr visn1 visn3: inc hl ; calcola in DE l'indirizzo del cursore in base alla riga/colonna nella locazione puntata da HL e HL+1 call nloc push de pop hl call lf060 ; carica in R14, R15, R18 e R19 l'indirizzo (HL) del cursore e del carattere da visualizzare pop hl pop bc pop af ret ;------------------------------------------------------ ; Input da tastiera inp: push hl ld a,0C3h ; abilita i tasti BREAK ld (0066h),a ld hl,break ld (0067h),hl call input ; routine di input del monitor multifirmware ld hl,45EDh ; disabilita i tasti BREAK ld (0066h),hl pop hl ret ;------------------------------------------------------ ; Routine per la gestione dei tasti BREAK break: ld hl,init ; salta all'inizio ritornando dall'interrupt non mascherabile push hl retn menu1: .byte 000h, 007h, "CONVERSIONE FLOPPY", 00h .byte 002h, 000h, "1 > DA IMMAGINE A FLOPPY Z80", 00h .byte 003h, 000h, "2 > DA FLOPPY Z80 A IMMAGINE", 00h .byte 004h, 000h, "3 > FINE PROGRAMMA" , 00h .byte 006h, 000h, "SCEGLI:", 00h .byte 00Fh, 000h, "(C) ROBERTO BAZZANO 2011" .byte "-2024", 00h .byte 0ffh .byte 006h, 008h ; riga/colonna in cui posizionare il cursore menu2: .byte 008h, 000h, "DRIVE DA UTILIZZARE (0..3):", 00h .byte 0ffh .byte 008h, 01Ch menu3: .byte 00Ah, 000h, "INSERIRE IL FLOPPY NEL DRIVE", 00h .byte 00Bh, 000h, "E PREMERE (RETURN):", 00h .byte 0ffh, 00Bh, 014h menu4: .byte 00Dh, 000h, "ATTENDERE - OPERAZIONE" .byte " IN CORSO", 00h, 0ffh, 000h, 000h, menu5: .byte 00Dh, 000h, "* OPERAZIONE COMPLETATA *" .byte " ", 00h, 0ffh, 000h, 000h, menu6: .byte 00Dh, 000h, "** ERRORE IN LETTURA " .byte " ", 00h, 0ffh, 000h, 000h, menu7: .byte 00Dh, 000h, "** ERRORE IN SCRITTURA " .byte " ", 00h, 0ffh, 000h, 000h, clrmsg: .byte 000h, 000h, " " .byte " ", 00h, 0ffh, 000h, 000h tabdrv: .byte 01h, 02h, 04h, 08h ;------------------------------------------------------ tabds1: .byte 08h, 092h, 046h, 0FFh, 0F9h, 0BFh, 0A4h, 0BFh, 0B0h ; SC. 1-2-3 tabds2: .byte 05h, 0A1h, 0AFh, 0F9h, 0E3h, 006h ; DRIVE. tabds3: .byte 06h, 0C6h, 087h, 0AFh, 047h, 0FFh, 0C0h ; CTRL.0 tabds4: .byte 03h, 088h, 087h, 007h ; ATT. tabds5: .byte 04h, 08Eh, 0F9h, 0ABh, 086h ; FINE tabds6: .byte 08h, 086h, 0AFh, 02Fh, 0FFh, 047h, 086h, 087h, 007h ; ERR. LETT. tabds7: .byte 08h, 086h, 0AFh, 02Fh, 0FFh, 092h, 0C6h, 0AFh, 079h ; ERR. SCRI. ;------------------------------------------------------ .org 0F7FFh .byte 00h .end