Autore Topic: Combinare Cia + Raster Irqs  (Letto 2512 volte)

Elder0010

  • Utente
  • **
  • Post: 75
    • http://csdb.dk/scener/?id=22731
  • Gioco Preferito: Rampage
Combinare Cia + Raster Irqs
« il: 22 Maggio 2011, 23:28:35 »
 I CIA irqs e i Raster interrupts possono coesistere durante l'esecuzione di un programma?

Ho provato a modificare questo codice inserendo un interrupt raster, in modo da combinare l'utilizzo di cia interrupts (per scatenare eventi con un timer) e raster interrupts (per eventi sincronizzati al raster).

(Nella mia versione, la parte superiore dello schermo viene distorta alterando $d016).

Non riesco a capire però cosa c'è di sbagliato nell'impostazione del raster interrupt, in quanto non viene mai eseguito!

Commentando le linee:
Codice: [Seleziona]
lda #$35; Select big bank without roms
sta $01 ; Change to big bank

il cia irq non viene eseguito perchè la zona di memoria dei vettori è occupata dalla kernal rom, giusto? (spero di aver capito bene). In questo caso, il raster irq si comporta correttamente.

Deduco quindi che ci sia un conflitto nel setup dei due interrupts.

Codice: [Seleziona]
*=$0801
.byte $0a,$08,$0a,$00,$9e,$32,$30,$36,$32
.byte $00,$00,$00,$00; a BASIC SYS LINE FOR STARTING CODE AT $080E  
*=$080e

  sei
  ldx #$ff
  txs ; Reset Stack pointer

;Via la rom, mappo piu ram
  lda #$35; Select big bank without roms
  sta $01 ; Change to big bank

;punto irq CIA
  lda #<irq
  sta $fffe; Set low IRQ adress in selected bank
  lda #>irq
  sta $ffff; Set high IRQ adress in selected bank


;Abilito tutti gli interrupts
;generati dai timer
  lda #$7f
  sta $dc0d; Clear IRQ interruptmask for CIA



;Timer A control register. Bits:
;Bit #0: 0 = Stop timer; 1 = Start timer.
;Bit #1: 1 = Indicate timer underflow on port B bit #6.
;Bit #2: 0 = Upon timer underflow, invert port B bit #6; 1 = upon timer underflow, generate a positive edge on port B bit #6 for 1 system cycle.
;Bit #3: 0 = Timer restarts upon underflow; 1 = Timer stops upon underflow.
;Bit #4: 1 = Load start value into timer.
;Bit #5: 0 = Timer counts system cycles; 1 = Timer counts positive edges on CNT pin.
;Bit #6: Serial shift register direction; 0 = Input, read; 1 = Output, write.
;Bit #7: TOD speed; 0 = 60 Hz; 1 = 50 Hz.

  lda $dc0e
  ora #%10011000
  and #%11110110
  sta $dc0e; count o2 pulses and forceload and continious and stop


  ; timer A
  tay ; Save for later use in y


;4cc7 = un frame
  lda #$c7; Cia time $4cc7 is a frame on a pal system with old
   ; cia (6526) 63 cycles per line * 312 lines - 1
  sta $dc04

  lda #$4c
  sta $dc05; Set timer A to one frame



  lda #$81
  sta $dc0d; Activate CIA timer A irq

  tya
  ora #%00000001 ; Start CIA Timer A
  sta $dc0e

  lda #<interrupt1
  ldx #>interrupt1
  sta $314
  stx $315

  lda #$01
  sta $d012
      
  asl $d019
  
  
  lda #$01
  sta $d01a ; Accendi  raster interrupts
  
  
   cli
   jmp * ; do nothing while no IRQ, just jump to this line

interrupt1
           inc $d020    

           asl $d019   ; ACK interrupt
           pla
           tay
           pla
           tax
           pla
           rti          


;CIA IRQ
irq

   php ; 3 cycles
   pha ; 3 cycles
   lda $dc0d; 4 cycles;Acknowledge CIA timer a interrupt

   tya ; 2 cycles
   pha ; 4 cycles
   txa ; 2 cycles
   pha ; 4 cycles


   lda $d012
   cmp #$90
   bpl skip

  ;Shakero lo schermo
   lda $d011
   ora #%00011011
   sta $d011

   dec $d016
   inc $d016
  
   lda $d016
   ora #%00000111
   sta $d016

   lda $d016
   and #%00000110
   sta $d016

   lda $d016
   and #%00000100
   sta $d016

   lda $d016
   and #%00000101
   sta $d016

   inc $d016
  
   lda $d016
   and #%00000011
   sta $d016

   lda $d016
   and #%00000001
   sta $d016

  
   inc $d016
  
   lda $d016
   and #%00000000
   sta $d016
