x49gp/sram.c

796 lines
16 KiB
C

/* $Id: sram.c,v 1.18 2008/12/11 12:18:17 ecd Exp $
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
#include <x49gp.h>
#include <memory.h>
#include <byteorder.h>
#include <saturn.h>
typedef struct {
void *data;
void *shadow;
int fd;
size_t size;
uint32_t offset;
x49gp_t *x49gp;
} x49gp_sram_t;
#define S3C2410_SRAM_BASE 0x08000000
#define S3C2410_SRAM_SIZE 0x00080000
#define BASE 0xbcbb5
#define SATURN(r) ((target_phys_addr_t) &((saturn_cpu_t *)0)->r)
static uint32_t
saturn_map_s2a(saturn_cpu_t *saturn, uint32_t saddr)
{
uint32_t addr;
addr = ldl_p(&saturn->read_map[saddr >> 12]) | ((saddr >> 1) & 0x7ff);
// printf("SATURN: saddr %05x, addr %08x\n", saddr, addr);
return addr;
}
static uint32_t
saturn_peek(saturn_cpu_t *saturn, uint32_t saddr, uint32_t size)
{
uint32_t addr, rot, mask, data;
uint64_t value;
addr = saturn_map_s2a(saturn, saddr) & 0xfffffffc;
if (addr > 0x08080000)
return 0;
// printf("SATURN: addr %08x\n", addr);
value = ((uint64_t) ldl_phys(addr)) | (((uint64_t) ldl_phys(addr + 4)) << 32);
// printf("SATURN: value %016llx\n", value);
rot = (saddr & 7) << 2;
mask = (1ULL << (size << 2)) - 1;
// printf("SATURN: rot %u, mask %08x\n", rot, mask);
data = ((uint32_t) (value >> rot)) & mask;
// printf("SATURN: data %08x\n", data);
return data;
}
static uint32_t
saturn_peek_address(saturn_cpu_t *saturn, uint32_t saddr)
{
return saturn_peek(saturn, saddr, 5);
}
static int
hxs2real(int hxs)
{
int n = 0, c = 1;
while (hxs) {
n += (hxs & 0xf) * c;
c *= 10;
hxs >>= 4;
}
return n;
}
typedef struct {
uint32_t x;
uint32_t ml;
uint32_t mh;
uint8_t m;
uint8_t s;
} hp_real_t;
static char *
real_number(saturn_cpu_t *saturn, uint32_t saddr, char *buffer, int ml, int xl)
{
char *p = buffer;
char fmt[20];
char m[16];
hp_real_t r;
int re, xs;
int i;
uint32_t pc;
pc = saddr;
/*
* Read the number
*/
r.x = saturn_peek(saturn, pc, xl);
pc += xl;
r.ml = saturn_peek(saturn, pc, ml - 8);
pc += ml - 8;
r.mh = saturn_peek(saturn, pc, 8);
pc += 8;
r.m = saturn_peek(saturn, pc, 1);
pc += 1;
r.s = saturn_peek(saturn, pc, 1);
pc += 1;
/*
* Figure out the exponent
*/
xs = 5;
while (--xl)
xs *= 10;
re = hxs2real(r.x);
if (re >= xs)
re = re - 2 * xs;
if ((re >= 0) && (re < ml + 1)) {
if (r.s >= 5)
*p++ = '-';
sprintf(fmt, "%%.1X%%.8X%%.%dX", ml - 8);
sprintf(m, fmt, r.m, r.mh, r.ml);
for (i = 0; i <= re; i++)
*p++ = m[i];
*p++ = '.';
for ( ; i < ml + 1; i++)
*p++ = m[i];
p--;
while(*p == '0')
p--;
if (*p == '.')
p--;
*++p = '\0';
return buffer;
}
if ((re < 0) && (re >= -ml - 1)) {
sprintf(fmt, "%%.1X%%.8X%%.%dX", ml - 8);
sprintf(m, fmt, r.m, r.mh, r.ml);
for (i = ml; m[i] == '0'; i--)
;
if (-re <= ml - i + 1) {
if (r.s >= 5)
*p++ = '-';
*p++ = '.';
for (i = 1; i < -re; i++)
*p++ = '0';
for (i = 0; i < ml + 1; i++)
*p++ = m[i];
p--;
while(*p == '0')
p--;
*++p = '\0';
return buffer;
}
}
sprintf(fmt, "%%s%%X.%%.8X%%.%dX", ml - 8);
sprintf(p, fmt, (r.s >= 5) ? "-" : "", r.m, r.mh, r.ml);
p += strlen(p) - 1;
while(*p == '0')
p--;
*++p = '\0';
if (re) {
sprintf(p, "E%d", re);
p += strlen(p);
*p = '\0';
}
return buffer;
}
static uint32_t
dump_object(x49gp_t *x49gp, x49gp_sram_t *sram, uint32_t saddr)
{
saturn_cpu_t *saturn = (sram->data + 0x3340);
char buffer[128];
uint32_t prolog, pc;
char c;
int i, n;
pc = saddr;
prolog = saturn_peek(saturn, pc, 5);
pc += 5;
switch (prolog) {
case 0x02e48:
case 0x02e6d:
printf(" ");
n = saturn_peek(saturn, pc, 2);
pc += 2;
for (i = 0; i < n; i++) {
c = saturn_peek(saturn, pc, 2);
printf("%c", c);
pc += 2;
}
break;
case 0x02a4e:
n = saturn_peek(saturn, pc, 5);
pc += 5;
if (n <= 16) {
printf(" #%08x%08xh", saturn_peek(saturn, pc + 8, 8),
saturn_peek(saturn, pc + 0, 8));
} else {
printf(" C#");
for (i = 0; i < n; i++) {
printf("%x", saturn_peek(saturn, pc + i, 1));
}
}
pc += n;
break;
case 0x02911:
printf(" <%05x>", saturn_peek(saturn, pc, 5));
pc += 5;
break;
case 0x02933:
printf(" %%%s", real_number(saturn, pc, buffer, 11, 3));
pc += 16;
break;
case 0x02955:
printf(" %%%%%s", real_number(saturn, pc, buffer, 14, 5));
pc += 21;
break;
case 0x02e92:
printf(" <%03x %03x>", saturn_peek(saturn, pc + 0, 3),
saturn_peek(saturn, pc + 3, 3));
pc += 6;
break;
case 0x026ac:
printf(" <%03x %04x>", saturn_peek(saturn, pc + 0, 3),
saturn_peek(saturn, pc + 3, 4));
pc += 7;
break;
case 0x02ab8:
printf(" '");
while (1) {
prolog = saturn_peek(saturn, pc, 5);
if (prolog == 0x0312b) {
pc += 5;
break;
}
pc += dump_object(x49gp, sram, pc);
}
printf(" '");
break;
case 0x02d9d:
printf(" :");
while (1) {
prolog = saturn_peek(saturn, pc, 5);
if (prolog == 0x0312b) {
pc += 5;
break;
}
pc += dump_object(x49gp, sram, pc);
}
printf(" ;");
break;
default:
printf(" %05x", prolog);
break;
}
return pc - saddr;
}
static void
debug_saturn(x49gp_t *x49gp, x49gp_sram_t *sram)
{
saturn_cpu_t *saturn = (sram->data + 0x3340);
uint32_t sp, se;
uint32_t prolog;
uint32_t rsp;
uint32_t first;
static uint32_t prev_first = 0;
static int state = 0;
int depth;
int i;
// printf("SATURN: %p, RPLTOP: %08x\n", saturn, saturn_map_s2a(saturn, SAT_RPLTOP));
// printf("SATURN: %p, RSKTOP: %08x\n", saturn, saturn_map_s2a(saturn, SAT_RSKTOP));
// rpltop = saturn_peek_address(saturn, SAT_RPLTOP);
// printf("SATURN: RPLTOP: %05x\n", rpltop);
rsp = saturn_peek_address(saturn, SAT_RSKTOP);
if (rsp == 0)
return;
first = saturn_peek_address(saturn, rsp - 5);
if (first == prev_first) {
return;
}
prev_first = first;
if (first == (BASE + 0x14a54)) {
state = 1;
}
if (state == 0)
return;
printf("SATURN: %p, rsp: %05x %08x\n", saturn, rsp, saturn_map_s2a(saturn, rsp));
for (i = 0; ; i++) {
rsp -= 5;
se = saturn_peek_address(saturn, rsp);
if (se == 0)
break;
if (se > BASE)
printf("SATURN: RSTK %02u: %05x <%05x>\n", i, se, se - BASE);
else
printf("SATURN: RSTK %02u: %05x\n", i, se);
}
depth = (saturn_peek_address(saturn, SAT_EDITLINE) - saturn_peek_address(saturn, SAT_DSKTOP) - 5) / 5;
printf("SATURN: depth %d\n", depth);
sp = saturn_peek_address(saturn, SAT_EDITLINE) - 10;
for (i = 0; i < depth; i++) {
se = saturn_peek_address(saturn, sp);
sp -= 5;
prolog = saturn_peek(saturn, se, 5);
printf("SATURN: %02u: <%05x> <%05x>", depth - i, se, prolog);
dump_object(x49gp, sram, se);
printf("\n");
}
}
static uint32_t
sram_get_word(void *opaque, target_phys_addr_t offset)
{
x49gp_sram_t *sram = opaque;
uint32_t data;
#ifdef QEMU_OLD
offset -= S3C2410_SRAM_BASE;
#endif
data = ldl_p(sram->data + offset);
#if 0
if (offset == 0x00000a1c) {
printf("read SRAM at offset %08x: %08x (pc %08x)\n", offset, data, x49gp->arm->Reg[15]);
}
#endif
#ifdef DEBUG_X49GP_SYSRAM_READ
if ((offset & ~(0x0001ffff)) == 0x00000000) {
printf("read SRAM 4 at offset %08x: %08x\n", offset, data);
}
#endif
#ifdef DEBUG_X49GP_ERAM_READ
if ((offset & ~(0x0001ffff)) == 0x00020000) {
printf("read SRAM 4 at offset %08x: %08x\n", offset, data);
}
#endif
#ifdef DEBUG_X49GP_IRAM_READ
if ((offset & ~(0x0003ffff)) == 0x00040000) {
printf("read SRAM 4 at offset %08x: %08x\n", offset, data);
}
#endif
return data;
}
static uint32_t
sram_get_halfword(void *opaque, target_phys_addr_t offset)
{
x49gp_sram_t *sram = opaque;
unsigned short data;
#ifdef QEMU_OLD
offset -= S3C2410_SRAM_BASE;
#endif
data = lduw_p(sram->data + offset);
#ifdef DEBUG_X49GP_SYSRAM_READ
if ((offset & ~(0x0001ffff)) == 0x00000000) {
printf("read SRAM 2 at offset %08x: %04x\n", offset, data);
}
#endif
#ifdef DEBUG_X49GP_ERAM_READ
if ((offset & ~(0x0001ffff)) == 0x00020000) {
printf("read SRAM 2 at offset %08x: %04x\n", offset, data);
}
#endif
#ifdef DEBUG_X49GP_IRAM_READ
if ((offset & ~(0x0003ffff)) == 0x00040000) {
printf("read SRAM 2 at offset %08x: %04x\n", offset, data);
}
#endif
return data;
}
static uint32_t
sram_get_byte(void *opaque, target_phys_addr_t offset)
{
x49gp_sram_t *sram = opaque;
unsigned char data;
#ifdef QEMU_OLD
offset -= S3C2410_SRAM_BASE;
#endif
data = ldub_p(sram->data + offset);
#ifdef DEBUG_X49GP_SYSRAM_READ
if ((offset & ~(0x0001ffff)) == 0x00000000) {
printf("read SRAM 1 at offset %08x: %02x\n", offset, data);
}
#endif
#ifdef DEBUG_X49GP_ERAM_READ
if ((offset & ~(0x0001ffff)) == 0x00020000) {
printf("read SRAM 1 at offset %08x: %02x\n", offset, data);
}
#endif
#ifdef DEBUG_X49GP_IRAM_READ
if ((offset & ~(0x0003ffff)) == 0x00040000) {
printf("read SRAM 1 at offset %08x: %02x\n", offset, data);
}
#endif
return data;
}
static void
sram_put_word(void *opaque, target_phys_addr_t offset, uint32_t data)
{
x49gp_sram_t *sram = opaque;
#ifdef QEMU_OLD
// offset -= S3C2410_SRAM_BASE;
offset -= (target_phys_addr_t)phys_ram_base + sram->offset;
#endif
if (offset == 0x00000a1c) {
printf("write SRAM 4 at offset %08x: %08x (pc %08x)\n",
offset, data, sram->x49gp->env->regs[15]);
}
debug_saturn(sram->x49gp, sram);
#if 0
if (offset == 0x3340 + SATURN(D1)) {
printf("write D1 at offset %08x: %08x (pc %08x)\n",
offset, data, sram->x49gp->env->regs[15]);
}
if (offset == 0x3340 + SATURN(A)) {
printf("write A at offset %08x: %08x (pc %08x)\n",
offset, data, sram->x49gp->env->regs[15]);
}
if (offset == 0x3340 + SATURN(A) + 8) {
printf("write Al at offset %08x: %08x (pc %08x)\n",
offset, data, sram->x49gp->env->regs[15]);
}
#endif
#ifdef DEBUG_X49GP_SYSRAM_WRITE
if ((offset & ~(0x0001ffff)) == 0x00000000) {
printf("write SRAM 4 at offset %08x: %08x\n", offset, data);
}
#endif
#ifdef DEBUG_X49GP_ERAM_WRITE
if ((offset & ~(0x0001ffff)) == 0x00020000) {
printf("write SRAM 4 at offset %08x: %08x\n", offset, data);
}
#endif
#ifdef DEBUG_X49GP_IRAM_WRITE
if ((offset & ~(0x0003ffff)) == 0x00040000) {
printf("write SRAM 4 at offset %08x: %08x\n", offset, data);
}
#endif
stl_p(sram->data + offset, data);
}
static void
sram_put_halfword(void *opaque, target_phys_addr_t offset, uint32_t data)
{
x49gp_sram_t *sram = opaque;
#ifdef QEMU_OLD
// offset -= S3C2410_SRAM_BASE;
offset -= (target_phys_addr_t)phys_ram_base + sram->offset;
#endif
data &= 0xffff;
#ifdef DEBUG_X49GP_SYSRAM_WRITE
if ((offset & ~(0x0001ffff)) == 0x00000000) {
printf("write SRAM 2 at offset %08x: %04x\n", offset, data);
}
#endif
#ifdef DEBUG_X49GP_ERAM_WRITE
if ((offset & ~(0x0001ffff)) == 0x00020000) {
printf("write SRAM 2 at offset %08x: %04x\n", offset, data);
}
#endif
#ifdef DEBUG_X49GP_IRAM_WRITE
if ((offset & ~(0x0003ffff)) == 0x00040000) {
printf("write SRAM 2 at offset %08x: %04x\n", offset, data);
}
#endif
stw_p(sram->data + offset, data);
}
static void
sram_put_byte(void *opaque, target_phys_addr_t offset, uint32_t data)
{
x49gp_sram_t *sram = opaque;
#ifdef QEMU_OLD
// offset -= S3C2410_SRAM_BASE;
offset -= (target_phys_addr_t)phys_ram_base + sram->offset;
#endif
data &= 0xff;
#ifdef DEBUG_X49GP_SYSRAM_WRITE
if ((offset & ~(0x0001ffff)) == 0x00000000) {
printf("write SRAM 1 at offset %08x: %02x\n", offset, data);
}
#endif
#ifdef DEBUG_X49GP_ERAM_WRITE
if ((offset & ~(0x0001ffff)) == 0x00020000) {
printf("write SRAM 1 at offset %08x: %02x\n", offset, data);
}
#endif
#ifdef DEBUG_X49GP_IRAM_WRITE
if ((offset & ~(0x0003ffff)) == 0x00040000) {
printf("write SRAM 1 at offset %08x: %02x\n", offset, data);
}
#endif
stb_p(sram->data + offset, data);
}
static CPUReadMemoryFunc *sram_readfn[] =
{
sram_get_byte,
sram_get_halfword,
sram_get_word
};
static CPUWriteMemoryFunc *sram_writefn[] =
{
sram_put_byte,
sram_put_halfword,
sram_put_word
};
static int
sram_load(x49gp_module_t *module, GKeyFile *key)
{
x49gp_sram_t *sram = module->user_data;
char *filename;
int error;
#ifdef DEBUG_X49GP_MODULES
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
#endif
filename = x49gp_module_get_filename(module, key, "filename");
if (NULL == filename) {
fprintf(stderr, "%s: %s:%u: key \"filename\" not found\n",
module->name, __FUNCTION__, __LINE__);
return -ENOENT;
}
sram->fd = open(filename, O_RDWR);
if (sram->fd < 0) {
error = -errno;
fprintf(stderr, "%s: %s:%u: open %s: %s\n",
module->name, __FUNCTION__, __LINE__,
filename, strerror(errno));
g_free(filename);
return error;
}
sram->size = 0x00080000;
sram->data = mmap(phys_ram_base + sram->offset, sram->size,
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED,
sram->fd, 0);
if (sram->data == (void *) -1) {
error = -errno;
fprintf(stderr, "%s: %s:%u: mmap %s: %s\n",
module->name, __FUNCTION__, __LINE__,
filename, strerror(errno));
g_free(filename);
close(sram->fd);
sram->fd = -1;
return error;
}
sram->shadow = mmap(phys_ram_base + sram->offset + sram->size,
sram->size,
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED,
sram->fd, 0);
if (sram->shadow == (void *) -1) {
error = -errno;
fprintf(stderr, "%s: %s:%u: mmap %s (shadow): %s\n",
module->name, __FUNCTION__, __LINE__,
filename, strerror(errno));
g_free(filename);
close(sram->fd);
sram->fd = -1;
return error;
}
sram->x49gp->sram = phys_ram_base + sram->offset;
g_free(filename);
return 0;
}
static int
sram_save(x49gp_module_t *module, GKeyFile *key)
{
x49gp_sram_t *sram = module->user_data;
int error;
#ifdef DEBUG_X49GP_MODULES
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
#endif
error = msync(sram->data, sram->size, MS_ASYNC);
if (error) {
fprintf(stderr, "%s:%u: msync: %s\n",
__FUNCTION__, __LINE__, strerror(errno));
return error;
}
error = fsync(sram->fd);
if (error) {
fprintf(stderr, "%s:%u: fsync: %s\n",
__FUNCTION__, __LINE__, strerror(errno));
return error;
}
return 0;
}
static int
sram_reset(x49gp_module_t *module, x49gp_reset_t reset)
{
#ifdef DEBUG_X49GP_MODULES
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
#endif
return 0;
}
static int
sram_init(x49gp_module_t *module)
{
x49gp_sram_t *sram;
#ifdef DEBUG_X49GP_MODULES
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
#endif
sram = malloc(sizeof(x49gp_sram_t));
if (NULL == sram) {
fprintf(stderr, "%s:%u: Out of memory\n",
__FUNCTION__, __LINE__);
return -ENOMEM;
}
memset(sram, 0, sizeof(x49gp_sram_t));
sram->fd = -1;
module->user_data = sram;
sram->x49gp = module->x49gp;
sram->data = (void *) -1;
sram->shadow = (void *) -1;
sram->offset = phys_ram_size;
phys_ram_size += S3C2410_SRAM_SIZE;
phys_ram_size += S3C2410_SRAM_SIZE;
#if 0
{
int iotype;
iotype = cpu_register_io_memory(0, sram_readfn, sram_writefn, sram);
printf("%s: iotype %08x\n", __FUNCTION__, iotype);
cpu_register_physical_memory(S3C2410_SRAM_BASE,
S3C2410_SRAM_SIZE,
sram->offset | iotype | IO_MEM_ROMD);
iotype = cpu_register_io_memory(0, sram_readfn, sram_writefn, sram);
printf("%s: iotype %08x\n", __FUNCTION__, iotype);
cpu_register_physical_memory(S3C2410_SRAM_BASE + S3C2410_SRAM_SIZE,
S3C2410_SRAM_SIZE,
(sram->offset + S3C2410_SRAM_SIZE) | iotype | IO_MEM_ROMD);
}
#else
cpu_register_physical_memory(S3C2410_SRAM_BASE, S3C2410_SRAM_SIZE,
sram->offset | IO_MEM_RAM);
cpu_register_physical_memory(S3C2410_SRAM_BASE + S3C2410_SRAM_SIZE,
S3C2410_SRAM_SIZE,
(sram->offset + S3C2410_SRAM_SIZE) | IO_MEM_RAM);
#endif
return 0;
}
static int
sram_exit(x49gp_module_t *module)
{
x49gp_sram_t *sram;
#ifdef DEBUG_X49GP_MODULES
printf("%s: %s:%u\n", module->name, __FUNCTION__, __LINE__);
#endif
if (module->user_data) {
sram = module->user_data;
if (sram->shadow != (void *) -1) {
munmap(sram->shadow, sram->size);
}
if (sram->data != (void *) -1) {
munmap(sram->data, sram->size);
}
if (sram->fd >= 0) {
close(sram->fd);
}
free(sram);
}
x49gp_module_unregister(module);
free(module);
return 0;
}
int
x49gp_sram_init(x49gp_t *x49gp)
{
x49gp_module_t *module;
if (x49gp_module_init(x49gp, "sram", sram_init, sram_exit,
sram_reset, sram_load, sram_save, NULL,
&module)) {
return -1;
}
return x49gp_module_register(module);
}