More reorganization and finally merged the two makefiles.

This commit is contained in:
OBattler
2020-06-13 12:32:09 +02:00
parent 4e48943ad5
commit ca55e2a12a
35 changed files with 3645 additions and 4372 deletions

502
src/mem/intel_flash.c Normal file
View File

@@ -0,0 +1,502 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Implementation of the Intel 1 Mbit and 2 Mbit, 8-bit and
* 16-bit flash devices.
*
*
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2008-2019 Sarah Walker.
* Copyright 2016-2019 Miran Grca.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/machine.h>
#include <86box/timer.h>
#include <86box/nvr.h>
#include <86box/plat.h>
#define FLAG_WORD 4
#define FLAG_BXB 2
#define FLAG_INV_A16 1
enum
{
BLOCK_MAIN1,
BLOCK_MAIN2,
BLOCK_DATA1,
BLOCK_DATA2,
BLOCK_BOOT,
BLOCKS_NUM
};
enum
{
CMD_READ_ARRAY = 0xff,
CMD_IID = 0x90,
CMD_READ_STATUS = 0x70,
CMD_CLEAR_STATUS = 0x50,
CMD_ERASE_SETUP = 0x20,
CMD_ERASE_CONFIRM = 0xd0,
CMD_ERASE_SUSPEND = 0xb0,
CMD_PROGRAM_SETUP = 0x40,
CMD_PROGRAM_SETUP_ALT = 0x10
};
typedef struct flash_t
{
uint8_t command, status,
pad, flags,
*array;
uint16_t flash_id, pad16;
uint32_t program_addr,
block_start[BLOCKS_NUM], block_end[BLOCKS_NUM],
block_len[BLOCKS_NUM];
mem_mapping_t mapping[4], mapping_h[8];
} flash_t;
static wchar_t flash_path[1024];
static uint8_t
flash_read(uint32_t addr, void *p)
{
flash_t *dev = (flash_t *) p;
uint8_t ret = 0xff;
if (dev->flags & FLAG_INV_A16)
addr ^= 0x10000;
addr &= biosmask;
switch (dev->command) {
case CMD_READ_ARRAY:
default:
ret = dev->array[addr];
break;
case CMD_IID:
if (addr & 1)
ret = dev->flash_id & 0xff;
else
ret = 0x89;
break;
case CMD_READ_STATUS:
ret = dev->status;
break;
}
return ret;
}
static uint16_t
flash_readw(uint32_t addr, void *p)
{
flash_t *dev = (flash_t *) p;
uint16_t *q;
uint16_t ret = 0xffff;
if (dev->flags & FLAG_INV_A16)
addr ^= 0x10000;
addr &= biosmask;
if (dev->flags & FLAG_WORD)
addr &= 0xfffffffe;
q = (uint16_t *)&(dev->array[addr]);
ret = *q;
if (dev->flags & FLAG_WORD) switch (dev->command) {
case CMD_READ_ARRAY:
default:
break;
case CMD_IID:
if (addr & 2)
ret = dev->flash_id;
else
ret = 0x0089;
break;
case CMD_READ_STATUS:
ret = dev->status;
break;
}
return ret;
}
static uint32_t
flash_readl(uint32_t addr, void *p)
{
flash_t *dev = (flash_t *)p;
uint32_t *q;
if (dev->flags & FLAG_INV_A16)
addr ^= 0x10000;
addr &= biosmask;
q = (uint32_t *)&(dev->array[addr]);
return *q;
}
static void
flash_write(uint32_t addr, uint8_t val, void *p)
{
flash_t *dev = (flash_t *) p;
int i;
uint32_t bb_mask = biosmask & 0xffffe000;
if (biosmask == 0x3ffff)
bb_mask &= 0xffffc000;
if (dev->flags & FLAG_INV_A16)
addr ^= 0x10000;
addr &= biosmask;
switch (dev->command) {
case CMD_ERASE_SETUP:
if (val == CMD_ERASE_CONFIRM) {
for (i = 0; i < 3; i++) {
if ((addr >= dev->block_start[i]) && (addr <= dev->block_end[i]))
memset(&(dev->array[dev->block_start[i]]), 0xff, dev->block_len[i]);
}
dev->status = 0x80;
}
dev->command = CMD_READ_STATUS;
break;
case CMD_PROGRAM_SETUP:
case CMD_PROGRAM_SETUP_ALT:
if (((addr & bb_mask) != (dev->block_start[4] & bb_mask)) && (addr == dev->program_addr))
dev->array[addr] = val;
dev->command = CMD_READ_STATUS;
dev->status = 0x80;
break;
default:
dev->command = val;
switch (val) {
case CMD_CLEAR_STATUS:
dev->status = 0;
break;
case CMD_PROGRAM_SETUP:
case CMD_PROGRAM_SETUP_ALT:
dev->program_addr = addr;
break;
}
}
}
static void
flash_writew(uint32_t addr, uint16_t val, void *p)
{
flash_t *dev = (flash_t *) p;
int i;
uint32_t bb_mask = biosmask & 0xffffe000;
if (biosmask == 0x3ffff)
bb_mask &= 0xffffc000;
if (dev->flags & FLAG_INV_A16)
addr ^= 0x10000;
addr &= biosmask;
if (dev->flags & FLAG_WORD) switch (dev->command) {
case CMD_ERASE_SETUP:
if (val == CMD_ERASE_CONFIRM) {
for (i = 0; i < 3; i++) {
if ((addr >= dev->block_start[i]) && (addr <= dev->block_end[i]))
memset(&(dev->array[dev->block_start[i]]), 0xff, dev->block_len[i]);
}
dev->status = 0x80;
}
dev->command = CMD_READ_STATUS;
break;
case CMD_PROGRAM_SETUP:
case CMD_PROGRAM_SETUP_ALT:
if (((addr & bb_mask) != (dev->block_start[4] & bb_mask)) && (addr == dev->program_addr))
*(uint16_t *) (&dev->array[addr]) = val;
dev->command = CMD_READ_STATUS;
dev->status = 0x80;
break;
default:
dev->command = val & 0xff;
switch (val) {
case CMD_CLEAR_STATUS:
dev->status = 0;
break;
case CMD_PROGRAM_SETUP:
case CMD_PROGRAM_SETUP_ALT:
dev->program_addr = addr;
break;
}
}
}
static void
flash_writel(uint32_t addr, uint32_t val, void *p)
{
#if 0
flash_writew(addr, val & 0xffff, p);
flash_writew(addr + 2, (val >> 16) & 0xffff, p);
#endif
}
static void
intel_flash_add_mappings(flash_t *dev)
{
int max = 2, i = 0;
uint32_t base, fbase;
uint32_t sub = 0x20000;
if (biosmask == 0x3ffff) {
sub = 0x40000;
max = 4;
}
for (i = 0; i < max; i++) {
if (biosmask == 0x3ffff)
base = 0xc0000 + (i << 16);
else
base = 0xe0000 + (i << 16);
fbase = base & biosmask;
if (dev->flags & FLAG_INV_A16)
fbase ^= 0x10000;
memcpy(&dev->array[fbase], &rom[base & biosmask], 0x10000);
if ((max == 2) || (i >= 2)) {
mem_mapping_add(&(dev->mapping[i]), base, 0x10000,
flash_read, flash_readw, flash_readl,
flash_write, flash_writew, flash_writel,
dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROMCS, (void *) dev);
}
mem_mapping_add(&(dev->mapping_h[i]), (base | 0xfff00000) - sub, 0x10000,
flash_read, flash_readw, flash_readl,
flash_write, flash_writew, flash_writel,
dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROMCS, (void *) dev);
mem_mapping_add(&(dev->mapping_h[i + 4]), (base | 0xfff00000), 0x10000,
flash_read, flash_readw, flash_readl,
flash_write, flash_writew, flash_writel,
dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROMCS, (void *) dev);
}
}
static void
intel_flash_reset(void *priv)
{
flash_t *dev = (flash_t *) priv;
dev->command = CMD_READ_ARRAY;
dev->status = 0;
}
static void *
intel_flash_init(const device_t *info)
{
FILE *f;
int l;
flash_t *dev;
wchar_t *machine_name, *flash_name;
uint8_t type = info->local & 0xff;
dev = malloc(sizeof(flash_t));
memset(dev, 0, sizeof(flash_t));
l = strlen(machine_get_internal_name_ex(machine))+1;
machine_name = (wchar_t *) malloc(l * sizeof(wchar_t));
mbstowcs(machine_name, machine_get_internal_name_ex(machine), l);
l = wcslen(machine_name)+5;
flash_name = (wchar_t *)malloc(l*sizeof(wchar_t));
swprintf(flash_name, l, L"%ls.bin", machine_name);
if (wcslen(flash_name) <= 1024)
wcscpy(flash_path, flash_name);
else
wcsncpy(flash_path, flash_name, 1024);
dev->flags = info->local & 0xff;
mem_mapping_disable(&bios_mapping);
mem_mapping_disable(&bios_high_mapping);
dev->array = (uint8_t *) malloc(biosmask + 1);
memset(dev->array, 0xff, biosmask + 1);
if (biosmask == 0x3ffff) {
if (dev->flags & FLAG_WORD)
dev->flash_id = (dev->flags & FLAG_BXB) ? 0x2275 : 0x2274;
else
dev->flash_id = (dev->flags & FLAG_BXB) ? 0x7D : 0x7C;
/* The block lengths are the same both flash types. */
dev->block_len[BLOCK_MAIN1] = 0x20000;
dev->block_len[BLOCK_MAIN2] = 0x18000;
dev->block_len[BLOCK_DATA1] = 0x02000;
dev->block_len[BLOCK_DATA2] = 0x02000;
dev->block_len[BLOCK_BOOT] = 0x04000;
if (dev->flags & FLAG_BXB) { /* 28F002BX-B/28F200BX-B */
dev->block_start[BLOCK_MAIN1] = 0x20000; /* MAIN BLOCK 1 */
dev->block_end[BLOCK_MAIN1] = 0x3ffff;
dev->block_start[BLOCK_MAIN2] = 0x08000; /* MAIN BLOCK 2 */
dev->block_end[BLOCK_MAIN2] = 0x1ffff;
dev->block_start[BLOCK_DATA1] = 0x06000; /* DATA AREA 1 BLOCK */
dev->block_end[BLOCK_DATA1] = 0x07fff;
dev->block_start[BLOCK_DATA2] = 0x04000; /* DATA AREA 2 BLOCK */
dev->block_end[BLOCK_DATA2] = 0x05fff;
dev->block_start[BLOCK_BOOT] = 0x00000; /* BOOT BLOCK */
dev->block_end[BLOCK_BOOT] = 0x03fff;
} else { /* 28F002BX-T/28F200BX-T */
dev->block_start[BLOCK_MAIN1] = 0x00000; /* MAIN BLOCK 1 */
dev->block_end[BLOCK_MAIN1] = 0x1ffff;
dev->block_start[BLOCK_MAIN2] = 0x20000; /* MAIN BLOCK 2 */
dev->block_end[BLOCK_MAIN2] = 0x37fff;
dev->block_start[BLOCK_DATA1] = 0x38000; /* DATA AREA 1 BLOCK */
dev->block_end[BLOCK_DATA1] = 0x39fff;
dev->block_start[BLOCK_DATA2] = 0x3a000; /* DATA AREA 2 BLOCK */
dev->block_end[BLOCK_DATA2] = 0x3bfff;
dev->block_start[BLOCK_BOOT] = 0x3c000; /* BOOT BLOCK */
dev->block_end[BLOCK_BOOT] = 0x3ffff;
}
} else {
dev->flash_id = (type & FLAG_BXB) ? 0x95 : 0x94;
/* The block lengths are the same both flash types. */
dev->block_len[BLOCK_MAIN1] = 0x1c000;
dev->block_len[BLOCK_MAIN2] = 0x00000;
dev->block_len[BLOCK_DATA1] = 0x01000;
dev->block_len[BLOCK_DATA2] = 0x01000;
dev->block_len[BLOCK_BOOT] = 0x02000;
if (dev->flags & FLAG_BXB) { /* 28F001BX-B/28F100BX-B */
dev->block_start[BLOCK_MAIN1] = 0x04000; /* MAIN BLOCK 1 */
dev->block_end[BLOCK_MAIN1] = 0x1ffff;
dev->block_start[BLOCK_MAIN2] = 0xfffff; /* MAIN BLOCK 2 */
dev->block_end[BLOCK_MAIN2] = 0xfffff;
dev->block_start[BLOCK_DATA1] = 0x02000; /* DATA AREA 1 BLOCK */
dev->block_end[BLOCK_DATA1] = 0x02fff;
dev->block_start[BLOCK_DATA2] = 0x03000; /* DATA AREA 2 BLOCK */
dev->block_end[BLOCK_DATA2] = 0x03fff;
dev->block_start[BLOCK_BOOT] = 0x00000; /* BOOT BLOCK */
dev->block_end[BLOCK_BOOT] = 0x01fff;
} else { /* 28F001BX-T/28F100BX-T */
dev->block_start[BLOCK_MAIN1] = 0x00000; /* MAIN BLOCK 1 */
dev->block_end[BLOCK_MAIN1] = 0x1bfff;
dev->block_start[BLOCK_MAIN2] = 0xfffff; /* MAIN BLOCK 2 */
dev->block_end[BLOCK_MAIN2] = 0xfffff;
dev->block_start[BLOCK_DATA1] = 0x1c000; /* DATA AREA 1 BLOCK */
dev->block_end[BLOCK_DATA1] = 0x1cfff;
dev->block_start[BLOCK_DATA2] = 0x1d000; /* DATA AREA 2 BLOCK */
dev->block_end[BLOCK_DATA2] = 0x1dfff;
dev->block_start[BLOCK_BOOT] = 0x1e000; /* BOOT BLOCK */
dev->block_end[BLOCK_BOOT] = 0x1ffff;
}
}
intel_flash_add_mappings(dev);
dev->command = CMD_READ_ARRAY;
dev->status = 0;
f = nvr_fopen(flash_path, L"rb");
if (f) {
fread(&(dev->array[dev->block_start[BLOCK_MAIN1]]), dev->block_len[BLOCK_MAIN1], 1, f);
if (dev->block_len[BLOCK_MAIN2])
fread(&(dev->array[dev->block_start[BLOCK_MAIN2]]), dev->block_len[BLOCK_MAIN2], 1, f);
fread(&(dev->array[dev->block_start[BLOCK_DATA1]]), dev->block_len[BLOCK_DATA1], 1, f);
fread(&(dev->array[dev->block_start[BLOCK_DATA2]]), dev->block_len[BLOCK_DATA2], 1, f);
fclose(f);
}
free(flash_name);
free(machine_name);
return dev;
}
static void
intel_flash_close(void *p)
{
FILE *f;
flash_t *dev = (flash_t *)p;
f = nvr_fopen(flash_path, L"wb");
fwrite(&(dev->array[dev->block_start[BLOCK_MAIN1]]), dev->block_len[BLOCK_MAIN1], 1, f);
if (dev->block_len[BLOCK_MAIN2])
fwrite(&(dev->array[dev->block_start[BLOCK_MAIN2]]), dev->block_len[BLOCK_MAIN2], 1, f);
fwrite(&(dev->array[dev->block_start[BLOCK_DATA1]]), dev->block_len[BLOCK_DATA1], 1, f);
fwrite(&(dev->array[dev->block_start[BLOCK_DATA2]]), dev->block_len[BLOCK_DATA2], 1, f);
fclose(f);
free(dev);
}
/* For AMI BIOS'es - Intel 28F001BXT with A16 pin inverted. */
const device_t intel_flash_bxt_ami_device =
{
"Intel 28F001BXT/28F002BXT Flash BIOS",
DEVICE_PCI,
FLAG_INV_A16,
intel_flash_init,
intel_flash_close,
intel_flash_reset,
NULL, NULL, NULL, NULL
};
const device_t intel_flash_bxt_device =
{
"Intel 28F001BXT/28F002BXT Flash BIOS",
DEVICE_PCI, 0,
intel_flash_init,
intel_flash_close,
intel_flash_reset,
NULL, NULL, NULL, NULL
};
const device_t intel_flash_bxb_device =
{
"Intel 28F001BXB/28F002BXB Flash BIOS",
DEVICE_PCI, FLAG_BXB,
intel_flash_init,
intel_flash_close,
intel_flash_reset,
NULL, NULL, NULL, NULL
};

