diff --git a/Source/Apps/VGM/vgminfo.asm b/Source/Apps/VGM/vgminfo.asm index 0465dc6b..5cef09ab 100644 --- a/Source/Apps/VGM/vgminfo.asm +++ b/Source/Apps/VGM/vgminfo.asm @@ -40,6 +40,8 @@ LF .equ 0AH ; line feed ; VGM Header offsets ;------------------------------------------------------------------------------ +DEBUG_SUM .equ 1 ; 1 = build with checksum support + VGM_IDENT .equ 00H ; "Vgm " identifier VGM_VERSION .equ 08H ; Version VGM_SN76489_CLK .equ 0CH ; SN76489 clock (4 bytes, little-endian) @@ -60,6 +62,9 @@ VGM_YM26123_W .equ 0A2H ; YM2612 #2 port 0 write VGM_YM26124_W .equ 0A3H ; YM2612 #2 port 1 write VGM_YM21511_W .equ 054H ; YM2151 write VGM_YM21512_W .equ 0A4H ; YM2151 #2 write +VGM_OPL2_W .equ 05AH ; YM3812 (OPL2) write +VGM_OPL31_W .equ 05EH ; YMF262 (OPL3) port 0 write +VGM_OPL32_W .equ 05FH ; YMF262 (OPL3) port 1 write VGM_AY_W .equ 0A0H ; AY-3-8910 write VGM_ESD .equ 066H ; End of sound data VGM_WNS .equ 061H ; Wait n samples @@ -74,6 +79,9 @@ VGM_W882 .equ 063H ; Wait 882 samples START: LD SP, STACK ; Setup stack + ; Parse command tail for debug flags (e.g. "D" or "/D") + CALL PARSE_DEBUG + ; Display header LD DE, MSG_HEADER CALL PRTSTR @@ -224,6 +232,27 @@ PRINT_NAME: LD A, (HL) LD A, ' ' CALL PRTCHR +#if DEBUG_SUM + ; Compute and optionally print 512-byte checksum over VGMBUF + CALL CALC_SUM512 + LD A, (DBG_SUM) + OR A + JR Z, PAD_DONE + + ; Print space + [HHLL] + space between filename and chips + LD A, ' ' + CALL PRTCHR + LD A, '[' + CALL PRTCHR + LD A, (SUM_HI) + CALL PRTHEX8 + LD A, (SUM_LO) + CALL PRTHEX8 + LD A, ']' + CALL PRTCHR + LD A, ' ' + CALL PRTCHR +#endif PAD_DONE: @@ -316,6 +345,14 @@ CHK_AY_CLK: LD (CHIP_TYPES), A START_CMD_SCAN: + ; Clear AY flags if AY is not present in header + LD A, (CHIP_TYPES) + BIT 3, A ; Check if AY is present + JR NZ, SCAN_CMDS ; If present, continue + LD A, (CHIP_FLAGS) + AND 3FH ; Clear bits 6 and 7 (AY flags) + LD (CHIP_FLAGS), A +SCAN_CMDS: ; If chip type is present, scan commands to detect multiples ; Set base flags from types LD A, (CHIP_TYPES) @@ -335,19 +372,14 @@ NO_YM2612_BASE: LD A, (CHIP_TYPES) BIT 2, A JR Z, NO_YM2151_BASE - LD A, (CHIP_FLAGS) - OR 10H ; Set YM2151 #1 - LD (CHIP_FLAGS), A + ; Do NOT pre-mark YM2151 as used from the header alone. + ; YM2151 will only be marked used when a command is seen. NO_YM2151_BASE: - LD A, (CHIP_TYPES) - BIT 3, A - JR Z, NO_AY_BASE - LD A, (CHIP_FLAGS) - OR 40H ; Set AY #1 - LD (CHIP_FLAGS), A + ; Do NOT pre-mark AY as used from the header alone. + ; AY will only be marked used when an 0xA0 command is seen. NO_AY_BASE: - - ; Compute absolute data start within VGMBUF window + +COMPUTE_DATA_START: LD HL, (VGMBUF+VGM_DATAOFF) LD A, H OR L @@ -379,10 +411,13 @@ SCAN_LOOP: LD A, (HL) CHK_PSG2: CP VGM_PSG2_W JP NZ, CHK_YM2612 + LD A, (CHIP_TYPES) ; Only if SN76489 is present + BIT 0, A + JR Z, SCAN_NEXT_1 LD A, (CHIP_FLAGS) OR 02H ; bit 1 = SN #2 LD (CHIP_FLAGS), A - INC HL +SCAN_NEXT_1: INC HL JP SCAN_NEXT CHK_YM2612: CP VGM_YM26121_W @@ -393,10 +428,13 @@ CHK_YM2612: CP VGM_YM26121_W JR Z, GOT_YM2612_2 CP VGM_YM26124_W JP NZ, CHK_YM2151 -GOT_YM2612_2: LD A, (CHIP_FLAGS) +GOT_YM2612_2: LD A, (CHIP_TYPES) ; Only if YM2612 is present + BIT 1, A + JR Z, SCAN_NEXT_2 + LD A, (CHIP_FLAGS) OR 08H ; bit 3 = YM2612 #2 LD (CHIP_FLAGS), A - INC HL +SCAN_NEXT_2: INC HL INC HL ; Skip 2 data bytes JP SCAN_NEXT GOT_YM2612_1: LD A, (CHIP_FLAGS) @@ -410,10 +448,13 @@ CHK_YM2151: CP VGM_YM21511_W JR Z, GOT_YM2151_1 CP VGM_YM21512_W JP NZ, CHK_AY + LD A, (CHIP_TYPES) ; Only if YM2151 is present + BIT 2, A + JR Z, SCAN_NEXT_3 LD A, (CHIP_FLAGS) OR 20H ; bit 5 = YM2151 #2 LD (CHIP_FLAGS), A - INC HL +SCAN_NEXT_3: INC HL INC HL JP SCAN_NEXT GOT_YM2151_1: LD A, (CHIP_FLAGS) @@ -424,23 +465,46 @@ GOT_YM2151_1: LD A, (CHIP_FLAGS) JP SCAN_NEXT CHK_AY: CP VGM_AY_W - JP NZ, CHK_WAIT + JP NZ, CHK_OPL2 + LD A, (CHIP_TYPES) ; Only if AY is present + BIT 3, A + JR Z, SCAN_SKIP_AY ; Skip if AY not present in header LD A, (HL) ; Get register/chip byte BIT 7, A ; Bit 7 = chip 2? JR Z, GOT_AY1 LD A, (CHIP_FLAGS) OR 80H ; bit 7 = AY #2 LD (CHIP_FLAGS), A - INC HL - INC HL - JP SCAN_NEXT + JR SCAN_SKIP_AY GOT_AY1: LD A, (CHIP_FLAGS) OR 40H ; bit 6 = AY #1 LD (CHIP_FLAGS), A - INC HL +SCAN_SKIP_AY: INC HL INC HL ; Skip 2 data bytes JP SCAN_NEXT +CHK_OPL2: CP VGM_OPL2_W + JP NZ, CHK_OPL3 + ; Mark OPL2 present + LD A, (CHIP_TYPES) + OR 010H ; bit 4 = OPL2 + LD (CHIP_TYPES), A + INC HL ; skip register + INC HL ; skip data + JP SCAN_NEXT + +CHK_OPL3: CP VGM_OPL31_W + JR Z, GOT_OPL3 + CP VGM_OPL32_W + JP NZ, CHK_WAIT +GOT_OPL3: ; Mark OPL3 present + LD A, (CHIP_TYPES) + OR 020H ; bit 5 = OPL3 + LD (CHIP_TYPES), A + INC HL ; skip register + INC HL ; skip data + JP SCAN_NEXT + CHK_WAIT: CP VGM_WNS JR NZ, CHK_W735 INC HL @@ -519,6 +583,28 @@ YM2151_DUAL: LD DE, MSG_YM2151X2 CALL PRTSTR YM2151_DONE: INC B NO_YM2151: + ; OPL2 (YM3812) + LD A, (CHIP_TYPES) + BIT 4, A + JR Z, NO_OPL2 + LD A, B + OR A + CALL NZ, PRINT_COMMA + LD DE, MSG_OPL2 + CALL PRTSTR + INC B +NO_OPL2: + ; OPL3 (YMF262) + LD A, (CHIP_TYPES) + BIT 5, A + JR Z, NO_OPL3 + LD A, B + OR A + CALL NZ, PRINT_COMMA + LD DE, MSG_OPL3 + CALL PRTSTR + INC B +NO_OPL3: ; AY-3-8910 LD A, C AND 0C0H ; bits 6-7 @@ -552,6 +638,118 @@ PRINT_COMMA: LD A, ',' RET +;------------------------------------------------------------------------------ +; Parse CP/M command tail for debug flag (D or /D) -> sets DBG_SUM +;------------------------------------------------------------------------------ + +PARSE_DEBUG: LD HL, BUFF ; CP/M command tail buffer + LD A, (HL) ; length byte + OR A + RET Z ; empty tail, no flags + + LD B, A ; B = remaining chars + INC HL ; HL -> first character + +PD_LOOP: LD A, (HL) + CP ' ' ; skip spaces + JR Z, PD_NEXT + + CP '/' + JR Z, PD_SLASH + + CP 'D' + JR Z, PD_SET + CP 'd' + JR Z, PD_SET + JR PD_NEXT + +PD_SLASH: ; look at next char for D/d + INC HL + DJNZ PD_CHECK2 + RET + +PD_CHECK2: LD A, (HL) + CP 'D' + JR Z, PD_SET + CP 'd' + JR Z, PD_SET + JR PD_NEXT_CONT + +PD_NEXT: INC HL +PD_NEXT_CONT: DJNZ PD_LOOP + RET + +PD_SET: LD A, 1 + LD (DBG_SUM), A + RET + + +;------------------------------------------------------------------------------ +; 512-byte checksum over VGMBUF (simple 16-bit sum) +;------------------------------------------------------------------------------ + +CALC_SUM512: PUSH AF + PUSH BC + PUSH DE + PUSH HL + + LD HL, VGMBUF + LD DE, 0200H ; 512 bytes + XOR A + LD (SUM_LO), A + LD (SUM_HI), A + +SUM_LOOP: LD A, (HL) + INC HL + LD B, A + LD A, (SUM_LO) + ADD A, B + LD (SUM_LO), A + LD A, (SUM_HI) + ADC A, 0 + LD (SUM_HI), A + DEC DE + LD A, D + OR E + JR NZ, SUM_LOOP + + POP HL + POP DE + POP BC + POP AF + RET + +;------------------------------------------------------------------------------ +; Print A as two hex digits +;------------------------------------------------------------------------------ + +PRTHEX8: PUSH AF + PUSH BC + + LD B, A ; Save original byte in B + SRL A + SRL A + SRL A + SRL A ; High nibble + CALL PRTHEX_NIB + + LD A, B + AND 0FH ; Low nibble + CALL PRTHEX_NIB + + POP BC + POP AF + RET + +PRTHEX_NIB: CP 0AH + JR C, HEX_DIGIT + ADD A, 'A' - 10 + JR PRTHEX_OUT +HEX_DIGIT: ADD A, '0' +PRTHEX_OUT: CALL PRTCHR + RET + + ;------------------------------------------------------------------------------ ; Print string pointed to by DE (terminated by 0) ;------------------------------------------------------------------------------ @@ -611,6 +809,8 @@ MSG_YM2612: .DB "YM2612", 0 MSG_YM2612X2: .DB "2xYM2612", 0 MSG_YM2151: .DB "YM2151", 0 MSG_YM2151X2: .DB "2xYM2151", 0 +MSG_OPL2: .DB "YM3812", 0 +MSG_OPL3: .DB "YMF262", 0 MSG_AY8910: .DB "AY-3-8910", 0 MSG_AY8910X2: .DB "2xAY-3-8910", 0 MSG_UNKNOWN: .DB "Unknown/None", 0 @@ -638,6 +838,11 @@ CHIP_FLAGS: .DB 0 ; Detected chip flags CHIP_TYPES: .DB 0 ; Chip types present from header ; bit0 SN76489, bit1 YM2612 ; bit2 YM2151, bit3 AY-3-8910 + ; bit4 OPL2 (YM3812), bit5 OPL3 (YMF262) + +SUM_LO: .DB 0 ; Low byte of 16-bit checksum +SUM_HI: .DB 0 ; High byte of 16-bit checksum +DBG_SUM: .DB 0 ; 0=disable checksum print, non-zero=enable ; Buffer for VGM header + first data sector (256 bytes) VGMBUF: .FILL 512, 0 diff --git a/Source/Apps/VGM/vgminfo.txt b/Source/Apps/VGM/vgminfo.txt index 8cf29d19..1af760d0 100644 --- a/Source/Apps/VGM/vgminfo.txt +++ b/Source/Apps/VGM/vgminfo.txt @@ -32,6 +32,8 @@ The program can detect the following audio chips: - SN76489 (PSG - Programmable Sound Generator) - YM2612 (FM Synthesis chip used in Sega Genesis/Mega Drive) - YM2151 (OPM - FM Operator Type-M) + - YM3812 (OPL2 - FM synthesis chip) + - YMF262 (OPL3 - Enhanced FM synthesis chip) - AY-3-8910 (PSG used in many arcade and home computers) Example Output: