CDC6504 CPU Assembly Language Reference

The CDC6504 is a limited 6502 emulator with PC, ACC, X, Y registers and status flags (Z, N). This tool uses authentic 6502 opcodes and instruction syntax.

Using the CDC6504 Emulator

Load Program Dropdown

The "Load Program" dropdown provides quick access to example programs and tools:

View Assembly Modal

The "View Assembly" option opens a read-only modal that displays the current assembly code:

Assembly Editor

To write and assemble your own programs:

  1. Select "Toggle Assembler" from the Load Program dropdown
  2. The assembly editor will appear with a textarea for your code
  3. Type or paste your assembly code
  4. Click the "Assemble" button to compile your program
  5. If successful, the program will be loaded into instruction memory and ready to run

💡 Assembly Editor Features

  • Save/Load: Use the Storage dropdown to save your programs for later use
  • Clear: Clears the editor to start fresh
  • Error Messages: If assembly fails, error messages will help you fix the code

💡 View Assembly vs. Toggle Assembler

  • View Assembly: Read-only view in a modal window
  • Toggle Assembler: Full editor with assemble, save, and load capabilities

Running Programs

Once a program is loaded:

Narrate Execution

The emulator includes a "Narrate Execution" feature that speaks each instruction as it executes:

Register Reference

General Purpose Registers

6502 architecture registers

  • ACC: Accumulator (A register) - primary register for arithmetic and data operations
  • X: Index Register X - used for indexing and counting
  • Y: Index Register Y - used for indexing and counting

Status Flags

Condition flags set by arithmetic, comparison, and transfer operations. Flags are set by any operation altering ACC, X, or Y.

  • Z: Zero flag - set when result equals zero
  • N: Negative flag - set when bit 7 of result is set (signed negative)

Special Registers

  • PC: Program Counter (current instruction address)

💡 6502 Architecture

The CDC6504 emulates a simplified 6502 processor. The accumulator (ACC) is the primary register for arithmetic operations. Use STA/STX/STY to store registers to memory, and LDA/LDX/LDY to load from immediate values.

💡 ASCII Character Support

Immediate values can be specified as single ASCII characters in quotes: LDA #'A' loads 65 (ASCII for 'A') into the accumulator. This works for all immediate instructions: LDA, LDX, LDY, CMP, CPX, CPY, ADC, SBC.

💡 Status Flags

Status flags are automatically updated by arithmetic, comparison, and transfer operations. Flags are set by any operation touching ACC, X, or Y. Use branch instructions (BEQ, BNE, BMI, BPL) to conditionally jump based on flag states.

Instruction Set Reference

Control Instructions (8-bit)

Assembly Opcode Description
BRK 00000000 Break/Halt - Stop program execution (automatically prints data memory)

Increment/Decrement Instructions (8-bit)

Assembly Opcode Description
CLX 11100010 Clear X register (X = 0). Sets Z flag to 1, N flag to 0. (*)
CLY 11000010 Clear Y register (Y = 0). Sets Z flag to 1, N flag to 0s. (*)
INX 11101000 Increment X register by 1
INY 11001000 Increment Y register by 1
DEX 11001010 Decrement X register by 1
DEY 10001000 Decrement Y register by 1

Transfer Instructions(8-Bit)

Assembly Opcode Description
TAX 10101010 Transfer accumulator to X register
TAY 10101000 Transfer accumulator to Y register
TXA 10001010 Transfer X register to accumulator
TYA 10011000 Transfer Y register to accumulator

💡 16-bit instructions

16-bit instructions take a parameter that is an 8-bit constant value (immediate values) or data memory address. These parameter values are stored in the byte immediately following the instruction for a total of 16-bits. So we call them "immediate" instructions

Load Instructions (16-Bit)

