KISS Data Aquisition and Control System
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

579 lines
16 KiB

/*
*
* PRU Debug Program
* (c) Copyright 2011, 2013 by Arctica Technologies
* Written by Steven Anderson
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <termios.h>
#include <sys/ioctl.h>
#include "prudbg.h"
#include "uio.h"
// global variable definitions
unsigned int *pru;
unsigned int pru_inst_base[MAX_NUM_OF_PRUS];
unsigned int pru_ctrl_base[MAX_NUM_OF_PRUS];
unsigned int pru_data_base[MAX_NUM_OF_PRUS];
unsigned int pru_num = 0;
unsigned int last_offset, last_addr, last_len, last_cmd;
struct breakpoints bp[MAX_NUM_OF_PRUS][MAX_BREAKPOINTS];
struct watchvariable wa[MAX_NUM_OF_PRUS][MAX_WATCH];
// processor database
typedef struct offsets_tag {
unsigned int pruss_inst;
unsigned int pruss_data;
unsigned int pruss_ctrl;
} offsets_t;
struct pdb_tag {
char processor[MAX_PROC_NAME];
char short_name[MAX_PROC_NAME];
unsigned int pruss_address;
unsigned int pruss_len;
unsigned int num_of_pruss;
const offsets_t offsets[MAX_NUM_OF_PRUS];
} pdb[] = {
// The following is a "database" of available processors.
// To add another processor please copy one of the existing structures to
// the end before the END MARKER structure. "processor" is the long name
// for the processor (used for displaying info), "short_name" is used to
// select a processor at the command prompt (should be short and no spaces),
// "pruss_address" is the byte address of the beginning of the PRUSS memory
// space on the ARM, "pruss_len" is the memory allocated starting at the
// pruss_address address, "num_of_pruss" is the number of PRUs in the ARM
// processor (currently 2 is the only valid value), and "offsets" is an
// array of 32-bit word address/index values used to locate the instruction,
// data, and control memory locations for a specific PRU. This offsets
// array much contain num_of_pruss entries. If you add a processor to
// this structure then you should also add a DEFINE to the beginning of
// the prudbg.h file to represent the processor index in the structure
// array. This is only used for the DEFAULT_PROCESSOR_INDEX in the
// prudbg.h file (this sets the processor used if none is selected
// on the command line).
{
.processor = "AM1707",
.short_name = "AM1707",
.pruss_address = 0x01C30000,
.pruss_len = 0x20000,
.num_of_pruss = 2,
.offsets = {
{
.pruss_inst = 0x2000,
.pruss_data = 0x0000,
.pruss_ctrl = 0x1C00
},
{
.pruss_inst = 0x3000,
.pruss_data = 0x0800,
.pruss_ctrl = 0x1E00
}
}
},
{
.processor = "AM335x",
.short_name = "AM335X",
.pruss_address = 0x4A300000,
.pruss_len = 0x40000,
.num_of_pruss = 2,
.offsets = {
{
.pruss_inst = 0xD000,
.pruss_data = 0x0000,
.pruss_ctrl = 0x8800
},
{
.pruss_inst = 0xE000,
.pruss_data = 0x0800,
.pruss_ctrl = 0x9000
}
}
},
{ // end marker
.processor = "NONE",
.short_name = "NONE",
.num_of_pruss = 0
}
};
int strcmpci(char *str1, char *str2, int m) {
unsigned int i;
char c1, c2;
int r;
r = 1;
for (i=0; str1[i] != 0 && i<m; i++) {
c1 = str1[i];
c2 = str2[i];
if (c1>96 && c1<123) c1 = c1 - 32;
if (c2>96 && c2<123) c2 = c2 - 32;
if (c1 != c2) r = 0;
}
if ((i==m) || (str2[i] != 0)) r = 0;
return r;
}
// main entry point for program
int main(int argc, char *argv[])
{
int fd;
char prompt_str[20];
char cmd[MAX_CMD_LEN], cmdargs[MAX_CMDARGS_LEN];
unsigned int argptrs[MAX_ARGS], numargs;
struct termios oldT, newT;
unsigned int i;
unsigned int addr, len, bpnum, offset, wanum, value;
int opt;
unsigned long opt_pruss_addr;
int pru_access_mode, pi, pitemp;
char uio_dev_file[50];
// say hello
printf ("PRU Debugger v0.25\n");
printf ("(C) Copyright 2011, 2013 by Arctica Technologies. All rights reserved.\n");
printf ("Written by Steven Anderson\n");
printf ("\n");
// get command line options
opt_pruss_addr = 0;
pru_access_mode = ACCESS_GUESS;
pi = DEFAULT_PROCESSOR_INDEX;
while ((opt = getopt(argc, argv, "?a:p:um")) != -1) {
switch (opt) {
case 'a':
opt_pruss_addr = strtol(optarg, NULL, 0);
break;
case 'u':
pru_access_mode = ACCESS_UIO;
break;
case 'm':
pru_access_mode = ACCESS_MEM;
break;
case 'p':
pitemp = -1;
for(i=0; pdb[i].num_of_pruss != 0; i++) if (strcmpci(optarg, pdb[i].short_name, MAX_PROC_NAME)) pitemp = i;
if (pitemp == -1) {
printf("WARNING: unrecognized processor - will use the compiled-in default processor.\n\n");
} else {
pi = pitemp;
}
break;
case '?':
default: /* '?' */
printf("Usage: prudebug [-a pruss-address] [-u] [-m] [-p processor]\n");
printf(" -a - pruss-address is the memory address of the PRU in ARM memory space\n");
printf(" -u - force the use of UIO to map PRU memory space\n");
printf(" -m - force the use of /dev/mem to map PRU memory space\n");
printf(" if neither the -u or -m options are used then it will try the UIO first\n");
printf(" -p - select processor to use (sets the PRU memory locations)\n");
for(i=0; pdb[i].num_of_pruss != 0; i++) {
printf(" %s - %s\n", pdb[i].short_name, pdb[i].processor);
}
return(-1);
}
}
// setup PRU memory offsets
for (i=0; i<pdb[pi].num_of_pruss ;i++) {
pru_inst_base[i] = pdb[pi].offsets[i].pruss_inst;
pru_data_base[i] = pdb[pi].offsets[i].pruss_data;
pru_ctrl_base[i] = pdb[pi].offsets[i].pruss_ctrl;
}
// if user hasn't requested a different PRU base address on the CLI, then use the PRU DB address
if (opt_pruss_addr == 0) opt_pruss_addr = pdb[pi].pruss_address;
// determine how to obtain the PRU base memory pointer (/dev/mem or a UIO PRUSS driver file - /dev/uio*)
if (pru_access_mode == ACCESS_GUESS || pru_access_mode == ACCESS_UIO) {
// get the UIO info (a UIO device file for the PRUSS)
uio_getprussfile(uio_dev_file);
if (uio_dev_file[0] != 0) {
// there is a valid UIO/PRUSS file so open it and use the pointer
fd = open (uio_dev_file, O_RDWR | O_SYNC);
if (fd == -1) {
printf ("ERROR: could not open /dev/mem.\n\n");
return 1;
}
pru = mmap (0, pdb[pi].pruss_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (pru == MAP_FAILED) {
printf ("ERROR: could not map memory.\n\n");
return 1;
}
close(fd);
printf ("Using UIO PRUSS device.\n");
} else if (pru_access_mode == ACCESS_UIO) {
// user wanted only UIO device and none found - generate an error and exit
printf ("ERROR: UIO PRUSS device requested and none found.\n\n");
return (1);
} else {
// no valid UIO device file and user wants a guess so open /dev/mem
fd = open ("/dev/mem", O_RDWR | O_SYNC);
if (fd == -1) {
printf ("ERROR: could not open /dev/mem.\n\n");
return 1;
}
pru = mmap (0, pdb[pi].pruss_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, opt_pruss_addr);
if (pru == MAP_FAILED) {
printf ("ERROR: could not map memory.\n\n");
return 1;
}
close(fd);
printf ("Using /dev/mem device.\n");
}
} else {
// user requested the use of /dev/mem
fd = open ("/dev/mem", O_RDWR | O_SYNC);
if (fd == -1) {
printf ("ERROR: could not open /dev/mem.\n\n");
return 1;
}
pru = mmap (0, pdb[pi].pruss_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, opt_pruss_addr);
if (pru == MAP_FAILED) {
printf ("ERROR: could not map memory.\n\n");
return 1;
}
close(fd);
printf ("Using /dev/mem device.\n");
}
// get memory pointer for PRU from /dev/mem
// clear breakpoints
for (i=0; i<MAX_BREAKPOINTS; i++) {
bp[pru_num][i].state = BP_UNUSED;
}
// clear watch variables
for (i=0; i<MAX_WATCH; i++) {
wa[pru_num][i].state = WA_UNUSED;
}
// print some useful info
printf("Processor type %s\n", pdb[pi].processor);
printf("PRUSS memory address 0x%08x\n", opt_pruss_addr);
printf("PRUSS memory length 0x%08x\n\n", pdb[pi].pruss_len);
printf(" offsets below are in 32-bit word addresses (not ARM byte addresses)\n");
printf(" PRU Instruction Data Ctrl\n");
for (i=0; i<pdb[pi].num_of_pruss; i++) {
printf(" %-15d0x%08x 0x%08x 0x%08x\n", i, pdb[pi].offsets[i].pruss_inst, pdb[pi].offsets[i].pruss_data, pdb[pi].offsets[i].pruss_ctrl);
}
printf("\n");
// setup the terminal for more flexible IO
ioctl(0,TCGETS,&oldT);
newT=oldT;
newT.c_lflag &= ~ECHO;
newT.c_lflag &= ~ICANON;
ioctl(0,TCSETS,&newT);
// Command prompt handler
do {
// get command from user
sprintf(prompt_str, "PRU%u> ", pru_num);
cmd_input(prompt_str, cmd, cmdargs, argptrs, &numargs);
// do something with command info
if (!strcmp(cmd, "?") || !strcmp(cmd, "HELP")) { // HELP - help command
last_cmd = LAST_CMD_NONE;
printhelp();
}
else if (!strcmp(cmd, "HB")) { // brief HELP
last_cmd = LAST_CMD_NONE;
printhelpbrief();
}
else if (!strcmp(cmd, "BR")) { // BR - Breakpoint command
last_cmd = LAST_CMD_NONE;
if (numargs == 0) {
cmd_print_breakpoints();
} else if (numargs == 1) {
bpnum = strtol(&cmdargs[argptrs[0]], NULL, 0);
if (bpnum < MAX_BREAKPOINTS) {
cmd_clear_breakpoint (bpnum);
} else {
printf("ERROR: breakpoint number must be equal to or between 0 and %u\n", MAX_BREAKPOINTS-1);
}
} else if (numargs == 2) {
bpnum = strtol(&cmdargs[argptrs[0]], NULL, 0);
addr = strtol(&cmdargs[argptrs[1]], NULL, 0);
if (bpnum < MAX_BREAKPOINTS) {
cmd_set_breakpoint (bpnum, addr);
} else {
printf("ERROR: breakpoint number must be equal to or between 0 and %u\n", MAX_BREAKPOINTS-1);
}
} else {
printf("ERROR: invalid breakpoint command\n");
}
}
else if ((!strcmp(cmd, "D")) || (!strcmp(cmd, "DD")) || (!strcmp(cmd, "DI"))) { // D - Dump command
if (numargs > 2) {
printf("ERROR: too many arguments\n");
} else {
if (numargs == 2) {
addr = strtol(&cmdargs[argptrs[0]], NULL, 0);
len = strtol(&cmdargs[argptrs[1]], NULL, 0);
} else if (numargs == 0) {
addr = 0;
len = 16;
} else {
addr = strtol(&cmdargs[argptrs[0]], NULL, 0);
len = 16;
}
if ((addr < 0) || (addr > MAX_PRU_MEM - 1) || (len < 0) || (addr+len > MAX_PRU_MEM)) {
printf("ERROR: arguments out of range.\n");
} else if (numargs > 2) {
printf("ERROR: Incorrect format. Please use help command to get command details.\n");
} else {
if (!strcmp(cmd, "DD")) {
offset = pru_data_base[pru_num];
last_cmd = LAST_CMD_DD;
} else if (!strcmp(cmd, "DI")) {
offset = pru_inst_base[pru_num];
last_cmd = LAST_CMD_DI;
} else {
offset = 0;
last_cmd = LAST_CMD_D;
}
last_offset = offset;
last_addr = addr + len;
last_len = len;
printf ("Absolute addr = 0x%04x, offset = 0x%04x, Len = %u\n", addr + offset, addr, len);
cmd_d(offset, addr, len);
}
}
}
else if (!strcmp(cmd, "DIS")) { // DIS - disassemble command
if (numargs > 2) {
printf("ERROR: too many arguments\n");
} else {
if (numargs == 2) {
addr = strtol(&cmdargs[argptrs[0]], NULL, 0);
len = strtol(&cmdargs[argptrs[1]], NULL, 0);
} else if (numargs == 0) {
addr = 0;
len = 16;
} else {
addr = strtol(&cmdargs[argptrs[0]], NULL, 0);
len = 16;
}
if ((addr < 0) || (addr > MAX_PRU_MEM - 1) || (len < 0) || (addr+len > MAX_PRU_MEM)) {
printf("ERROR: arguments out of range.\n");
} else if (numargs > 2) {
printf("ERROR: Incorrect format. Please use help command to get command details.\n");
} else {
offset = pru_inst_base[pru_num];
last_cmd = LAST_CMD_DIS;
last_offset = offset;
last_addr = addr + len;
last_len = len;
printf ("Absolute addr = 0x%04x, offset = 0x%04x, Len = %u\n", addr + offset, addr, len);
cmd_dis(offset, addr, len);
}
}
}
else if (!strcmp(cmd, "G")) { // G - Start program
last_cmd = LAST_CMD_NONE;
if (numargs > 1) {
printf("ERROR: too many arguments\n");
} else if (numargs == 0) {
// start processor
cmd_run();
} else {
// set instruction pointer
addr = strtol(&cmdargs[argptrs[0]], NULL, 0);
// start processor
// cmd_run_at(addr);
printf("NOT IMPLEMENTED YET.\n");
}
}
else if (!strcmp(cmd, "GSS")) { // GSS - Start program using single stepping to provde BP/Watch
last_cmd = LAST_CMD_NONE;
if (numargs > 0) {
printf("ERROR: too many arguments\n");
} else {
// halt the processor
cmd_runss();
}
}
else if (!strcmp(cmd, "HALT")) { // HALT - Halt PRU
last_cmd = LAST_CMD_NONE;
if (numargs > 0) {
printf("ERROR: too many arguments\n");
} else {
// halt the processor
cmd_halt();
}
}
else if (!strcmp(cmd, "L")) { // L - Load PRU program
last_cmd = LAST_CMD_NONE;
if (numargs != 2) {
printf("ERROR: incorrect number of arguments\n");
} else {
addr = strtol(&cmdargs[argptrs[0]], NULL, 0);
cmd_loadprog(addr, &cmdargs[argptrs[1]]);
}
}
else if (!strcmp(cmd, "PRU")) { // PRU - Select the active PRU
last_cmd = LAST_CMD_NONE;
if (numargs != 1) {
printf("ERROR: incorrect number of arguments\n");
} else {
pru_num = strtol(&cmdargs[argptrs[0]], NULL, 0);
printf("Active PRU is PRU%u.\n\n", pru_num);
}
}
else if (!strcmp(cmd, "R")) { // R - Print PRU registers
last_cmd = LAST_CMD_NONE;
if (numargs != 0) {
printf("ERROR: incorrect number of arguments\n");
} else {
cmd_printregs();
}
}
else if (!strcmp(cmd, "RESET")) { // RESET - Reset PRU
last_cmd = LAST_CMD_NONE;
if (numargs > 0) {
printf("ERROR: too many arguments\n");
} else {
// reset the processor
cmd_soft_reset();
printf("\n");
}
}
else if (!strcmp(cmd, "SS")) { // SS - Single step
last_cmd = LAST_CMD_SS;
if (numargs > 0) {
printf("ERROR: too many arguments\n");
} else {
// reset the processor
cmd_single_step();
}
}
else if (!strcmp(cmd, "WA")) { // WA - Watch command
last_cmd = LAST_CMD_NONE;
if (numargs == 0) {
cmd_print_watch();
} else if (numargs == 1) {
wanum = strtol(&cmdargs[argptrs[0]], NULL, 0);
if (wanum < MAX_WATCH) {
cmd_clear_watch (wanum);
} else {
printf("ERROR: breakpoint number must be equal to or between 0 and %u\n", MAX_WATCH-1);
}
} else if (numargs == 2) {
wanum = strtol(&cmdargs[argptrs[0]], NULL, 0);
addr = strtol(&cmdargs[argptrs[1]], NULL, 0);
if (wanum < MAX_WATCH) {
cmd_set_watch_any (wanum, addr);
} else {
printf("ERROR: breakpoint number must be equal to or between 0 and %u\n", MAX_WATCH-1);
}
} else if (numargs == 3) {
wanum = strtol(&cmdargs[argptrs[0]], NULL, 0);
addr = strtol(&cmdargs[argptrs[1]], NULL, 0);
value = strtol(&cmdargs[argptrs[2]], NULL, 0);
if (wanum < MAX_WATCH) {
cmd_set_watch (wanum, addr, value);
} else {
printf("ERROR: breakpoint number must be equal to or between 0 and %u\n", MAX_WATCH-1);
}
} else {
printf("ERROR: invalid breakpoint command\n");
}
}
else if ((!strcmp(cmd, "WR")) || (!strcmp(cmd, "WRD")) || (!strcmp(cmd, "WRI"))) { // WR - Write Raw
last_cmd = LAST_CMD_NONE;
addr = strtol(&cmdargs[argptrs[0]], NULL, 0);
if (numargs < 2) {
printf("ERROR: too few arguments\n");
} else {
if ((addr < 0) || (addr > MAX_PRU_MEM - 1)) {
printf("ERROR: arguments out of range.\n");
} else {
if (!strcmp(cmd, "WRD")) {
offset = pru_data_base[pru_num];
} else if (!strcmp(cmd, "WRI")) {
offset = pru_inst_base[pru_num];
} else {
offset = 0;
}
printf("Write to absolute address 0x%04x\n", offset+addr);
for (i=1; i<numargs; i++) pru[offset+addr+i-1] = (unsigned int) (strtoll(&cmdargs[argptrs[i]], NULL, 0) & 0xFFFFFFFF);
}
}
}
else if (!strcmp(cmd, "Q")) { // dummy so it's a valid command
}
else if (!strcmp(cmd, "")) { // repeat display command option
switch(last_cmd) {
case LAST_CMD_D:
case LAST_CMD_DD:
case LAST_CMD_DI:
printf ("Absolute addr = 0x%04x, offset = 0x%04x, Len = %u\n", last_addr + last_offset, last_addr, last_len);
cmd_d(last_offset, last_addr, last_len);
last_addr += last_len;
break;
case LAST_CMD_SS:
cmd_single_step();
break;
default:
break;
}
}
else {
printf("Invalid command.\n\n");
}
} while (strcmp(cmd, "Q"));
printf("\nGoodbye.\n\n");
// restore terminal IO settings
ioctl(0,TCSETS,&oldT);
return 0;
}