Autore Topic: Timing Rasters E Badline  (Letto 7018 volte)

Elder0010

  • Utente
  • **
  • Post: 75
    • http://csdb.dk/scener/?id=22731
  • Gioco Preferito: Rampage
Timing Rasters E Badline
« il: 14 Marzo 2011, 20:21:07 »
In riferimento al codice di Ian Coog:
http://ready64.org/smf/index.php?topic=1837 - aggiunto link

Codice: [Seleziona]

; 07: ora e' stabile!
; abbiamo trovato i valori per temporizzare il raster e ora c'e' una riga
; stabile, sia con lo schermo acceso che spento

    *=$0801
    include basicline.s
    sei
    lda #<irq
    ldx #>irq
    sta $0314
    stx $0315
    lda #$01
    sta $d019
    sta $d01a
    lda #$80
    sta $d012
    lda #$1b
    sta $d011
    lda #$7f
    sta $dc0d
    lda $dc0d
    cli
    rts
irq
    lda #$01
    sta $d019
    bit $24
    bit $24
    bit $24
    bit $24
    inc $d020
    ldx #$0b
    dex
    bne *-1

    dec $d020
    jmp $ea31

Se ho capito bene, facendo riferimento a un sistema PAL:
In ogni rasterline standard la routine deve durare 63 cicli per avere un raster stabile (no flicker)
In ogni badline 23 cicli.

Per routine intendo tutto l'irq, per cui da lda#$01 a jmp $ea31 compresi.

Eppure ho provato a fare i conti utilizzando
<a href='http://www.c64-wiki.com/index.php/Category:Machine_language_instruction' target='_blank'>questa tabella</a> e il conto viene:

   lda #$01 (2 cicli)
   sta $d019 (4 cicli)
   bit $24 (3 cicli, istruzione ripetuta 4 volte quindi 12 cicli totali)
   inc $d020 (6 cicli)
   ldx #$0b (2 cicli)
   e fino a qui siamo a 2+4+12+6+2 = 26 cicli.

Dopodichè inizia un iterazione: 11 volte due istruzioni da 2 cicli, per cui 4*11 = 44 cicli.

    dec $d020 6 cicli
    jmp $ea31 3 cicli

Per un totale di: 26+44+6+3 = 79 cicli  :huh:

Il raster risulta invece stabile, per cui sbaglio io qualcosa nei conti, ma non riesco a capire cosa!
Grazie per la pazienza ragazzi :)
« Ultima modifica: 22 Gennaio 2015, 00:23:34 da eregil »
lda #0 sta $d020 sta $d021

Freshness79

  • Utente
  • **
  • Post: 128
  • Gioco Preferito: Dizzy collection
Timing Rasters E Badline
« Risposta #1 il: 14 Marzo 2011, 23:54:58 »
 Dunque... innanzitutto il codice sopra non genera un raster veramente stabile (iAN non averne a male, niente di personale ;) ).
Per vederlo é sufficiente usare vice e, nel menu VIC-II, impostare i bordi a debug: noterai che sulla destra il punto di partenza della linea (il punto in cui la cpu esegue inc $d020) non é perfettamente stabile ma oscilla.
Questa instabilità é legata al modo col quale vengono servite le interruzioni: se un'interruzione viene 'triggerata' durante l'esecuzione di un'istruzione, il 6510 non la servirà fintanto che non avrà terminato l'istruzione stessa. Tale oscillazione, quindi, dipende dalla durata dell'istruzione che stava eseguendo la CPU nel momento in cui é stato ricevuto l'IRQ. Per istruzioni particolarmente lunghe (inc assoluto/lsr assoluto ecc) si può arrivare anche a 6 cicli di ritardo.
Esistono almeno due metodi molto usati per ovviare al problema:
- doppio raster interrupt
- timer sincronizzato
E' probabile ne esistano degli altri ma si tratta sostanzialmente di variazioni sul tema.
Personalmente conosco bene il primo e meno bene il secondo ma, se vuoi sapere qualcosa su come funzionano, chiedi pure.
Un modo più rapido (ma non altrettanto efficace) di creare un raster stabile si basa invece sul fatto che in una badline il VIC, prima di sottrarre il bus alla cpu, permette ad essa 3 cicli di write: se quindi si posiziona oculatamente una istruzione RMW (read modify write) come ad esempio una INC, immediatamente prima che il VIC prenda possesso del bus, si può fare in modo di assorbire ritardi di 1,2 o 3 cicli.
Chiaro che se la differenza supera i 3 il "giochino" non funziona più.
Ok, questa era la premessa... veniamo ai tuoi conti.
E' tutto giusto, ma manca una parte!
Quando viene generata un'interruzione, oltre a salvare lo status register e l'IP, il 6510 prende i valori delle locazioni di memoria $FFFE ed $FFFF e le mette nell'instruction pointer. Nel 64 quelle due locazioni puntano ad $FF48, se disassembly l'area troverai la seguente routine:
Codice: [Seleziona]
last instr. ;x
IRQ ;7
PHA ;3
TXA ;2
PHA ;3
TYA ;2
PHA ;3
TSX ;2
LDA $0104,X;4
AND #$10;2
BEQ $FF58;3
JMP ($0316);skip
JMP ($0314);5 - 36+x
In sostanza quando viene eseguito il salto alla routine puntata da $0314/$0315 il processore ha già eseguito 36 cicli (+x dipendente dall'istruzione durante la quale si é verificata l'interruzione).
Nel tuo conto erano questi a mancare.
La routine che ti propongo qua sotto é una rivisitazione di quella che hai postato e sfrutta il metodo 'rapido' che ti ho illustrato.
Codice: [Seleziona]
*=$0801    
include basicline.s
sei
lda #<irq
ldx #>irq
sta $0314
stx $0315
lda #$01
sta $d019
sta $d01a
lda #$82;Importante: dev'essere la riga prima di una badline!!
sta $d012
lda #$1b
sta $d011
lda #$7f
sta $dc0d
lda #$c8
sta $d016
lda $dc0d
cli
rts

