diff --git a/src/errno.asm b/src/errno.asm old mode 100755 new mode 100644 diff --git a/src/globals.asm b/src/globals.asm old mode 100755 new mode 100644 index d9398c5..3fd860b --- a/src/globals.asm +++ b/src/globals.asm @@ -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 \ No newline at end of file +pub const FB_LOG_BPP = 0x2b ; U8 Specialisations should hardcode this +pub const FB_MODE = 0x2c ; U8 Screen mode: 0 => text; 1 => graphics diff --git a/src/graphics_32.asm b/src/graphics_32.asm new file mode 100644 index 0000000..56321ba --- /dev/null +++ b/src/graphics_32.asm @@ -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 + 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 + 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 diff --git a/src/screen.asm b/src/screen.asm new file mode 100644 index 0000000..668197e --- /dev/null +++ b/src/screen.asm @@ -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 diff --git a/src/start.asm b/src/start.asm old mode 100755 new mode 100644