Compare commits

...

13 Commits

Author SHA1 Message Date
2bab877a7d Not sure why this was necessary... 2025-09-24 00:53:43 +02:00
f46b13e044 Add floppy image 2025-09-24 00:53:09 +02:00
bf16ae5646 Add polmon executable 2025-09-24 00:51:56 +02:00
3c90dd8b3d Add a fat12-enabled boot sector 2025-09-24 00:49:54 +02:00
bdb2fce4db Add fat12 lib 2025-09-24 00:46:50 +02:00
9bd84390d0 crc16: read data from the right segment 2025-09-24 00:45:56 +02:00
e4473e14f6 make crc16.s 2025-09-24 00:45:32 +02:00
7bf7e863eb kbd: now with ctrl-alt-del 2025-09-24 00:41:30 +02:00
ee97876115 Add a few toys 2025-09-24 00:40:56 +02:00
9daf8d7f97 Small cleanup in *floppy.asm 2025-09-24 00:39:18 +02:00
b5b679c4e2 Fix crc16 2025-09-24 00:38:34 +02:00
c818d185ba makefile: autobuild all nasm stuff 2025-09-24 00:37:05 +02:00
c45a312dd0 wozmon: make some room 2025-09-16 20:07:59 +02:00
24 changed files with 1058 additions and 441 deletions

View File

@@ -3,7 +3,7 @@ FROM ubuntu:jammy AS deps
RUN apt-get update && apt-get install -y software-properties-common RUN apt-get update && apt-get install -y software-properties-common
RUN add-apt-repository ppa:tkchia/build-ia16 RUN add-apt-repository ppa:tkchia/build-ia16
RUN apt-get update && apt-get install -y gcc-ia16-elf RUN apt-get update && apt-get install -y gcc-ia16-elf
RUN apt-get install nasm make RUN apt-get install -y nasm make mtools
FROM deps AS dev FROM deps AS dev

View File

@@ -1,10 +1,7 @@
dev-image = 5150-dev dev-image = 5150-dev
writefloppy.bin: writefloppy.asm %.bin: %.asm
nasm writefloppy.asm -o writefloppy.bin nasm $? -o $@
readfloppy.bin: readfloppy.asm
nasm readfloppy.asm -o readfloppy.bin
crc16.s: crc16.c crc16.s: crc16.c
ia16-elf-gcc -S -Os -o crc16.s crc16.c ia16-elf-gcc -S -Os -o crc16.s crc16.c
@@ -12,17 +9,54 @@ crc16.s: crc16.c
crc16.bin: crc16.s crt0.c crc16.bin: crc16.s crt0.c
ia16-elf-gcc -o crc16.bin -Os -nostdlib crc16.s crt0.c ia16-elf-gcc -o crc16.bin -Os -nostdlib crc16.s crt0.c
wozmon.s: wozmon.cc CC = ia16-elf-gcc
ia16-elf-gcc -S -Os -o wozmon.s wozmon.cc CXX = ia16-elf-gcc
LD = ia16-elf-gcc
CXXFLAGS = -mregparmcall -ffunction-sections -Os -flto
CFLAGS = -mregparmcall -ffunction-sections -Os -flto
LDFLAGS = -mregparmcall -Wl,--gc-sections -Os -nostdlib -flto
wozmon.bin: wozmon.s crt0.c %.elf:
ia16-elf-gcc -o wozmon.bin -Os -nostdlib wozmon.s crt0.c $(LD) $(LDFLAGS) $(CPPFLAGS) -o $@ $^
truncate -s 510 wozmon.bin
printf "\125\252" >> wozmon.bin bootsectors = fat12boot.bin wozmon.bin
$(bootsectors):
ia16-elf-objcopy -O binary $? $@
truncate -s 510 $@
printf "\125\252" >> $@
fat12boot.elf: fat12boot.o fat12.o bootsect.S
fat12boot.elf: LDFLAGS += -T bootsect.ld
fat12boot.bin: fat12boot.elf
polmon.elf: LDFLAGS += -T flat0600.ld
polmon.elf: polmon.o
polmon.com: polmon.elf
ia16-elf-objcopy -O binary $? $@
wozmon.o: polmon.cc
wozmon.o: CPPFLAGS = -DWOZMON=1
wozmon.o:
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
wozmon.elf: wozmon.o bootsect.S
wozmon.elf: LDFLAGS += -T bootsect.ld
wozmon.elf: CPPFLAGS += -DNOBPB
wozmon.bin: wozmon.elf
polos.img: fat12boot.bin polmon.com
dd if=/dev/zero of=$@ bs=512 count=720
mformat -i $@ -t 40 -h 2 -s 9
mcopy -i $@ polmon.com ::/polmon.com
dd if=fat12boot.bin of=$@ conv=notrunc
.PHONY: clean .PHONY: clean
clean: ## Remove generated files clean: ## Remove generated files
rm -rf wozmon.bin crc16.bin readfloppy.bin writefloppy.bin rm -rf wozmon.bin crc16.bin readfloppy.bin writefloppy.bin fat12boot.bin
.PHONY: dev-image .PHONY: dev-image
dev-image: dev-image:
@@ -39,6 +73,18 @@ binaries: ## Build all binaries
docker build --build-arg TARGET=writefloppy.bin -o . --target=export . docker build --build-arg TARGET=writefloppy.bin -o . --target=export .
docker build --build-arg TARGET=crc16.bin -o . --target=export . docker build --build-arg TARGET=crc16.bin -o . --target=export .
docker build --build-arg TARGET=wozmon.bin -o . --target=export . docker build --build-arg TARGET=wozmon.bin -o . --target=export .
docker build --build-arg TARGET=hello.bin -o . --target=export .
docker build --build-arg TARGET=copy.bin -o . --target=export .
docker build --build-arg TARGET=call.bin -o . --target=export .
docker build --build-arg TARGET=debug.bin -o . --target=export .
docker build --build-arg TARGET=dosdbt.bin -o . --target=export .
docker build --build-arg TARGET=format.bin -o . --target=export .
docker build --build-arg TARGET=polmon.com -o . --target=export .
docker build --build-arg TARGET=fat12boot.bin -o . --target=export .
.PHONY: floppy
floppy: ## Make a bootable floppy image
docker build --build-arg TARGET=polos.img -o . --target=export .
.PHONY: help .PHONY: help

11
add.asm Normal file
View File

@@ -0,0 +1,11 @@
BITS 16
CPU 8086
_start:
mov bp, sp
mov si, [bp+6]
mov ax, [si]
mov si, [bp+4]
mov dx, [si]
sub ax, dx
retf 4

View File

@@ -119,6 +119,22 @@ void sendShiftCode(int code) {
sendCode(42 | 0x80); sendCode(42 | 0x80);
} }
void sendCtrlAltDel() {
sendCode(0x1d); // ctrl
sendCode(0x38); // alt
sendCode(0x53); // del
sendCode(0x53 | 0x80);
sendCode(0x38 | 0x80);
sendCode(0x1d | 0x80);
}
void sendCtrlBreak() {
sendCode(0x1d); // ctrl
sendCode(0x46); // break
sendCode(0x46 | 0x80);
sendCode(0x1d | 0x80);
}
void sendAsciiChar(int c) { void sendAsciiChar(int c) {
if (c >= 'a' && c <= 'z') { if (c >= 'a' && c <= 'z') {
return sendNormalCode(kLetterCodes[c - 'a']); return sendNormalCode(kLetterCodes[c - 'a']);
@@ -160,6 +176,9 @@ void sendAsciiChar(int c) {
case '<': return sendShiftCode(51); case '<': return sendShiftCode(51);
case '>': return sendShiftCode(52); case '>': return sendShiftCode(52);
case '?': return sendShiftCode(53); case '?': return sendShiftCode(53);
case 0: return sendCtrlAltDel();
case 27: return sendCtrlBreak(); // escape
} }
} }

29
bootsect.S Normal file
View File

@@ -0,0 +1,29 @@
.arch i8086,jumps
.code16
.section .init
.global _start
_start:
#ifndef NOBPB
jmp l0
nop
.ascii "IBM 3.1"
bpb_bytespersect: .word 512
bpb_sectspercluster: .byte 2
bpb_reservedsects: .word 1
bbp_fats: .byte 2
bpb_rootentries: .word 112
bpb_localsectors: .word 720
bpb_mediadescr: .byte 0xfd
bpb_sectsperfat: .word 2
l0:
#endif // NOBPB
cli
xor %ax, %ax
mov %ax, %ds
mov %ax, %ss
mov $0x7c00, %sp
sti
jmp main

20
bootsect.ld Normal file
View File

@@ -0,0 +1,20 @@
SECTIONS {
. = 0x7c00;
.text : {
KEEP(*(.init))
*(.text*)
}
.rodata : {
*(.rodata*)
}
.bss (NOLOAD) : {
* (.bss)
}
.data : {
*(.data)
}
}

35
call.asm Normal file
View File

@@ -0,0 +1,35 @@
BITS 16
CPU 8086
org 0x7300
PARAMS equ 0x7380
; dw 0: target offset
; dw 2: target segment
; dw 4: number of params
; dw 6: param 0
; ...
_start:
push bx
push si
push di
push bp
mov si, PARAMS
mov bx, 0x6
xor cx, cx
a1:
cmp cx, [es:si+4]
jge a2
lea ax, [es:si+bx]
push ax
add bl, 2
inc cl
jmp a1
a2:
call far [es:si]
pop bp
pop di
pop si
pop bx
ret

19
copy.asm Normal file
View File

@@ -0,0 +1,19 @@
BITS 16
CPU 8086
main:
mov bp, sp
mov si, [bp+4]
mov cx, [si]
mov si, [bp+6]
mov di, [si]
mov si, [bp+8]
mov si, [si]
push ds
push es
pop ds
cld
rep movsw
pop ds
retf 6

View File

@@ -24,10 +24,11 @@ asm (
"main: \n" "main: \n"
" push %bp \n" " push %bp \n"
" mov %sp, %bp \n" " mov %sp, %bp \n"
" mov 6(%bp), %si \n" " mov 8(%bp), %si \n"
" push (%si) \n" " push (%si) \n"
" call crc16 \n" " call crc16 \n"
" mov 8(%bp), %di \n" " add $0x2, %sp \n"
" mov 6(%bp), %di \n"
" mov %ax, (%di) \n" " mov %ax, (%di) \n"
" pop %bp \n" " pop %bp \n"
" lret $4 \n" " lret $4 \n"

52
crc16.s Normal file
View File

@@ -0,0 +1,52 @@
.arch i8086,jumps
.code16
.att_syntax prefix
#NO_APP
#APP
.global main
main:
push %bp
mov %sp, %bp
mov 8(%bp), %si
push (%si)
call crc16
add $0x2, %sp
mov 6(%bp), %di
mov %ax, (%di)
pop %bp
lret $4
#NO_APP
.text
.global crc16
.type crc16, @function
crc16:
pushw %bp
movw %sp, %bp
xorw %bx, %bx
movw $-1, %ax
.L2:
cmpw 4(%bp), %bx
jne .L5
popw %bp
ret
.L5:
movb %cs:(%bx), %dl
movb $8, %cl
shlw %cl, %dx
xorw %dx, %ax
movb %cl, %dl
.L4:
movw %ax, %cx
shlw $1, %cx
testw %ax, %ax
xchgw %ax, %cx
jge .L3
xorw $4129, %ax
.L3:
decb %dl
jne .L4
incw %bx
jmp .L2
.size crc16, .-crc16
.ident "GCC: (GNU) 6.3.0"

12
crt0.c
View File

@@ -6,8 +6,16 @@ int main();
asm ( asm (
".section .init \n" ".section .init \n"
".global _start \n" ".global _start \n"
"_start: \n" "_start: \n\t"
" jmp main \n" "mov %cs, %ax \n\t"
"mov %ax, %ds \n\t"
"mov %ax, %es \n\t"
"cli \n\t"
"mov %ax, %ss \n\t"
"mov $0x1000, %ax \n\t"
"mov %ax, %sp \n\t"
"sti \n\t"
"jmp main"
); );
void* memset(void* ptr, int val, size_t len) { void* memset(void* ptr, int val, size_t len) {

66
debug.asm Normal file
View File

@@ -0,0 +1,66 @@
BITS 16
CPU 8086
org 0x7000
_start:
jmp main
hexdigits:
db "0123456789abcdef"
putc:
push bx
push bp
mov ah, 0x0e
xor bh, bh
int 0x10
pop bp
pop bx
ret
printnibble:
push si
push bx
mov si, hexdigits
xor bh, bh
mov bl, al
and bl, 0xf
mov al, cs:[si+bx]
call putc
pop bx
pop si
ret
printi8:
push bx
mov bl, al
mov cl, 4
shr al, cl
call printnibble
mov al, bl
call printnibble
pop bx
ret
printi16:
push bx
mov bx, ax
mov al, ah
call printi8
mov al, bl
call printi8
pop bx
ret
main:
mov bp, sp
mov si, [bp+4]
mov si, [si]
mov ax, [si]
call printi16
mov al, 0x0d
call putc
mov al, 0x0a
call putc
retf 2

25
dosdbt.asm Normal file
View File

@@ -0,0 +1,25 @@
BITS 16
CPU 8086
diskpointer equ 0x1e*4
dbtbase equ 0x100
_start:
jmp main
main:
push ds
mov si, diskpointer
lds si, [si]
mov di, dbtbase
mov cx, 0x0a
cld
rep movsb
pop ds
mov al, 9 ; sectors per track
mov di, dbtbase
mov [di+4], al
mov di, diskpointer
mov [di], word dbtbase
mov [di+2], ds
retf

138
fat12.c Normal file
View File

@@ -0,0 +1,138 @@
#include <stdint.h>
#include <stdlib.h>
#define kSectorsPerCluster 2
#define kSectorsPerTrack 9
#define kHeads 2
#define kFatSizeSectors 2
#define kRootDirSizeSectors 7
#define kDataRegionStartSector (1 + kFatSizeSectors*2 + kRootDirSizeSectors)
typedef struct {
char name[8];
char ext[3];
uint8_t attr;
uint8_t dontcare[14];
uint16_t cluster;
uint32_t size;
} direntry;
static uint8_t* gFat;
static direntry* gRootdir;
static int readsector(int c, int h, int s, uint8_t* addr) {
register uint8_t* dest asm ("bx") = addr;
register uint8_t nsects asm ("al") = 1;
register uint8_t func asm ("ah") = 0x02;
register uint8_t sect asm ("cl") = s;
register uint8_t cyl asm ("ch") = c;
register uint8_t head asm ("dh") = h;
register uint8_t drive asm ("dl") = 0;
register uint16_t seg asm ("es") = 0;
register uint8_t ret asm("ah");
for (int i = 0; i < 3; i++) {
asm volatile ("int $0x13"
: "=r" (ret)
: "r" (dest), "r" (nsects), "r" (func), "r" (sect),
"r" (cyl), "r" (head), "r" (drive), "r" (seg));
if (ret == 0x80) {
continue;
} else {
return ret;
}
}
return ret;
}
static int readcluster(int cluster) {
int offs = cluster * 3 / 2;
if (cluster % 2) {
// high nibble is lsb + whole byte
return ((gFat[offs] & 0xf0) >> 4) + (gFat[offs+1] << 4);
} else {
return gFat[offs] + ((gFat[offs+1] & 0x0f) << 8);
}
}
static void cluster2chs(int cluster, int* c, int* h, int* s) {
int logicalsector = kDataRegionStartSector + (cluster - 2) * kSectorsPerCluster;
*s = (logicalsector % kSectorsPerTrack) + 1;
*h = (logicalsector / kSectorsPerTrack) % kHeads;
*c = logicalsector / (kHeads * kSectorsPerTrack);
}
static int strncmp(const char* s1, const char *s2, size_t len) {
for (int i = 0; i < len && s1[i]; i++) {
if (s1[i] != s2[i]) {
return 1;
}
}
// XXX: really we should return 0 only if *s1 == *s2 here too
return 0;
}
static int loadfile(direntry* entry, void* addr) {
int cluster = entry->cluster;
for (int i = 0; i < entry->size; i+=1024) {
int c, h, s;
cluster2chs(cluster, &c, &h, &s);
if (readsector(c, h, s, addr + i)) {
return -5;
}
s++;
if (s > 9) {
s = 1;
h++;
}
if (h > 1) {
h = 0;
c++;
}
if (readsector(c, h, s, addr + i + 512)) {
return -5;
};
cluster = readcluster(cluster);
}
return 0;
}
int fat12_init(void* fat_addr, void* rootdir_addr) {
if (readsector(0, 0, 2, fat_addr)) {
return -2;
}
if (readsector(0, 0, 6, rootdir_addr)) {
return -3;
}
gFat = fat_addr;
gRootdir = rootdir_addr;
return 0;
}
int fat12_readfile(const char* name, void* addr) {
direntry* file = 0;
for (int i = 0; i < 16; i++) {
direntry* entry = &gRootdir[i];
if (entry->name[0] == 0) {
break;
}
if (!strncmp(entry->name, name, 11)) {
file = entry;
break;
}
}
if (!file) {
return -4;
}
return loadfile(file, addr);
}

15
fat12.h Normal file
View File

@@ -0,0 +1,15 @@
#pragma once
/*
* Arguments:
* - fat_addr: 1 KiB
* - rootdir_addr: 3.5 KiB
*/
int fat12_init(void* fat_addr, void* rootdir_addr);
/*
* Returns:
* -4 if file is not found
* -5 if there is a disk error
*/
int fat12_readfile(const char* name, void* addr);

59
fat12boot.c Normal file
View File

@@ -0,0 +1,59 @@
#include <stdint.h>
#include <stdlib.h>
#include "fat12.h"
#define kPolmonAddress ((void*)0x0600)
#define kFatAddress ((void*)0x1000)
#define kRootDirAddress ((void*)0x1200)
static int putchar(int c) {
register uint8_t khar asm ("al") = c;
register uint8_t func asm ("ah") = 0x0e;
register uint8_t page asm ("bh") = 0;
asm volatile ("int $0x10"
:: "r" (khar), "r" (func), "r" (page)
: "bp");
return c;
}
static int puts(const char* msg) {
while (*msg) {
putchar(*msg++);
}
return 0;
}
__attribute__((noreturn))
static void die(const char* msg) {
puts(msg);
while (1) {
}
__builtin_unreachable();
}
__attribute__((noreturn))
static void jump(void* addr) {
asm volatile ("ljmp $0,%0" :: "i"(addr));
__builtin_unreachable();
}
__attribute__((noreturn))
static void loadpolmon() {
if (fat12_init(kFatAddress, kRootDirAddress)) {
die("fi");
}
if (fat12_readfile("POLMON COM", kPolmonAddress)) {
die("pnf");
}
jump(kPolmonAddress);
}
int main() {
loadpolmon();
}

20
flat0600.ld Normal file
View File

@@ -0,0 +1,20 @@
SECTIONS {
. = 0x0600;
.text : {
KEEP(*(.init))
*(.text*)
}
.rodata : {
*(.rodata*)
}
.bss (NOLOAD) : {
* (.bss)
}
.data : {
*(.data)
}
}

63
format.asm Normal file
View File

@@ -0,0 +1,63 @@
BITS 16
CPU 8086
buffer equ 0xe000
sectors equ 9
_start:
jmp main
formattrack:
push bp
push bx
push di
mov bp, sp
push ax ; track
push cx ; head
mov bx, buffer
xor cx, cx
l0:
cmp cl, sectors
jnl l1
mov di, cx
and di, 0x0f ; max 15 sectors
shl di, 1
shl di, 1 ; di = cl*4
lea di, [bx+di]
mov al, [bp-2] ; track number
mov [di+0], al
mov al, [bp-4] ; head number
mov [di+1], al
mov al, cl ; sector number
inc al
mov [di+2], al
mov [di+3], byte 0x02 ; 512 bytes per sector
inc cl
jmp l0
l1:
mov ah, 0x05 ; format track
mov al, sectors
mov dl, 0 ; first drive
mov dh, [bp-4] ; head number
mov ch, [bp-2] ; track number
mov cl, 1 ; sector number (first sector?)
int 0x13
add sp, 4
pop di
pop bx
pop bp
ret
main:
mov bp, sp
mov si, [bp+8]
mov ax, [si]
mov si, [bp+6]
mov cx, [si]
call formattrack
mov si, [bp+4]
mov [si], ax
retf 6

25
hello.asm Normal file
View File

@@ -0,0 +1,25 @@
BITS 16
CPU 8086
org 0x7200
_start:
jmp main
hw:
db "Hello, world!", 0x0d, 0x0a, 0
main:
xor bx, bx
mov si, hw
printloop:
mov al, cs:[si]
test al, al
jz done
mov ah, 0x0e
int 0x10
inc si
jmp printloop
done:
retf

384
polmon.cc Normal file
View File

@@ -0,0 +1,384 @@
#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

View File

@@ -1,9 +1,6 @@
BITS 16 BITS 16
CPU 8086
org 0xff00
; actual entry point of the program, must be present
start: start:
; sp and all segment registers need to be saved ; sp and all segment registers need to be saved
@@ -32,4 +29,4 @@ mov [si], ax
pop es pop es
pop bp pop bp
retf 8 ; 6 is 2x the number of parameters on the stack retf 8 ; 2x the number of parameters on the stack

151
wozmon.cc
View File

@@ -1,151 +0,0 @@
#include <cstdint>
namespace {
uint8_t getc() {
register uint8_t c asm ("al");
asm volatile (
"mov $0x00, %%ah\n"
"int $0x16\n"
: "=r" (c)
);
return c;
}
void putc(uint8_t c) {
asm volatile (
"mov %0, %%al\n"
"mov $0x0e, %%ah\n"
"int $0x10\n"
:: "r" (c)
);
}
void Jump(uint32_t addr) {
auto jump = reinterpret_cast<void (*)()>(addr);
jump();
}
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');
}
uint32_t ReadHex(const char* buf) {
uint32_t out = 0;
while (*buf == ' ') {
buf++;
}
for (int i = 0; i < 8; i++) {
uint8_t c = ReadHexNibble(*buf);
if (c > 0xf) {
break;
}
out = (out << 4) + c;
buf++;
}
return out;
}
void WriteHexNibble(uint8_t c) {
if (c > 9) {
putc('a' + c - 10);
} else {
putc('0' + c);
}
}
void WriteUint32(uint32_t a) {
for (int i = 0; i < 8; i++) {
WriteHexNibble((a >> 28) & 0xf);
a <<= 4;
}
}
void WriteUint8(uint8_t a) {
WriteHexNibble(a >> 4);
WriteHexNibble(a & 0xf);
}
void Dump(uint32_t addr, int count) {
for (int i = 0; i < count; i++) {
putc(' ');
WriteUint8(*reinterpret_cast<uint8_t*>(addr + i));
}
}
void DumpHex(uint32_t addr) {
addr &= 0xfffffffc;
WriteUint32(addr);
putc(':');
Dump(addr, 4);
putc('\r');
putc('\n');
}
int FindChar(const char* buf, uint8_t c) {
int found = 0;
while (*buf) {
if (*buf == c) {
return found;
}
found++;
buf++;
}
return -1;
}
void wozmon() {
uint32_t cur_addr = 0;
uint32_t cur_data = 0;
char inbuf[64] = {};
char* inptr = inbuf;
while (1) {
uint8_t c = getc();
putc(c); // echo
if (c == '\r') {
*inptr = 0;
if (inptr == inbuf) {
cur_addr += 4;
} else if (FindChar(inbuf, 'r') >= 0) {
Jump(cur_addr);
} else {
cur_addr = ReadHex(inbuf);
putc('\n');
}
DumpHex(cur_addr);
int assigned = FindChar(inbuf, ':');
if (assigned >= 0) {
cur_data = ReadHex(inbuf + assigned + 1);
*(reinterpret_cast<uint32_t*>(cur_addr)) = cur_data;
}
inptr = inbuf;
} else if (c == kBackspace) {
inptr--;
if (inptr < inbuf) {
inptr = inbuf;
continue;
}
putc(kOtherBackspace);
putc(' ');
putc(kOtherBackspace);
} else {
*inptr++ = c;
}
}
}
} // namespace
int main() {
wozmon();
}

261
wozmon.s
View File

@@ -1,261 +0,0 @@
.arch i8086,jumps
.code16
.att_syntax prefix
#NO_APP
.text
.type _ZN12_GLOBAL__N_14putcEh, @function
_ZN12_GLOBAL__N_14putcEh:
movw %sp, %bx
movb 2(%bx), %al
#APP
;# 21 "wozmon.cc" 1
mov $0x0e, %ah
int $0x10
;# 0 "" 2
#NO_APP
ret
.size _ZN12_GLOBAL__N_14putcEh, .-_ZN12_GLOBAL__N_14putcEh
.type _ZN12_GLOBAL__N_17ReadHexEPKc, @function
_ZN12_GLOBAL__N_17ReadHexEPKc:
pushw %si
pushw %di
pushw %bp
movw %sp, %bp
pushw %ds
pushw %ds
movw 8(%bp), %ax
movw %ax, -2(%bp)
.L5:
movw -2(%bp), %bx
cmpb $32, (%bx)
jne .L4
incw -2(%bp)
jmp .L5
.L4:
xorw %di, %di
movw %di, %ax
movw %di, %dx
movb $4, %ch
.L9:
movw %di, %bx
movw -2(%bp), %si
movb (%bx,%si), %cl
cmpb $57, %cl
ja .L6
addb $-48, %cl
.L12:
movb %cl, %bl
cmpb $15, %cl
ja .L3
movw %ax, %si
movb $12, %cl
shrw %cl, %si
movb %ch, %cl
shlw %cl, %dx
orw %si, %dx
shlw %cl, %ax
movb %bl, -4(%bp)
movb -4(%bp), %bl
xorb %bh, %bh
addw %bx, %ax
movw $0, %bx
adcw %bx, %dx
incw %di
cmpw $8, %di
jne .L9
.L3:
movw %bp, %sp
popw %bp
popw %di
popw %si
ret
.L6:
addb $-87, %cl
jmp .L12
.size _ZN12_GLOBAL__N_17ReadHexEPKc, .-_ZN12_GLOBAL__N_17ReadHexEPKc
.type _ZN12_GLOBAL__N_114WriteHexNibbleEh, @function
_ZN12_GLOBAL__N_114WriteHexNibbleEh:
pushw %bp
movw %sp, %bp
movb 4(%bp), %al
movb %al, %dl
xorb %dh, %dh
cmpw $9, %dx
jle .L14
addb $87, %al
.L16:
movb %al, 4(%bp)
popw %bp
jmp _ZN12_GLOBAL__N_14putcEh
.L14:
addb $48, %al
jmp .L16
.size _ZN12_GLOBAL__N_114WriteHexNibbleEh, .-_ZN12_GLOBAL__N_114WriteHexNibbleEh
.section .text.startup,"ax",@progbits
.global main
.type main, @function
main:
movw %sp, %bp
subw $76, %sp
leaw -64(%bp), %di
movw $64, %ax
pushw %ax
xorw %ax, %ax
movw %ax, %es
pushw %ax
pushw %di
call memset
addw $6, %sp
movw %es, %si
movw %es, -70(%bp)
.L18:
#APP
;# 11 "wozmon.cc" 1
mov $0x00, %ah
int $0x16
;# 0 "" 2
#NO_APP
pushw %ax
movb %al, -71(%bp)
call _ZN12_GLOBAL__N_14putcEh
addw $2, %sp
movb -71(%bp), %al
cmpb $13, %al
jne .L19
movb $0, (%di)
leaw -64(%bp), %bx
cmpw %bx, %di
jne .L21
addw $4, %si
adcw $0, -70(%bp)
.L22:
movw %si, %ax
andw $-4, %ax
movw %ax, %es
movw -70(%bp), %di
movw $8, %bx
.L25:
movw %ax, -76(%bp)
movw %bx, -74(%bp)
movb $12, %cl
movb %cl, -71(%bp)
pushw -68(%bp)
call _ZN12_GLOBAL__N_114WriteHexNibbleEh
movw -76(%bp), %ax
movw %ax, %dx
movb -71(%bp), %cl
shrw %cl, %dx
movb $4, %cl
shlw %cl, %di
shlw %cl, %ax
orw %dx, %di
addw $2, %sp
movw -74(%bp), %bx
decw %bx
jne .L25
movb $58, %al
pushw %ax
call _ZN12_GLOBAL__N_14putcEh
movw %es, %di
leaw 4(%di), %cx
addw $2, %sp
.L26:
movw %cx, -74(%bp)
movb $32, %al
pushw %ax
call _ZN12_GLOBAL__N_14putcEh
movb (%di), %dl
movb %dl, %al
movb %dl, -71(%bp)
xorb %ah, %ah
movb $4, %cl
sarw %cl, %ax
pushw %ax
call _ZN12_GLOBAL__N_114WriteHexNibbleEh
movb -71(%bp), %dl
andb $15, %dl
pushw %dx
call _ZN12_GLOBAL__N_114WriteHexNibbleEh
incw %di
addw $6, %sp
movw -74(%bp), %cx
cmpw %di, %cx
jne .L26
movb $13, %al
pushw %ax
call _ZN12_GLOBAL__N_14putcEh
movb $10, %al
pushw %ax
call _ZN12_GLOBAL__N_14putcEh
addw $4, %sp
xorw %bx, %bx
leaw -64(%bp), %di
.L29:
movb (%bx,%di), %al
testb %al, %al
je .L18
cmpb $58, %al
je .L28
incw %bx
jmp .L29
.L32:
xchgw %ax, %di
jmp .L18
.L21:
movb (%bx), %al
testb %al, %al
je .L23
cmpb $114, %al
je .L24
incw %bx
jmp .L21
.L19:
cmpb $127, %al
jne .L30
decw %di
leaw -64(%bp), %ax
cmpw %ax, %di
jc .L32
movb $8, %al
pushw %ax
movb %al, -71(%bp)
call _ZN12_GLOBAL__N_14putcEh
movb $32, %dl
pushw %dx
call _ZN12_GLOBAL__N_14putcEh
movb -71(%bp), %al
pushw %ax
call _ZN12_GLOBAL__N_14putcEh
addw $6, %sp
jmp .L18
.L30:
movb %al, (%di)
incw %di
jmp .L18
.L24:
call *%si
jmp .L22
.L23:
leaw -64(%bp), %ax
pushw %ax
call _ZN12_GLOBAL__N_17ReadHexEPKc
addw $2, %sp
xchgw %ax, %si
movw %dx, -70(%bp)
movb $10, %al
pushw %ax
call _ZN12_GLOBAL__N_14putcEh
addw $2, %sp
jmp .L22
.L28:
leaw 1(%bx,%di), %bx
pushw %bx
call _ZN12_GLOBAL__N_17ReadHexEPKc
addw $2, %sp
movw %ax, (%si)
movw %dx, 2(%si)
jmp .L18
.size main, .-main
.ident "GCC: (GNU) 6.3.0"

View File

@@ -1,9 +1,6 @@
BITS 16 BITS 16
CPU 8086
org 0xfc00
; actual entry point of the program, must be present
start: start:
; sp and all segment registers need to be saved ; sp and all segment registers need to be saved
@@ -32,4 +29,4 @@ mov [si], ax
pop es pop es
pop bp pop bp
retf 8 ; 6 is 2x the number of parameters on the stack retf 8 ; 2x the number of parameters on the stack