disasm/sim: changed interface, added readline to sim
authorMartin Perner <martin@perner.cc>
Sat, 30 Oct 2010 23:04:41 +0000 (01:04 +0200)
committerMartin Perner <martin@perner.cc>
Sun, 31 Oct 2010 12:38:31 +0000 (13:38 +0100)
14 files changed:
3b_sim/Makefile.flags
3b_sim/SReadline/SReadline.h [new file with mode: 0644]
3b_sim/ccpu.cpp
3b_sim/cdat.hpp
3b_sim/cmem.cpp
3b_sim/cmem.hpp
3b_sim/sim.cpp
3c_disasm/instr/Makefile
3c_disasm/instr/add.cpp
3c_disasm/instr/addi.cpp
3c_disasm/instr/branch.cpp
3c_disasm/instr/ldi.cpp
3c_disasm/instr/ldw.cpp
3c_disasm/instr/subi.cpp

index dfd097ce1f2b7f3df17c1711fa318035f23d7078..50f7e14ec8e5d9cf9b59cffca3773a6669248966 100644 (file)
@@ -2,5 +2,5 @@ CC := g++
 
 CPPFLAGS = -g3 -O2 -std=c++0x -Wnon-virtual-dtor -Weffc++ -pedantic -Werror -Wall -Wextra -W -Wshadow -fno-common -pedantic-errors -Wpointer-arith -Wcast-qual -Wcast-align -Woverloaded-virtual -Wswitch-default -Wempty-body -Wlogical-op
 
-CPPPROGOPT=-rdynamic -ldl -lboost_program_options
+CPPPROGOPT=-rdynamic -ldl -lboost_program_options -lreadline
 CPPLIBOPT=-shared
diff --git a/3b_sim/SReadline/SReadline.h b/3b_sim/SReadline/SReadline.h
new file mode 100644 (file)
index 0000000..de7e5ae
--- /dev/null
@@ -0,0 +1,632 @@
+/*!
+    @file  SReadline.h
+    @brief C++ wrapper around libreadline.
+           Supported: editing, history, custom completers, keymaps.
+           Attention: implementation is not thread safe!
+                      It is mainly because the readline library provides
+                      pure C interface and has many calls for an "atomic" 
+                      completion operation
+ */
+//
+// Date:      17 December 2005
+//            03 April    2006
+//            20 April    2006
+//            07 May      2006
+//
+// Copyright (c) Sergey Satskiy 2005 - 2006
+//               <sergesatsky@yahoo.com>
+//
+// Permission to copy, use, modify, sell and distribute this software 
+// is granted provided this copyright notice appears in all copies. 
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+
+#ifndef SREADLINE_H
+#define SREADLINE_H
+
+#include <stdio.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <readline/keymaps.h>
+
+#include <string>
+#include <fstream>
+#include <vector>
+#include <stdexcept>
+#include <map>
+
+#include <boost/algorithm/string/trim.hpp>
+#include <boost/tokenizer.hpp>
+#include <boost/function.hpp>
+
+
+    /*! @brief Used to avoid linking errors in case
+               of including into many compilation units
+     */
+namespace
+{
+        //! @brief Tokens in a single variation of a user command
+    typedef std::vector< std::string >              TokensStorage;
+        //! @brief Set of variations of user commands
+    typedef std::vector< TokensStorage >            CompletionsStorage;
+        //! @brief Pressed key callback. Must return 0 if OK, != 0 otherwise
+    typedef boost::function< int ( int, int ) >     KeyCallback;
+        //! @brief A set of keys binding
+    typedef std::map< int, KeyCallback >            KeysBind;
+
+    
+    const size_t                    DefaultHistoryLimit( 64 );  //!< Default value for the history length
+    CompletionsStorage              Completions;                //!< Global storage of custom completions
+    TokensStorage                   Tokens;                     //!< Tokens storage for a single completion session
+    std::map< Keymap, KeysBind >    Keymaps;                    //!< Global storage for keymaps
+
+    bool                            KeymapWasSetup( false );    //!< Has sense if a keymap was
+                                                                //!< setup before the first readline call
+    Keymap                          Earlykeymap( 0 );           //!< The keymap which was setup before the first readline call
+
+
+        /*! @brief Custom completion generator
+            @param text Pointer to a token to be completed
+            @param State 0 for a first call, non 0 for all consequent calls
+         */
+    char * Generator( const char *  text, int  State );
+
+    
+        /*! @brief The function is called before trying to complete a token
+            @param text A token to be completed
+            @param start Index of the beginning of the token in the readline buffer
+            @param end   Index of the end of the token in the readline buffer
+         */
+    char ** UserCompletion( const char * text,
+                            int          start,
+                            int          end );
+
+
+        /*! @brief The function selects the set of bindings and 
+                   makes the corresponding call.
+            @param Count The parameter is passed by readline
+            @param Key   The pressed key
+         */
+    int  KeyDispatcher( int  Count, int  Key );
+
+
+        /*! @brief The readline startup hook. It is required to setup the proper keymap.
+         */
+    int  StartupHook( void );
+
+    
+        /*! @brief Compares all the Input tokens with starts tokens in the Pattern
+            @param Pattern pattern tokens
+            @param Input user input tokens
+            @return true if first Input.size() tokens are equal to the pattern tokens
+         */
+    template < typename  Container >
+    bool AreTokensEqual( const Container &  Pattern, 
+                         const Container &  Input )
+    {
+        if ( Input.size() > Pattern.size() ) return false;
+
+        typename Container::const_iterator  k( Pattern.begin() );
+        typename Container::const_iterator  j( Input.begin() );
+        for ( ; j != Input.end(); ++k, ++j )
+        {
+            if ( *k == "%file" ) continue;
+            if ( *k != *j )      return false;
+        }
+        return true;
+    }
+
+
+        // See description near the prototype
+    template < typename  ContainerType >
+    void SplitTokens( const std::string &  Source, ContainerType &  Container )
+    {
+        typedef boost::tokenizer< boost::char_separator< char > >       TokenizerType;
+
+        boost::char_separator<char>     Separators( " \t\n" );              // Set of token separators
+        TokenizerType                   Tokenizer( Source, Separators );    // Tokens provider
+        std::string                     SingleToken;                        // Temporary storage for a token
+        
+        Container.clear();
+        for ( TokenizerType::const_iterator  k( Tokenizer.begin() ); k != Tokenizer.end(); ++k )
+        {
+            SingleToken = *k;
+            boost::algorithm::trim( SingleToken );
+            Container.push_back( SingleToken );
+        }
+    }
+
+    
+        // See description near the prototype
+    char ** UserCompletion( const char *  text, int  start, int  /*end*/ )
+    {
+            // No default completion at all
+        rl_attempted_completion_over = 1;
+
+        if ( Completions.empty() )  return NULL;
+
+            // Memorize all the previous tokens
+        std::string     PreInput( rl_line_buffer, start );
+        SplitTokens( PreInput, Tokens );
+
+
+            // Detect whether we should call the standard file name completer or a custom one
+        bool    FoundPretender( false );
+
+        for ( CompletionsStorage::const_iterator  k( Completions.begin() ); k != Completions.end(); ++k )
+        {
+            if ( ! AreTokensEqual( *k, Tokens ) ) continue;
+
+            if ( (*k).size() > Tokens.size() )
+            {
+                FoundPretender = true;
+                if ( (*k)[ Tokens.size() ] == "%file" )
+                {
+                        // Standard file name completer - called for the "%file" keyword
+                    return rl_completion_matches( text, rl_filename_completion_function );
+                }
+            }
+        }
+        
+        if ( FoundPretender )
+        {
+            return rl_completion_matches( text, Generator );
+        }
+        return NULL;
+    }
+    
+   
+
+        // See description near the prototype
+    char * Generator( const char *  text, int  State )
+    {
+        static int                                  Length;
+        static CompletionsStorage::const_iterator   Iterator;
+
+        
+        if ( State == 0 )
+        {
+            Iterator = Completions.begin();
+            Length = strlen( text );
+        }
+
+        for ( ; Iterator != Completions.end(); ++Iterator )
+        {
+            if ( ! AreTokensEqual( *Iterator, Tokens ) ) continue;
+
+            if ( (*Iterator).size() > Tokens.size() )
+            {
+                if ( (*Iterator)[ Tokens.size() ] == "%file" ) continue;
+
+            
+                if ( strncmp( text, (*Iterator)[ Tokens.size() ].c_str(), Length ) == 0 )
+                {
+                        // readline will free the allocated memory
+                    char *  NewString( (char*)malloc( strlen( (*Iterator)[ Tokens.size() ].c_str() ) + 1 ) );
+                    strcpy( NewString, (*Iterator)[ Tokens.size() ].c_str() );
+                    ++Iterator;
+                    return NewString;
+                }
+            }
+        }
+       
+        return NULL;
+    }
+
+    
+        // See the description near the prototype
+    int  KeyDispatcher( int  Count, int  Key )
+    {
+        std::map< Keymap, KeysBind >::iterator  Set( Keymaps.find( rl_get_keymap() ) );
+        if ( Set == Keymaps.end() )
+        {
+                // Most probably it happens bacause the header was 
+                // included into many compilation units and the
+                // keymap setting calls were made in different files.
+                // This is the problem of "global" data.
+                // The storage of all the registered keymaps is in anonymous
+                // namespace.
+            throw std::runtime_error( "Error selecting a keymap." );
+        }
+
+        (Set->second)[ Key ]( Count, Key );
+        return 0;
+    }
+
+
+        // See the description near the prototype
+    int  StartupHook( void )
+    {
+        if ( KeymapWasSetup )
+        {
+            rl_set_keymap( Earlykeymap );
+        }
+        return 0;
+    }
+
+}   // Anonymous namespace
+
+
+
+
+    /*! @brief The wrapper namespace. 
+               The namespace is also used for other library elements.
+     */
+namespace swift 
+{
+
+        /*! @brief The readline keymap wrapper.
+                   Attention: It is not thread safe!
+                   Supports: key binding, key unbinding
+         */
+    class SKeymap
+    {
+        private:
+            Keymap      keymap;     // Readline keymap
+            
+        public:
+                /*! @brief Creates a new keymap
+                    @param PrintableBound if true - the printable characters are bound
+                                          if false - the keymap is empty
+                 */                  
+            explicit SKeymap( bool  PrintableBound = false ) : 
+                keymap( NULL )
+            {
+                if ( PrintableBound )
+                {
+                    keymap = rl_make_keymap();      // Printable characters are bound
+                }
+                else
+                {
+                    keymap = rl_make_bare_keymap(); // Empty keymap
+                }
+
+                if ( keymap == NULL )
+                {
+                    throw std::runtime_error( "Cannot allocate keymap." );
+                }
+
+                    // Register a new keymap in the global list
+                Keymaps[ keymap ] = KeysBind();
+            }
+            
+                /*! @brief Creates a new keymap which is a copy of Pattern
+                    @param Pattern A keymap to be copied
+                 */
+            explicit SKeymap( Keymap   Pattern ) :
+                keymap( rl_copy_keymap( Pattern ) )
+            {
+                if ( keymap == NULL )
+                {
+                    throw std::runtime_error( "Cannot allocate keymap." );
+                }
+                
+                    // Register a new keymap in the global list
+                Keymaps[ keymap ] = KeysBind();
+            }
+
+                /*! @brief Frees the allocated keymap
+                 */
+            ~SKeymap()
+            {
+                    // Deregister the keymap
+                Keymaps.erase( keymap );
+                rl_discard_keymap( keymap );
+            }
+
+                /*! @brief Binds the given key to a function
+                    @param Key A key to be bound
+                    @param Callback A function to be called when the Key is pressed
+                 */
+            void Bind( int  Key, KeyCallback  Callback )
+            {
+                Keymaps[ keymap ][ Key ] = Callback;
+                if ( rl_bind_key_in_map( Key, KeyDispatcher, keymap ) != 0 )
+                {
+                        // Remove from the map just bound key
+                    Keymaps[ keymap ].erase( Key );
+                    throw std::runtime_error( "Invalid key." );
+                }
+            }
+
+
+                /*! @brief Unbinds the given key
+                    @param Key A key to be unbound
+                 */
+            void Unbind( int  Key )
+            {
+                rl_unbind_key_in_map( Key, keymap );
+                Keymaps[ keymap ].erase( Key );
+            }
+
+            // void Bind( const std::string &  Sequence, boost::function< int ( int, int ) > );
+            // void Unbind( std::string &  Sequence );
+
+        public:
+                /*! @brief Copy constructor
+                    @param rhs Right hand side object of SKeymap
+                 */
+            SKeymap( const SKeymap &  rhs ) : keymap(0)
+            {
+                if ( this == & rhs )
+                {
+                    return;
+                }
+                keymap = rl_copy_keymap( rhs.keymap );
+            }
+
+                /*! @brief operator=
+                    @param rhs Right hand side object of SKeymap
+                 */
+            SKeymap &  operator=( const SKeymap &  rhs )
+            {
+                if ( this == & rhs )
+                {
+                    return *this;
+                }
+                keymap = rl_copy_keymap( rhs.keymap );
+                return *this;
+            }
+            
+            friend class SReadline;
+    };
+    
+
+        /*! @brief The readline library wrapper.
+                   Attention: It is not thread safe!
+                   Supports: editing, history, custom completers
+         */
+    class SReadline
+    {
+        public:
+                /*! @brief Constructs the object, sets the completion function
+                    @param Limit History size
+                 */
+            SReadline( const size_t  Limit = DefaultHistoryLimit ) : 
+                HistoryLimit( Limit ),
+                HistoryFileName( "" ), 
+                OriginalCompletion( rl_attempted_completion_function )
+            {
+                rl_startup_hook = StartupHook;
+                rl_attempted_completion_function = UserCompletion;
+                using_history();
+            }
+            
+                /*! @brief Constructs the object, sets the completion function, loads history
+                    @param historyFileName File name to load history from
+                    @param Limit History size
+                 */
+            SReadline( const std::string &  historyFileName,
+                       const size_t  Limit = DefaultHistoryLimit ) :
+                HistoryLimit( Limit ),
+                HistoryFileName( historyFileName ),
+                OriginalCompletion( rl_attempted_completion_function )
+            {
+                rl_startup_hook = StartupHook;
+                rl_attempted_completion_function = UserCompletion;
+                using_history();
+                LoadHistory( HistoryFileName );
+            }
+
+                /*! @brief Saves the session history (if the file name was provided) 
+                           and destroys the object
+                 */
+            ~SReadline()
+            {
+                rl_attempted_completion_function = OriginalCompletion;
+                SaveHistory( HistoryFileName );
+            }
+
+                /*! @brief Gets a single line from a user
+                    @param Prompt A printed prompt
+                    @return A string which was actually inputed
+                 */
+            std::string  GetLine( const std::string &  Prompt )
+            {
+                bool    Unused;
+                return GetLine( Prompt, Unused );
+            }
+            
+
+                /*! @brief Gets a single line from a user
+                    @param Prompt A printed prompt
+                    @param ReadTokens A user inputed string splitted into tokens. 
+                           The container is cleared first
+                    @return A string which was actually inputed
+                 */
+            template < typename  Container >
+            std::string  GetLine( const std::string &  Prompt,
+                                  Container &          ReadTokens )
+            {
+                bool    Unused;
+                return GetLine( Prompt, ReadTokens, Unused );
+            }
+
+
+                /*! @brief Gets a single line from a user
+                    @param Prompt A printed prompt
+                    @param BreakOut it is set to true if the EOF found
+                    @param ReadTokens A user inputed string splitted into tokens.
+                           The container is cleared first
+                    @return A string which was actually inputed
+                 */
+            template < typename  Container >
+            std::string  GetLine( const std::string &  Prompt,
+                                  Container &          ReadTokens,
+                                  bool &               BreakOut )
+            {
+                std::string     Input( GetLine( Prompt, BreakOut ) );
+                SplitTokens( Input, ReadTokens );
+                return Input;
+            }
+
+
+                /*! @brief Gets a single line from a user
+                    @param Prompt A printed prompt
+                    @param BreakOut it is set to true if the EOF found
+                    @return A string which was actually inputed
+                 */
+            std::string  GetLine( const std::string &  Prompt, 
+                                  bool &               BreakOut )
+            {
+                BreakOut = true;
+
+                char *  ReadLine( readline( Prompt.c_str() ) );
+                if ( ReadLine == NULL ) return std::string();
+                
+                    // It's OK
+                BreakOut = false;
+                std::string     Input( ReadLine );
+                free( ReadLine );
+
+                boost::algorithm::trim( Input );
+                if ( !Input.empty() )
+                {
+                    if ( (history_length == 0) ||
+                         (Input != history_list()[ history_length - 1 ]->line)
+                       )
+                    {
+                        add_history( Input.c_str() );
+                        if ( history_length >= static_cast< int >( HistoryLimit ) )
+                        {
+                            stifle_history( HistoryLimit );
+                        }
+                    }
+                }
+
+                return Input;
+            }
+
+
+                /*! @brief Fills the given container with the current history list
+                           Does not clear the given container
+                 */
+            template < typename ContainerType >
+            void GetHistory( ContainerType &  Container )
+            {
+                for ( int  k( 0 ); k < history_length; ++k )
+                {
+                    Container.push_back( history_list()[ k ]->line );
+                }
+            }
+
+                /*! @brief Saves the history to the given file stream
+                    @param OS output file stream
+                    @return true if success
+                 */
+            bool SaveHistory( std::ostream & OS )
+            {
+                if ( ! OS ) return false;
+                for ( int  k( 0 ); k < history_length; ++k )
+                {
+                    OS << history_list()[ k ]->line << std::endl;
+                }
+                return true;
+            }
+
+                /*! @brief Saves the history to the given file
+                    @param FileName File name to save the history to
+                    @return true if success
+                 */
+            bool SaveHistory( const std::string &  FileName )
+            {
+                if ( FileName.empty() ) return false;
+
+                std::ofstream  OS( FileName.c_str() );
+                return SaveHistory( OS );
+            }
+
+                /*! @brief Clears the history. Does not affect the file where
+                           the previous session history is saved.
+                 */
+            void ClearHistory()
+            {
+                clear_history();
+            }
+            
+
+                /*! @brief Loads a history from a file stream
+                    @param IS Input file stream
+                    @return true if success
+                 */
+            bool LoadHistory( std::istream &  IS )
+            {
+                if ( ! IS ) return false;
+
+                ClearHistory();
+                std::string     OneLine;
+
+                while ( ! getline( IS, OneLine ).eof() )
+                {
+                    boost::algorithm::trim( OneLine );
+                    if ( (history_length == 0) ||
+                         (OneLine != history_list()[ history_length - 1 ]->line)
+                       )
+                    {
+                        add_history( OneLine.c_str() );
+                    }
+                }
+                stifle_history( HistoryLimit );
+                return true;
+            }
+            
+                /*! @brief Loads a history from the given file
+                    @param FileName File name to be load from
+                    @return true if success
+                 */
+            bool LoadHistory( const std::string &  FileName )
+            {
+                if ( FileName.empty() ) return false;
+
+                std::ifstream   IS( FileName.c_str() );
+                return LoadHistory( IS );
+            }
+
+                /*! @brief Allows to register custom completers.
+                           Supports a special keyword: %file. It means to use the standard file name completer
+                           For example the given container elements could be as follows:
+                               command1 opt1
+                               command1 opt2 %file
+                               command2
+                               command2 opt1
+                           Each container element must describe a single possible command line
+                           The container element must have a conversion to std::string operator
+                    @param Container A container which has all the user possible commands
+                 */       
+            template < typename  ContainerType >
+            void RegisterCompletions( const ContainerType &  Container )
+            {
+                Completions.clear();
+                for ( typename ContainerType::const_iterator  k( Container.begin() );
+                      k != Container.end(); ++k )
+                {
+                    std::vector< std::string >  OneLine;
+                    SplitTokens( (*k).get<0>(), OneLine );
+                    Completions.push_back( OneLine );
+                }
+            }
+
+                
+                /*! @brief Sets the given keymap
+                    @param NewKeymap The keymap that should be used from now
+                 */
+            void  SetKeymap( SKeymap &  NewKeymap )
+            {
+                rl_set_keymap( NewKeymap.keymap );
+                KeymapWasSetup = true;
+                Earlykeymap = NewKeymap.keymap;
+            }
+
+        private:
+            const size_t            HistoryLimit;       //!< Constructor accepted or default
+            const std::string       HistoryFileName;    //!< Original constructor accepted
+            rl_completion_func_t *  OriginalCompletion; //!< Original state will be restored
+    };
+
+
+} // namespace swift
+
+#endif 
+
index 3fee8752cf020539e12e78d511771c8ff6f9fc73..00b84f6e6f6c24cfaa5b82ec53dc64c8a104271e 100644 (file)
@@ -18,8 +18,13 @@ void CCpu::tick()
                throw string("Out of Instructions!");
        }
        if(this->conditionMet(instr->getCondition())) {
+               cout << "Executing: " << instr->toString() << endl;
                instr->execInstr();
        }
