• 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.

Atomac: Acorn Atom Emulator For Classic Mac OS

Snial

Well-known member
A long time ago, I wrote an emulator for the Acorn Atom, a 1MHz 6502 home computer with a rather strange version of Basic and integrated macro assembler (yes). It's the grandad of the Archimedes, so you can see quite a bit of their first ARM computers in this machine. Actually, I took an X11, based Linux emulator from a Dutch guy and ported it to my PowerBook 5300 as a native PPC app using Metrowerks, where I was able to get it to emulate at the full speed of a real Acorn Atom.

But it took me a PPC Mac to make it that fast, which is why I'm impressed by SoftPC emulators getting anywhere near real PC speeds on 68K Macs. Admittedly, mine's written entirely in C and I think you'd need about a 20MHz '030 to achieve 100% emulation speed even in assembler. It boots to this:

1713392854930.png

When I developed it, I was running Mac OS 8.1, but it runs fine on InfiniteMac.org, with a PowerMac 9500 under Mac OS 7.6. There's two files included here, the application itself and the Metrowerks source code version. The application itself also contains a docs file which summarises the efficient Acorn Atom Basic (its 1MHz BASIC was faster than the original 4.77MHz IBM PC's GW BASIC) and how to write a bit of assembler code in it. Oddly enough, despite being fairly crude, the Atom can do colour graphics thanks to its Motorola MC6847 video chip.

Code:
10 DIM P2;[ TAX; RTS ];LINK TOP;END

Is a one-line program which allocates 2 bytes for a program (DIM P2); assembles a (useless) 2 instruction program ( [ TAX; RTS ]) and runs it (LINK TOP).
 

Attachments

  • AtomacApp.hqx.zip
    64 KB · Views: 1
  • Atomac0.8.1Source.sit.hqx.zip
    132.1 KB · Views: 0

Snial

Well-known member
Oooh, fun!
Fun indeed! Here's the first 'improvement', Atomac was originally written to run under CodeWarrior for PPC. Here I've converted it to run under Think C 5 for 68K. Keyboard scanning doesn't quite work at the full rate (some keys are missed) and every kind of Reset apart from the normal Reset seems to mess up memory. The app is 57kB and runs at about 70% to 90% full speed on the Quadra 650 emulator on Infinite Mac. I'll try and speed it up, but my next objective really is to make it work in monochrome (rather than 16 colour or 256 colour mode).

1713543661040.png
It would be great if I'd written a program to say "Hello 68KMLA" on the Atomic/68K version, but in fact I just typed it out using the cursor keys <shameOnMe>.

BTW: @mihai , I originally tried to use the THINK C IDE from Infinite HD, but opening the folder kept giving me this error:

1713543952264.png
So, I ended up copying my THINK C 5.0.4 to my Saved HD and using that version.
 

Attachments

  • AtomacProjTC.cpt.hqx.zip
    256.7 KB · Views: 0
  • AtomacTC.cpt.hqx.zip
    29.3 KB · Views: 0

Phipli

Well-known member
Fun indeed! Here's the first 'improvement', Atomac was originally written to run under CodeWarrior for PPC. Here I've converted it to run under Think C 5 for 68K. Keyboard scanning doesn't quite work at the full rate (some keys are missed) and every kind of Reset apart from the normal Reset seems to mess up memory. The app is 57kB and runs at about 70% to 90% full speed on the Quadra 650 emulator on Infinite Mac. I'll try and speed it up, but my next objective really is to make it work in monochrome (rather than 16 colour or 256 colour mode).

View attachment 72872
It would be great if I'd written a program to say "Hello 68KMLA" on the Atomic/68K version, but in fact I just typed it out using the cursor keys <shameOnMe>.
Think supports inline assembly doesn't it? Could an analysis of where time is spent in the main loop be done to see if there is a single routine that could be optimised to make a big speed improvement?

This is absolutely awesome by the way, I should have probably started with that, rather than jumping right in with suggestions that are easier to say than do 🤣
 

Snial

Well-known member
Think supports inline assembly doesn't it?
Yes, and I know how to use it :) !

