Академический Документы
Профессиональный Документы
Культура Документы
The editor responsible for all textual issues not in the purview of the copy editor. The line editor
reads the text for sense, clarity, tone, flow, logic, quality of expression, redundancy, good order,
conciseness, and consistency, covering some of the same ground as the copy editor but with a
view to the text as a whole (as opposed to the copy editor, whose focus tends to be on individual
words and sentences).
A line editor is a text editor computer program that is oriented around lines.Now considered
extremely old-fashioned, they stem from the days when a computer operator would be sitting in
front of a teletype (essentially a printer with a keyboard), so there was no screen and no way to
move a cursor around a document.
Assembly Language
© Copyright Brian Brown, 1988-2000. All rights reserved.
| Notes | Home Page |
Early computer systems were literally programmed by hand. Front panel switches were
used to enter instructions and data. These switches represented the address, data and
control lines of the computer system.To enter data into memory, the address switches
were toggled to the correct address, the data switches were toggled next, and finally the
WRite switch was toggled. This wrote the binary value on the front panel data switches to
the address specified. Once all the data and instruction were entered, the run switch was
toggled to run the program.
The programmer also needed to know the instruction set of the processor. Each
instruction needed to be manually converted into bit patterns by the programmer so the
front panel switches could be set correctly. This led to errors in translation as the
programmer could easily misread 8 as the value B. It became obvious that such methods
were slow and error prone.
With the advent of better hardware which could address larger memory, and the increase
in memory size (due to better production techniques and lower cost), programs were
written to perform some of this manual entry. Small monitor programs became popular,
which allowed entry of instructions and data via hex keypads or terminals. Additional
devices such as paper tape and punched cards became popular as storage methods for
programs.
Programs were still hand-coded, in that the conversion from mnemonics to instructions
was still performed manually. To increase programmer productivity, the idea of writing a
program to interpret another was a major breakthrough. This would be run by the
computer, and translate the actual mnemonics into instructions. The benefits of such a
program would be
reduced errors
faster translation times
changes could be made easier and faster
As programmers were writing the source code in mnemonics anyway, it seemed the
logical next step. The source file was fed as input into the program, which translated the
mnemonics into instructions, then wrote the output to the desired place (paper-tape etc).
This sequence is now accepted as common place.
The only advances have been the increasing use of high level languages to increase
programmer productivity.
here is also a probable maintenance phase also associated. The chosen language will
undoubtably need to be converted into the appropriate binary bit-patterns which make
sense to the target processor (the processor on which the software will be run). This
process of conversion is called translation.
The following diagram illustrates the translation sequence necessary to generate machine
code from specific languages.
ASSEMBLY LANGUAGE PROGRAMMING
Asemblers are programs which generate machine code instructions from a source code
program written in assembly language. The features provided by an assembler are,
allows the programmer to use mnemonics when writing source code programs.
variables are represented by symbolic names, not as memory locations
symbolic code is easier to read and follow
error checking is provided
changes can be quickly and easily incorporated with a re-assembly
programming aids are included for relocation and expression evaluation
The assembler converts the written assembly language source program into a format
which run on the processor. Each machine code instruction (the binary or hex value) is
replaced by a mnemonic. A mnemonic is an abbreviation which represents the actual
instruction.
+----------+---------+-----------------+
| Binary | Hex | Mnemonic |
+----------+---------+-----------------+
| 01001111 | 4F | CLRA | Clears the A accumulator
+----------+---------+-----------------+
| 00110110 | 36 | PSHA | Saves A acc on stack
+----------+---------+-----------------+
| 01001101 | 4D | TSTA | Tests A acc for 0
+----------+---------+-----------------+
Mnemonics are used because they
Assemblers also accept certain characters as representing number bases and addressing
modes.
Assembly language statements are written one per line. A machine code program thus
consists of a sequence of assembly language statements, where each statement contains a
mnemonic. Each line of an assembly language program is split into four fields, as shown
below
The label field is optional. A label is an identifier (or text string symbol). Labels are used
extensively in programs to reduce reliance upon programmers remembering where data
or code is located. A label can be used to refer to<
a memory location the value of a piece of data the address of a program, sub-
routine, code portion etc.
The maximum length of a label differs between assemblers. Some accept up to 32
characters long, others only four characters. A label, when declared, is suffixed by
a colon, and begins with a valid character (A..Z). Consider the following example.
Here, the label START is equal to the address of the instruction LDAA #24H.
The label is used in the program as a reference, eg,
JMP START
This would result in the processor jumping to the location (address) associated
with the label START, thus executing the instruction LDAA #24H immediately
after the JMP instruction. When a label is referenced later on in the program, it is
done so without the colon suffix.
Each instruction consists of an opcode and possible one or more operands. In the
above instruction
JMP START
the opcode is JMP and the operand is the address of the label START.
The opcode field contains a mnemonic. Opcode stands for operation code, ie, a
machine code instruction. The opcode may also require additional information
(operands). This additional information is separated from the opcode by using a
space (or tab stop).
The operand field consists of additional information or data that the opcode
requires. In certain types of addressing modes, the operand is used to specify
o constants or labels
o immediate data
o data contained in another accumulator or register
o an address
The comment field is optional, and is used by the programmer to explain how the
coded program works. Comments are preceded by a semi-colon. The assembler,
when generating instructions from the source file, ignores all comments. Consider
the following examples,
Note that the programmer does not need to worry about bit patterns, hex values,
and the addresses of STATUS or CODE. The assembler, when fed the above
program, will generate the correct code. The code output from the assembler will
be,
Location 0100 holds the value associated with the label STATUS
Locations 0101 to 0103 perform the LDAA STATUS instruction
Locations 0104 to 0106 perform the JMP CODE instruction
The statement ORG 0100H in the above program is not a machine code
instruction. It is an instruction to the assembler, which instructs the assembler to
generate the code to run at the designated origin address. Instructions to
assemblers are called pseudo-ops. These are used for
The assembler does not generate any machine code instructions for pseudo-ops or
comments. Assemblers scan the source program, generating machine instructions.
Sometimes, the assembler reaches a reference to a variable which has not yet been
defined. This is referred to as a forward reference problem. The assembler can
tackle this problem in a number of ways. It is resolved in a two pass assembler as
follows,
On the first pass, the assembler simply reads the source file, counting up the
number of locations that each instruction will take, and builds a symbol table in
memory which lists all the defined variables cross-referenced to their associated
memory address. On the second pass, the assembler substitutes opcodes for the
mnemonics, and variable names are replaced by the memory locations obtained
from the symbol table.
The functions that the assembler will perform in translating the program are,
The other counter is the line counter, which keeps track of the line number being
processed. After each source line has been examined on the first pass, the location
counter is incremented by the correct number of bytes.
When the assembler processes line 1 of the source, it cannot replace the symbols
ZERO and OLDER by their addresses because those symbols have not yet been
defined. This is called a forward reference problem.
The assembler will place the symbols into the symbol table, determine the number
of bytes to advance by altering the contents of the location counter to 3, then
proceed to process the next source line. After processing line 3 of the source, the
current state will be,
Symbol Address
ZERO ---
OLDER ---
ONE ---
OLD ---
LIMIT ---
Location Counter: 8
Line Counter: 4
The symbol table currently holds five symbols, none of which yet has an address.
During processing of line 4, the assembler picks up the symbol OLD. It
establishes that it is already in the symbol table, so does not enter it again.
During line 5, the assembler encounters FRONT, and it is entered into the symbol
table. The assembler also knows its address (10), so it is also placed into the table.
After processing line 9 of the program, the current state is,
Line Address Label Operation OPD1 OPD2
1 0 COPY ZERO OLDER
2 3 COPY ONE OLD
3 6 READ LIMIT
4 8 WRITE OLD
5 10 FRONT LOAD OLDER
6 12 ADD OLD
7 14 STORE NEW
8 16 SUB LIMIT
9 18 BRPOS FINAL
Symbol Address
ZERO ---
OLDER ---
ONE ---
OLD ---
LIMIT ---
FRONT 10
NEW ---
FINAL ---
Location Counter: 20
Line Counter: 10
The first pass continues, building up the symbol table. When the assembler
determines the address of the various symbols in lines 16 to 21, these are entered
into the table. At the end of pass 1, the symbol table should list all declared
symbols as well as their addresses.
Symbol Address
ZERO 33
OLDER 35
ONE 34
OLD 36
LIMIT 38
FRONT 10
NEW 37
FINAL 30
Location Counter: 39
Line Counter: 22
Code generation is performed on the second pass. Before starting, the line and
location counters will be reset to 1 and 0 respectively. The assembler now
generates one line of object code for each source line. Line one is translated to
Successive lines are translated in the same manner. On encountering the label
FRONT in line 5, the assembler ignores it. Lines 16 to 21, where space is reserved
for variables, the assembler may leave these undefined, or initialize them to zero.
The object code generated by the second pass will be,
ASSEMBLER DIRECTIVES
As mentioned previously, assembler directives are instructions to the assembler, and are
not translated into machine instructions. The use of directives gives the programmer
some control over the operation of the assembler, increasing flexibility in the way
programs are written. The following is a list of the common pseudo-ops.
EQUATE
is used to make programs easier to write. The EQU directive creates absolute
symbols and aliases by assigning an expression or value to the declared variable
name. Its format is,
LDAA #NUMBER1
LDAA #36H
ORIGIN
This specifies the address to be used for the generation of code. Subsequent
instructions and data address's begin at the new value. Normally, it is used to set
the start address of the program, but can also set the location counter to the value
specified.
ORG 120H
LDAA #FFH
ORG $ + 2
start: LDAA #34H
The instruction associated with the label start is declared to start at the address
2bytes beyond the current value of the location counter (specified by $).
CPU TYPES
This directive is used by multi-purpose assemblers to specify which target
processor is being used. The format for CRS8 is
CPU cpuname
CPU 6802
HOF recordtype
BYTE STORAGE
The directive used to allocate and initialize bytes (8bits) of storage is
DFB definebyte
The name portion is optional. Consider the following examples for CRS8.
value1: DFB 16
form: DFB 6*2
text: DFB "Enter your name: "
In the first example, the label value1 is assigned a single byte of storage, which is
initialized to 16 decimal.The second example allocates a single byte of storage for
the label form, and initializes it equal to 12. The last example allocates 17 bytes
of storage for the label text. The first byte will be initialized to E, whilst the last
byte is initialized to an ASCII space.
WORD STORAGE
The directive used to allocate and initialize words (two bytes) of memory storage
is,
DWM 1687H
mess: DWM 'ab'
The first example allocates one word of storage, having the values 16H followed
by 87H. The second example defines mess as a word initialized with the character
values a followed by b. The b will be placed in the low-order byte, and the a will
be placed in the high order byte. If only one character is specified, the high-order
byte will contain 0.
Strings when using the DW directive must not contain more than two characters.
This example allocates 100 storage bytes, associating the first byte with the label
array. The value of these bytes is indeterminate at this point. The 100 bytes will
be allocated relative to the current location counter.
END
In this example, the END directive informs the assembler that there is no more
source statements.
ORG 0100H
start: LDAA #3FH
JMP start
END start
In this example, the END directive also specifies that the entry point to the
program is the label start, whose address is 0100H.
CRS8 MC6802
It is not necessary to type the extension .ASM, and CRS8 will produce two output files.
The first column is the address, the second the instructions or data, and then the
mnemonics and comments. This listing is used by the programmer to verify that the
assembler has produced the correct instructions and data at the correct addresses. We can
clearly see that it has correctly interpreted the address of Source in the statement LDX
#Source as the bytes CE 0100.
S00D0000433A363830322E48455892
S113010048656C6C6F20616E642057656C636F6D1D
S10401106585
S1130120CE0100C611A600A711085A26F87E012D9F
S9030120DB
Digit
0,1 Record Type = S0, S1 or S9
2,3 Number of bytes in Record which includes the load address
and checksum bytes
4,5,6,7 Load Address 8 to n-2 Data or coded instructions
n-1 to n Checksum value
Lets look at how elementary data is represented by the programmer for use in assembly
language programs.
Characters
are single eight bit values represented using the ASCII code. Values range from 0
to 127. The statement
Letter: DFB 'A'
associates one byte of storage to the variable Letter, initializing it to the ASCII
character 'A' (41H).
Character Strings
are multiple bytes, each byte holding an ASCII character. The statement
String: DFB 'Hello there.'
allocates 12 bytes of storage space. The variable String has the address of the first
byte, which has been allocated the character 'H' (48H).
Integers
are stored as 16 bit values (two bytes or one word), and are signed or unsigned.
The statement
Number1: DWM -17D
allocates a word of storage for the variable Number1, initializing the word to -17
decimal. Some processors have different instructions for operations on signed and
unsigned integers. If the processor cannot handle a 16bit value (ie, has only eight
bit registers), software will need to be written to do any comparisons on these
types.
Character Arrays
are essentially text strings. Each element of the array has storage space for an
ASCII character. Strings in some HLL's are terminated with an End-Of-String
symbol (in C it is ASCII 00h, in PCDOS it is ASCII '$'). The following statement
Digits: DFS 10
allocates 10 locations for a character based array called Digits. The following
code routine initializes the Digits array (each successive element) to the digits 0
to 9.
ORG 0120H
start: LDAA #30H ; ASCII '0'
LDAB #11 ; ten digits
LDX #Digits
loop: STAA 0,X
INX ; next element
INCA ; next digit
DECB
BNE loop
exit: ....
Copy
This copys a source string to a destination area. The declaration of the routines is,
copystr( src, dest )where src and dest represent the address of the source and
destination strings. Writing this type of routine is ideally suited to a processor
which has more than one Index or Base register. The MC6802, having only one
Index register, presents a small problem. The following code shows this program
implemented for the MC6802.
CPU 6802
HOF MOT
ORG 100H
str1: DFS 10
st1len: EQU $ - str1
str2: DFS 10
ORG 120
HSRCINX:DFS 02H ; pointer for src string
DSTINX: DFS 02H ; pointer for dest string
start: LDX #str1 ; store address of str1
STX SRCINX
LDX #str2 ; store address of str2
STX DSTINX
jsr initstr1 ; initialise str1
jsr copystr ; copy str1 to str2
exit: bra exit
initstr1: LDAA #41H ; character 'A'
LDAB #11 ; elements 1 - 30
LDX #str1 ; point to str1
lp1: STAA 0,X ; store character
INX ; next element
INCA ; next value
DECB ; loop around
BNE lp1
LDAA #00 ; null terminator
STAA 0,X
RTS
copystr: LDX SRCINX ; pick up source pointer
cplp2: LDAA 0,X ; get source character
CMPA #00H ; eostr?
BEQ cpstrq ; yes, then exit
INX ; else inc source pointer
STX SRCINX ; store source ptr
LDX DSTINX ; get destination pointer
STAA 0,X ; store character
INX ; inc dest ptr
STX DSTINX ; store dest ptr
LDX SRCINX ; reload source pointer
BRA cplp2 ; repeat
cpstrq: LDX DSTINX ; Null terminate dest str
CLR 00,X
RTS
END start1
String Length
Returns the length of a terminated string. The following code shows this routine
implemented for the MC6802. Strlen is entered with the Index register pointing
to the string, and returns the length of the string in the B accumulator.
CPU 6802
HOF MOT
EOFSTR: EQU 00H
ORG 100H
str1: DFB 'Hello and Welcome.', 00H
ORG 120H
start: LDX #str1 ; point to string jsr strlen
; find length of str1
exit: bra exit
strlen: LDAB #00 ; character count
strlp1: LDAA 0,X ; read character
CMPA #EOFSTR ; is it end of string
BEQ strexit ; yes, then exit
INX ; no, inc str ptr
INCB ; inc character count
BRA strlp1 ; and repeatstr
exit: RTS ; acc B has length
END start2
Search for first occurrence of a character
This routine returns the address of the specified character found in the string. If
the address returned is zero, it indicates the character was not found. The
following code shows this routine implemented for the MC6802. Strpos is
entered with the Index register pointing to the search string, and the A
accumulator with the character search value.
CPU 6802
HOF MOT
EOFSTR: EQU 00H
ORG 100H
str1: DFB 'Hello and Welcome.', 00H
ORG 120H
start: LDAA #6FH ; ASCII 'o'
LDX #str1 ; point to src string jsr strpos
; find first 'o' in str1
exit: bra exit
strpos: CMPA 0,X ; is char = search value
BEQ strex2 ; yes then exit
CMPA #EOFSTR ; is it end of string
BEQ strex1 ; yes, then exit
INX ; no, inc str ptr
BRA strpos ; and repeat
strex1: LDX #0000H ; not found
strex2: RTS ; Index reg has address
END start3
Search for Substring
This routine is used to find the starting address of a substring within a larger
string. It accepts a source string pointer, and a pointer to a substring. It returns the
address of the substring, if not found it returns address zero.
Substring Insertion/Replacement
This routine inserts a substring into an existing string. Most versions overwrite
existing characters. It accepts a pointer to the source string, a pointer to the
substring to insert, and a numeric value representing the start position where
insertion should begin. No characters should overwrite the end-of-string
terminator, or be written to memory locations after the terminator. The routine
should return a numeric value representing the number of characters inserted.
String Reverse
This routine reverses the characters in a string. It accepts the address of the string.
Hello becomes olleH
String to Uppercase
This routine converts all characters of a string to uppercase. It accepts the address
of the string. Hello becomes HELLO
String to Lowercase
This routine converts all characters of a string to lowercase. It accepts the address
of the string. Hello becomes hello
BASE_ADDRESS + (ELEMENT_NUMBER *
NUMBER_OF_BYTES_PER_ELEMENT)
These types of instructions test the state of the various flags of the status register. All
variables are memory based. Any manipulation of variables normally involves three
steps,
Use eight bit registers for bytes/characters, and 16bit registers for integers. eg,
Letter := 'Y';
LDAA #'Y'
STAA Letter
The same principles apply to the various forms that expressions can take. eg,
IF X = 2 THEN Y := Y + 4 ELSE Z := 0;
if: LDAA X
CMPA #2
BNE else
LDAA Y
ADDA #4
STAA Y
JMP endif
else: LDAA #0
STAA Z
endif:
WHILE LOOPS
This involves the use of a conditional test at the entry of the while body, which
branches or jumps false to an endwhile label. The last statement in the while body
is a jump unconditional to the start of the while body.
1. Use a while label, comparison test
2. Branch false to an endwhile label
3. The last statement of the while body is a jump to the while label
while: ; comparison test
; branch false to endwhile
; while body statements
jmp while
endwhile:
WHILE X < 10 DO
BEGIN
Y := Y + X;
X := X + 1
END;
while: LDAA X
CMPA #10
BHI endwhile
LDAB X ; Y := Y + X
LDAA Y
ABA
STAA Y
LDAA X ; X := X + 1
ADDA #1
STAA X
JMP while
endwhile:
PREVIOUS RULES CONCERNING NEGATION ALSO APPLY. NOTE
THAT ALL PREVIOUS
FUNDAMENTALS OF STATEMENT ASSIGNMENT AND TESTING OF
VARIABLES AGAINST EACH
OTHER OR CONSTANTS ARE STILL BEING RIGIDLY APPLIED.
FOR NEXT LOOPS
1. Initialise the loop variable
2. Use a for label, Perform the comparison test with the final value
3. Branch false to an endfor label
4. Inside the for loop body, the last statement, should adjust the loop
variable, and use an unconditional branch back to the for label
initfor: ; initialise loop variable
for: ; comparison test
; jump false endfor
; for body statements
; adjust loop variable for next step jmp for
endfor:
FOR X := 1 to 10 do
BEGIN
Y := Y + X
END;
initfor: LDAA #1
STAA X
for: LDAA X
CMPA #10
BHI endfor
LDAB X ; Y := Y + X
LDAA Y
ABA
STAA Y
LDAA X ; NEXT X
ADDA #1
STAA X
JMP for
endfor:
PREVIOUS RULES CONCERNING NEGATION ALSO APPLY. NOTE
THAT ALL PREVIOUS
FUNDAMENTALS OF STATEMENT ASSIGNMENT AND TESTING OF
VARIABLES AGAINST EACH
OTHER OR CONSTANTS ARE STILL BEING RIGIDLY APPLIED.
1. The IF statement
In comparing the value of operands, consider the following example.
2.
3. IF X = 2 THEN Y = X
4.
The compare statement must be coded in such a way as to compare the value of X
against the constant 2. As the variable X is stored in memory, the programmer
should first load a register with the variable X before making the comparison
(because most processors do not support a compare between memory contents
and immediate data).This example gets coded as,
X: DFB 10
Y: DFB 00
....
LDAA X ; load A acc with value of X
CMPA #02 ; compare A acc with immediate data
BNE IF1 ; exit if false
LDAA X ; get value of X
STAA Y ; store value of X at variable Y
IF1: ..... ; next statement after if construct
IF X = Y THEN Y = 0
In this case, the code to be generated by the assembler for the compare statement
depends upon the addressing modes available. The options available are,
However, most processors do not support this. The most common option is the
comparison of a register variable against memory contents. This is coded as
follows,
This code can clearly be optimized (ie, some instructions can be removed without
affecting the original intent of the code). So far we have considered comparisons
for equality. The conditional branch instruction will vary depending upon what
type of comparison test is used. The following tables illustrate common
comparison tests and their associated conditional branch instructions.
+-----------------+-------------+--------------+
| Signed Operands | Branch True | Branch False |
+-----------------+-------------+--------------+
|r>m | BGT | BLE |
+-----------------+-------------+--------------+
| r >=m | BGE | BLT |
+-----------------+-------------+--------------+
|r=m | BEQ | BNE |
+-----------------+-------------+--------------+
| r <=m | BLE | BGT |
+-----------------+-------------+--------------+
|r<m | BLT | BGE |
+-----------------+-------------+--------------+
+-----------------+-------------+--------------+
|UnSigned Operands| Branch True | Branch False |
+-----------------+-------------+--------------+
|r>m | BHI | BLS |
+-----------------+-------------+--------------+
| r >=m | BCC | BCS |
+-----------------+-------------+--------------+
|r=m | BEQ | BNE |
+-----------------+-------------+--------------+
| r <=m | BLS | BHI |
+-----------------+-------------+--------------+
|r<m | BCS | BCC |
+-----------------+-------------+--------------+
+------+----------------+----------+
| 6802 | Flags Tested | 8088 |
+------+----------------+----------+
| BCC | C = 0 | JNB, JAE |
+------+----------------+----------+
| BCS | C = 1 | JB, JNAE |
+------+----------------+----------+
| BNE | Z = 0 | JNE, JNZ |
+------+----------------+----------+
| BEQ | Z = 1 | JE, JZ |
+------+----------------+----------+
| BPL | N = 0 | JNS |
+------+----------------+----------+
| BMI | N = 1 | JS |
+------+----------------+----------+
| BHI | C + Z = 0 | JNBE, JA |
+------+----------------+----------+
| BLS | C + Z = 1 | JBE, JNA |
+------+----------------+----------+
| BGE | N EOR V = 0 | JNL, JGE |
+------+----------------+----------+
| BLT | N EOR V = 1 | JL, JNGE |
+------+----------------+----------+
| BGT |Z + (N EOR V)= 0| JG, JNLE |
+------+----------------+----------+
| BLE |Z + (N EOR V)= 1| JLE,JNG |
+------+----------------+----------+
These tables are useful in determining the correct conditional instruction to use
for a particular comparison on specific data types. Coding the following statement
applicable to two unsigned 8bit data values
IF X <= Y THEN Y = 4
X: DFB 10H
Y: DFB 12H
IF: LDAA X
CMPA Y
BHI IF1
LDAA #04H
STAA Y
IF1: ....
X: DFB 00
Y: DFB 00
IF: LDAA X
CMPA #02D
BNE ELSE1
LDAA X
STAA Y
JMP IF1
ELSE1: LDAA Y
STAA X
IF1: ....
X: DFB 00H
Y: DFB 00H
DO1: LDAB X
CMPB #10D
BCC EXIT1 ; for signed use BLT
LDAA Y ; increment value of Y
ADDA #01
STAA Y
LDAA X ; increment value of X
ADDA #01
STAA X
JMP DO1
EXIT1: ...
Consider the coding of the following HLL program into 6802 assembler.
Program HLLTest();
var loop, val1, val2 : Byte;
Begin
val1 := 0;
val2 := 0;
loop := 0;
while loop <= 10 do
begin
val2 := val2 + loop;
loop := loop + 1
end;
if val1 < val2 then val1 := val2
else val2 := val1
end.
; HLLtest.asm
CPU 6802
HOF MOT
ORG 100h
loop: dfb 0
val1: dfb 0
val2: dfb 0
ORG 120h
Consider the entry from a keyboard of an integer value 276. This represents a three
character sequence of '2', '7' and '6'. This character sequence will need to be converted
into an appropriate 16bit value representing an integer. Also consider displaying the
value of a byte as two hex digits. Each nibble must be converted to an ASCII character
before displaying on the terminal screen.
GET DIGIT
MASK OFF HIGH NIBBLE
CONVERT TO ASCII
MASK OFF LOW NIBBLE
CONVERT TO ASCII
CPU 6802
HOF MOT
ORG 0100H
Val1: DFB 3FH
Result: DFS 02H
ORG 120H
Start:
LDAA Val1 ; get val1
PSHA ; save val1
ANDA #0F0H ; mask high byte
LSRA ; shift to low nibble
LSRA
LSRA
LSRA
JSR Conv ; convert high nibble
STAA Result ; store it
PULA
ANDA #0FH ; mask low nibble
JSR Conv ; convert low nibble
STAA Result+1 ; store it
Exit: BRA Exit
END Start
Get Digit
Subtract 30H from Digit
If Digit greater than Nine
Subtract 07H from Digit
EndIf
Shift into High Nibble and Store
Get Next Digit
Subtract 30H from Next Digit
If Next Digit greater than Nine
Subtract 07H from Next Digit
EndIf
OR Next Digit with stored High Nibble and Store
CPU 6802
HOF MOT
ORG 0100H
ASC1: DFB 33H
ASC2: DFB 46H
HexB: DFB 00H
ORG 120H
Start:
LDAA ASC1 ; get first digit
SUBA #30H
CMPA #09H
BLS If1
SUBA #07h
If1: ASLA
ASLA
ASLA
ASLA
STAA HexB
LDAA ASC2 ; get next digit
SUBA #30H
CMPA #09H
BLS If2
SUBA #07h
If2: ORAA HexB
STAA HexB
END Start
8BIT MULTIPLY
This routine multiplys two 8bit values together generating a 16bit result. The
following algorithm (for two unsigned 8bit values) is based on processors which
do not have MULTilpy instructions.
Set Product equal to Zero
Set Counter equal to Eight
While counter not equal to zero
Left Shift Product (Multiply by 2)
Shift Multiplier so bit goes into Carry
If Carry bit is Set
Product equals Product plus Multipicand
Endif
Subtract one from Counter
EndWhile
CPU 6802
HOF MOT
ORG 0100H
Val1: DFB 10H
Val2: DFB 20H
Result: DFS 02H
ORG 0120H
8BIT DIVIDE
This routine divides two 8bit values generating an 8bit quotient and 8bit
remainder.The following algorithm (for two unsigned 8bit values) is based on
processors which do not have DIVide instructions.
Set Quotient equal to Zero
Set Counter equal to Eight
While Counter not equal to zero
Left Shift Dividend (Multiply by 2)
Left Shift Quotient
If 8 MSB's of Dividend >= Divisor then
MSB of Dividend = MSB of Divident - Divisor
Add one to Quotient
EndIf
Subtract one from Counter
EndWhile
Remainder = MSB of Dividend
CPU 6802
HOF MOT
ORG 0100H
Val1: DFB 10H ; Dividend
Val2: DFB 20H ; Divisor
Quot: DFB 00H
Rem: DFB 00H
ORG 0120H
ASCII TO INTEGER
This routine converts an ASCII character string into a 16bit signed integer value.
To implement this routine, the following variables are used.
OFFSET DFB ;offset into ASCII string
BUFFER DFS ;space for ASCII string
BINV DFW ;integer result
BASE DFW ;base 10 value
CPU 6802
HOF MOT
ORG 0100H
Val1: DFB 00H
Val2: DFB 0AH ; multiply by 10 decimal
Result: DFS 02H ; result of Val1 * Val2
PackBCD:DFB 93H
DecVal: DFB 00H
ORG 0110H
CS and IP = instructions
DS, BX, SI= data
ES, BX, DI= extra data
SS, SP, BP= stack
In writing programs for modern processors like the 8088, the program is structured with a
minimum of three sections, called SEGMENTS. The three segments represent the
CODE, DATA and STACK areas of the program. Information within each segment is
accessed differently depending upon the segment type. To access data in the stack
segment requires the use of the SS, SP and or BP registers. The following diagrams
illustrates how information in the stack and data segments are accessed.
Special assembler directives are used to specify the different segments
SEGMENT DIRECTIVES
The following directives illustrate how to define the three basic segments for an 8088
assembly language program.
.STACK 100H
.DATA
.CODE
The value following the stack directive specifies the size of the stack segment.
The programmer is responsible for initializing the segment registers DS and ES to the
correct segments of the program. Failure to do so will result in a program which will not
access the data and extra data segments properly. The operating system will only
initialize the CS, SS, SP and IP registers.
The following code portion illustrates how to setup the data segment register. This is
performed at the beginning of the code segment.
.STACK 100H
.DATA
.CODE
MOV AX, @DATA ; initialize DS
MOV DS, AX
.186
.286
.386
.8087
.8086
RETURNING TO PCDOS
When an assembly language program running under PCDOS terminates, it must return to
the operating system so that the user shell program can be re-loaded. The correct format
is to use the following code sequence
EQUATES
The EQU directive creates absolute symbols and aliases by assigning an
expression or value to the declared variable name. Its format is,
name EQU expression
An absolute symbol represents a 16bit value; an alias is a name that represents
another symbol. The declared name must be unique, one that has not been
previously declared.
pi EQU 3.14159
clearax EQU xor ax,ax
The first example directs the assembler to replace every occurrence of the name
pi with the value 3.1459, whilst the second example instructs the assembler to
replace every occurrence of clearax with the instruction xor ax,ax
BYTE STORAGE
The DB directive allocates and initializes a byte (8bits) of storage for each
argument. Its format is,
name DB initialvalue,,,
value1 DB 16
form DB 6*2
text DB "Enter your name:"
In the first example, value1 is assigned a byte, and is initialized to 16, the second
example sets form equal to 12 and assigns it a byte, and in the last example, text
is defined as a sequence of bytes which each contain a character from the
specified string. The first byte will be initialized to 'E', whilst the last byte will be
initialized to a space character.
WORD STORAGE
The DW directive allocates a word (2bytes) of storage for each initialized value.
Its format is,
name DW initialvalue,,,
DW ?
mess DW 'ab'
The first example allocates one word of storage, but does not define its initial
value (?). The second example defines mess as a word initialized with the
character string 'ab'.
Strings when using the DW directive must not contain more than two characters.
The 'b' will be placed in the low-order byte, and the 'a' will be placed in the high
order byte. If only one character is specified, the high-order byte will contain
00H. The low-order byte appears FIRST for Intel Processors.
TITLE
The title directive specifies the program listing title.
TITLE Graphics
This appears at the top of each page in the assembler list file, after the source file
name.
NAME
The name directive is used to set the name of the current module. The module
name is used by the linker when displaying error messages. If no module name is
used, the linker will use the name specified using the title directive.
NAME Calculate_Gross
PAGE CONTROL
The PAGE directive can be used to designate the line length and width for the
program listing; normally used to generate a page break in the assembler listing
file.
When assembly is taking place, and the page directive is encountered, the
assembler generates a form-feed character to set a new page, and continues the
assembly on the new page. In this way, the programmer can organize a printout of
modules on a per page basis, so that the printout of more than one module per
page does not occur.
PROCEDURES
These directives are used to implement small procedures (modules).
name PROC codetype .... ret name
ENDP
The DQ directive defines a quad word [8bytes] of storage for double precision
floating point numbers.
The DT directive defines 10bytes of storage. This is normally used for Packed
BCD numbers and a 10 byte temporary real floating point value, as this storage
format is also used by the 80x87 arithmetic co-processor.
OFFSET
The offset directive returns the number of bytes a variable begins at, relative to
the start of the segment it is in. This is necessary when calling PCDOS routines.
.DATA
temp db 10
mess db 'Hi there','$'
.CODE
start: mov ax, @data
mov ds, ax
mov ah, 9h
mov dx, OFFSET mess ;1 byte in .DATA segment
int 21h ;print message
mov ax, 4c00h ;return to PCDOS
int 21h
END start
.stack 200h
.datamessage db 'Hello and welcome.'
db CR, LF, EOSTR
.code
print proc near
mov ah,9h ;PCDOS print function
int 21h
ret
print endp
$ TASM DOSCALL
Turbo Assembler V1.0 Copyright(c)1988 by Borland International
Assembling file: DOSCALL.ASM
Error messages: None
Warning messages: None
Remaining memory: 257k
$
This produces an object file named DOSCALL.OBJ which must be linked to create an
executable file which can run under PCDOS.
$ TLINK DOSCALL
Turbo LinkV2.0 Copyright (c) 1987, 1988 Borland International
$
$ DOSCALL
Hello and welcome.
$
MACROS
The macro directive allows the programmer to write a named block of source statements,
then use that name in the source file to represent the group of statements. During the
assembly phase, the assembler automatically replaces each occurrence of the macro name
with the statements in the macro definition.
Macros are expanded on every occurrence of the macro name, so they can increase the
length of the executable file if used repeatably. Procedures or subroutines take up less
space, but the increased overhead of saving and restoring addresses and parameters can
make them slower. In summary, the advantages and disadvantages of macros are,
Advantages
Disadvantages
In large programs, produce greater code size than procedures
MACRO DEFINITION
Defining Macros is done as follows,
Consider the following macro to return to PCDOS from an assembly language program.
TITLE dosmacro
.MODELsmall
exittodos MACRO mov ax,4C00h
int 21h
ENDM
.STACK 100h
.DATA
message DB 'Hello and Welcome', '$'
.CODE
start: mov ax, @data
mov ds, ax
mov ah, 9h
mov dx, OFFSET message
int 21h
exittodos
END start
When assembled, the macro is replaced and the internal representation of the file looks
like,
TITLE dosmacro
.MODELsmall
exittodos MACRO mov ax,4C00h
int 21h
ENDM
.STACK 100h
.DATA
message DB 'Hello and Welcome', '$'
.CODE
start: mov ax, @data
mov ds, ax
mov ah, 9h
mov dx, OFFSET message
int 21h
mov ax,4C00h
int 21h
END start
In this example a macro named addup is created. It accepts three parameters, ad1, ad2
and ad3. The code which follows, consisting of the mov statements, will be used to
replace every occurrence of the macro name addup in the source file. The macro is
terminated with the ENDM statement.Calling a macro with arguments is done as
follows,
This has the effect of loading the ax register with the contents of the bx register, the dx
register with the value 2, and the cx register with the value of count.
Macro definitions may include other macro names, and macros may also be recursive:
they can call themselves, eg,
This shows a recursive macro called pushall that continues to call itself until it
encounters a blank argument. In effect, it pushes the registers specified in the macro call
onto the stack.
The ;; indicates that the comment field of the macro should not be expanded with the
macro statements.
IMPLEMENTING FP NUMBERS, ARRAYS, RECORDS AND JUMP TABLES
FPnum1 DD 1.32740
BCD strings
The following example declares a packed BCD constant.
BCDval DT 123456
HANDLING ARRAYS
Arrays and array elements are dealt with using pointers. This involves either based or
indexed addressing.
Integer Arrays
Integer arrays occupy two bytes per element. A typical operation is to sum the contents of
an integer array. The following code for an 8086 shows this.
TITLE IntArray
.MODEL Large
.STACK 200h
.DATA
mess db 'The total is ','$'
result dw ?
IntArry dw 10, 34, 76, 25, 14, 9, 3, 22
IntAlen dw ($ - IntArry) / 2
buff db 6
dup( 20h ) db '$'
.CODE
Records (Structures)
Records in Pascal support the use of different sized field items. Consider the storage of
the following record.
The same record is implemented in assembly language by first defining its composition.
ex_rec STRUC
int_num dw
fp_num dd
lett db
ex_rec ENDS
The next step creates a record which has the composition of the previous records
definition.
Each field of the record is accessed in a similar method to that of Pascal, eg,
ex_rec.lett
accesses the lett field of the record ex_rec. The following program shows an
implementation for the 8088 processor.
TITLE Records
.MODEL Large
ex_rec STRUC
int_num dw
fp_num dd
mess db ""
ex_rec ENDS
.STACK 200h
.DATA
myrec ex_rec <22,1.30, "Hello there.$">
.CODE
start: mov ax, @data
mov ds, ax
mov dx, offset myrec.mess
mov ah, 9h
int 21h
mov ax,4c00h
int 21h
END start
Jump Tables
Jump tables are an efficient method of implementing switch/case type statements. A jump
table consists of an array of addresses. Using an offset into the array selects the address
of the routine which handles that particular value.
Jump tables are efficient, because it always take the same time to select any routine from
the table. The order may be re-arranged or new routines added simply be increasing the
size of the table.
TITLE Jump.asm
.MODEL Large
.STACK 200h
.DATA
help db 'This program exits when a function key is pressed.'
db 10, 13, 'Ctrl A generates underline.', 10, 13
db 'Ctrl B generates bold.', 10, 13
db 'Ctrl C generates blinking.', 10, 13
db 'All other control codes return to normal text.', 10, 13
db 10, 13, 'Start typing characters.', 10, 13, '$'attrib
db 07h ; screen attribute byte
; a table of addresses used to decipher recieve control codes
; each entry is the address of the appropriate routine
ctl_tbl label word
dw ctrl_null ;0
dw ctrla ; 1
dw ctrlb ; 2
dw ctrlc ; 3
dw ctrld ; 4
dw ctrle ; 5
dw ctrlf ; 6
dw ctrlg ; 7
dw ctrlh ; 8 10
dw ctrli ; 9 11
dw ctrlj ; a 12
dw ctrlk ; b 13
dw ctrll ; c 14
dw ctrlm ; d 15
dw ctrln ; e 16
dw ctrlo ; f 17
dw ctrlp ; 10 20
dw ctrlq ; 11 21
dw ctrlr ; 12 22
dw ctrls ; 13 23
dw ctrlt ; 14 24
dw ctrlu ; 15 25
dw ctrlv ; 16 26
dw ctrlw ; 17 27
dw ctrlx ; 18 30
dw ctrly ; 19 31
dw ctrlz ; 1a 32
dw ctrl_lbkt ; 1b 33
dw ctrl_bslash ; 1c 34
dw ctrl_rbkt ; 1d 35
dw ctrl_carat ; 1e 36
dw ctrl_ul ; 1f 37
.CODE
bumpcur proc far ; move cursor right one character
mov ah, 3
xor bh, bh
int 10h ; read int dh, dl
inc dl ; next column
cmp dl, 80 ; end of line?
jle short bpcur1
xor dl, dl ; go to start of next line
inc dh
cmp dh, 24 ; end of screen?
jl short bpcur1
mov ax, 0601h ; then scroll up
xor cx, cx
push dx
mov dh, 24
mov dl, 80
mov bh, [attrib]
int 10h
pop dx
mov dh, 24 ; position bottom
linebpcur1:
xor bh, bh ; set cursor position
mov ah, 2
int 10h
ret
bumpcur endp
PARAMETER PASSING
Parameter passing refers to the exchange of data between modules. There are many ways
this information can be exchanged.
Consider the following simple program which adds two numbers together, storing
the result. All data has been declared as common.
TITLE CommonData
.MODEL Large
.STACK 200h
.DATA
num1 dw 22
num2 dw 32
result dw 0
.CODE
addnum proc far
mov ax, [num1]
mov bx, [num2]
add ax, bx
mov [result], ax
ret
addnum endp
2. REGISTER VARIABLES
This technique involves passing and returning values using processor registers.
Routines must ensure that they do not corrupt any registers other than those which
have been specified. The programmer first determines which registers will be
used and which can be altered (contents destroyed).
TITLE CommonData
.MODEL Large
.STACK 200h
.DATA
num1 dw 22
num2 dw 32
result dw 0
.CODE
addnum proc far
; accepts num1 in ax, num2 in bx, returns result in dx
push ax
add ax, bx
mov dx, ax
pop ax
ret
addnum endp
The advantage is that only the calling module alters the data, whilst the module
addnum only works on copies of the data. In this way, it is easier to track which
modules affect the data variables.
3. STACK VARIABLES
Parameters may also be passed using the stack. This involves pushing the values
onto the stack before the module is called. This may also involve pushing space
onto the stack for a return result.
The module then accesses the parameters on the stack using the appropriate
addressing mode.
Upon return to the calling module, the stack space is deallocated using
appropriate pop or stack pointer adjustment instructions.
There are two ways in which data may be referenced using the stack.
1. Call by Value
This refers the placing of copies of the data value on the stack. Only the
copy is worked with, the original remains unmodified.
2. Call by Reference
This refers to the passing of the address of the variable using the stack.
This address is used to access the data, thus the original data is used.
Call by value is normally used for simple data types, whilst call by reference is
used for data types like arrays and records, because of the amount of memory
space they occupy (and stack space is normally limited).
Consider the following program for an MC6802 processor which uses Call by
Value to add two variables together.
CPU 6802
HOF MOT
ORG 100H
Num1: DFB 10
Num2: DFB 20
Result: DFB 0
push bp
It then transfers the address of SP into BP; BP now points to the top of the stack.
mov bp,sp
push bp
mov bp,sp
sub sp, n
instruction. This decrements the stack pointer by the number of bytes specified by n. For
example, a module might want to use temporary storage space for an integer i, which
equates to the machine code instruction
sub sp, 2
i = 24;
is equivalent to
The deallocation of any local variables (in our case the variable i) will occur with the
following code sequence,
The language pushes parameters (the values 10 and 20) right to left, thus the sequence of
statements which implement this are,
+---------+
| Return |<-- SP
+---------+
| address |
+---------+
| 00 | ;1st parameter, integer value 10
+---------+
| 0A |
+---------+
| 00 | ;2nd parameter, integer value 20
+---------+
| 14 |
+---------+
add_two: push bp
mov bp, sp
The stack frame now looks like (after those first two instructions inside add_two)
+---------+
| BPhigh |<-- BP <-- SP
+---------+
| BPlow |
+---------+
| Return |
+---------+
| address |
+---------+
| 0A | ;1st parameter, integer value 10
+---------+
| 00 |
+---------+
| 14 | ;2nd parameter, integer value 20
+---------+
| 00 |
+---------+
add sp, 4
where SP is adjusted upwards four bytes (ie, past the two integers).
The Pascal program will declare an integer based array, and pass the address of this array,
and the number of elements in the array, to an assembly language module.
Using the address, the assembly language module will add the sum of the array, returning
the result to the Pascal program.
TITLE Addup88
.MODEL TPASCAL
.CODE
PUBLIC Addup
Addup Proc Far Array : DWORD, Elements : WORD RETURNS Reslt :
WORD
push ds ; save ds register
push cx ; save cx register
push si ; save si register
lds si, Array ; point DS:SI to array element1
mov cx, Elements ; count of elements
xor ax, ax ; clear total
lp1: add ax, [si] ; add value to total
inc si ; next element
inc si
dec cx
jne lp1
pop si
pop cx
pop ds
RET ; exit to Pascal Module with
; result in AX
Addup ENDP
END
$TASM ADDUP88
begin
for loop:= 1 to 20 do
Numbers[loop] := loop;
Result := Addup( Numbers, 20 );
Writeln('The sum of the array is ', Result)
End.
When compiled under Turbo Pascal, the two object modules are linked together, creating
an executable file.
ASSEMBLER OPTIONS
Various options are supported by most assemblers. These options provide for
increase productivity
to check operation of assembler - macros, equates
to simplify control
provide flexibility
COMMAND FILES
Command files are text files which contain commands to the assembler.
$TASM @MYCMDFIL
will invoke the assembler using the options specified in the file Mycdfil. If this file
contained the following,
This simplifies the process of having to repeat all the command line options whilst the
program is being debugged.
The IF directives and the ENDIF and ELSE directives can be used to enclose the
statements to be considered for conditional assembly.
IF debug
xor ax,ax
ELSE
xor bx,bx
ENDIF
If the symbol debug equates to true (non-zero), the ax register will be cleared, otherwise
the bx register will be cleared.
The IFDEF and IFNDEF directives test whether or not the given variable name/symbol
has been defined.
IFDEF buffer
buf1 DB 10 DUP(?)
ENDIF
In this example, buf1 is allocated only if buffer has previously been defined. It consists
of ten bytes whose initial value is undefined.
The programmer adds these definitions to the source file using the include directive, and
may remove unwanted definitions using the purge directive.
The include directive inserts the definitions or code statements from the specified file
into the current source file during assembly, and allows any variables or declarations in
the include file to be referenced or accessed in the source program being written.
INCLUDE entry
INCLUDE b:\include\c_stuff
LIST FILES
List files have already been covered under section 6 dealing with CRS8.
The following 8088 assembler directives can disable and enable the output listing.
%NOLIST
%LIST
$TASM /l /n Doscall;
It generates a listing file. The list file for the program looks like,
SYMBOLIC INFORMATION
Symbolic information is useful in determining the size and location of variables,
segments etc. This information is used when debugging the program or locating the
program in Eprom.
When the previous program Doscall.asm is assembled with a list file and symbol plus
cross-referencing, the additional information appended to the list file is,
This also shows which lines variables and labels were defined and referenced.
MAKE
This utility is designed to ease updating of programs, especially multiple module
programs.
Each object file is generated from an assembler source file of the same name.
tasm start
tasm search
tasm fileio
tasm keybdio
tasm videoio
tlink start search fileio keybdio videio, mydbase;
The dependencies and command sequences required are entered into the makefile as
follows.
mydbase.exe: start.obj search.obj fileio.obj keybdio.obj videoio.obj
tlink start search fileio keybdio videio, mydbase;
start.obj: start.asm
tasm start
search.obj: search.asm
tasm search
fileio.obj: fileio.asm
tasm fileio
keybdio.obj: keybdio.asm
tasm keybdio
videoio.obj: videoio.asm
tasm videio
make
It works by comparing date and time stamps of the files in each dependency list. Consider
the lines
keybdio.obj: keybdio.asm
tasm keybdio
It compares the date/time stamp of keybdio.asm against keybdio.obj. If the object file is
newer than the assembly file, it will not re-assemble.
If the assembler file has a newer date/time stamp, it will execute the command tasm
keybdio to generate a new object file.
The use of make files simplifies the re-assembly by only assembling those files which
have been modified.
Previous revisions can be extracted from the database, and a printout detailing the
changes (time, who, line#) can be obtained.
LIBRARY MAINTENANCE
This applies to the maintenance of OBJECT code libraries.
An Object code library contains routines which can be reused in any program. The code
for the routine is extracted from the library and combined with the users object code at
linking time.
Users can create their own library routines. The source files are assembled into object
code then added to a library.
The following code represents a routine for placement into a Video routines library.
TITLE SetCur
.CODE
PUBLIC setcur
After assembling into Object code, the object code is placed into a video library using the
TLIB utility.
The following source file shows how to use the code in a library.
TITLE Libdemo
.STACK 200h
.CODE
EXTRN setcur:far
start: mov dx, 0 ; cursor 0,0
call setcur
mov ax, 4c00h
int 21h
END start
After assembling the file Libdemo.asm, the command to link the object and library code
together is,
TLINK Libdemo,libdemo.exe,libdemo.map, video
LINKERS
The assembler for 8088 PCDOS programs generates object code files. These cannot be
executed directly on the computer system, but require further processing in order to
generate a runfile. This further process is called the linking phase.
The map file generated by the linker for the program DOSCALL.ASM is,
Relocatable/Relative
The code generated by the linker is all relative to the location counter. This means
that all references to memory is relative to a base/index register, segment register
or program counter. This allows the operating system to load the program
anywhere in physical memory.
Absolute/Fixed
If the linker generates code which is absolute, all memory references are to
absolute addresses, thus the program must reside in a designated memory space. If
this space is unavailable, the program cannot be run and must wait.
Absolute code is normally used on small single processor systems (ie, CPM), and
is not suitable for multi-user environments.
Absolute code does not contain a header file used for relocation, if a header file
exists, it will specify the absolute load address of the code which follows the
header file.
Common
Variables, labels or symbols may be designated as common. In this way, they are
made accessible to those modules which wish to reference them by way of calls or
data usage. The common data is shared by the various modules.
External/Public
Public data segments are located in one module but called from another.
The Public directive makes the variable, label or symbol in the current segment
available to all other modules. It thus transforms locally defined symbols into
global symbols.
The Extern directive makes a global symbols name and type known in a source
file so that it may be used/referenced in that file. An extern item is a variable,
label or symbol that has been declared using the public directive in another
module of the program.
Main Module
NAME main
.MODEL small
PUBLIC exit ;defines exit as being known to other modules
EXTERN print:near ;defines print as existing in another module
.STACK 100h
.DATA
.CODE
start: mov ax, @data ; Load segment location
mov ds, ax ; into DS register
jmp print ; goto PRINT in other module
exit: mov ax, 4C00h ; call terminate function
int 21h
END start
Task Module
NAME task
.MODEL small
PUBLIC print ;defines print as public so it can
;be used by the calling module
EXTERN exit:near ;defines exit as existing in another module
; outside this one
.DATA
string DB "Hello",13,10,"$"
.CODE
print: mov dx, OFFSET string ;Load location of string
mov ah, 09h ;call string display function
int 21h
jmp exit ;go back to main module
END
In this example, the symbol exit is declared public in the main module so that it
can be accessed from another source module (task).
The main module also contains an external declaration of the symbol print. This
declaration defines print to be a near label so that it can be accessed from the
module main, even though it is assumed to be located and declared public in
another source module.
A jmp instruction later in main has the label print as its destination.
The symbol print is declared public in the task module so that it may be accessed
from another module (main).
The symbol exit is defined as a near label so that it can be accessed from this
module, even though it is assumed to be located and declared public in the other
module.
Before this program can be executed, the two source files (one containing main,
the other task) must be assembled individually, then linked together using a
linker.
The symbol listing for each source file shows the segment allocations.
The map listing form the linker clearly shows how these segments have been
combined.
The use of the segment directives provide the necessary controls for implementing large
multiple segment programs. The programmer can specify which segments should be
overlayed, combined, or stand alone.
obtains data from the code segment rather than the data segment.
Align specifies whether the segment starts at a byte, word or paragraph (10 byte)
boundary. The default is paragraph.
COMMON The linker locates all segments with the same name
at the same address (overlayed on top of each
other). The length becomes the longest segment.
Class controls the ordering of the segments at linking time. Segments with the same class
name are loaded together. A segment of class CODE would be loaded before a segment
of class STACK. The class name is enclosed using single or double quotes.
TITLE Segdemo
stck segment para private 'STACK'
db 200h dup (?)
stck ends
assume ds:data2
mov ax, seg data2
mov ds, ax
mov ah, 9
mov dx, offset message2
int 21h
mov ax, 4c00h
int 21h
code ends
end start
This clearly shows the ordering (class) and concatenation of segments which are the same
type.
Translation is an activity comprising the interpretation of the meaning of a text in one language—
the source text—and the production of a new, equivalent text in another language—called the
target text, or the translation.