[Из песочницы] Эмуляция Sinclair zx80/zx81

image

Многие согласятся, что возникшая пандемия COVID-19 изрядно попортила жизнь IT-сообществу. Но речь пойдет не о темной полосе, а о другом эпизоде.
Уже в марте была отменена известная demoparty Forever 2020, а позже мероприятие перенесено на осень. Задолго до отмены, я общался с организаторами. Они отказались принять одну мою работу, мотивируя тем, что нет Apple II, попросили взамен видео работы с реального компьютера.

Что же, получить запись мне не удалось, поэтому я обратил внимание на список платформ:
Amstrad CPC, Thomson, PMD-85, MSX, ZX81, Sam Coupe, all non-C=64 8-bit Commodores or any other 8-bit system

Меня привлек ZX81, так как я уже пытался изучить компьютер, но потерпел крах.

Исследования пошли по привычной для меня схеме:

Эмулятор


Я выбрал EightyOne
взял версию 1.6.1. У версии удобный отладчик, но программа не эмулирует другую модель — ZX80, позже я нашел другой билд 3.7.

Кросс-средства


Поиск вывел на FASM (топик на форуме, адаптированный для платформы. Однако, скомпилированные примеры не запускались. Я попробовал и другие варианты ассемблера — Pasmo и другие, но так и не собрал рабочую программу.

Долгие поиски вывели на пример печати Hello, world!

О, чудо! получилось! Теперь пришел черед к третьему эпизоду.

Документация


Часть информации нашлась тут
Дизассемблер ПЗУ здесь

Карта памяти:

0000-1FFF - ROM
2000-3FFF - Shadow ROM. Назначение не описано, иногда упоминается Interface 1
4000-7FFF - память 16К


Часть памяти отведена для системных переменных.

Далее по адресу 16509 хранится программа на Бейсике и её переменные.

Программа на Бейсике содержит формат:

2 байта номер строки в формате big endian
2 байта длина строки
... сама программа
1 байт ($76) - новая строка


Для кассеты возможны только программы на Бейсике, был предложен такой способ:

1 REM (бинарные данные или машинный код)
2 RANDOMIZE USR(16514) - тот самый адрес программы, хранящейся после REM


Следует обратить внимание на системную переменную D_FILE, которая указывает на видеопамять.

В указанном примере это реализовано так:

D_FILE:     defw    display_file

display_file:   defb    _NL
        defs    32
...
        defs    32
        defb    _NL


Первый байт — признак начала строки, затем 32 байта пробелы.

Так получилось 24 строки, что выглядело громоздко.

Первая программа, которую я написал:

image

;compile with sjasmplus
	device zxspectrum128

p_start:    org 0x4009
begin

VERSN:      defb    0
E_PPC:      defw    20      ; BASIC line number of line with cursor.
D_FILE:     defw    display_file2
DF_CC:      defw    display_file2+1
VARS:       defw    variables
DEST:       defw    0
E_LINE:     defw    edit_line
CH_ADD:     defw    p_end-1
X_PTR:      defw    0
STKBOT:     defw    p_end
STKEND:     defw    p_end
BERG:       defb    0
MEM:        defw    MEMBOT
SPARE1:     defb    0
DF_SZ:      defb    2       ; Number of lines in lower part of screen.
S_TOP:      defw    10      ; BASIC line number of line at top of screen.
LAST_K:     defw    0xffff
DB_ST:      defb    0
MARGIN:     defb    55      ; Blank lines above/below TV picture: US = 31, UK = 55.
NXTLIN:     defw    display_file    ; Memory address of next program line to be executed.
OLDPPC:     defw    0
FLAGX:      defb    0
STRLEN:     defw    0
T_ADDR:     defw    0x0c8d
SEED:       defw    0
FRAMES:     defw    0       ; Updated once for every TV frame displayed.
COORDS:     defw    0
PR_CC:      defb    0xbc
S_POSN:     defb    0x21,0x18
CDFLAG:     defb    0x40
PRBUF:      defs    0x20
        defb    _NL
MEMBOT:     defs    0x1e
SPARE2:     defw    0

; Start of the BASIC area for user programs.

basic_0001: defb    0,1     ; 1 REM
        defw    basic_0010-basic_0001-4
        defb    _REM

; Start of user machine code program
mem_16514:
	ld hl,p_end;display_file2
	push hl
;cls
	ld c,25
c1:
	ld b,32
	ld (hl),$76:inc hl
c2:
	ld (hl),0:inc hl
	djnz c2
	dec c
	jr nz,c1

	pop hl
	push hl
	ld c,$0
ylp:
	ld (hl),$76
	inc hl
	ld b,32
xlp:
	ld (hl),c
	inc hl
	inc c

	bit 6,c
	jr nz,endp;ret nz
	djnz xlp
	jr ylp
endp:
	pop hl
	ld (D_FILE),hl
	jr $
display_file2:
 dup 25
 defb _NL
 edup


end
	display /d,end-begin
	savebin "prb.p",begin,end-begin


Укороченный вариант подсказал этот топик.

Один недостаток: после загрузки программа не отображается нижняя строка. Это неудивительно, ведь строки пустые.Чтение руководств подсказало на еще одно изменение:

NXTLIN:     defw    basic_0010 ; адрес памяти выполняемой строки


Получился такой простой трюк: после загрузки не нужно набирать RUN, программа запустится сама.

Если коротко, то я опишу суть программы: сначала заполнение видеопамяти по образцу, как было в программе печати «Hello, world», затем заполнение строк символами с кодами 00–63.

image

При первой разработке я ошибся и написал заполнение символов с кодами 00–255, но программа не заработала, так как часть кодов не используется
Результатом исследований стала работа kerr, которая покажется неинтересной, но для меня сама программа — большое достижение.

А до проведения demoparty есть масса времени, которое будет потрачено на разработку программу в номинацию 1k.

Остался ZX80.

Для него есть другой порядок системных переменных.

Софт хранится здесь.

Поэтому я набрал программу и посмотрел в отладчике:

image

Здесь есть небольшое ограничение — память 1к, поэтому нужно подумать, какую программу написать.

Может быть, я напишу когда-нибудь.

© Habrahabr.ru