diff options
-rw-r--r-- | sim/erc32/ChangeLog | 30 | ||||
-rw-r--r-- | sim/erc32/erc32.c | 1495 | ||||
-rw-r--r-- | sim/erc32/interf.c | 56 | ||||
-rw-r--r-- | sim/erc32/sis.h | 145 |
4 files changed, 1725 insertions, 1 deletions
diff --git a/sim/erc32/ChangeLog b/sim/erc32/ChangeLog index 6112350..27e8d8b 100644 --- a/sim/erc32/ChangeLog +++ b/sim/erc32/ChangeLog @@ -1,3 +1,33 @@ +Wed Jul 3 16:05:23 1996 Stu Grossman (grossman@critters.cygnus.com) + + * erc32.c (mec_reset mec_read mec_write memory_read memory_write), + sis.h: Get rid of all uses of long long's. + * (close_port read_uart write_uart uarta_tx): Don't seg fault + when can't open pty's. + * exec.c: Add two new instructions: smul, and divscc. + * interf.c (flush_windows): New routine to flush the register + windows out to the stack just before returning to GDB. Makes + backtraces work much better. + +Wed Jun 26 12:19:11 1996 Jason Molenda (crash@godzilla.cygnus.co.jp) + + * Makefile.in (bindir, libdir, datadir, mandir, infodir, includedir, + INSTALL_PROGRAM, INSTALL_DATA): Use autoconf-set values. + (docdir, oldincludedir): Removed. + * configure.in (AC_PREREQ): autoconf 2.5 or higher. + (AC_PROG_INSTALL): Added. + * configure: Rebuilt. + +Mon Jun 24 14:19:07 1996 Ian Lance Taylor <ian@cygnus.com> + + * configure.in: Call AC_PROG_CC before running configure.host. + * configure: Rebuild with autoconf 2.10. + +Tue Jun 4 10:37:12 1996 Tom Tromey <tromey@csk3.cygnus.com> + + * Makefile.in (install): Don't check to see if tooldir exists. + Make $(tooldir) and $(tooldir)/bin. + Mon Jun 3 12:33:38 1996 Ian Lance Taylor <ian@cygnus.com> * Makefile.in (end.h): Use explicit ./ when running end. diff --git a/sim/erc32/erc32.c b/sim/erc32/erc32.c new file mode 100644 index 0000000..2b0b370 --- /dev/null +++ b/sim/erc32/erc32.c @@ -0,0 +1,1495 @@ +/* + * This file is part of SIS. + * + * SIS, SPARC instruction simulator V1.8 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 2 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, write to the Free Software Foundation, Inc., 675 + * Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* The control space devices */ + +#include <sys/types.h> +#include <stdio.h> +#include <sys/ioctl.h> +#include <sys/fcntl.h> +#include <sys/file.h> +#include "sis.h" +#include "end.h" + +extern int32 sis_verbose; +extern int mecrev0; +extern char uart_dev1[], uart_dev2[]; + +#define MEC_WS 0 /* Waitstates per MEC access (0 ws) */ +#define MOK 0 + +/* MEC register addresses */ + +#define MEC_UARTA 0x0E0 +#define MEC_UARTB 0x0E4 +#define MEC_UART_CTRL 0x0E8 +#define MEC_TIMER_CTRL 0x098 +#define MEC_RTC_COUNTER 0x080 +#define MEC_RTC_RELOAD 0x080 +#define MEC_RTC_SCALER 0x084 +#define MEC_GPT_COUNTER 0x088 +#define MEC_GPT_RELOAD 0x088 +#define MEC_GPT_SCALER 0x08C +#define MEC_DBG 0x0C0 +#define MEC_BRK 0x0C4 +#define MEC_WPR 0x0C8 +#define MEC_SFSR 0x0A0 +#define MEC_FFAR 0x0A4 +#define MEC_IPR 0x048 +#define MEC_IMR 0x04C +#define MEC_ICR 0x050 +#define MEC_IFR 0x054 +#define MEC_MCR 0x000 +#define MEC_MEMCFG 0x010 +#define MEC_WCR 0x018 +#define MEC_MAR0 0x020 +#define MEC_MAR1 0x024 +#define MEC_SFR 0x004 +#define MEC_WDOG 0x060 +#define MEC_TRAPD 0x064 +#define MEC_PWDR 0x008 +#define SIM_LOAD 0x0F0 + +/* Memory exception causes */ +#define PROT_EXC 0x3 +#define UIMP_ACC 0x4 +#define MEC_ACC 0x6 +#define WATCH_EXC 0xa +#define BREAK_EXC 0xb + +/* Size of UART buffers (bytes) */ +#define UARTBUF 1024 + +/* Number of simulator ticks between flushing the UARTS. */ +/* For good performance, keep above 1000 */ +#define UART_FLUSH_TIME 3000 + +/* MEC timer control register bits */ +#define TCR_GACR 1 +#define TCR_GACL 2 +#define TCR_GASE 4 +#define TCR_GASL 8 +#define TCR_TCRCR 0x100 +#define TCR_TCRCL 0x200 +#define TCR_TCRSE 0x400 +#define TCR_TCRSL 0x800 + +/* New uart defines */ +#define UART_TX_TIME 1000 +#define UART_RX_TIME 1000 +#define UARTA_DR 0x1 +#define UARTA_SRE 0x2 +#define UARTA_HRE 0x4 +#define UARTA_OR 0x40 +#define UARTA_CLR 0x80 +#define UARTB_DR 0x10000 +#define UARTB_SRE 0x20000 +#define UARTB_HRE 0x40000 +#define UARTB_OR 0x400000 +#define UARTB_CLR 0x800000 + +#define UART_DR 0x100 +#define UART_TSE 0x200 +#define UART_THE 0x400 + +/* MEC registers */ + +static char fname[256]; +static uint32 find = 0; +static char simfn[] = "simload"; +static uint32 brk_point = 0; +static uint32 watch_point = 0; +static uint32 mec_dbg = 0; +static uint32 mec_sfsr = 0x078; +static uint32 mec_ffar = 0; +static uint32 mec_ipr = 0; +static uint32 mec_imr = 0x3fff; +static uint32 mec_icr = 0; +static uint32 mec_ifr = 0; +static uint32 mec_mcr; /* MEC control register */ +static uint32 mec_memcfg; /* Memory control register */ +static uint32 mec_wcr; /* MEC waitstate register */ +static uint32 mec_mar0; /* MEC access registers (2) */ +static uint32 mec_mar1; /* MEC access registers (2) */ +static uint32 mec_regs[64]; +static uint32 posted_irq; +static uint32 mec_ersr = 0; /* MEC error and status register */ +static uint32 mec_emr = 0x60; /* MEC error mask register */ +static uint32 mec_tcr = 0; /* MEC test comtrol register */ + +static uint32 rtc_counter = 0xffffffff; +static uint32 rtc_reload = 0xffffffff; +static uint32 rtc_scaler = 0xff; +static uint32 rtc_enabled = 0; +static uint32 rtc_cr = 0; +static uint32 rtc_se = 0; +static uint32 rtc_cont = 0; + +static uint32 gpt_counter = 0xffffffff; +static uint32 gpt_reload = 0xffffffff; +static uint32 gpt_scaler = 0xffff; +static uint32 gpt_enabled = 0; +static uint32 gpt_cr = 0; +static uint32 gpt_se = 0; +static uint32 gpt_cont = 0; + +static uint32 wdog_scaler; +static uint32 wdog_counter; +static uint32 wdog_rst_delay; +static uint32 wdog_rston; + +#ifdef MECREV0 +static uint32 gpt_irqon = 1; +static uint32 rtc_irqon = 1; +#endif + +enum wdog_type { + init, disabled, enabled, stopped +}; + +static enum wdog_type wdog_status; + +/* Memory support variables */ + +static uint32 mem_ramr_ws; /* RAM read waitstates */ +static uint32 mem_ramw_ws; /* RAM write waitstates */ +static uint32 mem_romr_ws; /* ROM read waitstates */ +static uint32 mem_romw_ws; /* ROM write waitstates */ +static uint32 mem_ramsz; /* RAM size */ +static uint32 mem_romsz; /* RAM size */ +static uint32 mem_banksz; /* RAM bank size */ +static uint32 mem_accprot; /* RAM write protection enabled */ + +/* UART support variables */ + +static unsigned char Adata, Bdata; +static int32 fd1, fd2; /* file descriptor for input file */ +static int32 Ucontrol; /* UART status register */ +static unsigned char aq[UARTBUF], bq[UARTBUF]; +static int32 res; +static int32 anum, aind = 0; +static int32 bnum, bind = 0; +static char wbufa[UARTBUF], wbufb[UARTBUF]; +static unsigned wnuma; +static unsigned wnumb; +static FILE *f1 = NULL, *f2 = NULL; + +static char uarta_sreg, uarta_hreg, uartb_sreg, uartb_hreg; +static uint32 uart_stat_reg; +static uint32 uarta_data, uartb_data; + +void uarta_tx(); +void uartb_tx(); +uint32 read_uart(); +void write_uart(); +uint32 rtc_counter_read(); +void rtc_scaler_set(); +void rtc_reload_set(); +uint32 gpt_counter_read(); +void gpt_scaler_set(); +void gpt_reload_set(); +void timer_ctrl(); +void port_init(); +void uart_irq_start(); +void mec_reset(); +void wdog_start(); + + +/* One-time init */ + +void +init_sim() +{ + port_init(); +} + +/* Power-on reset init */ + +void +reset() +{ + mec_reset(); + uart_irq_start(); + wdog_start(); +} + +/* IU error mode manager */ + +int +error_mode(pc) + uint32 pc; +{ + + if ((mec_emr & 0x1) == 0) { + if (mec_mcr & 0x20) { + sys_reset(); + mec_ersr = 0x8000; + printf("Error manager reset - IU in error mode at 0x%08x\n", pc); + } + } +} + +/* Check memory settings */ + +void +decode_memcfg() +{ + mem_ramsz = (256 * 1024) << ((mec_memcfg >> 10) & 7); + mem_banksz = ((mec_memcfg >> 10) & 7) + 18 - 6; + mem_romsz = (4 * 1024) << ((mec_memcfg >> 18) & 7); + if (sis_verbose) + printf("RAM size: %d K, ROM size: %d K, protection bank size: %d K\n", + mem_ramsz >> 10, mem_romsz >> 10, 1 << mem_banksz); +} + +void +decode_wcr() +{ + mem_ramr_ws = mec_wcr & 3; + mem_ramw_ws = (mec_wcr >> 2) & 3; + mem_romr_ws = (mec_wcr >> 4) & 0x0f; + mem_romw_ws = (mec_wcr >> 8) & 0x0f; + if (sis_verbose) + printf("Waitstates = RAM read: %d, RAM write: %d, ROM read: %d, ROM write: %d\n", + mem_ramr_ws, mem_ramw_ws, mem_romr_ws, mem_romw_ws); +} + +void +decode_mcr() +{ + mem_accprot = (mec_mcr >> 3) & 1; + if (sis_verbose && mem_accprot) + printf("Memory access protection enabled\n"); + if (sis_verbose && (mec_mcr & 2)) + printf("Software reset enabled\n"); + if (sis_verbose && (mec_mcr & 1)) + printf("Power-down mode enabled\n"); +} + +/* Flush ports when simulator stops */ + +void +sim_stop() +{ +#ifdef FAST_UART + flush_uart(); +#endif +} + +void +close_port() +{ + if (f1) + fclose(f1); + if (f2) + fclose(f2); +} + +void +exit_sim() +{ + close_port(); +} + +void +mec_reset() +{ + + find = 0; + brk_point = 0; + watch_point = 0; + mec_dbg = 0; + mec_sfsr = 0x078; + mec_ffar = 0; + mec_ipr = 0; + mec_imr = 0x3fff; + mec_icr = 0; + mec_ifr = 0; + mec_memcfg = 0x10000; + mec_mcr = 0x01b50014; + mec_wcr = -1; + mec_mar0 = -1; + mec_mar1 = -1; + mec_ersr = 0; /* MEC error and status register */ + mec_emr = 0x60; /* MEC error mask register */ + mec_tcr = 0; /* MEC test comtrol register */ + + decode_memcfg(); + decode_wcr(); + decode_mcr(); + + posted_irq = 0; + wnuma = wnumb = 0; + anum = aind = bnum = bind = 0; + + uart_stat_reg = UARTA_SRE | UARTA_HRE | UARTB_SRE | UARTB_HRE; + uarta_data = uartb_data = UART_THE | UART_TSE; + + rtc_counter = 0xffffffff; + rtc_reload = 0xffffffff; + rtc_scaler = 0xff; + rtc_enabled = 0; + rtc_cr = 0; + rtc_se = 0; + rtc_cont = 0; + + gpt_counter = 0xffffffff; + gpt_reload = 0xffffffff; + gpt_scaler = 0xffff; + gpt_enabled = 0; + gpt_cr = 0; + gpt_se = 0; + gpt_cont = 0; + + wdog_scaler = 255; + wdog_rst_delay = 255; + wdog_counter = 0xffff; + wdog_rston = 0; + wdog_status = init; + +#ifdef MECREV0 + gpt_irqon = 1; + rtc_irqon = 1; +#endif + +} + + + +int32 +mec_intack(level) + int32 level; +{ + int irq_test; + + if (sis_verbose) + printf("interrupt %d acknowledged\n",level); + irq_test = mec_tcr & 0x80000; + if ((irq_test) && (mec_ifr & (1 << level))) + mec_ifr &= ~(1 << level); + else + mec_ipr &= ~(1 << level); + posted_irq &= ~(1 << level); +#ifdef MECREV0 + if (mecrev0) { + if (uart_stat_reg & 1) + mec_ipr |= (1 << 4); + if (uart_stat_reg & 0x100) + mec_ipr |= (1 << 5); + } +#endif +} + +int32 +chk_irq() +{ + int32 i; + uint32 itmp; + + itmp = ((mec_ipr | mec_ifr) & ~mec_imr) & 0x0fffe; + if (itmp != 0) { + for (i = 15; i > 0; i--) { + if (((itmp >> i) & 1) != 0) { + if ((posted_irq & (1 << i)) == 0) { + if (sis_verbose) + printf("interrupt %d generated\n",i); + set_int(i, mec_intack, i); + posted_irq |= (1 << i); + } + } + } + } +} + +void +mec_irq(level) + int32 level; +{ + mec_ipr |= (1 << level); + chk_irq(); +} + +void +set_sfsr(fault, addr, asi, read) + uint32 fault; + uint32 addr; + uint32 asi; + uint32 read; +{ + mec_ffar = addr; + mec_sfsr = (fault << 3) | (!read << 15); + switch (asi) { + case 8: + mec_sfsr |= 0x2002; + break; + case 9: + mec_sfsr |= 0x3002; + break; + case 0xa: + mec_sfsr |= 0x0004; + break; + case 0xb: + mec_sfsr |= 0x1004; + break; + } +} + +int32 +chk_brk(addr, asi) + uint32 addr; +{ + if ((mec_dbg & 0x80000) && (addr == brk_point) && + ((asi == 9) || (asi == 8))) { + mec_dbg |= 0x00800000; + if (mec_dbg & 0x00200000) { + set_sfsr(BREAK_EXC, addr, asi, 1); + return (1); + } + } + return (0); +} + +int32 +chk_watch(addr, read, asi) + uint32 addr; + uint32 read; +{ + uint32 hit; + + if ((mec_dbg & 0x40000) && (asi != 9) && (asi != 8) && + (((mec_dbg & 0x10000) && (read == 0)) || ((mec_dbg & 0x20000) && read))) { + if (((addr ^ watch_point) & + (0xffff0000 | (mec_dbg & 0x0ffff))) == 0) { + mec_dbg |= 0x00400000; + if (mec_dbg & 0x100000) { + set_sfsr(WATCH_EXC, addr, asi, read); + return (1); + } + } + } + return (0); +} + +int32 +mec_read(addr, asi, data) + uint32 addr; + uint32 asi; + uint32 *data; +{ + + switch (addr & 0x0ff) { + + case MEC_SFR: + case MEC_WDOG: + return (1); + break; + case MEC_DBG: + *data = mec_dbg; + break; + case MEC_UARTA: + case MEC_UARTB: + if (asi != 0xb) + return (1); + *data = read_uart(addr); + break; + + case MEC_UART_CTRL: + + *data = read_uart(addr); + break; + + case MEC_RTC_COUNTER: + *data = rtc_counter_read(); + break; + + case MEC_GPT_COUNTER: + *data = gpt_counter_read(); + break; + + case MEC_SFSR: + *data = mec_sfsr; + break; + + case MEC_FFAR: + *data = mec_ffar; + break; + + case MEC_IPR: + *data = mec_ipr; + break; + + case MEC_IMR: + *data = mec_imr; + break; + + case MEC_IFR: + *data = mec_ifr; + break; + + case SIM_LOAD: + fname[find] = 0; + if (find == 0) + strcpy(fname, "simload"); + *data = bfd_load(fname); + find = 0; + break; + + case MEC_MCR: + *data = mec_mcr; + break; + + case MEC_MEMCFG: + *data = mec_memcfg; + break; + + case MEC_WCR: + *data = mec_wcr; + break; + + case MEC_MAR0: + *data = mec_mar0; + break; + + case MEC_MAR1: + *data = mec_mar1; + break; + + case MEC_PWDR: + return (1); + break; + + default: + if (sis_verbose) + printf("Warning, read from unimplemented MEC register %x\n\r", addr); + *data = mec_regs[((addr & 0x0ff) >> 2)]; + break; + } + return (MOK); +} + +int +mec_write(addr, data) + uint32 addr; + uint32 data; +{ + + switch (addr & 0x0ff) { + + case MEC_SFR: + if (mec_mcr & 0x2) { + sys_reset(); + mec_ersr = 0x4000; + printf(" Software reset issued\n"); + } + break; + + case MEC_BRK: + brk_point = data; + break; + + case MEC_DBG: + mec_dbg = data; + break; + + case MEC_WPR: + watch_point = data; + break; + + case MEC_UARTA: + case MEC_UARTB: + case MEC_UART_CTRL: + write_uart(addr, data); + break; + + case MEC_GPT_RELOAD: + gpt_reload_set(data); + break; + + case MEC_GPT_SCALER: + gpt_scaler_set(data); + break; + + case MEC_TIMER_CTRL: + timer_ctrl(data); + break; + + case MEC_RTC_RELOAD: + rtc_reload_set(data); + break; + + case MEC_RTC_SCALER: + rtc_scaler_set(data); + break; + + case MEC_SFSR: + mec_sfsr = 0; + break; + + case MEC_IMR: + mec_imr = data & 0x7ffe; + chk_irq(); + break; + + case MEC_ICR: + mec_icr &= ~data & 0x0fffe; + break; + + case MEC_IFR: + mec_ifr = data & 0xfffe; + chk_irq(); + break; + case SIM_LOAD: + fname[find++] = (char) data; + break; + + case MEC_MCR: + mec_mcr = data; + decode_mcr(); + break; + + case MEC_MEMCFG: + mec_memcfg = data & ~0xC0e08000; + decode_memcfg(); + break; + + case MEC_WCR: + mec_wcr = data; + decode_wcr(); + break; + + case MEC_MAR0: + mec_mar0 = data; + break; + + case MEC_MAR1: + mec_mar1 = data; + break; + + case MEC_WDOG: + wdog_scaler = (data >> 16) & 0x0ff; + wdog_counter = data & 0x0ffff; + wdog_rst_delay = data >> 24; + wdog_rston = 0; + if (wdog_status == stopped) + wdog_start(); + wdog_status = enabled; + break; + + case MEC_TRAPD: + if (wdog_status == init) { + wdog_status = disabled; + if (sis_verbose) + printf("Watchdog disabled\n"); + } + break; + + case MEC_PWDR: + if (mec_mcr & 1) + wait_for_irq(); + break; + + default: + if (sis_verbose) + printf("Warning, write to unimplemented MEC register %x\n\r", + addr); + mec_regs[((addr & 0x0ffc) >> 2)] = data; + break; + } + return (MOK); +} + + +/* MEC UARTS */ + + +void +port_init() +{ + + int32 pty_remote = 1; + + + + if ((fd1 = open(uart_dev1, O_RDWR | O_NDELAY | O_NONBLOCK)) < 0) { + printf("Warning, couldn't open output device %s\n", uart_dev1); + } else { + printf("serial port A on %s\n", uart_dev1); + f1 = fdopen(fd1, "r+"); + setbuf(f1, NULL); + } + if ((fd2 = open(uart_dev2, O_RDWR | O_NDELAY | O_NONBLOCK)) < 0) { + printf("Warning, couldn't open output device %s\n", uart_dev2); + } else { + printf("serial port B on %s\n", uart_dev2); + f2 = fdopen(fd2, "r+"); + setbuf(f2, NULL); + } + + wnuma = wnumb = 0; +} + +uint32 +read_uart(addr) + uint32 addr; +{ + + unsigned tmp; + + switch (addr & 0xff) { + + case 0xE0: /* UART 1 */ +#ifdef FAST_UART + if (aind < anum) { + if ((aind + 1) < anum) + mec_irq(4); + return (0x700 | (uint32) aq[aind++]); + } else { + if (f1) + anum = fread(aq, 1, UARTBUF, f1); + else + anum = 0; + if (anum > 0) { + aind = 0; + if ((aind + 1) < anum) + mec_irq(4); + return (0x700 | (uint32) aq[aind++]); + } else { + return (0x600 | (uint32) aq[aind]); + } + + } +#else + tmp = uarta_data; + uarta_data &= ~UART_DR; + uart_stat_reg &= ~UARTA_DR; + return tmp; +#endif + break; + + case 0xE4: /* UART 2 */ +#ifdef FAST_UART + if (bind < bnum) { + if ((bind + 1) < bnum) + mec_irq(5); + return (0x700 | (uint32) bq[bind++]); + } else { + if (f2) + bnum = fread(bq, 1, UARTBUF, f2); + else + bnum = 0; + if (bnum > 0) { + bind = 0; + if ((bind + 1) < bnum) + mec_irq(5); + return (0x700 | (uint32) bq[bind++]); + } else { + return (0x600 | (uint32) bq[bind]); + } + + } +#else + tmp = uartb_data; + uartb_data &= ~UART_DR; + uart_stat_reg &= ~UARTB_DR; + return tmp; +#endif + break; + + case 0xE8: /* UART status register */ +#ifdef FAST_UART + Ucontrol = 0; + if (aind < anum) { + Ucontrol |= 0x00000001; + } else { + if (f1) + anum = fread(aq, 1, UARTBUF, f1); + else + anum = 0; + if (anum > 0) { + Ucontrol |= 0x00000001; + aind = 0; + mec_irq(4); + } + } + if (bind < bnum) { + Ucontrol |= 0x00010000; + } else { + if (f2) + bnum = fread(bq, 1, UARTBUF, f2); + else + bnum = 0; + if (bnum > 0) { + Ucontrol |= 0x00010000; + bind = 0; + mec_irq(5); + } + } + + Ucontrol |= 0x00060006; + return (Ucontrol); +#else + return (uart_stat_reg); +#endif + break; + default: + if (sis_verbose) + printf("Read from unimplemented MEC register (%x)\n", addr); + + } + return (0); +} + +void +write_uart(addr, data) + uint32 addr; + uint32 data; +{ + + int32 wnum = 0; + unsigned char c; + + c = (unsigned char) data; + switch (addr & 0xff) { + + case 0xE0: /* UART A */ +#ifdef FAST_UART + if (wnuma < UARTBUF) + wbufa[wnuma++] = c; + else { + while (wnuma) + if (f1) + wnuma -= fwrite(wbufa, 1, wnuma, f1); + else + wnuma--; + wbufa[wnuma++] = c; + } + mec_irq(4); +#else + if (uart_stat_reg & UARTA_SRE) { + uarta_sreg = c; + uart_stat_reg &= ~UARTA_SRE; + event(uarta_tx, 0, UART_TX_TIME); + } else { + uarta_hreg = c; + uart_stat_reg &= ~UARTA_HRE; + } +#endif + break; + + case 0xE4: /* UART B */ +#ifdef FAST_UART + if (wnumb < UARTBUF) + wbufb[wnumb++] = c; + else { + while (wnumb) + if (f2) + wnumb -= fwrite(wbufb, 1, wnumb, f2); + else + wnumb--; + wbufb[wnumb++] = c; + } + mec_irq(5); +#else + if (uart_stat_reg & UARTB_SRE) { + uartb_sreg = c; + uart_stat_reg &= ~UARTB_SRE; + event(uartb_tx, 0, UART_TX_TIME); + } else { + uartb_hreg = c; + uart_stat_reg &= ~UARTB_HRE; + } +#endif + break; + case 0xE8: /* UART status register */ +#ifndef FAST_UART + if (data & UARTA_CLR) { + uart_stat_reg &= 0xFFFF0000; + uart_stat_reg |= UARTA_SRE | UARTA_HRE; + } + if (data & UARTB_CLR) { + uart_stat_reg &= 0x0000FFFF; + uart_stat_reg |= UARTB_SRE | UARTB_HRE; + } +#endif + break; + default: + if (sis_verbose) + printf("Write to unimplemented MEC register (%x)\n", addr); + + } +} + +flush_uart() +{ + while (wnuma) + if (f1) + wnuma -= fwrite(wbufa, 1, wnuma, f1); + else + wnuma = 0; + while (wnumb) + if (f2) + wnumb -= fwrite(wbufb, 1, wnumb, f2); + else + wnumb = 0; +} + + + +void +uarta_tx() +{ + + while ((f1 ? fwrite(&uarta_sreg, 1, 1, f1) : 1) != 1); + if (uart_stat_reg & UARTA_HRE) { + uart_stat_reg |= UARTA_SRE; + } else { + uarta_sreg = uarta_hreg; + uart_stat_reg |= UARTA_HRE; + event(uarta_tx, 0, UART_TX_TIME); + } + mec_irq(4); +} + +void +uartb_tx() +{ + while (fwrite(&uartb_sreg, 1, 1, f2) != 1); + if (uart_stat_reg & UARTB_HRE) { + uart_stat_reg |= UARTB_SRE; + } else { + uartb_sreg = uartb_hreg; + uart_stat_reg |= UARTB_HRE; + event(uartb_tx, 0, UART_TX_TIME); + } + mec_irq(5); +} + +void +uart_rx(arg) + caddr_t arg; +{ + int32 rsize; + char rxd; + + rsize = fread(&rxd, 1, 1, f1); + if (rsize) { + uarta_data = UART_DR | rxd; + if (uart_stat_reg & UARTA_HRE) + uarta_data |= UART_THE; + if (uart_stat_reg & UARTA_SRE) + uarta_data |= UART_TSE; + if (uart_stat_reg & UARTA_DR) { + uart_stat_reg |= UARTA_OR; + mec_irq(7); /* UART error interrupt */ + } + uart_stat_reg |= UARTA_DR; + mec_irq(4); + } + rsize = fread(&rxd, 1, 1, f2); + if (rsize) { + uartb_data = UART_DR | rxd; + if (uart_stat_reg & UARTB_HRE) + uartb_data |= UART_THE; + if (uart_stat_reg & UARTB_SRE) + uartb_data |= UART_TSE; + if (uart_stat_reg & UARTB_DR) { + uart_stat_reg |= UARTB_OR; + mec_irq(7); /* UART error interrupt */ + } + uart_stat_reg |= UARTB_DR; + mec_irq(5); + } + event(uart_rx, 0, UART_RX_TIME); +} + +void +uart_intr(arg) + caddr_t arg; +{ + read_uart(0xE8); /* Check for UART interrupts every 1000 clk */ + flush_uart(); /* Flush UART ports */ + event(uart_intr, 0, UART_FLUSH_TIME); +} + + +void +uart_irq_start() +{ +#ifdef FAST_UART + event(uart_intr, 0, UART_FLUSH_TIME); +#else + event(uart_rx, 0, UART_RX_TIME); +#endif +} + +/* Watch-dog */ + +void +wdog_intr(arg) + caddr_t arg; +{ + if (wdog_status == disabled) { + wdog_status = stopped; + } else { + + if (wdog_counter) { + wdog_counter--; + event(wdog_intr, 0, wdog_scaler + 1); + } else { + if (wdog_rston) { + printf("Watchdog reset!\n"); + sys_reset(); + mec_ersr = 0xC000; + } else { + mec_irq(15); + wdog_rston = 1; + wdog_counter = wdog_rst_delay; + event(wdog_intr, 0, wdog_scaler + 1); + } + } + } +} + +void +wdog_start() +{ + event(wdog_intr, 0, wdog_scaler + 1); + if (sis_verbose) + printf("Watchdog started, scaler = %d, counter = %d\n", + wdog_scaler, wdog_counter); +} + + +/* MEC timers */ + + +void +rtc_intr(arg) + caddr_t arg; +{ + if (rtc_counter == 0) { +#ifdef MECREV0 + if (mecrev0) { + if (rtc_cr) { + rtc_counter = rtc_reload; + mec_irq(13); + } else { + rtc_cont = 0; + if (rtc_irqon) { + mec_irq(13); + rtc_irqon = 0; + } else { + if (sis_verbose) + printf("RTC interrupt lost (MEC rev.0)\n"); + } + } + } else { + mec_irq(13); + if (rtc_cr) + rtc_counter = rtc_reload; + else + rtc_cont = 0; + } + +#else + + mec_irq(13); + if (rtc_cr) + rtc_counter = rtc_reload; + else + rtc_cont = 0; +#endif + + } else + rtc_counter -= 1; + if (rtc_se && rtc_cont) { + event(rtc_intr, 0, rtc_scaler + 1); + rtc_enabled = 1; + } else { + if (sis_verbose) + printf("RTC stopped\n\r"); + rtc_enabled = 0; + } +} + +void +rtc_start() +{ + if (sis_verbose) + printf("RTC started (period %d)\n\r", rtc_scaler + 1); + event(rtc_intr, 0, rtc_scaler + 1); + rtc_enabled = 1; +} + +uint32 +rtc_counter_read() +{ + return (rtc_counter); +} + +void +rtc_scaler_set(val) + uint32 val; +{ + rtc_scaler = val & 0x0ff; /* eight-bit scaler only */ +} + +void +rtc_reload_set(val) + uint32 val; +{ + rtc_reload = val; +} + +void +gpt_intr(arg) + caddr_t arg; +{ + if (gpt_counter == 0) { +#ifdef MECREV0 + if (mecrev0) { + if (gpt_cr) { + gpt_counter = gpt_reload; + mec_irq(12); + } else { + gpt_cont = 0; + if (gpt_irqon) { + mec_irq(12); + gpt_irqon = 0; + } else { + if (sis_verbose) + printf("GPT interrupt lost (MEC rev.0)\n"); + } + } + } else { + mec_irq(12); + if (gpt_cr) + gpt_counter = gpt_reload; + else + gpt_cont = 0; + } + +#else + mec_irq(12); + if (gpt_cr) + gpt_counter = gpt_reload; + else + gpt_cont = 0; +#endif + } else + gpt_counter -= 1; + if (gpt_se && gpt_cont) { + event(gpt_intr, 0, gpt_scaler + 1); + gpt_enabled = 1; + } else { + if (sis_verbose) + printf("GPT stopped\n\r"); + gpt_enabled = 0; + } +} + +void +gpt_start() +{ + if (sis_verbose) + printf("GPT started (period %d)\n\r", gpt_scaler + 1); + event(gpt_intr, 0, gpt_scaler + 1); + gpt_enabled = 1; +} + +uint32 +gpt_counter_read() +{ + return (gpt_counter); +} + +void +gpt_scaler_set(val) + uint32 val; +{ + gpt_scaler = val & 0x0ffff; /* 16-bit scaler */ +} + +void +gpt_reload_set(val) + uint32 val; +{ + gpt_reload = val; +} + +void +timer_ctrl(val) + uint32 val; +{ + +#ifdef MECREV0 + if ((mecrev0) && (val & 0x500)) + rtc_irqon = 1; +#endif + + rtc_cr = ((val & TCR_TCRCR) != 0); + if (val & TCR_TCRCL) { + rtc_counter = rtc_reload; + rtc_cont = 1; + } + if (val & TCR_TCRSL) { + rtc_cont = 1; + } + rtc_se = ((val & TCR_TCRSE) != 0); + if (rtc_cont && rtc_se && (rtc_enabled == 0)) + rtc_start(); + +#ifdef MECREV0 + if ((mecrev0) && (val & 0x5)) + gpt_irqon = 1; +#endif + + gpt_cr = (val & TCR_GACR); + if (val & TCR_GACL) { + gpt_counter = gpt_reload; + gpt_cont = 1; + } + if (val & TCR_GACL) { + gpt_cont = 1; + } + gpt_se = (val & TCR_GASE) >> 2; + if (gpt_cont && gpt_se && (gpt_enabled == 0)) + gpt_start(); +} + + +/* Memory emulation */ + +/* ROM size 512 Kbyte */ +#define ROM_SZ 0x080000 + +/* RAM size 4 Mbyte */ +#define RAM_START 0x02000000 +#define RAM_END 0x02400000 +#define RAM_MASK 0x003fffff + +/* MEC registers */ +#define MEC_START 0x01f80000 +#define MEC_END 0x01f80100 + +/* Memory exception waitstates */ +#define MEM_EX_WS 1 + +/* ERC32 always adds one waitstate during ldd/std */ +#define LDD_WS 1 +#define STD_WS 1 + +extern int32 sis_verbose; + +static uint32 romb[ROM_SZ / 4]; +static uint32 ramb[(RAM_END - RAM_START) / 4]; + +int +memory_read(asi, addr, data, ws) + int32 asi; + uint32 addr; + uint32 *data; + int32 *ws; +{ + int32 mexc; + uint32 *mem; + +#ifdef MECBRK + + if (mec_dbg & 0x80000) { + if (chk_brk(addr, asi)) { + *ws = MEM_EX_WS; + return (1); + } + } + if (mec_dbg & 0x40000) { + if (chk_watch(addr, 1, asi)) { + *ws = MEM_EX_WS; + return (1); + } + } +#endif + + if (addr < mem_romsz) { + *data = romb[addr >> 2]; + *ws = mem_romr_ws; + return (0); + } else if ((addr >= RAM_START) && (addr < (RAM_START + mem_ramsz))) { + *data = ramb[(addr & RAM_MASK) >> 2]; + *ws = mem_ramr_ws; + return (0); + } else if ((addr >= MEC_START) && (addr < MEC_END)) { + mexc = mec_read(addr, asi, data); + if (mexc) { + set_sfsr(MEC_ACC, addr, asi, 1); + *ws = MEM_EX_WS; + } else { + *ws = 0; + } + return (mexc); + } + printf("Memory exception at %x (illegal address)\n", addr); + set_sfsr(UIMP_ACC, addr, asi, 1); + *ws = MEM_EX_WS; + return (1); +} + +int +memory_write(asi, addr, data, sz, ws) + int32 asi; + uint32 addr; + uint32 *data; + int32 sz; + int32 *ws; +{ + uint32 byte_addr; + uint32 byte_mask; + uint32 waddr; + uint32 bank; + int32 mexc; + +#ifdef MECBRK + if (mec_dbg & 0x40000) { + if (chk_watch(addr, 0, asi)) { + *ws = MEM_EX_WS; + return (1); + } + } +#endif + + if ((addr >= RAM_START) && (addr < (RAM_START + mem_ramsz))) { + if (mem_accprot) { + bank = (addr & RAM_MASK) >> mem_banksz; + if (bank < 32 + ? !((1 << bank) & mec_mar0) + : !((1 << (bank - 32) & mec_mar1))) { + printf("Memory access protection error at %x\n", addr); + set_sfsr(PROT_EXC, addr, asi, 0); + *ws = MEM_EX_WS; + return (1); + } + } + *ws = mem_ramw_ws; + waddr = (addr & RAM_MASK) >> 2; + switch (sz) { + case 0: + byte_addr = addr & 3; + byte_mask = 0x0ff << (24 - (8 * byte_addr)); + ramb[waddr] = (ramb[waddr] & ~byte_mask) + | ((*data & 0x0ff) << (24 - (8 * byte_addr))); + break; + case 1: + byte_addr = (addr & 2) >> 1; + byte_mask = 0x0ffff << (16 - (16 * byte_addr)); + ramb[waddr] = (ramb[waddr] & ~byte_mask) + | ((*data & 0x0ffff) << (16 - (16 * byte_addr))); + break; + case 2: + ramb[waddr] = *data; + break; + case 3: + ramb[waddr] = data[0]; + ramb[waddr + 1] = data[1]; + *ws += mem_ramw_ws + STD_WS; + break; + } + return (0); + } else if ((addr >= MEC_START) && (addr < MEC_END)) { + if ((sz != 2) || (asi != 0xb)) { + set_sfsr(MEC_ACC, addr, asi, 0); + *ws = MEM_EX_WS; + return (1); + } + mexc = mec_write(addr, *data); + if (mexc) { + set_sfsr(MEC_ACC, addr, asi, 0); + *ws = MEM_EX_WS; + } else { + *ws = 0; + } + return (mexc); + + } + *ws = MEM_EX_WS; + set_sfsr(UIMP_ACC, addr, asi, 0); + return (1); +} + +unsigned char * +get_mem_ptr(addr, size) + uint32 addr; + uint32 size; +{ + char *bram, *brom; + + brom = (char *) romb; + bram = (char *) ramb; + if ((addr + size) < ROM_SZ) { + return (&brom[addr]); + } else if ((addr >= RAM_START) && ((addr + size) < RAM_END)) { + return (&bram[(addr & RAM_MASK)]); + } + return ((char *) -1); +} + +int +sis_memory_write(addr, data, length) + uint32 addr; + char *data; + uint32 length; +{ + char *mem; + uint32 i; + + if ((mem = get_mem_ptr(addr, length)) == ((char *) -1)) + return (0); +#ifdef HOST_LITTLE_ENDIAN + for (i = 0; i < length; i++) { + mem[i ^ 0x3] = data[i]; + } +#else + memcpy(mem, data, length); +#endif + return (length); +} + +int +sis_memory_read(addr, data, length) + uint32 addr; + char *data; + uint32 length; +{ + char *mem; + int i; + + if ((mem = get_mem_ptr(addr, length)) == ((char *) -1)) + return (0); + +#ifdef HOST_LITTLE_ENDIAN + for (i = 0; i < length; i++) { + data[i] = mem[i ^ 0x3]; + } +#else + memcpy(data, mem, length); +#endif + return (length); +} diff --git a/sim/erc32/interf.c b/sim/erc32/interf.c index e81fbf3..2cc3a00 100644 --- a/sim/erc32/interf.c +++ b/sim/erc32/interf.c @@ -228,10 +228,12 @@ sim_close(int quitting) }; +/* Return non-zero if the caller should handle the load. Zero if + we have loaded the image. */ int sim_load(char *prog, int from_tty) { - bfd_load(*prog); + bfd_load(prog); return (0); } @@ -317,11 +319,63 @@ sim_stop_reason(enum sim_stop * reason, int *sigrc) simstat = OK; } +/* Flush all register windows out to the stack. Starting after the invalid + window, flush all windows up to, and including the current window. This + allows GDB to do backtraces and look at local variables for frames that + are still in the register windows. Note that strictly speaking, this + behavior is *wrong* for several reasons. First, it doesn't use the window + overflow handlers. It therefore assumes standard frame layouts and window + handling policies. Second, it changes system state behind the back of the + target program. I expect this to mainly pose problems when debugging trap + handlers. +*/ + +#define PSR_CWP 0x7 + +static void +flush_windows () +{ + int invwin; + int cwp; + int win; + int ws; + + /* Keep current window handy */ + + cwp = sregs.psr & PSR_CWP; + + /* Calculate the invalid window from the wim. */ + + for (invwin = 0; invwin <= PSR_CWP; invwin++) + if ((sregs.wim >> invwin) & 1) + break; + + /* Start saving with the window after the invalid window. */ + + invwin = (invwin - 1) & PSR_CWP; + + for (win = invwin; ; win = (win - 1) & PSR_CWP) + { + uint32 sp; + int i; + + sp = sregs.r[(win * 16 + 14) & 0x7f]; + + for (i = 0; i < 16; i++) + memory_write (11, sp + 4 * i, &sregs.r[(win * 16 + 16 + i) & 0x7f], 2, + &ws); + + if (win == cwp) + break; + } +} void sim_resume(int step, int siggnal) { simstat = run_sim(&sregs, 1, 0, 0); + + flush_windows (); } void diff --git a/sim/erc32/sis.h b/sim/erc32/sis.h new file mode 100644 index 0000000..144ae5d --- /dev/null +++ b/sim/erc32/sis.h @@ -0,0 +1,145 @@ +/* + * This file is part of SIS. + * + * ERC32SIM, SPARC instruction simulator. 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 2 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, write to the Free Software Foundation, Inc., 675 + * Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "end.h" + +#define I_ACC_EXC 1 + +/* Maximum events in event queue */ +#define EVENT_MAX 256 + +/* Maximum # of floating point queue */ +#define FPUQN 1 + +/* Maximum # of breakpoints */ +#define BPT_MAX 256 + +struct histype { + unsigned addr; + unsigned time; +}; + +/* type definitions */ + +typedef short int int16; /* 16-bit signed int */ +typedef unsigned short int uint16; /* 16-bit unsigned int */ +typedef int int32; /* 32-bit signed int */ +typedef unsigned int uint32; /* 32-bit unsigned int */ +typedef float float32; /* 32-bit float */ +typedef double float64; /* 64-bit float */ + +struct pstate { + + float64 fd[16]; /* FPU registers */ +#ifdef HOST_LITTLE_ENDIAN_FLOAT + float32 fs[32]; + float32 *fdp; +#else + float32 *fs; +#endif + int32 *fsi; + uint32 fsr; + int32 fpstate; + uint32 fpq[FPUQN * 2]; + uint32 fpqn; + uint32 ftime; + uint32 flrd; + uint32 frd; + uint32 frs1; + uint32 frs2; + uint32 fpu_pres; /* FPU present (0 = No, 1 = Yes) */ + + uint32 psr; /* IU registers */ + uint32 tbr; + uint32 wim; + uint32 g[8]; + uint32 r[128]; + uint32 y; + uint32 pc, npc; + + + uint32 trap; /* Current trap type */ + uint32 annul; /* Instruction annul */ + uint32 data; /* Loaded data */ + uint32 inst; /* Current instruction */ + uint32 asi; /* Current ASI */ + uint32 err_mode; /* IU error mode */ + uint32 breakpoint; + uint32 bptnum; + uint32 bphit; + uint32 bpts[BPT_MAX]; /* Breakpoints */ + + uint32 ltime; /* Load interlock time */ + uint32 hold; /* IU hold cycles in current inst */ + uint32 fhold; /* FPU hold cycles in current inst */ + uint32 icnt; /* Instruction cycles in curr inst */ + + uint32 histlen; /* Trace history management */ + uint32 histind; + struct histype *histbuf; + float32 freq; /* Simulated processor frequency */ + + + uint32 tottime; + uint32 ninst; + uint32 fholdt; + uint32 holdt; + uint32 icntt; + uint32 finst; + uint32 simstart; + uint32 starttime; + uint32 pwdtime; /* Cycles in power-down mode */ + uint32 nstore; /* Number of load instructions */ + uint32 nload; /* Number of store instructions */ + uint32 nannul; /* Number of annuled instructions */ + uint32 nbranch; /* Number of branch instructions */ + uint32 ildreg; /* Destination of last load instruction */ + uint32 ildtime; /* Last time point for load dependency */ + + int rett_err; /* IU in jmpl/restore error state (Rev.0) */ + int jmpltime; +}; + +struct evcell { + void (*cfunc) (); + int32 arg; + uint32 time; + struct evcell *nxt; +}; + +struct estate { + struct evcell eq; + struct evcell *freeq; + uint32 simtime; +}; + +struct irqcell { + void (*callback) (); + int32 arg; +}; + + +#define OK 0 +#define TIME_OUT 1 +#define BPT_HIT 2 +#define ERROR 3 +#define CTRL_C 4 |