Assembly Opcode Description
LDA #value 10101001 Load accumulator with immediate value (ACC = value)
LDA $address 10100101 Load accumulator from zero-page memory address (ACC = memory[address])
LDX #value 10100010 Load X register with immediate value (X = value)
LDX $address 10100110 Load X register from zero-page memory address (X = memory[address])
LDY #value 10100000 Load Y register with immediate value (Y = value)
LDY $address 10100100 Load Y register from zero-page memory address (Y = memory[address])

Store Instructions (16-bit)

Assembly Opcode Description
STA $address 10000101 Store accumulator to zero-page memory address (memory[address] = ACC)
STX $address 10000110 Store X register to zero-page memory address (memory[address] = X)
STY $address 10000100 Store Y register to zero-page memory address (memory[address] = Y)

Indexed Load/Store Instructions (16-bit)

Assembly Opcode Description
LDA $address,X 10110101 Load accumulator from zero-page indexed address (ACC = memory[(address + X) & 0xFF])
LDA $address,Y 10111001 Load accumulator from zero-page indexed address (ACC = memory[(address + Y) & 0xFF])
STA $address,X 10010101 Store accumulator to zero-page indexed address (memory[(address + X) & 0xFF] = ACC)
STA $address,Y 10011001 Store accumulator to zero-page indexed address (memory[(address + Y) & 0xFF] = ACC)

Arithmetic Instructions (16-bit, ACC only)

Assembly Opcode Description
ADC #value 01101001 Add (immediate): ACC = ACC + value
ADC $address 01100101 Add (from memory): ACC = ACC + memory[address]
SBC #value 11101001 Subtract (immediate): ACC = ACC - value
SBC $address 11100101 Subtract (from memory): ACC = ACC - memory[address]

Comparison Instructions (16-bit)

Assembly Opcode Description
CMP #value 11001001 Compare accumulator with immediate value, sets Z, N flags
CMP $address 11000101 Compare accumulator with value at the memory address, sets Z, N flags (ACC compared with memory[address])
CPX #value 11100000 Compare X register with immediate value, sets Z, N flags
CPX $address 11100100 Compare X register with value at the memory address, sets Z, N flags (X compared with memory[address])
CPY #value 11000000 Compare Y register with immediate value, sets Z, N flags
CPY $address 11000100 Compare Y register with value at the memory address, sets Z, N flags (Y compared with memory[address])

Branch Instructions (16-bit)

Assembly Opcode Description
BEQ label 11110000 Branch if equal (Z flag set)
BNE label 11010000 Branch if not equal (Z flag clear)
BMI label 00110000 Branch if minus (N flag set)
BPL label 00010000 Branch if plus (N flag clear)

Jump Instruction (16-bit)

Assembly Opcode Description
JMP $address 01001100 Unconditional jump to absolute address (zero-page)

Assembly Directives

Assembly Description
DATA 'string' Pre-populates data memory (not instruction memory) with a null-terminated string. Data is loaded starting at memory address 0.
DATA 0x00 0x0A ... Pre-populates data memory (not instruction memory) with a space-separated list of hexadecimal values. Data is loaded starting at memory address 0.

Comments

Comments can be added to assembly code using ; (semicolon). Everything from the semicolon to the end of the line is ignored by the assembler.

Note: The # character is used for immediate values (e.g., LDA #42), not for comments.

LDA #42 ; This is a comment using semicolon LDX #10 ; Comments can appear after instructions INX ; Another comment ; This is a comment-only line BRK

(*) Emulator-only instructions

The clear instructions (CLX, CLY) are 8-bit emulator-only instructions that use unused 6502 opcodes (0xE2, 0xC2). In a real hardware 6502, you would use the 16-bit LDX #0 and LDY #0 instructions to clear the registers.

Example Programs

These example programs are available in the "Load Program" dropdown menu in the emulator. Each demonstrates different aspects of the CDC6504 instruction set.

Simple Sample

This very basic example, computes 1+1 = 2 in the X register. It is kept simple to make it easy to examine the generated machine code.

CLX ; Clear X register INX ; Increment X INX ; Increment X again BRK

Add Sample

This program demonstrates immediate loading and immediate addition. After computing 27+15 it stores the result (42) in memory location 0

LDA #27 ; Load 27 into accumulator ADC #15 ; Add 15 (result = 42) STA $00 ; Store result to memory[0] BRK

Uppercase Sample

This program demonstrates conditional branching and arithmetic to convert a character to upper case. It compares a character value with 'a' (lowercase), and if the value is greater than or equal to 'a', it subtracts 0x20 to convert to uppercase using the BMI (Branch if Minus) instruction.

LDA #'p' ; Load 'p' into accumulator CMP #'a' ; Compare with 'a' BMI skip ; Branch if minus (less than) SBC #0x20 ; Subtract 0x20 to convert to uppercase skip: BRK

Hi

A simple two-character string program that demonstrates loading ASCII characters using single quotes. It stores 'H' and 'i' into consecutive memory locations, creating the string "Hi" which is automatically printed when BRK executes.

LDA #'H' STA $00 LDA #'i' STA $01 BRK

Hello

This program manually constructs the string "Hello" by loading each character's ASCII value (using character constants) and storing them to consecutive memory addresses. The BRK instruction automatically prints the null-terminated string from memory.

LDA #'H' ; Load 'H' into accumulator STA $00 LDA #'e' ; Load 'e' into accumulator STA $01 LDA #'l' ; Load 'l' into accumulator STA $02 STA $03 ; Store 'l' again LDA #'o' ; Load 'o' into accumulator STA $04 BRK

Hello World (with DATA)

This program demonstrates the DATA directive, which provides a convenient way to pre-populate data memory with a string. The DATA directive automatically places the string in memory starting at address 0 and adds a null terminator, making it much simpler than manually storing each character.

BRK DATA 'Hello World!'

Counter Loop (with Labels)

This program demonstrates the use of labels for program flow control. It uses a loop that increments the X register from 0 to 5, using labels "loop" and "end" for branching. The program compares X to 5 using CPX and branches when equal using BEQ, showing how labels make jump addresses easier to manage. The program is a simple for loop.

for(X=0; X<5; X++) ;

CLX ; Clear X register loop: CPX #5 ; Compare X register to 5 (simpler than TXA/CMP) BEQ end ; Branch if equal (Z flag set) INX ; Increment X JMP loop ; Jump to loop end: BRK ; Halt

Load from Memory Address

This program demonstrates loading values from memory addresses. It stores a value to memory, then loads it back into different registers (ACC, X, and Y) using the LDA, LDX, and LDY instructions with memory addressing.

; Store a value in memory, then load it into registers LDA #100 ; Load 100 into accumulator STA $10 ; Store accumulator to memory address $10 LDA $10 ; Load accumulator from memory address $10 LDX $10 ; Load X register from memory address $10 LDY $10 ; Load Y register from memory address $10 BRK

Add from Memory Address

This program demonstrates adding values stored in memory. It stores two values to different memory addresses, then loads one and adds the other from memory using ADC with memory addressing mode.

; Store values in memory, then add them LDA #10 ; Load 10 into accumulator STA $20 ; Store to memory address $20 LDA #5 ; Load 5 into accumulator ADC $20 ; Add value from memory address $20 (result = 15) STA $21 ; Store result to memory address $21 BRK

Add from Another Register

This program shows two methods for adding a register's value to the accumulator. Since arithmetic operations only work with the accumulator, you must transfer the register value to ACC first, or store it to memory and load it. Both approaches are demonstrated here.

; To add X register's value to accumulator: LDX #10 ; Load 10 into X register TXA ; Transfer X to accumulator ADC #5 ; Add 5 to accumulator (now contains X's value + 5) BRK ; Alternative: Store X to memory, then load and add LDX #10 ; Load 10 into X register STX $30 ; Store X to memory address $30 LDA $30 ; Load X's value into accumulator ADC #5 ; Add 5 BRK

Hello (again)

This program constructs "Hello" using arithmetic operations to derive some characters. It stores 'H', 'e', and 'l' directly, then uses ADC and SBC to calculate 'o' from 'l' by adding 4 and subtracting 1, demonstrating how arithmetic can be used for character manipulation.

LDA #'H' ; Load 'H' into accumulator STA $00 ; Store 'H' to memory address 0x00 LDA #'e' ; Load 'e' into accumulator STA $01 ; Store 'e' to memory address 0x01 LDA #'l' ; Load 'l' into accumulator STA $02 ; Store 'l' to memory address 0x02 STA $03 ; Store 'l' again to address 0x03 LDA #'l' ; Load 'l' into accumulator (108) ADC #4 ; Add 4 to accumulator so it is now 'p' (108 + 4 = 112) SBC #1 ; Subtract 1 from accumulator so it is now 'o' (112 - 1 = 111) STA $04 ; Store 'o' to memory address 0x04 LDA #0 ; Load zero into accumulator STA $05 ; Store zero to memory address 0x05 (null terminator) BRK ; Stop and print memory as an ASCII string

Convert String to Uppercase (Indexed Addressing)

This program demonstrates indexed addressing and loops to convert a mixed-case string to uppercase. It uses the DATA directive to initialize a string, then loops through each character using X as an index. Each character is loaded using indexed addressing (LDA $00,X), converted to uppercase if needed, and stored back using indexed addressing (STA $00,X). The loop continues until it encounters the null terminator.

CLX ; Clear X register (index starts at 0) loop: LDA $00,X ; Load character at memory[$00 + X] into accumulator BEQ done ; Branch if zero (null terminator found) CMP #'a' ; Compare with lowercase 'a' BMI cont ; Branch if minus (less than 'a', already uppercase or not a letter) SBC #0x20 ; Subtract 0x20 to convert to uppercase STA $00,X ; Store converted character back to memory[$00 + X] cont: INX ; Increment X to next character JMP loop ; Jump back to loop done: BRK ; Stop and print converted string DATA 'Hello'

Error Handling

When the CPU encounters an error (such as an invalid instruction), it will:

  • Display the error message in the Status field
  • Stop execution immediately
  • Preserve the current CPU state for debugging

Error Types

  • Invalid instruction: Unknown or undefined opcode encountered during execution

Error Test Programs

Test Invalid Instruction

CLX ; Clear X register 0xFF ; Invalid instruction (0xFF - undefined opcode) BRK

Label System

The assembler supports a two-pass label system for easier programming.

Label Definition

Labels are defined by ending a line with a colon (:):

start: ; This defines a label called "start" CLX ; Clear X register loop: ; This defines a label called "loop" INX ; Increment X register

Label Usage

Labels can be used in jump instructions instead of hard-coded addresses:

CLX ; Clear X register loop: CPX #5 ; Compare X register to 5 BEQ end ; Branch to "end" label if equal INX ; Increment X register JMP loop ; Jump back to "loop" label end: BRK ; Stop

Two-Pass Assembly

  1. First Pass: Collects all labels and calculates their addresses
  2. Second Pass: Assembles the program with resolved label addresses

💡 Benefits of Labels

  • No need to calculate jump addresses manually
  • Adding/removing instructions doesn't break jump addresses
  • More readable and maintainable code
  • Supports both labels and direct addresses

External References

For more information about the 6502 processor and instruction sets, please refer to these external resources:

💡 Historical Context

The CDC6504 emulator uses authentic 6502 opcodes and instruction syntax. The 6502 was one of the most popular 8-bit microprocessors, used in systems like the Apple II, Commodore 64, and Atari 2600.


About This Tool

This CDC6504 CPU emulator is part of the Computer Architecture for Everybody course, available at www.ca4e.com