Casio PD‑700 — Часть 9: соответствие CS, ROM‑карта, общение с драйверами дисплея
Так как никакого упоминания о существовании ROM-карты для Casio PD‑700B так и не нашлось, я решил собрать свою карту с RAM и поэкспериментировать. Коннектор не самый распространённый, но часто используемый в Casio - 45 пинов с шагом 1 мм, такой же, как в картах OM c языками программирования для PB‑2000C/AI‑1000, в картах ES для органайзеров серии SF/DK и некоторых других. Кроме того, оказалось, что помимо PB‑2000C карта подобного форм-фактора, содержащая токенизированные программы, применяется и в промышленном карманном компьютере Sandvik Coromant TRIM 8401T.
Схожий коннектор на 50 пинов нашёлся на Aliexpress, правда, он имеет гораздо меньшую глубину посадки.
Первым делом я собрал подобие карты и подключил светодиоды к старшим адресным линиям и к линии CS (инверсный) для определения диапазона адресов, при обращении к которым активируется карта. Я предполагал, что каждый CS активируется в зависимости от состояния адресных линий, но как оказалось, всё зависит только от абсолютного адреса, и при разных адресах с одинаковым состоянием линий активируются разные CS.
Всего адресных линий 19 (A0-A18), то есть теоретически при одном активном CS может быть адресовано 512 кБ. Максимальное значение для DEFSEG – 65535 (16*4096-1), следовательно, 64-килобайтовых областей может быть 16, то есть программно можно адресовать 1 мегабайт.
Выполняя PEEK в циклах c разных адресов стало понятно, что ROM-карта (CS6) активируется при обращении к адресам &H080000-&H0FFFFF, а это означает, что максимальный поддерживаемый объём карты - 512 кБ. Далее я подпаялся к оставшимся линиям CS, чтобы определить их соответствие адресам. Оказалось, что физически тоже адресуется мегабайт!
00 01 02 03 04 05 06 07 |
A16
A17
A16 A17
A18
A16 A18
A17 A18
A16 A17 A18
| CS1,CS2 CS3 CS4 CS4 CS5 CS5 CS5 CS5 | 0-32-64 kB 64-128 kB 128-192 kB 192-256 kB 256-320 kB 320-384 kB 384-448 kB 448-512 kB | RAM 64 FP-50 (30-pin port) \ Display Drivers / (POKE only) ROM 64 ROM 128 ROM 192 \ repeats ROM 256 / ROM 64&128 |
08 09 0A 0B 0C 0D 0E 0F |
A16
A17
A16 A17
A18
A16 A18
A17 A18
A16 A17 A18
| CS6 CS6 CS6 CS6 CS6 CS6 CS6 CS6 | 0-64 kB 64-128 kB 128-192 kB 192-256 kB 256-320 kB 320-384 kB 384-448 kB 448-512 kB | CARD 64 CARD 128 CARD 192 CARD 256 CARD 320 CARD 384 CARD 448 CARD 512 |
Максимальный поддерживаемый объём ROM - 256 кБ, а при использовании 128 кБ её содержимое дублируется, потому что в таком случае адресная линия A17 не учитывается.
Так как один сегмент для DEFSEG равен 16 байтам, максимальная возможная позиция оказывается за 16 байт до конца всей адресуемой области, следующие 16 байт соответствуют её концу, а далее адресация циклически возвращается к началу адресного пространства.
Теперь можно переходить к сборке самой карты. Распиновка коннектора слегка отличается от таковой в PB‑2000C, и главное отличие - тут нет пина для определения наличия ROM-карты. Но откуда в таком случае он об этом узнает? Оказалось, что CS6 кратковременно активируется при включении калькулятора даже при отсутствии карты. Получается, что он проверяет на ней содержимое по определённым адресам в момент запуска.
Пример схемы подключения распространённых микросхем RAM на 8 или 32 кБ:
Карту придётся часто вставлять и вытаскивать, не выключая калькулятор, но ROM-свитч этого не позволит. Можно, конечно, вытащить защёлку, но гораздо удобнее сразу установить выключатель на CS.
После увеличения памяти на Casio VX‑4 у меня оставалась микросхема 4464-08LL – SRAM на 8 кБ от Matsushita (ныне Panasonic), и я решил использовать её для изготовления карты.
При первом подключении ожидаемо никакой реакции, ведь сейчас в памяти мусор. В попытках подобрать нужные данные для определения наличия карты я решил скопировать на неё первые байты из внутренней ROM калькулятора. Теперь при включении он выдаёт "NF error ", то есть теперь он ищет программы на карте! Чтобы окончательно в этом убедиться, я собрал полный образ RAM, содержащий программу для побайтового копирования, а в свободной области разместил требуемые для ROM-карты заголовок, адреса и одну программу в токенизированном виде.
Сейчас, при наличии уже правильно отформатированной ROM-карты, программы, находящиеся в RAM калькулятора, не видны. Чтобы увидеть их и при этом иметь доступ к карте, нужно включить его с отключённой картой, а после этого включить саму карту (или вставить её после включения калькулятора).
После запуска программы для копирования, небольшого ожидания и перезапуска калькулятора, он включился без ошибок и увидел программу, которую я перенёс на карту.
Пример содержания заголовка ROM-карты:
- 43 — StartByte?
- 4D04
- 002000 – ROM Card upper bound
- 0101 – ROM Card version
- 000000454C2D3100 – Program name and version
- 250930 – Program date
- FFFFFFFFFFFFFFFF
- 240008
- 240008 – Program address area start address
- 7C0008 – Program address area end address
Для определения наличия карты необходимы только первые 3 байта и версия карты. Адреса программ хранятся так же, как и в RAM, могут лежать где угодно, главное - правильно указать соответствующие адреса. Мне удобнее держать их в начале, сразу после заголовка.
При наличии ROM-карты команды LOAD, NEW, а также попытки создания или редактирования программ приводят к "FC error", RESET не затрагивает карту. В стартовой информации образа RAM после StartByte следуют 2 байта для проверки соответствия образа экземпляру устройства, и при наличии ROM-карты они должны соответствовать адресу начала области адресов программ на карте (значения по адресам &H1E и &H1F, в моем случае - "&H2400").
В результате я написал программу для удобного форматирования карты и копирования на неё программ из памяти калькулятора:
10 WIDTH,4
20 PRINT "FORMAT CARD=NO"," COPY PROG=YES"
30 K$=INPUT$(1,@)
40 IF K$=CHR$(240) GOTO 110
50 IF K$=CHR$(241) GOTO 610
60 GOTO 30
110 INPUT "FROM RAM P",RP," TO CARD P",CP
120 IF RP>10 OR CP>10 THEN BEEP:GOTO 110
130 PRINT "PLEASE WAIT...";
210 DEFSEG=0
220 RA=PEEK&HCF1+PEEK&HCF2*256-8-RP*8
230 RS=PEEK RA+PEEK(RA+1)*256
240 RE=PEEK(RA+3)+PEEK(RA+4)*256
250 S=RE-RS
310 DEFSEG=32768
320 CA=124-8*(CP+1)
330 CS=PEEK CA+PEEK(CA+1)*256
340 CE=CS+S
410 FOR I=CP TO 10
420 POKE CA+3,CE MOD 256:POKE CA+4,CE MOD 65536\256
430 IF I=10 GOTO 470
440 POKE CE,0:CA=CA-8
450 POKE CA,CE MOD 256:POKE CA+1,CE MOD 65536\256
460 CE=CE+1
470 NEXT I
510 S=S-1:PRINT:PRINT "COPYING";S;"B";
520 FOR I=0 TO S:DEFSEG=0:A=PEEK(RS+I):DEFSEG=32768:POKE CS+I,A:NEXT I
530 PRINT:GOTO 710
610 PRINT "FORMATTING..."
620 DEFSEG=32768
630 D$="434D040020000101000000454C2D3100250930FFFFFFFFFFFFFFFF2400082400087C0008"
640 FOR I=0 TO 35:POKE I,VAL("&H"+MID$(D$,I*2+1,2)):NEXT I
650 FOR I=0 TO 10:A=36+I*8
660 POKE A,135-I-1:POKE A+1,0:POKE A+2,8
670 POKE A+3,135-I:POKE A+4,0:POKE A+5,8
680 POKE A+6,80:POKE A+7,ASC(RIGHT$(HEX$(10-I),1))
690 POKE I+124,0:NEXT I
710 BEEP1:PRINT "DONE";:K$=INPUT$(1,@)
При первом запуске требуется нажать "NO" для форматирования карты в требуемый для PD‑700 вид:
При последующих запусках можно переносить программы, нажав клавишу "YES", а затем указав номер копируемой программы и номер программы на карте для записи (копирование 1 кБ занимает примерно 1 минуту):
Так как эта программа разрабатывалась в экспериментальных целях, она работает только с первыми 64 кБ карты и правильно копирует только при записи в номера программ на карте в порядке возрастания.
Вот и разгадана ещё одна загадка - ROM-карта предназначалась для энергонезависимого хранения программ. Если же включить калькулятор с отключённой картой, он продолжает работать с ранее записанными в RAM программами, ничего не очищается, а смысл предупреждения на наклейке ROM-свитча остаётся неясным. Не исключено, что при определённом содержимом заголовка выполняется очистка памяти или запускается перенос программ с карты.
Исследование адресного пространства привело меня ещё к одному интересному наблюдению: обнаружилось, что можно общаться с драйверами дисплея напрямую.
Как было видно из таблицы соответствия адресов и линий CS, обращение к адресам &H02XXXX и &H03XXXX одинаково активирует CS4, но только при отправке данных (POKE). В схеме же было видно, что этот сигнал поступает на вход Gate Array, где генерируется общий сигнал CS для обоих драйверов дисплея - HD44352A02 и HD44353. А ещё в схеме видно, что связь с драйверами осуществляется по 4 битной шине через DB5-DB8, а адресная линия A15 играет роль "OP" (Data operation signal), в отличие от PB‑2000C и FX‑8000G, где для этих задач используются отдельные линии.. Подключение пинов "Designation of segment direction" обоих драйверов соответствует PB‑2000C (а не FX‑8000G), а пина "Device code" - первому HD44353 в обеих моделях. При этом подключение "Frame frequency designation" не соответствует ни одному из них (подключены к плюсу, а не к минусу).
Теперь можно попробовать отправить что-нибудь на дисплей. Эксперименты показали, что:
- Данные отправляются при активном сигнале "OP" (линии A15), а операции - при неактивном.
- Передаётся только старшая тетрада байта, так как используются только старшие линии данных процессора, поэтому каждый байт передаётся двумя байтами.
- Очерёдность тетрад в каждом байте для отправки обратная.
- Вручную удаётся выполнять две операции: вывод графики (&HD) и вывод текста (&HC).
Да, хотя в данном устройстве информация от процессора драйверам дисплея передаётся только в графическом виде (попиксельно), в HD44352A02 содержится встроенный знакогенератор и собственная таблица символов. Текстовый режим можно активировать вручную, передав соответствующую операцию. Но нумерация символов в таблице идёт от конца к началу, поэтому приходится передавать не их коды, а значения, полученные вычитанием этих кодов из &HFF. Например, для вывода "123" нужно передать &HCE, &HCD, &HCC, а так как очерёдность тетрад в каждом байте обратная и передаются только старшие тетрады, программа будет выглядеть следующим образом:
10 DEFSEG=2*4096
20 POKE 0,&HC0
30 POKE 32768,&HE0
40 POKE 32768,&HC0
50 POKE 32768,&HD0
60 POKE 32768,&HC0
70 POKE 32768,&HC0
80 POKE 32768,&HC0
90 K$=INPUT$(1,@)
20 POKE 0,&HC0
30 POKE 32768,&HE0
40 POKE 32768,&HC0
50 POKE 32768,&HD0
60 POKE 32768,&HC0
70 POKE 32768,&HC0
80 POKE 32768,&HC0
90 K$=INPUT$(1,@)
Для обращения к драйверам дисплея задаётся соответствующее значение DEFSEG. Для передачи операции выполняется обращение к адресу, не активирующему линию A15, а для передачи данных - к адресу, активирующему её, например 32768.
Выполнив следующую программу, можно увидеть всю таблицу символов. Для каждого символа она передаёт по два байта, старшие тетрады которых в обратной очерёдности соответствуют их кодам.
10 DEFSEG=2*4096
20 POKE 0,&HC0
30 FOR A=15 TO 3 STEP -4
40 GOSUB 100
50 K$=INPUT$(1,@)
60 GOSUB 100
70 NEXT A
80 END
100 FOR I=A TO A-3 STEP -1
110 FOR J=15 TO 0 STEP -1
120 POKE 32768,(J*16)
130 POKE 32768,(I*16)
140 NEXT J:NEXT I
150 RETURN
20 POKE 0,&HC0
30 FOR A=15 TO 3 STEP -4
40 GOSUB 100
50 K$=INPUT$(1,@)
60 GOSUB 100
70 NEXT A
80 END
100 FOR I=A TO A-3 STEP -1
110 FOR J=15 TO 0 STEP -1
120 POKE 32768,(J*16)
130 POKE 32768,(I*16)
140 NEXT J:NEXT I
150 RETURN
После правого нижнего символа вывод возвращается в начало экрана, но после выполнения CLS или PRINT вывод перестаёт работать. Поэтому для очистки экрана я воспользовался тем, что повторно активируемые пиксели выключаются, и очищаю экран выводом тех же самых символов поверх. Вот как выглядит полученная таблица символов:
В интернете уже описан опыт программирования этих драйверов, но на PB‑1000, с совершенно другим процессором, позволяющим выполнять передачу в машинных кодах. Ознакомление с этим материалом показало, что в PD‑700 драйверам всё передаётся в инвертированном виде. Например, команда "C" соответствует команде "2", а команда "D" - "3". И, судя по обратной очерёдности символов, данные инвертированы именно тут, а не в PB‑1000. Там же есть и примеры передачи команд с параметрами, но в случае с PD‑700 команды длиннее одной тетрады передать не удаётся: применяется только последняя. Скорее всего, это связано с задержками между выполнением POKE в интерпретаторе BASIC. А вывод символов поверх очищает экран, потому что по умолчанию применяется параметр "not Old and New", "Left LCD" (0000 без учёта инверсии).





Комментарии
Отправить комментарий