/*
* This file is part of SIS.
*
* SIS, SPARC instruction simulator V2.5 Copyright (C) 1995 Jiri Gaisler,
* European Space Agency
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, see <http://www.gnu.org/licenses/>.
*
* Leon3 emulation, loosely based on erc32.c.
*/
#define ROM_START 0x00000000
#define ROM_SIZE 0x01000000
#define RAM_START 0x40000000
#define RAM_SIZE 0x04000000
#include "config.h"
#include <errno.h>
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#ifdef HAVE_TERMIOS_H
#include <termios.h>
#endif
#include <sys/file.h>
#include <unistd.h>
#include "sis.h"
#include "grlib.h"
/* APB registers */
#define APBSTART 0x80000000
/* Memory exception waitstates. */
#define MEM_EX_WS 1
/* Forward declarations. */
static char *get_mem_ptr (uint32 addr, uint32 size);
/* One-time init. */
static void
init_sim (void)
{
int i;
/* Use extended interrupt line of GR712RC by default */
if (irqmp_extirq < 0)
irqmp_extirq = 12;
for (i = 0; i < ncpu; i++)
grlib_ahbm_add (&leon3s, 0);
grlib_ahbs_add (&apbmst, 0, APBSTART, 0xFFF);
grlib_ahbs_add (&sdctrl, 0, RAM_START, RAM_MASKPP);
grlib_ahbs_add (&dsu, 0, 0x90000000, 0xFFF);
grlib_apb_add (&apbuart, 3, APBSTART + 0x100, 0xFFF);
grlib_apb_add (&irqmp, 0, APBSTART + 0x200, 0xFFF);
grlib_apb_add (&gptimer, 8, APBSTART + 0x300, 0xFFF);
grlib_apb_add (&greth, 6, APBSTART + 0xB00, 0xFFF);
grlib_init ();
ebase.ramstart = RAM_START;
}
/* Power-on reset init. */
static void
reset (void)
{
grlib_reset ();
}
/* IU error mode manager. */
static void
error_mode (uint32 pc)
{
}
/* Flush ports when simulator stops. */
static void
sim_halt (void)
{
#ifdef FAST_UART
apbuart_flush ();
#endif
}
static void
exit_sim (void)
{
apbuart_close_port ();
}
/* Memory emulation. */
static int
memory_read (uint32 addr, uint32 * data, int32 * ws)
{
int32 mexc;
*ws = 0;
if ((addr >= RAM_START) && (addr < RAM_END))
{
memcpy (data, &ramb[addr & RAM_MASK], 4);
return 0;
}
else if ((addr >= ROM_START) && (addr < ROM_END))
{
memcpy (data, &romb[addr & ROM_MASK], 4);
*ws = 2;
return 0;
}
else
{
mexc = grlib_read (addr, data);
*ws = 4;
}
if (sis_verbose && mexc)
{
printf ("Memory exception at %x (illegal address)\n", addr);
*ws = MEM_EX_WS;
}
return mexc;
}
static int
memory_write (uint32 addr, uint32 * data, int32 sz, int32 * ws)
{
uint32 waddr;
int32 mexc;
*ws = 0;
if ((addr >= RAM_START) && (addr < RAM_END))
{
waddr = addr & RAM_MASK;
grlib_store_bytes (ramb, waddr, data, sz);
return 0;
}
else if ((addr >= ROM_START) && (addr < ROM_END))
{
grlib_store_bytes (romb, addr, data, sz);
return 0;
}
else
{
mexc = grlib_write (addr, data, sz);
*ws = 4;
}
if (sis_verbose && mexc)
{
printf ("Memory exception at %x (illegal address)\n", addr);
*ws = MEM_EX_WS;
}
return mexc;
}
static char *
get_mem_ptr (uint32 addr, uint32 size)
{
if ((addr >= RAM_START) && ((addr + size) < RAM_END))
{
return &ramb[addr & RAM_MASK];
}
else if ((addr >= ROM_START) && ((addr + size) < ROM_END))
{
return &romb[addr & ROM_MASK];
}
return NULL;
}
static int
sis_memory_write (uint32 addr, const char *data, uint32 length)
{
char *mem;
int32 ws;
if ((mem = get_mem_ptr (addr, length)) != NULL)
{
memcpy (mem, data, length);
return length;
}
else if (length == 4)
memory_write (addr, (uint32 *) data, 2, &ws);
return 0;
}
static int
sis_memory_read (uint32 addr, char *data, uint32 length)
{
char *mem;
int ws;
if (length == 4)
{
memory_read (addr, (uint32 *) data, &ws);
return 4;
}
if ((mem = get_mem_ptr (addr, length)) == NULL)
return 0;
memcpy (data, mem, length);
return length;
}
static void
boot_init (void)
{
int i;
grlib_boot_init ();
for (i = 0; i < NCPU; i++)
{
sregs[i].wim = 2;
sregs[i].psr = 0xF30010e0;
sregs[i].r[30] = RAM_END - (i * 0x20000);
sregs[i].r[14] = sregs[i].r[30] - 96 * 4;
sregs[i].cache_ctrl = 0x81000f;
sregs[i].r[2] = sregs[i].r[30]; /* sp on RISCV-V */
}
}
const struct memsys leon3 = {
init_sim,
reset,
error_mode,
sim_halt,
exit_sim,
apbuart_init_stdio,
apbuart_restore_stdio,
memory_read,
memory_read,
memory_write,
sis_memory_write,
sis_memory_read,
boot_init,
get_mem_ptr,
grlib_set_irq
};