irq
ldx #$00 ;2 (si parte da 36+x)
inc $ffff;6
inc $ffff;6
inc $ffff,x;7
inc $d020;6 (27+36+x) => (Saltata un'intera linea) + x

bit $ff;3+x Questa é la badline
inc $ffff;9+x Qui parte della differenza viene assorbita (max 3 cicli)

dec $d020;6
lda #$01 ;2
sta $d019;4
jmp $ea31

Elder0010

  • Utente
  • **
  • Post: 75
    • http://csdb.dk/scener/?id=22731
  • Gioco Preferito: Rampage
Timing Rasters E Badline
« Risposta #2 il: 16 Marzo 2011, 21:57:17 »
Non incollo il codice perchè è un po lungo e non vorrei "floodare" il forum :)

Ho ragionato un po' sulle cose che hai scritto, e ho fatto diversi esperimenti, ora i conti tornano.

A questo punto ho tentato la strada del doppio interrupt.

La logica che ho applicato è questa (spero sia corretta)

init del programma
set up primo interrupt

primo_interrupt
    set up secondo interrupt

secondo_interrupt
      chiamate a procedure (logica del programma)         

     set up primo interrupt


In allegato la prova che ho fatto, con 3 interrupts:

Il primo si limita a puntare il secondo
Il secondo disegna una rasterbar di 10 linee nella zona superiore (bordo)
Il terzo disegna una rasterbar di 1 linea al centro dello schermo e cicla i colori delle rasterbars

Ho provato a muovere la linea centrale, e c'è un flicker regolare: penso si tratti delle badlines. Per risolvere, dovrei creare delle timing tables dal quale pescare il valore giusto di ritardo a seconda della linea in cui mi trovo, penso!

Allego il sorgente, e il compilato :)

 
« Ultima modifica: 22 Gennaio 2015, 00:24:02 da eregil »
lda #0 sta $d020 sta $d021

Freshness79

  • Utente
  • **
  • Post: 128
  • Gioco Preferito: Dizzy collection
Timing Rasters E Badline
« Risposta #3 il: 17 Marzo 2011, 02:58:29 »
 ...no! :D
Non funziona così la tecnica del doppio raster.
Quello che hai fatto tu é creare un secondo raster interrupt totalmente slegato dal primo.
Cerco di metterti nella strada giusta perché secondo me hai tranquillamente i mezzi per farcela da solo.
Il problema da risolvere é fare in modo che l'interruzione dovuta ad una raster line non accumuli un eccessivo ritardo a causa di un'istruzione (al momento del trigger) troppo lunga. Dunque... perché doppio raster?
La cpu, nella sua normale esecuzione, incontra istruzioni di qualsiasi lunghezza: il primo raster interrupt di fatto serve ad "impossessarci" della cpu, impostare un nuovo raster interrupt e assicurarci che quando questo secondo interrupt verrà chiamato la cpu starà eseguendo un'istruzione più corta possibile (2 cicli).
A quel punto, nel secondo interrupt sapremo con certezza che potremo essere in sincrono col raster o al massimo in ritardo di un ciclo: sarà sufficiente eliminare quest'ultimo ciclo di incertezza per avere la cpu totalmente sincronizzata con il raster.
Hint1
Il primo raster interrupt non necessita un'uscita ($EA31) perché... non deve arrivarci!
Hint2
I due interrupt sono nested: il secondo avviene durante l'esecuzione del primo.
PS: pensaci, pensaci e ripensaci. Raggiungere il raster stabile e capire come lo si é ottenuto apre la strada a diversi effetti ottenibili con il VIC.
Buon divertimento!
 