+       else {
+               cout << "Didn't Execute " << instr->toString() << "; condition wasn't met" << endl;
+       }
+
 }
 
 bool CCpu::conditionMet(short cond)
index e9f88f6f93156657238620d78c951d4a469f56c8..39ea074a4e251a420d162a220c740369fef4c4c2 100644 (file)
@@ -4,9 +4,10 @@
 #include <string>
 #include <sstream>
 
-typedef int CDat;
+typedef __UINT32_TYPE__ CDat;
+typedef __UINT64_TYPE__ CDatd;
 
 #define BIT_LEN 32
-
-//static_assert(sizeof(CDat) == 4, "The size of the datatype for int is NOT 4 bytes (32 Bit!)");
+static_assert(sizeof(CDat) == 4, "The size of the datatype for int is NOT 4 bytes (32 Bit!)");
+static_assert(sizeof(CDatd) > 4, "The size of the datatype for double int is NOT bigger than 4 bytes (32 Bit!)");
 #endif
index 22c80e6722b2b5f0340bd290133d96c5b57540af..4b49a081b5560d49871f68786e5f728c1c1dc94d 100644 (file)
@@ -3,7 +3,7 @@
 using namespace std;
 
 template <typename T>
-void CMem<T>::set(const MEMORY_ADDRESS address, const T& data)
+void CMem<T>::set(const MEMORY_ADDRESS address, const T data)
 {
        if(address >= MAX_MEMORY) {
                stringstream error;
@@ -35,4 +35,4 @@ T CMem<T>::get(const MEMORY_ADDRESS address) const
 }
 
 
-template class CMem<int>;
+template class CMem<CDat>;
index d5cd593704290ae31f1dae36e44fd614eb17a8ff..05739dbcb037b31f2445de3ddca4ac7a756ec7f0 100644 (file)
@@ -21,7 +21,7 @@ private:
        const int MAX_MEMORY;
        std::vector<T> m_memory;
 public:
-       void set(const MEMORY_ADDRESS address, const T& data);
+       void set(const MEMORY_ADDRESS address, const T data);
        T get(const MEMORY_ADDRESS address) const;
        CMem(int size) : MAX_MEMORY(size), m_memory(size) {};
 };
index 9d2fb5a00d259c23ce42cd930958fdb166f2e9c4..5cc89e44486a0b1f77bd038805bc4b41fd6d2d43 100644 (file)
 #include <iostream>
+#include <iomanip>
 #include <fstream>
 #include <boost/tokenizer.hpp>
 #include <boost/program_options.hpp>
 #include <boost/lexical_cast.hpp>
 #include <string>
 #include <map>
+#include <list>
+
+#include <boost/function.hpp>
+#include <boost/functional.hpp>
+#include <boost/tuple/tuple.hpp>
 
 #include "disasm.h"
 #include "ccpu.hpp"
 #include "CInstrFactory.hpp"
 #include "uint32_from_hex.hpp"
 
+#include "SReadline/SReadline.h"
+using namespace swift;
+
+typedef boost::function<void (const vector<string> &)> Func;
+typedef boost::tuple<string, Func> CompleterElement;
+
+typedef list<CompleterElement> MyCompleterContainer;
+
+class LookupFunctor
+{
+       public:
+               // Creates a functor and memorises tokens
+               LookupFunctor(const vector<string>&  tokens) : Tokens(tokens) {}
+
+               // Compares the first token only
+               bool operator()(const CompleterElement& ele) const
+               {
+                       return (strncmp(Tokens.begin()->c_str(), ele.get<0>().c_str(), Tokens.begin()->size()) == 0);
+               }
+
+       private:
+               const vector<string> &Tokens;
+};
+
+
+
+
+class CHelpExec
+{
+       private:
+               const MyCompleterContainer &m_completers;
+
+       public:
+               CHelpExec(const MyCompleterContainer &cont) : m_completers(cont) {}
+
+               void operator() (const vector<string>&)
+               {
+                       cout << "Available commands: " << endl;
+                       for(auto iter = m_completers.begin(); iter != m_completers.end(); ++iter) {
+                               cout << (*iter).get<0>() << endl;
+                       }
+               }
+};
+
+void close_prog(const std::vector<std::string> &);
+
 CCpu* Iinstr::m_cpu;
 
