Autore Topic: Hiryu's 1st Asm Prog  (Letto 2439 volte)

hiryu

  • Utente
  • **
  • Post: 649
    • http://hiryu.netsons.org/
  • Gioco Preferito: Wizard Of Wor
Hiryu's 1st Asm Prog
« il: 04 Novembre 2004, 09:30:18 »
 Signori, questo è il mio primo programmino in assembler per il nostro beneamato computer; di mio c'è ben poco, il 99% del codice è stato rubato e da vari altri sorgenti.

Al momento non fa che generare una scritta scorrevole con il bordo che flasha, volevo sapere se si può far apparire un'immagine mente la scritta scrolla

Codice: [Seleziona]

   .byte $0b
   .byte $08; link alla prossima riga Basic (inesistente)
   .byte $0a
   .byte $00; numero riga Basic ($000a = 10)
   .byte $9e; codice SYS ($9e = 158)
   .byte $32
   .byte $30
   .byte $36
   .byte $34; indirizzo di partenza = 2064 ($0810)

; A label, used for counting frames and setting smooth scroll.

scroll_pos  = $0340

; Set assembly point - $0900 (2304) for the program.

   * = $0810

; Switch off the system interrupts ('cos this is runtime code).

   sei

; Clear the screen RAM and set the colour map.

   ldx #$00
screen_clear lda #$20
   sta $0400,x
   sta $0500,x
   sta $0600,x
   sta $06e8,x
   lda #$01
   sta $d800,x
   sta $d900,x
   sta $da00,x
   sta $dae8,x
   inx
   bne screen_clear

; Reset the scrolltext to the start.

   jsr reset_scroll

; The main loop - first wait for the raster to reach $FC.

main_loop  inc $D020; <-- This Flash border
   lda #$fc
   cmp $d012
   bne main_loop

; Little timer to make sure it only happens once a frame...

   ldx #$10
delay   dex
   bne delay

; Rea d scroll_pos, add one and if it gets to 4 it's time to move.

   ldx scroll_pos
   inx
   cpx #$04
   bne scroll_pos_xb

; Move the data for the scroller.

   ldx #$00
move_scroll  lda $0401,x
   sta $0400,x
   inx
   cpx #$27
   bne move_scroll

; Read the next character and if it's $00 reset the scroller.

read_scroll  lda $1000
   bne ok
   jsr reset_scroll
   jmp read_scroll

; Write the character to the screen at the right.

ok   sta $0427

; Add one to the position in the text.

   inc read_scroll+$01
   bne no_highbyte
   inc read_scroll+$02

; Put a 0 into the X so that it resets scroll_pos

no_highbyte  ldx #$00

; Write back to scroll_pos - if it wasn't 4 this is where we branched to.

scroll_pos_xb stx scroll_pos

; This is a "sneaky" bit to get the $D016 value - transfer the X to
; the A, multiply by two with an ASL and exclusive OR by 7 to reverse
; the value before writing to $D016.,
   txa
   asl
   eor #$07
   sta $d016

; Finally, back to the main loop.

   jmp main_loop

; This subroutine resets the scroller to $1000.

reset_scroll lda #$00
   sta read_scroll+$01
   lda #$10
   sta read_scroll+$02
   rts

; Change assembly point to $1000 (4096)

   *=$1000

; And here's the scrolltext.

message  .scrl "this is my 1st c64 asm program... it's only a simple scrolling text, without music, withou graphic, only text !!!  -hiryu   ***   "
   .byte $00
Elwood: "E' partito un pistone"
Jake: "Poi torna?"
________________________________________________________
Hiryu @ http://hiryu.netsons.org | http://www.virb.com/hiryu

Alberto

  • Utente
  • **
  • Post: 589
  • Gioco Preferito: Grand Prix Circuit
Hiryu's 1st Asm Prog
« Risposta #1 il: 04 Novembre 2004, 10:45:56 »
 
Citazione
volevo sapere se si può far apparire un'immagine mente la scritta scrolla
Usa le interruzioni del raster;in una parte dello schermo avrai la bitmap,nell'altra la scritta scorrevole.

hiryu

  • Utente
  • **
  • Post: 649
    • http://hiryu.netsons.org/
  • Gioco Preferito: Wizard Of Wor
Hiryu's 1st Asm Prog
« Risposta #2 il: 04 Novembre 2004, 11:18:28 »
 si va bene... ma come si fa? calcola che da 1 a 100 sto a 0,5
Elwood: "E' partito un pistone"
Jake: "Poi torna?"
________________________________________________________
Hiryu @ http://hiryu.netsons.org | http://www.virb.com/hiryu

fab

  • Utente
  • **
  • Post: 493
    • http://wav-prg.sourceforge.net/
  • Gioco Preferito: Tetris, Turrican, Impossible Mission
Hiryu's 1st Asm Prog
« Risposta #3 il: 04 Novembre 2004, 20:04:37 »
 Una volta scritto il programma, che strumento usi per assemblarlo? E' un cross-assembler?
Un giapponese sa recitare a memoria tutti i numeri di pi greco fino all'83431º decimale. Sa a memoria anche l'unico numero telefonico che è nella sua agendina - Daniele Luttazzi

hiryu

  • Utente
  • **
  • Post: 649
    • http://hiryu.netsons.org/
  • Gioco Preferito: Wizard Of Wor
Hiryu's 1st Asm Prog
« Risposta #4 il: 04 Novembre 2004, 21:26:36 »
 uso c64asm
Elwood: "E' partito un pistone"
Jake: "Poi torna?"
________________________________________________________
Hiryu @ http://hiryu.netsons.org | http://www.virb.com/hiryu

MarC=ello

  • Utente
  • **
  • Post: 337
  • Gioco Preferito: CBM BASIC 2.0
Hiryu's 1st Asm Prog
« Risposta #5 il: 11 Novembre 2004, 23:35:45 »
 Io ho scritto una routine di esempio sulle interruzioni del raster... magari è troppo complicata per chi sta muovendo i primi passi con l'asm, però credo sia una routine che potrebbe risultare utile in futuro  ;)

La routine parte con SYS 49152 (non ho avuto voglia di mettere l'autostart). Per assemblarla, usare c64asm.

Ho visto che postando le indentazioni scompaiono, mi spiace...

Codice: [Seleziona]

; Example code on raster interrupts
; GAMMATRON/Hokuto Force
; Commented code written as a reply to a request dealing with interrupts handling.

; This routines provides the border with different colors, splits the screen with bitmap
; mode, text mode and scrolls a line of text.
; (code non optimized).

* = $c000

interrupt_status = $d019
interrupt_enable = $d01a
old_vector = $fd

lda #$7f
          
sta $dc0d;turn off CIA 1 interrupts
sta $dd0d;turn off CIA 2 interrupts


lda #$00
sta index;index used to change scanlines and colors
sei ;disables interrupt. This is an absolutely important task.
  ;Normally the system knows that it has to execute the code
  ;pointed by the vector at locations $314 - $315. If we want
  ;to add our own interrupt job, we must change this vector. BUT,
  ;before doing so, we must disable interrupts. If we don't do that,
  ;the interrupt will occur just while we are changing the vector
  ;and a wrong vector would be used... a vector with a new low byte
  ;and a old high byte... resulting in crashing the system.
  ;Thus, always SEI, change vector, then CLI.
lda interrupt_enable
ora #$01
sta interrupt_enable
  ;enables VIC-II interrupts. This means that when the current
  ;rastercount value equals the compare value written in the
  ;rastercount register, an interrupt will be generated by the
  ;VIC-II. Thus, our interrupt routine will be executed.
lda $d011
and #127
sta $d011;set high bit of raster position counter to 0
lda #50
sta $d012;set low bits of raster position counter to 50 decimal
lda #<routine
sta $314
lda #>routine
sta $315;install our own interrupt routine
lda $dc0d;acknowledge CIA 1 interrupts
lda $dd0d;acknowledge CIA 2 interrupts
cli ;reenable interrupts.
; rts
loop jmp loop
routine  ;The following is the routine which determines what to do
  ;in each scan line where the interrupt has taken place

;lda interrupt_status
  ;looks what is going on in the i. status register
;and #$01
;beq return;if the compare value doesn't match the current raster count,
  ;return from this interrupt job
ldx index;loads current index value
bne no_delay1
nop ;delay to make things stabler
nop
nop
nop
nop
no_delay1
ldx index
cpx #$07
bne no_delay2
nop
nop
nop
nop
no_delay2
lda color_table,x
  ;color border determined by the value of the index

sta $d020;now changes border color

lda jump_table,x
beq skip_jump
tay
lda address_high,y
pha
lda address_low,y
pha
rts ;jumps to routine (routine, when finished, must jump to skip_jump label).
skip_jump
inc index;increment index value
lda index
cmp #color_table-scanline_table
  ;have we reached the end of the color table?
bne skip;if not, don't reset index
lda #$00
sta index;yep, so reset index

skip lda $d011
and #127
sta $d011;clears high-bit of rastercount
ldx index
lda scanline_table,x
sta $d012;sets next scanline on which interrupt must happen
lda #$01
sta interrupt_status
  ;clears latch
pla
tay
pla
tax
pla
rti ;correctly returns from interrupt (this works even with no ROM).



routine1
lda #59
sta 53265
jmp skip_jump

routine2
lda #27
sta 53265
jmp skip_jump

routine3
lda coarse_flag
beq skip_coarse
jsr coarse_scrolling
skip_coarse
jsr fine_scrolling
jmp skip_jump

routine4
lda #192
sta 53270
jmp skip_jump          

coarse_scrolling;moves text line of one character

screen = 2023-39;scrolls first line of screen
last = 2023 ;last character cell in that line

ldx #$00;this routine scrolls character in the first line
copy  lda screen+1,x;this way we update our line text and we free one place
sta screen,x;for the new character. Always update screen first, then
inx ;insert new data.
cpx #39
bne copy

read ldx counter;loads counter into x register (counter must contain 0
  ;at the beginning)

lda message,x
bne continue;if we haven't reached the end of the messagge, continue
lda #$00;else reset counter (re-read the message)
sta counter
jmp read
continue
sta last;puts character in the last cell
inc counter;prepare to get next character

lda #$00;yes
sta coarse_flag;the coarse scroll has been done

rts ;exit

fine_scrolling ;scrolls of one pixel



lda screen_pos;loads screen position (must start from 199)
sta 53270
dec screen_pos;add another for faster scroll

lda screen_pos
cmp #191
bne exit
lda #199
sta screen_pos
lda #$01
sta coarse_flag;the coarse scroll must be done
exit rts  

screen_pos
.byte 199

counter .byte 0

message .scru "hello there! this is a scroller, as you can see! bye!  gmt/hf    "
.byte 0

coarse_flag  
.byte 1 ;the coarse scroll is the first thing to do, so we must
  ;set it to a one at the beginning.

scanline_table
.byte 49,75,100,125,150,175,200,225,255
  ;this table ols the lines in which the IRQ is to be triggered
color_table
.byte 0,1,2,3,4,5,6,7,8  
  ;border colors for each area
jump_table
.byte 4,1,0,0,2,0,3,0,0
  ;contains the number of the routine to call

index .byte 0

address_high
.byte 0,>routine1,>routine2,>routine3,>routine4

address_low
.byte 0,<routine1-1,<routine2-1,<routine3-1,<routine4-1




Mi rendo conto del fatto che per chi è all'inizio le interruzioni del raster non sono proprio la cosa più adatta per cominciare... comunque ecco una versione più tranquilla:

Codice: [Seleziona]
; Interrupt routine: divides the border in three different areas, each with its color
; _GAMMATRON/Hokuto Force
; Commented code written to reply to a request dealing with interrupts handling.
; Notice that here we want a split border with the BASIC interpreter working.

* = $c000

interrupt_status = $d019
interrupt_enable = $d01a
old_vector = $fd

lda $314
sta old_vector;stores low byte of system vector
lda $315
sta old_vector+1
  ;stores high byte of system vector
lda #$00
sta index;index used to change scanlines and colors
sei ;disables interrupt. This is an absolutely important task.
  ;Normally the system knows that it has to execute the code
  ;pointed by the vector at locations $314 - $315. If we want
  ;to add our own interrupt job, we must change this vector. BUT,
  ;before doing so, we must disable interrupts. If we don't do that,
  ;the interrupt will occur just while we are changing the vector
  ;and a wrong vector would be used... resulting in crashing the
  ;system. Thus, always SEI, change vector, then CLI.
lda interrupt_enable
ora #$01
sta interrupt_enable
  ;enables VIC-II interrupts. This means that when the current
  ;rastercount value equals the compare value written in the
  ;rastercount register, an interrupt will be generated by the
  ;VIC-II. Thus, our interrupt routine will be executed.
lda $d011
and #127
sta $d011;set high bit of raster position counter to 0
lda #50
sta $d012;set low bits of raster position counter to 50 decimal
lda #<routine
sta $314
lda #>routine
sta $315;install our own interrupt routine
cli ;reenable interrupts
rts

routine  ;The following is the routine which determines what to do
  ;in each scan line where the interrupt has taken place

lda interrupt_status
  ;looks what is going on in the i. status register
and #$01
beq return;if the compare value doesn't match the current raster count,
  ;return from this interrupt job
ldx index;loads current index value
lda color_table,x
nop
nop ;short delay to make things stabler
sta $d020;color border determined by the value of the index

inc index;increment index value
lda index
cmp #$04;have we reached the end of the color table?
bne skip;nope, don't reset index
lda #$00
sta index;yep, so reset index

skip lda $d011
and #127
sta $d011;clears high-bit of rastercount
ldx index
lda scanline_table,x
sta $d012;sets next scanline on which interrupt must happen
lda #$01
sta interrupt_status
  ;clears latch
pla
tay
pla
tax
pla
rti ;correctly returns from interrupt

return jmp (old_vector)
  ;jumps to ROM routine (if the interrupt status register of the
  ;VIC-II has a not set flag, that means the interrupt is caused by
  ;the CIA, and the normal system routines must be executed).


scanline_table
.byte 50,100,250
color_table
.byte 1,2,3  
index .byte 0






Questa routine si limita a dividere il bordo in tre aree con colori differenti, e mantiene attivo l'interprete BASIC (di qui la stabilità non perfetta).

Ciao!
-=MarC=ellO=-

Alberto

  • Utente
  • **
  • Post: 589
  • Gioco Preferito: Grand Prix Circuit
Hiryu's 1st Asm Prog
« Risposta #6 il: 12 Novembre 2004, 11:15:59 »
 
Citazione
si va bene... ma come si fa? calcola che da 1 a 100 sto a 0,5
Allora ti consiglio di leggere qualche guida introduttiva all'asm,ad esempio il corso di lm di Marcello. ;)
Comunque,cerco di spiegarti il procedimento in due parole.
Per settare un'interruzione del raster,devi scrivere la linea video a cui vuoi l'interruzione nei registri $d012 e nel bit più significativo di $d011 (servono 9 bit perchè le linee processate dal raster sono più di 256,per la precisione 312 nel sistema video PAL);poi,attivi le interruzioni del raster settando il bit 0 del registro $d01a.
Quando il raster arriva a ridisegnare la linea definita in questi due registri,la CPU passa ad eseguire il codice di interrupt (che inizia dall'indirizzo puntato dalle locazioni $0314/$0315);per permettere l'esecuzione del codice di interruzione,devi sbloccare il registro $d019 (per esempio,attraverso un inc $d019).

Nel tuo caso ti serve una parte di schermo in modalità bitmap (per visualizzare l'immagine),e un'altra parte in modalità testo normale (per capirci,la modalità grafica in cui si trova il C64 all'accensione).
Per far questo puoi generare un'interruzione del raster alla linea 241 (per avere del testo scorrevole nell'ultima riga di schermo),e un'altra interruzione alla linea
49,dove setterai la modalità bitmap.
In codice macchina,avrai una cosa di questo genere:
Codice: [Seleziona]
sei          ; disattiva interruzioni
lda #<irq
sta $0314
lda #>irq
sta $0315; dirotta il vettore di interrupt alla tua routine
lda #$31
sta $d012
lda #$7f
and $d011
sta $d011; definisce la prima interruzione del raster alla riga 50
lda #$01
sta $d01a
cli          ; riattiva interruzioni
rts

;*** CODICE ESEGUITO PER DEFINIRE L'IMMAGINE NELLA PARTE ALTA DEL;VIDEO ***

irq  

[...setta la modalità bitmap e fa qualcos'altro...]

lda #<irq2
sta $0314
lda #>irq2
sta $0315; setta il nuovo vettore di interruzione
lda #$f1
sta $d012; definisce la prossima interruzione del raster alla riga 241
inc $d019; sblocca lo stato di IRQ per permettere le interruzioni successive
jmp $ea81; la CPU torna ad eseguire il codice principale

; *** CODICE ESEGUITO NELLA PARTE BASSA DEL VIDEO

irq2

[...setta la modalità testo normale e fa qualcos'altro...]

lda #<irq
sta $0314
lda #>irq
sta $0315; setta il nuovo vettore di interruzione
lda #$31
sta $d012; definisce la prossima interruzione del raster alla riga 49
inc $d019; sblocca lo stato di IRQ per permettere le interruzioni successive
jmp $ea81; la CPU torna ad eseguire il codice principale

Per sapere come definire le modalità bitmap e testo normale,ti consiglio di riferirti alla PRG italiana di Marcello.;)
Bye

hiryu

  • Utente
  • **
  • Post: 649
    • http://hiryu.netsons.org/
  • Gioco Preferito: Wizard Of Wor
Hiryu's 1st Asm Prog
« Risposta #7 il: 12 Novembre 2004, 11:58:46 »
 vi ringrazio tantissimo per le utili info... se mai ci saranno sviluppi vi terrò informati
Elwood: "E' partito un pistone"
Jake: "Poi torna?"
________________________________________________________
Hiryu @ http://hiryu.netsons.org | http://www.virb.com/hiryu

MarC=ello

  • Utente
  • **
  • Post: 337
  • Gioco Preferito: CBM BASIC 2.0
Hiryu's 1st Asm Prog
« Risposta #8 il: 12 Novembre 2004, 15:52:34 »
 
Citazione
vi ringrazio tantissimo per le utili info...

Di nulla  ;)

Citazione
Allora ti consiglio di leggere qualche guida introduttiva all'asm,ad esempio il corso di lm di Marcello.

Per quanto riguarda le IRQ, purtroppo non ho ancora trattato l'argomento interruzioni (comunque è prevista, ma non certo in tempi brevi, una seconda parte del corso). Comunque, prima è bene fissarsi i concetti più elementari, le interrupts vengono alla fine, naturalmente.

In ogni caso, raccomando come sempre il libro di Butterfield (disponibile in rete, grazie al grandissimo Whiteflame), nel quale viene spiegato per bene cos'è un'interruzione e cosa sia una IA (e il concetto di latching).

Specificamente per le interruzioni del VIC-II, consiglio l'ottimo tutorial "Interrupts on the 64" contenuto nel C= Knowledge Base, articolo n. 121. E' utilissimo anche il testo "Mapping the 64", disponibile anche questo in rete (grazie ancora a Whiteflame per la conversione in formato elettronico).

Esistono anche altri tutorial, ho citato quelli nei quali personalmente mi sono ritrovato meglio. La mia revisione della Guida di Riferimento del Programmatore per ora è ancora parziale e non tratta le interruzioni del raster, tuttavia consiglio di dare un'occhiata alla versione inglese di Project 64, anche se nell'argomento interruzioni non è certo esaustiva.

Bye.
-=MarC=ellO=-