MK61S, протокол обмена с PC

Ветка форума для обсуждения протокола обмена MK61S с PC.
Протокол обмена

Другие тематические ветки форума:

Forums: 

Хороший вопрос. Но не уверен, что что-то готовое есть.
С этим и в существующих софтовых эмуляторах явная проблема. У эмулятора для андроида свой формат состояния ПМК, у JS-эмулятора свой. Оба нечитабельные и несовместимые друг с другом. Программы еще как-то можно в них в текстовом виде загружать, но не регистры памяти.
Неплохо было бы какой-то универсальный, читабельный (с комментариями и пр.) формат для этого иметь.

Для обмена привычнее мнемокод команд МК61, т.е. обычный текст с возможностью добавления комментариев, инициализации регистров и перехода на начало программы (это не всегда В/0, немало программ начинаются с БП хх). Единственная заковыка с кодировками, т.к. русские символы потребуют либо юникод, либо кодовую страницу, но эту информацию легко добавить в заголовок файла.

Пример для "Билетов"

// Заголовок
ENCODING=Win1251
// Программа: начальный адрес в десятичной системе + команда или список команд через пробелы или табуляции
PROGRAM
00. ИП8 
01. П0  ИП0 ИП1 +    ИП2 +   ИП3 -  ИП4   
10. -   ИП5 -   Fx=0 19  ИП7 1   +  П7  FL0 03 С/П
22. БП 00
// Инициализация регистров: константа + регистр или список регистров 
// Допустимы как русские П0..ПЕ так и латинские R0..RE
REGISTERS
1 П1 П2 П3 П4 П5
0 П7
10 П8
// Стартовый адрес
START=00

У каждой клавиши есть название. Даже несколько, написанных над ней, под ней или справа. Можно эти названия и использовать, памяти же хватит на все синонимы:

В/О F ПРГ ИП Д F x<0 0 9 В↑ ИП 8 …

Пустое место (пробелы, табуляции, переводы строки, возвраты каретки) отделяют одну клавишу от другой. Как комментарий можно использовать \ и ; — они пропускают текст до конца строки. В конце можно передать «спецклавишу» END , другие «спецклавиши» могут использоваться для возвращения статуса.

Кодировка для отечественных ПМК уже разработана. Вряд ли есть смысл плодить вавилонское нагромождение, лучше использовать имеющуюся. Если есть ненависть к русским буквам, можно использовать латинскую мнемонику, там ASCII и меньше синонимов.

На компьютере программы лучше хранить в стандартном формате MKP, преобразовывая их при передаче в нажатия клавиш. Существуют компиляторы из MKL в MKP. Вроде, даже с открытым исходным текстом.

Использовать надо привычный мнемокод, это однозначно.
Но плодить форматы (MKP, MKT) нет особого желания, формат файлов должен быть один - читабельный человеком и MK61S, то есть текстовый. Можно написать "компилятор" на Питоне, который будет осуществлять конвертации кодировок или пересчет адресов, но формат файлов должен быть один.

Мне пока ближе что-то, похожее на формат HP42S:

    00    { 36-Byte Prgm }
    01  LBL "PSN"             ;
    02    MVAR "mu"           ; mu = ALPHA down MATH mu
    03    MVAR "N"            ;
    04    VARMENU "PSN"       ;
    05    STOP                ;
    06    EXITALL             ;
    07    RCL "mu"            ;
    08    ENTER               ;
    09    +/-                 ;
    10    E^X                 ;
    11    X<>Y                  ; x=mu y=exp(-mu)
    12    RCL "N"             ;
    13    Y^X                 ; mu^n
    14    LASTX               ; n
    15    N!                  ;
    16    /                   ;
    17    x                   ;
    18    .END.               ;

Добавить только тип кодировки, стартовый адрес, контрольную сумму и содержимое регистров памяти.
МК61S сможет "поглощать" такой формат "нативно" (через терминал или утилиту на Питоне), равно как и выкидывать программу в тот же терминал. В последнем случае пропадут комментарии

— Как много стандартов! Надо что-то с этим делать.
— Точно! Давайте сделаем ещё один стандарт.

Никаких MKT в МК61S не потребуется, так как в нём нет области текста.

Есть стандарт MKP для откомпилированной программы и MKL для исходного текста. Максимум, если потребуется, можно добавить MKD для сохранения регистров.

