diff --git a/complx/AdvancedLoadDialog.cpp b/complx/AdvancedLoadDialog.cpp index 37c9a4d..2f3f1ae 100644 --- a/complx/AdvancedLoadDialog.cpp +++ b/complx/AdvancedLoadDialog.cpp @@ -7,6 +7,11 @@ extern lc3_state state; AdvancedLoadDialog::AdvancedLoadDialog(wxWindow* parent, const LoadingOptions& opts) : AdvancedLoadDialogDecl(parent) { assemblyFile->SetPath(opts.file); + replayString->SetValue(opts.replay_string); +#ifndef ENABLE_LC3_REPLAY + replayString->Enable(false); + replayString->SetValue(""); +#endif consoleInput->SetValue(opts.console_input); regInitializer->SetSelection(opts.registers == RANDOMIZE ? 0 : (opts.registers == ZEROED ? 1 : 2)); if (opts.registers != RANDOMIZE && opts.registers != ZEROED) @@ -34,6 +39,9 @@ LoadingOptions AdvancedLoadDialog::GetOptions() return options; options.file = file; +#ifdef ENABLE_LC3_REPLAY + options.replay_string = replayString->GetValue().ToStdString(); +#endif options.console_input = consoleInput->GetValue().ToStdString(); int ret = -1; int error; diff --git a/complx/CMakeLists.txt b/complx/CMakeLists.txt index d579ce3..e44ceef 100644 --- a/complx/CMakeLists.txt +++ b/complx/CMakeLists.txt @@ -47,6 +47,15 @@ add_executable( ${SRC_COMPLX} ) +if (ENABLE_REPLAY) + add_definitions(-DENABLE_LC3_REPLAY) + include_directories("../replay") + target_link_libraries( + complx + lc3_replay + ) +endif (ENABLE_REPLAY) + target_link_libraries( complx lc3 @@ -54,6 +63,8 @@ target_link_libraries( ${GLIB2_LIBRARIES} ) + + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/complx DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES ../doc/complx-tools.pdf DESTINATION share/doc/complx-tools) diff --git a/complx/ComplxFrame.cpp b/complx/ComplxFrame.cpp index b3db429..dfca300 100644 --- a/complx/ComplxFrame.cpp +++ b/complx/ComplxFrame.cpp @@ -33,6 +33,10 @@ #include "LC3RunThread.hpp" #include "version.h" +#ifdef ENABLE_LC3_REPLAY +#include +#endif + lc3_state state; extern ComplxFrame* complxframe; @@ -203,6 +207,8 @@ void ComplxFrame::OnAdvancedLoad(wxCommandEvent& event) } reload_options = options; DoLoadFile(reload_options); + if (!reload_options.replay_string.empty()) + DoSetupReplayString(reload_options.replay_string); } delete dialog; } @@ -1322,6 +1328,121 @@ void ComplxFrame::OnDestroyView(wxCloseEvent& event) frame->Destroy(); } +void ComplxFrame::OnSetupReplayString(wxCommandEvent& event) +{ +#ifdef ENABLE_LC3_REPLAY + if (Running()) + return; + + if (reload_options.file.empty()) + OnLoad(event); + + if (reload_options.file.empty()) + { + wxMessageBox("An assembly file must be loaded to perform this operation", "Error"); + return; + } + + std::string replay_str = DoAskForReplayString(); + + if (replay_str.empty()) + return; + + DoSetupReplayString(replay_str); +#else + wxMessageBox("Support for this menu function was not enabled.", "Error"); +#endif +} +void ComplxFrame::OnReloadReplayString(wxCommandEvent& event) +{ +#ifdef ENABLE_LC3_REPLAY + if (reload_options.replay_string.empty() || reload_options.file.empty()) + { + OnSetupReplayString(event); + return; + } + + DoSetupReplayString(reload_options.replay_string); +#else + wxMessageBox("Support for this menu function was not enabled.", "Error"); +#endif +} +void ComplxFrame::OnDescribeReplayString(wxCommandEvent& event) +{ +#ifdef ENABLE_LC3_REPLAY + std::string replay_str = reload_options.replay_string; + if (replay_str.empty()) + { + replay_str = DoAskForReplayString(); + + if (replay_str.empty()) + { + wxMessageBox("No replay string given.", "Error"); + return; + } + } + + try + { + std::string description = lc3_describe_replay(replay_str); + wxMessageBox(description); + } + catch (std::string err) + { + wxMessageBox(err.c_str(), "Error"); + return; + } + catch (const char* err) + { + wxMessageBox(err, "Error"); + return; + } +#else + wxMessageBox("Support for this menu function was not enabled.", "Error"); +#endif +} + +std::string ComplxFrame::DoAskForReplayString() +{ +#ifdef ENABLE_LC3_REPLAY + wxString replay = wxGetTextFromUser("Enter Replay String", "Testing"); + if (replay.IsEmpty()) + { + wxMessageBox("No replay string given", "Error"); + return ""; + } + return replay.ToStdString(); +#else + return ""; +#endif +} + +void ComplxFrame::DoSetupReplayString(const std::string& replay_string) +{ +#ifdef ENABLE_LC3_REPLAY + try + { + std::stringstream input; + lc3_setup_replay(state, reload_options.file, replay_string, input); + console->SetInput(input.str()); + reload_options.replay_string = replay_string; + UpdateRegisters(); + UpdateMemory(); + UpdateStatus(); + } + catch (std::string err) + { + wxMessageBox(err.c_str(), "Error"); + return; + } + catch (const char* err) + { + wxMessageBox(err, "Error"); + return; + } +#endif +} + /** OnAbout * * Displays information about this program @@ -1332,7 +1453,7 @@ void ComplxFrame::OnAbout(wxCommandEvent& event) aboutInfo.SetName("Complx"); aboutInfo.SetVersion(Version::FULLVERSION_STRING); aboutInfo.SetDescription(_("LC-3 Simulator\nBug reports, thanks, and feature requests should be sent to Brandon.\nbwhitehead0308@gmail.com")); - aboutInfo.SetCopyright("(C) 2010-2016"); + aboutInfo.SetCopyright("(C) 2010-2018"); aboutInfo.AddDeveloper("Brandon Whitehead bwhitehead0308@gmail.com"); aboutInfo.SetIcon(wxIcon(icon64_xpm)); @@ -1485,22 +1606,22 @@ void PrintError(int error) switch(error) { case 1: - msg = _("ERROR! Error evaluating expression: Unbalanced parenthesis"); + msg = _("Error evaluating expression: Unbalanced parenthesis"); break; case 2: - msg = _("ERROR! Error evaluating expression: Invalid Operator"); + msg = _("Error evaluating expression: Invalid Operator"); break; case 3: - msg = _("ERROR! Error evaluating expression: Invalid operand"); + msg = _("Error evaluating expression: Invalid operand"); break; case 4: - msg = _("ERROR! Error evaluating expression: Malformed reference"); + msg = _("Error evaluating expression: Malformed reference"); break; case 5: - msg = _("ERROR! Error evaluating expression: Undefined symbol"); + msg = _("Error evaluating expression: Undefined symbol"); break; default: - msg = _("ERROR! Error evaluating expression."); + msg = _("Error evaluating expression."); break; } diff --git a/complx/ComplxFrame.hpp b/complx/ComplxFrame.hpp index bf54be0..22d08cd 100644 --- a/complx/ComplxFrame.hpp +++ b/complx/ComplxFrame.hpp @@ -106,6 +106,13 @@ class ComplxFrame : public ComplxFrameDecl void OnAdvancedBreakpoint(wxCommandEvent& event) override; void OnBlackbox(wxCommandEvent& event) override; + // Test menu event handlers + void OnSetupReplayString(wxCommandEvent& event) override; + void OnReloadReplayString(wxCommandEvent& event) override; + void OnDescribeReplayString(wxCommandEvent& event) override; + std::string DoAskForReplayString(); + void DoSetupReplayString(const std::string& replay_string); + // Help menu event handlers void OnDocs(wxCommandEvent& event) override; void OnISA(wxCommandEvent& event) override; @@ -153,7 +160,7 @@ class ComplxFrame : public ComplxFrameDecl * Attempts to detect if a subroutine is found in the loaded code * The way this function works is it will try to find a RET, JSR, or JSRR instruction. * We do not look at trap instructions since they are black boxed anyway if true traps are disabled, - * however if a custom trap is written then it will of course have a RETY statement. + * however if a custom trap is written then it will of course have a RET statement. * The usage of this function is for enabling or disabling the Next/Prev Line and Finish control buttons. * @param ranges Code ranges the file that was loaded touches * @return True if a subroutine was detected false otherwise diff --git a/complx/ComplxFrameDecl.cpp b/complx/ComplxFrameDecl.cpp index 3b9a8e3..c60fecb 100644 --- a/complx/ComplxFrameDecl.cpp +++ b/complx/ComplxFrameDecl.cpp @@ -17,7 +17,7 @@ class wxFBContextSensitiveHelpSetter public: wxFBContextSensitiveHelpSetter() { -wxHelpControllerHelpProvider* help = new wxSimpleHelpProvider(); +wxSimpleHelpProvider* help = new wxSimpleHelpProvider(); wxHelpProvider* old = wxHelpProvider::Set( help ); if (old != 0){ delete old; @@ -31,330 +31,330 @@ static wxFBContextSensitiveHelpSetter s_wxFBSetTheHelpProvider; ComplxFrameDecl::ComplxFrameDecl( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style ) { this->SetSizeHints( wxDefaultSize, wxDefaultSize ); - + menu = new wxMenuBar( 0 ); menuFile = new wxMenu(); wxMenuItem* menuFileLoad; menuFileLoad = new wxMenuItem( menuFile, ID_LOAD, wxString( _("&Load") ) + wxT('\t') + wxT("Ctrl+O"), _("Loads a asm file"), wxITEM_NORMAL ); menuFile->Append( menuFileLoad ); - + wxMenuItem* menuFileReload; menuFileReload = new wxMenuItem( menuFile, ID_RELOAD, wxString( _("&Reload") ) + wxT('\t') + wxT("Ctrl+R"), _("Reloads current asm file under same conditions."), wxITEM_NORMAL ); menuFile->Append( menuFileReload ); - + wxMenuItem* menuFileCleanLoad; menuFileCleanLoad = new wxMenuItem( menuFile, ID_CLEAN_LOAD, wxString( _("&Clean Load") ) + wxT('\t') + wxT("Ctrl+Shift+O"), _("Zeroes out memory and loads asm file."), wxITEM_NORMAL ); menuFile->Append( menuFileCleanLoad ); - + wxMenuItem* menuFileAdvancedLoad; menuFileAdvancedLoad = new wxMenuItem( menuFile, ID_ADVANCED_LOAD, wxString( _("&Advanced Load...") ) , _("Opens dialog for loading program under special conditions."), wxITEM_NORMAL ); menuFile->Append( menuFileAdvancedLoad ); - + menuFile->AppendSeparator(); - + wxMenuItem* menuFileQuit; menuFileQuit = new wxMenuItem( menuFile, ID_QUIT, wxString( _("&Quit") ) + wxT('\t') + wxT("Ctrl+Q"), _("Quits the program."), wxITEM_NORMAL ); menuFile->Append( menuFileQuit ); - - menu->Append( menuFile, _("File") ); - + + menu->Append( menuFile, _("File") ); + menuView = new wxMenu(); wxMenuItem* menuViewNew; menuViewNew = new wxMenuItem( menuView, ID_NEW_VIEW, wxString( _("New View") ) + wxT('\t') + wxT("Ctrl+V"), _("Shows a new view of main memory."), wxITEM_NORMAL ); menuView->Append( menuViewNew ); - + wxMenuItem* menuViewGoto; menuViewGoto = new wxMenuItem( menuView, ID_GOTO_ADDRESS, wxString( _("Goto Address") ) + wxT('\t') + wxT("Ctrl+G"), _("Moves memory to a specific address."), wxITEM_NORMAL ); menuView->Append( menuViewGoto ); - + menuViewHideAddresses = new wxMenu(); wxMenuItem* menuViewHideAddressesItem = new wxMenuItem( menuView, wxID_ANY, _("Hide Addresses"), wxEmptyString, wxITEM_NORMAL, menuViewHideAddresses ); menuViewHideAddressesShowAll = new wxMenuItem( menuViewHideAddresses, ID_SHOW_ALL, wxString( _("Show All") ) , _("Shows all memory addresses"), wxITEM_RADIO ); menuViewHideAddresses->Append( menuViewHideAddressesShowAll ); - + menuViewHideAddressesShowNonZero = new wxMenuItem( menuViewHideAddresses, ID_SHOW_NON_ZERO, wxString( _("Show Non Zero") ) , _("Show all memory addresses that have a value other than 0"), wxITEM_RADIO ); menuViewHideAddresses->Append( menuViewHideAddressesShowNonZero ); - + menuViewHideAddressesShowOnlyCodeData = new wxMenuItem( menuViewHideAddresses, ID_SHOW_ONLY_CODEDATA, wxString( _("Show Only Code/Data") ) , _("Shows addresses modified when your program was loaded."), wxITEM_RADIO ); menuViewHideAddresses->Append( menuViewHideAddressesShowOnlyCodeData ); - + menuViewHideAddressesCustom = new wxMenuItem( menuViewHideAddresses, ID_CUSTOM, wxString( _("Custom...") ) + wxT('\t') + wxT("Ctrl+H"), _("Allows you to show/hide memory address ranges"), wxITEM_RADIO ); menuViewHideAddresses->Append( menuViewHideAddressesCustom ); - + menuView->Append( menuViewHideAddressesItem ); - + menuViewDisassemble = new wxMenu(); wxMenuItem* menuViewDisassembleItem = new wxMenuItem( menuView, wxID_ANY, _("Disassemble"), wxEmptyString, wxITEM_NORMAL, menuViewDisassemble ); menuViewBasic = new wxMenuItem( menuViewDisassemble, ID_BASIC, wxString( _("Basic") ) , _("Disassembles ignoring symbols"), wxITEM_RADIO ); menuViewDisassemble->Append( menuViewBasic ); - + menuViewNormal = new wxMenuItem( menuViewDisassemble, ID_NORMAL, wxString( _("Normal") ) , _("Disassembles with symbol info."), wxITEM_RADIO ); menuViewDisassemble->Append( menuViewNormal ); - + menuViewHighLevel = new wxMenuItem( menuViewDisassemble, ID_HIGH_LEVEL, wxString( _("High Level") ) , _("Disassembles into C-like statements"), wxITEM_RADIO ); menuViewDisassemble->Append( menuViewHighLevel ); menuViewHighLevel->Check( true ); - + menuView->Append( menuViewDisassembleItem ); - + menuViewInstructionHighlighting = new wxMenuItem( menuView, ID_INSTRUCTION_HIGHLIGHTING, wxString( _("Instruction Highlighting") ) , _("Highlights bits of the instruction."), wxITEM_CHECK ); menuView->Append( menuViewInstructionHighlighting ); menuViewInstructionHighlighting->Check( true ); - + wxMenuItem* menuViewFlipMemory; menuViewFlipMemory = new wxMenuItem( menuView, ID_FLIP_MEMORY, wxString( _("Flip Memory") ) , _("Reverses memory such that high addresses come first."), wxITEM_CHECK ); menuView->Append( menuViewFlipMemory ); - - menu->Append( menuView, _("View") ); - + + menu->Append( menuView, _("View") ); + menuState = new wxMenu(); menuStateControl = new wxMenu(); wxMenuItem* menuStateControlItem = new wxMenuItem( menuState, wxID_ANY, _("Control"), wxEmptyString, wxITEM_NORMAL, menuStateControl ); wxMenuItem* menuStateControlStep; menuStateControlStep = new wxMenuItem( menuStateControl, ID_STEP, wxString( _("Step") ) + wxT('\t') + wxT("F2"), _("Runs one instruction"), wxITEM_NORMAL ); menuStateControl->Append( menuStateControlStep ); - + wxMenuItem* menuStateControlBack; menuStateControlBack = new wxMenuItem( menuStateControl, ID_BACK, wxString( _("Back") ) + wxT('\t') + wxT("Shift+F2"), _("Undoes one instruction"), wxITEM_NORMAL ); menuStateControl->Append( menuStateControlBack ); - + wxMenuItem* menuStateControlNextLine; menuStateControlNextLine = new wxMenuItem( menuStateControl, ID_NEXT_LINE, wxString( _("Next Line") ) + wxT('\t') + wxT("F3"), _("Steps over the next instruction."), wxITEM_NORMAL ); menuStateControl->Append( menuStateControlNextLine ); - + wxMenuItem* menuStateControlPreviousLine; menuStateControlPreviousLine = new wxMenuItem( menuStateControl, ID_PREVIOUS_LINE, wxString( _("Previous Line") ) + wxT('\t') + wxT("Shift+F3"), _("Steps over the previous instruction."), wxITEM_NORMAL ); menuStateControl->Append( menuStateControlPreviousLine ); - + wxMenuItem* menuStateControlRun; menuStateControlRun = new wxMenuItem( menuStateControl, ID_RUN, wxString( _("Run") ) + wxT('\t') + wxT("F4"), _("Runs until program halts."), wxITEM_NORMAL ); menuStateControl->Append( menuStateControlRun ); - + wxMenuItem* menuStateControlRunFor; menuStateControlRunFor = new wxMenuItem( menuStateControl, ID_RUN_FOR, wxString( _("Run For...") ) + wxT('\t') + wxT("Ctrl+F4"), _("Runs for a specified number of steps"), wxITEM_NORMAL ); menuStateControl->Append( menuStateControlRunFor ); - + wxMenuItem* menuStateControlRunAgain; menuStateControlRunAgain = new wxMenuItem( menuStateControl, ID_RUN_AGAIN, wxString( _("Run Again...") ) + wxT('\t') + wxT("Ctrl+Space"), _("Runs the default number of instructions (see RunFor)"), wxITEM_NORMAL ); menuStateControl->Append( menuStateControlRunAgain ); - + wxMenuItem* menuStateControlRewind; menuStateControlRewind = new wxMenuItem( menuStateControl, ID_REWIND, wxString( _("Rewind") ) + wxT('\t') + wxT("Shift+F4"), _("Undoes all instructions."), wxITEM_NORMAL ); menuStateControl->Append( menuStateControlRewind ); - + wxMenuItem* menuStateControlFinish; menuStateControlFinish = new wxMenuItem( menuStateControl, ID_FINISH, wxString( _("Finish") ) + wxT('\t') + wxT("Shift+F5"), _("Finishes current subroutine."), wxITEM_NORMAL ); menuStateControl->Append( menuStateControlFinish ); - + menuState->Append( menuStateControlItem ); - + menuStateControlMode = new wxMenu(); wxMenuItem* menuStateControlModeItem = new wxMenuItem( menuState, wxID_ANY, _("Control Mode"), wxEmptyString, wxITEM_NORMAL, menuStateControlMode ); wxMenuItem* menuStateControlModeSimple; menuStateControlModeSimple = new wxMenuItem( menuStateControlMode, ID_SIMPLE, wxString( _("Simple") ) , _("Show commonly used control buttons."), wxITEM_RADIO ); menuStateControlMode->Append( menuStateControlModeSimple ); - + wxMenuItem* menuStateControlModeAdvanced; menuStateControlModeAdvanced = new wxMenuItem( menuStateControlMode, ID_ADVANCED, wxString( _("Advanced") ) , _("Show control buttons related to subroutines."), wxITEM_RADIO ); menuStateControlMode->Append( menuStateControlModeAdvanced ); - + menuState->Append( menuStateControlModeItem ); - + menuState->AppendSeparator(); - + menuStateTrueTraps = new wxMenuItem( menuState, ID_TRUE_TRAPS, wxString( _("&True Traps") ) , _("Enables True Traps"), wxITEM_CHECK ); menuState->Append( menuStateTrueTraps ); - + menuStateInterrupts = new wxMenuItem( menuState, ID_INTERRUPTS, wxString( _("&Interrupts") ) , _("Enables Interrupts"), wxITEM_CHECK ); menuState->Append( menuStateInterrupts ); - + menuStateStrictExecution = new wxMenuItem( menuState, ID_STRICT_EXECUTION_MODE, wxString( _("&Strict Execution Mode") ) + wxT('\t') + wxT("Ctrl+S"), _("Enables strict execution mode."), wxITEM_CHECK ); menuState->Append( menuStateStrictExecution ); menuStateStrictExecution->Check( true ); - + menuState->AppendSeparator(); - + wxMenuItem* menuStateClearConsole; menuStateClearConsole = new wxMenuItem( menuState, ID_CLEAR_CONSOLE, wxString( _("&Clear Console") ) , _("Clears the console output."), wxITEM_NORMAL ); menuState->Append( menuStateClearConsole ); - + wxMenuItem* menuStateClearConsoleInput; menuStateClearConsoleInput = new wxMenuItem( menuState, wxID_ANY, wxString( _("Clear Console Input") ) , _("Clears the console input."), wxITEM_NORMAL ); menuState->Append( menuStateClearConsoleInput ); - - menu->Append( menuState, _("State") ); - + + menu->Append( menuState, _("State") ); + menuDebug = new wxMenu(); wxMenuItem* menuDebugUndoStack; menuDebugUndoStack = new wxMenuItem( menuDebug, ID_UNDO_STACK, wxString( _("&Undo Stack") ) + wxT('\t') + wxT("F6"), _("Modifies the undo stack size"), wxITEM_NORMAL ); menuDebug->Append( menuDebugUndoStack ); - + wxMenuItem* menuDebugCallStack; menuDebugCallStack = new wxMenuItem( menuDebug, ID_CALL_STACK, wxString( _("&Call Stack") ) , _("Views the call stack."), wxITEM_NORMAL ); menuDebug->Append( menuDebugCallStack ); - + menuDebug->AppendSeparator(); - + wxMenuItem* menuDebugSimulateSubroutineCall; menuDebugSimulateSubroutineCall = new wxMenuItem( menuDebug, ID_SIMULATE_SUBROUTINE_CALL, wxString( _("Simulate Subroutine &Call...") ) , _("Simulates a subroutine call."), wxITEM_NORMAL ); menuDebug->Append( menuDebugSimulateSubroutineCall ); - + menuDebug->AppendSeparator(); - + wxMenuItem* menuDebugBreakWatchpoints; menuDebugBreakWatchpoints = new wxMenuItem( menuDebug, ID_BREAKPOINTS_AND_WATCHPOINTS, wxString( _("Breakpoints &and Watchpoints") ) + wxT('\t') + wxT("F7"), _("View all breakpoints and watchpoints"), wxITEM_NORMAL ); menuDebug->Append( menuDebugBreakWatchpoints ); - + wxMenuItem* menuDebugTemporary; menuDebugTemporary = new wxMenuItem( menuDebug, ID_ADD_TEMPORARY_BREAKPOINT, wxString( _("Add &Temporary Breakpoint") ) + wxT('\t') + wxT("F8"), _("Adds/Removes a one time breakpoint"), wxITEM_NORMAL ); menuDebug->Append( menuDebugTemporary ); - + wxMenuItem* menuDebugBreakpoint; menuDebugBreakpoint = new wxMenuItem( menuDebug, ID_ADD_BREAKPOINT, wxString( _("Add &Breakpoint") ) + wxT('\t') + wxT("F9"), _("Adds/Removes a breakpoint"), wxITEM_NORMAL ); menuDebug->Append( menuDebugBreakpoint ); - + wxMenuItem* menuDebugWatchpoint; menuDebugWatchpoint = new wxMenuItem( menuDebug, ID_ADD_WATCHPOINT, wxString( _("Add &Watchpoint") ) + wxT('\t') + wxT("F11"), _("Adds a watchpoint."), wxITEM_NORMAL ); menuDebug->Append( menuDebugWatchpoint ); - + wxMenuItem* menuDebugAdvanced; menuDebugAdvanced = new wxMenuItem( menuDebug, ID_ADVANCED_BREAKPOINT, wxString( _("Ad&vanced Breakpoint") ) + wxT('\t') + wxT("F12"), _("Adds a customizable breakpoint."), wxITEM_NORMAL ); menuDebug->Append( menuDebugAdvanced ); - + wxMenuItem* menuDebugBlackbox; menuDebugBlackbox = new wxMenuItem( menuDebug, ID_ADD_BLACKBOX, wxString( _("Add B&lackbox") ) + wxT('\t') + wxT("F5"), _("Adds a blackbox."), wxITEM_NORMAL ); menuDebug->Append( menuDebugBlackbox ); - - menu->Append( menuDebug, _("Debug") ); - + + menu->Append( menuDebug, _("Debug") ); + menuTest = new wxMenu(); wxMenuItem* menuTestSetupReplayString; menuTestSetupReplayString = new wxMenuItem( menuTest, ID_SETUP_REPLAY_STRING, wxString( _("&Setup Replay String...") ) + wxT('\t') + wxT("Ctrl+T"), _("Loads a replay string from the pylc3 unit test framework."), wxITEM_NORMAL ); menuTest->Append( menuTestSetupReplayString ); - + wxMenuItem* menuTestReloadReplayString; menuTestReloadReplayString = new wxMenuItem( menuTest, ID_RELOAD_REPLAY_STRING, wxString( _("&Reload Replay String") ) + wxT('\t') + wxT("Ctrl+Alt+T"), _("Reloads a replay string from the pylc3 unit test framework."), wxITEM_NORMAL ); menuTest->Append( menuTestReloadReplayString ); - + wxMenuItem* menuTestDescribeReplayString; menuTestDescribeReplayString = new wxMenuItem( menuTest, ID_DESCRIBE_REPLAY_STRING, wxString( _("&Describe Replay String") ) + wxT('\t') + wxT("Ctrl+D"), _("Pops a dialog explaining the current replay string."), wxITEM_NORMAL ); menuTest->Append( menuTestDescribeReplayString ); - - menu->Append( menuTest, _("Test") ); - + + menu->Append( menuTest, _("Test") ); + menuHelp = new wxMenu(); wxMenuItem* menuHelpDocs; menuHelpDocs = new wxMenuItem( menuHelp, wxID_ANY, wxString( _("&Documentation") ) + wxT('\t') + wxT("F1"), _("Opens up the Complx Documentation."), wxITEM_NORMAL ); menuHelp->Append( menuHelpDocs ); - + wxMenuItem* menuHelpISA; menuHelpISA = new wxMenuItem( menuHelp, wxID_ANY, wxString( _("&LC-3 ISA") ) + wxT('\t') + wxT("SHIFT+F1"), _("Opens up the lc3 isa reference manual."), wxITEM_NORMAL ); menuHelp->Append( menuHelpISA ); - + wxMenuItem* menuHelpChangeLog; menuHelpChangeLog = new wxMenuItem( menuHelp, ID_CHANGE_LOG, wxString( _("&Change Log") ) , _("Shows the change log"), wxITEM_NORMAL ); menuHelp->Append( menuHelpChangeLog ); - + wxMenuItem* menuHelpCreateBugReport; menuHelpCreateBugReport = new wxMenuItem( menuHelp, ID_CREATE_BUG_REPORT, wxString( _("Create &Bug Report") ) , _("Create a bug report"), wxITEM_NORMAL ); menuHelp->Append( menuHelpCreateBugReport ); - + wxMenuItem* menuHelpFirstTime; menuHelpFirstTime = new wxMenuItem( menuHelp, ID_FIRST_TIME_MESSAGE, wxString( _("&First Time Message") ) , _("Displays the first time running message."), wxITEM_NORMAL ); menuHelp->Append( menuHelpFirstTime ); - + wxMenuItem* menuHelpTips; menuHelpTips = new wxMenuItem( menuHelp, ID_TIPS, wxString( _("Tips") ) , _("Displays the tips"), wxITEM_NORMAL ); menuHelp->Append( menuHelpTips ); - + wxMenuItem* menuHelpAbout; menuHelpAbout = new wxMenuItem( menuHelp, ID_ABOUT, wxString( _("&About") ) , _("Shows info about this program"), wxITEM_NORMAL ); menuHelp->Append( menuHelpAbout ); - - menu->Append( menuHelp, _("Help") ); - + + menu->Append( menuHelp, _("Help") ); + this->SetMenuBar( menu ); - + wxBoxSizer* main; main = new wxBoxSizer( wxVERTICAL ); - + mainPanel = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); wxBoxSizer* subsizer; subsizer = new wxBoxSizer( wxVERTICAL ); - + memory = new MemoryGrid( mainPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL|wxWANTS_CHARS ); - + // Grid memory->CreateGrid( 5, 5 ); memory->EnableEditing( true ); memory->EnableGridLines( false ); memory->EnableDragGridSize( false ); memory->SetMargins( 0, 0 ); - + // Columns memory->EnableDragColMove( true ); memory->EnableDragColSize( true ); memory->SetColLabelSize( 20 ); memory->SetColLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); - + // Rows memory->EnableDragRowSize( false ); memory->SetRowLabelSize( 0 ); memory->SetRowLabelAlignment( wxALIGN_CENTRE, wxALIGN_CENTRE ); - + // Label Appearance memory->SetLabelFont( wxFont( 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxT("Courier New") ) ); - + // Cell Defaults memory->SetDefaultCellFont( wxFont( 10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxT("Courier New") ) ); memory->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_CENTRE ); memory->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); - + subsizer->Add( memory, 1, wxEXPAND, 5 ); - + controlSizer = new wxBoxSizer( wxHORIZONTAL ); - + runButton = new wxButton( mainPanel, wxID_ANY, _("&Run"), wxDefaultPosition, wxDefaultSize, 0 ); runButton->SetToolTip( _("Runs your code until it HALTs") ); - + controlSizer->Add( runButton, 1, wxALL|wxEXPAND, 2 ); - + stepButton = new wxButton( mainPanel, wxID_ANY, _("&Step"), wxDefaultPosition, wxDefaultSize, 0 ); stepButton->SetToolTip( _("Runs one instruction") ); - + controlSizer->Add( stepButton, 1, wxALL|wxEXPAND, 2 ); - + backStepButton = new wxButton( mainPanel, wxID_ANY, _("&Back"), wxDefaultPosition, wxDefaultSize, 0 ); backStepButton->SetToolTip( _("Undoes one instruction") ); - + controlSizer->Add( backStepButton, 1, wxALL|wxEXPAND, 2 ); - + nextLineButton = new wxButton( mainPanel, wxID_ANY, _("&Next Line"), wxDefaultPosition, wxDefaultSize, 0 ); nextLineButton->Hide(); nextLineButton->SetToolTip( _("Run the next instruction (blackboxes subroutines)") ); - + controlSizer->Add( nextLineButton, 1, wxALL|wxEXPAND, 2 ); - + prevLineButton = new wxButton( mainPanel, wxID_ANY, _("&Prev Line"), wxDefaultPosition, wxDefaultSize, 0 ); prevLineButton->Hide(); prevLineButton->SetToolTip( _("Undoes the last instruction (blackboxing subroutines)") ); - + controlSizer->Add( prevLineButton, 1, wxALL|wxEXPAND, 2 ); - + finishButton = new wxButton( mainPanel, wxID_ANY, _("&Finish"), wxDefaultPosition, wxDefaultSize, 0 ); finishButton->Hide(); finishButton->SetToolTip( _("Steps out of the current subroutine.") ); - + controlSizer->Add( finishButton, 1, wxALL|wxEXPAND, 2 ); - + rewindButton = new wxButton( mainPanel, wxID_ANY, _("Rewin&d"), wxDefaultPosition, wxDefaultSize, 0 ); rewindButton->SetToolTip( _("Rewinds back to start (or undoes all of the instructions in the stack)") ); - + controlSizer->Add( rewindButton, 1, wxALL|wxEXPAND, 2 ); - - + + subsizer->Add( controlSizer, 0, wxEXPAND, 5 ); - + wxFlexGridSizer* stateSizer; stateSizer = new wxFlexGridSizer( 3, 4, 8, 16 ); stateSizer->AddGrowableCol( 0 ); @@ -363,15 +363,15 @@ ComplxFrameDecl::ComplxFrameDecl( wxWindow* parent, wxWindowID id, const wxStrin stateSizer->AddGrowableCol( 3 ); stateSizer->SetFlexibleDirection( wxBOTH ); stateSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); - + wxBoxSizer* R0; R0 = new wxBoxSizer( wxHORIZONTAL ); - + wxStaticText* r0label; r0label = new wxStaticText( mainPanel, wxID_ANY, _("R0"), wxDefaultPosition, wxDefaultSize, 0 ); r0label->Wrap( -1 ); R0->Add( r0label, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, 2 ); - + r0text = new wxTextCtrl( mainPanel, wxID_ANY, _("x0000"), wxDefaultPosition, wxSize( 64,-1 ), wxTE_PROCESS_ENTER|wxTE_RIGHT, wxDefaultValidator, wxT("R0") ); #ifdef __WXGTK__ if ( !r0text->HasFlag( wxTE_MULTILINE ) ) @@ -382,20 +382,20 @@ ComplxFrameDecl::ComplxFrameDecl( wxWindow* parent, wxWindowID id, const wxStrin r0text->SetMaxLength( 24 ); #endif r0text->SetToolTip( _("R0's value.\n (enter an expression i.e. R0+5 or PC+10 or LABEL[0])\n Double click to change the base.") ); - + R0->Add( r0text, 1, wxALIGN_CENTER|wxLEFT|wxRIGHT, 2 ); - - + + stateSizer->Add( R0, 1, wxEXPAND, 0 ); - + wxBoxSizer* R1; R1 = new wxBoxSizer( wxHORIZONTAL ); - + wxStaticText* r1abel; r1abel = new wxStaticText( mainPanel, wxID_ANY, _("R1"), wxDefaultPosition, wxDefaultSize, 0 ); r1abel->Wrap( -1 ); R1->Add( r1abel, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, 2 ); - + r1text = new wxTextCtrl( mainPanel, wxID_ANY, _("x0000"), wxDefaultPosition, wxSize( 64,-1 ), wxTE_PROCESS_ENTER|wxTE_RIGHT, wxDefaultValidator, wxT("R1") ); #ifdef __WXGTK__ if ( !r1text->HasFlag( wxTE_MULTILINE ) ) @@ -406,20 +406,20 @@ ComplxFrameDecl::ComplxFrameDecl( wxWindow* parent, wxWindowID id, const wxStrin r1text->SetMaxLength( 24 ); #endif r1text->SetToolTip( _("R1's value.\n (enter an expression i.e. R0+5 or PC+10 or LABEL[0])\n Double click to change the base.") ); - + R1->Add( r1text, 1, wxALIGN_CENTER|wxLEFT|wxRIGHT, 2 ); - - + + stateSizer->Add( R1, 1, wxEXPAND, 5 ); - + wxBoxSizer* R2; R2 = new wxBoxSizer( wxHORIZONTAL ); - + wxStaticText* r2label; r2label = new wxStaticText( mainPanel, wxID_ANY, _("R2"), wxDefaultPosition, wxDefaultSize, 0 ); r2label->Wrap( -1 ); R2->Add( r2label, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, 2 ); - + r2text = new wxTextCtrl( mainPanel, wxID_ANY, _("x0000"), wxDefaultPosition, wxSize( 64,-1 ), wxTE_PROCESS_ENTER|wxTE_RIGHT, wxDefaultValidator, wxT("R2") ); #ifdef __WXGTK__ if ( !r2text->HasFlag( wxTE_MULTILINE ) ) @@ -430,20 +430,20 @@ ComplxFrameDecl::ComplxFrameDecl( wxWindow* parent, wxWindowID id, const wxStrin r2text->SetMaxLength( 24 ); #endif r2text->SetToolTip( _("R2's value.\n (enter an expression i.e. R0+5 or PC+10 or LABEL[0])\n Double click to change the base.") ); - + R2->Add( r2text, 1, wxALIGN_CENTER|wxLEFT|wxRIGHT, 2 ); - - + + stateSizer->Add( R2, 1, wxEXPAND, 5 ); - + wxBoxSizer* R3; R3 = new wxBoxSizer( wxHORIZONTAL ); - + wxStaticText* r3label; r3label = new wxStaticText( mainPanel, wxID_ANY, _("R3"), wxDefaultPosition, wxDefaultSize, 0 ); r3label->Wrap( -1 ); R3->Add( r3label, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, 2 ); - + r3text = new wxTextCtrl( mainPanel, wxID_ANY, _("x0000"), wxDefaultPosition, wxSize( 64,-1 ), wxTE_PROCESS_ENTER|wxTE_RIGHT, wxDefaultValidator, wxT("R3") ); #ifdef __WXGTK__ if ( !r3text->HasFlag( wxTE_MULTILINE ) ) @@ -454,20 +454,20 @@ ComplxFrameDecl::ComplxFrameDecl( wxWindow* parent, wxWindowID id, const wxStrin r3text->SetMaxLength( 24 ); #endif r3text->SetToolTip( _("R3's value.\n (enter an expression i.e. R0+5 or PC+10 or LABEL[0])\n Double click to change the base.") ); - + R3->Add( r3text, 1, wxALIGN_CENTER|wxLEFT|wxRIGHT, 2 ); - - + + stateSizer->Add( R3, 1, wxEXPAND, 5 ); - + wxBoxSizer* R4; R4 = new wxBoxSizer( wxHORIZONTAL ); - + wxStaticText* r4label; r4label = new wxStaticText( mainPanel, wxID_ANY, _("R4"), wxDefaultPosition, wxDefaultSize, 0 ); r4label->Wrap( -1 ); R4->Add( r4label, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, 2 ); - + r4text = new wxTextCtrl( mainPanel, wxID_ANY, _("x0000"), wxDefaultPosition, wxSize( 64,-1 ), wxTE_PROCESS_ENTER|wxTE_RIGHT, wxDefaultValidator, wxT("R4") ); #ifdef __WXGTK__ if ( !r4text->HasFlag( wxTE_MULTILINE ) ) @@ -478,20 +478,20 @@ ComplxFrameDecl::ComplxFrameDecl( wxWindow* parent, wxWindowID id, const wxStrin r4text->SetMaxLength( 24 ); #endif r4text->SetToolTip( _("R4's value.\n (enter an expression i.e. R0+5 or PC+10 or LABEL[0])\n Double click to change the base.") ); - + R4->Add( r4text, 1, wxALIGN_CENTER|wxLEFT|wxRIGHT, 2 ); - - + + stateSizer->Add( R4, 1, wxEXPAND, 5 ); - + wxBoxSizer* R5; R5 = new wxBoxSizer( wxHORIZONTAL ); - + wxStaticText* r5label; r5label = new wxStaticText( mainPanel, wxID_ANY, _("R5"), wxDefaultPosition, wxDefaultSize, 0 ); r5label->Wrap( -1 ); R5->Add( r5label, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, 2 ); - + r5text = new wxTextCtrl( mainPanel, wxID_ANY, _("x0000"), wxDefaultPosition, wxSize( 64,-1 ), wxTE_PROCESS_ENTER|wxTE_RIGHT, wxDefaultValidator, wxT("R5") ); #ifdef __WXGTK__ if ( !r5text->HasFlag( wxTE_MULTILINE ) ) @@ -502,20 +502,20 @@ ComplxFrameDecl::ComplxFrameDecl( wxWindow* parent, wxWindowID id, const wxStrin r5text->SetMaxLength( 24 ); #endif r5text->SetToolTip( _("R5's value.\n (enter an expression i.e. R0+5 or PC+10 or LABEL[0])\n Double click to change the base.") ); - + R5->Add( r5text, 1, wxALIGN_CENTER|wxLEFT|wxRIGHT, 2 ); - - + + stateSizer->Add( R5, 1, wxEXPAND, 5 ); - + wxBoxSizer* R6; R6 = new wxBoxSizer( wxHORIZONTAL ); - + wxStaticText* r6label; r6label = new wxStaticText( mainPanel, wxID_ANY, _("R6"), wxDefaultPosition, wxDefaultSize, 0 ); r6label->Wrap( -1 ); R6->Add( r6label, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, 2 ); - + r6text = new wxTextCtrl( mainPanel, wxID_ANY, _("x0000"), wxDefaultPosition, wxSize( 64,-1 ), wxTE_PROCESS_ENTER|wxTE_RIGHT, wxDefaultValidator, wxT("R6") ); #ifdef __WXGTK__ if ( !r6text->HasFlag( wxTE_MULTILINE ) ) @@ -526,20 +526,20 @@ ComplxFrameDecl::ComplxFrameDecl( wxWindow* parent, wxWindowID id, const wxStrin r6text->SetMaxLength( 24 ); #endif r6text->SetToolTip( _("R6's value.\n (enter an expression i.e. R0+5 or PC+10 or LABEL[0])\n Double click to change the base.") ); - + R6->Add( r6text, 1, wxALIGN_CENTER|wxLEFT|wxRIGHT, 2 ); - - + + stateSizer->Add( R6, 1, wxEXPAND, 5 ); - + wxBoxSizer* R7; R7 = new wxBoxSizer( wxHORIZONTAL ); - + wxStaticText* r7label; r7label = new wxStaticText( mainPanel, wxID_ANY, _("R7"), wxDefaultPosition, wxDefaultSize, 0 ); r7label->Wrap( -1 ); R7->Add( r7label, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, 2 ); - + r7text = new wxTextCtrl( mainPanel, wxID_ANY, _("x0000"), wxDefaultPosition, wxSize( 64,-1 ), wxTE_PROCESS_ENTER|wxTE_RIGHT, wxDefaultValidator, wxT("R7") ); #ifdef __WXGTK__ if ( !r7text->HasFlag( wxTE_MULTILINE ) ) @@ -550,20 +550,20 @@ ComplxFrameDecl::ComplxFrameDecl( wxWindow* parent, wxWindowID id, const wxStrin r7text->SetMaxLength( 24 ); #endif r7text->SetToolTip( _("R7's value.\n (enter an expression i.e. R0+5 or PC+10 or LABEL[0])\n Double click to change the base.") ); - + R7->Add( r7text, 1, wxALIGN_CENTER|wxLEFT|wxRIGHT, 2 ); - - + + stateSizer->Add( R7, 1, wxEXPAND, 5 ); - + wxBoxSizer* CC; CC = new wxBoxSizer( wxHORIZONTAL ); - + wxStaticText* cclabel; cclabel = new wxStaticText( mainPanel, wxID_ANY, _("CC"), wxDefaultPosition, wxDefaultSize, 0 ); cclabel->Wrap( -1 ); CC->Add( cclabel, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, 2 ); - + cctext = new wxTextCtrl( mainPanel, wxID_ANY, _("z"), wxDefaultPosition, wxSize( 64,-1 ), wxTE_PROCESS_ENTER|wxTE_RIGHT, wxDefaultValidator, wxT("CC") ); #ifdef __WXGTK__ if ( !cctext->HasFlag( wxTE_MULTILINE ) ) @@ -574,20 +574,20 @@ ComplxFrameDecl::ComplxFrameDecl( wxWindow* parent, wxWindowID id, const wxStrin cctext->SetMaxLength( 24 ); #endif cctext->SetToolTip( _("CC's state.\n (enter an expression i.e. R0+5 or PC+10 or LABEL[0])\n Double click to change the base.") ); - + CC->Add( cctext, 1, wxALIGN_CENTER|wxLEFT|wxRIGHT, 2 ); - - + + stateSizer->Add( CC, 1, wxEXPAND, 5 ); - + wxBoxSizer* PC; PC = new wxBoxSizer( wxHORIZONTAL ); - + wxStaticText* pclabel; pclabel = new wxStaticText( mainPanel, wxID_ANY, _("PC"), wxDefaultPosition, wxDefaultSize, 0 ); pclabel->Wrap( -1 ); PC->Add( pclabel, 0, wxALIGN_CENTER|wxLEFT|wxRIGHT, 2 ); - + pctext = new wxTextCtrl( mainPanel, wxID_ANY, _("x0000"), wxDefaultPosition, wxSize( 64,-1 ), wxTE_PROCESS_ENTER|wxTE_RIGHT, wxDefaultValidator, wxT("PC") ); #ifdef __WXGTK__ if ( !pctext->HasFlag( wxTE_MULTILINE ) ) @@ -598,34 +598,34 @@ ComplxFrameDecl::ComplxFrameDecl( wxWindow* parent, wxWindowID id, const wxStrin pctext->SetMaxLength( 24 ); #endif pctext->SetToolTip( _("PC's value.\n (enter an expression i.e. R0+5 or PC+10 or LABEL[0])\n Double click to change the base.") ); - + PC->Add( pctext, 1, wxALIGN_CENTER|wxLEFT|wxRIGHT, 2 ); - - + + stateSizer->Add( PC, 1, wxEXPAND, 5 ); - - + + stateSizer->Add( 0, 0, 1, wxEXPAND, 5 ); - - + + stateSizer->Add( 0, 0, 1, wxEXPAND, 5 ); - - + + subsizer->Add( stateSizer, 0, wxEXPAND, 5 ); - - + + mainPanel->SetSizer( subsizer ); mainPanel->Layout(); subsizer->Fit( mainPanel ); main->Add( mainPanel, 1, wxEXPAND | wxALL, 0 ); - - + + this->SetSizer( main ); this->Layout(); statusBar = this->CreateStatusBar( 5, wxSTB_SIZEGRIP, wxID_ANY ); - + this->Centre( wxBOTH ); - + // Connect Events this->Connect( wxEVT_ACTIVATE, wxActivateEventHandler( ComplxFrameDecl::OnActivate ) ); this->Connect( wxEVT_IDLE, wxIdleEventHandler( ComplxFrameDecl::OnIdle ) ); @@ -828,5 +828,5 @@ ComplxFrameDecl::~ComplxFrameDecl() pctext->Disconnect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( ComplxFrameDecl::OnBaseChange ), NULL, this ); pctext->Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( ComplxFrameDecl::OnBaseChangeContext ), NULL, this ); pctext->Disconnect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( ComplxFrameDecl::OnRegisterChanged ), NULL, this ); - + } diff --git a/complx/version.h b/complx/version.h index 463bb84..e468212 100644 --- a/complx/version.h +++ b/complx/version.h @@ -2,6 +2,6 @@ #define VERSION_H namespace Version { - static const char FULLVERSION_STRING[] = "4.17.0"; + static const char FULLVERSION_STRING[] = "4.18.0"; } #endif diff --git a/pylc3/CMakeLists.txt b/pylc3/CMakeLists.txt index ea37479..652a7bc 100644 --- a/pylc3/CMakeLists.txt +++ b/pylc3/CMakeLists.txt @@ -41,6 +41,15 @@ target_link_libraries( ${PYTHON_LIBRARIES} ) +if (ENABLE_REPLAY) +add_definitions(-DENABLE_LC3_REPLAY) +include_directories("../replay") +target_link_libraries( + pylc3 + lc3_replay +) +endif(ENABLE_REPLAY) + set_target_properties(pylc3 PROPERTIES SUFFIX .so) set_target_properties(pylc3 PROPERTIES PREFIX "") diff --git a/pylc3/PyLC3.cpp b/pylc3/PyLC3.cpp index 8a8da5a..fb2c771 100644 --- a/pylc3/PyLC3.cpp +++ b/pylc3/PyLC3.cpp @@ -1,5 +1,10 @@ #include "PyLC3.hpp" +#ifdef ENABLE_LC3_REPLAY +#include +#endif + + bool LC3State::load(const std::string& filename, bool disable_plugins, bool process_debug_comments, bool multiple_errors, bool enable_warnings, bool warnings_as_errors) { try @@ -70,28 +75,44 @@ bool LC3State::loadCode(const std::string& code) return true; } -#ifdef HAVE_LC3_REPLAY -#include -void LC3State::setup_replay(const std::string& file, const std::string& replay_str) +std::string LC3State::setup_replay(const std::string& file, const std::string& replay_str) { +#ifdef ENABLE_LC3_REPLAY try { lc3_setup_replay(state, file, replay_str, in); state.input = ∈ - return "" + return ""; } - catch(std::string err) + catch (std::string err) { return err; } - catch(const char* str) + catch (const char* err) { return err; } -} #else -std::string LC3State::setup_replay(const std::string& file, const std::string& replay_str) -{ return "NOT IMPLEMENTED"; +#endif } + +std::string LC3State::describe_replay(const std::string& replay_str) +{ +#ifdef ENABLE_LC3_REPLAY + try + { + return lc3_describe_replay(replay_str); + } + catch (std::string err) + { + return ""; + } + catch (const char* err) + { + return ""; + } +#else + return ""; #endif +} diff --git a/pylc3/PyLC3.hpp b/pylc3/PyLC3.hpp index e98d73b..01e465a 100644 --- a/pylc3/PyLC3.hpp +++ b/pylc3/PyLC3.hpp @@ -20,7 +20,7 @@ class LC3State * @param randomize Enable randomizing of both memory and registers. * @param fill_value If randomize is false the value for every single memory address and register. */ - void init(bool randomize = true, short fill_value = 0) + void init(bool randomize = true, int fill_value = 0) { lc3_init(state, randomize, randomize, fill_value, fill_value); } @@ -136,7 +136,7 @@ class LC3State void seed(unsigned int seed) { srand(seed); } /** @see lc3_random */ - unsigned int random() { return lc3_random(); } + short random() { return lc3_random(); } int get_r0() const { return state.regs[0]; } void set_r0(int r0) { state.regs[0] = r0; } @@ -191,6 +191,7 @@ class LC3State void set_strict_execution(bool setting) { state.strict_execution = setting; } std::string setup_replay(const std::string& file, const std::string& replay_str); + std::string describe_replay(const std::string& replay_str); /** The following accessors are only meaningful if testing_mode was set */ std::string get_input() const { return in.str(); } diff --git a/pylc3/unittests/lc3_unit_test_case.py b/pylc3/unittests/lc3_unit_test_case.py index 8a5ba30..6434d31 100644 --- a/pylc3/unittests/lc3_unit_test_case.py +++ b/pylc3/unittests/lc3_unit_test_case.py @@ -179,7 +179,7 @@ def init(self, strategy=MemoryFillStrategy.fill_with_value, value=0): value: Param for Memory Fill Strategy, either a fill value or random seed. """ if strategy == MemoryFillStrategy.fill_with_value: - self.state.init(False, value) + self.state.init(False, toShort(value)) elif strategy == MemoryFillStrategy.random_fill_with_seed: self.state.seed(value) self.state.init(False, self.state.random()) diff --git a/pylc3/unittests/lc3_unit_test_case_test.py b/pylc3/unittests/lc3_unit_test_case_test.py index d55d0ea..7146e5c 100644 --- a/pylc3/unittests/lc3_unit_test_case_test.py +++ b/pylc3/unittests/lc3_unit_test_case_test.py @@ -11,6 +11,10 @@ def loadCode(self, snippet): # This function is test only, Only use loadAsmFile for student code. self.state.loadCode(snippet) + def testInit(self): + self.init(lc3_unit_test_case.MemoryFillStrategy.fill_with_value, 0x8000) + self.assertEqual(self._readMem(0x3005) & 0xFFFF, 0x8000) + def testRegister(self): snippet = """ .orig x3000 diff --git a/replay/BinaryStreamReader.cpp b/replay/BinaryStreamReader.cpp index 8556db5..b113181 100644 --- a/replay/BinaryStreamReader.cpp +++ b/replay/BinaryStreamReader.cpp @@ -71,6 +71,12 @@ BinaryStreamReader& BinaryStreamReader::operator>>(std::string& val) if ((flags & BinaryStreamReader::READ_STRING_SIZES) && width == 0) (*this) >> effSize; + if (effSize > max_string_size) + { + stream.setstate(std::ios_base::failbit); + return *this; + } + char data[effSize]; stream.read(data, effSize); val.assign(data, effSize); diff --git a/replay/BinaryStreamReader.hpp b/replay/BinaryStreamReader.hpp index 1c29281..54c2e3a 100644 --- a/replay/BinaryStreamReader.hpp +++ b/replay/BinaryStreamReader.hpp @@ -2,6 +2,7 @@ #define BINARY_STREAM_READER_HPP #include +#include #include #include #include @@ -28,6 +29,11 @@ class BinaryStreamReader void SetWidth(uint32_t _width) { width = _width; } uint32_t Flags() const { return flags; } uint32_t Width() const { return width; } + void SetMaxStringSize(uint32_t size) { max_string_size = size; } + uint32_t GetMaxStringSize() const { return max_string_size; } + void SetMaxVectorSize(uint32_t size) { max_vector_size = size; } + uint32_t GetMaxVectorSize() const { return max_vector_size; } + void SetInternalStreamState(std::ios_base::iostate state) { stream.setstate(state); } bool Ok() const { return !stream.fail(); } enum { @@ -43,6 +49,8 @@ class BinaryStreamReader std::istream& stream; uint32_t flags; uint32_t width; + uint32_t max_string_size = -1; + uint32_t max_vector_size = -1; }; template @@ -55,6 +63,12 @@ BinaryStreamReader& operator>>(BinaryStreamReader& cs, std::vector& vec else size = vec.size(); + if (size > cs.GetMaxVectorSize()) + { + cs.SetInternalStreamState(std::ios_base::failbit); + return cs; + } + vec.resize(size); VecType el; for (uint32_t i = 0; i < size; i++) diff --git a/replay/CMakeLists.txt b/replay/CMakeLists.txt index 3af6894..488578e 100644 --- a/replay/CMakeLists.txt +++ b/replay/CMakeLists.txt @@ -17,5 +17,7 @@ add_library( target_link_libraries( lc3_replay lc3 + ${Boost_LIBRARIES} ) +set_property(TARGET lc3_replay PROPERTY POSITION_INDEPENDENT_CODE ON) diff --git a/replay/lc3_replay.cpp b/replay/lc3_replay.cpp index b7d924a..f3ac095 100644 --- a/replay/lc3_replay.cpp +++ b/replay/lc3_replay.cpp @@ -79,7 +79,7 @@ std::string base64_decode(const std::string& str) } } -void lc3_setup_replay(lc3_state& state, std::string& filename, const std::string& replay_string, std::stringstream& newinput) +void lc3_setup_replay(lc3_state& state, const std::string& filename, const std::string& replay_string, std::stringstream& newinput) { std::ifstream file(filename.c_str()); @@ -97,6 +97,8 @@ void lc3_setup_replay(lc3_state& state, std::istream& file, const std::string& r std::istringstream stream(decoded); BinaryStreamReader bstream(stream); + bstream.SetMaxStringSize(65536); + bstream.SetMaxVectorSize(65536); char memory_strategy = 0; unsigned int memory_strategy_value = 0; @@ -114,11 +116,15 @@ void lc3_setup_replay(lc3_state& state, std::istream& file, const std::string& r unsigned int value; bstream >> id; + if (!bstream.Ok()) + throw "Error reading replay string."; if (id == END_OF_ENVIRONMENT) break; bstream >> value; + if (!bstream.Ok()) + throw "Error reading replay string."; switch (id) { @@ -187,12 +193,18 @@ void lc3_setup_replay(lc3_state& state, std::istream& file, const std::string& r std::vector params; bstream >> id; + if (!bstream.Ok()) + throw "Error reading replay string."; if (id == END_OF_INPUT) break; bstream >> label; + if (!bstream.Ok()) + throw "Error reading replay string."; bstream >> params; + if (!bstream.Ok()) + throw "Error reading replay string."; unsigned short address; int address_calc; @@ -220,6 +232,8 @@ void lc3_setup_replay(lc3_state& state, std::istream& file, const std::string& r } address = (unsigned short) address_calc; break; + default: + address = 0; } switch (id) @@ -317,6 +331,8 @@ std::string lc3_describe_replay(const std::string& replay_string) } } + description << "\n"; + while (bstream.Ok()) { unsigned char id; diff --git a/replay/lc3_replay.hpp b/replay/lc3_replay.hpp index ec148a8..f8d519c 100644 --- a/replay/lc3_replay.hpp +++ b/replay/lc3_replay.hpp @@ -2,6 +2,7 @@ #define LC3_REPLAY_HPP #include +#include #include void lc3_setup_replay(lc3_state& state, const std::string& filename, const std::string& replay_string, std::stringstream& newinput); diff --git a/tests/lc3_replay_test.cpp b/tests/lc3_replay_test.cpp index 560c94c..2612cc5 100644 --- a/tests/lc3_replay_test.cpp +++ b/tests/lc3_replay_test.cpp @@ -26,6 +26,7 @@ const std::vector REPLAY_DESCRIPTIONS = { "memory_strategy: fill_with_value", "memory_strategy_value: 4294967295", "breakpoint: x8000", +"", "R4 = (16385 x4001)", "PC = x0500", "MEM[AHH] = (7 x0007)",