/* Copyright (c) 1995 Simtec / Neil A Carson / WonderWorks
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are not permitted without express permission of the Authors.
 */

/* C language code for Hydra concurrent kernel / support code
 */

#include <string.h>

#include "hydra.h"
#include "hydraswis.h"
#include "kernel.h"

static _kernel_swi_regs r;
static _kernel_oserror *e;

int hydra_version(void)
{
    e = _kernel_swi(Hydra_Version, &r, &r);
    if (!e) return -1;
    return r.r[0];
}

_kernel_oserror *hydra_processors(hydra_cpu_id_block *b)
{
    r.r[0] = (int) b;
    return _kernel_swi(Hydra_Processors, &r, &r);
}

_kernel_oserror *hydra_reset(hydra_cpu_mask m)
{
    r.r[0] = (int) m;
    return _kernel_swi(Hydra_Reset, &r, &r);
}

_kernel_oserror *hydra_snapshot_regs(int cpu_number, hydra_cpu_snapshot *regs)
{
    r.r[0] = cpu_number;
    r.r[1] = (int) regs;
    return _kernel_swi(Hydra_SnapshotRegs, &r, &r);
}

extern void *hydra_new_chunk(hydra_chunk_parms *info, hydra_chunk *h)
{
    r.r[1] = (int) info->name;
    r.r[2] = info->init_size;
    r.r[3] = info->max_size;
    r.r[4] = (int) info->base_addr;
    r.r[5] = (int) info->mode;
    if ((e = _kernel_swi(Hydra_NewChunk, &r, &r)) != 0)
        return 0;
    *h = r.r[0];
    return (void *) r.r[1];
}

extern _kernel_oserror *hydra_free_chunk(hydra_chunk c)
{
    r.r[0] = c;
    return _kernel_swi(Hydra_FreeChunk, &r, &r);
}

extern _kernel_oserror *hydra_resize_chunk(hydra_chunk c, int delta)
{
    r.r[0] = c;
    r.r[1] = delta;
    return _kernel_swi(Hydra_ResizeChunk, &r, &r);
}

extern _kernel_oserror *hydra_map_chunk(hydra_chunk c, int cpu, hydra_map_type a)
{
    r.r[0] = c;
    r.r[1] = cpu;
    r.r[2] = (int) a;
    return _kernel_swi(Hydra_MapChunk, &r, &r);
}

extern _kernel_oserror *hydra_call(int cpu_number, void *address)
{
    r.r[0] = cpu_number;
    r.r[1] = (int) address;
    return _kernel_swi(Hydra_Call, &r, &r);
}

extern _kernel_oserror *hydra_load_chunk(char *filename, hydra_chunk *h,
					 int **base, int *chunk_size)
{
    r.r[1] = (int) filename;
    e = _kernel_swi(Hydra_LoadChunk, &r, &r);
    *h = (hydra_chunk) r.r[0];
    *base = (int *) r.r[1];
    *chunk_size = r.r[2];
    return e;
}

extern _kernel_oserror *hydra_chunk_info(hydra_chunk h, hydra_chunk_data *info)
{
    r.r[0] = (int) h;
    e = _kernel_swi(Hydra_ChunkInfo, &r, &r);
    memcpy(info, &r.r[1], sizeof(hydra_chunk_data));
    return e;
}

extern _kernel_oserror *hydra_queue_task(hydra_chunk c, hydra_chunk d,
					 hydra_thread *t)
{
    r.r[1] = (int) c;
    r.r[2] = (int) d;
    e = _kernel_swi(Hydra_QueueTask, &r, &r);
    *t = (hydra_thread) r.r[0];
    return e;
}

extern hydra_thread_state hydra_poll_task(hydra_thread t)
{
    r.r[0] = (int) t;
    if (_kernel_swi(Hydra_PollTask, &r, &r)) return THREAD_error;
    return (hydra_thread_state) r.r[1];
}

extern _kernel_oserror *hydra_new_alias(void *base_addr, int handle, hydra_access a,
                            hydra_chunk *h)
{
    r.r[1] = handle;
    r.r[4] = (int) base_addr;
    r.r[5] = (int) a;
    e = _kernel_swi(Hydra_NewAlias, &r, &r);
    if (!e) *h = (int) r.r[0];
    return e;
}
