1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-06-11 15:29:34 +00:00

R800 support

This commit is contained in:
Karol Stasiak 2021-09-18 00:36:16 +02:00
parent 7530b382a8
commit 166acf2b18
20 changed files with 353 additions and 36 deletions

View File

@ -37,6 +37,8 @@ if a line ends with a backslash character, the value continues to the next line.
* `z80` (Zilog Z80) * `z80` (Zilog Z80)
* `strictz80` (Z80 without illegal instructions) * `strictz80` (Z80 without illegal instructions)
* `r800` (R800)
* `z80next` (Z80 core from ZX Spectrum Next) * `z80next` (Z80 core from ZX Spectrum Next)
Note: Millfork version 0.3.18 and earlier uses the name `zx80next` for this architecture. Note: Millfork version 0.3.18 and earlier uses the name `zx80next` for this architecture.
@ -80,6 +82,8 @@ This list cannot contain module template instantiations.
* `emit_x80` whether the compiler should emit instructions present on Sharp LR35902 and Z80, but absent on Intel 8080, default is `true` on compatible processors and `false` elsewhere * `emit_x80` whether the compiler should emit instructions present on Sharp LR35902 and Z80, but absent on Intel 8080, default is `true` on compatible processors and `false` elsewhere
* `emit_z80` whether the compiler should emit Zilog Z80 instructions not covered by `emit_x80`, default is `true` on compatible processors and `false` elsewhere * `emit_z80` whether the compiler should emit Zilog Z80 instructions not covered by `emit_x80`, default is `true` on compatible processors and `false` elsewhere
* `emit_r800` whether the compiler should emit R800 instructions, default is `true` on compatible processors and `false` elsewhere
* `prevent_jmp_indirect_bug` whether the compiler should try to avoid the indirect JMP bug, * `prevent_jmp_indirect_bug` whether the compiler should try to avoid the indirect JMP bug,
default is `false` on 65C02-compatible or non-6502 processors and `true` elsewhere default is `false` on 65C02-compatible or non-6502 processors and `true` elsewhere

View File

@ -11,6 +11,12 @@ inline asm byte __mul_u8u8u8() {
? LD A, E ? LD A, E
? RET ? RET
} }
#elseif CPUFEATURE_R800
inline asm byte __mul_u8u8u8() {
? MULUB A,D
? LD A,L
? RET
}
#elseif CPUFEATURE_Z80 || CPUFEATURE_GAMEBOY #elseif CPUFEATURE_Z80 || CPUFEATURE_GAMEBOY
//A = A * D //A = A * D
noinline asm byte __mul_u8u8u8() { noinline asm byte __mul_u8u8u8() {
@ -89,6 +95,16 @@ __divmod_u16u8u16u8_skip:
? RET ? RET
} }
#if CPUFEATURE_R800
inline asm word __mul_u16u8u16() {
? LD L,A
? LD H,0
? MULUW HL,DE
? RET
}
#else
// HL=A*DE
noinline asm word __mul_u16u8u16() { noinline asm word __mul_u16u8u16() {
? LD HL,0 ? LD HL,0
? LD B,8 ? LD B,8
@ -113,8 +129,17 @@ __mul_u16u8u16_skip:
#endif #endif
? RET ? RET
} }
#endif
#if CPUFEATURE_Z80 || CPUFEATURE_GAMEBOY
#if CPUFEATURE_R800
inline asm word __mul_u16u16u16() {
? EX DE,HL
? MULUW HL,BC
? RET
}
#elseif CPUFEATURE_Z80 || CPUFEATURE_GAMEBOY
// HL=BC*DE
noinline asm word __mul_u16u16u16() { noinline asm word __mul_u16u16u16() {
LD HL,0 LD HL,0
LD A,16 LD A,16

View File

@ -45,7 +45,7 @@ case class CompilationOptions(platform: Platform,
EmitIntel8085Opcodes, EmitIntel8080Opcodes, UseIxForStack, UseIntelSyntaxForInput, UseIntelSyntaxForOutput) EmitIntel8085Opcodes, EmitIntel8080Opcodes, UseIxForStack, UseIntelSyntaxForInput, UseIntelSyntaxForOutput)
if (CpuFamily.forType(platform.cpu) != CpuFamily.I80) invalids ++= Set( if (CpuFamily.forType(platform.cpu) != CpuFamily.I80) invalids ++= Set(
EmitExtended80Opcodes, EmitZ80Opcodes, EmitSharpOpcodes, EmitEZ80Opcodes, EmitZ80NextOpcodes, EmitExtended80Opcodes, EmitZ80Opcodes, EmitSharpOpcodes, EmitEZ80Opcodes, EmitZ80NextOpcodes, EmitR800Opcodes,
UseIyForStack, UseIxForScratch, UseIyForScratch, UseShadowRegistersForInterrupts) UseIyForStack, UseIxForScratch, UseIyForScratch, UseShadowRegistersForInterrupts)
if (CpuFamily.forType(platform.cpu) != CpuFamily.M6809) invalids ++= Set( if (CpuFamily.forType(platform.cpu) != CpuFamily.M6809) invalids ++= Set(
@ -172,6 +172,11 @@ case class CompilationOptions(platform: Platform,
log.error("Extended 8080-like opcodes enabled for architecture that doesn't support them") log.error("Extended 8080-like opcodes enabled for architecture that doesn't support them")
} }
} }
if (flags(EmitR800Opcodes)) {
if (platform.cpu != R800) {
log.error("R800 opcodes enabled for architecture that doesn't support them")
}
}
if (flags(EmitIntel8080Opcodes)) { if (flags(EmitIntel8080Opcodes)) {
if (!Intel8080Compatible(platform.cpu)) { if (!Intel8080Compatible(platform.cpu)) {
log.error("Intel 8080 opcodes enabled for architecture that doesn't support them") log.error("Intel 8080 opcodes enabled for architecture that doesn't support them")
@ -220,6 +225,7 @@ case class CompilationOptions(platform: Platform,
"OPTIMIZE_IPO" -> toLong(flag(CompilationFlag.InterproceduralOptimization)), "OPTIMIZE_IPO" -> toLong(flag(CompilationFlag.InterproceduralOptimization)),
"CPUFEATURE_DECIMAL_MODE" -> toLong(flag(CompilationFlag.DecimalMode)), "CPUFEATURE_DECIMAL_MODE" -> toLong(flag(CompilationFlag.DecimalMode)),
"CPUFEATURE_Z80" -> toLong(flag(CompilationFlag.EmitZ80Opcodes)), "CPUFEATURE_Z80" -> toLong(flag(CompilationFlag.EmitZ80Opcodes)),
"CPUFEATURE_R800" -> toLong(flag(CompilationFlag.EmitR800Opcodes)),
"CPUFEATURE_EZ80" -> toLong(flag(CompilationFlag.EmitEZ80Opcodes)), "CPUFEATURE_EZ80" -> toLong(flag(CompilationFlag.EmitEZ80Opcodes)),
"CPUFEATURE_8080" -> toLong(flag(CompilationFlag.EmitIntel8080Opcodes)), "CPUFEATURE_8080" -> toLong(flag(CompilationFlag.EmitIntel8080Opcodes)),
"CPUFEATURE_8085" -> toLong(flag(CompilationFlag.EmitIntel8085Opcodes)), "CPUFEATURE_8085" -> toLong(flag(CompilationFlag.EmitIntel8085Opcodes)),
@ -290,7 +296,7 @@ object CpuFamily extends Enumeration {
import Cpu._ import Cpu._
cpu match { cpu match {
case Mos | StrictMos | Ricoh | StrictRicoh | Cmos | SC02 | Rockwell | Wdc | HuC6280 | CE02 | Sixteen => M6502 case Mos | StrictMos | Ricoh | StrictRicoh | Cmos | SC02 | Rockwell | Wdc | HuC6280 | CE02 | Sixteen => M6502
case Intel8080 | Intel8085 | StrictIntel8085 | Sharp | Z80 | StrictZ80 | EZ80 | Z80Next => I80 case Intel8080 | Intel8085 | StrictIntel8085 | Sharp | Z80 | StrictZ80 | R800 | EZ80 | Z80Next => I80
case Intel8086 | Intel80186 => I86 case Intel8086 | Intel80186 => I86
case Cpu.Motorola6809 => M6809 case Cpu.Motorola6809 => M6809
} }
@ -368,6 +374,10 @@ object Cpu extends Enumeration {
* The Zilog Z80 processor, without illegal instructions * The Zilog Z80 processor, without illegal instructions
*/ */
val StrictZ80: Cpu.Value = Value val StrictZ80: Cpu.Value = Value
/**
* The R800 CPU (used in MSX Turbo-R)
*/
val R800: Cpu.Value = Value
/** /**
* The Zilog eZ80 processor * The Zilog eZ80 processor
*/ */
@ -400,11 +410,11 @@ object Cpu extends Enumeration {
/** /**
* Processors that can run code for Zilog Z80 * Processors that can run code for Zilog Z80
*/ */
val Z80Compatible: Set[Cpu.Value] = Set(Z80, StrictZ80, EZ80, Z80Next) val Z80Compatible: Set[Cpu.Value] = Set(Z80, StrictZ80, R800, EZ80, Z80Next)
/** /**
* Processors that can run code for Intel 8080 * Processors that can run code for Intel 8080
*/ */
val Intel8080Compatible: Set[Cpu.Value] = Set(Intel8080, Intel8085, StrictIntel8085, Z80, StrictZ80, EZ80, Z80Next) val Intel8080Compatible: Set[Cpu.Value] = Set(Intel8080, Intel8085, StrictIntel8085, Z80, StrictZ80, R800, EZ80, Z80Next)
/** /**
* Processors that can run code for Intel 8085 * Processors that can run code for Intel 8085
*/ */
@ -468,6 +478,8 @@ object Cpu extends Enumeration {
i80AlwaysDefaultFlags ++ Set(EmitIntel8080Opcodes, EmitIntel8085Opcodes, UseIntelSyntaxForInput, UseIntelSyntaxForOutput) i80AlwaysDefaultFlags ++ Set(EmitIntel8080Opcodes, EmitIntel8085Opcodes, UseIntelSyntaxForInput, UseIntelSyntaxForOutput)
case StrictZ80 | Z80 => case StrictZ80 | Z80 =>
i80AlwaysDefaultFlags ++ Set(EmitIntel8080Opcodes, EmitExtended80Opcodes, EmitZ80Opcodes, UseIxForStack, UseShadowRegistersForInterrupts) i80AlwaysDefaultFlags ++ Set(EmitIntel8080Opcodes, EmitExtended80Opcodes, EmitZ80Opcodes, UseIxForStack, UseShadowRegistersForInterrupts)
case R800 =>
i80AlwaysDefaultFlags ++ Set(EmitIntel8080Opcodes, EmitExtended80Opcodes, EmitZ80Opcodes, UseIxForStack, UseShadowRegistersForInterrupts, EmitR800Opcodes)
case Z80Next => case Z80Next =>
i80AlwaysDefaultFlags ++ Set(EmitIntel8080Opcodes, EmitExtended80Opcodes, EmitZ80Opcodes, UseIxForStack, UseShadowRegistersForInterrupts, EmitIllegals, EmitZ80NextOpcodes) i80AlwaysDefaultFlags ++ Set(EmitIntel8080Opcodes, EmitExtended80Opcodes, EmitZ80Opcodes, UseIxForStack, UseShadowRegistersForInterrupts, EmitIllegals, EmitZ80NextOpcodes)
case EZ80 => case EZ80 =>
@ -514,6 +526,7 @@ object Cpu extends Enumeration {
case "strict2a07" => StrictRicoh case "strict2a07" => StrictRicoh
case "z80" => Z80 case "z80" => Z80
case "strictz80" => Z80 case "strictz80" => Z80
case "r800" => R800
case "zx80next" => Z80Next case "zx80next" => Z80Next
case "z80next" => Z80Next case "z80next" => Z80Next
// disabled for now: // disabled for now:
@ -564,7 +577,7 @@ object CompilationFlag extends Enumeration {
EmitCmosOpcodes, EmitCmosNopOpcodes, EmitSC02Opcodes, EmitRockwellOpcodes, EmitWdcOpcodes, EmitHudsonOpcodes, Emit65CE02Opcodes, EmitEmulation65816Opcodes, EmitNative65816Opcodes, EmitCmosOpcodes, EmitCmosNopOpcodes, EmitSC02Opcodes, EmitRockwellOpcodes, EmitWdcOpcodes, EmitHudsonOpcodes, Emit65CE02Opcodes, EmitEmulation65816Opcodes, EmitNative65816Opcodes,
PreventJmpIndirectBug, LargeCode, ReturnWordsViaAccumulator, SoftwareStack, PreventJmpIndirectBug, LargeCode, ReturnWordsViaAccumulator, SoftwareStack,
// compilation options for I80 // compilation options for I80
EmitIntel8080Opcodes, EmitIntel8085Opcodes, EmitExtended80Opcodes, EmitZ80Opcodes, EmitEZ80Opcodes, EmitSharpOpcodes, EmitZ80NextOpcodes, EmitIntel8080Opcodes, EmitIntel8085Opcodes, EmitExtended80Opcodes, EmitZ80Opcodes, EmitR800Opcodes, EmitEZ80Opcodes, EmitSharpOpcodes, EmitZ80NextOpcodes,
UseShadowRegistersForInterrupts, UseShadowRegistersForInterrupts,
UseIxForStack, UseIyForStack, UseIxForStack, UseIyForStack,
UseIxForScratch, UseIyForScratch, UseIxForScratch, UseIyForScratch,
@ -628,6 +641,7 @@ object CompilationFlag extends Enumeration {
"emit_65ce02" -> Emit65CE02Opcodes, "emit_65ce02" -> Emit65CE02Opcodes,
"emit_huc6280" -> EmitHudsonOpcodes, "emit_huc6280" -> EmitHudsonOpcodes,
"emit_z80" -> EmitZ80Opcodes, "emit_z80" -> EmitZ80Opcodes,
"emit_r800" -> EmitR800Opcodes,
"emit_ez80" -> EmitEZ80Opcodes, "emit_ez80" -> EmitEZ80Opcodes,
"emit_x80" -> EmitExtended80Opcodes, "emit_x80" -> EmitExtended80Opcodes,
"emit_8080" -> EmitIntel8080Opcodes, "emit_8080" -> EmitIntel8080Opcodes,

View File

@ -46,10 +46,24 @@ case class Context(errorReporting: Logger,
if (isFlagSet(CompilationFlag.EmitEZ80Opcodes)) { if (isFlagSet(CompilationFlag.EmitEZ80Opcodes)) {
addons += CompilationFlag.EmitZ80Opcodes -> true addons += CompilationFlag.EmitZ80Opcodes -> true
} }
if (isFlagSet(CompilationFlag.EmitZ80Opcodes) || isFlagSet(CompilationFlag.EmitSharpOpcodes)) { if (isFlagSet(CompilationFlag.EmitZ80NextOpcodes)) {
addons += CompilationFlag.EmitZ80Opcodes -> true
}
if (isFlagSet(CompilationFlag.EmitR800Opcodes)) {
addons += CompilationFlag.EmitZ80Opcodes -> true
}
if (isFlagSet(CompilationFlag.EmitEZ80Opcodes)
|| isFlagSet(CompilationFlag.EmitZ80NextOpcodes)
|| isFlagSet(CompilationFlag.EmitR800Opcodes)
|| isFlagSet(CompilationFlag.EmitZ80Opcodes)
|| isFlagSet(CompilationFlag.EmitSharpOpcodes)) {
addons += CompilationFlag.EmitExtended80Opcodes -> true addons += CompilationFlag.EmitExtended80Opcodes -> true
} }
if (isFlagSet(CompilationFlag.EmitZ80Opcodes) || isFlagSet(CompilationFlag.EmitIntel8085Opcodes)) { if (isFlagSet(CompilationFlag.EmitEZ80Opcodes)
|| isFlagSet(CompilationFlag.EmitZ80NextOpcodes)
|| isFlagSet(CompilationFlag.EmitR800Opcodes)
|| isFlagSet(CompilationFlag.EmitZ80Opcodes)
|| isFlagSet(CompilationFlag.EmitIntel8085Opcodes)) {
addons += CompilationFlag.EmitIntel8080Opcodes -> true addons += CompilationFlag.EmitIntel8080Opcodes -> true
} }
if (isFlagSet(CompilationFlag.OptimizeForSpeed)) { if (isFlagSet(CompilationFlag.OptimizeForSpeed)) {

View File

@ -321,7 +321,9 @@ object Main {
val assemblyOptimizations = optLevel match { val assemblyOptimizations = optLevel match {
case 0 => Nil case 0 => Nil
case _ => case _ =>
if (options.flag(CompilationFlag.EmitZ80Opcodes)) if (options.flag(CompilationFlag.EmitR800Opcodes))
Z80OptimizationPresets.GoodForR800
else if (options.flag(CompilationFlag.EmitZ80Opcodes))
Z80OptimizationPresets.GoodForZ80 Z80OptimizationPresets.GoodForZ80
else if (options.flag(CompilationFlag.EmitIntel8080Opcodes)) else if (options.flag(CompilationFlag.EmitIntel8080Opcodes))
Z80OptimizationPresets.GoodForIntel8080 Z80OptimizationPresets.GoodForIntel8080

View File

@ -1067,6 +1067,17 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
case LHLX | RLDE => r == D || r == E case LHLX | RLDE => r == D || r == E
case RRHL => r == H || r == L case RRHL => r == H || r == L
case MULUB => r == A || (registers match {
case TwoRegisters(p, q) => r == q || r == p
case _ => true
})
case MULUW => r == H || r == L || (registers match {
case TwoRegisters(_, BC) => r == B || r == C
case TwoRegisters(_, DE) => r == D || r == E
case TwoRegisters(_, SP) => r == SP
case _ => true
})
case _ => true // TODO case _ => true // TODO
} }
} }
@ -1230,6 +1241,9 @@ case class ZLine(opcode: ZOpcode.Value, registers: ZRegisters, parameter: Consta
case LHLX | RRHL | DSUB => r == H || r == L case LHLX | RRHL | DSUB => r == H || r == L
case SHLX => false case SHLX => false
case MULUB => r == H || r == L
case MULUW => r == H || r == L || r == D || r == E
case _ => true // TODO case _ => true // TODO
} }
} }

View File

@ -29,6 +29,8 @@ object ZOpcode extends Enumeration {
LD_DESP, LD_DEHL, RRHL, RLDE, DSUB, RSTV, LHLX, SHLX, LD_DESP, LD_DEHL, RRHL, RLDE, DSUB, RSTV, LHLX, SHLX,
//sharp: //sharp:
LD_AHLI, LD_AHLD, LD_HLIA, LD_HLDA, SWAP, LDH_DA, LDH_AD, LDH_CA, LDH_AC, LD_HLSP, ADD_SP, STOP, LD_AHLI, LD_AHLD, LD_HLIA, LD_HLDA, SWAP, LDH_DA, LDH_AD, LDH_CA, LDH_AC, LD_HLSP, ADD_SP, STOP,
// R800:
MULUB, MULUW,
// next: // next:
LDIX, LDWS, LDIRX, LDDX, LDDRX, LDPIRX, OUTINB, MUL, SWAPNIB, MIRROR, NEXTREG, PIXELDN, PIXELAD, SETAE, TEST, 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, DISCARD_A, DISCARD_F, DISCARD_HL, DISCARD_BC, DISCARD_DE, DISCARD_IX, DISCARD_IY, CHANGED_MEM,
@ -55,6 +57,7 @@ object ZOpcodeClasses {
val CbInstructions: Set[ZOpcode.Value] = Set(SLA, SRA, SRL, SLL, RLC, RRC, RL, RR) ++ BIT ++ RES ++ SET val CbInstructions: Set[ZOpcode.Value] = Set(SLA, SRA, SRL, SLL, RLC, RRC, RL, RR) ++ BIT ++ RES ++ SET
val EdInstructions: Set[ZOpcode.Value] = Set(NEG, RETN, RETI, IM, RRD, RLD, val EdInstructions: Set[ZOpcode.Value] = Set(NEG, RETN, RETI, IM, RRD, RLD,
MULUB, MULUW,
INI, INIR, OUTI, OUTIR, IND, INDR, OUTD, OUTDR, INI, INIR, OUTI, OUTIR, IND, INDR, OUTD, OUTDR,
LDI, LDIR, LDD, LDDR, CPI, CPIR, CPD, CPDR) ++ BIT ++ RES ++ SET LDI, LDIR, LDD, LDDR, CPI, CPIR, CPD, CPDR) ++ BIT ++ RES ++ SET
@ -63,6 +66,7 @@ object ZOpcodeClasses {
val ChangesAFAlways: Set[ZOpcode.Value] = Set( // TODO: ! val ChangesAFAlways: Set[ZOpcode.Value] = Set( // TODO: !
DAA, ADD, ADC, SUB, SBC, XOR, OR, AND, INC, DEC, DAA, ADD, ADC, SUB, SBC, XOR, OR, AND, INC, DEC,
SCF, CCF, NEG, RIM, SCF, CCF, NEG, RIM,
MULUB, MULUW,
LDH_AC, LDH_AD, LD_AHLI, LD_AHLD, LDH_AC, LDH_AD, LD_AHLI, LD_AHLD,
ADD_16, ADC_16, SBC_16, INC_16, DEC_16, ADD_16, ADC_16, SBC_16, INC_16, DEC_16,
INI, INIR, OUTI, OUTIR, IND, INDR, OUTD, OUTDR, INI, INIR, OUTI, OUTIR, IND, INDR, OUTD, OUTDR,
@ -74,6 +78,7 @@ object ZOpcodeClasses {
LDIX, LDIRX, LDDX, LDDRX, LDPIRX, LDIX, LDIRX, LDDX, LDDRX, LDPIRX,
EXX, CALL, JR, JP, LABEL, DJNZ) EXX, CALL, JR, JP, LABEL, DJNZ)
val ChangesHLAlways: Set[ZOpcode.Value] = Set( val ChangesHLAlways: Set[ZOpcode.Value] = Set(
MULUB, MULUW,
INI, INIR, OUTI, OUTIR, IND, INDR, OUTD, OUTDR, INI, INIR, OUTI, OUTIR, IND, INDR, OUTD, OUTDR,
LDI, LDIR, LDD, LDDR, CPI, CPIR, CPD, CPDR, LDI, LDIR, LDD, LDDR, CPI, CPIR, CPD, CPDR,
LD_AHLI, LD_AHLD, LD_HLIA, LD_HLDA, LD_HLSP, DSUB, LD_AHLI, LD_AHLD, LD_HLIA, LD_HLDA, LD_HLSP, DSUB,
@ -81,6 +86,7 @@ object ZOpcodeClasses {
LDWS, LDIX, LDIRX, LDDX, LDDRX, LDPIRX, PIXELAD, PIXELDN, OUTINB, LDWS, LDIX, LDIRX, LDDX, LDDRX, LDPIRX, PIXELAD, PIXELDN, OUTINB,
EXX, EX_DE_HL, CALL, JR, JP, LABEL) EXX, EX_DE_HL, CALL, JR, JP, LABEL)
val ChangesDEAlways: Set[ZOpcode.Value] = Set( val ChangesDEAlways: Set[ZOpcode.Value] = Set(
MULUW,
LDI, LDIR, LDD, LDDR, LDI, LDIR, LDD, LDDR,
LD_DESP, LD_DEHL, RLDE, LD_DESP, LD_DEHL, RLDE,
LDWS, LDIX, LDIRX, LDDX, LDDRX, LDPIRX, MUL, LDWS, LDIX, LDIRX, LDDX, LDDRX, LDPIRX, MUL,
@ -88,6 +94,7 @@ object ZOpcodeClasses {
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 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 ChangesFirstRegister: Set[ZOpcode.Value] = Set(LD, LD_16, ADD_16, SBC_16)
val ChangesAAlways: Set[ZOpcode.Value] = Set( val ChangesAAlways: Set[ZOpcode.Value] = Set(
MULUB,
DAA, ADD, ADC, SUB, SBC, XOR, OR, AND, LD_AHLI, LD_AHLD, RIM, DAA, ADD, ADC, SUB, SBC, XOR, OR, AND, LD_AHLI, LD_AHLD, RIM,
MIRROR, SETAE, MIRROR, SETAE,
) )

View File

@ -0,0 +1,24 @@
package millfork.assembly.z80.opt
import millfork.assembly.AssemblyOptimization
import millfork.assembly.z80.ZLine
import millfork.assembly.z80.ZOpcode.MULUB
import millfork.assembly.z80.ZOpcode.MULUW
import millfork.node.ZRegister
/**
* Optimizations valid for R800
* @author Karol Stasiak
*/
object AlwaysGoodR800Optimizations {
val UnusedR800Instructions = new RuleBasedAssemblyOptimization("Simplifiable maths (R800)",
needsFlowInfo = FlowInfoRequirement.BackwardFlow,
(Elidable & HasOpcode(MULUB) & DoesntMatterWhatItDoesWith(ZRegister.H, ZRegister.L) & DoesntMatterWhatItDoesWithFlags) ~~> (_ => Nil),
(Elidable & HasOpcode(MULUW) & DoesntMatterWhatItDoesWith(ZRegister.H, ZRegister.L, ZRegister.D, ZRegister.E) & DoesntMatterWhatItDoesWithFlags) ~~> (_ => Nil),
)
val All: List[AssemblyOptimization[ZLine]] = List[AssemblyOptimization[ZLine]](
UnusedR800Instructions,
)
}

View File

@ -361,6 +361,38 @@ object CoarseFlowAnalyzer {
case ZLine0(RIM, _, _) => case ZLine0(RIM, _, _) =>
currentStatus = currentStatus.copy(a = AnyStatus) currentStatus = currentStatus.copy(a = AnyStatus)
case ZLine0(MULUB, TwoRegisters(ZRegister.A, r@(ZRegister.B | ZRegister.C | ZRegister.D | ZRegister.E)), _) =>
val hl = (currentStatus.a<*>currentStatus.getRegister(r, 0)){(a,b) => (a*b)&0xff}
currentStatus = currentStatus.copy(
h = hl.hi,
l = hl.lo,
hl = hl.map(NumericConstant(_, 2)),
cf = AnyStatus,
nf = AnyStatus,
hf = AnyStatus,
zf = AnyStatus,
sf = AnyStatus,
pf = AnyStatus
)
case ZLine0(MULUW, TwoRegisters(ZRegister.HL, ZRegister.BC), _) =>
val hl = (currentStatus.h<*>currentStatus.l)(currentStatus.mergeBytes)
val bc = (currentStatus.b<*>currentStatus.c)(currentStatus.mergeBytes)
val hi = (hl<*>bc){(a,b) => (a*b).>>(16).&(0xffff)}
val lo = (hl<*>bc){(a,b) => (a*b).&(0xffff)}
currentStatus = currentStatus.copy(
d = hi.hi,
e = hi.lo,
h = lo.hi,
l = lo.lo,
hl = lo.map(NumericConstant(_, 2)),
cf = AnyStatus,
nf = AnyStatus,
hf = AnyStatus,
zf = AnyStatus,
sf = AnyStatus,
pf = AnyStatus
)
case ZLine0(opcode, registers, _) => case ZLine0(opcode, registers, _) =>
currentStatus = currentStatus.copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus) currentStatus = currentStatus.copy(cf = AnyStatus, zf = AnyStatus, sf = AnyStatus, pf = AnyStatus, hf = AnyStatus)
if (ZOpcodeClasses.ChangesAAlways(opcode)) currentStatus = currentStatus.copy(a = AnyStatus) if (ZOpcodeClasses.ChangesAAlways(opcode)) currentStatus = currentStatus.copy(a = AnyStatus)

View File

@ -22,6 +22,21 @@ object Z80OptimizationPresets {
).flatten ).flatten
} }
val GoodForR800: List[AssemblyOptimization[ZLine]] = {
List.fill(5)(
List.fill(5)(
AlwaysGoodI80Optimizations.All ++
AlwaysGoodZ80Optimizations.All ++
AlwaysGoodR800Optimizations.All ++
List(
EmptyParameterStoreRemoval,
EmptyMemoryStoreRemoval)
).flatten ++
List(ChangeRegisterPairPreferringDE, WordVariableToRegisterOptimization, ByteVariableToRegisterOptimization, ChangeRegisterPairPreferringBC, CompactStackFrame) ++
LaterIntel8080Optimizations.All ++ LaterI80Optimizations.All
).flatten
}
val GoodForIntel8080: List[AssemblyOptimization[ZLine]] = { val GoodForIntel8080: List[AssemblyOptimization[ZLine]] = {
List.fill(5)( List.fill(5)(
List.fill(5)( List.fill(5)(

View File

@ -67,6 +67,14 @@ class Z80Assembler(program: Program,
def requireZ80Illegals(): Unit = if (!options.flag(EmitZ80Opcodes) || !options.flag(EmitIllegals)) log.error("Unsupported instruction: " + instr) def requireZ80Illegals(): Unit = if (!options.flag(EmitZ80Opcodes) || !options.flag(EmitIllegals)) log.error("Unsupported instruction: " + instr)
def requireR800(): Unit = if (!options.flag(EmitR800Opcodes)) log.error("Unsupported instruction: " + instr)
def requireNoR800(): Unit = if (options.flag(EmitR800Opcodes)) log.error("Unsupported instruction: " + instr)
def requireR800OrIllegals(): Unit = if (!options.flag(EmitR800Opcodes) && !options.flag(EmitIllegals)) log.error("Unsupported instruction: " + instr)
def requireR800Illegals(): Unit = if (!options.flag(EmitR800Opcodes) || !options.flag(EmitIllegals)) log.error("Unsupported instruction: " + instr)
def requireExtended80(): Unit = if (!options.flag(EmitExtended80Opcodes)) log.error("Unsupported instruction: " + instr) def requireExtended80(): Unit = if (!options.flag(EmitExtended80Opcodes)) log.error("Unsupported instruction: " + instr)
def requireSharp(): Unit = if (!options.flag(EmitSharpOpcodes)) log.error("Unsupported instruction: " + instr) def requireSharp(): Unit = if (!options.flag(EmitSharpOpcodes)) log.error("Unsupported instruction: " + instr)
@ -326,7 +334,7 @@ class Z80Assembler(program: Program,
writeByte(bank, index + 2, instr.parameter) writeByte(bank, index + 2, instr.parameter)
index + 3 index + 3
case ZLine0(op, OneRegister(ix@(IXH | IYH | IXL | IYL)), _) if oneRegister.contains(op) => case ZLine0(op, OneRegister(ix@(IXH | IYH | IXL | IYL)), _) if oneRegister.contains(op) =>
requireZ80Illegals() requireR800OrIllegals()
val o = oneRegister(op) val o = oneRegister(op)
writeByte(bank, index, prefixByte(ix)) writeByte(bank, index, prefixByte(ix))
writeByte(bank, index + 1, o.opcode + internalRegisterIndex(ix) * o.multiplier) writeByte(bank, index + 1, o.opcode + internalRegisterIndex(ix) * o.multiplier)
@ -337,6 +345,7 @@ class Z80Assembler(program: Program,
index + 1 index + 1
case ZLine0(SLL, OneRegister(reg), _) => case ZLine0(SLL, OneRegister(reg), _) =>
requireZ80Illegals() requireZ80Illegals()
requireNoR800()
writeByte(bank, index, 0xcb) writeByte(bank, index, 0xcb)
writeByte(bank, index + 1, 0x30 + internalRegisterIndex(reg)) writeByte(bank, index + 1, 0x30 + internalRegisterIndex(reg))
index + 2 index + 2
@ -347,6 +356,7 @@ class Z80Assembler(program: Program,
index + 2 index + 2
case ZLine0(SLL, OneRegisterOffset(ix@(ZRegister.MEM_IX_D | ZRegister.MEM_IY_D), offset), _) => case ZLine0(SLL, OneRegisterOffset(ix@(ZRegister.MEM_IX_D | ZRegister.MEM_IY_D), offset), _) =>
requireZ80Illegals() requireZ80Illegals()
requireNoR800()
writeByte(bank, index, prefixByte(ix)) writeByte(bank, index, prefixByte(ix))
writeByte(bank, index + 1, 0xcb) writeByte(bank, index + 1, 0xcb)
writeByte(bank, index + 2, offset) writeByte(bank, index + 2, offset)
@ -443,22 +453,22 @@ class Z80Assembler(program: Program,
writeByte(bank, index + 2, offset) writeByte(bank, index + 2, offset)
index + 3 index + 3
case TwoRegisters(target@(IXH | IYH | IXL | IYL), source@(A | B | C | D | E)) => case TwoRegisters(target@(IXH | IYH | IXL | IYL), source@(A | B | C | D | E)) =>
requireZ80Illegals() requireR800OrIllegals()
writeByte(bank, index, prefixByte(target)) writeByte(bank, index, prefixByte(target))
writeByte(bank, index, 0x40 + internalRegisterIndex(source) + internalRegisterIndex(target) * 8) writeByte(bank, index, 0x40 + internalRegisterIndex(source) + internalRegisterIndex(target) * 8)
index + 2 index + 2
case TwoRegisters(target@(A | B | C | D | E), source@(IXH | IYH | IXL | IYL)) => case TwoRegisters(target@(A | B | C | D | E), source@(IXH | IYH | IXL | IYL)) =>
requireZ80Illegals() requireR800OrIllegals()
writeByte(bank, index, prefixByte(source)) writeByte(bank, index, prefixByte(source))
writeByte(bank, index, 0x40 + internalRegisterIndex(source) + internalRegisterIndex(target) * 8) writeByte(bank, index, 0x40 + internalRegisterIndex(source) + internalRegisterIndex(target) * 8)
index + 2 index + 2
case TwoRegisters(target@(IXH | IXL), source@(IXH | IXL)) => case TwoRegisters(target@(IXH | IXL), source@(IXH | IXL)) =>
requireZ80Illegals() requireR800OrIllegals()
writeByte(bank, index, prefixByte(source)) writeByte(bank, index, prefixByte(source))
writeByte(bank, index, 0x40 + internalRegisterIndex(source) + internalRegisterIndex(target) * 8) writeByte(bank, index, 0x40 + internalRegisterIndex(source) + internalRegisterIndex(target) * 8)
index + 2 index + 2
case TwoRegisters(target@(IYH | IYL), source@(IYH | IYL)) => case TwoRegisters(target@(IYH | IYL), source@(IYH | IYL)) =>
requireZ80Illegals() requireR800OrIllegals()
writeByte(bank, index, prefixByte(source)) writeByte(bank, index, prefixByte(source))
writeByte(bank, index, 0x40 + internalRegisterIndex(source) + internalRegisterIndex(target) * 8) writeByte(bank, index, 0x40 + internalRegisterIndex(source) + internalRegisterIndex(target) * 8)
index + 2 index + 2
@ -771,6 +781,61 @@ class Z80Assembler(program: Program,
requireIntel8085Illegals() requireIntel8085Illegals()
writeByte(bank, index, 0x10) writeByte(bank, index, 0x10)
index + 1 index + 1
case ZLine0(MULUB, TwoRegisters(A, A), _) =>
requireR800Illegals()
writeByte(bank, index, 0xED)
writeByte(bank, index + 1, 0xF9)
index + 2
case ZLine0(MULUB, TwoRegisters(A, B), _) =>
requireR800()
writeByte(bank, index, 0xED)
writeByte(bank, index + 1, 0xC1)
index + 2
case ZLine0(MULUB, TwoRegisters(A, C), _) =>
requireR800()
writeByte(bank, index, 0xED)
writeByte(bank, index + 1, 0xC9)
index + 2
case ZLine0(MULUB, TwoRegisters(A, D), _) =>
requireR800()
writeByte(bank, index, 0xED)
writeByte(bank, index + 1, 0xD1)
index + 2
case ZLine0(MULUB, TwoRegisters(A, E), _) =>
requireR800()
writeByte(bank, index, 0xED)
writeByte(bank, index + 1, 0xD9)
index + 2
case ZLine0(MULUB, TwoRegisters(A, H), _) =>
requireR800Illegals()
writeByte(bank, index, 0xED)
writeByte(bank, index + 1, 0xE1)
index + 2
case ZLine0(MULUB, TwoRegisters(A, L), _) =>
requireR800Illegals()
writeByte(bank, index, 0xED)
writeByte(bank, index + 1, 0xE9)
index + 2
case ZLine0(MULUW, TwoRegisters(HL, BC), _) =>
requireR800()
writeByte(bank, index, 0xED)
writeByte(bank, index + 1, 0xC3)
index + 2
case ZLine0(MULUW, TwoRegisters(HL, DE), _) =>
requireR800Illegals()
writeByte(bank, index, 0xED)
writeByte(bank, index + 1, 0xD3)
index + 2
case ZLine0(MULUW, TwoRegisters(HL, HL), _) =>
requireR800Illegals()
writeByte(bank, index, 0xED)
writeByte(bank, index + 1, 0xE3)
index + 2
case ZLine0(MULUW, TwoRegisters(HL, SP), _) =>
requireR800()
writeByte(bank, index, 0xED)
writeByte(bank, index + 1, 0xF3)
index + 2
case _ => case _ =>
log.fatal("Cannot assemble " + instr) log.fatal("Cannot assemble " + instr)
index index

View File

@ -109,7 +109,7 @@ case class Z80Parser(filename: String,
case (VariableExpression(r), false) if toRegister.contains(r)=> (toRegister(r), None) case (VariableExpression(r), false) if toRegister.contains(r)=> (toRegister(r), None)
case (VariableExpression(r), false) case (VariableExpression(r), false)
if options.flag(CompilationFlag.EmitZ80Opcodes) && if options.flag(CompilationFlag.EmitZ80Opcodes) &&
options.flag(CompilationFlag.EmitIllegals) && (options.flag(CompilationFlag.EmitIllegals) || options.flag(CompilationFlag.EmitR800Opcodes)) &&
toIndexHalf.contains(r)=> (toIndexHalf(r), None) toIndexHalf.contains(r)=> (toIndexHalf(r), None)
case (SumExpression(List( case (SumExpression(List(
(false, LiteralExpression(0xff00, _)), (false, LiteralExpression(0xff00, _)),
@ -534,7 +534,7 @@ case class Z80Parser(filename: String,
case "PIXELAD" => imm(PIXELAD) case "PIXELAD" => imm(PIXELAD)
case "SETAE" => imm(SETAE) case "SETAE" => imm(SETAE)
case "MUL" => (("D"|"d") ~ HWS ~ "," ~/ HWS ~ ("E" | "e")).?.map { _ => (MUL, NoRegisters, None, zero)} case "MUL" => (("D"|"d") ~ HWS ~ "," ~/ HWS ~ ("E" | "e")).?.map { _ => (MUL, NoRegisters, None, zero)}
case "MIRROR" => ("A"|"a").?.map { _ => (MUL, NoRegisters, None, zero)} case "MIRROR" => ("A"|"a").?.map { _ => (MIRROR, NoRegisters, None, zero)}
case "NEXTREG" =>(param(allowAbsolute = false) ~ HWS ~ position("comma").map(_ => ()) ~ "," ~/ HWS ~ param(allowAbsolute = false)).map { 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.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 (ZRegister.IMM_8, Some(n), (ZRegister.IMM_8, Some(v))) => (NEXTREG, TwoRegisters(ZRegister.IMM_8, ZRegister.IMM_8), None, SeparateBytesExpression(v, n))
@ -544,6 +544,19 @@ case class Z80Parser(filename: String,
} }
case "TEST" => one8Register(TEST) case "TEST" => one8Register(TEST)
case "MULUB" => (param(allowAbsolute = false) ~ HWS ~ "," ~/ HWS ~ param(allowAbsolute = false)).map {
case (ZRegister.A, None, (r, None)) => (MULUB, TwoRegisters(ZRegister.A, r), None, zero)
case _ =>
log.error("Invalid parameters for MULUB", Some(pos))
(NOP, NoRegisters, None, zero)
}
case "MULUW" => (param(allowAbsolute = false) ~ HWS ~ "," ~/ HWS ~ param(allowAbsolute = false)).map {
case (ZRegister.HL, None, (r, None)) => (MULUW, TwoRegisters(ZRegister.HL, r), None, zero)
case _ =>
log.error("Invalid parameters for MULUW", Some(pos))
(NOP, NoRegisters, None, zero)
}
case _ => case _ =>
log.error("Unsupported opcode " + opcode, Some(pos)) log.error("Unsupported opcode " + opcode, Some(pos))
imm(NOP) imm(NOP)

View File

@ -193,7 +193,7 @@ class ByteMathSuite extends FunSuite with Matchers with AppendedClues {
} }
test("Byte multiplication 2") { test("Byte multiplication 2") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Motorola6809)( EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.R800, Cpu.Motorola6809)(
""" """
| import zp_reg | import zp_reg
| byte output1 @$c001, output2 @$c002, output3 @$c003 | byte output1 @$c001, output2 @$c002, output3 @$c003

View File

@ -249,6 +249,7 @@ class StructSuite extends FunSuite with Matchers {
| p->tmp[1] = 77 | p->tmp[1] = 77
| outputAlias[0].tmp[id(3)] = 3 | outputAlias[0].tmp[id(3)] = 3
| outputAlias[id(0)].tmp[5] = 55 | outputAlias[id(0)].tmp[5] = 55
| output.tmp[6] = lo(output.tmp - output.addr)
|} |}
|""".stripMargin |""".stripMargin
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8086, Cpu.Motorola6809)(code){ m => EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8086, Cpu.Motorola6809)(code){ m =>
@ -257,6 +258,7 @@ class StructSuite extends FunSuite with Matchers {
m.readByte(0xc003) should equal(3) m.readByte(0xc003) should equal(3)
m.readByte(0xc004) should equal(4) m.readByte(0xc004) should equal(4)
m.readByte(0xc005) should equal(55) m.readByte(0xc005) should equal(55)
m.readByte(0xc006) should equal(0)
} }
} }

View File

@ -1,7 +1,7 @@
package millfork.test package millfork.test
import millfork.Cpu import millfork.Cpu
import millfork.test.emu.{EmuUnoptimizedCrossPlatformRun, EmuUnoptimizedIntel8080Run, EmuUnoptimizedIntel8085Run, EmuUnoptimizedSharpRun, EmuUnoptimizedZ80NextRun, EmuUnoptimizedZ80Run} import millfork.test.emu.{EmuUnoptimizedCrossPlatformRun, EmuUnoptimizedIntel8080Run, EmuUnoptimizedIntel8085Run, EmuUnoptimizedR800Run, EmuUnoptimizedSharpRun, EmuUnoptimizedZ80NextRun, EmuUnoptimizedZ80Run}
import org.scalatest.{FunSuite, Matchers} import org.scalatest.{FunSuite, Matchers}
/** /**
@ -1340,4 +1340,42 @@ class Z80AssemblySuite extends FunSuite with Matchers {
""".stripMargin) """.stripMargin)
} }
test("R800 stuff") {
EmuUnoptimizedR800Run(
"""
| #pragma zilog_syntax
| asm void main () {
| ret
| mulub a,b
| mulub a,c
| mulub a,d
| mulub a,e
| muluw hl,bc
| muluw hl,sp
| inc ixh
| inc ixl
| inc iyh
| inc iyl
| dec ixh
| dec ixl
| dec iyh
| dec iyl
| ld a,ixh
| ld a,ixl
| ld iyh,a
| ld iyl,a
| add a,iyl
| adc a,iyl
| sub iyl
| sbc a,iyl
| or iyl
| xor iyl
| and iyl
| cp iyl
| ld ixh,0
| ret
| }
""".stripMargin)
}
} }

View File

@ -106,6 +106,31 @@ object EmuSharpBenchmarkRun {
} }
} }
object EmuR800BenchmarkRun {
def apply(source: String)(verifier: MemoryBank => Unit): Unit = {
val (Timings(t0, _), m0) = EmuUnoptimizedR800Run.apply2(source)
val (Timings(t1, _), m1) = EmuOptimizedR800Run.apply2(source)
val (Timings(t2, _), m2) = EmuOptimizedInlinedR800Run.apply2(source)
if (t0 > 0)println(f"Before optimization: $t0%7d")
if (t1 > 0)println(f"After optimization: $t1%7d")
if (t2 > 0)println(f"After inlining: $t2%7d")
if (t0 > 0 && t1 > 0) println(f"Gain: ${(100L * (t0 - t1) / t0.toDouble).round}%7d%%")
if (t0 > 0 && t2 > 0) println(f"Gain with inlining: ${(100L * (t0 - t2) / t0.toDouble).round}%7d%%")
if (t0 > 0) {
println(f"Running R800 unoptimized")
verifier(m0)
}
if (t1 > 0) {
println(f"Running R800 optimized")
verifier(m1)
}
if (t2 > 0) {
println(f"Running R800 optimized inlined")
verifier(m2)
}
}
}
object EmuIntel8086BenchmarkRun { object EmuIntel8086BenchmarkRun {
def apply(source: String)(verifier: MemoryBank => Unit): Unit = { def apply(source: String)(verifier: MemoryBank => Unit): Unit = {
val (Timings(t0, _), m0) = EmuUnoptimizedIntel8086Run.apply2(source) val (Timings(t0, _), m0) = EmuUnoptimizedIntel8086Run.apply2(source)
@ -170,6 +195,9 @@ object EmuCrossPlatformBenchmarkRun {
if (Settings.enableIntel8080Tests && platforms.contains(millfork.Cpu.Intel8080)) { if (Settings.enableIntel8080Tests && platforms.contains(millfork.Cpu.Intel8080)) {
EmuIntel8080BenchmarkRun.apply(source)(verifier) EmuIntel8080BenchmarkRun.apply(source)(verifier)
} }
if (Settings.enableZ80Tests && platforms.contains(millfork.Cpu.R800)) {
EmuR800BenchmarkRun.apply(source)(verifier)
}
if (Settings.enableUnemulatedTests && platforms.contains(millfork.Cpu.Intel8085)) { if (Settings.enableUnemulatedTests && platforms.contains(millfork.Cpu.Intel8085)) {
EmuUnoptimizedIntel8085Run.apply(source) EmuUnoptimizedIntel8085Run.apply(source)
} }

View File

@ -50,6 +50,10 @@ object EmuOptimizedInlinedSharpRun extends EmuZ80Run(Cpu.Sharp, OptimizationPres
override def inline: Boolean = true override def inline: Boolean = true
} }
object EmuOptimizedInlinedR800Run extends EmuZ80Run(Cpu.R800, OptimizationPresets.NodeOpt, Z80OptimizationPresets.GoodForR800) {
override def inline: Boolean = true
}
object EmuOptimizedInlinedM6809Run extends EmuM6809Run(Cpu.Motorola6809, OptimizationPresets.NodeOpt, M6809OptimizationPresets.Default) { object EmuOptimizedInlinedM6809Run extends EmuM6809Run(Cpu.Motorola6809, OptimizationPresets.NodeOpt, M6809OptimizationPresets.Default) {
override def inline: Boolean = true override def inline: Boolean = true
} }

View File

@ -95,4 +95,6 @@ object EmuSizeOptimizedIntel8080Run extends EmuZ80Run(Cpu.Intel8080, Optimizatio
object EmuOptimizedSharpRun extends EmuZ80Run(Cpu.Sharp, OptimizationPresets.NodeOpt, Z80OptimizationPresets.GoodForSharp) object EmuOptimizedSharpRun extends EmuZ80Run(Cpu.Sharp, OptimizationPresets.NodeOpt, Z80OptimizationPresets.GoodForSharp)
object EmuOptimizedR800Run extends EmuZ80Run(Cpu.R800, OptimizationPresets.NodeOpt, Z80OptimizationPresets.GoodForR800)
object EmuOptimizedM6809Run extends EmuM6809Run(Cpu.Motorola6809, OptimizationPresets.NodeOpt, M6809OptimizationPresets.Default) object EmuOptimizedM6809Run extends EmuM6809Run(Cpu.Motorola6809, OptimizationPresets.NodeOpt, M6809OptimizationPresets.Default)

View File

@ -28,6 +28,8 @@ object EmuUnoptimizedIntel8085Run extends EmuZ80Run(Cpu.Intel8085, Nil, Nil)
object EmuUnoptimizedZ80NextRun extends EmuZ80Run(Cpu.Z80Next, Nil, Nil) object EmuUnoptimizedZ80NextRun extends EmuZ80Run(Cpu.Z80Next, Nil, Nil)
object EmuUnoptimizedR800Run extends EmuZ80Run(Cpu.R800, Nil, Nil)
object EmuUnoptimizedIntel8086Run extends EmuI86Run(Nil, Nil) object EmuUnoptimizedIntel8086Run extends EmuI86Run(Nil, Nil)
object EmuUnoptimizedSharpRun extends EmuZ80Run(Cpu.Sharp, Nil, Nil) object EmuUnoptimizedSharpRun extends EmuZ80Run(Cpu.Sharp, Nil, Nil)

View File

@ -30,6 +30,8 @@ import scala.collection.mutable
*/ */
object EmuZ80Run { object EmuZ80Run {
val secondBytesOfMulOnR800: Set[Int] = Set(0xf9, 0xc1, 0xc9, 0xd1, 0xf9, 0xe1, 0xe9, 0xc3, 0xd3, 0xe3, 0xf3)
private def preload(cpu: millfork.Cpu.Value, filename: String): Option[Program] = { private def preload(cpu: millfork.Cpu.Value, filename: String): Option[Program] = {
TestErrorReporting.log.info(s"Loading $filename for $cpu") TestErrorReporting.log.info(s"Loading $filename for $cpu")
val source = Files.readAllLines(Paths.get(filename), StandardCharsets.US_ASCII).asScala.mkString("\n") val source = Files.readAllLines(Paths.get(filename), StandardCharsets.US_ASCII).asScala.mkString("\n")
@ -87,6 +89,7 @@ class EmuZ80Run(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimizatio
CompilationFlag.SubroutineExtraction -> optimizeForSize, CompilationFlag.SubroutineExtraction -> optimizeForSize,
CompilationFlag.EmitIllegals -> (cpu == millfork.Cpu.Z80 || cpu == millfork.Cpu.Intel8085 || cpu == millfork.Cpu.Z80Next), CompilationFlag.EmitIllegals -> (cpu == millfork.Cpu.Z80 || cpu == millfork.Cpu.Intel8085 || cpu == millfork.Cpu.Z80Next),
CompilationFlag.EmitZ80NextOpcodes -> (cpu == millfork.Cpu.Z80Next), CompilationFlag.EmitZ80NextOpcodes -> (cpu == millfork.Cpu.Z80Next),
CompilationFlag.EmitR800Opcodes -> (cpu == millfork.Cpu.R800),
CompilationFlag.LenientTextEncoding -> true) CompilationFlag.LenientTextEncoding -> true)
if (source.contains("intel_syntax")) { if (source.contains("intel_syntax")) {
extraFlags += CompilationFlag.UseIntelSyntaxForOutput -> true extraFlags += CompilationFlag.UseIntelSyntaxForOutput -> true
@ -199,26 +202,35 @@ class EmuZ80Run(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimizatio
method method
} }
val timings = platform.cpu match { val timings = platform.cpu match {
case millfork.Cpu.Z80 | millfork.Cpu.Intel8080 => case millfork.Cpu.Z80 | millfork.Cpu.Intel8080 | millfork.Cpu.R800 =>
val cpu = new Z80Core(Z80Memory(memoryBank), DummyIO) val hasMultiplications = (platform.cpu == millfork.Cpu.R800) && ((0x200 to 0xfffe).exists { addr =>
cpu.reset() val b0 = memoryBank.output(addr)
cpu.setProgramCounter(0x1ed) val b1 = memoryBank.output(addr + 1)
cpu.resetTStates() b0.&(0xff) == 0xED && EmuZ80Run.secondBytesOfMulOnR800(b1.&(0xff))
while (!cpu.getHalt) { })
cpu.executeOneInstruction() if (hasMultiplications) {
if (resetN) { Timings(-1, -1) -> memoryBank
resetNMethod.invoke(cpu) } else {
val cpu = new Z80Core(Z80Memory(memoryBank), DummyIO)
cpu.reset()
cpu.setProgramCounter(0x1ed)
cpu.resetTStates()
while (!cpu.getHalt) {
cpu.executeOneInstruction()
if (resetN) {
resetNMethod.invoke(cpu)
}
if (cpu.getSP.&(0xffff) < 0xd002) {
log.debug("stack dump:")
(0xD000 until 0xD0FF).map(memoryBank.output).grouped(16).map(_.map(i => f"$i%02x").mkString(" ")).foreach(log.debug(_))
throw new IllegalStateException("stack overflow")
}
// dump(cpu)
cpu.getTStates should be < TooManyCycles
} }
if (cpu.getSP.&(0xffff) < 0xd002) { val tStates = cpu.getTStates
log.debug("stack dump:") Timings(tStates, tStates) -> memoryBank
(0xD000 until 0xD0FF).map(memoryBank.output).grouped(16).map(_.map(i => f"$i%02x").mkString(" ")).foreach(log.debug(_))
throw new IllegalStateException("stack overflow")
}
// dump(cpu)
cpu.getTStates should be < TooManyCycles
} }
val tStates = cpu.getTStates
Timings(tStates, tStates) -> memoryBank
case millfork.Cpu.Sharp => case millfork.Cpu.Sharp =>
var ticks = 0L var ticks = 0L
val cpu = GameboyStubs(memoryBank).cpu val cpu = GameboyStubs(memoryBank).cpu