subroutines and assignment changes

This commit is contained in:
Irmen de Jong 2017-12-25 00:15:04 +01:00
parent 63aa3cae8c
commit 4025d44b74
10 changed files with 253 additions and 207 deletions

View File

@ -8,7 +8,7 @@ License: GNU GPL 3.0, see LICENSE
import ast
from typing import Union, Optional
from .symbols import FLOAT_MAX_POSITIVE, FLOAT_MAX_NEGATIVE, SourceRef, SymbolTable, SymbolError, DataType, PrimitiveType
from .symbols import FLOAT_MAX_POSITIVE, FLOAT_MAX_NEGATIVE, SourceRef, SymbolTable, SymbolError, PrimitiveType
class ParseError(Exception):
@ -191,10 +191,3 @@ class ExpressionTransformer(EvaluatingTransformer):
else:
raise self.error("invalid MatMult/Pointer node in AST")
return node
if __name__ == "__main__":
symbols = SymbolTable("<root>", None, None)
symbols.define_variable("derp", SourceRef("<source>", 1), DataType.BYTE, address=2345)
result = parse_expr_as_primitive("2+#derp", symbols, None, SourceRef("<source>", 1))
print("EXPRESSION RESULT:", result)

View File

@ -634,7 +634,31 @@ class CodeGenerator:
self.p("\t\tst{:s} {}".format(r_register[0].lower(), lv_string))
self.p("\t\tst{:s} {}+1".format(r_register[1].lower(), lv_string))
elif lv.datatype == DataType.FLOAT:
raise CodeError("assigning register to float not yet supported") # @todo support float=reg
# assigning a register to a float requires ROM routines
if r_register in REGISTER_WORDS:
raise CodeError("cannot yet assign register pair to float", r_register) # XXX reg pair -> float
elif r_register in "AXY":
def do_rom_calls():
self.p("\t\tjsr c64.FREADUY") # ubyte Y -> fac1
self.p("\t\tldx #<" + lv_string)
self.p("\t\tldy #>" + lv_string)
self.p("\t\tjsr c64.FTOMEMXY") # fac1 -> memory XY
if r_register == "A":
with self.preserving_registers({'A', 'X', 'Y'}):
self.p("\t\ttay")
do_rom_calls()
elif r_register == "X":
with self.preserving_registers({'A', 'X', 'Y'}):
self.p("\t\ttxa")
self.p("\t\ttay")
do_rom_calls()
elif r_register == "Y":
with self.preserving_registers({'A', 'X', 'Y'}):
do_rom_calls()
else:
raise CodeError("invalid register to assign to float", r_register)
else:
raise CodeError("invalid lvalue type", lv.datatype)
@ -803,7 +827,7 @@ class CodeGenerator:
else:
raise CodeError("can only assign a byte or word to a word", str(rvalue))
else:
raise CodeError("can only assign memory to a memory mapped byte or word value for now "
raise CodeError("can only assign memory to a memory mapped value for now "
"(if you need other types, can't you use a var?)", str(rvalue))
def generate_assign_char_to_memory(self, lv: ParseResult.MemMappedValue, char_str: str) -> None:

View File

@ -99,6 +99,20 @@ class ParseResult:
def __str__(self):
return "<IndirectValue {} itype={} name={}>".format(self.value, self.datatype, self.name)
def __hash__(self):
return hash((self.datatype, self.name, self.value))
def __eq__(self, other: Any) -> bool:
if not isinstance(other, ParseResult.IndirectValue):
return NotImplemented
elif self is other:
return True
else:
vvo = getattr(other.value, "value", getattr(other.value, "address", None))
vvs = getattr(self.value, "value", getattr(self.value, "address", None))
return (other.datatype, other.name, other.value.name, other.value.datatype, other.value.constant, vvo) ==\
(self.datatype, self.name, self.value.name, self.value.datatype, self.value.constant, vvs)
def assignable_from(self, other: 'ParseResult.Value') -> Tuple[bool, str]:
if self.constant:
return False, "cannot assign to a constant"
@ -151,7 +165,7 @@ class ParseResult:
elif self is other:
return True
else:
return other.datatype == self.datatype and other.value == self.value and other.name == self.name
return (other.datatype, other.value, other.name) == (self.datatype, self.value, self.name)
def __str__(self):
return "<IntegerValue {} name={}>".format(self.value, self.name)
@ -173,7 +187,7 @@ class ParseResult:
elif self is other:
return True
else:
return other.datatype == self.datatype and other.value == self.value and other.name == self.name
return (other.datatype, other.value, other.name) == (self.datatype, self.value, self.name)
def __str__(self):
return "<FloatValue {} name={}>".format(self.value, self.name)
@ -184,7 +198,7 @@ class ParseResult:
self.value = value
def __hash__(self):
return hash((self.datatype, self.value, self.name))
return hash((self.datatype, self.value, self.name, self.constant))
def __eq__(self, other: Any) -> bool:
if not isinstance(other, ParseResult.StringValue):
@ -192,7 +206,7 @@ class ParseResult:
elif self is other:
return True
else:
return other.datatype == self.datatype and other.value == self.value and other.name == self.name
return (other.datatype, other.value, other.name, other.constant) == (self.datatype, self.value, self.name, self.constant)
def __str__(self):
return "<StringValue {!r:s} name={} constant={}>".format(self.value, self.name, self.constant)
@ -213,7 +227,7 @@ class ParseResult:
elif self is other:
return True
else:
return other.datatype == self.datatype and other.register == self.register and other.name == self.name
return (other.datatype, other.register, other.name) == (self.datatype, self.register, self.name)
def __str__(self):
return "<RegisterValue {:s} type {:s} name={}>".format(self.register, self.datatype, self.name)
@ -271,7 +285,7 @@ class ParseResult:
assert address is None or type(address) is int
def __hash__(self):
return hash((self.datatype, self.address, self.length, self.name))
return hash((self.datatype, self.address, self.length, self.name, self.constant))
def __eq__(self, other: Any) -> bool:
if not isinstance(other, ParseResult.MemMappedValue):
@ -279,8 +293,8 @@ class ParseResult:
elif self is other:
return True
else:
return other.datatype == self.datatype and other.address == self.address and \
other.length == self.length and other.name == self.name
return (other.datatype, other.address, other.length, other.name, other.constant) ==\
(self.datatype, self.address, self.length, self.name, self.constant)
def __str__(self):
addr = "" if self.address is None else "${:04x}".format(self.address)
@ -365,6 +379,10 @@ class ParseResult:
self.right.name = stringvar_name
self._immediate_string_vars[self.right.value] = (cur_block.name, stringvar_name)
def remove_identity_assigns(self) -> None:
remaining_leftvalues = [lv for lv in self.leftvalues if lv != self.right]
self.leftvalues = remaining_leftvalues
class ReturnStmt(_AstNode):
def __init__(self, a: Optional['ParseResult.Value']=None,
x: Optional['ParseResult.Value']=None,
@ -530,12 +548,24 @@ class Parser:
raise self.PError("A block named 'main' should be defined for the program's entry point 'start'")
def _parse_2(self) -> None:
# parsing pass 2
# parsing pass 2 (not done during preprocessing!)
self.cur_block = None
self.sourceref.line = -1
self.sourceref.column = 0
for block in self.result.blocks:
self.cur_block = block
# remove identity assignments
have_removed_stmts = False
for index, stmt in enumerate(list(block.statements)):
if isinstance(stmt, ParseResult.AssignmentStmt):
stmt.remove_identity_assigns()
if not stmt.leftvalues:
print("warning: {:s}:{:d}: removed identity assignment".format(self.sourceref.file, stmt.lineno))
have_removed_stmts = True
block.statements[index] = None
if have_removed_stmts:
# remove the Nones
block.statements = [s for s in block.statements if s is not None]
# create parameter loads for calls
for index, stmt in enumerate(list(block.statements)):
if isinstance(stmt, ParseResult.CallStmt):
@ -719,7 +749,6 @@ class Parser:
# first line contains block header "~ [name] [addr]" followed by a '{'
self._parse_comments()
line = self.next_line()
block_def_lineno = self.sourceref.line
line = line.lstrip()
if not line.startswith("~"):
raise self.PError("expected '~' (block)")
@ -792,7 +821,7 @@ class Parser:
self.parse_const_def(line)
elif line.startswith(("memory ", "memory\t")):
self.parse_memory_def(line, is_zp_block)
elif line.startswith(("subx ", "subx\t")):
elif line.startswith(("sub ", "sub\t")):
if is_zp_block:
raise self.PError("ZP block cannot contain subroutines")
self.parse_subx_def(line)
@ -814,7 +843,7 @@ class Parser:
raise self.PError("ZP block cannot contain code labels")
self.parse_label(line)
else:
raise self.PError("missing } to close block from line " + str(self.cur_block.sourceref.line))
raise self.PError("invalid statement in block")
def parse_label(self, line: str) -> None:
label_line = line.split(maxsplit=1)
@ -855,13 +884,13 @@ class Parser:
raise self.PError(str(x)) from x
def parse_subx_def(self, line: str) -> None:
match = re.match(r"^subx\s+(?P<name>\w+)\s+"
match = re.match(r"^sub\s+(?P<name>\w+)\s+"
r"\((?P<parameters>[\w\s:,]*)\)"
r"\s*->\s*"
r"\((?P<results>[\w\s?,]*)\)\s*"
r"(?P<decltype>\s+=\s+(?P<address>\S*)|{)\s*$", line)
if not match:
raise self.PError("invalid subx declaration")
raise self.PError("invalid sub declaration")
code_decl = match.group("decltype") == "{"
name, parameterlist, resultlist, address_str = \
match.group("name"), match.group("parameters"), match.group("results"), match.group("address")
@ -889,7 +918,7 @@ class Parser:
if line == "}":
# subroutine end
break
if line.startswith(("subx ", "subx\t")):
if line.startswith(("sub ", "sub\t")):
raise self.PError("cannot nest subroutines")
elif line.startswith(("asm ", "asm\t")):
self.prev_line()
@ -899,7 +928,7 @@ class Parser:
elif line:
self.parse_label(line)
else:
raise self.PError("missing } to close subroutine from line " + str(subroutine_block.sourceref.line))
raise self.PError("invalid statement in subroutine")
self.cur_block = current_block
self.cur_block.sourceref = subroutine_block.sourceref
else:
@ -993,7 +1022,7 @@ class Parser:
target = None # type: ParseResult.Value
if targetstr[0] == '[' and targetstr[-1] == ']':
# indirect call to address in register pair or memory location
targetstr, target = self.parse_indirect_value(targetstr)
targetstr, target = self.parse_indirect_value(targetstr, True)
if target.datatype != DataType.WORD:
raise self.PError("invalid call target (should contain 16-bit)")
else:
@ -1005,7 +1034,7 @@ class Parser:
and not isinstance(target.value, (ParseResult.IntegerValue, ParseResult.RegisterValue, ParseResult.MemMappedValue)):
raise self.PError("cannot call that type of indirect symbol")
address = target.address if isinstance(target, ParseResult.MemMappedValue) else None
_, symbol = self.cur_block.lookup(targetstr)
_, symbol = self.lookup(targetstr)
if isinstance(symbol, SubroutineDef):
# verify subroutine arguments
if len(arguments or []) != len(symbol.parameters):
@ -1050,7 +1079,7 @@ class Parser:
rhs = parts.pop()
l_values = [self.parse_expression(part) for part in parts]
if any(isinstance(lv, ParseResult.IntegerValue) for lv in l_values):
raise self.PError("can't have a constant as assignment target, did you mean [name] instead?")
raise self.PError("can't have a constant as assignment target, perhaps you wanted indirection [...] instead?")
r_value = self.parse_expression(rhs)
for lv in l_values:
assignable, reason = lv.assignable_from(r_value)
@ -1220,7 +1249,7 @@ class Parser:
else:
raise self.PError("invalid value '" + text + "'")
def parse_indirect_value(self, text: str) -> Tuple[str, ParseResult.IndirectValue]:
def parse_indirect_value(self, text: str, allow_mmapped_for_call: bool=False) -> Tuple[str, ParseResult.IndirectValue]:
indirect = text[1:-1].strip()
indirect2, sep, typestr = indirect.rpartition('.')
type_modifier = None
@ -1240,8 +1269,11 @@ class Parser:
if type_modifier not in (DataType.BYTE, DataType.WORD, DataType.FLOAT):
raise self.PError("invalid type modifier for the value's datatype")
elif isinstance(expr, ParseResult.MemMappedValue):
if type_modifier and expr.datatype != type_modifier:
raise self.PError("invalid type modifier for the value's datatype, must be " + expr.datatype.name)
if allow_mmapped_for_call:
if type_modifier and expr.datatype != type_modifier:
raise self.PError("invalid type modifier for the value's datatype, must be " + expr.datatype.name)
else:
raise self.PError("use variable directly instead of using indirect addressing")
return indirect, ParseResult.IndirectValue(expr, type_modifier)
def is_identifier(self, name: str) -> bool:
@ -1367,10 +1399,10 @@ class Optimizer:
if len(lvalues) != len(stmt.leftvalues):
print("{:s}:{:d}: removed duplicate assignment targets".format(block.sourceref.file, stmt.lineno))
# change order: first registers, then zp addresses, then non-zp addresses, then the rest (if any)
stmt.leftvalues = list(sorted(lvalues, key=value_sortkey))
stmt.leftvalues = list(sorted(lvalues, key=_value_sortkey))
def value_sortkey(value: ParseResult.Value) -> int:
def _value_sortkey(value: ParseResult.Value) -> int:
if isinstance(value, ParseResult.RegisterValue):
num = 0
for char in value.register:
@ -1378,18 +1410,11 @@ def value_sortkey(value: ParseResult.Value) -> int:
num += ord(char)
return num
elif isinstance(value, ParseResult.MemMappedValue):
if value.address is None:
return 99999999
if value.address < 0x100:
return 10000 + value.address
else:
return 20000 + value.address
else:
return 99999999
if __name__ == "__main__":
p = Parser("readme.txt", outputdir="output")
p.cur_block = ParseResult.Block("test", SourceRef("testfile", 1), None)
p.parse_subx_def("subx SUBNAME (A, test2:XY, X) -> (A?, X) = $c000")
sub = list(p.cur_block.symbols.iter_subroutines())[0]
import pprint
pprint.pprint(vars(sub))

View File

@ -405,6 +405,7 @@ class SymbolTable:
self.eval_dict = None
def merge_roots(self, other_root: 'SymbolTable') -> None:
assert self.parent is None and other_root.parent is None
for name, thing in other_root.symbols.items():
if isinstance(thing, SymbolTable):
try:
@ -428,7 +429,7 @@ class SymbolTable:
def print_symbols(symbols: 'SymbolTable', level: int) -> None:
indent = '\t' * level
print("\n" + indent + "BLOCK:", symbols.name)
for name, s in sorted(symbols.symbols.items(), key=lambda x: getattr(x[1], "sourceref", ("", 0))):
for name, s in sorted(symbols.symbols.items(), key=lambda x: str(getattr(x[1], "sourceref", ""))):
if isinstance(s, SymbolTable):
print_symbols(s, level + 1)
elif isinstance(s, SubroutineDef):

View File

@ -93,68 +93,68 @@ output raw
; note: for subtraction and division, the left operand is in fac2, the right operand in fac1.
; checked functions below:
subx MOVFM (mflpt: AY) -> (A?, Y?) = $bba2 ; load mflpt value from memory in A/Y into fac1
subx FREADMEM () -> (A?, Y?) = $bba6 ; load mflpt value from memory in $22/$23 into fac1
subx CONUPK (mflpt: AY) -> (A?, Y?) = $ba8c ; load mflpt value from memory in A/Y into fac2
subx FAREADMEM () -> (A?, Y?) = $ba90 ; load mflpt value from memory in $22/$23 into fac2
subx MOVFA () -> (A?, X?) = $bbfc ; copy fac2 to fac1
subx MOVAF () -> (A?, X?) = $bc0c ; copy fac1 to fac2 (rounded)
subx MOVEF () -> (A?, X?) = $bc0f ; copy fac1 to fac2
subx FTOMEMXY (mflpt: XY) -> (A?, Y?) = $bbd4 ; store fac1 to memory X/Y as 5-byte mflpt
subx FTOSWORDYA () -> (Y, A, X?) = $b1aa ; fac1-> signed word in Y/A (might throw ILLEGAL QUANTITY)
sub MOVFM (mflpt: AY) -> (A?, Y?) = $bba2 ; load mflpt value from memory in A/Y into fac1
sub FREADMEM () -> (A?, Y?) = $bba6 ; load mflpt value from memory in $22/$23 into fac1
sub CONUPK (mflpt: AY) -> (A?, Y?) = $ba8c ; load mflpt value from memory in A/Y into fac2
sub FAREADMEM () -> (A?, Y?) = $ba90 ; load mflpt value from memory in $22/$23 into fac2
sub MOVFA () -> (A?, X?) = $bbfc ; copy fac2 to fac1
sub MOVAF () -> (A?, X?) = $bc0c ; copy fac1 to fac2 (rounded)
sub MOVEF () -> (A?, X?) = $bc0f ; copy fac1 to fac2
sub FTOMEMXY (mflpt: XY) -> (A?, Y?) = $bbd4 ; store fac1 to memory X/Y as 5-byte mflpt
sub FTOSWORDYA () -> (Y, A, X?) = $b1aa ; fac1-> signed word in Y/A (might throw ILLEGAL QUANTITY)
; use c64util.FTOSWRDAY to get A/Y output (lo/hi switched to normal order)
subx GETADR () -> (Y, A, X?) = $b7f7 ; fac1 -> unsigned word in Y/A (might throw ILLEGAL QUANTITY)
sub GETADR () -> (Y, A, X?) = $b7f7 ; fac1 -> unsigned word in Y/A (might throw ILLEGAL QUANTITY)
; (result also in $14/15) use c64util.GETADRAY to get A/Y output (lo/hi switched to normal order)
subx QINT () -> (A?, X?, Y?) = $bc9b ; fac1 -> 4-byte signed integer in 98-101 ($62-$65), with the MSB FIRST.
subx AYINT () -> (A?, X?, Y?) = $b1bf ; fac1-> signed word in 100-101 ($64-$65) MSB FIRST. (might throw ILLEGAL QUANTITY)
subx GIVAYF (lo: Y, hi: A) -> (A?, X?, Y?) = $b391 ; signed word in Y/A -> float in fac1
sub QINT () -> (A?, X?, Y?) = $bc9b ; fac1 -> 4-byte signed integer in 98-101 ($62-$65), with the MSB FIRST.
sub AYINT () -> (A?, X?, Y?) = $b1bf ; fac1-> signed word in 100-101 ($64-$65) MSB FIRST. (might throw ILLEGAL QUANTITY)
sub GIVAYF (lo: Y, hi: A) -> (A?, X?, Y?) = $b391 ; signed word in Y/A -> float in fac1
; use c64util.GIVAYFAY to use A/Y input (lo/hi switched to normal order)
; there is also c64util.GIVUAYF - unsigned word in A/Y (lo/hi) to fac1
; there is also c64util.FREADS32 that reads from 98-101 ($62-$65) MSB FIRST
; there is also c64util.FREADUS32 that reads from 98-101 ($62-$65) MSB FIRST
; there is also c64util.FREADS24AXY that reads signed int24 into fac1 from A/X/Y (lo/mid/hi bytes)
subx FREADUY (ubyte: Y) -> (A?, X?, Y?) = $b3a2 ; 8 bit unsigned Y -> float in fac1
subx FREADSA (sbyte: A) -> (A?, X?, Y?) = $bc3c ; 8 bit signed A -> float in fac1
subx FREADSTR (len: A) -> (A?, X?, Y?) = $b7b5 ; str -> fac1, $22/23 must point to string, A=string length
subx FPRINTLN () -> (A?, X?, Y?) = $aabc ; print string of fac1, on one line (= with newline)
subx FOUT () -> (AY, X?) = $bddd ; fac1 -> string, address returned in AY ($0100)
sub FREADUY (ubyte: Y) -> (A?, X?, Y?) = $b3a2 ; 8 bit unsigned Y -> float in fac1
sub FREADSA (sbyte: A) -> (A?, X?, Y?) = $bc3c ; 8 bit signed A -> float in fac1
sub FREADSTR (len: A) -> (A?, X?, Y?) = $b7b5 ; str -> fac1, $22/23 must point to string, A=string length
sub FPRINTLN () -> (A?, X?, Y?) = $aabc ; print string of fac1, on one line (= with newline)
sub FOUT () -> (AY, X?) = $bddd ; fac1 -> string, address returned in AY ($0100)
subx FADDH () -> (A?, X?, Y?) = $b849 ; fac1 += 0.5, for rounding- call this before INT
subx MUL10 () -> (A?, X?, Y?) = $bae2 ; fac1 *= 10
subx DIV10 () -> (A?, X?, Y?) = $bafe ; fac1 /= 10 , CAUTION: result is always positive!
subx FCOMP (mflpt: AY) -> (A, X?, Y?) = $bc5b ; A = compare fac1 to mflpt in A/Y, 0=equal 1=fac1 is greater, 255=fac1 is less than
sub FADDH () -> (A?, X?, Y?) = $b849 ; fac1 += 0.5, for rounding- call this before INT
sub MUL10 () -> (A?, X?, Y?) = $bae2 ; fac1 *= 10
sub DIV10 () -> (A?, X?, Y?) = $bafe ; fac1 /= 10 , CAUTION: result is always positive!
sub FCOMP (mflpt: AY) -> (A, X?, Y?) = $bc5b ; A = compare fac1 to mflpt in A/Y, 0=equal 1=fac1 is greater, 255=fac1 is less than
subx FADDT () -> (A?, X?, Y?) = $b86a ; fac1 += fac2
subx FADD (mflpt: AY) -> (A?, X?, Y?) = $b867 ; fac1 += mflpt value from A/Y
subx FSUBT () -> (A?, X?, Y?) = $b853 ; fac1 = fac2-fac1 mind the order of the operands
subx FSUB (mflpt: AY) -> (A?, X?, Y?) = $b850 ; fac1 = mflpt from A/Y - fac1
subx FMULTT () -> (A?, X?, Y?) = $ba2b ; fac1 *= fac2
subx FMULT (mflpt: AY) -> (A?, X?, Y?) = $ba28 ; fac1 *= mflpt value from A/Y
subx FDIVT () -> (A?, X?, Y?) = $bb12 ; fac1 = fac2/fac1 mind the order of the operands
subx FDIV (mflpt: AY) -> (A?, X?, Y?) = $bb0f ; fac1 = mflpt in A/Y / fac1
subx FPWRT () -> (A?, X?, Y?) = $bf7b ; fac1 = fac2 ** fac1
subx FPWR (mflpt: AY) -> (A?, X?, Y?) = $bf78 ; fac1 = fac2 ** mflpt from A/Y
sub FADDT () -> (A?, X?, Y?) = $b86a ; fac1 += fac2
sub FADD (mflpt: AY) -> (A?, X?, Y?) = $b867 ; fac1 += mflpt value from A/Y
sub FSUBT () -> (A?, X?, Y?) = $b853 ; fac1 = fac2-fac1 mind the order of the operands
sub FSUB (mflpt: AY) -> (A?, X?, Y?) = $b850 ; fac1 = mflpt from A/Y - fac1
sub FMULTT () -> (A?, X?, Y?) = $ba2b ; fac1 *= fac2
sub FMULT (mflpt: AY) -> (A?, X?, Y?) = $ba28 ; fac1 *= mflpt value from A/Y
sub FDIVT () -> (A?, X?, Y?) = $bb12 ; fac1 = fac2/fac1 mind the order of the operands
sub FDIV (mflpt: AY) -> (A?, X?, Y?) = $bb0f ; fac1 = mflpt in A/Y / fac1
sub FPWRT () -> (A?, X?, Y?) = $bf7b ; fac1 = fac2 ** fac1
sub FPWR (mflpt: AY) -> (A?, X?, Y?) = $bf78 ; fac1 = fac2 ** mflpt from A/Y
subx NOTOP () -> (A?, X?, Y?) = $aed4 ; fac1 = NOT(fac1)
subx INT () -> (A?, X?, Y?) = $bccc ; INT() truncates, use FADDH first to round instead of trunc
subx LOG () -> (A?, X?, Y?) = $b9ea ; fac1 = LN(fac1) (natural log)
subx SGN () -> (A?, X?, Y?) = $bc39 ; fac1 = SGN(fac1), result of SIGN (-1, 0 or 1)
subx SIGN () -> (A) = $bc2b ; SIGN(fac1) to A, $ff, $0, $1 for negative, zero, positive
subx ABS () -> () = $bc58 ; fac1 = ABS(fac1)
subx SQR () -> (A?, X?, Y?) = $bf71 ; fac1 = SQRT(fac1)
subx EXP () -> (A?, X?, Y?) = $bfed ; fac1 = EXP(fac1) (e ** fac1)
subx NEGOP () -> (A?) = $bfb4 ; switch the sign of fac1
subx RND () -> (A?, X?, Y?) = $e097 ; fac1 = RND()
subx COS () -> (A?, X?, Y?) = $e264 ; fac1 = COS(fac1)
subx SIN () -> (A?, X?, Y?) = $e26b ; fac1 = SIN(fac1)
subx TAN () -> (A?, X?, Y?) = $e2b4 ; fac1 = TAN(fac1)
subx ATN () -> (A?, X?, Y?) = $e30e ; fac1 = ATN(fac1)
sub NOTOP () -> (A?, X?, Y?) = $aed4 ; fac1 = NOT(fac1)
sub INT () -> (A?, X?, Y?) = $bccc ; INT() truncates, use FADDH first to round instead of trunc
sub LOG () -> (A?, X?, Y?) = $b9ea ; fac1 = LN(fac1) (natural log)
sub SGN () -> (A?, X?, Y?) = $bc39 ; fac1 = SGN(fac1), result of SIGN (-1, 0 or 1)
sub SIGN () -> (A) = $bc2b ; SIGN(fac1) to A, $ff, $0, $1 for negative, zero, positive
sub ABS () -> () = $bc58 ; fac1 = ABS(fac1)
sub SQR () -> (A?, X?, Y?) = $bf71 ; fac1 = SQRT(fac1)
sub EXP () -> (A?, X?, Y?) = $bfed ; fac1 = EXP(fac1) (e ** fac1)
sub NEGOP () -> (A?) = $bfb4 ; switch the sign of fac1
sub RND () -> (A?, X?, Y?) = $e097 ; fac1 = RND()
sub COS () -> (A?, X?, Y?) = $e264 ; fac1 = COS(fac1)
sub SIN () -> (A?, X?, Y?) = $e26b ; fac1 = SIN(fac1)
sub TAN () -> (A?, X?, Y?) = $e2b4 ; fac1 = TAN(fac1)
sub ATN () -> (A?, X?, Y?) = $e30e ; fac1 = ATN(fac1)
; ---- C64 basic routines ----
subx CLEARSCR () -> (A?, X?, Y?) = $E544 ; clear the screen
subx HOMECRSR () -> (A?, X?, Y?) = $E566 ; cursor to top left of screen
sub CLEARSCR () -> (A?, X?, Y?) = $E544 ; clear the screen
sub HOMECRSR () -> (A?, X?, Y?) = $E566 ; cursor to top left of screen
; ---- end of C64 basic routines ----
@ -163,45 +163,45 @@ subx HOMECRSR () -> (A?, X?, Y?) = $E566 ; cursor to top left of screen
; ---- C64 kernal routines ----
subx CINT () -> (A?, X?, Y?) = $FF81 ; (alias: SCINIT) initialize screen editor and video chip
subx IOINIT () -> (A?, X?) = $FF84 ; initialize I/O devices
subx RAMTAS () -> (A?, X?, Y?) = $FF87 ; initialize RAM, tape buffer, screen
subx RESTOR () -> () = $FF8A ; restore default I/O vectors
subx VECTOR (dir: SC, userptr: XY) -> (A?, Y?) = $FF8D ; read/set I/O vector table
subx SETMSG (value: A) -> () = $FF90 ; set Kernal message control flag
subx SECOND (address: A) -> (A?) = $FF93 ; (alias: LSTNSA) send secondary address after LISTEN
subx TKSA (address: A) -> (A?) = $FF96 ; (alias: TALKSA) send secondary address after TALK
subx MEMTOP (dir: SC, address: XY) -> (XY) = $FF99 ; read/set top of memory pointer
subx MEMBOT (dir: SC, address: XY) -> (XY) = $FF9C ; read/set bottom of memory pointer
subx SCNKEY () -> (A?, X?, Y?) = $FF9F ; scan the keyboard
subx SETTMO (timeout: A) -> () = $FFA2 ; set time-out flag for IEEE bus
subx ACPTR () -> (A) = $FFA5 ; (alias: IECIN) input byte from serial bus
subx CIOUT (byte: A) -> () = $FFA8 ; (alias: IECOUT) output byte to serial bus
subx UNTLK () -> (A?) = $FFAB ; command serial bus device to UNTALK
subx UNLSN () -> (A?) = $FFAE ; command serial bus device to UNLISTEN
subx LISTEN (device: A) -> (A?) = $FFB1 ; command serial bus device to LISTEN
subx TALK (device: A) -> (A?) = $FFB4 ; command serial bus device to TALK
subx READST () -> (A) = $FFB7 ; read I/O status word
subx SETLFS (logical: A, device: X, address: Y) -> () = $FFBA ; set logical file parameters
subx SETNAM (namelen: A, filename: XY) -> () = $FFBD ; set filename parameters
subx OPEN () -> (A?, X?, Y?) = $FFC0 ; (via 794 ($31A)) open a logical file
subx CLOSE (logical: A) -> (A?, X?, Y?) = $FFC3 ; (via 796 ($31C)) close a logical file
subx CHKIN (logical: X) -> (A?, X?) = $FFC6 ; (via 798 ($31E)) define an input channel
subx CHKOUT (logical: X) -> (A?, X?) = $FFC9 ; (via 800 ($320)) define an output channel
subx CLRCHN () -> (A?, X?) = $FFCC ; (via 802 ($322)) restore default devices
subx CHRIN () -> (A, Y?) = $FFCF ; (via 804 ($324)) input a character
subx CHROUT (char: A) -> () = $FFD2 ; (via 806 ($326)) output a character
subx LOAD (verify: A, address: XY) -> (SC, A, X, Y) = $FFD5 ; (via 816 ($330)) load from device
subx SAVE (zp_startaddr: A, endaddr: XY) -> (SC, A) = $FFD8 ; (via 818 ($332)) save to a device
subx SETTIM (low: A, middle: X, high: Y) -> () = $FFDB ; set the software clock
subx RDTIM () -> (A, X, Y) = $FFDE ; read the software clock
subx STOP () -> (SZ, SC, A?, X?) = $FFE1 ; (via 808 ($328)) check the STOP key
subx GETIN () -> (A, X?, Y?) = $FFE4 ; (via 810 ($32A)) get a character
subx CLALL () -> (A?, X?) = $FFE7 ; (via 812 ($32C)) close all files
subx UDTIM () -> (A?, X?) = $FFEA ; update the software clock
subx SCREEN () -> (X, Y) = $FFED ; read number of screen rows and columns
subx PLOT (dir: SC, col: X, row: Y) -> (X, Y) = $FFF0 ; read/set position of cursor on screen
subx IOBASE () -> (X, Y) = $FFF3 ; read base address of I/O devices
sub CINT () -> (A?, X?, Y?) = $FF81 ; (alias: SCINIT) initialize screen editor and video chip
sub IOINIT () -> (A?, X?) = $FF84 ; initialize I/O devices
sub RAMTAS () -> (A?, X?, Y?) = $FF87 ; initialize RAM, tape buffer, screen
sub RESTOR () -> () = $FF8A ; restore default I/O vectors
sub VECTOR (dir: SC, userptr: XY) -> (A?, Y?) = $FF8D ; read/set I/O vector table
sub SETMSG (value: A) -> () = $FF90 ; set Kernal message control flag
sub SECOND (address: A) -> (A?) = $FF93 ; (alias: LSTNSA) send secondary address after LISTEN
sub TKSA (address: A) -> (A?) = $FF96 ; (alias: TALKSA) send secondary address after TALK
sub MEMTOP (dir: SC, address: XY) -> (XY) = $FF99 ; read/set top of memory pointer
sub MEMBOT (dir: SC, address: XY) -> (XY) = $FF9C ; read/set bottom of memory pointer
sub SCNKEY () -> (A?, X?, Y?) = $FF9F ; scan the keyboard
sub SETTMO (timeout: A) -> () = $FFA2 ; set time-out flag for IEEE bus
sub ACPTR () -> (A) = $FFA5 ; (alias: IECIN) input byte from serial bus
sub CIOUT (byte: A) -> () = $FFA8 ; (alias: IECOUT) output byte to serial bus
sub UNTLK () -> (A?) = $FFAB ; command serial bus device to UNTALK
sub UNLSN () -> (A?) = $FFAE ; command serial bus device to UNLISTEN
sub LISTEN (device: A) -> (A?) = $FFB1 ; command serial bus device to LISTEN
sub TALK (device: A) -> (A?) = $FFB4 ; command serial bus device to TALK
sub READST () -> (A) = $FFB7 ; read I/O status word
sub SETLFS (logical: A, device: X, address: Y) -> () = $FFBA ; set logical file parameters
sub SETNAM (namelen: A, filename: XY) -> () = $FFBD ; set filename parameters
sub OPEN () -> (A?, X?, Y?) = $FFC0 ; (via 794 ($31A)) open a logical file
sub CLOSE (logical: A) -> (A?, X?, Y?) = $FFC3 ; (via 796 ($31C)) close a logical file
sub CHKIN (logical: X) -> (A?, X?) = $FFC6 ; (via 798 ($31E)) define an input channel
sub CHKOUT (logical: X) -> (A?, X?) = $FFC9 ; (via 800 ($320)) define an output channel
sub CLRCHN () -> (A?, X?) = $FFCC ; (via 802 ($322)) restore default devices
sub CHRIN () -> (A, Y?) = $FFCF ; (via 804 ($324)) input a character
sub CHROUT (char: A) -> () = $FFD2 ; (via 806 ($326)) output a character
sub LOAD (verify: A, address: XY) -> (SC, A, X, Y) = $FFD5 ; (via 816 ($330)) load from device
sub SAVE (zp_startaddr: A, endaddr: XY) -> (SC, A) = $FFD8 ; (via 818 ($332)) save to a device
sub SETTIM (low: A, middle: X, high: Y) -> () = $FFDB ; set the software clock
sub RDTIM () -> (A, X, Y) = $FFDE ; read the software clock
sub STOP () -> (SZ, SC, A?, X?) = $FFE1 ; (via 808 ($328)) check the STOP key
sub GETIN () -> (A, X?, Y?) = $FFE4 ; (via 810 ($32A)) get a character
sub CLALL () -> (A?, X?) = $FFE7 ; (via 812 ($32C)) close all files
sub UDTIM () -> (A?, X?) = $FFEA ; update the software clock
sub SCREEN () -> (X, Y) = $FFED ; read number of screen rows and columns
sub PLOT (dir: SC, col: X, row: Y) -> (X, Y) = $FFF0 ; read/set position of cursor on screen
sub IOBASE () -> (X, Y) = $FFF3 ; read base address of I/O devices
; ---- end of C64 kernal routines ----
@ -211,11 +211,10 @@ subx IOBASE () -> (X, Y) = $FFF3 ; read base addres
}
~ c64util {
; @todo use user-defined subroutines here to have param definitions
subx FREADS32 () -> (A?, X?, Y?) {
sub FREADS32 () -> (A?, X?, Y?) {
; ---- fac1 = signed int32 from $62-$65 big endian (MSB FIRST)
asm {
lda $62
@ -227,7 +226,7 @@ subx FREADS32 () -> (A?, X?, Y?) {
}
}
subx FREADUS32 () -> (A?, X?, Y?) {
sub FREADUS32 () -> (A?, X?, Y?) {
; ---- fac1 = uint32 from $62-$65 big endian (MSB FIRST)
asm {
sec
@ -237,7 +236,7 @@ subx FREADUS32 () -> (A?, X?, Y?) {
}
}
subx FREADS24AXY (lo: A, mid: X, hi: Y) -> (A?, X?, Y?) {
sub FREADS24AXY (lo: A, mid: X, hi: Y) -> (A?, X?, Y?) {
; ---- fac1 = signed int24 (A/X/Y contain lo/mid/hi bytes)
; note: there is no FREADU24AXY (unsigned), use FREADUS32 instead.
asm {
@ -254,7 +253,7 @@ subx FREADS24AXY (lo: A, mid: X, hi: Y) -> (A?, X?, Y?) {
}
}
subx GIVUAYF (uword: AY) -> (A?, X?, Y?) {
sub GIVUAYF (uword: AY) -> (A?, X?, Y?) {
; ---- unsigned 16 bit word in A/Y (lo/hi) to fac1
asm {
sty $62
@ -265,7 +264,7 @@ subx GIVUAYF (uword: AY) -> (A?, X?, Y?) {
}
}
subx GIVAYFAY (sword: AY) -> (A?, X?, Y?) {
sub GIVAYFAY (sword: AY) -> (A?, X?, Y?) {
; ---- signed 16 bit word in A/Y (lo/hi) to float in fac1
asm {
sta c64.SCRATCH_ZP1
@ -275,7 +274,7 @@ subx GIVAYFAY (sword: AY) -> (A?, X?, Y?) {
}
}
subx FTOSWRDAY () -> (A, Y, X?) {
sub FTOSWRDAY () -> (A, Y, X?) {
; ---- fac1 to signed word in A/Y
asm {
jsr c64.FTOSWORDYA ; note the inverse Y/A order
@ -286,7 +285,7 @@ subx FTOSWRDAY () -> (A, Y, X?) {
}
}
subx GETADRAY () -> (A, Y, X?) {
sub GETADRAY () -> (A, Y, X?) {
; ---- fac1 to unsigned word in A/Y
asm {
jsr c64.GETADR ; this uses the inverse order, Y/A
@ -297,7 +296,7 @@ subx GETADRAY () -> (A, Y, X?) {
}
}
subx print_string (address: XY) -> (A?, Y?) {
sub print_string (address: XY) -> (A?, Y?) {
; ---- print null terminated string from X/Y
asm {
stx c64.SCRATCH_ZP1
@ -312,7 +311,7 @@ subx print_string (address: XY) -> (A?, Y?) {
}
}
subx print_pstring (address: XY) -> (A?, X?, Y) {
sub print_pstring (address: XY) -> (A?, X?, Y) {
; ---- print pstring (length as first byte) from X/Y, returns str len in Y
asm {
stx c64.SCRATCH_ZP1
@ -330,7 +329,7 @@ subx print_pstring (address: XY) -> (A?, X?, Y) {
}
}
subx print_pimmediate () -> () {
sub print_pimmediate () -> () {
; ---- print pstring in memory immediately following the subroutine fast call instruction
; note that the clobbered registers (A,X,Y) are not listed ON PURPOSE
asm {
@ -358,7 +357,7 @@ subx print_pimmediate () -> () {
}
}
subx byte2decimal (ubyte: A) -> (Y, X, A) {
sub byte2decimal (ubyte: A) -> (Y, X, A) {
; ---- A to decimal string in Y/X/A (100s in Y, 10s in X, 1s in A)
asm {
ldy #$2f
@ -375,7 +374,7 @@ subx byte2decimal (ubyte: A) -> (Y, X, A) {
}
}
subx byte2hex (ubyte: A) -> (X, Y, A?) {
sub byte2hex (ubyte: A) -> (X, Y, A?) {
; ---- A to hex string in XY (first hex char in X, second hex char in Y)
asm {
pha
@ -399,7 +398,7 @@ hex_digits .text "0123456789abcdef" ; can probably be reused for other st
var .array(3) word2bcd_bcdbuff
subx word2bcd (address: XY) -> (A?, X?) {
sub word2bcd (address: XY) -> (A?, X?) {
; Convert an 16 bit binary value to BCD
;
; This function converts a 16 bit binary value in X/Y into a 24 bit BCD. It
@ -437,7 +436,7 @@ subx word2bcd (address: XY) -> (A?, X?) {
var .array(5) word2decimal_output
subx word2decimal (address: XY) -> (A?, X?, Y?) {
sub word2decimal (address: XY) -> (A?, X?, Y?) {
; ---- convert 16 bit word in X/Y into decimal string into memory 'word2decimal_output'
asm {
jsr word2bcd
@ -468,7 +467,7 @@ subx word2decimal (address: XY) -> (A?, X?, Y?) {
}
}
subx print_byte_decimal0 (ubyte: A) -> (A?, X?, Y?) {
sub print_byte_decimal0 (ubyte: A) -> (A?, X?, Y?) {
; ---- print the byte in A in decimal form, with left padding 0s (3 positions total)
asm {
jsr byte2decimal
@ -482,7 +481,7 @@ subx print_byte_decimal0 (ubyte: A) -> (A?, X?, Y?) {
}
}
subx print_byte_decimal (ubyte: A) -> (A?, X?, Y?) {
sub print_byte_decimal (ubyte: A) -> (A?, X?, Y?) {
; ---- print the byte in A in decimal form, without left padding 0s
asm {
jsr byte2decimal
@ -500,7 +499,7 @@ subx print_byte_decimal (ubyte: A) -> (A?, X?, Y?) {
}
}
subx print_byte_hex (ubyte: A) -> (A?, X?, Y?) {
sub print_byte_hex (ubyte: A) -> (A?, X?, Y?) {
; ---- print the byte in A in hex form
asm {
jsr byte2hex
@ -512,7 +511,7 @@ subx print_byte_hex (ubyte: A) -> (A?, X?, Y?) {
}
subx print_word_decimal0 (address: XY) -> (A?, X?, Y?) {
sub print_word_decimal0 (address: XY) -> (A?, X?, Y?) {
; ---- print the word in X/Y in decimal form, with left padding 0s (5 positions total)
asm {
jsr word2decimal
@ -530,7 +529,7 @@ subx print_word_decimal0 (address: XY) -> (A?, X?, Y?) {
}
subx print_word_decimal (address: XY) -> (A?, X? Y?) {
sub print_word_decimal (address: XY) -> (A?, X? Y?) {
; ---- print the word in X/Y in decimal form, without left padding 0s
asm {
jsr word2decimal

View File

@ -154,9 +154,12 @@ Expressions can contain function calls to the math library (sin, cos, etc) and y
all builtin functions (max, avg, min, sum etc). They can also reference idendifiers defined elsewhere in your code,
if this makes sense.
The syntax "[address]" means: the contents of the memory at address.
The syntax "[address]" means: the contents of the memory at address, or "indirect addressing".
By default, if not otherwise known, a single byte is assumed. You can add the ".byte" or ".word" or ".float" suffix
to make it clear what data type the address points to.
This addressing mode is only supported for constant (integer) addresses and not for variable types,
unless it is part of a subroutine call statement. For an indirect goto call, the 6502 CPU has a special opcode
(JMP indirect) and an indirect subroutine call (JSR indirect) is synthesized using a couple of instructions.
Everything after a semicolon ';' is a comment and is ignored, however the comment (if it is the only thing
on the line) is copied into the resulting assembly source code.
@ -316,40 +319,44 @@ MEMORY BLOCK OPERATIONS:
- strings: identical operations as on lists.
these call (or emit inline) optimized pieces of assembly code, so they run as fast as possible
these should call (or emit inline) optimized pieces of assembly code, so they run as fast as possible
SUBROUTINES DEFINITIONS
-----------------------
External subroutines for instance defined in ROM, can be defined using the 'subx' statement.
Subroutines are parts of the code that can be repeatedly invoked using a subroutine call from elsewhere.
Their definition, using the sub statement, includes the specification of the required input- and output parameters.
For now, only register based parameters are supported (A, X, Y and paired registers, and the carry status bit SC as a special).
The syntax is:
subx <identifier> ([proc_parameters]) -> ([proc_results]) <address>
sub <identifier> ([proc_parameters]) -> ([proc_results]) {
... statements ...
}
proc_parameters = sequence of "<parametername>:<register>" pairs that specify what the input parameters are
proc_results = sequence of <register> names that specify in which register(s) the output is returned
if the name ends with a '?', that means the register doesn't contain a real return value but
is clobbered in the process so the original value it had before calling the sub is no longer valid.
example: "subx CLOSE (logical: A) -> (A?, X?, Y?) $FFC3"
proc_parameters = comma separated list of "<parametername>:<register>" pairs specifying the input parameters
proc_results = comma separated list of <register> names specifying in which register(s) the output is returned.
If the register name ends with a '?', that means the register doesn't contain a real return value but
is clobbered in the process so the original value it had before calling the sub is no longer valid.
This is not immediately useful for your own code, but the compiler needs this information to
emit the correct assembly code to preserve the cpu registers if needed when the call is made.
REGISTER PRESERVATION BLOCK: @todo (no)preserve
Subroutines that are pre-defined on a specific memory location (usually routines from ROM),
can also be defined using the 'sub' statement. But in this case you don't supply a block with statements,
but instead assign a memory address to it:
preserve [regs] { .... } adds register preservation around the containing code default = all 3 regs, or specify which.
nopreserve [regs] { .... } removes register preservation on all statements in the block that would otherwise have it.
sub <identifier> ([proc_parameters]) -> ([proc_results]) = <address>
@todo document user defined subroutines
example: "sub CLOSE (logical: A) -> (A?, X?, Y?) = $FFC3"
SUBROUTINE CALLS
----------------
You call a subroutine like this:
subroutinename[!] ( [arguments...] )
subroutinename_or_address [!] ( [arguments...] )
Normally, the registers are preserved when calling the subroutine and restored on return.
If you add a '!' after the name, no register preserving is done and the call essentially
@ -363,9 +370,16 @@ Unlike gotos in other languages, here it take arguments as well, because it
essentially is the same as calling a subroutine and only doing something different when it's finished.
@todo support call non-register args (variable parameter passing)
@todo support call return values (so that you can assign these to other variables, and allows the line to be a full expression)
@todo support assigning call return values (so that you can assign these to other variables, and allows the subroutine call be an actual expression)
REGISTER PRESERVATION BLOCK: @todo (no)preserve
----------------------------
preserve [regs] { .... } adds register preservation around the containing code default = all 3 regs, or specify which.
nopreserve [regs] { .... } removes register preservation on all statements in the block that would otherwise have it.
@todo BITMAP DEFINITIONS:

View File

@ -15,8 +15,8 @@
const .float constf = 3.4556677
const .text constt = "derp"
subx sub1 () -> (X?) = $ffdd
subx sub2 (A) -> (Y?) = $eecc
sub sub1 () -> (X?) = $ffdd
sub sub2 (A) -> (Y?) = $eecc
bar

View File

@ -88,7 +88,7 @@ clobberzp
const .byte cbyte2 = 1
const .byte cbyte3 = '@'
const .byte cbyte4 = true
const .word cbyte6 = false
const .word cword1 = false
const .word cword2 = $1234
const .word cword5 = 9876.5432
const cfloat1 = 1.2345
@ -134,6 +134,10 @@ start
; --- immediate primitive value assignments ----
A = [$99]
A = [$aabb]
A = $99
A = [cbyte3]
A = 0
A = '@'
A = 1.2345
@ -147,10 +151,6 @@ start
A = cbyte3
A = membyte2
A = uninitbyte1
;A = [membyte2] ; @todo error, invalid rvalue, use membyte without indirect?
;A = [membyte2.byte] ; @todo error, "
;A = [cbyte3] ; @todo error invalid rvalue
;A = [initbytea0] ; @todo error, invalid rvalue, use initbytea0 without indirect?
XY = 0
@ -162,7 +162,8 @@ start
XY = false
XY = text
XY = cbyte3
XY = cword2
XY = [cbyte3]
XY = [cword2]
XY = uninitbyte1
XY = "text-immediate"
AY = "text-immediate"
@ -172,12 +173,8 @@ start
AX = ""
AX = XY
AX = Y
XY = [membyte2] ; @todo indirection error?
XY = [membyte2.byte] ; @todo indirection error?
XY = membyte2
XY = #membyte2
XY = [memword1] ; @todo indirection error?
XY = [memword1.word] ; @todo indirection error?
XY = memword1
XY = sin
XY = #sin
@ -190,9 +187,9 @@ start
[$c000] = false
[$c000] = cbyte3
[$c000] = uninitbyte1
[$c000] = [membyte2] ; @todo indirection error?
[$c000] = [membyte2.byte] ; @todo indirection error?
[$c000] = membyte2
[$c000] = cbyte2
[$c000] = [cword2]
[$c000.word] = A
[$c000.word] = AX
@ -203,12 +200,9 @@ start
[$c000.word] = "text"
[$c000.word] = ""
[$c000.word] = uninitbyte1
[$c000.word] = [membyte2] ; @todo indirection error?
[$c000.word] = [membyte2.byte] ; @todo indirection error?
[$c000.word] = membyte2
[$c000.word] = #membyte2
[$c000.word] = [memword1] ; @todo indirection error?
[$c000.word] = [memword1.word] ; @todo indirection error?
[$c000.word] = [cword2]
[$c000.word] = memword1
[$c000.float] = 65535
[$c000.float] = 456.66
@ -268,10 +262,6 @@ start
membyte1 = 22
memword1 = 2233
memfloat = 3.4567
;[membyte1] = 33 ; @todo error, invalid lvalue, use without []
;[memword1] = 4444 ; @todo error ^
;[memword1] = [AX] ; @todo error, only address allowed in []
;[memfloat] = 5.5566 ; @todo error ^
memword1 = sin
memword1 = #sin
@ -281,13 +271,17 @@ start
memfloat = cbyte3
memfloat = cword2
; @todo float assignments that require ROM functions:
; @todo float assignments that require ROM functions or shims:
; memfloat = Y
; memfloat = XY
; uninitfloat = Y
; uninitfloat = XY
; initfloat2 = Y
; initfloat2 = XY
; initfloat2 = initbyte2
; initfloat2 = initword2
; initfloat1 = uninitfloat
; initfloat1 = initfloat2
return
}

View File

@ -48,22 +48,19 @@ start
var .float flt_half_pi = 1.5707963267948966
var .float flt_double_pi = 6.283185307179586
var .float flt_point25 = .25
var .float my_float
memory .word some_address = $ccdd
memory .byte some_addressb = $ccee
var .byte bytevar = $cc
var .word wordvar = $cdef
start
; assign some float values to the memory
AY = #flt_pi
[some_address] = # flt_pi
[some_address] = # flt_pi
[some_address] = # flt_pi
[some_address] = 4123.2342342222
[some_address] = 4123.2342342222
[some_address] = 4123.2342342222
[some_address.word] = #flt_pi
[some_address.word] = #flt_pi
[some_address.word] = #flt_pi
some_address = # flt_pi
some_address = 4123.2342342222
[$c000.word] = # flt_pi
; print some floating points from source and compare them with ROM
@ -139,5 +136,4 @@ start
c64.FPRINTLN!()
return
}

View File

@ -73,7 +73,7 @@ _loop block2.zpw1 ++
X --
Y--
[$d020]--
[block2.zpw2] = 99
block2.zpw2 = 99
fidget.subroutine()
goto _loop
return 155,2,%00000101 ; will end up in A, X, Y
@ -85,9 +85,9 @@ _loop block2.zpw1 ++
return
subx memsub () -> () = $fff2
sub memsub () -> () = $fff2
subx customsub (Y)->() {
sub customsub (Y)->() {
asm {
nop