Removed BCI-base and BCI-assembler from BCI-dev
This commit is contained in:
parent
b6a3cdcd59
commit
f4304de5ad
|
@ -1,3 +0,0 @@
|
||||||
.PHONY: test
|
|
||||||
test:
|
|
||||||
python3 -m pytest test/
|
|
|
@ -1,311 +0,0 @@
|
||||||
from collections import deque
|
|
||||||
|
|
||||||
from .context import FileContext
|
|
||||||
from .tokenize import Tokenizer, WHITESPACE
|
|
||||||
from .opcodes import make_opcodes
|
|
||||||
from .util import can_be_mark, can_convert_to_int, autoint, int16_2_bytes
|
|
||||||
from .directives import SetDirective
|
|
||||||
|
|
||||||
class ParsingError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class Assembler(object):
|
|
||||||
"""
|
|
||||||
This class is used for generating bytecode from a file containing assembly.
|
|
||||||
|
|
||||||
Also required is the memory definition of the interpreter given as a dict::
|
|
||||||
|
|
||||||
{
|
|
||||||
"registers": <register_count>,
|
|
||||||
"memory": <number of memory words>,
|
|
||||||
"program_memory": <number of words available for the program>
|
|
||||||
}
|
|
||||||
|
|
||||||
And the definition of the commands. This is a list of dicts::
|
|
||||||
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"mnemonic": <mnemonic>,
|
|
||||||
"args": [
|
|
||||||
("register"|"memory"|"program_memory"|"direct_input"), ...
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
The method ``parse`` will parse the input file and ``bindump`` will dump the binary
|
|
||||||
bytecode into a file.
|
|
||||||
"""
|
|
||||||
def __init__(self, file_, memory_definition, command_definition, custom_directives):
|
|
||||||
self._file_context = FileContext(file_)
|
|
||||||
self._code_objects = deque()
|
|
||||||
self._memory_definition = memory_definition
|
|
||||||
self._command_definition = command_definition
|
|
||||||
self._word_count = 0
|
|
||||||
self._marks = {}
|
|
||||||
|
|
||||||
self._opcodes = make_opcodes([cmd["mnemonic"] for cmd in command_definition])
|
|
||||||
self._commands_by_mnemonic = {cmd["mnemonic"]: cmd for cmd in command_definition}
|
|
||||||
self._tokenizer = Tokenizer(self._file_context)
|
|
||||||
|
|
||||||
self._directives = {"set": SetDirective()}
|
|
||||||
self._directives.update(custom_directives)
|
|
||||||
|
|
||||||
def parse(self):
|
|
||||||
try:
|
|
||||||
for token in self._tokenizer:
|
|
||||||
|
|
||||||
# Comments
|
|
||||||
if(token == ";"):
|
|
||||||
while(token != "\n"):
|
|
||||||
token = next(self._tokenizer)
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Commands
|
|
||||||
if(token in self._commands_by_mnemonic):
|
|
||||||
self.parse_command(token)
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Directives
|
|
||||||
if(token == "."):
|
|
||||||
self.parse_directive()
|
|
||||||
continue
|
|
||||||
|
|
||||||
# The default is trying to parse a mark
|
|
||||||
if(not can_be_mark(token)):
|
|
||||||
self.raise_unexpected_token(token
|
|
||||||
, "comment, command, directive or mark"
|
|
||||||
, token)
|
|
||||||
self.parse_mark(token)
|
|
||||||
except StopIteration:
|
|
||||||
raise ParsingError("Unexpected EOF while parsing.")
|
|
||||||
|
|
||||||
for mark, mark_data in self._marks.items():
|
|
||||||
if(mark_data["target"] < 0):
|
|
||||||
raise ParsingError("Mark {} undefined. Referenced in lines: {}".format(
|
|
||||||
mark
|
|
||||||
, mark_data["references"]))
|
|
||||||
|
|
||||||
self._code_objects = [self._marks[c]["target"] if c in self._marks else c
|
|
||||||
for c in self._code_objects ]
|
|
||||||
|
|
||||||
def bindump(self, file_):
|
|
||||||
# FIXME:
|
|
||||||
# Make this work for tons of data.
|
|
||||||
# Or is that necessary?
|
|
||||||
# TODO:
|
|
||||||
# Figure out whether/what improovements are necessary here
|
|
||||||
length = int16_2_bytes(len(self._code_objects))
|
|
||||||
if(len(self._code_objects).bit_length() > 16):
|
|
||||||
raise ValueError("Program size excceeds 2^16.")
|
|
||||||
file_.write(length)
|
|
||||||
for word in self._code_objects:
|
|
||||||
file_.write(int16_2_bytes(word))
|
|
||||||
|
|
||||||
|
|
||||||
def parse_mark(self, token):
|
|
||||||
should_be_colon = next(self._tokenizer)
|
|
||||||
|
|
||||||
if(should_be_colon != ":"):
|
|
||||||
self.raise_unexpected_token(token, "':'", should_be_colon)
|
|
||||||
|
|
||||||
should_be_newline = next(self._tokenizer)
|
|
||||||
if(should_be_newline != "\n"):
|
|
||||||
self.raise_unexpected_token(token + ":", "'\\n'", should_be_newline)
|
|
||||||
|
|
||||||
if(token in self._marks):
|
|
||||||
if(self._marks[token]["target"] != -1):
|
|
||||||
raise ParsingError("Error in line {} column {} mark already defined: '{}'. Previous was in line {}.".format(
|
|
||||||
self._file_context._line
|
|
||||||
, self._column
|
|
||||||
, token
|
|
||||||
, self._marks[token]["target_line"]))
|
|
||||||
self._marks[token]["target"] = self._word_count
|
|
||||||
self._marks[token]["target_line"] = self._file_context._line
|
|
||||||
|
|
||||||
else:
|
|
||||||
self._marks[token] = {
|
|
||||||
"target": self._word_count
|
|
||||||
, "target_line": self._file_context._line
|
|
||||||
, "references": []
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def parse_directive(self):
|
|
||||||
should_be_name = next(self._tokenizer)
|
|
||||||
|
|
||||||
if(not should_be_name in self._directives):
|
|
||||||
self.raise_unexpected_token(".", "directive name", should_be_name)
|
|
||||||
|
|
||||||
should_be_whitespace = next(self._tokenizer)
|
|
||||||
if(not should_be_whitespace in WHITESPACE):
|
|
||||||
self.raise_unexpected_token(should_be_name, "' '", should_be_whitespace)
|
|
||||||
|
|
||||||
words = self._directives[should_be_name].parse(self, self._tokenizer)
|
|
||||||
|
|
||||||
self._word_count += len(words)
|
|
||||||
self._code_objects.extend(words)
|
|
||||||
|
|
||||||
should_be_newline = next(self._tokenizer)
|
|
||||||
if(should_be_newline != "\n"):
|
|
||||||
self.raise_unexpected_token(".", "newline", should_be_newline)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def parse_command(self, cmd):
|
|
||||||
# We have no arguments
|
|
||||||
if(not self._commands_by_mnemonic[cmd]["args"]):
|
|
||||||
self._code_objects.append(self._opcodes[cmd])
|
|
||||||
self._word_count += 1
|
|
||||||
token = next(self._tokenizer)
|
|
||||||
if(token != "\n"):
|
|
||||||
self.raise_unexpected_token(cmd, "newline", token)
|
|
||||||
return
|
|
||||||
|
|
||||||
# Small argument must be treated separately
|
|
||||||
should_be_whitespace = next(self._tokenizer)
|
|
||||||
if(should_be_whitespace not in WHITESPACE
|
|
||||||
or should_be_whitespace == "\n"):
|
|
||||||
self.raise_unexpected_token(cmd, "' '", should_be_whitespace)
|
|
||||||
|
|
||||||
should_be_an_argument = next(self._tokenizer)
|
|
||||||
argument = self.check_and_convert_argument(cmd
|
|
||||||
, should_be_an_argument
|
|
||||||
, self._commands_by_mnemonic[cmd]["args"][0])
|
|
||||||
self._word_count += 1
|
|
||||||
# NOTE:
|
|
||||||
# The Small Argument is stored within the first word (!)
|
|
||||||
self._code_objects.append(self._opcodes[cmd] | (argument & 0xffff))
|
|
||||||
|
|
||||||
|
|
||||||
# All the 16bit arguments
|
|
||||||
for argument in self._commands_by_mnemonic[cmd]["args"][1:]:
|
|
||||||
should_be_comma = next(self._tokenizer)
|
|
||||||
if(should_be_comma != ","):
|
|
||||||
self.raise_unexpected_token(cmd, "','", should_be_comma)
|
|
||||||
|
|
||||||
self._word_count += 1
|
|
||||||
self._code_objects.append(
|
|
||||||
self.check_and_convert_argument(
|
|
||||||
cmd
|
|
||||||
, next(self._tokenizer)
|
|
||||||
, argument))
|
|
||||||
|
|
||||||
should_be_newline = next(self._tokenizer)
|
|
||||||
if(should_be_newline != "\n"):
|
|
||||||
self.raise_unexpected_token(cmd, "newline", should_be_newline)
|
|
||||||
|
|
||||||
|
|
||||||
def raise_unexpected_token(self, after, expected, got):
|
|
||||||
raise ParsingError("Error in line {} column {} after '{}': expected {}, got '{}'".format(
|
|
||||||
self._file_context._line
|
|
||||||
, self._file_context._column
|
|
||||||
, after
|
|
||||||
, expected
|
|
||||||
, got))
|
|
||||||
|
|
||||||
def raise_invalid_address(self, after, memtype, maxval, got):
|
|
||||||
raise ParsingError("Error in line {} column {} after '{}': value {} is invalid for {} (max is {})".format(
|
|
||||||
self._file_context._line
|
|
||||||
, self._file_context._column
|
|
||||||
, after
|
|
||||||
, got
|
|
||||||
, memtype
|
|
||||||
, maxval))
|
|
||||||
|
|
||||||
def check_and_convert_argument(self, cmd, argument, argument_definition):
|
|
||||||
if(argument_definition == "register"):
|
|
||||||
if(not argument.startswith("r")):
|
|
||||||
self.raise_unexpected_token(cmd, "register name", argument)
|
|
||||||
register_offset = argument[1:]
|
|
||||||
raise_could_not_convert_register_offset = False
|
|
||||||
try:
|
|
||||||
register_offset = int(register_offset)
|
|
||||||
except:
|
|
||||||
raise_could_not_convert_register_offset = True
|
|
||||||
|
|
||||||
if(raise_could_not_convert_register_offset):
|
|
||||||
self.raise_unexpected_token(cmd, "register name", argument)
|
|
||||||
|
|
||||||
if(register_offset > self._memory_definition["registers"]
|
|
||||||
or register_offset < 0):
|
|
||||||
self.raise_invalid_address(cmd
|
|
||||||
, "register"
|
|
||||||
, self._memory_definition["registers"]
|
|
||||||
, register_offset)
|
|
||||||
|
|
||||||
return register_offset
|
|
||||||
|
|
||||||
if(argument_definition == "memory"):
|
|
||||||
if(not can_convert_to_int(argument)):
|
|
||||||
self.raise_unexpected_token(cmd, "integer address", argument)
|
|
||||||
argument = autoint(argument)
|
|
||||||
|
|
||||||
if(argument < 0 or argument > self._memory_definition["memory"]):
|
|
||||||
self.raise_invalid_address(cmd
|
|
||||||
, "memory"
|
|
||||||
, self._memory_definition["memory"]
|
|
||||||
, argument)
|
|
||||||
return argument
|
|
||||||
|
|
||||||
if(argument_definition == "program_memory"):
|
|
||||||
# Non-integer Argument.
|
|
||||||
if(not can_convert_to_int(argument)):
|
|
||||||
# Just nonsense.
|
|
||||||
if(not can_be_mark(argument)):
|
|
||||||
self.raise_unexpected_token(cmd, "integer address or mark", argument)
|
|
||||||
# The Mark has appeared before.
|
|
||||||
if(argument in self._marks):
|
|
||||||
# Add this line to the references.
|
|
||||||
self._marks[argument]["references"].append(self._file_context._line)
|
|
||||||
# The target is already known. Insert it now.
|
|
||||||
if(self._marks[argument]["target"] != -1):
|
|
||||||
return self._marks[argument]["target"]
|
|
||||||
# The target is unknown.
|
|
||||||
return argument
|
|
||||||
# The Mark has not appeared before.
|
|
||||||
self._marks[argument] = {
|
|
||||||
"target": -1
|
|
||||||
, "target_line": 0
|
|
||||||
, "references": [self._file_context._line]
|
|
||||||
}
|
|
||||||
# Target is obviously unknown.
|
|
||||||
return argument
|
|
||||||
|
|
||||||
|
|
||||||
# Integer argument.
|
|
||||||
argument = autoint(argument)
|
|
||||||
|
|
||||||
if(argument < 0 or argument > self._memory_definition["program_memory"]):
|
|
||||||
self.raise_invalid_address(cmd
|
|
||||||
, "program_memory"
|
|
||||||
, self._memory_definition["program_memory"]
|
|
||||||
, argument)
|
|
||||||
return argument
|
|
||||||
|
|
||||||
# This is direct input (default).
|
|
||||||
|
|
||||||
# Integer
|
|
||||||
if(can_convert_to_int(argument)):
|
|
||||||
return autoint(argument)
|
|
||||||
|
|
||||||
# This is nonsense.
|
|
||||||
if(not can_be_mark(argument)):
|
|
||||||
self.raise_unexpected_token(cmd, "integer, char or mark", argument)
|
|
||||||
|
|
||||||
# It is a Mark.
|
|
||||||
if(argument in self._marks):
|
|
||||||
if(self._marks[argument]["target"] >= 0):
|
|
||||||
self._marks[argument]["references"].append(self._file_context._line)
|
|
||||||
return self._marks[argument]["target"]
|
|
||||||
self._marks[argument]["references"].append(self._file_context._line)
|
|
||||||
return argument
|
|
||||||
|
|
||||||
self._marks[argument] = {
|
|
||||||
"target": -1
|
|
||||||
, "target_line": 0
|
|
||||||
, "references": [self._file_context._line]
|
|
||||||
}
|
|
||||||
|
|
||||||
return argument
|
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
from collections import deque
|
|
||||||
|
|
||||||
class FileContext(object):
|
|
||||||
def __init__(self, file_):
|
|
||||||
self._file = file_
|
|
||||||
self._line = 0
|
|
||||||
self._column = 0
|
|
||||||
self._column_stack = deque()
|
|
||||||
|
|
||||||
def getc(self):
|
|
||||||
c = self._file.read(1)
|
|
||||||
if(c == "\n"):
|
|
||||||
self._line += 1
|
|
||||||
self._column_stack.append(self._column)
|
|
||||||
self._column = 0
|
|
||||||
else:
|
|
||||||
self._column += 1
|
|
||||||
|
|
||||||
return c
|
|
||||||
|
|
||||||
def ungetc(self, c):
|
|
||||||
self._file.seek(self._file.tell() - 1, 0)
|
|
||||||
if(c == "\n"):
|
|
||||||
self._line -= 1
|
|
||||||
self._column = self._column_stack.pop()
|
|
||||||
else:
|
|
||||||
self._column -= 1
|
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
"""
|
|
||||||
Directives for explicitly modifying the program memory.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from abc import ABC, abstractmethod
|
|
||||||
from collections import deque
|
|
||||||
|
|
||||||
from .util import can_convert_to_int, autoint
|
|
||||||
|
|
||||||
class AbstractDirective(ABC):
|
|
||||||
@abstractmethod
|
|
||||||
def parse(self, assembler, tokenizer):
|
|
||||||
"""
|
|
||||||
Parse the directive by converting the text to a list of words.
|
|
||||||
Returns a list of 16bit words.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SetDirective(AbstractDirective):
|
|
||||||
def parse(self, assembler, tokenizer):
|
|
||||||
words = deque()
|
|
||||||
should_be_bracket = next(tokenizer)
|
|
||||||
if(not should_be_bracket == "["):
|
|
||||||
assembler.raise_unexpected_token(".set", "'['", should_be_bracket)
|
|
||||||
|
|
||||||
while(True):
|
|
||||||
should_be_value = next(tokenizer)
|
|
||||||
if(not can_convert_to_int(should_be_value)):
|
|
||||||
assembler.raise_unexpected_token(".set"
|
|
||||||
, "integer or character value"
|
|
||||||
, should_be_value)
|
|
||||||
words.append(autoint(should_be_value))
|
|
||||||
|
|
||||||
comma_or_bracket = next(tokenizer)
|
|
||||||
if(not comma_or_bracket in (",", "]")):
|
|
||||||
assembler.raise_unexpected_token(".set"
|
|
||||||
, "',' or ']'"
|
|
||||||
, comma_or_bracket)
|
|
||||||
|
|
||||||
if(comma_or_bracket == "]"):
|
|
||||||
break
|
|
||||||
return list(words)
|
|
|
@ -1,33 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
class Autoinserter(object):
|
|
||||||
def __init__(self):
|
|
||||||
self.mayor = 2
|
|
||||||
self.minor = 1
|
|
||||||
def __next__(self):
|
|
||||||
"""Generate the next opcode"""
|
|
||||||
# 10bit opcode
|
|
||||||
opcode = 0b1111111111
|
|
||||||
|
|
||||||
# Calculate this opcode.
|
|
||||||
opcode *= self.minor
|
|
||||||
opcode //= self.mayor
|
|
||||||
|
|
||||||
# The lower 6 bits are reserved.
|
|
||||||
opcode <<= 6
|
|
||||||
# 16 bits in total. Should not matter.
|
|
||||||
opcode &= 0xffff
|
|
||||||
|
|
||||||
# Update the state.
|
|
||||||
self.minor = (self.minor + 2) % self.mayor
|
|
||||||
if(self.minor == 1):
|
|
||||||
self.mayor *= 2
|
|
||||||
|
|
||||||
return opcode
|
|
||||||
def __iter__(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
def make_opcodes(mnemonics_in_order):
|
|
||||||
|
|
||||||
ai = Autoinserter()
|
|
||||||
return {mnemonic: opcode for (mnemonic, opcode) in zip(mnemonics_in_order, ai)}
|
|
|
@ -1,55 +0,0 @@
|
||||||
from collections import deque
|
|
||||||
|
|
||||||
WHITESPACE = {" ", "\t", "\n", "\r"}
|
|
||||||
TOKENS_END_OF_WORD = WHITESPACE | {";", ":", ",", ".", "[", "]"}
|
|
||||||
|
|
||||||
TOKENS_EXPECT_NEWLINE = {":", "]"}
|
|
||||||
|
|
||||||
|
|
||||||
class Tokenizer(object):
|
|
||||||
def __init__(self, context):
|
|
||||||
self._context = context
|
|
||||||
self._expect_newline = False
|
|
||||||
self._expect_whitespace = False
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
return self
|
|
||||||
def __next__(self):
|
|
||||||
"""
|
|
||||||
Return the next token.
|
|
||||||
"""
|
|
||||||
|
|
||||||
current_token = deque()
|
|
||||||
|
|
||||||
while(True):
|
|
||||||
c = self._context.getc()
|
|
||||||
|
|
||||||
# Sometimes we need the explicit newline.
|
|
||||||
if(self._expect_newline and c == "\n"):
|
|
||||||
self._expect_newline = False
|
|
||||||
return c
|
|
||||||
|
|
||||||
# Skip multiple whitespaces.
|
|
||||||
if(c in WHITESPACE and not current_token):
|
|
||||||
if(self._expect_whitespace):
|
|
||||||
self._expect_whitespace = False
|
|
||||||
return c
|
|
||||||
continue
|
|
||||||
|
|
||||||
if(c in TOKENS_END_OF_WORD):
|
|
||||||
if(current_token):
|
|
||||||
self._context.ungetc(c)
|
|
||||||
if(c in WHITESPACE):
|
|
||||||
self._expect_whitespace = True
|
|
||||||
return "".join(current_token)
|
|
||||||
else:
|
|
||||||
if(c in TOKENS_EXPECT_NEWLINE):
|
|
||||||
self._expect_newline = True
|
|
||||||
return c
|
|
||||||
|
|
||||||
if(not c):
|
|
||||||
raise StopIteration()
|
|
||||||
|
|
||||||
current_token.append(c)
|
|
||||||
|
|
||||||
|
|
|
@ -1,94 +0,0 @@
|
||||||
"""
|
|
||||||
Utility functions used for parsing.
|
|
||||||
"""
|
|
||||||
import struct
|
|
||||||
|
|
||||||
|
|
||||||
def can_be_mark(argument):
|
|
||||||
"""
|
|
||||||
The ``argument`` can be interpreted as a Mark.
|
|
||||||
"""
|
|
||||||
a = ord("a")
|
|
||||||
a_z = [chr(a + i) for i in range(26)]
|
|
||||||
A = ord("A")
|
|
||||||
A_Z = [chr(A + i) for i in range(26)]
|
|
||||||
null = ord("0")
|
|
||||||
null_9 = [chr(null + i) for i in range(10)]
|
|
||||||
|
|
||||||
if(not argument[0] in a_z):
|
|
||||||
return False
|
|
||||||
|
|
||||||
for char in argument[1:]:
|
|
||||||
if(not (char in a_z
|
|
||||||
or char in A_Z
|
|
||||||
or char in null_9
|
|
||||||
or char == "_")):
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def can_convert_to_int(value):
|
|
||||||
"""
|
|
||||||
``value`` can be converted to an integer.
|
|
||||||
|
|
||||||
**Note** that this returns ``True`` if the value is a
|
|
||||||
character definition like ``'a'``.
|
|
||||||
"""
|
|
||||||
if(value.startswith("0x")):
|
|
||||||
try:
|
|
||||||
int(value[2:], 16)
|
|
||||||
return True
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
if(value.startswith("0b")):
|
|
||||||
try:
|
|
||||||
int(value[2:], 2)
|
|
||||||
return True
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
if(value.startswith("'") and value.endswith("'")):
|
|
||||||
if(len(value) == 3):
|
|
||||||
return True
|
|
||||||
if(len(value) == 4):
|
|
||||||
if(value[1:-1] in {"\\n", "\\r", "\\t"}):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
try:
|
|
||||||
int(value)
|
|
||||||
return True
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def autoint(value):
|
|
||||||
"""
|
|
||||||
Convert ``value`` to an integer automatically.
|
|
||||||
"""
|
|
||||||
escape_sequences = {"\\n": "\n", "\\r": "\r", "\\t":"\t"}
|
|
||||||
if(value.startswith("0x")):
|
|
||||||
return int(value[2:], 16)
|
|
||||||
|
|
||||||
if(value.startswith("0b")):
|
|
||||||
return int(value[2:], 2)
|
|
||||||
|
|
||||||
if(value.startswith("'") and value.endswith("'")):
|
|
||||||
if(len(value) == 3):
|
|
||||||
return ord(value[1:-1])
|
|
||||||
if(len(value) == 4):
|
|
||||||
if(value[1:-1] in escape_sequences):
|
|
||||||
return ord(escape_sequences[value[1:-1]])
|
|
||||||
|
|
||||||
return int(value)
|
|
||||||
|
|
||||||
|
|
||||||
def int16_2_bytes(value):
|
|
||||||
"""
|
|
||||||
Return the bytes representation of a 16bit unsigned
|
|
||||||
integer in 8bit words.
|
|
||||||
"""
|
|
||||||
if(value < 0):
|
|
||||||
return struct.pack("<h", value)
|
|
||||||
return struct.pack("<H", value)
|
|
|
@ -1,244 +0,0 @@
|
||||||
%PDF-1.4
|
|
||||||
%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com
|
|
||||||
1 0 obj
|
|
||||||
<< /F1 2 0 R /F2 3 0 R /F3 10 0 R >>
|
|
||||||
endobj
|
|
||||||
2 0 obj
|
|
||||||
<< /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >>
|
|
||||||
endobj
|
|
||||||
3 0 obj
|
|
||||||
<< /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font >>
|
|
||||||
endobj
|
|
||||||
4 0 obj
|
|
||||||
<< /Border [ 0 0 0 ] /Contents () /Dest [ 13 0 R /XYZ 62.69291 636.0236 0 ] /Rect [ 62.69291 687.0236 178.2829 699.0236 ] /Subtype /Link /Type /Annot >>
|
|
||||||
endobj
|
|
||||||
5 0 obj
|
|
||||||
<< /Border [ 0 0 0 ] /Contents () /Dest [ 13 0 R /XYZ 62.69291 636.0236 0 ] /Rect [ 527.0227 687.7736 532.5827 699.7736 ] /Subtype /Link /Type /Annot >>
|
|
||||||
endobj
|
|
||||||
6 0 obj
|
|
||||||
<< /Border [ 0 0 0 ] /Contents () /Dest [ 13 0 R /XYZ 62.69291 525.0236 0 ] /Rect [ 62.69291 669.0236 197.7229 681.0236 ] /Subtype /Link /Type /Annot >>
|
|
||||||
endobj
|
|
||||||
7 0 obj
|
|
||||||
<< /Border [ 0 0 0 ] /Contents () /Dest [ 13 0 R /XYZ 62.69291 525.0236 0 ] /Rect [ 527.0227 669.7736 532.5827 681.7736 ] /Subtype /Link /Type /Annot >>
|
|
||||||
endobj
|
|
||||||
8 0 obj
|
|
||||||
<< /Border [ 0 0 0 ] /Contents () /Dest [ 13 0 R /XYZ 62.69291 414.0236 0 ] /Rect [ 62.69291 651.0236 213.8229 663.0236 ] /Subtype /Link /Type /Annot >>
|
|
||||||
endobj
|
|
||||||
9 0 obj
|
|
||||||
<< /Border [ 0 0 0 ] /Contents () /Dest [ 13 0 R /XYZ 62.69291 414.0236 0 ] /Rect [ 527.0227 651.7736 532.5827 663.7736 ] /Subtype /Link /Type /Annot >>
|
|
||||||
endobj
|
|
||||||
10 0 obj
|
|
||||||
<< /BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font >>
|
|
||||||
endobj
|
|
||||||
11 0 obj
|
|
||||||
<< /Border [ 0 0 0 ] /Contents () /Dest [ 13 0 R /XYZ 62.69291 528.5236 0 ] /Rect [ 515.3527 333.0236 532.1177 345.0236 ] /Subtype /Link /Type /Annot >>
|
|
||||||
endobj
|
|
||||||
12 0 obj
|
|
||||||
<< /Border [ 0 0 0 ] /Contents () /Dest [ 13 0 R /XYZ 62.69291 528.5236 0 ] /Rect [ 62.69291 321.0236 168.2829 333.0236 ] /Subtype /Link /Type /Annot >>
|
|
||||||
endobj
|
|
||||||
13 0 obj
|
|
||||||
<< /Annots [ 4 0 R 5 0 R 6 0 R 7 0 R 8 0 R 9 0 R 11 0 R 12 0 R ] /Contents 21 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0
|
|
||||||
/Trans << >> /Type /Page >>
|
|
||||||
endobj
|
|
||||||
14 0 obj
|
|
||||||
<< /Outlines 16 0 R /PageLabels 22 0 R /PageMode /UseNone /Pages 20 0 R /Type /Catalog >>
|
|
||||||
endobj
|
|
||||||
15 0 obj
|
|
||||||
<< /Author () /CreationDate (D:20181006214730+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20181006214730+00'00') /Producer (ReportLab PDF Library - www.reportlab.com)
|
|
||||||
/Subject (\(unspecified\)) /Title (BCI Bytecode) /Trapped /False >>
|
|
||||||
endobj
|
|
||||||
16 0 obj
|
|
||||||
<< /Count 3 /First 17 0 R /Last 19 0 R /Type /Outlines >>
|
|
||||||
endobj
|
|
||||||
17 0 obj
|
|
||||||
<< /Dest [ 13 0 R /XYZ 62.69291 636.0236 0 ] /Next 18 0 R /Parent 16 0 R /Title (Assembly and Bytecode) >>
|
|
||||||
endobj
|
|
||||||
18 0 obj
|
|
||||||
<< /Dest [ 13 0 R /XYZ 62.69291 525.0236 0 ] /Next 19 0 R /Parent 16 0 R /Prev 17 0 R /Title (The Dynamic Instruction Set) >>
|
|
||||||
endobj
|
|
||||||
19 0 obj
|
|
||||||
<< /Dest [ 13 0 R /XYZ 62.69291 414.0236 0 ] /Parent 16 0 R /Prev 18 0 R /Title (Byte Code Interpreter Definition) >>
|
|
||||||
endobj
|
|
||||||
20 0 obj
|
|
||||||
<< /Count 1 /Kids [ 13 0 R ] /Type /Pages >>
|
|
||||||
endobj
|
|
||||||
21 0 obj
|
|
||||||
<< /Length 3790 >>
|
|
||||||
stream
|
|
||||||
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 741.0236 cm
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 4 Tm /F2 20 Tf 24 TL 169.9349 0 Td (BCI Bytecode) Tj T* -169.9349 0 Td ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 708.0236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Contents) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 648.0236 cm
|
|
||||||
0 0 0 rg
|
|
||||||
BT /F1 10 Tf 12 TL ET
|
|
||||||
q
|
|
||||||
1 0 0 1 0 39 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Assembly and Bytecode) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 397.8898 39 cm
|
|
||||||
q
|
|
||||||
0 0 .501961 rg
|
|
||||||
0 0 .501961 RG
|
|
||||||
BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 66.44 0 Td (1) Tj T* -66.44 0 Td ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 0 21 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (The Dynamic Instruction Set) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 397.8898 21 cm
|
|
||||||
q
|
|
||||||
0 0 .501961 rg
|
|
||||||
0 0 .501961 RG
|
|
||||||
BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 66.44 0 Td (1) Tj T* -66.44 0 Td ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 0 3 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Byte Code Interpreter Definition) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 397.8898 3 cm
|
|
||||||
q
|
|
||||||
0 0 .501961 rg
|
|
||||||
0 0 .501961 RG
|
|
||||||
BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 66.44 0 Td (1) Tj T* -66.44 0 Td ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 615.0236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Assembly and Bytecode) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 585.0236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 14 Tm 3.309982 Tw 12 TL /F1 10 Tf 0 0 0 rg (Unlike machine code \(and other bytecode\) BCI bytecode has dynamic opcodes. This means that) Tj T* 0 Tw (bytecode is ) Tj /F2 10 Tf (not ) Tj /F1 10 Tf (necessarily portable.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 567.0236 cm
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (This makes sense since the BCI instruction set can be extended for applications.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 537.0236 cm
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL .742619 Tw (If one wants to share code that should run on any BCI it should be shared as assembly. The assembler) Tj T* 0 Tw (will then use the local interpreter definition and generate suiting bytecode.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 504.0236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (The Dynamic Instruction Set) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 474.0236 cm
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL 1.093876 Tw (The BCI comes with a set of prepared instructions. These are complete and provide a way to do basic) Tj T* 0 Tw (operations like routines, loops and branching.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 444.0236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 14 Tm .743672 Tw 12 TL /F1 10 Tf 0 0 0 rg (The methods are organized in a binary tree internally. To build the tree in a comfortable way there is an) Tj T* 0 Tw (autoinserter that can insert up to ) Tj /F3 10 Tf 0 0 0 rg (1023 ) Tj /F1 10 Tf 0 0 0 rg (methods into the tree.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 426.0236 cm
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (The autoinserter creates the opcode basing on the order of the method that he inserts.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 393.0236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Byte Code Interpreter Definition) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 351.0236 cm
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 26 Tm /F1 10 Tf 12 TL 1.843555 Tw (A Bytecode Interpreter Definition consists of two mayor parts: The memory definition that defines the) Tj T* 0 Tw 1.896098 Tw (number of data registers \(up to 63\), the number of memory words \(up to 65535\) and the number of) Tj T* 0 Tw (program memory words \(up to 65535\).) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 321.0236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 14 Tm .464985 Tw 12 TL /F1 10 Tf 0 0 0 rg (The second part defines the commands. The definition contains bot the order of the commands \(see ) Tj 0 0 .501961 rg (The) Tj T* 0 Tw (Dynamic Instruction Set) Tj 0 0 0 rg (\) and the required arguments.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
|
|
||||||
endstream
|
|
||||||
endobj
|
|
||||||
22 0 obj
|
|
||||||
<< /Nums [ 0 23 0 R ] >>
|
|
||||||
endobj
|
|
||||||
23 0 obj
|
|
||||||
<< /S /D /St 1 >>
|
|
||||||
endobj
|
|
||||||
xref
|
|
||||||
0 24
|
|
||||||
0000000000 65535 f
|
|
||||||
0000000075 00000 n
|
|
||||||
0000000130 00000 n
|
|
||||||
0000000240 00000 n
|
|
||||||
0000000355 00000 n
|
|
||||||
0000000526 00000 n
|
|
||||||
0000000697 00000 n
|
|
||||||
0000000868 00000 n
|
|
||||||
0000001039 00000 n
|
|
||||||
0000001210 00000 n
|
|
||||||
0000001381 00000 n
|
|
||||||
0000001490 00000 n
|
|
||||||
0000001662 00000 n
|
|
||||||
0000001834 00000 n
|
|
||||||
0000002106 00000 n
|
|
||||||
0000002215 00000 n
|
|
||||||
0000002489 00000 n
|
|
||||||
0000002566 00000 n
|
|
||||||
0000002692 00000 n
|
|
||||||
0000002837 00000 n
|
|
||||||
0000002974 00000 n
|
|
||||||
0000003038 00000 n
|
|
||||||
0000006885 00000 n
|
|
||||||
0000006929 00000 n
|
|
||||||
trailer
|
|
||||||
<< /ID
|
|
||||||
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
|
|
||||||
[(\003\236V\37247z\240'\2312!\276\204\362\214) (\003\236V\37247z\240'\2312!\276\204\362\214)]
|
|
||||||
/Info 15 0 R /Root 14 0 R /Size 24 >>
|
|
||||||
startxref
|
|
||||||
6966
|
|
||||||
%%EOF
|
|
|
@ -1,46 +0,0 @@
|
||||||
BCI Bytecode
|
|
||||||
*************
|
|
||||||
|
|
||||||
.. contents::
|
|
||||||
|
|
||||||
Assembly and Bytecode
|
|
||||||
=====================
|
|
||||||
|
|
||||||
Unlike machine code (and other bytecode) BCI bytecode has
|
|
||||||
dynamic opcodes. This means that bytecode is **not**
|
|
||||||
necessarily portable.
|
|
||||||
|
|
||||||
This makes sense since the BCI instruction set can be
|
|
||||||
extended for applications.
|
|
||||||
|
|
||||||
If one wants to share code that should run on any BCI it
|
|
||||||
should be shared as assembly. The assembler will then use
|
|
||||||
the local interpreter definition and generate suiting
|
|
||||||
bytecode.
|
|
||||||
|
|
||||||
The Dynamic Instruction Set
|
|
||||||
===========================
|
|
||||||
|
|
||||||
The BCI comes with a set of prepared instructions. These are
|
|
||||||
complete and provide a way to do basic operations like
|
|
||||||
routines, loops and branching.
|
|
||||||
|
|
||||||
The methods are organized in a binary tree internally. To
|
|
||||||
build the tree in a comfortable way there is an autoinserter
|
|
||||||
that can insert up to ``1023`` methods into the tree.
|
|
||||||
|
|
||||||
The autoinserter creates the opcode basing on the order of
|
|
||||||
the method that he inserts.
|
|
||||||
|
|
||||||
Byte Code Interpreter Definition
|
|
||||||
================================
|
|
||||||
|
|
||||||
A Bytecode Interpreter Definition consists of two mayor
|
|
||||||
parts: The memory definition that defines the number of data
|
|
||||||
registers (up to 63), the number of memory words (up to
|
|
||||||
65535) and the number of program memory words (up to 65535).
|
|
||||||
|
|
||||||
The second part defines the commands. The definition
|
|
||||||
contains bot the order of the commands (see `The Dynamic
|
|
||||||
Instruction Set`_) and the required arguments.
|
|
||||||
|
|
|
@ -1,881 +0,0 @@
|
||||||
%PDF-1.4
|
|
||||||
%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com
|
|
||||||
1 0 obj
|
|
||||||
<< /F1 2 0 R /F2 3 0 R /F3 14 0 R >>
|
|
||||||
endobj
|
|
||||||
2 0 obj
|
|
||||||
<< /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font >>
|
|
||||||
endobj
|
|
||||||
3 0 obj
|
|
||||||
<< /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font >>
|
|
||||||
endobj
|
|
||||||
4 0 obj
|
|
||||||
<< /Border [ 0 0 0 ] /Contents () /Dest [ 15 0 R /XYZ 62.69291 600.0236 0 ] /Rect [ 62.69291 687.0236 299.9529 699.0236 ] /Subtype /Link /Type /Annot >>
|
|
||||||
endobj
|
|
||||||
5 0 obj
|
|
||||||
<< /Border [ 0 0 0 ] /Contents () /Dest [ 15 0 R /XYZ 62.69291 600.0236 0 ] /Rect [ 527.0227 687.7736 532.5827 699.7736 ] /Subtype /Link /Type /Annot >>
|
|
||||||
endobj
|
|
||||||
6 0 obj
|
|
||||||
<< /Border [ 0 0 0 ] /Contents () /Dest [ 15 0 R /XYZ 62.69291 224.2236 0 ] /Rect [ 62.69291 669.0236 154.3629 681.0236 ] /Subtype /Link /Type /Annot >>
|
|
||||||
endobj
|
|
||||||
7 0 obj
|
|
||||||
<< /Border [ 0 0 0 ] /Contents () /Dest [ 15 0 R /XYZ 62.69291 224.2236 0 ] /Rect [ 527.0227 669.7736 532.5827 681.7736 ] /Subtype /Link /Type /Annot >>
|
|
||||||
endobj
|
|
||||||
8 0 obj
|
|
||||||
<< /Border [ 0 0 0 ] /Contents () /Dest [ 16 0 R /XYZ 62.69291 380.0236 0 ] /Rect [ 62.69291 651.0236 114.3629 663.0236 ] /Subtype /Link /Type /Annot >>
|
|
||||||
endobj
|
|
||||||
9 0 obj
|
|
||||||
<< /Border [ 0 0 0 ] /Contents () /Dest [ 16 0 R /XYZ 62.69291 380.0236 0 ] /Rect [ 527.0227 651.7736 532.5827 663.7736 ] /Subtype /Link /Type /Annot >>
|
|
||||||
endobj
|
|
||||||
10 0 obj
|
|
||||||
<< /Border [ 0 0 0 ] /Contents () /Dest [ 16 0 R /XYZ 62.69291 329.0236 0 ] /Rect [ 62.69291 633.0236 91.59291 645.0236 ] /Subtype /Link /Type /Annot >>
|
|
||||||
endobj
|
|
||||||
11 0 obj
|
|
||||||
<< /Border [ 0 0 0 ] /Contents () /Dest [ 16 0 R /XYZ 62.69291 329.0236 0 ] /Rect [ 527.0227 633.7736 532.5827 645.7736 ] /Subtype /Link /Type /Annot >>
|
|
||||||
endobj
|
|
||||||
12 0 obj
|
|
||||||
<< /Border [ 0 0 0 ] /Contents () /Dest [ 18 0 R /XYZ 62.69291 765.0236 0 ] /Rect [ 62.69291 615.0236 118.2529 627.0236 ] /Subtype /Link /Type /Annot >>
|
|
||||||
endobj
|
|
||||||
13 0 obj
|
|
||||||
<< /Border [ 0 0 0 ] /Contents () /Dest [ 18 0 R /XYZ 62.69291 765.0236 0 ] /Rect [ 527.0227 615.7736 532.5827 627.7736 ] /Subtype /Link /Type /Annot >>
|
|
||||||
endobj
|
|
||||||
14 0 obj
|
|
||||||
<< /BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font >>
|
|
||||||
endobj
|
|
||||||
15 0 obj
|
|
||||||
<< /Annots [ 4 0 R 5 0 R 6 0 R 7 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R 13 0 R ] /Contents 28 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 27 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0
|
|
||||||
/Trans << >> /Type /Page >>
|
|
||||||
endobj
|
|
||||||
16 0 obj
|
|
||||||
<< /Contents 29 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 27 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0 /Trans << >>
|
|
||||||
/Type /Page >>
|
|
||||||
endobj
|
|
||||||
17 0 obj
|
|
||||||
<< /Border [ 0 0 0 ] /Contents () /Dest [ 16 0 R /XYZ 62.69291 332.5236 0 ] /Rect [ 62.69291 680.7736 91.59291 692.7736 ] /Subtype /Link /Type /Annot >>
|
|
||||||
endobj
|
|
||||||
18 0 obj
|
|
||||||
<< /Annots [ 17 0 R ] /Contents 30 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 27 0 R /Resources << /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Rotate 0
|
|
||||||
/Trans << >> /Type /Page >>
|
|
||||||
endobj
|
|
||||||
19 0 obj
|
|
||||||
<< /Outlines 21 0 R /PageLabels 31 0 R /PageMode /UseNone /Pages 27 0 R /Type /Catalog >>
|
|
||||||
endobj
|
|
||||||
20 0 obj
|
|
||||||
<< /Author () /CreationDate (D:20181006214702+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20181006214702+00'00') /Producer (ReportLab PDF Library - www.reportlab.com)
|
|
||||||
/Subject (\(unspecified\)) /Title (BCI Assembly Language) /Trapped /False >>
|
|
||||||
endobj
|
|
||||||
21 0 obj
|
|
||||||
<< /Count 5 /First 22 0 R /Last 26 0 R /Type /Outlines >>
|
|
||||||
endobj
|
|
||||||
22 0 obj
|
|
||||||
<< /Dest [ 15 0 R /XYZ 62.69291 600.0236 0 ] /Next 23 0 R /Parent 21 0 R /Title (Commands, Small Arguments and Big Arguments) >>
|
|
||||||
endobj
|
|
||||||
23 0 obj
|
|
||||||
<< /Dest [ 15 0 R /XYZ 62.69291 224.2236 0 ] /Next 24 0 R /Parent 21 0 R /Prev 22 0 R /Title (Built-In Commands) >>
|
|
||||||
endobj
|
|
||||||
24 0 obj
|
|
||||||
<< /Dest [ 16 0 R /XYZ 62.69291 380.0236 0 ] /Next 25 0 R /Parent 21 0 R /Prev 23 0 R /Title (Comments) >>
|
|
||||||
endobj
|
|
||||||
25 0 obj
|
|
||||||
<< /Dest [ 16 0 R /XYZ 62.69291 329.0236 0 ] /Next 26 0 R /Parent 21 0 R /Prev 24 0 R /Title (Marks) >>
|
|
||||||
endobj
|
|
||||||
26 0 obj
|
|
||||||
<< /Dest [ 18 0 R /XYZ 62.69291 765.0236 0 ] /Parent 21 0 R /Prev 25 0 R /Title (Direct Input) >>
|
|
||||||
endobj
|
|
||||||
27 0 obj
|
|
||||||
<< /Count 3 /Kids [ 15 0 R 16 0 R 18 0 R ] /Type /Pages >>
|
|
||||||
endobj
|
|
||||||
28 0 obj
|
|
||||||
<< /Length 6815 >>
|
|
||||||
stream
|
|
||||||
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 741.0236 cm
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 4 Tm /F2 20 Tf 24 TL 117.6949 0 Td (BCI Assembly Language) Tj T* -117.6949 0 Td ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 708.0236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Contents) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 612.0236 cm
|
|
||||||
0 0 0 rg
|
|
||||||
BT /F1 10 Tf 12 TL ET
|
|
||||||
q
|
|
||||||
1 0 0 1 0 75 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Commands, Small Arguments and Big Arguments) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 397.8898 75 cm
|
|
||||||
q
|
|
||||||
0 0 .501961 rg
|
|
||||||
0 0 .501961 RG
|
|
||||||
BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 66.44 0 Td (1) Tj T* -66.44 0 Td ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 0 57 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Built-In Commands) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 397.8898 57 cm
|
|
||||||
q
|
|
||||||
0 0 .501961 rg
|
|
||||||
0 0 .501961 RG
|
|
||||||
BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 66.44 0 Td (1) Tj T* -66.44 0 Td ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 0 39 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Comments) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 397.8898 39 cm
|
|
||||||
q
|
|
||||||
0 0 .501961 rg
|
|
||||||
0 0 .501961 RG
|
|
||||||
BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 66.44 0 Td (2) Tj T* -66.44 0 Td ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 0 21 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Marks) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 397.8898 21 cm
|
|
||||||
q
|
|
||||||
0 0 .501961 rg
|
|
||||||
0 0 .501961 RG
|
|
||||||
BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 66.44 0 Td (2) Tj T* -66.44 0 Td ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 0 3 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf 0 0 .501961 rg (Direct Input) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 397.8898 3 cm
|
|
||||||
q
|
|
||||||
0 0 .501961 rg
|
|
||||||
0 0 .501961 RG
|
|
||||||
BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL 66.44 0 Td (3) Tj T* -66.44 0 Td ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 579.0236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Commands, Small Arguments and Big Arguments) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 549.0236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 14 Tm .87311 Tw 12 TL /F1 10 Tf 0 0 0 rg (A command in BCI Assembly is a word starting with an alphabetic character \() Tj /F3 10 Tf 0 0 0 rg (a..zA..Z) Tj /F1 10 Tf 0 0 0 rg (\) following by a) Tj T* 0 Tw (sequence of alphanumeric characters \() Tj /F3 10 Tf 0 0 0 rg (a..zA..Z0..9) Tj /F1 10 Tf 0 0 0 rg (\). This word will be converted to a 10bit opcode.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 519.0236 cm
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL 2.147882 Tw (Embedded in the 16bits of a word there is also a 6bit small argument. If a command has no small) Tj T* 0 Tw (argument these bits will be zeroed. In the assembly the command will be only one word, for example:) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 485.8236 cm
|
|
||||||
q
|
|
||||||
q
|
|
||||||
1 0 0 1 0 0 cm
|
|
||||||
q
|
|
||||||
1 0 0 1 6.6 6.6 cm
|
|
||||||
q
|
|
||||||
.662745 .662745 .662745 RG
|
|
||||||
.5 w
|
|
||||||
.960784 .960784 .862745 rg
|
|
||||||
n -6 -6 468.6898 24 re B*
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL (cli) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 453.8236 cm
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL .345988 Tw (If the command has a small argument, the 6 bit will be filled with the small argument. In the assembly the) Tj T* 0 Tw (small argument is separated by one whitespace, for example:) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 420.6236 cm
|
|
||||||
q
|
|
||||||
q
|
|
||||||
1 0 0 1 0 0 cm
|
|
||||||
q
|
|
||||||
1 0 0 1 6.6 6.6 cm
|
|
||||||
q
|
|
||||||
.662745 .662745 .662745 RG
|
|
||||||
.5 w
|
|
||||||
.960784 .960784 .862745 rg
|
|
||||||
n -6 -6 468.6898 24 re B*
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL (inc r0) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 376.6236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 26 Tm .629431 Tw 12 TL /F1 10 Tf 0 0 0 rg (Any other arguments are stored in further words and have thus a width of 16bits. They are separated by) Tj T* 0 Tw 2.211751 Tw (commas \() Tj /F3 10 Tf 0 0 0 rg (,) Tj /F1 10 Tf 0 0 0 rg (\) from both the first and any other arguments. It is recommended to only add one more) Tj T* 0 Tw (argument.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 358.6236 cm
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Example for one big argument:) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 325.4236 cm
|
|
||||||
q
|
|
||||||
q
|
|
||||||
1 0 0 1 0 0 cm
|
|
||||||
q
|
|
||||||
1 0 0 1 6.6 6.6 cm
|
|
||||||
q
|
|
||||||
.662745 .662745 .662745 RG
|
|
||||||
.5 w
|
|
||||||
.960784 .960784 .862745 rg
|
|
||||||
n -6 -6 468.6898 24 re B*
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL (ldi r0, 0xdead) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 293.4236 cm
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL 1.571318 Tw (It might be useful to have more arguments for other applications, like double precision floating points.) Tj T* 0 Tw (Example \(not implemented\):) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 236.2236 cm
|
|
||||||
q
|
|
||||||
q
|
|
||||||
1 0 0 1 0 0 cm
|
|
||||||
q
|
|
||||||
1 0 0 1 6.6 6.6 cm
|
|
||||||
q
|
|
||||||
.662745 .662745 .662745 RG
|
|
||||||
.5 w
|
|
||||||
.960784 .960784 .862745 rg
|
|
||||||
n -6 -6 468.6898 48 re B*
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 26 Tm /F3 10 Tf 12 TL (lddfi r0, 0xdead, 0xbeef) Tj T* (; load double precision floating point) Tj T* (; to r0 and r1) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 203.2236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Built-In Commands) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 185.2236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 0 rg (ldi) Tj ( ) Tj (<) Tj (sa) Tj (>) Tj (,) Tj ( ) Tj (<) Tj (ba) Tj (>) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 170.2236 cm
|
|
||||||
0 0 0 rg
|
|
||||||
BT /F1 10 Tf 12 TL ET
|
|
||||||
BT 1 0 0 1 0 2 Tm T* ET
|
|
||||||
q
|
|
||||||
1 0 0 1 20 0 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (Load the value ) Tj /F3 10 Tf 0 0 0 rg (<) Tj (ba) Tj (> ) Tj /F1 10 Tf 0 0 0 rg (into register ) Tj /F3 10 Tf 0 0 0 rg (<) Tj (sa) Tj (>) Tj /F1 10 Tf 0 0 0 rg (.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 154.2236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 0 rg (ld) Tj ( ) Tj (<) Tj (sa) Tj (>) Tj (,) Tj ( ) Tj (<) Tj (ba) Tj (>) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 139.2236 cm
|
|
||||||
0 0 0 rg
|
|
||||||
BT /F1 10 Tf 12 TL ET
|
|
||||||
BT 1 0 0 1 0 2 Tm T* ET
|
|
||||||
q
|
|
||||||
1 0 0 1 20 0 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (Load the value of the memory cell at ) Tj /F3 10 Tf 0 0 0 rg (<) Tj (ba) Tj (> ) Tj /F1 10 Tf 0 0 0 rg (into register ) Tj /F3 10 Tf 0 0 0 rg (<) Tj (sa) Tj (>) Tj /F1 10 Tf 0 0 0 rg (.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 123.2236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 0 rg (st) Tj ( ) Tj (<) Tj (sa) Tj (>) Tj (,) Tj ( ) Tj (<) Tj (ba) Tj (>) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 108.2236 cm
|
|
||||||
0 0 0 rg
|
|
||||||
BT /F1 10 Tf 12 TL ET
|
|
||||||
BT 1 0 0 1 0 2 Tm T* ET
|
|
||||||
q
|
|
||||||
1 0 0 1 20 0 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (Store the value of register ) Tj /F3 10 Tf 0 0 0 rg (<) Tj (sa) Tj (> ) Tj /F1 10 Tf 0 0 0 rg (into the memory cell at ) Tj /F3 10 Tf 0 0 0 rg (<) Tj (ba) Tj (>) Tj /F1 10 Tf 0 0 0 rg (.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 92.22362 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 0 rg (inc) Tj ( ) Tj (<) Tj (sa) Tj (>) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 77.22362 cm
|
|
||||||
0 0 0 rg
|
|
||||||
BT /F1 10 Tf 12 TL ET
|
|
||||||
BT 1 0 0 1 0 2 Tm T* ET
|
|
||||||
q
|
|
||||||
1 0 0 1 20 0 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (Increment the value of register ) Tj /F3 10 Tf 0 0 0 rg (<) Tj (sa) Tj (>) Tj /F1 10 Tf 0 0 0 rg (.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
|
|
||||||
endstream
|
|
||||||
endobj
|
|
||||||
29 0 obj
|
|
||||||
<< /Length 7261 >>
|
|
||||||
stream
|
|
||||||
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 753.0236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 0 rg (dec) Tj ( ) Tj (<) Tj (sa) Tj (>) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 738.0236 cm
|
|
||||||
0 0 0 rg
|
|
||||||
BT /F1 10 Tf 12 TL ET
|
|
||||||
BT 1 0 0 1 0 2 Tm T* ET
|
|
||||||
q
|
|
||||||
1 0 0 1 20 0 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (Decrement the value of register ) Tj /F3 10 Tf 0 0 0 rg (<) Tj (sa) Tj (>) Tj /F1 10 Tf 0 0 0 rg (.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 722.0236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 0 rg (add|sub|mul|div) Tj ( ) Tj (<) Tj (sa) Tj (>) Tj (,) Tj ( ) Tj (<) Tj (ba) Tj (>) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 695.0236 cm
|
|
||||||
0 0 0 rg
|
|
||||||
BT /F1 10 Tf 12 TL ET
|
|
||||||
BT 1 0 0 1 0 14 Tm T* ET
|
|
||||||
q
|
|
||||||
1 0 0 1 20 0 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 14 Tm 1.127318 Tw 12 TL /F3 10 Tf 0 0 0 rg (<) Tj (sa) Tj (>) Tj ( ) Tj (=) Tj ( ) Tj (<) Tj (sa) Tj (>) Tj ( ) Tj (+|-|*|/) Tj ( ) Tj (<) Tj (ba) Tj (> ) Tj /F1 10 Tf 0 0 0 rg (where ) Tj /F3 10 Tf 0 0 0 rg (<) Tj (sa) Tj (> ) Tj /F1 10 Tf 0 0 0 rg (and ) Tj /F3 10 Tf 0 0 0 rg (<) Tj (ba) Tj (> ) Tj /F1 10 Tf 0 0 0 rg (are registers. Write the overflow into the) Tj T* 0 Tw (status register.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 679.0236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 0 rg (gt|ge|lt|le|eq) Tj ( ) Tj (<) Tj (sa) Tj (>) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 652.0236 cm
|
|
||||||
0 0 0 rg
|
|
||||||
BT /F1 10 Tf 12 TL ET
|
|
||||||
BT 1 0 0 1 0 14 Tm T* ET
|
|
||||||
q
|
|
||||||
1 0 0 1 20 0 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 14 Tm 2.431098 Tw 12 TL /F1 10 Tf 0 0 0 rg (Check if the value of register ) Tj /F3 10 Tf 0 0 0 rg (<) Tj (sa) Tj (> ) Tj /F1 10 Tf 0 0 0 rg (is ) Tj /F3 10 Tf 0 0 0 rg (>) Tj (|) Tj (>) Tj (=|) Tj (<) Tj (|) Tj (<) Tj (=|== ) Tj /F1 10 Tf 0 0 0 rg (to ) Tj /F3 10 Tf 0 0 0 rg (0) Tj /F1 10 Tf 0 0 0 rg (. Set the status register to ) Tj /F3 10 Tf 0 0 0 rg (1 ) Tj /F1 10 Tf 0 0 0 rg (if it) Tj T* 0 Tw (evaluates true, else to ) Tj /F3 10 Tf 0 0 0 rg (0) Tj /F1 10 Tf 0 0 0 rg (.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 636.0236 cm
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL (not) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 621.0236 cm
|
|
||||||
0 0 0 rg
|
|
||||||
BT /F1 10 Tf 12 TL ET
|
|
||||||
BT 1 0 0 1 0 2 Tm T* ET
|
|
||||||
q
|
|
||||||
1 0 0 1 20 0 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (If the status register is ) Tj /F3 10 Tf 0 0 0 rg (0 ) Tj /F1 10 Tf 0 0 0 rg (set it to ) Tj /F3 10 Tf 0 0 0 rg (1) Tj /F1 10 Tf 0 0 0 rg (, else set it to ) Tj /F3 10 Tf 0 0 0 rg (0) Tj /F1 10 Tf 0 0 0 rg (.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 605.0236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 0 rg (jmp) Tj ( ) Tj (<) Tj (sa) Tj (>) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 590.0236 cm
|
|
||||||
0 0 0 rg
|
|
||||||
BT /F1 10 Tf 12 TL ET
|
|
||||||
BT 1 0 0 1 0 2 Tm T* ET
|
|
||||||
q
|
|
||||||
1 0 0 1 20 0 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (Set the program counter to the value of register ) Tj /F3 10 Tf 0 0 0 rg (<) Tj (sa) Tj (>) Tj /F1 10 Tf 0 0 0 rg (.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 574.0236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 0 rg (call) Tj ( ) Tj (<) Tj (sa) Tj (>) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 547.0236 cm
|
|
||||||
0 0 0 rg
|
|
||||||
BT /F1 10 Tf 12 TL ET
|
|
||||||
BT 1 0 0 1 0 14 Tm T* ET
|
|
||||||
q
|
|
||||||
1 0 0 1 20 0 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 14 Tm .797633 Tw 12 TL /F1 10 Tf 0 0 0 rg (Push the current program counter on the stack and set the program counter to the value of register) Tj T* 0 Tw /F3 10 Tf 0 0 0 rg (<) Tj (sa) Tj (>) Tj /F1 10 Tf 0 0 0 rg (.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 531.0236 cm
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL (ret) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 516.0236 cm
|
|
||||||
0 0 0 rg
|
|
||||||
BT /F1 10 Tf 12 TL ET
|
|
||||||
BT 1 0 0 1 0 2 Tm T* ET
|
|
||||||
q
|
|
||||||
1 0 0 1 20 0 cm
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Pop the previously pushed program counter from the stack.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 500.0236 cm
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL (stop) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 485.0236 cm
|
|
||||||
0 0 0 rg
|
|
||||||
BT /F1 10 Tf 12 TL ET
|
|
||||||
BT 1 0 0 1 0 2 Tm T* ET
|
|
||||||
q
|
|
||||||
1 0 0 1 20 0 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (Write ) Tj /F3 10 Tf 0 0 0 rg (1 ) Tj /F1 10 Tf 0 0 0 rg (into the shutdown register. This will cause the interpreter to halt.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 469.0236 cm
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 2 Tm /F3 10 Tf 12 TL (cl) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 454.0236 cm
|
|
||||||
0 0 0 rg
|
|
||||||
BT /F1 10 Tf 12 TL ET
|
|
||||||
BT 1 0 0 1 0 2 Tm T* ET
|
|
||||||
q
|
|
||||||
1 0 0 1 20 0 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (Write ) Tj /F3 10 Tf 0 0 0 rg (0 ) Tj /F1 10 Tf 0 0 0 rg (into the status register.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 438.0236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 0 rg (cjmp) Tj ( ) Tj (<) Tj (sa) Tj (>) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 423.0236 cm
|
|
||||||
0 0 0 rg
|
|
||||||
BT /F1 10 Tf 12 TL ET
|
|
||||||
BT 1 0 0 1 0 2 Tm T* ET
|
|
||||||
q
|
|
||||||
1 0 0 1 20 0 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (If there not a ) Tj /F3 10 Tf 0 0 0 rg (0 ) Tj /F1 10 Tf 0 0 0 rg (in the status register, ) Tj /F3 10 Tf 0 0 0 rg (jmp <) Tj (sa) Tj (>) Tj /F1 10 Tf 0 0 0 rg (, else continue execution.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 407.0236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F3 10 Tf 0 0 0 rg (ccall) Tj ( ) Tj (<) Tj (sa) Tj (>) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 392.0236 cm
|
|
||||||
0 0 0 rg
|
|
||||||
BT /F1 10 Tf 12 TL ET
|
|
||||||
BT 1 0 0 1 0 2 Tm T* ET
|
|
||||||
q
|
|
||||||
1 0 0 1 20 0 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (Like ) Tj /F3 10 Tf 0 0 0 rg (cjmp) Tj ( ) Tj (<) Tj (sa) Tj (> ) Tj /F1 10 Tf 0 0 0 rg (but with ) Tj /F3 10 Tf 0 0 0 rg (call ) Tj /F1 10 Tf 0 0 0 rg (instead.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 359.0236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Comments) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 341.0236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (Comments start with a ) Tj /F3 10 Tf 0 0 0 rg (; ) Tj /F1 10 Tf 0 0 0 rg (at the beginning of the line and end at the end of the line.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 308.0236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Marks) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 278.0236 cm
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL .467485 Tw (Marks represent a special location of the assembly code. The assembler keeps track of those marks and) Tj T* 0 Tw (they can be used as immediate input.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 236.0236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 26 Tm 2.869983 Tw 12 TL /F1 10 Tf 0 0 0 rg (A mark is defined by a single word, starting with an alphabetic character \() Tj /F3 10 Tf 0 0 0 rg (a..zA...Z) Tj /F1 10 Tf 0 0 0 rg (\) containing) Tj T* 0 Tw 2.330814 Tw (alphanumeric characters and underscores \() Tj /F3 10 Tf 0 0 0 rg (a..zA..Z0..9_) Tj /F1 10 Tf 0 0 0 rg (\) followed by a colon \() Tj /F3 10 Tf 0 0 0 rg (:) Tj /F1 10 Tf 0 0 0 rg (\) and a newline) Tj T* 0 Tw (character.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 218.0236 cm
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Example:) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 100.8236 cm
|
|
||||||
q
|
|
||||||
q
|
|
||||||
1 0 0 1 0 0 cm
|
|
||||||
q
|
|
||||||
1 0 0 1 6.6 6.6 cm
|
|
||||||
q
|
|
||||||
.662745 .662745 .662745 RG
|
|
||||||
.5 w
|
|
||||||
.960784 .960784 .862745 rg
|
|
||||||
n -6 -6 468.6898 108 re B*
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 86 Tm /F3 10 Tf 12 TL (ldi r0, this_is_a_mark) Tj T* (ldi r1, 0xfefe) Tj T* (ldi r2, 0xefef) Tj T* T* (this_is_a_mark:) Tj T* (add r2, r1) Tj T* (; this will result in an infinite loop.) Tj T* (jmp r0) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
|
|
||||||
endstream
|
|
||||||
endobj
|
|
||||||
30 0 obj
|
|
||||||
<< /Length 2972 >>
|
|
||||||
stream
|
|
||||||
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 744.0236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Direct Input) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 726.0236 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (The core instruction set contains the ) Tj /F3 10 Tf 0 0 0 rg (ldi ) Tj /F1 10 Tf 0 0 0 rg (command that can be used to load data into a register directly.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 696.0236 cm
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL 2.501318 Tw (The first \(big\) argument of this command is always a 16bit word. The assembler can automatically) Tj T* 0 Tw (generate the correct value if the argument is provided in the following ways:) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 680.0236 cm
|
|
||||||
q
|
|
||||||
0 0 .501961 rg
|
|
||||||
0 0 .501961 RG
|
|
||||||
BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL (Marks) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 665.0236 cm
|
|
||||||
0 0 0 rg
|
|
||||||
BT /F1 10 Tf 12 TL ET
|
|
||||||
BT 1 0 0 1 0 2 Tm T* ET
|
|
||||||
q
|
|
||||||
1 0 0 1 20 0 cm
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (The assembler inserts the absolute offset of the Mark.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 649.0236 cm
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL (A decimal value) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 634.0236 cm
|
|
||||||
0 0 0 rg
|
|
||||||
BT /F1 10 Tf 12 TL ET
|
|
||||||
BT 1 0 0 1 0 2 Tm T* ET
|
|
||||||
q
|
|
||||||
1 0 0 1 20 0 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (The assembler inserts the value \(i.e. ) Tj /F3 10 Tf 0 0 0 rg (ldi) Tj ( ) Tj (r0, 12) Tj /F1 10 Tf 0 0 0 rg (\).) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 618.0236 cm
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL (A hexadecimal value) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 603.0236 cm
|
|
||||||
0 0 0 rg
|
|
||||||
BT /F1 10 Tf 12 TL ET
|
|
||||||
BT 1 0 0 1 0 2 Tm T* ET
|
|
||||||
q
|
|
||||||
1 0 0 1 20 0 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (If the argument starts with ) Tj /F3 10 Tf 0 0 0 rg (0x ) Tj /F1 10 Tf 0 0 0 rg (the assembler will interpret the argument as hexadecimal.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 587.0236 cm
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL (A binary value) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 572.0236 cm
|
|
||||||
0 0 0 rg
|
|
||||||
BT /F1 10 Tf 12 TL ET
|
|
||||||
BT 1 0 0 1 0 2 Tm T* ET
|
|
||||||
q
|
|
||||||
1 0 0 1 20 0 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (If the argument starts with ) Tj /F3 10 Tf 0 0 0 rg (0b ) Tj /F1 10 Tf 0 0 0 rg (the assembler will interpret the value as binary.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 556.0236 cm
|
|
||||||
q
|
|
||||||
0 0 0 rg
|
|
||||||
BT 1 0 0 1 0 2 Tm /F2 10 Tf 12 TL (A character) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
1 0 0 1 62.69291 529.0236 cm
|
|
||||||
0 0 0 rg
|
|
||||||
BT /F1 10 Tf 12 TL ET
|
|
||||||
BT 1 0 0 1 0 14 Tm T* ET
|
|
||||||
q
|
|
||||||
1 0 0 1 20 0 cm
|
|
||||||
q
|
|
||||||
BT 1 0 0 1 0 14 Tm .82811 Tw 12 TL /F1 10 Tf 0 0 0 rg (If the argument is either a single character surrounded by two ) Tj /F3 10 Tf 0 0 0 rg (' ) Tj /F1 10 Tf 0 0 0 rg (characters or any unicode escape) Tj T* 0 Tw (sequence surrounded by ) Tj /F3 10 Tf 0 0 0 rg (' ) Tj /F1 10 Tf 0 0 0 rg (characters the assembler will insert the integer representation.) Tj T* ET
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
q
|
|
||||||
Q
|
|
||||||
Q
|
|
||||||
|
|
||||||
endstream
|
|
||||||
endobj
|
|
||||||
31 0 obj
|
|
||||||
<< /Nums [ 0 32 0 R 1 33 0 R 2 34 0 R ] >>
|
|
||||||
endobj
|
|
||||||
32 0 obj
|
|
||||||
<< /S /D /St 1 >>
|
|
||||||
endobj
|
|
||||||
33 0 obj
|
|
||||||
<< /S /D /St 2 >>
|
|
||||||
endobj
|
|
||||||
34 0 obj
|
|
||||||
<< /S /D /St 3 >>
|
|
||||||
endobj
|
|
||||||
xref
|
|
||||||
0 35
|
|
||||||
0000000000 65535 f
|
|
||||||
0000000075 00000 n
|
|
||||||
0000000130 00000 n
|
|
||||||
0000000240 00000 n
|
|
||||||
0000000355 00000 n
|
|
||||||
0000000526 00000 n
|
|
||||||
0000000697 00000 n
|
|
||||||
0000000868 00000 n
|
|
||||||
0000001039 00000 n
|
|
||||||
0000001210 00000 n
|
|
||||||
0000001381 00000 n
|
|
||||||
0000001553 00000 n
|
|
||||||
0000001725 00000 n
|
|
||||||
0000001897 00000 n
|
|
||||||
0000002069 00000 n
|
|
||||||
0000002178 00000 n
|
|
||||||
0000002464 00000 n
|
|
||||||
0000002674 00000 n
|
|
||||||
0000002846 00000 n
|
|
||||||
0000003075 00000 n
|
|
||||||
0000003184 00000 n
|
|
||||||
0000003467 00000 n
|
|
||||||
0000003544 00000 n
|
|
||||||
0000003692 00000 n
|
|
||||||
0000003827 00000 n
|
|
||||||
0000003953 00000 n
|
|
||||||
0000004076 00000 n
|
|
||||||
0000004193 00000 n
|
|
||||||
0000004271 00000 n
|
|
||||||
0000011143 00000 n
|
|
||||||
0000018461 00000 n
|
|
||||||
0000021490 00000 n
|
|
||||||
0000021552 00000 n
|
|
||||||
0000021589 00000 n
|
|
||||||
0000021626 00000 n
|
|
||||||
trailer
|
|
||||||
<< /ID
|
|
||||||
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
|
|
||||||
[(\372\(\217\316\222\3169q\222\376\355\325c1\302>) (\372\(\217\316\222\3169q\222\376\355\325c1\302>)]
|
|
||||||
/Info 20 0 R /Root 19 0 R /Size 35 >>
|
|
||||||
startxref
|
|
||||||
21663
|
|
||||||
%%EOF
|
|
|
@ -1,180 +0,0 @@
|
||||||
BCI Assembly Language
|
|
||||||
*********************
|
|
||||||
|
|
||||||
.. contents::
|
|
||||||
|
|
||||||
Commands, Small Arguments and Big Arguments
|
|
||||||
===========================================
|
|
||||||
|
|
||||||
A command in BCI Assembly is a word starting with an
|
|
||||||
alphabetic character (``a..zA..Z``) following by a sequence
|
|
||||||
of alphanumeric characters (``a..zA..Z0..9``).
|
|
||||||
This word will be converted to a 10bit opcode.
|
|
||||||
|
|
||||||
Embedded in the 16bits of a word there is also a 6bit small
|
|
||||||
argument. If a command has no small argument these bits will
|
|
||||||
be zeroed. In the assembly the command will be only one
|
|
||||||
word, for example::
|
|
||||||
|
|
||||||
cli
|
|
||||||
|
|
||||||
If the command has a small argument, the 6 bit will be
|
|
||||||
filled with the small argument. In the assembly the small
|
|
||||||
argument is separated by one whitespace, for example::
|
|
||||||
|
|
||||||
inc r0
|
|
||||||
|
|
||||||
Any other arguments are stored in further words and have
|
|
||||||
thus a width of 16bits. They are separated by commas (``,``)
|
|
||||||
from both the first and any other arguments.
|
|
||||||
It is recommended to only add one more argument.
|
|
||||||
|
|
||||||
Example for one big argument::
|
|
||||||
|
|
||||||
ldi r0, 0xdead
|
|
||||||
|
|
||||||
It might be useful to have more arguments for other
|
|
||||||
applications, like double precision floating points.
|
|
||||||
Example (not implemented)::
|
|
||||||
|
|
||||||
lddfi r0, r1, 0xdead, 0xbeef
|
|
||||||
; load double precision floating point
|
|
||||||
; to r0 and r1
|
|
||||||
|
|
||||||
Register Names
|
|
||||||
==============
|
|
||||||
|
|
||||||
Only data registers can be accessed directly. They are
|
|
||||||
prefixed with a ``r`` and are indexed starting with ``0``.
|
|
||||||
|
|
||||||
Examples: ``r0, r1, r2, ..., r11, r12``
|
|
||||||
|
|
||||||
|
|
||||||
Built-In Commands
|
|
||||||
=================
|
|
||||||
|
|
||||||
``ldi <sa>, <ba>``
|
|
||||||
Load the value ``<ba>`` into register ``<sa>``.
|
|
||||||
|
|
||||||
``ld <sa>, <ba>``
|
|
||||||
Load the value of the memory cell at ``<ba>`` into
|
|
||||||
register ``<sa>``.
|
|
||||||
|
|
||||||
``st <sa>, <ba>``
|
|
||||||
Store the value of register ``<sa>`` into the memory
|
|
||||||
cell at ``<ba>``.
|
|
||||||
|
|
||||||
``inc <sa>``
|
|
||||||
Increment the value of register ``<sa>``.
|
|
||||||
|
|
||||||
``dec <sa>``
|
|
||||||
Decrement the value of register ``<sa>``.
|
|
||||||
|
|
||||||
``add|sub|mul|div <sa>, <ba>``
|
|
||||||
``<sa> = <sa> +|-|*|/ <ba>`` where ``<sa>`` and
|
|
||||||
``<ba>`` are registers. Write the overflow into the
|
|
||||||
status register.
|
|
||||||
|
|
||||||
``gt|ge|lt|le|eq <sa>``
|
|
||||||
Check if the value of register ``<sa>`` is
|
|
||||||
``>|>=|<|<=|==`` to ``0``. Set the status register
|
|
||||||
to ``1`` if it evaluates true, else to ``0``.
|
|
||||||
|
|
||||||
``not``
|
|
||||||
If the status register is ``0`` set it to ``1``,
|
|
||||||
else set it to ``0``.
|
|
||||||
|
|
||||||
``jmp <sa>``
|
|
||||||
Set the program counter to the value of register
|
|
||||||
``<sa>``.
|
|
||||||
|
|
||||||
``call <sa>``
|
|
||||||
Push the current program counter on the stack and
|
|
||||||
set the program counter to the value of register ``<sa>``.
|
|
||||||
|
|
||||||
``ret``
|
|
||||||
Pop the previously pushed program counter from the stack.
|
|
||||||
|
|
||||||
``stop``
|
|
||||||
Write ``1`` into the shutdown register. This will
|
|
||||||
cause the interpreter to halt.
|
|
||||||
``cl``
|
|
||||||
Write ``0`` into the status register.
|
|
||||||
|
|
||||||
``cjmp <sa>``
|
|
||||||
If there not a ``0`` in the status register, ``jmp
|
|
||||||
<sa>``, else continue execution.
|
|
||||||
|
|
||||||
``ccall <sa>``
|
|
||||||
Like ``cjmp <sa>`` but with ``call`` instead.
|
|
||||||
|
|
||||||
Comments
|
|
||||||
========
|
|
||||||
|
|
||||||
Comments start with a ``;`` at the beginning of the line and
|
|
||||||
end at the end of the line.
|
|
||||||
|
|
||||||
Marks
|
|
||||||
=====
|
|
||||||
|
|
||||||
Marks represent a special location of the assembly code. The
|
|
||||||
assembler keeps track of those marks and they can be used as
|
|
||||||
immediate input.
|
|
||||||
|
|
||||||
A mark is defined by a single word, starting with an
|
|
||||||
alphabetic character (``a..zA...Z``) containing alphanumeric
|
|
||||||
characters and underscores (``a..zA..Z0..9_``) followed by
|
|
||||||
a colon (``:``) and a newline character.
|
|
||||||
|
|
||||||
Example::
|
|
||||||
|
|
||||||
ldi r0, this_is_a_mark
|
|
||||||
ldi r1, 0xfefe
|
|
||||||
ldi r2, 0xefef
|
|
||||||
|
|
||||||
this_is_a_mark:
|
|
||||||
add r2, r1
|
|
||||||
; this will result in an infinite loop.
|
|
||||||
jmp r0
|
|
||||||
|
|
||||||
|
|
||||||
Direct Input
|
|
||||||
============
|
|
||||||
|
|
||||||
The core instruction set contains the ``ldi`` command that
|
|
||||||
can be used to load data into a register directly.
|
|
||||||
|
|
||||||
The first (big) argument of this command is always a 16bit
|
|
||||||
word. The assembler can automatically generate the correct
|
|
||||||
value if the argument is provided in the following ways:
|
|
||||||
|
|
||||||
`Marks`_
|
|
||||||
The assembler inserts the absolute offset of the
|
|
||||||
Mark.
|
|
||||||
A decimal value
|
|
||||||
The assembler inserts the value (i.e. ``ldi r0,
|
|
||||||
12``).
|
|
||||||
A hexadecimal value
|
|
||||||
If the argument starts with ``0x`` the assembler
|
|
||||||
will interpret the argument as hexadecimal.
|
|
||||||
A binary value
|
|
||||||
If the argument starts with ``0b`` the assembler
|
|
||||||
will interpret the value as binary.
|
|
||||||
A character
|
|
||||||
If the argument is either a single character
|
|
||||||
surrounded by two ``'`` characters or any unicode
|
|
||||||
escape sequence surrounded by ``'`` characters the
|
|
||||||
assembler will insert the integer representation.
|
|
||||||
|
|
||||||
Explicit Data Programming
|
|
||||||
=========================
|
|
||||||
|
|
||||||
One can explicitly set data in the program memory by using
|
|
||||||
the ``.set`` directive. It uses the following semantics::
|
|
||||||
|
|
||||||
".set" "[" <value> {,<value>} "]"
|
|
||||||
|
|
||||||
Where ``<value>`` is a `Direct Input`_ value. The assembler
|
|
||||||
will insert the data at exactly the location where the
|
|
||||||
``.set`` appears. The assembler ignores any whitespace or
|
|
||||||
newline characters between the brackets ``[]``.
|
|
|
@ -1,101 +0,0 @@
|
||||||
import pytest
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def basic_machine_definition():
|
|
||||||
return (
|
|
||||||
{
|
|
||||||
"registers": 20
|
|
||||||
, "memory": 100
|
|
||||||
, "program_memory": 500
|
|
||||||
}
|
|
||||||
, [
|
|
||||||
{
|
|
||||||
"mnemonic": "ldi"
|
|
||||||
, "args": ["register", "direct_input"]
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"mnemonic": "ld"
|
|
||||||
, "args": ["register", "register"]
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"mnemonic": "st"
|
|
||||||
, "args": ["register", "register"]
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"mnemonic": "inc"
|
|
||||||
, "args": ["register"]
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"mnemonic": "dec"
|
|
||||||
, "args": ["register"]
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"mnemonic": "add"
|
|
||||||
, "args": ["register", "register"]
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"mnemonic": "sub"
|
|
||||||
, "args": ["register", "register"]
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"mnemonic": "mul"
|
|
||||||
, "args": ["register", "register"]
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"mnemonic": "div"
|
|
||||||
, "args": ["register", "register"]
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"mnemonic": "gt"
|
|
||||||
, "args": ["register"]
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"mnemonic": "ge"
|
|
||||||
, "args": ["register"]
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"mnemonic": "lt"
|
|
||||||
, "args": ["register"]
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"mnemonic": "le"
|
|
||||||
, "args": ["register"]
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"mnemonic": "eq"
|
|
||||||
, "args": ["register"]
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"mnemonic": "not"
|
|
||||||
, "args": []
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"mnemonic": "jmp"
|
|
||||||
, "args": ["register"]
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"mnemonic": "call"
|
|
||||||
, "args": ["register"]
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"mnemonic": "ret"
|
|
||||||
, "args": []
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"mnemonic": "stop"
|
|
||||||
, "args": []
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"mnemonic": "cl"
|
|
||||||
, "args": []
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"mnemonic": "cjmp"
|
|
||||||
, "args": ["register"]
|
|
||||||
}
|
|
||||||
, {
|
|
||||||
"mnemonic": "ccall"
|
|
||||||
, "args": ["register"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
)
|
|
|
@ -1,24 +0,0 @@
|
||||||
from io import StringIO
|
|
||||||
from assembler.context import FileContext
|
|
||||||
|
|
||||||
|
|
||||||
def test_getc_ungetc():
|
|
||||||
data = StringIO("abc\ndefg")
|
|
||||||
context = FileContext(data)
|
|
||||||
|
|
||||||
assert context.getc() == "a"
|
|
||||||
assert context.getc() == "b"
|
|
||||||
assert context._line == 0
|
|
||||||
assert context._column == 2
|
|
||||||
assert context.getc() == "c"
|
|
||||||
assert context.getc() == "\n"
|
|
||||||
assert context.getc() == "d"
|
|
||||||
assert context._line == 1
|
|
||||||
assert context._column == 1
|
|
||||||
|
|
||||||
context.ungetc("d")
|
|
||||||
context.ungetc("\n")
|
|
||||||
|
|
||||||
assert context._column == 3
|
|
||||||
assert context._line == 0
|
|
||||||
assert context.getc() == "\n"
|
|
|
@ -1,71 +0,0 @@
|
||||||
from io import StringIO
|
|
||||||
from assembler.tokenize import Tokenizer
|
|
||||||
from assembler.context import FileContext
|
|
||||||
|
|
||||||
def test_tokenize_1():
|
|
||||||
data = '''
|
|
||||||
ldi r0, 0xfefe
|
|
||||||
ldi r1, 0xefef
|
|
||||||
add r0, r1
|
|
||||||
'''
|
|
||||||
data = StringIO(data)
|
|
||||||
tokenizer = Tokenizer(FileContext(data))
|
|
||||||
|
|
||||||
result = list(tokenizer)
|
|
||||||
|
|
||||||
assert result == [
|
|
||||||
"ldi", " ", "r0", ",", "0xfefe", "\n"
|
|
||||||
, "ldi", " ", "r1", ",", "0xefef", "\n"
|
|
||||||
, "add", " ", "r0", ",", "r1", "\n"
|
|
||||||
]
|
|
||||||
|
|
||||||
def test_tokenize_2():
|
|
||||||
data = '''
|
|
||||||
; This is a comment
|
|
||||||
|
|
||||||
ldi r0, 0xfefe
|
|
||||||
'''
|
|
||||||
data = StringIO(data)
|
|
||||||
tokenizer = Tokenizer(FileContext(data))
|
|
||||||
|
|
||||||
result = list(tokenizer)
|
|
||||||
|
|
||||||
assert result == [
|
|
||||||
";", "This", " ", "is", " ", "a", " ", "comment", "\n"
|
|
||||||
, "ldi", " ", "r0", ",", "0xfefe", "\n"
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def test_tokenize_3():
|
|
||||||
data = '''
|
|
||||||
ldi r0, 0xfefe
|
|
||||||
string:
|
|
||||||
.set ['h', 'e', 'l', 'l', 'o']
|
|
||||||
'''
|
|
||||||
data = StringIO(data)
|
|
||||||
tokenizer = Tokenizer(FileContext(data))
|
|
||||||
|
|
||||||
result = list(tokenizer)
|
|
||||||
|
|
||||||
assert result == [
|
|
||||||
"ldi", " ", "r0", ",", "0xfefe", "\n"
|
|
||||||
, "string", ":", "\n"
|
|
||||||
, ".", "set", " ", "[", "'h'", ",", "'e'", ",", "'l'", ",", "'l'", ",", "'o'", "]", "\n"
|
|
||||||
]
|
|
||||||
|
|
||||||
def test_tokenize_4():
|
|
||||||
data = '''
|
|
||||||
ldi r0, 0xfefe
|
|
||||||
test_mark:
|
|
||||||
ldi r1, 0xefef
|
|
||||||
'''
|
|
||||||
data = StringIO(data)
|
|
||||||
tokenizer = Tokenizer(FileContext(data))
|
|
||||||
|
|
||||||
result = list(tokenizer)
|
|
||||||
|
|
||||||
assert result == [
|
|
||||||
"ldi", " ", "r0", ",", "0xfefe", "\n"
|
|
||||||
, "test_mark", ":", "\n"
|
|
||||||
, "ldi", " ", "r1", ",", "0xefef", "\n"
|
|
||||||
]
|
|
|
@ -1,14 +0,0 @@
|
||||||
from assembler.opcodes import make_opcodes
|
|
||||||
|
|
||||||
|
|
||||||
def test_make_opcodes():
|
|
||||||
mnemonics = ["ldi", "ld", "st", "add", "mul"]
|
|
||||||
|
|
||||||
opcodes = make_opcodes(mnemonics)
|
|
||||||
|
|
||||||
assert opcodes == {"ldi": 32704
|
|
||||||
, "ld" : 16320
|
|
||||||
, "st": 49088
|
|
||||||
, "add": 8128
|
|
||||||
, "mul": 24512
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
from assembler.util import can_be_mark, can_convert_to_int, autoint, int16_2_bytes
|
|
||||||
|
|
||||||
|
|
||||||
def test_can_be_mark():
|
|
||||||
assert can_be_mark("this_is_a_mark") == True
|
|
||||||
assert can_be_mark("this_is_a_mark0") == True
|
|
||||||
assert can_be_mark("tHIS0") == True
|
|
||||||
|
|
||||||
assert can_be_mark("This_is_not_a_mark") == False
|
|
||||||
assert can_be_mark("0this_is_no_mark") == False
|
|
||||||
assert can_be_mark("this#is_no_mark") == False
|
|
||||||
|
|
||||||
def test_can_convert_to_int():
|
|
||||||
assert can_convert_to_int("0xfe") == True
|
|
||||||
assert can_convert_to_int("0xFE") == True
|
|
||||||
assert can_convert_to_int("10") == True
|
|
||||||
assert can_convert_to_int("0b100") == True
|
|
||||||
assert can_convert_to_int("'a'") == True
|
|
||||||
assert can_convert_to_int("'\\n'") == True
|
|
||||||
|
|
||||||
|
|
||||||
assert can_convert_to_int("0xfg") == False
|
|
||||||
assert can_convert_to_int("0xFG") == False
|
|
||||||
assert can_convert_to_int("10a") == False
|
|
||||||
assert can_convert_to_int("0b20") == False
|
|
||||||
assert can_convert_to_int("'aa'") == False
|
|
||||||
assert can_convert_to_int("'\\z'") == False
|
|
||||||
|
|
||||||
def test_autoint():
|
|
||||||
assert autoint("0xfe") == 0xfe
|
|
||||||
assert autoint("0xFE") == 0xfe
|
|
||||||
assert autoint("10") == 10
|
|
||||||
assert autoint("0b1010101") == 0b1010101
|
|
||||||
assert autoint("'a'") == ord("a")
|
|
||||||
assert autoint("'\\n'") == ord("\n")
|
|
||||||
|
|
||||||
def test_int16_2_bytes():
|
|
||||||
assert int16_2_bytes(2) == b"\x02\00"
|
|
||||||
assert int16_2_bytes(0x0200) == b"\x00\x02"
|
|
||||||
assert int16_2_bytes(-1) == b"\xff\xff"
|
|
|
@ -1,68 +0,0 @@
|
||||||
from io import StringIO
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from assembler.assembler import Assembler
|
|
||||||
|
|
||||||
|
|
||||||
def test_commands(basic_machine_definition):
|
|
||||||
memory_definition, command_defintion = basic_machine_definition
|
|
||||||
|
|
||||||
data = StringIO(
|
|
||||||
'''
|
|
||||||
ldi r0, 0xfe
|
|
||||||
ldi r1, 0xfe
|
|
||||||
add r0, r1
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
assembler = Assembler(data, memory_definition, command_defintion, {})
|
|
||||||
assembler.parse()
|
|
||||||
|
|
||||||
assert assembler._code_objects == [32704 | 0, 0xfe
|
|
||||||
, 32704 | 1, 0xfe
|
|
||||||
, 40896 | 0, 1]
|
|
||||||
|
|
||||||
def test_mark(basic_machine_definition):
|
|
||||||
memory_definition, command_defintion = basic_machine_definition
|
|
||||||
|
|
||||||
data = StringIO(
|
|
||||||
'''
|
|
||||||
ldi r0, test_mark
|
|
||||||
ldi r1, 0xfe
|
|
||||||
test_mark:
|
|
||||||
add r0, r1
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
assembler = Assembler(data, memory_definition, command_defintion, {})
|
|
||||||
assembler.parse()
|
|
||||||
|
|
||||||
|
|
||||||
assert assembler._code_objects == [32704 | 0, 4
|
|
||||||
, 32704 | 1, 0xfe
|
|
||||||
, 40896 | 0, 1]
|
|
||||||
|
|
||||||
|
|
||||||
def test_set_directive(basic_machine_definition):
|
|
||||||
memory_definition, command_defintion = basic_machine_definition
|
|
||||||
|
|
||||||
data = StringIO(
|
|
||||||
'''
|
|
||||||
ldi r0, test_mark
|
|
||||||
ldi r1, 0xfe
|
|
||||||
test_mark:
|
|
||||||
.set [0xfe, 0xef,
|
|
||||||
10, 20,
|
|
||||||
'a', 'b',
|
|
||||||
'\\n', 0b10]
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
assembler = Assembler(data, memory_definition, command_defintion, {})
|
|
||||||
assembler.parse()
|
|
||||||
|
|
||||||
|
|
||||||
assert assembler._code_objects == [32704 | 0, 4
|
|
||||||
, 32704 | 1, 0xfe
|
|
||||||
, 0xfe, 0xef
|
|
||||||
, 10, 20
|
|
||||||
, ord("a"), ord("b")
|
|
||||||
, ord("\n"), 0b10]
|
|
||||||
|
|
|
@ -1,210 +0,0 @@
|
||||||
from io import StringIO
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from assembler.assembler import Assembler, ParsingError
|
|
||||||
|
|
||||||
def test_missing_comma(basic_machine_definition):
|
|
||||||
memory_definition, command_defintion = basic_machine_definition
|
|
||||||
|
|
||||||
data = StringIO(
|
|
||||||
'''
|
|
||||||
ldi r0 0xfe
|
|
||||||
ldi r1, 0xfe
|
|
||||||
add r0, r1
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
assembler = Assembler(data, memory_definition, command_defintion, {})
|
|
||||||
|
|
||||||
with pytest.raises(ParsingError):
|
|
||||||
assembler.parse()
|
|
||||||
|
|
||||||
def test_missing_newline(basic_machine_definition):
|
|
||||||
memory_definition, command_defintion = basic_machine_definition
|
|
||||||
|
|
||||||
data = StringIO(
|
|
||||||
'''
|
|
||||||
ldi r0, 0xfe ldi r1, 0xfe
|
|
||||||
add r0, r1
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
assembler = Assembler(data, memory_definition, command_defintion, {})
|
|
||||||
|
|
||||||
with pytest.raises(ParsingError):
|
|
||||||
assembler.parse()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_additional_comma1(basic_machine_definition):
|
|
||||||
memory_definition, command_defintion = basic_machine_definition
|
|
||||||
|
|
||||||
data = StringIO(
|
|
||||||
'''
|
|
||||||
ldi, r0, 0xfe
|
|
||||||
ldi r1, 0xfe
|
|
||||||
add r0, r1
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
assembler = Assembler(data, memory_definition, command_defintion, {})
|
|
||||||
|
|
||||||
with pytest.raises(ParsingError):
|
|
||||||
assembler.parse()
|
|
||||||
|
|
||||||
def test_additional_comma2(basic_machine_definition):
|
|
||||||
memory_definition, command_defintion = basic_machine_definition
|
|
||||||
|
|
||||||
data = StringIO(
|
|
||||||
'''
|
|
||||||
ldi r0, 0xfe,
|
|
||||||
ldi r1, 0xfe
|
|
||||||
add r0, r1
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
assembler = Assembler(data, memory_definition, command_defintion, {})
|
|
||||||
|
|
||||||
with pytest.raises(ParsingError):
|
|
||||||
assembler.parse()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_bad_mark1(basic_machine_definition):
|
|
||||||
memory_definition, command_defintion = basic_machine_definition
|
|
||||||
|
|
||||||
data = StringIO(
|
|
||||||
'''
|
|
||||||
ldi r0, 0xfe
|
|
||||||
this_is_a_bad_mark
|
|
||||||
ldi r1, 0xfe
|
|
||||||
add r0, r1
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
assembler = Assembler(data, memory_definition, command_defintion, {})
|
|
||||||
|
|
||||||
with pytest.raises(ParsingError):
|
|
||||||
assembler.parse()
|
|
||||||
|
|
||||||
def test_bad_mark2(basic_machine_definition):
|
|
||||||
memory_definition, command_defintion = basic_machine_definition
|
|
||||||
|
|
||||||
data = StringIO(
|
|
||||||
'''
|
|
||||||
ldi r0, 0xfe
|
|
||||||
This_is_a_bad_mark:
|
|
||||||
ldi r1, 0xfe
|
|
||||||
add r0, r1
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
assembler = Assembler(data, memory_definition, command_defintion, {})
|
|
||||||
|
|
||||||
with pytest.raises(ParsingError):
|
|
||||||
assembler.parse()
|
|
||||||
|
|
||||||
def test_bad_mark3(basic_machine_definition):
|
|
||||||
memory_definition, command_defintion = basic_machine_definition
|
|
||||||
|
|
||||||
data = StringIO(
|
|
||||||
'''
|
|
||||||
ldi r0, 0xfe
|
|
||||||
0this_is_a_bad_mark:
|
|
||||||
ldi r1, 0xfe
|
|
||||||
add r0, r1
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
assembler = Assembler(data, memory_definition, command_defintion, {})
|
|
||||||
|
|
||||||
with pytest.raises(ParsingError):
|
|
||||||
assembler.parse()
|
|
||||||
|
|
||||||
def test_bad_mark4(basic_machine_definition):
|
|
||||||
memory_definition, command_defintion = basic_machine_definition
|
|
||||||
|
|
||||||
data = StringIO(
|
|
||||||
'''
|
|
||||||
ldi r0, this_is_a_missing_mark
|
|
||||||
ldi r1, 0xfe
|
|
||||||
add r0, r1
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
assembler = Assembler(data, memory_definition, command_defintion, {})
|
|
||||||
|
|
||||||
with pytest.raises(ParsingError):
|
|
||||||
assembler.parse()
|
|
||||||
|
|
||||||
def test_bad_mark5(basic_machine_definition):
|
|
||||||
memory_definition, command_defintion = basic_machine_definition
|
|
||||||
|
|
||||||
data = StringIO(
|
|
||||||
'''
|
|
||||||
ldi r0, this_is_a_missing_mark:
|
|
||||||
ldi r1, 0xfe
|
|
||||||
add r0, r1
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
assembler = Assembler(data, memory_definition, command_defintion, {})
|
|
||||||
|
|
||||||
with pytest.raises(ParsingError):
|
|
||||||
assembler.parse()
|
|
||||||
|
|
||||||
def test_bad_directive1(basic_machine_definition):
|
|
||||||
memory_definition, command_defintion = basic_machine_definition
|
|
||||||
|
|
||||||
data = StringIO(
|
|
||||||
'''
|
|
||||||
ldi r0, 0
|
|
||||||
ldi r1, 0xfe
|
|
||||||
add r0, r1
|
|
||||||
.set data [0x00, 0x10]
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
assembler = Assembler(data, memory_definition, command_defintion, {})
|
|
||||||
|
|
||||||
with pytest.raises(ParsingError):
|
|
||||||
assembler.parse()
|
|
||||||
|
|
||||||
def test_bad_directive2(basic_machine_definition):
|
|
||||||
memory_definition, command_defintion = basic_machine_definition
|
|
||||||
|
|
||||||
data = StringIO(
|
|
||||||
'''
|
|
||||||
ldi r0, 0
|
|
||||||
ldi r1, 0xfe
|
|
||||||
add r0, r1
|
|
||||||
.set[0x00, 0x10]
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
assembler = Assembler(data, memory_definition, command_defintion, {})
|
|
||||||
|
|
||||||
with pytest.raises(ParsingError):
|
|
||||||
assembler.parse()
|
|
||||||
|
|
||||||
def test_bad_directive3(basic_machine_definition):
|
|
||||||
memory_definition, command_defintion = basic_machine_definition
|
|
||||||
|
|
||||||
data = StringIO(
|
|
||||||
'''
|
|
||||||
ldi r0, 0
|
|
||||||
ldi r1, 0xfe
|
|
||||||
add r0, r1
|
|
||||||
.set [0x00, 0x10,]
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
assembler = Assembler(data, memory_definition, command_defintion, {})
|
|
||||||
|
|
||||||
with pytest.raises(ParsingError):
|
|
||||||
assembler.parse()
|
|
||||||
|
|
||||||
def test_bad_directive4(basic_machine_definition):
|
|
||||||
memory_definition, command_defintion = basic_machine_definition
|
|
||||||
|
|
||||||
data = StringIO(
|
|
||||||
'''
|
|
||||||
ldi r0, 0
|
|
||||||
ldi r1, 0xfe
|
|
||||||
add r0, r1
|
|
||||||
.set [0x00, 0x10
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
assembler = Assembler(data, memory_definition, command_defintion, {})
|
|
||||||
|
|
||||||
with pytest.raises(ParsingError):
|
|
||||||
assembler.parse()
|
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
CC=gcc
|
|
||||||
objects= stack.o method_dispatcher/method_dispatcher.o interpreter/core_methods.o interpreter/interpreter.o
|
|
||||||
|
|
||||||
all: $(objects) test
|
|
||||||
|
|
||||||
CFLAG= -c -O -o
|
|
||||||
|
|
||||||
%.o: %.c
|
|
||||||
$(CC) $(CFLAG) $@ $<
|
|
||||||
|
|
||||||
.PHONY: test
|
|
||||||
|
|
||||||
test:
|
|
||||||
cd test && make
|
|
||||||
cd method_dispatcher/test && make
|
|
||||||
cd interpreter/test && make
|
|
||||||
|
|
||||||
clean:
|
|
||||||
- rm $(objects)
|
|
|
@ -1,20 +0,0 @@
|
||||||
#ifndef bci_base_h__
|
|
||||||
#define bci_base_h__
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include "stack.h"
|
|
||||||
|
|
||||||
#define BCI_CORE_NUM_REG 40
|
|
||||||
|
|
||||||
// Note that void * state will later be casted to
|
|
||||||
// machine_state_t.
|
|
||||||
typedef char (* bci_core_method_t)(uint8_t small_arg
|
|
||||||
, void * state);
|
|
||||||
|
|
||||||
|
|
||||||
#define BCI_CORE_RESULT_RESERVED_BITS 0b11000000
|
|
||||||
#define BCI_CORE_RESULT_APPLICATION_BITS 0b00111111
|
|
||||||
|
|
||||||
#define BCI_CORE_SMALL_ARG_MASK 0b0000000000111111
|
|
||||||
#define BCI_CORE_OPCODE_MASK 0b1111111111000000
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,370 +0,0 @@
|
||||||
#include "core_methods.h"
|
|
||||||
|
|
||||||
#define BCI_CORE_REGISTER_CHECK(var) if(var > BCI_CORE_NUM_REG) return 1
|
|
||||||
|
|
||||||
// #1 -> $0
|
|
||||||
char bci_cm_ldi(uint8_t small_arg, machine_state_t state)
|
|
||||||
{
|
|
||||||
BCI_CORE_REGISTER_CHECK(small_arg);
|
|
||||||
|
|
||||||
uint16_t arg;
|
|
||||||
char res;
|
|
||||||
res = machine_state_t_get_word(state, state->program_counter + 1, &arg);
|
|
||||||
if(res)
|
|
||||||
{
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
state->data_reg[small_arg] = arg;
|
|
||||||
|
|
||||||
return machine_state_t_default_afterexec(state, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// @($1) -> $0
|
|
||||||
char bci_cm_ld(uint8_t small_arg, machine_state_t state)
|
|
||||||
{
|
|
||||||
BCI_CORE_REGISTER_CHECK(small_arg);
|
|
||||||
|
|
||||||
uint16_t arg;
|
|
||||||
char res;
|
|
||||||
res = machine_state_t_get_word(state, state->program_counter + 1, &arg);
|
|
||||||
if(res)
|
|
||||||
{
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
BCI_CORE_REGISTER_CHECK(arg);
|
|
||||||
arg = state->data_reg[arg];
|
|
||||||
|
|
||||||
res = machine_state_t_get_mem(state, arg, &arg);
|
|
||||||
if(res)
|
|
||||||
{
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
state->data_reg[small_arg] = arg;
|
|
||||||
|
|
||||||
return machine_state_t_default_afterexec(state, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// $0 -> @($1)
|
|
||||||
char bci_cm_st(uint8_t small_arg, machine_state_t state)
|
|
||||||
{
|
|
||||||
BCI_CORE_REGISTER_CHECK(small_arg);
|
|
||||||
char res;
|
|
||||||
|
|
||||||
uint16_t arg;
|
|
||||||
res = machine_state_t_get_word(state, state->program_counter + 1, &arg);
|
|
||||||
if(res)
|
|
||||||
{
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
BCI_CORE_REGISTER_CHECK(arg);
|
|
||||||
arg = state->data_reg[arg];
|
|
||||||
|
|
||||||
res = machine_state_t_set_mem(state, arg, state->data_reg[small_arg]);
|
|
||||||
if(res)
|
|
||||||
{
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
return machine_state_t_default_afterexec(state, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// $0 + 1 -> $0
|
|
||||||
char bci_cm_inc(uint8_t small_arg, machine_state_t state)
|
|
||||||
{
|
|
||||||
int32_t result;
|
|
||||||
BCI_CORE_REGISTER_CHECK(small_arg);
|
|
||||||
result = state->data_reg[small_arg] + 1;
|
|
||||||
state->data_reg[small_arg] = result & 0xffff;
|
|
||||||
state->status_reg = result >> 16;
|
|
||||||
return machine_state_t_default_afterexec(state, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// $0 - 1 -> $0
|
|
||||||
char bci_cm_dec(uint8_t small_arg, machine_state_t state)
|
|
||||||
{
|
|
||||||
BCI_CORE_REGISTER_CHECK(small_arg);
|
|
||||||
int32_t result = state->data_reg[small_arg] - 1;
|
|
||||||
state->data_reg[small_arg] = result & 0xffff;
|
|
||||||
state->status_reg = result >> 16;
|
|
||||||
return machine_state_t_default_afterexec(state, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// $0 + $1 -> $0
|
|
||||||
char bci_cm_add(uint8_t small_arg, machine_state_t state)
|
|
||||||
{
|
|
||||||
BCI_CORE_REGISTER_CHECK(small_arg);
|
|
||||||
uint16_t arg;
|
|
||||||
char res;
|
|
||||||
res = machine_state_t_get_word(state, state->program_counter + 1, &arg);
|
|
||||||
if(res)
|
|
||||||
{
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
BCI_CORE_REGISTER_CHECK(arg);
|
|
||||||
int32_t result = state->data_reg[small_arg] + state->data_reg[arg];
|
|
||||||
state->data_reg[small_arg] = result & 0xffff;
|
|
||||||
state->status_reg = result >> 16;
|
|
||||||
|
|
||||||
return machine_state_t_default_afterexec(state, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// $0 - $1 -> $0
|
|
||||||
char bci_cm_sub(uint8_t small_arg, machine_state_t state)
|
|
||||||
{
|
|
||||||
BCI_CORE_REGISTER_CHECK(small_arg);
|
|
||||||
uint16_t arg;
|
|
||||||
char res;
|
|
||||||
res = machine_state_t_get_word(state, state->program_counter + 1, &arg);
|
|
||||||
if(res)
|
|
||||||
{
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
BCI_CORE_REGISTER_CHECK(arg);
|
|
||||||
int32_t result = state->data_reg[small_arg] - state->data_reg[arg];
|
|
||||||
|
|
||||||
state->data_reg[small_arg] = result & 0xffff;
|
|
||||||
state->status_reg = result >> 16;
|
|
||||||
|
|
||||||
return machine_state_t_default_afterexec(state, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// $0 * $1 -> $0
|
|
||||||
char bci_cm_mul(uint8_t small_arg, machine_state_t state)
|
|
||||||
{
|
|
||||||
BCI_CORE_REGISTER_CHECK(small_arg);
|
|
||||||
uint16_t arg;
|
|
||||||
char res;
|
|
||||||
res = machine_state_t_get_word(state, state->program_counter + 1, &arg);
|
|
||||||
if(res)
|
|
||||||
{
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
BCI_CORE_REGISTER_CHECK(arg);
|
|
||||||
int32_t result = state->data_reg[small_arg] * state->data_reg[arg];
|
|
||||||
state->data_reg[small_arg] = result & 0xffff;
|
|
||||||
state->status_reg = result >> 16;
|
|
||||||
return machine_state_t_default_afterexec(state, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// $0 / $1 -> $0
|
|
||||||
char bci_cm_div(uint8_t small_arg, machine_state_t state)
|
|
||||||
{
|
|
||||||
BCI_CORE_REGISTER_CHECK(small_arg);
|
|
||||||
uint16_t arg;
|
|
||||||
char res;
|
|
||||||
res = machine_state_t_get_word(state, state->program_counter + 1, &arg);
|
|
||||||
if(res)
|
|
||||||
{
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
BCI_CORE_REGISTER_CHECK(arg);
|
|
||||||
int32_t result = state->data_reg[small_arg] / state->data_reg[arg];
|
|
||||||
state->data_reg[small_arg] = result & 0xffff;
|
|
||||||
state->status_reg = result >> 16;
|
|
||||||
return machine_state_t_default_afterexec(state, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// if($0 > 0): 1 -> $st_reg
|
|
||||||
// else: 0 -> $st_reg
|
|
||||||
char bci_cm_gt(uint8_t small_arg, machine_state_t state)
|
|
||||||
{
|
|
||||||
BCI_CORE_REGISTER_CHECK(small_arg);
|
|
||||||
|
|
||||||
if(state->data_reg[small_arg] > 0)
|
|
||||||
{
|
|
||||||
state->status_reg = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
state->status_reg = 0;
|
|
||||||
}
|
|
||||||
return machine_state_t_default_afterexec(state, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if($0 >= 0): 1 -> $st_reg
|
|
||||||
// else: 0 -> $st_reg
|
|
||||||
char bci_cm_ge(uint8_t small_arg, machine_state_t state)
|
|
||||||
{
|
|
||||||
BCI_CORE_REGISTER_CHECK(small_arg);
|
|
||||||
|
|
||||||
if(state->data_reg[small_arg] >= 0)
|
|
||||||
{
|
|
||||||
state->status_reg = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
state->status_reg = 0;
|
|
||||||
}
|
|
||||||
return machine_state_t_default_afterexec(state, 0);
|
|
||||||
}
|
|
||||||
// if($0 < 0): 1 -> $st_reg
|
|
||||||
// else: 0 -> $st_reg
|
|
||||||
char bci_cm_lt(uint8_t small_arg, machine_state_t state)
|
|
||||||
{
|
|
||||||
BCI_CORE_REGISTER_CHECK(small_arg);
|
|
||||||
|
|
||||||
if(state->data_reg[small_arg] < 0)
|
|
||||||
{
|
|
||||||
state->status_reg = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
state->status_reg = 0;
|
|
||||||
}
|
|
||||||
return machine_state_t_default_afterexec(state, 0);
|
|
||||||
}
|
|
||||||
// if($0 <= 0): 1 -> $st_reg
|
|
||||||
// else: 0 -> $st_reg
|
|
||||||
char bci_cm_le(uint8_t small_arg, machine_state_t state)
|
|
||||||
{
|
|
||||||
BCI_CORE_REGISTER_CHECK(small_arg);
|
|
||||||
|
|
||||||
if(state->data_reg[small_arg] <= 0)
|
|
||||||
{
|
|
||||||
state->status_reg = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
state->status_reg = 0;
|
|
||||||
}
|
|
||||||
return machine_state_t_default_afterexec(state, 0);
|
|
||||||
}
|
|
||||||
// if($0 == 0): 1 -> $st_reg
|
|
||||||
// else: 0 -> $st_reg
|
|
||||||
char bci_cm_eq(uint8_t small_arg, machine_state_t state)
|
|
||||||
{
|
|
||||||
BCI_CORE_REGISTER_CHECK(small_arg);
|
|
||||||
|
|
||||||
if(state->data_reg[small_arg] == 0)
|
|
||||||
{
|
|
||||||
state->status_reg = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
state->status_reg = 0;
|
|
||||||
}
|
|
||||||
return machine_state_t_default_afterexec(state, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// $0 -> $pc; 0 -> $st_reg
|
|
||||||
char bci_cm_jmp(uint8_t small_arg, machine_state_t state)
|
|
||||||
{
|
|
||||||
BCI_CORE_REGISTER_CHECK(small_arg);
|
|
||||||
uint16_t arg = state->data_reg[arg];
|
|
||||||
|
|
||||||
state->status_reg = 0;
|
|
||||||
state->program_counter = arg;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if($st_reg): $0 -> $pc; 0 -> $st_reg
|
|
||||||
// else: do nothing
|
|
||||||
char bci_cm_cjmp(uint8_t small_arg, machine_state_t state)
|
|
||||||
{
|
|
||||||
uint16_t arg = small_arg;
|
|
||||||
BCI_CORE_REGISTER_CHECK(small_arg);
|
|
||||||
#ifdef DEBUG
|
|
||||||
printf("MSG: cjmp: arg=0x%x (=0x%x)\n", arg, state->data_reg[arg]);
|
|
||||||
#endif
|
|
||||||
arg = state->data_reg[arg];
|
|
||||||
|
|
||||||
if(state->status_reg)
|
|
||||||
{
|
|
||||||
state->program_counter = arg;
|
|
||||||
state->status_reg = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return machine_state_t_default_afterexec(state, 0);
|
|
||||||
}
|
|
||||||
// $pc -> @stack
|
|
||||||
// $0 -> $pc
|
|
||||||
char bci_cm_call(uint8_t small_arg, machine_state_t state)
|
|
||||||
{
|
|
||||||
uint16_t arg;
|
|
||||||
BCI_CORE_REGISTER_CHECK(small_arg);
|
|
||||||
arg = state->data_reg[arg];
|
|
||||||
|
|
||||||
char res = bci_stack_t_push(&(state->stack), state->program_counter);
|
|
||||||
if(res)
|
|
||||||
{
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
state->program_counter = arg;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
// if($st_reg): $pc -> @stack; $0 -> $pc; 0 -> $st_reg
|
|
||||||
// else: do nothing
|
|
||||||
char bci_cm_ccall(uint8_t small_arg, machine_state_t state)
|
|
||||||
{
|
|
||||||
uint16_t arg;
|
|
||||||
char res;
|
|
||||||
BCI_CORE_REGISTER_CHECK(small_arg);
|
|
||||||
arg = state->data_reg[small_arg];
|
|
||||||
|
|
||||||
if(state->status_reg)
|
|
||||||
{
|
|
||||||
state->program_counter = arg;
|
|
||||||
res = bci_stack_t_push(&(state->stack), state->program_counter);
|
|
||||||
if(res)
|
|
||||||
{
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
state->status_reg = 0;
|
|
||||||
return machine_state_t_default_afterexec(state, 0);
|
|
||||||
}
|
|
||||||
// @stack -> $pc
|
|
||||||
char bci_cm_ret(uint8_t small_arg, machine_state_t state)
|
|
||||||
{
|
|
||||||
uint16_t result;
|
|
||||||
char res = bci_stack_t_pop(&(state->stack), &result);
|
|
||||||
if(res)
|
|
||||||
{
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
state->program_counter = result;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0 -> $st_reg
|
|
||||||
char bci_cm_cl(uint8_t small_arg, machine_state_t state)
|
|
||||||
{
|
|
||||||
state->status_reg = 0;
|
|
||||||
return machine_state_t_default_afterexec(state, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1 -> $su_reg
|
|
||||||
char bci_cm_stop(uint8_t small_arg, machine_state_t state)
|
|
||||||
{
|
|
||||||
state->shutdown_reg = 1;
|
|
||||||
return machine_state_t_default_afterexec(state, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if($st_reg): 0 -> $st_reg
|
|
||||||
// else: 1 -> $st_reg
|
|
||||||
char bci_cm_not(uint8_t small_arg, machine_state_t state)
|
|
||||||
{
|
|
||||||
if(state->status_reg)
|
|
||||||
{
|
|
||||||
state->status_reg = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
state->status_reg = 1;
|
|
||||||
}
|
|
||||||
return machine_state_t_default_afterexec(state, 0);
|
|
||||||
}
|
|
|
@ -1,114 +0,0 @@
|
||||||
#ifndef bci_core_methods_h__
|
|
||||||
#define bci_core_methods_h__
|
|
||||||
#include "interpreter.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This library brings a set of essential core methods.
|
|
||||||
* */
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Naming conventions:
|
|
||||||
*
|
|
||||||
* x = 0, 1, 2, 3...: arguments.
|
|
||||||
* 0: small_arg (6 bit)
|
|
||||||
* 1, 2, ...: 16 bit optional arguments
|
|
||||||
*
|
|
||||||
* $x: value of data register x
|
|
||||||
* @x: value of memory word x
|
|
||||||
* #x: value of argument x
|
|
||||||
* 0, 1, 2, ...: integer 0, 1, 2, ...
|
|
||||||
*
|
|
||||||
* -> write result in register/word on the right
|
|
||||||
*
|
|
||||||
* st_reg: status register
|
|
||||||
* su_reg: shutdown register
|
|
||||||
* pc: program counter
|
|
||||||
*
|
|
||||||
* stack: the builtin stack
|
|
||||||
* */
|
|
||||||
|
|
||||||
// #1 -> $0
|
|
||||||
char bci_cm_ldi(uint8_t small_arg, machine_state_t state);
|
|
||||||
|
|
||||||
// @($1) -> $0
|
|
||||||
char bci_cm_ld(uint8_t small_arg, machine_state_t state);
|
|
||||||
|
|
||||||
// $0 -> @($1)
|
|
||||||
char bci_cm_st(uint8_t small_arg, machine_state_t state);
|
|
||||||
|
|
||||||
|
|
||||||
// NOTES on inc, dec, add, sub, mul, div:
|
|
||||||
//
|
|
||||||
// These methods will store the overflow-word in $st_reg.
|
|
||||||
|
|
||||||
|
|
||||||
// $0 + 1 -> $0
|
|
||||||
char bci_cm_inc(uint8_t small_arg, machine_state_t state);
|
|
||||||
|
|
||||||
// $0 - 1 -> $0
|
|
||||||
char bci_cm_dec(uint8_t small_arg, machine_state_t state);
|
|
||||||
|
|
||||||
// $0 + $1 -> $0
|
|
||||||
char bci_cm_add(uint8_t small_arg, machine_state_t state);
|
|
||||||
|
|
||||||
// $0 - $1 -> $0
|
|
||||||
char bci_cm_sub(uint8_t small_arg, machine_state_t state);
|
|
||||||
|
|
||||||
// $0 * $1 -> $0
|
|
||||||
char bci_cm_mul(uint8_t small_arg, machine_state_t state);
|
|
||||||
|
|
||||||
// $0 / $1 -> $0
|
|
||||||
char bci_cm_div(uint8_t small_arg, machine_state_t state);
|
|
||||||
|
|
||||||
// if($0 > 0): 1 -> $st_reg
|
|
||||||
// else: 0 -> $st_reg
|
|
||||||
char bci_cm_gt(uint8_t small_arg, machine_state_t state);
|
|
||||||
|
|
||||||
// if($0 >= 0): 1 -> $st_reg
|
|
||||||
// else: 0 -> $st_reg
|
|
||||||
char bci_cm_ge(uint8_t small_arg, machine_state_t state);
|
|
||||||
|
|
||||||
// if($0 < 0): 1 -> $st_reg
|
|
||||||
// else: 0 -> $st_reg
|
|
||||||
char bci_cm_lt(uint8_t small_arg, machine_state_t state);
|
|
||||||
|
|
||||||
// if($0 <= 0): 1 -> $st_reg
|
|
||||||
// else: 0 -> $st_reg
|
|
||||||
char bci_cm_le(uint8_t small_arg, machine_state_t state);
|
|
||||||
|
|
||||||
// if($0 == 0): 1 -> $st_reg
|
|
||||||
// else: 0 -> $st_reg
|
|
||||||
char bci_cm_eq(uint8_t small_arg, machine_state_t state);
|
|
||||||
|
|
||||||
// if($st_reg): 0 -> $st_reg
|
|
||||||
// else: 1 -> $st_reg
|
|
||||||
char bci_cm_not(uint8_t small_arg, machine_state_t state);
|
|
||||||
|
|
||||||
// $1 -> $pc
|
|
||||||
char bci_cm_jmp(uint8_t small_arg, machine_state_t state);
|
|
||||||
|
|
||||||
// if($st_reg): $1 -> $pc
|
|
||||||
// else: do nothing
|
|
||||||
char bci_cm_cjmp(uint8_t small_arg, machine_state_t state);
|
|
||||||
|
|
||||||
// $pc -> @stack
|
|
||||||
// $0 -> $pc
|
|
||||||
char bci_cm_call(uint8_t small_arg, machine_state_t state);
|
|
||||||
|
|
||||||
// if($st_reg): $pc -> @stack; $0 -> $pc
|
|
||||||
// else: do nothing
|
|
||||||
char bci_cm_ccall(uint8_t small_arg, machine_state_t state);
|
|
||||||
|
|
||||||
// @stack -> $pc
|
|
||||||
char bci_cm_ret(uint8_t small_arg, machine_state_t state);
|
|
||||||
|
|
||||||
// 0 -> $st_reg
|
|
||||||
char bci_cm_cl(uint8_t small_arg, machine_state_t state);
|
|
||||||
|
|
||||||
// 1 -> $su_reg
|
|
||||||
char bci_cm_stop(uint8_t small_arg, machine_state_t state);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,217 +0,0 @@
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "interpreter.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
machine_state_t machine_state_t_new( void * cache_function_data
|
|
||||||
, size_t program_size
|
|
||||||
, size_t cache_size
|
|
||||||
, size_t memory_size
|
|
||||||
, size_t (* cache_block)(uint16_t * cache
|
|
||||||
, uint16_t offset
|
|
||||||
, size_t cache_size
|
|
||||||
, void * cache_function_data)
|
|
||||||
, dispatch_tree_t method_dispatcher)
|
|
||||||
{
|
|
||||||
|
|
||||||
machine_state_t state = malloc(sizeof(struct machine_state_s));
|
|
||||||
if(!state)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
uint16_t * cache = calloc(sizeof(uint16_t), cache_size);
|
|
||||||
if(!cache)
|
|
||||||
{
|
|
||||||
free(state);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
uint16_t * memory = calloc(sizeof(uint16_t), memory_size);
|
|
||||||
if(!memory)
|
|
||||||
{
|
|
||||||
free(state);
|
|
||||||
free(cache);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
state->program_size = program_size;
|
|
||||||
state->cache = cache;
|
|
||||||
state->cache_block = cache_block;
|
|
||||||
state->cache_size = cache_size;
|
|
||||||
state->cache_loaded = 0;
|
|
||||||
state->cache_offset = 0;
|
|
||||||
state->cache_function_data = cache_function_data;
|
|
||||||
|
|
||||||
state->program_counter = 0;
|
|
||||||
state->status_reg = 0;
|
|
||||||
state->shutdown_reg = 0;
|
|
||||||
int i;
|
|
||||||
for(i = 0; i < BCI_CORE_NUM_REG; i++)
|
|
||||||
{
|
|
||||||
state->data_reg[i] = 0;
|
|
||||||
}
|
|
||||||
state->stack = NULL;
|
|
||||||
|
|
||||||
state->memory = memory;
|
|
||||||
state->memory_size = memory_size;
|
|
||||||
|
|
||||||
state->method_dispatcher = method_dispatcher;
|
|
||||||
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
void machine_state_t_del(machine_state_t state)
|
|
||||||
{
|
|
||||||
free(state->cache);
|
|
||||||
free(state->memory);
|
|
||||||
dispatch_tree_t_del(state->method_dispatcher);
|
|
||||||
bci_stack_t_del(&(state->stack));
|
|
||||||
free(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
char update_cache(machine_state_t state, uint16_t offset)
|
|
||||||
{
|
|
||||||
// Calculate a clever offset for caching.
|
|
||||||
uint16_t cache_offset = offset;
|
|
||||||
if((cache_offset + state->cache_size)
|
|
||||||
> state->program_size)
|
|
||||||
{
|
|
||||||
if(state->program_size < state->cache_size)
|
|
||||||
{
|
|
||||||
cache_offset = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cache_offset = state->program_size - state->cache_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
size_t cached = state->cache_block(state->cache
|
|
||||||
, cache_offset
|
|
||||||
, state->cache_size
|
|
||||||
, state->cache_function_data);
|
|
||||||
|
|
||||||
if(cached != state->cache_size)
|
|
||||||
{
|
|
||||||
#ifdef DEBUG
|
|
||||||
printf("ERROR: should have cached %zu words, but got %zu.\n", state->cache_size, cached);
|
|
||||||
#endif
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
state->cache_offset = cache_offset;
|
|
||||||
state->cache_loaded = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char machine_state_t_get_word(machine_state_t state, uint16_t offset, uint16_t * result)
|
|
||||||
{
|
|
||||||
|
|
||||||
// This would be bad.
|
|
||||||
if(offset >= state->program_size)
|
|
||||||
{
|
|
||||||
return 0b01000000 | 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the in-cache offset of the desired offset.
|
|
||||||
int32_t in_cache_offset = offset - state->cache_offset;
|
|
||||||
|
|
||||||
// Check if we need to update the cache.
|
|
||||||
if( in_cache_offset < 0
|
|
||||||
|| !(state->cache_loaded)
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if(update_cache(state, offset))
|
|
||||||
{
|
|
||||||
#ifdef DEBUG
|
|
||||||
printf("ERROR: failed to update cache\n");
|
|
||||||
#endif
|
|
||||||
state->error = 0b01000000 | 2;
|
|
||||||
return 0b01000000 | 2;
|
|
||||||
}
|
|
||||||
// Re-calculate the in-cache offset
|
|
||||||
in_cache_offset = offset - state->cache_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
*result = state->cache[in_cache_offset];
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
char machine_state_t_exec_cycle(machine_state_t state)
|
|
||||||
{
|
|
||||||
char res = 0;
|
|
||||||
uint16_t opcode;
|
|
||||||
res = machine_state_t_get_word(state, state->program_counter, &opcode);
|
|
||||||
|
|
||||||
if(res)
|
|
||||||
{
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
printf("MSG: opcode = 0x%x, small_arg = 0x%x\n"
|
|
||||||
, opcode & BCI_CORE_OPCODE_MASK
|
|
||||||
, opcode & BCI_CORE_SMALL_ARG_MASK);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bci_core_method_t method = dispatch_tree_t_dispatch(
|
|
||||||
state->method_dispatcher
|
|
||||||
, opcode & BCI_CORE_OPCODE_MASK);
|
|
||||||
if(!method)
|
|
||||||
{
|
|
||||||
state->error = res;
|
|
||||||
return 0b10000000 | 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return BCI_CORE_RESULT_APPLICATION_BITS
|
|
||||||
& method( opcode & BCI_CORE_SMALL_ARG_MASK
|
|
||||||
, state);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
char machine_state_t_default_afterexec(machine_state_t state, uint8_t argc)
|
|
||||||
{
|
|
||||||
state->program_counter += 1 + argc;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
char machine_state_t_get_mem(machine_state_t state, uint16_t offset, uint16_t * result)
|
|
||||||
{
|
|
||||||
if(offset > state->memory_size)
|
|
||||||
{
|
|
||||||
state->error = 0b01000000 | 15;
|
|
||||||
return 0b01000000 | 15;
|
|
||||||
}
|
|
||||||
|
|
||||||
*result = state->memory[offset];
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
char machine_state_t_set_mem(machine_state_t state, uint16_t offset, uint16_t data)
|
|
||||||
{
|
|
||||||
if(offset > state->memory_size)
|
|
||||||
{
|
|
||||||
state->error = 0b01000000 | 15;
|
|
||||||
return 0b01000000 | 15;
|
|
||||||
}
|
|
||||||
|
|
||||||
state->memory[offset] = data;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
char machine_state_t_exec(machine_state_t state)
|
|
||||||
{
|
|
||||||
char status = 0;
|
|
||||||
while((!status) && (!state->shutdown_reg))
|
|
||||||
{
|
|
||||||
status = machine_state_t_exec_cycle(state);
|
|
||||||
}
|
|
||||||
state->error = status;
|
|
||||||
return status;
|
|
||||||
}
|
|
|
@ -1,121 +0,0 @@
|
||||||
#ifndef bci_interpreter_h__
|
|
||||||
#define bci_interpreter_h__
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include "../base.h"
|
|
||||||
#include "../method_dispatcher/method_dispatcher.h"
|
|
||||||
#include "../stack.h"
|
|
||||||
|
|
||||||
typedef struct machine_state_s
|
|
||||||
{
|
|
||||||
// The size of the program in 16-bit words
|
|
||||||
uint16_t program_size;
|
|
||||||
void * cache_function_data;
|
|
||||||
|
|
||||||
size_t cache_size;
|
|
||||||
uint16_t cache_offset;
|
|
||||||
uint16_t * cache;
|
|
||||||
size_t (* cache_block)(uint16_t * cache
|
|
||||||
, uint16_t offset
|
|
||||||
, size_t cache_size
|
|
||||||
, void * cache_function_data);
|
|
||||||
char cache_loaded;
|
|
||||||
|
|
||||||
uint16_t program_counter;
|
|
||||||
uint16_t status_reg;
|
|
||||||
// Any non-zero value in this register will
|
|
||||||
// break the program execution.
|
|
||||||
uint16_t shutdown_reg;
|
|
||||||
uint16_t data_reg[BCI_CORE_NUM_REG];
|
|
||||||
bci_stack_t stack;
|
|
||||||
|
|
||||||
size_t memory_size;
|
|
||||||
uint16_t * memory;
|
|
||||||
|
|
||||||
|
|
||||||
dispatch_tree_t method_dispatcher;
|
|
||||||
|
|
||||||
// Possible Error Codes:
|
|
||||||
// 0b01xxxxxx: memory related internal error
|
|
||||||
// 0b10xxxxxx: core method related internal error
|
|
||||||
// 0b00xxxxxx: application related internal error
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// 0b01000000 | 1: Program offset out of bounds
|
|
||||||
// 0b01000000 | 2: Failed to cache new data
|
|
||||||
// 0b01000000 | 15: Memory offset out of bounds
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// 0b10000000 | 1: Unknown opcode
|
|
||||||
char error;
|
|
||||||
|
|
||||||
} * machine_state_t;
|
|
||||||
|
|
||||||
machine_state_t machine_state_t_new( void * cache_function_data
|
|
||||||
, size_t program_size
|
|
||||||
, size_t cache_size
|
|
||||||
, size_t memory_size
|
|
||||||
, size_t (* cache_block)(uint16_t * cache
|
|
||||||
, uint16_t offset
|
|
||||||
, size_t cache_size
|
|
||||||
, void * cache_function_data)
|
|
||||||
, dispatch_tree_t method_dispatcher);
|
|
||||||
|
|
||||||
void machine_state_t_del(machine_state_t state);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This function essentially executes one cycle of the machine execution.
|
|
||||||
* It will fetch the opcode and argument, dispatch the method and execute it.
|
|
||||||
*
|
|
||||||
* Also this will update the cache if needed.
|
|
||||||
*
|
|
||||||
* Possible return codes:
|
|
||||||
*
|
|
||||||
* - 0bxyXXXXXX
|
|
||||||
* Error while executing the cycle.
|
|
||||||
* - 0b01XXXXXX
|
|
||||||
* Error in the internal memory management (i.e. program counter out
|
|
||||||
* of bounds)
|
|
||||||
* - 0b01000000 | 1: program_counter or argument offset > program_size
|
|
||||||
* - 0b01000000 | 2: failed to cache new data
|
|
||||||
*
|
|
||||||
* - 0b10XXXXXX
|
|
||||||
* Error while dispatching the method
|
|
||||||
* - 0b10000000 | 1: unknown opcode
|
|
||||||
*
|
|
||||||
* - 0b00XXXXXX
|
|
||||||
* XXXXXX is the return value of the bci_core_method_t method.
|
|
||||||
* */
|
|
||||||
char machine_state_t_exec_cycle(machine_state_t state);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Runs ``machine_state_t_exec_cycle`` until either this function
|
|
||||||
* returns a non-zero value or a non-zero value is stored in
|
|
||||||
* ``state->shutdown_reg``.
|
|
||||||
* Sets ``state->error`` to the last return value of ``machine_state_t_exec_cycle``
|
|
||||||
* and returns it.
|
|
||||||
* */
|
|
||||||
char machine_state_t_exec(machine_state_t state);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Do the default updates on the machine state.
|
|
||||||
* This will be basically increasing the program counter.
|
|
||||||
* */
|
|
||||||
char machine_state_t_default_afterexec(machine_state_t state, uint8_t argc);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get the word at offset in the program memory.
|
|
||||||
* Returns 0 on success, a non-zero value otherwise.
|
|
||||||
*
|
|
||||||
* It will set state->error appropiately.
|
|
||||||
* */
|
|
||||||
char machine_state_t_get_word(machine_state_t state, uint16_t offset, uint16_t * result);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get the word at offset in the RAM-alike memory.
|
|
||||||
* Works like machine_state_t_get_word.
|
|
||||||
* */
|
|
||||||
char machine_state_t_get_mem(machine_state_t state, uint16_t offset, uint16_t * result);
|
|
||||||
char machine_state_t_set_mem(machine_state_t state, uint16_t offset, uint16_t data);
|
|
||||||
#endif
|
|
|
@ -1,14 +0,0 @@
|
||||||
CC=gcc
|
|
||||||
|
|
||||||
all: test_interpreter
|
|
||||||
|
|
||||||
interpreter: clean
|
|
||||||
$(CC) -g ../../stack.c ../interpreter.c ../core_methods.c ../../method_dispatcher/method_dispatcher.c test_interpreter.c -o interpreter
|
|
||||||
|
|
||||||
test_interpreter: interpreter
|
|
||||||
valgrind ./interpreter
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
clean:
|
|
||||||
|
|
|
@ -1,69 +0,0 @@
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include "../interpreter.h"
|
|
||||||
#include "../core_methods.h"
|
|
||||||
#include "../../method_dispatcher/method_dispatcher.h"
|
|
||||||
|
|
||||||
size_t copy_cache(uint16_t * cache
|
|
||||||
, uint16_t offset
|
|
||||||
, size_t cache_size
|
|
||||||
, void * cache_function_data);
|
|
||||||
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
dispatch_tree_t tree = dispatch_tree_t_new();
|
|
||||||
dispatch_tree_autoinserter_t inserter = dispatch_tree_autoinserter_t_new(tree);
|
|
||||||
uint16_t ldi = dispatch_tree_autoinserter_t_insert(inserter, (bci_core_method_t) bci_cm_ldi);
|
|
||||||
uint16_t add = dispatch_tree_autoinserter_t_insert(inserter, (bci_core_method_t) bci_cm_add);
|
|
||||||
|
|
||||||
uint16_t * program = calloc(sizeof(uint16_t), 20);
|
|
||||||
program[0] = ldi;
|
|
||||||
program[1] = 0xfefe;
|
|
||||||
program[2] = ldi | 1;
|
|
||||||
program[3] = 2;
|
|
||||||
program[4] = ldi | 2;
|
|
||||||
program[5] = 3;
|
|
||||||
program[6] = add | 1;
|
|
||||||
program[7] = 2;
|
|
||||||
|
|
||||||
machine_state_t state = machine_state_t_new(
|
|
||||||
program
|
|
||||||
, 8
|
|
||||||
, 20
|
|
||||||
, 20
|
|
||||||
, copy_cache
|
|
||||||
, tree);
|
|
||||||
|
|
||||||
machine_state_t_exec_cycle(state);
|
|
||||||
machine_state_t_exec_cycle(state);
|
|
||||||
machine_state_t_exec_cycle(state);
|
|
||||||
machine_state_t_exec_cycle(state);
|
|
||||||
printf("data_reg[0]: %x\n", state->data_reg[0]);
|
|
||||||
assert(state->data_reg[0] == 0xfefe);
|
|
||||||
printf("data_reg[1]: %x\n", state->data_reg[1]);
|
|
||||||
assert(state->data_reg[1] == 5);
|
|
||||||
printf("data_reg[2]: %x\n", state->data_reg[2]);
|
|
||||||
assert(state->data_reg[2] == 3);
|
|
||||||
printf("program_counter: %d\n", state->program_counter);
|
|
||||||
assert(state->program_counter == 8);
|
|
||||||
dispatch_tree_autoinserter_t_del(inserter);
|
|
||||||
machine_state_t_del(state);
|
|
||||||
free(program);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t copy_cache(uint16_t * cache
|
|
||||||
, uint16_t offset
|
|
||||||
, size_t cache_size
|
|
||||||
, void * cache_function_data)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
for(i = 0; i < cache_size; i++)
|
|
||||||
{
|
|
||||||
printf("\tCP [%zd]->[%zd]: %x\n", i + offset, i, ((uint16_t *) cache_function_data)[i + offset]);
|
|
||||||
cache[i] = ((uint16_t *) cache_function_data)[i + offset];
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,158 +0,0 @@
|
||||||
#include <stdlib.h>
|
|
||||||
#include "method_dispatcher.h"
|
|
||||||
|
|
||||||
|
|
||||||
dispatch_tree_t dispatch_tree_t_new(void)
|
|
||||||
{
|
|
||||||
dispatch_tree_t tree = malloc(sizeof(struct dispatch_tree_s));
|
|
||||||
tree->root = NULL;
|
|
||||||
return tree;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dispatch_tree_t_del(dispatch_tree_t tree)
|
|
||||||
{
|
|
||||||
dispatch_tree_node_t_del(tree->root);
|
|
||||||
free(tree);
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch_tree_node_t dispatch_tree_node_t_new(uint16_t word
|
|
||||||
, bci_core_method_t method)
|
|
||||||
{
|
|
||||||
dispatch_tree_node_t node = malloc(sizeof(struct dispatch_tree_node_s));
|
|
||||||
node->higher = NULL;
|
|
||||||
node->lower = 0;
|
|
||||||
node->method = method;
|
|
||||||
node->word = word;
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dispatch_tree_node_t_del(dispatch_tree_node_t node)
|
|
||||||
{
|
|
||||||
if(node->higher)
|
|
||||||
{
|
|
||||||
dispatch_tree_node_t_del(node->higher);
|
|
||||||
}
|
|
||||||
if(node->lower)
|
|
||||||
{
|
|
||||||
dispatch_tree_node_t_del(node->lower);
|
|
||||||
}
|
|
||||||
free(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
char dispatch_tree_t_insert(dispatch_tree_t tree
|
|
||||||
, uint16_t word
|
|
||||||
, bci_core_method_t method)
|
|
||||||
{
|
|
||||||
dispatch_tree_node_t new_node = dispatch_tree_node_t_new(word, method);
|
|
||||||
if(!new_node)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// explicitly handle empty tree
|
|
||||||
if(!tree->root)
|
|
||||||
{
|
|
||||||
tree->root = new_node;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// non-empty tree
|
|
||||||
dispatch_tree_node_t this_node = tree->root;
|
|
||||||
dispatch_tree_node_t parent_node = NULL;
|
|
||||||
// search for place
|
|
||||||
do
|
|
||||||
{
|
|
||||||
parent_node = this_node;
|
|
||||||
if(parent_node->word < word)
|
|
||||||
{
|
|
||||||
this_node = parent_node->higher;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(parent_node->word > word)
|
|
||||||
{
|
|
||||||
this_node = parent_node->lower;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(parent_node->word == word)
|
|
||||||
{
|
|
||||||
// we already have that key.
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
while(this_node);
|
|
||||||
if(parent_node->word < word)
|
|
||||||
{
|
|
||||||
parent_node->higher = new_node;
|
|
||||||
}
|
|
||||||
if(parent_node->word > word)
|
|
||||||
{
|
|
||||||
parent_node->lower = new_node;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bci_core_method_t dispatch_tree_t_dispatch(dispatch_tree_t tree
|
|
||||||
, uint16_t word)
|
|
||||||
{
|
|
||||||
dispatch_tree_node_t this_node = tree->root;
|
|
||||||
while(this_node)
|
|
||||||
{
|
|
||||||
if(this_node->word < word)
|
|
||||||
{
|
|
||||||
this_node = this_node->higher;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(this_node->word > word)
|
|
||||||
{
|
|
||||||
this_node = this_node->lower;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(this_node->word == word)
|
|
||||||
{
|
|
||||||
return this_node->method;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch_tree_autoinserter_t dispatch_tree_autoinserter_t_new(dispatch_tree_t tree)
|
|
||||||
{
|
|
||||||
dispatch_tree_autoinserter_t autoinserter = malloc(
|
|
||||||
sizeof(struct dispatch_tree_autoinserter_s));
|
|
||||||
if(!autoinserter)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
autoinserter->mayor = 2;
|
|
||||||
autoinserter->minor = 1;
|
|
||||||
autoinserter->tree = tree;
|
|
||||||
return autoinserter;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dispatch_tree_autoinserter_t_del(dispatch_tree_autoinserter_t autoinserter)
|
|
||||||
{
|
|
||||||
free(autoinserter);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
uint16_t dispatch_tree_autoinserter_t_insert(
|
|
||||||
dispatch_tree_autoinserter_t autoinserter
|
|
||||||
, bci_core_method_t method)
|
|
||||||
{
|
|
||||||
uint16_t opcode = 0b1111111111;
|
|
||||||
opcode *= autoinserter->minor;
|
|
||||||
opcode /= autoinserter->mayor;
|
|
||||||
opcode <<= 6;
|
|
||||||
|
|
||||||
dispatch_tree_t_insert(autoinserter->tree, opcode, method);
|
|
||||||
|
|
||||||
autoinserter->minor = (autoinserter->minor + 2) % autoinserter->mayor;
|
|
||||||
if(autoinserter->minor == 1)
|
|
||||||
{
|
|
||||||
autoinserter->mayor *= 2;
|
|
||||||
}
|
|
||||||
return opcode;
|
|
||||||
}
|
|
|
@ -1,87 +0,0 @@
|
||||||
#ifndef bci_method_dispatcher_h__
|
|
||||||
#define bci_method_dispatcher_h__
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include "../base.h"
|
|
||||||
|
|
||||||
typedef struct dispatch_tree_node_s
|
|
||||||
{
|
|
||||||
struct dispatch_tree_node_s * higher;
|
|
||||||
struct dispatch_tree_node_s * lower;
|
|
||||||
uint16_t word;
|
|
||||||
bci_core_method_t method;
|
|
||||||
} * dispatch_tree_node_t;
|
|
||||||
|
|
||||||
typedef struct dispatch_tree_s
|
|
||||||
{
|
|
||||||
dispatch_tree_node_t root;
|
|
||||||
} * dispatch_tree_t;
|
|
||||||
|
|
||||||
dispatch_tree_t dispatch_tree_t_new(void);
|
|
||||||
/*
|
|
||||||
* This deletes the tree and will invoke dispatch_tree_node_t_del on
|
|
||||||
* tree->root (which will delete all the other nodes recursively).
|
|
||||||
* If you want to keep nodes you have to explicityl remove the reference to
|
|
||||||
* them by setting them to NULL.
|
|
||||||
* */
|
|
||||||
void dispatch_tree_t_del(dispatch_tree_t tree);
|
|
||||||
|
|
||||||
|
|
||||||
dispatch_tree_node_t dispatch_tree_node_t_new(uint16_t word
|
|
||||||
, bci_core_method_t method);
|
|
||||||
/*
|
|
||||||
* This deletes the node an will invoke dispatch_tree_node_t_del on
|
|
||||||
* node->higher and node->lower. If you want to keep those nodes
|
|
||||||
* you have to explicitly clear the reference by setting them to NULL.
|
|
||||||
* */
|
|
||||||
void dispatch_tree_node_t_del(dispatch_tree_node_t node);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Insert a new key-value-pair into the tree.
|
|
||||||
*
|
|
||||||
* Return codes:
|
|
||||||
* 0: OK
|
|
||||||
* 1: out of memory
|
|
||||||
* 2: key already in tree
|
|
||||||
* */
|
|
||||||
char dispatch_tree_t_insert(dispatch_tree_t tree
|
|
||||||
, uint16_t word
|
|
||||||
, bci_core_method_t method);
|
|
||||||
|
|
||||||
|
|
||||||
bci_core_method_t dispatch_tree_t_dispatch(dispatch_tree_t tree
|
|
||||||
, uint16_t word);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct dispatch_tree_autoinserter_s
|
|
||||||
{
|
|
||||||
uint16_t mayor;
|
|
||||||
uint16_t minor;
|
|
||||||
dispatch_tree_t tree;
|
|
||||||
} * dispatch_tree_autoinserter_t;
|
|
||||||
|
|
||||||
dispatch_tree_autoinserter_t dispatch_tree_autoinserter_t_new(dispatch_tree_t tree);
|
|
||||||
void dispatch_tree_autoinserter_t_del(dispatch_tree_autoinserter_t autoinserter);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This function inserts a new method into the tree and automatically
|
|
||||||
* chooses the optimal word to prevent degeneration.
|
|
||||||
*
|
|
||||||
* NOTE:
|
|
||||||
* When inserting mutliple methods this function acts deterministic,
|
|
||||||
* IF AND ONLY IF the order of the methods is not changed.
|
|
||||||
*
|
|
||||||
* The assembler will bring an analogous function that allows one
|
|
||||||
* to determine the opcodes of the methods.
|
|
||||||
*
|
|
||||||
* NOTE:
|
|
||||||
* This algorithm will not work for more that 1023 registered opcodes.
|
|
||||||
* This limit is however considered acceptable.
|
|
||||||
*
|
|
||||||
* */
|
|
||||||
uint16_t dispatch_tree_autoinserter_t_insert(
|
|
||||||
dispatch_tree_autoinserter_t autoinserter
|
|
||||||
, bci_core_method_t method);
|
|
||||||
#endif
|
|
|
@ -1,14 +0,0 @@
|
||||||
CC=gcc
|
|
||||||
|
|
||||||
all: test_method_dispatcher
|
|
||||||
|
|
||||||
method_dispatcher: clean
|
|
||||||
$(CC) -g ../method_dispatcher.c test_method_dispatcher.c -o method_dispatcher
|
|
||||||
|
|
||||||
test_method_dispatcher: method_dispatcher
|
|
||||||
valgrind ./method_dispatcher
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
clean:
|
|
||||||
-rm method_dispatcher
|
|
|
@ -1,63 +0,0 @@
|
||||||
#include <stdio.h>
|
|
||||||
#include "../method_dispatcher.h"
|
|
||||||
|
|
||||||
char m1(uint8_t small_arg, void * state);
|
|
||||||
char m2(uint8_t small_arg, void * state);
|
|
||||||
char m3(uint8_t small_arg, void * state);
|
|
||||||
char m4(uint8_t small_arg, void * state);
|
|
||||||
char m5(uint8_t small_arg, void * state);
|
|
||||||
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
printf("sizeof struct dispatch_tree_node_s: %zd\n", sizeof(struct dispatch_tree_node_s));
|
|
||||||
dispatch_tree_t tree = dispatch_tree_t_new();
|
|
||||||
|
|
||||||
dispatch_tree_t_insert(tree, 3 << 6, m3);
|
|
||||||
dispatch_tree_t_insert(tree, 2 << 6, m2);
|
|
||||||
dispatch_tree_t_insert(tree, 1 << 6, m1);
|
|
||||||
dispatch_tree_t_insert(tree, 4 << 6, m4);
|
|
||||||
dispatch_tree_t_insert(tree, 5 << 6, m5);
|
|
||||||
|
|
||||||
int i;
|
|
||||||
for(i = 1; i < 6; i++)
|
|
||||||
{
|
|
||||||
dispatch_tree_t_dispatch(tree, i << 6)(i, NULL);
|
|
||||||
}
|
|
||||||
dispatch_tree_t_del(tree);
|
|
||||||
|
|
||||||
|
|
||||||
bci_core_method_t methods[5] = {m1, m2, m3, m4, m5};
|
|
||||||
tree = dispatch_tree_t_new();
|
|
||||||
dispatch_tree_autoinserter_t inserter = dispatch_tree_autoinserter_t_new(tree);
|
|
||||||
for(i = 0; i < 5; i++)
|
|
||||||
{
|
|
||||||
printf("%u\n", dispatch_tree_autoinserter_t_insert(inserter, methods[i]));
|
|
||||||
}
|
|
||||||
dispatch_tree_autoinserter_t_del(inserter);
|
|
||||||
dispatch_tree_t_del(tree);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
char m1(uint8_t small_arg, void * state)
|
|
||||||
{
|
|
||||||
printf("m1: %d\n", small_arg);
|
|
||||||
}
|
|
||||||
char m2(uint8_t small_arg, void * state)
|
|
||||||
{
|
|
||||||
printf("m2: %d\n", small_arg);
|
|
||||||
}
|
|
||||||
char m3(uint8_t small_arg, void * state)
|
|
||||||
{
|
|
||||||
printf("m3: %d\n", small_arg);
|
|
||||||
}
|
|
||||||
char m4(uint8_t small_arg, void * state)
|
|
||||||
{
|
|
||||||
printf("m4: %d\n", small_arg);
|
|
||||||
}
|
|
||||||
char m5(uint8_t small_arg, void * state)
|
|
||||||
{
|
|
||||||
printf("m5: %d\n", small_arg);
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
#include <stdlib.h>
|
|
||||||
#include "stack.h"
|
|
||||||
|
|
||||||
char bci_stack_t_push(bci_stack_t * stack, uint16_t value)
|
|
||||||
{
|
|
||||||
bci_stack_t node = malloc(sizeof(struct bci_stack_s));
|
|
||||||
if(!node)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
node->next = *stack;
|
|
||||||
node->value = value;
|
|
||||||
*stack = node;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
char bci_stack_t_pop(bci_stack_t * stack, uint16_t * result)
|
|
||||||
{
|
|
||||||
bci_stack_t this_node;
|
|
||||||
if(!*stack)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
this_node = *stack;
|
|
||||||
*result = this_node->value;
|
|
||||||
*stack = this_node->next;
|
|
||||||
free(this_node);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bci_stack_t_del(bci_stack_t * stack)
|
|
||||||
{
|
|
||||||
bci_stack_t this_node;
|
|
||||||
|
|
||||||
while(*stack)
|
|
||||||
{
|
|
||||||
this_node = *stack;
|
|
||||||
*stack = this_node->next;
|
|
||||||
free(this_node);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
#ifndef bci_stack_h__
|
|
||||||
#define bci_stack_h__
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
typedef struct bci_stack_s
|
|
||||||
{
|
|
||||||
struct bci_stack_s * next;
|
|
||||||
uint16_t value;
|
|
||||||
} * bci_stack_t;
|
|
||||||
|
|
||||||
char bci_stack_t_push(bci_stack_t * stack, uint16_t value);
|
|
||||||
char bci_stack_t_pop(bci_stack_t * stack, uint16_t * result);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Deletes the entire (!) stack.
|
|
||||||
*
|
|
||||||
* */
|
|
||||||
void bci_stack_t_del(bci_stack_t * stack);
|
|
||||||
#endif
|
|
|
@ -1,12 +0,0 @@
|
||||||
CC=gcc
|
|
||||||
|
|
||||||
all: test_stack
|
|
||||||
|
|
||||||
stack: clean
|
|
||||||
$(CC) -g ../stack.c test_stack.c -o stack
|
|
||||||
|
|
||||||
test_stack: stack
|
|
||||||
valgrind ./stack
|
|
||||||
|
|
||||||
clean:
|
|
||||||
-rm stack
|
|
|
@ -1,34 +0,0 @@
|
||||||
#include <stdio.h>
|
|
||||||
#include "../stack.h"
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
bci_stack_t stack = NULL;
|
|
||||||
int i;
|
|
||||||
uint16_t res;
|
|
||||||
char status = 0;
|
|
||||||
|
|
||||||
|
|
||||||
for(i = 0; i < 10; i++)
|
|
||||||
{
|
|
||||||
bci_stack_t_push(&stack, (uint16_t) i);
|
|
||||||
}
|
|
||||||
--i;
|
|
||||||
while(!status)
|
|
||||||
{
|
|
||||||
status = bci_stack_t_pop(&stack, &res);
|
|
||||||
if(!status)
|
|
||||||
{
|
|
||||||
assert(res == i--);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for(i = 0; i < 10; i++)
|
|
||||||
{
|
|
||||||
bci_stack_t_push(&stack, (uint16_t) i);
|
|
||||||
}
|
|
||||||
bci_stack_t_del(&stack);
|
|
||||||
return 0;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user