Compare commits

..

14 Commits

26 changed files with 1210 additions and 446 deletions

9
.clang-format Normal file
View File

@@ -0,0 +1,9 @@
---
Language: Cpp
BasedOnStyle: LLVM
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
IndentWidth: 4
InsertNewlineAtEOF: true
PointerAlignment: Left
SpacesBeforeTrailingComments: 2

4
.gitignore vendored
View File

@@ -1,3 +1,5 @@
*.bin *.bin
*.o
*.elf
*.com
polos.img polos.img
polmon.com

View File

@@ -1,7 +1,7 @@
dev-image = 5150-dev dev-image = 5150-dev
%.bin: %.asm %.bin: %.asm
nasm $? -o $@ nasm $< -o $@
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
@@ -19,23 +19,23 @@ LDFLAGS = -mregparmcall -Wl,--gc-sections -Os -nostdlib -flto
%.elf: %.elf:
$(LD) $(LDFLAGS) $(CPPFLAGS) -o $@ $^ $(LD) $(LDFLAGS) $(CPPFLAGS) -o $@ $^
bootsectors = fat12boot.bin wozmon.bin %.com: %.elf
ia16-elf-objcopy -O binary $< $@
bootsectors = fat12boot.bin wozmon.bin
$(bootsectors): $(bootsectors):
ia16-elf-objcopy -O binary $? $@ ia16-elf-objcopy -O binary $< $@
truncate -s 510 $@
printf "\125\252" >> $@
fat12boot.elf: fat12boot.o fat12.o bootsect.S fat12boot.elf: fat12boot.o fat12.o bootsect.S
fat12boot.elf: LDFLAGS += -T bootsect.ld fat12boot.elf: LDFLAGS += -T bootsect.ld
fat12boot.bin: fat12boot.elf fat12boot.bin: fat12boot.elf
polmon.elf: LDFLAGS += -T flat0600.ld polmon.elf: LDFLAGS += -T flat1000.ld
polmon.elf: polmon.o polmon.elf: polmon.o stdlib.o
polmon.com: polmon.elf polio.elf: LDFLAGS += -T flat0600.ld
ia16-elf-objcopy -O binary $? $@ polio.elf: polio.s fat12.o
wozmon.o: polmon.cc wozmon.o: polmon.cc
wozmon.o: CPPFLAGS = -DWOZMON=1 wozmon.o: CPPFLAGS = -DWOZMON=1
@@ -48,15 +48,20 @@ wozmon.elf: CPPFLAGS += -DNOBPB
wozmon.bin: wozmon.elf wozmon.bin: wozmon.elf
polos.img: fat12boot.bin polmon.com paracli.elf: LDFLAGS += -T doscom.ld
paracli.elf: paracli.s paracomm.o
polos.img: fat12boot.bin polmon.com polio.com paracli.com
dd if=/dev/zero of=$@ bs=512 count=720 dd if=/dev/zero of=$@ bs=512 count=720
mformat -i $@ -t 40 -h 2 -s 9 mformat -i $@ -t 40 -h 2 -s 9
mcopy -i $@ polmon.com ::/polmon.com mcopy -i $@ polio.com ::/
mcopy -i $@ polmon.com ::/
mcopy -i $@ paracli.com ::/
dd if=fat12boot.bin of=$@ conv=notrunc dd if=fat12boot.bin of=$@ conv=notrunc
.PHONY: clean .PHONY: clean
clean: ## Remove generated files clean: ## Remove generated files
rm -rf *.bin polmon.com polos.img rm -rf *.bin *.elf *.o *.com polos.img
.PHONY: dev-image .PHONY: dev-image
dev-image: dev-image:
@@ -68,7 +73,7 @@ dev: dev-image ## Launch a dev container
.PHONY: binaries .PHONY: binaries
binaries: ## Build all binaries binaries: ## Build all small binaries
docker build --build-arg TARGET=readfloppy.bin -o . --target=export . 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=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 .
@@ -76,11 +81,9 @@ binaries: ## Build all binaries
docker build --build-arg TARGET=hello.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=copy.bin -o . --target=export .
docker build --build-arg TARGET=call.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=format.bin -o . --target=export .
docker build --build-arg TARGET=polmon.com -o . --target=export . docker build --build-arg TARGET=readio.bin -o . --target=export .
docker build --build-arg TARGET=fat12boot.bin -o . --target=export . docker build --build-arg TARGET=writeio.bin -o . --target=export .
.PHONY: floppy .PHONY: floppy
floppy: ## Make a bootable floppy image floppy: ## Make a bootable floppy image

193
arduino/kbd/kbd.cc Normal file
View File

@@ -0,0 +1,193 @@
// keyboard wiring diagram:
// https://www.minuszerodegrees.net/5150/misc/5150_keyboard_reset.jpg
#include "Arduino.h"
constexpr int kClockPin = PC6;
constexpr int kDataPin = PC4;
constexpr int kBitDelayMicros = 100;
constexpr int kCodeDelayMicros = 200;
constexpr int kKeyDelayMicros = 100;
namespace {
void sendCode(int code) {
// preconditions: clock and data pins are INPUT
while (digitalRead(kDataPin) == LOW || digitalRead(kClockPin) == LOW) {
// wait. we're not allowed to send
}
digitalWrite(kDataPin, LOW);
digitalWrite(kClockPin, LOW);
pinMode(kClockPin, OUTPUT);
delayMicroseconds(kBitDelayMicros);
pinMode(kClockPin, INPUT);
// delayMicroseconds(kDelayMicros);
for (int i = 0; i < 8; i++) {
if ((code & (1 << i)) == 0) {
// send a 0
pinMode(kDataPin, OUTPUT);
} // else do nothing, it's already a 1
delayMicroseconds(kBitDelayMicros);
pinMode(kClockPin, OUTPUT);
delayMicroseconds(kBitDelayMicros);
pinMode(kDataPin, INPUT);
pinMode(kClockPin, INPUT);
}
delayMicroseconds(kCodeDelayMicros);
}
enum State {
kReady,
kMaybeReset,
};
constexpr int kResetDelay = 19;
constexpr int kLetterCodes[] = {
0x1E, // 'a'
0x30, 0x2E, 0x20, 0x12, 0x21, 0x22, 0x23, 0x17, 0x24,
0x25, 0x26, 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1F,
0x14, 0x16, 0x2F, 0x11, 0x2D, 0x15, 0x2c,
};
constexpr int kNumberCodes[] = {
0x0B, // '0'
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
};
void sendNormalCode(int code) {
sendCode(code);
sendCode(code | 0x80);
}
void sendShiftCode(int code) {
sendCode(42); // left shift
sendNormalCode(code);
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);
}
} // namespace
void sendAsciiChar(int c) {
if (c >= 'a' && c <= 'z') {
return sendNormalCode(kLetterCodes[c - 'a']);
} else if (c >= '0' && c <= '9') {
return sendNormalCode(kNumberCodes[c - '0']);
} else if (c >= 'A' && c <= 'Z') {
return sendShiftCode(kLetterCodes[c - 'A']);
}
switch (c) {
case '-':
return sendNormalCode(12);
case '=':
return sendNormalCode(13);
case '[':
return sendNormalCode(26);
case ']':
return sendNormalCode(27);
case ';':
return sendNormalCode(39);
case '\'':
return sendNormalCode(40);
case ',':
return sendNormalCode(51);
case '.':
return sendNormalCode(52);
case '/':
return sendNormalCode(53);
case ' ':
return sendNormalCode(57);
case '\n':
return sendNormalCode(28);
case '!':
return sendShiftCode(2);
case '@':
return sendShiftCode(3);
case '#':
return sendShiftCode(4);
case '$':
return sendShiftCode(5);
case '%':
return sendShiftCode(6);
case '^':
return sendShiftCode(7);
case '&':
return sendShiftCode(8);
case '*':
return sendShiftCode(9);
case '(':
return sendShiftCode(10);
case ')':
return sendShiftCode(11);
case '_':
return sendShiftCode(12);
case '+':
return sendShiftCode(13);
case '{':
return sendShiftCode(26);
case '}':
return sendShiftCode(27);
case ':':
return sendShiftCode(39);
case '"':
return sendShiftCode(40);
case '<':
return sendShiftCode(51);
case '>':
return sendShiftCode(52);
case '?':
return sendShiftCode(53);
case 0:
return sendCtrlAltDel();
case 27:
return sendCtrlBreak(); // escape
}
}
void setupKbd() {
pinMode(kClockPin, INPUT);
pinMode(kDataPin, INPUT);
}
void checkKbdReset() {
static State state = kReady;
static int lastclocklow = 0;
int clockp = digitalRead(kClockPin);
if (state == State::kReady && clockp == LOW) {
state = State::kMaybeReset;
lastclocklow = millis();
} else if (state == State::kMaybeReset) {
if (clockp == HIGH && millis() - lastclocklow > kResetDelay) {
delay(1);
state = State::kReady;
sendCode(0xaa);
Serial.println("Reset!");
}
}
}

5
arduino/kbd/kbd.h Normal file
View File

@@ -0,0 +1,5 @@
#pragma once
void sendAsciiChar(int c);
void setupKbd();
void checkKbdReset();

View File

@@ -1,213 +1,67 @@
// keyboard wiring diagram: https://www.minuszerodegrees.net/5150/misc/5150_keyboard_reset.jpg #include "kbd.h"
#include "paracomm.h"
#include "parallel.h"
constexpr int kClockPin = PC6; ParaComms pc;
constexpr int kDataPin = PC4;
constexpr int kBitDelayMicros = 100;
constexpr int kCodeDelayMicros = 200;
constexpr int kKeyDelayMicros = 100;
void setup() { void setup() {
// put your setup code here, to run once: // put your setup code here, to run once:
Serial.begin(115200); Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT); pinMode(LED_BUILTIN, OUTPUT);
pinMode(kClockPin, INPUT); setupKbd();
pinMode(kDataPin, INPUT); setupParallel();
Serial.println("kbd 0.1"); pc = ParaComms{
} .mosi_cb =
[](uint8_t *data, uint8_t len) {
for (int i = 0; i < len; i++) {
Serial.printf("%c", data[i]);
pc.SendByte(data[i]); // echo
if (data[i] == '\r') {
pc.SendByte('\n');
}
}
},
};
// 0. reset Serial.println("kbd 0.1");
// 0.0. clock line will be held low externally for 20 ms
// when back up, keyboard needs to clock 0xAA as a response
//
// 1. operation
// 1.0. just directly clock out scan codes of pressed keys
void sendCode(int code) {
Serial.printf("sending code 0x%02x\n", code);
// preconditions: clock and data pins are INPUT
while (digitalRead(kDataPin) == LOW || digitalRead(kClockPin) == LOW) {
// wait. we're not allowed to send
}
digitalWrite(kDataPin, LOW);
digitalWrite(kClockPin, LOW);
pinMode(kClockPin, OUTPUT);
delayMicroseconds(kBitDelayMicros);
pinMode(kClockPin, INPUT);
// delayMicroseconds(kDelayMicros);
for (int i = 0; i < 8; i++) {
if ((code & (1 << i)) == 0) {
// send a 0
pinMode(kDataPin, OUTPUT);
} // else do nothing, it's already a 1
delayMicroseconds(kBitDelayMicros);
pinMode(kClockPin, OUTPUT);
delayMicroseconds(kBitDelayMicros);
pinMode(kDataPin, INPUT);
pinMode(kClockPin, INPUT);
}
delayMicroseconds(kCodeDelayMicros);
}
enum State {
kReady,
kMaybeReset,
};
constexpr int kResetDelay = 19;
State state = State::kReady;
int lastclocklow = 0;
constexpr int kLetterCodes[] = {
0x1E, // 'a'
0x30,
0x2E,
0x20,
0x12,
0x21,
0x22,
0x23,
0x17,
0x24,
0x25,
0x26,
0x32,
0x31,
0x18,
0x19,
0x10,
0x13,
0x1F,
0x14,
0x16,
0x2F,
0x11,
0x2D,
0x15,
0x2c,
};
constexpr int kNumberCodes[] = {
0x0B, // '0'
0x02,
0x03,
0x04,
0x05,
0x06,
0x07,
0x08,
0x09,
0x0A,
};
void sendNormalCode(int code) {
sendCode(code);
sendCode(code | 0x80);
}
void sendShiftCode(int code) {
sendCode(42); // left shift
sendNormalCode(code);
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) {
if (c >= 'a' && c <= 'z') {
return sendNormalCode(kLetterCodes[c - 'a']);
} else if (c >= '0' && c <= '9') {
return sendNormalCode(kNumberCodes[c - '0']);
} else if (c >= 'A' && c <= 'Z') {
return sendShiftCode(kLetterCodes[c - 'A']);
}
switch (c) {
case '-': return sendNormalCode(12);
case '=': return sendNormalCode(13);
case '[': return sendNormalCode(26);
case ']': return sendNormalCode(27);
case ';': return sendNormalCode(39);
case '\'': return sendNormalCode(40);
case ',': return sendNormalCode(51);
case '.': return sendNormalCode(52);
case '/': return sendNormalCode(53);
case ' ': return sendNormalCode(57);
case '\n': return sendNormalCode(28);
case '!': return sendShiftCode(2);
case '@': return sendShiftCode(3);
case '#': return sendShiftCode(4);
case '$': return sendShiftCode(5);
case '%': return sendShiftCode(6);
case '^': return sendShiftCode(7);
case '&': return sendShiftCode(8);
case '*': return sendShiftCode(9);
case '(': return sendShiftCode(10);
case ')': return sendShiftCode(11);
case '_': return sendShiftCode(12);
case '+': return sendShiftCode(13);
case '{': return sendShiftCode(26);
case '}': return sendShiftCode(27);
case ':': return sendShiftCode(39);
case '"': return sendShiftCode(40);
case '<': return sendShiftCode(51);
case '>': return sendShiftCode(52);
case '?': return sendShiftCode(53);
case 0: return sendCtrlAltDel();
case 27: return sendCtrlBreak(); // escape
}
} }
void loop() { void loop() {
static int led_counter = 0; static int led_counter = 0;
static int led = HIGH; static int led = HIGH;
if (led_counter > 400000) {
led_counter = 0;
led = (led == HIGH) ? LOW : HIGH;
digitalWrite(LED_BUILTIN, led);
}
led_counter += 1;
int clockp = digitalRead(kClockPin); static int mode = 0; // 0 = keyboard, 1 = parallel
if (state == State::kReady && clockp == LOW) {
state = State::kMaybeReset; if (led_counter > 400000) {
lastclocklow = millis(); led_counter = 0;
} else if (state == State::kMaybeReset) { led = (led == HIGH) ? LOW : HIGH;
if (clockp == HIGH && millis() - lastclocklow > kResetDelay) { digitalWrite(LED_BUILTIN, led);
delay(1);
state = State::kReady;
sendCode(0xaa);
Serial.println("Reset!");
} }
} led_counter += 1;
if (Serial.available() > 0) { checkKbdReset();
int c = Serial.read();
sendAsciiChar(c); uint8_t mosib;
//delayMicroseconds(kKeyDelayMicros); if (strobeOccurred(mosib)) {
} pc.FeedMosiData(mosib);
uint8_t misob = pc.NextMisoNibble();
writeParallel(misob);
}
if (Serial.available() > 0) {
int c = Serial.read();
if (c == 2) {
mode = 0;
} else if (c == 3) {
mode = 1;
} else {
if (mode == 0) {
sendAsciiChar(c);
} else {
pc.SendByte(c);
}
}
}
} }

