vm tweaks

This commit is contained in:
Irmen de Jong 2018-03-03 00:07:44 +01:00
parent 0603b93f47
commit 27e6749533
5 changed files with 64 additions and 31 deletions

View File

@ -1,19 +1,14 @@
; source code for a tinyvm program ; source code for a tinyvm program
%block b1 %block b1
%vardefs %vardefs
var byte teller 1 var byte teller 0
var byte numbertoprint 0 var byte numbertoprint 0
const byte one 1 const byte one 1
const byte thousand 100000 const byte thousand 1000
var array_byte newlinestr 2 [32 32] const byte space_chr 32
%end_vardefs %end_vardefs
%instructions %instructions
push teller
syscall decimalstr_signed
syscall printstr
push newlinestr
syscall printstr
back: back:
push teller push teller
push one push one
@ -29,8 +24,8 @@ back:
printnumber: printnumber:
syscall decimalstr_signed syscall decimalstr_signed
syscall printstr syscall printstr
push newlinestr push space_chr
syscall printstr syscall printchr
return 0 return 0
%end_instructions %end_instructions

View File

@ -1,6 +1,6 @@
import sys import sys
from .parse import Parser from .parse import Parser
from .core import Program, Opcode, Block, Instruction from .program import Program, Opcode, Block, Instruction
from .vm import VM from .vm import VM

View File

@ -1,6 +1,6 @@
import array import array
from typing import Optional, List, Tuple, Dict from typing import Optional, List, Tuple, Dict, Any
from .core import DataType, Opcode, Program, Block, Variable, Instruction from .program import DataType, Opcode, Program, Block, Variable, Instruction
from .vm import StackValueType from .vm import StackValueType
@ -112,6 +112,7 @@ class Parser:
def parse_instruction(ln: str) -> Instruction: def parse_instruction(ln: str) -> Instruction:
parts = ln.split(maxsplit=1) parts = ln.split(maxsplit=1)
opcode = Opcode[parts[0].upper()] opcode = Opcode[parts[0].upper()]
args = [] # type: List[Any]
if len(parts) == 2: if len(parts) == 2:
args = parts[1].split() args = parts[1].split()
else: else:

View File

@ -65,7 +65,7 @@ class Variable:
class Instruction: class Instruction:
__slots__ = ["opcode", "args", "next", "alt_next"] __slots__ = ["opcode", "args", "next", "alt_next"]
def __init__(self, opcode: Opcode, args: List[Any], nxt: Optional['Instruction'], alt_next: Optional['Instruction']) -> None: def __init__(self, opcode: Opcode, args: List[Any], nxt: Optional['Instruction']=None, alt_next: Optional['Instruction']=None) -> None:
self.opcode = opcode self.opcode = opcode
self.args = args self.args = args
self.next = nxt # regular next statement, None=end self.next = nxt # regular next statement, None=end
@ -77,16 +77,16 @@ class Instruction:
class Block: class Block:
def __init__(self, name: str, parent: 'Block', def __init__(self, name: str, parent: 'Block',
variables: List[Variable], variables: List[Variable] = None,
instructions: List[Instruction], instructions: List[Instruction] = None,
labels: Dict[str, Instruction], # named entry points labels: Dict[str, Instruction] = None, # named entry points
blocks: List['Block']) -> None: subblocks: List['Block'] = None) -> None:
self.name = name self.name = name
self.parent = parent self.parent = parent
self.variables = variables self.variables = variables or []
self.blocks = blocks self.blocks = subblocks or []
self.instructions = instructions self.instructions = instructions or []
self.labels = labels self.labels = labels or {}
def __str__(self) -> str: def __str__(self) -> str:
if self.parent: if self.parent:

View File

@ -16,11 +16,11 @@
# or in one of the dynamic variables. # or in one of the dynamic variables.
# #
# I/O: either via programmed I/O routines: # I/O: either via programmed I/O routines:
# write [byte to text output/screen], # write [byte/bytearray to text output/screen],
# read [byte from keyboard], # read [byte/bytearray from keyboard],
# wait [till any input comes available], # wait [till any input comes available], @todo
# check [if input is available) # check [if input is available) @todo
# or via memory-mapped I/O (text screen matrix, keyboard scan register) # or via memory-mapped I/O (text screen matrix, keyboard scan register) @todo
# #
# CPU: stack based execution, no registers. # CPU: stack based execution, no registers.
# unlimited dynamic variables (v0, v1, ...) that have a value and a type. # unlimited dynamic variables (v0, v1, ...) that have a value and a type.
@ -63,9 +63,9 @@ import collections
import array import array
import threading import threading
import pprint import pprint
from .core import Instruction, Variable, Block, Program, Opcode
from typing import Dict, List, Tuple, Union from typing import Dict, List, Tuple, Union
from il65.emit import mflpt5_to_float, to_mflpt5 from il65.emit import mflpt5_to_float, to_mflpt5
from .program import Instruction, Variable, Block, Program, Opcode
class ExecutionError(Exception): class ExecutionError(Exception):
@ -522,7 +522,7 @@ class VM:
def opcode_RETURN(self, instruction: Instruction) -> bool: def opcode_RETURN(self, instruction: Instruction) -> bool:
callframe = self.stack.pop_under(instruction.args[0]) callframe = self.stack.pop_under(instruction.args[0])
assert isinstance(callframe, CallFrameMarker) assert isinstance(callframe, CallFrameMarker), callframe
self.pc = callframe.returninstruction self.pc = callframe.returninstruction
return False return False
@ -591,8 +591,8 @@ class System:
def _encodestr(self, string: str, alt: bool=False) -> bytearray: def _encodestr(self, string: str, alt: bool=False) -> bytearray:
return bytearray(string, self.vm.str_alt_encoding if alt else self.vm.str_encoding) return bytearray(string, self.vm.str_alt_encoding if alt else self.vm.str_encoding)
def _decodestr(self, bb: bytearray, alt: bool=False) -> str: def _decodestr(self, bb: Union[bytearray, array.array], alt: bool=False) -> str:
return str(bb, self.vm.str_alt_encoding if alt else self.vm.str_encoding) return str(bb, self.vm.str_alt_encoding if alt else self.vm.str_encoding) # type: ignore
def syscall_printstr(self) -> bool: def syscall_printstr(self) -> bool:
value = self.vm.stack.pop() value = self.vm.stack.pop()
@ -602,6 +602,22 @@ class System:
else: else:
raise TypeError("printstr expects bytearray", value) raise TypeError("printstr expects bytearray", value)
def syscall_printchr(self) -> bool:
character = self.vm.stack.pop()
if isinstance(character, int):
print(self._decodestr(bytearray([character])), end="")
return True
else:
raise TypeError("printchr expects integer (1 char)", character)
def syscall_input(self) -> bool:
self.vm.stack.push(self._encodestr(input()))
return True
def syscall_getchr(self) -> bool:
self.vm.stack.push(self._encodestr(input() + '\n')[0])
return True
def syscall_decimalstr_signed(self) -> bool: def syscall_decimalstr_signed(self) -> bool:
value = self.vm.stack.pop() value = self.vm.stack.pop()
if type(value) is int: if type(value) is int:
@ -631,3 +647,24 @@ class System:
value, address = self.vm.stack.pop2() value, address = self.vm.stack.pop2()
self.vm.memory.set_sbyte(address, value) # type: ignore self.vm.memory.set_sbyte(address, value) # type: ignore
return True return True
def syscall_memwrite_word(self) -> bool:
value, address = self.vm.stack.pop2()
self.vm.memory.set_word(address, value) # type: ignore
return True
def syscall_memwrite_sword(self) -> bool:
value, address = self.vm.stack.pop2()
self.vm.memory.set_sword(address, value) # type: ignore
return True
def syscall_memwrite_float(self) -> bool:
value, address = self.vm.stack.pop2()
self.vm.memory.set_float(address, value) # type: ignore
return True
def syscall_memwrite_str(self) -> bool:
strbytes, address = self.vm.stack.pop2()
for i, b in enumerate(strbytes): # type: ignore
self.vm.memory.set_byte(address+i, b) # type: ignore
return True