The Pro Audio Spectrum 16 NuBus's YMF262 FM synthesizer...

demik

Well-known member
Thank you. Will try with 7.5. It's either a 8.1 issue or the board is checking for the PatchPanel presence and doesn't enable outputs when it's not there.

Mapped a few of the analog parts, will double check with a scope.

As for the YMF262 / YAC512 combo, U11B is the output buffer opamp for theses, which some additional circuitry tuned for this application.
As @NJRoadfan suspected its output stage indeed was traced to the mixer chip (MVA508). Outputs pins are 1 and 14 (not sure which is left and right yet)

What's weird is that there is no mixer control for that in MacOS, so you will need to do that somewhat as well in order to use...
There is a few conflicting reports around the web, as the OPL could be controlled from MIDI and some others from software, with the game "Out of this world" supposedly having support for that.
 
Last edited:

Mr. Ksoft

Well-known member
@KennyPowers, @Mr. Ksoft, What MacOS version are you using ? I seem to have trouble having sound out of the codec. MacOS control panel reports a 0kHz ramping rate (Mac OS 8.1) Alert sounds make the menu bar blink as well
7.6.1 here, though iirc I used it on 8.1 a few years ago. The software is definitely quite buggy, when first installed I see it having the sampling rate set to nothing at all (blank menu selection) but then once selected it shows the correct values. I've also had times when the system alerts still come out of the system speaker but everything else from the PAS. But on some installs I've also had everything come out of the PAS. Can't find any rhyme or reason to it. I wonder if it works better on 7.1.
 

Mr. Ksoft

Well-known member
Hey folks, bumping this cause I've been poking at it again and would like to share my findings.

I started looking at this from a different perspective, namely, disassembling the PAS16 extension. I know basically no ASM so kind of stumbling through it while reading up on it, but I figured I still may find some hints that way.

Indeed, I do think I found some stuff. The extension has two blocks of code in the DRVR resource, .PAS16 and .BD_PAS16. Conveniently, .BD_PAS16 actually has a number of modules in it that have human-readable names, which helped lead me in the right direction despite barely being able to read the code. Of particular interest to the ultimate goal here are two named FM_Bd_Status and FM_Bd_Control. FM? That sure sounds like the OPL3...

Of course I can't make sense of it. They're pretty short and I think they depend on code from other parts of the extension. Might revisit this later.

Anyway, more importantly, there's some code labeled ResetHW_SetInitialState, tied closely to two named WrtByte and RdByte. I found this very interesting because I was able to make some connections here.

ResetHW_SetInitialState:
Code:
     FE0:                                 QUAL    ResetHW_SetInitialState ; b# =72  s#1  =proc42



                                 vbu_1     VEQU  -5

                                 vbu_2     VEQU  -2

                                 vbu_3     VEQU  -1

     FE0:                                 VEND   



                                 ;-refs - Bd_Control  Bd_Open   



                                 ResetHW_SetInitialState

     FE0: 4E56 FFFA      'NV..'           LINK    A6,#-6

     FE4: 48E7 0F10      'H...'           MOVEM.L D4-D7/A3,-(A7)

     FE8: 42AC 0218      'B...'           CLR.L   $218(A4)

     FEC: 2E2C 0214      '.,..'           MOVE.L  $214(A4),D7

     FF0: 0687 0008 0000 '......'         ADDI.L  #$80000,D7

     FF6: 2C3C 0000 8000 ',<....'         MOVE.L  #$8000,D6

     FFC: 2647           '&G'             MOVEA.L D7,A3

     FFE: 1D7C 0001 FFFB 200FFFB          MOVE.B  #1,vbu_1(A6)

    1004: 41EE FFFB      200FFFB          LEA     vbu_1(A6),A0

    1008: 1010           '..'             MOVE.B  (A0),D0

    100A: A05D           '.]'             _SwapMMUMode 

    100C: 1080           '..'             MOVE.B  D0,(A0)

    100E: 6008           1001018          BRA.S   lbu_2

    1010: 26FC 8080 8080 '&..... lbu_1    MOVE.L  #$80808080,(A3)+

    1016: 5986           'Y.'             SUBQ.L  #4,D6

    1018: 4A86           'J.'    lbu_2    TST.L   D6

    101A: 6EF4           1001010          BGT     lbu_1

    101C: 41EE FFFB      200FFFB          LEA     vbu_1(A6),A0

    1020: 1010           '..'             MOVE.B  (A0),D0

    1022: A05D           '.]'             _SwapMMUMode 

    1024: 1080           '..'             MOVE.B  D0,(A0)

    1026: 2F3C 000C 0000 '/<....'         PUSH.L  #$C0000

    102C: 4267           'Bg'             CLR     -(A7)

    102E: 4EBA FAEE      1000B1E          JSR     WrtByte

    1032: 4297           'B.'             CLR.L   (A7)

    1034: A975           '.u'             _TickCount ; :LongInt

    1036: 2A1F           '*.'             POP.L   D5

    1038: 548F           'T.'             ADDQ.L  #2,A7

    103A: 42A7           'B.'    lbu_3    CLR.L   -(A7)

    103C: A975           '.u'             _TickCount ; :LongInt

    103E: 2005           ' .'             MOVE.L  D5,D0

    1040: 5880           'X.'             ADDQ.L  #4,D0

    1042: B09F           '..'             CMP.L   (A7)+,D0

    1044: 62F4           100103A          BHI     lbu_3

    1046: 2F3C 0000 9A01 '/<....'         PUSH.L  #$9A01

    104C: 3F3C 00BC      '?<..'           PUSH    #$BC

    1050: 4EBA FACC      1000B1E          JSR     WrtByte

    1054: 2EBC 0000 9A01 '......'         MOVE.L  #$9A01,(A7)

    105A: 3F3C 00E2      '?<..'           PUSH    #$E2

    105E: 4EBA FABE      1000B1E          JSR     WrtByte

    1062: 2EBC 0000 BF88 '......'         MOVE.L  #$BF88,(A7)

    1068: 3F3C 0001      '?<..'           PUSH    #1

    106C: 4EBA FAB0      1000B1E          JSR     WrtByte

    1070: 2EBC 0000 F388 '......'         MOVE.L  #$F388,(A7)

    1076: 3F3C 0040      '?<.@'           PUSH    #64

    107A: 4EBA FAA2      1000B1E          JSR     WrtByte

    107E: 2EBC 0000 F389 '......'         MOVE.L  #$F389,(A7)

    1084: 3F3C 0001      '?<..'           PUSH    #1

    1088: 4EBA FA94      1000B1E          JSR     WrtByte

    108C: 7839           'x9'             MOVEQ   #57,D4

    108E: 4878 0F8A      'Hx..'           PEA     $F8A

    1092: 3F04           '?.'             PUSH    D4

    1094: 4EBA FA88      1000B1E          JSR     WrtByte

    1098: 383C 0080      '8<..'           MOVE    #$80,D4

    109C: 2EBC 0004 0000 '......'         MOVE.L  #$40000,(A7)

    10A2: 3F04           '?.'             PUSH    D4

    10A4: 4EBA FA78      1000B1E          JSR     WrtByte

    10A8: 4878 0B8B      'Hx..'           PEA     $B8B

    10AC: 4267           'Bg'             CLR     -(A7)

    10AE: 4EBA FA6E      1000B1E          JSR     WrtByte

    10B2: 4878 0B89      'Hx..'           PEA     $B89

    10B6: 4267           'Bg'             CLR     -(A7)

    10B8: 4EBA FA64      1000B1E          JSR     WrtByte

    10BC: 4878 0B8A      'Hx..'           PEA     $B8A

    10C0: 4267           'Bg'             CLR     -(A7)

    10C2: 4EBA FA5A      1000B1E          JSR     WrtByte

    10C6: 2EBC 0000 FF8B '......'         MOVE.L  #$FF8B,(A7)

    10CC: 486E FFFE      200FFFE          PEA     vbu_2(A6)

    10D0: 4EBA FA02      1000AD4          JSR     RdByte

    10D4: 082E 0002 FFFF 200FFFF          BTST    #2,vbu_3(A6)

    10DA: 4FEF 002C      'O..,'           LEA     44(A7),A7

    10DE: 6606           10010E6          BNE.S   lbu_4

    10E0: 422C 0220      'B,. '           CLR.B   $220(A4)

    10E4: 6006           10010EC          BRA.S   lbu_5

    10E6: 197C 0001 0220 '.|...  lbu_4    MOVE.B  #1,$220(A4)

    10EC: 2F3C 0000 EF8B '/<.... lbu_5    PUSH.L  #$EF8B

    10F2: 486E FFFE      200FFFE          PEA     vbu_2(A6)

    10F6: 4EBA F9DC      1000AD4          JSR     RdByte

    10FA: 7003           'p.'             MOVEQ   #3,D0

    10FC: C06E FFFE      200FFFE          AND     vbu_2(A6),D0

    1100: 5740           'W@'             SUBQ    #3,D0

    1102: 508F           'P.'             ADDQ.L  #8,A7

    1104: 6608           100110E          BNE.S   lbu_6

    1106: 197C 0001 021F '.|....'         MOVE.B  #1,$21F(A4)

    110C: 6004           1001112          BRA.S   lbu_7

    110E: 422C 021F      'B,..'  lbu_6    CLR.B   $21F(A4)

    1112: 4A2C 0220      'J,. '  lbu_7    TST.B   $220(A4)

    1116: 660E           1001126          BNE.S   lbu_8

    1118: 4878 0B88      'Hx..'           PEA     $B88

    111C: 3F3C 0007      '?<..'           PUSH    #7

    1120: 4EBA F9FC      1000B1E          JSR     WrtByte

    1124: 5C8F           '\.'             ADDQ.L  #6,A7

    1126: 306C 028C      '0l..'  lbu_8    MOVEA   $28C(A4),A0

    112A: 2F08           '/.'             PUSH.L  A0

    112C: 2F2C 0288      '/,..'           PUSH.L  $288(A4)

    1130: 1F3C 0001      '.<..'           PUSH.B  #1

    1134: 4EBA FCCC      1000E02          JSR     SetTheSampleRate

    1138: 7874           'xt'             MOVEQ   #$74,D4

    113A: 4878 138B      'Hx..'           PEA     $138B

    113E: 3F04           '?.'             PUSH    D4

    1140: 4EBA F9DC      1000B1E          JSR     WrtByte

    1144: 4878 1389      'Hx..'           PEA     $1389

    1148: 4267           'Bg'             CLR     -(A7)

    114A: 4EBA F9D2      1000B1E          JSR     WrtByte

    114E: 4878 1389      'Hx..'           PEA     $1389

    1152: 3F3C 0040      '?<.@'           PUSH    #64

    1156: 4EBA F9C6      1000B1E          JSR     WrtByte

    115A: 2EBC 0000 BF8A '......'         MOVE.L  #$BF8A,(A7)

    1160: 3F3C 0003      '?<..'           PUSH    #3

    1164: 4EBA F9B8      1000B1E          JSR     WrtByte

    1168: 2EBC 0000 8388 '......'         MOVE.L  #$8388,(A7)

    116E: 3F3C 0002      '?<..'           PUSH    #2

    1172: 4EBA F9AA      1000B1E          JSR     WrtByte

    1176: 4217           'B.'             CLR.B   (A7)

    1178: 306C 028C      '0l..'           MOVEA   $28C(A4),A0

    117C: 2F08           '/.'             PUSH.L  A0

    117E: 4EBA FCDA      1000E5A          JSR     SetTheSampleSize

    1182: 2EBC 0000 838A '......'         MOVE.L  #$838A,(A7)

    1188: 3F3C 0018      '?<..'           PUSH    #24

    118C: 4EBA F990      1000B1E          JSR     WrtByte

    1190: 2EBC 0000 838B '......'         MOVE.L  #$838B,(A7)

    1196: 3F3C 0049      '?<.I'           PUSH    #73

    119A: 4EBA F982      1000B1E          JSR     WrtByte

    119E: 4EBA F748      10008E8          JSR     ZeroOutMixer

    11A2: 3EAC 028E      '>...'           MOVE    $28E(A4),(A7)

    11A6: 1F3C 0001      '.<..'           PUSH.B  #1

    11AA: 4EBA FCFE      1000EAA          JSR     SetStereoMono

    11AE: 2EBC 0000 F38A '......'         MOVE.L  #$F38A,(A7)

    11B4: 3F3C 0002      '?<..'           PUSH    #2

    11B8: 4EBA F964      1000B1E          JSR     WrtByte

    11BC: 4878 0B8B      'Hx..'           PEA     $B8B

    11C0: 4267           'Bg'             CLR     -(A7)

    11C2: 4EBA F95A      1000B1E          JSR     WrtByte

    11C6: 4878 0B89      'Hx..'           PEA     $B89

    11CA: 4267           'Bg'             CLR     -(A7)

    11CC: 4EBA F950      1000B1E          JSR     WrtByte

    11D0: 422C 021E      'B,..'           CLR.B   $21E(A4)

    11D4: 383C 0080      '8<..'           MOVE    #$80,D4

    11D8: 2EBC 0004 0000 '......'         MOVE.L  #$40000,(A7)

    11DE: 3F04           '?.'             PUSH    D4

    11E0: 4EBA F93C      1000B1E          JSR     WrtByte

    11E4: 383C 00F9      '8<..'           MOVE    #$F9,D4

    11E8: 4878 0B8A      'Hx..'           PEA     $B8A

    11EC: 3F04           '?.'             PUSH    D4

    11EE: 4EBA F92E      1000B1E          JSR     WrtByte

    11F2: 4878 1788      'Hx..'           PEA     $1788

    11F6: 3F3C 0010      '?<..'           PUSH    #16

    11FA: 4EBA F922      1000B1E          JSR     WrtByte

    11FE: 4878 178B      'Hx..'           PEA     $178B

    1202: 3F3C 0060      '?<.`'           PUSH    #96

    1206: 4EBA F916      1000B1E          JSR     WrtByte

    120A: 4878 178B      'Hx..'           PEA     $178B

    120E: 4267           'Bg'             CLR     -(A7)

    1210: 4EBA F90C      1000B1E          JSR     WrtByte

    1214: 4878 1B88      'Hx..'           PEA     $1B88

    1218: 3F3C 00FF      '?<..'           PUSH    #$FF

    121C: 4EBA F900      1000B1E          JSR     WrtByte

    1220: 197C 0001 0222 '.|..."'         MOVE.B  #1,$222(A4)

    1226: 4EBA 0442      100166A          JSR     proc48

    122A: 3EAC 025A      '>..Z'           MOVE    $25A(A4),(A7)

    122E: 3F2C 0258      '?,.X'           PUSH    $258(A4)

    1232: 4EBA F572      10007A6          JSR     SetTheOutVolume

    1236: 4A2C 0220      'J,. '           TST.B   $220(A4)

    123A: 4FEF 005A      'O..Z'           LEA     90(A7),A7

    123E: 6724           1001264          BEQ.S   lbu_10

    1240: 2F3C 0000 FF8B '/<....'         PUSH.L  #$FF8B

    1246: 486E FFFE      200FFFE          PEA     vbu_2(A6)

    124A: 4EBA F888      1000AD4          JSR     RdByte

    124E: 082E 0003 FFFF 200FFFF          BTST    #3,vbu_3(A6)

    1254: 508F           'P.'             ADDQ.L  #8,A7

    1256: 6606           100125E          BNE.S   lbu_9

    1258: 422C 0223      'B,.#'           CLR.B   $223(A4)

    125C: 6006           1001264          BRA.S   lbu_10

    125E: 197C 0001 0223 '.|...# lbu_9    MOVE.B  #1,$223(A4)

    1264: 4CDF 08F0      'L...'  lbu_10   MOVEM.L (A7)+,D4-D7/A3

    1268: 4E5E           'N^'             UNLK    A6

    126A: 4E75           'Nu'             RTS     





    126C: 9752 6573 6574 4857    data25   DNAME   ResetHW_SetInitialState,0,0

WrtByte:
Code:
     B1E:                                 QUAL    WrtByte ; b# =59  s#1  =proc35



                                 vbn_1     VEQU  -1

                                 param2    VEQU  8

                                 param1    VEQU  10

     B1E:                                 VEND   



                                 ;-refs - WrtMixerByte  WrtMixerVolByte 

                                 ;-       SetTheSampleRate  SetTheSampleSize 

                                 ;-       SetStereoMono  proc41   

                                 ;-       ResetHW_SetInitialState  StartupPlaying 

                                 ;-       SetupForRecord  proc45   

                                 ;-       SetupForPlayingSound 

                                 ;-       MyCInterruptHandler  MIDI_Bd_Control 

                                 ;-       myReadProc  InitMIDI 

                                 ;-       SndOutputBd_Control 



     B1E: 4E56 FFFC      'NV..'  WrtByte  LINK    A6,#-4

     B22: 48E7 0110      'H...'           MOVEM.L D7/A3,-(A7)

     B26: 266E 000A      200000A          MOVEA.L param1(A6),A3

     B2A: D7EC 0214      '....'           ADDA.L  $214(A4),A3

     B2E: 3E2E 0008      2000008          MOVE    param2(A6),D7

     B32: 1D7C 0001 FFFF 200FFFF          MOVE.B  #1,vbn_1(A6)

     B38: 41EE FFFF      200FFFF          LEA     vbn_1(A6),A0

     B3C: 1010           '..'             MOVE.B  (A0),D0

     B3E: A05D           '.]'             _SwapMMUMode 

     B40: 1080           '..'             MOVE.B  D0,(A0)

     B42: 1687           '..'             MOVE.B  D7,(A3)

     B44: 41EE FFFF      200FFFF          LEA     vbn_1(A6),A0

     B48: 1010           '..'             MOVE.B  (A0),D0

     B4A: A05D           '.]'             _SwapMMUMode 

     B4C: 1080           '..'             MOVE.B  D0,(A0)

     B4E: 4CDF 0880      'L...'           MOVEM.L (A7)+,D7/A3

     B52: 4E5E           'N^'             UNLK    A6

     B54: 4E75           'Nu'             RTS     





     B56: 8757 7274 4279 7465    data19   DNAME   WrtByte,0,0

