Ready64 Forum
Commodore 64 => Programmazione, Grafica e Musica => Topic aperto da: Elder0010 - 14 Marzo 2011, 20:21:07
-
In riferimento al codice di Ian Coog:
http://ready64.org/smf/index.php?topic=1837 - aggiunto link
; 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 :)
-
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:
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.
*=$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
-
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 :)
-
...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!
-
ahha bocciato alla grande :lol:
sfida accettata! Ora ci penso su e vedo cosa riesco a combinare!!
-
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 :(.
;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
-
... 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!
-
Ho studiato un po' del tuo codice sul forum + la routine di fungus su
codebase (http://codebase64.org/doku.php?id=base:double_irq).
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 :)
;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
-
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)
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!
-
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 :(
;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
-
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.
-
... 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.
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.
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:
;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
-
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!
-
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!
;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
-
In riferimento al codice di Ian Coog:
http://ready64.org/smf/index.php?topic=1837.0 (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.
-
colpa mia, mi è sfuggito. grazie!
-
Bene... a conferma che l'argomento é di una certa complessità, sono qui a ritrattare le mie stesse dichiarazioni!
Ieri ti stavo per rispondere ma mi sono bloccato un attimo perché c'era qualcosa che non tornava: una delle affermazioni che avevo fatto non coincideva con la realtà.
Ho dovuto ravanare in rete e fare alcune prove prima di tornare a risponderti con ragionevole cognizione di causa, e ti ringrazio perché questo thread mi ha dato lo spunto per chiarire gli ultimi dubbi che avevo su questa tecnica.
Ho sbagliato a dirti che un IRQ richiamato tra un istruzione e l'altra sia immediatamente eseguito dalla cpu: non é assolutamente così.
La realtà é che perché un IRQ sia eseguito subito dopo una determinata istruzione, é necessario che sia segnalato almeno due cicli prima del termine della stessa (fonte: Stable Raster - Makela (http://www.antimon.org/dl/c64/code/stable.txt)).
Questo comporta che il tempo minimo di ritardo con il quale viene eseguito un IRQ é esattamente di 2 cicli (e non di 0 come ti avevo detto).
Faccio un esempio:
posso scomporre il seguente codice:
NOP ;2 cicli (prima nop)
NOP ;2 cicli (seconda nop)
nei 4 cicli di cui si compone
0 - NOP1
1 - NOP1
2 - NOP2
3 - NOP2
4... (fine del 2° NOP)
Se l'irq capita in 0, all'inizio della prima NOP, verrà servito in 2: esattamente 2 cicli più tardi.
Se l'irq capita in 1, cioé in mezzo alla prima NOP, manca solo 1 ciclo alla fine della stessa perciò l'IRQ non può essere eseguito in 2 ma sarà necessario attendere la fine della seconda NOP: l'IRQ verrà eseguito in 4 per un ritardo totale di 3 cicli di ritardo.
Il discorso si può estendere anche alle istruzioni più lunghe, alla fine si ottiene che il campo di variabilità del ritardo di esecuzione di un interrupt dovuto all'istruzione correntemente eseguita va dai 2 ai 9 cicli.
Alla luce di questo cambiano i timing delle routine di cui abbiamo parlato nel thread: in particolare quella del primo interrupt dev'essere ulteriormente accorciata perché il massimo ritardo accumulabile é 9 (max ritardo di istruzione)+7 (istruzione IRQ) + 29 (routine del kernel) = 45. La routine quindi ha al massimo 18 cicli (45+18=63) per fare l'acknowledge dell'irq, l'aggiornamento di $D012 e l'aggiornamento di $0314.
Può sembrare poco tempo ma é ancora possibile farci stare tutto con un semplice accorgimento, questa volta per semplicità ti propongo il codice:
...
...
irqpre
lda #<secirq;2 (36+2/9)
sta $0314;4
sta $d019;4
inc $d012 ;6
cli ;2
nop ;2 gli IRQ inizieranno qua ma questo nop verrà sempre eseguito
nop ;2
nop ;2
nop ;2
nop ;2
brk ; Qua non ci si arriva mai!
align 2
*=*+1; Mi assicuro che l'indirizzo sia dispari
; così posso usare il valore per l'ack
secirq
....
....
Ora per il secondo interrupt tieni presente che la routine verrà eseguita con un ritardo di 2/3+7+29=38/39 cicli.
Dovrai fare in modo di posizionare una LDA $d012 o una CMP $d012 (a seconda di come preferisci strutturare la cosa) in modo tale che il suo ultimo ciclo, il 4°, venga ad essere il 63° della 2° riga/1° della 3° riga.
A quel punto, se risulti essere ancora nella 2° riga, un semplice branch all'istruzione successiva ti permetterà di eliminare l'ultimo ciclo di incertezza.
Se hai bisogno "fai un fischio"!
-
*=*+1; Mi assicuro che l'indirizzo sia dispari
; così posso usare il valore per l'ack
Questo significa: prendi la locazione corrente di memoria e skip di 1 posizione? Se si, come fa a rendermi sicuro che l'indirizzo sia dispari? Se mi trovassi in un indirizzo pari + 1 = dispari. Se fossi in un dispari + 1 = di nuovo pari.
Perdona la mia (somma) ignoranza, non capisco che relazione ha con l'ack :(
Apparte questo, ho provato a sistemare il codice! Ora in teoria dovrebbe essere stabile. Ho pensato che al momento di eseguire il salto jsr rasterbars, il conto dei cicli si resetta, e mi trovo il raster allineato.
Però, per saltare, caricare l'accumulatore ecc ecc, servono altri cicli, e infatti la rasterline bianca non è allineata con il bordo sx dello schermo. Come fare? aspettare altri 63 cicli e eseguire gli sta $d020 / sta $d021 in modo da terminare esattamente al 63° ciclo successivo?
La situazione sarebbe quindi questa:
irqpre -> ci assicura il ritardo su irq
irq -> siamo sicuri sul ritardo, possiamo fare un conto sicuro: raster stabile.
raster stabile -> per avere una linea completa e allineata, bisogna fare in modo che l'ultimo sta $d021 termini esattamente al 63°esimo ciclo. Si tratta quindi di ritardare fino all'ultimo!
spero di averci capito qualcosa :) incollo solo la parte centrale del programma per non floodare
;FINO A QUI X + 7 + 29 cicli.
;ricorda che 2<=X<=9 e X è la
;durata dell'ultima istruzione eseguita
;prima dell'interrupt
;quindi lsr $d019 viene seguita dopo 29+X+7
;caso peggiore 45 cicli, ne ho solo 18
irqpre
lda #<irq ;2
sta $0314 ;4
sta $d019;4 rispetto ad una inc scendo di 2 cicli
inc $d012 ;6
cli ;2
;---FINO A QUI MAX 18 CICLI (cosiderato caso peggiore)
;Aggiungo una serie di nop per "non fare nulla" intanto che
;l'altro interrupt viene eseguito
nop
nop
nop
nop
nop;5 nop per totale di 10 cicli, sono sicuro in tutti i casi
;(considerando anche il caso migliore)
brk
*=*+1;
;la routine verrà eseguita con un ritardo di 2/3+7+29=38/39 cicli.
irq
nop ;41
nop ;43
nop ;45
nop ;47
nop ;49
nop ;51
asl $d019;6 = 57
lda #$35 ;2 = 59
cmp $d012 ;4 =63
beq start ;con questo branch allineo l'ultimo
start ;ciclo di insicurezza
;In teoria qui il conto si resetta a 0 cicli
;perche ho stabilizzato il tutto
jsr rasterbars;6 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
;TODO: ritardare in modo da avere gli sta $d020 / 21
;allineati al 63esimo ciclo (?)
lda colors;2
sta $d020;4
sta $d021;4
ldx #$0a
dex
bne *-1
lda #0
sta $d020
sta $d021
rts
-
Rispondo per punti:
1)
*=*+1 significa in effetti "incrementa di uno l'attuale indirizzo". La garanzia che sia dispari ce l'ho perché ho fatto precedere un align 2 (allinea l'indirizzo a multipli di 2).
Perché serve dispari? Perché per effettuare l'acknowledge di interrupt generati dal raggiungimento di un raster é necessario scrivere un 1 nel bit 0 di $d019. Ti ricordo che $D019 é strutturato in questo modo:
Bit 0
RST (Interrupt generato dal raggiungimento di un raster)
Read: 1 se c'é un interrupt da servire
Write: 1 per dare l'ack
Bit 1
MBC (Interrupt generato da collisioni sprite/sfondo)
Read: 1 se c'é un interrupt da servire
Write: 1 per dare l'ack
Bit 2
MMC (Interrupt generato da collisioni sprite/sprite)
Read: 1 se c'é un interrupt da servire
Write: 1 per dare l'ack
Bit 3
LP (Interrupt triggerato da una lightpen)
Read: 1 se c'é un interrupt da servire
Write: 1 per dare l'ack
2)
Ho trovato una piccola svista nel tuo codice. Quando alla fine dell'interruzione vai a reimpostare il raster $34, l'istruzione giusta é LDA #$34!! L'hai indicato senza la "#" e quindi il processore va ad impostare l'accumulatore col valore letto nella posizione $34. ;)
3)
Dal momento che nel secondo interrupt sei partito a contare usando il worst case, dovresti arrivare al cmp #$d012 con 64, cioé col primo ciclo della riga successiva: solo in questo modo puoi usare quell'istruzione come discriminante. Se infatti il secondo irq verrà eseguito con un ritardo base di 38 la cmp sara ancora nella riga $35, il confronto andrà a buon fine e ti troverai in start che sei nel 3° ciclo della riga $36 (beq con salto = 3 cicli); se invece il secondo irq partirà con ritardo 39 la cmp sarà già nella riga successiva, il confronto andrà male ma ti troverai in start con lo stesso ritardo di 3 (1 dovuto al ritardo di base + 2 della beq senza salto).
4)
Ti consiglio di usare costantemente i debug border di vice per avere il polso della situazione: solo con quelli puoi avere un feedback visivo sull'effettiva stabilità della routine che stai scrivendo. Prova a vedere il programma così com'é adesso e dopo gli aggiustamenti necessari.
5)
Per il resto é sostanzialmente corretta la tua osservazione: una volta raggiunta la sincronizzazione della cpu con i raster, devi organizzare il tuo codice in modo da "far capitare le cose nel momento giusto"! Puoi ad esempio cambiare il colore del bordo al ciclo 63 di tutte le righe per creare delle linee orizzontali. E' chiaro che per arrivare al ciclo 63 di ciascuna riga dovrai far fare qualcosa al processore... al limite fargli perdere tempo!
In realtà si può cambiare il colore di sfondo anche più volte in una riga creando i famosi raster split; o ancora provare ad aprire i bordi laterali (cosa che si può fare unicamente con un raster stabile).
6)
Comincia a pensare alla maledizione delle badline... :doh: non sono sparite eh!
-
Ok, grazie per l'ennesima spiegazione! é tutto chiaro. Ho aggiustato un po i timing, e ora mi sembra stabile!!
Ho visto il codice con il bordo in modalità debug, e ora è perfettamente fermo! è sparito anche il problema del flickering sui tasti premuti.
Ho contato i cicli in modo che il termine dell'istruzione sta $d021 (dentro la routine rasterbars) cada esattamente al 63°esimo ciclo.
Cosi facendo si avrà una linea che partirà precisamente alla successiva linea raster (quindi la #$36!). Inoltre poi ho "perso tempo" in modo da far terminare la rts al 63°esimo ciclo della linea #$36.
Che te ne pare? se non vedi errori comincio a lavorare un po sulle badlines :)
;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 X + 7 + 29 cicli.
;ricorda che 2<=X<=9 e X è la
;durata dell'ultima istruzione eseguita
;prima dell'interrupt
;quindi lsr $d019 viene seguita dopo 29+X+7
;caso peggiore 45 cicli, ne ho solo 18
irqpre
lda #<irq ;2
sta $0314 ;4
sta $d019;4 rispetto ad una inc scendo di 2 cicli
inc $d012 ;6
cli ;2
;---FINO A QUI MAX 18 CICLI (cosiderato caso peggiore)
;Aggiungo una serie di nop per "non fare nulla" intanto che
;l'altro interrupt viene eseguito
nop
nop
nop
nop
nop;5 nop per totale di 10 cicli, sono sicuro in tutti i casi
;(considerando anche il caso migliore)
brk
align 2
*=*+1;
;la routine verrà eseguita con un ritardo di 2/3+7+29=38/39 cicli.
irq
nop;41
nop;43
nop;45
nop;47
nop;49
bit $24;52
asl $d019;6 = 58
lda #$35 ;2 = 60
cmp $d012 ;4 = 64 / 1° ciclo
beq start ;con questo branch allineo l'ultimo
start ;ciclo di insicurezza
;In teoria qui il conto si resetta a 0 cicli
;perche ho stabilizzato il tutto
jsr rasterbars;6 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
;ora devo perdere tempo in modo da esaurire i 63-8 = 55 cicli
;**********************************
;*Questo blocco sono 4*12 + 2 = 50
;**********************************
ldx #$0a;2
dex;2
bne *-1;2
nop
bit $24;55 !!
;Finisco di disegnare la riga proprio al 63°esimo ciclo
sta $d020;4
sta $d021;4
;Ora devo aspettare altri 63 cicli prima di
;resettare il colore del background
ldx #$0a
dex
bne *-1
nop
;e siamo a 47
lda #$0;2
sta $d020;4
sta $d021;4
rts;6 - 63 tondi
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
-
Ok, hai realizzato la tua prima raster routine perfettamente stabile!
Puoi anche levare il jmp hold e mettere un semplice rts: la stabilità rimane anche se lavori in basic e fai altre cose. Solo se premi restore noterai del movimento, perché viene generato un nmi. Ci sarebbe il modo di eliminare pure quello ma per il momento sorvoliamo.
Il raster adesso é stabile comunque, senza ombra di dubbio.
I conti che hai fatto per i cicli di ritardo, invece, sono un po' meno giusti, ti propongo lo spezzone di codice corretto. Dai un'occhiata e regolati per le eventuali righe successive.
cmp $d012 ;Qua o siamo a 0 o a 1
beq start ;Qua aggiungiamo 3 oppure 2 cicli
start ;3 QUA SIAMO SEMPRE NEL 3° CICLO DELLA 3° RIGA
;(In teoria qui il conto si resetta a 0 cicli) ?? :) IN PRATICA NO!
;ho (stabilizzato)-> SINCRONIZZATO il tutto
jsr rasterbars;9
;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;13
;ora devo perdere tempo in modo da esaurire i 63-(13-4) = 46 cicli
ldx #$09;2 2+2+(x-1)*5+2 => 4+8*5+2 = 46
dex ;2
bne *-1 ;2/3
;Finisco di disegnare la riga proprio al 63°esimo ciclo
sta $d020;(63) Fine riga
sta $d021;4° ciclo riga successiva
;Ora devo aspettare altri 63-4 cicli prima di
;resettare il colore del background
ldx #$0a;51 stessa formula di sopra
dex
bne *-1
nop; 51+4+2=57
;e siamo a... 57
lda #$0 ;59
sta $d020;(63) fine riga
sta $d021;4° ciclo nuova riga
rts;6 - 10... comunque tondi ma non 63!;)
-
Ecco qua: chiedo scusa per la rozzezza del codice (sarebbe stato meglio mettere tutto in un loop e fare riferimento a una timing table per i delays..) però cosi' è stato piu' facile fare le prove. sono andato avanti finchè non ho incontrato una badline, e ho cambiato il timing value. poi ho disegnato un ulteriore riga "standard".
;prova doppio interrupt nested
*=$0801
include basicline.s
sei
jsr $e544;screen clear
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 X + 7 + 29 cicli.
;ricorda che 2<=X<=9 e X è la
;durata dell'ultima istruzione eseguita
;prima dell'interrupt
;quindi lsr $d019 viene seguita dopo 29+X+7
;caso peggiore 45 cicli, ne ho solo 18
irqpre
lda #<irq ;2
sta $0314 ;4
sta $d019;4 rispetto ad una inc scendo di 2 cicli
inc $d012 ;6
cli ;2
;---FINO A QUI MAX 18 CICLI (cosiderato caso peggiore)
;Aggiungo una serie di nop per "non fare nulla" intanto che
;l'altro interrupt viene eseguito
nop
nop
nop
nop
nop;5 nop per totale di 10 cicli, sono sicuro in tutti i casi
;(considerando anche il caso migliore)
brk
align 2
*=*+1;
;la routine verrà eseguita con un ritardo di 2/3+7+29=38/39 cicli.
irq
nop ;41
nop ;43
nop ;45
nop ;47
nop ;49
bit $24;52
asl $d019;6 = 58
lda #$35 ;2 = 60
cmp $d012 ;4 = 64 - siamo a 0 o 1 cicli
beq start ;3 con questo branch allineo l'ultimo
start ;ciclo di insicurezza
;QUI SIAMO SICURAMENTE a 3.
jsr rasterbars;9
;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;13
;ora devo perdere tempo in modo da esaurire i 63-(13-4) = 46 cicli
ldx #$09;2 2+2+(x-1)*5+2 => 4+8*5+2 = 46
dex ;2
bne *-1;2/3
;Finisco di disegnare la riga proprio al 63°esimo ciclo
sta $d020;(63) Fine riga
sta $d021;4° ciclo riga successiva
;NUOVA LINEA!
;Ora devo aspettare altri 63-4 cicli prima di
;resettare il colore del background
ldx #$0a;51 stessa formula di sopra
dex
bne *-1
; 51+4=55
;e siamo a... 55
lda colors+2;59
sta $d020;(63) fine riga
sta $d021;4° ciclo nuova riga
;NUOVA LINEA! - mancano 59 cicli
ldx #$0a;51 stessa formula di sopra
dex
bne *-1
lda colors+3
sta $d020
sta $d021
;NUOVA LINEA! - mancano 59 cicli
ldx #$0a;51 stessa formula di sopra
dex
bne *-1
lda colors+4;59
sta $d020;(63) fine riga
sta $d021;4° ciclo nuova riga
;NUOVA LINEA! - mancano 59 cicli
ldx #$0a;51 stessa formula di sopra
dex
bne *-1
lda colors+5
sta $d020;
sta $d021;4° ciclo nuova riga BADLINE
;NUOVA LINEA! BADLINE!! siccome l'ultima istruzione eseguita è una STA allora
; ho solo 22 cicli, di cui 4 ne ho gia consumati. ne restano 18
ldx #$01;6
dex
bne *-1
nop
lda colors+6;10
sta $d020;14
sta $d021;22
;NUOVA LINEA! (non badline)
ldx #$0a
dex
bne *-1
lda colors+5
sta $d020
sta $d021
nop;allineo timings!
ldx #$0a;51 stessa formula di sopra
dex
bne *-1
lda #$0
sta $d020
sta $d021
rts
colors
.byte $06,$02,$03,$04,$05,$08
.byte $07,$08,$04,$01,$00,$06
.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
-
Complimenti per il sorgente e per come ci sei arrivato!
Leggere la discussione è stato illuminante!
-
il merito è tutto di freshness e delle sue spiegazioni!
-
E' veramente preparatissimo!
-
Vi ringrazio molto ma i meriti vanno tutti alle persone che, con notevole dovizia di particolari, hanno documentato l'hardware.
Io, come molti altri, mi sono limitato a leggere, ad applicare e a riportare.
Vi ricordo le due bibbie del 64:
- VIC-article
- 64DOC
Non metto i link ma basta una "googolata"... Il primo dei due in particolare consente di capire a fondo il comparto grafico del 64.
Non so se esistano documenti altrettanto dettagliati sul SID: magari iAN potrebbe conoscerne.
Ed ho sempre trovato informazioni spezzettate anche sui 2 CIA.
Forza Elder, attendo un raster più alto: almeno una 40ina di righe!
;)