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:
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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`,
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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).
|
||||
|
||||
@@ -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).
|
||||
Reference in New Issue
Block a user