Actions

Difference between revisions of "Design of sxgo"

From Just in Time

 
(18 intermediate revisions by the same user not shown)
Line 1: Line 1:
This page describes the main design ideas behind [[sxgo]]. The implementation of this microcontroller emulator revolves around a few main ideas:
+
[[Sxgo]] constists of a core emulator library, a graphical UI and, alternatively, a set of Python bindings. This page describes the design of the core emulator. The implementation of this emulator revolves around a few main ideas:
  
 +
* a class that emulates the state of an SX, with member functions for each SX instruction.
 
* a meta-programmed list of instructions
 
* a meta-programmed list of instructions
 
* using meta programming to create a binary decision tree of those instructions for use in an instruction decoder.
 
* using meta programming to create a binary decision tree of those instructions for use in an instruction decoder.
Line 9: Line 10:
 
==Instruction Implementation==
 
==Instruction Implementation==
 
===implementation of the SX emulator===
 
===implementation of the SX emulator===
The idea is to have one class that consists of an SX 'state' (ram, rom, special registers, program counter) and that implements the instruction set. See the snippet (of file ''sx_controller.hpp'')below:
+
The idea is to have one class that consists of an SX 'state' (ram, rom, special registers, program counter) and that implements the instruction set. See the snippet (of file [https://github.com/DannyHavenith/sxsim/blob/master/sxsim/sx_controller.hpp sx_controller.hpp])below:
  
 
<source lang="cpp">
 
<source lang="cpp">
Line 42: Line 43:
 
</source>
 
</source>
  
As you can see, most instructions become very simple member functions and their implementation is quite readable. You may notice something odd: instead of naming member functions ''clr_frw'' or ''clr_w'', they're all called ''execute'' and take some--otherwise ignored--first argument of some type with names like ''clr_frw''. The reason for this is best explained after some explanation of the implementation of the [[#Instruction set|instruction set]] and the [[#Instruction decoder|instruction decoder]]. It has all to do with the fact that the instruction set is defined independently of it's implementaton and in fact there is more than one implementation of the instructions.
+
In C++ terms, this means that an implementation of the SX instruction set needs to ''model'' the [http://en.wikipedia.org/wiki/Concepts_%28C%2B%2B%29 Concept] of SXImplementation. Where (informally) the concept of SXImplementation is any class that implements one of the following member functions for each of the tags that are in the SX instruction set.
 +
<source lang="cpp">
 +
void execute( const tag &);
 +
void execute( const tag &, int arg);
 +
void execute( const tag &, int arg, int arg);
 +
</source>
 +
This concept is important, because as we shall see there are more models of this concept ('implementations of this interface') than just the sx emulator itself. We shall see that any class that models this concept can be used as the target of an instruction decoder, so that we can feed SX instruction words to a decoder and the decoder will call the correct overload of the ''execute'' function for such a class.
  
 
===Alternative instruction implementations===
 
===Alternative instruction implementations===
Line 53: Line 60:
 
As could be seen in the previous Section, the implementation of the sx instruction set was all in terms of an ''execute'' method that is overloaded for several types, each type representing one instruction. Defining the instruction set becomes therefore a matter of defining a set of types, one for each instruction. These are the ''instruction tag types'' and the execute method is similar to  a technique called ''[http://www.boost.org/community/generic_programming.html#tag_dispatching tag dispatching]''.
 
As could be seen in the previous Section, the implementation of the sx instruction set was all in terms of an ''execute'' method that is overloaded for several types, each type representing one instruction. Defining the instruction set becomes therefore a matter of defining a set of types, one for each instruction. These are the ''instruction tag types'' and the execute method is similar to  a technique called ''[http://www.boost.org/community/generic_programming.html#tag_dispatching tag dispatching]''.
  
In order to facilitate instruction decoding, the instruction types will be enhanced with information about their bit-patterns. This is in contrast with normal tag dispatching, where the tag types are completely empty types. The instruction list for sxgo can be found in ''sx_instruction_list.hpp'' and has the following form:
+
In order to facilitate instruction decoding, the instruction types will be enhanced with information about their bit-patterns. This is in contrast with normal tag dispatching, where the tag types are completely empty types. The instruction list for sxgo can be found in [https://github.com/DannyHavenith/sxsim/blob/master/sxsim/sx_instruction_list.hpp sx_instruction_list.hpp] and has the following form:
 
<source lang="cpp">
 
<source lang="cpp">
 
// ...
 
// ...
Line 94: Line 101:
  
 
==Instruction decoder==
 
==Instruction decoder==
As stated before, it is the task of the instruction decoder to take an instruction word (a number) and based on the value of that word, call an ''execute'' function with the right parameters. SX instructions are all 12 bits, and those bits are typically divided in a number of opcode bits (the instruction) and some operand bits (the arguments). The number of opcode bits is not the same for every instruction. The opcode for "''jmp''" for instance has only three bits (and they have the values '''''101'''''), the other nine bits are reserved for the 9-bit address to jump to.
+
An instruction decoder is essentially a function that takes an instruction word and a reference to an SXImplementation and that will determine from the instruction word which ''execute'' overload needs to be called and subsequently call that member function with the right arguments. In sxgo, this function is a static member function of a template class:
 +
 
 +
<source lang="cpp">
 +
    template<typename instruction_list, typename implementation_type>
 +
    struct instruction_decoder {
 +
        // ...
 +
        static void feed( instruction_type word, implementation_type &implementation);
 +
        // ...
 +
    };
 +
</source>
 +
 
 +
SX instructions are all 12 bits, and those bits are typically divided in a number of opcode bits (the instruction) and some operand bits (the arguments). The number of opcode bits is not the same for every instruction. The opcode for "''jmp''" for instance has only three bits (and they have the values '''''101'''''), the other nine bits are reserved for the 9-bit address to jump to.
  
 
There are several ways to go about implementing an instruction decoder. One could group all instructions according to opcode size and start checking for the shortest opcodes first, and then, if no opcode was recognized start looking in the next group of opcodes, etc. This would look somewhat like this:
 
There are several ways to go about implementing an instruction decoder. One could group all instructions according to opcode size and start checking for the shortest opcodes first, and then, if no opcode was recognized start looking in the next group of opcodes, etc. This would look somewhat like this:
 
<source lang="cpp">
 
<source lang="cpp">
void decode( int instruction, implementation &impl)
+
void feed( instruction_type instruction, implementation_type &impl)
 
{
 
{
 
     switch (instruction & 0xf00) // look at top 4 bits
 
     switch (instruction & 0xf00) // look at top 4 bits
Line 136: Line 154:
 
Then a decision tree in the form of if-statements would look like this:
 
Then a decision tree in the form of if-statements would look like this:
 
<source lang="cpp">
 
<source lang="cpp">
void decode( int instruction, implementation &imp)
+
void feed( instruction_type instruction, implementation_type &imp)
 
{
 
{
 
     if (instruction & 4) // test bit 2
 
     if (instruction & 4) // test bit 2
Line 162: Line 180:
 
The algorithm recursively splits up the instruction set and works as foll