• Updated 2023-07-12: Hello, Guest! Welcome back, and be sure to check out this follow-up post about our outage a week or so ago.

Making a Game in Assembly with MDS 2.0

jkheiser

Well-known member
Tonight I did some more debugging with MAME and learned the culprit of the big nasty pop that plagues all the sounds on 128k and 512k Macs: it’s KillIO, which MacKaboom’s sound framework calls before every sound. It fills the buffer with $FF, the loudest byte there is.
MacKaboom’s sound framework uses KillIO before every sound so the Device Manager can stop whatever is playing in order to play what’s next. Without it, sounds cannot interrupt sounds. Instead, they pile up in the Device Manager’s I/O queue and wait their turn to be played.

What if... instead of calling KillIO, we pull a switcheroo on the Sound Driver while it is busy? Let’s give it a shot by setting up a common Parameter Block all sounds can share. Whenever the sound framework’s PLAY_SOUND_ASYNC routine is called, this block is updated accordingly:
  • ioBuffer
    ffSynthRec of next sound
  • ioReqCount
    WaveByte length of next sound
  • ioNumDone
    Reset this to zero
If ioReqCount and ioNumDone are the same, that means whatever sound was playing is done, and that means we have to call _Write,ASYNC to start our sound. If they are not the same, however, then the Sound Driver is already streaming bytes to the hardware buffer and we can skip the write trap.

Did it work? Yes it did! No more nasty pop on a Fat Mac! In fact, I think this technique makes the transition between sounds smoother. No cycles are chewed up with KillIO. Instead, we’ve nearly instantly switched to a different stream of WaveBytes.

I need to do some more testing with this. Because sound generation is interrupt driven, there is some risk in meddling with these fields while the Sound Driver is busy. This switcheroo involves at least three operations, and any one of them could get interrupted, leading to unwanted side effects.
 
Last edited:

jkheiser

Well-known member
And there it is: a Device Manager Error when you quit the application. There is some housekeeping in the Device Manager that is not getting done correctly after the contents of the I/O queue are tampered with directly. Fortunately there are toolbox routines for managing this queue. MacKaboom’s sound framework will have to do some cleanup when it finishes jerking the Sound Driver around. More fun R&D!

As an aside, this is one of the reasons I decided to make this particular game. Look at this juxtaposition! I love it.

device-error.gif
 

Snial

Well-known member
I got some assembly tips from the maker of Advanced Mac Substitute and tried one with John Stogdell Stokes III’s M68000 Condition Code Demonstrator, a terrific Desk Accessory that lets you evaluate M68k operations. A later version (1.3) is on Macintosh Garden.

The demonstration below and shows how to flip the 16th bit of a video buffer address to ascertain its alternate. Thanks for the tip, Josh!
I thought AMS had gone inactive, because when you click on the GitHub link from the main page [Source code], you get 404. The correct link is: https://github.com/jjuran/metamage_1 . It looks useful. I thought I knew how all 68K instructions affected the conditions codes, but in my current MacASM app development (where I set the mini vMac speed to 1x for extra authenticity pain :) ), I used swap to switch between menu Ids and menu items:

swap d0 cmp.w #kMenuIdFile,d0 swap d0 bne.s DoMenu20 ;File menu handling

It doesn't work, because swap d0 also does tst.w d0. I'd either forgotten that or I'd become confused by ARM condition code behaviour.
 

jkheiser

Well-known member
A light bulb went off in my head tonight: why not use the better Sound Driver that’s in the 128K ROM? So I copied its bytes and pasted them into a DRVR resource inside MacKaboom. There’s no way this crazy idea will work, right?!

HAHAHAHA IT DID!

Seriously, I cackled. What a great feeling.

This is a much better solution than that crackpot switcheroo gimmickry I was contemplating.

sound-driver.gif

Code:
; -----------------------------------------------------------------------------
; Use superior Sound Driver from the 128k ROM

UPGRADE_DRIVER

    MOVE.L          #(ioQElSize/2)-1,D0     ; Make loop for stack-based PB
@0  CLR.W           -(SP)                   ; Zero out PB fields on stack
    DBRA            D0,@0                   ; Loop until all done
    MOVE.L          SP,A0                   ; Point A0 at start of PB
    MOVE.W          #sndRefNum,ioRefNum(A0) ; Set ioRefNum to Sound Driver
    _Close                                  ; Close ROM-based driver
    LEA             '.Sound',A1             ; Get address of driver name
    MOVE.L          A1,ioFileName(A0)       ; Put driver name in PB field
    _Open                                   ; Open better driver
    ADD             #ioQElSize,SP           ; Clean up stack
    RTS                                     ; Return from subroutine
 

CC_333

Well-known member
Neat!

Since the better sound driver from the 128k (aka Plus) ROM is now implemented as a DRVR resource, could it theoretically work as such on Macs with the original 64k ROM (128k and 512k), or are there other dependencies?

c
 

mdeverhart

Well-known member
This whole thread is amazing! I knew things like this were possible on classic Macs, but it’s fun seeing it in practice. Great work, and keep the updates coming!
 

jkheiser

