lundi 23 février 2009

Exemple d'interruption sur Vblank

Dans cet exemple on va simplement desactiver le Background grâce au Vblank interrupt sur IRQ1. A l'aide d'un compteur initialisé à 60 et décrémenté à chaque Vblank, on désactivera l'affichage lorque celui arrivera à 0 (ce qui doit faire une seconde).

Cet exemple sert surtout à comprendre comment fonctionne les IRQs sur PC Engine.
Quelque soit l'interruption provoqué par le VDC, c'est l'irq1 qui receptionne, du coup il est important de tester tous les bits du VDC Status Register $0000, ce qui nous permettra d'identifier l'origine de l'interruption.

Pour cela nous avons l'instruction BBS ou BBR qui testera le bit voulu et effectuera un branchement en fonction de son statut.

L'ensemble des sources (code et binaires) est disponible ici : vblank_irq.7z

; ----------------
; DISPLAY A BACKGROUND
; 02/03/2009
; Enguerrand SOULIER
; -----------------

vdc_sr = $20F6 ; vdc status register copy
bg_display = $20F7 ; vdc control register copy

.org $2200
irq_cnt: .ds 1

.bank 0
.org $FFF6

.dw _irq2
.dw _irq1
.dw _timer
.dw _nmi
.dw _reset

.org $E000
.db "Create by Peperocket"

; -------------
; INTERRUPT HANDLER
; -------------

_irq2:
nop
rti

_irq1:
pha
lda $0000
sta vdc_sr ; copy of video status register
bbs5 vdc_sr,l5 ; goto l5 if vblank
pla
rti

_timer:
pha
stz $1403 ; write for avoid infinity loop !
rti

_nmi:
nop
rti

_reset:
sei
csh
cld

lda #$FF
tam #0

lda #$F8
tam #1

stz $2000
tii $2000,$2001,$1FFF

ldx #$FF
txs

lda #$01
tam #2

lda #$3C
sta $2200

jmp main

;------------------------
; vsync interrupt
; ----------------------

l5:
dec irq_cnt
beq .cnt_int ; if equal zero, goto cnt_int for disable display
pla
rti

.cnt_int:
st0 #5 ; disable display
lda #$00
sta $0002
pla
rti

; -------------
; CODE
; -------------
main:
cli
lda #$05 ; enable irq1
sta $1402

st0 #5 ; disable display
lda #$00
sta $0002

st0 #$0B ; HDR Horizontal Display Width for 256*240 display
st1 #$1F
st2 #$03

st0 #$0D ; VDR Vertical Diplay Width for 256*240 display
st1 #$EF
st2 #$00


st0 #9 ; init bat size 32*32
st1 #0
st2 #0

d01:
lda #bank(test_set)
tam #page(test_set)
inc a
tam #3
inc a
tam #4
inc a
tam #5
inc a
tam #6

st0 #0
st1 #0
st2 #$10
st0 #2

tia test_set,$0002,$7000


d02:
lda #bank(test_pal)
tam #page(test_pal)

stz $402
stz $403
tia test_pal,$404,$200

d03:
lda #bank(test_map)
tam #page(test_map)

st0 #0
st1 #0
st2 #0
st0 #2
tia test_map,$0002,$700

st0 #5
lda #$C8
sta $0002

.inf_loop:
jmp .inf_loop

; -----------
; DATA
; -----------
.bank 1
.org $4000

test_pal:
.incbin "pce_pal.bin"

test_map:
.incbin "pce_map.bin"

test_set:
.incbin "pce_set.bin"

J'utiliserais le timer la prochaine fois pour vous montrer comment on fait clignoter un background ou un sprite....

dimanche 15 février 2009

Les TILES en VRAM, mode PLANAR

Pour rappel :
  • Un background sur PC Engine est composé de tiles.
  • Une tile fait 8*8 pixels et est associée à une palette de 16 couleurs.
  • 16 palettes sont disponibles donc ça nous ferait 256 couleurs si la couleur couleur 0 (transparente) n'était pas sur chaque palette, ce qui nous fait quand même 240 couleurs.
  • Chaque pixel dans une tile est codé sur 4bits (donc 16 possibilités) qui correspond a une couleur de sa palette.
  • Une tile et sa palette sont associées par la BAT (Background Attribut Table).
  • Les donnés en VRAM sont en WORD (16bits) et non en BYTE (8bits) le processeur graphique étant 16 bits !

Mais comment sont ordonnées les tiles en VRAM ?

Vram offset
  • 0 [ Bytes 1 & 2 ] Line 1
  • 2 [ Bytes 1 & 2 ] Line 2
  • 4 [ Bytes 1 & 2 ] Line 3
  • 6 [ Bytes 1 & 2 ] Line 4
  • 8 [ Bytes 1 & 2 ] Line 5
  • 10 [ Bytes 1 & 2 ] Line 6
  • 12 [ Bytes 1 & 2 ] Line 7
  • 14 [ Bytes 1 & 2 ] Line 8
  • 16 [ Bytes 3 & 4 ] Line 1
  • etc ...
Dans le mode PLANAR, les 4bits qui forment l'index de couleur sont stockés dans 4 différents bytes.

Pour la ligne 1, le byte 1 sera composé du premier bit de chaque pixel et le byte 2 sera quand à lui composé du deuxiéme byte de chaque pixel, qui composent au final le WORD (16bits). On fera de même pour toutes les lignes et on terminera enfin avec les bits 3 et 4 des 8 lignes, 16 bytes plus tard ;)

Enfin il en est de même pour les sprites (16*16 pixels) sauf que ceux ci ne seront pas entrelacés, on aura donc les 4 bytes de chaque ligne, placés consécutivements en VRAM.