Assembly Language Question
AIman
Posts: 531
I have been trying to find free courses on learning Assembly language and so far have not come across any.
Does anyone know where I can find such courses and any backup software that may be require?
Does anyone know where I can find such courses and any backup software that may be require?
Comments
And welcome to the Forum as they say.
Now as to your question, which dialect are you thinking of? For your PC? For a target? We'd need to know which of course to help you. For all of the machines I've written for, I found I needed to read the books on them, for the PC there are plenty, for the target? It depends.
----
This message is sponsored by Wookiees for a freer world.
-- https://www.amazon.com/gp/product/1540831825
I bought a copy, but I'm told you can find it a PDF on the Internet.
http://robotics.hobbizine.com/asmlau.html
Arm Cortex are simple load-and-store (accumulator) but makes up for it by merging shift or multiple registers in same instruction,
that makes your head spin, so program them in C.
Building your own processor from TTL logic gates will give you a ground up approach. This way you'll build The ALU, registers, counters, clock, control logic and write your own instruction set.
if that's to much you can always download one of the emulators.
I'd also avoid the complex mess that is the Intel x86 instruction set unless you really need to use that for some odd reason.
The Propeller instructions set and assembly language is about one of the simplest and nicest I have ever seen. Especially as PASM is nice integrated into the Spin language and the whole thing is so easy to use from the Propeller tool. It's about the easiest way to start with assembler whilst programming an actual machine.
Surely there is some nice course material out there for learning PASM. I have never checked as I quickly picked up what I needed from the Propeller manual.
I don't know if they still do it but universities and colleges used to introduce assembler programming using the MIPS instruction set. That is nice and simple to get started with. They would often do the teaching using a simulator so no messing about with hardware was required. For example: https://chortle.ccsu.edu/AssemblyTutorial/index.html
MIPS is not such a common machine to find now a days, except your home network router probably runs a MIPS processor. But learning assembler with it is very relevant as it is a RISC machine similar to ARM, as in your phone, or the up and coming RISC V architecture and others.
It takes a mental shift away from higher level programming where operating the computer is indirect most of the time.
Take a print statement. You write it, and all sorts of code happens, and you see what you asked for rendered on what you asked for.
In assembly, there is a loop somewhere taking the print characters say it is "hello world", from where they may be in RAM, and copying them to the device memory, port or register, one at a time.
That same kind of loop may point at something entirely different, say adding numbers together, to a different outcome.
At the most basic level, computers do only three things:
Add numbers together.
Operate on them, AND, OR, NOT, XOR, etc...
Copy numbers from one address, into another address or register.
That's it!
Storing a number somewhere can mean very different things! There may be one move or store operator. What the number is, and where it goes determines what happens. You have an impact on that, due to what you want the numbers to mean, and the computer does, based on how it was made and what it may contain, how it was connected, addressed.
Store a number in a screen memory range and it may be dots, or a character, or a color.
Store it in a memory location you intend to hold a counter, and that is what it is, because you say it is and your code is written based on that being what it is, or means.
Store it in a hardware register, and a light may come on, or some action may happen.
Think of the computer not as a unit. It has many parts. They almost all matter to an assembly language programmer.
You need the schematics, or at the least, functional description of it's parts, what is connected to what, where, and how it is addressed.
https://www.nand2tetris.org/book
I would start somewhere like that book to get the right frame of mind.
I would also get a commented assembly listing from one or more of your intended targets, along with the CPU reference cards that detail the instruction set.
Here is one that makes a beep on the old Apple 2. This is one of the very first things I did way back when.
A, X, Y are CPU registers. Those are the working parts of the CPU. The memory holds data, or some memory addresses are actually wired to hardware! Every type of CPU is different. This one is very simple, also very limited.
That program sits in the memory, and the CPU fetches it a byte at a time, does the operations with its registers, or by working with memory, and that is it! Anything else that happens is all about what hardware is in the computer. Important to understand.
In this case, address $C030 is wired to the speaker. When it is accessed, the speaker clicks. Access it a lot of times and you get a buzz. Access it fast, and you get a tone. On that computer, it is just the address access that makes the click. Other computers may want a specific number too. This can be true even though they have the same CPU, and thus, same assembly language!
This program is just two nested FOR loops. Outer, and inner. The only thing in this whole program that makes sound is the store instruction. The rest is what makes the loop happen.
In a higher level language, this might be something like BEEP(frequency, duration)
Now, here is a key insight: what frequency numbers make what sounds? Secondly, what duration numbers equal what times?
To answer these, you have to go look at how the computer was made. That computer ran at 1mhz. Sloooow. That gives you one clue. The clock and that CPU getting things one byte each clock.
Look at the data sheet for the 6502 CPU, and each line of that program, an instruction, takes X number of cycles. Clocks.
With that, you can add all the cycles up, figure out how long a loop takes, and understand what duration and time mean. Clicks per second = pitch.
Those things all are an artifact of the hardware, and the code. They are not predetermined for you like they would be for something like a BEEP statement that can be written for many different computers.
I will stop there. Pick a target machine. Get some really simple code, ideally with comments. Get the hardware description, the CPU, and begin to work through the program. Comment it yourself. Then change it, etc...
Use the book, or similar, for background.
Start asking questions. It may take a lot of them. That is OK, usually does.
Sure we need arithmetic, logical operators etc. They are all variants of the same thing. They take a couple of operands from memory somewhere and produce a result somewhere else. But we need more than memory in which to store operands and results and operators like that.
To make a computer that runs programs we need to be able to do many such operations one after the other, sequentially.
But we need more, we need the machine to be able to make decisions depending on some condition or other. That is to say, select one sequence of instructions to follow next or some other.
From a program building point of view we also need a way to do iteration. Repeating some sequence of instructions many times.
There we have all of programming: Sequence, Selection, Iteration.
(Arguably "iteration" is redundant as it can be built from "selection")
Now, we can achieve all of that with a single instruction, SUBLEQ. That is "Subtract something from something then jump somewhere else in the code if the result is negative else continue with the next sequential instruction"
SUBLEQ A, B, C
Of course if you only have one instruction you don't need to say what it is so we have
A, B, C
https://esolangs.org/wiki/Subleq
On the other hand if you are programming an Intel x86 processor you only need the move instruction (MOV):
https://github.com/xoreaxeaxeax/movfuscator
Get Spin2Cpp (including FastSpin) and translate whatever you are interested in from C or Spin (BASIC is work in progress) to PASM (cog mode) with them and compare the PASM output to your high level language source.
This method may work with other systems/compilers too but it was an opportunity to mention FastSpin which currently is the coolest kid on the block... ;-D
Bonus: anyone questioning the three things has the important mindset to advance mastery of ASM.
What I started out trying to say is that we need something more than just operators like ADD, SUB, AND, OR, XOR, MOV etc. Conceptually we need more, we also need flow control, JMP, CALL, RET, and critically we need decision making BEQ, BLE, etc.
Without those we cannot express algorithms.
Add does all math. Bit ops handles bits and can help make conditionals easier. Moving numbers handles, call, jump, and friends.
I find thinking right here somewhere super useful for that mindset. The times I have taught ASM lead rapidly to your observations.
What is JMP? Put a number in the program counter and find out!
Going lower, we only need NAND. Going a bit higher, may not convey what assembly, and or machine language is as it begins to look higher level.
OK. If we are prepared to accept the program counter as just another number that we can operate on (Not true in many machines) we don't need jump and branch instructions. Just move stuff into it or add to it etc.
Yes, with only NAND or NOR we can make any other gate, and registers, memory, adders, multipliers etc, etc.
Hmmm... Foregt the SUBLEQ we have to build a NAND only instruction set and assembly language.
But, at risk of being annoying, riddle me this:
Given nothing but a huge supply of perfect NAND or NOR gates is it possible to build a computer? When I say perfect I imply zero propagation delay.
Seems to me that one needs a clock. That is going to require a capacitor or other time delay in the circuit somewhere.
That is not one of our NAND or NOR building blocks.
The clock is what gives us the "sequential" part of computing. It's what ensures steps get done in the right order.
I'm sure you are familiar with Conway' Game of Life.
In the Game of life there are no logic gates. There are cells. Their inputs are the state (live or dead) of their neighbors. Their output is their own state (live or dead).
Arguably cells can all be implemented without NAND or NOR. An analogue comparator would do.
But, I'm told the game of life is Turing complete. It can do anything a computer can do. Which includes computing NAND or NOR.
Seems NAND and NOR are not the fundamental building blocks after all.
It does have a clock mind...
I'm pretty sure there's no single "fundamental building block", there are a number of alternate approaches that can be equally "fundamental" in that sense that any one of them can be built from the others. That's kind of what Church's thesis is. (For example, the lambda calculus, which has no comparators, NAND, or NOR at all, is Turing complete.)
Getting back from the realms of abstract computing to the original thread...
@yeti's suggestion to look at assembly output from a compiler is a good one. Not only fastspin, but also PropBasic and PropGCC can produce assembly language, as can gcc or clang for any platform. Try writing simple functions and run them through the compiler, and see what kinds of output it produces. This won't replace an assembly language tutorial, but it may supplement it and help you to see how to do specific things. As a for-instance, if you want to know how to add numbers you can create a function like: or in C then compile it with "spin2cpp --asm foo.spin" or "propeller-elf-gcc -S -Os foo.c" to get something like:
spin2cpp output:
PropGCC output:
These are a little different (different compilers enforce different ways of calling functions and storing variables in memory) but the basic iinformation is the same -- to add two integers x and y, use the "add" instruction.
Hmm... I have no idea about Church's thesis or lambda calculus. I have never seen even a description of them that is written in any kind of language I understand.
If there are no comparators, NAND, or NOR at all then how are we ever going to build an actual computing machine out of it? Don't we need a fundamental building block somewhere? A simple conceptual thing we can make in hardware.
I have often looked at the assembler generator by compilers to see what is going on. Especially when I want to link my own assembler functions with a high level language or vice versa and want to be sure how parameter passing and such goes on.
I'm not sure it's the best way to start learning assembler from scratch though.
Agreed, it's not enough on its own. Reading manuals is good; so is reading good examples (like from the obex).
Which Microcontroller or processor ?
A good way to learn both the Assembler Code and what the assembler actually does, as it runs, is on a Chip Simulator (or good debugger)
Google finds a few useful looking simulators, & do not be averse to trying more than one... or more than one core..
8 Bit Simulators are well tested and well supported with examples
https://sourceforge.net/projects/mcu8051ide/
https://www.edsim51.com/
http://www.oshonsoft.com/avr.html#screenshot
http://starlo.org/blake/boardmicro/
Or, if you want to learn, and also run some real code in a HW project, look at the low cost eval boards, with USB-Debug-Bridges included.
SiLabs toolsticks (eg TOOLSTICK850-B-SK) and Atmel Xplained minis for example.
Those Debug IDEs tend to be rather larger, but they are actively supported.
I think the same, but: I changed jobs recently and had to learn 8051 assembly. Yes, we program in C but I may be custom to the good code produced by gcc (loosely use of "good", if you want) and sometimes choke at the code produced by certain commercial compiler. The compiler doesn't let you do much, not that much is possible but I have a couple wishes for the writers. I may not have wanted to learn yet another assembly dialect but I really enjoy programming again, even... that . We develop and fab integrated circuits, what else can I want ?
8-bit: Z8
16-bit: MSP430
32-bit: Propeller!
Avoid the AVR. The instruction set is optimized for C, not for native assembly programming.
-Phil
-Phil
In terms of staying away from non-orthogonality I would suggest staying away from the 8080 and 8086 machines.
Is it so that we don't have a super simple beginners tutorial for Propeller assembler that we can link people to?
-Phil
"Program execution
Atmel's AVRs have a two-stage, single-level pipeline design. This means the next machine instruction is fetched as the current one is executing.
Most instructions take just one or two clock cycles, making AVRs relatively fast among eight-bit microcontrollers.
The AVR processors were designed with the efficient execution of compiled C code in mind and have several built-in pointers for the task.
Instruction set
Main article: Atmel AVR instruction set
The AVR instruction set is more orthogonal than those of most eight-bit microcontrollers, in particular the 8051 clones and PIC microcontrollers with which AVR competes today. However, it is not completely regular:
Pointer registers X, Y, and Z have addressing capabilities that are different from each other.
Register locations R0 to R15 have more limited addressing capabilities than register locations R16 to R31.
I/O ports 0 to 31 can be bit addressed, unlike I/O ports 32 to 63.
CLR (clear all bits to zero) affects flags, while SER (set all bits to one) does not, even though they are complementary instructions. (CLR is pseudo-op for EOR R, R; while SER is short for LDI R,$FF. Arithmetic operations such as EOR modify flags, while moves/loads/stores/branches such as LDI do not.)
Accessing read-only data stored in the program memory (flash) requires special LPM instructions; the flash bus is otherwise reserved for instruction memory.
Additionally, some chip-specific differences affect code generation.
Code pointers (including return addresses on the stack) are two bytes long on chips with up to 128 KB of flash memory, but three bytes long on larger chips;
not all chips have hardware multipliers;
chips with over 8 KB of flash have branch and call instructions with longer ranges; and so forth.
The mostly regular instruction set makes programming it using C (or even Ada) compilers fairly straightforward. GCC has included AVR support for quite some time, and that support is widely used.
In fact, Atmel solicited input from major developers of compilers for small microcontrollers, to determine the instruction set features that were most useful in a compiler for high-level languages."
So all in all more orthogonal that something like Intel 8080/8086. Not bad at all.
If you want orthogonal you have to go RISC V or Propeller!
This is really good question. I have seen a number of times where no documentation on assembly was available at all. Just a C compiler.
I can recommend books, depending on the processor.
I have this fantasy that now that Microchip bought Atmel, they slowly phase out all the PIC crp and start ramping up AVR and 8051. Of course the OPPOSITE could happen too. And that would really really suck.
In the sub 35c MCU space, Microchip have some Tiny's but they have less code:ram than the STM8 and EFM8 alternatives from ST & Silabs.