From d1058b6223e1e282cde1f21bc00319c238f2c581 Mon Sep 17 00:00:00 2001 From: Karol Stasiak Date: Tue, 1 Oct 2019 00:46:15 +0200 Subject: [PATCH] ZX Spectrum Next CPU support --- docs/api/custom-platform.md | 2 + docs/lang/assemblyz80.md | 2 + docs/lang/preprocessor.md | 2 +- include/i80_math.mfk | 12 +++- .../scala/millfork/CompilationOptions.scala | 25 ++++++-- .../scala/millfork/assembly/z80/ZOpcode.scala | 10 +++- .../scala/millfork/output/Z80Assembler.scala | 58 +++++++++++++++++++ .../scala/millfork/parser/Z80Parser.scala | 36 ++++++++++++ .../millfork/test/Z80AssemblySuite.scala | 39 ++++++++++++- .../millfork/test/emu/EmuUnoptimizedRun.scala | 2 + .../scala/millfork/test/emu/EmuZ80Run.scala | 3 +- 11 files changed, 178 insertions(+), 13 deletions(-) diff --git a/docs/api/custom-platform.md b/docs/api/custom-platform.md index 4cb8bdc1..47a80b40 100644 --- a/docs/api/custom-platform.md +++ b/docs/api/custom-platform.md @@ -31,6 +31,8 @@ if a line ends with a backslash character, the value continues to the next line. * `strictz80` (Z80 without illegal instructions) + * `z80next` (Z80 core from ZX Spectrum Next) + * `i8080` (Intel 8080) * `i8085` (Intel 8085) diff --git a/docs/lang/assemblyz80.md b/docs/lang/assemblyz80.md index 15bfa959..740e72e1 100644 --- a/docs/lang/assemblyz80.md +++ b/docs/lang/assemblyz80.md @@ -25,6 +25,8 @@ Only instructions available on the current CPU architecture are available. Intel syntax does not support instructions that are unavailable on the 8080. Undocumented Z80 instructions are not supported, except for `SLL`. +Not all ZX Spectrum Next are supported. `JP (C)`, `BSLA` and similar instructions are not supported. + Labels have to be followed by a colon and they can optionally be on a separate line. Indentation is not important: diff --git a/docs/lang/preprocessor.md b/docs/lang/preprocessor.md index 02c04710..a32f8d33 100644 --- a/docs/lang/preprocessor.md +++ b/docs/lang/preprocessor.md @@ -52,7 +52,7 @@ The following features are defined based on the chosen CPU and compilation optio * `CPUFEATURE_65C02`, `CPUFEATURE_65CE02`, `CPUFEATURE_HUC6280`, `CPUFEATURE_65816_EMULATION`, `CPUFEATURE_65816_NATIVE`, `CPUFEATURE_8080`, `CPUFEATURE_8085`, `CPUFEATURE_GAMEBOY`, `CPUFEATURE_Z80`, -`CPUFEATURE_6502_ILLEGALS`, `CPUFEATURE_8085_ILLEGALS`, `CPUFEATURE_Z80_ILLEGALS` – 1 if given instruction subset is enabled, 0 otherwise +`CPUFEATURE_6502_ILLEGALS`, `CPUFEATURE_8085_ILLEGALS`, `CPUFEATURE_Z80_ILLEGALS`, `CPUFEATURE_Z80_NEXT` – 1 if given instruction subset is enabled, 0 otherwise * `ENCODING_SAME` - 1 if the encodings `default` and `src` are the same, 0 otherwise. diff --git a/include/i80_math.mfk b/include/i80_math.mfk index 42a6b843..2edf6acd 100644 --- a/include/i80_math.mfk +++ b/include/i80_math.mfk @@ -4,9 +4,15 @@ #endif #pragma zilog_syntax - -#if CPUFEATURE_Z80 || CPUFEATURE_GAMEBOY - +#if CPUFEATURE_Z80_NEXT +inline asm byte __mul_u8u8u8() { + ? LD E,A + ? MUL + ? LD A, E + ? RET +} +#elseif CPUFEATURE_Z80 || CPUFEATURE_GAMEBOY +//A = A * D noinline asm byte __mul_u8u8u8() { ? LD E,A ? LD A, 0 diff --git a/src/main/scala/millfork/CompilationOptions.scala b/src/main/scala/millfork/CompilationOptions.scala index c3a312ff..d7a3c51c 100644 --- a/src/main/scala/millfork/CompilationOptions.scala +++ b/src/main/scala/millfork/CompilationOptions.scala @@ -43,7 +43,7 @@ case class CompilationOptions(platform: Platform, EmitIntel8085Opcodes, EmitIntel8080Opcodes, UseIxForStack, UseIntelSyntaxForInput, UseIntelSyntaxForOutput) if (CpuFamily.forType(platform.cpu) != CpuFamily.I80) invalids ++= Set( - EmitExtended80Opcodes, EmitZ80Opcodes, EmitSharpOpcodes, EmitEZ80Opcodes, + EmitExtended80Opcodes, EmitZ80Opcodes, EmitSharpOpcodes, EmitEZ80Opcodes, EmitZ80NextOpcodes, UseIyForStack, UseIxForScratch, UseIyForScratch, UseShadowRegistersForInterrupts) if (CpuFamily.forType(platform.cpu) != CpuFamily.M6809) invalids ++= Set( @@ -111,7 +111,7 @@ case class CompilationOptions(platform: Platform, } case CpuFamily.I80 => if (flags(EmitIllegals)) { - if (platform.cpu != Z80 && platform.cpu != Intel8085) { + if (platform.cpu != Z80 && platform.cpu != Intel8085 && platform.cpu != Z80Next) { log.error("Illegal opcodes enabled for architecture that doesn't support them") } } @@ -160,6 +160,11 @@ case class CompilationOptions(platform: Platform, log.error("Sharp LR35902 opcodes enabled for architecture that doesn't support them") } } + if (flags(EmitZ80NextOpcodes)) { + if (platform.cpu != Z80Next) { + log.error("ZX Spectrum Next opcodes enabled for architecture that doesn't support them") + } + } if (flags(EmitExtended80Opcodes)) { if (platform.cpu != Sharp && !Z80Compatible(platform.cpu)) { log.error("Extended 8080-like opcodes enabled for architecture that doesn't support them") @@ -221,6 +226,7 @@ case class CompilationOptions(platform: Platform, "CPUFEATURE_65816_NATIVE" -> toLong(flag(CompilationFlag.EmitNative65816Opcodes)), "CPUFEATURE_6502_ILLEGALS" -> toLong(platform.cpuFamily == CpuFamily.M6502 && flag(CompilationFlag.EmitIllegals)), "CPUFEATURE_Z80_ILLEGALS" -> toLong(flag(CompilationFlag.EmitZ80Opcodes) && flag(CompilationFlag.EmitIllegals)), + "CPUFEATURE_Z80_NEXT" -> toLong(flag(CompilationFlag.EmitZ80NextOpcodes)), "CPUFEATURE_8085_ILLEGALS" -> toLong(flag(CompilationFlag.EmitIntel8080Opcodes) && flag(CompilationFlag.EmitIllegals)), "BIG_ENDIAN" -> toLong(Cpu.isBigEndian(platform.cpu)), "LITTLE_ENDIAN" -> toLong(!Cpu.isBigEndian(platform.cpu)), @@ -276,7 +282,7 @@ object CpuFamily extends Enumeration { import Cpu._ cpu match { case Mos | StrictMos | Ricoh | StrictRicoh | Cmos | HuC6280 | CE02 | Sixteen => M6502 - case Intel8080 | Intel8085 | StrictIntel8085 | Sharp | Z80 | StrictZ80 | EZ80 => I80 + case Intel8080 | Intel8085 | StrictIntel8085 | Sharp | Z80 | StrictZ80 | EZ80 | Z80Next => I80 case Intel8086 | Intel80186 => I86 case Cpu.Motorola6809 => M6809 } @@ -346,6 +352,10 @@ object Cpu extends Enumeration { * The Zilog eZ80 processor */ val EZ80: Cpu.Value = Value + /** + * The Z80 core from the ZX Spectrum Next + */ + val Z80Next: Cpu.Value = Value /** * The Sharp LR35902 processor */ @@ -370,11 +380,11 @@ object Cpu extends Enumeration { /** * Processors that can run code for Zilog Z80 */ - val Z80Compatible: Set[Cpu.Value] = Set(Z80, StrictZ80, EZ80) + val Z80Compatible: Set[Cpu.Value] = Set(Z80, StrictZ80, EZ80, Z80Next) /** * Processors that can run code for Intel 8080 */ - val Intel8080Compatible: Set[Cpu.Value] = Set(Intel8080, Intel8085, StrictIntel8085, Z80, StrictZ80, EZ80) + val Intel8080Compatible: Set[Cpu.Value] = Set(Intel8080, Intel8085, StrictIntel8085, Z80, StrictZ80, EZ80, Z80Next) /** * Processors that can run code for Intel 8085 */ @@ -415,6 +425,8 @@ object Cpu extends Enumeration { i80AlwaysDefaultFlags ++ Set(EmitIntel8080Opcodes, EmitIntel8085Opcodes, UseIntelSyntaxForInput, UseIntelSyntaxForOutput) case StrictZ80 | Z80 => i80AlwaysDefaultFlags ++ Set(EmitIntel8080Opcodes, EmitExtended80Opcodes, EmitZ80Opcodes, UseIxForStack, UseShadowRegistersForInterrupts) + case Z80Next => + i80AlwaysDefaultFlags ++ Set(EmitIntel8080Opcodes, EmitExtended80Opcodes, EmitZ80Opcodes, UseIxForStack, UseShadowRegistersForInterrupts, EmitIllegals, EmitZ80NextOpcodes) case EZ80 => i80AlwaysDefaultFlags ++ Set(EmitIntel8080Opcodes, EmitExtended80Opcodes, EmitZ80Opcodes, UseIxForStack, UseShadowRegistersForInterrupts, EmitEZ80Opcodes) case Sharp => @@ -456,6 +468,7 @@ object Cpu extends Enumeration { case "strict2a07" => StrictRicoh case "z80" => Z80 case "strictz80" => Z80 + case "zx80next" => Z80Next // disabled for now: // case "ez80" => EZ80 case "gameboy" => Sharp @@ -504,7 +517,7 @@ object CompilationFlag extends Enumeration { EmitCmosOpcodes, EmitCmosNopOpcodes, EmitHudsonOpcodes, Emit65CE02Opcodes, EmitEmulation65816Opcodes, EmitNative65816Opcodes, PreventJmpIndirectBug, LargeCode, ReturnWordsViaAccumulator, SoftwareStack, // compilation options for I80 - EmitIntel8080Opcodes, EmitIntel8085Opcodes, EmitExtended80Opcodes, EmitZ80Opcodes, EmitEZ80Opcodes, EmitSharpOpcodes, + EmitIntel8080Opcodes, EmitIntel8085Opcodes, EmitExtended80Opcodes, EmitZ80Opcodes, EmitEZ80Opcodes, EmitSharpOpcodes, EmitZ80NextOpcodes, UseShadowRegistersForInterrupts, UseIxForStack, UseIyForStack, UseIxForScratch, UseIyForScratch, diff --git a/src/main/scala/millfork/assembly/z80/ZOpcode.scala b/src/main/scala/millfork/assembly/z80/ZOpcode.scala index d40e7bd0..805360cf 100644 --- a/src/main/scala/millfork/assembly/z80/ZOpcode.scala +++ b/src/main/scala/millfork/assembly/z80/ZOpcode.scala @@ -29,6 +29,8 @@ object ZOpcode extends Enumeration { LD_DESP, LD_DEHL, RRHL, RLDE, DSUB, RSTV, LHLX, SHLX, //sharp: LD_AHLI, LD_AHLD, LD_HLIA, LD_HLDA, SWAP, LDH_DA, LDH_AD, LDH_CA, LDH_AC, LD_HLSP, ADD_SP, STOP, + // next: + LDIX, LDWS, LDIRX, LDDX, LDDRX, LDPIRX, OUTINB, MUL, SWAPNIB, MIRROR, NEXTREG, PIXELDN, PIXELAD, SETAE, TEST, DISCARD_A, DISCARD_F, DISCARD_HL, DISCARD_BC, DISCARD_DE, DISCARD_IX, DISCARD_IY, CHANGED_MEM, LABEL, BYTE = Value } @@ -69,19 +71,25 @@ object ZOpcodeClasses { val ChangesBCAlways: Set[ZOpcode.Value] = Set( INI, INIR, OUTI, OUTIR, IND, INDR, OUTD, OUTDR, LDI, LDIR, LDD, LDDR, CPI, CPIR, CPD, CPDR, + LDIX, LDIRX, LDDX, LDDRX, LDPIRX, EXX, CALL, JR, JP, LABEL, DJNZ) val ChangesHLAlways: Set[ZOpcode.Value] = Set( INI, INIR, OUTI, OUTIR, IND, INDR, OUTD, OUTDR, LDI, LDIR, LDD, LDDR, CPI, CPIR, CPD, CPDR, LD_AHLI, LD_AHLD, LD_HLIA, LD_HLDA, LD_HLSP, DSUB, RRHL, LHLX, + LDWS, LDIX, LDIRX, LDDX, LDDRX, LDPIRX, PIXELAD, PIXELDN, OUTINB, EXX, EX_DE_HL, CALL, JR, JP, LABEL) val ChangesDEAlways: Set[ZOpcode.Value] = Set( LDI, LDIR, LDD, LDDR, LD_DESP, LD_DEHL, RLDE, + LDWS, LDIX, LDIRX, LDDX, LDDRX, LDPIRX, MUL, EXX, EX_DE_HL, CALL, JR, JP, LABEL) val ChangesOnlyRegister: Set[ZOpcode.Value] = Set(INC, DEC, INC_16, DEC_16, POP, EX_SP, IN_C, IN_IMM, RL, RR, RLC, RRC, SLA, SRA, SRL, SLL) ++ SET ++ RES val ChangesFirstRegister: Set[ZOpcode.Value] = Set(LD, LD_16, ADD_16, SBC_16) - val ChangesAAlways: Set[ZOpcode.Value] = Set(DAA, ADD, ADC, SUB, SBC, XOR, OR, AND, LD_AHLI, LD_AHLD, RIM) + val ChangesAAlways: Set[ZOpcode.Value] = Set( + DAA, ADD, ADC, SUB, SBC, XOR, OR, AND, LD_AHLI, LD_AHLD, RIM, + MIRROR, SETAE, + ) val NonLinear: Set[ZOpcode.Value] = Set(JP, JR, CALL, LABEL, BYTE, EXX, EX_DE_HL, EX_SP, EXX, RET, RETI, RETN, HALT, RST, RSTV) } diff --git a/src/main/scala/millfork/output/Z80Assembler.scala b/src/main/scala/millfork/output/Z80Assembler.scala index 52e0ddcd..ef53e5cf 100644 --- a/src/main/scala/millfork/output/Z80Assembler.scala +++ b/src/main/scala/millfork/output/Z80Assembler.scala @@ -69,6 +69,8 @@ class Z80Assembler(program: Program, def requireIntel8085Illegals(): Unit = if (!options.flag(EmitIntel8085Opcodes) || !options.flag(EmitIllegals)) log.error("Unsupported instruction: " + instr) + def requireNext(): Unit = if (!options.flag(EmitZ80NextOpcodes)) log.error("Unsupported instruction: " + instr) + def useSharpOpcodes():Boolean = { if (!options.flag(EmitSharpOpcodes) && !options.flag(EmitIntel8080Opcodes)) log.error("Cannot determine which variant to emit : " + instr) @@ -144,6 +146,47 @@ class Z80Assembler(program: Program, writeByte(bank, index, 0xed) writeByte(bank, index + 1, edImplieds(op)) index + 2 + case ZLine0(op, NoRegisters, _) if nextEdImplieds.contains(op) => + requireNext() + writeByte(bank, index, 0xed) + writeByte(bank, index + 1, nextEdImplieds(op)) + index + 2 + case ZLine0(ADD_16, TwoRegisters(r@(ZRegister.HL | ZRegister.BC | ZRegister.DE), ZRegister.A), _) => + requireNext() + writeByte(bank, index, 0xed) + writeByte(bank, index + 1, 0x33 - internalRegisterIndex(r)) + index + 2 + case ZLine0(ADD_16, TwoRegisters(r@(ZRegister.HL | ZRegister.BC | ZRegister.DE), ZRegister.IMM_16), nn) => + requireNext() + writeByte(bank, index, 0xed) + writeByte(bank, index + 1, 0x36 - internalRegisterIndex(r)) + writeWord(bank, index + 2, nn) + index + 4 + case ZLine0(PUSH, OneRegister(ZRegister.IMM_16), nn) => + requireNext() + writeByte(bank, index, 0xed) + writeByte(bank, index + 1, 0x8A) + writeByte(bank, index + 2, nn.hiByte) + writeByte(bank, index + 3, nn.loByte) + index + 4 + case ZLine0(TEST, OneRegister(ZRegister.IMM_8), nn) => + requireNext() + writeByte(bank, index, 0xed) + writeByte(bank, index + 1, 0x27) + writeByte(bank, index + 2, nn) + index + 3 + case ZLine0(NEXTREG, TwoRegisters(ZRegister.IMM_8, ZRegister.IMM_8), nn) => + requireNext() + writeByte(bank, index, 0xed) + writeByte(bank, index + 1, 0x91) + writeWord(bank, index + 2, nn) + index + 4 + case ZLine0(NEXTREG, TwoRegisters(ZRegister.IMM_8, ZRegister.A), nn) => + requireNext() + writeByte(bank, index, 0xed) + writeByte(bank, index + 1, 0x92) + writeByte(bank, index + 2, nn) + index + 3 case ZLine0(ADD_16, TwoRegisters(ZRegister.HL, source), _) => writeByte(bank, index, 9 + 16 * internalRegisterIndex(source)) index + 1 @@ -776,6 +819,7 @@ object Z80Assembler { val edImplieds: mutable.Map[ZOpcode.Value, Int] = mutable.Map[ZOpcode.Value, Int]() val oneRegister: mutable.Map[ZOpcode.Value, One] = mutable.Map[ZOpcode.Value, One]() val cbOneRegister: mutable.Map[ZOpcode.Value, One] = mutable.Map[ZOpcode.Value, One]() + val nextEdImplieds: mutable.Map[ZOpcode.Value, Int] = mutable.Map[ZOpcode.Value, Int]() do { import ZOpcode._ @@ -846,6 +890,20 @@ object Z80Assembler { cbOneRegister(SLA) = One(0x20, 1) cbOneRegister(SRA) = One(0x28, 1) cbOneRegister(SRL) = One(0x38, 1) + + nextEdImplieds(LDIX) = 0xa4 + nextEdImplieds(LDWS) = 0xa5 + nextEdImplieds(LDIRX) = 0xb4 + nextEdImplieds(LDDX) = 0xb5 + nextEdImplieds(LDDRX) = 0xac + nextEdImplieds(LDPIRX) = 0xbc + nextEdImplieds(OUTINB) = 0x90 + nextEdImplieds(MUL) = 0xa4 + nextEdImplieds(SWAPNIB) = 0x23 + nextEdImplieds(MIRROR) = 0x24 + nextEdImplieds(PIXELDN) = 0x93 + nextEdImplieds(PIXELAD) = 0x94 + nextEdImplieds(SETAE) = 0x95 } while (false) } diff --git a/src/main/scala/millfork/parser/Z80Parser.scala b/src/main/scala/millfork/parser/Z80Parser.scala index a21559fa..4d1c353d 100644 --- a/src/main/scala/millfork/parser/Z80Parser.scala +++ b/src/main/scala/millfork/parser/Z80Parser.scala @@ -452,6 +452,20 @@ case class Z80Parser(filename: String, case (r1, e1, (r2, e2)) => merge(LD, LD_16, skipTargetA = false)((r1, e1, r2, e2)) } case "ADD" => (param(allowAbsolute = false) ~ HWS ~ position("comma").map(_ => ()) ~ "," ~/ HWS ~ param(allowAbsolute = false)).map { + + case (ZRegister.HL, None, (ZRegister.A, None)) if options.flags(CompilationFlag.EmitZ80NextOpcodes) => + (ADD_16, TwoRegisters(ZRegister.HL, ZRegister.A), None, zero) + case (ZRegister.DE, None, (ZRegister.A, None)) if options.flags(CompilationFlag.EmitZ80NextOpcodes) => + (ADD_16, TwoRegisters(ZRegister.DE, ZRegister.A), None, zero) + case (ZRegister.BC, None, (ZRegister.A, None)) if options.flags(CompilationFlag.EmitZ80NextOpcodes) => + (ADD_16, TwoRegisters(ZRegister.BC, ZRegister.A), None, zero) + case (ZRegister.HL, None, (ZRegister.IMM_8, Some(expr))) => + (ADD_16, TwoRegisters(ZRegister.HL, ZRegister.IMM_16), None, expr) + case (ZRegister.DE, None, (ZRegister.IMM_8, Some(expr))) => + (ADD_16, TwoRegisters(ZRegister.DE, ZRegister.IMM_16), None, expr) + case (ZRegister.BC, None, (ZRegister.IMM_8, Some(expr))) => + (ADD_16, TwoRegisters(ZRegister.BC, ZRegister.IMM_16), None, expr) + case (ZRegister.SP, None, (ZRegister.IMM_8, Some(expr))) if options.flags(CompilationFlag.EmitSharpOpcodes) => (ADD_SP, OneRegister(ZRegister.IMM_8), None, expr) case (r1, e1, (r2, e2)) => merge(ADD, ADD_16, skipTargetA = true)((r1, e1, r2, e2)) @@ -466,6 +480,28 @@ case class Z80Parser(filename: String, case "DSUB" => imm(DSUB) case "RSTV" => imm(RSTV) + case "LDIX" => imm(LDIX) + case "LDWS" => imm(LDWS) + case "LDIRX" => imm(LDIRX) + case "LDDX" => imm(LDDX) + case "LDDRX" => imm(LDDRX) + case "LDPIRX" => imm(LDPIRX) + case "OUTINB" => imm(OUTINB) + case "SWAPNIB" => imm(SWAPNIB) + case "PIXELDN" => imm(PIXELDN) + case "PIXELAD" => imm(PIXELAD) + case "SETAE" => imm(SETAE) + case "MUL" => (("D"|"d") ~ HWS ~ "," ~/ HWS ~ ("E" | "e")).?.map { _ => (MUL, NoRegisters, None, zero)} + case "MIRROR" => ("A"|"a").?.map { _ => (MUL, NoRegisters, None, zero)} + case "NEXTREG" =>(param(allowAbsolute = false) ~ HWS ~ position("comma").map(_ => ()) ~ "," ~/ HWS ~ param(allowAbsolute = false)).map { + case (ZRegister.IMM_8, Some(n), (ZRegister.A, None)) => (NEXTREG, TwoRegisters(ZRegister.IMM_8, ZRegister.A), None, n) + case (ZRegister.IMM_8, Some(n), (ZRegister.IMM_8, Some(v))) => (NEXTREG, TwoRegisters(ZRegister.IMM_8, ZRegister.IMM_8), None, SeparateBytesExpression(v, n)) + case _ => + log.error("Invalid parameters for NEXTREG", Some(pos)) + (NOP, NoRegisters, None, zero) + } + case "TEST" => one8Register(TEST) + case _ => log.error("Unsupported opcode " + opcode, Some(pos)) imm(NOP) diff --git a/src/test/scala/millfork/test/Z80AssemblySuite.scala b/src/test/scala/millfork/test/Z80AssemblySuite.scala index 95784b68..ad21b760 100644 --- a/src/test/scala/millfork/test/Z80AssemblySuite.scala +++ b/src/test/scala/millfork/test/Z80AssemblySuite.scala @@ -1,7 +1,7 @@ package millfork.test import millfork.Cpu -import millfork.test.emu.{EmuUnoptimizedCrossPlatformRun, EmuUnoptimizedIntel8080Run, EmuUnoptimizedIntel8085Run, EmuUnoptimizedSharpRun, EmuUnoptimizedZ80Run} +import millfork.test.emu.{EmuUnoptimizedCrossPlatformRun, EmuUnoptimizedIntel8080Run, EmuUnoptimizedIntel8085Run, EmuUnoptimizedSharpRun, EmuUnoptimizedZ80NextRun, EmuUnoptimizedZ80Run} import org.scalatest.{FunSuite, Matchers} /** @@ -975,4 +975,41 @@ class Z80AssemblySuite extends FunSuite with Matchers { | } """.stripMargin) } + + test("Z80 Next instructions (Zilog syntax)") { + EmuUnoptimizedZ80NextRun( + """ + | #pragma zilog_syntax + | asm void main () { + | ret + | ldix + | ldws + | ldirx + | lddx + | lddrx + | ldpirx + | outinb + | mul + | mul d,e + | add hl,a + | add de,a + | add bc,a + | add hl,1 + | add de,2 + | add bc,3 + | swapnib + | mirror + | mirror a + | push $5555 + | nextreg 1,2 + | nextreg 1,a + | pixeldn + | pixelad + | setae + | test 8 + | ret + | } + """.stripMargin) + } + } diff --git a/src/test/scala/millfork/test/emu/EmuUnoptimizedRun.scala b/src/test/scala/millfork/test/emu/EmuUnoptimizedRun.scala index 6e16c62f..1c989360 100644 --- a/src/test/scala/millfork/test/emu/EmuUnoptimizedRun.scala +++ b/src/test/scala/millfork/test/emu/EmuUnoptimizedRun.scala @@ -22,6 +22,8 @@ object EmuUnoptimizedIntel8080Run extends EmuZ80Run(Cpu.Intel8080, Nil, Nil) object EmuUnoptimizedIntel8085Run extends EmuZ80Run(Cpu.Intel8085, Nil, Nil) +object EmuUnoptimizedZ80NextRun extends EmuZ80Run(Cpu.Z80Next, Nil, Nil) + object EmuUnoptimizedIntel8086Run extends EmuI86Run(Nil, Nil) object EmuUnoptimizedSharpRun extends EmuZ80Run(Cpu.Sharp, Nil, Nil) diff --git a/src/test/scala/millfork/test/emu/EmuZ80Run.scala b/src/test/scala/millfork/test/emu/EmuZ80Run.scala index 8f06d14c..55675867 100644 --- a/src/test/scala/millfork/test/emu/EmuZ80Run.scala +++ b/src/test/scala/millfork/test/emu/EmuZ80Run.scala @@ -83,7 +83,8 @@ class EmuZ80Run(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimizatio CompilationFlag.OptimizeStdlib -> this.inline, CompilationFlag.OptimizeForSize -> this.optimizeForSize, CompilationFlag.SubroutineExtraction -> optimizeForSize, - CompilationFlag.EmitIllegals -> (cpu == millfork.Cpu.Z80 || cpu == millfork.Cpu.Intel8085), + CompilationFlag.EmitIllegals -> (cpu == millfork.Cpu.Z80 || cpu == millfork.Cpu.Intel8085 || cpu == millfork.Cpu.Z80Next), + CompilationFlag.EmitZ80NextOpcodes -> (cpu == millfork.Cpu.Z80Next), CompilationFlag.LenientTextEncoding -> true) val options = CompilationOptions(platform, millfork.Cpu.defaultFlags(cpu).map(_ -> true).toMap ++ extraFlags, None, 0, Map(), JobContext(log, new LabelGenerator)) println(cpu)