diff --git a/README.markdown b/README.markdown index ccbf08c..6da3d2c 100644 --- a/README.markdown +++ b/README.markdown @@ -74,9 +74,9 @@ Each routine is a block. It may be composed of inner blocks, attached to some instructions. SixtyPical does not have instructions that map literally to the 6502 branch -instructions. Instead, each branch instruction has a corresponding -"if-then-else"-like construct with the same name as the branch instruction. -These _test_ instructions each have two blocks, for the then and the else. +instructions. Instead, it has an `if` construct, with two blocks (for the +"then" and `else` parts), and the branch instructions map to conditions for +this construct. The abstract states of the machine at each of the different block exits are merged during analysis. If any register or memory location is treated @@ -85,7 +85,9 @@ that register cannot subsequently be used without a declaration to the effect that we know what's going on. (This is all a bit fuzzy right now.) There is also no `rts` instruction. It is included at the end of a routine, -but only when the routine is used as a subroutine. +but only when the routine is used as a subroutine. Also, if the routine +ends by `jsr`ing another routine, it reserves the right to do a tail-call +or even a fallthrough. There are also _with_ instructions, which are associated with an opcode that has a natural symmetrical opcode (e.g. `pha`, `sei`). These instructions @@ -120,12 +122,150 @@ This might be Note, `screen` must be a `byte table` here. +Instruction Support so far +-------------------------- + +A `X` indicates unsupported. A `!` indicates will-not-support. + +Funny syntax indicates use of a special form. + +In these, `absolute` must be a `reserve`d or `locate`d address. + + X adc #immediate + X adc absolute + + X and #immediate + X and absolute + + X asl + X asl absolute + + if bcc { block } else { block } + + if bcs { block } else { block } + + if beq { block } else { block } + + X bit absolute + + if bmi { block } else { block } + + if bne { block } else { block } + + if bpl { block } else { block } + + ! brk + + if bvc { block } else { block } + + if bvs { block } else { block } + + X clc + + X cld + + ! cli + + X clv + + cmp absolute + X cmp #immediate + + X cpx absolute + X cpx #immediate + + X cpy absolute + X cpy #immediate + + X dec absolute + + X dex + + X dey + + X eor #immediate + X eor absolute + + X inc absolute + + X inx + + X iny + + ! jmp + + * jsr routine + + lda absolute + X lda #immediate + + ldx absolute + X ldx #immediate + + ldy absolute + X ldy #immediate + + X lsr + X lsr absolute + + nop + + X ora #immediate + X ora absolute + + X pha { block } + + X php { block } + + ! pla -- (although note this does change flags) + + ! plp -- (although note this does change flags -- obviously) + + X rol + X rol absolute + + X ror + X ror absolute + + ! rti + + ! rts + + X sbc #immediate + X sbc absolute + + X sec + + X sed + + X sei { block } + + sta absolute + + stx absolute + + sty absolute + + tax + + tay + + X tsx + + txa + + X txs + + tya + TODO ---- * Parse HEX values like $40A3 * Fuller machine model +* parse support immediate loads, compares * Addressing modes; rename instructions to match +* Generate code for BEQ Tests ----- @@ -192,7 +332,7 @@ Even in inner blocks. | routine main { | lda score | cmp screen - | beq { + | if beq { | lda score | } else { | lda fnord diff --git a/eg/compare.60pical b/eg/compare.60pical index 405613f..78ac1de 100644 --- a/eg/compare.60pical +++ b/eg/compare.60pical @@ -6,7 +6,7 @@ reserve byte n_low routine compare_16_bit { lda m_high cmp n_high - beq { + if beq { lda m_low cmp n_low } else { diff --git a/src/SixtyPical/Analyzer.hs b/src/SixtyPical/Analyzer.hs index 9efe5bf..13d180e 100644 --- a/src/SixtyPical/Analyzer.hs +++ b/src/SixtyPical/Analyzer.hs @@ -75,7 +75,7 @@ checkInstr (JSR name) progCtx routCtx = checkInstr (CMP reg addr) progCtx routCtx = -- TODO: mark Carry bit as "touched" here routCtx -checkInstr (IFEQ b1 b2) progCtx routCtx = +checkInstr (IF branch b1 b2) progCtx routCtx = -- TODO: oooh, this one's gonna be fun routCtx checkInstr NOP progCtx routCtx = diff --git a/src/SixtyPical/Checker.hs b/src/SixtyPical/Checker.hs index 664b113..97f2bd4 100644 --- a/src/SixtyPical/Checker.hs +++ b/src/SixtyPical/Checker.hs @@ -34,7 +34,7 @@ instrUsedLocations (COPY (NamedLocation loc) _) = [loc] instrUsedLocations (COPY _ (NamedLocation loc)) = [loc] instrUsedLocations (CMP reg (NamedLocation loc)) = [loc] -- TODO: JSR... -instrUsedLocations (IFEQ b1 b2) = +instrUsedLocations (IF branch b1 b2) = blockUsedLocations b1 ++ blockUsedLocations b2 instrUsedLocations _ = [] diff --git a/src/SixtyPical/Model.hs b/src/SixtyPical/Model.hs index 4b1b5f8..6c09655 100644 --- a/src/SixtyPical/Model.hs +++ b/src/SixtyPical/Model.hs @@ -46,11 +46,14 @@ data Decl = Assign LocationName Size Address -- .alias type RoutineName = String +data Branch = BCC | BCS | BEQ | BMI | BNE | BPL | BVC | BVS + deriving (Show, Ord, Eq) + data Instruction = LOADIMM StorageLocation DataValue | COPY StorageLocation StorageLocation | CMP StorageLocation StorageLocation | JSR RoutineName - | IFEQ [Instruction] [Instruction] + | IF Branch [Instruction] [Instruction] | NOP deriving (Show, Ord, Eq) diff --git a/src/SixtyPical/Parser.hs b/src/SixtyPical/Parser.hs index 5b464dd..dc4c8e7 100644 --- a/src/SixtyPical/Parser.hs +++ b/src/SixtyPical/Parser.hs @@ -13,13 +13,14 @@ Decl := "reserve" Size LocationName Size := "byte" | "word". Routine := "routine" RoutineName Block. Block := "{" {Command} "}". -Command := "beq" Block "else" Block +Command := "if" Branch Block "else" Block | "lda" (LocationName | Immediate) | "ldx" (LocationName | Immediate) | "ldy" (LocationName | Immediate) | "txa" | "tax" | "tya" | "tay" | "cmp" (LocationName | Immediate) | "nop". +Branch := "bcc" | "bcs" | "beq" | "bmi" | "bne" | "bpl" | "bvc" | "bvs". -} @@ -76,7 +77,7 @@ command :: Parser Instruction command = cmp <|> (try lda) <|> (try ldx) <|> (try ldy) <|> (try sta) <|> (try stx) <|> (try sty) <|> (try txa) <|> (try tax) <|> (try tya) <|> (try tay) <|> - beq <|> nop + if_statement <|> nop nop :: Parser Instruction nop = do @@ -157,15 +158,27 @@ tay = do spaces return (COPY A Y) -beq :: Parser Instruction -beq = do - string "beq" +if_statement :: Parser Instruction +if_statement = do + string "if" spaces + brch <- branch b1 <- block string "else" spaces b2 <- block - return (IFEQ b1 b2) + return (IF brch b1 b2) + +branch :: Parser Branch +branch = try (b "bcc" BCC) <|> try (b "bcs" BCS) <|> try (b "beq" BEQ) <|> + try (b "bmi" BMI) <|> try (b "bne" BNE) <|> try (b "bpl" BPL) <|> + try (b "bvc" BVC) <|> (b "bvs" BVS) + +b :: String -> Branch -> Parser Branch +b s k = do + string s + spaces + return k routineName :: Parser String routineName = do