How did you learn assembly [solved]

Thread Starter

Pushkar1

Joined Apr 5, 2021
416
I'm curious to know how you started learning assembly language.

Have you started writing assembly code for microcontrollers directly?

Did you learn by writing assembly code for PC?

What is the best way to learn assembly language?
 

Sensacell

Joined Jun 19, 2012
3,432
Start with a simple microcontroller- like a PIC18 series 8 bit part.

Read some books or websites about assembly and binary, etc.

Try to code some simple stuff like blinking LEDs etc-

Challenge yourself with more complex projects

Enjoy it!
 

IgorZg

Joined Jul 10, 2021
5
I started with Z80 and 6502. Did some 8086 assembler under DOS, like keyboard,drivers and similar stuff. Then i programmed 8051 MCUs. Then Atmel.
But today, if you don't write own rtos kernel or stuff like that, there is no need to use assembler. C is good enough for everything. Plus, if you write something in assembler, it will be very difficult to move code to another platform. So, if you really not forced to use assembler, avoid it.
 

BobTPH

Joined Jun 5, 2013
8,804
My second computer science course, after Fortran, was assembly language for the Univac 1108, c 1970. 36-bit word with 6 6-bit bytes. No upper case letters in the character set!

Edir: it was no lower case, not upper.

Bob
 
Last edited:

boostbuck

Joined Oct 5, 2017
501
The best way is to learn to code assembler is within a development environment that offers simulation, which means you can step and debug your code and observe the processor register and memory behaviour as you play with code structures and blocks.

I started assembler coding with a primitive 6809 simulator running on a DEC machine (a vax?) but my familiarity now is with Microchip MPLAB. I should imagine that most controller manufacturers offer simulation-capable IDEs.
 

Ian0

Joined Aug 7, 2020
9,667
I started by coding it in hex on a PET. Then I got a BBC Micro, which had a built-in assembler, and I was so impressed just how much quicker it was than BASIC.
MPLAB with breakpoints was the next step forward.

If you use a RISC a processor such as an ARM, ATmega or PIC, the instruction set is so small (50 instructions or so) that you can easily memorise them all. The manual will tell you EXACTLY what they all do (not many C libraries can make that claim).

If you are working with ARMs, I’d recommend Joseph Yiu’s books.

To paraphrase @IgorZg , if you don’t want to use Ethernet stacks, or write a web servers etc. , there’s no need to learn C. There are ARM processors in every possible shape or size, ARM code can be used everywhere. But the idea of either Assembler or C being portable is a fallacy, because every processor’s peripherals are different.
 

click_here

Joined Sep 22, 2020
548
Here is a good starting guide

Note that the instructions sets are different for PICs to AVR to Motorola. (So that can catch you out). This means that a program on one will not work on another.

You'll have to choose one and go with it.

[edit] It might be worth looking at a local job advertisement website to see what direction you want to go in [/edit]

I personally don't do any assembly programming these days (once I started programming in C I never looked back), but there are plenty of people here who do. It's just another way to write a program :)
 
Last edited:

MrChips

Joined Oct 2, 2009
30,703
My first contact with assembly language programming was for a CDC 6400 mainframe computer.
My second exposure to assembly language programming was for DEC PDP-8/S mini-computer.
Text code had to be typed with zero errors via a Teletype machine and punched on paper tape.

1631801168261.png

1631801209418.png
 

LesJones

Joined Jan 8, 2017
4,174
I started on a DEC PDP 9 computer that was part of the system at a site I hepled to maintain. It was a job where there was quite a lot of spare time between faults so I started reading the manuals. The instruction set was quite easy to understand. It was a slow job entering the program using the data and address switches. The first microcontroler I bought was an National INS8060. I later built a copy of the Nascom 2 based on the Z80. For that I actualy bought a book on programming the Z80. I used that for many years. When I started working for DEC it was initialy on the PDP11 range of computers and for fault finding we would sometimes write small programs to do basic test on peripherals such as printers VDUs paper tape readers and punches etc. I later started using PIC chips and learned to program them from magazine articles seeing how other people programed them. I like the simplicity of assembler. all you need is the datasheet on the microcontroller, the datasheet devices you are communicating with and the specification for the the protocol (Such as I2C) Programmining in C requires learning complex syntax and there is a lot to learn about thing like how header files work.

Les.
 

MaxHeadRoom

