📄 rwmem.c
字号:
/*************************************************************************** * rwmem.c ***************************************************************************//*************************************************************************** * Included Files ***************************************************************************/#include "util.h"/*************************************************************************** * Definitions ***************************************************************************/#define MAX_LINE 128/*************************************************************************** * Private Variables ***************************************************************************//* These describe one input line */static char line[MAX_LINE];/* These describe one command parsed from the input line */static int cmd_code;static unsigned long cmd_address;static unsigned long cmd_value;static unsigned long cmd_write;static unsigned long cmd_count;/*************************************************************************** * In-line Functions/Macros ***************************************************************************//* These macros/inline functions allow us to precisely control how data * is accessed. For the case of arm, for example, certain compiler options * can make 16-bit short data accessed as a pair of bytes. Very bad * if we are trying to read/write hardware registers! */#define inb(a) *((unsigned char *)(a))#define outb(v,a) (*((unsigned char *)(a))=(v))#if 0# define inw(a) *((unsigned short *)(a))# define outw(v,a) (*((unsigned short *)(a))=(v))#elsestatic inline unsigned short inw(unsigned int addr){ unsigned short retval; __asm__("\tldrh %0, [%1]\n\t" : "=r"(retval) : "r"(addr)); return retval;}static inline void outw(unsigned short val, unsigned int addr){ __asm__("\tstrh %0, [%1]\n\t": : "r"(val), "r"(addr));}#endif#define inl(a) *((unsigned long *)(a))#define outl(v,a) (*((unsigned long *)(a))=(v))/*************************************************************************** * Private Functions ***************************************************************************//*************************************************************************** * show_usage ***************************************************************************/static void show_usage(void){ util_printf("< {b,w,l} <hex-address>[=<hex-value>][ <hex-byte-count>]\n" "< to read/write bytes(b), short integers(w), or longs(l)\n"); util_printf("< {h,?} to print this usage information\n"); util_printf("< q to quit\n");}/*************************************************************************** * skip_spaces ***************************************************************************/static void skip_spaces(char **string){ char *ptr = *string; while(*ptr == ' ') ptr++; *string = ptr;}/*************************************************************************** * parse_decimal ***************************************************************************/static int parse_decimal(char **string, long *value){ char *ptr = *string; long accumulator = 0; int c; /* Loop until an non-numeric character is encountered. */ for(;;) { /* Get the next character from the line. Note that "ptr" is not * incremented. This is because we want "string" to point to * the first non-numeric after the number on return. */ c = *ptr; /* Is it a numeric? */ if ((c >= '0') && (c <= '9')) { /* Add the new digit to the accumulator */ accumulator *= 10; accumulator += (c - '0'); /* Now we can increment the pointer to the next character */ ptr++; } else { /* No, we are done here */ break; } } /* Return the decimal value and the adjusted pointer. */ *string = ptr; *value = accumulator; /* Always return success. It is okay if no number is found in the * context in which this function is called. */ return 0;}/*************************************************************************** * parse_hex ***************************************************************************/static int parse_hex(char **string, long *value){ char *ptr = *string; long accumulator = 0; int nibbles = 0; int c; /* Loop until an non-hex character is encountered. */ for(;;) { /* Get the next character from the line. Note that "ptr" is not * incremented. This is because we want "string" to point to * the first non-numeric after the number on return. */ c = *ptr; /* Is it a numeric? */ if ((c >= '0') && (c <= '9')) { /* Add the nibble to the accumulator */ accumulator <<= 4; accumulator += (c - '0'); /* Count the number of nibbles we have encounter */ nibbles++; /* Now we can increment the pointer to the next character */ ptr++; } /* Is it a ascii A-F? */ else if ((c >= 'A') && (c <= 'F')) { /* Add the nibble to the accumulator */ accumulator <<= 4; accumulator += (c - 'A' + 10); /* Count the number of nibbles we have encounter */ nibbles++; /* Now we can increment the pointer to the next character */ ptr++; } /* Is it a ascii a-f? */ else if ((c >= 'a') && (c <= 'f')) { /* Add the nibble to the accumulator */ accumulator <<= 4; accumulator += (c - 'a' + 10); /* Count the number of nibbles we have encounter */ nibbles++; /* Now we can increment the pointer to the next character */ ptr++; } /* Somebody might want to put an "0x" in front. We won't complain * in this case (even though it is not necessary). This logic * will also accept crazy prefixes like: "x", "0x0x0x", "0000x", * "xxx". It is completely tolerant of "x"'s on the line until * a non-zero hex character is found. We could make this strict * by also insisting that (nibbles == 1). */ else if ((c == 'x') && (accumulator == 0)) { ptr++; } else { break; } } /* Return the hex value and the adjusted pointer. */ *string = ptr; *value = accumulator; /* In the context in which this function is called, it would be an * error if no hex number were found. */ if (nibbles) { return 0; } else { util_printf("< Missing hex constant\n"); return -1; }}/*************************************************************************** * parse_line ***************************************************************************/static int parse_line(void){ char *ptr = line; /* Initialize command variables */ cmd_code = 0; cmd_address = 0; cmd_value = 0; cmd_write = 0; cmd_count = 0; /* Make certain that the line is not empty. */ if (!*ptr) { util_printf("< No command supplied\n"); return -1; } /* Get the command */ skip_spaces(&ptr); cmd_code = *ptr++; /* Force the command to lower case */ if ((cmd_code >= 'A') && (cmd_code <= 'Z')) cmd_code += ('a' - 'A'); /* Make sure that the command is a single lower case letter */ if ((((cmd_code < 'a') || (cmd_code > 'z')) && (cmd_code != '?')) || ((*ptr != ' ') && (*ptr != '\0'))) { util_printf("< Command must be a single letter\n"); return -1; } /* And that that letter is our command set */ if (!util_strchr("bwlqh?", cmd_code)) { util_printf("< Unrecognized command\n"); return -1; } /* These commands have arguments */ if (util_strchr("bwl", cmd_code)) { /* Get the address */ skip_spaces(&ptr); if (parse_hex(&ptr, &cmd_address) != 0) { util_printf("< Could not parse required address\n"); return -1; } /* Check for an optional write value */ skip_spaces(&ptr); if (*ptr == '=') { cmd_write = 1; ptr++; /* Get the write value */ skip_spaces(&ptr); if (parse_hex(&ptr, &cmd_value) != 0) { util_printf("< Could not parse optional value\n"); return -1; } } /* Check for an optional count */ skip_spaces(&ptr); (void)parse_decimal(&ptr, &cmd_count); if (cmd_count) cmd_count--; } /* Make sure we are at the end of the line */ skip_spaces(&ptr); if (*ptr) { util_printf(" >Garbage at the end of line\n"); return -1; } return 0;}/*************************************************************************** * do_command * returns zero on okay * positive number if user wants to quit * negative number if error encountered ***************************************************************************/static int do_command(void){ int i; /* Process each command by its command letter */ switch (cmd_code) { /* We will be transferring bytes */ case 'b': /* Loop for the number of requested bytes (plus one) */ for (i = 0; i <= cmd_count; i++, cmd_address++) { /* Print the value at the address */ util_printf("< 0x%X = 0x%b", cmd_address, inb(cmd_address)); /* Are we supposed to write a value to this address? */ if (cmd_write) { /* Yes, was the supplied value within range? */ if (cmd_value > 0x000000ff) { util_printf("\n> Value to write is out of range\n"); return -1; } /* Write the value and re-read the address so that we * print its current value (not necessarily the value * written). */ outb((unsigned char)cmd_value, cmd_address); util_printf(" -> 0x%b", inb(cmd_address)); } /* Make sure we end it with a newline */ util_putchar('\n'); } break; /* We will be transferring "short" values */ case 'w': /* Loop for the number of requested bytes (plus one) */ for (i = 0; i <= cmd_count; i += 2, cmd_address += 2) { /* Print the value at the address */ util_printf("< 0x%X = 0x%x", cmd_address, inw(cmd_address)); /* Are we supposed to write a value to this address? */ if (cmd_write) { /* Yes, was the supplied value within range? */ if (cmd_value > 0x0000ffff) { util_printf("\n> Value to write is out of range\n"); return -1; } /* Write the value and re-read the address so that we * print its current value (not necessarily the value * written). */ outw((unsigned short)cmd_value, cmd_address); util_printf(" -> 0x%x", inw(cmd_address)); } /* Make sure we end it with a newline */ util_putchar('\n'); } break; /* We will be transferring "long" values */ case 'l': /* Loop for the number of requested bytes (plus one) */ for (i = 0; i <= cmd_count; i += 4, cmd_address += 4) { /* Print the value at the address */ util_printf("< 0x%X = 0x%X", cmd_address, inl(cmd_address)); /* Are we supposed to write a value to this address? */ if (cmd_write) { /* Write the value and re-read the address so that we * print its current value (not necessarily the value * written). */ outl(cmd_value, cmd_address); util_printf(" -> 0x%X", inl(cmd_address)); } /* Make sure we end it with a newline */ util_putchar('\n'); } break; case 'h': case '?': util_printf("< Usage:\n"); show_usage(); break; case 'q': return 1; default: util_printf("< Unrecognized command\n"); return -1; } return 0;}/*************************************************************************** * Public Functions ***************************************************************************//*************************************************************************** * main ***************************************************************************/void modify_memory(void){ int i; util_printf("< Usage:\n"); show_usage(); /* Loop until do_command processes a quit command. */ for(;;) { /* Show a prompt. Including <esc>[K VT100 command that erases to * the end of the line. */ util_printf("> \033[K"); /* Read the next input line. */ util_gets(line, MAX_LINE-1); if (line[0] != 0) { /* Parse the command from the input line */ if (!parse_line()) { /* Process the command */ i=do_command(); if (i<0) { util_printf("< Could not execute command\n"); show_usage(); } if (i>0) { return; } } else { util_printf("< Could not parse command line\n"); show_usage(); } } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -