Initial commit: try make binaries
This commit is contained in:
commit
789fa1306c
29
Dockerfile
Normal file
29
Dockerfile
Normal file
@ -0,0 +1,29 @@
|
||||
FROM ubuntu:jammy AS deps
|
||||
|
||||
RUN apt-get update && apt-get install -y software-properties-common
|
||||
RUN add-apt-repository ppa:tkchia/build-ia16
|
||||
RUN apt-get update && apt-get install -y gcc-ia16-elf
|
||||
RUN apt-get install nasm make
|
||||
|
||||
|
||||
FROM deps AS dev
|
||||
|
||||
WORKDIR /workspace
|
||||
RUN adduser --home /workspace paul
|
||||
USER 1000:1000
|
||||
|
||||
|
||||
FROM deps AS build
|
||||
|
||||
ARG TARGET
|
||||
|
||||
ADD . /workspace
|
||||
WORKDIR /workspace
|
||||
RUN make ${TARGET}
|
||||
|
||||
|
||||
FROM scratch AS export
|
||||
|
||||
ARG TARGET
|
||||
|
||||
COPY --from=build /workspace/${TARGET} /
|
48
Makefile
Normal file
48
Makefile
Normal file
@ -0,0 +1,48 @@
|
||||
dev-image = 5150-dev
|
||||
|
||||
writefloppy.bin: writefloppy.asm
|
||||
nasm writefloppy.asm -o writefloppy.bin
|
||||
|
||||
readfloppy.bin: readfloppy.asm
|
||||
nasm readfloppy.asm -o readfloppy.bin
|
||||
|
||||
crc16.s: crc16.c
|
||||
ia16-elf-gcc -S -Os -o crc16.s crc16.c
|
||||
|
||||
crc16.bin: crc16.s crt0.c 5150.ld
|
||||
ia16-elf-gcc -o crc16.bin -Os -nostdlib crc16.s crt0.c
|
||||
|
||||
wozmon.s: wozmon.cc
|
||||
ia16-elf-gcc -S -Os -o wozmon.s wozmon.cc
|
||||
|
||||
wozmon.bin: wozmon.s crt0.c 5150.ld
|
||||
ia16-elf-gcc -o wozmon.bin -Os -nostdlib wozmon.s crt0.c
|
||||
truncate -s 510 wozmon.bin
|
||||
printf "\125\252" >> wozmon.bin
|
||||
|
||||
.PHONY: clean
|
||||
clean: ## Remove generated files
|
||||
rm -rf wozmon.bin crc16.bin readfloppy.bin writefloppy.bin
|
||||
|
||||
.PHONY: dev-image
|
||||
dev-image:
|
||||
docker build -t $(dev-image) --target dev .
|
||||
|
||||
.PHONY: dev
|
||||
dev: dev-image ## Launch a dev container
|
||||
docker run -it --rm -v $(CURDIR):/workspace $(dev-image)
|
||||
|
||||
|
||||
.PHONY: binaries
|
||||
binaries: ## Build all binaries
|
||||
docker build --build-arg TARGET=readfloppy.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=wozmon.bin -o . --target=export .
|
||||
|
||||
|
||||
.PHONY: help
|
||||
help: ## Show this help
|
||||
@echo Noteworthy targets:
|
||||
@egrep '^[a-zA-Z_-]+:.*?## .*$$' $(firstword $(MAKEFILE_LIST)) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
|
||||
.DEFAULT_GOAL := help
|
13
README.md
Normal file
13
README.md
Normal file
@ -0,0 +1,13 @@
|
||||
5150 stuff
|
||||
==========
|
||||
|
||||
The binary programs here use multiple conventions (more Fun!):
|
||||
- .asm files use NASM syntax and are built with `nasm xx.asm`
|
||||
- .s files use GAS syntax, they are built with `ia14-elf-gcc`
|
||||
|
||||
The reason is uh, because you see, I did things.
|
||||
|
||||
The .asm came first and was copy pasta from the internet.
|
||||
The .s files came from the output of `ia16-elf-gcc -S` when I couldn't be bothered to write programs in assembly but still needed to make them compatible with BASIC's *CALL* instruction.
|
||||
|
||||
Also the wozmon binary contains special care to make it into a boot sector (0xaa55 magic).
|
34
crc16.c
Normal file
34
crc16.c
Normal file
@ -0,0 +1,34 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#define kDataAddr ((uint8_t*) 0x0000)
|
||||
|
||||
uint16_t crc16(int data_len) {
|
||||
const uint8_t* data = kDataAddr;
|
||||
|
||||
uint16_t crc = 0xFFFF;
|
||||
for (unsigned int i = 0; i < data_len; ++i) {
|
||||
uint16_t dbyte = data[i];
|
||||
crc ^= dbyte << 8;
|
||||
for (unsigned char j = 0; j < 8; ++j) {
|
||||
uint16_t mix = crc & 0x8000;
|
||||
crc = (crc << 1);
|
||||
if (mix)
|
||||
crc = crc ^ 0x1021;
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
asm (
|
||||
".global main \n"
|
||||
"main: \n"
|
||||
" push %bp \n"
|
||||
" mov %sp, %bp \n"
|
||||
" mov 6(%bp), %si \n"
|
||||
" push (%si) \n"
|
||||
" call crc16 \n"
|
||||
" mov 8(%bp), %di \n"
|
||||
" mov %ax, (%di) \n"
|
||||
" pop %bp \n"
|
||||
" lret $4 \n"
|
||||
);
|
19
crt0.c
Normal file
19
crt0.c
Normal file
@ -0,0 +1,19 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
int main();
|
||||
|
||||
asm (
|
||||
".section .init \n"
|
||||
".global _start \n"
|
||||
"_start: \n"
|
||||
" jmp main \n"
|
||||
);
|
||||
|
||||
void* memset(void* ptr, int val, size_t len) {
|
||||
uint8_t* p = ptr;
|
||||
while(len--) {
|
||||
*p++ = val;
|
||||
}
|
||||
return ptr;
|
||||
}
|
35
readfloppy.asm
Normal file
35
readfloppy.asm
Normal file
@ -0,0 +1,35 @@
|
||||
BITS 16
|
||||
|
||||
org 0xff00
|
||||
|
||||
|
||||
; actual entry point of the program, must be present
|
||||
start:
|
||||
|
||||
; sp and all segment registers need to be saved
|
||||
push bp ; and we also save bp (??)
|
||||
push es
|
||||
mov bp, sp ; we'll need that to access parameters
|
||||
|
||||
xor dx, dx ; drive 0, head 0
|
||||
mov es, dx ; es = 0
|
||||
|
||||
mov bx, 0xf000 ; store the read sector there
|
||||
mov ax, 0x0201 ; read, 1 sector
|
||||
|
||||
; params: head, cylinder, sector, out
|
||||
mov si, [bp+14]
|
||||
mov dh, [si]
|
||||
mov si, [bp+12]
|
||||
mov ch, [si]
|
||||
mov si, [bp+10]
|
||||
mov cl, [si]
|
||||
|
||||
int 0x13
|
||||
|
||||
mov si, [bp+8]
|
||||
mov [si], ax
|
||||
|
||||
pop es
|
||||
pop bp
|
||||
retf 8 ; 6 is 2x the number of parameters on the stack
|
151
wozmon.cc
Normal file
151
wozmon.cc
Normal file
@ -0,0 +1,151 @@
|
||||
#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();
|
||||
}
|
35
writefloppy.asm
Normal file
35
writefloppy.asm
Normal file
@ -0,0 +1,35 @@
|
||||
BITS 16
|
||||
|
||||
org 0xfc00
|
||||
|
||||
|
||||
; actual entry point of the program, must be present
|
||||
start:
|
||||
|
||||
; sp and all segment registers need to be saved
|
||||
push bp ; and we also save bp (??)
|
||||
push es
|
||||
mov bp, sp ; we'll need that to access parameters
|
||||
|
||||
xor dx, dx ; drive 0, head 0
|
||||
mov es, dx ; es = 0
|
||||
|
||||
mov bx, 0xf000 ; store the read sector there
|
||||
mov ax, 0x0301 ; write, 1 sector
|
||||
|
||||
; params: head, cylinder, sector, out
|
||||
mov si, [bp+14]
|
||||
mov dh, [si]
|
||||
mov si, [bp+12]
|
||||
mov ch, [si]
|
||||
mov si, [bp+10]
|
||||
mov cl, [si]
|
||||
|
||||
int 0x13
|
||||
|
||||
mov si, [bp+8]
|
||||
mov [si], ax
|
||||
|
||||
pop es
|
||||
pop bp
|
||||
retf 8 ; 6 is 2x the number of parameters on the stack
|
Loading…
Reference in New Issue
Block a user