7.13. NURVE

7.13.1. INTRODUCTION

The NURVE (New University of Regina Virtual Education) machine and assembler is a software package that provides a machine independent environment for learning assembly and machine language programming. The NURVE virtual machine architecture is similar to 'real' micro-computer organizations.

7.13.1.1. NURVE ARCHITECTURE

a

7.13.1.2. CENTRAL PROCESSING UNIT

The Central Processing Unit (CPU) decodes and executes instructions fetched from memory. These instructions direct the operation of the computer. Instructions other than input/output (I/O) instructions are executed by the CPU. I/O instructions are handled by the appropriate I/O sub-unit. The NURVE CPU has 32 bit architecture. The memory is byte addressable. Byte (8 bits), half-word (16 bits) and word (32 bits) accesses to memory are possible. A suffix to the instruction mnemonic is used to select the correct addressing.

7.13.1.2.1. REGISTERS

Registers are very fast storage locations in the CPU. There are sixteen registers of 32 bit width, labeled R0, R1, ... R9, RA, RB, RC, RD, RE, and RF; the letters A, B, C, D, E, and F are the hexadecimal (hex) representations for the values: 10, 11, 12, 13, 14, and 15.

The general purpose registers, R0 to RA, can be used to hold any data.

The Base Register (BR), register RB, containing the address of the top of the user memory area, is set by the operating system and cannot be changed by the user. The BR is added to any virtual user memory address to form the actual or physical address.

The Program Counter (PC), register RC, points at the next instruction to be executed. Thus, the PC contains the virtual address of the word containing the next instruction to be executed.

The Stack Pointer (SP), register RD, points at the bottom of the user data stack area. The operating system initializes the SP to the hexadecimal value 7FFF.

The Instruction Register (IR), register RF, contains a copy of the current instruction being executed by the CPU.

The Processor Status (PS) Register, register RE, is used to store a program's condition codes. Each condition code is usually set after each instruction executes and produces a result. The condition codes, the low order eight bits of the PS register, are named I, A, S, T, N, Z, V, and C. The PS bits are usually used to determine selective branching.

Condition Code       Mask   Set                     Cleared                 
Interrupt        I    80    1 = Interrupts          0 = Interrupts          
                            enabled.                disabled.               
Addressing       A    40    1 = Relative            0 = Absolute            
                            addressing.             addressing.             
Supervisor       S    20    1 = Supervisor mode.    0 = User mode.          
Trace            T    10    1 = Trace enabled.      0 = Trace disabled.     
Negative         N    08    1 = Result is           0 = Non negative.       
                            negative.                                       
Zero             Z    04    1 = Result is zero.     0 = Non zero.           
Overflow         V    02    1 = Overflow resulted.  0 = No overflow.        
Carry            C     01   1 = Carry from MSB.     0 = No carry.           

Processor Status (PS) Register Bits

We will be using only the N, Z, V and C flags. The flags are set when data movement or arithmetic operations are performed on the datum in any register or memory. Look at the values for the N, Z, V and C flags in the 'Mask' in the preceding table. Notice that if you converted the mask to its binary equivalent, only one bit is set. e.g. the hex value 08 corresponds to the binary value 1000 - only one bit set. This bit corresponds to the flag that is currently set.

N Z V C

1 0 0 0 <- hex value 08 means the N bit is set (negative)

0 1 0 0 <- hex value 04 - the Z flag (zero)

0 0 1 0 <- hex value 02 - the V flag (overflow)

0 0 0 1 <- hex value 01 - the C flag (carry)

The following programs (Program 7.13.1.1.1 to 7.13.1.1.4) set the individual flags. Compile, link and execute each of the following programs. When executing, use the option to produce a core dump at the end of the execution. In the core dump, notice the value of the PS register.

From the hexadecimal value of the PS register you will be able to see which flag(s) is/are set. All the flags that we are interested in are in the least significant nibble (4 bits) of the PS register, so ignore all but the least significant hex digit of the PS register value.

The comments in each of the programs will help you understand the working of the program.

All the programs in this manual can be obtained via anonymous ftp from ftp.cs.uregina.ca. Refer to Appendix A in this manual to see an example of how to obtain a file.

Sample program to set the N bit in the Processor Status register:

;=========================================================================

; Filename: 7.13.1.2.1.asm

; Author: Christian, Burt Berel. S.

; Student #: 123 456 789

;

; Purpose: to set the processor status word negative flag.

;

;=========================================================================

.CODE ; Code Segment.

code:

clr r0 ; Initialize.

dec r0, r0 ; Generate a negative result.

halt

.END

As stated previously: after you compile and link these programs use the option to produce a core dump at the end of the execution. In the core dump, notice the value of the PS register. From the hexadecimal value of the PS register you will be able to see which flag(s) is/are set.

Example:

hercules[2]% nurve 7.13.2.1.asm [Return]

Nurve: completed with 0 errors and 0 warnings

hercules[3]% nlink 7.13.2.1.obj [Return]

hercules[6]% nload -c 7.13.2.1.lmn [Return]

Nload: End of Execution.

Execution terminated. PC = 0000000C. 2 instructions executed.

NURVE CORE DUMP (Hex)

----- ---- ---- -----

Code Segment PCB Heap Stack Stack Top

00000000 00000400 00000480 00000880 00000C80

R0 R1 R2 R3 R4 R5 R6 R7

FFFFFFFF 00000000 00000000 00000000 00000000 00000000 00000000 00000000

R8 R9 RA BR PC SP PS IR

00000000 00000000 00000000 41A0E400 0000000C 00000C80 00000108 00000000

ADDR OFFSET 0 04 08 0C 10 14 18 1C

----| -------- -------- -------- -------- -------- -------- -------- --------

0000| 1D000000 3A000000 00000000 00000000 00000000 00000000 00000000 00000000

...

hercules[7]%

From this dump, we see that the PS (Processor Status) register is set to the value 00000108. All the flags that we are interested in are in the least significant nibble of the PS register, so ignore all but the least significant hex digit of the PS register value. In this case it is the value "8" that we are interested in. Remember that hex value 08 means the N bit is set..

Following, are other programs that will allow you to examine other flags in the processor status word.

;=========================================================================

; Filename: 7.13.1.2.2.asm

; Author: Christian, Burt Berel. S.

; Student #: 123 456 789

;

; Purpose: to set the processor status word zero flag.

;

;=========================================================================

.CODE ; Code Segment.

code:

clr r0 ; Generate a zero result.

halt

.END

;=========================================================================; Filename: 7.13.1.2.3.asm

; Author: Christian, Burt Berel. S.

; Student #: 123 456 789

;

; Purpose: to set the processor status word overflow flag.

;

;=========================================================================

.CODE ; Code Segment.

code:

mov #07fffffff, r0

inc r0, r0 ; Generate an overflow.

; This operation not only generates an overflow, but

; also sets the negative flag so we turn it off. This will

; let us see only the overflow flag in the core dump.

clp.n ; There.

halt

.END

;=========================================================================; Filename: 7.13.1.2.4.asm

; Author: Christian, Burt Berel. S.

; Student #: 123 456 789

;

; Purpose: to set the processor status word carry flag.

;

;=========================================================================

.CODE ; Code Segment.

code:

clr r0

dec r0, r0

rot #01, r0, r0 ; Generate a carry.

; This operation not only sets the carry, but

; also sets the negative flag so we turn it off. This will

; let us see only the carry flag in the core dump.

clp.n ; There.

halt

.END

These simple examples show how to set a specific condition code bit in the Processor Status register. More generally, an instruction is used to examine a particular value, causing one of the condition code bits to be set. Then a branch instruction directs program flow depending on the value in the condition codes.

You will see an example of this when you get to the program in section 7.13.3.2 of this manual. For now, be aware that some instructions cause condition code bits to be set and that there are branch instructions that depend on values in the PS.


7.13.1.2.2. ARITHMETIC LOGIC UNIT

The arithmetic logic unit (ALU) performs all arithmetic (add, subtract, multiply, divide) and logic (and, or, xor) operations. The source and destination operands of an instruction can be a CPU register or a memory location (within the user memory area). The following illustration is extracted from the NURVE architecture diagram:

NURVE uses two's complement arithmetic. The sign bit, used to indicate the sign of a value being stored, is the most significant bit (MSB) and is also called the high order bit. This bit is set to one when the value is negative and cleared to zero when the value is positive.

In two's complement arithmetic, the negative representation of a positive number, P, is obtained by adding 1 to the one's complement of P. The one's complement of P is obtained by flipping each bit in P (change zero's to one's and one's to zero's). Thus, the two's complement of the value one, is a word (or byte or halfword) where all the bits are set to one.

The maximum integer (the largest positive integer value that can be stored), in hex notation, is: 0x7F for a byte, 0x7FFF for a half-word, and 0x7FFFFFFF for a word.

When a byte is copied into a halfword (or a halfword is copied into a word), its sign bit is copied into the whole high order byte (or halfword). This is called sign extension. In NURVE, there will always be sign extension on byte/halfword operations when the destination is a register. There is no sign extension if the destination is the stack.

7.13.1.3. MEMORY

The NURVE machine memory is composed of a sequence of words divided into blocks. Some blocks, such as the I/O buffers, are reserved by the operating system and others are allocated to individual users. Each word of memory is accessed by a unique address and can contain either an instruction or datum. The differentiation between data and instructions is made at execution time by how the word is used.

Each 32 bit NURVE word can be divided into two halfwords (16 bits each), or four bytes (8 bits each), or eight nibbles (4 bits each). An instruction takes up a full word, but each byte is addressable.

A 32 bit NURVE word

Each user is allocated a 32K block of NURVE's memory space that is accessed by a virtual address, numbered sequentially from hex 0 to 7FFF. A virtual address is converted into a physical address by adding the Base Register (see "Registers") to the virtual address.

User programs are loaded at virtual address 0 followed by a process control block (PCB). The PCB is used by the operating system to save CPU registers during a context switch. A context switch is when a multi-tasking operating system takes back control of the CPU from an executing user process. A multi-tasking operating system shares a single CPU between several different processes executing concurrently.

During execution, the code segment and PCB areas are treated as read only memory by the operating system. The heap and the stack are two data areas at the bottom of the user memory area and expand towards each other.

A user area memory map (extracted from the NURVE Architecture diagram is shown next.

Memory Map

7.13.1.4. FETCH/EXECUTE CYCLE

The fetch/execute cycle is the process within the CPU control unit that executes a program residing in memory. When a program is loaded into the user memory area, the PC is set to 0. The CPU repeatedly loads the IR with the instruction pointed to by the PC and increments the PC (by 4) before the instruction in the IR is decoded and executed.

ALGORITHM: FETCH/EXECUTE CYCLE

SET PC to 0

REPEAT

SET IR to contents of word pointed to by PC

ADD 4 to PC

EXIT LOOP if IR is 0 (HALT instruction)

DECODE & EXECUTE instruction in IR

UNTIL IR is 0

END FETCH/EXECUTE CYCLE

7.13.1.5. INPUT/OUTPUT UNITS

The input/output units are the communication media between the NURVE machine and external devices, such as disk drives, keyboards or printers. NURVE does not provide any specific I/O instructions. I/O is performed through calls provided by the operating system (system calls) . Each I/O unit is connected to NURVE via the communication bus.

The next section of the manual describes the general format of machine language instructions.

Opcodes and the specific format of operands are discussed in detail in the following sections.

7.13.2. MACHINE LANGUAGE

7.13.2.1. INTRODUCTION

The NURVE machine only executes machine language instructions. Each NURVE operation is given a specific hex numeric code called an operation code or opcode. Opcodes perform operations on data called operands. Operands are classified as either source (src) operands that identify input data to an operation, or destination (dest) operands that determines where results are stored. A word containing an instruction is partitioned in one of the following ways:

Opcode

No operand instruction word

Opcode Dest

Single Operand instruction word

Opcode SrcA Dest

Double operand instruction word

Opcode SrcA SrcB Dest

Triple operand instruction word

Opcode Address

Jump instruction word

7.13.2.2. MACHINE LANGUAGE FORMAT

A machine language statement consists of three fields:

ADDRESS CONTENTS ;COMMENT

The machine language equivalent program of the Program 7.13.1.1.1 is shown below.

0000 1D000000 ; CLR r0 ; Initialize.

0004 3A000000 ; DEC r0, r0 ; Generate a negative result.

0008 00000000 ; HALT

Machine language programs require the address as well as the contents of each memory location to be specified for every instruction and datum. An optional comment field can be included after the address and contents fields.

Each statement must be on a single line. Continuation over more than one line is not allowed. The maximum length of a line is 80 characters. The common format of programs is:

columns 1-4 memory addresses

columns 8-13 memory contents

columns 15-80 comments

Looking at the first line in the preceding example:

address memory contents <- comments ->

0000 1D000000 ; CLR r0 ; Initialize.

7.13.2.2.1. ADDRESS FIELD

The four hex digit address field specifies the location in memory where an instruction or datum is placed. In the following line from the preceding program we can see that the address field is 0000 which means that in this line is specified the contents of the memory word beginning at 0000.

0000 1D000000 ; CLR r0 ; Initialize.

7.13.2.2.2. CONTENTS FIELD

The eight hex digit contents field contains an instructions or datum. Hex numbers are in the range from 00000000 to FFFFFFFF. An instruction consists of a valid opcode and its required operands. (Refer to the "Instruction Set" section of this document). In the line referred to earlier, the second field, 1D000000 represents the contents of the word beginning at address 0000. 1D000000 is the machine language equivalent or the opcode for the instruction CLR r0.

0000 1D000000 ; CLR r0 ; Initialize.

7.13.2.2.3. COMMENT FIELD

Comments are optional and do not affect the execution of a program. They make programs easier to read and simplify the debugging process. They also increase the possibility of getting a good mark on your assignment! It should be noted that some class instructors and lab instructors have been known to refuse to look at programs without adequate documentation. (i.e. comments).

The comments should not simply translate the machine code into words but attempt to explain the underlying logic. For example:

0020 3D000102 ;Move R1 to R2

is not adequate documentation and will not be considered as a comment. It aids little in the understanding of the program. The preceding comment could be rewritten as:

0020 3D000102 ;Save SUM (R1) into GROSS PAY (R2)

The second comment greatly enhances the readability of the code and the level of understanding obtained by the people who read your programs. (i.e. markers, consultants, lab instructors, yourself, etc.).

A comment can also be placed on a line by itself by simply preceding it with a semicolon ';'.

7.13.3. ASSEMBLY LANGUAGE

7.13.3.1. INTRODUCTION

Machine language programming is tedious as programs are difficult to read and require the memorization of numeric opcodes. However, the major difficulty with machine language programming is its inflexibility. When an error is found in a machine language program, new instructions need to be inserted in the program to correct it. To insert new instructions between the extant instructions, the addresses following the inserted instruction must be modified, because each instruction in machine language is associated with a particular memory location. This can lead to serious loss in productivity when frequent changes requiring address changes are to be made not only because it is tedious to do but is highly error-prone by itself.

Assembly Language overcomes these problems by using mnemonic opcodes in place of numeric opcodes to aid readability, and symbolic labels in place of machine addresses to aid modifiability.

An assembler translates each assembly language instruction into its corresponding machine language by translating mnemonic opcodes into numeric opcodes, and binding symbolic labels to actual memory locations.

An assembly language program does not require any more or any fewer actual instructions than its machine language translation. There is a one to one correspondence between each assembly and machine language instruction.

7.13.3.2. ASSEMBLY LANGUAGE FORMAT

A NURVE assembly language statement consists of three fields:

LABEL: INSTRUCTION ; COMMENT

Each statement must be on a single line.

Each of the label, instruction and comment fields is optional.

Continuation across lines is not allowed.

The maximum line length is 80 characters.

Program 7.13.3.1.asm, shown as follows, illustrates a simple assembly language program.

;=========================================================================; Filename: 7.13.3.1.asm

; Author: Christian, Burt Berel. S.

; Student #: 123 456 789

;

; Purpose: Add 10 numbers stored in an array.

;

;=========================================================================

; Pseudo code.

; Let pointer (r3) point to the beginning of the array.

; Let counter (r4) = 10

; Let sum (r5) = 0

; While (counter <> 0)

; Let sum = sum + number pointed to by r3

; Increment the pointer r3

; Let counter = counter - 1

; End

;___________________________________________________________________

.CODE

start:

mov.w #array,r3 ;Register r3 is the pointer

; to the array elements.

mov.w #0a,r4 ;Register r4 is a down counter

; starting at 10 (decimal).

clr.w r5 ;Register r5 will accumulate the

; sum of 10 numbers.

loop: ; Repeat

add.w @r3+, r5, r5; Add the number pointed to by r3

; to running total in r5

dec.w r4, r4 ; Decrement the counter.

tst.w r4 ;

jne @#loop ; until counter is zero

halt ;

.DATA

array: ; Data items for the 10 element array.

.init.w 1

.init.w 3

.init.w 5

.init.w 7

.init.w 9

.init.w b

.init.w d

.init.w f

.init.w 17

.init.w 19

.END


7.13.3.2.1. LABEL FIELD

Assembly language uses symbolic labels instead of actual memory addresses. The first character must be alphabetic, the other characters may be alphanumeric. For example, X, M2, R2D2, AABCD, K123, and HELPME, are all valid labels. Program readability is enhanced by using meaningful label names. The label field is optional, but if present, it must appear before the instruction field and must be immediately followed by a colon. For example, notice that the preceding program begins with the label start.

start:

Only statements referenced elsewhere by the program require symbolic labels. In the above example program start is not referenced anywhere but serves the useful purpose of labeling the entry point of the program.

Locations used to hold data (variables and constants) are also often given labels. The assembler assigns each label the value of the address of the memory location where the label is found. Notice that the array is labeled in the data segment at the end of the preceding program.

7.13.3.2.2. INSTRUCTION FIELD

The optional instruction field may be either

1) a mnemonic instruction described in the Instructions Section or

