Board index » delphi » How to generate 486-Code?

How to generate 486-Code?

Hello everybody!

I want to ask: In order to gain speed out of the fast architecture of 486
and Pentium CPU, the compilation of Pascal code needs to produce machine
code using the 32-bit machine commands. But which interpreter supports 486-
code or maybe 386-code and with wich compilation swicht can it be activated?

Joerg.

 

Re:How to generate 486-Code?


Quote
jo...@hp1.ang-physik.uni-kiel.de (Joerg Kunze) writes:
>Hello everybody!
>I want to ask: In order to gain speed out of the fast architecture of 486
>and Pentium CPU, the compilation of Pascal code needs to produce machine
>code using the 32-bit machine commands. But which interpreter supports 486-
>code or maybe 386-code and with wich compilation swicht can it be activated?

If you want fast code, forget about Borland Pascal. At least until they launch the 32 bit version of Delphi - it should be better they say.

If you need speed, get the Stony Brook Pascal compiler. It is TP 6
compatible. Don't know if they are still in business, though??

Quote
>Joerg.

--
   Niels Ull Jacobsen, Dep. of CS, U of Copenhagen (n...@diku.dk)
   Roenne Alle 3 st.th, 2860 Soeborg, Denmark, tel. +45 39 66 39 86

Re:How to generate 486-Code?


In article <3u0ngi$...@odin.diku.dk>, Niels Ull Jacobsen <n...@diku.dk> wrote:

Quote
>jo...@hp1.ang-physik.uni-kiel.de (Joerg Kunze) writes:

>>Hello everybody!

>>I want to ask: In order to gain speed out of the fast architecture of 486
>>and Pentium CPU, the compilation of Pascal code needs to produce machine
>>code using the 32-bit machine commands. But which interpreter supports 486-
>>code or maybe 386-code and with wich compilation swicht can it be activated?

There are two ways to do it.  One is to actually put in the opcodes
for instructions, the other is to compile the code into an obj file with TASM
and declare external procedures.  

The first way:

All 386 registers (eax, ebx, ecx, edx, ebp, esi, edi, etc) have a size prefix
66h.  For example:

xor eax,eax  
would become:
db 66h; xor ax,ax

mov eax,12345678h
would be:
db 66h; mov ax,5678h; dw 1234h  {due to little endian memory storage}

rep movsd    
would become:
db 66h; rep movsw

Using segment overrides are done the same way.  FS is 64h and GS is 65h

mov ax,fs:[bx]
would become:
db 64h; mov ax,[bx]

mov eax,gs:[bx]
would become:
db 65h; db 66h; mov ax,[bx]

Other opcodes are a little harder.  For example, something like btr ax,5
would have to be completely opcodes since there is nothing similar on the
286.  

The second way:

blah.asm:

.386
.model tpascal
.data
 MR struc
   x dw ?
   y dw ?
   pntr dd ?
 MR ends
 EXTRN MyArray[256]:Dword
 EXTRN MyWord:word
 EXTRN MyByte:byte
 EXTRN MyRecord:MR
 ThisIsALocalVariable dw ?
.code

MyProc proc near
       public MyProc
       push    ds
       mov     bx,MyWord   ; Load pointer MyArray[10]
       shl     bx,2        ; A pointer is a dword...
       lds     si,dword ptr MyArray[bx]  ; ds:[si] equivilant to MyArray[10]^
       pop     ds
       ret                 ; Don't forget this!!!!!!
endp MyProc

CODE ENDS
     END

test.pas:

program test;
var MyArray:array[1..256] of pointer;
    MyWord:word;
    MyByte:byte;
    MyRecord:record
              x,y:word;
              pntr:pointer;
             end;

procedure MyProc; external;
{$L blah}

