18/09/2018

Setting the record straight on AMOS

I feel I have an apology to make.

One of my first posts, and the one people most seem to appreciate, is the one in which I absolutely slated AMOS for the Amiga as a programming language. I went to some lengths on the matter of how poorly I found AMOS to be constructed, how its organization was lackluster, and pointed to the inconsistency of its design and various choices made. Those were the things that frustrated me back when I was a weedy little sprog desperate to code games on the Amiga.

Which is all well and good, but that's not everything that is important about a language. A language isn't just its syntax or its implementation. The most important part of a language is the intangibles. The community. The accessibility. The culture.

AMOS had that. And what's more... it still does. In my post I made mention of François Lionet, the man who wrote AMOS. I paid him what was at best a backhanded compliment, in saying he was an able programmer. Not only did I undersell things (the man wrote a language that touched almost all of the Amiga's hardware, and in a fast but systems-friendly way), but I did the man himself a tremendous disservice.

AMOS had its share of flaws, yes. But if the alternative was not to push it out the door, aspiring Amiga coders would have had a much higher bar to clear.

And perhaps that was why my reaction to it was so negative. As the youngest boy in a well-to-do academic household, I grew up internalizing elitism and my supposedly fated intellectual superiority. AMOS was supposed to teach me how to attain full control over the machine, and yet learning its basics brought me no closer to understanding Assembler or C. I think my lingering resentment toward AMOS may be a reflection of my own reaction to a perceived failing, and the need to reframe AMOS as a condescending play-toy.

If that's true, I'd say it's high time I grew out of it. I now believe that François Lionet was entirely correct on several key points.

  • The Amiga community needed a REPL-capable language that was powerful, reasonably fast, and tailored to the machine. AMOS was that.
  • The playing field needed to be leveled. The Amiga base was largely split into gamers and power users, with few of the latter having the patience to educate the former. But coding should not just be the province of an enlightened priesthood. The Amiga, after all, always held the potential to be all things to all people. For all its flaws, AMOS democratized coding. That is a badge of honor.
  • AMOS is often good enough. It's not weak simply for not being Assembler, and you can pull off some pretty impressive things in AMOS if you know how. That fact is often overlooked, but no less true for all that, because the worth of a program isn't in its presentation. If you have a game that is shit in 16 colors and increase the colors to 256, then what you have now is slightly more colorful shit. What makes a good program? Solid concepts. Great art. Attention to detail. Clever use of algorithms. If your idea is good enough, it should be viable on the Amstrad.
  • Documentation is key. Most Amiga programmers wrote their own instructions, which tended to be confusing, omit key information, and generally required you to live inside the author's skull. Worse for me as a teen was that nobody seemed to acknowledge this, which left me with the impression of constantly missing something important. In AMOS, François Lionet produced a manual that actually made a degree of sense. While it still managed to confuse me in places (mainly in mixing AMOS-specific concepts with general Amiga ones), the manual was very readable, explained most concepts in a way that didn't confuse the reader, and was sensibly laid out.
  • It was inspiring. Where other communities were opaque and grudging, AMOS wanted to welcome you. Back then, I wanted coding to be a secret club, so I scoffed at the lack of gatekeeping. Even then, though, Lionet's honest celebration of aspiring coders shone through, and it was a great motivator. It's a pity I didn't fully appreciate that back then, but I treasure it all the more today. We need a more enthusiastic approach to computer programming and content creation, and AMOS had that in spades.

These factors are, I think, enough to excuse a litany of sins. It was enough to make me join the Amos group on Facebook, where François Lionet himself is a regular poster. AMOS may never be my holy grail, but I've taken to using it when I want to quickly slap some graphics on the screen or construct a table of precomputed values. Explorative development is quite quick, and less likely to crash the machine than Assembler or even C. I still would have preferred a system that didn't reinvent graphics handling or sandbox the system, but the existing AMOS is a flawed but solid product. François Lionet could have left it at that when he left Europress. He's working on Friend OS, and that could easily be his legacy. It would certainly be enough for most people.

Not for François Lionet, though.

François Lionet, it turns out, is more of a visionary than I gave him credit for. He's also a far greater person. Why? Well, aside from unfailing courtesy and unstinting helpfulness on his own Facebook group (which he does not, I must add, treat as his own private fiefdom even though he easily could), and disregarding his work and advocacy for the Amiga-like Friend OS, his sheer enthusiasm and investment in doing right by his fans should be an inspiration for all of us.

You know guys, what prevents me from coming back to AMOS source code and change it, is that I fear it will take me a long time to setup a proper dev environment with UAE, with disc and everything, editor, graphcx editor, assembler... all the necessary tools to work...

Once I have that, I am sure that I can find how to compile again very quickly...

But, if someone does that, that is, make me such machine, and provides me with a zip file with everything installed and ready to run in one click, I can try! It will be really fun to dive again into 68000 code, I will feel 30 years younger! And if in AGA you only allow one screen, full size, and only 16 colors rainbows (the first ones) or something like that, then it is not much to do! I think I can do that in a week-end...

What do you think?

The group erupted into standing ovation. A bit of faffing about ensued regarding just how this thing would be accomplished. But in the end, this was the conclusion, from the mouth of the Lionet himself:

OK guys. You have really cool ideas, and it would be so stupid to leave them get forgotten in the depths of FB.

