- PVSM.RU - https://www.pvsm.ru -
После появления идеи добавления второго дисплея к Commodore 64 я довольно быстро реализовал этот проект. Все «железо» уместилось в картридж стандартного размера (вместе с коннектором DE-15). Видеовыход совместим с VGA (31 кГц).
Внутри картриджа — 128 КБ SRAM для кадрового буфера и простой 1-битный ЦАП.
Вот так выглядит плата, размещенная внутри картриджа. Загрузить исходник можно здесь [1].
Картридж можно поместить в любую часть 64 КБ адресного пространства, включая I/O1 или I/O2. Есть Verilog код для представления либо в окне в буфере кадра @EXPROM, что заберет 8 КБ памяти Basic, либо основанный на регистрах подход, экономящий оперативную память.
В приведенных примерах для регистров управления используется I/O1 на $DE00. У вас может возникнуть желание изменить поданный пример, если есть конфликт с каким либо другим эддоном (второй SID-чип и т.п.). В целом, существует поддержка специального токена, который позволяет избежать конфликтов, но у меня нет дополнительного ПО, которое эти конфликты вызывает.
Регистры
IOBASE = token
IOBASE+1 = lsb address
IOBASE+2 = msb address
IOBASE+3 = data
Кадровый буфер — линейный, использовать его несложно, подобно собственным режимам C64 с растровым отображением. В SRAM его начало — $00000.
Вне зависимости от выбранного режима видео выводится с pixel rate в 25 МГц благодаря встроенному генератору 100 МГц. Этот параметр близок к стандарту в 25,175 МГц для экрана с разрешением 640x480 при FPS 60 Гц. Соответственно, любой подключаемый мною дисплей показывал изображение корректно и без проблем. Вертикальная и горизонтальная синхронизация, а также области гашения настроены на правильную полярность и длину для запуска этого режима. Возможны две интерпретации данных кадрового буфера: режим высокого разрешения 640x480 1 бит на пиксель и многоцветный режим низкого разрешения 320x480. Оба режима — palette direct.
Аппаратное обеспечение достаточно простое: регулятор 3,3 В, CPLD, генератор и SRAM. SRAM тратит половину своего времени на ответы хосту, и еще половину — на загрузку пиксельных данных. Используемый здесь CPLD, Xilinx 95144XL, устойчив к 5 В, поэтому он установлен на шине расширения C64, хотя и запитан от регулятора 3,3 В вместе с остальным оборудованием.
Используются почти все ресурсы CPLD. Я надеялся поместить один аппаратный спрайт для указателя, но для этого просто не осталось места.
Для тех, кто будет печатать кулеры, в модели STL есть все необходимое, причем в стиле C64.
Важный момент — вам понадобится программатор JTAG для загрузки битового потока в CPLD.
И еще — картридж не работает с платой Ultimate 64. Более того, установка картриджа на эту плату может вызвать повреждение картриджа. Зато все работает со всеми версиями плат C64, C128 и C64 Reloaded. Точно не знаю, совместим ли картридж со всеми версиями C64 или C128, выпущенными Commodore, но я никаких проблем не вижу.
Я использовал Xilinx ISE 14.5, поскольку не нашел открытого набора инструментов для этих CPLD. Если у кого-то есть такая информация, то поделитесь.
В режиме высокого разрешения каждый бит соответствует одному пикселю. 1 = белый, 0 = черный. Адреса перемещаются от (0,0) в верхнем левом наиболее видимом положении к нижнему правому (639 479), по столбцу, затем по строке. Бит 7 в каждом байте — это первый пиксель.
В многоцветном режиме пиксели выводятся с той же скоростью, что и в монохромном режиме, но каждый цветовой канал имеет разное разрешение. Зеленый — это 1/2 pixel rate, а красный и синий — 1/4 pixel rate. Сопоставление битового шаблона с цветовым каналом побайтно (фрагментарно) и составляет:
G0 G1 G2 G3 R0 R1 B0 B1
В то время как экранное представление каждого байта буфера кадра выглядит следующим образом:
R0 R0 R0 R0 R1 R1 R1 R1
G0 G0 G1 G1 G2 G2 G3 G3
B0 B0 B0 B0 B1 B1 B1 B1
Преобразование изображений для отображения с помощью ImageMagick, монохромный режим:
convert input.tiff -resize 640x480 -colors 2 -depth 1 output.mono
Цветной режим:
convert input.tiff +dither -posterize 2 -resize 640x480 output.tiff
convert output.tiff -separate channel%d.png
Код написан на Python — мне этот вариант показался самым простым:
from PIL import Image
from array import *
import numpy as np
ir = Image.open("channel0.png")
ig = Image.open("channel1.png")
ib = Image.open("channel2.png")
ir = ir.resize((640,480))
ig = ig.resize((640,480))
ib = ib.resize((640,480))
r = ir.load()
g = ig.load()
b = ib.load()
arr=np.zeros((480,80,8))
out=np.zeros((480,640))
for y in range(0,480):
for x in range(0,80):
# 0 1 2 3 is green level
# 4 5 is red level
# 6 7 is blue level
# GREEN
arr[y][x][0]=(g[x*8+0,y]+g[x*8+1,y])/2
arr[y][x][1]=(g[x*8+2,y]+g[x*8+3,y])/2
arr[y][x][2]=(g[x*8+4,y]+g[x*8+5,y])/2
arr[y][x][3]=(g[x*8+6,y]+g[x*8+7,y])/2
# RED
arr[y][x][4]=(r[x*8+0,y]+r[x*8+1,y]+r[x*8+2,y]+r[x*8+3,y])/4
arr[y][x][5]=(r[x*8+4,y]+r[x*8+5,y]+r[x*8+6,y]+r[x*8+7,y])/4
#BLUE
arr[y][x][6]=(b[x*8+0,y]+b[x*8+1,y]+b[x*8+2,y]+b[x*8+3,y])/4
arr[y][x][7]=(b[x*8+4,y]+b[x*8+5,y]+b[x*8+6,y]+b[x*8+7,y])/4
for y in range(0,480):
for x in range(0,80):
for bit in range(0,8):
arr[y][x][bit] = int(round(round(arr[y][x][bit])/255))
newfile=open("output.bin","wb")
for y in range(0,480):
for x in range(0,80):
out[y][x] = int(arr[y][x][0] + arr[y][x][1]*2 + arr[y][x][2]*4 + arr[y][x][3]*8
+ arr[y][x][4]*16 + arr[y][x][5]*32 + arr[y][x][6]*64 + arr[y][x][7]*128)
newfile.write(out[y][x].astype(np.ubyte))
newfile.close()
Демонстрационное видео:
Собираем и припаиваем:
По этой ссылке можно загрузить [1] все необходимые для работы файлы.
Автор: Trifida
Источник [2]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/diy/365158
Ссылки в тексте:
[1] можно здесь: https://github.com/rkbrooks/vg64
[2] Источник: https://habr.com/ru/post/562176/?utm_source=habrahabr&utm_medium=rss&utm_campaign=562176
Нажмите здесь для печати.