mirror of
https://github.com/catseye/SixtyPical.git
synced 2024-11-29 18:49:22 +00:00
commit
3cd28bdb3e
17
HISTORY.md
17
HISTORY.md
@ -1,6 +1,23 @@
|
|||||||
History of SixtyPical
|
History of SixtyPical
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
|
0.17
|
||||||
|
----
|
||||||
|
|
||||||
|
* `save X, Y, Z { }` now allowed as a shortcut for nested `save`s.
|
||||||
|
* If the name in a location expression isn't found in the symbol
|
||||||
|
table, a forward reference will _always_ be generated; and forward
|
||||||
|
references in _all_ operations will be resolved after parsing.
|
||||||
|
* As a consequence, trying to call or goto a non-routine-typed symbol
|
||||||
|
is now an analysis error, not a syntax error.
|
||||||
|
* Deprecated `routine foo ...` syntax has been removed.
|
||||||
|
* Split TODO off into own file.
|
||||||
|
* `sixtypical` no longer writes the compiled binary to standard
|
||||||
|
output. The `--output` command-line argument should be given
|
||||||
|
to get a compiled binary; otherwise only analysis is run.
|
||||||
|
* Internal cleanups, including a hierarchy of `Outputters`.
|
||||||
|
* All tests pass when `sixtypical` is run under Python 3.5.2.
|
||||||
|
|
||||||
0.16
|
0.16
|
||||||
----
|
----
|
||||||
|
|
||||||
|
160
README.md
160
README.md
@ -1,32 +1,38 @@
|
|||||||
SixtyPical
|
SixtyPical
|
||||||
==========
|
==========
|
||||||
|
|
||||||
_Version 0.16. Work-in-progress, everything is subject to change._
|
_Version 0.17. Work-in-progress, everything is subject to change._
|
||||||
|
|
||||||
**SixtyPical** is a 6502-like programming language with advanced
|
**SixtyPical** is a low-level programming language with advanced
|
||||||
static analysis.
|
static analysis. Many of its primitive instructions resemble
|
||||||
|
those of the 6502 CPU — in fact it is intended to be compiled to
|
||||||
|
6502 machine code — but along with these instructions are
|
||||||
|
constructs which ease structuring and analyzing the code. The
|
||||||
|
language aims to fill this niche:
|
||||||
|
|
||||||
"6502-like" means that it has similar restrictions as programming
|
* You'd use assembly, but you don't want to spend hours
|
||||||
in 6502 assembly (e.g. the programmer must choose the registers that
|
debugging (say) a memory overrun that happened because of a
|
||||||
values will be stored in) and is concomitantly easy for a compiler to
|
ridiculous silly error.
|
||||||
translate it to 6502 machine language code.
|
* You'd use C or some other "high-level" language, but you don't
|
||||||
|
want the extra overhead added by the compiler to manage the
|
||||||
|
stack and registers.
|
||||||
|
|
||||||
"Advanced static analysis" includes _abstract interpretation_, where we
|
SixtyPical gives the programmer a coding regimen on par with assembly
|
||||||
go through the program step by step, tracking not just the changes that
|
language in terms of size and hands-on-ness, but also able to catch
|
||||||
happen during a _specific_ execution of the program, but _sets_ of changes
|
many ridiculous silly errors at compile time, such as
|
||||||
that could _possibly_ happen in any run of the program. This lets us
|
|
||||||
determine that certain things can never happen, which we can then formulate
|
|
||||||
as safety checks.
|
|
||||||
|
|
||||||
In practice, this means it catches things like
|
|
||||||
|
|
||||||
* you forgot to clear carry before adding something to the accumulator
|
* you forgot to clear carry before adding something to the accumulator
|
||||||
* a subroutine that you call trashes a register you thought was preserved
|
* a subroutine that you called trashes a register you thought it preserved
|
||||||
* you tried to read or write a byte beyond the end of a byte array
|
* you tried to read or write a byte beyond the end of a byte array
|
||||||
* you tried to write the address of something that was not a routine, to
|
* you tried to write the address of something that was not a routine, to
|
||||||
a jump vector
|
a jump vector
|
||||||
|
|
||||||
and suchlike. It also provides some convenient operations based on
|
Many of these checks are done with _abstract interpretation_, where we
|
||||||
|
go through the program step by step, tracking not just the changes that
|
||||||
|
happen during a _specific_ execution of the program, but _sets_ of changes
|
||||||
|
that could _possibly_ happen in any run of the program.
|
||||||
|
|
||||||
|
SixtyPical also provides some convenient operations based on
|
||||||
machine-language programming idioms, such as
|
machine-language programming idioms, such as
|
||||||
|
|
||||||
* copying values from one register to another (via a third register when
|
* copying values from one register to another (via a third register when
|
||||||
@ -35,8 +41,15 @@ machine-language programming idioms, such as
|
|||||||
* explicit tail calls
|
* explicit tail calls
|
||||||
* indirect subroutine calls
|
* indirect subroutine calls
|
||||||
|
|
||||||
The reference implementation can analyze and compile SixtyPical programs to
|
SixtyPical is defined by a specification document, a set of test cases,
|
||||||
6502 machine code.
|
and a reference implementation written in Python 2. The reference
|
||||||
|
implementation can analyze and compile SixtyPical programs to 6502 machine
|
||||||
|
code, which can be run on several 6502-based 8-bit architectures:
|
||||||
|
|
||||||
|
* Commodore 64
|
||||||
|
* Commodore VIC-20
|
||||||
|
* Atari 2600 VCS
|
||||||
|
* Apple II
|
||||||
|
|
||||||
Quick Start
|
Quick Start
|
||||||
-----------
|
-----------
|
||||||
@ -68,111 +81,4 @@ Documentation
|
|||||||
* [Literate test suite for SixtyPical fallthru optimization](tests/SixtyPical%20Fallthru.md)
|
* [Literate test suite for SixtyPical fallthru optimization](tests/SixtyPical%20Fallthru.md)
|
||||||
* [6502 Opcodes used/not used in SixtyPical](doc/6502%20Opcodes.md)
|
* [6502 Opcodes used/not used in SixtyPical](doc/6502%20Opcodes.md)
|
||||||
* [Output formats supported by `sixtypical`](doc/Output%20Formats.md)
|
* [Output formats supported by `sixtypical`](doc/Output%20Formats.md)
|
||||||
|
* [TODO](TODO.md)
|
||||||
TODO
|
|
||||||
----
|
|
||||||
|
|
||||||
### `low` and `high` address operators
|
|
||||||
|
|
||||||
To turn `word` type into `byte`.
|
|
||||||
|
|
||||||
Trying to remember if we have a compelling case for this or now. The best I can think
|
|
||||||
of is for implementing 16-bit `cmp` in an efficient way. Maybe we should see if we
|
|
||||||
can get by with 16-bit `cmp` instead though.
|
|
||||||
|
|
||||||
The problem is that once a byte is extracted, putting it back into a word is awkward.
|
|
||||||
The address operators have to modify a destination in a special way. That is, when
|
|
||||||
you say `st a, >word`, you are updating `word` to be `word & $ff | a << 8`, somelike.
|
|
||||||
Is that consistent with `st`? Well, probably it is, but we have to explain it.
|
|
||||||
It might make more sense, then, for it to be "part of the operation" instead of "part of
|
|
||||||
the reference"; something like `st.hi x, word`; `st.lo y, word`. Dunno.
|
|
||||||
|
|
||||||
### Save multiple values in single block
|
|
||||||
|
|
||||||
As a shortcut for the idiom
|
|
||||||
|
|
||||||
save a { save var {
|
|
||||||
...
|
|
||||||
} }
|
|
||||||
|
|
||||||
allow
|
|
||||||
|
|
||||||
save a, var {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
### Save values to other-than-the-stack
|
|
||||||
|
|
||||||
Allow
|
|
||||||
|
|
||||||
save a to temp_a {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
Which uses some other storage location instead of the stack. A local static
|
|
||||||
would be a good candidate for such.
|
|
||||||
|
|
||||||
### Make all symbols forward-referencable
|
|
||||||
|
|
||||||
Basically, don't do symbol-table lookups when parsing, but do have a more formal
|
|
||||||
"symbol resolution" (linking) phase right after parsing.
|
|
||||||
|
|
||||||
### Associate each pointer with the buffer it points into
|
|
||||||
|
|
||||||
Check that the buffer being read or written to through pointer, appears in appropriate
|
|
||||||
inputs or outputs set.
|
|
||||||
|
|
||||||
In the analysis, when we obtain a pointer, we need to record, in contect, what buffer
|
|
||||||
that pointer came from.
|
|
||||||
|
|
||||||
When we write through that pointer, we need to set that buffer as written.
|
|
||||||
|
|
||||||
When we read through the pointer, we need to check that the buffer is readable.
|
|
||||||
|
|
||||||
### Table overlays
|
|
||||||
|
|
||||||
They are uninitialized, but the twist is, the address is a buffer that is
|
|
||||||
an input to and/or output of the routine. So, they are defined (insofar
|
|
||||||
as the buffer is defined.)
|
|
||||||
|
|
||||||
They are therefore a "view" of a section of a buffer.
|
|
||||||
|
|
||||||
This is slightly dangerous since it does permit aliases: the buffer and the
|
|
||||||
table refer to the same memory.
|
|
||||||
|
|
||||||
Although, if they are `static`, you could say, in the routine in which they
|
|
||||||
are `static`, as soon as you've established one, you can no longer use the
|
|
||||||
buffer; and the ones you establish must be disjoint.
|
|
||||||
|
|
||||||
(That seems to be the most compelling case for restricting them to `static`.)
|
|
||||||
|
|
||||||
An alternative would be `static` pointers, which are currently not possible because
|
|
||||||
pointers must be zero-page, thus `@`, thus uninitialized.
|
|
||||||
|
|
||||||
### Question "consistent initialization"
|
|
||||||
|
|
||||||
Question the value of the "consistent initialization" principle for `if` statement analysis.
|
|
||||||
|
|
||||||
Part of this is the trashes at the end; I think what it should be is that the trashes
|
|
||||||
after the `if` is the union of the trashes in each of the branches; this would obviate the
|
|
||||||
need to `trash` values explicitly, but if you tried to access them afterwards, it would still
|
|
||||||
error.
|
|
||||||
|
|
||||||
### Tail-call optimization
|
|
||||||
|
|
||||||
More generally, define a block as having zero or one `goto`s at the end. (and `goto`s cannot
|
|
||||||
appear elsewhere.)
|
|
||||||
|
|
||||||
If a block ends in a `call` can that be converted to end in a `goto`? Why not? I think it can.
|
|
||||||
The constraints should iron out the same both ways.
|
|
||||||
|
|
||||||
And - once we have this - why do we need `goto` to be in tail position, strictly?
|
|
||||||
As long as the routine has consistent type context every place it exits, that should be fine.
|
|
||||||
|
|
||||||
### "Include" directives
|
|
||||||
|
|
||||||
Search a searchlist of include paths. And use them to make libraries of routines.
|
|
||||||
|
|
||||||
One such library routine might be an `interrupt routine` type for various architectures.
|
|
||||||
Since "the supervisor" has stored values on the stack, we should be able to trash them
|
|
||||||
with impunity, in such a routine.
|
|
||||||
|
89
TODO.md
Normal file
89
TODO.md
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
TODO for SixtyPical
|
||||||
|
===================
|
||||||
|
|
||||||
|
### 16-bit `cmp`
|
||||||
|
|
||||||
|
This is because we don't actually want `low` and `high` address operators
|
||||||
|
that turn `word` type into `byte`.
|
||||||
|
|
||||||
|
This is because this immediately makes things harder (that is, effectively
|
||||||
|
impossible) to analyze.
|
||||||
|
|
||||||
|
16-bit `cmp` also benefits from some special differences between `cmp`
|
||||||
|
and `sub` on 6502, so it would be nice to capture them.
|
||||||
|
|
||||||
|
### Save values to other-than-the-stack
|
||||||
|
|
||||||
|
Allow
|
||||||
|
|
||||||
|
save a to temp_a {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
Which uses some other storage location instead of the stack. A local static
|
||||||
|
would be a good candidate for such.
|
||||||
|
|
||||||
|
### Associate each pointer with the buffer it points into
|
||||||
|
|
||||||
|
Check that the buffer being read or written to through pointer, appears in appropriate
|
||||||
|
inputs or outputs set.
|
||||||
|
|
||||||
|
In the analysis, when we obtain a pointer, we need to record, in context, what buffer
|
||||||
|
that pointer came from.
|
||||||
|
|
||||||
|
When we write through that pointer, we need to set that buffer as written.
|
||||||
|
|
||||||
|
When we read through the pointer, we need to check that the buffer is readable.
|
||||||
|
|
||||||
|
### Table overlays
|
||||||
|
|
||||||
|
They are uninitialized, but the twist is, the address is a buffer that is
|
||||||
|
an input to and/or output of the routine. So, they are defined (insofar
|
||||||
|
as the buffer is defined.)
|
||||||
|
|
||||||
|
They are therefore a "view" of a section of a buffer.
|
||||||
|
|
||||||
|
This is slightly dangerous since it does permit aliases: the buffer and the
|
||||||
|
table refer to the same memory.
|
||||||
|
|
||||||
|
Although, if they are `static`, you could say, in the routine in which they
|
||||||
|
are `static`, as soon as you've established one, you can no longer use the
|
||||||
|
buffer; and the ones you establish must be disjoint.
|
||||||
|
|
||||||
|
(That seems to be the most compelling case for restricting them to `static`.)
|
||||||
|
|
||||||
|
An alternative would be `static` pointers, which are currently not possible because
|
||||||
|
pointers must be zero-page, thus `@`, thus uninitialized.
|
||||||
|
|
||||||
|
### Question "consistent initialization"
|
||||||
|
|
||||||
|
Question the value of the "consistent initialization" principle for `if` statement analysis.
|
||||||
|
|
||||||
|
Part of this is the trashes at the end; I think what it should be is that the trashes
|
||||||
|
after the `if` is the union of the trashes in each of the branches; this would obviate the
|
||||||
|
need to `trash` values explicitly, but if you tried to access them afterwards, it would still
|
||||||
|
error.
|
||||||
|
|
||||||
|
### Tail-call optimization
|
||||||
|
|
||||||
|
More generally, define a block as having zero or one `goto`s at the end. (and `goto`s cannot
|
||||||
|
appear elsewhere.)
|
||||||
|
|
||||||
|
If a block ends in a `call` can that be converted to end in a `goto`? Why not? I think it can,
|
||||||
|
if the block is in tail position. The constraints should iron out the same both ways.
|
||||||
|
|
||||||
|
And - once we have this - why do we need `goto` to be in tail position, strictly?
|
||||||
|
As long as the routine has consistent type context every place it exits, that should be fine.
|
||||||
|
|
||||||
|
### "Include" directives
|
||||||
|
|
||||||
|
Search a searchlist of include paths. And use them to make libraries of routines.
|
||||||
|
|
||||||
|
One such library routine might be an `interrupt routine` type for various architectures.
|
||||||
|
Since "the supervisor" has stored values on the stack, we should be able to trash them
|
||||||
|
with impunity, in such a routine.
|
||||||
|
|
||||||
|
### Line numbers in analysis error messages
|
||||||
|
|
||||||
|
For analysis errors, there is a line number, but it's the line of the routine
|
||||||
|
after the routine in which the analysis error occurred. Fix this.
|
@ -18,25 +18,12 @@ from pprint import pprint
|
|||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from sixtypical.parser import Parser, ParsingContext
|
from sixtypical.parser import Parser, ParsingContext, merge_programs
|
||||||
from sixtypical.analyzer import Analyzer
|
from sixtypical.analyzer import Analyzer
|
||||||
from sixtypical.emitter import Emitter, Byte, Word
|
from sixtypical.outputter import outputter_class_for
|
||||||
from sixtypical.compiler import Compiler
|
from sixtypical.compiler import Compiler
|
||||||
|
|
||||||
|
|
||||||
def merge_programs(programs):
|
|
||||||
"""Assumes that the programs do not have any conflicts."""
|
|
||||||
|
|
||||||
from sixtypical.ast import Program
|
|
||||||
|
|
||||||
full = Program(1, defns=[], routines=[])
|
|
||||||
for p in programs:
|
|
||||||
full.defns.extend(p.defns)
|
|
||||||
full.routines.extend(p.routines)
|
|
||||||
|
|
||||||
return full
|
|
||||||
|
|
||||||
|
|
||||||
def process_input_files(filenames, options):
|
def process_input_files(filenames, options):
|
||||||
context = ParsingContext()
|
context = ParsingContext()
|
||||||
|
|
||||||
@ -68,7 +55,7 @@ def process_input_files(filenames, options):
|
|||||||
return
|
return
|
||||||
if label:
|
if label:
|
||||||
sys.stdout.write("*** {}:\n".format(label))
|
sys.stdout.write("*** {}:\n".format(label))
|
||||||
sys.stdout.write(json.dumps(data, indent=4, sort_keys=True))
|
sys.stdout.write(json.dumps(data, indent=4, sort_keys=True, separators=(',', ':')))
|
||||||
sys.stdout.write("\n")
|
sys.stdout.write("\n")
|
||||||
|
|
||||||
fa = FallthruAnalyzer(debug=options.debug)
|
fa = FallthruAnalyzer(debug=options.debug)
|
||||||
@ -76,60 +63,26 @@ def process_input_files(filenames, options):
|
|||||||
compilation_roster = fa.serialize()
|
compilation_roster = fa.serialize()
|
||||||
dump(compilation_roster)
|
dump(compilation_roster)
|
||||||
|
|
||||||
if options.analyze_only:
|
if options.analyze_only or options.output is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
fh = sys.stdout
|
start_addr = None
|
||||||
|
|
||||||
if options.output_format == 'raw':
|
|
||||||
start_addr = 0x0000
|
|
||||||
prelude = []
|
|
||||||
elif options.output_format == 'prg':
|
|
||||||
start_addr = 0xc000
|
|
||||||
prelude = []
|
|
||||||
elif options.output_format == 'c64-basic-prg':
|
|
||||||
start_addr = 0x0801
|
|
||||||
prelude = [0x10, 0x08, 0xc9, 0x07, 0x9e, 0x32,
|
|
||||||
0x30, 0x36, 0x31, 0x00, 0x00, 0x00]
|
|
||||||
elif options.output_format == 'vic20-basic-prg':
|
|
||||||
start_addr = 0x1001
|
|
||||||
prelude = [0x0b, 0x10, 0xc9, 0x07, 0x9e, 0x34,
|
|
||||||
0x31, 0x30, 0x39, 0x00, 0x00, 0x00]
|
|
||||||
elif options.output_format == 'atari2600-cart':
|
|
||||||
start_addr = 0xf000
|
|
||||||
prelude = [0x78, 0xd8, 0xa2, 0xff, 0x9a, 0xa9,
|
|
||||||
0x00, 0x95, 0x00, 0xca, 0xd0, 0xfb]
|
|
||||||
else:
|
|
||||||
raise NotImplementedError("Unknown output format: {}".format(options.output_format))
|
|
||||||
|
|
||||||
if options.origin is not None:
|
if options.origin is not None:
|
||||||
if options.origin.startswith('0x'):
|
if options.origin.startswith('0x'):
|
||||||
start_addr = int(options.origin, 16)
|
start_addr = int(options.origin, 16)
|
||||||
else:
|
else:
|
||||||
start_addr = int(options.origin, 10)
|
start_addr = int(options.origin, 10)
|
||||||
|
|
||||||
# If we are outputting a .PRG, we output the load address first.
|
with open(options.output, 'wb') as fh:
|
||||||
# We don't use the Emitter for this b/c not part of addr space.
|
outputter = outputter_class_for(options.output_format)(fh, start_addr=start_addr)
|
||||||
if options.output_format in ('prg', 'c64-basic-prg', 'vic20-basic-prg'):
|
outputter.write_prelude()
|
||||||
fh.write(Word(start_addr).serialize(0))
|
compiler = Compiler(outputter.emitter)
|
||||||
|
compiler.compile_program(program, compilation_roster=compilation_roster)
|
||||||
emitter = Emitter(start_addr)
|
outputter.write_postlude()
|
||||||
for byte in prelude:
|
if options.debug:
|
||||||
emitter.emit(Byte(byte))
|
pprint(outputter.emitter)
|
||||||
compiler = Compiler(emitter)
|
else:
|
||||||
compiler.compile_program(program, compilation_roster=compilation_roster)
|
outputter.emitter.serialize_to(fh)
|
||||||
|
|
||||||
# If we are outputting a cartridge with boot and BRK address
|
|
||||||
# at the end, pad to ROM size minus 4 bytes, and emit addresses.
|
|
||||||
if options.output_format == 'atari2600-cart':
|
|
||||||
emitter.pad_to_size(4096 - 4)
|
|
||||||
emitter.emit(Word(start_addr))
|
|
||||||
emitter.emit(Word(start_addr))
|
|
||||||
|
|
||||||
if options.debug:
|
|
||||||
pprint(emitter.accum)
|
|
||||||
else:
|
|
||||||
emitter.serialize(fh)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
@ -140,6 +93,10 @@ if __name__ == '__main__':
|
|||||||
help="The SixtyPical source files to compile."
|
help="The SixtyPical source files to compile."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
argparser.add_argument(
|
||||||
|
"--output", "-o", type=str, metavar='FILENAME',
|
||||||
|
help="File to which generated 6502 code will be written."
|
||||||
|
)
|
||||||
argparser.add_argument(
|
argparser.add_argument(
|
||||||
"--origin", type=str, default=None,
|
"--origin", type=str, default=None,
|
||||||
help="Location in memory where the `main` routine will be "
|
help="Location in memory where the `main` routine will be "
|
||||||
|
@ -8,8 +8,7 @@ Output Formats
|
|||||||
The file contains only the emitted bytes of the compiled SixtyPical
|
The file contains only the emitted bytes of the compiled SixtyPical
|
||||||
program.
|
program.
|
||||||
|
|
||||||
The default origin is $0000; it is not unlikely you will want to
|
The default origin is $0000; you will likely want to override this.
|
||||||
override this.
|
|
||||||
|
|
||||||
Note that the origin is not stored in the output file in this format;
|
Note that the origin is not stored in the output file in this format;
|
||||||
that information must be recorded separately.
|
that information must be recorded separately.
|
||||||
@ -20,8 +19,7 @@ The first two bytes of the file contain the origin address in
|
|||||||
little-endian format. The remainder of the file is the emitted bytes
|
little-endian format. The remainder of the file is the emitted bytes
|
||||||
of the compiled SixtyPical program, starting at that origin.
|
of the compiled SixtyPical program, starting at that origin.
|
||||||
|
|
||||||
The default origin is $C000; it is likely you will want to
|
The default origin is $C000; you will likely want override this.
|
||||||
override this.
|
|
||||||
|
|
||||||
This format coincides with Commodore's PRG format for disk files,
|
This format coincides with Commodore's PRG format for disk files,
|
||||||
thus its name.
|
thus its name.
|
||||||
|
20
eg/apple2/lores.60p
Normal file
20
eg/apple2/lores.60p
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
byte ds_graphics @ $C050
|
||||||
|
byte ds_text @ $C051
|
||||||
|
byte ds_full @ $C052
|
||||||
|
byte ds_split @ $C053
|
||||||
|
byte ds_page1 @ $C054
|
||||||
|
byte ds_page2 @ $C055
|
||||||
|
byte ds_lores @ $C056
|
||||||
|
byte ds_hires @ $C057
|
||||||
|
|
||||||
|
define main routine
|
||||||
|
inputs a
|
||||||
|
outputs ds_lores, ds_page1, ds_split, ds_graphics
|
||||||
|
trashes a, z, n
|
||||||
|
{
|
||||||
|
ld a, 0
|
||||||
|
st a, ds_lores
|
||||||
|
st a, ds_page1
|
||||||
|
st a, ds_split
|
||||||
|
st a, ds_graphics
|
||||||
|
}
|
19
eg/apple2/print.60p
Normal file
19
eg/apple2/print.60p
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// Write ">AB>" to "standard output"
|
||||||
|
|
||||||
|
define cout routine
|
||||||
|
inputs a
|
||||||
|
trashes a
|
||||||
|
@ $FDED
|
||||||
|
|
||||||
|
define main routine
|
||||||
|
trashes a, z, n
|
||||||
|
{
|
||||||
|
ld a, 62
|
||||||
|
call cout
|
||||||
|
ld a, 65
|
||||||
|
call cout
|
||||||
|
ld a, 66
|
||||||
|
call cout
|
||||||
|
ld a, 62
|
||||||
|
call cout
|
||||||
|
}
|
@ -33,9 +33,11 @@
|
|||||||
typedef routine
|
typedef routine
|
||||||
inputs joy2, press_fire_msg, dispatch_game_state,
|
inputs joy2, press_fire_msg, dispatch_game_state,
|
||||||
actor_pos, actor_delta, actor_logic,
|
actor_pos, actor_delta, actor_logic,
|
||||||
|
player_died,
|
||||||
screen, screen1, screen2, screen3, screen4, colormap1, colormap2, colormap3, colormap4
|
screen, screen1, screen2, screen3, screen4, colormap1, colormap2, colormap3, colormap4
|
||||||
outputs dispatch_game_state,
|
outputs dispatch_game_state,
|
||||||
actor_pos, actor_delta, actor_logic,
|
actor_pos, actor_delta, actor_logic,
|
||||||
|
player_died,
|
||||||
screen, screen1, screen2, screen3, screen4, colormap1, colormap2, colormap3, colormap4
|
screen, screen1, screen2, screen3, screen4, colormap1, colormap2, colormap3, colormap4
|
||||||
trashes a, x, y, c, z, n, v, pos, new_pos, delta, ptr, dispatch_logic
|
trashes a, x, y, c, z, n, v, pos, new_pos, delta, ptr, dispatch_logic
|
||||||
game_state_routine
|
game_state_routine
|
||||||
@ -45,13 +47,13 @@ typedef routine
|
|||||||
//
|
//
|
||||||
// Routines that conform to this type also follow this convention:
|
// Routines that conform to this type also follow this convention:
|
||||||
//
|
//
|
||||||
// Set carry if the player perished. Carry clear otherwise.
|
// Set player_died to 1 if the player perished. Unchanged otherwise.
|
||||||
//
|
//
|
||||||
|
|
||||||
typedef routine
|
typedef routine
|
||||||
inputs pos, delta, joy2, screen
|
inputs pos, delta, joy2, screen, player_died
|
||||||
outputs pos, delta, new_pos, screen, c
|
outputs pos, delta, new_pos, screen, player_died
|
||||||
trashes a, x, y, z, n, v, ptr
|
trashes a, x, y, z, n, v, c, ptr
|
||||||
logic_routine
|
logic_routine
|
||||||
|
|
||||||
// ----------------------------------------------------------------
|
// ----------------------------------------------------------------
|
||||||
@ -87,6 +89,8 @@ word new_pos
|
|||||||
word table[256] actor_delta
|
word table[256] actor_delta
|
||||||
word delta
|
word delta
|
||||||
|
|
||||||
|
byte player_died
|
||||||
|
|
||||||
vector logic_routine table[256] actor_logic
|
vector logic_routine table[256] actor_logic
|
||||||
vector logic_routine dispatch_logic
|
vector logic_routine dispatch_logic
|
||||||
|
|
||||||
@ -117,7 +121,7 @@ vector game_state_routine
|
|||||||
// Utility Routines
|
// Utility Routines
|
||||||
// ----------------------------------------------------------------
|
// ----------------------------------------------------------------
|
||||||
|
|
||||||
routine read_stick
|
define read_stick routine
|
||||||
inputs joy2
|
inputs joy2
|
||||||
outputs delta
|
outputs delta
|
||||||
trashes a, x, z, n
|
trashes a, x, z, n
|
||||||
@ -182,7 +186,7 @@ define check_button routine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
routine clear_screen
|
define clear_screen routine
|
||||||
outputs screen1, screen2, screen3, screen4, colormap1, colormap2, colormap3, colormap4
|
outputs screen1, screen2, screen3, screen4, colormap1, colormap2, colormap3, colormap4
|
||||||
trashes a, y, c, n, z
|
trashes a, y, c, n, z
|
||||||
{
|
{
|
||||||
@ -205,7 +209,7 @@ routine clear_screen
|
|||||||
} until z
|
} until z
|
||||||
}
|
}
|
||||||
|
|
||||||
routine calculate_new_position
|
define calculate_new_position routine
|
||||||
inputs pos, delta
|
inputs pos, delta
|
||||||
outputs new_pos
|
outputs new_pos
|
||||||
trashes a, c, n, z, v
|
trashes a, c, n, z, v
|
||||||
@ -239,9 +243,9 @@ define check_new_position_in_bounds routine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
routine init_game
|
define init_game routine
|
||||||
inputs actor_pos, actor_delta, actor_logic
|
inputs actor_pos, actor_delta, actor_logic
|
||||||
outputs actor_pos, actor_delta, actor_logic
|
outputs actor_pos, actor_delta, actor_logic, player_died
|
||||||
trashes pos, a, y, z, n, c, v
|
trashes pos, a, y, z, n, c, v
|
||||||
{
|
{
|
||||||
ld y, 0
|
ld y, 0
|
||||||
@ -259,9 +263,11 @@ routine init_game
|
|||||||
} until z
|
} until z
|
||||||
|
|
||||||
ld y, 0
|
ld y, 0
|
||||||
copy word 0, actor_pos + y
|
copy word 40, actor_pos + y
|
||||||
copy word 0, actor_delta + y
|
copy word 0, actor_delta + y
|
||||||
copy player_logic, actor_logic + y
|
copy player_logic, actor_logic + y
|
||||||
|
|
||||||
|
st y, player_died
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------
|
// ----------------------------------------------------------------
|
||||||
@ -301,10 +307,9 @@ define player_logic logic_routine
|
|||||||
st off, c
|
st off, c
|
||||||
add ptr, pos
|
add ptr, pos
|
||||||
copy 81, [ptr] + y
|
copy 81, [ptr] + y
|
||||||
|
|
||||||
st off, c
|
|
||||||
} else {
|
} else {
|
||||||
st on, c
|
ld a, 1
|
||||||
|
st a, player_died
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME these trashes, strictly speaking, probably shouldn't be needed,
|
// FIXME these trashes, strictly speaking, probably shouldn't be needed,
|
||||||
@ -314,8 +319,6 @@ define player_logic logic_routine
|
|||||||
trash ptr
|
trash ptr
|
||||||
trash y
|
trash y
|
||||||
trash v
|
trash v
|
||||||
} else {
|
|
||||||
st off, c
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,10 +354,6 @@ define enemy_logic logic_routine
|
|||||||
st off, c
|
st off, c
|
||||||
add ptr, pos
|
add ptr, pos
|
||||||
copy 82, [ptr] + y
|
copy 82, [ptr] + y
|
||||||
|
|
||||||
st off, c
|
|
||||||
} else {
|
|
||||||
st on, c
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME these trashes, strictly speaking, probably shouldn't be needed,
|
// FIXME these trashes, strictly speaking, probably shouldn't be needed,
|
||||||
@ -373,8 +372,6 @@ define enemy_logic logic_routine
|
|||||||
copy $ffd8, delta
|
copy $ffd8, delta
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
st off, c
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------
|
// ----------------------------------------------------------------
|
||||||
@ -408,6 +405,7 @@ define game_state_title_screen game_state_routine
|
|||||||
define game_state_play game_state_routine
|
define game_state_play game_state_routine
|
||||||
{
|
{
|
||||||
ld x, 0
|
ld x, 0
|
||||||
|
st x, player_died
|
||||||
for x up to 15 {
|
for x up to 15 {
|
||||||
copy actor_pos + x, pos
|
copy actor_pos + x, pos
|
||||||
copy actor_delta + x, delta
|
copy actor_delta + x, delta
|
||||||
@ -420,18 +418,19 @@ define game_state_play game_state_routine
|
|||||||
save x {
|
save x {
|
||||||
copy actor_logic + x, dispatch_logic
|
copy actor_logic + x, dispatch_logic
|
||||||
call dispatch_logic
|
call dispatch_logic
|
||||||
|
|
||||||
if c {
|
|
||||||
// Player died! Want no dead!
|
|
||||||
call clear_screen
|
|
||||||
copy game_state_game_over, dispatch_game_state
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
copy pos, actor_pos + x
|
copy pos, actor_pos + x
|
||||||
copy delta, actor_delta + x
|
copy delta, actor_delta + x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ld a, player_died
|
||||||
|
if not z {
|
||||||
|
// Player died! Want no dead!
|
||||||
|
call clear_screen
|
||||||
|
copy game_state_game_over, dispatch_game_state
|
||||||
|
}
|
||||||
|
|
||||||
goto save_cinv
|
goto save_cinv
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,7 +457,7 @@ define our_cinv game_state_routine
|
|||||||
goto dispatch_game_state
|
goto dispatch_game_state
|
||||||
}
|
}
|
||||||
|
|
||||||
routine main
|
define main routine
|
||||||
inputs cinv
|
inputs cinv
|
||||||
outputs cinv, save_cinv, pos, dispatch_game_state,
|
outputs cinv, save_cinv, pos, dispatch_game_state,
|
||||||
screen1, screen2, screen3, screen4, colormap1, colormap2, colormap3, colormap4
|
screen1, screen2, screen3, screen4, colormap1, colormap2, colormap3, colormap4
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
// Define where the screen starts in memory:
|
// Define where the screen starts in memory:
|
||||||
byte table[256] screen @ 1024
|
byte table[256] screen @ 1024
|
||||||
|
|
||||||
routine main
|
define main routine
|
||||||
// These are the values that will be written to by this routine:
|
// These are the values that will be written to by this routine:
|
||||||
trashes a, x, z, n, screen
|
trashes a, x, z, n, screen
|
||||||
{
|
{
|
||||||
|
@ -24,7 +24,7 @@ vector routine
|
|||||||
trashes z, n
|
trashes z, n
|
||||||
save_cinv
|
save_cinv
|
||||||
|
|
||||||
routine our_cinv
|
define our_cinv routine
|
||||||
inputs vic_border
|
inputs vic_border
|
||||||
outputs vic_border
|
outputs vic_border
|
||||||
trashes z, n
|
trashes z, n
|
||||||
@ -33,7 +33,7 @@ routine our_cinv
|
|||||||
goto save_cinv
|
goto save_cinv
|
||||||
}
|
}
|
||||||
|
|
||||||
routine main
|
define main routine
|
||||||
inputs cinv
|
inputs cinv
|
||||||
outputs cinv, save_cinv
|
outputs cinv, save_cinv
|
||||||
trashes a, n, z
|
trashes a, n, z
|
||||||
|
@ -3,7 +3,7 @@ byte joy2 @ $dc00
|
|||||||
|
|
||||||
word delta
|
word delta
|
||||||
|
|
||||||
routine read_stick
|
define read_stick routine
|
||||||
inputs joy2
|
inputs joy2
|
||||||
outputs delta
|
outputs delta
|
||||||
trashes a, x, z, n
|
trashes a, x, z, n
|
||||||
@ -36,7 +36,7 @@ routine read_stick
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
routine main
|
define main routine
|
||||||
inputs joy2
|
inputs joy2
|
||||||
outputs delta
|
outputs delta
|
||||||
trashes a, x, z, n, screen
|
trashes a, x, z, n, screen
|
||||||
|
@ -49,7 +49,7 @@ byte scanline : 85 // %01010101
|
|||||||
// generating them as part of a SixtyPical program would not
|
// generating them as part of a SixtyPical program would not
|
||||||
// be practical. So we just jump to this location instead.
|
// be practical. So we just jump to this location instead.
|
||||||
|
|
||||||
routine pla_tay_pla_tax_pla_rti
|
define pla_tay_pla_tax_pla_rti routine
|
||||||
inputs a
|
inputs a
|
||||||
trashes a
|
trashes a
|
||||||
@ $EA81
|
@ $EA81
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
byte screen @ 1024
|
byte screen @ 1024
|
||||||
|
|
||||||
routine main
|
define main routine
|
||||||
trashes a, z, n, screen
|
trashes a, z, n, screen
|
||||||
{
|
{
|
||||||
ld a, 83
|
ld a, 83
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
routine add_four
|
define add_four routine
|
||||||
inputs a
|
inputs a
|
||||||
outputs a
|
outputs a
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
routine main
|
define main routine
|
||||||
inputs a
|
inputs a
|
||||||
outputs a
|
outputs a
|
||||||
trashes c, z, n, v
|
trashes c, z, n, v
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
word score
|
word score
|
||||||
routine main
|
define main routine
|
||||||
inputs score
|
inputs score
|
||||||
outputs score
|
outputs score
|
||||||
trashes a, c, z, v, n
|
trashes a, c, z, v, n
|
||||||
|
@ -2,7 +2,7 @@ buffer[2048] buf
|
|||||||
pointer ptr @ 254
|
pointer ptr @ 254
|
||||||
byte foo
|
byte foo
|
||||||
|
|
||||||
routine main
|
define main routine
|
||||||
inputs buf
|
inputs buf
|
||||||
outputs buf, y, foo
|
outputs buf, y, foo
|
||||||
trashes a, z, n, ptr
|
trashes a, z, n, ptr
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
routine chrout
|
define chrout routine
|
||||||
inputs a
|
inputs a
|
||||||
trashes a
|
trashes a
|
||||||
@ 65490
|
@ 65490
|
||||||
|
|
||||||
routine print
|
define print routine
|
||||||
trashes a, z, n
|
trashes a, z, n
|
||||||
{
|
{
|
||||||
ld a, 65
|
ld a, 65
|
||||||
call chrout
|
call chrout
|
||||||
}
|
}
|
||||||
|
|
||||||
routine main
|
define main routine
|
||||||
trashes a, z, n
|
trashes a, z, n
|
||||||
{
|
{
|
||||||
call print
|
call print
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
routine chrout
|
define chrout routine
|
||||||
inputs a
|
inputs a
|
||||||
trashes a
|
trashes a
|
||||||
@ 65490
|
@ 65490
|
||||||
|
|
||||||
routine main
|
define main routine
|
||||||
trashes a, x, y, z, n, c, v
|
trashes a, x, y, z, n, c, v
|
||||||
{
|
{
|
||||||
ld a, 0
|
ld a, 0
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
routine chrout
|
define chrout routine
|
||||||
inputs a
|
inputs a
|
||||||
trashes a
|
trashes a
|
||||||
@ 65490
|
@ 65490
|
||||||
|
|
||||||
routine main
|
define main routine
|
||||||
trashes a, x, y, z, n, c, v
|
trashes a, x, y, z, n, c, v
|
||||||
{
|
{
|
||||||
ld a, 0
|
ld a, 0
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
byte bar
|
byte bar
|
||||||
byte baz
|
byte baz
|
||||||
|
|
||||||
routine main
|
define main routine
|
||||||
inputs baz
|
inputs baz
|
||||||
outputs bar
|
outputs bar
|
||||||
trashes a, n, z
|
trashes a, n, z
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
byte lives
|
byte lives
|
||||||
|
|
||||||
routine main
|
define main routine
|
||||||
inputs lives
|
inputs lives
|
||||||
outputs lives
|
outputs lives
|
||||||
trashes a, x
|
trashes a, x, z, n, c, v
|
||||||
{
|
{
|
||||||
ld a, 0
|
ld a, 0
|
||||||
st a, lives
|
st a, lives
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
routine main
|
define main routine
|
||||||
trashes a, y, z, n, c
|
trashes a, y, z, n, c
|
||||||
{
|
{
|
||||||
ld y, 65
|
ld y, 65
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
routine chrout
|
define chrout routine
|
||||||
inputs a
|
inputs a
|
||||||
trashes a
|
trashes a
|
||||||
@ 65490
|
@ 65490
|
||||||
|
|
||||||
routine bar trashes a, z, n {
|
define bar routine trashes a, z, n {
|
||||||
ld a, 66
|
ld a, 66
|
||||||
call chrout
|
call chrout
|
||||||
}
|
}
|
||||||
|
|
||||||
routine main trashes a, z, n {
|
define main routine trashes a, z, n {
|
||||||
ld a, 65
|
ld a, 65
|
||||||
call chrout
|
call chrout
|
||||||
goto bar
|
goto bar
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
routine foo
|
define main routine
|
||||||
inputs a
|
inputs a
|
||||||
outputs a
|
outputs a
|
||||||
|
trashes z, n, c
|
||||||
{
|
{
|
||||||
cmp a, 42
|
cmp a, 42
|
||||||
if z {
|
if z {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
routine chrout
|
define chrout routine
|
||||||
inputs a
|
inputs a
|
||||||
trashes a
|
trashes a
|
||||||
@ 65490
|
@ 65490
|
||||||
|
|
||||||
routine main
|
define main routine
|
||||||
trashes a, y, z, n, c
|
trashes a, y, z, n, c
|
||||||
{
|
{
|
||||||
ld y, 65
|
ld y, 65
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
byte foo
|
byte foo
|
||||||
|
|
||||||
routine chrout
|
define chrout routine
|
||||||
inputs a
|
inputs a
|
||||||
trashes a
|
trashes a
|
||||||
@ 65490
|
@ 65490
|
||||||
|
|
||||||
routine print
|
define print routine
|
||||||
inputs foo
|
inputs foo
|
||||||
trashes a, z, n
|
trashes a, z, n
|
||||||
{
|
{
|
||||||
@ -13,7 +13,7 @@ routine print
|
|||||||
call chrout
|
call chrout
|
||||||
}
|
}
|
||||||
|
|
||||||
routine main
|
define main routine
|
||||||
trashes a, y, z, n, foo
|
trashes a, y, z, n, foo
|
||||||
{
|
{
|
||||||
ld y, 65
|
ld y, 65
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
routine chrout
|
define chrout routine
|
||||||
inputs a
|
inputs a
|
||||||
trashes a
|
trashes a
|
||||||
@ 65490
|
@ 65490
|
||||||
|
|
||||||
routine main
|
define main routine
|
||||||
inputs a
|
inputs a
|
||||||
trashes a, z, n
|
trashes a, z, n
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
byte table[8] message : "WHAT?"
|
byte table[8] message : "WHAT?"
|
||||||
|
|
||||||
routine main
|
define main routine
|
||||||
inputs message
|
inputs message
|
||||||
outputs x, a, z, n
|
outputs x, a, z, n
|
||||||
{
|
{
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
// This will not compile on its own, because there is no `main`.
|
// This will not compile on its own, because there is no `main`.
|
||||||
// But this and `vector-main.60p` together will compile.
|
// But this and `vector-main.60p` together will compile.
|
||||||
|
|
||||||
routine chrout
|
define chrout routine
|
||||||
inputs a
|
inputs a
|
||||||
trashes a
|
trashes a
|
||||||
@ 65490
|
@ 65490
|
||||||
|
|
||||||
routine printa
|
define printa routine
|
||||||
trashes a, z, n
|
trashes a, z, n
|
||||||
{
|
{
|
||||||
ld a, 65
|
ld a, 65
|
||||||
call chrout
|
call chrout
|
||||||
}
|
}
|
||||||
|
|
||||||
routine printb
|
define printb routine
|
||||||
trashes a, z, n
|
trashes a, z, n
|
||||||
{
|
{
|
||||||
ld a, 66
|
ld a, 66
|
||||||
|
@ -12,7 +12,7 @@ vector routine
|
|||||||
// call chrout
|
// call chrout
|
||||||
// }
|
// }
|
||||||
|
|
||||||
routine main
|
define main routine
|
||||||
trashes print, a, z, n
|
trashes print, a, z, n
|
||||||
{
|
{
|
||||||
copy printa, print
|
copy printa, print
|
||||||
|
@ -11,26 +11,26 @@ vector (routine
|
|||||||
trashes a, z, n)
|
trashes a, z, n)
|
||||||
table[32] vectors
|
table[32] vectors
|
||||||
|
|
||||||
routine chrout
|
define chrout routine
|
||||||
inputs a
|
inputs a
|
||||||
trashes a
|
trashes a
|
||||||
@ 65490
|
@ 65490
|
||||||
|
|
||||||
routine printa
|
define printa routine
|
||||||
trashes a, z, n
|
trashes a, z, n
|
||||||
{
|
{
|
||||||
ld a, 65
|
ld a, 65
|
||||||
call chrout
|
call chrout
|
||||||
}
|
}
|
||||||
|
|
||||||
routine printb
|
define printb routine
|
||||||
trashes a, z, n
|
trashes a, z, n
|
||||||
{
|
{
|
||||||
ld a, 66
|
ld a, 66
|
||||||
call chrout
|
call chrout
|
||||||
}
|
}
|
||||||
|
|
||||||
routine main
|
define main routine
|
||||||
inputs vectors
|
inputs vectors
|
||||||
outputs vectors
|
outputs vectors
|
||||||
trashes print, a, x, z, n, c
|
trashes print, a, x, z, n, c
|
||||||
|
@ -2,26 +2,26 @@ vector routine
|
|||||||
trashes a, z, n
|
trashes a, z, n
|
||||||
print
|
print
|
||||||
|
|
||||||
routine chrout
|
define chrout routine
|
||||||
inputs a
|
inputs a
|
||||||
trashes a
|
trashes a
|
||||||
@ 65490
|
@ 65490
|
||||||
|
|
||||||
routine printa
|
define printa routine
|
||||||
trashes a, z, n
|
trashes a, z, n
|
||||||
{
|
{
|
||||||
ld a, 65
|
ld a, 65
|
||||||
call chrout
|
call chrout
|
||||||
}
|
}
|
||||||
|
|
||||||
routine printb
|
define printb routine
|
||||||
trashes a, z, n
|
trashes a, z, n
|
||||||
{
|
{
|
||||||
ld a, 66
|
ld a, 66
|
||||||
call chrout
|
call chrout
|
||||||
}
|
}
|
||||||
|
|
||||||
routine main
|
define main routine
|
||||||
trashes print, a, z, n
|
trashes print, a, z, n
|
||||||
{
|
{
|
||||||
copy printa, print
|
copy printa, print
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
word one
|
word one
|
||||||
word table[256] many
|
word table[256] many
|
||||||
|
|
||||||
routine main
|
define main routine
|
||||||
inputs one, many
|
inputs one, many
|
||||||
outputs one, many
|
outputs one, many
|
||||||
trashes a, x, y, n, z
|
trashes a, x, y, n, z
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
// Define where the screen starts in memory:
|
// Define where the screen starts in memory:
|
||||||
byte table[256] screen @ 7680
|
byte table[256] screen @ 7680
|
||||||
|
|
||||||
routine main
|
define main routine
|
||||||
// These are the values that will be written to by this routine:
|
// These are the values that will be written to by this routine:
|
||||||
trashes a, x, z, n, screen
|
trashes a, x, z, n, screen
|
||||||
{
|
{
|
||||||
|
19
loadngo.sh
19
loadngo.sh
@ -1,6 +1,6 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
usage="Usage: loadngo.sh (c64|vic20|atari2600) [--dry-run] <source.60p>"
|
usage="Usage: loadngo.sh (c64|vic20|atari2600|apple2) [--dry-run] <source.60p>"
|
||||||
|
|
||||||
arch="$1"
|
arch="$1"
|
||||||
shift 1
|
shift 1
|
||||||
@ -21,6 +21,21 @@ elif [ "X$arch" = "Xvic20" ]; then
|
|||||||
elif [ "X$arch" = "Xatari2600" ]; then
|
elif [ "X$arch" = "Xatari2600" ]; then
|
||||||
output_format='atari2600-cart'
|
output_format='atari2600-cart'
|
||||||
emu='stella'
|
emu='stella'
|
||||||
|
elif [ "X$arch" = "Xapple2" ]; then
|
||||||
|
src="$1"
|
||||||
|
out=/tmp/a-out.bin
|
||||||
|
bin/sixtypical --traceback --origin=0x2000 --output-format=raw $src --output $out || exit 1
|
||||||
|
ls -la $out
|
||||||
|
cp ~/scratchpad/linapple/res/Master.dsk sixtypical.dsk
|
||||||
|
# TODO: replace HELLO with something that does like
|
||||||
|
# BLOAD "PROG"
|
||||||
|
# CALL 8192
|
||||||
|
# (not BRUN because it does not always return to BASIC afterwards not sure why)
|
||||||
|
a2rm sixtypical.dsk PROG
|
||||||
|
a2in B sixtypical.dsk PROG $out
|
||||||
|
linapple -d1 sixtypical.dsk -autoboot
|
||||||
|
rm -f $out sixtypical.dsk
|
||||||
|
exit 0
|
||||||
else
|
else
|
||||||
echo $usage && exit 1
|
echo $usage && exit 1
|
||||||
fi
|
fi
|
||||||
@ -38,7 +53,7 @@ fi
|
|||||||
### do it ###
|
### do it ###
|
||||||
|
|
||||||
out=/tmp/a-out.prg
|
out=/tmp/a-out.prg
|
||||||
bin/sixtypical --traceback --output-format=$output_format $src > $out || exit 1
|
bin/sixtypical --traceback --output-format=$output_format $src --output $out || exit 1
|
||||||
ls -la $out
|
ls -la $out
|
||||||
$emu $out
|
$emu $out
|
||||||
rm -f $out
|
rm -f $out
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# encoding: UTF-8
|
# encoding: UTF-8
|
||||||
|
|
||||||
from sixtypical.ast import Program, Routine, Block, Instr, SingleOp, If, Repeat, For, WithInterruptsOff, Save
|
from sixtypical.ast import Program, Routine, Block, SingleOp, If, Repeat, For, WithInterruptsOff, Save
|
||||||
from sixtypical.model import (
|
from sixtypical.model import (
|
||||||
TYPE_BYTE, TYPE_WORD,
|
TYPE_BYTE, TYPE_WORD,
|
||||||
TableType, BufferType, PointerType, VectorType, RoutineType,
|
TableType, BufferType, PointerType, VectorType, RoutineType,
|
||||||
@ -372,23 +372,23 @@ class Analyzer(object):
|
|||||||
context = Context(self.routines, routine, type_.inputs, type_.outputs, type_.trashes)
|
context = Context(self.routines, routine, type_.inputs, type_.outputs, type_.trashes)
|
||||||
|
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print "at start of routine `{}`:".format(routine.name)
|
print("at start of routine `{}`:".format(routine.name))
|
||||||
print context
|
print(context)
|
||||||
|
|
||||||
self.analyze_block(routine.block, context)
|
self.analyze_block(routine.block, context)
|
||||||
trashed = set(context.each_touched()) - set(context.each_meaningful())
|
trashed = set(context.each_touched()) - set(context.each_meaningful())
|
||||||
|
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print "at end of routine `{}`:".format(routine.name)
|
print("at end of routine `{}`:".format(routine.name))
|
||||||
print context
|
print(context)
|
||||||
print "trashed: ", LocationRef.format_set(trashed)
|
print("trashed: ", LocationRef.format_set(trashed))
|
||||||
print "outputs: ", LocationRef.format_set(type_.outputs)
|
print("outputs: ", LocationRef.format_set(type_.outputs))
|
||||||
trashed_outputs = type_.outputs & trashed
|
trashed_outputs = type_.outputs & trashed
|
||||||
if trashed_outputs:
|
if trashed_outputs:
|
||||||
print "TRASHED OUTPUTS: ", LocationRef.format_set(trashed_outputs)
|
print("TRASHED OUTPUTS: ", LocationRef.format_set(trashed_outputs))
|
||||||
print ''
|
print('')
|
||||||
print '-' * 79
|
print('-' * 79)
|
||||||
print ''
|
print('')
|
||||||
|
|
||||||
# even if we goto another routine, we can't trash an output.
|
# even if we goto another routine, we can't trash an output.
|
||||||
for ref in trashed:
|
for ref in trashed:
|
||||||
@ -550,6 +550,8 @@ class Analyzer(object):
|
|||||||
context.invalidate_range(dest)
|
context.invalidate_range(dest)
|
||||||
elif opcode == 'call':
|
elif opcode == 'call':
|
||||||
type = instr.location.type
|
type = instr.location.type
|
||||||
|
if not isinstance(type, (RoutineType, VectorType)):
|
||||||
|
raise TypeMismatchError(instr, instr.location)
|
||||||
if isinstance(type, VectorType):
|
if isinstance(type, VectorType):
|
||||||
type = type.of_type
|
type = type.of_type
|
||||||
for ref in type.inputs:
|
for ref in type.inputs:
|
||||||
@ -771,17 +773,22 @@ class Analyzer(object):
|
|||||||
context.set_writeable(instr.dest)
|
context.set_writeable(instr.dest)
|
||||||
|
|
||||||
def analyze_save(self, instr, context):
|
def analyze_save(self, instr, context):
|
||||||
if len(instr.locations) != 1:
|
batons = []
|
||||||
raise NotImplementedError("Only 1 location in save is supported right now")
|
for location in instr.locations:
|
||||||
location = instr.locations[0]
|
self.assert_type(TYPE_BYTE, location)
|
||||||
self.assert_type(TYPE_BYTE, location)
|
baton = context.extract(location)
|
||||||
|
batons.append(baton)
|
||||||
|
|
||||||
baton = context.extract(location)
|
|
||||||
self.analyze_block(instr.block, context)
|
self.analyze_block(instr.block, context)
|
||||||
if context.encountered_gotos():
|
if context.encountered_gotos():
|
||||||
raise IllegalJumpError(instr, instr)
|
raise IllegalJumpError(instr, instr)
|
||||||
context.re_introduce(baton)
|
|
||||||
|
|
||||||
|
for location in reversed(instr.locations):
|
||||||
|
baton = batons.pop()
|
||||||
|
context.re_introduce(baton)
|
||||||
|
|
||||||
|
# We do this check outside the loop, because A is only preserved
|
||||||
|
# if it is the outermost thing being `save`d.
|
||||||
if location == REG_A:
|
if location == REG_A:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
@ -37,14 +37,16 @@ class AST(object):
|
|||||||
def all_children(self):
|
def all_children(self):
|
||||||
for attr in self.children_attrs:
|
for attr in self.children_attrs:
|
||||||
for child in self.attrs[attr]:
|
for child in self.attrs[attr]:
|
||||||
|
if child is not None:
|
||||||
|
yield child
|
||||||
|
for subchild in child.all_children():
|
||||||
|
yield subchild
|
||||||
|
for attr in self.child_attrs:
|
||||||
|
child = self.attrs[attr]
|
||||||
|
if child is not None:
|
||||||
yield child
|
yield child
|
||||||
for subchild in child.all_children():
|
for subchild in child.all_children():
|
||||||
yield subchild
|
yield subchild
|
||||||
for attr in self.child_attrs:
|
|
||||||
child = self.attrs[attr]
|
|
||||||
yield child
|
|
||||||
for subchild in child.all_children():
|
|
||||||
yield subchild
|
|
||||||
|
|
||||||
|
|
||||||
class Program(AST):
|
class Program(AST):
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# encoding: UTF-8
|
# encoding: UTF-8
|
||||||
|
|
||||||
from sixtypical.ast import Program, Routine, Block, Instr, SingleOp, If, Repeat, For, WithInterruptsOff, Save
|
from sixtypical.ast import Program, Routine, Block, SingleOp, If, Repeat, For, WithInterruptsOff, Save
|
||||||
from sixtypical.model import (
|
from sixtypical.model import (
|
||||||
ConstantRef, LocationRef, IndexedRef, IndirectRef, AddressRef,
|
ConstantRef, LocationRef, IndexedRef, IndirectRef, AddressRef,
|
||||||
TYPE_BIT, TYPE_BYTE, TYPE_WORD,
|
TYPE_BIT, TYPE_BYTE, TYPE_WORD,
|
||||||
@ -112,7 +112,7 @@ class Compiler(object):
|
|||||||
routine_name = roster_row[-1]
|
routine_name = roster_row[-1]
|
||||||
self.compile_routine(self.routines[routine_name])
|
self.compile_routine(self.routines[routine_name])
|
||||||
|
|
||||||
for location, label in self.trampolines.iteritems():
|
for location, label in self.trampolines.items():
|
||||||
self.emitter.resolve_label(label)
|
self.emitter.resolve_label(label)
|
||||||
self.emitter.emit(JMP(Indirect(self.get_label(location.name))))
|
self.emitter.emit(JMP(Indirect(self.get_label(location.name))))
|
||||||
self.emitter.emit(RTS())
|
self.emitter.emit(RTS())
|
||||||
@ -618,27 +618,32 @@ class Compiler(object):
|
|||||||
self.emitter.emit(CLI())
|
self.emitter.emit(CLI())
|
||||||
|
|
||||||
def compile_save(self, instr):
|
def compile_save(self, instr):
|
||||||
location = instr.locations[0]
|
for location in instr.locations:
|
||||||
if location == REG_A:
|
if location == REG_A:
|
||||||
self.emitter.emit(PHA())
|
self.emitter.emit(PHA())
|
||||||
self.compile_block(instr.block)
|
elif location == REG_X:
|
||||||
self.emitter.emit(PLA())
|
self.emitter.emit(TXA())
|
||||||
elif location == REG_X:
|
self.emitter.emit(PHA())
|
||||||
self.emitter.emit(TXA())
|
elif location == REG_Y:
|
||||||
self.emitter.emit(PHA())
|
self.emitter.emit(TYA())
|
||||||
self.compile_block(instr.block)
|
self.emitter.emit(PHA())
|
||||||
self.emitter.emit(PLA())
|
else:
|
||||||
self.emitter.emit(TAX())
|
src_label = self.get_label(location.name)
|
||||||
elif location == REG_Y:
|
self.emitter.emit(LDA(Absolute(src_label)))
|
||||||
self.emitter.emit(TYA())
|
self.emitter.emit(PHA())
|
||||||
self.emitter.emit(PHA())
|
|
||||||
self.compile_block(instr.block)
|
self.compile_block(instr.block)
|
||||||
self.emitter.emit(PLA())
|
|
||||||
self.emitter.emit(TAY())
|
for location in reversed(instr.locations):
|
||||||
else:
|
if location == REG_A:
|
||||||
src_label = self.get_label(location.name)
|
self.emitter.emit(PLA())
|
||||||
self.emitter.emit(LDA(Absolute(src_label)))
|
elif location == REG_X:
|
||||||
self.emitter.emit(PHA())
|
self.emitter.emit(PLA())
|
||||||
self.compile_block(instr.block)
|
self.emitter.emit(TAX())
|
||||||
self.emitter.emit(PLA())
|
elif location == REG_Y:
|
||||||
self.emitter.emit(STA(Absolute(src_label)))
|
self.emitter.emit(PLA())
|
||||||
|
self.emitter.emit(TAY())
|
||||||
|
else:
|
||||||
|
src_label = self.get_label(location.name)
|
||||||
|
self.emitter.emit(PLA())
|
||||||
|
self.emitter.emit(STA(Absolute(src_label)))
|
||||||
|
@ -8,12 +8,15 @@ class Emittable(object):
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def serialize(self, addr):
|
def serialize(self, addr):
|
||||||
|
"""Should return an array of unsigned bytes (integers from 0 to 255.)
|
||||||
|
`addr` is the address the value is being serialized at; for most objects
|
||||||
|
it makes no difference, but some objects (like relative branches) do care."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
class Byte(Emittable):
|
class Byte(Emittable):
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
if isinstance(value, basestring):
|
if isinstance(value, str):
|
||||||
value = ord(value)
|
value = ord(value)
|
||||||
if value < -127 or value > 255:
|
if value < -127 or value > 255:
|
||||||
raise IndexError(value)
|
raise IndexError(value)
|
||||||
@ -24,8 +27,8 @@ class Byte(Emittable):
|
|||||||
def size(self):
|
def size(self):
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def serialize(self, addr=None):
|
def serialize(self, addr):
|
||||||
return chr(self.value)
|
return [self.value]
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s(%r)" % (self.__class__.__name__, self.value)
|
return "%s(%r)" % (self.__class__.__name__, self.value)
|
||||||
@ -39,11 +42,11 @@ class Word(Emittable):
|
|||||||
def size(self):
|
def size(self):
|
||||||
return 2
|
return 2
|
||||||
|
|
||||||
def serialize(self, addr=None):
|
def serialize(self, addr):
|
||||||
word = self.value
|
word = self.value
|
||||||
low = word & 255
|
low = word & 255
|
||||||
high = (word >> 8) & 255
|
high = (word >> 8) & 255
|
||||||
return chr(low) + chr(high)
|
return [low, high]
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s(%r)" % (self.__class__.__name__, self.value)
|
return "%s(%r)" % (self.__class__.__name__, self.value)
|
||||||
@ -59,10 +62,12 @@ class Table(Emittable):
|
|||||||
def size(self):
|
def size(self):
|
||||||
return self._size
|
return self._size
|
||||||
|
|
||||||
def serialize(self, addr=None):
|
def serialize(self, addr):
|
||||||
buf = ''.join([emittable.serialize() for emittable in self.value])
|
buf = []
|
||||||
|
for emittable in self.value:
|
||||||
|
buf.extend(emittable.serialize(addr)) # FIXME: addr + offset
|
||||||
while len(buf) < self.size():
|
while len(buf) < self.size():
|
||||||
buf += chr(0)
|
buf.append(0)
|
||||||
return buf
|
return buf
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
@ -84,17 +89,17 @@ class Label(Emittable):
|
|||||||
def size(self):
|
def size(self):
|
||||||
return 2
|
return 2
|
||||||
|
|
||||||
def serialize(self, addr=None, offset=0):
|
def serialize(self, addr, offset=0):
|
||||||
assert self.addr is not None, "unresolved label: %s" % self.name
|
assert self.addr is not None, "unresolved label: %s" % self.name
|
||||||
return Word(self.addr + offset).serialize()
|
return Word(self.addr + offset).serialize(addr)
|
||||||
|
|
||||||
def serialize_relative_to(self, addr):
|
def serialize_relative_to(self, addr):
|
||||||
assert self.addr is not None, "unresolved label: %s" % self.name
|
assert self.addr is not None, "unresolved label: %s" % self.name
|
||||||
return Byte(self.addr - (addr + 2)).serialize()
|
return Byte(self.addr - (addr + 2)).serialize(addr)
|
||||||
|
|
||||||
def serialize_as_zero_page(self, offset=0):
|
def serialize_as_zero_page(self, addr, offset=0):
|
||||||
assert self.addr is not None, "unresolved label: %s" % self.name
|
assert self.addr is not None, "unresolved label: %s" % self.name
|
||||||
return Byte(self.addr + offset).serialize()
|
return Byte(self.addr + offset).serialize(addr)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
addr_s = ', addr=%r' % self.addr if self.addr is not None else ''
|
addr_s = ', addr=%r' % self.addr if self.addr is not None else ''
|
||||||
@ -111,11 +116,11 @@ class Offset(Emittable):
|
|||||||
def size(self):
|
def size(self):
|
||||||
self.label.size()
|
self.label.size()
|
||||||
|
|
||||||
def serialize(self, addr=None):
|
def serialize(self, addr):
|
||||||
return self.label.serialize(offset=self.offset)
|
return self.label.serialize(addr, offset=self.offset)
|
||||||
|
|
||||||
def serialize_as_zero_page(self, offset=0):
|
def serialize_as_zero_page(self, addr, offset=0):
|
||||||
return self.label.serialize_as_zero_page(offset=self.offset)
|
return self.label.serialize_as_zero_page(addr, offset=self.offset)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s(%r, %r)" % (self.__class__.__name__, self.label, self.offset)
|
return "%s(%r, %r)" % (self.__class__.__name__, self.label, self.offset)
|
||||||
@ -129,8 +134,8 @@ class HighAddressByte(Emittable):
|
|||||||
def size(self):
|
def size(self):
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def serialize(self, addr=None):
|
def serialize(self, addr):
|
||||||
return self.label.serialize()[0]
|
return [self.label.serialize(addr)[0]]
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s(%r)" % (self.__class__.__name__, self.label)
|
return "%s(%r)" % (self.__class__.__name__, self.label)
|
||||||
@ -144,8 +149,8 @@ class LowAddressByte(Emittable):
|
|||||||
def size(self):
|
def size(self):
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def serialize(self, addr=None):
|
def serialize(self, addr):
|
||||||
return self.label.serialize()[1]
|
return [self.label.serialize(addr)[1]]
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s(%r)" % (self.__class__.__name__, self.label)
|
return "%s(%r)" % (self.__class__.__name__, self.label)
|
||||||
@ -166,11 +171,12 @@ class Emitter(object):
|
|||||||
self.accum.append(thing)
|
self.accum.append(thing)
|
||||||
self.addr += thing.size()
|
self.addr += thing.size()
|
||||||
|
|
||||||
def serialize(self, stream):
|
def serialize_to(self, stream):
|
||||||
|
"""`stream` should be a file opened in binary mode."""
|
||||||
addr = self.start_addr
|
addr = self.start_addr
|
||||||
for emittable in self.accum:
|
for emittable in self.accum:
|
||||||
chunk = emittable.serialize(addr)
|
chunk = emittable.serialize(addr)
|
||||||
stream.write(chunk)
|
stream.write(bytearray(chunk))
|
||||||
addr += len(chunk)
|
addr += len(chunk)
|
||||||
|
|
||||||
def make_label(self, name=None):
|
def make_label(self, name=None):
|
||||||
|
@ -43,7 +43,7 @@ class FallthruAnalyzer(object):
|
|||||||
|
|
||||||
while pending_routines:
|
while pending_routines:
|
||||||
chains = [self.find_chain(k, pending_routines) for k in pending_routines.keys()]
|
chains = [self.find_chain(k, pending_routines) for k in pending_routines.keys()]
|
||||||
chains.sort(key=len, reverse=True)
|
chains.sort(key=lambda x: (len(x), str(x)), reverse=True)
|
||||||
c = chains[0]
|
c = chains[0]
|
||||||
roster.append(c)
|
roster.append(c)
|
||||||
for k in c:
|
for k in c:
|
||||||
|
@ -8,7 +8,7 @@ class AddressingMode(Emittable):
|
|||||||
"""Size of the operand for the mode (not including the opcode)"""
|
"""Size of the operand for the mode (not including the opcode)"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def serialize(self, addr=None):
|
def serialize(self, addr):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
@ -19,8 +19,8 @@ class Implied(AddressingMode):
|
|||||||
def size(self):
|
def size(self):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def serialize(self, addr=None):
|
def serialize(self, addr):
|
||||||
return ''
|
return []
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s()" % (self.__class__.__name__)
|
return "%s()" % (self.__class__.__name__)
|
||||||
@ -34,8 +34,8 @@ class Immediate(AddressingMode):
|
|||||||
def size(self):
|
def size(self):
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def serialize(self, addr=None):
|
def serialize(self, addr):
|
||||||
return self.value.serialize()
|
return self.value.serialize(addr)
|
||||||
|
|
||||||
|
|
||||||
class Absolute(AddressingMode):
|
class Absolute(AddressingMode):
|
||||||
@ -46,8 +46,8 @@ class Absolute(AddressingMode):
|
|||||||
def size(self):
|
def size(self):
|
||||||
return 2
|
return 2
|
||||||
|
|
||||||
def serialize(self, addr=None):
|
def serialize(self, addr):
|
||||||
return self.value.serialize()
|
return self.value.serialize(addr)
|
||||||
|
|
||||||
|
|
||||||
class AbsoluteX(Absolute):
|
class AbsoluteX(Absolute):
|
||||||
@ -66,8 +66,8 @@ class ZeroPage(AddressingMode):
|
|||||||
def size(self):
|
def size(self):
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def serialize(self, addr=None):
|
def serialize(self, addr):
|
||||||
return self.value.serialize_as_zero_page()
|
return self.value.serialize_as_zero_page(addr)
|
||||||
|
|
||||||
|
|
||||||
class Indirect(AddressingMode):
|
class Indirect(AddressingMode):
|
||||||
@ -78,8 +78,8 @@ class Indirect(AddressingMode):
|
|||||||
def size(self):
|
def size(self):
|
||||||
return 2
|
return 2
|
||||||
|
|
||||||
def serialize(self, addr=None):
|
def serialize(self, addr):
|
||||||
return self.value.serialize()
|
return self.value.serialize(addr)
|
||||||
|
|
||||||
|
|
||||||
class IndirectY(ZeroPage):
|
class IndirectY(ZeroPage):
|
||||||
@ -94,7 +94,7 @@ class Relative(AddressingMode):
|
|||||||
def size(self):
|
def size(self):
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def serialize(self, addr=None):
|
def serialize(self, addr):
|
||||||
return self.value.serialize_relative_to(addr)
|
return self.value.serialize_relative_to(addr)
|
||||||
|
|
||||||
|
|
||||||
@ -108,11 +108,8 @@ class Instruction(Emittable):
|
|||||||
def size(self):
|
def size(self):
|
||||||
return 1 + self.operand.size() if self.operand else 0
|
return 1 + self.operand.size() if self.operand else 0
|
||||||
|
|
||||||
def serialize(self, addr=None):
|
def serialize(self, addr):
|
||||||
return (
|
return [self.opcodes[self.operand.__class__]] + self.operand.serialize(addr)
|
||||||
chr(self.opcodes[self.operand.__class__]) +
|
|
||||||
self.operand.serialize(addr)
|
|
||||||
)
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s(%r)" % (self.__class__.__name__, self.operand)
|
return "%s(%r)" % (self.__class__.__name__, self.operand)
|
||||||
|
@ -18,20 +18,6 @@ class Type(object):
|
|||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
return hash(self.name)
|
return hash(self.name)
|
||||||
|
|
||||||
def backpatch_constraint_labels(self, resolver):
|
|
||||||
def resolve(w):
|
|
||||||
if not isinstance(w, basestring):
|
|
||||||
return w
|
|
||||||
return resolver(w)
|
|
||||||
if isinstance(self, TableType):
|
|
||||||
self.of_type.backpatch_constraint_labels(resolver)
|
|
||||||
elif isinstance(self, VectorType):
|
|
||||||
self.of_type.backpatch_constraint_labels(resolver)
|
|
||||||
elif isinstance(self, RoutineType):
|
|
||||||
self.inputs = set([resolve(w) for w in self.inputs])
|
|
||||||
self.outputs = set([resolve(w) for w in self.outputs])
|
|
||||||
self.trashes = set([resolve(w) for w in self.trashes])
|
|
||||||
|
|
||||||
|
|
||||||
TYPE_BIT = Type('bit', max_range=(0, 1))
|
TYPE_BIT = Type('bit', max_range=(0, 1))
|
||||||
TYPE_BYTE = Type('byte', max_range=(0, 255))
|
TYPE_BYTE = Type('byte', max_range=(0, 255))
|
||||||
@ -41,11 +27,11 @@ TYPE_WORD = Type('word', max_range=(0, 65535))
|
|||||||
|
|
||||||
class RoutineType(Type):
|
class RoutineType(Type):
|
||||||
"""This memory location contains the code for a routine."""
|
"""This memory location contains the code for a routine."""
|
||||||
def __init__(self, inputs=None, outputs=None, trashes=None):
|
def __init__(self, inputs, outputs, trashes):
|
||||||
self.name = 'routine'
|
self.name = 'routine'
|
||||||
self.inputs = inputs or set()
|
self.inputs = inputs
|
||||||
self.outputs = outputs or set()
|
self.outputs = outputs
|
||||||
self.trashes = trashes or set()
|
self.trashes = trashes
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '%s(%r, inputs=%r, outputs=%r, trashes=%r)' % (
|
return '%s(%r, inputs=%r, outputs=%r, trashes=%r)' % (
|
||||||
@ -172,7 +158,7 @@ class LocationRef(Ref):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def format_set(cls, location_refs):
|
def format_set(cls, location_refs):
|
||||||
return '{%s}' % ', '.join([str(loc) for loc in sorted(location_refs)])
|
return '{%s}' % ', '.join([str(loc) for loc in sorted(location_refs, key=lambda x: x.name)])
|
||||||
|
|
||||||
|
|
||||||
class IndirectRef(Ref):
|
class IndirectRef(Ref):
|
||||||
|
74
src/sixtypical/outputter.py
Normal file
74
src/sixtypical/outputter.py
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
"""Executable file writer."""
|
||||||
|
|
||||||
|
from sixtypical.emitter import Emitter, Byte, Word
|
||||||
|
|
||||||
|
|
||||||
|
class Outputter(object):
|
||||||
|
def __init__(self, fh, start_addr=None):
|
||||||
|
self.start_addr = self.__class__.start_addr
|
||||||
|
if start_addr is not None:
|
||||||
|
self.start_addr = start_addr
|
||||||
|
self.prelude = self.__class__.prelude
|
||||||
|
self.fh = fh
|
||||||
|
self.emitter = Emitter(self.start_addr)
|
||||||
|
|
||||||
|
def write_header(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def write_prelude(self):
|
||||||
|
self.write_header()
|
||||||
|
for byte in self.prelude:
|
||||||
|
self.emitter.emit(Byte(byte))
|
||||||
|
|
||||||
|
def write_postlude(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class RawOutputter(Outputter):
|
||||||
|
start_addr = 0x0000
|
||||||
|
prelude = []
|
||||||
|
|
||||||
|
|
||||||
|
class PrgOutputter(Outputter):
|
||||||
|
start_addr = 0xc000
|
||||||
|
prelude = []
|
||||||
|
|
||||||
|
def write_header(self):
|
||||||
|
# If we are outputting a .PRG, we output the load address first.
|
||||||
|
# We don't use the Emitter for this b/c not part of addr space.
|
||||||
|
self.fh.write(bytearray(Word(self.start_addr).serialize(0)))
|
||||||
|
|
||||||
|
|
||||||
|
class C64BasicPrgOutputter(PrgOutputter):
|
||||||
|
start_addr = 0x0801
|
||||||
|
prelude = [0x10, 0x08, 0xc9, 0x07, 0x9e, 0x32,
|
||||||
|
0x30, 0x36, 0x31, 0x00, 0x00, 0x00]
|
||||||
|
|
||||||
|
|
||||||
|
class Vic20BasicPrgOutputter(PrgOutputter):
|
||||||
|
start_addr = 0x1001
|
||||||
|
prelude = [0x0b, 0x10, 0xc9, 0x07, 0x9e, 0x34,
|
||||||
|
0x31, 0x30, 0x39, 0x00, 0x00, 0x00]
|
||||||
|
|
||||||
|
|
||||||
|
class Atari2600CartOutputter(Outputter):
|
||||||
|
start_addr = 0xf000
|
||||||
|
prelude = [0x78, 0xd8, 0xa2, 0xff, 0x9a, 0xa9,
|
||||||
|
0x00, 0x95, 0x00, 0xca, 0xd0, 0xfb]
|
||||||
|
|
||||||
|
def write_postlude(self):
|
||||||
|
# If we are outputting a cartridge with boot and BRK address
|
||||||
|
# at the end, pad to ROM size minus 4 bytes, and emit addresses.
|
||||||
|
self.emitter.pad_to_size(4096 - 4)
|
||||||
|
self.emitter.emit(Word(self.start_addr))
|
||||||
|
self.emitter.emit(Word(self.start_addr))
|
||||||
|
|
||||||
|
|
||||||
|
def outputter_class_for(output_format):
|
||||||
|
return {
|
||||||
|
'raw': RawOutputter,
|
||||||
|
'prg': PrgOutputter,
|
||||||
|
'c64-basic-prg': C64BasicPrgOutputter,
|
||||||
|
'vic20-basic-prg': Vic20BasicPrgOutputter,
|
||||||
|
'atari2600-cart': Atari2600CartOutputter,
|
||||||
|
}[output_format]
|
@ -18,6 +18,14 @@ class SymEntry(object):
|
|||||||
return "%s(%r, %r)" % (self.__class__.__name__, self.ast_node, self.model)
|
return "%s(%r, %r)" % (self.__class__.__name__, self.ast_node, self.model)
|
||||||
|
|
||||||
|
|
||||||
|
class ForwardReference(object):
|
||||||
|
def __init__(self, name):
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "%s(%r)" % (self.__class__.__name__, self.name)
|
||||||
|
|
||||||
|
|
||||||
class ParsingContext(object):
|
class ParsingContext(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.symbols = {} # token -> SymEntry
|
self.symbols = {} # token -> SymEntry
|
||||||
@ -33,7 +41,7 @@ class ParsingContext(object):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "Symbols: {}\nStatics: {}\nTypedefs: {}\nConsts: {}".format(self.symbols, self.statics, self.typedefs, self.consts)
|
return "Symbols: {}\nStatics: {}\nTypedefs: {}\nConsts: {}".format(self.symbols, self.statics, self.typedefs, self.consts)
|
||||||
|
|
||||||
def lookup(self, name):
|
def fetch(self, name):
|
||||||
if name in self.statics:
|
if name in self.statics:
|
||||||
return self.statics[name].model
|
return self.statics[name].model
|
||||||
if name in self.symbols:
|
if name in self.symbols:
|
||||||
@ -45,17 +53,65 @@ class Parser(object):
|
|||||||
def __init__(self, context, text, filename):
|
def __init__(self, context, text, filename):
|
||||||
self.context = context
|
self.context = context
|
||||||
self.scanner = Scanner(text, filename)
|
self.scanner = Scanner(text, filename)
|
||||||
self.backpatch_instrs = []
|
|
||||||
|
|
||||||
def syntax_error(self, msg):
|
def syntax_error(self, msg):
|
||||||
self.scanner.syntax_error(msg)
|
self.scanner.syntax_error(msg)
|
||||||
|
|
||||||
def lookup(self, name):
|
def lookup(self, name):
|
||||||
model = self.context.lookup(name)
|
model = self.context.fetch(name)
|
||||||
if model is None:
|
if model is None:
|
||||||
self.syntax_error('Undefined symbol "{}"'.format(name))
|
self.syntax_error('Undefined symbol "{}"'.format(name))
|
||||||
return model
|
return model
|
||||||
|
|
||||||
|
def declare(self, name, symentry, static=False):
|
||||||
|
if self.context.fetch(name):
|
||||||
|
self.syntax_error('Symbol "%s" already declared' % name)
|
||||||
|
if static:
|
||||||
|
self.context.statics[name] = symentry
|
||||||
|
else:
|
||||||
|
self.context.symbols[name] = symentry
|
||||||
|
|
||||||
|
def clear_statics(self):
|
||||||
|
self.context.statics = {}
|
||||||
|
|
||||||
|
# ---- symbol resolution
|
||||||
|
|
||||||
|
def resolve_symbols(self, program):
|
||||||
|
# This could stand to be better unified.
|
||||||
|
|
||||||
|
def backpatch_constraint_labels(type_):
|
||||||
|
def resolve(w):
|
||||||
|
if not isinstance(w, ForwardReference):
|
||||||
|
return w
|
||||||
|
return self.lookup(w.name)
|
||||||
|
if isinstance(type_, TableType):
|
||||||
|
backpatch_constraint_labels(type_.of_type)
|
||||||
|
elif isinstance(type_, VectorType):
|
||||||
|
backpatch_constraint_labels(type_.of_type)
|
||||||
|
elif isinstance(type_, RoutineType):
|
||||||
|
type_.inputs = set([resolve(w) for w in type_.inputs])
|
||||||
|
type_.outputs = set([resolve(w) for w in type_.outputs])
|
||||||
|
type_.trashes = set([resolve(w) for w in type_.trashes])
|
||||||
|
|
||||||
|
for defn in program.defns:
|
||||||
|
backpatch_constraint_labels(defn.location.type)
|
||||||
|
for routine in program.routines:
|
||||||
|
backpatch_constraint_labels(routine.location.type)
|
||||||
|
|
||||||
|
def resolve_fwd_reference(obj, field):
|
||||||
|
field_value = getattr(obj, field, None)
|
||||||
|
if isinstance(field_value, ForwardReference):
|
||||||
|
setattr(obj, field, self.lookup(field_value.name))
|
||||||
|
elif isinstance(field_value, IndexedRef):
|
||||||
|
if isinstance(field_value.ref, ForwardReference):
|
||||||
|
field_value.ref = self.lookup(field_value.ref.name)
|
||||||
|
|
||||||
|
for node in program.all_children():
|
||||||
|
if isinstance(node, SingleOp):
|
||||||
|
resolve_fwd_reference(node, 'location')
|
||||||
|
resolve_fwd_reference(node, 'src')
|
||||||
|
resolve_fwd_reference(node, 'dest')
|
||||||
|
|
||||||
# --- grammar productions
|
# --- grammar productions
|
||||||
|
|
||||||
def program(self):
|
def program(self):
|
||||||
@ -70,47 +126,19 @@ class Parser(object):
|
|||||||
typenames.extend(self.context.typedefs.keys())
|
typenames.extend(self.context.typedefs.keys())
|
||||||
while self.scanner.on(*typenames):
|
while self.scanner.on(*typenames):
|
||||||
defn = self.defn()
|
defn = self.defn()
|
||||||
name = defn.name
|
self.declare(defn.name, SymEntry(defn, defn.location))
|
||||||
if self.context.lookup(name):
|
|
||||||
self.syntax_error('Symbol "%s" already declared' % name)
|
|
||||||
self.context.symbols[name] = SymEntry(defn, defn.location)
|
|
||||||
defns.append(defn)
|
defns.append(defn)
|
||||||
while self.scanner.on('define', 'routine'):
|
while self.scanner.consume('define'):
|
||||||
if self.scanner.consume('define'):
|
name = self.scanner.token
|
||||||
name = self.scanner.token
|
self.scanner.scan()
|
||||||
self.scanner.scan()
|
routine = self.routine(name)
|
||||||
routine = self.routine(name)
|
self.declare(name, SymEntry(routine, routine.location))
|
||||||
else:
|
|
||||||
routine = self.legacy_routine()
|
|
||||||
name = routine.name
|
|
||||||
if self.context.lookup(name):
|
|
||||||
self.syntax_error('Symbol "%s" already declared' % name)
|
|
||||||
self.context.symbols[name] = SymEntry(routine, routine.location)
|
|
||||||
routines.append(routine)
|
routines.append(routine)
|
||||||
self.scanner.check_type('EOF')
|
self.scanner.check_type('EOF')
|
||||||
|
|
||||||
# now backpatch the executable types.
|
program = Program(self.scanner.line_number, defns=defns, routines=routines)
|
||||||
#for type_name, type_ in self.context.typedefs.iteritems():
|
self.resolve_symbols(program)
|
||||||
# type_.backpatch_constraint_labels(lambda w: self.lookup(w))
|
return program
|
||||||
for defn in defns:
|
|
||||||
defn.location.type.backpatch_constraint_labels(lambda w: self.lookup(w))
|
|
||||||
for routine in routines:
|
|
||||||
routine.location.type.backpatch_constraint_labels(lambda w: self.lookup(w))
|
|
||||||
for instr in self.backpatch_instrs:
|
|
||||||
if instr.opcode in ('call', 'goto'):
|
|
||||||
name = instr.location
|
|
||||||
model = self.lookup(name)
|
|
||||||
if not isinstance(model.type, (RoutineType, VectorType)):
|
|
||||||
self.syntax_error('Illegal call of non-executable "%s"' % name)
|
|
||||||
instr.location = model
|
|
||||||
if instr.opcode in ('copy',) and isinstance(instr.src, basestring):
|
|
||||||
name = instr.src
|
|
||||||
model = self.lookup(name)
|
|
||||||
if not isinstance(model.type, (RoutineType, VectorType)):
|
|
||||||
self.syntax_error('Illegal copy of non-executable "%s"' % name)
|
|
||||||
instr.src = model
|
|
||||||
|
|
||||||
return Program(self.scanner.line_number, defns=defns, routines=routines)
|
|
||||||
|
|
||||||
def typedef(self):
|
def typedef(self):
|
||||||
self.scanner.expect('typedef')
|
self.scanner.expect('typedef')
|
||||||
@ -250,27 +278,10 @@ class Parser(object):
|
|||||||
outputs = set(self.labels())
|
outputs = set(self.labels())
|
||||||
if self.scanner.consume('trashes'):
|
if self.scanner.consume('trashes'):
|
||||||
trashes = set(self.labels())
|
trashes = set(self.labels())
|
||||||
return (inputs, outputs, trashes)
|
return (
|
||||||
|
set([ForwardReference(n) for n in inputs]),
|
||||||
def legacy_routine(self):
|
set([ForwardReference(n) for n in outputs]),
|
||||||
self.scanner.expect('routine')
|
set([ForwardReference(n) for n in trashes])
|
||||||
name = self.scanner.token
|
|
||||||
self.scanner.scan()
|
|
||||||
(inputs, outputs, trashes) = self.constraints()
|
|
||||||
type_ = RoutineType(inputs=inputs, outputs=outputs, trashes=trashes)
|
|
||||||
if self.scanner.consume('@'):
|
|
||||||
self.scanner.check_type('integer literal')
|
|
||||||
block = None
|
|
||||||
addr = int(self.scanner.token)
|
|
||||||
self.scanner.scan()
|
|
||||||
else:
|
|
||||||
block = self.block()
|
|
||||||
addr = None
|
|
||||||
location = LocationRef(type_, name)
|
|
||||||
return Routine(
|
|
||||||
self.scanner.line_number,
|
|
||||||
name=name, block=block, addr=addr,
|
|
||||||
location=location
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def routine(self, name):
|
def routine(self, name):
|
||||||
@ -286,9 +297,11 @@ class Parser(object):
|
|||||||
else:
|
else:
|
||||||
statics = self.statics()
|
statics = self.statics()
|
||||||
|
|
||||||
self.context.statics = self.compose_statics_dict(statics)
|
self.clear_statics()
|
||||||
|
for defn in statics:
|
||||||
|
self.declare(defn.name, SymEntry(defn, defn.location), static=True)
|
||||||
block = self.block()
|
block = self.block()
|
||||||
self.context.statics = {}
|
self.clear_statics()
|
||||||
|
|
||||||
addr = None
|
addr = None
|
||||||
location = LocationRef(type_, name)
|
location = LocationRef(type_, name)
|
||||||
@ -298,15 +311,6 @@ class Parser(object):
|
|||||||
location=location, statics=statics
|
location=location, statics=statics
|
||||||
)
|
)
|
||||||
|
|
||||||
def compose_statics_dict(self, statics):
|
|
||||||
c = {}
|
|
||||||
for defn in statics:
|
|
||||||
name = defn.name
|
|
||||||
if self.context.lookup(name):
|
|
||||||
self.syntax_error('Symbol "%s" already declared' % name)
|
|
||||||
c[name] = SymEntry(defn, defn.location)
|
|
||||||
return c
|
|
||||||
|
|
||||||
def labels(self):
|
def labels(self):
|
||||||
accum = []
|
accum = []
|
||||||
accum.append(self.label())
|
accum.append(self.label())
|
||||||
@ -328,23 +332,19 @@ class Parser(object):
|
|||||||
accum.append(self.locexpr())
|
accum.append(self.locexpr())
|
||||||
return accum
|
return accum
|
||||||
|
|
||||||
def locexpr(self, forward=False):
|
def locexpr(self):
|
||||||
if self.scanner.token in ('on', 'off', 'word') or self.scanner.token in self.context.consts or self.scanner.on_type('integer literal'):
|
if self.scanner.token in ('on', 'off', 'word') or self.scanner.token in self.context.consts or self.scanner.on_type('integer literal'):
|
||||||
return self.const()
|
return self.const()
|
||||||
elif forward:
|
else:
|
||||||
name = self.scanner.token
|
name = self.scanner.token
|
||||||
self.scanner.scan()
|
self.scanner.scan()
|
||||||
loc = self.context.lookup(name)
|
loc = self.context.fetch(name)
|
||||||
if loc is not None:
|
if loc:
|
||||||
return loc
|
return loc
|
||||||
else:
|
else:
|
||||||
return name
|
return ForwardReference(name)
|
||||||
else:
|
|
||||||
loc = self.lookup(self.scanner.token)
|
|
||||||
self.scanner.scan()
|
|
||||||
return loc
|
|
||||||
|
|
||||||
def indlocexpr(self, forward=False):
|
def indlocexpr(self):
|
||||||
if self.scanner.consume('['):
|
if self.scanner.consume('['):
|
||||||
loc = self.locexpr()
|
loc = self.locexpr()
|
||||||
self.scanner.expect(']')
|
self.scanner.expect(']')
|
||||||
@ -355,11 +355,11 @@ class Parser(object):
|
|||||||
loc = self.locexpr()
|
loc = self.locexpr()
|
||||||
return AddressRef(loc)
|
return AddressRef(loc)
|
||||||
else:
|
else:
|
||||||
return self.indexed_locexpr(forward=forward)
|
return self.indexed_locexpr()
|
||||||
|
|
||||||
def indexed_locexpr(self, forward=False):
|
def indexed_locexpr(self):
|
||||||
loc = self.locexpr(forward=forward)
|
loc = self.locexpr()
|
||||||
if not isinstance(loc, basestring):
|
if not isinstance(loc, str):
|
||||||
index = None
|
index = None
|
||||||
if self.scanner.consume('+'):
|
if self.scanner.consume('+'):
|
||||||
index = self.locexpr()
|
index = self.locexpr()
|
||||||
@ -453,17 +453,15 @@ class Parser(object):
|
|||||||
self.scanner.scan()
|
self.scanner.scan()
|
||||||
name = self.scanner.token
|
name = self.scanner.token
|
||||||
self.scanner.scan()
|
self.scanner.scan()
|
||||||
instr = SingleOp(self.scanner.line_number, opcode=opcode, location=name, dest=None, src=None)
|
instr = SingleOp(self.scanner.line_number, opcode=opcode, location=ForwardReference(name), dest=None, src=None)
|
||||||
self.backpatch_instrs.append(instr)
|
|
||||||
return instr
|
return instr
|
||||||
elif self.scanner.token in ("copy",):
|
elif self.scanner.token in ("copy",):
|
||||||
opcode = self.scanner.token
|
opcode = self.scanner.token
|
||||||
self.scanner.scan()
|
self.scanner.scan()
|
||||||
src = self.indlocexpr(forward=True)
|
src = self.indlocexpr()
|
||||||
self.scanner.expect(',')
|
self.scanner.expect(',')
|
||||||
dest = self.indlocexpr()
|
dest = self.indlocexpr()
|
||||||
instr = SingleOp(self.scanner.line_number, opcode=opcode, dest=dest, src=src)
|
instr = SingleOp(self.scanner.line_number, opcode=opcode, dest=dest, src=src)
|
||||||
self.backpatch_instrs.append(instr)
|
|
||||||
return instr
|
return instr
|
||||||
elif self.scanner.consume("with"):
|
elif self.scanner.consume("with"):
|
||||||
self.scanner.expect("interrupts")
|
self.scanner.expect("interrupts")
|
||||||
@ -479,3 +477,17 @@ class Parser(object):
|
|||||||
return SingleOp(self.scanner.line_number, opcode='trash', src=None, dest=dest)
|
return SingleOp(self.scanner.line_number, opcode='trash', src=None, dest=dest)
|
||||||
else:
|
else:
|
||||||
self.syntax_error('bad opcode "%s"' % self.scanner.token)
|
self.syntax_error('bad opcode "%s"' % self.scanner.token)
|
||||||
|
|
||||||
|
|
||||||
|
# - - - -
|
||||||
|
|
||||||
|
|
||||||
|
def merge_programs(programs):
|
||||||
|
"""Assumes that the programs do not have any conflicts."""
|
||||||
|
|
||||||
|
full = Program(1, defns=[], routines=[])
|
||||||
|
for p in programs:
|
||||||
|
full.defns.extend(p.defns)
|
||||||
|
full.routines.extend(p.routines)
|
||||||
|
|
||||||
|
return full
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -7,20 +7,20 @@ SixtyPical to 6502 machine code.
|
|||||||
[Falderal]: http://catseye.tc/node/Falderal
|
[Falderal]: http://catseye.tc/node/Falderal
|
||||||
|
|
||||||
-> Functionality "Compile SixtyPical program" is implemented by
|
-> Functionality "Compile SixtyPical program" is implemented by
|
||||||
-> shell command "bin/sixtypical --output-format=c64-basic-prg --traceback %(test-body-file) >/tmp/foo && tests/appliances/bin/dcc6502-adapter </tmp/foo"
|
-> shell command "bin/sixtypical --output-format=c64-basic-prg --traceback %(test-body-file) --output /tmp/foo && tests/appliances/bin/dcc6502-adapter </tmp/foo"
|
||||||
|
|
||||||
-> Tests for functionality "Compile SixtyPical program"
|
-> Tests for functionality "Compile SixtyPical program"
|
||||||
|
|
||||||
Null program.
|
Null program.
|
||||||
|
|
||||||
| routine main
|
| define main routine
|
||||||
| {
|
| {
|
||||||
| }
|
| }
|
||||||
= $080D RTS
|
= $080D RTS
|
||||||
|
|
||||||
`nop` program.
|
`nop` program.
|
||||||
|
|
||||||
| routine main
|
| define main routine
|
||||||
| {
|
| {
|
||||||
| nop
|
| nop
|
||||||
| }
|
| }
|
||||||
@ -29,7 +29,7 @@ Null program.
|
|||||||
|
|
||||||
Rudimentary program.
|
Rudimentary program.
|
||||||
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs a
|
| inputs a
|
||||||
| outputs a
|
| outputs a
|
||||||
| trashes c, z, n, v
|
| trashes c, z, n, v
|
||||||
@ -43,12 +43,12 @@ Rudimentary program.
|
|||||||
|
|
||||||
Call extern.
|
Call extern.
|
||||||
|
|
||||||
| routine chrout
|
| define chrout routine
|
||||||
| inputs a
|
| inputs a
|
||||||
| trashes a
|
| trashes a
|
||||||
| @ 65490
|
| @ 65490
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs a
|
| inputs a
|
||||||
| trashes a, z, n
|
| trashes a, z, n
|
||||||
| {
|
| {
|
||||||
@ -61,7 +61,7 @@ Call extern.
|
|||||||
|
|
||||||
Call defined routine.
|
Call defined routine.
|
||||||
|
|
||||||
| routine foo
|
| define foo routine
|
||||||
| outputs a, x, y
|
| outputs a, x, y
|
||||||
| trashes z, n
|
| trashes z, n
|
||||||
| {
|
| {
|
||||||
@ -70,7 +70,7 @@ Call defined routine.
|
|||||||
| ld y, 0
|
| ld y, 0
|
||||||
| }
|
| }
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| trashes a, x, y, z, n
|
| trashes a, x, y, z, n
|
||||||
| {
|
| {
|
||||||
| call foo
|
| call foo
|
||||||
@ -86,7 +86,7 @@ Access a defined memory location.
|
|||||||
|
|
||||||
| byte foo
|
| byte foo
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| trashes a, y, z, n, foo
|
| trashes a, y, z, n, foo
|
||||||
| {
|
| {
|
||||||
| ld y, 0
|
| ld y, 0
|
||||||
@ -102,7 +102,7 @@ Memory location with explicit address.
|
|||||||
|
|
||||||
| byte screen @ 1024
|
| byte screen @ 1024
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| trashes a, z, n, screen
|
| trashes a, z, n, screen
|
||||||
| {
|
| {
|
||||||
| ld a, 100
|
| ld a, 100
|
||||||
@ -118,7 +118,7 @@ and `and`, `or`, and `xor` use zero-page addressing.
|
|||||||
| byte zp @ $00
|
| byte zp @ $00
|
||||||
| byte screen @ 100
|
| byte screen @ 100
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs screen, zp
|
| inputs screen, zp
|
||||||
| outputs screen, zp
|
| outputs screen, zp
|
||||||
| trashes a, z, n
|
| trashes a, z, n
|
||||||
@ -144,7 +144,7 @@ Memory location with initial value.
|
|||||||
|
|
||||||
| byte lives : 3
|
| byte lives : 3
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs lives
|
| inputs lives
|
||||||
| trashes a, z, n
|
| trashes a, z, n
|
||||||
| {
|
| {
|
||||||
@ -159,7 +159,7 @@ Word memory locations with explicit address, initial value.
|
|||||||
| word w1 @ 60001
|
| word w1 @ 60001
|
||||||
| word w2 : 3003
|
| word w2 : 3003
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs w1
|
| inputs w1
|
||||||
| outputs w2
|
| outputs w2
|
||||||
| trashes a, z, n
|
| trashes a, z, n
|
||||||
@ -178,7 +178,7 @@ Initialized byte table, initialized with ASCII string. Bytes allocated, but bey
|
|||||||
|
|
||||||
| byte table[8] message : "WHAT?"
|
| byte table[8] message : "WHAT?"
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs message
|
| inputs message
|
||||||
| outputs x, a, z, n
|
| outputs x, a, z, n
|
||||||
| {
|
| {
|
||||||
@ -200,7 +200,7 @@ Initialized byte table, initialized with list of byte values.
|
|||||||
|
|
||||||
| byte table[8] message : 255, 0, 129, 128, 127
|
| byte table[8] message : 255, 0, 129, 128, 127
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs message
|
| inputs message
|
||||||
| outputs x, a, z, n
|
| outputs x, a, z, n
|
||||||
| {
|
| {
|
||||||
@ -222,7 +222,7 @@ Initialized word table, initialized with list of word values.
|
|||||||
|
|
||||||
| word table[4] message : 65535, 0, 127, 127
|
| word table[4] message : 65535, 0, 127, 127
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| {
|
| {
|
||||||
| }
|
| }
|
||||||
= $080D RTS
|
= $080D RTS
|
||||||
@ -239,7 +239,7 @@ Some instructions.
|
|||||||
|
|
||||||
| byte foo
|
| byte foo
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| trashes a, x, y, z, n, c, v, foo
|
| trashes a, x, y, z, n, c, v, foo
|
||||||
| {
|
| {
|
||||||
| ld a, 0
|
| ld a, 0
|
||||||
@ -317,7 +317,7 @@ Some instructions on tables. (1/3)
|
|||||||
|
|
||||||
| byte table[256] many
|
| byte table[256] many
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs many
|
| inputs many
|
||||||
| outputs many
|
| outputs many
|
||||||
| trashes a, x, c, n, z, v
|
| trashes a, x, c, n, z, v
|
||||||
@ -341,7 +341,7 @@ Some instructions on tables. (2/3)
|
|||||||
|
|
||||||
| byte table[256] many
|
| byte table[256] many
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs many
|
| inputs many
|
||||||
| outputs many
|
| outputs many
|
||||||
| trashes a, x, c, n, z
|
| trashes a, x, c, n, z
|
||||||
@ -363,7 +363,7 @@ Some instructions on tables. (3/3)
|
|||||||
|
|
||||||
| byte table[256] many
|
| byte table[256] many
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs many
|
| inputs many
|
||||||
| outputs many
|
| outputs many
|
||||||
| trashes a, x, c, n, z
|
| trashes a, x, c, n, z
|
||||||
@ -387,7 +387,7 @@ Some instructions on tables. (3/3)
|
|||||||
|
|
||||||
Compiling `if`.
|
Compiling `if`.
|
||||||
|
|
||||||
| routine main
|
| define main routine
|
||||||
| trashes a, x, y, z, n, c, v
|
| trashes a, x, y, z, n, c, v
|
||||||
| {
|
| {
|
||||||
| ld a, 0
|
| ld a, 0
|
||||||
@ -406,7 +406,7 @@ Compiling `if`.
|
|||||||
|
|
||||||
Compiling `if not`.
|
Compiling `if not`.
|
||||||
|
|
||||||
| routine main
|
| define main routine
|
||||||
| trashes a, x, y, z, n, c, v
|
| trashes a, x, y, z, n, c, v
|
||||||
| {
|
| {
|
||||||
| ld a, 0
|
| ld a, 0
|
||||||
@ -425,7 +425,7 @@ Compiling `if not`.
|
|||||||
|
|
||||||
Compiling `if` without `else`.
|
Compiling `if` without `else`.
|
||||||
|
|
||||||
| routine main
|
| define main routine
|
||||||
| trashes a, x, y, z, n, c, v
|
| trashes a, x, y, z, n, c, v
|
||||||
| {
|
| {
|
||||||
| ld a, 0
|
| ld a, 0
|
||||||
@ -442,7 +442,7 @@ Compiling `if` without `else`.
|
|||||||
|
|
||||||
Compiling `repeat ... until z`.
|
Compiling `repeat ... until z`.
|
||||||
|
|
||||||
| routine main
|
| define main routine
|
||||||
| trashes a, y, z, n, c
|
| trashes a, y, z, n, c
|
||||||
| {
|
| {
|
||||||
| ld y, 65
|
| ld y, 65
|
||||||
@ -461,7 +461,7 @@ Compiling `repeat ... until z`.
|
|||||||
|
|
||||||
Compiling `repeat ... until not z`.
|
Compiling `repeat ... until not z`.
|
||||||
|
|
||||||
| routine main
|
| define main routine
|
||||||
| trashes a, y, z, n, c
|
| trashes a, y, z, n, c
|
||||||
| {
|
| {
|
||||||
| ld y, 65
|
| ld y, 65
|
||||||
@ -480,7 +480,7 @@ Compiling `repeat ... until not z`.
|
|||||||
|
|
||||||
Compiling `repeat ... until n`.
|
Compiling `repeat ... until n`.
|
||||||
|
|
||||||
| routine main
|
| define main routine
|
||||||
| trashes a, y, z, n, c
|
| trashes a, y, z, n, c
|
||||||
| {
|
| {
|
||||||
| ld y, 65
|
| ld y, 65
|
||||||
@ -497,7 +497,7 @@ Compiling `repeat ... until n`.
|
|||||||
|
|
||||||
Compiling `repeat ... until not n`.
|
Compiling `repeat ... until not n`.
|
||||||
|
|
||||||
| routine main
|
| define main routine
|
||||||
| trashes a, y, z, n, c
|
| trashes a, y, z, n, c
|
||||||
| {
|
| {
|
||||||
| ld y, 199
|
| ld y, 199
|
||||||
@ -514,7 +514,7 @@ Compiling `repeat ... until not n`.
|
|||||||
|
|
||||||
Compiling `repeat forever`.
|
Compiling `repeat forever`.
|
||||||
|
|
||||||
| routine main
|
| define main routine
|
||||||
| trashes a, y, z, n, c
|
| trashes a, y, z, n, c
|
||||||
| {
|
| {
|
||||||
| ld y, 65
|
| ld y, 65
|
||||||
@ -529,7 +529,7 @@ Compiling `repeat forever`.
|
|||||||
|
|
||||||
The body of `repeat forever` can be empty.
|
The body of `repeat forever` can be empty.
|
||||||
|
|
||||||
| routine main
|
| define main routine
|
||||||
| {
|
| {
|
||||||
| repeat {
|
| repeat {
|
||||||
| } forever
|
| } forever
|
||||||
@ -579,7 +579,7 @@ Compiling `for ... down to`.
|
|||||||
|
|
||||||
Compiling `save`.
|
Compiling `save`.
|
||||||
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs a
|
| inputs a
|
||||||
| outputs a
|
| outputs a
|
||||||
| trashes z, n
|
| trashes z, n
|
||||||
@ -601,10 +601,32 @@ Compiling `save`.
|
|||||||
= $0816 PLA
|
= $0816 PLA
|
||||||
= $0817 RTS
|
= $0817 RTS
|
||||||
|
|
||||||
|
Compiling `save` with shortcut syntax.
|
||||||
|
|
||||||
|
| define main routine
|
||||||
|
| inputs a
|
||||||
|
| outputs a
|
||||||
|
| trashes z, n
|
||||||
|
| {
|
||||||
|
| save a, x {
|
||||||
|
| ld a, 0
|
||||||
|
| ld x, 1
|
||||||
|
| }
|
||||||
|
| }
|
||||||
|
= $080D PHA
|
||||||
|
= $080E TXA
|
||||||
|
= $080F PHA
|
||||||
|
= $0810 LDA #$00
|
||||||
|
= $0812 LDX #$01
|
||||||
|
= $0814 PLA
|
||||||
|
= $0815 TAX
|
||||||
|
= $0816 PLA
|
||||||
|
= $0817 RTS
|
||||||
|
|
||||||
Compiling `save` on a user-defined location.
|
Compiling `save` on a user-defined location.
|
||||||
|
|
||||||
| byte foo
|
| byte foo
|
||||||
| routine main
|
| define main routine
|
||||||
| trashes a, z, n
|
| trashes a, z, n
|
||||||
| {
|
| {
|
||||||
| save foo {
|
| save foo {
|
||||||
@ -625,7 +647,7 @@ Indexed access.
|
|||||||
| byte one
|
| byte one
|
||||||
| byte table[256] many
|
| byte table[256] many
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| outputs many
|
| outputs many
|
||||||
| trashes a, x, n, z
|
| trashes a, x, n, z
|
||||||
| {
|
| {
|
||||||
@ -645,7 +667,7 @@ Byte tables take up, at most, 256 bytes in memory.
|
|||||||
| byte table[256] tab1
|
| byte table[256] tab1
|
||||||
| byte table[256] tab2
|
| byte table[256] tab2
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs tab1
|
| inputs tab1
|
||||||
| outputs tab2
|
| outputs tab2
|
||||||
| trashes a, x, n, z
|
| trashes a, x, n, z
|
||||||
@ -664,7 +686,7 @@ Byte storage locations take up only 1 byte in memory.
|
|||||||
| byte one
|
| byte one
|
||||||
| byte two
|
| byte two
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| outputs one, two
|
| outputs one, two
|
||||||
| trashes a, x, n, z
|
| trashes a, x, n, z
|
||||||
| {
|
| {
|
||||||
@ -682,7 +704,7 @@ Copy byte to byte.
|
|||||||
| byte bar
|
| byte bar
|
||||||
| byte baz
|
| byte baz
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs baz
|
| inputs baz
|
||||||
| outputs bar
|
| outputs bar
|
||||||
| trashes a, n, z
|
| trashes a, n, z
|
||||||
@ -698,7 +720,7 @@ Copy word to word.
|
|||||||
| word bar
|
| word bar
|
||||||
| word baz
|
| word baz
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs baz
|
| inputs baz
|
||||||
| outputs bar
|
| outputs bar
|
||||||
| trashes a, n, z
|
| trashes a, n, z
|
||||||
@ -715,7 +737,7 @@ Copy literal word to word.
|
|||||||
|
|
||||||
| word bar
|
| word bar
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| outputs bar
|
| outputs bar
|
||||||
| trashes a, n, z
|
| trashes a, n, z
|
||||||
| {
|
| {
|
||||||
@ -731,7 +753,7 @@ You can also copy a literal word to a word table.
|
|||||||
|
|
||||||
| word table[256] many
|
| word table[256] many
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs many
|
| inputs many
|
||||||
| outputs many
|
| outputs many
|
||||||
| trashes a, x, n, z
|
| trashes a, x, n, z
|
||||||
@ -751,7 +773,7 @@ Copy vector to vector.
|
|||||||
| vector routine bar
|
| vector routine bar
|
||||||
| vector routine baz
|
| vector routine baz
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs baz
|
| inputs baz
|
||||||
| outputs bar
|
| outputs bar
|
||||||
| trashes a, n, z
|
| trashes a, n, z
|
||||||
@ -772,7 +794,7 @@ Copy routine to vector, inside an `interrupts off` block.
|
|||||||
| trashes z, n
|
| trashes z, n
|
||||||
| bar
|
| bar
|
||||||
|
|
|
|
||||||
| routine foo
|
| define foo routine
|
||||||
| inputs x
|
| inputs x
|
||||||
| outputs x
|
| outputs x
|
||||||
| trashes z, n
|
| trashes z, n
|
||||||
@ -780,7 +802,7 @@ Copy routine to vector, inside an `interrupts off` block.
|
|||||||
| inc x
|
| inc x
|
||||||
| }
|
| }
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| outputs bar
|
| outputs bar
|
||||||
| trashes a, n, z
|
| trashes a, n, z
|
||||||
| {
|
| {
|
||||||
@ -806,14 +828,14 @@ Copy routine (by forward reference) to vector.
|
|||||||
| trashes z, n
|
| trashes z, n
|
||||||
| bar
|
| bar
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| outputs bar
|
| outputs bar
|
||||||
| trashes a, n, z
|
| trashes a, n, z
|
||||||
| {
|
| {
|
||||||
| copy foo, bar
|
| copy foo, bar
|
||||||
| }
|
| }
|
||||||
|
|
|
|
||||||
| routine foo
|
| define foo routine
|
||||||
| inputs x
|
| inputs x
|
||||||
| outputs x
|
| outputs x
|
||||||
| trashes z, n
|
| trashes z, n
|
||||||
@ -833,7 +855,7 @@ Copy word to word table and back, with both `x` and `y` as indexes.
|
|||||||
| word one
|
| word one
|
||||||
| word table[256] many
|
| word table[256] many
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs one, many
|
| inputs one, many
|
||||||
| outputs one, many
|
| outputs one, many
|
||||||
| trashes a, x, y, n, z
|
| trashes a, x, y, n, z
|
||||||
@ -877,14 +899,14 @@ Indirect call.
|
|||||||
| trashes z, n
|
| trashes z, n
|
||||||
| foo
|
| foo
|
||||||
|
|
|
|
||||||
| routine bar
|
| define bar routine
|
||||||
| outputs x
|
| outputs x
|
||||||
| trashes z, n
|
| trashes z, n
|
||||||
| {
|
| {
|
||||||
| ld x, 200
|
| ld x, 200
|
||||||
| }
|
| }
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| outputs x, foo
|
| outputs x, foo
|
||||||
| trashes a, z, n
|
| trashes a, z, n
|
||||||
| {
|
| {
|
||||||
@ -904,7 +926,7 @@ Indirect call.
|
|||||||
|
|
||||||
Compiling `goto`. Note that no `RTS` is emitted after the `JMP`.
|
Compiling `goto`. Note that no `RTS` is emitted after the `JMP`.
|
||||||
|
|
||||||
| routine bar
|
| define bar routine
|
||||||
| inputs y
|
| inputs y
|
||||||
| outputs x, y
|
| outputs x, y
|
||||||
| trashes z, n
|
| trashes z, n
|
||||||
@ -912,7 +934,7 @@ Compiling `goto`. Note that no `RTS` is emitted after the `JMP`.
|
|||||||
| ld x, 200
|
| ld x, 200
|
||||||
| }
|
| }
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| outputs x, y
|
| outputs x, y
|
||||||
| trashes a, z, n
|
| trashes a, z, n
|
||||||
| {
|
| {
|
||||||
@ -937,11 +959,11 @@ Copying to and from a vector table.
|
|||||||
| trashes a, z, n
|
| trashes a, z, n
|
||||||
| table[256] many
|
| table[256] many
|
||||||
|
|
|
|
||||||
| routine bar outputs x trashes a, z, n {
|
| define bar routine outputs x trashes a, z, n {
|
||||||
| ld x, 200
|
| ld x, 200
|
||||||
| }
|
| }
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs one, many
|
| inputs one, many
|
||||||
| outputs one, many
|
| outputs one, many
|
||||||
| trashes a, x, n, z
|
| trashes a, x, n, z
|
||||||
@ -982,7 +1004,7 @@ Copying to and from a vector table.
|
|||||||
Adding a constant word to a word memory location.
|
Adding a constant word to a word memory location.
|
||||||
|
|
||||||
| word score
|
| word score
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs score
|
| inputs score
|
||||||
| outputs score
|
| outputs score
|
||||||
| trashes a, c, z, v, n
|
| trashes a, c, z, v, n
|
||||||
@ -1003,7 +1025,7 @@ Adding a word memory location to another word memory location.
|
|||||||
|
|
||||||
| word score
|
| word score
|
||||||
| word delta
|
| word delta
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs score, delta
|
| inputs score, delta
|
||||||
| outputs score
|
| outputs score
|
||||||
| trashes a, c, z, v, n
|
| trashes a, c, z, v, n
|
||||||
@ -1023,7 +1045,7 @@ Adding a word memory location to another word memory location.
|
|||||||
Subtracting a constant word from a word memory location.
|
Subtracting a constant word from a word memory location.
|
||||||
|
|
||||||
| word score
|
| word score
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs score
|
| inputs score
|
||||||
| outputs score
|
| outputs score
|
||||||
| trashes a, c, z, v, n
|
| trashes a, c, z, v, n
|
||||||
@ -1044,7 +1066,7 @@ Subtracting a word memory location from another word memory location.
|
|||||||
|
|
||||||
| word score
|
| word score
|
||||||
| word delta
|
| word delta
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs score, delta
|
| inputs score, delta
|
||||||
| outputs score
|
| outputs score
|
||||||
| trashes a, c, z, v, n
|
| trashes a, c, z, v, n
|
||||||
@ -1068,7 +1090,7 @@ Load address into pointer.
|
|||||||
| buffer[2048] buf
|
| buffer[2048] buf
|
||||||
| pointer ptr @ 254
|
| pointer ptr @ 254
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs buf
|
| inputs buf
|
||||||
| outputs buf, y
|
| outputs buf, y
|
||||||
| trashes a, z, n, ptr
|
| trashes a, z, n, ptr
|
||||||
@ -1088,7 +1110,7 @@ Write literal through a pointer.
|
|||||||
| buffer[2048] buf
|
| buffer[2048] buf
|
||||||
| pointer ptr @ 254
|
| pointer ptr @ 254
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs buf
|
| inputs buf
|
||||||
| outputs buf, y
|
| outputs buf, y
|
||||||
| trashes a, z, n, ptr
|
| trashes a, z, n, ptr
|
||||||
@ -1112,7 +1134,7 @@ Write stored value through a pointer.
|
|||||||
| pointer ptr @ 254
|
| pointer ptr @ 254
|
||||||
| byte foo
|
| byte foo
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs foo, buf
|
| inputs foo, buf
|
||||||
| outputs y, buf
|
| outputs y, buf
|
||||||
| trashes a, z, n, ptr
|
| trashes a, z, n, ptr
|
||||||
@ -1136,7 +1158,7 @@ Read through a pointer, into a byte storage location, or the `a` register.
|
|||||||
| pointer ptr @ 254
|
| pointer ptr @ 254
|
||||||
| byte foo
|
| byte foo
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs buf
|
| inputs buf
|
||||||
| outputs y, foo
|
| outputs y, foo
|
||||||
| trashes a, z, n, ptr
|
| trashes a, z, n, ptr
|
||||||
@ -1162,7 +1184,7 @@ Read and write through two pointers.
|
|||||||
| pointer ptra @ 252
|
| pointer ptra @ 252
|
||||||
| pointer ptrb @ 254
|
| pointer ptrb @ 254
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs buf
|
| inputs buf
|
||||||
| outputs buf
|
| outputs buf
|
||||||
| trashes a, y, z, n, ptra, ptrb
|
| trashes a, y, z, n, ptra, ptrb
|
||||||
@ -1191,7 +1213,7 @@ Write the `a` register through a pointer.
|
|||||||
| pointer ptr @ 254
|
| pointer ptr @ 254
|
||||||
| byte foo
|
| byte foo
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs buf
|
| inputs buf
|
||||||
| outputs buf
|
| outputs buf
|
||||||
| trashes a, y, z, n, ptr
|
| trashes a, y, z, n, ptr
|
||||||
@ -1218,7 +1240,7 @@ Note that this is *not* range-checked. (Yet.)
|
|||||||
| byte foo
|
| byte foo
|
||||||
| word delta
|
| word delta
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs buf
|
| inputs buf
|
||||||
| outputs y, foo, delta
|
| outputs y, foo, delta
|
||||||
| trashes a, c, v, z, n, ptr
|
| trashes a, c, v, z, n, ptr
|
||||||
@ -1261,7 +1283,7 @@ Note that this is *not* range-checked. (Yet.)
|
|||||||
|
|
||||||
Trash does nothing except indicate that we do not care about the value anymore.
|
Trash does nothing except indicate that we do not care about the value anymore.
|
||||||
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs a
|
| inputs a
|
||||||
| outputs x
|
| outputs x
|
||||||
| trashes a, z, n
|
| trashes a, z, n
|
||||||
|
@ -48,7 +48,7 @@ Treat R as a mutable set and start with an empty list of lists L. Then,
|
|||||||
- Remove all elements occurring in C, from R.
|
- Remove all elements occurring in C, from R.
|
||||||
- Repeat until R is empty.
|
- Repeat until R is empty.
|
||||||
|
|
||||||
When times comes to generate code, generate it in the order given by L.
|
When time comes to generate code, generate it in the order given by L.
|
||||||
In addition, each sublist in L represents a number of routines to
|
In addition, each sublist in L represents a number of routines to
|
||||||
generate; all except the final routine in such a sublist need not have
|
generate; all except the final routine in such a sublist need not have
|
||||||
any jump instruction generated for its final `goto`.
|
any jump instruction generated for its final `goto`.
|
||||||
@ -65,7 +65,7 @@ to pass these tests to be considered an implementation of SixtyPical.
|
|||||||
-> shell command "bin/sixtypical --optimize-fallthru --dump-fallthru-info --analyze-only --traceback %(test-body-file)"
|
-> shell command "bin/sixtypical --optimize-fallthru --dump-fallthru-info --analyze-only --traceback %(test-body-file)"
|
||||||
|
|
||||||
-> Functionality "Compile SixtyPical program with fallthru optimization" is implemented by
|
-> Functionality "Compile SixtyPical program with fallthru optimization" is implemented by
|
||||||
-> shell command "bin/sixtypical --output-format=c64-basic-prg --optimize-fallthru --traceback %(test-body-file) >/tmp/foo && tests/appliances/bin/dcc6502-adapter </tmp/foo"
|
-> shell command "bin/sixtypical --output-format=c64-basic-prg --optimize-fallthru --traceback %(test-body-file) --output /tmp/foo && tests/appliances/bin/dcc6502-adapter </tmp/foo"
|
||||||
|
|
||||||
-> Tests for functionality "Dump fallthru info for SixtyPical program"
|
-> Tests for functionality "Dump fallthru info for SixtyPical program"
|
||||||
|
|
||||||
@ -94,7 +94,7 @@ If `main` does a `goto foo`, then it can fall through to `foo`.
|
|||||||
| }
|
| }
|
||||||
= [
|
= [
|
||||||
= [
|
= [
|
||||||
= "main",
|
= "main",
|
||||||
= "foo"
|
= "foo"
|
||||||
= ]
|
= ]
|
||||||
= ]
|
= ]
|
||||||
@ -119,9 +119,9 @@ of them to fall through, when selecting the order of routines.
|
|||||||
| }
|
| }
|
||||||
= [
|
= [
|
||||||
= [
|
= [
|
||||||
= "main",
|
= "main",
|
||||||
= "foo"
|
= "foo"
|
||||||
= ],
|
= ],
|
||||||
= [
|
= [
|
||||||
= "bar"
|
= "bar"
|
||||||
= ]
|
= ]
|
||||||
@ -144,7 +144,7 @@ nothing ever falls through to `main`.
|
|||||||
= [
|
= [
|
||||||
= [
|
= [
|
||||||
= "main"
|
= "main"
|
||||||
= ],
|
= ],
|
||||||
= [
|
= [
|
||||||
= "foo"
|
= "foo"
|
||||||
= ]
|
= ]
|
||||||
@ -172,10 +172,10 @@ fall through to the other.
|
|||||||
= [
|
= [
|
||||||
= [
|
= [
|
||||||
= "main"
|
= "main"
|
||||||
= ],
|
= ],
|
||||||
= [
|
= [
|
||||||
= "bar",
|
= "foo",
|
||||||
= "foo"
|
= "bar"
|
||||||
= ]
|
= ]
|
||||||
= ]
|
= ]
|
||||||
|
|
||||||
@ -204,12 +204,12 @@ routine.
|
|||||||
= [
|
= [
|
||||||
= [
|
= [
|
||||||
= "main"
|
= "main"
|
||||||
= ],
|
= ],
|
||||||
= [
|
|
||||||
= "bar"
|
|
||||||
= ],
|
|
||||||
= [
|
= [
|
||||||
= "foo"
|
= "foo"
|
||||||
|
= ],
|
||||||
|
= [
|
||||||
|
= "bar"
|
||||||
= ]
|
= ]
|
||||||
= ]
|
= ]
|
||||||
|
|
||||||
@ -238,9 +238,9 @@ If, however, they are the same goto, one can be optimized away.
|
|||||||
= [
|
= [
|
||||||
= [
|
= [
|
||||||
= "main"
|
= "main"
|
||||||
= ],
|
= ],
|
||||||
= [
|
= [
|
||||||
= "foo",
|
= "foo",
|
||||||
= "bar"
|
= "bar"
|
||||||
= ]
|
= ]
|
||||||
= ]
|
= ]
|
||||||
@ -269,12 +269,12 @@ because we don't necessarily know what actual routine the vector contains.
|
|||||||
= [
|
= [
|
||||||
= [
|
= [
|
||||||
= "main"
|
= "main"
|
||||||
= ],
|
= ],
|
||||||
= [
|
|
||||||
= "bar"
|
|
||||||
= ],
|
|
||||||
= [
|
= [
|
||||||
= "foo"
|
= "foo"
|
||||||
|
= ],
|
||||||
|
= [
|
||||||
|
= "bar"
|
||||||
= ]
|
= ]
|
||||||
= ]
|
= ]
|
||||||
|
|
||||||
@ -321,14 +321,14 @@ Our algorithm might not be strictly optimal, but it does a good job.
|
|||||||
| }
|
| }
|
||||||
= [
|
= [
|
||||||
= [
|
= [
|
||||||
= "main",
|
= "main",
|
||||||
= "r1",
|
= "r1",
|
||||||
= "r2",
|
= "r2",
|
||||||
= "r3",
|
= "r3",
|
||||||
= "r4"
|
= "r4"
|
||||||
= ],
|
= ],
|
||||||
= [
|
= [
|
||||||
= "r5",
|
= "r5",
|
||||||
= "r6"
|
= "r6"
|
||||||
= ]
|
= ]
|
||||||
= ]
|
= ]
|
||||||
@ -416,12 +416,12 @@ in the "true" branch is a `goto`.
|
|||||||
| {
|
| {
|
||||||
| }
|
| }
|
||||||
= $080D RTS
|
= $080D RTS
|
||||||
= $080E LDA #$FF
|
= $080E LDA #$00
|
||||||
= $0810 RTS
|
= $0810 BNE $081A
|
||||||
= $0811 LDA #$00
|
= $0812 LDA #$01
|
||||||
= $0813 BNE $081D
|
= $0814 JMP $081F
|
||||||
= $0815 LDA #$01
|
= $0817 JMP $081F
|
||||||
= $0817 JMP $080E
|
= $081A LDA #$02
|
||||||
= $081A JMP $0822
|
= $081C JMP $080D
|
||||||
= $081D LDA #$02
|
= $081F LDA #$FF
|
||||||
= $081F JMP $080D
|
= $0821 RTS
|
||||||
|
@ -16,7 +16,7 @@ but not necessarily sensible programs.
|
|||||||
|
|
||||||
Rudimentary program.
|
Rudimentary program.
|
||||||
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| ld a, 0
|
| ld a, 0
|
||||||
| add a, 1
|
| add a, 1
|
||||||
| }
|
| }
|
||||||
@ -26,7 +26,7 @@ Program with comments.
|
|||||||
|
|
||||||
| // Welcome to my program.
|
| // Welcome to my program.
|
||||||
|
|
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| ld a, 0
|
| ld a, 0
|
||||||
| add a, 1 // We are adding the thing.
|
| add a, 1 // We are adding the thing.
|
||||||
| sub a, 1
|
| sub a, 1
|
||||||
@ -40,7 +40,7 @@ Program with comments.
|
|||||||
|
|
||||||
Hex literals.
|
Hex literals.
|
||||||
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| ld a, $ff
|
| ld a, $ff
|
||||||
| add a, $01
|
| add a, $01
|
||||||
| }
|
| }
|
||||||
@ -48,7 +48,7 @@ Hex literals.
|
|||||||
|
|
||||||
Syntax error.
|
Syntax error.
|
||||||
|
|
||||||
| routine foo (
|
| define foo routine (
|
||||||
| ld a, 0
|
| ld a, 0
|
||||||
| add a, 1
|
| add a, 1
|
||||||
| )
|
| )
|
||||||
@ -65,12 +65,12 @@ Another syntax error.
|
|||||||
|
|
||||||
Extern routines
|
Extern routines
|
||||||
|
|
||||||
| routine chrout
|
| define chrout routine
|
||||||
| inputs a
|
| inputs a
|
||||||
| trashes a
|
| trashes a
|
||||||
| @ 65490
|
| @ 65490
|
||||||
|
|
|
|
||||||
| routine chrin
|
| define chrin routine
|
||||||
| outputs a
|
| outputs a
|
||||||
| trashes x
|
| trashes x
|
||||||
| @ 65487
|
| @ 65487
|
||||||
@ -78,7 +78,7 @@ Extern routines
|
|||||||
|
|
||||||
Trash.
|
Trash.
|
||||||
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| trash a
|
| trash a
|
||||||
| trash n
|
| trash n
|
||||||
| }
|
| }
|
||||||
@ -86,7 +86,7 @@ Trash.
|
|||||||
|
|
||||||
`nop`.
|
`nop`.
|
||||||
|
|
||||||
| routine main
|
| define main routine
|
||||||
| {
|
| {
|
||||||
| nop
|
| nop
|
||||||
| }
|
| }
|
||||||
@ -94,7 +94,7 @@ Trash.
|
|||||||
|
|
||||||
If with not
|
If with not
|
||||||
|
|
||||||
| routine foo {
|
| define foo routine {
|
||||||
| ld y, 0
|
| ld y, 0
|
||||||
| cmp y, 10
|
| cmp y, 10
|
||||||
| if not z {
|
| if not z {
|
||||||
@ -106,7 +106,7 @@ If with not
|
|||||||
|
|
||||||
Repeat loop
|
Repeat loop
|
||||||
|
|
||||||
| routine foo {
|
| define foo routine {
|
||||||
| ld y, 0
|
| ld y, 0
|
||||||
| repeat {
|
| repeat {
|
||||||
| inc y
|
| inc y
|
||||||
@ -117,7 +117,7 @@ Repeat loop
|
|||||||
|
|
||||||
"While" loop
|
"While" loop
|
||||||
|
|
||||||
| routine foo inputs y {
|
| define foo routine inputs y {
|
||||||
| repeat {
|
| repeat {
|
||||||
| cmp y, 10
|
| cmp y, 10
|
||||||
| if not z {
|
| if not z {
|
||||||
@ -129,7 +129,7 @@ Repeat loop
|
|||||||
|
|
||||||
Repeat forever
|
Repeat forever
|
||||||
|
|
||||||
| routine foo inputs y {
|
| define foo routine inputs y {
|
||||||
| repeat {
|
| repeat {
|
||||||
| inc y
|
| inc y
|
||||||
| } forever
|
| } forever
|
||||||
@ -138,7 +138,7 @@ Repeat forever
|
|||||||
|
|
||||||
Repeat with not
|
Repeat with not
|
||||||
|
|
||||||
| routine foo inputs y {
|
| define foo routine inputs y {
|
||||||
| repeat {
|
| repeat {
|
||||||
| inc y
|
| inc y
|
||||||
| } until not z
|
| } until not z
|
||||||
@ -149,7 +149,7 @@ Basic "open-faced for" loops, up and down.
|
|||||||
|
|
||||||
| byte table[256] tab
|
| byte table[256] tab
|
||||||
|
|
|
|
||||||
| routine foo trashes a, x, c, z, v {
|
| define foo routine trashes a, x, c, z, v {
|
||||||
| ld x, 0
|
| ld x, 0
|
||||||
| for x up to 15 {
|
| for x up to 15 {
|
||||||
| ld a, tab + x
|
| ld a, tab + x
|
||||||
@ -163,7 +163,7 @@ Basic "open-faced for" loops, up and down.
|
|||||||
|
|
||||||
Other blocks.
|
Other blocks.
|
||||||
|
|
||||||
| routine main trashes a, x, c, z, v {
|
| define main routine trashes a, x, c, z, v {
|
||||||
| with interrupts off {
|
| with interrupts off {
|
||||||
| save a, x, c {
|
| save a, x, c {
|
||||||
| ld a, 0
|
| ld a, 0
|
||||||
@ -183,7 +183,7 @@ User-defined memory addresses of different types.
|
|||||||
| buffer[2048] buf
|
| buffer[2048] buf
|
||||||
| pointer ptr
|
| pointer ptr
|
||||||
|
|
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| }
|
| }
|
||||||
= ok
|
= ok
|
||||||
|
|
||||||
@ -193,7 +193,7 @@ Tables of different types and some operations on them.
|
|||||||
| word table[256] wmany
|
| word table[256] wmany
|
||||||
| vector (routine trashes a) table[256] vmany
|
| vector (routine trashes a) table[256] vmany
|
||||||
|
|
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| ld x, 0
|
| ld x, 0
|
||||||
| ld a, 0
|
| ld a, 0
|
||||||
| st off, c
|
| st off, c
|
||||||
@ -215,7 +215,7 @@ greater than 0 and less than or equal to 256.
|
|||||||
|
|
||||||
| word table[512] many
|
| word table[512] many
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs many
|
| inputs many
|
||||||
| outputs many
|
| outputs many
|
||||||
| trashes a, x, n, z
|
| trashes a, x, n, z
|
||||||
@ -227,7 +227,7 @@ greater than 0 and less than or equal to 256.
|
|||||||
|
|
||||||
| word table[0] many
|
| word table[0] many
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs many
|
| inputs many
|
||||||
| outputs many
|
| outputs many
|
||||||
| trashes a, x, n, z
|
| trashes a, x, n, z
|
||||||
@ -239,7 +239,7 @@ greater than 0 and less than or equal to 256.
|
|||||||
|
|
||||||
| word table[48] many
|
| word table[48] many
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
| inputs many
|
| inputs many
|
||||||
| outputs many
|
| outputs many
|
||||||
| trashes a, x, n, z
|
| trashes a, x, n, z
|
||||||
@ -256,7 +256,7 @@ Typedefs of different types.
|
|||||||
| typedef routine trashes a game_routine
|
| typedef routine trashes a game_routine
|
||||||
| vector game_routine start_game
|
| vector game_routine start_game
|
||||||
|
|
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| }
|
| }
|
||||||
= ok
|
= ok
|
||||||
|
|
||||||
@ -265,7 +265,7 @@ Can't have two typedefs with the same name.
|
|||||||
| typedef byte frank
|
| typedef byte frank
|
||||||
| typedef word frank
|
| typedef word frank
|
||||||
|
|
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| }
|
| }
|
||||||
? SyntaxError
|
? SyntaxError
|
||||||
|
|
||||||
@ -280,7 +280,7 @@ Constants.
|
|||||||
|
|
|
|
||||||
| byte lark: lives
|
| byte lark: lives
|
||||||
|
|
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| ld a, lives
|
| ld a, lives
|
||||||
| }
|
| }
|
||||||
= ok
|
= ok
|
||||||
@ -290,7 +290,7 @@ Can't have two constants with the same name.
|
|||||||
| const w1 1000
|
| const w1 1000
|
||||||
| const w1 word 0
|
| const w1 word 0
|
||||||
|
|
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| }
|
| }
|
||||||
? SyntaxError
|
? SyntaxError
|
||||||
|
|
||||||
@ -298,7 +298,7 @@ Explicit memory address.
|
|||||||
|
|
||||||
| byte screen @ 1024
|
| byte screen @ 1024
|
||||||
|
|
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| ld a, 100
|
| ld a, 100
|
||||||
| st a, screen
|
| st a, screen
|
||||||
| shl screen
|
| shl screen
|
||||||
@ -310,7 +310,7 @@ Initialized memory locations.
|
|||||||
|
|
||||||
| byte lives : 3
|
| byte lives : 3
|
||||||
|
|
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| ld a, lives
|
| ld a, lives
|
||||||
| st a, lives
|
| st a, lives
|
||||||
| }
|
| }
|
||||||
@ -320,7 +320,7 @@ Cannot have both initial value and explicit address.
|
|||||||
|
|
||||||
| byte screen : 3 @ 1024
|
| byte screen : 3 @ 1024
|
||||||
|
|
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| ld a, lives
|
| ld a, lives
|
||||||
| st a, lives
|
| st a, lives
|
||||||
| }
|
| }
|
||||||
@ -333,7 +333,7 @@ User-defined locations of other types.
|
|||||||
| word r2 @ 60000
|
| word r2 @ 60000
|
||||||
| word r3 : 2000
|
| word r3 : 2000
|
||||||
|
|
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| }
|
| }
|
||||||
= ok
|
= ok
|
||||||
|
|
||||||
@ -341,15 +341,15 @@ Initialized byte table, initialized with ASCII string.
|
|||||||
|
|
||||||
| byte table[32] message : "WHAT DO YOU WANT TO DO NEXT?"
|
| byte table[32] message : "WHAT DO YOU WANT TO DO NEXT?"
|
||||||
|
|
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| }
|
| }
|
||||||
= ok
|
= ok
|
||||||
|
|
||||||
Can't initialize anything but a byte table with a string.
|
Can't initialize anything but a byte table with a string.
|
||||||
|
|
||||||
| word message : "WHAT DO YOU WANT TO DO NEXT?"
|
| word message : "OUCH! WHAT DO YOU DO?"
|
||||||
|
|
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| }
|
| }
|
||||||
? SyntaxError
|
? SyntaxError
|
||||||
|
|
||||||
@ -357,13 +357,13 @@ Initialized byte table, initialized with list of bytes.
|
|||||||
|
|
||||||
| byte table[8] charmap : 0, 255, 129, 192, 0, 1, 2, 4
|
| byte table[8] charmap : 0, 255, 129, 192, 0, 1, 2, 4
|
||||||
|
|
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| }
|
| }
|
||||||
= ok
|
= ok
|
||||||
|
|
||||||
Can't access an undeclared memory location.
|
Can't access an undeclared memory location.
|
||||||
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| ld a, 0
|
| ld a, 0
|
||||||
| st a, lives
|
| st a, lives
|
||||||
| }
|
| }
|
||||||
@ -374,7 +374,7 @@ Can't define two memory locations with the same name.
|
|||||||
| byte lives
|
| byte lives
|
||||||
| byte lives
|
| byte lives
|
||||||
|
|
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| ld a, 0
|
| ld a, 0
|
||||||
| st a, lives
|
| st a, lives
|
||||||
| }
|
| }
|
||||||
@ -384,19 +384,19 @@ Can't shadow the name of a register or a flag.
|
|||||||
|
|
||||||
| byte a
|
| byte a
|
||||||
|
|
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| }
|
| }
|
||||||
? SyntaxError
|
? SyntaxError
|
||||||
|
|
||||||
| byte z
|
| byte z
|
||||||
|
|
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| }
|
| }
|
||||||
? SyntaxError
|
? SyntaxError
|
||||||
|
|
||||||
Can't call routine that hasn't been defined.
|
Can't call routine that hasn't been defined.
|
||||||
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| ld x, 0
|
| ld x, 0
|
||||||
| ld y, 1
|
| ld y, 1
|
||||||
| call up
|
| call up
|
||||||
@ -404,44 +404,26 @@ Can't call routine that hasn't been defined.
|
|||||||
| }
|
| }
|
||||||
? SyntaxError
|
? SyntaxError
|
||||||
|
|
||||||
And you can't call a non-routine.
|
|
||||||
|
|
||||||
| byte up
|
|
||||||
|
|
|
||||||
| routine main {
|
|
||||||
| ld x, 0
|
|
||||||
| ld y, 1
|
|
||||||
| call up
|
|
||||||
| }
|
|
||||||
? SyntaxError
|
|
||||||
|
|
||||||
| routine main {
|
|
||||||
| ld x, 0
|
|
||||||
| ld y, 1
|
|
||||||
| call x
|
|
||||||
| }
|
|
||||||
? SyntaxError
|
|
||||||
|
|
||||||
But you can call a routine that is yet to be defined, further on.
|
But you can call a routine that is yet to be defined, further on.
|
||||||
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| ld x, 0
|
| ld x, 0
|
||||||
| ld y, 1
|
| ld y, 1
|
||||||
| call up
|
| call up
|
||||||
| call up
|
| call up
|
||||||
| }
|
| }
|
||||||
| routine up {
|
| define up routine {
|
||||||
| ld a, 0
|
| ld a, 0
|
||||||
| }
|
| }
|
||||||
= ok
|
= ok
|
||||||
|
|
||||||
Can't define two routines with the same name.
|
Can't define two routines with the same name.
|
||||||
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| inc x
|
| inc x
|
||||||
| inc y
|
| inc y
|
||||||
| }
|
| }
|
||||||
| routine main {
|
| define main routine {
|
||||||
| ld x, 0
|
| ld x, 0
|
||||||
| ld y, 1
|
| ld y, 1
|
||||||
| }
|
| }
|
||||||
@ -451,7 +433,7 @@ Declaring byte and word table memory location.
|
|||||||
|
|
||||||
| byte table[256] tab
|
| byte table[256] tab
|
||||||
|
|
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| ld x, 0
|
| ld x, 0
|
||||||
| ld y, 0
|
| ld y, 0
|
||||||
| ld a, tab + x
|
| ld a, tab + x
|
||||||
@ -462,7 +444,7 @@ Declaring byte and word table memory location.
|
|||||||
| word one
|
| word one
|
||||||
| word table[256] many
|
| word table[256] many
|
||||||
|
|
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| ld x, 0
|
| ld x, 0
|
||||||
| copy one, many + x
|
| copy one, many + x
|
||||||
| copy word 0, many + x
|
| copy word 0, many + x
|
||||||
@ -478,10 +460,10 @@ Declaring and calling a vector.
|
|||||||
| trashes a, x, z, n
|
| trashes a, x, z, n
|
||||||
| cinv @ 788
|
| cinv @ 788
|
||||||
|
|
|
|
||||||
| routine foo {
|
| define foo routine {
|
||||||
| ld a, 0
|
| ld a, 0
|
||||||
| }
|
| }
|
||||||
| routine main {
|
| define main routine {
|
||||||
| with interrupts off {
|
| with interrupts off {
|
||||||
| copy foo, cinv
|
| copy foo, cinv
|
||||||
| }
|
| }
|
||||||
@ -497,7 +479,7 @@ Only vectors can be decorated with constraints like that.
|
|||||||
| trashes a, x, z, n
|
| trashes a, x, z, n
|
||||||
| @ 788
|
| @ 788
|
||||||
|
|
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| }
|
| }
|
||||||
? SyntaxError
|
? SyntaxError
|
||||||
|
|
||||||
@ -509,10 +491,10 @@ Constraints set may only contain labels.
|
|||||||
| trashes a, x, z, n
|
| trashes a, x, z, n
|
||||||
| cinv @ 788
|
| cinv @ 788
|
||||||
|
|
|
|
||||||
| routine foo {
|
| define foo routine {
|
||||||
| ld a, 0
|
| ld a, 0
|
||||||
| }
|
| }
|
||||||
| routine main {
|
| define main routine {
|
||||||
| with interrupts off {
|
| with interrupts off {
|
||||||
| copy foo, cinv
|
| copy foo, cinv
|
||||||
| }
|
| }
|
||||||
@ -528,10 +510,10 @@ A vector can name itself in its inputs, outputs, and trashes.
|
|||||||
| trashes a, x, z, n
|
| trashes a, x, z, n
|
||||||
| cinv @ 788
|
| cinv @ 788
|
||||||
|
|
|
|
||||||
| routine foo {
|
| define foo routine {
|
||||||
| ld a, 0
|
| ld a, 0
|
||||||
| }
|
| }
|
||||||
| routine main {
|
| define main routine {
|
||||||
| with interrupts off {
|
| with interrupts off {
|
||||||
| copy foo, cinv
|
| copy foo, cinv
|
||||||
| }
|
| }
|
||||||
@ -548,50 +530,43 @@ references in the source of a `copy` instruction.
|
|||||||
| outputs cinv, x
|
| outputs cinv, x
|
||||||
| trashes a, x, z, n
|
| trashes a, x, z, n
|
||||||
| cinv @ 788
|
| cinv @ 788
|
||||||
| routine main {
|
| define main routine {
|
||||||
| with interrupts off {
|
| with interrupts off {
|
||||||
| copy foo, cinv
|
| copy foo, cinv
|
||||||
| }
|
| }
|
||||||
| call cinv
|
| call cinv
|
||||||
| }
|
| }
|
||||||
| routine foo {
|
| define foo routine {
|
||||||
| ld a, 0
|
| ld a, 0
|
||||||
| }
|
| }
|
||||||
= ok
|
= ok
|
||||||
|
|
||||||
goto.
|
goto.
|
||||||
|
|
||||||
| routine foo {
|
| define foo routine {
|
||||||
| ld a, 0
|
| ld a, 0
|
||||||
| }
|
| }
|
||||||
| routine main {
|
| define main routine {
|
||||||
| goto foo
|
| goto foo
|
||||||
| }
|
| }
|
||||||
= ok
|
= ok
|
||||||
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| goto foo
|
| goto foo
|
||||||
| }
|
| }
|
||||||
| routine foo {
|
| define foo routine {
|
||||||
| ld a, 0
|
| ld a, 0
|
||||||
| }
|
| }
|
||||||
= ok
|
= ok
|
||||||
|
|
||||||
| vector routine foo
|
| vector routine foo
|
||||||
|
|
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| goto foo
|
| goto foo
|
||||||
| }
|
| }
|
||||||
= ok
|
= ok
|
||||||
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| goto foo
|
|
||||||
| }
|
|
||||||
? SyntaxError
|
|
||||||
|
|
||||||
| byte foo
|
|
||||||
|
|
|
||||||
| routine main {
|
|
||||||
| goto foo
|
| goto foo
|
||||||
| }
|
| }
|
||||||
? SyntaxError
|
? SyntaxError
|
||||||
@ -603,7 +578,7 @@ Buffers and pointers.
|
|||||||
| pointer ptrb
|
| pointer ptrb
|
||||||
| byte foo
|
| byte foo
|
||||||
|
|
|
|
||||||
| routine main {
|
| define main routine {
|
||||||
| copy ^buf, ptr
|
| copy ^buf, ptr
|
||||||
| copy 123, [ptr] + y
|
| copy 123, [ptr] + y
|
||||||
| copy [ptr] + y, foo
|
| copy [ptr] + y, foo
|
||||||
@ -629,7 +604,28 @@ Routines can be defined in a new style.
|
|||||||
| inc x
|
| inc x
|
||||||
| }
|
| }
|
||||||
|
|
|
|
||||||
| routine main
|
| define main routine
|
||||||
|
| outputs vec
|
||||||
|
| trashes a, z, n
|
||||||
|
| {
|
||||||
|
| copy foo, vec
|
||||||
|
| }
|
||||||
|
= ok
|
||||||
|
|
||||||
|
| typedef routine
|
||||||
|
| inputs x
|
||||||
|
| outputs x
|
||||||
|
| trashes z, n
|
||||||
|
| routine_type
|
||||||
|
|
|
||||||
|
| vector routine_type vec
|
||||||
|
|
|
||||||
|
| define foo routine_type
|
||||||
|
| {
|
||||||
|
| inc x
|
||||||
|
| }
|
||||||
|
|
|
||||||
|
| define main routine
|
||||||
| outputs vec
|
| outputs vec
|
||||||
| trashes a, z, n
|
| trashes a, z, n
|
||||||
| {
|
| {
|
||||||
|
Loading…
Reference in New Issue
Block a user