/**********
 * Copyright (c) 2003-2004 Greg Parker.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **********/

#include "bn_includes.h"
#include "bn_internal.h"
#include "bn_armcalls.h"


uint32_t BN_is_negative_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_CTX_new_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_CTX_free_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_CTX_start_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_CTX_get_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_CTX_end_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_rand_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_num_bits_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_new_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_clear_free_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_bin2bn_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_bn2bin_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_cmp_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_free_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_is_bit_set_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_mod_exp_mont_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_mod_exp_mont_word_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_bn2hex_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_hex2bn_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_MONT_CTX_new_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_MONT_CTX_free_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_MONT_CTX_set_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_is_zero_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_mod_mul_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_ucmp_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_mod_inverse_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_div_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_add_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_sub_stub(bn_globals *globals, uint32_t *param);
uint32_t BN_rand_range_stub(bn_globals *globals, uint32_t *param);

#ifdef BNTEST
uint32_t BN_set_negative_stub(bn_args *args);
uint32_t BN_bntest_rand_stub(bn_args *args);
uint32_t BN_copy_stub(bn_args *args);
uint32_t BN_set_bit_stub(bn_args *args);
uint32_t BN_add_word_stub(bn_args *args);
uint32_t BN_lshift_stub(bn_args *args);
uint32_t BN_mul_stub(bn_args *args);
uint32_t BN_RECP_CTX_new_stub(bn_args *args);
uint32_t BN_sqr_stub(bn_args *args);
uint32_t BN_nnmod_stub(bn_args *args);
uint32_t BN_to_montgomery_stub(bn_args *args);
uint32_t BN_mod_mul_montgomery_stub(bn_args *args);
uint32_t BN_from_montgomery_stub(bn_args *args);
uint32_t BN_mod_exp_stub(bn_args *args);
uint32_t BN_exp_stub(bn_args *args);
uint32_t BN_RECP_CTX_set_stub(bn_args *args);
uint32_t BN_RECP_CTX_free_stub(bn_args *args);
uint32_t BN_div_recp_stub(bn_args *args);
uint32_t BN_set_word_stub(bn_args *args);
#endif

uint32_t BN_time_stub(bn_globals *globals, uint32_t *param);


