mirror of
https://github.com/KarolS/millfork.git
synced 2025-04-13 05:39:54 +00:00
Improvements for 65CE02 assembly (fixes #116)
This commit is contained in:
parent
faf97cee1f
commit
7f0def54bc
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user