2888
src/mem/mem.c Normal file

File diff suppressed because it is too large Load Diff

450
src/mem/rom.c Normal file
View File

@@ -0,0 +1,450 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Handling of ROM image files.
*
* NOTES: - pc2386 BIOS is corrupt (JMP at F000:FFF0 points to RAM)
* - pc2386 video BIOS is underdumped (16k instead of 24k)
* - c386sx16 BIOS fails checksum
*
*
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
*
* Copyright 2008-2019 Sarah Walker.
* Copyright 2016-2019 Miran Grca.
* Copyright 2018,2019 Fred N. van Kempen.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/mem.h>
#include <86box/rom.h>
#include <86box/plat.h>
#include <86box/machine.h>
#include <86box/m_xt_xi8088.h>
#ifdef ENABLE_ROM_LOG
int rom_do_log = ENABLE_ROM_LOG;
static void
rom_log(const char *fmt, ...)
{
va_list ap;
if (rom_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
#define rom_log(fmt, ...)
#endif
FILE *
rom_fopen(wchar_t *fn, wchar_t *mode)
{
wchar_t temp[1024];
if (wcslen(exe_path) <= 1024)
wcscpy(temp, exe_path);
else
wcsncpy(temp, exe_path, 1024);
plat_put_backslash(temp);
wcscat(temp, fn);
return(plat_fopen(temp, mode));
}
int
rom_getfile(wchar_t *fn, wchar_t *s, int size)
{
FILE *f;
wcscpy(s, exe_path);
plat_put_backslash(s);
wcscat(s, fn);
f = plat_fopen(s, L"rb");
if (f != NULL) {
(void)fclose(f);
return(1);
}
return(0);
}
int
rom_present(wchar_t *fn)
{
FILE *f;
f = rom_fopen(fn, L"rb");
if (f != NULL) {
(void)fclose(f);
return(1);
}
return(0);
}
uint8_t
rom_read(uint32_t addr, void *priv)
{
rom_t *rom = (rom_t *)priv;
#ifdef ROM_TRACE
if (rom->mapping.base==ROM_TRACE)
rom_log("ROM: read byte from BIOS at %06lX\n", addr);
#endif
if (addr < rom->mapping.base)
return 0xff;
if (addr >= (rom->mapping.base + rom->sz))
return 0xff;
return(rom->rom[(addr - rom->mapping.base) & rom->mask]);
}
uint16_t
rom_readw(uint32_t addr, void *priv)
{
rom_t *rom = (rom_t *)priv;
#ifdef ROM_TRACE
if (rom->mapping.base==ROM_TRACE)
rom_log("ROM: read word from BIOS at %06lX\n", addr);
#endif
if (addr < (rom->mapping.base - 1))
return 0xffff;
if (addr >= (rom->mapping.base + rom->sz))
return 0xffff;
return(*(uint16_t *)&rom->rom[(addr - rom->mapping.base) & rom->mask]);
}
uint32_t
rom_readl(uint32_t addr, void *priv)
{
rom_t *rom = (rom_t *)priv;
#ifdef ROM_TRACE
if (rom->mapping.base==ROM_TRACE)
rom_log("ROM: read long from BIOS at %06lX\n", addr);
#endif
if (addr < (rom->mapping.base - 3))
return 0xffffffff;
if (addr >= (rom->mapping.base + rom->sz))
return 0xffffffff;
return(*(uint32_t *)&rom->rom[(addr - rom->mapping.base) & rom->mask]);
}
/* Load a ROM BIOS from its chips, interleaved mode. */
int
rom_load_linear(wchar_t *fn, uint32_t addr, int sz, int off, uint8_t *ptr)
{
FILE *f = rom_fopen(fn, L"rb");
if (f == NULL) {
rom_log("ROM: image '%ls' not found\n", fn);
return(0);
}
/* Make sure we only look at the base-256K offset. */
if (addr >= 0x40000)
addr = 0;
else
addr &= 0x03ffff;
if (ptr != NULL) {
if (fseek(f, off, SEEK_SET) == -1)
fatal("rom_load_linear(): Error seeking to the beginning of the file\n");
if (fread(ptr+addr, 1, sz, f) > sz)
fatal("rom_load_linear(): Error reading data\n");
}
(void)fclose(f);
return(1);
}
/* Load a ROM BIOS from its chips, linear mode with high bit flipped. */
int
rom_load_linear_inverted(wchar_t *fn, uint32_t addr, int sz, int off, uint8_t *ptr)
{
FILE *f = rom_fopen(fn, L"rb");
if (f == NULL) {
rom_log("ROM: image '%ls' not found\n", fn);
return(0);
}
/* Make sure we only look at the base-256K offset. */
if (addr >= 0x40000)
{
addr = 0;
}
else
{
addr &= 0x03ffff;
}
(void)fseek(f, 0, SEEK_END);
if (ftell(f) < sz) {
(void)fclose(f);
return(0);
}
if (ptr != NULL) {
if (fseek(f, off, SEEK_SET) == -1)
fatal("rom_load_linear_inverted(): Error seeking to the beginning of the file\n");
if (fread(ptr+addr+0x10000, 1, sz >> 1, f) > (sz >> 1))
fatal("rom_load_linear_inverted(): Error reading the upper half of the data\n");
if (fread(ptr+addr, sz >> 1, 1, f) > (sz >> 1))
fatal("rom_load_linear_inverted(): Error reading the lower half of the data\n");
}
(void)fclose(f);
return(1);
}
/* Load a ROM BIOS from its chips, interleaved mode. */
int
rom_load_interleaved(wchar_t *fnl, wchar_t *fnh, uint32_t addr, int sz, int off, uint8_t *ptr)
{
FILE *fl = rom_fopen(fnl, L"rb");
FILE *fh = rom_fopen(fnh, L"rb");
int c;
if (fl == NULL || fh == NULL) {
if (fl == NULL) rom_log("ROM: image '%ls' not found\n", fnl);
else (void)fclose(fl);
if (fh == NULL) rom_log("ROM: image '%ls' not found\n", fnh);
else (void)fclose(fh);
return(0);
}
/* Make sure we only look at the base-256K offset. */
if (addr >= 0x40000)
{
addr = 0;
}
else
{
addr &= 0x03ffff;
}
if (ptr != NULL) {
(void)fseek(fl, off, SEEK_SET);
(void)fseek(fh, off, SEEK_SET);
for (c=0; c<sz; c+=2) {
ptr[addr+c] = fgetc(fl) & 0xff;
ptr[addr+c+1] = fgetc(fh) & 0xff;
}
}
(void)fclose(fh);
(void)fclose(fl);
return(1);
}
static int
bios_normalize(int n, int up)
{
/* 0x2000 -> 0x0000; 0x4000 -> 0x4000; 0x6000 -> 0x4000 */
int temp_n = n & ~MEM_GRANULARITY_MASK;
/* 0x2000 -> 0x4000; 0x4000 -> 0x4000; 0x6000 -> 0x8000 */
if (up && (n % MEM_GRANULARITY_SIZE))
temp_n += MEM_GRANULARITY_SIZE;
return temp_n;
}
static uint8_t *
rom_reset(uint32_t addr, int sz)
{
biosaddr = bios_normalize(addr, 0);
biosmask = bios_normalize(sz, 1) - 1;
if ((biosaddr + biosmask) > 0x000fffff)
biosaddr = 0x000fffff - biosmask;
rom_log("Load BIOS: %i bytes at %08X-%08X\n", biosmask + 1, biosaddr, biosaddr + biosmask);
/* If not done yet, allocate a 128KB buffer for the BIOS ROM. */
if (rom != NULL) {
rom_log("ROM allocated, freeing...\n");
free(rom);
rom = NULL;
}
rom_log("Allocating ROM...\n");
rom = (uint8_t *)malloc(biosmask + 1);
rom_log("Filling ROM with FF's...\n");
memset(rom, 0xff, biosmask + 1);
return rom;
}
/* These four are for loading the BIOS. */
int
bios_load(wchar_t *fn1, wchar_t *fn2, uint32_t addr, int sz, int off, int flags)
{
uint8_t ret = 0;
uint8_t *ptr = NULL;
int i, old_sz = sz;
/*
f0000, 65536 = prepare 64k rom starting at f0000, load 64k bios at 0000
fe000, 65536 = prepare 64k rom starting at f0000, load 8k bios at e000
fe000, 49152 = prepare 48k rom starting at f4000, load 8k bios at a000
fe000, 8192 = prepare 16k rom starting at fc000, load 8k bios at 2000
*/
if (!bios_only)
ptr = (flags & FLAG_AUX) ? rom : rom_reset(addr, sz);
if (!(flags & FLAG_AUX) && ((addr + sz) > 0x00100000))
sz = 0x00100000 - addr;
#ifdef ENABLE_ROM_LOG
if (!bios_only)
rom_log("%sing %i bytes of %sBIOS starting with ptr[%08X] (ptr = %08X)\n", (bios_only) ? "Check" : "Load", sz, (flags & FLAG_AUX) ? "auxiliary " : "", addr - biosaddr, ptr);
#endif
if (flags & FLAG_INT)
ret = rom_load_interleaved(fn1, fn2, addr - biosaddr, sz, off, ptr);
else {
if (flags & FLAG_INV)
ret = rom_load_linear_inverted(fn1, addr - biosaddr, sz, off, ptr);
else
ret = rom_load_linear(fn1, addr - biosaddr, sz, off, ptr);
}
if (!bios_only && (flags & FLAG_REP) && (old_sz >= 65536) && (sz < old_sz)) {
old_sz /= sz;
for (i = 0; i < (old_sz - 1); i++) {
rom_log("Copying ptr[%08X] to ptr[%08X]\n", addr - biosaddr, i * sz);
memcpy(&(ptr[i * sz]), &(ptr[addr - biosaddr]), sz);
}
}
if (!bios_only && ret && !(flags & FLAG_AUX))
mem_add_bios();
return ret;
}
int
bios_load_linear_combined(wchar_t *fn1, wchar_t *fn2, int sz, int off)
{
uint8_t ret = 0;
ret = bios_load_linear(fn1, 0x000f0000, 131072, 128);
ret &= bios_load_aux_linear(fn2, 0x000e0000, sz - 65536, 128);
return ret;
}
int
bios_load_linear_combined2(wchar_t *fn1, wchar_t *fn2, wchar_t *fn3, wchar_t *fn4, wchar_t *fn5, int sz, int off)
{
uint8_t ret = 0;
ret = bios_load_linear(fn3, 0x000f0000, 262144, 128);
ret &= bios_load_aux_linear(fn1, 0x000d0000, 65536, 128);
ret &= bios_load_aux_linear(fn2, 0x000c0000, 65536, 128);
ret &= bios_load_aux_linear(fn4, 0x000e0000, sz - 196608, 128);
ret &= bios_load_aux_linear(fn5, 0x000ec000, 16384, 128);
return ret;
}
int
rom_init(rom_t *rom, wchar_t *fn, uint32_t addr, int sz, int mask, int off, uint32_t flags)
{
rom_log("rom_init(%08X, %08X, %08X, %08X, %08X, %08X, %08X)\n", rom, fn, addr, sz, mask, off, flags);
/* Allocate a buffer for the image. */
rom->rom = malloc(sz);
memset(rom->rom, 0xff, sz);
/* Load the image file into the buffer. */
if (! rom_load_linear(fn, addr, sz, off, rom->rom)) {
/* Nope.. clean up. */
free(rom->rom);
rom->rom = NULL;
return(-1);
}
rom->sz = sz;
rom->mask = mask;
mem_mapping_add(&rom->mapping,
addr, sz,
rom_read, rom_readw, rom_readl,
mem_write_null, mem_write_nullw, mem_write_nulll,
rom->rom, flags | MEM_MAPPING_ROM, rom);
return(0);
}
int
rom_init_interleaved(rom_t *rom, wchar_t *fnl, wchar_t *fnh, uint32_t addr, int sz, int mask, int off, uint32_t flags)
{
/* Allocate a buffer for the image. */
rom->rom = malloc(sz);
memset(rom->rom, 0xff, sz);
/* Load the image file into the buffer. */
if (! rom_load_interleaved(fnl, fnh, addr, sz, off, rom->rom)) {
/* Nope.. clean up. */
free(rom->rom);
rom->rom = NULL;
return(-1);
}
rom->sz = sz;
rom->mask = mask;
mem_mapping_add(&rom->mapping,
addr, sz,
rom_read, rom_readw, rom_readl,
mem_write_null, mem_write_nullw, mem_write_nulll,
rom->rom, flags | MEM_MAPPING_ROM, rom);
return(0);
}

383
src/mem/spd.c Normal file
View File

@@ -0,0 +1,383 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Emulation of SPD (Serial Presence Detect) devices.
*
*
*
* Authors: RichardG, <richardg867@gmail.com>
*
* Copyright 2020 RichardG.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/smbus.h>
#include <86box/spd.h>
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define SPD_ROLLUP(x) ((x) >= 16 ? ((x) - 15) : (x))
spd_t *spd_devices[SPD_MAX_SLOTS];
uint8_t spd_data[SPD_MAX_SLOTS][SPD_DATA_SIZE];
static uint8_t spd_read_byte(uint8_t addr, void *priv);
static uint8_t spd_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv);
static void spd_write_byte(uint8_t addr, uint8_t val, void *priv);
#ifdef ENABLE_SPD_LOG
int spd_do_log = ENABLE_SPD_LOG;
static void
spd_log(const char *fmt, ...)
{
va_list ap;
if (spd_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
#define spd_log(fmt, ...)
#endif
uint8_t
spd_read_byte(uint8_t addr, void *priv)
{
spd_t *dev = (spd_t *) priv;
return spd_read_byte_cmd(addr, dev->addr_register, priv);
}
uint8_t
spd_read_byte_cmd(uint8_t addr, uint8_t cmd, void *priv)
{
spd_t *dev = (spd_t *) priv;
uint8_t ret = *(spd_data[dev->slot] + cmd);
spd_log("SPD: read(%02X, %02X) = %02X\n", addr, cmd, ret);
return ret;
}
uint16_t
spd_read_word_cmd(uint8_t addr, uint8_t cmd, void *priv)
{
return (spd_read_byte_cmd(addr, cmd + 1, priv) << 8) | spd_read_byte_cmd(addr, cmd, priv);
}
uint8_t
spd_read_block_cmd(uint8_t addr, uint8_t cmd, uint8_t *data, uint8_t len, void *priv)
{
uint8_t read = 0;
for (uint8_t i = cmd; i < len && i < SPD_DATA_SIZE; i++) {
data[read++] = spd_read_byte_cmd(addr, i, priv);
}
return read;
}
void
spd_write_byte(uint8_t addr, uint8_t val, void *priv)
{
spd_t *dev = (spd_t *) priv;
dev->addr_register = val;
}
static void
spd_close(void *priv)
{
spd_t *dev = (spd_t *) priv;
spd_log("SPD: closing slot %d (SMBus %02Xh)\n", dev->slot, SPD_BASE_ADDR + dev->slot);
smbus_removehandler(SPD_BASE_ADDR + dev->slot, 1,
spd_read_byte, spd_read_byte_cmd, spd_read_word_cmd, spd_read_block_cmd,
spd_write_byte, NULL, NULL, NULL,
dev);
free(dev);
}
static void *
spd_init(const device_t *info)
{
spd_t *dev = spd_devices[info->local];
spd_log("SPD: initializing slot %d (SMBus %02Xh)\n", dev->slot, SPD_BASE_ADDR + dev->slot);
smbus_sethandler(SPD_BASE_ADDR + dev->slot, 1,
spd_read_byte, spd_read_byte_cmd, spd_read_word_cmd, spd_read_block_cmd,
spd_write_byte, NULL, NULL, NULL,
dev);
return dev;
}
uint8_t
log2_ui16(uint16_t i)
{
uint8_t ret = 0;
while ((i >>= 1))
ret++;
return ret;
}
int
comp_ui16_rev(const void *elem1, const void *elem2)
{
uint16_t a = *((uint16_t *) elem1);
uint16_t b = *((uint16_t *) elem2);
return ((a > b) ? -1 : ((a < b) ? 1 : 0));
}
void
spd_register(uint8_t ram_type, uint8_t slot_mask, uint16_t max_module_size)
{
uint8_t slot, slot_count, vslot, next_empty_vslot, i, split;
uint16_t min_module_size, total_size, vslots[SPD_MAX_SLOTS], asym;
device_t *info;
spd_edo_t *edo_data;
spd_sdram_t *sdram_data;
/* determine the minimum module size for this RAM type */
switch (ram_type) {
case SPD_TYPE_FPM:
case SPD_TYPE_EDO:
min_module_size = SPD_MIN_SIZE_EDO;
break;
case SPD_TYPE_SDRAM:
min_module_size = SPD_MIN_SIZE_SDRAM;
break;
default:
spd_log("SPD: unknown RAM type 0x%02X\n", ram_type);
return;
}
/* count how many (real) slots are enabled */
slot_count = 0;
for (slot = 0; slot < SPD_MAX_SLOTS; slot++) {
vslots[slot] = 0;
if (slot_mask & (1 << slot)) {
slot_count++;
}
}
/* populate vslots with modules in power-of-2 capacities */
total_size = (mem_size >> 10);
for (vslot = 0; vslot < slot_count && total_size; vslot++) {
/* populate slot */
vslots[vslot] = (1 << log2_ui16(MIN(total_size, max_module_size)));
if (total_size >= vslots[vslot]) {
spd_log("SPD: initial vslot %d = %d MB\n", vslot, vslots[vslot]);
total_size -= vslots[vslot];
} else {
vslots[vslot] = 0;
break;
}
}
/* did we populate all the RAM? */
if (total_size) {
/* work backwards to add the missing RAM as asymmetric modules */
vslot = slot_count - 1;
do {
asym = (1 << log2_ui16(MIN(total_size, vslots[vslot])));
if (vslots[vslot] + asym <= max_module_size) {
vslots[vslot] += asym;
total_size -= asym;
}
} while (vslot-- > 0 && total_size);
if (total_size) /* still not enough */
spd_log("SPD: not enough RAM slots (%d) to cover memory (%d MB short)\n", slot_count, total_size);
}
/* populate empty vslots by splitting modules... */
split = (total_size == 0); /* ...if possible */
while (split) {
/* look for a module to split */
split = 0;
for (vslot = 0; vslot < slot_count; vslot++) {
if ((vslots[vslot] < (min_module_size << 1)) || (vslots[vslot] != (1 << log2_ui16(vslots[vslot]))))
continue; /* no module here, module is too small to be split, or asymmetric module */
/* find next empty vslot */
next_empty_vslot = 0;
for (i = vslot + 1; i < slot_count && !next_empty_vslot; i++) {
if (!vslots[i])
next_empty_vslot = i;
}
if (!next_empty_vslot)
break; /* no empty vslots left */
/* split the module into its own vslot and the next empty vslot */
spd_log("SPD: splitting vslot %d (%d MB) into %d and %d (%d MB each)\n", vslot, vslots[vslot], vslot, next_empty_vslot, (vslots[vslot] >> 1));
vslots[vslot] = vslots[next_empty_vslot] = (vslots[vslot] >> 1);
split = 1;
}
/* re-sort vslots by descending capacity if any modules were split */
if (split)
qsort(vslots, slot_count, sizeof(uint16_t), comp_ui16_rev);
}
/* register SPD devices and populate their data according to the vslots */
vslot = 0;
for (slot = 0; slot < SPD_MAX_SLOTS && vslots[vslot]; slot++) {
if (!(slot_mask & (1 << slot)))
continue; /* slot disabled */
info = (device_t *) malloc(sizeof(device_t));
memset(info, 0, sizeof(device_t));
info->name = "Serial Presence Detect ROM";
info->local = slot;
info->init = spd_init;
info->close = spd_close;
spd_devices[slot] = (spd_t *) malloc(sizeof(spd_t));
memset(spd_devices[slot], 0, sizeof(spd_t));
spd_devices[slot]->info = info;
spd_devices[slot]->slot = slot;
spd_devices[slot]->size = vslots[vslot];
/* determine the second row size, from which the first row size can be obtained */
asym = (vslots[vslot] - (1 << log2_ui16(vslots[vslot]))); /* separate the powers of 2 */
if (!asym) /* is the module asymmetric? */
asym = (vslots[vslot] >> 1); /* symmetric, therefore divide by 2 */
spd_devices[slot]->row1 = (vslots[vslot] - asym);
spd_devices[slot]->row2 = asym;
spd_log("SPD: registering slot %d = vslot %d = %d MB (%d/%d)\n", slot, vslot, vslots[vslot], spd_devices[slot]->row1, spd_devices[slot]->row2);
switch (ram_type) {
case SPD_TYPE_FPM:
case SPD_TYPE_EDO:
edo_data = (spd_edo_t *) &spd_data[slot];
memset(edo_data, 0, sizeof(spd_edo_t));
/* EDO SPD is specified by JEDEC and present in some modules, but
most utilities cannot interpret it correctly. SIV32 at least gets
the module capacities right, so it was used as a reference here. */
edo_data->bytes_used = 0x80;
edo_data->spd_size = 0x08;
edo_data->mem_type = ram_type;
edo_data->row_bits = SPD_ROLLUP(7 + log2_ui16(spd_devices[slot]->row1)); /* first row */
edo_data->col_bits = 9;
if (spd_devices[slot]->row1 != spd_devices[slot]->row2) { /* the upper 4 bits of row_bits/col_bits should be 0 on a symmetric module */
edo_data->row_bits |= (SPD_ROLLUP(7 + log2_ui16(spd_devices[slot]->row2)) << 4); /* second row, if different from first */
edo_data->col_bits |= (9 << 4); /* same as first row, but just in case */
}
edo_data->banks = 2;
edo_data->data_width_lsb = 64;
edo_data->signal_level = SPD_SIGNAL_LVTTL;
edo_data->trac = 50;
edo_data->tcac = 13;
edo_data->refresh_rate = SPD_REFRESH_NORMAL;
edo_data->dram_width = 8;
edo_data->spd_rev = 0x12;
sprintf(edo_data->part_no, EMU_NAME "-%s-%03dM", (ram_type == SPD_TYPE_FPM) ? "FPM" : "EDO", vslots[vslot]);
for (i = strlen(edo_data->part_no); i < sizeof(edo_data->part_no); i++)
edo_data->part_no[i] = ' '; /* part number should be space-padded */
edo_data->rev_code[0] = EMU_VERSION_MAJ;
edo_data->rev_code[1] = (((EMU_VERSION_MIN / 10) << 4) | (EMU_VERSION_MIN % 10));
edo_data->mfg_year = 20;
edo_data->mfg_week = 17;
for (i = 0; i < 63; i++)
edo_data->checksum += spd_data[slot][i];
for (i = 0; i < 129; i++)
edo_data->checksum2 += spd_data[slot][i];
break;
case SPD_TYPE_SDRAM:
sdram_data = (spd_sdram_t *) &spd_data[slot];
memset(sdram_data, 0, sizeof(spd_sdram_t));
sdram_data->bytes_used = 0x80;
sdram_data->spd_size = 0x08;
sdram_data->mem_type = ram_type;
sdram_data->row_bits = SPD_ROLLUP(6 + log2_ui16(spd_devices[slot]->row1)); /* first row */
sdram_data->col_bits = 9;
if (spd_devices[slot]->row1 != spd_devices[slot]->row2) { /* the upper 4 bits of row_bits/col_bits should be 0 on a symmetric module */
sdram_data->row_bits |= (SPD_ROLLUP(6 + log2_ui16(spd_devices[slot]->row2)) << 4); /* second row, if different from first */
sdram_data->col_bits |= (9 << 4); /* same as first row, but just in case */
}
sdram_data->rows = 2;
sdram_data->data_width_lsb = 64;
sdram_data->signal_level = SPD_SIGNAL_LVTTL;
sdram_data->tclk = 0x75; /* 7.5 ns = 133.3 MHz */
sdram_data->tac = 0x10;
sdram_data->refresh_rate = SPD_SDR_REFRESH_SELF | SPD_REFRESH_NORMAL;
sdram_data->sdram_width = 8;
sdram_data->tccd = 1;
sdram_data->burst = SPD_SDR_BURST_PAGE | 1 | 2 | 4 | 8;
sdram_data->banks = 4;
sdram_data->cas = 0x1c; /* CAS 5/4/3 supported */
sdram_data->cslat = sdram_data->we = 0x7f;
sdram_data->dev_attr = SPD_SDR_ATTR_EARLY_RAS | SPD_SDR_ATTR_AUTO_PC | SPD_SDR_ATTR_PC_ALL | SPD_SDR_ATTR_W1R_BURST;
sdram_data->tclk2 = 0xA0; /* 10 ns = 100 MHz */
sdram_data->tclk3 = 0xF0; /* 15 ns = 66.7 MHz */
sdram_data->tac2 = sdram_data->tac3 = 0x10;
sdram_data->trp = sdram_data->trrd = sdram_data->trcd = sdram_data->tras = 1;
if (spd_devices[slot]->row1 != spd_devices[slot]->row2) {
/* Utilities interpret bank_density a bit differently on asymmetric modules. */
sdram_data->bank_density = (1 << (log2_ui16(spd_devices[slot]->row1 >> 1) - 2)); /* first row */
sdram_data->bank_density |= (1 << (log2_ui16(spd_devices[slot]->row2 >> 1) - 2)); /* second row */
} else {
sdram_data->bank_density = (1 << (log2_ui16(spd_devices[slot]->row1 >> 1) - 1)); /* symmetric module = only one bit is set */
}
sdram_data->ca_setup = sdram_data->data_setup = 0x15;
sdram_data->ca_hold = sdram_data->data_hold = 0x08;
sdram_data->spd_rev = 0x12;
sprintf(sdram_data->part_no, EMU_NAME "-SDR-%03dM", vslots[vslot]);
for (i = strlen(sdram_data->part_no); i < sizeof(sdram_data->part_no); i++)
sdram_data->part_no[i] = ' '; /* part number should be space-padded */
sdram_data->rev_code[0] = EMU_VERSION_MAJ;
sdram_data->rev_code[1] = (((EMU_VERSION_MIN / 10) << 4) | (EMU_VERSION_MIN % 10));
sdram_data->mfg_year = 20;
sdram_data->mfg_week = 13;
sdram_data->freq = 100;
sdram_data->features = 0xFF;
for (i = 0; i < 63; i++)
sdram_data->checksum += spd_data[slot][i];
for (i = 0; i < 129; i++)
sdram_data->checksum2 += spd_data[slot][i];
break;
}
device_add(info);
vslot++;
}
}

458
src/mem/sst_flash.c Normal file
View File

@@ -0,0 +1,458 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Implementation of an SST flash chip.
*
*
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
* Melissa Goad, <mszoopers@protonmail.com>
*
* Copyright 2008-2020 Sarah Walker.
* Copyright 2016-2020 Miran Grca.
* Copyright 2020 Melissa Goad.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/machine.h>
#include <86box/timer.h>
#include <86box/nvr.h>
#include <86box/plat.h>
typedef struct sst_t
{
uint8_t id, is_39, page_bytes, sdp;
int command_state, id_mode,
dirty;
uint32_t size, mask,
page_mask, page_base;
uint8_t page_buffer[128];
uint8_t *array;
mem_mapping_t mapping[8], mapping_h[8];
pc_timer_t page_write_timer;
} sst_t;
static wchar_t flash_path[1024];
#define SST_CHIP_ERASE 0x10 /* Both 29 and 39, 6th cycle */
#define SST_SDP_DISABLE 0x20 /* Only 29, Software data protect disable and write - treat as write */
#define SST_SECTOR_ERASE 0x30 /* Only 39, 6th cycle */
#define SST_SET_ID_MODE_ALT 0x60 /* Only 29, 6th cycle */
#define SST_ERASE 0x80 /* Both 29 and 39 */
/* With data 60h on 6th cycle, it's alt. ID */
#define SST_SET_ID_MODE 0x90 /* Both 29 and 39 */
#define SST_BYTE_PROGRAM 0xa0 /* Both 29 and 39 */
#define SST_CLEAR_ID_MODE 0xf0 /* Both 29 and 39 */
/* 1st cycle variant only on 39 */
#define SST_ID_MANUFACTURER 0xbf /* SST Manufacturer's ID */
#define SST_ID_SST29EE010 0x07
#define SST_ID_SST29LE_VE010 0x08
#define SST_ID_SST29EE020 0x10
#define SST_ID_SST29LE_VE020 0x12
#define SST_ID_SST39SF512 0xb4
#define SST_ID_SST39SF010 0xb5
#define SST_ID_SST39SF020 0xb6
#define SST_ID_SST39SF040 0xb7
static void
sst_sector_erase(sst_t *dev, uint32_t addr)
{
memset(&dev->array[addr & (dev->mask & ~0xfff)], 0xff, 4096);
dev->dirty = 1;
}
static void
sst_new_command(sst_t *dev, uint32_t addr, uint8_t val)
{
if (dev->command_state == 5) switch (val) {
case SST_CHIP_ERASE:
memset(dev->array, 0xff, 0x20000);
dev->command_state = 0;
break;
case SST_SDP_DISABLE:
if (!dev->is_39)
dev->sdp = 0;
dev->command_state = 0;
break;
case SST_SECTOR_ERASE:
if (dev->is_39)
sst_sector_erase(dev, addr);
dev->command_state = 0;
break;
case SST_SET_ID_MODE_ALT:
dev->id_mode = 1;
dev->command_state = 0;
break;
default:
dev->command_state = 0;
break;
} else switch (val) {
case SST_ERASE:
dev->command_state = 3;
break;
case SST_SET_ID_MODE:
dev->id_mode = 1;
dev->command_state = 0;
break;
case SST_BYTE_PROGRAM:
if (!dev->is_39) {
memset(dev->page_buffer, 0xff, 128);
dev->page_bytes = 0;
timer_on_auto(&dev->page_write_timer, 210.0);
}
dev->command_state = 6;
break;
case SST_CLEAR_ID_MODE:
dev->id_mode = 0;
dev->command_state = 0;
break;
default:
dev->command_state = 0;
break;
}
}
static void
sst_page_write(void *priv)
{
sst_t *dev = (sst_t *) priv;
memcpy(&(dev->array[dev->page_base]), dev->page_buffer, 128);
dev->dirty = 1;
dev->page_bytes = 0;
dev->command_state = 0;
}
static uint8_t
sst_read_id(uint32_t addr, void *p)
{
sst_t *dev = (sst_t *) p;
if ((addr & 0xffff) == 0)
return SST_ID_MANUFACTURER; /* SST */
else if ((addr & 0xffff) == 1)
return dev->id;
else
return 0xff;
}
static void
sst_buf_write(sst_t *dev, uint32_t addr, uint8_t val)
{
dev->page_buffer[addr & 0x0000007f] = val;
timer_disable(&dev->page_write_timer);
dev->page_bytes++;
if (dev->page_bytes >= 128)
sst_page_write(dev);
else
timer_set_delay_u64(&dev->page_write_timer, 210 * TIMER_USEC);
}
static void
sst_write(uint32_t addr, uint8_t val, void *p)
{
sst_t *dev = (sst_t *) p;
switch (dev->command_state) {
case 0:
case 3:
/* 1st and 4th Bus Write Cycle */
if ((val == 0xf0) && dev->is_39 && (dev->command_state == 0)) {
if (dev->id_mode)
dev->id_mode = 0;
dev->command_state = 0;
} else if (((addr & 0x7fff) == 0x5555) && (val == 0xaa))
dev->command_state++;
else {
if (!dev->is_39 && !dev->sdp && (dev->command_state == 0)) {
/* 29 series, software data protection off, start loading the page. */
dev->page_base = addr & dev->page_mask; /* First byte, A7 onwards of its address are the page mask. */
dev->command_state = 7;
sst_buf_write(dev, addr, val);
}
dev->command_state = 0;
}
break;
case 1:
case 4:
/* 2nd and 5th Bus Write Cycle */
if (((addr & 0x7fff) == 0x2aaa) && (val == 0x55))
dev->command_state++;
else
dev->command_state = 0;
break;
case 2:
case 5:
/* 3rd and 6th Bus Write Cycle */
if ((addr & 0x7fff) == 0x5555)
sst_new_command(dev, addr, val);
else
dev->command_state = 0;
break;
case 6:
/* Page Load Cycle (29) / Data Write Cycle (39SF) */
if (dev->is_39) {
dev->array[addr & dev->mask] = val;
dev->command_state = 0;
dev->dirty = 1;
} else {
dev->page_base = addr & dev->page_mask; /* First byte, A7 onwards of its address are the page mask. */
dev->command_state++;
sst_buf_write(dev, addr, val);
}
break;
case 7:
if (!dev->is_39 && ((addr & dev->page_mask) == dev->page_base))
sst_buf_write(dev, addr, val);
break;
}
}
static uint8_t
sst_read(uint32_t addr, void *p)
{
sst_t *dev = (sst_t *) p;
uint8_t ret = 0xff;
addr &= 0x000fffff;
if (dev->id_mode)
ret = sst_read_id(addr, p);
else {
if ((addr >= biosaddr) && (addr <= (biosaddr + biosmask)))
ret = dev->array[addr - biosaddr];
}
return ret;
}
static uint16_t
sst_readw(uint32_t addr, void *p)
{
sst_t *dev = (sst_t *) p;
uint16_t ret = 0xffff;
addr &= 0x000fffff;
if (dev->id_mode)
ret = sst_read(addr, p) | (sst_read(addr + 1, p) << 8);
else {
if ((addr >= biosaddr) && (addr <= (biosaddr + biosmask)))
ret = *(uint16_t *)&dev->array[addr - biosaddr];
}
return ret;
}
static uint32_t
sst_readl(uint32_t addr, void *p)
{
sst_t *dev = (sst_t *) p;
uint32_t ret = 0xffffffff;
addr &= 0x000fffff;
if (dev->id_mode)
ret = sst_readw(addr, p) | (sst_readw(addr + 2, p) << 16);
else {
if ((addr >= biosaddr) && (addr <= (biosaddr + biosmask)))
ret = *(uint32_t *)&dev->array[addr - biosaddr];
}
return ret;
}
static void
sst_add_mappings(sst_t *dev)
{
int i = 0, count;
uint32_t base, fbase;
uint32_t root_base;
count = dev->size >> 16;
root_base = 0x100000 - dev->size;
for (i = 0; i < count; i++) {
base = root_base + (i << 16);
fbase = base & biosmask;
memcpy(&dev->array[fbase], &rom[base & biosmask], 0x10000);
if (base >= 0xe0000) {
mem_mapping_add(&(dev->mapping[i]), base, 0x10000,
sst_read, sst_readw, sst_readl,
sst_write, NULL, NULL,
dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROMCS, (void *) dev);
}
mem_mapping_add(&(dev->mapping_h[i]), (base | 0xfff00000), 0x10000,
sst_read, sst_readw, sst_readl,
sst_write, NULL, NULL,
dev->array + fbase, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROMCS, (void *) dev);
}
}
static void *
sst_init(const device_t *info)
{
FILE *f;
sst_t *dev = malloc(sizeof(sst_t));
memset(dev, 0, sizeof(sst_t));
size_t l = strlen(machine_get_internal_name_ex(machine))+1;
wchar_t *machine_name = (wchar_t *) malloc(l * sizeof(wchar_t));
mbstowcs(machine_name, machine_get_internal_name_ex(machine), l);
l = wcslen(machine_name)+5;
wchar_t *flash_name = (wchar_t *)malloc(l*sizeof(wchar_t));
swprintf(flash_name, l, L"%ls.bin", machine_name);
if (wcslen(flash_name) <= 1024)
wcscpy(flash_path, flash_name);
else
wcsncpy(flash_path, flash_name, 1024);
mem_mapping_disable(&bios_mapping);
mem_mapping_disable(&bios_high_mapping);
dev->array = (uint8_t *) malloc(biosmask + 1);
memset(dev->array, 0xff, biosmask + 1);
dev->id = info->local;
dev->is_39 = (dev->id >= SST_ID_SST39SF512);
if (dev->id == SST_ID_SST39SF512)
dev->size = 0x10000;
else if ((dev->id == SST_ID_SST29EE020) || (dev->id == SST_ID_SST29LE_VE020) || (dev->id == SST_ID_SST39SF020))
dev->size = 0x40000;
else if (dev->id == SST_ID_SST39SF040)
dev->size = 0x80000;
else
dev->size = 0x20000;
dev->mask = dev->size - 1;
dev->page_mask = dev->mask & 0xffffff80; /* Filter out A0-A6. */
dev->sdp = 1;
sst_add_mappings(dev);
f = nvr_fopen(flash_path, L"rb");
if (f) {
if (fread(&(dev->array[0x00000]), 1, dev->size, f) != dev->size)
fatal("Less than %i bytes read from the SST Flash ROM file\n", dev->size);
fclose(f);
} else
dev->dirty = 1; /* It is by definition dirty on creation. */
free(flash_name);
free(machine_name);
if (!dev->is_39)
timer_add(&dev->page_write_timer, sst_page_write, dev, 0);
return dev;
}
static void
sst_close(void *p)
{
FILE *f;
sst_t *dev = (sst_t *)p;
if (dev->dirty) {
f = nvr_fopen(flash_path, L"wb");
fwrite(&(dev->array[0x00000]), dev->size, 1, f);
fclose(f);
}
free(dev->array);
dev->array = NULL;
free(dev);
}
const device_t sst_flash_29ee010_device =
{
"SST 29EE010 Flash BIOS",
0,
SST_ID_SST29EE010,
sst_init,
sst_close,
NULL,
NULL, NULL, NULL, NULL
};
const device_t sst_flash_29ee020_device =
{
"SST 29EE020 Flash BIOS",
0,
SST_ID_SST29EE020,
sst_init,
sst_close,
NULL,
NULL, NULL, NULL, NULL
};
const device_t sst_flash_39sf010_device =
{
"SST 39SF010 Flash BIOS",
0,
SST_ID_SST39SF010,
sst_init,
sst_close,
NULL,
NULL, NULL, NULL, NULL
};
const device_t sst_flash_39sf020_device =
{
"SST 39SF020 Flash BIOS",
0,
SST_ID_SST39SF020,
sst_init,
sst_close,
NULL,
NULL, NULL, NULL, NULL
};