А, да, я забыл уже, что MKL это программа в текстовом виде.
Но все-таки я сторонник одного файла - программа, регистры и служебная информация. Все в текстовом виде. Мощи Cortex-M4 микроконтроллера, на котором будет MK61S хватит для обработки "на лету".

Никто не мешает добавить в MKL псевдокоманды для генерации MKD.

Собственно, отсутствие такой возможности и заставило меня перейти с MK.EXE на SP-Forth в черновиках Каллисто-2 и бета-версии 161eForth. IMHO надо развивать культуру, а не начинать каждый раз с нуля.

MKL выглядит почти так как мы тут обсуждаем (HP42S-подобно), за исключением того, что там метки в тексте, а не адреса. Предполагает создание утилиты-компилятора. Отладка в виде "гляжу в текст программы и на экран МК61S" не очень удобно - в тексте нет адресов.

Метки и компилятор необходимы для 10000 шагов ассемблерных портянок МК161, но надо ли это для ретрокалькулятора в 105 шагов памяти?

.CHARSET 1251

; Файл uskorenie
.ORG 0


A0:	 ; с адреса 24
	K MS->D
	M A
	0
	PP M 9045	; Размерность аргумента тригонометрических функций (Дополнительные функции)
	RM A
	F SIN
	F X^2
	RM 2
	*
	RM A
	2
	*
	F SIN
	F X^2
	RM 3
	*
	-
	1
	+
	RM 1
	*
	R/S
	GOTO A0
.END 

Есть две разные вещи — файл, как программа хранится на диске десктопа, и протокол, по которому эта программа передаётся в ПМК. Файл и протокол могут быть близки друг другу, могут сильно отличаться, но это разные сущности.

Опять же, компилятор из исходного текста (MKL) в код программы (MKP) может быть только на десктопе — так сделано в МК-161. Но можно компилятор прошить и в ПМК. Если в ПМК есть свой компилятор, там же может быть и текстовый редактор.

В минимальном решении исходный код (MKL) хранится только на десктопе, в ПМК же встроен отладчик и усовершенствованный редактор кода программы (MKP) с декомпилятором из кода в мнемонику.

Возможности MKL, конечно, избыточны для МК-61S. Те же макрокоманды графического интерфейса на МК-61S не нужны. Но неплохо, если у простых программ будет единая запись, чтобы их можно было загружать как в МК-61S, так и в МК-161.

Программы, написанные по правилам (например, из справочника Дьяконова), будут работать и там, и там одинаково. Неплохо, когда у них единое представление. Тогда владелец может скачать их исходный код (MKL) и загрузить в свой ПМК, не заботясь о его версии. И небольшие программы тогда тоже можно будет писать и выкладывать для обоих ПМК.

В своей реализации скриптового интерпретатора кода МК я организовал работу с метками так:
1. Выделил код 0xFF под идентификатор "метка", за ним один байт - сама метка, итого 256 меток.
2. Если эта пара ("Метка" + идентификатор) встречается в программе автономно без предстоящей команды
перехода - она считается объявлением метки, исполняется как НОП.
3. Если после команды перехода есть пара "Метка- идентификатор" - то ищем метку в коде и переходим на нее. Иначе - переходим по адресу. Например, БП FF MM, где ММ - метка. При такой логике ничего не рушится в области совместимости снизу вверх и метки реализуются безболезненно. Переход на метку может быть выполнен из любой команды перехода, кроме косвенного.
При исполнении программы организована очередь на 16 меток (пара метка - адрес), если метка есть в очереди - то ничего не ищем, сразу переходим, если метки нет - то тогда нужно искать по коду программы с последующим запихиванием ее в очередь.

В принципе, упрощает наброску программы на коленке.

Мне тоже такой формат программ для HP-42S нравится. Я в нем программы для free42 и храню, примерно в таком виде:

