forked from TCShenanigans/symphony_stdlib
Add globals and error codes
Added support for global variables. This requires including `start.asm` as the first code. This includes a `jmp` to 0x100 for user code, and a magic number that modules can check to verify th the user has correctly reserved the space. The magic number is 0xb301534c: * This has the high bit set so is not a valid instruction * On builds that ignore the high bit this decodes to `nor zr, zr, 0x534c` a no-op. * The immediate is "SL" for standardl ibrary. Due to a bug start pads with U... 0, instead of @addr. `start.asm` also initialises `sp` so it start just below the 64KiB LUT memory alocation. Added some error codes for the upcoming graphics module.
This commit is contained in:
+12
-1
@@ -16,10 +16,21 @@ All functions in the standard library should follow the following outline:
|
|||||||
; Arguments: <which register contains what argument>
|
; Arguments: <which register contains what argument>
|
||||||
; Result: <what is the result, and where is it stored>
|
; Result: <what is the result, and where is it stored>
|
||||||
; Clobbers: <list of registers that are clobbered>
|
; Clobbers: <list of registers that are clobbered>
|
||||||
|
; Globals: <list of globals are accessed. OPTIONAL>
|
||||||
<label>: <;SHOULD BE INLINED>
|
<label>: <;SHOULD BE INLINED>
|
||||||
<CODE>
|
<CODE>
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Functions should be in the appropriate asm file, if you are unsure where functionality fits make a seperate file and ask in the pull request
|
Functions should be in the appropriate asm file, if you are unsure where functionality fits make a seperate file and ask in the pull request
|
||||||
Functions that are provided for convenience/reference but should be inlined in production code should be marked with `;SHOULD BE INLINED` after their label
|
Functions that are provided for convenience/reference but should be inlined in production code should be marked with `;SHOULD BE INLINED` after their label.
|
||||||
|
|
||||||
|
If the function returns a status code in flags, the preamble should list all it might return.
|
||||||
|
|
||||||
|
## Globals
|
||||||
|
|
||||||
|
Any function that uses global variables should document this in the preamble comment, see above.
|
||||||
|
|
||||||
|
A file/module should check on intialisation that the address `globals.MAGIC_ADDRESS` contains the 16 bit value `globals.MAGIC_VALUE`, to ensure that the user has properly included [[src/start.asm]] and reservered the global variable area.
|
||||||
|
|
||||||
|
No opinion is offered on whether modules can assume globals variables are initialised to zero.
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
This is a standard library for symphony.
|
This is a standard library for symphony.
|
||||||
It is both intended as a practical toolkit to develop more complex software as well as a teaching resource.
|
It is both intended as a practical toolkit to develop more complex software as well as a teaching resource.
|
||||||
|
|
||||||
If you just want to use the standard library [[src/stdlib.asm]] is your main header, include it after your code.
|
If you just want to use the standard library [[src/stdlib.asm]] is your main header, include it after your code. Some modules also require [[src/start.asm]] at the very start of the program.
|
||||||
|
|
||||||
If you are using it as a learning resource have a look at the [teaching folder](teaching).
|
If you are using it as a learning resource have a look at the [teaching folder](teaching).
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ If you are intersted in contributing have a look at [[CONTRIBUTING.md]]
|
|||||||
| preserved | sp, r8 - r12 |
|
| preserved | sp, r8 - r12 |
|
||||||
| scratch | flags, r1 - r7 |
|
| scratch | flags, r1 - r7 |
|
||||||
| arguments | r1 - r7 |
|
| arguments | r1 - r7 |
|
||||||
| result | r1-r7 |
|
| result | flags, r1 - r7 |
|
||||||
| return address | r13 |
|
| return address | r13 |
|
||||||
|
|
||||||
Arguments not fitting into the 7 registers should be passed on the top of the stack, meaning they should be the last values pushed before the function call.
|
Arguments not fitting into the 7 registers should be passed on the top of the stack, meaning they should be the last values pushed before the function call.
|
||||||
@@ -32,9 +32,14 @@ Should a function return more values than fit into the 7 registers, the caller h
|
|||||||
This reduces the amount of argument registers to 6 and all arguments above that shall go on the stack, the pointer to the result stack shall **always** be passed in an argument register.
|
This reduces the amount of argument registers to 6 and all arguments above that shall go on the stack, the pointer to the result stack shall **always** be passed in an argument register.
|
||||||
This register points at the highest available address for results, with the 8th result being stored there, the 9th below it and so on.
|
This register points at the highest available address for results, with the 8th result being stored there, the 9th below it and so on.
|
||||||
|
|
||||||
|
Some functions return a success/failure status code in flags. A set low bit will indicate some error condition, the function may return more than one possible value to report different errors. A flags value of 0 is set on success. No other even values are used. This can be checked with `je` or `jne` immediatly on return to the caller. All other functions clobber flags.
|
||||||
|
|
||||||
### Stack
|
### Stack
|
||||||
Grows downwards from 0xXXFE_0000 (so top of memory -0x1_0000).
|
Grows downwards from 0xXXFE_0000 (so top of memory -0x1_0000).
|
||||||
|
|
||||||
|
### Globals
|
||||||
|
Global variables are stored near the bottom of RAM in the address range 0x0010..0x0100. Programs should `include src/start` as the first line before their own code and before other includes, or otherwise reserve this space, the first instruction should be a jump to user code.
|
||||||
|
|
||||||
### Types
|
### Types
|
||||||
|
|
||||||
#### String
|
#### String
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ pub const OK = 0x0000
|
|||||||
pub const SCREEN_INVALID_MODE = 0x0001
|
pub const SCREEN_INVALID_MODE = 0x0001
|
||||||
pub const SCREEN_INVALID_WIDTH = 0x0003
|
pub const SCREEN_INVALID_WIDTH = 0x0003
|
||||||
pub const SCREEN_FB_TOO_SMALL = 0x0005
|
pub const SCREEN_FB_TOO_SMALL = 0x0005
|
||||||
|
pub const SCREEN_OUTSIDE_FB = 0x0007
|
||||||
|
|
||||||
|
pub const MAGIC_BAD = 0x8001
|
||||||
|
|
||||||
; Extended error codes, these would require loading a 32 bit value.
|
; Extended error codes, these would require loading a 32 bit value.
|
||||||
pub const EXT_OK = 0x00000000
|
pub const EXT_OK = 0x00000000
|
||||||
+17
-7
@@ -1,18 +1,28 @@
|
|||||||
; Addresses of global variables
|
; Addresses of global variables
|
||||||
|
|
||||||
; If not double buffering these point to the same buffer
|
; If not double buffering these point to the same buffer
|
||||||
|
; If double buffering they must the same size
|
||||||
pub const FB_DISPLAY_PTR = 16 ; U32 Currently displayed buffer
|
pub const FB_DISPLAY_PTR = 16 ; U32 Currently displayed buffer
|
||||||
pub const FB_DRAW_PTR = 20 ; U32 Draw to this buffer
|
pub const FB_DISPLAY_STRIDE = 20 ; U32 Bytes in each row of the displayed buffer
|
||||||
pub const FRAME_BUFFER_SIZE = 24 ; U32
|
pub const FB_DRAW_PTR = 24 ; U32 Draw to this buffer
|
||||||
pub const PIXEL_WIDTH = 28 ; U16
|
pub const FB_DRAW_STRIDE = 28 ; U32 Bytes in each row of the draw buffer
|
||||||
pub const PIXEL_HEIGHT = 30 ; U16
|
pub const FB_SIZE_BYTE = 32 ; U32 In bytes
|
||||||
|
pub const FB_WIDTH_PX = 36 ; U16 Width of screen in pixels
|
||||||
|
pub const FB_HEIGHT_PX = 38 ; U16 Height of screen in pixels
|
||||||
|
|
||||||
; Log2 of width in pixels, e.g.
|
; Log2 of width in pixels, e.g.
|
||||||
; * 10 => 1024 * 768
|
; * 10 => 1024 * 768
|
||||||
pub const LOG_WIDTH = 32 ; U8
|
; * 8 => 256 * 192
|
||||||
|
pub const FB_LOG_WIDTH = 40 ; U8
|
||||||
|
pub const FB_LOG_STRIDE = 41 ; U8 Log2 of FB_xxx_STRIDE in bytes
|
||||||
|
|
||||||
pub const BYTES_PER_PIXEL = 33 ; U8
|
pub const FB_BYTES_PER_PIXEL = 42 ; U8 Specialisations should hardcode this
|
||||||
; Log2 of bytes per pixel
|
; Log2 of bytes per pixel
|
||||||
; * 0 => 8 bits per pixel
|
; * 0 => 8 bits per pixel
|
||||||
; * 2 => 32 bits per pixel
|
; * 2 => 32 bits per pixel
|
||||||
pub const LOG_BPP = 34 ; U8
|
pub const FB_LOG_BPP = 43 ; U8 Specialisations should hardcode this
|
||||||
|
|
||||||
|
pub const MAGIC_ADDRESS_LONG = 12 ; U32 Location of the magic value
|
||||||
|
pub const MAGIC_VALUE_LONG = 0xb301534c ; U32 Full 32 bits of the magic value
|
||||||
|
pub const MAGIC_ADDRESS = 14 ; U16 Location of the low 16 bits of magic value
|
||||||
|
pub const MAGIC_VALUE = 0x534c ; U16 Low 16 bits of the magic value
|
||||||
|
|||||||
@@ -0,0 +1,672 @@
|
|||||||
|
; 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 ? 1 : -1;
|
||||||
|
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, 1
|
||||||
|
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, zr ; sx = -1
|
||||||
|
; endif
|
||||||
|
draw_line_move_right_done:
|
||||||
|
|
||||||
|
; int dy = -abs(y1-y0), sy = y0<y1 ? 1 : -1;
|
||||||
|
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, 1
|
||||||
|
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, 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
|
||||||
+19
-4
@@ -1,4 +1,19 @@
|
|||||||
@0 ; Reserve space for globals
|
;@0 ; Reserve space for globals
|
||||||
|
|
||||||
jmp 0x100 ; jump over them
|
; First initialise the stack pointer
|
||||||
@0x100 ; start of user code
|
nor sp, zr, 0xffff
|
||||||
|
; Jump over the globals to user code
|
||||||
|
jmp 0x100
|
||||||
|
|
||||||
|
U32 0 ; 4 bytes
|
||||||
|
|
||||||
|
; MAGIC_VALUE
|
||||||
|
;@0x0c
|
||||||
|
U32 0xb301534c
|
||||||
|
|
||||||
|
; Pad with zeroes since the @addr feature is currently broken.
|
||||||
|
; * https://discord.com/channels/828292123936948244/1545010596246847568
|
||||||
|
;
|
||||||
|
U1920 0 ; 240 bytes
|
||||||
|
|
||||||
|
;@0x100 ; start of user code
|
||||||
Reference in New Issue
Block a user