Skip to content

Instantly share code, notes, and snippets.

@evost
Last active August 17, 2018 21:28
Show Gist options
  • Save evost/8492b871c24f556e843eb2e148c90016 to your computer and use it in GitHub Desktop.
Save evost/8492b871c24f556e843eb2e148c90016 to your computer and use it in GitHub Desktop.
| номер | команда | тип первого аргумента | тип второго аргумента | пояснение |
| ----- | ------- | --------------------- | --------------------- | -----------------------------------------|
| 0 | nop | - | - | ничего не делать |
| 1 | ret | - | - | выход из подпрограммы |
| 2 | clf | - | - | закрыть открытый файл |
| 3 | end | - | - | завершает программу |
| 4 | clr | - | - | очистить экран и установить X=0, Y=0 |
| 5 | xch | var1 | var2 | swap(var1, var2) |
| 6 | add | var1 | var2/num | var1 += var2 |
| 7 | sub | var1 | var2/num | var1 -= var2 |
| 8 | mul | var1 | var2/num | var1 *= var2 |
| 9 | div | var1 | var2/num | var1 /= var2 |
| 10 | mod | var1 | var2/num | var1 %= var2 |
| 11 | pow | var1 | var2/num | var1 = var1 ^ var2 |
| 12 | mov | var1 | var2/num | var1 = var2 |
| 13 | orl | var1 | var2/num | var1 |= var2 |
| 14 | and | var1 | var2/num | var1 &= var2 |
| 15 | not | var1 | var2/num | var1 ~= var2 |
| 16 | xor | var1 | var2/num | var1 ^= var2 |
| 17 | neg | var1 | var2/num | var1 = -var2 |
| 18 | rol | var1 | var2/num | var1 = var1 << var2 + var1 >> (16 - var2)|
| 19 | ror | var1 | var2/num | var1 = var1 >> var2 + var1 << (16 - var2)|
| 20 | shl | var1 | var2/num | var1 = var1 << var2 |
| 21 | shr | var1 | var2/num | var1 = var1 >> var2 |
| 22 | rnd | var1 | var2/num | var1 = random(var2) |
| 23 | rci | var1 | var2/num | считать с консоли var2 целых |
| 24 | rcc | var1 | var2/num | считать с консоли var2 символов |
| 25 | wci | var1 | var2/num | вывести в консоль var2 целых |
| 26 | wcc | var1 | var2/num | вывести в консоль var2 символов |
| 27 | rfi | var1 | var2/num | считать с файла var2 целых |
| 28 | rfc | var1 | var2/num | считать с файла var2 символов |
| 29 | wfi | var1 | var2/num | вывести в файл var2 целых |
| 30 | wfc | var1 | var2/num | вывести в файл var2 символов |
| 31 | rdd | var1 | var2/num | var1 = digitalRead(var2) |
| 32 | rda | var1 | var2/num | var1 = analogRead(var2) |
| 33 | wfd | var1 | var2/num | digitalWrite(var1, var2) |
| 34 | wfa | var1 | var2/num | analogWrite(var1, var2) |
| 35 | wsd | var1 | var2/num | digitalWrite(var2, var1) |
| 36 | wsa | var1 | var2/num | analogWrite(var2, var1) |
| 37 | stx | var1/num | - | cursorX = var1 * LCD.getFontXsize() |
| 38 | sty | var1/num | - | cursorY = var1 * LCD.getFontYsize() |
| 39 | stc | var1/num | - | устанавливает цвет фона и курсора |
| 40 | pni | var1/num | - | pinMode(var1, INPUT) |
| 41 | pno | var1/num | - | pinMode(var1, OUTPUT) |
| 42 | wsr | var1/num | - | Serial.Write(var1) |
| 43 | rsr | var1 | - | var1 = Serial.Read() |
| 44 | inc | var1 | - | var1++ |
| 45 | dec | var1 | - | var1-- |
| 46 | ofr | var1 | - | открыть файл на чтение |
| 47 | ofw | var1 | - | открыть файл на запись |
| 48 | ofa | var1 | - | открыть файл на дополнение |
| 49 | mkd | var1 | - | создать каталог |
| 50 | rmd | var1 | - | удалить каталог |
| 51 | rmf | var1 | - | удалить файл |
| 52 | ife | var1 | lab | если равно нулю перейти по метке |
| 53 | ifn | var1 | lab | если не равно нулю перейти по метке |
| 54 | ifb | var1 | lab | если больше нуля перейти по метке |
| 55 | ifs | var1 | lab | если меньше нуля перейти по метке |
| 56 | jmp | lab | - | безусловный переход по метке lab |
| 57 | cal | lab | - | вызвать подпрограмму по метке lab |
| ----- | ------- | --------------------- | --------------------- | -----------------------------------------|
| 58 | lab | new_lab | - | объявление метки new_lab |
| 59 | prс | new_lab | - | объявление подпрограммы new_lab |
| 60 | dat | new_var | num | объявление массива из num>0 целых |
#include <iostream>
#include <string>
#include <fstream>
#include <map>
#include <algorithm>
#include <regex>
using namespace std;
uint8_t current_var = 0;
uint16_t current_str = 0;
uint16_t p_size = 0;
ofstream outf;
map <string, uint8_t> var_names;
map <string, uint16_t> label_names;
map <string, uint8_t> coms = {
{ "nop", 0 },
{ "ret", 1 },
{ "clf", 2 },
{ "end", 3 },
{ "rst", 4 },
{ "clr", 5 },
{ "xch", 6 },
{ "add", 7 },
{ "sub", 8 },
{ "mul", 9 },
{ "div", 10 },
{ "mod", 11 },
{ "pow", 12 },
{ "mov", 13 },
{ "orl", 14 },
{ "and", 15 },
{ "not", 16 },
{ "xor", 17 },
{ "neg", 18 },
{ "rol", 19 },
{ "ror", 20 },
{ "shl", 21 },
{ "shr", 22 },
{ "rnd", 23 },
{ "rci", 24 },
{ "rcc", 25 },
{ "wci", 26 },
{ "wcc", 27 },
{ "rfi", 28 },
{ "rfc", 29 },
{ "wfi", 30 },
{ "wfc", 31 },
{ "rdd", 32 },
{ "rda", 33 },
{ "wfd", 34 },
{ "wfa", 35 },
{ "wsd", 36 },
{ "wsa", 37 },
{ "stx", 38 },
{ "sty", 39 },
{ "stс", 40 },
{ "pni", 41 },
{ "pno", 42 },
{ "wsr", 43 },
{ "rsr", 44 },
{ "inc", 45 },
{ "dec", 46 },
{ "ofr", 47 },
{ "ofw", 48 },
{ "ofa", 49 },
{ "mkd", 50 },
{ "rmd", 51 },
{ "rmf", 52 },
{ "ife", 53 },
{ "ifn", 54 },
{ "ifb", 55 },
{ "ifs", 56 },
{ "jmp", 57 },
{ "cal", 58 },
{ "lab", 59 },
{ "prс", 60 },
{ "dat", 61 }
};
map <uint8_t, string> errors = {
{0, "UNKNOWN COMMAND"},
{1, "BAD NEW VARIABLE"},
{2, "VARIABLES OVERFLOW"},
{3, "BAD NEW LABEL"},
{4, "UNNECESSARY ARGUMENT"},
{5, "PROGRAM SIZE OVERFLOW"},
{6, "UNKNOWN SYMBOL"},
{7, "UNKNOWN VARIABLE"},
{8, "BAD VARIABLE"},
{9, "UNKNOWN LABEL"}
};
bool is_number(string s) {
if (s.length() == 0)
return false;
uint8_t i = 0;
if (s[0] == '-') {
i++;
if (s.length() == 1)
return false;
}
for (; i < s.length(); i++)
if (!isdigit(s[i]))
return false;
return true;
}
void push_data(int8_t data) {
outf.put(data);
p_size++;
}
uint16_t get_lab_num(string s) {
if (label_names.find(s) == label_names.end() || s.length() == 0)
throw 9;
return label_names[s];
}
uint8_t get_var_num(string s) {
string var = "", index = "";
for (uint8_t i = 0; i < s.length(); i++)
if (s[i] != '[')
var += s[i];
else
for (i++; i < s.length(); i++)
if (s[i] != ']')
index += s[i];
else
if (i + 1 != s.length() || !is_number(index))
throw 8;
if (var_names.find(var) == var_names.end())
throw 7;
else
if (index.length() > 0)
return var_names[var] + stoi(index);
else
return var_names[var];
}
int8_t bigbits(int16_t i) {
i = i >> 8;
return (int8_t)i;
}
int8_t litbits(int16_t i) {
i = i << 8;
i = i >> 8;
return (int8_t)i;
}
void parse(string s) {
current_str++;
transform(s.begin(), s.end(), s.begin(), ::tolower);
s = regex_replace(s, regex("^ +| +$|( ) +"), "$1");
if (s.length() > 0) {
if (s[0] != ';') {
string op = "", arg1, arg2;
for (uint8_t i = 0; i < s.length(); i++)
if (!isspace(s[i]) && !isdigit(s[i]) && !isalpha(s[i]) && s[i] != '_' && s[i] != '[' && s[i] != ']' && s[i] != '-')
throw 6;
uint8_t i = 0;
for (; i < s.length() && !isspace(s[i]); i++)
op += s[i];
for (i++; i < s.length() && isspace(s[i]); i++) {};
for (; i < s.length() && !isspace(s[i]); i++)
arg1 += s[i];
for (i++; i < s.length() && isspace(s[i]); i++) {};
for (; i < s.length() && !isspace(s[i]); i++)
arg2 += s[i];
if (coms.find(op) != coms.end()) {
if (p_size >= 65536)
throw 5;
if (coms[op] <= coms["clr"]) {
if (arg1 != "" || arg2 != "")
throw 4;
push_data(coms[op]);
}
else if (coms[op] <= coms["xch"]) {
push_data(coms[op] + 128);
push_data(get_var_num(arg1));
push_data(get_var_num(arg2));
}
else if (coms[op] <= coms["wsa"]) {
if (is_number(arg2)) {
push_data(coms[op]);
push_data(get_var_num(arg1));
push_data(bigbits(stoi(arg2)));
push_data(litbits(stoi(arg2)));
}
else {
push_data(coms[op] + 128);
push_data(get_var_num(arg1));
push_data(get_var_num(arg2));
}
}
else if (coms[op] <= coms["wsr"]) {
if (arg2 != "")
throw 4;
if (is_number(arg1)) {
push_data(coms[op]);
push_data(bigbits(stoi(arg1)));
push_data(litbits(stoi(arg1)));
}
else {
push_data(coms[op] + 128);
push_data(get_var_num(arg1));
}
}
else if (coms[op] <= coms["rmf"]) {
if (arg2.length() != 0)
throw 4;
push_data(coms[op]);
push_data(get_var_num(arg1));
}
else if (coms[op] <= coms["ifs"]) {
push_data(coms[op]);
push_data(get_var_num(arg1));
push_data(bigbits(get_lab_num(arg2)));
push_data(litbits(get_lab_num(arg2)));
}
else if (coms[op] <= coms["cal"]) {
if (arg2.length() != 0)
throw 4;
push_data(coms[op]);
push_data(bigbits(get_lab_num(arg1)));
push_data(litbits(get_lab_num(arg1)));
}
else if (coms[op] <= coms["prc"]) {
if (!isalpha(arg1[0]) || label_names.find(arg1) != label_names.end() || label_names.size() == 4096)//why 4096
throw 3;
else label_names[arg1] = p_size;
}
else if (coms[op] <= coms["dat"]) {
if (!isalpha(arg1[0]) || !is_number(arg2) || var_names.find(arg1) != var_names.end())
throw 2;
if (current_var + stoi(arg2) > 255)
throw 1;
var_names[arg1] = current_var;
current_var += stoi(arg2);
}
cout << current_str << ": " << op << ' ' << arg1 << ' ' << arg2 << ' ' << '\n';
}
else
throw 0;
}
}
}
int main(int argc, char *argv[]) {
if (argc == 1)
return 0;
string buff = "", outname, name = argv[1];
try {
ifstream inpf(name);
outname = name;
outname[outname.length() - 3] = 'b';
outname[outname.length() - 2] = 'i';
outname[outname.length() - 1] = 'n';
outf = ofstream(outname, ios::out | ios::binary);
while (getline(inpf, buff))
parse(buff);
inpf.close();
outf.close();
cout << "DONE " << p_size << " BYTES, " << to_string(current_str) << " STRINGS, IN " << clock() / 1000.0 << " S" << '\n';
}
catch (int a) {
cout << errors[a] << ". LINE " << to_string(current_str) << ": " << buff << '\n';
}
catch (...) {
cout << "UNKNOWN ERROR. LINE " << to_string(current_str) << ": " << buff << '\n';
}
cin.get();
return 0;
}
#define ps2key_int_pin 3
#define ps2key_data_pin 4
#define pin_BL 5
#define pin_SD 6
#define exe_ok 0
#define exe_end 1
#define stack_overflow 2
#define division_by_zero 3
#define end_of_file 4
#define file_not_exist 5
#define opening_error 6
#define rewrite_error 7
#define off_by_one 8
#include <SD.h>
#include <UTFT.h>
#include <PS2Keyboard.h>
#include <Wire.h>
#include <RTClib.h>
#include <MemoryFree.h>
char exe_file_name[256];//текущий исполняемый файл, 255 для имени и пути и 1 для нуль-терминатора
char work_file_name[256];//файл, с которым работает программа (не больше 64 кбайт)
int8_t exe_code;//код, возвращаемый функцией обработки операции
int8_t delta = 0;//количество байт, на которое нужно перескочить после выполнения операции
int8_t data[4];//место для предварительной выгрузки из файла кода операции и трех следующих байт
uint8_t BL = 64;//яркость подсветки
int16_t registers[256];
uint16_t call_stack[255];//т.к. call не может быть больше 255
uint8_t call = 0;//номер следующей записи в стэк вызовов
uint16_t cursorY = 0;
uint16_t cursorX = 0;
char sTime[3];
File exe_file;
File work_file;
PS2Keyboard keyboard;
UTFT LCD(ILI9486, 38, 39, 40, 41);
RTC_DS3231 rtc;
extern uint8_t BigFont[];
const unsigned int VGA_COLORS[16] = {VGA_BLACK, VGA_WHITE, VGA_RED, VGA_GREEN, VGA_BLUE, VGA_SILVER, VGA_GRAY, VGA_MAROON, VGA_YELLOW, VGA_OLIVE, VGA_LIME, VGA_AQUA, VGA_TEAL, VGA_NAVY, VGA_FUCHSIA, VGA_PURPLE};
inline int16_t dbytes(const int8_t &a, const int8_t &b) {
return (((int16_t)a) << 8) + b;
}
void setc8(const char &k) {
char c[2] = {k, 0};
if ((cursorX > LCD.getDisplayXSize() - LCD.getFontXsize()) || k == '\n') {
cursorX = 0;
cursorY += LCD.getFontYsize();
if (cursorY > LCD.getDisplayYSize() - LCD.getFontYsize()) {
LCD.clrScr();
cursorY = 0;
}
} else if (k >= 32 && k != 127) {
LCD.print(c, cursorX, cursorY);
cursorX += LCD.getFontXsize();
}
}
void echo(const char* s, const uint8_t &len) {
for (uint8_t i = 0; i < len; i++)
setc8(s[i]);
}
void echoln(const char* s, const uint8_t &len) {
echo(s, len);
setc8('\n');
}
void setc16(const int16_t &k) {
char s[6];
itoa(k, s, 10);
echo(s, strlen(s));
}
void setf8(const int8_t &u) {
work_file.write(u);
}
void setf16(const int16_t &u) {
setf8(u >> 8);
setf8((u << 8) >> 8);
}
void getstr(char* str, const uint8_t &len = 255) { //len - длинна строки без нулевого символа
echo("> ", 2);
uint8_t i = 0, buf;
while (buf != PS2_ENTER) {
while (!keyboard.available());
buf = keyboard.read();
if (buf >= 32 && buf != PS2_DELETE && i < len) {
str[i++] = buf;
setc8(buf);
} else if (buf == PS2_DELETE) {
if (i > 0) {
str[i] = ' ';
i--;
cursorX -= LCD.getFontXsize();
setc8(' ');
cursorX -= LCD.getFontXsize();
}
} else {
str[i] = 0;
cursorY += LCD.getFontYsize();
cursorX = 0;
if (cursorY > LCD.getDisplayYSize() - LCD.getFontYsize()) {
LCD.clrScr();
cursorY = 0;
}
break;
}
}
while (keyboard.available())
keyboard.read();
}
void getc16(int16_t &u) {
char s[6];
getstr(s, 5);
u = (int16_t)atoi(s);
}
void getc8(int16_t &u) {
char s[2];
getstr(s, 1);
u = s[0];
}
void getf8(int16_t &u) {
if (work_file.available())
u = work_file.read();
else
u = 0;
}
void getf16(int16_t &u) {//если остался один байт в файле - вернет его как старший!
int16_t a, b;
getf8(a);
getf8(b);
u = dbytes(a, b);
}
uint8_t exe() {
int8_t opcode = data[0];
int16_t swpbuf;
if (opcode > 128)
opcode -= 128;
delta = 0;
switch (opcode) {
case 0:
delta = 1;
break;
case 1:
if (call == 0)
return off_by_one;
call--;
exe_file.seek(call_stack[call]);
break;
case 2:
work_file.close();
delta = 1;
break;
case 3:
return exe_end;
break;
case 4:
LCD.clrScr();
cursorX = 0;
cursorY = 0;
break;
case 5:
swpbuf = registers[data[1]];
registers[data[1]] = registers[data[2]];
registers[data[2]] = swpbuf;
delta = 3;
break;
case 6:
if (data[0] >= 128) {
registers[data[1]] += registers[data[2]];
delta = 3;
} else {
registers[data[1]] += dbytes(data[2], data[3]);
delta = 4;
}
break;
case 7:
if (data[0] >= 128) {
registers[data[1]] -= registers[data[2]];
delta = 3;
} else {
registers[data[1]] -= dbytes(data[2], data[3]);
delta = 4;
}
break;
case 8:
if (data[0] >= 128) {
registers[data[1]] *= registers[data[2]];
delta = 3;
} else {
registers[data[1]] *= dbytes(data[2], data[3]);
delta = 4;
}
break;
case 9:
if (data[0] >= 128) {
if (registers[data[2]] == 0)
return division_by_zero;
registers[data[1]] /= registers[data[2]];
delta = 3;
} else {
if (dbytes(data[2], data[3] == 0))
return division_by_zero;
registers[data[1]] /= dbytes(data[2], data[3]);
delta = 4;
}
break;
case 10:
if (data[0] >= 128) {
if (registers[data[2]] == 0)
return division_by_zero;
registers[data[1]] %= registers[data[2]];
delta = 3;
} else {
if (dbytes(data[2], data[3] == 0))
return division_by_zero;
registers[data[1]] %= dbytes(data[2], data[3]);
delta = 4;
}
break;
case 11:
if (data[0] >= 128) {
registers[data[1]] = pow(registers[data[1]], registers[data[2]]);
delta = 3;
} else {
registers[data[1]] = pow(registers[data[1]], dbytes(data[2], data[3]));
delta = 4;
}
break;
case 12:
if (data[0] >= 128) {
registers[data[1]] = registers[data[2]];
delta = 3;
} else {
registers[data[1]] = dbytes(data[2], data[3]);
delta = 4;
}
break;
case 13:
if (data[0] >= 128) {
registers[data[1]] |= registers[data[2]];
delta = 3;
} else {
registers[data[1]] |= dbytes(data[2], data[3]);
delta = 4;
}
break;
case 14:
if (data[0] >= 128) {
registers[data[1]] &= registers[data[2]];
delta = 3;
} else {
registers[data[1]] &= dbytes(data[2], data[3]);
delta = 4;
}
break;
case 15:
if (data[0] >= 128) {
registers[data[1]] = ~registers[data[2]];
delta = 3;
} else {
registers[data[1]] = ~dbytes(data[2], data[3]);
delta = 4;
}
break;
case 16:
if (data[0] >= 128) {
registers[data[1]] ^= registers[data[2]];
delta = 3;
} else {
registers[data[1]] ^= dbytes(data[2], data[3]);
delta = 4;
}
break;
case 17:
if (data[0] >= 128) {
registers[data[1]] = -registers[data[2]];
delta = 3;
} else {
registers[data[1]] = -dbytes(data[2], data[3]);
delta = 4;
}
break;
case 18:
if (data[0] >= 128) {
registers[data[1]] = (registers[data[1]] << (registers[data[2]] % 16)) + (registers[data[1]] >> (16 - registers[data[2]] % 16));
delta = 3;
} else {
registers[data[1]] = (registers[data[1]] << (dbytes(data[2], data[3]) % 16)) + (registers[data[1]] >> (16 - dbytes(data[2], data[3]) % 16));
delta = 4;
}
break;
case 19:
if (data[0] >= 128) {
registers[data[1]] = (registers[data[1]] >> (registers[data[2]] % 16)) + (registers[data[1]] << (16 - registers[data[2]] % 16));
delta = 3;
} else {
registers[data[1]] = (registers[data[1]] >> (dbytes(data[2], data[3]) % 16)) + (registers[data[1]] << (16 - dbytes(data[2], data[3]) % 16));
delta = 4;
}
break;
case 20:
if (data[0] >= 128) {
registers[data[1]] = registers[data[1]] << registers[data[2]];
delta = 3;
} else {
registers[data[1]] = registers[data[1]] << dbytes(data[2], data[3]);
delta = 4;
}
break;
case 21:
if (data[0] >= 128) {
registers[data[1]] = registers[data[1]] >> registers[data[2]];
delta = 3;
} else {
registers[data[1]] = registers[data[1]] >> dbytes(data[2], data[3]);
delta = 4;
}
break;
case 22:
if (data[0] >= 128) {
registers[data[1]] = random(registers[data[2]]);
delta = 3;
} else {
registers[data[1]] = random(dbytes(data[2], data[3]));
delta = 4;
}
break;
case 23:
if (data[0] >= 128) {
for (int i = 0; i < registers[data[2]]; i++)
getc16(registers[data[1] + i]);
delta = 3;
} else {
for (int i = 0; i < dbytes(data[2], data[3]); i++)
getc16(registers[data[1] + i]);
delta = 4;
}
break;
case 24:
if (data[0] >= 128) {
for (int i = 0; i < registers[data[2]]; i++)
getc8(registers[data[1] + i]);
delta = 3;
} else {
for (int i = 0; i < dbytes(data[2], data[3]); i++)
getc8(registers[data[1] + i]);
delta = 4;
}
break;
case 25:
if (data[0] >= 128) {
for (int i = 0; i < registers[data[2]]; i++)
setc16(registers[data[1] + i]);
delta = 3;
} else {
for (int i = 0; i < dbytes(data[2], data[3]); i++)
setc16(registers[data[1] + i]);
delta = 4;
}
break;
case 26:
if (data[0] >= 128) {
for (int i = 0; i < registers[data[2]]; i++)
setc8(registers[data[1] + i]);
delta = 3;
} else {
for (int i = 0; i < dbytes(data[2], data[3]); i++)
setc8(registers[data[1] + i]);
delta = 4;
}
break;
case 27:
if (work_file.available()) {
if (data[0] >= 128) {
for (int i = 0; i < registers[data[2]]; i++)
getf16(registers[data[1] + i]);
delta = 3;
} else {
for (int i = 0; i < dbytes(data[2], data[3]); i++)
getf16(registers[data[1] + i]);
delta = 4;
}
} else
return end_of_file;
break;
case 28:
if (work_file.available()) {
if (data[0] >= 128) {
for (int i = 0; i < registers[data[2]]; i++)
getf8(registers[data[1] + i]);
delta = 3;
} else {
for (int i = 0; i < dbytes(data[2], data[3]); i++)
getf8(registers[data[1] + i]);
delta = 4;
}
} else
return end_of_file;
break;
case 29:
if (data[0] >= 128) {
for (int i = 0; i < registers[data[2]]; i++)
setf16(registers[data[1] + i]);
delta = 3;
} else {
for (int i = 0; i < dbytes(data[2], data[3]); i++)
setf16(registers[data[1] + i]);
delta = 4;
}
break;
case 30:
if (data[0] >= 128) {
for (int i = 0; i < registers[data[2]]; i++)
setf8(registers[data[1] + i]);
delta = 3;
} else {
for (int i = 0; i < dbytes(data[2], data[3]); i++)
setf8(registers[data[1] + i]);
delta = 4;
}
break;
case 31:
if (data[0] >= 128) {
registers[data[1]] = digitalRead(registers[data[2]]);
delta = 3;
} else {
registers[data[1]] = digitalRead(dbytes(data[2], data[3]));
delta = 4;
}
break;
case 32:
if (data[0] >= 128) {
registers[data[1]] = analogRead(registers[data[2]]);
delta = 3;
} else {
registers[data[1]] = analogRead(dbytes(data[2], data[3]));
delta = 4;
}
break;
case 33:
if (data[0] >= 128) {
digitalWrite(registers[data[1]], registers[data[2]]);
delta = 3;
} else {
digitalWrite(registers[data[1]], dbytes(data[2], data[3]));
delta = 4;
}
break;
case 34:
if (data[0] >= 128) {
analogWrite(registers[data[1]], registers[data[2]]);
delta = 3;
} else {
analogWrite(registers[data[1]], dbytes(data[2], data[3]));
delta = 4;
}
break;
case 35:
if (data[0] >= 128) {
digitalWrite(registers[data[2]], registers[data[1]]);
delta = 3;
} else {
digitalWrite(dbytes(data[2], data[3]), registers[data[1]]);
delta = 4;
}
break;
case 36:
if (data[0] >= 128) {
analogWrite(registers[data[2]], registers[data[1]]);
delta = 3;
} else {
analogWrite(dbytes(data[2], data[3]), registers[data[1]]);
delta = 4;
}
break;
case 37:
if (data[0] >= 128) {
cursorX = registers[data[1]] * LCD.getFontXsize();
delta = 3;
} else {
cursorX = dbytes(data[1], data[2]) * LCD.getFontXsize();
delta = 4;
}
break;
case 38:
if (data[0] >= 128) {
cursorY = registers[data[1]] * LCD.getFontYsize();
delta = 3;
} else {
cursorY = dbytes(data[1], data[2]) * LCD.getFontYsize();
delta = 4;
}
break;
case 39:
if (data[0] >= 128) {
LCD.setBackColor(VGA_COLORS[(registers[data[1]] >> 8) % 16]);
LCD.setColor(VGA_COLORS[((registers[data[1]] << 8) >> 8) % 16]);
delta = 3;
} else {
LCD.setBackColor(VGA_COLORS[(dbytes(data[1], data[2]) >> 8) % 16]);
LCD.setColor(VGA_COLORS[((dbytes(data[1], data[2]) << 8) >> 8) % 16]);
delta = 4;
}
break;
case 40:
if (data[0] >= 128) {
pinMode(registers[data[1]], OUTPUT);
delta = 3;
} else {
pinMode(dbytes(data[1], data[2]), OUTPUT);
delta = 4;
}
break;
case 41:
if (data[0] >= 128) {
pinMode(registers[data[1]], INPUT);
delta = 3;
} else {
pinMode(dbytes(data[1], data[2]), INPUT);
delta = 4;
}
break;
case 42:
if (data[0] >= 128) {
Serial.write(registers[data[1]]);
delta = 3;
} else {
Serial.write(dbytes(data[1], data[2]));
delta = 4;
}
break;
case 43:
registers[data[1]] = Serial.read();
delta = 2;
break;
case 44:
registers[data[1]] = registers[data[1]] + 1;
delta = 2;
break;
case 45:
registers[data[1]] = registers[data[1]] - 1;
delta = 2;
break;
case 46:
for (int8_t i = 0; i < 256; i++) {
work_file_name[i] = registers[data[1] + i];
if (registers[data[1] + i] == 0)
break;
}
if (!SD.exists(work_file_name))
return file_not_exist;
work_file = SD.open(work_file_name, FILE_READ);
if (!work_file)
return opening_error;
delta = 2;
break;
case 47:
for (int8_t i = 0; i < 256; i++) {
work_file_name[i] = registers[data[1] + i];
if (registers[data[1] + i] == 0)
break;
}
if (SD.exists(work_file_name) && !SD.remove(work_file_name))
return rewrite_error;
work_file = SD.open(work_file_name, FILE_WRITE);
if (!work_file)
return opening_error;
delta = 2;
break;
case 48:
for (int8_t i = 0; i < 256; i++) {
work_file_name[i] = registers[data[1] + i];
if (registers[data[1] + i] == 0)
break;
}
work_file = SD.open(work_file_name, FILE_WRITE);
if (!work_file)
return opening_error;
delta = 2;
break;
case 49:
for (int8_t i = 0; i < 256; i++) {
work_file_name[i] = registers[data[1] + i];
if (registers[data[1] + i] == 0)
break;
}
SD.mkdir(work_file_name);
break;
case 50:
for (int8_t i = 0; i < 256; i++) {
work_file_name[i] = registers[data[1] + i];
if (registers[data[1] + i] == 0)
break;
}
SD.rmdir(work_file_name);
break;
case 51:
for (int8_t i = 0; i < 256; i++) {
work_file_name[i] = registers[data[1] + i];
if (registers[data[1] + i] == 0)
break;
}
SD.remove(work_file_name);
break;
case 52:
if (registers[data[1]] == 0)
exe_file.seek(dbytes(data[2], data[3]));
else
delta = 4;
break;
case 53:
if (registers[data[1]] != 0)
exe_file.seek(dbytes(data[2], data[3]));
else
delta = 4;
break;
case 54:
if (registers[data[1]] > 0)
exe_file.seek(dbytes(data[2], data[3]));
else
delta = 4;
break;
case 55:
if (registers[data[1]] < 0)
exe_file.seek(dbytes(data[2], data[3]));
else
delta = 4;
break;
case 56:
exe_file.seek(dbytes(data[1], data[2]));
break;
case 57:
if (call == 255)
return stack_overflow;
call_stack[call] = exe_file.position();
exe_file.seek(dbytes(data[1], data[2]));
call++;
break;
default:
return data[0];
break;
}
return exe_ok;
}
void printDirectory(File dir, int numTabs) {
while (true) {
File entry = dir.openNextFile();
if (! entry)
break;
for (int8_t i = 0; i < numTabs; i++)
setc8('-');
echo(entry.name(), strlen(entry.name()));
if (entry.isDirectory()) {
setc8('/');
setc8('\n');
printDirectory(entry, numTabs + 1);
} else {
echo(" ", 4);
setc16(entry.size());
setc8('\n');
}
entry.close();
}
}
void nano() {
File edit;
char text_buf[128][16], t;
for (uint8_t ti = 0; ti <= 127; ti++)
for (uint8_t tk = 0; tk <= 15; tk++)
text_buf[ti][tk] = 0;
int8_t i = 0, k = 0, page = 0;//i-тая строка, k-ый символ
if (SD.exists(exe_file_name)) {
edit = SD.open(exe_file_name, FILE_READ);
while (edit.available() && i <= 127) {
text_buf[i][k] = edit.read();
if (text_buf[i][k] == '\n' || text_buf[i][k] == 0) {
text_buf[i][k] = 0;
k = 0;
i++;
} else if (text_buf[i][k] == '\r')
text_buf[i][k] = 0;
else
k++;
if (k == 15) {
text_buf[i][k] = 0;
k = 0;
i++;
}
}
edit.close();
}
cursorX = 0;
cursorY = LCD.getFontYsize();
i = 0;
k = 0;
bool refresh = true;
while (t != PS2_ESC) {
if (k >= 15) {
text_buf[page * 16 + i][15] = 0;
k = 0;
i++;
}
if (k < 0) {
k = 0;
i--;
}
if (i > 15 || i < 0 || refresh) {
if (i < 0)
page--;
else if (i > 15)
page++;
if (!refresh) {
k = 0;
i = 0;
}
refresh = false;
if (page > 15)
page = 15;
if (page < 0)
page = 0;
LCD.clrScr();
cursorX = 0;
cursorY = 0;
echo("ESC-exit TAB-save PAGE=", 23);
setc16(page);
setc8('\n');
setc8('\n');
for (uint8_t x = 0; x <= 15; x++)
for (uint8_t y = 0; y <= 15; y++)
if (text_buf[page * 16 + x][y] == 0) {
setc8('\n');
y = 16;
}
else
setc8(text_buf[page * 16 + x][y]);
}
cursorX = k * LCD.getFontXsize();
cursorY = (i + 2) * LCD.getFontYsize();
setc8('_');
cursorX -= LCD.getFontXsize();
while (!keyboard.available());
t = keyboard.read();
if (t == PS2_TAB) {
SD.remove(exe_file_name);
edit = SD.open(exe_file_name, FILE_WRITE);
for (uint8_t ti = 0; ti <= 127; ti++)
for (uint8_t tk = 0; tk <= 15; tk++)
if (text_buf[ti][tk] != 0)
edit.write(text_buf[ti][tk]);
else {
if (tk != 0 || text_buf[ti - 1][0] != 0)
edit.write('\n');
tk = 16;
}
edit.close();
} else if (t == PS2_ENTER) {
setc8(text_buf[page * 16 + i][k]);
i++;
if (text_buf[127][0] == 0) {
for (int8_t ti = 127; ti >= i + 1; ti--)
for (int8_t tk = 15; tk >= 0; tk--)
text_buf[ti][tk] = text_buf[ti - 1][tk];
for (int8_t tk = 0; tk < 15 - k; tk++) {
text_buf[i][tk] = text_buf[i - 1][k + tk + 1];
text_buf[i - 1][k + tk + 1] = 0;
}
for (int8_t tk = 15 - k; tk <= 15; tk++)
text_buf[i][tk] = 0;
refresh = true;
}
k = 0;
} else if (t == PS2_DELETE){
if (text_buf[page * 16 + i][0] == 0) {
for (int8_t ti = i; ti <= 126; ti++)
for (int8_t tk = 0; tk <= 15; tk++)
text_buf[ti][tk] = text_buf[ti + 1][tk];
for (int8_t tk = 0; tk <= 15; tk++)
text_buf[127][tk] = 0;
refresh = true;
} else if (k > 0) {
cursorX -= LCD.getFontXsize();
for (int8_t tk = k; tk <= 15; tk++) {
text_buf[i][tk - 1] = text_buf[i][tk];
setc8(text_buf[i][tk]);
}
k--;
}
} else if (t == PS2_RIGHTARROW){
setc8(text_buf[page * 16 + i][k]);
if (text_buf[page * 16 + i][k] != 0) {
k++;
} else {
k = 0;
i++;
}
} else if (t == PS2_LEFTARROW){
setc8(text_buf[page * 16 + i][k]);
k--;
} else if (t == PS2_DOWNARROW){
setc8(text_buf[page * 16 + i][k]);
i++;
k = 0;
} else if (t == PS2_UPARROW){
setc8(text_buf[page * 16 + i][k]);
i--;
k = 0;
} else if (t == PS2_PAGEDOWN){
i = 16;
k = 0;
} else if (t == PS2_PAGEUP){
i = -1;
k = 0;
} else if (text_buf[i][14] == 0) {
for (int8_t tk = 14; tk > k; tk--)
text_buf[i][tk] = text_buf[i][tk - 1];
text_buf[page * 16 + i][k] = t;
for (int8_t tk = k; tk < 15; tk++)
setc8(text_buf[page * 16 + i][tk]);
k++;
}
}
LCD.clrScr();
cursorX = 0;
cursorY = 0;
}
void setup() {
pinMode(pin_SD, OUTPUT);
pinMode(pin_BL, OUTPUT);
LCD.InitLCD();
LCD.clrScr();
LCD.setFont(BigFont);
LCD.setColor(VGA_COLORS[10]);
analogWrite(pin_BL, BL);
echoln("MicConOS 0.8b", 13);
if (!rtc.begin())
echoln("RTC fail", 8);
if (rtc.lostPower())
rtc.adjust(DateTime(__DATE__, __TIME__));
keyboard.begin(ps2key_data_pin, ps2key_int_pin);
if (!SD.begin(pin_SD))
echoln("SD fail", 7);
#if (__AVR__)
File root = SD.open("/");//без этих двух строк не работает freeMemory()
root.close();
#endif
}
void loop() {
echo("/", 1);
getstr(exe_file_name);
if (strlen(exe_file_name) > 0)
if (!strcmp(exe_file_name, "ls")) {
File root = SD.open("/");
printDirectory(root, 0);
root.close();
} else if (!strcmp(exe_file_name, "uptime")) {
setc16(millis() / 1000);
echoln(" s", 2);
} else if (!strcmp(exe_file_name, "time")) {
itoa(rtc.now().hour(), sTime, 10);
echo(sTime, 2);
echo(":", 1);
itoa(rtc.now().minute(), sTime, 10);
echoln(sTime, 2);
} else if (!strcmp(exe_file_name, "ram")) {
setc16(freeMemory());
echoln(" bytes free RAM", 15);
} else if (!strcmp(exe_file_name, "nano")) {
getstr(exe_file_name);
nano();
} else if (!strcmp(exe_file_name, "mkdir")) {
getstr(exe_file_name);
SD.mkdir(exe_file_name);
} else if (!strcmp(exe_file_name, "rmdir")) {
getstr(exe_file_name);
SD.rmdir(exe_file_name);
} else if (!strcmp(exe_file_name, "mk")) {
File temp = SD.open(exe_file_name, FILE_WRITE);
temp.close();
} else if (!strcmp(exe_file_name, "rm")) {
getstr(exe_file_name);
SD.remove(exe_file_name);
} else if (!strcmp(exe_file_name, "+")) {
BL += 8;
analogWrite(pin_BL, BL);
} else if (!strcmp(exe_file_name, "-")) {
BL -= 8;
analogWrite(pin_BL, BL);
} else if (!strcmp(exe_file_name, "color")) {
getstr(exe_file_name);
LCD.setColor(VGA_COLORS[atoi(exe_file_name)]);
getstr(exe_file_name);
LCD.setBackColor(VGA_COLORS[atoi(exe_file_name)]);
} else if (!SD.exists(exe_file_name))
echoln("File not exist or bad command", 29);
else {
exe_file = SD.open(exe_file_name, FILE_READ);
if (exe_file) {
while (exe_file.available()) {
for (int8_t i = 0; i < 4; i++)
if (exe_file.available())
data[i] = exe_file.read();
else
data[i] = 0;
exe_code = exe();
if (exe_code == exe_end)
break;
else if (exe_code != exe_ok) {
setc16(exe_code);
echoln(" runtime error", 14);
break;
}
if (delta != 0 && delta != 4)
exe_file.seek(exe_file.position() - (4 - delta));
}
exe_file.close();
} else {
echo(exe_file_name, strlen(exe_file_name));
echoln(" error opening", 14);
}
}
}
- исходный код программы пишется на assembler-like языке и транслируется (ассемблером, макропроцессором) в объектный файл, содержащий интерпретируемый байт-код
- среда исполнения (интерпретации) байт-кода представляет собой регистровую виртуальную машину (подобную Java, Dalvik, .Net)
- при выполнении программы используется массив переменных (регистры по своей сути) и стек вызовов
- размер стека вызовов - 254, количество вложенных подпрограмм во время выполнения не должно превышать это количество
- имена переменных и меток должны начинаться с маленькой или большой латинской буквы и состоять из букв, цифр и символа "_"
- все переменные глобальны, всего uint8_max = 256 переменных (регистров)
- все переменные имеют тип int16, объявляются как массив размерности uint8 > 0 с мусорными начальными значениями
- индексация массивов с 0
- обращение к массиву без указания номера элемента эквивалентна указанию нулевого уэлемента
- однострочный комментарий после ';'
- длинна "машинного слова" 8 бит
- первый бит в команде - тип аргумента, остальные 7 - опкод операции
- всего возможно 2^7 = 128 команды (RISC-принцип), из них используется 57, свободно 71
- типы аргументов в байт-коде:
0 - uint16 / метка / null (2 или 0 байт)
1 - переменная (1 байт)
- int16 передаются и хранятся в байт-коде с порядком big-endian
- при выводе символов используется ASCII кодировка, учитывается только младший байт int16-числа
- файловая система - fat16 (или fat32, с теми же ограничениями, что и fat16)
- имена файлов записываются массивом (с обязательным нуль терминатором) в нотации 8.3, каталоги и файлы разграничиваются символом '/'
- рабочий каталог - всегда корневой каталог SD-карты, его можно не указывать при обращении к файлу
- в качестве символа переноса строки используется '\n', все строки обязательно оканчиваются нуль терминатором
- подпрограмма начинается с (prс) и заканчивается (ret)
- условный (if*) и безусловный (jmp) переход по метке отличается от вызова подпрограммы (prc) тем, что не вносит текущий адрес в стек вызовов
- отсутствует проверка подпрограмма-метка, т.е. "безусловный переход по подпрограмме" и "вызов метки" не вызовут никаких ошибок
- интерпретатор использует 16тибитную адресацию, размер итогового объектного файла или файлов, с которыми работает программа не должен превышать 2^16=65536 байт (исполняемые файлы могут быть больше этого размера (но не поддерживаются транслятором), однако переход по меткам и вызов подпрограмм из/в сверх этого размера будет невозможен)
- команды в исходном коде записываются в виде
OPERATION {ARG_1{[X]} {ARG_2{[Y]}}} {;COMMENT}
где
OPERATION - имя команды
ARG_1 - первый аргумент команды
ARG_2 - второй аргумент операции
X, Y - индекс элемента при работе с массивами
COMMENT - однострочный комментарий, необязателен
- список свободных пинов
Digital: 0 1 14 15 16 17 18 19 42 43 44 45 46 47 48 49 53
PWM: 8 9 10 11 12 13
Analog in: 54 55 56 57 58 59 60 61 62 63 64 65
I2C: 20 21
Other: 66 67 68 69
Due only: 50 51 52
TODO
- ассемблер (asm)
COMMANDS
- ls - список файлов на SD карте
- ram - количество свободной ОЗУ
- uptime- количество секунд непрерывной работы МК
- time - системное время
- mkdir - создать каталог
- rmdir - удалить каталог
- mk - создать файл
- rm - удалить файл
- nano - текстовый редоактор
- + - увеличить яркость подсветки
- - - уменьшить яркость подсветки
- file - запуск файла с расположением "/file"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment