/*
 * math.c
 *
 * Arithmetic, compare and logical instructions
 *
 */

#include <stdlib.h>

#include <oslib/os.h>

#include "ztypes.h"
#include "math.h"
#include "operand.h"
#include "osdepend.h"

#if 0
/*
 * add
 *
 * Add two operands
 *
 */

void z_add(int a, int b)
{
    store_operand(a + b);

}/* add */

/*
 * sub
 *
 * Subtract two operands
 *
 */

void z_sub(int a, int b)
{
    store_operand(a - b);

}/* sub */

/*
 * mul
 *
 * Multiply two operands
 *
 */

void z_mul(int a, int b)
{
    store_operand(a * b);

}/* mul */

/*
 * div
 *
 * Divide two operands
 *
 */

void z_div(short a, short b)
{
    if (b==0)
    {
        fatal_lookup("DivZero");
        return;
    }

    store_operand(a / b);

}/* div */

/*
 * mod
 *
 * Modulus divide two operands
 *
 */

void z_mod(short a, short b)
{
    if (b==0)
    {
        fatal_lookup("DivZero");
        return;
    }

    store_operand(a % b);

}/* mod */
#endif

/*
 * log_shift
 *
 * Shift +/- n bits
 *
 */

void z_log_shift(unsigned a, short b)
{
    if (b >= 0)
        store_operand(a << b);
    else
        store_operand(a >> -b);

}/* log_shift */


/*
 * art_shift
 *
 * Arithmetic shift +/- n bits
 *
 */

void z_art_shift(short a, short b)
{
    if (b >= 0)
        store_operand(a << b);
    else
        /* This works with ARM C, but is not guaranteed to! */
        store_operand(a >> -b);

}/* art_shift */

#if 0
/*
 * or
 *
 * Logical OR
 *
 */

void z_or(unsigned a, unsigned b)
{
    store_operand(a | b);

}/* or */
#endif

/*
 * not
 *
 * Logical NOT
 *
 */

void z_not(unsigned a)
{
    store_operand(~a);

}/* not */

#if 0
/*
 * and
 *
 * Logical AND
 *
 */

void z_and(unsigned a, unsigned b)
{
    store_operand(a & b);

}/* and */

/*
 * xor
 *
 * Logical Exclusive OR
 *
 */

void z_xor(unsigned a, unsigned b)
{
    store_operand(a ^ b);

}/* xor */
#endif

/*
 * random
 *
 * Return random number between 1 and operand
 *
 */

void z_random(short a)
{
    static int seed, counter;

    if (a == 0)   /* a = 0 - reseed RNG as randomly as possible */
    {
        seed = 0;
        srand(os_read_monotonic_time());
        store_operand(0);
    }
    else if (a < 0) /* (a < 0) - used to set seed with #RANDOM */
    {
        if (a < -1000)
        {
            seed = 0;
            srand(-a);
        }
        else
        {
            seed = -a;
            counter = 0;
        }
        store_operand(0);
    }
    else /* (a > 0) */
    {
        unsigned val;
        if (seed)
        {
            if (++counter > seed) counter = 1;
            val = counter;
        }
        else
            val = rand();

        store_operand(val % a + 1);
    }

}/* random */

/*
 * test
 *
 * Jump if operand 2 bit mask not set in operand 1
 *
 */

void z_test(unsigned bitmap, unsigned flags)
{
    conditional_jump((~bitmap & flags)==0);

}/* test */

/*
 * jz
 *
 * Compare operand against zero
 *
 */

void z_jz(unsigned a)
{
    conditional_jump(a == 0);

}/* jz */

/*
 * je
 *
 * Jump if operand 1 is equal to any other operand
 *
 */

void z_je(int count, unsigned *operand)
{
    count--;

    do
    {
        if (operand[0] == operand[count])
        {
            conditional_jump(TRUE);
            return;
        }
    } while (--count != 0);

    conditional_jump(FALSE);

}/* je */

/*
 * jl
 *
 * Jump if operand 1 is less than operand 2
 *
 */

void z_jl(short a, short b)
{
    conditional_jump(a < b);

}/* compare_jl */

/*
 * jg
 *
 * Jump if operand 1 is greater than operand 2
 *
 */

void z_jg(short a, short b)
{
    conditional_jump(a > b);

}/* jg */
