diff --git a/README.markdown b/README.markdown index b937e7a..0c9d340 100644 --- a/README.markdown +++ b/README.markdown @@ -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)` diff --git a/doc/Checking.markdown b/doc/Checking.markdown index ffcca1d..194b812 100644 --- a/doc/Checking.markdown +++ b/doc/Checking.markdown @@ -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 ### diff --git a/doc/Emitting.markdown b/doc/Emitting.markdown index e30aa18..1671539 100644 --- a/doc/Emitting.markdown +++ b/doc/Emitting.markdown @@ -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 + diff --git a/doc/Instruction_Support.markdown b/doc/Instruction_Support.markdown index 986d506..3c529c5 100644 --- a/doc/Instruction_Support.markdown +++ b/doc/Instruction_Support.markdown @@ -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 diff --git a/src/SixtyPical/Checker.hs b/src/SixtyPical/Checker.hs index c2ffcfc..35663fc 100644 --- a/src/SixtyPical/Checker.hs +++ b/src/SixtyPical/Checker.hs @@ -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 diff --git a/src/SixtyPical/Emitter.hs b/src/SixtyPical/Emitter.hs index 8f249e4..43369d2 100644 --- a/src/SixtyPical/Emitter.hs +++ b/src/SixtyPical/Emitter.hs @@ -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" diff --git a/src/SixtyPical/Model.hs b/src/SixtyPical/Model.hs index ed0ce45..b790ff0 100644 --- a/src/SixtyPical/Model.hs +++ b/src/SixtyPical/Model.hs @@ -23,7 +23,7 @@ type LocationName = String data StorageType = Byte | Word | Vector - | ByteTable + | ByteTable DataValue deriving (Show, Ord, Eq) data StorageLocation = A diff --git a/src/SixtyPical/Parser.hs b/src/SixtyPical/Parser.hs index c037e0d..683b278 100644 --- a/src/SixtyPical/Parser.hs +++ b/src/SixtyPical/Parser.hs @@ -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