1
0
mirror of https://github.com/KarolS/millfork.git synced 2026-04-20 18:16:35 +00:00

Add 8080-to-8086 translation

This commit is contained in:
Karol Stasiak
2019-05-31 17:03:35 +02:00
parent b4a6c261de
commit 1cb3b672b1
71 changed files with 1422 additions and 291 deletions
+42
View File
@@ -76,3 +76,45 @@ and the most significant word is passed via the DE register pair
* callee may clobber all registers except for IX, IY and shadow registers
## 8086
The Intel 8086 calling conventions is based on the Intel 8080 calling convention,
plus it uses the BP register in the same role as the IX register of Z80.
#### Parameters:
* if the function has one parameter of size one byte, it is passed via the AL register
* if the function has one parameter of size two bytes, it is passed via the BX register
* if the function has one parameter of size three bytes,
its least significant two bytes are passed via the BX register
and the most significant byte is passed via the DL register
* if the function has one parameter of size four bytes,
its least significant word is passed via the BX register
and the most significant word is passed via the DX register
* otherwise, all parameters are passed via static locations
#### Return values:
* one-byte return values are passed via the AL register
* two-byte return values are passed via the BX register
* in case of three-byte return values,
its least significant two bytes are passed via the BX register
and the most significant byte is passed via the DL register
* in case of four-byte return values,
its least significant word is passed via the BX register
and the most significant word is passed via the DX register
* otherwise, the return value is passed via a static location
#### Register preservation:
* callee may clobber all flags
* callee may clobber all registers except for BP
+4
View File
@@ -69,3 +69,7 @@ AHX, LAS, LXA, SHX, SHY, TAS, XAA.
Original Z80 processors accidentally supported a bunch of extra undocumented instructions.
Millfork will not emit them.
The only exception is SLL, which will be emitted if it occurs in a handwritten assembly block.
## 8086
Undocumented instructions are not supported.
+3
View File
@@ -63,6 +63,9 @@ this makes stack-allocated variables independent from other stack operations
and allows for optimizing them by inlining them into registers
(this can be disabled, so the 8080 method is used, or switched to use IY instead)
* on 8086, the BP register is used as the base pointer, behaving similarly to the IX register on Z80
(this can be disabled, so the 8080 method is used, with the target address register being BX instead of HL)
## Automatic variables
Automatic variables have lifetime starting with the beginning of the function they're in
+3
View File
@@ -32,6 +32,9 @@ if a line ends with a backslash character, the value continues to the next line.
* `i8080` (Intel 8080; experimental, buggy and very incomplete)
* `gameboy` (Sharp LR35902; experimental, buggy and very incomplete)
* `i8086` (Intel 8086; very experimental, very buggy and very, very incomplete
see the [8086 support disclaimer](../lang/x86disclaimer.md))
* `encoding` default encoding for console I/O, one of
`ascii`, `pet`/`petscii`, `petscr`/`cbmscr`, `atascii`, `bbc`, `jis`/`jisx`, `apple2`,
+2
View File
@@ -87,6 +87,8 @@ The compiler emits COM files.
* `cpm_z80` CP/M on Z80
* `dos_com` a COM file for DOS on IBM PC. (very experimental)
The primary and most tested platform is Commodore 64.
Currently, targets that assume that the program will be loaded from disk or tape are better tested.
+4 -1
View File
@@ -18,7 +18,7 @@ The goal of Millfork is to succeed where Atalan failed.
Large programs in Millfork have been developed for Commodore 64.
Millfork was also tested (via emulators) to run trivial programs on other 8-bit Commodore computers,
Atari 8-bit computers, Apple II, BBC Micro, ZX Spectrum 48k, NEC PC-88, CP/M, NES, Game Boy and Atari 2600.
Atari 8-bit computers, Apple II, BBC Micro, ZX Spectrum 48k, NEC PC-88, CP/M, NES, Game Boy, Atari 2600 and MS-DOS.
Support for other devices using supported processors can be easily added, usually without even modifying the compiler.
@@ -28,6 +28,9 @@ Support for other devices using supported processors can be easily added, usuall
* Intel 8080, 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.
### Why Millfork when I can use assembly?
* Assembly will not be portable. If you want to target both 6502 and Z80, you'd have to maintain two separate codebases.
+2 -1
View File
@@ -16,7 +16,8 @@ Syntax:
* `asm` the function is written in assembly, not in Millfork (obligatory for `extern` functions),
see [Using 6502 assembly within Millfork programs#Assembly functions](./assembly.md#assembly-functions)
or [Using 8080/LR35902/Z80 assembly within Millfork programs#Assembly functions](./assemblyz80.md#assembly-functions)
or [Using 8080/LR35902/Z80 assembly within Millfork programs#Assembly functions](./assemblyz80.md#assembly-functions);
for 8086, see the [8086 support disclaimer](./x86disclaimer.md).
* `macro` the function is a macro,
see [Macros_and inlining#Macros](../abi/inlining.md#macros)
+4
View File
@@ -38,6 +38,8 @@ The following features are defined based on the chosen CPU and compilation optio
* `ARCH_I80` 1 if compiling for Intel 8080-like processor, 0 otherwise
* `ARCH_X86` 1 if compiling for Intel 8086-like processor, 0 otherwise
* `CPU_65C02`, `CPU_65CE02`, `CPU_65816`, `CPU_HUC6280`, `CPU_8080`, `CPU_GAMEBOY`, `CPU_Z80`
1 if compiling for the exact given processor, 0 otherwise
@@ -86,6 +88,8 @@ The following features are defined based on the chosen CPU and compilation optio
* `CPM` 1 if the target is CP/M, 0 otherwise
* `IBM_PC` 1 if the target is IBM PC, 0 otherwise
* `NTSC` 1 if the target is NTSC, 0 otherwise
* `PAL` 1 if the target is PAL, 0 otherwise
+1 -1
View File
@@ -324,4 +324,4 @@ continue <variable>
See [Using 6502 assembly within Millfork programs](./assembly.md)
or [Using 8080/LR35902/Z80 assembly within Millfork programs](./assemblyz80.md).
**Work in progress**: For 8086, see the [8086 support disclaimer](./x86disclaimer.md).
+78
View File
@@ -0,0 +1,78 @@
[< back to index](../index.md)
# 8086 support disclaimer
Millfork does not support Intel 8086 directly.
Instead, it generates Intel 8080 code and translates it automatically to 8086 machine code.
For convenience, Z80 instructions using `IX` are also translated.
This means that:
* code is going to be large and slow;
* there is no support for writing 8086 assembly;
* Millfork currently translates majority of Intel 8080 assembly instructions to 8086 machine code,
so you can write 8080/Z80 assembly instead.
For example, code like
asm {
LD HL, x
LD BC, i
ADD HL, BC
JP C, skip
LD A, IX(5)
LD (HL), A
skip:
}
is compiled to
MOV BX, x
MOV CX, i
ADD BX, CX
JNC .next
JMP skip
.next:
MOV AL, BYTE PTR [BP+5]
MOV BYTE PTR [BX], AL
skip:
Generated assembly output uses Intel 8086 syntax.
#### Major deficiencies of generated code
* hardware multiplication is not used
* many 16-bit operations are not used
* many operations are restricted to the `AL` register
* the overflow flag is not used
* `DAS` is not used
* conditional jumps are never optimized to short 2-byte jumps and always use 5 bytes
* the `SI` register is reloaded before every use
* the converter translates the `DAD` instruction (16-bit `ADD` on Z80) to `ADD`,
which may change behaviour of assembly code,
as 8080's `DAD` changes only the carry flag, and 8086's `ADD` changes many flags.
Luckily, this is not an issue with Millfork code, as the optimizer does not assume anything about flags after that instruction.
The proper sequence is `LAHF`/`ADD r1,r2`/`RCR SI,1`/`SAHF`/`RCL SI,1`, but it is obviously too slow.
#### Register mapping
The registers are translated as following:
A → AL
B → CH C → CL BC → CX
D → DH E → DL DE → DX
H → BH L → BL HL → BX
SP → SP
IX → BP
The `SI` register is used as a temporary register for holding the address in `LDAX`/`STAX`
(`LD (DE),A`/`LD(BC),A`/`LD A,(DE)`/`LD A,(BC)` on Z80).