1
0
mirror of https://github.com/catseye/SixtyPical.git synced 2025-01-25 08:30:07 +00:00

byte table -> byte[SIZE], and you can reserve them.

This commit is contained in:
Cat's Eye Technologies 2014-04-11 21:47:18 +01:00
parent 9a0896c90f
commit 9532a9399c
8 changed files with 85 additions and 28 deletions

View File

@ -90,6 +90,30 @@ poisoned in the result context.
(Same should apply for `repeat` and `with` and, really, many other cases
which there just aren't enough test cases for yet.)
### "It's a Partial Solution" ###
SixtyPical does not attempt to force your typed, abstractly interpreted
program to be absolutely watertight. In assembly language on an 8-bit
microprocessor, you will sometimes _need_ to do dangerous and tricky things,
like self-modifying code and cycle-counting, in order to accomplish a
sophisticated effect, like a raster interrupt trick.
For that reason, `sixtypical` does not attempt to emit a fully-formed
Ophis assembler source. Instead, it expects you to mix its output with
some raw Ophis assembler to make a complete program. This "mixin" may contain
as much unchecked assembler code as you like. An example is provided in the
`lib` directory which adds a prelude that makes the resulting program
runnable from Commodore BASIC 2.0 and stores uninitialized data at `$C000`.
In addition, various checks are not attempted (such as tracking the usage
of an indirect indexed table) and other checks may be subverted (for example
by `locate`ing two variables with two different types of storage at the same
address.)
In summary, SixtyPical helps you write a very-nearly-assembly-level program
which is a bit more "solid" than raw assembly, but it still expects you to
know what you're doing down there.
For More Information
--------------------
@ -123,7 +147,6 @@ TODO
----
* Initial values for reserved 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)`

View File

@ -116,8 +116,8 @@ Test for many combinations of `reserve` and `assign`.
| assign word memstr 641
| reserve vector v
| assign vector cinv 788
| reserve byte table frequencies
| assign byte table screen 1024
| reserve byte[16] frequencies
| assign byte[256] screen 1024
| routine main {
| nop
| }
@ -223,7 +223,7 @@ We can't jump indirectly through a byte.
We can absolute-indexed a byte table.
| assign byte table screen 1024
| assign byte[256] screen 1024
| routine main {
| sta screen, x
| }
@ -296,9 +296,9 @@ An address knows what kind of data is stored at the address:
* `jsr`'ing indirectly to a vector (which is done with a fun
generated trick (NYI))
* `byte table`: a series of `byte`s contiguous in memory starting from the
address. This is the only kind of address that can be used in
indexed addressing.
* `byte [SIZE]`: a series of `SIZE` `byte`s contiguous in memory starting
from the address. This is the only kind of address that can be used in
indexed addressing. `SIZE` has a minimum of 1 and a maximum of 256.
### Blocks ###

View File

@ -189,3 +189,25 @@ Copy command: immediate -> word
=
= .data
= .space position 2
Reserving and assigning byte tables.
| reserve byte[16] frequencies
| assign byte[256] screen $0400
| routine main {
| lda #0
| ldy #0
| sta frequencies, y
| sta screen, y
| }
= main:
= lda #0
= ldy #0
= sta frequencies, y
= sta screen, y
= rts
=
= .data
= .space frequencies 16
= .alias screen 1024

View File

@ -150,7 +150,7 @@ Big test for parsing and emitting instructions.
| reserve word vword
| reserve byte vbyte
| assign byte table table 1024
| assign byte[256] table 1024
| routine main {
| lda #4
| ldx #0
@ -263,7 +263,7 @@ Big test for parsing and emitting instructions.
| reserve word vword
| reserve byte vbyte
| assign byte table table 1024
| assign byte[256] table 1024
| routine main {
| asl .a
| asl vbyte

View File

@ -30,8 +30,8 @@ noIndexedAccessOfNonTables p@(Program decls routines) =
where
checkInstr j@(COPY _ (Indexed (NamedLocation sz g) reg)) =
case lookupDecl p g of
Just (Assign _ ByteTable _) -> j
Just (Reserve _ ByteTable _) -> j
Just (Assign _ (ByteTable _) _) -> j
Just (Reserve _ (ByteTable _) _) -> j
Just _ -> (COPY A A)
Nothing -> (COPY A A)
checkInstr other = other
@ -158,8 +158,8 @@ fillOutNamedLocationTypes p@(Program decls routines) =
in
case (typeRx == typeRy, typeRx, typeRy) of
(True, _, _) -> constructor rx ry
(_, Byte, ByteTable) -> constructor rx ry
(_, ByteTable, Byte) -> constructor rx ry
(_, Byte, (ByteTable _)) -> constructor rx ry
(_, (ByteTable _), Byte) -> constructor rx ry
_ -> error ("incompatible types '" ++ (show typeRx) ++ "' and '" ++ (show typeRy) ++ "'")
resolve (NamedLocation Nothing name) =
case lookupDecl p name of

View File

@ -30,6 +30,9 @@ emitDecl p (Reserve name typ (Just val))
| typ == Word = name ++ ": .word " ++ (show val)
| typ == Vector = name ++ ": .word " ++ (show val)
emitDecl p (Reserve name (ByteTable size) Nothing) =
".space " ++ name ++ " " ++ (show size)
emitDecl p (Reserve name typ Nothing)
| typ == Byte = ".space " ++ name ++ " 1"
| typ == Word = ".space " ++ name ++ " 2"
@ -79,11 +82,11 @@ emitInstr p r (COPY A Y) = "tay"
emitInstr p r (COPY X A) = "txa"
emitInstr p r (COPY Y A) = "tya"
emitInstr p r (COPY A (Indexed (NamedLocation (Just ByteTable) label) X)) = "sta " ++ label ++ ", x"
emitInstr p r (COPY A (Indexed (NamedLocation (Just ByteTable) label) Y)) = "sta " ++ label ++ ", y"
emitInstr p r (COPY A (Indexed (NamedLocation (Just (ByteTable _)) label) X)) = "sta " ++ label ++ ", x"
emitInstr p r (COPY A (Indexed (NamedLocation (Just (ByteTable _)) label) Y)) = "sta " ++ label ++ ", y"
emitInstr p r (COPY (Indexed (NamedLocation (Just ByteTable) label) X) A) = "lda " ++ label ++ ", x"
emitInstr p r (COPY (Indexed (NamedLocation (Just ByteTable) label) Y) A) = "lda " ++ label ++ ", y"
emitInstr p r (COPY (Indexed (NamedLocation (Just (ByteTable _)) label) X) A) = "lda " ++ label ++ ", x"
emitInstr p r (COPY (Indexed (NamedLocation (Just (ByteTable _)) label) Y) A) = "lda " ++ label ++ ", y"
emitInstr p r (COPY A (IndirectIndexed (NamedLocation st label) Y)) = "sta (" ++ label ++ "), y"
emitInstr p r (COPY (IndirectIndexed (NamedLocation st label) Y) A) = "lda (" ++ label ++ "), y"

View File

@ -23,7 +23,7 @@ type LocationName = String
data StorageType = Byte
| Word
| Vector
| ByteTable
| ByteTable DataValue
deriving (Show, Ord, Eq)
data StorageLocation = A

View File

@ -14,7 +14,7 @@ Toplevel := {Decl} {Routine}.
Decl := "reserve" StorageType LocationName [":" Literal]
| "assign" StorageType LocationName Literal
| "external" RoutineName Address.
StorageType := "byte" | "word" | "byte table" | "vector".
StorageType := "byte" ["[" Literal "]"] | "word" | "vector".
Routine := "routine" RoutineName ["outputs" "(" {LocationName} ")"] Block.
Block := "{" {Command} "}".
Command := "if" Branch Block "else" Block
@ -91,17 +91,26 @@ external = do
addr <- literal_address
return $ External name addr
get_storage "byte" = Byte
get_storage "word" = Word
get_storage "vector" = Vector
get_storage "byte table" = ByteTable
storage :: String -> StorageType -> Parser StorageType
storage s t = do
string s
nspaces
return t
byte_table :: Parser StorageType
byte_table = do
string "byte"
nspaces
string "["
nspaces
size <- literal_data_value
string "]"
nspaces
return $ ByteTable size
storage_type :: Parser StorageType
storage_type = do
s <- (try $ string "byte table") <|> (string "byte") <|>
(string "word") <|> (string "vector")
nspaces
return $ get_storage s
storage_type = (try $ byte_table) <|> (storage "byte" Byte) <|>
(storage "word" Word) <|> (storage "vector" Vector)
routine :: Parser Routine
routine = do