uint32_t BN_dispatch_from_68K(uint32_t fn, pace_globals *pg, uint32_t *param)
{
    bn_globals *bg = (bn_globals *)pg;

    switch (fn) {
    case BN_is_negative_id:
        return BN_is_negative_stub(bg, param);
    case BN_CTX_new_id:
        return BN_CTX_new_stub(bg, param);
    case BN_CTX_free_id:
        return BN_CTX_free_stub(bg, param);
    case BN_CTX_start_id:
        return BN_CTX_start_stub(bg, param);
    case BN_CTX_get_id:
        return BN_CTX_get_stub(bg, param);
    case BN_CTX_end_id:
        return BN_CTX_end_stub(bg, param);
    case BN_rand_id:
        return BN_rand_stub(bg, param);
    case BN_num_bits_id:
        return BN_num_bits_stub(bg, param);
    case BN_new_id:
        return BN_new_stub(bg, param);
    case BN_clear_free_id:
        return BN_clear_free_stub(bg, param);
    case BN_bin2bn_id:
        return BN_bin2bn_stub(bg, param);
    case BN_bn2bin_id:
        return BN_bn2bin_stub(bg, param);
    case BN_cmp_id:
        return BN_cmp_stub(bg, param);
    case BN_free_id:
        return BN_free_stub(bg, param);
    case BN_is_bit_set_id:
        return BN_is_bit_set_stub(bg, param);
    case BN_mod_exp_mont_id:
        return BN_mod_exp_mont_stub(bg, param);
    case BN_mod_exp_mont_word_id:
        return BN_mod_exp_mont_word_stub(bg, param);
    case BN_bn2hex_id:
        return BN_bn2hex_stub(bg, param);
    case BN_hex2bn_id:
        return BN_hex2bn_stub(bg, param);
    case BN_MONT_CTX_new_id:
        return BN_MONT_CTX_new_stub(bg, param);
    case BN_MONT_CTX_free_id:
        return BN_MONT_CTX_free_stub(bg, param);
    case BN_MONT_CTX_set_id:
        return BN_MONT_CTX_set_stub(bg, param);
    case BN_is_zero_id:
        return BN_is_zero_stub(bg, param);
    case BN_mod_mul_id:
        return BN_mod_mul_stub(bg, param);
    case BN_ucmp_id:
        return BN_ucmp_stub(bg, param);
    case BN_mod_inverse_id:
        return BN_mod_inverse_stub(bg, param);
    case BN_div_id:
        return BN_div_stub(bg, param);
    case BN_add_id:
        return BN_add_stub(bg, param);
    case BN_sub_id:
        return BN_sub_stub(bg, param);
    case BN_rand_range_id:
        return BN_rand_range_stub(bg, param);
#ifdef BNTEST
    case BN_set_negative_id:
        return BN_set_negative_stub(bg, param);
    case BN_bntest_rand_id:
        return BN_bntest_rand_stub(bg, param);
    case BN_copy_id:
        return BN_copy_stub(bg, param);
    case BN_set_bit_id:
        return BN_set_bit_stub(bg, param);
    case BN_add_word_id:
        return BN_add_word_stub(bg, param);
    case BN_lshift_id:
        return BN_lshift_stub(bg, param);
    case BN_mul_id:
        return BN_mul_stub(bg, param);
    case BN_RECP_CTX_new_id:
        return BN_RECP_CTX_new_stub(bg, param);
    case BN_sqr_id:
        return BN_sqr_stub(bg, param);
    case BN_nnmod_id:
        return BN_nnmod_stub(bg, param);
    case BN_to_montgomery_id:
        return BN_to_montgomery_stub(bg, param);
    case BN_mod_mul_montgomery_id:
        return BN_mod_mul_montgomery_stub(bg, param);
    case BN_from_montgomery_id:
        return BN_from_montgomery_stub(bg, param);
    case BN_mod_exp_id:
        return BN_mod_exp_stub(bg, param);
    case BN_exp_id:
        return BN_exp_stub(bg, param);
    case BN_RECP_CTX_set_id:
        return BN_RECP_CTX_set_stub(bg, param);
    case BN_div_recp_id:
        return BN_div_recp_stub(bg, param);
    case BN_RECP_CTX_free_id:
        return BN_RECP_CTX_free_stub(bg, param);
    case BN_set_word_id:
        return BN_set_word_stub(bg, param);
#endif
    case BN_time_id:
        return BN_time_stub(bg, param);

    default:
        return 0;
    }
}

uint32_t BN_is_negative_stub(bn_globals *globals, uint32_t *param) {
    BIGNUM *a = (BIGNUM *)param[0];
    return (uint32_t) BN_is_negative(a);
}

uint32_t BN_CTX_new_stub(bn_globals *globals, uint32_t *param) {
    return (uint32_t) BN_CTX_new(globals);
}

uint32_t BN_CTX_free_stub(bn_globals *globals, uint32_t *param) {
    BN_CTX *ctx = (BN_CTX *)param[0];
    BN_CTX_free(ctx);
    return 0;
}

uint32_t BN_CTX_start_stub(bn_globals *globals, uint32_t *param) {
    BN_CTX *ctx = (BN_CTX *)param[0];
    BN_CTX_start(ctx);
    return 0;
}

uint32_t BN_CTX_get_stub(bn_globals *globals, uint32_t *param) {
    BN_CTX *ctx = (BN_CTX *)param[0];
    return (uint32_t) BN_CTX_get(ctx);
}

uint32_t BN_CTX_end_stub(bn_globals *globals, uint32_t *param) {
    BN_CTX *ctx = (BN_CTX *)param[0];
    BN_CTX_end(ctx);
    return 0;
}

uint32_t BN_rand_stub(bn_globals *globals, uint32_t *param) {
    BIGNUM *rnd = (BIGNUM *)param[0];
    int bits = (int)param[1];
    int top = (int)param[2];
    int bottom = (int)param[3];
    return (uint32_t) BN_rand(rnd, bits, top, bottom);
}

uint32_t BN_num_bits_stub(bn_globals *globals, uint32_t *param) {
    BIGNUM *a = (BIGNUM *)param[0];
    return (uint32_t) BN_num_bits(a);
}

uint32_t BN_new_stub(bn_globals *globals, uint32_t *param) {
    return (uint32_t) BN_new(globals);
}

uint32_t BN_clear_free_stub(bn_globals *globals, uint32_t *param) {
    BIGNUM *a = (BIGNUM *)param[0];
    BN_clear_free(a);
    return 0;
}

uint32_t BN_bin2bn_stub(bn_globals *globals, uint32_t *param) {
    unsigned char *s = (unsigned char *)param[0];
    int len = (int)param[1];
    BIGNUM *ret = (BIGNUM *)param[2];
    return (uint32_t) BN_bin2bn(globals, s, len, ret);
}

uint32_t BN_bn2bin_stub(bn_globals *globals, uint32_t *param) {
    BIGNUM *a = (BIGNUM *)param[0];
    unsigned char *to = (unsigned char *)param[1];
    return (uint32_t) BN_bn2bin(a, to);
}

uint32_t BN_cmp_stub(bn_globals *globals, uint32_t *param) {
    BIGNUM *a = (BIGNUM *)param[0];
    BIGNUM *b = (BIGNUM *)param[1];
    return (uint32_t) BN_cmp(a, b);
}

uint32_t BN_free_stub(bn_globals *globals, uint32_t *param) {
    BIGNUM *a = (BIGNUM *)param[0];
    BN_free(a);
    return 0;
}

uint32_t BN_is_bit_set_stub(bn_globals *globals, uint32_t *param) {
    BIGNUM *a = (BIGNUM *)param[0];
    int n = (int)param[1];
    return (uint32_t) BN_is_bit_set(a, n);
}

uint32_t BN_mod_exp_mont_stub(bn_globals *globals, uint32_t *param) {
    BIGNUM *r = (BIGNUM *)param[0];
    BIGNUM *a = (BIGNUM *)param[1];
    BIGNUM *p = (BIGNUM *)param[2];
    BIGNUM *m = (BIGNUM *)param[3];
    BN_CTX *ctx = (BN_CTX *)param[4];
    BN_MONT_CTX *m_ctx = (BN_MONT_CTX *)param[5];
    return (uint32_t) BN_mod_exp_mont(r, a, p, m, ctx, m_ctx);
}

uint32_t BN_mod_exp_mont_word_stub(bn_globals *globals, uint32_t *param) {
    BIGNUM *r = (BIGNUM *)param[0];
    BN_ULONG a = (BN_ULONG)param[1];
    BIGNUM *p = (BIGNUM *)param[2];
    BIGNUM *m = (BIGNUM *)param[3];
    BN_CTX *ctx = (BN_CTX *)param[4];
    BN_MONT_CTX *m_ctx = (BN_MONT_CTX *)param[5];
    return (uint32_t) BN_mod_exp_mont_word(r, a, p, m, ctx, m_ctx);
}

uint32_t BN_bn2hex_stub(bn_globals *globals, uint32_t *param) {
    BIGNUM *a = (BIGNUM *)param[0];
    return (uint32_t) BN_bn2hex(a);
}

uint32_t BN_hex2bn_stub(bn_globals *globals, uint32_t *param) {
    BIGNUM **a = (BIGNUM **)param[0];
    char *str = (char *)param[1];
    *a = (BIGNUM *)ByteSwap32(*a);
    uint32_t result = (uint32_t) BN_hex2bn(globals, a, str);
    *a = (BIGNUM *)ByteSwap32(*a);
    return result;
}

uint32_t BN_MONT_CTX_new_stub(bn_globals *globals, uint32_t *param) {
    return (uint32_t) BN_MONT_CTX_new(globals);
}

uint32_t BN_MONT_CTX_free_stub(bn_globals *globals, uint32_t *param) {
    BN_MONT_CTX *ctx = (BN_MONT_CTX *)param[0];
    BN_MONT_CTX_free(ctx);
    return 0;
}

uint32_t BN_MONT_CTX_set_stub(bn_globals *globals, uint32_t *param) {
    BN_MONT_CTX *mont = (BN_MONT_CTX *)param[0];
    BIGNUM *mod = (BIGNUM *)param[1];
    BN_CTX *ctx = (BN_CTX *)param[2];
    return BN_MONT_CTX_set(mont, mod, ctx);
}

uint32_t BN_is_zero_stub(bn_globals *globals, uint32_t *param) {
    BIGNUM *a = (BIGNUM *)param[0];
    return (uint32_t) BN_is_zero(a);
}

uint32_t BN_mod_mul_stub(bn_globals *globals, uint32_t *param) {
    BIGNUM *r = (BIGNUM *)param[0];
    BIGNUM *a = (BIGNUM *)param[1];
    BIGNUM *b = (BIGNUM *)param[2];
    BIGNUM *m = (BIGNUM *)param[3];
    BN_CTX *ctx = (BN_CTX *)param[4];
    return (uint32_t) BN_mod_mul(r, a, b, m, ctx);
}

uint32_t BN_ucmp_stub(bn_globals *globals, uint32_t *param) {
    BIGNUM *a = (BIGNUM *)param[0];
    BIGNUM *b = (BIGNUM *)param[1];
    return (uint32_t) BN_ucmp(a, b);
}

uint32_t BN_mod_inverse_stub(bn_globals *globals, uint32_t *param) {
    BIGNUM *r = (BIGNUM *)param[0];
    BIGNUM *a = (BIGNUM *)param[1];
    BIGNUM *n = (BIGNUM *)param[2];
    BN_CTX *ctx = (BN_CTX *)param[3];
    return (uint32_t) BN_mod_inverse(r, a, n, ctx);
}

uint32_t BN_div_stub(bn_globals *globals, uint32_t *param) {
    BIGNUM *dv = (BIGNUM *)param[0];
    BIGNUM *rem = (BIGNUM *)param[1];
    BIGNUM *m = (BIGNUM *)param[2];
    BIGNUM *d = (BIGNUM *)param[3];
    BN_CTX *ctx = (BN_CTX *)param[4];
    return (uint32_t) BN_div(dv, rem, m, d, ctx);
}

uint32_t BN_add_stub(bn_globals *globals, uint32_t *param) {
    BIGNUM *r = (BIGNUM *)param[0];
    BIGNUM *a = (BIGNUM *)param[1];
    BIGNUM *b = (BIGNUM *)param[2];
    return (uint32_t) BN_add(r, a, b);
}

uint32_t BN_sub_stub(bn_globals *globals, uint32_t *param) {
    BIGNUM *r = (BIGNUM *)param[0];
    BIGNUM *a = (BIGNUM *)param[1];
    BIGNUM *b = (BIGNUM *)param[2];
    return (uint32_t) BN_sub(r, a, b);
}

uint32_t BN_rand_range_stub(bn_globals *globals, uint32_t *param) {
    BIGNUM *r = (BIGNUM *)param[0];
    BIGNUM *range = (BIGNUM *)param[1];
    return (uint32_t) BN_rand_range(r, range);
}

#ifdef BNTEST

// fixme not updated

uint32_t BN_set_negative_stub(bn_args *args) {
    BIGNUM *a = (BIGNUM *)args->param[0];
    int neg = (int)args->param[1];
    BN_set_negative(a, neg);
    return 0;
}

uint32_t BN_bntest_rand_stub(bn_args *args) {
    BIGNUM *rnd = (BIGNUM *)args->param[0];
    int bits = (int)args->param[1];
    int top = (int)args->param[2];
    int bottom = (int)args->param[3];
    return (uint32_t) BN_bntest_rand(rnd, bits, top, bottom);
}

