This is a simple machine language simulator that handles basic operations such as read, write, load, store, add, subtract, multiply, divide, modulus, branch, branch if negative, branch if zero.
Inputs are gotten from the user in hexadecimal, the memory is simulated as a built-in array
of integers which can hold a maximum of 1 word.
A word consist of 4 digits, the first two represents the operand code (sml instruction code), the last two represents the operand (location in memory) The simulator also reads and output string literals.
Here is the code.
constants.h
constexpr unsigned read = 0xA; // Read a word(int) from the keyboard into a specific location in memory
constexpr unsigned write = 0xB; // Write a word(int) from a specific location in memory to the screen
constexpr unsigned read_str = 0xC; // Read a word(string) from the keyboard into a specific location in memory
constexpr unsigned write_str = 0xD; // Write a word(string) from a specific location in memory to the screen
constexpr unsigned load = 0x14; // Load a word from a specific location in memory to the accumulator
constexpr unsigned store = 0x15; // Store a word from the accumulator into a specific location in memory
constexpr unsigned add = 0x1E; /* Add a word from a specific location in memory to the word in the accumulator; store the
result in the accumulator */
constexpr unsigned subtract = 0x1F;
constexpr unsigned multiply = 0x20;
constexpr unsigned divide = 0x21;
constexpr unsigned modulo = 0x22;
constexpr unsigned branch = 0x28; // Branch to a specific location in the memory
constexpr unsigned branchneg = 0x29; // Branch if accumulator is negative
constexpr unsigned branchzero = 0x2A; // Branch if accumulator is zero
constexpr unsigned halt = 0x2B; // Halt the program when a task is completed
constexpr unsigned newline = 0x32; // Insert a new line
constexpr unsigned end = -0x1869F; // End the program execution
constexpr unsigned memory_size = 1000;
constexpr unsigned sml_debug = 0x2C; // SML debug
registers.h
int accumulator = 0;
unsigned instruction_counter = 0;
unsigned instruction_register = 0;
unsigned operation_code = 0;
unsigned operand = 0;
sml.h
#include "constants.h"
void memory_dump( int memory[memory_size], const unsigned &mem_size, const int &acc, const unsigned &ins_reg, \
const unsigned &ins_cnt, const unsigned &opr_code, const unsigned &opr );
void execute( int memory[memory_size], int &acc, unsigned &ins_reg, unsigned &ins_cnt, unsigned &opr_code, unsigned &opr ); // executes the statement in sequential manner
void evaluate( int memory[memory_size], int &acc, unsigned &ins_reg, unsigned &ins_cnt, unsigned &opr_code, unsigned &opr );
void display_welcome_message();
bool division_by_zero( int memory[ memory_size ], unsigned operand );
sml.cpp
#include <iostream>
#include <iomanip>
#include <string>
#include "sml.h"
int temp_cnt = 0; // holds instruction_counter when performing branch operation
std::string temp_str; // holds the string before it is written into the memory
bool debug = false;
void memory_dump( int memory[memory_size], const unsigned &mem_size, const int &acc, const unsigned &ins_reg, \
const unsigned &ins_cnt, const unsigned &opr_code, const unsigned &opr )
{
std::cout << "\nREGISTERS:\n";
std::cout << std::setw( 25 ) << std::left << std::setfill( ' ' ) << "accumulator" << std::showpos
<< std::setw( 5 ) << std::setfill( '0' ) << std::internal << acc << '\n';
std::cout << std::setw( 28 ) << std::left << std::setfill( ' ' )
<< "instruction counter" << std::noshowpos << std::setfill( '0' )
<< std::right << std::setw( 2 ) << ins_cnt << '\n';
std::cout << std::setw( 25 ) << std::left << std::setfill( ' ' )
<< "instruction register" << std::showpos << std::setw( 5 ) << std::setfill( '0' )
<< std::internal << ins_reg << '\n';
std::cout << std::setw( 28 ) << std::left << std::setfill( ' ' )
<< "operation code" << std::noshowpos << std::setfill( '0' )
<< std::right << std::setw( 2 ) << opr_code << '\n';
std::cout << std::setw( 28 ) << std::left << std::setfill( ' ' )
<< "operand" << std::noshowpos << std::setfill( '0' )
<< std::right << std::setw( 2 ) << opr << '\n';
std::cout << "\n\nMEMORY:\n";
std::cout << " ";
for( int i = 0; i != 10; ++i )
std::cout << std::setw( 6 ) << std::setfill( ' ') << std::right << i;
for( size_t i = 0; i != mem_size; ++i )
{
if( i % 10 == 0 )
std::cout << "\n" << std::setw( 3 ) << std::setfill( ' ' ) << i << " ";
std::cout << std::setw( 5 ) << std::setfill( '0' ) << std::showpos << std::internal << memory[ i ] << " ";
}
std::cout << std::endl;
}
void execute( int memory[memory_size], int &acc, unsigned &ins_reg, \
unsigned &ins_cnt, unsigned &opr_code, unsigned &opr )
{
int divisor;
while( memory[ ins_cnt ] != 0 )
{
ins_reg = memory[ ins_cnt++ ];
if( ins_reg < 1000 ) divisor = 0x10;
else if( ins_reg >= 1000 && ins_reg < 10000 ) divisor = 0x100;
else if( ins_reg >= 10000 && ins_reg < 100000 ) divisor = 0x1000;
opr_code = ins_reg / divisor;
opr = ins_reg % divisor ;
if( opr_code == halt )
break;
evaluate( memory, acc, ins_reg, ins_cnt, opr_code, opr );
if( debug )
memory_dump( memory, memory_size, acc, ins_reg, ins_cnt, \
opr_code, opr );
}
}
void evaluate( int memory[memory_size], int &acc, unsigned &ins_reg, \
unsigned &ins_cnt, unsigned &opr_code, unsigned &opr )
{
switch ( opr_code )
{
case read:
std::cin >> memory[ opr ];
break;
case read_str:
std::cin >> temp_str;
memory[ opr ] = temp_str.size();
for( int i = 1; i != temp_str.size() + 1; ++i )
memory[ opr + i ] = int( temp_str[ i - 1 ] );
break;
case write:
std::cout << memory[ opr ] << " ";
break;
case write_str:
for( int i = 0; i != memory[ opr ] + 1; ++i ) {
std::cout << char( memory[ opr + i ]);
}
break;
case load:
acc = memory[ opr ];
break;
case store:
memory[ opr ] = acc;
break;
case add:
acc += memory[ opr ];
break;
case subtract:
acc -= memory[ opr ];
break;
case multiply:
acc *= memory[ opr ];
break;
case divide:
if ( division_by_zero( memory, opr ) )
{
memory_dump( memory, memory_size, acc, ins_reg, ins_cnt, opr_code, opr );
exit( EXIT_FAILURE );
}
else
{
acc /= memory[ opr ];
break;
}
case modulo:
if( division_by_zero( memory, opr ) )
{
memory_dump( memory, memory_size, acc, ins_reg, ins_cnt, opr_code, opr );
exit( EXIT_FAILURE );
}
else
{
acc %= memory[ opr ];
break;
}
case branch:
temp_cnt = ins_cnt;
ins_cnt = opr;
execute( memory, acc, ins_reg, ins_cnt, opr_code, opr );
ins_cnt = temp_cnt;
break;
case branchneg:
if( acc < 0 )
{
temp_cnt = ins_cnt;
ins_cnt = opr;
execute( memory, acc, ins_reg, ins_cnt, opr_code, opr );
ins_cnt = temp_cnt;
}
break;
case branchzero:
if( acc == 0 )
{
temp_cnt = ins_cnt;
ins_cnt = opr;
execute( memory, acc, ins_reg, ins_cnt, opr_code, opr );
ins_cnt = temp_cnt;
}
break;
case newline:
std::cout << '\n' << std::flush;
break;
case sml_debug:
if ( opr == 1 ) debug = true;
else if ( opr == 0 ) debug = false;
else
{
std::cout << std::setw( 5 ) << std::setfill( ' ') << std::left << "***"
<< "Invalid debug mode"
<< std::setw( 5 ) << std::right << "***\n";
}
break;
default:
break;
}
}
void display_welcome_message () {
std::cout << "***" << " WELCOME TO SIMPLETRON! " << "***\n\n";
std::cout << std::setw( 5 ) << std::left << "***"
<< "Please enter your program one instruction"
<< std::setw( 5 ) << std::right << "***\n";
std::cout << std::setw( 5 ) << std::left << "***"
<< "(or data word) at a time. I will type the"
<< std::setw( 5 ) << std::right << "***\n";
std::cout << std::setw( 5 ) << std::left << "***"
<< "location number and a question mark (?)."
<< std::setw( 6 ) << std::right << "***\n";
std::cout << std::setw( 5 ) << std::left << "***"
<< "You then type the word for that location"
<< std::setw( 6 ) << std::right << "***\n";
std::cout << std::setw( 5 ) << std::left << "***"
<< "Type the sentinel -0x1869F to stop entering"
<< std::setw( 5 ) << std::right << "***\n";
std::cout << std::setw( 5 ) << std::left << "***"
<< "your program"
<< std::setw( 5 ) << std::right << "***";
std::cout << "\n\n" << std::flush;
}
bool division_by_zero( int memory[ memory_size ], unsigned operand )
{
if ( memory[ operand ] == 0 )
{
std::cout << std::setw( 5 ) << std::left << "***"
<< "Attempting division by zero"
<< std::setw( 5 ) << std::right << "***\n";
std::cout << std::setw( 5 ) << std::left << "***"
<< "Program terminated abnormally"
<< std::setw( 5 ) << std::right << "***\n";
std::cout << "\n";
return true;
}
return false;
}
main.cpp
#include <iostream>
#include <iomanip>
#include "registers.h"
#include "sml.h"
int main()
{
int memory[ memory_size ]{};
size_t memory_size = sizeof( memory )/ sizeof( memory[ 0 ] );
int temp;
display_welcome_message();
while( instruction_counter != memory_size )
{
std::cout << std::setw( 2 ) << std::setfill( '0' )
<< instruction_counter << " ? ";
std::cin >> std::hex >> temp;
if( temp == end ) {
break;
}
if( temp >= -0xB3E8 && temp < 0xB3E8 )
memory[ instruction_counter++ ] = temp;
else
continue;
}
instruction_counter = 0;
std::cout << std::setfill( ' ' );
std::cout << std::setw( 5 ) << std::left << "***"
<< "Program loaded into memory"
<< std::setw( 5 ) << std::right << "***\n";
std::cout << std::setw( 5 ) << std::left << "***"
<< "Program execution starts..."
<< std::setw( 5 ) << std::right << "***\n";
execute( memory, accumulator, instruction_register, instruction_counter, operation_code, operand );
std::cout << std::endl;
}