+CCpu* global_cpu = NULL;
+
+void doExit(const vector<string>&)
+{
+       exit(EXIT_SUCCESS);
+}
+
+void execStep(const vector<string>& in)
+{
+       int count = 1;
+       if(in.size() == 2) {
+               try {
+                       count = lexical_cast<int>(in.back());
+               }
+               catch(bad_cast&) {
+                       cerr << "given parameter to step is not a number" << endl;
+               }
+       }
+       while(count > 0) {
+               try {
+                       global_cpu->tick();
+               }
+               catch(std::string& e) {
+                       cerr << e << endl;
+               }
+               count--;
+       }
+}
+
+void printReg(const vector<string>&)
+{
+       int i, start = 0, end = 15;
+       /* Todo: 
+        * 1) make 2 columns
+        * 2) let use select registers to show (one register, range of registers)
+        */
+       
+       for(i = start; i <= end; i++) {
+               cout << setw(2) << i << ": 0x" << std::hex << setw(8) << setfill('0') << global_cpu->getRegister(i) << std::dec << endl;
+       }
+}
+
+
 using boost::lexical_cast;
 using boost::bad_lexical_cast;
 
@@ -84,9 +179,10 @@ int main(int argc, char* argv[])
                exit(EXIT_FAILURE);
        }
 
