; 32 bit graphics library for Symphony 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: Point 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: ; - r1: Status ; * 0 OK ; * SCREEN_INVALID_SIZE width invalid ; * SCREEN_INVALID_MODE bits_per_pixel invalid ; * SCREEN_FB_TOO_SMALL allocation too small ; Clobbers: ; - r2-r6, flags ; Globals written: ; - LOG_STRIDE ; - FB_WIDTH ; - FB_HEIGHT ; - BITS_PER_PIXEL ; Check the magic number load_16 flags, [globals.MAGIC_ADDRESS] cmp flags, globals.MAGIC_VALUE je set_graphics_mode_magic_ok mov flags, errno.MAGIC_BAD jmp r13 ; return set_graphics_mode_magic_ok: push r8 ; LOG Bytes/pixel push r9 ; Log width push r10 ; Height push r11 ; Size of FB in bytes/pixels cmp r3, 32 jne not_32_bit_mode mov r3, SCREEN_MODE_GRAPHICS_32 mov r8, 2 jmp mode_ok not_32_bit_mode: cmp r3, 8 jne invalid_mode mov r3, SCREEN_MODE_GRAPHICS_8 mov r8, 0 jmp mode_ok invalid_mode: pop r11 pop r10 pop r9 pop r8 mov flags, errno.SCREEN_INVALID_MODE jmp r13 ; return mode_ok: ; Width must be between 4 and 1024 cmp r4, 1024 ; max width of screen ja width_invalid cmp r4, 4 jb width_invalid ; Is width a power of two? mov r9, 10 mov r10, 1024 log_width_loop: cmp r4, r10 je width_ok lsr r10, r10, 1 sub r9, r9, 1 cmp r9, 4 jae log_width_loop width_invalid: pop r11 pop r10 pop r9 pop r8 mov flags, errno.SCREEN_INVALID_WIDTH jmp r13 ; return 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 single_buff ; ..we need twice the space lsl r11, r11, 1 single_buff: cmp r2, r11 jae size_ok pop r11 pop r10 pop r9 pop r8 mov flags, errno.SCREEN_FB_TOO_SMALL jmp r13 ; return size_ok: ; Set screen mode screen zr, r3 ; 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 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 save_fb_done 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 save_fb_done: store_32 [globals.FB_DRAW_PTR], r2 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 mov r1, r2 ; Return draw FB mov r3, 0 mov r4, 0 ; TODO call clear nor r2, zr, 0xff ; Colour = White (32-bit) pop r11 pop r10 pop r9 pop r8 mov flags, 0 ; OK jmp r13 ; return 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 fore ground 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: ; - r1: Status ; * 0 OK ; * SCREEN_INVALID_SIZE width invalid ; * SCREEN_INVALID_MODE bits_per_pixel invalid ; * SCREEN_FB_TOO_SMALL allocation too small ; Clobbers: ; - r2-r6, flags ; Globals written: ; - LOG_STRIDE ; - FB_WIDTH ; - FB_HEIGHT ; - BITS_PER_PIXEL ; Check the magic number load_16 flags, [globals.MAGIC_ADDRESS] cmp flags, globals.MAGIC_VALUE je set_text_mode_magic_ok mov flags, errno.MAGIC_BAD jmp r13 ; return set_text_mode_magic_ok: ;TODO: Sanity checks ;TODO: ?Clear screen push r8 ; LOG Bytes/pixel push r9 ; Log width push r10 ; Height push r11 ; Size of FB in bytes/pixels cmp r3, 32 jne not_32_bit_text_mode mov r3, SCREEN_MODE_TEXT_32 mov r8, 2 jmp text_mode_ok not_32_bit_text_mode: cmp r3, 8 jne invalid_text_mode mov r3, SCREEN_MODE_TEXT_8 mov r8, 0 jmp text_mode_ok invalid_text_mode: pop r11 pop r10 pop r9 pop r8 mov flags, errno.SCREEN_INVALID_MODE jmp r13 ; return text_mode_ok: ; Set screen mode screen zr, r3 ; Set FB pointer ; If double buffering.. cmp r6, 0 je save_fb_single_text_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 save_fb_text_done save_fb_single_text_buff: store_32 [globals.FB_SIZE_BYTE], r11 store_32 [globals.FB_DISPLAY_PTR], r2 mov r3, SCREEN_SETTING_DATA_OFFSET screen r3, r2 save_fb_text_done: store_32 [globals.FB_DRAW_PTR], r2 ; 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 pop r11 pop r10 pop r9 pop r8 mov flags, 0 ; OK jmp r13 ; return 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. ; 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 ; Set screen mode to default 8 bit text screen zr, zr ; Set FB pointer store_32 [globals.FB_DISPLAY_PTR], r1 store_32 [globals.FB_DRAW_PTR], r1 ; Size is 96*40*1 byte mov r1, 3840 store_32 [globals.FB_SIZE_BYTE], r1 mov flags, SCREEN_SETTING_DATA_OFFSET screen flags, r1 ; Set default screen font mov flags, SCREEN_SETTING_FONT screen flags, zr ; Set foreground to white mov flags, SCREEN_SETTING_FOREGROUND_COLOR nor r1, zr, 0xff ; White screen flags, r1 ; Set background to black mov flags, SCREEN_SETTING_BACKGROUND_COLOR screen flags, zr mov flags, 0 ; OK jmp r13 pub clear: ; void clear() ; Paints the whole screen black ; ; Arguments: ; - None ; Clobbers: ; - r1: Color ; - r2: fill_screen ; - r3: fill_screen ; - r4: fill_screen ; - flags mov r1, 0 ; Black ; Fall through pub fill_screen: ; void fill_screen(u32 color) ; Fills the whole screen in a single color. ; ; Arguments: ; - r1: Color, 32 bit RGB0 ; Clobbers: ; - r2: Pixel pointer ; - r3: End address ; - r4: Stride ; - flags ; 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] lsl r3, r3, r4 ; Num bytes in FB load_32 r2, [globals.FB_DRAW_PTR] add r3, r3, r2 ; End of FB load_8 r4, [globals.FB_BYTES_PER_PIXEL] fill_screen_loop: ; Screen is always a multiple of 4*3 ; we can unroll this 12 times. store_32 [r2], r1 add r2, r2, r4 store_32 [r2], r1 add r2, r2, r4 store_32 [r2], r1 add r2, r2, r4 store_32 [r2], r1 add r2, r2, r4 store_32 [r2], r1 add r2, r2, r4 store_32 [r2], r1 add r2, r2, r4 store_32 [r2], r1 add r2, r2, r4 store_32 [r2], r1 add r2, r2, r4 store_32 [r2], r1 add r2, r2, r4 store_32 [r2], r1 add r2, r2, r4 store_32 [r2], r1 add r2, r2, r4 store_32 [r2], r1 add r2, r2, r4 cmp r2, r3 jb fill_screen_loop 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: ; - None ; Clobbers: ; - r1: Old display FB => new draw FB ; - r2: Old draw FB => new display FB ; - flags ; Globals written: ; - FB_DISPLAY_PTR ; - FB_DRAW_PTR load_32 r1, [globals.FB_DISPLAY_PTR] load_32 r2, [globals.FB_DRAW_PTR] mov flags, SCREEN_SETTING_DATA_OFFSET screen flags, r2 store_32 [globals.FB_DISPLAY_PTR], r2 store_32 [globals.FB_DRAW_PTR], r1 jmp r13 ; return 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 ; - r4-r7 ignored but PRESERVED ; Result: ; - None ; Clobbers: ; - flags ; Globals read: ; - FB_DRAW_PTR ; - LOG_WIDTH ; Screen is `1 << WIDTH pixels wide load_8 flags, [globals.FB_LOG_WIDTH] ; Compute pixel address lsl flags, r4, flags ; Y * width add flags, flags, r3 ; Y * width + X lsl flags, flags, 2 ; pixel to address load_32 r1, [globals.FB_DRAW_PTR] add flags, flags, r1 ; += frambuffer_ptr ; Set pixel value store_32 [flags], r2 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: ; - r7, flags push r13 ; if x0 > x1 ; dx = -1 ; else ; dx = +1 ; endif cmp r4, r2 or r7, flags, 0x02 lsl r7, r7, 29 asr r7, r7, 30 jmp draw_line_h_loop_in draw_line_h_loop: add r2, r2, r7 draw_line_h_loop_in: qcall draw_pixel cmp r2, r4 jne draw_line_h_loop pop r13 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 but PRESERVED ; - r5: Y1 coord ; Returns: ; - r1: Color 24 bit RGB0 PRESERVED ; - r2: X coord PRESERVED ; - r3: Y1 coord ; Clobbers: ; - r7, flags push r13 ; if y0 > y1 ; dy = -1 ; else ; dy = +1 ; endif cmp r5, r3 or r7, flags, 0x02 lsl r7, r7, 29 asr r7, r7, 30 jmp draw_line_v_loop_in draw_line_v_loop: add r3, r3, r7 draw_line_v_loop_in: qcall draw_pixel cmp r3, r5 jne draw_line_v_loop pop r13 jmp r13 ; return 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 ; Globals read: ; - FB_DRAW_PTR ; - FB_DRAW_STRIDE ; - ...others I expect ; push r11 ; sy ; push r10 ; dy ; push r9 ; sx ; push r8 ; dx ; 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, zr ; sx = -1 ; endif draw_line_move_right_done: ; 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, zr ; sy = -1 ; endif draw_line_move_down_done: push r12 ; err, err2 push r13 ; lr ; int err = dx+dy /* error value e_xy */ add r12, r8, r10 ; loop while(true) draw_line_loop: qcall draw_pixel ; err2 = 2*err; lsl r12, r12, 1 ; if (err2 >= dy) { /* e_xy+e_x > 0 */ cmp r12, r10 lsr r12, r12, 1 ; restore err jl draw_line_loop_skip_x ; if (x0 == x1) break; cmp r2, r4 je draw_line_loop_done ; err += dy add r12, r12, r10 ; x0 += sx; add r2, r2, r9 draw_line_loop_skip_x: ; err2 = 2*err; lsl r12, r12, 1 ; if (err2 <= dx) { /* e_xy+e_y < 0 */ cmp r12, r8 lsl r12, r12, 1 ; restore err jl draw_line_loop_skip_y ; if (y0 == y1) break; cmp r3, r5 je draw_line_loop_done ; err += dx add r12, r12, r8 ; y0 += sy add r3, r3, r11 draw_line_loop_skip_y: jmp draw_line_loop ; endloop draw_line_loop_done: pop r13 pop r12 pop r11 pop r10 pop r9 pop r8 jmp r13 ; return