1999-04-16 09:35:26 +08:00
/*> interp.c <*/
/* Simulator for the MIPS architecture.
This file is part of the MIPS sim
THIS SOFTWARE IS NOT COPYRIGHTED
Cygnus offers the following for use in the public domain . Cygnus
makes no warranty with regard to the software or it ' s performance
and the user accepts the software " AS IS " with all faults .
CYGNUS DISCLAIMS ANY WARRANTIES , EXPRESS OR IMPLIED , WITH REGARD TO
THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .
$ Revision $
$ Date $
NOTEs :
The IDT monitor ( found on the VR4300 board ) , seems to lie about
register contents . It seems to treat the registers as sign - extended
32 - bit values . This cause * REAL * problems when single - stepping 64 - bit
code on the hardware .
*/
/* The TRACE manifests enable the provision of extra features. If they
are not defined then a simpler ( quicker ) simulator is constructed
without the required run - time checks , etc . */
# if 1 /* 0 to allow user build selection, 1 to force inclusion */
# define TRACE (1)
# endif
# include "bfd.h"
# include "sim-main.h"
# include "sim-utils.h"
# include "sim-options.h"
# include "sim-assert.h"
# include "sim-hw.h"
# include "itable.h"
# include "config.h"
# include <stdio.h>
# include <stdarg.h>
# include <ansidecl.h>
# include <ctype.h>
# include <limits.h>
# include <math.h>
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
# ifdef HAVE_STRING_H
# include <string.h>
# else
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
# endif
# include "getopt.h"
# include "libiberty.h"
# include "bfd.h"
# include "callback.h" /* GDB simulator callback interface */
# include "remote-sim.h" /* GDB simulator interface */
# include "sysdep.h"
# ifndef PARAMS
# define PARAMS(x)
# endif
char * pr_addr PARAMS ( ( SIM_ADDR addr ) ) ;
char * pr_uword64 PARAMS ( ( uword64 addr ) ) ;
/* Within interp.c we refer to the sim_state and sim_cpu directly. */
# define CPU cpu
# define SD sd
/* The following reserved instruction value is used when a simulator
trap is required . NOTE : Care must be taken , since this value may be
used in later revisions of the MIPS ISA . */
# define RSVD_INSTRUCTION (0x00000005)
# define RSVD_INSTRUCTION_MASK (0xFC00003F)
# define RSVD_INSTRUCTION_ARG_SHIFT 6
# define RSVD_INSTRUCTION_ARG_MASK 0xFFFFF
/* Bits in the Debug register */
# define Debug_DBD 0x80000000 /* Debug Branch Delay */
# define Debug_DM 0x40000000 /* Debug Mode */
# define Debug_DBp 0x00000002 /* Debug Breakpoint indicator */
/*---------------------------------------------------------------------------*/
/*-- GDB simulator interface ------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void ColdReset PARAMS ( ( SIM_DESC sd ) ) ;
/*---------------------------------------------------------------------------*/
# define DELAYSLOT() {\
if ( STATE & simDELAYSLOT ) \
sim_io_eprintf ( sd , " Delay slot already activated (branch in delay slot?) \n " ) ; \
STATE | = simDELAYSLOT ; \
}
# define JALDELAYSLOT() {\
DELAYSLOT ( ) ; \
STATE | = simJALDELAYSLOT ; \
}
# define NULLIFY() {\
STATE & = ~ simDELAYSLOT ; \
STATE | = simSKIPNEXT ; \
}
# define CANCELDELAYSLOT() {\
DSSTATE = 0 ; \
STATE & = ~ ( simDELAYSLOT | simJALDELAYSLOT ) ; \
}
# define INDELAYSLOT() ((STATE & simDELAYSLOT) != 0)
# define INJALDELAYSLOT() ((STATE & simJALDELAYSLOT) != 0)
1999-07-20 07:30:11 +08:00
/* Note that the monitor code essentially assumes this layout of memory.
If you change these , change the monitor code , too . */
1999-04-16 09:35:26 +08:00
# define K0BASE (0x80000000)
# define K0SIZE (0x20000000)
# define K1BASE (0xA0000000)
# define K1SIZE (0x20000000)
1999-07-20 07:30:11 +08:00
/* Simple run-time monitor support.
We emulate the monitor by placing magic reserved instructions at
the monitor ' s entry points ; when we hit these instructions , instead
of raising an exception ( as we would normally ) , we look at the
instruction and perform the appropriate monitory operation .
` * _monitor_base ' are the physical addresses at which the corresponding
monitor vectors are located . ` 0 ' means none . By default ,
install all three .
The RSVD_INSTRUCTION . . . macros specify the magic instructions we
use at the monitor entry points . */
static int firmware_option_p = 0 ;
static SIM_ADDR idt_monitor_base = 0xBFC00000 ;
static SIM_ADDR pmon_monitor_base = 0xBFC00500 ;
static SIM_ADDR lsipmon_monitor_base = 0xBFC00200 ;
static SIM_RC sim_firmware_command ( SIM_DESC sd , char * arg ) ;
1999-04-16 09:35:26 +08:00
# define MEM_SIZE (2 << 20)
# if defined(TRACE)
static char * tracefile = " trace.din " ; /* default filename for trace log */
FILE * tracefh = NULL ;
static void open_trace PARAMS ( ( SIM_DESC sd ) ) ;
# endif /* TRACE */
static const char * get_insn_name ( sim_cpu * , int ) ;
/* simulation target board. NULL=canonical */
static char * board = NULL ;
static DECLARE_OPTION_HANDLER ( mips_option_handler ) ;
enum {
OPTION_DINERO_TRACE = OPTION_START ,
OPTION_DINERO_FILE ,
1999-07-20 07:30:11 +08:00
OPTION_FIRMWARE ,
1999-04-16 09:35:26 +08:00
OPTION_BOARD
} ;
static SIM_RC
mips_option_handler ( sd , cpu , opt , arg , is_command )
SIM_DESC sd ;
sim_cpu * cpu ;
int opt ;
char * arg ;
int is_command ;
{
int cpu_nr ;
switch ( opt )
{
case OPTION_DINERO_TRACE : /* ??? */
# if defined(TRACE)
/* Eventually the simTRACE flag could be treated as a toggle, to
allow external control of the program points being traced
( i . e . only from main onwards , excluding the run - time setup ,
etc . ) . */
for ( cpu_nr = 0 ; cpu_nr < MAX_NR_PROCESSORS ; cpu_nr + + )
{
sim_cpu * cpu = STATE_CPU ( sd , cpu_nr ) ;
if ( arg = = NULL )
STATE | = simTRACE ;
else if ( strcmp ( arg , " yes " ) = = 0 )
STATE | = simTRACE ;
else if ( strcmp ( arg , " no " ) = = 0 )
STATE & = ~ simTRACE ;
else if ( strcmp ( arg , " on " ) = = 0 )
STATE | = simTRACE ;
else if ( strcmp ( arg , " off " ) = = 0 )
STATE & = ~ simTRACE ;
else
{
fprintf ( stderr , " Unrecognized dinero-trace option `%s' \n " , arg ) ;
return SIM_RC_FAIL ;
}
}
return SIM_RC_OK ;
# else /* !TRACE */
fprintf ( stderr , " \
Simulator constructed without dinero tracing support ( for performance ) . \ n \
Re - compile simulator with \ " -DTRACE \" to enable this option. \n " ) ;
return SIM_RC_FAIL ;
# endif /* !TRACE */
case OPTION_DINERO_FILE :
# if defined(TRACE)
if ( optarg ! = NULL ) {
char * tmp ;
tmp = ( char * ) malloc ( strlen ( optarg ) + 1 ) ;
if ( tmp = = NULL )
{
sim_io_printf ( sd , " Failed to allocate buffer for tracefile name \" %s \" \n " , optarg ) ;
return SIM_RC_FAIL ;
}
else {
strcpy ( tmp , optarg ) ;
tracefile = tmp ;
sim_io_printf ( sd , " Placing trace information into file \" %s \" \n " , tracefile ) ;
}
}
# endif /* TRACE */
return SIM_RC_OK ;
1999-07-20 07:30:11 +08:00
case OPTION_FIRMWARE :
return sim_firmware_command ( sd , arg ) ;
1999-04-16 09:35:26 +08:00
case OPTION_BOARD :
{
if ( arg )
{
board = zalloc ( strlen ( arg ) + 1 ) ;
strcpy ( board , arg ) ;
}
return SIM_RC_OK ;
}
}
return SIM_RC_OK ;
}
static const OPTION mips_options [ ] =
{
{ { " dinero-trace " , optional_argument , NULL , OPTION_DINERO_TRACE } ,
' \0 ' , " on|off " , " Enable dinero tracing " ,
mips_option_handler } ,
{ { " dinero-file " , required_argument , NULL , OPTION_DINERO_FILE } ,
' \0 ' , " FILE " , " Write dinero trace to FILE " ,
mips_option_handler } ,
1999-07-20 07:30:11 +08:00
{ { " firmware " , required_argument , NULL , OPTION_FIRMWARE } ,
' \0 ' , " [idt|pmon|lsipmon|none][@ADDRESS] " , " Emulate ROM monitor " ,
mips_option_handler } ,
1999-04-16 09:35:26 +08:00
{ { " board " , required_argument , NULL , OPTION_BOARD } ,
' \0 ' , " none " /* rely on compile-time string concatenation for other options */
# define BOARD_JMR3904 "jmr3904"
" | " BOARD_JMR3904
# define BOARD_JMR3904_PAL "jmr3904pal"
" | " BOARD_JMR3904_PAL
# define BOARD_JMR3904_DEBUG "jmr3904debug"
" | " BOARD_JMR3904_DEBUG
1999-07-12 19:15:22 +08:00
# define BOARD_BSP "bsp"
" | " BOARD_BSP
1999-04-16 09:35:26 +08:00
, " Customize simulation for a particular board. " , mips_option_handler } ,
{ { NULL , no_argument , NULL , 0 } , ' \0 ' , NULL , NULL , NULL }
} ;
int interrupt_pending ;
void
interrupt_event ( SIM_DESC sd , void * data )
{
sim_cpu * cpu = STATE_CPU ( sd , 0 ) ; /* FIXME */
address_word cia = CIA_GET ( cpu ) ;
if ( SR & status_IE )
{
interrupt_pending = 0 ;
SignalExceptionInterrupt ( 1 ) ; /* interrupt "1" */
}
else if ( ! interrupt_pending )
sim_events_schedule ( sd , 1 , interrupt_event , data ) ;
}
/*---------------------------------------------------------------------------*/
/*-- Device registration hook -----------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void device_init ( SIM_DESC sd ) {
# ifdef DEVICE_INIT
extern void register_devices ( SIM_DESC ) ;
register_devices ( sd ) ;
# endif
}
/*---------------------------------------------------------------------------*/
/*-- GDB simulator interface ------------------------------------------------*/
/*---------------------------------------------------------------------------*/
SIM_DESC
sim_open ( kind , cb , abfd , argv )
SIM_OPEN_KIND kind ;
host_callback * cb ;
struct _bfd * abfd ;
char * * argv ;
{
SIM_DESC sd = sim_state_alloc ( kind , cb ) ;
sim_cpu * cpu = STATE_CPU ( sd , 0 ) ; /* FIXME */
SIM_ASSERT ( STATE_MAGIC ( sd ) = = SIM_MAGIC_NUMBER ) ;
/* FIXME: watchpoints code shouldn't need this */
STATE_WATCHPOINTS ( sd ) - > pc = & ( PC ) ;
STATE_WATCHPOINTS ( sd ) - > sizeof_pc = sizeof ( PC ) ;
STATE_WATCHPOINTS ( sd ) - > interrupt_handler = interrupt_event ;
/* Initialize the mechanism for doing insn profiling. */
CPU_INSN_NAME ( cpu ) = get_insn_name ;
CPU_MAX_INSNS ( cpu ) = nr_itable_entries ;
STATE = 0 ;
if ( sim_pre_argv_init ( sd , argv [ 0 ] ) ! = SIM_RC_OK )
return 0 ;
sim_add_option_table ( sd , NULL , mips_options ) ;
/* getopt will print the error message so we just have to exit if this fails.
FIXME : Hmmm . . . in the case of gdb we need getopt to call
print_filtered . */
if ( sim_parse_args ( sd , argv ) ! = SIM_RC_OK )
{
/* Uninstall the modules to avoid memory leaks,
file descriptor leaks , etc . */
sim_module_uninstall ( sd ) ;
return 0 ;
}
/* handle board-specific memory maps */
if ( board = = NULL )
{
/* Allocate core managed memory */
1999-07-20 07:30:11 +08:00
1999-04-16 09:35:26 +08:00
/* For compatibility with the old code - under this (at level one)
are the kernel spaces K0 & K1 . Both of these map to a single
smaller sub region */
sim_do_command ( sd , " memory region 0x7fff8000,0x8000 " ) ; /* MTZ- 32 k stack */
sim_do_commandf ( sd , " memory alias 0x%lx@1,0x%lx%%0x%lx,0x%0x " ,
K1BASE , K0SIZE ,
MEM_SIZE , /* actual size */
K0BASE ) ;
device_init ( sd ) ;
}
1999-07-12 19:15:22 +08:00
else if ( board ! = NULL
& & ( strcmp ( board , BOARD_BSP ) = = 0 ) )
{
int i ;
STATE_ENVIRONMENT ( sd ) = OPERATING_ENVIRONMENT ;
/* ROM: 0x9FC0_0000 - 0x9FFF_FFFF and 0xBFC0_0000 - 0xBFFF_FFFF */
sim_do_commandf ( sd , " memory alias 0x%lx@1,0x%lx,0x%0x " ,
0x9FC00000 ,
4 * 1024 * 1024 , /* 4 MB */
0xBFC00000 ) ;
/* SRAM: 0x8000_0000 - 0x803F_FFFF and 0xA000_0000 - 0xA03F_FFFF */
sim_do_commandf ( sd , " memory alias 0x%lx@1,0x%lx,0x%0x " ,
0x80000000 ,
4 * 1024 * 1024 , /* 4 MB */
0xA0000000 ) ;
/* DRAM: 0x8800_0000 - 0x89FF_FFFF and 0xA800_0000 - 0xA9FF_FFFF */
for ( i = 0 ; i < 8 ; i + + ) /* 32 MB total */
{
unsigned size = 4 * 1024 * 1024 ; /* 4 MB */
sim_do_commandf ( sd , " memory alias 0x%lx@1,0x%lx,0x%0x " ,
0x88000000 + ( i * size ) ,
size ,
0xA8000000 + ( i * size ) ) ;
}
}
1999-04-16 09:35:26 +08:00
# if (WITH_HW)
1999-07-12 19:15:22 +08:00
else if ( board ! = NULL
& & ( strcmp ( board , BOARD_JMR3904 ) = = 0 | |
strcmp ( board , BOARD_JMR3904_PAL ) = = 0 | |
strcmp ( board , BOARD_JMR3904_DEBUG ) = = 0 ) )
1999-04-16 09:35:26 +08:00
{
/* match VIRTUAL memory layout of JMR-TX3904 board */
int i ;
1999-07-20 07:30:11 +08:00
/* --- disable monitor unless forced on by user --- */
if ( ! firmware_option_p )
{
idt_monitor_base = 0 ;
pmon_monitor_base = 0 ;
lsipmon_monitor_base = 0 ;
}
1999-04-16 09:35:26 +08:00
/* --- environment --- */
STATE_ENVIRONMENT ( sd ) = OPERATING_ENVIRONMENT ;
/* --- memory --- */
/* ROM: 0x9FC0_0000 - 0x9FFF_FFFF and 0xBFC0_0000 - 0xBFFF_FFFF */
sim_do_commandf ( sd , " memory alias 0x%lx@1,0x%lx,0x%0x " ,
0x9FC00000 ,
4 * 1024 * 1024 , /* 4 MB */
0xBFC00000 ) ;
/* SRAM: 0x8000_0000 - 0x803F_FFFF and 0xA000_0000 - 0xA03F_FFFF */
sim_do_commandf ( sd , " memory alias 0x%lx@1,0x%lx,0x%0x " ,
0x80000000 ,
4 * 1024 * 1024 , /* 4 MB */
0xA0000000 ) ;
/* DRAM: 0x8800_0000 - 0x89FF_FFFF and 0xA800_0000 - 0xA9FF_FFFF */
for ( i = 0 ; i < 8 ; i + + ) /* 32 MB total */
{
unsigned size = 4 * 1024 * 1024 ; /* 4 MB */
sim_do_commandf ( sd , " memory alias 0x%lx@1,0x%lx,0x%0x " ,
0x88000000 + ( i * size ) ,
size ,
0xA8000000 + ( i * size ) ) ;
}
/* Dummy memory regions for unsimulated devices */
sim_do_commandf ( sd , " memory alias 0x%lx@1,0x%lx " , 0xFFFFE010 , 0x00c ) ; /* EBIF */
sim_do_commandf ( sd , " memory alias 0x%lx@1,0x%lx " , 0xFFFF9000 , 0x200 ) ; /* EBIF */
sim_do_commandf ( sd , " memory alias 0x%lx@1,0x%lx " , 0xFFFFF500 , 0x300 ) ; /* PIO */
/* --- simulated devices --- */
sim_hw_parse ( sd , " /tx3904irc@0xffffc000/reg 0xffffc000 0x20 " ) ;
sim_hw_parse ( sd , " /tx3904cpu " ) ;
sim_hw_parse ( sd , " /tx3904tmr@0xfffff000/reg 0xfffff000 0x100 " ) ;
sim_hw_parse ( sd , " /tx3904tmr@0xfffff100/reg 0xfffff100 0x100 " ) ;
sim_hw_parse ( sd , " /tx3904tmr@0xfffff200/reg 0xfffff200 0x100 " ) ;
sim_hw_parse ( sd , " /tx3904sio@0xfffff300/reg 0xfffff300 0x100 " ) ;
{
/* FIXME: poking at dv-sockser internals, use tcp backend if
- - sockser_addr option was given . */
extern char * sockser_addr ;
if ( sockser_addr = = NULL )
sim_hw_parse ( sd , " /tx3904sio@0xfffff300/backend stdio " ) ;
else
sim_hw_parse ( sd , " /tx3904sio@0xfffff300/backend tcp " ) ;
}
sim_hw_parse ( sd , " /tx3904sio@0xfffff400/reg 0xfffff400 0x100 " ) ;
sim_hw_parse ( sd , " /tx3904sio@0xfffff400/backend stdio " ) ;
/* -- device connections --- */
sim_hw_parse ( sd , " /tx3904irc > ip level /tx3904cpu " ) ;
sim_hw_parse ( sd , " /tx3904tmr@0xfffff000 > int tmr0 /tx3904irc " ) ;
sim_hw_parse ( sd , " /tx3904tmr@0xfffff100 > int tmr1 /tx3904irc " ) ;
sim_hw_parse ( sd , " /tx3904tmr@0xfffff200 > int tmr2 /tx3904irc " ) ;
sim_hw_parse ( sd , " /tx3904sio@0xfffff300 > int sio0 /tx3904irc " ) ;
sim_hw_parse ( sd , " /tx3904sio@0xfffff400 > int sio1 /tx3904irc " ) ;
/* add PAL timer & I/O module */
if ( ! strcmp ( board , BOARD_JMR3904_PAL ) )
{
/* the device */
sim_hw_parse ( sd , " /pal@0xffff0000 " ) ;
sim_hw_parse ( sd , " /pal@0xffff0000/reg 0xffff0000 64 " ) ;
/* wire up interrupt ports to irc */
sim_hw_parse ( sd , " /pal@0x31000000 > countdown tmr0 /tx3904irc " ) ;
sim_hw_parse ( sd , " /pal@0x31000000 > timer tmr1 /tx3904irc " ) ;
sim_hw_parse ( sd , " /pal@0x31000000 > int int0 /tx3904irc " ) ;
}
if ( ! strcmp ( board , BOARD_JMR3904_DEBUG ) )
{
/* -- DEBUG: glue interrupt generators --- */
sim_hw_parse ( sd , " /glue@0xffff0000/reg 0xffff0000 0x50 " ) ;
sim_hw_parse ( sd , " /glue@0xffff0000 > int0 int0 /tx3904irc " ) ;
sim_hw_parse ( sd , " /glue@0xffff0000 > int1 int1 /tx3904irc " ) ;
sim_hw_parse ( sd , " /glue@0xffff0000 > int2 int2 /tx3904irc " ) ;
sim_hw_parse ( sd , " /glue@0xffff0000 > int3 int3 /tx3904irc " ) ;
sim_hw_parse ( sd , " /glue@0xffff0000 > int4 int4 /tx3904irc " ) ;
sim_hw_parse ( sd , " /glue@0xffff0000 > int5 int5 /tx3904irc " ) ;
sim_hw_parse ( sd , " /glue@0xffff0000 > int6 int6 /tx3904irc " ) ;
sim_hw_parse ( sd , " /glue@0xffff0000 > int7 int7 /tx3904irc " ) ;
sim_hw_parse ( sd , " /glue@0xffff0000 > int8 dmac0 /tx3904irc " ) ;
sim_hw_parse ( sd , " /glue@0xffff0000 > int9 dmac1 /tx3904irc " ) ;
sim_hw_parse ( sd , " /glue@0xffff0000 > int10 dmac2 /tx3904irc " ) ;
sim_hw_parse ( sd , " /glue@0xffff0000 > int11 dmac3 /tx3904irc " ) ;
sim_hw_parse ( sd , " /glue@0xffff0000 > int12 sio0 /tx3904irc " ) ;
sim_hw_parse ( sd , " /glue@0xffff0000 > int13 sio1 /tx3904irc " ) ;
sim_hw_parse ( sd , " /glue@0xffff0000 > int14 tmr0 /tx3904irc " ) ;
sim_hw_parse ( sd , " /glue@0xffff0000 > int15 tmr1 /tx3904irc " ) ;
sim_hw_parse ( sd , " /glue@0xffff0000 > int16 tmr2 /tx3904irc " ) ;
sim_hw_parse ( sd , " /glue@0xffff0000 > int17 nmi /tx3904cpu " ) ;
}
device_init ( sd ) ;
}
# endif
/* check for/establish the a reference program image */
if ( sim_analyze_program ( sd ,
( STATE_PROG_ARGV ( sd ) ! = NULL
? * STATE_PROG_ARGV ( sd )
: NULL ) ,
abfd ) ! = SIM_RC_OK )
{
sim_module_uninstall ( sd ) ;
return 0 ;
}
/* Configure/verify the target byte order and other runtime
configuration options */
if ( sim_config ( sd ) ! = SIM_RC_OK )
{
sim_module_uninstall ( sd ) ;
return 0 ;
}
if ( sim_post_argv_init ( sd ) ! = SIM_RC_OK )
{
/* Uninstall the modules to avoid memory leaks,
file descriptor leaks , etc . */
sim_module_uninstall ( sd ) ;
return 0 ;
}
/* verify assumptions the simulator made about the host type system.
This macro does not return if there is a problem */
SIM_ASSERT ( sizeof ( int ) = = ( 4 * sizeof ( char ) ) ) ;
SIM_ASSERT ( sizeof ( word64 ) = = ( 8 * sizeof ( char ) ) ) ;
/* This is NASTY, in that we are assuming the size of specific
registers : */
{
int rn ;
for ( rn = 0 ; ( rn < ( LAST_EMBED_REGNUM + 1 ) ) ; rn + + )
{
if ( rn < 32 )
cpu - > register_widths [ rn ] = WITH_TARGET_WORD_BITSIZE ;
else if ( ( rn > = FGRIDX ) & & ( rn < ( FGRIDX + NR_FGR ) ) )
cpu - > register_widths [ rn ] = WITH_TARGET_FLOATING_POINT_BITSIZE ;
else if ( ( rn > = 33 ) & & ( rn < = 37 ) )
cpu - > register_widths [ rn ] = WITH_TARGET_WORD_BITSIZE ;
else if ( ( rn = = SRIDX )
| | ( rn = = FCR0IDX )
| | ( rn = = FCR31IDX )
| | ( ( rn > = 72 ) & & ( rn < = 89 ) ) )
cpu - > register_widths [ rn ] = 32 ;
else
cpu - > register_widths [ rn ] = 0 ;
}
}
# if defined(TRACE)
if ( STATE & simTRACE )
open_trace ( sd ) ;
# endif /* TRACE */
1999-07-20 07:30:11 +08:00
/*
sim_io_eprintf ( sd , " idt@%x pmon@%x lsipmon@%x \n " ,
idt_monitor_base ,
pmon_monitor_base ,
lsipmon_monitor_base ) ;
*/
1999-04-16 09:35:26 +08:00
/* Write the monitor trap address handlers into the monitor (eeprom)
address space . This can only be done once the target endianness
has been determined . */
1999-07-20 07:30:11 +08:00
if ( idt_monitor_base ! = 0 )
{
unsigned loop ;
unsigned idt_monitor_size = 1 < < 11 ;
/* the default monitor region */
sim_do_commandf ( sd , " memory region 0x%x,0x%x " ,
idt_monitor_base , idt_monitor_size ) ;
/* Entry into the IDT monitor is via fixed address vectors, and
not using machine instructions . To avoid clashing with use of
the MIPS TRAP system , we place our own ( simulator specific )
" undefined " instructions into the relevant vector slots . */
for ( loop = 0 ; ( loop < idt_monitor_size ) ; loop + = 4 )
{
address_word vaddr = ( idt_monitor_base + loop ) ;
unsigned32 insn = ( RSVD_INSTRUCTION |
( ( ( loop > > 2 ) & RSVD_INSTRUCTION_ARG_MASK )
< < RSVD_INSTRUCTION_ARG_SHIFT ) ) ;
H2T ( insn ) ;
sim_write ( sd , vaddr , ( char * ) & insn , sizeof ( insn ) ) ;
}
}
if ( ( pmon_monitor_base ! = 0 ) | | ( lsipmon_monitor_base ! = 0 ) )
{
1999-04-16 09:35:26 +08:00
/* The PMON monitor uses the same address space, but rather than
branching into it the address of a routine is loaded . We can
cheat for the moment , and direct the PMON routine to IDT style
instructions within the monitor space . This relies on the IDT
monitor not using the locations from 0xBFC00500 onwards as its
entry points . */
1999-07-20 07:30:11 +08:00
unsigned loop ;
for ( loop = 0 ; ( loop < 24 ) ; loop + + )
{
unsigned32 value = ( ( 0x500 - 8 ) / 8 ) ; /* default UNDEFINED reason code */
switch ( loop )
{
1999-04-16 09:35:26 +08:00
case 0 : /* read */
value = 7 ;
break ;
case 1 : /* write */
value = 8 ;
break ;
case 2 : /* open */
value = 6 ;
break ;
case 3 : /* close */
value = 10 ;
break ;
case 5 : /* printf */
value = ( ( 0x500 - 16 ) / 8 ) ; /* not an IDT reason code */
break ;
case 8 : /* cliexit */
value = 17 ;
break ;
case 11 : /* flush_cache */
value = 28 ;
break ;
}
1999-07-20 07:30:11 +08:00
SIM_ASSERT ( idt_monitor_base ! = 0 ) ;
value = ( ( unsigned int ) idt_monitor_base + ( value * 8 ) ) ;
1999-04-16 09:35:26 +08:00
H2T ( value ) ;
1999-07-20 07:30:11 +08:00
if ( pmon_monitor_base ! = 0 )
{
address_word vaddr = ( pmon_monitor_base + ( loop * 4 ) ) ;
sim_write ( sd , vaddr , ( char * ) & value , sizeof ( value ) ) ;
}
if ( lsipmon_monitor_base ! = 0 )
{
address_word vaddr = ( lsipmon_monitor_base + ( loop * 4 ) ) ;
sim_write ( sd , vaddr , ( char * ) & value , sizeof ( value ) ) ;
}
1999-04-16 09:35:26 +08:00
}
1999-07-20 07:30:11 +08:00
/* Write an abort sequence into the TRAP (common) exception vector
addresses . This is to catch code executing a TRAP ( et . al . )
instruction without installing a trap handler . */
if ( ( idt_monitor_base ! = 0 ) | |
( pmon_monitor_base ! = 0 ) | |
( lsipmon_monitor_base ! = 0 ) )
{
unsigned32 halt [ 2 ] = { 0x2404002f /* addiu r4, r0, 47 */ ,
HALT_INSTRUCTION /* BREAK */ } ;
H2T ( halt [ 0 ] ) ;
H2T ( halt [ 1 ] ) ;
sim_write ( sd , 0x80000000 , ( char * ) halt , sizeof ( halt ) ) ;
sim_write ( sd , 0x80000180 , ( char * ) halt , sizeof ( halt ) ) ;
sim_write ( sd , 0x80000200 , ( char * ) halt , sizeof ( halt ) ) ;
/* XXX: Write here unconditionally? */
sim_write ( sd , 0xBFC00200 , ( char * ) halt , sizeof ( halt ) ) ;
sim_write ( sd , 0xBFC00380 , ( char * ) halt , sizeof ( halt ) ) ;
sim_write ( sd , 0xBFC00400 , ( char * ) halt , sizeof ( halt ) ) ;
}
1999-04-16 09:35:26 +08:00
}
return sd ;
}
# if defined(TRACE)
static void
open_trace ( sd )
SIM_DESC sd ;
{
tracefh = fopen ( tracefile , " wb+ " ) ;
if ( tracefh = = NULL )
{
sim_io_eprintf ( sd , " Failed to create file \" %s \" , writing trace information to stderr. \n " , tracefile ) ;
tracefh = stderr ;
}
}
# endif /* TRACE */
/* Return name of an insn, used by insn profiling. */
static const char *
get_insn_name ( sim_cpu * cpu , int i )
{
return itable [ i ] . name ;
}
void
sim_close ( sd , quitting )
SIM_DESC sd ;
int quitting ;
{
# ifdef DEBUG
printf ( " DBG: sim_close: entered (quitting = %d) \n " , quitting ) ;
# endif
/* "quitting" is non-zero if we cannot hang on errors */
/* shut down modules */
sim_module_uninstall ( sd ) ;
/* Ensure that any resources allocated through the callback
mechanism are released : */
sim_io_shutdown ( sd ) ;
# if defined(TRACE)
if ( tracefh ! = NULL & & tracefh ! = stderr )
fclose ( tracefh ) ;
tracefh = NULL ;
# endif /* TRACE */
/* FIXME - free SD */
return ;
}
int
sim_write ( sd , addr , buffer , size )
SIM_DESC sd ;
SIM_ADDR addr ;
unsigned char * buffer ;
int size ;
{
int index ;
sim_cpu * cpu = STATE_CPU ( sd , 0 ) ; /* FIXME */
/* Return the number of bytes written, or zero if error. */
# ifdef DEBUG
sim_io_printf ( sd , " sim_write(0x%s,buffer,%d); \n " , pr_addr ( addr ) , size ) ;
# endif
/* We use raw read and write routines, since we do not want to count
the GDB memory accesses in our statistics gathering . */
for ( index = 0 ; index < size ; index + + )
{
address_word vaddr = ( address_word ) addr + index ;
address_word paddr ;
int cca ;
if ( ! address_translation ( SD , CPU , NULL_CIA , vaddr , isDATA , isSTORE , & paddr , & cca , isRAW ) )
break ;
if ( sim_core_write_buffer ( SD , CPU , read_map , buffer + index , paddr , 1 ) ! = 1 )
break ;
}
return ( index ) ;
}
int
sim_read ( sd , addr , buffer , size )
SIM_DESC sd ;
SIM_ADDR addr ;
unsigned char * buffer ;
int size ;
{
int index ;
sim_cpu * cpu = STATE_CPU ( sd , 0 ) ; /* FIXME */
/* Return the number of bytes read, or zero if error. */
# ifdef DEBUG
sim_io_printf ( sd , " sim_read(0x%s,buffer,%d); \n " , pr_addr ( addr ) , size ) ;
# endif /* DEBUG */
for ( index = 0 ; ( index < size ) ; index + + )
{
address_word vaddr = ( address_word ) addr + index ;
address_word paddr ;
int cca ;
if ( ! address_translation ( SD , CPU , NULL_CIA , vaddr , isDATA , isLOAD , & paddr , & cca , isRAW ) )
break ;
if ( sim_core_read_buffer ( SD , CPU , read_map , buffer + index , paddr , 1 ) ! = 1 )
break ;
}
return ( index ) ;
}
int
sim_store_register ( sd , rn , memory , length )
SIM_DESC sd ;
int rn ;
unsigned char * memory ;
int length ;
{
sim_cpu * cpu = STATE_CPU ( sd , 0 ) ; /* FIXME */
/* NOTE: gdb (the client) stores registers in target byte order
while the simulator uses host byte order */
# ifdef DEBUG
sim_io_printf ( sd , " sim_store_register(%d,*memory=0x%s); \n " , rn , pr_addr ( * ( ( SIM_ADDR * ) memory ) ) ) ;
# endif /* DEBUG */
/* Unfortunately this suffers from the same problem as the register
numbering one . We need to know what the width of each logical
register number is for the architecture being simulated . */
if ( cpu - > register_widths [ rn ] = = 0 )
{
sim_io_eprintf ( sd , " Invalid register width for %d (register store ignored) \n " , rn ) ;
return 0 ;
}
if ( rn > = FGRIDX & & rn < FGRIDX + NR_FGR )
{
1999-04-27 02:34:20 +08:00
cpu - > fpr_state [ rn - FGRIDX ] = fmt_uninterpreted ;
1999-04-16 09:35:26 +08:00
if ( cpu - > register_widths [ rn ] = = 32 )
{
1999-08-03 07:48:37 +08:00
if ( length = = 8 )
{
cpu - > fgr [ rn - FGRIDX ] =
( unsigned32 ) T2H_8 ( * ( unsigned64 * ) memory ) ;
return 8 ;
}
else
{
cpu - > fgr [ rn - FGRIDX ] = T2H_4 ( * ( unsigned32 * ) memory ) ;
return 4 ;
}
1999-04-16 09:35:26 +08:00
}
else
{
cpu - > fgr [ rn - FGRIDX ] = T2H_8 ( * ( unsigned64 * ) memory ) ;
return 8 ;
}
}
if ( cpu - > register_widths [ rn ] = = 32 )
{
1999-08-03 07:48:37 +08:00
if ( length = = 8 )
{
cpu - > registers [ rn ] =
( unsigned32 ) T2H_8 ( * ( unsigned64 * ) memory ) ;
return 8 ;
}
else
{
cpu - > registers [ rn ] = T2H_4 ( * ( unsigned32 * ) memory ) ;
return 4 ;
}
1999-04-16 09:35:26 +08:00
}
else
{
cpu - > registers [ rn ] = T2H_8 ( * ( unsigned64 * ) memory ) ;
return 8 ;
}
return 0 ;
}
int
sim_fetch_register ( sd , rn , memory , length )
SIM_DESC sd ;
int rn ;
unsigned char * memory ;
int length ;
{
sim_cpu * cpu = STATE_CPU ( sd , 0 ) ; /* FIXME */
/* NOTE: gdb (the client) stores registers in target byte order
while the simulator uses host byte order */
# ifdef DEBUG
#if 0 /* FIXME: doesn't compile */
sim_io_printf ( sd , " sim_fetch_register(%d=0x%s,mem) : place simulator registers into memory \n " , rn , pr_addr ( registers [ rn ] ) ) ;
# endif
# endif /* DEBUG */
if ( cpu - > register_widths [ rn ] = = 0 )
{
sim_io_eprintf ( sd , " Invalid register width for %d (register fetch ignored) \n " , rn ) ;
return 0 ;
}
/* Any floating point register */
if ( rn > = FGRIDX & & rn < FGRIDX + NR_FGR )
{
if ( cpu - > register_widths [ rn ] = = 32 )
{
1999-08-03 07:48:37 +08:00
if ( length = = 8 )
{
* ( unsigned64 * ) memory =
H2T_8 ( ( unsigned32 ) ( cpu - > fgr [ rn - FGRIDX ] ) ) ;
return 8 ;
}
else
{
* ( unsigned32 * ) memory = H2T_4 ( cpu - > fgr [ rn - FGRIDX ] ) ;
return 4 ;
}
1999-04-16 09:35:26 +08:00
}
else
{
* ( unsigned64 * ) memory = H2T_8 ( cpu - > fgr [ rn - FGRIDX ] ) ;
return 8 ;
}
}
if ( cpu - > register_widths [ rn ] = = 32 )
{
1999-08-03 07:48:37 +08:00
if ( length = = 8 )
{
* ( unsigned64 * ) memory =
H2T_8 ( ( unsigned32 ) ( cpu - > registers [ rn ] ) ) ;
return 8 ;
}
else
{
* ( unsigned32 * ) memory = H2T_4 ( ( unsigned32 ) ( cpu - > registers [ rn ] ) ) ;
return 4 ;
}
1999-04-16 09:35:26 +08:00
}
else
{
* ( unsigned64 * ) memory = H2T_8 ( ( unsigned64 ) ( cpu - > registers [ rn ] ) ) ;
return 8 ;
}
return 0 ;
}
SIM_RC
sim_create_inferior ( sd , abfd , argv , env )
SIM_DESC sd ;
struct _bfd * abfd ;
char * * argv ;
char * * env ;
{
# ifdef DEBUG
#if 0 /* FIXME: doesn't compile */
printf ( " DBG: sim_create_inferior entered: start_address = 0x%s \n " ,
pr_addr ( PC ) ) ;
# endif
# endif /* DEBUG */
ColdReset ( sd ) ;
if ( abfd ! = NULL )
{
/* override PC value set by ColdReset () */
int cpu_nr ;
for ( cpu_nr = 0 ; cpu_nr < sim_engine_nr_cpus ( sd ) ; cpu_nr + + )
{
sim_cpu * cpu = STATE_CPU ( sd , cpu_nr ) ;
CIA_SET ( cpu , ( unsigned64 ) bfd_get_start_address ( abfd ) ) ;
}
}
#if 0 /* def DEBUG */
if ( argv | | env )
{
/* We should really place the argv slot values into the argument
registers , and onto the stack as required . However , this
assumes that we have a stack defined , which is not
necessarily true at the moment . */
char * * cptr ;
sim_io_printf ( sd , " sim_create_inferior() : passed arguments ignored \n " ) ;
for ( cptr = argv ; ( cptr & & * cptr ) ; cptr + + )
printf ( " DBG: arg \" %s \" \n " , * cptr ) ;
}
# endif /* DEBUG */
return SIM_RC_OK ;
}
void
sim_do_command ( sd , cmd )
SIM_DESC sd ;
char * cmd ;
{
if ( sim_args_command ( sd , cmd ) ! = SIM_RC_OK )
sim_io_printf ( sd , " Error: \" %s \" is not a valid MIPS simulator command. \n " ,
cmd ) ;
}
/*---------------------------------------------------------------------------*/
/*-- Private simulator support interface ------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Read a null terminated string from memory, return in a buffer */
static char *
fetch_str ( SIM_DESC sd ,
address_word addr )
{
char * buf ;
int nr = 0 ;
char null ;
while ( sim_read ( sd , addr + nr , & null , 1 ) = = 1 & & null ! = 0 )
nr + + ;
buf = NZALLOC ( char , nr + 1 ) ;
sim_read ( sd , addr , buf , nr ) ;
return buf ;
}
1999-07-20 07:30:11 +08:00
/* Implements the "sim firmware" command:
sim firmware NAME [ @ ADDRESS ] - - - emulate ROM monitor named NAME .
NAME can be idt , pmon , or lsipmon . If omitted , ADDRESS
defaults to the normal address for that monitor .
sim firmware none - - - don ' t emulate any ROM monitor . Useful
if you need a clean address space . */
static SIM_RC
sim_firmware_command ( SIM_DESC sd , char * arg )
{
int address_present = 0 ;
SIM_ADDR address ;
/* Signal occurrence of this option. */
firmware_option_p = 1 ;
/* Parse out the address, if present. */
{
char * p = strchr ( arg , ' @ ' ) ;
if ( p )
{
char * q ;
address_present = 1 ;
p + + ; /* skip over @ */
address = strtoul ( p , & q , 0 ) ;
if ( * q ! = ' \0 ' )
{
sim_io_printf ( sd , " Invalid address given to the "
" `sim firmware NAME@ADDRESS' command: %s \n " ,
p ) ;
return SIM_RC_FAIL ;
}
}
else
address_present = 0 ;
}
if ( ! strncmp ( arg , " idt " , 3 ) )
{
idt_monitor_base = address_present ? address : 0xBFC00000 ;
pmon_monitor_base = 0 ;
lsipmon_monitor_base = 0 ;
}
else if ( ! strncmp ( arg , " pmon " , 4 ) )
{
/* pmon uses indirect calls. Hook into implied idt. */
pmon_monitor_base = address_present ? address : 0xBFC00500 ;
idt_monitor_base = pmon_monitor_base - 0x500 ;
lsipmon_monitor_base = 0 ;
}
else if ( ! strncmp ( arg , " lsipmon " , 7 ) )
{
/* lsipmon uses indirect calls. Hook into implied idt. */
pmon_monitor_base = 0 ;
lsipmon_monitor_base = address_present ? address : 0xBFC00200 ;
idt_monitor_base = lsipmon_monitor_base - 0x200 ;
}
else if ( ! strncmp ( arg , " none " , 4 ) )
{
if ( address_present )
{
sim_io_printf ( sd ,
" The `sim firmware none' command does "
" not take an `ADDRESS' argument. \n " ) ;
return SIM_RC_FAIL ;
}
idt_monitor_base = 0 ;
pmon_monitor_base = 0 ;
lsipmon_monitor_base = 0 ;
}
else
{
sim_io_printf ( sd , " \
Unrecognized name given to the ` sim firmware NAME ' command : % s \ n \
Recognized firmware names are : ` idt ' , ` pmon ' , ` lsipmon ' , and ` none ' . \ n " ,
arg ) ;
return SIM_RC_FAIL ;
}
return SIM_RC_OK ;
}
1999-04-16 09:35:26 +08:00
/* Simple monitor interface (currently setup for the IDT and PMON monitors) */
void
sim_monitor ( SIM_DESC sd ,
sim_cpu * cpu ,
address_word cia ,
unsigned int reason )
{
# ifdef DEBUG
printf ( " DBG: sim_monitor: entered (reason = %d) \n " , reason ) ;
# endif /* DEBUG */
/* The IDT monitor actually allows two instructions per vector
slot . However , the simulator currently causes a trap on each
individual instruction . We cheat , and lose the bottom bit . */
reason > > = 1 ;
/* The following callback functions are available, however the
monitor we are simulating does not make use of them : get_errno ,
isatty , lseek , rename , system , time and unlink */
switch ( reason )
{
case 6 : /* int open(char *path,int flags) */
{
char * path = fetch_str ( sd , A0 ) ;
V0 = sim_io_open ( sd , path , ( int ) A1 ) ;
zfree ( path ) ;
break ;
}
case 7 : /* int read(int file,char *ptr,int len) */
{
int fd = A0 ;
int nr = A2 ;
char * buf = zalloc ( nr ) ;
V0 = sim_io_read ( sd , fd , buf , nr ) ;
sim_write ( sd , A1 , buf , nr ) ;
zfree ( buf ) ;
}
break ;
case 8 : /* int write(int file,char *ptr,int len) */
{
int fd = A0 ;
int nr = A2 ;
char * buf = zalloc ( nr ) ;
sim_read ( sd , A1 , buf , nr ) ;
V0 = sim_io_write ( sd , fd , buf , nr ) ;
zfree ( buf ) ;
break ;
}
case 10 : /* int close(int file) */
{
V0 = sim_io_close ( sd , ( int ) A0 ) ;
break ;
}
case 2 : /* Densan monitor: char inbyte(int waitflag) */
{
if ( A0 = = 0 ) /* waitflag == NOWAIT */
V0 = ( unsigned_word ) - 1 ;
}
/* Drop through to case 11 */
case 11 : /* char inbyte(void) */
{
char tmp ;
1999-07-12 19:15:22 +08:00
/* ensure that all output has gone... */
sim_io_flush_stdout ( sd ) ;
1999-04-16 09:35:26 +08:00
if ( sim_io_read_stdin ( sd , & tmp , sizeof ( char ) ) ! = sizeof ( char ) )
{
sim_io_error ( sd , " Invalid return from character read " ) ;
V0 = ( unsigned_word ) - 1 ;
}
else
V0 = ( unsigned_word ) tmp ;
break ;
}
case 3 : /* Densan monitor: void co(char chr) */
case 12 : /* void outbyte(char chr) : write a byte to "stdout" */
{
char tmp = ( char ) ( A0 & 0xFF ) ;
sim_io_write_stdout ( sd , & tmp , sizeof ( char ) ) ;
break ;
}
case 17 : /* void _exit() */
{
sim_io_eprintf ( sd , " sim_monitor(17): _exit(int reason) to be coded \n " ) ;
sim_engine_halt ( SD , CPU , NULL , NULL_CIA , sim_exited ,
( unsigned int ) ( A0 & 0xFFFFFFFF ) ) ;
break ;
}
case 28 : /* PMON flush_cache */
break ;
case 55 : /* void get_mem_info(unsigned int *ptr) */
/* in: A0 = pointer to three word memory location */
/* out: [A0 + 0] = size */
/* [A0 + 4] = instruction cache size */
/* [A0 + 8] = data cache size */
{
unsigned_4 value = MEM_SIZE /* FIXME STATE_MEM_SIZE (sd) */ ;
unsigned_4 zero = 0 ;
H2T ( value ) ;
sim_write ( sd , A0 + 0 , ( char * ) & value , 4 ) ;
sim_write ( sd , A0 + 4 , ( char * ) & zero , 4 ) ;
sim_write ( sd , A0 + 8 , ( char * ) & zero , 4 ) ;
/* sim_io_eprintf (sd, "sim: get_mem_info() depreciated\n"); */
break ;
}
case 158 : /* PMON printf */
/* in: A0 = pointer to format string */
/* A1 = optional argument 1 */
/* A2 = optional argument 2 */
/* A3 = optional argument 3 */
/* out: void */
/* The following is based on the PMON printf source */
{
address_word s = A0 ;
char c ;
signed_word * ap = & A1 ; /* 1st argument */
/* This isn't the quickest way, since we call the host print
routine for every character almost . But it does avoid
having to allocate and manage a temporary string buffer . */
/* TODO: Include check that we only use three arguments (A1,
A2 and A3 ) */
while ( sim_read ( sd , s + + , & c , 1 ) & & c ! = ' \0 ' )
{
if ( c = = ' % ' )
{
char tmp [ 40 ] ;
enum { FMT_RJUST , FMT_LJUST , FMT_RJUST0 , FMT_CENTER } fmt = FMT_RJUST ;
int width = 0 , trunc = 0 , haddot = 0 , longlong = 0 ;
while ( sim_read ( sd , s + + , & c , 1 ) & & c ! = ' \0 ' )
{
if ( strchr ( " dobxXulscefg% " , c ) )
break ;
else if ( c = = ' - ' )
fmt = FMT_LJUST ;
else if ( c = = ' 0 ' )
fmt = FMT_RJUST0 ;
else if ( c = = ' ~ ' )
fmt = FMT_CENTER ;
else if ( c = = ' * ' )
{
if ( haddot )
trunc = ( int ) * ap + + ;
else
width = ( int ) * ap + + ;
}
else if ( c > = ' 1 ' & & c < = ' 9 ' )
{
address_word t = s ;
unsigned int n ;
while ( sim_read ( sd , s + + , & c , 1 ) = = 1 & & isdigit ( c ) )
tmp [ s - t ] = c ;
tmp [ s - t ] = ' \0 ' ;
n = ( unsigned int ) strtol ( tmp , NULL , 10 ) ;
if ( haddot )
trunc = n ;
else
width = n ;
s - - ;
}
else if ( c = = ' . ' )
haddot = 1 ;
}
switch ( c )
{
case ' % ' :
sim_io_printf ( sd , " %% " ) ;
break ;
case ' s ' :
if ( ( int ) * ap ! = 0 )
{
address_word p = * ap + + ;
char ch ;
while ( sim_read ( sd , p + + , & ch , 1 ) = = 1 & & ch ! = ' \0 ' )
sim_io_printf ( sd , " %c " , ch ) ;
}
else
sim_io_printf ( sd , " (null) " ) ;
break ;
case ' c ' :
sim_io_printf ( sd , " %c " , ( int ) * ap + + ) ;
break ;
default :
if ( c = = ' l ' )
{
sim_read ( sd , s + + , & c , 1 ) ;
if ( c = = ' l ' )
{
longlong = 1 ;
sim_read ( sd , s + + , & c , 1 ) ;
}
}
if ( strchr ( " dobxXu " , c ) )
{
word64 lv = ( word64 ) * ap + + ;
if ( c = = ' b ' )
sim_io_printf ( sd , " <binary not supported> " ) ;
else
{
sprintf ( tmp , " %%%s%c " , longlong ? " ll " : " " , c ) ;
if ( longlong )
sim_io_printf ( sd , tmp , lv ) ;
else
sim_io_printf ( sd , tmp , ( int ) lv ) ;
}
}
else if ( strchr ( " eEfgG " , c ) )
{
double dbl = * ( double * ) ( ap + + ) ;
sprintf ( tmp , " %%%d.%d%c " , width , trunc , c ) ;
sim_io_printf ( sd , tmp , dbl ) ;
trunc = 0 ;
}
}
}
else
sim_io_printf ( sd , " %c " , c ) ;
}
break ;
}
default :
sim_io_error ( sd , " TODO: sim_monitor(%d) : PC = 0x%s \n " ,
reason , pr_addr ( cia ) ) ;
break ;
}
return ;
}
/* Store a word into memory. */
static void
store_word ( SIM_DESC sd ,
sim_cpu * cpu ,
address_word cia ,
uword64 vaddr ,
signed_word val )
{
address_word paddr ;
int uncached ;
if ( ( vaddr & 3 ) ! = 0 )
SignalExceptionAddressStore ( ) ;
else
{
if ( AddressTranslation ( vaddr , isDATA , isSTORE , & paddr , & uncached ,
isTARGET , isREAL ) )
{
const uword64 mask = 7 ;
uword64 memval ;
unsigned int byte ;
paddr = ( paddr & ~ mask ) | ( ( paddr & mask ) ^ ( ReverseEndian < < 2 ) ) ;
byte = ( vaddr & mask ) ^ ( BigEndianCPU < < 2 ) ;
memval = ( ( uword64 ) val ) < < ( 8 * byte ) ;
StoreMemory ( uncached , AccessLength_WORD , memval , 0 , paddr , vaddr ,
isREAL ) ;
}
}
}
/* Load a word from memory. */
static signed_word
load_word ( SIM_DESC sd ,
sim_cpu * cpu ,
address_word cia ,
uword64 vaddr )
{
if ( ( vaddr & 3 ) ! = 0 )
{
SIM_CORE_SIGNAL ( SD , cpu , cia , read_map , AccessLength_WORD + 1 , vaddr , read_transfer , sim_core_unaligned_signal ) ;
}
else
{
address_word paddr ;
int uncached ;
if ( AddressTranslation ( vaddr , isDATA , isLOAD , & paddr , & uncached ,
isTARGET , isREAL ) )
{
const uword64 mask = 0x7 ;
const unsigned int reverse = ReverseEndian ? 1 : 0 ;
const unsigned int bigend = BigEndianCPU ? 1 : 0 ;
uword64 memval ;
unsigned int byte ;
paddr = ( paddr & ~ mask ) | ( ( paddr & mask ) ^ ( reverse < < 2 ) ) ;
LoadMemory ( & memval , NULL , uncached , AccessLength_WORD , paddr , vaddr ,
isDATA , isREAL ) ;
byte = ( vaddr & mask ) ^ ( bigend < < 2 ) ;
return SIGNEXTEND ( ( ( memval > > ( 8 * byte ) ) & 0xffffffff ) , 32 ) ;
}
}
return 0 ;
}
/* Simulate the mips16 entry and exit pseudo-instructions. These
would normally be handled by the reserved instruction exception
code , but for ease of simulation we just handle them directly . */
static void
mips16_entry ( SIM_DESC sd ,
sim_cpu * cpu ,
address_word cia ,
unsigned int insn )
{
int aregs , sregs , rreg ;
# ifdef DEBUG
printf ( " DBG: mips16_entry: entered (insn = 0x%08X) \n " , insn ) ;
# endif /* DEBUG */
aregs = ( insn & 0x700 ) > > 8 ;
sregs = ( insn & 0x0c0 ) > > 6 ;
rreg = ( insn & 0x020 ) > > 5 ;
/* This should be checked by the caller. */
if ( sregs = = 3 )
abort ( ) ;
if ( aregs < 5 )
{
int i ;
signed_word tsp ;
/* This is the entry pseudo-instruction. */
for ( i = 0 ; i < aregs ; i + + )
store_word ( SD , CPU , cia , ( uword64 ) ( SP + 4 * i ) , GPR [ i + 4 ] ) ;
tsp = SP ;
SP - = 32 ;
if ( rreg )
{
tsp - = 4 ;
store_word ( SD , CPU , cia , ( uword64 ) tsp , RA ) ;
}
for ( i = 0 ; i < sregs ; i + + )
{
tsp - = 4 ;
store_word ( SD , CPU , cia , ( uword64 ) tsp , GPR [ 16 + i ] ) ;
}
}
else
{
int i ;
signed_word tsp ;
/* This is the exit pseudo-instruction. */
tsp = SP + 32 ;
if ( rreg )
{
tsp - = 4 ;
RA = load_word ( SD , CPU , cia , ( uword64 ) tsp ) ;
}
for ( i = 0 ; i < sregs ; i + + )
{
tsp - = 4 ;
GPR [ i + 16 ] = load_word ( SD , CPU , cia , ( uword64 ) tsp ) ;
}
SP + = 32 ;
if ( CURRENT_FLOATING_POINT = = HARD_FLOATING_POINT )
{
if ( aregs = = 5 )
{
FGR [ 0 ] = WORD64LO ( GPR [ 4 ] ) ;
FPR_STATE [ 0 ] = fmt_uninterpreted ;
}
else if ( aregs = = 6 )
{
FGR [ 0 ] = WORD64LO ( GPR [ 5 ] ) ;
FGR [ 1 ] = WORD64LO ( GPR [ 4 ] ) ;
FPR_STATE [ 0 ] = fmt_uninterpreted ;
FPR_STATE [ 1 ] = fmt_uninterpreted ;
}
}
PC = RA ;
}
}
/*-- trace support ----------------------------------------------------------*/
/* The TRACE support is provided (if required) in the memory accessing
routines . Since we are also providing the architecture specific
features , the architecture simulation code can also deal with
notifying the TRACE world of cache flushes , etc . Similarly we do
not need to provide profiling support in the simulator engine ,
since we can sample in the instruction fetch control loop . By
defining the TRACE manifest , we add tracing as a run - time
option . */
# if defined(TRACE)
/* Tracing by default produces "din" format (as required by
dineroIII ) . Each line of such a trace file * MUST * have a din label
and address field . The rest of the line is ignored , so comments can
be included if desired . The first field is the label which must be
one of the following values :
0 read data
1 write data
2 instruction fetch
3 escape record ( treated as unknown access type )
4 escape record ( causes cache flush )
The address field is a 32 bit ( lower - case ) hexadecimal address
value . The address should * NOT * be preceded by " 0x " .
The size of the memory transfer is not important when dealing with
cache lines ( as long as no more than a cache line can be
transferred in a single operation : - ) , however more information
could be given following the dineroIII requirement to allow more
complete memory and cache simulators to provide better
results . i . e . the University of Pisa has a cache simulator that can
also take bus size and speed as ( variable ) inputs to calculate
complete system performance ( a much more useful ability when trying
to construct an end product , rather than a processor ) . They
currently have an ARM version of their tool called ChARM . */
void
dotrace ( SIM_DESC sd ,
sim_cpu * cpu ,
FILE * tracefh ,
int type ,
SIM_ADDR address ,
int width ,
char * comment , . . . )
{
if ( STATE & simTRACE ) {
va_list ap ;
fprintf ( tracefh , " %d %s ; width %d ; " ,
type ,
pr_addr ( address ) ,
width ) ;
va_start ( ap , comment ) ;
vfprintf ( tracefh , comment , ap ) ;
va_end ( ap ) ;
fprintf ( tracefh , " \n " ) ;
}
/* NOTE: Since the "din" format will only accept 32bit addresses, and
we may be generating 64 bit ones , we should put the hi - 32 bits of the
address into the comment field . */
/* TODO: Provide a buffer for the trace lines. We can then avoid
performing writes until the buffer is filled , or the file is
being closed . */
/* NOTE: We could consider adding a comment field to the "din" file
produced using type 3 markers ( unknown access ) . This would then
allow information about the program that the " din " is for , and
the MIPs world that was being simulated , to be placed into the
trace file . */
return ;
}
# endif /* TRACE */
/*---------------------------------------------------------------------------*/
/*-- simulator engine -------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
ColdReset ( SIM_DESC sd )
{
int cpu_nr ;
for ( cpu_nr = 0 ; cpu_nr < sim_engine_nr_cpus ( sd ) ; cpu_nr + + )
{
sim_cpu * cpu = STATE_CPU ( sd , cpu_nr ) ;
/* RESET: Fixed PC address: */
PC = ( unsigned_word ) UNSIGNED64 ( 0xFFFFFFFFBFC00000 ) ;
/* The reset vector address is in the unmapped, uncached memory space. */
SR & = ~ ( status_SR | status_TS | status_RP ) ;
SR | = ( status_ERL | status_BEV ) ;
/* Cheat and allow access to the complete register set immediately */
if ( CURRENT_FLOATING_POINT = = HARD_FLOATING_POINT
& & WITH_TARGET_WORD_BITSIZE = = 64 )
SR | = status_FR ; /* 64bit registers */
/* Ensure that any instructions with pending register updates are
cleared : */
PENDING_INVALIDATE ( ) ;
/* Initialise the FPU registers to the unknown state */
if ( CURRENT_FLOATING_POINT = = HARD_FLOATING_POINT )
{
int rn ;
for ( rn = 0 ; ( rn < 32 ) ; rn + + )
FPR_STATE [ rn ] = fmt_uninterpreted ;
}
}
}
/* Description from page A-26 of the "MIPS IV Instruction Set" manual (revision 3.1) */
/* Signal an exception condition. This will result in an exception
that aborts the instruction . The instruction operation pseudocode
will never see a return from this function call . */
void
signal_exception ( SIM_DESC sd ,
sim_cpu * cpu ,
address_word cia ,
int exception , . . . )
{
/* int vector; */
# ifdef DEBUG
sim_io_printf ( sd , " DBG: SignalException(%d) PC = 0x%s \n " , exception , pr_addr ( cia ) ) ;
# endif /* DEBUG */
/* Ensure that any active atomic read/modify/write operation will fail: */
LLBIT = 0 ;
/* Save registers before interrupt dispatching */
# ifdef SIM_CPU_EXCEPTION_TRIGGER
SIM_CPU_EXCEPTION_TRIGGER ( sd , cpu , cia ) ;
# endif
switch ( exception ) {
case DebugBreakPoint :
if ( ! ( Debug & Debug_DM ) )
{
if ( INDELAYSLOT ( ) )
{
CANCELDELAYSLOT ( ) ;
Debug | = Debug_DBD ; /* signaled from within in delay slot */
DEPC = cia - 4 ; /* reference the branch instruction */
}
else
{
Debug & = ~ Debug_DBD ; /* not signaled from within a delay slot */
DEPC = cia ;
}
Debug | = Debug_DM ; /* in debugging mode */
Debug | = Debug_DBp ; /* raising a DBp exception */
PC = 0xBFC00200 ;
sim_engine_restart ( SD , CPU , NULL , NULL_CIA ) ;
}
break ;
case ReservedInstruction :
{
va_list ap ;
unsigned int instruction ;
va_start ( ap , exception ) ;
instruction = va_arg ( ap , unsigned int ) ;
va_end ( ap ) ;
/* Provide simple monitor support using ReservedInstruction
exceptions . The following code simulates the fixed vector
entry points into the IDT monitor by causing a simulator
trap , performing the monitor operation , and returning to
the address held in the $ ra register ( standard PCS return
address ) . This means we only need to pre - load the vector
space with suitable instruction values . For systems were
actual trap instructions are used , we would not need to
perform this magic . */
if ( ( instruction & RSVD_INSTRUCTION_MASK ) = = RSVD_INSTRUCTION )
{
sim_monitor ( SD , CPU , cia , ( ( instruction > > RSVD_INSTRUCTION_ARG_SHIFT ) & RSVD_INSTRUCTION_ARG_MASK ) ) ;
/* NOTE: This assumes that a branch-and-link style
instruction was used to enter the vector ( which is the
case with the current IDT monitor ) . */
sim_engine_restart ( SD , CPU , NULL , RA ) ;
}
/* Look for the mips16 entry and exit instructions, and
simulate a handler for them . */
else if ( ( cia & 1 ) ! = 0
& & ( instruction & 0xf81f ) = = 0xe809
& & ( instruction & 0x0c0 ) ! = 0x0c0 )
{
mips16_entry ( SD , CPU , cia , instruction ) ;
sim_engine_restart ( sd , NULL , NULL , NULL_CIA ) ;
}
/* else fall through to normal exception processing */
sim_io_eprintf ( sd , " ReservedInstruction at PC = 0x%s \n " , pr_addr ( cia ) ) ;
}
default :
/* Store exception code into current exception id variable (used
by exit code ) : */
/* TODO: If not simulating exceptions then stop the simulator
execution . At the moment we always stop the simulation . */
# ifdef SUBTARGET_R3900
/* update interrupt-related registers */
/* insert exception code in bits 6:2 */
CAUSE = LSMASKED32 ( CAUSE , 31 , 7 ) | LSINSERTED32 ( exception , 6 , 2 ) ;
/* shift IE/KU history bits left */
SR = LSMASKED32 ( SR , 31 , 4 ) | LSINSERTED32 ( LSEXTRACTED32 ( SR , 3 , 0 ) , 5 , 2 ) ;
if ( STATE & simDELAYSLOT )
{
STATE & = ~ simDELAYSLOT ;
CAUSE | = cause_BD ;
EPC = ( cia - 4 ) ; /* reference the branch instruction */
}
else
EPC = cia ;
if ( SR & status_BEV )
PC = ( signed ) 0xBFC00000 + 0x180 ;
else
PC = ( signed ) 0x80000000 + 0x080 ;
# else
/* See figure 5-17 for an outline of the code below */
if ( ! ( SR & status_EXL ) )
{
CAUSE = ( exception < < 2 ) ;
if ( STATE & simDELAYSLOT )
{
STATE & = ~ simDELAYSLOT ;
CAUSE | = cause_BD ;
EPC = ( cia - 4 ) ; /* reference the branch instruction */
}
else
EPC = cia ;
/* FIXME: TLB et.al. */
/* vector = 0x180; */
}
else
{
CAUSE = ( exception < < 2 ) ;
/* vector = 0x180; */
}
SR | = status_EXL ;
/* Store exception code into current exception id variable (used
by exit code ) : */
if ( SR & status_BEV )
PC = ( signed ) 0xBFC00200 + 0x180 ;
else
PC = ( signed ) 0x80000000 + 0x180 ;
# endif
switch ( ( CAUSE > > 2 ) & 0x1F )
{
case Interrupt :
/* Interrupts arrive during event processing, no need to
restart */
return ;
case NMIReset :
/* Ditto */
# ifdef SUBTARGET_3900
/* Exception vector: BEV=0 BFC00000 / BEF=1 BFC00000 */
PC = ( signed ) 0xBFC00000 ;
# endif SUBTARGET_3900
return ;
case TLBModification :
case TLBLoad :
case TLBStore :
case AddressLoad :
case AddressStore :
case InstructionFetch :
case DataReference :
/* The following is so that the simulator will continue from the
exception handler address . */
sim_engine_halt ( SD , CPU , NULL , PC ,
sim_stopped , SIM_SIGBUS ) ;
case ReservedInstruction :
case CoProcessorUnusable :
PC = EPC ;
sim_engine_halt ( SD , CPU , NULL , PC ,
sim_stopped , SIM_SIGILL ) ;
case IntegerOverflow :
case FPE :
sim_engine_halt ( SD , CPU , NULL , PC ,
sim_stopped , SIM_SIGFPE ) ;
case BreakPoint :
sim_engine_halt ( SD , CPU , NULL , PC , sim_stopped , SIM_SIGTRAP ) ;
break ;
case SystemCall :
case Trap :
sim_engine_restart ( SD , CPU , NULL , PC ) ;
break ;
case Watch :
PC = EPC ;
sim_engine_halt ( SD , CPU , NULL , PC ,
sim_stopped , SIM_SIGTRAP ) ;
default : /* Unknown internal exception */
PC = EPC ;
sim_engine_halt ( SD , CPU , NULL , PC ,
sim_stopped , SIM_SIGABRT ) ;
}
case SimulatorFault :
{
va_list ap ;
char * msg ;
va_start ( ap , exception ) ;
msg = va_arg ( ap , char * ) ;
va_end ( ap ) ;
sim_engine_abort ( SD , CPU , NULL_CIA ,
" FATAL: Simulator error \" %s \" \n " , msg ) ;
}
}
return ;
}
# if defined(WARN_RESULT)
/* Description from page A-26 of the "MIPS IV Instruction Set" manual (revision 3.1) */
/* This function indicates that the result of the operation is
undefined . However , this should not affect the instruction
stream . All that is meant to happen is that the destination
register is set to an undefined result . To keep the simulator
simple , we just don ' t bother updating the destination register , so
the overall result will be undefined . If desired we can stop the
simulator by raising a pseudo - exception . */
# define UndefinedResult() undefined_result (sd,cia)
static void
undefined_result ( sd , cia )
SIM_DESC sd ;
address_word cia ;
{
sim_io_eprintf ( sd , " UndefinedResult: PC = 0x%s \n " , pr_addr ( cia ) ) ;
#if 0 /* Disabled for the moment, since it actually happens a lot at the moment. */
state | = simSTOP ;
# endif
return ;
}
# endif /* WARN_RESULT */
/*-- FPU support routines ---------------------------------------------------*/
/* Numbers are held in normalized form. The SINGLE and DOUBLE binary
formats conform to ANSI / IEEE Std 754 - 1985. */
/* SINGLE precision floating:
* seeeeeeeefffffffffffffffffffffff
* s = 1 bit = sign
* e = 8 bits = exponent
* f = 23 bits = fraction
*/
/* SINGLE precision fixed:
* siiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
* s = 1 bit = sign
* i = 31 bits = integer
*/
/* DOUBLE precision floating:
* seeeeeeeeeeeffffffffffffffffffffffffffffffffffffffffffffffffffff
* s = 1 bit = sign
* e = 11 bits = exponent
* f = 52 bits = fraction
*/
/* DOUBLE precision fixed:
* siiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
* s = 1 bit = sign
* i = 63 bits = integer
*/
/* Extract sign-bit: */
# define FP_S_s(v) (((v) & ((unsigned)1 << 31)) ? 1 : 0)
# define FP_D_s(v) (((v) & ((uword64)1 << 63)) ? 1 : 0)
/* Extract biased exponent: */
# define FP_S_be(v) (((v) >> 23) & 0xFF)
# define FP_D_be(v) (((v) >> 52) & 0x7FF)
/* Extract unbiased Exponent: */
# define FP_S_e(v) (FP_S_be(v) - 0x7F)
# define FP_D_e(v) (FP_D_be(v) - 0x3FF)
/* Extract complete fraction field: */
# define FP_S_f(v) ((v) & ~((unsigned)0x1FF << 23))
# define FP_D_f(v) ((v) & ~((uword64)0xFFF << 52))
/* Extract numbered fraction bit: */
# define FP_S_fb(b,v) (((v) & (1 << (23 - (b)))) ? 1 : 0)
# define FP_D_fb(b,v) (((v) & (1 << (52 - (b)))) ? 1 : 0)
/* Explicit QNaN values used when value required: */
# define FPQNaN_SINGLE (0x7FBFFFFF)
# define FPQNaN_WORD (0x7FFFFFFF)
# define FPQNaN_DOUBLE (((uword64)0x7FF7FFFF << 32) | 0xFFFFFFFF)
# define FPQNaN_LONG (((uword64)0x7FFFFFFF << 32) | 0xFFFFFFFF)
/* Explicit Infinity values used when required: */
# define FPINF_SINGLE (0x7F800000)
# define FPINF_DOUBLE (((uword64)0x7FF00000 << 32) | 0x00000000)
# define RMMODE(v) (((v) == FP_RM_NEAREST) ? "Round" : (((v) == FP_RM_TOZERO) ? "Trunc" : (((v) == FP_RM_TOPINF) ? "Ceil" : "Floor")))
# define DOFMT(v) (((v) == fmt_single) ? "single" : (((v) == fmt_double) ? "double" : (((v) == fmt_word) ? "word" : (((v) == fmt_long) ? "long" : (((v) == fmt_unknown) ? "<unknown>" : (((v) == fmt_uninterpreted) ? "<uninterpreted>" : (((v) == fmt_uninterpreted_32) ? "<uninterpreted_32>" : (((v) == fmt_uninterpreted_64) ? "<uninterpreted_64>" : "<format error>"))))))))
uword64
value_fpr ( SIM_DESC sd ,
sim_cpu * cpu ,
address_word cia ,
int fpr ,
FP_formats fmt )
{
uword64 value = 0 ;
int err = 0 ;
/* Treat unused register values, as fixed-point 64bit values: */
if ( ( fmt = = fmt_uninterpreted ) | | ( fmt = = fmt_unknown ) )
# if 1
/* If request to read data as "uninterpreted", then use the current
encoding : */
fmt = FPR_STATE [ fpr ] ;
# else
fmt = fmt_long ;
# endif
/* For values not yet accessed, set to the desired format: */
if ( FPR_STATE [ fpr ] = = fmt_uninterpreted ) {
FPR_STATE [ fpr ] = fmt ;
# ifdef DEBUG
printf ( " DBG: Register %d was fmt_uninterpreted. Now %s \n " , fpr , DOFMT ( fmt ) ) ;
# endif /* DEBUG */
}
if ( fmt ! = FPR_STATE [ fpr ] ) {
sim_io_eprintf ( sd , " FPR %d (format %s) being accessed with format %s - setting to unknown (PC = 0x%s) \n " , fpr , DOFMT ( FPR_STATE [ fpr ] ) , DOFMT ( fmt ) , pr_addr ( cia ) ) ;
FPR_STATE [ fpr ] = fmt_unknown ;
}
if ( FPR_STATE [ fpr ] = = fmt_unknown ) {
/* Set QNaN value: */
switch ( fmt ) {
case fmt_single :
value = FPQNaN_SINGLE ;
break ;
case fmt_double :
value = FPQNaN_DOUBLE ;
break ;
case fmt_word :
value = FPQNaN_WORD ;
break ;
case fmt_long :
value = FPQNaN_LONG ;
break ;
default :
err = - 1 ;
break ;
}
} else if ( SizeFGR ( ) = = 64 ) {
switch ( fmt ) {
case fmt_single :
case fmt_word :
value = ( FGR [ fpr ] & 0xFFFFFFFF ) ;
break ;
case fmt_uninterpreted :
case fmt_double :
case fmt_long :
value = FGR [ fpr ] ;
break ;
default :
err = - 1 ;
break ;
}
} else {
switch ( fmt ) {
case fmt_single :
case fmt_word :
value = ( FGR [ fpr ] & 0xFFFFFFFF ) ;
break ;
case fmt_uninterpreted :
case fmt_double :
case fmt_long :
if ( ( fpr & 1 ) = = 0 ) { /* even registers only */
# ifdef DEBUG
printf ( " DBG: ValueFPR: FGR[%d] = %s, FGR[%d] = %s \n " ,
fpr + 1 , pr_uword64 ( ( uword64 ) FGR [ fpr + 1 ] ) ,
fpr , pr_uword64 ( ( uword64 ) FGR [ fpr ] ) ) ;
# endif
value = ( ( ( ( uword64 ) FGR [ fpr + 1 ] ) < < 32 ) | ( FGR [ fpr ] & 0xFFFFFFFF ) ) ;
} else {
SignalException ( ReservedInstruction , 0 ) ;
}
break ;
default :
err = - 1 ;
break ;
}
}
if ( err )
SignalExceptionSimulatorFault ( " Unrecognised FP format in ValueFPR() " ) ;
# ifdef DEBUG
printf ( " DBG: ValueFPR: fpr = %d, fmt = %s, value = 0x%s : PC = 0x%s : SizeFGR() = %d \n " , fpr , DOFMT ( fmt ) , pr_uword64 ( value ) , pr_addr ( cia ) , SizeFGR ( ) ) ;
# endif /* DEBUG */
return ( value ) ;
}
void
store_fpr ( SIM_DESC sd ,
sim_cpu * cpu ,
address_word cia ,
int fpr ,
FP_formats fmt ,
uword64 value )
{
int err = 0 ;
# ifdef DEBUG
printf ( " DBG: StoreFPR: fpr = %d, fmt = %s, value = 0x%s : PC = 0x%s : SizeFGR() = %d, \n " , fpr , DOFMT ( fmt ) , pr_uword64 ( value ) , pr_addr ( cia ) , SizeFGR ( ) ) ;
# endif /* DEBUG */
if ( SizeFGR ( ) = = 64 ) {
switch ( fmt ) {
case fmt_uninterpreted_32 :
fmt = fmt_uninterpreted ;
case fmt_single :
case fmt_word :
FGR [ fpr ] = ( ( ( uword64 ) 0xDEADC0DE < < 32 ) | ( value & 0xFFFFFFFF ) ) ;
FPR_STATE [ fpr ] = fmt ;
break ;
case fmt_uninterpreted_64 :
fmt = fmt_uninterpreted ;
case fmt_uninterpreted :
case fmt_double :
case fmt_long :
FGR [ fpr ] = value ;
FPR_STATE [ fpr ] = fmt ;
break ;
default :
FPR_STATE [ fpr ] = fmt_unknown ;
err = - 1 ;
break ;
}
} else {
switch ( fmt ) {
case fmt_uninterpreted_32 :
fmt = fmt_uninterpreted ;
case fmt_single :
case fmt_word :
FGR [ fpr ] = ( value & 0xFFFFFFFF ) ;
FPR_STATE [ fpr ] = fmt ;
break ;
case fmt_uninterpreted_64 :
fmt = fmt_uninterpreted ;
case fmt_uninterpreted :
case fmt_double :
case fmt_long :
if ( ( fpr & 1 ) = = 0 ) { /* even register number only */
FGR [ fpr + 1 ] = ( value > > 32 ) ;
FGR [ fpr ] = ( value & 0xFFFFFFFF ) ;
FPR_STATE [ fpr + 1 ] = fmt ;
FPR_STATE [ fpr ] = fmt ;
} else {
FPR_STATE [ fpr ] = fmt_unknown ;
FPR_STATE [ fpr + 1 ] = fmt_unknown ;
SignalException ( ReservedInstruction , 0 ) ;
}
break ;
default :
FPR_STATE [ fpr ] = fmt_unknown ;
err = - 1 ;
break ;
}
}
# if defined(WARN_RESULT)
else
UndefinedResult ( ) ;
# endif /* WARN_RESULT */
if ( err )
SignalExceptionSimulatorFault ( " Unrecognised FP format in StoreFPR() " ) ;
# ifdef DEBUG
printf ( " DBG: StoreFPR: fpr[%d] = 0x%s (format %s) \n " , fpr , pr_uword64 ( FGR [ fpr ] ) , DOFMT ( fmt ) ) ;
# endif /* DEBUG */
return ;
}
int
NaN ( op , fmt )
uword64 op ;
FP_formats fmt ;
{
int boolean = 0 ;
switch ( fmt ) {
case fmt_single :
case fmt_word :
{
sim_fpu wop ;
sim_fpu_32to ( & wop , op ) ;
boolean = sim_fpu_is_nan ( & wop ) ;
break ;
}
case fmt_double :
case fmt_long :
{
sim_fpu wop ;
sim_fpu_64to ( & wop , op ) ;
boolean = sim_fpu_is_nan ( & wop ) ;
break ;
}
default :
fprintf ( stderr , " Bad switch \n " ) ;
abort ( ) ;
}
# ifdef DEBUG
printf ( " DBG: NaN: returning %d for 0x%s (format = %s) \n " , boolean , pr_addr ( op ) , DOFMT ( fmt ) ) ;
# endif /* DEBUG */
return ( boolean ) ;
}
int
Infinity ( op , fmt )
uword64 op ;
FP_formats fmt ;
{
int boolean = 0 ;
# ifdef DEBUG
printf ( " DBG: Infinity: format %s 0x%s \n " , DOFMT ( fmt ) , pr_addr ( op ) ) ;
# endif /* DEBUG */
switch ( fmt ) {
case fmt_single :
{
sim_fpu wop ;
sim_fpu_32to ( & wop , op ) ;
boolean = sim_fpu_is_infinity ( & wop ) ;
break ;
}
case fmt_double :
{
sim_fpu wop ;
sim_fpu_64to ( & wop , op ) ;
boolean = sim_fpu_is_infinity ( & wop ) ;
break ;
}
default :
printf ( " DBG: TODO: unrecognised format (%s) for Infinity check \n " , DOFMT ( fmt ) ) ;
break ;
}
# ifdef DEBUG
printf ( " DBG: Infinity: returning %d for 0x%s (format = %s) \n " , boolean , pr_addr ( op ) , DOFMT ( fmt ) ) ;
# endif /* DEBUG */
return ( boolean ) ;
}
int
Less ( op1 , op2 , fmt )
uword64 op1 ;
uword64 op2 ;
FP_formats fmt ;
{
int boolean = 0 ;
/* Argument checking already performed by the FPCOMPARE code */
# ifdef DEBUG
printf ( " DBG: Less: %s: op1 = 0x%s : op2 = 0x%s \n " , DOFMT ( fmt ) , pr_addr ( op1 ) , pr_addr ( op2 ) ) ;
# endif /* DEBUG */
/* The format type should already have been checked: */
switch ( fmt ) {
case fmt_single :
{
sim_fpu wop1 ;
sim_fpu wop2 ;
sim_fpu_32to ( & wop1 , op1 ) ;
sim_fpu_32to ( & wop2 , op2 ) ;
boolean = sim_fpu_is_lt ( & wop1 , & wop2 ) ;
break ;
}
case fmt_double :
{
sim_fpu wop1 ;
sim_fpu wop2 ;
sim_fpu_64to ( & wop1 , op1 ) ;
sim_fpu_64to ( & wop2 , op2 ) ;
boolean = sim_fpu_is_lt ( & wop1 , & wop2 ) ;
break ;
}
default :
fprintf ( stderr , " Bad switch \n " ) ;
abort ( ) ;
}
# ifdef DEBUG
printf ( " DBG: Less: returning %d (format = %s) \n " , boolean , DOFMT ( fmt ) ) ;
# endif /* DEBUG */
return ( boolean ) ;
}
int
Equal ( op1 , op2 , fmt )
uword64 op1 ;
uword64 op2 ;
FP_formats fmt ;
{
int boolean = 0 ;
/* Argument checking already performed by the FPCOMPARE code */
# ifdef DEBUG
printf ( " DBG: Equal: %s: op1 = 0x%s : op2 = 0x%s \n " , DOFMT ( fmt ) , pr_addr ( op1 ) , pr_addr ( op2 ) ) ;
# endif /* DEBUG */
/* The format type should already have been checked: */
switch ( fmt ) {
case fmt_single :
{
sim_fpu wop1 ;
sim_fpu wop2 ;
sim_fpu_32to ( & wop1 , op1 ) ;
sim_fpu_32to ( & wop2 , op2 ) ;
boolean = sim_fpu_is_eq ( & wop1 , & wop2 ) ;
break ;
}
case fmt_double :
{
sim_fpu wop1 ;
sim_fpu wop2 ;
sim_fpu_64to ( & wop1 , op1 ) ;
sim_fpu_64to ( & wop2 , op2 ) ;
boolean = sim_fpu_is_eq ( & wop1 , & wop2 ) ;
break ;
}
default :
fprintf ( stderr , " Bad switch \n " ) ;
abort ( ) ;
}
# ifdef DEBUG
printf ( " DBG: Equal: returning %d (format = %s) \n " , boolean , DOFMT ( fmt ) ) ;
# endif /* DEBUG */
return ( boolean ) ;
}
uword64
AbsoluteValue ( op , fmt )
uword64 op ;
FP_formats fmt ;
{
uword64 result = 0 ;
# ifdef DEBUG
printf ( " DBG: AbsoluteValue: %s: op = 0x%s \n " , DOFMT ( fmt ) , pr_addr ( op ) ) ;
# endif /* DEBUG */
/* The format type should already have been checked: */
switch ( fmt ) {
case fmt_single :
{
sim_fpu wop ;
unsigned32 ans ;
sim_fpu_32to ( & wop , op ) ;
sim_fpu_abs ( & wop , & wop ) ;
sim_fpu_to32 ( & ans , & wop ) ;
result = ans ;
break ;
}
case fmt_double :
{
sim_fpu wop ;
unsigned64 ans ;
sim_fpu_64to ( & wop , op ) ;
sim_fpu_abs ( & wop , & wop ) ;
sim_fpu_to64 ( & ans , & wop ) ;
result = ans ;
break ;
}
default :
fprintf ( stderr , " Bad switch \n " ) ;
abort ( ) ;
}
return ( result ) ;
}
uword64
Negate ( op , fmt )
uword64 op ;
FP_formats fmt ;
{
uword64 result = 0 ;
# ifdef DEBUG
printf ( " DBG: Negate: %s: op = 0x%s \n " , DOFMT ( fmt ) , pr_addr ( op ) ) ;
# endif /* DEBUG */
/* The format type should already have been checked: */
switch ( fmt ) {
case fmt_single :
{
sim_fpu wop ;
unsigned32 ans ;
sim_fpu_32to ( & wop , op ) ;
sim_fpu_neg ( & wop , & wop ) ;
sim_fpu_to32 ( & ans , & wop ) ;
result = ans ;
break ;
}
case fmt_double :
{
sim_fpu wop ;
unsigned64 ans ;
sim_fpu_64to ( & wop , op ) ;
sim_fpu_neg ( & wop , & wop ) ;
sim_fpu_to64 ( & ans , & wop ) ;
result = ans ;
break ;
}
default :
fprintf ( stderr , " Bad switch \n " ) ;
abort ( ) ;
}
return ( result ) ;
}
uword64
Add ( op1 , op2 , fmt )
uword64 op1 ;
uword64 op2 ;
FP_formats fmt ;
{
uword64 result = 0 ;
# ifdef DEBUG
printf ( " DBG: Add: %s: op1 = 0x%s : op2 = 0x%s \n " , DOFMT ( fmt ) , pr_addr ( op1 ) , pr_addr ( op2 ) ) ;
# endif /* DEBUG */
/* The registers must specify FPRs valid for operands of type
" fmt " . If they are not valid , the result is undefined . */
/* The format type should already have been checked: */
switch ( fmt ) {
case fmt_single :
{
sim_fpu wop1 ;
sim_fpu wop2 ;
sim_fpu ans ;
unsigned32 res ;
sim_fpu_32to ( & wop1 , op1 ) ;
sim_fpu_32to ( & wop2 , op2 ) ;
sim_fpu_add ( & ans , & wop1 , & wop2 ) ;
sim_fpu_to32 ( & res , & ans ) ;
result = res ;
break ;
}
case fmt_double :
{
sim_fpu wop1 ;
sim_fpu wop2 ;
sim_fpu ans ;
unsigned64 res ;
sim_fpu_64to ( & wop1 , op1 ) ;
sim_fpu_64to ( & wop2 , op2 ) ;
sim_fpu_add ( & ans , & wop1 , & wop2 ) ;
sim_fpu_to64 ( & res , & ans ) ;
result = res ;
break ;
}
default :
fprintf ( stderr , " Bad switch \n " ) ;
abort ( ) ;
}
# ifdef DEBUG
printf ( " DBG: Add: returning 0x%s (format = %s) \n " , pr_addr ( result ) , DOFMT ( fmt ) ) ;
# endif /* DEBUG */
return ( result ) ;
}
uword64
Sub ( op1 , op2 , fmt )
uword64 op1 ;
uword64 op2 ;
FP_formats fmt ;
{
uword64 result = 0 ;
# ifdef DEBUG
printf ( " DBG: Sub: %s: op1 = 0x%s : op2 = 0x%s \n " , DOFMT ( fmt ) , pr_addr ( op1 ) , pr_addr ( op2 ) ) ;
# endif /* DEBUG */
/* The registers must specify FPRs valid for operands of type
" fmt " . If they are not valid , the result is undefined . */
/* The format type should already have been checked: */
switch ( fmt ) {
case fmt_single :
{
sim_fpu wop1 ;
sim_fpu wop2 ;
sim_fpu ans ;
unsigned32 res ;
sim_fpu_32to ( & wop1 , op1 ) ;
sim_fpu_32to ( & wop2 , op2 ) ;
sim_fpu_sub ( & ans , & wop1 , & wop2 ) ;
sim_fpu_to32 ( & res , & ans ) ;
result = res ;
}
break ;
case fmt_double :
{
sim_fpu wop1 ;
sim_fpu wop2 ;
sim_fpu ans ;
unsigned64 res ;
sim_fpu_64to ( & wop1 , op1 ) ;
sim_fpu_64to ( & wop2 , op2 ) ;
sim_fpu_sub ( & ans , & wop1 , & wop2 ) ;
sim_fpu_to64 ( & res , & ans ) ;
result = res ;
}
break ;
default :
fprintf ( stderr , " Bad switch \n " ) ;
abort ( ) ;
}
# ifdef DEBUG
printf ( " DBG: Sub: returning 0x%s (format = %s) \n " , pr_addr ( result ) , DOFMT ( fmt ) ) ;
# endif /* DEBUG */
return ( result ) ;
}
uword64
Multiply ( op1 , op2 , fmt )
uword64 op1 ;
uword64 op2 ;
FP_formats fmt ;
{
uword64 result = 0 ;
# ifdef DEBUG
printf ( " DBG: Multiply: %s: op1 = 0x%s : op2 = 0x%s \n " , DOFMT ( fmt ) , pr_addr ( op1 ) , pr_addr ( op2 ) ) ;
# endif /* DEBUG */
/* The registers must specify FPRs valid for operands of type
" fmt " . If they are not valid , the result is undefined . */
/* The format type should already have been checked: */
switch ( fmt ) {
case fmt_single :
{
sim_fpu wop1 ;
sim_fpu wop2 ;
sim_fpu ans ;
unsigned32 res ;
sim_fpu_32to ( & wop1 , op1 ) ;
sim_fpu_32to ( & wop2 , op2 ) ;
sim_fpu_mul ( & ans , & wop1 , & wop2 ) ;
sim_fpu_to32 ( & res , & ans ) ;
result = res ;
break ;
}
case fmt_double :
{
sim_fpu wop1 ;
sim_fpu wop2 ;
sim_fpu ans ;
unsigned64 res ;
sim_fpu_64to ( & wop1 , op1 ) ;
sim_fpu_64to ( & wop2 , op2 ) ;
sim_fpu_mul ( & ans , & wop1 , & wop2 ) ;
sim_fpu_to64 ( & res , & ans ) ;
result = res ;
break ;
}
default :
fprintf ( stderr , " Bad switch \n " ) ;
abort ( ) ;
}
# ifdef DEBUG
printf ( " DBG: Multiply: returning 0x%s (format = %s) \n " , pr_addr ( result ) , DOFMT ( fmt ) ) ;
# endif /* DEBUG */
return ( result ) ;
}
uword64
Divide ( op1 , op2 , fmt )
uword64 op1 ;
uword64 op2 ;
FP_formats fmt ;
{
uword64 result = 0 ;
# ifdef DEBUG
printf ( " DBG: Divide: %s: op1 = 0x%s : op2 = 0x%s \n " , DOFMT ( fmt ) , pr_addr ( op1 ) , pr_addr ( op2 ) ) ;
# endif /* DEBUG */
/* The registers must specify FPRs valid for operands of type
" fmt " . If they are not valid , the result is undefined . */
/* The format type should already have been checked: */
switch ( fmt ) {
case fmt_single :
{
sim_fpu wop1 ;
sim_fpu wop2 ;
sim_fpu ans ;
unsigned32 res ;
sim_fpu_32to ( & wop1 , op1 ) ;
sim_fpu_32to ( & wop2 , op2 ) ;
sim_fpu_div ( & ans , & wop1 , & wop2 ) ;
sim_fpu_to32 ( & res , & ans ) ;
result = res ;
break ;
}
case fmt_double :
{
sim_fpu wop1 ;
sim_fpu wop2 ;
sim_fpu ans ;
unsigned64 res ;
sim_fpu_64to ( & wop1 , op1 ) ;
sim_fpu_64to ( & wop2 , op2 ) ;
sim_fpu_div ( & ans , & wop1 , & wop2 ) ;
sim_fpu_to64 ( & res , & ans ) ;
result = res ;
break ;
}
default :
fprintf ( stderr , " Bad switch \n " ) ;
abort ( ) ;
}
# ifdef DEBUG
printf ( " DBG: Divide: returning 0x%s (format = %s) \n " , pr_addr ( result ) , DOFMT ( fmt ) ) ;
# endif /* DEBUG */
return ( result ) ;
}
uword64 UNUSED
Recip ( op , fmt )
uword64 op ;
FP_formats fmt ;
{
uword64 result = 0 ;
# ifdef DEBUG
printf ( " DBG: Recip: %s: op = 0x%s \n " , DOFMT ( fmt ) , pr_addr ( op ) ) ;
# endif /* DEBUG */
/* The registers must specify FPRs valid for operands of type
" fmt " . If they are not valid , the result is undefined . */
/* The format type should already have been checked: */
switch ( fmt ) {
case fmt_single :
{
sim_fpu wop ;
sim_fpu ans ;
unsigned32 res ;
sim_fpu_32to ( & wop , op ) ;
sim_fpu_inv ( & ans , & wop ) ;
sim_fpu_to32 ( & res , & ans ) ;
result = res ;
break ;
}
case fmt_double :
{
sim_fpu wop ;
sim_fpu ans ;
unsigned64 res ;
sim_fpu_64to ( & wop , op ) ;
sim_fpu_inv ( & ans , & wop ) ;
sim_fpu_to64 ( & res , & ans ) ;
result = res ;
break ;
}
default :
fprintf ( stderr , " Bad switch \n " ) ;
abort ( ) ;
}
# ifdef DEBUG
printf ( " DBG: Recip: returning 0x%s (format = %s) \n " , pr_addr ( result ) , DOFMT ( fmt ) ) ;
# endif /* DEBUG */
return ( result ) ;
}
uword64
SquareRoot ( op , fmt )
uword64 op ;
FP_formats fmt ;
{
uword64 result = 0 ;
# ifdef DEBUG
printf ( " DBG: SquareRoot: %s: op = 0x%s \n " , DOFMT ( fmt ) , pr_addr ( op ) ) ;
# endif /* DEBUG */
/* The registers must specify FPRs valid for operands of type
" fmt " . If they are not valid , the result is undefined . */
/* The format type should already have been checked: */
switch ( fmt ) {
case fmt_single :
{
sim_fpu wop ;
sim_fpu ans ;
unsigned32 res ;
sim_fpu_32to ( & wop , op ) ;
sim_fpu_sqrt ( & ans , & wop ) ;
sim_fpu_to32 ( & res , & ans ) ;
result = res ;
break ;
}
case fmt_double :
{
sim_fpu wop ;
sim_fpu ans ;
unsigned64 res ;
sim_fpu_64to ( & wop , op ) ;
sim_fpu_sqrt ( & ans , & wop ) ;
sim_fpu_to64 ( & res , & ans ) ;
result = res ;
break ;
}
default :
fprintf ( stderr , " Bad switch \n " ) ;
abort ( ) ;
}
# ifdef DEBUG
printf ( " DBG: SquareRoot: returning 0x%s (format = %s) \n " , pr_addr ( result ) , DOFMT ( fmt ) ) ;
# endif /* DEBUG */
return ( result ) ;
}
#if 0
uword64
Max ( uword64 op1 ,
uword64 op2 ,
FP_formats fmt )
{
int cmp ;
unsigned64 result ;
# ifdef DEBUG
printf ( " DBG: Max: %s: op1 = 0x%s : op2 = 0x%s \n " , DOFMT ( fmt ) , pr_addr ( op1 ) , pr_addr ( op2 ) ) ;
# endif /* DEBUG */
/* The registers must specify FPRs valid for operands of type
" fmt " . If they are not valid , the result is undefined . */
/* The format type should already have been checked: */
switch ( fmt )
{
case fmt_single :
{
sim_fpu wop1 ;
sim_fpu wop2 ;
sim_fpu_32to ( & wop1 , op1 ) ;
sim_fpu_32to ( & wop2 , op2 ) ;
cmp = sim_fpu_cmp ( & wop1 , & wop2 ) ;
break ;
}
case fmt_double :
{
sim_fpu wop1 ;
sim_fpu wop2 ;
sim_fpu_64to ( & wop1 , op1 ) ;
sim_fpu_64to ( & wop2 , op2 ) ;
cmp = sim_fpu_cmp ( & wop1 , & wop2 ) ;
break ;
}
default :
fprintf ( stderr , " Bad switch \n " ) ;
abort ( ) ;
}
switch ( cmp )
{
case SIM_FPU_IS_SNAN :
case SIM_FPU_IS_QNAN :
result = op1 ;
case SIM_FPU_IS_NINF :
case SIM_FPU_IS_NNUMBER :
case SIM_FPU_IS_NDENORM :
case SIM_FPU_IS_NZERO :
result = op2 ; /* op1 - op2 < 0 */
case SIM_FPU_IS_PINF :
case SIM_FPU_IS_PNUMBER :
case SIM_FPU_IS_PDENORM :
case SIM_FPU_IS_PZERO :
result = op1 ; /* op1 - op2 > 0 */
default :
fprintf ( stderr , " Bad switch \n " ) ;
abort ( ) ;
}
# ifdef DEBUG
printf ( " DBG: Max: returning 0x%s (format = %s) \n " , pr_addr ( result ) , DOFMT ( fmt ) ) ;
# endif /* DEBUG */
return ( result ) ;
}
# endif
#if 0
uword64
Min ( uword64 op1 ,
uword64 op2 ,
FP_formats fmt )
{
int cmp ;
unsigned64 result ;
# ifdef DEBUG
printf ( " DBG: Min: %s: op1 = 0x%s : op2 = 0x%s \n " , DOFMT ( fmt ) , pr_addr ( op1 ) , pr_addr ( op2 ) ) ;
# endif /* DEBUG */
/* The registers must specify FPRs valid for operands of type
" fmt " . If they are not valid , the result is undefined . */
/* The format type should already have been checked: */
switch ( fmt )
{
case fmt_single :
{
sim_fpu wop1 ;
sim_fpu wop2 ;
sim_fpu_32to ( & wop1 , op1 ) ;
sim_fpu_32to ( & wop2 , op2 ) ;
cmp = sim_fpu_cmp ( & wop1 , & wop2 ) ;
break ;
}
case fmt_double :
{
sim_fpu wop1 ;
sim_fpu wop2 ;
sim_fpu_64to ( & wop1 , op1 ) ;
sim_fpu_64to ( & wop2 , op2 ) ;
cmp = sim_fpu_cmp ( & wop1 , & wop2 ) ;
break ;
}
default :
fprintf ( stderr , " Bad switch \n " ) ;
abort ( ) ;
}
switch ( cmp )
{
case SIM_FPU_IS_SNAN :
case SIM_FPU_IS_QNAN :
result = op1 ;
case SIM_FPU_IS_NINF :
case SIM_FPU_IS_NNUMBER :
case SIM_FPU_IS_NDENORM :
case SIM_FPU_IS_NZERO :
result = op1 ; /* op1 - op2 < 0 */
case SIM_FPU_IS_PINF :
case SIM_FPU_IS_PNUMBER :
case SIM_FPU_IS_PDENORM :
case SIM_FPU_IS_PZERO :
result = op2 ; /* op1 - op2 > 0 */
default :
fprintf ( stderr , " Bad switch \n " ) ;
abort ( ) ;
}
# ifdef DEBUG
printf ( " DBG: Min: returning 0x%s (format = %s) \n " , pr_addr ( result ) , DOFMT ( fmt ) ) ;
# endif /* DEBUG */
return ( result ) ;
}
# endif
uword64
convert ( SIM_DESC sd ,
sim_cpu * cpu ,
address_word cia ,
int rm ,
uword64 op ,
FP_formats from ,
FP_formats to )
{
sim_fpu wop ;
sim_fpu_round round ;
unsigned32 result32 ;
unsigned64 result64 ;
# ifdef DEBUG
#if 0 /* FIXME: doesn't compile */
printf ( " DBG: Convert: mode %s : op 0x%s : from %s : to %s : (PC = 0x%s) \n " , RMMODE ( rm ) , pr_addr ( op ) , DOFMT ( from ) , DOFMT ( to ) , pr_addr ( IPC ) ) ;
# endif
# endif /* DEBUG */
switch ( rm )
{
case FP_RM_NEAREST :
/* Round result to nearest representable value. When two
representable values are equally near , round to the value
that has a least significant bit of zero ( i . e . is even ) . */
round = sim_fpu_round_near ;
break ;
case FP_RM_TOZERO :
/* Round result to the value closest to, and not greater in
magnitude than , the result . */
round = sim_fpu_round_zero ;
break ;
case FP_RM_TOPINF :
/* Round result to the value closest to, and not less than,
the result . */
round = sim_fpu_round_up ;
break ;
case FP_RM_TOMINF :
/* Round result to the value closest to, and not greater than,
the result . */
round = sim_fpu_round_down ;
break ;
default :
round = 0 ;
fprintf ( stderr , " Bad switch \n " ) ;
abort ( ) ;
}
/* Convert the input to sim_fpu internal format */
switch ( from )
{
case fmt_double :
sim_fpu_64to ( & wop , op ) ;
break ;
case fmt_single :
sim_fpu_32to ( & wop , op ) ;
break ;
case fmt_word :
sim_fpu_i32to ( & wop , op , round ) ;
break ;
case fmt_long :
sim_fpu_i64to ( & wop , op , round ) ;
break ;
default :
fprintf ( stderr , " Bad switch \n " ) ;
abort ( ) ;
}
/* Convert sim_fpu format into the output */
/* The value WOP is converted to the destination format, rounding
using mode RM . When the destination is a fixed - point format , then
a source value of Infinity , NaN or one which would round to an
integer outside the fixed point range then an IEEE Invalid
Operation condition is raised . */
switch ( to )
{
case fmt_single :
sim_fpu_round_32 ( & wop , round , 0 ) ;
sim_fpu_to32 ( & result32 , & wop ) ;
result64 = result32 ;
break ;
case fmt_double :
sim_fpu_round_64 ( & wop , round , 0 ) ;
sim_fpu_to64 ( & result64 , & wop ) ;
break ;
case fmt_word :
sim_fpu_to32i ( & result32 , & wop , round ) ;
result64 = result32 ;
break ;
case fmt_long :
sim_fpu_to64i ( & result64 , & wop , round ) ;
break ;
default :
result64 = 0 ;
fprintf ( stderr , " Bad switch \n " ) ;
abort ( ) ;
}
# ifdef DEBUG
printf ( " DBG: Convert: returning 0x%s (to format = %s) \n " , pr_addr ( result64 ) , DOFMT ( to ) ) ;
# endif /* DEBUG */
return ( result64 ) ;
}
/*-- co-processor support routines ------------------------------------------*/
static int UNUSED
CoProcPresent ( unsigned int coproc_number )
{
/* Return TRUE if simulator provides a model for the given co-processor number */
return ( 0 ) ;
}
void
cop_lw ( SIM_DESC sd ,
sim_cpu * cpu ,
address_word cia ,
int coproc_num ,
int coproc_reg ,
unsigned int memword )
{
switch ( coproc_num )
{
case 1 :
if ( CURRENT_FLOATING_POINT = = HARD_FLOATING_POINT )
{
# ifdef DEBUG
printf ( " DBG: COP_LW: memword = 0x%08X (uword64)memword = 0x%s \n " , memword , pr_addr ( memword ) ) ;
# endif
StoreFPR ( coproc_reg , fmt_word , ( uword64 ) memword ) ;
FPR_STATE [ coproc_reg ] = fmt_uninterpreted ;
break ;
}
default :
#if 0 /* this should be controlled by a configuration option */
sim_io_printf ( sd , " COP_LW(%d,%d,0x%08X) at PC = 0x%s : TODO (architecture specific) \n " , coproc_num , coproc_reg , memword , pr_addr ( cia ) ) ;
# endif
break ;
}
return ;
}
void
cop_ld ( SIM_DESC sd ,
sim_cpu * cpu ,
address_word cia ,
int coproc_num ,
int coproc_reg ,
uword64 memword )
{
# ifdef DEBUG
printf ( " DBG: COP_LD: coproc_num = %d, coproc_reg = %d, value = 0x%s : PC = 0x%s \n " , coproc_num , coproc_reg , pr_uword64 ( memword ) , pr_addr ( cia ) ) ;
# endif
switch ( coproc_num ) {
case 1 :
if ( CURRENT_FLOATING_POINT = = HARD_FLOATING_POINT )
{
StoreFPR ( coproc_reg , fmt_uninterpreted , memword ) ;
break ;
}
default :
#if 0 /* this message should be controlled by a configuration option */
sim_io_printf ( sd , " COP_LD(%d,%d,0x%s) at PC = 0x%s : TODO (architecture specific) \n " , coproc_num , coproc_reg , pr_addr ( memword ) , pr_addr ( cia ) ) ;
# endif
break ;
}
return ;
}
unsigned int
cop_sw ( SIM_DESC sd ,
sim_cpu * cpu ,
address_word cia ,
int coproc_num ,
int coproc_reg )
{
unsigned int value = 0 ;
switch ( coproc_num )
{
case 1 :
if ( CURRENT_FLOATING_POINT = = HARD_FLOATING_POINT )
{
FP_formats hold ;
hold = FPR_STATE [ coproc_reg ] ;
FPR_STATE [ coproc_reg ] = fmt_word ;
value = ( unsigned int ) ValueFPR ( coproc_reg , fmt_uninterpreted ) ;
FPR_STATE [ coproc_reg ] = hold ;
break ;
}
default :
#if 0 /* should be controlled by configuration option */
sim_io_printf ( sd , " COP_SW(%d,%d) at PC = 0x%s : TODO (architecture specific) \n " , coproc_num , coproc_reg , pr_addr ( cia ) ) ;
# endif
break ;
}
return ( value ) ;
}
uword64
cop_sd ( SIM_DESC sd ,
sim_cpu * cpu ,
address_word cia ,
int coproc_num ,
int coproc_reg )
{
uword64 value = 0 ;
switch ( coproc_num )
{
case 1 :
if ( CURRENT_FLOATING_POINT = = HARD_FLOATING_POINT )
{
value = ValueFPR ( coproc_reg , fmt_uninterpreted ) ;
break ;
}
default :
#if 0 /* should be controlled by configuration option */
sim_io_printf ( sd , " COP_SD(%d,%d) at PC = 0x%s : TODO (architecture specific) \n " , coproc_num , coproc_reg , pr_addr ( cia ) ) ;
# endif
break ;
}
return ( value ) ;
}
void
decode_coproc ( SIM_DESC sd ,
sim_cpu * cpu ,
address_word cia ,
unsigned int instruction )
{
int coprocnum = ( ( instruction > > 26 ) & 3 ) ;
switch ( coprocnum )
{
case 0 : /* standard CPU control and cache registers */
{
int code = ( ( instruction > > 21 ) & 0x1F ) ;
int rt = ( ( instruction > > 16 ) & 0x1F ) ;
int rd = ( ( instruction > > 11 ) & 0x1F ) ;
int tail = instruction & 0x3ff ;
/* R4000 Users Manual (second edition) lists the following CP0
instructions :
CODE > < - RT > < RD - > < - - TAIL - - - >
DMFC0 Doubleword Move From CP0 ( VR4100 = 01000000001 tttttddddd00000000000 )
DMTC0 Doubleword Move To CP0 ( VR4100 = 01000000101 tttttddddd00000000000 )
MFC0 word Move From CP0 ( VR4100 = 01000000000 tttttddddd00000000000 )
MTC0 word Move To CP0 ( VR4100 = 01000000100 tttttddddd00000000000 )
TLBR Read Indexed TLB Entry ( VR4100 = 01000010000000000000000000000001 )
TLBWI Write Indexed TLB Entry ( VR4100 = 01000010000000000000000000000010 )
TLBWR Write Random TLB Entry ( VR4100 = 01000010000000000000000000000110 )
TLBP Probe TLB for Matching Entry ( VR4100 = 01000010000000000000000000001000 )
CACHE Cache operation ( VR4100 = 101111 bbbbbpppppiiiiiiiiiiiiiiii )
ERET Exception return ( VR4100 = 01000010000000000000000000011000 )
*/
if ( ( ( code = = 0x00 ) | | ( code = = 0x04 ) ) & & tail = = 0 )
{
/* M[TF]C0 - 32 bit word */
switch ( rd ) /* NOTEs: Standard CP0 registers */
{
/* 0 = Index R4000 VR4100 VR4300 */
/* 1 = Random R4000 VR4100 VR4300 */
/* 2 = EntryLo0 R4000 VR4100 VR4300 */
/* 3 = EntryLo1 R4000 VR4100 VR4300 */
/* 4 = Context R4000 VR4100 VR4300 */
/* 5 = PageMask R4000 VR4100 VR4300 */
/* 6 = Wired R4000 VR4100 VR4300 */
/* 8 = BadVAddr R4000 VR4100 VR4300 */
/* 9 = Count R4000 VR4100 VR4300 */
/* 10 = EntryHi R4000 VR4100 VR4300 */
/* 11 = Compare R4000 VR4100 VR4300 */
/* 12 = SR R4000 VR4100 VR4300 */
# ifdef SUBTARGET_R3900
case 3 :
/* 3 = Config R3900 */
case 7 :
/* 7 = Cache R3900 */
case 15 :
/* 15 = PRID R3900 */
/* ignore */
break ;
case 8 :
/* 8 = BadVAddr R4000 VR4100 VR4300 */
if ( code = = 0x00 )
GPR [ rt ] = COP0_BADVADDR ;
else
COP0_BADVADDR = GPR [ rt ] ;
break ;
# endif /* SUBTARGET_R3900 */
case 12 :
if ( code = = 0x00 )
GPR [ rt ] = SR ;
else
SR = GPR [ rt ] ;
break ;
/* 13 = Cause R4000 VR4100 VR4300 */
case 13 :
if ( code = = 0x00 )
GPR [ rt ] = CAUSE ;
else
CAUSE = GPR [ rt ] ;
break ;
/* 14 = EPC R4000 VR4100 VR4300 */
case 14 :
if ( code = = 0x00 )
GPR [ rt ] = ( signed_word ) ( signed_address ) EPC ;
else
EPC = GPR [ rt ] ;
break ;
/* 15 = PRId R4000 VR4100 VR4300 */
# ifdef SUBTARGET_R3900
/* 16 = Debug */
case 16 :
if ( code = = 0x00 )
GPR [ rt ] = Debug ;
else
Debug = GPR [ rt ] ;
break ;
# else
/* 16 = Config R4000 VR4100 VR4300 */
case 16 :
if ( code = = 0x00 )
GPR [ rt ] = C0_CONFIG ;
else
C0_CONFIG = GPR [ rt ] ;
break ;
# endif
# ifdef SUBTARGET_R3900
/* 17 = Debug */
case 17 :
if ( code = = 0x00 )
GPR [ rt ] = DEPC ;
else
DEPC = GPR [ rt ] ;
break ;
# else
/* 17 = LLAddr R4000 VR4100 VR4300 */
# endif
/* 18 = WatchLo R4000 VR4100 VR4300 */
/* 19 = WatchHi R4000 VR4100 VR4300 */
/* 20 = XContext R4000 VR4100 VR4300 */
/* 26 = PErr or ECC R4000 VR4100 VR4300 */
/* 27 = CacheErr R4000 VR4100 */
/* 28 = TagLo R4000 VR4100 VR4300 */
/* 29 = TagHi R4000 VR4100 VR4300 */
/* 30 = ErrorEPC R4000 VR4100 VR4300 */
GPR [ rt ] = 0xDEADC0DE ; /* CPR[0,rd] */
/* CPR[0,rd] = GPR[rt]; */
default :
if ( code = = 0x00 )
GPR [ rt ] = ( signed_word ) ( signed32 ) COP0_GPR [ rd ] ;
else
COP0_GPR [ rd ] = GPR [ rt ] ;
#if 0
if ( code = = 0x00 )
sim_io_printf ( sd , " Warning: MFC0 %d,%d ignored, PC=%08x (architecture specific) \n " , rt , rd , ( unsigned ) cia ) ;
else
sim_io_printf ( sd , " Warning: MTC0 %d,%d ignored, PC=%08x (architecture specific) \n " , rt , rd , ( unsigned ) cia ) ;
# endif
}
}
else if ( code = = 0x10 & & ( tail & 0x3f ) = = 0x18 )
{
/* ERET */
if ( SR & status_ERL )
{
/* Oops, not yet available */
sim_io_printf ( sd , " Warning: ERET when SR[ERL] set not handled yet " ) ;
PC = EPC ;
SR & = ~ status_ERL ;
}
else
{
PC = EPC ;
SR & = ~ status_EXL ;
}
}
else if ( code = = 0x10 & & ( tail & 0x3f ) = = 0x10 )
{
/* RFE */
# ifdef SUBTARGET_R3900
/* TX39: Copy IEp/KUp -> IEc/KUc, and IEo/KUo -> IEp/KUp */
/* shift IE/KU history bits right */
SR = LSMASKED32 ( SR , 31 , 4 ) | LSINSERTED32 ( LSEXTRACTED32 ( SR , 5 , 2 ) , 3 , 0 ) ;
/* TODO: CACHE register */
# endif /* SUBTARGET_R3900 */
}
else if ( code = = 0x10 & & ( tail & 0x3f ) = = 0x1F )
{
/* DERET */
Debug & = ~ Debug_DM ;
DELAYSLOT ( ) ;
DSPC = DEPC ;
}
else
sim_io_eprintf ( sd , " Unrecognised COP0 instruction 0x%08X at PC = 0x%s : No handler present \n " , instruction , pr_addr ( cia ) ) ;
/* TODO: When executing an ERET or RFE instruction we should
clear LLBIT , to ensure that any out - standing atomic
read / modify / write sequence fails . */
}
break ;
case 2 : /* co-processor 2 */
{
int handle = 0 ;
if ( ! handle )
{
sim_io_eprintf ( sd , " COP2 instruction 0x%08X at PC = 0x%s : No handler present \n " ,
instruction , pr_addr ( cia ) ) ;
}
}
break ;
case 1 : /* should not occur (FPU co-processor) */
case 3 : /* should not occur (FPU co-processor) */
SignalException ( ReservedInstruction , instruction ) ;
break ;
}
return ;
}
/* This code copied from gdb's utils.c. Would like to share this code,
but don ' t know of a common place where both could get to it . */
/* Temporary storage using circular buffer */
# define NUMCELLS 16
# define CELLSIZE 32
static char *
get_cell ( void )
{
static char buf [ NUMCELLS ] [ CELLSIZE ] ;
static int cell = 0 ;
if ( + + cell > = NUMCELLS ) cell = 0 ;
return buf [ cell ] ;
}
/* Print routines to handle variable size regs, etc */
/* Eliminate warning from compiler on 32-bit systems */
static int thirty_two = 32 ;
char *
pr_addr ( addr )
SIM_ADDR addr ;
{
char * paddr_str = get_cell ( ) ;
switch ( sizeof ( addr ) )
{
case 8 :
sprintf ( paddr_str , " %08lx%08lx " ,
( unsigned long ) ( addr > > thirty_two ) , ( unsigned long ) ( addr & 0xffffffff ) ) ;
break ;
case 4 :
sprintf ( paddr_str , " %08lx " , ( unsigned long ) addr ) ;
break ;
case 2 :
sprintf ( paddr_str , " %04x " , ( unsigned short ) ( addr & 0xffff ) ) ;
break ;
default :
sprintf ( paddr_str , " %x " , addr ) ;
}
return paddr_str ;
}
char *
pr_uword64 ( addr )
uword64 addr ;
{
char * paddr_str = get_cell ( ) ;
sprintf ( paddr_str , " %08lx%08lx " ,
( unsigned long ) ( addr > > thirty_two ) , ( unsigned long ) ( addr & 0xffffffff ) ) ;
return paddr_str ;
}
void
mips_core_signal ( SIM_DESC sd ,
sim_cpu * cpu ,
sim_cia cia ,
unsigned map ,
int nr_bytes ,
address_word addr ,
transfer_type transfer ,
sim_core_signals sig )
{
const char * copy = ( transfer = = read_transfer ? " read " : " write " ) ;
address_word ip = CIA_ADDR ( cia ) ;
switch ( sig )
{
case sim_core_unmapped_signal :
sim_io_eprintf ( sd , " mips-core: %d byte %s to unmapped address 0x%lx at 0x%lx \n " ,
nr_bytes , copy ,
( unsigned long ) addr , ( unsigned long ) ip ) ;
COP0_BADVADDR = addr ;
SignalExceptionDataReference ( ) ;
break ;
case sim_core_unaligned_signal :
sim_io_eprintf ( sd , " mips-core: %d byte %s to unaligned address 0x%lx at 0x%lx \n " ,
nr_bytes , copy ,
( unsigned long ) addr , ( unsigned long ) ip ) ;
COP0_BADVADDR = addr ;
if ( transfer = = read_transfer )
SignalExceptionAddressLoad ( ) ;
else
SignalExceptionAddressStore ( ) ;
break ;
default :
sim_engine_abort ( sd , cpu , cia ,
" mips_core_signal - internal error - bad switch " ) ;
}
}
void
mips_cpu_exception_trigger ( SIM_DESC sd , sim_cpu * cpu , address_word cia )
{
ASSERT ( cpu ! = NULL ) ;
if ( cpu - > exc_suspended > 0 )
sim_io_eprintf ( sd , " Warning, nested exception triggered (%d) \n " , cpu - > exc_suspended ) ;
PC = cia ;
memcpy ( cpu - > exc_trigger_registers , cpu - > registers , sizeof ( cpu - > exc_trigger_registers ) ) ;
cpu - > exc_suspended = 0 ;
}
void
mips_cpu_exception_suspend ( SIM_DESC sd , sim_cpu * cpu , int exception )
{
ASSERT ( cpu ! = NULL ) ;
if ( cpu - > exc_suspended > 0 )
sim_io_eprintf ( sd , " Warning, nested exception signal (%d then %d) \n " ,
cpu - > exc_suspended , exception ) ;
memcpy ( cpu - > exc_suspend_registers , cpu - > registers , sizeof ( cpu - > exc_suspend_registers ) ) ;
memcpy ( cpu - > registers , cpu - > exc_trigger_registers , sizeof ( cpu - > registers ) ) ;
cpu - > exc_suspended = exception ;
}
void
mips_cpu_exception_resume ( SIM_DESC sd , sim_cpu * cpu , int exception )
{
ASSERT ( cpu ! = NULL ) ;
if ( exception = = 0 & & cpu - > exc_suspended > 0 )
{
/* warn not for breakpoints */
if ( cpu - > exc_suspended ! = sim_signal_to_host ( sd , SIM_SIGTRAP ) )
sim_io_eprintf ( sd , " Warning, resuming but ignoring pending exception signal (%d) \n " ,
cpu - > exc_suspended ) ;
}
else if ( exception ! = 0 & & cpu - > exc_suspended > 0 )
{
if ( exception ! = cpu - > exc_suspended )
sim_io_eprintf ( sd , " Warning, resuming with mismatched exception signal (%d vs %d) \n " ,
cpu - > exc_suspended , exception ) ;
memcpy ( cpu - > registers , cpu - > exc_suspend_registers , sizeof ( cpu - > registers ) ) ;
}
else if ( exception ! = 0 & & cpu - > exc_suspended = = 0 )
{
sim_io_eprintf ( sd , " Warning, ignoring spontanous exception signal (%d) \n " , exception ) ;
}
cpu - > exc_suspended = 0 ;
}
/*---------------------------------------------------------------------------*/
/*> EOF interp.c <*/