Elder0010

  • Utente
  • **
  • Post: 75
    • http://csdb.dk/scener/?id=22731
  • Gioco Preferito: Rampage
Timing Rasters E Badline
« Risposta #4 il: 17 Marzo 2011, 09:16:58 »
 ahha bocciato alla grande  :lol:  

sfida accettata! Ora ci penso su e vedo cosa riesco a combinare!!  
lda #0 sta $d020 sta $d021

Elder0010

  • Utente
  • **
  • Post: 75
    • http://csdb.dk/scener/?id=22731
  • Gioco Preferito: Rampage
Timing Rasters E Badline
« Risposta #5 il: 17 Marzo 2011, 15:22:46 »
 Cosi' credo di essere su una buona strada, anche se ancora non va! Ho visto un po' di esempi in rete, e ho provato a riproporre quello che ho capito.

Sia in modalità standard che debug dei bordi la linea non inizia dal punto giusto, perchè il salto jsr rasterbars viene fatto troppo presto. Inoltre non cè un flickering continuo: la linea è ferma ma a intervalli regolari si sposta di qualche px :(.



Codice: [Seleziona]
;prova doppio interrupt nested

    *=$0801
    include basicline.s

  tax
  stx $d020
  stx $d021
  lda #$0b ; spegnamo il bit che controlla l'accensione dello schermo
      sta $d011
  
      sei
      lda #<irqpre
      ldx #>irqpre
      sta $0314
      stx $0315
    
      sta $d01a
      lda #$34    
  sta $d012
  lda #$1b    
  sta $d011
      lda #$7f
      sta $dc0d
      lda $dc0d
  
  
      cli

hold
  jmp hold



irqpre
  
  lda #<irq
      ldx #>irq
      sta $0314
      stx $0315
  
  inc $d019
  inc $d012
            
 
;Aggiungo una serie di nop per "non fare nulla" intanto che
               ;l'altro interrupt viene eseguito
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
   nop
  
  
irq
  nop
  jsr rasterbars
  
  lda #<irqpre
             ldx #>irqpre
      sta $0314
      stx $0315
  
  inc $d019
  lda #$34    
  sta $d012
  jmp $ea31
  

rasterbars
  
   nop
   lda colors
   sta $d020
   sta $d021
  
   ldx #$0a
   dex
   bne *-1
  
   lda #0
   sta $d020
   sta $d021
      
   rts
  

dir   .byte $0
offs   .byte $90

colors
         .byte $01,$07,$05,$03,$07,$02
         .byte $09,$06,$03,$05,$03,$02
         .byte $0e,$03,$03,$0e,$03,$03
         .byte $03,$01,$03,$01,$01,$03
         .byte $01,$01,$01,$03,$01,$01
         .byte $03,$01,$03,$03,$03,$0e
         .byte $03,$03,$0e,$03,$0e,$0e
         .byte $0e,$06,$0e,$0e,$06,$0e
         .byte $06,$06,$06,$06,$06,$06

 
lda #0 sta $d020 sta $d021

Freshness79

  • Utente
  • **
  • Post: 128
  • Gioco Preferito: Dizzy collection
Timing Rasters E Badline
« Risposta #6 il: 18 Marzo 2011, 15:15:35 »
 ... in effetti il 2° interrupt non viene mai chiamato.
Nella routine preirq hai configurato correttamente il secondo IRQ ma ti sei dimenticato di riattivare le interruzioni: quando il 6510 serve un'interruzione imposta lo status flag in modo da mascherare successivi IRQ.
In sostanza prima delle NOP devi inserire una CLI.
A quel punto il 2° interrupt verrà generato tra le NOP ma avrai comunque un'incertezza di 1 ciclo da correggere, hai già visto come fare? Tutto si gioca su un confronto ben mirato su D012.
Infine, importantissimo, dal momento che hai servito due interruzioni una dentro all'altra, lo stack avrà le informazioni di ritorno relative al primo e al secondo IRQ. Quelle al primo ci servono, quelle al secondo no pertanto possono scartate.
Tieni presente che un'interruzione gestita con l'appoggio del kernel ($0314) inserisce 6 byte nello stack: vanno tolti.
Se hai altri dubbi chiedi pure, forza con i fix!
 

Elder0010

  • Utente
  • **
  • Post: 75
    • http://csdb.dk/scener/?id=22731
  • Gioco Preferito: Rampage
Timing Rasters E Badline
« Risposta #7 il: 18 Marzo 2011, 23:53:48 »
 Ho studiato un po' del tuo codice sul forum + la routine di fungus su
codebase.

Credo che adesso il 2° interrupt sia ok (il break che ho inserito non viene mai eseguito!).

Inoltre ho salvato e ripristinato lo stato stack pointer usando la locazione $5f, copiando da te. hai scelto proprio quella locazione per un motivo?

Il raster è ancora ballerino, e ho notato che premendo tasti della tastiera va tutto a farsi friggere ancora di piu'! Forse devo disabilitare qualcosa nel set up iniziale dell'ambiente?

Grazie per tutte queste informazioni!! spero di essere riuscito a cogliere le dritte che mi hai dato :)

