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
%block b1
%vardefs
var byte teller 1
var byte teller 0
var byte numbertoprint 0
const byte one 1
const byte thousand 100000
var array_byte newlinestr 2 [32 32]
const byte thousand 1000
const byte space_chr 32
%end_vardefs
%instructions
push teller
syscall decimalstr_signed
syscall printstr
push newlinestr
syscall printstr
back:
push teller
push one
@ -29,8 +24,8 @@ back:
printnumber:
syscall decimalstr_signed
syscall printstr
push newlinestr
syscall printstr
push space_chr
syscall printchr
return 0
%end_instructions

View File

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

View File

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

View File

@ -65,7 +65,7 @@ class Variable:
class Instruction:
__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.args = args
self.next = nxt # regular next statement, None=end
@ -77,16 +77,16 @@ class Instruction:
class Block:
def __init__(self, name: str, parent: 'Block',
variables: List[Variable],
instructions: List[Instruction],
labels: Dict[str, Instruction], # named entry points
blocks: List['Block']) -> None:
variables: List[Variable] = None,
instructions: List[Instruction] = None,
labels: Dict[str, Instruction] = None, # named entry points
subblocks: List['Block'] = None) -> None:
self.name = name
self.parent = parent
self.variables = variables
self.blocks = blocks
self.instructions = instructions
self.labels = labels
self.variables = variables or []
self.blocks = subblocks or []
self.instructions = instructions or []
self.labels = labels or {}
def __str__(self) -> str:
if self.parent:

View File

@ -16,11 +16,11 @@
# or in one of the dynamic variables.
#
# I/O: either via programmed I/O routines:
# write [byte to text output/screen],
# read [byte from keyboard],
# wait [till any input comes available],
# check [if input is available)
# or via memory-mapped I/O (text screen matrix, keyboard scan register)
# write [byte/bytearray to text output/screen],
# read [byte/bytearray from keyboard],
# wait [till any input comes available], @todo
# check [if input is available) @todo
# or via memory-mapped I/O (text screen matrix, keyboard scan register) @todo
#
# CPU: stack based execution, no registers.
# unlimited dynamic variables (v0, v1, ...) that have a value and a type.
@ -63,9 +63,9 @@ import collections
import array
import threading
import pprint
from .core import Instruction, Variable, Block, Program, Opcode
from typing import Dict, List, Tuple, Union
from il65.emit import mflpt5_to_float, to_mflpt5
from .program import Instruction, Variable, Block, Program, Opcode
class ExecutionError(Exception):
@ -522,7 +522,7 @@ class VM:
def opcode_RETURN(self, instruction: Instruction) -> bool:
callframe = self.stack.pop_under(instruction.args[0])
assert isinstance(callframe, CallFrameMarker)
assert isinstance(callframe, CallFrameMarker), callframe
self.pc = callframe.returninstruction
return False
@ -591,8 +591,8 @@ class System:
def _encodestr(self, string: str, alt: bool=False) -> bytearray:
return bytearray(string, self.vm.str_alt_encoding if alt else self.vm.str_encoding)
def _decodestr(self, bb: bytearray, alt: bool=False) -> str:
return str(bb, self.vm.str_alt_encoding if alt else self.vm.str_encoding)
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) # type: ignore
def syscall_printstr(self) -> bool:
value = self.vm.stack.pop()
@ -602,6 +602,22 @@ class System:
else:
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:
value = self.vm.stack.pop()
if type(value) is int:
@ -631,3 +647,24 @@ class System:
value, address = self.vm.stack.pop2()
self.vm.memory.set_sbyte(address, value) # type: ignore
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