2) an assembler directive described in the Assembler Directives Section.

The instruction field contains an opcode and any operands when applicable.

The following are both two-operand instructions.

mov.w #array,r3

mov.w #0a,r4

Assembler directives are intended to convey information to the assembler and do not produce any code. In the preceding example, .CODE and .DATA are assembler directives. The former directs the assembler to put the subsequent instructions in the code area of the memory. This area of the memory is also referred to as the code segment. Everything following a .CODE directive and before any .DATA directive will be loaded into the code segment at execution time. Everything following a .DATA directive and before a .CODE directive is placed into the data segment. A NURVE source program can have any number of .CODE and .DATA directives.

All numbers in a NURVE source are assumed to be in hexadecimal representation. They must always begin with a zero.

7.13.3.2.3. COMMENT FIELD

Comments are optional and do not affect assembly processing or program execution. A comment must begin with a semicolon. It may be preceded by a label and an instruction. (See "Comment Field" in Machine Language). Notice the use of indentation in the comments in the preceding program. Since indenting the assembly language instructions is usually not a good idea, it is helpful to indent the comments to emphasize the scope of the control structures. Also notice that obvious comments are avoided in the preceding program.

7.13.3.2.4. ASSEMBLY DOCUMENTATION

There is a danger in documenting an assembly language program, of over-documentation. This is largely because assembly language is so low-level; there are no formal constructs for if/then/else statements or looping. In a higher level language, vertical alignment and indentation are used to make the code readable. For example:

IF condition THEN

do this

and this

ELSE

do this

and this

This type of self-documentation does not translate to assembly language because the higher level constructs do not exist. For example, a single 'if' statement is composed of a compare statement, a conditional branch or jump statement, and then the line(s) of code that are to be performed in the case that the 'if' condition is met. The danger in placing comments beside each assembler statement is that the program becomes so cluttered, that the function of a series of statements becomes lost to the reader.

The solution to this problem is to use vertical alignment and indentation in your comments. Instead of attempting to comment each line of code, place comments beside blocks of code so that your comments look like a high level language or pseudo-code. Pick a standard you like and try to follow its structure throughout your comments. Be consistent!

For example:

cmp.b R0, #41 ; if (input_char = 'a')

jne other

jsub aroute ; process for 'a' input

jump next

other: ; else

jsub alt ; process for other input

next:

Use blank lines to improve readability. Also, white space (blanks and tabs) may be inserted anywhere in a statement to improve readability and neatness of a program provided it is not embedded within symbols or numbers. Notice the way the preceding program is neatly laid out in columnar fashion. Easy readability is very important in developing assembly language programs.

Use meaningful names in your comments, e.g.: "input_char" is better than R0

Do include a reasonable number of extra comments in your code; program headers are mandatory, but you might also wish to add some explanatory comments before particularly complex sections of code.

Do not clutter up a program with too many comments; a comment for each line of code is often not always necessary in an assembly language program.

Program header - a program should begin with a block of comments which includes the following information:

;=========================================================

; Filename: rootsearch.asm

; Author: your name

; Student #: 123 456 789

;

; Purpose: include a brief explanation of the purpose of the program

;

;==========================================================

A sample header file, header.asm, can be obtained from FTP - refer to Appendix A for an explanation of how to obtain a file from FTP and then include the file in your program.

For lab assignments: Documentation and comments will not normally be required - this is only because of time constraints. Also, you do not need to include rigorous error checking in a lab assignment, unless this is specified in the assignment sheet.

7.13.4. EXECUTION

The machine language output from an assembler is called an object module. A linker joins one or more object modules to produce an executable load module, also called an executable. System calls (I/O routines) from a system library are included in a user program by the linker (see getc and putc). A loader places a load module in a machine's memory and executes it.

Assembling, linking and running a program. ('file' is the name of a file.)

7.13.4.1. ASSEMBLING A PROGRAM

An assembly language program is converted into machine language (assembled) by the NURVE assembler. The command for assembling is:

nurve filename.asm

where filename is the name of an assembly language program. The extension asm is assumed. The assembler produces a file named filename.obj, which contains the machine language translation of the source code, along with the assembler mnemonics as comments, and any errors that were detected. For example to assemble a file named test.asm, and produce a file named test.obj:

nurve test [Return]

7.13.4.2. LINKING A PROGRAM

If no errors were detected during assembly, the object file filename.obj can be linked to produce the load module named filename.lmn, using the command:

nlink filename.obj

7.13.4.3. EXECUTING A PROGRAM

The NURVE loader places a load module into memory and executes it starting at location 0000. The command for executing a NURVE load module is:

nload [-ctv] [-h=heapsize] [-s=stacksize] [-i=maxinstr] [-o=outfile] filename[.extension]

where:

nload - Command keyword to start the executing a program.

filename - The name of the executable load module. The filename should have a file type of 'lmn'.

extension - Filetype of executable. If omitted, an extension lmn is assumed.

[] - Signifies that the characters within are OPTIONAL. The square brackets are NOT to be typed in.

- - Signifies that the characters following the '-' are flags. The flags change the type and amount of output generated while your program executes. They do NOT affect the output generated from within a user program.

c - Causes a core dump to be printed at the end of the output file when the program stops executing.

t - Traces the step by step execution of each machine language instruction.

v - Verbose mode. Provides more detailed information than a trace.

h=heapsize - Sets the size of the heap area. Heapsize is a hexadecimal value.

s=stacksize - Sets the size of the user stack area. Stacksize is a hexadecimal value.

i=maxinstr - Sets the maximum number of instructions to execute before the program halts. Maxinstr is a hexadecimal value.

o=outfile - Name of the output file. (Defaults to the standard output device.)

Examples of executing NURVE programs, in a file called 'test.lmn':

nload test [Return]

output goes to the standard output device (the user terminal).

nload -c test [Return]

output goes to the standard output device (the user terminal). A core dump follows the output.

nload -tc -o=test.lis test.lmn [Return]

output goes to a file called 'test.lis'. A trace is printed to the screen and to 'test.lis' and a core dump is printed at the bottom of the file.

7.13.5. INSTRUCTION SET

Instructions are classified as one of: No Operand, Single Operand, Jump Instruction, Double Operand, or Triple Operand. This section lists each instruction showing the hexadecimal opcode, assembler mnemonic, and the instruction format. A more detailed description of each instruction is found in Appendix B.

Let us first look more closely at the complete program presented before in this manual. Hopefully, this will provide some familiarity with assembler instructions, before we examine all instructions in detail.

;=========================================================================

; Filename: 7.13.3.1.asm

; Author: Christian, Burt Berel. S.

; Student #: 123 456 789

;

; Purpose: Add 10 numbers stored in an array.

;

;=========================================================================

; Pseudo code.

; Let pointer (r3) point to the beginning of the array.

; Let counter (r4) = 10

; Let sum (r5) = 0

; While (counter <> 0)

; Let sum = sum + number pointed to by r3

; Increment the pointer r3

; Let counter = counter - 1

; End

;______________________________________________________________

.CODE

mov.w #array, r3 ; Register 3 is the pointer to the array elements.

mov.w #0a, r4 ; Register 4 is a down counter starting

; at 10 (decimal).

clr.w r5 ; Register 5 will accumulate the sum of 10 numbers.

loop: ; Repeat

add.w @r3+, r5, r5; Add the number pointed to by r3

; to running total in r5

dec.w r4, r4 ; Decrement the counter.

tst.w r4 ;

jne @#loop ; until counter is zero

halt ;

.DATA

array: ; Data items for the 10 element array.

.init.w 1

.init.w 3

.init.w 5

.init.w 7

.init.w 9

.init.w b

.init.w d

.init.w f

.init.w 17

.init.w 19

.END

Notice the .CODE and .DATA directives that separate the code and data portions of the program.

The first instruction - mov.w #array, r3 -puts the address of the array in register r3. The meanings of the non-alphanumeric characters (such as '@' and '#') will be explained later in the section on addressing modes.

The next instruction - mov.w #0a, r4 - initializes the down counter with 0A hex or 10 decimal.

Next, - clr.w r5 - the register r5,which will accumulate the sum of the ten numbers, is initialized to zero.

The label in the next line - loop: - will be associated with the address at which the `add' instruction in the next line will be stored.

The `add' instruction - add.w @r3+, r5, r5 - takes the value pointed to by the register r3, adds to the current contents of register r5 and stores back the result in register r5 - thus maintaining a running total in register r5.

The down counter in r4 is decremented next - dec.w r4, r4 - and the test instruction in the next line - tst.w r4 - sets the flags in the PS register according to the value in r4. Refer back to the description of Processor Status Register condition code bits if this is not clear.

The `jne' instruction in the next line - jne @#loop - will take the branch if the zero flag is not set in the PS register. When ultimately the value in r4 will reach zero, the `tst.w' instruction will cause the zero flag to be set which in turn will prevent the `jne' instruction from taking the branch and therefor the control falls through to the `halt' instruction.

That will halt the processor and no further changes will occur in the system. Thus the program execution comes to a termination at which time a core dump can be produced by the `nload -c' command, wherein one can inspect the final value in the register r5 which will contain the sum of the ten numbers.

______________________________________________________________

We will now look at some notation that is necessary for a concise description of the instruction set.

7.13.5.1. NOTATION

LSB           Least Significant Bit.                               
MSB           Most Significant Bit.                                
Rn            Register number (R0-RF).                             
              1 hex digit                                          
aaaa          16 bit address.                                      
              4 hex digits                                         
hhh           Hex number.                                          
pp            Processor Status Flag.  [I A S T N Z V C]    2 hex   
              digits                                               
t             Type of operand (0-2).  [W=0 B=1 H=2]      1 hex     
              digit                                                
xx            Mode + Register.  Source Operand A.           2      
              hex digits                                           
yy            Mode + Register.  Source Operand B.           2      
              hex digits                                           
zz            Mode + Register.  Destination Operand.        2      
              hex digits                                           
nn            2 digit hex number                                   
<-            becomes                                              
v             logical OR                                           
v             logical exclusive OR                                 

Many opcodes have an extension which refers to the Processor Status (PS) Register bits (I, A, S, T, N, Z, V, C) or operation word size (W, B, H).

Processor Status Register Bit Specification:

PS register bits I,A,S,T,N,Z,V,C may be specified with the CLP, SEP, JC and JS instructions. Refer to the PS Register bits table for a description of all PS register bits. The relevant bit(s) are specified by the appropriate letter. Multiple bits can be specified in a single instruction. For example, CLP.NZV clears the N, Z and V bits in the PS register.

Word Size Specification:

Only one of the letters W,B, or H (W=word, B=byte, H=halfword) may be specified in a single, double or triple operand instruction. For example, MOV is the mnemonic to move all, or a portion of a word, depending on the letter specified. To move the hex byte value 28 to R5, use the instruction MOV.B #28, R5.

7.13.5.2. ADDRESSING MODES

Addressing modes, contained in Nurve instructions, define the way registers are used to access operands. For example, a register may contain a value to be manipulated or it may contain the address of the value. You may want to increment or decrement a value that is being used as a counter. Or, you may want to increment the address of a value, to point at the next value in a series. Each of these functions can be specified by an addressing mode. There are 16 addressing modes available in Nurve - a table follows.

An addressing mode is paired with a CPU register to define an operand. When an operand is shown as xx (for source operand A), yy (for source operand B) or zz (for the destination operand) the first hex digit (the high order nibble) is an addressing mode (from 0 to F) and the second hex digit (the low order nibble) is a CPU register (R0 to RF). Thus, the low order nibble specifies one of the 16 CPU registers and the high order nibble defines one of 16 different addressing modes.

An instruction may require no operands, or it may require up to 3 operands; an addressing mode and a register must be specified for each. Think back to the explanation of a machine language instruction.

Opcode

No operand instruction word

Opcode Dest

Single Operand instruction word

Opcode SrcA Dest

Double operand instruction word

Opcode SrcA SrcB Dest

Triple operand instruction word

Part of the instruction contains the code for the actual instruction (the opcode) and the remainder of the word contains the operands. Now we know that each operand consists of an addressing mode digit and a register digit - 4 bits (a nibble) each. Looking at machine instructions with bit positions marked (and remembering that a nibble consists of 4 bits) we can further decompose the format of instructions to see how the addressing modes fit in.

Opcode Dest

Mode Reg

... 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1

Single Operand instruction word

Opcode SrcA Dest

Mode Reg Mode Reg

... 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1

Double Operand instruction word

Opcode SrcA SrcB Dest

Mode Reg Mode Reg Mode Reg

... 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1

Triple Operand instruction word

The following table defines each of the 16 addressing modes available in Nurve.

The simplest mode, Register Direct, uses the value in the register as the operand.

Other modes use a register to contain an address, or use the address in a register combined with the PC (program counter).

There are different modes available for incrementing and decrementing register values. You may wish to increment/decrement the register and then use it, or use the value first and then increment/decrement it.

 Addressing Mode        Binary  hex  Assembly  Description of Addressing Mode      
 Register Direct         0000    0      Rn      Register n is operand.             
 Register Indirect       0001    1     @Rn     Register n is address of operand.   
 Double Indirect         0010    2     @@Rn    Rn is address of address of         
                                               operand.                            
 Indexed                 0011    3     [Rn]    (Rn) + (@PC+) is address of         
                                               operand.                            
 Indirect Pre            0100    4     @+Rn    Increment register n.  Access @Rn.  
Increment                                                                          
 Indirect Pre            0101    5     @-Rn    Decrement register n.  Access @Rn.  
Decrement                                                                          
 Indirect Post           0110    6     @Rn+    Access @Rn.  Increment register n.  
Increment                                                                          
 Indirect Post           0111    7     @Rn-    Access @Rn.  Decrement register n.  
Decrement                                                                          
 Double Pre Increment    1000    8    @@+Rn     Increment register n.  Access      
                                               @@Rn.                               
 Double Pre Decrement    1001    9    @@-Rn    Decrement register n.  Access       
                                               @@Rn.                               
 Double Post Increment   1010    A    @@Rn+    Access @@Rn.  Increment register    
                                               n.                                  
 Double Post Decrement   1011    B    @@Rn-    Access @@Rn.  Decrement register    
                                               n.                                  
 Indexed Pre             1100    C    [+Rn]    Increment register n.  Access [Rn.  
Increment                                                                          
 Indexed Pre Decrement   1101    D    [-Rn]    Decrement register n.  Access *Rn.  
 Indexed Post            1110    E    [Rn+]    Access *Rn.  Increment register n.  
Increment                                                                          
 Indexed Post            1111    F    [Rn-]     Access *Rn.  Decrement register    
Decrement                                      n.                                  

PC addressing modes

 Immediate      #hhh    @PC+      6C       Constant (number)        
    mode                                   follows the              
                                           instruction.             
  Absolute     @#hhh    @@PC+     AC       Address of operand       
    mode                                   follows the              
                                           instruction.             

All of these addressing modes may appear somewhat overwhelming at first glance. However, each of them is useful depending on what you want to accomplish.

Some simple examples are shown here, followed by some complete programs.

Examples:

i) Both operands are mode 0 (the registers are the operands):

MOV R2, R3 ; machine code is: 3D000203

; 02 - mode 0, register 2

; 03 - mode 0, register 3

ii) First operand is mode 1, second operand is mode 0 (in mode 1, the register contains the address of the operand; in mode 0, the register is the operand)

MOV @R2, R3 ; machine code is: 3D001203

; 12 - mode 1, register 2

; 03 - mode 0, register 3

iii) MOV R2, @#SYMBOL ; machine code is: 3D0002AC

; 02 - mode 0, register 2

; AC - mode A, register C (PC)

iv) MOV #05, R6 ; machine code is: 3D006C06

; 6C - mode 6, register C

; 06 - mode 0, register 6

v) MOV #SYMBOL, R6 ; machine code is: 3D006C06

; 6C - mode 6, register C

; 06 - mode 0, register 6

NOTE: Assume label SYMBOL is located at address 200

The following program 7.13.5a illustrates the use of double indirect addressing mode. The program prints three strings. The pointers to the three strings are stored in a table. Notice the reservation of four words for this table in the data segment. The first three words will store the actual pointers to the three strings and the last word will be set to zero. That is called a NULL pointer. As we step through the table, we will watch for the NULL pointer and when it is encountered, we will terminate the processing there. This technique allows one to write programs that can scale with data size. This very same program can be used to print any number of strings by simply adding the strings in the data area and the code to set-up the pointer table at the beginning of the table. Both of these are trivial changes to the program. The core program does not need to be changed one bit.

Examine the program carefully and then read the further explanation of instructions which follows the program.

;=========================================================================

; Filename: 7.13.5a.asm

; Author: Christian, Burt Berel. S.

; Student #: 123 456 789

;

; Purpose: Print three strings using double indirect addressing mode.

;

;=========================================================================

; Test Double Indirect Addressing Mode.

; This program is not easy to understand. Simply reading

; it will not help. Use paper and pencil and form a diagram

; of table of pointers and strings they point to. Draw arrows

; to follow the pointers.

;_________________________________________________________________

.CODE ; Code Segment.

code:

; Main program.

; Set up the table of pointers to strings.

mov #table, r0

mov #str0, @r0+

mov #str1, @r0+

mov #str2, @r0+

clr @r0 ; Last pointer is NULL pointer.

mov #table, r0

loop0:

mov.b @@r0, r1

mov r1, r0 ; Pass character to putc.

jsub @#putc

inc @r0, @r0 ; Increment pointer.

tst.b @@r0 ; Is the character there NULL ?

jne @#loop0

mov #crlf, @-sp ; Print a CR/LF.

jsub @#print

tst @sp+ ; Clear stack.

tst @r0+ ;Equivalent to : add r0, #04, r0

tst @r0 ; Is it a NULL pointer ?

jne @#loop0 ; If not, print the string pointed to.

halt

;--------------------- Subroutine Area follows: ----------

; Subroutine Name: print

; Purpose: : Prints a string.

; Arguments : The pointer to the string is received

; on the stack.

; Registers

; used : r0, r1, sp

; modified : none

; Side effects : none

; Remarks : SP is left for the calling program to clear.

; Documentation :

; Register r1 is used to scan through the string, byte at a time.

; Register r0 is used to convert the character byte to a word that

; can be put on the stack before calling putc.

.CODE ; Code Segment.

print:

push r0

push r1

mov.w #0c[sp], r1 ; Get the pointer to the string.

begin0:

jeq @#end0 ; If end of string, exit loop

mov.b @r1+, r0 ; Convert character byte to word.

jsub @#putc

jump @#begin0

end0:

pop r1

pop r0

rsub

;_________________________________________________________________

.DATA ; Data Segment.

data:

.align.w

table: .block.w 4 ; Table of pointers.

str0: .string "A string."

str1: .string "Another string."

str2: .string "Yet another string."

crlf: .init.b 0a

.init.b 0d

.init.b 00

.END ; End of source file.

---------------------------------------------------------------------------------------------------------------------------------------------------

The instruction :

mov #table, r0

loads the address of the beginning of the table in register r0. The instruction

mov #str0, @r0+

stores the address of the first string in the first position of the table. The first position of the table is pointed to by the register r0 as a result of the previous instruction that initialized r0. The @r0+ is to be decoded as follows. The @ causes the contents of the register r0 to be taken as the address of the operand. The `+' suffix causes the address in r0 to be incremented by four. The amount of increment depends upon whether a suffix has been used after the instruction mnemonic. If no suffix is used the increment is by four which is the length of the NURVE word in bytes. A `.b' suffix will cause an increment of 1 and a `.h' suffix will cause an increment of 2. The following two instructions :

mov #str1, @r0+

mov #str2, @r0+

store the addresses of the next two strings in the next two positions of the table. The instruction:

clr @r0

causes the last pointer to be zero. By now, register r0 points at the last element of the table and so in the next instruction it is reset to point to the beginning of the table. Now we want to print the first string. The first character of the first string is obtained by taking the address in r0 at which is stored the actual address of the first character of the first string. Since there are two pointers in this path, we need the double indirect addressing mode as in :

mov.b @@r0, r1

We take that character and put it in the word register r1 and also into r0 for printing. A call to the system function `putc' is made which outputs the character to the standard output or the terminal.

A jsub call to print is made to print a CRLF to improve the readability of the output. The following `tst' instruction is actually not used to set the flags in the PS register but is an efficient way of incrementing the stack pointer. This technique is widely used in assembly language programs and you will see its use in many places in the programs in this manual.

The following program shows the use of the register direct, register indirect, double indirect, indirect postincrement, indirect predecrement, indirect postdecrement addressing modes.

;=========================================================================

; Filename: 7.13.5b.asm

; Author: Christian, Burt Berel. S.

; Student #: 123 456 789

;

; Purpose: Print three strings using double indirect addressing mode.

; First the program prints the strings from first to last and

; then from last to first and in the process uses

; most of the addressing modes.

;

;=========================================================================

; Test all the major addressing modes.

; This program is not easy to understand. Simply reading

; it will not help. Use paper and pencil and form a diagram

; of table of pointers and strings they point to. Draw arrows

; to follow the pointers.

; This program uses all the major addressing modes although

; not all the variations of each of those addressing modes.

; However, the reader should be able to get a good understanding

; of all the addressing modes and be able to perceive the need

; for any of those in a real applications and use them.

; The following addressing modes are used :

; Register Direct.

; Register Indirect.

; Double Indirect.

; Indirect Postincrement.

; Indirect Predecrement.

; Indirect Postdecrement.

;_________________________________________________________________

.CODE ; Code Segment.

code:

; Main program.

; Set up the table of pointers to strings.

; There is a NULL pointer at the beginning of the table

; as well as the end of the table which will permit us to

; traverse the list forwards as well as backwards when using

; the NULL pointer as a termination point.

mov #f_table, r2

clr @r2+

mov #beg_ary0, @r2+

mov #beg_ary1, @r2+

mov #beg_ary2, @r2+

mov #beg_ary3, @r2+

clr @r2 ; Last pointer is NULL pointer.

; Print the strings first to last.

mov #f_table, r2 ; Point to the beginning of the table.

tst @r2+ ; Equivalent to add r2, #04, r2

loop0:

mov.b @@r2, r1

mov r1, r0 ; Pass character to putc().

jsub @#putc

inc @r2, @r2 ; Increment pointer.

tst.b @@r2 ; Is the character there a NULL ?

jne @#loop0

mov #crlf, @-sp ; Print a CR/LF.

jsub @#print

tst @sp+ ; Clear stack.

tst @r2+ ; Equivalent to : add r2, #04, r2

; Notice the REGISTER INDIRECT WITH AUTO-INCREMENT ADDRESSING MODE.

tst @r2 ; Is it a NULL pointer ?

jne @#loop0 ; If not, print the string pointed to.

mov #dashes, @-sp

jsub @#print

tst @sp+

mov #crlf, @-sp

jsub @#print

tst @sp+

; Print the strings last to first.

mov #f_table, r2

clr @r2+

mov #beg_ary0, @r2+

mov #beg_ary1, @r2+

mov #beg_ary2, @r2+

mov #beg_ary3, @r2+

clr @r2 ; Last pointer is NULL pointer.

mov #f_table, r2 ; Point to the beginning of the table.

; Take the pointer to the end of the table by searching for

; the NULL pointer.

loop1:

tst @+r2

jne @#loop1

; Now r2 is pointing to the NULL pointer, so we take it one

; step back so as to have r2 point to a string we can work with.

tst @-r2

; Notice the REGISTER INDIRECT WITH AUTO-PREDECREMENT ADDRESSING MODE.

loop2:

mov.b @@r2, r1

mov r1, r0 ; Pass character to putc().

jsub @#putc

inc @r2, @r2 ; Increment pointer.

tst.b @@r2

; Is the character there a NULL ?

jne @#loop2

mov #crlf, @-sp ; Print a CR/LF.

jsub @#print

tst @sp+ ; Clear stack.

tst @r2-

; Equivalent to : sub r2, #04, r2

; Notice the REGISTER INDIRECT WITH AUTO-DECREMENT ADDRESSING MODE.

tst @r2 ; Is it a NULL pointer ?

jne @#loop2 ; If not, print the string pointed to.

halt

;_________________________________________________________________

; Here include the code for subroutine print from program 7.13.5a

.DATA ; Data Segment.

data:

.align.w

; Table of pointers.

f_table: .block.w 4

beg_ary0: .string 'ABCDEF'

beg_ary1: .string 'GHIJKL'

beg_ary2: .string 'MNOPQR'

beg_ary3: .string 'STUVWX'

dashes: .string "------"

crlf: .init.b 0a

.init.b 0d

.init.b 00

.END ; End of source file.

7.13.5.3. OPCODES

This section contains a tabular summary of all of the Nurve opcodes organized by the number of operands that are required for each instruction.

The entries on the left side of the tables are complete machine code instructions. The opcode is the first part of each 'word'.

Before looking at the following opcode tables, look again at the "Notation" section for a complete description of all abbreviations - for example xx, yy, and zz are used as place-holders for operands; NZVC are for condition code bits, and so on.

Some opcodes can have an extension to indicate if the instruction is to be applied to a word, a byte or a halfword. (WBH) If the extension is not included in your program, Nurve assumes that a word is what you want.

Machine Code  Assemble Mnemonic   Description                       

No operand

00000000      HALT                Halt process                      
00000001      RISR                Return from interrupt service     
                                  routine                           

Single operand

000001pp      CLP.   IASTNZVC     Clear PS Register bit(s).         
000002pp      SEP.    IASTNZVC    Set PS Register bit(s).           
1Dt000zz      CLR.   WBH          Clear (zero) the destination.     
1Et000xx      TST.    WBH         Set PS register relative to       
                                  zero.                             

Jump Instructions

20ppaaaa      JC.     IASTNZVC    Jump if PS bit(s) clear.          
21ppaaaa      JC.     *           Jump if PS bit(s) clear           
                                  (special).                        
22ppaaaa      JS.     IASTNZVC    Jump if PS bit(s) set.            
2200aaaa      JSUB                Jump SUBroutine.                  
23ppaaaa      JS.     *           Jump if PS bit(s) set (special).  

Double Operand

35t0xxzz      XCH.    WH          Exchange Halfwords/Bytes.         
36t0xxzz      TAS.     WH         Test and Set.                     
37t0xxzz      COM.    WBH         One's Complement.  (Flip bits.)   
38t0xxzz      NEG.    WBH         Negate.  (Two's Complement.)      
39t0xxzz      INC.     WBH        Increment.  (Add 1.)              
3At0xxzz      DEC.    WBH         Decrement.  (Subtract 1.)         
3Bt0xxzz      ADC.    WBH         Add Carry bit.                    
3Ct0xxzz      SBC.    WBH         Subtract Carry bit.               
3Dt0xxzz      MOV.   WBH          Move. (Copy.)                     
3Et0xxyy      CMP.   WBH          Compare xx-yy and set PS          
                                  register.                         
3Fttxxzz      CNV.    WB WH  BW   Convert size of xx to size of     
              BH  HW HB           yy.                               

Triple Operand

4txxyyzz      AND.    WBH         Logical bitwise AND.              
5txxyyzz      OR.       WBH       Logical bitwise OR.               
6txxyyzz      XOR.    WBH         Logical bitwise XOR (exclusive    
                                  or).                              
7txxyyzz      ROT.     WBH        Rotate (through the Carry bit).   
8txxyyzz      ASH.     WBH        Arithmetic Shift.                 
9txxyyzz      ADD.     WBH        Add.        zz <- xx + yy.        
Atxxyyzz      SUB.     WBH        Subtract.  zz <- xx - yy.         
Btxxyyzz      MUL.    WBH         Multiply.  zz <- xx * yy.         
Ctxxyyzz      DIV.      WBH       Divide.     zz <- xx / yy.        
Dtxxyyzz      MOD.    WBH         Modulo.   zz <- remainder( xx /   
                                  yy )                              

Examples:

Assembler Machine Description

1) and r1, r2, r3 ; 40010203 r3 <- r1 and r2.

2) and r0, #0f, r0 ; 40006C00 Mask out all but the least significant nibble of r0

; 0000000F (operand follows instruction)

and r1, #0f0, r1 ; 40016C01 Retain only the second least significant nibble of r1

; 000000F0 (operand follows instruction)

or r0, r1, r1 ; 50000101 The least significant byte of r1 is a composite of the

; higher nibble of r1 and lower nibble of r0 of their least

; significant bytes respectively.

3) xor r0, @r1, r0 ; 60001100 XOR r0 with contents of memory pointed to by r1.

xor r0, @r1, r0 ; This brings back the original value of r0.

4) rot #04, r0, r0 ; 706C0000 Rotate the value in r0 through C four times.

; 000000004 (operand follows instruction)

5) ash #01, r0, r0 ; 806C0000 Multiply the value in r0 by two.

; 000000001 (operand follows instruction)

ash #0ffffffff,r0, r0 ; 806C0000 Divide the value in r0 by two.

; FFFFFFFF (operand follows instruction)

6) add r0, @r1, r0 ; 90001100 Add word pointed to by r1 to r0.

7) sub r0, @r1, r0 ; A0001100 Subtract word pointed to by r1 from r0.

8) mul r0, #12, r0 ; B0006C00 Multiply the value in r0 by 17 (decimal).

; 000000012 (operand follows instruction)

9) div r0, #0a, r0 ; C0006C00 Divide the value in r0 by 10 (decimal).

; 00000000A (operand follows instruction)

10) mod r0, #02, r0 ; Take the remainder of r0/2 to check if r0 is even.

7.13.5.4. MACROS

An assembler macro is a short hand notation for a previously defined instruction. For example, the macro RSUB is another way of writing MOV @SP+, PC. Macros are made available only for the convenience of an assembler programmer.

00000100      NOOP     =  CLP         NO OPeration.                      
2000aaaa      JUMP     =  JC          Unconditional Jump.                
2001aaaa      JGEU     =  JC.C        Jump Greater than or Equal         
                                      Unsigned                           
2004aaaa      JNE       =  JC.Z       Jump Not Equal                     
2005aaaa      JGTU    =  JC.CZ        Jump Greater Than Unsigned         
2008aaaa      JPL        =  JC.N      Jump PLus                          
210Aaaaa      JGE       =  JC.N*V     Jump Greater than or Equal signed  
210Eaaaa      JGT       =  JC.ZN*V    Jump Greater Than signed           
2201aaaa      JLTU     =  JS.C        Jump Less Than Unsigned            
2204aaaa      JEQ        =  JS.Z      Jump EQual                         
2205aaaa      JLEU     =  JS.CZ       Jump Less than or Equal Unsigned   
2208aaaa      JMI        =  JS.N      Jump MInus                         
230Aaaaa      JLT        =  JS.N*V    Jump Less Than signed              
230Eaaaa      JLE        =  JS.ZN*V   Jump Less than or Equal signed     
3D006D0C      RSUB                    Return from SUBroutine.            
3Dt0xx5D      PUSH.  WBH              PUSH xx onto system stack.         
3Dt06Dzz      POP.     WBH            NOTE: Auto inc/dec on SP is  +/-   
                                      4                                  

For examples of the various branch instructions, please see the program 7.13.9.1

The PUSH and POP instructions are used to save registers and values on the stack for subsequent retrieval.

They are mainly used in subroutines to save all the registers that are used within the subroutine. This facilitates the free use of registers by the calling program and the subroutine. The stack is also used in applications like expression parsing.

When a PUSH instruction is executed the SP is decremented by four and the value is stored at the new address in SP.

POP reverses the action of the PUSH instruction. POP retrieves the value currently pointed to by the SP and then increments the SP by four.

7.13.6. ASSEMBLER DIRECTIVES

Assembler directives (also called Pseudo operations or pseudo-ops) provide information to the assembler and look like assembly language instructions, but do not generate machine language instructions. All assembler directives begin with a period.

7.13.6.1. .ALIGN .WBH

Align the next item onto a word boundary (.ALIGN.W), a byte boundary (.ALIGN.B) or a halfword boundary (.ALIGN.H). The assembler maintains a location counter (LC) that keeps track of where the next instruction or datum is to be assembled. The .ALIGN assembler directive increments the LC, until the LC is aligned along a proper boundary.

Format:

LABEL: .ALIGN.WBH ;COMMENT

where LABEL is an optional label. Only one of the letters W, B, or H must be specified.

Example:

.ALIGN.H

SALARY: .BLOCK.H 1 ; Net Employee SALARY (is 16 bits).

The ALIGN.H ensures that SALARY is properly aligned on a half word boundary.

7.13.6.2. .BLOCK .WBH

Reserve a block of memory. .BLOCK.W reserves words, .BLOCK.B reserves bytes and .BLOCK.H reserves halfwords. The storage reserved is not initialized. The LC must be at a word boundary for .BLOCK.W or a halfword boundary for .BLOCK.H.

Format:

LABEL: .BLOCK.WBH nn ;COMMENT

where LABEL is an optional label, nn is a 1 or 2 digit positive (hex) integer giving the number of words to be reserved.

Example:

SUM: .BLOCK.W 1 ;Total or daily sales

TABEL: .BLOCK.W 4 ;TABEL will contain

; product codes

This reserves 5 memory words and associates the symbolic address SUM with the first word. The second block can be referenced by TABEL.


7.13.6.3. .CODE

User initialized storage is either a program instruction placed in the code segment or a global data item placed in the heap. Thus, any code generated by the assembler must be given a code segment address or a heap address. Code generated following a .CODE directive will be placed in the code segment area (until the next .DATA directive is encountered).

7.13.6.4. .DATA

See .CODE above. Code generated following a .DATA directive will be placed in the heap data area (until the next .CODE directive is encountered).


7.13.6.5. .END

The .END directive must be the last statement in an assembly language program. It informs the assembler that the end of the program has been reached (i.e.. proceed to second pass).


7.13.6.6. .INIT .WBH

Reserve and initialize a single word (.INIT.W), byte (.INIT.B) or halfword (.INIT.H). This directive is usually used to define constant data.

Format:

LABEL: .INIT.WBH nn ;COMMENT

where LABEL is an optional label, and nn is a hex integer specifying the value of a constant.

Example :

CRLF: .INIT.B 0A ; ASCII 10 - Line Feed

.INIT.B 0D ; ASCII 13 - Carriage Return

7.13.6.7. .STRING

The .STRING directive reserves and initializes consecutive bytes of ASCII codes, assigning one character per byte.

Format:

LABEL: .STRING 'text_string' ;COMMENT

where LABEL is an optional label, and text_string is any string of characters enclosed in (delimited by) quotation marks. A NULL byte (zero byte) is placed at the end of the string.

Example:

LOGIN: .STRING 'Login please: ' ; User login prompt.

will reserve 15 consecutive bytes and initializes them to the ASCII codes of the letters inside the quotes (including blanks and the trailing NULL byte).

7.13.7. SYSTEM CALLS (I/O)

System calls are provided by the operating system for the convenience (and safety) of users.

All I/O is performed via system calls.

System calls are invoked using the JSUB subroutine call instruction. The subroutines from the system library are linked into a load module by the linker.

There is no facility for obtaining numbers, or for printing numbers. You must convert from ascii to binary or from binary to ascii. Write your own routines for these functions, or use the subroutines given in the next section of the manual.

7.13.7.1. GETC

Getc accepts a single character from the default input device (usually the user terminal) and returns it in the low byte of R0.

Input is buffered by the operating system. Individual input characters are stored in a system buffer until a control character (usually a newline character) is found or the system buffer is full. Thus, a user program waiting to input a single character will be blocked (forced to wait) until more input (usually a newline character) is typed by the user.

Example:

jsub @#getc ; Get a character

; getc puts it into R0

The call to getc is generally placed in a loop, with a test for the line feed character to terminate the loop. This is demonstrated in the next section of this manual.

7.13.7.2. PUTC

Putc outputs a single ASCII character passed to it in the low byte of R0 onto the default output device (usually the user terminal).

Example:

mov.b @R5+, R0 ; Place a character into R0

jsub @#putc ; call putc to print the char

Calls to putc are also generally placed in a loop. This is also demonstrated in the next section of this manual.

7.13.8. SUBROUTINES

7.13.8.1. GENERAL DESCRIPTION

As you will have observed by now, assembly language is very low level; it takes 3 or more lines of code to implement a simple 'if' statement. A 'small' program can rapidly grow to many lines or pages of code. Despite the best intentions of a programmer to document the program well, it can become difficult to discern the logic flow nestled in the many lines of code.

The solution to this problem is to divide the program into sections of code, each section performing a specific function. The main part of the program can then consist of simple calls to the sections of code required to perform the desired functions. This has the added advantage that, if a section of code is required more than once, it can simply be called again, rather than repeating the code each time the function is required.

Consider the assembly code that would be required to simply prompt the user for a string, and then get the string.

WITHOUT SUBROUTINES: WITH SUBROUTINES

mov #prompt, r1 mov #prompt, r1

putstr: mov @r1+, r0 jsub @#putstr

jeq endprint mov #string, r1

jsub @#putc jsub @#getstr

jump @#putstr

endprint: ;----------------------

mov #string, r1 ; subroutines down here

getwhile: jsub @#getc

cmp.b r0, @#LF

jeq @#endget

mov.b r0, @r1+

jump getwhile

endget:

The program section on the right - the one with subroutines - is much easier to follow than the longer version on the left. If you really want to see the details involved in the subroutines, you can always go down and look at the code; but the main part of the program is kept simple.

7.13.8.2. NURVE SUBROUTINE IMPLEMENTATION

In the Nurve programming language, there are two instructions relating to subroutines.

jsub subroutine_label and rsub

The first instruction, jsub subroutine_label (e.g. jsub @#putc), instructs the assembler to jump to the location specified by the subroutine label. At the end of the subroutine, execution of code must return to the main program, at the instruction following the jsub. Question: How will the assembler know what location to return to in the main program? Answer: The jsub instruction actually does 2 things; it causes a jump to a subroutine, but it also, automatically, causes the return address (the address following the jsub instruction) to be placed on the stack.

The second instruction, rsub, instructs the assembler to return to the point in the main program following the jsub call. Question: How does the assembler know what location to return to in the main program? Answer: The rsub instruction automatically pops the return address from the stack; remember this was placed on the stack when the jsub instruction was executed.

7.13.8.2.1. USING THE STACK TO SAVE VALUES

It is quite likely that you will be using registers in your main program to hold certain values, such as loop counters and so on. However, you may also need to use some registers in your subroutine. It is a very good idea to save these register contents at the beginning of a subroutine and then restore them at the end of the subroutine. The stack can be used for temporary storage of values.

For example:

; Subroutine: putstr

;-------------------------------------

putstr:

push r0 ; save register

putwhile:

mov.b @r1+, r0 ; body of subrtn

...

endput:

pop r0 ; restore register

Use the push and pop instructions as you would parentheses i.e. make sure you always have matched sets - if you push a value on the stack at the beginning of a subroutine, make sure you pop it off at the end.

Also, remember that the stack operates on a LIFO - Last In First Out. - basis. For example, if you wanted to save and restore R1 and R2, you would have to code:

push R1

push R2 ; R2 is the last value to go into the stack

... ; main part of subroutine

pop R2 ; the R2 value is the first out of the stack

pop R1

7.13.8.2.2. USING REGISTERS TO PASS VALUES

More often than not, it is necessary to pass one or more values between the calling area, and the subroutine.

e.g. jsub @#putc ; the subroutine 'putc' expects a value in R0

e.g. jsub @#getc ; the 'getc' subroutine places a character into R0

This is the simplest and easiest method of passing arguments - you can put an address or a value in a register.

7.13.8.2.3. USING THE STACK TO PASS VALUES

This method of passing values to and from a subroutine can be dangerous if not used properly. It is included in this manual for the sake of completeness. Use it only if you are sure you completely understand it - otherwise, stick to using registers for passing values.

In order to use the stack to pass values to and from subroutines, you must understand how the stack is used in the execution of subroutines, or you can destroy the return address to the main program. If you put a value or address on the stack and then issue a jsub call, then there are 2 items on the stack. e.g. Consider the instructions:

mov #holdit, @-SP

jsub @#putstring

The address of the label "holdit" would be on the stack, followed by the return address following the jsub call. If you wanted to access the address 'holdit' from the subroutine you would have to use an instruction such as:

mov #04[SP], R4

The offset "04" is required to get around the return address stored on the stack. The stack pointer does not change after this instruction, a value is simply copied from the stack.

If you put something on the stack before a jsub call, you should remove it after the call. e.g.

tst @SP+ ; clean up stack

This instruction does change the stack pointer.

7.13.8.3. SUBROUTINES FOR STRING I/O

The only facility for I/O in Nurve is for single characters. It is relatively straightforward to set up subroutines that will get a string of characters, and to print a string. You must decide though, what character will be used to terminate a string. The Nurve Assembly directive ".STRING" appends a null byte to the end of each string that the user defines. Given this, it makes sense to use the null byte as a terminator for any string that you input.

The following program contains "getstr" and "putstr", two subroutines that you can use for character string I/O. You will notice in getstr, that the stored string is not terminated with the 'return' character; the 'null' character (ASCII value 0) is used instead.

*** Both subroutines use R1 to pass the address of the string.

These subroutines are stored as individual files in anonymous FTP on Hercules. Refer to the appendix on FTP for an example of how to get a file and add it to your own program. Feel free to encorporate them in your programs - just give credit to this manual for the code.

e.g. ; This subroutine is taken from the C.S. Nurve Users' Manual

;========================================================================

; Filename: 7.13.8.4.asm

; Author: Grace Hopper

; Student #: 000 000 000

;

; Purpose: To test the putstr and getstr subroutines.

;

;========================================================================

.CODE

mov #prompt1, r1 ; prompt for a string

jsub @#putstr

mov #stringin, r1 ; set up the string address for getstr

jsub @#getstr ; get the string

mov #mesg1, r1 ; echo the string

jsub @#putstr

mov #stringin, r1

jsub @#putstr

mov #CRLF, r1 ; add a carriage return line feed

jsub @#putstr

halt

.DATA

prompt1: .string "Input a string: "

.ALIGN

mesg1: .STRING "This is what you entered: "

.ALIGN

stringin: .BLOCK 80

CRLF: .INIT 0A ; ascii value for line feed

.INIT 0D ; ascii for carriage return

;-------------------------- Subroutines ---------------------------------

;--------------------------- putstr --------------------------------

; Subroutine: putstr

; Author: Grace Hopper

; Purpose: to output a character string

; Arguments: r1 holds the address of the string to be printed

;-------------------------------------------------------------------

.CODE

putstr:

push r0 ; save register

putwhile:

mov.b @r1+, r0 ; While (char not a null)

jeq @#endput ;

jsub @#putc ; print the character

jump @#putwhile ; end while

endput:

pop r0 ; restore register

rsub

;--------------------------- getstr --------------------------------

; Subroutine: getstr

; Author: Grace Hopper

; Purpose: to input a character string

; Arguments: r1 holds the address of the string to be input

;-------------------------------------------------------------------

.CODE

getstr:

push r0 ; save register

getwhile:

jsub @#getc ; While (char not a line feed - 0A)

cmp.b r0,@#LF

jeq @#endget

mov.b r0,@r1+ ; store the character

jump @#getwhile ; end while

endget:

mov.b #0,@r1 ; append a null byte to the string

pop r0 ; restore register

rsub

.DATA

LF: .INIT.B 0A ; ascii for line feed

.END

7.13.8.4. SUBROUTINES FOR NUMERIC I/O

As noted previously, the only facility for I/O in Nurve is for single characters. If you wish to enter a number, you must input the Ascii value for each digit and convert the Ascii values to the corresponding numeric value. Similarly, if you wish to output a numeric value, you must go through each digit, one at a time, and convert the numeric values to the Ascii counterpart.

The following program contains "getnum" and "putnum", two subroutines that you can use for numeric I/O. You will notice that 'getnum' is more complex than 'putnum'; it requires a great deal of error checking to be sure the user has entered valid values.

*** Both subroutines use R1 to pass the address of the string.

You will find that the 'putnum' routine is handy in debugging. It is often desirable to display the contents of a register as a program executes. Simply add putnum to your program, and put in jsub calls wherever.

These subroutines are stored as individual files in anonymous FTP on Hercules. Refer to the appendix on FTP for an example of how to get a file and add it to your own program. Feel free to encorporate them in your programs - just give credit to this manual for the code.

e.g. ; This subroutine is taken from the C.S. Nurve Users' Manual

;========================================================================

; Filename: 7.13.8.5.asm

; Author: Grace Hopper

; Student #: 000 000 000

;

; Purpose: To test the getnum and putnum subroutines.

;

;========================================================================

.CODE

mov #prompt1, r1 ; prompt for a number

jsub @#putstr

jsub @#getnum ; get the number

mov r1, @#numbr1

mov #prompt1, r1 ; prompt for a number

jsub @#putstr

jsub @#getnum ; get the number

mov r1, @#numbr2

add @#numbr1, @#numbr2, @#sum

mov #mesg1, r1 ; print it out

jsub @#putstr

mov @#sum, r1

jsub @#putnum

mov #CRLF, r1

jsub @#putstr

halt

.DATA

prompt1: .string "Input a number: "

.ALIGN

mesg1: .STRING "This is the sum: "

.ALIGN

numbr1: .BLOCK 01

numbr2: .BLOCK 01

sum: .BLOCK 01

CRLF: .INIT 0A ; ascii value for line feed

.INIT 0D ; ascii for carriage return

;-------------------------- Subroutines ---------------------------------

;--------------------------- putstr --------------------------------

; Subroutine: putstr

; Author: Grace Hopper

; Purpose: to output a character string

; Arguments: r1 holds the address of the string to be printed

;-------------------------------------------------------------------

.CODE

putstr:

push r0 ; save register

putwhile:

mov.b @r1+, r0 ; While (char not a null)

jeq @#endput ;

jsub @#putc ; print the character

jump @#putwhile ; end while

endput:

pop r0 ; restore register

rsub

;--------------------------- getnum --------------------------------

; Subroutine: getnum

; Author: Grace Hopper

; Purpose: to input a number, converting from ascii to binary.

; Arguments: r1 will contain the binary number

;-------------------------------------------------------------------

.CODE

getnum:

push r0 ; save registers

push r2

push r3

push r4

push r5

push r6

getinit: ; Repeat (getting a valid string)

mov #gbuffer, r4 ; set pointer to char array

clr r2 ; set up counter for char's entered

getnwhile: ; Repeat (inputing characters)

jsub @#getc ; get a character

cmp.b r0, @#LF ; check it for line feed terminator

jeq @#endgetchars

mov.b r0,@r4+ ; move input char into array

inc r2, r2 ; increment digit counter

jump @#getnwhile ; Until a LF (0A) entered

endgetchars:

cmp #08, r2 ; If less than = 8 char's input

jleu @#checkerr ; carry on to check err rtn

push r1 ; Else

mov #sizerr, r1 ; display an error

jsub @#putstr

pop r1

jump @#getinit ; go back to start of loop

; Repeat (error checking)

; hex 00-2F invalid

; hex 30-39 NUMBERS

; hex 3A-40 invalid

; hex 41-46 LETTERS (A-F)

; hex 60-7F lowercase letters and others

checkerr: ;

mov #gbuffer, r3 ; set up character pointer to input string

errloop:

cmp.b @r3, #030 ; If ascii under 30

jmi @#prnterr ; break to print error routine

cmp.b @r3, #060 ; If ascii over 60

jmi @#nextchk ;

sub.b @r3, #020, @r3 ; map lower case letters to upper case

nextchk:

cmp.b @r3, #040 ; If ascii is for a number (30-39)

jmi @#endchk ; carry on to end of checks

cmp.b #046, @r3 ; If ascii of letter beyond 'F' (46)

jmi @#prnterr ; break to print error routine

cmp.b @r3,#040 ; If ascii between numbers and 'A'

jmi @#prnterr ; break to print error routine

endchk:

tst.b @r3+ ; increment character pointer

cmp r3, r4 ; If all char's ok

jeq @#asci2bin ; carry on to conversion rtn

jump @#errloop ; Until all char's checked

prnterr:

push r1 ; print out error message

mov #invalid, r1 ; and go back to start of loop

jsub @#putstr

pop r1

jump @#getinit ; Until 8 or less valid char's entered

; Input string has been validated, now convert ascii to binary

asci2bin:

clr r1 ; clear target for binary value

mov r2, r5 ; set up for shift counter

a2binloop: ; Repeat (converting characters)

clr r3 ; clear intermediate target for binary value

mov.b @-r4, r3 ; get a character from the array

cmp.b #039, r3 ; If it's a number

jmi @#sub37

sub r3, #030, r3 ; convert number to binary

jump @#storedig ; Else

sub37:

sub.b r3, #037, r3 ; convert letter to binary

storedig:

and #0f, r3, r3 ; clear high order bits

sub.b r5, r2, r6 ; calculate the shift count

mul #04, r6, r6 ; " " "

ash r6, r3, r3 ; move binary digit to position

add r1, r3, r1 ; add it to the target

dec r2, r2 ; decrement the character pointer

jeq @#endgetnum

jump @#a2binloop ; Until all characters converted

endgetnum:

pop r6 ;

pop r5 ;

pop r4 ; restore registers

pop r3

pop r2

pop r0

rsub

.DATA

.ALIGN

gbuffer: .BLOCK 20

sizerr: .string "Please re-enter value with 8 or less characters: "

.ALIGN

invalid: .string "Invalid characters input. Please re-enter: "

.ALIGN

LF: .INIT.B 0A

.ALIGN

;--------------------------- putnum --------------------------------

; Subroutine: putnum

; Author: Grace Hopper

; Purpose: to convert a binary value to ascii and output it.

; Arguments: r1 contains the number

;-------------------------------------------------------------------

.CODE

putnum:

push r4 ; save registers

push r2

push r0

mov #08, r4 ; set up a counter for digits

digits:

; Repeat

mov r1, r2 ; get top digit out of r1

ash #04,r1,r1 ; move the rest of the digits over

ash #0ffffffe4, r2,r2 ; move digit to the right for printing

and #0f, r2, r2 ;

cmp.b #09, r2 ; if digit is numeric

jmi @#leters

add.b #030, r2, r2 ; add 30 to convert to ascii

jump @#prntdig

leters: ; else (letters A-f)

add.b #037, r2, r2 ; add 37 to convert

prntdig:

mov.b r2,r0 ; print the digit

jsub @#putc ;

dec r4,r4 ; decrement the digit counter

jeq @#endputnum ;

jump @#digits ; until 8 digits printed

endputnum:

pop r0 ; restore registers

pop r2

pop r4

rsub

.END


7.13.9. COREDUMPS AND TRACES


7.13.9.1. COREDUMPS

A coredump is a 'snapshot' of the NURVE memory when a program terminates. A core dump is automatically produced if the program terminates abnormally or if the '-c' option is given on the command line. A coredump can be used to aid in debugging a program. The contents of all the non-zero memory locations as well as the contents of the registers and the processor status register are displayed on the default output device.

Example:

;=========================================================================

; Filename: 7.13.1.2.1.asm

; Author: Christian, Burt Berel. S.

; Student #: 123 456 789

;

; Purpose: to set the processor status word negative flag.

;

;=========================================================================

.CODE ; Code Segment.

code:

clr r0 ; Initialize.

dec r0, r0 ; Generate a negative result.

halt

.END

Remember that the hex value 08 in the low order portion of the Processor Status register means that the N bit (the negative flag) is set. Look at the value of the PS in the following dump, and also look at the value of register 0.

 

hercules[2]% nurve 7.13.1.1.asm [Return]

Nurve: completed with 0 errors and 0 warnings

hercules[3]% nlink 7.13.1.1.obj [Return]

hercules[6]% nload -c 7.13.1.1.lmn [Return]

Nload: End of Execution.

Execution terminated. PC = 0000000C. 2 instructions executed.

NURVE CORE DUMP (Hex)

----- ---- ---- -----

Code Segment PCB Heap Stack Stack Top

00000000 00000400 00000480 00000880 00000C80

R0 R1 R2 R3 R4 R5 R6 R7

FFFFFFFF 00000000 00000000 00000000 00000000 00000000 00000000 00000000

R8 R9 RA BR PC SP PS IR

00000000 00000000 00000000 41A0E400 0000000C 00000C80 00000108 00000000

ADDR OFFSET 0 04 08 0C 10 14 18 1C

----| -------- -------- -------- -------- -------- -------- -------- --------

0000| 1D000000 3A000000 00000000 00000000 00000000 00000000 00000000 00000000

...

hercules[7]%



7.13.9.2. TRACES

The '-t' option on the command line activates the trace facility. The trace prints the instruction about to be executed. This is useful when debugging a program.

7.13.9.3. PROGRAM EXAMPLES

This section presents some program examples. The first one is the one that adds ten numbers which has been presented before in this manual.

;=========================================================================; Filename: 7.13.3.1.asm

; Author: Christian, Burt Berel. S.

; Student #: 123 456 789

;

; Purpose: Add 10 numbers stored in an array.

;

;=========================================================================

; Pseudo code.

; Let pointer (r3) point to the beginning of the array.

; Let counter (r4) = 10

; Let sum (r5) = 0

; While (counter <> 0)

; Let sum = sum + number pointed to by r3

; Increment the pointer r3

; Let counter = counter - 1

; End

;___________________________________________________________________

.CODE

start:

mov.w #array,r3 ;Register r3 is the pointer

; to the array elements.

mov.w #0a,r4 ;Register r4 is a down counter

; starting at 10 (decimal).

clr.w r5 ;Register r5 will accumulate the

; sum of 10 numbers.

loop: ; Repeat

add.w @r3+, r5, r5; Add the number pointed to by r3

; to running total in r5

dec.w r4, r4 ; Decrement the counter.

tst.w r4 ;

jne @#loop ; until counter is zero

halt ;

.DATA

array: ; Data items for the 10 element array.

.init.w 1

.init.w 3

.init.w 5

.init.w 7

.init.w 9

.init.w b

.init.w d

.init.w f

.init.w 17

.init.w 19

.END

The next program shows how to use various branch instructions and subroutines.

;=========================================================================; Filename: 7.13.9.1.asm

; Author: Christian, Burt Berel. S.

; Student #: 123 456 789

;

; Purpose: Sets and tests the N, Z, V and C flags in the PS

; registers.

;

;========================================================================= ; Documentation :

; Performs data movement or arithmetic to set particular PS register

; flags and prints messages accordingly. Prints messages before the

; setting of the flags too, so as to allow the reader to follow the flow of

; control in the program.

;_________________________________________________________________

.CODE ; Code Segment.

start:

; Main program.

mov #00, r0 ; Initialize.

mov #01, r1

tst_neg:

mov #neg_tst, @-sp ; Pass pointer of string to print().

jsub @#print

tst @sp+ ; Clear stack.

sub r0, r1, r0 ; Generate a negative result.

js.n @#pr_neg_msg

jump @#pr_abs_msg ; This line will never be executed.

tst_zip:

mov #zip_tst, @-sp ; Pass pointer of string to print().

jsub @#print

tst @sp+ ; Clear stack.

inc r0, r0 ; Generate a zero result.

js.z @#pr_zip_msg

jump @#pr_abs_msg ; This line will never be executed.

tst_ovf:

mov #ovf_tst, @-sp ; Pass pointer of string to print().

jsub @#print

tst @sp+ ; Clear stack.

mov #07fffffff, r0

inc r0, r0 ; Generate an overflow.

js.v @#pr_ovf_msg

jump @#pr_abs_msg ; This line will never be executed.

tst_cry:

mov #cry_tst, @-sp ; Pass pointer of string to print().

jsub @#print

tst @sp+ ; Clear stack.

clr r0

sub r0, #01, r0

rot #01, r0, r0 ; Generate a carry.

js.c @#pr_cry_msg

jump @#pr_abs_msg ; This line will never be executed.

end_tst:

halt

pr_neg_msg:

mov #neg_msg, @-sp ; Pass pointer of string to print().

jsub @#print

tst @sp+ ; Clear stack.

mov #cr_lf, -sp ; Pass pointer of string to print().

jsub @#print

tst @sp+ ; Clear stack.

jump @#tst_zip

pr_zip_msg:

mov #zip_msg, @-sp ; Pass pointer of string to print().

jsub @#print

tst @sp+ ; Clear stack.

mov #cr_lf, @-sp ; Pass pointer of string to print().

jsub @#print

tst @sp+ ; Clear stack.

jump @#tst_ovf

pr_ovf_msg:

mov #ovf_msg, @-sp ; Pass pointer of string to print().

jsub @#print

tst @sp+ ; Clear stack.

mov #cr_lf, @-sp ; Pass pointer of string to print().

jsub @#print

tst @sp+ ; Clear stack.

jump @#tst_cry

pr_cry_msg:

mov #cry_msg, @-sp ; Pass pointer of string to print().

jsub @#print

tst @sp+ ; Clear stack.

mov #cr_lf, @-sp ; Pass pointer of string to print().

jsub @#print

tst @sp+ ; Clear stack.

jump @#end_tst

pr_abs_msg:

mov #abs_msg, @-sp ; Pass pointer of string to print().

jsub @#print

tst @sp+ ; Clear stack.

mov #cr_lf, @-sp ; Pass pointer of string to print().

jsub @#print

tst @sp+ ; Clear stack.

halt ; Should control come here, it would

; be best to halt the CPU.

;_________________________________________________________________

;

; Subroutine : print

; Function : Prints a string.

;_________________________________________________________________

; Arguments : The pointer to the string is received

; on the stack.

; Registers

; used : r0, r1, sp

; modified : none

; Side effects : none

; Remarks : SP is left for the calling program to clear.

; Documentation :

; Register r1 is used to scan through the string, byte at a time.

; Register r0 is used to convert the character byte to a word that

; can be put on the stack before calling putc().

.CODE ; Code Segment.

print:

push r0

push r1

mov.w #0c[sp], r1 ; Get the pointer to the string.

begin0:

jeq @#end0 ; If end of string, exit loop

mov.b @r1+, r0 ; Convert character byte to word.

jsub @#putc

jump @#begin0

end0:

pop r1

pop r0

rsub

;_________________________________________________________________

.DATA ; Data Segment.

data:

.align.w

neg_tst: .string "Testing Negative flag..."

zip_tst: .string "Testing Zero flag..."

ovf_tst: .string "Testing Overflow flag..."

cry_tst: .string "Testing Carry flag..."

neg_msg: .string "Result is negative."

zip_msg: .string "Result is zero."

ovf_msg: .string "Result caused overflow."

cry_msg: .string "Result caused carry."

abs_msg: .string "Buy a new CPU."

cr_lf: .init.b 0a

.init.b 0d

.init.b 00

.END ; End of source file.

________________________________________________________________________________________

The next program shows how to use getc and putc system calls.

;========================================================================

; Filename: 7.13.8.4.asm

; Author: Grace Hopper

; Student #: 000 000 000

;

; Purpose: To test the putstr and getstr subroutines.

;

;========================================================================

.CODE

mov #prompt1, r1 ; prompt for a string

jsub @#putstr

mov #stringin, r1 ; set up the string address for getstr

jsub @#getstr ; get the string

mov #mesg1, r1 ; echo the string

jsub @#putstr

mov #stringin, r1

jsub @#putstr

mov #CRLF, r1 ; add a carriage return line feed

jsub @#putstr

halt

.DATA

prompt1: .string "Input a string: "

.ALIGN

mesg1: .STRING "This is what you entered: "

.ALIGN

stringin: .BLOCK 80

CRLF: .INIT 0A ; ascii value for line feed

.INIT 0D ; ascii for carriage return

;-------------------------- Subroutines ---------------------------------

;--------------------------- putstr --------------------------------

; Subroutine: putstr

; Author: Grace Hopper

; Purpose: to output a character string

; Arguments: r1 holds the address of the string to be printed

;-------------------------------------------------------------------

.CODE

putstr:

push r0 ; save register

putwhile:

mov.b @r1+, r0 ; While (char not a null)

jeq @#endput ;

jsub @#putc ; print the character

jump @#putwhile ; end while

endput:

pop r0 ; restore register

rsub

;--------------------------- getstr --------------------------------

; Subroutine: getstr

; Author: Grace Hopper

; Purpose: to input a character string

; Arguments: r1 holds the address of the string to be input

;-------------------------------------------------------------------

.CODE

getstr:

push r0 ; save register

getwhile:

jsub @#getc ; While (char not a line feed - 0A)

cmp.b r0,@#LF

jeq @#endget

mov.b r0,@r1+ ; store the character

jump @#getwhile ; end while

endget:

mov.b #0,@r1 ; append a null byte to the string

pop r0 ; restore register

rsub

.DATA

LF: .INIT.B 0A ; ascii for line feed

.END

The following program shows how to pass a parameter to a function via a register and obtain a return value via register.

The sign subroutine receives a parameter in the r1 register and returns a value in the r0 register.

;=========================================================================;
Filename: 	7.13.9.3.asm

; Author: Christian, Burt Berel. S.

; Student #: 123 456 789

;

; Purpose: Test the sign of a number.

;

;=========================================================================

.CODE ; Code Segment.

code:

; Main program.

mov #0ffffffff, r1 ; Comment out this one to test for +ve

mov #02, r1 ; Comment out this one to test for -ve

jsub @#sign

tst r0

jc.z @#its_neg

mov #pos_msg, r1 ; Pass pointer of string to putstr

jsub @#putstr

jump @#end

its_neg:

mov #neg_msg, r1 ; Pass pointer of string to putstr.

jsub @#putstr

end:

halt ; End of main program.

;_________________________________________________________________

;

; Subroutine : sign

; Purpose : Determines the sign of the input argument.

;_________________________________________________________________

; Arguments : The number is received in r1

; Return value : In r0, 0 if negative else 1

; Registers

; used : r0, r1

; modified : none

; Side effects : none

; Remarks : SP is left for the calling program to clear.

; Documentation :

; Register r1 is divided by two and remainder taken in r0

; If register r0 is zero we return right then. Otherwise, since

; we want to return 1 in r0 indicate that the number is not

; even, we divide r0 by itself and take the result in r0 which

; will always be one.

.CODE ; Code Segment.

sign:

clr r0

tst r1

jc.n @#negative

inc r0, r0

rsub

negative:

rsub

;--------------------------- putstr --------------------------------

; Subroutine: putstr

; Author: Grace Hopper

; Purpose: to output a character string

; Arguments: r1 holds the address of the string to be printed

;-------------------------------------------------------------------

.CODE

putstr:

push r0 ; save register

putwhile:

mov.b @r1+, r0 ; While (char not a null)

jeq @#endput ;

jsub @#putc ; print the character

jump @#putwhile ; end while

endput:

pop r0 ; restore register

rsub

;_________________________________________________________________

.DATA ; Data Segment.

data:

.align.w

neg_msg: .string "The number is negative."

pos_msg: .string "The number is positive."

.END ; End of source file.

__________________________________________________________________________

APPENDIX A: ANONYMOUS FTP

You may wish to obtain the files used as programming examples in this manual. To do this you must logon to your Hercules account, and then access the FTP program as an anonymous user. FTP will ask you to type in your username as the password. When you get on, then change to the subdirectory /pub/170/nurvman and then you can enter "dir" to see what files are there. Use the FTP 'get' command to get a copy of a file from the FTP area to your own account. Enter the 'quit' command to exit the FTP program.

An example follows:

hercules[2]% ftp ftp [Return]

220 mercury.cs.uregina.ca FTP server ready.

Name (ftp:username): anonymous [Return]

331 Guest login ok, type your name as password.

Password: . (enter your username here) . [Return]

230 Guest login ok, access restrictions apply.

ftp> cd /pub/170/nurvman [Return]

250 CWD command successful.

ftp> dir [Return]

200 PORT command successful.

150 Opening ASCII mode data connection for '/bin/ls'.

total 58

-rw-r--r-- 1 11021 archive file.asm

.

.

.

-rw-r--r-- 1 11021 archive file.asm

226 Transfer complete.

745 bytes received in 0.31 seconds (2.4 Kbytes/s)

ftp> get file.asm [Return]

200 PORT command successful.

150 Opening ASCII mode data connection for 'file.asm' (826 bytes).

226 Transfer complete.

local: file.asm remote: file.asm

868 bytes received in 0.091 seconds (9.4 Kbytes/s)

ftp> quit [Return]

221 Goodbye.

hercules[3]%

When you have completed these steps, a copy of the file you specified in the "get file.asm" instruction will be placed in your account.

You may wish to include one of the subroutines into your own program - if so, remember to credit the Nurve Users's Manual.

Suppose you had obtained the file "putnum.asm". To include this file in your program:

* edit your file

* move the cursor to the point in the program that you want the subroutine

* enter :r putnum.asm [Return]

* this tells the editor to read the file into the edit buffer

* now enter :wq [Return]

* assemble, link, and run your program as usual.

Note: There are periods (.) in the file names of the example programs in /pub/170/nurvman

Because of this, you will have to enter the complete file specification (including the extension) when you assemble, link, and run and example. Suppose you had copied the file 7.13.3.1.asm. You would have to enter:

nurve 7.13.3.1.asm [Return]

nlink 7.13.3.1.obj [Return]

nload 7.13.3.1.lmn [Return]

APPENDIX B. NURVE INSTRUCTION SET

This section contains a detailed explanation of each of the opcodes and macros previously presented in table form. In the preceding tables, opcodes and macros were listed by group, e.g. no operand, single operand, and so on.

This section presents the opcodes and macros in alphabetical order.


ADC. [WBH]
ADd Carry (dest) <- (srcA) plus (C bit)

Format: 3Bt0XXZZ ADC srcA, dest

Description: Add the Carry bit of PS register and source A into destination.

Condition Codes: N=Set if result < 0

Z=Set if result = 0

V=1 if XX is max_int(signed) and C=1

C=1 if XX is max_int(unsigned) and C=1

Example:

ADC r0, r0

ADC @r0, @r0


ADD. [WBH]
ADD (dest) <- (srcA) plus (srcB)

Format: 9txxyyzz ADD srcA, srcB, dest

Description: Add source A and source B into the destination.

Condition Codes: N=Set if result < 0

Z=Set if result = 0

V=set if both operands have same sign and

result has a different sign

C=Set if carry from MSB

Example:

ADD r0, #0a, r0

ADD @r0, @r1, @r2

ADD @r0, #0a, @r0

AND. [WBH]
AND (Bitwise logical ) (dest) <- (srcA) and (srcB)

Format: 4tXXYYZZ AND srcA, srcB, dest

Description: Clear the destination and set only those bits whose corresponding bits in both source A and source B are set (to one).

Condition Codes: N=Set if result < 0

Z=Set if result = 0

V=0

C=0

Example: AND r0, #0f, r0

ASH. [WBH]
Arithmetic SHift (dest) <- (srcB) shifted (srcA) times

Format: 8tXXYYZZ ASH count, srcB, dest

Description: The destination becomes source B shifted count times. If count is negative, the shift is towards the right. On a right shift the MSB is duplicated. If count is positive the shift is towards the left. On a left shift the LSB is cleared. The original contents of the destination are lost. The contents of the sources are not affected.

Condition Codes: N=Set if result < 0

Z=Set if result = 0

V=Set if sign changes during shift

C=Loaded with MSB on left shift, with LSB on right shift

Example:

ASH #04, r0, r0 ; shifts 4 bits to the left

ASH #0fffffffc,r0, r0 ; shifts 4 bits to the right

CLP. [IASTNZVC]
CLear Ps register bit(s)

Format: 000001pp CLP

Description: Selectively clear bits in the PS register.

Condition Codes: Indicated Condition code is cleared

Example: CLP.V

CLP.N

CLP.Z

CLP.C


CLR. [WBH]
CLeaR (dest) <- 0

Format: 1Dt000zz CLR dest

Description: The destination is set to zero.

Condition codes: N=0

Z=1

V=0

C=0

Example:

CLR r0

CLR @r0+

CMP. [WBH]
CoMPare (srcA) minus (srcB)

Format: 3Et0xxyy CMP srcA, srcB

Description: Compare the source and destination operands and set the PS condition codes, which may then be used for conditional branches. Both operands are unaffected even though the compare is actually done using subtraction.

Condition Codes: N=Set if result < 0

Z=Set if result = 0

V=set if arithmetic overflow.

C=set if carry from MSB.

Example:

CMP r0, #0a

CMP #0, r0

CMP @-r0, #0

CNV. [WBH] [WBH]
CoNVert (dest) <- (srcA)

Format: 3FttXXZZ CNV srcA, dest

Description: Copy source A into destination. XX and ZZ can be different sizes.

Condition Codes: N=Set if result < 0

Z=Set if result = 0

V=0

C=unaffected

Example:

CNV r0, r1

COM. [WBH]
COMplement (dest) <- flip bits of (srcA)

Format: 37t0XXZZ COM srcA, dest

Description: Place the one's complement of source A into the destination.

Condition Codes: N=Set if result < 0

Z=Set if result = 0

V=0

C=1

Example:

COM r0, r0

COM @r0, r1

DEC. [WBH]
DECrement (dest) <- (srcA) minus 1

Format: 3At0xxzz DEC srcA, dest

Description: Subtract 1 from source A and place in the destination.

Condition Codes: N=Set if result < 0

Z=Set if result = 0

V=1 if XX is min_int(signed)

C=unaffected

Example:

DEC r0, r0

DEC @r0

DIV. [WBH]
DIVide (dest) <- (srcA) divided by (srcB)

Format: Ctxxyyzz DIV srcA, srcB, dest

Description: Divide the source A operand by the source B operand and store the result in the destination.

Condition Codes: N=Set if result < 0

Z=Set if result = 0

V=set if abs(srcA) < abs(srcB)

C=set if srcB is zero

Example: DIV r0, #0a, r1

HALT
HALT

Format: 00000000 HALT

Description: Stop program execution.

Condition Codes: Not affected

Example: HALT


INC. [WBH]
INCrement (dest) <- (srcA) plus 1

Format: 39t0xxzz INC srcA, dest

Description: Destination becomes one plus source A.

Condition Codes: N=Set if result < 0

Z=Set if result = 0

V=1 if result is max.int (signed)

C=unaffected

Example:

INC r0, r0

INC @r0, @r0

JC. [IASTNZVC]
Jump if PS bit(s) Clear PC <- dest if indicated PS bit(s) cleared

Format: 20ppaaaa JC dest

Format: 21ppaaaa JC.* dest [ * special form * ]

Description: Jump to aaaa if indicated bit(s) in PS is(are) clear (zero). JC special, tests if N XOR V is zero. Other bits (especially the Z bit) can be tested along with the N and V bits.

Condition Codes: Not affected.

Example: JC.N @#begin0

JC.Z @#end0

JC.V @#err0

JC.C @#over0


JEQ
Jump if EQual PC <- dest if Z = 1

Format: 2204aaaa JEQ dest

Description: Jump to aaaa if PS Z bit is set, otherwise continue with the next instruction.

Condition Codes: Not affected.

Example: JEQ @#done0

JGE
Jump if Greater than or Equal signed PC <- dest if N v V = 1 or Z=1

Format: 210Aaaaa JGE dest

Description: Jump to aaaa if N exclusive or V is zero. In particular JGE will cause a branch if it follows a CMP instruction where the source A operand was greater than or equal to the source B operand, when they are treated as signed numbers.

Condition Codes: Not affected.

Example: JGE @#continue0


JGEU
Jump Greater than or Equal Unsigned PC <- dest if C bit is clear (zero)

Format: 2001aaaa JGEU dest

Description: Jump to aaaa if the C bit is zero. In particular JGEU will cause a branch if it follows a CMP instruction where the source A operand was greater than or equal to the source operand B, when they are treated as unsigned numbers.

Condition Codes: Not affected.

Example: JGEU @#over

JGT
Jump if Greater Than signed PC <- dest if Z = 0 and (N v V) = 0

Format: 210Eaaaa JGT dest

Description: Causes a branch if the Z bit is zero and the N and V bits are both the same. In particular, JGT will cause a branch if it follows a CMP instruction where the source A operand is greater than the source B operand, when they are treated as signed numbers.

Condition Codes: Not affected.

Example: JGT @#done0


JGTU
Jump Greater Than Unsigned PC <- dest if C = 0 and Z = 0

Format: 2005aaaa JGTU dest

Description: Causes a branch if both the Z and C bits are zero. In particular, JGTU will cause a branch if it follows a CMP instruction where the source A operand is greater than the source B operand, when they are treated as unsigned numbers.

Condition Codes: Not affected.

Example: JGTU @#trigger0


JLE
Jump if Less than or Equal signed PC <- dest if Z = 1 or (N v V) = 1

Format: 230Eaaaa JLE dest

Description: Causes a branch if the Z bit is set and the N bit is different from the V bit. In particular, JLE will branch if it follows a CMP instruction where the source A operand is less than or equal to the source B operand, when they are treated as signed numbers.

Condition Codes: Not affected.

Example: JLE @#begin0

JLEU
Jump Less than or Equal Unsigned PC <- dest if Z = 1 and C = 1

Format: 2205aaaa JLEU dest

Description: Causes a branch if both the Z and C bits are set. In particular, JLEU will branch if it follows a CMP instruction where the source operand A is less than or equal to the source B operand, when they treated as unsigned numbers.

Condition Codes: Not affected.

Example: JLEU @#finished0


JLT
Jump if Less Than signed PC <- dest if N v V = 1

Format: 230Aaaaa JLT dest

Description: Jump to aaaa if the N and V bits are different. In particular JLT will cause a branch if it follows a CMP instruction where the source A operand was less than the source B operand, when they are treated as signed numbers.

Condition Codes: Not affected.

Example: JLT @#end0

JLTU
Jump Less Than Unsigned PC <- dest if C = 1

Jump Less Than Unsigned

Operation: PC <- dest if C = 1

Format: 2201aaaa JLTU dest

Description: Jump to aaaa if the C bit is set. In particular JLTU will cause a branch if it follows a CMP instruction where the source A operand was less than the source B operand, when they are treated as unsigned numbers.

Condition Codes: Not affected.

Example: JLTU @#finished0

JMI
Jump if MInus PC <- dest if N = 1

Format: 2208aaaa JMI dest

Description: Jump to aaaa if the N bit is set, otherwise continue with the next instruction.

Condition Codes: Not affected.

Example: JMI @#bad_val0


JNE
Jump Not Equal PC <- dest if Z = 0

Format: 2004aaaa JNE dest

Description: Jump to aaaa if the Z bit is clear. JNE is the complementary operation to JEQ.

Condition Codes: Not affected.

Example: JNE @#continue0


JPL
Jump if PLus PC <- dest if N = 0

Format: 2008aaaa JPL dest

Description: Jump to aaaa if the N bit is clear, otherwise continue with the next instruction. JPL is the complimentary operation to JMI.

Condition Codes: Not affected.

Example: JPL @#start0

JS. [IASTNZVC]
Jump if PS bit(s) Set PC <- dest if indicated PS bit(s) set

Format: 22ppaaaa JS dest

Format: 23ppaaaa JS.* dest [ * special form * ]

Description: Jump to aaaa if indicated bit(s) in PS is(are) set (one). JS special, tests if N XOR V is one. Other bits (especially the Z bit) can be tested along with the N and V bits.

Condition Codes: Not affected.

Example: JS @#unusual0


JSUB
Jump to SUBroutine

Format: 2200aaaa JSUB dest

Operation: PUSH PC onto top of stack

PC <- dest

Description: This instruction causes a jump to the subroutine whose starting address is specified by aaaa. Upon return from the subroutine, execution will continue at the instruction following the JSUB instruction. During the execution of the JSUB, the old contents of the PC are first pushed onto the system stack before the dest is placed in the PC, causing the next instruction to be executed to be the first instruction in the subroutine. Subroutines nested within subroutines are allowed. The maximum number of such nested subroutines depends on the size of the stack.

Condition Codes: Not affected

Example: JSUB @#print

JSUB @#scanf

JSUB @#err0

JUMP
JUMP PC <- dest

Format: 2000aaaa JUMP dest

Description: Transfer program control to address aaaa.

Condition Codes: Not affected.

Example: JUMP @#end0

JUMP @#default0

MOD. WBH
MODulus (dest) <- (srcA) remainder (srcB)

MODulus

Operation: (dest) <- (srcA) remainder (srcB)

Format: Dtxxyyzz MOD srcA, srcB, dest

Description: Place the integer remainder of source A divided by source B into the destination.

Condition Codes: N=Set if result < 0

Z=Set if result = 0

V=Set if abs(srcA) < abs(srcB)

C=Set if srcB = 0

Example:

MOD r0, #02, r1

MOV. [WBH]
MOVe (dest) <- (srcA)

Format: 3Dt0xxzz MOV srcA, dest

Description: Move the source operand to the destination location. The previous contents of the destination are lost.

Condition Codes: N=Set if result < 0

Z=Set if result = 0

V=0

C=Unaffected

Example:

MOV r0, @r1

MOV @r0, @r1

MOV #base, r0

MOV @@r0, @-SP

MUL. [WBH]
MULtiply (dest) <- (srcA) times (srcB)

Format: Btxxyyzz MUL srcA, srcB, dest

Description: Multiply the source A operand by the source B operand and store the result in the destination.

NOTES: If operands are Byte, result is Half-word.

If operands are Half-word result is Word.

If operands are Word result is Word.

ex: MUL.B source is Bytes but destination is Halfword

ex: MUL.H source is Halfwords but destination is Word

Condition Code: N=Set if result < 0

Z=Set if result = 0

V=set if result < min(abs(XX),abs(YY))

C=0

Example:

MUL r0, #0a, r0


NEG. [WBH]
NEGate (dest) <- 0 minus (srcA)

Format: 38t0XXZZ NEG srcA, dest

Description: Place the two's complement of the source A operand into the destination.

Condition Codes: N=Set if result < 0

Z=Set if result = 0

V=1 if result = min_int (signed)

(min_int is 0x80 for BYTE, 0x8000 for Half and 0x80000000 for word)

C=1 if result = 0

Example:

NEG r0, r0

NEG @r0, r1

NOOP
NO OPeration

Format: 00000100 NOOP

Description: No operation is performed when this instruction is executed. This instruction is usually used by machine language programmers, who place a few NOOP's after every ten instructions or so. If new instructions have to be inserted at a later time, these NOOP's can be replaced with the new instructions.

Condition Codes: Not affected

Example: NOOP

OR. [WBH]
Bitwise OR (dest) <- (srcA) inclusive or with (srcB)

Format: 5tYYXXZZ OR srcA, srcB, dest

Description: Set all bits in the destination operand. Clear only those bits that are cleared in both the source operands.

Condition Codes: N=Set if result < 0

Z=Set if result = 0

V=0

C=0

Example:

OR r0, #0ffff0000, r0

OR r0, @r1, r0

POP. [WBH]
POP operand from the stack - this is a special case of the MOV instruction.

Operation: (dest) <- @SP

SP <- SP + 4

Format: 3Dt0xx5D POP dest

Description: The value at the location pointed to by the stack pointer is moved to the destination, then the stack pointer is incremented.

Condition Codes: N=Set if result < 0

Z=Set if result = 0

V=0

C=unaffected

Example:

POP r1


PUSH. [WBH]
PUSH operand onto the stack - this is a special case of the MOV instruction.

Operation: SP <- SP - 4

@SP <- (srcA)

Format: 3Dt06Dxx PUSH srcA

Description: The stack pointer is decremented then the source A operand is moved to the destination (pointed to by the stack pointer).

Condition Codes: N=Set if result < 0

Z=Set if result = 0

V=0

C=unaffected

Example:

PUSH r0


RISR
Return from Interrupt Service Routine

Format: 00000001 RISR

Operation: POP PC from stack

POP PS from stack

Description: Interrupt services routines are invoked by the NURVE machine when a (hardware or software) interrupt is signaled. The machine PUSHes the PS and PC registers onto the stack before loading the address of the ISR into the PC. I/O operations are performed using Interrupt Service Routines.

Condition Codes: Not affected.

Example: RISR


ROT. [WBH]
ROTate thru the C bit. (dest) <- (srcB) rotated (srcA) times

Format: 7tXXYYZZ ROT count, srcB, dest

Description: Copy the source B operand into the destination. If count is negative rotate right by shifting the C bit into the MSB and the LSB into the C bit. If count is positive rotate left by shifting the C bit into the LSB and the MSB into the C bit. Repeat this process count times.

Condition Codes: N=Set if result < 0

Z=Set if result = 0

V=N xor C

C=LSB (ROT right) or MSB (ROT left)

Example: ROT #04, r0, r0

ROT #0ffffffff, r0, r0


RSUB
Return from SUBroutine

Operation: POP top of stack into PC (PC <- @SP+)

Format: 3D006D0C RSUB

Description: The value on the top of the stack is popped and placed into the PC. Exit from a subroutine and resume execution at the instruction following the JSUB instruction, in the part of the program that called the subroutine.

Condition Codes: Not affected.

Example: RSUB

SBC. [WBH]
SuBtract Carry (dest) <- (srcA) minus (Carry)

Format: 3Ct0xxzz SBC srcA, dest

Description: Place the source A operand minus the Carry bit into the destination.

Condition Codes: N=Set if result < 0

Z=Set if result = 0

V=1 if srcA is min_int(signed) and C=1

C=0 if srcA is 0 and C=1

Example: SBC r0, r0

SEP. IASTNZVC]
SEt Ps register bit(s)

