Ready64 Forum
Commodore 64 => Programmazione, Grafica e Musica => Topic aperto da: Freshness79 - 28 Aprile 2009, 01:14:42
-
Se ne parlava l'altro giorno in chat e visto che non avevo mai provato a ricreare questo effetto, stasera ho provato a scrivere un paio di righe.
L'effetto DMA delay, per chi non ne fosse al corrente, si basa sulla creazione "artificiosa" di una bad line durante la visualizzazione di una linea.
A seconda del momento in cui si crea la badline, il counter interno del VIC sarà soggetto ad un diverso offset: questo 'difetto' nell'allineamento, unito all'uso dello scrolling fine $D016, permette maggiore libertà nel movimento orizzontale di tutto lo schermo. Nel semplice esempio che propongo in effetti nessun carattere viene cambiato o spostato nella mappa dello schermo: tutto il movimento é creato con i registri del VIC.
Segue come sempre il source:
NOPopcode = $EA
temp = $FE
setDEN = $FA
rastline = $FB
sinuspos = $FD
*=$0801
word eoprg
word 2009
byte $9E,[intro]d
petc ":rem dma delay"
byte 0
eoprg
word 0
*=$0840
intro
lda #$10 ; Attivazione schermo (D011 - bit DEN)
sta setDEN
lda #$2e ; Linea $30 (-2 per la stabilizzazione)
sta rastline
lda #$00 ; Resetta la posizione della sinus table
sta sinuspos
jsr initIRQ ; Inizializzazione raster IRQ
cli ; Interrupt attivati
rts
; ***************************************************
; * Routine di sincronizzazione a doppio raster IRQ *
; ***************************************************
; La prima chiamata IRQ é su JMP, quindi l'incertezza é di 1-3 cicli
; Il primo handler permette di ridurla a 1-2 cicli: IRQ arriva sulla NOP
; Il secondo handler infine grazie ad un confronto a fine raster elimina
; l'ultima possibile incertezza
fstirq lsr $d019 ; 6 + (36 Kernal IRQ) + (da 2 a 4 JMP)
inc $d012 ; 6 interrupt al prossimo raster
lda #<secirq ; 2 reimposto il vettore IRQ perché punti
sta $0314 ; 4 al secondo handler
cli ; 2 attivo gli interrupt
tsx ; 2
stx temp ; 3
nop ; 2 (63-65) <= IRQ
nop ; 2 (65-67) <= IRQ
brk ; Qua non ci si arriva mai, lascio BRK per test
secirq ldx sinuspos ; 3 + (36 Kernal IRQ) + (da 2 a 3 NOP)
lda sinushigh,x ; 4 Carico la parte più significativa dello spostamento
lsr ; 2 orizzontale, nel carry metto il bit meno significativo
sta brnch+1 ; 4 uso il resto per creare un displacement
lda $d012 ; 4 Stabilizzazione raster
nop ; 2w
nop ; 2w
bit $d012 ; 4 se il ritardo dovuto alla NOP era 1
beq synced ; 2/3 effettuo un branch per allinearmi
; Routine di delay della prima badline
synced bcc brnch ; questo branch serve per saltare un ciclo
brnch bpl * ; con questo si saltano 2*N cicli
ds $13,NOPopcode; (0-38 cicli) 19xNOP (la nop impiega 2 cicli)
lda setDEN ;
sta $d011 ; Attivazione badline
inc sinuspos ; incrementa il pointer e setta 06 il colore del garbage (INC = $E6)
lda sinuslow,x ; Parte meno significativa dello spostamento
sta $d016 ; orizzontale - scrolling fine
lda #$00 ; reset
sta $d011 ; del bit DEN nel registro $D011
lda rastline
sta $d012 ; ripristino del corretto raster compare
ldx #<fstirq
stx $0314 ; ripristino il vecchio IRQ pointer
ldx temp ;
txs ; ripristino dello stack pointer
lsr $d019 ; Acknowledge del raster IRQ
cli ; Interrupt nuovamente attivi
jmp $ea31 ; Salto alla normale routine di interruzione
; ************
; * Init IRQ *
; ************
;
; Disattivazione dell'interrupt standard,
; Impostazione della prima rasterline e dell'indirizzo
; del primo handler della routine di interrupt
; attivazione dei raster interrupt
initIRQ
sei
lda #$7f
sta $dc0d
sta $dd0d
lda $dd0c
lda $dc0c
lda #$10
sta $d011
lda $fb
sta $d012
lda #<fstirq
sta $0314
lda #>fstirq
sta $0315
lda #$01
sta $d01a
lsr $d019
rts
*=$0b00
sinuslow
.byte $07,$04,$00,$04,$00,$04,$00,$04,$00,$05,$01,$05,$01,$06,$02,$06
.byte $03,$07,$04,$00,$05,$01,$06,$02,$07,$04,$01,$06,$03,$00,$05,$02
.byte $07,$04,$02,$07,$05,$02,$00,$06,$03,$01,$07,$05,$03,$01,$00,$06
.byte $05,$03,$02,$01,$07,$06,$05,$04,$04,$03,$02,$02,$01,$01,$01,$01
.byte $00,$01,$01,$01,$01,$02,$02,$03,$04,$04,$05,$06,$07,$01,$02,$03
.byte $05,$06,$00,$01,$03,$05,$07,$01,$03,$06,$00,$02,$05,$07,$02,$04
.byte $07,$02,$05,$00,$03,$06,$01,$04,$07,$02,$06,$01,$05,$00,$04,$07
.byte $03,$06,$02,$06,$01,$05,$01,$05,$00,$04,$00,$04,$00,$04,$00,$04
.byte $07,$03,$07,$03,$07,$03,$07,$03,$07,$02,$06,$02,$06,$01,$05,$01
.byte $04,$00,$03,$07,$02,$06,$01,$05,$00,$03,$06,$01,$04,$07,$02,$05
.byte $00,$03,$05,$00,$02,$05,$07,$01,$04,$06,$00,$02,$04,$06,$07,$01
.byte $02,$04,$05,$06,$00,$01,$02,$03,$03,$04,$05,$05,$06,$06,$06,$06
.byte $06,$06,$06,$06,$06,$05,$05,$04,$03,$03,$02,$01,$00,$06,$05,$04
.byte $02,$01,$07,$06,$04,$02,$00,$06,$04,$01,$07,$05,$02,$00,$05,$03
.byte $00,$05,$02,$07,$04,$01,$06,$03,$00,$05,$01,$06,$02,$07,$03,$00
.byte $04,$01,$05,$01,$06,$02,$06,$02,$07,$03,$07,$03,$07,$03,$07,$03
sinushigh
.byte $14,$14,$14,$15,$15,$16,$16,$17,$17,$18,$18,$19,$19,$1A,$1A,$1B
.byte $1B,$1C,$1C,$1C,$1D,$1D,$1E,$1E,$1F,$1F,$1F,$20,$20,$20,$21,$21
.byte $22,$22,$22,$23,$23,$23,$23,$24,$24,$24,$25,$25,$25,$25,$25,$26
.byte $26,$26,$26,$26,$27,$27,$27,$27,$27,$27,$27,$27,$27,$27,$27,$27
.byte $27,$27,$27,$27,$27,$27,$27,$27,$27,$27,$27,$27,$27,$26,$26,$26
.byte $26,$26,$25,$25,$25,$25,$25,$24,$24,$24,$23,$23,$23,$23,$22,$22
.byte $22,$21,$21,$20,$20,$20,$1F,$1F,$1F,$1E,$1E,$1D,$1D,$1C,$1C,$1C
.byte $1B,$1B,$1A,$1A,$19,$19,$18,$18,$17,$17,$16,$16,$15,$15,$14,$14
.byte $14,$13,$13,$12,$12,$11,$11,$10,$10,$0F,$0F,$0E,$0E,$0D,$0D,$0C
.byte $0C,$0B,$0B,$0B,$0A,$0A,$09,$09,$08,$08,$08,$07,$07,$07,$06,$06
.byte $05,$05,$05,$04,$04,$04,$04,$03,$03,$03,$02,$02,$02,$02,$02,$01
.byte $01,$01,$01,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$01,$01,$01
.byte $01,$01,$02,$02,$02,$02,$02,$03,$03,$03,$04,$04,$04,$04,$05,$05
.byte $05,$06,$06,$07,$07,$07,$08,$08,$08,$09,$09,$0A,$0A,$0B,$0B,$0B
.byte $0C,$0C,$0D,$0D,$0E,$0E,$0F,$0F,$10,$10,$11,$11,$12,$12,$13,$13
-
Non funziona nulla ne' in vice 2.19 ne' in hoxs. Schermo spento e null'altro.
Hai per caso provato su C64 e ti funziona? se si, siamo di fronte ad un altro baco di emulazione :)
Edit: funziona solo in vice 2.1, come abbiamo verificato in chat. Essendo stato corretto un baco di emulazione dalla 2.1.5, si puo' solo dedurre che cosi' com'e' questa routine si basa su un'assunzione errata.
Andrebbe provato su c64 reale prima di stabilire dove stia l'errore.
-
Ok, in effetti il codice andava corretto: ora dovrebbe andare meglio.
NOPopcode = $EA
temp = $FE
setDEN = $FA
rastline = $FB
sinuspos = $FD
*=$0801
word eoprg
word 2009
byte $9E,[intro]d
petc ":rem dma delay"
byte 0
eoprg
word 0
*=$0840
intro
lda #$18 ; Attivazione schermo (D011 - bit DEN)
sta setDEN
lda #$2e ; Linea $30 (-2 per la stabilizzazione)
sta rastline
lda #$00 ; Resetta la posizione della sinus table
sta sinuspos
jsr initIRQ ; Inizializzazione raster IRQ
cli ; Interrupt attivati
rts
; ***************************************************
; * Routine di sincronizzazione a doppio raster IRQ *
; ***************************************************
; La prima chiamata IRQ é su JMP, quindi l'incertezza é di 1-3 cicli
; Il primo handler permette di ridurla a 1-2 cicli: IRQ arriva sulla NOP
; Il secondo handler infine grazie ad un confronto a fine raster elimina
; l'ultima possibile incertezza
fstirq lsr $d019 ; 6 + (36 Kernal IRQ) + (da 2 a 4 JMP)
inc $d012 ; 6 interrupt al prossimo raster
lda #<secirq ; 2 reimposto il vettore IRQ perché punti
sta $0314 ; 4 al secondo handler
cli ; 2 attivo gli interrupt
nop ; 2 (63-65) <= IRQ
nop ; 2 (65-67) <= IRQ
nop
nop
nop
nop
brk ; Qua non ci si arriva mai, lascio BRK per test
secirq ldx sinuspos ; 3 + (36 Kernal IRQ) + (da 2 a 3 NOP)
lda sinushigh,x ; 4 Carico la parte più significativa dello spostamento
lsr ; 2 orizzontale, nel carry metto il bit meno significativo
sta brnch+1 ; 4 uso il resto per creare un displacement
lda $d012 ; 4 Stabilizzazione raster
nop ; 2w
nop ; 2w
bit $d012 ; 4 se il ritardo dovuto alla NOP era 1
beq synced ; 2/3 effettuo un branch per allinearmi
; Routine di delay della prima badline
synced bcc brnch ; questo branch serve per saltare un ciclo
brnch bpl * ; con questo si saltano 2*N cicli
ds $13,NOPopcode; (0-38 cicli) 19xNOP (la nop impiega 2 cicli)
lda setDEN ;
sta $d011 ; Attivazione badline
inc sinuspos ; incrementa il pointer e setta 06 il colore del garbage (INC = $E6)
lda sinuslow,x ; Parte meno significativa dello spostamento
sta $d016 ; orizzontale - scrolling fine
lda rastline
sta $d012 ; ripristino del corretto raster compare
ldx #<fstirq
stx $0314 ; ripristino il vecchio IRQ pointer
tsx
txa
clc
adc #$06
tax
txs ; ripristino dello stack pointer
lsr $d019 ; Acknowledge del raster IRQ
cli ; Interrupt nuovamente attivi
inc $ffff
inc $ffff
inc $ffff
inc $ffff
inc $ffff
inc $ffff
inc $ffff
inc $ffff
inc $ffff
inc $ffff
inc $ffff
inc $ffff
inc $ffff
inc $ffff
inc $ffff
inc $ffff
inc $ffff
inc $ffff
inc $ffff
inc $ffff
inc $ffff
inc $ffff
inc $ffff
inc $ffff
lda #$00 ; reset
sta $d011 ; del bit DEN nel registro $D011
jmp $ea31 ; Salto alla normale routine di interruzione
; ************
; * Init IRQ *
; ************
;
; Disattivazione dell'interrupt standard,
; Impostazione della prima rasterline e dell'indirizzo
; del primo handler della routine di interrupt
; attivazione dei raster interrupt
initIRQ
sei
lda #$7f
sta $dc0d
sta $dd0d
lda $dd0c
lda $dc0c
lda #$00
sta $d011
lda $fb
sta $d012
lda #<fstirq
sta $0314
lda #>fstirq
sta $0315
lda #$01
sta $d01a
; lsr $d019
rts
*=$0b00
sinuslow
.byte $07,$04,$00,$04,$00,$04,$00,$04,$00,$05,$01,$05,$01,$06,$02,$06
.byte $03,$07,$04,$00,$05,$01,$06,$02,$07,$04,$01,$06,$03,$00,$05,$02
.byte $07,$04,$02,$07,$05,$02,$00,$06,$03,$01,$07,$05,$03,$01,$00,$06
.byte $05,$03,$02,$01,$07,$06,$05,$04,$04,$03,$02,$02,$01,$01,$01,$01
.byte $00,$01,$01,$01,$01,$02,$02,$03,$04,$04,$05,$06,$07,$01,$02,$03
.byte $05,$06,$00,$01,$03,$05,$07,$01,$03,$06,$00,$02,$05,$07,$02,$04
.byte $07,$02,$05,$00,$03,$06,$01,$04,$07,$02,$06,$01,$05,$00,$04,$07
.byte $03,$06,$02,$06,$01,$05,$01,$05,$00,$04,$00,$04,$00,$04,$00,$04
.byte $07,$03,$07,$03,$07,$03,$07,$03,$07,$02,$06,$02,$06,$01,$05,$01
.byte $04,$00,$03,$07,$02,$06,$01,$05,$00,$03,$06,$01,$04,$07,$02,$05
.byte $00,$03,$05,$00,$02,$05,$07,$01,$04,$06,$00,$02,$04,$06,$07,$01
.byte $02,$04,$05,$06,$00,$01,$02,$03,$03,$04,$05,$05,$06,$06,$06,$06
.byte $06,$06,$06,$06,$06,$05,$05,$04,$03,$03,$02,$01,$00,$06,$05,$04
.byte $02,$01,$07,$06,$04,$02,$00,$06,$04,$01,$07,$05,$02,$00,$05,$03
.byte $00,$05,$02,$07,$04,$01,$06,$03,$00,$05,$01,$06,$02,$07,$03,$00
.byte $04,$01,$05,$01,$06,$02,$06,$02,$07,$03,$07,$03,$07,$03,$07,$03
sinushigh
.byte $14,$14,$14,$15,$15,$16,$16,$17,$17,$18,$18,$19,$19,$1A,$1A,$1B
.byte $1B,$1C,$1C,$1C,$1D,$1D,$1E,$1E,$1F,$1F,$1F,$20,$20,$20,$21,$21
.byte $22,$22,$22,$23,$23,$23,$23,$24,$24,$24,$25,$25,$25,$25,$25,$26
.byte $26,$26,$26,$26,$27,$27,$27,$27,$27,$27,$27,$27,$27,$27,$27,$27
.byte $27,$27,$27,$27,$27,$27,$27,$27,$27,$27,$27,$27,$27,$26,$26,$26
.byte $26,$26,$25,$25,$25,$25,$25,$24,$24,$24,$23,$23,$23,$23,$22,$22
.byte $22,$21,$21,$20,$20,$20,$1F,$1F,$1F,$1E,$1E,$1D,$1D,$1C,$1C,$1C
.byte $1B,$1B,$1A,$1A,$19,$19,$18,$18,$17,$17,$16,$16,$15,$15,$14,$14
.byte $14,$13,$13,$12,$12,$11,$11,$10,$10,$0F,$0F,$0E,$0E,$0D,$0D,$0C
.byte $0C,$0B,$0B,$0B,$0A,$0A,$09,$09,$08,$08,$08,$07,$07,$07,$06,$06
.byte $05,$05,$05,$04,$04,$04,$04,$03,$03,$03,$02,$02,$02,$02,$02,$01
.byte $01,$01,$01,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$01,$01,$01
.byte $01,$01,$02,$02,$02,$02,$02,$03,$03,$03,$04,$04,$04,$04,$05,$05
.byte $05,$06,$06,$07,$07,$07,$08,$08,$08,$09,$09,$0A,$0A,$0B,$0B,$0B
.byte $0C,$0C,$0D,$0D,$0E,$0E,$0F,$0F,$10,$10,$11,$11,$12,$12,$13,$13
-
Non ho potuto fare a meno di applicare un paio di modifiche :D
Come gia' detto a freshness in chat, non riuscivo a capacitarmi del perche' non mi partisse in autorun, l'errore era nella init.
; v2.1 revisione di iAN CooG
;
;- sysline che non causa ?SYNTAX ERROR
;- ciclo all'uscita della fstirq anziche' inc $ffff ripetuti
;- corretta initIRQ, ora parte in ogni emulatore, sempre.
;- ridotta occupazione in memoria. ok, non era necessario :)
NOPopcode = $EA
temp = $FE
setDEN = $FA
rastline = $FB
sinuspos = $FD
*=$0801
word eoprg
word 2009
byte $9E,[intro]d,":",$8f,$0d,"FRESHNESS79(CODE) + IAN COOG(FIX)"
byte 0
eoprg
word 0
intro
lda #$18 ; Attivazione schermo (D011 - bit DEN)
sta setDEN
lda #$2e ; Linea $30 (-2 per la stabilizzazione)
sta rastline
lda #$00 ; Resetta la posizione della sinus table
sta sinuspos
jsr initIRQ ; Inizializzazione raster IRQ
cli ; Interrupt attivati
rts
; ***************************************************
; * Routine di sincronizzazione a doppio raster IRQ *
; ***************************************************
; La prima chiamata IRQ e' su JMP, quindi l'incertezza e' di 1-3 cicli
; Il primo handler permette di ridurla a 1-2 cicli: IRQ arriva sulla NOP
; Il secondo handler infine grazie ad un confronto a fine raster elimina
; l'ultima possibile incertezza
fstirq
lsr $d019 ; 6 + (36 Kernal IRQ) + (da 2 a 4 JMP)
inc $d012 ; 6 interrupt al prossimo raster
lda #<secirq ; 2 reimposto il vettore IRQ perche' punti
sta $0314 ; 4 al secondo handler
cli ; 2 attivo gli interrupt
nop ; 2 (63-65) <= IRQ
nop ; 2 (65-67) <= IRQ
nop
nop
nop
nop
brk ; Qua non ci si arriva mai, lascio BRK per test
secirq
ldx sinuspos ; 3 + (36 Kernal IRQ) + (da 2 a 3 NOP)
lda sinushigh,x ; 4 Carico la parte piu' significativa dello spostamento
lsr ; 2 orizzontale, nel carry metto il bit meno significativo
sta brnch+1 ; 4 uso il resto per creare un displacement
lda $d012 ; 4 Stabilizzazione raster
nop ; 2w
nop ; 2w
bit $d012 ; 4 se il ritardo dovuto alla NOP era 1
beq synced ; 2/3 effettuo un branch per allinearmi
; Routine di delay della prima badline
synced
bcc brnch ; questo branch serve per saltare un ciclo
brnch
bpl * ; con questo si saltano 2*N cicli
ds $13,NOPopcode; (0-38 cicli) 19xNOP (la nop impiega 2 cicli)
lda setDEN
sta $d011 ; Attivazione badline
inc sinuspos ; incrementa il pointer e setta 06 il colore del garbage (INC = $E6)
lda sinuslow,x ; Parte meno significativa dello spostamento
sta $d016 ; orizzontale - scrolling fine
lda rastline
sta $d012 ; ripristino del corretto raster compare
ldx #<fstirq
stx $0314 ; ripristino il vecchio IRQ pointer
tsx
txa
clc
adc #$06
tax
txs ; ripristino dello stack pointer
lsr $d019 ; Acknowledge del raster IRQ
;cli ; Interrupt nuovamente attivi << ha senso durante l'IRQ?
;qua possiamo ciclare, CREDO siano sufficienti, aggiustare alla bisogna;D
ldx #$0d
dexdel
inc $ffff
dex
bne dexdel
lda #$00 ; reset
sta $d011 ; del bit DEN nel registro $D011
jmp $ea31 ; Salto alla normale routine di interruzione
; ************
; * Init IRQ *
; ************
;
; Disattivazione dell'interrupt standard,
; Impostazione della prima rasterline e dell'indirizzo
; del primo handler della routine di interrupt
; attivazione dei raster interrupt
initIRQ
sei
lda #$7f
sta $dc0d
sta $dd0d
lda $dc0d;non dc0c !
lda $dd0d;non dd0c !
lda #$00
sta $d011
lda $fb
sta $d012
lda #<fstirq
sta $0314
lda #>fstirq
sta $0315
lda #$01
sta $d01a
; Meglio settare SEMPRE d019 per pulire ogni irq pendente, come le lda $dc0d.
; A me ad esempio in Vice 2.1.9 non parte MAI in autostart senza questa :)
sta $d019
rts
align $100
sinuslow
byte $07,$04,$00,$04,$00,$04,$00,$04,$00,$05,$01,$05,$01,$06,$02,$06
byte $03,$07,$04,$00,$05,$01,$06,$02,$07,$04,$01,$06,$03,$00,$05,$02
byte $07,$04,$02,$07,$05,$02,$00,$06,$03,$01,$07,$05,$03,$01,$00,$06
byte $05,$03,$02,$01,$07,$06,$05,$04,$04,$03,$02,$02,$01,$01,$01,$01
byte $00,$01,$01,$01,$01,$02,$02,$03,$04,$04,$05,$06,$07,$01,$02,$03
byte $05,$06,$00,$01,$03,$05,$07,$01,$03,$06,$00,$02,$05,$07,$02,$04
byte $07,$02,$05,$00,$03,$06,$01,$04,$07,$02,$06,$01,$05,$00,$04,$07
byte $03,$06,$02,$06,$01,$05,$01,$05,$00,$04,$00,$04,$00,$04,$00,$04
byte $07,$03,$07,$03,$07,$03,$07,$03,$07,$02,$06,$02,$06,$01,$05,$01
byte $04,$00,$03,$07,$02,$06,$01,$05,$00,$03,$06,$01,$04,$07,$02,$05
byte $00,$03,$05,$00,$02,$05,$07,$01,$04,$06,$00,$02,$04,$06,$07,$01
byte $02,$04,$05,$06,$00,$01,$02,$03,$03,$04,$05,$05,$06,$06,$06,$06
byte $06,$06,$06,$06,$06,$05,$05,$04,$03,$03,$02,$01,$00,$06,$05,$04
byte $02,$01,$07,$06,$04,$02,$00,$06,$04,$01,$07,$05,$02,$00,$05,$03
byte $00,$05,$02,$07,$04,$01,$06,$03,$00,$05,$01,$06,$02,$07,$03,$00
byte $04,$01,$05,$01,$06,$02,$06,$02,$07,$03,$07,$03,$07,$03,$07,$03
sinushigh
byte $14,$14,$14,$15,$15,$16,$16,$17,$17,$18,$18,$19,$19,$1A,$1A,$1B
byte $1B,$1C,$1C,$1C,$1D,$1D,$1E,$1E,$1F,$1F,$1F,$20,$20,$20,$21,$21
byte $22,$22,$22,$23,$23,$23,$23,$24,$24,$24,$25,$25,$25,$25,$25,$26
byte $26,$26,$26,$26,$27,$27,$27,$27,$27,$27,$27,$27,$27,$27,$27,$27
byte $27,$27,$27,$27,$27,$27,$27,$27,$27,$27,$27,$27,$27,$26,$26,$26
byte $26,$26,$25,$25,$25,$25,$25,$24,$24,$24,$23,$23,$23,$23,$22,$22
byte $22,$21,$21,$20,$20,$20,$1F,$1F,$1F,$1E,$1E,$1D,$1D,$1C,$1C,$1C
byte $1B,$1B,$1A,$1A,$19,$19,$18,$18,$17,$17,$16,$16,$15,$15,$14,$14
byte $14,$13,$13,$12,$12,$11,$11,$10,$10,$0F,$0F,$0E,$0E,$0D,$0D,$0C
byte $0C,$0B,$0B,$0B,$0A,$0A,$09,$09,$08,$08,$08,$07,$07,$07,$06,$06
byte $05,$05,$05,$04,$04,$04,$04,$03,$03,$03,$02,$02,$02,$02,$02,$01
byte $01,$01,$01,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$01,$01,$01
byte $01,$01,$02,$02,$02,$02,$02,$03,$03,$03,$04,$04,$04,$04,$05,$05
byte $05,$06,$06,$07,$07,$07,$08,$08,$08,$09,$09,$0A,$0A,$0B,$0B,$0B
byte $0C,$0C,$0D,$0D,$0E,$0E,$0F,$0F,$10,$10,$11,$11,$12,$12,$13,$13
Interessante il fatto che il colore del pattern in alto a sinistra (visibile se si cambia il colore di sfondo $d021 ad esempio in nero) sia dovuto all'opcode fetchato dopo la sta $d011, non sapevo di questa cosa =)
-
Grazie dei fix, effettivamente ora il codice é più pulito.
Per quanto riguarda il colore del garbage (e anche il carattere), riporto la parte riguardante il DMA delay tratta dal documento redatto da Christian Bauer - VIC-II Article (http://www.zimmers.net/cbmpics/cbm/c64/vic-ii.txt)
Ho evidenziato le parti salienti riguardanti il difetto: sostanzialmente é la stessa cosa che succede quando si creano dei FLI.
...
3.14.6. DMA delay
-----------------
The most sophisticated Bad Line manipulation is to create a Bad Line
Condition within cycles 15-53 of a raster line in the display window in
which the graphics data sequencer is in idle state, e.g. by modifying
register $d011 so that YSCROLL is equal to the lower three bits of RASTER.
The VIC will then set BA to low immediately in the next cycle, switch to
display state and start reading from the video matrix (the processor is now
stopped because BA is low and it wants to read the next opcode). However,
AEC still follows ø2 for three cycles before also staying at low state.
This behavior (AEC not until three cycles after BA) is hardwired in the VIC
and cannot be avoided.
Nevertheless, the VIC accesses the video matrix, or at least it tries,
because as long as AEC is still high in the second clock phase, the address
and data bus drivers D0-D7 of the VIC are in tri-state and the VIC reads
the value $ff from D0-D7 instead of the data from the video matrix in the
first three cycles. The data lines D8-D13 of the VIC however don't have
tri-state drivers and are always set to input. But the VIC doesn't get
valid Color RAM data from there either, because as AEC is high, the 6510 is
still considered the bus master and unless it doesn't by chance want to
read the next opcode from the Color RAM, the chip select input of the Color
RAM is not active. Instead, a 4 bit analog (!) switch, U16, connects the
data bits D0-D3 of the processor with the data bits D8-D13. This connection
is always in place when AEC is high and should allow the processor to
access the Color RAM if desired. To make a long story short: In the first
three cycles after BA went low, the VIC reads $ff as character pointers and
as color information the lower 4 bits of the opcode after the access to
$d011. Not until then, regular video matrix data is read.
...
-
Ah il Vic Article. Non sono mai riuscito a leggerlo interamente, dopo un po' mi va insieme la vista :lol:
-
Domanda: perche' l'effetto viene chiamato proprio "DMA delay"?
Cioe', la parola "DMA" viene dal nome di un coder che per primo l'ha scoperto oppure il trucco ha effettivamente a che fare con una operazione di DMA nella memoria?
-
In informatica DMA è l'acronimo per Direct Memory Access: l'accesso diretto alla memoria da parte di un dispositivo senza passare per una lettura tramite il processore. In questo contesto dovrebbe riferirsi al fatto che viene ritardato l'accesso da parte del chip grafico alla memoria video che avviene nella bad line.
-
...quindi qui , con DMA si intende la lettura della RAM da parte della circuiteria incaricata di generare l'immagine video.
Domanda: qualcuno sa dirmi se normalmente nel C64 il VICII provoca degli stalli al processore 6510, nel caso i due cerchino di accedere alla stessa area di memoria?
Ad esempio, il circuito grafico dello Spectrum (ULA) blocca sistematicamente il clock dello Z80 se c'e' un conflitto d'accesso nel banco RAM sotto i 32K (area video). Nell'Amiga, invece, usavano una tecnica di accesso a cicli alternati che evitava i conflitti...
-
L'accesso alla memoria da parte del processore è bloccata (BA request) quando il VIC accede alla memoria video. Peranto a ogni bad line, il processore ha meno cicli a disposizione (dato che ogni istruzione del 6510 accede alla memoria)
-
Aggiungo qualche dettaglio a quanto già detto da ice.
In realtà il VIC accede alla memoria costantemente, manda in stallo il 6510 solo in determinate condizioni (bad line, sprites).
La suddivisione dell'accesso alla memoria é basata sul segnale AEC che normalmente é identico al segnale PHI2 (Il clock principale da circa 1Mhz).
In sostanza, tenendo in mente che il PHI2 é un'onda quadra, durante la prima fase di PHI2 (quando PHI2 ed AEC sono low) la memoria é acceduta dal VIC, nell'altra fase (PHI2 e AEC high) é acceduta dal processore.
Gli accessi del VIC in questo caso sono di 4 tipi:
- 5 refresh della memoria
- lettura degli 8 sprite pointers
- lettura di 40 byte di memoria grafica o di font (solo nella zona interna ai bordi)
- idle (quando non fa nessuna delle prime 3, tipicamente "sotto" ai bordi, viene comunque letto un byte dall'ultima locazione della memoria video).
Queste 4 operazioni avvengono di fatto a costo 0 per il 6510.
I casi nei quali il VIC richiede esplicitamente uno stallo del 6510 sono invece essenzialmente due:
- lettura dei dati grafici di 1 o più sprite (2 cicli per sprite)
Avviene quando uno o più sprite sono attivi in una determinata linea
- lettura del colore (bitmap mode) o del codice carattere (textmode) (La cosiddetta badline che richiede 40 cicli)
Avviene (normalmente) ogni 8 linee per generare una nuova serie di colori (bitmap mode) oppure una nuova serie di caratteri (textmode).
Per ottenere ciò, 3 cicli prima di quando ne ha necessità il VIC porta a low il segnale BA e dopo (massimo) 3 cicli di clock il processore va in stallo: passati i 3 cicli diventa low anche il segnale AEC ed il VIC ottiene il controllo della memoria in entrambe le fasi di phi2.
Durante i 3 cicli intermedi allo stallo (Con BA low) il processore può solamente effettuare scritture, la prima lettura effettuata lo manda subito in stallo.
Di fatto quindi, quando si realizzano effetti come ad esempio i FLI, il processore viene mandato in stallo per diverse centinaia di cicli in ogni frame.
-
interessante... quindi possiamo dire che nell' architettura del C64 si sono posti il problema di contenere gli stalli entro il possibile, almeno nelle operazioni piu' comuni.
Mi viene da considerare che che la tecnologia del processore 6502, lavorante a basso numero di Mhz, avrebbe il vantaggio di consentire accessi in coesistenza col VIC, dato che le RAM dell'epoca erano circa cloccabili a 4 Mhz, quindi con un buon margine di banda residua...
Immagino anche che sia unicamente il VIC ad arbitrare l'uso del bus, quindi gli stalli della CPU accadono solo quando si va a lavorare dentro al suo banco da 16K, giusto?
-
Dunque... supponendo di lavorare in condizioni normali, cioé senza tirare per il collo il VIC con i vari trick hardware che sono stati scoperti, e con 8 sprite attivi - senza alcun multiplexing - il conto dei cicli CPU persi è più o meno questo:
Sprite: 8*21*2 (8 sprite, 21 linee per ogni sprite, 2 cicli cpu persi)
Foreground: 25*40 (25 linee per 40 cicli cpu persi)
(336+1000)*50 (50 frame per secondo) = 66800 cicli/sec
Tenendo presente che all'appello mancano in realtà altri cicli persi a causa del meccanismo di stallo (BA e dopo tre cicli AEC) direi che possiamo approssimare più o meno al 7/8% di un Mhz che comunque a mio avviso non é poco.
Nel caso del 64 in effetti la memoria viene acceduta 2 volte per ciclo di clock, pertanto con una frequenza di 2Mhz, bisogna ammettere che almeno da questo punto di vista l'architettura é stata disegnata in modo efficiente.
Quanto alla tua seconda domanda: si e no.
Si, é il VIC ad arbitrare il bus tramite il pin AEC.
No, non c'è alcun stallo legato ad un accesso alla stessa area di memoria: VIC e CPU non possono fare accessi contemporanei.
In base al valore di AEC vanno in tri-state le linee di indirizzamento della CPU oppure del VIC: pertanto in ogni istante a prescindere dall'indirizzo scelto solo uno dei due può leggere o scrivere in memoria.
In effetti nel precedente post forse mi sono spiegato male. Quando dicevo che il VIC accede costantemente alla memoria, intendevo dire in effetti che ci accede in ogni ciclo di clock: questo perché la prima fase del ciclo corrisponde sempre ad un accesso del VIC; nella seconda fase del ciclo però, a meno che il VIC non abbia motivi particolari (badline, sprite) per bloccarla, la CPU ha totale controllo sul bus indirizzi, a prescindere dalla locazione alla quale ha bisogno di accedere, il VIC in questo semiciclo ha le sue linee in tri-state.
-
Ho capito dove mi trovo!
MATRIX RELOAD :D
Prima o poi riuscivo a decodificare tutto mmmmmmmmmmmmn ;)
- cerchiamo di evitare gli OT, specialmente nei thread tecnici. Grazie
-
credo sia interessante far notare che alcuni programmi hanno necessità di avere una precisa PREDIZIONE dei tempi di esecuzione, come ad es. i programmi che generano/leggono il segnale della cassetta del datassette, e che grazie alla "chiusura" dello schermo, venendo meno le necessità di caricare le informazioni per la grafica dello schermo stesso, vengono eliminati gli accessi "extra" alla memoria che rimane sempre disponibile per il lavoro del 6502 senza introdurre "casuali" ritardi nel flusso esecutivo del SW.