diff --git a/Source/Apps/VGM/vgmplay.asm b/Source/Apps/VGM/vgmplay.asm index eb2a7f82..4a4b8c1c 100644 --- a/Source/Apps/VGM/vgmplay.asm +++ b/Source/Apps/VGM/vgmplay.asm @@ -39,13 +39,11 @@ MBC .equ 4 ; plt_romwbw .equ 1 ; Build for ROMWBW? plt_type .equ sbcecb ; Select build configuration -debug .equ 0 - +debug .equ 0 ; Display port, register, config info +; #IF (plt_type=custom) -RSEL .equ 0D8H ; Primary AY-3-8910 Register selection -RDAT .equ 0D0H ; Primary AY-3-8910 Register data -RSEL .SET 09AH ; Primary AY-3-8910 Register selection -RDAT .SET 09BH ; Primary AY-3-8910 Register data +RSEL .equ 09AH ; Primary AY-3-8910 Register selection +RDAT .equ 09BH ; Primary AY-3-8910 Register data RSEL2 .equ 88H ; Secondary AY-3-8910 Register selection RDAT2 .equ 89H ; Secondary AY-3-8910 Register data VGMBASE .equ $C0 @@ -105,8 +103,8 @@ plt_cpuspd .equ 7 ; Non ROMWBW cpu speed default #ENDIF ; #IF (plt_type=sbcecb) -RSEL .equ 0D8H ; Primary AY-3-8910 Register selection -RDAT .equ 0D0H ; Primary AY-3-8910 Register data +RSEL .equ 09AH ; Primary AY-3-8910 Register selection +RDAT .equ 09BH ; Primary AY-3-8910 Register data RSEL2 .equ 0A0H ; Secondary AY-3-8910 Register selection RDAT2 .equ 0A1H ; Secondary AY-3-8910 Register data VGMBASE .equ $C0 @@ -134,7 +132,7 @@ YMSEL .equ 0C0H ; 11000000 a1=0 a0=0 YMDAT .equ 0C1H ; 11000001 a1=0 a0=1 YM2SEL .equ 0C2H ; 11000010 a1=1 a0=0 YM2DAT .equ 0C3H ; 11000011 a1=1 a0=1 -PSG1REG .equ 0C6H ; Primary SN76489 +PSG1REG .equ 0C6H ; Primary SN76489 PSG2REG .equ 0C7H ; Secondary SN76489 ctcbase .equ 000H ; CTC base address YM2151_SEL1 .equ 0FEH ; Primary YM2151 register selection @@ -203,7 +201,7 @@ RTCIO .equ 070H #DEFCONT \ djnz $-6 ;------------------------------------------------------------------------------ -; VGM Codes +; VGM Codes - see vgmrips.net/wiki/VGM_specification ;------------------------------------------------------------------------------ VGM_GG_W .equ 04FH ; GAME GEAR PSG STEREO. WRITE DD TO PORT 0X06 @@ -280,32 +278,41 @@ _S1 LD DE, VGMDATA + 34H LD (VGMPOS), HL LD HL,D60 ; VGM delay (60hz) - LD (VGMDLY), HL - + LD (vdelay), HL +; + LD IX,VGM_DEV ; IX points to device mask +; +;------------------------------------------------------------------------------ +; Play loop +;------------------------------------------------------------------------------ +; MAINLOOP CALL PLAY ; Play one frame ; LD HL,KEYCHK ; Check for keypress DEC (HL) JR NZ,NO_CHK +; LD C,6 ; Every 256 commands - LD E,0FFH - CALL BDOS + LD E,0FFH ; because HBIOS calls + CALL BDOS ; take a long time OR A JR NZ,EXIT NO_CHK: #IF (delay_type==cpu_loop) - LD HL,(VGMDLY) ; Frame delay -fdelay: .equ $+1 -lp1: LD B,FRAME_DLY ; 44100 one frame = 0.0000226757 seconds - DJNZ $ - DEC HL - LD A,H - OR L - JR NZ,lp1 +vdelay: .equ $+1 + ld hl,vdelay +fdelay: .equ $+1 +lp1: LD B,FRAME_DLY ; 44100 one frame = 0.0000226757 seconds + DJNZ $ + DEC HL + LD A,H + OR L + JP NZ,lp1 ; Normally NZ so jp is faster #ENDIF - +; #IF (delay_type==ctc_poll) - LD HL,(VGMDLY) ; Frame delay +vdelay: .equ $+1 + ld hl,vdelay ; Frame delay lp1: in a,(ctcch3) ; wait for counter to reach zero dec a jr nz,lp1 @@ -321,13 +328,13 @@ lp3: in a,(ctcch3) ; wait for counter to reach zero DEC HL LD A,H OR L - JR NZ,lp1 + JP NZ,lp1 ; Normally NZ so jp is faster #ENDIF ; #IF (delay_type==ctc_int) #ENDIF ; - JR MAINLOOP + JP MAINLOOP ; ;------------------------------------------------------------------------------ ; Program Exit @@ -687,7 +694,6 @@ PLAY #IFDEF SBCV2004 CALL SLOWIO #ENDIF - LD IX,VGM_DEV LD HL, (VGMPOS) ; Start processing VGM commands NEXT LD A, (HL) INC HL @@ -704,13 +710,7 @@ NEXT LD A, (HL) JR NEXT NEXT1: -; CP VGM_GG_W ; Game Gear SN76489 stereo. Ignored -; JR NZ, PSG -; LD IX,VGM_DEV -; SET 0,(IX+1) -; INC HL -; JR NEXT - +; ; SN76489 SECTION PSG CP VGM_PSG1_W ; Write byte to SN76489. @@ -750,9 +750,9 @@ AY1 OUT (RSEL), A OUT (RDAT), A SET 3,(IX+0) JR NEXT - +; ; YM2612 SECTION - +; YM2162_1 CP VGM_YM26121_W JR NZ, YM2162_2 LD A,(HL) @@ -774,9 +774,9 @@ YM2162_2 CP VGM_YM26122_W INC HL SET 4,(IX+0) ; 2nd channel JP NEXT - +; ; YM2151 SECTION - +; YM2151_1 CP VGM_YM21511_W JR NZ,YM2151_2 LD A,(HL) @@ -789,7 +789,7 @@ YM2151_1 CP VGM_YM21511_W JP NEXT ; YM2151_2 CP VGM_YM21512_W - JR NZ,WAITNN + JR NZ,GG LD A,(HL) OUT (YM2151_SEL2),A INC HL @@ -798,6 +798,14 @@ YM2151_2 CP VGM_YM21512_W INC HL SET 7,(IX+0) JP NEXT +; +; GAME GEAR SN76489 STEREO SECTION +; +GG: CP VGM_GG_W ; Stereo steering port value + JR NZ, WAITNN +; SET 0,(IX+1) + INC HL + JP NEXT ; WAITNN CP VGM_WNS ; Wait nn samples JR NZ, WAIT60 @@ -808,35 +816,43 @@ WAITNN CP VGM_WNS ; Wait nn samples LD (VGMPOS), HL LD L, A LD H, D - LD (VGMDLY), HL + LD (vdelay), HL RET ; WAIT60 CP VGM_W735 ; Wait 735 samples (60Hz) JR NZ, WAIT50 LD (VGMPOS), HL LD HL, D60 - LD (VGMDLY), HL + LD (vdelay), HL RET ; -WAIT50 CP VGM_W882 ; Wait 882 samples (50Hz) - JR NZ, WAIT1 - LD (VGMPOS), HL - LD HL, D50 - LD (VGMDLY), HL +WAIT50: CP VGM_W882 ; Wait 882 samples (50Hz) + JR NZ, WAIT1 + LD (VGMPOS), HL + LD HL, D50 + LD (vdelay), HL RET ; -WAIT1 CP 70H ; WAIT 0-15 SAMPLES +WAIT1: CP 70H ; WAIT 0-15 SAMPLES JR C, UNK ; CODES 70-7FH CP 80H JP NC, UNK SUB 6FH LD L, A LD H, 0 - LD (VGMDLY), HL + LD (vdelay), HL RET ; UNK: SET 0,(IX+1) ; unknown device INC HL ; Try and skip +#IF (debug) + ld a,'u' ; Display unknow command + call PRTCHR + call PRTDOT + call PRTHEX + ld a,' ' + call PRTCHR +#ENDIF JP NEXT ; ;------------------------------------------------------------------------------ @@ -1277,7 +1293,7 @@ MSG_MBC .DB " [mbc] ",0 ;------------------------------------------------------------------------------ ; VGMPOS .DW 0 -VGMDLY .DW 0 +;VGMDLY .DW 0 ; Saves number of frames to delay KEYCHK .DB 0 ; Counter for keypress checks ; VGM_DEV .DB %00000000 ; IX+0 Flags for devices diff --git a/Source/Apps/VGM/vgmplay.txt b/Source/Apps/VGM/vgmplay.txt index 28c81d83..882a7c34 100644 --- a/Source/Apps/VGM/vgmplay.txt +++ b/Source/Apps/VGM/vgmplay.txt @@ -5,30 +5,30 @@ Simple player for VGM (Video Game Music) files. Usage: - VGMPLAY MUSIC[.VGM] +VGMPLAY MUSIC[.VGM] -Supported devices: +Press a key to exit the program. - SN76489 - AY-3-89810 - YM2612/YM3484 - YM2151 +Supported devices +================= -Default Ports: +SN76489 +AY-3-89810 +YM2612/YM3484 +YM2151 - D8H-D0H - First AY-3-8910 (RSEL/RDAT) - A0H-A1H - Second AY-3-8910 - FFH - First SN76489 - FBH - Second SN76489 - C6H-C7H - YM2612/YM3484 +Supported platforms +=================== + +VGM Player is currently being developed on the ROMWBW platform using the Retrobrew computers +EBC-SBC-V2 (Z80), ECB-SCG (AY-3-8910) and ECB-VGM (YM2612 and 2xSN76489) board. +It can be configured to run with other hardware such as RC2014, P8X180 and nhyodyne MBC. -If your system uses different ports you need to recompile the source. +VGM files can be very big and are limited in size by the available TPA space, which is typically 52k. -Note: The player should be compatible with VGM files up to version 1.51 -but there are very few controls (if any) in the code, be sure to have -a good VGM file that doesn't contain much extra data. These files can be -very big, the player is limited to the available TPA space which is -typically around 52k. +Processor speed affects the playback speed. Under ROMWBW the player will detect the cpu speed configuration +and adjust timing loops. For other platforms, default speeds are configured but may need to be changed +to suit your hardware. Counter/Timer hardware may be supported in future. Example Music Files =================== @@ -53,4 +53,22 @@ INCHINA.VGM - YM2612 * Double Dragon 3: The Rosetta Stone: In Chin * Included in disk images -Original Source by J.B Langston, Marco Maccaferri, Ed Brindley. ROMWBW version by Phil Summers. +VGM sources +=========== +https://www.smspower.org/forums/15359-VGMPacksGameGearMegaCollection +https://vgmrips.net/packs/chip/ym2612 +https://project2612.org/ + +VGM Tools +========= +https://vgmrips.net/wiki/VGMTool +https://github.com/vgmrips/vgmtools + +References +========== +http://www.primrosebank.net/computers/mtx/tools/PD/vgmplayer.zip - Paul Daniels MTX SN76489 interrupt version with embedded VGM tune. +https://github.com/jblang/SN76489/blob/master/examples/vgmplayer.asm - J.B. Langston RC2014 polled version with file loading. +https://groups.google.com/g/rc2014-z80/c/9nHnETJzGKU - Marco Maccaferri P8X180 & AY-3-8910 support +https://github.com/electrified/rc2014-ym2151/tree/main/software/vgmplay - Ed Brindly RC2014 & YM2151 support + +ROMWBW version by Phil Summers. VGM Player is still in development. The ECB-VGM is also still under development. diff --git a/Source/Doc/GettingStarted.md b/Source/Doc/GettingStarted.md index a0870957..9554e4c8 100644 --- a/Source/Doc/GettingStarted.md +++ b/Source/Doc/GettingStarted.md @@ -272,28 +272,22 @@ be VDU type devices or serial devices. If you want to change which device is the console, the ***I*** menu option can be used to choose the unit and it's speed. -The command format is ```I []``` +The command format is ```I []``` -where ***u*** is unit to select and ***c*** is the optional baud rate code as listed below. +where ***u*** is unit to select and ***b*** is the optional baud rate. +Supported baud rates are: ``` - Code | Rate | Code | Rate | Code | Rate | Code | Rate | -------|----------|------|----------|------|----------|------|----------| - 0 | 75 | 8 | 1800 | 16 | 28880 | 24 | 460800 | - 1 | 150 | 9 | 2400 | 17 | 38400 | 25 | 614400 | - 2 | 225 | 10 | 3600 | 18 | 57600 | 26 | 921600 | - 3 | 300 | 11 | 4800 | 19 | 76800 | 27 | 1228822 | - 4 | 450 | 12 | 7200 | 20 | 115200 | 28 | 1843200 | - 5 | 600 | 13 | 9600 | 21 | 153600 | 29 | 2457600 | - 6 | 900 | 14 | 14400 | 22 | 230400 | 30 | 3686400 | - 7 | 1200 | 15 | 19200 | 23 | 307200 | 31 | 7372800 | ------------------------------------------------------------------------- + 75 450 1800 7200 38400 115200 460800 1843200 +150 600 2400 9600 28800 153600 614400 2457600 +225 900 3600 14400 57600 230400 921600 3686400 +300 1200 4800 19200 76800 307200 1228800 7372800 ``` Example: To change current console to 9600 baud ``` -I 0 13 +I 0 9600 ``` diff --git a/Source/HBIOS/romldr.asm b/Source/HBIOS/romldr.asm index 386b93fd..51441a62 100644 --- a/Source/HBIOS/romldr.asm +++ b/Source/HBIOS/romldr.asm @@ -499,10 +499,50 @@ setcon: call skipws ; skip whitespace call isnum ; do we have a number? jp nz,docon ; if no we don't change baudrate - call getnum ; parse a number - jp c,err_invcmd ; handle overflow error + call getbnum ; return in HL:BC +; + ld e,32 ; search baud rate table + push de ; for a matching entry + ld de,tbl_baud +nextbaud: + ex de,hl ; hl = tbl_baud, de = msw + ld a,d ; check all four bytes + cp (hl) ; against HL:BC + inc hl ; exit to next table + jr nz,mm1 ; entry on mismatch + ld a,e + cp (hl) + inc hl + jr nz,mm2 + ld a,b + cp (hl) + inc hl + jr nz,mm3 + ld a,c + cp (hl) + inc hl + jr nz,mm4 +; + ; we have a match + pop de ; get our count value + ld a,32 + sub e + jr s_exit +; +mm1: inc hl +mm2: inc hl +mm3: inc hl +mm4: ex (sp),hl ; hl = count value, stack = tbl_baud, de = msw + dec l + ex (sp),hl ; hl = tbl_baud, stack= count + ex de,hl ; hl = msw, de = tbl_baud + jr nz,nextbaud +; + ; Failed to match + pop de + jp err_invcmd ; - cp 32 ; handle invalid +s_exit: cp 32 ; handle invalid jp nc,err_invcmd ; baud rate bit 0,a jr z,iseven ; convert sequential @@ -512,6 +552,7 @@ setcon: iseven: dec a ; 15=19200 srl a ; 17=38400 add a,16 ; 20=115200 +; setspd: ld (newspeed),a ; save validated baud rate ; ld hl,str_chspeed ; notify user @@ -554,7 +595,92 @@ docon: ld hl,str_newcon ; new console msg call nl2 ; formatting ld hl,str_banner ; display boot banner call pstr ; do it - ret ; done + ret +; +;======================================================================= +; Get numeric chars at DE and convert to BCD number returned in HL:BC +;======================================================================= +; +getbnum:ld bc,0 ; lsw + ld hl,0 ; msw +getbnum1: + ld a,(de) ; get the active char + cp '0' ; compare to ascii '0' + jr c,getbnum2 ; abort if below + cp '9' + 1 ; compare to ascii '9' + jr nc,getbnum2 ; abort if above +; + sub '0' ; convert '0'-'9' to 0-9 +; + push de ; save char posn + push hl ; save hl bcd +; + ld hl,tmpbcd ; rotate 1 nyble in A + ld (hl),c ; through HL:BC + rld + ld c,(hl) + ld (hl),b + rld + ld b,(hl) + pop de ; get hl bcd + ld (hl),e + rld + ld e,(hl) + ld (hl),d + rld + ld d,(hl) + ld h,d + ld l,e +; + pop de ; get char posn + inc de ; bump to next char + jr getbnum1 ; loop +; +getbnum2: + or a ; with flags set, CF is cleared + ret +; +tmpbcd: .db 0 +; +#DEFINE PACK(a,b,c,d,e,f,g) \ +#DEFCONT \ .db (16*('0'-'0'))+(a-'0')) +#DEFCONT \ .db (16*(b-'0'))+(c-'0')) +#DEFCONT \ .db (16*(d-'0'))+(e-'0')) +#DEFCONT \ .db (16*(f-'0'))+(g-'0')) +; +tbl_baud: + PACK('0','0','0','0','0','7','5') ; 75 0 > 0 + PACK('0','0','0','0','1','5','0') ; 150 1 > 1 + PACK('0','0','0','0','2','2','5') ; 225 2 > 16 + PACK('0','0','0','0','3','0','0') ; 300 3 > 2 + PACK('0','0','0','0','4','5','0') ; 450 4 > 17 + PACK('0','0','0','0','6','0','0') ; 600 5 > 3 + PACK('0','0','0','0','9','0','0') ; 900 6 > 18 + PACK('0','0','0','1','2','0','0') ; 1200 7 > 4 + PACK('0','0','0','1','8','0','0') ; 1800 8 > 19 + PACK('0','0','0','2','4','0','0') ; 2400 9 > 5 + PACK('0','0','0','3','6','0','0') ; 3600 10 > 20 + PACK('0','0','0','4','8','0','0') ; 4800 11 > 6 + PACK('0','0','0','7','2','0','0') ; 7200 12 > 21 + PACK('0','0','0','9','6','0','0') ; 9600 13 > 7 + PACK('0','0','1','4','4','0','0') ; 14400 14 > 22 + PACK('0','0','1','9','2','0','0') ; 19200 15 > 8 + PACK('0','0','2','8','8','0','0') ; 28800 16 > 23 + PACK('0','0','3','8','4','0','0') ; 38400 17 > 9 + PACK('0','0','5','7','6','0','0') ; 57600 18 > 24 + PACK('0','0','7','6','8','0','0') ; 76800 19 > 10 + PACK('0','1','1','5','2','0','0') ; 115200 20 > 25 + PACK('0','1','5','3','6','0','0') ; 153600 21 > 11 + PACK('0','2','3','0','4','0','0') ; 230400 22 > 26 + PACK('0','3','0','7','2','0','0') ; 307200 23 > 12 + PACK('0','4','6','0','8','0','0') ; 460800 24 > 27 + PACK('0','6','1','4','4','0','0') ; 614400 25 > 13 + PACK('0','9','2','1','6','0','0') ; 921600 26 > 28 + PACK('1','2','2','8','8','0','0') ; 1228800 27 > 14 + PACK('1','8','4','3','2','0','0') ; 1843200 28 > 29 + PACK('2','4','5','7','6','0','0') ; 2457600 29 > 15 + PACK('3','6','8','6','4','0','0') ; 3686400 30 > 30 + PACK('7','3','7','2','8','0','0') ; 7372800 31 > 31 ; #endif ; diff --git a/Source/HBIOS/ym2612.asm b/Source/HBIOS/ym2612.asm index 148e7329..afa4bd48 100644 --- a/Source/HBIOS/ym2612.asm +++ b/Source/HBIOS/ym2612.asm @@ -4,10 +4,15 @@ ; ;------------------------------------------------------------------------------ ; References: +; https://hiddenpalace.org/News/Sega_of_Japan_Sound_Documents_and_Source_Code ; https://www.smspower.org/maxim/Documents/YM2612 ; https://plutiedev.com/blog/20200103 ; https://www.plutiedev.com/ym2612-registers +; https://www.plutiedev.com/ym2612-operations ; https://en.wikipedia.org/wiki/Scientific_pitch_notation +; https://gendev.spritesmind.net/forum/viewtopic.php?t=2915 (1) +; http://nemesis.hacking-cult.org/MegaDrive/Documentation/YM2608J.PDF +; ;------------------------------------------------------------------------------ ; Octave range is A#0-B7+3/4 HBIOS note 0..343 ;------------------------------------------------------------------------------ @@ -24,14 +29,15 @@ YM2DAT .EQU VGMBASE+03H ; Secondary YM2162 11000011 a1=1 a0=1 YM_TONECNT .EQU 6 ; Count number of tone channels YM_NOISECNT .EQU 0 ; Count number of noise channels ; -YM_PENDING_PERIOD .DW 0 ; PENDING PERIOD (12 BITS) ; ORDER -YM_PENDING_VOLUME .DB 0 ; PENDING VOL (8 BITS) ; SIGNIFICANT +YM_PENDING_PERIOD .DW 0 ; PENDING PERIOD (12 BITS) +YM_PENDING_VOLUME .DB 0 ; PENDING VOL (8 BITS) YM_PENDING_DURATION .DW 0 ; PENDING DURATION (16 BITS) YM_READY .DB 0 ; BIT 0 -> NZ DRIVER IS READY TO RECEIVE PLAY COMMAND ; BIT 1 -> NZ EXECUTING WITHIN TIMER HANDLER = DO NOT DIS/ENABLE INT YM_RDY_RST .DB 0 ; FLAG INDICATES IF DEVICE IS IN READY (NZ) OR RESET STATE (Z) YM_DEBUG .EQU 0 ; CHANGE TO 1 TO ENABLE DEBUGGING YM_RSTCFG .EQU 0 ; SET TO 1 FOR FULL REGISTER CLEAR +YM_FAST3438 .EQU 0 ; FAST CPU'S WITH A YM3438 MAY REQUIRE A DELAY ; ;------------------------------------------------------------------------------ ; Driver function table and instance data @@ -111,10 +117,12 @@ t_loop: ld a,(hl) ; get register to write #ENDIF ; dec c ; point back to RSEL port - ld b,0 ; check device -nready1: in a,(c) ; ready with timeout - rlca ; - jr nc,ready1 ; bits 7 = busy + ld b,0 ; +nready1: +#IF YM_FAST3438==1) \ cp (ix) \ #ENDIF \ ; ym3438 delay (1) + in a,(c) ; check device + rlca ; ready with timeout + jr nc,ready1 ; bits 7 = busy djnz nready1 ; ; timed out @@ -397,7 +405,7 @@ ym_playcmd09: .db $F0 ; [0] KEY ON .db $00 ; End flag ; ;------------------------------------------------------------------------------ -; Quarter semitone values +; Quarter semitone F-Number values for frequency ;------------------------------------------------------------------------------ ; ym_notetable: .dw 644 ; C ; 152 @@ -497,14 +505,14 @@ ym_cfg_ready: .db part0, 2/2 .db $46, $7F ; .db part0, 6/2 - .db $4C, $7f ;$00 ; Channel 1-3 - .db $4d, $7f ;$00 ; Max volume for operator 4 - .db $4e, $7f ;$00 + .db $4C, $00 ; Channel 1-3 + .db $4d, $00 ; Max volume for operator 4 + .db $4e, $00 ; .db part1, 6/2 - .db $4C, $7f ;$00 ; Channel 4-6 - .db $4d, $7f ;$00 ; Max volume for operator 4 - .db $4e, $7f ;$00 + .db $4C, $00 ; Channel 4-6 + .db $4d, $00 ; Max volume for operator 4 + .db $4e, $00 ; .db part0, 6/2 .db $5C, $1F ; Channel 1-3