Improvements for 65CE02 assembly (fixes #116)

This commit is contained in:
Karol Stasiak 2021-06-29 02:29:30 +02:00
parent faf97cee1f
commit 7f0def54bc
9 changed files with 167 additions and 13 deletions

View File

@ -693,6 +693,8 @@ case class AssemblyLine(opcode: Opcode.Value, addrMode: AddrMode.Value, var para
parameter match {
case StructureConstant(_, List(a,b)) => s" $opcode $a,$b"
}
} else if (addrMode == LongRelative && opcode != BSR) { // BSR on Hudson is always 8-bit short, and on 65CE02 it's always 16-bit
s" L$opcode ${AddrMode.addrModeToString(addrMode, parameter.toString)}"
} else if (addrMode == ImmediateWithAbsolute || addrMode == ImmediateWithZeroPage) {
parameter match {
case StructureConstant(_, List(a,b)) => s" $opcode #$a,$b"

View File

@ -180,20 +180,31 @@ object Opcode extends Enumeration {
case "AXA" => AHX
case "AXS" => SBX // could mean SAX
case "BCC" => BCC
case "LBCC" => BCC
case "BCS" => BCS
case "LBCS" => BCS
case "BEQ" => BEQ
case "LBEQ" => BEQ
case "BIT" => BIT
case "BMI" => BMI
case "LBMI" => BMI
case "BNE" => BNE
case "LBNE" => BNE
case "BPL" => BPL
case "LBPL" => BPL
case "BRA" => BRA
case "LBRA" => BRA
case "BRK" => BRK
case "BRL" => BRL
case "BSR" => BSR
case "LBSR" => BSR
case "BVC" => BVC
case "LBVC" => BVC
case "BVS" => BVS
case "LBVS" => BVS
case "CLC" => CLC
case "CLD" => CLD
case "CLE" => CLE
case "CLI" => CLI
case "CLV" => CLV
case "CLX" => CLX
@ -232,6 +243,7 @@ object Opcode extends Enumeration {
case "LSE" => SRE
case "LSR" => LSR
case "LXA" => LXA
case "MAP" => MAP
case "NEG" => NEG
case "NOP" => NOP
case "OAL" => LXA
@ -247,17 +259,19 @@ object Opcode extends Enumeration {
case "PHW" => PHW
case "PHX" => PHX
case "PHY" => PHY
case "PHZ" => PHZ
case "PLA" => PLA
case "PLB" => PLB
case "PLD" => PLD
case "PLP" => PLP
case "PLX" => PLX
case "PLY" => PLY
case "PLZ" => PLZ
case "REP" => REP
case "RLA" => RLA
case "ROL" => ROL
case "ROR" => ROR
case "ROW" => ROR_W // TODO: is this correct?
case "ROW" => ROL_W
case "RRA" => RRA
case "RTI" => RTI
case "RTL" => RTL
@ -268,6 +282,7 @@ object Opcode extends Enumeration {
case "SBX" => SBX
case "SEC" => SEC
case "SED" => SED
case "SEE" => SEE
case "SEI" => SEI
case "SEP" => SEP
case "SET" => SET

View File

@ -164,14 +164,14 @@ object MosStatementCompiler extends AbstractStatementCompiler[AssemblyLine] {
val c: Constant = compileParameterForAssemblyStatement(env, o, x)
val actualAddrMode = a match {
case Absolute if OpcodeClasses.ShortBranching(o) => Relative
case Absolute if (o == ROR_W || o == ASL_W) && ctx.options.flag(CompilationFlag.Emit65CE02Opcodes) =>
case Absolute if (o == ROL_W || o == ASL_W) && ctx.options.flag(CompilationFlag.Emit65CE02Opcodes) =>
Absolute
case Absolute if OpcodeClasses.SupportsZeropage(o) && c.fitsProvablyIntoByte => ZeroPage
case ImmediateWithAbsolute if (c match {
case StructureConstant(_, List(a, b)) => b.fitsProvablyIntoByte
}) => ImmediateWithZeroPage
case IndexedX if o == JMP => AbsoluteIndexedX
case Indirect if o != JMP => IndexedZ
case IndexedX if o == JMP || o == JSR => AbsoluteIndexedX
case Indirect if o != JMP && o != JSR => IndexedZ
case _ => a
}
List(AssemblyLine(o, actualAddrMode, c, e)) -> Nil

View File

@ -64,6 +64,11 @@ class MosAssembler(program: Program,
writeByte(bank, index, MosAssembler.opcodeFor(op, am, options))
writeWord(bank, index + 1, param)
index + 3
case AssemblyLine0(op, am@LongRelative, param) =>
writeByte(bank, index, MosAssembler.opcodeFor(op, am, options))
// TODO:
writeWord(bank, index + 1, param - (index + 3))
index + 3
case AssemblyLine0(op, am@(LongAbsolute | LongAbsoluteX | LongIndirect), param) =>
writeByte(bank, index, MosAssembler.opcodeFor(op, am, options))
writeWord(bank, index + 1, param)
@ -720,8 +725,7 @@ object MosAssembler {
ce(DEC_W, ZeroPage, 0xC3)
ce(INC_W, ZeroPage, 0xE3)
ce(ASL_W, Absolute, 0xCB)
// TODO: or is it ROL_W?
ce(ROR_W, Absolute, 0xEB)
ce(ROL_W, Absolute, 0xEB)
ce(ASR, Implied, 0x43)
ce(ASR, ZeroPage, 0x44)
ce(ASR, ZeroPageX, 0x54)
@ -738,10 +742,26 @@ object MosAssembler {
ce(PHW, Absolute, 0xFC)
ce(PHZ, Implied, 0xDB)
ce(PLZ, Implied, 0xFB)
// ce(CLE, Implied, )
// ce(SEE, Implied, )
// ce(BSR, , )
ce(JSR, Indirect, 0x22)
ce(JSR, AbsoluteIndexedX, 0x23)
ce(CLE, Implied, 0x02)
ce(SEE, Implied, 0x03)
ce(NEG, Implied, 0x42)
ce(MAP, Implied, 0x5C)
ce(LDA, IndexedSY, 0xE2)
ce(STA, IndexedSY, 0x82)
ce(BSR, LongRelative, 0x63)
ce(BRA, LongRelative, 0x83)
ce(BPL, LongRelative, 0x13)
ce(BMI, LongRelative, 0x33)
ce(BVC, LongRelative, 0x53)
ce(BVS, LongRelative, 0x73)
ce(BCC, LongRelative, 0x93)
ce(BCS, LongRelative, 0xb3)
ce(BNE, LongRelative, 0xd3)
ce(BEQ, LongRelative, 0xf3)
hu(BSR, Relative, 0x44)
hu(CLY, Implied, 0xC2)
hu(CLX, Implied, 0x82)
hu(CLA, Implied, 0x62)
@ -816,6 +836,8 @@ object MosAssembler {
em(XBA, Implied, 0xEB)
em(TXY, Implied, 0x9B)
em(TYX, Implied, 0xBB)
em(JSR, LongAbsolute, 0x22)
em(JSR, AbsoluteIndexedX, 0xFC)
na(RTL, Implied, 0x6B)

View File

@ -24,7 +24,11 @@ case class MosParser(filename: String, input: String, currentDirectory: String,
// def zeropageAddrModeHint: P[Option[Boolean]] = Pass
val asmOpcode: P[Opcode.Value] = (position() ~ mosOpcodeLetter.rep(exactly = 3).! ~ octalDigit.?.! ~ ("_W" | "_w").?.!).map { case (p, bitNo, suffix, o) => Opcode.lookup(o + bitNo + suffix, Some(p), log) }
val asmOpcode: P[(Boolean, Opcode.Value)] = (position() ~
(("l" | "L") ~ ("b" | "B") ~ mosOpcodeLetter.rep(exactly = 2) |
(mosOpcodeLetter.rep(exactly = 3).! ~ octalDigit.?.! ~ ("_W" | "_w").?)).!).map { case (p, o) =>
o.toLowerCase.startsWith("lb") -> Opcode.lookup(o, Some(p), log)
}
private val commaX = HWS ~ "," ~ HWS ~ ("X" | "x") ~ HWS
private val commaY = HWS ~ "," ~ HWS ~ ("Y" | "y") ~ HWS
@ -77,8 +81,8 @@ case class MosParser(filename: String, input: String, currentDirectory: String,
import Opcode._
for {
elid <- !"}" ~ elidable
position <- position("assembly statement")
op <- asmOpcode ~/ Pass
pos <- position("assembly statement")
(longrelative, op) <- asmOpcode ~/ Pass
param <- op match {
case op if OpcodeClasses.SingleBitBranch(op) =>
(HWS ~ asmExpression ~ HWS ~ "," ~/ HWS ~ asmExpression).map{ x =>
@ -102,12 +106,23 @@ case class MosParser(filename: String, input: String, currentDirectory: String,
case (Opcode.ASR, AddrMode.Absolute) => MosAssemblyStatement(Opcode.ASR, AddrMode.ZeroPage, param._2, elid)
case (Opcode.ASR, AddrMode.AbsoluteX) => MosAssemblyStatement(Opcode.ASR, AddrMode.ZeroPageX, param._2, elid)
case (Opcode.SBX, _) => MosAssemblyStatement(Opcode.SAX, param._1, param._2, elid)
case (Opcode.BSR, AddrMode.Absolute) if options.flag(CompilationFlag.Emit65CE02Opcodes) || longrelative =>
MosAssemblyStatement(Opcode.BSR, AddrMode.LongRelative, param._2, elid)
case (Opcode.BSR, AddrMode.Absolute) if options.flag(CompilationFlag.EmitHudsonOpcodes) =>
MosAssemblyStatement(Opcode.BSR, AddrMode.Relative, param._2, elid)
case (Opcode.PHW, AddrMode.Immediate) => MosAssemblyStatement(Opcode.PHW, AddrMode.WordImmediate, param._2, elid)
case (op, AddrMode.AbsoluteX)
if (op == INC_W || op == DEC_W) && !options.flag(CompilationFlag.EmitNative65816Opcodes) =>
MosAssemblyStatement(op, AddrMode.ZeroPageX, param._2, elid)
case (_, AddrMode.Absolute) if OpcodeClasses.ShortBranching(op) =>
MosAssemblyStatement(op, if (longrelative) AddrMode.LongRelative else AddrMode.Relative, param._2, elid)
case (_, AddrMode.ZeroPageX) if !OpcodeClasses.SupportsZeroPageX(op) => MosAssemblyStatement(op, AddrMode.AbsoluteX, param._2, elid)
case (_, AddrMode.ZeroPageY) if !OpcodeClasses.SupportsZeroPageY(op) => MosAssemblyStatement(op, AddrMode.AbsoluteY, param._2, elid)
case (_, AddrMode.Absolute) if OpcodeClasses.SingleBit(op) => MosAssemblyStatement(op, AddrMode.ZeroPage, param._2, elid)
case (_, AddrMode.IndexedX) if op == Opcode.JMP || op == Opcode.JSR => MosAssemblyStatement(op, AddrMode.AbsoluteIndexedX, param._2, elid)
case (_, AddrMode.Indirect) if op != Opcode.JMP && op != Opcode.JSR => MosAssemblyStatement(op, AddrMode.IndexedZ, param._2, elid)
case _ => MosAssemblyStatement(op, param._1, param._2, elid)
}).pos(position)
}).pos(pos)
}
}

View File

@ -572,4 +572,91 @@ class AssemblySuite extends FunSuite with Matchers with AppendedClues {
|""".stripMargin)
m.readByte(0xc000) should equal(0x12)
}
test("65CE02 opcodes") {
EmuUnoptimizedCrossPlatformRun(Cpu.CE02)(
"""
|byte output @$c000
|void stuff() {
| output = 42
|}
|void main() {
| word p
| p = stuff.addr
| asm {
| jsr (p)
| }
| return
| asm {
| bsr stuff
| see
| cle
| ldz #$a3
| ldz $abab
| ldz $bbbb,x
| stz $64
| stz $74,x
| stz $9c9c
| stz $9e9e,x
| asr
| asr $44
| asr $54,x
| asw $cbcb
| row $ebeb
| dew $c3
| inw $e3
| neg
| dec
| inc
| dez
| inz
| tab
| tba
| taz
| tza
| tsy
| tys
| phw #$f4f4
| phw $fcfc
| phx
| phy
| phz
| plz
| ply
| plx
| .here: bra .here
| bbr0 $0F, .here
| bbs0 $8F, .here
| jsr ($2323,x)
| jmp ($7c7c,x)
| rmb0 $07
| smb0 $87
| ora ($12),z
| and ($32),z
| eor ($52),z
| adc ($72),z
| sta ($92),z
| lda ($b2),z
| cmp ($d2),z
| sbc ($f2),z
| lda ($e2,s),y
| sta ($82,s),y
| map
| [for x,0,until,300 [0]]
| lbra .here
| lbeq .here
| lbcc .here
| lbcs .here
| lbvs .here
| lbvc .here
| lbmi .here
| lbpl .here
| }
|}
|""".stripMargin) { m =>
m.readByte(0xc000) should equal(42)
}
}
}

View File

@ -10,6 +10,7 @@ object EmuUnoptimizedCrossPlatformRun {
def apply(platforms: Cpu.Value*)(source: String)(verifier: MemoryBank => Unit): Unit = {
val (_, mm) = if (platforms.contains(Cpu.Mos) || platforms.contains(Cpu.StrictMos)) EmuUnoptimizedRun.apply2(source) else Timings(-1, -1) -> null
val (_, mc) = if (platforms.contains(Cpu.Cmos)) EmuUnoptimizedCmosRun.apply2(source) else Timings(-1, -1) -> null
val (_, me) = if (platforms.contains(Cpu.CE02)) EmuUnoptimizedCE02Run.apply2(source) else Timings(-1, -1) -> null
val (_, ma) = if (platforms.contains(Cpu.Sixteen)) EmuUnoptimizedNative65816Run.apply2(source) else Timings(-1, -1) -> null
val (_, mn) = if (platforms.contains(Cpu.Ricoh)) EmuUnoptimizedRicohRun.apply2(source) else Timings(-1, -1) -> null
val (_, mz) = if (platforms.contains(Cpu.Z80)) EmuUnoptimizedZ80Run.apply2(source) else Timings(-1, -1) -> null
@ -33,6 +34,10 @@ object EmuUnoptimizedCrossPlatformRun {
println(f"Running 65C02")
verifier(mc)
}
if (Settings.enableCE02Tests && platforms.contains(Cpu.CE02)) {
println(f"Running 65CE02")
verifier(me)
}
if (Settings.enableZ80Tests && platforms.contains(Cpu.Z80)) {
println(f"Running Z80")
verifier(mz)

View File

@ -12,6 +12,8 @@ object EmuUnoptimizedRicohRun extends EmuRun(Cpu.Ricoh, Nil, Nil)
object EmuUnoptimizedCmosRun extends EmuRun(Cpu.Cmos, Nil, Nil)
object EmuUnoptimizedCE02Run extends EmuRun(Cpu.CE02, Nil, Nil)
object EmuUnoptimizedHudsonRun extends EmuRun(Cpu.HuC6280, Nil, Nil)
object EmuUnoptimizedNative65816Run extends EmuRun(Cpu.Sixteen, Nil, Nil) {

View File

@ -28,6 +28,12 @@ object Settings {
*/
val enableWdc85816Tests: Boolean = false
/**
* Should the 65CE02 tests be enabled?
* There is no emulator for 65CE02 right now.
*/
val enableCE02Tests: Boolean = false
/**
* Should the Ricoh tests be enabled?
* Ricoh tests: