changeset 1613:2d9e8a7b8ba2

Initial commit of CPU DSL and a WIP SVP implementation written in that DSL
author Michael Pavone <pavone@retrodev.com>
date Tue, 18 Sep 2018 09:06:42 -0700
parents 28ec17387be5
children c9639139aedf
files cpu_dsl.py svp.cpu
diffstat 2 files changed, 1631 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cpu_dsl.py	Tue Sep 18 09:06:42 2018 -0700
@@ -0,0 +1,1086 @@
+#!/usr/bin/env python3
+
+
+class Block:
+	def addOp(self, op):
+		pass
+	
+	def processLine(self, parts):
+		if parts[0] == 'switch':
+			o = Switch(self, parts[1])
+			self.addOp(o)
+			return o
+		elif parts[0] == 'if':
+			o = If(self, parts[1])
+			self.addOp(o)
+			return o
+		elif parts[0] == 'end':
+			raise Exception('end is only allowed inside a switch or if block')
+		else:
+			self.addOp(NormalOp(parts))
+		return self
+		
+	def resolveLocal(self, name):
+		return None
+			
+class ChildBlock(Block):
+	def processLine(self, parts):
+		if parts[0] == 'end':
+			return self.parent
+		return super().processLine(parts)
+
+#Represents an instruction of the emulated CPU
+class Instruction(Block):
+	def __init__(self, value, fields, name):
+		self.value = value
+		self.fields = fields
+		self.name = name
+		self.implementation = []
+		self.locals = {}
+		self.regValues = {}
+		self.varyingBits = 0
+		self.invalidFieldValues = {}
+		for field in fields:
+			self.varyingBits += fields[field][1]
+	
+	def addOp(self, op):
+		if op.op == 'local':
+			name = op.params[0]
+			size = op.params[1]
+			self.locals[name] = size
+		elif op.op == 'invalid':
+			name = op.params[0]
+			value = int(op.params[1])
+			self.invalidFieldValues.setdefault(name, set()).add(value)
+		else:
+			self.implementation.append(op)
+			
+	def resolveLocal(self, name):
+		if name in self.locals:
+			return name
+		return None
+	
+	def addLocal(self, name, size):
+		self.locals[name] = size
+		
+	def localSize(self, name):
+		return self.locals.get(name)
+			
+	def __lt__(self, other):
+		if isinstance(other, Instruction):
+			if self.varyingBits != other.varyingBits:
+				return self.varyingBits < other.varyingBits
+			return self.value < other.value
+		else:
+			return NotImplemented
+			
+	def allValues(self):
+		values = []
+		for i in range(0, 1 << self.varyingBits):
+			iword = self.value
+			doIt = True
+			for field in self.fields:
+				shift,bits = self.fields[field]
+				val = i & ((1 << bits) - 1)
+				if field in self.invalidFieldValues and val in self.invalidFieldValues[field]:
+					doIt = False
+					break
+				i >>= bits
+				iword |= val << shift
+			if doIt:
+				values.append(iword)
+		return values
+		
+	def getFieldVals(self, value):
+		fieldVals = {}
+		fieldBits = {}
+		for field in self.fields:
+			shift,bits = self.fields[field]
+			val = (value >> shift) & ((1 << bits) - 1)
+			fieldVals[field] = val
+			fieldBits[field] = bits
+		return (fieldVals, fieldBits)
+	
+	def generateName(self, value):
+		fieldVals,fieldBits = self.getFieldVals(value)
+		names = list(fieldVals.keys())
+		names.sort()
+		funName = self.name
+		for name in names:
+			funName += '_{0}_{1:0>{2}}'.format(name, bin(fieldVals[name])[2:], fieldBits[name])
+		return funName
+		
+	def generateBody(self, value, prog, otype):
+		output = []
+		prog.meta = {}
+		prog.currentScope = self
+		for var in self.locals:
+			output.append('\n\tuint{sz}_t {name};'.format(sz=self.locals[var], name=var))
+		fieldVals,_ = self.getFieldVals(value)
+		for op in self.implementation:
+			op.generate(prog, self, fieldVals, output, otype)
+		begin = '\nvoid ' + self.generateName(value) + '(' + prog.context_type + ' *context)\n{'
+		if prog.needFlagCoalesce:
+			begin += prog.flags.coalesceFlags(prog, otype)
+		if prog.needFlagDisperse:
+			output.append(prog.flags.disperseFlags(prog, otype))
+		return begin + ''.join(output) + '\n}'
+		
+	def __str__(self):
+		pieces = [self.name + ' ' + hex(self.value) + ' ' + str(self.fields)]
+		for name in self.locals:
+			pieces.append('\n\tlocal {0} {1}'.format(name, self.locals[name]))
+		for op in self.implementation:
+			pieces.append(str(op))
+		return ''.join(pieces)
+	
+#Represents the definition of a helper function
+class SubRoutine(Block):
+	def __init__(self, name):
+		self.name = name
+		self.implementation = []
+		self.args = []
+		self.arg_map = {}
+		self.locals = {}
+		self.regValues = {}
+	
+	def addOp(self, op):
+		if op.op == 'arg':
+			name = op.params[0]
+			size = op.params[1]
+			self.arg_map[name] = len(self.args)
+			self.args.append((name, size))
+		elif op.op == 'local':
+			name = op.params[0]
+			size = op.params[1]
+			self.locals[name] = size
+		else:
+			self.implementation.append(op)
+			
+	def resolveLocal(self, name):
+		if name in self.locals:
+			return self.name + '_' + name
+		return None
+	
+	def addLocal(self, name, size):
+		self.locals[name] = size
+	
+	def localSize(self, name):
+		return self.locals.get(name)
+			
+	def inline(self, prog, params, output, otype, parent):
+		if len(params) != len(self.args):
+			raise Exception('{0} expects {1} arguments, but was called with {2}'.format(self.name, len(self.args), len(params)))
+		argValues = {}
+		if parent:
+			self.regValues = parent.regValues
+		oldScope = prog.currentScope
+		prog.currentScope = self
+		i = 0
+		for name,size in self.args:
+			argValues[name] = params[i]
+			i += 1
+		for name in self.locals:
+			size = self.locals[name]
+			output.append('\n\tuint{size}_t {sub}_{local};'.format(size=size, sub=self.name, local=name))
+		for op in self.implementation:
+			op.generate(prog, self, argValues, output, otype)
+		prog.currentScope = oldScope
+		
+	def __str__(self):
+		pieces = [self.name]
+		for name,size in self.args:
+			pieces.append('\n\targ {0} {1}'.format(name, size))
+		for name in self.locals:
+			pieces.append('\n\tlocal {0} {1}'.format(name, self.locals[name]))
+		for op in self.implementation:
+			pieces.append(str(op))
+		return ''.join(pieces)
+	
+class Op:
+	def __init__(self, evalFun = None):
+		self.evalFun = evalFun
+		self.impls = {}
+		self.outOp = ()
+	def cBinaryOperator(self, op):
+		def _impl(prog, params):
+			if op == '-':
+				a = params[1]
+				b = params[0]
+			else:
+				a = params[0]
+				b = params[1]
+			return '\n\t{dst} = {a} {op} {b};'.format(
+				dst = params[2], a = a, b = b, op = op
+			)
+		self.impls['c'] = _impl
+		self.outOp = (2,)
+		return self
+	def cUnaryOperator(self, op):
+		def _impl(prog, params):
+			return '\n\t{dst} = {op}{a};'.format(
+				dst = params[1], a = params[0], op = op
+			)
+		self.impls['c'] = _impl
+		self.outOp = (1,)
+		return self
+	def addImplementation(self, lang, outOp, impl):
+		self.impls[lang] = impl
+		if not outOp is None:
+			if type(outOp) is tuple:
+				self.outOp = outOp
+			else:
+				self.outOp = (outOp,)
+		return self
+	def evaluate(self, params):
+		return self.evalFun(*params)
+	def canEval(self):
+		return not self.evalFun is None
+	def numArgs(self):
+		return self.evalFun.__code__.co_argcount
+	def generate(self, otype, prog, params, rawParams):
+		if self.impls[otype].__code__.co_argcount == 2:
+			return self.impls[otype](prog, params)
+		else:
+			return self.impls[otype](prog, params, rawParams)
+		
+		
+def _xchgCImpl(prog, params, rawParams):
+	size = prog.paramSize(rawParams[0])
+	decl,name = prog.getTemp(size)
+	return decl + '\n\t{tmp} = {a};\n\t{a} = {b};\n\t{b} = {tmp};'.format(a = params[0], b = params[1], tmp = name)
+
+def _dispatchCImpl(prog, params):
+	if len(params) == 1:
+		table = 'main'
+	else:
+		table = params[1]
+	return '\n\timpl_{tbl}[{op}](context);'.format(tbl = table, op = params[0])
+
+def _updateFlagsCImpl(prog, params, rawParams):
+	i = 0
+	last = ''
+	autoUpdate = set()
+	explicit = {}
+	for c in params[0]:
+		if c.isdigit():
+			if last.isalpha():
+				num = int(c)
+				if num > 1:
+					raise Exception(c + ' is not a valid digit for update_flags')
+				explicit[last] = num
+				last = c
+			else:
+				raise Exception('Digit must follow flag letter in update_flags')
+		else:
+			if last.isalpha():
+				autoUpdate.add(last)
+			last = c
+	if last.isalpha():
+		autoUpdate.add(last)
+	output = []
+	#TODO: handle autoUpdate flags
+	for flag in autoUpdate:
+		calc = prog.flags.flagCalc[flag]
+		calc,_,resultBit = calc.partition('-')
+		lastDst = prog.resolveReg(prog.lastDst, None, {})
+		storage = prog.flags.getStorage(flag)
+		if calc == 'bit' or calc == 'sign':
+			if calc == 'sign':
+				resultBit = prog.paramSize(prog.lastDst) - 1
+			else:
+				resultBit = int(resultBit)
+			if type(storage) is tuple:
+				reg,storageBit = storage
+				reg = prog.resolveReg(reg, None, {})
+				if storageBit == resultBit:
+					#TODO: optimize this case
+					output.append('\n\t{reg} = ({reg} & ~{mask}) | ({res} & {mask});'.format(
+						reg = reg, mask = 1 << resultBit, res = lastDst
+					))
+				else:
+					if resultBit > storageBit:
+						op = '>>'
+						shift = resultBit - storageBit
+					else:
+						op = '<<'
+						shift = storageBit - resultBit
+					output.append('\n\t{reg} = ({reg} & ~{mask}) | ({res} {op} {shift} & {mask});'.format(
+						reg = reg, mask = 1 << storageBit, res = lastDst, op = op, shift = shift
+					))
+			else:
+				reg = prog.resolveReg(storage, None, {})
+				output.append('\n\t{reg} = {res} & {mask};'.format(reg=reg, res=lastDst, mask = 1 << resultBit))
+		elif calc == 'zero':
+			if type(storage) is tuple:
+				reg,storageBit = storage
+				reg = prog.resolveReg(reg, None, {})
+				output.append('\n\t{reg} = {res} ? ({reg} & {mask}) : ({reg} | {bit});'.format(
+					reg = reg, mask = ~(1 << storageBit), res = lastDst, bit = 1 << storageBit
+				))
+			elif prog.paramSize(prog.lastDst) > prog.paramSize(storage):
+				reg = prog.resolveReg(storage, None, {})
+				output.append('\n\t{reg} = {res} != 0;'.format(
+					reg = reg, res = lastDst
+				))
+			else:
+				reg = prog.resolveReg(storage, None, {})
+				output.append('\n\t{reg} = {res};'.format(reg = reg, res = lastDst))
+		elif calc == 'half-carry':
+			pass
+		elif calc == 'carry':
+			pass
+		elif calc == 'overflow':
+			pass
+		elif calc == 'parity':
+			pass
+	#TODO: combine explicit flags targeting the same storage location
+	for flag in explicit:
+		location = prog.flags.getStorage(flag)
+		if type(location) is tuple:
+			reg,bit = location
+			reg = prog.resolveReg(reg, None, {})
+			value = str(1 << bit)
+			if explicit[flag]:
+				operator = '|='
+			else:
+				operator = '&='
+				value = '~' + value
+			output.append('\n\t{reg} {op} {val};'.format(reg=reg, op=operator, val=value))
+		else:
+			reg = prog.resolveReg(location, None, {})
+			output.append('\n\t{reg} = {val};'.format(reg=reg, val=explicit[flag]))
+	return ''.join(output)
+	
+def _cmpCImpl(prog, params):
+	size = prog.paramSize(params[1])
+	tmpvar = 'cmp_tmp{sz}__'.format(sz=size)
+	typename = ''
+	if not prog.currentScope.resolveLocal(tmpvar):
+		prog.currentScope.addLocal(tmpvar, size)
+		typename = 'uint{sz}_t '.format(sz=size)
+	prog.lastDst = tmpvar
+	return '\n\t{tp}{var} = {b} - {a};'.format(tp = typename, var = tmpvar, a = params[0], b = params[1])
+
+def _asrCImpl(prog, params, rawParams):
+	shiftSize = prog.paramSize(rawParams[0])
+	mask = 1 << (shiftSize - 1)
+	return '\n\t{dst} = ({a} >> {b}) | ({a} & {mask}'.format(a = params[0], b = params[1], dst = params[2], mask = mask)
+		
+_opMap = {
+	'mov': Op(lambda val: val).cUnaryOperator(''),
+	'not': Op(lambda val: ~val).cUnaryOperator('~'),
+	'lnot': Op(lambda val: 0 if val else 1).cUnaryOperator('!'),
+	'neg': Op(lambda val: -val).cUnaryOperator('-'),
+	'add': Op(lambda a, b: a + b).cBinaryOperator('+'),
+	'sub': Op(lambda a, b: b - a).cBinaryOperator('-'),
+	'lsl': Op(lambda a, b: a << b).cBinaryOperator('<<'),
+	'lsr': Op(lambda a, b: a >> b).cBinaryOperator('>>'),
+	'asr': Op(lambda a, b: a >> b).addImplementation('c', 2, _asrCImpl),
+	'and': Op(lambda a, b: a & b).cBinaryOperator('&'),
+	'or':  Op(lambda a, b: a | b).cBinaryOperator('|'),
+	'xor': Op(lambda a, b: a ^ b).cBinaryOperator('^'),
+	'cmp': Op().addImplementation('c', None, _cmpCImpl),
+	'ocall': Op().addImplementation('c', None, lambda prog, params: '\n\t{pre}{fun}({args});'.format(
+		pre = prog.prefix, fun = params[0], args = ', '.join(['context'] + [str(p) for p in params[1:]])
+	)),
+	'cycles': Op().addImplementation('c', None,
+		lambda prog, params: '\n\tcontext->current_cycle += context->opts->gen.clock_divider * {0};'.format(
+			params[0]
+		)
+	),
+	'addsize': Op(
+		lambda a, b: b + (2 * a if a else 1)
+	).addImplementation('c', 2, lambda prog, params: '\n\t{dst} = {val} + {sz} ? {sz} * 2 : 1;'.format(
+		dst = params[1], sz = params[0], val = params[1]
+	)),
+	'decsize': Op(
+		lambda a, b: b - (2 * a if a else 1)
+	).addImplementation('c', 2, lambda prog, params: '\n\t{dst} = {val} - {sz} ? {sz} * 2 : 1;'.format(
+		dst = params[2], sz = params[0], val = params[1]
+	)),
+	'xchg': Op().addImplementation('c', (0,1), _xchgCImpl),
+	'dispatch': Op().addImplementation('c', None, _dispatchCImpl),
+	'update_flags': Op().addImplementation('c', None, _updateFlagsCImpl)
+}
+
+#represents a simple DSL instruction
+class NormalOp:
+	def __init__(self, parts):
+		self.op = parts[0]
+		self.params = parts[1:]
+		
+	def generate(self, prog, parent, fieldVals, output, otype):
+		procParams = []
+		allParamsConst = True
+		opDef = _opMap.get(self.op)
+		for param in self.params:
+			allowConst = (self.op in prog.subroutines or len(procParams) != len(self.params) - 1) and param in parent.regValues
+			isDst = (not opDef is None) and len(procParams) in opDef.outOp
+			param = prog.resolveParam(param, parent, fieldVals, allowConst, isDst)
+			
+			if (not type(param) is int) and len(procParams) != len(self.params) - 1:
+				allParamsConst = False
+			procParams.append(param)
+			
+		if self.op == 'meta':
+			param,_,index = self.params[1].partition('.')
+			if index:
+				index = (parent.resolveLocal(index) or index)
+				if index in fieldVals:
+					index = str(fieldVals[index])
+				param = param + '.' + index
+			else:
+				param = parent.resolveLocal(param) or param
+				if param in fieldVals:
+					param = fieldVals[index]
+			prog.meta[self.params[0]] = param
+		elif self.op == 'dis':
+			#TODO: Disassembler
+			pass
+		elif not opDef is None:
+			if opDef.canEval() and allParamsConst:
+				#do constant folding
+				if opDef.numArgs() >= len(procParams):
+					raise Exception('Insufficient args for ' + self.op + ' (' + ', '.join(self.params) + ')')
+				dst = self.params[opDef.numArgs()]
+				result = opDef.evaluate(procParams[:opDef.numArgs()])
+				while dst in prog.meta:
+					dst = prog.meta[dst]
+				maybeLocal = parent.resolveLocal(dst)
+				if maybeLocal:
+					dst = maybeLocal
+				parent.regValues[dst] = result
+				if prog.isReg(dst):
+					output.append(_opMap['mov'].generate(otype, prog, procParams, self.params))
+			else:
+				output.append(opDef.generate(otype, prog, procParams, self.params))
+		elif self.op in prog.subroutines:
+			prog.subroutines[self.op].inline(prog, procParams, output, otype, parent)
+		else:
+			output.append('\n\t' + self.op + '(' + ', '.join([str(p) for p in procParams]) + ');')
+		prog.lastOp = self
+	
+	def __str__(self):
+		return '\n\t' + self.op + ' ' + ' '.join(self.params)
+		
+#represents a DSL switch construct
+class Switch(ChildBlock):
+	def __init__(self, parent, param):
+		self.op = 'switch'
+		self.parent = parent
+		self.param = param
+		self.cases = {}
+		self.regValues = None
+		self.current_locals = {}
+		self.case_locals = {}
+		self.current_case = None
+		self.default = None
+		self.default_locals = None
+	
+	def addOp(self, op):
+		if op.op == 'case':
+			self.cases[int(op.params[0])] = self.current_case = []
+			self.case_locals[int(op.params[0])] = self.current_locals = {}
+		elif op.op == 'default':
+			self.default = self.current_case = []
+			self.default_locals = self.current_locals = {}
+		elif self.current_case == None:
+			raise ion('Orphan instruction in switch')
+		elif op.op == 'local':
+			name = op.params[0]
+			size = op.params[1]
+			self.current_locals[name] = size
+		else:
+			self.current_case.append(op)
+			
+	def resolveLocal(self, name):
+		if name in self.current_locals:
+			return name
+		return self.parent.resolveLocal(name)
+	
+	def addLocal(self, name, size):
+		self.current_locals[name] = size
+		
+	def localSize(self, name):
+		if name in self.current_locals:
+			return self.current_locals[name]
+		return self.parent.localSize(name)
+			
+	def generate(self, prog, parent, fieldVals, output, otype):
+		oldScope = prog.currentScope
+		prog.currentScope = self
+		self.regValues = self.parent.regValues
+		param = prog.resolveParam(self.param, parent, fieldVals)
+		if type(param) is int:
+			if param in self.cases:
+				if self.case_locals[param]:
+					output.append('\n\t{')
+					for local in self.case_locals[param]:
+						output.append('\n\tuint{0}_t {1};'.format(self.case_locals[param][local], local))
+				for op in self.cases[param]:
+					op.generate(prog, self, fieldVals, output, otype)
+				if self.case_locals[param]:
+					output.append('\n\t}')
+			elif self.default:
+				if self.default_locals:
+					output.append('\n\t{')
+					for local in self.default:
+						output.append('\n\tuint{0}_t {1};'.format(self.default[local], local))
+				for op in self.default:
+					op.generate(prog, self, fieldVals, output, otype)
+		else:
+			output.append('\n\tswitch(' + param + ')')
+			output.append('\n\t{')
+			for case in self.cases:
+				output.append('\n\tcase {0}: '.format(case) + '{')
+				for local in self.case_locals[case]:
+					output.append('\n\tuint{0}_t {1};'.format(self.case_locals[case][local], local))
+				for op in self.cases[case]:
+					op.generate(prog, self, fieldVals, output, otype)
+				output.append('\n\tbreak;')
+				output.append('\n\t}')
+			if self.default:
+				output.append('\n\tdefault: {')
+				for local in self.default_locals:
+					output.append('\n\tuint{0}_t {1};'.format(self.default_locals[local], local))
+				for op in self.default:
+					op.generate(prog, self, fieldVals, output, otype)
+			output.append('\n\t}')
+		prog.currentScope = oldScope
+	
+	def __str__(self):
+		keys = self.cases.keys()
+		keys.sort()
+		lines = ['\n\tswitch']
+		for case in keys:
+			lines.append('\n\tcase {0}'.format(case))
+			lines.append(''.join([str(op) for op in self.cases[case]]))
+		lines.append('\n\tend')
+		return ''.join(lines)
+
+		
+def _geuCImpl(prog, parent, fieldVals, output):
+	if prog.lastOp.op == 'cmp':
+		output.pop()
+		params = prog.lastOp.params
+		for i in range(0, len(params)):
+			params[i] = prog.resolveParam(params[i], parent, fieldVals)
+		return '\n\tif ({a} >= {b}) '.format(a=params[0], b = params[1]) + '{'
+	else:
+		raise ion(">=U not implemented in the general case yet")
+	
+_ifCmpImpl = {
+	'c': {
+		'>=U': _geuCImpl
+	}
+}
+#represents a DSL conditional construct
+class If(ChildBlock):
+	def __init__(self, parent, cond):
+		self.op = 'if'
+		self.parent = parent
+		self.cond = cond
+		self.body = []
+		self.elseBody = []
+		self.curBody = self.body
+		self.locals = {}
+		self.regValues = parent.regValues
+		
+	def addOp(self, op):
+		if op.op in ('case', 'arg'):
+			raise Exception(self.op + ' is not allows inside an if block')
+		if op.op == 'local':
+			name = op.params[0]
+			size = op.params[1]
+			self.locals[name] = size
+		elif op.op == 'else':
+			self.curBody = self.elseBody
+		else:
+			self.curBody.append(op)
+			
+	def generate(self, prog, parent, fieldVals, output, otype):
+		try:
+			if prog.checkBool(self.cond):
+				for op in self.body:
+					op.generate(prog, self, fieldVals, output, otype)
+			else:
+				for op in self.elseBody:
+					op.generate(prog, self, fieldVals, output, otype)
+		except Exception:
+			if self.cond in _ifCmpImpl[otype]:
+				output.append(_ifCmpImpl[otype][self.cond](prog, parent, fieldVals, output))
+				for op in self.body:
+					op.generate(prog, self, fieldVals, output, otype)
+				if self.elseBody:
+					output.append('\n\t} else {')
+					for op in self.elseBody:
+						op.generate(prog, self, fieldVals, output, otype)
+				output.append('\n\t}')
+			else:
+				cond = prog.resolveParam(self.cond, parent, fieldVals)
+				if type(cond) is int:
+					if cond:
+						for op in self.body:
+							op.generate(prog, self, fieldVals, output, otype)
+					else:
+						for op in self.elseBody:
+							op.generate(prog, self, fieldVals, output, otype)
+				else:
+					output.append('\n\tif ({cond}) {'.format(cond=cond))
+					for op in self.body:
+						op.generate(prog, self, fieldVals, output, otype)
+					if self.elseBody:
+						output.append('\n\t} else {')
+						for op in self.elseBody:
+							op.generate(prog, self, fieldVals, output, otype)
+					output.append('\n\t}')
+						
+	
+	def __str__(self):
+		lines = ['\n\tif']
+		for op in self.body:
+			lines.append(str(op))
+		lines.append('\n\tend')
+		return ''.join(lines)
+
+class Registers:
+	def __init__(self):
+		self.regs = {}
+		self.regArrays = {}
+		self.regToArray = {}
+	
+	def addReg(self, name, size):
+		self.regs[name] = size
+	
+	def addRegArray(self, name, size, regs):
+		self.regArrays[name] = (size, regs)
+		idx = 0
+		for reg in regs:
+			self.regs[reg] = size
+			self.regToArray[reg] = (name, idx)
+			idx += 1
+	
+	def isReg(self, name):
+		return name in self.regs
+	
+	def isRegArray(self, name):
+		return name in self.regArrays
+		
+	def isRegArrayMember(self, name):
+		return name in self.regToArray
+		
+	def arrayMemberParent(self, name):
+		return self.regToArray[name][0]
+	
+	def arrayMemberIndex(self, name):
+		return self.regToArray[name][1]
+	
+	def arrayMemberName(self, array, index):
+		if type(index) is int:
+			return self.regArrays[array][1][index]
+		else:
+			return None
+	
+	def processLine(self, parts):
+		if len(parts) > 2:
+			self.addRegArray(parts[0], int(parts[1]), parts[2:])
+		else:
+			self.addReg(parts[0], int(parts[1]))
+		return self
+	
+class Flags:
+	def __init__(self):
+		self.flagBits = {}
+		self.flagCalc = {}
+		self.flagStorage = {}
+		self.flagReg = None
+		self.maxBit = -1
+	
+	def processLine(self, parts):
+		if parts[0] == 'register':
+			self.flagReg = parts[1]
+		else:
+			flag,bit,calc,storage = parts
+			bit,_,top = bit.partition('-')
+			bit = int(bit)
+			if top:
+				top = int(bit)
+				if top > self.maxBit:
+					self.maxBit = top
+				self.flagBits[flag] = (bit,top)
+			else:
+				if bit > self.maxBit:
+					self.maxBit = bit
+				self.flagBits[flag] = bit
+			self.flagCalc[flag] = calc
+			self.flagStorage[flag] = storage
+		return self
+	
+	def getStorage(self, flag):
+		if not flag in self.flagStorage:
+			raise Exception('Undefined flag ' + flag)
+		loc,_,bit = self.flagStorage[flag].partition('.')
+		if bit:
+			return (loc, int(bit))
+		else:
+			return loc
+	
+	def disperseFlags(self, prog, otype):
+		bitToFlag = [None] * (self.maxBit+1)
+		src = prog.resolveReg(self.flagReg, None, {})
+		output = []
+		for flag in self.flagBits:
+			bit = self.flagBits[flag]
+			if type(bit) is tuple:
+				bot,top = bit
+				mask = ((1 << (top + 1 - bot)) - 1) << bot
+				output.append('\n\t{dst} = {src} & mask;'.format(
+					dst=prog.resolveReg(self.flagStorage[flag], None, {}), src=src, mask=mask
+				))
+			else:
+				bitToFlag[self.flagBits[flag]] = flag		
+		multi = {}
+		for bit in range(len(bitToFlag)-1,-1,-1):
+			flag = bitToFlag[bit]
+			if not flag is None:
+				field,_,dstbit = self.flagStorage[flag].partition('.')
+				dst = prog.resolveReg(field, None, {})
+				if dstbit:
+					dstbit = int(dstbit)
+					multi.setdefault(dst, []).append((dstbit, bit))
+				else:
+					output.append('\n\t{dst} = {src} & {mask};'.format(dst=dst, src=src, mask=(1 << bit)))
+		for dst in multi:
+			didClear = False
+			direct = []
+			for dstbit, bit in multi[dst]:
+				if dstbit == bit:
+					direct.append(bit)
+				else:
+					if not didClear:
+						output.append('\n\t{dst} = 0;'.format(dst=dst))
+						didClear = True
+					if dstbit > bit:
+						shift = '<<'
+						diff = dstbit - bit
+					else:
+						shift = '>>'
+						diff = bit - dstbit
+					output.append('\n\t{dst} |= {src} {shift} {diff} & {mask};'.format(
+						src=src, dst=dst, shift=shift, diff=diff, mask=(1 << dstbit)
+					))
+			if direct:
+				if len(direct) == len(multi[dst]):
+					output.append('\n\t{dst} = {src};'.format(dst=dst, src=src))
+				else:
+					mask = 0
+					for bit in direct:
+						mask = mask | (1 << bit)
+					output.append('\n\t{dst} = {src} & {mask};'.format(dst=dst, src=src, mask=mask))
+		return ''.join(output)
+	
+	def coalesceFlags(self, prog, otype):
+		dst = prog.resolveReg(self.flagReg, None, {})
+		output = ['\n\t{dst} = 0;'.format(dst=dst)]
+		bitToFlag = [None] * (self.maxBit+1)
+		for flag in self.flagBits:
+			bit = self.flagBits[flag]
+			if type(bit) is tuple:
+				bot,_ = bit
+				src = prog.resolveReg(self.flagStorage[flag], None, {})
+				if bot:
+					output.append('\n\t{dst} |= {src} << {shift};'.format(
+						dst=dst, src = src, shift = bot
+					))
+				else:
+					output.append('\n\t{dst} |= {src};'.format(
+						dst=dst, src = src
+					))
+			else:
+				bitToFlag[bit] = flag
+		multi = {}
+		for bit in range(len(bitToFlag)-1,-1,-1):
+			flag = bitToFlag[bit]
+			if not flag is None:
+				field,_,srcbit = self.flagStorage[flag].partition('.')
+				src = prog.resolveReg(field, None, {})
+				if srcbit:
+					srcbit = int(srcbit)
+					multi.setdefault(src, []).append((srcbit,bit))
+				else:
+					output.append('\n\tif ({src}) {{\n\t\t{dst} |= 1 << {bit};\n\t}}'.format(
+						dst=dst, src=src, bit=bit
+					))
+		for src in multi:
+			direct = 0
+			for srcbit, dstbit in multi[src]:
+				if srcbit == dstbit:
+					direct = direct | (1 << srcbit)
+				else:
+					output.append('\n\tif ({src} & (1 << {srcbit})) {{\n\t\t{dst} |= 1 << {dstbit};\n\t}}'.format(
+						src=src, dst=dst, srcbit=srcbit, dstbit=dstbit
+					))
+			if direct:
+				output.append('\n\t{dst} |= {src} & {mask}'.format(
+					dst=dst, src=src, mask=direct
+				))
+		return ''.join(output)
+		
+		
+class Program:
+	def __init__(self, regs, instructions, subs, info, flags):
+		self.regs = regs
+		self.instructions = instructions
+		self.subroutines = subs
+		self.meta = {}
+		self.booleans = {}
+		self.prefix = info.get('prefix', [''])[0]
+		self.opsize = int(info.get('opcode_size', ['8'])[0])
+		self.extra_tables = info.get('extra_tables', [])
+		self.context_type = self.prefix + 'context'
+		self.body = info.get('body', [None])[0]
+		self.flags = flags
+		self.lastDst = None
+		self.currentScope = None
+		self.lastOp = None
+		
+	def __str__(self):
+		pieces = []
+		for reg in self.regs:
+			pieces.append(str(self.regs[reg]))
+		for name in self.subroutines:
+			pieces.append('\n'+str(self.subroutines[name]))
+		for instruction in self.instructions:
+			pieces.append('\n'+str(instruction))
+		return ''.join(pieces)
+		
+	def build(self, otype):
+		body = []
+		pieces = []
+		for table in self.instructions:
+			opmap = [None] * (1 << self.opsize)
+			bodymap = {}
+			instructions = self.instructions[table]
+			instructions.sort()
+			for inst in instructions:
+				for val in inst.allValues():
+					if opmap[val] is None:
+						self.meta = {}
+						self.temp = {}
+						self.needFlagCoalesce = False
+						self.needFlagDisperse = False
+						self.lastOp = None
+						opmap[val] = inst.generateName(val)
+						bodymap[val] = inst.generateBody(val, self, otype)
+			
+			pieces.append('\nstatic void *impl_{name}[{sz}] = {{'.format(name = table, sz=len(opmap)))
+			for inst in range(0, len(opmap)):
+				op = opmap[inst]
+				if op is None:
+					pieces.append('\n\tunimplemented,')
+				else:
+					pieces.append('\n\t' + op + ',')
+					body.append(bodymap[inst])
+			pieces.append('\n};')
+		if self.body in self.subroutines:
+			pieces.append('\nvoid {pre}execute({type} *context, uint32_t target_cycle)'.format(pre = self.prefix, type = self.context_type))
+			pieces.append('\n{')
+			pieces.append('\n\twhile (context->current_cycle < target_cycle)')
+			pieces.append('\n\t{')
+			self.meta = {}
+			self.temp = {}
+			self.subroutines[self.body].inline(self, [], pieces, otype, None)
+			pieces.append('\n\t}')
+			pieces.append('\n}')
+		return ''.join(body) +  ''.join(pieces)
+		
+	def checkBool(self, name):
+		if not name in self.booleans:
+			raise Exception(name + ' is not a defined boolean flag')
+		return self.booleans[name]
+	
+	def getTemp(self, size):
+		if size in self.temp:
+			return ('', self.temp[size])
+		self.temp[size] = 'tmp{sz}'.format(sz=size);
+		return ('\n\tuint{sz}_t tmp{sz};'.format(sz=size), self.temp[size])
+		
+	def resolveParam(self, param, parent, fieldVals, allowConstant=True, isdst=False):
+		keepGoing = True
+		while keepGoing:
+			keepGoing = False
+			try:
+				if type(param) is int:
+					pass
+				elif param.startswith('0x'):
+					param = int(param, 16)
+				else:
+					param = int(param)
+			except ValueError:
+				
+				if parent:
+					if param in parent.regValues and allowConstant:
+						return parent.regValues[param]
+					maybeLocal = parent.resolveLocal(param)
+					if maybeLocal:
+						return maybeLocal
+				if param in fieldVals:
+					param = fieldVals[param]
+				elif param in self.meta:
+					param = self.meta[param]
+					keepGoing = True
+				elif self.isReg(param):
+					param = self.resolveReg(param, parent, fieldVals, isdst)
+		return param
+	
+	def isReg(self, name):
+		if not type(name) is str:
+			return False
+		begin,sep,_ = name.partition('.')
+		if sep:
+			if begin in self.meta:
+				begin = self.meta[begin]
+			return self.regs.isRegArray(begin)
+		else:
+			return self.regs.isReg(name)
+	
+	def resolveReg(self, name, parent, fieldVals, isDst=False):
+		begin,sep,end = name.partition('.')
+		if sep:
+			if begin in self.meta:
+				begin = self.meta[begin]
+			if not self.regs.isRegArrayMember(end):
+				end = self.resolveParam(end, parent, fieldVals)
+			if not type(end) is int and self.regs.isRegArrayMember(end):
+				arrayName = self.regs.arrayMemberParent(end)
+				end = self.regs.arrayMemberIndex(end)
+				if arrayName != begin:
+					end = 'context->{0}[{1}]'.format(arrayName, end)
+			regName = self.regs.arrayMemberName(begin, end)
+			ret = 'context->{0}[{1}]'.format(begin, end)
+		else:
+			regName = name
+			if self.regs.isRegArrayMember(name):
+				arr,idx = self.regs.regToArray[name]
+				ret = 'context->{0}[{1}]'.format(arr, idx)
+			else:
+				ret = 'context->' + name
+		if regName == self.flags.flagReg:
+			if isDst:
+				self.needFlagDisperse = True
+			else:
+				self.needFlagCoalesce = True
+		if isDst:
+			self.lastDst = regName
+		return ret
+		
+	
+	
+	def paramSize(self, name):
+		size = self.currentScope.localSize(name)
+		if size:
+			return size
+		begin,sep,_ = name.partition('.')
+		if sep and self.regs.isRegArray(begin):
+			return self.regs.regArrays[begin][0]
+		if self.regs.isReg(name):
+			return self.regs.regs[name]
+		return 32
+
+def parse(f):
+	instructions = {}
+	subroutines = {}
+	registers = None
+	flags = None
+	errors = []
+	info = {}
+	line_num = 0
+	cur_object = None
+	for line in f:
+		line_num += 1
+		line,_,comment = line.partition('#')
+		if not line.strip():
+			continue
+		if line[0].isspace():
+			if not cur_object is None:
+				parts = [el.strip() for el in line.split(' ')]
+				if type(cur_object) is dict:
+					cur_object[parts[0]] = parts[1:]
+				else:
+					cur_object = cur_object.processLine(parts)
+				
+#				if type(cur_object) is Registers:
+#					if len(parts) > 2:
+#						cur_object.addRegArray(parts[0], int(parts[1]), parts[2:])
+#					else:
+#						cur_object.addReg(parts[0], int(parts[1]))
+#				elif type(cur_object) is dict:
+#					cur_object[parts[0]] = parts[1:]
+#				elif parts[0] == 'switch':
+#					o = Switch(cur_object, parts[1])
+#					cur_object.addOp(o)
+#					cur_object = o
+#				elif parts[0] == 'if':
+#					o = If(cur_object, parts[1])
+#					cur_object.addOp(o)
+#					cur_object = o
+#				elif parts[0] == 'end':
+#					cur_object = cur_object.parent
+#				else:
+#					cur_object.addOp(NormalOp(parts))
+			else:
+				errors.append("Orphan instruction on line {0}".format(line_num))
+		else:
+			parts = line.split(' ')
+			if len(parts) > 1:
+				if len(parts) > 2:
+					table,bitpattern,name = parts
+				else:
+					bitpattern,name = parts
+					table = 'main'
+				value = 0
+				fields = {}
+				curbit = len(bitpattern) - 1
+				for char in bitpattern:
+					value <<= 1
+					if char in ('0', '1'):
+						value |= int(char)
+					else:
+						if char in fields:
+							fields[char] = (curbit, fields[char][1] + 1)
+						else:
+							fields[char] = (curbit, 1)
+					curbit -= 1
+				cur_object = Instruction(value, fields, name.strip())
+				instructions.setdefault(table, []).append(cur_object)
+			elif line.strip() == 'regs':
+				if registers is None:
+					registers = Registers()
+				cur_object = registers
+			elif line.strip() == 'info':
+				cur_object = info
+			elif line.strip() == 'flags':
+				if flags is None:
+					flags = Flags()
+				cur_object = flags
+			else:
+				cur_object = SubRoutine(line.strip())
+				subroutines[cur_object.name] = cur_object
+	if errors:
+		print(errors)
+	else:
+		p = Program(registers, instructions, subroutines, info, flags)
+		p.booleans['dynarec'] = False
+		p.booleans['interp'] = True
+		
+		print('#include "m68k_prefix.c"')
+		print(p.build('c'))
+
+def main(argv):
+	f =  open(argv[1])
+	parse(f)
+
+if __name__ == '__main__':
+	from sys import argv
+	main(argv)
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/svp.cpu	Tue Sep 18 09:06:42 2018 -0700
@@ -0,0 +1,545 @@
+info
+	prefix svp_
+	opcode_size 16
+	body svp_run_op
+	
+regs
+	internal 16 scratch1 x y scratch2 st pad pc
+	a 32
+	stack 16 stack0 stack1 stack2 stack3 stack4 stack5
+	stackidx 8
+	p 32
+	external 16 pm0 pm1 pm2 xst pm4 ext5 pmc
+	pointers0 8 r0 r1 r2 r3 
+	pointers1 8 r4 r5 r6 r7
+	iram 16 1024
+	ram0 16 256
+	ram1 16 256
+	zflag 8
+	nflag 8
+	rpl 16
+	
+flags
+	register st
+	Z 13 zero zflag
+	N 15 sign nflag
+	R 0-2 none rpl
+	
+svp_pop
+	mov stack.stackidx dst
+	add 1 stackidx stackidx
+	switch stackidx
+	case 6
+	mov 0 stackidx
+	end
+	
+svp_push
+	arg src 16
+	add -1 stackidx stackidx
+	switch stackidx
+	case -1
+	mov 5 stackidx
+	end
+	mov src stack.stackidx
+	
+svp_ram_read
+	arg mode 16
+	arg banki 16
+	arg regi 16
+	local idx 16
+	
+	switch banki
+	case 0
+	meta bank ram0
+	meta reg pointers0.regi
+	
+	default
+	meta bank ram1
+	meta reg pointers1.regi
+	end
+	
+	mov reg idx
+	switch mode
+	case 0
+	meta modestr ""
+	
+	case 1
+	meta modestr +!
+	add 1 reg reg
+	
+	case 2
+	#loop decremenet
+	meta modestr -
+	mov reg tmp
+	switch rpl
+		case 0
+		sub 1 reg reg
+		
+		default
+		lsl 1 rpl rpl
+		sub 1 rpl rpl
+		local mask 16
+		not rpl mask
+		and reg mask reg
+		sub 1 tmp tmp
+		and rpl tmp tmp
+		or rpl reg reg
+		
+		end
+	
+	case 3
+	#loop increment
+	meta modestr +
+	
+	and 7 st rpl
+	switch rpl
+		case 0
+		sub 1 reg reg
+		
+		default
+		mov reg tmp
+		lsl 1 rpl rpl
+		sub 1 rpl rpl
+		local mask 16
+		not rpl mask
+		and reg mask reg
+		add 1 tmp tmp
+		and rpl tmp tmp
+		or rpl reg reg
+		
+		end
+	end
+	
+	and 255 idx idx
+	meta val bank.idx
+	
+svp_read_ext
+	arg regidxr 16
+	switch regidxr
+	case 7
+	meta val a
+	
+	default
+	#TODO: PMAR stuff
+	meta val external.regidxr
+	end
+	
+svp_write_ext
+	arg regidxw 16
+	switch regidxw
+	case 7
+	and 0xFFFF0000 a a
+	or src a a
+	
+	default
+	#TODO: PMAR stuff
+	mov src external.regidxw
+	end
+	
+svp_alu_op
+	arg P 16
+	arg param 32
+	
+	switch P
+	case 1
+	dis "sub %s" name
+	sub param a a
+	
+	case 3
+	dis "cmp %s" name
+	cmp param a
+	
+	case 4
+	dis "add %s" name
+	add param a a
+	
+	case 5
+	dis "and %s" name
+	and param a a
+	
+	case 6
+	dis "or %s" name
+	or param a a
+	
+	case 7
+	dis "eor %s" name
+	xor param a a
+	end
+	update_flags ZN
+	
+svp_check_cond
+	arg fval 16
+	arg cond 16
+	local invert 8
+	switch cond
+	case 0
+	meta flag 1
+	
+	case 5
+	meta flag zflag
+	
+	case 7
+	meta flag nflag
+	
+	default
+	meta flag 0
+	end
+	switch fval
+	case 0
+	lnot flag invert
+	meta istrue invert 
+	
+	default
+	meta istrue flag
+	end
+	
+PPP0000000000000 alu_n1
+	invalid P 0
+	invalid P 2
+	meta name "-"
+	svp_alu_op P 0xFFFF0000
+	
+PPP0000000000RRR alu_r
+	invalid P 0
+	invalid P 2
+	local tmp 32 
+	lsl internal.R 16 tmp
+	meta name internal.R
+	svp_alu_op P tmp
+	
+PPP0000000000011 alu_a
+	invalid P 0
+	invalid P 2
+	svp_alu_op P a
+	
+PPP0000000000101 alu_stack
+	invalid P 0
+	invalid P 2
+	local tmp 32
+	meta dst tmp
+	svp_pop
+	meta name "st"
+	svp_alu_op P tmp
+	
+PPP0000000000111 alu_p
+	invalid P 0
+	invalid P 2
+	meta name p
+	svp_alu_op P p
+	
+PPP0000000001RRR alu_ext
+	invalid P 0
+	invalid P 2
+	local tmp 32
+	svp_read_ext R
+	lsl val 16 tmp
+	meta name val
+	svp_alu_op P tmp
+	
+PPP0001B000MMRR alu_ram
+	invalid P 0
+	invalid P 2
+	svp_ram_read M B R
+	local tmp 32
+	lsl val 16 tmp
+	
+	switch P
+	case 1
+	dis "sub (%s%s)" reg modestr
+	sub tmp a a
+	
+	case 3
+	dis "cmp (%s%s)" reg modestr
+	cmp tmp a
+	
+	case 4
+	dis "add (%s%s)" reg modestr
+	add tmp a a
+	
+	case 5
+	dis "and (%s%s)" reg modestr
+	and tmp a a
+	
+	case 6
+	dis "or (%s%s)" reg modestr
+	or tmp a a
+	
+	case 7
+	dis "eor (%s%s)" reg modestr
+	xor tmp a a
+	end
+	
+	update_flags ZN
+	
+PPP0000000001111 alu_al
+	invalid P 0
+	invalid P 2
+	local tmp 32
+	lsl a 16 tmp
+	
+	meta name al
+	svp_alu_op P tmp
+	
+1001000FCCCC0OOO cond_mod
+	svp_check_cond F C
+	switch istrue
+	case 0
+	
+	default
+	switch O
+	case 2
+	asr a 1 a
+	update_flags ZN
+	
+	case 3
+	lsl a 1 a
+	update_flags ZN
+	
+	case 6
+	neg a a
+	update_flags ZN
+	
+	case 7
+	abs a a
+	update_flags N
+	end
+
+000000000DDD0SSS ld_int_int
+	dis "ld %s, %s" internal.D internal.S
+	mov internal.S internal.D
+	
+000000000DDD0101 ld_int_st
+	dis "ld %s, st" internal.D 
+	meta dst internal.D
+	svp_pop
+	
+0000000000110101 ld_a_st
+	dis "ld a, st"
+	local tmp 32
+	meta dst tmp
+	svp_pop
+	lsl tmp 16 tmp
+	and 0xFFFF a a
+	or tmp a a
+	
+0000000001110101 ld_p_st
+	dis "ld p, st"
+	local tmp 32
+	meta dst tmp
+	svp_pop
+	lsl tmp 16 tmp
+	and 0xFFFF p p
+	or tmp p p
+	
+0000000001010SSS ld_st_int
+	dis "ld st, %s" internal.S
+	svp_push internal.S
+	
+0000000001010011 ld_st_a
+	dis "ld st, a"
+	local tmp 32
+	lsr a 16 tmp
+	svp_push tmp
+	
+0000000001010111 ld_st_p
+	dis "ld st, p"
+	local tmp 32
+	lsr p 16 tmp
+	svp_push tmp
+	
+0000000000000000 ld_n1_n1
+	#nop?
+	dis "ld -, -"
+	
+0000000000000SSS ld_n1_int
+	#nop?
+	dis "nop??"
+	
+0000000000110111 ld_a_p
+	dis "ld a, p"
+	mov p a
+	
+0000000001110011 ld_p_a
+	dis "ld p, a"
+	mov a p
+	
+0000000000110011 ld_a_a
+	dis "ld a, a"
+	mov a a
+	
+0000000001110111 ld_p_p
+	dis "ld p, p"
+	mov p p
+
+000000000DDD0111 ld_int_p
+	local tmp 32
+	lsr p 16 tmp
+	mov tmp internal.D
+	dis "ld %s, p" internal.D
+	
+000000000DDD0111 ld_int_a
+	local tmp 32
+	lsr a 16 tmp
+	mov tmp internal.D
+	dis "ld %s, a" internal.D
+	
+0000000001110SSS ld_p_int
+	local tmp 32
+	lsl internal.S 16 tmp
+	mov tmp p
+	dis "ld p, %s" internal.S
+	
+0000000000110SSS ld_a_int
+	local tmp 32
+	lsl internal.S 16 tmp
+	mov tmp a
+	dis "ld a, %s" internal.S
+	
+000000000DDD0000 ld_int_n1
+	dis "ld %s, -" internal.D
+	mov 0xFFFF internal.D
+	
+0000000000110000 ld_a_n1
+	dis "ld a, -"
+	and 0xFFFF a a
+	or 0xFFFF0000 a a
+	
+0000000001110000 ld_p_n1
+	dis "ld p, -"
+	and 0xFFFF p p
+	or 0xFFFF0000 p p
+
+000000000DDD1SSS ld_int_ext
+	svp_read_ext S
+	dis "ld %s, %s" internal.D val
+	mov val internal.D
+	
+0000000000111SSS ld_a_ext
+	svp_read_ext S
+	dis "ld a, %s" val
+	local tmp 32
+	lsl val 16 tmp
+	and 0xFFFF a a
+	or tmp a a
+	
+0000000001111SSS ld_p_ext
+	svp_read_ext S
+	dis "ld p, %s" val
+	local tmp 32
+	lsl val 16 tmp
+	and 0xFFFF p p
+	or tmp p p
+	
+000000001DDD0SSS ld_ext_int
+	meta src internal.S
+	svp_write_ext D
+	switch D
+	case 7
+	dis "ld al, %s" src
+	
+	default
+	dis "ld %s, %s" external.D src
+	end
+	
+000000001DDD0011 ld_ext_a
+	local tmp 32
+	lsr a 16 tmp
+	meta src tmp
+	svp_write_ext D
+	switch D
+	case 7
+	dis "ld al, a"
+	
+	default
+	dis "ld %s, a" external.D
+	end
+	
+000000001DDD0111 ld_ext_p
+	local tmp 32
+	lsr p 16 tmp
+	meta src tmp
+	svp_write_ext D
+	switch D
+	case 7
+	dis "ld al, p"
+	
+	default
+	dis "ld %s, p" external.D
+	end
+	
+	
+000000001DDD1SSS ld_ext_ext
+	svp_read_ext S
+	meta src val
+	svp_write_ext D
+	switch D
+	case 7
+	dis "ld al, %s" src
+	default
+	dis "ld %s, %s" external.D src
+	end
+	
+0000001B0DDDMMPP ld_int_ram
+	svp_ram_read M B P
+	dis "ld %s, (%s%s)" internal.D reg modestr
+	mov val internal.D
+	
+0000001B0011MMPP ld_a_ram
+	svp_ram_read M B P
+	dis "ld a, (%s%s)" reg modestr
+	local tmp 32
+	lsl val 16 tmp
+	and 0xFFFF a a
+	or tmp a a
+	
+0000001B0111MMPP ld_p_ram
+	svp_ram_read M B P
+	dis "ld p, (%s%s)" reg modestr
+	local tmp 32
+	lsl val 16 tmp
+	and 0xFFFF p p
+	or tmp p p
+	
+0000001B0101MMPP ld_st_ram
+	svp_ram_read M B P
+	dis "ld st, (%s%s)" reg modestr
+	svp_push val
+	
+0100100FCCCC0000 call_cond
+	svp_check_cond F C
+	svp_op_fetch
+	switch istrue
+	case 0
+	
+	default
+	svp_push pc
+	mov scratch1 pc
+	end
+	
+0100110FCCCC0000 bra_cond
+	svp_check_cond F C
+	svp_op_fetch
+	switch istrue
+	case 0
+	
+	default
+	mov scratch1 pc
+	end
+
+svp_op_fetch
+	cycles 1
+	cmp 1024 pc
+	
+	if >=U
+	mov pc scratch1
+	add scratch1 scratch1 scratch1
+	ocall read_16
+	
+	else
+	mov iram.pc scratch1
+	end
+	add 1 pc pc
+	
+svp_run_op
+	svp_op_fetch
+	dispatch scratch1
\ No newline at end of file