RdByte:
Code:
     AD4:                                 QUAL    RdByte ; b# =57  s#1  =proc34



                                 vbm_1     VEQU  -1

                                 param2    VEQU  8

                                 param1    VEQU  12

     AD4:                                 VEND   



                                 ;-refs - WrtMixerByte  WrtMixerVolByte 

                                 ;-       SetStereoMono  ResetHW_SetInitialState 

                                 ;-       Bd_Control  sampleSoundVol 

                                 ;-       MIDI_Bd_Control  myReadProc 

                                 ;-       CheckForMIDIData 



     AD4: 4E56 FFFE      'NV..'  RdByte   LINK    A6,#-2

     AD8: 48E7 0110      'H...'           MOVEM.L D7/A3,-(A7)

     ADC: 266E 000C      200000C          MOVEA.L param1(A6),A3

     AE0: D7EC 0214      '....'           ADDA.L  $214(A4),A3

     AE4: 1D7C 0001 FFFF 200FFFF          MOVE.B  #1,vbm_1(A6)

     AEA: 41EE FFFF      200FFFF          LEA     vbm_1(A6),A0

     AEE: 1010           '..'             MOVE.B  (A0),D0

     AF0: A05D           '.]'             _SwapMMUMode 

     AF2: 1080           '..'             MOVE.B  D0,(A0)

     AF4: 1E13           '..'             MOVE.B  (A3),D7

     AF6: 4887           'H.'             EXT     D7

     AF8: 0247 00FF      '.G..'           ANDI    #$FF,D7

     AFC: 41EE FFFF      200FFFF          LEA     vbm_1(A6),A0

     B00: 1010           '..'             MOVE.B  (A0),D0

     B02: A05D           '.]'             _SwapMMUMode 

     B04: 1080           '..'             MOVE.B  D0,(A0)

     B06: 206E 0008      2000008          MOVEA.L param2(A6),A0

     B0A: 3087           '0.'             MOVE    D7,(A0)

     B0C: 4CDF 0880      'L...'           MOVEM.L (A7)+,D7/A3

     B10: 4E5E           'N^'             UNLK    A6

     B12: 4E75           'Nu'             RTS     





     B14: 8652 6442 7974 6500    data18   DNAME   RdByte,0,0

