Removed BCI-base and BCI-assembler from BCI-dev

This commit is contained in:
Daniel Knüttel 2018-10-27 19:54:01 +02:00
parent b6a3cdcd59
commit f4304de5ad
35 changed files with 0 additions and 3819 deletions

View File

@ -1,3 +0,0 @@
.PHONY: test
test:
python3 -m pytest test/

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)}

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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 ``[]``.

View File

@ -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"]
}
]
)

View File

@ -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"

View File

@ -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"
]

View File

@ -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
}

View File

@ -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"

View File

@ -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]

View File

@ -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()

View File

@ -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)

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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:

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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

View File

@ -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;
}