282 lines
13 KiB
C
282 lines
13 KiB
C
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||
│ │
|
||
│ This program is free software; you can redistribute it and/or modify │
|
||
│ it under the terms of the GNU General Public License as published by │
|
||
│ the Free Software Foundation; version 2 of the License. │
|
||
│ │
|
||
│ This program is distributed in the hope that it will be useful, but │
|
||
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
||
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
||
│ General Public License for more details. │
|
||
│ │
|
||
│ You should have received a copy of the GNU General Public License │
|
||
│ along with this program; if not, write to the Free Software │
|
||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||
│ 02110-1301 USA │
|
||
╠──────────────────────────────────────────────────────────────────────────────╣
|
||
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
|
||
│░░░░░░░█▀█░█▀█░▀█▀░█░█░█▀█░█░░░█░░░█░█░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
|
||
│░░░░░░░█▀█░█░▄░░█░░█░█░█▀█░█░░░█░░░▀█▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
|
||
│░░░░░░░▀░▀░▀▀▀░░▀░░▀▀▀░▀░▀░▀▀▀░▀▀▀░░▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
|
||
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
|
||
│░░░░░░░█▀█░█▀█░█▀█░▀█▀░█▀█░█▀█░█░░░█▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
|
||
│░░░░░░░█▀▀░█ █░██▀░░█░░█▀█░█▀█░█░░░█▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
|
||
│░░░░░░░▀░░░▀▀▀░▀░▀░░▀░░▀░▀░▀▀▀░▀▀▀░▀▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
|
||
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░│
|
||
│░░░░░░░█▀▀░█░█░█▀▀░█▀█░█░█░▀█▀░█▀█░█▀█░█░░█▀▀░░░░░░░░░░░░░░░░░░░░░░░░▄▄░░░▐█░░│
|
||
│░░░░░░░█▀▀░▄▀▄░█▀▀░█░▄░█░█░░█░░█▀█░█▀█░█░░█▀▀░░░░░░░░░░░░▄▄▄░░░▄██▄░░█▀░░░█░▄░│
|
||
│░░░░░░░▀▀▀░▀░▀░▀▀▀░▀▀▀░▀▀▀░░▀░░▀░▀░▀▀▀░▀▀░▀▀▀░░░░░░░░░░▄██▀█▌░██▄▄░░▐█▀▄░▐█▀░░│
|
||
│░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▐█▀▀▌░░░▄▀▌░▌░█░▌░░▌░▌░░│
|
||
╠──────────────────────────────────────────────────────▌▀▄─▐──▀▄─▐▄─▐▄▐▄─▐▄─▐▄─│
|
||
│ αcτµαlly pδrταblε εxεcµταblε § macros │
|
||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||
#ifndef APE_MACROS_H_
|
||
#define APE_MACROS_H_
|
||
#include "libc/macros.h"
|
||
#ifdef __ASSEMBLER__
|
||
/* clang-format off */
|
||
|
||
/**
|
||
* @fileoverview Macros relevant to αcτµαlly pδrταblε εxεcµταblε.
|
||
*/
|
||
|
||
/ Calls near (i.e. pc+pcrel<64kB) FUNCTION.
|
||
/ @mode long,legacy,real
|
||
/ @cost 9 bytes overhead
|
||
.macro rlcall function:req
|
||
.byte 0x50 # push %[er]ax
|
||
.byte 0xb8,0,0 # mov $?,%[e]ax
|
||
jmp 911f
|
||
.byte 0x58 # pop %[er]ax
|
||
.byte 0xe8 # call Jvds
|
||
.long \function\()-.-4
|
||
jmp 912f
|
||
911: .byte 0x58 # pop %[er]ax
|
||
.byte 0xe8 # call Jvds
|
||
.short \function\()-.-2
|
||
912:
|
||
.endm
|
||
|
||
/ Loads far (i.e. <1mb) abs constexpr ADDRESS into ES:DI+EDX+RDX.
|
||
/ @mode long,legacy,real
|
||
.macro movesdi address:req
|
||
.byte 0xbf # mov $0x????xxxx,%[e]di
|
||
.short \address>>4
|
||
.byte 0x8e,0xc7 # mov %di,%es
|
||
.byte 0xbf # mov $0x????xxxx,%[e]di
|
||
.short \address&0xf
|
||
jmp 297f
|
||
.byte 0xbf # mov $0x????xxxx,%edi
|
||
.long \address
|
||
297:
|
||
.endm
|
||
|
||
/ Loads 16-bit CONSTEXPR into Qw-register w/ optional zero-extend.
|
||
/ @mode long,legacy,real
|
||
.macro bbmov constexpr:req abcd abcd.hi:req abcd.lo:req
|
||
.ifnb \abcd
|
||
.if (\constexpr)<128 && (\constexpr)>=0
|
||
pushpop \constexpr,\abcd
|
||
.exitm
|
||
.endif
|
||
.endif
|
||
movb $(\constexpr)>>8&0xff,\abcd.hi
|
||
movb $(\constexpr)&0xff,\abcd.lo
|
||
.endm
|
||
|
||
/ Compares 16-bit CONSTEXPR with Qw-register.
|
||
/ @mode long,legacy,real
|
||
.macro bbcmp constexpr:req abcd.hi:req abcd.lo:req
|
||
cmpb $(\constexpr)>>8&0xff,\abcd.hi
|
||
jnz 387f
|
||
cmpb $(\constexpr)&0xff,\abcd.lo
|
||
387:
|
||
.endm
|
||
|
||
/ Adds 16-bit CONSTEXPR to Qw-register.
|
||
/ @mode long,legacy,real
|
||
.macro bbadd constexpr:req abcd.hi:req abcd.lo:req
|
||
addb $(\constexpr)&0xff,\abcd.lo
|
||
.if (\constexpr) != 0
|
||
adcb $(\constexpr)>>8&0xff,\abcd.hi
|
||
.endif
|
||
.endm
|
||
|
||
/ Subtracts 16-bit CONSTEXPR from Qw-register.
|
||
/ @mode long,legacy,real
|
||
.macro bbsub constexpr:req abcd.hi:req abcd.lo:req
|
||
subb $(\constexpr)&0xff,\abcd.lo
|
||
.if (\constexpr) != 0
|
||
sbbb $(\constexpr)>>8&0xff,\abcd.hi
|
||
.endif
|
||
.endm
|
||
|
||
/ Ands Qw-register with 16-bit CONSTEXPR.
|
||
/ @mode long,legacy,real
|
||
.macro bband constexpr:req abcd.hi:req abcd.lo:req
|
||
.if ((\constexpr)&0xff) != 0xff || ((\constexpr)>>8&0xff) == 0xff
|
||
andb $(\constexpr)&0xff,\abcd.lo
|
||
.endif
|
||
.if ((\constexpr)>>8&0xff) != 0xff
|
||
andb $(\constexpr)>>8&0xff,\abcd.hi
|
||
.endif
|
||
.endm
|
||
|
||
/ Ors Qw-register with 16-bit CONSTEXPR.
|
||
/ @mode long,legacy,real
|
||
.macro bbor constexpr:req abcd.hi:req abcd.lo:req
|
||
.if ((\constexpr)&0xff) != 0 || ((\constexpr)>>8&0xff) != 0
|
||
orb $(\constexpr)&0xff,\abcd.lo
|
||
.endif
|
||
.if ((\constexpr)>>8&0xff) != 0
|
||
orb $(\constexpr)>>8&0xff,\abcd.hi
|
||
.endif
|
||
.endm
|
||
|
||
/ Performs ACTION only if in real mode.
|
||
/ @mode long,legacy,real
|
||
.macro rlo clobber:req action:vararg
|
||
990: mov $0,\clobber
|
||
.if .-990b!=3
|
||
.error "bad clobber or assembler mode"
|
||
.endif
|
||
991: \action
|
||
.rept 2-(.-991b)
|
||
nop
|
||
.endr
|
||
.if .-991b!=2
|
||
.error "ACTION must be 1-2 bytes"
|
||
.endif
|
||
.endm
|
||
|
||
/ Initializes real mode stack.
|
||
/ The most holiest of holy code.
|
||
/ @mode real
|
||
/ @see www.pcjs.org/pubs/pc/reference/intel/8086/
|
||
.macro rlstack seg:req addr:req
|
||
cli
|
||
mov \seg,%ss
|
||
mov \addr,%sp
|
||
sti
|
||
.endm
|
||
|
||
/ Symbolic Linker-Defined Binary Content.
|
||
.macro .stub name:req kind:req default type=@object
|
||
.ifnb \default
|
||
.equ \name,\default
|
||
.endif
|
||
.\kind \name
|
||
.type \name,\type
|
||
.weak \name
|
||
.hidden \name
|
||
.endm
|
||
|
||
/ Symbolic Linker-Defined Binary-Encoded-Bourne Content.
|
||
/ @param units is the number of encoded 32-bit values to insert,
|
||
/ e.g. \000 can be encoded as 0x3030305c.
|
||
.macro .shstub name:req units:req
|
||
ss \name,0
|
||
.if \units>1
|
||
ss \name,1
|
||
.if \units>2
|
||
ss \name,2
|
||
ss \name,3
|
||
.if \units>4
|
||
ss \name,4
|
||
ss \name,5
|
||
ss \name,6
|
||
ss \name,7
|
||
.endif
|
||
.endif
|
||
.endif
|
||
.endm
|
||
.macro ss name n
|
||
.stub \name\()_bcs\n,long
|
||
.endm
|
||
|
||
/* clang-format on */
|
||
#elif defined(__LINKER__)
|
||
|
||
#define BCX_NIBBLE(X) ((((X)&0xf) > 0x9) ? ((X)&0xf) + 0x37 : ((X)&0xf) + 0x30)
|
||
#define BCX_OCTET(X) ((BCX_NIBBLE((X) >> 4) << 8) | (BCX_NIBBLE((X) >> 0) << 0))
|
||
#define BCX_INT16(X) ((BCX_OCTET((X) >> 8) << 16) | (BCX_OCTET((X) >> 0) << 0))
|
||
#define BCXSTUB(SYM, X) \
|
||
HIDDEN(SYM##_bcx0 = BCX_INT16((X) >> 48)); \
|
||
HIDDEN(SYM##_bcx1 = BCX_INT16((X) >> 32)); \
|
||
HIDDEN(SYM##_bcx2 = BCX_INT16((X) >> 16)); \
|
||
HIDDEN(SYM##_bcx3 = BCX_INT16((X) >> 0))
|
||
|
||
/**
|
||
* Binary coded backslash octet support.
|
||
*
|
||
* <p>This allows linker scripts to generate printf commands.
|
||
*/
|
||
#define BCO_OCTET(X) (((X)&0x7) + 0x30)
|
||
#define BCOB_UNIT(X) \
|
||
((BCO_OCTET((X) >> 0) << 24) | (BCO_OCTET((X) >> 3) << 16) | \
|
||
(BCO_OCTET(((X)&0xff) >> 6) << 8) | 0x5c)
|
||
|
||
#define PFBYTE(SYM, X, I) HIDDEN(SYM##_bcs##I = BCOB_UNIT((X) >> ((I)*8)))
|
||
#define PFSTUB2(SYM, X) \
|
||
HIDDEN(SYM = (X)); \
|
||
PFBYTE(SYM, X, 0); \
|
||
PFBYTE(SYM, X, 1)
|
||
#define PFSTUB4(SYM, X) \
|
||
PFSTUB2(SYM, X); \
|
||
PFBYTE(SYM, X, 2); \
|
||
PFBYTE(SYM, X, 3)
|
||
#define PFSTUB8(SYM, X) \
|
||
PFSTUB4(SYM, X); \
|
||
PFBYTE(SYM, X, 4); \
|
||
PFBYTE(SYM, X, 5); \
|
||
PFBYTE(SYM, X, 6); \
|
||
PFBYTE(SYM, X, 7)
|
||
|
||
/**
|
||
* Binary coded decimal support.
|
||
*
|
||
* <p>This allows linker scripts to generate dd commands. Leading spaces
|
||
* need to be inserted so Mac doesn't consider them octal; therefore,
|
||
* parameters must be quoted; and eight digits should be good enough.
|
||
*/
|
||
#define SHSTUB2(SYM, X) \
|
||
HIDDEN(SYM##_bcs0 = BCD10K(X)); \
|
||
HIDDEN(SYM##_bcs1 = BCD(X))
|
||
#define BCD(X) \
|
||
((X) == 0 \
|
||
? 0x20202030 \
|
||
: (X) < 10 ? 0x30202020 + (((X) % 10) << 24) \
|
||
: (X) < 100 ? 0x30302020 + (((X) % 10) << 24) + \
|
||
(((X) / 10 % 10) << 16) \
|
||
: (X) < 1000 ? 0x30303020 + (((X) % 10) << 24) + \
|
||
(((X) / 10 % 10) << 16) + \
|
||
(((X) / 100 % 10) << 8) \
|
||
: 0x30303030 + (((X) % 10) << 24) + \
|
||
(((X) / 10 % 10) << 16) + \
|
||
(((X) / 100 % 10) << 8) + \
|
||
(((X) / 1000 % 10) << 0))
|
||
#define BCD10K(X) \
|
||
((X) < 10000 \
|
||
? 0x20202020 \
|
||
: (X) < 100000 \
|
||
? 0x30202020 + (((X) / 10000 % 10) << 24) \
|
||
: (X) < 1000000 \
|
||
? 0x30302020 + (((X) / 10000 % 10) << 24) + \
|
||
(((X) / 100000 % 10) << 16) \
|
||
: (X) < 10000000 \
|
||
? 0x30303020 + (((X) / 10000 % 10) << 24) + \
|
||
(((X) / 100000 % 10) << 16) + \
|
||
(((X) / 1000000 % 10) << 8) \
|
||
: (X) < 100000000 \
|
||
? 0x30303030 + (((X) / 10000 % 10) << 24) + \
|
||
(((X) / 100000 % 10) << 16) + \
|
||
(((X) / 1000000 % 10) << 8) + \
|
||
(((X) / 10000000 % 10) << 0) \
|
||
: 0xffffffffffffffff)
|
||
|
||
#endif /* __ASSEMBLER__ */
|
||
#endif /* APE_MACROS_H_ */
|