skip


   pla
   tax
   pla
   tay
   pla
   plp
   rti

Spero di non aver fatto troppi strafalcioni al solito :)  
lda #0 sta $d020 sta $d021

Freshness79

  • Utente
  • **
  • Post: 128
  • Gioco Preferito: Dizzy collection
Combinare Cia + Raster Irqs
« Risposta #1 il: 23 Maggio 2011, 14:29:06 »
 Finalmente un post giusto nel posto giusto!
A buoni intenditori...
Allora Elder, premesso che i CIA sono gli integrati che conosco di meno nel biscottone, credo comunque di poterti chiarire le idee almeno su come si comporta il primo dei due.
Il punto focale é che il 6510 ha un solo piedino IRQ (più un NMI ma non c'entra con questo discorso).
Ciò comporta due cose:
- qualsiasi sorgente di interruzione (VIC/CIA/Porta espansione..) deve necessariamente agire su quel pin per 'triggerare' un IRQ
- il 6510 non ha nessun modo "autonomo" per capire chi possa aver generato l'IRQ: lui sa solo che deve salvare lo status flag e l'IP e poi saltare alla routine puntata da $fffe/$ffff

Nella tua routine avevi impostato $fffe/$ffff e $0314/$0315: impostare la prima é coppia é corretto, impostare la seconda é inutile.
Mi spiego meglio.
Il 6510, in risposta ad un IRQ, salta sempre (SEMPRE!) all'indirizzo puntato da $fffe/$ffff. Ora, se il kernal é attivo (leggi, se le ROM sono visibili) tale coppia viene letta appunto dalla ROM e punta all'handler del kernal(indirizzo $ff48). Questo handler in sostanza va ad eseguire a sua volta la routine puntata da $0314/$0315.
Ecco da dove arriva la seconda coppia.
E' chiaro che levando la ROM sparisce il puntamento ad $ff48 e perciò $0314/$0315 diventano due locazioni come le altre.
Il punto quindi é determinare nell'unico handler a disposizione chi sia stato a produrre l'IRQ; ci sono almeno due modi per risolvere il problema, io ho scelto quello che mi ricordo meglio.
- puoi leggere il bit 7 di $d019 (quando é attivo significa che é stato generato un IRQ dal VIC)
- puoi leggere non-mi-ricordo-dove nel CIA1 (in modo analogo c'é un bit che indica se é stato generato un IRA dal CIA1)
Altro miniappunto: negli interrupt handler non serve salvare lo status flag perché ci pensa il processore quando esegue l'IRQ (ed in modo analogo ripristina il flag con RTI).

Il codice (ho modificato qualcosina anche sulla parte di vibrazione anche se probabilmente non é come la intendevi tu).

Codice: [Seleziona]
*=$0801
.byte $0a,$08,$0a,$00,$9e,$32,$30,$36,$32
.byte $00,$00,$00,$00; a BASIC SYS LINE FOR STARTING CODE AT $080E
*=$080e

sei
; Blocco l'NMI altrimenti salta tutto (manca l'handler del NMI)!
lda #$7f
sta $dd0d
lda $dd0d

ldx #$ff
txs; Reset Stack pointer

;Via la rom, mappo piu ram
lda #$35; Select big bank without roms
sta $01; Change to big bank

;punto irq CIA
lda #<irq
sta $fffe; Set low IRQ adress in selected bank
lda #>irq
sta $ffff; Set high IRQ adress in selected bank


;Abilito tutti gli interrupts
;generati dai timer
lda #$7f
sta $dc0d; Clear IRQ interruptmask for CIA



;Timer A control register. Bits:
;Bit #0: 0 = Stop timer; 1 = Start timer.
;Bit #1: 1 = Indicate timer underflow on port B bit #6.
;Bit #2: 0 = Upon timer underflow, invert port B bit #6; 1 = upon timer underflow, generate a positive edge on port B bit #6 for 1 system cycle.
;Bit #3: 0 = Timer restarts upon underflow; 1 = Timer stops upon underflow.
;Bit #4: 1 = Load start value into timer.
;Bit #5: 0 = Timer counts system cycles; 1 = Timer counts positive edges on CNT pin.
;Bit #6: Serial shift register direction; 0 = Input, read; 1 = Output, write.
;Bit #7: TOD speed; 0 = 60 Hz; 1 = 50 Hz.

lda $dc0e
ora #%10011000
and #%11110110
sta $dc0e; count o2 pulses and forceload and continious and stop


; timer A
tay; Save for later use in y

waitrst; allineo il CIA ad una certa posizione dello schermo
lda $d012
cmp #$90
bne waitrst

;4cc7 = un frame
lda #$c7; Cia time $4cc7 is a frame on a pal system with old
; cia (6526) 63 cycles per line * 312 lines - 1
sta $dc04

lda #$4c
sta $dc05; Set timer A to one frame



lda #$81
sta $dc0d; Activate CIA timer A irq

tya
ora #%00000001; Start CIA Timer A
sta $dc0e

lda #$01
sta $d012

asl $d019


lda #$01
sta $d01a; Accendi raster interrupts


cli
jmp *; do nothing while no IRQ, just jump to this line

IRQbyVic
inc $d020

asl $d019; ACK interrupt
jmp skip

;CIA IRQ
irq

pha; 3 cycles
txa; 2 cycles
pha; 4 cycles
tya; 2 cycles
pha; 4 cycles
bit $d019; E' stato il VIC a generare l'IRQ
bmi IRQbyVic; Si => vai alla routine specifica
IRCbyCIA  
; No, allora é stato il timer del CIA
lda $dc0d; 4 cycles;Acknowledge CIA timer a interrupt

;Shakero lo schermo
lda $d011
eor #%00000111
sta $d011

lda $d016
eor #%00000111
sta $d016

skip  ; Da qua escono entrambi gli IRQ
pla
tay
pla
tax
pla
rti


Elder0010

  • Utente
  • **
  • Post: 75
    • http://csdb.dk/scener/?id=22731
  • Gioco Preferito: Rampage
Combinare Cia + Raster Irqs
« Risposta #2 il: 23 Maggio 2011, 22:34:57 »
 Ok, estendendo la ram le location $314/$315 diventano come tutte le altre! ecco perchè il mio irq non veniva mai eseguito!

Su indicazioni di Ian, aggiungo il disassemblato della zona puntata da $FFFE (cioè $FF48):

Codice: [Seleziona]
.C:ff48   48         PHA
.C:ff49   8A         TXA
.C:ff4a   48         PHA
.C:ff4b   98         TYA
.C:ff4c   48         PHA
.C:ff4d   BA         TSX
.C:ff4e   BD 04 01   LDA $0104,X
.C:ff51   29 10      AND #$10
.C:ff53   F0 03      BEQ $FF58
.C:ff55   6C 16 03   JMP ($0316)
.C:ff58   6C 14 03   JMP ($0314); <- puntamento all'IRQ settato normalmente
.C:ff5b   20 18 E5   JSR $E518
.C:ff5e   AD 12 D0   LDA $D012
.C:ff61   D0 FB      BNE $FF5E
.C:ff63   AD 19 D0   LDA $D019
.C:ff66   29 01      AND #$01
.C:ff68   8D A6 02   STA $02A6
.C:ff6b   4C DD FD   JMP $FDDD
.C:ff6e   A9 81      LDA #$81
.C:ff70   8D 0D DC   STA $DC0D

Inoltre, è possibile controllare tramite il bit #7 di $DC0D se un interrupt è stato generato!

Ora è chiaro: complicando un po' le cose, mi chiedo se questo schema può funzionare (scrivo in pseudocodice)

Codice: [Seleziona]
- init del sistema
- punto cia_interrupt_1

jmp *
- cia_interrupt_1
bit $d019; E' stato il VIC a generare l'IRQ
bmi raster_interrupt_handle; Si => vai alla routine specifica

...codice cia interrupt...distorci schermo
jmp uscita

- raster_interrupt_handle
  cmp $d012
     -> se maggiore di $40 jmp raster_interrupt_1
     -> se maggiore di $80 jmp raster_interrupt_2

- raster_interrupt_1
  ...codice raster interrupt 1
jmp uscita

- raster_interrupt_2
  ...codice raster interrupt 2
jmp uscita

- uscita dall'interrupt (tutti i casi)
pla
tay
pla
tax
pla
rti

In questo caso avremmo lo schermo splittato dai due raster interrupt, e la distorsione temporizzata dal cia, tutto gestito con un solo handler!
lda #0 sta $d020 sta $d021

Elder0010

  • Utente
  • **
  • Post: 75
    • http://csdb.dk/scener/?id=22731
  • Gioco Preferito: Rampage
Combinare Cia + Raster Irqs
« Risposta #3 il: 29 Maggio 2011, 17:14:33 »
 Ho meditato un po' sulla questione: in realtà la soluzione che ho proposto in pseudocodice non risponde alla mia domanda perchè effettua semplicemente un controllo sulla rasterline, invece di gestire cia + raster irqs.

Ho pensato quindi di generare 3 irq: uno cia e due raster, in sequenza.

Il cia irq viene chiamato una volta per frame: fa il suo lavoro, e poi si occupa di puntare al primo raster irq.
Idem per il primo raster irq, che punta al secondo, e poi il giro ricomincia da capo. Spero sia corretto!

Codice: [Seleziona]

*=$0801
.byte $0a,$08,$0a,$00,$9e,$32,$30,$36,$32
.byte $00,$00,$00,$00; a BASIC SYS LINE FOR STARTING CODE AT $080E
*=$080e

sei
; Blocco l'NMI altrimenti salta tutto (manca l'handler del NMI)!
lda #$7f
sta $dd0d
lda $dd0d

