1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-05-31 18:41:30 +00:00

Intel 8085 support

This commit is contained in:
Karol Stasiak 2019-05-31 17:27:38 +02:00
parent 1cb3b672b1
commit b3bb9bb063
17 changed files with 93 additions and 22 deletions

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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,

View File

@ -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
}

View File

@ -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),

View File

@ -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)
}

View File

@ -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 {

View File

@ -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)

View File

@ -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
}

View File

@ -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

View File

@ -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)

View File

@ -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)
}
}
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)
}
}

View File

@ -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)