Line 107... |
Line 107... |
registers. All that varies is the library function called and the error
|
registers. All that varies is the library function called and the error
|
message if anything goes wrong. So we common things up here.
|
message if anything goes wrong. So we common things up here.
|
|
|
@param[in] type 'D' if this is a data register, 'I' if an instruction
|
@param[in] type 'D' if this is a data register, 'I' if an instruction
|
register.
|
register.
|
@param[in] next_jreg Offset into argv of the next JTAG register hex
|
@param[in] next_jreg Offset into argv of the next JTAG register length
|
string.
|
field.
|
@param[in] argc argc from the main program (for checking next_jref).
|
@param[in] argc argc from the main program (for checking next_jref).
|
@param[in] argv argv from the main program.
|
@param[in] argv argv from the main program.
|
|
|
@return 1 (TRUE) on success, 0 (FALSE) on failure. */
|
@return 1 (TRUE) on success, 0 (FALSE) on failure. */
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
Line 122... |
Line 122... |
int argc,
|
int argc,
|
char *argv[])
|
char *argv[])
|
{
|
{
|
const char *long_name = ('D' == type) ? "data" : "instruction";
|
const char *long_name = ('D' == type) ? "data" : "instruction";
|
|
|
/* Do we have the arg? */
|
/* Do we have the arg (length and value)? */
|
if (next_jreg > argc)
|
if ((next_jreg + 1) > argc)
|
{
|
{
|
printf ("ERROR: no %s register found.\n", long_name);
|
printf ("ERROR: no %s register found.\n", long_name);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
|
/* Get the length field */
|
|
int bit_len = strtol (argv[next_jreg++], NULL, 0);
|
|
|
|
if (0 == bit_len)
|
|
{
|
|
printf ("ERROR: invalid register length\n");
|
|
return 0;
|
|
}
|
|
|
/* Is the reg an exact number of bytes? */
|
/* Is the reg an exact number of bytes? */
|
char *hex_str = argv[next_jreg];
|
char *hex_str = argv[next_jreg];
|
int num_chars = strlen (hex_str);
|
int num_chars = strlen (hex_str);
|
|
int num_bytes = (bit_len + 7) / 8;
|
|
|
if (0 != (num_chars % 2))
|
if (num_chars > (2 * num_bytes))
|
{
|
{
|
printf ("ERROR: %s register not exact number of bytes.\n", long_name);
|
printf ("Warning: Too many digits for register: truncated.\n");
|
return 0;
|
|
}
|
}
|
|
|
/* Allocate space */
|
/* Allocate and clear space */
|
int num_bytes = num_chars / 2;
|
|
unsigned char *jreg = malloc (num_bytes);
|
unsigned char *jreg = malloc (num_bytes);
|
|
|
if (NULL == jreg)
|
if (NULL == jreg)
|
{
|
{
|
printf ("ERROR: malloc for %s register failed.\n", long_name);
|
printf ("ERROR: malloc for %s register failed.\n", long_name);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
|
memset (jreg, 0, num_bytes);
|
|
|
/* Initialize the register. The hex presentation is MS byte of the string on
|
/* Initialize the register. The hex presentation is MS byte of the string on
|
the left (i.e. at offset 0), but the internal representation is LS byte
|
the left (i.e. at offset 0), but the internal representation is LS byte
|
at the lowest address. */
|
at the lowest address. */
|
int i;
|
int i;
|
|
|
for (i = 0; i < num_bytes; i++)
|
for (i = num_chars - 1; i >= 0; i--)
|
{
|
|
int byte_off = num_bytes - i - 1;
|
|
int ch_off = i * 2;
|
|
int j;
|
|
|
|
/* Each nybble in turn */
|
|
for (j = 0; j < 2; j++)
|
|
{
|
{
|
char c = hex_str[ch_off + j];
|
int dig_num = num_chars - 1 - i; /* Which digit */
|
int c_val = hexch2val (c);
|
int dig_val = hexch2val (hex_str[i]);
|
|
|
if (c_val < 0)
|
if (dig_val < 0)
|
{
|
{
|
printf ("ERROR: %c not valid hex digit.\n", c);
|
printf ("ERROR: %c not valid hex digit.\n", hex_str[i]);
|
free (jreg);
|
free (jreg);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
jreg[byte_off] <<= 4;
|
/* MS digits are the odd numbered ones */
|
jreg[byte_off] |= c_val;
|
jreg[dig_num / 2] |= (0 == (dig_num % 2)) ? dig_val : dig_val << 4;
|
}
|
|
}
|
}
|
|
|
/* Note what we are doing */
|
/* Note what we are doing */
|
dump_jreg (" shifting in", jreg, num_bytes);
|
dump_jreg (" shifting in", jreg, num_bytes);
|
|
|
double t;
|
double t;
|
|
|
if ('D' == type)
|
if ('D' == type)
|
{
|
{
|
t = or1ksim_jtag_shift_dr (jreg);
|
t = or1ksim_jtag_shift_dr (jreg, bit_len);
|
}
|
}
|
else
|
else
|
{
|
{
|
t = or1ksim_jtag_shift_ir (jreg);
|
t = or1ksim_jtag_shift_ir (jreg, bit_len);
|
}
|
}
|
|
|
dump_jreg (" shifted out", jreg, num_bytes);
|
dump_jreg (" shifted out", jreg, num_bytes);
|
printf (" time taken %.12fs\n", t);
|
printf (" time taken %.12fs\n", t);
|
|
|
Line 207... |
Line 209... |
/*!Main program
|
/*!Main program
|
|
|
Build an or1ksim program using the library which loads a program and config
|
Build an or1ksim program using the library which loads a program and config
|
from the command line which will drive JTAG.
|
from the command line which will drive JTAG.
|
|
|
lib-jtag <config-file> <image> <jtype> [<reg>] [<jtype> [<reg>]] ...
|
lib-jtag <config-file> <image> <jtype> [<bitlen> <reg>]
|
|
[<jtype> [<bitlen> <reg>]] ...
|
|
|
- config-file An Or1ksim configuration file.
|
- config-file An Or1ksim configuration file.
|
- image A OpenRISC binary image to load into Or1ksim
|
- image A OpenRISC binary image to load into Or1ksim
|
- jtype One of 'R' (JTAG reset), 'I' (JTAG instruction register) or
|
- jtype One of 'R' (JTAG reset), 'I' (JTAG instruction register) or
|
'D' (JTAG data register).
|
'D' (JTAG data register).
|
|
- bitlen If jtype is 'D' or 'I', the number of bits in the JTAG
|
|
register.
|
- reg If jtype is 'D' or 'I', a JTAG register specified in
|
- reg If jtype is 'D' or 'I', a JTAG register specified in
|
hex. Must be an even number of digits (i.e. exact number of
|
hex. Specified LS digit on the right, and leading zeros may
|
bytes), and use leading zeros if null bytes are needed at
|
be omitted.
|
the MS end.
|
|
|
|
The target program is run in bursts of 1ms execution, and the type of
|
The target program is run in bursts of 1ms execution, and the type of
|
return (OK, hit breakpoint) noted. Between each burst of execution, the
|
return (OK, hit breakpoint) noted. Between each burst of execution, the
|
next register is submitted to the corresponding Or1ksim JTAG interface
|
next register is submitted to the corresponding Or1ksim JTAG interface
|
function, and the resulting register (for 'I' and 'D') noted.
|
function, and the resulting register (for 'I' and 'D') noted.
|
Line 235... |
Line 239... |
char *argv[])
|
char *argv[])
|
{
|
{
|
/* Check we have minimum number of args. */
|
/* Check we have minimum number of args. */
|
if (argc < 4)
|
if (argc < 4)
|
{
|
{
|
printf ("usage: lib-jtag <config-file> <image> <jtype> <reg> [<jtype> "
|
printf ("usage: lib-jtag <config-file> <image> <jtype> [<bitlen> <reg>] "
|
"<reg>] ...\n");
|
"[<jtype> [<bitlen> <reg>]] ...\n");
|
return 1;
|
return 1;
|
}
|
}
|
|
|
/* Initialize the program. Put the initialization message afterwards, or it
|
/* Initialize the program. Put the initialization message afterwards, or it
|
will get swamped by the Or1ksim header. */
|
will get swamped by the Or1ksim header. */
|
Line 284... |
Line 288... |
break;
|
break;
|
|
|
case 'I':
|
case 'I':
|
printf ("Shifting instruction register.\n");
|
printf ("Shifting instruction register.\n");
|
|
|
if (!process_jreg ('I', next_jreg++, argc, argv))
|
if (process_jreg ('I', next_jreg, argc, argv))
|
|
{
|
|
next_jreg += 2;
|
|
}
|
|
else
|
{
|
{
|
return 1; /* Something went wrong */
|
return 1; /* Something went wrong */
|
}
|
}
|
|
|
break;
|
break;
|
|
|
case 'D':
|
case 'D':
|
printf ("Shifting data register.\n");
|
printf ("Shifting data register.\n");
|
|
|
if (!process_jreg ('D', next_jreg++, argc, argv))
|
if (process_jreg ('D', next_jreg, argc, argv))
|
|
{
|
|
next_jreg += 2;
|
|
}
|
|
else
|
{
|
{
|
return 1; /* Something went wrong */
|
return 1; /* Something went wrong */
|
}
|
}
|
|
|
break;
|
break;
|