mirror of
https://github.com/Ed94/pikuma_ps1.git
synced 2026-06-01 18:41:13 -07:00
graphics_system -> graphics_hello
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
; Symbol Alias Table
|
||||
|
||||
; Instructions
|
||||
; Load
|
||||
load_addr equ la ;
|
||||
load_imm equ li ; dst_reg, immeidate value (signed)
|
||||
load_uimm equ lui ; dst_reg, immediate value (unsigned)
|
||||
load_word equ lw ; dst_reg, offset(src_reg0) (offset is immediate value)
|
||||
; Store
|
||||
store_word equ sw ; src_reg, dst_address
|
||||
; Shift
|
||||
shift_ll equ sll ;
|
||||
shift_rl equ srl ;
|
||||
shift_ra equ sra ;
|
||||
; Addition
|
||||
add_s equ add ; dst_reg, reg_a, reg_b (signed)
|
||||
add_u equ add ; dst_reg, reg_a, reg_b (unsigned)
|
||||
add_si equ addi ; dst_reg, src_reg, immediate value (signed)
|
||||
add_ui equ addiu ; dst_reg, src_reg, immediate value (unsigned)
|
||||
; Subtraction
|
||||
sub_s equ sub ;
|
||||
sub_u equ subu ;
|
||||
; Multiplication
|
||||
|
||||
; Division
|
||||
div_s equ div ;
|
||||
div_u equ divu ;
|
||||
mov_from_high equ mfhi ;
|
||||
mov_from_low equ mflo ;
|
||||
; Branch
|
||||
branch_ne_zero equ bnez ;
|
||||
branch_equal equ beq ; reg, value(reg, immediate), dst_label
|
||||
branch_gt_equal equ bge ; reg, value(reg, immediate), dst_label
|
||||
branch_gt equ bgt ; reg, value(reg, immediate), dst_label
|
||||
branch_lt equ blt ; reg, value(reg, immediate), dst_label
|
||||
; Jump
|
||||
jump equ j ; address: immediate
|
||||
jump_nlink equ jal ; subroutine: immeidate
|
||||
jump_reg equ jr ; address: register
|
||||
jump_nreg equ jrl ; subroutine: register
|
||||
|
||||
; Registers
|
||||
; Stack
|
||||
rstack_ptr equ $sp ; I have this but won't really use the alias..
|
||||
; Temporaries, may be changed by subroutines
|
||||
rtmp_0 equ $t0
|
||||
rtmp_1 equ $t1
|
||||
rtmp_2 equ $t2
|
||||
rtmp_3 equ $t3
|
||||
rtmp_4 equ $t4
|
||||
; Static Variables
|
||||
rstatic_0 equ $s0
|
||||
rstatic_1 equ $s1
|
||||
rstatic_2 equ $s2
|
||||
rstatic_3 equ $s3
|
||||
rstatic_4 equ $s4
|
||||
rstatic_5 equ $s5
|
||||
rstatic_6 equ $s6
|
||||
rstatic_7 equ $s7
|
||||
; Subroutine arguments
|
||||
rarg_0 equ $a0
|
||||
rarg_1 equ $a1
|
||||
rarg_2 equ $a2
|
||||
rarg_3 equ $a3
|
||||
; Subroutine return values
|
||||
rret_0 equ $v0
|
||||
rret_1 equ $v1
|
||||
; Subroutine return address when doing a sub
|
||||
rret_addr equ $ra
|
||||
|
||||
; Data Widths
|
||||
byte equ 1
|
||||
word equ 4
|
||||
|
||||
.macro stack_alloc, amount
|
||||
add_ui $sp, - amount
|
||||
.endmacro
|
||||
|
||||
.macro stack_release, amount
|
||||
add_ui $sp, amount
|
||||
.endmacro
|
||||
@@ -0,0 +1,208 @@
|
||||
; IO PORT
|
||||
IO_BASE_ADDR equ 0x1F80 ; IO Ports Memory map base address
|
||||
|
||||
; GPU Registers
|
||||
gpio_port0 equ 0x1810 ; 1F801810h-Write GP0: Send GP0 Commands/Packets (Rendering and VRAM Access)
|
||||
gpio_port1 equ 0x1814 ; 1F801814h-Write GP1: Send GP1 Commands (Display Control) (and DMA Control)
|
||||
|
||||
; GPU Command Format: [7:8] Command (8-bit), [0:6] Paraemter (24-bit)
|
||||
|
||||
gcmd_offset equ 24
|
||||
|
||||
gp_Reset equ 0x0 << gcmd_offset
|
||||
|
||||
; GP1(03h) - Display Enable
|
||||
; On: 0x0
|
||||
; Off: 0x1
|
||||
gp_DisplayEnabled equ 0x03 << gcmd_offset | 0x0
|
||||
gp_DisplayDisabled equ 0x03 << gcmd_offset | 0x1
|
||||
|
||||
; GP1(04h) - DMA Direction / Data Request
|
||||
; 0-1 DMA Direction (0=Off, 1=FIFO, 2=CPUtoGP0, 3=GPUREADtoCPU) ;GPUSTAT.29-30
|
||||
; 2-23 Not used (zero)
|
||||
gp_DMA_FIFO equ 1
|
||||
gp_DMA_CPU_to_GPU equ 2
|
||||
gp_DMA_GPU_to_CPU equ 3
|
||||
gp_DMA_Request equ 0x04 << gcmd_offset
|
||||
|
||||
; GP1(06h) - Horizontal Display range (on Screen)
|
||||
; X2 = X1 + pixels * cycles_per_pix
|
||||
; 0 - 11 X1 (260h + 0) ; 12bit ; \ counted in video clock units,
|
||||
; 12 - 23 X2 (260h + 320 * 8) ; 12bit ; / relative to HSYNC
|
||||
gp_HorizontalDisplayRange_3168_608 equ 0x06 << gcmd_offset | 0xC60 << 12 | 0x260
|
||||
|
||||
; GP1(07h) - Vertical Display range (on Screen)
|
||||
; 0 - 9 Y1 (NTSC = 88h - (240 / 2), (PAL = A3h - (288 / 2)) ; \ scanline numbers on screen,
|
||||
; 10 - 19 Y2 (NTSC = 88h + (240 / 2), (PAL = A3h + (288 / 2)) ; / relative to VSYNC
|
||||
; 20 - 23 Not used (zero)
|
||||
gp_VerticalDiplayRange equ 0x07 << gcmd_offset
|
||||
gp_VerticalDisplayRange_264_24 equ gp_VerticalDiplayRange | 264 << 10 | 24
|
||||
gp_VerticalDisplayRange_504_24 equ gp_VerticalDiplayRange | 504 << 10 | 24
|
||||
|
||||
; GP1(08h) - Display mode
|
||||
; 0-1 Horizontal Resolution 1 (0=256, 1=320, 2=512, 3=640) ;GPUSTAT.17-18
|
||||
; 2 Vertical Resolution (0=240, 1=480, when Bit5=1) ;GPUSTAT.19
|
||||
; 3 Video Mode (0=NTSC/60Hz, 1=PAL/50Hz) ;GPUSTAT.20
|
||||
; 4 Display Area Color Depth (0=15bit, 1=24bit) ;GPUSTAT.21
|
||||
; 5 Vertical Interlace (0=Off, 1=On) ;GPUSTAT.22
|
||||
; 6 Horizontal Resolution 2 (0=256/320/512/640, 1=368) ;GPUSTAT.16
|
||||
; 7 Flip screen horizontally (0=Off, 1=On, v1 only) ;GPUSTAT.14
|
||||
; 8-23 Not used (zero)
|
||||
gp_DisplayMode equ 0x8 << gcmd_offset
|
||||
gp_Disp_HRes_256 equ 0x0
|
||||
gp_Disp_HRes_320 equ 0x1
|
||||
gp_Disp_HRes_512 equ 0x2
|
||||
gp_Disp_HRes_640 equ 0x3
|
||||
gp_Disp_VRes_240 equ 0x0 << 2
|
||||
gp_Disp_VRes_480 equ 0x1 << 2
|
||||
gp_Disp_Color15 equ 0x0 << 4
|
||||
gp_Disp_Color24 equ 0x1 << 4
|
||||
gp_Disp_VInterlace equ 0x1 << 5
|
||||
gp_DisplayMode_320x240_15bit_NTSC equ gp_DisplayMode | gp_Disp_HRes_320 | gp_Disp_VRes_240 | gp_Disp_Color15
|
||||
gp_DisplayMOde_640x480_24bbp_NTSC equ gp_DisplayMode | gp_Disp_HRes_640 | gp_Disp_VRes_480 | gp_Disp_Color24 | gp_Disp_VInterlace
|
||||
|
||||
;GP0(E1h) - Draw Mode setting (aka "Texpage")
|
||||
; 0 - 3 Texture page X Base (N * 64) (ie. in 64-halfword steps) ; GPUSTAT.0-3
|
||||
; 4 Texture page Y Base 1 (N * 256) (ie. 0, 256, 512 or 768) ; GPUSTAT.4
|
||||
; 5 - 6 Semi-transparency (0 = B / 2 + F / 2, 1 = B + F, 2 = B - F, 3 = B + F / 4) ; GPUSTAT.5-6
|
||||
; 7 - 8 Texture page colors (0 = 4 bit, 1 = 8bit, 2 = 15bit, 3 = Reserved) ; GPUSTAT.7-8
|
||||
; 9 Dither 24bit to 15bit (0=Off / strip LSBs, 1 = Dither Enabled) ; GPUSTAT.9
|
||||
; 10 Drawing to display area (0=Prohibited, 1=Allowed) ; GPUSTAT.10
|
||||
; 11 Texture page Y Base 2 (N * 512) (only for 2 MB VRAM) ; GPUSTAT.15
|
||||
; 12 Textured Rectangle X-Flip (BIOS does set this bit on power-up...?)
|
||||
; 13 Textured Rectangle Y-Flip (BIOS does set it equal to GPUSTAT.13...?)
|
||||
; 14 - 23 Not used (should be 0)
|
||||
; 24 - 31 Command (E1h)
|
||||
gp_ModeSetting_DrawAllowed equ 10
|
||||
gp_ModeSetting_DipArea equ 0xE1 << gcmd_offset | 0x1 << gp_ModeSetting_DrawAllowed
|
||||
|
||||
; GP0(E3h) - Set Drawing Area top left (X1,Y1)
|
||||
; GP0(E4h) - Set Drawing Area bottom right (X2,Y2)
|
||||
; Sets the drawing area corners. The Render commands GP0(20h..7Fh)
|
||||
; are automatically clipping any pixels that are outside of this region.
|
||||
; 0 - 9 X-coordinate (0..1023)
|
||||
; 10 - 18 Y-coordinate (0..511) ; \ on v0 GPU (max 1 MB VRAM)
|
||||
; 19 - 23 Not used (zero) ; /
|
||||
; 10 - 19 Y-coordinate (0..1023) ; \ on v2 GPU (max 2 MB VRAM)
|
||||
; 20 - 23 Not used (zero) ; /
|
||||
; 24 - 31 Command (Exh)
|
||||
gp_SetArea_TopLeft equ 0xE3 << gcmd_offset
|
||||
gp_SetArea_BottomRight equ 0xE4 << gcmd_offset
|
||||
|
||||
; GP0(E5h) - Set Drawing Offset (X,Y)
|
||||
; 0-9 X-coordinate (0..1023)
|
||||
; 10-18 Y-coordinate (0..511) ;\on v0 GPU (max 1 MB VRAM)
|
||||
; 19-23 Not used (zero) ;/
|
||||
; 10-19 Y-coordinate (0..1023) ;\on v2 GPU (max 2 MB VRAM)
|
||||
; 20-23 Not used (zero) ;/
|
||||
; 24-31 Command (Exh)
|
||||
gp_SetOffset equ 0xE5 << gcmd_offset
|
||||
|
||||
; GPU Memory Transfer Commands
|
||||
|
||||
; GP0(02h) Fill Vram
|
||||
; GP0(02h) - Fill Rectangle in VRAM
|
||||
; 1st Color+Command (CcBbGgRrh) ;24bit RGB value (see note)
|
||||
; 2nd Top Left Corner (YyyyXxxxh) ;Xpos counted in halfwords, steps of 10h
|
||||
; 3rd Width+Height (YsizXsizh) ;Xsiz counted in halfwords, steps of 10h
|
||||
; Fills the area in the frame buffer with the value in RGB.
|
||||
; Horizontally the filling is done in 16-pixel (32-bytes) units (see below masking/rounding).
|
||||
; The "Color" parameter is a 24bit RGB value, however, the actual fill data is 16bit:
|
||||
; The hardware automatically converts the 24bit RGB value to 15bit RGB (with bit15=0).
|
||||
; Fill is NOT affected by the Mask settings (acts as if Mask.Bit0,1 are both zero).
|
||||
gp_RectFillVM equ 0x02 << gcmd_offset
|
||||
|
||||
; GP0(A0h) - Copy Rectangle (CPU to VRAM)
|
||||
; Transfers data from CPU to frame buffer.
|
||||
; If the number of halfwords to be sent is odd, an extra halfword should be sent,
|
||||
; as packets consist of 32bits words. The transfer is affected by Mask setting.
|
||||
; 1st Command (Cc000000h)
|
||||
; 2nd Destination Coord (YyyyXxxxh) ;Xpos counted in halfwords
|
||||
; 3rd Width+Height (YsizXsizh) ;Xsiz counted in halfwords
|
||||
; ... Data (...) <--- usually transferred via DMA
|
||||
gp_Blit_VM_VM equ 0x80 << gcmd_offset
|
||||
gp_Blit_CPU_VM equ 0xA0 << gcmd_offset
|
||||
gp_Blit_VM_CPU equ 0xC0 << gcmd_offset
|
||||
|
||||
; GPU Render Polygon Commands
|
||||
|
||||
; When the upper 3 bits of the first GP0 command are set to 1 (001),
|
||||
; then the command can be decoded using the following bitfield:
|
||||
; bit number value meaning
|
||||
; 31-29 001 polygon render
|
||||
; 28 1/0 gouraud / flat shading
|
||||
; 27 1/0 4 / 3 vertices
|
||||
; 26 1/0 textured / untextured
|
||||
; 25 1/0 semi-transparent / opaque
|
||||
; 24 1/0 raw texture / modulation
|
||||
; 23-0 rgb first color value.
|
||||
gp_Poly_FirstColor equ 0
|
||||
gp_Poly_RawTexture equ 1 << 24
|
||||
gp_Poly_SemiTrans equ 1 << 25
|
||||
gp_Poly_Textured equ 1 << 26
|
||||
gp_Poly_Quad equ 1 << 27
|
||||
gp_Poly_Tri equ 0 << 27
|
||||
gp_Poly_ShadeFlat equ 0 << 28
|
||||
gp_Poly_ShadeGourand equ 1 << 28
|
||||
gp_Polygon equ 1 << 29
|
||||
|
||||
gp_Quad equ gp_Polygon | gp_Poly_Quad
|
||||
|
||||
gp_b10_X equ 0
|
||||
gp_b10_Y equ 10
|
||||
gp_b16_X equ 0
|
||||
gp_b16_Y equ 16
|
||||
|
||||
gp_pixel16 equ (2 * byte)
|
||||
gp_pixel24 equ (3 * byte)
|
||||
gp_vec2 equ word
|
||||
|
||||
.macro gp_push_pak, port, reg_scratch, packet
|
||||
load_imm reg_scratch, packet
|
||||
store_word reg_scratch, port
|
||||
.endmacro
|
||||
.macro gcmd_push, port, reg_scratch, cmd
|
||||
load_imm reg_scratch, cmd
|
||||
store_word reg_scratch, port
|
||||
.endmacro
|
||||
|
||||
// TODO(Ed): Figure out an auto region?
|
||||
.org 0x80010000 + 2000
|
||||
|
||||
.func gp_draw_tri_flat ;(
|
||||
gp_draw_tri_flat__sp_size equ (3 * gp_vec2)
|
||||
@@io_offset equ rarg_0 ; io_offset: word
|
||||
@@color equ rarg_1 ; color: word
|
||||
@@verts equ $sp ; verts: [3]gp_vec2
|
||||
;)
|
||||
@@vert_id equ rtmp_1
|
||||
@@cmd equ rtmp_2
|
||||
load_imm @@cmd, gp_Polygon
|
||||
or @@cmd, @@cmd, @@color
|
||||
store_word @@cmd, gpio_port0(@@io_offset)
|
||||
load_word @@vert_id, 0 * gp_vec2(@@verts) :: nop :: store_word @@vert_id, gpio_port0(@@io_offset)
|
||||
load_word @@vert_id, 1 * gp_vec2(@@verts) :: nop :: store_word @@vert_id, gpio_port0(@@io_offset)
|
||||
load_word @@vert_id, 2 * gp_vec2(@@verts) :: nop :: store_word @@vert_id, gpio_port0(@@io_offset)
|
||||
jump_reg rret_addr :: nop
|
||||
.endfunc
|
||||
|
||||
.func gp_draw_tri_gouraud ;(
|
||||
@@io_offset equ rarg_0
|
||||
@@color equ rarg_1
|
||||
@@color_2 equ rstatic_1
|
||||
@@color_3 equ rstatic_2
|
||||
@@vert_1 equ rarg_2
|
||||
@@vert_2 equ rarg_3
|
||||
@@vert_3 equ rstatic_0
|
||||
;)
|
||||
@@cmd equ rtmp_2
|
||||
load_imm @@cmd, gp_Polygon | gp_Poly_ShadeGourand
|
||||
or @@cmd, @@cmd, @@color
|
||||
store_word @@cmd, gpio_port0(@@io_offset)
|
||||
store_word @@vert_1, gpio_port0(@@io_offset)
|
||||
store_word @@color_2, gpio_port0(@@io_offset)
|
||||
store_word @@vert_2, gpio_port0(@@io_offset)
|
||||
store_word @@color_3, gpio_port0(@@io_offset)
|
||||
store_word @@vert_3, gpio_port0(@@io_offset)
|
||||
jump_reg rret_addr :: nop
|
||||
.endfunc
|
||||
@@ -0,0 +1,69 @@
|
||||
.psx
|
||||
.create "./build/hello_gouraud.bin", 0x80010000
|
||||
|
||||
.include "./code/graphics_hello/dsl.s"
|
||||
.include "./code/graphics_hello/gp.s"
|
||||
|
||||
; Entry Point of Code
|
||||
.org 0x80010000
|
||||
|
||||
Color_RedFF equ 0x0000FF
|
||||
Color_22 equ 0x222222
|
||||
Color_PS_CadmiumRed equ 0x2400DF
|
||||
Color_PS_CelticBlue equ 0x723F00
|
||||
Color_PS_GoldenPoppy equ 0x00C3F3
|
||||
Color_PS_PersianGreen equ 0x9FAC00
|
||||
|
||||
Display_Width equ 320
|
||||
Display_Height equ 239
|
||||
Display_HalfWidth equ 320 / 2
|
||||
Display_HalfHeight equ 240 / 2
|
||||
|
||||
main:
|
||||
reg_io_offset equ rtmp_0
|
||||
load_uimm rtmp_0, IO_BASE_ADDR
|
||||
|
||||
gp0 equ gpio_port0(reg_io_offset)
|
||||
gp1 equ gpio_port1(reg_io_offset)
|
||||
|
||||
; Setup Display Control
|
||||
gcmd_push gp1, rtmp_1, gp_Reset
|
||||
gcmd_push gp1, rtmp_1, gp_DisplayEnabled
|
||||
gcmd_push gp1, rtmp_1, gp_DisplayMode_320x240_15bit_NTSC
|
||||
gcmd_push gp1, rtmp_1, gp_HorizontalDisplayRange_3168_608
|
||||
gcmd_push gp1, rtmp_1, gp_VerticalDisplayRange_264_24
|
||||
gcmd_push gp0, rtmp_1, gp_ModeSetting_DipArea
|
||||
gcmd_push gp0, rtmp_1, gp_SetArea_TopLeft | 0 << gp_b10_Y | 0 << gp_b10_X
|
||||
gcmd_push gp0, rtmp_1, gp_SetArea_BottomRight | Display_Height << gp_b10_Y | Display_Width << gp_b10_X
|
||||
gcmd_push gp0, rtmp_1, gp_SetOffset | 0 << gp_b10_Y | 0 << gp_b10_X
|
||||
gcmd_push gp0, rtmp_1, gp_RectFillVM | Color_22
|
||||
gcmd_push gp0, rtmp_1, 0 << gp_b16_Y | 0 << gp_b16_X
|
||||
gcmd_push gp0, rtmp_1, Display_Height << gp_b16_Y | Display_Width << gp_b16_X
|
||||
; Draw a flat-shaded quad
|
||||
gcmd_push gp0, rtmp_1, gp_Quad | Color_PS_CelticBlue
|
||||
gcmd_push gp0, rtmp_1, 15 * -1 + Display_HalfHeight << gp_b16_Y | 0 + Display_HalfWidth << gp_b16_X
|
||||
gcmd_push gp0, rtmp_1, 24 * -1 + Display_HalfHeight << gp_b16_Y | 100 + Display_HalfWidth << gp_b16_X
|
||||
gcmd_push gp0, rtmp_1, -30 * -1 + Display_HalfHeight << gp_b16_Y | -100 + Display_HalfWidth << gp_b16_X
|
||||
gcmd_push gp0, rtmp_1, -50 * -1 + Display_HalfHeight << gp_b16_Y | 55 + Display_HalfWidth << gp_b16_X
|
||||
; Draw a flat-shaded triangle
|
||||
gcmd_push gp0, rtmp_1, gp_Polygon | Color_PS_GoldenPoppy
|
||||
gcmd_push gp0, rtmp_1, 100 * -1 + Display_HalfHeight << gp_b16_Y | -100 + Display_HalfWidth << gp_b16_X
|
||||
gcmd_push gp0, rtmp_1, 20 * -1 + Display_HalfHeight << gp_b16_Y | 20 + Display_HalfWidth << gp_b16_X
|
||||
gcmd_push gp0, rtmp_1, 50 * -1 + Display_HalfHeight << gp_b16_Y | 30 + Display_HalfWidth << gp_b16_X
|
||||
; Bonus traingle
|
||||
gcmd_push gp0, rtmp_1, gp_Polygon | Color_PS_CadmiumRed
|
||||
gcmd_push gp0, rtmp_1, 50 * -1 + Display_HalfHeight << gp_b16_Y | -100 + Display_HalfWidth << gp_b16_X
|
||||
gcmd_push gp0, rtmp_1, 0 * -1 + Display_HalfHeight << gp_b16_Y | 20 + Display_HalfWidth << gp_b16_X
|
||||
gcmd_push gp0, rtmp_1, -100 * -1 + Display_HalfHeight << gp_b16_Y | 30 + Display_HalfWidth << gp_b16_X
|
||||
; Gourand shaded triangle
|
||||
gcmd_push gp0, rtmp_1, gp_Polygon | gp_Poly_ShadeGourand | Color_PS_PersianGreen
|
||||
gcmd_push gp0, rtmp_1, -35 * -1 + Display_HalfHeight << gp_b16_Y | 145 + Display_HalfWidth << gp_b16_X
|
||||
gcmd_push gp0, rtmp_1, 0x00 << 16 | Color_PS_GoldenPoppy
|
||||
gcmd_push gp0, rtmp_1, 0 * -1 + Display_HalfHeight << gp_b16_Y | 50 + Display_HalfWidth << gp_b16_X
|
||||
gcmd_push gp0, rtmp_1, 0x00 << 16 | Color_PS_CadmiumRed
|
||||
gcmd_push gp0, rtmp_1, 40 * -1 + Display_HalfHeight << gp_b16_Y | 60 + Display_HalfWidth << gp_b16_X
|
||||
|
||||
idle:
|
||||
jump idle :: nop
|
||||
|
||||
.close
|
||||
@@ -0,0 +1,75 @@
|
||||
.psx
|
||||
.create "./build/hello_gp_routines.bin", 0x80010000
|
||||
|
||||
.include "./code/graphics_hello/dsl.s"
|
||||
.include "./code/graphics_hello/gp.s"
|
||||
|
||||
; Entry Point of Code
|
||||
.org 0x80010000
|
||||
|
||||
Color_RedFF equ 0x0000FF
|
||||
Color_22 equ 0x222222
|
||||
Color_PS_CadmiumRed equ 0x2400DF
|
||||
Color_PS_CelticBlue equ 0x723F00
|
||||
Color_PS_GoldenPoppy equ 0x00C3F3
|
||||
Color_PS_PersianGreen equ 0x9FAC00
|
||||
|
||||
Display_Width equ 320
|
||||
Display_Height equ 239
|
||||
Display_HalfWidth equ 320 / 2
|
||||
Display_HalfHeight equ 240 / 2
|
||||
|
||||
main:
|
||||
reg_io_offset equ rtmp_0
|
||||
load_uimm rtmp_0, IO_BASE_ADDR
|
||||
|
||||
gp0 equ gpio_port0(reg_io_offset)
|
||||
gp1 equ gpio_port1(reg_io_offset)
|
||||
|
||||
; Setup Display Control
|
||||
gcmd_push gp1, rtmp_1, gp_Reset
|
||||
gcmd_push gp1, rtmp_1, gp_DisplayEnabled
|
||||
gcmd_push gp1, rtmp_1, gp_DisplayMode_320x240_15bit_NTSC
|
||||
gcmd_push gp1, rtmp_1, gp_HorizontalDisplayRange_3168_608
|
||||
gcmd_push gp1, rtmp_1, gp_VerticalDisplayRange_264_24
|
||||
gcmd_push gp0, rtmp_1, gp_ModeSetting_DipArea
|
||||
gcmd_push gp0, rtmp_1, gp_SetArea_TopLeft | 0 << gp_b10_Y | 0 << gp_b10_X
|
||||
gcmd_push gp0, rtmp_1, gp_SetArea_BottomRight | Display_Height << gp_b10_Y | Display_Width << gp_b10_X
|
||||
gcmd_push gp0, rtmp_1, gp_SetOffset | 0 << gp_b10_Y | 0 << gp_b10_X
|
||||
gcmd_push gp0, rtmp_1, gp_RectFillVM | Color_22
|
||||
gcmd_push gp0, rtmp_1, 0 << gp_b16_Y | 0 << gp_b16_X
|
||||
gcmd_push gp0, rtmp_1, Display_Height << gp_b16_Y | Display_Width << gp_b16_X
|
||||
; Draw a flat-shaded quad
|
||||
gcmd_push gp0, rtmp_1, gp_Quad | Color_PS_CelticBlue
|
||||
gcmd_push gp0, rtmp_1, 15 * -1 + Display_HalfHeight << gp_b16_Y | 0 + Display_HalfWidth << gp_b16_X
|
||||
gcmd_push gp0, rtmp_1, 24 * -1 + Display_HalfHeight << gp_b16_Y | 100 + Display_HalfWidth << gp_b16_X
|
||||
gcmd_push gp0, rtmp_1, -30 * -1 + Display_HalfHeight << gp_b16_Y | -100 + Display_HalfWidth << gp_b16_X
|
||||
gcmd_push gp0, rtmp_1, -50 * -1 + Display_HalfHeight << gp_b16_Y | 55 + Display_HalfWidth << gp_b16_X
|
||||
; Draw a flat-shaded triangle
|
||||
stack_alloc gp_draw_tri_flat__sp_size ; (used for following call)
|
||||
move rarg_0, reg_io_offset ; (used for following call)
|
||||
load_imm rarg_1, Color_PS_GoldenPoppy
|
||||
load_imm rarg_2, 100 * -1 + Display_HalfHeight << gp_b16_Y | -100 + Display_HalfWidth << gp_b16_X :: sw rarg_2, 0 * gp_vec2($sp)
|
||||
load_imm rarg_2, 20 * -1 + Display_HalfHeight << gp_b16_Y | 20 + Display_HalfWidth << gp_b16_X :: sw rarg_2, 1 * gp_vec2($sp)
|
||||
load_imm rarg_2, 50 * -1 + Display_HalfHeight << gp_b16_Y | 30 + Display_HalfWidth << gp_b16_X :: sw rarg_2, 2 * gp_vec2($sp)
|
||||
jump_nlink gp_draw_tri_flat :: nop
|
||||
; Bonus traingle
|
||||
load_imm rarg_1, Color_PS_CadmiumRed
|
||||
load_imm rarg_2, 50 * -1 + Display_HalfHeight << gp_b16_Y | -100 + Display_HalfWidth << gp_b16_X :: sw rarg_2, 0 * gp_vec2($sp)
|
||||
load_imm rarg_2, 0 * -1 + Display_HalfHeight << gp_b16_Y | 20 + Display_HalfWidth << gp_b16_X :: sw rarg_2, 1 * gp_vec2($sp)
|
||||
load_imm rarg_2, -100 * -1 + Display_HalfHeight << gp_b16_Y | 30 + Display_HalfWidth << gp_b16_X :: sw rarg_2, 2 * gp_vec2($sp)
|
||||
jump_nlink gp_draw_tri_flat :: nop
|
||||
stack_release gp_draw_tri_flat__sp_size
|
||||
; Gourand shaded triangle
|
||||
load_imm rarg_1, Color_PS_PersianGreen
|
||||
load_imm rstatic_1, Color_PS_GoldenPoppy
|
||||
load_imm rstatic_2, Color_PS_CadmiumRed
|
||||
load_imm rarg_2, -35 * -1 + Display_HalfHeight << gp_b16_Y | 145 + Display_HalfWidth << gp_b16_X
|
||||
load_imm rarg_3, 0 * -1 + Display_HalfHeight << gp_b16_Y | 50 + Display_HalfWidth << gp_b16_X
|
||||
load_imm rstatic_0, 40 * -1 + Display_HalfHeight << gp_b16_Y | 60 + Display_HalfWidth << gp_b16_X
|
||||
jump_nlink gp_draw_tri_gouraud :: nop
|
||||
|
||||
idle:
|
||||
jump idle :: nop
|
||||
|
||||
.close
|
||||
@@ -0,0 +1,133 @@
|
||||
.psx
|
||||
.create "./build/hello_image.bin", 0x80010000
|
||||
|
||||
.include "./code/graphics_hello/dsl.s"
|
||||
.include "./code/graphics_hello/gp.s"
|
||||
|
||||
Color_RedFF equ 0x0000FF
|
||||
Color_22 equ 0x222222
|
||||
Color_PS_CadmiumRed equ 0x2400DF
|
||||
Color_PS_CelticBlue equ 0x723F00
|
||||
Color_PS_GoldenPoppy equ 0x00C3F3
|
||||
Color_PS_PersianGreen equ 0x9FAC00
|
||||
|
||||
Display_Width equ 319
|
||||
Display_Height equ 239
|
||||
Display_HalfWidth equ 319 / 2
|
||||
Display_HalfHeight equ 239 / 2
|
||||
|
||||
|
||||
.org 0x80010000 + 4000
|
||||
|
||||
Image_SizeX equ 32
|
||||
Image_SizeY equ 32
|
||||
Image_ByteSize equ Image_SizeX * Image_SizeY * gp_pixel16
|
||||
|
||||
Image:
|
||||
; 32 * 32 * 2 = 2048 bytes
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x7500,0x7500,0x7500,0x7500,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x7500,0x7500,0x7500,0x7500,0x7500,0x7500,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x7500,0x7500,0x7500,0x7500,0x7500,0x7500,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x7500,0x7500,0x7500,0x7500,0x7500,0x7500,0x7500,0x7500,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x7500,0x7500,0x7500,0x7500,0x7500,0x7500,0x7500,0x7500,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60
|
||||
.hword 0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x7500,0x7500,0x7500,0x7500,0x7500,0x7500,0x7500,0x7500,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x7500,0x7500,0x7500,0x7500,0x7500,0x7500,0x7500,0x7500,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x7500,0x7500,0x7500,0x7500,0x7500,0x7500,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x7500,0x7500,0x7500,0x7500,0x7500,0x7500,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x7500,0x7500,0x7500,0x7500,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0AFF,0x0AFF,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
.hword 0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60,0x0A60
|
||||
|
||||
; Entry Point of Code
|
||||
.org 0x80010000
|
||||
main:
|
||||
reg_io_offset equ rtmp_0
|
||||
load_uimm rtmp_0, IO_BASE_ADDR
|
||||
|
||||
gp0 equ gpio_port0(reg_io_offset)
|
||||
gp1 equ gpio_port1(reg_io_offset)
|
||||
|
||||
; Setup Display Control
|
||||
gcmd_push gp1, rtmp_1, gp_Reset
|
||||
gcmd_push gp1, rtmp_1, gp_DisplayEnabled
|
||||
gcmd_push gp1, rtmp_1, gp_DisplayMode_320x240_15bit_NTSC
|
||||
gcmd_push gp1, rtmp_1, gp_HorizontalDisplayRange_3168_608
|
||||
gcmd_push gp1, rtmp_1, gp_VerticalDisplayRange_264_24
|
||||
gcmd_push gp0, rtmp_1, gp_ModeSetting_DipArea
|
||||
gcmd_push gp0, rtmp_1, gp_SetArea_TopLeft | 0 << gp_b10_Y | 0 << gp_b10_X
|
||||
gcmd_push gp0, rtmp_1, gp_SetArea_BottomRight | Display_Height << gp_b10_Y | Display_Width << gp_b10_X
|
||||
gcmd_push gp0, rtmp_1, gp_SetOffset | 0 << gp_b10_Y | 0 << gp_b10_X
|
||||
; Clear the screen
|
||||
gcmd_push gp0, rtmp_1, gp_RectFillVM | Color_22
|
||||
gcmd_push gp0, rtmp_1, 0 << gp_b16_Y | 0 << gp_b16_X
|
||||
gcmd_push gp0, rtmp_1, Display_Height << gp_b16_Y | Display_Width << gp_b16_X
|
||||
|
||||
; Draw a flat-shaded quad
|
||||
gcmd_push gp0, rtmp_1, gp_Quad | Color_PS_CelticBlue
|
||||
gcmd_push gp0, rtmp_1, 15 * -1 + Display_HalfHeight << gp_b16_Y | 0 + Display_HalfWidth << gp_b16_X
|
||||
gcmd_push gp0, rtmp_1, 24 * -1 + Display_HalfHeight << gp_b16_Y | 100 + Display_HalfWidth << gp_b16_X
|
||||
gcmd_push gp0, rtmp_1, -30 * -1 + Display_HalfHeight << gp_b16_Y | -100 + Display_HalfWidth << gp_b16_X
|
||||
gcmd_push gp0, rtmp_1, -50 * -1 + Display_HalfHeight << gp_b16_Y | 55 + Display_HalfWidth << gp_b16_X
|
||||
; Draw a flat-shaded triangle
|
||||
stack_alloc gp_draw_tri_flat__sp_size ; (used for following call)
|
||||
move rarg_0, reg_io_offset ; (used for following call)
|
||||
load_imm rarg_1, Color_PS_GoldenPoppy
|
||||
load_imm rarg_2, 100 * -1 + Display_HalfHeight << gp_b16_Y | -100 + Display_HalfWidth << gp_b16_X :: store_word rarg_2, 0 * gp_vec2($sp)
|
||||
load_imm rarg_2, 20 * -1 + Display_HalfHeight << gp_b16_Y | 20 + Display_HalfWidth << gp_b16_X :: store_word rarg_2, 1 * gp_vec2($sp)
|
||||
load_imm rarg_2, 50 * -1 + Display_HalfHeight << gp_b16_Y | 30 + Display_HalfWidth << gp_b16_X :: store_word rarg_2, 2 * gp_vec2($sp)
|
||||
jump_nlink gp_draw_tri_flat :: nop
|
||||
; Bonus traingle
|
||||
load_imm rarg_1, Color_PS_CadmiumRed
|
||||
load_imm rarg_2, 50 * -1 + Display_HalfHeight << gp_b16_Y | -100 + Display_HalfWidth << gp_b16_X :: store_word rarg_2, 0 * gp_vec2($sp)
|
||||
load_imm rarg_2, 0 * -1 + Display_HalfHeight << gp_b16_Y | 20 + Display_HalfWidth << gp_b16_X :: store_word rarg_2, 1 * gp_vec2($sp)
|
||||
load_imm rarg_2, -100 * -1 + Display_HalfHeight << gp_b16_Y | 30 + Display_HalfWidth << gp_b16_X :: store_word rarg_2, 2 * gp_vec2($sp)
|
||||
jump_nlink gp_draw_tri_flat :: nop
|
||||
stack_release gp_draw_tri_flat__sp_size
|
||||
; Gourand shaded triangle
|
||||
load_imm rarg_1, Color_PS_PersianGreen
|
||||
load_imm rstatic_1, Color_PS_GoldenPoppy
|
||||
load_imm rstatic_2, Color_PS_CadmiumRed
|
||||
load_imm rarg_2, -35 * -1 + Display_HalfHeight << gp_b16_Y | 145 + Display_HalfWidth << gp_b16_X
|
||||
load_imm rarg_3, 0 * -1 + Display_HalfHeight << gp_b16_Y | 50 + Display_HalfWidth << gp_b16_X
|
||||
load_imm rstatic_0, 40 * -1 + Display_HalfHeight << gp_b16_Y | 60 + Display_HalfWidth << gp_b16_X
|
||||
jump_nlink gp_draw_tri_gouraud :: nop
|
||||
|
||||
; Copy image contents to vram
|
||||
gcmd_push gp0, rtmp_1, gp_Blit_CPU_VM
|
||||
gcmd_push gp0, rtmp_1, 0 << gp_b16_Y | Display_Width << gp_b16_X
|
||||
gcmd_push gp0, rtmp_1, Image_SizeY << gp_b16_Y | Image_SizeX << gp_b16_X
|
||||
; DMA commands
|
||||
@id equ rtmp_2
|
||||
@img_cursor equ rtmp_3
|
||||
load_imm @id, Image_ByteSize
|
||||
shift_rl @id, @id, (word / 2)
|
||||
load_addr @img_cursor, Image
|
||||
loop_dma:
|
||||
load_word rtmp_1, (@img_cursor) :: nop :: store_word rtmp_1, gp0 ; @img_curor -> gp_dma_cpu_vm(word)
|
||||
add_si @img_cursor, @img_cursor, word ; @img_cursor ++
|
||||
add_ui @id, @id, -1 :: branch_ne_zero @id, loop_dma :: nop
|
||||
|
||||
idle:
|
||||
jump idle :: nop
|
||||
|
||||
.close
|
||||
@@ -0,0 +1,69 @@
|
||||
.psx
|
||||
.create "./build/hello_logo.bin", 0x80010000
|
||||
|
||||
.include "./code/graphics_hello/dsl.s"
|
||||
.include "./code/graphics_hello/gp.s"
|
||||
|
||||
Color_RedFF equ 0x0000FF
|
||||
Color_22 equ 0x222222
|
||||
Color_PS_CadmiumRed equ 0x2400DF
|
||||
Color_PS_CelticBlue equ 0x723F00
|
||||
Color_PS_GoldenPoppy equ 0x00C3F3
|
||||
Color_PS_PersianGreen equ 0x9FAC00
|
||||
|
||||
Display_Width equ (640)
|
||||
Display_Height equ (480)
|
||||
Display_HalfWidth equ Display_Width / 2
|
||||
Display_HalfHeight equ Display_Height / 2
|
||||
|
||||
// TODO(Ed): Figure out an auto-region?
|
||||
.org 0x80010000 + 4000
|
||||
|
||||
Image_SizeX equ 640 * 3 / 2 ; 24bbp needs 1.5x
|
||||
Image_SizeY equ 480
|
||||
Image_ByteSize equ Image_SizeX * Image_SizeY * gp_pixel24
|
||||
Image:
|
||||
.incbin "./assets/logo.bin"
|
||||
|
||||
; Entry Point of Code
|
||||
.org 0x80010000
|
||||
main:
|
||||
reg_io_offset equ rtmp_0
|
||||
load_uimm rtmp_0, IO_BASE_ADDR
|
||||
|
||||
gp0 equ gpio_port0(reg_io_offset)
|
||||
gp1 equ gpio_port1(reg_io_offset)
|
||||
|
||||
; Setup Display Control
|
||||
gcmd_push gp1, rtmp_1, gp_Reset
|
||||
gcmd_push gp1, rtmp_1, gp_DisplayEnabled
|
||||
gcmd_push gp1, rtmp_1, gp_DisplayMode | gp_Disp_Color24 | gp_Disp_VInterlace | gp_Disp_VRes_480 | gp_Disp_HRes_640
|
||||
// gcmd_push gp1, rtmp_1, gp_DisplayMode_320x240_15bit_NTSC
|
||||
// gcmd_push gp1, rtmp_1, gp_DisplayMode_640x480_24bbp_NTSC
|
||||
gcmd_push gp1, rtmp_1, gp_HorizontalDisplayRange_3168_608
|
||||
gcmd_push gp1, rtmp_1, gp_VerticalDisplayRange_504_24
|
||||
gcmd_push gp0, rtmp_1, gp_ModeSetting_DipArea
|
||||
gcmd_push gp0, rtmp_1, gp_SetArea_TopLeft | 0 << gp_b10_Y | 0 << gp_b10_X
|
||||
gcmd_push gp0, rtmp_1, gp_SetArea_BottomRight | Display_Height << gp_b10_Y | Display_Width << gp_b10_X
|
||||
gcmd_push gp0, rtmp_1, gp_SetOffset | 0 << gp_b10_Y | 0 << gp_b10_X
|
||||
|
||||
; Copy image contents to vram
|
||||
gcmd_push gp0, rtmp_1, gp_Blit_CPU_VM
|
||||
gcmd_push gp0, rtmp_1, 0 << gp_b16_Y | 0 << gp_b16_X ; Top Left
|
||||
gcmd_push gp0, rtmp_1, Image_SizeY << gp_b16_Y | Image_SizeX << gp_b16_X ; Bottom Right
|
||||
; DMA commands
|
||||
@id equ rtmp_2
|
||||
@img_cursor equ rtmp_3
|
||||
load_imm @id, Image_ByteSize
|
||||
shift_rl @id, @id, (word / 2)
|
||||
load_addr @img_cursor, Image
|
||||
loop_dma:
|
||||
load_word rtmp_1, (@img_cursor)
|
||||
add_si @img_cursor, @img_cursor, word ; @img_cursor ++ (delay slot filled)
|
||||
store_word rtmp_1, gp0 ; @img_curor -> gp_dma_cpu_vm(word)
|
||||
branch_ne_zero @id, loop_dma :: add_ui @id, @id, -1 ; if != @id, 0 goto loop_dma :: -- @id (delay slot filled)
|
||||
|
||||
idle:
|
||||
jump idle :: nop
|
||||
|
||||
.close
|
||||
@@ -0,0 +1,225 @@
|
||||
.psx
|
||||
.create "./build/hellogpu.bin", 0x80010000
|
||||
|
||||
.include "./code/graphics_hello/dsl.s"
|
||||
|
||||
; Entry Point of Code
|
||||
.org 0x80010000
|
||||
|
||||
; IO PORT
|
||||
IO_BASE_ADDR equ 0x1F80 ; IO Ports Memory map base address
|
||||
|
||||
; GPU Registers
|
||||
gpio_port0 equ 0x1810 ; 1F801810h-Write GP0: Send GP0 Commands/Packets (Rendering and VRAM Access)
|
||||
gpio_port1 equ 0x1814 ; 1F801814h-Write GP1: Send GP1 Commands (Display Control) (and DMA Control)
|
||||
|
||||
; GPU Command Format: [7:8] Command (8-bit), [0:6] Paraemter (24-bit)
|
||||
|
||||
gcmd_offset equ 24
|
||||
|
||||
gp_Reset equ 0x0 << gcmd_offset
|
||||
|
||||
; On: 0x0
|
||||
; Off: 0x1
|
||||
gp_DisplayEnabled equ (0x03 << gcmd_offset) | 0x0
|
||||
gp_DisplayDisabled equ (0x03 << gcmd_offset) | 0x1
|
||||
|
||||
; GP1(08h) - Display mode
|
||||
; 0-1 Horizontal Resolution 1 (0=256, 1=320, 2=512, 3=640) ;GPUSTAT.17-18
|
||||
; 2 Vertical Resolution (0=240, 1=480, when Bit5=1) ;GPUSTAT.19
|
||||
; 3 Video Mode (0=NTSC/60Hz, 1=PAL/50Hz) ;GPUSTAT.20
|
||||
; 4 Display Area Color Depth (0=15bit, 1=24bit) ;GPUSTAT.21
|
||||
; 5 Vertical Interlace (0=Off, 1=On) ;GPUSTAT.22
|
||||
; 6 Horizontal Resolution 2 (0=256/320/512/640, 1=368) ;GPUSTAT.16
|
||||
; 7 Flip screen horizontally (0=Off, 1=On, v1 only) ;GPUSTAT.14
|
||||
; 8-23 Not used (zero)
|
||||
@DisplayMode equ 0x08
|
||||
gp_DisplayMode_320x240_15bit_NTSC equ @DisplayMode << gcmd_offset | 0x0 << 7 | 0x0 << 6 | 0x0 << 5 | 0x0 << 4 | 0x0 << 3 | 0x0 << 2 | 0x1
|
||||
|
||||
; GP1(06h) - Horizontal Display range (on Screen)
|
||||
; X2 = X1 + pixels * cycles_per_pix
|
||||
; 0 - 11 X1 (260h + 0) ; 12bit ; \ counted in video clock units,
|
||||
; 12 - 23 X2 (260h + 320 * 8) ; 12bit ; / relative to HSYNC
|
||||
gp_HorizontalDisplayRange_3168_608 equ 0x06 << gcmd_offset | 0xC60 << 12 | 0x260
|
||||
|
||||
; GP1(07h) - Vertical Display range (on Screen)
|
||||
; 0 - 9 Y1 (NTSC = 88h - (240 / 2), (PAL = A3h - (288 / 2)) ; \ scanline numbers on screen,
|
||||
; 10 - 19 Y2 (NTSC = 88h + (240 / 2), (PAL = A3h + (288 / 2)) ; / relative to VSYNC
|
||||
; 20 - 23 Not used (zero)
|
||||
gp_VerticalDisplayRange_264_24 equ 0x07 << gcmd_offset | 264 << 10 | 24
|
||||
|
||||
;GP0(E1h) - Draw Mode setting (aka "Texpage")
|
||||
; 0 - 3 Texture page X Base (N * 64) (ie. in 64-halfword steps) ; GPUSTAT.0-3
|
||||
; 4 Texture page Y Base 1 (N * 256) (ie. 0, 256, 512 or 768) ; GPUSTAT.4
|
||||
; 5 - 6 Semi-transparency (0 = B / 2 + F / 2, 1 = B + F, 2 = B - F, 3 = B + F / 4) ; GPUSTAT.5-6
|
||||
; 7 - 8 Texture page colors (0 = 4 bit, 1 = 8bit, 2 = 15bit, 3 = Reserved) ; GPUSTAT.7-8
|
||||
; 9 Dither 24bit to 15bit (0=Off / strip LSBs, 1 = Dither Enabled) ; GPUSTAT.9
|
||||
; 10 Drawing to display area (0=Prohibited, 1=Allowed) ; GPUSTAT.10
|
||||
; 11 Texture page Y Base 2 (N * 512) (only for 2 MB VRAM) ; GPUSTAT.15
|
||||
; 12 Textured Rectangle X-Flip (BIOS does set this bit on power-up...?)
|
||||
; 13 Textured Rectangle Y-Flip (BIOS does set it equal to GPUSTAT.13...?)
|
||||
; 14 - 23 Not used (should be 0)
|
||||
; 24 - 31 Command (E1h)
|
||||
gp_ModeSetting_DrawAllowed equ 10
|
||||
gp_ModeSetting_DipArea equ 0xE1 << gcmd_offset | 0x1 << gp_ModeSetting_DrawAllowed
|
||||
|
||||
; GP0(E3h) - Set Drawing Area top left (X1,Y1)
|
||||
; GP0(E4h) - Set Drawing Area bottom right (X2,Y2)
|
||||
; Sets the drawing area corners. The Render commands GP0(20h..7Fh) are automatically clipping any pixels that are outside of this region.
|
||||
; 0 - 9 X-coordinate (0..1023)
|
||||
; 10 - 18 Y-coordinate (0..511) ; \ on v0 GPU (max 1 MB VRAM)
|
||||
; 19 - 23 Not used (zero) ; /
|
||||
; 10 - 19 Y-coordinate (0..1023) ; \ on v2 GPU (max 2 MB VRAM)
|
||||
; 20 - 23 Not used (zero) ; /
|
||||
; 24 - 31 Command (Exh)
|
||||
gp_SetArea_TopLeft equ 0xE3 << gcmd_offset
|
||||
gp_SetArea_BottomRight equ 0xE4 << gcmd_offset
|
||||
|
||||
; GP0(E5h) - Set Drawing Offset (X,Y)
|
||||
; 0-9 X-coordinate (0..1023)
|
||||
; 10-18 Y-coordinate (0..511) ;\on v0 GPU (max 1 MB VRAM)
|
||||
; 19-23 Not used (zero) ;/
|
||||
; 10-19 Y-coordinate (0..1023) ;\on v2 GPU (max 2 MB VRAM)
|
||||
; 20-23 Not used (zero) ;/
|
||||
; 24-31 Command (Exh)
|
||||
gp_SetOffset equ 0xE5 << gcmd_offset
|
||||
|
||||
; GPU Memory Transfer Commands
|
||||
|
||||
; GP0(02h) Fill Vram
|
||||
; GP0(02h) - Fill Rectangle in VRAM
|
||||
; 1st Color+Command (CcBbGgRrh) ;24bit RGB value (see note)
|
||||
; 2nd Top Left Corner (YyyyXxxxh) ;Xpos counted in halfwords, steps of 10h
|
||||
; 3rd Width+Height (YsizXsizh) ;Xsiz counted in halfwords, steps of 10h
|
||||
; Fills the area in the frame buffer with the value in RGB.
|
||||
; Horizontally the filling is done in 16-pixel (32-bytes) units (see below masking/rounding).
|
||||
; The "Color" parameter is a 24bit RGB value, however, the actual fill data is 16bit:
|
||||
; The hardware automatically converts the 24bit RGB value to 15bit RGB (with bit15=0).
|
||||
; Fill is NOT affected by the Mask settings (acts as if Mask.Bit0,1 are both zero).
|
||||
gp_RectFillVM equ 0x02 << gcmd_offset
|
||||
|
||||
; GPU Render Polygon Commands
|
||||
|
||||
; When the upper 3 bits of the first GP0 command are set to 1 (001),
|
||||
; then the command can be decoded using the following bitfield:
|
||||
; bit number value meaning
|
||||
; 31-29 001 polygon render
|
||||
; 28 1/0 gouraud / flat shading
|
||||
; 27 1/0 4 / 3 vertices
|
||||
; 26 1/0 textured / untextured
|
||||
; 25 1/0 semi-transparent / opaque
|
||||
; 24 1/0 raw texture / modulation
|
||||
; 23-0 rgb first color value.
|
||||
gp_Poly_FirstColor equ 0
|
||||
gp_Poly_RawTexture equ 1 << 24
|
||||
gp_Poly_SemiTrans equ 1 << 25
|
||||
gp_Poly_Textured equ 1 << 26
|
||||
gp_Poly_Quad equ 1 << 27
|
||||
gp_Poly_Tri equ 0 << 27
|
||||
gp_Poly_ShadeFlat equ 0 << 28
|
||||
gp_Poly_ShadeGourand equ 1 << 28
|
||||
gp_Polygon equ 1 << 29
|
||||
|
||||
gp_Quad equ gp_Polygon | gp_Poly_Quad
|
||||
|
||||
gp_b10_X equ 0
|
||||
gp_b10_Y equ 10
|
||||
gp_b16_X equ 0
|
||||
gp_b16_Y equ 16
|
||||
|
||||
.macro gp_push_pak, port, packet, reg_scratch
|
||||
load_imm reg_scratch, packet
|
||||
store_word reg_scratch, port
|
||||
.endmacro
|
||||
.macro gcmd_push, port, cmd, reg_scratch
|
||||
load_imm reg_scratch, cmd
|
||||
store_word reg_scratch, port
|
||||
.endmacro
|
||||
|
||||
Color_RedFF equ 0x0000FF
|
||||
Color_22 equ 0x222222
|
||||
Color_PS_CadmiumRed equ 0x2400DF
|
||||
Color_PS_GoldenPoppy equ 0x00C3F3
|
||||
Color_PS_CelticBlue equ 0x723F00
|
||||
|
||||
Display_Width equ 320
|
||||
Display_Height equ 239
|
||||
Display_HalfWidth equ 320 / 2
|
||||
Display_HalfHeight equ 240 / 2
|
||||
|
||||
main:
|
||||
reg_io_offset equ rtmp_0
|
||||
load_uimm rtmp_0, IO_BASE_ADDR
|
||||
|
||||
; Setup Display Control
|
||||
; 1. GP1: Reset GPU
|
||||
load_imm rtmp_1, gp_Reset ; 00 = Reset GPU
|
||||
store_word rtmp_1, gpio_port1(reg_io_offset) ; Writing to GP1
|
||||
; 2. GP1: Display Enable
|
||||
load_imm rtmp_1, gp_DisplayEnabled
|
||||
store_word rtmp_1, gpio_port1(reg_io_offset) ; Write to GP1
|
||||
; 3. GP1: Dispaly Mode (320x240, 15-bit, NTSC)
|
||||
load_imm rtmp_1, gp_DisplayMode_320x240_15bit_NTSC
|
||||
store_word rtmp_1, gpio_port1(reg_io_offset) ; Write to GP1
|
||||
; 4. GP1: Horizontal Range
|
||||
load_imm rtmp_1, gp_HorizontalDisplayRange_3168_608
|
||||
store_word rtmp_1, gpio_port1(reg_io_offset)
|
||||
; 5. GP1: Vertical Range
|
||||
load_imm rtmp_1, gp_VerticalDisplayRange_264_24
|
||||
store_word rtmp_1, gpio_port1(reg_io_offset)
|
||||
; Setup VRAM Access
|
||||
; 1. GP0: Drawing mode settings
|
||||
load_imm rtmp_1, gp_ModeSetting_DipArea
|
||||
store_word rtmp_1, gpio_port0(reg_io_offset)
|
||||
; 2. GP0: Drawing area Top-Left
|
||||
load_imm rtmp_1, gp_SetArea_TopLeft | 0 << gp_b10_Y | 0 << gp_b10_X
|
||||
store_word rtmp_1, gpio_port0(reg_io_offset)
|
||||
; 3. GP0: Drawing area Bottom-Right
|
||||
load_imm rtmp_1, gp_SetArea_BottomRight | Display_Height << gp_b10_Y | Display_Width << gp_b10_X
|
||||
store_word rtmp_1, gpio_port0(reg_io_offset)
|
||||
; 4. GP0: Drawing area offset X & Y
|
||||
load_imm rtmp_1, gp_SetOffset | 0 << gp_b10_Y | 0 << gp_b10_X
|
||||
store_word rtmp_1, gpio_port0(reg_io_offset)
|
||||
; Clear the screen
|
||||
; 1. GP0: Fill rectangle on display area
|
||||
load_imm rtmp_1, gp_RectFillVM | Color_22
|
||||
store_word rtmp_1, gpio_port0(reg_io_offset)
|
||||
load_imm rtmp_1, 0 << gp_b16_Y | 0 << gp_b16_X
|
||||
store_word rtmp_1, gpio_port0(reg_io_offset)
|
||||
load_imm rtmp_1, Display_Height << gp_b16_Y | Display_Width << gp_b16_X
|
||||
store_word rtmp_1, gpio_port0(reg_io_offset)
|
||||
; Draw a flat-shaded quad
|
||||
load_imm rtmp_1, gp_Quad | Color_PS_CelticBlue
|
||||
store_word rtmp_1, gpio_port0(reg_io_offset)
|
||||
load_imm rtmp_1, -1 * 15 + Display_HalfHeight << gp_b16_Y | 0 + Display_HalfWidth << gp_b16_X
|
||||
store_word rtmp_1, gpio_port0(reg_io_offset)
|
||||
load_imm rtmp_1, -1 * 24 + Display_HalfHeight << gp_b16_Y | 100 + Display_HalfWidth << gp_b16_X
|
||||
store_word rtmp_1, gpio_port0(reg_io_offset)
|
||||
load_imm rtmp_1, -1 * -30 + Display_HalfHeight << gp_b16_Y | -100 + Display_HalfWidth << gp_b16_X
|
||||
store_word rtmp_1, gpio_port0(reg_io_offset)
|
||||
load_imm rtmp_1, -1 * -50 + Display_HalfHeight << gp_b16_Y | 55 + Display_HalfWidth << gp_b16_X
|
||||
store_word rtmp_1, gpio_port0(reg_io_offset)
|
||||
; Draw a flat-shaded triangle
|
||||
; 1. GP0: Send packets to GP0 to draw a triangle
|
||||
load_imm rtmp_1, gp_Polygon | Color_PS_GoldenPoppy
|
||||
store_word rtmp_1, gpio_port0(reg_io_offset)
|
||||
load_imm rtmp_1, -1 * 100 + Display_HalfHeight << gp_b16_Y | -100 + Display_HalfWidth << gp_b16_X
|
||||
store_word rtmp_1, gpio_port0(reg_io_offset)
|
||||
load_imm rtmp_1, -1 * 20 + Display_HalfHeight << gp_b16_Y | 20 + Display_HalfWidth << gp_b16_X
|
||||
store_word rtmp_1, gpio_port0(reg_io_offset)
|
||||
load_imm rtmp_1, -1 * 50 + Display_HalfHeight << gp_b16_Y | 30 + Display_HalfWidth << gp_b16_X
|
||||
store_word rtmp_1, gpio_port0(reg_io_offset)
|
||||
; Bonus traingle
|
||||
load_imm rtmp_1, gp_Polygon | Color_PS_CadmiumRed
|
||||
store_word rtmp_1, gpio_port0(reg_io_offset)
|
||||
load_imm rtmp_1, -1 * 50 + Display_HalfHeight << gp_b16_Y | -100 + Display_HalfWidth << gp_b16_X
|
||||
store_word rtmp_1, gpio_port0(reg_io_offset)
|
||||
load_imm rtmp_1, -1 * 0 + Display_HalfHeight << gp_b16_Y | 20 + Display_HalfWidth << gp_b16_X
|
||||
store_word rtmp_1, gpio_port0(reg_io_offset)
|
||||
load_imm rtmp_1, -1 * -100 + Display_HalfHeight << gp_b16_Y | 30 + Display_HalfWidth << gp_b16_X
|
||||
store_word rtmp_1, gpio_port0(reg_io_offset)
|
||||
|
||||
idle:
|
||||
jump idle :: nop
|
||||
|
||||
.close
|
||||
Reference in New Issue
Block a user