Casio PD‑700 — Часть 8: содержимое внешней ROM и секреты синтаксиса
На данный момент не существует известного способа считать программу, содержащуюся в процессоре HD62034 или HD62002 - по крайней мере мне таковой пока что найти не удалось. Зато есть возможность считать содержимое внешней микросхемы ROM.
Как было видно при анализе содержимого RAM, тут используются 3-х байтовые адреса и содержимое самого RAM адресуется в диапазоне &H000000-&H00FFFF. Хотя оператор PEEK принимает аргумент не более 65535, то есть в пределах 64 кБ, благодаря оператору DEFSEG можно изменить начальный адрес и заглянуть в другие области.
Размер одного сегмента для DEFSEG равен 16 байтам, и если установить DEFSEG, к примеру, равным 4096 (65536/16), то с помощью PEEK уже можно будет получить доступ к диапазону &H010000-&H01FFFF. Эксперименты показали, что ROM находится в диапазоне &H040000-&H05FFFF, и дублируется в диапазоне &H060000-&H07FFFF. Я немного изменил программу, с помощью которой считывал RAM:
5 POKE &H0E5D,&H60
10 DEFSEG=16384
20 OPEN "COM0:" FOR OUTPUT AS #1
30 FOR I=0 TO 65535
40 PRINT #1, RIGHT$(HEX$(PEEK I),2);
50 NEXT I
60 CLOSE #1
70 BEEP:BEEP1:BEEP:BEEP1:BEEP:BEEP1
10 DEFSEG=16384
20 OPEN "COM0:" FOR OUTPUT AS #1
30 FOR I=0 TO 65535
40 PRINT #1, RIGHT$(HEX$(PEEK I),2);
50 NEXT I
60 CLOSE #1
70 BEEP:BEEP1:BEEP:BEEP1:BEEP:BEEP1
В строке номер 5 я заменяю байт, отвечающий за скорость связи по "COM0:", чтобы установить максимальную допустимую скорость – 19200 bps. Но даже так передача одного блока занимает более получаса. Для считывания блока 04 значение DEFSEG нужно установить в 16384 (4096*4), а для блока 05 – в 20480 (4096*5). И вот, наконец-то, у меня полный дамп содержимого внешней ROM, и можно приступать к исследованию.
Общая структура содержимого внешней ROM:
- [040000] - Заголовок ROM с основной информацией
- [040040] - Таблицы назначения клавиш для разных режимов
- [040250] - Имена файлов
- [040300] - Адрес программы "K0"
- [040400] - Программа "K0"
- [043A00] - Битовая карта символов 6х8 режима WIDTH,4
- [044000] - Битовая карта символов 8х16 режима WIDTH,2
- [044E00] - Битовая карта верхних символов 8х16 режима простого калькулятора
- [044F00] - Битовая карта цифр 8х16 режима простого калькулятора
- [045000] - Битовая карта двухбайтовых символов 16x16 кодировки Shift JIS
Заголовок содержит следующую информацию:
- 43 — StartByte?
- 4D04
- 000002 — ROM upper bound: 131072 => 128 kB
- 0101 — Version for ROM Card
- 00003532322D3100 — Program name and version: 522-1
- 870303 — Program date: 1987, March 3
- FFFFFFFFFFFFFFFF
- 000304
- 000304 — address of "K0" program address
- 000304
Отсюда можно узнать, что программа называется "522-1" и была написана 3 марта 1987 года. Версия для совместимости ROM-карты имеет номер 0101, а так как у PB-2000C она 0104, можно предположить, что между ними были выпущены ещё 2 модели с подобным форматом карт.
Для наглядного представления очерёдности при адресации клавиш нужно переместить некоторые клавиши в таблице распиновки из правой части вверх:
После этого адресация начинается с правой нижней клавиши и продолжается снизу вверх в каждом столбце справа налево.
Содержание таблиц назначения клавиш для каждого режима, и соответствующие клавишам функции:
Стандартный режим (EN)
38 | 32 | 44 | 42 |
43 | 31 | 37 | 18 |
39 | 33 | 58 | 47 |
4D | 30 | 36 | 00 |
8 | 2 | D | B |
C | 1 | 7 | C |
9 | 3 | X | G |
M | 0 | 6 | |
2A | 34 | 53 | 54 |
4A | 50 | 35 | 00 |
2F | 2E | 57 | 56 |
55 | 4C | 11 | 00 |
* | 4 | S | T |
J | P | 5 | / | . | W | V |
U | L | DEL | ||
F3 | 2B | 5A | 46 |
4E | 4F | 3A | 0E |
0F | 2D | 41 | 52 |
48 | 4B | 2C | 1E |
MODE | + | Z | F |
N | O | : | SHIFT |
CAPS | - | A | R |
H | K | , | UP |
1C | 0D | 03 | 00 |
59 | 49 | 3D | 1D |
E0 | E5 | 51 | 45 |
91 | 18 | 20 | 1F |
RIGHT | EXE | CAL | Y | I | = | LEFT |
P0 | P5 | Q | E |
% | C | SPACE | DOWN | |
E1 | E6 | EB | 93 |
37 | 34 | 31 | 30 |
E2 | E7 | 95 | 92 |
38 | 35 | 32 | 9E |
P1 | P6 | CONT. | MC |
7 | 4 | 1 | 0 |
P2 | P7 | M- | MR |
8 | 5 | 2 | 000 |
E3 | E8 | F0 | 94 |
39 | 36 | 33 | 2E |
E4 | E9 | F1 | 2F |
2A | 2D | 2B | 0D |
P3 | P8 | YES | M+ |
9 | 6 | 3 | . |
P4 | P9 | NO | / |
* | - | + | = |
Стандартный режим с Shift (EN + SHIFT)
60 | A3 | 88 | 82 |
85 | A2 | 5F | 18 |
7C | A1 | 81 | 8C |
87 | 5C | 7B | 00 |
' | ⌟ | ⌜ | _ | C |
¦ | □ | ¥ | { | |||||||
7E | 5B | 8A | 25 |
8E | 40 | 5D | 00 |
3F | 5E | 22 | 86 |
27 | 84 | 12 | 00 |
~ | [ | % |
@ | ] | ? | ^ | " | ' | INS | ||||||
EA | A4 | 80 | 8B |
83 | 29 | 3E | 04 |
1A | 7D | 89 | 24 |
8D | 8F | 3B | 0B |
PA | ﹨ | ) | > | SH.RL |
KANA | } | $ |
; | HOME | ||||||
06 | 0D | 03 | 00 |
26 | 28 | 3C | 02 |
E0 | E5 | 21 | 23 |
91 | 18 | 20 | 0C |
R.END | EXE | CAL | & | ( | < | L.TOP |
P0 | P5 | ! | # |
% | C | SPACE | CLS | |
E1 | E6 | EB | 93 |
37 | 34 | 31 | 30 |
E2 | E7 | 95 | 92 |
38 | 35 | 32 | 9E |
P1 | P6 | CONT. | MC |
7 | 4 | 1 | 0 |
P2 | P7 | M- | MR |
8 | 5 | 2 | 000 |
E3 | E8 | F0 | 94 |
39 | 36 | 33 | 2E |
E4 | E9 | F1 | 2F |
2A | 2D | 2B | 0D |
P3 | P8 | YES | M+ |
9 | 6 | 3 | . |
P4 | P9 | NO | / |
* | - | + | = |
Клавиши с кодом "8X" - это Box Drawing по таблице символов, но это не имеет значения, так как далее они переназначены для быстрого ввода команд BASIC.
Режим простого калькулятора (CALC)
38 | 32 | 00 | 00 |
00 | 31 | 37 | 9D |
39 | 33 | 00 | 00 |
00 | 30 | 36 | 00 |
8 | 2 | 1 | 7 | AC |
9 | 3 | 0 | 6 | |||||||
9A | 34 | 00 | 00 |
00 | 00 | 35 | 00 |
9B | 3A | 00 | 00 |
00 | 00 | 00 | 00 |
* | 4 | 5 | / | . | |||||||||||
F3 | 98 | 00 | 00 |
00 | 00 | 00 | 00 |
00 | 99 | 00 | 00 |
00 | 00 | 00 | 00 |
MODE | + | - | |||||||||||||
00 | 90 | 03 | 00 |
00 | 00 | 00 | 00 |
E0 | E5 | 00 | 00 |
91 | 9C | 00 | 00 |
EXE | CAL | P0 | P5 | % | C | ||||||||||
E1 | E6 | EB | 93 |
37 | 34 | 31 | 30 |
E2 | E7 | 95 | 92 |
38 | 35 | 32 | 9E |
P1 | P6 | CONT. | MC |
7 | 4 | 1 | 0 |
P2 | P7 | M- | MR |
8 | 5 | 2 | 000 |
E3 | E8 | F0 | 94 |
39 | 36 | 33 | 3A |
E4 | E9 | F1 | 9B |
9A | 99 | 98 | 90 |
P3 | P8 | YES | M+ |
9 | 6 | 3 | . |
P4 | P9 | NO | / |
* | - | + | = |
Сюда внесены оба набора клавиш цифр. Кода цифр и математических операторов не соответствуют таблице ASCII, а клавиши "C" и "AC" только в этом режиме имеют разные кода ("9C" и "9D" соответственно).
Режим ввода символов Кана (KANA)
38 | 32 | BD | C9 |
C7 | 31 | 37 | 18 |
39 | 33 | C6 | BF |
B0 | 30 | 36 | 00 |
8 | 2 | ス | ノ |
ヌ | 1 | 7 | C |
9 | 3 | ニ | ソ |
ー | 0 | 6 | |
2A | 34 | BC | B5 |
C1 | BA | 35 | 00 |
2F | 2E | B2 | C8 |
B7 | C3 | 11 | 00 |
* | 4 | シ | オ |
チ | コ | 5 | / | . | イ | ネ |
キ | テ | DEL | ||
F3 | 2B | C5 | BE |
DD | B9 | DF | 0E |
0F | 2D | BB | B4 |
C0 | C2 | C4 | 1E |
MODE | + | ナ | セ |
ン | ケ | ゚ | SHIFT |
CAPS | - | サ | エ |
タ | ツ | ト | UP |
1C | 0D | 03 | 00 |
B6 | B8 | DE | 1D |
E0 | E5 | B1 | B3 |
91 | 18 | 20 | 1F |
RIGHT | EXE | CAL | カ | ク | ゙ | LEFT |
P0 | P5 | ア | ウ |
% | C | SPACE | DOWN | |
E1 | E6 | EB | 93 |
37 | 34 | 31 | 30 |
E2 | E7 | 95 | 92 |
38 | 35 | 32 | 9E |
P1 | P6 | CONT. | MC |
7 | 4 | 1 | 0 |
P2 | P7 | M- | MR |
8 | 5 | 2 | 000 |
E3 | E8 | F0 | 94 |
39 | 36 | 33 | 2E |
E4 | E9 | F1 | 2F |
2A | 2D | 2B | 0D |
P3 | P8 | YES | M+ |
9 | 6 | 3 | . |
P4 | P9 | NO | / |
* | - | + | = |
Режим ввода символов Кана с Shift (KANA + SHIFT)
60 | A3 | D1 | DB |
D9 | A2 | 5F | 18 |
7C | A1 | D8 | D3 |
AD | 5C | 7B | 00 |
' | ⌟ | ム | ロ |
ル | ⌜ | _ | C |
¦ | □ | リ | モ |
ュ | ¥ | { | |
7E | 5B | D0 | AB |
D5 | CE | 5D | 00 |
3F | 5E | A8 | DA |
CB | DC | 12 | 00 |
~ | [ | ミ | ォ |
ユ | ホ | ] | ? | ^ | ィ | レ |
ヒ | ワ | INS | ||
EA | A4 | D7 | D2 |
AC | CD | AF | 04 |
1B | 7D | CF | AA |
D4 | D6 | A6 | 0B |
PA | ﹨ | ラ | メ |
ャ | ヘ | ッ | SH.RL |
EN | } | マ | ェ |
ヤ | ヨ | ヲ | HOME |
06 | 0D | 03 | 00 |
CA | CC | AE | 02 |
E0 | E5 | A7 | A9 |
91 | 18 | A5 | 0C |
R.END | EXE | CAL | ハ | フ | ョ | L.TOP |
P0 | P5 | ァ | ゥ |
% | C | ▪ | CLS | |
E1 | E6 | EB | 93 |
37 | 34 | 31 | 30 |
E2 | E7 | 95 | 92 |
38 | 35 | 32 | 9E |
P1 | P6 | CONT. | MC |
7 | 4 | 1 | 0 |
P2 | P7 | M- | MR |
8 | 5 | 2 | 000 |
E3 | E8 | F0 | 94 |
39 | 36 | 33 | 2E |
E4 | E9 | F1 | 2F |
2A | 2D | 2B | 0D |
P3 | P8 | YES | M+ |
9 | 6 | 3 | . |
P4 | P9 | NO | / |
* | - | + | = |
Назначение команд BASIC для быстрого ввода через Shift (BASIC COMMANDS)
14A3 | 169B | 1459 | 146C |
1457 | 146A | 147C | 1473 | |
INPUT | LOAD | SAVE |
LIST | CLEAR | DIM | WIDTH | ||
Z | X | B | N |
L | C | V | M | |
1449 | 144A | 144B | 1481 |
17C1 | 1482 | 148D | 1747 | 0000 |
GOTO | GOSUB | RETURN | FOR |
TO | NEXT | IF | THEN | |
D | A | S | F |
G | H | J | K |
Несуществующим клавишам, неиспользуемым клавишам каждого режима, а также клавише "RESET" выставлены нули, то есть во включённом состоянии калькулятор никак не мог бы реагировать на сброс.
По адресу &H040250 лежат использующиеся в калькуляторе имена файлов, и вот их полный список:
RAM0: CARD: COM0:
P0 P1 P2 P3 P4 P5 P6 P7 P8 P9 PA
D0 D1 D2 D3 D4 D5 D6 D7 D8 D9
Назначение и способ применения имён "RAM0" и "CARD" пока не обнаружены (выполнение GOTO "RAM0:P2" приводит к ошибке).
Далее, по адресу &H040300, хранятся адреса начала и конца единственной программы - "K0". Той самой, которая запускается при нажатии в отверстие "CONT." и используется для регулировки контраста и остальных скрытых функций, таких как приём и отправка образа RAM и проверка чексумм. Теперь понятно, о чём калькулятор пытался сообщить ошибкой "SN error K0‑20" до правильного выполнения RESET.
Адрес этой программы хранится в таком же виде, как и адреса пользовательских программ в RAM. Да и сама программа написана на BASIC. Сопоставляя байт за байтом я детокенизировал программу по тому же принципу, как и пользовательские программы.
10 WIDTH 12,2
20 KPRINT "955C,8EA6,945A,82AD,3A,59,45,53,20,20,20,20,9496,82AD,3A,4E,4F";
30 •$=INPUT$(1,@)
40 IF ASC(•$)=240 THEN CONTUP
50 IF ASC(•$)=241 THEN CONTDOWN
60 IF ASC(•$)=43 THEN 100
70 IF ASC(•$)=45 THEN 200
80 GOTO 30
100 CLS : PRINT "LOAD RAM","OK ?";
110 •$=INPUT$(1)
120 IF ASC(•$)=42 THEN GOSUB 300 : GOTO 100
130 IF ASC(•$)=47 THEN 400
140 IF ASC(•$)=240 OR ASC(•$)=13 THEN PRINT CHR$(24); : LOAD @ :ELSE END
200 CLS : PRINT "SAVE RAM","OK ?";
210 •$=INPUT$(1)
220 IF ASC(•$)=42 THEN GOSUB 300 : GOTO 200
230 IF ASC(•$)=47 THEN 400
235 ON ERROR GOTO 1000
240 IF ASC(•$)=240 OR ASC(•$)=13 THEN PRINT CHR$(24); : SAVE @ :ELSE END
250 ON ERROR GOTO 0
300 IF PEEK(&HD5F)=255 THEN CLS : PRINT "19200 BPS" : •$=INPUT$(1,@) : IF ASC(•$)=42 THEN POKE &HD5F,0 : GOTO 310 :ELSE RETURN
310 IF PEEK(&HD5F)><255 THEN CLS : PRINT "9600 BPS" : •$=INPUT$(1,@) : IF ASC(•$)=42 THEN POKE &HD5F,255 : GOTO 320 :ELSE RETURN
320 GOTO 300
400 CLS : PRINT," CHECK SUM"," PRESS(1-3)";
410 •$=INPUT$(1,@)
420 DEFSEG=0
430 ON ASC(•$)-48 GOTO 500,600,700
440 END
500 CLS:PRINT"PROG:";LRC$(PEEK&HCC8*256+PEEK&HCC7-1,&HFA0)," DIR:";LRC$(PEEK&HCEF*256+PEEK&HCEE+87,PEEK&HCEF*256+PEEK&HCEE);
510 •$=INPUT$(1,@)
520 GOTO 400
600 CLS:PRINT"FILE:";LRC$(PEEK&HCCB*256+PEEK&HCCA-1,&HFA0)," DIR:";LRC$(PEEK&HCEC*256+PEEK&HCEB+167,PEEK&HCEC*256+PEEK&HCEB);
610 •$=INPUT$(1,@)
620 GOTO 400
700 INPUT ""+CHR$(24)+"START?";@5;⌜
710 IF ⌜ < -32768 OR ⌜ > 65535 THEN 700
720 INPUT " END?";@5;⌟
730 IF ⌟ < -32768 OR ⌟ > 65535 THEN 720
740 IF ⌜ >= ⌟ THEN 700
750 CLS : PRINT " ";HEX$(⌜);"-";HEX$(⌟)," SUM:";LRC$(⌟,⌜);
760 •$=INPUT$(1,@)
770 GOTO 400
1000 PRINT,"PR error";:•$=INPUT$(1,@):END
Хотя можно было прописать эти адреса для "P0", а затем отправить "P0" на компьютер командой SAVE "COM0:". Как бы там ни было, теперь, имея программу, написанную производителем, можно увидеть в ней некоторые скрытые особенности синтаксиса:
- INPUT (скрытые особенности синтаксиса)
Пример 1: A$=INPUT$(1,@) - вводимый текст не отображается, выполнение продолжается после ввода указанного количества символов. Символ "@" отключает отображение курсора. Это очень полезно, так как избавляет от необходимости в использовании костыля вроде "100 GOTO 100" для остановки программы после выполнения!
Пример 2: INPUT "TEXT";@5;A - водимый текст отображается, выполнение продолжается только после нажатия "EXE", но ввод в данном случае ограничен 5-ю символами (при дальнейшем вводе заменяется последний). Хотя в режиме WIDTH,4 параметр, ограничивающий количество символов, может принимать и большее значение, в такой конструкции INPUT выдаёт "OV error" при вводе более 100 символов.
В первом случае нажатие клавиши "STOP" останавливает программу, а все остальные клавиши, такие как "000", "C", "AC" и тд, вводят код соответствующей клавиши. Во втором случае все клавиши выполняют свои функции: "STOP" выполняет роль "CAPS", "000" вводит три нуля, "C" и "AC" очищают ввод.
Интересно, что такие же скрытые возможности обнаружились и в FX‑860Pvc.
- ON ERROR GOTO 0
Отключает ранее объявленный в программе перехват ошибок и возвращает программу к стандартному поведению при их возникновении.
- SAVE @ и LOAD @
Для приёма и передачи полного образа RAM указывается символ "@" после SAVE и LOAD.
- KPRINT (разделители)
Данные для KPRINT для удобства можно писать через запятую. Причём оказалось, что вывод не изменится, даже если указать её между байтами двухбайтового символа. Главное, чтобы запятая не стояла между 16-ричными знаками одного байта.
Кроме этого, разработчики почему-то указывают лишний аргумент для количества символов в строке: WIDTH 12,2. Для очистки строки они используют вывод символа 24, выполняющего функцию "LINE cancel". Для сообщения об ошибке во время отправки образа RAM на компьютер выводят "PR error" в виде текста - вероятно, в прошивке CPU не предусмотрена ошибка на такой случай.
И теперь можно с большей уверенностью предположить, что выбор скорости для "COM0:" выполняется только заменой байта, ведь скорость приёма/передачи образа RAM в "K0" тоже меняется таким путём.
Начиная с адреса &H043A00 хранятся битовые карты символов. Очерёдность тетрад внутри каждого байта отличается от используемой для DEFCHR$ и соответствует принципу расположения пикселей в Display Area.
Область символов 6x8 пикселей для режима WIDTH,4 для наглядности можно разбить на блоки по 6 байт:
. . . . .
408001020400
C7A8292AC700
0024EF200000
2468A8292600
48282A2DC800
. . . . .
Эта область занимает 1536 байт - объём, требуемый ровно для 256 символов. Но, так как графических символов фактически 224, в нижней части остаётся пустая область в размере 32 символов.
Для поиска начала этой области я написал программу, превращающую данные, начиная с введённого адреса, в код для DEFCHR$ (с перестановкой тетрад), и выводящую на экран. Но удобнее было бы сразу копировать байты в Display Area. Например, следующий код выводит первые 64 символа:
10 FOR I=0 TO 383
20 DEFSEG=16384:A=PEEK(&H3A00+I)
30 DEFSEG=0:POKE(&H300+I),A
40 NEXT I
50 PRINT:K$=INPUT$(1,@)
Область символов 8x16 пикселей для режима WIDTH,2 можно разбить на блоки по 16 байт, каждый из которых в свою очередь разделить пополам, так как символ состоит из двух строк:
. . . . . . .
00F001020201F000 000F804040800F00
00008001F3000000 00000040CF400000
00C001020211E000 00C142444840C100
00C001121221C000 0003804040880700
0000106081F30000 00060A0242CF4200
. . . . . . .
Эта область также занимает объём, требуемый для 256 символов. Но в данном случае последние 32 ячейки хранят символы для режима простого калькулятора: часть первых 16-и содержит верхние символы, такие как математические операторы, "K", "E" и тд, а часть следующих 16-и - цифры.
Битовые карты символов однобайтовой части кодировки, кода которых попадают в диапазон начальных байтов двухбайтовой части, тут заполнены нулями.
Область символов 16x16 пикселей для двухбайтовых символов кодировки Shift JIS можно разбить на блоки по 30 байт (а не 32, как можно было бы подумать), каждый из которых в свою очередь также разделить пополам:
. . . . . . .
0074444444F7444444F74444447400 101F121212FF121212FF1212121F10
F30202F300744444F74444F7444474 0F02021E101E1212FF1212FF12121E
8090EF8080F0A0222222EF22222220 162A41814E2010121212FF12121210
F70444A5160004F48484F40404F704 FF0001010E00000F02020E0010FF00
020272424242424E42424242720202 909019E92A2C484C0B8848A8291210
. . . . . . .
Дело в том, что правый столбец пикселей в каждом символе, оставляемый пустым для отступов, не записан. Логично, что при большом количестве символов экономия 2-х байт на каждом позволяет в сумме сэкономить много памяти. Поэтому символ фактически хранится как 15x16 пикселей.
Если убрать пустую область с конца, получается, что для символов двухбайтовой кодировки выделено 108690 байт, а это значит, что всего таких символов 3623. Но, возможно, среди них тоже есть пустые, и реальное количество немного меньше.


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