Il compilatore CC65 permette di scrivere programmi in modalita' grafica mediante TGI ma non ero mai riuscito a farli poi eseguire dall'emulatore/C64 perche' l'eseguibile non riusciva a trovare la libreria grafica...la soluzione e' quella di creare un disco virtuale in cui copiare la libreria virtuale ed il file PRG
Si puo' iniziare compilando la demo con il comando
../bin/cl65 -O -o "tgidemo.prg" -t c64 tgidemo.c
A questo punto con il comando c1541 (incluso in Vice) si crea un nuovo disco e si copiano i file tgidemo.prg e c64-hi.tgi
c1541 -format diskname,id d64 my_diskimage.d64 -attach my_diskimage.d64 -write tgidemo.prg
c1541 -attach my_diskimage.d64 -write c64-hi.tgi
dall'emulatore si seleziona Autostart Image ..si vedra' un messaggio "This program needs...." si preme y e si attende qualche secondo
A questo punto apparira' la schermata dell'immagine soprastante
Visualizzazione post con etichetta Vice. Mostra tutti i post
Visualizzazione post con etichetta Vice. Mostra tutti i post
lunedì 11 novembre 2019
venerdì 25 ottobre 2019
Mandelbrot C64 con tabella dei quadrati
circa 40 minuti di esecuzione..usando l'algoritmo del post precedente
per togliere un po- di bordo bianco si puo' modificare la riga 60 con
60 FOR JI = -35 TO 0
Si puo' migliorare leggermente
per togliere un po- di bordo bianco si puo' modificare la riga 60 con
60 FOR JI = -35 TO 0
Si puo' migliorare leggermente
mercoledì 11 luglio 2018
PRG in Vice
A volte puo' essere comodo lanciare un PRG dentro a VICE ma, almeno su Windows, il drag and drop non funziona. Vengono accettate solo immagini disco, cassetta o cartuccia
Un metodo per ovviare al problema e' creare una immagine disco da una directory da Impostazioni/Impostazioni periferiche/Directory
A questo punto la directory viene vista come un disco
LOAD"$",8
LIST
e si avra' il contenuto della directory selezionata. A questo punto basta caricare il PRG
Un metodo per ovviare al problema e' creare una immagine disco da una directory da Impostazioni/Impostazioni periferiche/Directory
A questo punto la directory viene vista come un disco
LOAD"$",8
LIST
e si avra' il contenuto della directory selezionata. A questo punto basta caricare il PRG
lunedì 9 luglio 2018
Sprites su C64
Un modifica del codice di MoveSprite.asm (qui su GitHub) che mostra due sprite. Il primo sprite
viene ubicato in una coordinata casuale con una routine random del SID. Il primo sprite si puo' muovere e quando tocca il secondo sprite il VIC sente la collisione ed il programma si arresta
Il codice ha una autoload in modo da non essere necessario digitare nessun comando SYS (che in ogni caso e' SYS 2304). Il codice dovrebbe essere sufficientemente commentato
Sviluppato con RelaunchC64 come IDE ed ACME come crosscompiler assembler. Lo sprite e' stato generato con http://www.spritemate.com/ che permette l'export sia in formato ACME che KickAssembler
-----------------------------------------------------------------------------
!cpu 6502
!to "move_2sprite.prg",cbm
; SYS 2034
;*=$0900
; LA DEFINIZIONE DELLE VARIABILI E' IN CODA AL CODICE
!macro start_at .address {
* = $0801
!byte $0c,$08,$00,$00,$9e
!if .address >= 10000 { !byte 48 + ((.address / 10000) % 10) }
!if .address >= 1000 { !byte 48 + ((.address / 1000) % 10) }
!if .address >= 100 { !byte 48 + ((.address / 100) % 10) }
!if .address >= 10 { !byte 48 + ((.address / 10) % 10) }
!byte $30 + (.address % 10), $00, $00, $00
* = .address
}
!macro sid_random{
; calcola un valore casuale usando il SID
; il byte random viene salvato nell'accumulatore
LDA #$FF
STA $D40E
STA $D40F
LDA #$80
STA $D412
LDA $D41B
}
;------------------------------------------------------------------------------------
!macro new_position{ ; cambia la posizione dello sprite 0 in modo casuale
LDA #0 ;stick with x0-255
STA $D010 ; la coordinata X puo' essere maggiore di 255 e non puo' essere
; contenuta in un byte. La parte alta e' inserita nella locazione $D010
; in questo esempio la parte alta e' settata a zero per imposizione
+sid_random
TAX
ricalcola
+sid_random
CMP #200 ; compara l'accumulatore con 200
BPL ricalcola
; qui c'e' il problema contrario rispetto a X
; la coordinata Y non puo' essere maggiore di 200 mentre un byte puo' essere 255
; quindi cicla nel calcolare numeri casuali fino a che non e' minore di 200
TAY
STX $D000 ; che contengono la posizione dello sprite 0
STY $D001
}
;------------------------------------------------------------------------------------
+start_at $0900
JSR $E09A
JSR $E544 ; vai alla subroutine che cancella lo schermo
LDA #13 ;
STA $C202
LDA #$0D ;ad $7F8 c'e' il puntatore dello sprite 0
STA $7F8
LDA #$0D ;ad $7F9 c'e' il puntatore dello sprite 1
STA $7F9
LDA #3 ;abilita lo sprite 0, e' una bit mask
STA $D015 ;che serve ad abilitare tutti gli sprite
;abilitare sprite 0 ed 1 si inserisce 3 (11b)
LDA #02 ; in D027 c'e' il colore dello sprite 0
STA $D027 ; viene inserito il valore 2 ovvero rosso
; setta il colore dello sprite 1
LDA #03
STA $D028
LDX #0
LDA #0
;a $0340 c'e' la locazione di memoria dello sprite 0
;ogni sprite e' lungo 63 byte (piu' un byte non utilizzato)
;il codice successivo cicla per pulire l'area di memoria
CLEANUP0 STA $0340,X
INX
CPX #63
BNE CLEANUP0
;ripulisce l'area dello sprite 1
LDX #0
CLEANUP1 STA $0340,X
INX
CPX #63
BNE CLEANUP1
;dopo aver ripulito l'area di memoria la riempie con
;la matrice DATA
LDX #0
BUILD LDA DATA,X
STA $0340,X
INX
CPX #63
BNE BUILD
;position
+new_position
;setta le variabili dello sprite 1
LDX #100 ;
LDY #100 ;
STX $D002 ;
STY $D003
SCAN JSR $FF9F ;richiede al Kernal lo stato della tastiera
JSR $FFE4 ;richiede al Kernal il valore del default input
;sposta lo sprite a seconda dello stato tastiera
START CMP #87 ;W - up
BEQ UP
CMP #83 ;S - down
BEQ DOWN
CMP #65 ;A - left
BEQ LEFT
CMP #68 ;D - right
BEQ RIGHT
CMP $C202 ;end if enter clicked
BEQ END
; controlla se ci sono state collision
LDA $D01E ; byte di collisione hardware tra sprite
CMP #0
BNE END
JMP SCAN
UP LDY $D001 ; carica la posizione Y dello sprite in Y
DEY ; decrementa Y (il sistema di riferimento e' rovesciato)
STY $D001 ; ed aggiorna la posizione dello sprite
;+new_position
JMP SCAN
DOWN LDY $D001
INY
STY $D001
JMP SCAN
LEFT LDX $D000
DEX
STX $D000
CPX #255
BNE SCAN
LDA #0
STA $D010
JMP SCAN
RIGHT LDX $D000
INX
STX $D000
CPX #255
BNE SCAN
LDA #1
STA $D010
JMP SCAN
;clean up at the end
END JSR $E544 ; pulisce lo schermo
LDA #0 ; disabilita lo sprite 0
STA $D015
RTS ; ritorna al prompt
;define the sprite
DATA !byte $00,$00,$00,$00,$00,$00,$00,$00
!byte $00,$00,$00,$00,$00,$00,$00,$00
!byte $38,$00,$00,$fc,$00,$00,$f2,$00
!byte $01,$c3,$00,$01,$89,$80,$03,$80
!byte $c0,$03,$83,$c0,$03,$82,$00,$07
!byte $03,$00,$07,$01,$80,$00,$c0,$80
!byte $00,$79,$80,$00,$0f,$00,$00,$00
!byte $00,$00,$00,$00,$00,$00,$00,$08
viene ubicato in una coordinata casuale con una routine random del SID. Il primo sprite si puo' muovere e quando tocca il secondo sprite il VIC sente la collisione ed il programma si arresta
Il codice ha una autoload in modo da non essere necessario digitare nessun comando SYS (che in ogni caso e' SYS 2304). Il codice dovrebbe essere sufficientemente commentato
Sviluppato con RelaunchC64 come IDE ed ACME come crosscompiler assembler. Lo sprite e' stato generato con http://www.spritemate.com/ che permette l'export sia in formato ACME che KickAssembler
-----------------------------------------------------------------------------
!cpu 6502
!to "move_2sprite.prg",cbm
; SYS 2034
;*=$0900
; LA DEFINIZIONE DELLE VARIABILI E' IN CODA AL CODICE
!macro start_at .address {
* = $0801
!byte $0c,$08,$00,$00,$9e
!if .address >= 10000 { !byte 48 + ((.address / 10000) % 10) }
!if .address >= 1000 { !byte 48 + ((.address / 1000) % 10) }
!if .address >= 100 { !byte 48 + ((.address / 100) % 10) }
!if .address >= 10 { !byte 48 + ((.address / 10) % 10) }
!byte $30 + (.address % 10), $00, $00, $00
* = .address
}
!macro sid_random{
; calcola un valore casuale usando il SID
; il byte random viene salvato nell'accumulatore
LDA #$FF
STA $D40E
STA $D40F
LDA #$80
STA $D412
LDA $D41B
}
;------------------------------------------------------------------------------------
!macro new_position{ ; cambia la posizione dello sprite 0 in modo casuale
LDA #0 ;stick with x0-255
STA $D010 ; la coordinata X puo' essere maggiore di 255 e non puo' essere
; contenuta in un byte. La parte alta e' inserita nella locazione $D010
; in questo esempio la parte alta e' settata a zero per imposizione
+sid_random
TAX
ricalcola
+sid_random
CMP #200 ; compara l'accumulatore con 200
BPL ricalcola
; qui c'e' il problema contrario rispetto a X
; la coordinata Y non puo' essere maggiore di 200 mentre un byte puo' essere 255
; quindi cicla nel calcolare numeri casuali fino a che non e' minore di 200
TAY
STX $D000 ; che contengono la posizione dello sprite 0
STY $D001
}
;------------------------------------------------------------------------------------
+start_at $0900
JSR $E09A
JSR $E544 ; vai alla subroutine che cancella lo schermo
LDA #13 ;
STA $C202
LDA #$0D ;ad $7F8 c'e' il puntatore dello sprite 0
STA $7F8
LDA #$0D ;ad $7F9 c'e' il puntatore dello sprite 1
STA $7F9
LDA #3 ;abilita lo sprite 0, e' una bit mask
STA $D015 ;che serve ad abilitare tutti gli sprite
;abilitare sprite 0 ed 1 si inserisce 3 (11b)
LDA #02 ; in D027 c'e' il colore dello sprite 0
STA $D027 ; viene inserito il valore 2 ovvero rosso
; setta il colore dello sprite 1
LDA #03
STA $D028
LDX #0
LDA #0
;a $0340 c'e' la locazione di memoria dello sprite 0
;ogni sprite e' lungo 63 byte (piu' un byte non utilizzato)
;il codice successivo cicla per pulire l'area di memoria
CLEANUP0 STA $0340,X
INX
CPX #63
BNE CLEANUP0
;ripulisce l'area dello sprite 1
LDX #0
CLEANUP1 STA $0340,X
INX
CPX #63
BNE CLEANUP1
;dopo aver ripulito l'area di memoria la riempie con
;la matrice DATA
LDX #0
BUILD LDA DATA,X
STA $0340,X
INX
CPX #63
BNE BUILD
;position
+new_position
;setta le variabili dello sprite 1
LDX #100 ;
LDY #100 ;
STX $D002 ;
STY $D003
SCAN JSR $FF9F ;richiede al Kernal lo stato della tastiera
JSR $FFE4 ;richiede al Kernal il valore del default input
;sposta lo sprite a seconda dello stato tastiera
START CMP #87 ;W - up
BEQ UP
CMP #83 ;S - down
BEQ DOWN
CMP #65 ;A - left
BEQ LEFT
CMP #68 ;D - right
BEQ RIGHT
CMP $C202 ;end if enter clicked
BEQ END
; controlla se ci sono state collision
LDA $D01E ; byte di collisione hardware tra sprite
CMP #0
BNE END
JMP SCAN
UP LDY $D001 ; carica la posizione Y dello sprite in Y
DEY ; decrementa Y (il sistema di riferimento e' rovesciato)
STY $D001 ; ed aggiorna la posizione dello sprite
;+new_position
JMP SCAN
DOWN LDY $D001
INY
STY $D001
JMP SCAN
LEFT LDX $D000
DEX
STX $D000
CPX #255
BNE SCAN
LDA #0
STA $D010
JMP SCAN
RIGHT LDX $D000
INX
STX $D000
CPX #255
BNE SCAN
LDA #1
STA $D010
JMP SCAN
;clean up at the end
END JSR $E544 ; pulisce lo schermo
LDA #0 ; disabilita lo sprite 0
STA $D015
RTS ; ritorna al prompt
;define the sprite
DATA !byte $00,$00,$00,$00,$00,$00,$00,$00
!byte $00,$00,$00,$00,$00,$00,$00,$00
!byte $38,$00,$00,$fc,$00,$00,$f2,$00
!byte $01,$c3,$00,$01,$89,$80,$03,$80
!byte $c0,$03,$83,$c0,$03,$82,$00,$07
!byte $03,$00,$07,$01,$80,$00,$c0,$80
!byte $00,$79,$80,$00,$0f,$00,$00,$00
!byte $00,$00,$00,$00,$00,$00,$00,$08
giovedì 14 giugno 2018
SetPixel su C64
Questo e' solo un promemoria....il codice e' stato preso su Internet...ho provato solo a capirci qualcosa senza neanche molto successo
Per accendere un pixel di posizione X,Y nella modalita' in alta risoluzione (320x200x2colori) del C64 la formula e' la seguente
indirizzo_pixel = base_mem_video +( int(y/8) *320) +(y AND 7) + (int(x/8)*8)
il motivo di questa curiosa formula deriva da come e' gestita la modalita' grafica. Al contrario di come si potrebbe fare con VGA (con un flusso continuo di bit a descrivere la pagina) in C64 lo schermo e' diviso in porzioni di 8x8 pixels.
Ho trovato su GitHub questo codice che funziona decisamente bene e si compila con ACME (per lanciarlo SYS 32768) ed ho provato a commentarlo con risultati decisamente alterni
------------------------------------------------------
!cpu 6502
!to "plot-asm.prg",cbm
base = $2000
SCROLY = $D011
VMCSB = $D018
colmap = $0400
C2DDRA = $DD02
CI2PRA = $DD00
scrlen = 8000
maplen = 1000
xcoord = $fb
ycoord = $fd
tabptr = xcoord
tabsiz = $9000
filval = tabsiz+2
; queste sono variabili in pagina zero
bmpage = $ff
mask = $59
loc = $5a
store = $5c
* = $8000 ; start address for 6502 code
; sys 32768
jmp start
; address = base + int(y/8) * 320 + (y and 7) + int(x/8) * 8
plotbit lda xcoord ; mette il valore della coordinata X in accumulatore
; questa e' il primo pezzo ovvero (X AND 7)
and #7 ; 7 = 111
tax ; mette (xcoord and 7) in X
; questo serve per il numero di cicli di SHIFT
sec ; setta il carry questo dovrebbe servire per il ror successivo
lda #0 ; azzera l'accumulatore
sta loc ; mette la locazione $5c di x and 7
shift ror ; ruota right bits dell'accumulatore
; (divide per 2 l'accumulatore)
dex ; decrementa x
bpl shift ; salta se x e' positivo o zero
; ror e' come dividere per 2 ogni ciclo
sta mask ; salva il valore in $59
lda xcoord ; carica l'accumulatore di xcoord
and #$f8 ; $f8=248 = 11111000
sta store ; metti in valore in store = $5c = 92 = 1011100
lda ycoord ; carica il valore di y
lsr ; shift left divide y/2
; nel carry c'e' il resto della divisione
lsr ; shift left divide y/4
lsr ; shift left divide y/8
sta loc+1 ;salva il $5a+1=$5b
lsr ; shift left
ror loc ; moltiplica * 320 ?????
lsr
ror loc
adc loc+1 ; salva la parte alta
sta loc+1
lda ycoord ; carica il valore di y
and #7 ; Y AND 7
; somma gli addendi
adc loc ; aggiungi LOC
adc store ; aggiungi STORE
sta loc ; salva tutto in STORE
lda loc+1
adc xcoord+1
adc bmpage ; aggiunge la base della memoria (ovvero base + .....)
sta loc+1
ldy #0
lda (loc),y
ora mask,y
sta (loc),y
rts
:--------------------------------------------------------------------------------
; fill routine
blkfil lda filval ; metti nell'accumulatore il valore della cella $9002 ovvero $10
ldx tabsiz + 1 ; carica in x $9001 ovvero
beq partpg ; salta alla label partpg se la flag di zero e' clear
ldy #0 ; carica Y con zero
fullpg sta (tabptr),y ; carica la cella puntata da $fb $400 con il valore zero inizialmente, poi cicla su fullpg su per $20
; indirect-indexed carica il valore zero dalla memoria puntata da $tabptr
; e' un modo che e' comune per realizzare array con y come indice ed il puntatore alla zona di memoria
iny ; incrementa Y
bne fullpg ; salta alla label fullpg
inc tabptr+1 ; incrementa la locazione $FC
dex ; decrementa X
bne fullpg ; ritorna a
partpg ldx tabsiz
beq fini
ldy #0
partlp sta (tabptr),y
iny
dex
bne partlp
fini rts
;---------------------------------------------------------------------------------
; main routine
; define bit map and enable high-res
start lda #$20
sta bmpage ; mette il valore $20 nella pagina zero a $FF
lda #$18
sta VMCSB ; seleziona lo screen mode $d018=53272
lda SCROLY ;
ora #32 ; attiva la risuoluzione 320x200 con OR 32 la locazione $d011=53265
sta SCROLY ;
; select graphics bank 1
lda C2DDRA ; $DD02
ora #$03 ; seleziona i banco VIC 1
sta C2DDRA ; ; $DD02
lda CI2PRA ; $DD00
ora #$03 ; $DD00 = %xxxxxx10 -> bank1: $4000-$7fff
sta CI2PRA
; clear bit map
lda #0 ; carica accumulatore con zero
sta filval ; tabsiz+2=$9002
lda #<base ; $2000 base della memoria schermo
sta tabptr ; metti il valore dell'accumulatore in $fb; locazione non usata di pagina zero
; qui e nella locazione successiva c'e' il puntatore alla zona di memoria tabptr
lda #>base ; mette $20
sta tabptr+1 ; carica il valore alto in $fc locazione pagina alta non utilizzata
lda #<scrlen ; mette la parte bassa basso $40 scrlen = 8000 byte
sta tabsiz ; mettilo alla locazione 9000
lda #>scrlen ; mette la parte alta $1F
sta tabsiz+1 ; dentro a $9001
jsr blkfil ; vai alla subroutune
; set bg and line colors
lda #$10 ; carica accumulatore $10
sta filval ; lo mette in $9002
lda #<colmap ; lda #$00
sta tabptr ; lo mette in $FB
lda #>colmap ; lda $04
sta tabptr+1 ; mette if $FC
lda #<maplen ;
sta tabsiz
lda #>maplen
sta tabsiz+1
jsr blkfil ; vai alla subroutine
; set horizontal and vertical position
lda #<160 ; visto che x puo' essere> 255 prende sia la parte bassa che alta
sta xcoord ; mette il valore 160 in xcoord
lda #>160
sta xcoord+1
lda #100 ; mette il valore di 100 in ycoord
sta ycoord
jsr plotbit ; vai alla routine di stampa bit per stampare il punto 160,100
inf jmp inf ; cicla qui all'infinito
------------------------------------------------------
Una cosa interessante che ho scoperto mentre cercavo di capire qualcosa del codice e' che VICE, l'emulatore di C64, e' dotato di un fantastico monitor in cui si puo' fare debug passo passo.
Si apre VICE e ci si trascina sopra il programma compilato in PRG. Poi si apre la finestra di monitor (ALT+H od ALT+M dipende dal sistema operativo)....si apre una consolle in cui si devono digitare comandi (per un elenco completo digitare help)
Dato che so che il codice inizia a $8000 e' stato sufficiente settare un breakpoint (BREAK $8000...tutti gli indirizzi devono essere messi in esadecimale) e poi lanciare il programma con SYS 32768. A questo punto si possono aprire le varie sottofinestre (per esempio dei registri...si puo' visualizzare lo stato anche con REGISTERS) e si pu' fare fare debug passo passo con STEP (oppure il tasto Z)
Un altro esempio per stampare punti in alta risoluzione puo' essere estratto da questo esempio in BASIC (e' un semplice PAINT che funziona con il joystick) (questa la fonte)
Il programma in Assembler funziona ... questo non lo ho testato
--------------------------------------------------------
Debug di VICE |
Per accendere un pixel di posizione X,Y nella modalita' in alta risoluzione (320x200x2colori) del C64 la formula e' la seguente
indirizzo_pixel = base_mem_video +( int(y/8) *320) +(y AND 7) + (int(x/8)*8)
il motivo di questa curiosa formula deriva da come e' gestita la modalita' grafica. Al contrario di come si potrebbe fare con VGA (con un flusso continuo di bit a descrivere la pagina) in C64 lo schermo e' diviso in porzioni di 8x8 pixels.
Ho trovato su GitHub questo codice che funziona decisamente bene e si compila con ACME (per lanciarlo SYS 32768) ed ho provato a commentarlo con risultati decisamente alterni
------------------------------------------------------
!cpu 6502
!to "plot-asm.prg",cbm
base = $2000
SCROLY = $D011
VMCSB = $D018
colmap = $0400
C2DDRA = $DD02
CI2PRA = $DD00
scrlen = 8000
maplen = 1000
xcoord = $fb
ycoord = $fd
tabptr = xcoord
tabsiz = $9000
filval = tabsiz+2
; queste sono variabili in pagina zero
bmpage = $ff
mask = $59
loc = $5a
store = $5c
* = $8000 ; start address for 6502 code
; sys 32768
jmp start
; address = base + int(y/8) * 320 + (y and 7) + int(x/8) * 8
plotbit lda xcoord ; mette il valore della coordinata X in accumulatore
; questa e' il primo pezzo ovvero (X AND 7)
and #7 ; 7 = 111
tax ; mette (xcoord and 7) in X
; questo serve per il numero di cicli di SHIFT
sec ; setta il carry questo dovrebbe servire per il ror successivo
lda #0 ; azzera l'accumulatore
sta loc ; mette la locazione $5c di x and 7
shift ror ; ruota right bits dell'accumulatore
; (divide per 2 l'accumulatore)
dex ; decrementa x
bpl shift ; salta se x e' positivo o zero
; ror e' come dividere per 2 ogni ciclo
sta mask ; salva il valore in $59
lda xcoord ; carica l'accumulatore di xcoord
and #$f8 ; $f8=248 = 11111000
sta store ; metti in valore in store = $5c = 92 = 1011100
lda ycoord ; carica il valore di y
lsr ; shift left divide y/2
; nel carry c'e' il resto della divisione
lsr ; shift left divide y/4
lsr ; shift left divide y/8
sta loc+1 ;salva il $5a+1=$5b
lsr ; shift left
ror loc ; moltiplica * 320 ?????
lsr
ror loc
adc loc+1 ; salva la parte alta
sta loc+1
lda ycoord ; carica il valore di y
and #7 ; Y AND 7
; somma gli addendi
adc loc ; aggiungi LOC
adc store ; aggiungi STORE
sta loc ; salva tutto in STORE
lda loc+1
adc xcoord+1
adc bmpage ; aggiunge la base della memoria (ovvero base + .....)
sta loc+1
ldy #0
lda (loc),y
ora mask,y
sta (loc),y
rts
:--------------------------------------------------------------------------------
; fill routine
blkfil lda filval ; metti nell'accumulatore il valore della cella $9002 ovvero $10
ldx tabsiz + 1 ; carica in x $9001 ovvero
beq partpg ; salta alla label partpg se la flag di zero e' clear
ldy #0 ; carica Y con zero
fullpg sta (tabptr),y ; carica la cella puntata da $fb $400 con il valore zero inizialmente, poi cicla su fullpg su per $20
; indirect-indexed carica il valore zero dalla memoria puntata da $tabptr
; e' un modo che e' comune per realizzare array con y come indice ed il puntatore alla zona di memoria
iny ; incrementa Y
bne fullpg ; salta alla label fullpg
inc tabptr+1 ; incrementa la locazione $FC
dex ; decrementa X
bne fullpg ; ritorna a
partpg ldx tabsiz
beq fini
ldy #0
partlp sta (tabptr),y
iny
dex
bne partlp
fini rts
;---------------------------------------------------------------------------------
; main routine
; define bit map and enable high-res
start lda #$20
sta bmpage ; mette il valore $20 nella pagina zero a $FF
lda #$18
sta VMCSB ; seleziona lo screen mode $d018=53272
lda SCROLY ;
ora #32 ; attiva la risuoluzione 320x200 con OR 32 la locazione $d011=53265
sta SCROLY ;
; select graphics bank 1
lda C2DDRA ; $DD02
ora #$03 ; seleziona i banco VIC 1
sta C2DDRA ; ; $DD02
lda CI2PRA ; $DD00
ora #$03 ; $DD00 = %xxxxxx10 -> bank1: $4000-$7fff
sta CI2PRA
; clear bit map
lda #0 ; carica accumulatore con zero
sta filval ; tabsiz+2=$9002
lda #<base ; $2000 base della memoria schermo
sta tabptr ; metti il valore dell'accumulatore in $fb; locazione non usata di pagina zero
; qui e nella locazione successiva c'e' il puntatore alla zona di memoria tabptr
lda #>base ; mette $20
sta tabptr+1 ; carica il valore alto in $fc locazione pagina alta non utilizzata
lda #<scrlen ; mette la parte bassa basso $40 scrlen = 8000 byte
sta tabsiz ; mettilo alla locazione 9000
lda #>scrlen ; mette la parte alta $1F
sta tabsiz+1 ; dentro a $9001
jsr blkfil ; vai alla subroutune
; set bg and line colors
lda #$10 ; carica accumulatore $10
sta filval ; lo mette in $9002
lda #<colmap ; lda #$00
sta tabptr ; lo mette in $FB
lda #>colmap ; lda $04
sta tabptr+1 ; mette if $FC
lda #<maplen ;
sta tabsiz
lda #>maplen
sta tabsiz+1
jsr blkfil ; vai alla subroutine
; set horizontal and vertical position
lda #<160 ; visto che x puo' essere> 255 prende sia la parte bassa che alta
sta xcoord ; mette il valore 160 in xcoord
lda #>160
sta xcoord+1
lda #100 ; mette il valore di 100 in ycoord
sta ycoord
jsr plotbit ; vai alla routine di stampa bit per stampare il punto 160,100
inf jmp inf ; cicla qui all'infinito
------------------------------------------------------
Una cosa interessante che ho scoperto mentre cercavo di capire qualcosa del codice e' che VICE, l'emulatore di C64, e' dotato di un fantastico monitor in cui si puo' fare debug passo passo.
Si apre VICE e ci si trascina sopra il programma compilato in PRG. Poi si apre la finestra di monitor (ALT+H od ALT+M dipende dal sistema operativo)....si apre una consolle in cui si devono digitare comandi (per un elenco completo digitare help)
Dato che so che il codice inizia a $8000 e' stato sufficiente settare un breakpoint (BREAK $8000...tutti gli indirizzi devono essere messi in esadecimale) e poi lanciare il programma con SYS 32768. A questo punto si possono aprire le varie sottofinestre (per esempio dei registri...si puo' visualizzare lo stato anche con REGISTERS) e si pu' fare fare debug passo passo con STEP (oppure il tasto Z)
Un altro esempio per stampare punti in alta risoluzione puo' essere estratto da questo esempio in BASIC (e' un semplice PAINT che funziona con il joystick) (questa la fonte)
Il programma in Assembler funziona ... questo non lo ho testato
--------------------------------------------------------
0 POKE 56, 32 : POKE 52, 32 : CLR : REM PROTECT SCREEN FROM BASIC :rem 108
1 POKE 53280, 1 : PRINT "{CLR}{WHT}" : GOTO 100 :rem 102
2 GOSUB 26 : BASE = 2 * 4096 : REM START ADDRESS OF HIRES SCREEN :rem 93
3 POKE 53272, PEEK(53272) OR 8 : REM BIT MAP AT 8192 :rem 39
4 POKE 53265, PEEK(53265)OR 32 : REM BIT MAP ON :rem 141
5 SYS 49152 : REM CLR HIRES SCREEN :rem 115
6 SYS 49173 : REM SET SCREEN COLOR (BITS THAT ARE OFF) :rem 237
7 X = 160 : Y = 100 : REM X & Y START POSITIONS :rem 15
8 GO SUB 13 : REM READ JOYSTICK :rem 198
9 REM UPDATE SCREEN :rem 160
10 CH = INT(X/8) : RO = INT(Y/8) : LN = YAND7 : BY = BA SE + RO * 320 + 8 * CH + LN : BI = 7 - (X AND 7) :rem 90
11 POKE BY, PEEK(BY) OR (2↑BI) : GOTO 8 :rem 33
12 REM READ JOYSTICK :rem 211
13 JV = PEEK(56320) : FR = JV AND 16 :rem 160
15 X = X + ((JV AND 4) = 0) - ((JV AND 8) = 0) :rem 27
16 Y = Y + ((JV AND 1) = 0) - ((JV AND 2) = 0) :rem 21
19 IF FR = 0 THEN 5 :rem 98
20 IF X > 319 THEN X = 319 :rem 133
21 IF Y > 199 THEN Y = 199 :rem 148
22 IF X < 0 THEN X = 0 :rem 171
23 IF Y < 0 THEN Y = 0 :rem 174
24 GET A$ : IF A$ < > "Q" THEN RETURN :rem 247
25 POKE 56, 160 : POKE 52, 160 : POKE 53272, 21 : POKE 53265, 27 : PRINT "{CLR}" : END :rem 4
26 PRINT "{CLR}" TAB(18)"{DOWN}MENU{DOWN}{4 LEFT}[<4 Y>]" :rem 72
27 PRINT "{DOWN}" TAB(16) "Q{2 SPACES} - QUIT" :rem 223
28 PRINT "{DOWN}" TAB(9) "FIRE BUTTON - CLR SCREEN" :rem 193
29 PRINT "{DOWN}" TAB(10) "JOYSTICK MOVES LINE." :rem 106
30 PRINT "{3 DOWN}{7 RIGHT} ENTER BORDER COLOR (0 TO 15)." : PRINT SPC(18); :rem 71
31 INPUT BC : POKE 53280, BC AND 15 :rem 206
32 PRINT"{3 DOWN}{7 RIGHT} ENTER SCREEN COLOR (0 TO 15)." : PRINT SPC(18); :rem 75
33 INPUT SC : POKE 49174, SC AND 15 : RETURN :rem 19
94 END : REM ELECTRIC ERASER :rem 111
95 A = PEEK(61) + 256 * PEEK(62) + 3 : POKE 786, INT(A/256) : POKE 785,A - 256 * PEEK(786) :rem 3
96 POKE A - 2, 0 : POKE A - 1,0 : POKE 45, PEEK(785) : POKE 46, PEEK(786) : CLR : GOTO95 :rem 44
100 FOR I = 0 TO 42 : READ J : POKE 49152 + I, J : NEXT I : GOTO 2 :rem 150
101 DATA 169, 0, 162, 32, 160, 0, 132, 33, 134, 34, 145, 33, 200, 208, 251, 232, 224, 64, 208, 244 :rem 17
102 DATA 96, 169, 1, 162, 4, 160, 0, 132, 33, 134, 34, 145, 33, 200, 208, 251, 232, 224, 8, 208, 244 :rem 75
103 DATA 96, 0
mercoledì 1 giugno 2016
Sviluppo assembler su C64
Mi e' presa la voglia di tornare alle origini e programmare in assembler sul MOS 6502 (o meglio sul MOS 6510 del Commodore 64). Ovviamente il computer fisico e' in qualche discarica (o spero recuperato) e cerco di usare l'emulatore VICE
In modo, piu' o meno tradizionale, dopo aver avviato l'emulatore, si deve impiegare un assemblatore (nel caso Turbo Assembler per C64...con una curiosa omonimia con TASM Borland per x86) caricando l'immagine di un disco (preventivamente scaricat) con File/Attach Disk Image/Disk 8
con LOAD"$",8 e successivo LIST si ottiene il contenuto del disco
Si carica l'assemblatore con LOAD"*",8,1 ed al READY si digita SYS36864 entrando nella schermata nera di editing. Questo e' il semplice programma di test che stampa a video una stringa
programma in sintassi TASM
--------------------------------------------------
Per compilare il programma si deve usare la combinazione BackArrow+3 ma BackArrow non esiste sulla tastiera PC; si tratta del tasto piu' in alto a sinistra al di sotto del tasto di ESC (che nella tastiera italiana e' il backslash o barra rovescia)
s per start e si avvia il programma. Per rientrare nella fase di editing e' sufficiente ridigitare SYS 36864
E' comunque piuttosto noioso procedere nel modo classico ed e' molto piu' comodo usare C64 Studio (una IDE con allegato ACME un cross compiler 6502) e che permette di eseguire il programma lanciando autonomamente VICE
La differenza sostanziale tra i due metodi e' che usando C64 Studio si deve scrivere un preambolo in Basic che lancia poi il codice Assembler (in pratica una sola linea di codice BASIC che indichi un SYS49152 per passare il controllo al codice assembler...tale preambolo e' ralizzato con le sole righe *=$0801 ovvero la locazione di memoria dove risiede il compilatore BASIC e !basic.. non risulta necessario impostare *=$01000)
programma in sintassi ACME. Da notare come viene dichiarata la stringa
--------------------------------------------------
fra le altre cose con C64 Studio si puo' utilizzare anche direttamente Basic
In modo, piu' o meno tradizionale, dopo aver avviato l'emulatore, si deve impiegare un assemblatore (nel caso Turbo Assembler per C64...con una curiosa omonimia con TASM Borland per x86) caricando l'immagine di un disco (preventivamente scaricat) con File/Attach Disk Image/Disk 8
con LOAD"$",8 e successivo LIST si ottiene il contenuto del disco
Si carica l'assemblatore con LOAD"*",8,1 ed al READY si digita SYS36864 entrando nella schermata nera di editing. Questo e' il semplice programma di test che stampa a video una stringa
programma in sintassi TASM
--------------------------------------------------
* = $1000
!basic
ldx #$00
loop
lda message,x
sta $0400,x
inx
cpx #$04
bne loop
rts
message .text "luca"
--------------------------------------------------
Per compilare il programma si deve usare la combinazione BackArrow+3 ma BackArrow non esiste sulla tastiera PC; si tratta del tasto piu' in alto a sinistra al di sotto del tasto di ESC (che nella tastiera italiana e' il backslash o barra rovescia)
s per start e si avvia il programma. Per rientrare nella fase di editing e' sufficiente ridigitare SYS 36864
E' comunque piuttosto noioso procedere nel modo classico ed e' molto piu' comodo usare C64 Studio (una IDE con allegato ACME un cross compiler 6502) e che permette di eseguire il programma lanciando autonomamente VICE
La differenza sostanziale tra i due metodi e' che usando C64 Studio si deve scrivere un preambolo in Basic che lancia poi il codice Assembler (in pratica una sola linea di codice BASIC che indichi un SYS49152 per passare il controllo al codice assembler...tale preambolo e' ralizzato con le sole righe *=$0801 ovvero la locazione di memoria dove risiede il compilatore BASIC e !basic.. non risulta necessario impostare *=$01000)
programma in sintassi ACME. Da notare come viene dichiarata la stringa
--------------------------------------------------
;set program start address
* = $0801
!basic
ldx #$00
loop
lda message,x
sta $0400,x
inx
cpx #$04
bne loop
rts
message !scr "luca"
fra le altre cose con C64 Studio si puo' utilizzare anche direttamente Basic
Iscriviti a:
Post (Atom)
Chershire Cat Ai
Chershire Ai e' un progetto italiano che sta crescendo adesso Per provarlo si clona il progetto git clone https://github.com/cheshire-...
-
In questo post viene indicato come creare uno scatterplot dinamico basato da dati ripresi da un file csv (nel dettaglio il file csv e' c...
-
La scheda ESP32-2432S028R monta un Esp Dev Module con uno schermo TFT a driver ILI9341 di 320x240 pixels 16 bit colore.Il sito di riferiment...
-
Questo post e' a seguito di quanto gia' visto nella precedente prova Lo scopo e' sempre il solito: creare un sistema che permet...