package com.htmlism.mos6502.dsl import scala.collection.immutable.ListSet import scala.collection.mutable.ListBuffer import cats.implicits._ import com.htmlism.mos6502.model._ object DslDemo extends App { val cpu = new CPU import registers.{A, X} // address demonstration withAssemblyContext { implicit ctx => val payloadLocation = 0x01.z cpu.A = 0x40 A.add(payloadLocation) } // a becomes others withAssemblyContext { implicit ctx => cpu.A = cpu.X cpu.A = cpu.Y } // demonstrate first example withAssemblyContext { implicit ctx => cpu.A = 0xc0 cpu.X = cpu.A X.incr A.add(0xc4) } def withAssemblyContext(f: AssemblyContext => Unit): Unit = { val ctx: AssemblyContext = new AssemblyContext f(ctx) ctx.printOut() println() println() } } object registers { sealed trait Register sealed trait DestinationA sealed trait IndexRegister case object A extends Register { def add[A](x: A)(implicit ctx: AssemblyContext, ev: Operand[A]): Unit = ev.operandType match { case ValueLiteral => ctx.push(ADC, x, s"add LITERAL to a") case MemoryLocation => ctx.push(ADC, x, s"add ADDR to a") } } case object X extends Register with DestinationA with IndexRegister { def incr(implicit ctx: AssemblyContext): Unit = ctx.push(INX, "incr x") def upTo(s: String, start: Int, stop: Int)(f: AssemblyContext => Unit)(implicit ctx: AssemblyContext): Unit = { ctx.push(LDX, start) label(s) f(ctx) ctx.push(INX) ctx.push(CPX, stop) ctx.branch(BNE, s) } def downTo(s: String, start: Int, stop: Int)(f: AssemblyContext => Unit)(implicit ctx: AssemblyContext): Unit = { ctx.push(LDX, start) label(s) f(ctx) ctx.push(DEX) ctx.push(CPX, stop) ctx.branch(BNE, s) } } case object Y extends Register with DestinationA with IndexRegister } class CPU { def A: registers.A.type = registers.A def A_=[A](x: A)(implicit ctx: AssemblyContext, ev: Operand[A]): Unit = ctx.push(LDA, x, "set A to " + ev.toShow(x)) def A_=(reg: registers.DestinationA)(implicit ctx: AssemblyContext): Unit = reg match { case registers.X => ctx.push(TXA) case registers.Y => ctx.push(TYA) } def X: registers.X.type = registers.X def X_=(reg: registers.A.type)(implicit ctx: AssemblyContext): Unit = ctx.push(TAX, s"set x to register $reg") def Y: registers.Y.type = registers.Y def Y_=(reg: registers.A.type)(implicit ctx: AssemblyContext): Unit = ctx.push(TAY, s"set x to register $reg") } class AssemblyContext { private val xs: ListBuffer[Statement] = ListBuffer() private var jumps: ListSet[Subroutine] = ListSet() def push(instruction: Instruction): Unit = xs.append(UnaryInstruction(instruction, None)) def push(instruction: Instruction, s: String): Unit = xs.append(UnaryInstruction(instruction, s.some)) def label(s: String): Unit = xs.append(Label(s)) def push[A: Operand](instruction: Instruction, x: A): Unit = xs.append(InstructionWithOperand(instruction, x, None)) def push[A: Operand](instruction: Instruction, x: A, s: String): Unit = xs.append(InstructionWithOperand(instruction, x: A, s.some)) def branch(instruction: Instruction, label: String): Unit = xs.append(BranchingInstruction(instruction, label)) def addJump(subroutine: Subroutine): Unit = jumps = jumps + subroutine def printOut(): Unit = { xs.map(_.toAsm) .foreach(println) } def triplets: List[(String, Option[String], Option[String])] = xs.map(_.toTriplet).toList def toFragment: AsmFragment = AsmFragment(xs.toList) def getJumps: ListSet[Subroutine] = jumps }