Convert CLI version input parsing to Lex/Yacc
authorHugo Villeneuve <hugo@hugovil.com>
Mon, 27 Jan 2014 00:59:34 +0000 (19:59 -0500)
committerHugo Villeneuve <hugo@hugovil.com>
Thu, 13 Feb 2014 05:25:17 +0000 (00:25 -0500)
Some error checking is still missing, but all commands seem to be
working correctly.

Update CLI help menu.

12 files changed:
Makefile.am
configure.ac
src/cli/Makefile.am
src/cli/emuconsole.c
src/cli/menu.c [new file with mode: 0644]
src/cli/menu.h [new file with mode: 0644]
src/cli/parser.y [new file with mode: 0644]
src/cli/scanner.l [new file with mode: 0644]
src/common/cpu8051.c
src/common/cpu8051.h
src/common/memory.c
src/common/memory.h

index c15bf3a..12f0515 100644 (file)
@@ -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          \
index 6bd5d18..1314fca 100644 (file)
@@ -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
index 63eedab..3fba226 100644 (file)
@@ -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
index e88ca0d..cbea820 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
-#define _GNU_SOURCE /* For getline() */
-#include <stdio.h>
 #include <stdbool.h>
-#include <string.h>
-#include <ctype.h> /* For isblank, toupper() */
-#include "config.h"
+#include <stdio.h>
 
+#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 (file)
index 0000000..478fe2b
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * menu.c
+ *
+ * Copyright (C) 1999 Jonathan St-AndrĂ©
+ * Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
+ *
+ * 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 <stdbool.h>
+#include <stdio.h>
+#include <string.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"
+
+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 (file)
index 0000000..9dd2919
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * menu.h
+ *
+ * Copyright (C) 1999 Jonathan St-AndrĂ©
+ * Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
+ *
+ * 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 (file)
index 0000000..00338b3
--- /dev/null
@@ -0,0 +1,257 @@
+%{
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#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 (file)
index 0000000..757376e
--- /dev/null
@@ -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];}
+%%
index 107f2ef..fb93126 100644 (file)
@@ -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)
index 49494f0..430e00e 100644 (file)
@@ -71,6 +71,9 @@ SetBreakpoint(unsigned int Address);
 void
 ClearBreakpoint(unsigned int Address);
 
+void
+ClearAllBreakpoints(void);
+
 void
 ToggleBreakpoint(unsigned int Address);
 
index 2e37210..d01153a 100644 (file)
@@ -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]);
                }
index 7beb0e8..cbb9eb8 100644 (file)
@@ -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 */