rrcc/asm/stdlib.asm

145 lines
7.3 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
.constant RRET std_RETURN_VALUE ;;Alias
.constant RRET_X std_RETURN_VALUE_EXTRA ;;Alias
.constant P0 std_PARAMETER_0
.constant P1 std_PARAMETER_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
.constant 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 simple addition
; TODO: use add + shift
.constant std_mul @std_multiply
.constant std_multiply @std_multiply
std_multiply:
PUSH BSM_COUNTER_0 ; Save old value of counter
MOV BSM_COUNTER_0, P0 ; Move A to counter
MOV RRET, 0
JUMP @.loop ; Skip first iteration
.multiply:
ADD RRET, RRET, P1 ; Add B to itself A times
.loop: LOOP @.multiply ; Check if 0, if not, decrease A and go back. Use COUNTER[0]
POP BSM_COUNTER_0 ; Restore old value of counter
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 R0, 0
.divide:
MOV R0, RRET ; Move quotient to temp R0
ADD RRET, RRET, RRET ; quotient = quotient + quotient
ADD RRET_X, RRET_X, RRET_X ; remainder = remainder + remainder + ...
SHL R0, RRET, R0 ; quot << R0
ADD RRET_X, RRET_X, R0 ; remainder = ... + (quot << R0)
SUB R0, RRET_X, P1 ; compare rem >= divisor
BNE R0, 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