From b3bb9bb063f27e7ccbb5d70664568db264c8cda1 Mon Sep 17 00:00:00 2001 From: Karol Stasiak Date: Fri, 31 May 2019 17:27:38 +0200 Subject: [PATCH] Intel 8085 support --- CHANGELOG.md | 2 ++ docs/api/command-line.md | 4 +-- docs/api/custom-platform.md | 10 +++--- docs/api/getting-started.md | 2 +- docs/faq.md | 2 +- docs/lang/assemblyz80.md | 2 +- .../scala/millfork/CompilationOptions.scala | 24 ++++++++++---- src/main/scala/millfork/Main.scala | 2 +- src/main/scala/millfork/Platform.scala | 3 ++ .../scala/millfork/assembly/z80/ZOpcode.scala | 6 ++-- .../z80/opt/AlwaysGoodI80Optimizations.scala | 2 +- .../assembly/z80/opt/CoarseFlowAnalyzer.scala | 4 ++- .../z80/opt/ReverseFlowAnalyzer.scala | 4 +++ .../scala/millfork/output/Z80Assembler.scala | 10 ++++++ .../scala/millfork/parser/Z80Parser.scala | 4 +++ .../millfork/test/Z80AssemblySuite.scala | 32 +++++++++++++++++-- .../millfork/test/emu/EmuUnoptimizedRun.scala | 2 ++ 17 files changed, 93 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 810ea5b4..f50df5ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ * Super experimental and very incomplete Intel 8086 support via 8080-to-8086 translation. +* Support for Intel 8085. + * Added `memory_barrier` macro. * Added `random` module. diff --git a/docs/api/command-line.md b/docs/api/command-line.md index ae4f33c1..c26b2c42 100644 --- a/docs/api/command-line.md +++ b/docs/api/command-line.md @@ -44,11 +44,11 @@ If given, then the compiler will NOT try to detect the default include directory * `-finput_intel_syntax`, `-finput_zilog_syntax` – Choose syntax for assembly sources on 8080-like targets. Can be overridden by the source file itself using `#pragma`. -`.ini` equivalent: `input_intel_syntax`. Default: Intel (true) on Intel 8080, Zilog (false) otherwise. +`.ini` equivalent: `input_intel_syntax`. Default: Intel (true) on Intel 8080/8085, Zilog (false) otherwise. * `-foutput_intel_syntax`, `-foutput_zilog_syntax` – Choose syntax for assembly output on 8080-like targets. -`.ini` equivalent: `output_intel_syntax`. Default: Intel (true) on Intel 8080, Zilog (false) otherwise. +`.ini` equivalent: `output_intel_syntax`. Default: Intel (true) on Intel 8080/8085, Zilog (false) otherwise. * `--syntax=intel`, `--syntax=zilog` – sets both previous options at once diff --git a/docs/api/custom-platform.md b/docs/api/custom-platform.md index c28f075d..108523b0 100644 --- a/docs/api/custom-platform.md +++ b/docs/api/custom-platform.md @@ -27,11 +27,13 @@ if a line ends with a backslash character, the value continues to the next line. * `65816` (WDC 65816/65802; experimental; currently only programs that use only 16-bit addressing are supported) - * `z80` (Zilog Z80; experimental and slightly incomplete) + * `z80` (Zilog Z80) - * `i8080` (Intel 8080; experimental, buggy and very incomplete) + * `i8080` (Intel 8080) - * `gameboy` (Sharp LR35902; experimental, buggy and very incomplete) + * `i8085` (Intel 8085) + + * `gameboy` (Sharp LR35902; experimental) * `i8086` (Intel 8086; very experimental, very buggy and very, very incomplete – see the [8086 support disclaimer](../lang/x86disclaimer.md)) @@ -94,7 +96,7 @@ Default: the same as `encoding`. * `software_stach` – use software stack for stack variables, default is `false` - * `output_intel_syntax` – use Intel syntax instead of Zilog syntax, default is `true` for Intel 8080 and `false` otherwise + * `output_intel_syntax` – use Intel syntax instead of Zilog syntax, default is `true` for Intel 8080/8085 and `false` otherwise #### `[define]` section diff --git a/docs/api/getting-started.md b/docs/api/getting-started.md index 2116b7ac..4867c796 100644 --- a/docs/api/getting-started.md +++ b/docs/api/getting-started.md @@ -44,7 +44,7 @@ You may be also interested in the following: * `-fipo` – enable interprocedural optimization * `-s` – additionally generate assembly output -(if targeting Intel 8080, use `--syntax=intel` or `--syntax=zilog` to choose the preferred assembly syntax) +(if targeting Intel 8080/8085, use `--syntax=intel` or `--syntax=zilog` to choose the preferred assembly syntax) * `-fsource-in-asm` – show original Millfork source in the assembly output diff --git a/docs/faq.md b/docs/faq.md index c6c9b35b..b2eda2a0 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -26,7 +26,7 @@ Support for other devices using supported processors can be easily added, usuall * 6502 and its descendants: 6510, 65C02, Ricoh 2A03, and to a lesser degree CSG 65CE02, Hudson Soft HuC6280 and WDC 65816. 6509 is not supported and will not be. -* Intel 8080, Zilog Z80, Sharp LR35902 (also known as GBZ80) +* Intel 8080, Intel 8085, Zilog Z80, Sharp LR35902 (also known as GBZ80) * There is also partial experimental support for Intel 8086, via automatic 8080-to-8086 translation. The generated code is very large and very slow. diff --git a/docs/lang/assemblyz80.md b/docs/lang/assemblyz80.md index 1a501fdd..71385fa5 100644 --- a/docs/lang/assemblyz80.md +++ b/docs/lang/assemblyz80.md @@ -10,7 +10,7 @@ There are two ways to include raw assembly code in your Millfork programs: ## Assembly syntax -By default, Millfork uses Zilog syntax for Z80 and LR35902 assembly and Intel syntax for Intel 8080 assembly. +By default, Millfork uses Zilog syntax for Z80 and LR35902 assembly and Intel syntax for Intel 8080/8085 assembly. This can be overridden per file by a pragma directive or by several other means. Using both kinds of syntax in one file is not supported. diff --git a/src/main/scala/millfork/CompilationOptions.scala b/src/main/scala/millfork/CompilationOptions.scala index 9c55e920..cc91fd89 100644 --- a/src/main/scala/millfork/CompilationOptions.scala +++ b/src/main/scala/millfork/CompilationOptions.scala @@ -41,7 +41,7 @@ case class CompilationOptions(platform: Platform, EmitIntel8080Opcodes, UseIxForStack, UseIntelSyntaxForInput, UseIntelSyntaxForOutput) if (CpuFamily.forType(platform.cpu) != CpuFamily.I80) invalids ++= Set( - EmitExtended80Opcodes, EmitZ80Opcodes, EmitSharpOpcodes, EmitEZ80Opcodes, + EmitIntel8085Opcodes, EmitExtended80Opcodes, EmitZ80Opcodes, EmitSharpOpcodes, EmitEZ80Opcodes, UseIyForStack, UseShadowRegistersForInterrupts) invalids = invalids.filter(flags) @@ -161,10 +161,15 @@ case class CompilationOptions(platform: Platform, } } if (flags(EmitIntel8080Opcodes)) { - if (platform.cpu != Intel8080 && platform.cpu != Z80 && platform.cpu != EZ80) { + if (platform.cpu != Intel8080 && platform.cpu != Intel8085 && platform.cpu != Z80 && platform.cpu != EZ80) { log.error("Intel 8080 opcodes enabled for architecture that doesn't support them") } } + if (flags(EmitIntel8085Opcodes)) { + if (platform.cpu != Intel8085) { + log.error("Intel 8085 opcodes enabled for architecture that doesn't support them") + } + } case CpuFamily.I86 => if (flags(EmitIllegals)) { log.error("Illegal opcodes enabled for architecture that doesn't support them") @@ -198,6 +203,7 @@ case class CompilationOptions(platform: Platform, "CPUFEATURE_Z80" -> toLong(flag(CompilationFlag.EmitZ80Opcodes)), "CPUFEATURE_EZ80" -> toLong(flag(CompilationFlag.EmitEZ80Opcodes)), "CPUFEATURE_8080" -> toLong(flag(CompilationFlag.EmitIntel8080Opcodes)), + "CPUFEATURE_8085" -> toLong(flag(CompilationFlag.EmitIntel8085Opcodes)), "CPUFEATURE_GAMEBOY" -> toLong(flag(CompilationFlag.EmitSharpOpcodes)), "CPUFEATURE_65C02" -> toLong(flag(CompilationFlag.EmitCmosOpcodes)), "CPUFEATURE_65CE02" -> toLong(flag(CompilationFlag.Emit65CE02Opcodes)), @@ -227,15 +233,15 @@ object CpuFamily extends Enumeration { import Cpu._ cpu match { case Mos | StrictMos | Ricoh | StrictRicoh | Cmos | HuC6280 | CE02 | Sixteen => M6502 - case Intel8080 | Sharp | Z80 | EZ80 => I80 - case Intel8086 => I86 + case Intel8080 | Intel8085 | Sharp | Z80 | EZ80 => I80 + case Intel8086 | Intel80186 => I86 } } } object Cpu extends Enumeration { - val Mos, StrictMos, Ricoh, StrictRicoh, Cmos, HuC6280, CE02, Sixteen, Intel8080, Z80, EZ80, Sharp, Intel8086, Intel80186 = Value + val Mos, StrictMos, Ricoh, StrictRicoh, Cmos, HuC6280, CE02, Sixteen, Intel8080, Intel8085, Z80, EZ80, Sharp, Intel8086, Intel80186 = Value val CmosCompatible = Set(Cmos, HuC6280, CE02, Sixteen) @@ -268,6 +274,8 @@ object Cpu extends Enumeration { mosAlwaysDefaultFlags ++ Set(DecimalMode, EmitCmosOpcodes, EmitEmulation65816Opcodes, EmitNative65816Opcodes, ReturnWordsViaAccumulator) case Intel8080 => i80AlwaysDefaultFlags ++ Set(EmitIntel8080Opcodes, UseIntelSyntaxForInput, UseIntelSyntaxForOutput) + case Intel8085 => + i80AlwaysDefaultFlags ++ Set(EmitIntel8080Opcodes, EmitIntel8085Opcodes, UseIntelSyntaxForInput, UseIntelSyntaxForOutput) case Z80 => i80AlwaysDefaultFlags ++ Set(EmitIntel8080Opcodes, EmitExtended80Opcodes, EmitZ80Opcodes, UseIxForStack, UseShadowRegistersForInterrupts) case EZ80 => @@ -315,6 +323,9 @@ object Cpu extends Enumeration { case "8080" => Intel8080 case "i8080" => Intel8080 case "intel8080" => Intel8080 + case "8085" => Intel8085 + case "i8085" => Intel8085 + case "intel8085" => Intel8085 case "intel8086" => Intel8086 case "i8086" => Intel8086 case "8086" => Intel8086 @@ -343,7 +354,7 @@ object CompilationFlag extends Enumeration { EmitCmosOpcodes, EmitCmosNopOpcodes, EmitHudsonOpcodes, Emit65CE02Opcodes, EmitEmulation65816Opcodes, EmitNative65816Opcodes, PreventJmpIndirectBug, LargeCode, ReturnWordsViaAccumulator, SoftwareStack, // compilation options for I80 - EmitIntel8080Opcodes, EmitExtended80Opcodes, EmitZ80Opcodes, EmitEZ80Opcodes, EmitSharpOpcodes, + EmitIntel8080Opcodes, EmitIntel8085Opcodes, EmitExtended80Opcodes, EmitZ80Opcodes, EmitEZ80Opcodes, EmitSharpOpcodes, UseShadowRegistersForInterrupts, UseIxForStack, UseIyForStack, UseIxForScratch, UseIyForScratch, @@ -381,6 +392,7 @@ object CompilationFlag extends Enumeration { "emit_ez80" -> EmitEZ80Opcodes, "emit_x80" -> EmitExtended80Opcodes, "emit_8080" -> EmitIntel8080Opcodes, + "emit_8085" -> EmitIntel8085Opcodes, "emit_sharp" -> EmitSharpOpcodes, "ix_stack" -> UseIxForStack, "iy_stack" -> UseIyForStack, diff --git a/src/main/scala/millfork/Main.scala b/src/main/scala/millfork/Main.scala index 26570191..93efe201 100644 --- a/src/main/scala/millfork/Main.scala +++ b/src/main/scala/millfork/Main.scala @@ -258,7 +258,7 @@ object Main { case 0 => Nil case _ => platform.cpu match { case Cpu.Z80 | Cpu.EZ80 => Z80OptimizationPresets.GoodForZ80 - case Cpu.Intel8080 => Z80OptimizationPresets.GoodForIntel8080 + case Cpu.Intel8080 | Cpu.Intel8085 => Z80OptimizationPresets.GoodForIntel8080 case Cpu.Sharp => Z80OptimizationPresets.GoodForSharp case _ => Nil } diff --git a/src/main/scala/millfork/Platform.scala b/src/main/scala/millfork/Platform.scala index 86960f4e..2f576701 100644 --- a/src/main/scala/millfork/Platform.scala +++ b/src/main/scala/millfork/Platform.scala @@ -249,6 +249,9 @@ object Platform { "CPU_Z80" -> toLong(cpu == Cpu.Z80), "CPU_EZ80" -> toLong(cpu == Cpu.EZ80), "CPU_8080" -> toLong(cpu == Cpu.Intel8080), + "CPU_8085" -> toLong(cpu == Cpu.Intel8085), + "CPU_8086" -> toLong(cpu == Cpu.Intel8086), + "CPU_80186" -> toLong(cpu == Cpu.Intel80186), "CPU_GAMEBOY" -> toLong(cpu == Cpu.Sharp), "ARCH_X86" -> toLong(CpuFamily.forType(cpu) == CpuFamily.I86), "ARCH_6800" -> toLong(CpuFamily.forType(cpu) == CpuFamily.M6800), diff --git a/src/main/scala/millfork/assembly/z80/ZOpcode.scala b/src/main/scala/millfork/assembly/z80/ZOpcode.scala index ea71b0fd..fea89753 100644 --- a/src/main/scala/millfork/assembly/z80/ZOpcode.scala +++ b/src/main/scala/millfork/assembly/z80/ZOpcode.scala @@ -23,6 +23,8 @@ object ZOpcode extends Enumeration { EXX, EX_DE_HL, EX_AF_AF, EX_SP, RST, IM, EI, DI, DJNZ, JP, JR, CALL, RET, RETN, RETI, HALT, + // 8085: + RIM, SIM, //sharp: LD_AHLI, LD_AHLD, LD_HLIA, LD_HLDA, SWAP, LDH_DA, LDH_AD, LDH_CA, LDH_AC, LD_HLSP, ADD_SP, STOP, DISCARD_A, DISCARD_F, DISCARD_HL, DISCARD_BC, DISCARD_DE, DISCARD_IX, DISCARD_IY, CHANGED_MEM, @@ -56,7 +58,7 @@ object ZOpcodeClasses { val ChangesAFAlways = Set( // TODO: ! DAA, ADD, ADC, SUB, SBC, XOR, OR, AND, INC, DEC, - SCF, CCF, NEG, + SCF, CCF, NEG, RIM, LDH_AC, LDH_AD, LD_AHLI, LD_AHLD, ADD_16, ADC_16, SBC_16, INC_16, DEC_16, INI, INIR, OUTI, OUTIR, IND, INDR, OUTD, OUTDR, @@ -76,6 +78,6 @@ object ZOpcodeClasses { 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(LD, LD_16, ADD_16, SBC_16) - val ChangesAAlways = Set(DAA, ADD, ADC, SUB, SBC, XOR, OR, AND, LD_AHLI, LD_AHLD) + val ChangesAAlways = Set(DAA, ADD, ADC, SUB, SBC, XOR, OR, AND, LD_AHLI, LD_AHLD, RIM) val NonLinear = Set(JP, JR, CALL, LABEL, BYTE, EXX, EX_DE_HL, EX_SP, EXX, RET, RETI, RETN, HALT) } \ No newline at end of file diff --git a/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodI80Optimizations.scala b/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodI80Optimizations.scala index 8898904b..25d07c1c 100644 --- a/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodI80Optimizations.scala +++ b/src/main/scala/millfork/assembly/z80/opt/AlwaysGoodI80Optimizations.scala @@ -10,7 +10,7 @@ import millfork.DecimalUtils._ import millfork.error.FatalErrorReporting /** - * Optimizations valid for Intel8080, Z80, EZ80 and Sharp + * Optimizations valid for Intel8080, Intel8085, Z80, EZ80 and Sharp * @author Karol Stasiak */ object AlwaysGoodI80Optimizations { diff --git a/src/main/scala/millfork/assembly/z80/opt/CoarseFlowAnalyzer.scala b/src/main/scala/millfork/assembly/z80/opt/CoarseFlowAnalyzer.scala index b59138d5..0eba885f 100644 --- a/src/main/scala/millfork/assembly/z80/opt/CoarseFlowAnalyzer.scala +++ b/src/main/scala/millfork/assembly/z80/opt/CoarseFlowAnalyzer.scala @@ -67,7 +67,7 @@ object CoarseFlowAnalyzer { ) } - case ZLine0(NOP | DISCARD_A | DISCARD_BC | DISCARD_DE | DISCARD_HL | DISCARD_F, _, _) => + case ZLine0(NOP | DISCARD_A | DISCARD_BC | DISCARD_DE | DISCARD_HL | DISCARD_F | SIM, _, _) => () case ZLine0(PUSH, _, _) => () @@ -287,6 +287,8 @@ object CoarseFlowAnalyzer { pf = AnyStatus, nf = Status.SingleFalse) + case ZLine0(RIM, _, _) => + currentStatus = currentStatus.copy(a = AnyStatus) case ZLine0(opcode, registers, _) => currentStatus = currentStatus.copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus) diff --git a/src/main/scala/millfork/assembly/z80/opt/ReverseFlowAnalyzer.scala b/src/main/scala/millfork/assembly/z80/opt/ReverseFlowAnalyzer.scala index 0841d998..dbe395fd 100644 --- a/src/main/scala/millfork/assembly/z80/opt/ReverseFlowAnalyzer.scala +++ b/src/main/scala/millfork/assembly/z80/opt/ReverseFlowAnalyzer.scala @@ -459,6 +459,10 @@ object ReverseFlowAnalyzer { currentImportance = currentImportance.butReadsRegister(ZRegister.A).copy(cf = Important, hf = Unimportant, nf = Unimportant) case ZLine0(SCF, _, _) => currentImportance = currentImportance.copy(cf = Unimportant, hf = Unimportant, nf = Unimportant) + case ZLine0(RIM, _, _) => + currentImportance = currentImportance.copy(a = Unimportant) + case ZLine0(SIM, _, _) => + currentImportance = currentImportance.copy(a = Important) case _ => currentImportance = finalImportance // TODO } diff --git a/src/main/scala/millfork/output/Z80Assembler.scala b/src/main/scala/millfork/output/Z80Assembler.scala index 357dfa8a..0c281b66 100644 --- a/src/main/scala/millfork/output/Z80Assembler.scala +++ b/src/main/scala/millfork/output/Z80Assembler.scala @@ -61,6 +61,8 @@ class Z80Assembler(program: Program, def requireEZ80(): Unit = if (!options.flag(EmitEZ80Opcodes)) log.error("Unsupported instruction: " + instr) + def requireIntel8085(): Unit = if (!options.flag(EmitIntel8085Opcodes)) log.error("Unsupported instruction: " + instr) + def useSharpOpcodes():Boolean = { if (!options.flag(EmitSharpOpcodes) && !options.flag(EmitIntel8080Opcodes)) log.error("Cannot determine which variant to emit : " + instr) @@ -78,6 +80,14 @@ class Z80Assembler(program: Program, index case ZLine0(LABEL | BYTE | DISCARD_F | DISCARD_HL | DISCARD_BC | DISCARD_DE | DISCARD_IX | DISCARD_IY | DISCARD_A | CHANGED_MEM, _, _) => ??? + case ZLine0(RIM, NoRegisters, _) => + requireIntel8085() + writeByte(bank, index, 0x20) + index + 1 + case ZLine0(SIM, NoRegisters, _) => + requireIntel8085() + writeByte(bank, index, 0x30) + index + 1 case ZLine0(RST, NoRegisters, param) => val opcode = param.quickSimplify match { case NumericConstant(n, _) if n >=0 && n <= 0x38 && n % 8 == 0 => 0xc7 + n.toInt diff --git a/src/main/scala/millfork/parser/Z80Parser.scala b/src/main/scala/millfork/parser/Z80Parser.scala index b8efe7d4..ee873256 100644 --- a/src/main/scala/millfork/parser/Z80Parser.scala +++ b/src/main/scala/millfork/parser/Z80Parser.scala @@ -230,6 +230,8 @@ case class Z80Parser(filename: String, case "HLT" => imm(HALT) case "HALT" => imm(HALT) case "STOP" => imm(STOP) + case "RIM" => imm(RIM) + case "SIM" => imm(SIM) case "RETN" => imm(RETN) case "RETI" => imm(RETI) @@ -449,6 +451,8 @@ case class Z80Parser(filename: String, case "CMA" => imm(CPL) case "STC" => imm(SCF) case "CMC" => imm(CCF) + case "RIM" => imm(RIM) + case "SIM" => imm(SIM) case "HLT" => imm(HALT) case "EI" => imm(EI) diff --git a/src/test/scala/millfork/test/Z80AssemblySuite.scala b/src/test/scala/millfork/test/Z80AssemblySuite.scala index 71b81414..81d8d46c 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, EmuUnoptimizedSharpRun, EmuUnoptimizedZ80Run} +import millfork.test.emu.{EmuUnoptimizedCrossPlatformRun, EmuUnoptimizedIntel8080Run, EmuUnoptimizedIntel8085Run, EmuUnoptimizedSharpRun, EmuUnoptimizedZ80Run} import org.scalatest.{FunSuite, Matchers} /** @@ -900,4 +900,32 @@ class Z80AssemblySuite extends FunSuite with Matchers { | } """.stripMargin) } -} \ No newline at end of file + + + test("Intel 8085 instructions (Zilog syntax)") { + EmuUnoptimizedIntel8085Run( + """ + | #pragma zilog_syntax + | asm void main () { + | ret + | rim + | sim + | ret + | } + """.stripMargin) + } + + + test("Intel 8085 instructions (Intel syntax)") { + EmuUnoptimizedIntel8085Run( + """ + | #pragma intelg_syntax + | asm void main () { + | ret + | rim + | sim + | ret + | } + """.stripMargin) + } +} diff --git a/src/test/scala/millfork/test/emu/EmuUnoptimizedRun.scala b/src/test/scala/millfork/test/emu/EmuUnoptimizedRun.scala index 778307da..079ea243 100644 --- a/src/test/scala/millfork/test/emu/EmuUnoptimizedRun.scala +++ b/src/test/scala/millfork/test/emu/EmuUnoptimizedRun.scala @@ -20,6 +20,8 @@ object EmuUnoptimizedZ80Run extends EmuZ80Run(Cpu.Z80, Nil, Nil) object EmuUnoptimizedIntel8080Run extends EmuZ80Run(Cpu.Intel8080, Nil, Nil) +object EmuUnoptimizedIntel8085Run extends EmuZ80Run(Cpu.Intel8085, Nil, Nil) + object EmuUnoptimizedIntel8086Run extends EmuI86Run(Nil, Nil) object EmuUnoptimizedSharpRun extends EmuZ80Run(Cpu.Sharp, Nil, Nil)