Autore Topic: Uso Dei Timer  (Letto 2252 volte)

Alberto

  • Utente
  • **
  • Post: 589
  • Gioco Preferito: Grand Prix Circuit
Uso Dei Timer
« il: 25 Agosto 2006, 22:05:18 »
 I timer di sistema sono una risorsa del C64 potente quanto bistrattata.Si tratta di veri e propri cronometri dotati di una risoluzione pari a un ciclo di clock (circa 1.015 microsecondi per i C64 europei) in grado di contare alla rovescia e di generare interrupt una volta arrivati a0:il C64 ne incorpora ben quattro (due per ogni chip CIA).

Normalmente vengono usati dal sistema operativo per rendere possibile l'interazione con l'utente,la comunicazione con il disk-drive e la trasmissione di dati attraverso la porta del registratore,ma sono talmente versatili da poter essere usati in molti altri contesti,per esempio come cronometri nei videogiochi.

QuestO semplice listato mostra una classica applicazione dei timer di sistema:un piccolo cronometro digitale nell'angolo in alto a sinistra dello schermo,che può essere resettato con la pressione di RUN-STOP.

Come al solito,questa non è una supposta ma una proposta. :) Per chi volesse saperne di più sull'uso dei timer e/o sofisticare la routine,c'e' l'eccellente "Mapping the C64".

P.S. piccola "sfida" per i più volenterosi:siete in grado di sofisticare il programma aggiungendo un tasto per fermare il cronometro per poi farlo ripartire (non da 0,ma dal punto in cui era arrivato a contare),e uno per ripristinare le condizioni standard?

Buon coding a tutti! B)

Codice: [Seleziona]
;esempio d'uso dei timer di sistema

screen = $400

norm = $ea31
ret = $ea81
ref = $fb

.word eop
.word 7102
.byte $9e
.asc "2061"
.byte 0
eop
.word 0

jsr draw

sei
lda #<irq
sta $314
lda #>irq
sta $315      ;irq vect
lda #$7c
sta $dc06
lda #$26
sta $dc07     ;~ 0.01 sec
lda #$82
sta $dc0d     ;irq timer B on
lda #1
sta $dc0f     ;timer B on
cli
rts

irq
lda $91
bpl rest
cont
        lda $dc0d
        lsr
bcc skip
jmp norm      ;irq normale
skip
ldx #7

ldy #"9"
jsr rfrsh     ;centesimi
cmp #"0"
bne exit

dex
jsr rfrsh     ;decimi
cmp #"0"
bne exit

dex
dex
jsr rfrsh     ;secondi
cmp #"0"
bne exit

dex
ldy #"5"      ;0-59 sec
jsr rfrsh     ;10 sec
cmp #$30
bne exit

dex
dex
        ldy #"9"
jsr rfrsh     ;minuti
cmp #$30
bne exit

dex
ldy #"5"      ;0-59 min
        jsr rfrsh
exit
jsr draw
jmp ret

;aggiorna il conteggio

rfrsh    
sty ref
lda time,x
cmp ref
bne ok
lda #$2e      ;-2 perchè il carry è settato
ok
        adc #1
sta time,x
rts

;stampa il conteggio

draw
ldx #7
lp1
lda time,x
sta screen,x
dex
bpl lp1

rts

;resetta il conteggio

rest
ldx #7
lp2
        lda time+9,x
         sta time,x
         dex
         bpl lp2

         jmp cont
time
.text "00:00:00"
.byte 0
.text "00:00:00"

iAN CooG

  • Utente
  • **
  • Post: 1774
    • http://iancoog.altervista.org
  • Gioco Preferito: Turbo Assembler, ActionReplay Monitor, DiskDemon
