Assembly Language Assignment Help

An assembly language is a low-level programming language used for microprocessors, microcontrollers, and additional programmable devices. Assembly language is used where speed is more important or there are operations which can’t be performed on high-level programming languages. It also gives the insight to develop efficient code in high-level language. It is the most powerful computer programming language available

Assembly languages helps users to know the operations of their PC better which in turn, helps them in consistent development of software. With the help of an assembler you have full control on your PC. The programs created in assembly languages are smaller and have much more capacity than ones developed with the use of other languages. In assembly language, symbolic memory addresses are used for used to remember where data is stored instead of remembering the exact memory location. To translate the assembly language statements into machine language code, an assembler is used.

We at Assignmentpedia provide best-in-class Assignment Help and Homework Help in Assembly Languages. You can interact with the expert first, before making the payment. This unique attribute helps the students specifically in Assembly Languages because of the complexity and criticality involved.

NOTE-The following Assembly Language Program has been prepared by our Assembly Language Programmers , just for demonstrating you the quality and comprehensiveness of our Assembly Language Homework Solutions and they do not constitute to any of our previous Assembly Language Assignment/Homework solution deliveries.

1. Sample Assembly Language Assignment

Write a program to measure the period of a periodic signal
connected to input channel 3 by measuring the count difference
Between two falling edges. Set PR2:PR0 = 011. Use polling method.


; **************************************************
; Program Definitions
; **************************************************
REG_BASEEQU $0000; Base address for calculating offsets to other registers
TMSK1EQU $8C; Offset for TMSK1 register
TMSK2EQU $8D; Offset for TMSK2 register
TCTL4EQU $8B; Offset for TCTL4 register
TIOSEQU $80; Offset for TIOS register
TC3HEQU $96; Offset for TC3H register
TSCREQU $86; Offset for TSCR register
TFLG1EQU $8E; Offset for TFLG1 register
TCNTEQU $96; Offset for TCNT register
TMSK2_INEQU $03; Set the pre-scale bits
TCTL4_INEQU $C0; Configure falling edges
TIOS_INEQU $00; Select channel 3 for input compare
TSCR_INEQU $80; Enable timer
CLR_CH3EQU $08; Mask to clear channel 3 flag
; Data section
ORG $6000
edge1
Period
FDB
FDB
; Code section
ORG $4000
$0000
$0000
; Reserve a word (16-bits) for edge measurement
; Reserve a word (16-bits) for period measurement

LDS #$8000; Initialize the stack pointer
JSRTIMERINIT; Initialize the timer
JSRMEASURE; Measure the period
DONE BRA DONE; infinitely loop to halt program
; **************************************************
; Function used to enable timer subsystem
; **************************************************
TIMERINIT
CLR TMSK1; disable interrupts
LDX #REG_BASE; Load X with base address of registers
LDAA #TMSK2_IN
STAA TMSSK2, X
LDAA #TCTL4_IN
STAA TCTL4, X
LDAA #TIOS_IN
STAA TIOS_IN, X
LDAA #TSCR_IN
STAA TSCR_IN, X
RTS
; return
; Set pre-scale
; Configure for falling edges
; Select channel 3
; Enable timer
; **************************************************
; Function used to measure signal period
; via polling method
; **************************************************
MEASURE
LDAA #CLR_CH3; Clear channel 3 flag to prepare measurements
STAA TFLG1,X
; Grab measurement of first edge
WAIT1
BRCLR TFLG1, X, $08, WTFLG; Wait for an edge
LDD TCNT, X; Load in counter value
STD edge1; Save the measurement
LDAA #CLR_CH3; Clear channel 3 flag again
STAA TFLG1, X
; Grab measurement of second edge
WAIT2
BRCLR TFLG1, X, $08, WTFLG
LDD TCNT, X
SUBD edge1
STD period
RTS
; return
; Wait for an edge
; Load in counter value
; Calculate the difference between edges
; Store the period result

Q5. Generate a 1500Hz square wave with a 40% duty cycle
(ON/PERIOD) on output compare channel 2 (OC2). MCLK = 8MHz.
Set the pre-scaler to divide by 4. Use interrupt.

A5.If the MCLK runs at 8 MHz and the pre-scaler is set to 4, then the
Counter will adjust at a rate of (8 MHz)/4 = 2 MHz, or with a period of 500 ns.
A 1500 Hz signal has a period of 666.67 microseconds, and a 40% duty cycle
Means that it will be high for 0.4*666.67 microseconds or 266.67 microseconds,
And low for 400 microseconds. This translates to counter value of:
High counter:
= 266.67 microseconds * (1 tick / 0.5 microseconds)
= 534 ticks ? $0216
Low counter:
= 400 microseconds * (1 tick / 0.5 microseconds)
= 800 ticks ? $0320
The program on p. 275 can be modified to perform the 40% duty cycle switch
By changing the following:



TMSK2_IN needs to be changed to $04
o This sets the correct pre-scale for our problem.
o Pre-scale of 4 (22 = 4).
The first instance of #$03E8 (in TIMERINIT) needs to be changed to the
Counter value for our high counter, or #$0216.
The instance of #$03E8 (in SQWAVE) needs to be changed to alternate
Between the high and low-counter values using a conditional branch to
Implement an IF statement.
o This can be easily done by reserving a word (double-byte) in
Memory to contain the count value. This value will “flip-flop”
Between the high and low counter value during every iteration of
the loop

;************************
; New data section
;************************
ORG $6000
COUNT_INCFDB $0000
.
.
.
<Within TIMERINIT>
; Location to hold counter increment
; Initialize COUNT_INC to be low counter value
LDD $0320
STD COUNT_INC
<Replace SQWAVE with the following>
SQWAVE
BRCLRTFLG1,$04,SQWAVE
LDDTC2H
LDX COUNT_INC
CPX #$0216
BEQ ADD_LOW
ADDD #$0216
LDX #$0216
STX COUNT_INC
; Poll for counter flag
; Load in counter value
; Load in current COUNT_INC
; Compare to high-count
; If high ? add low
; Otherwise, add high
; Update COUNT_INC
BRA ENDIF
ADD_LOW
ADDD #$0320; Add low
LDX #$0320; Update COUNT_INC
STX COUNT_INC
ENDIF
STD TC2H; Setup next transition time
JSR CLEARFLAG; generate repetitive signal
RTS; return

 

 

      .text
      j main
        .data                           # Constants and variables
                                        # declarations.
sum:    .float 0.0                        # the answer                                       
point3: .float 0.3                      # for nArray[i] = i * 0.3
                                        # Floats are 4 bytes each
nArray:     .space      200                     # float nArray[50] of 4 bytes each
endlineStr: .asciiz "\n"
nStr:   .asciiz "n = "
descStr:  .asciiz "If an odd number is entered, add numbes will be added, otherwise, even numbers will be added.\n"
enterStr: .asciiz "Please enter a number between 1 and 49. :"
sumStr:   .asciiz "sum = "

        .text                           # Main (must be global).
        .globl main
       
# for (int i = 0; i < 50; i++) nArray[i] = i * 0.3
# Registers:
# t0 = i
# t1 = nArray
# t2 = i * 0.3
setArray:
        li $t0,0                        # i = 0
        la $t1,nArray                   # t1 = nArray
        l.s $f1,point3
setArrayLoop:
        mtc1 $t0, $f0                   # move register to float
        cvt.s.w $f0, $f0                # convert from int to float
        mul.s $f12,$f0,$f1              # $f12 = $f0 * f1 (i * 0.3)
        mfc1 $t2,$f12                   # $t2 = $f12
        sw $t2,0($t1)                   # *nArray = i * 0.3
        addi $t1,$t1,4                  # nArray++
#        li $v0, 2                       # Syscall print_float
#        syscall
#        li $v0, 4                       # Syscall print_str
#        la $a0, endlineStr              # String to print
#        syscall
        add $t0,$t0,1                   # i++
        bne $t0,50,setArrayLoop         # end for loop
        jr $ra                          # return

2. Sample Assembly Language Assignment.

#Add all the even values
#Registers:
#In:
#       $v0 = n
#Out:
#       $f12 = float return value
addEven:
        addi $sp, $sp, -16              # allocate stack space for 4 words:
                                        # $ra, $v0, $f12
        sw $ra, 12($sp)                 # save $ra
        sw $v0, 0($sp)                  # use 0($sp) to save n ($v0) when needed
        mfc1 $t0,$f12                   # $t0 = $f12     
        sw $t0,4($sp)                   # use 4($sp) to save return ($f12) when needed
                                        # use 8($sp) to save ($) when needed

        move $v1,$v0                    # $v1 = n
        li $v0, 4                       # Syscall print_str
        la $a0, nStr                    # String to print
        syscall
        li $v0, 1                       # Syscall print_int
        move $a0,$v1                    # $a0 = n
        syscall
        li $v0, 4                       # Syscall print_str
        la $a0, endlineStr              # String to print
        syscall
        
        bne $v1,$zero,addEvenRecurse    # if (n == 0)
        l.s $f12,nArray
        lw $ra, 12($sp)                 # reload return address
        addi $sp, $sp, 16               # restore stack space
        jr $ra                          # return nArray[0]
       
addEvenRecurse:
        sub $v0,$v1,2                   # n = n - 2
       
        jal addEven
        lw $ra, 12($sp)                 # reload return address
        lw $v0, 0($sp)                  # restore n
        lw $t0, 4($sp)                  # restore $f12
#        mtc1 $t0,$f12                   # copy from temporary to $f12
        sll $t0,$v0,2                   # $t0 = $v0 * 4 (for index to float)
        la $t1,nArray                   # t1 = nArray
        add $t1,$t1,$t0                 # t1 = &nArray[n]
        lw $t1,0($t1)                   # t1 = *t1
        mtc1 $t1,$f10                   # $f10 = $t1
        add.s $f12,$f12,$f10            # $f12 += nArray[n]
        addi $sp, $sp, 16               # restore stack space
       
        jr $ra                          # return nArray[0]
       
