6502-opcodes/src/main/scala/com/htmlism/MatchOpcodes.scala

301 lines
7.2 KiB
Scala
Raw Normal View History

2018-05-05 18:23:21 +00:00
package com.htmlism
import java.io.PrintWriter
2023-10-03 20:15:10 +00:00
import cats.syntax.all.*
2020-08-15 06:04:21 +00:00
2023-10-03 20:15:10 +00:00
import com.htmlism.mos6502.model.*
2020-08-15 04:41:18 +00:00
2022-02-14 23:11:45 +00:00
object MatchOpcodes:
2018-05-05 18:23:21 +00:00
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)
2018-05-09 02:04:31 +00:00
def generatedOpcodes: Map[Int, (Instruction, AddressingMode)] =
(0 to 255)
.map(n => n -> toOpcode(n))
.collect { case (n, Some(x)) => (n, x) }
.toMap
2018-05-05 18:23:21 +00:00
2018-09-26 02:57:26 +00:00
// format: off
2020-08-13 02:19:49 +00:00
def injectedOpcodesSpecific: Map[Int, (Instruction, AddressingMode)] =
2020-08-13 01:56:09 +00:00
Map(
0x4C -> (JMP -> Absolute),
0x6C -> (JMP -> Indirect),
2020-08-13 02:19:49 +00:00
0x96 -> (STX -> ZeroPageY),
0xB6 -> (LDX -> ZeroPageY),
2020-08-15 04:49:07 +00:00
0xBE -> (LDX -> AbsoluteY)
2020-08-13 01:56:09 +00:00
)
2020-08-13 01:40:20 +00:00
def injectedOpcodesRelative: Map[Int, (Instruction, AddressingMode)] =
2018-05-09 02:05:40 +00:00
Map(
0x10 -> BPL,
0x30 -> BMI,
0x50 -> BVC,
0x70 -> BVS,
0x90 -> BCC,
0xB0 -> BCS,
0xD0 -> BNE,
2020-08-15 04:49:07 +00:00
0xF0 -> BEQ
2020-08-13 01:40:20 +00:00
).view.mapValues(x => x -> Relative).toMap
2018-05-09 02:05:40 +00:00
2020-08-13 01:40:20 +00:00
def injectedOpcodesImplied: Map[Int, (Instruction, AddressingMode)] =
Map(
2018-05-09 02:05:40 +00:00
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
2020-03-21 03:49:26 +00:00
).view.mapValues(x => x -> Implied).toMap
2018-09-26 02:57:26 +00:00
// format: on
2018-05-09 02:05:40 +00:00
2022-02-14 23:11:45 +00:00
def doStuff(out: PrintWriter): Unit =
2020-08-13 01:40:20 +00:00
val lookup =
generatedOpcodes ++
injectedOpcodesImplied ++
2020-08-13 01:56:09 +00:00
injectedOpcodesRelative ++
2020-08-13 02:19:49 +00:00
injectedOpcodesSpecific
2018-05-05 18:23:21 +00:00
2018-05-09 02:28:21 +00:00
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
2023-10-03 20:15:10 +00:00
for f <- fancyColumns do out.print(s"<th>${paddedBinary(f, 8)}</th>")
2018-05-09 02:28:21 +00:00
out.print("</tr>")
2023-10-03 20:15:10 +00:00
for r <- Seq(0x00, 0x20, 0x40, 0x60, 0x80, 0xa0, 0xc0, 0xe0) do
2018-05-09 02:28:21 +00:00
out.print("<tr>")
// left header
out.print(s"<th>${paddedBinary(r, 3)}</th>")
2023-10-03 20:15:10 +00:00
for f <- fancyColumns do
2018-05-09 02:28:21 +00:00
val fullInt = r + f
2022-02-14 23:11:45 +00:00
lookup.get(fullInt) match
2018-05-09 02:28:21 +00:00
case Some((ints, mode)) =>
val hex = f"$fullInt%2X"
2018-09-26 02:57:26 +00:00
out.print(
2020-03-21 04:28:04 +00:00
s"""<th class="${ints.theme}" style="${"background-color: " + ints.color}">$ints $mode<br>$hex</th>"""
2020-03-21 03:45:13 +00:00
)
2018-05-09 02:28:21 +00:00
case None =>
out.print(s"<td>UNDEF</td>")
out.print("</tr>")
out.print("</table>")
2018-05-05 18:23:21 +00:00
out.print("<table>")
// print headers
out.print("<tr>")
out.print("<th/>")
2023-10-03 20:15:10 +00:00
for c <- wideColumns do out.print(s"<th>${paddedBinary(c, 5)}</th>")
2018-05-05 18:23:21 +00:00
out.print("</tr>")
2023-10-03 20:15:10 +00:00
for r <- wideRows do
2018-05-05 18:23:21 +00:00
out.print("<tr>")
// left header
out.print(s"<th>${paddedBinary(r, 3)}</th>")
2023-10-03 20:15:10 +00:00
for c <- wideColumns do
2018-05-05 18:23:21 +00:00
val fullInt = (r << 5) + c
2022-02-14 23:11:45 +00:00
lookup.get(fullInt) match
2018-05-05 18:23:21 +00:00
case Some((ints, mode)) =>
val hex = f"$fullInt%2X"
2018-09-26 02:57:26 +00:00
out.print(
2020-03-21 04:28:04 +00:00
s"""<th class="${ints.theme}" style="${"background-color: " + ints.color}">$ints $mode<br>$hex</th>"""
2020-03-21 03:45:13 +00:00
)
2018-05-05 18:23:21 +00:00
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)
2022-02-14 23:11:45 +00:00
def quartile(out: PrintWriter, n: Int, lookup: Map[Int, (Instruction, AddressingMode)]) =
2018-05-05 18:23:21 +00:00
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
2018-05-09 03:03:43 +00:00
x <- 0 to 1
z <- 0 to 1
} yield (z << 2) + (x << 1) + y
2018-05-05 18:23:21 +00:00
val rows =
0 to 7
2023-10-03 20:15:10 +00:00
for c <- columns do out.print(s"<th>${paddedBinary(c, 3)}</th>")
2018-05-05 18:23:21 +00:00
out.print("</tr>")
2023-10-03 20:15:10 +00:00
for r <- rows do
2018-05-05 18:23:21 +00:00
out.print("<tr>")
// left header
out.print(s"<th>${paddedBinary(r, 3)}</th>")
2023-10-03 20:15:10 +00:00
for c <- columns do
2018-05-05 18:23:21 +00:00
val fullInt = (r << (3 + 2)) + (c << 2) + n
2022-02-14 23:11:45 +00:00
lookup.get(fullInt) match
2018-05-05 18:23:21 +00:00
case Some((ints, mode)) =>
val hex = f"$fullInt%2X"
2018-09-26 02:57:26 +00:00
out.print(
2020-03-21 04:28:04 +00:00
s"""<th class="${ints.theme}" style="${"background-color: " + ints.color}">$ints $mode<br>$hex</th>"""
2020-03-21 03:45:13 +00:00
)
2018-05-05 18:23:21 +00:00
case None =>
out.print(s"<td>UNDEF</td>")
out.print("</tr>")
out.print("</table>")
def wideColumns: Seq[Int] =
for {
cc <- 0 to 3
2022-12-02 01:44:59 +00:00
y <- 0 to 1
2018-05-05 18:23:21 +00:00
xx <- 0 to 3
} yield (xx << 3) + (y << 2) + cc
def wideRows: Seq[Int] =
0 to 7
2022-02-14 23:11:45 +00:00
private def write(file: String)(f: PrintWriter => Unit) =
2018-05-05 18:23:21 +00:00
val out = new PrintWriter(file)
f(out)
out.close()
2022-02-14 23:11:45 +00:00
def toOpcode(n: Int): Option[(Instruction, AddressingMode)] =
2018-05-05 18:23:21 +00:00
val BitPattern = ThreeBits >> ThreeBits >> TwoBits
2022-02-14 23:11:45 +00:00
n match
2020-08-13 01:13:30 +00:00
case BitPattern((aaa, bbb), cc) =>
2022-02-14 23:11:45 +00:00
cc match
2020-08-13 01:43:01 +00:00
case 0 => c00(aaa, bbb)
case 1 => c01(aaa, bbb)
case 2 => c10(aaa, bbb)
2018-05-05 18:23:21 +00:00
case 3 => None
2023-01-02 18:02:03 +00:00
case _ => throw new IllegalStateException("an int should always have bits to find")
2018-05-05 18:23:21 +00:00
2022-02-14 23:11:45 +00:00
def c01(aaa: Int, bbb: Int): Option[(Instruction, AddressingMode)] =
2018-05-05 18:23:21 +00:00
val instruction =
Seq(ORA, AND, EOR, ADC, STA, LDA, CMP, SBC)(aaa)
val addressingMode =
2018-09-29 13:15:33 +00:00
Seq(IndirectX, ZeroPage, Immediate, Absolute, IndirectY, ZeroPageX, AbsoluteY, AbsoluteX)(bbb)
2018-05-05 18:23:21 +00:00
2022-02-14 23:11:45 +00:00
(instruction, addressingMode) match
2020-08-13 02:08:51 +00:00
case (STA, Immediate) =>
None
case _ =>
(instruction -> addressingMode).some
2018-05-05 18:23:21 +00:00
2022-02-14 23:11:45 +00:00
def c10(aaa: Int, bbb: Int): Option[(Instruction, AddressingMode)] =
2018-05-05 18:23:21 +00:00
val instruction =
Seq(ASL, ROL, LSR, ROR, STX, LDX, DEC, INC)(aaa)
val addressingMode =
2020-08-13 02:16:53 +00:00
Seq(Immediate, ZeroPage, Accumulator, Absolute, NoMode, ZeroPageX, Implied, AbsoluteX)(bbb)
2018-05-05 18:23:21 +00:00
2020-08-13 02:16:53 +00:00
val useLookup =
2020-08-13 01:43:01 +00:00
(instruction -> addressingMode).some
2020-08-13 02:16:53 +00:00
2022-02-14 23:11:45 +00:00
(instruction, addressingMode) match
2020-08-13 02:16:53 +00:00
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
2018-05-05 18:23:21 +00:00
2022-02-14 23:11:45 +00:00
def c00(aaa: Int, bbb: Int): Option[(Instruction, AddressingMode)] =
2018-05-05 18:23:21 +00:00
val instruction =
2020-08-13 01:56:09 +00:00
Seq(NoInstruction, BIT, NoInstruction, NoInstruction, STY, LDY, CPY, CPX)(aaa)
2018-05-05 18:23:21 +00:00
val addressingMode =
2020-08-13 02:06:22 +00:00
Seq(Immediate, ZeroPage, NoMode, Absolute, NoMode, ZeroPageX, NoMode, AbsoluteX)(bbb)
2018-09-26 02:57:26 +00:00
2020-08-13 02:16:53 +00:00
val useLookup =
(instruction -> addressingMode).some
2022-02-14 23:11:45 +00:00
(instruction, addressingMode) match
2020-08-13 02:06:22 +00:00
case (BIT, ZeroPage | Absolute) =>
2020-08-13 02:16:53 +00:00
useLookup
2020-08-13 01:56:09 +00:00
2020-08-13 02:06:22 +00:00
case (STY, ZeroPage | Absolute | ZeroPageX) =>
2020-08-13 02:16:53 +00:00
useLookup
2020-08-13 01:56:09 +00:00
2020-08-13 02:06:22 +00:00
case (LDY, Immediate | ZeroPage | Absolute | ZeroPageX | AbsoluteX) =>
2020-08-13 02:16:53 +00:00
useLookup
2020-08-13 01:56:09 +00:00
2020-08-13 02:06:22 +00:00
case (CPY | CPX, Immediate | ZeroPage | Absolute) =>
2020-08-13 02:16:53 +00:00
useLookup
2020-08-13 02:06:22 +00:00
case _ =>
None