00 { 90-Byte Prgm }
// Папа, мама, я и микрокалькулятор. Финк Л.М.  Парусная регата
01 LBL "YAHT"
02 STO 04       // 00.П4
03 0            // 01.0
04 STO 12       // 02.ПC
05 STO 13       // 03.ПD
06 LBL 04
07 RCL 05       // 04.ИП5
08 STOP         // 05.С/П
09 STO 05       // 06.П5
10 COS          // 07.Fcos
11 RCL ST X     // 08.В^
12 SQRT         // 09.FКвКор
13 STO 06       // 10.П6
14 ×            // 11.x
15 1            // 12.1
16 +            // 13.+
17 STO 07       // 14.П7
18 RCL 04       // 15.ИП4
19 RCL 05       // 16.ИП5
20 +            // 17.+
21 COS          // 18.Fcos
22 RCL 06       // 19.ИП6
23 ×            // 20.x
24 RCL 00       // 21.ИП0
25 ×            // 22.x
26 RCL 07       // 23.ИП7
27 ÷            // 24.:
28 5            // 25.5
29 ×            // 26.x
30 STO 08       // 27.П8
31 RCL 04       // 28.ИП4
32 SIN          // 29.Fsin
33 ×            // 30.x
34 STO 10       // 31.ПA
35 RCL 12       // 32.ИПC
36 +            // 33.+
37 RCL 02       // 34.ИП2
38 +            // 35.+
39 STO 02       // 36.П2
40 STOP         // 37.С/П
41 RCL 10       // 38.ИПA
42 STO 12       // 39.ПC
43 RCL 08       // 40.ИП8
44 RCL 04       // 41.ИП4
45 COS          // 42.Fcos
46 ×            // 43.x
47 STO 11       // 44.ПB
48 RCL 13       // 45.ИПD
49 +            // 46.+
50 RCL 03       // 47.ИП3
51 +            // 48.+
52 STO 03       // 49.П3
53 STOP         // 50.С/П
54 RCL 11       // 51.ИПB
55 STO 13       // 52.ПD
56 RCL 04       // 53.ИП4
57 STOP         // 54.С/П
58 STO 04       // 55.П4
59 GTO 04       // 56.БП  57.04
60 END          
61 LBL "YINI"
62 0
63 STO 02       // x
64 STO 03       // y
65 10
66 STO 00       // v
67 END

Но без соответствующего расширения для VSCode его не очень удобно было бы использовать. Плюс, для инициализации регистров памяти приходится использовать такие вот подпрограммки как YINI в примере, благо тут память под код программ почти неограничена. Для МК-61S для регистров придется придумывать что-то другое.

LBL "Короткие Счастливые билеты"
LEN 22
00  ИП8
01  П0
02  ИП0
03  ИП1
04  +
05  ИП2
06  +
07  ИП3
08  -
09  ИП4
10  -
11  ИП5
12  -
13  Fx=0
14  19
15  ИП7
16  1
17  +
18  П7
19  FL0
20  03
21  С/П
REG
0 0
1 1
2 1
3 1
4 1
5 1
6 0
7 0
8 10
9 0
A 0
B 0
C 0
D 0
E 0
CHECKSUM 0xFA41
NOTE Тестовый результат: 1

Поскольку большинство программ используются в единственном числе в ПМК, то LBL, LEN, CHECKSUM, NOTE можно хранить в отдельной "metadata":

  • Загрузка из PC через терминал/утилиту обновляет метаданные автоматически. Контрольная сумма вычисляется заново и сравнивается с полученной из метаданных суммой.
  • Отображение и редактирование на экране ПМК в отдельном режиме (доп.кнопки)
  • Вывод программы в терминал PC автоматически подставляет метаданные в указанном формате.

"Вертикальный" способ отображения текста программ очень хорошо подходит будущему формату режима PRG в MK61S:
PRG mode

а также удобен для печати на узких ленточных принтерах типа HP82240B, почему бы и не замахнуться на такое? :)

Добавить еще XYZTL, текущий указатель на комманду, положение Р/ГРД/Г,.. что там еще? Все последние блоки сделать необязательными, кроме программы.
Неплохо получилось бы.

XYZTL и Р-ГРД-Г однозначно надо добавить. Текущий указатель (SP) - это для сохранения полного состояния калькулятора?

Да, все блоки, кроме программы, опциональны. При загрузке только программы из PC поля LEN, CHECKSUM обновятся автоматически. При выгрузке в PC все поля создадутся и заполнятся соответственно (в том числе через специальный интерфейс MK61S)

Почему счётчик адресов это SP?

Для сохранения полного состояния нужно ещё записывать стек возвратов, глубиной 5 вложений. Если у вас тут всё внезапно английское, например так:
RS: 000 000 000 000 000

это все в отдаленное будущее, для начала бы доделать базовый функционал.
Английское потому что в коммуникационных программах обычно все плохо с кириллицей и кодировками (и не только в коммуникационных, а во вполне официальных ПМК-шных утилитах).

Не разделяю убеждений, что сложности с русским алфавитом осознанно закладывают русофобы из ЦРУ и Пентагона.

