* ========== Copyright Header Begin ==========================================
* OpenSPARC T2 Processor File: dumbserial.c
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
* The above named program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2 as published by the Free Software Foundation.
* The above named 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 work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
* ========== Copyright Header End ============================================
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
#pragma ident "@(#)dumbserial.c 1.57 07/10/12 SMI"
* This is a very generic serial I/O / console device
* Basically, write to the out register and output the
* Read from the in register and get a character of
* A status register is a avilable to poll to indicate if
* a character is available for input ..
* ... not entirely dis-similar to the NEC 16550 device ..
#include <sys/param.h> /* MAXPATHLEN */
#define DBGX(s) do { } while (0)
* A dumb serial device - briefly modeled on the NS 16550 device
* ... i.e. register bit fields are similar, but that's about it.
* We support input and output character buffering.
* Eventually these sizes will be settable from the configfile
* Also eventually we will understand baud rates etc. and fake
* For the moment, we support only a simple status poll, byte
* Status simply returns, byte-available, underrun, and overrun
* for input info. Nothing for output (yet).
* Registers (8-bits only - 8byte addressing, upper bits read 0 write ignored)
* 0 R Input data register
* 0 W Output data register
* 1 RW Interrupt enable register
* 2 R Interrupt indentification register
* 2 W FIFO control register
* 3 RW Line control register
* 4 RW Modem control register
* 5 RW Line status register
* 6 RW Modem status register
* See 16550 data sheet p 14 - table M
DS_Output
= 0x0, /* WO */
DS_IntIdent
= 0x2, /* RO */
DS_FIFOCtrl
= 0x2, /* WO */
#if ERROR_TRAP_GEN /* { */
#endif /* } ERROR_TRAP_GEN */
* static only to avoid name clashes with other
* modules ... in reality these are exported
* via the dev_type_t struct pointers
static void ds_parse(config_dev_t
*);
static void ds_init(config_dev_t
*);
static void ds_dump(config_dev_t
*);
static bool_t
ds_cpu_access(simcpu_t
*, config_addr_t
*, tpaddr_t offset
, maccess_t op
, uint64_t * regp
);
#define ptest(_s) if (fds.revents & _s) printf(","#_s)
dev_type_t dev_type_dumbserial
={
generic_device_non_cacheable
,
config_dev_t
* config_devp
; /* back pointer to device record */
bool_t dlab
; /* DLAB bit from LCR */
/* device registers .. */
#define DS_LSTAT_DATA_READY 0x1
#define DS_LSTAT_OVERRUN 0x2
#define DS_LSTAT_PARTIY_ERR 0x4
#define DS_LSTAT_FRAMING_ERR 0x8
#define DS_LSTAT_BREAK 0x10
#define DS_LSTAT_TX_HOLD 0x20
#define DS_LSTAT_TX_EMPTY 0x40
#define DS_LSTAT_RCV_ERR 0x80
#define DEFAULT_RXFIFOSZ 1024
uint8_t *bufp
; /* Non null if allocated */
int reg_shift
; /* register alignment 0 .. 3 (default = 0 = byte align) */
#define DS_REG_SHIFT_DEF 0
/* the following if uses_xterm is set */
#define DEFAULT_XTERM_STR "/usr/openwin/bin/xterm -T TTY -e /bin/telnet %s %d &"
int tty_skt
; /* socket to send / receive to client on */
pthread_mutex_t tty_lock
;
ds_tildestate_t tilde_state
;
/* following are for exit_string and time_string */
static void ds_rxfifo_alloc(ds_state_t
* dsp
);
static void ds_parse_rxfifo_contents(ds_state_t
* dsp
);
static void ds_reg_init(ds_state_t
* dsp
, int regnum
, int val
);
static void create_term(ds_state_t
* dsp
);
static void * ds_input_thr(void * ptr
);
static void ds_insert_bytes(ds_state_t
* dsp
, uint8_t * bufp
, int len
);
static void dump_buf(char * strp
, uint8_t * bufp
, int len
);
static void ds_dump_instruction_counts(ds_state_t
* dsp
);
static void ds_output(ds_state_t
*dsp
, char *str
);
static void ds_save_state(ds_state_t
* dsp
);
static void ds_debug_hook_dump(ds_state_t
* dsp
);
/* Nasty hack for TLB debugging - to go away FIXME */
static void ds_dump_tlb(ds_state_t
* dsp
, bool_t is_itlb
);
#if ERROR_TRAP_GEN /* { */
static void ds_load_error_file(ds_state_t
* dsp
);
static void ds_dump_error_active(ds_state_t
* dsp
);
static void ds_dump_error_supported(ds_state_t
* dsp
);
* Complete the creation and parsing of this specific cpu
* .. basically parse and allocate what is necessary.
void ds_parse(config_dev_t
* config_devp
)
DBG( printf("dumbserial_parse: parsing device %d\n", config_devp
->device_id
); );
dsp
= (void*)Xcalloc(1, ds_state_t
);
config_devp
->devp
= (void*)dsp
;
dsp
->has_registers
= false;
dsp
->uses_xterm
= false; /* default: output but no input */
dsp
->reg_shift
= DS_REG_SHIFT_DEF
;
/* setup initial register values */
dsp
->line_status
= DS_LSTAT_TX_EMPTY
| DS_LSTAT_TX_HOLD
;
dsp
->xterm_string
= NULL
;
dsp
->xterm_string_pos
= 0;
dsp
->exit_on_string
= false;
lex_fatal("unexpected token");
while ( (tok
= lex_get_token()) != T_R_Brace
) {
if (streq(lex
.strp
, "xterm")) {
if (dsp
->term_strp
!= NULL
) lex_fatal("xterm directive given more than once");
dsp
->term_strp
= Xstrdup(DEFAULT_XTERM_STR
);
dsp
->term_strp
= Xstrdup(lex
.strp
);
if (streq(lex
.strp
, "exit_string") || streq(lex
.strp
, "time_string")) {
if (dsp
->xterm_string
!= NULL
)
lex_fatal("exit_string or time_string already declared");
time(&(dsp
->start_time
));
if (streq(lex
.strp
, "exit_string"))
dsp
->exit_on_string
= true;
lex_fatal("exit/time_string needs a valid 'string'");
if ((int)lex
.val
> 127) {
lex_fatal("time_string must be string or Ascii value <127 ");
dsp
->xterm_string
= Xcalloc(2, char);
dsp
->xterm_string
[0] = (char)lex
.val
;
dsp
->xterm_string
[1] = '\0';
dsp
->xterm_string
= Xstrdup(lex
.strp
);
if (strlen(dsp
->xterm_string
) == 0)
lex_fatal("exit/time_string 'string' length is 0");
if (streq(lex
.strp
, "rxfifosz")) {
EXEC_WARNING(("dumbserial: rxfifosz is a depricated directive. Use rxfifo instead."));
if (dsp
->in
.bufp
!= NULL
) lex_fatal("fxfifosz or rxfifo already declared");
lex_fatal("rxfifosz not positive");
dsp
->in
.size
= (int)lex
.val
;
if (streq(lex
.strp
, "rxfifo")) {
if (dsp
->in
.bufp
!= NULL
) lex_fatal("fxfifosz or rxfifo already declared");
lex_fatal("rxfifosz not positive");
dsp
->in
.size
= (int)lex
.val
;
ds_parse_rxfifo_contents(dsp
);
if (streq(lex
.strp
, "regshift")) {
if ((int)lex
.val
< 0 || (int)lex
.val
>3) {
lex_fatal("regshift must be an integer from 0 to 3");
dsp
->reg_shift
= (int)lex
.val
;
if (streq(lex
.strp
, "reg")) {
ds_reg_init(dsp
, regnum
, (int)lex
.val
);
if ((config_devp
->addrp
->range
>> dsp
->reg_shift
) < 0x8)
fatal("dumbserial: dumbserial requires address space size of 0x%x", 0x8<<dsp
->reg_shift
);
/* If xterm requested make sure we have an input buffer */
if (dsp
->uses_xterm
&& dsp
->in
.size
== -1) {
dsp
->in
.size
= DEFAULT_RXFIFOSZ
;
/* If we have an input buffer but no xterm .. fail */
if (dsp
->in
.bufp
!= NULL
&& !dsp
->uses_xterm
) lex_fatal("receive fifo has been specified, but no xterm directive for input delivery");
* Basic allocation of fifo space
static void ds_rxfifo_alloc(ds_state_t
* dsp
)
dsp
->in
.bufp
= Xcalloc(dsp
->in
.size
, uint8_t);
static void ds_parse_rxfifo_contents(ds_state_t
* dsp
)
while ( dsp
->in
.tail
<dsp
->in
.size
) {
if (lex
.val
<0 || lex
.val
>255) lex_fatal("Illegal rxfifo contents");
dsp
->in
.bufp
[dsp
->in
.tail
] = (int)lex
.val
;
lex_fatal("Unexpected token parsing rxfifo contents");
lex_fatal("Too many initialisers in rxfifo directive\n");
dsp
->in
.count
= dsp
->in
.tail
;
* Initialise the device after parsing is complete
void ds_init(config_dev_t
* config_devp
)
dsp
= (ds_state_t
*)config_devp
->devp
;
/* OK register values are now live */
dsp
->has_registers
= true;
/* if input fifo required it was created in parse phase */
ASSERT(!dsp
->uses_xterm
|| (dsp
->uses_xterm
&& dsp
->in
.bufp
!=NULL
));
/* if TTY to be created then do so ... */
if (dsp
->uses_xterm
) create_term(dsp
);
dsp
->config_devp
= config_devp
; /* back pointer */
* Dumb serial configuration dump
void ds_dump(config_dev_t
* config_devp
)
dsp
= (ds_state_t
*)config_devp
->devp
;
pi("regshift %d ;\n", dsp
->reg_shift
);
if (strcmp(dsp
->term_strp
, DEFAULT_XTERM_STR
)==0) {
pi("xterm \"%s\" ;\n", dsp
->term_strp
);
if (dsp
->in
.bufp
!= NULL
) {
ASSERT( dsp
->in
.count
<= dsp
->in
.size
);
pi("rxfifo %d { 0x%02x", dsp
->in
.size
, dsp
->in
.bufp
[dsp
->in
.head
]);
for (cnt
=1, idx
=dsp
->in
.head
; cnt
!=dsp
->in
.count
; cnt
++) {
if (idx
>=dsp
->in
.size
) idx
=0;
fprintf(dumpinfo
.outp
, ", 0x%02x", dsp
->in
.bufp
[idx
]);
fprintf(dumpinfo
.outp
, " }\n");
pi("rxfifo %d ;\n", dsp
->in
.size
);
if (dsp
->has_registers
) {
/* Dump live register contents here ... */
pi("reg 0x%x 0x%x ;\n", (int)DS_LineStatus
, dsp
->line_status
);
pi("reg 0x%x 0x%x ;\n", (int)DS_LineCtrl
, dsp
->dlab
? DS_LCR_DLAB
: 0);
pi("reg 0x%x 0x%x ;\n", (int)DS_Scratch
, dsp
->scratch
);
static void ds_reg_init(ds_state_t
* dsp
, int regnum
, int val
)
dsp
->dlab
= (val
& DS_LCR_DLAB
)!=0 ? true : false;
dsp
->has_registers
= true;
* Returns true if device access completes successfully
ds_cpu_access(simcpu_t
*sp
, config_addr_t
* cap
, tpaddr_t offset
, maccess_t op
, uint64_t * regp
)
ds_state_t
* dsp
= (ds_state_t
*)cap
->config_devp
->devp
;
* Unique identifier to tag guest/hv console output with legion time
* dump. This works when you have multiple dumbserial devices (one
* for hv, another for guest)as each line of console output on
* either serial device gets a unique tag.
static int output_tag
= 0;
size
= op
& MA_Size_Mask
;
acc_size
= (1<<dsp
->reg_shift
);
if ((offset
& (((tpaddr_t
)acc_size
)-1))!=0) {
EXEC_WARNING(("dumbserial: Illegal device access - offset "
"(0x%llx) not %d byte aligned",
(uint64_t)offset
, acc_size
));
EXEC_WARNING(("dumbserial: Illegal device access - op size "
reg
= offset
>> dsp
->reg_shift
;
EXEC_WARNING(("dumbserial: Illegal device access - no reg at "
"offset 0x%llx", offset
));
if (dsp
->dlab
&& (reg
== DS_Input
|| reg
== DS_IntEnable
))
pthread_mutex_lock(&dsp
->tty_lock
);
if (dsp
->in
.count
== 0) {
dsp
->line_status
&= ~DS_LSTAT_DATA_READY
;
val
= dsp
->in
.bufp
[dsp
->in
.head
];
if (dsp
->in
.head
>= dsp
->in
.size
) dsp
->in
.head
= 0;
if (dsp
->in
.count
== 0) {
dsp
->line_status
&= ~DS_LSTAT_DATA_READY
;
pthread_mutex_unlock(&dsp
->tty_lock
);
IMPL_WARNING(("dumbserial: Interrupt enable not yet supported"));
IMPL_WARNING(("dumbserial: FIFO control not yet supported"));
IMPL_WARNING(("dumbserial: Line control not yet supported"));
if (dsp
->dlab
) val
|= DS_LCR_DLAB
;
IMPL_WARNING(("dumbserial: Modem control not yet supported"));
/* FIXME - more to do here */
/* TX always empty for the moment */
pthread_mutex_lock(&dsp
->tty_lock
);
pthread_mutex_unlock(&dsp
->tty_lock
);
IMPL_WARNING(("dumbserial: Modem status not yet supported"));
IMPL_WARNING(("dumbserial: Divisor (low) not yet supported"));
IMPL_WARNING(("dumbserial: Divisor (high) not yet supported"));
EXEC_WARNING(("dumbserial: illegal register accessed - offset 0x%x", offset
));
if (MA_LdSigned
== op
) val
= (uint64_t)(sint64_t
)(sint8_t
)val
;
val
= *regp
& 0xff; /* byte acces only */
if (dsp
->xterm_string
!= NULL
) {
* Catch the case where it's just a single char (or an ascii char)
* that we are looking for
if (strlen(dsp
->xterm_string
) == 1) {
if ((int)dsp
->xterm_string
[0] == val
) {
/* print instn counts on legion console */
printf("(T-%d) (%d sec) ->", output_tag
,
((dsp
->stop_time
) - (dsp
->start_time
)));
ds_dump_instruction_counts(dsp
);
/* print time tag on guest console */
sprintf(timebuf
, "->(T-%d)", output_tag
++);
if (dsp
->exit_on_string
== true)
fatal("exit_string enabled exit\n");
if (val
== (dsp
->xterm_string
[dsp
->xterm_string_pos
]))
dsp
->xterm_string_pos
+= 1;
if (val
== dsp
->xterm_string
[0])
dsp
->xterm_string_pos
= 1;
dsp
->xterm_string_pos
= 0;
if (dsp
->xterm_string
[dsp
->xterm_string_pos
] == '\0') {
printf("\nTime from sim start to '%s' = %d seconds\n",\
dsp
->xterm_string
, (dsp
->stop_time
) - (dsp
->start_time
));
ds_dump_instruction_counts(dsp
);
if (dsp
->exit_on_string
== true)
fatal("exit_string enabled exit\n");
IMPL_WARNING(("dumbserial: Interrupt enable not yet supported"));
IMPL_WARNING(("dumbserial: FIFO control not yet supported"));
IMPL_WARNING(("dumbserial: Line control not yet supported"));
dsp
->dlab
= ((val
& DS_LCR_DLAB
) != 0);
IMPL_WARNING(("dumbserial: Modem control not yet supported"));
/* FIXME - more to do here */
/* TX always empty for the moment */
pthread_mutex_lock(&dsp
->tty_lock
);
dsp
->line_status
= (val
& 0xff) | DS_LSTAT_TX_EMPTY
| DS_LSTAT_TX_HOLD
;
pthread_mutex_unlock(&dsp
->tty_lock
);
IMPL_WARNING(("dumbserial: Modem status not yet supported"));
IMPL_WARNING(("dumbserial: Divisor (low) not yet supported"));
IMPL_WARNING(("dumbserial: Divisor (high) not yet supported"));
EXEC_WARNING(("dumbserial: illegal register accessed - offset 0x%x", offset
));
fatal("ds_cpu_access: Internal error unexpected op=0x%x\n", op
);
* Create term ... during initialisation, create the thread to run the
void create_term(ds_state_t
* dsp
)
dsp
->tty_attached
= false;
/* dsp->tilde_state = TE_Normal; */
dsp
->tilde_state
= TE_SawCR
; /* shouldn't have to CR to use ~ as first input char */
pthread_mutex_init(&dsp
->tty_lock
, NULL
);
pthread_cond_init(&dsp
->tty_cv
, NULL
);
* OK first we create the management thread for this console's input
* - then wait for it to tell us that it is happily up and running
* before we return to the simulator to continue initialisation.
pthread_mutex_lock(&dsp
->tty_lock
);
create_thread(ds_input_thr
, (void*)dsp
, &(dsp
->pthread_id
) );
/* should probably timeout here incase child doesn't start */
while (!dsp
->tty_attached
) pthread_cond_wait(&dsp
->tty_cv
, &dsp
->tty_lock
);
pthread_mutex_unlock(&dsp
->tty_lock
);
pthread_mutex_lock(&dsp
->tty_lock
);
extern void tcparams(int fd
);
ptest(POLLIN
); ptest(POLLRDNORM
); ptest(POLLRDBAND
); ptest(POLLOUT
); ptest(POLLWRNORM
); ptest(POLLWRBAND
); ptest(POLLERR
); ptest(POLLHUP
); ptest(POLLNVAL
);
sprintf(temp
, "test connect %d\n\r", count
);
write(dsp
->tty_skt
, temp
, strlen(temp
));
pthread_mutex_unlock(&dsp
->tty_lock
);
* Thread to manage external connections to this serial port.
* By default it creates an xterm with a telnet connection to
* the appropriate i/o port.
void * ds_input_thr(void * ptr
)
char myhostname
[MAXHOSTNAME
];
struct sockaddr_in ds_server
, from
;
* Create our socket to listen to
ds_sv_skt
= socket(AF_INET
, SOCK_STREAM
, 0);
if (ds_sv_skt
< 0) fatal("opening stream socket");
/* enable the reuse of this socket if this process dies */
if (setsockopt(ds_sv_skt
, SOL_SOCKET
, SO_REUSEADDR
, (uint8_t*)&on
, sizeof(on
))<0)
fatal("turning on REUSEADDR");
ds_server
.sin_family
= AF_INET
;
ds_server
.sin_addr
.s_addr
= INADDR_ANY
;
ds_server
.sin_port
= htons(0); /* bind to an OS selected local port */
if (bind(ds_sv_skt
, (struct sockaddr
*)&ds_server
, sizeof(ds_server
)) < 0) {
fatal("Port is already in use\n");
fatal("binding tcp stream socket");
length
= sizeof(ds_server
);
if (getsockname(ds_sv_skt
, (struct sockaddr
*) &ds_server
, &length
)==-1)
fatal("getting socket name");
* Create the client xterm etc
gethostname(myhostname
, MAXHOSTNAME
);
sprintf((char*)buf
, dsp
->term_strp
, myhostname
, ntohs(ds_server
.sin_port
));
* OK main loop for processing connections and data traffic
if (!dsp
->tty_attached
) {
PRINTF(("\ndumbserial: Waiting for connection to : %s:%d\n",
myhostname
, ntohs(ds_server
.sin_port
)));
dsp
->tty_skt
= accept(ds_sv_skt
, (struct sockaddr
*)&from
, (int*)&length
);
hp
= gethostbyaddr((char *)&from
.sin_addr
, 4, AF_INET
);
if (hp
== (struct hostent
*)0) {
froms
= inet_ntoa(from
.sin_addr
);
fprintf(stderr
,"cant resolve hostname for %s\n", froms
);
PRINTF(("dumbserial: Accepted connection on %s:%d from %s:%d\n",
myhostname
, ntohs(ds_server
.sin_port
),
froms
, ntohs(from
.sin_port
)));
pthread_mutex_lock(&dsp
->tty_lock
);
dsp
->tty_attached
= true;
pthread_mutex_unlock(&dsp
->tty_lock
);
pthread_cond_signal(&dsp
->tty_cv
);
#define POLL_TIMEOUT -1 /* wait forever ? FIXME ? */
fds
.events
= POLLIN
|POLLPRI
;
#if HOST_OS_SOLARIS9 /* { */
fds
.events
|= POLLRDNORM
|POLLRDBAND
;
res
= poll(&fds
, 1, POLL_TIMEOUT
);
#if HOST_OS_SOLARIS9 /* { */
if (fds
.revents
& POLLIN
) {
res
= read(dsp
->tty_skt
, buf
, sizeof (buf
));
/* a read of 0 bytes is an EOF */
pthread_mutex_lock(&dsp
->tty_lock
);
dsp
->tty_attached
= false;
pthread_mutex_unlock(&dsp
->tty_lock
);
pthread_cond_signal(&dsp
->tty_cv
);
SANITY(dsp
->tty_skt
= -1;);
DBGX( dump_buf("input bytes:", buf
, res
); );
ds_insert_bytes(dsp
, buf
, res
);
/* emits string and newline */
ds_output(ds_state_t
*dsp
, char *str
)
(void) write(dsp
->tty_skt
, str
, strlen(str
));
/* drop char if tty is not attached */
/* FIXME: This compile option
* enables the console to force an external chip reset of any procs
* attached to the same domain.
* This is somewhat of a hack, and should be handled else where ...
* ... which is why it is not a device option in the config file
#if CONSOLE_RESET /* { */
ds_domain_reset(ds_state_t
* dsp
)
* FIXME: this is a hack ...
* walk the procs in my domain, and reset them all
dp
= dsp
->config_devp
->domainp
;
for (i
=0; i
<dp
->procs
.count
; i
++) {
cp
= LIST_ENTRY(dp
->procs
, i
);
cp
->proc_typep
->ext_signal(cp
, ES_XIR
, NULL
);
ds_insert_bytes(ds_state_t
*dsp
, uint8_t *bufp
, int len
)
pthread_mutex_lock(&dsp
->tty_lock
);
* process all characters in buffer, don't check for overrun
for (i
= 0; i
< len
; i
++) {
DBGX( printf("State %d : Char typed 0x%x [%c]\n", (int)dsp
->tilde_state
, c
, c
>=' ' && c
<127 ? c
: '.'); fflush(stdout
); );
switch (dsp
->tilde_state
) {
case TE_Normal
: /* waiting for CR */
dsp
->tilde_state
= TE_SawCR
;
case TE_SawCR
: /* waiting for tilde */
dsp
->tilde_state
= TE_SawTilde
;
if (c
!= '\n') dsp
->tilde_state
= TE_Normal
;
case TE_SawTilde
: /* tilde command */
dsp
->tilde_state
= TE_SawCR
;
/* Flush logging output. */
case '~': /* emit single tilde */
dsp
->tilde_state
= TE_Normal
;
dsp
->line_status
|= DS_LSTAT_BREAK
;
ds_output(dsp
, "BREAK\n");
/* allow another ~ cmd without CR */
ds_output(dsp
, "dumb_serial tilde escapes:\n");
ds_output(dsp
, "\t# BREAK\n");
ds_output(dsp
, "\t~ generate tilde\n");
ds_output(dsp
, "\tz exit simulator\n");
#if ERROR_TRAP_GEN /* { */
ds_output(dsp
, "\ter reload (append) error config file into running legion\n");
ds_output(dsp
, "\t error config filename specified in " \
"legion config \n\t file used at startup using " \
"error_reload_file_name directive\n");
ds_output(dsp
, "\ted dump current error_event and error_asi lists\n");
ds_output(dsp
, "\tes dump supported (built-in) error types\n");
#if CONSOLE_RESET /* { */
ds_output(dsp
, "\tx external reset for CPUs in same domain\n");
ds_output(dsp
, "\tj generate JBus interrupt\n");
ds_output(dsp
, "\ts generate SSI interrupt\n");
ds_output(dsp
, "\tp generate PCIe interrupt\n");
ds_output(dsp
, "\tr generate FPGA RX intr\n");
ds_output(dsp
, "\tt generate FPGA TX intr\n");
ds_output(dsp
, "\ti dump I-TLB contents for CPUs in same domain\n");
ds_output(dsp
, "\td dump D-TLB contents for CPUs in same domain\n");
ds_output(dsp
, "\tb toggle the debug output enable bits\n");
ds_output(dsp
, "\tl dump data for the debug_hook"\
" function you are using\n\t\t(coverage, tracing, "\
"debug_log, lockstep)\n");
ds_output(dsp
, "\tn dump the current and delta instruction count for each CPU\n");
ds_output(dsp
, "\t? this message\n");
/* allow another ~ cmd without CR */
fatal("dumbserial requested exit");
#if CONSOLE_RESET /* { */
case 'x': /* Hack to enable extern chip reset easily */
ds_output(dsp
, "Resetting cpu(s) in domain\n");
goto skip
; /* swallow 'x' character after sending reset */
ds_output(dsp
, "JBUS intr\n");
mondo
.adr
.type
= 0x14; /* INT */
mondo
.data0
= 0xaabbccdd;
mondo
.data1
= 0x11223344;
dsp
->config_devp
->domainp
->procs
, 0);
cpp
->proc_typep
->ext_signal(cpp
, ES_JBUS
, &mondo
);
pcie_mondo_t
*mondo
= (pcie_mondo_t
*)Xcalloc(1, pcie_mondo_t
);
ds_output(dsp
, "PCIE mondo intr\n");
mondo
->data
[0] = 0xaabbccdd;
mondo
->data
[1] = 0x11223344;
dsp
->config_devp
->domainp
->procs
, 0);
cpp
->proc_typep
->ext_signal(cpp
, ES_PCIE
, mondo
);
ds_output(dsp
, "SSI intr\n");
dsp
->config_devp
->domainp
->procs
, 0);
cpp
->proc_typep
->ext_signal(cpp
, ES_SSI
, NULL
);
extern void (*fpga_intr
)(int a
);
ds_output(dsp
, "fpga RX intr\n");
dsp
->config_devp
->domainp
->procs
,
cpp
->proc_typep
->ext_signal(cpp
,
"no fpga intr attached\n");
extern void (*fpga_intr
)(int a
);
ds_output(dsp
, "fpga TX intr\n");
dsp
->config_devp
->domainp
->procs
,
cpp
->proc_typep
->ext_signal(cpp
,
"no fpga intr attached\n");
#if INTERNAL_BUILD /* { */
printf("Initiating Simulator state save\n");
#endif /* INTERNAL_BUILD } */
simcore_update_debug_bits(debug_bits
^ debug_bits_xor
);
ds_dump_instruction_counts(dsp
);
#if ERROR_TRAP_GEN /* { */
dsp
->tilde_state
= TE_SawTildeE
;
#endif /* ERROR_TRAP_GEN } */
default: /* eat current char */
* FIXME could emit ~ and current char
ds_output(dsp
, "~? for tilde help\n");
#if ERROR_TRAP_GEN /* { */
case TE_SawTildeE
: /* tilde e command */
dsp
->tilde_state
= TE_SawCR
;
ds_dump_error_active(dsp
);
ds_dump_error_supported(dsp
);
#endif /* } ERROR_TRAP_GEN */
if (dsp
->in
.count
< dsp
->in
.size
) {
dsp
->in
.bufp
[dsp
->in
.tail
] = bufp
[i
];
if (dsp
->in
.tail
>= dsp
->in
.size
)
dsp
->line_status
|= DS_LSTAT_DATA_READY
;
if (!(dsp
->line_status
& DS_LSTAT_OVERRUN
))
warning("dumbserial: buffer overrun");
dsp
->line_status
|= DS_LSTAT_OVERRUN
;
pthread_mutex_unlock(&dsp
->tty_lock
);
void dump_buf(char * strp
, uint8_t * bufp
, int len
)
printf("%s read %d bytes: ", strp
, len
);
for(i
=0; i
<len
; i
++) printf("0x%02x [%c]",bufp
[i
],bufp
[i
]>=32 && bufp
[i
]<127 ? bufp
[i
] : '.');
static void ds_save_state(ds_state_t
* dsp
)
domain_t
* dp
= dsp
->config_devp
->domainp
;
for (i
=0; i
<dp
->procs
.count
; i
++) {
cp
= LIST_ENTRY(dp
->procs
, i
);
cp
->proc_typep
->ext_signal(cp
, ES_LEGION_SAVE_STATE
, NULL
);
static void ds_dump_instruction_counts(ds_state_t
* dsp
)
domain_t
* dp
= dsp
->config_devp
->domainp
;
for (i
=0; i
<dp
->procs
.count
; i
++) {
cp
= LIST_ENTRY(dp
->procs
, i
);
cp
->proc_typep
->instn_cnt_dump(cp
);
static void ds_debug_hook_dump(ds_state_t
* dsp
)
domain_t
*dp
= dsp
->config_devp
->domainp
;
void (*debug_hook_dumpp
)(void);
for (i
=0; i
<dp
->procs
.count
; i
++) {
cp
= LIST_ENTRY(dp
->procs
, i
);
(void(*)(void))cp
->proc_typep
->debug_hook_dumpp
;
if (debug_hook_dumpp
!= NULL
) {
printf("\nNo debug_hook dump configured.\n");
/* Nasty hack for TLB debugging - to go away FIXME */
/* First find all the cpus, then dump their TLBs ... */
static void ds_dump_tlb(ds_state_t
* dsp
, bool_t is_dtlb
)
domain_t
* dp
= dsp
->config_devp
->domainp
;
* FIXME: this is a hack ...
* walk the procs in my domain, and dump the tlb contents
for (i
=0; i
<dp
->procs
.count
; i
++) {
cp
= LIST_ENTRY(dp
->procs
, i
);
cp
->proc_typep
->tlb_dump(cp
, is_dtlb
);
#if ERROR_TRAP_GEN /* { */
static void ds_load_error_file(ds_state_t
* dsp
)
domain_t
* dp
= dsp
->config_devp
->domainp
;
cp
= LIST_ENTRY(dp
->procs
, 0);
cp
->proc_typep
->load_error_file(cp
);
static void ds_dump_error_active(ds_state_t
* dsp
)
domain_t
* dp
= dsp
->config_devp
->domainp
;
cp
= LIST_ENTRY(dp
->procs
, 0);
cp
->proc_typep
->dump_error_active(cp
);
static void ds_dump_error_supported(ds_state_t
* dsp
)
domain_t
* dp
= dsp
->config_devp
->domainp
;
cp
= LIST_ENTRY(dp
->procs
, 0);
cp
->proc_typep
->dump_error_supported(cp
);
#endif /* } ERROR_TRAP_GEN */