|  | /* This file is part of SIS (SPARC instruction simulator) | 
|  |  | 
|  | Copyright (C) 1995-2022 Free Software Foundation, Inc. | 
|  | Contributed by 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/>.  */ | 
|  |  | 
|  | /* The control space devices */ | 
|  |  | 
|  | /* This must come before any other includes.  */ | 
|  | #include "defs.h" | 
|  |  | 
|  | #include <sys/types.h> | 
|  | #include <stdio.h> | 
|  | #include <string.h> | 
|  | #ifdef HAVE_TERMIOS_H | 
|  | #include <termios.h> | 
|  | #endif | 
|  | #include <sys/fcntl.h> | 
|  | #include <sys/file.h> | 
|  | #include <unistd.h> | 
|  | #include "sis.h" | 
|  | #include "sim-config.h" | 
|  |  | 
|  | extern int      ctrl_c; | 
|  | extern int32_t    sis_verbose; | 
|  | extern int32_t    sparclite, sparclite_board; | 
|  | extern int      rom8,wrp,uben; | 
|  | extern char     uart_dev1[], uart_dev2[]; | 
|  |  | 
|  | int dumbio = 0; /* normal, smart, terminal oriented IO by default */ | 
|  |  | 
|  | /* MEC registers */ | 
|  | #define MEC_START 	0x01f80000 | 
|  | #define MEC_END 	0x01f80100 | 
|  |  | 
|  | /* Memory exception waitstates */ | 
|  | #define MEM_EX_WS 	1 | 
|  |  | 
|  | /* ERC32 always adds one waitstate during RAM std */ | 
|  | #define STD_WS 1 | 
|  |  | 
|  | #ifdef ERRINJ | 
|  | extern int errmec; | 
|  | #endif | 
|  |  | 
|  | #define MEC_WS	0		/* Waitstates per MEC access (0 ws) */ | 
|  | #define MOK	0 | 
|  |  | 
|  | /* MEC register addresses */ | 
|  |  | 
|  | #define MEC_MCR		0x000 | 
|  | #define MEC_SFR  	0x004 | 
|  | #define MEC_PWDR  	0x008 | 
|  | #define MEC_MEMCFG	0x010 | 
|  | #define MEC_IOCR	0x014 | 
|  | #define MEC_WCR		0x018 | 
|  |  | 
|  | #define MEC_MAR0  	0x020 | 
|  | #define MEC_MAR1  	0x024 | 
|  |  | 
|  | #define MEC_SSA1 	0x020 | 
|  | #define MEC_SEA1 	0x024 | 
|  | #define MEC_SSA2 	0x028 | 
|  | #define MEC_SEA2 	0x02C | 
|  | #define MEC_ISR		0x044 | 
|  | #define MEC_IPR		0x048 | 
|  | #define MEC_IMR 	0x04C | 
|  | #define MEC_ICR 	0x050 | 
|  | #define MEC_IFR 	0x054 | 
|  | #define MEC_WDOG  	0x060 | 
|  | #define MEC_TRAPD  	0x064 | 
|  | #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_TIMER_CTRL	0x098 | 
|  | #define MEC_SFSR	0x0A0 | 
|  | #define MEC_FFAR	0x0A4 | 
|  | #define MEC_ERSR	0x0B0 | 
|  | #define MEC_DBG		0x0C0 | 
|  | #define MEC_TCR		0x0D0 | 
|  |  | 
|  | #define MEC_BRK		0x0C4 | 
|  | #define MEC_WPR		0x0C8 | 
|  |  | 
|  | #define MEC_UARTA	0x0E0 | 
|  | #define MEC_UARTB	0x0E4 | 
|  | #define MEC_UART_CTRL	0x0E8 | 
|  | #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 int32_t    find = 0; | 
|  | static uint32_t   mec_ssa[2];	/* Write protection start address */ | 
|  | static uint32_t   mec_sea[2];	/* Write protection end address */ | 
|  | static uint32_t   mec_wpr[2];	/* Write protection control fields */ | 
|  | static uint32_t   mec_sfsr; | 
|  | static uint32_t   mec_ffar; | 
|  | static uint32_t   mec_ipr; | 
|  | static uint32_t   mec_imr; | 
|  | static uint32_t   mec_isr; | 
|  | static uint32_t   mec_icr; | 
|  | static uint32_t   mec_ifr; | 
|  | static uint32_t   mec_mcr;	/* MEC control register */ | 
|  | static uint32_t   mec_memcfg;	/* Memory control register */ | 
|  | static uint32_t   mec_wcr;	/* MEC waitstate register */ | 
|  | static uint32_t   mec_iocr;	/* MEC IO control register */ | 
|  | static uint32_t   posted_irq; | 
|  | static uint32_t   mec_ersr;	/* MEC error and status register */ | 
|  | static uint32_t   mec_tcr;	/* MEC test comtrol register */ | 
|  |  | 
|  | static uint32_t   rtc_counter; | 
|  | static uint32_t   rtc_reload; | 
|  | static uint32_t   rtc_scaler; | 
|  | static uint32_t   rtc_scaler_start; | 
|  | static uint32_t   rtc_enabled; | 
|  | static uint32_t   rtc_cr; | 
|  | static uint32_t   rtc_se; | 
|  |  | 
|  | static uint32_t   gpt_counter; | 
|  | static uint32_t   gpt_reload; | 
|  | static uint32_t   gpt_scaler; | 
|  | static uint32_t   gpt_scaler_start; | 
|  | static uint32_t   gpt_enabled; | 
|  | static uint32_t   gpt_cr; | 
|  | static uint32_t   gpt_se; | 
|  |  | 
|  | static uint32_t   wdog_scaler; | 
|  | static uint32_t   wdog_counter; | 
|  | static uint32_t   wdog_rst_delay; | 
|  | static uint32_t   wdog_rston; | 
|  |  | 
|  | enum wdog_type { | 
|  | init, disabled, enabled, stopped | 
|  | }; | 
|  |  | 
|  | static enum wdog_type wdog_status; | 
|  |  | 
|  |  | 
|  | /* ROM size 1024 Kbyte */ | 
|  | #define ROM_SZ	 	0x100000 | 
|  | #define ROM_MASK 	0x0fffff | 
|  |  | 
|  | /* RAM size 4 Mbyte */ | 
|  | #define RAM_START 	0x02000000 | 
|  | #define RAM_END 	0x02400000 | 
|  | #define RAM_MASK 	0x003fffff | 
|  |  | 
|  | /* SPARClite boards all seem to have RAM at the same place. */ | 
|  | #define RAM_START_SLITE	0x40000000 | 
|  | #define RAM_END_SLITE 	0x40400000 | 
|  | #define RAM_MASK_SLITE 	0x003fffff | 
|  |  | 
|  | /* Memory support variables */ | 
|  |  | 
|  | static uint32_t   mem_ramr_ws;	/* RAM read waitstates */ | 
|  | static uint32_t   mem_ramw_ws;	/* RAM write waitstates */ | 
|  | static uint32_t   mem_romr_ws;	/* ROM read waitstates */ | 
|  | static uint32_t   mem_romw_ws;	/* ROM write waitstates */ | 
|  | static uint32_t	mem_ramstart;	/* RAM start */ | 
|  | static uint32_t	mem_ramend;	/* RAM end */ | 
|  | static uint32_t	mem_rammask;	/* RAM address mask */ | 
|  | static uint32_t   mem_ramsz;	/* RAM size */ | 
|  | static uint32_t   mem_romsz;	/* ROM size */ | 
|  | static uint32_t   mem_accprot;	/* RAM write protection enabled */ | 
|  | static uint32_t   mem_blockprot;	/* RAM block write protection enabled */ | 
|  |  | 
|  | static unsigned char	romb[ROM_SZ]; | 
|  | static unsigned char	ramb[RAM_END - RAM_START]; | 
|  |  | 
|  |  | 
|  | /* UART support variables */ | 
|  |  | 
|  | static int32_t    fd1, fd2;	/* file descriptor for input file */ | 
|  | static int32_t    Ucontrol;	/* UART status register */ | 
|  | static unsigned char aq[UARTBUF], bq[UARTBUF]; | 
|  | static int32_t    anum, aind = 0; | 
|  | static int32_t    bnum, bind = 0; | 
|  | static char     wbufa[UARTBUF], wbufb[UARTBUF]; | 
|  | static unsigned wnuma; | 
|  | static unsigned wnumb; | 
|  | static FILE    *f1in, *f1out, *f2in, *f2out; | 
|  | #ifdef HAVE_TERMIOS_H | 
|  | static struct termios ioc1, ioc2, iocold1, iocold2; | 
|  | #endif | 
|  | static int      f1open = 0, f2open = 0; | 
|  |  | 
|  | static char     uarta_sreg, uarta_hreg, uartb_sreg, uartb_hreg; | 
|  | static uint32_t   uart_stat_reg; | 
|  | static uint32_t   uarta_data, uartb_data; | 
|  |  | 
|  | #ifdef ERA | 
|  | int era = 0; | 
|  | int erareg; | 
|  | #endif | 
|  |  | 
|  | /* Forward declarations */ | 
|  |  | 
|  | static void	decode_ersr (void); | 
|  | #ifdef ERRINJ | 
|  | static void	iucomperr (void); | 
|  | #endif | 
|  | static void	mecparerror (void); | 
|  | static void	decode_memcfg (void); | 
|  | static void	decode_wcr (void); | 
|  | static void	decode_mcr (void); | 
|  | static void	close_port (void); | 
|  | static void	mec_reset (void); | 
|  | static void	mec_intack (int32_t level); | 
|  | static void	chk_irq (void); | 
|  | static void	mec_irq (int32_t level); | 
|  | static void	set_sfsr (uint32_t fault, uint32_t addr, | 
|  | uint32_t asi, uint32_t read); | 
|  | static int32_t	mec_read (uint32_t addr, uint32_t asi, uint32_t *data); | 
|  | static int	mec_write (uint32_t addr, uint32_t data); | 
|  | static void	port_init (void); | 
|  | static uint32_t	read_uart (uint32_t addr); | 
|  | static void	write_uart (uint32_t addr, uint32_t data); | 
|  | static void	flush_uart (void); | 
|  | static void	uarta_tx (void); | 
|  | static void	uartb_tx (void); | 
|  | static void	uart_rx (void *arg); | 
|  | static void	uart_intr (void *arg); | 
|  | static void	uart_irq_start (void); | 
|  | static void	wdog_intr (void *arg); | 
|  | static void	wdog_start (void); | 
|  | static void	rtc_intr (void *arg); | 
|  | static void	rtc_start (void); | 
|  | static uint32_t	rtc_counter_read (void); | 
|  | static void	rtc_scaler_set (uint32_t val); | 
|  | static void	rtc_reload_set (uint32_t val); | 
|  | static void	gpt_intr (void *arg); | 
|  | static void	gpt_start (void); | 
|  | static uint32_t	gpt_counter_read (void); | 
|  | static void	gpt_scaler_set (uint32_t val); | 
|  | static void	gpt_reload_set (uint32_t val); | 
|  | static void	timer_ctrl (uint32_t val); | 
|  | static void *	get_mem_ptr (uint32_t addr, uint32_t size); | 
|  | static void	store_bytes (unsigned char *mem, uint32_t waddr, | 
|  | uint32_t *data, int sz, int32_t *ws); | 
|  |  | 
|  | extern int	ext_irl; | 
|  |  | 
|  |  | 
|  | /* One-time init */ | 
|  |  | 
|  | void | 
|  | init_sim(void) | 
|  | { | 
|  | port_init(); | 
|  | } | 
|  |  | 
|  | /* Power-on reset init */ | 
|  |  | 
|  | void | 
|  | reset(void) | 
|  | { | 
|  | mec_reset(); | 
|  | uart_irq_start(); | 
|  | wdog_start(); | 
|  | } | 
|  |  | 
|  | static void | 
|  | decode_ersr(void) | 
|  | { | 
|  | if (mec_ersr & 0x01) { | 
|  | if (!(mec_mcr & 0x20)) { | 
|  | if (mec_mcr & 0x40) { | 
|  | sys_reset(); | 
|  | mec_ersr = 0x8000; | 
|  | if (sis_verbose) | 
|  | printf("Error manager reset - IU in error mode\n"); | 
|  | } else { | 
|  | sys_halt(); | 
|  | mec_ersr |= 0x2000; | 
|  | if (sis_verbose) | 
|  | printf("Error manager halt - IU in error mode\n"); | 
|  | } | 
|  | } else | 
|  | mec_irq(1); | 
|  | } | 
|  | if (mec_ersr & 0x04) { | 
|  | if (!(mec_mcr & 0x200)) { | 
|  | if (mec_mcr & 0x400) { | 
|  | sys_reset(); | 
|  | mec_ersr = 0x8000; | 
|  | if (sis_verbose) | 
|  | printf("Error manager reset - IU comparison error\n"); | 
|  | } else { | 
|  | sys_halt(); | 
|  | mec_ersr |= 0x2000; | 
|  | if (sis_verbose) | 
|  | printf("Error manager halt - IU comparison error\n"); | 
|  | } | 
|  | } else | 
|  | mec_irq(1); | 
|  | } | 
|  | if (mec_ersr & 0x20) { | 
|  | if (!(mec_mcr & 0x2000)) { | 
|  | if (mec_mcr & 0x4000) { | 
|  | sys_reset(); | 
|  | mec_ersr = 0x8000; | 
|  | if (sis_verbose) | 
|  | printf("Error manager reset - MEC hardware error\n"); | 
|  | } else { | 
|  | sys_halt(); | 
|  | mec_ersr |= 0x2000; | 
|  | if (sis_verbose) | 
|  | printf("Error manager halt - MEC hardware error\n"); | 
|  | } | 
|  | } else | 
|  | mec_irq(1); | 
|  | } | 
|  | } | 
|  |  | 
|  | #ifdef ERRINJ | 
|  | static void | 
|  | iucomperr() | 
|  | { | 
|  | mec_ersr |= 0x04; | 
|  | decode_ersr(); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | static void | 
|  | mecparerror(void) | 
|  | { | 
|  | mec_ersr |= 0x20; | 
|  | decode_ersr(); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* IU error mode manager */ | 
|  |  | 
|  | void | 
|  | error_mode(uint32_t pc) | 
|  | { | 
|  |  | 
|  | mec_ersr |= 0x1; | 
|  | decode_ersr(); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Check memory settings */ | 
|  |  | 
|  | static void | 
|  | decode_memcfg(void) | 
|  | { | 
|  | if (rom8) mec_memcfg &= ~0x20000; | 
|  | else mec_memcfg |= 0x20000; | 
|  |  | 
|  | mem_ramsz = (256 * 1024) << ((mec_memcfg >> 10) & 7); | 
|  | mem_romsz = (128 * 1024) << ((mec_memcfg >> 18) & 7); | 
|  |  | 
|  | if (sparclite_board) { | 
|  | mem_ramstart = RAM_START_SLITE; | 
|  | mem_ramend = RAM_END_SLITE; | 
|  | mem_rammask = RAM_MASK_SLITE; | 
|  | } | 
|  | else { | 
|  | mem_ramstart = RAM_START; | 
|  | mem_ramend = RAM_END; | 
|  | mem_rammask = RAM_MASK; | 
|  | } | 
|  | if (sis_verbose) | 
|  | printf("RAM start: 0x%x, RAM size: %d K, ROM size: %d K\n", | 
|  | mem_ramstart, mem_ramsz >> 10, mem_romsz >> 10); | 
|  | } | 
|  |  | 
|  | static void | 
|  | decode_wcr(void) | 
|  | { | 
|  | mem_ramr_ws = mec_wcr & 3; | 
|  | mem_ramw_ws = (mec_wcr >> 2) & 3; | 
|  | mem_romr_ws = (mec_wcr >> 4) & 0x0f; | 
|  | if (rom8) { | 
|  | if (mem_romr_ws > 0 )  mem_romr_ws--; | 
|  | mem_romr_ws = 5 + (4*mem_romr_ws); | 
|  | } | 
|  | 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); | 
|  | } | 
|  |  | 
|  | static void | 
|  | decode_mcr(void) | 
|  | { | 
|  | mem_accprot = (mec_wpr[0] | mec_wpr[1]); | 
|  | mem_blockprot = (mec_mcr >> 3) & 1; | 
|  | if (sis_verbose && mem_accprot) | 
|  | printf("Memory block write protection enabled\n"); | 
|  | if (mec_mcr & 0x08000) { | 
|  | mec_ersr |= 0x20; | 
|  | decode_ersr(); | 
|  | } | 
|  | 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_halt(void) | 
|  | { | 
|  | #ifdef FAST_UART | 
|  | flush_uart(); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | int | 
|  | sim_stop(SIM_DESC sd) | 
|  | { | 
|  | ctrl_c = 1; | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static void | 
|  | close_port(void) | 
|  | { | 
|  | if (f1open && f1in != stdin) | 
|  | fclose(f1in); | 
|  | if (f2open && f2in != stdin) | 
|  | fclose(f2in); | 
|  | } | 
|  |  | 
|  | void | 
|  | exit_sim(void) | 
|  | { | 
|  | close_port(); | 
|  | } | 
|  |  | 
|  | static void | 
|  | mec_reset(void) | 
|  | { | 
|  | int             i; | 
|  |  | 
|  | find = 0; | 
|  | for (i = 0; i < 2; i++) | 
|  | mec_ssa[i] = mec_sea[i] = mec_wpr[i] = 0; | 
|  | mec_mcr = 0x01350014; | 
|  | mec_iocr = 0; | 
|  | mec_sfsr = 0x078; | 
|  | mec_ffar = 0; | 
|  | mec_ipr = 0; | 
|  | mec_imr = 0x7ffe; | 
|  | mec_isr = 0; | 
|  | mec_icr = 0; | 
|  | mec_ifr = 0; | 
|  | mec_memcfg = 0x10000; | 
|  | mec_wcr = -1; | 
|  | mec_ersr = 0;		/* MEC error and status 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; | 
|  |  | 
|  | gpt_counter = 0xffffffff; | 
|  | gpt_reload = 0xffffffff; | 
|  | gpt_scaler = 0xffff; | 
|  | gpt_enabled = 0; | 
|  | gpt_cr = 0; | 
|  | gpt_se = 0; | 
|  |  | 
|  | wdog_scaler = 255; | 
|  | wdog_rst_delay = 255; | 
|  | wdog_counter = 0xffff; | 
|  | wdog_rston = 0; | 
|  | wdog_status = init; | 
|  |  | 
|  | #ifdef ERA | 
|  | erareg = 0; | 
|  | #endif | 
|  |  | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | static void | 
|  | mec_intack(int32_t 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); | 
|  | chk_irq(); | 
|  | } | 
|  |  | 
|  | static void | 
|  | chk_irq(void) | 
|  | { | 
|  | int32_t           i; | 
|  | uint32_t          itmp; | 
|  | int		    old_irl; | 
|  |  | 
|  | old_irl = ext_irl; | 
|  | if (mec_tcr & 0x80000) itmp = mec_ifr; | 
|  | else itmp  = 0; | 
|  | itmp = ((mec_ipr | itmp) & ~mec_imr) & 0x0fffe; | 
|  | ext_irl = 0; | 
|  | if (itmp != 0) { | 
|  | for (i = 15; i > 0; i--) { | 
|  | if (((itmp >> i) & 1) != 0) { | 
|  | if ((sis_verbose) && (i > old_irl)) | 
|  | printf("IU irl: %d\n", i); | 
|  | ext_irl = i; | 
|  | set_int(i, mec_intack, i); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void | 
|  | mec_irq(int32_t level) | 
|  | { | 
|  | mec_ipr |= (1 << level); | 
|  | chk_irq(); | 
|  | } | 
|  |  | 
|  | static void | 
|  | set_sfsr(uint32_t fault, uint32_t addr, uint32_t asi, uint32_t read) | 
|  | { | 
|  | if ((asi == 0xa) || (asi == 0xb)) { | 
|  | mec_ffar = addr; | 
|  | mec_sfsr = (fault << 3) | (!read << 15); | 
|  | mec_sfsr |= ((mec_sfsr & 1) ^ 1) | (mec_sfsr & 1); | 
|  | switch (asi) { | 
|  | case 0xa: | 
|  | mec_sfsr |= 0x0004; | 
|  | break; | 
|  | case 0xb: | 
|  | mec_sfsr |= 0x1004; | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static int32_t | 
|  | mec_read(uint32_t addr, uint32_t asi, uint32_t *data) | 
|  | { | 
|  |  | 
|  | switch (addr & 0x0ff) { | 
|  |  | 
|  | case MEC_MCR:		/* 0x00 */ | 
|  | *data = mec_mcr; | 
|  | break; | 
|  |  | 
|  | case MEC_MEMCFG:		/* 0x10 */ | 
|  | *data = mec_memcfg; | 
|  | break; | 
|  |  | 
|  | case MEC_IOCR: | 
|  | *data = mec_iocr;	/* 0x14 */ | 
|  | break; | 
|  |  | 
|  | case MEC_SSA1:		/* 0x20 */ | 
|  | *data = mec_ssa[0] | (mec_wpr[0] << 23); | 
|  | break; | 
|  | case MEC_SEA1:		/* 0x24 */ | 
|  | *data = mec_sea[0]; | 
|  | break; | 
|  | case MEC_SSA2:		/* 0x28 */ | 
|  | *data = mec_ssa[1] | (mec_wpr[1] << 23); | 
|  | break; | 
|  | case MEC_SEA2:		/* 0x2c */ | 
|  | *data = mec_sea[1]; | 
|  | break; | 
|  |  | 
|  | case MEC_ISR:		/* 0x44 */ | 
|  | *data = mec_isr; | 
|  | break; | 
|  |  | 
|  | case MEC_IPR:		/* 0x48 */ | 
|  | *data = mec_ipr; | 
|  | break; | 
|  |  | 
|  | case MEC_IMR:		/* 0x4c */ | 
|  | *data = mec_imr; | 
|  | break; | 
|  |  | 
|  | case MEC_IFR:		/* 0x54 */ | 
|  | *data = mec_ifr; | 
|  | break; | 
|  |  | 
|  | case MEC_RTC_COUNTER:	/* 0x80 */ | 
|  | *data = rtc_counter_read(); | 
|  | break; | 
|  | case MEC_RTC_SCALER:	/* 0x84 */ | 
|  | if (rtc_enabled) | 
|  | *data = rtc_scaler - (now() - rtc_scaler_start); | 
|  | else | 
|  | *data = rtc_scaler; | 
|  | break; | 
|  |  | 
|  | case MEC_GPT_COUNTER:	/* 0x88 */ | 
|  | *data = gpt_counter_read(); | 
|  | break; | 
|  |  | 
|  | case MEC_GPT_SCALER:	/* 0x8c */ | 
|  | if (rtc_enabled) | 
|  | *data = gpt_scaler - (now() - gpt_scaler_start); | 
|  | else | 
|  | *data = gpt_scaler; | 
|  | break; | 
|  |  | 
|  |  | 
|  | case MEC_SFSR:		/* 0xA0 */ | 
|  | *data = mec_sfsr; | 
|  | break; | 
|  |  | 
|  | case MEC_FFAR:		/* 0xA4 */ | 
|  | *data = mec_ffar; | 
|  | break; | 
|  |  | 
|  | case SIM_LOAD: | 
|  | fname[find] = 0; | 
|  | if (find == 0) | 
|  | strcpy(fname, "simload"); | 
|  | find = bfd_load(fname); | 
|  | if (find == -1) | 
|  | *data = 0; | 
|  | else | 
|  | *data = 1; | 
|  | find = 0; | 
|  | break; | 
|  |  | 
|  | case MEC_ERSR:		/* 0xB0 */ | 
|  | *data = mec_ersr; | 
|  | break; | 
|  |  | 
|  | case MEC_TCR:		/* 0xD0 */ | 
|  | *data = mec_tcr; | 
|  | break; | 
|  |  | 
|  | case MEC_UARTA:		/* 0xE0 */ | 
|  | case MEC_UARTB:		/* 0xE4 */ | 
|  | if (asi != 0xb) { | 
|  | set_sfsr(MEC_ACC, addr, asi, 1); | 
|  | return 1; | 
|  | } | 
|  | *data = read_uart(addr); | 
|  | break; | 
|  |  | 
|  | case MEC_UART_CTRL:		/* 0xE8 */ | 
|  |  | 
|  | *data = read_uart(addr); | 
|  | break; | 
|  |  | 
|  | case 0xF4:		/* simulator RAM size in bytes */ | 
|  | *data = 4096*1024; | 
|  | break; | 
|  |  | 
|  | case 0xF8:		/* simulator ROM size in bytes */ | 
|  | *data = 1024*1024; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | set_sfsr(MEC_ACC, addr, asi, 1); | 
|  | return 1; | 
|  | break; | 
|  | } | 
|  | return MOK; | 
|  | } | 
|  |  | 
|  | static int | 
|  | mec_write(uint32_t addr, uint32_t data) | 
|  | { | 
|  | if (sis_verbose > 1) | 
|  | printf("MEC write a: %08x, d: %08x\n",addr,data); | 
|  | switch (addr & 0x0ff) { | 
|  |  | 
|  | case MEC_MCR: | 
|  | mec_mcr = data; | 
|  | decode_mcr(); | 
|  | if (mec_mcr & 0x08000) mecparerror(); | 
|  | break; | 
|  |  | 
|  | case MEC_SFR: | 
|  | if (mec_mcr & 0x2) { | 
|  | sys_reset(); | 
|  | mec_ersr = 0x4000; | 
|  | if (sis_verbose) | 
|  | printf(" Software reset issued\n"); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case MEC_IOCR: | 
|  | mec_iocr = data; | 
|  | if (mec_iocr & 0xC0C0C0C0) mecparerror(); | 
|  | break; | 
|  |  | 
|  | case MEC_SSA1:		/* 0x20 */ | 
|  | if (data & 0xFE000000) mecparerror(); | 
|  | mec_ssa[0] = data & 0x7fffff; | 
|  | mec_wpr[0] = (data >> 23) & 0x03; | 
|  | mem_accprot = mec_wpr[0] || mec_wpr[1]; | 
|  | if (sis_verbose && mec_wpr[0]) | 
|  | printf("Segment 1 memory protection enabled (0x02%06x - 0x02%06x)\n", | 
|  | mec_ssa[0] << 2, mec_sea[0] << 2); | 
|  | break; | 
|  | case MEC_SEA1:		/* 0x24 */ | 
|  | if (data & 0xFF800000) mecparerror(); | 
|  | mec_sea[0] = data & 0x7fffff; | 
|  | break; | 
|  | case MEC_SSA2:		/* 0x28 */ | 
|  | if (data & 0xFE000000) mecparerror(); | 
|  | mec_ssa[1] = data & 0x7fffff; | 
|  | mec_wpr[1] = (data >> 23) & 0x03; | 
|  | mem_accprot = mec_wpr[0] || mec_wpr[1]; | 
|  | if (sis_verbose && mec_wpr[1]) | 
|  | printf("Segment 2 memory protection enabled (0x02%06x - 0x02%06x)\n", | 
|  | mec_ssa[1] << 2, mec_sea[1] << 2); | 
|  | break; | 
|  | case MEC_SEA2:		/* 0x2c */ | 
|  | if (data & 0xFF800000) mecparerror(); | 
|  | mec_sea[1] = data & 0x7fffff; | 
|  | break; | 
|  |  | 
|  | case MEC_UARTA: | 
|  | case MEC_UARTB: | 
|  | if (data & 0xFFFFFF00) mecparerror(); | 
|  | case MEC_UART_CTRL: | 
|  | if (data & 0xFF00FF00) mecparerror(); | 
|  | write_uart(addr, data); | 
|  | break; | 
|  |  | 
|  | case MEC_GPT_RELOAD: | 
|  | gpt_reload_set(data); | 
|  | break; | 
|  |  | 
|  | case MEC_GPT_SCALER: | 
|  | if (data & 0xFFFF0000) mecparerror(); | 
|  | gpt_scaler_set(data); | 
|  | break; | 
|  |  | 
|  | case MEC_TIMER_CTRL: | 
|  | if (data & 0xFFFFF0F0) mecparerror(); | 
|  | timer_ctrl(data); | 
|  | break; | 
|  |  | 
|  | case MEC_RTC_RELOAD: | 
|  | rtc_reload_set(data); | 
|  | break; | 
|  |  | 
|  | case MEC_RTC_SCALER: | 
|  | if (data & 0xFFFFFF00) mecparerror(); | 
|  | rtc_scaler_set(data); | 
|  | break; | 
|  |  | 
|  | case MEC_SFSR:		/* 0xA0 */ | 
|  | if (data & 0xFFFF0880) mecparerror(); | 
|  | mec_sfsr = 0x78; | 
|  | break; | 
|  |  | 
|  | case MEC_ISR: | 
|  | if (data & 0xFFFFE000) mecparerror(); | 
|  | mec_isr = data; | 
|  | break; | 
|  |  | 
|  | case MEC_IMR:		/* 0x4c */ | 
|  |  | 
|  | if (data & 0xFFFF8001) mecparerror(); | 
|  | mec_imr = data & 0x7ffe; | 
|  | chk_irq(); | 
|  | break; | 
|  |  | 
|  | case MEC_ICR:		/* 0x50 */ | 
|  |  | 
|  | if (data & 0xFFFF0001) mecparerror(); | 
|  | mec_ipr &= ~data & 0x0fffe; | 
|  | chk_irq(); | 
|  | break; | 
|  |  | 
|  | case MEC_IFR:		/* 0x54 */ | 
|  |  | 
|  | if (mec_tcr & 0x080000) { | 
|  | if (data & 0xFFFF0001) mecparerror(); | 
|  | mec_ifr = data & 0xfffe; | 
|  | chk_irq(); | 
|  | } | 
|  | break; | 
|  | case SIM_LOAD: | 
|  | fname[find++] = (char) data; | 
|  | break; | 
|  |  | 
|  |  | 
|  | case MEC_MEMCFG:		/* 0x10 */ | 
|  | if (data & 0xC0E08000) mecparerror(); | 
|  | mec_memcfg = data; | 
|  | decode_memcfg(); | 
|  | if (mec_memcfg & 0xc0e08000) | 
|  | mecparerror(); | 
|  | break; | 
|  |  | 
|  | case MEC_WCR:		/* 0x18 */ | 
|  | mec_wcr = data; | 
|  | decode_wcr(); | 
|  | break; | 
|  |  | 
|  | case MEC_ERSR:		/* 0xB0 */ | 
|  | if (mec_tcr & 0x100000) | 
|  | if (data & 0xFFFFEFC0) mecparerror(); | 
|  | mec_ersr = data & 0x103f; | 
|  | break; | 
|  |  | 
|  | case MEC_TCR:		/* 0xD0 */ | 
|  | if (data & 0xFFE1FFC0) mecparerror(); | 
|  | mec_tcr = data & 0x1e003f; | 
|  | break; | 
|  |  | 
|  | case MEC_WDOG:		/* 0x60 */ | 
|  | 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:		/* 0x64 */ | 
|  | 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: | 
|  | set_sfsr(MEC_ACC, addr, 0xb, 0); | 
|  | return 1; | 
|  | break; | 
|  | } | 
|  | return MOK; | 
|  | } | 
|  |  | 
|  |  | 
|  | /* MEC UARTS */ | 
|  |  | 
|  | static int      ifd1 = -1, ifd2 = -1, ofd1 = -1, ofd2 = -1; | 
|  |  | 
|  | void | 
|  | init_stdio(void) | 
|  | { | 
|  | if (dumbio) | 
|  | return; /* do nothing */ | 
|  | #ifdef HAVE_TERMIOS_H | 
|  | if (!ifd1) | 
|  | tcsetattr(0, TCSANOW, &ioc1); | 
|  | if (!ifd2) | 
|  | tcsetattr(0, TCSANOW, &ioc2); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | void | 
|  | restore_stdio(void) | 
|  | { | 
|  | if (dumbio) | 
|  | return; /* do nothing */ | 
|  | #ifdef HAVE_TERMIOS_H | 
|  | if (!ifd1) | 
|  | tcsetattr(0, TCSANOW, &iocold1); | 
|  | if (!ifd2) | 
|  | tcsetattr(0, TCSANOW, &iocold2); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | #define DO_STDIO_READ( _fd_, _buf_, _len_ )          \ | 
|  | ( dumbio                                \ | 
|  | ? (0) /* no bytes read, no delay */   \ | 
|  | : read( _fd_, _buf_, _len_ ) ) | 
|  |  | 
|  |  | 
|  | static void | 
|  | port_init(void) | 
|  | { | 
|  |  | 
|  | if (uben) { | 
|  | f2in = stdin; | 
|  | f1in = NULL; | 
|  | f2out = stdout; | 
|  | f1out = NULL; | 
|  | } else { | 
|  | f1in = stdin; | 
|  | f2in = NULL; | 
|  | f1out = stdout; | 
|  | f2out = NULL; | 
|  | } | 
|  | if (uart_dev1[0] != 0) { | 
|  | if ((fd1 = open(uart_dev1, O_RDWR | O_NONBLOCK)) < 0) { | 
|  | printf("Warning, couldn't open output device %s\n", uart_dev1); | 
|  | } else { | 
|  | if (sis_verbose) | 
|  | printf("serial port A on %s\n", uart_dev1); | 
|  | f1in = f1out = fdopen(fd1, "r+"); | 
|  | setbuf(f1out, NULL); | 
|  | f1open = 1; | 
|  | } | 
|  | } | 
|  | if (f1in) ifd1 = fileno(f1in); | 
|  | if (ifd1 == 0) { | 
|  | if (sis_verbose) | 
|  | printf("serial port A on stdin/stdout\n"); | 
|  | if (!dumbio) { | 
|  | #ifdef HAVE_TERMIOS_H | 
|  | tcgetattr(ifd1, &ioc1); | 
|  | iocold1 = ioc1; | 
|  | ioc1.c_lflag &= ~(ICANON | ECHO); | 
|  | ioc1.c_cc[VMIN] = 0; | 
|  | ioc1.c_cc[VTIME] = 0; | 
|  | #endif | 
|  | } | 
|  | f1open = 1; | 
|  | } | 
|  |  | 
|  | if (f1out) { | 
|  | ofd1 = fileno(f1out); | 
|  | if (!dumbio && ofd1 == 1) setbuf(f1out, NULL); | 
|  | } | 
|  |  | 
|  | if (uart_dev2[0] != 0) { | 
|  | if ((fd2 = open(uart_dev2, O_RDWR | O_NONBLOCK)) < 0) { | 
|  | printf("Warning, couldn't open output device %s\n", uart_dev2); | 
|  | } else { | 
|  | if (sis_verbose) | 
|  | printf("serial port B on %s\n", uart_dev2); | 
|  | f2in = f2out = fdopen(fd2, "r+"); | 
|  | setbuf(f2out, NULL); | 
|  | f2open = 1; | 
|  | } | 
|  | } | 
|  | if (f2in)  ifd2 = fileno(f2in); | 
|  | if (ifd2 == 0) { | 
|  | if (sis_verbose) | 
|  | printf("serial port B on stdin/stdout\n"); | 
|  | if (!dumbio) { | 
|  | #ifdef HAVE_TERMIOS_H | 
|  | tcgetattr(ifd2, &ioc2); | 
|  | iocold2 = ioc2; | 
|  | ioc2.c_lflag &= ~(ICANON | ECHO); | 
|  | ioc2.c_cc[VMIN] = 0; | 
|  | ioc2.c_cc[VTIME] = 0; | 
|  | #endif | 
|  | } | 
|  | f2open = 1; | 
|  | } | 
|  |  | 
|  | if (f2out) { | 
|  | ofd2 = fileno(f2out); | 
|  | if (!dumbio && ofd2 == 1) setbuf(f2out, NULL); | 
|  | } | 
|  |  | 
|  | wnuma = wnumb = 0; | 
|  |  | 
|  | } | 
|  |  | 
|  | static uint32_t | 
|  | read_uart(uint32_t addr) | 
|  | { | 
|  |  | 
|  | unsigned        tmp; | 
|  |  | 
|  | tmp = 0; | 
|  | switch (addr & 0xff) { | 
|  |  | 
|  | case 0xE0:			/* UART 1 */ | 
|  | #ifndef _WIN32 | 
|  | #ifdef FAST_UART | 
|  |  | 
|  | if (aind < anum) { | 
|  | if ((aind + 1) < anum) | 
|  | mec_irq(4); | 
|  | return (0x700 | (uint32_t) aq[aind++]); | 
|  | } else { | 
|  | if (f1open) { | 
|  | anum = DO_STDIO_READ(ifd1, aq, UARTBUF); | 
|  | } | 
|  | if (anum > 0) { | 
|  | aind = 0; | 
|  | if ((aind + 1) < anum) | 
|  | mec_irq(4); | 
|  | return (0x700 | (uint32_t) aq[aind++]); | 
|  | } else { | 
|  | return (0x600 | (uint32_t) aq[aind]); | 
|  | } | 
|  |  | 
|  | } | 
|  | #else | 
|  | tmp = uarta_data; | 
|  | uarta_data &= ~UART_DR; | 
|  | uart_stat_reg &= ~UARTA_DR; | 
|  | return tmp; | 
|  | #endif | 
|  | #else | 
|  | return 0; | 
|  | #endif | 
|  | break; | 
|  |  | 
|  | case 0xE4:			/* UART 2 */ | 
|  | #ifndef _WIN32 | 
|  | #ifdef FAST_UART | 
|  | if (bind < bnum) { | 
|  | if ((bind + 1) < bnum) | 
|  | mec_irq(5); | 
|  | return (0x700 | (uint32_t) bq[bind++]); | 
|  | } else { | 
|  | if (f2open) { | 
|  | bnum = DO_STDIO_READ(ifd2, bq, UARTBUF); | 
|  | } | 
|  | if (bnum > 0) { | 
|  | bind = 0; | 
|  | if ((bind + 1) < bnum) | 
|  | mec_irq(5); | 
|  | return (0x700 | (uint32_t) bq[bind++]); | 
|  | } else { | 
|  | return (0x600 | (uint32_t) bq[bind]); | 
|  | } | 
|  |  | 
|  | } | 
|  | #else | 
|  | tmp = uartb_data; | 
|  | uartb_data &= ~UART_DR; | 
|  | uart_stat_reg &= ~UARTB_DR; | 
|  | return tmp; | 
|  | #endif | 
|  | #else | 
|  | return 0; | 
|  | #endif | 
|  | break; | 
|  |  | 
|  | case 0xE8:			/* UART status register	 */ | 
|  | #ifndef _WIN32 | 
|  | #ifdef FAST_UART | 
|  |  | 
|  | Ucontrol = 0; | 
|  | if (aind < anum) { | 
|  | Ucontrol |= 0x00000001; | 
|  | } else { | 
|  | if (f1open) { | 
|  | anum = DO_STDIO_READ(ifd1, aq, UARTBUF); | 
|  | } | 
|  | if (anum > 0) { | 
|  | Ucontrol |= 0x00000001; | 
|  | aind = 0; | 
|  | mec_irq(4); | 
|  | } | 
|  | } | 
|  | if (bind < bnum) { | 
|  | Ucontrol |= 0x00010000; | 
|  | } else { | 
|  | if (f2open) { | 
|  | bnum = DO_STDIO_READ(ifd2, bq, UARTBUF); | 
|  | } | 
|  | if (bnum > 0) { | 
|  | Ucontrol |= 0x00010000; | 
|  | bind = 0; | 
|  | mec_irq(5); | 
|  | } | 
|  | } | 
|  |  | 
|  | Ucontrol |= 0x00060006; | 
|  | return Ucontrol; | 
|  | #else | 
|  | return uart_stat_reg; | 
|  | #endif | 
|  | #else | 
|  | return 0x00060006; | 
|  | #endif | 
|  | break; | 
|  | default: | 
|  | if (sis_verbose) | 
|  | printf("Read from unimplemented MEC register (%x)\n", addr); | 
|  |  | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void | 
|  | write_uart(uint32_t addr, uint32_t data) | 
|  | { | 
|  | unsigned char   c; | 
|  |  | 
|  | c = (unsigned char) data; | 
|  | switch (addr & 0xff) { | 
|  |  | 
|  | case 0xE0:			/* UART A */ | 
|  | #ifdef FAST_UART | 
|  | if (f1open) { | 
|  | if (wnuma < UARTBUF) | 
|  | wbufa[wnuma++] = c; | 
|  | else { | 
|  | while (wnuma) | 
|  | wnuma -= fwrite(wbufa, 1, wnuma, f1out); | 
|  | 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 (f2open) { | 
|  | if (wnumb < UARTBUF) | 
|  | wbufb[wnumb++] = c; | 
|  | else { | 
|  | while (wnumb) | 
|  | wnumb -= fwrite(wbufb, 1, wnumb, f2out); | 
|  | 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); | 
|  |  | 
|  | } | 
|  | } | 
|  |  | 
|  | static void | 
|  | flush_uart(void) | 
|  | { | 
|  | while (wnuma && f1open) | 
|  | wnuma -= fwrite(wbufa, 1, wnuma, f1out); | 
|  | while (wnumb && f2open) | 
|  | wnumb -= fwrite(wbufb, 1, wnumb, f2out); | 
|  | } | 
|  |  | 
|  | ATTRIBUTE_UNUSED | 
|  | static void | 
|  | uarta_tx(void) | 
|  | { | 
|  |  | 
|  | while (f1open && fwrite(&uarta_sreg, 1, 1, f1out) != 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); | 
|  | } | 
|  |  | 
|  | ATTRIBUTE_UNUSED | 
|  | static void | 
|  | uartb_tx(void) | 
|  | { | 
|  | while (f2open && fwrite(&uartb_sreg, 1, 1, f2out) != 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); | 
|  | } | 
|  |  | 
|  | ATTRIBUTE_UNUSED | 
|  | static void | 
|  | uart_rx(void *arg) | 
|  | { | 
|  | int32_t           rsize; | 
|  | char            rxd; | 
|  |  | 
|  |  | 
|  | rsize = 0; | 
|  | if (f1open) | 
|  | rsize = DO_STDIO_READ(ifd1, &rxd, 1); | 
|  | if (rsize > 0) { | 
|  | 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 = 0; | 
|  | if (f2open) | 
|  | rsize = DO_STDIO_READ(ifd2, &rxd, 1); | 
|  | 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); | 
|  | } | 
|  |  | 
|  | static void | 
|  | uart_intr(void *arg) | 
|  | { | 
|  | read_uart(0xE8);		/* Check for UART interrupts every 1000 clk */ | 
|  | flush_uart();		/* Flush UART ports      */ | 
|  | event(uart_intr, 0, UART_FLUSH_TIME); | 
|  | } | 
|  |  | 
|  |  | 
|  | static void | 
|  | uart_irq_start(void) | 
|  | { | 
|  | #ifdef FAST_UART | 
|  | event(uart_intr, 0, UART_FLUSH_TIME); | 
|  | #else | 
|  | #ifndef _WIN32 | 
|  | event(uart_rx, 0, UART_RX_TIME); | 
|  | #endif | 
|  | #endif | 
|  | } | 
|  |  | 
|  | /* Watch-dog */ | 
|  |  | 
|  | static void | 
|  | wdog_intr(void *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); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void | 
|  | wdog_start(void) | 
|  | { | 
|  | event(wdog_intr, 0, wdog_scaler + 1); | 
|  | if (sis_verbose) | 
|  | printf("Watchdog started, scaler = %d, counter = %d\n", | 
|  | wdog_scaler, wdog_counter); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* MEC timers */ | 
|  |  | 
|  |  | 
|  | static void | 
|  | rtc_intr(void *arg) | 
|  | { | 
|  | if (rtc_counter == 0) { | 
|  |  | 
|  | mec_irq(13); | 
|  | if (rtc_cr) | 
|  | rtc_counter = rtc_reload; | 
|  | else | 
|  | rtc_se = 0; | 
|  | } else | 
|  | rtc_counter -= 1; | 
|  | if (rtc_se) { | 
|  | event(rtc_intr, 0, rtc_scaler + 1); | 
|  | rtc_scaler_start = now(); | 
|  | rtc_enabled = 1; | 
|  | } else { | 
|  | if (sis_verbose) | 
|  | printf("RTC stopped\n\r"); | 
|  | rtc_enabled = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void | 
|  | rtc_start(void) | 
|  | { | 
|  | if (sis_verbose) | 
|  | printf("RTC started (period %d)\n\r", rtc_scaler + 1); | 
|  | event(rtc_intr, 0, rtc_scaler + 1); | 
|  | rtc_scaler_start = now(); | 
|  | rtc_enabled = 1; | 
|  | } | 
|  |  | 
|  | static uint32_t | 
|  | rtc_counter_read(void) | 
|  | { | 
|  | return rtc_counter; | 
|  | } | 
|  |  | 
|  | static void | 
|  | rtc_scaler_set(uint32_t val) | 
|  | { | 
|  | rtc_scaler = val & 0x0ff;	/* eight-bit scaler only */ | 
|  | } | 
|  |  | 
|  | static void | 
|  | rtc_reload_set(uint32_t val) | 
|  | { | 
|  | rtc_reload = val; | 
|  | } | 
|  |  | 
|  | static void | 
|  | gpt_intr(void *arg) | 
|  | { | 
|  | if (gpt_counter == 0) { | 
|  | mec_irq(12); | 
|  | if (gpt_cr) | 
|  | gpt_counter = gpt_reload; | 
|  | else | 
|  | gpt_se = 0; | 
|  | } else | 
|  | gpt_counter -= 1; | 
|  | if (gpt_se) { | 
|  | event(gpt_intr, 0, gpt_scaler + 1); | 
|  | gpt_scaler_start = now(); | 
|  | gpt_enabled = 1; | 
|  | } else { | 
|  | if (sis_verbose) | 
|  | printf("GPT stopped\n\r"); | 
|  | gpt_enabled = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | static void | 
|  | gpt_start(void) | 
|  | { | 
|  | if (sis_verbose) | 
|  | printf("GPT started (period %d)\n\r", gpt_scaler + 1); | 
|  | event(gpt_intr, 0, gpt_scaler + 1); | 
|  | gpt_scaler_start = now(); | 
|  | gpt_enabled = 1; | 
|  | } | 
|  |  | 
|  | static uint32_t | 
|  | gpt_counter_read(void) | 
|  | { | 
|  | return gpt_counter; | 
|  | } | 
|  |  | 
|  | static void | 
|  | gpt_scaler_set(uint32_t val) | 
|  | { | 
|  | gpt_scaler = val & 0x0ffff;	/* 16-bit scaler */ | 
|  | } | 
|  |  | 
|  | static void | 
|  | gpt_reload_set(uint32_t val) | 
|  | { | 
|  | gpt_reload = val; | 
|  | } | 
|  |  | 
|  | static void | 
|  | timer_ctrl(uint32_t val) | 
|  | { | 
|  |  | 
|  | rtc_cr = ((val & TCR_TCRCR) != 0); | 
|  | if (val & TCR_TCRCL) { | 
|  | rtc_counter = rtc_reload; | 
|  | } | 
|  | if (val & TCR_TCRSL) { | 
|  | } | 
|  | rtc_se = ((val & TCR_TCRSE) != 0); | 
|  | if (rtc_se && (rtc_enabled == 0)) | 
|  | rtc_start(); | 
|  |  | 
|  | gpt_cr = (val & TCR_GACR); | 
|  | if (val & TCR_GACL) { | 
|  | gpt_counter = gpt_reload; | 
|  | } | 
|  | if (val & TCR_GACL) { | 
|  | } | 
|  | gpt_se = (val & TCR_GASE) >> 2; | 
|  | if (gpt_se && (gpt_enabled == 0)) | 
|  | gpt_start(); | 
|  | } | 
|  |  | 
|  | /* Store data in host byte order.  MEM points to the beginning of the | 
|  | emulated memory; WADDR contains the index the emulated memory, | 
|  | DATA points to words in host byte order to be stored.  SZ contains log(2) | 
|  | of the number of bytes to retrieve, and can be 0 (1 byte), 1 (one half-word), | 
|  | 2 (one word), or 3 (two words); WS should return the number of | 
|  | wait-states.  */ | 
|  |  | 
|  | static void | 
|  | store_bytes (unsigned char *mem, uint32_t waddr, uint32_t *data, int32_t sz, | 
|  | int32_t *ws) | 
|  | { | 
|  | switch (sz) { | 
|  | case 0: | 
|  | waddr ^= EBT; | 
|  | mem[waddr] = *data & 0x0ff; | 
|  | *ws = mem_ramw_ws + 3; | 
|  | break; | 
|  | case 1: | 
|  | #ifdef HOST_LITTLE_ENDIAN | 
|  | waddr ^= 2; | 
|  | #endif | 
|  | memcpy (&mem[waddr], data, 2); | 
|  | *ws = mem_ramw_ws + 3; | 
|  | break; | 
|  | case 2: | 
|  | memcpy (&mem[waddr], data, 4); | 
|  | *ws = mem_ramw_ws; | 
|  | break; | 
|  | case 3: | 
|  | memcpy (&mem[waddr], data, 8); | 
|  | *ws = 2 * mem_ramw_ws + STD_WS; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Memory emulation */ | 
|  |  | 
|  | int | 
|  | memory_iread (uint32_t addr, uint32_t *data, uint32_t *ws) | 
|  | { | 
|  | uint32_t          asi; | 
|  | if ((addr >= mem_ramstart) && (addr < (mem_ramstart + mem_ramsz))) { | 
|  | memcpy (data, &ramb[addr & mem_rammask & ~3], 4); | 
|  | *ws = mem_ramr_ws; | 
|  | return 0; | 
|  | } else if (addr < mem_romsz) { | 
|  | memcpy (data, &romb[addr & ~3], 4); | 
|  | *ws = mem_romr_ws; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if (sis_verbose) | 
|  | printf ("Memory exception at %x (illegal address)\n", addr); | 
|  | if (sregs.psr & 0x080) | 
|  | asi = 9; | 
|  | else | 
|  | asi = 8; | 
|  | set_sfsr (UIMP_ACC, addr, asi, 1); | 
|  | *ws = MEM_EX_WS; | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | int | 
|  | memory_read(int32_t asi, uint32_t addr, void *data, int32_t sz, int32_t *ws) | 
|  | { | 
|  | int32_t           mexc; | 
|  |  | 
|  | #ifdef ERRINJ | 
|  | if (errmec) { | 
|  | if (sis_verbose) | 
|  | printf("Inserted MEC error %d\n",errmec); | 
|  | set_sfsr(errmec, addr, asi, 1); | 
|  | if (errmec == 5) mecparerror(); | 
|  | if (errmec == 6) iucomperr(); | 
|  | errmec = 0; | 
|  | return 1; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | if ((addr >= mem_ramstart) && (addr < (mem_ramstart + mem_ramsz))) { | 
|  | memcpy (data, &ramb[addr & mem_rammask & ~3], 4); | 
|  | *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; | 
|  |  | 
|  | #ifdef ERA | 
|  |  | 
|  | } else if (era) { | 
|  | if ((addr < 0x100000) || | 
|  | ((addr>= 0x80000000) && (addr < 0x80100000))) { | 
|  | memcpy (data, &romb[addr & ROM_MASK & ~3], 4); | 
|  | *ws = 4; | 
|  | return 0; | 
|  | } else if ((addr >= 0x10000000) && | 
|  | (addr < (0x10000000 + (512 << (mec_iocr & 0x0f)))) && | 
|  | (mec_iocr & 0x10))  { | 
|  | memcpy (data, &erareg, 4); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | } else  if (addr < mem_romsz) { | 
|  | memcpy (data, &romb[addr & ~3], 4); | 
|  | *ws = mem_romr_ws; | 
|  | return 0; | 
|  | #else | 
|  | } else if (addr < mem_romsz) { | 
|  | memcpy (data, &romb[addr & ~3], 4); | 
|  | *ws = mem_romr_ws; | 
|  | return 0; | 
|  | #endif | 
|  |  | 
|  | } | 
|  |  | 
|  | if (sis_verbose) | 
|  | 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(int32_t asi, uint32_t addr, uint32_t *data, int32_t sz, int32_t *ws) | 
|  | { | 
|  | uint32_t          byte_addr; | 
|  | uint32_t          byte_mask; | 
|  | uint32_t          waddr; | 
|  | uint32_t         *ram; | 
|  | int32_t           mexc; | 
|  | int             i; | 
|  | int             wphit[2]; | 
|  |  | 
|  | #ifdef ERRINJ | 
|  | if (errmec) { | 
|  | if (sis_verbose) | 
|  | printf("Inserted MEC error %d\n",errmec); | 
|  | set_sfsr(errmec, addr, asi, 0); | 
|  | if (errmec == 5) mecparerror(); | 
|  | if (errmec == 6) iucomperr(); | 
|  | errmec = 0; | 
|  | return 1; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | if ((addr >= mem_ramstart) && (addr < (mem_ramstart + mem_ramsz))) { | 
|  | if (mem_accprot) { | 
|  |  | 
|  | waddr = (addr & 0x7fffff) >> 2; | 
|  | for (i = 0; i < 2; i++) | 
|  | wphit[i] = | 
|  | (((asi == 0xa) && (mec_wpr[i] & 1)) || | 
|  | ((asi == 0xb) && (mec_wpr[i] & 2))) && | 
|  | ((waddr >= mec_ssa[i]) && ((waddr | (sz == 3)) < mec_sea[i])); | 
|  |  | 
|  | if (((mem_blockprot) && (wphit[0] || wphit[1])) || | 
|  | ((!mem_blockprot) && | 
|  | !((mec_wpr[0] && wphit[0]) || (mec_wpr[1] && wphit[1])) | 
|  | )) { | 
|  | if (sis_verbose) | 
|  | printf("Memory access protection error at 0x%08x\n", addr); | 
|  | set_sfsr(PROT_EXC, addr, asi, 0); | 
|  | *ws = MEM_EX_WS; | 
|  | return 1; | 
|  | } | 
|  | } | 
|  | waddr = addr & mem_rammask; | 
|  | store_bytes (ramb, waddr, data, sz, ws); | 
|  | 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; | 
|  |  | 
|  | #ifdef ERA | 
|  |  | 
|  | } else if (era) { | 
|  | if ((erareg & 2) && | 
|  | ((addr < 0x100000) || ((addr >= 0x80000000) && (addr < 0x80100000)))) { | 
|  | addr &= ROM_MASK; | 
|  | *ws = sz == 3 ? 8 : 4; | 
|  | store_bytes (romb, addr, data, sz, ws); | 
|  | return 0; | 
|  | } else if ((addr >= 0x10000000) && | 
|  | (addr < (0x10000000 + (512 << (mec_iocr & 0x0f)))) && | 
|  | (mec_iocr & 0x10))  { | 
|  | erareg = *data & 0x0e; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | } else if ((addr < mem_romsz) && (mec_memcfg & 0x10000) && (wrp) && | 
|  | (((mec_memcfg & 0x20000) && (sz > 1)) || | 
|  | (!(mec_memcfg & 0x20000) && (sz == 0)))) { | 
|  |  | 
|  | *ws = mem_romw_ws + 1; | 
|  | if (sz == 3) | 
|  | *ws += mem_romw_ws + STD_WS; | 
|  | store_bytes (romb, addr, data, sz, ws); | 
|  | return 0; | 
|  |  | 
|  | #else | 
|  | } else if ((addr < mem_romsz) && (mec_memcfg & 0x10000) && (wrp) && | 
|  | (((mec_memcfg & 0x20000) && (sz > 1)) || | 
|  | (!(mec_memcfg & 0x20000) && (sz == 0)))) { | 
|  |  | 
|  | *ws = mem_romw_ws + 1; | 
|  | if (sz == 3) | 
|  | *ws += mem_romw_ws + STD_WS; | 
|  | store_bytes (romb, addr, data, sz, ws); | 
|  | return 0; | 
|  |  | 
|  | #endif | 
|  |  | 
|  | } | 
|  |  | 
|  | *ws = MEM_EX_WS; | 
|  | set_sfsr(UIMP_ACC, addr, asi, 0); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static void  * | 
|  | get_mem_ptr(uint32_t addr, uint32_t size) | 
|  | { | 
|  | if ((addr + size) < ROM_SZ) { | 
|  | return &romb[addr]; | 
|  | } else if ((addr >= mem_ramstart) && ((addr + size) < mem_ramend)) { | 
|  | return &ramb[addr & mem_rammask]; | 
|  | } | 
|  |  | 
|  | #ifdef ERA | 
|  | else if ((era) && ((addr <0x100000) || | 
|  | ((addr >= (unsigned) 0x80000000) && ((addr + size) < (unsigned) 0x80100000)))) { | 
|  | return &romb[addr & ROM_MASK]; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | return (void *) -1; | 
|  | } | 
|  |  | 
|  | int | 
|  | sis_memory_write(uint32_t addr, const void *data, uint32_t length) | 
|  | { | 
|  | void           *mem; | 
|  |  | 
|  | if ((mem = get_mem_ptr(addr, length)) == ((void *) -1)) | 
|  | return 0; | 
|  |  | 
|  | memcpy(mem, data, length); | 
|  | return length; | 
|  | } | 
|  |  | 
|  | int | 
|  | sis_memory_read(uint32_t addr, void *data, uint32_t length) | 
|  | { | 
|  | char           *mem; | 
|  |  | 
|  | if ((mem = get_mem_ptr(addr, length)) == ((void *) -1)) | 
|  | return 0; | 
|  |  | 
|  | memcpy(data, mem, length); | 
|  | return length; | 
|  | } | 
|  |  | 
|  | extern struct pstate sregs; | 
|  |  | 
|  | void | 
|  | boot_init (void) | 
|  | { | 
|  | mec_write(MEC_WCR, 0);	/* zero waitstates */ | 
|  | mec_write(MEC_TRAPD, 0);	/* turn off watch-dog */ | 
|  | mec_write(MEC_RTC_SCALER, sregs.freq - 1); /* generate 1 MHz RTC tick */ | 
|  | mec_write(MEC_MEMCFG, (3 << 18) | (4 << 10)); /* 1 MB ROM, 4 MB RAM */ | 
|  | sregs.wim = 2; | 
|  | sregs.psr = 0x110010e0; | 
|  | sregs.r[30] = RAM_END; | 
|  | sregs.r[14] = sregs.r[30] - 96 * 4; | 
|  | mec_mcr |= 1;		/* power-down enabled */ | 
|  | } |