1
0
mirror of https://github.com/catseye/SixtyPical.git synced 2024-11-26 14:49:15 +00:00
SixtyPical/README.markdown
Cat's Eye Technologies 37215cb72a Always emit main first.
2014-04-04 16:54:25 +01:00

123 lines
4.5 KiB
Markdown

SixtyPical
==========
SixtyPical is a very low-level programming language, similar to 6502 assembly,
with static analysis through type-checking and abstract interpretation.
It is a **work in progress**, currently at the **proof-of-concept** stage.
It is expected that a common use case for SixtyPical would be retroprogramming
for the Commodore 64 and other 6502-based computers such as the VIC-20.
Many SixtyPical instructions map precisely to 6502 opcodes. However, SixtyPical
is not an assembly language: the programmer does not have total control over
the layout of code and data in memory. Some 6502 opcodes have no SixtyPical
equivalent, while some have an equivalent that acts in a slightly different
(but intuitively related) way. And some commands are unique to SixtyPical.
`sixtypical` is the reference implementation of SixtyPical. It is written in
Haskell. It can currently parse and check a SixtyPical program, and can
emit an Ophis assembler listing for it.
This distribution will soon be placed under an open-source license.
Quick Start
-----------
If you have `ghc`, Ophis, and VICE 2.4 installed, clone this repo, `cd` into it,
and run
./loadngo.sh eg/demo.60p
The Big Idea(s)
---------------
### Typed Addresses ###
SixtyPical distinguishes several kinds of addresses: those that hold a byte,
those that hold a word (in low-byte-high-byte sequence), those that are the
beginning of a table of bytes, and vectors (those that hold a word pointer to a
machine-language routine.) It prevents the program from accessing them in
certain ways. For example, these are illegal:
reserve byte lives
reserve word score
routine do_it {
lda score ; no! can't treat word as if it were a byte
lda lives, x ; no! can't treat a byte as if it were a table
}
### Abstract Interpretation ###
SixtyPical tries to prevent the program from using data that has no meaning.
The instructions of a routine are analyzed using abstract interpretation.
One thing we specifically do is determine which registers and memory locations
are *not* affected by the routine. For example, the following:
routine do_it {
lda #0
jsr update_score
sta vic_border_colour ; uh... what do we know about reg A here?
}
...is illegal *unless* one of the following is true:
* the A register is declared to be a meaningful output of `update_score`
* `update_score` was determined to not change the value of the A register
The first case must be done with an explicit declaration on `update_score`.
The second case will be be inferred using abstract interpretation of the code
of `update_score`.
### Structured Programming ###
SixtyPical eschews labels for code and instead organizes code into _blocks_.
Instead of the assembly-language subroutine, SixtyPical provides the _routine_
as the abstraction for a reusable sequence of code. A routine may be called,
or may be included inline, by another routine. The body of a routine is a
block.
Along with routines, you get `if`, `repeat`, and `with` constructs which take
blocks. The `with` construct takes an instruction like `sei` and implicitly
(and unavoidably) inserts the corresponding `cli` at the end of the block.
For More Information
--------------------
For more information, see the docs (which are written in the form of
Falderal literate test suites. If you have Falderal installed, you can run
the tests with `./test.sh`.)
Ideas
-----
These aren't implemented yet:
* Abstract interpretation must extend to `if`, `repeat`, and `with`
blocks. The two incoming contexts must be merged, and any storage
locations updated differently or poisoned in either context, will be
considered poisoned in the result context.
* Inside a routine, an address may be declared with `temporary`. This is like
`static` in C, except the value at that address is not guaranteed to be
retained between invokations of the routine. Such addresses may only be used
within the routine where they are declared. If analysis indicates that two
temporary addresses are never used simultaneously, they may be merged
to the same address.
TODO
----
* Initial values for reserved, incl. tables
* give length for tables, must be there for reserved, if no init val
* Character tables ("strings" to everybody else)
* Addressing modes — indexed mode on more instructions
* `jsr (vector)`
* `jmp routine`
* insist on EOL after each instruction. need spacesWOEOL production
* asl .a
* `outputs` on externals
* Routine is a kind of StorageLocation? (Location)?