124
arduino/kbd/paracomm.h Normal file
View File

@@ -0,0 +1,124 @@
#pragma once
#include <stdint.h>
struct ParaComms {
using MessageCallback = void (*)(uint8_t *, uint8_t);
enum State {
kIdle,
kLength,
kLength2, // for miso
kData,
// kCrc, // ?
};
static constexpr uint8_t kMosiStartByte = 0x42;
static constexpr uint8_t kIdleByte = 0x00;
static constexpr uint8_t kMisoStartNibble = 0xa;
static constexpr uint8_t kMisoIdleNibble = 0x0;
MessageCallback mosi_cb = nullptr;
uint8_t *miso_buffer = nullptr;
uint8_t miso_size = 0;
uint8_t miso_nibbles_sent = 0;
State miso_state = kIdle;
// double work buffer. one being sent, one being written to
uint8_t miso_workbuf[2][256];
uint8_t miso_workbuf_idx = 0;
uint8_t miso_workbuf_size = 0;
uint8_t mosi_buffer[256];
uint8_t mosi_size = 0;
uint8_t mosi_received = 0;
State mosi_state = kIdle;
void SwapBuffers() {
miso_buffer = miso_workbuf[miso_workbuf_idx];
miso_size = miso_workbuf_size;
miso_workbuf_idx = (miso_workbuf_idx + 1) % 2;
miso_workbuf_size = 0;
}
int SendByte(uint8_t b) {
if (miso_workbuf_size == 256) {
return -1; // sorry we're full
}
uint8_t *buff = miso_workbuf[miso_workbuf_idx];
buff[miso_workbuf_size] = b;
miso_workbuf_size += 1;
return 0;
}
void FeedMosiData(uint8_t b) {
switch (mosi_state) {
case kIdle:
// check start byte
if (b == kMosiStartByte) {
mosi_state = kLength;
} else if (b == kIdleByte) {
// just twiddling our thumb drives
} else {
// Serial.printf("sp: %02x\n", b);
}
break;
case kLength:
// assert(b > 0)
mosi_size = b;
mosi_received = 0;
mosi_state = kData;
break;
case kData:
mosi_buffer[mosi_received] = b;
mosi_received += 1;
if (mosi_received == mosi_size) {
if (mosi_cb != nullptr) {
mosi_cb(mosi_buffer, mosi_received);
}
mosi_state = kIdle;
}
case kLength2: // error
return;
}
}
uint8_t NextMisoNibble() {
switch (miso_state) {
case kIdle:
if (miso_size == 0) {
SwapBuffers();
if (miso_size == 0) {
return kMisoIdleNibble;
}
}
miso_state = kLength;
return kMisoStartNibble;
case kLength:
// assert(miso_size > 0);
miso_state = kLength2;
return miso_size & 0xf;
case kLength2:
miso_nibbles_sent = 0;
miso_state = kData;
return miso_size >> 4;
case kData: {
uint8_t b = miso_buffer[miso_nibbles_sent / 2];
if (miso_nibbles_sent % 2 == 0) {
b &= 0xf;
} else {
b >>= 4;
}
miso_nibbles_sent += 1;
if (miso_nibbles_sent == miso_size * 2) {
SwapBuffers();
miso_state = kIdle;
}
return b;
}
}
__builtin_unreachable();
}
};

95
arduino/kbd/parallel.cc Normal file
View File

@@ -0,0 +1,95 @@
#include "parallel.h"
#include <stdint.h>
#include "Arduino.h"
namespace {
constexpr int kParallelDataPins[] = {
D9, D8, D7, D6, D5, D4, D3, D2,
};
constexpr int kParallelBusyPin = D14;
constexpr int kParallelAckPin = D15;
constexpr int kParallelPaperoutPin = D12;
constexpr int kParallelSelectPin = D11;
constexpr int kParallelNibblePins[] = {
kParallelSelectPin,
kParallelPaperoutPin,
kParallelAckPin,
kParallelBusyPin,
};
constexpr bool kParallelNibbleInverted[] = {
false,
false,
false,
true,
};
constexpr int kParallelStrobePin = D10;
volatile bool strobe_pending = false;
volatile uint8_t strobe_byte = 0;
void strobeIsr() {
strobe_pending = true;
strobe_byte = readParallel();
}
} // namespace
uint8_t readParallel() {
uint8_t out = 0;
for (int i = 0; i < 8; i++) {
if (digitalReadFast(digitalPinToPinName(kParallelDataPins[i])) ==
HIGH) {
out |= (1 << i);
}
}
if (digitalReadFast(digitalPinToPinName(kParallelStrobePin)) == HIGH) {
out |= (1 << 8);
}
return out;
}
#define BIT(x, n) ((x & (1 << n)) ? HIGH : LOW)
void writeParallel(uint8_t nibble) {
for (int i = 0; i < 4; i++) {
int lvl = BIT(nibble, i);
if (kParallelNibbleInverted[i]) {
lvl = lvl == HIGH ? LOW : HIGH;
}
digitalWriteFast(digitalPinToPinName(kParallelNibblePins[i]), lvl);
}
}
bool strobeOccurred(uint8_t &byte) {
bool pending;
{
noInterrupts();
pending = strobe_pending;
byte = strobe_byte;
strobe_pending = false;
interrupts();
}
return pending;
}
void setupParallel() {
for (int i = 0; i < sizeof(kParallelDataPins) / sizeof(int); i++) {
pinMode(kParallelDataPins[i], INPUT);
}
for (int i = 0; i < sizeof(kParallelNibblePins) / sizeof(int); i++) {
pinMode(kParallelNibblePins[i], OUTPUT);
digitalWrite(kParallelNibblePins[i], HIGH);
}
pinMode(kParallelStrobePin, INPUT);
attachInterrupt(digitalPinToInterrupt(kParallelStrobePin), strobeIsr,
FALLING);
}

