225 lines
11 KiB
NASM
225 lines
11 KiB
NASM
; ═══════════════════════════════════════════════════════════════════════════
|
||
; Модуль ISR - 2734 Гц, обработчик прерывания
|
||
; ═══════════════════════════════════════════════════════════════════════════
|
||
;
|
||
; Архитектура: ВСЕ значения для регистров INT предрассчитаны в таблице.
|
||
; ISR читает 3 байта через 3×OUTI — НИКАКИХ вычислений!
|
||
;
|
||
; Частота: 3,500,000 / 1280 = 2734.375 Hz (~44100/16, разница ~0.8%)
|
||
; Цикл: 56 тиков × 1280 = 71680 позиций = 1 видеокадр → ИДЕАЛЬНОЕ замыкание
|
||
; Таблица: 56 × 5 = 280 байт
|
||
;
|
||
; При 14 МГц с wait-state (~x2.5): ~3200 эффективных тактов между тиками.
|
||
;
|
||
; Коды команд:
|
||
; CMD_WRITE_B0 = #40 [#40, reg, val, pad] → OUT OPL3_B0_ADDR/DATA
|
||
; CMD_WRITE_B1 = #80 [#80, reg, val, pad] → OUT OPL3_B1_ADDR/DATA
|
||
; CMD_WAIT = #C0 [#C0, lo, hi, pad] → ISR_WAIT_CTR = HL
|
||
; CMD_END_BUF = #E0 [#E0, pad,pad, pad] → переключить буфер
|
||
; ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
; Коды команд (= смещение от ISR_HANDLER, определены в vgmplayer.asm)
|
||
; CMD_WRITE_B0 = #40, CMD_WRITE_B1 = #80, CMD_WAIT = #C0, CMD_END_BUF = #E0
|
||
|
||
; ═══════════════════════════════════════════════════════════════════════════
|
||
; ISR_INIT - Инициализация таблицы векторов IM2 и указателя позиции
|
||
; ═══════════════════════════════════════════════════════════════════════════
|
||
ISR_INIT:
|
||
DI
|
||
|
||
; --- Заполнить таблицу векторов IM2 (257 байт, выровнено по 256) ---
|
||
LD HL,IM2_TABLE
|
||
LD DE,IM2_TABLE+1
|
||
LD A,LOW ISR_HANDLER
|
||
LD (HL),A
|
||
LD BC,256
|
||
LDIR
|
||
LD HL,IM2_TABLE+#100
|
||
LD (HL),HIGH ISR_HANDLER
|
||
|
||
; Установить регистр I
|
||
LD A,HIGH IM2_TABLE
|
||
LD I,A
|
||
|
||
; --- Разрешить только прерывание FRAME ---
|
||
LD BC,PORT_INTMASK
|
||
LD A,%00000001 ; только FRAME
|
||
OUT (C),A
|
||
|
||
; --- Инициализировать указатель позиции ---
|
||
LD HL,POS_TABLE
|
||
LD (POS_PTR),HL ; храним в переменной
|
||
|
||
; --- Инициализировать счётчик ожидания ---
|
||
LD HL,0
|
||
LD (ISR_WAIT_CTR),HL
|
||
|
||
; --- Записать начальную позицию в железо: строка 0, hpos 0 ---
|
||
LD BC,PORT_HSINT
|
||
XOR A
|
||
OUT (C),A ; HSINT = 0
|
||
LD B,HIGH PORT_VSINTL
|
||
OUT (C),A ; VSINTL = 0
|
||
LD B,HIGH PORT_VSINTH
|
||
OUT (C),A ; VSINTH = 0
|
||
|
||
; Переключиться в IM2
|
||
IM 2
|
||
RET
|
||
|
||
; ═══════════════════════════════════════════════════════════════════════════
|
||
; ISR_HANDLER - прерывание FRAME (2734 Гц)
|
||
; ─── OUTI-блок и таблицу не трогать! ────────────────────────────────────
|
||
; Команды: CMD_WRITE_B0=#40, CMD_WRITE_B1=#80, CMD_WAIT=#C0, CMD_END_BUF=#E0
|
||
; ═══════════════════════════════════════════════════════════════════════════
|
||
ISR_HANDLER:
|
||
PUSH AF
|
||
PUSH HL
|
||
PUSH BC
|
||
PUSH DE
|
||
|
||
; ─── OUTI×3: вывести позицию INT из таблицы (не трогать!) ───────
|
||
LD HL,(POS_PTR)
|
||
LD BC,#25AF ; B=#25, C=#AF
|
||
OUTI ; B→#24, OUT #24AF,(HL++) → VSINTH
|
||
OUTI ; B→#23, OUT #23AF,(HL++) → VSINTL
|
||
OUTI ; B→#22, OUT #22AF,(HL++) → HSINT
|
||
LD A,(HL) ; next_lo
|
||
INC HL
|
||
LD H,(HL) ; next_hi
|
||
LD L,A ; HL = next_ptr
|
||
LD (POS_PTR),HL
|
||
|
||
; ─── SECOND_TIMER: счётчик секунд (ВСЕГДА, независимо от WAIT_CTR) ──
|
||
LD HL,(SECOND_TIMER)
|
||
DEC HL
|
||
LD A,H
|
||
OR L
|
||
LD (SECOND_TIMER),HL
|
||
JR NZ,ISR_NO_SEC
|
||
; Секунда истекла
|
||
LD HL,ISR_FREQ
|
||
LD (SECOND_TIMER),HL
|
||
LD HL,(PLAY_SECONDS)
|
||
INC HL
|
||
LD (PLAY_SECONDS),HL
|
||
ISR_NO_SEC:
|
||
|
||
; ─── WAIT_CTR: если 0 — идти выполнять команды ──────────────────
|
||
LD HL,(ISR_WAIT_CTR)
|
||
LD A,H
|
||
OR L
|
||
JP Z,ISR_EXEC_CMD
|
||
DEC HL
|
||
LD (ISR_WAIT_CTR),HL
|
||
|
||
ISR_EXIT:
|
||
XOR A
|
||
OUT (#FE),A ; DEBUG: чёрный = выход из ISR
|
||
POP DE
|
||
POP BC
|
||
POP HL
|
||
POP AF
|
||
EI
|
||
RET
|
||
|
||
; ─── Exec-путь ───────────────────────────────────────────────────────────
|
||
ISR_EXEC_CMD:
|
||
LD A,(ISR_ENABLED)
|
||
OR A
|
||
JP Z,ISR_EXIT
|
||
LD HL,(ISR_READ_PTR)
|
||
EX DE,HL ; DE = указатель потока команд
|
||
|
||
ISR_CMD_LOOP:
|
||
LD A,(DE)
|
||
INC DE
|
||
CP CMD_WRITE_B0 ; #40
|
||
JP Z,ISR_WRITE_B0
|
||
CP CMD_WRITE_B1 ; #80
|
||
JP Z,ISR_WRITE_B1
|
||
CP CMD_WAIT ; #C0
|
||
JP Z,ISR_DO_WAIT
|
||
; CMD_END_BUF (#E0) — любое другое значение тоже сюда
|
||
ISR_DO_END_BUF:
|
||
LD A,2
|
||
OUT (#FE),A ; DEBUG: красный = смена буфера
|
||
LD A,(ISR_ACTIVE_BUF)
|
||
XOR 1
|
||
LD (ISR_ACTIVE_BUF),A
|
||
JR NZ,ISR_END_USE_B
|
||
LD DE,CMD_BUF_A
|
||
JP ISR_CMD_LOOP ; продолжать в новом буфере!
|
||
ISR_END_USE_B:
|
||
LD DE,CMD_BUF_B
|
||
JP ISR_CMD_LOOP ; продолжать в новом буфере!
|
||
|
||
ISR_WRITE_B0:
|
||
LD A,6
|
||
OUT (#FE),A ; DEBUG: жёлтый = запись OPL3
|
||
LD A,(DE) ; reg
|
||
LD BC,OPL3_ADDR0 ; B=0, C=#C4 → полный адрес порта #00C4
|
||
OUT (C),A
|
||
INC DE
|
||
LD A,(DE) ; val
|
||
LD BC,OPL3_DATA0 ; B=0, C=#C5 → полный адрес порта #00C5
|
||
OUT (C),A
|
||
INC DE
|
||
INC DE ; pad
|
||
JP ISR_CMD_LOOP
|
||
|
||
ISR_WRITE_B1:
|
||
LD A,6
|
||
OUT (#FE),A ; DEBUG: жёлтый = запись OPL3
|
||
LD A,(DE) ; reg
|
||
LD BC,OPL3_ADDR1 ; B=0, C=#C6 → полный адрес порта #00C6
|
||
OUT (C),A
|
||
INC DE
|
||
LD A,(DE) ; val
|
||
LD BC,OPL3_DATA1 ; B=0, C=#C7 → полный адрес порта #00C7
|
||
OUT (C),A
|
||
INC DE
|
||
INC DE ; pad
|
||
JP ISR_CMD_LOOP
|
||
|
||
ISR_DO_WAIT:
|
||
LD A,(DE) ; wait_lo
|
||
INC DE
|
||
LD L,A
|
||
LD A,(DE) ; wait_hi
|
||
INC DE
|
||
LD H,A ; HL = wait counter
|
||
INC DE ; pad
|
||
LD (ISR_WAIT_CTR),HL
|
||
EX DE,HL
|
||
LD (ISR_READ_PTR),HL ; сохранить позицию потока
|
||
JP ISR_EXIT
|
||
|
||
; ─── Переменные ISR ──────────────────────────────────────────────────────
|
||
POS_PTR: DW POS_TABLE ; указатель на текущую запись в таблице
|
||
SECOND_TIMER: DW ISR_FREQ ; обратный счётчик 2734 → 0 = 1 секунда
|
||
|
||
|
||
; ═══════════════════════════════════════════════════════════════════════════
|
||
; Таблица векторов IM2 (выравнивание по 256 байт, размер 257 байт)
|
||
; ═══════════════════════════════════════════════════════════════════════════
|
||
ALIGN 256
|
||
IM2_TABLE:
|
||
DS 257
|
||
|
||
; ═══════════════════════════════════════════════════════════════════════════
|
||
; Командные буферы (двойная буферизация)
|
||
; ═══════════════════════════════════════════════════════════════════════════
|
||
ALIGN 4
|
||
CMD_BUF_A:
|
||
DS CMD_BUF_SIZE
|
||
CMD_BUF_B:
|
||
DS CMD_BUF_SIZE
|
||
|
||
; ═══════════════════════════════════════════════════════════════════════════
|
||
; Таблица позиций - 2734 Гц (шаг=1280, 56 записей, чистый цикл)
|
||
; Формат: [VSINTH, VSINTL, HSINT] для последовательности 3×OUTI
|
||
; Размер: 280 байт
|
||
; ═══════════════════════════════════════════════════════════════════════════
|
||
INCLUDE "src/pos_table_43750.inc"
|