diff --git a/Makefile b/Makefile index b345799..ef7e141 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,7 @@ all: true false cat env hexdump $(AS) -o $@ $< prtest: prtest.o lib/printregs.o lib/hex.o +sorttest: lib/sort.o .PHONY: test test: diff --git a/lib/sort.s b/lib/sort.s new file mode 100644 index 0000000..7351bd6 --- /dev/null +++ b/lib/sort.s @@ -0,0 +1,152 @@ +.global sort + +# a0 = pointer to array to be sorted +# a1 = length of array (signed) +# a2 = element size (unsigned) +# a3 - comparison function +# a4 - context +sort: + # insertion sort + # for i = 0 to n-1 + # for j = i downto 0 + # if a[j-1] > a[j] + # swap a[j-1], a[j] + + # i = 0 + # for n-1 downto 0 + # i += esize + # j = i + # while j > 0: + # if cmp(j-esize, j) > 0 + # swap(j-esize, j) + # else + # break + # j -= esize + # + + # bail early if n <= 1 + li t0, 1 + bgt a1, t0, 0f + li a0, 0 + ret + 0: + + # check if n*esize overflows or is negative + mulhu t1, a1, a2 + beqz t1, 0f + li a0, -1 + ret + 0: + + sd ra, -1*8(sp) + sd s0, -2*8(sp) + sd s1, -3*8(sp) + sd s2, -4*8(sp) + sd s3, -5*8(sp) + sd s4, -6*8(sp) + sd s5, -7*8(sp) + sd s6, -8*8(sp) + addi sp, sp, -8*8 + + mv s0, a2 # pointer to element i - base + # s1 is pointer to element j - base + mv s2, a0 # base pointer + mv s3, a1 # array len + mv s4, a2 # element size + mv s5, a3 # cmp + mv s6, a4 # context + + # we know we have at least 2 elements, + # so no check necessary at the top of the loop + addi s3, s3, -1 +.Louter.top: + # i += esize + # j = i + add s0, s0, s4 + mv s1, s0 + +.Linner.top: + add a1, s1, s2 # create pointers + sub a0, a1, s4 + mv a2, s6 + jalr s5 # cmp + #li a0, 1 + blez a0, .Lcmp.less + +.Lcmp.greater: +.Lswap: + add a1, s1, s2 + sub a0, a1, s4 + mv a2, s4 + call swap + +.Linner.step: + sub s1, s1, s4 + bnez s1, .Linner.top + +.Lcmp.less: +.Louter.step: + addi s3, s3, -1 # n -= 1 + bnez s3, .Louter.top + +.Lreturn: + addi sp, sp, 8*8 + ld ra, -1*8(sp) + ld s0, -2*8(sp) + ld s1, -3*8(sp) + ld s2, -4*8(sp) + ld s3, -5*8(sp) + ld s4, -6*8(sp) + ld s5, -7*8(sp) + ld s6, -8*8(sp) + ret + +.Lerror: + li a0, -1 + j .Lreturn + +swap: + # TODO: larger things + li t0, 8 + bgtu a2, t0, bigswap + beq a2, t0, swap8 + li t0, 4 + beq a2, t0, swap4 + li t0, 2 + beq a2, t0, swap2 + li t0, 1 + beq a2, t0, swap1 + beqz a2, .Lret + + # TODO: weird size: 0, 3, 5, 6, 7 +.Lret: + ret + +swap8: + ld t0, (a0) + ld t1, (a1) + sd t1, (a0) + sd t0, (a1) + ret +swap4: + lwu t0, (a0) + lwu t1, (a1) + sw t1, (a0) + sw t0, (a1) + ret +swap2: + lhu t0, (a0) + lhu t1, (a1) + sh t1, (a0) + sh t0, (a1) + ret +swap1: + lbu t0, (a0) + lbu t1, (a1) + sb t1, (a0) + sb t0, (a1) + ret + +bigswap: + # TODO + ret diff --git a/sorttest.s b/sorttest.s new file mode 100644 index 0000000..f7560f1 --- /dev/null +++ b/sorttest.s @@ -0,0 +1,51 @@ +.globl _start +.extern sort + +.data + +array: + .ascii "ABC " + .ascii "ZZZ " + .ascii "CCC " + .ascii "BBB " + .ascii "DED " + .ascii "\n" +.equ len, (.) - array + +.text + +_start: + .option push + .option norelax + la gp, __global_pointer$ + .option pop + + li a7, 64 + li a0, 1 + la a1, array + li a2, len + ecall + + la a0, array + li a1, len/4 + li a2, 4 + la a3, cmp + li a4, 0 + + call sort + + li a7, 64 + li a0, 1 + la a1, array + li a2, len + ecall + + li a7, 93 # sys_exit + li a0, 0 + ecall + +cmp: + lw t0, (a0) + lw t1, (a1) + sgtu a0, t0, t1 + ret