One thing I've learned is that Inside Macintosh is just the primer. It may look like all you need - it lists all the Toolbox functions and how they work, and walks you through how things ought to fit together!

But in reality to make anything beyond TeachText you need to read: every Technote, every Q&A, skim every relevant sample code, every Snippet, and also read every issue of develop.

Then you can start to approach being able to attempt to do something!

#VintageApple #RetroComputing

Today I've been banging my head against AppleTalk ioCompletions. Inside Mac just says "you can use them! they're in interrupt so watch out!" Headers have a callback signature, great! Easy.

The naive approach worked great on PPC, but crashes on a pointer out in space on 68k. Weird.

Apparently to use them on 68k you need assembly code. Only documented in this develop article by @jimluther referenced by some sample code...

@jimluther Even armed with this exhaustive article, I'm still unable to get it to work. It was some faff figuring out inline asm in CW6, but even though the disassembly looks sane(?) the values are wrong

And it still doesn't explain why it magically works on PPC? I guess I need to study the history of Pascal and C calling conventions as well as they must have changed it to match whatever Apple were doing here?

In the end I may just say screw 68k and let them have their servers WaitNextEvent...

@jimluther Left: "Wow this works great on PPC, and I'm handling the A5 stuff on 68k for any future changes this is great and so easy to do”

Right: 4 hours later, whittling everything down to get it to work at all on 68k, I'm not even using globals anyway who needs the A5, adding inline ASM to copy registers manually, still doesn't work at all…

@kalleboo @jimluther What is the version on the right supposed to be doing? It looks like charPtr will always be 0 and you are computing a bad address which is 0 minus some positive value?
@_the_cloud @jimluther From what I've been able to understand is that the iocompletion doesn't put the atpPBPtr into whatever a high-level compiler is expecting for a function signature (yes I need to study pascal calling conventions to understand this properly, next weekend I guess) but instead just puts it into register a0. The sample code on the dev CDs uses this assembly to do that
@_the_cloud @jimluther So what my desperation code is attempting to accomplish is to first force CodeWarrior to assign a register we can work with by creating a local variable (the set to 0), and then uses inline assemly to copy the a0 value we want into that register, so we can then use it in C for our pointer math and assignment.

@kalleboo @jimluther Ah, I see that now. But I also see that you are subtracting the size of the struct from the pointer, and the size of that struct is only 8 bytes. Does the param block immediately follow it in memory?

In the first image it looked like the Info struct pointer was the same as the PB ptr, implying you made a new struct which extended the PB with items at the end, rather than in front.

@_the_cloud @jimluther Yeah the is something suggested in both the Apple sample code and Jim's article. The only data you have going in or out is the ParamBlock pointer so allocate a pointer with extra data before it (A5 + your own data ptr) and do pointer math to work back to get at that data.

In the original version I was using a pretty struct with the PB first so the release was the same as before but in an attempt to get closer to the sample code just in case I changed to the pointer math

@kalleboo @jimluther One thing to try would be to stick a Debugger() call in your completion routine, just after the GetPBPtr(). and inspect what the registers are pointing to. Is the value you get handed in A0 actually pointing to your PB?

@_the_cloud So, after studying the calling conventions for 68K and PPC, the difference in behavior makes sense - on PPC when calling routines, parameters are put in registers whereas on 68K, parameters are put on the stack.

When calling a completion routine inside of an interrupt, setting up the stack of a callback is probably a messy affair (you're in another process!) so they want to break convention and use a register for the parameter. On PPC, that's already the default, so it just works!