ldx #$ff
txs; Reset Stack pointer

;Via la rom, mappo piu ram
lda #$35; Select big bank without roms
sta $01; Change to big bank

;punto irq CIA
lda #<irq
sta $fffe; Set low IRQ adress in selected bank
lda #>irq
sta $ffff; Set high IRQ adress in selected bank


;Abilito tutti gli interrupts
;generati dai timer
lda #$7f
sta $dc0d; Clear IRQ interruptmask for CIA



;Timer A control register. Bits:
;Bit #0: 0 = Stop timer; 1 = Start timer.
;Bit #1: 1 = Indicate timer underflow on port B bit #6.
;Bit #2: 0 = Upon timer underflow, invert port B bit #6; 1 = upon timer underflow, generate a positive edge on port B bit #6 for 1 system cycle.
;Bit #3: 0 = Timer restarts upon underflow; 1 = Timer stops upon underflow.
;Bit #4: 1 = Load start value into timer.
;Bit #5: 0 = Timer counts system cycles; 1 = Timer counts positive edges on CNT pin.
;Bit #6: Serial shift register direction; 0 = Input, read; 1 = Output, write.
;Bit #7: TOD speed; 0 = 60 Hz; 1 = 50 Hz.

lda $dc0e
ora #%10011000
and #%11110110
sta $dc0e; count o2 pulses and forceload and continious and stop


