Subject: Re: AppleWin - Mockingboard From: "Thug" Newsgroups: comp.emulators.apple2 "Oliver Schmidt" wrote: > To be true I've never tried it. But some minutes ago I found a DSK > image of Skyfox with Mockingboard support and it worked - at least > sometimes. No I've two questions: > > 1. Is ApplePCs Mockingboard emulation as realistic as its video > emulation? It's not bad, allowing for the limitations of the AdLib/Soundblaster hardware. I was quite active in the Apple ][ Emulation scene at the time that Daid Ellsworth added Mockingboard support to ApplePC and provided him with a few bits of minor feedback. I don't believe he ever actually owned and Mockingboard himself. In a message he sent to me on News Year's Eve, 1995 he wrote: "So far, I have added noise emulation, but envelopes are going to be hard. The Adlib card only has 15 envelope attack/decay rates, whereas the Mockingboard has 65535. I may have to resort to continuous background DMA, something I have never programmed before. This would allow perfect emulation, however." So, there's one limitation to ApplePC. But to be honest, I'm not sure that many applications used more than a few envelopes at once. > 2. What DSKs should I try? Probably some music program or is there > something like a "Mockingboard Systems Disk" with demos? Cool games? There is indeed a System Master, available on Asimov. If you can't locate it, I'll send you a copy. Other games that used MockingBoard, off the top of my head, were: Ultima III (Some versions) Ultima IV Ultima V Skyfox Music Construction Set Night Flight One on One Willy Byte Broadside I've attached an old message on Mockingboard emulation that you might find usefull too. Michael ----8<---- cut here ----8<---- From: tom@snsys.com (Tom) Newsgroups: comp.emulators.apple2 Subject: Mockingboard Info. Date: Mon, 27 Nov 1995 18:30:43 GMT Organization: VBCnet GB Ltd Lines: 497 Message-ID: <49d0ug$m6u@news.uk1.vbc.net> NNTP-Posting-Host: tom.snsys.com X-Newsreader: Forte Free Agent v0.55 Someone was asking for information on the Mockingboard for the Apple ][. Well heres some code from my emulator for the Amiga. The Mockingboard is very simple - it has no ROM on the card. It consists of a 6522 & AY8910 x2. You pass simple commands to ORA on the 6522 and the logic decides whether to Select ORB as AY register. Write ORB to the selected AY register. Reset the AY chip. IE. To write 0xFF to AY register 0x02: ; Select AY register. 0x02 -> ORB ; Data 0x07 -> ORA ; Latch AY register command 0x04 -> ORA ; Process command ; Write the data the the AY register. 0xFF -> ORB ; Data 0x06 -> ORA ; Write AY register command 0x04 -> ORA ; Process command See the code. Tom. ; Module for the emulation of the Mockingboard Sound Card ; for the Apple ][. ; Thanks to Allan Crout for providing me with the original documentation ; for the Mockingboard. ; This comprises of: ; 2x SY6522 VIA I/O chip ; 2x AY-3-8910 sound generator chip ; 1x Votrax speech synthesizer chip ; Nb. Speech chip not emulated. ; Noise not emulated. ; Envelopes not emulated. ; Only Timer1 on 6522A is emulated. ; Chip offsets from card base. SY6522A_Offset = $00 SY6522B_Offset = $80 Votrax_Offset = $40 *ннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннн н* ; 6522 registers: RSRESET SY_ORB rs.b 1 ; $00 - Port B SY_ORA rs.b 1 ; $01 - Port A (with handshaking) SY_DDRB rs.b 1 ; $02 - Data Direction Register B SY_DDRA rs.b 1 ; $03 - Data Direction Register A SY_TIMER1L rs.b 1 ; $04 - Read / Write & latch. SY_TIMER1H rs.b 1 ; $05 - Read / Write & initiate count. SY_ACCESS_TIMER1L rs.b 1 ; $06 SY_ACCESS_TIMER1H rs.b 1 ; $07 SY_TIMER2L rs.b 1 ; $08 SY_ACCESS_TIMER2H rs.b 1 ; $09 SY_SERIAL_SHIFT rs.b 1 ; $0A SY_ACR rs.b 1 ; $0B - Auxiliary Control Register SY_PCR rs.b 1 ; $0C - Peripheral Control Register SY_IFR rs.b 1 ; $0D - Interrupt Flag Register SY_IER rs.b 1 ; $0E - Interrupt Enable Register SY_ORA_NO_HS rs.b 1 ; $0F - Port A (without handshaking) SY6522_SIZE = __RS ; AY-3-8910 registers: RSRESET AY_A_Tone_Fine rs.b 1 AY_A_Tone_Coarse rs.b 1 AY_B_Tone_Fine rs.b 1 AY_B_Tone_Coarse rs.b 1 AY_C_Tone_Fine rs.b 1 AY_C_Tone_Coarse rs.b 1 AY_Noise rs.b 1 AY_Enable rs.b 1 AY_A_Amplitude rs.b 1 AY_B_Amplitude rs.b 1 AY_C_Amplitude rs.b 1 AY_Envelope_Fine rs.b 1 AY_Envelope_Coarse rs.b 1 AY_Envelope_Shape rs.b 1 AY_Undefined1 rs.b 1 AY_Undefined2 rs.b 1 AY8910_SIZE = __RS *ннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннн н* ; IFR & IER: PERIPHERAL = 1<<1 TIMER2 = 1<<5 TIMER1 = 1<<6 ; ACR: RUNMODE = 1<<6 ; 0 = 1-Shot Mode, 1 = Free Running Mode ; Votrax registers: VO_DURPHON = $00 VO_INFLECT = $01 VO_RATEINF = $02 VO_CTTRAMP = $03 VO_FILFREQ = $04 *ннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннн н* ; Entry point for WRITES to Mockingboard. * Pre: D6= Byte to write. (Nb High WORD not zero!) * D7= 16 bit 6502 address. Mockingboard_Write swap d6 ; Keep data. move.w d7,d6 and.w #$00F0,d6 and.w #$000F,d7 ; D7 = Register # lsr.w #2,d6 move.l .Mockingboard_Write_Table(pc,d6.w),a6 clr.w d6 swap d6 ; D6 = BYTE to write. jmp (a6) .Mockingboard_Write_Table dc.l SY6522A_Write REPT 7 dc.l Mockingboard_Write_Undefined ENDR dc.l SY6522B_Write REPT 7 dc.l Mockingboard_Write_Undefined ENDR *ннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннн н* SY6522A_Write lea SY6522_AY8910_A(pc),a5 bra.s SY_W SY6522B_Write lea SY6522_AY8910_B(pc),a5 SY_W add.w d7,d7 add.w d7,d7 move.l .SY6522_Write_Table(pc,d7.w),a6 jmp (a6) .SY6522_Write_Table dc.l SY6522_Write_ORB dc.l SY6522_Write_ORA dc.l SY6522_Write_DDRB dc.l SY6522_Write_DDRA dc.l SY6522_Write_TIMER1L dc.l SY6522_Write_TIMER1H REPT 5 dc.l Mockingboard_Write_Out ENDR dc.l SY6522_Write_ACR dc.l SY6522_Write_PCR dc.l SY6522_Write_IFR dc.l SY6522_Write_IER dc.l Mockingboard_Write_Out SY6522_Write_ORB and.b SY6522+SY_DDRB(a5),d6 ; Ultima pads values written to 6522 with 1's, so mask these ; out to get true value. and.b #%00000111,d6 ; Only lower 3 data lines used. cmp.b #4,d6 bne.s .store move.b SY6522+SY_ORB(a5),d6 ; Get last value written. beq.s .reset ; 0 = RESET cmp.b #6,d6 ; 6 = WRITE beq.s .write cmp.b #7,d6 ; 7 = LATCH bne.s .empty .latch ; Select value in Port A as current AY-3-8910 register. move.b SY6522+SY_ORA(a5),AY_Current_Register(a5) bra.s .empty .write ; Write data in Port A to current AY-3-8910 register. move.b AY_Current_Register(a5),d6 move.b SY6522+SY_ORA(a5),AY8910(a5,d6.w) move.w AY_Registers_Written(a5),d7 bset d6,d7 move.w d7,AY_Registers_Written(a5) ; Check if written to all 14 AY8910 registers yet. and.w #$3FFF,d7 cmp.w #$3FFF,d7 ; %0011 1111 1111 1111 bne.s .zero_check bsr Do_AY8910 bra.s .empty ; Check if descended to zero: ; I.E. Written from AYRegX to AYReg0. ; (Ultima only uses [00..0A] - no envelopes) .zero_check tst.b d6 ; Leave if not Reg0. bne.s .empty tst.w d7 ; Leave if this is the first register. beq.s .empty bsr Do_AY8910 bra.s .empty .reset ; Reset 6522/AY8910 nop .empty ; Ultima writes (after masking with %00000111): ; 04,00,04 to ORB to RESET. ; 04,07,04 to ORB to LATCH an AY8910 register. ; 06,04,04 to ORB to WRITE to AY8910 register. moveq #4,d6 .store move.b d6,SY6522+SY_ORB(a5) bra Mockingboard_Write_Out SY6522_Write_ORA and.b SY6522+SY_DDRA(a5),d6 move.b d6,SY6522+SY_ORA(a5) bra Mockingboard_Write_Out SY6522_Write_DDRB move.b d6,SY6522+SY_DDRB(a5) bra Mockingboard_Write_Out SY6522_Write_DDRA move.b d6,SY6522+SY_DDRA(a5) bra Mockingboard_Write_Out SY6522_Write_TIMER1L move.b d6,SY6522+SY_TIMER1L(a5) bra Mockingboard_Write_Out SY6522_Write_TIMER1H ; Initiate timer & Clears time-out of timer1. ; Clear Timer Interrupt Flag. and.b #~TIMER1,SY6522+SY_IFR(a5) move.b d6,SY6522+SY_TIMER1H(a5) tst.b SY6522_Offset(a5) bne.s .out ; For 6522A only: ; If (Timer interrupt enabled) ; Get Timer Count ; Enable Amiga Timer move.b SY6522+SY_IER(a5),d6 and.b #TIMER1,d6 beq.s .out st TimerStatus(a5) move.b SY6522+SY_ACR(a5),d6 and.b #RUNMODE,d6 lsr.b #3,d6 ; RUNMODE-CIACR_RUNMODE eor.b #CIACRAF_RUNMODE,d6 ; SY bit is opposite to CIA. move.w d6,.SY_RunMode ; Setup Amiga Timer move.l CIA(pc),a6 move.w CIAcr(pc),d7 *** move.b (a6,d7.w),d6 ; Get CRx and.b CIAStopMask(pc),d6 ; Clear Timer specific bits. or.b .SY_RunMode(pc),d6 *** move.b d6,(a6,d7.w) move.w SY6522+SY_TIMER1L(a5),d7 ror.w #8,d7 ; Get Timer Count ; move.w #45457,d6 ; NTSC move.w #45875,d6 ; PAL mulu d6,d7 ; x 0.693 x 2^16 (PAL) clr.w d7 swap d7 ; / 2^16 ror.w #8,d7 move.w CIAlo(pc),d6 *** move.b d7,(a6,d6.w) ror.w #8,d7 move.w CIAhi(pc),d6 *** move.b d7,(a6,d6.w) ; And start counter .out bra.s Mockingboard_Write_Out .SY_RunMode dc.w 0 SY6522_Write_ACR move.b d6,SY6522+SY_ACR(a5) bra.s Mockingboard_Write_Out SY6522_Write_PCR ; Used for Speech chip only. move.b d6,SY6522+SY_PCR(a5) bra.s Mockingboard_Write_Out SY6522_Write_IFR ; Clear those bits which are set in the lower 7 bits. ; Can't clear bit 7. and.b #$7f,d6 ; Clear high bit. eor.b #$7f,d6 and.b d6,SY6522+SY_IFR(a5) bra.s Mockingboard_Write_Out SY6522_Write_IER tst.b d6 bmi.s .set .clr ; Clear those bits which are set in the lower 7 bits. eor.b #$7f,d6 and.b d6,SY6522+SY_IER(a5) ; Check if timer has been disabled. and.b #TIMER1,d6 bne.s .out ; Is timer on? tst.b TimerStatus(a5) beq.s .out ; Stop Amiga timer. sf TimerStatus(a5) move.l CIA(pc),a6 move.w CIAcr(pc),d7 *** and.b #%11111110,(a6,d7.w) ; Stop Timer .out bra.s Mockingboard_Write_Out .set ; Set those bits which are set in the lower 7 bits. and.b #$7f,d6 or.b d6,SY6522+SY_IER(a5) Mockingboard_Write_Out move.l WRT_PageTable(a4),a5 Mockingboard_Write_Undefined moveq #0,d6 moveq #0,d7 rts *ннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннн н* ; Entry point for READS from Mockingboard/Internal ROM for this slot. * Pre: D7= 16 bit 6502 address. * Post: D6= Value read. * D7= 16 bit 6502 address. Mockingboard_Read tst.b ss_SLOTCXROM+1 ; Check which ROM is in IO space. bpl.s .SlotROM .InternalROM move.b (a3,d7.l),d6 RTS .SlotROM move.w d7,-(sp) ; Keep 6502 address. move.w d7,d6 and.w #$000F,d6 ; Just register # and.w #$00F0,d7 lsr.w #2,d7 move.l .Mockingboard_Read_Table(pc,d7.w),a6 move.w d6,d7 ; D7 = Register # jsr (a6) move.w (sp)+,d7 ; Restore 6502 address. rts .Mockingboard_Read_Table dc.l SY6522A_Read REPT 7 dc.l Mockingboard_Read_Undefined ENDR dc.l SY6522B_Read REPT 7 dc.l Mockingboard_Read_Undefined ENDR *ннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннн н* SY6522A_Read lea SY6522_AY8910_A(pc),a5 bra.s SY_R SY6522B_Read lea SY6522_AY8910_B(pc),a5 SY_R add.w d7,d7 add.w d7,d7 move.l .SY6522_Read_Table(pc,d7.w),a6 jmp (a6) .SY6522_Read_Table dc.l SY6522_Read_ORB dc.l SY6522_Read_ORA dc.l SY6522_Read_DDRB dc.l SY6522_Read_DDRA dc.l SY6522_Read_TIMER1L REPT 6 dc.l Mockingboard_Read_Out ENDR dc.l SY6522_Read_ACR dc.l SY6522_Read_PCR dc.l SY6522_Read_IFR dc.l SY6522_Read_IER dc.l Mockingboard_Read_Out SY6522_Read_ORB move.b SY6522+SY_ORB(a5),d6 bra.s Mockingboard_Read_Out SY6522_Read_ORA move.b SY6522+SY_ORA(a5),d6 bra.s Mockingboard_Read_Out SY6522_Read_DDRB move.b SY6522+SY_DDRB(a5),d6 bra.s Mockingboard_Read_Out SY6522_Read_DDRA move.b SY6522+SY_DDRA(a5),d6 bra.s Mockingboard_Read_Out SY6522_Read_TIMER1L move.b .SY6522_TIMER1L_Data(pc),d6 subq.b #8,.SY6522_TIMER1L_Data ; Keep Skyfox's MB detection happy. ; Also clears Timer Interrupt Flag. and.b #~TIMER1,SY6522+SY_IFR(a5) bra.s Mockingboard_Read_Out .SY6522_TIMER1L_Data dc.b 0,0 SY6522_Read_ACR move.b SY6522+SY_ACR(a5),d6 bra.s Mockingboard_Read_Out SY6522_Read_PCR move.b SY6522+SY_PCR(a5),d6 bra.s Mockingboard_Read_Out SY6522_Read_IFR move.b SY6522+SY_IFR(a5),d6 bra.s Mockingboard_Read_Out SY6522_Read_IER move.b SY6522+SY_IER(a5),d6 Mockingboard_Read_Out move.l WRT_PageTable(a4),a5 Mockingboard_Read_Undefined ; Nb. Don't zero D6. moveq #0,d7 rts ----- Subject: Re: Ultima 3 "Mockingboard" version. From: Rubywand Newsgroups: comp.sys.apple2, comp.emulators.apple2 Linards Ticmanis writes ... > > Rubywand wrote: > > The C-64 definitely has better built-in sound than the 8-bit Apple II's. > > You especially notice the difference in stuff like the opening song for > > Alternate Reality. The Mockingboard's Programmable Sound Generator chip > > gives an Apple II the same capabilities. > > Does the Mockinboard contain any custom chips? Or is it something that > could be cloned with a bit of dedication? > .... Mockingboard uses off-the-shelf chips. Music and sound effects are produced using the General Instruments AY-3-8910 Programmable Sound Generator (PSG). (Some Mockingboard models include a chip to produce speech. Pretty sure these were also off-the-shelf items.) The 6581 Sound Interface Device (SID) chip used in the C-64 seems to work almost exactly the same as the General Instruments PSG. I'm pretty sure the 6581 is a proprietary chip. The PSG and SID can deliver three musical 'voices'. Mockingboard "Sound II" (and some other models) have two PSG chips. This gives the Apple II user two-channel sound and twice as many musical 'voices' as C-64 can produce. Besides the PSG, Mockingboard's use the 6522 for interfacing. A small audio amp chip (think it's the LM380) is included to allow directly driving speakers. (If you connect to an external amp, you can omit the LM380's.) So, yes; a Mockingboard for playing music and handling sound effects in games like Ultima III would be fairly easy to build. Rubywand