If you look at ResetHW_SetInitialState, there are a number of times where it moves specific numbers like 9A01 or F388 into A7, PUSHes another value, and then jumps to WrtByte. As it turns out, if you look at the PC PAS16 SDK in /PAS/INC/COMMON.H, those numbers are actually the same as the address locations for specific parts of the PAS16 (example, 9A01 is the "Master Address Pointer" and F388 is "I/O Config 1") . This indicates that the addresses are laid out identically.

I don't think these are sitting right at the base card offset, but possibly C0000 which is referenced early on. I did try doing writes using that offset from the base card address and I did actually get a result... namely I get a buzz on the speakers while doing the writes, and then the PAS16 audio dies completely until I reboot. That's more than I got before!

My continually uneducated analysis: I think this extension has a good bit of the glue in it to translate PC-style writes to what NuBus is expecting, with WrtByte and RdByte possibly doing a lot of that heavy lifting. That may explain why doing direct writes to the memory space are not working, and why direct reads are producing all 0's all the time - it may need to read in a specific way that the extension is handling.

So where does this lead? Either I need to replicate what the extension is doing in terms of byte reads/writes, or alternatively I think I need to figure out a way to communicate with the functions already present in the extension. I started looking into the latter, reading into the Toolbox Device Manager, and wrangled a bit of the example code into at least successfully opening a reference to the .BD_PAS16 driver. I got stuck there, though.
Seems there are a couple ways I can communicate with the driver, but of course we don't have a reference to work with. Looks like I can directly read/write a buffer to the driver with PBRead/PBWrite but I have no idea what it would be expecting. I'm thinking PBControl and PBStatus may be more promising as they can "send commands to the driver". Might the named functions I'm finding in the DRVR resource be exposed this way? That would allow external applications like the mixer control panel to alter the card, or those elusive PAS-enabled games to talk to it.
Thing is, good luck determining what to send to the driver... I need a csCode number apparently and those can range from 128 all the way to 32768 if we rule out the Apple reserved ranges. If there's a way to get a list of valid csCode numbers out of a driver, I might be able to get somewhere, but I haven't figured that out yet. Right now, I think my goal is to figure out if I can call ResetHW_SetInitialState using this method, which might help me get the card to output sound again after a bad write without having to reboot :)
If I can figure that out, then I would have confidence that RdByte and WrtByte may allow me to start doing direct OPL3 writes.

And so the saga continues... I think I have a lot of the puzzle pieces now. Now it's just figuring out how to put those pieces together. I'm probably getting way out of my element, but I'm trying to keep learning and get a better understanding.
 

trag

Well-known member
Not anything of note to contribute, but will note that my PAS16 did come with a copy of "Out of This World".

It always felt like it was a powerful piece of hardware with no real drivers or software to support it, back in the day.

It will be cool if you unlock its mysteries. 30 years later, it finally gets software support...
 

Mr. Ksoft

Well-known member
Not anything of note to contribute, but will note that my PAS16 did come with a copy of "Out of This World".

It always felt like it was a powerful piece of hardware with no real drivers or software to support it, back in the day.

It will be cool if you unlock its mysteries. 30 years later, it finally gets software support...
Do you know if there was anything special about that copy? Seems like the rumor on the street is that it may have been a PAS specific version.
 

trag

Well-known member
Can you upload that copy somewhere so I can test it there ?

I will see if I can find it and hope the floppy drive is still working. I haven't tried it in a while. I know it's around here somewhere.... I may have a copy already archived to a hard drive in which case the process will be easier.
 

trag

Well-known member
Okay, I had all the disks in my floppy archive. Years ago I copied all my floppies to disk images.

I put them here:

http://sphinxgroup.org/PAS16/

Let me know if the images work. They should just be Disk Copy images. If there's a problem I can binhex them or something.

I also had an archive of the LC version of the PAS16 disks.

The %AA was the trademark emblem. I guess that's how it converts.
 

Mr. Ksoft

