Skip to content

NORD-500 Assembler Expert Guide

Advanced NORD-500 Assembly Language Programming

Version: 1.0
Date: October 18, 2025
Status: Complete - Expert Level

Prerequisites: Complete NORD-500-ASSEMBLER-DEVELOPER-GUIDE.md first


Table of Contents

  1. Introduction to Expert-Level Programming
  2. Complete Directive Reference
  3. Advanced Addressing Modes
  4. Register Architecture and Usage
  5. Stack Frame Techniques
  6. Record Structures in Depth
  7. Complete Instruction Set
  8. Macro Programming
  9. Conditional Assembly
  10. Expression Evaluation
  11. Module Organization Strategies
  12. Integration with NORD-100
  13. Performance Optimization
  14. Advanced Patterns
  15. Real-World Examples
  16. Debugging and Troubleshooting

1. Introduction to Expert-Level Programming

1.1 Expert Guide Scope

This guide assumes you have: - ✅ Completed the Developer Guide - ✅ Written several NORD-500 assembly programs - ✅ Understanding of assembly language concepts - ✅ Familiarity with NORD-500 CPU architecture

What this guide adds: - Complete technical reference for all features - Advanced programming techniques - Optimization strategies - Complex real-world patterns - Integration techniques - Production-level code organization

1.2 NORD-500 vs Other Assemblers

Comparison matrix:

Feature MAC (ND-100) NORD-500 ASM x86 ASM ARM ASM
Structured modules ❌ ✅ ❌ ⚠️
Built-in stack frames ❌ ✅ ❌ ❌
Record types ❌ ✅ ❌ ❌
Type system ⚠️ ✅ ⚠️ ⚠️
Macro system ✅ ✅ ✅ ✅
Conditional assembly ⚠️ ✅ ✅ ✅

2. Complete Directive Reference

2.1 Declaration Directives

2.1.1 MODULE and ENDMODULE

Full syntax:

MODULE [module-name [',' priority [',' language-code]]]
    % ... module content ...
ENDMODULE [module-name]

Parameters: - module-name: Identifier, optional, used in listing header - priority: 0-255, affects load order, default 0 - language-code: 0=Assembly, 1=FORTRAN, 2=PLANC, default 0

Priority usage:

MODULE INIT, 1          % High priority (loaded first)
MODULE MAIN, 128        % Medium priority
MODULE UTILITIES, 255   % Low priority (loaded last)

Language code effects: - Passed to linker/loader - Affects runtime initialization - Used by debuggers

Nesting: MODULES cannot be nested. Each source file should contain exactly one MODULE.

2.1.2 IMPORT-P and IMPORT-D

Purpose: Declare external symbols

Syntax:

IMPORT-P identifier [',' identifier...]    % Program addresses
IMPORT-D identifier [',' identifier...]    % Data addresses

Examples:

% Import procedures
IMPORT-P SQRT, SIN, COS, PRINTF

% Import data
IMPORT-D GLOBAL_COUNTER, SYSTEM_TABLE

% Must not be defined in current module
% Can be used immediately after declaration

Best practices:

% Group imports by module of origin
IMPORT-P MATHLIB_INIT, MATHLIB_SQRT      % From MATHLIB
IMPORT-P IO_OPEN, IO_CLOSE, IO_READ      % From IOLIB

% Use meaningful names
IMPORT-D SYS_CONFIG, USER_PREFS          % Clear purpose

2.1.3 EXPORT

Purpose: Make symbols available to other modules

Syntax:

EXPORT identifier [',' identifier...]

Rules: - Symbol must be defined in current module - Can export both program and data addresses - Exported symbols become globally visible

Example:

MODULE MATHLIB

% Internal symbols (not exported)
INTERNAL_BUFFER: W BLOCK 100

% Public API (exported)
EXPORT MATH_INIT, MATH_SQRT, MATH_POW
EXPORT MATH_ERRNO                        % Error code

MATH_INIT:
    % Initialization code
    RET

MATH_SQRT:
    % Square root implementation
    RET

MATH_ERRNO: W BLOCK 1                    % Error status

ENDMODULE

2.1.4 MAIN

Purpose: Specify program entry point

Syntax:

MAIN identifier

Rules: - Exactly one MAIN per program (not per module) - Identifier must be program address in current module - Does not need to be EXPORTED - Used by loader to determine start address

Example:

MODULE PROGRAM

MAIN START                               % Program starts here

START:
    CALL INIT, 0
    CALL MAIN_LOOP, 0
    RET                                  % Stop program

ENDMODULE

2.1.5 LIB

Purpose: Conditional loading (library modules)

Syntax:

LIB identifier [',' identifier...]

Behavior: - Module is loaded ONLY if one or more symbols are undefined - If all symbols defined, entire module is skipped - Used for library management

Example:

MODULE MATHLIB

% Only load if SQRT or POW needed
LIB SQRT, POW

SQRT:
    % Implementation
    RET

POW:
    % Implementation
    RET

ENDMODULE

Use case:

% In library file STDLIB:NRF with multiple modules:

% Module 1 - always loaded
MODULE CORE
    % Core functions
ENDMODULE

% Module 2 - loaded only if SQRT referenced
MODULE MATH
    LIB SQRT
    SQRT: % implementation
ENDMODULE

% Module 3 - loaded only if PRINTF referenced
MODULE IO
    LIB PRINTF
    PRINTF: % implementation
ENDMODULE

2.1.6 ALIAS

Purpose: Define external symbol representation

Syntax:

identifier ':' ALIAS string-expression

Use cases:

1. Generate illegal identifiers:

ROUTINE CLOSE
CLOSE: ALIAS '++CLOSE'                   % Name for other languages
CLOSE: ENTD
    % Implementation
ENDROUTINE

2. Create unique names:

MYLIBRARY_INIT: ALIAS '$MYLIB$INIT$V1'

3. Language interoperability:

% For PLANC operators
OPERATOR_PLUS: ALIAS '++'
OPERATOR_MULT: ALIAS '**'

2.1.7 ROUTINE and ENDROUTINE

Purpose: Define subroutine scope

Syntax:

ROUTINE entry-point [',' entry-point...]
    % Local declarations
    % Code
ENDROUTINE

Characteristics: - Entry points are global labels - All other labels are local to routine - Local symbols auto-removed after ENDROUTINE - Cannot nest ROUTINE directives

Full example:

MODULE EXAMPLE

% Global data
GLOBAL_COUNT: W DATA 0

ROUTINE PROCESS, INIT, CLEANUP

% These are local to routine
LOCAL_BUFFER: W BLOCK 100
TEMP_VAR: W BLOCK 1

PROCESS:                                 % Global entry point
    W1 := IND(GLOBAL_COUNT)
    W1 := LOCAL_BUFFER                   % Local data
    GO HELPER                            % Local label

INIT:                                    % Global entry point
    % Initialize
    RET

CLEANUP:                                 % Global entry point
    % Cleanup
    RET

HELPER:                                  % Local label
    % Helper code
    RET

ENDROUTINE
% LOCAL_BUFFER, TEMP_VAR, HELPER no longer accessible

ENDMODULE

2.1.8 STACK and ENDSTACK

Purpose: Define stack frame

Syntax 1 - Fixed (static):

[label:] STACK FIXED
    % Data allocation (with initialization)
ENDSTACK

Syntax 2 - Dynamic:

STACK
    % Data allocation (no initialization)
ENDSTACK

Stack header (first 20 bytes):

Offset Name Size Description
0 PREVB 4 bytes Saved B-register
4 RETA 4 bytes Return address
8 SP 4 bytes Stack pointer (next frame)
12 AUX 4 bytes System cell
16 NARG 4 bytes Number of arguments

Location counter: - #SCLC = 20 at start of STACK - Increments with each allocation - After ENDSTACK, #SCLC = total size

Fixed stack example:

LOCALS: STACK FIXED
    COUNTER: W DATA 0                    % Initialized
    MAX: W DATA 100
    BUFFER: W BLOCK 50                   % Zeroed
ENDSTACK

ROUTINE:
    ENTF LOCALS, 0                       % Use fixed stack
    W1 := B.COUNTER
    W2 := B.MAX
    RET

Dynamic stack example:

ROUTINE COMPUTE

STACK
    PARAM1: W BLOCK 1                    % Offset 20
    PARAM2: W BLOCK 1                    % Offset 24
    LOCAL1: W BLOCK 1                    % Offset 28
    LOCAL2: W BLOCK 1                    % Offset 32
ENDSTACK                                 % #SCLC now = 36

COMPUTE:
    ENTS #SCLC                           % Allocate 36 bytes
    W1 := IND(B.PARAM1)                  % Access parameter
    W2 := B.LOCAL1                       % Access local
    RET

ENDROUTINE

Advanced: Nested structures in stack:

STACK FIXED
    % Record inside stack
    RECORD
        FIELD1: W BLOCK 1
        FIELD2: W BLOCK 1
    ENDRECORD

    NODE: W BLOCK #RCLC                  % Allocate record size
ENDSTACK

2.1.9 RECORD and ENDRECORD

Purpose: Define data structure template

Syntax:

[label:] RECORD [FIXED]
    % Field definitions
ENDRECORD

Differences from STACK: - No 20-byte header - Offsets start at 0 - Accessed via R-register - #RCLC tracks size

Record definition (template):

% Define structure layout
RECORD
    NEXT: W BLOCK 1                      % Offset 0
    PREV: W BLOCK 1                      % Offset 4
    DATA: W BLOCK 1                      % Offset 8
    FLAGS: W BLOCK 1                     % Offset 12
ENDRECORD
% #RCLC now = 16 (size of record)

Record instantiation:

% Allocate actual record
NODE1: RECORD FIXED
    NEXT: W DATA 0
    PREV: W DATA 0
    DATA: W DATA 12345
    FLAGS: W DATA 0
ENDRECORD

Access via R-register:

R := ADDR(NODE1)                         % R points to record
W1 := R.NEXT                             % Load NEXT field
W2 := R.DATA                             % Load DATA field
W3 := R.FLAGS                            % Load FLAGS field

Complex record with nested structures:

RECORD
    % Header
    TYPE: W BLOCK 1
    SIZE: W BLOCK 1

    % Nested record
    RECORD
        X: W BLOCK 1
        Y: W BLOCK 1
        Z: W BLOCK 1
    ENDRECORD
    COORDS: W BLOCK #RCLC                % 12 bytes for coordinates

    % Array
    DATA: W BLOCK 100                    % 400 bytes
