-
Notifications
You must be signed in to change notification settings - Fork 0
/
code.hpp
174 lines (138 loc) · 4.71 KB
/
code.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#ifndef CODE_HPP
#define CODE_HPP
#include <iostream>
#include <cassert>
using namespace std;
/*
Data representation:
The command is encoded into one 32-bit value:
|<---------- field B ---------->|<--------- field A ----------->|
| | |
| OpCode Modif| special ModeA ModeB|
| |1 2 3 4|1 2 3| |1 2 3 4|1 2 3|1 2 3|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0| | | | | | | |0|0|0|0|0|0| | | | | | | | | | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
3 2 1
Special cases:
0: no special case
1: DAT
2: NOP
3: SPL
4: JMP
5: MOV.I
This representation looks weired, but it makes it possible to handle
some simple instructions as special cases, which can be very fast.
The 'special'-Bitfield is used for some special opcodes, e.g the
DAT. DAT does not need any adress calculation at all (except for a
decrement/increment), so it's adressing mode calculation can be very
different from other opcodes. The same applies for NOP, JMP and SPL.
Although there is nothing special about MOV.I, it is also encoded
into the special-Bitfield, because MOV.I is heavily used by every
warrior and therefor has to be very fast.
The encoding is done in the following way:
1. Are we encoding a special opcode?
Yes: write the according number to the 'special' field
No: write 0 into the special field
2. Encode the Addressing-modes into ModeA and ModeB
3. Encode the Opcode and the Modifier into OpCode and Modif.
These fields are only used if there is no special opcode (when
special=0)
Now to the more interesting decoding process, which I used for the
optimized interpreter:
1. Extract the last 9 Bits and create a switch over this value. When
using 5 special cases, This is a switch over (5+1)*(2^6) = 384
values. I create the sourcecode automatically. When special=0 an
ordinary address-mode calculation is done.
2. If we did not have a special opcode, a second switch is executed,
it uses the Opcode and Modifier-fields. This is a switch with a
maximum of 128 cases (depending on how many special cases we
have).
*/
typedef unsigned long ulong;
enum EOpCode {
// the order is important
eDat, eNop, eSpl, eJmp, eMov,
eAdd, eSub, eMul, eDiv, eMod, eJmz, eJmn, eDjn, eSlt, eCmp, eSne
// SEQ is equivalent to CMP
// no LDP, STP
};
enum EModifier {
eI, eA, eB, eAB, eBA, eF, eX
};
enum EAddrMode {
eIm, // #
eDir, // $
eInB, // @
ePreDecInB, // <
ePostIncInB, // >
eInA, // *
ePreDecInA, // {
ePostIncInA // }
};
class Code
{
// FIXME: this should not be public. How can the Mars-template be
// a friend of Code?
public:
ulong ins;
ulong valA;
ulong valB;
public:
// Constructors / Destructors
Code();
Code(const Code& c);
Code(EOpCode op, EModifier mod, EAddrMode ma,
ulong va, EAddrMode mb, ulong vb);
// get data
EOpCode GetOpCode() const;
EModifier GetModifier() const;
EAddrMode GetAddrModeA() const;
EAddrMode GetAddrModeB() const;
ulong GetValA() const;
ulong GetValB() const;
// set data
void SetOpCode(EOpCode op);
void SetModifier(EModifier mo);
void SetAddrModeA(EAddrMode ad);
void SetAddrModeB(EAddrMode ad);
void SetCode(const Code& c);
void SetValA(ulong va);
void SetValB(ulong vb);
// output
friend ostream& operator<<(ostream& os, const Code& c);
private:
int exOpCode() const; // extract the special-field
int exModifier() const;
int exSpecial() const;
int exAddrModeA() const;
int exAddrModeB() const;
void inOpCode(int x); // inject new Opcode-value
void inModifier(int x);
void inSpecial(int x);
void inAddrModeA(int x);
void inAddrModeB(int x);
};
static const Code emptyCode;
// number of special modes
const int specialModes = 5;
// positions of bits
const ulong opCodePos = 19;
const ulong modifierPos = 16;
const ulong specialPos = 6;
const ulong addrModeAPos = 3;
const ulong addrModeBPos = 0;
const ulong opCodeMask = 15;
const ulong modifierMask = 7;
const ulong specialMask = 15;
const ulong addrModeAMask = 7;
const ulong addrModeBMask = 7;
const ulong fieldAMask = 511;
const ulong fieldBMask = 127;
const ulong fieldAPos = 0;
const ulong fieldBPos = 16;
const ulong fieldASwitchMask = fieldAMask << fieldAPos;
const ulong fieldBSwitchMask = fieldBMask << fieldBPos;
const ulong allMask = 0xffffffff;
#endif