forked from whaleygeek/MyLittleComputer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinstruction.py
185 lines (131 loc) · 3.93 KB
/
instruction.py
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
175
176
177
178
179
180
181
182
183
184
# instruction.py 03/11/2014 D.J.Whale
#
# Encode/Decode an instruction
#
# An instruction is a positive whole number 000-999
# xyy where:
# x is 0..9, the operator
# yy is 00..99, the operand
# decimal opcodes of all standard LMC instructions
HLT = 000
ADD = 100
SUB = 200
STA = 300
# 400 not defined by LMC architecture
LDA = 500
BRA = 600
BRZ = 700
BRP = 800
INP = 901
OUT = 902
# Pseudo opcodes, used by assembler only, not by LMC architecture
# An out of range opcode is used to signify these.
PSEUDO = 1000
DAT = 1000
#1001..1999 not used yet
# useful lookup table for string versions of operands
no_operands = [INP, OUT, HLT]
operators = {
HLT: "HLT", # this is really HLT 00
ADD: "ADD",
SUB: "SUB",
STA: "STA",
LDA: "LDA",
BRA: "BRA",
BRZ: "BRZ",
BRP: "BRP",
INP: "INP", # this is really IO 1
OUT: "OUT", # this is really IO 2
# PSEUDO
DAT: "DAT" # PSEUDO instruction, for convenience
}
def trace(msg):
print(str(msg))
def registerMnemonic(name, code, hasOperands=False):
"""Register a new Mnemonic in the instruction tables"""
# Define the constant (e.g. instruction.XXX)
import sys
me = sys.modules[__name__]
setattr(me, name, code)
# Add the name into the table (e.g. XXX: "XXX"
operators[code] = name
# If appropriate, flag that it has no operands
if not hasOperands:
global no_operands
no_operands += [code]
def reverseLookup(mymap, value):
"""Lookup a value in a map, and get it's key"""
value_idx = mymap.values().index(value)
key = mymap.keys()[value_idx]
return key
def build(operator, operand=None):
"""Build an instruction"""
#trace("build:" + str(operator) + " " + str(operand))
if operator == None and operand == None:
return 0
if type(operator) != int:
raise ValueError("non int operator:" + str(operator))
if operand == None:
operand = 0
elif operand < 0 or operand > 99: # TODO change to 0..255 to allow binary/hex machines
raise ValueError("Operand out of range:" + str(operand))
return operator + operand # TODO might have to store differently to allow bytes
# but beware, when we get it's value on a decimal machine, it must return correct value
def setOperator(instr, operator):
"""Set the operator in an existing instruction"""
operand = getOperand(instr)
return build(operator, operand)
def setOperand(instr, operand):
"""Set the operand in an existing instruction"""
operator = getOperator(instr)
return build(operator, operand)
def getOperator(instr):
"""Get the operator from an existing instruction"""
operator = (instr/100)*100 # change for binary machine, but beware of breaking number output
return operator
def getOperand(instr):
"""Get the operand from an existing instruction"""
return instr % 100 # change for binary machine, but beware of breaking number output
def has_operand(instr):
"""Check if this instruction has an operand or not"""
# Note the special handling for INP OUT HLT (and IO n, HLT n)
try:
no_operands.index(instr)
except:
return True
return False
def getOperatorString(instr):
"""Turn a numeric operator inside an instr into a string"""
if operators.has_key(instr):
return operators[instr]
instr = getOperator(instr)
if operators.has_key(instr):
return operators[instr]
else:
raise ValueError("Unknown operator:" + str(instr))
def toString(instr):
"""Get a string representation of any instruction"""
result = getOperatorString(instr)
if has_operand(instr):
operand = getOperand(instr)
result = result + " " + str(operand).zfill(2) ## might need to change for binary machine
return result
def isOperator(s):
"""Is this string an operator or not?"""
try:
reverseLookup(operators, s)
return True
except:
return False
def operatorFromString(s):
"""Turn a string into a numberic operator"""
# We also support numberic operators (000..999) # change this for binary machine
try:
operator = int(s)
return operator
except:
pass
s = s.upper()
operator = reverseLookup(operators, s)
return operator
# END