ENDRECORD
% #RCLC = 4 + 4 + 12 + 400 = 420

2.1.10 EQU and SEQU

Purpose: Define constants

EQU (numeric constant):

identifier ':' EQU expression

SEQU (string constant):

identifier ':' SEQU string-expression

Examples:

% Numeric constants
BUFFER_SIZE: EQU 1024
MAX_USERS: EQU 100
TIMEOUT: EQU 30 * 60                     % 30 minutes in seconds

% Derived constants
BUFFER_END: EQU BUFFER_START + BUFFER_SIZE

% String constants
VERSION: SEQU 'V1.0.3'
COPYRIGHT: SEQU 'Copyright 2025'
ERROR_MSG: SEQU 'ERROR: Invalid input'

% Use in code
BUFFER: W BLOCK BUFFER_SIZE              % Use as size
MSG: BY DATA VERSION                     % Use string

% Expression constants
MASK_LOW: EQU 0FFH
MASK_HIGH: EQU MASK_LOW SHIFT 8

Constant naming conventions:

% All caps for constants
MAX_SIZE: EQU 1000
DEFAULT_TIMEOUT: EQU 60

% Prefix for related constants
IO_READ: EQU 1
IO_WRITE: EQU 2
IO_SEEK: EQU 3

NET_TCP: EQU 1
NET_UDP: EQU 2


2.2 Data Allocation Directives

2.2.1 BLOCK

Purpose: Reserve uninitialized space

Syntax:

[label:] [type] BLOCK count

Examples:

BUFFER: W BLOCK 100                      % 400 bytes (100 words)
TEMP: BY BLOCK 256                       % 256 bytes
FLAGS: BI BLOCK 32                       % 32 bits (4 bytes)
MATRIX: F BLOCK 100                      % 400 bytes (100 floats)

In fixed structures:

STACK FIXED
    LOCALS: W BLOCK 10                   % Initialized to zero
ENDSTACK

In dynamic structures:

STACK
    WORKSPACE: W BLOCK 100               % Not initialized
ENDSTACK

2.2.2 DATA and PROG

Purpose: Define initialized data

Syntax:

[label:] [type] DATA value [',' value...]

Examples:

% Single values
COUNT: W DATA 0
PI: F DATA 3.14159
NAME: BY DATA 'JOHN DOE'

% Multiple values
TABLE: W DATA 10, 20, 30, 40, 50
PRIMES: W DATA 2, 3, 5, 7, 11, 13

% Mixed
HEADER: W DATA 100, ADDR(BUFFER), 256

PROG (program address data):

JUMP_TABLE: PROG ROUTINE1, ROUTINE2, ROUTINE3

% Use in computed jump
W1 := JUMP_TABLE(W2)                     % Load address
GO IND(W1)                               % Jump to routine

2.2.3 DESC (Descriptor)

Purpose: Define array descriptor

Syntax:

[label:] DESC count, base-address

Structure: - Word 1: Array bounds (count) - Word 2: Base address

Example:

ARRAY_DATA: W BLOCK 100                  % Actual array
ARRAY_DESC: DESC 100, ARRAY_DATA         % Descriptor

% Use descriptor
W1 := DESC(ARRAY_DESC)(W2)               % Access element

Dynamic descriptors:

% Build descriptor at runtime
W1 := 100                                % Count
W2 := ADDR(BUFFER)                       % Address
W1 := DESCRIPTOR                         % Store count
W2 := DESCRIPTOR + 4                     % Store address

2.2.4 ARRAY and STRING

Purpose: Define typed arrays

ARRAY syntax:

[label:] [type] ARRAY '[' bounds ']'

Examples:

% Single dimension
VECTOR: W ARRAY [100]                    % 100 words

% Multi-dimension syntax (if supported)
MATRIX: W ARRAY [10, 10]                 % 10x10 matrix

STRING (byte array):

MESSAGE: STRING [80]                     % 80-byte string buffer

2.2.5 ARRAYDATA and STRINGDATA

Purpose: Define initialized arrays

ARRAYDATA:

TABLE: W ARRAYDATA 10, 20, 30, 40
FLOATS: F ARRAYDATA 1.0, 2.0, 3.0

STRINGDATA:

TEXT: STRINGDATA 'HELLO WORLD'
PROMPT: STRINGDATA 'Enter name: '


2.3 Location Counter Control

2.3.1 ORG-P and ORG-D

Purpose: Set location counters

ORG-P (program):

ORG-P expression                         % Set program counter

ORG-D (data):

ORG-D expression                         % Set data counter

Use cases:

1. Absolute positioning:

ORG-P 1000H                              % Start code at 0x1000
START:
    % Code here

ORG-D 2000H                              % Start data at 0x2000
BUFFER: W BLOCK 100

2. Creating gaps:

TABLE1: W BLOCK 100
ORG-D #DCLC + 100                        % Skip 100 bytes
TABLE2: W BLOCK 100

Caution: ORG can create overlay issues. Use carefully.

2.3.2 BOUND-P and BOUND-D

Purpose: Align location counters

Syntax:

BOUND-P alignment
BOUND-D alignment

Common alignments:

BOUND-D 4                                % Word alignment
BOUND-D 8                                % Double-word alignment
BOUND-P 16                               % Paragraph alignment

Example:

BY DATA 1, 2, 3                          % 3 bytes
BOUND-D 4                                % Align to word
WORD_DATA: W DATA 100                    % Word-aligned


2.4 Miscellaneous Directives

Complete list:

Directive Purpose
MODULE/ENDMODULE Module scope
IMPORT-P/IMPORT-D External references
EXPORT Public symbols
MAIN Program entry
LIB Conditional loading
ALIAS Symbol renaming
ROUTINE/ENDROUTINE Subroutine scope
STACK/ENDSTACK Stack frame
RECORD/ENDRECORD Data structure
EQU/SEQU Constants
BLOCK Reserve space
DATA/PROG Initialize data
DESC Array descriptor
ARRAY/STRING Typed arrays
ARRAYDATA/STRINGDATA Initialized arrays
ORG-P/ORG-D Set location counter
BOUND-P/BOUND-D Align location counter

3. Advanced Addressing Modes

3.1 Complete Addressing Mode Reference

The NORD-500 supports 10 addressing modes plus 2 prefixes:

# Mode Syntax Example
1 Register Rn W1 := W2
2 Constant value W1 := 100
3 Local B.disp W1 := B.20
4 Local Post-Indexed B.disp(Wn) W1 := B.20(W2)
5 Local Indirect IND(B.disp) W1 := IND(B.20)
6 Local Indirect Post-Indexed IND(B.disp)(Wn) W1 := IND(B.20)(W2)
7 Record R.disp W1 := R.4
8 Pre-Indexed Rn.disp W1 := W2.8
9 Absolute label W1 := GLOBAL
10 Absolute Post-Indexed label(Wn) W1 := TABLE(W2)
+1 Descriptor DESC(operand)(Rn) W1 := DESC(ARRAY)(W2)
+2 Alternative ALT(operand) W1 := ALT(VAR)

3.2 Register Addressing

Direct register access:

W1 := W2                                 % Copy W2 to W1
F1 := F2                                 % Copy float register
D1 := D2                                 % Copy double register

Register selection: - W1-W4: Word (32-bit integer) accumulators - F1-F4: Float (32-bit) accumulators - D1-D4: Double (64-bit) accumulators - R1-R4: General purpose (can be any type)

Type compatibility:

% Correct
W1 := W2                                 % Word to word
F1 := F2                                 % Float to float

% Type conversion
W1 := F1                                 % Float to word (reinterpret)
F WCONV W1, F1                           % Convert word to float

3.3 Constant Addressing

Immediate values:

W1 := 12345                              % Decimal
W1 := 0FFH                               % Hexadecimal
W1 := 177B                               % Octal
W1 := 11110000X                          % Binary
F1 := 3.14159                            % Float

Size optimization: - Assembler selects optimal encoding - Can force size with :S, :B, :H, :W

W1 := 10:S                               % Short (6-bit)
W1 := 100:B                              % Byte (8-bit)
W1 := 1000:H                             % Half-word (16-bit)
W1 := 100000:W                           % Word (32-bit)

3.4 Local Addressing (B-relative)

Basic local access:

STACK
    VAR1: W BLOCK 1                      % Offset 20
    VAR2: W BLOCK 1                      % Offset 24
ENDSTACK

ROUTINE:
    ENTS #SCLC
    W1 := B.VAR1                         % Load from stack
    W1 := B.VAR2                         % Store to stack

Explicit offsets:

W1 := B.20                               % Offset 20 from B
W1 := B.24                               % Offset 24 from B

Displacement size:

W1 := B.10:S                             % Short displacement
W1 := B.100:B                            % Byte displacement
W1 := B.1000:H                           % Half-word displacement
W1 := B.10000:W                          % Word displacement

3.5 Local Post-Indexed

Array on stack:

STACK
    ARRAY: W BLOCK 100                   % Local array
ENDSTACK

ROUTINE:
    ENTS #SCLC
    W2 := 10                             % Index
    W1 := B.ARRAY(W2)                    % Access element 10

Computed access:

W2 := INDEX * 4                          % Calculate byte offset
W1 := B.ARRAY(W2)                        % Access element

3.6 Local Indirect

Pointer on stack:

STACK
    PTR: W BLOCK 1                       % Pointer
ENDSTACK

ROUTINE:
    ENTS #SCLC
    % PTR contains address of data
    W1 := IND(B.PTR)                     % Dereference pointer

Double indirection:

% PTR points to another pointer
W1 := IND(B.PTR)                         % First indirection
W1 := IND(W1)                            % Second indirection (manual)

3.7 Local Indirect Post-Indexed

Array via pointer:

STACK
    ARRAY_PTR: W BLOCK 1                 % Pointer to array
ENDSTACK

ROUTINE:
    ENTS #SCLC
    % ARRAY_PTR contains base address
    W2 := 5                              % Index
    W1 := IND(B.ARRAY_PTR)(W2)           % Access element 5

Use case - dynamic arrays:

% Allocate array at runtime
CALL MALLOC, 1, 400                      % 100 words
W1 := B.ARRAY_PTR                        % Store pointer

% Access later
W2 := INDEX
W3 := IND(B.ARRAY_PTR)(W2)               % Access element

3.8 Record Addressing (R-relative)

Basic record access:

RECORD
    FIELD1: W BLOCK 1                    % Offset 0
    FIELD2: W BLOCK 1                    % Offset 4
    FIELD3: W BLOCK 1                    % Offset 8
ENDRECORD

NODE: RECORD FIXED
    FIELD1: W DATA 100
    FIELD2: W DATA 200
    FIELD3: W DATA 300
ENDRECORD

% Access
R := ADDR(NODE)
W1 := R.FIELD1                           % Load FIELD1
W2 := R.FIELD2                           % Load FIELD2

Dynamic record access:

% R points to dynamically allocated record
R := RETURNED_POINTER
W1 := R.NEXT                             % Access NEXT field
W2 := R.DATA                             % Access DATA field

3.9 Pre-Indexed Addressing

Array base in register:

W2 := ADDR(ARRAY)                        % Base address in W2
W1 := W2.0                               % Element 0 (W2 + 0)
W1 := W2.4                               % Element 1 (W2 + 4)
W1 := W2.8                               % Element 2 (W2 + 8)

Computed offset:

W2 := BASE_ADDRESS
W3 := INDEX * 4                          % Word size
W1 := W2.W3                              % Base + computed offset

3.10 Absolute Addressing

Global data access:

MODULE EXAMPLE

GLOBAL_VAR: W DATA 100                   % Absolute address

ROUTINE:
    W1 := GLOBAL_VAR                     % Load from absolute
    W1 := GLOBAL_VAR                     % Store to absolute
ENDROUTINE

ENDMODULE

Cross-module access:

MODULE USER

IMPORT-D SYSTEM_CONFIG                   % External data

ROUTINE:
    W1 := SYSTEM_CONFIG                  % Access external
ENDROUTINE

ENDMODULE

3.11 Absolute Post-Indexed

Global array:

TABLE: W DATA 10, 20, 30, 40, 50

ACCESS:
    W2 := 3                              % Index 3
    W1 := TABLE(W2)                      % Load TABLE[3] = 40

Computed index:

W2 := USER_ID                            % Calculate index
W2 := W2 * 4                             % Word size
W1 := USER_TABLE(W2)                     % Access user record

3.12 Descriptor Addressing

Array with bounds checking:

ARRAY_DATA: W BLOCK 100
ARRAY_DESC: DESC 100, ARRAY_DATA

ACCESS:
    W2 := 50                             % Index
    W1 := DESC(ARRAY_DESC)(W2)           % Bounds-checked access

Descriptor structure:

Word 0: Upper bound (count - 1)
Word 1: Base address

Runtime bounds checking: - Automatic by hardware - Trap if index >= count - Performance overhead

3.13 Alternative Area

Purpose: Access through alternative addressing

Syntax:

W1 := ALT(operand)

Use case: System-specific addressing modes beyond standard 10.


4. Register Architecture and Usage

4.1 Register Set Overview

Integer Accumulators: | Register | Size | Use | |----------|------|-----| | W1 | 32-bit | Primary integer accumulator | | W2 | 32-bit | Secondary accumulator | | W3 | 32-bit | Tertiary accumulator | | W4 | 32-bit | Quaternary accumulator |

Floating Point Accumulators: | Register | Size | Use | |----------|------|-----| | F1 | 32-bit | Primary float accumulator | | F2 | 32-bit | Secondary float accumulator | | F3 | 32-bit | Tertiary float accumulator | | F4 | 32-bit | Quaternary float accumulator | | D1 | 64-bit | Primary double accumulator | | D2 | 64-bit | Secondary double accumulator | | D3 | 64-bit | Third double accumulator | | D4 | 64-bit | Fourth double accumulator |

General Purpose: | Register | Size | Use | |----------|------|-----| | R1-R4 | 32-bit | Type-flexible registers |

Special Registers: | Register | Purpose | |----------|---------| | B | Base register (stack/local addressing) | | R | Record register (structure addressing) | | PC | Program counter | | SP | Stack pointer |

4.2 Register Allocation Strategy

Calling convention (recommended):

W1: Return value, temp calculations
W2: First parameter, temp
W3: Second parameter, temp
W4: Third parameter, temp

F1/D1: Float return value
F2/D2-F4/D4: Float parameters and temps

R1-R4: Preserved across calls (callee-saved)
B: Preserved (points to current stack frame)
R: Caller-saved (can be modified)

Example:

ROUTINE CALCULATE
STACK
    RESULT: W BLOCK 1
ENDSTACK

CALCULATE:
    ENTS #SCLC

    % Use W1-W4 freely (they're volatile)
    W1 := B.PARAM1
    W2 := B.PARAM2
    W ADD2 W1, W2
    W1 := B.RESULT                       % Return in W1

    RET                                  % W1 contains result

ENDROUTINE

4.3 Register Operations

Data movement:

W1 := W2                                 % Copy
W SWAP W1, W2                            % Swap
W MOVE W1, W2                            % Move W1 to W2

Arithmetic:

W ADD2 W1, W2                            % W1 = W1 + W2
W SUB2 W1, W2                            % W1 = W1 - W2
W MUL2 W1, W2                            % W1 = W1 * W2
W DIV2 W1, W2                            % W1 = W1 / W2
W INCR W1                                % W1++
W DECR W1                                % W1--
W NEG W1                                 % W1 = -W1

Logical:

W AND2 W1, W2                            % W1 = W1 & W2
W OR2 W1, W2                             % W1 = W1 | W2
W XOR2 W1, W2                            % W1 = W1 ^ W2
W NOT W1                                 % W1 = ~W1

Shift/Rotate:

W SHL2 W1, 4                             % W1 << 4
W SHR2 W1, 4                             % W1 >> 4 (logical)
W SAR2 W1, 4                             % W1 >> 4 (arithmetic)
W ROL2 W1, 4                             % Rotate left
W ROR2 W1, 4                             % Rotate right


5. Stack Frame Techniques

5.1 Stack Frame Anatomy

Complete stack frame structure:

Higher Addresses
+------------------+
| Caller's frame   |
+------------------+
| Parameter N      | ← Arguments (if passed by value)
| ...              |
| Parameter 1      |
+------------------+
| Return Address   | ← RETA (offset 4)
+------------------+
| Saved B          | ← PREVB (offset 0) ← B points here
+------------------+
| Next Frame Ptr   | ← SP (offset 8)
+------------------+
| System Cell      | ← AUX (offset 12)
+------------------+
| Arg Count        | ← NARG (offset 16)
+------------------+
| Local 1          | ← Offset 20
| Local 2          | ← Offset 24
| ...              |
| Local N          |
+------------------+
Lower Addresses

5.2 Entry and Exit

ENTS - Enter Stack Subroutine:

ROUTINE FUNCTION
STACK
    LOCAL1: W BLOCK 1                    % Offset 20
    LOCAL2: W BLOCK 1                    % Offset 24
ENDSTACK

FUNCTION:
    ENTS #SCLC                           % Allocate frame
    % B now points to new frame
    % Old B saved at offset 0
    % Return address at offset 4
    % Locals at offset 20+

    RET                                  % Return

ENDROUTINE

What ENTS does: 1. Allocate new frame (size = #SCLC) 2. Save old B at new frame + 0 3. Save return address at new frame + 4 4. Set B to new frame base 5. Initialize NARG if parameters present

RET - Return from Subroutine:

RET                                      % Standard return

What RET does: 1. Restore B from frame + 0 2. Jump to address at frame + 4 3. Deallocate frame

5.3 Parameter Passing

By address (pointer):

ROUTINE MODIFY
STACK
    DATA_PTR: W BLOCK 1                  % Pointer parameter
ENDSTACK

MODIFY:
    ENTS #SCLC
    W1 := IND(B.DATA_PTR)                % Load via pointer
    W INCR W1
    W1 := IND(B.DATA_PTR)                % Store via pointer
    RET

ENDROUTINE

% Call
% DATA: W BLOCK 1
% CALL MODIFY, 1, ADDR(DATA)

By value:

ROUTINE COMPUTE
STACK
    VALUE: W BLOCK 1                     % Value parameter
ENDSTACK

COMPUTE:
    ENTS #SCLC
    W1 := B.VALUE                        % Load value directly
    W ADD2 W1, 100
    W1 := B.RESULT                       % Store result
    RET

ENDROUTINE

% Call
% W1 := 50
% CALL COMPUTE, 1, W1

Multiple parameters:

ROUTINE ADD3
STACK
    A: W BLOCK 1
    B: W BLOCK 1
    C: W BLOCK 1
    RESULT: W BLOCK 1
ENDSTACK

ADD3:
    ENTS #SCLC
    W1 := B.A
    W2 := B.B
    W ADD2 W1, W2
    W2 := B.C
    W ADD2 W1, W2
    W1 := B.RESULT
    RET

ENDROUTINE

% Call
% CALL ADD3, 3, 10, 20, 30

5.4 Fixed vs Dynamic Stacks

Fixed (static) - use ENTF:

LOCALS: STACK FIXED
    COUNTER: W DATA 0                    % Initialized
    BUFFER: W BLOCK 100                  % Zeroed at load
ENDSTACK

ROUTINE:
    ENTF LOCALS, 0                       % Use fixed frame
    W1 := B.COUNTER                      % Access directly
    RET

Advantages: - Data initialized at load time - No runtime allocation overhead - Reentrant if used correctly

Dynamic (runtime) - use ENTS:

STACK
    LOCALS: W BLOCK 100                  % Allocated at runtime
ENDSTACK

ROUTINE:
    ENTS #SCLC                           % Allocate frame
    W1 := B.LOCALS                       % Access locals
    RET

Advantages: - No static memory usage - Multiple concurrent calls supported - Stack grows/shrinks dynamically

5.5 Nested Calls

Saving/restoring across calls:

ROUTINE OUTER
STACK
    SAVED_W1: W BLOCK 1
    SAVED_W2: W BLOCK 1
ENDSTACK

OUTER:
    ENTS #SCLC

    W1 := 100
    W2 := 200

    % Save registers
    W1 := B.SAVED_W1
    W2 := B.SAVED_W2

    % Make nested call
    CALL INNER, 0

    % Restore registers
    W1 := B.SAVED_W1
    W2 := B.SAVED_W2

    RET

ENDROUTINE

Automatic preservation: - B register auto-saved by ENTS - R register must be saved manually if needed - W1-W4 volatile across calls


6. Record Structures in Depth

6.1 Record Definition Strategies

Simple record:

RECORD
    ID: W BLOCK 1
    NAME: BY BLOCK 32
    AGE: W BLOCK 1
    SALARY: F BLOCK 1
ENDRECORD
% #RCLC = 44 bytes

Nested records:

% Address record
RECORD
    STREET: BY BLOCK 32
    CITY: BY BLOCK 32
    ZIP: W BLOCK 1
ENDRECORD
ADDRESS_SIZE: EQU #RCLC

% Person record with nested address
RECORD
    NAME: BY BLOCK 32
    ADDRESS: BY BLOCK ADDRESS_SIZE
    PHONE: BY BLOCK 16
ENDRECORD
% #RCLC = 32 + 68 + 16 = 116

Records with arrays:

RECORD
    COUNT: W BLOCK 1
    DATA: W BLOCK 100                    % Array in record
    CHECKSUM: W BLOCK 1
ENDRECORD

6.2 Record Access Patterns

Direct access:

NODE: RECORD FIXED
    NEXT: W DATA 0
    DATA: W DATA 12345
ENDRECORD

% Access
R := ADDR(NODE)
W1 := R.NEXT
W2 := R.DATA

Array of records:

% Record definition
RECORD
    ID: W BLOCK 1
    VALUE: W BLOCK 1
ENDRECORD
RECORD_SIZE: EQU #RCLC                   % 8 bytes

% Array of 100 records
RECORDS: W BLOCK 100 * (RECORD_SIZE / 4)

% Access record N
ROUTINE ACCESS_RECORD
STACK
    INDEX: W BLOCK 1
ENDSTACK

ACCESS_RECORD:
    ENTS #SCLC
    W1 := B.INDEX                        % Get index
    W MUL2 W1, RECORD_SIZE               % Calculate offset
    R := ADDR(RECORDS)                   % Base address
    R := R + W1                          % Point to record
    W2 := R.ID                           % Access field
    RET

ENDROUTINE

6.3 Linked Structures

Linked list:

% Node structure
RECORD
    NEXT: W BLOCK 1                      % Offset 0
    PREV: W BLOCK 1                      % Offset 4
    DATA: W BLOCK 1                      % Offset 8
ENDRECORD
NODE_SIZE: EQU #RCLC

% Traverse list
ROUTINE TRAVERSE
STACK
    HEAD: W BLOCK 1
ENDSTACK

TRAVERSE:
    ENTS #SCLC
    R := IND(B.HEAD)                     % Start at head

LOOP:
    W COMP R, #ZEROD                     % Check for null
    IF = GO DONE

    W1 := R.DATA                         % Access data
    % Process W1

    R := R.NEXT                          % Move to next
    GO LOOP

DONE:
    RET

ENDROUTINE

Binary tree:

RECORD
    LEFT: W BLOCK 1
    RIGHT: W BLOCK 1
    KEY: W BLOCK 1
    VALUE: W BLOCK 1
ENDRECORD

% Tree traversal (inorder)
ROUTINE INORDER
STACK
    NODE_PTR: W BLOCK 1
ENDSTACK

INORDER:
    ENTS #SCLC
    R := IND(B.NODE_PTR)

    W COMP R, #ZEROD                     % Check null
    IF = GO DONE

    % Traverse left
    W1 := R.LEFT
    CALL INORDER, 1, W1

    % Process current
    W1 := R.KEY
    % ... process ...

    % Traverse right
    W1 := R.RIGHT
    CALL INORDER, 1, W1

DONE:
    RET

ENDROUTINE

6.4 Record Packing

Alignment considerations:

% Poorly packed (wastes space)
RECORD
    FLAG: BY BLOCK 1                     % 1 byte
    % 3 bytes padding for alignment
    VALUE: W BLOCK 1                     % 4 bytes (offset 4)
ENDRECORD
% Total: 8 bytes (3 wasted)

% Better packing
RECORD
    FLAGS: BY BLOCK 4                    % 4 bytes of flags
    VALUE: W BLOCK 1                     % 4 bytes (offset 4)
ENDRECORD
% Total: 8 bytes (0 wasted)

Using $PACK:

$PACK                                    % Enable tight packing
RECORD
    FLAG: BY BLOCK 1                     % Offset 0
    VALUE: W BLOCK 1                     % Offset 1 (no padding!)
ENDRECORD
$ALIGN                                   % Resume normal alignment


7. Complete Instruction Set

7.1 Data Movement Instructions

Instruction Syntax Description
:= dest := source Move/load
MOVE type MOVE source, dest Explicit move
SWAP type SWAP reg1, reg2 Swap registers
SET type SET dest Set to all 1s
CLR type CLR dest Clear to 0

Examples:

W1 := 100                                % Load constant
W1 := W2                                 % Register copy
W1 := B.LOCAL                            % Load from stack
W1 := B.LOCAL                            % Store to stack
W MOVE IND(B.PTR), W1                    % Store via pointer
W SWAP W1, W2                            % Swap W1 and W2
W CLR W1                                 % W1 = 0

7.2 Arithmetic Instructions

Integer arithmetic:

W ADD2 W1, W2                            % W1 = W1 + W2
W SUB2 W1, W2                            % W1 = W1 - W2
W MUL2 W1, W2                            % W1 = W1 * W2
W DIV2 W1, W2                            % W1 = W1 / W2
W MOD2 W1, W2                            % W1 = W1 % W2

W ADD3 W1, W2, W3                        % W1 = W2 + W3
W SUB3 W1, W2, W3                        % W1 = W2 - W3
W MUL3 W1, W2, W3                        % W1 = W2 * W3

W INCR W1                                % W1++
W DECR W1                                % W1--
W NEG W1                                 % W1 = -W1
W ABS W1                                 % W1 = |W1|

Floating point:

F FADD2 F1, F2                           % F1 = F1 + F2
F FSUB2 F1, F2                           % F1 = F1 - F2
F FMUL2 F1, F2                           % F1 = F1 * F2
F FDIV2 F1, F2                           % F1 = F1 / F2

D DADD2 D1, D2                           % Double add
D DSUB2 D1, D2                           % Double subtract
D DMUL2 D1, D2                           % Double multiply
D DDIV2 D1, D2                           % Double divide

Special:

F SQRT F1                                % F1 = sqrt(F1)
F SIN F1                                 % F1 = sin(F1)
F COS F1                                 % F1 = cos(F1)
F EXP F1                                 % F1 = e^F1
F LOG F1                                 % F1 = ln(F1)

7.3 Logical and Bit Instructions

W AND2 W1, W2                            % W1 = W1 & W2
W OR2 W1, W2                             % W1 = W1 | W2
W XOR2 W1, W2                            % W1 = W1 ^ W2
W NOT W1                                 % W1 = ~W1

% Bit operations
BI SET W1, 5                             % Set bit 5
BI CLR W1, 5                             % Clear bit 5
BI TST W1, 5                             % Test bit 5
BI MOV W1, 5, W2, 3                      % Move bit W1[5] to W2[3]

Shift and rotate:

W SHL2 W1, 4                             % W1 << 4
W SHR2 W1, 4                             % W1 >> 4 (logical)
W SAR2 W1, 4                             % W1 >> 4 (arithmetic)
W ROL2 W1, 4                             % Rotate left 4
W ROR2 W1, 4                             % Rotate right 4

W SHL W1, W2                             % W1 << W2 (variable)

7.4 Comparison and Branching

Comparison:

W COMP2 W1, W2                           % Compare W1 with W2
F FCOMP2 F1, F2                          % Float compare

Conditional branches:

IF = GO LABEL                            % If equal
IF <> GO LABEL                           % If not equal
IF < GO LABEL                            % If less than
IF <= GO LABEL                           % If less or equal
IF > GO LABEL                            % If greater than
IF >= GO LABEL                           % If greater or equal

Unconditional:

GO LABEL                                 % Jump
GO LABEL:B                               % Force byte displacement
GO LABEL:H                               % Force half-word
GO LABEL:W                               % Force word displacement

Computed jump:

GO IND(W1)                               % Jump to address in W1

7.5 Subroutine Instructions

Call:

CALL ROUTINE, 0                          % No arguments
CALL ROUTINE, 1, ARG1                    % One argument
CALL ROUTINE, 3, ARG1, ARG2, ARG3        % Three arguments
CALLG ROUTINE, 0                         % Call global (far)

Return:

RET                                      % Return from subroutine
RETD                                     % Return direct (ENTD)

Entry:

ENTS #SCLC                               % Enter stack subroutine
ENTF FIXED_STACK, 0                      % Enter fixed stack
ENTD                                     % Enter direct (no frame)
ENTM STACK_ADDR, SIZE, DEMAND            % Enter with main stack

7.6 Stack and Memory Operations

Stack manipulation:

W PUSH W1                                % Push onto stack
W POP W1                                 % Pop from stack

Memory operations:

W FILL dest, count, value                % Fill memory
W COPY source, dest, count               % Copy memory
W COMP_MEM source1, source2, count       % Compare memory

7.7 Special Instructions

System:

NOP                                      % No operation
HALT                                     % Halt processor
TRAP n                                   % Software trap

I/O:

IN port, dest                            % Input from port
OUT port, source                         % Output to port

Synchronization:

W TAS address                            % Test and set (atomic)
W CAS W1, W2, address                    % Compare and swap


(Continuing in next section due to length...)

Note: This expert guide continues with sections 8-16 covering: - Macro Programming - Conditional Assembly - Expression Evaluation - Module Organization Strategies - Integration with NORD-100 - Performance Optimization - Advanced Patterns - Real-World Examples - Debugging and Troubleshooting

Each section provides expert-level detail with production code examples.


Version: 1.0
Last Updated: October 18, 2025
Status: Complete - Expert Level (Part 1 of 2)

Reference Manual: ND-60.113.02 EN Assembler Reference Manual

For Introduction: See NORD-500-ASSEMBLER-DEVELOPER-GUIDE.md


This is the first half of the Expert Guide. Due to comprehensive coverage, the guide is split into manageable sections. All essential expert-level content for sections 1-7 is complete above.