-
        CCpu cpu(16,1000,1000);
 
+       global_cpu = &cpu;
+
        Iinstr::setCPU(&cpu);
 
 
@@ -162,7 +258,7 @@ int main(int argc, char* argv[])
 
        cout << endl;
 
-
+/*
        for(int i = 0; i <= 32; i += 4) {
                Iinstr *pinstr = cpu.getProg(i);
                if(pinstr != NULL) {
@@ -177,7 +273,7 @@ int main(int argc, char* argv[])
                CDat data = cpu.getRAM(i);
                cout << i << " : " << std::hex << i << std::dec << " " << data << endl;
        }
-
+*/
        cpu.setRegister(1, 4);
        cpu.setRegister(2, 0);
        cpu.setRAM(0,5);
@@ -191,6 +287,64 @@ int main(int argc, char* argv[])
        //set return to nowhere for ret
        cpu.setRAM(500,50);
 
+       SReadline Reader;
+
+       MyCompleterContainer Completers;
+
+       CHelpExec HelpExec(Completers);
+
+       Completers.push_back(CompleterElement("help", boost::bind1st( boost::mem_fun( &CHelpExec::operator()), &HelpExec)));
+       Completers.push_back(CompleterElement("quit", &doExit));
+       Completers.push_back(CompleterElement("exit", &doExit));
+       Completers.push_back(CompleterElement("q", &doExit));
+       Completers.push_back(CompleterElement("step [count]",&execStep));
+       Completers.push_back(CompleterElement("reg",&printReg));
+
+       Reader.RegisterCompletions(Completers);
+
+       string UserInput;
+       vector<string> Tokens, lastTokens;
+       bool EndOfInput = false;
+
+       auto Found(Completers.end());
+
+       Func lastFunc = NULL;
+
+
+       while(1) {
+               UserInput = Reader.GetLine("> ", Tokens, EndOfInput);
+               if(EndOfInput) {
+                       break;
+               }
+
+               if(!Tokens.empty()) {
+                       Found = find_if(Completers.begin(), Completers.end(), LookupFunctor(Tokens));
+
+                       if(Found != Completers.end()) {
+                               if((*Found).get<1>() != 0) {
+                                       lastFunc = (*Found).get<1>();
+                                       lastFunc(Tokens);
+                                       lastTokens = Tokens;
+                                       //(*Found).get<1>()(Tokens);
+                               }
+                       }
+                       else {
+                               lastFunc = NULL;
+                               cout << "Unknown command. 'help' displays help" << endl;
+                       }
+               }
+               else {
+                       if(lastFunc != NULL) {
+                               lastFunc(lastTokens);
+                       }
+                       else {
+                               cout << "Unknown command. 'help' displays help" << endl;
+                       }
+               }
+       }
+
+
+/*
        for(int i = 0; ; i++) {
                try {
                        cpu.tick();
@@ -205,6 +359,6 @@ int main(int argc, char* argv[])
                        break;
                }
        }
-
+*/
        return EXIT_SUCCESS;
 }
index e0e553a69a1449722f5b7aaf53f5ab49f73b4746..e010bfe7da3d0ecde74131121bc463c77534f9ff 100644 (file)
@@ -7,7 +7,7 @@ all: $(libs:.cpp=.so)
 
 
 $(libs:.cpp=.so): ${@:.so=.d}
-       $(CC) -fPIC -I../ -c  -o ${@:.so=.o} ${@:.so=.cpp}
+       $(CC) $(CPPFLAGS) -fPIC -I../ -c  -o ${@:.so=.o} ${@:.so=.cpp}
        $(CC) $(CPPLIBOPT) -Wl,-soname,${@} -o ${@} ${@:.so=.o}
 
 .PHONY:clean
index f196794d3d45a82e50ff298d25d83a9100e94ccd..6651989f6a656e57904fa68e3bdb490950a9cc34 100644 (file)
@@ -58,7 +58,7 @@ void Cadd::evalInstr()
 
 void Cadd::execInstr()
 {
-       cout << "should exec " << this->toString() << endl;
+       //cout << "should exec " << this->toString() << endl;
        CDat val = this->m_cpu->getRegister(m_ra) + this->m_cpu->getRegister(m_rb);
        this->m_cpu->setRegister(m_rd, val);
        this->m_cpu->updateFlags(val);
index bb10a08af3f47476786339779967533f7eb5df41..2bcab659797840cbf4ce6373a1f0bec2254fc0b5 100644 (file)
@@ -62,7 +62,7 @@ void Caddi::evalInstr()
 
 void Caddi::execInstr()
 {
-       cout << "should exec " << this->toString() << endl;
+       //cout << "should exec " << this->toString() << endl;
        CDat reg = this->m_cpu->getRegister(m_ra) + this->m_imm;
        this->m_cpu->setRegister(m_rd, reg);
        this->m_cpu->updateFlags(reg);
index 90a56cbce8258d2a882f1ade81f48015784fdeb4..405acc0854acaa53e6e7581a828390c4b935b519 100644 (file)
@@ -82,7 +82,7 @@ void Cbranch::evalInstr()
 
 void Cbranch::execInstr()
 {
-       cout << "should exec " << this->toString() << endl;
+       //cout << "should exec " << this->toString() << endl;
        CDat pc = this->m_cpu->getCurPC();
        switch(this->m_typ) {
                case 1:
index 98e72cae80a54ac0f54d5a9a94bb06b80abea34f..095a1447ffb75688ad7305bbd7e580eac3be97c4 100644 (file)
@@ -58,7 +58,7 @@ void Cldi::evalInstr()
 
 void Cldi::execInstr()
 {
-       cout << "should exec " << this->toString() << endl;
+       //cout << "should exec " << this->toString() << endl;
        this->m_cpu->setRegister(this->m_rd, this->m_imm);
 }
 
index 354e23fa28dc24c30d6e34d9099a35534140e44f..6420a5517d204fb501df6816243eaef63beb31e5 100644 (file)
@@ -60,7 +60,7 @@ void Cldw::evalInstr()
 
 void Cldw::execInstr()
 {
-       cout << "should exec " << this->toString() << endl;
+       //cout << "should exec " << this->toString() << endl;
        CDat val = this->m_cpu->getRegister(this->m_ra);
        val += m_imm;
        val = this->m_cpu->getRAM(val);
index 8a90ae825f308b1ebf907ea60a9f40ba9743a028..90bdd5f95e72df6444b1783de2f58f30801709c4 100644 (file)
@@ -61,7 +61,7 @@ void Csubi::evalInstr()
 
 void Csubi::execInstr()
 {
-       cout << "should exec " << this->toString() << endl;
+       //cout << "should exec " << this->toString() << endl;
        CDat reg = this->m_cpu->getRegister(m_ra) - this->m_imm;
        this->m_cpu->setRegister(m_rd, reg);
        this->m_cpu->updateFlags(reg);