; timer A
tay; Save for later use in y



;4cc7 = un frame
lda #$c7; Cia time $4cc7 is a frame on a pal system with old
; cia (6526) 63 cycles per line * 312 lines - 1
sta $dc04

lda #$4c
sta $dc05; Set timer A to one frame


waitrst; allineo il CIA ad una certa posizione dello schermo
lda $d012
cmp #$80
bne waitrst

lda #$ff
sta $dc0d; Activate CIA timer A irq

tya
ora #%00000001; Start CIA Timer A
sta $dc0e

lda #$01
sta $d012

asl $d019


lda #$01
sta $d01a; Accendi raster interrupts


cli
jmp *; do nothing while no IRQ, just jump to this line


;CIA IRQ
irq


bit $d019; E' stato il VIC a generare l'IRQ
bmi raster_interrupt_handle; Si => vai alla routine specifica

IRCbyCIA  
; No, allora é stato il timer del CIA

pha; 3 cycles
txa; 2 cycles
pha; 4 cycles
tya; 2 cycles
pha; 4 cycles



lda #$80
cmp $d012
BPL skip


;Shakero lo schermo

lda $d016
eor #%00000111
sta $d016


lda #<raster_irq
sta $fffe;
lda #>raster_irq
sta $ffff;

;Il prossimo evento deve essere un raster irq
lda #$ff
sta $d012


lda $dc0d; 4 cycles;Acknowledge CIA timer a interrupt

jmp skip

raster_interrupt_handle

lda #$ff
cmp $d012
BPL raster_irq_2
    
raster_irq

pha; 3 cycles
txa; 2 cycles
pha; 4 cycles
tya; 2 cycles
pha; 4 cycles
  
inc $d020


lda #$ff
sta $d012

;Il prossimo evento deve essere il Raster interrupt 2
lda #<raster_irq_2
sta $fffe;
lda #>raster_irq_2
sta $ffff;

asl $d019
  
jmp skip


raster_irq_2

pha; 3 cycles
txa; 2 cycles
pha; 4 cycles
tya; 2 cycles
pha; 4 cycles

dec $d020

inc $0400
  
;Il prossimo evento deve essere il CIA interrupt
lda #<irq
sta $fffe;
lda #>irq
sta $ffff;

asl $d019

jmp skip

skip ; Da qua escono tutti gli IRQ


pla
tay
pla
tax
pla
rti
lda #0 sta $d020 sta $d021