Well-known member
Since the better sound driver from the 128k (aka Plus) ROM is now implemented as a DRVR resource, could it theoretically work as such on Macs with the original 64k ROM (128k and 512k), or are there other dependencies?
Yes! I should have mentioned that it was tested on a Fat Mac. The only dependencies are the same global variables that are in the 64K ROM.
 

jkheiser

Well-known member
Have you tested it on a 128k, or is there not enough RAM?
I just tried it on the original 128k Macintosh. It works, but there’s room for only one sound to play. Granted, many of the sounds right now are luxurious in length because all development is being done on a 4-megabyte Mac Plus.

An alternate slate of abbreviated sound effects will be necessary for the 128k Mac. Later models can get the deluxe sounds, but the 128k gets the diet versions. I really want to support the original Mac. Too many collectors hate on it because they can’t get anything to run.
 

jkheiser

Well-known member
Seriously, one of the reasons I enjoy programming for the old Mac is how modular the OS is in weirdly unexpected ways. I've had several of this kind of moment...
100% true. The Resource Manager was a stroke of brilliance, and a gateway for my younger self to explore the Macintosh visually and modularly. Before them—and on other computers—I just stared incomprehensibly at lakes of hexadecimal soup. Spelunking with ResEdit was exciting, dangerous, educational, transgressive, and fun!
 

Crutch

Well-known member
Stumbling belatedly on this thread.

I love this project. Writing a nice and very sleek game for a 9” B&W Mac in MDS assembly is pretty high on my wish list, too (though right now I’m obsessed with writing system extensions for 7.0 in THINK C).

Following along with great interest.

How’d you create those terrific-looking graphics?

Re your device manager error at top of this page, maybe not relevant anymore but are you aware of the IAZNotify hook? It allows you to install code to be called if your application exits for any reason. Can be useful to ensure certain types of cleanup absolutely always happen no matter what. http://preserve.mactech.com/articles/mactech/Vol.04/04.10/HFSTransferDA/index.html
 

Crutch

Well-known member
One thing I couldn’t resist, I noticed this in your video:

1677701308362.png

I’m sure you know but maybe worth mentioning you don’t need ApplScratch here? Just push your rect on the stack, then pass the SP to _DrawPicture (and adjust the SP when you’re done). Example:

move.w #512, -(sp)
move.w #342, -(sp)
move.l $00000000, -(sp) ; (0, 0)
pea (sp)
_PaintRect
addq #8,sp ; pop our Rect off the stack

Your way saves 8 bytes on the stack which is cool, but somehow I find it more elegant to avoid sticking stuff into ApplScratch. 🤷‍♂️
 
Last edited:

jkheiser

Well-known member
How’d you create those terrific-looking graphics?
Hey, glad you like them! A good chunk of my adolescence was spent doodling in FatBits, making StartupScreens, customizing icons, vandalizing PICT resources, and drawing art for my World Builder game. 1-bit pixel artists like Mark Stephen Pierce, Trici Venola, Robyn Miller, and Mike Saenz were my heroes. As for this game, there’s a wealth of advertising material (for the original Atari game) that I’m liberally adapting with Photoshop.

Thanks for the tip on IAZNotify and how to use the stack better. I definitely want to get more creative with the latter.
 

Crutch

Well-known member
Ooo Steve Reeve is definitely getting a play. I was a World Builder myself circa 1990.
 

Crutch

Well-known member
by the way @jkheiser I also like that Condition Code DA but haven’t been able to figure out all the info. Like for example, what do the little filled vs hollow circles mean? Do you have a copy of the documentation by chance? (The DA says you get a copy if you pay the shareware fee…)
 

jkheiser

Well-known member
Funny you should ask! I just “connected the dots” myself when posting that screenshot of ConCode a few days ago.

The dots tell you what addressing modes are supported by the operand based on its memory size. For instance, BCHG supports waaaaay more addressing modes if the destination operand is just byte-sized.

operand-size.gif
 

Crutch

Well-known member
One more question @jkheiser did I read right that you are using MAME? How is that going? Are there good docs anywhere on how to set up MAME to emulate a 68K Mac? I have struggled to find anything really straightforward.
 

jkheiser

Well-known member
@Crutch: Most of the time I am using Mini vMac for its conveniences; all those Gryphel Project tools are indispensible. For debugging, TMON is usually good enough. But sometimes (often) my code breaks TMON! That’s when I turn to MAME. It has “god-tier debugging”, according to 4am, who has been using it recently to crack the copy protection on early Mac titles. MAME lets you view the contents of registers, memory locations, and disassembled 68k. You can set breakpoints and step through code. It also has watchpoints, which are amazing. It will break when a memory location is changed!

It’s not the most user-friendly setup. Some things you have to figure out yourself, but you’ll have no trouble. Here is a command snippet that probably comprises half my .zsh_history. It might be helpful.

Bash:
./mame macplus \
       -mouse
       -switchres
       -resolution 1024x684
       -gl_glsl -gl_glsl_filter 0
       -flop1 /Users/jason/Emulation/Macintosh/scratch.dc42
       -debug

68K-specific commands:

Debugger-specific commands:

mame-debugger.png
 
Last edited:

Crutch

Well-known member
Looks awesome (of course Macsbug can do all that too — but it must be very elegant to be able to do it from “outside the box” in parallel with running your app). I will have to give it a try!
 
Top