Codice: [Seleziona]
;prova doppio interrupt nested

    *=$0801
    include basicline.s

   sei  
   tax
   stx $d020
   stx $d021

   lda #<irqpre
   ldx #>irqpre
   sta $0314
   stx $0315
  
   lda #$01
          sta $d01a  ; Turn on raster interrupts
  
   lda #$34    
   sta $d012
   lda #$1b    
   sta $d011
   lda #$7f
   sta $dc0d
   sta $dd0d
   cli

hold
   jmp hold



irqpre  
   lsr $d019
   inc $d012;Vogliamo che il prossimo interrupt sia synchato a $35
  
   lda #<irq
   ldx #>irq
   sta $0314
   stx $0315

   tsx;Trasferisco lo stack pointer in x
   stx $5f;storo x in $5f

   cli
  
  ;Aggiungo una serie di nop per "non fare nulla" intanto che
          ;l'altro interrupt viene eseguito
   nop
   nop
   brk;questo brk non viene mai eseguito quindi andiamo un po' meglio!
    
irq
   asl $d019
  
   ldx $5f;carico quello che avevo salvato prima..
   txs;ripristino lo stack pointer

   lda #$35  ;Siamo a 35?
   cmp $d012
   beq start  ;se NO devo saltare un altro ciclo!
start

   nop
 
  
  
   jsr rasterbars
    
   lda #<irqpre;Punto di nuovo al primo interrupt
   ldx #>irqpre
  
   sta $0314
   stx $0315
    
      ;rimetto apposto anche il registro $d012
   lda $34
   sta $d012
  
   jmp $ea31
  

rasterbars    
   lda colors
   sta $d020
   sta $d021
  
   ldx #$03
   dex
   bne *-1
  
   lda #0
   sta $d020
   sta $d021
      
   rts
  


dir       .byte $0
offs      .byte $90

colors
         .byte $01,$07,$05,$03,$07,$02
         .byte $09,$06,$03,$05,$03,$02
         .byte $0e,$03,$03,$0e,$03,$03
         .byte $03,$01,$03,$01,$01,$03
         .byte $01,$01,$01,$03,$01,$01
         .byte $03,$01,$03,$03,$03,$0e
         .byte $03,$03,$0e,$03,$0e,$0e
         .byte $0e,$06,$0e,$0e,$06,$0e
         .byte $06,$06,$06,$06,$06,$06
lda #0 sta $d020 sta $d021

Freshness79

  • Utente
  • **
  • Post: 128
  • Gioco Preferito: Dizzy collection
Timing Rasters E Badline
« Risposta #8 il: 19 Marzo 2011, 16:19:37 »
 L'impostazione generale é corretta, i problemi sono dovuti ai timing.
Punto 1
Nel 6502 (ed analogamente nel 6510 del nostro c64), quando si genera un'interruzione avvengono le seguenti cose:
- si attende che finisca l'eventuale istruzione in corso (X cicli)
- si esegue l'IRQ (salvataggio IP e status register, salto alla routine puntata da $FFFE/$FFFF) (7 cicli)

Citazione
Ora, se stai lavorando col c64 in modalità normale (con le ROM attive), agli indirizzi $FFFE ed $FFFF ci sono rispettivamente i valori $48 e $FF. Il processore, quindi, non farà altro che saltare alla routine all'indirizzo $FF48: questa routine é quella che ho già postato nella mia prima risposta a questo thread. Se lavorassi con le ROM inattive (non é il caso del tuo programma) potresti iniziare a servire l'interruzione dopo un ritardo di soli 7+X cicli.
- si esegue la routine in $FF48 che, come ultima istruzione, effettua un salto all'indirizzo puntato in $0314/$0315 (29 cicli)

