rrcc/asm/stdlib.asm
DataHoarder e3535abed0
All checks were successful
continuous-integration/drone/push Build is passing
Added new ASM register fields, made std_divide use scratch registers
2021-08-06 00:04:44 +02:00

151 lines
7.6 KiB
NASM

;; Standard Library
;; These registers are used within virtual functions as temporary holders
.constant std_SCRATCH_0 MGMT_SCRATCH_0
.constant std_SCRATCH_1 MGMT_SCRATCH_1
;; Also used as single return value
.reserve std_RETURN_VALUE 0x1E0
.reserve std_RETURN_VALUE_EXTRA 0x1E1
.reserve std_PARAMETER_0 0x1E2
.reserve std_PARAMETER_1 0x1E3
;; Used for offset pointer access
.constant std_THIS %0
.constant RRET std_RETURN_VALUE ;;Alias
.constant RRET_X std_RETURN_VALUE_EXTRA ;;Alias
.constant P0 std_PARAMETER_0
.constant P1 std_PARAMETER_1
.constant S0 std_SCRATCH_0
.constant S1 std_SCRATCH_1
;; These are offset registers to be called with <OP>~2 to access stack frame parameters
.constant P2 %0, +1 ;; Equivalent to same address in GET <Reg>, 1
.constant P3 %0, +2 ;; Equivalent to same address in GET <Reg>, 2
.constant P4 %0, +3 ;; Equivalent to same address in GET <Reg>, 3
.constant P5 %0, +4 ;; Equivalent to same address in GET <Reg>, 4
.constant P6 %0, +5 ;; Equivalent to same address in GET <Reg>, 5
.constant P7 %0, +6 ;; Equivalent to same address in GET <Reg>, 6
.constant P8 %0, +7 ;; Equivalent to same address in GET <Reg>, 7
.constant P9 %0, +8 ;; Equivalent to same address in GET <Reg>, 8
.constant P10 %0, +9 ;; Equivalent to same address in GET <Reg>, 9
.constant P11 %0, +10 ;; Equivalent to same address in GET <Reg>, 10
.constant P12 %0, +11 ;; Equivalent to same address in GET <Reg>, 11
.constant P13 %0, +12 ;; Equivalent to same address in GET <Reg>, 12
.constant P14 %0, +13 ;; Equivalent to same address in GET <Reg>, 13
.constant P15 %0, +14 ;; Equivalent to same address in GET <Reg>, 14
.constant P16 %0, +15 ;; Equivalent to same address in GET <Reg>, 15
;; These are parameter registers to be called with GET to access stack frame parameters
.constant GET_P2 1
.constant GET_P3 2
.constant GET_P4 3
.constant GET_P5 4
.constant GET_P6 5
.constant GET_P7 6
.constant GET_P8 7
.constant GET_P9 8
.constant GET_P10 9
.constant GET_P11 10
.constant GET_P12 11
.constant GET_P13 12
.constant GET_P14 13
.constant GET_P15 14
.constant GET_P16 15
;; Ephemeral registers to be used within functions. These values may not be kept when calling other functions. They can be used when returning values if necessary.
;; Some std functions might restore these values.
.reserve std_EPHEMERAL_REGISTER_0 0x1F0
.reserve std_EPHEMERAL_REGISTER_1 0x1F1
.reserve std_EPHEMERAL_REGISTER_2 0x1F2
.reserve std_EPHEMERAL_REGISTER_3 0x1F3
.reserve std_EPHEMERAL_REGISTER_4 0x1F4
.reserve std_EPHEMERAL_REGISTER_5 0x1F5
.reserve std_EPHEMERAL_REGISTER_6 0x1F6
.reserve std_EPHEMERAL_REGISTER_7 0x1F7
.reserve std_EPHEMERAL_REGISTER_8 0x1F8
.reserve std_EPHEMERAL_REGISTER_9 0x1F9
.reserve std_EPHEMERAL_REGISTER_10 0x1FA
.reserve std_EPHEMERAL_REGISTER_11 0x1FB
.reserve std_EPHEMERAL_REGISTER_12 0x1FC
.reserve std_EPHEMERAL_REGISTER_13 0x1FD
.reserve std_EPHEMERAL_REGISTER_14 0x1FE
.reserve std_EPHEMERAL_REGISTER_15 0x1FF
;; Abbreviations
.constant R0 std_EPHEMERAL_REGISTER_0
.constant R1 std_EPHEMERAL_REGISTER_1
.constant R2 std_EPHEMERAL_REGISTER_2
.constant R3 std_EPHEMERAL_REGISTER_3
.constant R4 std_EPHEMERAL_REGISTER_4
.constant R5 std_EPHEMERAL_REGISTER_5
.constant R6 std_EPHEMERAL_REGISTER_6
.constant R7 std_EPHEMERAL_REGISTER_7
.constant R8 std_EPHEMERAL_REGISTER_8
.constant R9 std_EPHEMERAL_REGISTER_9
.constant R10 std_EPHEMERAL_REGISTER_10
.constant R11 std_EPHEMERAL_REGISTER_11
.constant R12 std_EPHEMERAL_REGISTER_12
.constant R13 std_EPHEMERAL_REGISTER_13
.constant R14 std_EPHEMERAL_REGISTER_14
.constant R15 std_EPHEMERAL_REGISTER_15
; FASTCALL uint std_multiply(uint A, uint B). Return value on RRET
; Uses shift + add multiplication
.constant std_mul @std_multiply
.constant std_multiply @std_multiply
std_multiply:
MOV S0, P0 ; S0 = A
MOV S1, P1 ; S1 = B
MOV RRET, 0 ; result = 0
.multiply:
BEQ S0, 0, 0xFFFFFFFF, @.return ; continue if S0 != 0
BNE S0, 1, 0x1, @.skipBit ; If the lowest order bit is set in A?
ADD RRET, RRET, S1 ; result = result + b
.skipBit:
SHR S0, S0, 1 ; a = a >> 1, no sign copy
ADD S1, S1, S1 ; b = b + b
JUMP @.multiply
.return: RET ; Return, no need to get rid of stack as fastcall passed them on registers
; FASTCALL uint std_divide(uint dividend, uint divisor). Return quotient on RRET, remainder on RRET_X
; Uses shift + add division
; TODO: check validity
.constant std_div @std_divide
.constant std_divide @std_divide
std_divide:
BNE P1, 0, 0xffffffff, @.normal_division ; Handle divisor = 0
WRITE RRET, 0xffffffff, 0xffffffff ; Return both values 0xffffffff
JUMP @.return
.normal_division:
PUSH BSM_COUNTER_0 ; Save old value of counter
MOV BSM_COUNTER_0, 32 ; Move bits left to counter (8 * 4)
MOV RRET, P0 ; Move dividend to RRET (quotient)
MOV RRET_X, 0 ; Move remainder to RRET_X
MOV S0, 0
.divide:
MOV S0, RRET ; Move quotient to temp S0
ADD RRET, RRET, RRET ; quotient = quotient + quotient
ADD RRET_X, RRET_X, RRET_X ; remainder = remainder + remainder + ...
SHL S0, RRET, S0 ; quot << S0
ADD RRET_X, RRET_X, S0 ; remainder = ... + (quot << S0)
SUB S0, RRET_X, P1 ; compare rem >= divisor
BNE S0, 0, 1 <31, @.no_reduce
SUB RRET_X, RRET_X, P1 ; remainder = remainder - divisor
ADD RRET, RRET, 1 ; quotient = quotient + 1
.no_reduce:
LOOP @.divide ; Check if 0, if not, decrease bits left and go back. Use COUNTER[0]
POP BSM_COUNTER_0 ; Restore old value of counter
.return: RET ; Return, no need to get rid of stack as fastcall passed them on registers
;; x86-like definitions
.constant ebp, rrcc_FRAME_POINTER
.constant esp, rrcc_STACK_POINTER
.constant eax, RRET