Casio PD-700 — Часть 5: структура и разметка RAM
Имея полный дамп содержимого RAM, а также дамп, нужный для полноценной передачи задуманным производителем методом, стоит разобраться, как устроена память. Во-первых, это просто интересно и иногда пригождается для написания программ с использованием команд PEEK и POKE, во-вторых, это необходимо понимать для возможности собирать образ с программами BASIC, а в-третьих, всегда есть вероятность обнаружить новые скрытые возможности!
Путём поиска закономерностей, множественных экспериментов и сравнений, и, естественно, методом тыка мне удалось понять основные моменты (в случае выявления новых деталей информация будет дополняться).
Общая структура памяти имеет следующий вид:
000000 | Screen text buffer area | 256 B |
000100 | 256 B | |
000200 | System Work Buffer | 256 B |
000300 | Display dot buffer | 1536 B |
000900 | System Text Buffer | 258 B |
000A02 | 256 B | |
000B02 | 192 B | |
000BC2 | 258 B | |
000CC4 | Parameter Area (Область параметров) | 732 B |
000FA0 | Programs and Data files (Программы и файлы Data) | 59064 B |
00F658 | Stack Area - CLEAR ,Y (Область стека) | 768 B |
00F958 | Variable Area - CLEAR X, (Область переменных) | 1536 B |
00FF58 | Data file addresses (Адреса файлов Data) | 80 B |
00FFA8 | Program addresses (Адреса программ) | 88 B |
010000 |
При выполнении "CLEAR X,Y" начало области переменных вычисляется как начало области адресации минус X, а начало области стека - начало области переменных минус Y.
Хотя "Screen text buffer area" и заполняется при выводе текста на экран, запись данных напрямую в эту область не влияет на отображаемое, как это работало на FX‑840P. Для отображаемого имеет значение только "Display dot buffer", в котором изображение хранится попиксельно, а не в виде текста. Для отображения данных после его заполнения необходимо заставить экран обновиться, например, переходом на новую строку пустой командой "PRINT".
Соответствие точек дисплея битам в памяти:
Как видно, строк здесь 16, а не 4: это потому что в памяти PD‑700 хранится виртуальный дисплей с разрешением 128x96 пикселей. Тут стоит заметить, что виртуальный дисплей в 2 раза выше, чем у других моделей, будь то FX‑880P или PB‑1000, так как он в то же время и в 2 раза короче. Это составляет 16 строк при стандартном размере символов или 8 строк при увеличенном.
Для включения выбранного пикселя сначала нужно вычислить адрес 8-битного столбца, в котором он находится, по формуле 768 + 90 * номер строки + номер столбца. Затем записать в этот адрес номер пикселя в столбце (очерёдность тетрад отличается от используемой для DEFCHR$). Для включения нескольких пикселей в одном столбце нужно в этот адрес записать сумму номеров пикселей.
В документации к FX‑880P весь диапазон от начала до области программ, включая названную мной "Parameter Area", называют "System Area". Но в нашем случае эту область стоит рассмотреть отдельно, так как с неё начинается передача образа, и она содержит все системные параметры. Ниже приведена таблица с содержимым области "Parameter Area" (все числовые значения хранятся в little-endian).
Описание | Адрес | Байт | Данные по умолчанию | |||||||
|---|---|---|---|---|---|---|---|---|---|---|
Начало области файлов программ | 0CC4 | 3 | A0 0F 00 | |||||||
Начало области файлов данных | 0CC7 | 3 | AB 0F 00 | |||||||
Начало свободной области файлов | 0CCA | 3 | B5 0F 00 | |||||||
Начало I/O BUFFER | 0CCD | 3 |
| |||||||
Начало CHARACTER OPERATION STACK | 0CD0 | 3 | ||||||||
Начало STACK FREE AREA | 0CD3 | 3 | ||||||||
Начало DATA STACK | 0CD6 | 3 | ||||||||
Начало FOR STACK | 0CD9 | 3 | ||||||||
Начало GOSUB STACK | 0CDC | 3 | ||||||||
Начало данных текстовых переменных | 0CDF | 3 |
| |||||||
Начало свободной области переменных | 0CE2 | 3 | ||||||||
Начало данных числовых переменных | 0CE5 | 3 | ||||||||
Начало имён переменных | 0CE8 | 3 | ||||||||
Начало области адресов файлов "D" | 0CEB | 3 | 58 FF 00 | |||||||
Начало области адресов файлов "P" | 0CEE | 3 | A8 FF 00 | |||||||
Верхняя граница памяти | 0CF1 | 3 | 00 00 01 | |||||||
Адрес имени прошивки в ROM | 0CF4 | 3 | 08 00 04 | |||||||
Адрес начала адресации на карте | 0CF7 | 3 | 00 00 00 | |||||||
Адрес конца адресации на карте | 0CFA | 3 | 00 00 00 | |||||||
Адрес для CONT (после STOP) | 0CFD | 3 | 00 00 00 | |||||||
Адрес элемента DATA для READ | 0D00 | 3 | 00 00 00 | |||||||
Адрес адреса программы с ON ERROR | 0D03 | 3 | 00 03 04 | |||||||
Адрес строки для ON ERROR GOTO | 0D06 | 3 | 65 09 04 | |||||||
0D09 | 1 | 00 | ||||||||
Номер строки, вызвавшей ошибку | 0D0A | 2 | 00 00 | |||||||
Адрес оператора, вызвавшего ошибку | 0D0C | 3 | 00 00 00 | |||||||
Номер ошибки (есть в списке PB-1000) | 0D0F | 1 | 00 | |||||||
Значение DEFSEG | 0D10 | 2 | 00 00 | |||||||
Состояние BRK (ON / OFF) | 0D12 | 1 | 00 | |||||||
Адрес адреса текущего файла | 0D13 | 3 | 00 03 04 // В данный момент - K0 | |||||||
Номер выполняемой строки | 0D16 | 2 | F0 00 // В данный момент - 240 | |||||||
Адрес выполняемого (после ":") | 0D18 | 3 | 1C 06 04 | |||||||
(*) | 0D1B | 1 | 00 | |||||||
Устройство вывода (Экран=0, COM0:=8) | 0D1C | 1 | 00 | |||||||
Адрес буффера? | 0D1D | 3 | 00 00 00 | |||||||
(*) | 0D20 | 1 | 00 | |||||||
Адрес буффера символов для вывода? | 0D21 | 3 | 00 00 00 | |||||||
Тип назнч. перем. NUM=&H14, STR=&H10 | 0D24 | 1 | 00 | |||||||
0D25 | 1 | 00 | ||||||||
Адрес назначаемой переменной в коде | 0D26 | 3 | 97 05 04 | |||||||
Контраст | 0D29 | 2 | 70 8F | |||||||
OD2B | 3 | 00 00 00 | ||||||||
Адрес для продолжения после INPUT | 0D2E | 3 | 00 00 00 | |||||||
0D31 | 3 | 00 00 99 | ||||||||
Стартовое число для рандома (в LE) | 0D34 | 7 | 30 90 81 44 29 34 04 | |||||||
Введённая клавиша | 0D3B | 1 | F0 | |||||||
0D3C | 16 | 00 72 72 6F 72 00 00 00 00 00 00 00 00 00 00 00 | ||||||||
Число в памяти режима калькулятора | 0D4C | 6 | 00 00 00 00 00 00 | |||||||
0D52 | 2 | 00 00 | ||||||||
Единица измерения угла (ANGLE) | 0D54 | 1 | 00 | |||||||
Пароль | 0D55 | 8 | FF FF FF FF FF FF FF FF | |||||||
0D5D | 2 | C0 34 | ||||||||
Скорость при приёме/передаче RAM | 0D5F | 1 | FF | |||||||
0D60 | 16 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ||||||||
|
0D70 | 6 | 85 FF 05 C2 12 FF | |||||||
0D76 | 6 | 20 C0 0F C0 20 00 | ||||||||
0D7C | 6 | AA 55 AA 55 AA 55 | ||||||||
0D82 | 6 | 00 00 00 00 00 00 | ||||||||
|
0D88 | 16 | 11 61 F7 41 90 F7 80 00 0C 00 8F 00 88 8F 00 00 | |||||||
0D98 | 16 | 00 00 30 C7 30 00 00 00 80 0F 00 00 00 0F 80 00 | ||||||||
0DA8 | 16 | 55 AA 55 AA 55 AA 55 00 55 AA 55 AA 55 AA 55 00 | ||||||||
0DB8 | 16 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ||||||||
|
0DC8 | 32 | 00 00 00 00 00 00 ....... 00 00 00 00 00 00 | |||||||
0DE8 | 32 | 00 00 00 00 00 00 ....... 00 00 00 00 00 00 | ||||||||
0E08 | 32 | 00 00 00 00 00 00 ....... 00 00 00 00 00 00 | ||||||||
0E28 | 32 | 00 00 00 00 00 00 ....... 00 00 00 00 00 00 | ||||||||
0E48 | 1 | 00 | ||||||||
Адрес данных после INPUT | 0E49 | 3 | 00 00 00 | |||||||
0E4C | 6 | 00 00 00 00 00 00 | ||||||||
Оператор в режиме калькулятора | 0E52 | 1 | 00 | |||||||
Число в режиме калькулятора | 0E53 | 7 | 00 00 00 00 00 00 00 | |||||||
Адрес буффера (в Parameter/System) | 0E5A | 3 | 00 00 00 | |||||||
Настройки связи для "COM0:" | 0E5D | 2 | 66 02 | |||||||
0E5F | 23 | 00 00 00 00 00 00 ....... 00 00 00 00 00 00 | ||||||||
Буфер | 0E76 | 118 | 00 00 00 00 00 00 ....... 00 00 00 00 00 00 | |||||||
Координаты DRAW | 0EEC | 4 | 00 00 00 00 | |||||||
0EF0 | 176 | 00 00 00 00 00 00 ....... 00 00 00 00 00 00 |
Описание организации некоторых данных из "Parameter Area":
- BRK ON/OFF - &H0D12:
"&H00"=ON, "&HFF"=OFF. При ручной замене любое значение кроме "&H00" - это OFF.
- Контраст - &H0D29:
Первый байт может иметь значение от &H00 (светлый) до &H80 (тёмный) с шагом 4 (всего 33 уровня), а второй для нормальной работы должен оставаться &H8F. Судя по всему, это адрес в ROM (little-endian).
При ручной замене вступает в силу только при изменении контраста или после перезагрузки. Если значение не соответствует ожидаемому, то при регулировке контраст меняется непредсказуемо, а второй байт всегда возвращается к значению &H8X.
- Число в памяти калькулятора (Memory) - &H0D4C:
После перестановки в порядок big-endian первые 5 байт содержат число в формате BCD (10 десятичных цифр).
Следующая тетрада хранит знак числа и экспоненты:
- "3" (0011) – число положительно, экспонента отрицательна.
- "4" (0100) – число положительно, экспонента положительна.
- "B" (1011) – число отрицательно, экспонента отрицательна
- "C" (1100) – число отрицательно, экспонента положительна.
Последняя тетрада - сама экспонента (только 1 знак, так как в режиме простого калькулятора он не работает при переполнении). Отрицательная экспонента хранится как 16 минус значение.
Пример: число 1234 будет записано как "1234000000 4 3", что в little-endian выглядит как "430000003412".
Отсутствие числа - только "000000000000".
- Единица измерения угла (ANGLE) - &H0D54:
"00"=DEG, "01"=RAD, "02"=GRAD.
- Пароль - &H0D55:
Каждый байт равен &HFF минус ASCII код цифры пароля (например, это может быть побитовый NOT). Отсутствующий пароль - это "&HFFFFFFFFFFFFFFFF".
Пример: пароль 123 будет сохранен как "&HCECDCCFFFFFFFFFF".
- Оператор в режиме калькулятора - &H0E52:
Значение битов в первой тетраде:
введён | конст. | оператор | HEX | |
|---|---|---|---|---|
1 | 0 | 00 | "+" | 8 |
1 | 0 | 01 | "-" | 9 |
1 | 0 | 10 | "*" | A |
1 | 0 | 11 | "/" | B |
1 | 1 | 00 | "K+" | C |
1 | 1 | 01 | "K-" | D |
1 | 1 | 10 | "K*" | E |
1 | 1 | 11 | "K/" | F |
Вторая тетрада: если на экране 0, тогда "1", в других случаях "0", при переполнении "E".
- Число в режиме калькулятора - &H0E53:
Тут, как и c числом, хранящемся в Memory, для удобства переставим байты в порядок big-endian.
Первая тетрада всегда "0", далее 10 десятичных цифр, знак и экспонента хранятся так же, как и в Memory.
Последняя тетрада хранит способ получения числа:
- "0" (0000) - получено в результате вычисления.
- "1" (0001) - выведено из Memory.
- "5" (0101) - вводится целое число.
- "6" (0110) - вводится десятичная дробь.
При вводе с клавиатуры число записывается с конца, а при получении в результате вычислений или при выводе из Memory – с начала (соответственно меняется и экспонента).
Пример: введённое число "5" хранится как "0 0000000005 4 9 5" => "95540000000000", а полученное в результате вычислений - "0 5000000000 4 0 0" => "00040000000005".
- Скорость при приёме/передаче образа RAM заводским методом - &H0D5F:
"&H00"=9600 bps, "&HFF"=19200 bps. При ручной замене любое значение кроме "&HFF" - это 9600.
- Настройки связи по RS-232C для "COM0:" - &H0E5D:
Это самое интересное, и я думаю, что единственный способ изменить эти параметры - это замена байта с помощью POKE, так как в FX‑603P скорость тоже меняется подменой байта.
Первый байт - &H0E5D:
- bit 1 (+&H80) - STOP BIT (0=1, 1=2)
- bit 2 (+&H40) - DATA LENTH (0=7, 1=8)
- bit 3 (+&H20) - PARITY ON/OFF (0=OFF, 1=ON)
- bit 4 (+&H10) - PARITY EVEN/ODD (0=EVEN, 1=ODD)
- bit 5 (+&H08) - Not Used
- bit 6 7 8 (+&H00..&H07) - BAUD RATE, 19200 / 2^X (000=19200, 001=9600, 010=4800, 011=2400, 100=1200, 101=600, 110=300, 111=150)
Начальное значение: &H66 (01100110) - STOP BIT 1, DATA LENTH 8, PARITY ON, EVEN, 300 bps. Для изменения скорости, например, на 9600 bps, нужно выполнить "POKE &H0E5D, &H61".
- 150 bps - "67" 01100111
- 300 bps - "66" 01100110
- 600 bps - "65" 01100101
- 1200 bps - "64" 01100100
- 2400 bps - "63" 01100011
- 4800 bps - "62" 01100010
- 9600 bps - "61" 01100001
- 19200 bps - "60" 01100000
Передача на компьютер на скорости 19200 работает нормально, но при приёме часто выдаёт "PO error". Максимальная, работающая в обе стороны, скорость - 9600. Но даже так, это вдвое выше, чем у FX‑880P при схожем процессоре.
Второй байт - &H0E5E:
- bit 1 (+&H80) - DS (Data Set Ready) (0=OFF, 1=ON)
- bit 2 (+&H40) - CD (Carrier Detect) (0=OFF, 1=ON)
- bit 3 (+&H20) - CS (Clear to Send) (0=OFF, 1=ON)
- bit 4 5 6 - Not Used
- bit 7 (+&H02) - XON/XOFF (0=OFF, 1-ON)
- bit 8 - Not Used
Начальное значение: &H02 (00000010) - DS OFF, CD OFF, CS OFF, XON/XOFF ON.
В самом конце RAM, начиная с адреса &HFF58, хранятся адреса программ и файлов Data.
Start End File name H3 H2 H1 H6 H5 H4 H7 H8 | ||
|---|---|---|
00FF58 | B4 0F 00 B5 0F 00 44 39 B3 0F 00 B4 0F 00 44 38 B2 0F 00 B3 0F 00 44 37 B1 0F 00 B2 0F 00 44 36 B0 0F 00 B1 0F 00 44 35 AF 0F 00 B0 0F 00 44 34 AE 0F 00 AF 0F 00 44 33 AD 0F 00 AE 0F 00 44 32 AC 0F 00 AD 0F 00 44 31 AB 0F 00 AC 0F 00 44 30 | D9 D8 D7 D6 D5 D4 D3 D2 D1 D0 |
00FFA8 | AA 0F 00 AB 0F 00 50 41 A9 0F 00 AA 0F 00 50 39 A8 0F 00 A9 0F 00 50 38 A7 0F 00 A8 0F 00 50 37 A6 0F 00 A7 0F 00 50 36 A5 0F 00 A6 0F 00 50 35 A4 0F 00 A5 0F 00 50 34 A3 0F 00 A4 0F 00 50 33 A2 0F 00 A3 0F 00 50 32 A1 0F 00 A2 0F 00 50 31 A0 0F 00 A1 0F 00 50 30 | PA P9 P8 P7 P6 P5 P4 P3 P2 P1 P0 |
010000 |
Адреса начала и конца занимают по 3 байта и записаны перед именами в little-endian. Начало области программ – &H000FA0. Далее, если программа или файл Data отсутствует, конец сдвигается на 1 байт. Так, к примеру, программа "P0" начинается с адреса &H000FA0 и заканчивается на &H000FA1. При отсутствии программы в её области хранится единственный байт со значением &H00, означающий конец программы, а при отсутствии файла Data, в его области хранится байт &H1A, означающий конец данных. Таким образом, пользователю доступно на 21 байт меньше (59043 из 59064). При изменении длины любой программы, адреса следующих сдвигаются и содержимое всех следующих программ также сдвигается, чтобы обеспечить непрерывность данных. Это напоминает дефрагментацию в реальном времени.
Ну а между "Parameter Area" и адресами файлов хранятся сами программы, файлы данных, стек, переменные и массивы. Их структуру хранения стоит рассмотреть отдельно.

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