Tirando le somme, quindi, in realtà l'istruzione "lsr $d019", la prima del tuo irqpre, viene eseguita dopo X+7+29 cicli da quando é stata generata l'interruzione (cioé da quando siamo nella riga $34!).
Questo 'X' dipende da quanto lunga era l'istruzione durante la quale é stato generato l'IRQ: può valere da 0 (interruzione avvenuta esattamente tra un'istruzione e l'altra) a 7 (interruzione avvenuta durante il primo ciclo di un'istruzione da 8 cicli).
Da ciò ne consegue che l'inizio di irqpre si attesta tra i 36 ed 43 cicli di ritardo rispetto all'inizio del raster.
Cosa comporta ciò? Che nel peggior caso hai solo 20 (63-43) cicli a disposizione per gestire la prima interruzione prima che sia triggerato l'interrupt per la seconda (quella relativa alla riga $35).
Tornando al tuo programma con un rapido conto puoi osservare che le istruzioni che, in irqpre, vanno dalla LSR $D019 alla CLI (compresa) superano abbondantemente i 20 cicli (sono già 20 con lo sta $0314).
Hai pochi cicli... come fare? C'é posto solo per l'essenziale: l'aknowledge dell'interrupt, l'impostazione della riga del secondo interrupt, l'aggiornamento dell'indirizzo della routine dell'handler.
Quest'ultima attività in particolare la puoi ridure al solo aggiornamento del LSB perché, se allinei bene il programma, é ragionevole pensare che il primo interrupt sia negli stessi 256 byte del secondo.
Quindi: 6 cicli per $D019, 6 per $D012,2+4 per $0314,2 per il CLI:20 cicli!
Fai quindi seguire almeno 4 NOP: noi abbiamo analizzato il caso peggiore, ma nel caso migliore avremmo 36+20=56 cicli e quindi dopo la CLI ci potrebbero essere ancora 7 cicli prima della seconda interruzione. Con 4 NOP siamo al sicuro.
Tutto questo cosa ci garantisce? Che la seconda interruzione cadrà:
- o tra una NOP e l'altra (Ritardo 0 cicli)
- o in mezzo ad una NOP (Ritardo 1 ciclo)
Il secondo interrupt ha lo scopo di sistemare questa incertezza: anche in questo caso i timing del tuo programma non sono corretti ma attendo la sistemazione di irqpre prima di chiarire il meccanismo (con quello che sarà il punto 2).
Perdona la logorrea, spero di averti chiarito un po' le idee! ;)
Attendo (attendiamo) nuove!

 

Elder0010

  • Utente
  • **
  • Post: 75
    • http://csdb.dk/scener/?id=22731
  • Gioco Preferito: Rampage
Timing Rasters E Badline
« Risposta #9 il: 19 Marzo 2011, 21:43:40 »
 Logorrea?? Non so davvero come ringraziarti!! La tua spiegazione è chiara e tutte queste info valgono oro :)
 
Credo di aver sistemato irqpre, però ho notato che il tutto va in crash quando arriva il momento di ritornare dal secondo interrupt. Ho provato a spostare un po' le istruzioni, credo che il problema sia dato dal fatto che ripristino $0314 troppo presto :(

Codice: [Seleziona]
;prova doppio interrupt nested

    *=$0801
    include basicline.s

   sei  
   tax
   stx $d020
   stx $d021

   lda #<irqpre
   ldx #>irqpre
   sta $0314
   stx $0315
  
   lda #$01
          sta $d01a   ; Turn on raster interrupts
  
   lda #$34    
   sta $d012
   lda #$1b    
   sta $d011
   lda #$7f
   sta $dc0d
   sta $dd0d
   cli

hold
   jmp hold


;FINO A QUI 20 + X + 7 + 29 cicli.
;ricorda che 0<=X<=7 e X è la
;durata dell'ultima istruzione eseguita
;prima dell'interrupt
;quindi lsr $d019 viene seguita dopo 20+X+7
irqpre  
   lsr $d019; 6
   inc $d012  ; 6
  
   lda #<irq  ;2
   sta $0314  ;4
        
   cli  ;2

;---FINO A QUI MAX 20 CICLI (cosiderato caso peggiore)

   tsx;Trasferisco lo stack pointer in x
   stx $5f;storo x in $5f
  
  ;Aggiungo una serie di nop per "non fare nulla" intanto che
                       ;l'altro interrupt viene eseguito
   nop
   nop
   nop
   nop;4 nop per totale di 8 cicli, sono sicuro in tutti i casi
   ;(considerando anche il caso migliore)

   brk
    
irq
   asl $d019
  
   ldx $5f;carico quello che avevo salvato prima..
   txs;ripristino lo stack pointer
  
   lda #$35   ;Siamo a 35?
  
   ldy #<irqpre;Punto di nuovo al primo interrupt
  
   cmp $d012
   beq start  ;se NO devo saltare un altro ciclo!
start
   sty $0314
   nop
   jsr rasterbars
  
  
  ;rimetto apposto anche il registro $d012
   lda $34
   sta $d012
  
   jmp $ea31
  

rasterbars    
   lda colors
   sta $d020
   sta $d021
  
   ldx #$0b
   dex
   bne *-1
  
   lda #0
   sta $d020
   sta $d021
      
   rts
  


dir       .byte $0
offs      .byte $90

colors
         .byte $01,$07,$05,$03,$07,$02
         .byte $09,$06,$03,$05,$03,$02
         .byte $0e,$03,$03,$0e,$03,$03
         .byte $03,$01,$03,$01,$01,$03
         .byte $01,$01,$01,$03,$01,$01
         .byte $03,$01,$03,$03,$03,$0e
         .byte $03,$03,$0e,$03,$0e,$0e
         .byte $0e,$06,$0e,$0e,$06,$0e
         .byte $06,$06,$06,$06,$06,$06
lda #0 sta $d020 sta $d021

Freshness79

  • Utente
  • **
  • Post: 128
  • Gioco Preferito: Dizzy collection
Timing Rasters E Badline
« Risposta #10 il: 19 Marzo 2011, 22:11:33 »
 Bene le prime 5 istruzioni di irqpre, bene i commenti, male le istruzioni che seguono le prime 5!!!!
Subito dopo la CLI ci sono 7 cicli (0<=x<=7) in uno qualsiasi dei quali può verificarsi il 2° IRQ: non devi mettere istruzioni che non siano delle NOP in quella zona!
Questo essenzialmente per due motivi:
- non avresti la certezza di eseguirle: se l'IRQ avviene prima di TSX, cosa perfettamente plausibile, quell'operazione non verrà mai eseguita.
- se le istruzioni hanno tempi di esecuzione diversi dai famosi due cicli (é il caso di STX che in 0 page vuole 3 cicli), finisce lo scopo del primo interrupt: ti ricordo che con il primo interrupt stiamo riducendo l'incertezza da 0-7 cicli a 0-1.
Quindi via assolutamente TSX e STX: devi trovare un altro modo di ripristinare lo stack alla fine del secondo interrupt.
Il modo più comodo é semplicemente eseguire 6 PLA di seguito.

Elder0010

  • Utente
  • **
  • Post: 75
    • http://csdb.dk/scener/?id=22731
  • Gioco Preferito: Rampage
Timing Rasters E Badline
« Risposta #11 il: 19 Marzo 2011, 22:50:34 »
 
Citazione da: "Freshness79"
... in effetti il 2° interrupt non viene mai chiamato.
Nella routine preirq hai configurato correttamente il secondo IRQ ma ti sei dimenticato di riattivare le interruzioni: quando il 6510 serve un'interruzione imposta lo status flag in modo da mascherare successivi IRQ.
In sostanza prima delle NOP devi inserire una CLI.
A quel punto il 2° interrupt verrà generato tra le NOP ma avrai comunque un'incertezza di 1 ciclo da correggere, hai già visto come fare? Tutto si gioca su un confronto ben mirato su D012.
Infine, importantissimo, dal momento che hai servito due interruzioni una dentro all'altra, lo stack avrà le informazioni di ritorno relative al primo e al secondo IRQ. Quelle al primo ci servono, quelle al secondo no pertanto possono scartate.
Tieni presente che un'interruzione gestita con l'appoggio del kernel ($0314) inserisce 6 byte nello stack: vanno tolti.
Se hai altri dubbi chiedi pure, forza con i fix!
Chiaro il problema del post cli.

Citazione
Tieni presente che un'interruzione gestita con l'appoggio del kernel ($0314) inserisce 6 byte nello stack: vanno tolti.

Quindi la prima volta vengono pushati 6 bytes. La seconda volta altri 6.

Citazione
Infine, importantissimo, dal momento che hai servito due interruzioni una dentro all'altra, lo stack avrà le informazioni di ritorno relative al primo e al secondo IRQ. Quelle al primo ci servono, quelle al secondo no pertanto possono scartate.

Ok, dentro lo stack (che è LIFO) ci sono le info sui due interrupt. Facendo 6 volte PLA di fila tengo nell'accumulatore solo i valori del primo interrupt, e scarto gli altri.

Ho provato a inserire i 6 pla, ma continua a crashare. Se però fermo le interruzioni (sei) e le riabilito (cli) subito prima e subito dopo dei pla, il tutto funziona e sembra stabile!

Incollo la versione SENZA sei e cli prima e dopo i pla:


