Copy Link
Add to Bookmark
Report

Playstation GPU print example

Printgpu: example of how to plot text in assembly.

PS_2's profile picture
Published in 
Playstation
 · 25 Jun 2021

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

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT