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
,
PUSH
es 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.