mirror of
https://github.com/irmen/prog8.git
synced 2025-02-21 10:29:03 +00:00
restructure codegen
This commit is contained in:
parent
44c0d243ef
commit
4d929e00f5
1
il65/codegen/__init__.py
Normal file
1
il65/codegen/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
# package
|
@ -1,21 +1,15 @@
|
|||||||
"""
|
"""
|
||||||
Programming Language for 6502/6510 microprocessors, codename 'Sick'
|
Programming Language for 6502/6510 microprocessors, codename 'Sick'
|
||||||
This is the assembly code generator (from the parse tree)
|
This is the 6502 assembly code generator (directly from the parse tree)
|
||||||
|
|
||||||
Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import math
|
|
||||||
import attr
|
import attr
|
||||||
from typing import Set, Callable, no_type_check
|
from typing import Set, Callable
|
||||||
from ..datatypes import FLOAT_MAX_POSITIVE, FLOAT_MAX_NEGATIVE
|
from ...plyparse import Scope, AstNode
|
||||||
from ..plyparse import Scope, AstNode
|
from ...compile import Zeropage
|
||||||
from ..compile import Zeropage
|
|
||||||
|
|
||||||
|
|
||||||
class CodeError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
@attr.s(repr=False, cmp=False)
|
@attr.s(repr=False, cmp=False)
|
||||||
@ -26,56 +20,6 @@ class Context:
|
|||||||
floats_enabled = attr.ib(type=bool)
|
floats_enabled = attr.ib(type=bool)
|
||||||
|
|
||||||
|
|
||||||
def to_hex(number: int) -> str:
|
|
||||||
# 0..15 -> "0".."15"
|
|
||||||
# 16..255 -> "$10".."$ff"
|
|
||||||
# 256..65536 -> "$0100".."$ffff"
|
|
||||||
assert type(number) is int
|
|
||||||
if number is None:
|
|
||||||
raise ValueError("number")
|
|
||||||
if 0 <= number < 16:
|
|
||||||
return str(number)
|
|
||||||
if 0 <= number < 0x100:
|
|
||||||
return "${:02x}".format(number)
|
|
||||||
if 0 <= number < 0x10000:
|
|
||||||
return "${:04x}".format(number)
|
|
||||||
raise OverflowError(number)
|
|
||||||
|
|
||||||
|
|
||||||
def to_mflpt5(number: float) -> bytearray:
|
|
||||||
# algorithm here https://sourceforge.net/p/acme-crossass/code-0/62/tree/trunk/ACME_Lib/cbm/mflpt.a
|
|
||||||
number = float(number)
|
|
||||||
if number < FLOAT_MAX_NEGATIVE or number > FLOAT_MAX_POSITIVE:
|
|
||||||
raise OverflowError("floating point number out of 5-byte mflpt range", number)
|
|
||||||
if number == 0.0:
|
|
||||||
return bytearray([0, 0, 0, 0, 0])
|
|
||||||
if number < 0.0:
|
|
||||||
sign = 0x80000000
|
|
||||||
number = -number
|
|
||||||
else:
|
|
||||||
sign = 0x00000000
|
|
||||||
mant, exp = math.frexp(number)
|
|
||||||
exp += 128
|
|
||||||
if exp < 1:
|
|
||||||
# underflow, use zero instead
|
|
||||||
return bytearray([0, 0, 0, 0, 0])
|
|
||||||
if exp > 255:
|
|
||||||
raise OverflowError("floating point number out of 5-byte mflpt range", number)
|
|
||||||
mant = sign | int(mant * 0x100000000) & 0x7fffffff
|
|
||||||
return bytearray([exp]) + int.to_bytes(mant, 4, "big")
|
|
||||||
|
|
||||||
|
|
||||||
def mflpt5_to_float(mflpt: bytearray) -> float:
|
|
||||||
# algorithm here https://sourceforge.net/p/acme-crossass/code-0/62/tree/trunk/ACME_Lib/cbm/mflpt.a
|
|
||||||
if mflpt == bytearray([0, 0, 0, 0, 0]):
|
|
||||||
return 0.0
|
|
||||||
exp = mflpt[0] - 128
|
|
||||||
sign = mflpt[1] & 0x80
|
|
||||||
number = 0x80000000 | int.from_bytes(mflpt[1:], "big")
|
|
||||||
number = float(number) * 2**exp / 0x100000000
|
|
||||||
return -number if sign else number
|
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def preserving_registers(registers: Set[str], scope: Scope, out: Callable, loads_a_within: bool=False, force_preserve: bool=False):
|
def preserving_registers(registers: Set[str], scope: Scope, out: Callable, loads_a_within: bool=False, force_preserve: bool=False):
|
||||||
# this sometimes clobbers a ZP scratch register and is therefore NOT safe to use in interrupts
|
# this sometimes clobbers a ZP scratch register and is therefore NOT safe to use in interrupts
|
@ -6,10 +6,11 @@ Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from ..plyparse import Scope, Assignment, AugAssignment, Register, LiteralValue, SymbolName, VarDef, Dereference
|
from . import preserving_registers, Context
|
||||||
from . import CodeError, preserving_registers, to_hex, Context
|
from ..shared import CodeError, to_hex
|
||||||
from ..datatypes import REGISTER_BYTES, VarType, DataType
|
from ...plyparse import Scope, Assignment, AugAssignment, Register, LiteralValue, SymbolName, VarDef, Dereference
|
||||||
from ..compile import Zeropage
|
from ...datatypes import REGISTER_BYTES, VarType, DataType
|
||||||
|
from ...compile import Zeropage
|
||||||
|
|
||||||
|
|
||||||
def generate_assignment(ctx: Context) -> None:
|
def generate_assignment(ctx: Context) -> None:
|
@ -5,8 +5,9 @@ This is the code generator for gotos and subroutine calls.
|
|||||||
Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from ..plyparse import Goto, SubCall, LiteralValue, SymbolName, Dereference, Register
|
from . import Context
|
||||||
from . import Context, CodeError, to_hex
|
from ..shared import CodeError, to_hex
|
||||||
|
from ...plyparse import Goto, SubCall, LiteralValue, SymbolName, Dereference
|
||||||
|
|
||||||
|
|
||||||
def generate_goto(ctx: Context) -> None:
|
def generate_goto(ctx: Context) -> None:
|
@ -8,14 +8,15 @@ Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
|||||||
import os
|
import os
|
||||||
import datetime
|
import datetime
|
||||||
from typing import TextIO, Callable, no_type_check
|
from typing import TextIO, Callable, no_type_check
|
||||||
from ..plylex import print_bold
|
from . import Context
|
||||||
from ..plyparse import (Module, ProgramFormat, Block, Directive, VarDef, Label, Subroutine, ZpOptions,
|
|
||||||
InlineAssembly, Return, Register, Goto, SubCall, Assignment, AugAssignment, IncrDecr)
|
|
||||||
from . import CodeError, to_hex, to_mflpt5, Context
|
|
||||||
from .variables import generate_block_init, generate_block_vars
|
from .variables import generate_block_init, generate_block_vars
|
||||||
from .assignment import generate_assignment, generate_aug_assignment
|
from .assignment import generate_assignment, generate_aug_assignment
|
||||||
from .calls import generate_goto, generate_subcall
|
from .calls import generate_goto, generate_subcall
|
||||||
from .incrdecr import generate_incrdecr
|
from .incrdecr import generate_incrdecr
|
||||||
|
from ..shared import CodeError, to_hex, to_mflpt5
|
||||||
|
from ...plylex import print_bold
|
||||||
|
from ...plyparse import (Module, ProgramFormat, Block, Directive, VarDef, Label, Subroutine, ZpOptions,
|
||||||
|
InlineAssembly, Return, Register, Goto, SubCall, Assignment, AugAssignment, IncrDecr)
|
||||||
|
|
||||||
|
|
||||||
class Output:
|
class Output:
|
@ -7,9 +7,10 @@ is quite frequent and this generates assembly code tweaked for this case.
|
|||||||
Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from ..plyparse import VarDef, Register, IncrDecr, SymbolName, Dereference, LiteralValue, scoped_name
|
from . import Context, preserving_registers
|
||||||
from ..datatypes import VarType, DataType, REGISTER_BYTES
|
from ..shared import CodeError, to_hex
|
||||||
from . import CodeError, preserving_registers, to_hex, Context
|
from ...plyparse import VarDef, Register, IncrDecr, SymbolName, Dereference, LiteralValue, scoped_name
|
||||||
|
from ...datatypes import VarType, DataType, REGISTER_BYTES
|
||||||
|
|
||||||
|
|
||||||
def generate_incrdecr(ctx: Context) -> None:
|
def generate_incrdecr(ctx: Context) -> None:
|
@ -7,9 +7,9 @@ Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
|||||||
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from typing import Dict, List, Callable, Any, no_type_check
|
from typing import Dict, List, Callable, Any, no_type_check
|
||||||
from ..plyparse import Block, VarDef, LiteralValue, AddressOf
|
from ..shared import to_hex, to_mflpt5, CodeError
|
||||||
from ..datatypes import DataType, VarType, STRING_DATATYPES
|
from ...plyparse import Block, VarDef, LiteralValue, AddressOf
|
||||||
from . import to_hex, to_mflpt5, CodeError
|
from ...datatypes import DataType, VarType, STRING_DATATYPES
|
||||||
|
|
||||||
|
|
||||||
def generate_block_init(out: Callable, block: Block) -> None:
|
def generate_block_init(out: Callable, block: Block) -> None:
|
64
il65/codegen/shared.py
Normal file
64
il65/codegen/shared.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
"""
|
||||||
|
Programming Language for 6502/6510 microprocessors, codename 'Sick'
|
||||||
|
Shared logic for the code generators.
|
||||||
|
|
||||||
|
Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
import math
|
||||||
|
from ..datatypes import FLOAT_MAX_POSITIVE, FLOAT_MAX_NEGATIVE
|
||||||
|
|
||||||
|
|
||||||
|
class CodeError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def to_hex(number: int) -> str:
|
||||||
|
# 0..15 -> "0".."15"
|
||||||
|
# 16..255 -> "$10".."$ff"
|
||||||
|
# 256..65536 -> "$0100".."$ffff"
|
||||||
|
assert type(number) is int
|
||||||
|
if number is None:
|
||||||
|
raise ValueError("number")
|
||||||
|
if 0 <= number < 16:
|
||||||
|
return str(number)
|
||||||
|
if 0 <= number < 0x100:
|
||||||
|
return "${:02x}".format(number)
|
||||||
|
if 0 <= number < 0x10000:
|
||||||
|
return "${:04x}".format(number)
|
||||||
|
raise OverflowError(number)
|
||||||
|
|
||||||
|
|
||||||
|
def to_mflpt5(number: float) -> bytearray:
|
||||||
|
# algorithm here https://sourceforge.net/p/acme-crossass/code-0/62/tree/trunk/ACME_Lib/cbm/mflpt.a
|
||||||
|
number = float(number)
|
||||||
|
if number < FLOAT_MAX_NEGATIVE or number > FLOAT_MAX_POSITIVE:
|
||||||
|
raise OverflowError("floating point number out of 5-byte mflpt range", number)
|
||||||
|
if number == 0.0:
|
||||||
|
return bytearray([0, 0, 0, 0, 0])
|
||||||
|
if number < 0.0:
|
||||||
|
sign = 0x80000000
|
||||||
|
number = -number
|
||||||
|
else:
|
||||||
|
sign = 0x00000000
|
||||||
|
mant, exp = math.frexp(number)
|
||||||
|
exp += 128
|
||||||
|
if exp < 1:
|
||||||
|
# underflow, use zero instead
|
||||||
|
return bytearray([0, 0, 0, 0, 0])
|
||||||
|
if exp > 255:
|
||||||
|
raise OverflowError("floating point number out of 5-byte mflpt range", number)
|
||||||
|
mant = sign | int(mant * 0x100000000) & 0x7fffffff
|
||||||
|
return bytearray([exp]) + int.to_bytes(mant, 4, "big")
|
||||||
|
|
||||||
|
|
||||||
|
def mflpt5_to_float(mflpt: bytearray) -> float:
|
||||||
|
# algorithm here https://sourceforge.net/p/acme-crossass/code-0/62/tree/trunk/ACME_Lib/cbm/mflpt.a
|
||||||
|
if mflpt == bytearray([0, 0, 0, 0, 0]):
|
||||||
|
return 0.0
|
||||||
|
exp = mflpt[0] - 128
|
||||||
|
sign = mflpt[1] & 0x80
|
||||||
|
number = 0x80000000 | int.from_bytes(mflpt[1:], "big")
|
||||||
|
number = float(number) * 2**exp / 0x100000000
|
||||||
|
return -number if sign else number
|
8
il65/codegen/tinyvm/__init__.py
Normal file
8
il65/codegen/tinyvm/__init__.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
"""
|
||||||
|
Programming Language for 6502/6510 microprocessors, codename 'Sick'
|
||||||
|
This is the tinyvm stack based program generator
|
||||||
|
|
||||||
|
Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
||||||
|
"""
|
||||||
|
|
||||||
|
# @todo
|
@ -12,7 +12,7 @@ import argparse
|
|||||||
import subprocess
|
import subprocess
|
||||||
from .compile import PlyParser
|
from .compile import PlyParser
|
||||||
from .optimize import optimize
|
from .optimize import optimize
|
||||||
from .emit.generate import AssemblyGenerator
|
from .codegen.mos6502.generate import AssemblyGenerator
|
||||||
from .plylex import print_bold
|
from .plylex import print_bold
|
||||||
from .plyparse import ProgramFormat
|
from .plyparse import ProgramFormat
|
||||||
|
|
||||||
|
@ -18,12 +18,13 @@ from .datatypes import (DataType, VarType, REGISTER_SYMBOLS, REGISTER_BYTES, REG
|
|||||||
FLOAT_MAX_NEGATIVE, FLOAT_MAX_POSITIVE, char_to_bytevalue)
|
FLOAT_MAX_NEGATIVE, FLOAT_MAX_POSITIVE, char_to_bytevalue)
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["ProgramFormat", "ZpOptions", "math_functions", "builtin_functions", "ParseError", "ExpressionEvaluationError",
|
__all__ = ["ProgramFormat", "ZpOptions", "math_functions", "builtin_functions",
|
||||||
"UndefinedSymbolError", "AstNode", "Directive", "Scope", "Block", "Module", "Label", "Expression",
|
"AstNode", "Directive", "Scope", "Block", "Module", "Label", "Expression",
|
||||||
"Register", "Subroutine", "LiteralValue", "AddressOf", "SymbolName", "Dereference", "IncrDecr",
|
"Register", "Subroutine", "LiteralValue", "AddressOf", "SymbolName", "Dereference", "IncrDecr",
|
||||||
"ExpressionWithOperator", "Goto", "SubCall", "VarDef", "Return", "Assignment", "AugAssignment",
|
"ExpressionWithOperator", "Goto", "SubCall", "VarDef", "Return", "Assignment", "AugAssignment",
|
||||||
"InlineAssembly", "BuiltinFunction", "TokenFilter", "parser", "connect_parents", "DatatypeNode",
|
"InlineAssembly", "BuiltinFunction", "TokenFilter", "parser", "connect_parents", "DatatypeNode",
|
||||||
"parse_file", "coerce_constant_value", "datatype_of", "check_symbol_definition", "NotCompiletimeConstantError"]
|
"parse_file", "coerce_constant_value", "datatype_of", "check_symbol_definition", "scoped_name",
|
||||||
|
"NotCompiletimeConstantError", "ExpressionEvaluationError", "ParseError", "UndefinedSymbolError"]
|
||||||
|
|
||||||
|
|
||||||
class ProgramFormat(enum.Enum):
|
class ProgramFormat(enum.Enum):
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
# package
|
60
tests/test_codegen_mos6502.py
Normal file
60
tests/test_codegen_mos6502.py
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import pytest
|
||||||
|
from il65.datatypes import FLOAT_MAX_NEGATIVE, FLOAT_MAX_POSITIVE
|
||||||
|
from il65.codegen.shared import to_hex, to_mflpt5
|
||||||
|
|
||||||
|
|
||||||
|
def test_to_hex():
|
||||||
|
assert to_hex(0) == "0"
|
||||||
|
assert to_hex(1) == "1"
|
||||||
|
assert to_hex(10) == "10"
|
||||||
|
assert to_hex(15) == "15"
|
||||||
|
assert to_hex(16) == "$10"
|
||||||
|
assert to_hex(255) == "$ff"
|
||||||
|
assert to_hex(256) == "$0100"
|
||||||
|
assert to_hex(20060) == "$4e5c"
|
||||||
|
assert to_hex(65535) == "$ffff"
|
||||||
|
with pytest.raises(OverflowError):
|
||||||
|
to_hex(-1)
|
||||||
|
with pytest.raises(OverflowError):
|
||||||
|
to_hex(65536)
|
||||||
|
|
||||||
|
|
||||||
|
def test_float_to_mflpt5():
|
||||||
|
mflpt = to_mflpt5(1.0)
|
||||||
|
assert type(mflpt) is bytearray
|
||||||
|
assert b"\x00\x00\x00\x00\x00" == to_mflpt5(0)
|
||||||
|
assert b"\x82\x49\x0F\xDA\xA1" == to_mflpt5(3.141592653)
|
||||||
|
assert b"\x82\x49\x0F\xDA\xA2" == to_mflpt5(3.141592653589793)
|
||||||
|
assert b"\x90\x80\x00\x00\x00" == to_mflpt5(-32768)
|
||||||
|
assert b"\x81\x00\x00\x00\x00" == to_mflpt5(1)
|
||||||
|
assert b"\x80\x35\x04\xF3\x34" == to_mflpt5(0.7071067812)
|
||||||
|
assert b"\x80\x35\x04\xF3\x33" == to_mflpt5(0.7071067811865476)
|
||||||
|
assert b"\x81\x35\x04\xF3\x34" == to_mflpt5(1.4142135624)
|
||||||
|
assert b"\x81\x35\x04\xF3\x33" == to_mflpt5(1.4142135623730951)
|
||||||
|
assert b"\x80\x80\x00\x00\x00" == to_mflpt5(-.5)
|
||||||
|
assert b"\x80\x31\x72\x17\xF8" == to_mflpt5(0.69314718061)
|
||||||
|
assert b"\x80\x31\x72\x17\xF7" == to_mflpt5(0.6931471805599453)
|
||||||
|
assert b"\x84\x20\x00\x00\x00" == to_mflpt5(10)
|
||||||
|
assert b"\x9E\x6E\x6B\x28\x00" == to_mflpt5(1000000000)
|
||||||
|
assert b"\x80\x00\x00\x00\x00" == to_mflpt5(.5)
|
||||||
|
assert b"\x81\x38\xAA\x3B\x29" == to_mflpt5(1.4426950408889634)
|
||||||
|
assert b"\x81\x49\x0F\xDA\xA2" == to_mflpt5(1.5707963267948966)
|
||||||
|
assert b"\x83\x49\x0F\xDA\xA2" == to_mflpt5(6.283185307179586)
|
||||||
|
assert b"\x7F\x00\x00\x00\x00" == to_mflpt5(.25)
|
||||||
|
|
||||||
|
|
||||||
|
def test_float_range():
|
||||||
|
assert b"\xff\x7f\xff\xff\xff" == to_mflpt5(FLOAT_MAX_POSITIVE)
|
||||||
|
assert b"\xff\xff\xff\xff\xff" == to_mflpt5(FLOAT_MAX_NEGATIVE)
|
||||||
|
with pytest.raises(OverflowError):
|
||||||
|
to_mflpt5(1.7014118346e+38)
|
||||||
|
with pytest.raises(OverflowError):
|
||||||
|
to_mflpt5(-1.7014118346e+38)
|
||||||
|
with pytest.raises(OverflowError):
|
||||||
|
to_mflpt5(1.7014118347e+38)
|
||||||
|
with pytest.raises(OverflowError):
|
||||||
|
to_mflpt5(-1.7014118347e+38)
|
||||||
|
assert b"\x03\x39\x1d\x15\x63" == to_mflpt5(1.7e-38)
|
||||||
|
assert b"\x00\x00\x00\x00\x00" == to_mflpt5(1.7e-39)
|
||||||
|
assert b"\x03\xb9\x1d\x15\x63" == to_mflpt5(-1.7e-38)
|
||||||
|
assert b"\x00\x00\x00\x00\x00" == to_mflpt5(-1.7e-39)
|
@ -1,9 +1,8 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from il65.datatypes import DataType, STRING_DATATYPES, FLOAT_MAX_POSITIVE, FLOAT_MAX_NEGATIVE, char_to_bytevalue
|
from il65.datatypes import DataType, STRING_DATATYPES, char_to_bytevalue
|
||||||
from il65.plyparse import coerce_constant_value, LiteralValue, Scope, SymbolName, VarDef
|
from il65.plyparse import coerce_constant_value, LiteralValue, Scope, SymbolName, VarDef
|
||||||
from il65.compile import ParseError
|
from il65.compile import ParseError
|
||||||
from il65.plylex import SourceRef
|
from il65.plylex import SourceRef
|
||||||
from il65.emit import to_hex, to_mflpt5
|
|
||||||
|
|
||||||
|
|
||||||
def test_datatypes():
|
def test_datatypes():
|
||||||
@ -31,63 +30,6 @@ def test_parseerror():
|
|||||||
assert str(p) == "filename:99:42 message"
|
assert str(p) == "filename:99:42 message"
|
||||||
|
|
||||||
|
|
||||||
def test_to_hex():
|
|
||||||
assert to_hex(0) == "0"
|
|
||||||
assert to_hex(1) == "1"
|
|
||||||
assert to_hex(10) == "10"
|
|
||||||
assert to_hex(15) == "15"
|
|
||||||
assert to_hex(16) == "$10"
|
|
||||||
assert to_hex(255) == "$ff"
|
|
||||||
assert to_hex(256) == "$0100"
|
|
||||||
assert to_hex(20060) == "$4e5c"
|
|
||||||
assert to_hex(65535) == "$ffff"
|
|
||||||
with pytest.raises(OverflowError):
|
|
||||||
to_hex(-1)
|
|
||||||
with pytest.raises(OverflowError):
|
|
||||||
to_hex(65536)
|
|
||||||
|
|
||||||
|
|
||||||
def test_float_to_mflpt5():
|
|
||||||
mflpt = to_mflpt5(1.0)
|
|
||||||
assert type(mflpt) is bytearray
|
|
||||||
assert b"\x00\x00\x00\x00\x00" == to_mflpt5(0)
|
|
||||||
assert b"\x82\x49\x0F\xDA\xA1" == to_mflpt5(3.141592653)
|
|
||||||
assert b"\x82\x49\x0F\xDA\xA2" == to_mflpt5(3.141592653589793)
|
|
||||||
assert b"\x90\x80\x00\x00\x00" == to_mflpt5(-32768)
|
|
||||||
assert b"\x81\x00\x00\x00\x00" == to_mflpt5(1)
|
|
||||||
assert b"\x80\x35\x04\xF3\x34" == to_mflpt5(0.7071067812)
|
|
||||||
assert b"\x80\x35\x04\xF3\x33" == to_mflpt5(0.7071067811865476)
|
|
||||||
assert b"\x81\x35\x04\xF3\x34" == to_mflpt5(1.4142135624)
|
|
||||||
assert b"\x81\x35\x04\xF3\x33" == to_mflpt5(1.4142135623730951)
|
|
||||||
assert b"\x80\x80\x00\x00\x00" == to_mflpt5(-.5)
|
|
||||||
assert b"\x80\x31\x72\x17\xF8" == to_mflpt5(0.69314718061)
|
|
||||||
assert b"\x80\x31\x72\x17\xF7" == to_mflpt5(0.6931471805599453)
|
|
||||||
assert b"\x84\x20\x00\x00\x00" == to_mflpt5(10)
|
|
||||||
assert b"\x9E\x6E\x6B\x28\x00" == to_mflpt5(1000000000)
|
|
||||||
assert b"\x80\x00\x00\x00\x00" == to_mflpt5(.5)
|
|
||||||
assert b"\x81\x38\xAA\x3B\x29" == to_mflpt5(1.4426950408889634)
|
|
||||||
assert b"\x81\x49\x0F\xDA\xA2" == to_mflpt5(1.5707963267948966)
|
|
||||||
assert b"\x83\x49\x0F\xDA\xA2" == to_mflpt5(6.283185307179586)
|
|
||||||
assert b"\x7F\x00\x00\x00\x00" == to_mflpt5(.25)
|
|
||||||
|
|
||||||
|
|
||||||
def test_float_range():
|
|
||||||
assert b"\xff\x7f\xff\xff\xff" == to_mflpt5(FLOAT_MAX_POSITIVE)
|
|
||||||
assert b"\xff\xff\xff\xff\xff" == to_mflpt5(FLOAT_MAX_NEGATIVE)
|
|
||||||
with pytest.raises(OverflowError):
|
|
||||||
to_mflpt5(1.7014118346e+38)
|
|
||||||
with pytest.raises(OverflowError):
|
|
||||||
to_mflpt5(-1.7014118346e+38)
|
|
||||||
with pytest.raises(OverflowError):
|
|
||||||
to_mflpt5(1.7014118347e+38)
|
|
||||||
with pytest.raises(OverflowError):
|
|
||||||
to_mflpt5(-1.7014118347e+38)
|
|
||||||
assert b"\x03\x39\x1d\x15\x63" == to_mflpt5(1.7e-38)
|
|
||||||
assert b"\x00\x00\x00\x00\x00" == to_mflpt5(1.7e-39)
|
|
||||||
assert b"\x03\xb9\x1d\x15\x63" == to_mflpt5(-1.7e-38)
|
|
||||||
assert b"\x00\x00\x00\x00\x00" == to_mflpt5(-1.7e-39)
|
|
||||||
|
|
||||||
|
|
||||||
def test_char_to_bytevalue():
|
def test_char_to_bytevalue():
|
||||||
assert char_to_bytevalue('a') == 65
|
assert char_to_bytevalue('a') == 65
|
||||||
assert char_to_bytevalue('\n') == 13
|
assert char_to_bytevalue('\n') == 13
|
||||||
|
@ -8,7 +8,7 @@ Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
|||||||
import enum
|
import enum
|
||||||
import struct
|
import struct
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from il65.emit import mflpt5_to_float, to_mflpt5
|
from il65.codegen.shared import mflpt5_to_float, to_mflpt5
|
||||||
|
|
||||||
|
|
||||||
class DataType(enum.IntEnum):
|
class DataType(enum.IntEnum):
|
||||||
|
18
tinyvm/vm.py
18
tinyvm/vm.py
@ -23,14 +23,12 @@ Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
|||||||
# or in one of the dynamic variables.
|
# or in one of the dynamic variables.
|
||||||
#
|
#
|
||||||
# I/O: either via programmed I/O routines:
|
# I/O: either via programmed I/O routines:
|
||||||
# write [byte/bytearray to text output/screen],
|
# write [byte/bytearray to text output/screen] : syscall_printstr / syscall_printchr,
|
||||||
# read [byte/bytearray from keyboard],
|
# read [byte/bytearray from keyboard] : syscall_input / syscall_getchr (both blocking)
|
||||||
# wait [till any input comes available], @todo
|
|
||||||
# check [if input is available) @todo
|
|
||||||
# or via memory-mapped I/O (text screen matrix, keyboard scan register)
|
# or via memory-mapped I/O (text screen matrix, keyboard scan register)
|
||||||
#
|
#
|
||||||
# CPU: stack based execution, no registers.
|
# CPU: single threaded, stack based execution,
|
||||||
# unlimited dynamic variables (v0, v1, ...) that have a value and a type.
|
# no registers, but unlimited dynamic variables (v0, v1, ...) that have a value and a type.
|
||||||
# types:
|
# types:
|
||||||
# 1-bit boolean,
|
# 1-bit boolean,
|
||||||
# 8-bit byte (singed and unsigned),
|
# 8-bit byte (singed and unsigned),
|
||||||
@ -41,9 +39,6 @@ Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
|||||||
# matrix (2-dimensional array) of bytes (signed and unsigned).
|
# matrix (2-dimensional array) of bytes (signed and unsigned).
|
||||||
# all of these can have the flag CONST as well which means they cannot be modified.
|
# all of these can have the flag CONST as well which means they cannot be modified.
|
||||||
#
|
#
|
||||||
# push (constant,
|
|
||||||
# mark, unwind to previous mark.
|
|
||||||
#
|
|
||||||
# CPU INSTRUCTIONS:
|
# CPU INSTRUCTIONS:
|
||||||
# stack manipulation mainly:
|
# stack manipulation mainly:
|
||||||
# nop
|
# nop
|
||||||
@ -53,12 +48,11 @@ Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
|||||||
# jump label
|
# jump label
|
||||||
# jump_if_true label, jump_if_false label
|
# jump_if_true label, jump_if_false label
|
||||||
# jump_if_status_XX label special system dependent status register conditional check such as carry bit or overflow bit)
|
# jump_if_status_XX label special system dependent status register conditional check such as carry bit or overflow bit)
|
||||||
|
# call function (arguments are on stack)
|
||||||
# return (return values on stack)
|
# return (return values on stack)
|
||||||
# syscall function (special system dependent implementation)
|
# syscall function (special system dependent implementation)
|
||||||
# call function (arguments are on stack)
|
|
||||||
# enter / exit (function call frame)
|
|
||||||
#
|
#
|
||||||
# TIMER INTERRUPT: triggered around each 1/60th of a second.
|
# TIMER 'INTERRUPT': triggered around each 1/60th of a second.
|
||||||
# executes on a DIFFERENT stack and with a different PROGRAM LIST,
|
# executes on a DIFFERENT stack and with a different PROGRAM LIST,
|
||||||
# but with access to ALL THE SAME DYNAMIC VARIABLES.
|
# but with access to ALL THE SAME DYNAMIC VARIABLES.
|
||||||
# This suspends the main program until the timer program RETURNs!
|
# This suspends the main program until the timer program RETURNs!
|
||||||
|
Loading…
x
Reference in New Issue
Block a user