Format: 000002pp SEP dest

Condition Codes: Indicated Condition code is set

Example: SEP.N

SEP.Z

SEP.V

SEP.C


SUB. [WBH]
SUBtract (dest) <- (srcA) minus (srcB)

Format: Atxxyyzz SUB srcA, srcB, dest

Description: Subtract the source B operand from the source A operand and store the result at the destination address.

Condition Codes: N=Set if result < 0

Z=Set if result = 0

V=Set if operands have opposite signs and result has same sign as srcB.

C=Set if borrow from MSB

Example: SUB r0, #05, r0


TAS. [WH]
Test And Set (dest) <- (dest)

Format: 36t0xxzz TAS dest

Description: For TAS.W, copy the low halfword of the source A operand into the destination while setting the high halfword of destination to -1. For TAS.H, copy the low byte of the source A operand into the destination while setting the high byte of destination to -1.

Condition Codes: N=Set if dest.low halfword(byte) < 0

Z=Set if dest.low halfword(byte) = 0

V=0

C=0

Example: TAS.W r0

TAS.H r1

TST. [WBH]
TeST

Format: 1Et000xx TST srcA

Description: Set the N and Z bits according to the value of source A operand.

Condition Codes: N=Set if srcA < 0

Z=Set if srcA = 0

V=0

