diff --git a/bit.asm b/bit.asm index e69de29..b33063b 100644 --- a/bit.asm +++ b/bit.asm @@ -0,0 +1,82 @@ +mov r1, 0 +qcall clz +add zr, zr, zr +mov r1, 0x1 +qcall clz +add zr, zr, zr +add r1, zr, 0xAAAA +lsl r1, r1, 6 +qcall popc + +pub rotate_left: + ; (r1 >> r2) | (r1 << (32 - r2)) + sub r3, zr, r2 + add r3, r3, 32 + lsr r3, r1, r3 + lsl r1, r1, r2 + or r1, r1, r3 + + jmp r13 + +pub rotate_right: + ; (r1 << r2) | (r1 >> (32 - r2)) + sub r3, zr, r2 + add r3, r3, 32 + lsl r3, r1, r3 + lsr r1, r1, r2 + or r1, r1, r3 + + jmp r13 + +pub clz: + ; special case + mov r4, 0 + ; since we start the loop by shifting r2 load twice the value we need + mov r2, 32 + mov r3, r1 + ; divide and conquer algorithm + clz_loop: + ; next finer step + lsr r2, r2, 1 + ; abort if there is no finer step + cmp r2, 0 + je clz_end + ; see if there are still some 1 bits left with this additional shift + lsr r3, r3, r2 + add r4, r4, r2 + cmp r3, 0 + jne clz_loop + ; undo shift if it resulted in zero + sub r4, r4, r2 + lsr r3, r1, r4 + jmp clz_loop + clz_end: + ; we calculated the position of the last 1 from the least significant side + ; inverse is what we want (position of last 0 from most significant side) + mov r1, 31 + sub r1, r1, r4 + jmp r13 + +pub popc: + mov r2, 0x0101 ; load mask of 0x01010101 + lsl r2, r2, 16 + or r2, r2, 0x0101 + + mov r3, 8 ; bits in byte + mov r4, 0 ; pop count of each byte + popc_loop: + and r5, r1, r2 ; extract least significant bit of byte + add r4, r4, r5 + + lsr r1, r1, 1 ; cycle through bits + sub r3, r3, 1 + cmp r3, 0 + jg popc_loop + + ; sum up bytes + lsr r2, r4, 8 + add r4, r4, r2 + lsr r2, r4, 16 + add r4, r4, r2 + and r1, r4, 0xFF ; mask out end result in lowest byte + jmp r13 \ No newline at end of file