/*
 * Copyright (c) 1997-2005 by Wayne C. Gramlich.
 * All rights reserved.
 */

/*
 * This file implements the float base type operations in ANSI-C.
 */

#ifndef ERROR_EXPORTS_H
#include "error_exports.h"
#endif

#ifndef MEMORY_H
#include "memory.h"
#endif

#ifndef STHEADERS_H
#include "stheaders.h"
#endif

#ifndef UNIX_ASSERT_H
#include "unix_assert.h"
#endif

extern void *memset(void *, int, size_t);

extern module___object memory__module__object;
extern type___reference memory_type_ref;

static Memory_struct memory___initial_value = {
    0,					/* limit */
    0,					/* size */
    (unsigned char *)0,			/* buffer */
    Memory_mode__permanent_read_only	/* Permanent read-only */
};
Memory memory___initial = &memory___initial_value;

extern module___object memory__module__object;
extern type___reference memory_type_ref;

static object___object memory_initial_object = {
	"",				/* Package name */
	"memory",			/* Type name */
	"??",				/* Object name */
	(type___reference *)0,		/*XXX: Fix me */
	(int *)0,			/* Size of float object */
	0,				/* Static needs count */
	(need___entry *)0,		/*XXX: Fix me Static needs */
	0,				/* Parameter needs count */
	(need___entry *)0,		/* Parameter needs */
	(void **)&memory___initial,	/* Object pointer */
	(instantiation___object *)0	/* Instantiation list */
};
static object___object *object_list[1] = {
	&memory_initial_object,
};

/*
 * memory__external__initailize()
 *	This routine will initialize the memory module.
 */
void
memory__external__initialize(void)
{
	Memory memory;

	memory = memory___initial;
	memory->mode = Memory_mode__permanent_read_only;
}

/*
 * memory_address_get(memory)
 *	This procedure will return the address associated with {memory}.
 *	Please note, this is the address associated with the {memory}
 *	object, not the memory buffer pointed to by {memory}.
 */
unsigned
memory__address_get(
    Memory memory)
{
    return (unsigned)memory;
}

/*
 * memory_allocate(size)
 *	This procedure will allocate and return a chunk of memory of
 *	at least {size} bytes.
 */
void *
memory_allocate(
    unsigned size)
{
    void *chunk;

    chunk = malloc(size);
    assert(chunk != (void *)0);
    return chunk;
}


/*
 * memory_resize(chunk, size)
 *    This procedure will force {chunk} to contain {size}.
 */
void *
memory_resize(
    void *chunk,
    unsigned new_size,
    unsigned old_size)
{
    void *new_chunk;

    /* assert(size != 0); */
    /* (void)printf("    =>memory_resize(0x%x, %d)\n", chunk, size); */
#ifdef LINUX
    new_chunk = realloc(chunk, new_size);
    assert(new_chunk != (void *)0);
#endif /* LINUX */
#ifdef WINDOWS
    /* FIXME: I think that windows has fixed the realloc() bug!!! */
    new_chunk = malloc(new_size);
    assert(new_chunk != (void *)0);
    if (new_size <= old_size) {
	/* The memory chunk is getting smaller: */
	(void)memcpy(new_chunk, chunk, new_size);
    } else {
	/* The memory chunk is getting larger: */
	(void)memcpy(new_chunk, chunk, old_size);
	/* (void)memset(new_chunk + old_size, 0, new_size - old_size); */
    }
#endif /* WINDOWS */
    /* assert(chunk != (void *)0); */
    /* (void)printf("    <=memory_resize(0x%x, %d) => 0x%x\n",
      chunk, size, new_chunk); */
    return new_chunk;
}

/*
 * memory_free(chunk)
 *	This procedure will release the memory associated with {chunk}.
 */
void
memory_free(
    void *chunk)
{
    assert(chunk != (void *)0);
    free(chunk);
}


/*
 * This procedure will return the buffer address associated with
 * {memory}.  The buffer address can change as a result of the
 * {resize}@{memory}() operation.
 */
unsigned
memory__buffer_address_get(
    Memory memory)
{
    return (unsigned)memory->buffer;
}

/*
 * memory__create(size)
 *	This procedure will return a chunk of memory that contains
 *	{size} bytes of memory.  The mode of the returned memory is
 *	{read_write}.
 */
Memory
memory__create(
    unsigned size)
{
    unsigned char *buffer;
    unsigned limit;
    Memory memory;

    limit = ((size - 1) | 3 ) + 1;
    buffer = (unsigned char *)malloc(limit);
    assert(buffer != (unsigned char *)0);
    (void)memset(buffer, 0, size);
    memory = (Memory)malloc(sizeof *memory);
    assert(memory != (Memory)0);
    memory->buffer = buffer;
    memory->limit = limit;
    memory->mode = Memory_mode__read_write;
    memory->size = size;

    /* (void)printf("memory__create(%d): memory:0x%x buffer:0x%x\n",
      size, memory, buffer); */

    return memory;
}

