;; 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 ~2 to access stack frame parameters .constant P2 %0, +1 ;; Equivalent to same address in GET , 1 .constant P3 %0, +2 ;; Equivalent to same address in GET , 2 .constant P4 %0, +3 ;; Equivalent to same address in GET , 3 .constant P5 %0, +4 ;; Equivalent to same address in GET , 4 .constant P6 %0, +5 ;; Equivalent to same address in GET , 5 .constant P7 %0, +6 ;; Equivalent to same address in GET , 6 .constant P8 %0, +7 ;; Equivalent to same address in GET , 7 .constant P9 %0, +8 ;; Equivalent to same address in GET , 8 .constant P10 %0, +9 ;; Equivalent to same address in GET , 9 .constant P11 %0, +10 ;; Equivalent to same address in GET , 10 .constant P12 %0, +11 ;; Equivalent to same address in GET , 11 .constant P13 %0, +12 ;; Equivalent to same address in GET , 12 .constant P14 %0, +13 ;; Equivalent to same address in GET , 13 .constant P15 %0, +14 ;; Equivalent to same address in GET , 14 .constant P16 %0, +15 ;; Equivalent to same address in GET , 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