mirror of
https://github.com/mcanlas/6502-opcodes.git
synced 2024-06-01 15:41:35 +00:00
scala3
This commit is contained in:
parent
7452871e71
commit
08960dc94c
|
@ -2,7 +2,6 @@ package com.htmlism.nescant
|
|||
|
||||
trait ByteSource[A]
|
||||
|
||||
object ByteSource {
|
||||
object ByteSource:
|
||||
implicit val sourceForInt: ByteSource[Int] =
|
||||
new ByteSource[Int] {}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
package com.htmlism.nescant
|
||||
|
||||
object GlobalAddress {
|
||||
object GlobalAddress:
|
||||
implicit val sourceForGlobalAddress: ByteSource[GlobalAddress] =
|
||||
new ByteSource[GlobalAddress] {}
|
||||
|
||||
implicit val sinkForGlobalAddress: ByteSink[GlobalAddress] =
|
||||
new ByteSink[GlobalAddress] {}
|
||||
}
|
||||
|
||||
case class GlobalAddress(n: Int)
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
package com.htmlism.nescant
|
||||
|
||||
trait Operand[A] {
|
||||
trait Operand[A]:
|
||||
def encode(x: A): String
|
||||
}
|
||||
|
||||
object Operand {
|
||||
object Operand:
|
||||
implicit val operandForInt: Operand[Int] =
|
||||
_.toString
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ package com.htmlism.nescant
|
|||
*/
|
||||
case class ReadWriteLocation[A](name: String, address: ZeroPageAddress)
|
||||
|
||||
object ReadWriteLocation {
|
||||
object ReadWriteLocation:
|
||||
implicit def sourceForReadWriteLocation[A]: ByteSource[ReadWriteLocation[A]] =
|
||||
new ByteSource[ReadWriteLocation[A]] {}
|
||||
|
||||
|
@ -20,4 +20,3 @@ object ReadWriteLocation {
|
|||
new Operand[ReadWriteLocation[A]] {
|
||||
def encode(x: ReadWriteLocation[A]): String = ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ package com.htmlism.nescant
|
|||
*/
|
||||
case class VolatileDevice[A](name: String, address: ZeroPageAddress)
|
||||
|
||||
object VolatileDevice {
|
||||
object VolatileDevice:
|
||||
implicit def sourceForVolatileDevice[A]: ByteSource[VolatileDevice[A]] =
|
||||
new ByteSource[VolatileDevice[A]] {}
|
||||
|
||||
|
@ -21,4 +21,3 @@ object VolatileDevice {
|
|||
new Operand[VolatileDevice[A]] {
|
||||
def encode(x: VolatileDevice[A]): String = ""
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
package com.htmlism.nescant
|
||||
|
||||
object ZeroPageAddress {
|
||||
object ZeroPageAddress:
|
||||
implicit val sourceForZeroPageAddress: ByteSource[ZeroPageAddress] =
|
||||
new ByteSource[ZeroPageAddress] {}
|
||||
|
||||
implicit val sinkForZeroPageAddress: ByteSink[ZeroPageAddress] =
|
||||
new ByteSink[ZeroPageAddress] {}
|
||||
}
|
||||
|
||||
case class ZeroPageAddress(n: Int)
|
||||
|
|
|
@ -1,17 +1,13 @@
|
|||
package com.htmlism.nescant
|
||||
|
||||
package object dsl {
|
||||
implicit class AddressOps(n: Int) {
|
||||
package object dsl:
|
||||
implicit class AddressOps(n: Int):
|
||||
def z: ZeroPageAddress =
|
||||
ZeroPageAddress(n)
|
||||
|
||||
def g: GlobalAddress =
|
||||
GlobalAddress(n)
|
||||
}
|
||||
|
||||
implicit class SinkOps[A: ByteSink](x: A) {
|
||||
def write[B](src: B): Unit = {
|
||||
implicit class SinkOps[A: ByteSink](x: A):
|
||||
def write[B](src: B): Unit =
|
||||
val _ = src
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ package dsl
|
|||
import org.scalatest.flatspec._
|
||||
import org.scalatest.matchers._
|
||||
|
||||
class ByteSinkSpec extends AnyFlatSpec with should.Matchers {
|
||||
class ByteSinkSpec extends AnyFlatSpec with should.Matchers:
|
||||
"A zero page address" should "be a byte-wide sync" in {
|
||||
123.z.write(456)
|
||||
}
|
||||
|
@ -18,4 +18,3 @@ class ByteSinkSpec extends AnyFlatSpec with should.Matchers {
|
|||
|
||||
sink.write(456)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ package dsl
|
|||
import org.scalatest.flatspec._
|
||||
import org.scalatest.matchers._
|
||||
|
||||
class ByteSourceSpec extends AnyFlatSpec with should.Matchers {
|
||||
class ByteSourceSpec extends AnyFlatSpec with should.Matchers:
|
||||
private val sink =
|
||||
123.z
|
||||
|
||||
|
@ -31,4 +31,3 @@ class ByteSourceSpec extends AnyFlatSpec with should.Matchers {
|
|||
|
||||
sink.write(src)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ package dsl
|
|||
import org.scalatest.flatspec._
|
||||
import org.scalatest.matchers._
|
||||
|
||||
class PostFixOpsSpec extends AnyFlatSpec with should.Matchers {
|
||||
class PostFixOpsSpec extends AnyFlatSpec with should.Matchers:
|
||||
"Numbers" should "support zero page ops" in {
|
||||
123.z shouldBe ZeroPageAddress(123)
|
||||
}
|
||||
|
@ -12,4 +12,3 @@ class PostFixOpsSpec extends AnyFlatSpec with should.Matchers {
|
|||
it should "support global address ops" in {
|
||||
123.g shouldBe GlobalAddress(123)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ object Scala3Plugin extends AutoPlugin {
|
|||
override def trigger: PluginTrigger = AllRequirements
|
||||
|
||||
override val buildSettings: Seq[Setting[_]] = Seq(
|
||||
scalaVersion := "2.13.8",
|
||||
scalaVersion := "3.1.0",
|
||||
scalacOptions ++= Seq("-indent", "-rewrite")
|
||||
)
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import cats.implicits._
|
|||
|
||||
import com.htmlism.mos6502.model._
|
||||
|
||||
object MatchOpcodes {
|
||||
object MatchOpcodes:
|
||||
def paddedBinary(n: Int, width: Int) =
|
||||
String.format(s"%${width}s", Integer.toBinaryString(n)).replace(" ", "0")
|
||||
|
||||
|
@ -76,7 +76,7 @@ object MatchOpcodes {
|
|||
).view.mapValues(x => x -> Implied).toMap
|
||||
// format: on
|
||||
|
||||
def doStuff(out: PrintWriter): Unit = {
|
||||
def doStuff(out: PrintWriter): Unit =
|
||||
val lookup =
|
||||
generatedOpcodes ++
|
||||
injectedOpcodesImplied ++
|
||||
|
@ -100,16 +100,16 @@ object MatchOpcodes {
|
|||
|
||||
out.print("</tr>")
|
||||
|
||||
for (r <- Seq(0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0)) {
|
||||
for (r <- Seq(0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0))
|
||||
out.print("<tr>")
|
||||
|
||||
// left header
|
||||
out.print(s"<th>${paddedBinary(r, 3)}</th>")
|
||||
|
||||
for (f <- fancyColumns) {
|
||||
for (f <- fancyColumns)
|
||||
val fullInt = r + f
|
||||
|
||||
lookup.get(fullInt) match {
|
||||
lookup.get(fullInt) match
|
||||
case Some((ints, mode)) =>
|
||||
val hex = f"$fullInt%2X"
|
||||
out.print(
|
||||
|
@ -118,11 +118,8 @@ object MatchOpcodes {
|
|||
|
||||
case None =>
|
||||
out.print(s"<td>UNDEF</td>")
|
||||
}
|
||||
}
|
||||
|
||||
out.print("</tr>")
|
||||
}
|
||||
|
||||
out.print("</table>")
|
||||
|
||||
|
@ -137,16 +134,16 @@ object MatchOpcodes {
|
|||
|
||||
out.print("</tr>")
|
||||
|
||||
for (r <- wideRows) {
|
||||
for (r <- wideRows)
|
||||
out.print("<tr>")
|
||||
|
||||
// left header
|
||||
out.print(s"<th>${paddedBinary(r, 3)}</th>")
|
||||
|
||||
for (c <- wideColumns) {
|
||||
for (c <- wideColumns)
|
||||
val fullInt = (r << 5) + c
|
||||
|
||||
lookup.get(fullInt) match {
|
||||
lookup.get(fullInt) match
|
||||
case Some((ints, mode)) =>
|
||||
val hex = f"$fullInt%2X"
|
||||
out.print(
|
||||
|
@ -155,11 +152,8 @@ object MatchOpcodes {
|
|||
|
||||
case None =>
|
||||
out.print(s"<td>UNDEF</td>")
|
||||
}
|
||||
}
|
||||
|
||||
out.print("</tr>")
|
||||
}
|
||||
|
||||
out.print("</table>")
|
||||
|
||||
|
@ -167,9 +161,8 @@ object MatchOpcodes {
|
|||
quartile(out, 1, lookup)
|
||||
quartile(out, 2, lookup)
|
||||
quartile(out, 3, lookup)
|
||||
}
|
||||
|
||||
def quartile(out: PrintWriter, n: Int, lookup: Map[Int, (Instruction, AddressingMode)]) = {
|
||||
def quartile(out: PrintWriter, n: Int, lookup: Map[Int, (Instruction, AddressingMode)]) =
|
||||
out.print(s"<h2>${paddedBinary(n, 2)}</h2>")
|
||||
|
||||
out.print("<table>")
|
||||
|
@ -193,16 +186,16 @@ object MatchOpcodes {
|
|||
|
||||
out.print("</tr>")
|
||||
|
||||
for (r <- rows) {
|
||||
for (r <- rows)
|
||||
out.print("<tr>")
|
||||
|
||||
// left header
|
||||
out.print(s"<th>${paddedBinary(r, 3)}</th>")
|
||||
|
||||
for (c <- columns) {
|
||||
for (c <- columns)
|
||||
val fullInt = (r << (3 + 2)) + (c << 2) + n
|
||||
|
||||
lookup.get(fullInt) match {
|
||||
lookup.get(fullInt) match
|
||||
case Some((ints, mode)) =>
|
||||
val hex = f"$fullInt%2X"
|
||||
out.print(
|
||||
|
@ -211,15 +204,11 @@ object MatchOpcodes {
|
|||
|
||||
case None =>
|
||||
out.print(s"<td>UNDEF</td>")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
out.print("</tr>")
|
||||
}
|
||||
|
||||
out.print("</table>")
|
||||
}
|
||||
|
||||
def wideColumns: Seq[Int] =
|
||||
for {
|
||||
|
@ -231,44 +220,38 @@ object MatchOpcodes {
|
|||
def wideRows: Seq[Int] =
|
||||
0 to 7
|
||||
|
||||
private def write(file: String)(f: PrintWriter => Unit) = {
|
||||
private def write(file: String)(f: PrintWriter => Unit) =
|
||||
val out = new PrintWriter(file)
|
||||
f(out)
|
||||
out.close()
|
||||
}
|
||||
|
||||
def toOpcode(n: Int): Option[(Instruction, AddressingMode)] = {
|
||||
def toOpcode(n: Int): Option[(Instruction, AddressingMode)] =
|
||||
val BitPattern = ThreeBits >> ThreeBits >> TwoBits
|
||||
|
||||
n match {
|
||||
n match
|
||||
case BitPattern((aaa, bbb), cc) =>
|
||||
cc match {
|
||||
cc match
|
||||
case 0 => c00(aaa, bbb)
|
||||
case 1 => c01(aaa, bbb)
|
||||
case 2 => c10(aaa, bbb)
|
||||
case 3 => None
|
||||
}
|
||||
case _ => throw new IllegalStateException("an int should always have bits to find")
|
||||
}
|
||||
}
|
||||
|
||||
def c01(aaa: Int, bbb: Int): Option[(Instruction, AddressingMode)] = {
|
||||
def c01(aaa: Int, bbb: Int): Option[(Instruction, AddressingMode)] =
|
||||
val instruction =
|
||||
Seq(ORA, AND, EOR, ADC, STA, LDA, CMP, SBC)(aaa)
|
||||
|
||||
val addressingMode =
|
||||
Seq(IndirectX, ZeroPage, Immediate, Absolute, IndirectY, ZeroPageX, AbsoluteY, AbsoluteX)(bbb)
|
||||
|
||||
(instruction, addressingMode) match {
|
||||
(instruction, addressingMode) match
|
||||
case (STA, Immediate) =>
|
||||
None
|
||||
|
||||
case _ =>
|
||||
(instruction -> addressingMode).some
|
||||
}
|
||||
}
|
||||
|
||||
def c10(aaa: Int, bbb: Int): Option[(Instruction, AddressingMode)] = {
|
||||
def c10(aaa: Int, bbb: Int): Option[(Instruction, AddressingMode)] =
|
||||
val instruction =
|
||||
Seq(ASL, ROL, LSR, ROR, STX, LDX, DEC, INC)(aaa)
|
||||
|
||||
|
@ -278,7 +261,7 @@ object MatchOpcodes {
|
|||
val useLookup =
|
||||
(instruction -> addressingMode).some
|
||||
|
||||
(instruction, addressingMode) match {
|
||||
(instruction, addressingMode) match
|
||||
case (ASL | ROL | LSR | ROR, ZeroPage | Accumulator | Absolute | ZeroPageX | AbsoluteX) =>
|
||||
useLookup
|
||||
|
||||
|
@ -293,10 +276,8 @@ object MatchOpcodes {
|
|||
|
||||
case _ =>
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
def c00(aaa: Int, bbb: Int): Option[(Instruction, AddressingMode)] = {
|
||||
def c00(aaa: Int, bbb: Int): Option[(Instruction, AddressingMode)] =
|
||||
val instruction =
|
||||
Seq(NoInstruction, BIT, NoInstruction, NoInstruction, STY, LDY, CPY, CPX)(aaa)
|
||||
|
||||
|
@ -306,7 +287,7 @@ object MatchOpcodes {
|
|||
val useLookup =
|
||||
(instruction -> addressingMode).some
|
||||
|
||||
(instruction, addressingMode) match {
|
||||
(instruction, addressingMode) match
|
||||
case (BIT, ZeroPage | Absolute) =>
|
||||
useLookup
|
||||
|
||||
|
@ -321,6 +302,3 @@ object MatchOpcodes {
|
|||
|
||||
case _ =>
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import scala.annotation.tailrec
|
|||
/**
|
||||
* Given an `Int`, destructure it into smaller `Int`s that use less bits
|
||||
*/
|
||||
trait BitExtractor[A] {
|
||||
trait BitExtractor[A]:
|
||||
self =>
|
||||
|
||||
def length: Int
|
||||
|
@ -26,24 +26,21 @@ trait BitExtractor[A] {
|
|||
a <- self.unapply(shifted)
|
||||
} yield (a, b)
|
||||
}
|
||||
}
|
||||
|
||||
object AtomExtractor {
|
||||
object AtomExtractor:
|
||||
@tailrec
|
||||
def pow(ex: Int, acc: Int = 1): Int =
|
||||
if (ex == 0)
|
||||
acc
|
||||
else
|
||||
pow(ex - 1, acc * 2)
|
||||
}
|
||||
|
||||
abstract class PrimitiveBitExtractor(val length: Int) extends BitExtractor[Int] {
|
||||
abstract class PrimitiveBitExtractor(val length: Int) extends BitExtractor[Int]:
|
||||
private lazy val mask =
|
||||
AtomExtractor.pow(length) - 1
|
||||
|
||||
def unapply(n: Int): Option[Int] =
|
||||
Some(n & mask)
|
||||
}
|
||||
|
||||
object OneBit extends PrimitiveBitExtractor(1)
|
||||
object TwoBits extends PrimitiveBitExtractor(2)
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
package com.htmlism.mos6502.dsl
|
||||
|
||||
sealed trait Address {
|
||||
sealed trait Address:
|
||||
def n: Int
|
||||
}
|
||||
|
||||
object ZeroAddress {
|
||||
object ZeroAddress:
|
||||
implicit val operandZero: Operand[ZeroAddress] =
|
||||
new Operand[ZeroAddress] {
|
||||
val operandType: OperandType =
|
||||
|
@ -19,11 +18,10 @@ object ZeroAddress {
|
|||
|
||||
implicit val definitionValueForZero: DefinitionValue[ZeroAddress] =
|
||||
operandZero.toAddressLiteral(_)
|
||||
}
|
||||
|
||||
case class ZeroAddress(n: Int) extends Address
|
||||
|
||||
object GlobalAddress {
|
||||
object GlobalAddress:
|
||||
implicit val operandGlobal: Operand[GlobalAddress] =
|
||||
new Operand[GlobalAddress] {
|
||||
val operandType: OperandType =
|
||||
|
@ -38,6 +36,5 @@ object GlobalAddress {
|
|||
|
||||
implicit val definitionValueForGlobal: DefinitionValue[GlobalAddress] =
|
||||
operandGlobal.toAddressLiteral(_)
|
||||
}
|
||||
|
||||
case class GlobalAddress(n: Int) extends Address
|
||||
|
|
|
@ -5,14 +5,13 @@ import scala.collection.mutable.ListBuffer
|
|||
|
||||
import cats.implicits._
|
||||
|
||||
case class AsmDocument(xs: List[TopLevelAsmDocumentFragment]) {
|
||||
case class AsmDocument(xs: List[TopLevelAsmDocumentFragment]):
|
||||
def toAsm: String =
|
||||
xs
|
||||
.map(_.toAsm)
|
||||
.mkString("\n\n")
|
||||
}
|
||||
|
||||
class AsmDocumentContext {
|
||||
class AsmDocumentContext:
|
||||
private val xs: ListBuffer[TopLevelAsmDocumentFragment] =
|
||||
ListBuffer()
|
||||
|
||||
|
@ -25,52 +24,44 @@ class AsmDocumentContext {
|
|||
def addJumpRegistry(ys: ListSet[Subroutine]): Unit =
|
||||
jumps = jumps ++ ys
|
||||
|
||||
def toDoc: AsmDocument = {
|
||||
def toDoc: AsmDocument =
|
||||
val asmFragmentsAndSubroutines =
|
||||
xs.toList ::: jumps.toList ++ jumps.flatMap(_.jumpRegistry).toList
|
||||
|
||||
AsmDocument(asmFragmentsAndSubroutines)
|
||||
}
|
||||
}
|
||||
|
||||
sealed trait TopLevelAsmDocumentFragment {
|
||||
sealed trait TopLevelAsmDocumentFragment:
|
||||
def toAsm: String
|
||||
}
|
||||
|
||||
case class AsmFragment(xs: List[Statement]) extends TopLevelAsmDocumentFragment {
|
||||
case class AsmFragment(xs: List[Statement]) extends TopLevelAsmDocumentFragment:
|
||||
def toAsm: String =
|
||||
xs.map(_.toAsm).mkString("\n")
|
||||
}
|
||||
|
||||
case class Subroutine(name: String, fragment: AsmFragment, jumpRegistry: ListSet[Subroutine])
|
||||
extends TopLevelAsmDocumentFragment {
|
||||
extends TopLevelAsmDocumentFragment:
|
||||
def toAsm: String =
|
||||
name + ":" + "\n" + fragment.toAsm
|
||||
}
|
||||
|
||||
case class DefinitionGroup(comment: String, xs: List[Definition[_]]) extends TopLevelAsmDocumentFragment {
|
||||
def toAsm: String = {
|
||||
case class DefinitionGroup(comment: String, xs: List[Definition[_]]) extends TopLevelAsmDocumentFragment:
|
||||
def toAsm: String =
|
||||
val groupCommentLine =
|
||||
"; " + comment
|
||||
|
||||
val definitionLines =
|
||||
xs
|
||||
.map { d =>
|
||||
d.comment match {
|
||||
d.comment match
|
||||
case Some(c) =>
|
||||
f"define ${d.name}%-20s${d.value} ; $c"
|
||||
|
||||
case None =>
|
||||
f"define ${d.name}%-20s${d.value}"
|
||||
}
|
||||
}
|
||||
|
||||
(groupCommentLine :: definitionLines)
|
||||
.mkString("\n")
|
||||
}
|
||||
}
|
||||
|
||||
class DefinitionGroupContext {
|
||||
class DefinitionGroupContext:
|
||||
private val xs: ListBuffer[Definition[_]] =
|
||||
ListBuffer()
|
||||
|
||||
|
@ -81,19 +72,17 @@ class DefinitionGroupContext {
|
|||
|
||||
def toGroup(s: String): DefinitionGroup =
|
||||
DefinitionGroup(s, xs.toList)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param comment
|
||||
* Typically used by resources to describe their type safety
|
||||
*/
|
||||
case class Definition[A](name: String, x: A, comment: Option[String])(implicit ev: DefinitionValue[A]) {
|
||||
case class Definition[A](name: String, x: A, comment: Option[String])(implicit ev: DefinitionValue[A]):
|
||||
lazy val value: String =
|
||||
ev
|
||||
.value(x)
|
||||
}
|
||||
|
||||
object Definition {
|
||||
object Definition:
|
||||
implicit def namedResourceForDefinition[A]: NamedResource[Definition[A]] =
|
||||
new NamedResource[Definition[A]] {
|
||||
def toDefinitions(x: Definition[A]): List[Definition[_]] =
|
||||
|
@ -105,12 +94,10 @@ object Definition {
|
|||
|
||||
def apply[A: DefinitionValue](name: String, x: A, comment: String): Definition[A] =
|
||||
Definition(name, x, comment.some)
|
||||
}
|
||||
|
||||
class AsmBlockContext {
|
||||
class AsmBlockContext:
|
||||
private val xs: ListBuffer[Statement] =
|
||||
ListBuffer()
|
||||
|
||||
def push(x: Statement): Unit =
|
||||
xs.append(x)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package com.htmlism.mos6502.dsl
|
|||
|
||||
import cats.data.NonEmptyList
|
||||
|
||||
trait BitField[A] {
|
||||
trait BitField[A]:
|
||||
def definitionGroupComment: String
|
||||
|
||||
/**
|
||||
|
@ -14,4 +14,3 @@ trait BitField[A] {
|
|||
* ASM-safe label
|
||||
*/
|
||||
def label(x: A): String
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import cats.data.NonEmptyList
|
|||
|
||||
sealed trait Color
|
||||
|
||||
object Color {
|
||||
object Color:
|
||||
implicit val colorOperand: Operand[Color] =
|
||||
new Operand[Color] {
|
||||
def toAddressLiteral(x: Color): String =
|
||||
|
@ -65,4 +65,3 @@ object Color {
|
|||
case object LightGreen extends Color
|
||||
case object LightBlue extends Color
|
||||
case object LightGrey extends Color
|
||||
}
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
package com.htmlism.mos6502.dsl
|
||||
|
||||
trait DefinitionValue[A] {
|
||||
trait DefinitionValue[A]:
|
||||
|
||||
/**
|
||||
* The value as presented in a `define` declaration (i.e. where no alias is possible)
|
||||
*/
|
||||
def value(x: A): String
|
||||
}
|
||||
|
||||
object DefinitionValue {
|
||||
object DefinitionValue:
|
||||
implicit val definitionValueForInt: DefinitionValue[Int] =
|
||||
(x: Int) => String.format("$%02x", x)
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import cats.implicits._
|
|||
|
||||
import com.htmlism.mos6502.model._
|
||||
|
||||
object DslDemo extends App {
|
||||
object DslDemo extends App:
|
||||
val cpu =
|
||||
new CPU
|
||||
|
||||
|
@ -40,7 +40,7 @@ object DslDemo extends App {
|
|||
A.add(0xc4)
|
||||
}
|
||||
|
||||
def withAssemblyContext(f: AssemblyContext => Unit): Unit = {
|
||||
def withAssemblyContext(f: AssemblyContext => Unit): Unit =
|
||||
val ctx: AssemblyContext =
|
||||
new AssemblyContext
|
||||
|
||||
|
@ -49,40 +49,35 @@ object DslDemo extends App {
|
|||
ctx.printOut()
|
||||
println()
|
||||
println()
|
||||
}
|
||||
}
|
||||
|
||||
object registers {
|
||||
object registers:
|
||||
sealed trait Register
|
||||
|
||||
sealed trait DestinationA
|
||||
|
||||
sealed trait IndexRegister
|
||||
|
||||
case object A extends Register {
|
||||
case object A extends Register:
|
||||
def add[A](x: A)(implicit ctx: AssemblyContext, ev: Operand[A]): Unit =
|
||||
ev.operandType match {
|
||||
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 {
|
||||
case object X extends Register with DestinationA with IndexRegister:
|
||||
def incr(implicit ctx: AssemblyContext): Unit =
|
||||
ctx.push(INX, "incr x")
|
||||
|
||||
def loop(s: String, spec: RangeSpec)(f: AssemblyContext => Unit)(implicit ctx: AssemblyContext): Unit = {
|
||||
def loop(s: String, spec: RangeSpec)(f: AssemblyContext => Unit)(implicit ctx: AssemblyContext): Unit =
|
||||
val (start, stop, instruction) =
|
||||
spec match {
|
||||
spec match
|
||||
case Incrementing(from, to) =>
|
||||
(from, to, INX)
|
||||
|
||||
case Decrementing(from, to) =>
|
||||
(from, to, DEX)
|
||||
}
|
||||
|
||||
ctx.push(LDX, start)
|
||||
|
||||
|
@ -93,13 +88,10 @@ object registers {
|
|||
ctx.push(instruction)
|
||||
ctx.push(CPX, stop)
|
||||
ctx.branch(BNE, s)
|
||||
}
|
||||
}
|
||||
|
||||
case object Y extends Register with DestinationA with IndexRegister
|
||||
}
|
||||
|
||||
class CPU {
|
||||
class CPU:
|
||||
def A: registers.A.type =
|
||||
registers.A
|
||||
|
||||
|
@ -107,12 +99,11 @@ class CPU {
|
|||
ctx.push(LDA, x, "set A to " + ev.toShow(x))
|
||||
|
||||
def A_=(reg: registers.DestinationA)(implicit ctx: AssemblyContext): Unit =
|
||||
reg match {
|
||||
reg match
|
||||
case registers.X =>
|
||||
ctx.push(TXA)
|
||||
case registers.Y =>
|
||||
ctx.push(TYA)
|
||||
}
|
||||
|
||||
def X: registers.X.type =
|
||||
registers.X
|
||||
|
@ -125,9 +116,8 @@ class CPU {
|
|||
|
||||
def Y_=(reg: registers.A.type)(implicit ctx: AssemblyContext): Unit =
|
||||
ctx.push(TAY, s"set x to register $reg")
|
||||
}
|
||||
|
||||
class AssemblyContext {
|
||||
class AssemblyContext:
|
||||
private val xs: ListBuffer[Statement] =
|
||||
ListBuffer()
|
||||
|
||||
|
@ -155,10 +145,9 @@ class AssemblyContext {
|
|||
def addJump(subroutine: Subroutine): Unit =
|
||||
jumps = jumps + subroutine
|
||||
|
||||
def printOut(): Unit = {
|
||||
def printOut(): Unit =
|
||||
xs.map(_.toAsm)
|
||||
.foreach(println)
|
||||
}
|
||||
|
||||
def triplets: List[(String, Option[String], Option[String])] =
|
||||
xs.map(_.toTriplet).toList
|
||||
|
@ -168,4 +157,3 @@ class AssemblyContext {
|
|||
|
||||
def getJumps: ListSet[Subroutine] =
|
||||
jumps
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package com.htmlism.mos6502.dsl
|
|||
|
||||
import cats.data.NonEmptyList
|
||||
|
||||
trait EnumAsm[A] {
|
||||
trait EnumAsm[A]:
|
||||
def comment: String
|
||||
|
||||
/**
|
||||
|
@ -19,4 +19,3 @@ trait EnumAsm[A] {
|
|||
* Comment string
|
||||
*/
|
||||
def comment(x: A): String
|
||||
}
|
||||
|
|
|
@ -5,12 +5,10 @@ import com.htmlism.mos6502.model._
|
|||
/**
|
||||
* A typed collection, like memory mapped to screen pixels. Access by index instead of by address.
|
||||
*/
|
||||
case class IndexedAddressCollection[A](baseAddress: Int, name: String)(implicit ev: Operand[A]) {
|
||||
case class IndexedAddressCollection[A](baseAddress: Int, name: String)(implicit ev: Operand[A]):
|
||||
def apply(n: Int): GlobalAddress =
|
||||
GlobalAddress(baseAddress + n)
|
||||
|
||||
def write(n: Int, x: A)(implicit ctx: AssemblyContext): Unit = {
|
||||
def write(n: Int, x: A)(implicit ctx: AssemblyContext): Unit =
|
||||
ctx.push(LDA, x, s"write ${ev.toShow(x)} to $name ($n)")
|
||||
ctx.push(STA, GlobalAddress(baseAddress + n), "")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import cats.data.NonEmptyList
|
|||
/**
|
||||
* Like an enum, but values are specified
|
||||
*/
|
||||
trait Mapping[A] {
|
||||
trait Mapping[A]:
|
||||
def definitionGroupComment: String
|
||||
|
||||
/**
|
||||
|
@ -24,9 +24,8 @@ trait Mapping[A] {
|
|||
* Comment string
|
||||
*/
|
||||
def comment(x: A): String
|
||||
}
|
||||
|
||||
object Mapping {
|
||||
object Mapping:
|
||||
implicit def mappingForBitField[A](implicit ev: BitField[A]): Mapping[A] =
|
||||
new Mapping[A] {
|
||||
private lazy val valueMap =
|
||||
|
@ -72,4 +71,3 @@ object Mapping {
|
|||
def comment(x: A): String =
|
||||
ev.comment(x)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
package com.htmlism.mos6502.dsl
|
||||
|
||||
trait NamedResource[A] {
|
||||
trait NamedResource[A]:
|
||||
|
||||
/**
|
||||
* A `Definable` can emit multiple definitions. Usually in the case of `word`s being split across two
|
||||
* byte-definitions
|
||||
*/
|
||||
def toDefinitions(x: A): List[Definition[_]]
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package com.htmlism.mos6502.dsl
|
||||
|
||||
trait Operand[A] {
|
||||
trait Operand[A]:
|
||||
self =>
|
||||
|
||||
def toAddressLiteral(x: A): String
|
||||
|
@ -11,9 +11,8 @@ trait Operand[A] {
|
|||
def toShow(x: A): String
|
||||
|
||||
def operandType: OperandType
|
||||
}
|
||||
|
||||
object Operand {
|
||||
object Operand:
|
||||
implicit val operandInt: Operand[Int] =
|
||||
new Operand[Int] {
|
||||
val operandType: OperandType =
|
||||
|
@ -37,4 +36,3 @@ object Operand {
|
|||
def operandType: OperandType =
|
||||
ValueLiteral
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
package com.htmlism.mos6502.dsl
|
||||
|
||||
sealed trait RangeSpec {
|
||||
sealed trait RangeSpec:
|
||||
def from: Int
|
||||
|
||||
def to: Int
|
||||
}
|
||||
|
||||
case class Incrementing(from: Int, to: Int) extends RangeSpec
|
||||
|
||||
|
|
|
@ -9,19 +9,16 @@ import com.htmlism.mos6502.model._
|
|||
* @tparam A
|
||||
* The input type of the write and the output type of the read
|
||||
*/
|
||||
case class ReadWriteLocation[A: Operand](name: String, address: ZeroAddress) {
|
||||
def read(implicit ctx: AssemblyContext): Unit = {
|
||||
case class ReadWriteLocation[A: Operand](name: String, address: ZeroAddress):
|
||||
def read(implicit ctx: AssemblyContext): Unit =
|
||||
val _ = ctx
|
||||
// ctx.push(LDA, ev, s"write ${ev.toShow(x)} to $name ($n)")
|
||||
}
|
||||
|
||||
def write(x: A)(implicit ctx: AssemblyContext): Unit = {
|
||||
def write(x: A)(implicit ctx: AssemblyContext): Unit =
|
||||
ctx.push(LDA, x)
|
||||
ctx.push(STA, this)
|
||||
}
|
||||
}
|
||||
|
||||
object ReadWriteLocation {
|
||||
object ReadWriteLocation:
|
||||
implicit def operandForReadWriteLocation[A]: Operand[ReadWriteLocation[A]] =
|
||||
new Operand[ReadWriteLocation[A]] {
|
||||
def toAddressLiteral(x: ReadWriteLocation[A]): String =
|
||||
|
@ -41,4 +38,3 @@ object ReadWriteLocation {
|
|||
Definition(x.name, x.address, "Read/write location for A values")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,68 +4,58 @@ import cats.implicits._
|
|||
|
||||
import com.htmlism.mos6502.model.Instruction
|
||||
|
||||
sealed trait Statement {
|
||||
sealed trait Statement:
|
||||
def toAsm: String
|
||||
|
||||
def toTriplet: (String, Option[String], Option[String])
|
||||
}
|
||||
|
||||
object Statement {
|
||||
object Statement:
|
||||
val indent: String =
|
||||
" "
|
||||
}
|
||||
|
||||
case class UnaryInstruction(instruction: Instruction, comment: Option[String]) extends Statement {
|
||||
def toAsm: String = {
|
||||
case class UnaryInstruction(instruction: Instruction, comment: Option[String]) extends Statement:
|
||||
def toAsm: String =
|
||||
val left =
|
||||
instruction.toString
|
||||
|
||||
comment match {
|
||||
comment match
|
||||
case Some(c) =>
|
||||
Statement.indent + f"$left%-16s ; " + c
|
||||
case None =>
|
||||
Statement.indent + left
|
||||
}
|
||||
}
|
||||
|
||||
def toTriplet: (String, Option[String], Option[String]) =
|
||||
(instruction.toString, None, comment)
|
||||
}
|
||||
|
||||
case class InstructionWithOperand[A](instruction: Instruction, operand: A, comment: Option[String])(implicit
|
||||
ev: Operand[A]
|
||||
) extends Statement {
|
||||
def toAsm: String = {
|
||||
) extends Statement:
|
||||
def toAsm: String =
|
||||
val left =
|
||||
instruction.toString
|
||||
|
||||
val operandStr =
|
||||
ev.toAddressLiteral(operand)
|
||||
|
||||
comment match {
|
||||
comment match
|
||||
case Some(c) =>
|
||||
Statement.indent + f"$left%-5s $operandStr%-11s; " + c
|
||||
case None =>
|
||||
Statement.indent + f"$left%-5s $operandStr"
|
||||
}
|
||||
}
|
||||
|
||||
def toTriplet: (String, Option[String], Option[String]) =
|
||||
(instruction.toString, ev.toAddressLiteral(operand).some, comment)
|
||||
}
|
||||
|
||||
case class Label(s: String) extends Statement {
|
||||
case class Label(s: String) extends Statement:
|
||||
def toAsm: String =
|
||||
s + ":"
|
||||
|
||||
def toTriplet: (String, Option[String], Option[String]) =
|
||||
(s, None, None)
|
||||
}
|
||||
|
||||
case class BranchingInstruction(instruction: Instruction, label: String) extends Statement {
|
||||
case class BranchingInstruction(instruction: Instruction, label: String) extends Statement:
|
||||
def toAsm: String =
|
||||
Statement.indent + instruction.toString + " " + label
|
||||
|
||||
def toTriplet: (String, Option[String], Option[String]) =
|
||||
(instruction.toString, label.some, None)
|
||||
}
|
||||
|
|
|
@ -11,14 +11,12 @@ package com.htmlism.mos6502.dsl
|
|||
* @tparam A
|
||||
* The return type of the read
|
||||
*/
|
||||
case class VolatileDevice[A](name: String, address: ZeroAddress) {
|
||||
def read(implicit ctx: AssemblyContext): Unit = {
|
||||
case class VolatileDevice[A](name: String, address: ZeroAddress):
|
||||
def read(implicit ctx: AssemblyContext): Unit =
|
||||
val _ = ctx
|
||||
// ctx.push(LDA, ev, s"write ${ev.toShow(x)} to $name ($n)")
|
||||
}
|
||||
}
|
||||
|
||||
object VolatileDevice {
|
||||
object VolatileDevice:
|
||||
implicit def namedResourceForVolatileDevice[A]: NamedResource[VolatileDevice[A]] =
|
||||
new NamedResource[VolatileDevice[A]] {
|
||||
def toDefinitions(x: VolatileDevice[A]): List[Definition[ZeroAddress]] =
|
||||
|
@ -26,4 +24,3 @@ object VolatileDevice {
|
|||
Definition(x.name, x.address, "Volatile generator for A values")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +1,24 @@
|
|||
package com.htmlism.mos6502
|
||||
|
||||
package object dsl extends syntax.DefinitionGroupSyntax with syntax.AsmDocSyntax with syntax.AsmSyntax {
|
||||
def asmDoc(f: AsmDocumentContext => Unit): AsmDocument = {
|
||||
package object dsl extends syntax.DefinitionGroupSyntax with syntax.AsmDocSyntax with syntax.AsmSyntax:
|
||||
def asmDoc(f: AsmDocumentContext => Unit): AsmDocument =
|
||||
val ctx: AsmDocumentContext =
|
||||
new AsmDocumentContext
|
||||
|
||||
f(ctx)
|
||||
|
||||
ctx.toDoc
|
||||
}
|
||||
|
||||
implicit class AddressOps(n: Int) {
|
||||
implicit class AddressOps(n: Int):
|
||||
def z: ZeroAddress =
|
||||
ZeroAddress(n)
|
||||
|
||||
def addr: GlobalAddress =
|
||||
GlobalAddress(n)
|
||||
}
|
||||
|
||||
implicit class RangeOps(from: Int) {
|
||||
implicit class RangeOps(from: Int):
|
||||
def upTo(to: Int): Incrementing =
|
||||
Incrementing(from, to)
|
||||
|
||||
def downTo(to: Int): Decrementing =
|
||||
Decrementing(from, to)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package com.htmlism.mos6502.dsl
|
||||
package syntax
|
||||
|
||||
trait AsmDocSyntax {
|
||||
def asm(f: AssemblyContext => Unit)(implicit ctx: AsmDocumentContext): Unit = {
|
||||
trait AsmDocSyntax:
|
||||
def asm(f: AssemblyContext => Unit)(implicit ctx: AsmDocumentContext): Unit =
|
||||
val asmCtx: AssemblyContext =
|
||||
new AssemblyContext
|
||||
|
||||
|
@ -13,9 +13,8 @@ trait AsmDocSyntax {
|
|||
|
||||
ctx
|
||||
.push(asmCtx.toFragment)
|
||||
}
|
||||
|
||||
def group[A](s: String)(f: DefinitionGroupContext => A)(implicit ctx: AsmDocumentContext): Unit = {
|
||||
def group[A](s: String)(f: DefinitionGroupContext => A)(implicit ctx: AsmDocumentContext): Unit =
|
||||
val g: DefinitionGroupContext =
|
||||
new DefinitionGroupContext
|
||||
|
||||
|
@ -23,21 +22,18 @@ trait AsmDocSyntax {
|
|||
|
||||
ctx
|
||||
.push(g.toGroup(s))
|
||||
}
|
||||
|
||||
def enumAsm[A: EnumAsm: Mapping](implicit ctx: AsmDocumentContext): Unit = {
|
||||
def enumAsm[A: EnumAsm: Mapping](implicit ctx: AsmDocumentContext): Unit =
|
||||
val _ = implicitly[EnumAsm[A]] // TODO unused
|
||||
|
||||
mapping
|
||||
}
|
||||
|
||||
def bitField[A: BitField: Mapping](implicit ctx: AsmDocumentContext): Unit = {
|
||||
def bitField[A: BitField: Mapping](implicit ctx: AsmDocumentContext): Unit =
|
||||
val _ = implicitly[BitField[A]] // TODO unused
|
||||
|
||||
mapping
|
||||
}
|
||||
|
||||
def mapping[A](implicit ctx: AsmDocumentContext, ev: Mapping[A]): Unit = {
|
||||
def mapping[A](implicit ctx: AsmDocumentContext, ev: Mapping[A]): Unit =
|
||||
val xs =
|
||||
ev.all
|
||||
.map(x => ev.label(x) -> ev.value(x))
|
||||
|
@ -54,5 +50,3 @@ trait AsmDocSyntax {
|
|||
|
||||
ctx
|
||||
.push(grp)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,12 @@ package syntax
|
|||
|
||||
import com.htmlism.mos6502.model._
|
||||
|
||||
trait AsmSyntax {
|
||||
trait AsmSyntax:
|
||||
def label(s: String)(implicit ctx: AssemblyContext): Unit =
|
||||
ctx
|
||||
.label(s)
|
||||
|
||||
def sub(s: String)(f: AssemblyContext => Unit): Subroutine = {
|
||||
def sub(s: String)(f: AssemblyContext => Unit): Subroutine =
|
||||
val ctx: AssemblyContext =
|
||||
new AssemblyContext
|
||||
|
||||
|
@ -17,13 +17,10 @@ trait AsmSyntax {
|
|||
ctx.push(RTS)
|
||||
|
||||
Subroutine(s, ctx.toFragment, ctx.getJumps)
|
||||
}
|
||||
|
||||
def jump(s: Subroutine)(implicit ctx: AssemblyContext): Unit = {
|
||||
def jump(s: Subroutine)(implicit ctx: AssemblyContext): Unit =
|
||||
ctx
|
||||
.addJump(s)
|
||||
|
||||
ctx
|
||||
.branch(JSR, s.name)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package com.htmlism.mos6502.dsl
|
||||
package syntax
|
||||
|
||||
trait DefinitionGroupSyntax {
|
||||
def define[A <: Address: DefinitionValue](name: String, x: A)(implicit ctx: DefinitionGroupContext): Definition[A] = {
|
||||
trait DefinitionGroupSyntax:
|
||||
def define[A <: Address: DefinitionValue](name: String, x: A)(implicit ctx: DefinitionGroupContext): Definition[A] =
|
||||
val definition =
|
||||
Definition(name, x)
|
||||
|
||||
|
@ -10,9 +10,8 @@ trait DefinitionGroupSyntax {
|
|||
.push(Definition(name, x))
|
||||
|
||||
definition
|
||||
}
|
||||
|
||||
def constant(name: String, x: Int)(implicit ctx: DefinitionGroupContext): Definition[Int] = {
|
||||
def constant(name: String, x: Int)(implicit ctx: DefinitionGroupContext): Definition[Int] =
|
||||
val definition =
|
||||
Definition(name, x)
|
||||
|
||||
|
@ -20,5 +19,3 @@ trait DefinitionGroupSyntax {
|
|||
.push(Definition(name, x))
|
||||
|
||||
definition
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,22 +2,19 @@ package com.htmlism.mos6502.model
|
|||
|
||||
sealed trait Instruction { def theme: String; def color: String }
|
||||
|
||||
case object NoInstruction extends Instruction {
|
||||
case object NoInstruction extends Instruction:
|
||||
def theme: String = "noop"; def color: String = "white"
|
||||
}
|
||||
|
||||
sealed trait Logical extends Instruction {
|
||||
sealed trait Logical extends Instruction:
|
||||
def theme: String = "logical"; def color: String = "OliveDrab"
|
||||
}
|
||||
|
||||
case object AND extends Logical
|
||||
case object EOR extends Logical
|
||||
case object ORA extends Logical
|
||||
case object BIT extends Logical
|
||||
|
||||
sealed trait Arithmetic extends Instruction {
|
||||
sealed trait Arithmetic extends Instruction:
|
||||
def theme: String = "arithmetic"; def color: String = "CadetBlue"
|
||||
}
|
||||
|
||||
case object ADC extends Arithmetic
|
||||
case object SBC extends Arithmetic
|
||||
|
@ -25,56 +22,49 @@ case object CMP extends Arithmetic
|
|||
case object CPX extends Arithmetic
|
||||
case object CPY extends Arithmetic
|
||||
|
||||
sealed trait Load extends Instruction {
|
||||
sealed trait Load extends Instruction:
|
||||
def theme: String = "load"; def color: String = "BurlyWood"
|
||||
}
|
||||
case object LDA extends Load
|
||||
case object LDX extends Load
|
||||
case object LDY extends Load
|
||||
|
||||
sealed trait Store extends Instruction {
|
||||
sealed trait Store extends Instruction:
|
||||
def theme: String = "store"; def color: String = "Bisque"
|
||||
}
|
||||
|
||||
case object STA extends Store
|
||||
case object STX extends Store
|
||||
case object STY extends Store
|
||||
|
||||
sealed trait Shift extends Instruction {
|
||||
sealed trait Shift extends Instruction:
|
||||
def theme: String = "shift"; def color: String = "SlateBlue"
|
||||
}
|
||||
|
||||
case object ASL extends Shift
|
||||
case object LSR extends Shift
|
||||
case object ROL extends Shift
|
||||
case object ROR extends Shift
|
||||
|
||||
sealed trait Increment extends Instruction {
|
||||
sealed trait Increment extends Instruction:
|
||||
def theme: String = "increment"; def color: String = "LightPink"
|
||||
}
|
||||
|
||||
case object INC extends Increment
|
||||
case object INX extends Increment
|
||||
case object INY extends Increment
|
||||
|
||||
sealed trait Decrement extends Instruction {
|
||||
sealed trait Decrement extends Instruction:
|
||||
def theme: String = "decrement"; def color: String = "Khaki"
|
||||
}
|
||||
|
||||
case object DEC extends Decrement
|
||||
case object DEX extends Decrement
|
||||
case object DEY extends Decrement
|
||||
|
||||
sealed trait Jump extends Instruction {
|
||||
sealed trait Jump extends Instruction:
|
||||
def theme: String = "jump"; def color: String = "Salmon"
|
||||
}
|
||||
case object JMP extends Jump
|
||||
case object JSR extends Jump
|
||||
case object RTS extends Jump
|
||||
|
||||
sealed trait Branch extends Instruction {
|
||||
sealed trait Branch extends Instruction:
|
||||
def theme: String = "branch"; def color: String = "DodgerBlue"
|
||||
}
|
||||
case object BCC extends Branch
|
||||
case object BCS extends Branch
|
||||
case object BEQ extends Branch
|
||||
|
@ -84,16 +74,14 @@ case object BPL extends Branch
|
|||
case object BVC extends Branch
|
||||
case object BVS extends Branch
|
||||
|
||||
sealed trait System extends Instruction {
|
||||
sealed trait System extends Instruction:
|
||||
def theme: String = "system"; def color: String = "Peru"
|
||||
}
|
||||
case object BRK extends System
|
||||
case object NOP extends System
|
||||
case object RTI extends System
|
||||
|
||||
sealed trait Stack extends Instruction {
|
||||
sealed trait Stack extends Instruction:
|
||||
def theme: String = "stack"; def color: String = "Wheat"
|
||||
}
|
||||
case object TSX extends Stack
|
||||
case object TXS extends Stack
|
||||
case object PHA extends Stack
|
||||
|
@ -101,25 +89,22 @@ case object PHP extends Stack
|
|||
case object PLA extends Stack
|
||||
case object PLP extends Stack
|
||||
|
||||
sealed trait Transfer extends Instruction {
|
||||
sealed trait Transfer extends Instruction:
|
||||
def theme: String = "transfer"; def color: String = "Teal"
|
||||
}
|
||||
case object TAX extends Transfer
|
||||
case object TAY extends Transfer
|
||||
case object TXA extends Transfer
|
||||
case object TYA extends Transfer
|
||||
|
||||
sealed trait Clear extends Instruction {
|
||||
sealed trait Clear extends Instruction:
|
||||
def theme: String = "clear"; def color: String = "LightSteelBlue"
|
||||
}
|
||||
case object CLC extends Clear
|
||||
case object CLD extends Clear
|
||||
case object CLI extends Clear
|
||||
case object CLV extends Clear
|
||||
|
||||
sealed trait SetFlag extends Instruction {
|
||||
sealed trait SetFlag extends Instruction:
|
||||
def theme: String = "set"; def color: String = "Thistle"
|
||||
}
|
||||
case object SEC extends SetFlag
|
||||
case object SED extends SetFlag
|
||||
case object SEI extends SetFlag
|
||||
|
|
|
@ -4,7 +4,7 @@ import cats.data.NonEmptyList
|
|||
import org.scalatest.flatspec._
|
||||
import org.scalatest.matchers._
|
||||
|
||||
class DslSpec extends AnyFlatSpec with should.Matchers {
|
||||
class DslSpec extends AnyFlatSpec with should.Matchers:
|
||||
|
||||
"the dsl" should "compile" in {
|
||||
val doc =
|
||||
|
@ -86,7 +86,6 @@ class DslSpec extends AnyFlatSpec with should.Matchers {
|
|||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
sealed trait Triforce
|
||||
|
||||
|
@ -94,7 +93,7 @@ case object Courage extends Triforce
|
|||
case object Wisdom extends Triforce
|
||||
case object Power extends Triforce
|
||||
|
||||
object Triforce {
|
||||
object Triforce:
|
||||
implicit val enumTriforce: EnumAsm[Triforce] =
|
||||
new EnumAsm[Triforce] {
|
||||
def comment: String =
|
||||
|
@ -109,7 +108,6 @@ object Triforce {
|
|||
def comment(x: Triforce): String =
|
||||
x.toString
|
||||
}
|
||||
}
|
||||
|
||||
sealed trait TestDirection
|
||||
|
||||
|
@ -118,7 +116,7 @@ case object Down extends TestDirection
|
|||
case object Left extends TestDirection
|
||||
case object Right extends TestDirection
|
||||
|
||||
object TestDirection {
|
||||
object TestDirection:
|
||||
implicit val bitFieldDirection: BitField[TestDirection] =
|
||||
new BitField[TestDirection] {
|
||||
def definitionGroupComment: String =
|
||||
|
@ -130,4 +128,3 @@ object TestDirection {
|
|||
def label(x: TestDirection): String =
|
||||
x.toString.toLowerCase
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package snake
|
|||
|
||||
import cats.data.NonEmptyList
|
||||
|
||||
object AsciiValue {
|
||||
object AsciiValue:
|
||||
implicit val asciiValueMapping: Mapping[AsciiValue] =
|
||||
new Mapping[AsciiValue] {
|
||||
def definitionGroupComment: String =
|
||||
|
@ -13,12 +13,11 @@ object AsciiValue {
|
|||
NonEmptyList.of(AsciiW, AsciiA, AsciiS, AsciiD)
|
||||
|
||||
def value(x: AsciiValue): Int =
|
||||
x match {
|
||||
x match
|
||||
case AsciiW => 0x77
|
||||
case AsciiA => 0x61
|
||||
case AsciiS => 0x73
|
||||
case AsciiD => 0x64
|
||||
}
|
||||
|
||||
def label(x: AsciiValue): String =
|
||||
x.toString.toLowerCase
|
||||
|
@ -26,7 +25,6 @@ object AsciiValue {
|
|||
def comment(x: AsciiValue): String =
|
||||
x.toString
|
||||
}
|
||||
}
|
||||
|
||||
sealed trait AsciiValue
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ package snake
|
|||
|
||||
import cats.data.NonEmptyList
|
||||
|
||||
object Direction {
|
||||
object Direction:
|
||||
implicit val directionBitField: BitField[Direction] =
|
||||
new BitField[Direction] {
|
||||
def definitionGroupComment: String =
|
||||
|
@ -15,7 +15,6 @@ object Direction {
|
|||
def label(x: Direction): String =
|
||||
"moving" + x.toString
|
||||
}
|
||||
}
|
||||
|
||||
sealed trait Direction
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import org.scalatest.matchers._
|
|||
|
||||
import com.htmlism.mos6502.model._
|
||||
|
||||
class Easy6502Spec extends AnyFlatSpec with should.Matchers {
|
||||
class Easy6502Spec extends AnyFlatSpec with should.Matchers:
|
||||
|
||||
"the three pixel demo" should "have the right instructions" in {
|
||||
val doc =
|
||||
|
@ -163,12 +163,10 @@ class Easy6502Spec extends AnyFlatSpec with should.Matchers {
|
|||
)
|
||||
}
|
||||
|
||||
def withAssemblyContext(f: AssemblyContext => Unit): AssemblyContext = {
|
||||
def withAssemblyContext(f: AssemblyContext => Unit): AssemblyContext =
|
||||
val ctx: AssemblyContext =
|
||||
new AssemblyContext
|
||||
|
||||
f(ctx)
|
||||
|
||||
ctx
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user