likearome / OwnFMDRV

코에이 IBM MS-DOS게임들의 BGM을 CD-DA로 바꾸는 프로그램
MIT License
7 stars 2 forks source link

1991년 버전 FMDRV.COM 사용 게임은 음악 반복이 되지 않습니다. #2

Closed likearome closed 7 months ago

likearome commented 7 months ago

개요

FMDRV.COM들 중 가장 오래된 버전인 1991년 버전을 사용하는 게임들의 CD 음악 반복 연주가 되지 않는 현상

대상 게임

공통점

상세한 문제 설명

likearome commented 7 months ago

우선 가장 쉽게 고려해볼 만한 것은 인터럽트 번호 1Ah / AH:06 명령어인 CMOS의 RTC 타이머 콜백인데, DOSBOX에서는 이 인터럽트 기능이 구현돼 있지 않다.

image

따라서 호환성 이슈가 있을 것으로 보인다.

likearome commented 7 months ago

그 다음 고려해볼만한 요소는 비디오 IRQ 혹은 마우스/키보드 IRQ를 통한 접근이다.

둘 모두 정확성도 떨어지고, 게임의 반응성에 영향을 줄 수 있기 때문에 썩 내키지는 않는다.

likearome commented 7 months ago

인터럽트 70번 핸들러가 열쇠가 될 수 있을 것 같다.

인터럽트 70번은 인터럽트 15번/AX:8300을 발동시키면 매 초 1024개의 인터럽트를 발생시킨다.

따라서 70번 후킹 뒤, 인터럽트 15번을 1초 걸어놓고 70번을 틱 인터럽트처럼 참조하다가 1초가 지나면 또 15번을 걸어두고 하는 식이면 게임 내내 반복 연주를 감시할 수 있을 것 같다.

likearome commented 7 months ago

70번으로 코드를 구성하고 VIDE-CDD.SYS를 올려보았더니 예전 이슈처럼 멈춘다.

결국 70번도 ~08번에서 호출된다는 사실을 알 수 있었다.~ (아래 설명. 8번에서 호출돼서 그런게 아님)

70번은 해결책이 되지 않았다.

likearome commented 7 months ago

https://www.[compuphase.com/int70.txt](https://www.compuphase.com/int70.txt)

위 문서를 살펴보면 인터럽트 15/AX:8300 없이도 70번 실시간 인터럽트를 발생시킬 수 있는 것으로 보인다. 이 경우 8번과 관계없이 동작할 수 있을지도 모르겠다.

likearome commented 7 months ago

위 과정대로 hz를 변경하고 해봤는데 VIDE-CDD를 설치하면 역시 먹통이 된다.

이 코드는 참조를 위해 브랜치를 따로 따기로 한다.

likearome commented 7 months ago

70번 핸들러를 사용하고도 문제가 안 생기는 방법을 찾았다.

70번 핸들러 발동시 바로 End of Interrupt부터 날려놓고 시작하면, 핸들러 구동중 CD에 접근하더라도 문제가 발생하지 않는다.

이를 여러 곳에서 테스트할 예정이다.

likearome commented 7 months ago

테스트를 잠정 완료하였다.

DOSBOX 성공 DOSBOX + VIDE-CDD.SYS 성공 86Box 성공 실기기 성공

이 이슈를 완료처리한다.

likearome commented 7 months ago

문제의 원인 및 해결방식을 간략히 설명한다.

IRQ에 의해 동작하는 이른바 하드웨어 인터럽트 콜백들(틱, RTC 등 포함)은 모두 IBM의 PIC 장치(Programmable Interrupt Controller)에 의해 발행된다. 이 PIC들은 한번에 하나의 하드웨어 인터럽트를 발행하는데, PIC의 0x20 (Primary), 0xA0(Secondary) 포트에 0x20(End of Interrupt)를 전달하지 않는 동안에는 PIC의 하드웨어 인터럽트가 더 이상 발행되지 않는다. 따라서 PIC를 통해 발행된 하드웨어 인터럽트들은 반드시 빠르게 0x20, 0xA0에 0x20값을 전달하여 원활한 하드웨어 인터럽트 발행이 될 수 있도록 해 주어야 한다.

IRQ 0 번에 설정되어 PIC가 발행하는 하드웨어 틱 인터럽트(Int 8h)의 BIOS 기본 핸들러는 여러가지 일을 수행하는데, 그 중 하나가 BIOS의 0040:006C (일반주소 0x46C)에 있는 Tick Counter를 증가시키는 것이다. OAKCDROM이나 VIDE-CDD등의 도스 드라이버들은 CD장치에 명령을 전달한 후, 이 Tick Counter의 증감을 관찰하여 CD장치의 타임아웃(먹통여부)를 체크한다. 이 때 이 카운터가 증가하지 않으면 도스 드라이버가 무한루프에 빠지는 문제가 발생한다.

기존 이슈에서 먹통이 발생한 원인: 우리가 Tick 인터럽트에서 CD 장치에 접근하면, Tick 인터럽트가 막혀있는 상태에서 CD 장치에 접근하기 때문에 0x46C의 값을 올려줄 프로세스가 잠겨버려서 무한루프를 도는 것이다.

70번 RTC 하드웨어 인터럽트는 기본적으로는 Tick 인터럽트와 관계없으나, 70번 역시 PIC를 통해 올라오는 하드웨어 인터럽트이기 때문에 PIC를 클리어해주지 않으면 Tick 인터럽트도 영향을 받게 된다.

따라서 70번 인터럽트 수신시 OwnFMDRV의 정상 동작을 위해서는, 70번 인터럽트 핸들러 내에서 CD장치에 접근하기 전에 먼저 Primary와 Secondary에 0x20(EOI)을 전달하여 Tick 인터럽트가 정상동작하도록 만들어주고 CD 장치에 접근하여야 한다.