By users' requests, I built an index page of previous lessons. It’s here.
As we have done in the past lessons, we're going to mix a refresh of the latest teachings with also new stuff that should you get excited enough to keep hammering that CPU to the wall of fame for late bloom assemblers.
I took the picture below from this robotics blog that I follow. Although it’s not directly linked to a 68K assembler, it is perfect to show all the same elements you will find in a typical assembler source code file.
You have commands or more properly machine instructions. Then you have operands that can indicate a source or a destination. Finally, you have labels used to jump among blocks of code and comment markers
The CPU handles everything in binary (bits) of course and we could work in binary too; that is if we want to employ a couple of decades and lose our minds to write down the simplest program that you can think of.
So someone smart came up with the idea of using mnemonics to represent instructions that the CPU would then parse in binary sequence to execute our requests. Those binary values are then converted into on/off electrical signals that literally make real what you coded.
The number of instructions available is very small compared to modern languages that offer lots of APIs to accomplish all sorts of complex tasks. When you write in assembler you don’t get much for free besides the extra luxury of talking directly to the machine's heart and soul.
Putting all together
We have learned about instructions, sizing of information, and addressing. Let’s put it all together and see what it looks like.
the .w indicates that the size of the operation you are performing is a word (two bytes) as shown in lessons 5 and 6. Alternatively, you can use a byte (.b) or .l (longword). D0 is a register and by far my favorite because when back in the 90s I was hacking my XBOX v1 messing with D0 was a matter of life and death of the hardware. Yes, I fried a couple of them…
The rockstar Scoopex has a great series of programming in assembler for Amiga in the form of vlogs. The existence of these Amiga posts is due to his inspiring videos. I got excited one day, running by accident on his YouTube channel and since then I wanted to have my joy of learning programming the Amiga in assembler.
In one of the most tedious ways possible that you can think of when comparing to how much time you can save when using higher-level languages. :-)
Watch the video first, it’s pretty short, and then come back and we can go into details that Scoopex doesn’t cover because his target audience is a bit higher in the knowledge of where we’re right now. We will get there though. At some point in life :-)
The objective of this lesson
Write a program that waits that you to press the left mouse button to exit. No other interaction will make the program exit.
The key logic behind this program is to loop between the starting point of the program and the line where we check “are we there yet?”.
The starting point is marked with a label, which I called:
then we move the bit 6 (immediate) into the register $bfe001. A couple of things about that register. bfe doesn’t stand for bum fucking Egypt. The whole register $bfe001 is responsible for tracking the status of PORT 1 and PORT 2 for joystick and mouse.
You can understand more about all the possibilities of controlling hardware operating with/thru registers, going thru this bible. That is the Amiga Hardware Reference manual, for that particular register look at page 223.
Amiga system contains two complex interface adapters (CIA). These adapters are used to communicate with the outside world using input/output devices such as joystick. Data from those devices can be read from a set of chip registers. The
CIAAPRAregister can be used to monitor if joystick button is pressed. On every iteration of the main loop, we check if joystick (or mouse) button is pressed and, in this case, exit the program.
Following code checks both bit 6 and 7 on
CIAAPRA– register and branches to exit if either one is set. Bit 6 is set if joystick (or mouse) in port 1 has its button pressed. Bit 7 is set if joystick (or mouse) in port 2 has its button pressed.
Therefore our code now looks like the following:
Which stands for “check that bit 6 is detected as ON in the registry $bfe001. You can read about what bit test (btst) can do from this manual. In this case, it returns zero if bit 6 in the registry $bfe001 is ON. Otherwise, it returns a non-zero value.
That means, that on the next line we want to check whether or not we have received a non-zero value. And if we did, then we jump back to the start until we receive confirmation of “fire in the hole!” signal. So our code becomes:
bne stands for Branch Not Equal. Branching, umm what is that?
In any language you might have used so far you are accustomed to writing something like the pseudo-code below:
IF i_am_awesome == true THEN print(”yeah”)
What happens backstage is a comparison that records the status of the operation (called flags in the status register) which indicates the result of the comparison. If the condition is met then the execution of the next line can detect that (Wikipedia: Branch)
The branching result/state is kept in a CC table or condition codes.
We will be looking more deeply into the meaning of this very important component as we become more confident in the matter. I expect to touch it in a lesson or two.
So, to summarize what the bne instruction does is to evaluate if the previous test, branched, leaving a trace in the status register (Z Flag). If that condition is met then the code moves forward to the next instruction. Which will be RTS or return from a subroutine.
The final code as shown by Scoopex looks like this:
I bet you would have never guessed how involving a simple mouse click could have been this involving when written in assembler :-). I hope you enjoyed this lesson.