Тема: Звуковая плата для Агат на базе AY-8910
Привет, наконец-то я довел свой проект до того уровня, когда можно что-то показать.
Первоначальная задумка была в том, чтобы попробовать создать карту расширения для шины Apple II/Агат. Я долго думал, что будет делать этот девайс и решил, что звуковая карта на базе AY-8910/8912 – это лучший выбор, т.к. музычка это всегда весело 😊
Почитав Мымрина и книги по Apple II, решил что ничего сложного в этом нет. Заказал у китайцев макетные платы на основе разводки уважаемого Wierzbowsky только под размер 10х10.
После прихода плат собрал на макетке схему из буферного формирователя, логики и пары регистров, помигал светодиодами через запись в $C0x0-$C0xF.
Изучил еще раз схему включения AY-8910, а также прототипы подобных карт для Apple II и решил, что мне хватит одной АП6 и ЛЕ1 (ИЛИ-НЕ), т.к. все уже придумано до нас. За запись в AY номера регистра будет отвечать ячейка памяти $C0x1, а запись значения регистра - $C0x0. Запаял все на макетку и добавил модуль усилителя с ali.
Потом написал простецкую программу на бейсике, убедился, что звук есть. Для этого нужно было включить выход канала A в регистре R7, поднять громкость в R8 и задать частоту в R0(R1).
poke $C0E1,7 # R7 00000111
poke $C0E0,56 # 00111000 (0x38)
poke $C0E1,8 # R10 00001000
poke $C0E0,15 # 15 00001111
poke $C0E1,0 # R0
poke $C0E0,254 # FE
Пришло время писать музыкальный проигрыватель!
Потратил несколько вечеров на изучение Агат BASIC и особенностей встроенного мини-ассемблера, в итоге родился примерно следующий код. В видео финальная версия программы. https://youtu.be/xnIm5mABi5Q
70 DATL=$1D: DATH=$1E
75 DATEL=$BA: DATEH=$7B ; address of data end
80 PWAIT=$FB94
100 *$5000
110 ! LDA #$10 ; load start address
! STA DATL
! LDA #$70
! STA DATH
120 ! LOOP:
! LDA DATL ; compare current address
! CMP #DATEL ; with end address
! LDA DATH
! SBC #DATEH
! BCS QUIT ; quit if song has ended
130 ! LDY #$0 ; write 0 to Y
! LDA (DATL),Y ; load data to A
! CMP #$FF ; compare to $FF
! BEQ SLEEP ; jmp to delay
! STA $C0E1 ; write reg num to C0E1
140 ! INY ; inc Y
! LDA (DATL),Y ; load data to A
! STA $C0E0 ; write val to C0E0
! LDX #$2 ; write 2 inc cycles to X
150 ! IN1:
! INC DATL ; inc low byte
! BNE IN2 ; jump to loop if <=255
! INC DATH ; inc high byte
! JMP IN2 ; jump to loop
160 ! IN2:
! DEX ; decrement X
! BEQ LOOP ; if X==0 return to LOOP
! JMP IN1 ; increment one more time
170 ! SLEEP:
! LDA #$4F ; delay for ~ 16 ms
! JSR PWAIT
! LDX #$1
! JMP INC
180 ! QUIT:
! BRK
200 CALL ($5000)
В планах на будущее:
добавить на плату генератор прерываний с частотой 50hz, т.к. встроенный в агат работает на частоте 500hz для сигнала IRQ, а 50hz там только NMI, что тоже не удобно. Переписать код, чтобы он мог работать по прерыванию.
добавить в программу возможность выбора произвольного файла с музыкой.
самое главное, перейти на более экономный формат хранения AY/YM музыки, например, RSF
еще есть идея, прикрутить простой ЦАП типа КР572ПА1 для звуковых эффектов.
Но об этом в следующий раз!