Files
5150/polmon.cc
2025-09-24 00:51:56 +02:00

385 lines
8.3 KiB
C++

#include <cstdint>
#ifndef WOZMON
#define WOZMON 0
#endif
#if WOZMON
#define BACKSPACE 0
#define ASCIIDUMP 0
#define CLEARSCREENCMD 0
#define FARCALL 0
#define SHOWTITLE 0
#define BOOTSTRAP 0
#endif // WOZMON
#ifndef BACKSPACE
#define BACKSPACE 1
#endif
#ifndef ASCIIDUMP
#define ASCIIDUMP 1
#endif
#ifndef CLEARSCREENCMD
#define CLEARSCREENCMD 1
#endif
#ifndef FARCALL
#define FARCALL 1
#endif
#ifndef SHOWTITLE
#define SHOWTITLE 1
#endif
#ifndef BOOTSTRAP
#define BOOTSTRAP 1
#endif
namespace {
constexpr int kDumpSize = 16;
uint8_t getc() {
register uint8_t c asm ("al");
asm volatile (
"movb $0x00, %%ah\n\t"
"int $0x16"
: "=r" (c)
:: "ah", "cc"
);
return c;
}
void putc(uint8_t c) {
asm volatile (
"movb %0, %%al \n\t"
"movb $0x0e, %%ah \n\t"
"movb $0, %%bh \n\t"
"int $0x10 \n\t"
:: "r" (c)
: "ax", "bh", "cc", "bp"
);
}
void puts(const char* s) {
while (*s) {
putc(*s++);
}
}
// arguments on the stack in reverse order
extern "C" uint16_t Jump(uint16_t addr, int nargs);
asm (
".section .text \n"
"Jump: \n"
" push %bx \n"
" push %si \n"
" push %di \n"
" push %bp \n"
" push %es \n"
" push %ax \n" // addr
" movw %sp, %bp \n"
" movw %dx, %si \n" // nargs
" add %si, %si \n"
"j0: \n"
" test %si, %si \n"
" jz j1 \n"
" lea 12(%bp,%si), %di\n"
" push %di \n"
" sub $2, %si \n"
" jmp j0 \n"
"j1: \n"
" lcall *(%bp) \n"
" add $4, %sp \n"
" pop %bp \n"
" pop %di \n"
" pop %si \n"
" pop %bx \n"
" ret"
// return value in ax
);
constexpr uint8_t kBackspace = 0x7f;
constexpr uint8_t kOtherBackspace = 0x08;
uint8_t ReadHexNibble(uint8_t c) {
// lowercase only
if (c <= '9') {
return c - '0';
}
return 10 + (c - 'a');
}
uint16_t ReadUintN(int n, const char* buf) {
uint16_t out = 0;
for (int i = 0; i < n; i++) {
if (buf[i] == 0) {
break;
}
out <<= 4;
out += ReadHexNibble(buf[i]);
}
return out;
}
uint8_t ReadUint8(const char* buf) {
return ReadUintN(2, buf);
}
uint16_t ReadUint16(const char* buf) {
return ReadUintN(4, buf);
}
void WriteHexNibble(uint8_t c) {
if (c > 9) {
putc('a' + c - 10);
} else {
putc('0' + c);
}
}
void WriteUint8(uint8_t a) {
WriteHexNibble(a >> 4);
WriteHexNibble(a & 0xf);
}
void WriteUint16(uint16_t a) {
WriteUint8(a >> 8);
WriteUint8(a & 0xff);
}
void __set_es__(uint16_t es) {
asm volatile (
"mov %0, %%es"
:: "r" (es)
: "es"
);
}
uint8_t __get_es_u8__(uint16_t addr) {
register uint16_t ad asm ("di") = addr;
uint8_t ret;
asm volatile (
"movb %%es:(%1), %0"
: "=r" (ret)
: "r" (ad)
);
return ret;
}
void __set_es_u8__(uint16_t addr, uint8_t val) {
register uint16_t ad asm ("di") = addr;
asm volatile (
"movb %0, %%es:(%1)"
:: "ri" (val), "rmi" (ad)
: "memory"
);
}
__attribute__((noreturn))
inline static void __basic__() {
asm volatile (
"movw $0x40, %ax \n\t"
"mov %ax, %ds \n\t"
"int $0x18"
);
__builtin_unreachable();
}
void Dump(uint16_t addr, int count) {
for (int i = 0; i < count; i++) {
putc(' ');
uint8_t d = __get_es_u8__(addr + i);
WriteUint8(d);
}
#if ASCIIDUMP
putc(' ');
putc(' ');
for (int i = 0; i < count; i++) {
uint8_t d = __get_es_u8__(addr + i);
if (d > 31 && d < 127) {
putc(d);
} else {
putc('.');
}
}
#endif
}
void DumpHex(uint16_t addr, uint16_t seg) {
addr &= -kDumpSize;
putc('[');
WriteUint16(seg);
putc(':');
__set_es__(seg);
WriteUint16(addr);
putc(']');
putc(':');
Dump(addr, kDumpSize);
putc('\r');
putc('\n');
}
void ClearScreen() {
asm volatile (
"movw $0x0002, %%ax \n\t"
"int $0x10"
::: "ax", "cc"
);
}
void Status(uint8_t status) {
asm volatile (
"xorb %%bh, %%bh \n\t"
"movb $0x03, %%ah \n\t"
"int $0x10 \n\t"
"mov %%dx, %%di \n\t"
"movb $0x02, %%ah \n\t"
"movw $77, %%dx \n\t"
"int $0x10 \n\t"
"movb %0, %%al \n\t"
"call _ZN12_GLOBAL__N_110WriteUint8Eh \n\t"
"movb $0x02, %%ah \n\t"
"movw %%di, %%dx \n\t"
"int $0x10"
:: "rm" (status)
: "ax", "bh", "dx", "cx", "di", "cc"
);
}
bool ParseCommand(const char* buf, uint16_t& cur_addr, uint16_t& cur_seg) {
bool dump = true;
for (const char* ptr = buf; *ptr;) {
if (*ptr == 's') {
cur_addr = 0;
cur_seg = ReadUint16(ptr+1);
ptr += 5;
} else if (*ptr == '$') {
__basic__();
} else if (*ptr == 'r') {
dump = false;
#if FARCALL
int nargs = 0;
ptr++;
for (; *ptr;) {
if (*ptr == ' ') {
ptr++;
continue;
}
uint16_t d = ReadUint16(ptr);
asm volatile ("push %0" :: "r" (d));
nargs++;
ptr += 4;
}
__set_es__(cur_seg);
uint16_t ret = Jump(cur_addr, nargs);
asm volatile (
"shl %0 \n\t"
"add %0, %%sp"
:: "r"(nargs)
);
WriteUint16(ret);
putc('\r'); putc('\n');
#else // FARCALL
auto jump = reinterpret_cast<void(*)()>(cur_addr);
jump();
#endif // FARCALL
ptr++;
#if CLEARSCREENCMD
} else if (*ptr == 'l') {
dump = false;
ClearScreen();
ptr++;
#endif
} else if (*ptr == 'w') {
dump = false;
uint16_t addr = cur_addr;
ptr += 1;
for (; *ptr;) {
if (*ptr == ' ') {
ptr++;
continue;
}
uint8_t d = ReadUint8(ptr);
__set_es__(cur_seg);
__set_es_u8__(addr, d);
addr++;
ptr += 2;
}
} else {
cur_addr = ReadUint16(ptr);
ptr += 4;
}
}
return dump;
}
const char* prompt = "> ";
void polmon() {
uint16_t cur_addr = 0;
uint16_t cur_seg = 0;
char inbuf[64];
bool first = true;
char* inptr = inbuf;
ClearScreen();
#if SHOWTITLE
puts("PolMon 0.2\r\n");
#endif // SHOWTITLE
puts(prompt);
while (1) {
uint8_t c = getc();
putc(c); // echo
if (c == '\r') {
*inptr = 0;
if (inbuf[0] == 0) {
if (!first) {
cur_addr += kDumpSize;
}
} else {
putc('\n');
}
if (ParseCommand(inbuf, cur_addr, cur_seg)) {
DumpHex(cur_addr, cur_seg);
};
first = false;
inptr = inbuf;
puts(prompt);
#if BACKSPACE
} else if (c == kBackspace || c == kOtherBackspace) {
inptr--;
if (inptr < inbuf) {
inptr = inbuf;
putc(' ');
continue;
}
putc(' ');
putc(kOtherBackspace);
#endif
} else {
*inptr = c;
inptr++;
}
}
}
} // namespace
int main() {
polmon();
}
#if BOOTSTRAP
__attribute__((section(".init"), noreturn, used))
void _start() {
main();
__builtin_unreachable();
}
#endif // BOOTSTRAP