#Add all the values
#Registers:
#In:
#       $v0 = n
#Out:
#       $f12 = float return value
addAll:
        addi $sp, $sp, -16              # allocate stack space for 4 words:
                                        # $ra, $v0, $f12
        sw $ra, 12($sp)                 # save $ra
        sw $v0, 0($sp)                  # use 0($sp) to save n ($v0) when needed
        mfc1 $t0,$f12                   # $t0 = $f12     
        sw $t0,4($sp)                   # use 4($sp) to save return ($f12) when needed
                                        # use 8($sp) to save ($) when needed

        move $v1,$v0                    # $v1 = n
        li $v0, 4                       # Syscall print_str
        la $a0, nStr                    # String to print
        syscall
        li $v0, 1                       # Syscall print_int
        move $a0,$v1                    # $a0 = n
        syscall
        li $v0, 4                       # Syscall print_str
        la $a0, endlineStr              # String to print
        syscall
       
        bne $v1,1,addAllRecurse         # if (n == 1)
        l.s $f12,nArray+4               # nArray[1]
        lw $ra, 12($sp)                 # reload return address
        addi $sp, $sp, 16               # restore stack space
        jr $ra                          # return nArray[1]
       
addAllRecurse:
        sub $v0,$v1,1                   # n = n - 1
       
        jal addAll
        lw $ra, 12($sp)                 # reload return address
        lw $v0, 0($sp)                  # restore n
        lw $t0, 4($sp)                  # restore $f12
#        mtc1 $t0,$f12                   # copy from temporary to $f12
        sll $t0,$v0,2                   # $t0 = $v0 * 4 (for index to float)
        la $t1,nArray                   # t1 = nArray
        add $t1,$t1,$t0                 # t1 = &nArray[n]
        lw $t1,0($t1)                   # t1 = *t1
        mtc1 $t1,$f10                   # $f10 = $t1
        add.s $f12,$f12,$f10            # $f12 += nArray[n]
        addi $sp, $sp, 16               # restore stack space
       
        jr $ra                          # return nArray[0]

        move $v1,$v0                    # $v1 = n
        li $v0, 4                       # Syscall print_str
        la $a0, nStr                    # String to print
        syscall
        li $v0, 1                       # Syscall print_int
        move $a0,$v1                    # $a0 = n
        syscall
        li $v0, 4                       # Syscall print_str
        la $a0, endlineStr              # String to print
        syscall

        l.s $f12,sum
        jr $ra                          # return

# if n is odd call addAll(n) else call addEven(n)
# Registers:
# $v0 = n
addEvenAll:
        andi $t0,$v0,1                  # n % 2 == 0
        beq $t0,0,addEven               # we just BRANCH to the routine
                                        # since we don't need to return
        j addAll                        # return from addAll will return
                                        # to addEvenAll() call
       
even:

main: 
        jal setArray                    # setArray()
        li $v0, 4                       # Syscall print_str
        la $a0, descStr                 # String to print
        syscall
enter:
        li $v0, 4                       # Syscall print_str
        la $a0, enterStr                # String to print
        syscall
        li $v0, 5                       # Syscall read_int
        syscall
        slti $v1,$v0,1                  # $v1 = $v0 < 1
        beq $v1,1,enter                 # if n < 1 goto enter
        slti $v1,$v0,50                 # $v1 = $v0 < 50
        bne $v1,1,enter                 # if n >= 49 goto enter
        jal addEvenAll                  # addEvenAll(n)
        mfc1 $t0,$f12                   # $t0 = $f12
        la $t1, sum
        sw $t2,0($t1)                   # sum = (addEvenAll return value)
        li $v0, 4                       # Syscall print_str
        la $a0, sumStr                  # String to print
        syscall
        li $v0, 2                       # Syscall print_float
        syscall
        li $v0, 10                      # Syscall to exit.
        syscall
 

Theoretical Sample Assignment on Assembly Language

MCIS500: Assembly Language

1. Discuss the role of interrupt handling. Why are interrupts used?

Interrupts are useful for handling events which do not appear on a regular schedule, or that need to processed as soon as they happen. It allows for events to be handled whilst you are running other programs or threads. You can use polling as an alternative to interrupts but that is inefficient since you will normally be busy waiting (if you are reading from a disk drive or a similar device, this may not be an issue).

 2. Discuss system architectures issues in evolution of x86 Intel processor family (segmentation, virtual memory, paging unit, floating point hardware, instruction pipeline, etc).

 The 8086 series started off being able to access memory in 64K segments, there were 4 segment registers (the stack segment is used for the processor stack, the code segment is used for the executable code, the data segment is used to access variables, and the extra segment is used when copying data between segments), It allowed 640 KB of memory, and code that ran inside a single segment was .com file. You needed to use far calls if the code exceeded 64 KB of memory. There were Dos extenders to handle memory above the 640 KB size, up to the 1 MB limit. The 386 processors and allow for the segment registers to access a full 32 bit range, or 4 GB per segment, so later versions of Windows use a flat memory model where all the segments refer to the same addresses. The early processors (upto the 386) had an optional floating point coprocessor to handle floating point arithmetic. They normally had the designation of 80287, 80387 etc. The Pentium had the floating point included, although the early Pentiums were recalled due to an error with division. Windows allowed the use of virtual memory, it uses the memory mapped unit to cause a page fault when memory is not available which the operation system then loads from disk. The instruction pipeline has been extended as the processor speed gets faster, because you are waiting for memory, so the caches become more important as the clock cycles become shorter. The pipeline allows floating point code to run at the same time as integer code. The early processors were 8/16 bit processors (16 bit registers, with an 8 bit data bus) (8088) or 16/16 (the 8086). The 386 was a 32 bit processor, and current processors are 64 bit.

 3. Discuss various assembly language issues including relationship between

assembly language statements, binary codes, and segment:address offsets. Explain the effects on various registers of executing assembly language statements.In segmented assembly language code, code runs in the code segment (controlled by the CS register). Data is accessed from the data segment (controlled by the DS register), and local variables are normally accessed on the stack which uses the stack segment (the SS register). If you need to call a routine in another segment you can do a far call which loads the CS register as well as the PC, and a return far gets the original CS back as well as the PC register. You can access memory in a segment with an override DS: ES: to indicate the segment register to use. A segment is 64K in size, which is 16 bits and they have to be located on a 16 byte boundary (the bottom 4 bits are 0), which leads to 1 MB of memory in total.

4. Give four different types of interrupts? Explain what is special in each type?

There are interrupts which can be caused by instructions such as divide by 0, which generates an interrupt. Another type of interrupt is caused when you execute an int #n instruction. This is called a software interrupt and used to be the way to call Dos functions (int 21h). The MMU can cause interrupts if memory is not available which is how virtual memory is handled, and you can also get hardware interrupts. Pressing the reset switch for example would cause an interrupt and can be used to get out of a loop where the processor would otherwise be unresponsive. There can also be timer interrupts which are used to enable multiprocessing. There are also interrupts used to support debugging with a single step interrupt and also breakpoint interrupt.

 5. How is an interrupt visible to the program in execution?

 When an interrupt happens it stops after the current instruction has finished executing, and then pushes the flags register, the code segment and instruction point and then jumps to the address controlled by the interrupt vector. The program is unaware of the interrupt (after it returns the program is in the exact same state).

 6. How is an interrupt visible to the processor?

 The program counter changes, the stack changes.

 7. How are interrupts processed?

 There is a routine to handle the interrupt, pointed to by the interrupt vector which contains the address of the handler. If you are writing a handler to deal with a software interrupt you may want to check one of the registers to decide what function you want to perform. Normally an interrupt should complete as quickly as possible in case another interrupt were to happen before that one completed processing (this does not apply to a software interrupt, since the original code is suspended until you return).

8. How does the system know whether some memory location contains an integer

number, floating point number or a machine instruction? What happens, if during an integer add instruction one encounters a floating point value in one of the argument registers?

The processor has no idea what is in a memory location, you can treat memory as a pointer, an integer, or floating point. The value 0 means the same thing for all of these types, which is why it is a good choice when allocating memory (0, 0.0, or NULL). The program is responsible for keeping track of what each location is used for. A character string ends with a 0 byte, which means if memory is cleared when allocated it is also a zero length string.

 9. Which problem does the cache memory solve? How is the solution implemented?How can application programmer best influence the proper operation of this solution?

Cache memory is faster to access that ram on the motherboard, and also has a wider data bus so more memory can be read in 1 chunk. It is normally limited in size, and can even have multiple caches with a level 1 cache and a level 2 cache. Because memory is accessed by a wider bus, it means that you should related data together. So If you have a series of points with X, Y, and Z coordinates if you have the structure X,Y,Z it is better than having separate tables with X[], Y[], Z[] if you need to access all 3. Once you access X, Y & Z are fetched as well, and so you don’t have to wait for them. If you are processing a lot of data, then it makes sense to keep the code located together rather than calling routines separated in memory.

 10. Which problem does the virtual memory solve? How is the solution

implemented? How can application programmer best influence the proper operation of this solution?

Virtual memory is designed to allow for more memory to be accessed than in physically present in RAM, it allows you to have multiple programs where the total memory used is more than is present, or even for a single program to use more RAM than is present. It works by using the MMU (memory management unit) to allocate memory as 4 KB chunks, and it gives these an address. If you run out of memory, some chunks of memory will be written to the hard drive, and a special flag will be set, so that when you access it, then an interrupt will occur and the operation system will load the memory back from the disk. If you are writing a program and want to make the most of virtual memory, you should keep related items together in memory so that they will be paged in or out of memory at the same time (say you are writing a program that handles a DVD collection, you always need the titles and record id to search through, but you may not need the details of the individual DVD unless it is in the one you are interested in. So you would allocate memory for the titles separately from the contents).