Could an analysis of where time is spent in the main loop be done to see if there is a single routine that could be optimised to make a big speed improvement?
Yes. I already know a few things I can do:
  • THINK C 5 doesn't support inline functions. The central get byte function was originally inline, but for compiling purposes I just deleted that. I would replace it with a #define macro. This would improve all the get byte operations including instruction fetching (I think, since I think it also uses get byte).
  • The set byte function is badly optimised, because it first checks for video, then for I/O (i.e. the keyboard byte); then lastly a normal write. As a Macro, I should rearrange that so that it first checks for normal memory, and writes to it if so; then checks for I/O (video or keyboard) handling video first.
  • As well as figuring out how to vector via inline assembly (which will improve performance); I'll also want to change how flags are generated since flag-handling is pretty slow on most emulators (I'm forever seeing blocks of code that handle each flag individually). The 68000 generates a similar set of flags to the 6502. So, the easiest way to handle flags is to copy the CCR to the 6502 state variables (move CCR,target) after the appropriate instruction. Then, for Bcc instructions we just jump based on those flags. Only for PHP, PLP or any other flag-handling 6502 instructions, should it convert from the 68000 representation to the 6502 representation.
This is absolutely awesome by the way, I should have probably started with that, rather than jumping right in with suggestions that are easier to say than do 🤣
No worries, I'm forever plaguing @mihai with InfiniteMac issues without doing a single thing to fix any! So, thanks a lot for the encouragement!
 

Snial

Well-known member
I've updated Atomac (which I pronounce "A-tommuk", rather than "Atom-Ack" or "Atto-Mac", so that it sounds more like "Atomic"). I 'fixed' the problem of missing keypresses, by hacking the Atom ROM to ignore flyback scans when scanning the keyboard. Nevertheless, because I now run frames at closer to 60Hz, the performance has actually gone down, because I execute fewer cycles per main loop on the Quadra 650 emulator I'm using on InfiniteMac.org (you'll need my installation of THINK C, the installed one's folder doesn't open properly).

I found that the emulator does actually run in monochrome (I didn't try graphics, just text mode, but that's good enough for me). I tried to improve the emulator speed by substituting assembly code for effective address calculations, but actually it was less efficient than whatever the compiler is doing (and I started to look at the compiler code). I have a few register variables, but on a 68000 you never get many. I haven't worked on improving flag access: the disassembly shows it's far too slow. Also, the 6502 emulator itself is fairly messy - it always was and I've made it messier! I've removed one level of switch indirection though.

Here's the current version in action:

1713617261144.png
As you can see, it's running in 1bpp. The program animates a crude block-graphic alien carrying each letter of the message across the top of the screen and then letting it drop; starting at the last character and working backwards. It's a crude 1-screen program, but it illustrates a few Atom techniques and peculiarities:
1713617416688.png
  • '#' denotes hex numbers (this carries on all the way to the ARM-based Archimedes computers).
  • '?' is PEEK and POKE byte.
  • DIM A20 makes A point to 20 characters of allocated space, $A then treats A as a string pointer.
  • ';' is used to separate commands, instead of ':' on conventional BASICs.
  • Inverse 'A' is a label, you can create 26 labelled subroutines, do GOSUB (inverse) A to call it.
  • You can abbrieve most commands by appending '.' as long as the commands can be distinguished.
  • Print assumes the equivalent of ';' in normal BASICs, so you don't need it between items and if you want <cr> at the end of a line, you need to type an apostrophe!
  • $x displays a character whose code is x (i.e. CHR$(x)) if x<256 or the string if x>=256.
  • Page 0 Addresses are system variables. 0xdf:0xde point to the beginning of a display line. 0xe0 is the print position from the start of the line. 0xe1 is the character code for the cursor (so setting it to 0 turns it off, setting it to 128 makes it the block as normal).

Finally, of course, my screenshots are now done by setting the display to 512 x 384, which is the perfect resolution introduced by the landmark Mac LC (of which one geriatric specimen is currently available for £60 in the UK).

Happy emulating!
 

Attachments

  • AtomacTC.cpt.hqx.zip
    29.3 KB · Views: 0
  • AtomacProj.cpt.hqx.zip
    241.4 KB · Views: 0
  • ThinkC5.cpt.hqx.zip
    1.2 MB · Views: 0
Top