~ubuntu-branches/ubuntu/intrepid/mit-scheme/intrepid-updates

« back to all changes in this revision

Viewing changes to src/microcode/cmpintmd/i386.h

  • Committer: Bazaar Package Importer
  • Author(s): Chris Hanson
  • Date: 2002-03-14 17:04:07 UTC
  • Revision ID: james.westby@ubuntu.com-20020314170407-m5lg1d6bdsl9lv0s
Tags: upstream-7.7.0
ImportĀ upstreamĀ versionĀ 7.7.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*-C-*-
 
2
 
 
3
$Id: i386.h,v 1.35 2002/02/03 03:38:55 cph Exp $
 
4
 
 
5
Copyright (c) 1992-2002 Massachusetts Institute of Technology
 
6
 
 
7
This program is free software; you can redistribute it and/or modify
 
8
it under the terms of the GNU General Public License as published by
 
9
the Free Software Foundation; either version 2 of the License, or (at
 
10
your option) any later version.
 
11
 
 
12
This program is distributed in the hope that it will be useful, but
 
13
WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15
General Public License for more details.
 
16
 
 
17
You should have received a copy of the GNU General Public License
 
18
along with this program; if not, write to the Free Software
 
19
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
 
20
USA.
 
21
*/
 
22
 
 
23
/*
 
24
 *
 
25
 * Compiled code interface macros.
 
26
 *
 
27
 * See cmpint.txt for a description of these fields.
 
28
 *
 
29
 * Specialized for the Intel 386 (and successors) architecture.
 
30
 */
 
31
 
 
32
#ifndef SCM_CMPINTMD_H
 
33
#define SCM_CMPINTMD_H
 
34
 
 
35
#include "cmptype.h"
 
36
 
 
37
/* Until cmpaux-i386.m4 is updated. */
 
38
#define CMPINT_USE_STRUCS
 
39
 
 
40
/* Hack for OS/2 calling-convention type: */
 
41
 
 
42
#if defined(__OS2__) && (defined(__IBMC__) || defined(__WATCOMC__))
 
43
#  define ASM_ENTRY_POINT(name) (_System name)
 
44
#else
 
45
#  if defined(__WIN32__) && defined(__WATCOMC__)
 
46
#    define ASM_ENTRY_POINT(name) (__cdecl name)
 
47
#  else
 
48
#    define ASM_ENTRY_POINT(name) name
 
49
#  endif
 
50
#endif
 
51
 
 
52
extern void EXFUN (ia32_cache_synchronize, (void));
 
53
extern int ia32_cpuid_needed;
 
54
 
 
55
#define IA32_CACHE_SYNCHRONIZE()                                        \
 
56
{                                                                       \
 
57
  if (ia32_cpuid_needed)                                                \
 
58
    ia32_cache_synchronize ();                                          \
 
59
}
 