Well-known member
Thanks, I was able to get these images working.
The copy of Out of this World is, in fact, a specific OEM version! It's marked as version "1.0mv" (presumably mv for Media Vision). Whether that means anything for this project remains to be seen. I messed with it a bit and the sound seems exactly the same as a regular copy of the game. They do seem to have slightly different sound driver resources, but that could just be a version difference as I'm using OotW version 1.0.3. Definitely something to look into further, though.
 

demik

Well-known member
How do you use the image file ? I've been trying with DiskCopy but it doesn't like it (because no ressource fork I guess)
 

Mr. Ksoft

Well-known member
Hey folks! I hadn't looked at this in a while, but I'm jumping back in as a project for this month.

I haven't really picked up 68k ASM like I hoped so reading a straight disassembly overall didn't do me much good. I decided to pivot a bit and try running the DRVR resources through Ghidra to get some messy decompiled C - which is considerably more readable for me. It is not perfect at all, in fact I may be doing it wrong considering sometimes I'll see function calls that are given 3 parameters but the decompiled function only shows 2, but good enough to find some things.

Unfortunately, the first thing I found is that FM_Bd_Status and FM_Bd_Control are effectively stubs. They basically just check if the number 6000 (or 1770h) is passed to the function, and if it is, they return a good status code, and if they don't, pass an error code. There is no code there to write to the card. This is in comparison to other functions like ResetHW_SetInitialState which calls such functions as WrtMixerByte which in turn calls WrtByte.

WrtMixerByte, however, is actually pretty educational because it shows calls to WrtByte, and one of the parameters it passes is the value 0xB88, which in the PC PAS16 documentation is the mixer address. This seems to confirm that the I/O addresses for the card are laid out the same as the PC card. I believe that WrtByte does some translation from the PC layout to talk to the correct memory addresses for the NuBus card, but the somewhat messed up decompliation is still confusing me. It would be easier if I could find a way to call WrtByte myself and let the driver do the heavy lifting - I could just use it to write to 0x388 and I believe it would "just work". The question is how to do that, unless it's exposed via the driver interface.

I've kept working on trying to talk to the driver via Device Manager and I guess you could say I've had some success. Continuing from last year's success opening the driver, I've managed to start finding csCode values I can send to the driver via PBControl. I think these call into the Bd_Control function which does a number of value checks that align with the ranges of valid csCodes I've identified. That said, I don't really know what they do yet. Values 1001 and 1002 cause a click on the speakers, 2001 and 2002 cause a constant buzzing and screeching that doesn't stop until I send 1001 or 1002 again - there are definitely tied to controlling audio output in some way. Typically there are clusters of valid numbers around the thousand boundaries (like 1001-1006) with the rest returning the status code indicating an invalid value, but the decompiled code I looked at shows much broader ranges (like an entire 1000 values all supposed to call the same function) so I'm still confused about that. Some valid numbers like 1006 cause a Bus Error in MacsBug and I am unable to break out of the program successfully, requiring a restart - which makes it a pain in the butt to just try every possible csCode in order to find the valid ones. I noted that 6000 is a valid csCode, which would align with the number FM_Bd_Control is looking for, but if it's getting there, it'll be hard to tell since that function is useless.

I'm also not sure if I can send data into the driver via PBControl or just receive success/failure data back via the parameter block. If so, I'd have to figure out what parts of the parameter block the driver is expecting to see data in - and if there's anything that can get that data to the part of the driver I want. I also looked into the more basic PBWrite function but it basically just sends data buffer directly to the driver and I have no indication where the driver would receive or process any of that (if it can). Seems too open-ended to explore yet; at least with PBControl I get some feedback on the csCode values. Maybe I need more knowledge from someone more familiar with the Device Manager. If there's good example code out there (more than just the basic examples in Inside Macintosh) it's probably buried in magazine cover discs or something - definitely not something I have found on a search engine.

So I think there's progress here, but it's a bit hampered by my inexperience with 68k ASM, Mac programming, and reverse engineering in general. Someday we're gonna get this figured out, though. I'm confident it's possible.

EDIT: Also, we looked at a bundled copy of Out of the World before, but apparently there was also a version of Fate of Atlantis mentioned in a manual scan that I never noticed. This says it's modified and calls out synthesis specifically... I wonder if it really is? Sensible game for it, too, given that the iMUSE system shines with synthesized music.

LucasArts Indiana Jones and the Fate of Atlantis is a challenging adventure game that has been especially modified to take advantage of the sound synthesis available on your PAS 16 Mac equipment.
 
Last edited:

oldappleguy

Well-known member
I have a used but boxed Pas 16 nubus Would like to pass it on to someone
 

Attachments

  • IMG_0347-1.jpeg
    IMG_0347-1.jpeg
    2.5 MB · Views: 23
  • IMG_0349.jpeg
    IMG_0349.jpeg
    1.8 MB · Views: 23
  • IMG_0351.jpeg
    IMG_0351.jpeg
    3.5 MB · Views: 23

Mr. Ksoft

Well-known member
I hope your card makes it to someone that either wants to check out this OPL3 mystery, or someone who eventually wants to enjoy the fruits of our labors!

I have an update that seems promising. I spent a lot of time just calling csCodes and stepping instruction by instruction through MacsBug to see what was getting loaded into the registers, having noted that register A3 stored the address to be written by WrtByte (or read in the case of RdByte).

Overall, this has made it seem like... well, I've been overthinking it. My original approach of just poking at address 0x388 of the card memory space wasn't really off the mark. I found that if the driver calls to set the mixer, it calls WrtMixerByte which then calls WrtByte, and that just writes to the addresses 0xB88 through 0xB8B offset from the start of the NuBus slot's memory space. Basically, the same spot as the PC card. I did also see some times when A3 stored the offsets 0x40000 and 0xC0000 but I think these may be red herrings. Writing anything to the former freezes the computer, anyhow.

I went back and wrote a new test program, and studied the code for WrtByte to see what it was doing differently to write to card addresses. Turns out what I was missing that WrtByte was doing is that it calls SwapMMUMode() before and after writing to card memory. Quoting Inside Macintosh...
If you are writing a driver for a slot-card device, you can use the SwapMMUMode procedure to change to 32-bit address-translation mode temporarily
I don't quite understand why this is necessary since the machine is already in 32-bit mode. I could see this being needed if MacOS was running in 24-bit mode since NuBus is a 32-bit bus. But adding this and then reading a byte from the NuBus space, I can actually get values back and not just 00's!

From there, my OPL detection routine started working without any changes:
DetectionSuccess.png

However, the test note that I play afterwards... well, I don't hear it! I am confident that my writes are making it to the chip, though - the detection routine works by manipulating the OPL timers and reading its status register. The fact that the values are as expected AND the value that differentiates an OPL2 from OPL3 all check out is a very good sign.

What's likely is that, since they didn't write any driver functionality for the OPL3, they muted it by default in the mixer (no point having low-level noise/hiss/etc coming off a chip that's not going to output anything). I tried just writing maxed out values to the mixer registers and nothing changed, so I think there's a mute flag somewhere else for those channels. Next step is to play around with my 386 PC with a PAS16 ISA card in it and see exactly what writes it does for the FM mixer channel (instead of firing blindly like I am now), then replicate that on the Mac.
 

demik

Well-known member
From there, my OPL detection routine started working without any changes:
View attachment 84285

However, the test note that I play afterwards... well, I don't hear it! I am confident that my writes are making it to the chip, though - the detection routine works by manipulating the OPL timers and reading its status register. The fact that the values are as expected AND the value that differentiates an OPL2 from OPL3 all check out is a very good sign.

What's likely is that, since they didn't write any driver functionality for the OPL3, they muted it by default in the mixer (no point having low-level noise/hiss/etc coming off a chip that's not going to output anything). I tried just writing maxed out values to the mixer registers and nothing changed, so I think there's a mute flag somewhere else for those channels. Next step is to play around with my 386 PC with a PAS16 ISA card in it and see exactly what writes it does for the FM mixer channel (instead of firing blindly like I am now), then replicate that on the Mac.

From my understanding when building the daughter board to replace the breakout box, the OPL3 goes through the mixer. There is few places where you can poke if the sound comes out. Check the opamp U11B outputs or the OPL preamp before that
 
Top