Skip to content

Commit

Permalink
document devices and add a command to the keyboard
Browse files Browse the repository at this point in the history
  • Loading branch information
MESYETI committed Nov 5, 2023
1 parent 84cc3a2 commit 82f0c5f
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 27 deletions.
8 changes: 0 additions & 8 deletions demos/tron.asm

This file was deleted.

35 changes: 35 additions & 0 deletions docs/devices.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Devices
YETI-16 has a few devices that you can control with the IO instructions (`IN`, `OUT`, `CHK`, `ACTV`)

## Common protocol
Devices operate by the program sending opcodes and operands through `OUT`

All devices have 1 opcode in common, which is 81 (or 0x51, or 'Q')

This opcode returns 51, and then a null terminated string containing the device's name

## Devices
### 0x00 - YETI-16 Debug Device
This device is for basic debug/testing, it can print to the console

#### Opcodes
- `P`/80/0x50 - Prints the operand to the console

### 0x01 - YETI-16 Keyboard
This device receives keyboard events and sends them to the console

It sends keyboard events through input in this format:
- Event type ('D' for key down)
- Key (ASCII)

You can also send commands to it to see what commands are currently pressed, in this format
- ASCII character `S`
- ASCII key you want to check
and then it returns data in this format
- ASCII character `S`
- 0xFFFF if the key is pressed, 0 if it isn't

### 0x02 YETI-16 Graphics Controller
This is a device for loading default palettes and fonts

The default palette can be loaded by sending the ASCII character `P`
2 changes: 1 addition & 1 deletion source/assembler/assembler.d
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class Assembler {
AddInstruction("jmpb", Opcode.JMPB, [Param.Addr]);
AddInstruction("jnzb", Opcode.JNZB, [Param.Addr]);
AddInstruction("chk", Opcode.CHK, [Param.Register]);
AddInstruction("ison", Opcode.ISON, [Param.Register]);
AddInstruction("actv", Opcode.ACTV, [Param.Register]);
AddInstruction("hlt", Opcode.HLT, []);
}

Expand Down
4 changes: 2 additions & 2 deletions source/computer.d
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ enum Opcode {
JMPB = 0x23,
JNZB = 0x24,
CHK = 0x25,
ISON = 0x26,
ACTV = 0x26,
HLT = 0xFF
}

Expand Down Expand Up @@ -571,7 +571,7 @@ class Computer {
a = device.data.length == 0? 0 : 0xFFFF;
break;
}
case Opcode.ISON: {
case Opcode.ACTV: {
auto dev = ReadReg(NextByte()) & 0xFF;

a = devices[dev] is null? 0 : 0xFFFF;
Expand Down
2 changes: 2 additions & 0 deletions source/devices/debug.d
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class Debug : Device {
else {
switch (dataIn) {
case 'Q': {
data ~= cast(ushort) 'Q';

foreach (ref ch ; name) {
data ~= cast(ushort) ch;
}
Expand Down
2 changes: 2 additions & 0 deletions source/devices/graphicsController.d
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class GraphicsController : Device {
override void Out(ushort dataIn) {
switch (dataIn) {
case 'Q': {
data ~= cast(ushort) 'Q';

foreach (ref ch ; name) {
data ~= cast(ushort) ch;
}
Expand Down
133 changes: 117 additions & 16 deletions source/devices/keyboard.d
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,78 @@ import std.string;
import bindbc.sdl;
import yeti16.deviceBase;

static SDL_Scancode[] CharToKeys(ushort ch) {
switch (ch) {
case '0': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_0];
case '1': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_1];
case '2': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_2];
case '3': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_3];
case '4': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_4];
case '5': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_5];
case '6': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_6];
case '7': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_7];
case '8': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_8];
case '9': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_9];
case 'A': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_A];
case 'B': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_B];
case 'C': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_C];
case 'D': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_D];
case 'E': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_E];
case 'F': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_F];
case 'G': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_G];
case 'H': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_H];
case 'I': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_I];
case 'J': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_J];
case 'K': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_K];
case 'L': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_L];
case 'M': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_M];
case 'N': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_N];
case 'O': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_O];
case 'P': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_P];
case 'Q': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_Q];
case 'R': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_R];
case 'S': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_S];
case 'T': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_T];
case 'U': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_U];
case 'V': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_V];
case 'W': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_W];
case 'X': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_X];
case 'Y': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_Y];
case 'Z': return [SDL_SCANCODE_LSHIFT, SDL_SCANCODE_Z];
case 'a': return [SDL_SCANCODE_A];
case 'b': return [SDL_SCANCODE_B];
case 'c': return [SDL_SCANCODE_C];
case 'd': return [SDL_SCANCODE_D];
case 'e': return [SDL_SCANCODE_E];
case 'f': return [SDL_SCANCODE_F];
case 'g': return [SDL_SCANCODE_G];
case 'h': return [SDL_SCANCODE_H];
case 'i': return [SDL_SCANCODE_I];
case 'j': return [SDL_SCANCODE_J];
case 'k': return [SDL_SCANCODE_K];
case 'l': return [SDL_SCANCODE_L];
case 'm': return [SDL_SCANCODE_M];
case 'n': return [SDL_SCANCODE_N];
case 'o': return [SDL_SCANCODE_O];
case 'p': return [SDL_SCANCODE_P];
case 'q': return [SDL_SCANCODE_Q];
case 'r': return [SDL_SCANCODE_R];
case 's': return [SDL_SCANCODE_S];
case 't': return [SDL_SCANCODE_T];
case 'u': return [SDL_SCANCODE_U];
case 'v': return [SDL_SCANCODE_V];
case 'w': return [SDL_SCANCODE_W];
case 'y': return [SDL_SCANCODE_Y];
case 'x': return [SDL_SCANCODE_X];
case 'z': return [SDL_SCANCODE_Z];
default: return [];
}
}

class Keyboard : Device {
ushort[] input;
bool waiting;

this() {
name = "YETI-16 Keyboard";
SDL_StartTextInput();
Expand All @@ -15,16 +86,55 @@ class Keyboard : Device {
}

override void Out(ushort dataIn) {
switch (dataIn) {
case 'Q': {
foreach (ref ch ; name) {
data ~= cast(ushort) ch;
if (waiting) {
char op = cast(char) input[0];

switch (op) {
case 'S': {
auto keys = CharToKeys(dataIn);

if (keys.length == 0) {
data ~= 0;
return;
}

auto keystate = SDL_GetKeyboardState(null);

bool ret = true;
foreach (ref key ; keys) {
if (!keystate[key]) {
ret = false;
break;
}
}

data ~= ret? 0xFFFF : 0;
waiting = false;
input = [];
break;
}
default: assert(0);
}
}
else {
switch (dataIn) {
case 'Q': {
data ~= cast(ushort) 'Q';

foreach (ref ch ; name) {
data ~= cast(ushort) ch;
}

data ~= 0;
break;
data ~= 0;
break;
}
case 'S': {
waiting = true;
input ~= cast(ushort) 'S';
break;
}
default: break;
}
default: break;
}
}

Expand Down Expand Up @@ -56,15 +166,6 @@ class Keyboard : Device {
}
break;
}
case SDL_KEYUP: {
auto key = KeycodeChar(e.key.keysym.scancode);

if (key != 0) {
data ~= cast(ushort) 'U';
data ~= cast(ushort) key;
}
break;
}
case SDL_TEXTINPUT: {
string text = cast(string) e.text.text.fromStringz();

Expand Down

0 comments on commit 82f0c5f

Please sign in to comment.