I will act as an administrator now on this side, sorry, but if YOU want a better version of AMOS, there is no choice.

1. I create a post with bugs

2. You post bugs there, it will come back up if it is active. But I am not making it sticky, this would be really depressing for me to see it fill up every time I connect

3. I create a 'suggestion' post, and this one will be sticky :) (possible Michael Ness?)

4. I will delete each and everyone of the posts with suggestions and bugs after this one. But carry on with conversations please!

BTW: I will not read them after... let me look... Colin Vella (sorry, not read), ' if possible, .... :P

Good to be the king! :D (I'm not, or if I am, a Viking king, not a French one with white powder acting as a lady. Don't come too close to me, I will slash your throat so that you can have fun in paradise :) )

This is what being a true gentleman looks like. So that is why I owe François Lionet an apology: instead of the whining and picking out perceived flaws in his work, I should have celebrated the soul of a man who, 30 years after a computer's demise, still makes good on his promises to its community.

One poster on FB responded to François' offer by simply saying, "you legend!"

Simple, but beyond dispute.

So thank you, François Lionet. Appreciated or underrated, a legend you remain.

05/09/2018

Converting C into Assembler on the Amiga

Introduction

This article is basically a cheat-sheet for converting C code into Amiga Assembler. The basic method is not my own. I found a page on it a year or so back, but unfortunately, I forgot to save the link. This is my rendition of the method, and any errors in thought or application should be considered mine.

Most coders, whether on the Amiga or not, are familiar with the C language. Not everyone knows how to work with Assembler, though, and the bar for learning it can be daunting.

For people already conversant with C who want to learn Assembler, there's a solution: translating it yourself, by hand, at speed. That sounds like a tall order, and complex C is indeed hard to translate. But C doesn’t have to be complex in order to be powerful. If it turns out a reduced subset of C code can help to not only dip our toes into Assembler but to write it quickly and accurately (and I aim to demonstrate that it can), then it should be an avenue worth pursuing.

Our goal, then, is to write our program in C, and then render that code into legal 68k Assembler. At first glance that would be intimidating. However, by adding just a few self-imposed constraints, we can restructure the C code into a form less concise but much easier to translate.

This is a deceptively powerful technique. After all, compiled C is just the computer doing its uninspired best to write Assembler in the first place. It just does it much faster than a human, though sometimes less efficiently (particularly on older systems, where memory and CPU speeds impose constraints on the fancy optimizations the compiler can pull). Still, manual translation remains a proven method of producing a working Assembler program in short order. The added benefit is the greater insight into one's own code offered by manual translation.

From C to A in three steps

The procedure itself is unambiguous. It takes a C listing, and the end result is a rough sketch of the final yet-to-be-optimized Assembler code. We will most likely require a few Amiga-specific additions to get something up on the screen, but the resulting binary will otherwise be fully functional.

  1. Write the routine in C. Determine its correctness.
  2. Restructure the routine in accordance with the following constraints:
    1. Calculations must be on the form of [value] = [value] [sign] [number or variable] (ex: "x = x + 2"), nothing more complex.
    2. Comparisons must be on the form of [number or value] [comparator] [number or variable] (ex: "x != 2"), nothing more complex.
    3. Remove complex branching constructs. Replace with goto or function call.
    4. Remove loop constructs. Replace with goto.
    5. The only allowed conditional is a single-line if statement followed by a goto.
    6. Remove references to variable length strings, arrays or lists. Use statically sized arrays.
    7. Replace primitive functions with calls to OS functions on the target platform when convenient (ie. typedef).
    8. Rename variable names to resemble register names, where appropriate.
    9. Test that the code’s output is unchanged (i.e. is still correct).
  3. Translate this modified code into rough Assembler form, add Amiga-specific code (libraries, interrupts, hardware access) and, again, verify correctness.

How the method is used

To illustrate the method, we could try a simple example. Project Euler is a website that offers a series of problems in roughly ascending difficulty. Most of these problems are constructed in such a way as to make a brute-force solution computationally expensive.

I generally try to avoid spoilers. However, the very first Project Euler exercise should be considered reasonably easy for any CS student to solve in a handful of minutes. The Sieve of Eratosthenes provides a fairly good, conceptually simple solution. Better still, it yields a short enough listing to be manageable for us to translate. Note that will not translate the printout part of the routine, as it would just be a distraction.

Running this program yields a sum of 233168, which in hex is 0x38ed0. This is our expected result.

Next is to prepare the C listing for translation. Applying our list gives us the following modified C listing:

This is already pretty close to what we want, but we're still not there. We need to put registers in place of variables:

Except for the Printf() function, this is practically Assembler at this point. The instructions are now ready to be translated. The result:

Assembling the program results in a minor error, easily fixed by changing the addq instruction in the third loop to add.w.

As noted, the program should result in a value of 0x38ED0 in register d0. When we assemble the corrected listing and run it, it yields exactly that: ergo, the program works. The only bug we encountered stemmed from my attempt to optimize instruction size, which was not part of the method. Had I stuck to the script, the first attempt would have assembled and given the correct response.

Two things bear mention about our C implementation. When I wrote this, I declared three iterators (scoped to each for loop). Doing so is good high-level practice, but runs contrary to the Assembler ethos of porous scope. When preparing for translation, consider deliberately compromising scoped constructs or even declaring variables as global.

Regardless, the results speak for themselves. Judging by the above demonstration, the idea is sound.