begin
 MyWord:=10;
 Myproc;  {This really won't do much, but is just an example}
end.

Quote
>If you want fast code, forget about Borland Pascal. At least until they launch
>the 32 bit version of Delphi - it should be better they say.

>If you need speed, get the Stony Brook Pascal compiler. It is TP 6
>compatible. Don't know if they are still in business, though??

Ugh.  I've used Stony Brook Pascal and I wasn't impressed.  The optimizaions
were minimal and in some cases anti-productive for the pentium.  It was also
about 80% TP6 compatible.

Quote
>>Joerg.

--TCA of NewOrder
newor...@carina.unm.edu

Re:How to generate 486-Code?


NewOrder Demo Group (newor...@unm.edu) wrote:
: In article <3u0ngi$...@odin.diku.dk>, Niels Ull Jacobsen <n...@diku.dk> wrote:
: >jo...@hp1.ang-physik.uni-kiel.de (Joerg Kunze) writes:
: >
: >>Hello everybody!
: >
: >>I want to ask: In order to gain speed out of the fast architecture of 486
: >>and Pentium CPU, the compilation of Pascal code needs to produce machine
: >>code using the 32-bit machine commands. But which interpreter supports 486-
: >>code or maybe 386-code and with wich compilation swicht can it be activated?

: There are two ways to do it.  One is to actually put in the opcodes
: for instructions, the other is to compile the code into an obj file with TASM
: and declare external procedures.  

: The first way:

: All 386 registers (eax, ebx, ecx, edx, ebp, esi, edi, etc) have a size prefix
: 66h.  For example:

: xor eax,eax  
: would become:
: db 66h; xor ax,ax

: mov eax,12345678h
: would be:
: db 66h; mov ax,5678h; dw 1234h  {due to little endian memory storage}

: rep movsd    
: would become:
: db 66h; rep movsw

: Using segment overrides are done the same way.  FS is 64h and GS is 65h

: mov ax,fs:[bx]
: would become:
: db 64h; mov ax,[bx]

: mov eax,gs:[bx]
: would become:
: db 65h; db 66h; mov ax,[bx]

: Other opcodes are a little harder.  For example, something like btr ax,5
: would have to be completely opcodes since there is nothing similar on the
: 286.  

: The second way:

: blah.asm:

: .386
: .model tpascal
: .data
:  MR struc
:    x dw ?
:    y dw ?
:    pntr dd ?
:  MR ends
:  EXTRN MyArray[256]:Dword
:  EXTRN MyWord:word
:  EXTRN MyByte:byte
:  EXTRN MyRecord:MR
:  ThisIsALocalVariable dw ?
: .code

: MyProc proc near
:        public MyProc
:        push    ds
:        mov     bx,MyWord   ; Load pointer MyArray[10]
:        shl     bx,2        ; A pointer is a dword...
:        lds     si,dword ptr MyArray[bx]  ; ds:[si] equivilant to MyArray[10]^
:        pop     ds
:        ret                 ; Don't forget this!!!!!!
: endp MyProc

: CODE ENDS
:      END

: test.pas:

: program test;
: var MyArray:array[1..256] of pointer;
:     MyWord:word;
:     MyByte:byte;
:     MyRecord:record
:               x,y:word;
:               pntr:pointer;
:              end;

: procedure MyProc; external;
: {$L blah}

: begin
:  MyWord:=10;
:  Myproc;  {This really won't do much, but is just an example}
: end.

: >If you want fast code, forget about Borland Pascal. At least until they launch
: >the 32 bit version of Delphi - it should be better they say.
: >
: >If you need speed, get the Stony Brook Pascal compiler. It is TP 6
: >compatible. Don't know if they are still in business, though??

: Ugh.  I've used Stony Brook Pascal and I wasn't impressed.  The optimizaions
: were minimal and in some cases anti-productive for the pentium.  It was also
: about 80% TP6 compatible.

: >>Joerg.

: --TCA of NewOrder
: newor...@carina.unm.edu

Well, so far, so good, but you still have yet another pitfall:

How about declaring indirect references by using 32 bit registers?!?

The trick is this: You first insert the address size prefix everywhere into your
code where you need 32 bit addresses. However, be warned! References like
mov reg,[BX+SI+offset16], etc. then do NOT translate into expressions like
mov reg,[EBX+ESI+offset32]! This is because now you may use any general-purpose
register in an indirect memory reference (including offsets and scaling)!
Here's the general layout of an instruction on an i386 or higher:

operand size prefix     - optional
address size prefix     - optional (required for 32 bit addresses)
segment override        - optional
repeat prefix           - optional
LOCK prefix             - optional
opcode                  
MODRM field             - needed by some instructions
SIB field               - needed by some instructions
displacement            - needed by some instructions
immediate value         - needed by some instructions

First of all, to determine what operands you have you must take a look on the
opcode and MODRM fields.
The opcode usually contains two bits indicating operation direction and operand
size. Bit 0 determines whether you are using 16/32 bit operands or not (if it's
clear you have 8 bit operands). Bit 1 determines the destination of the instruc-
tion. When it's cleared the destination always is operand 2, otherwise it's
operand 1.
The following examinations are for address mode = 32 bits
The MODRM field reveals what operands you are actually using.

Fig. 1: Layout of MODRM

Bit        ! 7 6 ! 5 4 3 ! 2 1 0
-----------+-----+-------+-------
Contents   ! mod ! reg   ! r/m

mod contains the operand mode, i.e.
mod = 00b: Indirect reference, no displacement
mod = 01b: Indirect reference, 8 bit displacement
mod = 10b: Indirect reference, 32 bit displacement
mod = 11b: Register-to-register operation

reg contains the register you are using, i.e.
           - 32 bit operands     - 8 bit operands
reg = 000b:     EAX                     AL
reg = 001b:     ECX                     CL
reg = 010b:     EDX                     DL
reg = 011b:     EBX                     BL
reg = 100b:     ESP                     AH
reg = 101b:     EBP                     CH
reg = 110b:     ESI                     DH
reg = 111b:     EDI                     BH

r/m contains the actual memory reference (providing mod <> 11b), i.e.
r/m = 000b: [EAX]
r/m = 001b: [ECX]
r/m = 010b: [EDX]
r/m = 011b: [EBX]
r/m = 100b: determined by SIB byte
r/m = 101b: [offs32] for mod = 00b     [EBP] for mod <> 00b
r/m = 110b: [ESI]
r/m = 111b: [EDI]
Note that for mod = 11b the r/m field merely yields another register, but no
memory operand.

Finally, the SIB field (if present) decodes to

Fig. 2: Layout of SIB

Bit        ! 7 6 ! 5 4 3 ! 2 1 0
-----------+-----+-------+-------
Contents   !scale! index ! base

The bit combinations for scale mean the following:
scale = 00b: 1
scale = 01b: 2
scale = 10b: 4
scale = 11b: 8

The index field decodes as:
index = 000b:     EAX                    
index = 001b:     ECX                    
index = 010b:     EDX                    
index = 011b:     EBX                    
index = 100b:     invalid combination                  
index = 101b:     EBP                    
index = 110b:     ESI                    
index = 111b:     EDI                    

The base field decodes as:index = 000b:     EAX                    
base = 001b:     ECX                    
base = 010b:     EDX                    
base = 011b:     EBX                    
base = 100b:     ESP                    
base = 101b:     no base present                    
base = 110b:     ESI                    
base = 111b:     EDI                    

When you use bit combination 100b for the index field you may get indeterminate
results!

However, all this information can be obtained in the book
"Processor and Coprocessor" by Roert H. Hummel.
It is a book by PC Magazine and covers the arcitecture and programming, etc. for
all Intel processors from the 8086 up to the i486 (or maybe already the Pentium).
If you need further information, jst get you that book!

Olaf
o.mart...@rz.tu-bs.de

Other Threads