Визуализатор для ZX Spectrum и MSX или с Днем Радио, Гики

в 21:09, , рубрики: demo, demoscene, diy или сделай сам, MSX, zx spectrum, визуализация данных, Демосцена, математика, Программирование
Визуализатор для ZX Spectrum и MSX или с Днем Радио, Гики - 1

Сегодня принимают поздравления с профессиональным праздником некоторые гики, ну и чтобы поднять настроение себе и остальным, захотелось поделиться историей создания красочного, светодиодного, радиотехнического… И да! для вечно живого Z80!

Если вы не представляете, что ещё можно такого придумать для Z80 в XXI веке, прошу под кат...

Когда под моим прошлым постом посвященным демо Bad Apple для MSX, @DolphinSoftнаписал: "Пускай это будет не последнее творение под MSX", то я подумал "Ну уж нет, хватит, нечто новое для Z80 придумать сложно!". Но уже вскоре вдруг пришло желание разнообразить вечерний просмотр демо. Преимуществом MSX перед множеством других моделей компьютеров на Z80 является наличие слота, в который обычно устанавливаются картриджи ROM с играми/программами. Так как слот в большинстве случаев располагается сверху, то визуальный картридж было бы интересно разместить именно в этом слоте, в верхней части картриджа.

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

Звук в стандарте компьютера MSX реализуется микросхемой трехканального генератора звука Yamaha YM2149, регистры управления которой располагаются на портах 0xA0 и 0xA1. И, к счастью, в слоте картриджа все сигналы для записи в порт присутствуют и их можно перехватить.

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

Таким образом, какие задачи должен решать такой картридж:

  1. размещаться в слот MSX

  2. перехватывать запись в порты микросхемы звукового генератора

  3. анализировать значения записанных звуковых нот и визуализировать их

На конец 90х годов - начало 2000х уже начали появляться PLD средней степени интеграции MAX7000 серии, в частности EPM7128 содержащие 128 блоков логики с регистром на выходе. И, что приятно, они совместимы с 5В уровнями Z80, не требуют микросхемы для хранения прошивки, имеют достаточно большое количество выводов для подключения диодов, доступны сейчас и дешевы в закупке.

Чтобы убедиться в возможности разработки на такой небольшой микросхеме, было проведено математическое моделирование визуализатора с одновременной разработкой проекта под PLD. Запись в порт с реальных игр и демо была записана на эмуляторе openMSX и далее обработана в математической модели PLD на Matlab. Результат работы такой модели на видео, где справа работа 9-ти индикаторов частот аудионот, записываемых в звукогенератор YM2149.

Распределение кодов нот записываемых в звуковой генератор. Данное распределение использовалось для последующей нормализации выдачи различных участков диапазонов нот, чтобы они более равномерно визуализировались. Значительная часть низких нот практически не встречается.
Распределение кодов нот записываемых в звуковой генератор. Данное распределение использовалось для последующей нормализации выдачи различных участков диапазонов нот, чтобы они более равномерно визуализировались. Значительная часть низких нот практически не встречается.

После разработки математической модели визуализатора была проведена работа по упрощению кода PLD таким образом, чтобы логическая схема разместилась в 128 логических блоках EPM7128. В какой-то момент удалось найти баланс между упрощением модели визуализации и плотным заполнением выбранной PLD.

Код пришлось максимально облегчить: собственно захватывается адрес регистра YM2149 при записи в порт 0xA0, далее, в зависимости от адреса, захватывается либо частота ноты, либо её уровень громкости. Значение уровня громкости загружается в один из девяти счетчиков светодиодных баров. С целью упрощения используются не все биты частоты и громкости.