uint32_t BN_copy_stub(bn_args *args) {
    BIGNUM *a = (BIGNUM *)args->param[0];
    BIGNUM *b = (BIGNUM *)args->param[1];
    return (uint32_t) BN_copy(a, b);
}

uint32_t BN_set_bit_stub(bn_args *args) {
    BIGNUM *a = (BIGNUM *)args->param[0];
    int n = (int)args->param[1];
    return (uint32_t) BN_set_bit(a, n);
}

uint32_t BN_add_word_stub(bn_args *args) {
    BIGNUM *a = (BIGNUM *)args->param[0];
    BN_ULONG n = (BN_ULONG)args->param[1];
    return (uint32_t) BN_add_word(a, n);
}

uint32_t BN_lshift_stub(bn_args *args) {
    BIGNUM *r = (BIGNUM *)args->param[0];
    BIGNUM *a = (BIGNUM *)args->param[1];
    int n = (int)args->param[2];
    return (uint32_t) BN_lshift(r, a, n);
}

uint32_t BN_mul_stub(bn_args *args) {
    BIGNUM *r = (BIGNUM *)args->param[0];
    BIGNUM *a = (BIGNUM *)args->param[1];
    BIGNUM *b = (BIGNUM *)args->param[2];
    BN_CTX *ctx = (BN_CTX *)args->param[3];
    return (uint32_t) BN_mul(r, a, b, ctx);
}

uint32_t BN_RECP_CTX_new_stub(bn_args *args) {
    return (uint32_t) BN_RECP_CTX_new(globals);
}

uint32_t BN_sqr_stub(bn_args *args) {
    BIGNUM *r = (BIGNUM *)args->param[0];
    BIGNUM *a = (BIGNUM *)args->param[1];
    BN_CTX *ctx = (BN_CTX *)args->param[2];
    return (uint32_t) BN_sqr(r, a, ctx);
}

uint32_t BN_nnmod_stub(bn_args *args) {
    BIGNUM *r = (BIGNUM *)args->param[0];
    BIGNUM *m = (BIGNUM *)args->param[1];
    BIGNUM *d = (BIGNUM *)args->param[2];
    BN_CTX *ctx = (BN_CTX *)args->param[3];
    return (uint32_t) BN_nnmod(r, m, d, ctx);
}

uint32_t BN_to_montgomery_stub(bn_args *args) {
    BIGNUM *r = (BIGNUM *)args->param[0];
    BIGNUM *a = (BIGNUM *)args->param[1];
    BN_MONT_CTX *mont = (BN_MONT_CTX *)args->param[2];
    BN_CTX *ctx = (BN_CTX *)args->param[3];
    return (uint32_t) BN_to_montgomery(r, a, mont, ctx);
}

uint32_t BN_mod_mul_montgomery_stub(bn_args *args) {
    BIGNUM *r = (BIGNUM *)args->param[0];
    BIGNUM *a = (BIGNUM *)args->param[1];
    BIGNUM *b = (BIGNUM *)args->param[2];
    BN_MONT_CTX *mont = (BN_MONT_CTX *)args->param[3];
    BN_CTX *ctx = (BN_CTX *)args->param[4];
    return (uint32_t) BN_mod_mul_montgomery(r, a, b, mont, ctx);
}

uint32_t BN_from_montgomery_stub(bn_args *args) {
    BIGNUM *r = (BIGNUM *)args->param[0];
    BIGNUM *a = (BIGNUM *)args->param[1];
    BN_MONT_CTX *mont = (BN_MONT_CTX *)args->param[2];
    BN_CTX *ctx = (BN_CTX *)args->param[3];
    return (uint32_t) BN_from_montgomery(r, a, mont, ctx);
}

uint32_t BN_mod_exp_stub(bn_args *args) {
    BIGNUM *r = (BIGNUM *)args->param[0];
    BIGNUM *a = (BIGNUM *)args->param[1];
    BIGNUM *p = (BIGNUM *)args->param[2];
    BIGNUM *m = (BIGNUM *)args->param[3];
    BN_CTX *ctx = (BN_CTX *)args->param[4];
    return (uint32_t) BN_mod_exp(r, a, p, m, ctx);
}