Uso Dei Timer
« Risposta #1 il: 26 Agosto 2006, 18:50:59 »
Citazione da: "Alberto"
aggiungendo un tasto per fermare il cronometro per poi farlo ripartire (non da 0,ma dal punto in cui era arrivato a contare
Non ci ho ancora provato, ma immagino che non basti uscire dalla irq con una jmp $ea31 ma proprio fermare il CIA timer? Questo implica doversi memorizzare l'ora in cui si ferma il timer e ripristinarla prima di farlo ripartire, o non dovrebbe essere necessario?
-=[]=--- iAN CooG/HVSC^C64Intros ---=[]=-
- http://hvsc.c64.org - http://intros.c64.org -

Alberto

  • Utente
  • **
  • Post: 589
  • Gioco Preferito: Grand Prix Circuit
Uso Dei Timer
« Risposta #2 il: 26 Agosto 2006, 22:09:02 »
 Ciao iAN

Citazione
Questo implica doversi memorizzare l'ora in cui si ferma il timer e ripristinarla prima di farlo ripartire, o non dovrebbe essere necessario?

è un'idea,ma non è necessario stare a diventar matti:in questo caso per fermare il conteggio è sufficiente disattivare gli interrupt del timer B,in questo modo la routine salterà sempre a $ea31.

Altre idee?Forza siori,dai... :mattsid:  

Alberto

  • Utente
  • **
  • Post: 589
  • Gioco Preferito: Grand Prix Circuit
Uso Dei Timer
« Risposta #3 il: 05 Settembre 2006, 17:11:26 »
 Ok ho capito,lo faccio io.

Si può inserire nella routine di interrupt un controllo del tipo

Codice: [Seleziona]
lda $91
bpl rest      ;RUN-STOP?
cmp #239
beq stop      ;SPC?
   

Come si nota,si salta a stop ogni volta che viene premuto il tasto spazio.

La routine di arresto/riavvio è la seguente (per maggiori informazioni su come si gestisce$dc0d,consultare MTC64).

Codice: [Seleziona]
;ferma/riprende il conteggio

stop
lda #2  
sta $dc0d
lda stop+1
eor #$80
sta stop+1
done
jmp ret

Alcune note sul listato completo:l'ultima linea della routine di reset permette di resettare il cronometro anche quando è fermo,mentre lo switch sulla condizione di tasto premuto serve a evitare che,data la frequenza dell'interrupt,il cronometro venga arrestato e/o riavviato più volte ad ogni pressione della spacebar.

Siamo comunque ancora ben lontani dalla perfezione,per cominciare:

1. La tecnica usata per arrestare il cronometro è semplice,ma anche molto approssimativa.

In effetti inibire le IRQ del timer B non significa fermarlo,per cui avremo un errore di anticipo o di ritardo alla ripresa del conteggio.Con una risoluzione  di un centesimo di secondo l'errore non è percettibile da un essere umano,ma può diventarlo per risoluzioni maggiori,ad esempio di un secondo.
In quel caso sarebbe molto più saggio arrestare il timer B per poi riavviarlo,come suggerito da iAN CooG.

2. La precisione del cronometro è comunque scarsa,perchè la routine gestisce DUE sorgenti di IRQ,per cui è possibile che di tanto in tanto i due timer si "pestino i piedi":niente di male se il timer A resta in attesa di vedere servita la IRQ del timer B,ma la situazione opposta implica un rallentamento nel conteggio.

3. Scegliere il tasto spazio come interruttore non è il massimo;sarebbe meglio un tasto funzione tipo CTRL altrimenti si può stampare a schermo qualcosa di indesiderato.
Chi vuole provare a migliorare la routine tenga presente che usando CTRL lo switch su $c5 non funzionerà,perchè questa locazione viene modificata solo per evitare letture ripetute di uno stesso carattere.

4. Non è previsto il caso in cui si voglia tornare alle condizioni standard (ancora da implementare,volontari? B) ).

Spero che queste osservazioni possano essere utili a qualcuno.Posto il codice

Codice: [Seleziona]
               screen = $400

                norm = $ea31
                ret = $ea81
                ref = $fb

                .word eop
                .word 7102
                .byte $9e
                .asc "2061"
                .byte 0
eop
                .word 0

                lda #$40
                sta 650      ;disattiva repeat (per SPC)
                lda #$f0
                sta sw

                jsr draw

                sei
                lda #<irq
                sta $314
                lda #>irq
                sta $315      ;irq vect
                lda #$7c
                sta $dc06
                lda #$26
                sta $dc07     ;~ 0.01 sec
                lda #$82
                sta $dc0d     ;irq timer B on
                lda #1
                sta $dc0f     ;timer B on
                cli
                rts
irq
                lda $c5
                cmp #$40      ;tasto premuto?
sw
                beq cont

                lda sw
                eor #$20
                sta sw

                lda $91
                bpl rest      ;RUN-STOP?
                cmp #239
beq stop      ;SPC?
cont        
                lda $dc0d
                lsr
                bcc skip
                jmp norm      ;irq normale
skip
                ldx #7

                ldy #"9"
                jsr rfrsh     ;centesimi
                cmp #"0"
                bne exit

                dex
                jsr rfrsh     ;decimi
                cmp #"0"
                bne exit

                dex
                dex
                jsr rfrsh     ;secondi
                cmp #"0"
                bne exit

                dex
                ldy #"5"      ;0-59 sec
                jsr rfrsh     ;10 sec
                cmp #$30
                bne exit

                dex
                dex
                ldy #"9"
                jsr rfrsh     ;minuti
                cmp #$30
                bne exit

                dex
                ldy #"5"      ;0-59 min
                jsr rfrsh
exit
                jsr draw
                jmp ret

;aggiorna il conteggio

rfrsh    
                sty ref
                lda time,x
                cmp ref
                bne ok
                lda #$2e      ;-2 perchè il carry è settato
ok
                adc #1
                sta time,x
                rts

;stampa il conteggio

draw
                ldx #7
lp1
                lda time,x
                sta screen,x
                dex
                bpl lp1

                rts

;resetta il conteggio

rest
                ldx #7
lp2
                lda time+8,x
                sta time,x
                dex
                bpl lp2

                jmp exit

;ferma/riprende il conteggio

stop
                lda #2  
                sta $dc0d
                lda stop+1
                eor #$80
                sta stop+1
done
                jmp ret
time
                .text "00:00:0000:00:00"