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.
This commit is contained in:
Hugo Villeneuve 2014-01-26 19:59:34 -05:00
parent fd418e0f87
commit c7d14532b0
12 changed files with 614 additions and 504 deletions

View 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 \

View 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

View 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

View File

@ -19,492 +19,19 @@
* 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;
}

228
src/cli/menu.c Normal file
View File

@ -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();
}

52
src/cli/menu.h Normal file
View File

@ -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_ */

257
src/cli/parser.y Normal file
View File

@ -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);
}
;

32
src/cli/scanner.l Normal file
View File

@ -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];}
%%

View 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)

View File

@ -71,6 +71,9 @@ SetBreakpoint(unsigned int Address);
void
ClearBreakpoint(unsigned int Address);
void
ClearAllBreakpoints(void);
void
ToggleBreakpoint(unsigned int Address);

View 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]);
}

View 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 */