14

Do you perhaps happen to know, what would be the easiest way to modify my AEC-to-x86 compiler (you can run the core of it in browser: https://flatassembler.github.io/compiler ) to be able to target i486? Right now, I think it targets i486, except relying on the fcomip instruction which exists only on i686 and newer. At first I thought I might replace fcomip with something like:

fsubp
fist dword [result]
cmp dword [result],0

But the problem with that is that I'd also need to replace every ja with jg and every jb with jl, which, given the way the compiler is structured, is not a simple task (I'm afraid it's too error-prone). Do you have a better idea? Is there a way to push FPU flags (ones affected by fcomp) and pop them into CPU flags that would work on both i486 and 64-bit x86 processors?

4
  • Related: Why do x86 FP compares set CF like unsigned integers, instead of using signed conditions? on Stack Overflow explains what fcomi (PPro) was replacing (fstsw ax + sahf), and that SSE2 ucomisd also sets FLAGS that way. (And that fstsw ax was new in 286; 8086 needed to store to memory and reload.) See also ray.masmcode.com/tutorial/fpuchap7.htm for a very good guide to x87 instructions with examples. Jan 8 at 3:09
  • Also, in general for 486 code sequences, you can look at compiler output from gcc -m32 -march=i486 on godbolt.org (see How to remove "noise" from GCC/clang assembly output?). Anything GCC emits with -march=i486 will also work on 64-bit CPUs in 32-bit compat mode. Jan 8 at 16:41
  • @PeterCordes I don't understand, how could I possibly use GCC to answer that question? The question is which sequence of instructions on i486 is equal to fcomip. May 26 at 15:11
  • 1
    You know that fcomip does an FP compare, right? So it's the same question as how to do FP compares on CPUs earlier than P6, without fcomi[p]. Thus, GCC asm output for something like return x > 1.0; will have to do that using earlier instructions: godbolt.org/z/KW4PM3osY - GCC13 -Os uses the standards fnswsw / sahf / jp / jne for an == compare, but -O3 just uses bitwise ops on AH instead of SAHF, so that's fun, only needing one branch for predicates that would normally need a jp to rule out unordered. May 26 at 15:18

1 Answer 1

19

This is actually documented in present-day Intel manuals. See the Intel 64 and IA-32 Architectures Software Developer’s Manual, volume 1, section 8.1.4, "Branching and Conditional Moves on Condition Codes", and use the "old mechanism" described there. The short answer is that you do

    fcomp
    fnstsw ax
    sahf
    jb less

noting that ax is clobbered.

Remember that up through the 386 (*), the FPU could be on a physically separate chip, which executed mostly independently of the CPU. So it wasn't trivial to have a floating-point instruction manipulate the regular CPU flags or registers. On the 286 and later, there was a special path between the two to support fnstsw ax, copying the status word into ax; see How is FSTSW AX implemented on the 80286/80287?. Since they had set up the bits of the status word to match the flags bits, you could then use sahf (which I believe originally existed for porting 8080 programs) to copy the relevant bits into flags, then do a normal conditional branch.

The 8086/8087 didn't have this path, and everything had to go via memory. So instead of fnstsw ax / sahf / jb less, you had to use a temporary variable in memory, and do fnstsw [tmp] / mov ax, [tmp] / sahf / jb less.

(*) I am not sure about the 486; the 486DX had the FPU built in, and if you wanted to add a math coprocessor to a 486SX, you could buy a 487 which was really just a 486DX. However, I seem to recall that there were some non-Intel 486 equivalents that had no FPU but could add a separate 387 coprocessor.

1
  • 10
    There are the Cyrix 486SLC and 486DLC processor and IBMs different 486SLC processor (later, IBM switched to the Cyrix design). Those processors have a 486-compatible integer core and a on-chip memory cache (although the original Cyrix SLC had just 1KB). But those processors use the 386SX or 386DX bus protocol. Whether they are "486 equivalent" or not depends on your point of view. From a mainboard's point of view, they were high-performance 386 processors, from a software point of view, they were low-performance 486 processors. Jan 6 at 17:16

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .