PDA

Просмотр полной версии : ПК8000 - Ассемблер



scaraby
04.03.2016, 13:37
А кто каким ассемблером пользуется для написания программ для этого компьютера? В детстве я использовал ASSM, который поставлялся на кассете с системными программами. При его запуске упоминался в качестве автора некий товарищ Карабутов. Неудобство состояло в том, что код исполнялся сразу и без вопросов, поэтому любой неверный шаг приводил к зависанию и утомительной загрузке с кассеты среды программирования. Тем не менее, с помощью этой программы можно было заглянуть внутрь игр, что-то даже своё наваять. Однако ассемблер там однопроходной, метки при любом телодвижении нужно править вручную - это ад и израиль!

В настоящее время пользуюсь следующей технологией для создания готовых wav-файлов, пригодных для загрузки на реале:

1. Исходник пишу в "Прекрасный ассемблер КР580ВМ80А" онлайн по адресу http://asdasd.rpg.fi/~svo/i8080/ Туда же можно закидывать текстовые исходники, написанные в чём угодно, хоть в блокноте. В сравнении с ASSM - счастье просто! Результаты творческих изысканий отражаются справа в окне "на лету". Результатом работы является бинарник, который можно смело внедрять в память ПК8000 и запускать на выполнение.

2. В эмуляторе emu загружаю пакет ASSM командой bload"ASSM",r и для удобства сохраняю это состояние, чтобы одним кликом сразу попадать в ASSM. На реале эта процедура занимает несколько минут: поиск на кассете, загрузка, ошибки загрузки, если плохой магнитофон и т.д.

3. Находясь в ASSM внутри emu выбираю пункт меню View/Start Debugger. Далее в открывшемся окне Ctrl+L (загрузить бинарник), указываю адрес в который грузить содержимое бинарника. Этот адрес является тем же адресом, который указывается директивой .org в "Прекрасном". После выполнения загрузки директивой ASSM-a G - запускаю на выполнение загруженный фрагмент кода.

4. Чтобы загрузить этот код в реальный ПК8000, использую директиву ASSM-а W ИмяФайла АдресНачала АдресКонца АдресЗапуска. Например W TEST01 4000 4100 4002. Не забываю при этом перед нажатием Enter включить кнопку "Record/Stop" на панели эмулятора emu и выбираю соответствующий wav файл, готовый для загрузки.

5. Если не нужен wav, а cas, то не использую команду "Record/Stop", директива W обрабатывается эмулятором и создаёт корректный cas.

Технология получилась вполне рабочая и проверена практикой, однако, несколько громоздкой. Может, у кого-то есть опыт или идеи, как проще пройти путь от текстового исходника до реального wav?

- - - Добавлено - - -

Ну и вдогонку, в качестве примера небольшой исходник, который в графическом режиме зажигает точку на экране в выбранной позиции, ждёт нажатия упр-стоп и выходит в ASSM. На реале в Бейсик.

;ПК8000
;Прекрасный ассемблер КР580ВМ80А
;http://asdasd.rpg.fi/~svo/i8080/

;Программа определяет адрес байта в массиве графики для графического курсора
;Массив графики располагается в адресах ОЗУ 0000h-17ffh
;Нумерация идёт по принципу знакомест 32х24. Знакоместо (0,0) имеет адреса
;0000h-0007h, (0,1) 0008h-000fh, (1,0) 0100h-0107h и т.д.
;в hl - искомый адрес видео озу, с - номер бита точки на которую указывает
;графический курсор. a - маска для операции с точкой (гашение/свечение)

.binfile GraphCursor.bin
.org 4000h ;начальный адрес программы в ОЗУ

;Чтение байта из видеоОЗУ. 004ah hl - адрес, a - байт
VRAMRead equ 004ah

;Включение режима экрана. Точка входа в ПЗУ: 006Ah или 286Dh A=режим {0,1,2}

Screen equ 286dh

;Опрос нажатия Упр+Стоп.3759h Если «Упр+Стоп», то флаг C:=1

CtrlBreak equ 3759h

;Возврат в СПА

Exit equ 0ea8ah

GraphCursor db 00h,00h ;координаты графического курсора x,y (0-255,0-191)

Start:

mvi a,02h ;выбор номера режима
call Screen ;установка режима 2

;модуль определения адреса искомого байта в видеоОЗУ

lhld GraphCursor ;координаты курсора в привычной форме
mov a,l ;взяли координату х
ani 07h ;в аккумуляторе остаток от деления x/8
;это - номер (положение) точки внутри байта в массиве графики
inr a ;используется как счётчик при формировании маски
mov c,a ;запоминаем его в регистре c

mov a,l ;взяли повторно координату х
ani 0f8h ;отбросили остаток от деления x/8
;это - адрес нулевого байта соответствующего знакоместа
mov l,a ;запоминаем его в регистре l

mov a,h ;взяли координату y
ani 07h ;остаток от деления x/8 - номер строки внутри знакоместа
add l ;прибавили его к адресу нулевого байта знакоместа
mov l,a ;младший полубайт адреса готов.

mov a,h ;взяли координату y
ani 0f8h ;отбросили остаток от деления y/8
rrc
rrc
rrc ;разделили нацело y/8
mov h,a ;старший полубайт адреса готов

;формируем в аккумуляторе маску для видеоОЗУ

xra a ;инициализация маски. Записываем в аккумулятор 01h
inr a
loop01:
rrc ;устанавливаем соответствующий бит маски
dcr c ;номер бита, полученный ранее из координаты x
jnz loop01

;зажигаем точку на экране

loop02:
mov c,a ;зажигаем одну точку, не изменяя соседние маска в с
call VRAMRead ;прочитали байт из массива графики
ora c ;добавили точку к прочитанному
mov m,a ;сохранили результат

EventLoop:
call CtrlBreak ;опрос клавиатуры
jnc EventLoop


mvi a,0h ;выбор номера режима
call Screen ;установка режима 0

call Exit ;возврат в СПА

DemonId7
04.03.2016, 17:08
Пользуюсь макроассемблером M80. Точнее кроссассемблером. Его макроязык похож на привычный TASM и MASM, хотя довольно примитивный. Вместо оболочки использую встроенный редактор файлового менеджера Folder Manager, неплохо справляющийся с подсветкой текста.
Компилирую либо в CAS, применив соответствующий заголовок, либо в COM. CAS можно сразу загружать в эмулятор по BLOAD (пару секунд по времени занимает), либо конвертировать в WAV и загрузить на реальный. Конвертирую в CAS2COM. Загружаю любым плеером, выставив в настройках режим MONO. COM-файлы в Total Commander можно записать в образ диска/винта, для CP/M.

scaraby
09.03.2016, 10:06
Это речь об вот этом идёт?

http://www.retroarchive.org/cpm/lang/MACRO-80.PDF

Если я правильно понял, то он под CP/M работает? Как вы его под Windows запускаете? Через эмулятор или в какой-то среде?

DemonId7
09.03.2016, 10:59
О нем. Только под платформу PC: M80 (http://a-moa.chat.ru/ma80.htm)
В аттаче шаблоны для компиляции в CAS и COM.
К сожалению в свободном доступе только незарегистрированная версия, с серьезными ограничениями.

Еще могу порекомендовать поискать файлик с макросами к Turbo Assembler. Он вроде поддерживает все команды 8080. Сам наверное на него перейду, надоели ограничения незарегистрированной версии M80, это не считая "родных" ограничений.
Непонимаю я этих писак - делать ограничения на продукт, которым будут пользоваться лишь десяток-другой любителей? Глупость, по моему. Ну да не мне их судить :)

hantarex
10.03.2016, 08:37
есть TASM(Telemark Assembler). поддерживает 8080/8085/Z80. правда он под дос. и насчет мнемоник 8080 не уверен.

scaraby
18.03.2016, 16:26
Продолжаю упражняться в программировании на ассемблере. На этот раз нарисовал сетку на экране, прикрутил клавиатуру, чтобы двигать точку по экрану, не вылезая за пределы. Разумеется, всё это в графическом режиме. Потрясающий размер программы в коде: 240 байт! Массив цвета пока не трогаю. Точка перемещается по экрану с шагом в один пиксель, поддерживается диагональное перемещение при одновременном нажатии двух кнопок. Скорость перемещения такая, что все фазы перемещения точки не успевают отрисовываться на экране. Состояние VRAM изменяется быстрее, чем к ней обращается "видеокарта".


;ПК8000
;Прекрасный ассемблер КР580ВМ80А
;http://asdasd.rpg.fi/~svo/i8080/

;Программа позволяет клавишами управления курсором перемещать точку по
;экрану. Процедура определения адреса точки в видео-ОЗУ и маски выделена
;в отдельный модуль, который вызывается из процедур "зажигания" и
;"гашения" точки.

.binfile GraphCursor.bin
.org 4000h ;начальный адрес программы в ОЗУ

;---------------------------------------------------------------------------------
; Константы
;---------------------------------------------------------------------------------

;Включение режима экрана. Точка входа в ПЗУ: 006Ah или 286Dh A=режим {0,1,2}
Screen equ 286dh

;Опрос нажатия Упр+Стоп.3759h Если «Упр+Стоп», то флаг C:=1
CtrlBreak equ 3759h

;Возврат в СПА
Exit equ 0ea8ah

;---------------------------------------------------------------------------------
; Переменные
;---------------------------------------------------------------------------------

GraphCursor db 0ah,0ah ;координаты графического курсора x,y (0-255,0-191)
AdressVRAMCursor db 0,0
BackgroundCursor db 0

;область в ОЗУ, в которой сохраняется состояние клавиатурной матрицы
Keyboard db 0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0ffh

;---------------------------------------------------------------------------------
; Главный модуль
;---------------------------------------------------------------------------------

Start:

mvi a,02h ;выбор номера режима
call Screen ;установка режима 2

call Grid ;рисуем на фоне сетку

Drawing:

call GetAdressCursor ;определение адреса и маски точки в массиве графики
shld AdressVRAMCursor
xra b ;зажигаем точку
mov m,a ;кладём её в видео-ОЗУ
lxi h,BackgroundCursor
mov m,b ;сохраняем состояние

EventLoop:
call KeyPress ;опрос клавиатуры
jz EventLoop

lxi h,BackgroundCursor
mov b,m ;восстанавливаем видео-ОЗУ
lhld AdressVRAMCursor
mov m,b

;нажатие и анализ
lxi h, Keyboard+8 ;адрес строки с состоянием кнопок управления курсором
mov b, m ;запоминаем это состояние, чтобы не дёргать ОЗУ постоянно

mvi a, 0ffh ;сбросили клавиатуру в исходное состояние
mov m, a

lhld GraphCursor ;помещаем в de координаты графического курсора
xchg

mvi a, 080h ;нажата стрелка вправо?
ana b
cz MoveRight

mvi a, 040h ;нажата стрелка вниз?
ana b
cz MoveDown


mvi a, 020h ;нажата стрелка вверх?
ana b
cz MoveUp


mvi a, 010h ;нажата стрелка влево?
ana b
cz MoveLeft

xchg
shld GraphCursor

call CtrlBreak
jnc Drawing


mvi a,0h ;выбор номера режима
call Screen ;установка режима 0

call Exit ;возврат в СПА

;---------------------------------------------------------------------------------
; Процедуры
;---------------------------------------------------------------------------------

;изменение координат графического курсора

MoveDown:

mvi a, 0c0h ;нижний предел экрана x=192
inr d ;координата y:=y+1
cmp d
rnz ;всё в порядке, мы внутри, штатная ситуация
dcr d ;отмена изменения координаты курсора
ret

