Line 47... |
Line 47... |
/* JTAG or1k target ops. */
|
/* JTAG or1k target ops. */
|
extern void jtag_init PARAMS ((char * args));
|
extern void jtag_init PARAMS ((char * args));
|
extern ULONGEST jtag_read_reg PARAMS ((unsigned int regno));
|
extern ULONGEST jtag_read_reg PARAMS ((unsigned int regno));
|
extern void jtag_write_reg PARAMS ((unsigned int regno, ULONGEST data));
|
extern void jtag_write_reg PARAMS ((unsigned int regno, ULONGEST data));
|
extern void jtag_done PARAMS ((void));
|
extern void jtag_done PARAMS ((void));
|
|
extern int jtag_read_block PARAMS ((unsigned int regno, void* block, int nRegisters));
|
|
extern int jtag_write_block PARAMS ((unsigned int regno, void* block, int nRegisters));
|
extern void jtag_set_chain PARAMS ((int chain));
|
extern void jtag_set_chain PARAMS ((int chain));
|
struct target_ops or1k_jtag_ops;
|
struct target_ops or1k_jtag_ops;
|
static struct or1k_target_ops or1k_target_jtag =
|
static struct or1k_target_ops or1k_target_jtag =
|
{
|
{
|
"jtag",
|
"jtag",
|
jtag_init,
|
jtag_init,
|
jtag_done,
|
jtag_done,
|
jtag_read_reg,
|
jtag_read_reg,
|
jtag_write_reg,
|
jtag_write_reg,
|
|
jtag_read_block,
|
|
jtag_write_block,
|
jtag_set_chain,
|
jtag_set_chain,
|
NULL,
|
NULL,
|
&or1k_jtag_ops,
|
&or1k_jtag_ops,
|
OPS_MAGIC
|
OPS_MAGIC
|
};
|
};
|
Line 73... |
Line 77... |
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
|
NULL,
|
|
NULL,
|
&or1k_sim_ops,
|
&or1k_sim_ops,
|
OPS_MAGIC
|
OPS_MAGIC
|
};
|
};
|
|
|
/* dummy or1k target ops. */
|
/* dummy or1k target ops. */
|
Line 88... |
Line 94... |
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
NULL,
|
|
NULL,
|
|
NULL,
|
&or1k_dummy_ops,
|
&or1k_dummy_ops,
|
OPS_MAGIC
|
OPS_MAGIC
|
};
|
};
|
|
|
const char *str_err[] =
|
const char *str_err[] =
|
Line 311... |
Line 319... |
|
|
static void
|
static void
|
or1k_unstall ()
|
or1k_unstall ()
|
{
|
{
|
unsigned int val;
|
unsigned int val;
|
|
|
or1k_set_chain (SC_REGISTER);
|
or1k_set_chain (SC_REGISTER);
|
val = or1k_read_reg (JTAG_RISCOP);
|
val = or1k_read_reg (JTAG_RISCOP);
|
or1k_write_reg (JTAG_RISCOP, val & ~1);
|
or1k_write_reg (JTAG_RISCOP, val & ~1);
|
}
|
}
|
|
|
Line 708... |
Line 717... |
{
|
{
|
/* Search all active breakpoints for a match. */
|
/* Search all active breakpoints for a match. */
|
CORE_ADDR pc = read_pc ();
|
CORE_ADDR pc = read_pc ();
|
int breakpoint = 0;
|
int breakpoint = 0;
|
int i;
|
int i;
|
|
unsigned long value; /* CZ */
|
|
|
for (i = 0; i < or1k_implementation.num_used_matchpoints; i++)
|
for (i = 0; i < or1k_implementation.num_used_matchpoints; i++)
|
if (dvr[i] == pc && dcr[i].dp && dcr[i].cc == CC_EQUAL
|
if (dvr[i] == pc && dcr[i].dp && dcr[i].cc == CC_EQUAL
|
&& !dcr[i].sc && dcr[i].ct == CT_FETCH)
|
&& !dcr[i].sc && dcr[i].ct == CT_FETCH)
|
{
|
{
|
breakpoint = 1;
|
breakpoint = 1;
|
break;
|
break;
|
}
|
}
|
hit_watchpoint = !breakpoint;
|
hit_watchpoint = !breakpoint;
|
|
|
|
/* Cause the trap/breakpoint exception to be ignored. This is
|
|
the behavior of the simulator when the PC value is changed
|
|
by a write command. All pending exceptions are cleared and
|
|
the simulator continues at the PC value specified. */
|
|
or1k_write_spr_reg(PC_SPRNUM,value);
|
}
|
}
|
else
|
else
|
hit_watchpoint = 0;
|
hit_watchpoint = 0;
|
|
|
/* If the stop PC is in the _exit function, assume
|
/* If the stop PC is in the _exit function, assume
|
Line 896... |
Line 913... |
register CORE_ADDR addr = memaddr & ~3;
|
register CORE_ADDR addr = memaddr & ~3;
|
/* Round ending address up; get number of longwords that makes. */
|
/* Round ending address up; get number of longwords that makes. */
|
register int count = (((memaddr + len) - addr) + 3) / 4;
|
register int count = (((memaddr + len) - addr) + 3) / 4;
|
/* Allocate buffer of that many longwords. */
|
/* Allocate buffer of that many longwords. */
|
register char *buffer = alloca (count * 4);
|
register char *buffer = alloca (count * 4);
|
|
|
int status;
|
int status;
|
|
|
|
int block_xfer_size = 256; /* CZ 21/06/01 ... number of 32 bit words */
|
|
int nBlocks = (count + block_xfer_size -1)/block_xfer_size;
|
|
int terminate = 0; /* Terminate the printing of '*'s... */
|
|
|
if (memaddr >= MEM_SPACE)
|
if (memaddr >= MEM_SPACE)
|
error("Invalid address");
|
error("Invalid address");
|
|
|
/* (CZ 21/06/01 -- because upper layers which know nothing about
|
/* (CZ 21/06/01 -- because upper layers which know nothing about
|
Or1k or JTAG call this function directly, it is always necessary
|
Or1k or JTAG call this function directly, it is always necessary
|
to set the chain to point to the Debug Unit. Otherwise, it may
|
to set the chain to point to the Debug Unit. Otherwise, it may
|
be pointint to the Development Interface chain, in which case
|
be pointing to the Development Interface chain, in which case
|
we're going to get bupkiss... */
|
we're going to get bupkiss... */
|
|
|
or1k_set_chain (SC_RISC_DEBUG);
|
or1k_set_chain (SC_RISC_DEBUG);
|
|
|
if (write)
|
if (write)
|
Line 930... |
Line 950... |
}
|
}
|
|
|
/* Copy data to be written over corresponding part of buffer */
|
/* Copy data to be written over corresponding part of buffer */
|
memcpy ((char *) buffer + (memaddr & 3), myaddr, len);
|
memcpy ((char *) buffer + (memaddr & 3), myaddr, len);
|
|
|
/* Write the entire buffer. */
|
/* CZ: rewrote the block transfer routines to make the code
|
for (i = 0; i < count; i++, addr += 4)
|
a little more efficient for implementations that can handle
|
|
variable sized scan chains. Might be useful in the future.
|
|
Certainly makes downloads to the simulator more efficient. */
|
|
for(i=0;i<nBlocks;i++,count-=block_xfer_size,addr += block_xfer_size*4)
|
|
{
|
|
int j;
|
|
int n = count < block_xfer_size ? count : block_xfer_size;
|
|
unsigned long *__buf;
|
|
|
|
if(!(__buf = (unsigned long*)malloc(n*sizeof(unsigned long))))
|
{
|
{
|
status = or1k_store_word (addr,
|
errno = ERR_MEM;
|
(unsigned long)extract_unsigned_integer (&buffer[i * 4], 4));
|
return 0;
|
/* Report each kilobyte (we download 32-bit words at a time) */
|
}
|
if (i % 256 == 255)
|
|
|
for(j=0;j<n;j++)
|
|
__buf[j] = (unsigned long)extract_unsigned_integer(&buffer[(i * block_xfer_size +j)*4], 4);
|
|
status = or1k_store_block(addr,__buf,n);
|
|
free(__buf);
|
|
if(n == block_xfer_size)
|
{
|
{
|
printf_unfiltered ("*");
|
printf_unfiltered ("*");
|
gdb_flush (gdb_stdout);
|
gdb_flush (gdb_stdout);
|
}
|
}
|
if (status)
|
if (status)
|
Line 948... |
Line 982... |
errno = status;
|
errno = status;
|
return 0;
|
return 0;
|
}
|
}
|
/* FIXME: Do we want a QUIT here? */
|
/* FIXME: Do we want a QUIT here? */
|
}
|
}
|
if (count >= 256)
|
if (terminate)
|
printf_unfiltered ("\n");
|
printf_unfiltered ("\n");
|
}
|
}
|
else
|
else
|
{
|
{
|
/* Read all the longwords */
|
for(i=0;i<nBlocks;i++,count-=block_xfer_size,addr += block_xfer_size*4)
|
for (i = 0; i < count; i++, addr += 4)
|
|
{
|
{
|
store_unsigned_integer (&buffer[i * 4], 4, or1k_fetch_word (addr));
|
int j;
|
QUIT;
|
int n = count < block_xfer_size ? count : block_xfer_size;
|
}
|
unsigned long *__buf;
|
|
|
|
__buf = (unsigned long*)malloc(n*sizeof(unsigned long));
|
|
status = or1k_load_block(addr,__buf,n);
|
|
if (!status)
|
|
for(j=0;j<n;j++)
|
|
store_unsigned_integer (&buffer[(i * block_xfer_size +j)*4], 4, __buf[j]);
|
|
else
|
|
errno = status;
|
|
free(__buf);
|
|
|
|
if(status)
|
|
return 0;
|
|
}
|
/* Copy appropriate bytes out of the buffer. */
|
/* Copy appropriate bytes out of the buffer. */
|
memcpy (myaddr, buffer + (memaddr & 3), len);
|
memcpy (myaddr, buffer + (memaddr & 3), len);
|
}
|
}
|
return len;
|
return len;
|
}
|
}
|
|
|
|
int or1k_load_block(CORE_ADDR addr,void* buffer,int nRegisters)
|
|
{
|
|
int i=0;
|
|
unsigned int regno = (addr >> 2) + MEM_SPACE;
|
|
|
|
if (current_or1k_target != NULL && current_or1k_target->to_read_block != NULL)
|
|
return current_or1k_target->to_read_block (regno,buffer,nRegisters);
|
|
else
|
|
for(i=0;i<nRegisters;i++)
|
|
((unsigned long*)buffer)[i] = 0x1234;
|
|
return 0;
|
|
}
|
|
|
|
int or1k_store_block(CORE_ADDR addr,void* buffer,int nRegisters)
|
|
{
|
|
unsigned int regno = (addr >> 2) + MEM_SPACE;
|
|
|
|
if (current_or1k_target != NULL && current_or1k_target->to_write_block != NULL)
|
|
return current_or1k_target->to_write_block (regno,buffer,nRegisters);
|
|
return 0;
|
|
}
|
|
|
/* Flushes pipeline. May not be needed by all implementations, but
|
/* Flushes pipeline. May not be needed by all implementations, but
|
it doen't hurt to do it. This function should be called every time
|
it doen't hurt to do it. This function should be called every time
|
or1k stops.
|
or1k stops.
|
When or1k stops it still has instructions in pipeline.
|
When or1k stops it still has instructions in pipeline.
|
We do this by inserting nop instructions.
|
We do this by inserting nop instructions.
|
Line 1254... |
Line 1321... |
}
|
}
|
|
|
int
|
int
|
or1k_stopped_by_watchpoint (void)
|
or1k_stopped_by_watchpoint (void)
|
{
|
{
|
return hit_watchpoint;
|
/* For now, no watchpoints */
|
|
return 0;
|
|
|
|
/* return hit_watchpoint; */
|
}
|
}
|
|
|
/* Insert a breakpoint. */
|
/* Insert a breakpoint. */
|
|
|
int
|
int
|