Моя основная мысль — ПМК это та область, где мы можем сознательно прокладывать путь для восстановления отечественной индустрии. Без западофобии :-), но с уважением к нашей культуре, нашим предкам. Потом эти наработки могут быть восприняты и в других областях.

Для ПМК уже предложена в Новосибирске хорошая кодовая таблица, где собраны все нужные нам символы. У русских букв есть однозначный 8-битный код, что позволяет проверять правильность их приёма и передачи по 8-битному каналу. Этот код основан на 866 странице, то есть имеется некоторая совместимость и вне мира ПМК.

Куда приятнее посылать MK61S "ИПД", а не "RMD". Это не такая уж сложная техническая задача, но народ оценит. Часть любителей советских ПМК любит и русскую, советскую культуру вообще. Это не только те, кто живут в России и имеют сложности с английским. Я встречал любителей русской культуры и русского языка в Польше и США.

Если есть сомнения по безопасности повторного использования новосибирских разработок, никто не мешает использовать Юникод, 16-битный или UTF-8.

Сложности с русским алфавитом заложились исторически, а не осознанно - кто первый выдал массовую вычислительную технику человечеству, того и кодовая таблица. Я вчера попробовал новосибирскую утилиту для связи с ЭКВМ - как были косяки с русским интерфейсом, так и остались. А уже пятая часть 21го века на дворе

Я тоже за использование русской мнемоники в МК61С (можно ее так называть, от слова СТМ32 :)
Можно, наверное, использовать уникод для хранения текстов программ в файле. А внутри МК61С хранить в 866 таблице, конвертировать самой ПМК на лету. Мощности хватит.

На новосибирские утилиты у нас сейчас влияния мало. Пусть останутся на их совести. Исправляют баги, уже хорошо.

Поддерживаю идею хранения символов внутри МК61S в cp866, с ПМКшным расширением из ЭКВМ. Также вполне разумно, что на международных устройствах используется Юникод.

Вопрос лишь в том, где граница. Предлагаю рассматривать протокол обмена, как часть MK61S. Тогда внутри самого ПМК всё будет последовательно, а общение с ним предсказуемо. Легче будет соединять этот ПМК с ЭКВМ и другой отечественной техникой, по мере её возникновения. Преобразования из / в Юникод можно осуществлять в коммуникационных программах, возможности десктопа позволяют.

Так сделано в MK.EXE, где псевдокоманда .CHARSET позволяет выбрать, из какой кодировки десктоп будет преобразовывать символьные константы в 866.

Edit. Название MK-61S мне больше нравится. Оно отражает гибридность устройства — советский ПМК поверх STM32. Надеюсь, однажды сможем сделать отечественный ПМК на отечественной комплектухе. Но пока так.

Ага, разумно все перекодировки переложить на сторону PC-шной утилиты. Которая, скорее всего, будет написана на Питоне, как кроссплатформенная и скриптовая.

Если у уважаемого st получился написать протокол парсера, можно будет сразу попробовать добавить такую перекодировку в будущую утилиту.

А я пока начинаю писать драйвер МК52й "железной" клавиатуры с дополнительными кнопками.

Покомандная запись неудобна для ручной набивки, при этом разбор текста весьма примитивный для обоих случаев. Длину указывать тоже не надо, это источник труднообъяснимых ошибок, просто разбивать на секции

PRG
01. .....
10. ....

При этом построчный формат позволяет записывать и покомандно тоже, 1 команда на строку, а не несколько.

покомандную запись сложно парсить средствами самой MK61S. Если, конечно, найдутся желающие реализовать это в прошивке, я за :) В "черной таблетке" ресурсов хватит

Там регулярная грамматика, все делается за один проход посимвольно без возвратов и вроде даже без lookahead-ов.

И со стороны человека не все так однозначно (с). Предполагая, что никаких сторонних утилит и компиляторов мы не используем, мне лично проще ввести программу и потом отлаживать ее в самой ПМК (глядя в экран ПМК и в текст), когда она записана в исходном тексте вот так:

00  ИП8
01  П0
02  ИП0
03  ИП1
04  +
05  ИП2
06  +
07  ИП3
08  -
09  ИП4
10  -
11  ИП5
12  -
...

чем когда вот так:

00 ИП8 П0 ИП0 ИП1 + ИП2 + ИП3 - ИП4
10 - ИП5 -...

Теоретически мы можем выделить еще килобайт, а то и несколько, ОЗУ для хранения комментариев к каждой строке в исходном тексте, и потом, при экспорте программы обратно в PC вписывать их обратно в нужные строки.

Но Гитлаб открыт всем, поэтому все дополнения с радостью принимаются :)

Поточному разбору текста все равно что обрабатывать:

00. хх
01. уу
...

или

00. хх уу ...

или даже

00. хх 01. уу ...

в грамматике, где адрес отделены от команды точкой или еще чем-то. Между пробелом, табуляцией и переводом строки в качестве разделителей разницы нет.

Прямо сейчас у меня, к сожалению, нет времени написать такой код, но работы там на один день максимум вместе с тестами. Возможно на выходных попробую хотя бы начать.

Если получится, можно сразу интегрировать в MK61S, UART уже работает полностью

У тебя чистый Си или можно с плюсами?

Сейчас все в Си, проще было с libopencm3 работать.
Проект под Stm32CubIDE тоже начали в Си, но если удобнее будет, могу переделать проект под плюсы. Мысль была попробовать, вот, причина появилась.

UPDATE: попробовал создать новый проект из старого .ioc файла и создать новый проект с нуля.
Несмотря на выбор C++ как Target Language:
target lang

в обоих случаях проект создается в C:
C

В общем, пока предлагаю ориентироваться на Си, как язык разработки фирмвари MK61S.

UPDATE 2: при помощи лома и ноутбука (с) таки можно заставить проект CubeIDE поддерживать Плюсы - там предлагают не трогать main.c (чтобы кодогенератор не создавала main.c из main.cpp каждый раз), а добавить в main() лишь один вызов - cpp_link(), где весь функционал написан на Плюсах.
Все хидер файлы уже с

