comments and negative immediates
This commit is contained in:
parent
582a0a2c9a
commit
15fb92e502
|
@ -5,15 +5,38 @@ from enum import Enum
|
||||||
class MalformedArgument(Exception):
|
class MalformedArgument(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def word_2c(w):
|
||||||
|
""" Negate a non-negative integer using two's compliment. """
|
||||||
|
return (~w + 1) & 0xFFFFFFFF
|
||||||
|
def ti(w):
|
||||||
|
""" Explicitly transform integer into two's compliment representation. """
|
||||||
|
return w if w >= 0 else word_wc(-w)
|
||||||
|
|
||||||
class ArgType(Enum):
|
class ArgType(Enum):
|
||||||
|
""" Class denoting the type of an argument to an instruction. """
|
||||||
|
|
||||||
IMM = 1
|
IMM = 1
|
||||||
|
""" Immediate values are ones that must be numbers (positive or negative). """
|
||||||
|
|
||||||
REG = 2
|
REG = 2
|
||||||
|
""" Type of registers. """
|
||||||
|
|
||||||
VAL = 3
|
VAL = 3
|
||||||
|
""" Type that denotes either immediate values or registers. """
|
||||||
|
|
||||||
LAB = 4
|
LAB = 4
|
||||||
|
""" Type of labels. """
|
||||||
|
|
||||||
def gettype(s):
|
def gettype(s):
|
||||||
|
""" Parses the type of the argument represented as a string
|
||||||
|
and returns a tuple with the first the first element being
|
||||||
|
the type and the second element being the integer value of
|
||||||
|
the argument.
|
||||||
|
"""
|
||||||
if s.isnumeric():
|
if s.isnumeric():
|
||||||
return (ArgType.IMM, int(s))
|
return (ArgType.IMM, int(s))
|
||||||
|
elif s[0] == "-" and s[1:].isnumeric():
|
||||||
|
return (ArgType.IMM, word_2c(int(s[1:])))
|
||||||
elif s[0] == 'r' and s[1:].isnumeric():
|
elif s[0] == 'r' and s[1:].isnumeric():
|
||||||
return (ArgType.REG, int(s[1:]))
|
return (ArgType.REG, int(s[1:]))
|
||||||
elif s[0] == 'l' and s[1:].isnumeric():
|
elif s[0] == 'l' and s[1:].isnumeric():
|
||||||
|
@ -22,6 +45,8 @@ class ArgType(Enum):
|
||||||
raise MalformedArgument(s)
|
raise MalformedArgument(s)
|
||||||
|
|
||||||
def typecheck(self, s):
|
def typecheck(self, s):
|
||||||
|
""" Parses the type of the string and returns it if it fits
|
||||||
|
the type of the enum value. """
|
||||||
t = ArgType.gettype(s)
|
t = ArgType.gettype(s)
|
||||||
if self == ArgType.VAL:
|
if self == ArgType.VAL:
|
||||||
if t[0] == ArgType.REG or t[0] == ArgType.IMM:
|
if t[0] == ArgType.REG or t[0] == ArgType.IMM:
|
||||||
|
@ -50,7 +75,11 @@ class TypecheckException(Exception):
|
||||||
self.opcode = opcode
|
self.opcode = opcode
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f'opcode {self.opcode} has invalid value {self.sarg} (expected {self.argtype} in position {self.i}'
|
return f'opcode {self.opcode} has invalid value {self.sarg} (expected {self.argtype} in position {self.i}'
|
||||||
|
|
||||||
class Instruction(Enum):
|
class Instruction(Enum):
|
||||||
|
""" Class of microcode instructions. The first number is the opcode
|
||||||
|
and the suceeding values are the types of each of the
|
||||||
|
arguments. """
|
||||||
NOP = 0
|
NOP = 0
|
||||||
PUSH = 1, ArgType.VAL
|
PUSH = 1, ArgType.VAL
|
||||||
POP = 2, ArgType.REG
|
POP = 2, ArgType.REG
|
||||||
|
@ -67,7 +96,10 @@ class Instruction(Enum):
|
||||||
|
|
||||||
self.opcode = opcode
|
self.opcode = opcode
|
||||||
self.argtypes = args
|
self.argtypes = args
|
||||||
|
|
||||||
def typecheck(self, sargs):
|
def typecheck(self, sargs):
|
||||||
|
""" Pass arguments to the instruction and check if the
|
||||||
|
arguments are correct. """
|
||||||
rargs = []
|
rargs = []
|
||||||
if len(sargs) != len(self.argtypes):
|
if len(sargs) != len(self.argtypes):
|
||||||
raise TypecheckLenException(self.opcode, sargs,
|
raise TypecheckLenException(self.opcode, sargs,
|
||||||
|
@ -129,10 +161,12 @@ def encode_pseudo_utf8(n, high_bits, to):
|
||||||
class RangeCheckException(Exception):
|
class RangeCheckException(Exception):
|
||||||
pass
|
pass
|
||||||
class Line:
|
class Line:
|
||||||
def __init__(self, opcode, args, labnum, regnum):
|
def __init__(self, opcode, args):
|
||||||
self.opcode = opcode
|
self.opcode = opcode
|
||||||
self.args = args
|
self.args = args
|
||||||
for a in args:
|
|
||||||
|
def check_line(self, labnum, regnum):
|
||||||
|
for a in self.args:
|
||||||
if a[0] == ArgType.REG:
|
if a[0] == ArgType.REG:
|
||||||
if a[1] < 0 or a[1] >= regnum:
|
if a[1] < 0 or a[1] >= regnum:
|
||||||
raise RangeCheckException(a[0],
|
raise RangeCheckException(a[0],
|
||||||
|
@ -158,7 +192,9 @@ class InstructionNotFoundException(Exception):
|
||||||
pass
|
pass
|
||||||
class Program:
|
class Program:
|
||||||
def asm_push_line(self, ins, args):
|
def asm_push_line(self, ins, args):
|
||||||
self.asm.append(Line(ins, args, self.labnum, self.regnum))
|
l = Line(ins, args)
|
||||||
|
l.check_line(self.labnum, self.regnum)
|
||||||
|
self.asm.append(l)
|
||||||
|
|
||||||
def parse_asm_line(self, line):
|
def parse_asm_line(self, line):
|
||||||
line = line.split()
|
line = line.split()
|
||||||
|
@ -182,3 +218,4 @@ class Program:
|
||||||
self.asm = []
|
self.asm = []
|
||||||
self.labnum = labnum
|
self.labnum = labnum
|
||||||
self.regnum = regnum
|
self.regnum = regnum
|
||||||
|
|
||||||
|
|
11
asm/test.py
11
asm/test.py
|
@ -143,5 +143,16 @@ class ProgramTest(unittest.TestCase):
|
||||||
self.assertEqual(ex.cenv.reg[0], 6)
|
self.assertEqual(ex.cenv.reg[0], 6)
|
||||||
self.assertEqual(ex.cenv.reg[1], 5)
|
self.assertEqual(ex.cenv.reg[1], 5)
|
||||||
|
|
||||||
|
def test_exec_add(self):
|
||||||
|
p = Program()
|
||||||
|
p.parse_asm_line("add r0 10 20")
|
||||||
|
p.parse_asm_line("add r1 5 0")
|
||||||
|
p.parse_asm_line("add r1 r0 -40")
|
||||||
|
ex = ffi.Environment()
|
||||||
|
self.assertEqual(ex.load(p()), ffi.CompileRet.OK)
|
||||||
|
self.assertEqual(ex(), ffi.RunRet.STOP)
|
||||||
|
self.assertEqual(ex.cenv.reg[0], 30)
|
||||||
|
self.assertEqual(ex.cenv.reg[1], word_2c(10))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
15
creole.c
15
creole.c
|
@ -448,17 +448,18 @@ creole_compile(struct creole_env *env, struct creole_reader *r)
|
||||||
return CREOLE_COMPILE_OK;
|
return CREOLE_COMPILE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum creole_run_ret creole_reg_write(struct creole_env *env,
|
enum creole_run_ret creole_reg_write(struct creole_env *env, unsigned reg,
|
||||||
creole_word w, unsigned reg)
|
creole_word w)
|
||||||
{
|
{
|
||||||
if (!valid_register(env, reg))
|
if (!valid_register(env, reg)) {
|
||||||
return CREOLE_REGISTER_OVERFLOW;
|
return CREOLE_REGISTER_OVERFLOW;
|
||||||
|
}
|
||||||
env->reg[reg] = w;
|
env->reg[reg] = w;
|
||||||
return CREOLE_STEP_CONTINUE;
|
return CREOLE_STEP_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum creole_run_ret creole_reg_read(struct creole_env *env, creole_word *w,
|
enum creole_run_ret creole_reg_read(struct creole_env *env, unsigned reg,
|
||||||
unsigned reg)
|
creole_word *w)
|
||||||
{
|
{
|
||||||
if (!valid_register(env, reg))
|
if (!valid_register(env, reg))
|
||||||
return CREOLE_REGISTER_OVERFLOW;
|
return CREOLE_REGISTER_OVERFLOW;
|
||||||
|
@ -472,7 +473,7 @@ static enum creole_run_ret read_val(struct creole_env *env,
|
||||||
creole_word *w)
|
creole_word *w)
|
||||||
{
|
{
|
||||||
if (ins->w_flags[arg] == CREOLE_REGISTER) {
|
if (ins->w_flags[arg] == CREOLE_REGISTER) {
|
||||||
return creole_reg_read(env, w, ins->w[arg]);
|
return creole_reg_read(env, ins->w[arg], w);
|
||||||
} else {
|
} else {
|
||||||
*w = ins->w[arg];
|
*w = ins->w[arg];
|
||||||
}
|
}
|
||||||
|
@ -526,7 +527,7 @@ enum creole_run_ret creole_step(struct creole_env *env, creole_word *sc)
|
||||||
break;
|
break;
|
||||||
case CREOLE_POP:
|
case CREOLE_POP:
|
||||||
check(creole_pop(env, &a1));
|
check(creole_pop(env, &a1));
|
||||||
check(creole_reg_write(env, a1, ins->w[0]));
|
check(creole_reg_write(env, ins->w[0], a1));
|
||||||
break;
|
break;
|
||||||
case CREOLE_ADD:
|
case CREOLE_ADD:
|
||||||
check(read_val(env, ins, 1, &a1));
|
check(read_val(env, ins, 1, &a1));
|
||||||
|
|
8
creole.h
8
creole.h
|
@ -91,10 +91,10 @@ creole_parse_line(struct creole_ins *ins, struct creole_reader *r);
|
||||||
enum creole_compiler_ret
|
enum creole_compiler_ret
|
||||||
creole_compile(struct creole_env *env, struct creole_reader *r);
|
creole_compile(struct creole_env *env, struct creole_reader *r);
|
||||||
|
|
||||||
enum creole_run_ret creole_reg_write(struct creole_env *env, creole_word w,
|
enum creole_run_ret creole_reg_write(struct creole_env *env, unsigned reg,
|
||||||
unsigned reg);
|
creole_word w);
|
||||||
enum creole_run_ret creole_reg_read(struct creole_env *env, creole_word *w,
|
enum creole_run_ret creole_reg_read(struct creole_env *env, unsigned reg,
|
||||||
unsigned reg);
|
creole_word *w);
|
||||||
enum creole_run_ret creole_push(struct creole_env *env, creole_word w);
|
enum creole_run_ret creole_push(struct creole_env *env, creole_word w);
|
||||||
enum creole_run_ret creole_pop(struct creole_env *env, creole_word *w);
|
enum creole_run_ret creole_pop(struct creole_env *env, creole_word *w);
|
||||||
enum creole_run_ret creole_step(struct creole_env *env, creole_word *sc);
|
enum creole_run_ret creole_step(struct creole_env *env, creole_word *sc);
|
||||||
|
|
Loading…
Reference in New Issue