mirror of
https://github.com/mcanlas/6502-opcodes.git
synced 2024-09-25 23:56:38 +00:00
302 lines
7.2 KiB
Scala
302 lines
7.2 KiB
Scala
package com.htmlism
|
|
|
|
import java.io.PrintWriter
|
|
|
|
import cats.syntax.all.*
|
|
|
|
import com.htmlism.mos6502.model.*
|
|
|
|
// sbt "runMain com.htmlism.MatchOpcodes out.html" && open out.html
|
|
object MatchOpcodes:
|
|
def paddedBinary(n: Int, width: Int) =
|
|
String.format(s"%${width}s", Integer.toBinaryString(n)).replace(" ", "0")
|
|
|
|
def main(args: Array[String]): Unit =
|
|
write(args(0))(doStuff)
|
|
|
|
def generatedOpcodes: Map[Int, (Instruction, AddressingMode)] =
|
|
(0 to 255)
|
|
.map(n => n -> toOpcode(n))
|
|
.collect { case (n, Some(x)) => (n, x) }
|
|
.toMap
|
|
|
|
// format: off
|
|
def injectedOpcodesSpecific: Map[Int, (Instruction, AddressingMode)] =
|
|
Map(
|
|
0x4C -> (JMP -> Absolute),
|
|
0x6C -> (JMP -> Indirect),
|
|
|
|
0x96 -> (STX -> ZeroPageY),
|
|
0xB6 -> (LDX -> ZeroPageY),
|
|
0xBE -> (LDX -> AbsoluteY)
|
|
)
|
|
|
|
def injectedOpcodesRelative: Map[Int, (Instruction, AddressingMode)] =
|
|
Map(
|
|
0x10 -> BPL,
|
|
0x30 -> BMI,
|
|
0x50 -> BVC,
|
|
0x70 -> BVS,
|
|
0x90 -> BCC,
|
|
0xB0 -> BCS,
|
|
0xD0 -> BNE,
|
|
0xF0 -> BEQ
|
|
).view.mapValues(x => x -> Relative).toMap
|
|
|
|
def injectedOpcodesImplied: Map[Int, (Instruction, AddressingMode)] =
|
|
Map(
|
|
0x00 -> BRK,
|
|
0x20 -> JSR,
|
|
0x40 -> RTI,
|
|
0x60 -> RTS,
|
|
|
|
0x08 -> PHP,
|
|
0x28 -> PLP,
|
|
0x48 -> PHA,
|
|
0x68 -> PLA,
|
|
0x88 -> DEY,
|
|
0xA8 -> TAY,
|
|
0xC8 -> INY,
|
|
0xE8 -> INX,
|
|
|
|
0x18 -> CLC,
|
|
0x38 -> SEC,
|
|
0x58 -> CLI,
|
|
0x78 -> SEI,
|
|
0x98 -> TYA,
|
|
0xB8 -> CLV,
|
|
0xD8 -> CLD,
|
|
0xF8 -> SED,
|
|
|
|
0x8A -> TXA,
|
|
0x9A -> TXS,
|
|
0xAA -> TAX,
|
|
0xBA -> TSX,
|
|
0xCA -> DEX,
|
|
0xEA -> NOP
|
|
).view.mapValues(x => x -> Implied).toMap
|
|
// format: on
|
|
|
|
def doStuff(out: PrintWriter): Unit =
|
|
val lookup =
|
|
generatedOpcodes ++
|
|
injectedOpcodesImplied ++
|
|
injectedOpcodesRelative ++
|
|
injectedOpcodesSpecific
|
|
|
|
out.print("<table>")
|
|
|
|
// print headers
|
|
out.print("<tr>")
|
|
out.print("<th/>")
|
|
|
|
val fancyColumns =
|
|
for
|
|
c <- 0 to 3
|
|
b <- 0 to 7
|
|
yield b * 4 + c
|
|
|
|
for f <- fancyColumns do out.print(s"<th>${paddedBinary(f, 8)}</th>")
|
|
|
|
out.print("</tr>")
|
|
|
|
for r <- Seq(0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0) do
|
|
out.print("<tr>")
|
|
|
|
// left header
|
|
out.print(s"<th>${paddedBinary(r, 3)}</th>")
|
|
|
|
for f <- fancyColumns do
|
|
val fullInt = r + f
|
|
|
|
lookup.get(fullInt) match
|
|
case Some((ints, mode)) =>
|
|
val hex = f"$fullInt%2X"
|
|
out.print(
|
|
s"""<th class="${ints.theme}" style="${"background-color: " + ints.color}">$ints $mode<br>$hex</th>"""
|
|
)
|
|
|
|
case None =>
|
|
out.print(s"<td>UNDEF</td>")
|
|
|
|
out.print("</tr>")
|
|
|
|
out.print("</table>")
|
|
|
|
out.print("<table>")
|
|
|
|
// print headers
|
|
out.print("<tr>")
|
|
out.print("<th/>")
|
|
|
|
for c <- wideColumns do out.print(s"<th>${paddedBinary(c, 5)}</th>")
|
|
|
|
out.print("</tr>")
|
|
|
|
for r <- wideRows do
|
|
out.print("<tr>")
|
|
|
|
// left header
|
|
out.print(s"<th>${paddedBinary(r, 3)}</th>")
|
|
|
|
for c <- wideColumns do
|
|
val fullInt = (r << 5) + c
|
|
|
|
lookup.get(fullInt) match
|
|
case Some((ints, mode)) =>
|
|
val hex = f"$fullInt%2X"
|
|
out.print(
|
|
s"""<th class="${ints.theme}" style="${"background-color: " + ints.color}">$ints $mode<br>$hex</th>"""
|
|
)
|
|
|
|
case None =>
|
|
out.print(s"<td>UNDEF</td>")
|
|
|
|
out.print("</tr>")
|
|
|
|
out.print("</table>")
|
|
|
|
quartile(out, 0, lookup)
|
|
quartile(out, 1, lookup)
|
|
quartile(out, 2, lookup)
|
|
quartile(out, 3, lookup)
|
|
|
|
def quartile(out: PrintWriter, n: Int, lookup: Map[Int, (Instruction, AddressingMode)]) =
|
|
out.print(s"<h2>${paddedBinary(n, 2)}</h2>")
|
|
|
|
out.print("<table>")
|
|
|
|
// print headers
|
|
out.print("<tr>")
|
|
out.print("<th/>")
|
|
|
|
val columns =
|
|
for
|
|
y <- 0 to 1
|
|
z <- List(1, 0)
|
|
x <- 0 to 1
|
|
yield (z << 2) + (x << 1) + y
|
|
|
|
val rows =
|
|
0 to 7
|
|
|
|
for c <- columns do out.print(s"<th>${paddedBinary(c, 3)}</th>")
|
|
|
|
out.print("</tr>")
|
|
|
|
for r <- rows do
|
|
out.print("<tr>")
|
|
|
|
// left header
|
|
out.print(s"<th>${paddedBinary(r, 3)}</th>")
|
|
|
|
for c <- columns do
|
|
val fullInt = (r << (3 + 2)) + (c << 2) + n
|
|
|
|
lookup.get(fullInt) match
|
|
case Some((ints, mode)) =>
|
|
val hex = f"$fullInt%2X"
|
|
out.print(
|
|
s"""<th class="${ints.theme}" style="${"background-color: " + ints.color}">$ints $mode<br>$hex</th>"""
|
|
)
|
|
|
|
case None =>
|
|
out.print(s"<td>UNDEF</td>")
|
|
|
|
out.print("</tr>")
|
|
|
|
out.print("</table>")
|
|
|
|
def wideColumns: Seq[Int] =
|
|
for
|
|
cc <- 0 to 3
|
|
y <- 0 to 1
|
|
xx <- 0 to 3
|
|
yield (xx << 3) + (y << 2) + cc
|
|
|
|
def wideRows: Seq[Int] =
|
|
0 to 7
|
|
|
|
private def write(file: String)(f: PrintWriter => Unit) =
|
|
val out = new PrintWriter(file)
|
|
f(out)
|
|
out.close()
|
|
|
|
def toOpcode(n: Int): Option[(Instruction, AddressingMode)] =
|
|
val BitPattern = ThreeBits >> ThreeBits >> TwoBits
|
|
|
|
n match
|
|
case BitPattern((aaa, bbb), cc) =>
|
|
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)] =
|
|
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
|
|
case (STA, Immediate) =>
|
|
None
|
|
|
|
case _ =>
|
|
(instruction -> addressingMode).some
|
|
|
|
def c10(aaa: Int, bbb: Int): Option[(Instruction, AddressingMode)] =
|
|
val instruction =
|
|
Seq(ASL, ROL, LSR, ROR, STX, LDX, DEC, INC)(aaa)
|
|
|
|
val addressingMode =
|
|
Seq(Immediate, ZeroPage, Accumulator, Absolute, NoMode, ZeroPageX, Implied, AbsoluteX)(bbb)
|
|
|
|
val useLookup =
|
|
(instruction -> addressingMode).some
|
|
|
|
(instruction, addressingMode) match
|
|
case (ASL | ROL | LSR | ROR, ZeroPage | Accumulator | Absolute | ZeroPageX | AbsoluteX) =>
|
|
useLookup
|
|
|
|
case (STX, ZeroPage | Absolute) =>
|
|
useLookup
|
|
|
|
case (DEC | INC, ZeroPage | Absolute | AbsoluteX | ZeroPageX) =>
|
|
useLookup
|
|
|
|
case (LDX, Immediate | ZeroPage | Absolute) =>
|
|
useLookup
|
|
|
|
case _ =>
|
|
None
|
|
|
|
def c00(aaa: Int, bbb: Int): Option[(Instruction, AddressingMode)] =
|
|
val instruction =
|
|
Seq(NoInstruction, BIT, NoInstruction, NoInstruction, STY, LDY, CPY, CPX)(aaa)
|
|
|
|
val addressingMode =
|
|
Seq(Immediate, ZeroPage, NoMode, Absolute, NoMode, ZeroPageX, NoMode, AbsoluteX)(bbb)
|
|
|
|
val useLookup =
|
|
(instruction -> addressingMode).some
|
|
|
|
(instruction, addressingMode) match
|
|
case (BIT, ZeroPage | Absolute) =>
|
|
useLookup
|
|
|
|
case (STY, ZeroPage | Absolute | ZeroPageX) =>
|
|
useLookup
|
|
|
|
case (LDY, Immediate | ZeroPage | Absolute | ZeroPageX | AbsoluteX) =>
|
|
useLookup
|
|
|
|
case (CPY | CPX, Immediate | ZeroPage | Absolute) =>
|
|
useLookup
|
|
|
|
case _ =>
|
|
None
|