Joined Jul 18, 2013
28,617
On the WEB there is the free tutoriols by Gooligum Australia, plus Nigel Goodwins Tutorials, also there is the book out there in PDF, by Han-Way Huang "PIC Microcontroller-an introduction to Software & Hardware Interfacing".
 
Last edited:

nsaspook

Joined Aug 27, 2009
13,079
I'm still amazed that people think that a HLL like C is complex when compared to just about any assembler. I learned and used assembler because it was necessary to get the job done. If you understand the fundamentals of computer architectures getting up to speed on any random instruction set is no big deal. What is a big deal is understanding the logic of a random program 30+ years after you wrote it.

Here is some old Modula-2 MX2 code for the 68000 cpu (on a Atart-ST) with assembler specific code to handle task switching details. Without even knowing the language you can follow the HLL program logic.
What the asm code does is totally Greek to a person without a detailed understanding of 68000 codes and internals.
Code:
IMPLEMENTATION MODULE NEWSYS; (*$S-,$T- *)
FROM           SYSTEM   IMPORT  ADDRESS,CODE,SETREG,REGISTER,ADR;

FROM    GEMDOS  IMPORT  Super,Alloc,Free; 

TYPE           trappointer      =       POINTER TO PROC;
               processpointer   =       POINTER TO ADDRESS;
TYPE           iotype   =       RECORD
                                        p1      : processpointer;
                                        p2      : processpointer;
                                        device  : ADDRESS;
                                END;
VAR            pc,ssv                           : ADDRESS;
               io1,io2                          : processpointer;
               sr,function                      : CARDINAL;
               iotranspointer                   : iotype;
               trap                             : trappointer;
               pr1,pr2,wsp                      : ADDRESS;
               n                                : LONGCARD;
               init                             : BOOLEAN;

PROCEDURE  NEWPROCESS(processProc       :  PROC;
                      workspace         :  ADDRESS;
                      worksize          :  LONGCARD;
                      VAR process       :  ADDRESS);
BEGIN
        IF NOT init THEN
           INITPROCESSES;
        END;
        workspace:=workspace+ADDRESS(worksize);
        SETREG(6,ADDRESS(processProc));
        SETREG(8,workspace);
        CODE(2106H);    (* move.l d6,-(a0) PC *)
        CODE(313cH,0300H);      (* move.w $0300,-(a0)   CCR  *)
        CODE(48e0H,0fffeH);     (* movem.l d0-d7/a0-a6,-(a0) *)
        process:=REGISTER(8);
END        NEWPROCESS;

