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

  1. /*
  2. *
  3. * PRU Debug Program
  4. * (c) Copyright 2011, 2013 by Arctica Technologies
  5. * Written by Steven Anderson
  6. *
  7. */
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <unistd.h>
  11. #include <fcntl.h>
  12. #include <sys/mman.h>
  13. #include <sys/types.h>
  14. #include <sys/stat.h>
  15. #include <errno.h>
  16. #include <termios.h>
  17. #include <sys/ioctl.h>
  18. #include "prudbg.h"
  19. #include "uio.h"
  20. // global variable definitions
  21. unsigned int *pru;
  22. unsigned int pru_inst_base[MAX_NUM_OF_PRUS];
  23. unsigned int pru_ctrl_base[MAX_NUM_OF_PRUS];
  24. unsigned int pru_data_base[MAX_NUM_OF_PRUS];
  25. unsigned int pru_num = 0;
  26. unsigned int last_offset, last_addr, last_len, last_cmd;
  27. struct breakpoints bp[MAX_NUM_OF_PRUS][MAX_BREAKPOINTS];
  28. struct watchvariable wa[MAX_NUM_OF_PRUS][MAX_WATCH];
  29. // processor database
  30. typedef struct offsets_tag {
  31. unsigned int pruss_inst;
  32. unsigned int pruss_data;
  33. unsigned int pruss_ctrl;
  34. } offsets_t;
  35. struct pdb_tag {
  36. char processor[MAX_PROC_NAME];
  37. char short_name[MAX_PROC_NAME];
  38. unsigned int pruss_address;
  39. unsigned int pruss_len;
  40. unsigned int num_of_pruss;
  41. const offsets_t offsets[MAX_NUM_OF_PRUS];
  42. } pdb[] = {
  43. // The following is a "database" of available processors.
  44. // To add another processor please copy one of the existing structures to
  45. // the end before the END MARKER structure. "processor" is the long name
  46. // for the processor (used for displaying info), "short_name" is used to
  47. // select a processor at the command prompt (should be short and no spaces),
  48. // "pruss_address" is the byte address of the beginning of the PRUSS memory
  49. // space on the ARM, "pruss_len" is the memory allocated starting at the
  50. // pruss_address address, "num_of_pruss" is the number of PRUs in the ARM
  51. // processor (currently 2 is the only valid value), and "offsets" is an
  52. // array of 32-bit word address/index values used to locate the instruction,
  53. // data, and control memory locations for a specific PRU. This offsets
  54. // array much contain num_of_pruss entries. If you add a processor to
  55. // this structure then you should also add a DEFINE to the beginning of
  56. // the prudbg.h file to represent the processor index in the structure
  57. // array. This is only used for the DEFAULT_PROCESSOR_INDEX in the
  58. // prudbg.h file (this sets the processor used if none is selected
  59. // on the command line).
  60. {
  61. .processor = "AM1707",
  62. .short_name = "AM1707",
  63. .pruss_address = 0x01C30000,
  64. .pruss_len = 0x20000,
  65. .num_of_pruss = 2,
  66. .offsets = {
  67. {
  68. .pruss_inst = 0x2000,
  69. .pruss_data = 0x0000,
  70. .pruss_ctrl = 0x1C00
  71. },
  72. {
  73. .pruss_inst = 0x3000,
  74. .pruss_data = 0x0800,
  75. .pruss_ctrl = 0x1E00
  76. }
  77. }
  78. },
  79. {
  80. .processor = "AM335x",
  81. .short_name = "AM335X",
  82. .pruss_address = 0x4A300000,
  83. .pruss_len = 0x40000,
  84. .num_of_pruss = 2,
  85. .offsets = {
  86. {
  87. .pruss_inst = 0xD000,
  88. .pruss_data = 0x0000,
  89. .pruss_ctrl = 0x8800
  90. },
  91. {
  92. .pruss_inst = 0xE000,
  93. .pruss_data = 0x0800,
  94. .pruss_ctrl = 0x9000
  95. }
  96. }
  97. },
  98. { // end marker
  99. .processor = "NONE",
  100. .short_name = "NONE",
  101. .num_of_pruss = 0
  102. }
  103. };
  104. int strcmpci(char *str1, char *str2, int m) {
  105. unsigned int i;
  106. char c1, c2;
  107. int r;
  108. r = 1;
  109. for (i=0; str1[i] != 0 && i<m; i++) {
  110. c1 = str1[i];
  111. c2 = str2[i];
  112. if (c1>96 && c1<123) c1 = c1 - 32;
  113. if (c2>96 && c2<123) c2 = c2 - 32;
  114. if (c1 != c2) r = 0;
  115. }
  116. if ((i==m) || (str2[i] != 0)) r = 0;
  117. return r;
  118. }
  119. // main entry point for program
  120. int main(int argc, char *argv[])
  121. {
  122. int fd;
  123. char prompt_str[20];
  124. char cmd[MAX_CMD_LEN], cmdargs[MAX_CMDARGS_LEN];
  125. unsigned int argptrs[MAX_ARGS], numargs;
  126. struct termios oldT, newT;
  127. unsigned int i;
  128. unsigned int addr, len, bpnum, offset, wanum, value;
  129. int opt;
  130. unsigned long opt_pruss_addr;
  131. int pru_access_mode, pi, pitemp;
  132. char uio_dev_file[50];
  133. // say hello
  134. printf ("PRU Debugger v0.25\n");
  135. printf ("(C) Copyright 2011, 2013 by Arctica Technologies. All rights reserved.\n");
  136. printf ("Written by Steven Anderson\n");
  137. printf ("\n");
  138. // get command line options
  139. opt_pruss_addr = 0;
  140. pru_access_mode = ACCESS_GUESS;
  141. pi = DEFAULT_PROCESSOR_INDEX;
  142. while ((opt = getopt(argc, argv, "?a:p:um")) != -1) {
  143. switch (opt) {
  144. case 'a':
  145. opt_pruss_addr = strtol(optarg, NULL, 0);
  146. break;
  147. case 'u':
  148. pru_access_mode = ACCESS_UIO;
  149. break;
  150. case 'm':
  151. pru_access_mode = ACCESS_MEM;
  152. break;
  153. case 'p':
  154. pitemp = -1;
  155. for(i=0; pdb[i].num_of_pruss != 0; i++) if (strcmpci(optarg, pdb[i].short_name, MAX_PROC_NAME)) pitemp = i;
  156. if (pitemp == -1) {
  157. printf("WARNING: unrecognized processor - will use the compiled-in default processor.\n\n");
  158. } else {
  159. pi = pitemp;
  160. }
  161. break;
  162. case '?':
  163. default: /* '?' */
  164. printf("Usage: prudebug [-a pruss-address] [-u] [-m] [-p processor]\n");
  165. printf(" -a - pruss-address is the memory address of the PRU in ARM memory space\n");
  166. printf(" -u - force the use of UIO to map PRU memory space\n");
  167. printf(" -m - force the use of /dev/mem to map PRU memory space\n");
  168. printf(" if neither the -u or -m options are used then it will try the UIO first\n");
  169. printf(" -p - select processor to use (sets the PRU memory locations)\n");
  170. for(i=0; pdb[i].num_of_pruss != 0; i++) {
  171. printf(" %s - %s\n", pdb[i].short_name, pdb[i].processor);
  172. }
  173. return(-1);
  174. }
  175. }
  176. // setup PRU memory offsets
  177. for (i=0; i<pdb[pi].num_of_pruss ;i++) {
  178. pru_inst_base[i] = pdb[pi].offsets[i].pruss_inst;
  179. pru_data_base[i] = pdb[pi].offsets[i].pruss_data;
  180. pru_ctrl_base[i] = pdb[pi].offsets[i].pruss_ctrl;
  181. }
  182. // if user hasn't requested a different PRU base address on the CLI, then use the PRU DB address
  183. if (opt_pruss_addr == 0) opt_pruss_addr = pdb[pi].pruss_address;
  184. // determine how to obtain the PRU base memory pointer (/dev/mem or a UIO PRUSS driver file - /dev/uio*)
  185. if (pru_access_mode == ACCESS_GUESS || pru_access_mode == ACCESS_UIO) {
  186. // get the UIO info (a UIO device file for the PRUSS)
  187. uio_getprussfile(uio_dev_file);
  188. if (uio_dev_file[0] != 0) {
  189. // there is a valid UIO/PRUSS file so open it and use the pointer
  190. fd = open (uio_dev_file, O_RDWR | O_SYNC);
  191. if (fd == -1) {
  192. printf ("ERROR: could not open /dev/mem.\n\n");
  193. return 1;
  194. }
  195. pru = mmap (0, pdb[pi].pruss_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  196. if (pru == MAP_FAILED) {
  197. printf ("ERROR: could not map memory.\n\n");
  198. return 1;
  199. }
  200. close(fd);
  201. printf ("Using UIO PRUSS device.\n");
  202. } else if (pru_access_mode == ACCESS_UIO) {
  203. // user wanted only UIO device and none found - generate an error and exit
  204. printf ("ERROR: UIO PRUSS device requested and none found.\n\n");
  205. return (1);
  206. } else {
  207. // no valid UIO device file and user wants a guess so open /dev/mem
  208. fd = open ("/dev/mem", O_RDWR | O_SYNC);
  209. if (fd == -1) {
  210. printf ("ERROR: could not open /dev/mem.\n\n");
  211. return 1;
  212. }
  213. pru = mmap (0, pdb[pi].pruss_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, opt_pruss_addr);
  214. if (pru == MAP_FAILED) {
  215. printf ("ERROR: could not map memory.\n\n");
  216. return 1;
  217. }
  218. close(fd);
  219. printf ("Using /dev/mem device.\n");
  220. }
  221. } else {
  222. // user requested the use of /dev/mem
  223. fd = open ("/dev/mem", O_RDWR | O_SYNC);
  224. if (fd == -1) {
  225. printf ("ERROR: could not open /dev/mem.\n\n");
  226. return 1;
  227. }
  228. pru = mmap (0, pdb[pi].pruss_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, opt_pruss_addr);
  229. if (pru == MAP_FAILED) {
  230. printf ("ERROR: could not map memory.\n\n");
  231. return 1;
  232. }
  233. close(fd);
  234. printf ("Using /dev/mem device.\n");
  235. }
  236. // get memory pointer for PRU from /dev/mem
  237. // clear breakpoints
  238. for (i=0; i<MAX_BREAKPOINTS; i++) {
  239. bp[pru_num][i].state = BP_UNUSED;
  240. }
  241. // clear watch variables
  242. for (i=0; i<MAX_WATCH; i++) {
  243. wa[pru_num][i].state = WA_UNUSED;
  244. }
  245. // print some useful info
  246. printf("Processor type %s\n", pdb[pi].processor);
  247. printf("PRUSS memory address 0x%08x\n", opt_pruss_addr);
  248. printf("PRUSS memory length 0x%08x\n\n", pdb[pi].pruss_len);
  249. printf(" offsets below are in 32-bit word addresses (not ARM byte addresses)\n");
  250. printf(" PRU Instruction Data Ctrl\n");
  251. for (i=0; i<pdb[pi].num_of_pruss; i++) {
  252. 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);
  253. }
  254. printf("\n");
  255. // setup the terminal for more flexible IO
  256. ioctl(0,TCGETS,&oldT);
  257. newT=oldT;
  258. newT.c_lflag &= ~ECHO;
  259. newT.c_lflag &= ~ICANON;
  260. ioctl(0,TCSETS,&newT);
  261. // Command prompt handler
  262. do {
  263. // get command from user
  264. sprintf(prompt_str, "PRU%u> ", pru_num);
  265. cmd_input(prompt_str, cmd, cmdargs, argptrs, &numargs);
  266. // do something with command info
  267. if (!strcmp(cmd, "?") || !strcmp(cmd, "HELP")) { // HELP - help command
  268. last_cmd = LAST_CMD_NONE;
  269. printhelp();
  270. }
  271. else if (!strcmp(cmd, "HB")) { // brief HELP
  272. last_cmd = LAST_CMD_NONE;
  273. printhelpbrief();
  274. }
  275. else if (!strcmp(cmd, "BR")) { // BR - Breakpoint command
  276. last_cmd = LAST_CMD_NONE;
  277. if (numargs == 0) {
  278. cmd_print_breakpoints();
  279. } else if (numargs == 1) {
  280. bpnum = strtol(&cmdargs[argptrs[0]], NULL, 0);
  281. if (bpnum < MAX_BREAKPOINTS) {
  282. cmd_clear_breakpoint (bpnum);
  283. } else {
  284. printf("ERROR: breakpoint number must be equal to or between 0 and %u\n", MAX_BREAKPOINTS-1);
  285. }
  286. } else if (numargs == 2) {
  287. bpnum = strtol(&cmdargs[argptrs[0]], NULL, 0);
  288. addr = strtol(&cmdargs[argptrs[1]], NULL, 0);
  289. if (bpnum < MAX_BREAKPOINTS) {
  290. cmd_set_breakpoint (bpnum, addr);
  291. } else {
  292. printf("ERROR: breakpoint number must be equal to or between 0 and %u\n", MAX_BREAKPOINTS-1);
  293. }
  294. } else {
  295. printf("ERROR: invalid breakpoint command\n");
  296. }
  297. }
  298. else if ((!strcmp(cmd, "D")) || (!strcmp(cmd, "DD")) || (!strcmp(cmd, "DI"))) { // D - Dump command
  299. if (numargs > 2) {
  300. printf("ERROR: too many arguments\n");
  301. } else {
  302. if (numargs == 2) {
  303. addr = strtol(&cmdargs[argptrs[0]], NULL, 0);
  304. len = strtol(&cmdargs[argptrs[1]], NULL, 0);
  305. } else if (numargs == 0) {
  306. addr = 0;
  307. len = 16;
  308. } else {
  309. addr = strtol(&cmdargs[argptrs[0]], NULL, 0);
  310. len = 16;
  311. }
  312. if ((addr < 0) || (addr > MAX_PRU_MEM - 1) || (len < 0) || (addr+len > MAX_PRU_MEM)) {
  313. printf("ERROR: arguments out of range.\n");
  314. } else if (numargs > 2) {
  315. printf("ERROR: Incorrect format. Please use help command to get command details.\n");
  316. } else {
  317. if (!strcmp(cmd, "DD")) {
  318. offset = pru_data_base[pru_num];
  319. last_cmd = LAST_CMD_DD;
  320. } else if (!strcmp(cmd, "DI")) {
  321. offset = pru_inst_base[pru_num];
  322. last_cmd = LAST_CMD_DI;
  323. } else {
  324. offset = 0;
  325. last_cmd = LAST_CMD_D;
  326. }
  327. last_offset = offset;
  328. last_addr = addr + len;
  329. last_len = len;
  330. printf ("Absolute addr = 0x%04x, offset = 0x%04x, Len = %u\n", addr + offset, addr, len);
  331. cmd_d(offset, addr, len);
  332. }
  333. }
  334. }
  335. else if (!strcmp(cmd, "DIS")) { // DIS - disassemble command
  336. if (numargs > 2) {
  337. printf("ERROR: too many arguments\n");
  338. } else {
  339. if (numargs == 2) {
  340. addr = strtol(&cmdargs[argptrs[0]], NULL, 0);
  341. len = strtol(&cmdargs[argptrs[1]], NULL, 0);
  342. } else if (numargs == 0) {
  343. addr = 0;
  344. len = 16;
  345. } else {
  346. addr = strtol(&cmdargs[argptrs[0]], NULL, 0);
  347. len = 16;
  348. }
  349. if ((addr < 0) || (addr > MAX_PRU_MEM - 1) || (len < 0) || (addr+len > MAX_PRU_MEM)) {
  350. printf("ERROR: arguments out of range.\n");
  351. } else if (numargs > 2) {
  352. printf("ERROR: Incorrect format. Please use help command to get command details.\n");
  353. } else {
  354. offset = pru_inst_base[pru_num];
  355. last_cmd = LAST_CMD_DIS;
  356. last_offset = offset;
  357. last_addr = addr + len;
  358. last_len = len;
  359. printf ("Absolute addr = 0x%04x, offset = 0x%04x, Len = %u\n", addr + offset, addr, len);
  360. cmd_dis(offset, addr, len);
  361. }
  362. }
  363. }
  364. else if (!strcmp(cmd, "G")) { // G - Start program
  365. last_cmd = LAST_CMD_NONE;
  366. if (numargs > 1) {
  367. printf("ERROR: too many arguments\n");
  368. } else if (numargs == 0) {
  369. // start processor
  370. cmd_run();
  371. } else {
  372. // set instruction pointer
  373. addr = strtol(&cmdargs[argptrs[0]], NULL, 0);
  374. // start processor
  375. // cmd_run_at(addr);
  376. printf("NOT IMPLEMENTED YET.\n");
  377. }
  378. }
  379. else if (!strcmp(cmd, "GSS")) { // GSS - Start program using single stepping to provde BP/Watch
  380. last_cmd = LAST_CMD_NONE;
  381. if (numargs > 0) {
  382. printf("ERROR: too many arguments\n");
  383. } else {
  384. // halt the processor
  385. cmd_runss();
  386. }
  387. }
  388. else if (!strcmp(cmd, "HALT")) { // HALT - Halt PRU
  389. last_cmd = LAST_CMD_NONE;
  390. if (numargs > 0) {
  391. printf("ERROR: too many arguments\n");
  392. } else {
  393. // halt the processor
  394. cmd_halt();
  395. }
  396. }
  397. else if (!strcmp(cmd, "L")) { // L - Load PRU program
  398. last_cmd = LAST_CMD_NONE;
  399. if (numargs != 2) {
  400. printf("ERROR: incorrect number of arguments\n");
  401. } else {
  402. addr = strtol(&cmdargs[argptrs[0]], NULL, 0);
  403. cmd_loadprog(addr, &cmdargs[argptrs[1]]);
  404. }
  405. }
  406. else if (!strcmp(cmd, "PRU")) { // PRU - Select the active PRU
  407. last_cmd = LAST_CMD_NONE;
  408. if (numargs != 1) {
  409. printf("ERROR: incorrect number of arguments\n");
  410. } else {
  411. pru_num = strtol(&cmdargs[argptrs[0]], NULL, 0);
  412. printf("Active PRU is PRU%u.\n\n", pru_num);
  413. }
  414. }
  415. else if (!strcmp(cmd, "R")) { // R - Print PRU registers
  416. last_cmd = LAST_CMD_NONE;
  417. if (numargs != 0) {
  418. printf("ERROR: incorrect number of arguments\n");
  419. } else {
  420. cmd_printregs();
  421. }
  422. }
  423. else if (!strcmp(cmd, "RESET")) { // RESET - Reset PRU
  424. last_cmd = LAST_CMD_NONE;
  425. if (numargs > 0) {
  426. printf("ERROR: too many arguments\n");
  427. } else {
  428. // reset the processor
  429. cmd_soft_reset();
  430. printf("\n");
  431. }
  432. }
  433. else if (!strcmp(cmd, "SS")) { // SS - Single step
  434. last_cmd = LAST_CMD_SS;
  435. if (numargs > 0) {
  436. printf("ERROR: too many arguments\n");
  437. } else {
  438. // reset the processor
  439. cmd_single_step();
  440. }
  441. }
  442. else if (!strcmp(cmd, "WA")) { // WA - Watch command
  443. last_cmd = LAST_CMD_NONE;
  444. if (numargs == 0) {
  445. cmd_print_watch();
  446. } else if (numargs == 1) {
  447. wanum = strtol(&cmdargs[argptrs[0]], NULL, 0);
  448. if (wanum < MAX_WATCH) {
  449. cmd_clear_watch (wanum);
  450. } else {
  451. printf("ERROR: breakpoint number must be equal to or between 0 and %u\n", MAX_WATCH-1);
  452. }
  453. } else if (numargs == 2) {
  454. wanum = strtol(&cmdargs[argptrs[0]], NULL, 0);
  455. addr = strtol(&cmdargs[argptrs[1]], NULL, 0);
  456. if (wanum < MAX_WATCH) {
  457. cmd_set_watch_any (wanum, addr);
  458. } else {
  459. printf("ERROR: breakpoint number must be equal to or between 0 and %u\n", MAX_WATCH-1);
  460. }
  461. } else if (numargs == 3) {
  462. wanum = strtol(&cmdargs[argptrs[0]], NULL, 0);
  463. addr = strtol(&cmdargs[argptrs[1]], NULL, 0);
  464. value = strtol(&cmdargs[argptrs[2]], NULL, 0);
  465. if (wanum < MAX_WATCH) {
  466. cmd_set_watch (wanum, addr, value);
  467. } else {
  468. printf("ERROR: breakpoint number must be equal to or between 0 and %u\n", MAX_WATCH-1);
  469. }
  470. } else {
  471. printf("ERROR: invalid breakpoint command\n");
  472. }
  473. }
  474. else if ((!strcmp(cmd, "WR")) || (!strcmp(cmd, "WRD")) || (!strcmp(cmd, "WRI"))) { // WR - Write Raw
  475. last_cmd = LAST_CMD_NONE;
  476. addr = strtol(&cmdargs[argptrs[0]], NULL, 0);
  477. if (numargs < 2) {
  478. printf("ERROR: too few arguments\n");
  479. } else {
  480. if ((addr < 0) || (addr > MAX_PRU_MEM - 1)) {
  481. printf("ERROR: arguments out of range.\n");
  482. } else {
  483. if (!strcmp(cmd, "WRD")) {
  484. offset = pru_data_base[pru_num];
  485. } else if (!strcmp(cmd, "WRI")) {
  486. offset = pru_inst_base[pru_num];
  487. } else {
  488. offset = 0;
  489. }
  490. printf("Write to absolute address 0x%04x\n", offset+addr);
  491. for (i=1; i<numargs; i++) pru[offset+addr+i-1] = (unsigned int) (strtoll(&cmdargs[argptrs[i]], NULL, 0) & 0xFFFFFFFF);
  492. }
  493. }
  494. }
  495. else if (!strcmp(cmd, "Q")) { // dummy so it's a valid command
  496. }
  497. else if (!strcmp(cmd, "")) { // repeat display command option
  498. switch(last_cmd) {
  499. case LAST_CMD_D:
  500. case LAST_CMD_DD:
  501. case LAST_CMD_DI:
  502. printf ("Absolute addr = 0x%04x, offset = 0x%04x, Len = %u\n", last_addr + last_offset, last_addr, last_len);
  503. cmd_d(last_offset, last_addr, last_len);
  504. last_addr += last_len;
  505. break;
  506. case LAST_CMD_SS:
  507. cmd_single_step();
  508. break;
  509. default:
  510. break;
  511. }
  512. }
  513. else {
  514. printf("Invalid command.\n\n");
  515. }
  516. } while (strcmp(cmd, "Q"));
  517. printf("\nGoodbye.\n\n");
  518. // restore terminal IO settings
  519. ioctl(0,TCSETS,&oldT);
  520. return 0;
  521. }