From c7d14532b034286e990bc28c994fa20b23aca95a Mon Sep 17 00:00:00 2001 From: Hugo Villeneuve Date: Sun, 26 Jan 2014 19:59:34 -0500 Subject: [PATCH] Convert CLI version input parsing to Lex/Yacc Some error checking is still missing, but all commands seem to be working correctly. Update CLI help menu. --- Makefile.am | 3 +- configure.ac | 4 + src/cli/Makefile.am | 14 +- src/cli/emuconsole.c | 493 ++----------------------------------------- src/cli/menu.c | 228 ++++++++++++++++++++ src/cli/menu.h | 52 +++++ src/cli/parser.y | 257 ++++++++++++++++++++++ src/cli/scanner.l | 32 +++ src/common/cpu8051.c | 7 + src/common/cpu8051.h | 3 + src/common/memory.c | 23 +- src/common/memory.h | 2 +- 12 files changed, 614 insertions(+), 504 deletions(-) create mode 100644 src/cli/menu.c create mode 100644 src/cli/menu.h create mode 100644 src/cli/parser.y create mode 100644 src/cli/scanner.l diff --git a/Makefile.am b/Makefile.am index c15bf3a..12f0515 100644 --- a/Makefile.am +++ b/Makefile.am @@ -22,7 +22,8 @@ MAINTAINERCLEANFILES = Makefile.in aclocal.m4 configure config-h.in \ $(ac_aux_dir)/config.sub $(ac_aux_dir)/ltmain.sh \ $(ac_aux_dir)/compile \ $(ac_aux_dir)/test-driver \ - $(ac_aux_dir)/ar-lib + $(ac_aux_dir)/ar-lib \ + $(ac_aux_dir)/ylwrap changelog: @if test -d $(srcdir)/.git; then \ diff --git a/configure.ac b/configure.ac index 6bd5d18..1314fca 100644 --- a/configure.ac +++ b/configure.ac @@ -17,6 +17,10 @@ dnl Testing for libtool support. AC_PROG_RANLIB AM_PROG_AR +dnl Testing for Lex/Yacc +AC_PROG_LEX +AC_PROG_YACC + dnl Checking for typedefs, structures, and compiler characteristics. AC_C_CONST AC_TYPE_PID_T diff --git a/src/cli/Makefile.am b/src/cli/Makefile.am index 63eedab..3fba226 100644 --- a/src/cli/Makefile.am +++ b/src/cli/Makefile.am @@ -5,18 +5,26 @@ AM_CPPFLAGS = \ -I@top_srcdir@ \ -I@top_srcdir@/src/common +# Option -d: produce header file parser.h +AM_YFLAGS = -d + LDADD = \ $(top_builddir)/src/common/libemu8051.a bin_PROGRAMS = emu8051-cli emu8051_cli_SOURCES = \ + parser.y scanner.l \ emuconsole.c \ + menu.c menu.h \ keyboard.c keyboard.h -# we want these in the dist tarball -EXTRA_DIST = +# We want these in the dist tarball +EXTRA_DIST = scanner.h CLEANFILES = *~ -MAINTAINERCLEANFILES = Makefile.in +MAINTAINERCLEANFILES = \ + Makefile.in \ + scanner.h scanner.c \ + parser.h parser.c diff --git a/src/cli/emuconsole.c b/src/cli/emuconsole.c index e88ca0d..cbea820 100644 --- a/src/cli/emuconsole.c +++ b/src/cli/emuconsole.c @@ -19,492 +19,19 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ -#define _GNU_SOURCE /* For getline() */ -#include #include -#include -#include /* For isblank, toupper() */ -#include "config.h" +#include +#include "config.h" #include "common.h" #include "cpu8051.h" -#include "reg8051.h" -#include "sfr.h" -#include "memory.h" -#include "timers.h" #include "options.h" #include "hexfile.h" -#include "keyboard.h" +#include "menu.h" +#include "parser.h" extern struct options_t options; -/* Capitalize all letters in buffer */ -static void -Capitalize(char *buffer) -{ - size_t k; - - for (k = 0; k < strlen(buffer); k++) - buffer[k] = toupper(buffer[k]); -} - -/* Remove leading spaces from string in buffer */ -static void -RemoveSpaces(char *buffer) -{ - size_t k = 0; - - while ((k < strlen(buffer)) && isblank(buffer[k])) - k++; - - if (k != 0) - strcpy(buffer, &buffer[k]); -} - -/* Disassemble NumberInst instructions at Address */ -static void -DisasmN(unsigned int Address, int NumberInst) -{ - char TextTmp[255]; - int Row; - - for (Row = 0; Row < NumberInst ; Row++) { - Address += cpu8051_Disasm(Address, TextTmp); - printf("%s\n", TextTmp); - - if (Address > 0xFFFF) - return; - } -} - -/* Disassemble 16 instructions at Address */ -static void -Disasm(char *Address, char *NumberInst) -{ - unsigned int MemAddress, NbInst; - - if ((strlen(Address) == 0) || (STREQ(Address, "PC"))) - MemAddress = cpu8051.pc; - else - MemAddress = Ascii2Hex(Address, strlen(Address)); - - if (strlen(NumberInst) == 0) - NumberInst = "10"; - NbInst = Ascii2Hex(NumberInst, strlen(NumberInst)); - DisasmN(MemAddress, NbInst); -} - -/* Set NewValue to Register */ -static void -SetRegister(char *Register, char *NewValue) -{ - if (STREQ(Register, "PC")) - cpu8051.pc = Ascii2Hex(NewValue, 4); - else if (STREQ(Register, "A")) - cpu8051_WriteD(_ACC_, Ascii2Hex(NewValue, 2)); - else if (STREQ(Register, "B")) - cpu8051_WriteD(_B_, Ascii2Hex(NewValue, 2)); - else if (STREQ(Register, "SP")) - cpu8051_WriteD(_SP_, Ascii2Hex(NewValue, 2)); - else { - printf("\nInvalid register name!\n"); - printf("Valid registers are A, B, PC and SP.\n"); - } -} - -/* Show CPU registers, one per line */ -static void -console_dump_sfr_registers_detailed(void) -{ - int k; - - for (k = 0; k < SFR_REGS; k++) { - struct regwin_infos_t *regwin_infos; - int val; - - regwin_infos = sfr_get_infos_from_row(k); - - printf("%s = ", regwin_infos->name); - - val = regwin_read(k); - if (regwin_infos->w == 2) - printf("$%02X", val); - else if (regwin_infos->w == 4) - printf("$%04X", val); - - printf("\n"); - } -} - -/* Show CPU registers, compact format */ -static void -console_dump_sfr_registers_compact(void) -{ - unsigned char PSW = cpu8051_ReadD(_PSW_); - int BankSelect = (PSW & 0x18); - - printf("---------------------------------------------------------------" - "-------\n"); - printf("| PC | SP | DPTR | ACC | B | PSW: CY AC F0 RS1 RS0 OV" - " - P |\n"); - printf("| %.4X | %.2X | %.4X | %.2X | %.2X |", cpu8051.pc, - cpu8051_ReadD(_SP_), - memory_sfr_read_dptr(), - cpu8051_ReadD(_ACC_), cpu8051_ReadD(_B_)); - printf(" %d %d %d %d %d %d %d %d |", - (PSW >> 7) & 1, (PSW >> 6) & 1, (PSW >> 5) & 1, (PSW >> 4) & 1, - (PSW >> 3) & 1, (PSW >> 2) & 1, (PSW >> 1) & 1, PSW & 1); - printf("\n"); - printf("---------------------------------------------------------------" - "-------\n"); - - printf("| TCON | TMOD | IE | IP | R0 | R1 | R2 | R3 | R4 | R5 | R6 | R7" - " | |\n"); - printf("| %.2X | %.2X | %.2X | %.2X ", cpu8051_ReadD(_TCON_), - cpu8051_ReadD(_TMOD_), cpu8051_ReadD(_IE_), cpu8051_ReadD(_IP_)); - printf("| %.2X | %.2X | %.2X | %.2X ", - cpu8051_ReadD(BankSelect + _R0_), - cpu8051_ReadD(BankSelect + _R1_), - cpu8051_ReadD(BankSelect + _R2_), - cpu8051_ReadD(BankSelect + _R3_)); - printf("| %.2X | %.2X | %.2X | %.2X ", - cpu8051_ReadD(BankSelect + _R4_), - cpu8051_ReadD(BankSelect + _R5_), - cpu8051_ReadD(BankSelect + _R6_), - cpu8051_ReadD(BankSelect + _R7_)); - printf("| |\n"); - printf("---------------------------------------------------------------" - "-------\n"); - - printf("| General-purpose Timer: %08d |\n", gp_timer_read()); - printf("-----------------------------------\n"); -} - -/* Show CPU registers */ -static void -console_show_registers(void) -{ - if (options.stop_address != 0) - console_dump_sfr_registers_detailed(); - else - console_dump_sfr_registers_compact(); -} - -/* CPU reset and Console UI update */ -static void -console_reset(void) -{ - log_info("Resetting..."); - cpu8051_Reset(); - log_info("Done"); -} - -/* CPU exec and Console UI update */ -static void -console_exec(char *NumberInst) -{ - int NbInst = -1; /* -1 is infinity */ - - if (NumberInst) - if (strlen(NumberInst) != 0) - NbInst = Ascii2Hex(NumberInst, strlen(NumberInst)); - - InitUnixKB(); - - log_info("Program executing..."); - - cpu8051_run(NbInst, kbhit); - - if (kbhit()) { - (void) getch(); /* Flush key */ - log_info("Caught break signal!"); - } - - ResetUnixKB(); - console_show_registers(); - DisasmN(cpu8051.pc, 1); -} - -/* CPU trace and Console UI update */ -static void -console_trace() -{ - cpu8051_Exec(); - console_show_registers(); - DisasmN(cpu8051.pc, 1); -} - -/* EmuConsole main loop */ -static void -console_main(void) -{ - unsigned int Index; - char *line = NULL; - int QuitRequest = 0; - char prompt[] = "-> "; - - char *Title[] = { " *******************", - " * 8051 Emulator *", - " *******************", - "", 0 }; - - char *Menu[] = { - " Available commands, [ ] = options", - "", - " Set Breakpoint.............. SB [address]", - " Remove Breakpoint........... RB [address]", - " Display Breakpoint(s)....... DB", - " Dump External Data Memory... DE [address] [size]", - " Dump Internal Data Memory... DI [address] [size]", - " Dump Program Memory......... DP [address] [size]", - " Display Registers content... DR", - " Execute (Run)............... EM [number of instructions]", - " Help........................ H or ?", - " Modify External Data Memory. ME address value", - " Modify Internal Data Memory. MI address value", - " Modify Program Memory....... MP address value", - " Modify Register............. MR register value", - " Quit Emulator............... Q", - " Trace (step)................ T", - " Unassemble.................. U [address]" - " [number of instructions]", - " Reset processor............. Z", - " Reset general-purpose timer. ZT", 0 }; - - console_reset(); - - if (options.stop_address != 0) { - /* Automatically run program and stop at specified address. */ - console_exec(NULL); - QuitRequest = 1; - } else { - Index = 0; - while (Title[Index] != 0) - printf("%s\n", Title[Index++]); - - Index = 0; - while (Menu[Index] != 0) - printf("%s\n", Menu[Index++]); - - console_show_registers(); - } - - while (!QuitRequest) { - int slen; - size_t len = 0; - int rc; - char Command[256]; - char Args[256]; - char Parameter1[256]; - char Parameter2[256]; - - Parameter1[0] = '\0'; - Parameter2[0] = '\0'; - - printf("%s", prompt); - rc = getline(&line, &len, stdin); - if (rc < 0) - goto syntax_error; - - Capitalize(line); - RemoveSpaces(line); - - /* Strip trailing newline */ - slen = strlen(line); - if (line[slen - 1] == '\n') - line[slen - 1] = '\0'; - - /* Find command-arguments delimiter */ - for (Index = 0; Index < strlen(line); Index++) { - if (isblank(line[Index])) - break; - } - - if (strlen(line) == 0) { - /* Empty line, this is not an error. */ - continue; - } - - /* Keep only the Command part from the input line */ - memcpy(Command, &line[0], Index); - Command[Index] = '\0'; - - /* Keep only the arguments part from the input line */ - if (Index < strlen(line)) { - slen = strlen(line) - Index; - memcpy(Args, &line[Index + 1], slen); - } else { - slen = 0; - } - Args[slen] = '\0'; - RemoveSpaces(Args); - - /* Find multi-arguments delimiter */ - for (Index = 0; Index < strlen(Args); Index++) { - if (isblank(Args[Index])) - break; - } - - memcpy(Parameter1, &Args[0], Index); - Parameter1[Index] = '\0'; - - if (Index < strlen(Args)) { - slen = strlen(Args) - Index; - memcpy(Parameter2, &Args[Index + 1], slen); - } else { - slen = 0; - } - Parameter2[slen] = '\0'; - RemoveSpaces(Parameter2); - - if (strlen(Command) == 0) { - goto syntax_error; - continue; - } - - if ((strlen(Parameter1) > 4) || (strlen(Parameter2) > 4)) { - printf("Invalid Parameter Format!\n"); - continue; - } - - switch (Command[0]) { - case 'D': - if (STREQ(Command, "DB") && - (strlen(Parameter1) == 0)) - ShowBreakpoints(); - else if (STREQ(Command, "DE")) - DumpMem(Parameter1, Parameter2, EXT_MEM_ID); - else if (STREQ(Command, "DI")) - DumpMem(Parameter1, Parameter2, INT_MEM_ID); - else if (STREQ(Command, "DP")) { - if ((strlen(Parameter1) == 0)) - strcpy(Parameter1, "PC"); - DumpMem(Parameter1, Parameter2, PGM_MEM_ID); - } else if (STREQ(Command, "DR") && - (strlen(Parameter1) == 0)) - console_show_registers(); - else - goto syntax_error; - break; - case 'E': - if (STREQ(Command, "EM") && - (strlen(Parameter1) == 0)) - console_exec(NULL); - else if (STREQ(Command, "EM") && - (strlen(Parameter1) != 0)) - console_exec(Parameter1); - else - goto syntax_error; - break; - case 'H': - case '?': - if ((STREQ(Command, "H") || STREQ(Command, "?")) && - (strlen(Parameter1) == 0) && - (strlen(Parameter2) == 0)) { - Index = 0; - while (Menu[Index] != 0) - printf("%s\n", Menu[Index++]); - } else - goto syntax_error; - break; - case 'M': - if ((strlen(Parameter1) == 0) || - (strlen(Parameter2) == 0)) - printf("Missing Parameter!\n"); - else if (STREQ(Command, "ME")) { - unsigned int adresse = Ascii2Hex(Parameter1, 4); - unsigned char valeur = Ascii2Hex(Parameter2, 2); - memory_write8(EXT_MEM_ID, adresse, valeur); - } else if (STREQ(Command, "MI")) { - unsigned int adresse = Ascii2Hex(Parameter1, 2); - unsigned char valeur = Ascii2Hex(Parameter2, 2); - memory_write8(INT_MEM_ID, adresse, valeur); - } else if (STREQ(Command, "MP")) { - unsigned int adresse = Ascii2Hex(Parameter1, 4); - unsigned char valeur = Ascii2Hex(Parameter2, 2); - memory_write8(PGM_MEM_ID, adresse, valeur); - } else if (STREQ(Command, "MR")) - SetRegister(Parameter1, Parameter2); - else - goto syntax_error; - break; - case 'Q': - if (STREQ(Command, "Q") && (strlen(Parameter1) == 0) && - (strlen(Parameter2) == 0)) - QuitRequest = 1; - else - goto syntax_error; - break; - case 'R': - if (strlen(Parameter2) != 0) - goto TooMuchParameters; - if (STREQ(Command, "RB")) { - if (strlen(Parameter1) == 0) - ClearBreakpoint(cpu8051.pc); - else - ClearBreakpoint( - Ascii2Hex(Parameter1, 4)); - } else - goto syntax_error; - break; - case 'S': - if (strlen(Parameter2) != 0) - goto TooMuchParameters; - - if (STREQ(Command, "SB")) { - if (strlen(Parameter1) == 0) - SetBreakpoint(cpu8051.pc); - else - SetBreakpoint(Ascii2Hex(Parameter1, 4)); - } else - goto syntax_error; - break; - case 'T': - if ((strlen(Parameter1) != 0) || - (strlen(Parameter2) != 0)) - printf("Wrong Number of Parameters!\n"); - - if (STREQ(Command, "T")) - console_trace(); - else - goto syntax_error; - break; - case 'U': - if (STREQ(Command, "U")) - Disasm(Parameter1, Parameter2); - else - goto syntax_error; - break; - case 'Z': - if (STREQ(Command, "Z") && (strlen(Parameter1) == 0) && - (strlen(Parameter2) == 0)) - cpu8051_Reset(); - else if (STREQ(Command, "ZT") && - (strlen(Parameter1) == 0) && - (strlen(Parameter2) == 0)) - gp_timer_reset(); - else - goto syntax_error; - break; - case '\n': - break; - default: - goto syntax_error; - } - continue; - -syntax_error: - printf("Syntax Error!\n"); - continue; -TooMuchParameters: - printf("Wrong Number of Parameters!\n"); - continue; - } - - if (line) - free(line); -} - int main(int argc, char **argv) { @@ -520,9 +47,17 @@ main(int argc, char **argv) exit(1); } - console_main(); + console_reset(); - log_info("Terminate"); + if (options.stop_address != 0) { + /* Automatically run program and stop at specified address. */ + console_exec(-1); + } else { + menu_display_usage(); + console_show_registers(); + menu_prompt(); + yyparse(); + } return 0; } diff --git a/src/cli/menu.c b/src/cli/menu.c new file mode 100644 index 0000000..478fe2b --- /dev/null +++ b/src/cli/menu.c @@ -0,0 +1,228 @@ +/* + * menu.c + * + * Copyright (C) 1999 Jonathan St-André + * Copyright (C) 1999 Hugo Villeneuve + * + * 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 Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include + +#include "common.h" +#include "cpu8051.h" +#include "reg8051.h" +#include "sfr.h" +#include "memory.h" +#include "timers.h" +#include "options.h" +#include "hexfile.h" +#include "keyboard.h" +#include "menu.h" + +extern struct options_t options; + +void +menu_prompt(void) +{ + printf("-> "); +} + +void +menu_display_usage(void) +{ + printf(" *******************\n" + " * 8051 Emulator *\n" + " *******************\n" + "\n" + " Available commands, [ ] = options\n" + "\n" + " Set Breakpoint.............. SB [address]\n" + " Remove Breakpoint........... RB [address]\n" + " address = all:" + " clear all breakpoints\n" + " Display Breakpoint(s)....... DB\n" + " Dump External Data Memory... DE [address] [size]\n" + " Dump Internal Data Memory... DI [address] [size]\n" + " Dump Program Memory......... DP [address] [size]\n" + " Display Registers........... DR\n" + " Help........................ H or ?\n" + " Modify External Data Memory. ME address value\n" + " Modify Internal Data Memory. MI address value\n" + " Modify Program Memory....... MP address value\n" + " Modify Register............. MR register value\n" + " Quit........................ Q\n" + " Run......................... R [number of instructions]\n" + " Step........................ S\n" + " Unassemble.................. U [address]" + " [number of instructions]\n" + " Reset processor............. Z\n" + " Reset general-purpose timer. ZT\n"); +} + +/* Disassemble NumberInst instructions at Address */ +void +DisasmN(unsigned int Address, int NumberInst) +{ + char TextTmp[255]; + int Row; + + for (Row = 0; Row < NumberInst ; Row++) { + Address += cpu8051_Disasm(Address, TextTmp); + printf("%s\n", TextTmp); + + if (Address > 0xFFFF) + return; + } +} + +/* Set NewValue to Register */ +void +SetRegister(char *Register, int NewValue) +{ + if (STREQ(Register, "PC")) + cpu8051.pc = NewValue; + else if (STREQ(Register, "A")) + cpu8051_WriteD(_ACC_, NewValue); + else if (STREQ(Register, "B")) + cpu8051_WriteD(_B_, NewValue); + else if (STREQ(Register, "SP")) + cpu8051_WriteD(_SP_, NewValue); + else { + printf("\nInvalid register name!\n"); + printf("Valid registers are A, B, PC and SP.\n"); + } +} + +/* CPU reset and Console UI update */ +void +console_reset(void) +{ + log_info("Resetting..."); + cpu8051_Reset(); + log_info("Done"); +} + +/* + * CPU exec and Console UI update + * NbInst = -1: run to infinity + */ +void +console_exec(int NbInst) +{ + InitUnixKB(); + + log_info("Program executing..."); + + cpu8051_run(NbInst, kbhit); + + if (kbhit()) { + (void) getch(); /* Flush key */ + log_info("Caught break signal!"); + } + + ResetUnixKB(); + console_show_registers(); + DisasmN(cpu8051.pc, 1); +} + +/* CPU trace and Console UI update */ +void +console_trace(void) +{ + cpu8051_Exec(); + console_show_registers(); + DisasmN(cpu8051.pc, 1); +} + +/* Show CPU registers, one per line */ +static void +console_dump_sfr_registers_detailed(void) +{ + int k; + + for (k = 0; k < SFR_REGS; k++) { + struct regwin_infos_t *regwin_infos; + int val; + + regwin_infos = sfr_get_infos_from_row(k); + + printf("%s = ", regwin_infos->name); + + val = regwin_read(k); + if (regwin_infos->w == 2) + printf("$%02X", val); + else if (regwin_infos->w == 4) + printf("$%04X", val); + + printf("\n"); + } +} + +/* Show CPU registers, compact format */ +static void +console_dump_sfr_registers_compact(void) +{ + unsigned char PSW = cpu8051_ReadD(_PSW_); + int BankSelect = (PSW & 0x18); + + printf("---------------------------------------------------------------" + "-------\n"); + printf("| PC | SP | DPTR | ACC | B | PSW: CY AC F0 RS1 RS0 OV" + " - P |\n"); + printf("| %.4X | %.2X | %.4X | %.2X | %.2X |", cpu8051.pc, + cpu8051_ReadD(_SP_), + memory_sfr_read_dptr(), + cpu8051_ReadD(_ACC_), cpu8051_ReadD(_B_)); + printf(" %d %d %d %d %d %d %d %d |", + (PSW >> 7) & 1, (PSW >> 6) & 1, (PSW >> 5) & 1, (PSW >> 4) & 1, + (PSW >> 3) & 1, (PSW >> 2) & 1, (PSW >> 1) & 1, PSW & 1); + printf("\n"); + printf("---------------------------------------------------------------" + "-------\n"); + + printf("| TCON | TMOD | IE | IP | R0 | R1 | R2 | R3 | R4 | R5 | R6 | R7" + " | |\n"); + printf("| %.2X | %.2X | %.2X | %.2X ", cpu8051_ReadD(_TCON_), + cpu8051_ReadD(_TMOD_), cpu8051_ReadD(_IE_), cpu8051_ReadD(_IP_)); + printf("| %.2X | %.2X | %.2X | %.2X ", + cpu8051_ReadD(BankSelect + _R0_), + cpu8051_ReadD(BankSelect + _R1_), + cpu8051_ReadD(BankSelect + _R2_), + cpu8051_ReadD(BankSelect + _R3_)); + printf("| %.2X | %.2X | %.2X | %.2X ", + cpu8051_ReadD(BankSelect + _R4_), + cpu8051_ReadD(BankSelect + _R5_), + cpu8051_ReadD(BankSelect + _R6_), + cpu8051_ReadD(BankSelect + _R7_)); + printf("| |\n"); + printf("---------------------------------------------------------------" + "-------\n"); + + printf("| General-purpose Timer: %08d |\n", gp_timer_read()); + printf("-----------------------------------\n"); +} + +/* Show CPU registers */ +void +console_show_registers(void) +{ + if (options.stop_address != 0) + console_dump_sfr_registers_detailed(); + else + console_dump_sfr_registers_compact(); +} diff --git a/src/cli/menu.h b/src/cli/menu.h new file mode 100644 index 0000000..9dd2919 --- /dev/null +++ b/src/cli/menu.h @@ -0,0 +1,52 @@ +/* + * menu.h + * + * Copyright (C) 1999 Jonathan St-André + * Copyright (C) 1999 Hugo Villeneuve + * + * 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 Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _MENU_H_ +#define _MENU_H_ + +int +yyparse(void); + +void +menu_prompt(void); + +void +menu_display_usage(void); + +void +console_show_registers(void); + +void +SetRegister(char *Register, int NewValue); + +void +console_reset(void); + +void +console_exec(int NbInst); + +void +console_trace(void); + +void +DisasmN(unsigned int Address, int NumberInst); + +#endif /* _MENU_H_ */ diff --git a/src/cli/parser.y b/src/cli/parser.y new file mode 100644 index 0000000..00338b3 --- /dev/null +++ b/src/cli/parser.y @@ -0,0 +1,257 @@ +%{ +#include +#include +#include +#include + +#include "config.h" +#include "log.h" +#include "menu.h" +#include "memory.h" +#include "timers.h" +#include "cpu8051.h" + +/* int yydebug = 1; */ + +/* To get rid of compiler warning. */ +int yylex(); + +int yyerror(const char *str) +{ + fprintf(stderr,"error: %s\n", str); + return 0; +} + +%} + +%token NUMBER TOK_ENTER TOK_ALL +%token TOK_SB TOK_RB TOK_DB +%token TOK_DE TOK_DI TOK_DP TOK_DR +%token TOK_PC +%token TOK_HELP +%token TOK_RUN +%token TOK_RST TOK_RST_TIMER +%token TOK_STEP +%token TOK_UNASM +%token TOK_MOD_EXT TOK_MOD_INT TOK_MOD_PROG TOK_MOD_REG +%token TOK_QUIT + +%% + +start : start command { menu_prompt(); } + | error TOK_ENTER { + /* In case of error, discard entire line */ + yyerrok; + menu_prompt(); + } + | start TOK_ENTER { menu_prompt(); } + | + ; + +command: + pc_set + | + breakpoint_clr + | + breakpoint_set + | + breakpoint_display + | + dump_ext_mem + | + dump_int_mem + | + dump_prog_mem + | + display_regs + | + help + | + modify + | + quit + | + reset + | + run + | + step + | + unasm + ; + +breakpoint_clr: + TOK_RB NUMBER TOK_ENTER + { + log_debug(" Remove breakpoint at $%04X", $2); + ClearBreakpoint($2); + } + | + TOK_RB TOK_ENTER + { + log_debug(" Remove breakpoint at PC"); + ClearBreakpoint(cpu8051.pc); + } + | + TOK_RB TOK_ALL TOK_ENTER + { + log_debug(" Remove all breakpoints"); + ClearAllBreakpoints(); + } + ; + +breakpoint_set: + TOK_SB TOK_ENTER + { + log_debug(" Set breakpoint at current PC"); + SetBreakpoint(cpu8051.pc); + } + | + + TOK_SB NUMBER TOK_ENTER + { + log_debug(" Set breakpoint at $%04X", $2); + SetBreakpoint($2); + } + ; + +breakpoint_display: + TOK_DB TOK_ENTER + { + log_debug(" Display breakpoints"); + ShowBreakpoints(); + } + ; + +dump_ext_mem: + TOK_DE NUMBER NUMBER TOK_ENTER + { + log_debug(" Dump External Data Memory at $%04X, len %d", $2, $3); + DumpMem($2, $3, EXT_MEM_ID); + } + ; + +dump_int_mem: + TOK_DI NUMBER NUMBER TOK_ENTER + { + log_debug(" Dump Internal Data Memory at $%04X, len %d", $2, $3); + DumpMem($2, $3, INT_MEM_ID); + } + ; + +dump_prog_mem: + TOK_DP NUMBER NUMBER TOK_ENTER + { + log_debug(" Dump Program Memory at $%04X, len %d", $2, $3); + DumpMem($2, $3, PGM_MEM_ID); + } + ; + +display_regs: + TOK_DR TOK_ENTER + { + log_debug(" Display Registers"); + console_show_registers(); + } + ; + +modify: + TOK_MOD_EXT NUMBER NUMBER TOK_ENTER + { + log_debug(" Modify external memory"); + memory_write8(EXT_MEM_ID, $2, $3); + } + | + TOK_MOD_INT NUMBER NUMBER TOK_ENTER + { + log_debug(" Modify internal memory"); + memory_write8(INT_MEM_ID, $2, $3); + } + | + TOK_MOD_PROG NUMBER NUMBER TOK_ENTER + { + log_debug(" Modify program memory"); + memory_write8(PGM_MEM_ID, $2, $3); + } + | + TOK_MOD_REG "pc" NUMBER TOK_ENTER + { + log_debug(" Modify register"); + SetRegister("PC", $2); + } + ; + +quit: + TOK_QUIT TOK_ENTER + { + printf(" Quit"); + YYACCEPT; + } + ; + +run: + TOK_RUN TOK_ENTER + { + log_debug(" Run"); + console_exec(-1); + } + | + TOK_RUN NUMBER TOK_ENTER + { + log_debug(" Run %d instructions", $2); + console_exec($2); + } + ; + +pc_set: + TOK_PC NUMBER TOK_ENTER + { + cpu8051.pc = $2; + } + ; + +help: + TOK_HELP TOK_ENTER + { + menu_display_usage(); + } + ; + +reset: + TOK_RST TOK_ENTER + { + cpu8051_Reset(); + } + | + TOK_RST_TIMER TOK_ENTER + { + gp_timer_reset(); + } + ; + +step: + TOK_STEP TOK_ENTER + { + console_trace(); + } + ; + +unasm: + TOK_UNASM NUMBER NUMBER TOK_ENTER + { + DisasmN($2, $3); + } + | + TOK_UNASM NUMBER TOK_ENTER + { + DisasmN(cpu8051.pc, $2); + } + ; + | + TOK_UNASM TOK_ENTER + { + DisasmN(cpu8051.pc, 16); + } + ; + + diff --git a/src/cli/scanner.l b/src/cli/scanner.l new file mode 100644 index 0000000..757376e --- /dev/null +++ b/src/cli/scanner.l @@ -0,0 +1,32 @@ +%option noyywrap +%option noinput +%option nounput +%{ + #include "parser.h" +%} +%% +[0-9]+ { yylval = atoi(yytext); return NUMBER;} +[h?] return TOK_HELP; +sb return TOK_SB; +rb return TOK_RB; +db return TOK_DB; +de return TOK_DE; +di return TOK_DI; +dp return TOK_DP; +dr return TOK_DR; +r return TOK_RUN; +pc return TOK_PC; +all return TOK_ALL; +me return TOK_MOD_EXT; +mi return TOK_MOD_INT; +mp return TOK_MOD_PROG; +mr return TOK_MOD_REG; +q return TOK_QUIT; +s return TOK_STEP; +u return TOK_UNASM; +z return TOK_RST; +zt return TOK_RST_TIMER; +[\n] return TOK_ENTER; +[ \t]+ { /* ignore whitespace */ } +. { return yytext[0];} +%% diff --git a/src/common/cpu8051.c b/src/common/cpu8051.c index 107f2ef..fb93126 100644 --- a/src/common/cpu8051.c +++ b/src/common/cpu8051.c @@ -99,6 +99,13 @@ ClearBreakpoint(unsigned int address) } } +/* Clear all breakpoints */ +void +ClearAllBreakpoints(void) +{ + cpu8051.bp_count = 0; +} + /* Toggle the breakpoint at Address. */ void ToggleBreakpoint(unsigned int address) diff --git a/src/common/cpu8051.h b/src/common/cpu8051.h index 49494f0..430e00e 100644 --- a/src/common/cpu8051.h +++ b/src/common/cpu8051.h @@ -71,6 +71,9 @@ SetBreakpoint(unsigned int Address); void ClearBreakpoint(unsigned int Address); +void +ClearAllBreakpoints(void); + void ToggleBreakpoint(unsigned int Address); diff --git a/src/common/memory.c b/src/common/memory.c index 2e37210..d01153a 100644 --- a/src/common/memory.c +++ b/src/common/memory.c @@ -205,34 +205,17 @@ pgm_read_addr16(uint16_t base) /* Dump memory */ void -DumpMem(char *Address, char *Asize, int memory_id) +DumpMem(unsigned int address, int size, int memory_id) { - unsigned int MemAddress; - int size; int Offset, Column; - if (strlen(Address) != 0) { - if (STREQ(Address, "PC")) - MemAddress = cpu8051.pc; - else - MemAddress = Ascii2Hex(Address, strlen(Address)); - } else { - MemAddress = 0; - } - - if (strlen(Asize) != 0) { - size = Ascii2Hex(Asize, strlen(Asize)); - } else { - size = 256; /* Default size if not specified. */ - } - for (Offset = 0; Offset < size; Offset += 16) { unsigned char data[16]; - printf("%.4X ", MemAddress + Offset); + printf("%.4X ", address + Offset); for (Column = 0; Column < 16; Column++) { - data[Column] = memory_read8(memory_id, MemAddress + + data[Column] = memory_read8(memory_id, address + Offset + Column); printf(" %.2X", (int) data[Column]); } diff --git a/src/common/memory.h b/src/common/memory.h index 7beb0e8..cbb9eb8 100644 --- a/src/common/memory.h +++ b/src/common/memory.h @@ -86,6 +86,6 @@ uint16_t pgm_read_addr16(uint16_t base); void -DumpMem(char *Address, char *Asize, int memory_id); +DumpMem(unsigned int address, int size, int memory_id); #endif /* MEMORY_H */ -- 2.20.1