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
58 F6 00
Область стека
CLEAR  ,Y
58 F6 00
58 F6 00
58 F9 00
58 F9 00
58 F9 00
Начало CHARACTER OPERATION STACK
0CD0
3
Начало STACK FREE AREA
0CD3
3
Начало DATA STACK
0CD6
3
Начало FOR STACK
0CD9
3
Начало GOSUB STACK
0CDC
3
Начало данных текстовых переменных
0CDF
3
58 F9 00
Область переменных
CLEAR X,
58 F9 00
58 FF 00
58 FF 00
Начало свободной области переменных
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
Символы DEFCHR$
при WIDTH,4
CHR$(252)
CHR$(253)
CHR$(254)
CHR$(255)
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
Символы DEFCHR$
при WIDTH,2
CHR$(252)
CHR$(253)
CHR$(254)
CHR$(255)
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
Символы DEFKAN$
32 => KPRINT "8120"
33 => KPRINT "8121"
34 => KPRINT "8122"
35 => KPRINT "8123"
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" и адресами файлов хранятся сами программы, файлы данных, стек, переменные и массивы. Их структуру хранения стоит рассмотреть отдельно.

Комментарии