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
|
||||
2022-06-18
|
||||
2022-08-19
|
||||
|
||||
|
||||
INTRODUCTION
|
||||
|
@ -38,6 +38,7 @@ cpm produces i80 CP/M .COM files
|
|||
rpi produces Raspberry Pi GPU binaries
|
||||
pdpv7 produces PDP/11 V7 Unix binaries
|
||||
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
|
||||
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 15MB in the target directory.
|
||||
|
|
|
@ -12,6 +12,7 @@ vars.plats = {
|
|||
"linuxppc",
|
||||
"linuxmips",
|
||||
"msdos86",
|
||||
"msdos386",
|
||||
"osx386",
|
||||
"osxppc",
|
||||
"pc86",
|
||||
|
@ -22,9 +23,9 @@ vars.plats = {
|
|||
vars.plats_with_tests = {
|
||||
"cpm",
|
||||
"linux68k",
|
||||
"linux386",
|
||||
--"linux386",
|
||||
"linuxppc",
|
||||
"linuxmips",
|
||||
--"linuxmips",
|
||||
"pc86",
|
||||
}
|
||||
|
||||
|
|
|
@ -225,7 +225,7 @@ definerule("cprogram",
|
|||
commands = {
|
||||
type="strings",
|
||||
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, 0252, "stosb"},
|
||||
{0, NOOP_1, 0253, "stos"},
|
||||
{0, NOOP_1, 0253, "stosw"},
|
||||
{0, NOOP_1, 0254, "lodsb"},
|
||||
{0, NOOP_1, 0255, "lods"},
|
||||
{0, NOOP_1, 0255, "lodsw"},
|
||||
{0, NOOP_1, 0256, "scasb"},
|
||||
{0, NOOP_1, 0257, "scas"},
|
||||
{0, NOOP_1, 0257, "scasw"},
|
||||
{0, NOOP_1, 0311, "leave"},
|
||||
{0, NOOP_1, 0316, "into"},
|
||||
{0, NOOP_1, 0317, "iret"},
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
|
||||
void ea_1_16(int param)
|
||||
{
|
||||
reg_1 &= 0377;
|
||||
if ((reg_1 & 070) || (param & ~070)) {
|
||||
reg_1 &= 0377;
|
||||
if (param & ~070) {
|
||||
serror("bad operand");
|
||||
}
|
||||
emit1(reg_1 | param);
|
||||
|
@ -39,542 +39,545 @@ void ea_1_16(int param)
|
|||
}
|
||||
|
||||
void ea_1(int param) {
|
||||
if (! address_long) {
|
||||
ea_1_16(param);
|
||||
return;
|
||||
}
|
||||
if (is_expr(reg_1)) {
|
||||
serror("bad operand");
|
||||
return;
|
||||
}
|
||||
if (is_reg(reg_1)) {
|
||||
emit1(0300 | param | (reg_1&07));
|
||||
return;
|
||||
}
|
||||
if (rm_1 == 04) {
|
||||
/* sib field use here */
|
||||
emit1(mod_1 << 6 | param | 04);
|
||||
emit1(sib_1 | reg_1);
|
||||
}
|
||||
else emit1(mod_1<<6 | param | (reg_1&07));
|
||||
if ((mod_1 == 0 && reg_1 == 5) || mod_1 == 2) {
|
||||
/* ??? should this be protected by a call to "small" ??? */
|
||||
if (! address_long) {
|
||||
ea_1_16(param);
|
||||
return;
|
||||
}
|
||||
if (is_expr(reg_1)) {
|
||||
serror("bad operand");
|
||||
return;
|
||||
}
|
||||
if (is_reg(reg_1)) {
|
||||
emit1(0300 | param | (reg_1&07));
|
||||
return;
|
||||
}
|
||||
if (rm_1 == 04) {
|
||||
/* sib field use here */
|
||||
emit1(mod_1 << 6 | param | 04);
|
||||
emit1(sib_1 | reg_1);
|
||||
}
|
||||
else emit1(mod_1<<6 | param | (reg_1&07));
|
||||
if ((mod_1 == 0 && reg_1 == 5) || mod_1 == 2) {
|
||||
/* ??? should this be protected by a call to "small" ??? */
|
||||
#ifdef RELOCATION
|
||||
RELOMOVE(relonami, rel_1);
|
||||
newrelo(exp_1.typ, RELO4);
|
||||
RELOMOVE(relonami, rel_1);
|
||||
newrelo(exp_1.typ, RELO4);
|
||||
#endif
|
||||
emit4((long)(exp_1.val));
|
||||
}
|
||||
else if (mod_1 == 1) {
|
||||
emit1((int)(exp_1.val));
|
||||
}
|
||||
emit4((long)(exp_1.val));
|
||||
}
|
||||
else if (mod_1 == 1) {
|
||||
emit1((int)(exp_1.val));
|
||||
}
|
||||
}
|
||||
|
||||
void ea_2(int param) {
|
||||
|
||||
op_1 = op_2;
|
||||
RELOMOVE(rel_1, rel_2);
|
||||
ea_1(param);
|
||||
op_1 = op_2;
|
||||
RELOMOVE(rel_1, rel_2);
|
||||
ea_1(param);
|
||||
}
|
||||
|
||||
int checkscale(valu_t val)
|
||||
{
|
||||
int v = val;
|
||||
int v = val;
|
||||
|
||||
if (! address_long) {
|
||||
serror("scaling not allowed in 16-bit mode");
|
||||
return 0;
|
||||
}
|
||||
if (v != val) v = 0;
|
||||
switch(v) {
|
||||
case 1:
|
||||
return 0;
|
||||
case 2:
|
||||
return 1 << 6;
|
||||
case 4:
|
||||
return 2 << 6;
|
||||
case 8:
|
||||
return 3 << 6;
|
||||
default:
|
||||
serror("bad scale");
|
||||
return 0;
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
if (! address_long) {
|
||||
serror("scaling not allowed in 16-bit mode");
|
||||
return 0;
|
||||
}
|
||||
if (v != val) v = 0;
|
||||
switch(v) {
|
||||
case 1:
|
||||
return 0;
|
||||
case 2:
|
||||
return 1 << 6;
|
||||
case 4:
|
||||
return 2 << 6;
|
||||
case 8:
|
||||
return 3 << 6;
|
||||
default:
|
||||
serror("bad scale");
|
||||
return 0;
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
void reverse(void) {
|
||||
struct operand op;
|
||||
struct operand op;
|
||||
#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
|
||||
op = op_1; op_1 = op_2; op_2 = op;
|
||||
op = op_1; op_1 = op_2; op_2 = op;
|
||||
}
|
||||
|
||||
void badsyntax(void)
|
||||
{
|
||||
|
||||
serror("bad operands");
|
||||
serror("bad operands");
|
||||
}
|
||||
|
||||
void regsize(int sz)
|
||||
{
|
||||
register int bit;
|
||||
register int bit;
|
||||
|
||||
bit = (sz&1) ? 0 : IS_R8;
|
||||
if ((is_reg(reg_1) && (reg_1 & IS_R8) != bit) ||
|
||||
(is_reg(reg_2) && (reg_2 & IS_R8) != bit))
|
||||
serror("register error");
|
||||
if (! address_long) {
|
||||
reg_1 &= ~010;
|
||||
reg_2 &= ~010;
|
||||
}
|
||||
bit = (sz&1) ? 0 : IS_R8;
|
||||
if ((is_reg(reg_1) && (reg_1 & IS_R8) != bit) ||
|
||||
(is_reg(reg_2) && (reg_2 & IS_R8) != bit))
|
||||
serror("register error");
|
||||
if (! address_long) {
|
||||
reg_1 &= ~010;
|
||||
reg_2 &= ~010;
|
||||
}
|
||||
}
|
||||
|
||||
void indexed(void) {
|
||||
if (address_long) {
|
||||
mod_2 = 0;
|
||||
if (sib_2 == -1)
|
||||
serror("register error");
|
||||
if (rm_2 == 0 && reg_2 == 4) {
|
||||
/* base register sp, no index register; use
|
||||
indexed mode without index register
|
||||
*/
|
||||
rm_2 = 04;
|
||||
sib_2 = 044;
|
||||
}
|
||||
if (reg_2 == 015) {
|
||||
reg_2 = 05;
|
||||
return;
|
||||
}
|
||||
if (small(exp_2.typ == S_ABS && fitb(exp_2.val), 3)) {
|
||||
if (small(exp_2.val == 0 && reg_2 != 5, 1)) {
|
||||
}
|
||||
else mod_2 = 01;
|
||||
}
|
||||
else if (small(0, 1)) {
|
||||
}
|
||||
else mod_2 = 02;
|
||||
}
|
||||
else {
|
||||
if (reg_2 & ~7)
|
||||
serror("register error");
|
||||
if (small(exp_2.typ == S_ABS && fitb(exp_2.val), 1)) {
|
||||
if (small(exp_2.val == 0 && reg_2 != 6, 1)) {
|
||||
}
|
||||
else reg_2 |= 0100;
|
||||
}
|
||||
else if (small(0, 1)) {
|
||||
}
|
||||
else reg_2 |= 0200;
|
||||
}
|
||||
if (address_long) {
|
||||
mod_2 = 0;
|
||||
if (sib_2 == -1)
|
||||
serror("register error");
|
||||
if (rm_2 == 0 && reg_2 == 4) {
|
||||
/* base register sp, no index register; use
|
||||
indexed mode without index register
|
||||
*/
|
||||
rm_2 = 04;
|
||||
sib_2 = 044;
|
||||
}
|
||||
if (reg_2 == 015) {
|
||||
reg_2 = 05;
|
||||
return;
|
||||
}
|
||||
if (small(exp_2.typ == S_ABS && fitb(exp_2.val), 3)) {
|
||||
if (small(exp_2.val == 0 && reg_2 != 5, 1)) {
|
||||
}
|
||||
else mod_2 = 01;
|
||||
}
|
||||
else if (small(0, 1)) {
|
||||
}
|
||||
else mod_2 = 02;
|
||||
}
|
||||
else {
|
||||
if (reg_2 & ~7)
|
||||
serror("register error");
|
||||
if (small(exp_2.typ == S_ABS && fitb(exp_2.val), 1)) {
|
||||
if (small(exp_2.val == 0 && reg_2 != 6, 1)) {
|
||||
}
|
||||
else reg_2 |= 0100;
|
||||
}
|
||||
else if (small(0, 1)) {
|
||||
}
|
||||
else reg_2 |= 0200;
|
||||
}
|
||||
}
|
||||
|
||||
void ebranch(register int opc,expr_t exp)
|
||||
{
|
||||
/* Conditional branching; Full displacements are available
|
||||
on the 80386, so the welknown trick with the reverse branch
|
||||
over a jump is not needed here.
|
||||
The only complication here is with the address size, which
|
||||
can be set with a prefix. In this case, the user gets what
|
||||
he asked for.
|
||||
*/
|
||||
register int sm;
|
||||
register long dist;
|
||||
int saving = address_long ? 4 : 2;
|
||||
/* Conditional branching; Full displacements are available
|
||||
on the 80386, so the welknown trick with the reverse branch
|
||||
over a jump is not needed here.
|
||||
The only complication here is with the address size, which
|
||||
can be set with a prefix. In this case, the user gets what
|
||||
he asked for.
|
||||
*/
|
||||
register int sm;
|
||||
register long dist;
|
||||
int saving = address_long ? 4 : 2;
|
||||
|
||||
if (opc == 0353) saving--;
|
||||
dist = exp.val - (DOTVAL + 2);
|
||||
if (pass == PASS_2 && dist > 0 && !(exp.typ & S_DOT))
|
||||
dist -= DOTGAIN;
|
||||
sm = dist > 0 ? fitb(dist-saving) : fitb(dist);
|
||||
if ((exp.typ & ~S_DOT) != DOTTYP)
|
||||
sm = 0;
|
||||
if ((sm = small(sm,saving)) == 0) {
|
||||
if (opc == 0353) {
|
||||
emit1(0xe9);
|
||||
}
|
||||
else {
|
||||
emit1(0xF);
|
||||
emit1(opc | 0x80);
|
||||
}
|
||||
dist -= saving;
|
||||
exp.val = dist;
|
||||
adsize_exp(exp, RELPC);
|
||||
}
|
||||
else {
|
||||
if (opc == 0353) {
|
||||
emit1(opc);
|
||||
}
|
||||
else {
|
||||
emit1(opc | 0x70);
|
||||
}
|
||||
emit1((int)dist);
|
||||
}
|
||||
if (opc == 0353) saving--;
|
||||
dist = exp.val - (DOTVAL + 2);
|
||||
if (pass == PASS_2 && dist > 0 && !(exp.typ & S_DOT))
|
||||
dist -= DOTGAIN;
|
||||
sm = dist > 0 ? fitb(dist-saving) : fitb(dist);
|
||||
if ((exp.typ & ~S_DOT) != DOTTYP)
|
||||
sm = 0;
|
||||
if ((sm = small(sm,saving)) == 0) {
|
||||
if (opc == 0353) {
|
||||
emit1(0xe9);
|
||||
}
|
||||
else {
|
||||
emit1(0xF);
|
||||
emit1(opc | 0x80);
|
||||
}
|
||||
dist -= saving;
|
||||
exp.val = dist;
|
||||
adsize_exp(exp, RELPC);
|
||||
}
|
||||
else {
|
||||
if (opc == 0353) {
|
||||
emit1(opc);
|
||||
}
|
||||
else {
|
||||
emit1(opc | 0x70);
|
||||
}
|
||||
emit1((int)dist);
|
||||
}
|
||||
}
|
||||
|
||||
void branch(register int opc,expr_t exp)
|
||||
{
|
||||
/* LOOP, JCXZ, etc. branch instructions.
|
||||
Here, the offset just must fit in a byte.
|
||||
*/
|
||||
register long dist;
|
||||
/* LOOP, JCXZ, etc. branch instructions.
|
||||
Here, the offset just must fit in a byte.
|
||||
*/
|
||||
register long dist;
|
||||
|
||||
dist = exp.val - (DOTVAL + 2);
|
||||
if (pass == PASS_2 && dist > 0 && !(exp.typ & S_DOT))
|
||||
dist -= DOTGAIN;
|
||||
fit((exp.typ & ~S_DOT) == DOTTYP && fitb(dist));
|
||||
emit1(opc);
|
||||
emit1((int)dist);
|
||||
dist = exp.val - (DOTVAL + 2);
|
||||
if (pass == PASS_2 && dist > 0 && !(exp.typ & S_DOT))
|
||||
dist -= DOTGAIN;
|
||||
fit((exp.typ & ~S_DOT) == DOTTYP && fitb(dist));
|
||||
emit1(opc);
|
||||
emit1((int)dist);
|
||||
}
|
||||
|
||||
void pushop(register int opc)
|
||||
{
|
||||
|
||||
regsize(1);
|
||||
if (is_segreg(reg_1)) {
|
||||
/* segment register */
|
||||
if ((reg_1 & 07) <= 3)
|
||||
emit1(6 | opc | (reg_1&7)<<3);
|
||||
else {
|
||||
emit1(0xF);
|
||||
emit1(0200 | opc | ((reg_1&7)<<3));
|
||||
}
|
||||
} else if (is_reg(reg_1)) {
|
||||
/* normal register */
|
||||
emit1(0120 | opc<<3 | (reg_1&7));
|
||||
} else if (opc == 0) {
|
||||
if (is_expr(reg_1)) {
|
||||
if (small(exp_1.typ == S_ABS && fitb(exp_1.val),
|
||||
operand_long ? 3 : 1)) {
|
||||
emit1(0152);
|
||||
emit1((int)(exp_1.val));
|
||||
}
|
||||
else {
|
||||
emit1(0150);
|
||||
RELOMOVE(relonami, rel_1);
|
||||
opsize_exp(exp_1, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
emit1(0377); ea_1(6<<3);
|
||||
}
|
||||
} else {
|
||||
emit1(0217); ea_1(0<<3);
|
||||
}
|
||||
regsize(1);
|
||||
if (is_segreg(reg_1)) {
|
||||
/* segment register */
|
||||
if ((reg_1 & 07) <= 3)
|
||||
emit1(6 | opc | (reg_1&7)<<3);
|
||||
else {
|
||||
emit1(0xF);
|
||||
emit1(0200 | opc | ((reg_1&7)<<3));
|
||||
}
|
||||
} else if (is_reg(reg_1)) {
|
||||
/* normal register */
|
||||
emit1(0120 | opc<<3 | (reg_1&7));
|
||||
} else if (opc == 0) {
|
||||
if (is_expr(reg_1)) {
|
||||
if (small(exp_1.typ == S_ABS && fitb(exp_1.val),
|
||||
operand_long ? 3 : 1)) {
|
||||
emit1(0152);
|
||||
emit1((int)(exp_1.val));
|
||||
}
|
||||
else {
|
||||
emit1(0150);
|
||||
RELOMOVE(relonami, rel_1);
|
||||
opsize_exp(exp_1, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
emit1(0377); ea_1(6<<3);
|
||||
}
|
||||
} else {
|
||||
emit1(0217); ea_1(0<<3);
|
||||
}
|
||||
}
|
||||
|
||||
void opsize_exp(expr_t exp, int nobyte)
|
||||
{
|
||||
if (! nobyte) {
|
||||
if (! nobyte) {
|
||||
#ifdef RELOCATION
|
||||
newrelo(exp.typ, RELO1);
|
||||
newrelo(exp.typ, RELO1);
|
||||
#endif
|
||||
emit1((int)(exp.val));
|
||||
}
|
||||
else if (operand_long) {
|
||||
emit1((int)(exp.val));
|
||||
}
|
||||
else if (operand_long) {
|
||||
#ifdef RELOCATION
|
||||
newrelo(exp.typ, RELO4);
|
||||
newrelo(exp.typ, RELO4);
|
||||
#endif
|
||||
emit4((long)(exp.val));
|
||||
}
|
||||
else {
|
||||
emit4((long)(exp.val));
|
||||
}
|
||||
else {
|
||||
#ifdef RELOCATION
|
||||
newrelo(exp.typ, RELO2);
|
||||
newrelo(exp.typ, RELO2);
|
||||
#endif
|
||||
emit2((int)(exp.val));
|
||||
}
|
||||
emit2((int)(exp.val));
|
||||
}
|
||||
}
|
||||
|
||||
void adsize_exp(expr_t exp, int relpc)
|
||||
{
|
||||
if (address_long) {
|
||||
if (address_long) {
|
||||
#ifdef RELOCATION
|
||||
newrelo(exp.typ, RELO4 | relpc);
|
||||
newrelo(exp.typ, RELO4 | relpc);
|
||||
#endif
|
||||
emit4((long)(exp.val));
|
||||
}
|
||||
else {
|
||||
emit4((long)(exp.val));
|
||||
}
|
||||
else {
|
||||
#ifdef RELOCATION
|
||||
newrelo(exp.typ, RELO2 | relpc);
|
||||
newrelo(exp.typ, RELO2 | relpc);
|
||||
#endif
|
||||
emit2((int)(exp.val));
|
||||
}
|
||||
emit2((int)(exp.val));
|
||||
}
|
||||
}
|
||||
|
||||
void addop(register int opc)
|
||||
{
|
||||
|
||||
regsize(opc);
|
||||
if (is_reg(reg_2)) {
|
||||
/* Add register to register or memory */
|
||||
emit1(opc); ea_1((reg_2&7)<<3);
|
||||
} else if (is_acc(reg_1) && is_expr(reg_2)) {
|
||||
/* Add immediate to accumulator */
|
||||
emit1(opc | 4);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
opsize_exp(exp_2, (opc&1));
|
||||
} else if (is_expr(reg_2)) {
|
||||
/* Add immediate to register or memory */
|
||||
if ((opc&1) == 0) {
|
||||
emit1(0200);
|
||||
} else if (! small(exp_2.typ == S_ABS && fitb(exp_2.val),
|
||||
operand_long ? 3 : 1)) {
|
||||
emit1(0201);
|
||||
} else {
|
||||
emit1(0203); opc &= ~1;
|
||||
}
|
||||
ea_1(opc & 070);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
opsize_exp(exp_2, (opc&1));
|
||||
} else if (is_reg(reg_1)) {
|
||||
/* Add register or memory to register */
|
||||
emit1(opc | 2);
|
||||
ea_2((reg_1&7)<<3);
|
||||
} else
|
||||
badsyntax();
|
||||
regsize(opc);
|
||||
if (is_reg(reg_2)) {
|
||||
/* Add register to register or memory */
|
||||
emit1(opc); ea_1((reg_2&7)<<3);
|
||||
} else if (is_acc(reg_1) && is_expr(reg_2)) {
|
||||
/* Add immediate to accumulator */
|
||||
emit1(opc | 4);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
opsize_exp(exp_2, (opc&1));
|
||||
} else if (is_expr(reg_2)) {
|
||||
/* Add immediate to register or memory */
|
||||
if ((opc&1) == 0) {
|
||||
emit1(0200);
|
||||
} else if (! small(exp_2.typ == S_ABS && fitb(exp_2.val),
|
||||
operand_long ? 3 : 1)) {
|
||||
emit1(0201);
|
||||
} else {
|
||||
emit1(0203); opc &= ~1;
|
||||
}
|
||||
ea_1(opc & 070);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
opsize_exp(exp_2, (opc&1));
|
||||
} else if (is_reg(reg_1)) {
|
||||
/* Add register or memory to register */
|
||||
emit1(opc | 2);
|
||||
ea_2((reg_1&7)<<3);
|
||||
} else
|
||||
badsyntax();
|
||||
}
|
||||
|
||||
void rolop(register int opc)
|
||||
{
|
||||
register int oreg;
|
||||
register int oreg;
|
||||
|
||||
oreg = reg_2;
|
||||
reg_2 = reg_1;
|
||||
regsize(opc);
|
||||
if (oreg == (IS_R8 | 1 | (address_long ? 0 : 0300))) {
|
||||
/* cl register */
|
||||
emit1(0322 | (opc&1)); ea_1(opc&070);
|
||||
} else if (is_expr(oreg)) {
|
||||
if (small(exp_2.typ == S_ABS && exp_2.val == 1, 1)) {
|
||||
/* shift by 1 */
|
||||
emit1(0320 | (opc&1)); ea_1(opc&070);
|
||||
} else {
|
||||
/* shift by byte count */
|
||||
emit1(0300 | (opc & 1));
|
||||
ea_1(opc & 070);
|
||||
oreg = reg_2;
|
||||
reg_2 = reg_1;
|
||||
regsize(opc);
|
||||
if (oreg == (IS_R8 | 1 | (address_long ? 0 : 0300))) {
|
||||
/* cl register */
|
||||
emit1(0322 | (opc&1)); ea_1(opc&070);
|
||||
} else if (is_expr(oreg)) {
|
||||
if (small(exp_2.typ == S_ABS && exp_2.val == 1, 1)) {
|
||||
/* shift by 1 */
|
||||
emit1(0320 | (opc&1)); ea_1(opc&070);
|
||||
} else {
|
||||
/* shift by byte count */
|
||||
emit1(0300 | (opc & 1));
|
||||
ea_1(opc & 070);
|
||||
#ifdef RELOCATION
|
||||
RELOMOVE(relonami, rel_2);
|
||||
newrelo(exp_2.typ, RELO1);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
newrelo(exp_2.typ, RELO1);
|
||||
#endif
|
||||
emit1((int)(exp_2.val));
|
||||
}
|
||||
}
|
||||
else
|
||||
badsyntax();
|
||||
emit1((int)(exp_2.val));
|
||||
}
|
||||
}
|
||||
else
|
||||
badsyntax();
|
||||
}
|
||||
|
||||
void incop(register int opc)
|
||||
{
|
||||
|
||||
regsize(opc);
|
||||
if ((opc&1) && is_reg(reg_1)) {
|
||||
/* word register */
|
||||
emit1(0100 | (opc&010) | (reg_1&7));
|
||||
} else {
|
||||
emit1(0376 | (opc&1));
|
||||
ea_1(opc & 010);
|
||||
}
|
||||
regsize(opc);
|
||||
if ((opc&1) && is_reg(reg_1)) {
|
||||
/* word register */
|
||||
emit1(0100 | (opc&010) | (reg_1&7));
|
||||
} else {
|
||||
emit1(0376 | (opc&1));
|
||||
ea_1(opc & 010);
|
||||
}
|
||||
}
|
||||
|
||||
void callop(register int opc)
|
||||
{
|
||||
|
||||
regsize(1);
|
||||
if (is_expr(reg_1)) {
|
||||
if (opc == (040+(0351<<8))) {
|
||||
RELOMOVE(relonami, rel_1);
|
||||
ebranch(0353,exp_1);
|
||||
} else {
|
||||
exp_1.val -= (DOTVAL+3 + (address_long ? 2 : 0));
|
||||
emit1(opc>>8);
|
||||
RELOMOVE(relonami, rel_1);
|
||||
adsize_exp(exp_1, RELPC);
|
||||
}
|
||||
} else {
|
||||
emit1(0377); ea_1(opc&070);
|
||||
}
|
||||
regsize(1);
|
||||
if (is_expr(reg_1)) {
|
||||
if (opc == (040+(0351<<8))) {
|
||||
RELOMOVE(relonami, rel_1);
|
||||
ebranch(0353,exp_1);
|
||||
} else {
|
||||
exp_1.val -= (DOTVAL+3 + (address_long ? 2 : 0));
|
||||
emit1(opc>>8);
|
||||
RELOMOVE(relonami, rel_1);
|
||||
adsize_exp(exp_1, RELPC);
|
||||
}
|
||||
} else {
|
||||
emit1(0377); ea_1(opc&070);
|
||||
}
|
||||
}
|
||||
|
||||
void xchg(register int opc)
|
||||
{
|
||||
|
||||
regsize(opc);
|
||||
if (! is_reg(reg_1) || is_acc(reg_2)) {
|
||||
reverse();
|
||||
}
|
||||
if (opc == 1 && is_acc(reg_1) && is_reg(reg_2)) {
|
||||
emit1(0220 | (reg_2&7));
|
||||
} else if (is_reg(reg_1)) {
|
||||
emit1(0206 | opc); ea_2((reg_1&7)<<3);
|
||||
} else
|
||||
badsyntax();
|
||||
regsize(opc);
|
||||
if (! is_reg(reg_1) || is_acc(reg_2)) {
|
||||
reverse();
|
||||
}
|
||||
if (opc == 1 && is_acc(reg_1) && is_reg(reg_2)) {
|
||||
emit1(0220 | (reg_2&7));
|
||||
} else if (is_reg(reg_1)) {
|
||||
emit1(0206 | opc); ea_2((reg_1&7)<<3);
|
||||
} else
|
||||
badsyntax();
|
||||
}
|
||||
|
||||
void test(register int opc)
|
||||
{
|
||||
|
||||
regsize(opc);
|
||||
if (is_reg(reg_2) || is_expr(reg_1))
|
||||
reverse();
|
||||
if (is_expr(reg_2)) {
|
||||
if (is_acc(reg_1)) {
|
||||
emit1(0250 | opc);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
opsize_exp(exp_2, (opc&1));
|
||||
}
|
||||
else {
|
||||
emit1(0366 | opc);
|
||||
ea_1(0<<3);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
opsize_exp(exp_2, (opc&1));
|
||||
}
|
||||
} else if (is_reg(reg_1)) {
|
||||
emit1(0204 | opc); ea_2((reg_1&7)<<3);
|
||||
} else
|
||||
badsyntax();
|
||||
regsize(opc);
|
||||
if (is_reg(reg_2) || is_expr(reg_1))
|
||||
reverse();
|
||||
if (is_expr(reg_2)) {
|
||||
if (is_acc(reg_1)) {
|
||||
emit1(0250 | opc);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
opsize_exp(exp_2, (opc&1));
|
||||
}
|
||||
else {
|
||||
emit1(0366 | opc);
|
||||
ea_1(0<<3);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
opsize_exp(exp_2, (opc&1));
|
||||
}
|
||||
} else if (is_reg(reg_1)) {
|
||||
emit1(0204 | opc); ea_2((reg_1&7)<<3);
|
||||
} else
|
||||
badsyntax();
|
||||
}
|
||||
|
||||
void mov(register int opc)
|
||||
{
|
||||
|
||||
regsize(opc);
|
||||
if (is_segreg(reg_1)) {
|
||||
/* to segment register */
|
||||
emit1(0216); ea_2((reg_1&07)<<3);
|
||||
} else if (is_segreg(reg_2)) {
|
||||
/* from segment register */
|
||||
emit1(0214); ea_1((reg_2&07)<<3);
|
||||
} else if (is_expr(reg_2)) {
|
||||
/* from immediate */
|
||||
if (is_reg(reg_1)) {
|
||||
/* to register */
|
||||
emit1(0260 | opc<<3 | (reg_1&7));
|
||||
} else {
|
||||
/* to memory */
|
||||
emit1(0306 | opc); ea_1(0<<3);
|
||||
}
|
||||
RELOMOVE(relonami, rel_2);
|
||||
opsize_exp(exp_2, (opc&1));
|
||||
} else if (rm_1 == 05 && is_acc(reg_2)) {
|
||||
/* from accumulator to memory (displacement) */
|
||||
emit1(0242 | opc);
|
||||
RELOMOVE(relonami, rel_1);
|
||||
adsize_exp(exp_1, 0);
|
||||
} else if (rm_2 == 05 && is_acc(reg_1)) {
|
||||
/* from memory (displacement) to accumulator */
|
||||
emit1(0240 | opc);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
adsize_exp(exp_2, 0);
|
||||
} else if (is_reg(reg_2)) {
|
||||
/* from register to memory or register */
|
||||
emit1(0210 | opc); ea_1((reg_2&07)<<3);
|
||||
} else if (is_reg(reg_1)) {
|
||||
/* from memory or register to register */
|
||||
emit1(0212 | opc); ea_2((reg_1&07)<<3);
|
||||
} else
|
||||
badsyntax();
|
||||
regsize(opc);
|
||||
if (is_segreg(reg_1)) {
|
||||
/* to segment register */
|
||||
emit1(0216); ea_2((reg_1&07)<<3);
|
||||
} else if (is_segreg(reg_2)) {
|
||||
/* from segment register */
|
||||
emit1(0214); ea_1((reg_2&07)<<3);
|
||||
} else if (is_expr(reg_2)) {
|
||||
/* from immediate */
|
||||
if (is_reg(reg_1)) {
|
||||
/* to register */
|
||||
emit1(0260 | opc<<3 | (reg_1&7));
|
||||
} else {
|
||||
/* to memory */
|
||||
emit1(0306 | opc); ea_1(0<<3);
|
||||
}
|
||||
RELOMOVE(relonami, rel_2);
|
||||
opsize_exp(exp_2, (opc&1));
|
||||
} else if (rm_1 == 05 && is_acc(reg_2)) {
|
||||
/* from accumulator to memory (displacement) */
|
||||
emit1(0242 | opc);
|
||||
RELOMOVE(relonami, rel_1);
|
||||
adsize_exp(exp_1, 0);
|
||||
} else if (rm_2 == 05 && is_acc(reg_1)) {
|
||||
/* from memory (displacement) to accumulator */
|
||||
emit1(0240 | opc);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
adsize_exp(exp_2, 0);
|
||||
} else if (is_reg(reg_2)) {
|
||||
/* from register to memory or register */
|
||||
emit1(0210 | opc); ea_1((reg_2&07)<<3);
|
||||
} else if (is_reg(reg_1)) {
|
||||
/* from memory or register to register */
|
||||
emit1(0212 | opc); ea_2((reg_1&07)<<3);
|
||||
} else
|
||||
badsyntax();
|
||||
}
|
||||
|
||||
void extshft(int opc, int reg)
|
||||
{
|
||||
int oreg2 = reg_2;
|
||||
int oreg2 = reg_2;
|
||||
|
||||
reg_2 = reg_1;
|
||||
regsize(1);
|
||||
reg_2 = reg_1;
|
||||
regsize(1);
|
||||
|
||||
emit1(0xF);
|
||||
if (oreg2 == (IS_R8 | 1 | (address_long ? 0 : 0300))) {
|
||||
/* cl register */
|
||||
emit1(opc|1);
|
||||
ea_1(reg << 3);
|
||||
}
|
||||
else if (is_expr(oreg2)) {
|
||||
emit1(opc);
|
||||
ea_1(reg << 3);
|
||||
emit1(0xF);
|
||||
if (oreg2 == (IS_R8 | 1 | (address_long ? 0 : 0300))) {
|
||||
/* cl register */
|
||||
emit1(opc|1);
|
||||
ea_1(reg << 3);
|
||||
}
|
||||
else if (is_expr(oreg2)) {
|
||||
emit1(opc);
|
||||
ea_1(reg << 3);
|
||||
#ifdef RELOCATION
|
||||
RELOMOVE(relonami, rel_2);
|
||||
newrelo(exp_2.typ, RELO1);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
newrelo(exp_2.typ, RELO1);
|
||||
#endif
|
||||
emit1((int)(exp_2.val));
|
||||
}
|
||||
else badsyntax();
|
||||
emit1((int)(exp_2.val));
|
||||
}
|
||||
else badsyntax();
|
||||
}
|
||||
|
||||
void bittestop(int opc)
|
||||
{
|
||||
regsize(1);
|
||||
emit1(0xF);
|
||||
if (is_expr(reg_2)) {
|
||||
emit1(0272);
|
||||
ea_1(opc << 3);
|
||||
regsize(1);
|
||||
emit1(0xF);
|
||||
if (is_expr(reg_2)) {
|
||||
emit1(0272);
|
||||
ea_1(opc << 3);
|
||||
#ifdef RELOCATION
|
||||
RELOMOVE(relonami, rel_2);
|
||||
newrelo(exp_2.typ, RELO1);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
newrelo(exp_2.typ, RELO1);
|
||||
#endif
|
||||
emit1((int)(exp_2.val));
|
||||
}
|
||||
else if (is_reg(reg_2)) {
|
||||
emit1(0203 | (opc<<3));
|
||||
ea_1((reg_2&7)<<3);
|
||||
}
|
||||
else badsyntax();
|
||||
emit1((int)(exp_2.val));
|
||||
}
|
||||
else if (is_reg(reg_2)) {
|
||||
emit1(0203 | (opc<<3));
|
||||
ea_1((reg_2&7)<<3);
|
||||
}
|
||||
else badsyntax();
|
||||
}
|
||||
|
||||
void imul(int reg)
|
||||
{
|
||||
/* This instruction is more elaborate on the 80386. Its most
|
||||
general form is:
|
||||
imul reg, reg_or_mem, immediate.
|
||||
This is the form processed here.
|
||||
*/
|
||||
regsize(1);
|
||||
if (is_expr(reg_1)) {
|
||||
/* To also handle
|
||||
imul reg, immediate, reg_or_mem
|
||||
*/
|
||||
reverse();
|
||||
}
|
||||
if (is_expr(reg_2)) {
|
||||
/* The immediate form; two cases: */
|
||||
if (small(exp_2.typ == S_ABS && fitb(exp_2.val),
|
||||
operand_long ? 3 : 1)) {
|
||||
/* case 1: 1 byte encoding of immediate */
|
||||
emit1(0153);
|
||||
ea_1((reg & 07) << 3);
|
||||
emit1((int)(exp_2.val));
|
||||
}
|
||||
else {
|
||||
/* case 2: WORD or DWORD encoding of immediate */
|
||||
emit1(0151);
|
||||
ea_1((reg & 07) << 3);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
opsize_exp(exp_2, 1);
|
||||
}
|
||||
}
|
||||
else if (is_reg(reg_1) && ((reg_1&7) == (reg & 07))) {
|
||||
/* the "reg" field and the "reg_or_mem" field are the same,
|
||||
and the 3rd operand is not an immediate ...
|
||||
*/
|
||||
if (reg == 0) {
|
||||
/* how lucky we are, the target is the ax register */
|
||||
/* However, we cannot make an optimization for f.i.
|
||||
imul eax, blablabla
|
||||
because the latter does not affect edx, whereas
|
||||
imul blablabla
|
||||
does! Therefore, "reg" is or-ed with 0x10 in the
|
||||
former case, so that the test above fails.
|
||||
*/
|
||||
emit1(0367);
|
||||
ea_2(050);
|
||||
}
|
||||
else {
|
||||
/* another register ... */
|
||||
emit1(0xF);
|
||||
emit1(0257);
|
||||
ea_2((reg & 07) << 3);
|
||||
}
|
||||
}
|
||||
else badsyntax();
|
||||
/* This instruction is more elaborate on the 80386. Its most
|
||||
general form is:
|
||||
imul reg, reg_or_mem, immediate.
|
||||
This is the form processed here.
|
||||
*/
|
||||
regsize(1);
|
||||
if (is_expr(reg_1)) {
|
||||
/* To also handle
|
||||
imul reg, immediate, reg_or_mem
|
||||
*/
|
||||
reverse();
|
||||
}
|
||||
if (is_expr(reg_2)) {
|
||||
/* The immediate form; two cases: */
|
||||
if (small(exp_2.typ == S_ABS && fitb(exp_2.val),
|
||||
operand_long ? 3 : 1)) {
|
||||
/* case 1: 1 byte encoding of immediate */
|
||||
emit1(0153);
|
||||
ea_1((reg & 07) << 3);
|
||||
emit1((int)(exp_2.val));
|
||||
}
|
||||
else {
|
||||
/* case 2: WORD or DWORD encoding of immediate */
|
||||
emit1(0151);
|
||||
ea_1((reg & 07) << 3);
|
||||
RELOMOVE(relonami, rel_2);
|
||||
opsize_exp(exp_2, 1);
|
||||
}
|
||||
}
|
||||
else if (is_reg(reg_1) && ((reg_1&7) == (reg & 07))) {
|
||||
/* the "reg" field and the "reg_or_mem" field are the same,
|
||||
and the 3rd operand is not an immediate ...
|
||||
*/
|
||||
if (reg == 0) {
|
||||
/* how lucky we are, the target is the ax register */
|
||||
/* However, we cannot make an optimization for f.i.
|
||||
imul eax, blablabla
|
||||
because the latter does not affect edx, whereas
|
||||
imul blablabla
|
||||
does! Therefore, "reg" is or-ed with 0x10 in the
|
||||
former case, so that the test above fails.
|
||||
*/
|
||||
emit1(0367);
|
||||
ea_2(050);
|
||||
}
|
||||
else {
|
||||
/* another register ... */
|
||||
emit1(0xF);
|
||||
emit1(0257);
|
||||
ea_2((reg & 07) << 3);
|
||||
}
|
||||
}
|
||||
else badsyntax();
|
||||
}
|
||||
|
||||
// vim: ts=8 sw=8 et
|
||||
|
||||
|
|
|
@ -86,6 +86,9 @@ char* remember(char* s)
|
|||
|
||||
int combine(int typ1, int typ2, int op)
|
||||
{
|
||||
typ1 &= ~S_VAR;
|
||||
typ2 &= ~S_VAR;
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case '+':
|
||||
|
|
|
@ -78,7 +78,7 @@ for _, plat in ipairs({"cpm"}) do
|
|||
},
|
||||
outleaves = { n..".s" },
|
||||
commands = {
|
||||
"$LUA %{ins[1]} <%{ins[2]} >%{outs}"
|
||||
"$(LUA) %{ins[1]} <%{ins[2]} >%{outs}"
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#ifndef PMAP_H
|
||||
#define PMAP_H
|
||||
|
||||
/* A bidirectional multimap, storing (left, right) tuples.
|
||||
*/
|
||||
|
||||
struct pmap_node
|
||||
{
|
||||
void* left;
|
||||
|
@ -23,10 +26,33 @@ struct pmap
|
|||
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);
|
||||
|
||||
/** 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);
|
||||
|
||||
/** Removes a relation from the map.
|
||||
*
|
||||
* Use this in multimap mode.
|
||||
*/
|
||||
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);
|
||||
|
||||
/** Given a `right`, find the first matching `left`.
|
||||
*/
|
||||
extern void* pmap_findright(void* map, void* right);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#ifndef SMAP_H
|
||||
#define SMAP_H
|
||||
|
||||
/* A string multimap (each key can have multiple values). */
|
||||
|
||||
struct smap_node
|
||||
{
|
||||
const char* left;
|
||||
|
@ -28,24 +30,33 @@ struct smap
|
|||
int max; \
|
||||
}
|
||||
|
||||
/** Initializes a string map and returns the initialized
|
||||
* handle in `mapp`.
|
||||
/** Initializes a string map. Optional; a zero-initialised map
|
||||
* structure is a valid empty map.
|
||||
*/
|
||||
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
|
||||
* value `value` associated with the existing `key`.
|
||||
|
||||
/** Adds a new item with name `key` in the string map if it does not already
|
||||
* 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);
|
||||
/** 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);
|
||||
/** 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);
|
||||
|
||||
/** Frees the data structure associated with the string map.
|
||||
* Also frees the memory associated with the key if
|
||||
* `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;
|
||||
if (freedata)
|
||||
{
|
||||
free(f->data);
|
||||
free((void*) f->data);
|
||||
f->data = NULL;
|
||||
}
|
||||
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;
|
||||
int i = 0;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
struct stringfragment
|
||||
{
|
||||
char* data;
|
||||
const char* data;
|
||||
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_init(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
|
||||
|
|
|
@ -8,7 +8,7 @@ normalrule {
|
|||
},
|
||||
outleaves = { "em_codeEK.h" },
|
||||
commands = {
|
||||
"$LUA %{ins[1]} < %{ins[3]} > %{outs}",
|
||||
"$(LUA) %{ins[1]} < %{ins[3]} > %{outs}",
|
||||
"cat %{ins[4]} >> %{outs}"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ for _, f in ipairs(GENFILES) do
|
|||
"h+emheaders"
|
||||
},
|
||||
commands = {
|
||||
"$LUA %{ins[1]} < %{ins[3]} > %{outs}"
|
||||
"$(LUA) %{ins[1]} < %{ins[3]} > %{outs}"
|
||||
}
|
||||
}
|
||||
end
|
||||
|
|
|
@ -7,7 +7,7 @@ normalrule {
|
|||
},
|
||||
outleaves = "C_mnem_narg.h",
|
||||
commands = {
|
||||
"$LUA %{ins[1]} < %{ins[3]} > %{outs}"
|
||||
"$(LUA) %{ins[1]} < %{ins[3]} > %{outs}"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ normalrule {
|
|||
},
|
||||
outleaves = "C_mnem.h",
|
||||
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, "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");
|
||||
|
||||
/* This might fail and cause a reentrant trap if cia is invalid, so
|
||||
|
|
|
@ -207,5 +207,5 @@
|
|||
|
||||
# Floating point conversions
|
||||
|
||||
<63--><FRT>.....<FRB><14------>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)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)(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 <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
@ -16,9 +17,7 @@ ssize_t read(int fd, void* buffer, size_t count)
|
|||
ssize_t r, tot;
|
||||
size_t left;
|
||||
int eof = 0;
|
||||
|
||||
if (!count || _sys_getmode(fd) == O_BINARY)
|
||||
return _sys_rawread(fd, buffer, count);
|
||||
bool text = _sys_getmode(fd) == O_TEXT;
|
||||
|
||||
if (_sys_iseof(fd))
|
||||
return 0;
|
||||
|
@ -47,33 +46,36 @@ ssize_t read(int fd, void* buffer, size_t count)
|
|||
if (r <= 0)
|
||||
return tot ? tot : r;
|
||||
|
||||
q = memchr(p, 0x1a, (size_t)r);
|
||||
if (q)
|
||||
if (text)
|
||||
{
|
||||
_sys_rawlseek(fd, (off_t)(q - p) - r, SEEK_CUR);
|
||||
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')
|
||||
q = memchr(p, 0x1a, (size_t)r);
|
||||
if (q)
|
||||
{
|
||||
*p++ = c;
|
||||
++tot;
|
||||
_sys_rawlseek(fd, (off_t)(q - p) - r, SEEK_CUR);
|
||||
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));
|
||||
|
|
@ -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
|
||||
* `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]))
|
||||
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
|
||||
program {EM}/bin/{LOD}
|
||||
args < >
|
||||
outfile msdos86.exe
|
||||
outfile msdos86.com
|
||||
end
|
||||
|
|
|
@ -3,41 +3,28 @@ acklibrary {
|
|||
srcs = {
|
||||
"./brk.c",
|
||||
"./close.s",
|
||||
"./creat.c",
|
||||
"./errno.s",
|
||||
"./getpid.s",
|
||||
"./gettimeofday.c",
|
||||
"./_hol0.s",
|
||||
"./isatty.s",
|
||||
"./kill.c",
|
||||
"./lseek.c",
|
||||
"./open.c",
|
||||
"./read.c",
|
||||
"./setmode.c",
|
||||
"./signal.c",
|
||||
"./rename.s",
|
||||
"./sys_exists.s",
|
||||
"./sys_fdmodes.c",
|
||||
"./sys_getdate.s",
|
||||
"./sys_getmode.c",
|
||||
"./sys_gettime.s",
|
||||
"./sys_initmain.c",
|
||||
"./sys_iseof.c",
|
||||
"./sys_isopen.s",
|
||||
"./sys_isreadyr.s",
|
||||
"./sys_rawcreat.s",
|
||||
"./sys_rawlseek.s",
|
||||
"./sys_rawopen.s",
|
||||
"./sys_rawrw.s",
|
||||
"./sys_seteof.c",
|
||||
"./sys_seterrno.c",
|
||||
"./sys_setmode.c",
|
||||
"./sys_xret.s",
|
||||
"./unlink.s",
|
||||
"./write.c",
|
||||
"plat/msdos/libsys+srcs",
|
||||
},
|
||||
deps = {
|
||||
"lang/cem/libcc.ansi/headers+headers",
|
||||
"plat/msdos86/include+headers",
|
||||
"plat/msdos/libsys+headers",
|
||||
},
|
||||
vars = {
|
||||
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
|
||||
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.
|
||||
|
||||
|
||||
.seek 0x1FE
|
||||
.data2 0xAA55
|
||||
|
||||
|
|
|
@ -12,29 +12,9 @@ errcho() {
|
|||
|
||||
get_test_output() {
|
||||
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-*)
|
||||
if ! command -v $method >/dev/null 2>&1 ; then
|
||||
errcho "Warning: $method not installed, skipping test"
|
||||
echo "@@SKIPPED"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
$method $img 2>&1
|
||||
errcho "qemu tests no longer supported (method $method)"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
*)
|
||||
|
|
|
@ -42,11 +42,11 @@ $(OBJDIR)/%.o: %.c
|
|||
|
||||
$(OBJDIR)/%.pdf: doc/%.n doc/LLgen.refs
|
||||
@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
|
||||
@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)
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
\}\
|
||||
\}
|
||||
.R1
|
||||
database doc/LLgen.refs
|
||||
accumulate
|
||||
.R2
|
||||
.ND
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
.RP
|
||||
.TL
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
aslod \- ACK simple loader
|
||||
.SH SYNOPSIS
|
||||
.B aslod
|
||||
[\-h] [\-v] inputfile outputfile
|
||||
[\-h] [\-v] [\-p prefixfile] inputfile outputfile
|
||||
.SH DESCRIPTION
|
||||
.I aslod
|
||||
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
|
||||
that the first byte of TEXT is at offset 0 in the file
|
||||
(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"
|
||||
ack.out(5)
|
||||
|
|
|
@ -37,6 +37,7 @@ struct outsect outsect[S_MAX];
|
|||
char* stringarea;
|
||||
|
||||
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] */
|
||||
|
||||
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 */
|
||||
#define Xchar(ch) ((ch) & 0377)
|
||||
|
@ -204,6 +218,12 @@ int main(int argc, char* argv[])
|
|||
verbose = true;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
argv++;
|
||||
argc--;
|
||||
prefixfile = argv[1];
|
||||
break;
|
||||
|
||||
default:
|
||||
syntaxerror:
|
||||
fatal("syntax error --- try -h for help");
|
||||
|
@ -288,6 +308,8 @@ int main(int argc, char* argv[])
|
|||
|
||||
/* And go! */
|
||||
|
||||
if (prefixfile)
|
||||
emitprefixfile();
|
||||
emits(&outsect[TEXT], &outsect[ROM]);
|
||||
emits(&outsect[ROM], &outsect[DATA]);
|
||||
emits(&outsect[DATA], NULL);
|
||||
|
|
|
@ -18,7 +18,7 @@ normalrule {
|
|||
},
|
||||
outleaves = { "enterkeyw.c" },
|
||||
commands = {
|
||||
"$LUA %{ins[1]} < %{ins[2]} > %{outs[1]}"
|
||||
"$(LUA) %{ins[1]} < %{ins[2]} > %{outs[1]}"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue