Compare commits
47 commits
03420ef4ad
...
db5a32c68c
Author | SHA1 | Date | |
---|---|---|---|
db5a32c68c | |||
56ebd1409b | |||
7dd8ea2ea5 | |||
6aa3fef91f | |||
3badc8ece7 | |||
1fb1016349 | |||
278ed3cf26 | |||
f21d256f3f | |||
42b8c481e3 | |||
0fe814b530 | |||
9dfa4a88c5 | |||
baff578256 | |||
5b554e8e6e | |||
b59422a24b | |||
8619ce3ada | |||
247a2bd6ae | |||
f8a6f92752 | |||
cba54b205b | |||
8891fae303 | |||
15955282f6 | |||
249e4b9069 | |||
95ed8ee484 | |||
0165c07c7b | |||
887ec0656e | |||
d24c3f8722 | |||
c37c0e62cc | |||
dc1f69be83 | |||
5329c98b81 | |||
cc356b5c75 | |||
48398b072a | |||
680b6b9857 | |||
1764c6baa2 | |||
967b46e98e | |||
b868c1ece9 | |||
d464606dd6 | |||
b48b5b13ce | |||
21b30ccadb | |||
1e0961c679 | |||
3716d49cd9 | |||
f2a49ff3ab | |||
b81ac5e2c3 | |||
00c722d2ef | |||
a47bb5493d | |||
63f646de78 | |||
6d9ac0b182 | |||
a45f1cdd33 | |||
01d978cc22 |
8
README
8
README
|
@ -2,7 +2,7 @@
|
||||||
===================================
|
===================================
|
||||||
|
|
||||||
© 1987-2005 Vrije Universiteit, Amsterdam
|
© 1987-2005 Vrije Universiteit, Amsterdam
|
||||||
2022-06-18
|
2022-08-19
|
||||||
|
|
||||||
|
|
||||||
INTRODUCTION
|
INTRODUCTION
|
||||||
|
@ -38,6 +38,7 @@ cpm produces i80 CP/M .COM files
|
||||||
rpi produces Raspberry Pi GPU binaries
|
rpi produces Raspberry Pi GPU binaries
|
||||||
pdpv7 produces PDP/11 V7 Unix binaries
|
pdpv7 produces PDP/11 V7 Unix binaries
|
||||||
msdos86 produces i86 MS-DOS .COM files
|
msdos86 produces i86 MS-DOS .COM files
|
||||||
|
msdos386 produces i386 MS-DOS 32-bit DPMI .EXE files
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -62,11 +63,6 @@ Requirements:
|
||||||
- (optionally) ninja; if you've got this, this will be autodetected and give
|
- (optionally) ninja; if you've got this, this will be autodetected and give
|
||||||
you faster builds.
|
you faster builds.
|
||||||
|
|
||||||
- (optionally) the qemu suite: if you have this installed, the build system
|
|
||||||
will detect it automatically and run the test suites for the supported
|
|
||||||
architectures. Get both the qemu-system-* platform emulators and the qemu-*
|
|
||||||
userland emulators (only works on Linux).
|
|
||||||
|
|
||||||
- about 115MB free in /tmp (or some other temporary directory).
|
- about 115MB free in /tmp (or some other temporary directory).
|
||||||
|
|
||||||
- about 15MB in the target directory.
|
- about 15MB in the target directory.
|
||||||
|
|
|
@ -12,6 +12,7 @@ vars.plats = {
|
||||||
"linuxppc",
|
"linuxppc",
|
||||||
"linuxmips",
|
"linuxmips",
|
||||||
"msdos86",
|
"msdos86",
|
||||||
|
"msdos386",
|
||||||
"osx386",
|
"osx386",
|
||||||
"osxppc",
|
"osxppc",
|
||||||
"pc86",
|
"pc86",
|
||||||
|
@ -22,9 +23,9 @@ vars.plats = {
|
||||||
vars.plats_with_tests = {
|
vars.plats_with_tests = {
|
||||||
"cpm",
|
"cpm",
|
||||||
"linux68k",
|
"linux68k",
|
||||||
"linux386",
|
--"linux386",
|
||||||
"linuxppc",
|
"linuxppc",
|
||||||
"linuxmips",
|
--"linuxmips",
|
||||||
"pc86",
|
"pc86",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -225,7 +225,7 @@ definerule("cprogram",
|
||||||
commands = {
|
commands = {
|
||||||
type="strings",
|
type="strings",
|
||||||
default={
|
default={
|
||||||
"$(CC) $LDFLAGS -o %{outs[1]} %{ins} %{ins}"
|
"$(CC) $(LDFLAGS) -o %{outs[1]} %{ins} %{ins}"
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -184,10 +184,13 @@
|
||||||
{0, NOOP_1, 0155, "ins"},
|
{0, NOOP_1, 0155, "ins"},
|
||||||
{0, NOOP_1, 0252, "stosb"},
|
{0, NOOP_1, 0252, "stosb"},
|
||||||
{0, NOOP_1, 0253, "stos"},
|
{0, NOOP_1, 0253, "stos"},
|
||||||
|
{0, NOOP_1, 0253, "stosw"},
|
||||||
{0, NOOP_1, 0254, "lodsb"},
|
{0, NOOP_1, 0254, "lodsb"},
|
||||||
{0, NOOP_1, 0255, "lods"},
|
{0, NOOP_1, 0255, "lods"},
|
||||||
|
{0, NOOP_1, 0255, "lodsw"},
|
||||||
{0, NOOP_1, 0256, "scasb"},
|
{0, NOOP_1, 0256, "scasb"},
|
||||||
{0, NOOP_1, 0257, "scas"},
|
{0, NOOP_1, 0257, "scas"},
|
||||||
|
{0, NOOP_1, 0257, "scasw"},
|
||||||
{0, NOOP_1, 0311, "leave"},
|
{0, NOOP_1, 0311, "leave"},
|
||||||
{0, NOOP_1, 0316, "into"},
|
{0, NOOP_1, 0316, "into"},
|
||||||
{0, NOOP_1, 0317, "iret"},
|
{0, NOOP_1, 0317, "iret"},
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
|
|
||||||
void ea_1_16(int param)
|
void ea_1_16(int param)
|
||||||
{
|
{
|
||||||
reg_1 &= 0377;
|
reg_1 &= 0377;
|
||||||
if ((reg_1 & 070) || (param & ~070)) {
|
if (param & ~070) {
|
||||||
serror("bad operand");
|
serror("bad operand");
|
||||||
}
|
}
|
||||||
emit1(reg_1 | param);
|
emit1(reg_1 | param);
|
||||||
|
@ -39,542 +39,545 @@ void ea_1_16(int param)
|
||||||
}
|
}
|
||||||
|
|
||||||
void ea_1(int param) {
|
void ea_1(int param) {
|
||||||
if (! address_long) {
|
if (! address_long) {
|
||||||
ea_1_16(param);
|
ea_1_16(param);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (is_expr(reg_1)) {
|
if (is_expr(reg_1)) {
|
||||||
serror("bad operand");
|
serror("bad operand");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (is_reg(reg_1)) {
|
if (is_reg(reg_1)) {
|
||||||
emit1(0300 | param | (reg_1&07));
|
emit1(0300 | param | (reg_1&07));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (rm_1 == 04) {
|
if (rm_1 == 04) {
|
||||||
/* sib field use here */
|
/* sib field use here */
|
||||||
emit1(mod_1 << 6 | param | 04);
|
emit1(mod_1 << 6 | param | 04);
|
||||||
emit1(sib_1 | reg_1);
|
emit1(sib_1 | reg_1);
|
||||||
}
|
}
|
||||||
else emit1(mod_1<<6 | param | (reg_1&07));
|
else emit1(mod_1<<6 | param | (reg_1&07));
|
||||||
if ((mod_1 == 0 && reg_1 == 5) || mod_1 == 2) {
|
if ((mod_1 == 0 && reg_1 == 5) || mod_1 == 2) {
|
||||||
/* ??? should this be protected by a call to "small" ??? */
|
/* ??? should this be protected by a call to "small" ??? */
|
||||||
#ifdef RELOCATION
|
#ifdef RELOCATION
|
||||||
RELOMOVE(relonami, rel_1);
|
RELOMOVE(relonami, rel_1);
|
||||||
newrelo(exp_1.typ, RELO4);
|
newrelo(exp_1.typ, RELO4);
|
||||||
#endif
|
#endif
|
||||||
emit4((long)(exp_1.val));
|
emit4((long)(exp_1.val));
|
||||||
}
|
}
|
||||||
else if (mod_1 == 1) {
|
else if (mod_1 == 1) {
|
||||||
emit1((int)(exp_1.val));
|
emit1((int)(exp_1.val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ea_2(int param) {
|
void ea_2(int param) {
|
||||||
|
|
||||||
op_1 = op_2;
|
op_1 = op_2;
|
||||||
RELOMOVE(rel_1, rel_2);
|
RELOMOVE(rel_1, rel_2);
|
||||||
ea_1(param);
|
ea_1(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
int checkscale(valu_t val)
|
int checkscale(valu_t val)
|
||||||
{
|
{
|
||||||
int v = val;
|
int v = val;
|
||||||
|
|
||||||
if (! address_long) {
|
if (! address_long) {
|
||||||
serror("scaling not allowed in 16-bit mode");
|
serror("scaling not allowed in 16-bit mode");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (v != val) v = 0;
|
if (v != val) v = 0;
|
||||||
switch(v) {
|
switch(v) {
|
||||||
case 1:
|
case 1:
|
||||||
return 0;
|
return 0;
|
||||||
case 2:
|
case 2:
|
||||||
return 1 << 6;
|
return 1 << 6;
|
||||||
case 4:
|
case 4:
|
||||||
return 2 << 6;
|
return 2 << 6;
|
||||||
case 8:
|
case 8:
|
||||||
return 3 << 6;
|
return 3 << 6;
|
||||||
default:
|
default:
|
||||||
serror("bad scale");
|
serror("bad scale");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/*NOTREACHED*/
|
/*NOTREACHED*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void reverse(void) {
|
void reverse(void) {
|
||||||
struct operand op;
|
struct operand op;
|
||||||
#ifdef RELOCATION
|
#ifdef RELOCATION
|
||||||
int r = rel_1;
|
int r = rel_1;
|
||||||
|
|
||||||
rel_1 = rel_2; rel_2 = r;
|
rel_1 = rel_2; rel_2 = r;
|
||||||
#endif
|
#endif
|
||||||
op = op_1; op_1 = op_2; op_2 = op;
|
op = op_1; op_1 = op_2; op_2 = op;
|
||||||
}
|
}
|
||||||
|
|
||||||
void badsyntax(void)
|
void badsyntax(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
serror("bad operands");
|
serror("bad operands");
|
||||||
}
|
}
|
||||||
|
|
||||||
void regsize(int sz)
|
void regsize(int sz)
|
||||||
{
|
{
|
||||||
register int bit;
|
register int bit;
|
||||||
|
|
||||||
bit = (sz&1) ? 0 : IS_R8;
|
bit = (sz&1) ? 0 : IS_R8;
|
||||||
if ((is_reg(reg_1) && (reg_1 & IS_R8) != bit) ||
|
if ((is_reg(reg_1) && (reg_1 & IS_R8) != bit) ||
|
||||||
(is_reg(reg_2) && (reg_2 & IS_R8) != bit))
|
(is_reg(reg_2) && (reg_2 & IS_R8) != bit))
|
||||||
serror("register error");
|
serror("register error");
|
||||||
if (! address_long) {
|
if (! address_long) {
|
||||||
reg_1 &= ~010;
|
reg_1 &= ~010;
|
||||||
reg_2 &= ~010;
|
reg_2 &= ~010;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void indexed(void) {
|
void indexed(void) {
|
||||||
if (address_long) {
|
if (address_long) {
|
||||||
mod_2 = 0;
|
mod_2 = 0;
|
||||||
if (sib_2 == -1)
|
if (sib_2 == -1)
|
||||||
serror("register error");
|
serror("register error");
|
||||||
if (rm_2 == 0 && reg_2 == 4) {
|
if (rm_2 == 0 && reg_2 == 4) {
|
||||||
/* base register sp, no index register; use
|
/* base register sp, no index register; use
|
||||||
indexed mode without index register
|
indexed mode without index register
|
||||||
*/
|
*/
|
||||||
rm_2 = 04;
|
rm_2 = 04;
|
||||||
sib_2 = 044;
|
sib_2 = 044;
|
||||||
}
|
}
|
||||||
if (reg_2 == 015) {
|
if (reg_2 == 015) {
|
||||||
reg_2 = 05;
|
reg_2 = 05;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (small(exp_2.typ == S_ABS && fitb(exp_2.val), 3)) {
|
if (small(exp_2.typ == S_ABS && fitb(exp_2.val), 3)) {
|
||||||
if (small(exp_2.val == 0 && reg_2 != 5, 1)) {
|
if (small(exp_2.val == 0 && reg_2 != 5, 1)) {
|
||||||
}
|
}
|
||||||
else mod_2 = 01;
|
else mod_2 = 01;
|
||||||
}
|
}
|
||||||
else if (small(0, 1)) {
|
else if (small(0, 1)) {
|
||||||
}
|
}
|
||||||
else mod_2 = 02;
|
else mod_2 = 02;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (reg_2 & ~7)
|
if (reg_2 & ~7)
|
||||||
serror("register error");
|
serror("register error");
|
||||||
if (small(exp_2.typ == S_ABS && fitb(exp_2.val), 1)) {
|
if (small(exp_2.typ == S_ABS && fitb(exp_2.val), 1)) {
|
||||||
if (small(exp_2.val == 0 && reg_2 != 6, 1)) {
|
if (small(exp_2.val == 0 && reg_2 != 6, 1)) {
|
||||||
}
|
}
|
||||||
else reg_2 |= 0100;
|
else reg_2 |= 0100;
|
||||||
}
|
}
|
||||||
else if (small(0, 1)) {
|
else if (small(0, 1)) {
|
||||||
}
|
}
|
||||||
else reg_2 |= 0200;
|
else reg_2 |= 0200;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ebranch(register int opc,expr_t exp)
|
void ebranch(register int opc,expr_t exp)
|
||||||
{
|
{
|
||||||
/* Conditional branching; Full displacements are available
|
/* Conditional branching; Full displacements are available
|
||||||
on the 80386, so the welknown trick with the reverse branch
|
on the 80386, so the welknown trick with the reverse branch
|
||||||
over a jump is not needed here.
|
over a jump is not needed here.
|
||||||
The only complication here is with the address size, which
|
The only complication here is with the address size, which
|
||||||
can be set with a prefix. In this case, the user gets what
|
can be set with a prefix. In this case, the user gets what
|
||||||
he asked for.
|
he asked for.
|
||||||
*/
|
*/
|
||||||
register int sm;
|
register int sm;
|
||||||
register long dist;
|
register long dist;
|
||||||
int saving = address_long ? 4 : 2;
|
int saving = address_long ? 4 : 2;
|
||||||
|
|
||||||
if (opc == 0353) saving--;
|
if (opc == 0353) saving--;
|
||||||
dist = exp.val - (DOTVAL + 2);
|
dist = exp.val - (DOTVAL + 2);
|
||||||
if (pass == PASS_2 && dist > 0 && !(exp.typ & S_DOT))
|
if (pass == PASS_2 && dist > 0 && !(exp.typ & S_DOT))
|
||||||
dist -= DOTGAIN;
|
dist -= DOTGAIN;
|
||||||
sm = dist > 0 ? fitb(dist-saving) : fitb(dist);
|
sm = dist > 0 ? fitb(dist-saving) : fitb(dist);
|
||||||
if ((exp.typ & ~S_DOT) != DOTTYP)
|
if ((exp.typ & ~S_DOT) != DOTTYP)
|
||||||
sm = 0;
|
sm = 0;
|
||||||
if ((sm = small(sm,saving)) == 0) {
|
if ((sm = small(sm,saving)) == 0) {
|
||||||
if (opc == 0353) {
|
if (opc == 0353) {
|
||||||
emit1(0xe9);
|
emit1(0xe9);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
emit1(0xF);
|
emit1(0xF);
|
||||||
emit1(opc | 0x80);
|
emit1(opc | 0x80);
|
||||||
}
|
}
|
||||||
dist -= saving;
|
dist -= saving;
|
||||||
exp.val = dist;
|
exp.val = dist;
|
||||||
adsize_exp(exp, RELPC);
|
adsize_exp(exp, RELPC);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (opc == 0353) {
|
if (opc == 0353) {
|
||||||
emit1(opc);
|
emit1(opc);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
emit1(opc | 0x70);
|
emit1(opc | 0x70);
|
||||||
}
|
}
|
||||||
emit1((int)dist);
|
emit1((int)dist);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void branch(register int opc,expr_t exp)
|
void branch(register int opc,expr_t exp)
|
||||||
{
|
{
|
||||||
/* LOOP, JCXZ, etc. branch instructions.
|
/* LOOP, JCXZ, etc. branch instructions.
|
||||||
Here, the offset just must fit in a byte.
|
Here, the offset just must fit in a byte.
|
||||||
*/
|
*/
|
||||||
register long dist;
|
register long dist;
|
||||||
|
|
||||||
dist = exp.val - (DOTVAL + 2);
|
dist = exp.val - (DOTVAL + 2);
|
||||||
if (pass == PASS_2 && dist > 0 && !(exp.typ & S_DOT))
|
if (pass == PASS_2 && dist > 0 && !(exp.typ & S_DOT))
|
||||||
dist -= DOTGAIN;
|
dist -= DOTGAIN;
|
||||||
fit((exp.typ & ~S_DOT) == DOTTYP && fitb(dist));
|
fit((exp.typ & ~S_DOT) == DOTTYP && fitb(dist));
|
||||||
emit1(opc);
|
emit1(opc);
|
||||||
emit1((int)dist);
|
emit1((int)dist);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pushop(register int opc)
|
void pushop(register int opc)
|
||||||
{
|
{
|
||||||
|
|
||||||
regsize(1);
|
regsize(1);
|
||||||
if (is_segreg(reg_1)) {
|
if (is_segreg(reg_1)) {
|
||||||
/* segment register */
|
/* segment register */
|
||||||
if ((reg_1 & 07) <= 3)
|
if ((reg_1 & 07) <= 3)
|
||||||
emit1(6 | opc | (reg_1&7)<<3);
|
emit1(6 | opc | (reg_1&7)<<3);
|
||||||
else {
|
else {
|
||||||
emit1(0xF);
|
emit1(0xF);
|
||||||
emit1(0200 | opc | ((reg_1&7)<<3));
|
emit1(0200 | opc | ((reg_1&7)<<3));
|
||||||
}
|
}
|
||||||
} else if (is_reg(reg_1)) {
|
} else if (is_reg(reg_1)) {
|
||||||
/* normal register */
|
/* normal register */
|
||||||
emit1(0120 | opc<<3 | (reg_1&7));
|
emit1(0120 | opc<<3 | (reg_1&7));
|
||||||
} else if (opc == 0) {
|
} else if (opc == 0) {
|
||||||
if (is_expr(reg_1)) {
|
if (is_expr(reg_1)) {
|
||||||
if (small(exp_1.typ == S_ABS && fitb(exp_1.val),
|
if (small(exp_1.typ == S_ABS && fitb(exp_1.val),
|
||||||
operand_long ? 3 : 1)) {
|
operand_long ? 3 : 1)) {
|
||||||
emit1(0152);
|
emit1(0152);
|
||||||
emit1((int)(exp_1.val));
|
emit1((int)(exp_1.val));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
emit1(0150);
|
emit1(0150);
|
||||||
RELOMOVE(relonami, rel_1);
|
RELOMOVE(relonami, rel_1);
|
||||||
opsize_exp(exp_1, 1);
|
opsize_exp(exp_1, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
emit1(0377); ea_1(6<<3);
|
emit1(0377); ea_1(6<<3);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
emit1(0217); ea_1(0<<3);
|
emit1(0217); ea_1(0<<3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void opsize_exp(expr_t exp, int nobyte)
|
void opsize_exp(expr_t exp, int nobyte)
|
||||||
{
|
{
|
||||||
if (! nobyte) {
|
if (! nobyte) {
|
||||||
#ifdef RELOCATION
|
#ifdef RELOCATION
|
||||||
newrelo(exp.typ, RELO1);
|
newrelo(exp.typ, RELO1);
|
||||||
#endif
|
#endif
|
||||||
emit1((int)(exp.val));
|
emit1((int)(exp.val));
|
||||||
}
|
}
|
||||||
else if (operand_long) {
|
else if (operand_long) {
|
||||||
#ifdef RELOCATION
|
#ifdef RELOCATION
|
||||||
newrelo(exp.typ, RELO4);
|
newrelo(exp.typ, RELO4);
|
||||||
#endif
|
#endif
|
||||||
emit4((long)(exp.val));
|
emit4((long)(exp.val));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
#ifdef RELOCATION
|
#ifdef RELOCATION
|
||||||
newrelo(exp.typ, RELO2);
|
newrelo(exp.typ, RELO2);
|
||||||
#endif
|
#endif
|
||||||
emit2((int)(exp.val));
|
emit2((int)(exp.val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void adsize_exp(expr_t exp, int relpc)
|
void adsize_exp(expr_t exp, int relpc)
|
||||||
{
|
{
|
||||||
if (address_long) {
|
if (address_long) {
|
||||||
#ifdef RELOCATION
|
#ifdef RELOCATION
|
||||||
newrelo(exp.typ, RELO4 | relpc);
|
newrelo(exp.typ, RELO4 | relpc);
|
||||||
#endif
|
#endif
|
||||||
emit4((long)(exp.val));
|
emit4((long)(exp.val));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
#ifdef RELOCATION
|
#ifdef RELOCATION
|
||||||
newrelo(exp.typ, RELO2 | relpc);
|
newrelo(exp.typ, RELO2 | relpc);
|
||||||
#endif
|
#endif
|
||||||
emit2((int)(exp.val));
|
emit2((int)(exp.val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addop(register int opc)
|
void addop(register int opc)
|
||||||
{
|
{
|
||||||
|
|
||||||
regsize(opc);
|
regsize(opc);
|
||||||
if (is_reg(reg_2)) {
|
if (is_reg(reg_2)) {
|
||||||
/* Add register to register or memory */
|
/* Add register to register or memory */
|
||||||
emit1(opc); ea_1((reg_2&7)<<3);
|
emit1(opc); ea_1((reg_2&7)<<3);
|
||||||
} else if (is_acc(reg_1) && is_expr(reg_2)) {
|
} else if (is_acc(reg_1) && is_expr(reg_2)) {
|
||||||
/* Add immediate to accumulator */
|
/* Add immediate to accumulator */
|
||||||
emit1(opc | 4);
|
emit1(opc | 4);
|
||||||
RELOMOVE(relonami, rel_2);
|
RELOMOVE(relonami, rel_2);
|
||||||
opsize_exp(exp_2, (opc&1));
|
opsize_exp(exp_2, (opc&1));
|
||||||
} else if (is_expr(reg_2)) {
|
} else if (is_expr(reg_2)) {
|
||||||
/* Add immediate to register or memory */
|
/* Add immediate to register or memory */
|
||||||
if ((opc&1) == 0) {
|
if ((opc&1) == 0) {
|
||||||
emit1(0200);
|
emit1(0200);
|
||||||
} else if (! small(exp_2.typ == S_ABS && fitb(exp_2.val),
|
} else if (! small(exp_2.typ == S_ABS && fitb(exp_2.val),
|
||||||
operand_long ? 3 : 1)) {
|
operand_long ? 3 : 1)) {
|
||||||
emit1(0201);
|
emit1(0201);
|
||||||
} else {
|
} else {
|
||||||
emit1(0203); opc &= ~1;
|
emit1(0203); opc &= ~1;
|
||||||
}
|
}
|
||||||
ea_1(opc & 070);
|
ea_1(opc & 070);
|
||||||
RELOMOVE(relonami, rel_2);
|
RELOMOVE(relonami, rel_2);
|
||||||
opsize_exp(exp_2, (opc&1));
|
opsize_exp(exp_2, (opc&1));
|
||||||
} else if (is_reg(reg_1)) {
|
} else if (is_reg(reg_1)) {
|
||||||
/* Add register or memory to register */
|
/* Add register or memory to register */
|
||||||
emit1(opc | 2);
|
emit1(opc | 2);
|
||||||
ea_2((reg_1&7)<<3);
|
ea_2((reg_1&7)<<3);
|
||||||
} else
|
} else
|
||||||
badsyntax();
|
badsyntax();
|
||||||
}
|
}
|
||||||
|
|
||||||
void rolop(register int opc)
|
void rolop(register int opc)
|
||||||
{
|
{
|
||||||
register int oreg;
|
register int oreg;
|
||||||
|
|
||||||
oreg = reg_2;
|
oreg = reg_2;
|
||||||
reg_2 = reg_1;
|
reg_2 = reg_1;
|
||||||
regsize(opc);
|
regsize(opc);
|
||||||
if (oreg == (IS_R8 | 1 | (address_long ? 0 : 0300))) {
|
if (oreg == (IS_R8 | 1 | (address_long ? 0 : 0300))) {
|
||||||
/* cl register */
|
/* cl register */
|
||||||
emit1(0322 | (opc&1)); ea_1(opc&070);
|
emit1(0322 | (opc&1)); ea_1(opc&070);
|
||||||
} else if (is_expr(oreg)) {
|
} else if (is_expr(oreg)) {
|
||||||
if (small(exp_2.typ == S_ABS && exp_2.val == 1, 1)) {
|
if (small(exp_2.typ == S_ABS && exp_2.val == 1, 1)) {
|
||||||
/* shift by 1 */
|
/* shift by 1 */
|
||||||
emit1(0320 | (opc&1)); ea_1(opc&070);
|
emit1(0320 | (opc&1)); ea_1(opc&070);
|
||||||
} else {
|
} else {
|
||||||
/* shift by byte count */
|
/* shift by byte count */
|
||||||
emit1(0300 | (opc & 1));
|
emit1(0300 | (opc & 1));
|
||||||
ea_1(opc & 070);
|
ea_1(opc & 070);
|
||||||
#ifdef RELOCATION
|
#ifdef RELOCATION
|
||||||
RELOMOVE(relonami, rel_2);
|
RELOMOVE(relonami, rel_2);
|
||||||
newrelo(exp_2.typ, RELO1);
|
newrelo(exp_2.typ, RELO1);
|
||||||
#endif
|
#endif
|
||||||
emit1((int)(exp_2.val));
|
emit1((int)(exp_2.val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
badsyntax();
|
badsyntax();
|
||||||
}
|
}
|
||||||
|
|
||||||
void incop(register int opc)
|
void incop(register int opc)
|
||||||
{
|
{
|
||||||
|
|
||||||
regsize(opc);
|
regsize(opc);
|
||||||
if ((opc&1) && is_reg(reg_1)) {
|
if ((opc&1) && is_reg(reg_1)) {
|
||||||
/* word register */
|
/* word register */
|
||||||
emit1(0100 | (opc&010) | (reg_1&7));
|
emit1(0100 | (opc&010) | (reg_1&7));
|
||||||
} else {
|
} else {
|
||||||
emit1(0376 | (opc&1));
|
emit1(0376 | (opc&1));
|
||||||
ea_1(opc & 010);
|
ea_1(opc & 010);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void callop(register int opc)
|
void callop(register int opc)
|
||||||
{
|
{
|
||||||
|
|
||||||
regsize(1);
|
regsize(1);
|
||||||
if (is_expr(reg_1)) {
|
if (is_expr(reg_1)) {
|
||||||
if (opc == (040+(0351<<8))) {
|
if (opc == (040+(0351<<8))) {
|
||||||
RELOMOVE(relonami, rel_1);
|
RELOMOVE(relonami, rel_1);
|
||||||
ebranch(0353,exp_1);
|
ebranch(0353,exp_1);
|
||||||
} else {
|
} else {
|
||||||
exp_1.val -= (DOTVAL+3 + (address_long ? 2 : 0));
|
exp_1.val -= (DOTVAL+3 + (address_long ? 2 : 0));
|
||||||
emit1(opc>>8);
|
emit1(opc>>8);
|
||||||
RELOMOVE(relonami, rel_1);
|
RELOMOVE(relonami, rel_1);
|
||||||
adsize_exp(exp_1, RELPC);
|
adsize_exp(exp_1, RELPC);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
emit1(0377); ea_1(opc&070);
|
emit1(0377); ea_1(opc&070);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void xchg(register int opc)
|
void xchg(register int opc)
|
||||||
{
|
{
|
||||||
|
|
||||||
regsize(opc);
|
regsize(opc);
|
||||||
if (! is_reg(reg_1) || is_acc(reg_2)) {
|
if (! is_reg(reg_1) || is_acc(reg_2)) {
|
||||||
reverse();
|
reverse();
|
||||||
}
|
}
|
||||||
if (opc == 1 && is_acc(reg_1) && is_reg(reg_2)) {
|
if (opc == 1 && is_acc(reg_1) && is_reg(reg_2)) {
|
||||||
emit1(0220 | (reg_2&7));
|
emit1(0220 | (reg_2&7));
|
||||||
} else if (is_reg(reg_1)) {
|
} else if (is_reg(reg_1)) {
|
||||||
emit1(0206 | opc); ea_2((reg_1&7)<<3);
|
emit1(0206 | opc); ea_2((reg_1&7)<<3);
|
||||||
} else
|
} else
|
||||||
badsyntax();
|
badsyntax();
|
||||||
}
|
}
|
||||||
|
|
||||||
void test(register int opc)
|
void test(register int opc)
|
||||||
{
|
{
|
||||||
|
|
||||||
regsize(opc);
|
regsize(opc);
|
||||||
if (is_reg(reg_2) || is_expr(reg_1))
|
if (is_reg(reg_2) || is_expr(reg_1))
|
||||||
reverse();
|
reverse();
|
||||||
if (is_expr(reg_2)) {
|
if (is_expr(reg_2)) {
|
||||||
if (is_acc(reg_1)) {
|
if (is_acc(reg_1)) {
|
||||||
emit1(0250 | opc);
|
emit1(0250 | opc);
|
||||||
RELOMOVE(relonami, rel_2);
|
RELOMOVE(relonami, rel_2);
|
||||||
opsize_exp(exp_2, (opc&1));
|
opsize_exp(exp_2, (opc&1));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
emit1(0366 | opc);
|
emit1(0366 | opc);
|
||||||
ea_1(0<<3);
|
ea_1(0<<3);
|
||||||
RELOMOVE(relonami, rel_2);
|
RELOMOVE(relonami, rel_2);
|
||||||
opsize_exp(exp_2, (opc&1));
|
opsize_exp(exp_2, (opc&1));
|
||||||
}
|
}
|
||||||
} else if (is_reg(reg_1)) {
|
} else if (is_reg(reg_1)) {
|
||||||
emit1(0204 | opc); ea_2((reg_1&7)<<3);
|
emit1(0204 | opc); ea_2((reg_1&7)<<3);
|
||||||
} else
|
} else
|
||||||
badsyntax();
|
badsyntax();
|
||||||
}
|
}
|
||||||
|
|
||||||
void mov(register int opc)
|
void mov(register int opc)
|
||||||
{
|
{
|
||||||
|
|
||||||
regsize(opc);
|
regsize(opc);
|
||||||
if (is_segreg(reg_1)) {
|
if (is_segreg(reg_1)) {
|
||||||
/* to segment register */
|
/* to segment register */
|
||||||
emit1(0216); ea_2((reg_1&07)<<3);
|
emit1(0216); ea_2((reg_1&07)<<3);
|
||||||
} else if (is_segreg(reg_2)) {
|
} else if (is_segreg(reg_2)) {
|
||||||
/* from segment register */
|
/* from segment register */
|
||||||
emit1(0214); ea_1((reg_2&07)<<3);
|
emit1(0214); ea_1((reg_2&07)<<3);
|
||||||
} else if (is_expr(reg_2)) {
|
} else if (is_expr(reg_2)) {
|
||||||
/* from immediate */
|
/* from immediate */
|
||||||
if (is_reg(reg_1)) {
|
if (is_reg(reg_1)) {
|
||||||
/* to register */
|
/* to register */
|
||||||
emit1(0260 | opc<<3 | (reg_1&7));
|
emit1(0260 | opc<<3 | (reg_1&7));
|
||||||
} else {
|
} else {
|
||||||
/* to memory */
|
/* to memory */
|
||||||
emit1(0306 | opc); ea_1(0<<3);
|
emit1(0306 | opc); ea_1(0<<3);
|
||||||
}
|
}
|
||||||
RELOMOVE(relonami, rel_2);
|
RELOMOVE(relonami, rel_2);
|
||||||
opsize_exp(exp_2, (opc&1));
|
opsize_exp(exp_2, (opc&1));
|
||||||
} else if (rm_1 == 05 && is_acc(reg_2)) {
|
} else if (rm_1 == 05 && is_acc(reg_2)) {
|
||||||
/* from accumulator to memory (displacement) */
|
/* from accumulator to memory (displacement) */
|
||||||
emit1(0242 | opc);
|
emit1(0242 | opc);
|
||||||
RELOMOVE(relonami, rel_1);
|
RELOMOVE(relonami, rel_1);
|
||||||
adsize_exp(exp_1, 0);
|
adsize_exp(exp_1, 0);
|
||||||
} else if (rm_2 == 05 && is_acc(reg_1)) {
|
} else if (rm_2 == 05 && is_acc(reg_1)) {
|
||||||
/* from memory (displacement) to accumulator */
|
/* from memory (displacement) to accumulator */
|
||||||
emit1(0240 | opc);
|
emit1(0240 | opc);
|
||||||
RELOMOVE(relonami, rel_2);
|
RELOMOVE(relonami, rel_2);
|
||||||
adsize_exp(exp_2, 0);
|
adsize_exp(exp_2, 0);
|
||||||
} else if (is_reg(reg_2)) {
|
} else if (is_reg(reg_2)) {
|
||||||
/* from register to memory or register */
|
/* from register to memory or register */
|
||||||
emit1(0210 | opc); ea_1((reg_2&07)<<3);
|
emit1(0210 | opc); ea_1((reg_2&07)<<3);
|
||||||
} else if (is_reg(reg_1)) {
|
} else if (is_reg(reg_1)) {
|
||||||
/* from memory or register to register */
|
/* from memory or register to register */
|
||||||
emit1(0212 | opc); ea_2((reg_1&07)<<3);
|
emit1(0212 | opc); ea_2((reg_1&07)<<3);
|
||||||
} else
|
} else
|
||||||
badsyntax();
|
badsyntax();
|
||||||
}
|
}
|
||||||
|
|
||||||
void extshft(int opc, int reg)
|
void extshft(int opc, int reg)
|
||||||
{
|
{
|
||||||
int oreg2 = reg_2;
|
int oreg2 = reg_2;
|
||||||
|
|
||||||
reg_2 = reg_1;
|
reg_2 = reg_1;
|
||||||
regsize(1);
|
regsize(1);
|
||||||
|
|
||||||
emit1(0xF);
|
emit1(0xF);
|
||||||
if (oreg2 == (IS_R8 | 1 | (address_long ? 0 : 0300))) {
|
if (oreg2 == (IS_R8 | 1 | (address_long ? 0 : 0300))) {
|
||||||
/* cl register */
|
/* cl register */
|
||||||
emit1(opc|1);
|
emit1(opc|1);
|
||||||
ea_1(reg << 3);
|
ea_1(reg << 3);
|
||||||
}
|
}
|
||||||
else if (is_expr(oreg2)) {
|
else if (is_expr(oreg2)) {
|
||||||
emit1(opc);
|
emit1(opc);
|
||||||
ea_1(reg << 3);
|
ea_1(reg << 3);
|
||||||
#ifdef RELOCATION
|
#ifdef RELOCATION
|
||||||
RELOMOVE(relonami, rel_2);
|
RELOMOVE(relonami, rel_2);
|
||||||
newrelo(exp_2.typ, RELO1);
|
newrelo(exp_2.typ, RELO1);
|
||||||
#endif
|
#endif
|
||||||
emit1((int)(exp_2.val));
|
emit1((int)(exp_2.val));
|
||||||
}
|
}
|
||||||
else badsyntax();
|
else badsyntax();
|
||||||
}
|
}
|
||||||
|
|
||||||
void bittestop(int opc)
|
void bittestop(int opc)
|
||||||
{
|
{
|
||||||
regsize(1);
|
regsize(1);
|
||||||
emit1(0xF);
|
emit1(0xF);
|
||||||
if (is_expr(reg_2)) {
|
if (is_expr(reg_2)) {
|
||||||
emit1(0272);
|
emit1(0272);
|
||||||
ea_1(opc << 3);
|
ea_1(opc << 3);
|
||||||
#ifdef RELOCATION
|
#ifdef RELOCATION
|
||||||
RELOMOVE(relonami, rel_2);
|
RELOMOVE(relonami, rel_2);
|
||||||
newrelo(exp_2.typ, RELO1);
|
newrelo(exp_2.typ, RELO1);
|
||||||
#endif
|
#endif
|
||||||
emit1((int)(exp_2.val));
|
emit1((int)(exp_2.val));
|
||||||
}
|
}
|
||||||
else if (is_reg(reg_2)) {
|
else if (is_reg(reg_2)) {
|
||||||
emit1(0203 | (opc<<3));
|
emit1(0203 | (opc<<3));
|
||||||
ea_1((reg_2&7)<<3);
|
ea_1((reg_2&7)<<3);
|
||||||
}
|
}
|
||||||
else badsyntax();
|
else badsyntax();
|
||||||
}
|
}
|
||||||
|
|
||||||
void imul(int reg)
|
void imul(int reg)
|
||||||
{
|
{
|
||||||
/* This instruction is more elaborate on the 80386. Its most
|
/* This instruction is more elaborate on the 80386. Its most
|
||||||
general form is:
|
general form is:
|
||||||
imul reg, reg_or_mem, immediate.
|
imul reg, reg_or_mem, immediate.
|
||||||
This is the form processed here.
|
This is the form processed here.
|
||||||
*/
|
*/
|
||||||
regsize(1);
|
regsize(1);
|
||||||
if (is_expr(reg_1)) {
|
if (is_expr(reg_1)) {
|
||||||
/* To also handle
|
/* To also handle
|
||||||
imul reg, immediate, reg_or_mem
|
imul reg, immediate, reg_or_mem
|
||||||
*/
|
*/
|
||||||
reverse();
|
reverse();
|
||||||
}
|
}
|
||||||
if (is_expr(reg_2)) {
|
if (is_expr(reg_2)) {
|
||||||
/* The immediate form; two cases: */
|
/* The immediate form; two cases: */
|
||||||
if (small(exp_2.typ == S_ABS && fitb(exp_2.val),
|
if (small(exp_2.typ == S_ABS && fitb(exp_2.val),
|
||||||
operand_long ? 3 : 1)) {
|
operand_long ? 3 : 1)) {
|
||||||
/* case 1: 1 byte encoding of immediate */
|
/* case 1: 1 byte encoding of immediate */
|
||||||
emit1(0153);
|
emit1(0153);
|
||||||
ea_1((reg & 07) << 3);
|
ea_1((reg & 07) << 3);
|
||||||
emit1((int)(exp_2.val));
|
emit1((int)(exp_2.val));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* case 2: WORD or DWORD encoding of immediate */
|
/* case 2: WORD or DWORD encoding of immediate */
|
||||||
emit1(0151);
|
emit1(0151);
|
||||||
ea_1((reg & 07) << 3);
|
ea_1((reg & 07) << 3);
|
||||||
RELOMOVE(relonami, rel_2);
|
RELOMOVE(relonami, rel_2);
|
||||||
opsize_exp(exp_2, 1);
|
opsize_exp(exp_2, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (is_reg(reg_1) && ((reg_1&7) == (reg & 07))) {
|
else if (is_reg(reg_1) && ((reg_1&7) == (reg & 07))) {
|
||||||
/* the "reg" field and the "reg_or_mem" field are the same,
|
/* the "reg" field and the "reg_or_mem" field are the same,
|
||||||
and the 3rd operand is not an immediate ...
|
and the 3rd operand is not an immediate ...
|
||||||
*/
|
*/
|
||||||
if (reg == 0) {
|
if (reg == 0) {
|
||||||
/* how lucky we are, the target is the ax register */
|
/* how lucky we are, the target is the ax register */
|
||||||
/* However, we cannot make an optimization for f.i.
|
/* However, we cannot make an optimization for f.i.
|
||||||
imul eax, blablabla
|
imul eax, blablabla
|
||||||
because the latter does not affect edx, whereas
|
because the latter does not affect edx, whereas
|
||||||
imul blablabla
|
imul blablabla
|
||||||
does! Therefore, "reg" is or-ed with 0x10 in the
|
does! Therefore, "reg" is or-ed with 0x10 in the
|
||||||
former case, so that the test above fails.
|
former case, so that the test above fails.
|
||||||
*/
|
*/
|
||||||
emit1(0367);
|
emit1(0367);
|
||||||
ea_2(050);
|
ea_2(050);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* another register ... */
|
/* another register ... */
|
||||||
emit1(0xF);
|
emit1(0xF);
|
||||||
emit1(0257);
|
emit1(0257);
|
||||||
ea_2((reg & 07) << 3);
|
ea_2((reg & 07) << 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else badsyntax();
|
else badsyntax();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// vim: ts=8 sw=8 et
|
||||||
|
|
||||||
|
|
|
@ -86,6 +86,9 @@ char* remember(char* s)
|
||||||
|
|
||||||
int combine(int typ1, int typ2, int op)
|
int combine(int typ1, int typ2, int op)
|
||||||
{
|
{
|
||||||
|
typ1 &= ~S_VAR;
|
||||||
|
typ2 &= ~S_VAR;
|
||||||
|
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case '+':
|
case '+':
|
||||||
|
|
|
@ -78,7 +78,7 @@ for _, plat in ipairs({"cpm"}) do
|
||||||
},
|
},
|
||||||
outleaves = { n..".s" },
|
outleaves = { n..".s" },
|
||||||
commands = {
|
commands = {
|
||||||
"$LUA %{ins[1]} <%{ins[2]} >%{outs}"
|
"$(LUA) %{ins[1]} <%{ins[2]} >%{outs}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
#ifndef PMAP_H
|
#ifndef PMAP_H
|
||||||
#define PMAP_H
|
#define PMAP_H
|
||||||
|
|
||||||
|
/* A bidirectional multimap, storing (left, right) tuples.
|
||||||
|
*/
|
||||||
|
|
||||||
struct pmap_node
|
struct pmap_node
|
||||||
{
|
{
|
||||||
void* left;
|
void* left;
|
||||||
|
@ -23,10 +26,33 @@ struct pmap
|
||||||
int max; \
|
int max; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Adds a new relation `(left -> right)` to the map
|
||||||
|
* if `left` is not present. Otherwise replaces the
|
||||||
|
* `right` associated with the first `left`.
|
||||||
|
*
|
||||||
|
* Use this in normal map mode.
|
||||||
|
*/
|
||||||
extern void pmap_put(void* map, void* left, void* right);
|
extern void pmap_put(void* map, void* left, void* right);
|
||||||
|
|
||||||
|
/** Adds a new relation to the map if that relation does
|
||||||
|
* not already exist.
|
||||||
|
*
|
||||||
|
* Use this in multimap mode.
|
||||||
|
*/
|
||||||
extern void pmap_add(void* map, void* left, void* right);
|
extern void pmap_add(void* map, void* left, void* right);
|
||||||
|
|
||||||
|
/** Removes a relation from the map.
|
||||||
|
*
|
||||||
|
* Use this in multimap mode.
|
||||||
|
*/
|
||||||
extern void pmap_remove(void* map, void* left, void* right);
|
extern void pmap_remove(void* map, void* left, void* right);
|
||||||
|
|
||||||
|
/** Given a `left`, find the first matching `right`.
|
||||||
|
*/
|
||||||
extern void* pmap_findleft(void* map, void* left);
|
extern void* pmap_findleft(void* map, void* left);
|
||||||
|
|
||||||
|
/** Given a `right`, find the first matching `left`.
|
||||||
|
*/
|
||||||
extern void* pmap_findright(void* map, void* right);
|
extern void* pmap_findright(void* map, void* right);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#ifndef SMAP_H
|
#ifndef SMAP_H
|
||||||
#define SMAP_H
|
#define SMAP_H
|
||||||
|
|
||||||
|
/* A string multimap (each key can have multiple values). */
|
||||||
|
|
||||||
struct smap_node
|
struct smap_node
|
||||||
{
|
{
|
||||||
const char* left;
|
const char* left;
|
||||||
|
@ -28,24 +30,33 @@ struct smap
|
||||||
int max; \
|
int max; \
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Initializes a string map and returns the initialized
|
/** Initializes a string map. Optional; a zero-initialised map
|
||||||
* handle in `mapp`.
|
* structure is a valid empty map.
|
||||||
*/
|
*/
|
||||||
extern void smap_init(void *mapp);
|
extern void smap_init(void *mapp);
|
||||||
/** Adds a new item with name `key` in the string map if
|
|
||||||
* it does not already exist, otherwise replaces the
|
/** Adds a new item with name `key` in the string map if it does not already
|
||||||
* value `value` associated with the existing `key`.
|
* exist. Otherwise replaces the value `value` associated with the existing
|
||||||
|
* `key`.
|
||||||
|
*
|
||||||
|
* Use this for normal map mode.
|
||||||
*/
|
*/
|
||||||
extern void smap_put(void *mapp, const char* key, void* value);
|
extern void smap_put(void *mapp, const char* key, void* value);
|
||||||
/** Adds a new item in a string map only if `key` does
|
|
||||||
* not already exist in the string map.
|
/** Adds a new item with name `key` and value `value`. If that relation already
|
||||||
|
* exists, nothing happens.
|
||||||
|
*
|
||||||
|
* Use this for multimap mode.
|
||||||
*/
|
*/
|
||||||
extern void smap_add(void *mapp, const char* key, void* value);
|
extern void smap_add(void *mapp, const char* key, void* value);
|
||||||
/** Returns the value associated with the specified `key`, returns
|
|
||||||
* NULL if `key` is not present in the string map.
|
/** Returns the first value associated with the specified `key`. Returns NULL
|
||||||
|
* if `key` is not present in the string map.
|
||||||
*
|
*
|
||||||
|
* Use this in normal map mode.
|
||||||
*/
|
*/
|
||||||
extern void* smap_get(void* mapp, const char* key);
|
extern void* smap_get(void* mapp, const char* key);
|
||||||
|
|
||||||
/** Frees the data structure associated with the string map.
|
/** Frees the data structure associated with the string map.
|
||||||
* Also frees the memory associated with the key if
|
* Also frees the memory associated with the key if
|
||||||
* `free_key` is non-zero, and free the memory associated
|
* `free_key` is non-zero, and free the memory associated
|
||||||
|
|
|
@ -39,7 +39,7 @@ void stringlist_free(struct stringlist* list, int freedata)
|
||||||
struct stringfragment* next = f->next;
|
struct stringfragment* next = f->next;
|
||||||
if (freedata)
|
if (freedata)
|
||||||
{
|
{
|
||||||
free(f->data);
|
free((void*) f->data);
|
||||||
f->data = NULL;
|
f->data = NULL;
|
||||||
}
|
}
|
||||||
free(f);
|
free(f);
|
||||||
|
@ -54,7 +54,7 @@ void stringlist_init(struct stringlist* list)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char* stringlist_get(struct stringlist *list, int index)
|
const char* stringlist_get(struct stringlist *list, int index)
|
||||||
{
|
{
|
||||||
struct stringfragment* f = list->first;
|
struct stringfragment* f = list->first;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
struct stringfragment
|
struct stringfragment
|
||||||
{
|
{
|
||||||
char* data;
|
const char* data;
|
||||||
struct stringfragment* next;
|
struct stringfragment* next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ extern void stringlist_addall(struct stringlist* list, struct stringlist* src);
|
||||||
extern void stringlist_free(struct stringlist* list, int freedata);
|
extern void stringlist_free(struct stringlist* list, int freedata);
|
||||||
extern void stringlist_init(struct stringlist* list);
|
extern void stringlist_init(struct stringlist* list);
|
||||||
extern int stringlist_count(struct stringlist *list);
|
extern int stringlist_count(struct stringlist *list);
|
||||||
extern char* stringlist_get(struct stringlist *list, int index);
|
extern const char* stringlist_get(struct stringlist *list, int index);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -8,7 +8,7 @@ normalrule {
|
||||||
},
|
},
|
||||||
outleaves = { "em_codeEK.h" },
|
outleaves = { "em_codeEK.h" },
|
||||||
commands = {
|
commands = {
|
||||||
"$LUA %{ins[1]} < %{ins[3]} > %{outs}",
|
"$(LUA) %{ins[1]} < %{ins[3]} > %{outs}",
|
||||||
"cat %{ins[4]} >> %{outs}"
|
"cat %{ins[4]} >> %{outs}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ for _, f in ipairs(GENFILES) do
|
||||||
"h+emheaders"
|
"h+emheaders"
|
||||||
},
|
},
|
||||||
commands = {
|
commands = {
|
||||||
"$LUA %{ins[1]} < %{ins[3]} > %{outs}"
|
"$(LUA) %{ins[1]} < %{ins[3]} > %{outs}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,7 +7,7 @@ normalrule {
|
||||||
},
|
},
|
||||||
outleaves = "C_mnem_narg.h",
|
outleaves = "C_mnem_narg.h",
|
||||||
commands = {
|
commands = {
|
||||||
"$LUA %{ins[1]} < %{ins[3]} > %{outs}"
|
"$(LUA) %{ins[1]} < %{ins[3]} > %{outs}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ normalrule {
|
||||||
},
|
},
|
||||||
outleaves = "C_mnem.h",
|
outleaves = "C_mnem.h",
|
||||||
commands = {
|
commands = {
|
||||||
"$LUA %{ins[1]} < %{ins[3]} > %{outs}"
|
"$(LUA) %{ins[1]} < %{ins[3]} > %{outs}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
include("tests/plat/build.lua")
|
|
||||||
|
|
||||||
plat_testsuite {
|
|
||||||
name = "tests",
|
|
||||||
plat = "linux386",
|
|
||||||
method = "qemu-i386"
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
include("tests/plat/build.lua")
|
|
||||||
|
|
||||||
plat_testsuite {
|
|
||||||
name = "tests",
|
|
||||||
plat = "linuxmips",
|
|
||||||
method = "qemu-mipsel",
|
|
||||||
skipsets = {
|
|
||||||
"long-long",
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -325,6 +325,12 @@ void dump_state(FILE* stream)
|
||||||
fprintf(stream, "\n");
|
fprintf(stream, "\n");
|
||||||
fprintf(stream, "gpr%02d=0x%08x ", i, cpu.gpr[i]);
|
fprintf(stream, "gpr%02d=0x%08x ", i, cpu.gpr[i]);
|
||||||
}
|
}
|
||||||
|
for (i=0; i<32; i++)
|
||||||
|
{
|
||||||
|
if ((i % 3) == 0)
|
||||||
|
fprintf(stream, "\n");
|
||||||
|
fprintf(stream, "fpr%02d=0x%016lx ", i, cpu.fpr[i]);
|
||||||
|
}
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
|
|
||||||
/* This might fail and cause a reentrant trap if cia is invalid, so
|
/* This might fail and cause a reentrant trap if cia is invalid, so
|
||||||
|
|
|
@ -207,5 +207,5 @@
|
||||||
|
|
||||||
# Floating point conversions
|
# Floating point conversions
|
||||||
|
|
||||||
<63--><FRT>.....<FRB><14------>R setcr1(R, fpr(FRB)); cpu.fpr[FRT] = (uint32_t)fpr(FRB);
|
<63--><FRT>.....<FRB><14------>R setcr1(R, fpr(FRB)); cpu.fpr[FRT] = (uint32_t)(int32_t)fpr(FRB);
|
||||||
<63--><FRT>.....<FRB><15------>R setcr1(R, fpr(FRB)); cpu.fpr[FRT] = (uint32_t)fpr(FRB);
|
<63--><FRT>.....<FRB><15------>R setcr1(R, fpr(FRB)); cpu.fpr[FRT] = (uint32_t)(int32_t)fpr(FRB);
|
||||||
|
|
11
plat/msdos/include/ack/plat.h
Normal file
11
plat/msdos/include/ack/plat.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
/* $Source$
|
||||||
|
* $State$
|
||||||
|
* $Revision$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _ACK_PLAT_H
|
||||||
|
#define _ACK_PLAT_H
|
||||||
|
|
||||||
|
#define ACKCONF_WANT_O_TEXT_O_BINARY 1
|
||||||
|
|
||||||
|
#endif
|
24
plat/msdos/include/build.lua
Normal file
24
plat/msdos/include/build.lua
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
include("plat/build.lua")
|
||||||
|
|
||||||
|
headermap = {}
|
||||||
|
packagemap = {}
|
||||||
|
|
||||||
|
local function addheader(h)
|
||||||
|
headermap[h] = "./"..h
|
||||||
|
packagemap["$(PLATIND)/msdos86/include/"..h] = "./"..h
|
||||||
|
end
|
||||||
|
|
||||||
|
addheader("ack/plat.h")
|
||||||
|
addheader("sys/types.h")
|
||||||
|
|
||||||
|
acklibrary {
|
||||||
|
name = "headers",
|
||||||
|
hdrs = headermap
|
||||||
|
}
|
||||||
|
|
||||||
|
installable {
|
||||||
|
name = "pkg",
|
||||||
|
map = packagemap
|
||||||
|
}
|
||||||
|
|
||||||
|
|
9
plat/msdos/include/sys/types.h
Normal file
9
plat/msdos/include/sys/types.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#ifndef _SYS_TYPES_H
|
||||||
|
#define _SYS_TYPES_H
|
||||||
|
|
||||||
|
typedef long pid_t;
|
||||||
|
typedef int mode_t;
|
||||||
|
typedef long time_t;
|
||||||
|
typedef long suseconds_t;
|
||||||
|
|
||||||
|
#endif
|
28
plat/msdos/libsys/build.lua
Normal file
28
plat/msdos/libsys/build.lua
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
bundle {
|
||||||
|
name = "srcs",
|
||||||
|
srcs = {
|
||||||
|
"./creat.c",
|
||||||
|
"./gettimeofday.c",
|
||||||
|
"./kill.c",
|
||||||
|
"./lseek.c",
|
||||||
|
"./open.c",
|
||||||
|
"./read.c",
|
||||||
|
"./setmode.c",
|
||||||
|
"./signal.c",
|
||||||
|
"./sys_fdmodes.c",
|
||||||
|
"./sys_getmode.c",
|
||||||
|
"./sys_initmain.c",
|
||||||
|
"./sys_iseof.c",
|
||||||
|
"./sys_seteof.c",
|
||||||
|
"./sys_seterrno.c",
|
||||||
|
"./sys_setmode.c",
|
||||||
|
"./write.c",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bundle {
|
||||||
|
name = "headers",
|
||||||
|
srcs = {
|
||||||
|
"./libsys.h"
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -16,9 +17,7 @@ ssize_t read(int fd, void* buffer, size_t count)
|
||||||
ssize_t r, tot;
|
ssize_t r, tot;
|
||||||
size_t left;
|
size_t left;
|
||||||
int eof = 0;
|
int eof = 0;
|
||||||
|
bool text = _sys_getmode(fd) == O_TEXT;
|
||||||
if (!count || _sys_getmode(fd) == O_BINARY)
|
|
||||||
return _sys_rawread(fd, buffer, count);
|
|
||||||
|
|
||||||
if (_sys_iseof(fd))
|
if (_sys_iseof(fd))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -47,33 +46,36 @@ ssize_t read(int fd, void* buffer, size_t count)
|
||||||
if (r <= 0)
|
if (r <= 0)
|
||||||
return tot ? tot : r;
|
return tot ? tot : r;
|
||||||
|
|
||||||
q = memchr(p, 0x1a, (size_t)r);
|
if (text)
|
||||||
if (q)
|
|
||||||
{
|
{
|
||||||
_sys_rawlseek(fd, (off_t)(q - p) - r, SEEK_CUR);
|
q = memchr(p, 0x1a, (size_t)r);
|
||||||
r = q - p;
|
if (q)
|
||||||
eof = 1;
|
|
||||||
_sys_seteof(fd, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
q = memchr(p, '\r', (size_t)r);
|
|
||||||
if (!q)
|
|
||||||
return tot + r;
|
|
||||||
|
|
||||||
tot += q - p;
|
|
||||||
left = r - (q + 1 - p);
|
|
||||||
p = q;
|
|
||||||
++q;
|
|
||||||
|
|
||||||
while (left)
|
|
||||||
{
|
|
||||||
char c = *q++;
|
|
||||||
if (c != '\r')
|
|
||||||
{
|
{
|
||||||
*p++ = c;
|
_sys_rawlseek(fd, (off_t)(q - p) - r, SEEK_CUR);
|
||||||
++tot;
|
r = q - p;
|
||||||
|
eof = 1;
|
||||||
|
_sys_seteof(fd, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
q = memchr(p, '\r', (size_t)r);
|
||||||
|
if (!q)
|
||||||
|
return tot + r;
|
||||||
|
|
||||||
|
tot += q - p;
|
||||||
|
left = r - (q + 1 - p);
|
||||||
|
p = q;
|
||||||
|
++q;
|
||||||
|
|
||||||
|
while (left)
|
||||||
|
{
|
||||||
|
char c = *q++;
|
||||||
|
if (c != '\r')
|
||||||
|
{
|
||||||
|
*p++ = c;
|
||||||
|
++tot;
|
||||||
|
}
|
||||||
|
--left;
|
||||||
}
|
}
|
||||||
--left;
|
|
||||||
}
|
}
|
||||||
} while (tot < count && !eof && _sys_isreadyr(fd));
|
} while (tot < count && !eof && _sys_isreadyr(fd));
|
||||||
|
|
|
@ -35,7 +35,7 @@ static const signed char err_map[] =
|
||||||
* Map an MS-DOS 2+ system error code to an `errno' value and store that in
|
* Map an MS-DOS 2+ system error code to an `errno' value and store that in
|
||||||
* `errno'. Return a longword -1.
|
* `errno'. Return a longword -1.
|
||||||
*/
|
*/
|
||||||
long _sys_seterrno(unsigned dos_err)
|
long _sys_seterrno(unsigned short dos_err)
|
||||||
{
|
{
|
||||||
if (dos_err < sizeof(err_map) / sizeof(err_map[0]))
|
if (dos_err < sizeof(err_map) / sizeof(err_map[0]))
|
||||||
errno = err_map[dos_err];
|
errno = err_map[dos_err];
|
74
plat/msdos/libsys/write.c
Normal file
74
plat/msdos/libsys/write.c
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
/* $Source$
|
||||||
|
* $State$
|
||||||
|
* $Revision$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "libsys.h"
|
||||||
|
|
||||||
|
ssize_t write(int fd, void* buffer, size_t count)
|
||||||
|
{
|
||||||
|
static const char crlf[2] = "\r\n";
|
||||||
|
int i;
|
||||||
|
char *p, *q;
|
||||||
|
size_t left, n;
|
||||||
|
ssize_t r, tot;
|
||||||
|
|
||||||
|
if (!count)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
p = buffer;
|
||||||
|
left = count;
|
||||||
|
tot = 0;
|
||||||
|
|
||||||
|
if (_sys_getmode(fd) == O_BINARY)
|
||||||
|
{
|
||||||
|
while (left)
|
||||||
|
{
|
||||||
|
r = _sys_rawwrite(fd, p, left);
|
||||||
|
if (r <= 0)
|
||||||
|
return tot ? tot : r;
|
||||||
|
tot += r;
|
||||||
|
p += r;
|
||||||
|
left -= r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* If the file descriptor is an O_TEXT fd, translate LFs to CRLFs. */
|
||||||
|
while (left)
|
||||||
|
{
|
||||||
|
q = memchr(p, '\n', left);
|
||||||
|
if (!q)
|
||||||
|
return _sys_rawwrite(fd, p, left);
|
||||||
|
|
||||||
|
n = q - p;
|
||||||
|
if (n)
|
||||||
|
{
|
||||||
|
r = _sys_rawwrite(fd, p, n);
|
||||||
|
if (r <= 0)
|
||||||
|
return tot ? tot : r;
|
||||||
|
tot += r;
|
||||||
|
p += r;
|
||||||
|
left -= r;
|
||||||
|
if (r != n)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = _sys_rawwrite(fd, crlf, sizeof crlf);
|
||||||
|
if (r != 2)
|
||||||
|
{
|
||||||
|
if (r > 0)
|
||||||
|
r = 0;
|
||||||
|
return tot ? tot : r;
|
||||||
|
}
|
||||||
|
++tot;
|
||||||
|
++p;
|
||||||
|
--left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tot;
|
||||||
|
}
|
24
plat/msdos386/README
Normal file
24
plat/msdos386/README
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
The msdos386 platform
|
||||||
|
=====================
|
||||||
|
|
||||||
|
msdos386 is an i386-based BSP that produces DPMI DOS executables. It should
|
||||||
|
have the same functionality as msdos86 (as the libc is all the same code), but
|
||||||
|
has been much less well tested.
|
||||||
|
|
||||||
|
The code runs in flat 32-bit mode, so normal 32-bit pointers work with no
|
||||||
|
worries about segmentation. It requires a DPMI host to run; it was tested with
|
||||||
|
CWSDPMI. It will _not_ automatically load the host --- you need to manually
|
||||||
|
install the DPMI hsot first.
|
||||||
|
|
||||||
|
IEEE floating point is available, but requires an FPU.
|
||||||
|
|
||||||
|
|
||||||
|
Example command line
|
||||||
|
====================
|
||||||
|
|
||||||
|
ack -mmsdos386 -O -o msdos386.exe examples/paranoia.c
|
||||||
|
|
||||||
|
|
||||||
|
David Given
|
||||||
|
dg@cowlark.com
|
||||||
|
|
235
plat/msdos386/boot.s
Normal file
235
plat/msdos386/boot.s
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
! Declare segments (the order is important).
|
||||||
|
|
||||||
|
.sect .text
|
||||||
|
.sect .rom
|
||||||
|
.sect .data
|
||||||
|
.sect .bss
|
||||||
|
|
||||||
|
.sect .text
|
||||||
|
#define STACK_BUFFER 128 /* number of bytes to leave for stack */
|
||||||
|
|
||||||
|
! g 18b to break at the retf before coming here
|
||||||
|
begtext:
|
||||||
|
! On entry, the stub has cs and ds pointing at the 32-bit
|
||||||
|
! segment, but ss is still pointing at the 16-bit segment.
|
||||||
|
!
|
||||||
|
! ax: pmode code segment of stub
|
||||||
|
! bx: pmode data segment of stub
|
||||||
|
! cx: rmode segment of stub
|
||||||
|
! dx: pointer to realloc routine (in stub)
|
||||||
|
! si: pointer to interrupt routine (in stub)
|
||||||
|
! di: pointer to transfer buffer (in stub)
|
||||||
|
! bp: rmode PSP segment
|
||||||
|
|
||||||
|
! Resize the segment to include the BSS.
|
||||||
|
|
||||||
|
o16 mov (realloc_ptr+4), ax
|
||||||
|
mov (realloc_ptr+0), edx
|
||||||
|
o16 mov (pmode_cs), ax
|
||||||
|
o16 mov (pmode_ds), bx
|
||||||
|
o16 mov (rmode), cx
|
||||||
|
o16 mov (interrupt_ptr+4), ax
|
||||||
|
mov (interrupt_ptr+0), esi
|
||||||
|
o16 mov (transfer_buffer_ptr), di
|
||||||
|
|
||||||
|
mov eax, __end
|
||||||
|
callf (realloc_ptr)
|
||||||
|
|
||||||
|
! Clear BSS.
|
||||||
|
|
||||||
|
mov edi, begbss
|
||||||
|
mov ecx, endbss+3
|
||||||
|
sub ecx, edi
|
||||||
|
shr ecx, 2
|
||||||
|
xor eax, eax
|
||||||
|
cld
|
||||||
|
rep stos
|
||||||
|
|
||||||
|
! It's now safe to switch stacks.
|
||||||
|
|
||||||
|
cli
|
||||||
|
mov eax, ds
|
||||||
|
mov ss, eax
|
||||||
|
mov sp, .stack
|
||||||
|
sti
|
||||||
|
|
||||||
|
! Create a handle for low 1MB access.
|
||||||
|
|
||||||
|
o16 mov ax, 0x0000
|
||||||
|
o16 mov cx, 1
|
||||||
|
int 0x31 ! allocate LDT
|
||||||
|
o16 mov (.doshandle), ax
|
||||||
|
mov es, ax
|
||||||
|
xchg ebx, eax
|
||||||
|
|
||||||
|
xor ecx, ecx
|
||||||
|
xor edx, edx
|
||||||
|
o16 mov ax, 0x0007
|
||||||
|
int 0x31 ! set base address to 0
|
||||||
|
o16 dec dx
|
||||||
|
o16 mov cx, 0x000f
|
||||||
|
o16 mov ax, 0x0008
|
||||||
|
int 0x31 ! set limit to 1MB
|
||||||
|
|
||||||
|
mov cx, ds
|
||||||
|
and cx, 3
|
||||||
|
shl cx, 5
|
||||||
|
or cx, 0xc093 ! 32-bit, big, data, r/w, expand-up
|
||||||
|
mov ax, 0x0009
|
||||||
|
int 0x31 ! set descriptor access rights
|
||||||
|
|
||||||
|
! Locate the PSP.
|
||||||
|
|
||||||
|
movzx esi, bp
|
||||||
|
shl esi, 4 ! convert to linear address
|
||||||
|
|
||||||
|
! Copy the whole thing into 32-bit memory.
|
||||||
|
|
||||||
|
mov ecx, 0x100/4
|
||||||
|
mov edi, .psp
|
||||||
|
cld
|
||||||
|
1:
|
||||||
|
eseg lods
|
||||||
|
mov (edi), eax
|
||||||
|
add edi, 4
|
||||||
|
loop 1b
|
||||||
|
|
||||||
|
! Find the environment.
|
||||||
|
|
||||||
|
mov es, (.psp + 0x002C) ! converted to pmode segment
|
||||||
|
|
||||||
|
! Count the size of the environment variable block.
|
||||||
|
|
||||||
|
xorb al, al ! byte to test for
|
||||||
|
xor edi, edi
|
||||||
|
xor edx, edx
|
||||||
|
cld
|
||||||
|
mov ecx, -1
|
||||||
|
scasb
|
||||||
|
jz 2f ! empty environment
|
||||||
|
1:
|
||||||
|
repnz scasb
|
||||||
|
inc edx
|
||||||
|
scasb
|
||||||
|
jnz 1b
|
||||||
|
2:
|
||||||
|
add edi, 2 ! skip the mysterious word
|
||||||
|
repnz scasb ! program name
|
||||||
|
|
||||||
|
! Copy the whole environment block onto the stack.
|
||||||
|
|
||||||
|
mov esi, edi
|
||||||
|
add esi, 3
|
||||||
|
and esi, ~3 ! round up
|
||||||
|
jz empty_environment
|
||||||
|
mov ecx, esi
|
||||||
|
shr ecx, 2 ! number of dwords
|
||||||
|
std
|
||||||
|
sub esi, 4
|
||||||
|
1:
|
||||||
|
eseg lods
|
||||||
|
push eax
|
||||||
|
loop 1b
|
||||||
|
empty_environment:
|
||||||
|
mov ecx, esp ! environment data
|
||||||
|
|
||||||
|
! Reset DF and es properly.
|
||||||
|
|
||||||
|
cld
|
||||||
|
push ss
|
||||||
|
pop es
|
||||||
|
|
||||||
|
! Reserve space for argc and the argv and envp pointers on the
|
||||||
|
! stack. These will be passed to __m_a_i_n later.
|
||||||
|
|
||||||
|
sub esp, 3*4
|
||||||
|
mov eax, esp
|
||||||
|
|
||||||
|
! Build up argc, argv[], and envp[].
|
||||||
|
push eax ! output buffer for argc, argv, envp
|
||||||
|
push 3 ! MS-DOS version
|
||||||
|
push ecx ! env. string data
|
||||||
|
push edx ! count of env. vars.
|
||||||
|
push .psp+0x80 ! raw command line
|
||||||
|
call __sys_initmain
|
||||||
|
add esp, 5*4
|
||||||
|
|
||||||
|
! Bail out if something went wrong.
|
||||||
|
test eax, eax
|
||||||
|
jnz no_room
|
||||||
|
|
||||||
|
! argc, argv, and envp are now at the stack top. Now go.
|
||||||
|
call __m_a_i_n
|
||||||
|
add sp, 3*4
|
||||||
|
push ax
|
||||||
|
call _exit
|
||||||
|
|
||||||
|
no_room:
|
||||||
|
mov dx, no_room_msg
|
||||||
|
!call dos_msg
|
||||||
|
movb al, -1
|
||||||
|
jmp al_exit
|
||||||
|
|
||||||
|
! Exit.
|
||||||
|
.define __exit
|
||||||
|
.extern __exit
|
||||||
|
.define EXIT
|
||||||
|
.extern EXIT
|
||||||
|
__exit:
|
||||||
|
EXIT:
|
||||||
|
pop bx
|
||||||
|
pop ax
|
||||||
|
al_exit:
|
||||||
|
movb ah, 0x4c
|
||||||
|
int 0x21
|
||||||
|
|
||||||
|
! These must be in the code segment due to bootstrap issues.
|
||||||
|
realloc_ptr: .space 6 ! far
|
||||||
|
interrupt_ptr: .space 6 ! far
|
||||||
|
transfer_buffer_ptr: .space 2 ! near
|
||||||
|
rmode: .space 2
|
||||||
|
pmode_cs: .space 2
|
||||||
|
pmode_ds: .space 2
|
||||||
|
|
||||||
|
.define realloc_ptr
|
||||||
|
.define interrupt_ptr
|
||||||
|
.define rmode
|
||||||
|
.define pmode_cs
|
||||||
|
.define pmode_ds
|
||||||
|
.define transfer_buffer_ptr
|
||||||
|
|
||||||
|
! Define symbols at the beginning of our various segments, so that we can find
|
||||||
|
! them. (Except .text, which has already been done.)
|
||||||
|
|
||||||
|
.define begtext, begdata, begbss
|
||||||
|
.sect .data; begdata:
|
||||||
|
.sect .rom; begrom:
|
||||||
|
.sect .bss; begbss:
|
||||||
|
|
||||||
|
.sect .rom
|
||||||
|
|
||||||
|
! Some text messages.
|
||||||
|
bad_sys_msg: .ascii 'Bad DOS$'
|
||||||
|
no_room_msg: .ascii 'No room$'
|
||||||
|
|
||||||
|
! Some magic data. All EM systems need these.
|
||||||
|
|
||||||
|
.define .trppc, .ignmask, _errno
|
||||||
|
.comm .trppc, 4
|
||||||
|
.comm .ignmask, 4
|
||||||
|
.comm _errno, 4
|
||||||
|
|
||||||
|
.comm .doshandle, 2
|
||||||
|
.comm .psp, 256
|
||||||
|
|
||||||
|
.sect .bss
|
||||||
|
.space 32*1024
|
||||||
|
.stack:
|
||||||
|
|
||||||
|
! vim: ts=4 sw=4 et ft=asm
|
||||||
|
|
53
plat/msdos386/build-pkg.lua
Normal file
53
plat/msdos386/build-pkg.lua
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
include("plat/build.lua")
|
||||||
|
|
||||||
|
ackfile {
|
||||||
|
name = "boot",
|
||||||
|
srcs = { "./boot.s" },
|
||||||
|
vars = { plat = "msdos386" }
|
||||||
|
}
|
||||||
|
|
||||||
|
ackfile {
|
||||||
|
name = "stub",
|
||||||
|
srcs = { "./stub.s" },
|
||||||
|
deps = { "plat/msdos386/libsys+headers" },
|
||||||
|
vars = { plat = "msdos386" }
|
||||||
|
}
|
||||||
|
|
||||||
|
normalrule {
|
||||||
|
name = "stub_aout",
|
||||||
|
ins = {
|
||||||
|
"util/led+led",
|
||||||
|
"+stub"
|
||||||
|
},
|
||||||
|
outleaves = { "stub.aout" },
|
||||||
|
commands = { "%{ins[1]} %{ins[2]} -o %{outs[1]}" }
|
||||||
|
}
|
||||||
|
|
||||||
|
normalrule {
|
||||||
|
name = "stub_exe",
|
||||||
|
ins = {
|
||||||
|
"util/amisc+aslod",
|
||||||
|
"+stub_aout"
|
||||||
|
},
|
||||||
|
outleaves = { "stub.exe" },
|
||||||
|
commands = { "%{ins[1]} %{ins[2]} %{outs[1]}" }
|
||||||
|
}
|
||||||
|
|
||||||
|
build_plat_libs {
|
||||||
|
name = "libs",
|
||||||
|
arch = "i386",
|
||||||
|
plat = "msdos386",
|
||||||
|
}
|
||||||
|
|
||||||
|
installable {
|
||||||
|
name = "pkg",
|
||||||
|
map = {
|
||||||
|
"+tools",
|
||||||
|
"+libs",
|
||||||
|
"./include+pkg",
|
||||||
|
["$(PLATIND)/msdos386/boot.o"] = "+boot",
|
||||||
|
["$(PLATIND)/msdos386/stub.exe"] = "+stub_exe",
|
||||||
|
["$(PLATIND)/msdos386/libsys.a"] = "./libsys+lib",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
21
plat/msdos386/build-tools.lua
Normal file
21
plat/msdos386/build-tools.lua
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
include("plat/build.lua")
|
||||||
|
|
||||||
|
build_as {
|
||||||
|
name = "as",
|
||||||
|
arch = "i386",
|
||||||
|
}
|
||||||
|
|
||||||
|
build_ncg {
|
||||||
|
name = "ncg",
|
||||||
|
arch = "i386",
|
||||||
|
}
|
||||||
|
|
||||||
|
return installable {
|
||||||
|
name = "tools",
|
||||||
|
map = {
|
||||||
|
["$(PLATDEP)/msdos386/as"] = "+as",
|
||||||
|
["$(PLATDEP)/msdos386/ncg"] = "+ncg",
|
||||||
|
["$(PLATIND)/descr/msdos386"] = "./descr",
|
||||||
|
"util/opt+pkg",
|
||||||
|
}
|
||||||
|
}
|
77
plat/msdos386/descr
Normal file
77
plat/msdos386/descr
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
var w=4
|
||||||
|
var wa=2
|
||||||
|
var p=4
|
||||||
|
var pa=2
|
||||||
|
var s=2
|
||||||
|
var sa=2
|
||||||
|
var l=4
|
||||||
|
var la=2
|
||||||
|
var f=4
|
||||||
|
var fa=2
|
||||||
|
var d=8
|
||||||
|
var da=2
|
||||||
|
var x=8
|
||||||
|
var xa=2
|
||||||
|
var ARCH=i386
|
||||||
|
var PLATFORM=msdos386
|
||||||
|
var PLATFORMDIR={EM}/share/ack/{PLATFORM}
|
||||||
|
var CPP_F=-D__MSDOS__ -D__DOS__ -D_DOS
|
||||||
|
var ALIGN=-a0:2 -a1:2 -a2:2 -a3:2
|
||||||
|
var MACHOPT_F=-m8
|
||||||
|
var EGO_PLAT_FLAGS=-M{EM}/share/ack/ego/{ARCH}.descr
|
||||||
|
|
||||||
|
# Override the setting in fe so that files compiled for this platform can see
|
||||||
|
# the platform-specific headers.
|
||||||
|
|
||||||
|
var C_INCLUDES=-I{PLATFORMDIR}/include -I{EM}/share/ack/include/ansi
|
||||||
|
|
||||||
|
name be
|
||||||
|
from .m.g
|
||||||
|
to .s
|
||||||
|
program {EM}/lib/ack/{PLATFORM}/ncg
|
||||||
|
args <
|
||||||
|
stdout
|
||||||
|
need .e
|
||||||
|
end
|
||||||
|
name as
|
||||||
|
from .s.so
|
||||||
|
to .o
|
||||||
|
program {EM}/lib/ack/{PLATFORM}/as
|
||||||
|
args - -o > <
|
||||||
|
prep cond
|
||||||
|
end
|
||||||
|
name led
|
||||||
|
from .o.a
|
||||||
|
to .out
|
||||||
|
program {EM}/lib/ack/em_led
|
||||||
|
mapflag -l* LNAME={PLATFORMDIR}/lib*
|
||||||
|
mapflag -fp FLOATS={EM}/{ILIB}fp
|
||||||
|
args {ALIGN} \
|
||||||
|
({RTS}:.b=-u _i_main) \
|
||||||
|
(.e:{HEAD}={PLATFORMDIR}/boot.o) \
|
||||||
|
({RTS}:.ocm.bas.b={PLATFORMDIR}/c-ansi.o) \
|
||||||
|
({RTS}:.c={PLATFORMDIR}/c-ansi.o) \
|
||||||
|
({RTS}:.mod={PLATFORMDIR}/modula2.o) \
|
||||||
|
({RTS}:.p={PLATFORMDIR}/pascal.o) \
|
||||||
|
-o > < \
|
||||||
|
(.p:{TAIL}={PLATFORMDIR}/libpascal.a) \
|
||||||
|
(.b:{TAIL}={PLATFORMDIR}/libb.a) \
|
||||||
|
(.bas:{TAIL}={PLATFORMDIR}/libbasic.a) \
|
||||||
|
(.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \
|
||||||
|
(.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \
|
||||||
|
(.ocm.bas.mod.b.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
|
||||||
|
{FLOATS?} \
|
||||||
|
(.e:{TAIL}={PLATFORMDIR}/libem.a \
|
||||||
|
{PLATFORMDIR}/libsys.a \
|
||||||
|
{PLATFORMDIR}/libc.a \
|
||||||
|
{PLATFORMDIR}/libem.a \
|
||||||
|
{PLATFORMDIR}/libend.a)
|
||||||
|
linker
|
||||||
|
end
|
||||||
|
name cv
|
||||||
|
from .out
|
||||||
|
to .exe
|
||||||
|
program {EM}/bin/aslod
|
||||||
|
args -p {PLATFORMDIR}/stub.exe < >
|
||||||
|
outfile msdos386.exe
|
||||||
|
end
|
6
plat/msdos386/include/ack/plat.h
Normal file
6
plat/msdos386/include/ack/plat.h
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef _ACK_PLAT_H
|
||||||
|
#define _ACK_PLAT_H
|
||||||
|
|
||||||
|
#define ACKCONF_WANT_O_TEXT_O_BINARY 1
|
||||||
|
|
||||||
|
#endif
|
24
plat/msdos386/include/build.lua
Normal file
24
plat/msdos386/include/build.lua
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
include("plat/build.lua")
|
||||||
|
|
||||||
|
headermap = {}
|
||||||
|
packagemap = {}
|
||||||
|
|
||||||
|
local function addheader(h)
|
||||||
|
headermap[h] = "./"..h
|
||||||
|
packagemap["$(PLATIND)/msdos386/include/"..h] = "./"..h
|
||||||
|
end
|
||||||
|
|
||||||
|
addheader("ack/plat.h")
|
||||||
|
addheader("sys/types.h")
|
||||||
|
|
||||||
|
acklibrary {
|
||||||
|
name = "headers",
|
||||||
|
hdrs = headermap
|
||||||
|
}
|
||||||
|
|
||||||
|
installable {
|
||||||
|
name = "pkg",
|
||||||
|
map = packagemap
|
||||||
|
}
|
||||||
|
|
||||||
|
|
9
plat/msdos386/include/sys/types.h
Normal file
9
plat/msdos386/include/sys/types.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#ifndef _SYS_TYPES_H
|
||||||
|
#define _SYS_TYPES_H
|
||||||
|
|
||||||
|
typedef long pid_t;
|
||||||
|
typedef int mode_t;
|
||||||
|
typedef long time_t;
|
||||||
|
typedef long suseconds_t;
|
||||||
|
|
||||||
|
#endif
|
14
plat/msdos386/libsys/_hol0.s
Normal file
14
plat/msdos386/libsys/_hol0.s
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
#include "libsysasm.h"
|
||||||
|
|
||||||
|
.sect .bss
|
||||||
|
|
||||||
|
! This data block is used to store information about the current line number
|
||||||
|
! and file.
|
||||||
|
|
||||||
|
.define hol0
|
||||||
|
.comm hol0, 8
|
16
plat/msdos386/libsys/brk.s
Normal file
16
plat/msdos386/libsys/brk.s
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
#include "libsysasm.h"
|
||||||
|
|
||||||
|
.define _brk
|
||||||
|
_brk:
|
||||||
|
mov ebx, esp
|
||||||
|
mov eax, 1*4(ebx)
|
||||||
|
callf (realloc_ptr)
|
||||||
|
xor eax, eax
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
44
plat/msdos386/libsys/build.lua
Normal file
44
plat/msdos386/libsys/build.lua
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
bundle {
|
||||||
|
name = "headers",
|
||||||
|
srcs = {
|
||||||
|
"./libsysasm.h"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
acklibrary {
|
||||||
|
name = "lib",
|
||||||
|
srcs = {
|
||||||
|
"./_hol0.s",
|
||||||
|
"./brk.s",
|
||||||
|
"./close.s",
|
||||||
|
"./errno.s",
|
||||||
|
"./getpid.s",
|
||||||
|
"./isatty.s",
|
||||||
|
"./rename.s",
|
||||||
|
"./sbrk.c",
|
||||||
|
"./sys_cpyin.s",
|
||||||
|
"./sys_cpyout.s",
|
||||||
|
"./sys_dpmidos.s",
|
||||||
|
"./sys_exists.s",
|
||||||
|
"./sys_getdate.s",
|
||||||
|
"./sys_gettime.s",
|
||||||
|
"./sys_isopen.s",
|
||||||
|
"./sys_isreadyr.s",
|
||||||
|
"./sys_rawcreat.s",
|
||||||
|
"./sys_rawlseek.s",
|
||||||
|
"./sys_rawopen.s",
|
||||||
|
"./sys_rawread.s",
|
||||||
|
"./sys_rawwrite.s",
|
||||||
|
"./sys_scpyout.s",
|
||||||
|
"./sys_xret.s",
|
||||||
|
"./unlink.s",
|
||||||
|
"plat/msdos/libsys+srcs",
|
||||||
|
},
|
||||||
|
deps = {
|
||||||
|
"plat/msdos/libsys+headers",
|
||||||
|
"+headers"
|
||||||
|
},
|
||||||
|
vars = {
|
||||||
|
plat = "msdos386"
|
||||||
|
}
|
||||||
|
}
|
16
plat/msdos386/libsys/close.s
Normal file
16
plat/msdos386/libsys/close.s
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
#include "libsysasm.h"
|
||||||
|
|
||||||
|
! Close a file.
|
||||||
|
|
||||||
|
.define _close
|
||||||
|
_close:
|
||||||
|
mov ebx, esp
|
||||||
|
mov ebx, 1*4(esp)
|
||||||
|
movb ah, 0x3E
|
||||||
|
int 0x21
|
||||||
|
jmp .sys_zret
|
23
plat/msdos386/libsys/errno.s
Normal file
23
plat/msdos386/libsys/errno.s
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
#include "libsysasm.h"
|
||||||
|
|
||||||
|
#define D(e) .define e; e
|
||||||
|
|
||||||
|
.sect .data
|
||||||
|
|
||||||
|
! Define various ACK error numbers. Note that these are *not* ANSI C
|
||||||
|
! errnos, and are used for different purposes.
|
||||||
|
|
||||||
|
D(ERANGE) = 1
|
||||||
|
D(ESET) = 2
|
||||||
|
D(EIDIVZ) = 6
|
||||||
|
D(EHEAP) = 17
|
||||||
|
D(EILLINS) = 18
|
||||||
|
D(EODDZ) = 19
|
||||||
|
D(ECASE) = 20
|
||||||
|
D(EBADMON) = 25
|
||||||
|
|
39
plat/msdos386/libsys/getpid.s
Normal file
39
plat/msdos386/libsys/getpid.s
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
! Copyright (c) 2021--2022 TK Chia
|
||||||
|
!
|
||||||
|
! The authors hereby grant permission to use, copy, modify, distribute,
|
||||||
|
! and license this software and its documentation for any purpose, provided
|
||||||
|
! that existing copyright notices are retained in all copies and that this
|
||||||
|
! notice is included verbatim in any distributions. No written agreement,
|
||||||
|
! license, or royalty fee is required for any of the authorized uses.
|
||||||
|
! Modifications to this software may be copyrighted by their authors
|
||||||
|
! and need not follow the licensing terms described here, provided that
|
||||||
|
! the new terms are clearly indicated on the first page of each file where
|
||||||
|
! they apply.
|
||||||
|
|
||||||
|
#include "libsysasm.h"
|
||||||
|
|
||||||
|
! Get the current process identifier. For MS-DOS, use the Program Segment
|
||||||
|
! Prefix (PSP) segment as the PID, unless the system supports an actual
|
||||||
|
! `getpid' syscall, e.g. European MS-DOS 4.0.
|
||||||
|
!
|
||||||
|
! (Note that pid_t is a 32-bit type. This is to allow for PSP segments and
|
||||||
|
! MS-DOS PIDs above 0x7FFF.)
|
||||||
|
|
||||||
|
.define _getpid
|
||||||
|
_getpid:
|
||||||
|
movb ah, 0x87
|
||||||
|
stc
|
||||||
|
int 0x21
|
||||||
|
jnc .eur_dos
|
||||||
|
movb ah, 0x51
|
||||||
|
mov ebx, 0x210000
|
||||||
|
callf (interrupt_ptr)
|
||||||
|
xchg ebx, eax
|
||||||
|
.eur_dos:
|
||||||
|
movzx eax, ax
|
||||||
|
ret
|
30
plat/msdos386/libsys/isatty.s
Normal file
30
plat/msdos386/libsys/isatty.s
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
#include "libsysasm.h"
|
||||||
|
|
||||||
|
! Say whether a given file descriptor number refers to a terminal.
|
||||||
|
|
||||||
|
.define _isatty
|
||||||
|
_isatty:
|
||||||
|
mov ebx, esp
|
||||||
|
mov ebx, 4(ebx)
|
||||||
|
o16 mov ax, 0x4400
|
||||||
|
int 0x21
|
||||||
|
jc error
|
||||||
|
testb dl, dl
|
||||||
|
jz not_tty
|
||||||
|
mov eax, 1
|
||||||
|
ret
|
||||||
|
not_tty:
|
||||||
|
mov (_errno), 25 ! ENOTTY
|
||||||
|
not_tty_2:
|
||||||
|
xor eax, eax
|
||||||
|
ret
|
||||||
|
error:
|
||||||
|
push eax
|
||||||
|
call __sys_seterrno
|
||||||
|
pop ecx
|
||||||
|
jmp not_tty_2
|
24
plat/msdos386/libsys/libsysasm.h
Normal file
24
plat/msdos386/libsys/libsysasm.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* © 2013 David Given
|
||||||
|
* © 2022 TK Chia
|
||||||
|
* This file is redistributable under the terms of the 3-clause BSD license.
|
||||||
|
* See the file 'Copying' in the root of the distribution for the full text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBSYSASM_H
|
||||||
|
#define LIBSYSASM_H
|
||||||
|
|
||||||
|
! Declare segments (the order is important).
|
||||||
|
|
||||||
|
.sect .text
|
||||||
|
.sect .rom
|
||||||
|
.sect .data
|
||||||
|
.sect .bss
|
||||||
|
|
||||||
|
.sect .text
|
||||||
|
|
||||||
|
! Size of transfer buffer, for 32-bit DPMI mode.
|
||||||
|
|
||||||
|
TRANSFER_BUFFER_SIZE = 32 * 1024
|
||||||
|
|
||||||
|
#endif
|
42
plat/msdos386/libsys/rename.s
Normal file
42
plat/msdos386/libsys/rename.s
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
#include "libsysasm.h"
|
||||||
|
|
||||||
|
! Rename a file.
|
||||||
|
|
||||||
|
.define _rename
|
||||||
|
_rename:
|
||||||
|
push edi
|
||||||
|
|
||||||
|
! Destination filename.
|
||||||
|
|
||||||
|
mov eax, 4+8(esp)
|
||||||
|
#define DEST_NAME_OFFSET (TRANSFER_BUFFER_SIZE / 2)
|
||||||
|
mov edx, DEST_NAME_OFFSET
|
||||||
|
mov ecx, edx
|
||||||
|
call .sys_sncpyout
|
||||||
|
jc 9f
|
||||||
|
xchg edi, eax
|
||||||
|
|
||||||
|
! Source filename.
|
||||||
|
|
||||||
|
mov eax, 4+4(esp)
|
||||||
|
xor edx, edx
|
||||||
|
call .sys_sncpyout
|
||||||
|
jc 9f
|
||||||
|
xchg edx, eax
|
||||||
|
|
||||||
|
! Make the DOS call.
|
||||||
|
|
||||||
|
movb ah, 0x56
|
||||||
|
call .sys_dpmidos
|
||||||
|
|
||||||
|
pop edi
|
||||||
|
jmp .sys_zret
|
||||||
|
|
||||||
|
9:
|
||||||
|
pop edi
|
||||||
|
jmp .sys_toolongret
|
40
plat/msdos386/libsys/sbrk.c
Normal file
40
plat/msdos386/libsys/sbrk.c
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/* $Source$
|
||||||
|
* $State$
|
||||||
|
* $Revision$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "libsys.h"
|
||||||
|
|
||||||
|
extern char _end[1];
|
||||||
|
static char* current = _end;
|
||||||
|
|
||||||
|
void* sbrk(int increment)
|
||||||
|
{
|
||||||
|
char* old;
|
||||||
|
char* new;
|
||||||
|
|
||||||
|
if (increment == 0)
|
||||||
|
return current;
|
||||||
|
|
||||||
|
old = current;
|
||||||
|
|
||||||
|
new = old + increment;
|
||||||
|
|
||||||
|
if ((increment > 0) && (new <= old))
|
||||||
|
goto out_of_memory;
|
||||||
|
else if ((increment < 0) && (new >= old))
|
||||||
|
goto out_of_memory;
|
||||||
|
|
||||||
|
if (brk(new) < 0)
|
||||||
|
goto out_of_memory;
|
||||||
|
|
||||||
|
current = new;
|
||||||
|
return old;
|
||||||
|
|
||||||
|
out_of_memory:
|
||||||
|
errno = ENOMEM;
|
||||||
|
return OUT_OF_MEMORY;
|
||||||
|
}
|
32
plat/msdos386/libsys/sys_cpyin.s
Normal file
32
plat/msdos386/libsys/sys_cpyin.s
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
#include "libsysasm.h"
|
||||||
|
|
||||||
|
! .sys_cpyin: copy ecx bytes from the transfer buffer to es:eax (= ds:eax).
|
||||||
|
! Preserve all registers, except the flags.
|
||||||
|
|
||||||
|
.extern .sys_cpyin
|
||||||
|
.sys_cpyin:
|
||||||
|
push eax
|
||||||
|
push ecx
|
||||||
|
push esi
|
||||||
|
push edi
|
||||||
|
movzx esi, (transfer_buffer_ptr)
|
||||||
|
xchg edi, eax
|
||||||
|
mov ds, (pmode_ds)
|
||||||
|
mov eax, ecx
|
||||||
|
shr ecx, 2
|
||||||
|
rep movs
|
||||||
|
andb al, 3
|
||||||
|
movb cl, al
|
||||||
|
rep movsb
|
||||||
|
mov eax, ss
|
||||||
|
mov ds, eax
|
||||||
|
pop edi
|
||||||
|
pop esi
|
||||||
|
pop ecx
|
||||||
|
pop eax
|
||||||
|
ret
|
34
plat/msdos386/libsys/sys_cpyout.s
Normal file
34
plat/msdos386/libsys/sys_cpyout.s
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
#include "libsysasm.h"
|
||||||
|
|
||||||
|
! .sys_cpyout: copy ecx bytes starting from ds:eax to the transfer
|
||||||
|
! buffer. Return eax := offset of transfer buffer in the real mode data
|
||||||
|
! segment. Preserve all other registers, except the flags.
|
||||||
|
|
||||||
|
.extern .sys_cpyout
|
||||||
|
.sys_cpyout:
|
||||||
|
push ecx
|
||||||
|
push edx
|
||||||
|
push esi
|
||||||
|
push edi
|
||||||
|
xchg esi, eax
|
||||||
|
movzx edi, (transfer_buffer_ptr)
|
||||||
|
mov eax, edi
|
||||||
|
mov es, (pmode_ds)
|
||||||
|
mov edx, ecx
|
||||||
|
shr ecx, 2
|
||||||
|
rep movs
|
||||||
|
movb cl, dl
|
||||||
|
andb cl, 3
|
||||||
|
rep movsb
|
||||||
|
mov ecx, ss
|
||||||
|
mov es, ecx
|
||||||
|
pop edi
|
||||||
|
pop esi
|
||||||
|
pop edx
|
||||||
|
pop ecx
|
||||||
|
ret
|
16
plat/msdos386/libsys/sys_dpmidos.s
Normal file
16
plat/msdos386/libsys/sys_dpmidos.s
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
#include "libsysasm.h"
|
||||||
|
|
||||||
|
! .sys_dpmidos: simulate a call to real-mode int 0x21 with the current
|
||||||
|
! 16-bit register values.
|
||||||
|
|
||||||
|
.extern .sys_dpmidos
|
||||||
|
.sys_dpmidos:
|
||||||
|
movzx ebx, bx
|
||||||
|
or ebx, 0x210000
|
||||||
|
callf (interrupt_ptr)
|
||||||
|
ret
|
21
plat/msdos386/libsys/sys_exists.s
Normal file
21
plat/msdos386/libsys/sys_exists.s
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
#include "libsysasm.h"
|
||||||
|
|
||||||
|
! Say whether a file exists with the given name.
|
||||||
|
|
||||||
|
.define __sys_exists
|
||||||
|
__sys_exists:
|
||||||
|
mov eax, 4(esp)
|
||||||
|
call .sys_scpyout
|
||||||
|
jc 9f
|
||||||
|
xchg edx, eax
|
||||||
|
mov eax, 0x4300
|
||||||
|
call .sys_dpmidos
|
||||||
|
9:
|
||||||
|
sbb eax, eax
|
||||||
|
inc eax
|
||||||
|
ret
|
18
plat/msdos386/libsys/sys_getdate.s
Normal file
18
plat/msdos386/libsys/sys_getdate.s
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
#include "libsysasm.h"
|
||||||
|
|
||||||
|
! Get the current system date from MS-DOS.
|
||||||
|
|
||||||
|
.define __sys_getdate
|
||||||
|
__sys_getdate:
|
||||||
|
movb ah, 0x2a
|
||||||
|
int 0x21
|
||||||
|
mov ebx, esp
|
||||||
|
mov ebx, 4(ebx)
|
||||||
|
o16 mov 0(ebx), dx
|
||||||
|
o16 mov 2(ebx), cx
|
||||||
|
ret
|
18
plat/msdos386/libsys/sys_gettime.s
Normal file
18
plat/msdos386/libsys/sys_gettime.s
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
#include "libsysasm.h"
|
||||||
|
|
||||||
|
! Get the current system time from MS-DOS.
|
||||||
|
|
||||||
|
.define __sys_gettime
|
||||||
|
__sys_gettime:
|
||||||
|
movb ah, 0x2c
|
||||||
|
int 0x21
|
||||||
|
mov ebx, esp
|
||||||
|
mov ebx, 4(ebx)
|
||||||
|
o16 mov 0(ebx), cx
|
||||||
|
o16 mov 2(ebx), dx
|
||||||
|
ret
|
18
plat/msdos386/libsys/sys_isopen.s
Normal file
18
plat/msdos386/libsys/sys_isopen.s
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
#include "libsysasm.h"
|
||||||
|
|
||||||
|
! Say whether a given file descriptor number refers to a valid open file
|
||||||
|
! descriptor.
|
||||||
|
|
||||||
|
.define __sys_isopen
|
||||||
|
__sys_isopen:
|
||||||
|
mov ebx, 4(esp)
|
||||||
|
mov eax, 0x4400
|
||||||
|
int 0x21
|
||||||
|
sbb eax, eax
|
||||||
|
inc eax
|
||||||
|
ret
|
22
plat/msdos386/libsys/sys_isreadyr.s
Normal file
22
plat/msdos386/libsys/sys_isreadyr.s
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
#include "libsysasm.h"
|
||||||
|
|
||||||
|
! Say whether a file descriptor is ready for input, i.e. reading from the
|
||||||
|
! fd will immediately return something.
|
||||||
|
|
||||||
|
.define __sys_isreadyr
|
||||||
|
__sys_isreadyr:
|
||||||
|
mov ebx, esp
|
||||||
|
mov eax, 0x4406
|
||||||
|
mov ebx, 4(ebx)
|
||||||
|
int 0x21
|
||||||
|
jnc ok
|
||||||
|
movb al, 0
|
||||||
|
ok:
|
||||||
|
o16 cbw
|
||||||
|
cwde
|
||||||
|
ret
|
28
plat/msdos386/libsys/sys_rawcreat.s
Normal file
28
plat/msdos386/libsys/sys_rawcreat.s
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
#include "libsysasm.h"
|
||||||
|
|
||||||
|
! Create or truncate a file.
|
||||||
|
|
||||||
|
.define __sys_rawcreat
|
||||||
|
__sys_rawcreat:
|
||||||
|
! Copy filename to transfer buffer.
|
||||||
|
|
||||||
|
mov eax, 4(esp)
|
||||||
|
call .sys_scpyout
|
||||||
|
jc 9f
|
||||||
|
|
||||||
|
! Make the DOS call.
|
||||||
|
|
||||||
|
xchg edx, eax
|
||||||
|
movb ah, 0x3c
|
||||||
|
movb al, 8(esp)
|
||||||
|
call .sys_dpmidos
|
||||||
|
|
||||||
|
jmp .sys_axret
|
||||||
|
|
||||||
|
9:
|
||||||
|
jmp .sys_toolongret
|
20
plat/msdos386/libsys/sys_rawlseek.s
Normal file
20
plat/msdos386/libsys/sys_rawlseek.s
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
#include "libsysasm.h"
|
||||||
|
|
||||||
|
! Move the current file position for a file descriptor.
|
||||||
|
|
||||||
|
.define __sys_rawlseek
|
||||||
|
__sys_rawlseek:
|
||||||
|
movb ah, 0x42
|
||||||
|
mov ebx, esp
|
||||||
|
mov edx, 8(ebx)
|
||||||
|
mov ecx, edx
|
||||||
|
shr ecx, 16
|
||||||
|
movb al, 12(ebx)
|
||||||
|
mov ebx, 4(ebx)
|
||||||
|
int 0x21
|
||||||
|
jmp .sys_dxaxret
|
24
plat/msdos386/libsys/sys_rawopen.s
Normal file
24
plat/msdos386/libsys/sys_rawopen.s
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
#include "libsysasm.h"
|
||||||
|
|
||||||
|
! Open an existing file.
|
||||||
|
|
||||||
|
.define __sys_rawopen
|
||||||
|
__sys_rawopen:
|
||||||
|
! Copy filename to transfer buffer.
|
||||||
|
|
||||||
|
mov eax, 4(esp)
|
||||||
|
call .sys_scpyout
|
||||||
|
|
||||||
|
! Make the DOS call.
|
||||||
|
|
||||||
|
xchg edx, eax
|
||||||
|
movb ah, 0x3d
|
||||||
|
movb al, 8(esp)
|
||||||
|
call .sys_dpmidos
|
||||||
|
|
||||||
|
jmp .sys_axret
|
50
plat/msdos386/libsys/sys_rawread.s
Normal file
50
plat/msdos386/libsys/sys_rawread.s
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
#include "libsysasm.h"
|
||||||
|
|
||||||
|
! Read bytes from a file descriptor. These routines do not do any
|
||||||
|
! translation between CRLF and LF line endings.
|
||||||
|
!
|
||||||
|
! Note that, for MS-DOS, a raw "write" request of zero bytes will truncate
|
||||||
|
! (or extend) the file to the current file position.
|
||||||
|
|
||||||
|
.define __sys_rawread
|
||||||
|
__sys_rawread:
|
||||||
|
file_handle = 1*4
|
||||||
|
write_buffer = 2*4
|
||||||
|
amount_to_read = 3*4
|
||||||
|
|
||||||
|
mov eax, amount_to_read(esp)
|
||||||
|
mov ecx, TRANSFER_BUFFER_SIZE
|
||||||
|
cmp eax, ecx
|
||||||
|
jge 2f
|
||||||
|
mov ecx, eax
|
||||||
|
2:
|
||||||
|
|
||||||
|
! Read from DOS into the transfer buffer.
|
||||||
|
|
||||||
|
movb ah, 0x3f
|
||||||
|
o16 mov dx, (transfer_buffer_ptr)
|
||||||
|
o16 mov bx, file_handle(esp)
|
||||||
|
call .sys_dpmidos
|
||||||
|
jc 3f
|
||||||
|
|
||||||
|
! Copy eax bytes out of the transfer buffer.
|
||||||
|
|
||||||
|
movzx ecx, ax
|
||||||
|
mov eax, write_buffer(esp)
|
||||||
|
call .sys_cpyin
|
||||||
|
|
||||||
|
xchg eax, ecx
|
||||||
|
ret
|
||||||
|
|
||||||
|
3:
|
||||||
|
! Process errors.
|
||||||
|
|
||||||
|
push eax
|
||||||
|
call __sys_seterrno
|
||||||
|
pop ecx
|
||||||
|
ret
|
48
plat/msdos386/libsys/sys_rawwrite.s
Normal file
48
plat/msdos386/libsys/sys_rawwrite.s
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
#include "libsysasm.h"
|
||||||
|
|
||||||
|
! Write bytes to/to a file descriptor. These routines do not do any
|
||||||
|
! translation between CRLF and LF line endings.
|
||||||
|
!
|
||||||
|
! Note that, for MS-DOS, a raw "write" request of zero bytes will truncate
|
||||||
|
! (or extend) the file to the current file position.
|
||||||
|
|
||||||
|
.define __sys_rawwrite
|
||||||
|
__sys_rawwrite:
|
||||||
|
file_handle = 1*4
|
||||||
|
read_buffer = 2*4
|
||||||
|
amount_to_write = 3*4
|
||||||
|
|
||||||
|
mov eax, amount_to_write(esp)
|
||||||
|
mov ecx, TRANSFER_BUFFER_SIZE
|
||||||
|
cmp eax, ecx
|
||||||
|
jge 2f
|
||||||
|
mov ecx, eax
|
||||||
|
2:
|
||||||
|
|
||||||
|
! Copy ecx bytes into the transfer buffer.
|
||||||
|
|
||||||
|
mov eax, read_buffer(esp)
|
||||||
|
call .sys_cpyout
|
||||||
|
|
||||||
|
! Write from the transfer buffer to DOS.
|
||||||
|
|
||||||
|
xchg edx, eax
|
||||||
|
movb ah, 0x40
|
||||||
|
o16 mov bx, file_handle(esp)
|
||||||
|
call .sys_dpmidos
|
||||||
|
movzx eax, ax
|
||||||
|
jnc exit
|
||||||
|
|
||||||
|
push eax
|
||||||
|
call __sys_seterrno
|
||||||
|
pop ecx
|
||||||
|
exit:
|
||||||
|
ret
|
||||||
|
|
||||||
|
! vim: sw=4 ts=4 et
|
||||||
|
|
58
plat/msdos386/libsys/sys_scpyout.s
Normal file
58
plat/msdos386/libsys/sys_scpyout.s
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
#include "libsysasm.h"
|
||||||
|
|
||||||
|
! .sys_scpyout: copy the ASCIIZ string starting from ds:eax to the
|
||||||
|
! transfer buffer. The resulting ASCIIZ string, including the final null,
|
||||||
|
! should fit into the entire transfer buffer. Return eax := offset of
|
||||||
|
! transfer buffer in real mode data segment. Return CF = 1 if and only if
|
||||||
|
! the ASCIIZ string is too long to fit. Preserve all other registers,
|
||||||
|
! except the flags.
|
||||||
|
!
|
||||||
|
! .sys_sncpyout: copy the ASCIIZ string starting from ds:eax to offset
|
||||||
|
! edx into the transfer buffer. The resulting ASCIIZ string should occupy
|
||||||
|
! at most ecx bytes, including the final null. Return eax : offset of
|
||||||
|
! string in real mode data segment. Return CF = 1 if and only if the ASCIIZ
|
||||||
|
! string is too long to fit. Preserve all other registers, except the
|
||||||
|
! flags.
|
||||||
|
|
||||||
|
.extern .sys_scpyout
|
||||||
|
.extern .sys_sncpyout
|
||||||
|
.sys_scpyout:
|
||||||
|
push ecx
|
||||||
|
push edx
|
||||||
|
mov ecx, TRANSFER_BUFFER_SIZE
|
||||||
|
xor edx, edx
|
||||||
|
jmp .cont
|
||||||
|
.sys_sncpyout:
|
||||||
|
push ecx
|
||||||
|
push edx
|
||||||
|
.cont:
|
||||||
|
push esi
|
||||||
|
push edi
|
||||||
|
mov esi, eax
|
||||||
|
movzx edi, (transfer_buffer_ptr)
|
||||||
|
add edi, edx
|
||||||
|
mov edx, edi
|
||||||
|
mov es, (pmode_ds)
|
||||||
|
jcxz .error
|
||||||
|
.loop:
|
||||||
|
lodsb
|
||||||
|
stosb
|
||||||
|
testb al, al
|
||||||
|
loopnz .loop
|
||||||
|
jz .ok
|
||||||
|
.error:
|
||||||
|
stc
|
||||||
|
.ok:
|
||||||
|
xchg edx, eax
|
||||||
|
mov edx, ss
|
||||||
|
mov es, edx
|
||||||
|
pop edi
|
||||||
|
pop esi
|
||||||
|
pop edx
|
||||||
|
pop ecx
|
||||||
|
ret
|
54
plat/msdos386/libsys/sys_xret.s
Normal file
54
plat/msdos386/libsys/sys_xret.s
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
#include "libsysasm.h"
|
||||||
|
|
||||||
|
! .sys_zret: if the carry flag is set, then set `errno' from the DOS error
|
||||||
|
! code in ax, and return an int -1. If the carry flag is clear, just
|
||||||
|
! return an int zero.
|
||||||
|
!
|
||||||
|
! .sys_axret: if the carry flag is set, then set `errno' from the DOS error
|
||||||
|
! code in ax, and return a shortword -1. If the carry flag is clear, just
|
||||||
|
! return eax := ax as a return value.
|
||||||
|
!
|
||||||
|
! .sys_dxaxret: same as .sys_axret, but return -1 or eax := dx:ax as a
|
||||||
|
! return value.
|
||||||
|
!
|
||||||
|
! .sys_toolongret: a file name is too long: set `errno' to E2BIG, and return
|
||||||
|
! -1.
|
||||||
|
|
||||||
|
.extern .sys_zret
|
||||||
|
.extern .sys_axret
|
||||||
|
.extern .sys_dxaxret
|
||||||
|
.extern .sys_toolongret
|
||||||
|
.sys_zret:
|
||||||
|
jc error
|
||||||
|
xor eax, eax
|
||||||
|
no_error:
|
||||||
|
ret
|
||||||
|
|
||||||
|
.sys_axret:
|
||||||
|
jc error
|
||||||
|
movzx eax, ax
|
||||||
|
ret
|
||||||
|
|
||||||
|
.sys_dxaxret:
|
||||||
|
jc error
|
||||||
|
shl edx, 16
|
||||||
|
o16 mov dx, ax
|
||||||
|
mov eax, edx
|
||||||
|
ret
|
||||||
|
|
||||||
|
.sys_toolongret:
|
||||||
|
mov (_errno), 7 ! E2BIG
|
||||||
|
or eax, -1
|
||||||
|
ret
|
||||||
|
|
||||||
|
error:
|
||||||
|
movzx eax, ax
|
||||||
|
push eax
|
||||||
|
call __sys_seterrno
|
||||||
|
pop ecx
|
||||||
|
ret
|
23
plat/msdos386/libsys/unlink.s
Normal file
23
plat/msdos386/libsys/unlink.s
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
#include "libsysasm.h"
|
||||||
|
|
||||||
|
! Remove a file.
|
||||||
|
|
||||||
|
.define _unlink
|
||||||
|
_unlink:
|
||||||
|
! Copy filename to transfer buffer.
|
||||||
|
|
||||||
|
mov eax, 4(esp)
|
||||||
|
call .sys_scpyout
|
||||||
|
|
||||||
|
! Make the DOS call.
|
||||||
|
|
||||||
|
xchg edx, eax
|
||||||
|
movb ah, 0x41
|
||||||
|
call .sys_dpmidos
|
||||||
|
|
||||||
|
jmp .sys_zret
|
414
plat/msdos386/stub.s
Normal file
414
plat/msdos386/stub.s
Normal file
|
@ -0,0 +1,414 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
#include "libsysasm.h"
|
||||||
|
|
||||||
|
.use16
|
||||||
|
exe_header:
|
||||||
|
.data2 0x5a4d ! magic number
|
||||||
|
.data2 exe_last_page ! number of bytes in last loadable page
|
||||||
|
.data2 exe_text_pages ! size of .exe, in pages
|
||||||
|
.data2 0 ! number of relocation entries
|
||||||
|
.data2 0 ! start of loadable area, in 16-byte paragraphs
|
||||||
|
.data2 exe_ram_paras ! required RAM size, in 16-byte paragraphs
|
||||||
|
.data2 exe_ram_paras ! maximum RAM siz, in 16-byte paragraphs
|
||||||
|
.data2 0 ! initial SS, relative to program
|
||||||
|
.data2 stack ! initial SP
|
||||||
|
.data2 0 ! checksum (ignored)
|
||||||
|
.data2 exe_start ! initial IP
|
||||||
|
.data2 0 ! initial CS, relative to program
|
||||||
|
.data2 0 ! offset of relocation table
|
||||||
|
.data2 0 ! overlay number
|
||||||
|
|
||||||
|
exe_start:
|
||||||
|
! On entry, DS=ES=PSP. Make DS=CS, so we're running in tiny mode.
|
||||||
|
|
||||||
|
push cs
|
||||||
|
pop ds
|
||||||
|
mov (rseg), ds
|
||||||
|
mov (pspseg), es
|
||||||
|
|
||||||
|
! Ensure that at least two handles are available by blindly closing some.
|
||||||
|
|
||||||
|
mov bx, 19 ! close handle
|
||||||
|
movb ah, 0x3e
|
||||||
|
int 0x21
|
||||||
|
mov bx, 18 ! close handle
|
||||||
|
movb ah, 0x3e
|
||||||
|
int 0x21
|
||||||
|
|
||||||
|
! Scan the environment to find the program name.
|
||||||
|
|
||||||
|
eseg mov es, (0x2c) ! environment pointer segment from PSP
|
||||||
|
xor di, di
|
||||||
|
xorb al, al
|
||||||
|
mov cx, 0xffff
|
||||||
|
cld
|
||||||
|
1:
|
||||||
|
repne scasb ! find end of next string
|
||||||
|
eseg cmpb (di), 0
|
||||||
|
jnz 1b
|
||||||
|
2:
|
||||||
|
add di, 3
|
||||||
|
mov si, di
|
||||||
|
repne scasb
|
||||||
|
|
||||||
|
! es:si now points at the program name, and es:di at one past the end.
|
||||||
|
|
||||||
|
mov cx, di
|
||||||
|
sub cx, si
|
||||||
|
sub sp, cx ! allocate space on stack
|
||||||
|
mov di, sp ! es:si source, ds:di dest
|
||||||
|
1:
|
||||||
|
eseg movb al, (si)
|
||||||
|
inc si
|
||||||
|
movb (di), al
|
||||||
|
inc di
|
||||||
|
cmpb al, 0
|
||||||
|
jnz 1b
|
||||||
|
|
||||||
|
! Open the file. (0x5f)
|
||||||
|
|
||||||
|
mov dx, sp
|
||||||
|
mov ax, 0x3d00
|
||||||
|
int 0x21
|
||||||
|
jc no_file
|
||||||
|
mov (fh), ax
|
||||||
|
add sp, cx ! don't need filename any more
|
||||||
|
|
||||||
|
! Get the file length (== text len).
|
||||||
|
|
||||||
|
mov bx, ax
|
||||||
|
mov ax, 0x4202
|
||||||
|
xor cx, cx ! high offset
|
||||||
|
xor dx, dx ! low offset
|
||||||
|
int 0x21 ! lseek
|
||||||
|
mov (pmemlen+0), ax
|
||||||
|
mov (pmemlen+2), dx
|
||||||
|
|
||||||
|
! Initialise DPMI.
|
||||||
|
|
||||||
|
mov ax, 0x1687
|
||||||
|
int 0x2f
|
||||||
|
or ax, ax
|
||||||
|
jnz no_dpmi
|
||||||
|
mov (pmode_switch+0), di ! write back PMODE switch routine
|
||||||
|
mov (pmode_switch+2), es
|
||||||
|
or si, si ! do we need a DPMI private area?
|
||||||
|
jz 1f
|
||||||
|
|
||||||
|
mov bx, si
|
||||||
|
movb ah, 0x48
|
||||||
|
int 0x21 ! allocate memory from DOS
|
||||||
|
mov es, ax ! data area segment -> es
|
||||||
|
1:
|
||||||
|
! Switch to protected mode.
|
||||||
|
|
||||||
|
mov ax, 1 ! 32-bit app
|
||||||
|
callf (pmode_switch)
|
||||||
|
jc bad_dpmi
|
||||||
|
|
||||||
|
! We're now in protected mode.
|
||||||
|
|
||||||
|
mov (psegcs), cs
|
||||||
|
mov (psegds), ds
|
||||||
|
|
||||||
|
! Allocate space for the code segment.
|
||||||
|
|
||||||
|
mov ax, 0x0000
|
||||||
|
mov cx, 1
|
||||||
|
int 0x31 ! allocate LDT
|
||||||
|
jc bad_dpmi
|
||||||
|
mov fs, ax
|
||||||
|
mov (psegcs32), ax
|
||||||
|
|
||||||
|
mov cx, (pmemlen+0)
|
||||||
|
mov bx, (pmemlen+2)
|
||||||
|
mov ax, 0x0501
|
||||||
|
int 0x31 ! allocate linear address
|
||||||
|
jc bad_dpmi
|
||||||
|
mov (pmemhandle+0), di
|
||||||
|
mov (pmemhandle+2), si
|
||||||
|
|
||||||
|
mov dx, cx
|
||||||
|
mov cx, bx
|
||||||
|
mov bx, fs
|
||||||
|
mov ax, 0x0007
|
||||||
|
int 0x31 ! set segment base address
|
||||||
|
jc bad_dpmi
|
||||||
|
|
||||||
|
mov bx, fs
|
||||||
|
mov dx, (pmemlen+0)
|
||||||
|
mov cx, (pmemlen+2)
|
||||||
|
sub dx, 1
|
||||||
|
sbb cx, 0
|
||||||
|
mov ax, 0x0008
|
||||||
|
int 0x31 ! set segment limit
|
||||||
|
|
||||||
|
mov cx, cs
|
||||||
|
and cx, 3
|
||||||
|
shl cx, 5
|
||||||
|
or cx, 0xc09b ! 32-bit, big, code, non-conforming, readable
|
||||||
|
mov bx, fs
|
||||||
|
mov ax, 0x0009
|
||||||
|
int 0x31 ! set descriptor access rights
|
||||||
|
|
||||||
|
! Allocate the data segment (as a simple clone of the code segment). (10e)
|
||||||
|
|
||||||
|
mov ax, 0x000a
|
||||||
|
mov bx, fs
|
||||||
|
int 0x31
|
||||||
|
mov es, ax
|
||||||
|
mov (psegds32), ax
|
||||||
|
|
||||||
|
mov cx, ax
|
||||||
|
and cx, 3
|
||||||
|
shl cx, 5
|
||||||
|
or cx, 0xc093 ! 32-bit, big, data, r/w, expand-up
|
||||||
|
mov bx, es
|
||||||
|
mov ax, 0x0009
|
||||||
|
int 0x31 ! set descriptor access rights
|
||||||
|
|
||||||
|
! Load the program.
|
||||||
|
|
||||||
|
mov bx, (fh)
|
||||||
|
mov ax, 0x4200
|
||||||
|
xor cx, cx ! high offset
|
||||||
|
mov dx, text_top ! low offset
|
||||||
|
int 0x21 ! lseek
|
||||||
|
|
||||||
|
o32 xor edi, edi ! destination 32-bit register
|
||||||
|
1:
|
||||||
|
movb ah, 0x3f
|
||||||
|
mov bx, (fh)
|
||||||
|
mov cx, TRANSFER_BUFFER_SIZE
|
||||||
|
mov dx, transfer_buffer
|
||||||
|
o32 push edi
|
||||||
|
call int21 ! read up to 32kB into transfer buffer
|
||||||
|
o32 pop edi
|
||||||
|
cmp ax, 0
|
||||||
|
je 2f
|
||||||
|
|
||||||
|
o32 movzx ecx, ax ! number of bytes read
|
||||||
|
o32 mov esi, transfer_buffer
|
||||||
|
cld
|
||||||
|
rep a32 movsb
|
||||||
|
jmp 1b
|
||||||
|
2:
|
||||||
|
|
||||||
|
! Close the file.
|
||||||
|
|
||||||
|
movb ah, 0x3e
|
||||||
|
mov bx, (fh)
|
||||||
|
int 0x21 ! close
|
||||||
|
|
||||||
|
! Jump to the new segment and enter 32-bit mode!
|
||||||
|
|
||||||
|
o32 movzx eax, (psegcs)
|
||||||
|
o32 movzx ebx, (psegds)
|
||||||
|
o32 movzx ecx, (rseg)
|
||||||
|
o32 mov edx, realloc
|
||||||
|
o32 mov esi, interruptf
|
||||||
|
o32 mov edi, transfer_buffer
|
||||||
|
o32 movzx ebp, (pspseg)
|
||||||
|
push es
|
||||||
|
pop ds
|
||||||
|
push fs
|
||||||
|
push 0
|
||||||
|
retf ! 19b
|
||||||
|
|
||||||
|
! Helper routine which reallocates the linear block that the 32-bit code
|
||||||
|
! is running from. This can't happen from inside the 32-bit code itself
|
||||||
|
! because it might move.
|
||||||
|
!
|
||||||
|
! On entry, ds and ss are ignored. On exit, ds and es are set to the
|
||||||
|
! 32-bit segment.
|
||||||
|
! eax: new block size
|
||||||
|
realloc:
|
||||||
|
cseg mov ds, (psegds)
|
||||||
|
cli ! atomically switch stacks
|
||||||
|
o32 mov (dpmi_ebp), esp ! yes, saving esp into the ebp field
|
||||||
|
mov (dpmi_ss), ss
|
||||||
|
mov ss, (psegds)
|
||||||
|
mov sp, dosstack
|
||||||
|
sti
|
||||||
|
pusha
|
||||||
|
|
||||||
|
o32 add eax, 1024*1024 - 1
|
||||||
|
o32 and eax, ~[1024*1024 - 1]
|
||||||
|
o32 mov (pmemlen), eax
|
||||||
|
mov cx, (pmemlen+0)
|
||||||
|
mov bx, (pmemlen+2)
|
||||||
|
mov di, (pmemhandle+0)
|
||||||
|
mov si, (pmemhandle+2)
|
||||||
|
mov ax, 0x0503
|
||||||
|
int 0x31 ! resize memory block
|
||||||
|
jc bad_dpmi
|
||||||
|
mov (pmemhandle+0), di
|
||||||
|
mov (pmemhandle+2), si
|
||||||
|
mov (pmemaddr+0), cx
|
||||||
|
mov (pmemaddr+2), bx
|
||||||
|
|
||||||
|
mov bx, (psegcs32)
|
||||||
|
mov dx, (pmemaddr+0)
|
||||||
|
mov cx, (pmemaddr+2)
|
||||||
|
mov ax, 0x0007
|
||||||
|
int 0x31 ! set cs linear address
|
||||||
|
jc bad_dpmi
|
||||||
|
mov bx, (psegds32)
|
||||||
|
int 0x31 ! set ds linear address
|
||||||
|
jc bad_dpmi
|
||||||
|
mov dx, (pmemlen+0)
|
||||||
|
mov cx, (pmemlen+2)
|
||||||
|
sub dx, 1
|
||||||
|
sbb cx, 0
|
||||||
|
mov ax, 0x0008
|
||||||
|
int 0x31 ! set ds segment limit
|
||||||
|
jc bad_dpmi
|
||||||
|
|
||||||
|
popa
|
||||||
|
o32 mov eax, (pmemlen)
|
||||||
|
cli ! atomically switch stacks back
|
||||||
|
mov ss, (dpmi_ss)
|
||||||
|
o32 mov esp, (dpmi_ebp)
|
||||||
|
mov es, (psegds32)
|
||||||
|
mov ds, (psegds32)
|
||||||
|
sti
|
||||||
|
|
||||||
|
o32 retf
|
||||||
|
|
||||||
|
bad_dpmi:
|
||||||
|
mov si, bad_dpmi_msg
|
||||||
|
jmp exit_with_error
|
||||||
|
|
||||||
|
no_file:
|
||||||
|
mov si, no_file_msg
|
||||||
|
jmp exit_with_error
|
||||||
|
|
||||||
|
no_dpmi:
|
||||||
|
mov si, no_dpmi_msg
|
||||||
|
! fall through
|
||||||
|
|
||||||
|
! Displays the message in si and exits.
|
||||||
|
! This uses a loop because from protected mode any interrupt which
|
||||||
|
! takes a pointer parameter requires special treatment.
|
||||||
|
exit_with_error:
|
||||||
|
movb dl, (si)
|
||||||
|
cmpb dl, 0
|
||||||
|
je 1f
|
||||||
|
inc si
|
||||||
|
|
||||||
|
movb ah, 2
|
||||||
|
int 0x21 ! print character
|
||||||
|
jmp exit_with_error
|
||||||
|
1:
|
||||||
|
mov ax, 0x4cff
|
||||||
|
int 0x21 ! terminate with error code al
|
||||||
|
|
||||||
|
! Simulate DOS interrupt.
|
||||||
|
int21:
|
||||||
|
o32 movzx ebx, bx
|
||||||
|
o32 or ebx, 0x210000
|
||||||
|
! Simulate interrupt in the high half of ebx.
|
||||||
|
interrupt:
|
||||||
|
o32 mov (dpmi_eax), eax
|
||||||
|
o32 mov (dpmi_ebx), ebx
|
||||||
|
o32 mov (dpmi_ecx), ecx
|
||||||
|
o32 mov (dpmi_edx), edx
|
||||||
|
o32 mov (dpmi_esi), esi
|
||||||
|
o32 mov (dpmi_edi), edi
|
||||||
|
pushf
|
||||||
|
pop (dpmi_flags)
|
||||||
|
mov ax, (rseg)
|
||||||
|
mov (dpmi_ds), ax
|
||||||
|
mov (dpmi_ss), ax
|
||||||
|
push es
|
||||||
|
mov (dpmi_sp), dosstack ! auto stack is too small
|
||||||
|
push ds
|
||||||
|
pop es
|
||||||
|
o32 mov edi, dpmi_edi
|
||||||
|
mov ax, 0x300
|
||||||
|
o32 shr ebx, 16
|
||||||
|
xor cx, cx
|
||||||
|
int 0x31 ! simulate DOS interrupt
|
||||||
|
pop es
|
||||||
|
o32 mov eax, (dpmi_eax)
|
||||||
|
o32 mov ebx, (dpmi_ebx)
|
||||||
|
o32 mov ecx, (dpmi_ecx)
|
||||||
|
o32 mov edx, (dpmi_edx)
|
||||||
|
o32 mov esi, (dpmi_esi)
|
||||||
|
o32 mov edi, (dpmi_edi)
|
||||||
|
push (dpmi_flags)
|
||||||
|
popf
|
||||||
|
ret
|
||||||
|
|
||||||
|
! Far call wrapper around interrupt.
|
||||||
|
interruptf:
|
||||||
|
push ds
|
||||||
|
cseg mov ds, (psegds)
|
||||||
|
call interrupt
|
||||||
|
pop ds
|
||||||
|
o32 retf
|
||||||
|
|
||||||
|
bad_dpmi_msg:
|
||||||
|
.asciz "DPMI error during setup"
|
||||||
|
no_file_msg:
|
||||||
|
.asciz "Couldn't open .exe"
|
||||||
|
no_dpmi_msg:
|
||||||
|
.asciz "No DPMI host installed"
|
||||||
|
.align 4
|
||||||
|
text_top:
|
||||||
|
|
||||||
|
exe_text_pages = [text_top - exe_header + 511] / 512
|
||||||
|
exe_last_page = [text_top - exe_header] % 512
|
||||||
|
|
||||||
|
.sect .rom
|
||||||
|
|
||||||
|
.sect .bss
|
||||||
|
bss_start:
|
||||||
|
|
||||||
|
dpmi_edi: .space 4
|
||||||
|
dpmi_esi: .space 4
|
||||||
|
dpmi_ebp: .space 4
|
||||||
|
.space 4 ! reserved
|
||||||
|
dpmi_ebx: .space 4
|
||||||
|
dpmi_edx: .space 4
|
||||||
|
dpmi_ecx: .space 4
|
||||||
|
dpmi_eax: .space 4
|
||||||
|
dpmi_flags: .space 2
|
||||||
|
dpmi_es: .space 2
|
||||||
|
dpmi_ds: .space 2
|
||||||
|
dpmi_fs: .space 2
|
||||||
|
dpmi_gs: .space 2
|
||||||
|
dpmi_ip: .space 2
|
||||||
|
dpmi_cs: .space 2
|
||||||
|
dpmi_sp: .space 2
|
||||||
|
dpmi_ss: .space 2
|
||||||
|
|
||||||
|
pmode_switch: .space 4
|
||||||
|
rseg: .space 2 ! real mode
|
||||||
|
pspseg: .space 2 ! real mode
|
||||||
|
psegcs: .space 2 ! protected mode 16-bit code segment
|
||||||
|
psegds: .space 2 ! protected mode 16-bit data segment
|
||||||
|
psegcs32: .space 2 ! protected mode 32-bit code segment
|
||||||
|
psegds32: .space 2 ! protected mode 32-bit data segment
|
||||||
|
pmemaddr: .space 4 ! protected mode linear memory address
|
||||||
|
pmemhandle: .space 4 ! protected mode linear memory handle
|
||||||
|
pmemlen: .space 4 ! protected mode linear memory length
|
||||||
|
fh: .space 2
|
||||||
|
|
||||||
|
.space 512
|
||||||
|
stack:
|
||||||
|
.space 512
|
||||||
|
dosstack:
|
||||||
|
|
||||||
|
transfer_buffer:
|
||||||
|
.space TRANSFER_BUFFER_SIZE
|
||||||
|
|
||||||
|
bss_top:
|
||||||
|
exe_ram_paras = [bss_top - bss_start + 15] / 16
|
||||||
|
|
||||||
|
! vim: ts=4 sw=4 et ft=asm
|
||||||
|
|
|
@ -84,5 +84,5 @@ name cv
|
||||||
mapflag -i LOD=amzlod
|
mapflag -i LOD=amzlod
|
||||||
program {EM}/bin/{LOD}
|
program {EM}/bin/{LOD}
|
||||||
args < >
|
args < >
|
||||||
outfile msdos86.exe
|
outfile msdos86.com
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,41 +3,28 @@ acklibrary {
|
||||||
srcs = {
|
srcs = {
|
||||||
"./brk.c",
|
"./brk.c",
|
||||||
"./close.s",
|
"./close.s",
|
||||||
"./creat.c",
|
|
||||||
"./errno.s",
|
"./errno.s",
|
||||||
"./getpid.s",
|
"./getpid.s",
|
||||||
"./gettimeofday.c",
|
|
||||||
"./_hol0.s",
|
"./_hol0.s",
|
||||||
"./isatty.s",
|
"./isatty.s",
|
||||||
"./kill.c",
|
"./rename.s",
|
||||||
"./lseek.c",
|
|
||||||
"./open.c",
|
|
||||||
"./read.c",
|
|
||||||
"./setmode.c",
|
|
||||||
"./signal.c",
|
|
||||||
"./sys_exists.s",
|
"./sys_exists.s",
|
||||||
"./sys_fdmodes.c",
|
|
||||||
"./sys_getdate.s",
|
"./sys_getdate.s",
|
||||||
"./sys_getmode.c",
|
|
||||||
"./sys_gettime.s",
|
"./sys_gettime.s",
|
||||||
"./sys_initmain.c",
|
|
||||||
"./sys_iseof.c",
|
|
||||||
"./sys_isopen.s",
|
"./sys_isopen.s",
|
||||||
"./sys_isreadyr.s",
|
"./sys_isreadyr.s",
|
||||||
"./sys_rawcreat.s",
|
"./sys_rawcreat.s",
|
||||||
"./sys_rawlseek.s",
|
"./sys_rawlseek.s",
|
||||||
"./sys_rawopen.s",
|
"./sys_rawopen.s",
|
||||||
"./sys_rawrw.s",
|
"./sys_rawrw.s",
|
||||||
"./sys_seteof.c",
|
|
||||||
"./sys_seterrno.c",
|
|
||||||
"./sys_setmode.c",
|
|
||||||
"./sys_xret.s",
|
"./sys_xret.s",
|
||||||
"./unlink.s",
|
"./unlink.s",
|
||||||
"./write.c",
|
"plat/msdos/libsys+srcs",
|
||||||
},
|
},
|
||||||
deps = {
|
deps = {
|
||||||
"lang/cem/libcc.ansi/headers+headers",
|
"lang/cem/libcc.ansi/headers+headers",
|
||||||
"plat/msdos86/include+headers",
|
"plat/msdos86/include+headers",
|
||||||
|
"plat/msdos/libsys+headers",
|
||||||
},
|
},
|
||||||
vars = {
|
vars = {
|
||||||
plat = "msdos86"
|
plat = "msdos86"
|
||||||
|
|
26
plat/msdos86/libsys/rename.s
Normal file
26
plat/msdos86/libsys/rename.s
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
! $Revision$
|
||||||
|
|
||||||
|
! Declare segments (the order is important).
|
||||||
|
|
||||||
|
.sect .text
|
||||||
|
.sect .rom
|
||||||
|
.sect .data
|
||||||
|
.sect .bss
|
||||||
|
|
||||||
|
.sect .text
|
||||||
|
|
||||||
|
! Rename a file.
|
||||||
|
|
||||||
|
.define _rename
|
||||||
|
_rename:
|
||||||
|
mov bx, sp
|
||||||
|
push di
|
||||||
|
mov dx, 2(bx)
|
||||||
|
mov di, 4(bx)
|
||||||
|
movb ah, 0x56
|
||||||
|
int 0x21
|
||||||
|
pop di
|
||||||
|
jmp .sys_zret
|
|
@ -1,61 +0,0 @@
|
||||||
/* $Source$
|
|
||||||
* $State$
|
|
||||||
* $Revision$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include "libsys.h"
|
|
||||||
|
|
||||||
ssize_t write(int fd, void* buffer, size_t count)
|
|
||||||
{
|
|
||||||
static const char crlf[2] = "\r\n";
|
|
||||||
int i;
|
|
||||||
char *p, *q;
|
|
||||||
size_t left, n;
|
|
||||||
ssize_t r, tot;
|
|
||||||
|
|
||||||
if (!count)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (_sys_getmode(fd) == O_BINARY)
|
|
||||||
return _sys_rawwrite(fd, buffer, count);
|
|
||||||
|
|
||||||
/* If the file descriptor is an O_TEXT fd, translate LFs to CRLFs. */
|
|
||||||
p = buffer;
|
|
||||||
left = count;
|
|
||||||
tot = 0;
|
|
||||||
while (left)
|
|
||||||
{
|
|
||||||
q = memchr(p, '\n', left);
|
|
||||||
if (!q)
|
|
||||||
return _sys_rawwrite(fd, p, left);
|
|
||||||
|
|
||||||
n = q - p;
|
|
||||||
if (n)
|
|
||||||
{
|
|
||||||
r = _sys_rawwrite(fd, p, n);
|
|
||||||
if (r <= 0)
|
|
||||||
return tot ? tot : r;
|
|
||||||
tot += r;
|
|
||||||
p += r;
|
|
||||||
left -= r;
|
|
||||||
if (r != n)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = _sys_rawwrite(fd, crlf, sizeof crlf);
|
|
||||||
if (r != 2)
|
|
||||||
{
|
|
||||||
if (r > 0)
|
|
||||||
r = 0;
|
|
||||||
return tot ? tot : r;
|
|
||||||
}
|
|
||||||
++tot;
|
|
||||||
++p;
|
|
||||||
--left;
|
|
||||||
}
|
|
||||||
return tot;
|
|
||||||
}
|
|
|
@ -302,8 +302,23 @@ argv: .data2 exename, 0
|
||||||
envp: .data2 0
|
envp: .data2 0
|
||||||
exename: .asciz 'pc86.img'
|
exename: .asciz 'pc86.img'
|
||||||
|
|
||||||
|
! A degenerate "hard disk partition table" covering this boot
|
||||||
|
! sector (possibly needed if booting from a USB drive).
|
||||||
|
|
||||||
|
.seek 0x1BE
|
||||||
|
.data1 0x80 ! boot indicator (0x80 = active)
|
||||||
|
.data1 0x00 ! partition start head
|
||||||
|
.data1 0x01 ! partition start sector and start track high
|
||||||
|
.data1 0x00 ! partition start track low
|
||||||
|
.data1 0x7F ! OS or filesystem indicator
|
||||||
|
.data1 0xFF ! partition end head
|
||||||
|
.data1 0xFF ! partition end sector and end track high
|
||||||
|
.data1 0xFF ! partition end track low
|
||||||
|
.data4 0 ! partition start LBA
|
||||||
|
.data4 0xFFFFFFFF ! length of partition in sectors
|
||||||
|
|
||||||
! ...and we need this to fool the PC into booting our boot sector.
|
! ...and we need this to fool the PC into booting our boot sector.
|
||||||
|
|
||||||
.seek 0x1FE
|
.seek 0x1FE
|
||||||
.data2 0xAA55
|
.data2 0xAA55
|
||||||
|
|
||||||
|
|
|
@ -12,29 +12,9 @@ errcho() {
|
||||||
|
|
||||||
get_test_output() {
|
get_test_output() {
|
||||||
case $method in
|
case $method in
|
||||||
qemu-system-*)
|
|
||||||
if ! command -v $method >/dev/null 2>&1 ; then
|
|
||||||
errcho "Warning: $method not installed, skipping test"
|
|
||||||
echo "@@SKIPPED"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
case $method in
|
|
||||||
qemu-system-i386) img="-drive file=$img,if=floppy,format=raw" ;;
|
|
||||||
qemu-system-ppc) img="-kernel $img" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
$timeoutprog -t $timeout -- $method -nographic $img 2>&1
|
|
||||||
;;
|
|
||||||
|
|
||||||
qemu-*)
|
qemu-*)
|
||||||
if ! command -v $method >/dev/null 2>&1 ; then
|
errcho "qemu tests no longer supported (method $method)"
|
||||||
errcho "Warning: $method not installed, skipping test"
|
exit 1
|
||||||
echo "@@SKIPPED"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
$method $img 2>&1
|
|
||||||
;;
|
;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
|
|
|
@ -42,11 +42,11 @@ $(OBJDIR)/%.o: %.c
|
||||||
|
|
||||||
$(OBJDIR)/%.pdf: doc/%.n doc/LLgen.refs
|
$(OBJDIR)/%.pdf: doc/%.n doc/LLgen.refs
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
refer $< | groff -G -e -g -p -ms -Tpdf $< > $@
|
refer -p doc/LLgen.refs $< | groff -G -e -g -p -ms -Tpdf $< > $@
|
||||||
|
|
||||||
$(OBJDIR)/%/index.html: doc/%.n doc/LLgen.refs
|
$(OBJDIR)/%/index.html: doc/%.n doc/LLgen.refs
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
refer $< | (cd $(dir $@) && groff -I$(PWD) -G -e -g -p -ms -Thtml) > $@
|
(cd $(dir $@) && refer -p $(PWD)/doc/LLgen.refs | groff -G -e -g -p -ms -Thtml) < $< > $@
|
||||||
|
|
||||||
doc:: $(PDFS) $(HTMLS)
|
doc:: $(PDFS) $(HTMLS)
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
\}\
|
\}\
|
||||||
\}
|
\}
|
||||||
.R1
|
.R1
|
||||||
database doc/LLgen.refs
|
|
||||||
accumulate
|
accumulate
|
||||||
.R2
|
.R2
|
||||||
.ND
|
.ND
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
.RP
|
|
||||||
.TL
|
.TL
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
aslod \- ACK simple loader
|
aslod \- ACK simple loader
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.B aslod
|
.B aslod
|
||||||
[\-h] [\-v] inputfile outputfile
|
[\-h] [\-v] [\-p prefixfile] inputfile outputfile
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
.I aslod
|
.I aslod
|
||||||
converts an absolute ack.out file into a simple binary memory dump.
|
converts an absolute ack.out file into a simple binary memory dump.
|
||||||
|
@ -16,5 +16,8 @@ The file must have all references resolved and be linked to a
|
||||||
fixed address. aslod will dump the segments, in order, such
|
fixed address. aslod will dump the segments, in order, such
|
||||||
that the first byte of TEXT is at offset 0 in the file
|
that the first byte of TEXT is at offset 0 in the file
|
||||||
(regardless of where it is in memory).
|
(regardless of where it is in memory).
|
||||||
|
.PP
|
||||||
|
If a prefix file is specified, this is prepended to the output before writing.
|
||||||
|
No changes to the output itself are made.
|
||||||
.SH "SEE ALSO"
|
.SH "SEE ALSO"
|
||||||
ack.out(5)
|
ack.out(5)
|
||||||
|
|
|
@ -37,6 +37,7 @@ struct outsect outsect[S_MAX];
|
||||||
char* stringarea;
|
char* stringarea;
|
||||||
|
|
||||||
char* outputfile = NULL; /* Name of output file, or NULL */
|
char* outputfile = NULL; /* Name of output file, or NULL */
|
||||||
|
char* prefixfile = NULL; /* Name of prefix file, or NULL */
|
||||||
char* program; /* Name of current program: argv[0] */
|
char* program; /* Name of current program: argv[0] */
|
||||||
|
|
||||||
FILE* input; /* Input stream */
|
FILE* input; /* Input stream */
|
||||||
|
@ -136,6 +137,19 @@ void emits(struct outsect* section, struct outsect* nextsect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void emitprefixfile(void)
|
||||||
|
{
|
||||||
|
FILE* fp = fopen(prefixfile, "rb");
|
||||||
|
|
||||||
|
while (!feof(fp))
|
||||||
|
{
|
||||||
|
char buffer[BUFSIZ];
|
||||||
|
size_t blocksize = fread(buffer, 1, BUFSIZ, fp);
|
||||||
|
writef(buffer, 1, blocksize);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
/* Macros from modules/src/object/obj.h */
|
/* Macros from modules/src/object/obj.h */
|
||||||
#define Xchar(ch) ((ch) & 0377)
|
#define Xchar(ch) ((ch) & 0377)
|
||||||
|
@ -204,6 +218,12 @@ int main(int argc, char* argv[])
|
||||||
verbose = true;
|
verbose = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'p':
|
||||||
|
argv++;
|
||||||
|
argc--;
|
||||||
|
prefixfile = argv[1];
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
syntaxerror:
|
syntaxerror:
|
||||||
fatal("syntax error --- try -h for help");
|
fatal("syntax error --- try -h for help");
|
||||||
|
@ -288,6 +308,8 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
/* And go! */
|
/* And go! */
|
||||||
|
|
||||||
|
if (prefixfile)
|
||||||
|
emitprefixfile();
|
||||||
emits(&outsect[TEXT], &outsect[ROM]);
|
emits(&outsect[TEXT], &outsect[ROM]);
|
||||||
emits(&outsect[ROM], &outsect[DATA]);
|
emits(&outsect[ROM], &outsect[DATA]);
|
||||||
emits(&outsect[DATA], NULL);
|
emits(&outsect[DATA], NULL);
|
||||||
|
|
|
@ -18,7 +18,7 @@ normalrule {
|
||||||
},
|
},
|
||||||
outleaves = { "enterkeyw.c" },
|
outleaves = { "enterkeyw.c" },
|
||||||
commands = {
|
commands = {
|
||||||
"$LUA %{ins[1]} < %{ins[2]} > %{outs[1]}"
|
"$(LUA) %{ins[1]} < %{ins[2]} > %{outs[1]}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue