2017-12-21 21:16:46 +00:00
|
|
|
"""
|
2017-12-25 15:00:25 +00:00
|
|
|
Programming Language for 6502/6510 microprocessors, codename 'Sick'
|
2017-12-21 21:16:46 +00:00
|
|
|
This is the main program that drives the rest.
|
|
|
|
|
2018-01-08 02:31:23 +00:00
|
|
|
Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
2017-12-21 21:16:46 +00:00
|
|
|
"""
|
|
|
|
|
2017-12-25 01:07:17 +00:00
|
|
|
import time
|
2017-12-21 21:16:46 +00:00
|
|
|
import os
|
2018-01-14 14:18:50 +00:00
|
|
|
import re
|
2017-12-21 21:16:46 +00:00
|
|
|
import argparse
|
2017-12-27 22:45:22 +00:00
|
|
|
import subprocess
|
2018-01-09 01:40:32 +00:00
|
|
|
from .compile import PlyParser
|
|
|
|
from .optimize import optimize
|
2018-01-14 14:18:50 +00:00
|
|
|
from .emit.generate import AssemblyGenerator
|
2018-01-09 01:40:32 +00:00
|
|
|
from .plylex import print_bold
|
2018-01-14 14:18:50 +00:00
|
|
|
from .plyparse import ProgramFormat
|
|
|
|
|
|
|
|
|
|
|
|
class Assembler64Tass:
|
|
|
|
def __init__(self, format: ProgramFormat) -> None:
|
|
|
|
self.format = format
|
|
|
|
|
|
|
|
def assemble(self, inputfilename: str, outputfilename: str) -> None:
|
|
|
|
args = ["64tass", "--ascii", "--case-sensitive", "-Wall", "-Wno-strict-bool",
|
|
|
|
"--dump-labels", "--vice-labels", "-l", outputfilename+".vice-mon-list",
|
2018-01-23 20:20:01 +00:00
|
|
|
"--no-monitor", "--output", outputfilename, inputfilename]
|
2018-01-14 14:18:50 +00:00
|
|
|
if self.format in (ProgramFormat.PRG, ProgramFormat.BASIC):
|
|
|
|
args.append("--cbm-prg")
|
|
|
|
elif self.format == ProgramFormat.RAW:
|
|
|
|
args.append("--nostart")
|
|
|
|
else:
|
|
|
|
raise ValueError("don't know how to create code format "+str(self.format))
|
|
|
|
try:
|
|
|
|
if self.format == ProgramFormat.PRG:
|
|
|
|
print("\nCreating C-64 prg.")
|
|
|
|
elif self.format == ProgramFormat.RAW:
|
|
|
|
print("\nCreating raw binary.")
|
|
|
|
try:
|
|
|
|
subprocess.check_call(args)
|
|
|
|
except FileNotFoundError as x:
|
|
|
|
raise SystemExit("ERROR: cannot run assembler program: "+str(x))
|
|
|
|
except subprocess.CalledProcessError as x:
|
|
|
|
raise SystemExit("assembler failed with returncode " + str(x.returncode))
|
|
|
|
|
|
|
|
def generate_breakpoint_list(self, program_filename: str) -> str:
|
|
|
|
breakpoints = []
|
2018-01-23 20:20:01 +00:00
|
|
|
vice_mon_file = program_filename + ".vice-mon-list"
|
|
|
|
with open(vice_mon_file, "rU") as f:
|
2018-01-14 14:18:50 +00:00
|
|
|
for line in f:
|
2018-01-23 20:20:01 +00:00
|
|
|
match = re.fullmatch(r"al (?P<address>\w+) \S+_il65_breakpoint_\d+.?", line, re.DOTALL)
|
2018-01-14 14:18:50 +00:00
|
|
|
if match:
|
|
|
|
breakpoints.append("$" + match.group("address"))
|
2018-01-23 20:20:01 +00:00
|
|
|
with open(vice_mon_file, "at") as f:
|
2018-01-14 14:18:50 +00:00
|
|
|
print("; vice monitor breakpoint list now follows", file=f)
|
|
|
|
print("; {:d} breakpoints have been defined here".format(len(breakpoints)), file=f)
|
|
|
|
print("del", file=f)
|
|
|
|
for b in breakpoints:
|
|
|
|
print("break", b, file=f)
|
2018-01-23 20:20:01 +00:00
|
|
|
return vice_mon_file
|
2017-12-21 21:16:46 +00:00
|
|
|
|
|
|
|
|
|
|
|
def main() -> None:
|
|
|
|
description = "Compiler for IL65 language, code name 'Sick'"
|
|
|
|
ap = argparse.ArgumentParser(description=description)
|
|
|
|
ap.add_argument("-o", "--output", help="output directory")
|
2017-12-27 22:45:22 +00:00
|
|
|
ap.add_argument("-no", "--nooptimize", action="store_true", help="do not optimize the parse tree")
|
|
|
|
ap.add_argument("-sv", "--startvice", action="store_true", help="autostart vice x64 emulator after compilation")
|
2017-12-21 21:16:46 +00:00
|
|
|
ap.add_argument("sourcefile", help="the source .ill/.il65 file to compile")
|
|
|
|
args = ap.parse_args()
|
|
|
|
assembly_filename = os.path.splitext(args.sourcefile)[0] + ".asm"
|
|
|
|
program_filename = os.path.splitext(args.sourcefile)[0] + ".prg"
|
|
|
|
if args.output:
|
|
|
|
os.makedirs(args.output, mode=0o700, exist_ok=True)
|
|
|
|
assembly_filename = os.path.join(args.output, os.path.split(assembly_filename)[1])
|
|
|
|
program_filename = os.path.join(args.output, os.path.split(program_filename)[1])
|
|
|
|
|
|
|
|
print("\n" + description)
|
|
|
|
|
2017-12-25 01:07:17 +00:00
|
|
|
start = time.perf_counter()
|
2018-01-09 01:40:32 +00:00
|
|
|
print("\nParsing program source code.")
|
|
|
|
parser = PlyParser()
|
|
|
|
parsed_module = parser.parse_file(args.sourcefile)
|
|
|
|
if parsed_module:
|
2017-12-27 22:45:22 +00:00
|
|
|
if args.nooptimize:
|
2018-01-29 20:10:06 +00:00
|
|
|
print_bold("Optimizations disabled!")
|
2017-12-21 22:05:35 +00:00
|
|
|
else:
|
2018-01-09 23:44:11 +00:00
|
|
|
print("\nOptimizing code.")
|
2018-01-09 01:40:32 +00:00
|
|
|
optimize(parsed_module)
|
|
|
|
print("\nGenerating assembly code.")
|
|
|
|
cg = AssemblyGenerator(parsed_module)
|
|
|
|
cg.generate(assembly_filename)
|
|
|
|
assembler = Assembler64Tass(parsed_module.format)
|
2017-12-21 21:16:46 +00:00
|
|
|
assembler.assemble(assembly_filename, program_filename)
|
2017-12-27 22:45:22 +00:00
|
|
|
mon_command_file = assembler.generate_breakpoint_list(program_filename)
|
2017-12-25 01:07:17 +00:00
|
|
|
duration_total = time.perf_counter() - start
|
|
|
|
print("Compile duration: {:.2f} seconds".format(duration_total))
|
2018-01-13 01:13:32 +00:00
|
|
|
size = os.path.getsize(program_filename)
|
|
|
|
print("Output size: {:d} bytes".format(size))
|
2018-01-09 01:40:32 +00:00
|
|
|
print_bold("Output file: " + program_filename)
|
2017-12-21 21:16:46 +00:00
|
|
|
print()
|
2017-12-27 22:45:22 +00:00
|
|
|
if args.startvice:
|
|
|
|
print("Autostart vice emulator...")
|
2018-01-13 21:42:07 +00:00
|
|
|
# "-remotemonitor"
|
|
|
|
cmdline = ["x64", "-moncommands", mon_command_file,
|
2017-12-28 03:20:59 +00:00
|
|
|
"-autostartprgmode", "1", "-autostart-warp", "-autostart", program_filename]
|
2017-12-27 22:45:22 +00:00
|
|
|
with open(os.devnull, "wb") as shutup:
|
2017-12-28 03:20:59 +00:00
|
|
|
subprocess.call(cmdline, stdout=shutup)
|