60
 
 
61
/*
 
62
 
 
63
        Problems with i386 ISA (instruction set architecture)
 
64
 
 
65
<1> Code space is separate from data space.  The only way to obtain a
 
66
code space address is to do a CALL and use the return address on the
 
67
stack.
 
68
 
 
69
Problem: References to the constants vector in compiled code.
 
70
 
 
71
Fix: Just as on RISC machines.  Use CALL when necessary, and cache the
 
72
result in the assembly language.
 
73
 
 
74
 
 
75
<2> Jumps are PC-relative.  There are absolute jumps, assuming the PC
 
76
is in a data location, or with immediate destinations that include a
 
77
segment descriptor (16 bits).  The short forms have a PC-relative
 
78
offset defined with respect to the immediately following instruction.
 
79
 
 
80
Problem: Closures and execute caches need their address in old space
 
81
in order to be relocated correctly.
 
82
 
 
83
Fix: 
 
84
 
 
85
  For execute caches we can define a new linker field, called
 
86
load-relocation-address which on every GC/relocation stores the new
 
87
address and the old contents into global variables and stores the new
 
88
address in the field.  Alternatively the difference between the new
 
89
address and the old contents can be stored into a single global
 
90
variable, and this can be used, together with the new address of each
 
91
cache, to find the old code.
 
92
 
 
93
  For closures the code that reads the header (manifest closure) can
 
94
do the same.
 
95
 
 
96
 
 
97
<3> The stack pointer register (ESP) cannot be used as the base in
 
98
(base + displacement) addressing mode.
 
99
 
 
100
Problem: Common operation in the compiler, which assumes direct access
 
101
to the stack.
 
102
 
 
103
Fix: Use base + indexed mode, which allows specification of ESP as
 
104
base and nullification of the index (by using ESP again).
 
105
This is one byte longer than otherwise, but...
 
106
 
 
107
        Register assignments
 
108
 
 
109
EAX (0)         Unassigned
 
110
ECX (1)         Unassigned
 
111
EDX (2)         Unassigned
 
112
EBX (3)         Unassigned
 
113
 
 
114
ESP (4)         Stack Pointer
 
115
EBP (5)         Register Mask
 
116
ESI (6)         Pointer to register block, etc.
 
117
EDI (7)         Free Pointer
 
118
 
 
119
The dynamic link and value "registers" are not processor registers.
 
120
Slots in the register array must be reserved for them.
 
121
 
 
122
The Free Pointer is EDI because EDI is the implicit base register for
 
123
the memory-to-memory move instructions, and the string store
 
124
instruction.  Perhaps we can make use of it.
 
125
 
 
126
The pointer to register block is not held in EBP (the processor's
 
127
"frame" register is typically used) because its most common use, (EBP)
 
128
(address syllable for memory memtop) takes more bytes than (ESI).
 
129
 
 
130
        Encodings and layout of various control features:
 
131
 
 
132
Assumptions:
 
133
 
 
134
  The processor will be in 32-bit address and operand mode.
 
135
Thus instructions use 32-bit operands, and displacements for
 
136
addressing modes and jump instructions are all 32-bits by default.
 
137
 
 
138
        Offset          Contents                Encoding
 
139
 
 
140
 
 
141
- Execute cache entry encoding:
 
142
 
 
143
                Before linking
 
144
 
 
145
        0               16-bit arity    \
 
146
        2               0x00              [TC_FIXNUM | arity]
 
147
entry   3               0x1A            /
 
148
        4               Symbol
 
149
        8               <next cache>
 
150
 
 
151
                After linking
 
152
 
 
153
        0               16-bit arity
 
154
        2               0x00
 
155
entry   3               JMP opcode              0x39
 
156
        4               32-bit offset
 
157
        8               <next cache>
 
158
 
 
159
Arity stays in place because the i386 is a little-endian architecture.
 
160
 
 
161
 
 
162
- Closure entry encoding:
 
163
 
 
164
entry   0               CALL opcode             0xE8
 
165
        1               32-bit offset
 
166
        5               <padding>               0x00
 
167
        6               <next entry or variables>
 
168
 
 
169
 
 
170
- Trampoline encoding:
 
171
 
 
172
entry   0               MOV     AL,code         0xB0, code-byte
 
173
        2               CALL    n(ESI)          0xFF 0x96 n-longword
 
174
        8               <trampoline dependent storage>
 
175
 
 
176
 
 
177
- GC & interrupt check at procedure/continuation entry:
 
178
 
 
179
gc_lab  -7              CALL    n(ESI)          0xFF 0x56 n-byte
 
180
        -4              <type/arity info>
 
181
        -2              <gc offset>
 
182
entry   0               CMP     EDI,(ESI)       0x39 0x3e
 
183
        2               JAE     gc_lab          0x73 -11
 
184
        4               <real code>
 
185
 
 
186
 
 
187
- GC & interrupt check at closure entry:
 
188
 
 
189
gc_lab  -11             ADD     (ESP),&offset   0x83 0x04 0x24 offset-byte
 
190
        -7              JMP     n(ESI)          0xFF 0x66 n-byte
 
191
        -4              <type/arity info>
 
192
        -2              <gc offset>
 
193
entry   0               ADD     (ESP),&magic    0x81 0x04 0x24 magic-longword
 
194
        7               CMP     EDI,(ESI)       0x39 0x3e
 
195
        9               JAE     gc_lab          0x73 0xea (= -22)
 
196
        11              <real code>
 
197
 
 
198
The magic value depends on the closure because of canonicalization.
 
199
 
 
200
The ADD instruction at offset -11 is not present for the 0th closure
 
201
entry, since it is the canonical entry point.  Its format depends on
 
202
the value of offset, since the sign-extending forms often suffice.
 
203
 
 
204
offset = entry_number * entry_size
 
205
magic = ([TC_COMPILED_ENTRY | 0] - (offset + length_of_CALL_instruction))
 
206
 
 
207
*/
 
208
 
 
209
#define COMPILER_PROCESSOR_TYPE                 COMPILER_IA32_TYPE
 
210
 
 
211
/* The i387 coprocessor and i486 use 80-bit extended format internally. */
 
212
 
 
213
#define COMPILER_TEMP_SIZE                      3
 
214
 
 
215
typedef unsigned short format_word;
 
216
 
 
217
/* i386 instructions can be aligned on any byte boundary. */
 
218
 
 
219
#define PC_ZERO_BITS                            0
 
220
 
 
221
/* See the encodings above. */
 
222
 
 
223
#define ENTRY_PREFIX_LENGTH                     3
 
224
 
 
225
#  define COMPILED_CLOSURE_ENTRY_SIZE                                   \
 
226
  ((2 * (sizeof (format_word))) + 6)
 
227
 
 
228
#  define ADJUST_CLOSURE_AT_CALL(entry_point, location)                 \
 
229
do {                                                                    \
 
230
  long magic_constant;                                                  \
 
231
                                                                        \
 
232
  magic_constant = (* ((long *) (((char *) (entry_point)) + 3)));       \
 
233
  (location) = ((SCHEME_OBJECT)                                         \
 
234
                ((((long) (OBJECT_ADDRESS (location))) + 5) +           \
 
235
                 magic_constant));                                      \
 
236
} while (0)
 
237
 
 
238
/* For the relocation of PC-relative JMP and CALL instructions.
 
239
   This is used during GC/relocation, when the displacement
 
240
   is incorrect, since it was computed with respect to the
 
241
   location in old space.
 
242
 */
 
243
 
 
244
extern long i386_pc_displacement_relocation;
 
245
 
 
246
#define EXTRACT_ADDRESS_FROM_DISPLACEMENT(var, instr_addr) do           \
 
247
{                                                                       \
 
248
  long displacement_address, new_displacement;                          \
 
249
                                                                        \
 
250
  displacement_address = (((long) (instr_addr)) + 1);                   \
 
251
  new_displacement = ((* ((long *) displacement_address))               \
 
252
                      + i386_pc_displacement_relocation);               \
 
253
  (* ((long *) displacement_address)) = new_displacement;               \
 
254
  (var) = ((SCHEME_OBJECT)                                              \
 
255
           ((ADDR_TO_SCHEME_ADDR (displacement_address + 4))            \
 
256
            + new_displacement));                                       \
 
257
} while (0)
 
