initial commit

This commit is contained in:
Bryan McShea
2022-10-11 17:54:20 -04:00
commit 63904ea09f
14 changed files with 711 additions and 0 deletions

62
src/lib/format.s Normal file
View File

@@ -0,0 +1,62 @@
.align 2
.section .text
# args:
# a0 - number
#
# returns:
# a0,a1 - hex string
.global format_hex
format_hex:
addi sp, sp, -(3*8)
sd ra, 0(sp)
sd s0, 8(sp)
sd s1, 16(sp)
move s0, a0
jal format_hex_lower
move s1, a0
srli a0, s0, 32
jal format_hex_lower
move a1, s1
ld ra, 0(sp)
ld s0, 8(sp)
ld s1, 16(sp)
addi sp, sp, +(3*8)
ret
# args:
# a0 - number
#
# returns:
# a0 - lower hex string
.global format_hex_lower
format_hex_lower:
move t0, a0
li t1, 0xffffffff
and t0, t0, t1
li a0, 0
li t1, 8*7
li t4, 16*4
0:
bltz t1, 0f
andi t2, t0, 0xf
addi t2, t2, 0x30
li t3, 0x30+9
ble t2, t3, 1f
addi t2, t2, 0x61-0x30-10
1:
sll t2, t2, t1
addi t1, t1, -8
srli t0, t0, 4
or a0, a0, t2
j 0b
0:
ret

225
src/lib/heap.s Normal file
View File

@@ -0,0 +1,225 @@
# This is a heap implemented with brk.
# It's slow / unoptimized, and only for
# learning how to set up a basic heap
# mask and imask are used to floor & ceil
# to get correct bounds
.equ align_imask, 0b111
.equ align_mask, ~align_imask
.equ used_mask, 0b001
.equ size_mask, align_mask
# block node
.equ bsize, 0
.equ fb_next, 8 # free only
# free also contains its address at the end
# sizes of metadata
.equ sizeof_fb, (8*3 + align_imask) & align_mask
.equ sizeof_ub, (8*1 + align_imask) & align_mask
.equ PAGE_SIZE, 4096
.align 2
.section .rodata
.word 0f - heap_oom
heap_oom:
.string "Heap ran out of memory!\n"
0:
.section .data
.align 4
.equ heap_start, 0
.equ heap_first_free, 8 # matches fb_next
.equ heap_end, 16
.global heap_info # for testing only
heap_info:
.dword __global_pointer$
.dword 0
.dword 0
.align 2
.section .text
.global heap_init
heap_init:
addi sp, sp, -8
sd ra, 0(sp)
# get heap info (t0)
la t0, heap_info
# set heap start (t1)
ld t1, heap_start(t0)
addi t1, t1, align_imask
andi t1, t1, align_mask
sd t1, heap_start(t0)
# set heap end (a0)
# also calculate heap size (t2)
li a0, 0
jal brk
andi a0, a0, align_mask
sub t2, a0, t1 # size = end - start (t2)
li t3, sizeof_fb
bgeu t2, t3, 0f # check if enough mem to start
move a1, a0
add a0, t1, t3
jal brk_or_panic # if not, get more
sub t2, a0, t1 # recalc size (t2)
0:
sd a0, heap_end(t0)
# create initial free block
ori t2, t2, 0x1 # add prev used
sd t2, bsize(t1) # store size
sd t0, fb_next(t1) # store next
sd t1, -8(a0) # store addr at end
sd t1, heap_first_free(t0)
ld ra, 0(sp)
addi sp, sp, +8
ret
# args:
# a0 - size
#
# returns:
# a0 - address
.global heap_alloc
heap_alloc:
addi sp, sp, -8
sd ra, 0(sp)
# align size properly (t0)
move t0, a0
addi t0, t0, sizeof_ub
addi t0, t0, align_imask
andi t0, t0, align_mask
# get a free block that will fit (t1)
# and its free space
la t3, heap_info
ld t4, heap_first_free(t3)
ld a1, heap_end(t3)
move t6, t3 # prev block (t6)
bne t4, t3, 0f # if no free blocks
move t4, a1 # pretend end is start
j 3f
0:
move t1, t4 # current block (t1)
0:
ld t2, bsize(t1) # size of current block (t2)
andi t2, t2, size_mask
bgeu t2, t0, 0f # is it big enough
ld t5, fb_next(t1) # if not, get the next
beq t5, t3, 1f
move t6, t1
move t1, t5
j 0b
1: # if no blocks are big enough
add t5, t1, t2 # get end of last free block
beq t5, a1, 2f # if no free block at end of heap:
move t6, t1
3:
move t1, a1 # immitate new free block at end
2:
add a0, t1, t0 # get needed heap end (a0)
jal brk_or_panic # set heap end (a0)
sd a0, heap_end(t3) # update end in info
sub t2, a0, t1 # new free space (t2)
andi t5, t2, 1 # prev used bit
sd t5, bsize(t1) # update size
sd t3, fb_next(t1) # update next (for case 3)
0:
# deal with extra free space
sub t5, t2, t0 # unneeded free space (t5)
li t4, sizeof_fb
bltu t5, t4, 0f # check if enough for a free block
add t3, t1, t0 # if so, get addr (t3)
sd t3, fb_next(t6) # set prev block next to new
add t6, t3, t5 # store addr at end
sd t3, -8(t6)
ori t6, t5, 1 # store size with prev in use
sd t6, bsize(t3)
ld t6, fb_next(t1) # copy next
sd t6, fb_next(t3)
j 1f
0:
move t0, t2 # if no space, fill in with used
ld t4, fb_next(t1)
sd t4, fb_next(t6) # set prev next to cur next
ld t4, heap_end(t3)
add t3, t1, t0
beq t3, t4, 1f # if this is not at the end
ld t4, bsize(t3) # set next's prev used to 1
ori t4, t4, 1
sd t4, bsize(t3)
1:
# create used block
add t2, t0, t1 # end of block
ori t0, t0, 1 # prev used bit
sd t0, bsize(t1) # store size
sd zero, fb_next(t1) # remove free block stuff
sd zero, -8(t2)
move a0, t1
addi a0, a0, sizeof_ub
ld ra, 0(sp)
addi sp, sp, +8
ret
# args:
# a0 - address
.global heap_free
heap_free:
ret
# args:
# a0 - min address needed
# a1 - old address
#
# returns:
# a0 - new address, aligned
brk_or_panic:
addi sp, sp, -8
sd ra, 0(sp)
jal brk
andi a0, a0, align_mask
bgtu a0, a1, 0f # make sure brk worked
la a0, heap_oom # if not, panic
lw a1, -4(a0)
j panic
0:
ld ra, 0(sp)
addi sp, sp, +8
ret

95
src/lib/print.s Normal file
View File

@@ -0,0 +1,95 @@
.section .rodata
newline:
.half '\n'
space:
.half ' '
.align 2
.section .text
# only uses a regs for convenience
#
# args:
# a0 - string
# a1 - length
.global print
print:
addi sp, sp, -8
sd ra, (sp)
move a2, a1
move a1, a0
li a0, 1 # stdout
jal write
ld ra, (sp)
addi sp, sp, +8
ret
# only uses a regs for convenience
.global printnl
printnl:
addi sp, sp, -8
sd ra, (sp)
la a0, newline
li a1, 1
jal print
ld ra, (sp)
addi sp, sp, +8
ret
# only uses a regs for convenience
#
# args:
# a0 - string
# a1 - length
.global println
println:
addi sp, sp, -8
sd ra, (sp)
jal print
jal printnl
ld ra, (sp)
addi sp, sp, +8
ret
.global print_space
print_space:
addi sp, sp, -8
sd ra, (sp)
la a0, space
li a1, 1
jal print
ld ra, (sp)
addi sp, sp, +8
ret
# args:
# a0 - the hex value to print
.global print_hex
print_hex:
addi sp, sp, -(8+16)
sd ra, (sp)
jal format_hex
addi t0, sp, 8
sd a0, 0(t0)
sd a1, 8(t0)
move a0, t0
li a1, 16
jal print
ld ra, (sp)
addi sp, sp, +(8+16)
ret

9
src/lib/start.s Normal file
View File

@@ -0,0 +1,9 @@
.align 2
.section .text
.global _start
_start:
jal heap_init
jal main
j exit

37
src/lib/str.s Normal file
View File

@@ -0,0 +1,37 @@
.align 2
.section .text
# args:
# a0 - string
#
# returns:
# a0 - length
.global strlen
strlen:
li t0, 0
0:
beq t0, a1, 0f
lb t1, (a0)
beqz t1, 0f
addi a0, a0, 1
addi t0, t0, 1
j 0b
0:
move a0, t0
ret
# args:
# a0 - dest
# a1 - src
.global strcpy
strcpy:
0:
lb t0, (a1)
beqz t0, 0f
sb t0, (a0)
addi a0, a0, 1
addi a1, a1, 1
j 0b
0:
sb t0, (a0)
ret