14
arduino/kbd/parallel.h Normal file
View File

@@ -0,0 +1,14 @@
#pragma once
#include <stdint.h>
/** Returns the byte present on D0~D7 */
uint8_t readParallel();
/** Writes a nibble on status pins */
void writeParallel(uint8_t nibble);
void setupParallel();
/** Returns true and sets the byte if a strobe was received */
bool strobeOccurred(uint8_t &byte);

View File

@@ -17,4 +17,9 @@ SECTIONS {
.data : { .data : {
*(.data) *(.data)
} }
. = 0x7dfe;
.magic : {
SHORT(0xAA55);
}
} }

View File

@@ -11,9 +11,12 @@ main:
mov si, [si] mov si, [si]
push ds push ds
push es push es
pop ds mov ax, cs
mov ds, ax
mov es, ax
cld cld
rep movsw rep movsw
pop es
pop ds pop ds
retf 6 retf 6

28
crc16.c
View File

@@ -1,6 +1,6 @@
#include <stdint.h> #include <stdint.h>
#define kDataAddr ((uint8_t*) 0x0000) #define kDataAddr ((uint8_t*)0x0000)
uint16_t crc16(int data_len) { uint16_t crc16(int data_len) {
const uint8_t* data = kDataAddr; const uint8_t* data = kDataAddr;
@@ -19,17 +19,15 @@ uint16_t crc16(int data_len) {
return crc; return crc;
} }
asm ( asm(".global main \n"
".global main \n" "main: \n"
"main: \n" " push %bp \n"
" push %bp \n" " mov %sp, %bp \n"
" mov %sp, %bp \n" " mov 8(%bp), %si \n"
" mov 8(%bp), %si \n" " push (%si) \n"
" push (%si) \n" " call crc16 \n"
" call crc16 \n" " add $0x2, %sp \n"
" add $0x2, %sp \n" " mov 6(%bp), %di \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"
);

28
crt0.c
View File

@@ -3,24 +3,22 @@
int main(); int main();
asm ( asm(".section .init \n"
".section .init \n" ".global _start \n"
".global _start \n" "_start: \n\t"
"_start: \n\t" "mov %cs, %ax \n\t"
"mov %cs, %ax \n\t" "mov %ax, %ds \n\t"
"mov %ax, %ds \n\t" "mov %ax, %es \n\t"
"mov %ax, %es \n\t" "cli \n\t"
"cli \n\t" "mov %ax, %ss \n\t"
"mov %ax, %ss \n\t" "mov $0x1000, %ax \n\t"
"mov $0x1000, %ax \n\t" "mov %ax, %sp \n\t"
"mov %ax, %sp \n\t" "sti \n\t"
"sti \n\t" "jmp main");
"jmp main"
);
void* memset(void* ptr, int val, size_t len) { void* memset(void* ptr, int val, size_t len) {
uint8_t* p = ptr; uint8_t* p = ptr;
while(len--) { while (len--) {
*p++ = val; *p++ = val;
} }
return ptr; return ptr;

20
doscom.ld Normal file
View File

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

45
fat12.c
View File

@@ -6,8 +6,7 @@
#define kHeads 2 #define kHeads 2
#define kFatSizeSectors 2 #define kFatSizeSectors 2
#define kRootDirSizeSectors 7 #define kRootDirSizeSectors 7
#define kDataRegionStartSector (1 + kFatSizeSectors*2 + kRootDirSizeSectors) #define kDataRegionStartSector (1 + kFatSizeSectors * 2 + kRootDirSizeSectors)
typedef struct { typedef struct {
char name[8]; char name[8];
@@ -23,28 +22,25 @@ typedef struct {
static uint8_t* gFat; static uint8_t* gFat;
static direntry* gRootdir; static direntry* gRootdir;
static int readsector(int c, int h, int s, uint8_t* addr) { static int readsector(int c, int h, int s, uint8_t* addr) {
register uint8_t* dest asm ("bx") = addr; register uint8_t* dest asm("bx") = addr;
register uint8_t nsects asm ("al") = 1; register uint8_t nsects asm("al") = 1;
register uint8_t func asm ("ah") = 0x02; register uint8_t func asm("ah") = 0x02;
register uint8_t sect asm ("cl") = s; register uint8_t sect asm("cl") = s;
register uint8_t cyl asm ("ch") = c; register uint8_t cyl asm("ch") = c;
register uint8_t head asm ("dh") = h; register uint8_t head asm("dh") = h;
register uint8_t drive asm ("dl") = 0; register uint8_t drive asm("dl") = 0;
register uint16_t seg asm ("es") = 0; register uint16_t seg asm("es") = 0;
register uint8_t ret asm("ah"); register uint8_t ret asm("ah");
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
asm volatile ("int $0x13" asm volatile("int $0x13"
: "=r" (ret) : "=r"(ret)
: "r" (dest), "r" (nsects), "r" (func), "r" (sect), : "r"(dest), "r"(nsects), "r"(func), "r"(sect), "r"(cyl),
"r" (cyl), "r" (head), "r" (drive), "r" (seg)); "r"(head), "r"(drive), "r"(seg));
if (ret == 0x80) { if (ret != 0x80) {
continue; break;
} else {
return ret;
} }
} }
@@ -55,20 +51,21 @@ static int readcluster(int cluster) {
int offs = cluster * 3 / 2; int offs = cluster * 3 / 2;
if (cluster % 2) { if (cluster % 2) {
// high nibble is lsb + whole byte // high nibble is lsb + whole byte
return ((gFat[offs] & 0xf0) >> 4) + (gFat[offs+1] << 4); return ((gFat[offs] & 0xf0) >> 4) + (gFat[offs + 1] << 4);
} else { } else {
return gFat[offs] + ((gFat[offs+1] & 0x0f) << 8); return gFat[offs] + ((gFat[offs + 1] & 0x0f) << 8);
} }
} }
static void cluster2chs(int cluster, int* c, int* h, int* s) { static void cluster2chs(int cluster, int* c, int* h, int* s) {
int logicalsector = kDataRegionStartSector + (cluster - 2) * kSectorsPerCluster; int logicalsector =
kDataRegionStartSector + (cluster - 2) * kSectorsPerCluster;
*s = (logicalsector % kSectorsPerTrack) + 1; *s = (logicalsector % kSectorsPerTrack) + 1;
*h = (logicalsector / kSectorsPerTrack) % kHeads; *h = (logicalsector / kSectorsPerTrack) % kHeads;
*c = logicalsector / (kHeads * kSectorsPerTrack); *c = logicalsector / (kHeads * kSectorsPerTrack);
} }
static int strncmp(const char* s1, const char *s2, size_t len) { static int strncmp(const char* s1, const char* s2, size_t len) {
for (int i = 0; i < len && s1[i]; i++) { for (int i = 0; i < len && s1[i]; i++) {
if (s1[i] != s2[i]) { if (s1[i] != s2[i]) {
return 1; return 1;
@@ -80,7 +77,7 @@ static int strncmp(const char* s1, const char *s2, size_t len) {
static int loadfile(direntry* entry, void* addr) { static int loadfile(direntry* entry, void* addr) {
int cluster = entry->cluster; int cluster = entry->cluster;
for (int i = 0; i < entry->size; i+=1024) { for (int i = 0; i < entry->size; i += 1024) {
int c, h, s; int c, h, s;
cluster2chs(cluster, &c, &h, &s); cluster2chs(cluster, &c, &h, &s);
if (readsector(c, h, s, addr + i)) { if (readsector(c, h, s, addr + i)) {

View File

@@ -7,15 +7,12 @@
#define kFatAddress ((void*)0x1000) #define kFatAddress ((void*)0x1000)
#define kRootDirAddress ((void*)0x1200) #define kRootDirAddress ((void*)0x1200)
static int putchar(int c) { static int putchar(int c) {
register uint8_t khar asm ("al") = c; register uint8_t khar asm("al") = c;
register uint8_t func asm ("ah") = 0x0e; register uint8_t func asm("ah") = 0x0e;
register uint8_t page asm ("bh") = 0; register uint8_t page asm("bh") = 0;
asm volatile ("int $0x10" asm volatile("int $0x10" ::"r"(khar), "r"(func), "r"(page) : "bp");
:: "r" (khar), "r" (func), "r" (page)
: "bp");
return c; return c;
} }
@@ -27,33 +24,30 @@ static int puts(const char* msg) {
return 0; return 0;
} }
__attribute__((noreturn)) __attribute__((noreturn)) static void die(const char* msg) {
static void die(const char* msg) {
puts(msg); puts(msg);
while (1) { while (1) {
} }
__builtin_unreachable(); __builtin_unreachable();
} }
__attribute__((noreturn)) __attribute__((noreturn)) static void jump(void* addr) {
static void jump(void* addr) { asm volatile("ljmp $0,%0" ::"i"(addr));
asm volatile ("ljmp $0,%0" :: "i"(addr));
__builtin_unreachable(); __builtin_unreachable();
} }
__attribute__((noreturn)) __attribute__((noreturn)) static void loadpolmon() {
static void loadpolmon() {
if (fat12_init(kFatAddress, kRootDirAddress)) { if (fat12_init(kFatAddress, kRootDirAddress)) {
die("fi"); die("fi");
} }
if (fat12_readfile("POLMON COM", kPolmonAddress)) { while (fat12_readfile("POLIO COM", kPolmonAddress)) {
die("pnf"); asm volatile("mov $00, %%ah \n\t"
"int $0x16 \n\t" ::
: "ax");
} }
jump(kPolmonAddress); jump(kPolmonAddress);
} }
int main() { int main() { loadpolmon(); }
loadpolmon();
}

20
flat1000.ld Normal file
View File

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

80
paracli.s Normal file
View File

@@ -0,0 +1,80 @@
.arch i8086,jumps
.code16
.intel_syntax noprefix
.section .init
.global _start
_start:
mov ax, cs
mov ds, ax
mov es, ax
cli
mov ss, ax
mov sp, 0x100
sti
jmp main
.section .text.parcb
parcb:
push bx
push si
push bp
mov si, ax
1:
test dx, dx
jz 0f
mov al, [si]
mov ah, 0x0e
mov bh, 0
int 0x10
dec dx
inc si
jmp 1b
0:
pop bp
pop si
pop bx
ret
.section .rodata.l0
.l0: .ascii "> "
.l1: .ascii "."
delay = 500
.section .text.main
.global main
main:
mov ax, 0x0002
int 0x10
mov ax, offset parcb
call paracomm_init
0:
mov ah, 0x01
int 0x16
jz 1f
mov ah, 0x00
int 0x16
mov ah, 0
call paracomm_send
test ax, ax
jz 0b
1:
call paracomm_nextbyte
mov dx, 0x3bc
out dx, al
add dl, 2
mov al, 1
out dx, al
mov cx, delay
2: loop 2b
mov al, 0
out dx, al
mov cx, delay
3: loop 3b
dec dl
in al, dx
mov cl, 4
shr al, cl
call paracomm_feed
jmp 0b

124
paracomm.c Normal file
View File

@@ -0,0 +1,124 @@
#include "paracomm.h"
#include <stdlib.h>
#define kMosiIdleByte 0x00
#define kMosiStartByte 0x42
#define kMisoIdleNibble 0x0
#define kMisoStartNibble 0xa
static uint8_t mosi_workbuf[2][256];
static uint8_t mosi_workbuf_idx;
static uint8_t mosi_workbuf_size;
static uint8_t* mosi_sendbuf;
static uint8_t mosi_size;
static uint8_t mosi_sent;
static uint8_t mosi_state;
static uint8_t miso_recvbuf[256];
static uint8_t miso_size;
static uint8_t miso_received_nibbles;
static uint8_t miso_state;
static void (*miso_cb)(const uint8_t*, uint8_t);
static void swapbuffers() {
mosi_sendbuf = mosi_workbuf[mosi_workbuf_idx];
mosi_size = mosi_workbuf_size;
mosi_workbuf_size = 0;
mosi_workbuf_idx = (mosi_workbuf_idx + 1) % 2;
}
uint8_t paracomm_nextbyte() {
switch (mosi_state) {
case 0:
if (mosi_size == 0) {
swapbuffers();
if (mosi_size == 0) {
return kMosiIdleByte;
}
}
mosi_state = 1;
return kMosiStartByte;
case 1:
// assert(mosi_size > 0)
mosi_sent = 0;
mosi_state = 2;
return mosi_size;
case 2: {
uint8_t b = mosi_sendbuf[mosi_sent];
mosi_sent += 1;
if (mosi_sent == mosi_size) {
swapbuffers();
mosi_state = 0;
}
return b;
}
}
__builtin_unreachable();
}
void paracomm_feed(uint8_t n) {
switch (miso_state) {
case 0:
if (n == kMisoStartNibble) {
miso_state = 1;
} else if (n == kMisoIdleNibble) {
} else {
// error: spurious nibble
}
break;
case 1:
miso_size = n;
miso_state = 2;
break;
case 2:
miso_size += n << 4;
miso_received_nibbles = 0;
miso_state = 3;
break;
case 3: {
uint8_t idx = miso_received_nibbles / 2;
if (miso_received_nibbles % 2 == 0) {
miso_recvbuf[idx] = n;
} else {
miso_recvbuf[idx] += n << 4;
}
miso_received_nibbles += 1;
if (miso_received_nibbles == 2 * miso_size) {
if (miso_cb != 0) {
miso_cb(miso_recvbuf, miso_size);
}
miso_state = 0;
}
} break;
}
}
void paracomm_init(miso_cb_t cb) {
mosi_size = 0;
mosi_workbuf_idx = 0;
mosi_workbuf_size = 0;
mosi_state = 0;
miso_state = 0;
miso_cb = cb;
}
int paracomm_send(uint8_t b) {
if (mosi_workbuf_size == 256) {
return -1;
}
uint8_t* buff = mosi_workbuf[mosi_workbuf_idx];
buff[mosi_workbuf_size] = b;
mosi_workbuf_size += 1;
return 0;
}

19
paracomm.h Normal file
View File

@@ -0,0 +1,19 @@
#pragma once
#include <stdint.h>
typedef void (*miso_cb_t)(const uint8_t* buff, uint8_t size);
/** Must call first **/
void paracomm_init(miso_cb_t miso_cb);
/** Sends a single byte.
* Returns: 0 if no error, non-0 otherwise.
*/
int paracomm_send(uint8_t b);
/** Call after reading a nibble from the port */
void paracomm_feed(uint8_t n);
/** Yields the next byte to send out the port */
uint8_t paracomm_nextbyte();

189
polio.s Normal file
View File

@@ -0,0 +1,189 @@
.arch i8086,jumps
.code16
.intel_syntax noprefix
.section .init
.global _start
_start:
jmp main
diskpointer = 0x1e*4
dbtbase = 0x0500
.section .text.dosdbt
.local dosdbt
dosdbt: # assumes es=0
push si
push di
push ds
mov si, diskpointer
lds si, [si]
mov di, dbtbase
mov cx, 0x0a # size of the dbt
cld
rep movsb # move dbt to dbtbase
pop ds
mov al, 9 # sectors per track
mov si, dbtbase
mov [si+4], al # set number of sectors
mov di, diskpointer
mov [di], si # new int1eh offset
mov [di+2], ds # and segment
pop di
pop si
ret
.section .text.int80stuff
# near copy [param 2] bytes, es:[param 0] -> es:[param 1]
copy:
mov si, [bp+0] # source
mov di, [bp+2] # destination
mov cx, [bp+4] # length
cld
rep movsb
ret
## floppy stuff
# same as read but with a different int13h:ah value
writesector:
mov ax, 0x0301 # write command, 1 sector
jmp 0f
# params: addr, c, h, s
# return status in ah, sectors read (1 or 0) in al
readsector:
mov ax, 0x0201 # read command, 1 sector
0:
mov bx, [bp+0] # addr
mov ch, [bp+2] # c
mov dh, [bp+4] # h
mov cl, [bp+6] # s
int 0x13
ret
# params: c, h
# returns: status in ah, 0 in al?
buffer = 0xe000 # buffer needs to be big enough for a whole track
# (for some reason), so 9 * 512 bytes = 0x1200 bytes
sectors = 9
formattrack:
mov bx, buffer
xor cx, cx
0:
cmp cl, sectors
jnl 1f
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+0] # track number
mov [di+0], al
mov al, [bp+2] # head number
mov [di+1], al
mov al, cl # sector number
inc al
mov [di+2], al
movb [di+3], 0x02 # 512 bytes per sector
inc cl
jmp 0b
1:
mov ah, 0x05 # format track
mov al, sectors
mov dl, 0 # first drive
mov ch, [bp+0] # track number
mov dh, [bp+2] # head number
mov cl, 1 # sector number (first sector?)
int 0x13
ret
readfile:
mov ax, [bp+0]
mov dx, [bp+2]
call fat12_readfile
ret
.section .rodata.polmon_str
polmon_str: .ascii "POLMON COM"
polmon_addr = 0x1000
.section .text.main
.global main
main:
cli
mov ax, 0x2000 # stack address
mov sp, ax # ss should already be 0
sti
call dosdbt
mov ax, 0x1a00 # first sector of first fat
mov dx, 0x1c00 # first sector of root dir
call fat12_init
mov si, 0x80*4
movw [si], offset int80h
movw [si+2], 0
mov ax, offset polmon_str
mov dx, polmon_addr
call fat12_readfile
test ax, ax
jnz 0f
jmp polmon_addr
0:
mov ax, 0x0e42
mov bh, 0
int 0x10
cli
hlt
.section .text.int80h
int80h:
push bx
push si
push di
push bp
push ds
push es
xor cx, cx
mov es, cx
mov ds, cx
shl ah
cmp ah, offset int80h_entries
jge 0f
mov al, ah
xor ah, ah
mov si, ax
mov bp, sp
lea bp, [bp + 18] # 12 for us, 6 for the interrupt
call [int80h_table+si]
jmp 1f
0:
mov ax, -1
1:
pop es
pop ds
pop bp
pop di
pop si
pop bx
iret
.section .rodata.int80h
int80h_table:
.word offset copy # 0x00
.word offset readsector # 0x01
.word offset writesector # 0x02
.word offset formattrack # 0x03
.word offset readfile # 0x04
int80h_entries = . - int80h_table

273
polmon.cc
View File

@@ -1,4 +1,5 @@
#include <cstdint> #include <cstdint>
#include <cstdio>
#ifndef WOZMON #ifndef WOZMON
#define WOZMON 0 #define WOZMON 0
@@ -8,7 +9,7 @@
#define BACKSPACE 0 #define BACKSPACE 0
#define ASCIIDUMP 0 #define ASCIIDUMP 0
#define CLEARSCREENCMD 0 #define CLEARSCREENCMD 0
#define FARCALL 0 #define INT80H 0
#define SHOWTITLE 0 #define SHOWTITLE 0
#define BOOTSTRAP 0 #define BOOTSTRAP 0
#endif // WOZMON #endif // WOZMON
@@ -25,8 +26,8 @@
#define CLEARSCREENCMD 1 #define CLEARSCREENCMD 1
#endif #endif
#ifndef FARCALL #ifndef INT80H
#define FARCALL 1 #define INT80H 1
#endif #endif
#ifndef SHOWTITLE #ifndef SHOWTITLE
@@ -39,69 +40,54 @@
namespace { namespace {
constexpr int kDumpSize = 16; #if WOZMON
uint8_t getc() { int getchar() {
register uint8_t c asm ("al"); register char c asm("al");
asm volatile ( asm volatile("movb $0x00, %%ah\n\t"
"movb $0x00, %%ah\n\t" "int $0x16"
"int $0x16" : "=r"(c)::"ah", "cc");
: "=r" (c)
:: "ah", "cc"
);
return c; return c;
} }
void putc(uint8_t c) { void putchar(int c) {
asm volatile ( asm volatile("push %%bp \n\t"
"push %%bp \n\t" "mov %0, %%ax \n\t"
"movb %0, %%al \n\t" "movb $0x0e, %%ah \n\t"
"movb $0x0e, %%ah \n\t" "movb $0, %%bh \n\t"
"movb $0, %%bh \n\t" "int $0x10 \n\t"
"int $0x10 \n\t" "pop %%bp \n\t" ::"r"(c)
"pop %%bp \n\t" : "ax", "bh", "cc");
:: "r" (c)
: "ax", "bh", "cc"
);
} }
void puts(const char* s) { #endif // WOZMON
while (*s) {
putc(*s++); constexpr int kDumpSize = 16;
}
}
// arguments on the stack in reverse order // arguments on the stack in reverse order
extern "C" uint16_t Jump(uint16_t addr, int nargs); extern "C" uint16_t Int80h(uint8_t fun, int nargs);
asm ( asm(".section .text.Int80h \n"
".section .text.Jump \n" "Int80h: \n"
"Jump: \n" " push %si \n"
" push %bx \n" " push %bp \n"
" push %si \n" " mov %al, %ah \n"
" push %di \n" " mov %sp, %bp \n"
" push %bp \n" " lea 6(%bp), %si \n" // 4 for pushed stuff, 2 for return addr
" push %es \n" "0: \n"
" push %ax \n" // addr " test %dx, %dx \n"
" movw %sp, %bp \n" " jz 1f \n"
" movw %dx, %si \n" // nargs " push (%si) \n"
" add %si, %si \n" " dec %dx \n"
"j0: \n" " add $2, %si \n"
" test %si, %si \n" " jmp 0b \n"
" jz j1 \n" "1: \n"
" lea 12(%bp,%si), %di\n" " int $0x80 \n"
" push %di \n" " mov %bp, %sp \n"
" sub $2, %si \n" " pop %bp \n"
" jmp j0 \n" " pop %si \n"
"j1: \n" " ret"
" lcall *(%bp) \n" // return value in ax
" 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 kBackspace = 0x7f;
constexpr uint8_t kOtherBackspace = 0x08; constexpr uint8_t kOtherBackspace = 0x08;
@@ -126,19 +112,15 @@ uint16_t ReadUintN(int n, const char* buf) {
return out; return out;
} }
uint8_t ReadUint8(const char* buf) { uint8_t ReadUint8(const char* buf) { return ReadUintN(2, buf); }
return ReadUintN(2, buf);
}
uint16_t ReadUint16(const char* buf) { uint16_t ReadUint16(const char* buf) { return ReadUintN(4, buf); }
return ReadUintN(4, buf);
}
void WriteHexNibble(uint8_t c) { void WriteHexNibble(uint8_t c) {
if (c > 9) { if (c > 9) {
putc('a' + c - 10); putchar('a' + c - 10);
} else { } else {
putc('0' + c); putchar('0' + c);
} }
} }
@@ -153,53 +135,42 @@ void WriteUint16(uint16_t a) {
} }
uint8_t __get_far_u8__(uint16_t addr, uint16_t seg) { uint8_t __get_far_u8__(uint16_t addr, uint16_t seg) {
register uint16_t ad asm ("si") = addr; register uint16_t ad asm("si") = addr;
register uint16_t sg asm ("ds") = seg; register uint16_t sg asm("ds") = seg;
register uint8_t ret asm ("al"); register uint8_t ret asm("al");
asm ( asm("lodsb \n\t" : "=r"(ret) : "r"(ad), "r"(sg));
"lodsb \n\t"
: "=r" (ret)
: "r" (ad), "r" (sg)
);
return ret; return ret;
} }
void __set_far_u8__(uint16_t addr, uint16_t seg, uint8_t val) { void __set_far_u8__(uint16_t addr, uint16_t seg, uint8_t val) {
register uint16_t ad asm ("di") = addr; register uint16_t ad asm("di") = addr;
register uint16_t sg asm ("es") = seg; register uint16_t sg asm("es") = seg;
register uint8_t v asm ("al") = val; register uint8_t v asm("al") = val;
asm ( asm("stosb \n\t" ::"r"(sg), "r"(ad), "r"(v) : "memory");
"stosb \n\t"
:: "r" (sg), "r" (ad), "r" (v)
: "memory"
);
} }
__attribute__((noreturn)) __attribute__((noreturn)) inline static void __basic__() {
inline static void __basic__() { asm volatile("movw $0x40, %ax \n\t"
asm volatile ( "mov %ax, %ds \n\t"
"movw $0x40, %ax \n\t" "int $0x18");
"mov %ax, %ds \n\t"
"int $0x18"
);
__builtin_unreachable(); __builtin_unreachable();
} }
void Dump(uint16_t addr, uint16_t seg, int count) { void Dump(uint16_t addr, uint16_t seg, int count) {
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
putc(' '); putchar(' ');
uint8_t d = __get_far_u8__(addr + i, seg); uint8_t d = __get_far_u8__(addr + i, seg);
WriteUint8(d); WriteUint8(d);
} }
#if ASCIIDUMP #if ASCIIDUMP
putc(' '); putchar(' ');
putc(' '); putchar(' ');
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
uint8_t d = __get_far_u8__(addr + i, seg); uint8_t d = __get_far_u8__(addr + i, seg);
if (d > 31 && d < 127) { if (d > 31 && d < 127) {
putc(d); putchar(d);
} else { } else {
putc('.'); putchar('.');
} }
} }
#endif #endif
@@ -208,42 +179,38 @@ void Dump(uint16_t addr, uint16_t seg, int count) {
void DumpHex(uint16_t addr, uint16_t seg) { void DumpHex(uint16_t addr, uint16_t seg) {
addr &= -kDumpSize; addr &= -kDumpSize;
putc('['); putchar('[');
WriteUint16(seg); WriteUint16(seg);
putc(':'); putchar(':');
WriteUint16(addr); WriteUint16(addr);
putc(']'); putchar(']');
putc(':'); putchar(':');
Dump(addr, seg, kDumpSize); Dump(addr, seg, kDumpSize);
putc('\r'); putchar('\r');
putc('\n'); putchar('\n');
} }
void ClearScreen() { void ClearScreen() {
asm volatile ( asm volatile("movw $0x0002, %%ax \n\t"
"movw $0x0002, %%ax \n\t" "int $0x10" ::
"int $0x10" : "ax", "cc");
::: "ax", "cc"
);
} }
void Status(uint8_t status) { void Status(uint8_t status) {
asm volatile ( asm volatile("xorb %%bh, %%bh \n\t"
"xorb %%bh, %%bh \n\t" "movb $0x03, %%ah \n\t"
"movb $0x03, %%ah \n\t" "int $0x10 \n\t"
"int $0x10 \n\t" "mov %%dx, %%di \n\t"
"mov %%dx, %%di \n\t" "movb $0x02, %%ah \n\t"
"movb $0x02, %%ah \n\t" "movw $77, %%dx \n\t"
"movw $77, %%dx \n\t" "int $0x10 \n\t"
"int $0x10 \n\t" "movb %0, %%al \n\t"
"movb %0, %%al \n\t" "call %1 \n\t"
"call _ZN12_GLOBAL__N_110WriteUint8Eh \n\t" "movb $0x02, %%ah \n\t"
"movb $0x02, %%ah \n\t" "movw %%di, %%dx \n\t"
"movw %%di, %%dx \n\t" "int $0x10" ::"rm"(status),
"int $0x10" "l"(WriteUint8)
:: "rm" (status) : "ax", "bh", "dx", "cx", "di", "cc");
: "ax", "bh", "dx", "cx", "di", "cc"
);
} }
bool ParseCommand(const char* buf, uint16_t& cur_addr, uint16_t& cur_seg) { bool ParseCommand(const char* buf, uint16_t& cur_addr, uint16_t& cur_seg) {
@@ -251,38 +218,42 @@ bool ParseCommand(const char* buf, uint16_t& cur_addr, uint16_t& cur_seg) {
for (const char* ptr = buf; *ptr;) { for (const char* ptr = buf; *ptr;) {
if (*ptr == 's') { if (*ptr == 's') {
cur_addr = 0; cur_addr = 0;
cur_seg = ReadUint16(ptr+1); cur_seg = ReadUint16(ptr + 1);
ptr += 5; ptr += 5;
} else if (*ptr == '$') { } else if (*ptr == '$') {
__basic__(); __basic__();
} else if (*ptr == 'r') { } else if (*ptr == 'j') {
dump = false;
ptr++;
auto jump = reinterpret_cast<uint16_t (*)()>(cur_addr);
uint16_t ret = jump();
WriteUint16(ret);
putchar('\r');
putchar('\n');
#if INT80H
} else if (*ptr == 'i') {
dump = false; dump = false;
#if FARCALL
int nargs = 0; int nargs = 0;
ptr++; ptr++;
int fun = ReadUint8(ptr);
ptr += 2;
for (; *ptr;) { for (; *ptr;) {
if (*ptr == ' ') { if (*ptr == ' ') {
ptr++; ptr++;
continue; continue;
} }
uint16_t d = ReadUint16(ptr); uint16_t d = ReadUint16(ptr);
asm volatile ("push %0" :: "r" (d)); asm volatile("push %0" ::"r"(d));
nargs++; nargs++;
ptr += 4; ptr += 4;
} }
uint16_t ret = Jump(cur_addr, nargs); uint16_t ret = Int80h(fun, nargs);
asm volatile ( asm volatile("shl %0 \n\t"
"shl %0 \n\t" "add %0, %%sp" ::"r"(nargs));
"add %0, %%sp"
:: "r"(nargs)
);
WriteUint16(ret); WriteUint16(ret);
putc('\r'); putc('\n'); putchar('\r');
#else // FARCALL putchar('\n');
auto jump = reinterpret_cast<void(*)()>(cur_addr); #endif // INT80H
jump();
#endif // FARCALL
ptr++;
#if CLEARSCREENCMD #if CLEARSCREENCMD
} else if (*ptr == 'l') { } else if (*ptr == 'l') {
dump = false; dump = false;
@@ -311,7 +282,10 @@ bool ParseCommand(const char* buf, uint16_t& cur_addr, uint16_t& cur_seg) {
return dump; return dump;
} }
const char* prompt = "> "; void DisplayPrompt() {
putchar('>');
putchar(' ');
}
void polmon() { void polmon() {
uint16_t cur_addr = 0; uint16_t cur_addr = 0;
@@ -324,11 +298,11 @@ void polmon() {
#if SHOWTITLE #if SHOWTITLE
puts("PolMon 0.2\r\n"); puts("PolMon 0.2\r\n");
#endif // SHOWTITLE #endif // SHOWTITLE
puts(prompt); DisplayPrompt();
while (1) { while (1) {
uint8_t c = getc(); uint8_t c = getchar();
putc(c); // echo putchar(c); // echo
if (c == '\r') { if (c == '\r') {
*inptr = 0; *inptr = 0;
if (inbuf[0] == 0) { if (inbuf[0] == 0) {
@@ -336,7 +310,7 @@ void polmon() {
cur_addr += kDumpSize; cur_addr += kDumpSize;
} }
} else { } else {
putc('\n'); putchar('\n');
} }
if (ParseCommand(inbuf, cur_addr, cur_seg)) { if (ParseCommand(inbuf, cur_addr, cur_seg)) {
@@ -344,17 +318,17 @@ void polmon() {
}; };
first = false; first = false;
inptr = inbuf; inptr = inbuf;
puts(prompt); DisplayPrompt();
#if BACKSPACE #if BACKSPACE
} else if (c == kBackspace || c == kOtherBackspace) { } else if (c == kBackspace || c == kOtherBackspace) {
inptr--; inptr--;
if (inptr < inbuf) { if (inptr < inbuf) {
inptr = inbuf; inptr = inbuf;
putc(' '); putchar(' ');
continue; continue;
} }
putc(' '); putchar(' ');
putc(kOtherBackspace); putchar(kOtherBackspace);
#endif #endif
} else { } else {
*inptr = c; *inptr = c;
@@ -365,13 +339,10 @@ void polmon() {
} // namespace } // namespace
int main() { int main() { polmon(); }
polmon();
}
#if BOOTSTRAP #if BOOTSTRAP
__attribute__((section(".init"), noreturn, used)) __attribute__((section(".init"), noreturn, used)) void _start() {
void _start() {
main(); main();
__builtin_unreachable(); __builtin_unreachable();
} }

10
readio.asm Normal file
View File

@@ -0,0 +1,10 @@
BITS 16
CPU 8086
_start:
mov bp, sp
mov si, [bp+4]
mov dx, [si]
xor ax, ax
in al, dx
retf 2

25
stdlib.c Normal file
View File

@@ -0,0 +1,25 @@
int getchar() {
register char c asm("al");
asm volatile("movb $0x00, %%ah\n\t"
"int $0x16"
: "=r"(c)::"ah", "cc");
return c;
}
int putchar(int c) {
asm volatile("push %%bp \n\t"
"mov %0, %%ax \n\t"
"movb $0x0e, %%ah \n\t"
"movb $0, %%bh \n\t"
"int $0x10 \n\t"
"pop %%bp \n\t" ::"r"(c)
: "ax", "bh", "cc");
return 0;
}
int puts(const char* s) {
while (*s) {
putchar(*s++);
}
return 0;
}

12
writeio.asm Normal file
View File

@@ -0,0 +1,12 @@
BITS 16
CPU 8086
_start:
mov bp, sp
mov si, [bp+6]
mov dx, [si]
xor ax, ax
mov si, [bp+4]
mov al, [si]
out dx, al
retf 4