MoveUp:
mvi a, 0ffh ;верхний предел экрана y=-1 (логически)
dcr d ;координата y:=y-1
cmp d
rnz ;всё в порядке, мы внутри, штатная ситуация
inr d ;отмена изменения координаты курсора
ret


MoveRight:

xra a ;правый предел экрана x=256 (логически)
inr e ;координата х:=х+1
cmp e
rnz ;всё в порядке, мы внутри, штатная ситуация
dcr e ;отмена изменения координаты курсора
ret


MoveLeft:

mvi a, 0ffh ;левый предел экрана x=-1 (логически)
dcr e ;координата х:=х-1
cmp e
rnz ;всё в порядке, мы внутри, штатная ситуация
inr e ;отмена изменения координаты курсора
ret
;---------------------------------




;Процедура опроса клавиатуры и регистрации нажатых клавиш
;Идея состоит в том, чтобы опросить состояние строк клавиатурной матрицы
;и запомнить его в ОЗУ для дальнейшего анализа
;если флаг Z=0, то ничего не нажато
;hl - адрес последней строки формируемого массива
;b - текущее состояние порта 82h
;с - счётчик количества строк клавиатуры (0ah)
;d - флаг нажатия. Если ничего не нажато, то 0ffh

KeyPress:
di
lxi h, Keyboard+9 ;адрес ОЗУ, в который сохраняем состояние кнопок
mvi c, 0ah ;счётчик количества строк клавиатуры (10)
in 82h ;читаем порт, чтобы не потерять его состояние
ani 0f0h ;формируем в младшем полубайте номер строки клавиатуры
adi 09h ;опрос от 9-й строки к 0-й
mvi d, 0ffh ;флаг нажатия. Если нажато, появляются нулевые биты

loop001:
out 82h ;выбираем текущую строку клавиатуры
mov b, a ;сохраняем состояние порта 82h
in 81h ;читаем состояние текущей строки
mov m,a ;сохранили состояние текущей строки в массиве KeyPress
ana d ;если есть нажатие, то появятся нулевые биты
mov d, a ;запоминаем любые нули, важно их наличие в принципе
dcx h ;очередной байт в массиве KeyPress
dcr b ;очередная строка клавиатурной матрицы
dcr c ;счётчик количества строк
mov a,b ;формируем данные для выбора следующей строки
jnz loop001

mvi a,0ffh ;проверка наличия нажатых клавиш
xra d ;флаг Z=0, если имеется хотя бы один нулевой бит
ei
ret
;---------------------------------



;Процедура определяет адрес байта в массиве графики для графического курсора
;Массив графики располагается в адресах ОЗУ 0000h-17ffh
;Нумерация идёт по принципу знакомест 32х24. Знакоместо (0,0) имеет адреса
;0000h-0007h, (0,1) 0008h-000fh, (1,0) 0100h-0107h и т.д.
;в hl - искомый адрес видео озу, с - счётчик, номер бита точки на которую
;указывает графический курсор, b - байт, извлечённый из видео-ОЗУ
;a - маска для операции с точкой (гашение/свечение)
;

;Временно по найденной координате зажигается точка.


GetAdressCursor:
lhld GraphCursor ;координаты курсора в привычной форме
mov a,l ;взяли координату х
ani 07h ;в аккумуляторе остаток от деления x/8
;это - номер (положение) точки внутри байта в массиве графики
inr a ;используется как счётчик при формировании маски
mov c,a ;запоминаем его в регистре c

mov a,l ;взяли повторно координату х
ani 0f8h ;отбросили остаток от деления x/8
;это - адрес нулевого байта соответствующего знакоместа
mov l,a ;запоминаем его в регистре l

mov a,h ;взяли координату y
ani 07h ;остаток от деления x/8 - номер строки внутри знакоместа
add l ;прибавили его к адресу нулевого байта знакоместа
mov l,a ;младший полубайт адреса готов.

