#include <stdlib.h>
#include "ibm.h"
#include "device.h"
#include "io.h"
#include "ps2_nvr.h"
#include "nvr.h"

typedef struct ps2_nvr_t
{
        int addr;
        uint8_t ram[8192];
} ps2_nvr_t;

static uint8_t ps2_nvr_read(uint16_t port, void *p)
{
        ps2_nvr_t *nvr = (ps2_nvr_t *)p;
        
        switch (port)
        {
                case 0x74:
                return nvr->addr & 0xff;
                case 0x75:
                return nvr->addr >> 8;
                case 0x76:
                return nvr->ram[nvr->addr];
        }
        
        return 0xff;
}

static void ps2_nvr_write(uint16_t port, uint8_t val, void *p)
{
        ps2_nvr_t *nvr = (ps2_nvr_t *)p;
        
//        pclog("ps2_nvr_write: port=%04x val=%02x\n", port, val);
        switch (port)
        {
                case 0x74:
                nvr->addr = (nvr->addr & 0x1f00) | val;
                break;
                case 0x75:
                nvr->addr = (nvr->addr & 0xff) | ((val & 0x1f) << 8);
                break;
                case 0x76:
                nvr->ram[nvr->addr] = val;
                break;
        }
}

static void *ps2_nvr_init()
{
        ps2_nvr_t *nvr = (ps2_nvr_t *)malloc(sizeof(ps2_nvr_t));
        FILE *f = NULL;

        memset(nvr, 0, sizeof(ps2_nvr_t));
        
        io_sethandler(0x0074, 0x0003, ps2_nvr_read, NULL, NULL, ps2_nvr_write, NULL, NULL, nvr);

        switch (romset)
        {
                case ROM_IBMPS2_M70_TYPE3:f = nvrfopen("ibmps2_m70_type3_sec.nvr", "rb"); break;
                case ROM_IBMPS2_M70_TYPE4:f = nvrfopen("ibmps2_m70_type4_sec.nvr", "rb"); break;
                case ROM_IBMPS2_M80:      f = nvrfopen("ibmps2_m80_sec.nvr",       "rb"); break;
        }
        if (f)
        {
                fread(nvr->ram, 8192, 1, f);
                fclose(f);
        }
        else
                memset(nvr->ram, 0xFF, 8192);
        
        return nvr;
}

static void ps2_nvr_close(void *p)
{
        ps2_nvr_t *nvr = (ps2_nvr_t *)p;
        FILE *f = NULL;

        switch (romset)
        {
                case ROM_IBMPS2_M70_TYPE3:f = nvrfopen("ibmps2_m70_type3_sec.nvr", "wb"); break;
                case ROM_IBMPS2_M70_TYPE4:f = nvrfopen("ibmps2_m70_type4_sec.nvr", "wb"); break;
                case ROM_IBMPS2_M80:      f = nvrfopen("ibmps2_m80_sec.nvr",       "wb"); break;
        }
        if (f)
        {
                fwrite(nvr->ram, 8192, 1, f);
                fclose(f);
        }
        
        free(nvr);
}

device_t ps2_nvr_device =
{
        "PS/2 NVRRAM",
        0,
        ps2_nvr_init,
        ps2_nvr_close,
        NULL,
        NULL,
        NULL,
        NULL
};