#ifdef __cplusplus
extern "C" {
#endif

Так что если на Плюсах удобнее писать, пиши на Плюсах, потом затащим в проект.

Перетащил оболочку MK61S и драйвер дисплея в Плюсы.
Результаты эксперимента (Release билд, оптимизация -Ofast):
1. Скорость "коротких" билетов не изменилась
2. Потребление памяти в Плюсах чуток больше

ССpp

Думаю, можно все в Плюсы перетаскивать, удобство налицо

Хорошая новость, хоть и ожидаемая. На моей памяти Алексей уже пробовал подобное на MSP430, накладные расходы на "плюсы" были на уровне единиц процентов.

Да, вполне ожидаемо.
Единственное - Mk61Emu оставлен в C и вынесен в отдельный каталог Firmware/Mk61sApp/Mk61EmuCore. Предлагаю его оставить Сишным, а в Плюсах делать всю инфраструктуру вокруг.

Я перенес версию с Плюсми в /master, как основную ветку.

Последний код в /master Гитлаба.

Сеанс программирования MK61S "короткими билетами" через UART:

00:13:00.051 -> FrankenCalc MK52S v.0.5.6
00:13:00.429 -> PMK started. 'z': get PRG/REG data, 'x': go to AUT mode
00:13:02.126 -> Waiting for PRG/REG data ...
00:13:10.748 -> Start MK61S programming, 59 bytes
00:13:10.748 -> Code:82 (R), x:4, y:9
00:13:11.124 -> Code:91 ([), x:0, y:0
00:13:11.788 -> Code:64 (@), x:8, y:9
00:13:12.118 -> Code:56 (8), x:0, y:0
00:13:12.448 -> Code:33 (!), x:6, y:9
00:13:12.827 -> Code:48 (0), x:0, y:0
00:13:13.158 -> Code:64 (@), x:8, y:9
00:13:13.487 -> Code:48 (0), x:0, y:0
00:13:13.815 -> Code:64 (@), x:8, y:9
00:13:14.192 -> Code:49 (1), x:0, y:0
00:13:14.522 -> Code:43 (+), x:2, y:8
00:13:14.850 -> Code:64 (@), x:8, y:9
00:13:15.179 -> Code:50 (2), x:0, y:0
00:13:15.506 -> Code:43 (+), x:2, y:8
00:13:15.836 -> Code:64 (@), x:8, y:9
00:13:16.212 -> Code:51 (3), x:0, y:0
00:13:16.542 -> Code:45 (-), x:3, y:8
00:13:16.870 -> Code:64 (@), x:8, y:9
00:13:17.200 -> Code:52 (4), x:0, y:0
00:13:17.575 -> Code:45 (-), x:3, y:8
00:13:17.904 -> Code:64 (@), x:8, y:9
00:13:18.235 -> Code:53 (5), x:0, y:0
00:13:18.565 -> Code:45 (-), x:3, y:8
00:13:18.897 -> Code:70 (F), x:11, y:9
00:13:19.226 -> Code:60 (<), x:9, y:9
00:13:19.603 -> Code:49 (1), x:0, y:0
00:13:19.933 -> Code:57 (9), x:0, y:0
00:13:20.262 -> Code:64 (@), x:8, y:9
00:13:20.592 -> Code:55 (7), x:0, y:0
00:13:20.923 -> Code:49 (1), x:0, y:0
00:13:21.299 -> Code:43 (+), x:2, y:8
00:13:21.629 -> Code:33 (!), x:6, y:9
00:13:21.959 -> Code:55 (7), x:0, y:0
00:13:22.289 -> Code:70 (F), x:11, y:9
00:13:22.618 -> Code:64 (@), x:8, y:9
00:13:22.946 -> Code:48 (0), x:0, y:0
00:13:23.322 -> Code:51 (3), x:0, y:0
00:13:23.651 -> Code:71 (G), x:2, y:9
00:13:23.980 -> Code:93 (]), x:0, y:0
00:13:24.684 -> Code:82 (R), x:4, y:9
00:13:25.014 -> Code:49 (1), x:0, y:0
00:13:25.341 -> Code:33 (!), x:6, y:9
00:13:25.670 -> Code:49 (1), x:0, y:0
00:13:26.049 -> Code:33 (!), x:6, y:9
00:13:26.378 -> Code:50 (2), x:0, y:0
00:13:26.708 -> Code:33 (!), x:6, y:9
00:13:27.036 -> Code:51 (3), x:0, y:0
00:13:27.398 -> Code:33 (!), x:6, y:9
00:13:27.729 -> Code:52 (4), x:0, y:0
00:13:28.103 -> Code:33 (!), x:6, y:9
00:13:28.432 -> Code:53 (5), x:0, y:0
00:13:28.766 -> Code:48 (0), x:0, y:0
00:13:29.097 -> Code:33 (!), x:6, y:9
00:13:29.426 -> Code:55 (7), x:0, y:0
00:13:29.801 -> Code:49 (1), x:0, y:0
00:13:30.131 -> Code:48 (0), x:0, y:0
00:13:30.460 -> Code:33 (!), x:6, y:9
00:13:30.838 -> Code:56 (8), x:0, y:0
00:13:31.166 -> Code:71 (G), x:2, y:9
00:13:31.640 -> RUN...
00:13:38.094 -> PRG finished

Разница в секундах между RUN... и PRG finished: (38094 - 31640) = 6.45
Что дает на "синей таблетке" 6.2x от скорости предка ( Stm32Cube IDE, Release build, Optimization level: "For speed -Ofast" )

Лог программирования "коротких билетов", FW v.0.6.6 (Debug build):

23:25:57.669 -> FrankenCalc MK61S; HW v.1.4, SW v.0.6.6
23:25:57.669 -> MK61S:[ 0,           ]
23:28:50.432 -> R[@8!0@0@1+@2+@3-@4-@5-F<19@71+!7F@03G]R1!1!2!3!4!50!710!8G

23:28:50.432 -> Code:R (0x52); x:4, y:9
23:28:50.812 -> MK61S:[ 0,           ]
23:28:50.812 -> 
23:28:50.812 -> Code:[ (0x5B); x:0, y:0
23:28:51.571 -> MK61S:[          , 00]
23:28:51.571 -> 
23:28:51.571 -> Code:@ (0x40); x:8, y:9
23:28:51.951 -> MK61S:[          , 00]
23:28:51.951 -> 
23:28:51.951 -> Code:8 (0x38); x:0, y:0
23:28:52.332 -> MK61S:[ 68       , 01]
23:28:52.332 -> 
23:28:52.332 -> Code:! (0x21); x:6, y:9
23:28:52.706 -> MK61S:[ 68       , 01]
23:28:52.706 -> 
23:28:52.706 -> Code:0 (0x30); x:0, y:0
23:28:53.089 -> MK61S:[ 40 68    , 02]
23:28:53.089 -> 
23:28:53.089 -> Code:@ (0x40); x:8, y:9
23:28:53.468 -> MK61S:[ 40 68    , 02]
23:28:53.468 -> 
23:28:53.468 -> Code:0 (0x30); x:0, y:0
23:28:53.846 -> MK61S:[ 60 40 68 , 03]
23:28:53.846 -> 
23:28:53.846 -> Code:@ (0x40); x:8, y:9
23:28:54.180 -> MK61S:[ 60 40 68 , 03]
23:28:54.180 -> 
23:28:54.180 -> Code:1 (0x31); x:0, y:0
23:28:54.591 -> MK61S:[ 61 60 40 , 04]
23:28:54.591 -> 
23:28:54.591 -> Code:+ (0x2B); x:2, y:8
23:28:54.924 -> MK61S:[ 10 61 60 , 05]
23:28:54.924 -> 
23:28:54.924 -> Code:@ (0x40); x:8, y:9
23:28:55.302 -> MK61S:[ 10 61 60 , 05]
23:28:55.302 -> 
23:28:55.302 -> Code:2 (0x32); x:0, y:0
23:28:55.685 -> MK61S:[ 62 10 61 , 06]
23:28:55.685 -> 
23:28:55.685 -> Code:+ (0x2B); x:2, y:8
23:28:56.065 -> MK61S:[ 10 62 10 , 07]
23:28:56.065 -> 
23:28:56.065 -> Code:@ (0x40); x:8, y:9
23:28:56.445 -> MK61S:[ 10 62 10 , 07]
23:28:56.445 -> 
23:28:56.445 -> Code:3 (0x33); x:0, y:0
23:28:56.825 -> MK61S:[ 63 10 62 , 08]
23:28:56.825 -> 
23:28:56.825 -> Code:- (0x2D); x:3, y:8
23:28:57.202 -> MK61S:[ 11 63 10 , 09]
23:28:57.202 -> 
23:28:57.202 -> Code:@ (0x40); x:8, y:9
23:28:57.587 -> MK61S:[ 11 63 10 , 09]
23:28:57.587 -> 
23:28:57.587 -> Code:4 (0x34); x:0, y:0
23:28:57.952 -> MK61S:[ 64 11 63 , 10]
23:28:57.952 -> 
23:28:57.952 -> Code:- (0x2D); x:3, y:8
23:28:58.327 -> MK61S:[ 11 64 11 , 11]
23:28:58.327 -> 
23:28:58.327 -> Code:@ (0x40); x:8, y:9
23:28:58.703 -> MK61S:[ 11 64 11 , 11]
23:28:58.703 -> 
23:28:58.703 -> Code:5 (0x35); x:0, y:0
23:28:59.082 -> MK61S:[ 65 11 64 , 12]
23:28:59.082 -> 
23:28:59.082 -> Code:- (0x2D); x:3, y:8
23:28:59.413 -> MK61S:[ 11 65 11 , 13]
23:28:59.413 -> 
23:28:59.413 -> Code:F (0x46); x:11, y:9
23:28:59.796 -> MK61S:[ 11 65 11 , 13]
23:28:59.796 -> 
23:28:59.796 -> Code:< (0x3C); x:9, y:9
23:29:00.174 -> MK61S:[ 5E 11 65 , 14]
23:29:00.174 -> 
23:29:00.174 -> Code:1 (0x31); x:0, y:0
23:29:00.555 -> MK61S:[ 5E 11 65 , 14]
23:29:00.555 -> 
23:29:00.555 -> Code:9 (0x39); x:0, y:0
23:29:00.937 -> MK61S:[ 19 5E 11 , 15]
23:29:00.937 -> 
23:29:00.937 -> Code:@ (0x40); x:8, y:9
23:29:01.319 -> MK61S:[ 19 5E 11 , 15]
23:29:01.319 -> 
23:29:01.319 -> Code:7 (0x37); x:0, y:0
23:29:01.700 -> MK61S:[ 67 19 5E , 16]
23:29:01.700 -> 
23:29:01.700 -> Code:1 (0x31); x:0, y:0
23:29:02.076 -> MK61S:[ 01 67 19 , 17]
23:29:02.076 -> 
23:29:02.076 -> Code:+ (0x2B); x:2, y:8
23:29:02.411 -> MK61S:[ 10 01 67 , 18]
23:29:02.411 -> 
23:29:02.411 -> Code:! (0x21); x:6, y:9
23:29:02.791 -> MK61S:[ 10 01 67 , 18]
23:29:02.791 -> 
23:29:02.791 -> Code:7 (0x37); x:0, y:0
23:29:03.171 -> MK61S:[ 47 10 01 , 19]
23:29:03.171 -> 
23:29:03.171 -> Code:F (0x46); x:11, y:9
23:29:03.553 -> MK61S:[ 47 10 01 , 19]
23:29:03.553 -> 
23:29:03.553 -> Code:@ (0x40); x:8, y:9
23:29:03.935 -> MK61S:[ 5r 47 10 , 20]
23:29:03.935 -> 
23:29:03.935 -> Code:0 (0x30); x:0, y:0
23:29:04.313 -> MK61S:[ 5r 47 10 , 20]
23:29:04.313 -> 
23:29:04.313 -> Code:3 (0x33); x:0, y:0
23:29:04.691 -> MK61S:[ 03 5r 47 , 21]
23:29:04.691 -> 
23:29:04.691 -> Code:G (0x47); x:2, y:9
23:29:05.070 -> MK61S:[ 50 03 5r , 22]
23:29:05.070 -> 
23:29:05.070 -> Code:] (0x5D); x:0, y:0
23:29:05.788 -> MK61S:[ 0,           ]
23:29:05.788 -> 
23:29:05.788 -> Code:R (0x52); x:4, y:9
23:29:06.168 -> MK61S:[ 0,           ]
23:29:06.168 -> 
23:29:06.168 -> Code:1 (0x31); x:0, y:0
23:29:06.549 -> MK61S:[ 1,           ]
23:29:06.549 -> 
23:29:06.549 -> Code:! (0x21); x:6, y:9
23:29:06.933 -> MK61S:[ 1,           ]
23:29:06.933 -> 
23:29:06.933 -> Code:1 (0x31); x:0, y:0
23:29:07.315 -> MK61S:[ 1,           ]
23:29:07.315 -> 
23:29:07.315 -> Code:! (0x21); x:6, y:9
23:29:07.692 -> MK61S:[ 1,           ]
23:29:07.692 -> 
23:29:07.692 -> Code:2 (0x32); x:0, y:0
23:29:08.060 -> MK61S:[ 1,           ]
23:29:08.060 -> 
23:29:08.060 -> Code:! (0x21); x:6, y:9
23:29:08.440 -> MK61S:[ 1,           ]
23:29:08.440 -> 
23:29:08.440 -> Code:3 (0x33); x:0, y:0
23:29:08.821 -> MK61S:[ 1,           ]
23:29:08.821 -> 
23:29:08.821 -> Code:! (0x21); x:6, y:9
23:29:09.201 -> MK61S:[ 1,           ]
23:29:09.201 -> 
23:29:09.201 -> Code:4 (0x34); x:0, y:0
23:29:09.578 -> MK61S:[ 1,           ]
23:29:09.578 -> 
23:29:09.578 -> Code:! (0x21); x:6, y:9
23:29:09.956 -> MK61S:[ 1,           ]
23:29:09.956 -> 
23:29:09.956 -> Code:5 (0x35); x:0, y:0
23:29:10.335 -> MK61S:[ 1,           ]
23:29:10.335 -> 
23:29:10.335 -> Code:0 (0x30); x:0, y:0
23:29:10.712 -> MK61S:[ 0,           ]
23:29:10.712 -> 
23:29:10.712 -> Code:! (0x21); x:6, y:9
23:29:11.091 -> MK61S:[ 0,           ]
23:29:11.091 -> 
23:29:11.091 -> Code:7 (0x37); x:0, y:0
23:29:11.424 -> MK61S:[ 0,           ]
23:29:11.472 -> 
23:29:11.472 -> Code:1 (0x31); x:0, y:0
23:29:11.801 -> MK61S:[ 1,           ]
23:29:11.848 -> 
23:29:11.848 -> Code:0 (0x30); x:0, y:0
23:29:12.179 -> MK61S:[ 10,          ]
23:29:12.179 -> 
23:29:12.179 -> Code:! (0x21); x:6, y:9
23:29:12.559 -> MK61S:[ 10,          ]
23:29:12.559 -> 
23:29:12.559 -> Code:8 (0x38); x:0, y:0
23:29:12.937 -> MK61S:[ 10,          ]
23:29:12.937 -> 
23:29:12.937 -> Code:G (0x47); x:2, y:9
23:29:13.321 -> RUN...
23:29:20.655 -> +MK61S:[ 1,           ]
23:29:20.801 -> MK61S:[ 1,           ]