An eDSL for writing 65(C)02 bytecode.
An eDSL for writing 65(C)02 bytecode. Please see the README on GitHub at https://github.com/aearnus/sixty-five-oh-two#readme
DSL.SixtyFiveOhTwo: A 65C02 Assembly eDSL in Haskell
... shut up, show me the code!
Here's some example code utilizing all of the features of the eDSL:
import DSL.SixtyFiveOhTwo
accumulatorLoadNStore :: Instruction
accumulatorLoadNStore = do
lda (Immediate 0x10)
sta (Absolute 0x0200)
rts (Implied)
myProgram :: Instruction
myProgram = do
define "accumulatorLoadNStore" accumulatorLoadNStore
call "accumulatorLoadNStore"
Here's a fun little snippet that adds 10 to the accumulator using Haskell Monad Magic:tm::
test3f2 :: Instruction
test3f2 = replicateM_ 10 (inc (Accumulator))
Everything that this module exposes is in src/DSL/SixtyFiveOhTwo.hs. A quick browse through this file will reveal the full extent of the features of this eDSL.
What is this?
This is an embedded Domain Specific Language that allows a user to write code that runs on the 65C02 CPU. This is the CPU that runs devices such as the Apple II, Commodore 64, or the NES.
What does the language provide me?
- Full coverage. Everything bit of code that the 65C02 can understand is represented in this language. Everywhere
adc
towai
can be used. These opcodes are represented as generic operations, each of which simply append to the bytecode that gets passed into it. Here's an example of the definition for a certain opcode:
lda :: AddressingMode -> Instruction
lda (Immediate b) = genericOp 169 b
lda (ZeroPage b) = genericOp 165 b
lda (ZeroPageX b) = genericOp 181 b
lda (Absolute b) = genericTwoByteOp 173 b
lda (AbsoluteX b) = genericTwoByteOp 189 b
lda (AbsoluteY b) = genericTwoByteOp 185 b
lda (ZeroPageIndirect b) = genericOp 178 b
lda (IndirectX b) = genericOp 161 b
lda (IndirectY b) = genericOp 177 b
- Type safety. Every addressing mode is represented the Haskell type system, and thus issues will be caught at compile time. The
AddressingMode
ADT is used to represent a function's addressing mode, and opcodes do not take addressing modes that they do not support.
data AddressingMode =
Implied |
Accumulator |
Immediate Word8 |
Relative Int8 | -- Signed
ZeroPageRelative Int8 | -- Signed
Absolute Word16 |
AbsoluteX Word16 |
AbsoluteY Word16 |
ZeroPage Word8 |
ZeroPageX Word8 |
ZeroPageY Word8 |
ZeroPageIndirect Word8 |
Indirect Word16 |
IndirectX Word8 |
IndirectY Word8
- Easy abstractions. The
define
andcall
keywords automatically generate the code necessary to create and call subroutines.
Support or Donate
Please contact me if you have any wish to support this project or any other projects I've worked on. The information is in package.yaml
.