Copy Link
Add to Bookmark
Report
Playstation GPU print example
Printgpu: example of how to plot text in assembly.
PRINTGPU.ASM
;-------------------------------------------------------------
;GPU print example. 1999 doomed/padua
;-syntax of spasm.
;-uses the caetla 8*16 font, but can be any 8*16 font (font.bin)
;-prints fixed width. If you want proportional, just add the char
; width after a plot to X, instead of 8.
;
;PrintGPU_Dma routine makes a linked list. Useful in stuff
; that plot lots off primitive.
;PrintGPU routine waits for gpu ready and plots
; without DMA. More useful for debugging.. less
; speedy, but does not require a variable amount
; of memory for the list.
;-------------------------------------------------------------
;Quick explanation:
;Simply converts character codes to UV coordinates. So if you
;want ASCII, put the characters on the texture page in ascii
;order. (32 chars of 8pixels wide besides eachother, then fill
;up the rows)
;
;PrintGPU_dma quits on a control codes (<$20) as first character
;-------------------------------------------------------------
org $80010000
; Init stuff.
lui a0, $0800 ; initialise the GPU
jal InitGPU ; command 8
ori a0,a0,$0009 ; bit $00,$01= %01 -> screen width:320
; bit $03 = 1 -> video mode = pal
la a0,back ; draw a nice backdrop
jal SendList ;
nop ;
jal Loadfont ; upload font data.
nop ;
; Plot with DMA.
la a0,text1 ; a0 = pointer to string.
li a1,$00200018 ; a1 : y<<16|x (y=$20,x=$20)
li a2,$00808080 ; a2 : bgr = 808080 = white.
jal PrintGPU_dma ; print
nop ;
jal SendList ; plot text.
or a0,zero,v0 ;
; Plot without DMA
la a0,text2 ; a0 = pointer to string.
li a1,$00600018 ; a1 : y<<16|x (y=$20,x=$20)
li a2,$00208080 ; a2 : bgr = 808080 = white.
jal PrintGPU ; print
nop ;
self j self
nop
text1 db 'Here',$27,'s yar stuff printed.',$0a,$0d,'Next line'
db $0a,'Just a linefeed..',$00
text2 db 'And here',$27,'s some more text in yellow',$2c
db $0d,$0a,'printed without DMA.'
align 4
dw $0
;-------------------------------------------------------------
include sys2.asm ; GPU routines
;-------------------------------------------------------------
txtDMA equ $0000 ; primitive offsets
txtRGB equ $0004
txtX equ $0008
txtY equ $000a
txtU equ $000c
txtV equ $000d
txtClut equ $000e
;-------------------------------------------------------------
; PrintGPU_dma
; in: a0 : pointer to string (0 terminated)
; a1 : hiword Y, loword X
; a2 : color
; out: v0 : pointer to list
;-------------------------------------------------------------
PrintGPU_dma
sw a1,cXY ; save XY
lui v0,$7400 ; type $70 = 8*8 sprite
or t2,a2,v0 ; t2 = type + color
li t3, 511<<6 ; t3 = clut (0,511)
la t0,list2 ; t0 = pointer to list entry 2, first is
; setting of texture page.
lui v0,$00ff ; t1 = DMA link to next entry
ori v0,v0,$ffff
and t1,t0,v0
lui v0,$0300
or t1,t1,v0
addiu t1,t1,$0010
lh t5,cY ; t5 = Y1
lh t4,cX ; t4 = X
addiu t6,t5,$08 ; t6 = Y2
lbu v0,$0000(a0) ; get character
nop
slti v1,v0,$0020
beq v1,zero,pgpuloop ; first char command -> quit.
nop
jr ra ; quit, return -1.
addiu v0,zero,-1 ;
pgpuloop
; find texture coords
andi v1,v0,$001f ; get loworder 5 bits
sll v1,v1,3 ; * 8 = u
srl v0,v0,5 ; get highorder 3 bits
sll v0,v0,4 ; * 16 = v
sw t1,txtDMA(t0) ; set DMA pointer top half
sw t2,txtRGB(t0) ; set type + RGB
sh t4,txtX(t0) ; set xy
sh t5,txtY(t0) ;
sb v1,txtU(t0) ; set uv
sb v0,txtV(t0) ;
sh t3,txtClut(t0) ; set clut
addiu t0,t0,$10 ; next list entry
addiu t1,t1,$10 ;
addiu v0,v0,$08 ; y=y+8
sw t1,txtDMA(t0) ; set DMA pointer bottom half
sw t2,txtRGB(t0) ; set type + RGB
sh t4,txtX(t0) ; set xy
sh t6,txtY(t0) ;
sb v1,txtU(t0) ; set uv
sb v0,txtV(t0) ;
addiu t4,t4,$08 ; x = x + 8 <- for proportional
; feed the char width here.
addiu a0,a0,$01 ; next character
lbu v0,$0000(a0)
sh t3,txtClut(t0) ; set clut
pgpuchk
slti v1,v0,$0020 ; command char?
bgtz v1,pgpucommand ; go to handler.
nop
addiu t0,t0,$10 ; update pointers
j pgpuloop
addiu t1,t1,$10 ;
pgpudone
li t1,$03ffffff ; end of list
sw t1,txtDMA(t0) ;
la v0,list ; return address of list.
jr ra ;
nop ;
pgpucommand
beq v0,zero,pgpudone ; done yet?
ori v1,zero,$000a ; linefeed = $0a
beq v0,v1,pgpuLF ;
ori v1,zero,$000d ; carriage return = $0d
beq v0,v1,pgpuCR
nop
pgpunxt
addiu a0,a0,$0001 ; not a valid command?
lbu v0,$0000(a0) ;
j pgpuchk ; skip..
nop
pgpuLF addiu t6,t6,$0010 ; handle linefeed.
j pgpunxt ; do next.
addiu t5,t5,$0010
pgpuCR lw t4,cX ; handle carriage return.
j pgpunxt ; do next.
nop
cXY
cX dh $0
cY dh $0
;-------------------------------------------------------------
;-------------------------------------------------------------
; PrintGPU - plots text to the screen without using DMA.
; in: a0 : pointer to string (0 terminated)
; a1 : hi word=Y, lo word=X
; a2 : color
;-------------------------------------------------------------
PrintGPU
or t0,zero,ra ; save RA
li t1,$e100060f ; draw mode setting.
li t2,$04000000 ; Dma transfer off command
jal WaitDone ; also sets fp to $1f800000
nop
sw t2,GP1(fp) ; DMA mode = 0
nop
sw t1,GP0(fp) ; Set texture page
sw a1,c2XY ; save XY
lui v0,$7400 ; type $70 = 8*8 sprite
or t1,a2,v0 ; t1 = type + color
lui t2, 511<<6 ; t2 = clut (0,511)
lh t4,c2Y ; t5 = Y1
lh t3,c2X ; t4 = X
addiu t5,t4,$08 ; t6 = Y2
lbu v0,$0000(a0) ; get character
nop
slti v1,v0,$0020 ; first char command -> handle.
bne v1,zero,p2gpucommand
nop
p2gpuloop
; find texture coords
andi v1,v0,$001f ; get loworder 5 bits
sll v1,v1,3 ; * 8 = u
srl v0,v0,5 ; get highorder 3 bits
sll v0,v0,4 ; * 16 = v
sll t9,v0,$8 ; V Top part
or t9,t9,v1 ; U
or t9,t9,t2 ; Clut
addiu v0,v0,$08 ;
sll t6,v0,$8 ; V Bottom part
or t6,t6,v1 ; U
or t6,t6,t2 ; Clut
; Plot top half
sll t8,t4,$10 ; Y
or t8,t8,t3 ; X
jal WaitGPU
nop
sw t1,GP0(fp) ; set type RGB
sw t8,GP0(fp) ; Y X
sw t9,GP0(fp) ; clut U V
; Bottom half
sll t8,t5,$10 ; Y
or t8,t8,t3 ; X
jal WaitGPU
nop
sw t1,GP0(fp) ; send type|BGR
sw t8,GP0(fp) ; send Y |X
sw t6,GP0(fp) ; send clut|U|V
addiu t3,t3,$08 ; x = x + 8 <- for proportional
; feed char width here.
p2gpunxt
addiu a0,a0,$01 ; next character
lbu v0,$0000(a0) ; fetch
nop ;
slti v1,v0,$0020 ; command char?->handle
bgtz v1,p2gpucommand ;
nop ;
j p2gpuloop ; otherwise plot next char.
nop
p2gpudone
or ra,zero,t0 ; return if done.
jr ra ;
nop ;
p2gpucommand
beq v0,zero,p2gpudone ; done yet?
ori v1,zero,$000a ;
beq v0,v1,p2gpuLF ; handle linefeed.
ori v1,zero,$000d ;
beq v0,v1,p2gpuCR ; handle carriage return.
nop ; discard unknown codes.
j p2gpunxt ;
p2gpuLF addiu t4,t4,$0010 ; linefeed.
j p2gpunxt ; Y=Y+$10
addiu t5,t5,$0010 ;
p2gpuCR lw t3,c2X ; carriage return.
j p2gpunxt ; X = start X.
nop
c2XY ; Temp XY storage.
c2X dh $0 ;
c2Y dh $0 ;
;-------------------------------------------------------------
; Upload the font into vram.
Loadfont
or s0,zero,ra
la a0,img ; source address font
li a1,$000003c0 ; target topleft Y|X
li a2,$00400040 ; target H|W
li a3,$00000800 ; number of words to send
jal MemtoVRAM
nop
la a0,clut ; source address clut
li a1,$01ff0000 ; target topleft Y|X
li a2,$00010010 ; target H|W
li a3,$00000008 ; number of words to send
jal MemtoVRAM
nop
or ra,zero,s0
jr ra
nop
;-------------------------------------------------------------
;The list area..
back
dw back2,back2>>8,back2>>16,$03
dw $02000000
dw $000003c0
dw $010000fe
back2 dw $08ffffff ; Primitive of gouroud 4 point polygon
dw $38300040 ; Type + bgr top left
dw $00000000 ; XY
dw $00250010 ; bgr top right
dw $00000150 ; XY
dw $00250010 ; bgr bottom left
dw $01100000 ; XY
dw $00800000 ; bgr bottom right
dw $01100150 ; XY
list db list2,list2>>8,list2>>16,$01 ;
dw $e100060f ; dtd, dfe = 1
; tpage xy = 960,0
; 4 bit clut
list2 dw $0 ; Here go the primitives
; generated by the routine.
;-------------------------------------------------------------
;Temporary data. Clut + Font image data.
;-------------------------------------------------------------
clut dh $0000,$7fff,$7fff,$7fff,$7fff,$7fff,$7fff,$7fff
dh $7fff,$7fff,$7fff,$7fff,$7fff,$7fff,$7fff,$7fff
img incbin font.bin ; this is the font.
;-------------------------------------------------------------
SYS2.ASM
;-------------------------------------------------------------
; GPU routines.
;-------------------------------------------------------------
GP0 equ $1810 ; some equ's for easy ref.
GP1 equ $1814
DPCR equ $10f0
DICR equ $10f4
D2_MADR equ $10a0
D2_BCR equ $10a4
D2_CHCR equ $10a8
;-------------------------------------------------------------
; InitGPU - basic GPU init routine
; in: a0 - display mode
;-------------------------------------------------------------
InitGPU
lui fp,$1f80
or t0,zero,ra
sw zero, GP1(fp) ; reset (command 0)
li t1, $05000000 ; display offset
jal WaitGPU ;
nop ;
sw t1, GP1(fp) ;
li t1, $06ca0220 ; horizontal start/end command 6
sw t1, GP1(fp) ; $|06|ca0|220 = 336 pixels
; x2 x1
li t1, $0704b81e ; vertical start/end command $07
sw t1, GP1(fp) ; Y start =$1e, Y end =$12e=272 pixels
sw a0, GP1(fp) ; set display mode
nop ;
li t1, $e10006cf ; draw mode
sw t1, GP0(fp) ; command $e1 set draw mode
; data: bit $17-$0b = 0
; bit $0a-$00: %1|1|01|10|0|0101
; a|b|c |d |e|f
; A: DFE=$1 (Draw to display area allowed)
; B: DTD=$1 (Dither on)
; C: TP =$1 (8bit clut mode)
; D: ABR=$0 (half transparancy 0.5F+0.5B)
; E: TY =$0 (Texture page at Y=0*256= 0)
; F: TX =$f (Texture page at X=15*64=960)
li t1, $e3000000 ; clip start command $e3
sw t1, GP0(fp) ; bit $0a-$00= X, bit $14-$0b = Y
; sets top left corner of drawing area
li t1, $e407429f ; clip end command $e4
sw t1, GP0(fp) ; set bottom right of drawing area
; X = bit $09-$00 =$014f $29f
; Y = bit $13-$0a =$0110 $110
li t1, $e5000000 ; draw offset
sw t1, GP0(fp) ;
li t1, $03000000 ; enable display
sw t1, GP1(fp) ;
or ra,zero,t0
jr ra
nop
;-------------------------------------------------------------
; SendList - sends a list of primitives to GPU
; in: a0 - address of list
;-------------------------------------------------------------
SendList
lui fp,$1f80
or t0, zero, ra
li t2, $04000002
jal WaitGPU
nop
lw t3, DPCR(fp)
sw zero, DICR(fp)
ori t3, t3, $0800
sw t3, DPCR(fp)
sw t2, GP1(fp)
sw a0, D2_MADR(fp)
sw zero, D2_BCR(fp)
li t1, $01000401
sw t1, D2_CHCR(fp)
or ra, zero, t0
jr ra
nop
;-------------------------------------------------------------
; MemtoVRAM - transfer graphic data to VRAM.
; in: a0 - source address
; a1 - x,y (y << 16 | x)
; a2 - w,h (h << 16 | w)
; a3 - amount to copy (in words)
;-------------------------------------------------------------
MemtoVRAM
or t4,zero,ra ; save RA
jal WaitDone ; wait for idle + DMA finish.
nop
or t5,zero,a0 ; save start addy.
lui at,>mvl1 ;
sw a1,<mvl1(at) ; set XY
sw a2,<mvl2(at) ; set HW
lui a0,>mvl ; send transfer setup.
jal SendList ;
ori a0,a0,<mvl ;
sll t1,a3,$10 ; set number of dma blocks.
ori t1,t1,$0001 ; set block size to 1 word.
li t2,$01000201 ; dma control: continuous, mem->vram
jal WaitDMA ; Wait for setup to complete
nop ;
sw t5,D2_MADR(fp) ; set base address
sw t1,D2_BCR(fp) ; set block control
sw t2,D2_CHCR(fp) ; start dma
or ra, zero, t4 ; return.
jr ra ;
nop
mvl dw $04ffffff
dw $01000000
dw $a0000000
mvl1 dw $00000000
mvl2 dw $00000000
;-------------------------------------------------------------
; WaitGPU - waits until GPU ready to recieve commands
;-------------------------------------------------------------
WaitGPU
lui fp,$1f80
lw v1, GP1(fp) ; load status word from GPU
lui v0, $1000 ; load bit $1c
and v1, v1, v0 ; and out all but bit $1c
beqz v1, WaitGPU ; bit $1c = 0 -> GPU is busy
nop
jr ra
nop
;-------------------------------------------------------------
; WaitIdle - waits until GPU is idle
;-------------------------------------------------------------
WaitIdle
lui fp,$1f80
lui v1, $0400
widl lw v0, GP1(fp)
nop
and v0, v0, v1
beqz v0, widl
nop
jr ra
nop
;-------------------------------------------------------------
; WaitDone - waits for DMA & GPU to be idle.
;-------------------------------------------------------------
WaitDone
lui fp, $1f80
wd1 lw v0, D2_CHCR(fp)
lui v1, $0100
and v0, v0, v1
bne v0, zero, wd1
nop
wd2 lw v0, GP1(fp)
lui v1, $0400
and v0, v0, v1
beq v0, zero, WaitDone
nop
jr ra
nop
;-------------------------------------------------------------
; WaitDMA - waits for DMA idle.
;-------------------------------------------------------------
WaitDMA
lui fp, $1f80
wdmalp lw v0, D2_CHCR(fp)
lui v1, $0100
and v0, v0, v1
bne v0, zero, wdmalp
nop
jr ra
nop