mov a,h ;взяли координату y
ani 0f8h ;отбросили остаток от деления y/8
rrc
rrc
rrc ;разделили нацело y/8
mov h,a ;старший полубайт адреса готов

xra a ;формируем в аккумуляторе маску для видеоОЗУ
inr a ;инициализация маски. Записываем в аккумулятор 01h
loop002:
rrc ;устанавливаем соответствующий бит маски
dcr c ;номер бита, полученный ранее из координаты x
jnz loop002
mov c,a ;сохранили маску в регистр c

;извлечение байта данных из видео-ОЗУ, сохраняем в регистре b

di ;обработчики прерываний в ПЗУ, поэтому запрещаем прерывания
in 80h ;сохраняем состояние порта 80h в регистре d
mov d,a
mvi a,0ffh ;записываем в порт 80h единицы, тем самым выбирая ОЗУ для
out 80h ;всех диапазонов адресов
mov b,m ;читаем байт из видеоОЗУ в регистр b
mov a,d ;восстанавливаем конфигурацию адресного пространства
out 80h

mov a,c ;кладём маску в аккумулятор
ei ;разрешаем прерывания
ret
;---------------------------------




;Процедура Grid рисования сетки на экране

Grid:

lxi h,1800h ;чтобы сработало тело цикла при нулевом значении "+1"
mvi c,08h ;считаем попутно байты внутри знакоместа
Grid001:
dcx h
mvi m,81h ;рисуем вертикальные линии
dcr c
jnz Grid002
mvi m,0ffh ;в нужных местах вертикальные линии заменяем горизонтальными
mvi c,08h
Grid002:
mvi a,07h ;в нижней строке знакоместа тоже горизонтальная линия
cmp c
jnz Grid003
mvi m,0ffh
Grid003:
mov a,l ;проверяем, досчитали до нуля или ещё нет
ora h
jnz Grid001
ret

Если кому интересно, как это работает в эмуляторе, ниже файл состояния эмулятора EMU. Разархивируем, открываем файл из EMU, попадаем сразу в Debugger, в нём жмём F5, оказываемся в среде ASSM, в которой подаём команду на запуск G 400F. Возврат в ASSM по нажатию Ctrl+F12 (Упр+Стоп).

56505

Следующим шагом хочу сделать плавное перемещение спрайта 8 на 8 пикселей. Что меня всегда бесило в играх на ПК8000 - дискретное "тырканье" по знакоместам. Интересно выяснить, это проблема аппаратной реализации, нехватки быстродействия, чтобы обрабатывать плавную анимацию, или криворукость программистов.

MacBuster
29.05.2018, 09:20
Скорость перемещения такая, что все фазы перемещения точки не успевают отрисовываться на экране.
Насколько я понимаю, здесь скорость перемещения точки никак не регулируется т.к. нет привязки к кадровым прерываниям.

Как это можно сделать?

ivagor
29.05.2018, 09:37
В данной программе (GraphCursor) проще всего добавить ei до EventLoop: и hlt после.

ivagor
15.12.2018, 15:15
Адаптировал рисование окружностей (а также эллипсов и дуг) с вектора (https://zx-pk.ru/threads/29144-programmirovanie-na-assemblere.html?p=989448&viewfull=1#post989448) на ПК8000. По векторовской ссылке есть немного дополнительной информации.

- - - Добавлено - - -

Забыл написать, выход в бейсик по пробелу.
И как только выложил сообразил, что в рисовании точки можно обойтись без DE, соответственно будет быстрее.

ivagor
16.12.2018, 11:00
Перетащил на ПК8000 еще и недавний векторовский paint с маской. В комплекте идет circle с оптимизированной точкой. Выход в бейсик - пробел.
Отмечу, что цвет в данных процедурах никак не затрагивается. Добавить можно, только будет еще запутаннее и медленнее.