258
 
 
259
#define STORE_DISPLACEMENT_FROM_ADDRESS(target, instr_address) do       \
 
260
{                                                                       \
 
261
  long displacement_address = (((long) (instr_address)) + 1);           \
 
262
  (* ((long *) displacement_address)) =                                 \
 
263
    (((long) (target))                                                  \
 
264
     - (ADDR_TO_SCHEME_ADDR (displacement_address + 4)));               \
 
265
} while (0)
 
266
 
 
267
#define BCH_EXTRACT_ADDRESS_FROM_DISPLACEMENT(var, v_addr, p_addr) do   \
 
268
{                                                                       \
 
269
  long displacement_address, new_displacement;                          \
 
270
                                                                        \
 
271
  displacement_address = (((long) (p_addr)) + 1);                       \
 
272
  new_displacement = ((* ((long *) displacement_address))               \
 
273
                      + i386_pc_displacement_relocation);               \
 
274
  (* ((long *) displacement_address)) = new_displacement;               \
 
275
  (var) = ((SCHEME_OBJECT)                                              \
 
276
           ((ADDR_TO_SCHEME_ADDR (((long) (v_addr)) + 5))               \
 
277
            + new_displacement));                                       \
 
278
} while (0)
 
279
 
 
280
#define BCH_STORE_DISPLACEMENT_FROM_ADDRESS(target, v_addr, p_addr) do  \
 
281
{                                                                       \
 
282
  long displacement_address = (((long) (p_addr)) + 1);                  \
 
283
  (* ((long *) displacement_address))                                   \
 
284
    = (((long) (target))                                                \
 
285
       - (ADDR_TO_SCHEME_ADDR (((long) (v_addr)) + 5)));                \
 
286
} while (0)
 
287
 
 
288
#define START_CLOSURE_RELOCATION(scan) do                               \
 
289
{                                                                       \
 
290
  SCHEME_OBJECT * _block, * _old;                                       \
 
291
  char * _new;                                                          \
 
292
                                                                        \
 
293
  _block = ((SCHEME_OBJECT *) (scan));                                  \
 
294
  _old = (OBJECT_ADDRESS (_block[(OBJECT_DATUM (*_block))]));           \
 
295
  _new = ((char *) (FIRST_MANIFEST_CLOSURE_ENTRY (_block + 1)));        \
 
296
                                                                        \
 
297
  i386_pc_displacement_relocation = (((long) _old) - ((long) _new));    \
 
298
} while (0)
 
299
 
 
300
#define END_CLOSURE_RELOCATION(scan)    i386_pc_displacement_relocation = 0
 
301
#define EXTRACT_CLOSURE_ENTRY_ADDRESS   EXTRACT_ADDRESS_FROM_DISPLACEMENT
 
302
#define STORE_CLOSURE_ENTRY_ADDRESS     STORE_DISPLACEMENT_FROM_ADDRESS
 
303
 
 
304
#define BCH_START_CLOSURE_RELOCATION(scan) do                           \
 
305
{                                                                       \
 
306
  SCHEME_OBJECT * _scan, * _block, _old_obj, * _old;                    \
 
307
  char * _new;                                                          \
 
308
                                                                        \
 
309
  _scan = ((SCHEME_OBJECT *) (scan));                                   \
 
310
  _block = ((SCHEME_OBJECT *)                                           \
 
311
            (SCAN_POINTER_TO_NEWSPACE_ADDRESS (_scan)));                \
 
312
  READ_NEWSPACE_ADDRESS (_old_obj,                                      \
 
313
                         (_block + (OBJECT_DATUM (* _scan))));          \
 
314
  _old = (OBJECT_ADDRESS (_old_obj));                                   \
 
315
  _new = ((char *) (FIRST_MANIFEST_CLOSURE_ENTRY (_scan + 1)));         \
 
316
                                                                        \
 
317
  i386_pc_displacement_relocation                                       \
 
318
    = (((long) _old)                                                    \
 
319
       - ((long) (SCAN_POINTER_TO_NEWSPACE_ADDRESS (_new))));           \
 
320
} while (0)
 
321
 
 
322
#define BCH_END_CLOSURE_RELOCATION      END_CLOSURE_RELOCATION
 
323
 
 
324
#define BCH_EXTRACT_CLOSURE_ENTRY_ADDRESS(var, p_addr) do               \
 
325
{                                                                       \
 
326
  SCHEME_OBJECT * _p_addr, * _v_addr;                                   \
 
327
                                                                        \
 
328
  _p_addr = ((SCHEME_OBJECT *) (p_addr));                               \
 
329
  _v_addr = ((SCHEME_OBJECT *)                                          \
 
330
             (SCAN_POINTER_TO_NEWSPACE_ADDRESS (_p_addr)));             \
 
331
                                                                        \
 
332
  BCH_EXTRACT_ADDRESS_FROM_DISPLACEMENT (var, _v_addr, _p_addr);        \
 
333
} while (0)
 
334
 
 
335
#define BCH_STORE_CLOSURE_ENTRY_ADDRESS(target, p_addr) do              \
 
336
{                                                                       \
 
337
  SCHEME_OBJECT * _p_addr, * _v_addr;                                   \
 
338
                                                                        \
 
339
  _p_addr = ((SCHEME_OBJECT *) (p_addr));                               \
 
340
  _v_addr = ((SCHEME_OBJECT *)                                          \
 
341
             (SCAN_POINTER_TO_NEWSPACE_ADDRESS (_p_addr)));             \
 
342
                                                                        \
 
343
  BCH_STORE_DISPLACEMENT_FROM_ADDRESS (target, _v_addr, _p_addr);       \
 
344
} while (0)
 
345
 
 
346
#define EXECUTE_CACHE_ENTRY_SIZE                2
 
347
 
 
348
#define FIRST_OPERATOR_LINKAGE_OFFSET           2
 
349
 
 
350
#define EXTRACT_EXECUTE_CACHE_ARITY(target, address) do                 \
 
351
{                                                                       \
 
352
  (target) = ((long) (* ((unsigned short *) (address))));               \
 
353
} while (0)
 
354
 
 
355
#define EXTRACT_EXECUTE_CACHE_SYMBOL(target, address) do                \
 
356
{                                                                       \
 
357
  (target) = (* (((SCHEME_OBJECT *) (address)) + 1));                   \
 
358
} while (0)
 
359
 
 
360
/* This is used during GC/relocation.
 
361
   The displacement stored in the instruction refers to the old space
 
362
   location.
 
363
 */   
 
364
 
 
365
#define EXTRACT_OPERATOR_LINKAGE_ADDRESS(target, address) do            \
 
366
{                                                                       \
 
367
  EXTRACT_ADDRESS_FROM_DISPLACEMENT (target,                            \
 
368
                                     (((long) (address)) + 3));         \
 
369
} while (0)
 
370
 
 
371
/* This is used when not relocating.
 
372
   The displacement refers to the current location of the instruction.
 
373
 */
 
374
 
 
375
#define EXTRACT_EXECUTE_CACHE_ADDRESS(loc, cache_addr) do               \
 
376
{                                                                       \
 
377
  long displacement_address, displacement;                              \
 
378
                                                                        \
 
379
  displacement_address = (((long) (cache_addr)) + 4);                   \
 
380
  displacement = (* ((long *) displacement_address));                   \
 
381
  (loc) = ((SCHEME_OBJECT)                                              \
 
382
           ((displacement_address + 4) + displacement));                \
 
383
} while (0)
 
384
 
 
385
#define STORE_EXECUTE_CACHE_ADDRESS(address, entry_address) do          \
 
386
{                                                                       \
 
387
  STORE_DISPLACEMENT_FROM_ADDRESS (entry_address,                       \
 
388
                                   (((long) (address)) + 3));           \
 
389
} while (0)
 
390
 
 
391
#define STORE_EXECUTE_CACHE_CODE(address) do                            \
 
392
{                                                                       \
 
393
  /* Store a <JMP rel32> opcode. */                                     \
 
394
  (* (((unsigned char *) (address)) + 3)) = 0xe9;                       \
 
395
} while (0)
 
396
 
 
397
#define START_OPERATOR_RELOCATION(scan) do                              \
 
398
{                                                                       \
 
399
  SCHEME_OBJECT * _scan, * _old, _loc;                                  \
 
400
                                                                        \
 
401
  _scan = (((SCHEME_OBJECT *) (scan)) + 1);                             \
 
402
  _old = ((SCHEME_OBJECT *) (* _scan));                                 \
 
403
  _loc = (ADDR_TO_SCHEME_ADDR (_scan));                                 \
 
404
                                                                        \
 
405
  (* _scan) = _loc;                                                     \
 
406
  i386_pc_displacement_relocation = (((long) _old) - ((long) _loc));    \
 
407
} while (0)
 
408
 
 
409
#define END_OPERATOR_RELOCATION(scan)   i386_pc_displacement_relocation = 0
 
410
 
 
411
#define BCH_START_OPERATOR_RELOCATION(scan) do                          \
 
412
{                                                                       \
 
413
  SCHEME_OBJECT * _scan, * _old, _loc;                                  \
 
414
                                                                        \
 
415
  _scan = (((SCHEME_OBJECT *) (scan)) + 1);                             \
 
416
  _old = ((SCHEME_OBJECT *) (* _scan));                                 \
 
417
  _loc = (ADDR_TO_SCHEME_ADDR                                           \
 
418
          (SCAN_POINTER_TO_NEWSPACE_ADDRESS (_scan)));                  \
 
419
                                                                        \
 
420
  * _scan = _loc;                                                       \
 
421
  i386_pc_displacement_relocation = (((long) _old) - ((long) _loc));    \
 
422
} while (0)
 
423
 
 
424
#define BCH_END_OPERATOR_RELOCATION             END_OPERATOR_RELOCATION
 
425
 
 
426
#define BCH_EXTRACT_OPERATOR_LINKAGE_ADDRESS(var, p_addr) do            \
 
427
{                                                                       \
 
428
  SCHEME_OBJECT * _p_addr, * _v_addr;                                   \
 
429
                                                                        \
 
430
  _p_addr = ((SCHEME_OBJECT *) (((long) (p_addr)) + 3));                \
 
431
  _v_addr = ((SCHEME_OBJECT *)                                          \
 
432
             (SCAN_POINTER_TO_NEWSPACE_ADDRESS (_p_addr)));             \
 
433
                                                                        \
 
434
  BCH_EXTRACT_ADDRESS_FROM_DISPLACEMENT (var, _v_addr, _p_addr);        \
 
435
} while (0)
 
436
 
 
437
#define BCH_STORE_OPERATOR_LINKAGE_ADDRESS(e_addr, p_addr) do           \
 
438
{                                                                       \
 
439
  SCHEME_OBJECT * _p_addr, * _v_addr;                                   \
 
440
                                                                        \
 
441
  _p_addr = ((SCHEME_OBJECT *) (((long) (p_addr)) + 3));                \
 
442
  _v_addr = ((SCHEME_OBJECT *)                                          \
 
443
             (SCAN_POINTER_TO_NEWSPACE_ADDRESS (_p_addr)));             \
 
444
                                                                        \
 
445
  BCH_STORE_DISPLACEMENT_FROM_ADDRESS (e_addr, _v_addr, _p_addr);       \
 
446
} while (0)
 
447
 
 
448
#define TRAMPOLINE_ENTRY_SIZE                   3
 
449
#define TRAMPOLINE_BLOCK_TO_ENTRY               3 /* MNV to MOV instr. */
 
450
 
 
451
#define STORE_TRAMPOLINE_ENTRY(entry_address, index) do                 \
 
452
{                                                                       \
 
453
  unsigned char *PC = ((unsigned char *) (entry_address));              \
 
454
                                                                        \
 
455
  *PC++ = 0xb0;                         /* MOV  AL,byte */              \
 
456
  *PC++ = ((unsigned char) (index));    /* byte value */                \
 
457
  *PC++ = 0xff;                         /* CALL */                      \
 
458
  *PC++ = 0x96;                         /* /2 disp32(ESI) */            \
 
459
  (* ((unsigned long *) PC)) = ESI_TRAMPOLINE_TO_INTERFACE_OFFSET;      \
 
460
  IA32_CACHE_SYNCHRONIZE ();                                            \
 
461
} while (0)
 
462
 
 
463
#define TRAMPOLINE_ENTRY_POINT(tramp_block)                             \
 
464
  (((SCHEME_OBJECT *) (tramp_block)) + TRAMPOLINE_BLOCK_TO_ENTRY)
 
465
 
 
466
#define TRAMPOLINE_STORAGE(tramp_entry)                                 \
 
467
  ((((SCHEME_OBJECT *) (tramp_entry)) - TRAMPOLINE_BLOCK_TO_ENTRY) +    \
 
468
   (2 + TRAMPOLINE_ENTRY_SIZE)) 
 
469
 
 
470
#define FLUSH_I_CACHE() do                                              \
 
471
{                                                                       \
 
472
  IA32_CACHE_SYNCHRONIZE ();                                            \
 
473
} while (0)
 
474
 
 
475
#define FLUSH_I_CACHE_REGION(address, nwords) do                        \
 
476
{                                                                       \
 
477
  IA32_CACHE_SYNCHRONIZE ();                                            \
 
478
} while (0)
 
479
 
 
480
#define PUSH_D_CACHE_REGION(address, nwords) do                         \
 
481
{                                                                       \
 
482
  IA32_CACHE_SYNCHRONIZE ();                                            \
 
483
} while (0)
 
484
 
 
485
 
 
486
/* These must aggree with cmpaux-i386.m4!
 
487
   The register block is actually allocated there.
 
488
 */
 
489
 
 
490
#define COMPILER_REGBLOCK_N_FIXED               16
 
491
 
 
492
#define COMPILER_REGBLOCK_N_HOOKS               80
 
493
 
 
494
        /* A hook is the address (offset) of an assembly-language routine. */
 
495
 
 
496
#define COMPILER_HOOK_SIZE                      1
 
497
 
 
498
#define COMPILER_REGBLOCK_EXTRA_SIZE                                    \
 
499
  (COMPILER_REGBLOCK_N_HOOKS * COMPILER_HOOK_SIZE)
 
500
 
 
501
#define REGBLOCK_ALLOCATED_BY_INTERFACE
 
502
 
 
503
#define ESI_TRAMPOLINE_TO_INTERFACE_OFFSET                              \
 
504
  ((COMPILER_REGBLOCK_N_FIXED + (2 * COMPILER_HOOK_SIZE)) *             \
 
505
   (sizeof (SCHEME_OBJECT)))
 
506
 
 
507
#ifdef IN_CMPINT_C
 
508
 
 
509
#ifdef _MACH_UNIX
 
510
#  include <mach.h>
 
511
#  define VM_PROT_SCHEME (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE)
 
512
#endif
 
513
 
 
514
long i386_pc_displacement_relocation = 0;
 
515
 
 
516
#define ASM_RESET_HOOK i386_reset_hook
 
517
 
 
518
#ifndef HOOK_TO_SCHEME_OFFSET
 
519
#  define HOOK_TO_SCHEME_OFFSET(hook) ((unsigned long) (hook))
 
520
#endif
 
521
 
 
522
#ifdef HAVE_STDC
 
523
#  define STRINGIFY(x) #x
 
524
#else
 
525
#  define STRINGIFY(x) "x"
 
526
#endif
 
527
 
 
528
#define SETUP_REGISTER(hook) do                                         \
 
529
{                                                                       \
 
530
  extern void hook ();                                                  \
 
531
                                                                        \
 
532
  (* ((unsigned long *) (esi_value + offset))) =                        \
 
533
    (HOOK_TO_SCHEME_OFFSET (hook));                                     \
 
534
  offset += (COMPILER_HOOK_SIZE * (sizeof (SCHEME_OBJECT)));            \
 
535
  declare_builtin (((unsigned long) hook), (STRINGIFY (hook)));         \
 
536
} while (0)
 
537
 
 
538
void
 
539
DEFUN_VOID (i386_reset_hook)
 
540
{
 
541
  extern int EXFUN (ASM_ENTRY_POINT(i386_interface_initialize), (void));
 
542
  extern void EXFUN (declare_builtin, (unsigned long, char *));
 
543
  int offset = (COMPILER_REGBLOCK_N_FIXED * (sizeof (SCHEME_OBJECT)));
 
544
  unsigned char * esi_value = ((unsigned char *) (&Registers[0]));
 
545
  int fp_support_present = (i386_interface_initialize ());
 
546
 
 
547
  /* These must match machines/i386/lapgen.scm */
 
548
 
 
549
  SETUP_REGISTER (asm_scheme_to_interface);             /* 0 */
 
550
  SETUP_REGISTER (asm_scheme_to_interface_call);        /* 1 */
 
551
 
 
552
  if (offset != ESI_TRAMPOLINE_TO_INTERFACE_OFFSET)
 
553
  {
 
554
    outf_fatal ("\ni386_reset_hook: ESI_TRAMPOLINE_TO_INTERFACE_OFFSET\n");
 
555
    Microcode_Termination (TERM_EXIT);
 
556
  }
 
557
  SETUP_REGISTER (asm_trampoline_to_interface);         /* 2 */
 
558
 
 
559
  SETUP_REGISTER (asm_interrupt_procedure);             /* 3 */
 
560
  SETUP_REGISTER (asm_interrupt_continuation);          /* 4 */
 
561
  SETUP_REGISTER (asm_interrupt_closure);               /* 5 */
 
562
  SETUP_REGISTER (asm_interrupt_dlink);                 /* 6 */
 
563
 
 
564
  SETUP_REGISTER (asm_primitive_apply);                 /* 7 */
 
565
  SETUP_REGISTER (asm_primitive_lexpr_apply);           /* 8 */
 
566
  SETUP_REGISTER (asm_assignment_trap);                 /* 9 */
 
567
  SETUP_REGISTER (asm_reference_trap);                  /* 10 */
 
568
  SETUP_REGISTER (asm_safe_reference_trap);             /* 11 */
 
569
  SETUP_REGISTER (asm_link);                            /* 12 */
 
570
  SETUP_REGISTER (asm_error);                           /* 13 */
 
571
  SETUP_REGISTER (asm_primitive_error);                 /* 14 */
 
572
  SETUP_REGISTER (asm_short_primitive_apply);           /* 15 */
 
573
 
 
574
  /* No more room for positive offsets without going to 32-bit
 
575
     offsets!
 
576
   */
 
577
 
 
578
  /* This is a hack to make all the hooks be addressable
 
579
     with byte offsets (instead of longword offsets).
 
580
     The register block extends to negative offsets as well,
 
581
     so all the following hooks are accessed with negative
 
582
     offsets, and all fit in a byte.
 
583
   */
 
584
 
 
585
  offset    = -128;
 
586
 
 
587
  if (fp_support_present != 0)
 
588
  {
 
589
    SETUP_REGISTER (asm_generic_add);                   /* -32 */
 
590
    SETUP_REGISTER (asm_generic_subtract);              /* -31 */
 
591
    SETUP_REGISTER (asm_generic_multiply);              /* -30 */
 
592
    SETUP_REGISTER (asm_generic_divide);                /* -29 */
 
593
    SETUP_REGISTER (asm_generic_equal);                 /* -28 */
 
594
    SETUP_REGISTER (asm_generic_less);                  /* -27 */
 
595
    SETUP_REGISTER (asm_generic_greater);               /* -26 */
 
596
    SETUP_REGISTER (asm_generic_increment);             /* -25 */
 
597
    SETUP_REGISTER (asm_generic_decrement);             /* -24 */
 
598
    SETUP_REGISTER (asm_generic_zero);                  /* -23 */
 
599
    SETUP_REGISTER (asm_generic_positive);              /* -22 */
 
600
    SETUP_REGISTER (asm_generic_negative);              /* -21 */
 
601
    SETUP_REGISTER (asm_generic_quotient);              /* -20 */
 
602
    SETUP_REGISTER (asm_generic_remainder);             /* -19 */
 
603
    SETUP_REGISTER (asm_generic_modulo);                /* -18 */
 
604
  }
 
605
  else
 
606
  {
 
607
    SETUP_REGISTER (asm_nofp_add);                      /* -32 */
 
608
    SETUP_REGISTER (asm_nofp_subtract);                 /* -31 */
 
609
    SETUP_REGISTER (asm_nofp_multiply);                 /* -30 */
 
610
    SETUP_REGISTER (asm_nofp_divide);                   /* -29 */
 
611
    SETUP_REGISTER (asm_nofp_equal);                    /* -28 */
 
612
    SETUP_REGISTER (asm_nofp_less);                     /* -27 */
 
613
    SETUP_REGISTER (asm_nofp_greater);                  /* -26 */
 
614
    SETUP_REGISTER (asm_nofp_increment);                /* -25 */
 
615
    SETUP_REGISTER (asm_nofp_decrement);                /* -24 */
 
616
    SETUP_REGISTER (asm_nofp_zero);                     /* -23 */
 
617
    SETUP_REGISTER (asm_nofp_positive);                 /* -22 */
 
618
    SETUP_REGISTER (asm_nofp_negative);                 /* -21 */
 
619
    SETUP_REGISTER (asm_nofp_quotient);                 /* -20 */
 
620
    SETUP_REGISTER (asm_nofp_remainder);                /* -19 */
 
621
    SETUP_REGISTER (asm_nofp_modulo);                   /* -18 */
 
622
  }
 
623
 
 
624
  SETUP_REGISTER (asm_sc_apply);                        /* -17 */
 
625
  SETUP_REGISTER (asm_sc_apply_size_1);                 /* -16 */
 
626
  SETUP_REGISTER (asm_sc_apply_size_2);                 /* -15 */
 
627
  SETUP_REGISTER (asm_sc_apply_size_3);                 /* -14 */
 
628
  SETUP_REGISTER (asm_sc_apply_size_4);                 /* -13 */
 
629
  SETUP_REGISTER (asm_sc_apply_size_5);                 /* -12 */
 
630
  SETUP_REGISTER (asm_sc_apply_size_6);                 /* -11 */
 
631
  SETUP_REGISTER (asm_sc_apply_size_7);                 /* -10 */
 
632
  SETUP_REGISTER (asm_sc_apply_size_8);                 /* -9 */
 
633
  SETUP_REGISTER (asm_interrupt_continuation_2);        /* -8 */
 
634
  if (ia32_cpuid_needed)
 
635
    {
 
636
      SETUP_REGISTER (asm_serialize_cache);             /* -7 */
 
637
    }
 
638
  else
 
639
    {
 
640
      SETUP_REGISTER (asm_dont_serialize_cache);        /* -7 */
 
641
    }
 
642
 
 
643
#ifdef _MACH_UNIX
 
644
  {
 
645
    vm_address_t addr;
 
646
    vm_size_t size;
 
647
    vm_prot_t prot;
 
648
    vm_prot_t max_prot;
 
649
    vm_inherit_t inheritance;
 
650
    boolean_t shared;
 
651
    port_t object;
 
652
    vm_offset_t offset;
 
653
 
 
654
    addr = ((vm_address_t) Heap);
 
655
    if ((vm_region ((task_self ()), &addr, &size, &prot, &max_prot,
 
656
                    &inheritance, &shared, &object, &offset))
 
657
        != KERN_SUCCESS)
 
658
    {
 
659
      outf_fatal ( "compiler_reset: vm_region() failed.\n");
 
660
      Microcode_Termination (TERM_EXIT);
 
661
      /*NOTREACHED*/
 
662
    }
 
663
    if ((prot & VM_PROT_SCHEME) != VM_PROT_SCHEME)
 
664
    {
 
665
      if ((max_prot & VM_PROT_SCHEME) != VM_PROT_SCHEME)
 
666
      {
 
667
        outf_fatal (
 
668
                 "compiler_reset: inadequate protection for Heap.\n");
 
669
        outf_fatal ( "maximum = 0x%lx; desired = 0x%lx\n",
 
670
                 ((unsigned long) (max_prot & VM_PROT_SCHEME)),
 
671
                 ((unsigned long) VM_PROT_SCHEME));
 
672
        Microcode_Termination (TERM_EXIT);
 
673
        /*NOTREACHED*/
 
674
      }
 
675
      if ((vm_protect ((task_self ()), ((vm_address_t) Heap),
 
676
                       (((char *) Constant_Top) - ((char *) Heap)),
 
677
                       0, VM_PROT_SCHEME))
 
678
          != KERN_SUCCESS)
 
679
      {
 
680
        outf_fatal (
 
681
                 "compiler_reset: unable to change protection for Heap.\n");
 
682
        outf_fatal ( "actual = 0x%lx; desired = 0x%lx\n",
 
683
                 ((unsigned long) (prot & VM_PROT_SCHEME)),
 
684
                 ((unsigned long) VM_PROT_SCHEME));
 
685
        Microcode_Termination (TERM_EXIT);
 
686
        /*NOTREACHED*/
 
687
      }
 
688
    }
 
689
  }
 
690
#endif /* _MACH_UNIX */
 
691
}
 