PROCEDURE  TRANSFER(VAR p1,p2: ADDRESS);
BEGIN      (* pass p1 and p2 as the location of these variables *)
        IF NOT init THEN
           INITPROCESSES;
        END;
           SETREG(0,ADR(p2));
           CODE(2f00H); (* move.l d0,-(sp) *)
           SETREG(0,ADR(p1));
           CODE(2f00H); (* move.l d0,-(sp) *)
           CODE(3f3cH,1); (* move.w #1,-(sp) *)
           CODE(4e49H); (* trap #9 *)
           CODE(0dffcH,0,10); (* add.l #10,sp *)
END        TRANSFER;

PROCEDURE  IOTRANSFER(VAR p1,p2: ADDRESS; device: ADDRESS);
BEGIN      (* pass p1 and p2 as the location of these variables *)
        IF NOT init THEN
           INITPROCESSES;
        END;
           SETREG(0,device);
           CODE(2f00H); (* move.l d0,-(sp) *)
           SETREG(0,ADR(p2));
           CODE(2f00H); (* move.l d0,-(sp) *)
           SETREG(0,ADR(p1));
           CODE(2f00H); (* move.l d0,-(sp) *)
           CODE(3f3cH,2); (* move.w #2,-(sp) *)
           CODE(4e49H); (* trap #9 *)
           CODE(0dffcH,0,14); (* add.l #14,sp *)
END        IOTRANSFER;
 

Ian0

Joined Aug 7, 2020
9,667
I like the simplicity of assembler. all you need is the datasheet on the microcontroller, the datasheet devices you are communicating with and the specification for the the protocol (Such as I2C) Programmining in C requires learning complex syntax and there is a lot to learn about thing like how header files work.
I agree entirely. On 8-bit systems, the need to have extra code to deal with numbers >255 was irksome, but writing assembler on ARMs removes that problem!
I would no more use code downloaded from the internet than I would buy components from dubious E-bay suppliers.
The accuracy of microcontroller datasheets is orders of magnitude better than the quality of documentation for code C libraries. Have you ever noticed that the majority of posts on software fora are about peripheral “drivers” that don’t work. That’s never a problem working in assembler from the datasheet.
 

dl324

Joined Mar 30, 2015
16,839
Did you learn by writing assembly code for PC?
The first assembly language I learned was for the 8080 in an Altair 8800. The PC wouldn't be invented for a few years or so.
What is the best way to learn assembly language?
Pick some programs to write and keep at it until you can do it. I learned in college and our first programs were to shift and rotate LEDs to become with shift left, shift right, and circular shifts.

In the early 80's I took a one week class at DEC for VAX assembly language programming. I didn't know that knowing the language was a prerequisite and it took me half the class to learn enough to start writing programs. Once I learned the commands, the programs were easy after we learned about the machine.
 

MaxHeadRoom

Joined Jul 18, 2013
28,617
One useful thing with the first two examples I listed in #10, is you make can easily construct the physical circuit, which aids & enhances the code learning curve that goes with it.
 

panic mode

Joined Oct 10, 2011
2,715
oh well.... this takes me back... my first exposure was in the 80s on a little 8-bit computer with only 1kb or RAM. that was the only way to accomplish anything due limited resources. so quickly built 16kb RAM expansion and shortly after that moved to a PC where the real fun begun.... that was the time of assembly demo scene with tons of great code (with of without source). see, and even things that were not available in source code would disassemble to something very nice, lots of hand optimized code and tricks. at that time i used Pascal for any high level things. that was quick way to prototype but Pascal compilers at that time were only 16-bit. still remember using inline assembler (ASM/END) and prefixing 16-bit Assembler mnemonics with a character to turn them into 32-bit instructions so it can do double work in same number of clocks. still love going back through old code.
one day there was book PC Intern by Michael Tischer. i still have hard copies of V2.0 and 4.0. version of it can still be bought on Amazon.
for me working with microcontrollers came later.
 
Last edited:

nsaspook

Joined Aug 27, 2009
13,079
I’ve no idea what it does, and I‘m pretty much fluent in 68000 assembler.
Simple machine dependent coroutines functions that use trap #9 for a task switcher.
https://www.modula2.org/reference/isomodules/isomodule.php?m=COROUTIN.DEF
https://eprints.usq.edu.au/3525/

Code:
(*$P- *)
PROCEDURE       PTRAP; 
BEGIN
        CODE(043374B,2700H); (* disable ints *)
        CODE(48e7H,0fffeH);   (* save regs movem  *)
        CODE(306fH,60); (* move.w 60(a7),a0 get sr *)
        sr:=CARDINAL(REGISTER(8));
        IF sr>3fffH THEN         (* called from supermode, not valid *)
           CODE(4cdfH,7fffH);    (* restore regs movem *)
           CODE(4e73H);          (* rte go back to where we came from *)
        END;

        CODE(4e69H);        (* move.l usp,a1 *)
        CODE(3069H,0);      (* move.w 0(a1),a0 *)
        function:=CARDINAL(REGISTER(8));
        CODE(4e69H);        (* move.l usp,a1 *)
        CODE(2069H,2);      (* move.l 2(a1),a0 *)
        iotranspointer.p1:=REGISTER(8);
        CODE(4e69H);        (* move.l usp,a1 *)
        CODE(2069H,6);      (* move.l 6(a1),a0 *)
        iotranspointer.p2:=REGISTER(8);
        CODE(4e69H);        (* move.l usp,a1 *)
        CODE(2069H,10);     (* move.l 10(a1),a0 *)
        iotranspointer.device:=REGISTER(8);

        CASE function OF
             1  : CODE(4e68H); (* move.l usp,a0 TRANSFER *) (* SAVE *)
                  CODE(0dffcH,0,42H); (* add.l #66,sp *)
                  CODE(2127H); (* move.l -(sp),-(a0) D0 *)
                  CODE(2127H); (* move.l -(sp),-(a0) D1 *)
                  CODE(2127H); (* move.l -(sp),-(a0) D2 *)
                  CODE(2127H); (* move.l -(sp),-(a0) D3 *)
                  CODE(2127H); (* move.l -(sp),-(a0) D4 *)
                  CODE(2127H); (* move.l -(sp),-(a0) D5 *)
                  CODE(2127H); (* move.l -(sp),-(a0) D6 *)
                  CODE(2127H); (* move.l -(sp),-(a0) D7 *)
                  CODE(2127H); (* move.l -(sp),-(a0) A0 *)
                  CODE(2127H); (* move.l -(sp),-(a0) A1 *)
                  CODE(2127H); (* move.l -(sp),-(a0) A2 *)
                  CODE(2127H); (* move.l -(sp),-(a0) A3 *)
                  CODE(2127H); (* move.l -(sp),-(a0) A4 *)
                  CODE(2127H); (* move.l -(sp),-(a0) A5 *)
                  CODE(2127H); (* move.l -(sp),-(a0) A6 *)
                  CODE(3127H); (* move.w -(sp),-(a0) SR *)
                  CODE(2127H); (* move.l -(sp),-(a0) PC *)
                  iotranspointer.p1^:=REGISTER(8); (* set p1 to process *)
                  
                  SETREG(8,iotranspointer.p2^); (* load p2 to a0 RESTORE *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ D0 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ D1 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ D2 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ D3 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ D4 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ D5 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ D6 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ D7 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ A0 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ A1 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ A2 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ A3 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ A4 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ A5 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ A6 *)
                  CODE(3ed8H); (* move.w (a0)+,(sp)+ SR *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ PC *)
                  CODE(9ffcH,0,42H); (* sub.l #66,sp *)
                  CODE(4e60H); (* move.l a0,usp *)
                  CODE(4cdfH,7fffH);    (* restore regs movem *)
                  CODE(4e73H); |        (* rte *)

             2  : CODE(4e68H); (* move.l usp,a0 IOTRANSFER *) (* SAVE *)
                  CODE(0dffcH,0,42H); (* add.l #66,sp *)
                  CODE(2127H); (* move.l -(sp),-(a0) D0 *)
                  CODE(2127H); (* move.l -(sp),-(a0) D1 *)
                  CODE(2127H); (* move.l -(sp),-(a0) D2 *)
                  CODE(2127H); (* move.l -(sp),-(a0) D3 *)
                  CODE(2127H); (* move.l -(sp),-(a0) D4 *)
                  CODE(2127H); (* move.l -(sp),-(a0) D5 *)
                  CODE(2127H); (* move.l -(sp),-(a0) D6 *)
                  CODE(2127H); (* move.l -(sp),-(a0) D7 *)
                  CODE(2127H); (* move.l -(sp),-(a0) A0 *)
                  CODE(2127H); (* move.l -(sp),-(a0) A1 *)
                  CODE(2127H); (* move.l -(sp),-(a0) A2 *)
                  CODE(2127H); (* move.l -(sp),-(a0) A3 *)
                  CODE(2127H); (* move.l -(sp),-(a0) A4 *)
                  CODE(2127H); (* move.l -(sp),-(a0) A5 *)
                  CODE(2127H); (* move.l -(sp),-(a0) A6 *)
                  CODE(3127H); (* move.w -(sp),-(a0) SR *)
                  CODE(2127H); (* move.l -(sp),-(a0) PC *)
                  iotranspointer.p1^:=REGISTER(8); (* set p1 to process *)
                  io1:=iotranspointer.p1;
                  
                  io2:=iotranspointer.p2;
                  SETREG(8,iotranspointer.p2^); (* load p2 to a0 RESTORE *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ D0 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ D1 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ D2 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ D3 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ D4 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ D5 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ D6 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ D7 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ A0 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ A1 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ A2 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ A3 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ A4 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ A5 *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ A6 *)
                  CODE(3ed8H); (* move.w (a0)+,(sp)+ SR *)
                  CODE(2ed8H); (* move.l (a0)+,(sp)+ PC *)
                  CODE(9ffcH,0,42H); (* sub.l #66,sp *)
                  CODE(4e60H); (* move.l a0,usp *)
                  trap:=trappointer(iotranspointer.device); (* TRAP ADR *)
                  trap^:=ITRAP; (* set trap to IOTRANSFER int code *)
                  CODE(4cdfH,7fffH);    (* restore regs movem *)
                  CODE(4e73H); |        (* rte *)
        END;

        CODE(4cdfH,7fffH);    (* restore regs movem *)
        CODE(4e73H);          (* rte *)
END             PTRAP;
(*$P+ *)

(*$P- *)
PROCEDURE       ITRAP;
BEGIN
        CODE(043374B,2700H); (* disable ints *)
        CODE(48e7H,0fffeH);   (* save regs movem  *)
        CODE(4e68H); (* move.l usp,a0 TRANSFER *) (* SAVE *)
        CODE(0dffcH,0,42H); (* add.l #66,sp *)
        CODE(2127H); (* move.l -(sp),-(a0) D0 *)
        CODE(2127H); (* move.l -(sp),-(a0) D1 *)
        CODE(2127H); (* move.l -(sp),-(a0) D2 *)
        CODE(2127H); (* move.l -(sp),-(a0) D3 *)
        CODE(2127H); (* move.l -(sp),-(a0) D4 *)
        CODE(2127H); (* move.l -(sp),-(a0) D5 *)
        CODE(2127H); (* move.l -(sp),-(a0) D6 *)
        CODE(2127H); (* move.l -(sp),-(a0) D7 *)
        CODE(2127H); (* move.l -(sp),-(a0) A0 *)
        CODE(2127H); (* move.l -(sp),-(a0) A1 *)
        CODE(2127H); (* move.l -(sp),-(a0) A2 *)
        CODE(2127H); (* move.l -(sp),-(a0) A3 *)
        CODE(2127H); (* move.l -(sp),-(a0) A4 *)
        CODE(2127H); (* move.l -(sp),-(a0) A5 *)
        CODE(2127H); (* move.l -(sp),-(a0) A6 *)
        CODE(3127H); (* move.w -(sp),-(a0) SR *)
        CODE(2127H); (* move.l -(sp),-(a0) PC *)
        io2^:=REGISTER(8); (* set interrupted process to process *)
                  
        SETREG(8,io1^); (* load iotransfer process to a0 RESTORE *)
        CODE(2ed8H); (* move.l (a0)+,(sp)+ D0 *)
        CODE(2ed8H); (* move.l (a0)+,(sp)+ D1 *)
        CODE(2ed8H); (* move.l (a0)+,(sp)+ D2 *)
        CODE(2ed8H); (* move.l (a0)+,(sp)+ D3 *)
        CODE(2ed8H); (* move.l (a0)+,(sp)+ D4 *)
        CODE(2ed8H); (* move.l (a0)+,(sp)+ D5 *)
        CODE(2ed8H); (* move.l (a0)+,(sp)+ D6 *)
        CODE(2ed8H); (* move.l (a0)+,(sp)+ D7 *)
        CODE(2ed8H); (* move.l (a0)+,(sp)+ A0 *)
        CODE(2ed8H); (* move.l (a0)+,(sp)+ A1 *)
        CODE(2ed8H); (* move.l (a0)+,(sp)+ A2 *)
        CODE(2ed8H); (* move.l (a0)+,(sp)+ A3 *)
        CODE(2ed8H); (* move.l (a0)+,(sp)+ A4 *)
        CODE(2ed8H); (* move.l (a0)+,(sp)+ A5 *)
        CODE(2ed8H); (* move.l (a0)+,(sp)+ A6 *)
        CODE(3ed8H); (* move.w (a0)+,(sp)+ SR *)
        CODE(2ed8H); (* move.l (a0)+,(sp)+ PC *)
        CODE(9ffcH,0,42H); (* sub.l #66,sp *)
        CODE(4e60H); (* move.l a0,usp *)
        CODE(4cdfH,7fffH);    (* restore regs movem *)
        CODE(4e73H);         (* rte *)
END             ITRAP;
(*$P+ *)

PROCEDURE  INITPROCESSES;
BEGIN
        ssv:=0;
        Super(ssv);
        trap:=trappointer(TRAP);
        trap^:=PTRAP;
        Super(ssv);
        init:=TRUE;
END        INITPROCESSES;
 

MrChips

Joined Oct 2, 2009
30,703
My next venture into assembly language programming was for an RCA 1802 microcontroller. There was no assembler available at the time. I had to write out the ASM program and then translate the code to binary by hand. Then the code was programmed into UV-EPROM. Make one mistake and you had to repeat the whole process. Erasing a UV-EPROM took 30 minutes.

We ought to appreciate how much easier it is to program today.
 

DickCappels

Joined Aug 21, 2008
10,153
(Some text removed for brevity) Make one mistake and you had to repeat the whole process. Erasing a UV-EPROM took 30 minutes.

We ought to appreciate how much easier it is to program today.
That's why some of use kept dozens of EPROMs at the standby! I sure am grateful for integrated flash memory. I don't think I would have gone back to microcontrollers if integrated flash had not come about.
 
Top