50
src/lib/sys.s Normal file
View File

@@ -0,0 +1,50 @@
# This contains all syscalls used,
# as functions for convenience.
# These are guaranteed to not modify
# any registers other than the
# arguments needed for the syscalls
.align 2
.section .text
# args:
# a0 - code
.global exit
exit:
li a7, 93
ecall
0: j 0b # loop if failed for safety
# args:
# a0 - relative dir fd;
# 0 for none, -100 for cwd
# a1 - path / name
# a2 - flags
# a3 - mode
#
# returns:
# a0 - fd
.global openat
openat:
li a7, 56
ecall
ret
# args:
# a0 - fd
# a1 - content buf
# a2 - size
.global write
write:
li a7, 64
ecall
ret
# args:
# a0 - address to end at
# returns current addr if 0
.global brk
brk:
li a7, 214
ecall
ret

11
src/lib/util.s Normal file
View File

@@ -0,0 +1,11 @@
.align 2
.section .text
# args:
# a0 - message
# a1 - length
.global panic
panic:
jal print
li a0, 1
j exit

20
src/main.s Normal file
View File

@@ -0,0 +1,20 @@
.align 2
.section .text
.global main
main:
addi sp, sp, -8
sd ra, 0(sp)
# do stuff
#jal write_test
jal heap_test
# exit with code 0
ld ra, 0(sp)
addi sp, sp, +8
li a0, 0
ret

125
src/test/heap.s Normal file
View File

@@ -0,0 +1,125 @@
.section .rodata
.word 0f - print_msg
print_msg:
.string "Current heap:"
0:
.word 0f - dots
dots:
.string "................"
0:
.word 0f - hexstr
hexstr:
.string "0x"
0:
.align 2
.section .text
.global heap_test
heap_test:
addi sp, sp, -(3*8)
sd ra, 0(sp)
sd s0, 8(sp)
sd s1, 16(sp)
# empty heap
jal print_heap
jal printnl
# put stuff on heap
li a0, 8*4
jal heap_alloc
li t0, 0x1111111111111111
sd t0, (a0)
sd t0, 8(a0)
sd t0, 24(a0)
li s0, 0x0f
0:
bltz s0, 0f
li a0, 8*3
jal heap_alloc
sd s0, (a0)
li t0, 0xf000000000000000
add t0, s0, t0
sd t0, 16(a0)
addi s0, s0, -1
j 0b
0:
li a0, 8*7
jal heap_alloc
li t0, 0xffff
sd t0, 6*8(a0)
li a0, 8*3
jal heap_alloc
jal print_heap
ld ra, 0(sp)
ld s0, 8(sp)
ld s1, 16(sp)
addi sp, sp, +(3*8)
ret
print_heap:
addi sp, sp, -(3*8)
sd ra, 0(sp)
sd s0, 8(sp)
sd s1, 16(sp)
la a0, print_msg
lw a1, -4(a0)
jal println
la t0, heap_info
ld s0, 0(t0)
ld s1, 16(t0)
0:
la a0, hexstr
lw a1, -4(a0)
jal print
move a0, s0
jal print_hex
jal print_space
ld a0, 0(s0)
jal print_hex
jal print_space
ld a0, 8(s0)
jal print_hex
jal print_space
la a0, dots
lw a1, -4(a0)
jal print
jal print_space
ld t0, 0(s0)
andi t0, t0, ~0b11
add t0, s0, t0
ld a0, -8(t0)
move s0, t0
jal print_hex
jal printnl
beq s0, s1, 0f
j 0b
0:
ld ra, 0(sp)
ld s0, 8(sp)
ld s1, 16(sp)
addi sp, sp, +(3*8)
ret

55
src/test/write.s Normal file
View File

@@ -0,0 +1,55 @@
.equ PATH_MAX, 255
.section .rodata
.word 0f - start_msg
start_msg:
.string "Writing file..."
0:
.word 0f - file_name
file_name:
.string "test.txt"
0:
.word 0f - content
content:
.string "Hello world!\n"
0:
.align 2
.section .text
.global write_test
write_test:
addi sp, sp, -8-PATH_MAX
sd ra, 0(sp)
# print msg
la a0, start_msg
lw a1, -4(a0)
jal println
# open file
li a0, -100
la a1, file_name
li a2, 01102 # TRUNC | CREAT | RDWR
li a3, 0b110100100 # -rw-r--r--
jal openat
# write to file
la a1, content
lw a2, -4(a1)
jal write
# return
ld ra, 0(sp)
addi sp, sp, +8+PATH_MAX
ret