WIP: Graphics screen and graphics_32/draw_line #23

Draft
Gelthor wants to merge 5 commits from Gelthor/symphony_stdlib:graphics into main
5 changed files with 981 additions and 1 deletions
Executable → Regular
View File
Executable → Regular
+2 -1
View File
@@ -27,4 +27,5 @@ pub const FB_BYTES_PER_PIXEL = 0x2a ; U8 Specialisations should hardcode t
; Log2 of bytes per pixel
; * 0 => 8 bits per pixel
; * 2 => 32 bits per pixel
pub const FB_LOG_BPP = 0x2b ; U8 Specialisations should hardcode this
pub const FB_LOG_BPP = 0x2b ; U8 Specialisations should hardcode this
pub const FB_MODE = 0x2c ; U8 Screen mode: 0 => text; 1 => graphics
+444
View File
@@ -0,0 +1,444 @@
; 32 bit graphics library for Symphony
;
; Screen MUST be initialsed by calling `screen.set_graphics_mode`.
include globals
include errno
pub draw_pixel_safe:
; bool draw_pixel_safe(u32 color, u16 x, u16 y)
; Checks if the position is valid for the current mode. If not the FB
; is not touched and returns -1, otherwise the pixel is drawn on the
; current draw framebuffer.
;
; Arguments:
; - r1: Color 24 bit RGB0 PRESERVED
; - r2: X coord PRESERVED
; - r3: Y coord PRESERVED
; Returns:
; - flags: Status code
; Errors: Was the draw sucessful?
; - SCREEN_OUTSIDE_FB: if (X,Y) not on screen
; Clobbers:
; - r6: scratch
mov r6, 1
load_8 flags, [globals.FB_LOG_WIDTH]
lsl r5, r6, flags
cmp r2, r5
jb draw_pixel_safe_X_ok
mov flags, errno.SCREEN_OUTSIDE_FB
jmp r13 ; return
draw_pixel_safe_X_ok:
mov r6, 1
load_8 flags, [globals.FB_LOG_WIDTH]
lsl r6, r6, flags
lsr flags, r6, 1
lsr r6, r6, 2 ; (LOG_BPP)
add r6, flags, r6
cmp r3, r6
jb draw_pixel_safe_Y_ok
mov flags, errno.SCREEN_OUTSIDE_FB
jmp r13 ; return
draw_pixel_safe_Y_ok:
; Fall through
pub draw_pixel:
; void draw_pixel(u32 color, u16 x, u16 y)
; Draw pixel at the position, no checks on position, can potentally write to any memory.
; Framebuffer pointer is stored in FB_PTR.
;
; Arguments:
; - r1 Color 24 bit RGB0 PRESERVED
; - r2 X coord PRESERVED
; - r3 Y coord PRESERVED
; Result:
; - flags: errno.OK
; Cobbers:
; - r6: Pixel address
; Globals read:
; - FB_DRAW_PTR
; - FB_LOG_WIDTH
; Screen is `1 << WIDTH pixels wide
load_8 flags, [globals.FB_LOG_WIDTH]
; Compute pixel address
lsl flags, r3, flags ; Y * width
add flags, flags, r2 ; Y * width + X
lsl flags, flags, 2 ; pixel to address
load_32 r6, [globals.FB_DRAW_PTR]
add flags, flags, r6 ; += frambuffer_ptr
; Set pixel value
store_32 [flags], r1
mov flags, errno.OK ; return OK for draw_pixel_safe
jmp r13 ; return
pub draw_line_h:
; void draw_line_h(u32 color, u16 x0, u16 y, u16 x1)
; Draws a straight horizontal line from (x0, y) to (x1, y) (inclusive) using `color`
; on to the current `FB_DRAW_PTR` buffer.
;
; Arguments:
; - r1: Color 24 bit RGB0 PRESERVED
; - r2: X0 coord
; - r3: Y coord PRESERVED
; - r4: X1 coord
; Returns:
; - r1: Color 24 bit RGB0 PRESERVED
; - r2: X1 coord
; - r3: Y coord PRESERVED
; Clobbers:
; - r5: pixel ptr
; - r6: FB end
; - r7: FB increment
; - flags
; Globals read:
; - FB_DRAW_PTR
; - LOG_WIDTH
push r13
; if start.x > end.x
; dx = -4 = -1 * bytes_per_pixel
; else
; dx = +4 = +1 * bytes_per_pixel
; endif
cmp r4, r2 ; ...00???
and r7, flags, 0x04 ; ...00??0
or r7, flags, 0x02 ; ...00?10
lsl r7, r7, 29 ; ?100...
asr r7, r7, 28 ; +/- 4 (Hardcode LOG_BPP)
mov r5, r3 ; Y1 = Y0 = Y
; Fall through
draw_line_basic:
; void draw_line_h(u32 color, u16 x0, u16 y0, u16 x1, u16 y1, _, u32 incr)
; Draws a straight line at any multiple of 45° from (x0, y0) to (x1, y1) (inclusive) using `color`
; on to the current `FB_DRAW_PTR` buffer.
; `r7` contains a precomputed increment to the FB pointer.
;
; Arguments:
; - r1: Color 24 bit RGB0 PRESERVED
; - r2: X0 coord
; - r3: Y0 coord
; - r4: X1 coord
; - r5: Y1 coord
; - r6: ignored, non-standard calling convetion for internal function
; - r7: FB pointer increment
; Returns:
; - r1: Color 24 bit RGB0 PRESERVED
; - r2: X1 coord
; - r3: Y1 coord
; Clobbers:
; - r5: last pixel address
; - r6: first pixel address/ptr
; - r7: FB increment
; - flags
; Globals read:
; - FB_DRAW_PTR
; - FB_LOG_WIDTH
; Compute start and end pixel addresses
load_8 flags, [globals.FB_LOG_WIDTH]
lsl r6, r3, flags ; start.y * width
add r6, r6, r2 ; start.y * width + start.x
mov r2, r4 ; return end.x
mov r3, r5 ; return end.y
lsl r5, r5, flags ; end.y * width
add r5, r5, r2 ; end.y * width + end.x
lsl r6, r6, 2 ; scale pixel to bytes (LOG_BBP)
lsl r5, r5, 2 ; scale pixel to bytes (LOG_BBP)
load_32 flags, [globals.FB_DRAW_PTR]
add r6, r6, flags ; pixel_ptr += frambuffer_ptr
add r5, r5, flags ; end_ptr += frambuffer_ptr
jmp draw_line_h_loop_in
draw_line_h_loop:
add r6, r6, r7
draw_line_h_loop_in:
; Set pixel value
store_32 [r6], r1
cmp r5, r6
jne draw_line_h_loop
jmp r13 ; return
pub draw_line_v:
; void draw_line_v(u32 color, u16 x, u16 _, u16 y0, u16 x1)
; Draws a straight verticle line from (x, y0) to (x, y1) (inclusive) using `color`
; on to the current `FB_DRAW_PTR` buffer.
;
; Arguments:
; - r1: Color 24 bit RGB0 PRESERVED
; - r2: X coord PRESERVED
; - r3: Y0 coord
; - r4: ignored
; - r5: Y1 coord
; Returns:
; - r1: Color 24 bit RGB0 PRESERVED
; - r2: X coord PRESERVED
; - r3: Y1 coord
; Clobbers:
; - r5: draw_line_basic
; - r6: draw_line_basic
; - r7: increment
; - flags
; Globls read:
; - FB_DRAW_PTR
; - FB_LOG_WIDTH
push r13
; if start.x > end.x
; dx = -4 = -1 * bytes_per_pixel
; else
; dx = +4 = +1 * bytes_per_pixel
; endif
cmp r5, r3 ; ...00???
and r7, flags, 0x04 ; ...00??0
or r7, flags, 0x02 ; ...00?10
lsl r7, r7, 29 ; ?100...
asr r7, r7, 28 ; +/- 4 (Hardcode LOG_BPP)
load_8 flags, [globals.FB_LOG_WIDTH]
lsl r7, r7, flags ; +/- 4 * width
mov r4, r2 ; X1 = X0 = X
jmp draw_line_basic ; tail call
pub draw_line:
; void draw_line(u32 color, u16 x0, u16 y0, u16 x1, u16 y1)
; Draws a straight line from (x0, y0) to (x1, y1) (inclusive) using `color`
; on to the current `FB_DRAW_PTR` buffer.
;
; Arguments:
; - r1: Color 24 bit RGB0 PRESERVED
; - r2: X0 coord
; - r3: Y0 coord
; - r4: X1 coord
; - r5: Y1 coord
; Returns:
; - r1: Color 24 bit RGB0 PRESERVED
; - r2: X1 coord
; - r3: Y1 coord
; Clobbers:
; - r4-r7, flags
; - r5: draw_pixel
; - r6: draw_pixel
; Globals read:
; - FB_DRAW_PTR
; - FB_DRAW_STRIDE
; - ...others I expect
; push r13 ; lr
; push r12 ; err
; push r11 ; sy
; push r10 ; dy
; push r9 ; sx
; push r8 ; dx
; - r7: err2
; Stack () ; empty
; int dx = abs(x1-x0), sx = x0<x1 ? 4 : -4;
cmp r2, r4
ja draw_line__move_left
jb draw_line__move_right
; if x0 == x1
jmp draw_line_v ; tail call
; elif x0 < x1
draw_line__move_right:
push r8 ; dx
push r9 ; sx
sub r8, r4, r2
mov r9, 4 ; sx = 1 * FB_BYTES_PER_PIXEL
jmp draw_line__move_right_done
; else x0 > x1
draw_line__move_left:
push r8 ; dx
push r9 ; sx
sub r8, r2, r4
nor r9, zr, 3 ; sx = -1 * FB_BYTES_PER_PIXEL
; endif
draw_line__move_right_done:
; Stack (r8 r9)
; int dy = -abs(y1-y0), sy = y0<y1 ? 4 * width : -4 * width;
cmp r3, r5
jb draw_line__move_down
ja draw_line__move_up
; if y0 == y0
; Restore r8, r9
pop r9
pop r8
jmp draw_line_h ; tail call
; elif y0 < y1
draw_line__move_down:
push r10 ; dy
push r11 ; sy
sub r10, r3, r5
mov r11, 4 ; sy = 1 * FB_BYTES_PER_PIXEL
jmp draw_line__move_down_done
; else y0 > y1
draw_line__move_up:
push r10 ; dy
push r11 ; sy
sub r10, r5, r3
nor r11, zr, 3 ; sy = -1 * FB_BYTES_PER_PIXEL
; endif
draw_line__move_down_done:
load_8 flags, [globals.FB_LOG_WIDTH]
lsl r11, r11, flags ; sy = +/- 1 * FB_BYTES_PER_PIXEL * width
; Stack (r8 r9 r10 r11)
; Compute start and end pixel addresses
load_8 flags, [globals.FB_LOG_WIDTH]
lsl r6, r3, flags ; start.y * width
add r6, r6, r2 ; start.y * width + start.x
mov r2, r4 ; return end.x
mov r3, r5 ; return end.y
lsl r5, r5, flags ; end.y * width
add r5, r5, r2 ; end.y * width + end.x
lsl r6, r6, 2 ; scale pixel to bytes (LOG_BBP)
lsl r5, r5, 2 ; scale pixel to bytes (LOG_BBP)
load_32 flags, [globals.FB_DRAW_PTR]
add r6, r6, flags ; pixel_ptr += frambuffer_ptr
add r5, r5, flags ; end_ptr += frambuffer_ptr
; Stack (r8 r9 r10 r11)
push r12 ; err
push r13 ; lr
; Stack (r8 r9 r10 r11 r12 r13)
; int err = dx+dy /* error value e_xy */
add r12, r8, r10
; loop while(true)
draw_line__loop:
; Draw pixel
store_32 [r6], r1
; err2 = 2*err;
lsl r7, r12, 1
; if (err2 >= dy) { /* e_xy+e_x > 0 */
cmp r7, r10
jl draw_line__loop_skip_x
; if (x0 == x1) break;
cmp r6, r5
je draw_line__loop_done
; err += dy
add r12, r12, r10
; x0 += sx;
add r6, r6, r9
draw_line__loop_skip_x:
; if (err2 <= dx) { /* e_xy+e_y < 0 */
cmp r7, r8
jg draw_line__loop_skip_y
; if (y0 == y1) break;
cmp r6, r5
je draw_line__loop_done
; err += dx
add r12, r12, r8
; y0 += sy
add r6, r6, r11
draw_line__loop_skip_y:
jmp draw_line__loop
; endloop
draw_line__loop_done:
; Stack (r8 r9 r10 r11 r12 r13)
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
jmp r13 ; return
pub fill_rectangle:
; void fill_rectangle(u32 fill color, u16 left, u16 top, u16 right, u16 bottom)
; Draws a rectangle from (left,top) to (right,bottom) with the outline in `border_color`.
; Fills it with `fill_color`
; Arguments:
; - r1: Fill color 24 bit RGB0
; - r2: Left coord
; - r3: Top coord
; - r4: Right coord
; - r5: Bottom coord
; Returns:
; - r1: Color 24 bit RGB0 PRESERVED???
; - r2: X1 coord
; - r3: Y1 coord
; Clobbers:
; - r4-r7, flags
; - r5: draw_pixel
; - r6: draw_pixel
; Globals read:
; - FB_DRAW_PTR
; - FB_DRAW_STRIDE
push r8 ;
push r9 ;
push r10 ;
; Compute start and end pixel addresses of first row
load_8 flags, [globals.FB_LOG_WIDTH]
lsl r7, r5, flags ; bottom * width
lsl r5, r3, flags ; top * width
add r6, r5, r4 ; top * width + right
add r5, r5, r2 ; top * width + left
add r7, r7, r4 ; bottom * width + right
lsl r6, r6, 2 ; scale pixel to bytes (LOG_BBP)
lsl r5, r5, 2 ; scale pixel to bytes (LOG_BBP)
lsl r7, r7, 2 ; scale pixel to bytes (LOG_BBP)
load_32 flags, [globals.FB_DRAW_PTR]
add r7, r7, flags ; bottom_right_ptr += frambuffer_ptr
add r6, r6, flags ; row_end_ptr += frambuffer_ptr
add r5, r5, flags ; pixel_ptr += frambuffer_ptr
mov r8, 4 ; X increment
mov r10, 1
load_8 flags, [globals.FB_LOG_WIDTH]
lsl r10, r10, flags ; screen width
sub r9, r10, r4
add r9, r9, r2 ; Y wraparound = screen_width - (right-left)
lsl r9, r9, 2 ; scale pixel to bytes (LOG_BBP)
lsl r10, r10, 2 ; scale pixel to bytes (LOG_BBP)
jmp fill_rectangle__loop_in
; For each row
fill_rectangle__loop_y:
add r5, r5, r9 ; move to start of next row
add r6, r6, r10 ; move end_ptr down 1 row
fill_rectangle__loop_in:
; Draw pixel
store_32 [r5], r1
; Fill rest of the row
fill_rectangle__loop_x:
add r5, r5, r8
; Draw pixel
store_32 [r5], r1
cmp r5, r6
jb fill_rectangle__loop_x
cmp r5, r7
jb fill_rectangle__loop_y
pop r10
pop r9
pop r8
jmp r13 ; return
+535
View File
@@ -0,0 +1,535 @@
;include stdlib/src/globals
;include stdlib/src/errno
include globals
include errno
const SCREEN_SETTING_MODE = 0 ; Use zr instead
const SCREEN_SETTING_DATA_OFFSET = 1
const SCREEN_SETTING_RESOLUTION = 2
const SCREEN_SETTING_FOREGROUND_COLOR = 2
const SCREEN_SETTING_BACKGROUND_COLOR = 3
const SCREEN_SETTING_FONT = 4
const SCREEN_MODE_TEXT_8 = 0
const SCREEN_MODE_TEXT_32 = 1
const SCREEN_MODE_GRAPHICS_8 = 2
const SCREEN_MODE_GRAPHICS_32 = 3
pub set_graphics_mode:
; u16 set_graphics_mode(void *FB_ptr, size_t FB_size, u8 bit_per_pixel, u16 width, bool clear, bool double_buf)
; Sets the screen to graphics mode, the resolution, and colour depth.
; Optionally clears the screen.
;
; Arguments:
; - r1: Pointer to allocated framebuffer
; - r2: Size of FB allocation, in bytes
; - r3: Bits per pixel: One of `8` or `32`
; - r4: Width - height is set to `width / 4 * 3`
; - r5: If non-zero, clears the current framebuffer.
; - r6: If non-zero, enable double buffering
; Returns:
; - flags: Error code
; Clobbers:
; - r7: Screen mode setting
; Errors:
; - 0 OK
; - SCREEN_INVALID_SIZE width invalid
; - SCREEN_INVALID_MODE bits_per_pixel invalid
; - SCREEN_FB_TOO_SMALL allocation too small
; - MAGIC_BAD stdlib magic not present
; Globals written:
; - FB_DISPLAY_PTR
; - FB_DISPLAY_DEPTH
; - FB_DISPLAY_STRIDE
; - FB_DRAW_PTR
; - FB_DRAW_DEPTH
; - FB_DRAW_STRIDE
; - FB_SIZE_BYTE
; - FB_WIDTH_PX
; - FB_HEIGHT_PX
; - FB_LOG_WIDTH
; - FB_LOG_STRIDE
; - FB_BYTES_PER_PIXEL
; - FB_LOG_BPP
; - FB_MODE
; Globals read:
; - MAGIC_ADDRESS
push r8 ; LOG Bytes/pixel
push r9 ; Log width
push r10 ; Height
push r11 ; Size of FB in bytes/pixels
; Check the magic number
load_16 flags, [globals.MAGIC_ADDRESS]
cmp flags, globals.MAGIC_VALUE
je set_graphics_mode__magic_ok
mov r6, errno.MAGIC_BAD
jmp set_graphics_mode__error
set_graphics_mode__magic_ok:
cmp r3, 32
jne set_graphics_mode__not_32_bit_mode
mov r7, SCREEN_MODE_GRAPHICS_32
mov r8, 2
jmp set_graphics_mode__mode_ok
set_graphics_mode__not_32_bit_mode:
cmp r3, 8
jne set_graphics_mode__invalid_mode
mov r7, SCREEN_MODE_GRAPHICS_8
mov r8, 0
jmp set_graphics_mode__mode_ok
set_graphics_mode__invalid_mode:
mov r6, errno.SCREEN_INVALID_MODE
jmp set_graphics_mode__error
set_graphics_mode__mode_ok:
; Width must be between 4 and 1024
cmp r4, 1024 ; max width of screen
ja set_graphics_mode__width_invalid
cmp r4, 4
jb set_graphics_mode__width_invalid
; Compute log base 2 of width, fail if
; width is not a exact power of 2
mov r9, 10
mov r10, 1024
set_graphics_mode__log_width_loop:
cmp r4, r10
je set_graphics_mode__width_ok
lsr r10, r10, 1
sub r9, r9, 1
cmp r9, 4
jae set_graphics_mode__log_width_loop
set_graphics_mode__width_invalid:
mov r6, errno.SCREEN_INVALID_WIDTH
jmp set_graphics_mode__error
set_graphics_mode__width_ok:
; Now r9 = log width
; height = width/4 * 3
lsr r4, r4, 2
lsl r10, r4, 1
add r10, r10, r4 ; height
; Compute size of FB
lsl r11, r10, r9 ; Size of FB in pixels
lsl r11, r11, r8 ; Size of FB in bytes
; If double buffering..
cmp r6, 0
je set_graphics_mode__single_buff
; ..we need twice the space
lsl r11, r11, 1
set_graphics_mode__single_buff:
cmp r2, r11
jae set_graphics_mode__size_ok
mov r6, errno.SCREEN_FB_TOO_SMALL
jmp set_graphics_mode__error
set_graphics_mode__size_ok:
; Set screen mode
screen zr, r7
; Set screen size
mov flags, SCREEN_SETTING_RESOLUTION
; Setting is width/4 - 1
sub r4, r4, 1
screen flags, r4
; Restore width
add r4, r4, 1
lsl r4, r4, 2
; Set FB pointer
; If double buffering..
cmp r6, 0
je set_graphics_mode__save_fb_single_buff
; ..we want the size of each FB
lsr r11, r11, 1
store_32 [globals.FB_DISPLAY_PTR], r2
mov flags, SCREEN_SETTING_DATA_OFFSET
screen flags, r2
add r2, r2, r11
jmp set_graphics_mode__save_fb_done
set_graphics_mode__save_fb_single_buff:
store_32 [globals.FB_DISPLAY_PTR], r2
mov flags, SCREEN_SETTING_DATA_OFFSET
screen flags, r2
set_graphics_mode__save_fb_done:
store_32 [globals.FB_DRAW_PTR], r2
store_16 [globals.FB_DISPLAY_DEPTH], r3
store_16 [globals.FB_DRAW_DEPTH], r3
store_16 [globals.FB_SIZE_BYTE], r11
store_16 [globals.FB_WIDTH_PX], r4
store_16 [globals.FB_HEIGHT_PX], r10
store_8 [globals.FB_LOG_WIDTH], r9
store_8 [globals.FB_LOG_BPP], r8
mov flags, 1
lsl r8, flags, r8
store_8 [globals.FB_BYTES_PER_PIXEL], r8
lsl r4, r4, r8 ; Stride in bytes
store_16 [globals.FB_DISPLAY_STRIDE], r4
store_16 [globals.FB_DRAW_STRIDE], r4
mov flags, 1 ; Graphics mode
store_8 [globals.FB_MODE], flags
; Clean stack
pop r11
pop r10
pop r9
pop r8
cmp r5, 0
je set_graphics_mode__not_clear
; If double buffering
cmp r6, 0
je set_graphics_mode__clear_single_fb
; Clear one buffer..
push r13
counter r13
add r13, r13, 12
jmp clear_graphics_fb ; Call
pop r13
; ...then the other
set_graphics_mode__clear_single_fb:
jmp clear_graphics_fb ; Tail call
set_graphics_mode__not_clear:
mov flags, errno.OK
jmp r13 ; return
set_graphics_mode__error:
; r6 has the error code
pop r11
pop r10
pop r9
pop r8
mov flags, r6
jmp r13 ; return
pub clear:
; void clear()
; Paints the draw framebuffer black and switches to it
;
; Arguments:
; - None
; Returns:
; - flags: 0 OK
; Clobbers:
; - r1: Color
; - r2: fill_screen
; - r3: fill_screen
; - r4: fill_screen
; - r5: Alternate link register
mov r5, r13
load_8 flags, [globals.FB_MODE]
mov r13, clear__done
je clear__graphics
jmp clear_text_fb ; Call, return to clear__done
clear__graphics:
jmp clear_graphics_fb ; Call
clear__done:
mov r13, r5
jmp switch_buffers ; Tail call
pub clear_text_fb:
; void clear_text_mode()
; Paints the whole text mode screen in the background colour
;
; Arguments:
; - None
; Returns:
; - flags: 0 OK
; Clobbers:
; - r1: Color
; - r2: Pixel pointer
; - r3: End address
; - r4: Bytes in FB
mov r1, 0 ; Blank background colour in either 8 or 32 bit
mov r3, 3840 ; 96*40 characters on screen
load_8 r4, [globals.FB_LOG_BPP]
lsl r3, r3, r4 ; Num bytes in FB
load_32 r2, [globals.FB_DRAW_PTR]
add r3, r3, r2 ; Start of FB
lsl r4, r3, r4 ; Num bytes in FB
load_32 r2, [globals.FB_DRAW_PTR]
add r3, r4, r2 ; End of FB
jmp fill_screen__loop
pub clear_graphics_fb:
; u16 clear_graphics_fb()
; Paints all of the current graphics mode draw buffer black
;
; Arguments:
; - None
; Returns:
; - flags: 0 OK
; Clobbers:
; - r1: Color
; - r2: fill_screen
; - r3: fill_screen
; - r4: fill_screen
mov r1, 0 ; Black in either 8 or 32 bit
; Fall through
pub fill_screen:
; u16 fill_screen(u32 color)
; Fills the whole graphics framebuffer in a single color.
;
; Arguments:
; - r1: Color. Either 8 bit or 32 bit RGB0
; Returns:
; - flags: 0 OK
; Clobbers:
; - r2: Pixel pointer
; - r3: End address
; - r4: Bytes in FB
; Reads globals:
; - FB_DRAW_PTR
; - LOG_BPP
; - LOG_WIDTH
; - PIXEL_HEIGHT
load_8 r2, [globals.FB_LOG_WIDTH]
load_16 r3, [globals.FB_HEIGHT_PX]
lsl r3, r3, r2
load_8 r4, [globals.FB_LOG_BPP]
cmp r4, 0
jne fill_screen__32_bit
; 8-bit: So copy the color so we write 32 bits at a time
lsl flags, r1, 8
or r1, flags, r1
lsl flags, r1, 16
or r1, flags, r1
fill_screen__32_bit:
lsl r4, r3, r4 ; Num bytes in FB
load_32 r2, [globals.FB_DRAW_PTR]
add r3, r4, r2 ; End of FB
; All modes have multiple of 4*3*4 bytes
; so we can unroll writing 4 bytes 12 times.
; Except: 4x3 8-bit graphics mode has only 12 bytes
cmp r4, 12
je fill_screen__12
fill_screen__loop:
store_32 [r2], r1
add r2, r2, 4
store_32 [r2], r1
add r2, r2, 4
store_32 [r2], r1
add r2, r2, 4
store_32 [r2], r1
add r2, r2, 4
store_32 [r2], r1
add r2, r2, 4
store_32 [r2], r1
add r2, r2, 4
store_32 [r2], r1
add r2, r2, 4
store_32 [r2], r1
add r2, r2, 4
store_32 [r2], r1
add r2, r2, 4
fill_screen__12:
store_32 [r2], r1
add r2, r2, 4
store_32 [r2], r1
add r2, r2, 4
store_32 [r2], r1
add r2, r2, 4
cmp r2, r3
jb fill_screen__loop
mov flags, errno.OK
jmp switch_buffers ; Tail call
pub set_text_mode_default:
; u16 set_text_mode_default(void *FB_ptr)
; Sets the screen to default text mode, the font, and colour depth. Also sets fore ground and background colors.
; Disables double buffering. Does not clear the screen.
; Size of allcation is not checked.
;
; Arguments:
; - r1: Address of allocated framebuffer
; Returns:
; - flags: 0 ; OK, never fails
; Clobbers:
; - r1, flags
; Globals written:
; - FB_DISPLAY_PTR
; - FB_DRAW_PTR
; - FRAME_BUFFER_SIZE
; Size is 96*40*1 byte
mov r2, 3840 ; Size of FB in bytes
mov r3, 8 ; Bits per pixel
mov r4, 0 ; Default font
mov r5, 0 ; Don't clear
mov r6, 0 ; Single buffer
; Fall through
pub set_text_mode:
; u16 set_text_mode(void *FB_ptr, size_t FB_size, u8 bit_per_pixel, u8 font, bool clear, bool double_buf)
; Sets the screen to text mode, the font, and colour depth. Also sets foreground and background colors.
; Optionally clears the screen.
; Arguments:
; - r1: Address of allocated framebuffer
; - r2: Size of FB allocation, in bytes
; - r3: Bits per pixel: One of `8` or `32`
; - r4: Font, one of {0,1,2,3}
; - r5: If non-zero, clears the current framebuffer.
; - r6: If non-zero, enable double buffering
; Returns:
; - flags: Error code
; Clobbers:
; - r7: Screen mode setting
; Errors:
; - 0 OK
; - SCREEN_INVALID_SIZE width invalid
; - SCREEN_INVALID_MODE bits_per_pixel invalid
; - SCREEN_FB_TOO_SMALL allocation too small
; Globals written:
; - LOG_STRIDE
; - FB_WIDTH
; - FB_HEIGHT
; - BITS_PER_PIXEL
; - FB_DRAW_PTR
; - FB_SIZE_BYTE
; - FB_MODE
; - FB_SIZE_BYTE
; Globals read:
; - MAGIC_ADDRESS
push r8 ; LOG Bytes/pixel
push r9 ; Log width
push r10 ; Height
push r11 ; Size of FB in bytes/pixels
; Check the magic number
load_16 flags, [globals.MAGIC_ADDRESS]
cmp flags, globals.MAGIC_VALUE
je set_text__mode_magic_ok
mov r6, errno.MAGIC_BAD
jmp set_text_mode__end
set_text__mode_magic_ok:
;TODO: Sanity checks
cmp r3, 32
jne set_text__not_32_bit_text_mode
mov r7, SCREEN_MODE_TEXT_32
mov r8, 2
jmp text_mode__ok
set_text__not_32_bit_text_mode:
cmp r3, 8
jne set_text_mode__invalid_mode
mov r7, SCREEN_MODE_TEXT_8
mov r8, 0
jmp text_mode__ok
set_text_mode__invalid_mode:
mov r6, errno.SCREEN_INVALID_MODE
jmp set_text_mode__end
text_mode__ok:
_set_test_mode__default:
; Set screen mode
screen zr, r7
; Set FB pointer
; If double buffering..
cmp r6, 0
je set_text_mode__save_fb_single_buff
; ..we want the size of each FB
lsr r11, r11, 1
store_32 [globals.FB_SIZE_BYTE], r11
store_32 [globals.FB_DISPLAY_PTR], r2
mov r3, SCREEN_SETTING_DATA_OFFSET
screen r3, r2
add r2, r2, r11
jmp set_text_mode__save_fb_done
set_text_mode__save_fb_single_buff:
store_32 [globals.FB_SIZE_BYTE], r11
store_32 [globals.FB_DISPLAY_PTR], r2
mov r3, SCREEN_SETTING_DATA_OFFSET
screen r3, r2
set_text_mode__save_fb_done:
store_32 [globals.FB_DRAW_PTR], r2
store_16 [globals.FB_SIZE_BYTE], r11
; Set screen font
; Only 0, 1, 2, 3 are valid
and r4, r4, 3
mov flags, SCREEN_SETTING_FONT
screen flags, r4
; Set foreground to white
mov flags, SCREEN_SETTING_FOREGROUND_COLOR
nor r4, zr, 0xff ; White
screen flags, r4
; Set background to black
mov flags, SCREEN_SETTING_BACKGROUND_COLOR
screen flags, zr
store_8 [globals.FB_MODE], zr ; Text mode
;TODO: ?Clear screen
mov r6, errno.OK
set_text_mode__end:
pop r11
pop r10
pop r9
pop r8
mov flags, r6
jmp r13 ; return
pub switch_buffers: ; SHOULD BE INLINED
; void switch_buffers()
; Swaps the display and draw buffers, and updates the screen to use the new display buffer.
;; Safe to run when single buffered.
;
; Arguments:
; - None
; Returns:
; - r1: Old display FB => new draw FB
; - r2: Old draw FB => new display FB
; Preserves:
; - flags: So it can be tail called from set_graphics_mode and set_text_mode
; Clobbers:
; - r3: Setting
; Globals written:
; - FB_DISPLAY_PTR
; - FB_DRAW_PTR
load_32 r1, [globals.FB_DISPLAY_PTR]
load_32 r2, [globals.FB_DRAW_PTR]
mov r3, SCREEN_SETTING_DATA_OFFSET
screen r3, r2
store_32 [globals.FB_DISPLAY_PTR], r2
store_32 [globals.FB_DRAW_PTR], r1
jmp r13 ; return
Executable → Regular
View File