Define, in your own words, each term .

1. binary number

 A binary number is built out of 1’s and 0’s (it is base 2), and is the way numbers are stored in the processor with a + voltage being 1, and a 0 voltage being a 0 for example. When you talk about a processor being 16 bit, or 32 bit you are talking about how many binary digits can the processor handle in 1 instruction.

 2. signed integer

 A signed integer uses the most significant bit as a negative value, so an 8 bit integer would have -128 as the most significant bit, and could represent numbers from -128 to 127, a 16 bit integer would range between -32768 and 32767 and a 32 bit integer would range between -2 billion and +2 billion.

3. twos complement

 A twos complement number means that the most significant bit is used to determine the sign, and represents the smallest possible value. The alternative is ones complement where the most significant bit is used as a sign indicator, this means an 8 bit value would range from -127 to 127. In a ones complement number there are 2 values of 0 (a negative version also exists).

4. normalized floating point numbers

 A floating point number consists of 3 components, a sign bit, a mantissa and an exponent. The sign bit is used to indicate whether the number is negative and the mantissa represents the fractional part of the number. The exponent represents how the fractional part is shifted, there is an implicit 1 in the 1.xxxxxxx value for the mantissa, which represents a normalized floating point value. When the number gets very small, the implicit 1 is not used and the number is denormalized, it loses a lot of accuracy but extends the range that can be represented.

 5. byte

 A byte is a collection of 8 bits, it normally used to represent characters (although not Unicode characters which are larger). A signed byte goes between -128 and 127, and unsigned byte allows you to store a number up to 256.

 6. word

 A word is a collection of 16 bits, it is normally used to represent Unicode characters, or short values. It ranges in size between -32778 and 32767 if signed and upto 65536 if unsigned. This is the size of memory you can access in a single segment, and used as the offset.

 7. fetch-execute

 The processor fetches an instruction from memory and then executes it (after it fetches the instruction it modifies the program counter and then decodes the instruction and executes it).

 8. error-correction

 Error correction allows for a value to be automatically corrected if there is a problem reading it, CD’s have error correction data on them so that if they are scratched it is still possible to read the data without an error.

9. parity bit

 Parity is used as a simple form of error detection, there are 2 types of parity bit. Odd or even parity, odd parity means the number of bits set is odd, and even parity means the number of bits set is even.

 10. gate

 A gate performs a logical operation, such as NOR (not or). It is possible to build a processor with just NOR gates.

 11. Boolean algebra

 Boolean algebra is named after George Boole and deals with 1s and 0s. There are operations such as AND (if both values are true then the answer is true), OR (if either value is true then the answer is true), XOR (exclusive or, which is true if the 2 inputs are different), and NOT which is the opposite value of a single input.

 12. combinational circuit

 A combinational circuit takes as input a series of binary values and outputs another binary value. This is done using logic gates.

 13. multiplexor

 A multiplexor is used to select between several input lines to go a single output line. For example you may have R,G,B signals representing a color value, and a multiplex would allow you to just send one of those values down a single wire.

 14. decoder

 A decoder allows you convert from binary channels back to a single value. Say you have 1,0,0 in your input select, then it will select line 4.

 15. comparator

 A comparator compares 2 analog values and switches between them depending on which is largest (or smallest). This is used when converting from an analog signal to a digital signal, where you use a reference value for one of the 2 values.

 16. half adder

 A half adder, takes 2 bits as input and gives as output the sum of the 2 bits plus a carry bit.

 17. adder

 A full adder, takes 3 bits as input with one of those bits representing a carry bit, and gives as output the sum of the 3 bits plus a new carry flag. You can chain multiple adders together to add 16 or 32 bit values.

 18. shifter

A shifter is used to implement a binary shift operation or a rotate. It moves the bits into a new value (so 1001100 could become 0100110 for example).

 

 

19. ALU

 

ALU stands for arithmetic and logical unit, this is the “heart” of the processor and is where the program logic is actually carried out. It handles logical instructions (and, or, not), arithmetic instructions (add, multiply, divide) and comparisons (these are normally treated as a subtract instruction).

 

20. register

 

A register is where the computer keeps track of what it is doing. Mathematical instructions and logical instructions involves registers, and moving to and from memory uses registers as a temporary store. There are registers used for controlling the execution of the program (the instruction pointer), for dealing with the stack (the stack pointer), and accessing variables on the stack (the BP register). Certain instructions use a fixed register, for example LOOP uses the CX register as the count, You can access part of the register with AL,AH,AX,EAX (AL access the low 8 bits of the A register), AH (access the high 8 bits of the 16 bit AX register), AX accesses the low 16 bits of the register and EAX accesses the full 32 bits of the register.

 

21. register

 

Segment register are used to control how the memory is accessed, so reading from DS:[DX] uses the segment register combined with the DX register to determine the address to access.

 22. addressing modes

 There are several addressing modes, such as immediate where the value is part of the instruction. Absolute means the memory is accessed at a particular address. Indirect means that the value is accessed using a pointer in a register, and you can also access memory with an offset so you can use [DX+4] for example.

 

23. cache

 

The cache is memory that can be accessed more quickly than the main memory, it is normally small compared to the amount of memory you have installed but can make the program run faster if used correctly.

 

24. instruction pipeline

 

When an instruction is fetched, it is read from memory, then it is decoded, if the instruction is accessing memory, then that memory is fetched, then the instruction is executed, if the instruction writes to memory then that write is done. There are 2 points during this where you may be waiting for memory, so it is possible for another instruction to happen whilst it is waiting. In addition floating point instructions use a different execution circuit so they can happen at the same time as a integer operation is being performed.

25. interrupt handling

When an interrupt happens, the processor uses a vector to jump to a memory address. The routine at this address responds to the interrupt, in the case of a division by zero interrupt for example it may output a message to the screen and stop execution of the program (or throw an interrupt if the program is in a language that supports them). If you are dealing with hardware you may want to re-enable the interrupt and set control lines depending on what you are controlling.

An overview about Assembly Languages

6502 assembly language programming.

            The 6502 is one of the simplest processors in use, as it only has 3 registers (A,X,Y). The

A register, is the accumulator and is used as a general purpose register. All arithmetic operations

work on the accumulator. You can access memory indexed with the X and Y registers. It has a

stack of 256 values, and a zero page (the first 256 bytes of memory) which can be accessed with

a shorter instruction that takes less time. You use instructions such as LDA which loads the

accumulator which a value from memory, STA which stores the accumulator. You have branch

instructions such as BEQ (branch if the zero flag is set), BNE (branch if the zero flag is not set),

BCC and BCS (which branch depending on the carry flag), BMI and BPL (which branch based on

the negative flag). You can't set the condition code flag can't be set directly, although you can use

CLC, and SEC to clear or set the carry flag. JSR which is used to call a subroutine and RTS which

returns. TAX, TXA, TAY, TYA are used to transfer between the accumulator and the X & Y registers.

There are instructions for adding (ADC), subtracting (SBC), shifting (ASL, LSR), rotating (ROR, ROL),

as well as the boolean instructions (AND, ORA, NOT, XOR). There is also a decimal mode for BCD

(binary coded decimal) artithmetic, which simplifies the logic on dealing with numbers you need to

display (each 4 bits of of a number is treated as 0-9 with the carry automatically going the half bytes).

This means you can extract the number with a simple mask, rather than having to divide by 10.

 

Z80 assembly language programming.

            The Zilog Z80 processor was used in Sinclair's home computers (Timex in America). It was

also used to implement CP/M which was the basis of the original MS-Dos. I'm not aware of any courses

that are using Z80, but if there are any please let us know, but even so we can handle the assignments

if there are any.

 

AVR assembly language programming (as used in the Arduino)

            The AVR microprocessor is normally programmed in C, but for higher performance or more

accurate timing assembly language is useful. The Arduino is a reasonably low cost microcontroller

that offers an open source platform with shields providing all types of input / output controls.

 

Motorola 68000 assembly language programming.

            The 68000 family are 32 bit processors (although the 68000 only had a 16 bit data bus, and

a 24 bit address bus). It has 16 registers, 8 data registers (D0-D7) and 8 address registers (A0-A7).

You can access the data registers as either a byte, word, of long (8,16,32 bit value) and they can be

used orthogonally (you can use any data register when a data register is required). Accessing data

registers can set the condition code flags, whilst accessing the address registers does not set the

condition code flags. You can access memory using the address registers, with post increment or

pre decrement on the address. It is a big endian processor unlike the 8086 series (the most significant

byte comes first in memory). It was used in the Atari ST and Commodore Amiga computers as well as

the Apple Macintosh and ran around 8Mhz, and supported 16MB of RAM (although they typically came

with 512KB of RAM). It supports the basic mathematical operations, including support for multiplication

and division (signed and unsigned).

 

ARM assembly language programming.

            The ARM processor uses a RISC model, with all instructions being 32 bits in size. The ARM

processor has a source 1, source 2, destination instruction set. So you can do ADD R0,R1,R2 to do

R0 = R1 + R2. Unlike the other processors mentioned so far, it has some other nice features. Most

instructions can be executed conditionally, so to do an abs function you can just do RSBMI a, #0

which means if the minus flag is set, then subtract a from 0. The ARM processors are very efficient

with low power usage which means they are still used a lot in current machines (most Mobile phones,

the Nintendo DS and even the Windows 8 notebooks). Since all the instructions have to fit into 32

bits, it means that you can't load any value you want into a register since there isn't enough room. The

assembler will construct a pair of instructions if needed to load a constant value. When loading a

constant it has a shift and a value, so if the values 0-255 are efficiently represented, but so is 0x8000.

If you need to load the constant 0xffff, it may load (0xff << 8) and then or with (0xff).

The ARM processor also supports an additional mode, called thumb mode which uses 16 bit instructions.

It takes more instructions to run the code, but since they are smaller it can reduce the code size by around

30%.

 

MIPS and SPARC assembly language programming.

            Both of these are used in current courses, normally using an emulator such as MARS or SPIM for

MIPS programming. Both of them are RISC processors which use the 3 operand format of instructions.

 

8086 assembly language programming.

            Some courses still teach programming under DOS mode using 8086 instructions which means you

have to use segment registers to access more than 64K. The 8086 has segment registers for code, data,

stack. It also has 4 registers AX,BX,CX,DX which are general purpose although some instructions will only

work with certain registers. You can also access the high or low bytes of each of these registers with AL, AH.

It also has index registers SP (stack pointer), BP (base pointer normally used to access arguments passed

on the stack), DI (destination index), SI (source index). From the 386 processor onwards, it was expanded

to 32 bits, with EAX to EDX and the segments expanded to allow for so called flat mode (4GB segments).

The processor is a little endian and is a CISC design. It has instructions for string handling (LODSB & MOVSB

for byte orientated strings and LODSW & MOVSW for word orientated strings). You can use a REP instruction

in front of certain instructions to repeat the instruction (in front of the string instructions). With the introduction

of the MMX processor, additional registers were added that allow you to operate as SIMD (single instruction

multiple data) where you can do multiple operations at the same time with interleaved data. There is also a

64 bit variant of the 8086 which adds RAX-RDX. The 8086 supported a floating point coprocessor, but that

became an integrated part of the processor with the Pentium processor.

 

Assembly language programming in general.

            This is a rough outline of the topics involved in assembly language programming, I've tried to be

reasonably comprehensive and so there will be sections that are not appropriate to some microprocessors,

for example the MMU (Memory Management Unit) is not typically found on 8 bit microprocessors, and the

FPU (Floating Point Unit) may even be missing on current processors such as certain configurations of the

ARM processor.

 

Beginning Machine Code programming.

 

            Inline assembly language and call assembly language routines from C/C++. Inline assembly language

allows you to mix C code and assembly language in the same function it is easy to use but is not portable

between different compilers. If you write a routine in assembly language, you can link it with C compiler and call

it as though it were a regular function (although you may need to specify some options in the C code to determine

how parameters are passed, and the external name).You can also write an entire in assembly language in which

case you don't need to worry about how it will interface. The sample code given below is for a generic processor

with registers with single letter names, that uses OPERAND SOURCE, DESTINATION syntax, you may find

other formats in use, such as OPERAND DESTINATION, SOURCE [, SOURCE2] depending on the actual

processor you are writing code for.

 

Binary and Hexidecimal values.

            Since you are working at a very low level, it is common to represent values as hexidecimal or binary values.

Binary values are useful when working with masks, since you can see the bitpatterns involved, hexidecimal values

make it easier to view the contents of memory since they are the same length (8 hexidecimal digits for each 32

bit word for example).

 

What Are Registers?

            Almost all processors are register based (there are some that are stack based but they are not in the

mainstream). Most processors have a limited number of registers (between 3 & 32) and they have specific

roles. The typical roles used by registers are address registers (including the stack pointer, and program counter),

segment registers (80x86 family in particular, the segment registers define how the physical memory is mapped

to a logical address and also determines the access rights), status (or condition code) register which keeps

track of flags such as zero flag, negative flag, parity flag, overflow flag, carry flag, the interrupt level, supervisor mode,

and possible others. There may also be index registers (although these tend to have been replaced with just regular

registers now), and general arithmetic registers. You can normally use a value from a register, an immediate value,

or by accessing memory either from an absolute location, an indirect address (similar to using a pointer in C/C++),

an indirect address with an offset (either fixed, or provided by a register). A register is fast to access, and is generally

what determines the size of the processor (so an 8 bit processor means 8 but registers, a 32 bit processor has 32 bit

registers, and so on). There may also be floating point registers which have some bits for exponent, mantissa and a

sign bit, there can also be some registers which are used as vector registers, so there can be multiple values inside

a single register (for example the MMX registers). Some processors allow you to treat a pair of registers as a single

value, or to access part of a the register as though it were the full value.

 

Arithmetic in machine code.

            Since artithmetic operations involve the registers, you can perform simple arithmetic operations such as

addition and subtraction (some processors also have multipication and division). You use the carry flag if you need

to handle numbers that won't fit inside a register. So for adding AB + CD you would do CLC; ADD B,D; ADD A,C.

Some processors also have a BCD (Binary Coded Decimal) mode, which puts a single decimal digit in each 4 bits,

so you add the numbers together, and it may carry between each 4 bit value. Also there can be floating point

arithmetic instructions, which treat the values as a floating point number. You can get underflow values (where the

number is too small to represent correctly) as well as infinity values, and NaN (not a number value) for operations

such as divide by 0.

 Binary operations in machine code.

            Assembly language provides operands for and, or, xor (exclusive or), not, shift and rotate, there may also

by bit operations such as set, clear or test an individual bit.

 Conditional code in assembly language:

            Most processors don't have conditional instructions (the ARM family does, and so you can write code slightly

differently, although you still need to know about inverting the condition). You do a check, and then branch on the

results of the condition code register, so if you want to write if (a < 0) a = b; you actually code it as if ( a >= 0) goto

skip; a = b; .skip:

            CMP A              ;Just loading A on some processors will set the condition flag, so this instruction may not

                                    ;be needed

            BMI .SKIP

            MOVE B,A

 Loops in assembly language.

            Normally with loops, you tend to write them in the reverse order you would do in a high level language.

 Here we have an example of a for loop (for (int a = 0; a < 10; a++) although we have reversed it to

for (int a = 10; a != 0; a--). The reason for reversing the loop is that we can avoid the CMP #10,A if we changed it

to INC A instead of DEC A.

 MOVE #10,A     ;We want to do this 10 times

.LOOP:

 ADD B,C          ;Add B to C

            DEC A              ;A = A - 1

            BNE .LOOP      ;If A is not 0 then goto loop

           

A whle loop is even simpler, we just do

            JMP .WHILETEST

.WHILELOOP:

.WHILETEST:

            CMP #17,A

            BNE .WHILELOOP

Macros in assembly language.

            Since assembly language is more verbose than higher level languages, it is common to use macros to

perform common operations. You may have a macro to display a string for example, which might look like this.

MACRO DisplayString MOVE /1,B; MOVE #PRINT_STRING,A; SYSCALL A; ENDMACRO which you would

use as DisplayString "Assembly Language Is Easy", it may need to be more complex depending on the

assembler, perhaps you might need to put the string into the data segment, so you could have a macro

MACRO DisplayString DATA  @StrData: DCB /1,0 CODE MOVE #@StrData,B; MOVE #PRINT_STRING,A;

SYSCALL A; ENDMACRO, so as you can see a macro can simplify the differences between assemblers, and

allow for code that can be more easily ported and easier to read as well.

 Assembly Language Addressing Modes.

            You can specify a value as an immediate value (typically with a # sign, so MOVE #10,A). As an

absolute value MOVE NUM_ELEMENTS,A. From a register MOVE B,A, or from an indirect register

MOVE (B),A equivalent to A = *B. Indirect register with post increment MOVE (B)+,A equivalent A = *B++.

Indirect register with pre decrement MOVE -(B),A equivalent A = *--B. Indirect with offset MOVE (B,#4),A

which is used for accessing structures, and indirect with register offset MOVE (B,C),A which is used for

accessing arrays A = B[C]. Some processors allow for MOVE (B,C*4),A type operands (where the *4 may

be replaced by 2,4 or 8)

 Calling Subroutines and passing arguements.

            There are 2 main ways of passing arguments to subroutines, you can either use the stack (which

is commonly the way arguements are passed from C/C++), or you can use the registers. The advantage

of using registers is that it is faster but means that the code can be more complex since you need to

preserve the registers at the calling site, and you are normally limited to a certain number of arguements

before you need to use the stack anyway. When you use the stack to pass arguements, it automatically

allows you to have recursive calls and also reserve space for local variables. When you call a subroutine

the address of the program counter goes on the stack and when you return, it sets the program counter

to equal the value on the top of the stack and increments the stack pointer. IF you know that a routine

you are calling is the last thing in the routine you are currently in, then you can jump to the subroutine

with a normal jump command rather than a jump to subroutine command, and then when it returns it

will return back to the the previous routine this is called tail end recursion and is a useful optimization.

To access the arguements passed on the stack you would have code something like the following.

.SETCOLOR:     ;Set the color to R,G,B

            MOVE SP,S

            MOVE [S,#-3],R

            MOVE [S,#-2],G

            MOVE [S,#-1],B

            .... Rest of the code     

 

Hardware access in assembly language.

            Most hardware can be accessed using memory mapped addresses, although on some processors

it may be done by accessing a port using a special instruction IN, or OUT for example. Since you are

operating at the level device drivers operate at, you need to make sure you don't exceed the capabilities

of the device, so you may need to insert wait statements after accessing the hardware before checking the

result or writing to the hardware again.

 

Interrupt routines in assembly language.

            Interrupts are handled in a similar way to subroutines, but you need to make sure that you don't

change the state of any of the registers otherwise it may lead to unpredictable behavior in the rest of the

program. Normally when entering an interrupt, further interrupts are disabled until the processing is

complete so you should ensure that the interrupt routines execute as fast as possible. You should also

avoid calling system functions during an interrupt such as writing to disk, and many operating system

routines are not designed to be reentrant.