немного кода PLD
 cnt_to_3[] = cnt_div.q[15..14];
	(spec[8..0], cnt_div).clock = gclk;
	(RegAddr[], FreqA[], FreqB[], FreqC[], ValA[], ValB[], ValC[]).clk = gclk;
    
    RegAddr[] = data[3..0];
    RegAddr[].ena = !wr&!ioreq&(addr[7..0]==H"A0");
        
    (FreqA[3..2], FreqB[3..2], FreqC[3..2]) = data[7..6];
    (FreqA[6..4], FreqB[6..4], FreqC[6..4]) = data[2..0]#data[3];    
    ( ValA[2..0],  ValB[2..0],  ValC[2..0]) = data[3..1];     
    FreqA[3..2].ena = !wr&!ioreq&(addr[7..0]==H"A1")&(RegAddr[]==H"00");
    FreqB[3..2].ena = !wr&!ioreq&(addr[7..0]==H"A1")&(RegAddr[]==H"02");
    FreqC[3..2].ena = !wr&!ioreq&(addr[7..0]==H"A1")&(RegAddr[]==H"04");
    FreqA[6..4].ena = !wr&!ioreq&(addr[7..0]==H"A1")&(RegAddr[]==H"01");
    FreqB[6..4].ena = !wr&!ioreq&(addr[7..0]==H"A1")&(RegAddr[]==H"03");
    FreqC[6..4].ena = !wr&!ioreq&(addr[7..0]==H"A1")&(RegAddr[]==H"05");
    ValA[].ena      = !wr&!ioreq&(addr[7..0]==H"A1")&(RegAddr[]==H"08");
    ValB[].ena      = !wr&!ioreq&(addr[7..0]==H"A1")&(RegAddr[]==H"09");
    ValC[].ena      = !wr&!ioreq&(addr[7..0]==H"A1")&(RegAddr[]==H"0A");

    spec[0].cnt_en = !spec[0].cout&cnt_div.cout;        
	  spec[1].cnt_en = (spec[1].q[]>0)&cnt_div.cout; -- (spec[7].q[]>0);           
	  spec[2].cnt_en = (spec[2].q[]>0)&cnt_div.cout; -- (spec[7].q[]>0);           
	  spec[3].cnt_en = (spec[3].q[]>0)&cnt_div.cout; -- (spec[7].q[]>0);           
	  spec[4].cnt_en = (spec[4].q[]>0)&cnt_div.cout; -- (spec[7].q[]>0);           
	  spec[5].cnt_en = (spec[5].q[]>0)&cnt_div.cout; -- (spec[7].q[]>0);           
	  spec[6].cnt_en = (spec[6].q[]>0)&cnt_div.cout; -- (spec[7].q[]>0);           
    spec[7].cnt_en = (spec[7].q[]>0)&cnt_div.cout; -- (spec[7].q[]>0);           
    spec[8].cnt_en = (spec[8].q[]>0)&cnt_div.cout; -- (spec[8].q[]>0); 
                  
    if !wr&!ioreq&(addr[7..0]==H"A1") then
		if (RegAddr[]==H"00")#(RegAddr[]==H"01")#(RegAddr[]==H"08") then
			Val_ch[] = ValA[];
			spec[8].sload = (FreqA[6..2] <H"02");
			spec[7].sload = (FreqA[6..2]>=H"02")&(FreqA[6..2] <H"03");			
			spec[6].sload = (FreqA[6..2]>=H"03")&(FreqA[6..2] <H"05");			
			spec[5].sload = (FreqA[6..2]>=H"05")&(FreqA[6..2] <H"07");			
			spec[4].sload = (FreqA[6..2]>=H"07")&(FreqA[6..2] <H"0A");			
			spec[3].sload = (FreqA[6..2]>=H"0A")&(FreqA[6..2] <H"0C");			
			spec[2].sload = (FreqA[6..2]>=H"0C")&(FreqA[6..2] <H"0F");			
			spec[1].sload = (FreqA[6..2]>=H"0F")&(FreqA[6..2] <H"18");			
			spec[0].sload = (FreqA[6..2]>=H"18");
		end if;
		if (RegAddr[]==H"02")#(RegAddr[]==H"03")#(RegAddr[]==H"09") then
			Val_ch[] = ValB[];
			spec[8].sload = (FreqB[6..2] <H"02");
			spec[7].sload = (FreqB[6..2]>=H"02")&(FreqB[6..2] <H"03");			
			spec[6].sload = (FreqB[6..2]>=H"03")&(FreqB[6..2] <H"05");			
			spec[5].sload = (FreqB[6..2]>=H"05")&(FreqB[6..2] <H"07");			
			spec[4].sload = (FreqB[6..2]>=H"07")&(FreqB[6..2] <H"0A");			
			spec[3].sload = (FreqB[6..2]>=H"0A")&(FreqB[6..2] <H"0D");			
			spec[2].sload = (FreqB[6..2]>=H"0D")&(FreqB[6..2] <H"0F");			
			spec[1].sload = (FreqB[6..2]>=H"0F")&(FreqB[6..2] <H"18");			
			spec[0].sload = (FreqB[6..2]>=H"18");					
		end if;
		if (RegAddr[]==H"04")#(RegAddr[]==H"05")#(RegAddr[]==H"0A") then
			Val_ch[] = ValC[];
			spec[8].sload = (FreqC[6..2] <H"02");
			spec[7].sload = (FreqC[6..2]>=H"02")&(FreqC[6..2] <H"03");			
			spec[6].sload = (FreqC[6..2]>=H"03")&(FreqC[6..2] <H"05");			
			spec[5].sload = (FreqC[6..2]>=H"05")&(FreqC[6..2] <H"07");			
			spec[4].sload = (FreqC[6..2]>=H"07")&(FreqC[6..2] <H"0A");			
			spec[3].sload = (FreqC[6..2]>=H"0A")&(FreqC[6..2] <H"0D");			
			spec[2].sload = (FreqC[6..2]>=H"0D")&(FreqC[6..2] <H"0F");			
			spec[1].sload = (FreqC[6..2]>=H"0F")&(FreqC[6..2] <H"18");			
			spec[0].sload = (FreqC[6..2]>=H"18");				
		end if;
    end if;     
    
    spec[0].data[] = Val_ch[];   
    spec[1].data[] = Val_ch[];
    spec[2].data[] = Val_ch[];
    spec[3].data[] = Val_ch[];
    spec[4].data[] = Val_ch[];
    spec[5].data[] = Val_ch[];
    spec[6].data[] = Val_ch[];
    spec[7].data[] = Val_ch[];
    spec[8].data[] = Val_ch[];

Когда математическая модель получилась, наступило время приступать к разработке схемы, которая была максимально упрощена: не используются транзисторы или повторители для диодов, а с целью недопущения перегрузки портов PLD диоды разделены на три группы, которые мультиплицируются, не используются стабилизаторы напряжения и генератор. Все резисторы выбраны 1кОм. Такая схема предельно проста, и может быть собрана радиолюбителем.

Схема визуализатора
Схема визуализатора

Плата в сборе
Плата в сборе

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

Ну и, конечно же, сразу захотелось добавить аналогичный визуализатор и для своего любимого Скорпиона 256к. Для этого потребовалось разработать подставку для установки слота и картриджа, а также припаять на порты микросхемы AY-3-8910 сигналы

Плата визуализатора в поставке перед корпусом Скорпа
Плата визуализатора в поставке перед корпусом Скорпа
Монтаж сигналов к микросхеме звука Скорпиона YM2149F
Монтаж сигналов к микросхеме звука Скорпиона YM2149F
Картридж для ZX Spectrum и элементы корпуса из полупрозрачного пластика
Картридж для ZX Spectrum и элементы корпуса из полупрозрачного пластика

Ну и, конечно же, теперь можно посмотреть любимые демо в новом оформлении =)

ну и видео в корпусе с другими цветами на Скорпионе

Теперь просмотр дем на ZX Spectrum и MSX не будет прежним!

Ну и, наверное, самое главное. Проект локализован группой RBSC и является открытым, каждый может собрать и произвести такой визуализатор для себя. Ссылка на страничку проекта: MSX-EQ PSG Spectrolyzer для платформы MSX.

и проекты на github для MSX и для ZX Spectrum.

Всем кто захочет собрать - легкой сборки, буду рад вашим фото и видео в комментариях =)

Большое спасибо группе RBSC, World_of_MSX, а также всем, кто оказывал поддержку и помогал в тестировании. Очень приятно творить, ощущая вашу поддержку.

Всех с Днем Радио! За связь без брака! 73!

Автор:
Pyhesty

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js