Codice: [Seleziona]
;prova doppio interrupt nested

    *=$0801
    include basicline.s

   sei  
   tax
   stx $d020
   stx $d021

   lda #<irqpre
   ldx #>irqpre
   sta $0314
   stx $0315
  
   lda #$01
      sta $d01a   ; Turn on raster interrupts
  
   lda #$34    
   sta $d012
   lda #$1b    
   sta $d011
   lda #$7f
   sta $dc0d
   sta $dd0d
   cli

hold
   jmp hold


;FINO A QUI 20 + X + 7 + 29 cicli.
;ricorda che 0<=X<=7 e X è la
;durata dell'ultima istruzione eseguita
;prima dell'interrupt
;quindi lsr $d019 viene seguita dopo 20+X+7
irqpre  
   lsr $d019; 6
   inc $d012  ; 6
  
   lda #<irq  ;2
   sta $0314  ;4
        
   cli  ;2

;---FINO A QUI MAX 20 CICLI (cosiderato caso peggiore)

  
  ;Aggiungo una serie di nop per "non fare nulla" intanto che
           ;l'altro interrupt viene eseguito
   nop
   nop
   nop
   nop;4 nop per totale di 8 cicli, sono sicuro in tutti i casi
   ;(considerando anche il caso migliore)

   brk
    
irq
   asl $d019
  
  
      
   lda #$35   ;Siamo a 35?
  
   ldy #<irqpre;Punto di nuovo al primo interrupt
  
   cmp $d012
   beq start  ;se NO devo saltare un altro ciclo!
start
  
   nop
   jsr rasterbars
  
  ;Tolgo i 6 bytes inseriti nello stack
  ;facendo push nell'accumulatore 6 volte
   pla
   pla
   pla
   pla
   pla
   pla
  
   sty $0314
  
  ;rimetto apposto anche il registro $d012
   lda $34
   sta $d012
  
   jmp $ea31
  

rasterbars    
   lda colors
   sta $d020
   sta $d021
  
   ldx #$0b
   dex
   bne *-1
  
   lda #0
   sta $d020
   sta $d021
      
   rts
  


dir       .byte $0
offs      .byte $90

colors
         .byte $01,$07,$05,$03,$07,$02
         .byte $09,$06,$03,$05,$03,$02
         .byte $0e,$03,$03,$0e,$03,$03
         .byte $03,$01,$03,$01,$01,$03
         .byte $01,$01,$01,$03,$01,$01
         .byte $03,$01,$03,$03,$03,$0e
         .byte $03,$03,$0e,$03,$0e,$0e
         .byte $0e,$06,$0e,$0e,$06,$0e
         .byte $06,$06,$06,$06,$06,$06
lda #0 sta $d020 sta $d021

Freshness79

  • Utente
  • **
  • Post: 128
  • Gioco Preferito: Dizzy collection
Timing Rasters E Badline
« Risposta #12 il: 20 Marzo 2011, 00:46:22 »
 Il codice della prima interruzione é corretto.
Il programma può crashare ma in realtà va nella maggior parte dei casi. Questo comportamento "instabile" é dovuto al fatto che non hai messo degli acknoledge "di sicurezza" nella routine di inizializzazione.
Me ne sono accorto solo ora quindi chiedo venia!
Perché mettere degli acknowledge? Per lavorare a bocce ferme. Se viene generato un IRQ mentre stai inizializzando (le prime righe di codice "coperte" dalla mascheratura SEI) alla riattivazione degli interrupt (CLI) verrà eseguito irqpre ma l'interrupt in questione avrà accumulato un maggior ritardo a causa delle istruzioni nelle quali era rimasto mascherato.
Questo ha il probabile effetto di andare ad impostare il secondo IRQ quando il raster é già arrivato a quella linea: a quel punto il secondo IRQ non viene eseguito e la routine chiude con il BRK.
Ottimo debugger il break! ;)
La soluzione quindi é aggiungere queste tre righe prima della CLI di fine inizializzazione:

LDA $DC0D ; Acknowledge CIA IRQ
LDA $DD0D ; Acknowledge CIA NMI
LSR $D019 ; Acknowledge VIC IRQ

Ora puoi ragionare sulla seconda interruzione!
 

Elder0010

  • Utente
  • **
  • Post: 75
    • http://csdb.dk/scener/?id=22731
  • Gioco Preferito: Rampage
Timing Rasters E Badline
« Risposta #13 il: 20 Marzo 2011, 11:22:50 »
 Ok, ora con le intestazioni corrette va tutto bene anche senza "incartare" con sei e cli i PLA.

