Compare commits
14 Commits
202bae362a
...
f1b2902640
| Author | SHA1 | Date | |
|---|---|---|---|
| f1b2902640 | |||
| f3057e92be | |||
| e20b09f130 | |||
| 8b434f4434 | |||
| 83e267fa36 | |||
| dd5d329dff | |||
| 044e58ef12 | |||
| de41328677 | |||
| 8a06693456 | |||
| 05d5e5413f | |||
| 50e3017c5c | |||
| 7cbd423ef9 | |||
| c49d00422a | |||
| bbaefabf8a |
9
.clang-format
Normal file
9
.clang-format
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
||||
ConstructorInitializerIndentWidth: 8
|
||||
ContinuationIndentWidth: 8
|
||||
IndentWidth: 4
|
||||
InsertNewlineAtEOF: true
|
||||
PointerAlignment: Left
|
||||
SpacesBeforeTrailingComments: 2
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,3 +1,5 @@
|
||||
*.bin
|
||||
*.o
|
||||
*.elf
|
||||
*.com
|
||||
polos.img
|
||||
polmon.com
|
||||
|
||||
37
Makefile
37
Makefile
@@ -1,7 +1,7 @@
|
||||
dev-image = 5150-dev
|
||||
|
||||
%.bin: %.asm
|
||||
nasm $? -o $@
|
||||
nasm $< -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:
|
||||
$(LD) $(LDFLAGS) $(CPPFLAGS) -o $@ $^
|
||||
|
||||
bootsectors = fat12boot.bin wozmon.bin
|
||||
%.com: %.elf
|
||||
ia16-elf-objcopy -O binary $< $@
|
||||
|
||||
bootsectors = fat12boot.bin wozmon.bin
|
||||
$(bootsectors):
|
||||
ia16-elf-objcopy -O binary $? $@
|
||||
truncate -s 510 $@
|
||||
printf "\125\252" >> $@
|
||||
ia16-elf-objcopy -O binary $< $@
|
||||
|
||||
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.elf: LDFLAGS += -T flat1000.ld
|
||||
polmon.elf: polmon.o stdlib.o
|
||||
|
||||
polmon.com: polmon.elf
|
||||
ia16-elf-objcopy -O binary $? $@
|
||||
polio.elf: LDFLAGS += -T flat0600.ld
|
||||
polio.elf: polio.s fat12.o
|
||||
|
||||
wozmon.o: polmon.cc
|
||||
wozmon.o: CPPFLAGS = -DWOZMON=1
|
||||
@@ -48,15 +48,20 @@ wozmon.elf: CPPFLAGS += -DNOBPB
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
.PHONY: clean
|
||||
clean: ## Remove generated files
|
||||
rm -rf *.bin polmon.com polos.img
|
||||
rm -rf *.bin *.elf *.o *.com polos.img
|
||||
|
||||
.PHONY: dev-image
|
||||
dev-image:
|
||||
@@ -68,7 +73,7 @@ dev: dev-image ## Launch a dev container
|
||||
|
||||
|
||||
.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=writefloppy.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=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 .
|
||||
docker build --build-arg TARGET=readio.bin -o . --target=export .
|
||||
docker build --build-arg TARGET=writeio.bin -o . --target=export .
|
||||
|
||||
.PHONY: floppy
|
||||
floppy: ## Make a bootable floppy image
|
||||
|
||||
193
arduino/kbd/kbd.cc
Normal file
193
arduino/kbd/kbd.cc
Normal 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
5
arduino/kbd/kbd.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
void sendAsciiChar(int c);
|
||||
void setupKbd();
|
||||
void checkKbdReset();
|
||||
@@ -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;
|
||||
constexpr int kDataPin = PC4;
|
||||
|
||||
constexpr int kBitDelayMicros = 100;
|
||||
constexpr int kCodeDelayMicros = 200;
|
||||
constexpr int kKeyDelayMicros = 100;
|
||||
ParaComms pc;
|
||||
|
||||
void setup() {
|
||||
// put your setup code here, to run once:
|
||||
Serial.begin(115200);
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
// put your setup code here, to run once:
|
||||
Serial.begin(115200);
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
|
||||
pinMode(kClockPin, INPUT);
|
||||
pinMode(kDataPin, INPUT);
|
||||
setupKbd();
|
||||
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
|
||||
// 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
|
||||
}
|
||||
Serial.println("kbd 0.1");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
static int led_counter = 0;
|
||||
static int led = HIGH;
|
||||
if (led_counter > 400000) {
|
||||
led_counter = 0;
|
||||
led = (led == HIGH) ? LOW : HIGH;
|
||||
digitalWrite(LED_BUILTIN, led);
|
||||
}
|
||||
led_counter += 1;
|
||||
static int led_counter = 0;
|
||||
static int led = HIGH;
|
||||
|
||||
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!");
|
||||
static int mode = 0; // 0 = keyboard, 1 = parallel
|
||||
|
||||
if (led_counter > 400000) {
|
||||
led_counter = 0;
|
||||
led = (led == HIGH) ? LOW : HIGH;
|
||||
digitalWrite(LED_BUILTIN, led);
|
||||
}
|
||||
}
|
||||
led_counter += 1;
|
||||
|
||||
if (Serial.available() > 0) {
|
||||
int c = Serial.read();
|
||||
sendAsciiChar(c);
|
||||
//delayMicroseconds(kKeyDelayMicros);
|
||||
}
|
||||
checkKbdReset();
|
||||
|
||||
uint8_t mosib;
|
||||
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
124
arduino/kbd/paracomm.h
Normal 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
95
arduino/kbd/parallel.cc
Normal 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
14
arduino/kbd/parallel.h
Normal 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);
|
||||
@@ -17,4 +17,9 @@ SECTIONS {
|
||||
.data : {
|
||||
*(.data)
|
||||
}
|
||||
|
||||
. = 0x7dfe;
|
||||
.magic : {
|
||||
SHORT(0xAA55);
|
||||
}
|
||||
}
|
||||
|
||||
5
copy.asm
5
copy.asm
@@ -11,9 +11,12 @@ main:
|
||||
mov si, [si]
|
||||
push ds
|
||||
push es
|
||||
pop ds
|
||||
mov ax, cs
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
cld
|
||||
rep movsw
|
||||
pop es
|
||||
pop ds
|
||||
|
||||
retf 6
|
||||
|
||||
28
crc16.c
28
crc16.c
@@ -1,6 +1,6 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#define kDataAddr ((uint8_t*) 0x0000)
|
||||
#define kDataAddr ((uint8_t*)0x0000)
|
||||
|
||||
uint16_t crc16(int data_len) {
|
||||
const uint8_t* data = kDataAddr;
|
||||
@@ -19,17 +19,15 @@ uint16_t crc16(int data_len) {
|
||||
return crc;
|
||||
}
|
||||
|
||||
asm (
|
||||
".global main \n"
|
||||
"main: \n"
|
||||
" push %bp \n"
|
||||
" mov %sp, %bp \n"
|
||||
" mov 8(%bp), %si \n"
|
||||
" push (%si) \n"
|
||||
" call crc16 \n"
|
||||
" add $0x2, %sp \n"
|
||||
" mov 6(%bp), %di \n"
|
||||
" mov %ax, (%di) \n"
|
||||
" pop %bp \n"
|
||||
" lret $4 \n"
|
||||
);
|
||||
asm(".global main \n"
|
||||
"main: \n"
|
||||
" push %bp \n"
|
||||
" mov %sp, %bp \n"
|
||||
" mov 8(%bp), %si \n"
|
||||
" push (%si) \n"
|
||||
" call crc16 \n"
|
||||
" add $0x2, %sp \n"
|
||||
" mov 6(%bp), %di \n"
|
||||
" mov %ax, (%di) \n"
|
||||
" pop %bp \n"
|
||||
" lret $4 \n");
|
||||
|
||||
28
crt0.c
28
crt0.c
@@ -3,24 +3,22 @@
|
||||
|
||||
int main();
|
||||
|
||||
asm (
|
||||
".section .init \n"
|
||||
".global _start \n"
|
||||
"_start: \n\t"
|
||||
"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"
|
||||
);
|
||||
asm(".section .init \n"
|
||||
".global _start \n"
|
||||
"_start: \n\t"
|
||||
"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) {
|
||||
uint8_t* p = ptr;
|
||||
while(len--) {
|
||||
while (len--) {
|
||||
*p++ = val;
|
||||
}
|
||||
return ptr;
|
||||
|
||||
20
doscom.ld
Normal file
20
doscom.ld
Normal file
@@ -0,0 +1,20 @@
|
||||
SECTIONS {
|
||||
. = 0x100;
|
||||
|
||||
.text : {
|
||||
KEEP(*(.init))
|
||||
*(.text*)
|
||||
}
|
||||
|
||||
.rodata : {
|
||||
*(.rodata*)
|
||||
}
|
||||
|
||||
.bss (NOLOAD) : {
|
||||
* (.bss)
|
||||
}
|
||||
|
||||
.data : {
|
||||
*(.data)
|
||||
}
|
||||
}
|
||||
45
fat12.c
45
fat12.c
@@ -6,8 +6,7 @@
|
||||
#define kHeads 2
|
||||
#define kFatSizeSectors 2
|
||||
#define kRootDirSizeSectors 7
|
||||
#define kDataRegionStartSector (1 + kFatSizeSectors*2 + kRootDirSizeSectors)
|
||||
|
||||
#define kDataRegionStartSector (1 + kFatSizeSectors * 2 + kRootDirSizeSectors)
|
||||
|
||||
typedef struct {
|
||||
char name[8];
|
||||
@@ -23,28 +22,25 @@ typedef struct {
|
||||
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* 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;
|
||||
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) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,20 +51,21 @@ 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);
|
||||
return ((gFat[offs] & 0xf0) >> 4) + (gFat[offs + 1] << 4);
|
||||
} 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) {
|
||||
int logicalsector = kDataRegionStartSector + (cluster - 2) * kSectorsPerCluster;
|
||||
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) {
|
||||
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;
|
||||
@@ -80,7 +77,7 @@ static int strncmp(const char* s1, const char *s2, size_t len) {
|
||||
|
||||
static int loadfile(direntry* entry, void* addr) {
|
||||
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;
|
||||
cluster2chs(cluster, &c, &h, &s);
|
||||
if (readsector(c, h, s, addr + i)) {
|
||||
|
||||
2
fat12.h
2
fat12.h
@@ -11,5 +11,5 @@ 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);
|
||||
|
||||
32
fat12boot.c
32
fat12boot.c
@@ -7,15 +7,12 @@
|
||||
#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;
|
||||
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");
|
||||
asm volatile("int $0x10" ::"r"(khar), "r"(func), "r"(page) : "bp");
|
||||
|
||||
return c;
|
||||
}
|
||||
@@ -27,33 +24,30 @@ static int puts(const char* msg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
__attribute__((noreturn))
|
||||
static void die(const char* msg) {
|
||||
__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));
|
||||
__attribute__((noreturn)) static void jump(void* addr) {
|
||||
asm volatile("ljmp $0,%0" ::"i"(addr));
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
__attribute__((noreturn))
|
||||
static void loadpolmon() {
|
||||
__attribute__((noreturn)) static void loadpolmon() {
|
||||
if (fat12_init(kFatAddress, kRootDirAddress)) {
|
||||
die("fi");
|
||||
}
|
||||
|
||||
if (fat12_readfile("POLMON COM", kPolmonAddress)) {
|
||||
die("pnf");
|
||||
while (fat12_readfile("POLIO COM", kPolmonAddress)) {
|
||||
asm volatile("mov $00, %%ah \n\t"
|
||||
"int $0x16 \n\t" ::
|
||||
: "ax");
|
||||
}
|
||||
|
||||
jump(kPolmonAddress);
|
||||
}
|
||||
|
||||
int main() {
|
||||
loadpolmon();
|
||||
}
|
||||
int main() { loadpolmon(); }
|
||||
|
||||
20
flat1000.ld
Normal file
20
flat1000.ld
Normal file
@@ -0,0 +1,20 @@
|
||||
SECTIONS {
|
||||
. = 0x1000;
|
||||
|
||||
.text : {
|
||||
KEEP(*(.init))
|
||||
*(.text*)
|
||||
}
|
||||
|
||||
.rodata : {
|
||||
*(.rodata*)
|
||||
}
|
||||
|
||||
.bss (NOLOAD) : {
|
||||
* (.bss)
|
||||
}
|
||||
|
||||
.data : {
|
||||
*(.data)
|
||||
}
|
||||
}
|
||||
80
paracli.s
Normal file
80
paracli.s
Normal 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
124
paracomm.c
Normal 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
19
paracomm.h
Normal 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
189
polio.s
Normal 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
|
||||
277
polmon.cc
277
polmon.cc
@@ -1,4 +1,5 @@
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
|
||||
#ifndef WOZMON
|
||||
#define WOZMON 0
|
||||
@@ -8,7 +9,7 @@
|
||||
#define BACKSPACE 0
|
||||
#define ASCIIDUMP 0
|
||||
#define CLEARSCREENCMD 0
|
||||
#define FARCALL 0
|
||||
#define INT80H 0
|
||||
#define SHOWTITLE 0
|
||||
#define BOOTSTRAP 0
|
||||
#endif // WOZMON
|
||||
@@ -25,8 +26,8 @@
|
||||
#define CLEARSCREENCMD 1
|
||||
#endif
|
||||
|
||||
#ifndef FARCALL
|
||||
#define FARCALL 1
|
||||
#ifndef INT80H
|
||||
#define INT80H 1
|
||||
#endif
|
||||
|
||||
#ifndef SHOWTITLE
|
||||
@@ -39,69 +40,54 @@
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int kDumpSize = 16;
|
||||
#if WOZMON
|
||||
|
||||
uint8_t getc() {
|
||||
register uint8_t c asm ("al");
|
||||
asm volatile (
|
||||
"movb $0x00, %%ah\n\t"
|
||||
"int $0x16"
|
||||
: "=r" (c)
|
||||
:: "ah", "cc"
|
||||
);
|
||||
int getchar() {
|
||||
register char 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 (
|
||||
"push %%bp \n\t"
|
||||
"movb %0, %%al \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"
|
||||
);
|
||||
void 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");
|
||||
}
|
||||
|
||||
void puts(const char* s) {
|
||||
while (*s) {
|
||||
putc(*s++);
|
||||
}
|
||||
}
|
||||
#endif // WOZMON
|
||||
|
||||
constexpr int kDumpSize = 16;
|
||||
|
||||
// arguments on the stack in reverse order
|
||||
extern "C" uint16_t Jump(uint16_t addr, int nargs);
|
||||
asm (
|
||||
".section .text.Jump \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
|
||||
);
|
||||
extern "C" uint16_t Int80h(uint8_t fun, int nargs);
|
||||
asm(".section .text.Int80h \n"
|
||||
"Int80h: \n"
|
||||
" push %si \n"
|
||||
" push %bp \n"
|
||||
" mov %al, %ah \n"
|
||||
" mov %sp, %bp \n"
|
||||
" lea 6(%bp), %si \n" // 4 for pushed stuff, 2 for return addr
|
||||
"0: \n"
|
||||
" test %dx, %dx \n"
|
||||
" jz 1f \n"
|
||||
" push (%si) \n"
|
||||
" dec %dx \n"
|
||||
" add $2, %si \n"
|
||||
" jmp 0b \n"
|
||||
"1: \n"
|
||||
" int $0x80 \n"
|
||||
" mov %bp, %sp \n"
|
||||
" pop %bp \n"
|
||||
" pop %si \n"
|
||||
" ret"
|
||||
// return value in ax
|
||||
);
|
||||
|
||||
constexpr uint8_t kBackspace = 0x7f;
|
||||
constexpr uint8_t kOtherBackspace = 0x08;
|
||||
@@ -126,19 +112,15 @@ uint16_t ReadUintN(int n, const char* buf) {
|
||||
return out;
|
||||
}
|
||||
|
||||
uint8_t ReadUint8(const char* buf) {
|
||||
return ReadUintN(2, buf);
|
||||
}
|
||||
uint8_t ReadUint8(const char* buf) { return ReadUintN(2, buf); }
|
||||
|
||||
uint16_t ReadUint16(const char* buf) {
|
||||
return ReadUintN(4, buf);
|
||||
}
|
||||
uint16_t ReadUint16(const char* buf) { return ReadUintN(4, buf); }
|
||||
|
||||
void WriteHexNibble(uint8_t c) {
|
||||
if (c > 9) {
|
||||
putc('a' + c - 10);
|
||||
putchar('a' + c - 10);
|
||||
} 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) {
|
||||
register uint16_t ad asm ("si") = addr;
|
||||
register uint16_t sg asm ("ds") = seg;
|
||||
register uint8_t ret asm ("al");
|
||||
asm (
|
||||
"lodsb \n\t"
|
||||
: "=r" (ret)
|
||||
: "r" (ad), "r" (sg)
|
||||
);
|
||||
register uint16_t ad asm("si") = addr;
|
||||
register uint16_t sg asm("ds") = seg;
|
||||
register uint8_t ret asm("al");
|
||||
asm("lodsb \n\t" : "=r"(ret) : "r"(ad), "r"(sg));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __set_far_u8__(uint16_t addr, uint16_t seg, uint8_t val) {
|
||||
register uint16_t ad asm ("di") = addr;
|
||||
register uint16_t sg asm ("es") = seg;
|
||||
register uint8_t v asm ("al") = val;
|
||||
asm (
|
||||
"stosb \n\t"
|
||||
:: "r" (sg), "r" (ad), "r" (v)
|
||||
: "memory"
|
||||
);
|
||||
register uint16_t ad asm("di") = addr;
|
||||
register uint16_t sg asm("es") = seg;
|
||||
register uint8_t v asm("al") = val;
|
||||
asm("stosb \n\t" ::"r"(sg), "r"(ad), "r"(v) : "memory");
|
||||
}
|
||||
|
||||
__attribute__((noreturn))
|
||||
inline static void __basic__() {
|
||||
asm volatile (
|
||||
"movw $0x40, %ax \n\t"
|
||||
"mov %ax, %ds \n\t"
|
||||
"int $0x18"
|
||||
);
|
||||
__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, uint16_t seg, int count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
putc(' ');
|
||||
putchar(' ');
|
||||
uint8_t d = __get_far_u8__(addr + i, seg);
|
||||
WriteUint8(d);
|
||||
}
|
||||
#if ASCIIDUMP
|
||||
putc(' ');
|
||||
putc(' ');
|
||||
putchar(' ');
|
||||
putchar(' ');
|
||||
for (int i = 0; i < count; i++) {
|
||||
uint8_t d = __get_far_u8__(addr + i, seg);
|
||||
if (d > 31 && d < 127) {
|
||||
putc(d);
|
||||
putchar(d);
|
||||
} else {
|
||||
putc('.');
|
||||
putchar('.');
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -208,42 +179,38 @@ void Dump(uint16_t addr, uint16_t seg, int count) {
|
||||
void DumpHex(uint16_t addr, uint16_t seg) {
|
||||
addr &= -kDumpSize;
|
||||
|
||||
putc('[');
|
||||
putchar('[');
|
||||
WriteUint16(seg);
|
||||
putc(':');
|
||||
putchar(':');
|
||||
WriteUint16(addr);
|
||||
putc(']');
|
||||
putc(':');
|
||||
putchar(']');
|
||||
putchar(':');
|
||||
Dump(addr, seg, kDumpSize);
|
||||
putc('\r');
|
||||
putc('\n');
|
||||
putchar('\r');
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void ClearScreen() {
|
||||
asm volatile (
|
||||
"movw $0x0002, %%ax \n\t"
|
||||
"int $0x10"
|
||||
::: "ax", "cc"
|
||||
);
|
||||
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"
|
||||
);
|
||||
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 %1 \n\t"
|
||||
"movb $0x02, %%ah \n\t"
|
||||
"movw %%di, %%dx \n\t"
|
||||
"int $0x10" ::"rm"(status),
|
||||
"l"(WriteUint8)
|
||||
: "ax", "bh", "dx", "cx", "di", "cc");
|
||||
}
|
||||
|
||||
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;) {
|
||||
if (*ptr == 's') {
|
||||
cur_addr = 0;
|
||||
cur_seg = ReadUint16(ptr+1);
|
||||
cur_seg = ReadUint16(ptr + 1);
|
||||
ptr += 5;
|
||||
} else if (*ptr == '$') {
|
||||
__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;
|
||||
#if FARCALL
|
||||
int nargs = 0;
|
||||
ptr++;
|
||||
int fun = ReadUint8(ptr);
|
||||
ptr += 2;
|
||||
for (; *ptr;) {
|
||||
if (*ptr == ' ') {
|
||||
ptr++;
|
||||
continue;
|
||||
}
|
||||
uint16_t d = ReadUint16(ptr);
|
||||
asm volatile ("push %0" :: "r" (d));
|
||||
asm volatile("push %0" ::"r"(d));
|
||||
nargs++;
|
||||
ptr += 4;
|
||||
}
|
||||
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++;
|
||||
uint16_t ret = Int80h(fun, nargs);
|
||||
asm volatile("shl %0 \n\t"
|
||||
"add %0, %%sp" ::"r"(nargs));
|
||||
WriteUint16(ret);
|
||||
putchar('\r');
|
||||
putchar('\n');
|
||||
#endif // INT80H
|
||||
#if CLEARSCREENCMD
|
||||
} else if (*ptr == 'l') {
|
||||
dump = false;
|
||||
@@ -311,7 +282,10 @@ bool ParseCommand(const char* buf, uint16_t& cur_addr, uint16_t& cur_seg) {
|
||||
return dump;
|
||||
}
|
||||
|
||||
const char* prompt = "> ";
|
||||
void DisplayPrompt() {
|
||||
putchar('>');
|
||||
putchar(' ');
|
||||
}
|
||||
|
||||
void polmon() {
|
||||
uint16_t cur_addr = 0;
|
||||
@@ -321,14 +295,14 @@ void polmon() {
|
||||
char* inptr = inbuf;
|
||||
|
||||
ClearScreen();
|
||||
#if SHOWTITLE
|
||||
#if SHOWTITLE
|
||||
puts("PolMon 0.2\r\n");
|
||||
#endif // SHOWTITLE
|
||||
puts(prompt);
|
||||
DisplayPrompt();
|
||||
|
||||
while (1) {
|
||||
uint8_t c = getc();
|
||||
putc(c); // echo
|
||||
uint8_t c = getchar();
|
||||
putchar(c); // echo
|
||||
if (c == '\r') {
|
||||
*inptr = 0;
|
||||
if (inbuf[0] == 0) {
|
||||
@@ -336,7 +310,7 @@ void polmon() {
|
||||
cur_addr += kDumpSize;
|
||||
}
|
||||
} else {
|
||||
putc('\n');
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
if (ParseCommand(inbuf, cur_addr, cur_seg)) {
|
||||
@@ -344,17 +318,17 @@ void polmon() {
|
||||
};
|
||||
first = false;
|
||||
inptr = inbuf;
|
||||
puts(prompt);
|
||||
DisplayPrompt();
|
||||
#if BACKSPACE
|
||||
} else if (c == kBackspace || c == kOtherBackspace) {
|
||||
inptr--;
|
||||
if (inptr < inbuf) {
|
||||
inptr = inbuf;
|
||||
putc(' ');
|
||||
putchar(' ');
|
||||
continue;
|
||||
}
|
||||
putc(' ');
|
||||
putc(kOtherBackspace);
|
||||
putchar(' ');
|
||||
putchar(kOtherBackspace);
|
||||
#endif
|
||||
} else {
|
||||
*inptr = c;
|
||||
@@ -365,13 +339,10 @@ void polmon() {
|
||||
|
||||
} // namespace
|
||||
|
||||
int main() {
|
||||
polmon();
|
||||
}
|
||||
int main() { polmon(); }
|
||||
|
||||
#if BOOTSTRAP
|
||||
__attribute__((section(".init"), noreturn, used))
|
||||
void _start() {
|
||||
__attribute__((section(".init"), noreturn, used)) void _start() {
|
||||
main();
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
10
readio.asm
Normal file
10
readio.asm
Normal 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
25
stdlib.c
Normal 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
12
writeio.asm
Normal 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
|
||||
Reference in New Issue
Block a user