692
 
 
693
#endif /* IN_CMPINT_C */
 
694
 
 
695
/* Derived parameters and macros.
 
696
   These macros expect the above definitions to be meaningful.
 
697
   If they are not, the macros below may have to be changed as well.
 
698
 */
 
699
 
 
700
#define COMPILED_ENTRY_OFFSET_WORD(entry)                               \
 
701
  (((format_word *) (entry))[-1])
 
702
#define COMPILED_ENTRY_FORMAT_WORD(entry)                               \
 
703
  (((format_word *) (entry))[-2])
 
704
 
 
705
/* The next one assumes 2's complement integers....*/
 
706
#define CLEAR_LOW_BIT(word)                     ((word) & ((unsigned long) -2))
 
707
#define OFFSET_WORD_CONTINUATION_P(word)        (((word) & 1) != 0)
 
708
 
 
709
#if (PC_ZERO_BITS == 0)
 
710
/* Instructions aligned on byte boundaries */
 
711
#define BYTE_OFFSET_TO_OFFSET_WORD(offset)      ((offset) << 1)
 
712
#define OFFSET_WORD_TO_BYTE_OFFSET(offset_word)                         \
 
713
  ((CLEAR_LOW_BIT(offset_word)) >> 1)
 
714
#endif
 
715
 
 
716
#if (PC_ZERO_BITS == 1)
 
717
/* Instructions aligned on word (16 bit) boundaries */
 
718
#define BYTE_OFFSET_TO_OFFSET_WORD(offset)      (offset)
 
719
#define OFFSET_WORD_TO_BYTE_OFFSET(offset_word)                         \
 
720
  (CLEAR_LOW_BIT(offset_word))
 
721
#endif
 
722
 
 
723
#if (PC_ZERO_BITS >= 2)
 
724
/* Should be OK for =2, but bets are off for >2 because of problems
 
725
   mentioned earlier!
 
726
*/
 
727
#define SHIFT_AMOUNT                            (PC_ZERO_BITS - 1)
 
728
#define BYTE_OFFSET_TO_OFFSET_WORD(offset)      ((offset) >> (SHIFT_AMOUNT))
 
729
#define OFFSET_WORD_TO_BYTE_OFFSET(offset_word)                         \
 
730
  ((CLEAR_LOW_BIT(offset_word)) << (SHIFT_AMOUNT))
 
731
#endif
 
732
 
 
733
#define MAKE_OFFSET_WORD(entry, block, continue)                        \
 
734
  ((BYTE_OFFSET_TO_OFFSET_WORD(((char *) (entry)) -                     \
 
735
                               ((char *) (block)))) |                   \
 
736
   ((continue) ? 1 : 0))
 
737
 
 
738
#if (EXECUTE_CACHE_ENTRY_SIZE == 2)
 
739
#define EXECUTE_CACHE_COUNT_TO_ENTRIES(count)                           \
 
740
  ((count) >> 1)
 
741
#define EXECUTE_CACHE_ENTRIES_TO_COUNT(entries)                         \
 
742
  ((entries) << 1)
 
743
#endif
 
744
 
 
745
#if (EXECUTE_CACHE_ENTRY_SIZE == 4)
 
746
#define EXECUTE_CACHE_COUNT_TO_ENTRIES(count)                           \
 
747
  ((count) >> 2)
 
748
#define EXECUTE_CACHE_ENTRIES_TO_COUNT(entries)                         \
 
749
  ((entries) << 2)
 
750
#endif
 
751
 
 
752
#if (!defined(EXECUTE_CACHE_COUNT_TO_ENTRIES))
 
753
#define EXECUTE_CACHE_COUNT_TO_ENTRIES(count)                           \
 
754
  ((count) / EXECUTE_CACHE_ENTRY_SIZE)
 
755
#define EXECUTE_CACHE_ENTRIES_TO_COUNT(entries)                         \
 
756
  ((entries) * EXECUTE_CACHE_ENTRY_SIZE)
 
757
#endif
 
758
 
 
759
/* The first entry in a cc block is preceeded by 2 headers (block and nmv),
 
760
   a format word and a gc offset word.   See the early part of the
 
761
   TRAMPOLINE picture, above.
 
762
 */
 
763
 
 
764
#define CC_BLOCK_FIRST_ENTRY_OFFSET                                     \
 
765
  (2 * ((sizeof(SCHEME_OBJECT)) + (sizeof(format_word))))
 
766
 
 
767
/* Format words */
 
768
 
 
769
#define FORMAT_BYTE_EXPR                0xFF
 
770
#define FORMAT_BYTE_COMPLR              0xFE
 
771
#define FORMAT_BYTE_CMPINT              0xFD
 
772
#define FORMAT_BYTE_DLINK               0xFC
 
773
#define FORMAT_BYTE_RETURN              0xFB
 
774
 
 
775
#define FORMAT_WORD_EXPR        (MAKE_FORMAT_WORD(0xFF, FORMAT_BYTE_EXPR))
 
776
#define FORMAT_WORD_CMPINT      (MAKE_FORMAT_WORD(0xFF, FORMAT_BYTE_CMPINT))
 
777
#define FORMAT_WORD_RETURN      (MAKE_FORMAT_WORD(0xFF, FORMAT_BYTE_RETURN))
 
778
 
 
779
/* This assumes that a format word is at least 16 bits,
 
780
   and the low order field is always 8 bits.
 
781
 */
 
782
 
 
783
#define MAKE_FORMAT_WORD(field1, field2)                                \
 
784
  (((field1) << 8) | ((field2) & 0xff))
 
785
 
 
786
#define SIGN_EXTEND_FIELD(field, size)                                  \
 
787
  (((field) & ((1 << (size)) - 1)) |                                    \
 
788
   ((((field) & (1 << ((size) - 1))) == 0) ? 0 :                        \
 
789
    ((-1) << (size))))
 
790
 
 
791
#define FORMAT_WORD_LOW_BYTE(word)                                      \
 
792
  (SIGN_EXTEND_FIELD((((unsigned long) (word)) & 0xff), 8))
 
793
 
 
794
#define FORMAT_WORD_HIGH_BYTE(word)                                     \
 
795
  (SIGN_EXTEND_FIELD((((unsigned long) (word)) >> 8),                   \
 
796
                     (((sizeof (format_word)) * CHAR_BIT) - 8)))
 
797
 
 
798
#define COMPILED_ENTRY_FORMAT_HIGH(addr)                                \
 
799
  (FORMAT_WORD_HIGH_BYTE(COMPILED_ENTRY_FORMAT_WORD(addr)))
 
800
 
 
801
#define COMPILED_ENTRY_FORMAT_LOW(addr)                                 \
 
802
  (FORMAT_WORD_LOW_BYTE(COMPILED_ENTRY_FORMAT_WORD(addr)))
 
803
 
 
804
#define FORMAT_BYTE_FRAMEMAX            0x7f
 
805
 
 
806
#define COMPILED_ENTRY_MAXIMUM_ARITY    COMPILED_ENTRY_FORMAT_LOW
 
807
#define COMPILED_ENTRY_MINIMUM_ARITY    COMPILED_ENTRY_FORMAT_HIGH
 
808
 
 
809
#endif /* not SCM_CMPINTMD_H */