/* lib-jtag-full.c. Comprehensive test of Or1ksim library JTAG interface.
|
/* lib-jtag-full.c. Comprehensive test of Or1ksim library JTAG interface.
|
|
|
Copyright (C) 1999-2006 OpenCores
|
Copyright (C) 1999-2006 OpenCores
|
Copyright (C) 2010 Embecosm Limited
|
Copyright (C) 2010 Embecosm Limited
|
|
|
Contributors various OpenCores participants
|
Contributors various OpenCores participants
|
Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
|
Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
|
|
|
This file is part of OpenRISC 1000 Architectural Simulator.
|
This file is part of OpenRISC 1000 Architectural Simulator.
|
|
|
This program is free software; you can redistribute it and/or modify it
|
This program is free software; you can redistribute it and/or modify it
|
under the terms of the GNU General Public License as published by the Free
|
under the terms of the GNU General Public License as published by the Free
|
Software Foundation; either version 3 of the License, or (at your option)
|
Software Foundation; either version 3 of the License, or (at your option)
|
any later version.
|
any later version.
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
more details.
|
more details.
|
|
|
You should have received a copy of the GNU General Public License along
|
You should have received a copy of the GNU General Public License along
|
with this program. If not, see <http://www.gnu.org/licenses/>. */
|
with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
This code is commented throughout for use with Doxygen.
|
This code is commented throughout for use with Doxygen.
|
--------------------------------------------------------------------------*/
|
--------------------------------------------------------------------------*/
|
|
|
#include <errno.h>
|
#include <errno.h>
|
#include <stddef.h>
|
#include <stddef.h>
|
#include <stdlib.h>
|
#include <stdlib.h>
|
#include <stdio.h>
|
#include <stdio.h>
|
#include <string.h>
|
#include <string.h>
|
|
|
#include "or1ksim.h"
|
#include "or1ksim.h"
|
|
|
|
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
/*!Compute a IEEE 802.3 CRC-32.
|
/*!Compute a IEEE 802.3 CRC-32.
|
|
|
Print an error message if we get a duff argument, but we really should
|
Print an error message if we get a duff argument, but we really should
|
not.
|
not.
|
|
|
@param[in] value The value to shift into the CRC
|
@param[in] value The value to shift into the CRC
|
@param[in] num_bits The number of bits in the value.
|
@param[in] num_bits The number of bits in the value.
|
@param[in] crc_in The existing CRC
|
@param[in] crc_in The existing CRC
|
|
|
@return The computed CRC. */
|
@return The computed CRC. */
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
static unsigned long int
|
static unsigned long int
|
crc32 (unsigned long long int value,
|
crc32 (unsigned long long int value,
|
int num_bits,
|
int num_bits,
|
unsigned long int crc_in)
|
unsigned long int crc_in)
|
{
|
{
|
if ((1 > num_bits) || (num_bits > 64))
|
if ((1 > num_bits) || (num_bits > 64))
|
{
|
{
|
printf ("ERROR: Max 64 bits of CRC can be computed. Ignored\n");
|
printf ("ERROR: Max 64 bits of CRC can be computed. Ignored\n");
|
return crc_in;
|
return crc_in;
|
}
|
}
|
|
|
static const unsigned long int CRC32_POLY = 0x04c11db7;
|
static const unsigned long int CRC32_POLY = 0x04c11db7;
|
int i;
|
int i;
|
|
|
/* Compute the CRC, MS bit first */
|
/* Compute the CRC, MS bit first */
|
for (i = num_bits - 1; i >= 0; i--)
|
for (i = num_bits - 1; i >= 0; i--)
|
{
|
{
|
unsigned long int d;
|
unsigned long int d;
|
unsigned long int t;
|
unsigned long int t;
|
|
|
d = (1 == ((value >> i) & 1)) ? 0xfffffff : 0x0000000;
|
d = (1 == ((value >> i) & 1)) ? 0xfffffff : 0x0000000;
|
t = (1 == ((crc_in >> 31) & 1)) ? 0xfffffff : 0x0000000;
|
t = (1 == ((crc_in >> 31) & 1)) ? 0xfffffff : 0x0000000;
|
|
|
crc_in <<= 1;
|
crc_in <<= 1;
|
crc_in ^= (d ^ t) & CRC32_POLY;
|
crc_in ^= (d ^ t) & CRC32_POLY;
|
}
|
}
|
|
|
return crc_in;
|
return crc_in;
|
|
|
} /* crc32 () */
|
} /* crc32 () */
|
|
|
|
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
/*!Reverse a value's bits
|
/*!Reverse a value's bits
|
|
|
@param[in] val The value to reverse (up to 64 bits).
|
@param[in] val The value to reverse (up to 64 bits).
|
@param[in] len The number of bits to reverse.
|
@param[in] len The number of bits to reverse.
|
|
|
@return The reversed value */
|
@return The reversed value */
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
static unsigned long long
|
static unsigned long long
|
reverse_bits (unsigned long long val,
|
reverse_bits (unsigned long long val,
|
int len)
|
int len)
|
{
|
{
|
if ((1 > len) || (len > 64))
|
if ((1 > len) || (len > 64))
|
{
|
{
|
printf ("ERROR: Cannot reverse %d bits. Returning zero\n", len);
|
printf ("ERROR: Cannot reverse %d bits. Returning zero\n", len);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Reverse the string */
|
/* Reverse the string */
|
val = (((val & 0xaaaaaaaaaaaaaaaaULL) >> 1) |
|
val = (((val & 0xaaaaaaaaaaaaaaaaULL) >> 1) |
|
((val & 0x5555555555555555ULL) << 1));
|
((val & 0x5555555555555555ULL) << 1));
|
val = (((val & 0xccccccccccccccccULL) >> 2) |
|
val = (((val & 0xccccccccccccccccULL) >> 2) |
|
((val & 0x3333333333333333ULL) << 2));
|
((val & 0x3333333333333333ULL) << 2));
|
val = (((val & 0xf0f0f0f0f0f0f0f0ULL) >> 4) |
|
val = (((val & 0xf0f0f0f0f0f0f0f0ULL) >> 4) |
|
((val & 0x0f0f0f0f0f0f0f0fULL) << 4));
|
((val & 0x0f0f0f0f0f0f0f0fULL) << 4));
|
val = (((val & 0xff00ff00ff00ff00ULL) >> 8) |
|
val = (((val & 0xff00ff00ff00ff00ULL) >> 8) |
|
((val & 0x00ff00ff00ff00ffULL) << 8));
|
((val & 0x00ff00ff00ff00ffULL) << 8));
|
val = (((val & 0xffff0000ffff0000ULL) >> 16) |
|
val = (((val & 0xffff0000ffff0000ULL) >> 16) |
|
((val & 0x0000ffff0000ffffULL) << 16));
|
((val & 0x0000ffff0000ffffULL) << 16));
|
|
|
return ((val >> 32) | (val << 32)) >> (64 - len);
|
return ((val >> 32) | (val << 32)) >> (64 - len);
|
|
|
} /* reverse_bits () */
|
} /* reverse_bits () */
|
|
|
|
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
/*!Dump a JTAG register
|
/*!Dump a JTAG register
|
|
|
Prefix with the supplied string and add a newline afterwards.
|
Prefix with the supplied string and add a newline afterwards.
|
|
|
@param[in] prefix Prefix string to print out
|
@param[in] prefix Prefix string to print out
|
@param[in] jreg The JTAG register
|
@param[in] jreg The JTAG register
|
@param[in] num_bytes The number of bytes in the register */
|
@param[in] num_bytes The number of bytes in the register */
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
static void
|
static void
|
dump_jreg (const char *prefix,
|
dump_jreg (const char *prefix,
|
unsigned char *jreg,
|
unsigned char *jreg,
|
int num_bytes)
|
int num_bytes)
|
{
|
{
|
int i;
|
int i;
|
|
|
printf ("%s: 0x", prefix);
|
printf ("%s: 0x", prefix);
|
|
|
/* Dump each byte in turn */
|
/* Dump each byte in turn */
|
for (i = num_bytes - 1; i >=0; i--)
|
for (i = num_bytes - 1; i >=0; i--)
|
{
|
{
|
printf ("%02x", jreg[i]);
|
printf ("%02x", jreg[i]);
|
}
|
}
|
|
|
printf ("\n");
|
printf ("\n");
|
|
|
} /* dump_jreg () */
|
} /* dump_jreg () */
|
|
|
|
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
/*!Process a JTAG instruction register
|
/*!Process a JTAG instruction register
|
|
|
Usage:
|
Usage:
|
|
|
INSTRUCTION <value>
|
INSTRUCTION <value>
|
|
|
The single argument is a single hex digit, specifying the instruction
|
The single argument is a single hex digit, specifying the instruction
|
value.
|
value.
|
|
|
Like all the JTAG instructions, it must be reversed, so it is shifted MS
|
Like all the JTAG instructions, it must be reversed, so it is shifted MS
|
bit first.
|
bit first.
|
|
|
@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 hex
|
string.
|
string.
|
@param[in] argc argc from the main program (for checking next_jreg).
|
@param[in] argc argc from the main program (for checking next_jreg).
|
@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. */
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
static int
|
static int
|
process_instruction (int next_jreg,
|
process_instruction (int next_jreg,
|
int argc,
|
int argc,
|
char *argv[])
|
char *argv[])
|
{
|
{
|
printf ("Shifting instruction.\n");
|
printf ("Shifting instruction.\n");
|
|
|
/* Do we have the arg? */
|
/* Do we have the arg? */
|
if (next_jreg >= argc)
|
if (next_jreg >= argc)
|
{
|
{
|
printf ("ERROR: no instruction register value found.\n");
|
printf ("ERROR: no instruction register value found.\n");
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Is the argument in range? */
|
/* Is the argument in range? */
|
unsigned long int ival = strtoul (argv[next_jreg], NULL, 16);
|
unsigned long int ival = strtoul (argv[next_jreg], NULL, 16);
|
|
|
if (ival > 0xf)
|
if (ival > 0xf)
|
{
|
{
|
printf ("ERROR: instruction value 0x%lx too large\n", ival);
|
printf ("ERROR: instruction value 0x%lx too large\n", ival);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Reverse the bits of the value */
|
/* Reverse the bits of the value */
|
ival = reverse_bits (ival, 4);
|
ival = reverse_bits (ival, 4);
|
|
|
/* Allocate space and populate the register */
|
/* Allocate space and populate the register */
|
unsigned char *jreg = malloc (1);
|
unsigned char *jreg = malloc (1);
|
|
|
if (NULL == jreg)
|
if (NULL == jreg)
|
{
|
{
|
printf ("ERROR: malloc for instruction register failed.\n");
|
printf ("ERROR: malloc for instruction register failed.\n");
|
return 0;
|
return 0;
|
}
|
}
|
|
|
jreg[0] = ival;
|
jreg[0] = ival;
|
|
|
dump_jreg (" shifting in", jreg, 1);
|
dump_jreg (" shifting in", jreg, 1);
|
|
|
double t = or1ksim_jtag_shift_ir (jreg, 4);
|
double t = or1ksim_jtag_shift_ir (jreg, 4);
|
|
|
dump_jreg (" shifted out", jreg, 1);
|
dump_jreg (" shifted out", jreg, 1);
|
printf (" time taken: %.12fs\n", t);
|
printf (" time taken: %.12fs\n", t);
|
|
|
free (jreg);
|
free (jreg);
|
return 1; /* Completed successfully */
|
return 1; /* Completed successfully */
|
|
|
} /* process_instruction () */
|
} /* process_instruction () */
|
|
|
|
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
/*!Process a JTAG SELECT_MODULE debug data register
|
/*!Process a JTAG SELECT_MODULE debug data register
|
|
|
Usage:
|
Usage:
|
|
|
SELECT_MODULE <value>
|
SELECT_MODULE <value>
|
|
|
The one argument is a single hex digit, specifying the module value.
|
The one argument is a single hex digit, specifying the module value.
|
|
|
Like all the JTAG fields, it must be reversed, so it is shifted MS
|
Like all the JTAG fields, it must be reversed, so it is shifted MS
|
bit first. It also requires a 32-bit CRC.
|
bit first. It also requires a 32-bit CRC.
|
|
|
On return we get a status register and CRC.
|
On return we get a status register and CRC.
|
|
|
@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 hex
|
string.
|
string.
|
@param[in] argc argc from the main program (for checking next_jreg).
|
@param[in] argc argc from the main program (for checking next_jreg).
|
@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. */
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
static int
|
static int
|
process_select_module (int next_jreg,
|
process_select_module (int next_jreg,
|
int argc,
|
int argc,
|
char *argv[])
|
char *argv[])
|
{
|
{
|
printf ("Selecting module.\n");
|
printf ("Selecting module.\n");
|
|
|
/* Do we have the arg? */
|
/* Do we have the arg? */
|
if (next_jreg >= argc)
|
if (next_jreg >= argc)
|
{
|
{
|
printf ("ERROR: no module specified.\n");
|
printf ("ERROR: no module specified.\n");
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Is the argument in range? */
|
/* Is the argument in range? */
|
unsigned long int module_id = strtoul (argv[next_jreg], NULL, 16);
|
unsigned long int module_id = strtoul (argv[next_jreg], NULL, 16);
|
|
|
if (module_id > 0xf)
|
if (module_id > 0xf)
|
{
|
{
|
printf ("ERROR: module value 0x%lx too large\n", module_id);
|
printf ("ERROR: module value 0x%lx too large\n", module_id);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Compute the CRC */
|
/* Compute the CRC */
|
unsigned long int crc_in;
|
unsigned long int crc_in;
|
|
|
crc_in = crc32 (1, 1, 0xffffffff);
|
crc_in = crc32 (1, 1, 0xffffffff);
|
crc_in = crc32 (module_id, 4, crc_in);
|
crc_in = crc32 (module_id, 4, crc_in);
|
|
|
/* Reverse the fields */
|
/* Reverse the fields */
|
module_id = reverse_bits (module_id, 4);
|
module_id = reverse_bits (module_id, 4);
|
crc_in = reverse_bits (crc_in, 32);
|
crc_in = reverse_bits (crc_in, 32);
|
|
|
/* Allocate space and initialize the register
|
/* Allocate space and initialize the register
|
- 1 indicator bit
|
- 1 indicator bit
|
- 4 module bits in
|
- 4 module bits in
|
- 32 bit CRC in
|
- 32 bit CRC in
|
- 4 bits status out
|
- 4 bits status out
|
- 32 bits CRC out
|
- 32 bits CRC out
|
|
|
Total 73 bits = 10 bytes */
|
Total 73 bits = 10 bytes */
|
int num_bytes = 10;
|
int num_bytes = 10;
|
unsigned char *jreg = malloc (num_bytes);
|
unsigned char *jreg = malloc (num_bytes);
|
|
|
if (NULL == jreg)
|
if (NULL == jreg)
|
{
|
{
|
printf ("ERROR: malloc for SELECT_MODULE register failed.\n");
|
printf ("ERROR: malloc for SELECT_MODULE register failed.\n");
|
return 0;
|
return 0;
|
}
|
}
|
|
|
memset (jreg, 0, num_bytes);
|
memset (jreg, 0, num_bytes);
|
|
|
jreg[0] = 0x01;
|
jreg[0] = 0x01;
|
jreg[0] |= module_id << 1;
|
jreg[0] |= module_id << 1;
|
jreg[0] |= crc_in << 5;
|
jreg[0] |= crc_in << 5;
|
jreg[1] = crc_in >> 3;
|
jreg[1] = crc_in >> 3;
|
jreg[2] = crc_in >> 11;
|
jreg[2] = crc_in >> 11;
|
jreg[3] = crc_in >> 19;
|
jreg[3] = crc_in >> 19;
|
jreg[4] = crc_in >> 27;
|
jreg[4] = crc_in >> 27;
|
|
|
/* Note what we are shifting in and shift it. */
|
/* Note what we are shifting in and shift it. */
|
dump_jreg (" shifting in", jreg, num_bytes);
|
dump_jreg (" shifting in", jreg, num_bytes);
|
double t = or1ksim_jtag_shift_dr (jreg, 32 + 4 + 32 + 4 + 1);
|
double t = or1ksim_jtag_shift_dr (jreg, 32 + 4 + 32 + 4 + 1);
|
|
|
/* Diagnose what we are shifting out. */
|
/* Diagnose what we are shifting out. */
|
dump_jreg (" shifted out", jreg, num_bytes);
|
dump_jreg (" shifted out", jreg, num_bytes);
|
|
|
/* Break out fields */
|
/* Break out fields */
|
unsigned char status;
|
unsigned char status;
|
unsigned long int crc_out;
|
unsigned long int crc_out;
|
|
|
status = ((jreg[4] >> 5) | (jreg[5] << 3)) & 0xf ;
|
status = ((jreg[4] >> 5) | (jreg[5] << 3)) & 0xf ;
|
|
|
crc_out = ((unsigned long int) jreg[5] >> 1) |
|
crc_out = ((unsigned long int) jreg[5] >> 1) |
|
((unsigned long int) jreg[6] << 7) |
|
((unsigned long int) jreg[6] << 7) |
|
((unsigned long int) jreg[7] << 15) |
|
((unsigned long int) jreg[7] << 15) |
|
((unsigned long int) jreg[8] << 23) |
|
((unsigned long int) jreg[8] << 23) |
|
((unsigned long int) jreg[9] << 31);
|
((unsigned long int) jreg[9] << 31);
|
|
|
/* Reverse the fields */
|
/* Reverse the fields */
|
status = reverse_bits (status, 4);
|
status = reverse_bits (status, 4);
|
crc_out = reverse_bits (crc_out, 32);
|
crc_out = reverse_bits (crc_out, 32);
|
|
|
/* Compute our own CRC */
|
/* Compute our own CRC */
|
unsigned long int crc_computed = crc32 (status, 4, 0xffffffff);
|
unsigned long int crc_computed = crc32 (status, 4, 0xffffffff);
|
|
|
/* Log the results */
|
/* Log the results */
|
printf (" status: 0x%01x\n", status);
|
printf (" status: 0x%01x\n", status);
|
|
|
if (crc_out != crc_computed)
|
if (crc_out != crc_computed)
|
{
|
{
|
printf (" CRC mismatch\n");
|
printf (" CRC mismatch\n");
|
printf (" CRC out: 0x%08lx\n", crc_out);
|
printf (" CRC out: 0x%08lx\n", crc_out);
|
printf (" CRC computed: 0x%08lx\n", crc_computed);
|
printf (" CRC computed: 0x%08lx\n", crc_computed);
|
}
|
}
|
|
|
printf (" time taken: %.12fs\n", t);
|
printf (" time taken: %.12fs\n", t);
|
|
|
free (jreg);
|
free (jreg);
|
return 1; /* Completed successfully */
|
return 1; /* Completed successfully */
|
|
|
} /* process_select_module () */
|
} /* process_select_module () */
|
|
|
|
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
/*!Process a JTAG WRITE_COMMAND debug data register
|
/*!Process a JTAG WRITE_COMMAND debug data register
|
|
|
Usage:
|
Usage:
|
|
|
WRITE_COMMAND <access_type> <address> <length>
|
WRITE_COMMAND <access_type> <address> <length>
|
|
|
The argumens are all hex values:
|
The argumens are all hex values:
|
- access_type Access type - 4 bits
|
- access_type Access type - 4 bits
|
- address 32-bit address
|
- address 32-bit address
|
- length number of bytes to transer up to 2^16.
|
- length number of bytes to transer up to 2^16.
|
|
|
Like all the JTAG fields these must be reversed, so they are shifted MS bit
|
Like all the JTAG fields these must be reversed, so they are shifted MS bit
|
first. They also require a 32-bit CRC.
|
first. They also require a 32-bit CRC.
|
|
|
On return we get a status register and CRC.
|
On return we get a status register and CRC.
|
|
|
@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 hex
|
string.
|
string.
|
@param[in] argc argc from the main program (for checking next_jreg).
|
@param[in] argc argc from the main program (for checking next_jreg).
|
@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. */
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
static int
|
static int
|
process_write_command (int next_jreg,
|
process_write_command (int next_jreg,
|
int argc,
|
int argc,
|
char *argv[])
|
char *argv[])
|
{
|
{
|
printf ("Processing WRITE_COMMAND.\n");
|
printf ("Processing WRITE_COMMAND.\n");
|
|
|
/* Do we have the args */
|
/* Do we have the args */
|
if (next_jreg + 3 > argc)
|
if (next_jreg + 3 > argc)
|
{
|
{
|
printf ("WRITE_COMMAND usage: WRITE_COMMAND <access_type> <address> "
|
printf ("WRITE_COMMAND usage: WRITE_COMMAND <access_type> <address> "
|
"<length>\n");
|
"<length>\n");
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Are the arguments in range? Remember the length we actually put in has 1
|
/* Are the arguments in range? Remember the length we actually put in has 1
|
subtracted. */
|
subtracted. */
|
unsigned long int cmd = 2; /* WRITE_COMMAND */
|
unsigned long int cmd = 2; /* WRITE_COMMAND */
|
|
|
unsigned long int access_type = strtoul (argv[next_jreg ], NULL, 16);
|
unsigned long int access_type = strtoul (argv[next_jreg ], NULL, 16);
|
unsigned long int addr = strtoul (argv[next_jreg + 1], NULL, 16);
|
unsigned long int addr = strtoul (argv[next_jreg + 1], NULL, 16);
|
unsigned long int len = strtoul (argv[next_jreg + 2], NULL, 16) - 1;
|
unsigned long int len = strtoul (argv[next_jreg + 2], NULL, 16) - 1;
|
|
|
if (access_type > 0xf)
|
if (access_type > 0xf)
|
{
|
{
|
printf ("ERROR: WRITE_COMMAND access type 0x%lx too large\n",
|
printf ("ERROR: WRITE_COMMAND access type 0x%lx too large\n",
|
access_type);
|
access_type);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
if (addr > 0xffffffff)
|
if (addr > 0xffffffff)
|
{
|
{
|
printf ("ERROR: WRITE_COMMAND address 0x%lx too large\n", addr);
|
printf ("ERROR: WRITE_COMMAND address 0x%lx too large\n", addr);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
if ((len + 1) < 0x1)
|
if ((len + 1) < 0x1)
|
{
|
{
|
printf ("ERROR: WRITE_COMMAND length 0x%lx too small\n", len + 1);
|
printf ("ERROR: WRITE_COMMAND length 0x%lx too small\n", len + 1);
|
return 0;
|
return 0;
|
}
|
}
|
else if ((len + 1) > 0x10000)
|
else if ((len + 1) > 0x10000)
|
{
|
{
|
printf ("ERROR: WRITE_COMMAND length 0x%lx too large\n", len + 1);
|
printf ("ERROR: WRITE_COMMAND length 0x%lx too large\n", len + 1);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Compute the CRC */
|
/* Compute the CRC */
|
unsigned long int crc_in;
|
unsigned long int crc_in;
|
|
|
crc_in = crc32 (0, 1, 0xffffffff);
|
crc_in = crc32 (0, 1, 0xffffffff);
|
crc_in = crc32 (cmd, 4, crc_in);
|
crc_in = crc32 (cmd, 4, crc_in);
|
crc_in = crc32 (access_type, 4, crc_in);
|
crc_in = crc32 (access_type, 4, crc_in);
|
crc_in = crc32 (addr, 32, crc_in);
|
crc_in = crc32 (addr, 32, crc_in);
|
crc_in = crc32 (len, 16, crc_in);
|
crc_in = crc32 (len, 16, crc_in);
|
|
|
/* Reverse the fields */
|
/* Reverse the fields */
|
cmd = reverse_bits (cmd, 4);
|
cmd = reverse_bits (cmd, 4);
|
access_type = reverse_bits (access_type, 4);
|
access_type = reverse_bits (access_type, 4);
|
addr = reverse_bits (addr, 32);
|
addr = reverse_bits (addr, 32);
|
len = reverse_bits (len, 16);
|
len = reverse_bits (len, 16);
|
crc_in = reverse_bits (crc_in, 32);
|
crc_in = reverse_bits (crc_in, 32);
|
|
|
/* Allocate space and initialize the register
|
/* Allocate space and initialize the register
|
- 1 indicator bit
|
- 1 indicator bit
|
- 4 bits command in
|
- 4 bits command in
|
- 4 bits access type in
|
- 4 bits access type in
|
- 32 bits address in
|
- 32 bits address in
|
- 16 bits length in
|
- 16 bits length in
|
- 32 bits CRC in
|
- 32 bits CRC in
|
- 4 bits status out
|
- 4 bits status out
|
- 32 bits CRC out
|
- 32 bits CRC out
|
|
|
Total 125 bits = 16 bytes */
|
Total 125 bits = 16 bytes */
|
int num_bytes = 16;
|
int num_bytes = 16;
|
unsigned char *jreg = malloc (num_bytes);
|
unsigned char *jreg = malloc (num_bytes);
|
|
|
if (NULL == jreg)
|
if (NULL == jreg)
|
{
|
{
|
printf ("ERROR: malloc for WRITE_COMMAND register failed.\n");
|
printf ("ERROR: malloc for WRITE_COMMAND register failed.\n");
|
return 0;
|
return 0;
|
}
|
}
|
|
|
memset (jreg, 0, num_bytes);
|
memset (jreg, 0, num_bytes);
|
|
|
jreg[ 0] = 0x0;
|
jreg[ 0] = 0x0;
|
|
|
jreg[ 0] |= cmd << 1;
|
jreg[ 0] |= cmd << 1;
|
|
|
jreg[ 0] |= access_type << 5;
|
jreg[ 0] |= access_type << 5;
|
jreg[ 1] = access_type >> 3;
|
jreg[ 1] = access_type >> 3;
|
|
|
jreg[ 1] |= addr << 1;
|
jreg[ 1] |= addr << 1;
|
jreg[ 2] = addr >> 7;
|
jreg[ 2] = addr >> 7;
|
jreg[ 3] = addr >> 15;
|
jreg[ 3] = addr >> 15;
|
jreg[ 4] = addr >> 23;
|
jreg[ 4] = addr >> 23;
|
jreg[ 5] = addr >> 31;
|
jreg[ 5] = addr >> 31;
|
|
|
jreg[ 5] |= len << 1;
|
jreg[ 5] |= len << 1;
|
jreg[ 6] = len >> 7;
|
jreg[ 6] = len >> 7;
|
jreg[ 7] = len >> 15;
|
jreg[ 7] = len >> 15;
|
|
|
jreg[ 7] |= crc_in << 1;
|
jreg[ 7] |= crc_in << 1;
|
jreg[ 8] = crc_in >> 7;
|
jreg[ 8] = crc_in >> 7;
|
jreg[ 9] = crc_in >> 15;
|
jreg[ 9] = crc_in >> 15;
|
jreg[10] = crc_in >> 23;
|
jreg[10] = crc_in >> 23;
|
jreg[11] = crc_in >> 31;
|
jreg[11] = crc_in >> 31;
|
|
|
/* Note what we are shifting in and shift it. */
|
/* Note what we are shifting in and shift it. */
|
dump_jreg (" shifting in", jreg, num_bytes);
|
dump_jreg (" shifting in", jreg, num_bytes);
|
double t = or1ksim_jtag_shift_dr (jreg, 32 + 4 + 32 + 16 + 32 + 4 + 4 + 1);
|
double t = or1ksim_jtag_shift_dr (jreg, 32 + 4 + 32 + 16 + 32 + 4 + 4 + 1);
|
|
|
/* Diagnose what we are shifting out. */
|
/* Diagnose what we are shifting out. */
|
dump_jreg (" shifted out", jreg, num_bytes);
|
dump_jreg (" shifted out", jreg, num_bytes);
|
|
|
/* Break out fields */
|
/* Break out fields */
|
unsigned char status;
|
unsigned char status;
|
unsigned long int crc_out;
|
unsigned long int crc_out;
|
|
|
status = (jreg[11] >> 1) & 0xf ;
|
status = (jreg[11] >> 1) & 0xf ;
|
|
|
crc_out = ((unsigned long int) jreg[11] >> 5) |
|
crc_out = ((unsigned long int) jreg[11] >> 5) |
|
((unsigned long int) jreg[12] << 3) |
|
((unsigned long int) jreg[12] << 3) |
|
((unsigned long int) jreg[13] << 11) |
|
((unsigned long int) jreg[13] << 11) |
|
((unsigned long int) jreg[14] << 19) |
|
((unsigned long int) jreg[14] << 19) |
|
((unsigned long int) jreg[15] << 27);
|
((unsigned long int) jreg[15] << 27);
|
|
|
/* Reverse the fields */
|
/* Reverse the fields */
|
status = reverse_bits (status, 4);
|
status = reverse_bits (status, 4);
|
crc_out = reverse_bits (crc_out, 32);
|
crc_out = reverse_bits (crc_out, 32);
|
|
|
/* Compute our own CRC */
|
/* Compute our own CRC */
|
unsigned long int crc_computed = crc32 (status, 4, 0xffffffff);
|
unsigned long int crc_computed = crc32 (status, 4, 0xffffffff);
|
|
|
/* Log the results */
|
/* Log the results */
|
printf (" status: 0x%01x\n", status);
|
printf (" status: 0x%01x\n", status);
|
|
|
if (crc_out != crc_computed)
|
if (crc_out != crc_computed)
|
{
|
{
|
printf (" CRC mismatch\n");
|
printf (" CRC mismatch\n");
|
printf (" CRC out: 0x%08lx\n", crc_out);
|
printf (" CRC out: 0x%08lx\n", crc_out);
|
printf (" CRC computed: 0x%08lx\n", crc_computed);
|
printf (" CRC computed: 0x%08lx\n", crc_computed);
|
}
|
}
|
|
|
printf (" time taken: %.12fs\n", t);
|
printf (" time taken: %.12fs\n", t);
|
|
|
free (jreg);
|
free (jreg);
|
return 1; /* Completed successfully */
|
return 1; /* Completed successfully */
|
|
|
} /* process_write_command () */
|
} /* process_write_command () */
|
|
|
|
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
/*!Process a JTAG READ_COMMAND debug data register
|
/*!Process a JTAG READ_COMMAND debug data register
|
|
|
Usage:
|
Usage:
|
|
|
READ_COMMAND
|
READ_COMMAND
|
|
|
There are no arguments. It is used to read back the values used in a prior
|
There are no arguments. It is used to read back the values used in a prior
|
WRITE_COMMAND.
|
WRITE_COMMAND.
|
|
|
On return we get the access type, address, length, status register and CRC.
|
On return we get the access type, address, length, status register and CRC.
|
|
|
@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 hex
|
string.
|
string.
|
@param[in] argc argc from the main program (for checking next_jreg).
|
@param[in] argc argc from the main program (for checking next_jreg).
|
@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. */
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
static int
|
static int
|
process_read_command (int next_jreg,
|
process_read_command (int next_jreg,
|
int argc,
|
int argc,
|
char *argv[])
|
char *argv[])
|
{
|
{
|
printf ("Processing READ_COMMAND.\n");
|
printf ("Processing READ_COMMAND.\n");
|
|
|
/* The only value on input is the READ_COMMAND command */
|
/* The only value on input is the READ_COMMAND command */
|
unsigned long int cmd = 1; /* READ_COMMAND */
|
unsigned long int cmd = 1; /* READ_COMMAND */
|
|
|
/* Compute the CRC */
|
/* Compute the CRC */
|
unsigned long int crc_in;
|
unsigned long int crc_in;
|
|
|
crc_in = crc32 (0, 1, 0xffffffff);
|
crc_in = crc32 (0, 1, 0xffffffff);
|
crc_in = crc32 (cmd, 4, crc_in);
|
crc_in = crc32 (cmd, 4, crc_in);
|
|
|
/* Reverse the fields */
|
/* Reverse the fields */
|
cmd = reverse_bits (cmd, 4);
|
cmd = reverse_bits (cmd, 4);
|
crc_in = reverse_bits (crc_in, 32);
|
crc_in = reverse_bits (crc_in, 32);
|
|
|
/* Allocate space and initialize the register
|
/* Allocate space and initialize the register
|
- 1 indicator bit
|
- 1 indicator bit
|
- 4 bits command in
|
- 4 bits command in
|
- 32 bits CRC in
|
- 32 bits CRC in
|
- 4 bits access type out
|
- 4 bits access type out
|
- 32 bits address out
|
- 32 bits address out
|
- 16 bits length out
|
- 16 bits length out
|
- 4 bits status out
|
- 4 bits status out
|
- 32 bits CRC out
|
- 32 bits CRC out
|
|
|
Total 125 bits = 16 bytes */
|
Total 125 bits = 16 bytes */
|
int num_bytes = 16;
|
int num_bytes = 16;
|
unsigned char *jreg = malloc (num_bytes);
|
unsigned char *jreg = malloc (num_bytes);
|
|
|
if (NULL == jreg)
|
if (NULL == jreg)
|
{
|
{
|
printf ("ERROR: malloc for READ_COMMAND register failed.\n");
|
printf ("ERROR: malloc for READ_COMMAND register failed.\n");
|
return 0;
|
return 0;
|
}
|
}
|
|
|
memset (jreg, 0, num_bytes);
|
memset (jreg, 0, num_bytes);
|
|
|
jreg[ 0] = 0x0;
|
jreg[ 0] = 0x0;
|
|
|
jreg[0] |= cmd << 1;
|
jreg[0] |= cmd << 1;
|
|
|
jreg[0] |= crc_in << 5;
|
jreg[0] |= crc_in << 5;
|
jreg[1] = crc_in >> 3;
|
jreg[1] = crc_in >> 3;
|
jreg[2] = crc_in >> 11;
|
jreg[2] = crc_in >> 11;
|
jreg[3] = crc_in >> 19;
|
jreg[3] = crc_in >> 19;
|
jreg[4] = crc_in >> 27;
|
jreg[4] = crc_in >> 27;
|
|
|
/* Note what we are shifting in and shift it. */
|
/* Note what we are shifting in and shift it. */
|
dump_jreg (" shifting in", jreg, num_bytes);
|
dump_jreg (" shifting in", jreg, num_bytes);
|
double t = or1ksim_jtag_shift_dr (jreg, 32 + 4 + 16 + 32 + 4 + 32 + 4 + 1);
|
double t = or1ksim_jtag_shift_dr (jreg, 32 + 4 + 16 + 32 + 4 + 32 + 4 + 1);
|
|
|
/* Diagnose what we are shifting out. */
|
/* Diagnose what we are shifting out. */
|
dump_jreg (" shifted out", jreg, num_bytes);
|
dump_jreg (" shifted out", jreg, num_bytes);
|
|
|
/* Break out fields */
|
/* Break out fields */
|
unsigned char access_type;
|
unsigned char access_type;
|
unsigned long int addr;
|
unsigned long int addr;
|
unsigned long int len;
|
unsigned long int len;
|
unsigned char status;
|
unsigned char status;
|
unsigned long int crc_out;
|
unsigned long int crc_out;
|
|
|
access_type = ((jreg[4] >> 5) | (jreg[5] << 3)) & 0xf ;
|
access_type = ((jreg[4] >> 5) | (jreg[5] << 3)) & 0xf ;
|
addr = ((unsigned long int) jreg[ 5] >> 1) |
|
addr = ((unsigned long int) jreg[ 5] >> 1) |
|
((unsigned long int) jreg[ 6] << 7) |
|
((unsigned long int) jreg[ 6] << 7) |
|
((unsigned long int) jreg[ 7] << 15) |
|
((unsigned long int) jreg[ 7] << 15) |
|
((unsigned long int) jreg[ 8] << 23) |
|
((unsigned long int) jreg[ 8] << 23) |
|
((unsigned long int) jreg[ 9] << 31);
|
((unsigned long int) jreg[ 9] << 31);
|
|
|
len = ((unsigned long int) jreg[ 9] >> 1) |
|
len = ((unsigned long int) jreg[ 9] >> 1) |
|
((unsigned long int) jreg[10] << 7) |
|
((unsigned long int) jreg[10] << 7) |
|
((unsigned long int) (jreg[11] & 0x1) << 15);
|
((unsigned long int) (jreg[11] & 0x1) << 15);
|
|
|
status = (jreg[11] >> 1) & 0xf ;
|
status = (jreg[11] >> 1) & 0xf ;
|
|
|
crc_out = ((unsigned long int) jreg[11] >> 5) |
|
crc_out = ((unsigned long int) jreg[11] >> 5) |
|
((unsigned long int) jreg[12] << 3) |
|
((unsigned long int) jreg[12] << 3) |
|
((unsigned long int) jreg[13] << 11) |
|
((unsigned long int) jreg[13] << 11) |
|
((unsigned long int) jreg[14] << 19) |
|
((unsigned long int) jreg[14] << 19) |
|
((unsigned long int) jreg[15] << 27);
|
((unsigned long int) jreg[15] << 27);
|
|
|
/* Reverse the fields */
|
/* Reverse the fields */
|
|
|
access_type = reverse_bits (access_type, 4);
|
access_type = reverse_bits (access_type, 4);
|
addr = reverse_bits (addr, 32);
|
addr = reverse_bits (addr, 32);
|
len = reverse_bits (len, 16);
|
len = reverse_bits (len, 16);
|
status = reverse_bits (status, 4);
|
status = reverse_bits (status, 4);
|
crc_out = reverse_bits (crc_out, 32);
|
crc_out = reverse_bits (crc_out, 32);
|
|
|
/* Compute our own CRC */
|
/* Compute our own CRC */
|
unsigned long int crc_computed;
|
unsigned long int crc_computed;
|
|
|
crc_computed = crc32 (access_type, 4, 0xffffffff);
|
crc_computed = crc32 (access_type, 4, 0xffffffff);
|
crc_computed = crc32 (addr, 32, crc_computed);
|
crc_computed = crc32 (addr, 32, crc_computed);
|
crc_computed = crc32 (len, 16, crc_computed);
|
crc_computed = crc32 (len, 16, crc_computed);
|
crc_computed = crc32 (status, 4, crc_computed);
|
crc_computed = crc32 (status, 4, crc_computed);
|
|
|
/* Log the results. Remember the length is 1 greater than the value
|
/* Log the results. Remember the length is 1 greater than the value
|
returned. */
|
returned. */
|
printf (" access_type: 0x%x\n", access_type);
|
printf (" access_type: 0x%x\n", access_type);
|
printf (" address: 0x%lx\n", addr);
|
printf (" address: 0x%lx\n", addr);
|
printf (" length: 0x%lx\n", len + 1);
|
printf (" length: 0x%lx\n", len + 1);
|
printf (" status: 0x%x\n", status);
|
printf (" status: 0x%x\n", status);
|
|
|
if (crc_out != crc_computed)
|
if (crc_out != crc_computed)
|
{
|
{
|
printf (" CRC mismatch\n");
|
printf (" CRC mismatch\n");
|
printf (" CRC out: 0x%08lx\n", crc_out);
|
printf (" CRC out: 0x%08lx\n", crc_out);
|
printf (" CRC computed: 0x%08lx\n", crc_computed);
|
printf (" CRC computed: 0x%08lx\n", crc_computed);
|
}
|
}
|
|
|
printf (" time taken: %.12fs\n", t);
|
printf (" time taken: %.12fs\n", t);
|
|
|
free (jreg);
|
free (jreg);
|
return 1; /* Completed successfully */
|
return 1; /* Completed successfully */
|
|
|
} /* process_read_command () */
|
} /* process_read_command () */
|
|
|
|
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
/*!Process a JTAG GO_COMMAND_WRITE debug data register
|
/*!Process a JTAG GO_COMMAND_WRITE debug data register
|
|
|
Usage:
|
Usage:
|
|
|
GO_COMMAND_WRITE <data>
|
GO_COMMAND_WRITE <data>
|
|
|
The one argument is a string of bytes to be written, LS byte first.
|
The one argument is a string of bytes to be written, LS byte first.
|
|
|
Like all the JTAG fields, each data byte must be reversed, so it is shifted
|
Like all the JTAG fields, each data byte must be reversed, so it is shifted
|
MS bit first. It also requires a 32-bit CRC.
|
MS bit first. It also requires a 32-bit CRC.
|
|
|
On return we get a status register and CRC.
|
On return we get a status register and CRC.
|
|
|
@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 hex
|
string.
|
string.
|
@param[in] argc argc from the main program (for checking next_jreg).
|
@param[in] argc argc from the main program (for checking next_jreg).
|
@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. */
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
static int
|
static int
|
process_go_command_write (int next_jreg,
|
process_go_command_write (int next_jreg,
|
int argc,
|
int argc,
|
char *argv[])
|
char *argv[])
|
{
|
{
|
printf ("Processing GO_COMMAND_WRITE.\n");
|
printf ("Processing GO_COMMAND_WRITE.\n");
|
|
|
/* Do we have the arg */
|
/* Do we have the arg */
|
if (next_jreg >= argc)
|
if (next_jreg >= argc)
|
{
|
{
|
printf ("GO_COMMAND_WRITE usage: GO_COMMAND_WRITE <data>.\n");
|
printf ("GO_COMMAND_WRITE usage: GO_COMMAND_WRITE <data>.\n");
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Break out the fields, including the data string into a vector of bytes. */
|
/* Break out the fields, including the data string into a vector of bytes. */
|
unsigned long int cmd = 0; /* GO_COMMAND */
|
unsigned long int cmd = 0; /* GO_COMMAND */
|
|
|
char *data_str = argv[next_jreg];
|
char *data_str = argv[next_jreg];
|
int data_len = strlen (data_str);
|
int data_len = strlen (data_str);
|
int data_bytes = data_len / 2;
|
int data_bytes = data_len / 2;
|
unsigned char *data = malloc (data_bytes);
|
unsigned char *data = malloc (data_bytes);
|
|
|
if (NULL == data)
|
if (NULL == data)
|
{
|
{
|
printf ("ERROR: data malloc for GO_COMMAND_WRITE register failed.\n");
|
printf ("ERROR: data malloc for GO_COMMAND_WRITE register failed.\n");
|
return 0;
|
return 0;
|
}
|
}
|
|
|
if (1 == (data_len % 2))
|
if (1 == (data_len % 2))
|
{
|
{
|
printf ("Warning: GO_COMMAND_WRITE odd char ignored\n");
|
printf ("Warning: GO_COMMAND_WRITE odd char ignored\n");
|
}
|
}
|
|
|
int i;
|
int i;
|
|
|
for (i = 0; i < data_bytes; i++)
|
for (i = 0; i < data_bytes; i++)
|
{
|
{
|
int ch_off_ms = i * 2;
|
int ch_off_ms = i * 2;
|
int ch_off_ls = i * 2 + 1;
|
int ch_off_ls = i * 2 + 1;
|
|
|
/* Get each nybble in turn, remembering that we may not have a MS nybble
|
/* Get each nybble in turn, remembering that we may not have a MS nybble
|
if the data string has an odd number of chars. */
|
if the data string has an odd number of chars. */
|
data[i] = 0;
|
data[i] = 0;
|
|
|
int j;
|
int j;
|
|
|
for (j = ch_off_ms; j <= ch_off_ls; j++)
|
for (j = ch_off_ms; j <= ch_off_ls; j++)
|
{
|
{
|
char c = data_str[j];
|
char c = data_str[j];
|
int dig_val = (('0' <= c) && (c <= '9')) ? c - '0' :
|
int dig_val = (('0' <= c) && (c <= '9')) ? c - '0' :
|
(('a' <= c) && (c <= 'f')) ? c - 'a' + 10 :
|
(('a' <= c) && (c <= 'f')) ? c - 'a' + 10 :
|
(('A' <= c) && (c <= 'F')) ? c - 'A' + 10 : -1;
|
(('A' <= c) && (c <= 'F')) ? c - 'A' + 10 : -1;
|
|
|
if (dig_val < 0)
|
if (dig_val < 0)
|
{
|
{
|
printf ("ERROR: Non-hex digit in data: %c\n", c);
|
printf ("ERROR: Non-hex digit in data: %c\n", c);
|
free (data);
|
free (data);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
data[i] = (data[i] << 4) | dig_val;
|
data[i] = (data[i] << 4) | dig_val;
|
}
|
}
|
}
|
}
|
|
|
/* Are the arguments in range? Remember the length we actually put in has 1
|
/* Are the arguments in range? Remember the length we actually put in has 1
|
subtracted. */
|
subtracted. */
|
|
|
/* Compute the CRC */
|
/* Compute the CRC */
|
unsigned long int crc_in;
|
unsigned long int crc_in;
|
|
|
crc_in = crc32 (0, 1, 0xffffffff);
|
crc_in = crc32 (0, 1, 0xffffffff);
|
crc_in = crc32 (cmd, 4, crc_in);
|
crc_in = crc32 (cmd, 4, crc_in);
|
|
|
for (i = 0; i < data_bytes; i++)
|
for (i = 0; i < data_bytes; i++)
|
{
|
{
|
crc_in = crc32 (data[i], 8, crc_in);
|
crc_in = crc32 (data[i], 8, crc_in);
|
}
|
}
|
|
|
/* Reverse the fields */
|
/* Reverse the fields */
|
cmd = reverse_bits (cmd, 4);
|
cmd = reverse_bits (cmd, 4);
|
|
|
for (i = 0; i < data_bytes; i++)
|
for (i = 0; i < data_bytes; i++)
|
{
|
{
|
data[i] = reverse_bits (data[i], 8);
|
data[i] = reverse_bits (data[i], 8);
|
}
|
}
|
|
|
crc_in = reverse_bits (crc_in, 32);
|
crc_in = reverse_bits (crc_in, 32);
|
|
|
/* Allocate space and initialize the register
|
/* Allocate space and initialize the register
|
- 1 indicator bit
|
- 1 indicator bit
|
- 4 bits command in
|
- 4 bits command in
|
- data_bytes * 8 bits access type in
|
- data_bytes * 8 bits access type in
|
- 32 bits CRC in
|
- 32 bits CRC in
|
- 4 bits status out
|
- 4 bits status out
|
- 32 bits CRC out
|
- 32 bits CRC out
|
|
|
Total 73 + data_bytes * 8 bits = 10 + data_bytes bytes */
|
Total 73 + data_bytes * 8 bits = 10 + data_bytes bytes */
|
int num_bytes = 10 + data_bytes;
|
int num_bytes = 10 + data_bytes;
|
unsigned char *jreg = malloc (num_bytes);
|
unsigned char *jreg = malloc (num_bytes);
|
|
|
if (NULL == jreg)
|
if (NULL == jreg)
|
{
|
{
|
printf ("ERROR: jreg malloc for GO_COMMAND_WRITE register failed.\n");
|
printf ("ERROR: jreg malloc for GO_COMMAND_WRITE register failed.\n");
|
free (data);
|
free (data);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
memset (jreg, 0, num_bytes);
|
memset (jreg, 0, num_bytes);
|
|
|
jreg[ 0] = 0x0;
|
jreg[ 0] = 0x0;
|
jreg[ 0] |= cmd << 1;
|
jreg[ 0] |= cmd << 1;
|
|
|
for (i = 0; i < data_bytes; i++)
|
for (i = 0; i < data_bytes; i++)
|
{
|
{
|
jreg[i] |= data[i] << 5;
|
jreg[i] |= data[i] << 5;
|
jreg[i + 1] = data[i] >> 3;
|
jreg[i + 1] = data[i] >> 3;
|
}
|
}
|
|
|
jreg[data_bytes ] |= crc_in << 5;
|
jreg[data_bytes ] |= crc_in << 5;
|
jreg[data_bytes + 1] = crc_in >> 3;
|
jreg[data_bytes + 1] = crc_in >> 3;
|
jreg[data_bytes + 2] = crc_in >> 11;
|
jreg[data_bytes + 2] = crc_in >> 11;
|
jreg[data_bytes + 3] = crc_in >> 19;
|
jreg[data_bytes + 3] = crc_in >> 19;
|
jreg[data_bytes + 4] = crc_in >> 27;
|
jreg[data_bytes + 4] = crc_in >> 27;
|
|
|
/* Note what we are shifting in and shift it. */
|
/* Note what we are shifting in and shift it. */
|
dump_jreg (" shifting in", jreg, num_bytes);
|
dump_jreg (" shifting in", jreg, num_bytes);
|
double t = or1ksim_jtag_shift_dr (jreg,
|
double t = or1ksim_jtag_shift_dr (jreg,
|
32 + 4 + 32 + data_bytes * 8 + 4 + 1);
|
32 + 4 + 32 + data_bytes * 8 + 4 + 1);
|
|
|
/* Diagnose what we are shifting out. */
|
/* Diagnose what we are shifting out. */
|
dump_jreg (" shifted out", jreg, num_bytes);
|
dump_jreg (" shifted out", jreg, num_bytes);
|
|
|
/* Break out fields */
|
/* Break out fields */
|
unsigned char status;
|
unsigned char status;
|
unsigned long int crc_out;
|
unsigned long int crc_out;
|
|
|
status = ((jreg[data_bytes + 4] >> 5) | (jreg[data_bytes + 5] << 3)) & 0xf ;
|
status = ((jreg[data_bytes + 4] >> 5) | (jreg[data_bytes + 5] << 3)) & 0xf ;
|
|
|
crc_out = ((unsigned long int) jreg[data_bytes + 5] >> 1) |
|
crc_out = ((unsigned long int) jreg[data_bytes + 5] >> 1) |
|
((unsigned long int) jreg[data_bytes + 6] << 7) |
|
((unsigned long int) jreg[data_bytes + 6] << 7) |
|
((unsigned long int) jreg[data_bytes + 7] << 15) |
|
((unsigned long int) jreg[data_bytes + 7] << 15) |
|
((unsigned long int) jreg[data_bytes + 8] << 23) |
|
((unsigned long int) jreg[data_bytes + 8] << 23) |
|
((unsigned long int) jreg[data_bytes + 9] << 31);
|
((unsigned long int) jreg[data_bytes + 9] << 31);
|
|
|
/* Reverse the fields */
|
/* Reverse the fields */
|
status = reverse_bits (status, 4);
|
status = reverse_bits (status, 4);
|
crc_out = reverse_bits (crc_out, 32);
|
crc_out = reverse_bits (crc_out, 32);
|
|
|
/* Compute our own CRC */
|
/* Compute our own CRC */
|
unsigned long int crc_computed = crc32 (status, 4, 0xffffffff);
|
unsigned long int crc_computed = crc32 (status, 4, 0xffffffff);
|
|
|
/* Log the results */
|
/* Log the results */
|
printf (" status: 0x%01x\n", status);
|
printf (" status: 0x%01x\n", status);
|
|
|
if (crc_out != crc_computed)
|
if (crc_out != crc_computed)
|
{
|
{
|
printf (" CRC mismatch\n");
|
printf (" CRC mismatch\n");
|
printf (" CRC out: 0x%08lx\n", crc_out);
|
printf (" CRC out: 0x%08lx\n", crc_out);
|
printf (" CRC computed: 0x%08lx\n", crc_computed);
|
printf (" CRC computed: 0x%08lx\n", crc_computed);
|
}
|
}
|
|
|
printf (" time taken: %.12fs\n", t);
|
printf (" time taken: %.12fs\n", t);
|
|
|
free (data);
|
free (data);
|
free (jreg);
|
free (jreg);
|
return 1; /* Completed successfully */
|
return 1; /* Completed successfully */
|
|
|
} /* process_go_command_write () */
|
} /* process_go_command_write () */
|
|
|
|
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
/*!Process a JTAG GO_COMMAND_READ debug data register
|
/*!Process a JTAG GO_COMMAND_READ debug data register
|
|
|
Usage:
|
Usage:
|
|
|
GO_COMMAND_READ <length>
|
GO_COMMAND_READ <length>
|
|
|
The one argument is a length in hex, specifying the number of bytes to be
|
The one argument is a length in hex, specifying the number of bytes to be
|
read.
|
read.
|
|
|
On return we get a status register and CRC.
|
On return we get a status register and CRC.
|
|
|
Like all JTAG fields, the CRC shifted in, the data read back, the status
|
Like all JTAG fields, the CRC shifted in, the data read back, the status
|
and CRC shifted out, must be reversed, since they are shifted in MS bit
|
and CRC shifted out, must be reversed, since they are shifted in MS bit
|
first and out LS bit first.
|
first and out LS bit first.
|
|
|
@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 hex
|
string.
|
string.
|
@param[in] argc argc from the main program (for checking next_jreg).
|
@param[in] argc argc from the main program (for checking next_jreg).
|
@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. */
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
static int
|
static int
|
process_go_command_read (int next_jreg,
|
process_go_command_read (int next_jreg,
|
int argc,
|
int argc,
|
char *argv[])
|
char *argv[])
|
{
|
{
|
printf ("Processing GO_COMMAND_READ.\n");
|
printf ("Processing GO_COMMAND_READ.\n");
|
|
|
/* Do we have the args */
|
/* Do we have the args */
|
if (next_jreg >= argc)
|
if (next_jreg >= argc)
|
{
|
{
|
printf ("GO_COMMAND_READ usage: GO_COMMAND_READ <length>\n");
|
printf ("GO_COMMAND_READ usage: GO_COMMAND_READ <length>\n");
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Is the argument in range? Remember the length we actually put in has 1
|
/* Is the argument in range? Remember the length we actually put in has 1
|
subtracted, so although it is a 16-bit field, it can be up to 2^16. */
|
subtracted, so although it is a 16-bit field, it can be up to 2^16. */
|
unsigned long int cmd = 0; /* GO_COMMAND */
|
unsigned long int cmd = 0; /* GO_COMMAND */
|
unsigned long int data_bytes = strtoul (argv[next_jreg], NULL, 16);
|
unsigned long int data_bytes = strtoul (argv[next_jreg], NULL, 16);
|
|
|
if (data_bytes < 0)
|
if (data_bytes < 0)
|
{
|
{
|
printf ("ERROR: GO_COMMAND_READ length 0x%lx too small\n", data_bytes);
|
printf ("ERROR: GO_COMMAND_READ length 0x%lx too small\n", data_bytes);
|
return 0;
|
return 0;
|
}
|
}
|
else if (data_bytes > 0x10000)
|
else if (data_bytes > 0x10000)
|
{
|
{
|
printf ("ERROR: GO_COMMAND_READ length 0x%lx too large\n", data_bytes);
|
printf ("ERROR: GO_COMMAND_READ length 0x%lx too large\n", data_bytes);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Compute the CRC */
|
/* Compute the CRC */
|
unsigned long int crc_in;
|
unsigned long int crc_in;
|
|
|
crc_in = crc32 (0, 1, 0xffffffff);
|
crc_in = crc32 (0, 1, 0xffffffff);
|
crc_in = crc32 (cmd, 4, crc_in);
|
crc_in = crc32 (cmd, 4, crc_in);
|
|
|
/* Reverse the fields */
|
/* Reverse the fields */
|
cmd = reverse_bits (cmd, 4);
|
cmd = reverse_bits (cmd, 4);
|
crc_in = reverse_bits (crc_in, 32);
|
crc_in = reverse_bits (crc_in, 32);
|
|
|
/* Allocate space and initialize the register
|
/* Allocate space and initialize the register
|
- 1 indicator bit
|
- 1 indicator bit
|
- 4 bits command in
|
- 4 bits command in
|
- 32 bits CRC in
|
- 32 bits CRC in
|
- data_bytes * 8 bits access type out
|
- data_bytes * 8 bits access type out
|
- 4 bits status out
|
- 4 bits status out
|
- 32 bits CRC out
|
- 32 bits CRC out
|
|
|
Total 73 + data_bytes * 8 bits = 10 + data_bytes bytes */
|
Total 73 + data_bytes * 8 bits = 10 + data_bytes bytes */
|
int num_bytes = 10 + data_bytes;
|
int num_bytes = 10 + data_bytes;
|
unsigned char *jreg = malloc (num_bytes);
|
unsigned char *jreg = malloc (num_bytes);
|
|
|
if (NULL == jreg)
|
if (NULL == jreg)
|
{
|
{
|
printf ("ERROR: malloc forGO_COMMAND_READ register failed.\n");
|
printf ("ERROR: malloc forGO_COMMAND_READ register failed.\n");
|
return 0;
|
return 0;
|
}
|
}
|
|
|
memset (jreg, 0, num_bytes);
|
memset (jreg, 0, num_bytes);
|
|
|
jreg[0] = 0x0;
|
jreg[0] = 0x0;
|
jreg[0] |= cmd << 1;
|
jreg[0] |= cmd << 1;
|
|
|
jreg[0] |= crc_in << 5;
|
jreg[0] |= crc_in << 5;
|
jreg[1] = crc_in >> 3;
|
jreg[1] = crc_in >> 3;
|
jreg[2] = crc_in >> 11;
|
jreg[2] = crc_in >> 11;
|
jreg[3] = crc_in >> 19;
|
jreg[3] = crc_in >> 19;
|
jreg[4] = crc_in >> 27;
|
jreg[4] = crc_in >> 27;
|
|
|
/* Note what we are shifting in and shift it. */
|
/* Note what we are shifting in and shift it. */
|
dump_jreg (" shifting in", jreg, num_bytes);
|
dump_jreg (" shifting in", jreg, num_bytes);
|
double t = or1ksim_jtag_shift_dr (jreg,
|
double t = or1ksim_jtag_shift_dr (jreg,
|
32 + 4 + data_bytes * 8 + 32 + 4 + 1);
|
32 + 4 + data_bytes * 8 + 32 + 4 + 1);
|
|
|
/* Diagnose what we are shifting out. */
|
/* Diagnose what we are shifting out. */
|
dump_jreg (" shifted out", jreg, num_bytes);
|
dump_jreg (" shifted out", jreg, num_bytes);
|
|
|
/* Break out fields */
|
/* Break out fields */
|
unsigned char *data = malloc (data_bytes);
|
unsigned char *data = malloc (data_bytes);
|
unsigned char status;
|
unsigned char status;
|
unsigned long int crc_out;
|
unsigned long int crc_out;
|
|
|
if (NULL == data)
|
if (NULL == data)
|
{
|
{
|
printf ("ERROR: data malloc for GO_COMMAND_READ register failed.\n");
|
printf ("ERROR: data malloc for GO_COMMAND_READ register failed.\n");
|
free (jreg);
|
free (jreg);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
int i;
|
int i;
|
|
|
for (i = 0; i < data_bytes; i++)
|
for (i = 0; i < data_bytes; i++)
|
{
|
{
|
data[i] = ((jreg[i + 4] >> 5) | (jreg[i + 5] << 3)) & 0xff;
|
data[i] = ((jreg[i + 4] >> 5) | (jreg[i + 5] << 3)) & 0xff;
|
}
|
}
|
|
|
status = ((jreg[data_bytes + 4] >> 5) | (jreg[data_bytes + 5] << 3)) & 0xf ;
|
status = ((jreg[data_bytes + 4] >> 5) | (jreg[data_bytes + 5] << 3)) & 0xf ;
|
|
|
crc_out = ((unsigned long int) jreg[data_bytes + 5] >> 1) |
|
crc_out = ((unsigned long int) jreg[data_bytes + 5] >> 1) |
|
((unsigned long int) jreg[data_bytes + 6] << 7) |
|
((unsigned long int) jreg[data_bytes + 6] << 7) |
|
((unsigned long int) jreg[data_bytes + 7] << 15) |
|
((unsigned long int) jreg[data_bytes + 7] << 15) |
|
((unsigned long int) jreg[data_bytes + 8] << 23) |
|
((unsigned long int) jreg[data_bytes + 8] << 23) |
|
((unsigned long int) jreg[data_bytes + 9] << 31);
|
((unsigned long int) jreg[data_bytes + 9] << 31);
|
|
|
/* Reverse the fields */
|
/* Reverse the fields */
|
for (i = 0; i < data_bytes; i++)
|
for (i = 0; i < data_bytes; i++)
|
{
|
{
|
data[i] = reverse_bits (data[i], 8);
|
data[i] = reverse_bits (data[i], 8);
|
}
|
}
|
|
|
status = reverse_bits (status, 4);
|
status = reverse_bits (status, 4);
|
crc_out = reverse_bits (crc_out, 32);
|
crc_out = reverse_bits (crc_out, 32);
|
|
|
/* Compute our own CRC */
|
/* Compute our own CRC */
|
unsigned long int crc_computed = 0xffffffff;
|
unsigned long int crc_computed = 0xffffffff;
|
|
|
for (i = 0; i < data_bytes; i++)
|
for (i = 0; i < data_bytes; i++)
|
{
|
{
|
crc_computed = crc32 (data[i], 8, crc_computed);
|
crc_computed = crc32 (data[i], 8, crc_computed);
|
}
|
}
|
|
|
crc_computed = crc32 (status, 4, crc_computed);
|
crc_computed = crc32 (status, 4, crc_computed);
|
|
|
/* Log the results, remembering these are bytes, so endianness is not a
|
/* Log the results, remembering these are bytes, so endianness is not a
|
factor here. Since the OR1K is big endian, the lowest numbered byte will
|
factor here. Since the OR1K is big endian, the lowest numbered byte will
|
be the least significant, and the first printed */
|
be the least significant, and the first printed */
|
printf (" data: ");
|
printf (" data: ");
|
|
|
for (i = 0; i < data_bytes; i++)
|
for (i = 0; i < data_bytes; i++)
|
{
|
{
|
printf ("%02x", data[i]);
|
printf ("%02x", data[i]);
|
}
|
}
|
|
|
printf ("\n");
|
printf ("\n");
|
printf (" status: 0x%01x\n", status);
|
printf (" status: 0x%01x\n", status);
|
|
|
if (crc_out != crc_computed)
|
if (crc_out != crc_computed)
|
{
|
{
|
printf (" CRC mismatch\n");
|
printf (" CRC mismatch\n");
|
printf (" CRC out: 0x%08lx\n", crc_out);
|
printf (" CRC out: 0x%08lx\n", crc_out);
|
printf (" CRC computed: 0x%08lx\n", crc_computed);
|
printf (" CRC computed: 0x%08lx\n", crc_computed);
|
}
|
}
|
|
|
printf (" time taken: %.12fs\n", t);
|
printf (" time taken: %.12fs\n", t);
|
|
|
free (data);
|
free (data);
|
free (jreg);
|
free (jreg);
|
return 1; /* Completed successfully */
|
return 1; /* Completed successfully */
|
|
|
} /* process_go_command_read () */
|
} /* process_go_command_read () */
|
|
|
|
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
/*!Process a JTAG WRITE_CONTROL debug data register
|
/*!Process a JTAG WRITE_CONTROL debug data register
|
|
|
Usage:
|
Usage:
|
|
|
WRITE_CONTROL <reset> <stall>
|
WRITE_CONTROL <reset> <stall>
|
|
|
The arguments should be either zero or one.
|
The arguments should be either zero or one.
|
|
|
The arguments are used to construct the 52-bit CPU control register. Like
|
The arguments are used to construct the 52-bit CPU control register. Like
|
all JTAG fields, it must be reversed, so it is shifted MS bit first. It
|
all JTAG fields, it must be reversed, so it is shifted MS bit first. It
|
also requires a 32-bit CRC.
|
also requires a 32-bit CRC.
|
|
|
On return we get a status register and CRC.
|
On return we get a status register and CRC.
|
|
|
@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 hex
|
string.
|
string.
|
@param[in] argc argc from the main program (for checking next_jreg).
|
@param[in] argc argc from the main program (for checking next_jreg).
|
@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. */
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
static int
|
static int
|
process_write_control (int next_jreg,
|
process_write_control (int next_jreg,
|
int argc,
|
int argc,
|
char *argv[])
|
char *argv[])
|
{
|
{
|
printf ("Processing WRITE_CONTROL.\n");
|
printf ("Processing WRITE_CONTROL.\n");
|
|
|
/* Do we have the args */
|
/* Do we have the args */
|
if (next_jreg + 2 > argc)
|
if (next_jreg + 2 > argc)
|
{
|
{
|
printf ("WRITE_CONTROL usage: WRITE_CONTROL <reset> <status>\n");
|
printf ("WRITE_CONTROL usage: WRITE_CONTROL <reset> <status>\n");
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Are the arguments in range? */
|
/* Are the arguments in range? */
|
unsigned long int cmd = 4; /* WRITE_CONTROL */
|
unsigned long int cmd = 4; /* WRITE_CONTROL */
|
|
|
unsigned long int reset = strtoul (argv[next_jreg ], NULL, 16);
|
unsigned long int reset = strtoul (argv[next_jreg ], NULL, 16);
|
unsigned long int stall = strtoul (argv[next_jreg + 1], NULL, 16);
|
unsigned long int stall = strtoul (argv[next_jreg + 1], NULL, 16);
|
|
|
if (reset > 0x1)
|
if (reset > 0x1)
|
{
|
{
|
printf ("ERROR: invalid WRITE_CONTROL reset value 0x%lx.\n", reset);
|
printf ("ERROR: invalid WRITE_CONTROL reset value 0x%lx.\n", reset);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
if (stall > 0x1)
|
if (stall > 0x1)
|
{
|
{
|
printf ("ERROR: invalid WRITE_CONTROL stall value 0x%lx.\n", stall);
|
printf ("ERROR: invalid WRITE_CONTROL stall value 0x%lx.\n", stall);
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Construct the control register */
|
/* Construct the control register */
|
unsigned long long int creg = ((unsigned long long int) reset << 51) |
|
unsigned long long int creg = ((unsigned long long int) reset << 51) |
|
((unsigned long long int) stall << 50);
|
((unsigned long long int) stall << 50);
|
|
|
/* Compute the CRC */
|
/* Compute the CRC */
|
unsigned long int crc_in;
|
unsigned long int crc_in;
|
|
|
crc_in = crc32 (0, 1, 0xffffffff);
|
crc_in = crc32 (0, 1, 0xffffffff);
|
crc_in = crc32 (cmd, 4, crc_in);
|
crc_in = crc32 (cmd, 4, crc_in);
|
crc_in = crc32 (creg, 52, crc_in);
|
crc_in = crc32 (creg, 52, crc_in);
|
|
|
/* Reverse the fields */
|
/* Reverse the fields */
|
cmd = reverse_bits (cmd, 4);
|
cmd = reverse_bits (cmd, 4);
|
creg = reverse_bits (creg, 52);
|
creg = reverse_bits (creg, 52);
|
crc_in = reverse_bits (crc_in, 32);
|
crc_in = reverse_bits (crc_in, 32);
|
|
|
/* Allocate space and initialize the register
|
/* Allocate space and initialize the register
|
- 1 indicator bit
|
- 1 indicator bit
|
- 4 bits command in
|
- 4 bits command in
|
- 52 bits control register
|
- 52 bits control register
|
- 32 bits CRC in
|
- 32 bits CRC in
|
- 4 bits status out
|
- 4 bits status out
|
- 32 bits CRC out
|
- 32 bits CRC out
|
|
|
Total 125 bits = 16 bytes */
|
Total 125 bits = 16 bytes */
|
int num_bytes = 16;
|
int num_bytes = 16;
|
unsigned char *jreg = malloc (num_bytes);
|
unsigned char *jreg = malloc (num_bytes);
|
|
|
if (NULL == jreg)
|
if (NULL == jreg)
|
{
|
{
|
printf ("ERROR: malloc for WRITE_CONTROL register failed.\n");
|
printf ("ERROR: malloc for WRITE_CONTROL register failed.\n");
|
return 0;
|
return 0;
|
}
|
}
|
|
|
memset (jreg, 0, num_bytes);
|
memset (jreg, 0, num_bytes);
|
|
|
jreg[ 0] = 0x0;
|
jreg[ 0] = 0x0;
|
|
|
jreg[ 0] |= cmd << 1;
|
jreg[ 0] |= cmd << 1;
|
|
|
jreg[ 0] |= creg << 5;
|
jreg[ 0] |= creg << 5;
|
jreg[ 1] = creg >> 3;
|
jreg[ 1] = creg >> 3;
|
jreg[ 2] = creg >> 11;
|
jreg[ 2] = creg >> 11;
|
jreg[ 3] = creg >> 19;
|
jreg[ 3] = creg >> 19;
|
jreg[ 4] = creg >> 27;
|
jreg[ 4] = creg >> 27;
|
jreg[ 5] = creg >> 35;
|
jreg[ 5] = creg >> 35;
|
jreg[ 6] = creg >> 43;
|
jreg[ 6] = creg >> 43;
|
jreg[ 7] = creg >> 51;
|
jreg[ 7] = creg >> 51;
|
|
|
jreg[ 7] |= crc_in << 1;
|
jreg[ 7] |= crc_in << 1;
|
jreg[ 8] = crc_in >> 7;
|
jreg[ 8] = crc_in >> 7;
|
jreg[ 9] = crc_in >> 15;
|
jreg[ 9] = crc_in >> 15;
|
jreg[10] = crc_in >> 23;
|
jreg[10] = crc_in >> 23;
|
jreg[11] = crc_in >> 31;
|
jreg[11] = crc_in >> 31;
|
|
|
/* Note what we are shifting in and shift it. */
|
/* Note what we are shifting in and shift it. */
|
dump_jreg (" shifting in", jreg, num_bytes);
|
dump_jreg (" shifting in", jreg, num_bytes);
|
double t = or1ksim_jtag_shift_dr (jreg, 32 + 4 + 32 + 52 + 4 + 1);
|
double t = or1ksim_jtag_shift_dr (jreg, 32 + 4 + 32 + 52 + 4 + 1);
|
|
|
/* Diagnose what we are shifting out. */
|
/* Diagnose what we are shifting out. */
|
dump_jreg (" shifted out", jreg, num_bytes);
|
dump_jreg (" shifted out", jreg, num_bytes);
|
|
|
/* Break out fields */
|
/* Break out fields */
|
unsigned char status;
|
unsigned char status;
|
unsigned long int crc_out;
|
unsigned long int crc_out;
|
|
|
status = (jreg[11] >> 1) & 0xf ;
|
status = (jreg[11] >> 1) & 0xf ;
|
|
|
crc_out = ((unsigned long int) jreg[11] >> 5) |
|
crc_out = ((unsigned long int) jreg[11] >> 5) |
|
((unsigned long int) jreg[12] << 3) |
|
((unsigned long int) jreg[12] << 3) |
|
((unsigned long int) jreg[13] << 11) |
|
((unsigned long int) jreg[13] << 11) |
|
((unsigned long int) jreg[14] << 19) |
|
((unsigned long int) jreg[14] << 19) |
|
((unsigned long int) jreg[15] << 27);
|
((unsigned long int) jreg[15] << 27);
|
|
|
/* Reverse the fields */
|
/* Reverse the fields */
|
status = reverse_bits (status, 4);
|
status = reverse_bits (status, 4);
|
crc_out = reverse_bits (crc_out, 32);
|
crc_out = reverse_bits (crc_out, 32);
|
|
|
/* Compute our own CRC */
|
/* Compute our own CRC */
|
unsigned long int crc_computed = crc32 (status, 4, 0xffffffff);
|
unsigned long int crc_computed = crc32 (status, 4, 0xffffffff);
|
|
|
/* Log the results */
|
/* Log the results */
|
printf (" status: 0x%01x\n", status);
|
printf (" status: 0x%01x\n", status);
|
|
|
if (crc_out != crc_computed)
|
if (crc_out != crc_computed)
|
{
|
{
|
printf (" CRC mismatch\n");
|
printf (" CRC mismatch\n");
|
printf (" CRC out: 0x%08lx\n", crc_out);
|
printf (" CRC out: 0x%08lx\n", crc_out);
|
printf (" CRC computed: 0x%08lx\n", crc_computed);
|
printf (" CRC computed: 0x%08lx\n", crc_computed);
|
}
|
}
|
|
|
printf (" time taken: %.12fs\n", t);
|
printf (" time taken: %.12fs\n", t);
|
|
|
free (jreg);
|
free (jreg);
|
return 1; /* Completed successfully */
|
return 1; /* Completed successfully */
|
|
|
} /* process_write_control () */
|
} /* process_write_control () */
|
|
|
|
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
/*!Process a JTAG READ_CONTROL debug data register
|
/*!Process a JTAG READ_CONTROL debug data register
|
|
|
Usage:
|
Usage:
|
|
|
READ_CONTROL
|
READ_CONTROL
|
|
|
There are no arguments. It requires a 32-bit CRC.
|
There are no arguments. It requires a 32-bit CRC.
|
|
|
On return we get the control register, status and CRC.
|
On return we get the control register, status and CRC.
|
|
|
Like all the JTAG fields, they must be reversed, as resutl is shifted out
|
Like all the JTAG fields, they must be reversed, as resutl is shifted out
|
LS bit first.
|
LS bit first.
|
|
|
@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 hex
|
string.
|
string.
|
@param[in] argc argc from the main program (for checking next_jreg).
|
@param[in] argc argc from the main program (for checking next_jreg).
|
@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. */
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
static int
|
static int
|
process_read_control (int next_jreg,
|
process_read_control (int next_jreg,
|
int argc,
|
int argc,
|
char *argv[])
|
char *argv[])
|
{
|
{
|
printf ("Processing READ_CONTROL.\n");
|
printf ("Processing READ_CONTROL.\n");
|
|
|
/* Only input field is cmd. */
|
/* Only input field is cmd. */
|
unsigned long int cmd = 3; /* READ_CONTROL */
|
unsigned long int cmd = 3; /* READ_CONTROL */
|
|
|
/* Compute the CRC */
|
/* Compute the CRC */
|
unsigned long int crc_in;
|
unsigned long int crc_in;
|
|
|
crc_in = crc32 (0, 1, 0xffffffff);
|
crc_in = crc32 (0, 1, 0xffffffff);
|
crc_in = crc32 (cmd, 4, crc_in);
|
crc_in = crc32 (cmd, 4, crc_in);
|
|
|
/* Reverse the fields */
|
/* Reverse the fields */
|
cmd = reverse_bits (cmd, 4);
|
cmd = reverse_bits (cmd, 4);
|
crc_in = reverse_bits (crc_in, 32);
|
crc_in = reverse_bits (crc_in, 32);
|
|
|
/* Allocate space and initialize the register
|
/* Allocate space and initialize the register
|
- 1 indicator bit
|
- 1 indicator bit
|
- 4 bits command in
|
- 4 bits command in
|
- 32 bits CRC in
|
- 32 bits CRC in
|
- 52 bits control register out
|
- 52 bits control register out
|
- 4 bits status out
|
- 4 bits status out
|
- 32 bits CRC out
|
- 32 bits CRC out
|
|
|
Total 125 bits = 16 bytes */
|
Total 125 bits = 16 bytes */
|
int num_bytes = 16;
|
int num_bytes = 16;
|
unsigned char *jreg = malloc (num_bytes);
|
unsigned char *jreg = malloc (num_bytes);
|
|
|
if (NULL == jreg)
|
if (NULL == jreg)
|
{
|
{
|
printf ("ERROR: malloc for READ_CONTROL register failed.\n");
|
printf ("ERROR: malloc for READ_CONTROL register failed.\n");
|
return 0;
|
return 0;
|
}
|
}
|
|
|
memset (jreg, 0, num_bytes);
|
memset (jreg, 0, num_bytes);
|
|
|
jreg[0] = 0x0;
|
jreg[0] = 0x0;
|
|
|
jreg[0] |= cmd << 1;
|
jreg[0] |= cmd << 1;
|
|
|
jreg[0] |= crc_in << 5;
|
jreg[0] |= crc_in << 5;
|
jreg[1] = crc_in >> 3;
|
jreg[1] = crc_in >> 3;
|
jreg[2] = crc_in >> 11;
|
jreg[2] = crc_in >> 11;
|
jreg[3] = crc_in >> 19;
|
jreg[3] = crc_in >> 19;
|
jreg[4] = crc_in >> 27;
|
jreg[4] = crc_in >> 27;
|
|
|
/* Note what we are shifting in and shift it. */
|
/* Note what we are shifting in and shift it. */
|
dump_jreg (" shifting in", jreg, num_bytes);
|
dump_jreg (" shifting in", jreg, num_bytes);
|
double t = or1ksim_jtag_shift_dr (jreg, 32 + 4 + 52 + 32 + 4 + 1);
|
double t = or1ksim_jtag_shift_dr (jreg, 32 + 4 + 52 + 32 + 4 + 1);
|
|
|
/* Diagnose what we are shifting out. */
|
/* Diagnose what we are shifting out. */
|
dump_jreg (" shifted out", jreg, num_bytes);
|
dump_jreg (" shifted out", jreg, num_bytes);
|
|
|
/* Break out fields */
|
/* Break out fields */
|
unsigned long long int creg;
|
unsigned long long int creg;
|
unsigned char status;
|
unsigned char status;
|
unsigned long int crc_out;
|
unsigned long int crc_out;
|
|
|
creg = ((unsigned long long int) jreg[ 4] >> 5) |
|
creg = ((unsigned long long int) jreg[ 4] >> 5) |
|
((unsigned long long int) jreg[ 5] << 3) |
|
((unsigned long long int) jreg[ 5] << 3) |
|
((unsigned long long int) jreg[ 6] << 11) |
|
((unsigned long long int) jreg[ 6] << 11) |
|
((unsigned long long int) jreg[ 7] << 19) |
|
((unsigned long long int) jreg[ 7] << 19) |
|
((unsigned long long int) jreg[ 8] << 27) |
|
((unsigned long long int) jreg[ 8] << 27) |
|
((unsigned long long int) jreg[ 9] << 35) |
|
((unsigned long long int) jreg[ 9] << 35) |
|
((unsigned long long int) jreg[10] << 43) |
|
((unsigned long long int) jreg[10] << 43) |
|
((unsigned long long int) (jreg[11] & 0x1) << 51);
|
((unsigned long long int) (jreg[11] & 0x1) << 51);
|
|
|
status = (jreg[11] >> 1) & 0xf ;
|
status = (jreg[11] >> 1) & 0xf ;
|
|
|
crc_out = ((unsigned long int) jreg[11] >> 5) |
|
crc_out = ((unsigned long int) jreg[11] >> 5) |
|
((unsigned long int) jreg[12] << 3) |
|
((unsigned long int) jreg[12] << 3) |
|
((unsigned long int) jreg[13] << 11) |
|
((unsigned long int) jreg[13] << 11) |
|
((unsigned long int) jreg[14] << 19) |
|
((unsigned long int) jreg[14] << 19) |
|
((unsigned long int) jreg[15] << 27);
|
((unsigned long int) jreg[15] << 27);
|
|
|
/* Reverse the fields */
|
/* Reverse the fields */
|
creg = reverse_bits (creg, 52);
|
creg = reverse_bits (creg, 52);
|
status = reverse_bits (status, 4);
|
status = reverse_bits (status, 4);
|
crc_out = reverse_bits (crc_out, 32);
|
crc_out = reverse_bits (crc_out, 32);
|
|
|
/* Compute our own CRC */
|
/* Compute our own CRC */
|
unsigned long int crc_computed;
|
unsigned long int crc_computed;
|
|
|
crc_computed = crc32 (creg, 52, 0xffffffff);
|
crc_computed = crc32 (creg, 52, 0xffffffff);
|
crc_computed = crc32 (status, 4, crc_computed);
|
crc_computed = crc32 (status, 4, crc_computed);
|
|
|
const char *reset = (1 == ((creg >> 51) & 1)) ? "enabled" : "disabled";
|
const char *reset = (1 == ((creg >> 51) & 1)) ? "enabled" : "disabled";
|
const char *stall = (1 == ((creg >> 50) & 1)) ? "stalled" : "unstalled";
|
const char *stall = (1 == ((creg >> 50) & 1)) ? "stalled" : "unstalled";
|
|
|
/* Log the results */
|
/* Log the results */
|
printf (" reset: %s\n", reset);
|
printf (" reset: %s\n", reset);
|
printf (" stall: %s\n", stall);
|
printf (" stall: %s\n", stall);
|
printf (" status: 0x%01x\n", status);
|
printf (" status: 0x%01x\n", status);
|
|
|
if (crc_out != crc_computed)
|
if (crc_out != crc_computed)
|
{
|
{
|
printf (" CRC mismatch\n");
|
printf (" CRC mismatch\n");
|
printf (" CRC out: 0x%08lx\n", crc_out);
|
printf (" CRC out: 0x%08lx\n", crc_out);
|
printf (" CRC computed: 0x%08lx\n", crc_computed);
|
printf (" CRC computed: 0x%08lx\n", crc_computed);
|
}
|
}
|
|
|
printf (" time taken: %.12fs\n", t);
|
printf (" time taken: %.12fs\n", t);
|
|
|
free (jreg);
|
free (jreg);
|
return 1; /* Completed successfully */
|
return 1; /* Completed successfully */
|
|
|
} /* process_read_control () */
|
} /* process_read_control () */
|
|
|
|
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
/*!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 and then drives JTAG.
|
from the command line and then drives JTAG.
|
|
|
lib-jtag-full <config-file> <image> <jregtype> [<args>]
|
lib-jtag-full <config-file> <image> <jregtype> [<args>]
|
[<jregtype> [<args>]] ...
|
[<jregtype> [<args>]] ...
|
|
|
- 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
|
- jregtype One of RESET, INSTRUCTION, SELECT_MODULE, WRITE_COMMAND,
|
- jregtype One of RESET, INSTRUCTION, SELECT_MODULE, WRITE_COMMAND,
|
READ_COMMAND, GO_COMMAND_WRITE, GO_COMMAND_READ,
|
READ_COMMAND, GO_COMMAND_WRITE, GO_COMMAND_READ,
|
WRITE_CONTROL or READ_CONTROL.
|
WRITE_CONTROL or READ_CONTROL.
|
- args Arguments required by the jregtype. RESET, READ_COMMAND and
|
- args Arguments required by the jregtype. RESET, READ_COMMAND and
|
READ_CONTROL require none.
|
READ_CONTROL require none.
|
|
|
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
|
JTAG interface is reset (for RESET) or the next register is submitted to
|
JTAG interface is reset (for RESET) or the next register is submitted to
|
the corresponding Or1ksim JTAG interface and the resulting register noted.
|
the corresponding Or1ksim JTAG interface and the resulting register noted.
|
|
|
@param[in] argc Number of elements in argv
|
@param[in] argc Number of elements in argv
|
@param[in] argv Vector of program name and arguments
|
@param[in] argv Vector of program name and arguments
|
|
|
@return Return code for the program, zero on success. */
|
@return Return code for the program, zero on success. */
|
/* --------------------------------------------------------------------------*/
|
/* --------------------------------------------------------------------------*/
|
int
|
int
|
main (int argc,
|
main (int argc,
|
char *argv[])
|
char *argv[])
|
{
|
{
|
const double QUANTUM = 5.0e-3; /* Time in sec for each step. */
|
const double QUANTUM = 5.0e-3; /* Time in sec for each step. */
|
|
|
/* 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> <jregtype> [<args>] "
|
printf ("usage: lib-jtag <config-file> <image> <jregtype> [<args>] "
|
"[<jregtype> [<args>]] ...\n");
|
"[<jregtype> [<args>]] ...\n");
|
return 1;
|
return 1;
|
}
|
}
|
|
|
|
/* Dummy argv array to pass arguments to or1ksim_init. Varies depending on
|
|
whether an image file is specified. */
|
|
int dummy_argc;
|
|
char *dummy_argv[5];
|
|
|
|
dummy_argv[0] = "libsim";
|
|
dummy_argv[1] = "-q";
|
|
dummy_argv[2] = "-f";
|
|
dummy_argv[3] = argv[1];
|
|
dummy_argv[4] = argv[2];
|
|
|
|
dummy_argc = 5;
|
|
|
/* 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. */
|
if (0 == or1ksim_init (argv[1], argv[2], NULL, NULL, NULL))
|
if (0 == or1ksim_init (dummy_argc, dummy_argv, NULL, NULL, NULL))
|
{
|
{
|
printf ("Initalization succeeded.\n");
|
printf ("Initalization succeeded.\n");
|
}
|
}
|
else
|
else
|
{
|
{
|
printf ("Initalization failed.\n");
|
printf ("Initalization failed.\n");
|
return 1;
|
return 1;
|
}
|
}
|
|
|
/* Run repeatedly for 10 milliseconds until we have processed all JTAG
|
/* Run repeatedly for 10 milliseconds until we have processed all JTAG
|
registers */
|
registers */
|
int next_jreg = 3; /* Offset to next JTAG register */
|
int next_jreg = 3; /* Offset to next JTAG register */
|
|
|
do
|
do
|
{
|
{
|
switch (or1ksim_run (QUANTUM))
|
switch (or1ksim_run (QUANTUM))
|
{
|
{
|
case OR1KSIM_RC_OK:
|
case OR1KSIM_RC_OK:
|
printf ("Execution step completed OK.\n");
|
printf ("Execution step completed OK.\n");
|
break;
|
break;
|
|
|
case OR1KSIM_RC_BRKPT:
|
case OR1KSIM_RC_BRKPT:
|
printf ("Execution step completed with breakpoint.\n");
|
printf ("Execution step completed with breakpoint.\n");
|
break;
|
break;
|
|
|
default:
|
default:
|
printf ("ERROR: run failed.\n");
|
printf ("ERROR: run failed.\n");
|
return 1;
|
return 1;
|
}
|
}
|
|
|
/* Process the next register appropriately, skipping any args after
|
/* Process the next register appropriately, skipping any args after
|
processing. */
|
processing. */
|
char *jregtype = argv[next_jreg++];
|
char *jregtype = argv[next_jreg++];
|
|
|
if (0 == strcasecmp ("RESET", jregtype))
|
if (0 == strcasecmp ("RESET", jregtype))
|
{
|
{
|
printf ("Resetting JTAG.\n");
|
printf ("Resetting JTAG.\n");
|
or1ksim_jtag_reset ();
|
or1ksim_jtag_reset ();
|
}
|
}
|
else if (0 == strcasecmp ("INSTRUCTION", jregtype))
|
else if (0 == strcasecmp ("INSTRUCTION", jregtype))
|
{
|
{
|
if (process_instruction (next_jreg, argc, argv))
|
if (process_instruction (next_jreg, argc, argv))
|
{
|
{
|
next_jreg++; /* succeeded */
|
next_jreg++; /* succeeded */
|
}
|
}
|
else
|
else
|
{
|
{
|
return 1; /* failed */
|
return 1; /* failed */
|
}
|
}
|
}
|
}
|
else if (0 == strcasecmp ("SELECT_MODULE", jregtype))
|
else if (0 == strcasecmp ("SELECT_MODULE", jregtype))
|
{
|
{
|
if (process_select_module (next_jreg, argc, argv))
|
if (process_select_module (next_jreg, argc, argv))
|
{
|
{
|
next_jreg++; /* succeeded */
|
next_jreg++; /* succeeded */
|
}
|
}
|
else
|
else
|
{
|
{
|
return 1; /* failed */
|
return 1; /* failed */
|
}
|
}
|
}
|
}
|
else if (0 == strcasecmp ("WRITE_COMMAND", jregtype))
|
else if (0 == strcasecmp ("WRITE_COMMAND", jregtype))
|
{
|
{
|
if (process_write_command (next_jreg, argc, argv))
|
if (process_write_command (next_jreg, argc, argv))
|
{
|
{
|
next_jreg += 3; /* succeeded */
|
next_jreg += 3; /* succeeded */
|
}
|
}
|
else
|
else
|
{
|
{
|
return 1; /* failed */
|
return 1; /* failed */
|
}
|
}
|
}
|
}
|
else if (0 == strcasecmp ("READ_COMMAND", jregtype))
|
else if (0 == strcasecmp ("READ_COMMAND", jregtype))
|
{
|
{
|
if (process_read_command (next_jreg, argc, argv))
|
if (process_read_command (next_jreg, argc, argv))
|
{
|
{
|
/* succeeded (no args) */
|
/* succeeded (no args) */
|
}
|
}
|
else
|
else
|
{
|
{
|
return 1; /* failed */
|
return 1; /* failed */
|
}
|
}
|
}
|
}
|
else if (0 == strcasecmp ("GO_COMMAND_WRITE", jregtype))
|
else if (0 == strcasecmp ("GO_COMMAND_WRITE", jregtype))
|
{
|
{
|
if (process_go_command_write (next_jreg, argc, argv))
|
if (process_go_command_write (next_jreg, argc, argv))
|
{
|
{
|
next_jreg++; /* succeeded */
|
next_jreg++; /* succeeded */
|
}
|
}
|
else
|
else
|
{
|
{
|
return 1; /* failed */
|
return 1; /* failed */
|
}
|
}
|
}
|
}
|
else if (0 == strcasecmp ("GO_COMMAND_READ", jregtype))
|
else if (0 == strcasecmp ("GO_COMMAND_READ", jregtype))
|
{
|
{
|
if (process_go_command_read (next_jreg, argc, argv))
|
if (process_go_command_read (next_jreg, argc, argv))
|
{
|
{
|
next_jreg++; /* succeeded */
|
next_jreg++; /* succeeded */
|
}
|
}
|
else
|
else
|
{
|
{
|
return 1; /* failed */
|
return 1; /* failed */
|
}
|
}
|
}
|
}
|
else if (0 == strcasecmp ("WRITE_CONTROL", jregtype))
|
else if (0 == strcasecmp ("WRITE_CONTROL", jregtype))
|
{
|
{
|
if (process_write_control (next_jreg, argc, argv))
|
if (process_write_control (next_jreg, argc, argv))
|
{
|
{
|
next_jreg += 2; /* succeeded */
|
next_jreg += 2; /* succeeded */
|
}
|
}
|
else
|
else
|
{
|
{
|
return 1; /* failed */
|
return 1; /* failed */
|
}
|
}
|
}
|
}
|
else if (0 == strcasecmp ("READ_CONTROL", jregtype))
|
else if (0 == strcasecmp ("READ_CONTROL", jregtype))
|
{
|
{
|
if (process_read_control (next_jreg, argc, argv))
|
if (process_read_control (next_jreg, argc, argv))
|
{
|
{
|
/* succeeded (no args) */
|
/* succeeded (no args) */
|
}
|
}
|
else
|
else
|
{
|
{
|
return 1; /* failed */
|
return 1; /* failed */
|
}
|
}
|
}
|
}
|
else
|
else
|
{
|
{
|
printf ("ERROR: Unrecognized JTAG register '%s'.\n", jregtype);
|
printf ("ERROR: Unrecognized JTAG register '%s'.\n", jregtype);
|
return 1;
|
return 1;
|
}
|
}
|
}
|
}
|
while (next_jreg < argc);
|
while (next_jreg < argc);
|
|
|
/* A little longer to allow response to last upcall to be handled. */
|
/* A little longer to allow response to last upcall to be handled. */
|
switch (or1ksim_run (QUANTUM))
|
switch (or1ksim_run (QUANTUM))
|
{
|
{
|
case OR1KSIM_RC_OK:
|
case OR1KSIM_RC_OK:
|
printf ("Execution step completed OK.\n");
|
printf ("Execution step completed OK.\n");
|
break;
|
break;
|
|
|
case OR1KSIM_RC_BRKPT:
|
case OR1KSIM_RC_BRKPT:
|
printf ("Execution step completed with breakpoint.\n");
|
printf ("Execution step completed with breakpoint.\n");
|
break;
|
break;
|
|
|
default:
|
default:
|
printf ("ERROR: run failed.\n");
|
printf ("ERROR: run failed.\n");
|
return 1;
|
return 1;
|
}
|
}
|
|
|
printf ("Test completed successfully.\n");
|
printf ("Test completed successfully.\n");
|
return 0;
|
return 0;
|
|
|
} /* main () */
|
} /* main () */
|
|
|