// -*- c++ -*-
//
// memory.h:
// (little-endian access only)
//
#ifndef	MEMORY_H
#define	MEMORY_H

using namespace std;
#include <vector>
#include "sim.h"

//
// memory class
//
class memory {

    //
    // constants
    //

    // size of memory block
    static const int mblock_size = 4096;		// 4K bytes (== 2^12)
    static const int mblock_size_nbits = 12;

    // size of memory block table
    static const int mblock_table_size = 65536;		// 64K entries (== 2^16)
    static const int mblock_table_size_nbits = 16;

    // size of memory management root_table's entries
    static const int root_table_size = 16;		// 16 entries (== 2^4)


    //
    // type definitions
    //

    // mblock data array
    typedef sim_word	*mblock;

    // pointer table to mblock
    typedef mblock	*mblock_table;


    //
    // member variables
    //

    // root table (pointer table to mblock pointer tables)
    mblock_table	root_table[root_table_size];


    //
    // helper functions
    //

    // mblock base address
    sim_addr mblock_base(sim_addr addr) {
	return addr & ~(mblock_size - 1);
    }
    // mblock offset address
    sim_addr mblock_offset(sim_addr addr) {
	return addr & (mblock_size - 1);
    }
    // mblock index number (within mblock_table)
    int mblock_index(sim_addr addr) {
	return (addr >> mblock_size_nbits) & (mblock_table_size - 1);
    }
    // mblock table number (within root_table)
    int mblock_table_number(sim_addr addr) {
	return addr >> (mblock_size_nbits + mblock_table_size_nbits);
    }

    // address checker
    void check_address(sim_addr addr, int size);

    // data accessor (get)
    sim_word get(sim_addr addr);

    // data accessor (put)
    void put(sim_addr addr, sim_word val);

public:
    // constructor
    memory();
    // destructor
    ~memory();

    // allocate memory
    void alloc(sim_addr addr, sim_size sz);

    // free memory
    void free(sim_addr addr);

    // clear memory
    void clear(sim_addr addr, sim_size sz, sim_byte val = 0);

    // check allocated or not
    bool is_allocated(sim_addr addr);
    bool is_allocated(sim_addr addr, sim_size sz);

    // read data
    sim_byte read_byte(sim_addr addr);
    sim_hword read_hword(sim_addr addr);
    sim_word read_word(sim_addr addr);
    sim_dword read_dword(sim_addr addr);

    // write write
    void write_byte(sim_addr addr, sim_byte val);
    void write_hword(sim_addr addr, sim_hword val);
    void write_word(sim_addr addr, sim_word val);
    void write_dword(sim_addr addr, sim_dword val);

    // misc.
    void print(sim_addr addr, sim_size sz);
};

#endif
// end of memory.h