uint32_t BN_exp_stub(bn_args *args) {
    BIGNUM *r = (BIGNUM *)args->param[0];
    BIGNUM *a = (BIGNUM *)args->param[1];
    BIGNUM *p = (BIGNUM *)args->param[2];
    BN_CTX *ctx = (BN_CTX *)args->param[3];
    return (uint32_t) BN_exp(r, a, p, ctx);
}

uint32_t BN_RECP_CTX_set_stub(bn_args *args) {
    BN_RECP_CTX *recp = (BN_RECP_CTX *)args->param[0];
    BIGNUM *rdiv = (BIGNUM *)args->param[1];
    BN_CTX *ctx = (BN_CTX *)args->param[2];
    return (uint32_t) BN_RECP_CTX_set(recp, rdiv, ctx);
}

uint32_t BN_RECP_CTX_free_stub(bn_args *args) {
    BN_RECP_CTX *recp = (BN_RECP_CTX *)args->param[0];
    BN_RECP_CTX_free(recp);
    return 0;
}

uint32_t BN_div_recp_stub(bn_args *args) {
    BIGNUM *dv = (BIGNUM *)args->param[0];
    BIGNUM *rem = (BIGNUM *)args->param[1];
    BIGNUM *m = (BIGNUM *)args->param[2];
    BN_RECP_CTX *recp = (BN_RECP_CTX *)args->param[3];
    BN_CTX *ctx = (BN_CTX *)args->param[4];
    return (uint32_t) BN_div_recp(dv, rem, m, recp, ctx);
}

uint32_t BN_set_word_stub(bn_args *args) {
    BIGNUM *a = (BIGNUM *)args->param[0];
    BN_ULONG n = (BN_ULONG)args->param[1];
    return (uint32_t) BN_set_word(a, n);
}

#endif


static void _enable_timer(void)
{
    asm("ldr r1, =0x00000005;"
        "mcr p14, 0, r1, c0, c0, 0 ;"
        : : : "r1" );
}

static uint32_t _read_timer(void)
{
    uint32_t x = 0;
    asm("mrc p14, 0, %0, c1, c0, 0;" : "=r"(x) : );
    return x;
}

uint32_t BN_time_stub(bn_globals *globals, uint32_t *param) 
{
    uint32_t oldtime = (uint32_t)param[0];
    uint32_t newtime = _read_timer();
    if (oldtime == newtime) _enable_timer();
    return newtime;
}







void *arena_malloc(bn_globals *g, uint32_t sizeARM)
{
    uint32_t size68K = ByteSwap32(sizeARM);

    return (void *)((*g->call68K)(g->emulState, g->arena_malloc, 
                                  &size68K, 4 | kPceNativeWantA0));
}


void arena_free(bn_globals *g, void *ptrARM)
{
    uint32_t ptr68K = ByteSwap32(ptrARM);

    (*g->call68K)(g->emulState, g->arena_free, &ptr68K, 4);
}


int32_t RAND_pseudo_bytes(bn_globals *g, char *bufARM, uint32_t lenARM)
{
    return RAND_bytes(g, bufARM, lenARM);
}


int32_t RAND_bytes(bn_globals *g, char *bufARM, uint32_t lenARM)
{
    uint32_t param[2];
    param[0] = ByteSwap32(bufARM);
    param[1] = ByteSwap32(lenARM);

    return (int32_t)((*g->call68K)(g->emulState, g->rand_bytes, param, 8));
}

void assert_failed(bn_globals *g, uint32_t which)
{
    uint32_t param[1];
    param[0] = ByteSwap32(which);

    (*g->call68K)(g->emulState, g->assert_failed, param, 4);
}
/*
void memset(void *a, char v, uint32_t size)
{
    char *c = (char *)a;
    char *end = c+size;
    while (c < end) *c++ = v;
}*/
