mirror of
https://github.com/irmen/prog8.git
synced 2024-09-10 09:54:32 +00:00
various
This commit is contained in:
parent
a5b4849058
commit
a7465f480a
@ -126,14 +126,7 @@ class CodeGenerator:
|
|||||||
def initialize_variables(self) -> None:
|
def initialize_variables(self) -> None:
|
||||||
must_save_zp = self.parsed.clobberzp and self.parsed.restorezp
|
must_save_zp = self.parsed.clobberzp and self.parsed.restorezp
|
||||||
if must_save_zp:
|
if must_save_zp:
|
||||||
self.p("; save zp")
|
self.p("\t\tjsr il65_lib_zp.save_zeropage")
|
||||||
self.p("\t\tsei")
|
|
||||||
self.p("\t\tldx #2")
|
|
||||||
self.p("-\t\tlda $00,x")
|
|
||||||
self.p("\t\tsta _il65_zp_backup-2,x")
|
|
||||||
self.p("\t\tinx")
|
|
||||||
self.p("\t\tbne -")
|
|
||||||
|
|
||||||
# Only the vars from the ZeroPage need to be initialized here,
|
# Only the vars from the ZeroPage need to be initialized here,
|
||||||
# the vars in all other blocks are just defined and pre-filled there.
|
# the vars in all other blocks are just defined and pre-filled there.
|
||||||
zpblocks = [b for b in self.parsed.blocks if b.name == "ZP"]
|
zpblocks = [b for b in self.parsed.blocks if b.name == "ZP"]
|
||||||
@ -173,17 +166,8 @@ class CodeGenerator:
|
|||||||
main_block_label = [b.label for b in self.parsed.blocks if b.name == "main"][0]
|
main_block_label = [b.label for b in self.parsed.blocks if b.name == "main"][0]
|
||||||
if must_save_zp:
|
if must_save_zp:
|
||||||
self.p("\t\tjsr {:s}.start\t\t; call user code".format(main_block_label))
|
self.p("\t\tjsr {:s}.start\t\t; call user code".format(main_block_label))
|
||||||
self.p("; restore zp")
|
|
||||||
self.p("\t\tcld")
|
self.p("\t\tcld")
|
||||||
self.p("\t\tphp\n\t\tpha\n\t\ttxa\n\t\tpha\n\t\tsei")
|
self.p("\t\tjmp il65_lib_zp.restore_zeropage")
|
||||||
self.p("\t\tldx #2")
|
|
||||||
self.p("-\t\tlda _il65_zp_backup-2,x")
|
|
||||||
self.p("\t\tsta $00,x")
|
|
||||||
self.p("\t\tinx")
|
|
||||||
self.p("\t\tbne -")
|
|
||||||
self.p("\t\tcli\n\t\tpla\n\t\ttax\n\t\tpla\n\t\tplp")
|
|
||||||
self.p("\t\trts")
|
|
||||||
self.p("_il65_zp_backup\t\t.fill 254, 0")
|
|
||||||
else:
|
else:
|
||||||
self.p("\t\tjmp {:s}.start\t\t; call user code".format(main_block_label))
|
self.p("\t\tjmp {:s}.start\t\t; call user code".format(main_block_label))
|
||||||
|
|
||||||
@ -532,6 +516,7 @@ class CodeGenerator:
|
|||||||
self.p("\t\tpla")
|
self.p("\t\tpla")
|
||||||
elif what.datatype == DataType.WORD:
|
elif what.datatype == DataType.WORD:
|
||||||
if stmt.howmuch == 1:
|
if stmt.howmuch == 1:
|
||||||
|
# mem.word +=/-= 1
|
||||||
if is_incr:
|
if is_incr:
|
||||||
self.p("\t\tinc " + r_str)
|
self.p("\t\tinc " + r_str)
|
||||||
self.p("\t\tbne +")
|
self.p("\t\tbne +")
|
||||||
@ -545,7 +530,25 @@ class CodeGenerator:
|
|||||||
self.p("+\t\tdec " + r_str)
|
self.p("+\t\tdec " + r_str)
|
||||||
self.p("\t\tpla")
|
self.p("\t\tpla")
|
||||||
else:
|
else:
|
||||||
raise CodeError("cannot yet incr/decr 16 bit memory by more than 1") # @todo 16-bit incr/decr
|
# mem.word +=/-= 2..255
|
||||||
|
if is_incr:
|
||||||
|
self.p("\t\tpha")
|
||||||
|
self.p("\t\tclc")
|
||||||
|
self.p("\t\tlda " + r_str)
|
||||||
|
self.p("\t\tadc #{:d}".format(stmt.howmuch))
|
||||||
|
self.p("\t\tsta " + r_str)
|
||||||
|
self.p("\t\tbcc +")
|
||||||
|
self.p("\t\tinc {:s}+1".format(r_str))
|
||||||
|
self.p("+\t\tpla")
|
||||||
|
else:
|
||||||
|
self.p("\t\tpha")
|
||||||
|
self.p("\t\tsec")
|
||||||
|
self.p("\t\tlda " + r_str)
|
||||||
|
self.p("\t\tsbc #{:d}".format(stmt.howmuch))
|
||||||
|
self.p("\t\tsta " + r_str)
|
||||||
|
self.p("\t\tbcs +")
|
||||||
|
self.p("\t\tdec {:s}+1".format(r_str))
|
||||||
|
self.p("+\t\tpla")
|
||||||
else:
|
else:
|
||||||
raise CodeError("cannot in/decrement memory of type " + str(what.datatype))
|
raise CodeError("cannot in/decrement memory of type " + str(what.datatype))
|
||||||
else:
|
else:
|
||||||
@ -718,13 +721,23 @@ class CodeGenerator:
|
|||||||
self.p(line_after_branch)
|
self.p(line_after_branch)
|
||||||
|
|
||||||
def branch_emitter_indirect_cond(targetstr: str, is_goto: bool, target_indirect: bool) -> None:
|
def branch_emitter_indirect_cond(targetstr: str, is_goto: bool, target_indirect: bool) -> None:
|
||||||
print("EMIT", stmt.target, stmt.condition, is_goto, target_indirect)
|
|
||||||
assert is_goto and not stmt.condition.comparison_op
|
assert is_goto and not stmt.condition.comparison_op
|
||||||
assert stmt.condition.lvalue and not stmt.condition.rvalue
|
assert stmt.condition.lvalue and not stmt.condition.rvalue
|
||||||
assert stmt.condition.ifstatus in ("true", "not", "zero")
|
assert stmt.condition.ifstatus in ("true", "not", "zero")
|
||||||
|
assert not target_indirect
|
||||||
cv = stmt.condition.lvalue.value # type: ignore
|
cv = stmt.condition.lvalue.value # type: ignore
|
||||||
if isinstance(cv, ParseResult.RegisterValue):
|
if isinstance(cv, ParseResult.RegisterValue):
|
||||||
raise CodeError("indirect registers not yet supported") # @todo indirect reg
|
branch = "bne" if stmt.condition.ifstatus == "true" else "beq"
|
||||||
|
self.p("\t\tsta " + Parser.to_hex(Zeropage.SCRATCH_B1)) # need to save A, because the goto may not be taken
|
||||||
|
if cv.register in REGISTER_BYTES:
|
||||||
|
self.p("\t\tst{:s} *+2\t; self-modify".format(cv.register.lower()))
|
||||||
|
self.p("\t\tlda $ff")
|
||||||
|
else:
|
||||||
|
self.p("\t\tst{:s} (+)+1\t; self-modify".format(cv.register[0].lower()))
|
||||||
|
self.p("\t\tst{:s} (+)+2\t; self-modify".format(cv.register[1].lower()))
|
||||||
|
self.p("+\t\tlda $ffff")
|
||||||
|
self.p("\t\t{:s} {:s}".format(branch, targetstr))
|
||||||
|
self.p("\t\tlda " + Parser.to_hex(Zeropage.SCRATCH_B1)) # restore A
|
||||||
elif isinstance(cv, ParseResult.MemMappedValue):
|
elif isinstance(cv, ParseResult.MemMappedValue):
|
||||||
raise CodeError("memmapped indirect should not occur, use the variable without indirection")
|
raise CodeError("memmapped indirect should not occur, use the variable without indirection")
|
||||||
elif isinstance(cv, ParseResult.IntegerValue) and cv.constant:
|
elif isinstance(cv, ParseResult.IntegerValue) and cv.constant:
|
||||||
@ -917,27 +930,15 @@ class CodeGenerator:
|
|||||||
unclobber_result_registers(preserve_regs, stmt.desugared_output_assignments)
|
unclobber_result_registers(preserve_regs, stmt.desugared_output_assignments)
|
||||||
with self.preserving_registers(preserve_regs, loads_a_within=params_load_a()):
|
with self.preserving_registers(preserve_regs, loads_a_within=params_load_a()):
|
||||||
generate_param_assignments()
|
generate_param_assignments()
|
||||||
# @todo optimize this with RTS_trick? https://wiki.nesdev.com/w/index.php/6502_assembly_optimisations#Use_Jump_tables_with_RTS_instruction_instead_of_JMP_indirect_instruction
|
|
||||||
if targetstr in REGISTER_WORDS:
|
if targetstr in REGISTER_WORDS:
|
||||||
if stmt.preserve_regs:
|
print("warning: {:s}:{:d}: indirect register pair call is quite inefficient, use a jump table in memory instead?"
|
||||||
# cannot use zp scratch. This is very inefficient code!
|
|
||||||
print("warning: {:s}:{:d}: indirect register pair call, this is very inefficient"
|
|
||||||
.format(self.cur_block.sourceref.file, stmt.lineno))
|
.format(self.cur_block.sourceref.file, stmt.lineno))
|
||||||
self.p("\t\tst{:s} ++".format(targetstr[0].lower()))
|
if stmt.preserve_regs:
|
||||||
self.p("\t\tst{:s} +++".format(targetstr[1].lower()))
|
# cannot use zp scratch because it may be used by the register backup. This is very inefficient code!
|
||||||
self.p("\t\tjsr +")
|
self.p("\t\tjsr il65_lib.jsr_indirect_nozpuse_"+targetstr)
|
||||||
self.p("\t\tjmp ++++")
|
|
||||||
self.p("+\t\tjmp (+)")
|
|
||||||
self.p("+\t\t.byte 0\t; lo")
|
|
||||||
self.p("+\t\t.byte 0\t; hi")
|
|
||||||
self.p("+")
|
|
||||||
else:
|
else:
|
||||||
self.p("\t\tst{:s} {:s}".format(targetstr[0].lower(), Parser.to_hex(Zeropage.SCRATCH_B1)))
|
self.p("\t\tjsr il65_lib.jsr_indirect_"+targetstr)
|
||||||
self.p("\t\tst{:s} {:s}".format(targetstr[1].lower(), Parser.to_hex(Zeropage.SCRATCH_B2)))
|
|
||||||
self.p("\t\tjsr +")
|
|
||||||
self.p("\t\tjmp ++")
|
|
||||||
self.p("+\t\tjmp ({:s})".format(Parser.to_hex(Zeropage.SCRATCH_B1)))
|
|
||||||
self.p("+")
|
|
||||||
else:
|
else:
|
||||||
self.p("\t\tjsr +")
|
self.p("\t\tjsr +")
|
||||||
self.p("\t\tjmp ++")
|
self.p("\t\tjmp ++")
|
||||||
@ -1720,17 +1721,14 @@ class CodeGenerator:
|
|||||||
raise CodeError("can only assign a byte or word to a word", str(rvalue))
|
raise CodeError("can only assign a byte or word to a word", str(rvalue))
|
||||||
elif lv.datatype == DataType.FLOAT:
|
elif lv.datatype == DataType.FLOAT:
|
||||||
if rvalue.datatype == DataType.FLOAT:
|
if rvalue.datatype == DataType.FLOAT:
|
||||||
with self.preserving_registers({'A'}, loads_a_within=True):
|
with self.preserving_registers({'A', 'X', 'Y'}, loads_a_within=True):
|
||||||
self.p("\t\tlda " + r_str)
|
self.p("\t\tlda #<" + r_str)
|
||||||
self.p("\t\tsta " + l_str)
|
self.p("\t\tsta c64.SCRATCH_ZPWORD")
|
||||||
self.p("\t\tlda {:s}+1".format(r_str))
|
self.p("\t\tlda #>" + r_str)
|
||||||
self.p("\t\tsta {:s}+1".format(l_str))
|
self.p("\t\tsta c64.SCRATCH_ZPWORD+1")
|
||||||
self.p("\t\tlda {:s}+2".format(r_str))
|
self.p("\t\tldx #<" + l_str)
|
||||||
self.p("\t\tsta {:s}+2".format(l_str))
|
self.p("\t\tldy #>" + l_str)
|
||||||
self.p("\t\tlda {:s}+3".format(r_str))
|
self.p("\t\tjsr c64_lib.copy_mflt")
|
||||||
self.p("\t\tsta {:s}+3".format(l_str))
|
|
||||||
self.p("\t\tlda {:s}+4".format(r_str))
|
|
||||||
self.p("\t\tsta {:s}+4".format(l_str))
|
|
||||||
elif rvalue.datatype == DataType.BYTE:
|
elif rvalue.datatype == DataType.BYTE:
|
||||||
with self.preserving_registers({'A', 'X', 'Y'}):
|
with self.preserving_registers({'A', 'X', 'Y'}):
|
||||||
self.p("\t\tldy " + r_str)
|
self.p("\t\tldy " + r_str)
|
||||||
|
@ -35,11 +35,11 @@ def main() -> None:
|
|||||||
print("\n" + description)
|
print("\n" + description)
|
||||||
|
|
||||||
start = time.perf_counter()
|
start = time.perf_counter()
|
||||||
pp = PreprocessingParser(args.sourcefile, )
|
pp = PreprocessingParser(args.sourcefile, set())
|
||||||
sourcelines, symbols = pp.preprocess()
|
sourcelines, symbols = pp.preprocess()
|
||||||
# symbols.print_table()
|
# symbols.print_table()
|
||||||
|
|
||||||
p = Parser(args.sourcefile, args.output, sourcelines, ppsymbols=symbols, sub_usage=pp.result.subroutine_usage)
|
p = Parser(args.sourcefile, args.output, set(), sourcelines=sourcelines, ppsymbols=symbols, sub_usage=pp.result.subroutine_usage)
|
||||||
parsed = p.parse()
|
parsed = p.parse()
|
||||||
if parsed:
|
if parsed:
|
||||||
if args.nooptimize:
|
if args.nooptimize:
|
||||||
|
@ -472,10 +472,27 @@ class ParseResult:
|
|||||||
if not assignment.is_identity():
|
if not assignment.is_identity():
|
||||||
assignment.lineno = self.lineno
|
assignment.lineno = self.lineno
|
||||||
self.desugared_call_arguments.append(assignment)
|
self.desugared_call_arguments.append(assignment)
|
||||||
|
if all(not isinstance(v, ParseResult.RegisterValue) for r, v in self.outputvars or []):
|
||||||
|
# if none of the output variables are registers, we can simply generate the assignments without issues
|
||||||
|
for register, value in self.outputvars or []:
|
||||||
|
rvalue = parser.parse_expression(register)
|
||||||
|
assignment = ParseResult.AssignmentStmt([value], rvalue, self.lineno)
|
||||||
|
assignment.lineno = self.lineno
|
||||||
|
self.desugared_output_assignments.append(assignment)
|
||||||
|
else:
|
||||||
|
result_reg_mapping = [(register, value.register, value) for register, value in self.outputvars or []
|
||||||
|
if isinstance(value, ParseResult.RegisterValue)]
|
||||||
|
if any(r[0] != r[1] for r in result_reg_mapping):
|
||||||
|
# not all result parameter registers line up with the correct order of registers in the statement,
|
||||||
|
# reshuffling call results is not supported yet.
|
||||||
|
raise parser.PError("result registers and/or their ordering is not the same as in the "
|
||||||
|
"subroutine definition, this isn't supported yet")
|
||||||
|
else:
|
||||||
|
# no register alignment issues, just generate the assignments
|
||||||
|
# note: do not remove the identity assignment here or the output register handling generates buggy code
|
||||||
for register, value in self.outputvars or []:
|
for register, value in self.outputvars or []:
|
||||||
rvalue = parser.parse_expression(register)
|
rvalue = parser.parse_expression(register)
|
||||||
assignment = ParseResult.AssignmentStmt([value], rvalue, self.lineno)
|
assignment = ParseResult.AssignmentStmt([value], rvalue, self.lineno)
|
||||||
# note: we need the identity assignment here or the output register handling generates buggy code
|
|
||||||
assignment.lineno = self.lineno
|
assignment.lineno = self.lineno
|
||||||
self.desugared_output_assignments.append(assignment)
|
self.desugared_output_assignments.append(assignment)
|
||||||
|
|
||||||
@ -552,8 +569,8 @@ class ParseResult:
|
|||||||
|
|
||||||
|
|
||||||
class Parser:
|
class Parser:
|
||||||
def __init__(self, filename: str, outputdir: str, sourcelines: List[Tuple[int, str]] = None, parsing_import: bool = False,
|
def __init__(self, filename: str, outputdir: str, existing_imports: Set[str], parsing_import: bool = False,
|
||||||
ppsymbols: SymbolTable = None, sub_usage: Dict=None) -> None:
|
sourcelines: List[Tuple[int, str]] = None, ppsymbols: SymbolTable = None, sub_usage: Dict=None) -> None:
|
||||||
self.result = ParseResult(filename)
|
self.result = ParseResult(filename)
|
||||||
if sub_usage is not None:
|
if sub_usage is not None:
|
||||||
# re-use the (global) subroutine usage tracking
|
# re-use the (global) subroutine usage tracking
|
||||||
@ -571,6 +588,7 @@ class Parser:
|
|||||||
self.root_scope.set_zeropage(self.result.zeropage)
|
self.root_scope.set_zeropage(self.result.zeropage)
|
||||||
self.ppsymbols = ppsymbols # symboltable from preprocess phase
|
self.ppsymbols = ppsymbols # symboltable from preprocess phase
|
||||||
self.print_block_parsing = True
|
self.print_block_parsing = True
|
||||||
|
self.existing_imports = existing_imports
|
||||||
|
|
||||||
def load_source(self, filename: str) -> List[Tuple[int, str]]:
|
def load_source(self, filename: str) -> List[Tuple[int, str]]:
|
||||||
with open(filename, "rU") as source:
|
with open(filename, "rU") as source:
|
||||||
@ -624,6 +642,7 @@ class Parser:
|
|||||||
def parse_file(self) -> ParseResult:
|
def parse_file(self) -> ParseResult:
|
||||||
print("\nparsing", self.sourceref.file)
|
print("\nparsing", self.sourceref.file)
|
||||||
self._parse_1()
|
self._parse_1()
|
||||||
|
self._parse_import_file("il65lib") # compiler support library is always imported.
|
||||||
self._parse_2()
|
self._parse_2()
|
||||||
return self.result
|
return self.result
|
||||||
|
|
||||||
@ -658,7 +677,7 @@ class Parser:
|
|||||||
block = self.parse_block()
|
block = self.parse_block()
|
||||||
if block:
|
if block:
|
||||||
self.result.add_block(block)
|
self.result.add_block(block)
|
||||||
elif next_line.startswith("import"):
|
elif next_line.startswith(("import ", "import\t")):
|
||||||
self.parse_import()
|
self.parse_import()
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
@ -861,7 +880,7 @@ class Parser:
|
|||||||
def parse_import(self) -> None:
|
def parse_import(self) -> None:
|
||||||
line = self.next_line()
|
line = self.next_line()
|
||||||
line = line.lstrip()
|
line = line.lstrip()
|
||||||
if not line.startswith("import"):
|
if not line.startswith(("import ", "import\t")):
|
||||||
raise self.PError("expected import")
|
raise self.PError("expected import")
|
||||||
try:
|
try:
|
||||||
_, arg = line.split(maxsplit=1)
|
_, arg = line.split(maxsplit=1)
|
||||||
@ -872,6 +891,9 @@ class Parser:
|
|||||||
filename = arg[1:-1]
|
filename = arg[1:-1]
|
||||||
if not filename:
|
if not filename:
|
||||||
raise self.PError("invalid filename")
|
raise self.PError("invalid filename")
|
||||||
|
self._parse_import_file(filename)
|
||||||
|
|
||||||
|
def _parse_import_file(self, filename: str) -> None:
|
||||||
filename_at_source_location = os.path.join(os.path.split(self.sourceref.file)[0], filename)
|
filename_at_source_location = os.path.join(os.path.split(self.sourceref.file)[0], filename)
|
||||||
filename_at_libs_location = os.path.join(os.getcwd(), "lib", filename)
|
filename_at_libs_location = os.path.join(os.getcwd(), "lib", filename)
|
||||||
candidates = [filename,
|
candidates = [filename,
|
||||||
@ -882,10 +904,12 @@ class Parser:
|
|||||||
filename_at_libs_location+".ill"]
|
filename_at_libs_location+".ill"]
|
||||||
for filename in candidates:
|
for filename in candidates:
|
||||||
if os.path.isfile(filename):
|
if os.path.isfile(filename):
|
||||||
print("importing", filename)
|
if not self.check_import_okay(filename):
|
||||||
|
return
|
||||||
|
self.print_import_progress("importing", filename)
|
||||||
parser = self.create_import_parser(filename, self.outputdir)
|
parser = self.create_import_parser(filename, self.outputdir)
|
||||||
result = parser.parse()
|
result = parser.parse()
|
||||||
print("\ncontinuing", self.sourceref.file)
|
self.print_import_progress("\ncontinuing", self.sourceref.file)
|
||||||
if result:
|
if result:
|
||||||
# merge the symbol table of the imported file into our own
|
# merge the symbol table of the imported file into our own
|
||||||
try:
|
try:
|
||||||
@ -898,8 +922,11 @@ class Parser:
|
|||||||
raise self.PError("Error while parsing imported file")
|
raise self.PError("Error while parsing imported file")
|
||||||
raise self.PError("imported file not found")
|
raise self.PError("imported file not found")
|
||||||
|
|
||||||
|
def print_import_progress(self, message: str, *args: str) -> None:
|
||||||
|
print(message, *args)
|
||||||
|
|
||||||
def create_import_parser(self, filename: str, outputdir: str) -> 'Parser':
|
def create_import_parser(self, filename: str, outputdir: str) -> 'Parser':
|
||||||
return Parser(filename, outputdir, parsing_import=True, ppsymbols=self.ppsymbols, sub_usage=self.result.subroutine_usage)
|
return Parser(filename, outputdir, self.existing_imports, True, ppsymbols=self.ppsymbols, sub_usage=self.result.subroutine_usage)
|
||||||
|
|
||||||
def parse_block(self) -> Optional[ParseResult.Block]:
|
def parse_block(self) -> Optional[ParseResult.Block]:
|
||||||
# first line contains block header "~ [name] [addr]" followed by a '{'
|
# first line contains block header "~ [name] [addr]" followed by a '{'
|
||||||
@ -1276,7 +1303,7 @@ class Parser:
|
|||||||
raise self.PError("all call arguments should have a name or be matched on a named parameter")
|
raise self.PError("all call arguments should have a name or be matched on a named parameter")
|
||||||
if isinstance(target, (type(None), ParseResult.Value)):
|
if isinstance(target, (type(None), ParseResult.Value)):
|
||||||
# special case for the C-64 lib's print function, to be able to use it with a single character argument
|
# special case for the C-64 lib's print function, to be able to use it with a single character argument
|
||||||
if target.name == "c64util.print_string" and len(arguments) == 1 and len(arguments[0][0]) > 1:
|
if target.name == "c64util.print_string" and len(arguments) == 1 and isinstance(arguments[0], str):
|
||||||
if arguments[0][1].startswith("'") and arguments[0][1].endswith("'"):
|
if arguments[0][1].startswith("'") and arguments[0][1].endswith("'"):
|
||||||
target = self.parse_expression("c64.CHROUT")
|
target = self.parse_expression("c64.CHROUT")
|
||||||
address = target.address
|
address = target.address
|
||||||
@ -1662,6 +1689,14 @@ class Parser:
|
|||||||
self.print_warning("if_not condition inverted to if")
|
self.print_warning("if_not condition inverted to if")
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def check_import_okay(self, filename: str) -> bool:
|
||||||
|
if filename == self.sourceref.file and not filename.endswith("il65lib.ill"):
|
||||||
|
raise self.PError("can't import itself")
|
||||||
|
if filename in self.existing_imports:
|
||||||
|
return False
|
||||||
|
self.existing_imports.add(filename)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class Optimizer:
|
class Optimizer:
|
||||||
def __init__(self, parseresult: ParseResult) -> None:
|
def __init__(self, parseresult: ParseResult) -> None:
|
||||||
@ -1765,8 +1800,7 @@ class Optimizer:
|
|||||||
block.symbols.discard_sub(sub.name)
|
block.symbols.discard_sub(sub.name)
|
||||||
discarded.append(sub.name)
|
discarded.append(sub.name)
|
||||||
if discarded:
|
if discarded:
|
||||||
print("{}: discarded unused subroutines from block '{:s}': ".format(block.sourceref, block.name), end="")
|
print("{}: discarded {:d} unused subroutines from block '{:s}'".format(block.sourceref, len(discarded), block.name))
|
||||||
print(", ".join(discarded))
|
|
||||||
|
|
||||||
|
|
||||||
def _value_sortkey(value: ParseResult.Value) -> int:
|
def _value_sortkey(value: ParseResult.Value) -> int:
|
||||||
|
@ -6,14 +6,14 @@ Written by Irmen de Jong (irmen@razorvine.net)
|
|||||||
License: GNU GPL 3.0, see LICENSE
|
License: GNU GPL 3.0, see LICENSE
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import List, Tuple
|
from typing import List, Tuple, Set
|
||||||
from .parse import Parser, ParseResult, SymbolTable, SymbolDefinition
|
from .parse import Parser, ParseResult, SymbolTable, SymbolDefinition
|
||||||
from .symbols import SourceRef
|
from .symbols import SourceRef
|
||||||
|
|
||||||
|
|
||||||
class PreprocessingParser(Parser):
|
class PreprocessingParser(Parser):
|
||||||
def __init__(self, filename: str, parsing_import: bool=False) -> None:
|
def __init__(self, filename: str, existing_imports: Set[str], parsing_import: bool=False) -> None:
|
||||||
super().__init__(filename, "", parsing_import=parsing_import)
|
super().__init__(filename, "", existing_imports=existing_imports, parsing_import=parsing_import)
|
||||||
self.print_block_parsing = False
|
self.print_block_parsing = False
|
||||||
|
|
||||||
def preprocess(self) -> Tuple[List[Tuple[int, str]], SymbolTable]:
|
def preprocess(self) -> Tuple[List[Tuple[int, str]], SymbolTable]:
|
||||||
@ -37,7 +37,7 @@ class PreprocessingParser(Parser):
|
|||||||
return lines
|
return lines
|
||||||
|
|
||||||
def parse_file(self) -> ParseResult:
|
def parse_file(self) -> ParseResult:
|
||||||
print("\npreprocessing", self.sourceref.file)
|
print("preprocessing", self.sourceref.file)
|
||||||
self._parse_1()
|
self._parse_1()
|
||||||
return self.result
|
return self.result
|
||||||
|
|
||||||
@ -63,4 +63,7 @@ class PreprocessingParser(Parser):
|
|||||||
super().parse_subroutine_def(line)
|
super().parse_subroutine_def(line)
|
||||||
|
|
||||||
def create_import_parser(self, filename: str, outputdir: str) -> 'Parser':
|
def create_import_parser(self, filename: str, outputdir: str) -> 'Parser':
|
||||||
return PreprocessingParser(filename, parsing_import=True)
|
return PreprocessingParser(filename, parsing_import=True, existing_imports=self.existing_imports)
|
||||||
|
|
||||||
|
def print_import_progress(self, message: str, *args: str) -> None:
|
||||||
|
pass
|
||||||
|
@ -208,6 +208,7 @@ class SubroutineDef(SymbolDefinition):
|
|||||||
class Zeropage:
|
class Zeropage:
|
||||||
SCRATCH_B1 = 0x02
|
SCRATCH_B1 = 0x02
|
||||||
SCRATCH_B2 = 0x03
|
SCRATCH_B2 = 0x03
|
||||||
|
SCRATCH_W1 = 0xfd # $fd/$fe
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.unused_bytes = [] # type: List[int]
|
self.unused_bytes = [] # type: List[int]
|
||||||
@ -218,13 +219,13 @@ class Zeropage:
|
|||||||
if self._configured:
|
if self._configured:
|
||||||
raise SymbolError("cannot configure the ZP multiple times")
|
raise SymbolError("cannot configure the ZP multiple times")
|
||||||
if clobber_zp:
|
if clobber_zp:
|
||||||
self.unused_bytes = list(range(0x04, 0x80))
|
self.unused_bytes = list(range(0x04, 0x80)) + [0xfc, 0xff]
|
||||||
self.unused_words = list(range(0x80, 0x100, 2))
|
self.unused_words = list(range(0x80, 0xfc, 2))
|
||||||
else:
|
else:
|
||||||
# these are valid for the C-64:
|
# these are valid for the C-64 (when no RS232 I/O is performed):
|
||||||
# ($02 and $03 are reserved as scratch addresses for various routines)
|
# ($02, $03, $fd-$fe are reserved as scratch addresses for various routines)
|
||||||
self.unused_bytes = [0x06, 0x0a, 0x2a, 0x52, 0x93] # 5 zp variables (8 bits each)
|
self.unused_bytes = [0x04, 0x05, 0x06, 0x2a, 0x52] # 5 zp variables (1 byte each)
|
||||||
self.unused_words = [0x04, 0xf7, 0xf9, 0xfb, 0xfd] # 5 zp variables (16 bits each)
|
self.unused_words = [0xf7, 0xf9, 0xfb] # 3 zp word variables (2 bytes each)
|
||||||
assert self.SCRATCH_B1 not in self.unused_bytes and self.SCRATCH_B1 not in self.unused_words
|
assert self.SCRATCH_B1 not in self.unused_bytes and self.SCRATCH_B1 not in self.unused_words
|
||||||
assert self.SCRATCH_B2 not in self.unused_bytes and self.SCRATCH_B2 not in self.unused_words
|
assert self.SCRATCH_B2 not in self.unused_bytes and self.SCRATCH_B2 not in self.unused_words
|
||||||
self._configured = True
|
self._configured = True
|
||||||
@ -252,7 +253,7 @@ class SymbolTable:
|
|||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.owning_block = owning_block
|
self.owning_block = owning_block
|
||||||
self.eval_dict = None
|
self.eval_dict = None
|
||||||
self._zeropage = parent._zeropage if parent else None
|
self._zeropage = parent._zeropage if parent else None # type: Zeropage
|
||||||
|
|
||||||
def set_zeropage(self, zp: Zeropage) -> None:
|
def set_zeropage(self, zp: Zeropage) -> None:
|
||||||
if self._zeropage is None:
|
if self._zeropage is None:
|
||||||
|
@ -10,8 +10,9 @@
|
|||||||
output raw
|
output raw
|
||||||
|
|
||||||
~ c64 {
|
~ c64 {
|
||||||
memory SCRATCH_ZP1 = $02 ; scratch register #1 in ZP
|
memory .byte SCRATCH_ZP1 = $02 ; scratch register #1 in ZP
|
||||||
memory SCRATCH_ZP2 = $03 ; scratch register #2 in ZP
|
memory .byte SCRATCH_ZP2 = $03 ; scratch register #2 in ZP
|
||||||
|
memory .word SCRATCH_ZPWORD = $fd ; scratch word in ZP ($fd/$fe)
|
||||||
|
|
||||||
memory .byte COLOR = $0286 ; cursor color
|
memory .byte COLOR = $0286 ; cursor color
|
||||||
memory .word CINV = $0314 ; IRQ vector
|
memory .word CINV = $0314 ; IRQ vector
|
||||||
@ -335,6 +336,9 @@ sub GETADRAY () -> (AY, X?) {
|
|||||||
|
|
||||||
sub print_string (address: XY) -> (A?, Y?) {
|
sub print_string (address: XY) -> (A?, Y?) {
|
||||||
; ---- print null terminated string from X/Y
|
; ---- print null terminated string from X/Y
|
||||||
|
; note: the IL65 compiler contains an optimization that will replace
|
||||||
|
; a call to this subroutine with a string argument of just one char,
|
||||||
|
; by just one call to c64.CHROUT of that single char.
|
||||||
asm {
|
asm {
|
||||||
stx c64.SCRATCH_ZP1
|
stx c64.SCRATCH_ZP1
|
||||||
sty c64.SCRATCH_ZP2
|
sty c64.SCRATCH_ZP2
|
||||||
@ -433,7 +437,7 @@ hex_digits .text "0123456789abcdef" ; can probably be reused for other stuff as
|
|||||||
}
|
}
|
||||||
|
|
||||||
; var .array(4) word2hex_output_array @todo support to use array/matrix type by address
|
; var .array(4) word2hex_output_array @todo support to use array/matrix type by address
|
||||||
var .text word2hex_output = "123" ; 0-terminated, 4 bytes total @todo remove if array works
|
var .text word2hex_output = "123" ; 0-terminated, 4 bytes total @todo remove once array works
|
||||||
sub word2hex (word: XY) -> (A?, X?, Y?) {
|
sub word2hex (word: XY) -> (A?, X?, Y?) {
|
||||||
; ---- convert 16 bit word in X/Y into hexadecimal string into memory 'word2hex_output'
|
; ---- convert 16 bit word in X/Y into hexadecimal string into memory 'word2hex_output'
|
||||||
asm {
|
asm {
|
||||||
@ -706,3 +710,33 @@ sub input_chars (buffer: AX) -> (A?, Y) {
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
~ c64_lib {
|
||||||
|
|
||||||
|
asm {
|
||||||
|
|
||||||
|
; ---- copy a 5 byte MFLT floating point variable to another place
|
||||||
|
; input: X/Y = source address, SCRATCH_ZPWORD = destination address
|
||||||
|
copy_mflt stx c64.SCRATCH_ZP1
|
||||||
|
sty c64.SCRATCH_ZPWORD+1
|
||||||
|
ldy #0
|
||||||
|
lda (c64.SCRATCH_ZP1),y
|
||||||
|
sta (c64.SCRATCH_ZPWORD),y
|
||||||
|
iny
|
||||||
|
lda (c64.SCRATCH_ZP1),y
|
||||||
|
sta (c64.SCRATCH_ZPWORD),y
|
||||||
|
iny
|
||||||
|
lda (c64.SCRATCH_ZP1),y
|
||||||
|
sta (c64.SCRATCH_ZPWORD),y
|
||||||
|
iny
|
||||||
|
lda (c64.SCRATCH_ZP1),y
|
||||||
|
sta (c64.SCRATCH_ZPWORD),y
|
||||||
|
iny
|
||||||
|
lda (c64.SCRATCH_ZP1),y
|
||||||
|
sta (c64.SCRATCH_ZPWORD),y
|
||||||
|
ldy c64.SCRATCH_ZPWORD+1
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
88
lib/il65lib.ill
Normal file
88
lib/il65lib.ill
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
; IL65 internal library routines
|
||||||
|
;
|
||||||
|
; Written by Irmen de Jong (irmen@razorvine.net)
|
||||||
|
; License: GNU GPL 3.0, see LICENSE
|
||||||
|
;
|
||||||
|
; indent format: TABS, size=8
|
||||||
|
|
||||||
|
output raw
|
||||||
|
|
||||||
|
~ il65_lib_zp {
|
||||||
|
; note: separate block so the 64tass assembler can remove this when no zp restore is required
|
||||||
|
|
||||||
|
asm {
|
||||||
|
|
||||||
|
; ---- store the Zeropage in a backup area
|
||||||
|
save_zeropage
|
||||||
|
sei
|
||||||
|
ldx #2
|
||||||
|
- lda $00,x
|
||||||
|
sta zp_backup-2,x
|
||||||
|
inx
|
||||||
|
bne -
|
||||||
|
rts
|
||||||
|
|
||||||
|
restore_zeropage
|
||||||
|
php
|
||||||
|
pha
|
||||||
|
txa
|
||||||
|
pha
|
||||||
|
sei
|
||||||
|
ldx #2
|
||||||
|
- lda zp_backup-2,x
|
||||||
|
sta $00,x
|
||||||
|
inx
|
||||||
|
bne -
|
||||||
|
cli
|
||||||
|
pla
|
||||||
|
tax
|
||||||
|
pla
|
||||||
|
plp
|
||||||
|
rts
|
||||||
|
|
||||||
|
zp_backup .fill 254, 0
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
~ il65_lib {
|
||||||
|
; note: the following two ZP scratch registers must be the same as in c64lib
|
||||||
|
memory SCRATCH_ZP1 = $02 ; scratch register #1 in ZP
|
||||||
|
memory SCRATCH_ZP2 = $03 ; scratch register #2 in ZP
|
||||||
|
|
||||||
|
|
||||||
|
asm {
|
||||||
|
|
||||||
|
; ---- jmp (indirect) routines for register pairs containing the indirect address
|
||||||
|
jsr_indirect_nozpuse_AX
|
||||||
|
sta jsr_indirect_tmp
|
||||||
|
stx jsr_indirect_tmp+1
|
||||||
|
jmp (jsr_indirect_tmp)
|
||||||
|
jsr_indirect_nozpuse_AY
|
||||||
|
sta jsr_indirect_tmp
|
||||||
|
sty jsr_indirect_tmp+1
|
||||||
|
jmp (jsr_indirect_tmp)
|
||||||
|
jsr_indirect_nozpuse_XY
|
||||||
|
stx jsr_indirect_tmp
|
||||||
|
sty jsr_indirect_tmp+1
|
||||||
|
jmp (jsr_indirect_tmp)
|
||||||
|
jsr_indirect_tmp
|
||||||
|
.byte 0, 0
|
||||||
|
|
||||||
|
|
||||||
|
jsr_indirect_AX
|
||||||
|
sta SCRATCH_ZP1
|
||||||
|
stx SCRATCH_ZP2
|
||||||
|
jmp (SCRATCH_ZP1)
|
||||||
|
jsr_indirect_AY
|
||||||
|
sta SCRATCH_ZP1
|
||||||
|
sty SCRATCH_ZP2
|
||||||
|
jmp (SCRATCH_ZP1)
|
||||||
|
jsr_indirect_XY
|
||||||
|
stx SCRATCH_ZP1
|
||||||
|
sty SCRATCH_ZP2
|
||||||
|
jmp (SCRATCH_ZP1)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
; IL65 integer math library for 6502
|
; IL65 integer math library for 6502
|
||||||
; (floating point math is done via the C-64's BASIC ROM routines)
|
; (floating point math is done via the C-64's BASIC ROM routines)
|
||||||
;
|
;
|
||||||
|
; some more interesting routines can be found here http://6502org.wikidot.com/software-math
|
||||||
|
;
|
||||||
; Written by Irmen de Jong (irmen@razorvine.net)
|
; Written by Irmen de Jong (irmen@razorvine.net)
|
||||||
; License: GNU GPL 3.0, see LICENSE
|
; License: GNU GPL 3.0, see LICENSE
|
||||||
;
|
;
|
||||||
@ -10,9 +12,79 @@
|
|||||||
output raw
|
output raw
|
||||||
|
|
||||||
~ math {
|
~ math {
|
||||||
|
; note: the following two ZP scratch registers must be the same as in c64lib
|
||||||
|
memory SCRATCH_ZP1 = $02 ; scratch register #1 in ZP
|
||||||
|
memory SCRATCH_ZP2 = $03 ; scratch register #2 in ZP
|
||||||
|
|
||||||
|
|
||||||
; @todo some interesting routines can be found here http://6502org.wikidot.com/software-math
|
|
||||||
|
|
||||||
|
sub multiply_bytes (byte1: X, byte2: Y) -> (A, X?) {
|
||||||
|
; ---- multiply 2 bytes, result as byte in A (signed or unsigned)
|
||||||
|
asm {
|
||||||
|
stx SCRATCH_ZP1
|
||||||
|
sty SCRATCH_ZP2
|
||||||
|
ldx #8
|
||||||
|
- asl a
|
||||||
|
asl SCRATCH_ZP1
|
||||||
|
bcc +
|
||||||
|
clc
|
||||||
|
adc SCRATCH_ZP2
|
||||||
|
+ dex
|
||||||
|
bne -
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub multiply_bytes_16 (byte1: X, byte2: Y) -> (A?, XY) {
|
||||||
|
; ---- multiply 2 bytes, result as word in X/Y (unsigned)
|
||||||
|
asm {
|
||||||
|
lda #0
|
||||||
|
_m_with_add stx SCRATCH_ZP1
|
||||||
|
sty SCRATCH_ZP2
|
||||||
|
ldx #8
|
||||||
|
lsr SCRATCH_ZP1
|
||||||
|
- bcc +
|
||||||
|
clc
|
||||||
|
adc SCRATCH_ZP2
|
||||||
|
+ ror a
|
||||||
|
ror SCRATCH_ZP1
|
||||||
|
dex
|
||||||
|
bne -
|
||||||
|
tay
|
||||||
|
ldx SCRATCH_ZP1
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub multiply_bytes_addA_16 (byte1: X, byte2: Y, add: A) -> (A?, XY) {
|
||||||
|
; ---- multiply 2 bytes and add A, result as word in X/Y (unsigned)
|
||||||
|
asm {
|
||||||
|
jmp multiply_bytes_16._m_with_add
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub divide_bytes (numerator: X, denominator: Y) -> (X, A) {
|
||||||
|
; ---- divide X by Y, result quotient in X, remainder in A (unsigned)
|
||||||
|
; division by zero will result in quotient = 255 and remainder = original number
|
||||||
|
asm {
|
||||||
|
stx SCRATCH_ZP1
|
||||||
|
sty SCRATCH_ZP2
|
||||||
|
lda #0
|
||||||
|
ldx #8
|
||||||
|
asl SCRATCH_ZP1
|
||||||
|
- rol a
|
||||||
|
cmp SCRATCH_ZP2
|
||||||
|
bcc +
|
||||||
|
sbc SCRATCH_ZP2
|
||||||
|
+ rol SCRATCH_ZP1
|
||||||
|
dex
|
||||||
|
bne -
|
||||||
|
ldx SCRATCH_ZP1
|
||||||
|
rts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
13
reference.md
13
reference.md
@ -86,7 +86,7 @@ The following 6502 hardware registers are directly accessible in your code (and
|
|||||||
The zero page locations ``$02`` - ``$ff`` can be regarded as 254 other registers because
|
The zero page locations ``$02`` - ``$ff`` can be regarded as 254 other registers because
|
||||||
they take less clock cycles to access and need fewer instruction bytes than access to other memory locations.
|
they take less clock cycles to access and need fewer instruction bytes than access to other memory locations.
|
||||||
Theoretically you can use all of them in your program but there are a few limitations:
|
Theoretically you can use all of them in your program but there are a few limitations:
|
||||||
- ``$02`` and ``$03`` are reserved for internal use as scratch registers by IL65
|
- the four locations ``$02``, ``$03``, ``$fd - $fe`` are reserved for internal use as scratch registers by IL65
|
||||||
- most other addresses often are in use by the machine's operating system or kernal,
|
- most other addresses often are in use by the machine's operating system or kernal,
|
||||||
and overwriting them can crash the machine. Your program must take over the entire
|
and overwriting them can crash the machine. Your program must take over the entire
|
||||||
system to be able to safely use all zero page locations.
|
system to be able to safely use all zero page locations.
|
||||||
@ -95,10 +95,11 @@ Theoretically you can use all of them in your program but there are a few limita
|
|||||||
|
|
||||||
For the Commodore-64 here is a list of free-to-use zero page locations even when its BASIC and KERNAL are active:
|
For the Commodore-64 here is a list of free-to-use zero page locations even when its BASIC and KERNAL are active:
|
||||||
|
|
||||||
``$02`` - ``$03`` (but see remark above); ``$04`` - ``$05``; ``$06``;
|
``$02``; ``$03``; ``$04``; ``$05``; ``$06``; ``$2a``; ``$52``;
|
||||||
``$0a``; ``$2a``; ``$52``; ``$93``;
|
|
||||||
``$f7`` - ``$f8``; ``$f9`` - ``$fa``; ``$fb`` - ``$fc``; ``$fd`` - ``$fe``
|
``$f7`` - ``$f8``; ``$f9`` - ``$fa``; ``$fb`` - ``$fc``; ``$fd`` - ``$fe``
|
||||||
|
|
||||||
|
The four reserved locations mentioned above are subtracted from this set, leaving you with
|
||||||
|
five 1-byte and three 2-byte usable zero page registers.
|
||||||
IL65 knows about all this: it will use the above zero page locations to place its ZP variables in,
|
IL65 knows about all this: it will use the above zero page locations to place its ZP variables in,
|
||||||
until they're all used up. You can instruct it to treat your program as taking over the entire
|
until they're all used up. You can instruct it to treat your program as taking over the entire
|
||||||
machine, in which case all of the zero page locations are suddenly available for variables.
|
machine, in which case all of the zero page locations are suddenly available for variables.
|
||||||
@ -193,6 +194,9 @@ However you can specify some options globally in your program to change this beh
|
|||||||
- ``zp clobber, restore``
|
- ``zp clobber, restore``
|
||||||
Use the whole zeropage, but make a backup copy of the original values at program start.
|
Use the whole zeropage, but make a backup copy of the original values at program start.
|
||||||
When your program exits, the original ZP is restored and you drop back to the BASIC prompt.
|
When your program exits, the original ZP is restored and you drop back to the BASIC prompt.
|
||||||
|
Not that the interrupts are *disabled* when your program is entered!
|
||||||
|
(you want/have to set your own IRQ routine because the default one will write to
|
||||||
|
various locations in the zeropage)
|
||||||
|
|
||||||
If you use ``zp clobber``, you can no longer use BASIC or KERNAL routines,
|
If you use ``zp clobber``, you can no longer use BASIC or KERNAL routines,
|
||||||
because these depend on most of the locations in the ZP. This includes most of the floating-point
|
because these depend on most of the locations in the ZP. This includes most of the floating-point
|
||||||
@ -231,7 +235,8 @@ want to work on later, because the contents of the ignored block are not syntact
|
|||||||
### Importing, Including and Binary-Including Files
|
### Importing, Including and Binary-Including Files
|
||||||
|
|
||||||
import "filename[.ill]"
|
import "filename[.ill]"
|
||||||
Can only be used outside of a block (usually at the top of your file).
|
Must be used *after* any global option statements such as ``output``,
|
||||||
|
and can only be used outside of a block. But can otherwise occur between any blocks.
|
||||||
Reads everything from the named IL65 file at this point and compile it as a normal part of the program.
|
Reads everything from the named IL65 file at this point and compile it as a normal part of the program.
|
||||||
|
|
||||||
asminclude "filename.txt", scopelabel
|
asminclude "filename.txt", scopelabel
|
||||||
|
@ -21,13 +21,13 @@ start
|
|||||||
if_ge goto label
|
if_ge goto label
|
||||||
if_gt goto label
|
if_gt goto label
|
||||||
if_cc goto value
|
if_cc goto value
|
||||||
if_cc goto memvalue
|
;if_cc goto memvalue
|
||||||
if_cc goto #value
|
if_cc goto #value
|
||||||
if_cc goto #memvalue
|
;if_cc goto #memvalue
|
||||||
if_cc goto [value]
|
if_cc goto [value]
|
||||||
if_cc goto [memvalue]
|
;if_cc goto [memvalue]
|
||||||
if_cc goto $c000
|
;if_cc goto $c000
|
||||||
if_cc goto [$c000.word]
|
;if_cc goto [$c000.word]
|
||||||
|
|
||||||
label
|
label
|
||||||
; conditional if with a single 'truth' value (register)
|
; conditional if with a single 'truth' value (register)
|
||||||
@ -59,14 +59,20 @@ label2
|
|||||||
if_zero memvalue goto label3
|
if_zero memvalue goto label3
|
||||||
if memvalue goto label3
|
if memvalue goto label3
|
||||||
|
|
||||||
; conditional if with a single 'truth' value (indirect address)
|
|
||||||
if_true [$c000] goto label
|
|
||||||
if_not [$c000] goto label
|
|
||||||
if_zero [$c000] goto label
|
|
||||||
if [$c000] goto label
|
|
||||||
; if_true [XY] goto label ; @todo support indirect reg
|
|
||||||
|
|
||||||
label3
|
label3
|
||||||
|
; conditional if with a single 'truth' value (indirect address)
|
||||||
|
if_true [$c000] goto label4
|
||||||
|
if_not [$c000] goto label4
|
||||||
|
if_zero [$c000] goto label4
|
||||||
|
if [$c000] goto label4
|
||||||
|
if_true [XY] goto label4 ; @todo support indirect reg
|
||||||
|
if_true [AY] goto label4 ; @todo support indirect reg
|
||||||
|
if_true [AX] goto label4 ; @todo support indirect reg
|
||||||
|
if_true [X] goto label4 ; @todo support indirect reg
|
||||||
|
if_true [A] goto label4 ; @todo support indirect reg
|
||||||
|
if_true [Y] goto label4 ; @todo support indirect reg
|
||||||
|
|
||||||
|
label4
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
output prg,basic
|
output prg,basic
|
||||||
;reg_preserve off ; @todo global option
|
;reg_preserve off ; @todo global option off/on default off?
|
||||||
|
|
||||||
import "c64lib"
|
import "c64lib"
|
||||||
|
|
||||||
@ -14,70 +14,6 @@ import "c64lib"
|
|||||||
start
|
start
|
||||||
c64util.init_system()
|
c64util.init_system()
|
||||||
|
|
||||||
|
|
||||||
XY = $0401
|
|
||||||
c64util.print_word_decimal(XY)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
XY--
|
|
||||||
c64util.print_word_decimal(XY)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
XY--
|
|
||||||
c64util.print_word_decimal(XY)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
|
|
||||||
AX = $0401
|
|
||||||
c64util.print_word_decimal(AX)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
AX--
|
|
||||||
c64util.print_word_decimal(AX)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
AX--
|
|
||||||
c64util.print_word_decimal(AX)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
|
|
||||||
AY = $0401
|
|
||||||
c64util.print_word_decimal(AY)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
AY--
|
|
||||||
c64util.print_word_decimal(AY)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
AY--
|
|
||||||
c64util.print_word_decimal(AY)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
|
|
||||||
XY = $03ff
|
|
||||||
c64util.print_word_decimal(XY)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
XY++
|
|
||||||
c64util.print_word_decimal(XY)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
XY++
|
|
||||||
c64util.print_word_decimal(XY)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
|
|
||||||
AX = $03ff
|
|
||||||
c64util.print_word_decimal(AX)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
AX++
|
|
||||||
c64util.print_word_decimal(AX)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
AX++
|
|
||||||
c64util.print_word_decimal(AX)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
|
|
||||||
AY = $03ff
|
|
||||||
c64util.print_word_decimal(AY)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
AY++
|
|
||||||
c64util.print_word_decimal(AY)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
AY++
|
|
||||||
c64util.print_word_decimal(AY)
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
c64.CHROUT('\n')
|
|
||||||
|
|
||||||
|
|
||||||
A = c64.VMCSB
|
A = c64.VMCSB
|
||||||
A |= 2 ; @todo c64.VMCSB |= 2
|
A |= 2 ; @todo c64.VMCSB |= 2
|
||||||
c64.VMCSB = A
|
c64.VMCSB = A
|
||||||
@ -115,7 +51,7 @@ printloop
|
|||||||
c64util.print_string("es")
|
c64util.print_string("es")
|
||||||
ask_guess
|
ask_guess
|
||||||
c64util.print_string(" left.\nWhat is your next guess? ")
|
c64util.print_string(" left.\nWhat is your next guess? ")
|
||||||
A = c64util.input_chars(guess)
|
Y = c64util.input_chars(guess)
|
||||||
c64.CHROUT('\n')
|
c64.CHROUT('\n')
|
||||||
[$22.word] = guess
|
[$22.word] = guess
|
||||||
c64.FREADSTR(A)
|
c64.FREADSTR(A)
|
||||||
|
@ -32,14 +32,14 @@ start2
|
|||||||
c64util.print_string(greeting)
|
c64util.print_string(greeting)
|
||||||
c64util.print_pstring(p_greeting)
|
c64util.print_pstring(p_greeting)
|
||||||
c64util.print_byte_decimal(0)
|
c64util.print_byte_decimal(0)
|
||||||
c64util.print_byte_hex(0)
|
c64util.print_byte_hex(0, 0)
|
||||||
c64.CHROUT(13)
|
c64.CHROUT(13)
|
||||||
c64util.print_byte_decimal(13)
|
c64util.print_byte_decimal(13)
|
||||||
c64util.print_byte_hex(13)
|
c64util.print_byte_hex(0, 13)
|
||||||
c64.CHROUT(13)
|
c64.CHROUT(13)
|
||||||
c64util.print_byte_decimal(255)
|
c64util.print_byte_decimal(255)
|
||||||
c64util.print_byte_hex(254)
|
c64util.print_byte_hex(0, 254)
|
||||||
c64util.print_byte_hex(129)
|
c64util.print_byte_hex(0, 129)
|
||||||
c64.CHROUT(13)
|
c64.CHROUT(13)
|
||||||
|
|
||||||
c64.CHROUT(13)
|
c64.CHROUT(13)
|
||||||
|
27
todo.ill
Normal file
27
todo.ill
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
output prg,basic
|
||||||
|
|
||||||
|
import "c64lib"
|
||||||
|
import "mathlib"
|
||||||
|
|
||||||
|
|
||||||
|
~ main {
|
||||||
|
|
||||||
|
; zpvar myvar @todo allow for zp vars like this
|
||||||
|
var bytevar
|
||||||
|
var bytevar2
|
||||||
|
var .word wordvar
|
||||||
|
var .float fl1
|
||||||
|
var .float fl2
|
||||||
|
|
||||||
|
|
||||||
|
start
|
||||||
|
; XY() ; @todo better syntax error, need [XY]
|
||||||
|
[AX]()
|
||||||
|
[AY]()
|
||||||
|
[XY]()
|
||||||
|
[AX]!()
|
||||||
|
[AY]!()
|
||||||
|
[XY]!()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user