Ho fatto un po' di spostamenti e conti nel secondo interrupt, ho pensato questo: se è tutto ok con il 1°interrupt, l'incertezza è 0/1 cicli. E questo si sistema aggiungendo il controllo su $d012. A questo punto, il conto riparte da capo, e ho di nuovo 63 cicli per disegnare la linea. Rifacendo i conti però, mi sono accorto che la mia funzione occupa molti piu cicli!

Codice: [Seleziona]
;prova doppio interrupt nested

    *=$0801
    include basicline.s

   sei  
   tax
   stx $d020
   stx $d021

   lda #<irqpre
   ldx #>irqpre
   sta $0314
   stx $0315
  
   lda #$01
      sta $d01a   ; Turn on raster interrupts
  
   lda #$34    
   sta $d012
   lda #$1b    
   sta $d011
   lda #$7f
   sta $dc0d
   sta $dd0d
  
   LDA $DC0D; Acknowledge CIA IRQ
   LDA $DD0D; Acknowledge CIA NMI
   LSR $D019; Acknowledge VIC IRQ
   cli

hold
   jmp hold


;FINO A QUI 20 + X + 7 + 29 cicli.
;ricorda che 0<=X<=7 e X è la
;durata dell'ultima istruzione eseguita
;prima dell'interrupt
;quindi lsr $d019 viene seguita dopo 20+X+7
irqpre  
   lsr $d019; 6
   inc $d012  ; 6
  
   lda #<irq  ;2
   sta $0314  ;4
        
   cli  ;2

;---FINO A QUI MAX 20 CICLI (cosiderato caso peggiore)

  
  ;Aggiungo una serie di nop per "non fare nulla" intanto che
           ;l'altro interrupt viene eseguito
   nop
   nop
   nop
   nop;4 nop per totale di 8 cicli, sono sicuro in tutti i casi
   ;(considerando anche il caso migliore)

   brk

;Anche qui 20 + X + 7 + 29 cicli.
;Però grazie all'interrupt precedente 0<=X<=1
;In teoria dovrei far entrare la 1° linea bianca
;in 63 cicli  
irq
  ;nel caso peggiore qui siamo a 57 cicli
  ;20+1+7+29 = 57
  
  ;**************************************
  ;* Rientro: precisamente nei 63 cicli *
  ;* infatti 57+2+4 = 63
  ;**************************************
   lda #$35   ;2
   cmp $d012  ;4
   beq start  ;con questo branch allineo l'ultimo
start                  ;ciclo di insicurezza

   jsr rasterbars;6 cicli
        
   asl $d019;spostato  qui dall'inizio interrupt
    ; perchè altrimenti non rientro nei 63 cicli
  
  ;Tolgo i 6 bytes inseriti nello stack
  ;facendo push nell'accumulatore 6 volte
   pla
   pla
   pla
   pla
   pla
   pla
  
   ldy #<irqpre;Punto di nuovo al primo interrupt
   sty $0314
  
  ;rimetto apposto anche il registro $d012
   lda $34
   sta $d012
  
   jmp $ea31
  

rasterbars    
  
   lda colors;2
   sta $d020;4
   sta $d021;4
  
   ldx #$0b;3 + 11*4 = 47
   dex;2
   bne *-1;2
  ;fino a qui siamo a 6+2+4+4+47 = 63!    
  
   lda #0    ;2
   sta $d020 ;4
   sta $d021 ;4 come faccio con questi 10 cicli in piu'?
      
   rts
  


dir       .byte $0
offs      .byte $90

colors
         .byte $01,$07,$05,$03,$07,$02
         .byte $09,$06,$03,$05,$03,$02
         .byte $0e,$03,$03,$0e,$03,$03
         .byte $03,$01,$03,$01,$01,$03
         .byte $01,$01,$01,$03,$01,$01
         .byte $03,$01,$03,$03,$03,$0e
         .byte $03,$03,$0e,$03,$0e,$0e
         .byte $0e,$06,$0e,$0e,$06,$0e
         .byte $06,$06,$06,$06,$06,$06
lda #0 sta $d020 sta $d021

Roberto

  • Administrator
  • Utente
  • *****
  • Post: 2411
    • https://ready64.org
  • Gioco Preferito: Impossible Mission
Timing Rasters E Badline
« Risposta #14 il: 20 Marzo 2011, 13:22:46 »
 
Citazione da: "Elder0010"
In riferimento al codice di Ian Coog:
http://ready64.org/smf/index.php?topic=1837.0
(Breve) Nota di Servizio: ho aggiunto il link ad inizio discussione a favore di quanti, privi di facoltà extransesoriali quali preveggenza e divinazione, avessero incontrato problemi nel rintracciare la discussione di riferimento.
Per collaborare, segnalare un errore (o qualsiasi altra comunicazione importante) utilizzare la pagina dei contatti:
https://ready64.org/informazioni/contatti.php