/*
 * memory__fetch1(memory, index)
 *	This procedure will fetch and return the byte value at the
 *	{index}'th location in {memory}.
 */
unsigned
memory__fetch1(
    Memory memory,
    unsigned index)
{
    assert(index < memory->size);
    return memory->buffer[index];
}

/*
 * memory__integer_word_fetch(memory, word_index)
 *	This procedure will return the 4-byte signed integer from
 *	{memory} starting {word_offset}.  The word is fetched from
 *	the memory location in the "natural" byte order for the machine.
 */
int
memory__integer_word_fetch(
    Memory memory,
    unsigned word_index)
{
    assert(word_index < (memory->size >> 2));
    return ((int *)memory->buffer)[word_index];
}

/*
 * memory__integer_word_store(memory, word_index, value)
 *	This procedure will store {value} into {memory} at {word_offset}
 *	as a 4-byte signed integer.  The word is fetched from the memory
 *	location in the "natural" byte order for the machine.
 */
void
memory__integer_word_store(
    Memory memory,
    unsigned word_index,
    unsigned value)
{
    assert(memory->mode == Memory_mode__read_write);
    assert(word_index < (memory->size >> 2));
    ((int *)memory->buffer)[word_index] = value;
}

/*
 * memory__limit_get(memory)
 *	This procudure will the number of bytes associated with {memory}.
 */
unsigned
memory__limit_get(
    Memory memory)
{
    return memory->limit;
}

/*
 * memory__mode_get(memory)
 *	This procudure will the {memory_mode} associated with {memory}.
 */
unsigned
memory__mode_get(
    Memory memory)
{
    return memory->mode;
}

/*
 * memory___resize(memory, new_size)
 *	This procedure ensure that there are {new_size} bytes of
 *	memory in {memory}.
 */
void
memory__resize(
    Memory memory,
    unsigned new_size)
{
    /* (void)printf("=>memory__resize(0x%x, %d)\n", memory, new_size); */
    assert(memory->mode == Memory_mode__read_write);
    if (new_size > memory->limit) {
	unsigned char *old_buffer;
	unsigned char *new_buffer;
	unsigned new_limit;
	unsigned old_size;

	/* unsigned char *old_buffer;
	old_buffer = memory->buffer; */

	old_buffer = memory->buffer;
	old_size = memory->size;
	new_limit = ((new_size - 1) | 3) + 1;
#ifdef LINUX
	new_buffer = (unsigned char *)realloc(old_buffer, new_limit);
	assert(new_buffer != (unsigned char *)0);
#endif /* LINUX */
#ifdef WINDOWS
	/* FIXME: I think that windows has fixed the realloc() bug!!! */
	new_buffer = (unsigned char *)malloc(new_limit);
	assert(new_buffer != (unsigned char *)0);
	memcpy(new_buffer, old_buffer, old_size);
#endif /* WINDOWS */
	memory->buffer = new_buffer;
	memory->limit = new_limit;

	/* (void)printf("old_buffer:0x%x new_buffer:0x%x\n",
	  old_buffer, buffer); */

	/* (void)memset(new_buffer + old_size, 0, new_size - old_size); */
    }
    memory->size = new_size;
    /* (void)printf("<=memory__resize(0x%x, %d)\n", memory, new_size); */
}

/*
 * memory__size_get(memory)
 *	This procudure will the number of bytes associated with {memory}.
 */
unsigned
memory__size_get(
    Memory memory)
{
    return memory->size;
}

/*
 * memory_store1(memory, index, value)
 *	This procedure will store {value} into the {index}'th location
 *	in {memory}.
 */
void
memory__store1(
    Memory memory,
    unsigned index,
    unsigned value)
{
    /* (void)printf("memory__store1(0x%x, %d, %d) size=%d\n",
       memory, index, value, memory->size); */
    assert(memory->mode == Memory_mode__read_write);
    assert(index < memory->size);
    memory->buffer[index] = value;
}

/*
 * memory__unsigned_word_fetch(memory, word_index)
 *	This procedure will return the 4-byte signed unsigned from
 *	{memory} starting {word_offset}.  The word is fetched from
 *	the memory location in the "natural" byte order for the machine.
 */
unsigned
memory__unsigned_word_fetch(
    Memory memory,
    unsigned word_index)
{
    assert(word_index < (memory->size >> 2));
    return ((unsigned *)memory->buffer)[word_index];
}

/*
 * memory__unsigned_word_store(memory, word_index, value)
 *	This procedure will store {value} into {memory} at {word_offset}
 *	as a 4-byte signed unsigned.  The word is fetched from the memory
 *	location in the "natural" byte order for the machine.
 */
void
memory__unsigned_word_store(
    Memory memory,
    unsigned word_index,
    unsigned value)
{
    assert(memory->mode == Memory_mode__read_write);
    assert(word_index < (memory->size >> 2));
    ((unsigned *)memory->buffer)[word_index] = value;
}