C=0

Example:

TST @r0+

TST @@r0

TST r0

TST @SP+

XCH. [WH]
eXCHange halfwords or bytes

high low high low

Operation: BYTE 1 BYTE 0 becomes BYTE 0 BYTE 1

Format: 35t0xxzz XCH srcA, dest

Description: If XCH.W, exchange the high-order halfword and low-order halfword of the source A operand and place in the destination. If XCH.H, exchange the high-order byte and low-order byte of the source A operand and place in the destination.

Condition Codes: N=Set result < 0

Z=Set if result = 0

V=0

C=0

Example: ; r1 contains: 12345678

XCH.W r1, r1 ; after this, r1 holds: 56781234

XCH.H r1, r1 ; after this, r1 has: 00003412

XOR. [WBH]
Bitwise XOR (dest) <- (srcA) v (srcB)

Format: 6tYYXXZZ XOR srcA, srcB, dest

Description: After setting all bits in the destination, clear only those bits in the destination that are the same in both source operands.

Condition Codes: N=Set if result < 0

Z=Set if result = 0

V=0

C=0

Example: XOR r0, #055555555, r0

XOR r0, r1, r0

APPENDIX C: NURVE PROGRAMMING CARD

NOTATION

LSB      Least Significant Bit.                               
MSB      Most Significant Bit.                                
LC       Assembler Location Counter                           
Rn       Register number (R0-RF).                             
         1 hex digit                                          
aaaa     16 bit address.                                      
         4 hex digits                                         
hhh      Hex number.                                          
pp       Processor Status Flag.  [I A S T N Z V C]    2 hex   
         digits                                               
t        Type of operand (0-2).  [W=0 B=1 H=2]      1 hex     
         digit                                                
xx       Mode + Register.  Source Operand A.           2      
         hex digits                                           
yy       Mode + Register.  Source Operand B.           2      
         hex digits                                           
zz       Mode + Register.  Destination Operand.        2      
         hex digits                                           
nn       2 digit hex number                                   
<-       becomes                                              
v        logical OR                                           
v        logical exclusive OR                                 

REGISTERS

PROCESSOR STATUS (PS) REGISTER BITS

PS BIT          Mask  Set = 1             Cleared = 0         
Interrupt   I    80   Interrupts          Interrupts          
                      enabled.            disabled.           
Addressing  A    40   Relative            Absolute            
                      addressing.         addressing.         
Supervisor  S    20   Supervisor mode.    User mode.          
Trace       T    10   Trace enabled.      Trace disabled.     
Negative    N    08   Result is           Non negative.       
                      negative.                               
Zero        Z    04   Result is zero.     Non zero.           
Overflow    V    02   Overflow resulted.  No overflow.        
Carry       C    01   Carry from MSB.     No carry.           

USER MEMORY AREA

THE 32 BIT NURVE WORD

ADDRESING MODES

 Mode            hex  Assembly  Description of Addressing Mode      
 Register         0      Rn      Register n is operand.             
Direct                                                              
 Register         1     @Rn     Register n is address of operand.   
Indirect                                                            
 Double           2     @@Rn    Rn is address of address of         
Indirect                        operand.                            
 Indexed          3     [Rn]    (Rn) + (@PC+) is address of         
                                operand.                            
 Indirect Pre     4     @+Rn    Increment register n.  Access @Rn.  
Inc                                                                 
 Indirect Pre     5     @-Rn    Decrement register n.  Access @Rn.  
Dec                                                                 
 Indirect Post    6     @Rn+    Access @Rn.  Increment register n.  
Inc                                                                 
 Indirect Post    7     @Rn-    Access @Rn.  Decrement register n.  
Dec                                                                 
 Double Pre Inc   8    @@+Rn     Increment register n.  Access      
                                @@Rn.                               
 Double Pre Dec   9    @@-Rn    Decrement register n.  Access       
                                @@Rn.                               
 Double Post      A    @@Rn+    Access @@Rn.  Increment register    
Inc                             n.                                  
 Double Post      B    @@Rn-    Access @@Rn.  Decrement register    
Dec                             n.                                  
 Indexed Pre      C    [+Rn]    Increment register n.  Access       
Inc                             [Rn].                               
 Indexed Pre      D    [-Rn]    Decrement register n.  Access       
Dec                             [Rn].                               
 Indexed Post     E    [Rn+]    Access [Rn].  Increment register    
Inc                             n.                                  
 Indexed Post     F    [Rn-]     Access [Rn].  Decrement register   
Dec                             n.                                  

PC ADDRESING MODES

 Immediate      #hhh    @PC+      6C       Constant (number)        
    mode                                   follows the              
                                           instruction.             
  Absolute     @#hhh    @@PC+     AC       Address of operand       
    mode                                   follows the              
                                           instruction.             

NO OPERAND

00000000     HALT               Halt process                      
00000001     RISR               Return from interrupt service     
                                routine                           

SINGLE OPERAND

000001pp     CLP.  IASTNZVC     Clear PS Register bit(s).         
000002pp     SEP.  IASTNZVC     Set PS Register bit(s).           
1Dt000zz     CLR.   WBH         Clear (zero) the destination.     
1Et000xx     TST.    WBH        Set PS register relative to       
                                zero.                             

JUMP INSTRUCTIONS

20ppaaaa     JC.     IASTNZVC   Jump if PS bit(s) clear.          
21ppaaaa     JC.     *          Jump if PS bit(s) clear           
                                (special).                        
22ppaaaa     JS.     IASTNZVC   Jump if PS bit(s) set.            
2200aaaa     JSUB               Jump SUBroutine.                  
23ppaaaa     JS.     *          Jump if PS bit(s) set (special).  

DOUBLE OPERAND

35t0xxzz     XCH.    WH         Exchange Halfwords/Bytes.         
36t0xxzz     TAS.     WH        Test and Set.                     
37t0xxzz     COM.    WBH        One's Complement.  (Flip bits.)   
38t0xxzz     NEG.    WBH        Negate.  (Two's Complement.)      
39t0xxzz     INC.     WBH       Increment.  (Add 1.)              
3At0xxzz     DEC.    WBH        Decrement.  (Subtract 1.)         
3Bt0xxzz     ADC.    WBH        Add Carry bit.                    
3Ct0xxzz     SBC.    WBH        Subtract Carry bit.               
3Dt0xxzz     MOV.   WBH         Move. (Copy.)                     
3Et0xxyy     CMP.   WBH         Compare xx-yy and set PS          
                                register.                         
3Fttxxzz     CNV.    WB WH      Convert size of xx to size of     
             BW BH  HW HB       yy.                               

TRIPLE OPERAND

4txxyyzz     AND.    WBH        Logical bitwise AND.              
5txxyyzz     OR.       WBH      Logical bitwise OR.               
6txxyyzz     XOR.    WBH        Logical bitwise XOR (exclusive    
                                or).                              
7txxyyzz     ROT.     WBH       Rotate (through the Carry bit).   
8txxyyzz     ASH.     WBH       Arithmetic Shift.                 
9txxyyzz     ADD.     WBH       Add.        zz <- xx + yy.        
Atxxyyzz     SUB.     WBH       Subtract.  zz <- xx - yy.         
Btxxyyzz     MUL.    WBH        Multiply.  zz <- xx * yy.         
Ctxxyyzz     DIV.      WBH      Divide.     zz <- xx / yy.        
Dtxxyyzz     MOD.    WBH        Modulo.   zz <- remainder( xx /   
                                yy )                              

MACROS

00000100     NOOP = CLP         NO OPeration.                     
2000aaaa     JUMP  = JC         Unconditional Jump.               
2001aaaa     JGEU  = JC.C       Jump > or = Unsigned              
2004aaaa     JNE   = JC.Z       Jump Not =                        
2005aaaa     JGTU = JC.CZ       Jump > Unsigned                   
2008aaaa     JPL  = JC.N        Jump PLus                         
210Aaaaa     JGE  = JC.N*V      Jump > or = signed                
210Eaaaa     JGT = JC.ZN*V      Jump > signed                     
2201aaaa     JLTU  = JS.C       Jump < Unsigned                   
2204aaaa     JEQ     = JS.Z     Jump =                            
2205aaaa     JLEU  = JS.CZ      Jump < or = Unsigned              
2208aaaa     JMI     = JS.N     Jump MInus                        
230Aaaaa     JLT     = JS.N*V   Jump < signed                     
230Eaaaa     JLE     = JS.ZN*V  Jump < or = signed                
3D006D0C     RSUB               Return from SUBroutine.           
3Dt0xx5D     PUSH.  WBH         @-SP <- xx                        
3Dt06Dzz     POP.     WBH       zz <- @SP+                        


OPCODES IN NUMERIC ORDER

             .ALIGN. WBH         Align LC on boundary              
             .BLOCK. WBH         Reserve storage                   
             .CODE               Position LC in CODE area          
             .DATA               Position LC in HEAP area          
             .END                End of program.                   
             .INIT. WBH          Initialize storage                
 00000000    HALT                Halt process                      
 00000001    RISR                Return from interrupt routine.    
 00000100    NOOP = CLP          No Operation.                     
 000001pp    CLP. IASTNZVC       Clear PS Register bit(s).         
 000002pp    SEP. IASTNZVC       Set PS Register bit(s).           
 1Dt000zz    CLR. WBH            Clear (zero) the destination.     
 1Et000xx    TST. WBH            Set PS register relative to #0.   
 2000aaaa    JUMP = JC           Unconditional Jump.               
 2001aaaa    JGEU = JC.C         Jump > or = Unsigned              
 2004aaaa    JNE  = JC.Z         Jump Not =                        
 2005aaaa    JGTU = JC.CZ        Jump > Unsigned                   
 2008aaaa    JPL  = JC.N         Jump PLus                         
 20ppaaaa    JC. IASTNZVC        Jump if PS bit(s) clear.          
 210Aaaaa    JGE  = JC.N*V       Jump > or = signed                
 210Eaaaa    JGT  = JC.ZN*V      Jump > signed                     
 21ppaaaa    JC. *               Jump if PS bit(s) clear           
                                 (special).                        
 2200aaaa    JSUB                Jump SUBroutine.                  
 2201aaaa    JLTU = JS.C         Jump < Unsigned                   
 2204aaaa    JEQ  = JS.Z         Jump =                            
 2205aaaa    JLEU = JS.CZ        Jump < or = Unsigned              
 2208aaaa    JMI  = JS.N         Jump MInus                        
 22ppaaaa    JS. IASTNZVC        Jump if PS bit(s) set.            
 230Aaaaa    JLT  = JS.N*V       Jump < signed                     
 230Eaaaa    JLE  = JS.ZN*V      Jump < or = signed                
 23ppaaaa    JS. *               Jump if PS bit(s) set (special).  
 35t0xxzz    XCH. WH             Exchange Halfwords/Bytes.         
 36t0xxzz    TAS. WH             Test and Set.                     
 37t0xxzz    COM. WBH            Complement.                       
 38t0xxzz    NEG. WBH            Negate.                           
 39t0xxzz    INC. WBH            Increment.                        
 3At0xxzz    DEC. WBH            Decrement.                        
 3Bt0xxzz    ADC. WBH            Add carry.                        
 3Ct0xxzz    SBC. WBH            Subtract carry.                   
 3D006D0C    RSUB                Return from subroutine.           
 3Dt06Dzz    POP.  WBH           zz <- @SP+                        
 3Dt0xx5D    PUSH. WBH           @-SP <- xx                        
 3Dt0xxzz    MOV. WBH            Move (copy).                      
 3Et0xxyy    CMP. WBH            Compare. xx-yy & set PS register  
 3Fttxxzz    CNV. WBH WBH        Convert size of xx to size of yy  
 4txxyyzz    AND. WBH            Logical bitwise AND.              
 5txxyyzz    OR.  WBH            Logical bitwise OR.               
 6txxyyzz    XOR. WBH            Logical bitwise XOR (exculsive    
                                 or).                              
 7txxyyzz    ROT. WBH            Rotate.                           
 8txxyyzz    ASH. WBH            Arithmetic Shift.                 
 9txxyyzz    ADD. WBH            Add.       zz <- xx + yy.         
 Atxxyyzz    SUB. WBH            Subtract.  zz <- xx - yy.         
 Btxxyyzz    MUL. WBH            Multiply.  zz <- xx * yy.         
 Ctxxyyzz    DIV. WBH            Divide.    zz <- xx / yy.         
 Dtxxyyzz    MOD. WBH            Modulo.  zz <- remainder (xx /    
                                 yy).                              

OPCODES IN ALPHABETICAL ORDER

             .ALIGN. WBH         Align LC on boundary              
             .BLOCK. WBH         Reserve storage                   
             .CODE               Position LC in CODE area          
             .DATA               Position LC in HEAP area          
             .END                End of program.                   
             .INIT. WBH          Initialize storage                
 3Bt0xxzz    ADC. WBH            Add carry.                        
 9txxyyzz    ADD. WBH            Add.       zz <- xx + yy.         
 4txxyyzz    AND. WBH            Logical bitwise AND.              
 8txxyyzz    ASH. WBH            Arithmetic Shift.                 
 000001pp    CLP. IASTNZVC       Clear PS Register bit(s).         
 1Dt000zz    CLR. WBH            Clear (zero) the destination.     
 3Et0xxyy    CMP. WBH            Compare. xx-yy & set PS           
                                 register.                         
 3Fttxxzz    CNV. WBH WBH        Convert size of xx to size of yy  
 37t0xxzz    COM. WBH            Complement.                       
 3At0xxzz    DEC. WBH            Decrement.                        
 Ctxxyyzz    DIV. WBH            Divide.    zz <- xx / yy.         
 00000000    HALT                Halt process                      
 39t0xxzz    INC. WBH            Increment.                        
 21ppaaaa    JC. *               Jump if PS bit(s) clear           
                                 (special).                        
 20ppaaaa    JC. IASTNZVC        Jump if PS bit(s) clear.          
 2204aaaa    JEQ  = JS.Z         Jump EQual                        
 210Aaaaa    JGE  = JC.N*V       Jump > or = signed                
 2001aaaa    JGEU = JC.C         Jump > or = Unsigned              
 210Eaaaa    JGT  = JC.ZN*V      Jump > signed                     
 2005aaaa    JGTU = JC.CZ        Jump > Unsigned                   
 230Eaaaa    JLE  = JS.ZN*V      Jump < or = signed                
 2205aaaa    JLEU = JS.CZ        Jump < or = Unsigned              
 230Aaaaa    JLT  = JS.N*V       Jump < signed                     
 2201aaaa    JLTU = JS.C         Jump < Unsigned                   
 2208aaaa    JMI  = JS.N         Jump MInus                        
 2004aaaa    JNE  = JC.Z         Jump Not =                        
 2008aaaa    JPL  = JC.N         Jump PLus                         
 23ppaaaa    JS. *               Jump if PS bit(s) set (special).  
 22ppaaaa    JS. IASTNZVC        Jump if PS bit(s) set.            
 2200aaaa    JSUB                Jump SUBroutine.                  
 2000aaaa    JUMP = JC           Unconditional Jump.               
 Dtxxyyzz    MOD. WBH            Modulo.  zz <- remainder (xx /    
                                 yy).                              
 3Dt0xxzz    MOV. WBH            Move (copy).                      
 Btxxyyzz    MUL. WBH            Multiply.  zz <- xx * yy.         
 38t0xxzz    NEG. WBH            Negate.                           
 00000100    NOOP = CLP          No Operation.                     
 5txxyyzz    OR.  WBH            Logical bitwise OR.               
 3Dt06Dzz    POP.  WBH           zz <- @SP+                        
 3Dt0xx5D    PUSH. WBH           @-SP <- xx                        
 00000001    RISR                Return from interrupt routine.    
 7txxyyzz    ROT. WBH            Rotate.                           
 3D006D0C    RSUB                Return from subroutine.           
 3Ct0xxzz    SBC. WBH            Subtract carry.                   
 000002pp    SEP. IASTNZVC       Set PS Register bit(s).           
 Atxxyyzz    SUB. WBH            Subtract.  zz <- xx - yy.         
 36t0xxzz    TAS. WH             Test and Set.                     
 1Et000xx    TST. WBH            Set PS register relative to #0.   
 35t0xxzz    XCH. WH             Exchange Halfwords/Bytes.         
 6txxyyzz    XOR. WBH            Logical bitwise XOR (exculsive    
                                 or).                              

HEX ASCII TABLE

MSB

 LSB    0      1      2      3      4      5      6      7      
  0     NUL    DLE    SP     0      @      P      `      p      
  1     SOH    DC1    !      1      A      Q      a      q      
  2     STX    DC2    "      2      B      R      b      r      
  3     ETX    DC3    #      3      C      S      c      s      
  4     EOT    DC4    $      4      D      T      d      t      
  5     ENQ    NAK    %      5      E      U      e      u      
  6     ACK    SYN    &      6      F      V      f      v      
  7     BEL    ETB    '      7      G      W      g      w      
  8     BS     CAN    (      8      H      X      h      x      
  9     HT     EM     )      9      I      Y      i      y      
  A     LF     SUB    *      :      J      Z      j      z      
  B     VT     ESC    +      ;      K      [      k      {      
  C     FF     FS     ,      <      L      \      l      |      
  D     CR     GS     -      =      M      ]      m      }      
  E     SO     RS     .      >      N      ^      n      ~      
  F     SI     US     /      ?      O      _      o      DEL    

eg: B = 42 hex

TABLE OF CONTENTS

NOTATION 1

REGISTERS 1

PROCESSOR STATUS (PS) REGISTER BITS 1

USER MEMORY AREA 2

THE 32 BIT NURVE WORD 2

INSTRUCTION FORMATS 2

ADDRESSING MODES 2

PC ADDRESSING MODES 2

INSTRUCTION SET 3

NO OPERAND 3

SINGLE OPERAND 3

DOUBLE OPERAND 3

TRIPLE OPERAND 3

MACROS 3

OPCODES IN NUMERIC ORDER 4

OPCODES IN ALPHABETICAL ORDER 5

HEX ASCII TABLE 6

TABLE OF CONTENTS 6