Manuel de programmation du 65C816

Manuel de programmation du 65C816

The Western Design Center

Programming

Manual

1

The Western Design Center

Table of Contents

1) Chapter One .......................................................................................................... 12

Basic Assembly Language Programming Concepts..................................................................................12

Binary Numbers.................................................................................................................................................... 12

Grouping Bits into Bytes....................................................................................................................................... 13

Hexadecimal Representation of Binary ................................................................................................................ 14

The ACSII Character Set ..................................................................................................................................... 15

Boolean Logic........................................................................................................................................................ 16

Logical And ........................................................................................................................................................ 16

Logical Or .......................................................................................................................................................... 17

Logical Exclusive Or........................................................................................................................................... 17

Logical Complement ........................................................................................................................................... 17

Signed Numbers .................................................................................................................................................... 18

Storing Numbers in Decimal Form....................................................................................................................... 19

Computer Arithmetic............................................................................................................................................ 20

Microprocessor Programming.............................................................................................................................. 20

Machine Language .............................................................................................................................................. 20

Assembly Language ............................................................................................................................................ 22

Writing in Assembly Language ............................................................................................................................ 22

Basic Programming Concepts............................................................................................................................... 23

Selection Between Paths...................................................................................................................................... 24

Looping .............................................................................................................................................................. 24

Subroutines ......................................................................................................................................................... 24

2) Chapter Two .......................................................................................................... 26

Architecture of the 6502 ............................................................................................................................26

Microprocessor Architecture................................................................................................................................ 26

The 6502 Registers ................................................................................................................................................ 26

The Accumulator ................................................................................................................................................ 27

The X and Y Index Registers............................................................................................................................... 29

The Status Register ............................................................................................................................................. 29

Abbrev................................................................................................................................................................ 30

Name .................................................................................................................................................................. 31

The Stack Pointer ................................................................................................................................................ 31

The Program Counter .......................................................................................................................................... 33

Addressing Modes ................................................................................................................................................. 33

Instructions ........................................................................................................................................................... 35

The 6502 System Design........................................................................................................................................ 38

Pipelining ........................................................................................................................................................... 38

Memory Order of Multiple-Byte Values .............................................................................................................. 39

Memory-Mapped Input/Output............................................................................................................................ 39

Interrupts ............................................................................................................................................................ 39

NMOS Process ...................................................................................................................................................... 40

Bugs and Quirks ................................................................................................................................................... 40

3) Chapter Three ....................................................................................................... 41

Architecture of the 65C02 .........................................................................................................................41

The 65C02 Architecture........................................................................................................................................ 41

Addressing Modes ................................................................................................................................................. 41

Instructions ........................................................................................................................................................... 42

CMOS Process ...................................................................................................................................................... 42

Bugs and Quirks ................................................................................................................................................... 42

4) Chapter Four......................................................................................................... 44

Sixteen-Bit Architecture The 65816 and the 65802...................................................................................44

2

The Western Design Center

Power-On Status: 6502 Emulation Mode..................................................................................................45

The Full-Featured 65x Processor: The 65816 in Native Mode ................................................................45

The Program Bank Register ................................................................................................................................. 47

The Data Bank Register........................................................................................................................................ 48

The Direct Page Register ...................................................................................................................................... 48

The Stack Pointer.................................................................................................................................................. 48

Accumulator and Index Registers ........................................................................................................................ 48

Switching Registers Between Eight and Sixteen Bits............................................................................................ 50

The Status Register ............................................................................................................................................... 50

6502/65C02 Addressing Modes on the 65816........................................................................................................ 51

New 65816 Addressing Modes .............................................................................................................................. 52

Instructions ........................................................................................................................................................... 54

Interrupts .............................................................................................................................................................. 55

The 65802 Native Mode .............................................................................................................................55

Emulation Mode.................................................................................................................................................... 58

Emulation Mode Registers.................................................................................................................................... 60

Switching Between 6502 Emulation and Native Modes............................................................................61

Switching from Emulation to Native Mode .......................................................................................................... 61

Switching from Native to Emulation Mode .......................................................................................................... 61

65802/65816 Bugs and Quirks ...................................................................................................................62

5) Chapter Five.......................................................................................................... 64

SEP, REP, and Other Details ....................................................................................................................64

The Assembler Used in This Book ........................................................................................................................ 66

Address Notation................................................................................................................................................... 68

6) Chapter Six............................................................................................................ 69

First Examples: Moving Data....................................................................................................................69

Loading and Storing Registers ............................................................................................................................. 71

Effect of Load and Store Operations on Status Flags............................................................................................ 73

Moving Data Using the Stack .............................................................................................................................. 73

Push.................................................................................................................................................................... 74

Pushing the Basic 65x Registers .......................................................................................................................... 76

Pull ..................................................................................................................................................................... 76

Pulling the Basic 65x Registers ........................................................................................................................... 76

Pushing and Pulling the 65816’s Additional Registers.......................................................................................... 78

Pushing Effective Addresses................................................................................................................................ 79

Other Attributes of Push and Pull ........................................................................................................................ 79

Moving Data Between Registers ........................................................................................................................... 79

Transfers............................................................................................................................................................. 79

Exchanges........................................................................................................................................................... 86

Storing Zero to Memory ....................................................................................................................................... 86

Block Moves .......................................................................................................................................................... 87

7) Chapter Seven ....................................................................................................... 89

SimpleAddressing Modes ..........................................................................................................................89

Immediate Addressing .......................................................................................................................................... 90

Absolute Addressing ............................................................................................................................................. 92

Direct Page Addressing......................................................................................................................................... 94

Indexing................................................................................................................................................................. 95

Absolute Indexed with X and Absolute Indexed with Y Addressing ................................................................... 98

Direct Page Indexed with X and Direct Page Indexed with Y Addressing ........................................................ 101

Accumulator Addressing .................................................................................................................................... 103

Implied Addressing ............................................................................................................................................. 103

Stack.................................................................................................................................................................... 104

Direct Page Indirect Addressing......................................................................................................................... 104

Absolute Long Addressing .................................................................................................................................. 105

3

The Western Design Center

Absolute Long Indexed with X Addressing ........................................................................................................ 108

Direct Page Indirect Long................................................................................................................................... 109

Block Move.......................................................................................................................................................... 110

8) Chapter Eight ...................................................................................................... 111

The Flow of Control................................................................................................................................. 111

Jump Instructions ............................................................................................................................................... 112

Conditional Branching........................................................................................................................................ 114

Branching Based on the Zero Flag ..................................................................................................................... 115

Branching Based on the Carry Flag ................................................................................................................... 117

Branching Based on the Negative Flag .............................................................................................................. 118

Branching Based on the Overflow Flag.............................................................................................................. 119

Limitations of Conditional Branches.................................................................................................................. 119

Unconditional Branching .................................................................................................................................... 119

9) Chapter Nine ....................................................................................................... 122

Built-In Arithmetic Functions ................................................................................................................. 122

Description ............................................................................................................................................... 122

Increment and Decrement .................................................................................................................................. 123

Addition and Subtraction: Unsigned Arithmetic .............................................................................................. 127

Comparison ......................................................................................................................................................... 130

Signed Arithmetic ............................................................................................................................................... 134

Signed Comparisons............................................................................................................................................ 136

Decimal Mode ..................................................................................................................................................... 137

10) Chapter Ten...................................................................................................... 139

Logic and Bit Manipulation Operations ................................................................................................. 139

Logic Functions ................................................................................................................................................... 139

Logical AND .................................................................................................................................................... 140

Logical OR ....................................................................................................................................................... 142

Logical Exclusive-Or ........................................................................................................................................ 143

Bit Manipulation ................................................................................................................................................. 145

Shifts and Rotates ............................................................................................................................................... 146

11) Chapter Eleven ................................................................................................. 154

The Complex Addressing Modes............................................................................................................. 154

Relocating the Direct Page.................................................................................................................................. 155

Assembler Addressing Mode Assumptions......................................................................................................... 156

Direct Page Indirect Indexed With Y Addressing .............................................................................................. 158

Direct Page Indexing Indirect Addressing ......................................................................................................... 161

Absolute Indexed Indirect Addressing ............................................................................................................... 163

Direct Page Indirect Long Indexed with Y Addressing...................................................................................... 165

Stack Relative Addressing .................................................................................................................................. 166

Stack Relative Indirect Indexed Addressing ...................................................................................................... 168

Push Effective Instructions ................................................................................................................................. 169

12) Chapter Twelve................................................................................................. 174

The Basic Building Block: ....................................................................................................................... 174

The Subroutine.................................................................................................................................................... 174

The Jump-To-Subroutine Instruction ................................................................................................................ 175

The Return-from-Subroutine Instruction .......................................................................................................... 175

JRS Using Absolute Indexed Indirect Addressing ............................................................................................. 177

The Long Jump to Subroutine............................................................................................................................ 178

Return from Subroutine Long ............................................................................................................................ 178

Branch to Subroutine.......................................................................................................................................... 179

Coding a Subroutine: How and When................................................................................................................ 180

6502 Eight-Bit Negation – A Library Example .................................................................................................. 180

65C02, 65802, and 65816 Eight-Bit Negation .................................................................................................... 181

4

The Western Design Center

6502 Sixteen-Bit Negation ................................................................................................................................ 181

65802 and 65816 Sixteen-Bit Negation.............................................................................................................. 181

Parameter Passing .............................................................................................................................................. 182

13) Chapter Thirteen .............................................................................................. 192

Interrupts and System Control Instructions........................................................................................... 192

Interrupts ............................................................................................................................................................ 192

Processing Interrupts ......................................................................................................................................... 197

Interrupt Response Time ................................................................................................................................... 200

Status Register Control Instruction.................................................................................................................... 201

No Operation Instructions .................................................................................................................................. 202

14) Chapter Fourteen ............................................................................................. 204

Selected Code Samples............................................................................................................................. 204

Multiplication...................................................................................................................................................... 204

6502 Multiplication........................................................................................................................................... 205

65C02 Multiplication ........................................................................................................................................ 205

65802 and 65816 Multiplication ........................................................................................................................ 205

Division................................................................................................................................................................ 208

6502 Division ................................................................................................................................................... 209

65C02 Division ................................................................................................................................................. 211

65802/65816 Division ....................................................................................................................................... 211

Calling an Arbitrary 6502 Routine..................................................................................................................... 213

Testing Processor Type ....................................................................................................................................... 219

Compiler-Generated 65816 Code for a RecursiveProgram ............................................................................... 220

The Same Example Hand-Coded in Assembly Language ................................................................................... 224

The Sieve of Eratosthenes Benchmark ............................................................................................................... 226

15) Chapter Fifteen ................................................................................................ 230

DEGUG16 – A 65816 Programming Tool............................................................................................... 230

Declarations......................................................................................................................................................... 232

LIST .................................................................................................................................................................... 234

FLIST .................................................................................................................................................................. 236

FRMOPRND....................................................................................................................................................... 238

POB ..................................................................................................................................................................... 243

STEP ................................................................................................................................................................... 244

PUTHEX ............................................................................................................................................................. 246

CLRLN................................................................................................................................................................ 248

UPDATE ............................................................................................................................................................. 249

PRINTLN............................................................................................................................................................ 251

TRACE................................................................................................................................................................ 252

EBRKIN .............................................................................................................................................................. 254

CHKSPCL........................................................................................................................................................... 259

DUMPREGS ....................................................................................................................................................... 263

PUTRTEG8......................................................................................................................................................... 265

TABLES .............................................................................................................................................................. 266

16) Chapter Sixteen ................................................................................................ 276

Design and Debugging ............................................................................................................................. 276

Debugging Checklist ........................................................................................................................................... 276

Decimal Flag .................................................................................................................................................... 276

Adjusting Carry Prior to Add / Subtract ............................................................................................................. 276

65x Left-to-Right Syntax................................................................................................................................... 276

65x Branches .................................................................................................................................................... 277

6502 Jump Bug ................................................................................................................................................. 277

Interrupt-Handling Code.................................................................................................................................... 277

65802/65816: Emulation Versus Native Mode ................................................................................................... 277

65802/65816: Eight-Bit Versus Sixteen-Bit Registers ........................................................................................ 278

65802/65816: The Direct Page .......................................................................................................................... 278

5

The Western Design Center

65802/65816: Stack Overruns Program or Data ................................................................................................. 278

65802/65816: JSR/JSL and RTS/RTL................................................................................................................ 278

65802/65816: MVN/MVP ................................................................................................................................. 278

Return Address ................................................................................................................................................. 279

Inconsistent Assembler Syntax .......................................................................................................................... 279

Generic Bugs: They Can Happen Anywhere...................................................................................................... 279

Uninitialized Variables ...................................................................................................................................... 279

Missing Code .................................................................................................................................................... 279

Failure to Increment the Index in a Loop............................................................................................................ 279

Failure to Clean Up Stack.................................................................................................................................. 280

Immediate Data Versus Memory Location......................................................................................................... 280

Initializing the Stack Pointer from a Subroutine ................................................................................................. 280

Top-Down Design and Structured Programming .............................................................................................. 280

Documentation .................................................................................................................................................... 281

17) Chapter Seventeen ............................................................................................ 283

The Addressing Modes ............................................................................................................................ 283

Absolute Addressing ......................................................................................................................................... 288

Absolute Indexed, X Addressing ....................................................................................................................... 289

Absolute Indexed, Y Addressing ....................................................................................................................... 290

Absolute Indexed Indirect Addressing ............................................................................................................... 291

Absolute Indirect Addressing ............................................................................................................................ 292

Absolute Indirect Long Addressing ................................................................................................................... 293

JMP [addr]........................................................................................................................................................ 293

Absolute Long Addressing ................................................................................................................................ 294

Absolute Long Indexed, X Addressing .............................................................................................................. 295

Accumulator Addressing ................................................................................................................................... 296

Block Move Addressing .................................................................................................................................... 297

Direct Page Addressing ..................................................................................................................................... 298

Direct Page Indexed, X Addressing ................................................................................................................... 299

Direct Page Indexed, Y Addressing ................................................................................................................... 300

Direct Page Indexed Indirect, X Addressing....................................................................................................... 301

Direct Page Indirect Addressing ........................................................................................................................ 302

Direct Page Indirect Long Addressing ............................................................................................................... 303

Direct Page Indirect Indexed, Y Addressing....................................................................................................... 304

Direct Page Indirect Long Indexed, Y Addressing.............................................................................................. 305

Immediate Addressing....................................................................................................................................... 306

Implied Addressing ........................................................................................................................................... 307

Program Counter Relative Addressing ............................................................................................................... 308

Program Counter Relative Long Address ........................................................................................................... 309

Stack (Absolute) Addressing ............................................................................................................................. 310

Stack (Direct Page Indirect) Addressing ............................................................................................................ 312

Stack (Interrupt) Addressing.............................................................................................................................. 314

Stack (Program Counter Relative) Addressing ................................................................................................... 316

Stack (Pull) Addressing..................................................................................................................................... 317

Stack (Push) Addressing.................................................................................................................................... 319

Stack (RTI) Addressing..................................................................................................................................... 321

Stack (RTL) Addressing.................................................................................................................................... 322

Stack (RTS) Addressing .................................................................................................................................... 323

Stack Relative Addressing................................................................................................................................. 324

Stack Relative Indirect Indexed, Y Addressing .................................................................................................. 325

18) Chapter Eighteen.............................................................................................. 326

The Instruction Sets................................................................................................................................. 326

Add With Carry.................................................................................................................................................. 327

Opcode ............................................................................................................................................................. 327

Bytes................................................................................................................................................................. 327

Cycles............................................................................................................................................................... 327

And Accumulator with Memory......................................................................................................................... 328

Second .............................................................................................................................................................. 328

6

The Western Design Center

Operand ............................................................................................................................................................ 328

Shift Memory or Accumulator Left.................................................................................................................... 329

Branch if Carry Clear......................................................................................................................................... 330

Branch if Carry Set............................................................................................................................................. 331

Branch if Equal ................................................................................................................................................... 332

Test Memory Bits against Accumulator ............................................................................................................. 333

Branch if Minus .................................................................................................................................................. 334

Branch if Not Equal ............................................................................................................................................ 335

Branch if Plus...................................................................................................................................................... 336

Branch Always .................................................................................................................................................... 337

Software Break ................................................................................................................................................... 338

Branch Always Long........................................................................................................................................... 340

Branch if Overflow Clear ................................................................................................................................... 341

Branch if Overflow Set ....................................................................................................................................... 342

Clear Carry Flag................................................................................................................................................. 343

Clear Decimal Mode Flag ................................................................................................................................... 344

Clear Interrupt Disable Flag .............................................................................................................................. 345

Clear Overflow Flag............................................................................................................................................ 346

Compare Accumulator with Memory................................................................................................................. 347

Co-Processor Enable........................................................................................................................................... 349

Compare Index Register X with Memory........................................................................................................... 350

Compare Index Register Y with Memory CPY.................................................................................................. 351

Decrement ........................................................................................................................................................... 352

Decrement Index Register X............................................................................................................................... 353

Decrement Index Register Y............................................................................................................................... 354

Exclusive-OR Accumulator with Memory ......................................................................................................... 355

Increment ............................................................................................................................................................ 357

Increment Index Register X................................................................................................................................ 358

Increment Index Register Y................................................................................................................................ 359

Jump.................................................................................................................................................................... 360

Jump to Subroutine Long (Inter-Bank) ............................................................................................................. 361

Jump to Subroutine............................................................................................................................................. 362

Load Accumulator from Memory....................................................................................................................... 363

Load Index Register X from Memory ................................................................................................................ 364

Load Index Register Y from Memory ................................................................................................................ 365

Logical Shift Memory or Accumulator Right..................................................................................................... 366

Block Move Next ................................................................................................................................................. 367

Block Move Previous........................................................................................................................................... 368

MVP ......................................................................................................................................................... 368

No Operation....................................................................................................................................................... 369

OR Accumulator with Memory .......................................................................................................................... 370

Push Effective Absolute Address ........................................................................................................................ 372

Push Effective Indirect Address ......................................................................................................................... 373

Push Effective PC Relative Indirect Address ..................................................................................................... 374

PER ..................................................................................................................................................................... 374

Push Accumulator............................................................................................................................................... 375

Push Data Bank Register .................................................................................................................................... 376

Push Direct Page Register................................................................................................................................... 377

Push Program Bank Register ............................................................................................................................. 378

Push Processor Status Register........................................................................................................................... 379

Push Index Register ............................................................................................................................................ 380

Push Index Register ............................................................................................................................................ 381

Pull Accumulator ................................................................................................................................................ 382

Pull Data Bank Register...................................................................................................................................... 383

Pull Direct Page Register .................................................................................................................................... 384

Pull Status Flags.................................................................................................................................................. 385

Pull Index Register X from Stack ....................................................................................................................... 386

Pull Index Register Y from Stack ....................................................................................................................... 387

Reset Status Bits.................................................................................................................................................. 388

Rotate Memory or Accumulator Left................................................................................................................. 389

7

The Western Design Center

Rotate Memory or Accumulator Right............................................................................................................... 390

Return from Interrupt ........................................................................................................................................ 391

Return from Subroutine Long ............................................................................................................................ 393

Return from Subroutine ..................................................................................................................................... 394

Subtract with Borrow from Accumulator .......................................................................................................... 395

Set Carry Flag..................................................................................................................................................... 397

Set Decimal Mode Flag ....................................................................................................................................... 398

Set Interrupt Disable Flag .................................................................................................................................. 399

Set Status Bits ..................................................................................................................................................... 400

Store Accumulator to Memory ........................................................................................................................... 401

Stop the Processor............................................................................................................................................... 402

Store Index Register X to Memory ..................................................................................................................... 403

Store Index Register Y to Memory ..................................................................................................................... 404

Store Zero to Memory......................................................................................................................................... 405

Transfer Accumulator to Index Register X ........................................................................................................ 406

Transfer Accumulator to Index Register Y ........................................................................................................ 407

Transfer 16-Bit Accumulator to Direct Page Register ....................................................................................... 408

Transfer Accumulator to Stack Pointer ............................................................................................................. 409

Transfer Direct Page Register to 16-Bit Accumulator ....................................................................................... 410

Test and Reset Memory Bits Against Accumulator............................................................................................ 411

Test and Set Memory Bits Against Accumulator ............................................................................................... 412

Transfer Stack Pointer to 16-Bit Accumulator................................................................................................... 413

Transfer Stack Pointer to Index Register X ....................................................................................................... 414

Transfer Index Register X to Accumulator ........................................................................................................ 415

Transfer Index Register X to Stack Pointer ....................................................................................................... 416

Transfer Index Register X to Y .......................................................................................................................... 417

Transfer Index Register Y to Accumulator ........................................................................................................ 418

Transfer Index register Y to X............................................................................................................................ 419

Wait for Interrupt............................................................................................................................................... 420

Reserved for Future Expansion .......................................................................................................................... 421

Exchange the B and A Accumulators ................................................................................................................. 422

Exchange Carry and Emulation Bits .................................................................................................................. 423

19) Chapter Nineteen.............................................................................................. 424

Instruction Lists....................................................................................................................................... 424

Processor ............................................................................................................................................................. 434

Addressing mode box:....................................................................................................................................... 434

Operation column: ............................................................................................................................................ 434

Bytes, cycles, and status codes:.......................................................................................................................... 435

Op Code Matrix Legend ..................................................................................................................................... 437

Table of Figures

F

IGURE

1-1 B

INARY

R

EPRESENTATION

............................................................................................................................. 13

F

IGURE

1-2 B

IT

N

UMBERS

............................................................................................................................................... 14

F

IGURE

1-3 AND

ING

B

ITS

............................................................................................................................................... 16

F

IGURE

1-4 OR

ING

B

ITS

.................................................................................................................................................. 17

F

IGURE

1-5 EXCLUSIVE OR

ING

B

ITS

............................................................................................................................ 17

F

IGURE

1-6 COMPLEMENT

ING

B

ITS

............................................................................................................................. 18

F

IGURE

1-7 COMPLEMENT

ING

B

ITS

U

SING

E

XCLUSIVE

OR .......................................................................................... 18

F

IGURE

1-8 M

ULTIPLE

-P

RECISION

A

RITHMETIC

............................................................................................................... 21

F

IGURE

1-9 T

YPICAL

A

SSEMBLER

S

OURCE

C

ODE

............................................................................................................. 23

F

IGURE

2-1 6502 P

ROGRAMMING

M

ODEL

........................................................................................................................ 28

F

IGURE

2-2 I

NITIALIZING THE

S

TACK

P

OINTER TO

$FF ..................................................................................................... 32

F

IGURE

2-3 A

FTER

P

USHING THE

A

CCUMULATOR

............................................................................................................. 33

F

IGURE

2-4 I

NDEXING

: B

ASE

P

LUS

I

NDEX

........................................................................................................................ 35

F

IGURE

2-5 I

NDIRECTION

: O

PERAND

L

OCATES

I

NDIRECT

A

DDRESS

.................................................................................. 36

F

IGURE

4-1 65816 N

ATIVE

M

ODE

P

ROGRAMMING

M

ODEL

.............................................................................................. 46

F

IGURE

4-2 R

ESULTS OF

S

WITCHING

R

EGISTER

S

IZE

........................................................................................................ 51

8

The Western Design Center

F

IGURE

4-3 65802 N

ATIVE

M

ODE

P

ROGRAMMING

M

ODEL

.............................................................................................. 57

F

IGURE

4-4 65816 E

MULATION

M

ODE

P

ROGRAMMING

M

ODEL

........................................................................................ 60

F

IGURE

6-1 S

TACK

M

EMORY

.......................................................................................................................................... 75

F

IGURE

6-2. P

USH

.......................................................................................................................................................... 77

F

IGURE

6-3 R

EGISTER

T

RANSFERS

B

ETWEEN

D

IFFERENT

-S

IZED

R

EGISTERS

..................................................................... 83

F

IGURE

7-1 I

MMEDIATE

A

DDRESSING

: 8

VS

. 16

BITS

...................................................................................................... 91

F

IGURE

7-2 A

BSOLUTE

A

DDRESSING

............................................................................................................................... 93

F

IGURE

7-3 Z

ERO

P

AGE

A

DDRESSING

.............................................................................................................................. 94

F

IGURE

7-4 I

NDEXING

.................................................................................................................................................... 97

F

IGURE

7-5 I

NDEXING

B

EYOND THE

E

ND OF THE

B

ANK

................................................................................................... 98

F

IGURE

7-6 A

BSOLUTE

I

NDEXING WITH A

G

ENERIC

I

NDEX

R

EGISTER

............................................................................. 100

F

IGURE

7-7 D

IRECT

P

AGE

I

NDEXING WITH A

G

ENERIC

I

NDEX

R

EGISTER

......................................................................... 102

F

IGURE

7-8 D

IRECT

P

AGE

I

NDIRECT

A

DDRESSING

......................................................................................................... 105

F

IGURE

7-9 A

BSOLUTE

L

ONG

A

DDRESSING

................................................................................................................... 108

F

IGURE

7-10 D

IRECT

P

AGE

I

NDIRECT

L

ONG

A

DDRESSING

.............................................................................................. 110

F

IGURE

8-1 J

UMP

S

A

BSOLUTE

I

NDIRECT

A

DDRESSING

M

ODE

....................................................................................... 113

F

IGURE

8-2. R

ELATIVE

B

RANCH

C

ALCULATION

............................................................................................................ 115

F

IGURE

8-3. L

INKED

L

IST

............................................................................................................................................. 117

F

IGURE

10-1 T

HE

AND O

PERATION

.............................................................................................................................. 140

F

IGURE

10-2 S

HIFT AND

R

OTATE

L

EFT

.......................................................................................................................... 148

F

IGURE

10-3 S

HIFT AND

R

OTATE

R

IGHT

........................................................................................................................ 149

F

IGURE

11-1 P

OSTINDEXING

......................................................................................................................................... 159

F

IGURE

11-2 P

REINDEXING

........................................................................................................................................... 162

F

IGURE

11-3 A

BSOLUTE

I

NDEXED

I

NDIRECT

.................................................................................................................. 165

F

IGURE

11-4 P

OSTINDEXED

L

ONG

................................................................................................................................. 167

F

IGURE

11-5 S

TACK

R

ELATIVE

..................................................................................................................................... 168

F

IGURE

11-6 S

TACK

R

ELATIVE

I

NDIRECT

I

NDEXED

........................................................................................................ 169

F

IGURE

11-7 PEA A

DDRESSING

.................................................................................................................................... 170

F

IGURE

11-8 PEI A

DDRESSING

..................................................................................................................................... 171

F

IGURE

11-9. PER A

DDRESSING

................................................................................................................................... 172

F

IGURE

12-1 JSR ......................................................................................................................................................... 176

F

IGURE

12-2 RTS......................................................................................................................................................... 177

F

IGURE

12-3 JSL.......................................................................................................................................................... 178

F

IGURE

12-4 RTL ........................................................................................................................................................ 179

F

IGURE

13-1 I/O M

ANAGEMENT

: I

NTERRUPTS VS

. P

OLLING

.......................................................................................... 193

F

IGURE

13-2 I

NTERRUPT

P

ROCESSING

........................................................................................................................... 194

F

IGURE

13-3B

REAK

S

IGNATURE

B

YTE

I

LLUSTRATION

.................................................................................................... 197

F

IGURE

13-4 6522 VIA I

NTERRUPT

F

LAG

R

EGISTER

...................................................................................................... 198

F

IGURE

14-1 S

TACK

S

NAPSHOT AFTER

PEI (12) I

NSTRUCTION

....................................................................................... 218

F

IGURE

15-1 D

ISASSEMBLY

O

UTPUT

............................................................................................................................. 231

F

IGURE

15-2 T

RACER

O

UTPUT

...................................................................................................................................... 231

F

IGURE

17-1 6502/65C02 P

ROGRAMMING

M

ODEL

........................................................................................................ 284

F

IGURE

17-2. 65802 N

ATIVE

M

ODE

P

ROGRAMMING

M

ODEL

.......................................................................................... 285

F

IGURE

17-3 65816 N

ATIVE

M

ODE

P

ROGRAMMING

M

ODEL

........................................................................................... 286

F

IGURE

17-4 65816 E

MULATION

M

ODE

P

ROGRAMMING

M

ODEL

.................................................................................... 287

F

IGURE

18-1 AND T

RUTH

T

ABLE

................................................................................................................................. 328

F

IGURE

18-2 ASL ........................................................................................................................................................ 329

F

IGURE

18-3 65802/65816 S

TACK

A

FTER

BRK............................................................................................................. 339

F

IGURE

18-4 S

TACK AFTER

COP................................................................................................................................... 349

F

IGURE

18-5E

XCLUSIVE

OR T

RUTH

T

ABLE

.................................................................................................................... 355

F

IGURE

18-6 LSR ......................................................................................................................................................... 366

F

IGURE

18-7 L

OGICAL

OR T

RUTH

T

ABLE

..................................................................................................................... 370

F

IGURE

18-8 ROL ........................................................................................................................................................ 389

F

IGURE

18-9 ROR........................................................................................................................................................ 390

F

IGURE

18-10N

ATIVE

M

ODE

S

TACK BEFORE

RTI. .......................................................................................................... 391

F

IGURE

18-11 S

TACK BEFORE

RTL ............................................................................................................................... 393

F

IGURE

18-12 S

TACK BEFORE

RTS ............................................................................................................................... 394

9

The Western Design Center

Table of Tables

T

ABLE

1-1 D

ECIMAL AND

H

EX

N

UMBERS

........................................................................................................................ 15

T

ABLE

1-2 T

RUTH

T

ABLE FOR

AND ............................................................................................................................... 17

T

ABLE

1-3 T

RUTH

T

ABLE FOR

OR ................................................................................................................................... 17

T

ABLE

1-4 T

RUTH

T

ABLE FOR

EXCLUSIVE OR ............................................................................................................. 17

T

ABLE

1-5 T

RUTH

T

ABLE FOR

COMPLEMENT .............................................................................................................. 18

T

ABLE

1-6 T

HE

E

IGHT

-B

IT

R

ANGE OF

T

WO

S

-C

OMPLEMENT

N

UMBERS

............................................................................ 19

T

ABLE

1-7 T

HE

F

IRST

16 BCD N

UMBERS

........................................................................................................................ 20

T

ABLE

2-1 S

TATUS

R

EGISTER

C

ONDITION

C

ODE

F

LAGS

.................................................................................................... 30

T

ABLE

2-2 S

TATUS

R

EGISTER

M

ODE

S

ELECT

F

LAGS

......................................................................................................... 31

T

ABLE

2-3 6502 A

DDRESSING

M

ODES

............................................................................................................................ 34

T

ABLE

2-4 6502 I

NSTRUCTIONS

...................................................................................................................................... 37

T

ABLE

3-1 T

HE

65C02’

S

N

EW

A

DDRESSING

M

ODES

......................................................................................................... 41

T

ABLE

3-2. N

EW

65C02 I

NSTRUCTIONS

.......................................................................................................................... 42

T

ABLE

4-1 T

HE

F

OUR

P

OSSIBLE

N

ATIVE

M

ODE

R

EGISTER

C

OMBINATIONS

....................................................................... 49

T

ABLE

4-2 A

DDRESSING

M

ODES

: Z

ERO

P

AGE VS

. D

IRECT

P

AGE

..................................................................................... 52

T

ABLE

4-3 T

HE

65816/65802’

S

N

EW

A

DDRESSING

M

ODES

.............................................................................................. 53

T

ABLE

4-4 N

EW

65816/65802 I

NSTRUCTIONS

................................................................................................................. 54

T

ABLE

4-5 I

NTERRUPT

V

ECTOR

L

OCATIONS

.................................................................................................................... 55

T

ABLE

6-1 D

ATA

M

OVEMENT

I

NSTRUCTION

.................................................................................................................... 70

T

ABLE

7-1 L

IST OF

S

IMPLE

A

DDRESSING

M

ODES

............................................................................................................. 89

T

ABLE

8-1. B

RANCH AND

J

UMP

I

NSTRUCTIONS

.............................................................................................................. 111

T

ABLE

9-1 A

RITHMETIC

I

NSTRUCTIONS

........................................................................................................................ 122

T

ABLE

9-2. E

QUALITIES

................................................................................................................................................ 131

T

ABLE

10-1 L

OGIC

I

NSTRUCTIONS

................................................................................................................................ 139

T

ABLE

11-1 C

OMPLEX

A

DDRESSING

M

ODES

................................................................................................................. 154

T

ABLE

11-2 C

OMPLEX

P

USH

I

NSTRUCTIONS

.................................................................................................................. 154

T

ABLE

11-3 A

SSEMBLER

S

YNTAX FOR

C

OMPLETE

M

EMORY

A

CCESS

............................................................................. 157

T

ABLE

12-1 S

UBROUTINE

I

NSTRUCTIONS

...................................................................................................................... 174

T

ABLE

13-1. I

NTERRUPT AND

S

YSTEM

C

ONTROL

I

NSTRUCTIONS

. ................................................................................... 192

T

ABLE

13-2 I

NTERRUPT

V

ECTORS

................................................................................................................................. 195

T

ABLE

13-3 R

ESET

I

NITIALIZATION

............................................................................................................................... 201

T

ABLE

17-1 O

PERAND

S

YMBOLS

.................................................................................................................................. 284

T

ABLE

18-1 O

PERAND

S

YMBOLS

.................................................................................................................................. 326

T

ABLE

18-2 65

X

F

LAGS

................................................................................................................................................ 326

10

The Western Design Center

Part 1

Basics

11

The Western Design Center

1) Chapter One

Basic Assembly Language Programming Concepts

This chapter reviews some of the key concepts that must be mastered prior to learning to program a computer in assembly language. These concepts include the use of the binary and hexadecimal number systems; boolean logic; how memory is addressed as bytes of data; how characters are represented as ASCII codes; binary-coded decimal (BCD) number systems, and more. The meaning of these terms is explained in this chapter. Also discussed is the use of an assembler, which is a program used to write machine-language programs, and programming techniques like selection, loops, and subroutines.

Since the primary purpose of this book is to introduce you to programming the 65816 and the other members of the 65x family, this single chapter can only be a survey of this information rather than a complete guide

.

Binary Numbers

In its normal, everyday work, most of the world uses the decimal, or base ten, number system, and everyone takes for granted that this system is the “natural” (or even the only) way to express the concept of numbers. Each place in a decimal number stands for a power of ten: ten to the 0 power is 1, ten to the 1 st

power is ten, ten to the 2 nd

power is 100, and so on. Thus, starting from a whole number’s right-most digit and working your way left, the first digit is multiplied by the zero power of ten, the second by the first power of ten, and so on. The right-most digits are called the low-order or least significant digits in a positional notation system such as this, because they contribute least to the total magnitude of the number; conversely, the leftmost digits are called the high-order or most significant digits, because they add the most weight to the value of the number. Such a system is called a positional notation system because the position of a digit within a string of numbers determines its value.

Presumably, it was convenient and natural for early humans to count in multiples of ten because they had ten fingers to count with. But it is rather inconvenient for digital computers to count in decimal; they have the equivalent of only one finger, since the representation of numbers in a computer is simply the reflection of electrical charges, which are either on or off in a given circuit. The all or nothing nature of digital circuitry lends itself to the use of the binary, or base two, system of numbers, with one represented by “on” and zero represented by “off”. A one or a zero in binary arithmetic is called a binary digit, or a bit for short.

Like base ten digits, base two digits can be strung together to represent numbers larger than a single digit can represent, using the same technique of positional notation described for base ten numbers above. In this case, each binary digit is such a base two number represents a power of two, with a whole number’s rightmost bit representing two to the zero power (ones), the next bit representing two to the first power (twos), the next representing two to the second power (fours), and so on (Figure 1-1 Binary

Representation

)

12

The Western Design Center

Grouping Bits into Bytes

As explained, if the value of a binary digit, or bit, is a one, it is stored in a computer’s memory by switching to an “on” or charged state, in which case the bit is described as being set; if the value of a given bit is a zero, it is marked in memory by switching to an “off” state, and the bit is said to be reset.

While memory may be filled with thousands or even millions of bits, a microprocessor must be able to deal with them in a workable size.

0 1 1 0 0 1 1 0

32

64

102

2

4

Figure 1-1 Binary Representation

The smallest memory location that can be individually referenced, or addressed, is usually, and always in the case of the 65x processors, a group of eight bits. This basic eight-bit unit of memory is known as a byte.

Different types of processors can operate on different numbers of bits at any given time, with most microprocessors handling one, two, or four bytes of memory in a single operation. The 6502 and 65C02 processors can handle only eight bits at a time. The 65816 and 65802 can process either eight or sixteen bits at a time.

Memory is organized as adjacent, non-overlapping bytes, each of which has its own specific address.

An address is the unique, sequential identifying number used to reference the byte at a particular location.

Addresses start at zero and continue in ascending numeric order up to the highest addressable location.

As stated, the 65802 and 65816 can optionally manipulate two adjacent bytes at the same time; a sixteen-bit data item stored in two contiguous bytes is called a double byte in this book. A more common but misleading usage is to describe a sixteen-bit value as a word; the term word is more properly used to describe the number of bits a processor fetches in a single operation, which may be eight, sixteen, thirty-two, or some other number of bits depending on the type of processor.

It turns out that bytes – multiples of eight bits – are conveniently sized storage units for programming microprocessors. For example, a single byte can readily store enough information to uniquely represent all of the characters in the normal computer character set. An eight-bit binary value can be easily converted to two hexadecimal (base sixteen) digits; this fact provides a useful intermediate notation between the binary and decimal number systems. A double byte can represent the entire range of memory addressable by the 6502,

65C02, and 65802, and one complete bank – 64K bytes – on the 65816. Once you’ve adjusted to it, you’ll find that there is a consistent logic behind the organization of a computer’s memory into eight-bit bytes.

Since the byte is one of the standard units of a computer system, a good question to ask at this point would be just how large a decimal number can you store in eight bits? The answer is 255. The largest binary number you can store in a given number of bits is the number represented by that many one-bits. In the case of

13

The Western Design Center

the byte, this is 11111111, or 255 decimal (or 2

8

- 1). Larger numbers are formed by storing longer bit-strings in consecutive bytes.

The size of a computer’s memory is typically expressed in bytes, which makes sense because the byte is the smallest addressable unit. And since a byte is required to store the representation of a single alphanumeric character, you can get an easy visualization of about how much storage 64K of memory is by thinking of that many characters. The K stands for one thousand (from the Greek kilo meaning thousand, as in kilogram or kilometer); however, since powers of two are always much more relevant when discussing computer memories, the symbol K in this context actually stands for 1024 bytes, the nearest power-of-two approximation of 1000, so

64K is 65,536 bytes, 128K is 131,072 bytes, and so on. Within a given byte (or double byte) it is often necessary to refer to specific bits within the word. Bits are referred to by number. The low-order, or right-most bit, is called bit zero; this corresponds to the one’s place. The next-higher-order bit is bit one, and so on. The high-order bit of a byte is therefore bit seven; of a double byte, bit fifteen. The convention of calling the lowerorder bit the “right-most” is consistent with the convention used in decimal positional notation; normal decimal numbers are read from left to right, from high-order to low-order. Figure 1.2 illustrates the bit numbers for bytes and double bytes, as well as the relative weights of each bit position.

Double-Byte

Byte

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

High-Order Low-Order

Hexadecimal Representation of Binary

Figure 1-2 Bit Numbers

While binary is a convenient number system for computers to use, it is somewhat difficult to translate a series of ones and zeros into a number that is meaningful. Any number that can be represented by eight binary bits can also be represented by two hexadecimal (or hex for short) digits. Hexadecimal numbers are base sixteen numbers. Since base two uses the digits zero through one, and base ten the digits zero through nine, clearly base sixteen must use digits standing for the numbers zero through fifteen. Table 1.1 is a chart of the sixteen possible four-bit numbers, with their respective decimal and hexadecimal representations.

14

The Western Design Center

Binary

0111

1000

1001

1010

1011

1100

1101

1110

1111

0000

0001

0010

0011

0100

0101

0110

Decimal

7

8

9

10

11

12

13

14

15

5

6

3

4

0

1

2

Hexadecimal

0

1

2

9

A

7

8

B

5

6

3

4

C

D

E

F

Table 1-1 Decimal and Hex Numbers

Because the positional notation convention reserves only a single place for each multiplier of the power of that base, the numbers ten through fifteen must be represented by a single base-sixteen digit. Rather than create entirely new symbols for digits, the first six letters of the alphabet were chosen to represent the numbers ten through fifteen. Each of the sixteen hex digits corresponds to one of the possible combinations of four binary digits.

Binary numbers larger than 1111 are converted to hexadecimal by first separating the bits into groups of fur, starting from the right-most digit and moving left. Each group of four bits is converted into its corresponding hex equivalent. It is generally easier to work with a hexadecimal number like F93B than its binary counterpart 111100100111011. Hexadecimal numbers are often used by machine language programming tools such as assemblers, monitors, and debuggers to represent memory addresses and their contents. The value of hexadecimal numbers is the ease with which they can be converted to and from their binary equivalents once the table has been memorized.

While a hexadecimal 3 and a decimal 3 stand for the same number, a hexadecimal 23 represents two decimal sixteen’s plus 3, or 35 decimal. To distinguish a multiple-digit hex number from a decimal one, either the word hexadecimal should precede or follow it, or a ‘$’ should prefix it, as in $23 for decimal 35, or $FF to represent 255. A number without any indication of base is presumed to be decimal. An alternative notation for hexadecimal numbers is to use the letter H as a suffix to the number (for example, FFH); however, the dollarsign prefix is generally used by assemblers for the 65x processors.

The ASCII

Characters – letters, numbers, and punctuation – are stored in the computer as number values, and translated to and from readable form on input or output by hardware such as keyboards, printers, and CRTs.

There are 26 English-language lower-case letters, another 26 upper-case ones, and a score or so of special characters, plus the ten numeric digits, any of which might be typed from a keyboard or displayed on a screen or printer, as well as stored or manipulated internally. Further, additional codes may be needed to tell a terminal or printer to perform a given function, such as cursor or print head positioning. These control codes including

carriage return, which returns the cursor or print head to the beginning of a line; line feed, which moves the cursor or print head down a line; bell, which rings a bell; and back space, which moves the cursor or print head back one character.

The American Standard Code for Information Interchange abbreviated ASCII and pronounced AS key, was designed to provide a common representation of characters for all computers. An ASCII code is stored in the low-order seven bits of a byte; the most significant bit is conventionally a zero, although a system can be designed either to expect it to be set or to ignore it. Seven bits allow the ASCII set to provide 128 different character codes, one for each English letter and number, most punctuation marks, the most commonly use mathematical symbols, and 32 control codes.

15

The Western Design Center

The use of different bit values, or numbers, to store character codes, is entirely analogous to the

“decoder ring” type of cipher: the letter ‘A’ is one, ‘B’ is two, and so on; but in the case of the ASCII character set, the numbers assigned to the letters of the alphabet are different, and there are different codes for upper- and lower-case letters.

There is an ASCII chart in Appendix F of this book. Notice that since the decimal digits 0 through 9 are represented by $30 to $39, they can be easily converted between their binary representations and their actual values by the addition or subtraction of $30. The letters are arranged in alphabetical order, the capital letters from A through Z represented by $41 through $5A and the lower-case letters from a through z represented by

$61 through $7A. This allows letters to be placed in alphabetical order by numerically sorting their ASCII values, and characters to be converted between upper- and lower-case by the addition or subtraction of $20.

Finally, notice that the control characters from [email protected] and Ctrl-A through Ctrl-Z and on to Ctrl-_ run from zero to $1F and allow easy conversion between the control characters and the equivalent printing characters by the addition or subtraction of $40.

To print a character on an output device, you must send it the ASCII value of the character: to print an

‘A’, you must send $41 to the screen, not $A, which is the ASCII code for a line feed; and to print an ’8’, you must send $38, not $8, which is the ASCII code for a backspace. The space character, too, has and ASCII code:

$20.

Since any memory value – take $41 for example – could represent either an ASCII code (for ‘A’ in this case) or a number (decimal 65), the interpretation of the data is defined by the code of the program itself and how it treats each piece of data it uses within a give context.

Boolean Logic

Logical operations interpret the binary on/off states of a computer’s memory as the values true and

false rather than the numbers one and zero. Since the computer handles data one or two bytes at a time, each logical operation actually manipulates a set of bits, each with its own position.

Logical operations manipulate binary “flags”. There are three logical operations that are supported by

65x microprocessor instructions, each combining two operands to yield a logical (true or false) result: and, or, and exclusive or.

Logical And

The AND operator yields true only if both of the operands are themselves true; otherwise, it yields false. Remember, true is equivalent to one, and false equivalent to zero. Within the 65x processors, two strings of eight, or in the case of the 65816, eight or sixteen, individual logical values may be ANDed, generating a third string of bits; each bit in the third set is the result of ANDing the respective bit in each of the first two operands. As a result, the operation is called bitwise.

When considering bitwise logical operations, it is normal to use binary representation. When considered as a numeric operation on two binary numbers, the result given in Figure 1.3 makes little sense. By examining each bit of the result, however, you will see that each has been determined by ANDing the two corresponding operand bits.

AND equals

11011010

01000110

01000010

$DA

$45

$42

Figure 1-3 ANDing Bits

16

The Western Design Center

A truth table can be drawn for two-operand logical operations. You find the result of ANDing two bits by finding the setting of one bit on the left and following across until you’re under the setting of the other bit.

Table 1.2 shows the truth table for AND.

Second Operand

0 1

First Operand

0 0 0

1 0 1

Table 1-2 Truth Table for AND

Logical Or

The OR operator yields a one or true value if either (or both) of the operands is true. Taking the same values as before, examine the result of the logical OR operation in Figure 1.4. The truth table for the OR function is shown in Table 1.3.

OR equals

11011010

01000110

11011110

$DA

$45

$DE

Figure 1-4 ORing Bits

Logical Exclusive Or

The exclusive OR operator is similar to the previously-described OR operation; in this case, the result is true only if one or the other of the operands is true, but not if both are true or (as with OR) neither is true.

That is, the result is true only if the operands are different, as Figure 1.5 illustrates using the same values as before. The truth table for exclusive OR is shown in Table 1.4.

Second Operand

0 1

First Operand

0 0 1

1 1 1

Table 1-3 Truth Table for OR

EOR equals

11011010

01000110

10011100

$DA

$45

$9C

0 1

Figure 1-5 EXCLUSIVE ORing Bits

Second Operand

First Operand

0 0 1

1 1 0

Table 1-4 Truth Table for EXCLUSIVE OR

Logical Complement

As Figure 1.6 shows, the logical complement of a value is its inverse: the complement of true is false, and the complement of false is true.

17

The Western Design Center

11011010

COMPLEMENTED equals 00100101

Figure 1-6 COMPLEMENTing Bits

$DA

$25

While the 65x processors have no complement or not function built in, exclusive ORing a value with a string of ones ($FF or $FFFF) produces the complement, as Figure 1.7 illustrates.

EOR equals Complement

11011010

11111111

00100101

$DA

$FF

$25

Figure 1-7 COMPLEMENTing Bits Using Exclusive OR

Since complement has only one operand, its truth table, drawn in Table 1.5, is simpler than the other truth tables.

operand

0

1 result

1

0

Table 1-5 Truth Table for COMPLEMENT

Signed Numbers

Many programs need nothing more than the whole numbers already discussed. But others need to store and perform arithmetic on both positive and negative numbers.

Of the possible systems for representing signed numbers, most microprocessors, among them those in the 65x family, use two’s complement. Using two’s-complement form, positive numbers are distinguished from negative ones by the most significant bit of the number: a zero means the number is positive; a one means it is negative.

To negate a number in the two’s-complement system, you first complement each of its bits, then add one. For example, to negate one (to turn plus-one into minus-one):

00000001

11111110

+1

11111111

To negate +1, complement each bit and add one.

The result is – 1.

So $FF if the two’s-complement representation of minus-one. When converting to two’s complement by hand, an easier technique than the two-step process is to copy zeroes from the right (least significant bit) until the first one is reached; copy that one, and then change every zero to a one and every one to a zero as you continue to the left. Try it on the example above.

Now, instead of using eight bits to represent the integers from zero to 255, two’s-complement arithmetic uses eight bits to represent signed numbers from –128 ($80) to + 127 ($7F), as Table 1.6 shows.

There is always one more negative than positive number in a two’s-complement system.

18

The Western Design Center

Decimal

+127

+126

+125

.

.

.

-126

.

-127

-128

.

.

+1

0

-1

-2

-3

Hexadecimal

$7F

$7E

$7D

.

.

.

$FF

$FE

$FD

1

0

$82

.

$81

$80

.

.

Binary

0111 1111

0111 1110

0111 1101

.

.

.

0000 0001

0000 0000

1111 1111

1111 1110

1111 1101

.

.

.

1000 0010

1000 0001

1000 0000

Table 1-6 The Eight-Bit Range of Two’s-Complement Numbers

Another practical way to think of negative two’s-complement numbers is to think of negative numbers as the (unsigned) value that must be added to the corresponding positive number to produce zero as the result.

For example, in an eight-bit number system, the value that must be added to one to produce zero (disregarding the carry) is $FF; 1+$FF=$100, or 0 if only the low-order eight bits is considered. $FF must therefore be the two’s-complement value for minus one.

The introduction of two’s-complement notation creates yet another possibility in interpreting the data stored at an arbitrary memory location. Since $FF could represent either the unsigned number 255 or the negative integer minus-one, it’s important to remember that it is only the way in which a program interprets the data stored in memory that gives it its proper value – signed or unsigned.

Storing Numbers in Decimal Form

Computers use numbers in binary form most efficiently. But when a program calls for decimal numbers to be entered or output frequently, storing numbers in their decimal form – rather than converting them to binary and back – may be preferable. Further, converting floating-point decimal numbers to a binary floating-point form and back can introduce errors: for example, 8 minus 2.1 could result in 5.90000001 rather than the correct answer, 5.9.

As a result, some programs, such as accounting applications, store numbers in decimal form, each decimal digit represented by four bits, yielding two decimals digits per byte, as Table 1.7 shows. This form is called binary-coded decimal BCD lies somewhere between the machine’s native binary and abstractions such as the ASCII character codes for numbers.

Since four bits can represent the decimal numbers from zero to fifteen, using the same number of bits to represent only the numbers from zero through nine wastes six combinations of the binary digits. This less than optimal use of storage is the price of decimal accuracy and convenience.

19

The Western Design Center

Binary

0000 0000

0000 0001

0000 0010

0000 0011

0000 0100

0000 0101

0000 0110

0000 0111

0000 1000

0000 1001

0000 1010

0000 1011

0000 1100

0000 1101

0000 1110

0000 1111

Hexadecimal

8

9

A

6

7

2

3

0

1

4

5

B

C

D

E

F

Decimal

8

9

10

6

7

2

3

0

1

4

5

11

12

13

14

15

BCD

0000 0000

0000 0001

0000 0010

0000 0011

0000 0100

0000 0101

0000 0110

0000 0111

0000 1000

0000 1001

0001 0000

0001 0001

0001 0010

0001 0011

0001 0100

0001 0101

Table 1-7 The First 16 BCD Numbers

The 65x processors have a special decimal mode which can be set by the programmer. When decimal mode is set, numbers are added and subtracted with the assumption that they are BCD numbers: in BCD mode, for example, 1001+1 (9+1) yields the BCD results of 0001 0000 rather than the binary result of 1010 (1010 has no meaning in the context of BCD number representation).

Obviously, in different context 0001 0000 could represent either 10 decimal or $10 hexadecimal (16 decimal); in this case, the interpretation is dependent on whether the processor is in decimal mode or not.

Computer Arithmetic

Binary arithmetic is just like decimal arithmetic, except that the highest digit isn’t nine, it’s one. Thus

1+0=1, while 1+1=0 with a carry of 1, or binary 10. Binary of 10 is equivalent of a decimal 2. And 1-0=1, while during the subtraction of binary 1 from binary 10, the 1 can’t be subtracted from the 0, so a borrow is done, getting the 1 from the next position (leaving it 0); thus, 10-1=1.

Addition and subtraction are generally performed in one or more main processor registers, called accumulators. On the 65x processors, they can store either one or, optionally on the 65802 and 65816, two bytes. When two numbers are added that cause a carry from the highest bit in the accumulator, the result is larger than the accumulator can hold. To account for this, there is a special one-bit location, called a carry bit, which holds the carry out of the high bit from an addition. Very large numbers can be added by adding the loworder eight or sixteen bits (whichever the accumulator holds) of the numbers, and then adding the next set of bit plus the carry from the previous addition, and so on. Figure 1.8 illustrates this concept of multiple-precision arithmetic.

Microprocessor Programming

You have seen how various kinds of data are represented and, in general, how this data can be manipulated. To make those operations take place, a programmer must instruct the computer on the steps it must take to get the data, the operations to perform on it, and finally the steps to deliver the results in the appropriate manner. Just as a record player is useless without a record to play, so a computer is useless without a program to execute.

Machine Language

The microprocessor itself speaks only one language, its machine language, which inevitably is just another form of binary data. Each chip design has its own set of machine language instructions, called its

instruction set, which defines the function that it can understand and execute. Whether you program in machine language, in its corresponding assembly language, or in a higher level language like BASIC or Pascal, the instructions that the microprocessor ultimately executes are always machine language instructions.

Programs in assembly and higher-level languages are translated (by assemblers, compilers and interpreters) to machine language before the processor can execute them.

20

The Western Design Center

Each machine language instruction in the 65x series of microprocessors is one to four bytes long. The first byte of each instruction is called the operation code (opcode for short); it specifies the operation the computer is to do. Any additional bytes in the instruction make up the operand, typically all or part of an address to be accessed, or a value to be processed

.

0 0 1 1 1 0 0 0 1 0 0 0 0 0 1 1

$38 $83

1 0 1 0 0 1 0 1 1 0 1 0 0

Plus $A5 Plus $A5

1 0 1

PLUS CARRY 1

1 1 0 1 1

Equal $DE

1 1 0 0 0 1 0 1

Equals

$28

0 0 0

$3883 Plus $A5A5 Equals $DE28

Figure 1-8 Multiple-Precision Arithmetic

Carry = 1

21

The Western Design Center

Assembly Language

Writing long strings of hexadecimal or binary instructions to program a computer is obviously not something you would want to do if you could at all avoid it. The 65816’s 256 different opcodes, for example, would be difficult to remember in hexadecimal form – and even harder in binary form. Assembly language, and programs which translate assembly language to machine code (called assemblers) were devised to simplify the task of machine programming.

Assembly language substitutes a short word – known as a mnemonic (which means memory aid) – for each binary machine code instruction. So while the machine code instruction 1010 1010, which instructs the

65x processor to transfer the contents of the A accumulator to the X index register, may be hard to remember, its assembler mnemonic TAX (for “Transfer A to X”) is much easier.

The entire set of 65x opcodes are covered alphabetically by mnemonic label in Chapter Eighteen, while

Chapter Five through Thirteen discuss them in functional groups, introducing each of them, and providing examples of their use.

To write an assembly language program, you first use a text editing program to create a file containing the series of instruction mnemonics and operands that comprise it; this is called the source program, source

code or just source. You then use this as the input to the assembler program, which translates the assembler statements into machine code, storing the generated code in an output file. The machine code is either in the form of executable object code, which is ready to be executed by the computer, or (using some development systems), a relocatable object module, which can be linked together with other assembled object modules before execution.

If this were all that assembly language provided, it would be enough to make machine programming practical. But just as the assembler lets you substitute instruction mnemonics for binary operation codes, it lets you use names for the memory locations specified in operands so you don’t have to remember or compute their addresses. By naming routines, instructions which transfer control to them can be coded without having to know their addresses. By naming constant data, the value of each constant is stated only in one place, the place where it is named. If a program modification requires you to change the values of the constants, changing the definition of the constant in that one place changes the value wherever the name has been used in the program.

These symbolic names given to routines and data are known as labels.

As your source program changes during development, the assembler will resolve each label reference anew each time an assembly is performed, allowing code insertions and deletions to be made. If you hardcoded the addresses yourself, you would have to recalculate them by hand each time you inserted or deleted a line of code.

The use of an assembler also lets you comment your program within the source file – that is, to explain in English what it is you intend the adjacent assembly statements to do and accomplish.

More sophisticated macro assemblers take symbol manipulation even further, allowing special labels, called macro instructions (or just macros for short), to be assigned to a whole series of instructions. Macro is a Greek word meaning long, so a macro instruction is a “long” instruction. Macros usually represent a series of instructions which will appear in the code frequently with slight variations. When you need the series, you can type in just the macro name, as though it were an instruction mnemonic; the assembler automatically “expand” the macro instruction to the previously-defined string of instructions. Slight variations in the expansion are provided for by a mechanism that allows macro instructions to have operands.

Writing in Assembly Language

In addition to understanding the processor you’re working with, you must also have a good knowledge of the particular assembler you are using to program in assembly language. While the specific opcodes used are carved in the silicon die of the processor itself, the mnemonics for those opcodes are simple conventions and may vary slightly from one assembler to another (although the mnemonics proposed by a processor’s manufacturer will tend to be seen as the standard). Varying even more widely are assembler directives – assembler options which can be specified in the midst of code. These options tell the assembler such things as where to locate the program in memory, which portions of the source listing to print, or what labels to assign to constants.

22

The Western Design Center

Nevertheless, most microcomputer assemblers have a great deal in common. They generally provide four columns, or fields, for different types of information about an operation: a label which can be used to symbolically identify the location of the code; the opcode; the operand; and space for comments. Figure 1.9

illustrates some typical assembler source code, with the different fields highlighted.

While an opcode or directive appears in every assembler statement, the operand field may or may not be required by any particular opcode, since there are several one-byte instructions which consist solely of an opcode. The label and comment field are optional, added to make the program easier to read, write, debug, and modify later.

During assembly, the assembler checks the fields to be sure the information there is complete, of the proper type, and not out of order, and issues error messages to warn you problems. It also checks to be sure you have not tried to define the same label twice, and that you have not used a label you did not define.

Basic Programming Concepts

execute.

There are several concepts which, in general terms, characterize the different ways a program can

The most obvious concept is that of straight-line execution: a program starts in low memory and steps a few bytes higher into memory with execution of each new instruction until it reaches the end, never doubling back or jumping forward. Straight-line execution is clean and clear: it begins at the beginning, executes every instruction in the program once, and ends at the end. This type of execution is the default execution mode. The

65x processors have register called the program counter, which is automatically updated at the end of each instruction so that it contains the address of the next instruction to be executed

.

Label

Field

Opcode

Field

Operand

Field

Comment

Field

REP

LONGI

#$10

ON

SEP #$20

LONGA OFF

LDY

LOOP LDA

BEQ

CMP

BNE

INY

BRA

;

PASS

FAIL

#0

(1,S),Y

PASS

(3,S),Y

FAIL

LOOP get character from first string if zero, end of string: match compare to corresponding char in 2 nd bra if not equal; probably failure else do not pair

string matches shortest string

PLP

CLC

BRA

LDA

BEQ

PLP

SEC

EXIT

(3,S),Y

PASS they match up to shortest string; restore status, but clear carry was last failure due to end of string2?

yes; let it pass restore status, but set carry (no match)

Figure 1-9 Typical Assembler Source Code

23

The Western Design Center

Selection Between Paths

Real-life problems – the kind you want to write computer programs to solve – are seldom straight and simple. A computer would be very limited with only straight-line execution capability, that is, if it could not make choices between different courses of action based on the conditions that exist while it is executing.

Selection between paths provides computers with their decision-making capabilities. The 65x microprocessors carry out selection between paths by means of conditional branch instructions.

An example of selection between paths would be a tic-tac-toe program. Playing second, the program must choose where to place its first token from eight different squares. If the opponent has taken the center square, the program must respond differently than if a side square were taken.

Execution still begins at the beginning and ends at the end, in a single pass through the code, but whole groups of instructions on paths not taken are not executed.

Looping

Let’s say you write a program to convert a Fahrenheit temperature to Celsius. If you had only one temperature to convert, you wouldn’t spend the time writing a program. What you want the program to do is prompt for a Fahrenheit temperature, convert it to Celsius, print out the result, then loop back and prompt for another Fahrenheit temperature, and so on – until you run out of temperatures to convert. This program uses a program concept called looping or iteration, which is simply the idea that the same code can be reexecuted repeatedly – with different values for key variables – until a given exit condition. In this case the exit condition might be the entry of a null or empty input string.

Often, it’s not the whole program that loops, but just a portion of it. While a poker program could deal out 20 cards, one at a time, to four players, it would use much less program memory to deal out one card to each of the players, then loop back to do the same thing over again four more times, before going on to take bets and play the poker hands dealt.

Looping saves writing repetitive code over and over again, which is both tedious and uses up memory.

The 65x microprocessors execute loops by means of branch and jump instructions.

Looping almost always uses the principle of selection between paths to handle exiting the loop. In the poker program, after each set of four cards has been dealt to the four players, the program must decide if that was the fifth set of four cards or if there are more to deal. Four times it will select to loop back and deal another set; the fifth time, it will select another path – to break out of the loop to begin prompting for bets.

Subroutines

Even with loops, programmers could find themselves writing the same section of code over and over when it appears in a program not in quick succession but rather recurring at irregular intervals throughout the program. The solution is to make the section of code a subroutine, which the program can call as many times and from as many locations as it needs to by means of a jump-to-subroutine instruction. The program, on encountering the subroutine call, makes note of its current location for purposes of returning to it, then jumps to the beginning of the subroutine code. At the end of the subroutine code, a return-from-subroutine instruction tells the program to return from the subroutine to the instruction after the subroutine call. There are several different types of calls and returns available on the different 65x processors; all of them have a basic call and return instruction in common.

Programmers often build up large libraries of general subroutines that multiply, divide, output messages, send bytes to and receive bytes from a communications line, output binary numbers in ASCII, translate numbers from keyboard ASCII into binary, and so on. Then when one of these subroutines is needed, the programmer can get a copy from the library or include the entire library as part of his program.

24

The Western Design Center

Part 2

Architecture

25

The Western Design Center

2) Chapter Two

Architecture of the 6502

This chapter, and the two which follow, provide overviews of the architecture of the four 65x family processors: the 6502, the 65C02, and the 65802/65816. Each chapter discusses the register set and the function of the individual registers, the memory model, the addressing modes, and the kinds of operations available for each respective processor. Because each successive processor is a superset of the previous one, each of the next two chapters will build on the material already covered. Much of what is discussed in this chapter will not be repeated in the next two chapters because it is true of all 65x processors. As the original 65x machine, the 6502 architecture is particularly fundamental, since it describes a great number of common architectural features.

Microprocessor Architecture

The number, kinds, and sizes of registers, and the types of operations available using them, defines the

architecture of a processor. This architecture determines the way in which programming problems will be solved. An approach which is simple and straightforward on one processor may become clumsy and inefficient on another if the architectures are radically different.

A register is a special memory location within the processor itself, where intermediate results, addresses, and other information which must be accessed quickly are stored. Since the registers are within the processor itself, they can be accessed and manipulated much faster than external memory. Some instructions perform operations on only a single bit within a register; others on two registers at once; and others move data between a register within the processor and external memory. (Although the registers are indeed a special kind of memory, the term memory will be used only to refer to the addressable memory external to the microprocessor registers.)

The 6502 is not a register-oriented machine. As you will see, it has a comparatively small set of registers, each dedicated to a special purpose. The 6502 instead relies on its large number of addressing modes, particularly its direct-page indirect addressing modes, to give it power.

An addressing mode is a method, which may incorporate several intermediate calculations involving index registers, offset, and base addresses, for generating an instruction’s effective address – the memory address at which data is read or written. Many 6502 instructions, such as those for addition, have many alternate forms, each specifying a different addressing mode. The selection of the addressing mode by you, the programmer, determines the way in which the effective address will be calculated.

There are three aspects to learning how to program the 6502 or any processor. Learning the different addressing modes available and how to use them is a big part. Learning the available instructions and operations, such as addition, subtraction, branching, and comparing, is another. But to make sense of either, you must begin by understanding what each of the different registers is and does, and how the memory is organized.

If you compare the different processors in the 65x family – the eight-bit 6502 and 65C02 and the sixteen-bit 65816 and 65802 – you will find they all have a basic set of registers and a basic set of addressing modes in common: the 6502’s.

The 6502 Registers

The 6502 registers are:

The accumulator, or A register, is the primary user register and generally holds one of the operands, as well as the result, of any of the basic data-manipulation instructions.

The X and Y index registers are used chiefly in forming effective addresses for memory accesses and as loop counters.

The processor status, or P, register contains bit-fields to indicate various conditions, modes, and results within the processor.

The stack pointer, or S register, is a pointer to the next available location on the system stack, a special area of memory for temporary data storage. In addition to being available to the user, the stack pointer and stack are also used automatically every time a subroutine is called or an interrupt occurs to store return information.

26

The Western Design Center

Finally, the program counter, or PC, is a pointer to the memory location of the instruction to be executed next.

These six basic 6502 registers are depicted in the programmer model diagrammed in Figure 2.1.

Notice that, with the exception of the program counter (PC), all of them are eight-bit registers. Because they can contain only eight bits, or one byte, of data at a time, they can only perform operations, such as addition, on one byte at a time. Hence the 6502 is characterized as an “eight-bit” processor.

Although the user registers of the 6502 are only eight bits wide, all of the external addresses generated are sixteen bits. This gives the 6502 an address space of 64K (2

16

=65,536). In order to access data located anywhere in that 64K space with an eight bit processor, one instruction operand in calculating effective addresses is almost always found in memory – either in the code itself following an instruction, or at a specified memory location – rather than in a register, because operands in memory have no such limits. All that is needed to make a memory operand sixteen bits are two adjacent memory locations to put them in.

To allow programs longer than 256 bytes, the program counter, which always points to the location of the next instruction to be executed, is necessarily sixteen bits, or two bytes, wide. You may therefore locate a

6502 program anywhere within its 64K address space.

Now each of the 6502 registers will be described in more detail.

The Accumulator

The accumulator (A) is the primary register in the 65x processor. Almost all arithmetic and most local operations are performed on the data in the accumulator, with the result of the operation being stored in the accumulator. For example to add two numbers which are stored in memory, you must first load one of them into the accumulator. Then you add the other to it and the result is automatically stored in the accumulator, replacing the value previously loaded there.

Because the accumulator is the primary user register, there are more addressing modes for accumulator operations than for any other register.

The 6502 accumulator is an eight-bit register. Only one byte is ever fetched from memory when the accumulator is loaded, or for operations which use two values – one from memory and the other in the accumulator (as in the addition example above).

27

The Western Design Center

15

6502 Programming Model

7

Accumulator (A)

X Index Register (X)

Y Index Register (Y)

Program

Stack Pointer (S)

Counter (PC) n v

Processor Status Register (P) b d i z c

0

IRQ Disable

Carry 1= Carry

Zero 1= Result Zero

1= Disable

Decimal Mode

Break Instruction

1= Decimal Mode

1= Break caused

interrupt

Overflow

Negative

Figure 2-1 6502 Programming Model

1= Overflow

1= Negative

28

The Western Design Center

The X and Y Index Registers

The index registers are generally used either as components in generating effective addresses when any of the indexed addressing modes are used, or as loop counters. They can be easily incremented or decremented; that is, the value in the index registers can, by means of a single instruction, be increased or decreased by the number one. They are, therefore, useful in accessing successive table locations, moving memory, and counting loop iterations. Unlike the accumulator, no logical or arithmetic operations (other than incrementing, decrementing, and comparing) may be performed upon them.

The use of indexing allows easy access to continuous series of memory locations, such as a multiplebyte objects. Indexing is performed by adding one of several forms of base addresses, specified in the operand field of an instruction, to the contents of an index register. While a constant operand is fixed when a program is created, the index registers are variable and their contents can be changed readily during the execution of a program. As a result, indexing provides an extremely flexible mechanism for accessing data in memory.

Although the X and Y index registers are basically similar, their capabilities are not identical. Certain instructions and addressing modes work only with one or the other of these registers. The indirect indexed addressing modes require the Y register. And while the X is primarily used with direct page indexed and

absolute indexed addressing, it has its own unique (though infrequently used) indexed indirect addressing mode. These differences will become clear as you learn more about the different addressing modes.

The Status Register

The status register (also called the P register, for processor status) contains a number of flags which describe, in part, the status of the microprocessor and its operations. A flag is, in this case, a single bit within the status register. Its value, set (a one) or reset (a zero), indicates one of two conditions. While the 6502’s eight-bit status register could provide eight one-bit flags, only seven of them are used.

Figure 2.1 showed the 6502 P status register; Tables 2.1 and 2.2 describe the functions of its flags.

Table 2.1 describes the five status register condition code flags – negative, zero, overflow, carry, and

break. Their values indicate various conditions that result from the execution of many 6502 instructions. Some instructions affect none of the condition code flags, others affect only some, and still others affect all. The effect that an instruction has on the condition flags is an important part of describing what the instruction does.

These condition code flags are used to determine the success or failure of the branch on condition instructions.

Notice particularly the zero flag (z). It can sometimes confuse assembly programmers because a zero flag setting of one indicates a zero result while a zero flag setting of zero indicates a non-zero result.

29

The Western Design Center

Name

negative zero

Abbrev

n z

Bit

7

1

Explicitly set or clear

-

-

Set or cleared to

Reflect an operation result

Reflects most significant bit results

(the sign of a two’s-complement binary number):

0= High bit clear (positive result)

1= high bit set (negative result)

Indicates zero or non-zero results:

0= non-zero result

1- zero result overflow v 6

Clear to reverse

“set-overflow” hardware input

Indicates invalid carry into high bit of arithmetic result (tow’s-complement overflow):

0= two’s-compliment result ok

1= error if two’s-complement arithmetic carry break c b

0

4

Clear before starting

addition

Set before starting

subtraction

Arithmetic overflow:

addition: carry out of high bit:

0= no carry

1= carry

subtraction: borrow required to subtract:

0= borrow required

1= no borrow required

Logic:

receives bit shifted or rotated out;

source of bit rotated in

Status register itself: no function; value unknown.

Pushed status register after interrupt:

indicates source of interrupt:

0= hardware interrupt

1= software interrupt (BRK) instruction)

Table 2-1 Status Register Condition Code Flags

In connection with the carry flag, it is important to know that the 6502 add operation has been designed to always add in the carry, and the subtract operation to always use the carry as a borrow flag, making it possible to do multiple-precision arithmetic where you add successively higher sets of bytes plus the previous adds carry or subtract successfully higher sets of bytes taking into the operation that previous subtract’s borrow.

The drawback to this scheme is that the carry must be zeroed before starting an add and set before starting a subtraction.

In the case of subtraction, the 6502’s carry flag is an inverted borrow, unlike that of most other microprocessors. If a borrow occurred during the last operation, it is cleared; if a borrow did not result, it is set.

Finally, notice that in the status register itself, the break bit has no function. Only when an interrupt pushes the statue register onto the stack is the break bit either cleared or set to indicate the type of interrupt responsible.

Table 2.2 describes the other two P register flags, the mode select flags: by explicitly setting or clearing them, you can change the operational modes of the processor.

30

The Western Design Center

Name

decimal

Abbrev Bit

d 3

Reason to explicitly set or clear

Determines mode for add & subtract (not increment/decrement, through):

Set to force decimal operations (BCD)

Clear to return to binary operation interrupt i 2 Enables or disables processor’s IRQ interrupt line:

Set to disable interrupts by masking the IRQ line

Clear to enable IRQ interrupts

Table 2-2 Status Register Mode Select Flags

The decimal mode flag toggles add and subtract operations (but not increment or decrement instructions) between binary and decimal (BCD). Most processors require a separate decimal-adjust operation after numbers represented in decimal format have been added or subtracted. The 65x processors do on-the-fly decimal adjustment when the decimal flag is set.

The IRQ disable or interrupt disable flag, toggles between enabling and diabling interrupts.

Typically, the interrupt mask is set during time-critical loops, during certain I/O operations, and while servicing another interrupt.

The Stack Pointer

The stack pointer (S) implements directly in hardware a data structure known as a stack or push-down

stack. The stack is a dedicated area of memory which is accessed by the user via push and pull instructions.

Push stores the contents of a register onto the stack; pull retrieves a data item from the stack, storing it into a register.

The 6502’s stack is limited to 256 bytes by the eight-bit width of its stack pointer. The chip confines it in memory between $100 and $1FF by fixing the high-order byte of the stack address at $01. Software powerup routines generally initialize the 6502 stack pointer to $FF, resulting in an initial stack location of $1FF (see

Figure 2.2).

The push and pull instructions are one-byte instructions: the instruction itself specifies the register affected and the value in the stack pointer register, added to $100, specifies the stack memory location to be accessed.

When a push instruction is executed, data is moved from the register specified by the instructions opcode to the stack address pointed to by the stack pointer. As Figure 2.3 shows, the value in the stack pointer is then decremented so that it points to the next memory location – the location to which the next push instruction encountered will store its data.

The pull instruction reverses the process and retrieves data from the stack. When a pull instruction is executed, first the stack pointer is incremented, the register specified in the instruction opcode is loaded with the data at the incremented address point to by SP.

31

The Western Design Center

Initializing the Stack Pointer to $FF:

Resulting Initial Stack of $1FF

Stack Pointer = $FF

0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1

$01FF

$01FE

$01FD

$01FC

$01FB

Stack

(1 st

available)

Figure 2-2 Initializing the Stack Pointer to $FF

In addition to being available as a temporary storage area, the stack is also used by the system itself in processing interrupts, subroutine calls, and returns. When a subroutine is called the current value of the program counter is pushed automatically onto the stack; the processor executes a return instruction by reloading the program counter with the value on the top of the stack.

While data is pushed into subsequently lower memory locations on the 65x stacks, the location of the last data pushed is nonetheless referred to an the top of the stack.

32

The Western Design Center

After Pushing the Accumulator

Stack Pointer = $FE

0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0

Stack

$01FE

$01FF A A A A A A A A

(next available)

$01FD

$01FC

$01FB

Accumulator

A A A A A A A A

Figure 2-3 After Pushing the Accumulator

The Program Counter

The program counter (PC) contains the address of the next byte in the instruction stream to fetch.

Execution of a program begins when the program counter is set to the program’s entry point (typically the address at which it is loaded). The processor fetches an instruction opcode from location, and proceeds to execute it. Based on the given opcode, the processor will need to fetch zero, one, or two bytes of operand from the successive locations following the instruction. When the operand has been fetched, the instruction is executed. The program counter is normally incremented to point to the next instruction in memory, except in the case of jump, branch, and call instructions, which pass control to a new location within the program by storing the new location to the program counter.

The 6502 program counter is sixteen bits wide, allowing for programs of up to 64K byte. If the program counter is still incremented past $FFFF, it wraps around to $0000.

Addressing Modes

The fourteen different addressing modes that may be used with the 6502 are shown in Table 2.3. The availability of this many different addressing modes on the 6502 gives it much of its power: Each one allows a given instruction to specify its effective address – the source of the data it will reference – in a different manner.

Not all addressing modes are available for all instructions; but each instruction provides a separate opcode for each of the addressing modes its supports.

33

The Western Design Center

Addressing Mode

Implied

Accumulator

Immediate

Absolute

Program Counter Relative

Stack

Zero Stack

Absolute Indexed with X

Absolute Indexed with Y

Zero Page Indexed with X

Zero Page Indexed with Y

Absolute Indirect

Zero Page Indirect Indexed with Y (Postindexed)

Zero Page Indexed Indirect with X (Preindexed)

LDA

LDA

LDA

LDA

LDX

JMP

LDA

LDA

Syntax Example

Opcode Operand

DEX

ASL

LDA

LDA

BEQ

PHA

A

#55

$2000

LABEL12

$81

$2000,X

$2000,Y

$55,X

$55,Y

($1020)

($55),Y

($55,X)

Table 2-3 6502 Addressing Modes

For some of the 6502 addressing modes, the entire effective address is provided in the operand field of the instruction; for many of them, however, formation of the effective address involves an address calculation, that is, the addition of two or more values. The addressing mode indicates where these values are to come from and how they are to be added together to form the effective address.

Implied addressing instructions, such as DEY and INX, need no operands. The register that is the source of the data is named in the instruction mnemonic and is specified to the processor by the opcode.

Accumulator addressing, in which data to be referenced is in the accumulator, is specified to the assembler by the operand A. Immediate addressing, used to access data which is constant throughout the execution of a program, causes the assembler to store the data right into the instruction stream. Relative addressing provides the means for conditional branch instructions to require only two bytes, one byte less than jump instructions take. The one-byte operand following the branch instruction is an offset from the current contents of the program counter. Stack addressing encompasses all instructions, such as push or pull instructions, which use the stack pointer register to access memory. And absolute addressing allows data in memory to be accessed by means of its address.

Like the 6800 processor, the 6502 treats the zero page of memory specially. A page of memory is an address range $100 bytes (256 decimal) long: the high bytes of the addresses in a given page are all the same, while the low bytes run from $00 through $FF. The zero page is the first page of memory, from $0000 through

$00FF (the high byte of each address in the zero page is zero). Zero page addressing, a short form of absolute addressing, allows zero page operands to be referenced by just one byte, the lower-order byte, resulting both in fewer code bytes and in fewer clock cycles.

While most other processors provide for some form of indexing, the 6502 provides some of the broadest indexing possibilities. Indexed effective addresses are formed from the addition of a specified base address and index, as shown in Figure 2.4. Because the 6502’s index registers (X and Y) can hold only eight bits, they are seldom used to hold index bases; rather, they are almost always used to hold the indexes themselves. The 6502’s four simplest indexing modes add the contents of the X or Y register to an absolute or zero page base.

Indirection (Figure 2.5) is less commonly found in microprocessor repertoires, particularly among those microprocessors of the same design generation as the 6502. It lets the operand specify an address at which another address, the indirect address, can be found. It is at this second address that data will be referenced. The 6502 not only provides indirection for its jump instruction, allowing jumps to be vectored and revectored, but it also combines indirection with indexing to give it real power in accessing data. It’s as though the storage cells for the indirect addresses are additional 6502 registers, massively extending the 6502’s register set and possibilities. In one addressing mode, indexing is performed before indirection; in another, after. The first provides indexing into an array of indirect addresses and the second provides indexing into array which is located by the indirect address.

The full set of 65x addressing modes are explained in detail in Chapters 7 and 11 and are reviewed in the Reference Section

34

The Western Design Center

.

For example

Indexing: Base plus Index

Base = $2000

Index Register X = $ 03

Effective Address = $2003

Base = $2000

0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0

$2003

$2000

$2001

$2002

$2004

X = $03

0 0 0 0 0 0 1 1

Figure 2-4 Indexing: Base Plus Index

Instructions

The 6502 has 56 operation mnemonics, as listed in Table 2.4, which combine with its many addressing modes to make 151 instructions available to 6502 programmers.

Arithmetic instructions are available, including comparisons, increment, and decrement. But missing are addition or subtraction instructions which do not involve the carry; as a result, you must clear the carry before beginning an add and set it before beginning subtraction.

35

The Western Design Center

Indirection: Operand Locates Indirect Address

For Example: Zero Page Operand = $20

Data at $20.21 (Indirect Address) = $3458

Effective Address = $3458

Zero Page

Operand = $20

0 0 1 0 0 0 0 0

$0020

$0021

Memory

$001F

0 1 0 1 1 0

0 0 1 1 0 1

0

0

0

$58

0

$34

$0022

$0023

$3456

$3457

$3458

$3459

$345A

Figure 2-5 Indirection: Operand Locates Indirect Address

$3458

36

The Western Design Center

PLP

ROL

ROR

RTI

RTS

SBC

SEC

LDX

LDY

LSR

NOP

ORA

PHA

PHP

PLA

SED

SEI

STA

STX

STY

TAX

TAY

TSX

TXA

TXS

TYA

DEX

DEY

EOR

INC

INX

INY

JMP

JSR

LDA

CLD

CLI

CLV

CMP

CPX

CPY

DEC

BEQ

BIT

BNE

BPL

BRK

BVC

BVS

CLC

Instruction

Mnemonic

ADC

AND

ASL

BCC

BCS

Description

Add memory and carry to accumulator

And accumulator with memory

Shift memory or accumulator left one bit

Branch if carry clear

Branch if carry set

Branch if equal

Test memory bits against accumulator

Branch if negative

Branch if not equal

Branch if plus Software break (interrupt)

Branch if overflow clear

Branch if overflow set

Clear carry flag

Clear decimal mode flag

Clear interrupt-disable flag

Clear overflow flag

Compare accumulator with memory

Compare index register X with memory

Compare index register Y with memory

Decrement

Decrement index register X

Decrement index register Y

Exclusive-OR accumulator with memory

Increment

Increment index register X

Increment index register Y

Jump

Jump to subroutine

Load accumulator from memory

Load index register X from memory

Load index register Y from memory

Logical shift memory or accumulator right

No operation

OR accumulator with memory

Push accumulator onto stack

Push status flags onto stack

Pull accumulator from stack

Pull status flags from stack

Rotate memory or accumulator left one bit

Rotate memory or accumulator fight one bit

Return from interrupt

Return from subroutine

Subtract memory with borrow from accumulator

Set carry flag

Set decimal mode flag

Set interrupt-disable flag

Store accumulator to memory

Store index register X to memory

Store index register Y to memory

Transfer accumulator to index register X

Transfer accumulator to index register Y

Transfer stacker point to index register X

Transfer index register X to accumulator

Transfer index register X to stack pointer

Transfer index register Y to accumulator

Table 2-4 6502 Instructions

37

The Western Design Center

Logic instructions available include shifts and rotates, as well as an instruction for bit comparing.

Branch instructions are entirely flag-based, not arithmetic-operation based, so there are no single branch-on-greater-than, branch-on-less-than-or-equal, or signed arithmetic branches. There is also no unconditional branch and no branch-to-subroutine. The unconditional branch can be imitated by first executing one of the 6502’s many clear- or set- flag instructions, then executing a branch-on-the-flag’s-condition instruction.

All three of the main user registers can be loaded from and stored to memory, but only the accumulator

(not the index register) can be pushed onto and pulled from the stack (although the flags can also be pushed and pulled). On the other hand, single instructions let the accumulator value be transferred to either index register or loaded from either index register. One more transfer instruction is provided for setting the value of the stack pointer to the value in the X index register.

The 6502 System Design

There are a number of other features of the 6502’s design which make it unique and make systems designed with it stand apart from systems designed with other microprocessors.

Pipelining

The 65x microprocessors have the capability of doing two things at once: the 6502 can be carrying on an internal activity (like an arithmetic or logical operation) even as it’s getting the next instruction byte from the instruction stream or accessing data in memory.

A processor is driven by a clock signal which synchronizes events within the processor with memory accesses. A cycle is a basic unit of time within which a single step of an operation can be performed. The speed with which an instruction can be executed is expressed in the number of cycles required to complete it.

The actual speed of execution is a function both of the number of cycles required for completion and the number of timing signals provided by the clock every second. Typical clock values for 65x processors start at one million cycles per second and go up from there.

As a result of the 6502’s capability of performing two different but overlapping phases of a task within a single cycle, which is called pipelining, the 65x processors are much faster than non- pipelined processors.

Take the addition of a constant to the 6502’s eight-bit accumulator as an example.This requires five distinct steps:

Step 1: Fetch the instruction opcode ADC.

Step 2: Interpret the opcode to be ADC of a constant.

Step 3: Fetch the operand, the constant to be added.

Step 4: Add the constant to the accumulator contents.

Step 5: Store the result back to the accumulator.

Pipelining allows the 6502 to execute steps two and three in a single cycle: after getting an opcode, it increments the program counter, puts the new program address onto the address bus, and gets the next program byte, while simultaneously interpreting the opcode. The completion of steps four and five overlaps the next instruction’s step one, eliminating the need for two additional cycles.

So the 6502’s pipelining reduces the operation of adding a constant from five cycles to two!

The clock speed of a microprocessor has often been incorrectly presumed to be the sole determinant of its speed. What is most significant, however, is the memory cycle time. The 68000, for example, which typically operates at 6 to 12 megahertz (MHz, or millions of cycles per second) requires four clock periods to read or write data to and from memory. The 65x processors require only one clock period. Because the 6502 requires fewer machine cycles to perform the same functions, a one-megahertz 6502 has a

throughput unmatched by the 8080 and Z80 processors until their clock rates are up to about four MHz.

The true measure of the relative speeds of various microprocessors can only be made by comparing how long each takes, in its own machine code, to complete the same operation.

38

The Western Design Center

Memory Order of Multiple-Byte Values

Multiple-byte values could be stored in memory in one of two ways: low-order byte first, followed by successively high order bytes; or high-order bytes first, followed by successively lower order bytes. The 6502, like the Intel and Zilog chip (the 8080, Z80, 8086, and so on), but unlike the Motorola chips (the 6800, 6809,

68000, and so on), puts the low-order byte first, into the lower memory address.

This seemingly unnatural order of the placement of multiple-byte values in memory as a $30 followed by $FE is not $30FE but rather $FE30. Multiple-byte values are written high-order first, to read from left to right; this is the opposite of how the bytes are placed in memory. This memory order, however, contributes to the success and speed of pipelining. Consider, as an example, the loading of the accumulator using absolute indexed addressing (two lines for a cycle indicate simultaneous operations due to pipelining):

Cycle 1:Fetch the instruction opcode, LDA.

Cycle 2:Fetch the operand byte, the low byte of an array base.

Interpret the opcode to be LDA absolute indexed.

Cycle 3:Fetch the second operand byte, the high array base byte.

Add the contents of the index register to the low byte.

Cycle 4:Add the carry from the low address add to the high byte.

Cycle 5:Fetch the byte at the new effective memory address

.

(

NOTE: The 6502 also does a fetch during Cycle 4, before it checks to see if there was any carry; if there is no carry into the high byte of the address, as is often true, then the address fetched from was correct and there is no cycle five; the operation is a four-cycle operation in this case. Absolute indexed writes, however, always require five cycles.)

The low-high memory order means that the first operand byte, which the 6502 fetches before it even knows that the opcode is LDA and the addressing mode is absolute indexed, is the low byte of the address base, the byte which must be added to the index register value first; it can do that add while getting the high-byte.

Consider how high-low memory order would weaken the benefits of pipelining and slow the process down:

Cycle 1:Fetch the instruction opcode, LDA.

Cycle 2:Fetch an operand byte, the high byte of an array base.

Interpret the opcode to be LDA absolute indexed.

Cycle 3:Fetch the second operand byte, the low array base byte.

Store the high byte temporarily.

Cycle 4:Add the contents of the index register to the low byte.

Cycle 5:Add the carry from the low address add to the high byte.

Cycle 6:Fetch the byte at the new effective memory address.

Memory-Mapped Input/Output

The 65x family (like Motorola’s but unlike Zilog’s and Intel’s) accomplishes input and output not with special opcodes, but by assigning each input/output device a memory location, and by reading from or writing to that location. As a result, there’s virtually no limit to the number of I/O devices which may be connected to a

65x system. The disadvantage of this method is that memory in a system is reduced by the number of locations which are set for I/O functions.

Interrupts

Interrupts tell the processor to stop what it is doing and to take care of some more pressing matter instead, before returning to where it left off in regular program code. An interrupt is much like a doorbell: having one means you don’t have to keep going to the door every few minutes to see if someone is there; you can wait for it to ring instead.

An external device like a keyboard, for example, might cause an interrupt to present input. Or a clock might generate interrupts to toggle the processor back and forth between two or more routines, letting it do several tasks “at once.” A special kind of interrupt is reset (the panic button), which is generally used out of

39

The Western Design Center

frustration to force the processor into re-initialization. Reset generally does not return to the interrupted code after it has been served, however.

The 6502 has three interrupt vectors – memory addresses that hold the locations of routines which are automatically executed upon recognition of an interrupt by the processor. The first of these is used for reset.

The second vector is used both by maskable interrupts – those which you can force the processor to ignore, either temporarily or permanently, by setting the i interrupt bit in the status register - and by software

interrupts - which are caused by the execution of the break instruction (BRK). If any hardware can cause a maskable interrupt, the interrupt service routine pointed to by this vector must still determine the source of the interrupt. It must poll a status flag on each possible hardware source as well as check the stacked register’s b flag, which is set and pushed when a break instruction is executed. When it finds the source of the interrupt, it must then branch to a routine which will respond to the interrupt in a way appropriate to the source (getting a character from a communications port, for example).

The third vector is used by nonmaskable interrupts, those which interrupt regardless of the i bit in the status register. The non-maskable interrupt is usually reserved for a single high-priority or time-critical interrupt, such as refresh of a CRT screen or to warn of impending power failure.

The 6502 was designed to service interrupts as fast as possible. Because interrupts cannot be served until the current instruction is completed (so no data is lost), the worst case is the longest instruction time and the 6502’s instructions each take very few cycles to execute. As a result, the 6502 and its successors have the lowest interrupt latency – the time between interrupt occurrence and interrupt-handling response – of any eightbit or sixteen-bit processors.

NMOS Process

The 6502 is fabricated using the NMOS (pronounced “EN moss”) process (for N-channel Metal-Oxide

Semiconductor). Still one of the most common of the technologies used in large-scale and very-large-scale integrated circuits, NMOS was, at the time the 6502 was designed and for many years after, the most costefficient of the MOS technologies and the easiest process for implementation of relatively high-speed parts.

This made NMOS popular among designers of microcomputers and other devices in which hardware was an important design factor

.

Most of the current generation of 8-, 16-, and 32-bit processors were originally implemented in NMOS.

Some, like the 6502, are still only available in NMOS process versions. Others, like all of the recently designed members of the 65x family (65C02, 65802, and 65816) were produced exclusively using the CMOS process.

Bugs and Quirks

The 6502 has a number of features which the less enthusiastic might be inclined to call bugs or quirks.

The one most clearly a bug involves using indirect addressing with the jump instruction, when its operand ends in $FF. To use an example,

JMP ($20FF) should cause the program counter to get, as its new low byte, the contents of $20FF, and as its new high byte, the contents of $2100. However, while the 6502 increments the low byte of the indirect address from $FF to 00, it fails to add the carry into the high byte, and as a result gets the program counter’s new high byte from $2000 rather than $2100.

You can also run into trouble trying to execute an unused opcode, of which the 6502 has many. The results are unpredictable, but can include causing the processor to “hang”.

Finally, the decimal mode is not as easy to use as it might be. The negative, overflow, and zero flags in the status register are not valid in decimal mode and the setting of the decimal flag, which toggles the processor between binary and decimal math, is unknown after the processor has received a hardware “reset”.

40

The Western Design Center

3) Chapter Three

Architecture of the 65C02

The 65C02 microprocessor is an enhanced version of the 6502, implemented using a silicon-gate

CMOS process. The 65C02 was designed primarily as a CMOS replacement for the 6502. As a result, the significant differences between the two products are few. While the 65C02 adds 27 new opcodes and two new addressing modes (in addition to implementing the original 151 opcodes of the 6502), its register set, memory model, and types of operations remain the same.

The 65C02 is used in the AppleIIc and, since early 1985, in the AppleIIe, ands it has been provided as an enhancement kit for earlier IIe’s.

Remember that even as the 65C02 is a superset of the 6502, the 65802 and 65816, described in the next chapter, are supersets of the 65C02. All of the enhancements found in the 65C02 are additionally significant in that they are intermediate to the full 65816 architecture. The next chapter will continue to borrow from the material covered in the previous ones, and generally what is covered in the earlier of these three architecture chapters is not repeated in the subsequent ones, since it is true for all 65x processors.

The 65C02 Architecture

Both the 65C02 and the 6502 are eight-bit processors, with a 64K address space and exactly the same register set.

The 65C02 features some small but highly desirable improvements in the use of the status register flags: it gives valid negative, overflow, and zero flags while in decimal mode, unlike the 6502; and it resets the decimal flag to zero after reset and interrupt.

The 65C02 has slightly different cycle counts on a number of operations from the 6502, some shorter and a few longer. The longer cycle counts are generally necessary to correct or improve operations from the

6502

.

Addressing Modes

The 65C02 introduces the two new addressing modes shown in table 3.1, as well as supporting all the

6502 addressing modes. All of them will be explained in detail in Chapters 7 and 11, and will be reviewed in the Reference Section.

Addressing Mode

Zero Page Indirect

Absolute Indexed Indirect

Syntax Example

Opcode

LDA

JMP

Operand

($55)

($2000,X)

Table 3-1 The 65C02’s New Addressing Modes

.

Zero page indirect provides an indirect addressing mode for accessing data which requires no indexing

(the 6502’s absolute indirect mode is available only to the jump instructions). 6502 programmers commonly simulate indirection by loading an index register with zero (losing its contents and taking extra steps), then using the preindexed or postindexed addressing modes to indirectly reference the data.

On the other hand, combining indexing and indirection proved so powerful for accessing data on the

6502 that programmers wanted to see this combination made available for tables of jump vectors. Absolute

indexed indirect, available for jump instruction only, provides this multi-directional branching capability, which can be very useful for case or switch statements common to many languages.

41

The Western Design Center

Instructions

While the 65C02 provides 27 new opcodes, there are only eight new operations. The 27 opcodes result from providing four different addressing modes for one on the new mnemonics and two for two others, and also from expanding the addressing modes for twelve 6502 instructions. The most significant expansion of a 6502 instruction by combining it with a 6502 addressing mode it did not previously use is probably the addition of accumulator addressing for the increment and decrement instructions.

The new 65C02 operations, shown in Table 3.2, answer many programmer’s prayers: an unconditional branch instruction, instructions to push and pull the index registers, and instructions to zero out memory cells.

These may be small enhancements, but they make programming the 65C02 easier, more straightforward, and clearer to document. Two more operations allow the 65C02 to set or clear any or all of the bits in a memory cell with a single instruction.

Instruction

Mnemonic

BRA

PHX

PHY

PLX

PLY

STZ

TRB

TSB

Description

Branch always (unconditional)

Push index register X onto stack

Push index register Y onto stack

Pull index register X form stack

Pull index register Y from stack

Store zero to memory

Test and reset memory bits against accumulator

Test and set memory bits against accumulator

Table 3-2. New 65C02 Instructions

CMOS Process

Unlike the 6502, which is fabricated in NMOS, the 65C02 is a CMOS (pronounced “SEE moss”) part. CMOS stands for Complementary Metal-Oxide Semiconductor.

The most exciting feature of CMOS is its low power consumption, which has made portable, battery-operated computers possible. Its low power needs also result in lower heat generation, which means parts can be placed closer together and heat-dissipating air space minimized in CMOS-based computer designs.

CMOS technology is not a new process. It’s been around for about as long as other MOS technologies. But higher manufacturing costs during the early days of the technology made CMOS impractical for the highly competitive microcomputer market until the mid 1980s, so process development efforts were concentrated on NMOS and not applied to CMOS until 1980 or 1981.

CMOS technology has reached a new threshold in that most of its negative qualities, such as the difficulty with which smaller geometries are achieved relative to the NMOS process, have been overcome.

Price has become competitive with the more established NMOS as well.

Bugs and Quirks

The 65C02 fixes all of the known bugs and quirks in the 6502. The result of executing unused opcodes is now predictable-they do nothing (that is, they act like no-operation instructions). An interesting footnote is that, depending on the unimplemented instruction that is executed, the number of cycles consumed by the nooperation is variable between one and eight cycles. Also, the number of bytes the program counter is incremented by is variable. It is strongly recommended that this feature not be exploited, as its use will produce code incompatible with the next-generation 65802 and 65816.

The jump indirect instruction has been fixed to work correctly when its operand crosses a page boundary (although at the cost of an execution cycle). The negative overflow, and zero flags have been implemented to work in decimal mode (also at the cost of an execution cycle). The decimal mode is now reset to binary after a hardware reset or an interrupt.

42

The Western Design Center

Finally, a fix which is generally transparent to the programmer, but which eliminates a possible cause of interference with memory-mapped I/O devices on the 6502, is the elimination of an invalid address read while generating an indexed effective address when a page boundary is crossed.

The quirk unique to the 65C02 results from trying to eliminate the quirks of the 6502. The timing improvements of a number of instructions and the bug fixes from the 6502 make the 65c02 an improvement over the 6502, but not quite fully compatible on a cycle-by-cycle basis. This is only a consideration during the execution of time-critical code, such as software timing loops. As a practical example, this has affected very little software being ported from the Apple IIe to the IIc.

43

The Western Design Center

4) Chapter Four

Sixteen-Bit Architecture The 65816 and the 65802

While the 65C02 was designed more as a CMOS replacement for the 6502 than an enhancement of it, the 65802 and 65816 were created to move the earlier designs into the world of sixteen-bit processing.

Although the eight-bit 6502 had been a speed demon when first released, it’s competition changed over the years as processing sixteen bits at a time became common, and as the memory new processors could address started at a megabyte.

The 65816 and the 65802 were designed to bring the 65x family into line with the current generation of advanced processors. First produced in prototypes in the second half of 1984, they were released simultaneously early in 1985. The 65816 is a full-featured realization of the 65x concept as a sixteen-bit machine. The 65802 is its little brother, with the 65816’s sixteen-bit processing packaged with the 6502’s pinout for compatibility with existing hardware.

The two processors are quite similar. They are, in fact, two different versions of the same basic design.

In the early stages of the chip fabrication process they are identical and only assume their distinct

“personalities” during the final (metalization) phase of manufacture.

The two processors provide a wealth of enhancements: another nine addressing modes, 78 new opcodes, a “hidden” second accumulator in eight-bit mode, and zero page which, renamed the direct page, can be relocated to any contiguous set of $100 bytes anywhere within the first 64K of memory (which in the case of the 65802 is anywhere in its address space). The most dramatic of all the enhancements common to both 65802 and 65816, though, is the expansion of the primary user registers – the accumulator, index register, and stack pointer – to sixteen-bit word size. The accumulator and index registers can be toggled to sixteen bits from eight, and back to eight when needed. The stack, pointed to by an expanded-to-sixteen-bit stack register, can be relocated from page one to anywhere in a 64K range.

The primary distinction between the two processors is the range of addressable memory: the 65816 can address up to sixteen megabytes; the 65802 is constrained by its 6502 pinout to 64K.

A secondary distinction between the two processors is that the 65816’s new pinout also provides several significant new signals for the hardware designer. While outside the primary scope of this book, these new signals are mentioned in part in this chapter and described in some detail in Appendix C.

It is important to remember that the 65802 is in fact a 65816 that has been coerced to live in the environment designed originally for the 6502 and 65C02. Outside of the memory and signal distinctions just listed, the 65816 and the 65802 are identical. Both have a native mode, in which their registers can be used for either eight- or sixteen-bit operations. Both have a 6502 emulation mode, in which the 6502’s register set and instruction timings emulate the eight-bit 6502 (not the 65C02) exactly (except they correct a few 6502 bugs).

All existing 6502 software can be run by the new processor – as can virtually all 65C02 software – even as most of the native mode’s enhancements (other than sixteen-bit register) are programmable in emulation mode, too.

To access sixteen megabytes, the signals assigned to the various pins of the 65816’s 40-pin package are different from the 6502, and the 65C02 and the 65802, so it cannot be installed in existing 65x computers as a replacement upgrade. The 65802, on the other hand, has a pinout that is identical to that of the 6502 and 65C02 and can indeed be used as a replacement upgrade.

This makes the 65802 a unique, pin-compatible, software-compatible sixteen-bit upgrade chip. You can pull a 6502 out of its socket in any existing 6502 system, and replace it with a 65802 because it powers-on in the 6502 emulation mode. It will run existing applications exactly the same as the 6502 did. Yet new software can be written, and 6502 programs rewritten, to take advantage of the 65802’s sixteen-bit capabilities, resulting in programs which take up much less code space and which run faster. Unfortunately, even with a

65802 installed, an older system will remain unable to address memory beyond the original 64K limits of the

6502. This is the price of hardware compatibility.

The information presented in this chapter builds directly on the information in the previous two chapters; it should be considered as a continuous treatment of a single theme. Even in native mode with sixteen-bit registers, the 65802 and 65816 processors utilize many of the 6502 and 65C02 instructions, registers, and addressing modes in a manner which differs little from their use on the earlier processors. If you are

44

The Western Design Center

already familiar with the 6502 or the 65C02, you will discover that the 65802 and 65816 logically expand on these earlier designs

.

Power-On Status: 6502 Emulation Mode

When the 65816 and 65802 are powered on, they initialize themselves into 6502 emulation mode in which, with the exception of fixing several 6502 bugs, they exactly emulate the 6502. The stack is confined to page one, just like the 6502 stack pointer. The registers are configured to eight bits, to model the 6502’s registers. Every 6502 instruction is implemented identically. The timing of each instruction is exactly the same as on the original NMOS 6502. The direct page of the 65802 and 65816, which as you will learn can be relocated using the sixteen-bit direct page register, is initialized to page zero, making direct page addressing exactly equivalent to the 6502 zero page addressing. The program and data bank registers, which as you will learn provide efficient access in the 65816 to any one or two 64K banks of memory at a time, are initialized to the zero bank.

Unlike the NMOS 6502, which has undefined results when unimplemented opcodes are executed, and the 65C02, which treats unimplemented opcodes as variously-timed and –sized no-operations, the 65802 instruction set implements every one of the 256 possible one-byte opcodes. These additional instructions are available in emulation mode as well as in native mode.

Among the newly implemented opcodes are ones that allow the processors to be switched to their native mode – sixteen-bit operation. While there is more to say about 6502 emulation mode, it will be easier to understand in then context of native mode.

The Full-Featured 65x Processor: The 65816 in Native Mode

The 65816 in its native mode (as opposed to its 6502 emulation mode) has it all: sixteen-bit registers,

24-bit addressing, and all the rest. The 65802’s native mode is a subset of this, as are the emulation modes of both processors

.

45

The Western Design Center

23

65816 Native Mode Programming Model

(16-bit accumulator & index register modes: m=0 & x=0)

15 7

Accumulator (B) (A) or (C) Accumulator (A)

0

Data Bank Register (DBR)

0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0

Program Bank Register (PBR)

X Index Register (X)

Y Index Register (Y)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC)

Processor Status Register (P)

7 n v m x d i z

0 e c

Emulation 0 = Native Mode

Carry 1 = Carry

Zero 1 = Result Zero

IRQ Disable 1 = Disabled

Decimal Mode 1 = Decimal, 0 = Binary

Index Register Select 1 = 8-bit, 0 = 16-bit

Memory/Accumulator Select 1 = 8-bit, 0 = 16-bit

Overflow 1 = Overflow

Negative 1 = Negative

Figure 4-1 65816 Native Mode Programming Model

Figure 4.1 shows the programming model for the 65816 in native mode. While the accumulator is shown as a sixteen-bit register, it may be set to be either a single sixteen-bit accumulator (A or C) or two eightbit accumulators, one accessible (A) and the other hidden but exchangeable (B). While the index registers are shown as sixteen-bit registers, they may be set, as a pair, to be either sixteen-bit registers or eight-bit registers – their high bytes are zeroed when they are set to eight-bits. The obvious advantage of switching from a processor with eight-bit registers to one with sixteen-bit registers is the ability to write programs which are from

25 to 50 percent shorter, and which run 25 to 50 percent faster due to the ease with which sixteen-bit data is manipulated.

The feature that most clearly distinguishes the current generation of advanced microcomputer systems, however, is the ability to address lots of memory. It is this increased memory addressability which has ushered in the new era of microcomputer applications possibilities, such as large spreadsheets, integrated software, multi-user systems, and more. In this regard, the 65816 stands on or above par with any of the other highperformance microprocessors, such as the 68000, the 8086, or their successors.

There are two new eight-bit registers called bank registers. One, called the data bank register, is shown placed above the index registers and the other, called the program bank register, is appended to the program counter. The 65816 uses the two bank registers to provide 24-bit addressing.

A bank of memory is much like a page; just as a page is a range of memory that can be defined by eight bits (256 bytes), a bank is a range of memory that can be defined by sixteen bits (64K bytes). For processors like the 6502, which have only sixteen-bit addressing, a 64K bank is not a relevant concept, since the only bank is the one being currently addressed. The 65816, on the other hand, partitions its memory range into

64K banks so that sixteen-bit registers and addressing modes can be used to address the entire range of memory.

46

The Western Design Center

Bank zero, for example, is that 64K range for which, when addressed using 24 bits, the highest byte

(also called the bank byte) is zero. Similarly, a highest byte of nine in a 24-bit address would address a location somewhere in bank nine. This highest byte is called the bank byte so that the high byte can still be used to refer to the byte that determines the page address. In other words, “high byte” is used on the 65816 as it is on the 6502, 65C02, and 65802, where addresses are only sixteen bits.

Another new register shown in Figure 4.1 is the direct page register. Much like the 6800’s special zero page became the 6809’s direct page, the 6502’s and 65C02’s zero page has been transformed into the

65802’s and 65816’s direct page. This direct page is, as Figure 4.1 shows, limited to bank zero, shown in the programming model by the implied zero as its bank byte. The direct page register can be set to any 256-byte page starting on any byte boundary within bank zero. All of the 6502 instructions that use zero page addressing use an expanded form called direct page addressing on the 65816 and 65802; however, when the direct page register value is zero, the two modes are operationally identical.

Figure 4.1 also shows that the stack pointer has been unbound from page one to float anywhere in bank zero by making it a sixteen-bit register.

While figure 4.1 doesn’t show the interrupt vectors, they too are located in bank zero, and they point to interrupt handling routines which also must be located in bank zero.

Finally, the status register is different from the 6502’s and 65C02’s (compare Figure 4.1 with Figure 2.1

in chapter 2). The first obvious difference is the single bit labeled e for emulation hanging off the top of the carry flag. Accessible only through the carry flag, its contents determine whether the processor is in native or

6502 emulation mode. Here it holds a zero to indicate the processor is in native mode. The second difference is the m and x flags replace the 6502’s break and unused flags: m indicates the size of the accumulator (eight or sixteen bits) as well as the size and memory accesses; x indicates the size of the two index registers (eight or sixteen bits). Changing the contents of either of these two new flags toggles the size of the corresponding registers. The b flag is no longer necessary to distinguish the BRK software interrupt from hardware interrupts because native mode provides a new interrupt vector for software interrupts, separate from the hardware interrupt vector.

Native mode also provides one timing improvement over the 6502: one cycle is saved during a crosspage branch.

The Program Bank Register

The 65816’s sixteen-bit program counter is concatenated to its eight-bit program counter bank register

(PBR, or K when used in instruction mnemonics) to extend its instruction-addressing capability to 24 bits.

When the 65816 gets an instruction from memory, it gets it from the location pointed to by the concatenation of the two registers. In many ways, the net effect is a 24-bit program counter; for example, when an interrupt occurs, all 24 bits (program counter plus program counter bank) are pushed onto the stack. Likewise, when a return-from-interrupt occurs, 24 bits (both registers) are pulled from the stack.

All previous instructions that jumped to sixteen-bit absolute addresses still work by staying within the same bank. Relative branches stay in the same bank; that is, you can’t branch across bank boundaries. Program segments cannot cross bank boundaries; if the program counter increments past $FFFF, it rolls over to $0000

without incrementing the program counter bank.

New instructions and addressing modes were added to let you transfer control between banks: jump absolute long (jump to a specified 24-bit address), jump indirect long (the operand is an absolute address in bank zero pointing to a 24-bit address to which control is transferred), jump to subroutine long (to a specified

24-bit address, with the current program counter and program bank register pushed onto the stack first), and a corresponding return from subroutine long, which re-loads the bank register as well as the program counter.

(The addressing modes are among those listed in Table 4.3, the instructions in Table 4.4.)

These instructions that specify a complete 24-bit address to go to, along with native mode’s software interrupt and return from interrupt instructions, are the only ones that modify the value in the program bank register. The program bank can be pushed onto the stack so it can be pulled into another register and be examined or tested. But there is no instruction for pulling the program bank register from the stack, since that would change the bank the next instruction would come from – certain to be catastrophic. To avoid such

“strange” branches across banks, the program counter bank register can only be changed when the program counter is changed at the same time.

47

The Western Design Center

The Data Bank Register

The data bank register (DBR or, when used as part of a mnemonic, B) defines the default bank to be used for reading or writing data whenever one of the addressing modes that specifies (only) a sixteen-bit address is used, such as the absolute, indirect, or indexed instructions found on the 6502. Such sixteen-bit effective addresses as used with the 6502 are concatenated with the value in the data bank register to form a 24-bit address, much as the program counter is concatenated with the program bank register. An important difference is that, unlike the program counter bank register, the data bank register can be temporarily incremented by instructions which use indexed addressing; in other words, bank boundaries do not confine indexing, which crosses them into the next bank.

As already mentioned, direct page and stack-based values are always accessed in bank zero, since the implied bank used with the direct page and stack is zero. But indirect addresses pulled out of the direct page or off stack (when used with addressing modes that do not further specify the bank value) point to locations in the current data bank.

The existence of the data bank register on the 65816 provides a convenient way to access a large range of data memory without having to resort to 24-bit address operands for every operation.

The Direct Page Register

The direct page register (D) points to the beginning of direct page memory, which replaces zero page memory as the special page used for short-operand addressing. All of the 6502 instructions that use zero page addressing use and expanded form called direct page addressing on the 65816 and 65802. If the direct page register is set to zero, the direct page memory is the zero page, and direct page addressing is operationally identical to zero page addressing

.

One effect of having a direct page register is that you can set up and alternate between multiple direct page areas, giving each subroutine or task its own private direct page of memory, which can prove both useful and efficient.

The Stack Pointer

The native mode stack pointer holds a sixteen-bit address value. This means it can be set to point to any location in bank zero. It also means the stack is no longer limited in length to just $100 bytes, nor limited to page one ($100 to $1FF). Page one therefore loses its character as a “special” memory area and may be treated like any other page while running the 65802 or 65816 in the native mode.

Accumulator and Index Registers

The key difference between the 65816/65802 and the earlier processors in the series is that the 65816’s three primary user registers – the accumulator and the X and Y index registers – can be toggled between eight and sixteen bits. You can select which size (eight or sixteen bits) you wish to use by executing special control instructions that modify the new m and x flags.

This enhances the basic processing power of the chip tremendously. A simple subtraction of sixteen-bit numbers, for example, illustrates the difference. The eight-bit 6502 must be programmed to load the low byte of the first sixteen-bit number, subtract the low byte of the second number, then save the result, load the first number’s high byte, subtract the second number’s, and finally, save the high result. The sixteen-bit processors, on the other hand, can load one sixteen-bit value, subtract the other then save the sixteen-bit result. Three steps replace six.

With its ability to change register size, the 65816 functions equally well with eight bits or sixteen.

From the programmer’s point of view, it is a dual word size machine. The machine word size – the basic unit of data the machine processes in a given instruction cycle – may be either byte or double byte, that is eight or sixteen.

In the terminology used in describing other sixteen-bit processors, the term word is used specifically to refer to sixteen-bit data, and byte to refer to eight-bit data. But other sixteen-bit processors generally have

48

The Western Design Center

different mechanisms for selecting byte or double byte data to operate upon. The terminology appropriate to the

65802 and 65816 is to refer to sixteen-bit data as double byte, rather than word, since their word size alternates between eight bits and sixteen, and since they can operate in either byte mode or double byte mode with equal effectiveness. They are hybrid processors.

The width of the accumulator and the width of the index registers are independently controlled by setting and resetting the two special flag bits within the status register, the index register select (x) and

memory/accumulator select (m) flags. When both are set, the eight-bit register architecture of the 6502 is in force. While very similar to the emulation mode, this eight-bit native mode is subtly different in important ways: a BRK vector is available in the native mode; interrupt processing is different between emulation and native mode in general; and of course sixteen-bit processing can be called up with a single instruction. Yet the

65802 and 65816 will execute a good deal of existing 6502 programs without modification in this mode.

When either or both the index register select or memory select flags are cleared, the word size of the corresponding register(s) is expanded from eight bits to sixteen.

The four possible modes of operation are shown in Table 4.1.

eight-bit accumulator eight-bit index registers

(m bit is set)

(x bit is set) eight-bit accumulator sixteen-bit index registers

(m bit is set)

(x bit is clear) sixteen-bit accumulator eight-bit index registers sixteen-bit accumulator sixteen-bit index registers

(m bit is clear)

(x bit is set)

(m bit is clear)

(x bit is clear)

Table 4-1 The Four Possible Native Mode Register Combinations

When the opcode for a given instruction is fetched from memory during program execution, the processor may respond differently based upon the setting of the register select flags. Their settings may be thought of as extensions to the opcode. For example, consider the following instruction: object code instruction

BD

00

B

0

LDA $B

000

X which loads the accumulator with data from the effective address formed by the sum of $B000 and the contents of the X register. The X register contents can be either eight bits or sixteen, depending upon the value of the index select flag. Furthermore, the accumulator will be loaded from the effective address with either eight or sixteen bits of data, depending upon the value of the memory/accumulator select flag.

The instruction and addressing mode used in the example are found also on the 6502 and 65C02; the opcode byte

($BD) is identical on all four processors. The 65816’s new mode flags greatly expand the scope of the 6502’s instructions.

For programmers already familiar with the 6502, the understanding of this basic principle – how one opcode can have up to four different effects based on the flag settings – is the single most important principle to grasp in moving to a quick mastery of the 65802 or 65816.

49

The Western Design Center

Switching Registers Between Eight and Sixteen Bits

The two register select flags are set or cleared by two new instructions provided for modifying the status register: one of the instructions, SEP, (set P) can be used to set any bit or bits in the P status register; the other, REP, (reset P) can be used to reset any bit or bits in the status register.

Figure 4.2 shows the results of changing the index registers and accumulator between eight and sixteen bits. When a sixteen-bit index register is switched to eight bits, the high byte is lost irretrievably and replaced by a zero. On the other hand, when an eight-bit index register is switched to sixteen bits, its unsigned value is retained by concatenating fit to a zero high byte; that is, the eight-bit unsigned index already in the register is extended to sixteen bits.

Unlike the index operations, switching the accumulator’s size either direction is reversible. The accumulator is treated differently due to its function, not as an index register, but as the register of arithmetic and logic. In this role, it is often called upon to operate on eight-bit values with sixteen-bit ones and vice versa.

When the sixteen-bit A accumulator is switched to eight bits, the low byte becomes the new eight-bit A accumulator while the high bit becomes the eight-bit “hidden” B accumulator. B may be seen as an annex to the A accumulator, accessible only through a new instruction which exchanges the values in the two accumulators (making B useful for temporarily storing of the eight-bit value in A). Conversely, when the accumulator is switched from eight bits to sixteen, the new sixteen-bit A accumulator has, as its low byte, the previous eight-bit A accumulator and, as its high byte, the previous hidden B accumulator.

Certain instructions that transfer the accumulator to or from other sixteen-bit registers refer to the sixteen-bit accumulator as C to emphasize that all sixteen accumulator bits will be referenced regardless of whether the accumulator is set to eight- or sixteen-bit mode. Again, this is illustrated in Figure 4.2.

The Status Register

Because the emulation bit is a “phantom” bit, it cannot be directly tested, set, or cleared. The flag that it

“phantoms” or overlays is the carry bit; there is a special instruction, XCE, that exchanges the contents of the two flags. This is the “trapdoor” through which the emulation mode is entered and exited.

50

The Western Design Center

HHHH HHHH x = 0

Results of Switching Register Sizes

(L = bits in low byte; H = bits in high byte)

Index Registers: 16 Bits to 8

LLLL LLLL 0000 0000 x = 1

LLLL LLLL

0000 0000 x = 1

LLLL LLLL

Index Register: 8 Bits to 16

0000 0000 x = 0

LLLL LLLL

A

HHHH HHHH m = 0

LLLL LLLL

Accumulator: 16 Bits to 8

B A

HHHH HHHH m = 1

LLLL LLLL

(also C)

B A

HHHH HHHH m = 1

LLLL LLLL

(also C)

Accumulator: 8 Bits to 16

A

HHHH HHHH m = 0

LLLL LLLL

(also C) (also C)

Figure 4-2 Results of Switching Register Size

Two status register bits were required for the two-flag eight-or-sixteen-bit scheme. While the 6502’s status register has only one unused status register bit available, its break flag is used only for interrupt processing, not during regular program execution, to flag whether an interrupt comes from a break instruction or from a hardware interrupt. By giving the break instruction its own interrupt vector in native mode, the 65816’s designers made a second bit available for the m and x register select flags.

6502/65C02 Addressing Modes on the 65816

All of the 6502 and 65C02 addressing modes are available to the 65816/65802, but native mode’s sixteen-bit features mean you need to expand your thinking about what they will do. For example, the 65816’s direct page, which can be located anywhere in memory, replaces the earlier zero page as the special page for short-operand addressing modes. All 6502/65C02 zero page addressing modes become direct page addressing modes, as shown in Table 4.2.

51

The Western Design Center

6502/65C02

Zero Page Addressing Mode

Zero Page

Zero Page Indexed with X

Zero Page Indexed with Y

Zero Page Indirect Indexed with Y

(Postindexed)

Zero Page Indirect Indexed with X

(Preindexed)

Zero Page Indirect

65802/65816

Direct Page Addressing Mode

Direct Page

Direct Page Indexed with X

Direct Page Indexed with Y

Direct Page Indirect Indexed with Y

Direct Page Indexed Indirect with X

Direct Page Indirect

Syntax Example Common to Both

Opcode Operand

LDA $55

LDA $55, X

LDX $55, Y

LDA

LDA

LDA

($55), Y

($55, X)

($55)

Table 4-2 Addressing Modes: Zero Page vs. Direct Page

Notice in Table 4.2 that the assembler syntax for each direct page addressing mode (not to mention the object bytes themselves) is the same as its zero page counterpart. The names and the results of the addressing modes are what differ. Direct page addressing, like the 6502/65C02 zero page addressing, allows a memory location to be addressed using only an eight-bit operand. In case of the 6502, a sixteen-bit zero page effect address is formed from an eight-bit offset by concatenating a zero high byte to it. In the 65802/65816, the direct page effective address is formed by adding the eight-bit offset to the sixteen-bit value in the direct register. This lets you relocate the direct page anywhere in bank zero, on any byte boundary. Note, however, that it is most efficient to start the direct page on a page boundary because this saves one cycle for every direct page addressing operation.

When considering the use of 6502/65C02 zero page instructions as 65802/65816 direct page instructions, remember that a direct page address of $23 is located in memory at location $0023 only if the direct page register is set to zero; if the direct page register holds $4600, for example, the direct page address

$23 is located at $4623. The direct page is essentially an array which, when it was the zero page, began at address zero, but which on the 65816 and 65802 can be set to begin at any location.

In the 6502/65C02, the effective address formed using zero page indexed addressing from a zero page base address of $F0 and an index of $20 is $10; that is, zero page indexed effective addresses wrap around to always remain in the zero page. In the emulation mode this is also true. But in native mode, there is no page wraparound: a direct page starting at $2000 combined with a direct page base of $20 and a sixteen-bit index holding $300 results in an effective address of $2320.

The three main registers of the 65802/65816 can, in native mode, be set to hold sixteen bits. When a register is set to sixteen bits, then the data to be accessed by that register will also be sixteen bits.

For example, shifting the accumulator left one bit, an instruction which uses the accumulator addressing mode, shifts sixteen bits left rather than eight if the accumulator is in sixteen-bit mode. Loading a sixteen-bit index register with a constant using immediate addressing means that a sixteen-bit value follows the instruction opcode. Loading a sixteen-bit accumulator by using absolute addressing means that the sixteen-bit value stored starting at the absolute address, and continuing into location at the next address, is loaded into the accumulator.

Sixteen-bit index registers give new power to the indexed addressing modes. Sixteen-bit index registers can hold values ranging up to 64K; no longer must the double-byte base of an array be specified as a constant with the index register used for the index. A sixteen-bit index can hold the array base with the double-byte constant specifying the (fixed) index.

Finally, the 65816 has expanded the scope of 6502 and 65C02 instructions by mixing and matching many of them with more of the 6502/65C02 addressing modes. For example, the jump-to-subroutine instruction can now perform absolute indexed indirect addressing, a mode introduced on the 65C02 solely for jump instruction.

New 65816 Addressing Modes

Not only do the 65802 and 65816 provide all the 6502 and 65C02 addressing modes, but they also offer nine new addressing modes of there own, in both emulation and native modes. They are shown in Table 4.3.

52

The Western Design Center

Addressing Mode

Program Counter Relative Long

Stack Relative

Stack Relative Indirect Indexed with Y

Block Move

Absolute Long

Absolute Long Indexed with X

Absolute Indirect Long

Direct Page Indirect Long

Direct Page Indirect Long Indexed with Y

Syntax Example

Opcode Operand

BRL JMPLABEL

LDA

LDA

3, S

(5,S), Y

MVP 0,0

LDA

LDA

JMP

LDA

LDA

$02F000

$12D080, X

[$2000]

[$55]

[$55], Y

Table 4-3 The 65816/65802’s New Addressing Modes

There are six new addressing modes that use the word “long”, but with two very different meanings.

Five of the “long” modes provide 24-bit addressing for intrabank accesses. Program counter relative long

addressing, on the other hand, provides an intrabank sixteen-bit form of relative addressing for branching. Like all the other branch instructions, its operand is an offset from the current contents of the program counter, but branch long’s operand is sixteen bits instead of eight, which expands relative branching from plus 127 or minus

128 bytes to plus 32767 or minus 32768. This and other features greatly ease the task of writing positionindependent code. The use of the word “long” in the description of this addressing mode means “longer than an eight bit offset”, whereas the word “long” used with the other four addressing modes means “longer than sixteen bits”.

Stack relative addressing and Stack relative indirect indexed with Y addressing treat the stack like an array and index into it. The stack pointer register holds the base of the array, while a one-byte operand provides the index into it. Since the stack register points to the next available location for data, a zero index is meaningless: data and addresses which have been pushed onto the stack start at index one. For stack relative, this locates the data; for stack relative indirect indexed, this locates an indirect address that points to the base of an array located elsewhere. Both give you the means to pass parameters on the stack in a clean, efficient manner. Stack relative addressing is a particularly useful capability, for example, in generating code for recursive high-level languages such as Pascal or C, which store local variables and parameters on a “stack frame”.

Block move addressing is the power behind two new instructions that move a block of bytes – up to

64K of them – from one memory location to another all at once. The parameters of the move are held in the accumulator (the count), the index registers (the source and destination addresses), and a unique double operand

(source and destination addresses in the operand specify the source and destination banks for the move operation).

The five remaining “long” addressing modes provide an alternative to the use of bank registers for referencing the 65816’s sixteen-megabyte address space. They let you temporarily override the data bank register value to address memory anywhere within the sixteen-megabytes address space. Absolute long

addressing, for example, is just like absolute addressing except that, instead of providing a two-byte absolution address to be accessed in the data bank, you provide a three-byte absolute address which overrides the databank.

Absolute long indexed with X, too, is four bytes instead of three. On the other hand, it is the memory locations specified by absolute indirect long, direct page indirect long, and direct page indirect long indexed with Y that hold three-byte indirect addresses instead of two-byte ones. Three-byte addresses in memory appear in conventional 65x order; that is, the low byte is in the lower memory locations, the middle byte (still referred to in 6502 fashion as the “high” byte) is in the next higher location, and the highest (bank) byte is in the highest location.

53

The Western Design Center

Instructions

There are 78 new opcodes put into use through the 28 new operations listed in Table 4.4, as well as through giving the previous processors’ operations additional addressing modes.

Instruction

Mnemonic

STP

TCD

TCS

TDC

TSC

TXY

TYX

WAI

WDM

XBA

XCE

PHB

PHD

PHK

PLB

PLD

REP

RTL

SEP

BRL

COP

JML

JSL

MVN

MVP

PEA

PEI

PER

Description

Branch always long

Co-processor empowerment

Jump long (interbank)

Jump to subroutine long(interbank)

Block move negative

Block move positive

Push effective absolute address onto stack

Push effective indirect address onto stack

Push effective program counter relative address onto stack

Push data bank register onto stack

Push direct page register onto stack

Push program bank register onto stack

Pull data bank register from stack

Pull direct page register from stack

Reset status bits

Return from subroutine long

Set status bits

Stop the processor

Transfer 16-bit accumulator to direct page register

Transfer accumulator to stack pointer

Transfer direct page register to 16-bit accumulator

Transfer stack pointer to 16-bit accumulator

Transfer index registers X to Y

Transfer index registers Y to X

Wait for interrupt

Reserved for future two-byte opcodes

Exchange the B and A accumulators

Exchange carry and emulation bits

Table 4-4 New 65816/65802 Instructions

Five of the new push and pull instructions allow the new registers to be stored on the stack; the other three let you push constants and memory values onto the stack without having to first load them into a register.

PER is unique in that it lets data be accessed relative to the program counter, a function useful when writing relocatable code.

There are also instructions to transfer data between new combinations of the registers; including between the index registers – a long-wished-for operation; to exchange the two bytes of the sixteen-bit accumulator; and to exchange the carry and emulation bits, the only method for toggling the processor between emulation and native modes.

There are new jump, branch, return, and move instructions already described in the section on addressing modes. There’s a new software interrupt provided for sharing a system with a co-processor. There are two instructions for putting the processor to “sleep” in special low-power states. And finally, there’s a reserved opcode, called WDM (the initials of the 65816’s designer, William D. Mensch, Jr.), reserved for some future compatible processor as the first byte of a possible 256 two-byte opcodes.

54

The Western Design Center

Interrupts

Native mode supplies an entire set of interrupt vectors at different locations from the emulation mode

(and earlier 6502/65C02) ones to service native mode and emulation mode interrupts differently. Shown in

Table 4.5, all are in bank zero; in addition, the sixteen-bit contents of each vector points to a handling routine which must be located in bank zero.

IRQ

RESET

NMI

ABORT

BRK

COP

Emulation Mode

FFFE,FFFF

FFFC,FFFD

FFFA,FFFB

FFF8,FFF9

-

FFF4,FFF5

All locations are in bank zero.

Native Mode

FFEE,FFEF

-

FFEA,FFEB

FFE8,FFE9

FFE6,FFE7

FFE4,FFE5

Table 4-5 Interrupt Vector Locations

As discussed earlier in this chapter, native mode frees up the b bit in the status register by giving the break instruction its own vector. When the BRK is executed, the program counter and the status register are pushed onto the stack and the program counter is loaded with the address at $FFE6, the break instruction vector location.

The reset vector is only available in emulation mode because reset always returns the processor to that mode.

The 65816/65802, both emulation and native modes, also provides a new co processor interrupt instruction to support hardware co processing, such as by a floating point processor. When the COP instruction is encountered, the 65802’s interrupt processing routines transfer control to the co-processor vector location.

Finally, the pinout on the 65816 provides a new abort signal. This lets external hardware prevent the

65816 from updating memory or registers while completing the current instruction, useful in sophisticated memory-management schemes. An interrupt-like operation then occurs, transferring control through the special abort vector.

The 65802 Native Mode

For all that the 65816 is, it is not pin-compatible with the 6502 and 65C02. You can’t just replace the earlier chips with it. It is here that the other version of this chip, the 65802, comes to its glory. The price, of course, is that the 65802 has the same addressability limitations as the 6502 and 65C02.

Figure 4.3 shows the programming model for the 65802’s native mode. The bank registers, while they exist, do not modify addressability, so they are shown as eight-bit entities. All registers have been scaled back to sixteen bits. There is only one bank a 65802 can address; since it holds the direct page, the stacker point, and the interrupt vectors (bank-zero features on the 65816), you can consider the 65802’s bank to be bank zero.

Otherwise, the programming model is identical to the 65816’s.

The bank registers are an anomaly. They have no function because the packaging provides no pins to connect them to. But they exist because, inside the package, the chip itself is a 65816. In fact, you can change their value just as you would on the 65816, with a pull instruction, a long jump or JSR, an interrupt, or a long return, either from subroutine or from interrupt. Furthermore, every interrupt and return from interrupt pushes the program bank byte onto the stack or pulls it off, just like the 65816 does. But the bank register values are ignored (stripped from 24-bit addresses when they’re sent to the sixteen-bit output pins).

The long addressing modes also seem misplaced here. You can execute instructions using long addressing on the 65802, but the bank addresses are, again, ignored. They are certainly an inefficient method for undertaking intrabank accesses and transfers, since they take up extra bytes for the bank address, and use up extra cycles in translation. Still, they cause the 65802 no problems, as long as you understand that the bank value is disregarded and only the remaining sixteen bits of address are effective in pointing to an address in the

65802’s single addressable bank of memory.

55

The Western Design Center

Five of the new push and pull instructions allow the new registers to be stored on the stack; the other three let you push constants and memory values onto the stack without having to first load them into a register.

PER is unique in that it lets data be accessed relative to the program counter, a function useful when writing relocatable code.

56

The Western Design Center

65802 Native Mode Programming Model

(16-bit accumulator & index register modes: m=0 & x=0)

15

Accumulator (B)

7

(A or C)

0

Accumulator (A)

X Index Register (X)

Y Index Register (Y)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC)

Data Bank Register (DBR)

Program Bank Register (PBR)

Processor Status Register (P)

7 n v m x d i z e c

0

Emulation 0 = Native Mode

Carry

Zero

IRQ Disable

Decimal Mode

Index Register Select

Memory/Accumulator Select

Overflow

Negative

1 = Carry

1 = Result Zero

1 = Disabled

1 = Decimal, 0 = Binary

1 = 8-bit, 0 = 16-bit

1 = 8-bit, 0 = 16-bit

1 = Overflow

1 = Negative

Figure 4-3 65802 Native Mode Programming Model

Finally, the bank bytes specified to the block move instructions are ignored, too. Block moves are by necessity entirely intrabank on the 65802.

Because the abort signal was designed into the 65816 by virtue of its redesigned pinout, its vector exists on the 65802 but has no connection to the outside world. Since there is no way to abort an instruction without using the external pin, the abort operation can never occur on the 65802.

In all other respects, the 65802 and the 65816 are identical, so the 65802 can almost be thought of as a

65816 in a system with only 64K of physical memory installed. Table 4.6 summarizes the differences between the 65802 and 65816 native modes and the 6502 and 65C02

.

57

The Western Design Center

Emulation Mode

That the 65802 provides a pinout the same as the 6502’s and the 65C02’s is not enough to run all the software written for the earlier two processors. For one thing, the eight-bit software expects interrupt handlers to distinguish break instructions by checking the stacked break flag, and the 65802’s native mode has no break flag, having replaced both it and the 6502’s unused flag with the m and x flags. For another, 6502 instructions that use eight-bit registers to set the stack would set only half of the sixteen-bit stack. The native mode interrupt vectors are only half of the sixteen-bit stack. The native mode interrupt vectors are different from their

6502/65C02 counterparts, as Table 4.5 showed. There are also little differences; for example, while the direct page can be set to the zero page, direct page indexed addresses can cross pages in native mode, but wrap on the

6502 and 65C02.

Reaching beyond hardware compatibility to software compatibility was clearly so important that the designers of the 65802 and 65816 devised the 6502 emulation mode scheme. Both processors power-on in emulation mode, with the bank registers and the direct page register initialized to zero. As a result of both this and having the same pinout, a 65802 can be substituted for a 6502 in any application and will execute the existing software the same. Furthermore, it is possible to design second-generation 65816 systems compatible with existing 6502 designs which, provided the computer’s designers do as good a job in providing compatibility as the 65816’s designers have, could run all existing software of the first generation system in emulation mode, yet switch into native mode for sixteen-bit power and 24-bit addressing.

It is important to realize, however, that 6502 emulation mode goes far beyond emulating the 6502. It embodies all the addressing mode and instruction enhancements of both the 65C02 and the 65802/65816; it has a fully relocatable direct page register; it provides the stack relative addressing modes; and in the 65816’s emulation mode, it can switch between banks to use 24-bit addressing. The primary differences between native and emulation modes are limitations placed on certain emulation mode registers and flags so that existing programs are not surprised (and crashed) by non-6502-like results. These differences are summarized in Table

4.6.

58

The Western Design Center

59

The Western Design Center

The pair of 65816 instructions have little use in emulation mode are the block move instructions.

Because the source and destination parameters for moves are passed to the instruction in the index registers, their eight-bit limits confine the instruction to the zero page: a block can only be moved from one zero page location to another.

Only in emulation mode do 65802/65816 interrupt vectors match their 6502/65C02 counterparts.

Native mode interrupt vectors have their own locations, as Table 4.5 showed.

Emulation Mode Registers

The 65802/65816, under emulation mode, has the same six registers as the 6502/65C02. In addition, all of the new 65802/65816 registers are available in some form, although some of these on a limited basis. Figure

4.4 shows the result.

The primary accumulator A is always limited to eight bits by lack of an m flag, but hidden eight-bit accumulator B is available, as with the native mode eight-bit accumulator setting. For certain register-transfer operations, the two are combined to form the sixteen-bit register C, just as in native mode. The index registers are limited to eight bits by lack of a x flag. The direct page register is fully functional, although direct page indexing wraps rather than crossing into the next page. The stack pointer is curtailed to page one, as on the

6502 and 65C02; if a sixteen-bit value is used to set it, the high bit is ignored. Finally there are two bank registers, which are initialized to zero, but which can be changed to point to other banks.

Now look at the P status register. In addition to the eight bits of the standard 6502/65C02 status register, you’ll see the ninth “phantom” e bit, which contains a one; this setting puts the processor into its 6502 emulation mode.

23

65816 Emulation Mode Programming Model

15 7

Accumulator (B)

©

Accumulator (A)

0

Data Bank Register (DBR)

X Index Register (X)

Y Index Register (Y)

0 0 0 0 0 0 0 0 Direct Page Register (D)

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 Stack Pointer (S)

Program Bank Register (PBR) Program Counter (PC)

Processor Status Register (P)

7 n v b d i z e

0 c

Emulation 1=6502 Emulation Mode

Carry 1=Carry

Zero 1=Result Zero

IRQ Disable 1=Disabled

Decimal Mode 1=Decimal, 0=Binary

Break Instruction 1=Break caused interrupt

Overflow 1=Overflow

Negative 1=Negative

Figure 4-4 65816 Emulation Mode Programming Model

60

The Western Design Center

The A and B registers, which together make up the native mode sixteen-bit accumulator, are used together in emulation mode as C solely for transferring values to and from the direct page register and the stack.

The direct page register (D) points to the beginning of direct page memory. You’ll probably normally set it to zero in the emulation mode to make the direct page identical to 6502 zero page memory. This is particularly true if your 65802 program is running within a 6502 or 65C02 operating system. The operating system will have stored values to zero page memory; if you change the direct page to point to another page, then call an operation system routine, the operating system will load its information from the wrong direct page (any page other than the zero page) and fail miserably.

Switching Between 6502 Emulation and Native Modes

As you’ve seen, the native mode and the 6502 emulation mode embody a number of significant differences. When running the 65802 in an older machine, such as Apple II c, II e, or II Plus, you will probably call your 65802 programs from a 6502 operating system or program. Your 65802 code can immediately switch the processor into native mode, so you can take advantage of the additional power. You must, however, switch back to emulation mode to use any I/O routines, or to call the 6502-based operating system.

Understanding the transitions between the two modes is critical, particularly in an environment where you are switching back and forth between 6502 systems programs and your own 65802 code.

Switching from Emulation to Native Mode

When the 65802 is switched from emulation to native mode, the value in the status register’s carry bit winds up being toggled. Native mode is set by sweeping a cleared carry bit with the current value in the emulation bit (which was a one if the processor was in emulation mode). The m and x flags in the status register are switched into place (replacing the b break flag) and the processor automatically forces the flags to one which leaves the accumulator and index registers as eight-bit registers, the same as they were in emulation mode. The rest of the bits in the status register remain the same.

While the emulation mode stack pointer register is only eight-bit register, it can be thought of as a sixteen-bit register with its high byte hard-wired to one, so that the emulation stack is always in page one.

When the 65802 is switched from emulation to native mode, the sixteen-bit native mode stack pointer assumes the same value the emulation mode stack pointer has been pointing to - page one address.

All other registers make the transition unchanged

.

Switching from Native to Emulation Mode

Switching from native to emulation mode also toggles the carry. The carry bit is set, then exchanged with the emulation bit to force the processor back into emulation mode. Provided the processor was previously in native mode, the carry flag is cleared. The status register’s m and x bits disappear, forcing the accumulator and index registers back to eight bits. If the index registers were in sixteen-bit mode, they keep their low bytes, but their high bytes are permanently lost. If, on the other hand, the accumulator was in sixteen-bit mode, the low byte remains in accumulator A while the high byte remains accessible as the hidden accumulator B. The m bit (bit five) returns to its emulation role as the break flag; the x bit (bit four) becomes once again an unused flag.

The stack is truncated from sixteen to eight bits, with its high byte forced to a one; that is, the stack is forced to page one. Any value in the high byte of the stack pointer register is permanently lost, which means you must be very careful not to “lose” a non-page-one stack. Solving this and other sticky problems involved with calling an emulation mode routine from native mode is the goal of one of the routines in Chapter 14.

All other registers make the transition unchanged.

61

The Western Design Center

65802/65816 Bugs and Quirks

As on the 65C02, the 6502’s bugs are corrected by the 65802. Unlike the 65C02, however, the 65802 fixes the bug either only in native mode or without modifying the 6502’s cycle counts (as the 65C02 in some cases does). There are no unused opcodes on the 65802, although there is an opcode which, while technically

“used”, is really reserved. If executed, it acts like a no-operation instruction.

The most anomolous feature of the 65816 is the behavior of new opcodes while in the 6502 emulation mode. While strict 6502 compatibility is enforced for all 6502 and 65C02 opcodes, this is not the case with new opcodes. For example, although the high byte of the stack registers is always set to one, wrapping of the stack during the execution of a single non-6502 instruction is not supported. These issues are discussed more fully in

Chapter 16.

Because the 65802 fixes the 6502’s bugs and quirks while leaving that chip’s timing cycles untouched, the 65802 is in fact a hair more compatible as an upgrade chip than it the 65C02.

62

The Western Design Center

Part 3

Tutorial

63

The Western Design Center

5) Chapter Five

SEP, REP, and Other Details

Part Three is devoted to a step by step survey of all 92 different 65816 instructions and the 25 different types of addressing modes which, together, account for the 256 operation codes of the 65802 and 65816. As a matter of course, this survey naturally embraces the instruction sets of the 6502 and 65C02 as well.

The instructions are grouped into six categories: data movement, flow of control, arithmetic, logical and bit manipulation, subroutine calls, and system control instructions. A separate chapter is devoted to each group, and all of the instructions in a group are presented in their respective chapter.

The addressing modes are divided into two classes, simple and complex. The simple addressing modes are those that form their effective address directly - that is, without requiring any, or only minimal, combination or addition of partial addresses from several sources. The complex addressing modes are those that combine two or more of the basic addressing concepts, such as indirection and indexing, as part of the effective address calculation.

Almost all of the examples found in this book are intended to be executed on a system with either a

65802 or 65816 processor, and most include 65816 instructions, although there are some examples that are intentionally restricted to either the 6502 or 65C02 instructions set for purpose of comparison.

Because of the easy availability of the pin-compatible 65802, there is a good chance that you may, in fact, be executing your first sample programs on a system originally designed as a 6502-based system, with system software such as machine-level monitors and operating systems that naturally support 6502 code only.

All of the software in this book was developed and tested on just such systems (AppleII computers with either

65802s replacing the 6502, or with 65816 processor cards installed).

It is assumed that you will have some kind of support environment allowing you to develop programs and load them into memory, as well as a monitor program that lets you examine and modify memory, such as that found in the Apple II firmware. Since such programs were originally designed to support 6502 code, the case of calling a 65816 program from a 6502-based system program must be given special attention.

A 65802 or 65816 system is in the 6502 emulation mode when first initialized at power-up.

This is quite appropriate if the system software you are using to load and execute the sample programs is 6502-based, as it would probably not execute correctly in the native 65816 mode.

Even though almost all of the examples are for the 65816 native mode of operation, the early examples assume that the direct page register, program counter bank register, and data register are all in their default condition - set to zero - in which case they provide an environment that corresponds to the 64K programming space and zero page addressing of the 6502 and 65C02. Aside from keeping the examples simple, it permits easy switching between the native mode and the emulation mode. If you have just powered up your 65816 or

65802 system, nothing needs be done to alter these default values.

The one initialization you must do is switch from the emulation to the native mode. To switch out of the 6502 emulation mode, which is the default condition upon powering up a system, the code in Fragment 5.1

must be executed once.

0000 18

0001 FB

CLC

XCE clear carry flag exchange carry with e bit (clears e bit)

Fragment 5.1.

This clears the special e flag, putting the processor into the 65816 native mode.

If you are using a 65802 processor in an old 6502 system, the above code needs to be executed each time an example is called. Further, before exiting a 65816 program to return to a 6502 calling program, the opposite sequence in Fragment 5.2 must be executed

.

64

The Western Design Center

0000

0001

38

FB

SEC

XCE set carry flag exchange carry with e bit (set e bit)

Fragment 5.2.

Even if you are running your test programs from a fully supported 65816 or 65802 environment, you should include the first mode-switching fragment, since the operating mode may be undefined on entry to a program. Execution of the second should be acceptable since the system program should reinitialize itself to the native mode upon return from a called program.

A further requirement to successfully execute the example programs is to provide a means for returning control to the calling monitor program. In the examples, the RTS (return from subroutine) instruction is used.

The RTS instruction is not explained in detail until Chapter 12; however, by coding it at the end of each example, control will normally return to the system program that called the example program. So to exit a program, you will always code the sequence in Fragment 5.3.

0000 38

0001 FB

0002 60

SEC

XCE

RTS set carry flag exchange carry with e bit (sets e bit)

Fragment 5.3.

Some systems may have a mechanism other than RTS to return control to the system; consult your system documentation.

In addition to these two details, a final pair of housekeeping instructions must be mastered early in order to understand the examples.

These two instructions are SEP and REP (set P and reset P). Although they are not formally introduced until Chapter 13, their use is essential to effective use of the 65802 and 65816. The SEP and REP instructions have many uses, but their primary use is to change the value of the m and x flags in the status register. As you recall from Chapter 4, the m and x registers determine the size of the accumulator and index registers, respectively. When a flag is set (has a value of one), the corresponding register is eight bits; when a flag is clear, the corresponding register is sixteen bits. SEP, which sets bits in the status register, is used to change either accumulator, or index registers, or both, to eight bits; REP, which clears bits, is used to change either or both to sixteen bits. Whenever a register changes size, all of the operations that move data in and out of the register are affected as well. In this sense, the flag bits are extensions to the opcode, changing their interpretation by the processor.

The operand following the SEP and REP instructions is a “mask” of the flags to be modified. Since bit five of the status register is the m memory/accumulator select flag, an instruction of the form:

REP

#%00100000 makes the accumulator size sixteen bits; a SEP instruction with the same argument (or its hexadecimal equivalent, $20) would make it eight bits. The binary value for modifying the x flag is %00010000, or $10; the value for modifying both flags at once is %00110000, or $30. The sharp (#) preceding the operand signifies the operand is immediate data, stored in the byte following the opcode in program memory; the percent (%) and dollar ($) signs are special symbols signifying either binary or hexadecimal number representation, respectively, as explained in Chapter 1.

Understanding the basic operation of SEP and REP is relatively simple. What takes more skill is to develop a sense of their appropriate use, since there is always more than one way to do things. Although there is an immediate impulse to want to use the sixteen-bit modes for everything, it should be fairly obvious that the eight-bit accumulator mode will, for example, be more appropriate to applications such as character manipulation. Old 6502 programmers should resist the feeling that if they’re not using the sixteen-bit modes

“all the time” they’re not getting full advantage from their 65802 or 65816. The eight-bit accumulator and index register size modes, which correspond to the 6502 architecture, can be used to do some of the kinds of

65

The Western Design Center

things the 6502 was doing successfully before the option of using sixteen-bit registers was provided by the

65816. Even in eight-bit mode, the 65802 or 65816 will provide numerous advantages over the 6502.

What is most important is to develop a sense of rhythm; it is undesirable to be constantly switching modes. Since the exact order in which a short sequence of loosely related instructions is executed is somewhat arbitrary, try to do as many operations in a single mode as possible before switching modes. At the same time, you should be aware that the point at which an efficiency gain is made by switching to a more appropriate mode is reached very quickly. By examining the various possibilities, and experimenting with them, a sense that translates into an effective rhythm in coding can be developed.

Finally, a word about the examples as they appear in this book. Two different styles are used: Code

Fragments, and complete Code Listings.

Code Fragments are the kinds of examples used so far in this chapter. Code Listings, on the other hand, are self-contained programs, ready to be executed. Both appear in boxes, and are listed with the generated object code as produced by the assembler. Single-line listings are included in the text.

The Assembler Used in This Book

The assembly syntax used in this book is that recommended by the Western Design Center in their data sheet (see Appendix F). The assembler actually used in the ProDOS ORCA / M assembler for the Apple II computer, by Byteworks, Inc. Before learning how to code the 65816, a few details about some of the assembler directives need to be explained

.

Full-line comments are indicated by starting a line with an asterisk or a semicolon.

If no starting address is specified, programs begin by default at $2000. That address can be changed by using the origin directive, ORG. The statement

ORG $7000

When included in a source program, will cause the next byte of code generated to be located at memory location

$7000, with subsequently generated bytes following it.

Values can be assigned labels with the global equate directive, GEQU. For example, in a card-playing program, spades might be represented by the value $7F; the program is much easier to code (and read) if you can use label SPADE instead of remembering which of four values goes with which of the four suits, as seen in

Fragment 5.4.

0000

0000

0000

0000

SPADE

HEART

CLUB

DIAMOND

GEQU $7F

GEQU $FF

GEQU $3F

GEQU $1F

Fragment 5.4.

Now rather than loading the A accumulator by specifying a hard-to-remember value,

A97F LDA

You can load it by specifying the easier-to-remember label:

#$7F

A900 LDA #SPADE

Once you have defined a label using GEQU, the assembler automatically substitutes the value assigned whenever the label is encountered.

constant.

The # sharp or pound sign is used to indicate that the accumulator is to be loaded with an immediate

66

The Western Design Center

In addition to being defined by GEQU statements, labels are also defined by coded in the label field starting in the first column of a source line, right in front of an instruction or storage-defining directive. When coded in front of an instruction:

A905 BEGIN LDA #5

The label defines an entry point for a branch or jump to go to; when an instruction such as is assembled,

4C0400 JMP BEGIN the assembler automatically calculates the value of BEGIN and uses that value as the operand of the JMP instruction.

Variable and array space can be set aside and optionally labelled with the define storage directive, DS directive sets aside one byte at $1000 for the variable FLAG1; the second DS directive sets aside 20 bytes starting at $1001 for ARRAY1.

0000

0000

0000

0001

0015

00

00000000

MAIN

FLAG1

ARRAY1

ORG

START

DS

DS

END

$1000

1

20

Fragment 5.5

The value stored at FLAG1 can be loaded into the accumulator by specifying FLAG1 as the operand of the LDA instruction

:

AD

0010 LDA FLAG1

Program constants, primarily default values for initializing variables, prompts, and messages, are located in memory and optionally given a label by the declare constant directive, DC. The first character(s) of its operand specifies a type (A for two-byte addresses, I1 for one-byte integers, H for hex bytes and C for character strings, for example) followed by the value or values to be stored, which are delimited by single quotes

.

Fragment 5.6 gives an example. The first constant, DFLAG1, is a default value for code in the program to assign to the variable FLAG1. You may realize that DFLAG1 could be used as a variable; with a label, later values of the flag could be stored here and then there would be no need for any initialization code.

But good programming practice suggests otherwise: once another value is stored into DFLAG1, its initial value is lost, which keeps the program from being restarted from memory. On the other hand, using a GEQU to set up DFLAG1 would prevent you from patching the location with a different value should you change your mind about its initial value after the code has been assembled.

0000

0001

0003

001B

FE

0010

496E7365

00

DFLAG1

COUNT

PROMPT

DC

DC

DC

DC

I1 ‘ $FE ‘

A ‘ $1000 ‘

C ’ Insert disk into drive 1 ’

I1 ‘ 0 ‘

Fragment 5.6

Defining COUNT as a declared constant allows it, too, to patched in object as well as edited in source.

PROMPT is a message to be written to the screen when the program is running. The assembler lists only the first four object bytes generated (‘496E7365‘) to save room, but generates them all. The zero on the next line acts as a string terminator.

Sometimes it is useful to define a label at a given point in the code, but not associate it with a particular source line; the ANOP (assembler no-operation) instruction does this. The value of the label will be the

67

The Western Design Center

location of the code resulting from the next code-generating source line. One use of this feature is to define two labels with the same value, as shown in Fragment 5.7.

0000

0000 0000

BLACK

WHITE

ANOP

DS 2

Fragment 5.7

The two bytes of variable storage reserved may now be referred to as either BLACK or WHITE; their value is the same.

Address Notation

The 16-megabyte address space of the 65816 is divided into 256 64K banks. Although it is possible to treat the address space in a linear fashion - the range of bytes from $000000 to $FFFFFF - it is often desirable and almost always easier to read if you distinguish the bank component of a 24-bit address by separating it with a colon:

$00:FFF0

$xx:1234

$01:XXXX

In these examples, the X characters indicate that that address component can be any legal value; the thing of interest is the specified component.

Similarly, when specifying direct page addresses, remember that a direct page address is only an offset; it must be added to the value in the direct page register:

dp:$30

$1000:30

The dp in the first example is used to simply indicate the contents of the direct page register, whatever it may be; in the second case, the value in the direct page register is given as $1000. Note that this notation is distinguished from the previous one by the fact that the address to the left of the colon is a sixteen-bit value, the address on the right is eight. Twenty-four-bit addresses are the other way around.

A third notation used in this book describes ranges of address. Whenever two addresses appear together seperated by a single dot, the entire range of memory location between and including the two addresses is being referred to. For example, $2000.2001 refers to the double-byte starting at $2000. If high bytes of the second address are omitted, they are assumed to have the same value as the first address. Thus, $2000.03 refers to the addresses between $2000 and $2003 inclusive.

68

The Western Design Center

6)

Chapter Six

First Examples: Moving Data

Most people associate what a computer does with arithmetic calculations and computations. That is only part of the story. A great deal of compute time in any application is devoted to simply moving data around the system: from here to there in memory, from memory into the processor to perform some operation, and from the processor to memory to store a result or to temporarily save an intermediate value. Data movement is one of the easiest computer operations to grasp and is ideal for learning the various addressing modes (there are more addressing modes available to the data movement operations than to any other class of instructions). It, therefore, presents a natural point of entry for learning to program the 65x instruction set.

On the 65x series of processors - the eight-bit 6502 and 65C02 and their sixteen-bit successors, the

65802 and 65816 - you move data almost entirely using the microprocessor registers.

This chapter discusses how to load the registers with data and store data from the registers to memory

(using one of the simple addressing modes as an example), how to transfer and exchange data between registers, how to move information onto and off of the stack, and how to move blocks (or strings) of data from one memory location to another (see Table 6-1).

69

The Western Design Center

Mnemonic

Load/Store Instructions:

LDA

LDX

LDY

STA

STX

STY

6502

x x x x x x

Push Instructions:

PHA

PHP

PHX

PHY

PHB

PHK

PHD x x

Push Instructions Introduced:

PEA

PEI

PER

Pull Instructions:

PLA

PLP

PLX

PLY

PLB

PLD

Transfer Instructions:

TAX

TAY

TSX

TXS

TXA

TYA

TCD

TDC

TCS

TSC

TXY

TYX

Exchange Instructions:

XBA

XCE

Store Zero to Memory:

STZ

Block Moves:

MVN

MVP x x x x x x x x

Available on:

65C02 65802/816

x x x x x x x x x x x x

Description

load the accumulator load the X index register load the Y index register store the accumulator store the X index register store the Y index register x x x x x x x x x x x push the accumulator push status register (flags) push X index register push Y index register push data bank register push program bank register push direct page register x x x x x x x x x x x x x push effective absolute address push effective indirect address push effective relative address pull the accumulator pull status register (flags) pull X index register pull Y index register pull data bank register pull direct page register x x x x x x x x x x x x x x x x x x x x x x transfer A to X transfer A to Y transfer S to X transfer X to S transfer X to A transfer Y to A transfer C accumulator to D transfer D to C accumulator transfer C accumulator to S

(Continued)

transfer S to C accumulator transfer X to Y transfer Y to X exchange B & A accumulator exchange carry & emulation bits store zero to memory x x move block in negative direction move block in positive direction

Table 6-1 Data Movement Instruction

70

The Western Design Center

When programming the 6502, whether you’re storing a constant value to memory or moving data from one memory location to another, one of the registers is always intermediate. The same is generally true for the other 65x processors, with a few exceptions: the 65816’s two block move instructions, three of its push instructions, and an instruction first introduced on the 65C02 to store zero to memory.

As a result, two instructions are required for most data movement: one to load a register either with a constant value from program memory or with a variable value from data memory; the second to store the value to a new memory location.

Most data is moved via the accumulator. This is true for several reasons. First, the accumulator can access memory using more addressing modes than any of the other registers. Second, with a few exceptions, it’s only in the accumulator that you can arithmetically or logically operate on data (although the index registers, in keeping with their role as loop counters and array pointers, can be incremented, decremented, and compared). Third, data movement often takes places inside of loops, program structures in which the index registers are often dedicated to serving as counters and pointers.

Loading and Storing Registers

To provide examples of the six basic data-movement instructions - LDA, LDX, LDY (load accumulator or index registers) and STA, STX, and STY (store accumulator or index registers) - requires introducing at least one of the 65x addressing modes. Except for certain instructions - such as push and pull, which use forms of stack addressing - the absolute addressing mode will generally be used in this chapter.

Absolute addressing, available on all four 65x processors, is one of the simplest modes to understand. It accesses data at a known, fixed memory location.

For example, to move a byte from one absolute memory location to another, load a register from the first location, then store that register to the other location. In Listing 6.1, the eight-bit value $77 stored at the absolute location identified by the label SOURCE is first loaded into the accumulator, then saved to the absolute location DEST. Note the inclusion of the mode-switching code described in the previous chapter.

The code generated by the assembler, when linked, will begin at the default origin location, $2000. The example generates 13 ($0D) bytes of actual code (the address of the RTS instruction is at memory location

$200C). The assembler then automatically assigns the next available memory location, $200D, to the label on the following line, SOURCE. This line contains a DC (define constant) assembler directive, which causes the hexadecimal value $77 to be stored at that location in the code file ($200D). Since only one byte of storage is used, the data storage location reserved for the label DEST on the next line is $200E.

The syntax for absolute addressing lets you code, as an instruction’s operand, either a symbolic label or an actual value. The assembler converts a symbolic operand to its correct absolute value, determined from its context that absolute addressing is intended, and generates the correct opcode for the instruction using absolute addressing. The assembler-generated hexadecimal object code listed to the left of the source code shows that the assembler filled in addresses $000D and $000E as the operands for the LDA and STA instructions, respectively (they are, of course, in the 65x’s standard low-high order and relative to the $0000 start address the assembler assigns to its relocatable modules; the linker will modify these addresses to $200D and $200E when creating the final loadable object).

As Chapter 4 explained, the 65816’s accumulator can be toggled to deal with either eight-bit or sixteenbit quantities, as can its index registers, by setting or resetting the m (memory/accumulator select) or x (index register select) flag bits of the status register. You don’t need to execute a SEP or REP instruction before every instruction or every memory move, provided you know the register you intend to use is already set correctly.

But always be careful to avoid making invalid assumptions about the modes currently in force, particularly when transferring control from code in one location to code in another.

The load and store instructions in Listing 6.1 will as easily move a double byte as they did a byte, if the register you use is in sixteen-bit mode, as in Listing 6.2.

71

The Western Design Center

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000

0008 0000 18

0009 0001 FB

0010 0002

0011 0002

0012 0002

0013 0002 E220

0014 0004 AD0D00

0015 0007 8D0E00

0016 000A

0017 000A

0018 000A

0019 000A 38

0020 000B FB

0021 000C

0022 000C 60

0023 000D

0024 000D 77

0025 000E 00

0026 000F

0027 000F

;

;

;

;

MAIN

KEEP KL.6.1

65816 ON

START code to switch from 6502 emulation to native mode

CLC

XCE main example code clear carry flag exchange carry with E bits (clear E bit)

SEP #%00100000

LDA SOURCE

STA DEST set 8-bit data mode load byte from memory location SOURCE store byte to memory location DEST code to return to 6502 emulation mode

SEC

XCE

RTS set carry flag exchange carry with E bit (set E bit)

SOURCE DC H’77’

DEST DS 1

END

Listing 6.1.

Note that the source data in the define constant statement is now two bytes long, as is storage reserved by the define storage statement that follows. If you look at the interlisted hexadecimal code generated by the assembler, you will see that the address of the label DEST is now $200F. The assembler has automatically adjusted for the increase in the size of the data at SOURCE, which is the great advantage of using symbolic labels rather than fixed addresses in writing assembler programs.

The load and store instructions are paired here to demonstrate that, when using identical addressing modes, the load and store operations are symmetrical. In case, though, a value loaded into a register will be stored many instructions later, or never at all, or stored using an addressing mode different from that of the load instruction.

72

The Western Design Center

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000 18

0008 0001 FB

0009 0002

0010 0002 C220

0011 0004 AD0D00

0012 0007 8D0F00

0013 000A

0014 000A

0015 000A 38

0016 000B FB

0017 000C

0018 000C 60

0019 000D

0020 000D 7F7F

0021 000F 0000

0022 0011

MAIN

KEEP KL.6.2

65816 ON

START

; switch from 6502 emulation to native mode

CLC

XCE

;

REP

LDA

STA

#%00100000 reset accumulator to 16-bit mode

SOURCE load double byte from memory location SOURCE

DEST store double byte to memory location DEST

;

DEST switch back to emulation mode

SEC

XCE

;

RTS

;

SOURCE DC

DS

END

A’$7F7F’

2

Listing 6.2.

Effect of Load and Store Operations on Status Flags

One of the results of the register load operations - LDA, LDY, and LDX - is their effect on certain

status flags in the status register. When a register is loaded, the n and z flags are changed to reflect two conditions: whether the value loaded has its high bit set (is negative when considered as a signed, two’scomplement number); and whether the number is equal to zero. The n flag is set when the value loaded is negative and cleared otherwise. The z flag is set when the value loaded is zero and cleared otherwise. How you use these status flags will be covered in detail in Chapter 8, Flow of Control.

The store operation does not change any flags, unlike the Motorola 68xx store instructions. On the other hand, Intel 808x programmers will discover the 65x processors use load and store instructions instead of the 808x’s all-encompassing MOV instruction. The 808x move instruction changes no flags whatsoever, unlike the 65x load instruction, which does.

Moving Data Using the Stack

All of the 65x processors have a single stack pointer. (This is a typical processor design, although there are designs that feature other stack implementations, such as providing separate stack pointers for the system supervisor and the user.) This single stack is therefore used both by the system for automatic storage of address information during subroutine calls and of address and register information during interrupts, and by user programs for temporary storage of data. Stack use by the system will be covered in later chapters.

As the architecture chapters in Part II discussed. The S register (stack pointer) points to the next available stack location; that is, S holds the address of the next available stack location. Instructions using stack addressing locate their data storage either at or relative to the next available stack location.

The stack pointers of the 6502 and 65C02 are only eight bits wide; the eight-bit value in the stack pointer is added to an implied base of $100, giving the actual stack memory of $100 to $1FF; the stack is confined to page one. The 65816’s native mode stack pointer, on the other hand, is sixteen bits wide, and may point to any location in bank zero (the first 64K of memory). The difference is illustrated in Figure 6.1.

73

The Western Design Center

Push

Push instructions store data, generally located in a register, onto the stack. Regardless of a register’s size, the instruction that pushes it takes only a single byte.

When a byte is pushed onto the stack, it is stored to the location pointed to by the stack pointer, after which the stack pointer is automatically decremented to point to the next available location.

When double-byte data or a sixteen-bit address is pushed onto the stack, first its high-order byte is stored to the location pointed to by the stack pointer, the stack pointer is decremented, the low byte is stored to the new location pointed to by the stack pointer, and finally the stack pointer is decremented once again, pointing past both bytes of pushed data. The sixteen-bit value ends up on the stack in the usual 65x memory order: low byte in the lower address, high byte in the higher address.

In both cases, the stack grows downward, and the stack pointer points to the next available (unused) location at the end of the operation.

74

The Western Design Center

$ffff

MEMORY

65816/65802 native mode stack pointer:

16-bit range

$0000-$FFFF

6502/65C02 and

65816/65802 emulation mode stack pointer:

8-bit range

$0100-$01FF

$0200

$0100

$0000

Figure 6-1 Stack Memory

75

The Western Design Center

Pushing the Basic 65x Registers

On the 6502, only the contents of the accumulator and the status register can be pushed directly onto the stack in a single operation, using the PHA and PHP instructions, respectively. The 65C02 adds instructions to push the index registers onto the stack: PHX and PHY.

The 65816 and 65802 let double-byte data as well as single bytes be pushed onto the stack. Figure 6.2

shows the results of both. In the case of the accumulator and index registers, the size of the data pushed onto the stack depends on the settings of the m memory/accumulator select and x index register select flags. Since the accumulator and index registers are of variable size (eight bits or sixteen), the PHA, PHX, and PHY instructions have correspondingly variable effects.

Pull

Pull instructions reverse the effects of the path instructions, but there are fewer pull instructions, all of them single-bit instructions that pull a value off the stack into a register. Unlike the Motorola and Intel processors (68xx and

808x), the 65x pull instructions set the n and z flags. So programmers used to using pull instructions between a test and a branch on the other processors should exercise caution with the 65x pull instructions.

Pulling the Basic 65x Registers

The 6502 pull instructions completely complement its push instructions. PLP increments the stack pointer, then loads the processor status register (the flags) from the page one address pointed to by the offset in the stack pointer (of course, this destroys the previous contents of the status register). PLA pulls a byte from the stack into the accumulator, which affects the n and z flags in the status register just as a load accumulator instruction does.

As instructions for pushing the index registers were added to the 65C02, complementary pull instructions were added, too - that is, PLX and PLY. The pull index register instructions also affect the n and z flags.

On the 65802 and 65816, the push and pull instructions for the primary user registers - A, X, and Y have been augmented to handle sixteen-bit data when the appropriate select flag (memory/accumulator or index register) is clear. Code these three pull instructions carefully since the stack pointer will be incremented one or two bytes per pull depending on the current settings of the m and x flags.

76

The Western Design Center

High

Old Stack Pointer

New Stack Pointer

High

8-Bit or Low Byte of 16-Bit Register

Low

·

·

·

8 Bit Data

Next Stack Location

·

·

·

Stack

Memory

16-Bit Register

Low

Old Stack Pointer

New Stack Pointer

·

·

·

Data High

Data Low

Next Stack Location

·

·

·

Stack

Memory

Figure 6-2. Push

77

The Western Design Center

Pushing and Pulling the 65816’s Additional Registers

The 65816 adds one-byte push instructions for all its new registers, and pull instructions for all but one of them. In fact, the bank registers can only be accessed using the stack. PHB pushes the contents of the data bank register, an eight-bit register, onto the stack. PLB pulls an eight-bit value from the stack into the data bank register. Two most common uses for PHB are, first, to let a program determine the currently active data bank, and second, to save the current data bank prior to switching to another bank.

Fragment 6.1 is a 65816 code fragment which switches between two data banks. While OTHBNK is declared just once, it represents two different memory cells, both with the same sixteen-bit address of $FFF3, but in two different 64K banks: one is in the data bank that is current when the code fragment is entered; the second is in the data bank switched to by the code fragment. The code fragment could be executed a second time and the data bank would be switched back to the original bank.

0002

0005

0005

0006

0007

0007

0008

0009

0009

0000

0000

0000

0000

0000

0000

0002

000C

000C

000C

000C

E220

ADF3FF

8B

48

AB

68

8DF3FF

OTHBNK GEQU $FFF3

.

.

.

SEP #%00100000 location of other bank stored here set accumulator to 8-bit mode

LDA

PHB

PHA

PLB

PLA

.

.

.

STA

OTHBNK

OTHBNK get location of bank to switch to push current data bank onto stack push other data bank onto stack pull data bank: make other data bank current get original data bank into accum store it in 2 nd

bank so can be restored

Fragment 6.1.

Similar to PHB, the PHK instruction pushes the value in the eight-bit program counter bank register onto the stack. Again, the instruction can be used to let you locate the current bank; this is useful in writing bank-independent code, which can be executed out of any arbitrarily assigned bank.

You’re less likely to use PHK to preserve the current bank prior to changing banks (as in the case of

PHB above) because the jump to subroutine long instruction automatically pushes the program counter bank as it changes it, and because there is no complementary pull instruction. The only way to change the value in the program counter bank register is to execute a long jump instruction, and interrupt, or a return from subroutine or interrupt. However, you can use PHK to synthesize more complex call and return sequences, or to set the data bank equal to the program bank.

Finally, the PHD instruction pushes the sixteen-bit direct page register onto the stack, and PLD pulls a sixteen-bit value from the stack into the direct page register. PHD is useful primarily for preserving the direct page location before changing it, while PLD is an easy way to change or restore it. Note that PLB and PLD also affect the n and z flags.

78

The Western Design Center

Pushing Effective Addresses

The 65816 also provides three instructions which can push data onto the stack without altering any registers. These three push effective address instructions - PEA, PEI, and PER - push absolute, indirect, and relative sixteen-bit addresses or data directly onto the stack from memory. Their use will be explained when their addressing modes are presented in detail in Chapter 11 (Complex Addressing Modes).

Other Attributes of Push and Pull

The types of data that can be pushed but not pulled are effective addresses and the K (or more commonly PBR) program bank register.

PLD and PLB are typically used to restore values from a previous state.

Finally, you should note that even though the push and pull operations are largely symmetrical, data that is pushed onto the stack from one register does not need to be pulled off the stack into the same register.

As far as the processor is concerned, data pulled off the stack does not have to be the same size as was pushed onto it. But needless to say, the stack can quickly become garbled if you are not extremely careful.

Moving Data Between Registers

Transfers

The accumulator is the most powerful of the user registers, both in the addressing modes available to accumulator operations and in its arithmetic and logic capabilities. As a result, addresses and indexes that must be used in one of the index registers must often be calculated in the accumulator. A typical problem on the

6502 and 65C02, since their registers are only eight bits wide, is that sixteen-bit values such as addresses must be added or otherwise manipulated eight bits at a time. The other half of the value, the high or low byte, must meanwhile be stored away for easy retrieval and quick temporary storage of register contents in a currently unused register is desirable.

For these reasons as well as to transfer a value to a register where a different operation or addressing mode is available, all 65x processors implement a set of one-byte implied operand instructions which transfer data from one register to another:

TAX

TAY

TSX

TXS

TXA

TYA

transfers the contents of the accumulator to the X index register transfers the contents of the accumulator to the Y index register transfers the contents of the stack pointer to the X index register transfers the contents of the X index register to the stack pointer transfers the contents of the X index register to the accumulator transfers the contents of the Y index register to the accumulator

Like the load instructions, all of these transfer operations except TXS set both the n and z flags. (TXS does not affect the flags because setting the stack is considered an operation in which the data transferred is fully known and will not be further manipulated.)

The availability of these instructions on the 65802/65816, with its dual-word-size architecture, naturally leads to some questions when you consider transfer of data between registers of different sizes. For example, you may have set the accumulator word size to sixteen bits, and the index register size to eight. What happens when you execute a TAY (transfer A to Y) instruction?

The first rule to remember is that the nature of the transfer is determined by the destination register. In this case, only the low-order eight bits of the accumulator will be transferred to the eight-bit Y register. A second rule also applies here: when the index registers are eight bits (because the index register select flag is set), the high byte of each index register is always forced to zero upon return to sixteen-bit size, and the loworder value of each sixteen-bit index register contains its previous eight-bit value.

Listing 6.3 illustrates these rules with TAY. In this example, the value stored at the location DATA2 is

$0033; only the low order byte has been transferred from the accumulator, while the high byte has been zeroed.

The accumulator, on the other hand, operates differently. When the accumulator word size is switched from sixteen bits to eight, the high-order byte is preserved in a “hidden” accumulator, B. It can even be

79

The Western Design Center

accessed without changing modes back to the sixteen-bit accumulator size by executing the XBA (exchange B with A) instructions, described in the following section. Listing 6.4 illustrates this persistence of the accumulator’s high byte. After running it, the contents of locations RESULT. RESULT+1 will be $7F33, or

33 7F, in low-high memory order. In other words, the value in the high byte of the sixteen-bit accumulator,

$7F, was preserved across the mode switch to eight-bit word size.

Now consider the case where the sixteen-bit Y register is transferred to an eight-bit accumulator, as shown in Listing 6.5. The result in this case is $33FF, making it clear that the high byte of the Y register has not been transferred into the inactive high-order byte of the accumulator. The rule is that operations on the eight-bit A accumulator affect only the low-order byte in A, not the hidden high byte in B. Transfers into the A accumulator fall within the rule.

Figure 6.3 summarizes the effects of transfers between registers of different sizes.

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000

0008 0000

0009 0001

0010 0002

0011

0012

0013

0014

0002

0004

0006

0009

18

FB

0015 000A C210

0016 000C 8C1400

0017 000F

0018 000F

0019 000F 38

0020 0010

0021 0011

0022 0011

C220

E210

AD1200

A8

FB

60

0023 0012

0024 0012

0025 0014

0026 0016

0027 0016

33FF

0000

;

;

MAIN

DATA

DATA2

KEEP

65816

KL.6.3

ON

START switch-to-native-mode code

CLC

XCE clear carry flag exchange carry with e bit (clear e bit)

REP

SEP

LDA

TAY

REP

STY

#$20

#$10

DATA set accum to 16 set index to 8 set index to 16 return to 6502 emulation mode

SEC set carry flag

XCE exchange carry with e bit (set e bit)

RTS

#$10

DATA2

DC

DS

END

A’$FF33’

2

Listing 6.3.

There are also rules for transfers from eight-bit to a sixteen-bit register. Transfers out of the eight-bit accumulator into a sixteen-bit index register transfer both eight-bit accumulators.

In Listing 6.6, the value saved to RESULT is $7FFF, showing that not only is the eight-bit A accumulator transferred to become the low byte of the sixteen-bit index register, but the hidden B accumulator is transferred to become the high byte of the index register. This means you can form a sixteen-bit index in the eight-bit accumulator one byte at a time, then transfer the whole thing to the index register without having to then transfer the whole thing without having to switch the accumulator to sixteen bits first. However, take care not to inadvertently transfer an unknown hidden value when doing transfers from the eight-bit accumulator to a sixteen-bit index register.

80

The Western Design Center

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000 18

0008 0001 FB

0009 0002

0010 0002 C230

0011 0004 AD1400

0012 0007 E220

0013 0009 AD1600

0014 000C C220

0015 000E 8D1700

0016 0011

0017 0011

0018 0011 38

0019 0012 FB

0020 0013

0021 0013 60

0022 0014

0023 0014 FF7F

0024 0016 33

0025 0017 0000

0026 0019

0027 0019

;

;

MAIN

KEEP

65816

START switch-to-native-mode code

CLC

XCE

REP

LDA

SEP

LDA

REP

STA

#$30 clear carry flag exchange carry with e bit (clear e bit)

DATA16 load accum with 16-bit value at DATA16

#$20

DATA8

#$20 set accum and index size to 16 set accum to eight bits load 8-bit value at DATA8 make accum 16 again

RESULT save accum lo.hi in RESULT.RESULT+1 return to 6502 emulation mode

SEC

XCE

RTS

DATA16 DC

DATA8 DC

RESULT DS

END

A’$7FFF’

H’33’

2 set carry flag exchange carry with e bit (set e bit)

Listing 6.4

81

The Western Design Center

Transfers from eight-bit index register to the sixteen-bit accumulator result in the index register being transferred into the accumulator’s low byte while the accumulator’s high byte is zeroed. This is consistent with the zeroing of the high byte when eight-bit index registers are switched to sixteen bits.

In Listing 6.7, the result is $0033, demonstrating that when an eight-bit index register is transferred to the sixteen-bit accumulator, a zero is concatenated as the high byte of the new accumulator value.

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000

0008 0000

0009 0001

0010 0002

0011 0002

0012 0004

18

FB

C230

AC1500

0013 0007 AD1700

0014 000A E220

0015 000C 98

0016 000D C220

8D1900 0017 000F

0018 0012

0019 0012

0020 0012

0021 0012

0022 0013

0023 0014

0024 0014

0025 0015

0026 0015

0027 0017

0028 0019

0029 001B

0030 001B

38

FB

60

FF7F

4433

0000

;

;

MAIN

DATA16

DATA2

RESULT

KEEP

65816

START

DC

DC

DS

END

KL.6.5

ON switch to native mode

CLC

XCE clear carry flag exchange carry with e bit (clear e bit)

REP

LDY

LDA

SEP

TYA

REP

STA

#$30

DATA16

DATA2

#$20

#$20

RESULT return to 6502 emulation mode set accum, index size to 16 load Y-reg with 16-bit value at DATA16 load accum with 16-bit value at DATA2 set accum to eight bits transfer Y register’s value to A make accum 16 again save accum lo.hi in RESULT>RESULT+1

SEC

XCE

RTS

A’$7FFF’

A’$3344’

2 set carry flag exchange carry with e bit (set e bit)

Listing 6.5.

In the 65816, transfers between index registers and the stack also depend on the setting of the destination register.

For example, transferring the sixteen-bit stack to an eight-bit register, as in Fragment 6.2, results in the transfer of just the low byte. Obviously, though, you’ll find few reasons to transfer only the low byte of the sixteen-bit stack pointer. As

always, you need to be watchful of the current modes in force in each of your routines.

The 65816 also adds new transfer operations to accommodate direct transfer of data to and from the new 65816 environment-setting registers (the direct page register and the sixteen-bit stack register), and also to complete the set of possible register transfer instructions for the basic 65x user register set:

82

The Western Design Center

(L = bits in low byte; H = bits in high byte; P = previous bits unmodified by transfer)

HHHH HHHH

16-Bit Index Register-------------------to-------------------8-Bit Accumulator A

LLLL LLLL

1 byte

PPPP PPPP LLLL LLLL

X or Y

only transfer low byte (hidden B accumulator not affected)

B A

HHHH HHHH

16-Bit Accumulator A-----------------to-------------------8-Bit Index Register

1 byte

LLLL LLLL 0000 0000

A only transfer low byte

LLLL LLLL

X or Y

16-Bit Stack Pointer----------------------to-------------------8-Bit Index Register X

HHHH HHHH LLLL LLLL

1 byte

0000 0000 LLLL LLLL

S X of little use: only transfers address-low

0000 0000

8-Bit Register----------------------------to-------------------16-Bit Accumulator A

LLLL LLLL

2 bytes

0000 0000 LLLL LLLL

X or Y A high byte transferred is 0

8-Bit Accumulator A------------------to-------------------16-Bit index Register

HHHH HHHH LLLL LLLL

2 bytes

HHHH HHHH LLLL LLLL

B A X or Y transfer both accumulators

0000 0000

8-Bit index Register X----------------to-------------------16-Bit Stack Pointer

LLLL LLLL

2 bytes

0000 0000

X S

LLLL LLLL sets stack to page 0 value

Figure 6-3 Register Transfers Between Different-Sized Registers

83

The Western Design Center

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000

0008 0000

0009 0001

0010 0002

0011 0002

18

FB

C230

0012 0004

0013 0007

AD1300

AC1500

0014 000A E220

0015 000C A8

0016 000D 8C1700

0017 0010

0018 0010

0019 0010

0020 0010

0021 0011

0022 0012

0023 0012

38

FB

60

0024 0013

0025 0013

0026 0013

0027 0015

0028 0017

0029 0019

0030 0019

FF7F

4433

0000

;

;

MAIN

DATA16

DATA2

RESULT

KEEP

65816

START

KL.6.6

ON switch to native mode

CLC

XCE

REP

LDA

LDY

SEP

TAY

STY

#$30

DATA16

DATA2

#$20

RESULT clear carry flag exchange carry with e bit (clear e bit) set accum, index size to 16 bits load accum with 16-bit value at DATA16 load Y-reg with 16-bit value at DATA2 set accum to eight bits transfer accum to Y save 16-bit index into RESULT.RESULT+1 return to 6502 emulation mode

SEC

XCE

RTS set carry flag exchange carry with e bit (set e bit)

DC

DC

DS

END

A’$7FFF’

A’$3344’

2

Listing 6.6

84

The Western Design Center

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000

0008 0000

0009 0000 18

0010 0001 FB

0011 0002

0012 0002 E210

0013 0004 C220

0014 0006 AD1300

0015 0009 AC1500

0016 000C 98

0017 000D 8D1600

0018 0010

0019 0010

0020 0010

0021 0010 38

0022 0011 FB

0023 0012

0024 0012 60

0025 0013

0026 0013

0027 0013 FF7F

0028 0015 33

0029 0016 0000

0030 0018

0031 0018

;

;

MAIN

DATA16

DATA8

RESULT

KEEP

65816

KL.6.7

ON

START switch-to-native-mode code

CLC

XCE clear carry flag exchange carry with e bit (clear e bit)

SEP

REP

LDA

LDY

TYA

STA

#$10

#$20

DATA16

DATA8 set index size to 8 bits set accum to 16 bits load accum with 16-bit value at DATA16 load Y-reg with 8-bit value at DATA8 transfer Y to accumulator save 16-bit accum into RESULT.RESULT+1 RESULT return to 6502 emulation mode

SEC

XCE

RTS set carry flag exchange carry with e bit (set e bit)

DC

DC

DS

END

A’$7FFF’

H’33’

2

0000

0002

E210

BA

SEP

TSX

#%00010000

Listing 6.7

set index mode to 8 bits transfer low byte of stack ptr to 8-bit x

Fragment 6.2

TCD

transfers the contents of the sixteen-bit accumulator C to the D direct page register. The use of the letter C in this instruction’s mnemonic to refer to the accumulator indicates that this operation is always is a sixteen-bit transfer, regardless of the setting of the memory select flag.

For such a transfer to be meaningful, of course, the high-order byte of the accumulator must contain a valid value.

TDC

transfer the contents of the D direct page register to the sixteen-bit accumulator. Again, the use of the letter C in the mnemonic to name the accumulator indicates that the sixteen-bit accumulator is always used, regardless of the setting of the memory select flag. Thus, sixteen bits are always transferred, even if the accumulator size is eight bits, in which case the high byte is stored to the hidden B accumulator.

TCS

transfers the contents of the sixteen-bit C accumulator to the S stacker pointer register, thereby relocating the stack. Since sixteen bits will be transferred regardless of the accumulator word size, the high byte of the accumulator must contain valid data.

TSC

transfer the contents of the sixteen-bit S stacker pointer register to the sixteen-bit accumulator,

C, regardless of the accumulator word size.

TXY

transfers the contents of the X index register to the Y index register. Since X and Y will always have the same register size, there is no ambiguity.

TYX

transfers the contents of the Y index register to the X index register. Both will always be the same size

.

85

The Western Design Center

Transfer instructions take only one byte, with the source and destination both specified in the opcode itself. In all transfers, the data remains intact in the original register as well as being copied into the new register.

Using TCS and TCD can be dangerous when the accumulator is in eight-bit mode, unless the accumulator was recently loaded in sixteen-bit mode so that the high byte, hidden when the switch was made to eight-bit mode, is still known. Transferring an indeterminate hidden high byte of the accumulator along with its known low byte into a sixteen-bit environment register such as the stack pointer will generally result in disaster

.

As always, you need to be watchful of the modes currently in force in each of your routines.

Exchanges

The 65802 and 65816 also implement two exchange instructions, neither available on the 6502 or

65C02. An exchange differs from a transfer in the two values are swapped, rather than one value being copied to a new location.

The first of the two exchange instructions, XBA, swaps the high and low bytes of the sixteen-bit accumulator (the C accumulator).

The terminology used to describe the various components of the eight-or-sixteen bit accumulator is: to use A to name the accumulator as a register that may be optionally eight or sixteen bits wide (depending on the

m memory/accumulator select flag); to use C when the accumulator is considered to be sixteen bits regardless of the setting of the m flag; and, when A is used in eight-bit mode to describe the low byte only, to use B to describe the hidden high byte of the sixteen-bit accumulator. In the latter case, when the accumulator size is set to eight bits, only the XBA instruction can directly access the high byte of the sixteen-bit “double accumulator”,

B. This replacement of A for B and B for A can be used to simulate two eight-bit accumulators, each of which, by swapping, “shares” the actual A accumulator. It can also be used in the sixteen-bit mode for inverting a double-byte value. The XBA instruction is exceptional in that the n flag is always set on the basis of bit seven of the resulting accumulator A, even if the accumulator is sixteen bits.

The second exchange instruction, XCE, is the 65816’s only, method for toggling between 6502 emulation mode and 65816 native mode. Rather than exchange register values, it exchanges two-bits - the carry flag, which is bit zero of the status register, and the e bit, which should be considered a kind of appendage to the status register and which determines the use of several of the other flags.

Fragment 6.3 sets the processor to 6502 emulation mode. Conversely, native mode can be set by replacing the SEC with a CLC clear carry instruction.

0010 38

0011 FB

SEC

XCE

Fragment 6.3

Because the exchange stores the previous emulation flag setting into the carry, it can be saved and restored later. It can also be evaluated with the branch-on-condition instructions to be discussed in Chapter 8

(Flow of Control) to determine which mode the processor was just in. A device driver routine that needs to set the emulation bit, for example, can save its previous value for restoration before returning.

The selection of the carry flag for the e bit exchange instruction is in no way connected to the normal use of the carry flag in arithmetic operations. It was selected because it is easy to set and reset, it is less frequently used than the sign and zero flags, and there are branch-on-conditions instructions which test it. The primary use of the SEC and CLC instructions for arithmetic will be covered in upcoming chapters.

Storing Zero to Memory

The STZ instructions, introduced on the 65C02, lets you clear either a single or double byte memory word zero, depending, as usual, on the current memory/accumulator select flag word size. Zero has long been recognized as one of the most commonly stored values, so a “dedicated” instruction to store zero to memory can improve the efficiency of many 65x programs. Furthermore, the STZ instruction lets you clear memory without having to first load one of the registers with zero. Using STZ results in fewer bytes of code, faster execution, and undisturbed registers.

86

The Western Design Center

Block Moves

The two block move instructions, available only on the 65802 and the 65816, let entire blocks (or strings) of memory be moved at once.

Before using either instruction, all three user registers (C,X, and Y) must be set up with values which serve as parameters.

The C accumulator holds the count of the number of bytes to be moved, minus one. It may take some getting used to, but this “count” is numbered from zero rather than one. The C accumulator is always sixteen bits: if the m mode flag is set to eight bits, the count is still the sixteen-bit value in C, the concatenation of B and A.

X and Y specify either the top or the bottom addresses of the two blocks, depending on which of the two versions of the instruction you choose. In Listing 6.8, $2000 bytes of data are moved from location $2000 to $4000.

0001

0002

0003

0004

0005

0006

0007

0008

0009

0010

0011

0012

0013

0014

0015

0016

0017

0018

0019

0020

0021

0022

0023

0024

0025

0026

0027

0000

0000

0000

0000

0000

0000

0001

0002

0002

0004

0004

0004

0004

0007

000A

000D

000D

0010

0010

0011

0012

0013

0013

0015

0017

0019

0019

18

FB

C230

AD1300

AE1500

AC1700

540000

38

FB

60

FF1F

0020

0040

MAIN

COUNT

SOURCE

DEST

SEC

XCE

RTS

DC

DC

DC

END

KEEP

65816

START

CLC

XCE

REP

LONGA

LONGI

LDA

LDX

LDY

MVN

KL.6.8

ON

#$30

ON

ON

COUNT

SOURCE

DEST

0,0

A’$1FFF’

A’$2000’

A’$4000’

Listing 6.8.

reset data and index mode to 16 bits load 16-bit C accum with # bytes to be moved load 16-bit X reg with address of source load 16-bit Y reg with address of destination

The MVN instruction uses X and Y to specify the bottom (or beginning) addresses of the two blocks of memory. The first byte is moved from the address in X to the address in Y; then X and Y are incremented, C is decremented, and the next byte is moved, and so on, until the number of bytes specified by the value in C is moved (that is, until C reaches $FFFF). If C is zero, a single first byte is moved, X and Y are each incremented once, and C is decremented to $FFFF.

The MVP instruction assumes X and Y specify the top (or ending) addresses of the two blocks of memory. The first byte is moved from the address in X to the address in Y; the X, Y and C are decremented, the next byte is moved , and so on, until the number of bytes specified by the value in C is moved (until C reaches $FFFF).

The need for two distinct block move instructions becomes apparent when the problem of memory

overlap is considered. Typically, when a block of memory starting at location X is to be moved to location Y, the intention is to replace the memory locations from Y to Y + C with the identical contents of the range X through X + C. However, if these two ranges overlap, it is possible that as the processor blindly transfers memory one byte at a time, it may overwrite a value in the source range before that value has been transferred.

The rule of thumb is, when the destination range is a lower memory address than the source range, the

MVN instruction should be used (thus “Move Next”) to avoid overwriting source bytes before they have been copied to the destination. When the destination range is a higher memory location than the source range, the

MVP instruction should be used (“Move Previous”).

87

The Western Design Center

While you could conceivably move blocks with the index registers set to eight bits (your only option in emulation mode), you could only move blocks in page zero to other page zero location. For all practical purposes, you must reset the x mode flag to sixteen bits before setting up and executing a block move.

Notice that assembling an MVN or MVP instruction generates not only an opcode, but also two bytes of operand. The operand bytes specify the 64K bank from which and to which data is moved. When operating in the 65816’s sixteen-megabyte memory space, this supports the transfer of up to 64K of memory from one bank to another. In the object code, the first byte following the opcode is the bank address of the destination and the second byte is the bank address of the source.

But while this order provides microprocessor efficiency, assembler syntax has always been the more logical left to right, source to destination (TAY, for example, transfers the accumulator to the Y index register).

As a result, the recommended assembler syntax is to follow the mnemonic first with a 24-bit source address then with a 24-bit destination address - or more commonly with labels representing code or data addresses. The assembler strips the bank byte from each address (ignoring the rest) and inserts them in the correct object code sequence. (Destination bank, source bank.) For example:

440102 MVP SOURCE, DEST move from bank of source(02) to bank of dest(01)

The bank byte of the label SOURCE is 02 while the bank byte of the label DEST is 01. As always, the assembler does the work of converting the more human-friendly assembly code to the correct object code format for the processor.

If the source and destination banks are not specified, some assemblers will provide a user-specified default bank value.

The assembler will translate the opcode to object code, then supply its bank value for both of the operand bytes:

440000 MVP

If either bank is different from the default value, both must be specified.

88

The Western Design Center

7) Chapter Seven

SimpleAddressing Modes

The term addressing mode refers to the method by which the processor determines where it is to get the data needed to perform a given operation. The data used by a 65x processor may come either from memory or from one or another of the processor’s register’s. Data for certain operations may optionally come from either location, some from only one or the other. For those operations which take one of their operands from memory, there may be several ways of specifying a given memory location. The method best suited in a particular instance is a function of the overall implementation of a chosen problem-solving algorithm. Indeed, there are so many addressing modes available on the 65x processors that there is not necessarily a single

“correct” addressing mode in each situation.

This chapter deals with those addressing modes which may be described as the “simple” addressing modes. You have already seen some of these used in the examples of the previous chapter; the simple addressing modes are listed in Table 7.1. Each of these addressing modes is straightforward. Those addressing modes that require more than a simple combination of values from several memory locations or registers are described as “complex modes” in Chapter 11.

Available on all 65x processors:

immediate absolute direct page (zero page) accumulator implied stack

Example Syntax

LDA

LDA

LDA

#$12

$1234

$12

ASL

TAY

PHA

A

Available on the 65C02, 65802, and 65816 only:

direct page (zero page) indirect

Available on the 65802 and 65816 only:

LDA ($12) absolute long direct page indirect long block move

LDA

LDA

MVN

$123456

[$12]

SOURCE, DEST

Table 7-1 List of Simple Addressing Modes

In addition to solving a given problem, the processor must spend a great deal of its time simply calculating effective addresses. The simple addressing modes require little or no effective address computation, and therefore tend to be the fastest executing. However, the problem-solving and memory efficiencies of the complex addressing modes, which will be described in subsequent chapters, can make up for their effective address calculation overhead. In each case, the nature of the problem at hand determines the best addressing mode to use.

89

The Western Design Center

Immediate Addressing

Immediate data is data found embedded in the instruction stream of a program itself, immediately following the opcode which uses the data. Because it is part of the program itself, it is always a constant value, known at assembly time and specified when you create the program. Typically, small amounts of constant data are handled most efficiently by using the immediate addressing mode to load either the accumulator or an index register with specific value. Note that the immediate addressing mode is not available with any of the store instructions (STA, STX, or STY), since it makes no sense to store a value to the operand location within the code stream.

To specify the immediate addressing mode to a 65x assembler, prefix the operand with a # (pound or sharp) sign. The constant operand may be either data or an address.

For example,

A912 LDA #$12 loads the hexadecimal value $12 into the accumulator.

The 6502 and 65C02, their registers limited to only eight bits, permit only an eight-bit operand to follow the load register immediate opcodes. When the constant in an assembly source line is a sixteen-bit value, greater-than and less-than signs are used to specify whether the high- or low-order byte of the doublebyte value are to be used. A less-than indicates that the low byte is to be used, and thus:

A234 LDX #<$1234 causes the assembler to generate the LDX opcode followed by a one-byte operand, the low byte of the source operand, which is $34. It’s equivalent to:

A234 LDX #$34

The use of a greater-than sign would cause the value $12 to be loaded. If neither the less-than nor greater-than operator is specified, most assemblers will default to the low byte when confronted with a doublebyte value.

When assembling 65816 source code, the problem becomes trickier. The 6502 and 65C02 neither have nor need an instruction to set up the eight-bit mode because they are always in it. But the 65816’s accumulator may be toggled to deal with eight- or sixteen-bit quantities, as can its index registers, by setting or resetting the

m (memory/accumulator select) or x (index select) flag bits of the status register. Setting the m bit puts the accumulator in eight-bit mode; resetting it puts it in sixteen-bit mode. Setting the x bit puts the index registers in eight-bit mode; resetting it puts them in sixteen-bit mode.

The m and x flags may be set and reset many times throughout a 65816 program. But while assembly code is assembled from beginning to end, it rarely executes in that fashion. More commonly, it follows a circuitous route of execution filled with branches, jumps, and subroutine calls. Except for right after the m or x flag has been explicitly set or reset, the assembler has no way of knowing the correct value of either: your program may branch somewhere, and re-enter with either flag having either value, quite possibly an incorrect one.

While the programmer must always be aware of the proper values of these two flags, for most instructions the assembler doesn’t need to know their status in order to generate code. Most instructions generated are the same in both eight- or sixteen-bit mode. Assembling a load accumulator absolute instruction, for example, puts the same opcode value and the same absolute address into the code stream regardless of accumulator size; it is at execution time that the m bit setting makes a difference between whether the accumulator is loaded with one or two bytes from the absolute address.

But a load register immediate instruction is followed by the constant to be loaded. As Figure 7.1 shows, if the register is set to eight-bit mode at the point the instruction is encountered, the 65816 expects a one-byte constant to follow before it fetches the next opcode. On the other hand, if the register is set to sixteen-bit mode at the point the instruction is encountered , the 65816 expects a double-byte constant to follow before it fetches the next opcode. The assembler must put either a one-byte or two-byte constant operand into the code following the load register immediate opcode based on the status of a flag which it doesn’t know.

90

The Western Design Center

Immediate Addressing: 8 bit vs. 16

8-Bit Data [all processors]: Data: operand byte.

Instruction:

Opcode Data = Operand

16-Bit Data (65802/65816. native mode, applicable mode flag m or x=0)

Data High: Second operand byte

Data Low: First operand byte

Instruction:

Opcode

Data Low =

Operand Low

Data High =

Operand High

Figure 7-1 Immediate Addressing: 8 vs. 16 bits

Two assembler directives have been designed to tell the assembler which way to go: LONGA and

LONGI, each followed with the value ON or OFF. LONGA ON indicates the accumulator is in sixteen-bit mode, LONGA OFF in eight-bit mode. LONGI ON tells the assembler that the index registers are in sixteenbit mode, LOGI OFF that they are in eight-bit mode. Load register immediate instructions are assembled on the basis of the last LONGA or LONGI directive the assemble has seen - that is, the one most immediately preceding it in the source file. For example,

LONGA ON

LONGI ON

tells the assembler that both accumulator and index registers are set to sixteen bits. Now, if it next encounters the following two instructions

A93412

A05600

LDA

LDY

#$1234

#$56 then the first puts a LDA immediate opcode followed by the constant $1234 into the code, and the second a

LDY immediate opcode followed by the constant $0056, again two bytes of operand, the high byte padded with zero.

On the other hand

,

LONGA OFF

LONGI OFF tells the assembler that both accumulator and index registers are set to eight bits. Now,

A934

A056

LDA

LDY

#$1234

#$56 puts LDA immediate opcode followed by the constant $34 into code, and the second a LDY immediate opcode followed by the constant $56, each one byte of operand.

Like the flags themselves, of course, one directive may be ON and the other OFF at any time. They also do not need to both be specified at the same time.

The setting of the LONGA and LONGI directives to either ON or OFF simply represent a promise by you, the programmer, that the flags will, in fact, have these values at execution time. The directives do nothing by themselves to change the settings of the actual m and x flags; this is typically done by using the SEP and

REP instructions, explained earlier. (Note, incidentally, that these two instructions use a special form of the immediate addressing mode, where the operand is always eight bits.) Nor does setting the flags change the

91

The Western Design Center

settings of the directives. You must therefore exercise to set the LONGA and LONGI flags to correctly represent the settings of the m or x flags, and to be sure never to branch into the code with the m or x flag set differently. If, for example, the assembler generated a LDA #$1234 instruction with LONGA set ON, only to have the m accumulator flag set to eight bits when the code is executed, the processor would load the accumulator with $34, then see the $12 which follows as the next opcode and try to execute it, resulting in program failure.

Absolute Addressing

There are two categories of simple addressing modes available for accessing data in a known memory location: absolute and direct page. The first of these, absolute addressing, is used to load or store a byte to or from a fixed memory location (within the current 65K data bank on the 65816, which defaults to bank zero on power up). You specify the sixteen-bit memory location in the operand field (following the opcode) in your assembly language source line, as Figure

7.1 loads the eight-bit constant $34 into the accumulator, then stores it to memory location $B100 in the current data bank.

0000 E220

0002

0002 A934

0004 8D00B1

SEP

LONGA

LDA

STA

#%00100000

OFF

#$34

$B100 set 8-bit accumulator/memory mode tell assembler the accumulator mode load constant $34 as immediate data store byte to memory location $B100

Fragment 7.1.

The same memory move could be done with either of the index registers, as shown in Fragment 7.2

using the X register. Symbolic labels in the operand fields provide better self-documentation and easier program modification

.

0000

0000

0000

0000 E210

0002

0002 A234

0004 8E00B1

NUM1 GEQU $34

DATA GEQU $B100

SEP

LDX

STX give this data byte a symbolic label give this data byte a symbolic label

#%00010000 set index registers to 8-bit mode

LONGI OFF

#NUM1

DATA tell assembler the index mode is 8-bit load constant $34 as immediate data store byte to memory location $B100

Fragment 7.2

As you have seen, the 65816’s accumulator may be toggled to deal with either eight- or sixteen-bit quantities, as can its index registers, by setting or resetting the m or x flag bits of the status register. Naturally, you don’t need to execute a SEP or REP instructions nor a LONGA or LONGI assembler directive before every routine, provided you know the register you intend to use is already set correctly, and the assembler correctly knows that the setting. But you must always exercise extreme care when developing 65816 programs to avoid making invalid assumptions about the modes currently in force or taking unintentional branches from code in one mode to code in another.

92

The Western Design Center

Effective Address:

23

Bank

15

Data Bank (DBR)

Instruction:

Opcode Operand Low Operand High

High

7

Low

0

Figure 7-2 Absolute Addressing

As Fragment 7.3 shows, the load and store instructions above will as easily move sixteen bits of data as they did eight bits; all that’s needed is to be sure the register used is in sixteen-bit mode, and that the assembler has alerted to the setting.

0000

0000

0000 C210

0002

0002 A23412

0005 8E00B1

DATA GEQU $B100

REP

LONGI ON

LDX #1234

STX

#%00010000

DATA give this location a symbolic label reset index registers to 16-bit mode tell assembler load 16-bit constant $1234 immediate store double byte to memory loc $B100

Fragment 7.3.

As indicated, absolute addresses are sixteen-bit addresses. On the 6502, 65C02, and 65802, with memory space limited to 64K, sixteen bits can specify any fixed location within the entire address space of the processor. Therefore, the term absolute addressing was appropriate.

The 65816, on the other hand, with its segmentation into 256 possible 64K banks, requires a 24-bit address to specify any fixed location within its address space. However, the same opcodes that generate 24-bit addresses on the 65816 by concatenating the value of the data bank register with the sixteen-bit value in the operand field of the instruction. (Instructions that transfer control, to be discussed in Chapter 8, substitute the program bank register value for the data bank register value.)

Absolute addressing on the 65816 is therefore actually an offset from the base of the current bank; nevertheless, the use of the term absolute addressing has survived on the 65816 to refer to sixteen-bit fixed addresses within the current 64K data bank.

So long as the programmer needs to access only the contents of the current data bank, (sixteen-bit) absolute addressing is the best way to access data at any known location in that bank.

93

The Western Design Center

Direct Page Addressing

One of the most powerful and useful features of the 6502 and 65C02 processors is their zero page addressing modes. A page of memory on a 65x processor consists of 256 memory locations, starting at an address which is an integer multiple of $100 hexadecimal, that is, $0000, $0100, $0200, and so on. Generally, pages are numbered in hexadecimal, so their range within a 64K bank is $00 through $FF. Zero page addressing is made even more powerful and generalized as direct page addressing on the 65802 and 65816.

The zero page is the first of the 256 pages found within the 64K address space of the 6502 and 65C02 memory addresses $0000 to $00FF. These addresses may be accessed one byte cheaper than absolute memory accesses. Whereas loading or storing data from an absolute location will require three bytes of code, loading or storing a byte from a zero page location requires only two bytes, as Figure 7.3 shows.

Effective Address:

High Low

0 0 0 0 0 0 0 0

Instruction:

Opcode Operand

Figure 7-3 Zero Page Addressing.

Since all of the addresses in the zero page are less than $0100 (such as $003F, for example) it follows that, if the computer knew enough to assume two leading hexadecimal zeroes, a zero page address could be represented in only one byte, saving both space and time. But if absolute addressing is used, the processor has to assume that two bytes follow an instruction to represent the operand, regardless of whether the high-order byte is zero or not.

This concept of expressing a zero page address with a single-byte operand was implemented on the

6502 and 65C02 by reserving separate opcodes for the various instructions using zero page addressing. Since an instruction’s opcode for using zero page addressing is unique (as opcodes are for all of the different modes of a given instruction), the processor will fetch only one operand byte from the code stream, using it in effect as a displacement from a known base ($0000, in the case of the 6502 and 65C02). Since only one byte need be fetched from the instruction stream to determine the effective address, the execution time is faster by one cycle.

The result is a form of addressing that is shorter, both in memory use and execution time, than regular sixteenbit absolute addressing.

Clearly, locating your most often accessed variables in zero page memory results in considerably shorter code and faster execution time.

The limitation of having this special area of memory available to the zero page addressing mode instructions is that there are only 256 bytes of memory available for use in connection with it. That is, there are only 256 zero page addresses. Resident system programs, such as operating systems and language interprets, typically grab large chunks of page zero for their own variable space; applications programmers must carefully step around the operating system’s variables, limiting assignment of their own program’s zero page variables to some fraction of the zero page.

This problem is overcome on the 65816 by letting its direct page be set up anywhere within the first

64K of system memory (bank zero), under program control. No longer limited to page zero, it is referred to as

direct page addressing. The result is, potentially, multiple areas of 256 ($100) bytes each, which can be accessed one byte and one cycle cheaper than absolute memory. Setting the direct page anywhere is made possible by the 65816’s direct page register, which serves as the base pointer for the direct page area of

94

The Western Design Center

memory. Expressed in terms of the 65816’s direct page concept, it can be said that on the 6502 (and 65C02), the direct page is fixed in memory to be the zero page.

So 6502 and 65C02 zero page addressing opcodes become direct page opcodes on the 65802 and

65816; and when they are executed, the “zero page address” - the single byte that the processor fetches immediately after the opcode fetch - becomes instead a direct page offset. This means that instead of simply pointing to a location in the range $0000 to $00FF as it would on the 6502 and 65C02, the direct page offset is added to the sixteen-bit value in the direct page register to form the effective direct page address, which can be anywhere in the range $00;0000 to $00;FFFF.

For purposes of this chapter, however, the discussion of the direct page addressing will be limited to the default case, where the value in the direct page register is zero, making it functionally identical to the 6502 and

65C02 zero page addressing mode. Since it requires the effective address to be computed, relocation of the direct page will be considered as a form of complex addressing, and will be covered in future chapters. While

“direct page offset” is more correct, it is also more abstract; the term direct page address is most commonly used. However, it is essential to remember that it is, in fact, an offset relative to a previously established direct page value (again, as used in this chapter, $0000).

An example of the use of direct page addressing to store a constant value to memory is as follows:

A9F0

8512

LDA

STA

#$FO

$12

This stores the one-byte value $F0 at address $0012. Note that the object code generated for the store requires only one byte for the opcode and one for operand.

A9F0

8D0081

LDA

STA

#$FO

$B100

This stores the same one-byte value at the address $B100. In this case, the store requires one byte for the opcode and two bytes for the operand.

Notice how the assembler automatically assumes that if the value of the operand can be expressed in eight bits - if it is a value less than $100, whether coded as $34 or $000034 - the address is a direct page address. It therefore generates the opcode for the direct page addressing form of the instruction, and puts only a one-byte operand into the direct page address to store to is $12. One result of the assembler’s assumption that values less than $100 are direct page offsets is that physical addresses in the range $xx:0000 to $xxx:00FF cannot be referenced normally when either the bank (the “xx”) register is other than zero or the direct page register is set to other than $0000. For example, assembler syntax like:

A4FO LDY $FO or

A4FO LDY $00FO is direct page syntax. It will not access absolute address $00F0 if the direct page register holds a value other than zero; nor will it access $00F0 in another bank, even if the data bank register is set to the other bank. Both are evaluated to the same $F0 offset in the direct page. Instead, to access physical address $xx00F0, you must force absolute addressing by using the vertical bar or exclamation point in your assembler source line:

ACF000 LDY !$F0 load Y absolute (not direct page ) from $00F0

Indexing

An array is a table or list in memory of sequentially stored data items of the same type and size.

Accessing any particular item of data in an array requires that you specify both location of the base of the array and the item number within the array. Either your program or the processor must translate the item number into the byte number within the array (they are the same if the items are bytes) and add it to the base location to find the address of the item to be accessed (see Figure 7.4).

95

The Western Design Center

Sometimes an array might be a table of addresses, either of data to be accessed or of the locations of routines to be executed. In this case, the size of each item is two bytes; the first address is at locations zero and one within the array, the second at locations two and three, the third at locations four and five and so on. You must double the item number,

96

The Western Design Center

Indexing: Base plus Index

For example: Base = $2000

Index Register X = $ 03

Effective Address = $2003

0 0 1 0 0 0 0

Base = $2000

0 0 0 0 0 0 0 0 0

$2003

$2000

$2001

$2002

$2004

0 0

X = $03

0 0 0 0 1 1

Figure 7-4 Indexing

resulting in the values 0, 2, 4, . . . from the array indicates 0, 1, 2, . . . . and so on, to create an index into this array of two-byte data items.

The 65x processors provide a wide range of indexing addressing modes that provide automatic indexing capability. In all of them, a value in one of the two index registers specifies the unsigned (positive integer) index into the array, while the instruction’s operand specifies either the base of the array or a pointer to an indirect address at which the base may be found. Each addressing mode has a special operand field syntax for specifying the addressing mode to the assembler. It selects the opcode that will correctly instruct the processor where to find both the base and index.

Some early processors (the 6800, for example) had only one index register; moving data from one array to another required saving off the first index and loading the second before accessing the second array, then incrementing the second index and saving it before reloading the first index to again access the first array. The

65x processors were designed with two index registers so data can be quickly moved from an array indexed by one to a second array indexed by the other.

97

The Western Design Center

$4000

$FFFF

Correct Result

on 65816

=

$8000

Base =

$C000

“Wrapped” result on 65802

$4000

$0000

Figure 7-5 Indexing Beyond the End of the Bank

Often, the index registers are used simultaneously as indexes and as counters within loops in which consecutive memory locations are accessed.

The 65802 and 65816 index registers can optionally specify sixteen-bit offsets into an array, rather than eight-bit offsets, if the x index register select flag is clear when an indexed addressing mode is encountered.

This lets simple arrays and other structured data elements be as large as 64K.

On the 6502, 65C02, and 65802, if an index plus its base would exceed $FFFF, it wraps to continue from the beginning of the 64K bank zero; that is, when index is added to base, any carry out of the low-order sixteen bits lost. (See Figure 7.5.)

On the 65816, the same is true of direct page indexing: because the direct page is always located in bank zero, any time the direct page, plus an offset into the direct page, plus an index exceeds $FFFF, the address wraps to remain in bank zero.

But as Figure 7.5 shows, whenever a 65816 base is specified by a 24-bit (long) address, or the base is specified by sixteen bits and assumes the data bank as its bank, then, if an index plus the low-order sixteen bits of its base exceeds $FFFF, it will temporarily (just for the current instruction) increment the bank. The 65816 assumes that the array being accessed extends into the next bank.

Absolute Indexed with X and Absolute Indexed with Y Addressing

Absolute addresses can be indexed with either the X (referred to as Asolute,X addressing) or the Y

(referred to as Absolute,Y addressing) index register; but indexing with X is available to half again as many instructions as indexing with Y.

The base in these modes is specified by the operand, a sixteen-bit absolute address in the current data bank (Figure 7.6). The index is specified by the value in the X or Y register; the assembler picks the correct opcode on the basis of which index register the syntax specifies.

98

The Western Design Center

In Fragment 7.4, the X register is used to load the accumulator from $2200 plus 5, or $2205. If run on the 65816 in native mode, then if the accumulator is set to sixteen-bit mode, two bytes will be loaded from

$2205 and $2206 in the current data bank.

0000

0003

A20500

BD0022

LDX

LDA

#5

$2200,X load an index value of five load the accumulator from $2205

Fragment 7.4

If the 65816 is in native mode and the index registers are set to sixteen-bit mode, indexes greater than

$FF can be used, as Fragment 7.5 illustrates.

0000 A00501

0003 B90022

LDY

LDA

#$105

$2200,Y load an index value of $105 load the accumulator from $2305

Fragment 7.5

If the index register plus the constant base exceeds $FFFF, the result will continue beyond the end of the current 64K data bank into the next bank (the bank byte of the 24-bit address is temporarily incremented by one). So an array of any length (up to 64K bytes) can be started at any location and absolute indexed addressing will correctly index into the array, even across a bank boundary. 65802 arrays, however, wrap at the 64K boundary, since effectively there is only the single 64K bank zero.

Loading the index register with an immediate constant, as in the previous two examples, is of limited use: if, when writing a program, you know that you want the accumulator from $2305, you will generate far fewer bytes by using absolute addressing

:

AD0523 LDA $2305 load the accumulator from $2305

The usefulness of indexed addressing becomes clear when you don’t know, as you write a program, what the index into the array will be. Perhaps the program will select among indexes, or calculate one, or retrieve it from a variable, as in Fragment 7.6.

99

The Western Design Center

Effective Address:

23 15

Bank High

7

Low

0

Instructions:

Opcode Operand Low Operand High

65816 Registers:

Bank

23 15

Data Bank (DBR)

High

7

Low

0

+

Index Register x = 1 x = 0

Figure 7-6 Absolute Indexing with a Generic Index Register

0000 AE0600

0003 BD0022

0006

0006

0006

0006 0000

.

LDX INDEX get previously calculated index from memory

LDA $2200,X load the accumulator from the array, X

.

.

INDEX DS 2

Fragment 7.6.

It can be useful to be able to put the base of an array into the index register and let it vary, while keeping the index into the array constant. This is seldom possible with the eight bits of the 6502’s and 65C02’s index registers, since they limit the base addresses they can hold to the zero page, but it is a useful capability of the 65802 and 65816.

For example, suppose, as in Fragment 7.7, you’re dealing with dozens (or hundreds) of records in memory. You need to be able to update the fifth byte (which is a status field) of an arbitrary record. By loading the base address of the desired record into an index register, you can use a constant to access the status field.

The index into the array, five, is fixed; the array base varies.

Because the index is less than $100, the assembler would normally generate direct page indexing. To force the assembler to generate absolute indexing, not direct page indexing, you must use the vertical bar (or exclamation point) in front of the five, as Fragment 7.7 shows. That way, the five is generated as the doublebyte operand $0005, an absolute address to which the address in the index register is added to form the absolute effective address.

100

The Western Design Center

0000

0000

0000

0000

0000 18

0001 FB

0002

0002 C210

0004

0004

0004 E220

0006

0006

0006 AE0E00

0006 AE0E00

0009 A901

000B 9D0500

000E

000E

000E

000E

000E 0030

;

STATUS GEQU

OK GEQU

BAD GEQU

REC

5

1

0

CLC

XCE

REP

LONGI

.

.

.

DC

#$10

ON

SEP #$20

LONGA OFF

LDX

LDX

LDA

STA

REC

#OK get location of record to update load A with ok status token

!STATUS,X store to status field force absolute,X addressing a’$3000’

Fragment 7.7

set index registers to 16 bits loc of 1 st

record (in data bank)

Had the Y index register been used instead of the X in Fragment 7.7, the vertical bar would have been acceptable but not necessary; direct page, Y addressing, as you will learn in the next section, can only be used with the LDX and STX instructions, so the assembler would have been forced to use absolute,Y addressing regardless.

Both absolute,X and absolute,Y can be used by what are called the eight Group I instructions, the memory-to-accumulator instructions which can use more addressing modes than any others: LDA, STA, ADC,

SBC, CMP, AND, ORA, and EOR. In addition, absolute,X can be used for shifting data in memory, incrementing and decrementing data in memory, loading the Y register, and for other instructions; but absolute,Y has only one other use – to load the X register.

Direct Page Indexed with X and Direct Page Indexed with Y Addressing

Arrays based in the direct page (the zero page on the 6502 and 65C02) can be indexed with either the X register (called Direct Page,X addressing) or the Y register (called Direct Page,Y addressing). However, direct page,Y addressing is available only for the purpose of loading and storing the X register, while direct page,X is full-featured.

As is standard with indexed addressing modes, the index, which is specified by the index register, is added to the array base specified by the operand. Unlike the absolute indexed modes, array always starts in the direct page. So the array base, a direct page offset, can be specified with a single byte. The sum of the base and the index, a direct page offset, must be added to the value in the direct page register to find its absolute address, as shown in Figure 7.7.

In Fragment 7.8, the accumulator is loaded from a direct page offset base of $32 plus index of $10, or an offset of $42 from the direct page register’s setting

.

0000

0003

A21000 LDX #$10

B532 LDA $32,X set up an index of $10 load accumulator from dp:$42

Fragment 7.8

Remember that the effective address is an offset of $42 from the direct page register and is always in bank zero. It will correspond to an absolute address of $0042 only when the direct page register is equal to zero

101

The Western Design Center

(the default here in this chapter). Chapter 11, which covers the complex addressing modes, details relocation of the direct page.

When the index registers are set to eight bits, you can code the index and the array base interchangeably

– they are both the same size. So the index, if it is a constant, may be specified as the operand, with the array base in the index register. Using the last example, the $10 in the index register could be the direct page base of the array; the operand, $32, would then be the index into an array in the direct page which begins at the direct page offset $10.

On the 6502 and 65C02, and in they 6502 emulation modes of the two sixteen-bit processors, indexing past the end of the direct page wraps to the beginning of the direct page, as Fragment 7.9 shows. The index and the direct page array base are added, but only the low eight bits of the sum specify the direct page offset of the effective address. So in Fragment 7.9, while the base of $32 plus the index of $F0 equals $122, only the $22 is kept, and the accumulator is loaded from dp:$22

.

A2FO

B532

LDX

LDA

#$F0

$32,X set up an index of $F0 load accumulator from dp:$22

Fragment 7.9

In 65802 and 65816 native mode, however, indexes can be sixteen bits, so direct page indexing was freed of the restriction that the effective address be within the direct page. Arrays always start in the direct page, but indexing past the end of the direct page extends on through bank zero, except that it wraps when the result is greater than $FFFF to remain in bank zero (unlike absolute indexing, which temporarily allows access into the next higher bank).

23

Effective Address:

Bank

15

High

7

Low

0

Instruction:

Opcode Operand

0 0 0 0 0 0 0 0

23

65816 Registers:

Bank

15

0000 0000

High Low

7 0 +

Direct Page Register (D)

+

Index Register x = 1 x = 0

Figure 7-7 Direct Page Indexing with a Generic Index Register

In Fragment 7.10, the accumulator is loaded from the value in the direct page register plus the direct page base of $12 plus index of $FFF0, or dp:$0002. Note this is in bank zero, not bank one.

102

The Western Design Center

0000 C230

0002

0002

0002

0002

REP

LONGA

LONGI

0002 A2F0FF LDX

0005 B512 LDA

#$30

ON

ON

#$FFF0

$12,X set index and accumulator 16-bit modes load accum from $0002

Fragment 7.10

If the index registers are set to sixteen bits and the array indexes you need to use are all known constants less than $100, then you can use direct page indexing to access arrays beginning, not just in the direct page, but anywhere in bank zero memory: load the index register with the sixteen-bit base of the array and specify the index into the array as the operand constant. This technique would generally only be useful if the direct page register has its default value of zero.

Accumulator Addressing

Accumulator addressing is only available for the read-modify-write instructions such as shifts and rotates. The instructions themselves will be explained in subsequent chapters, and use of accumulator addressing with them will be reviewed in detail.

As a simple addressing mode, accumulator addressing is included in this chapter for the sake of completeness even though the instructions which use it have not yet been introduced.

Generally, most operations take place upon two operands, one of which is stored in the accumulator, the other in memory, with the result being stored in the accumulator. Read-modify-write instructions, such as the shifts and rotates, are “unary” operations; that is, they have only a single operand, which in the case of accumulator addressing, is located in the accumulator. There is no reference to external memory in the accumulator addressing modes. As usual, the result is stored in the accumulator.

The syntax for accumulator addressing, using the ASL (arithmetic shift left) instruction as an example, is:

OA ASL A

Implied Addressing

In implied addressing, the operand of the instruction is implicit in the operation code itself; when the operand is a register, it is specified in the opcode’s mnemonic. Implied operand instructions are therefore single-byte instructions consisting of opcode only, unlike instructions that reference external memory and as a result must have operands in subsequent bytes of the instruction.

You have already encountered implied addressing in the previous chapter in the form of the register transfer instructions and exchanges. Since there are a small number of registers, it is possible to dedicate an opcode to each specific registers transfer operation. Other instructions that use implied addressing are the register increments and decrements.

As one-byte instructions, there is no assembler operand field to be coded: You simply code the assembler mnemonic for the given instruction, as below:

7B

AA

9B

TDC transfer direct page register to double accumulator

TAX transfer A to X

TXY transfer X to Y

103

The Western Design Center

Stack

Stack addressing references the memory location pointed to by the stack register. Typical use of the stack addressing mode is via the push and pull instructions, which add or remove data to or from the stack area of memory and which automatically decrement or increment the stack pointer. Examples of the use of push and pull instructions were given in the previous chapter.

Additionally, the stack is used by the jump to subroutine, return from subroutine, interrupt, and return from interrupt instructions to automatically store and retrieve addresses and in some cases also the status register. This form of stack addressing will be covered in Chapter 12, Subroutines, and Chapter 13, System

Control.

The assembler syntax of the push and pull instructions is similar to that of implied instructions; no operand field is coded, since the operation will always access memory at the stack pointer location.

Direct Page Indirect Addressing

Direct page indirect addressing, or, as it is known on the 65C02, zero page indirect, is unavailable on the 6502; it was first introduced on the 65C02.

Indirect addressing was designed for the 65C02 as a simplification of two often-used complex forms of addressing available on the 6502 known as zero page indirect indexed and zero page indexed indirect addressing (these forms of addressing on the 65816 are of course direct page indirect indexed or indexed indirect addressing; they are explained in Chapter 11, Complex Addressing Modes). It was found that programmers were tolerating the overhead inherent in these two complex addressing modes to simulate indirection.

The concept of simple indirect addressing lies on the borderline between the simple and complex addressing modes. An understanding of it forms the basis for understanding several of the more complex indexed modes which use indirection as well.

An indirect address is an address stored in memory which points to the data to be accessed; it is located by means of the operand, an address which points to the indirect address, as shown in Figure 7.8.

Except in the case of indirect jump instructions, explained in Chapter 8, Flow of Control, this pointer is always a direct page address.

The use of indirect addresses brings great flexibility to the addressing options available to you. There is, however, a penalty in execution speed, imposed by the fact that, in addition to the operand fetch from the code stream, the actual effective address must also be fetched from memory before the data itself can be accessed. For this reason, direct page addresses are used as the pointers to the indirect addresses since, as you will remember from the discussion of direct page addressing, the direct page offset itself can be determined with only a single memory fetch.

The syntax for indirect addressing is to enclose in parentheses, as the operand, the direct page pointer to the indirect address.

B280 LDA ($80)

This means, as figure 7.8 illustrates, “go to the direct page address $80 and fetch the absolute (sixteen-bit) address stored there, and then load the accumulator with the data at the address.” The low-order byte of the indirect address is stored at dp:$80, the high-order byte at dp:$81 – typical 65x low/high fashion. Remember, in the default case where DP equals $0000, the direct page address equals the zero page address, namely

$00:0080.

As explained above, the indirect address stored at the direct page location (point to by the instruction operand) is a sixteen-bit address.

104

The Western Design Center

Effective Address:

23 15

Bank

7

High Low

0

Instruction:

Opcode

65816 Registers:

Bank

23 15

Data Bank (DBR)

Operand

High

7

Low

0

0000 0000 Direct Page Register (D)

+

+1

High Indirect Address

Low Indirect Address

Bank 0

Figure 7-8 Direct Page Indirect Addressing

The general rule for the 65816 is that when an addressing mode only specifies sixteen bits of the address, then the bank byte (bits 16-23) of the address is provided by the data bank register. This rule applies here; but you must first note that the direct page offset which points to the indirect address is itself always located in bank zero because the direct page itself is always located in bank zero. The examples, however, were simplified to assume both the data bank and the direct page register to by zero.

The use of indirect addressing allows an address that is referenced numerous times throughout a routine and is subject to modification – for example, a pointer to a data region – to be modified in only one location and yet alter the effective address of many instructions.

In Listing 7.1, the data $1234 is moved from location VAR1 to VAR2. Note that the load and store instructions had the same operand: the symbol DPA, which had been given a value of $80. The indirect address stored at that location was different in each case, however, resulting in the data being copied from one location to another. While this example in itself is an inefficient way to move a double-byte word to another location, it does illustrate the basic method of indirect addressing, which will become quite useful as looping and counting instructions are added to your working set of 65x instructions.

Absolute Long Addressing

This is the first of the simple addressing modes that are available only on the 65816 and 65802 processors.

Absolute long addressing is an extension of (sixteen-bit) absolute addressing – that is, addressing at a known location. Remember that on the 6502 and 65C02, address space is limited to 64K, and any location within the entire memory range can be specified with a sixteen-bit address. This is not the case with the 65816, which can address up to sixteen megabytes of memory. Thus 24 bits are required to specify a given memory location.

In general, there are two ways by which a 24-bit data address is generated. In the case of sixteen-bit absolute addressing, a 64K memory context is defined by the value of the data bank register; the bank byte of

105

The Western Design Center

the 24-bit address is derived directly from that register via simple concatenation (connecting together) of the data bank value and the sixteen-bit address. The alternative method is to specify a complete 24-bit effective address for a given instruction. The absolute long address-bit effective address for a given instruction. The absolute long addressing mode is one of the means for doing this.

As the name should imply, this addressing mode specifies a known, fixed location within the sixteenmegabyte addressing space of the 65816, just as sixteen-bit absolute addressing specifies a known, fixed location within either the 64K space of the 6502, 65C02, or 65802, or else the 64K data space determined by the 65816’s data bank register. Just as the sixteen-bit absolute addressing operations are three-byte instructions, consisting of opcode, address low, and address high, the instructions that use the 24-bit absolute long addressing modes are four-byte instructions, comprised of opcode, low byte of address, high byte of address, and bank byte of address, as shown in Figure 7.9. The value in bits 8-15 of the effective address is described as the high byte, and 16-23 as the bank byte, because this most clearly reflects both the parallels with the 6502 and 65C02 and bank-oriented memory segmentation of the

65816 architecture

.

106

The Western Design Center

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000

0008 0000

0009 0000

0010 0000

0011 0000

0012 0001

0013 0002

0014 0002

0015 0004

18

FB

C230

0016 0004

0017 0004

0018 0004

0019 0007

A01500

8480

0020 0009 8280

0021 000B A01700

0022 000E 8480

0023 0010 9280

0024 0012

0025 0012

0026 0012

0027 0012

0028 0013

0029 0014

0030 0014

0031 0015

0032 0015

0033 0017

0034 0019

0035 0019

38

FB

60

3412

0000

;

KEEP

65816

MAIN START

DPA EQU

KL.7.1

ON

$80 give memory cell at $80 a label switch from 6502 emulation to native mode

CLC

XCE clear carry flag exchange carry with e bit (clear e bit)

REP #$30

LONGA ON

LONGI ON

LDY

STY

LDA

LDY

STY

STA

#VAR1

DPA

(DPA)

#VAR2

DPA

(DPA) set 16-bit registers get the address where $1234 is stored

and store it as an indirect address at $80 now load $1234 indirectly change the indirect address DPA

to point to VAR2 and store $1234 by overwriting the $0000 there

;

VAR1

VAR2 return to 6502 emulation mode

SEC

XCE

RTS set carry flag exchange carry with e bit (set e bit)

DC

DC

END

A’$1234’

A’000’

Listing 7.1

When absolute long addressing is used, the bank address in the operand of the instruction temporarily overrides the value in the data bank register for the duration of a single instruction. Thus, it is possible to directly address any memory location within the entire sixteen-megabyte address space.

You will likely find, however, that this form of addressing is one of the less frequently used. There are two reasons for this: first, it is more efficient to use the shorter sixteen-bit addressing modes, provided that the data bank register has been appropriately set; second, it is generally undesirable to hard code fixed 24-bit addresses into an application, as this tends to make the application dependent on being run in a fixed location within a fixed bank. (An exception to this is the case where the address referenced is an I/O location, which is fixed by the given system hardware configuration.)

The 65x processors, in general, do not lend themselves to writing entirely position-independent code, although the 65816 certainly eases this task compared to the 6502 and 65C02. There is, however, no reason why code should not be written on the 65816 and 65802 to be bank-independent – that is, capable of being executed from an arbitrary memory bank. But using absolute long addressing will tend to make this difficult if not impossible.

If you are using a 65802 in an existing system, it is important to note that although the address space of the 65802 is limited to 64K at the hardware level, internally the processor still works with 24-bit addresses.

One thing this means is that it is legal to use the long addressing modes such as absolute long. But using them is futile, even wasteful: an extra address byte is required for the bank, but the bank address generated is ignored.

There are cases where use of forms of long addressing other than absolute long should be used if you are targeting your code for both the 65802 and the 65816. But generally there is little reason to use the absolute

107

The Western Design Center

long addressing mode on the 65802, except perhaps for fine-tuning a timing loop (the absolute long addressing mode requires and extra cycle to execute in order to fetch the bank address in the fourth byte of the instruction).

The assembler syntax to indicate the absolute long addressing mode is simply to code a value in the operand field greater than $FFFF. To force long addressing for bank zero addresses ($00:0000 to $00:FFFF), use the greater sign (>) as a prefix to the operand (similar to the use of the vertical bar to force sixteen-bit absolute addressing) as shown in Fragment 7.11.

23

Effective Address:

15 7 0

Bank High Low

Instruction:

Opcode Operand Low Operand High Operand Bank

Figure 7-9 Absolute Long Addressing

Note that the first STA instruction in Fragment 7.11 generates a four-byte instruction to store the accumulator to a bank zero address, while the second STA instruction generates a three-byte instruction to store the accumulator to the same sixteen-bit displacement but within bank two, the current data bank. Also note that for both the load and the first store instructions, absolute long addressing causes the current data bank register, which is set to two, to be overridden.

0000 E220

0002

0002

0002 A902

0004 48

0005 AB

0006

0006 AF9DA303

000A 8F7F2E00

000E 8D7F2E

SEP #$20

LONGA OFF

#$02 LDA

PHA

PLB

LDA

STA

STA

$03A39D

>$2E7F

$2E7F

Fragment 7.11

set 8 bit accumulator set data bank to bank two absolute long at $03:A39D store data to $00:2E7F store data to $02:2E7F

Absolute Long Indexed with X Addressing

Absolute long indexed with X, or absolute long indexed, uses the X register for its index, and an absolute long address as its base. It lets you index into an array located in a bank other than the data bank.

Instructions using absolute long indexed addressing are four bytes in length, since three bytes are needed to express 24-bit absolute-long operands. The bank byte, being the highest byte in the operand, is the fourth byte of the instruction. The contents of the X index register are added to the absolute-long operand to form the 24-bit effective address at which data will be accessed.

For example, Fragment 7.12 gets a character from a text buffer starting at $3000 in bank zero and stores it into buffers starting at $1000 in bank two and at $E000 in bank three. Because the character to be loaded is in bank zero, its long address is expressed in sixteen bits. You must preface a reference to it with the greater-than sign to override the assembler assumption that a sixteen-bit operand is in the data bank, and force the assembler to instead use long addressing. The next instruction stores to the data bank, requiring only absolute indexing; the assembler assumes simple sixteen-bit operands are located in the data bank. Finally, storing into bank three

108

The Western Design Center

requires no special specification: since $03E000 cannot be expressed in sixteen bits, long addressing is assumed.

0000 E220

0002

0002 C210

0004

0004

0004 A902

0006 AB48

0007 AB

0008

0008 AE0080

000B BF003000

000F 9D0010

0012 9F00E003

SEP #$20

LONGA OFF

REP #$10

LONGI ON

LDA

PHA

PLB

#2

LDX

LDA

STA

STA

BUFIDX

>$3000,X

$1000,X

$03E000,X

Fragment 7.12

set accumulator to 8 bits set indexes to 16 bits set the data bank to bank 2 get 16 bit buffer index force long indexed abbr:bank0 store into data bank (bank 2) store into bank 3

Direct Page Indirect Long

Direct page indirect long is another case of long (24-bit) addressing, where the effective address generated temporarily overrides the current value in the data bank register. Unlike the previous two long addressing modes, however, the 24-bit address is not contained in the operand itself. The instruction is two bytes long, much like regular direct page indirect addressing. The operand of the instruction is, like its non-long counterpart, a direct page offset acting as an indirect pointer; the difference in this case is that rather than pointing to a sixteen-bit address in the data bank, it points to a 24-bit address. If, for example, the direct page address is $80, as in Figure 7.10, the processor will fetch the low byte of the effective address from dp:$80, the high byte from dp:$81, and the bank byte from dp:$82. The bank byte temporarily overrides the value in the data bank register.

Fragment 7.13 shows the use of both direct page indirect addressing and direct page indirect long, using the latter to access the data as set up in Figure 7.10. The syntax for indirect long addressing is similar to that for direct page indirect, except left and right square brackets rather than parentheses enclose the direct page address to indicate the indirect address is long.

In this example, a sixteen-bit accumulator size is used with eight-bit index registers. The simultaneous availability of both an eight-bit and a sixteen-bit register in this mode simplifies the manipulation of long addresses. First, a value of $04 is loaded into the eight-bit Y register using immediate addressing.

Since the LONGI OFF directive has been coded, the assembler automatically generates an eight-bit operand for this instruction. This is pushed onto the stack, and then pulled into the bank register. Next, Y is loaded with

#$02, the bank component of the indirect address, which is stored to dp:$82. The sixteen-bit accumulator is then used to load an immediate $2000 (high/low of the indirect and the indirect long addresses), which is stored at dp:$80. This results in the following values in memory: at dp:$80 is $00, at dp:$81 is $20, and at dp:$82 is

$02. The data bank register contains the indirect address $2000, while the memory at locations dp:$80.81

contains the indirect address $2000, while the memory at locations dp:$80.82 contains the indirect long address

$02:2000. The load indirect instruction uses the data bank register to form the bank address, and so loads double-byte data from $04:2000. The store indirect long stores the double-byte data at $02:2000. The overlapping of the low and high bytes of the indirect address in location dp:$80 and dp:$81 highlights the difference in the source of the bank byte using the two addressing modes.

109

The Western Design Center

23

Effective Address:

15

Bank High

7

Low

0

Instruction:

Opcode

0000 0000

Operand = $80

+

2 dp:$82

+

1 dp:$81

Direct Page Register (D)

+ dp:$80

Bank Indirect Address

High Indirect Address

Low Indirect Address

Bank 0

Figure 7-10 Direct Page Indirect Long Addressing

0000 C220

0002

0002

0002 E210

0004

0004

0004 A004

0006 5A

0007 AB

0008

0008 A002

000A 8482

000C

000C A90020

000F 8580

0011

0011 B280

0013 8780

;

;

;

LDA

STA

LDA

STA

LDA

STA

REP #$20

LONGA ON

SEP #$10

LONGI OFF

#$04 LDY

PHY

PLB set accum/memory size to 16 bits set index size to eight bits set data bank to bank 4

#$02

$82 bank of indirect address

#$2000 high/low of indirect address

$80

($80)

[$80] load indirect from $04:2000 store indirect long to $02:2000

Fragment 7.13

Block Move

Block move addressing is a dedicated addressing mode, available only for two instructions, MVN and

MVP, which have no other addressing modes available to them. These operations were explained in the previous chapter

.

110

The Western Design Center

8) Chapter Eight

The Flow of Control

Flow of control refers to the way in which a processor, as it executes a program, makes its way through the various sections of code. Chapter 1 discussed four basic types of execution: straight-line, selection between paths, looping, and subroutines. This chapter deals with those instructions that cause the processor to jump or branch to other areas of code, rather than continuing the default straight-line flow of execution. Such instructions are essential to selection and looping.

The jump and branch instructions alter the default flow of control by causing the program counter to be loaded with an entirely new value. In sequential execution, on the other hand, the program counter is incremented as each byte from the code stream – opcode or operand – is fetched.

The 65x processors have a variety of branch and jump instructions, as shown in Table 8.1. Of these, when coding in the larger-than-64K environment of the 65816, only the three jumping-long instructions (jump indirect long, jump absolute long, and jump subroutine long) and the return from subroutine long instruction are capable of changing the program bank register – that is, of jumping to a segment of code in another bank. All of the other branch or jump instructions simply transfer within the current bank. In fact, the interrupt instructions (break, return from interrupt, and coprocessor instructions) are the only others which can change the program bank; there is no direct way to modify the program counter bank without at the same time modifying the program counter register because the program counter would still point to the next instruction in the old bank.

Mnemonic

BEQ

JMP

JMP

JSR

RTS

BRA

JMP

BRL

JSR

JMP

JMP

JSL

RTL

6502

x x x x x

Available on:

65C02 65802/816

x x x x x x x x x x x x x x x x x x x x

Description

branch on condition instruction

(eight) jump absolute jump indirect jump subroutine absolute return from subroutine branch always (unconditional) jump absolute indexed indirect branch long always

(unconditional, 64K range) jump to subroutine absolute indexed indirect jump indirect long (interbank) jump absolute long (interbank) jump subroutine long

(interbank) return from subroutine long

(interbank)

Table 8-1. Branch and Jump Instructions

As you many have noticed, all of the flow-of-control instructions (except the return instructions) can be divided into two categories: jump-type instructions and branch-type instructions. This division is based on addressing modes: branch instructions use program counter relative addressing modes; jump instructions don’t.

Jump instruction can be further split into two groups: those which transfer control to another section of code, irreversibly, and those which transfer control to a subroutine, a section of code which is meant to eventually return control to the original (calling) section of code, at the instruction following the jump-tosubroutine instruction.

111

The Western Design Center

The jump instructions will be covered in this chapter first, then the branches; jump-to-subroutine instructions will be discussed in Chapter 12, which deals with subroutines.

Jump Instructions

The jump inst ruction (JMP) can be used with any one of five different 65816 addressing modes (only two of these are available on the 6502, a third is available on the 65C02) to form an effective address; control then passes to that address when the processor loads the program counter with it. For example,

4C0020 JMP $2000 jump absolute to the code at location $2000 uses absolute addressing, a mode available to all 65x processors, to pass control to the code located at $2000 in the current program bank. (Notice that using absolute addressing to access data in the last chapter used the data bank in place of the program bank.)

In addition to absolute addressing, all of the 65x processors provide a jump instruction with absolute indirect addressing. While this form of indirect addressing is unique to the jump instruction, it is quite similar to the direct page indirect addressing mode described in Chapter 7. In this case, the sixteen-bit operand is the address of a double-byte variable located in bank zero containing the effective address; the effective address is loaded into the program counter. As with absolute addressing, the program bank remains unchanged (Figure

8.1).

For example, the jump instruction in Fragment 8.1 causes the processor to load the program counter with the value in the double-byte variable located at $00:2000. Unlike direct page indirect addressing, the operand is an absolute address rather than a direct page offset. Furthermore, this form of absolute addressing is unusual in that it always references a location in bank zero, not the current data bank.

0000

0000 C220

0002 A93412

0005 8F002000

0009 6C0020

LONGA ON

REP

LDA

#$20 set 16-bit accumulator

#$1234 load sixteen-bit accumulator with$1234

STA

JMP

>$2000 store long to location $00:2000

($2000) jump to location $1234 in program bank

Fragment 8.1

The 65C02 added the absolute indexed indirect addressing mode to those available to the jump instruction. This mode is discussed further in Chapter 12, The Complex Addressing Modes. Although its effective address calculation is not as simple as the jump absolute or jump absolute indirect, its result is the same: a transfer of control to a new location.

The 65802 and 65816 added long (24-bit) versions of the absolute and indirect addressing modes. The absolute long addressing mode has a three-byte operand; the first two bytes are loaded into the program counter as before, while the third byte is loaded into the program bank register, giving the jump instruction a full 24-bit absolute addressing mode. For example,

5C4423FF JMP $FF2344 causes the program counter to be loaded with $2344 and the program bank counter with $FF. Note that on that 65802, even though the bank address is effectively ignored; the jump is to the same location as the equivalent (sixteen-bit) absolute jump.

112

The Western Design Center

Program Bank (PBR)

Effective Address:

23 15

Bank High

7

Low

0

Instruction:

Opcode Operand Low Operand High

+ 1

High Indirect Address

Low Indirect Address

Bank 0

Figure 8-1 Jump’s Absolute Indirect Addressing Mode

When the target of a long jump is in bank zero, say to $00A030, then the assembler has a problem. It assumes a jump to any address between zero and $FFFF (regardless of whether it’s written as $A030 or

$00A030) is a jump within the current program bank, not to another bank, so it will generate an absolute jump, not a long jump. There are two solutions. One is to use the greater-than sign (>) in front of the operand, which forces the assembler to override its assumptions and use long addressing:

5C30A000 JMP >$A030 long jump from current program bank to $00:A030

The alternative is to use the JML alias, or alternate mnemonic, which also forces a jump to be long, even if the value of the operand is less than $10000:

5C30A000 JML $A030 jump from current bank to $00:A030

The final form of the jump instruction is a 24-bit (long) jump using absolute indirect addressing. In the instruction,

DC0020 JMP [$2000] jump to the 24-bit address stored at $00:2000 the operand is the bank zero double-byte address $2000, which locates a triple-byte value; the program counter low is loaded with the byte at $2000 and the program counter high with the byte at $2001; the program bank register is loaded with the byte at $2002. A standard assembler will allow the JML (jump long) alias here as well.

Notice that absolute indirect long jumps are differentiated from absolute indirect jumps within the same bank by using parentheses for absolute indirect jumps within the same bank by using parentheses for absolute direct and square brackets for absolute indirect long. In both cases the operand, an absolute address, points to a location in bank zero.

The jump instructions change no flags and affect no registers other than the program counter.

113

The Western Design Center

Conditional Branching

While the jump instructions provide the tools for executing a program made up of disjoined code segments or for looping, they provide no way to conditionally break out of a loop or to select between paths.

These are the jobs of the conditional branch instructions.

The jump instruction requires a minimum three bytes to transfer control anywhere in a 64K range. But selection between paths is needed so frequently and for the most part for short hops that using three bytes would tend to be unnecessarily costly in memory usage. To save memory, branches use an addressing mode called program counter relative, which requires just two bytes; the branch opcode is followed by a one-byte operand – a signed, two’s-complement offset from the current program location.

When a conditional branch instruction is encountered, the processor first tests the value of a status register flag for the condition specified by the branch opcode. If the branch condition is false, the processor ignores the branch instruction and goes on to fetch and execute the next instruction from the next sequential program location. If, on the other hand, the branch condition is true, then the processor transfers control to the effective address formed by adding the one-byte signed operand to the value currently in the program counter

(Figure 8.2).

As Chapter 1 notes, positive numbers are indicated by a zero in the high bit (bit seven), negative numbers by a one in the high bit. Branching is limited by the signed one-byte operands to 127 bytes forward or

128 bytes backward, counting from the end of the instruction. Because a new value for the program counter must be calculated if the branch is taken, an extra execution cycle is required. Further, the 6502 and 65C02

(and 65802 and 65816 in emulation mode) require an additional cycle if the branch crosses a page boundary.

The native mode 65802 and 65816 do not require the second additional cycle, because they use a sixteen-bit

(rather than eight-bit) adder to make the calculation.

The program counter value to which the operand is added is not the address of the branch instruction but rather the address of the opcode following the branch instruction. Thus, measured from the branch opcode itself, branching is limited to 129 bytes forward and 126 bytes backward. A conditional branch instruction with an operand of zero will continue with the next instruction regardless of whether the condition tested is true or false. A branch with an operand of zero is thus a two-byte no-operation instruction, with a variable (by one cycle) execution time, depending on whether the branch is or isn’t taken.

The 65x processors have eight instructions which let your programs branch based on the settings of four of the condition code flag bits in the status register: the zero flag, the carry flag, the negative flag, and the overflow flag.

None of the conditional branch instructions change any of the flags, nor do they affect any registers other than the program counter, which they affect only if the condition being tested for is true. The most recent flag value always remains valid until the next flag-modifying instruction is executed.

114

The Western Design Center

Effective Address:

23

Bank

15

High

7

Low

0

Instruction:

Opcode

65816 Registers:

Bank

23

Program Bank (PBR)

15

Operand

High sign extended to 16 bits

Low

7

Program Counter (PC)

0

+

Figure 8-2. Relative Branch Calculation

Branching Based on the Zero Flag

The zero bit in the status register indicates whether or not the result of an arithmetic, logical, load, pull, or transfer operation is zero. A zero result causes the bit to be set; a non-zero result causes the bit to be reset.

The BEQ instruction is used to branch when a result is zero – that is, when the zero bit is set. Its mnemonic meaning, that of branch if equal (to zero), describes what the processor does. Alternatively, it may be considered a mnemonic for branch if (comparison) equal because it is often used after two values are compared or subtracted; if the two values are equal, then the result of the comparison (subtraction) is zero (no difference), and the branch is taken.

The BNE instruction is used to branch when a result is not zero. Also, any non-zero value which is loaded into a register will clear the zero flag. It is a mnemonic for branch if not equal; it too is used to branch after a comparison or subtraction if the two values are not equal.

Zero is often used as a terminator, indicating the end list, or that a loop counter has counted down to the end of the loop. Fragment 8.2 is a short routine to search for the end of a linked list of records, and then insert a new element at the end. Each element in the list contains a pointer to the next element in the chain. The last element in the chain contains a zero in its link field, indicating that the end of the list has been reached.

115

The Western Design Center

0000

0000

0000 AC0080

0003

0003 A90080

0006

0006

0006 AA

0007 B500

0009 D0FB

000B

000B 98

000C 6500

000E

000E AA

000F 7400

0011

;

;

;

;

;

;

;

LOOP traverse linked list searching for end of chain

LDY

LDA

TAX

LDA

BNE

TYA

STA

TAX

STZ

NEXTNODE

#ROOT

0,x

LOOP

0,x

0,x nextnode contains address of next

data element to be inserted.

ROOT contains the address of

the link field of the first

record in the chain.

use fetched address to bet next link if not zero, use value to go to next

record store address of next record

in link field of current record now store zero to link field of

new record, which is now end

Fragment 8.2

The routine hinges on the BNE instruction found half-way through the code; until the zero element is reached. the processor continues looping through as many linked records as exist. Notice that the routine has no need to know how many elements there are or to count them as it adds a new element. Figure 8.3 pictures such a linked list.

116

The Western Design Center

Data

Link Field

$1204

$1203

$1202

$1201

$1200

X

X

X

$12

$50

$1254

$1253 -

-

$1252 -

$1251 $00

$1250 $00

End of

List

Inserted Data

New Link Field

$1254

$1253

Y

Y

$1252 Y

$1251 $13

$1250 $00

$1304

$1303

$1302

$1301

$1300

-

-

-

$00

$00

New End of List

Figure 8-3. Linked List

The two conditional branch instructions that check the zero flag are also frequently used following a subtraction or comparison to evaluate the equality or inequality of two values. Their use in arithmetic, logical, and relational expressions will be covered in more detail, with examples, in the next few chapters.

Branching Based on the Carry Flag

The carry flag in the status register is affected by addition, subtraction, and shift instructions, as well as by two implied-addressing instructions that explicitly set or clear the carry (SEC and CLC) and, on the

65802/65816, by the emulation and carry swapping XCE instruction, and the SEP and REP instructions.

The BCC instruction (branch on carry clear) is used to branch when the carry flag is a zero. The BCS instruction (branch on carry set) is used to branch when the carry flag is a one.

The carry flag bit is the only condition code flag for which there are explicit instructions both to clear and to set it. (The decimal flag, which can also be set and cleared explicitly, is a mode-setting flag; there are no instructions to branch on the status of the decimal flag.) This can come in handy on the 6502, which has no branch-always instruction (only the non-relocatable absolute jump): branch-always can be faked by setting the carry, then branching on carry set:

38

B0EB

SEC

BCS set carry bit in status register

NEWCODE always document a BCS being used as branch-always

Since the code which follows this use of the BCS instruction will never be executed due to failure of the condition test, it should be documented as acting like a branch-always instruction

.

The 6502 emulation mode of the 65802 and 65816 can be toggled on or off only by exchanging the carry bit with the emulation bit; so the only means of testing whether the processor is in emulation mode or native mode is to exchange the emulation flag with the carry flag and test the carry flag, as in Fragment 8.3.

Note that CLC, XCE, and BCS instructions themselves always behave the same regardless of mode.

117

The Western Design Center

0000

0000

0000 18

0001 FB

0002 B0FC

0004

0004

0004

0004

.

.

.

.

CLC

.

XCE

BCS shift to native mode swap previous emulation bit value into carry

EMHAND if was emulation, branch to emulation handler else processor in native mode

Fragment 8.3

Arithmetic and logical uses of branching based on the carry flag will be discussed in the next two chapters.

Branching Based on the Negative Flag

The negative flag bit in the status register indicates whether the result of arithmetic, logical, load, pull, or transfer operation is negative or positive when considered as a two’s-complement number. A negative result causes the flag to be set; a zero or positive result causes the flag to be cleared. The processor determines the sign of a result by checking to see if the high-order bit is set or not. A two’s-complement negative number will always have its high-order bit set, a positive number always has it clear.

The BMI (branch-minus) instruction is used to branch when a result is negative, or whenever a specific action needs to be taken if the high-order (sign) bit of a value is set. Execution of the BPL (branch-plus) instruction will cause a branch whenever a result is positive or zero – that is, when the high-order bit is clear.

The ease with which these instructions can check the status of the high order-bit has not been lost on hardware designers. For example, the AppleII keyboard is read by checking a specific memory location

(remember, the 65x processor use memory-mapped I/O). Like most computer I/O devices, the keyboard generates ASCII codes in response to key presses. The code returned by the keyboard only uses the low-order seven bits; this leaves the eight bit free to be used as a special flag to determine if a key has been pressed since the last time a key was retrieved. To wait for a keypress, a routine (see Fragment 8.4) loops until the high-order bit of the keyboard I/O location is set.

0000

0000

0000

0000

KEYBD

KSTRB

;

0000

0000 E230

0002

0002 AD00C0 LOOP

GEQU

GEQU

LDA

$C000

$C010 wait until a character is pressed at the keyboard

SEP #$30 eight-bit words are used for I/O

0005

0007

000A

000A

000A

10FB

8D10C0

.

.

.

BPL

STA

KEYBD

LOOP loop until high order bit is set

KSTRB got one; reset keyboard continue execution having fetched key from keyboard

000A

Fragment 8.4

The STA KSTRB instruction that follows a successful fetch is necessary to tell the hardware that a key has been read; it clears the high-order bit at the KEYBD location so that the next time the routine is called, it will again loop until the next key is pressed.

Remember that the high-order or sign bit is always bit seven on a 6502 or 65C02 or, on the 65802 and

65816, if the register loaded is set to an eight-bit mode. If a register being used an the 65802 or 65816 is set to sixteen-bit mode, however, then the high bit – the bit that affects the negative flag – is bit fifteen.

118

The Western Design Center

Branching Based on the Overflow Flag

Only four instructions affect the overflow (v) flag on the 6502 and 65C02: adding, subtracting, bittesting, and an instruction dedicated to explicitly clearing it. The 65802/65816’s SEP and REP instructions can set and clear the overflow flag as well. The next chapter will discuss the conditions under which the flag is set or cleared.

The BVS instruction is used to branch when a result sets the overflow flag. The BVC instruction is used to branch when a result clears the overflow flag.

Additionally, there is a hardware input on the 6502, 65C02, and 65802 that causes the overflow flag to be set in response to a hardware signal. This input pin is generally left unconnected in most personal computer systems. It is more likely to be useful in dedicated control applications.

Limitations of Conditional Branches

If you attempt to exceed the limits (+127 and –128) of the conditional branches by coding a target operand that is out of range, an error will result when you try to assemble it. If you should need a conditional branch with a longer reach, one solution is to use the inverse branch; if you would have used BNE, test it instead for equal to zero using BEQ. If the condition is true, target the next location past a jump to your real target. For example, Fragment 8.5 shows the end of a fairly large section of code, at the point at which it is necessary to loop back to the top (TOP) of the section if the value in location CONTROL is not equal to zero.

You would use the code like Fragment 8.5 if TOP is more than 128 bytes back.

0000 AD0080

0003 F003

0005 4C0080

0008

0008

0008

LDA

BEQ

JMP

DONE ANOP

.

.

CONTROL

DONE

TOP done processing; skip over loop back control not equal to zero; loop again go on to next phase of processing

Fragment 8.5

The price of having efficient two-byte short branches is that you must use five bytes to simulate a long conditional branch.

Many times it is possible and sensible to branch to another nearby flow of control statement and use it to puddle-jump to your final target. Sometimes you will find the branch or jump statement you need for puddle jumping already within your code because it’s not unusual for two or more segments of code to conditionally branch to the same place. This method costs you no additional code, but you should document the intermediate branch, nothing that it’s being used as a puddle-jump. Should you change it later, you won’t inadvertently alter its use by the other branch.

Each of the 65x branch instructions is based on a single status bit. Some arithmetic conditions, however, are based on more than one flag being changed. There are no branch instructions available for the relations of unsigned greater than and unsigned less than or equal to, these relations can only be determined by examining more than one flag bit. There are also no branch instructions available for signed comparisons, other than equal and not equal. How to synthesize these options is described in the following chapter.

Unconditional Branching

The 65C02 introduced the BRA branch always (or unconditional branch) instruction, to the relief of

6502 programmers; they had found that a good percentage of the jump instructions coded were for short distance within the range of a branch instruction.

Having an unconditional branch available makes creating relocatable code easier. Every program must have a starting address, or origin, specified, which tells the assembler where in memory the program will be

119

The Western Design Center

loaded. This is necessary so that the assembler will be able to generate the correct values for locations defined by labels in the source code.

Consider Fragment 8.6, the beginning of a program that specifies an origin of $2000. In order to make patching certain variables easier, they have been located right at the beginning of the program. When this program is assembled, location $2000 holds a jump instruction, and the assembler gives its operand the value of the location of BEGCODE, that is, $2005. If this program were then loaded at $2200, instead of $2000 as was

“promised” by the ORG directive, it would fail because the very first instruction executed, at $2200, would be the jump to $2005. since the program has now been loaded at $2200, the contents of $2005 are no longer as expected, and the program is in deep trouble.

By substituting an unconditional branch instruction for the jump, as in Fragment 8.7, the operand of the branch is now a relative displacement (the value two), and the branch instruction will cause two to be added to the current value of the counter program counter, whatever it may be. The result is that execution continues at

BEGCODE, the same relative location the jump instruction transferred control to in the fixed-position version.

The code is now one byte shorter. Most importantly, though, this section of the

0000

0000

0000 4C0500

0003 77

0004 88

0005

0005

0005

0005

ORG

MAIN START

JMP

DATA1

DATA2

DC

DC

BEGCODE ANOP

.

.

.

$2000

BEGCODE jump around data to beginning code

H’77’

H’88’

Fragment 8.6

program is now position-independent. If executed at $2000, the branch is located at $2000; the program counter value before the branch’s operand is added is $2002; the result of the addition is $2004, the location of

BEGCODE. Load and execute the program instead at $2200, and the branch is located at $2200; the program counter value before the branch operand is added is $2202; the result of the addition is $2204, which is the new location of BEGCODE.

0000

0000

0000 8002

0007

0007

0007

MAIN

0002 77

0003 88

DATA1

DATA2

DC

DC

0004 AD0200 BEGCODE LDA

0007 .

.

.

ORG

START

BRA

$2000

BEGCODE branch around data to beginning code

H’77’

H’88’

DATA1

Fragment 8.7

Because the operand of a branch instruction is always relative to the program counter, its effective address can only be formed by using the program counter. Programs that use branches rather than jump may be located anywhere in memory.

6502 programmers in need of relocatability get around the lack of an unconditional branch instruction by using the technique described earlier of setting a flag to a known value prior to executing a branch-on-thatcondition instruction.

Even with the unconditional branch instruction, however, relocatability can still be a problem if the need for branching extends beyond the limits imposed by its eight-bit operand. There is some help available on the 6502 and 65C02 in the form of the absolute indirect jump, which can be loaded with a target that is calculated at run time.

120

The Western Design Center

The 65802 and 65816 introduce the BRL unconditional branch long instruction. This is the only 65x branch instruction which does not take an eight-bit operand: its operand, being sixteen bits, lets it specify a target anywhere within the current 64K program bank. It is coded like any other branch, except that the target label can be outside the range of the other branches. Obviously, a two-byte displacement is generated by the assembler, making this branch a three-byte instruction. If the effective address that results when the sixteen-bit displacement is added to the current program counter would extend beyond the 64K limit of the current program bank.

The BRL instruction can replace entirely the absolute JMP instruction in a relocatable program; the price is an extra execution cycle per branch.

121

The Western Design Center

9) Chapter Nine

Built-In Arithmetic Functions

With this chapter you make your first approach to the heart of the beast: the computer as an automated calculator. Although their applications cover a broad range of functions, computers are generally associated first and foremost with their prodigious calculating abilities. Not without reason, for even in chapter oriented applications such as word processing, the computer is constantly calculating. At the level of the word processor itself, everything from instructions decoding to effective address generation is permeated by arithmetic or arithmetic-like operations. At the software implementation level, the program is constantly calculating horizontal and vertical cursor location, buffer pointer locations, indents, page numbers, and more.

But unlike dedicated machines, such as desk-top or pocket calculators, which are merely calculators, a computer is a flexible and generalized system which can be programmed and reprogrammed to perform an unlimited variety of functions. One of the keys to this ability lies in the computer’s ability to implement control structures, such as loops, and to perform comparisons and select an action based on the result. Because this chapter introduces comparison, the elements necessary to demonstrate these features are complete. The other key element, the ability to branch on condition, was presented in the previous chapter. This chapter therefore contains the first examples of these control structures, as they are implemented on the 65x processor

.

Armed with the material presented in Chapter 1 about positional notation as it applies to the binary and hexadecimal number systems, as well as the facts concerning two’s-complement binary numbers and binary arithmetic, you should posses the background required to study the arithmetic instructions available on the 65x series of processors.

Consistent with the simple design approach of the 65x family, only elementary arithmetic functions are provided, as listed in Table 9.1, leaving the rest to be synthesized in software. There are, for example, no builtin integer multiply or divide. More advanced examples presented in later chapters will show how to synthesize these more complex operations.

Mnemonic 6502

Increment Instructions:

DEC x

DEX

DEY

INC

INX

INY x x x x x

Arithmetic Instructions:

ADC

SBC x x

Available on:

65C02

x x

Compare with Memory Instructions:

CMP x x

CPX

CPY x x x x x x x x x x

65802/816

x x x x x x x x x x x

Description decrement decrement index register X decrement index register Y increment increment index register X increment index register Y add with carry subtract with borrow compare accumulator compare index register X compare index register Y

Table 9-1 Arithmetic Instructions

122

The Western Design Center

Increment and Decrement

The simplest of the 65x arithmetic instructions are increment and decrement. In the case of the 65x processors, all of the increment and decrement operations add or subtract one to a number. (Some other processors allow you to increment or decrement by one, two, or more.)

There are several reasons for having special instructions to add or subtract one to a number, but the most general explanation says it all: the number one tends to be, by far, the most frequently added number in virtually any computer application. One reason for this is that indexing is used so frequently to access multibyte data structures, such as address tables, character strings, multiple-precision numbers, and most forms of record structures. Since the items in a great percentage of such data structures are byte or double-byte wide, the index counter step value (the number of bytes from one array item to the next) is usually one or two. The 65x processors, in particular, have many addressing modes that feature indexing; that is, they use a value in one of the index registers as part of the effective address.

All 65x processors have four instructions to increment and decrement the index registers: INX, INY,

DEX, and DEY. They are single-byte implied operand instructions and either add one to, or subtract one from, the X or Y register. They execute quite quickly – in two cycles – because they access no memory and affect only a single register.

All 65x processors also have a set of instructions for incrementing and decrementing memory, the INC and DEC instructions, which operate similarly. They too are unary operations, the operand being the data stored at the effective address specified in the operand field of the instruction. There are several addressing modes available to these two instructions. Note that, unlike the register increment and decrement instructions, the INC and DEC instructions are among the slowest-executing 65x instructions. That is because they are

Read-Modify-Write operations: the number to be incremented or decremented must first be fetched from memory; then it is operated upon within the processor; and, finally, the modified value is written back to memory. Compare this with some of the more typical operations, where the result is left in the accumulator.

Although read-modify-write instructions require many cycles to execute, each is much more efficient, both byte- and cycle-wise, than the three instructions it replaces – load, modify, and store.

In Chapter 6, you saw how the load operations affected the n and z flags depending on whether the loaded number was negative (that is, had its high bit set), or was zero. The 65x arithmetic functions, including the increment and decrement operations, also set the n and z status flags to reflect the result of the operation.

In Fragment 9.1, one is added to the value in the Y register, $7FFF. The result is $8000, which, since the high-order bit is turned on, may be interpreted as a negative two’s-complement number. Therefore the n flag is set.

0000 C230

0002

0002

0002 A0FF7F

0005 C8

REP

LONGA

LONGI

LDY

INY

#$30

ON

ON

#$7FFF

16-bit registers

$7FFF is a positive number

$8000 is a negative number;n=1

Fragment 9.1

In a similar example, Fragment 9.2, the Y register is loaded with the highest possible value which can be represented in sixteen bits (all bits turned on).

0000 C230

0002

0002

0002 A0FFFF

0005 C8

REP

LONGA

LONGI

LDY

INY

#$30

ON

ON

#$FFFF z = 1 in status register

Fragment 9.2

123

The Western Design Center

If one is added to the unsigned value $FFFF, the result is $10000:

+ 1111

1 0000

1111

0000

1111

0000

1

1111

0000 one to be added binary equivalent of $FFFF result is $10000

Since there are no longer any extra bits available in the sixteen-bit register, however, the low-order sixteen bits of the number in Y (that is, zero) does not represent the actual result. As you will see later, addition and subtraction instructions use the carry flag to reflect a carry out of the register, indicating that a number larger than can be represented using the current word size (sixteen bits in the above example) has been generated. While increment and decrement instructions do not affect the carry, a zero result in the Y register after an increment (indicated by the z status flag being set) shows that a carry has been generated, even though the carry flag itself does not indicate this.

A classic example of this usage is found in Fragment 9.3, which shows the technique commonly used on the eight-bit 6502 and 65C02 to increment a sixteen-bit value in memory. Note the branch-on-condition instruction, BNE, which was introduced in the previous chapter, is being used to indicate if any overflow from the low byte requires the high byte to be incremented, too. As long as the value stored at the direct page location ABC is non-zero following the increment operation, processing continues at the location SKIP. If

ABC is zero as a result of the increment operation, a page boundary has been crossed, and the high order byte of the value must be incremented, the sixteen-bit value would “wrap around” within the low byte.

0000 EE0080

0003 D0FB

0005 EE0180

0008

0008

0008

0008

TOP

SKIP .

.

.

.

INC

BNE

INC

ABC

SKIP

ABC+1 increment low byte if no overflow, done if overflow: increment high byte, too continue

Fragment 9.3

Such use of the z flag to detect carry (or borrow) is peculiar to the increment and decrement operations: if you could increment or decrement by values other than one, this technique would not work consistently, since it would be possible to cross the “threshold” (zero) without actually “landing” on it (you might, for example, go from $FFFF to $0001 if the step value was 2).

A zero result following a decrement operation, on the other hand, indicates that the next decrement operation will cause a borrow to be generated. In Fragment 9.4, the Y register is loaded with one, and then one is subtracted from it by the DEY instruction. The result is clearly zero; however, if Y is decremented again,

$FFFF will result. If you are treating the number as a signed, two’s-complement number, this is just fine, as

$FFFF is equivalent to a sixteen-bit, negative one. But if it is an unsigned number, a borrow exists.

0000 C230

0002

0002

0002 A00100

0005 88

REP

LONGA

LONGI

LDY

DEY

#$30

ON

ON

#$0001

16-bit registers z = 0 in the status register z = 1 in the status register

Fragment 9.4

Together with the branch-on-condition instructions introduced in the previous chapter, you can now efficiently implement one of the most commonly used control structures in computer programming,, the

program loop.

A rudimentary loop would be a zero-fill loop; that is, a piece of code to fill a range of memory with zeroes. Suppose, as in Listing 9.1, the memory area from $4000 to $5FFF was to be zeroed (for example, to clear hi-res page two graphics memory in the AppleII). By loading an index register with the size of the area to be cleared, the memory can be easily accessed by indexing from an absolute base of $4000.

124

The Western Design Center

The two lines at BASE and COUNT assign symbolic names to the starting address and length of the fill area. The REP instruction puts the processor into the long index/long accumulator mode. The long index allows the range of memory being zeroed to be greater than 256 bytes; the long accumulator provides for faster zeroing of memory, by clearing two bytes with a single instruction.

The loop is initialized by loading the X register with the value COUNT, which is the number of bytes to be zeroed. The assembler is instructed to subtract two from the total to allow for the fact that the array starts at zero, rather than one, and for the fact that two bytes are cleared at a time.

125

The Western Design Center

0024

0025

0026

0027

0028

0029

0030

0016

0017

0018

0019

0020

0021

0022

0023

0007

0008

0009

0010

0011

0012

0013

0014

0015

0001

0002

0003

0004

0005

0006

0000

0000

0000

0000

0000

0000 18

0001 FB

0002

0002

0002

0002

0002

0002 C230

0004

0004

L91

BASE

COUNT GEQU

0004

0004

0004 A2FE1F

0007

0007

;

0007 9E0040 LOOP

000A CA

000B CA

000C 10F9

000E

000E 38

000F FB

0010 60

0011

0011

DONE

KEEP

65816

START

CLC

XCE

GEQU

REP

LONGA

LONGI

LDX

STZ

DEX

DEX

BPL

SEC

XCE

RTS

END

KL.9.1

ON

$4000

$2000

#$30

ON

ON

#COUNT-2

BASE,X

LOOP starting address of fill area number of bytes to clear turn 16-bit modes on get the number of bytes to clear into x minus two store zero to memory repeat loop again if not done

Listing 9.1

The loop itself is then entered for the first time, and the STZ instruction is used to clear the memory location formed by adding the index register to the constant BASE. Next come two decrement instructions; two are needed because the STZ instruction stored a double-byte zero. By starting at the end of the memory range and indexing down, it is possible to use a single register for both address generation and loop control. A simple comparison, checking to see that the index register is still positive, is all that is needed to control the loop.

Another concrete example of a program loop is provided in Listing 9.2, which toggles the built-in speaker in an AppleII computer with increasing frequency, resulting in a tone of increasing pitch. It features an outer driving loop (TOP), an inner loop that produces a tone of a given pitch, and an inner-most delay loop.

The pitch of the tone can be varied by using different initial values for the loop indices.

126

The Western Design Center

0001 0000

0002 0000

0003 0000

0004

0005

0006

0000

0000

0001

18

FB

L92

KEEP

65816

0007 0002 E230

0008 0004

0009 0004

0010 0004

0011 0004

0012 0004 A200

0013 0006 8A

0014 0007

0015 0007 9B

0019 000B 8A

0020 000C

0021 000C 3A

0022 000D D0FD

0023 000F

BELL

TOP TXY

0016 0008

0017 0008 8D30C0 LOOP STA

0018 000B

TXA

DELAY

LDX

TXA

DEC

BNE

KL.9.2

ON

START

CLC

XCE

SEP #$30

LONGA OFF

LONGI OFF

GEQU $C030

#0

BELL

A

DELAY

0024 000F

0025 000F 88

0026 0010 D0F6

0027 0012

0028 0012 CA

0029 0013 D0F2

0030 0015

0031 0015 38

0032 0016 FB

0033 0017 60

0034 0018

DEY

BNE

DEX

BNE

SEC

XCE

RTS

END

LOOP

TOP

Listing 9.2

set 8-bit mode

X, now in A, initializes the delay loop initialize X & Y to 0 accessing the tone generator pulses it diminishing delay loop loop 256 times before continuing

Addition and Subtraction: Unsigned Arithmetic

The 65x processors have only two dedicated general purpose arithmetic instructions: add with carry,

ADC, and subtract with carry, SBC. As will be seen later, it is possible to synthesize all other arithmetic functions using these and other 65x instructions.

As the names of these instructions indicate, the carry flag from the status register is involved with the two operations. The role of the carry flag is to “link” the individual additions and subtractions that make up multiple-precision arithmetic operations. The earlier example of the 6502 sixteen-bit increment was a special case of the multiple-precision arithmetic technique used on the 65x processors, the link provided in that case by the BNE instruction.

Consider the addition of two decimal numbers, 56 and 72. You begin your calculation by adding six to two. If you are working the calculation out on paper, you place the result, eight, in the right-most column, the one’s place:

56

72

8

127

The Western Design Center

Next you add the ten’s column; 5 plus 7 equals 12. The two is placed in the tens place of the sum, and the one is a carry into the 100’s place. Normally, since you have plenty of room on your worksheet, you simply pencil in the one to the left of the two, and you have the answer.

The situation within the processor when it adds two numbers is basically similar, but with a few differences. First, the numbers added and subtracted in a 65x processor are normally binary numbers (although there is also a special on-the-fly decimal adjust mode for adding and subtracting numbers in binary-coded decimal format). Just as you began adding, the processor starts in the right-most column, or one’s place, and continues adding columns to the left. The augend (the number added to) is always in the accumulator; the location of the addend is specified in the operand field of the instruction. Since a binary digit can only be a zero or a one, the addition of 2 ones results in a zero in the current column and a carry into the next column. This process of addition continues until the highest bit of the accumulator has been added (the highest bit being either bit seven or, alternatively on the 65802 / 65816, bit fifteen, if the m flag is cleared). But suppose that $82 is added to $AB in the eight-bit accumulator:

1

1000

+ 1010

0010

1

0010

1011

1101 carry digits from previous addition to right binary equivalent of $82 binary equivalent of $AB

If you begin by adding the binary digits from the right and marking the sum in the proper column, and then placing any carry that results at the top of the next column to the left, you will find that a carry results when the ones in column seven are added together. However, since the accumulator is only eight bits wide, there is no place to store this value; the result has “overflowed” the space allocated to it. In this case, the final carry is stored in the carry flag after the operation. If there had been no carry, the carry flag would be reset to zero.

The automatic generation of a carry flag at the end of an addition is complemented by a second feature of this instruction that is executed at the beginning of the instruction: the ADC instruction itself always adds the previously generated one-bit carry flag value with the right-most column of binary digits. Therefore, it is always necessary to explicitly clear the carry flag before adding two numbers together, unless the numbers being added are succeeding words of a multi-word arithmetic operation. By adding in a previous value held in the carry flag, and storing a resulting carry there, it is possible to chain together several limited-precision (each only eight or sixteen bits) arithmetic operations

.

First, consider how you would represent an unsigned binary number greater than $FFFF (decimal

65,536) – that is, one that cannot be stored in a single double-byte cell. Suppose the number is $023A8EF1.

This would simply be stored in memory in four successive bytes, from low to high order, as follows, beginning at $1000:

1000 F1

1001 8E

1002 3A

1003 02

Since the number is greater than the largest available word size of the processor (double byte), any arithmetic operations performed on this number will have to be treated as multiple-precision operations, where only one part of a number is added to the corresponding part of another number at a time. As each part is added, and so on, until all of the parts of the number have been added.

Multiple-precision operations always proceed from low-order part to high-order part because the carry is generated from low to high, as seen in our original addition of decimal 56 to 72.

Listing 9.3 is an assembly language example of the addition of multi-precision numbers $023A8EF1 to

$0000A2C1. This example begins by setting the accumulator word size to sixteen bits, which lets you process half of the four-byte addition in a single operation. The carry flag is then cleared because there must be no initial carry when an add operation begins. The two bytes stored at BIGNUM and BIGNUM+1 are loaded into the double-byte accumulator. Note that the DC 14 assembler directive automatically stores the four-byte integer constant value in memory in low-to-high order. The ADC instruction is then executed, adding $8EF1 to

$A2C1.

128

The Western Design Center

0001 0000

0002 0000

0003 0000

0004

0005

0006

0007 0002 S220

0008 0004

0009 0004 18

0010 0005 AD1A00

0011 0008 6D1E00

0012 000B 8D2200

0013 000E AD1C00

0014 0011 6D2000

0015

0000

0000

0001

0014

18

FB

8D2400

L93

KEEP

65816

0016 0017 38

0017 0018 FB

0018 0019 60

SEC

XCE

RTS

0019 001A F18E3A02 BIGNUM DC

0020 001E C1A20000 NEXTNUM DC

0021 0022 00000000 RESULT

0022 0026

DS

END

KL.9.3

ON

START

CLC

XCE

REP #$20

LONGA ON

CLC

LDA BIGNUM

ADC

STA

LDA

ADC

STA use sixteen-bit accumulator make sure carry is clear to start load low-order two bytes

NEXTNUM

RESULT add to low-order two bytes of NEXTNUM save low-order result

BIGNUM+2 now load high-order two bytes

NEXTNUM+2 add to high order of NEXTNUM with carry

RESULT+2 save result

I4’$023A8EF1’

I4’$0000A2C1’

4

Listing 9.3

Examine the equivalent binary addition:

1 1 11 1 1 1

1000 1110 1111 0001

1010 0010 1100 0001

0011 0001 1011 0010 carry from addition of column to right

$8EF1

$A2C1

$31B2

The sixteen-bit result found in the accumulator after the ADC is executed is $31B2; however, this is clearly incorrect. The correct answer, $13B2, requires seventeen bits to represent it, so an additional result of the ADC operation in this case is that the carry flag in the status register is set. Meanwhile, since the value in the accumulator consists of the correct low-order sixteen bits, the accumulator is stored at RESULT and

RESULT+1.

With the partial sum of the last operation saved, the high-order sixteen bits of BIGNUM are loaded

(from BIGNUM+2) into the accumulator, followed immediately by the ADC NEXTNUM + 2 instruction, which is not preceded by CLC this time. For all but the first addition of a multiple-precision operation, the carry flag is not cleared; rather, the setting of the carry flag from the previous addition is allowed to be automatically added into the next addition. You will note in the present example that the high-order sixteen bits of NEXTNUM are zero; it almost seems unnecessary to add them. At the same time, remember that there was a carry left over from the first addition; when the ADC NEXTNUM + 2 instruction is executed, this carry is automatically added in; that is, the resulting value in the accumulator is equal to the carry flag (1) plus the original value in the accumulator ($023A) plus the value at the address NEXTNUM + 2 ($0000), or $023B.

This is then stored in the high-order bytes of RESULT, which leaves the complete, correct value stored in locations RESULT through RESULT + 3 in low-high order:

RESULT

-

B2

RESULT + 1 31

RESULT + 2 3B

RESULT + 3 02

Reading from high to low, the sum is $023B31B2.

This type of multiple precision addition is required constantly on the eight-bit 6502 and 65C02 processors in order to manipulate addresses, which are sixteen-bit quantities. Since the 65816 and 65802 provide sixteen-bit arithmetic operations when the m flag is cleared, this burden is greatly reduced. If you wish,

129

The Western Design Center

however, to manipulate long addresses on the 65816, that is , 24-bit addresses, you will similarly have to resort to multiple precision. Otherwise, it is likely that multiple-precision arithmetic generally will only be required on the 65802 or 65816 in math routines to perform number-crunching on user data, rather than for internal address manipulation.

An interesting footnote to the multiple-precision arithmetic comparison between the 6502 and the

65816 is to observe that since the 6502 only has an eight-bit adder, even those instructions that automatically perform sixteen-bit arithmetic (such as branch calculation and affective address generation) require an additional cycle to perform the addition of the high-order byte of the address. The presence of a sixteen-bit adder within the 65802 and 65816 explains how it is able to shave cycles off certain operations while in native mode, such as branching across page boundaries, where an eight-bit quantity is added to a sixteen-bit value. On the 6502, if a page boundary isn’t crossed, the high byte of the sixteen-bit operand is used as-is; if a carry is generated by adding the two low bytes, a second eight-bit add must be performed, requiring an additional machine cycle. On the 65816, the addition is treated as a single operation.

Subtraction on the 65x processors is analogous to addition, with the borrow serving a similar role in handling multiple-precision subtractions. On the 65x processors, the carry flag is also used to store a subtraction’s borrow. In the case of the addition operation, a one stored in the carry flag indicates that a carry exists, and the value in the carry flag will be added into the next add operation. The borrow stored in the carry flag is actually an inverted borrow: that is, the carry flag cleared to zero means that there is a borrow, while carry set means that there is none. Thus prior to beginning a subtraction, the carry flag should be set so that no borrow is subtracted by the SBC instruction.

Although you can simply accept this rule at face value, the explanation is interesting, The simple way to understand the inverted borrow of the 65x series is to realize that, like most computers, a 65x processor has no separate subtraction circuits as such; all it has is an adder, which serves for both addition and subtraction.

Obviously, addition of a negative number is the same as subtraction of a positive. To subtract a number, then, the value which is being subtracted is inverted, yielding a one’s-complement negative number. This is then added to the other value and, as is usual with addition on the 65x machines, the carry is added in as well.

Since the add operation automatically adds in the carry, if the carry is set prior to subtraction, this simply converts the inverted value to two’s complement form. (Remember, two’s complement is formed by inverting a number and adding one; in this case the added one is the carry flag.) If, on the other hand, the carry was clear, this has the effect of subtracting one by creating a two’s-complement number which is one greater than if the carry had been presented. (Assuming a negative number is being formed, remember that the more negative a number is, the greater its value as an unsigned number, for example, $FFFF = -1, $8000 = -32767.)

Thus, if a borrow exists, a value which is more negative by one is created, which is added to the other operand, effectively subtracting a carry.

Comparison

The comparison operation – is VALUE1 equal to VALUE2, for example – is implemented on the 65x, as on most processors, as an implied subtraction. In order to compare VALUE1 to VALUE2, one of the values is subtracted from the other. Clearly, if the result is zero, then the numbers are equal.

This kind of comparison can be made using the instructions you already know, as Fragment 9.5

illustrates. In this fragment, you can see that the branch to TRUE will be taken, and the INC VAL instruction never executed, because $1234 minus 1234 equals zero. Since the results of subtractions condition the z flag, the BEQ instruction (which literally means “branch if result equal to zero”), in this case, means “branch if the compared values are equal.”

130

The Western Design Center

0000 C230

0002

0002

0002

0002 9C1200

0005 A93412

0008 38

0009 E93412

000C F003

000E EE1200

0011 60

0012 0000

REP

LONGA ON

LONGI

STZ

LDA

SEC

SBC

BEQ

INC

TRUE RTS

VAL DS

#$30

ON

VAL

#$1234 get one value

#$1234

TRUE

VAL

2

16-bit registers clear double-byte at VAL subtract another if they are the same, leave VAL zero if they are different, set VAL

Fragment 9.5

There are two undesirable aspects of this technique, however, if comparison is all that is desired rather than actual subtraction. First, because the 65x subtraction instruction expects the carry flag to be set for single precision subtractions, the SBC instruction must be executed before each comparison using SBC. Second, it is not always desirable to have the original value in the accumulator lost when the result of the subtraction is stored there.

Because comparison is such a common programming operation, there is a separate compare instruction,

CMP. Compare subtracts the value specified in the operand field of the instruction from the value in the accumulator without storing the result; the original accumulator value remains intact. Status flags normally affected by a subtraction – z, n, and c – are set to reflect the result of the subtraction just performed.

Additionally, the carry flag is automatically set before the instruction is executed, as it should be for a singleprecision subtraction. (Unlike the ADC and SBC instructions, CMP does not set the overflow flag, complicating signed comparisons somewhat, a problem which will be covered later in this chapter.)

Given the flags that are set by the CMP instruction, and the set of branch-on-condition instructions, the relations shown in Table 9.2 can be easily tested for. A represents the value in the accumulator, DATA is the value specified in the operand field of the instruction, and Bxx is the branch-on-condition instruction that causes a branch to be taken (to the code labelled TRUE) if the indicated relationship is true after a comparison

.

Because the action taken after a comparison by the BCC and BCS is not immediately obvious from their mnemonic names, the recommended assembler syntax standard allows the alternate mnemonics BLT, for

“branch on less than,” and BGE, for

BEQ

BNE

BCC

BCS

TRUE

TRUE

TRUE

TRUE branch if A = DATA branch if A < > DATA branch if A < DATA branch if A > = DATA

Table 9-2. Equalities

“ branch if greater of equal,” respectively, which generate the identical object code.

Other comparisons can be synthesized using combinations of branch-on-condition instructions.

Fragment 9.6 shows how the operation “branch on greater than” can be synthesized.

branch to TRUE if

A > DATA

0000 F002

0002 B0FC

0004

BEQ

BGE

SKIP ANOP

Fragment 9.6

Fragment 9.7 shows “branch on less or equal.”

SKIP

TRUE

131

The Western Design Center

0000 F0FE

0002 90FC

BEQ

BCC

TRUE

TRUE branch if

A <= DATA

Fragment 9.7

Listing 9.4 features the use of the compare instruction to count the number of elements in a list which are less than, equal to, and greater than a given value. While of little utility by itself, this type of comparison operation is just a few steps away from a simple sort routine. The value the list will be compared against is assumed to be stored in memory locations $88.89, which are given the symbolic name VALUE in the example.

The list, called TABLE, uses the DC I directive, which stores each number as a sixteen-bit integer.

132

The Western Design Center

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000

0008 0000

0009 0000

0010 0000

0011 0000

0012 0000

0013 0000 18

0014 0001 FB

0015 0002 C230

0016 0004

0017 0004

0018 0004

0019 0004

0020 0004

0021 0004 6482

0022 0006 6484

0023 0008 6486

0024 000A

0025 000A

0026 000A A588

0027 000C A01A00

0028 000F

0029 000F

0030 000F D92700

0031 0012 F006

0032 0014 9008

0033 0016 E682

0034 0018 8006

0035 001A E684

0036 001C 8002

0037 001E E686

0038 0020

0039 0020 88

0040 0021 88

0041 0022 10EB

0042 0024

0043 0024

0044 0024 38

0045 0025 FB

0046 0026 60

0047 0027

0048 0027 0C00009000

0049 0035 04116300

0050 0041 0F27

0051 0043

0052 0043

;

L94

LESS

SAME

MORE

VALUE GEQU

TOP CMP

BEQ

BLT

INC

BRA

ISEQ INC

BRA

ISMORE INC

LOOP

LAST

KEEP

65816

START

GEQU

GEQU

GEQU

CLC

XCE

REP

LONGA

LONGI

STZ

STZ

STZ

LDA

LDY

DEY

DEY

BPL

SEC

XCE

RTS

DC

DC

DC

END

KL.9.4

ON

$82

$84

$86

$88

#$30

ON

ON

LESS

SAME

MORE

VALUE

#LAST-TABLE

TABLE,Y

ISEQ

ISMORE

LESS

LOOP

SAME

LOOP

MORE

TOP counter counter counter value for list to be compared against turn on both 16-bit modes zero the counters get the comparison value get a counter to # of list items compare accum to first list item

VALUE is less, bump LESS value is same; bump SAME

VALUE is greater; bump MORE move pointer to next list item continue if there are any list items left to compare

I’12,9,302,956,123,1234,98’

I’4356,99,11,40000,23145,562’

I’9999”

Listing 9.4.

After setting the mode to sixteen-bit word/index size, the locations that will hold the number of occurrences of each of the three possible relationships are zeroed. The length of the list is loaded into the Y register. The accumulator is loaded with the comparison value.

The loop itself is entered, with a comparison to the first item in the list; in this and each succeeding case, control is transferred to counter-incrementing code depending on the relationship that exists. Note that equality and less-than are tested first, and greater-than is assumed if control falls through. This is necessary since there is no branch on greater-than (only branch on greater-than-or-equal). Following the incrementing of the selected relation-counter, control passes either via an unconditional branch, or by falling through, to the loop-control code, which decrements Y twice (since double-byte integers are being compared). Control

133

The Western Design Center

resumes at the top of the loop unless all of the elements have been compared, at which point Y is negative, and the routine ends.

In addition to comparing the accumulator with memory, there are instructions for comparing the values in the two index registers with memory, CPX and CPY. These instructions come in especially handy when it is not convenient or possible to decrement an index to zero – if instead you must increment or decrement it until a particular value is reached. The appropriate compare index register instruction is inserted before the branch-oncondition instruction either loops or breaks out of the loop. Fragment 9.8 shows a loop that continues until the value in X reaches $A0.

0000

0000

0000

0000

0000 E8

0001 E0A000

0004 D0FA

0006

LOOP

.

.

.

ANOP

INX

CPX

BNE

ANOP

#$A0

LOOP work to be done in the loop goes here continue incrementing X until

X = $A0, so loop ended

Fragment 9.8

Signed Arithmetic

The examples so far have dealt with unsigned arithmetic – that is, addition and subtraction of binary numbers of the same sign. What about signed numbers?

As you saw in Chapter 1, signed numbers can be represented using two’s-complement notation. The two’s complement of a number is formed by inverting it (one bits become zeroes, zeroes become ones) and then adding one. For example, a negative one is represented by forming the two’s complement of one

:

0000 0000 0000 0001

1111 1111 1111 1110

0000 0000 0000 0001

1111 1111 1111 1111

-binary one in sixteen-bit word

-complement word

-add one to complement

-result is two’s-complement

representation of minus one

Minus one is therefore equivalent to a hexadecimal $FFFF. But as far as the processor is concerned, the unsigned value $FFFF (65,535 decimal) and the signed value minus-one are equivalent. They both amount to the same stream of bits stored in a register. It’s the interpretation of them given by the programmer which is significant – an interpretation that must be consistently applied across each of the steps that perform a multi-step function.

Consider all of the possible signed and unsigned numbers that can be represented using a sixteen-bit register. The two’s complement of $0002 is $FFFE – as the positive numbers increase, the two’s-complement

(negative) numbers decrease (in the unsigned sense). Increasing the positive value to $7FFF (%0111 1111 1111

1111), the two’s complement is $8001 (%1000 0000 0000 0001); except for $8000, all of the possible values have been used to represent the respective positive and negative numbers between $0001 and $7FFF.

Since their point of intersection, $8000, determines the maximum range of a signed number, the highorder bit (bit fifteen will always be one if the number is negative, and zero if the number is positive. Thus the range of possible binary values (%0000 0000 0000 0000 through %1111 1111 1111 1111, or $0000 . . $FFFF), using two’s-complement form, is divided evenly between representations of positive numbers, and representations of the corresponding range of negative numbers. Since $8000 is also negative, there seems to be one more possible negative number than positive; for the purpose here, however, zero is considered positive.

The high-order bit is therefore referred to as the sign bit. On the 6502, with its eight-bit word size (or the 65816 in an eight-bit register mode), bit seven is the sign bit. With sixteen-bit registers, bit fifteen is the sign bit. The n or negative flag in the status register reflects whether or not the high-order bit of a given register is set or clear after execution of operations which affect that register, allowing easy determination of the sign of a signed number by using either the BPL (branch on plus) or BMI (branch if minus) instructions introduced in the last chapter.

134

The Western Design Center

Using the high-order bit as the sign bit sacrifices the carry flag’s normal (unsigned) function. If the high-order bit is used to represent the sign, then the addition or subtraction of the sign bits (plus a possible carry out of the next-to-highest bit) results in a sign bit that may be invalid and that will erroneously affect the carry flag.

To deal with this situation, the status register provides another flag bit, the v or overflow flag, which is set or rest as the result of the ADC and SBC operations. The overflow bit indicates whether a signed result is too large (or too small) to be represented in the precision available, just as the carry flag does for unsigned arithmetic.

Since the high-order bit is used to store the sign, the penultimate bit (the next highest bit) is the highorder bit as far as magnitude representation is concerned. If you knew if there was a carry out of this bit, it would obviously be helpful in determining overflow or underflow.

However, the overflow flag is not simply the carry out bit six (if m = 1 for eight-bit mode) or bit fourteen (if m = 0 for sixteen-bit mode). Signed generation of the v flag is not as straightforward as unsigned generation of the carry flag. It is not automatically true that if there is a carry out of the penultimate bits that overflow has occurred, because it could also mean that the sign has changed. This is because of the circular or wraparound nature of two’s-complement representation.

Consider Fragment 9.9. Decimal values with sign prefixes are used for emphasis (and convenience) as the immediate operands in the source program; their hexadecimal values appear in the left-hand column which interlists the generated object code (opcode first, low byte, high byte). You can see that –10 is equivalent to

$FFF6 hexadecimal, while 20 is hexadecimal $0014. Examine this addition operation in binary:

0000 C230

0002

0002

0002

0002 A9F6FF

0005 18

0006 691400

REP #$30

LONGA ON

LONGI ON

LDA

CLC

ADC

#-10

#20

16-bit registers

Fragment 9.9

Two things should become clear: that the magnitude of the result (10 decimal) is such that it will easily fit within the number of bits available for its representation, and that there is a carry out of bit fourteen:

1 1111 1111

1111 1111

0000 0000

1 0000 0000

111

1111

0001

0000

1 carry from previous bit

0110 -10 decimal

0100 +20 decimal

1010 result is +10 decimal

In this case, the overflow flag is not set, because the carry out of the penultimate bit indicates wraparound rather than overflow (or underflow). Whenever the two operands are different signs, carry out of the next-tohighest bit indicates wraparound; the addition of a positive and a negative number (or vice versa) can result in a number too large (try it), but it may result in wraparound.

Conversely, overflow exists in the addition of two negative numbers if no carry results from the addition of the next-to-highest (penultimate) bits. If two negative numbers are added without overflow, they will always wrap around, resulting in a carry out of the next-to-highest bit. When wraparound has occurred, the sign bit is set due to the carry out of the penultimate bit. In the case of the two negative numbers being added

(which always produces a negative result), this setting of the sign bit results in the correct sign. In the case of the addition of two positive numbers, wraparound never occurs, so a carry out of the penultimate bit always means that the overflow flag will be set.

These rules likewise apply for subtraction; however, you must consider that subtraction is really an addition with the sign of the addend inverted, and apply them in this sense.

In order for the processor to determine the correct overflow flag value, it exclusive-or’s the carry out of the penultimate bit with the carry out of the high-order bit (the value that winds up in the carry flag), and sets or

135

The Western Design Center

resets the overflow according to the result. By taking the exclusive-or of these two values, the overflow flag is set according to the rules above.

Consider the possible results:

If both values are positive, the carry will be clear; if there is no penultimate carry, the overflow flag, too, will be clear, because 0 XOR 0 equals 0; the value in the sign bit is zero, which is correct because a positive number plus a positive number always equals a positive number. On the other hand, if there is a penultimate carry, the sign bit will change. While there is still no final carry, overflow is set. The final carry (clear) xor penultimate carry (set) equals one. Whenever overflow is set, the sign bit of the result has the wrong value.

If the signs are different, and there is a penultimate carry (which means wraparound in this case), there will be a final carry. But when this is exlusive-or’d with the penultimate carry, it is canceled out, resulting in overflow being cleared. If, though, there were no penultimate carry, there would be no final carry; again, 0 XOR 0 = 0, or overflow clear. If the sign bit is cleared by the addition of a penultimate carry and the single negative sign bit, since wraparound in this case implies the translation from a negative to a positive number, the sign (clear) is correct. If there was no wraparound, the result is negative, and the sign bit is also correct (set).

Finally, if both signs are negative, there will always be a carry out of the sign bit. A carry out of the penultimate bit means wraparound (with a correctly negative result), so carry (set) XOR penultimate carry (set) equals zero and the overflow flag is clear. If, however, there is no carry, overflow (or rather, underflow) has occurred, and the overflow is set because XOR no carry equals one.

The net result of this analysis is that, with the exception of overflow detection, signed arithmetic is performed in the same way as unsigned arithmetic. Multiple-precision signed arithmetic is also done in the same way as unsigned multiple-precision arithmetic; the sign of the two numbers is only significant when the high-order word is added.

When overflow is detected, it can be handled in three ways: treated as an error, and reported; ignored; or responded to by attempting to extend the precision of the result. Although this latter case is not generally practical, you must remember that, in this case, the value in the sign bit will have been inverted. Having determined the correct sign, the precision may be expanded using sign extension, if there is an extra byte of storage available and your arithmetic routines can work with a higher-precision variable. The method for extending the sign of a number involves the bit manipulation instructions described in the next chapter; an example of it is found there.

Signed Comparisons

The principle of signed comparisons is similar to that of unsigned comparisons: the relation of one operand to another is determined by subtracting one from the other. However, the 65x CMP instruction, unlike

SBC, does not affect the v flag, so does not reflect signed overflow/underflow. Therefore, signed comparisons must be performed using the SBC instruction. This means that the carry flag must be set prior to the comparison (subtraction), and that the original value in the accumulator will be replaced by the difference.

Although the value of the difference is not relevant to the comparison operation, the sign is. If the sign of the result (now in the accumulator) is positive (as determined according to rules outlined above for proper determination of the sign of the result of a signed operation), then the value in memory is less than the original value in the accumulator; if the sign is negative, it is greater. If, though, the result of the subtraction is zero, then the values were equal, so this should be checked for first.

The code for signed comparisons is similar to that for signed subtraction. Since a correct result need not be completely formed, however, overflow can be tolerated since the goal of the subtraction is not to generate a result that can be represented in a given precision, but only to determine the relationship of one value to another. Overflow must still be taken into account in correctly determining the sign. The value of the sign bit (the high-order bit) will be the correct sign of the result unless overflow has occurred. In that case, it is the inverted sign.

Listing 9.5 does a signed comparison of the number stored in VAL1 with the number stored in VAL2, and sets RELATION to minus one, zero, or one, depending on whether VAL1 < VAL2, VAL1 = VAL2 or

VAL1 > VAL2, respectively:

136

The Western Design Center

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000 18

COMPARE

KEEP

65816

START

KL.9.5

ON

0007 0001 FB

0008 0002 C230

0009 0004

0010 0004

0011 0004

0012 0004

0013

0014

0015

0004

0007

000A

9C2500

AD2100

38

0016 000B ED2300

0017 000E F00E

0018 0010 7007

CLC

XCE

REP

LONGA

LONGI

STZ

LDA

SEC

SBC

BEQ

BVS

0019 0012 3007 BMI

0020 0014 EE2500 GREATER INC

0021

0022

0017

0019

8005

30F9 INVERT

0023 001B CE2500 LESS

BRA

BMI

DEC

0024 001E 38

0025 001F FB

0026 0020 60

0027 0021

SAME CLC

XCE

RTS

#$30

ON

ON

RELATION

VAL1

VAL2

SAME

INVERT

LESS

RELATION

SAME

GREATER

RELATION turn 16-bit modes on clear result cell if v set, invert meaning of sign bra if VAL1 is less than VAL2

VAL1 is greater than VAL2 invert: bra if minus: minus = greater

0028

0029

0030

0021

0023

0025

0031 0027

0032 0027

0000

0000

0000

VAL1

VAL2

DS

DS

RELATION DS

END

2

2

2

Listing 9.5

Decimal Mode

All of the examples in this chapter have dealt with binary numbers. In certain applications, however, such as numeric I/O programming, where conversion between ASCII and binary representation of decimal strings is inconvenient, and business applications, in which conversion of binary fractions to decimal fractions results in approximation errors, it is convenient to represent numbers in decimal form and, if possible, perform arithmetic operations on them directly in this form.

Like most processors, the 65x series provides a way to handle decimal representations of numbers.

Unlike most processors, it does this providing a special decimal mode that causes the processor to use decimal arithmetic for ADC, SBC, and CMP operations, with automatic “on the fly” decimal adjustment. Most other microprocessors, on the other hand, do all arithmetic the same, requiring a second “decimal adjust” operation to convert back to decimal form the binary result of arithmetic performed on decimal numbers. As you remember from Chapter 1, binary-coded-decimal (BCD) digits are represented in four bits as binary values from zero to nine. Although values from $A to $F (ten to fifteen) may also be represented in four bits, these bit patterns are illegal in decimal mode. So when $03 is added to $09, the result is $12, not $0C as in binary mode.

Each four-bit field in a BCD number is a binary representation of a single decimal digit, the rightmost being the one’s place, the second the ten’s, and so on. Thus, the eight-bit accumulator can represent numbers in the range

0 through 99 decimal, and the sixteen-bit accumulator can represent numbers in the range 0 through 9999.

Larger decimal numbers can be represented in multiple-precision, using memory variables to store the partial results and the carry flag to link the component fields of the number together, just as multiple-precision binary numbers are.

137

The Western Design Center

Decimal mode is set via execution of the SED instruction (or a SEP instruction with bit three set). This sets the d or decimal flag in the status register, causing all future additions and subtractions to be performed in decimal mode until the flag is cleared.

The default mode of the 65x processors is the binary mode with the decimal flag clear. It is important to remember that the decimal flag may accidentally be set by a wild branch, and on the NMOS 6502, it is not cleared on reset. The 65C02, 65802, and 65816 do clear the decimal flag on reset, so this is of slightly less concern. Arithmetic operations intended to be executed in binary mode, such as address calculations, can produce totally unpredictable results if they are accidentally executed in decimal mode.

Finally, although the carry flag is set correctly in the decimal mode allowing unsigned multipleprecision operations, the overflow flag is not, making signed decimal arithmetic, while possible, difficult. You must create your own sign representation and logic for handling arithmetic based on the signs of the operands.

Borrowing from the binary two’s-complement representation, you could represent negative numbers as those

(unsigned) values which, when added to a positive number result in zero if overflow is ignored. For example,

99 would equal –1, since 1 plus 99 equals 100, or zero within a two-digit precision. 98 would be –2, and so on.

The different nature of decimal representation, however, does not lead itself to signed operation quite as conveniently as does the binary two’s-complement form.

138

The Western Design Center

10) Chapter Ten

Logic and Bit Manipulation Operations

The logical operations found in this chapter are the very essence of computer processing; even the arithmetic functions, at the lowest level, are implemented as combinations of logic gates. Logic, or more accurately, boolean logic, is concerned with the determination of “true” and “false”.

Computers can represent simple logical propositions and relationships as binary states: the bit-value used to represent “1” in a given computer is considered equivalent to true; the bit-value which stands for “0” is considered equivalent to false. This designation is in fact arbitrary, and the values could easily be reversed.

What matters is the consistent application of the convention. Alternative terms are “set” and “reset” (or

“clear”), “on” and “off,” “high” and “low,” “asserted” and “negated.” There is a tendency to equate all of these terms; this is generally acceptable except when you are concerned with the actual hardware implementation of these values, in which case the issue of positive logic (“on” means “true”) vs. negative logic (“off” means

“true”) becomes a consideration. But the intuitive assumption of a positive logic system (“1” equals “on” equals “true”) seems the most natural, and may be considered conventional, so the terms listed above as equivalent will be used interchangeably, as appropriate for a given context.

Before discussing these functions, it is important to remember the bit-numbering scheme described in

Chapter 1: bits are numbered right to left from least significant to most significant, starting with zero. So a single byte contains bits zero through seven, and a double byte contains bits zero through fifteen. Bit zero always stands for the “one’s place.” Bit seven stands for the “128ths place” and bit fifteen stands for the

“32768ths place,” except that the high bit of a signed number is, instead, the sign bit. A single bit (or string of bits smaller than a byte or double byte) is sometimes called a bit-field, implying that the bits are just a part of a larger data element like a byte or a double byte.

You’ll find two types of instructions discussed in this chapter: the basic logic functions, and the shifts and rotates. They’re listed in Table 10.1.

Mnemonic 6502

Logic Instruction:

AND

EOR

ORA x x x

Available on:

65C02 65802/816

x x x x x x

Description

logical and logical exclusive-or logical or (inclusive or)

Bit Manipulation Instruction:

BIT x x

TRB x

TSB x

Shift and Rotate Instructions:

ASL x x

LSR x x

ROL

ROR x x x x x x x x x x x

test bits test and reset bits test and set bits shift bits left shift bits right rotate bits left rotate bits right

Table 10-1 Logic Instructions

Logic Functions

The fundamental logical operations implemented on the 65x processor are and, inclusive or, and

exclusive or. These are implemented as the AND, ORA, and EOR machine instructions. These three logical operators have two operands, one in the accumulator and the second in memory. All of the addressing modes

139

The Western Design Center

available for the LDA, STA, ADC, SBC, and CMP instructions are also available to the logical operations.

The truth tables for these operations are found in Chapter 1 and are repeated again in the descriptions of the individual instructions in Chapter 18.

In addition to these instructions, there are also bit testing instructions that perform logical operations; these are the BIT (test memory bits), TSB (test and set bits), and TRB (test and reset bits) instructions. These three instructions set status flags of memory values based on the result of logical operations, rather than affecting the accumulator.

The logical and bit manipulation instructions are broadly useful: for testing for a condition using boolean logic (for example, if this is true and that is true then do this); for masking bit fields in a word, forcing them to be on or off; for performing quick, simple multiplication and division functions, such as multiplying by two or taking the modulus of a power of two (finding the remainder of a division by a power of two); for controlling I/O devices; and for a number of other functions.

The most typical usage of the boolean or logical operators is probably where one of the two operands is an immediate value. Immediate values will generally be used in these examples. Additionally, operands will usually be represented in binary form (prefixed by a percent sign - %), since it makes the bit-pattern more obvious. All of the logical operations are performed bitwise; that is, the result is determined by applying the logical operation to each of the respective bits of the operands.

Logical AND

Consider, for example, the eight-bit AND operation illustrated in Figure 10.1.

bit number

7 6 5 4 3 2 1 0

0 1 1 1 0 1 1 0 and 1 1 0 0 1 0 1 1

0 1 0 0 0 0 1 0

$76 and $CB

$42 result

Figure 10-1 The AND Operation

The result, $42 or %0100 0010, is formed by ANDing bit zero of the first operand with bit zero of the second to form bit zero of the result; bit one with bit one; and so on. In each bit, a one results only if there is a one in the corresponding bit-fields of both the first operand and the second operand; otherwise zero results.

An example of the use of the AND instruction would be to mask bits out of a double-byte word to isolate a character (single-byte) value. A mask is a string of bits, typically a constant, used as an operand to a logic instruction to single out of the second operand a given bit or bit-field by forcing the other bits to zeroes or ones. Masking characters out of double bytes is common in 65802 and 65816 applications where a “default” mode of sixteen-bit accumulator and sixteen-bit index registers has been selected by the programmer, but character data needs to be accessed as well. For some types of character manipulation, it is quicker to simply mask out the extraneous data in the high-order byte than to switch into eight-bit mode. The code in Listing 10.1

is fragmentary in the sense that it is assumed that the core routine is inserted in the middle of other code, with the sixteen-bit accumulator size already selected.

It may seem to be splitting hairs, but this routine, which compares the value in a string of characters pointed to by the value in the memory variable CHARDEX to the letter ‘e’ is two machine cycles faster than the alternative approach, which would be to switch the processor into the eight-bit accumulator mode, compare the character, and then switch back into the sixteen-bit mode.

140

The Western Design Center

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000 18

0008 0001 FB

0009 0002

0010 0002 C230

0011 0004

0012 0004

0013 0004

0014 0004 AC4C00

0015 0007 B91A00

MAIN

PTR

KEEP

65816

START

GEQU

CLC

XCE

REP

LOOP

LDY

LDA

AND 0016 000A 29FF00

0017 000D C96500

0018 0010 D004

0019 0012

0020 0012 38

0021 0013 FB

0022 0014

0023 0014 38

0024 0015 60

0025 0016

0026 0016 38

0027 0017 FB

0028 0018

0029 0018 18

0030 0019 60

NOMATCH

CMP

BNE

SEC

XCE

SEC

RTS

SEC

XCE

CLC

RTS

0031 001A

0032 001A 54686573 STRING

0033 002A 61726520

0034 0040 65616368

0035 004A 0000

0036 004C 0000

0037 004E

DC

DC

DC

DC

CHARDEX DC

END

KL.10.1

ON

$80

#$30

LONGA ON

LONGI ON assume operation in 16-bit modes

CHARDEX get index pointing to desired char

STRING,Y get the char & the one after it

#%000000001111

111

#’e’

NOMATCH

AND out the “next” char cmp low byte to ‘e’, high 0 byte to 0 return to emulation mode set carry indicates successful match return to emulation mode clear carry indicates unsuccessful match

C ‘These characters’

C ‘are all packed next to’

C ‘each other’

H ‘0000’

2 index to a particular char in STRING

Listing 10.1

Each time the program is executed with a different value for CHARDEX, a different adjacent character will also be loaded into the high byte of the accumulator. Suppose the value in CHARDEX were four; when the LDA STRING,Y instruction is executed, the value in the low byte of the accumulator is $65, the ASCII value for a lower-case ‘e’. The value in the high byte is $20, the ASCII value for the space character (the space between “These” and “characters”). Even though the low bytes match, a comparison to ‘e’ would fail, because the high byte of the CMP instruction’s immediate operand is zero, not $20 (the assembler having automatically generated a zero as the high byte for the single-character operand ‘e’).

However, by ANDing the value in the accumulator wit %0000000011111111 ($00FF), no matter what

the original value in the accumulator, the high byte of the accumulator is zeroed (since none of the corresponding bits in the immediate operand are set). Therefore the comparison in this case will succeed, as it will for CHARDEX values of 2, 13, 18, 28, 32, 38, and 46, even though their adjacent characters, automatically loaded into the high byte of the accumulator, are different.

The AND instruction is also useful in performing certain multiplication and division functions. For example, it may be used to calculate the modulus of a power of two. (The modulus operation returns the remainder of an integer division; for example, 13 mod 5 equals 3, which is the remainder of 13 divided by 5.)

This is done simply by ANDing with ones all of the bits to the right of the power of two you wish the modulus

141

The Western Design Center

of and masking out the rest. A program fragment illustrating this will be provided later in this chapter, where an example of the use of the LSR instruction to perform division by powers of two will also be given.

In general, the AND operation is found in two types of applications: selectively turning bits off (byte

ANDing with zero), and determining if two logical values are both true.

Logical OR

The ORA instruction is used to selectively turn bits on by Oring them with ones, and to determine if either (or both) of two logical values is true. A character-manipulation example (Listing 10.2) is used – this time writing a string of characters, the high bit of each of which must be set, to the AppleII screen memory – to demonstrate a typical use of the ORA instruction.

Since the video screen is memory-mapped, outputting a string is basically a string move. Since normal

Apple video characters must be stored in memory with their high-order bit turned on, however, the ORA

#%10000000 instruction is required to do this if the character string, as in the example, was originally stored in normal ASCII, with the high-order bit turned off. Note that it clearly does no harm to OR a character with $80

(%10000000) even if its high bit is already set, so the output routine does not check characters to see if they need to have set high bit, but rather routinely Ors them all with $80 before writing them to the screen. When each character is first loaded into the eight-bit accumulator from STRING, its high bit is off (zero); the ORA instruction converts each of the values - $48, $65, $6C, $6C, $6F – into the corresponding high-bit-set ASCII values - $C8, $E5, $EC, $EC, and $EF, before storing them to screen memory, where they will be displayed as normal, non-inverse characters on the video screen. In this case, the same effect (the setting of the high-order bit) could have been achieved if $80 had been added to each of the characters instead; however, the OR operation differs from addition in that even if the high bit of the character already had a value of one, the result would still be one, rather than zero plus a carry as would be the case if addition were used. (Further a CLC operation would also have been required prior to the addition, making ORA a more efficient choice as well.)

142

The Western Design Center

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000

0008 0000 18

0009 0001 FB

0010 0002

0011 0002 C210

0012 0004

0013 0004

0014 0004 E220

0015 0006

L102

KEEP

65816

START

MSB

SCREEN GEQU

CLC

XCE

REP

LONGI

KL.10.2

ON

OFF

$400

#$10

ON start of AppleII screen memory

16-bit index register

SEP #$20

LONGA OFF

0016 0006

0017 0006 A00000

0018 0009

0019 0009 B91900

0020 000C F008

0021 000E 0980

0022 0010 990004

0023 0013

0024 0013 C8

TOP

LDY

LDA

BEQ

ORA

STA

0025 0014 80F3

0026 0016

0027 0016 38

0033 001F

0034 001F

DONE

INY

BRA

SEC

0028 0017 FB

0029 0018 60

XCE

RTS

0030 0019

0031 0019 48656C6C STRING DC

0032 001E 00 DC

END

#0

STRING,Y

8-bit accum starting index into string & screen = 0 get char from string

DONE branch if at 0 terminator

#%10000000 set the high bit

SCREEN,Y store the char into screen memory

TOP

C ‘Hello’

H ‘00’

Listing 10.2

Logical Exclusive-Or

The third logical operation, Exclusive-OR, is used to invert bits. Just as inclusive-OR (ORA) will yield a true result if either or both of the operands are true, exclusive-or yields true only if one operand is true and the other is false; if both are true or both are false, the result is false. This means that by setting a bit in the memory operand of an EOR instruction, you can invert the corresponding bit of the accumulator operand

(where the result is stored). In the preceding example, where the character constants were stored with their high bits off, an EOR #$80 instruction would have had the same effect as ORA #$80; but like addition, if some of the characters to be converted already had their high-order bits set, the EOR operation would clear them.

Two good examples of the application of the EOR operation apply to signed arithmetic. Consider the multiplication of two signed numbers. As you know, the sign of the product is determined by the signs of the multiplier and multiplicand according to the following rule: if both operands have the same sign, either positive or negative, the result is always positive; if the two operands have different signs, the result is always negative.

You perform signed multiplication by determining the sign of the result, and then multiplying the absolute values of both operands using the same technique as for unsigned arithmetic. Finally, you consider the sign of the result: if it is positive, your unsigned result is the final result; if it is negative, you form the final result by taking the two’s-complement of the unsigned result. Because the actual multiplication code is not included, this example is given as two fragments, 10.1 and 10.2.

Fragment 10.1 begins by clearing the memory location SIGN, which will be used to store the sign of the result. Then the two values to be multiplied are exclusive-OR’d, and the sign of the result is tested with the

143

The Western Design Center

BPL instruction. If the sign bit of the result is negative, you know that the sign bits of the two operands were different, and therefore the result will be negative; a negative result is preserved by decrementing the variable

SIGN, making its value $FFFF.

Next, the two operands are converted to their absolute values by two’s complementing them if they are negative. The technique for forming the two’s complement of a number is to invert it, and then add one. The

EOR operation is used again to perform the inversion; the instruction EOR #$FFFF will invert all of the bits in the accumulator: ones become zeroes, and zeros become ones. An INC A instruction adds one. In the case of

NUM2, this result must be saved to memory before the accumulator is reloaded with NUM1, which is also two’s complemented if negative

.

0000 0000

0002 0000

0004

0004 C230

0006

NUM1

NUM2

0006

0006

0006 9C0080

0009 AD0000

000C 4D0200

000F 1003

0011 CE0080

0014 AD0200 OK

0017 1007

DS

DS

REP

LONGA

LONGI

STZ

LDA

EOR

BPL

DEC

LDA

BPL

2

2

#$30

ON

ON

SIGN

NUM1

NUM2

OK

SIGN

NUM2

OK1

0019 49FFFF

001C 1A

001D 8D0200

0020 AD0000 OK1

0023 1004

0025 49FFFF

0028 1A

0029 OK2

EOR

INC

STA

LDA

BPL

EOR

INC

ANOP

#$FFFF

A

NUM2

NUM1

OK2

#$FFFF

A

16-bit modes clear the sign exclusive-or: check sign negative: sign = $FFFF minus: get absolute value

Fragment 10.1

At this point, the unsigned multiplication of the accumulator and NUM2 can be performed. The code for the multiplication itself is omitted from these fragments; however, an example of unsigned multiplication is found in Chapter 14. The important fact for the moment is that the multiplication code is assumed to return the unsigned product in the accumulator.

0000 AE0080

0003 1004

0005 49FFFF

0008 1A

0009 60

000A

LDX SIGN

BPL DONE

EOR #$FFFF

INC A

DONE RTS

Fragment 10.2

if should be neg, two’s complement the result

144

The Western Design Center

What remains is to adjust the sign of the result; this code is found in Fragment 10.2. By testing the sign of SIGN, it can be determined whether or not the result is negative; if it is negative, the actual result is the two’s complement of the unsigned product, which is formed as described above.

Bit Manipulation

You have now been introduced to the three principal logical operators, AND, ORA, and EOR. In addition there are three more specialized bit-manipulating instructions that use the same logical operations

.

The first of these is the BIT instruction. The BIT instruction really performs two distinct operations.

First, it directly transfers the highest and next to highest bits of the memory operand (that is, seven and six if m

= 1, or fifteen and fourteen if m = 0) to the n and v flags. It does this without modifying the value in the accumulator, making it useful for testing the sign of a value in memory without loading it into one of the registers. An exception to this is the case where the immediate addressing mode is used with the BIT instruction: since it serves no purpose to test the bits of a constant value, the n and v flags are left unchanged in this one case.

BIT’s second operation is to logically AND the value of the memory operand with the value in the accumulator, conditioning the z flag in the status register to reflect whether or not the result of the ANDing was zero or not, but without storing the result in the accumulator (as is the case with the AND instruction) or saving the result in any other way. This provides the ability to test if a given bit (or one or more bits in a bit-field) is set by first loading the accumulator with a mask of the desired bit patterns, and then performing the BIT operation. The result will be non-zero only if at least one of the bits set in the accumulator is likewise set in the memory operand. Actually, you can write your programs to use either operand as the mask to test the other, except when immediate addressing is used, in which case the immediate operand is the mask, and the value in the accumulator is tested.

A problem that remained from the previous chapter was sign extension, which is necessary when mixed-precision arithmetic is performed – that is, when the operands are of different sizes. It might also be used when converting to a higher precision due to overflow. The most typical example of this is the addition (or subtraction) of a signed eight-bit and a signed sixteen-bit value. In order for the lesser-precision number to be converted to a signed number of the same precision as the larger number, it must be sign-extended first, by setting or clearing all of the high-order bits of the expanded-precision number to the same value as the sign bit of the original, lesser-precision number.

In other words, $7F would become $007F when sign-extended to sixteen bits, while $8F would become

$FF8F. A sign-extended number evaluates to the same number as its lesser precision form. For example, $FF and $FFFF both evaluate to –1.

You can use the BIT instruction to determine if the high-order bit of the low-order byte of the accumulator is set, even while in the sixteen-bit accumulator mode. This is used to sign extend an eight-bit value in the accumulator to a sixteen-bit one in Listing 10.3.

145

The Western Design Center

0008

0009

0010

0011

0012

0013

0014

0015

0001

0002

0003

0004

0005

0006

0007

0016

0017

0018

0019

0020

0021

0022

0023

0024

0000

0000

0000

0000

0000 18

0001 FB

0002

0002 C230

0004

0004

0004

0004 A500

0006

0006 29FF00

0009 898000

000C F003

000E 0900FF

0011

0011 8500

0013

0013 38

0014 FB

0015 60

0016

KEEP

65816

L103 START

CLC

XCE

OK

REP

LONGA

LONGI

LDA

AND

BIT

BEQ

ORA

STA

SEC

XCE

RTS

END

KL.10.3

ON

#$30

ON

ON

0 turn 16-bit modes on get value to sign extend

#$FF

#$80 zero out any garbage in high byte test high bit of low byte

OK number is positive; leave as is

#$FF00 turn on high bits

0 save sign-extended value

Listing 10.3

The pair of “test-and-set” instructions, TSB and TRB, are similar to the BIT instruction in that they set the zero flag to represent the result of ANDing the two operands. They are dissimilar in that they do not affect the n and v flags. Importantly, they also set (in the case of TSB) or reset (in the case of TRB) the bits of the memory operand according to the bits that are set in the accumulator (the accumulator value is a mask). You should recognize that the mechanics of this involve the logical functions described above: the TSB instruction

Ors the accumulator with the memory operand, and stores the result to memory; the TRB inverts the value in the accumulator, and then ANDs it with the memory operand. Unlike the BIT instruction, both of the test-andset operations are read-modify-write instructions; that is, in addition to performing an operation on the memory value specified in the operand field of the instruction, they also store a result to the same location.

The test-and-set instructions are highly specialized instructions intended primarily for control of memory-mapped I/O devices. This is evidenced by the availability of only two addressing modes, direct and absolute, for these instructions; this is sufficient when dealing with memory-mapped I/O, since I/O devices are always found at fixed memory locations.

Shifts and Rotates

The second class of bit-manipulating instructions to be presented in this chapter are the shift and rotate instructions: ASL, LSR, ROL, and ROR. These instructions copy each bit value of a given word into the adjacent bit to the

“left” or “right.” A shift t o the left means that the bits are shifted into the next-higher-order bit; a shift to the right means that each is shifted into the next-lower-order bit. The bit shifted out of the end-that is, the orginal high-order bit for a left shift, or the original low order bit for a right shift-is copied into the carry flag.

Shift and rotate instructions differ in the value chosen for the origin bit of the shift or rotate. The shift instructions write a zero into the origin bit of the shift – the low-order bit for a shift left of the high-order bit for shift right. The rotates, on the other hand, copy the original value of the carry flag into the origin bit of the shift. Figure 10.2. and Figure 10.3 illustrate the operation of the shift and rotate instructions.

The carry flag, as Fragment 10.3 illustrates, is used by the combination of a shift followed by one or more rotate instructions to allow multiple-precision shifts, much as it is used by ADC and SBC instructions to enable multiple-precision arithmetic operations.

146

The Western Design Center

In this code fragment, the high-order bit in LOC1 is shifted into the carry flag in the first ASL instruction and a zero is shifted into the low-order bit of LOC1; its binary value changes from

1010101010101010 to

0101010101010100 carry = 1

The next instruction, ROL, shifts the value in the carry flag (the old high bit of LOC1) into the low bit of

LOC2. The high bit of LOC2 is shifted into the carry.

147

The Western Design Center

ASL-Before

1 0 1 1 0 0 1 1

X

CARRY FLAG

ASL

1 0 1 1 0 0 1 1

X

CARRY FLAG

0

ROL-Before

1 0 1 1 0 0 1 1

X

CARRY FLAG

ROL

1 0 1 1 0 0 1 1

X

CARRY FLAG

ASL-After

0 1 1 0 0 1 1 0

0000

A9AAAA

0003 8D0080

0006 A9AAAA

0009 8D0080

000C 0E0080

000F 2E0080

1

CARRY FLAG

ROL-After

0 1 1 0 0 1 1 X

1

CARRY FLAG

Figure 10-2 Shift and Rotate Left

LDA

STA

LDA

STA

ASL

ROL

Fragment 10.3

#%1010101010101010

LOC1

#%1010101010101010

LOC2

LOC1

LOC2

148

The Western Design Center

0

LSR-Before

1 0 1 1 0 0 1 1

LSR

X

CARRY FLAG

ROR-Before

1 0 1 1 0 0 1 1

X

CARRY FLAG

ROR

1 0 1 1 0 0 1 1

X

CARRY FLAG

1 0 1 1 0 0 1 1

X

CARRY FLAG

LSR-After

0 1 0 1 1 0 0 1

1

CARRY FLAG

X 1

Figure 10-3 Shift and Rotate Right

0

ROR-After

1 1 0 0 1

1

CARRY FLAG

149

The Western Design Center

1010101010101010 becomes

0101010101010101 carry = 1

A double-precision shift left has been performed.

What is the application of the shift and rotate instructions? There are two distinct categories: multiplication and division by powers of two, and generalized bit-manipulation.

Left shifts multiply the original value by two. Right shifts divided the original value by two.

This principal is inherent in the concept of positional notation; when you multiply a value by ten by adding a zero to the end of it, you are in effect shifting it left one position; likewise when you divide by ten by taking away the right-most digit, which in this case is base two.

Shifting is also useful, for the same reason, in a generalized multiply routine, where a combination of shift and add operations are performed iteratively to accomplish the multiplication. Sometimes, however, it is useful to have a dedicated multiplication routine, as when a quick multiplication by a constant value is needed.

If the constant value is a power of two – such as four, the constant multiplier in Fragment 10.4 – the solution is simple: shift left a number of times equal to the constant’s power of two (four is two to the power, so two left shifts are equivalent to multiplying by four).

0000 A93423

0003 0A

0004 0A

LDA

ASL

ASL

#$2334

A

A

Fragment 10.4

times 4 (2 to the 2 nd

power)

The result in the accumulator is $2334 times four, or $8CD0. Other “quickie” multiply routines can be easily devised for multiplication by constants that are not a power of two. Fragment 10.5 illustrates multiplication by ten: the problem is reduced to a multiplication by eight plus a multiplication by two.

0000 A9D204

0003 0A

0004 8D0080

0007 0A

0008 0A

0009 18

000A 6D0080

LDA

ASL

STA

ASL

ASL

CLC

ADC

#1234

A

TEMP

A

A

TEMP multiply by 2 save intermediate result times 2 again = times 4 times 2 again = times 8

= times 10

Fragment 10.5

After the first shift left, which multiplies the original value by two, the intermediate result (1234 * 2 =

2468) is stored at location TEMP. Two more shifts are applied to the value in the accumulator, which equals

9872 at the end of the third shift. This is added to the intermediate result of 1234 times 2, which was earlier stored at location TEMP, to give the result 12,340, or 1234 * 10.

Division using the shift right instructions is similar. Since bits are lost during a shift right operation, just as there is often a remainder when an integer division is performed, it would be useful if there were an easy way to calculate the remainder (or modulus) of a division by a power of two. This is where the use of the AND instruction alluded to earlier comes into play.

150

The Western Design Center

0000 A91FE2

0003 48

0004 4A

0005 4A

0006 8D0080

0009 68

000A 290300

000D 8D0080

LDA

PHA

LSR

LSR

STA

PLA

AND

STA

#$E21F

A

A

QUO

#$3

MOD save accumulator divide by 2 divide by 2 again = divide save quotient recover original value save modulus

Fragment 10.6

Consider Fragment 10.6. In this case, $E21F is to be divided by four. As with multiplication, so with division: two shifts are applied, one for each power of two, this time to the right. By the end of the second shift, the value in the accumulator is $3887, which is the correct answer. However, two bits have been shifted off to the right. The original value in the accumulator is recovered from the stack and then ANDed with the divisor minus one, or three. This masks out all but the bits that are shifted out during division by four, the bits which correspond to the remainder or modulus the quotient times four, and then adding the remainder.

The second use for the shift instructions is general bit manipulation. Since the bit shifted out of the word always ends up in the carry flag, this is an easy way to quickly test the value of the high- or low-order bit of a word. Listing 10.4 gives a particularly useful example: a short routine to display the value of each of the flags in the status register. This routine will, one by one, print the letter-name of each of the status register flags if the flag is set (as tested by the BCS instruction), or else print a dash if it is clear.

151

The Western Design Center

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000

0008 0000

0009 0000

0010 0000 08

0011 0001

0012 0001

0013 0001 18

0014 0002 FB

0015 0003

;

KEEP

65816

PRINTP

PREG

PTR

KL.10.4

ON

START

GEQU

GEQU

PHP

CLC

XCE

$80

$82 save (on the stack) the status reg to be displayed

0016 0003 C2FF

0017 0005 E220

0018 0007

0019 0007

0020 0007

0021 0007 68

0022 0008 8580

0023 000A A23000

0024 000D 8682

0025 000F A20800

0026 0012

0027 0012 0680

0028

0029

0030

0031

0032

0014

0016

0018

001A

001C

B004

A92D

8002

B282

200080

0033 001F E682

0034 0021 D002

0035 0023 E683

0036 0025 CA

0037 0026 D0EA

0038 0028 A90D

0039 002A 200080

0040 002D

0041 002D 38

0042 002E FB

0043 002F 60

0044 0030

0045 0030 6E766D78 FLAGS

0046 0038

0047 0038

REP

SEP

LONGI ON

LONGA OFF

PLA

STA

LDX

STX

LDX

LOOP ASL

BCS

LDA

BRA

DOFLAG LDA

SKIP JSR

OK

INC

BNE

INC

DEX

BNE

LDA

JSR

SEC

XCE

RTS

DC

END

#$FF

#$20

PREG

#FLAGS

PTR

#8

PREG

16-bit index regs; reset all flags

8-bit accum pull status reg to display into accum then store to memory location PREG load 16-bit X with ptr to flag string and store to PTR load X with counter (# of flag bits)

DOFLAG branch if set

#’-‘ if flag not set, output ‘-‘

SKIP

(PTR)

COUT get flag letter from FLAGS output flag letter or ‘-‘

PTR

OK

PTR+1

LOOP

#$0D

COUT c’nvmxdizc’ shift high bit of PREG Õ carry

16-bit increment

(incr hi byte if low rolls over) decrement counter continue thru all 8 bits of status reg output cr after all 8 flags

SKIP 00001C

0048 0000

0049 0000

0050 0000

0051 0000

0052 0000 48

COUT

ECOUT

START

GEQU

PHA

$FDED COUT IN APPLE I I MONITOR

152

The Western Design Center

0053 0001 DA

0054 0002 5A

0055 0003 08

0056 0004 38

0057 0005 FB

0058 0006 20EDFD

0059 0009 18

0060 000A FB

0061 000B 28

0062 000C 7A

0063 000D FA

0064 000E 68

0065 000F 60

0066 0010

XCE

PLP

PLY

PLX

PLA

RTS

END

PHX

PHY

PHP

SEC

XCE

JSR

CLC

ECOUT

Listing 10.4

153

The Western Design Center

11) Chapter Eleven

The Complex Addressing Modes

Chapter 7 defined the term addressing mode and introduced the set of simple 65x addressing modes, those which involve at most a minimum of calculating combined values from multiple locations.

This chapter continues and expands the discussion of one of those modes, the direct page addressing mode, for those cases where the direct page register value is other than zero. It discusses the basis for selection by the assembler among the direct page, absolute, and long addressing modes, and how you can explicitly override those assumptions. And it discusses the set of complex addressing modes available on the 6502, the

65C02, the 65802, and the 65816, those which require the effective address to be calculated from several sources (Table 11.1). The understanding of these modes also provides the context within which to discuss several more complex push instructions that were previously deferred to this chapter (Table 11.2).

Available on all 65x processors:

absolute indexed with X absolute indexed with Y direct page (zero page) indexed with X direct page (zero page) indexed with Y direct page (zero page) indirect indexed with Y direct page (zero page) indexed indirect with X

Available on the 65C02, 65802, and 65816 only:

absolute indexed indirect

Available on the 6502 and 65816 only:

non-zero direct page absolute long indexed with X direct page indirect long indexed with Y stack relative stack relative indirect indexed with Y

Example Syntax

LDA

LDA

$2234,X

$2234,Y

LDA

LDX

LDA

LDA

$17,X

$17,Y

($17),Y

($17,X)

JMP

LDA

LDA

LDA

LDA

LDA

($ 7821,X)

$17

$654321,X

[$17],Y

$29,S

($29,S),Y

Mnemonic

PEA

PEI

PER

6502

Table 11-1 Complex Addressing Modes

Available on:

65C02 65802/816

x x x

Description

push effective absolute address push effective indirect address push effective relative address

Table 11-2 Complex Push Instructions

154

The Western Design Center

Relocating the Direct Page

Chapter 7 discussed zero page addressing as found on the 6502 and 65C02 and introduced direct page addressing, the 65816’s enhancement to zero page addressing. The 65816 lets the zero page addressing modes use a direct page that can be located and relocated anywhere in the first 64K of memory. But Chapter 7 left the direct page set to page zero so it could be discussed as a simple addressing mode – that is, so no calculation of direct page register base plus direct page offset needed to be done and so the operand, a direct page offset, could be thought of as an absolute address with a high-order byte of zero.

Relocating the direct page from page zero, to which it is initialized on power-up, can be accomplished in either of two ways. The first would let a new value be pulled off the stack into the direct page register with the PLD instruction, as found in Fragment 11.1.

0000

0000 A20034

0003 DA

0004 2B

;

LDX

PHX

PLD

#$3400 set direct page register to $3400 get $3400 into a register and push it onto the stack, then pull it into direct page reg

Fragment 11.1

Fragment 11.2 illustrates the second method. The direct page register can be set to the value in the sixteen-bit C accumulator by use of the TCD instruction, which transfers sixteen bits from accumulator to direct page register.

0000

0000 A900FE

0003 5B

;

LDA

TCD

#$FE00 set direct page register to $FE00 get $FE00 into sixteen-bit accum and transfer from C accum into direct pg

Fragment 11.2

Both methods of setting the direct page register give it a sixteen-bit value. Since sixteen bits are only capable of specifying an address within a 64K range, its bank component must be provided in another manner; this has been done by limiting the direct page to bank zero. The direct page can be located anywhere in 64K but the bank address of the direct page is always bank zero.

Chapter 7, which limited the use of the direct page to page zero, used the example shown in Fragment

11.3 to store the one-byte value $F0 at address $0012, which is the direct page offset of $12 added to a direct page register value of zero. If instead the direct page register is set to $FE00, then $F0 is stored to $FE12; the direct page offset of $12 is added to the direct page register value of $FE00.

0000 A9F0000

0003 8512

LDA

STA

#$F0

$12 store accumulator to dp:$12

Fragment 11.3

While it is common to speak of a direct page address of $12, $12 is really an offset from the base value in the direct page register ($FE00 in the last example). The two values are added to form the effective

direct page address of $FE12.

But while Chapter 7 defined a page of memory as $100 locations starting from a page boundary (any multiple of $100), the direct page does not have to start on a page boundary; the direct page register can hold

any sixteen-bit value. If the code in Fragment 11.4 is executed, running the code in Fragment 11.3 stores the one-byte value $f0 at address $1025: $1013 plus $12.

155

The Western Design Center

0000

0000 A91310

0003 5B

;

LDA

TCD

#$1013 set direct page register to $1013 get $1013 into sixteen-bit accum transfer $1013 from C into direct pg reg

Fragment 11.4

You will for the most part, however, want to set the direct page to begin on a boundary: it saves one cycle for every direct page addressing operation. This is because the processor design includes logic that, when the direct page register’s low byte is zero, concatenates the direct page register’s high byte to the direct page offset – instead of adding the offset to the entire direct page register – to form the effective direct page address; concatenation saves a cycle over addition.

One of the benefits of the direct page concept is that programs, and even parts of programs, can have their own $100-byte direct pages of variable space separate from the operating system’s direct page of variable space. A routine might set up its own direct page with the code in Fragment 11.5.

0000

0000 0B

0001 A90003

0004 5B

;

PHD

LDA

TCD set up direct page for this routine at $0300 first save current direct page location

#$300 load sixteen-bit accumulator with $300 transfer $300 into direct page reg

Fragment 11.5

To end the routine and restore the direct page register to its previous value, simply execute a PLD instruction.

As discussed in Chapter 7, having a direct page makes accessing zero page addresses in any bank require special assembler syntax. Since the zero page is no longer special, absolute addressing must be used; but since the assembler normally selects direct page addressing for operands less than $100, the standard syntax requires that you prefix a vertical bar or exclamation point to the operand to force the assembler to use absolute addressing. This is just one of the potential assembler misassumptions covered in the next section.

Assembler Addressing Mode Assumptions

When the assembler encounters an address in the operand field of an instruction, it must decide whether the address is a direct page offset, a sixteen-bit absolute address, or a 24-bit long address and generate opcode and operand values which are appropriate. Its decision is based on the operand’s size – not the number of digits in the operand, but whether the value of the operand is greater than $FF of greater than $FFFF. For example, the assembler will interpret the operand $3F to be a direct page offset regardless of whether it is written as $3F,

$003F, or $00003F, because its value is less than 100 hex.

As a result, there are several areas of memory in 65802 and 65816 systems that the assembler will not access without entering the special syntax shown in Table 11.3 to override the assembler’s assumptions.

156

The Western Design Center

Syntax

8-bit operand (less than $100):

Description

Normal direct page addressing:

LDA $32 load accum from: bank zero: direct page: $32

Force absolute addressing: zero page in data bank:

LDA !$32 load accum from: data bank: $0032

Force long addressing: zero page in bank zero:

LDA >$32 load accum from: $00:0032

16-bit operand (from $100 through $FFFF):

Normal absolute addressing:

LDA $7512 load accum from: data bank: $7512

Force direct page addressing:

LDA <47512 load accum from: bank zero: direct page: $12

Force long addressing:

LDA >$7512 load accum from: $00:7512

24-bit operand (over $FFFF):

Normal long addressing:

LDA $123456 load accum from: $12:3456

Force absolute addressing:

LDA !$123456 load accum from: data bank: $3456

Force direct page addressing:

LDA <$123456 load accum from: bank zero: direct page: $56

Table 11-3 Assembler Syntax for Complete Memory Access

The first is zero page memory. Page zero has no special meaning in the 65802 and 65816: its special attributes have been usurped by the direct page, so accessing it requires use of absolute addressing just like any other absolute location. But the assembler assumes addresses less than $100 are direct page offsets, not zero page addresses; it will not generate code to access the zero page (unless the direct page is set to the zero page so that the two are one and the same) without explicit direction. And even if the direct page is set to the zero page,

65816 systems have a zero page not only in bank zero but also in every other bank, and those other page zeroes cannot ever be accessed by absolute addressing without special direction.

The syntax to force the assembler to use absolute addressing is to precede an operand with a vertical bar or exclamation point as shown in Fragment 11.6.

157

The Western Design Center

0000 C220

0002

0002 A90032

0005 5B

0006 E210

0008

0008 A202

000A DA

000B AB

000C A532

000E 8D3200

0011 8F320000

#$20

ON

#$3200

#$10

OFF

#2

Fragment 11.6

Notice the use of another symbol, the greater-than sign (>), to force long addressing. This solves another problem: The assembler assumes absolute addresses are in the data bank; if the value in the data bank is other than zero, then it similarly will not generate code to access bank zero without special direction. The greater-than sign forces the assembler to use a long addressing mode, concatenating zero high bits onto the operand until it’s 24 bits in length. This usage is shown in Fragment 11.7, where the greater-than sign forces absolute long addressing, resulting in the assembler generating an opcode using absolute long addressing to store the accumulator, followed by the three absolute long address bytes for $00:0127, which are, in 65x order,

$27, then $01, then $00.

The ASL instruction in Fragment 11.7 makes use of the third assembler override syntax: prefixing an operand with the less-than sign (<) forces direct page addressing. It’s not likely you’ll use this last syntax often, but it may come in handy when you’ve assigned a label to a value that you need the assembler to truncate to its low-order eight bits so it will be used as a direct page offset.

Note that this override syntax is the recommended standard syntax. As Chapter 1 (Basic Concepts) points out, even mnemonics can vary from one assembler to another, so assembler syntax such as this can differ as well.

0000

0002

0002

0002

0004

0005

E210

A202

DA

AB

0006

0009

AD2701

8F270100

000D 0627

REP

LONGA

LDA

TCD

SEP

LONGI

LDX

PHX

PLB

LDA

STA

STA

SEP #$10

LONGI OFF

#2 LDX

PHX

PLB

LDA

STA

ASL

$127

>$127

<$127

$32

!$32

>$32 set accumulator/memory to sixteen get new direct page location and set up direct page at $3200 set index registers to eight-bit set new data location to bank 2 push 2 on stack and pull it off into data bank load accumulator from dp:$32 in bank 0 store accum at $02:0032 (data bank) store accum at $00:0032 (long address) use 8 bit index registers get new data bank value push it on stack pull into data bank from B:$0127 ($02:0127) store at $00:0127 shift word at dp:$27

Fragment 11.7

Direct Page Indirect Indexed With Y Addressing

Direct page indirect indexed addressing or postindexing, which uses the Y register, is one of two ways indirect addressing can be combined with indexing (the other will be described in the next section). In postindexing, the processor goes to the location the direct page operand specifies and adds the index to the indirect address found there.

Like direct page addressing, which was discussed in Chapter 7 (The Simple Addressing Modes), postindexing gives you the freedom to access a memory location which is not determined until the program is executing. As you also learned from Chapter 7, direct page indirect lets your program store the absolute address of a data bank location you want to access (this address is called the indirect address) into any two consecutive bytes in the direct page. This makes those two bytes perform as though they are an extra sixteen-bit register in the microprocessor itself. Further, it leaves the processor’s registers unobstructed, and it allows data at the location stored in the direct page “register” to be accessed at any time.

158

The Western Design Center

Postindexing differs in that the absolute address you store into the direct page “register” is not one location but the base of an array; you can then access a particular byte in the array by loading its array index into the Y register and specifying, as your operand, the direct page “register” (the location of the indirect base of the array). As Figure 11.1 shows, the processor goes to the direct page offset, gets the absolute memory location stored there, than adds the contents of the Y register to get the absolute memory location it will access.

The direct page offset, being in the direct page, is in bank zero on the 65816; the array, on the other hand, is in the data bank.

65816 Registers

Bank

23

Data Bank (DBR)

15

High

7

23

Effective Address:

15

Bank

Low

0

High

7

Low

0

Instruction:

Opcode Operand

+

+1

High Indirect Address

Low Indirect Address

Bank 0

+

Y Index Register (Y) x = 1 x = 0

Direct Page Register (D)

Figure 11-1 Postindexing

This addressing mode is called postindexing because the Y index register is added after the indirect address is retrieved from the direct page.

For example, suppose that your program needs to write a dash (hyphen) character to a location on the

AppleII’s 40-column screen that will be determined while the program is running. Further suppose your program picks a screen location at column nine on line seven. The AppleII has a firmware routine (called

BASCALC) which, when presented with the number of a line on the screen, calculates the address of the leftmost position in the line and returns it in zero page location BASL, located at memory locations $0028 and

$00029.

If you wanted to write your hyphen to the first position on the line, you could, after calling BASCALC and loading the character to print into the accumulator, use the 65C02’s indirect addressing mode:

9228 STA (BASL)

The 6502 has no simple indirect addressing mode, but Fragment 11.8 illustrates what 6502 programmers long ago learned: you can use postindexing to the same effect as simple indirect by loading the Y register with zero.

159

The Western Design Center

0000

0000 A92D

0002 A000

0004 9128

0006

0006

0006

BASL EQU $28

LDA #’-‘

LDY #0

.

.

.

STA (BASL),Y write a dash to (BASL)

Fragment 11.8

But you want to write the hyphen character to column nine (the leftmost position being column zero), not column zero. After calling BASCALC, you load the Y register with nine and write your character indirect through BASL indexed by the nine in Y as seen in Fragment 11.9. If BASCALC calculates line seven on the screen to start at location $780, and as a result stores that address at BASL, then the routine in Fragment 11.9

will write a dash to location $789 (column nine on line seven).

0000 A92D

0002 A009

0004 9128

LDA

LDY

STA

#’-‘

#9

(BASL),Y

Fragment 11.9

write a dash to col 9 on the line with its base i

You could write a line of dashes from column nine through column sixteen simply by creating the loop coded in Listing 11.1. This kind of routine has been used for years on the 6502-based AppleII .

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000

0008 0000

0009 0000

0010 0000 A980

0011 0002 8528

0012 0004 A907

0013 0006 8529

0014 0008 A92D

0015 000A A009

0016 000C 9128

0017 000E C8

0018 000F C011

0019 0011 90F9

0020 0013 60

0021 0014

0022 0014

;

L111

BASL

LINE7

LOOP

KEEP

65816

6502

KL.11.1

OFF example

LDA

STA

LDA

STA

LDA

LDY

STA

INY

CPY

BCC

RTS

END

START

GEQU $28

GEQU $780

#LINE7

BASL

#>LINE7

BASL+1

#’-‘

#9 write a dash to col 9

(BASL),Y on the line with its base in BASL incr pointer to next column position

#17

LOOP (BLT): write another dash up to col. 17

Listing 11.1

Finally, note that, like absolute indexed addressing, the array of memory accessible to the indirect indexed addressing mode can extend beyond the current 64K data bank into the next 64K bank, if the index plus the array base exceeds $FFFF.

160

The Western Design Center

Direct Page Indexing Indirect Addressing

As the introduction to the last section pointed out, you can combine indexing with indirection in two ways. Postindexing, discussed in the last section, is one. The other is called direct page indexed indirect

addressing or preindexing and uses the X register. It adds the index to the operand (a direct page base) to form a direct page offset at which the indirect address (the address of the data to be accessed) is located.

In effect, preindexing lets you index into a double-byte array of absolute memory addresses based in the direct page to choose the memory location to access; the array begins at the direct page offset specified by the operand

.

Since the array base is a direct page location, adding the direct page register value yields the absolute location in bank zero. The processor then adds the value in the X register, which is the index into the array of memory locations. Now the processor finally has an address that holds the memory location you want to access; it now gets the location and accesses the data at that location. This is shown in Figure 11.2. Since indexing is done in order to find the indirect address, this addressing mode is also called preindexing .

You’ll find preindexing useful for writing routines which need to access data in a number of different locations in exactly the same way. For example, a tic-tac-toe game drawn on the screen has nine boxes to which an ‘O’ or an ‘X’ might be written. The tic-tac-toe program might keep internal arrays of information about the content of each of the nine boxes, as well as arrays of data for working its win-seeking algorithms, using indexes from 0 to 8 to represent the locations

.

When it comes time for the program to write an ‘X’ to a chosen square, you could, of course, write nine nearly identical routines which differ only in the address to which the ‘X’ will be written; you would also have to write a tenth routine to select which one of the routines needs to be called, based on the value of the box index (from zero to eight).

When it comes time for the program to write an ‘X’ to a chosen square, you could, of course, write nine nearly identical routines which differ only in the address to which the ‘X’ will be written; you would also have to write a tenth routine to select which one of the routines needs to be called, based on the value of the box index (from zero to eight).

A faster and less wasteful method of writing the ‘X’ would be to use pre-indexing. In the section of code which initially draws the tic-tac-toe grid, you would determine the nine addresses where characters are to be direct page offset $50; this puts the 0 location at $50 and $51 (stored, in 65x fashion, low byte in $50 and high byte in $51), the 1 location at $52 and 53, and so on. The nine addresses use 18 bytes of memory.

When an ‘X’ is to be stored to one of the nine screen locations, only one routine is necessary: you multiply the box number by two (using the ASL instruction). Remember that each indirect address takes up two bytes in the direct page array. Transfer it to the X register. Then load an ‘X’ character into the accumulator and write it to the box on the screen using preindexing as Fragment 11.10 shows.

0000 AD0080 WRITEX LDA BOXNUMBER get which box to write an ‘X’ to

0003 0A ASL A multiply by two to get index

0004 AA

0005 A958

0007 8150

TAX

LDA

STA

#’X’

($50,X) and transfer index to X register write ’X’ character to scrn location at (dp:$50, index reg)

Fragment 11.10

161

The Western Design Center

Effective Address:

23 15

Bank High

7

Low

0

Instruction

Opcode Operand

65816 Registers:

23

Bank

Data Bank (DBR)

15

High

7

Low

0

0000 0000

X Index Register (X)

Direct

Page Register (D

) x=1 x=0

+

+

+1

High Indirect Address

High Indirect Address

Bank 0

Figure 11-2 Preindexing

162

The Western Design Center

Notice the differing syntax: postindexing looked like this:

9128 STA (BASL),Y

In postindexed, the operand locates the direct address, so it’s in parentheses to indicate indirection. The, “Y” is not in parentheses, since the index register is not part of finding the indirect address – it’s added to the indirect address once it is found.

On the other hand, with preindexing:

8150 STA ($50,X) both the operand and the index register are involved in locating the indirect address, so both are in parentheses

.

A very different application for preindexing enables the 65x to read from (or write to) several I/O peripherals “at once.” Obviously, a microprocessor can only read from one device at a time, so it polls each device: provided each device uses the same I/O controller chip (so that a single routine can check the status of all devices and read a character from each of them identically), your program can poll the various status locations using pre-indexing. Begin by storing an array of all the status locations in the direct page. Specify the base of the array as the operand to preindexed instruction. Load the X index with 0 and increment it by two until you’ve checked the last device. Finally, restore it to zero and cycle through again and again.

If a status check reveals a character waiting to be read, your program can branch to code that actually reads the character from the device. This time, you’ll use preindexing to access a second direct page array of the character-reading addresses for each device; the index in the X register from the status-checking routine provides the index into the character-reading routine.

On the 6502, the 65C02, and the 6502 emulation modes, the entire array set up for preindexing must be in the direct page. (On the 6502 and 65C02, this means the array must be entirely in the zero page which, unfortunately, severely limits the use of preindexing due to the competition for zero page locations.) If the specified direct page offset plus the index in the X exceeds $FF, the array wraps around within the direct page rather than extending beyond it. That is,

LDX #$1A A21A followed by

A1F0 LDA ($FO,X) would load the accumulator from the indirect address in location $0A not $10A.

On the 65802 and 65816 (in native mode), the array must still start in the direct page but wraps, not at the end of the direct page but at the end of bank zero, when the array base plus the D direct page setting plus the X index exceeds $00:FFFF.

On the 65816, the data that is ultimately accessed (after the indirection) is always in the data

bank.

Absolute Indexed Indirect Addressing

The 65C02 introduced a new addressing mode, absolute indexed indirect addressing, which is quite similar to direct page indexed indirect. (It is also preindexed using the X index register, but indexes into absolute addressed memory rather than the direct page to find the indirect address.) This new addressing mode is used only by the jump instruction and, on the 65802 and 65816, the jump-to-subroutine instruction.

Absolute indexed indirect provides a method for your program, not to access data in scattered locations by putting the locations of the data into a table and indexing into it, but to jump to routines at various locations by putting those locations into a table, indexing into it, and jumping to the location stored in the stored in the table at the index. Figure 11.3 shows what happens.

163

The Western Design Center

A menu-driven program, for example, could ask users to respond to a prompt by pressing a number key from ‘0’ through ‘7’. Your program would convert the key’s value to an index by subtracting the ASCII value of ‘0’ and doubling the result (to reflect the fact that each table entry is an address and thus takes two bytes in the table) (Fragment 11.11). It would then jump indexed indirect to a routine appropriate to the menu choice.

0000

0000

0000 38

0001 E93000

0004 0A

0005 AA

0006 7C0900

0009

0009 0080

000B 0080

000D 0080

000F 0080

0011 0080

0013 0080

0015 0080

0017 0080

;

TABLE get menu choice into accumulator

SEC

SBC #’0’

ASL A

TAX

JMP (TABLE,X) set carry before subtract convert’0’-‘7’ to 0-7 times 2 = index transfer index to X jump to address TABLE + X

DC A’ROUTIN0’

DC A’ROUTIN1’

DC A’ROUTIN2’

DC A’ROUTIN3’

DC A’ROUTIN4’

DC A’ROUTIN5’

DC A’ROUTIN6’

DC A’ROUTIN7’ routine for reason ‘0’ menu response ‘1’ menu response ‘2’ menu response ‘3’ menu response ‘4’ menu response ‘5’ menu response ‘6’ menu response ‘7’

Fragment 11.11

164

The Western Design Center

23

Effective Address:

New Program Counter Value

15 7

Bank High Low

Instruction:

Opcode

23

65816 Registers:

Bank

15

Operand Low Operand High

High

X Index

Low

7

Register (X)

0 x

+1

High Indirect Address

Low Indirect Address x = 1 x = 0

Program Bank

Program Bank (PBR)

0

Figure 11-3 Absolute Indexed Indirect

Because both the operand (the absolute address of the base of the table) and the index register are involved in determining the indirect address, both are within the parentheses.

On the 65816, a jump-indirect operand is in bank zero, but a jump-indexed-indirect operand is in the

program bank. There is a different assumption for each mode. Jump indirect assumes that the indirect address to be jumped to was stored by the program in a variable memory cell; such variables are generally in bank zero.

Jump indexed indirect, on the other hand, assumes that a table of locations of routines would be part of the program itself and would be loaded, right along with the routines, into the bank holding the program. So,

6C3412 JMP ($1234) jump to address stored at $00:1234.1235

assumes $1234 is in a double-byte cell in bank zero. But

7C3412 JMP (1234,X) jump to address stored at pb:$1234,X assumes $1234 is in the program bank, the bank in which the code currently being executed resides.

The indirect addresses stored in the table are absolute addresses also assumed to be in the current program bank

.

Direct Page Indirect Long Indexed with Y Addressing

The 65816 can access sixteen megabytes of memory, yet lets you access most data (data located in the current data bank) with just two bytes. Nevertheless, there are times when data must be accessed in a bank other than the current data bank when it would be inconvenient to change the data bank, then change it back.

As Chapter 7 pointed out, this problem is solved by the “long” addressing modes, which allow three bytes (the bank in addition to the address within the bank) to specify a full 24-bit address. This solution lets you access the 65816’s full sixteen-megabyte address space. Probably the most useful way to reference data outside of the current data bank is via the direct page indirect long indexed with Y, or postindexed long, addressing mode.

This is the long version of direct page indirect indexed addressing, discussed earlier in this chapter.

Instructions are two bytes in length, as shown in Fragment 11.4: The opcode is followed by a single byte, which is a direct page offset in bank zero. The indirect address stored in the direct page (to which the operand points) is, in the long version, three bytes (a full 24-bit address); the byte at the direct page offset is the low byte of the 24-bit address, the byte in the next direct page location the middle byte of the 24-bit address,

165

The Western Design Center

and the byte in the third location the bank byte of the 24-bit address. The contents of the Y index register are added to this 24-bit address to form the 24-bit effective address at which data will be accessed.

The syntax for postindexed long is:

B715 LDA [$15],Y

The square brackets are used to indicate the indirect address is long.

So, like its sixteen-bit counterpart, indirect long indexed addressing allows you to index into an array of which neither the base nor the index need be determined until the program is executing. Unlike its sixteen-bit counterpart, it allows you to access an array in any bank, not just the current data bank.

Stack Relative Addressing

Possibly the most exciting new addressing method introduced by the 65802 and 65816 is stack relative.

This is the first 65x method for directly accessing a stack byte other than the last data item pushed.

Stack relative addressing lets you easily access any byte or address in the last $FF bytes stacked.

Instructions using stack relative addressing are two bytes long, the operand a single byte that is an index into the stack. As Figure 11.5 shows, the stack is treated as an array with its base the address in the stack pointer. The operand is added to the stack pointer value to form the bank zero effective address which will be accessed.

This can be especially useful when one part of a program needs to send data to another part of the program, such as a multiply routine. The two sixteen-bit values to be multiplied are pushed onto the stack in one part of the program. Later, the multiply routine loads one of the operands using stack relative addressing, leaving both the other operand and the stack pointer undisturbed:

LDA 3,S load first operand or

A303

A301 LDA 3,S load second operand

Notice that accessing the last data put on the stack requires an index of 1, not of 0. This is because the stack pointer always points to the next available location, which is one byte below the last byte pushed onto the stack. An index of zero would generally be meaningless, except perhaps to re-read the last byte pulled off the stack! (The latter would also be extremely dangerous since, should an interrupt occur, the left-behind byte would be overwritten by interrupt-stacked bytes.)

166

The Western Design Center

Instruction:

Opcode

65816 Registers:

Bank

23 15

Operand

High Low

7

Y Index Register (Y)

23

Effective Address:

15

Bank

0

+

+2

+1 x = 1 x = 0

0000 0000 Direct

Page Register

(D)

High

7

Low

0

Bank Indirect Address

High Indirect Address

Low Indirect Address

Bank 0

+

Figure 11-4 Postindexed Long

167

The Western Design Center

23

Effective Address:

Bank

15

00000000

High

Instruction:

Opcode

65816 Registers:

Bank

23 15

0000 0000

Operand

High

Stack

Low

7

Pointers (S)

0

+

7

Low

0

Figure 11-5 Stack Relative

Stack Relative Indirect Indexed Addressing

While the stack relative addressing mode serves to access data on the stack, the stack relative indirect indexed addressing mode lets you access data indirectly through addresses that have been pushed onto the stack.

Change the previous example: Instead of stacking the two sixteen-bit values to be multiplied, the values are found in memory cells in the data bank, one after the other (occupying four consecutive bytes), and it’s the address of the first that is pushed onto the stack. Now, Fragment 11.12 shows, either value can be loaded using the stack indirect address:

0000 A00000

0003 B301

0005 AA

0006 A00200

0009 B301

LDY

LDA

TAX

LDY

LDA

#0

(1,S),Y

#2

(1,S),Y load first 16-bit multiply operand save first value load second 16-bit multiply operand

Fragment 11.12

The 1,S is the stack location where the indirect address was pushed. (Actually, 1,S points to the stack location of the low byte of the indirect address; the high byte is in 2,S, the next higher stack location.) To this indirect address, the value in the Y is added: the indirect address plus 0 locates the first value to be multiplied; the indirect address plus 2 locates the second. Finally the accumulator is loaded from this indirect indexed address. Figure 11.6 illustrates the sequence.

This mode, very similar to direct page indirect indexing (also called postindexing), might be called

“stack postindexing.” The operand which indexes into the stack is very similar to a direct page address; both are limited to eight bits and both are added to a sixteen-bit base register (D or S). In both cases, the indirect address points to a cell or an array in the data bank. In both cases, Y must be the index register. And in both cases in the 65816, the postindexed indirect address about to be accessed may extend out of the data bank and into the next bank if index plus address exceeds $FFFF; that is, if the indirect address is the base of an array, the array can extend into the next bank.

168

The Western Design Center

Push Effective Instructions

23

Effective Address:

15

Bank High

7

Low

0

Instruction:

Opcode Operand

65816 Registers:

Bank

23

Data Bank (DBR)

15

High

7

0000 0000

Low

0

Y Index

Register (Y) x = 1 x = 0

+

+1

Stack Pointer (S)

Stack

High Indirect Address

Low Indirect Address

Bank 0

+

Figure 11-6 Stack Relative Indirect Indexed

As Figure 11.7 shows, the PEA(push effective absolute address) instruction pushes the operand, a

The 65802 and the 65816 provide three instructions which push, not registers, but absolute, indirect, and relative addresses straight onto the stack. These three instructions are PEA, PEI, and

PER, the push effective address instructions. Addresses so pushed might be accessed, for example, using the stack relative indirect indexed addressing mode just discussed. Chapter 6, which introduced the push instructions in the context of data movement, deferred discussion of these three instructions to this chapter.

Except for the block move instructions, these are the only instructions that move data directly from one memory location to another.

16-bit absolute address or immediate data word, onto the stack. For example,

F43421 PEA $2134 push $2134 onto the stack pushes what may be either sixteen-bit immediate data or a sixteen-bit address onto the stack. The operand pushed by the PEA instruction is always 16 bits regardless of the settings of the m memory/accumulator and x index mode select flags.

The PEI (push effective indirect address) instruction has, as an operand, a direct page location: it’s the sixteen-bit value stored at the location that is pushed onto the stack. Figure 11.8 shows that this has the effect of pushing either an indirect address or sixteen bits of direct page data onto the stack. For example, if you had stored the value or indirect address $5678 at direct page location $21, then

D421 PEI ($21) push two bytes at dp:$21 and dp:$22

169

The Western Design Center

would get the $5678 from direct page location and push it onto the stack. Like the PEA instruction, the PEI instruction always pushes sixteen bits regardless of the settings of the m memory/accumulator and x index node select flags.

The PER (push effective relative) instruction pushes an effective program counter relative address onto the stack, a capability helpful in writing relocatable code. The operand you specify to the assembler is a location in the program, for example, of a data area; the operand the assembler generates is a sixteen-bit relative displacement, the difference between the nest instruction’s address and the operand address. Figure 11.9 shows that when the instruction is executed, the displacement is added to the next instruction’s run-time address to form the address at which the data is now located it is this address which is pushed onto the stack. If the data location precedes the PER instruction, the assembler generates a very large sixteen-bit displacement which, when added to the program counter value, will wrap around within the program bank to reach the data.

The operation of the PER instruction is similar to the operation of the BRL (branch long) instruction: the branch long operand you specify to the assembler is also a

Instruction:

Opcode

Data Low =

Operand Low

Data High =

Operand High

Stack

Pointer (S) before after

Stack

Data High

Data Low

Bank 0

Figure 11-7 PEA Addressing

170

The Western Design Center

Effective Address:

23

Bank

15

0000 0000

Instruction:

Opcode

65816 Registers:

Bank

23 15

0000 0000

Operand

High Low

7

Direct

Page Register (D

)

0

High

7

+

Low

0

Stack Pointer (S)

Source

Effective Address + 1

Source

Effective Address

High Indirect Address

Low Indirect Address

Bank 0 before after

Stack

High Indirect Address

Low Indirect Address

Bank 0

Figure 11-8 PEI Addressing

171

The Western Design Center

Instruction:

Opcode Operand Low Operand High

15

Register:

7

Program Counter (PC)

0

+ Data

Stack Pointer (S) before after

Stack

Data High

Data Low

Data

Bank 0

Figure 11-9. PER Addressing

location in the program; the operand the assembler generates is also a sixteen-bit displacement; and when the instruction is executed, the displacement is added to the next instruction’s run-time address to form the address to which the program will branch.

To understand the use of the PER instruction, together with the relative branches, in writing a program that will run at any address, suppose that your relocatable program is assembled starting at location $2000. There’s a data area starting at location $2500 called DATA0. A section of program code at $2200 needs to access a byte three bytes past, called DATA1. A simple LDA $2503 would work, but only if the program were intended to always begin at location $2000. If it’s meant to be relocatable, you might load the program at $3000, in which case the data is at $3503 and a LDA $2503 loads the accumulator with random information from what is now a non-program address. Using the instruction

62E17F PER DATA3 push address of DATA3 relative to PC in your source program causes the assembler to calculate the offset from $2203 (from the instruction following the PER instruction at $2200) to DATA1 at $2503, an offset of $300. So the assembler generates object code of a PER opcode followed by $300. Now if the code is loaded at $3000, execution of the PER instruction causes the processor to calculate and stack the current absolute address of DATA1 by adding the operand, $300, to the current program counter location; the result is

$3503, so it’s $3503 that’s stacked. Once on the stack, provided the program and data banks are the same, the data can be accessed using stack relative indirect indexed addressing. Fragment 11.13

contains the example code.

Once the address of DATA1 is on the stack, the values at DATA2 and DATA3 can be accessed as well simply by using values of one and two, respectively, in the Y index register.

172

The Western Design Center

0000

0000

0000

0000 62FD7F

0003 E220

0005 A00000

0008 B301

000A

000A

000A

000A

000A

000A

;

ACCESS

.

.

.

ORG

START

PER

SEP

LDY

LDA

END

$2200

DATA1

#$20

#0

(1,S),Y

0000

0000

0000

0000 2A2A2A

0003 FF

0004 F7

0005 E3

0006

0006

ORG $2500

DATA0 START

DC

DATA1 DC

C’***’

H’FF’

DATA2 DC

DATA3 DC

H’F7’

H’E3’

END push run-time address of DATA1 onto stack set accum to 8-bit mode zero index: DATA1 is cell, not array load accum from DATA1 in data ban

(address of DATA1 @ 1,S & 2,S)

Fragment 11.13

173

The Western Design Center

12) Chapter Twelve

The Basic Building Block:

The Subroutine

The feature essential to any processor to support efficient, compact code, as well as modular or topdown programming methods, is a means of defining a subroutine. A subroutine is a block of code that can be entered (called) repeatedly from various parts of a main program, and that can automatically return control to the instruction following the calling instruction, wherever it may be. The 65x jump-to-subroutine instruction provides just such a capability.

When a jump-to-subroutine, or JSR, instruction is encountered, the processor first pushes its current location onto the stack for purposes of returning, then jumps to the beginning of the subroutine code. At the end of the subroutine code, a return-from-subroutine (RTS) instruction tells the processor to return from the subroutine to the instruction after the subroutine call, which it locates by pulling the previously saved return location from the stack.

Because subroutines let you write a recurring section of program code just once and call it from each place that it’s needed, they are the basis of top-down, structured programming. Common subroutines are often collected together by programmers to form a library, from which they can be selected and reused as needed.

Chapter 8, Flow of Control, introduced the 65x jump instructions – those flow-of-control instructions which do not use the stack for return purposes. But discussion of the jump-to-subroutine instructions was put off to this chapter.

Table 12.1 lists the instructions to be explained in this chapter. In addition, this chapter will use the simple example of a negation routine to illustrate how library routines (and routines in general) are written and documented, and it examines the question of when to code a subroutine and when to use in-line code. Finally, methods of passing information (or parameters) to and from subroutines are compared and illustrated.

Mnemonic

Available on:

65x Subroutine Instructions:

JSR x

RTS

JSL

RTL

6502

x

65C02

x x

65802/816

x x x x

Description

jump to subroutine return from subroutine long jump to subroutine long return from subroutine

Table 12-1 Subroutine Instructions

174

The Western Design Center

The Jump-To-Subroutine Instruction

There is just one addressing mode available to the JSR instruction on the 6502 and 65C02 – absolute addressing. This mode lets you code a subroutine call to a known location. When used on the 65816, that location must be within the current program bank. It uses the absolute addressing syntax introduced earlier:

200020 JSR $2000 jump to subroutine located at pb:$2000 or

200080 JSR SUBR1 jump to subroutine SUBR1 in program bank

In the second case, the assembler determines the address of subroutine SUBR1.

The processor, upon encountering a jump-to-subroutine instruction, first saves a return address. The address saved is the address of the last byte of the JSR instruction (the address of the last byte of the operand), not the address of the next instruction as is the case with some other processors. The address is pushed onto the stack in standard 65x order – the low byte in the lower address, the high byte in the higher address – and done in standard 65x fashion – the first byte is stored at the location pointed to by the stack pointer, the stack pointer is decremented, the second byte is stored, and the stack pointer is decremented again. Once the return address has been saved onto the stack, the processor loads the program counter with the operand value, thus jumping to the operand location, as shown in Figure 12.1. Jumping to a subroutine has no effect on the status register flags.

The Return-from-Subroutine Instruction

At the end of each subroutine you write, the one-byte RTS, or return-from-subroutine, instruction must be coded. When the return-from-subroutine instruction is executed, the processor pulls the stored address from the stack, incrementing the stack

175

The Western Design Center

Effective Address: New Program Counter Value

23

Bank

15

High

7 0

Low

Instruction:

Opcode Operand Low Operand High

65816 Registers:

23

Bank

15

Program Bank (PBR)

High

7

Low

0

Program Counter (PC)

Address of last JSR instruction byte

Return Address High

Return Address Low

Bank 0

Stack before

Stack Pointer after

Figure 12-1 JSR

pointer by one before retrieving each of the two bytes to which it points. But the return address that was stored on the stack was the address of the third byte of the JSR instruction. When the processor pulls the return address off the stack, it automatically increments the address by one so that it points to the instruction following the JSR instruction which should be executed when the subroutine is done. The processor loads this incremented return address into the program counter and continues execution from the instruction following the original JSR instruction, as Figure 12.2 shows.

The processor assumes that the two bytes at the top of the stack are a return address stored by a JSR instruction and that these bytes got there as the result of a previous LSR. But as a result, if the subroutine used the stack and left it pointing to data other than the return address, the RTS instruction will pull two irrelevant data bytes as the address to return to. Cleaning up the stack after using it within a subroutine is therefore imperative.

The useful side of the processor’s inability to discern whether the address at the top of the stack was pushed there by a JSR instruction is that you can write a reentrant indirect jump using the RTS instruction.

First formulate the address to be jumped to, then decrement it by one (or better, start with an alreadydecremented address), push it onto the stack (pushing first high byte, then low byte, so that it is in correct 65x order on the stack) and, finally, code an RTS instruction. The return-from-subroutine pulls the address back off the stack, increments it, and loads the result into the program counter to cause a jump to the location, as

Fragment 12.1 illustrates.

0000

0000 3A

0001 48

0002 60

; 16-bit accumulator holds address of code to jump to

DEC

PHA

RTS

A DEST – 1: address of byte before target push it; now address is stacked as tho JSR pull address; increment it; transfer control

Fragment 12.1

Reentrancy is the ability of a section of code to be interrupted, then executed by the interrupting routine, and still execute properly both for the interrupting routine and for the original routine when control is returned to it. The interruption may be a result of a hardware interrupt (as described in the next chapter), or the

176

The Western Design Center

result of the routine calling itself, in which case the routine is said to be recursive. The keys to reentrancy are, first, to be sure you save all important registers before reentering and, second to use no fixed memory locations in the reentrant code. (There will be more on interrupts and reentrancy in the next chapters.) after

Stack Pointer (S)

before

Stack

PC High

PC Low

Bank 0

+1

Program Counter (PC)

Figure 12-2 RTS

The indirect jump using RTS qualifies for reentrancy: While normally you would code an indirect jump by forming the address to jump to and storing it to an absolute address, then jumping indirect through the address, this jump by use of RTS uses only registers and stack.

A subroutine can have more than one RTS instruction. It’s common for subroutine from internal loops upon certain error conditions, in addition to returning normally from one or more locations. Some structured programming purists would object to this practice, but the efficiency of having multiple exit points is unquestionable.

Returning from a subroutine does not affect the status flags.

JRS Using Absolute Indexed Indirect Addressing

The 65802/65816 gives JSR another addressing mode – absolute indexed indirect (covered in the last chapter) which lets your program select, on the basis of the index in the register, a subroutine location from a table of such locations and call it:

FC0080 JSR (TABLE,X) JSR to indirect address in (TABLE at X)

The array Table must be located in the program bank. The addressing mode assumes that a table of locations of routines would be part of the program itself and would be loaded, right along with the routines, into the bank holding the program. The indirect address (the address with which the program counter will be loaded), a sixteen-bit value, is concatenated with the program bank register, resulting in a transfer within the current program bank. If the addition of X causes a result greater than $FFFF, the effective address will wrap, remaining in the current program bank, unlike the indexing across banks that occurs for data accesses.

This addressing mode also lets you do an indirect jump-to-subroutine through a single double-byte cell by first loading the X register with zero. You must remember in coding this use for the 65816, however, that the cell holding the indirect address is in the program bank, not bank zero as with absolute indirect jumps.

The indexed indirect jump-to-subroutine is executed in virtually the same manner as the absolute jumpto-subroutine: the processor pushes the address of the final byte of the instruction onto the stack as a return address; then the address in the double-byte cell pointed to by the sum of the operand and the X index register is loaded into the program counter.

There is no difference between returning from a subroutine called by this instruction and returning from a subroutine called by an absolute JSR. You code an RTS instruction which, when executed, causes the address on the top of the stack to be pulled and incremented to point to the instruction following the JSR, then to be loaded into the program counter to give control to that instruction.

177

The Western Design Center

The Long Jump to Subroutine

A third jump-to-subroutine addressing mode is provided for programming in the 16-megabyte address space of the 65816 – absolute long addressing. Jump-to-subroutine absolute long is a four-byte instruction, the operand a 24-bit address in standard 65x order (the low byte of the 24-bit address is in the lowest memory location immediately following the opcode and the high byte is next, followed by the bank byte):

22563412 JSR $123456 jump to subroutine at $3456 in bank $12

This time a three-byte (long) return address is pushed onto the stack. Again it is not the address of the next instruction but rather the address of the last byte of the JSR instruction which pushed onto the stack (the address of the fourth byte the JSR instruction in this case). As Figure 12.3 shows, the address is pushed onto the stack in standard 65x order: low byte in the lower address, high byte in the higher address, bank byte in the highest address (which also means the bank byte is the first of the three pushed, the low byte last).

chapter:

Jumping long to a bank zero subroutine requires the greater-than (>) sign, as explained in the last

22563400 JSR >$3456 long jump to subroutine at $3456 in bank 0

The greater-than sign forces long addressing to bank zero, voiding the assembler’s normal assumption to use absolute addressing to jump to a subroutine at $3456 in the current program bank.

To avoid this confusion altogether, there is an equivalent standard mnemonic for jump-to-subroutine long – JSL:

22563400 JSL $3456 long jump to subroutine at $3456 in bank 0 or

22563402 JSL $023456 long jump to subroutine at $3456 in bank 2

Using an alternate mnemonic is particularly appropriate for jump-to-subroutine long, since this instruction requires you to use an entirely different return-from-subroutine instruction – RTL, or return-from-

subroutine long.

Return Address

(last JSR instruction byte)

Stack

Return Address Bank

Return Address High

Return Address Low before after

Stack Pointer (S)

Bank 0

Figure 12-3 JSL

Return from Subroutine Long

The return from subroutine instruction pops two bytes off the stack as an absolute address, increments it, and jumps there. But the jump to subroutine long instruction pushes a three-byte address onto the stack – a

long return address that points to the original code, and is typically in a bank different from the subroutine bank

.

So the 65816 provides a return from subroutine long instruction, RTL. This return instruction first pulls, increments, and loads the program counter, just as RTS does; then it pulls and loads a third byte, the program bank register, to jump long to the return address. This is illustrated in Figure 12.4.

178

The Western Design Center

Branch to Subroutine

One of the glaring deficiencies of the 6502 was its lack of support for writing relocatable code; the 65802 and 65816 address this deficiency, but still lack the branch-to-subroutine instruction some other processors provide. There is no instruction that lets you call a subroutine with an operand that is program counter relative, not an absolute address. Yet, to write relocatable code easily, a BSR instruction is required: suppose a relocatable program assembled at $0 has an often-called multiply subroutine at $07FE; if the program is later loaded at $7000, that subroutine is at $77FE; obviously, a

JSR to $07FE will fail.

Stack Pointer (S) after before

Stack

Program Bank (PBR)

PC High

PC Low

Bank 0

+1

Program Bank (PBR)

Program Counter (PC)

Figure 12-4 RTL

The 65802 and 65816 can synthesize the BSR function using their PER instruction. You use PER to compute and push the current run-time return address; since its operand is the return address’ relative offset

(from the current address of the PER instruction), PER provides relocatability. As Fragment 12.2 shows, once the correct return address is on the stack, a BRA or BRL completes the synthesized BSR operation.

0000

0000

0000

0000 62FC7F

0003 82FA7F

0006

0006

0006

0006

0006

0006

0006

0006

0006

0006 60

RETURN

SUBR1

.

.

.

.

.

.

.

.

.

PER RETURN-1 push run-time return address

BRL SUBR1 intra-bank relative branch is BSR

RTS continue processing here execute subroutine function return from subroutine

Fragment 12.2

In this case, you specify as the assembler operand the symbolic location of the routine you want to return to minus one. Remember that the return address on the stack is pulled, then incremented, before control is passed to it. The assembler transforms the source code operand, RETURN – 1, into the instruction’s object code operand, a relative displacement from the next instruction to RETURN – 1. In this case, the displacement is $0002, the difference between the first byte of the BRL instruction and its last byte.

(Remember, PER works the same as the BRL instruction; in both cases, the assembler turns the location you specify into a relative displacement from the program counter.) When the instruction is executed, the processor adds the displacement

($0002, in this case) to the current program counter address (the address of the BRL instruction); the resulting sum is the current absolute address of RETURN – 1, which is what is pushed onto the stack.

179

The Western Design Center

If at run-time the PER instruction is at $1000, then the BRL instruction will be at $1003, and

RETURN at $1006. Execution of PER pushes $1005 onto the stack, and the program branches to SUBR1.

The RTS at the end of the subroutine causes the $1005 to be pulled from the stack, incremented to $1006 (the address of RETURN), and loaded into the program counter.

If, on the other hand, the instructions are at $2000, $2003, and $2006, then $2005 is pushed onto the stack by execution of PER, then pulled off again when RTS is encountered, incremented to $2006 (the current run-time address of RETURN), and loaded into the program counter.

If a macro assembler is available, synthetic instructions such as this are best dealt with by burying this code in a single macro call.

Coding a Subroutine: How and When

The uses of subroutines are many. At the simplest level, they let you compact in a single location instructions that would otherwise be repeated if coded in-line. Programmers often build up libraries of general subroutines from which they can pluck the routine they want for use in a particular program; even if the routine is only called once, this allows quick coding of commonly used functions.

The next few pages will look at a simple logic function for the 65x processors – forming the negation

(two’s complement) of eight- and sixteen-bit numbers – and how such a routine is written. Also covered is how subroutines in general (and library routines in particular) should be documented.

The 65x processors have no negate instruction, so the two’s complement is formed by complementing the number (one’s complement) and adding one.

6502 Eight-Bit Negation – A Library Example

If the value to be negated is an eight-bit value, the routine in Listing 12.1 will yield the desired result.

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000

0008 0000

0009 0000

0010 0000 46FF

0011 0002 18

0012 0003 6901

0013 0005 60

0014 0006

KEEP KL.12.1

;

; NEGACC - -

; Negate the 8-bit value in the accumulator

; On entry: Value to be negated is in accumulator

; On exit: Value now negated is in accumulator

NEGACC START

EOR

CLC

ADC

RTS

END

#$11111111

#1 form one’s complement prepare to add one add one return

Listing 12.1

It is extremely important to clearly document library routines. Perhaps the best approach is to begin with a block comment at the head of the routine, describing its name, what the routine does, what it expects as input, what direct page locations it uses during execution, if the contents of any registers or any memory special locations are modified during execution, and how and where results are returned.

By documenting the entry and exit conditions as part of the header, as in the example, when the routine is used from a library you won’t have to read the code to get this information. Although this example is quite simple, when applied to larger, more complex subroutines, the principle is the same: document the entry and exit conditions, the function performed, and any side effects.

As a subroutine, this code to negate the accumulator takes six bytes. Each JSR instruction takes three.

So calling it twice from a single program requires 12 bytes of code; if called three times, 15 bytes; if four, 18 bytes.

180

The Western Design Center

On the other hand, if this code were in-line once, it would take only five bytes, but each additional time it is needed would require another five bytes, so using it twice takes 10 bytes, three times takes 15, and four times takes 20. You can see that only if you need to negate the accumulator four or more times does calling as a subroutine make sense in view of object byte economy.

65C02, 65802, and 65816 Eight-Bit Negation

The addition of the accumulator addressing mode for the INC increment instruction on the

65C02, 65802, and 65816 means no subroutine is required for negating an eight-bit value in the accumulator on these processors: the in-line code in Fragment 12.3 takes only three bytes.

0000 49FF

0002 1A

EOR #%11111111

INC A form one’s complement of accum increment the accum by one

Fragment 12.3.

Since the in-line code takes the same number of bytes as the JSR instruction, you would lose four bytes (the number in the subroutine itself) by calling it as a subroutine.

6502 Sixteen-Bit Negation

Negating sixteen-bit values makes even more sense as a subroutine on the 6502. One method, given the previously-coded routine NEGACC, is shown in Listing 12.2.

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000

0008 0000

0009 0000

0010 0000

0011 0000

0012 0000 200080

0013 0003

0014 0003 A8

0015 0004 8A

0016 0005 49FF

0017 0007 6900

0018 0009 60

0019 000A

KEEP KL.12.2

; Negate the 16-bit value in registers X – A (hi-lo)

; On entry: Value to be negated is in X – A (hi-lo)

;

;

; On exit: Value now negated is in A – Y (hi-lo)

X is unchanged must be linked with NEGACC

NEGXA START

; first call the 8-bit negation routine defined a few pages back

JSR NEGACC negate the low 8 bits in the accum

; then get and negate the high 8 bits

TAY

TXA

EOR

ADC

RTS

END get high 8 bits into accum

#%11111111 form one’s complement add carry from adding 1 to low byte return bits).

Listing 12.2

Here, one subroutine (NEGXA) calls another (the subroutine described previously that negates eight

65802 and 65816 Sixteen-Bit Negation

Fragment 12.4 shows that on the 65802 and 65816, the sixteen-bit accumulator can be negated in-line in only four bytes. As a result, a subroutine to negate the sixteen-bit accumulator would be inefficient, requiring five calls to catch up with the on-byte difference; in addition, you should note that there is a speed penalty associated with calling a subroutine – the time required to executed the JSR and RTS instructions.

181

The Western Design Center

0000 49FFFF

0003 1A

EOR

INC

#$FFFF

A form one’s complement of accum increment the accum by one

Fragment 12.4

Parameter Passing

When dealing with subroutines, which by definition are generalized pieces of code used over and over again, the question of how to give the subroutine the information needed to perform its function must be considered. Values passed to or from subroutines are referred to as the parameters of the subroutine.

Parameters can include values to be acted upon, such as two numbers to be multiplied, or may be information that defines the context or range of activity of the subroutine. For example, a subroutine parameter could be the address of a region of memory to work on or in, rather than the actual data itself.

The preceding examples demonstrated one of the simplest methods of parameter-passing, by using the registers. Since many of the operations that are coded are subroutines in assembly language are primitives that operate on a single element, like “print a character on the output device” or “convert this character from binary to hexadecimal,” passing parameters in registers is probably the approach most commonly found.

A natural extension of this approach, which is particularly appropriate for the 65802 and 65816, but also possible on the 6502 and 65C02, is to pass the address of a parameter list in a register (or, on the 6502 and

65C02, in two registers). Listing 12.3 gives example.

182

The Western Design Center

0000

0000

0000

0000

0000

0000

0003

BD0000

F006

200080 0005

0008

0009

E8

80F5

000B 60

000C

000C

0000

0000

0000

0000

0000

0000

0000

0001

0002

0003

0004

0005

48

DA

5A

08

38

FB

0006

0009

20EDFD

18

000A FB

000B 28

000C 7A

000D FA

000E

000F

0010

68

60

0012

0012

0013

0014

0015

0015

0028

003B

003B

0000

0000

0000

0000

0000

0001

0002

0002

0004

0004

18

FB

E220

0004

0006

0006

0006

C210

0009

000C

A21500

2000080

000C A22800

000F 200080

38

FB

60

54686973

54686973

0050

0051

0052

0053

0054

0055

0056

0057

0058

0059

0060

0061

0042

0043

0044

0045

0046

0047

0048

0049

0035

0036

0037

0038

0039

0040

0041

0023

0024

0025

0026

0027

0028

0029

0030

0031

0032

0033

0034

0015

0016

0017

0018

0019

0020

0021

0022

0001

0002

0003

0004

0005

0006

0007

0008

0009

0010

0011

0012

0013

0014

L123

KEEP

65816

START

CLC

XCE

SEP

LONGA

KL.12.3

ON

#$20

OFF

8-bit accumulator

;

;

;

COUT

ECOUT

REP

LONGI

LDX

JSR

LDX

JSR

SEC

XCE

RTS

#$10

ON

#STRING1

PRSTRNG

#STRING2

PRSTRNG

16-bit index register pass the address of STRING1 to PRSTRNG print STRING1 pass the address of STRING2 to PRSTRNG print STRING2

STRING1

STRING2

DC

DC

END

C ’This is string one’, H ‘00’

C ‘This is string two’, H ‘00’

; print a string of characters terminated by a 0 byte

; on entry: X register holds location of string

PRSTRNG

TOP

DONE

START

LDA

BEQ

JSR

INX

BRA

RTS

!0,X

DONE

COUT

TOP get char at index position in string if character is 0, return print character in accum

END

COUT machine-dependent routine to output a character

JSR

CLC

XCE

PLP

PLY

PLX

PLA

RTS

END

START

GEQU

PHA

PHX

PHY

PHP

SEC

XCE

$FDED

ECOUT

Apple / / COUT

Save registers and status, switch to emulation call 6502 routine restore native mode restore status restore register return

Listing 12.3

183

The Western Design Center

By loading the X register with the address of a string constant, the subroutine PRSTRNG has all the information it needs to print the string at that address each time it is called. The data at the address passed in a register could also be a more complex data structure than a string constant.

On the 6502 and 65C02, a sixteen-bit address has to be passed in two registers. Because of this, parameters are often passed in fixed memory locations. Typically, these might be direct page addresses.

Listing 12.4 gives an example of this method.

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

;

PEX

KEEP

6502/65C02 example

START

KL.12.4

0007 0000

0008 0000

0009 0000

0010 0000 A200

0011

0012

0013

0002

0004

0006

8681

A20C

8680

PARAM GEQU

LDX

STX

LDX

STX

$80

#>STRING1 load high byte of STRING1’s address

PARAM+1 store the high byte of direct page cell

#<STRING1 load low byte of STRING1’s address

PARAM store to low byte of direct page cell

PRSTRNG print STRING1 0014 0008 2000080

0015 0008 60

0016 000C

0017 000C 54686973 STRING1 DC

0018 001F

JSR

RTS

END 0019 001F

0020 0000

0021 0000

0022 0000

C ‘This is string one’, H’00’

; print a string of characters terminated by a 0 byte

; on entry: direct page location PARAM holds address of string

0023 0000

0024 0000

0025 0000

0026 0000

0027 0000 A000

0028 0002 B180

0029 0004 F006

0030 0006 20EDFD

0031 0009 C8

0032 000A D0F6

0033 000C 60

0034 000D

0035 000D

0036 000D

PRSTRNG

COUT

LOOP

DONE

START

GEQU

LDY

LDA

BEQ

JSR

INY

BNE

RTS

END

$FDED Apple / / output routine

#0 start at string position zero

(PARAM),Y get char at index position in string

DONE

COUT

LOOP if character is 0, return print character in accum point to next char loop thru string: must be < 256

Listing 12.4

Unfortunately, it takes eight bytes to set up PARAM each time PRSTRNG is called. As a result, a frequently used method of passing parameters to a subroutine is to code the data in-line, immediately following the subroutine call. This technique (see Fragment 12.5) uses no registers and no data memory, only program memory.

184

The Western Design Center

0000

0000

0000 2000080

0003 54686520

001C

001C

001C

001C

001C

REUTRN .

DC C ‘The string to be printed’, H ‘00’ execution continues here

.

.

.

.

.

JSR PRSTRNG print the following string

Fragment 12.5

This method looks, at first glance, bizarre. Normally, when a subroutine returns to the calling section of code, the instruction immediately following the JSR is executed. Obviously, in this example, the data stored at that location is not executable code, but string data. Execution should resume instead at the label RETURN, which is exactly what happens using the PRSTRNG coded in Listing 12.5. The return address pushed onto the stack by the JSR is not a return address at all; it is, rather, the parameter to PRSTRNG

.

185

The Western Design Center

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0001

0008 0002

0009 0002

0010 0004

0011 0004

0012 0004

0013 0006

0014 0006

18

FB

E220

C210

0015 0006

0016 0007

FA

E8

0017 0008 BD0000

0018 000B F006

0019 000D 200080

0020 0010 E8

0021 0011

0022 0013

80F5

0023 0013

0024 0013

0025 0013

0026 0014

0027 0015

0028 0000

0029 0000

0030 0000

0031 0000

0032 0000

0033 0000

0034 0000

DA

60

0035 000

0036 0001

0037 0002

0038 0003

0039 0004

0040 0005

0041 0006

0042 0009 18

0043 000A FB

0044 000B 28

0045 000C 7A

0046 000D FA

0047 000E 68

0048 000F

0049 0010

60

48

DA

5A

08

38

FB

20EDFD

PRSTRNG

KEEP

65816

START

CLC

XCE

KL.12.5

ON

SEP

LONGA

REP

LONGI

#$20

OFF

#$10

ON

8-bit accum

16-bit index regs

LOOP

PLX

INX

LDA

BEQ

JSR

INX

BRA

!0,X

DONE

COUT pull return address and increment to point JSR to string get char at index position in string if character is 0, return print char in accum point to next char loop thru string LOOP

; push pointer to zero-terminator as return addr (RETURN-1)

DONE PHX

RTS

END return to label RETURN

;

;

;

COUT

ECOUT

COUT machine-dependent routine to output a character

XCE

JSR

CLC

XCE

PLP

PLY

PLX

PLA

RTS

END

START

GEQU

PHA

PHX

PHY

PHP

SEC

$FDED

ECOUT

Apple / / COUT

Save registers and status, switch to emulation call 6502 routine restore native mode restore status restore registers return

Listing 12.5

The parameter address on the stack need only be pulled and incremented once, and the data can then be accessed in the same manner as in the foregoing example. Since the loop terminates when the zero end-ofstring marker is reached, pushing its address in the X register onto the stack gives RTS a correct return, value –

RETURN-1 – the byte before the location where execution should resume. Note that the data bank is assumed to equal the program bank.

The advantage of this method is in bytes used: there is no need for any explicit parameter-passing by the calling code, and the JSR mechanism makes the required information available to the subroutine automatically. In fact, for most applications on all four 65x microprocessors, this method uses fewer bytes for passing a single parameter than any other.

One slight disadvantage of this method is that if the string is to be output more than once, it and its preceding JSR must be made into a subroutine that is called to output the string.

186

The Western Design Center

A second disadvantage to this method comes in calling routines to which more than one parameter must be passed. This last example demonstrated how a parameter (the address of the string) can be implicitly passed on the stack. But there is no way to extend the principle so two parameters could be implicitly passed, for instance, to a routine that compares two strings. On the other hand, parameter can also be explicitly passed on the stack. The push effective address instructions and stack-relative addressing modes make this all the easier, as Fragment 12.6 and Listing 12.6 show.

0000

0003

0006

0009

0009

0009

F40080

F40080

200080

.

.

.

PEA

PEA

JSR

STRING1

STRING2

COMPARE push address of STRING1 onto stack push address of STRING2 onto stack compare the two return and continue processing

Fragment 12.6

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000

0008 0000

0009 0000

0010 0000

0011 0000

0012 0001

0013 0001

0014 0003

0015 0003

0016 0005

08

C210

0017 0005

0018 0005 A00000

0019 0008 B303

0020 000A F007

0021 000C D305

0022

0023

000E

0010

0024 0011

0025 0013

0026 0013

D006

C8

80F5

0027 0013

0028 0013

0029 0013

0030 0014

0031 0015

0032

0033

0016

0016

28

18

60

B305

F0F9

F0F9 0034 0018

0035 001A

0036 001A 28

0037 001B 38

0038 001C 60

0039 001D

0040 001D

;

PASS

FAIL

;

; compare two strings of characters, each terminated by a 0 byte

; on entry: locs of strings are stacked just below the return addr

; on exit : carry clear if chars match up to len of shortest string else carry set for no match

COMPARE

KEEP

65816

KL.12.6

ON

START

PHP assume native mode; save status

LOOP

REP

LONGI

SEP

LONGA

LDY

LDA

BEQ

CMP

BNE

INY

BRA

#$10

ON

#$20

OFF

#0

(3,S),Y

PASS

(5,S),Y

FAIL

LOOP get character from first string if zero, end of string: match compare to corresponding char in 2 nd

string branch if not equal; probably failure else do next pair matches shortest string: ok

PLP

CLC

RTS

LDA

BEQ

PLP

SEC

RTS

END

(5,S),Y

PASS restore previous status but clear carry was last failure due to end of string2?

yes; let it pass restore previous status sorry, no good

Listing 12.6

This example, which compares two strings to see if they are equal up to the length of the shorter of the two strings, uses parameters that have been explicitly passed on the stack. This approach, since it explicitly passes the address of the strings, lets them be located anywhere and referred to any number of times. Its

187

The Western Design Center

problem is that when the subroutine returns, the parameters are left on the stack. Clearly, the subroutine should clean up the stack before returning; however, it can’t simply pull the parameters off, because the return address is sitting on top of the stack (which explains why stack offsets of three and five, rather than one and three, are used).

Perhaps the cleanest way to pass parameters on the stack prior to a subroutine call is to decompose the

JSR instruction into two: one to push the return address, the other to transfer to the subroutine. The push effective address instructions again come in handy. Fragment 12.7 shows how the parameters to the routine in

Listing 12.7 are passed.

0000

0000

0000 F4FF7F

0003 F40080

0006 F40080

0009 4C0080

000C

000C

000C

000C

.

.

PEA RETURN-1 push return addr before parameters

PEA STRING1

PEA STRING2 push address of STRING1 onto stack push address of STRING2 onto stack

RETURN .

JMP COMPARE compare them continue processing

.

.

Fragment 12.7

188

The Western Design Center

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000

0008 0000

0009 0000

0010 0000

0011 0000

0012 0000 08

0013 0000

0014 0001 C210

0015 0003

0016 0003

0017 0003 E220

0018 0005

0019 0005

0020 0005 A00000

0021 0008 B301

0022 000A F007

0023 000C D303

0024 000E D007

0025 0010 C8

0026 0011 80F5

0027 0013

0028 0013

0029 0013

0030 0013 28

0031 0014 18

0032 0015 8006

0033 0017

0034 0017 B303

0035 0019 F0F8

0036 001B 28

0037 001C 38

0038 001D

0039 001D FA

0040 001E FA

0041 001F 60

0042 0020

0043 0020

;

KEEP

65816

LDY

LDA

BEQ

CMP

BNE

INY

BRA

LDA

BEQ

PLP

SEC

KL.12.7

ON

; compare two strings of characters, each terminated by a 0 byte

; on entry: locs of strings are at top of stack

;

; return address is stacked just beneath

; on exit: carry clear if chars match up to len of shortest string else carry set for no match

COMPARE START

LOOP

PASS

FAIL

EXIT

PHP

REP

LONGI

SEP

LONGA

PLP

CLC

BRA

PLX

PLX

RTS

END

#$10

ON

#$20

OFF

#0 assume native mode; save status

(1,S),Y get character from first string

PASS if zero, end of string: match

(3,S),Y compare to corresponding char in 2 nd

string

FAIL

LOOP matches shortest string

EXIT

(3,S),Y

PASS bra if not equal; probably failure else do next pair they match up to shortest string; restore status, but clear carry was last failure due to end of string2?

yes, let it pass restore status, but set carry (no match) clean up stack: remove both 16-bit params now return

Listing 12.7

Since the return address was pushed first, the parameter addresses on the stack are accessed via offsets of one and three. Before returning, two pull instructions pop the parameters off the stack, then the RTS is executed, which returns control to the main program with the stack in order.

Passing parameters on the stack is particularly well suited for both recursive routines (routines that call themselves) and reentrant routines (routines that can be interrupted and used successfully both by the interrupting code and the original call) because new memory is automatically allocated for parameters for each invocation of the subroutine. This is the method generally used by most highlevel languages that support recursion.

Fragment 12.8 sets up multiple parameters implicitly passed on the stack by coding after the JSR, not data, but pointers to data. The routine called is in Listing 12.8.

189

The Western Design Center

0000

0000

0000 200080

0003 0080

0005 0080

0007

0007

0007

0007 compare two strings; addresses follow

RETURN .

.

DC A ‘STRING1’ address of STRING1

DC A ‘STRING2’ address of STRING2 continue processing

.

.

.

JSR COMPARE

Fragment 12.8

While this subroutine, unlike the previous one, uses a dozen bytes just getting itself ready to start, each call requires only seven bytes (three for the JSR, and two each for the parameters), while each call to the previous routine required twelve bytes (three PERs at three bytes each plus three for the JMP).

Apple Computer’s ProDOS operating system takes this method a step further: all operating system routines are called via a JSR to a single ProDOS entry point. One of the parameters that follow the JSR specifies the routine to be called, the second parameter specifies the address of the routine’s parameter block.

This method allows the entry points of the internal ProDOS routines to “float” from one version of ProDOS to the next; user programs don’t need to know where any given routine is located

.

190

The Western Design Center

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000

0008 0000

0009 0000

0010 0000

0011 0002

0012 0002

C210

0013 0002

0014 0004

E220

0015 0004

0016 0004

0017 0005

0018 0006

0019 0009

7A

C8

B90000

C8

0020 000A C8

;

COMPARE

0021 000B BE0000

0022 000E C8

0023 000F 5A

0024 0010 A8

0025 0011

0026 0011

0027 0014

0028 0016

0029 0019

B90000 LOOP

F009

DD0000

D006

0030 001B C8

0031 001C E8

0032 001D 80F2

0033 001F 18

0034 0020 60

0035 0021

0036 0024

BD0000

F0F9

PASS

FAIL

0037

0038

0026

0027

0039 0028

0040 0028

38

60 EXIT

KEEP

65816

; compare two strings of characters, each terminated by a 0 byte

; on entry: increment address at top of stack: pts to loc of 1 st

str incr twice more to point to loc of 2 nd

str

START

REP

LONGI

SEP

LONGA

PLY

INY

LDA

INY

INY

LDX

INY

PHY

TAY

LDA

BEQ

CMP

BNE

INY

INX

BRA

CLC

RTS

LDA

BEQ

SEC

RTS

END

KL.12.8

ON

#$10

ON

#$20

OFF

!0,Y

!0,Y

!0,Y

PASS

!0,X

FAIL

LOOP

!0,X

PASS caller must save and restore mode status points to indirect address of 1 load accum with address of 1 point Y to indirect addr of 2 nd load X with address of 2 nd get character from first string if zero, end of string: match compare to corresponding char in 2 nd

string bra if not equal; probably failure else do next pair

string

string point Y to RETURN-1 for RTS and push it onto stack for RTS load Y with address of 1 st

string was last failure due to end of string2?

yes; let it pass sorry, no good now return!

st st

str

string they match up to shortest string;

Listing 12.8

191

The Western Design Center

13) Chapter Thirteen

Interrupts and System Control Instructions

This is the last chapter that introduces new instructions; almost the entire 65816 instruction set, and all of the addressing modes, have been presented. The only instructions remaining are the interrupts and status register control instructions, listed in Table 13.1. This chapter introduces interrupt processing, as well.

Most of the system control functions described are of practical interest only if you are implementing systems programs for the 65x processors, such as operating systems or device handling routines. It is quite possible that if you are programming on an existing machine, with full operating system support, you will have little cause to use many of the system control instructions

.

Mnemonic

BRK

RTI

NOP

SEC

CLC

SED

CLD

SEI

CLI

CLV

SEP

REP

COP

STP

WAI

WDM x x x x x x x

6502

x x x

Available on:

65C02 65802/816

x x x x x x x x x x x x x x x x x x x x x x x x x x

Description

Break (software interrupt)

Return from Interrupt

No operation

Set carry flag

Clear carry flag

Set decimal mode

Clear decimal mode

Set interrupt disable flag

Clear interrupt disable flag

Clear overflow flag

Set status register bits

Clear status register bits

Co-processor or software interrupt

Stop the clock

Wait for interrupt

Reserved for expansion

Table 13-1

. Interrupt and System Control Instructions.

Interrupts

An interrupt, as the name implies, is a disruption of the normal sequential flow of control, as modified by the flow-altering statements such as branches and jump instructions encountered in the stream of code.

Hardware interrupts are generated when an external device causes one of the interrupt pins, usually the IRQ’ or interrupt request pin, to be electrically pulled low from its normally high signal level. The typical application of 65x interrupts is the implementation of an interrupt-driven I/O system, where input-output devices are allowed to operate asynchronously from the processor. This type of system is generally considered to be superior to the alternative type of I/O management system, where devices are polled at regular intervals to determine whether or not they are ready to send or receive data; in an interrupt-driven system, I/O service only claims processor time when an I/O operation is ready for service. Figure 13.1 illustrates how processor time is spent under either system.

192

The Western Design Center

I/O

Service

Polling

Loop

User Task

POLLING

A TIME

INTERRUPT-DRIVEN

I/O

Service

B

User

Task

A TIME

I/O Requested at Times A and B

B

Figure 13-1 I/O Management: Interrupts vs. Polling

Software interrupts are special instructions that trigger the same type of system behavior as occurs during a hardware interrupt.

When an interrupt signal is received, the processor loads the program counter with the address stored in one of the sixteen-bit interrupt vectors in page $FF of bank zero memory, jumping to the (bank zero) routine whose address is stored there. (In the case of the 6502, 65C02, and 65802, “bank zero” refers to the lone 64K bank memory addressable by these processors.) The routine that it finds there must determine the nature of the interrupt and handle it accordingly.

When an interrupt is first received, the processor finishes the currently executing instruction and pushes the double-byte program counter (which now points to the instruction following the one being executed when the interrupt was received) and the status flag byte onto the stack. Since the 6502 and 65C02 have only a sixteen-bit program counter, only a sixteen-bit program counter address is pushed onto the stack; naturally, this is the way the 65802 and 65816 behave when in emulation mode as well. The native-mode 65802 and 65816 must (and do) also push the program counter bank register, since it is changed to zero when control is transferred through the bank zero interrupt vectors.

As Figure 13.2 shows, in native mode the program bank is pushed onto the stack first, before the program counter and the status register: but emulation mode it is lost. This means that if a 65816 program is running in emulation mode in a bank other than zero when an interrupt occurs, there will be no way of knowing where to return to after the interrupt is processed because the original bank will have been lost.

193

The Western Design Center

This unavoidable but fairly esoteric problem can be dealt with in two ways. The first is simply never run in emulation mode outside bank zero. The second solution, which is to store the value of the program counter bank register in a known location before entering the emulation mode with a non-zero program counter bank register, is described later in this chapter.

In addition to pushing the status and program counter information onto the stack, the d decimal flag in the status register is cleared (except on the 6502), returning arithmetic to binary mode. The i interrupt disable flag is set, preventing further interrupts until your interrupt-service routine resets it (it may do this as soon as it is finished saving the previous context) or the routine is exited (with an RTI return-from-interrupt instruction).

Indeed, if the interrupt flag had already been set, the first interrupt would have been ignored as well.

This last feature of disabling interrupts, however, does not apply to a second type of hardware interrupt, called the non-maskable interrupt (or NMI’) for the very reason that it cannot be ignored, even if the i flag is set. NMI’ is triggered by a separate pin on a 65x processor; its use is usually reserved for a single high priority interrupt, such as power failure detection.

Stack Pointer (S) before

6502/65C02/Emulation Mode

Stack

PC High

PC Low

Status (P) after

Program Counter (PC)

Status (P)

Bank 0

Stack Pointer (S) before

65802/65816 Native Mode

Stack

Program Bank (PBR)

PC High

PC Low

Status (P)

Program Bank (PBR)

Program Counter (PC)

Status (P) after

Bank 0

Figure 13-2 Interrupt Processing

Just as the two types of interrupt have their own signals and pins, they also have their own vectors – locations where the address of the interrupt-handling routine is stored. As Table 13.2 shows, on the 65802 and

65816 there are two sets of interrupt vectors: one set for when the processor is in emulation mode, and one set for when the processor is in native mode. Needless to say, the locations of the emulation mode vectors are identical to the locations of the 6502 and 65C02 vectors.

194

The Western Design Center

Emulation mode, e = 1

00FFFE,FF - IRQ/BRK

00FFFC,FD - RESET

00FFFA,FB - NMI

00FFF8,F9 - ABORT

00FFF4,F5 - COP

Native mode, e = 0

00FFEE,EF IRQ

-

00FFEA,EB NMI

00FFE8,E9 ABORT

00FFE6,E7 BRK

00FFE4,E5 COP

Table 13-2 Interrupt Vectors

0009

000C

000C

000C

000C

000C

000C

000C

000F

0010

0010

0011

0011

0000

0000

0000

0000

0003

0004

0005

0007

0009

0009

0009

0009

0009

As you can see in Table 13.2, there are several other vector locations named in addition to IRQ’ and

NMI’. Note that there is no native mode RESET’ vector: RESET’ always forces the processor to emulation mode. Also note that the IRQ’ vector among the 6502 vectors is listed as IRQ’/BRK, while in the

65802/65816 native mode list, each has a separate vector.

The BRK and COP vectors are for handling software interrupts. A software interrupt is an instruction that imitates the behavior of a hardware interrupt by stacking the program counter and the status register, and then branching through a vector location. On the 6502 and 65C02, the location jumped to in response to the execution of a BRK (a software interrupt) and the location to which control is transferred after an IRQ’ (a hardware interrupt) is the same; the interrupt routine itself must determine the source of the interrupt

(that is, either software or hardware) by checking the value of bit five of the processor status register pushed onto the stack. On the 6502 and 65C02 (and the 6502 emulation mode of the 65802 and 65816), bit five is the b break flag. Note first that this is not true of the 65816 native mode, since bit five of its status register is the m memory select flag. Secondly, notice that it is the stacked status byte which must be checked, not the current status byte.

Suppose, for example, that the IRQ’/BRK vector at $00:FFFE.FF contains the address $B100

(naturally, in the low-high order all 65x addresses are stored in), and the code in Fragment 13.1 is stored starting at $B100. When a BRK instruction is executed, this routine distinguishes it from a hardware interrupt and handles each uniquely.

8D1000

68

48

2920

D0F7

4C0C00

AD1000

40

00

;

IRQBRKIN

ORG

START

STA

PLA

PHA

AND

BNE

.

.

.

.

JMP

$B100

SAVEA

#%00010000

ISBRK

RETURN

; handle interrupt caused by BRK instruction

ISBRK

RETURN

.

.

.

LDA

RTI

SAVEA

SAVEA DS 1

END save original accumulator copy p register return it to stack look at bit four only bra if bit 4 set:

BRK caused interrupt else caused by IRQ” reload accum and return do BRK handling code reload saved accumulator return

Fragment 13.1

195

The Western Design Center

The RTI, or return-from-interrupt instruction is similar to the RTS (return-from-subroutine) instruction. RTI returns control to the location following the instruction that was interrupted by pulling the return address off the stack.

Unlike the RTS instruction, however, since the status register was also pushed onto the stack in response to the interrupt, it too is restored, returning the system to its prior state. Further, in the 65802/65816 native mode the RTI instruction behaves like an RTL (return from subroutine long), in that the program counter bank register is also pulled off the stack. This difference makes it critical that the processor always be in the same state when the RTI instruction is executed as it was when it was interrupted. The fact that the 65816 has separate vector groups for native and emulation modes makes this easier to achieve.

There is another key difference between the RTI and the RTS or RTL: RTS and RTL increment the return address after pulling it off the stack and before loading it into the program counter; RTI on the other hand loads the program counter with the stack return address unchanged.

RTI will probably not function correctly in the special case where an interrupt occurred while code was executing in the emulation mode in a non-zero bank: RTI will try to return control to an address within the bank the RTI is executed in, which will probably not be the correct bank because (as on the 6502 and 65C02) the bank address is not stacked. As mentioned earlier, the only way to deal with this is to save the bank address prior to entering emulation mode. When the interrupt handler returns, it should use this saved bank address to execute a long jump to an RTI instruction stored somewhere within the return bank, the long jump will present the program bank address to the correct value before the RTI is executed.

The interrupt handler itself should enter the native mode if interrupts are to be reenabled before exiting in order to avoid the same problem, the return to emulation mode before exiting via the long jump to the RTI instruction.

Concerning the BRK instruction, you should also note that although its second byte is basically a “don’t care” byte – that is, it can have any value - the BRK (and COP instruction as well) is a two-byte instruction, the second byte sometimes is used as a signature byte to determine the nature of the BRK being executed. When an RTI instruction is executed, control always returns to the second byte past the BRK opcode. Figure 13.3

illustrates a stream of instructions in hexadecimal form, the BRK instruction, its signature byte, and location an

RTI returns to. The BRK instruction has been inserted in the middle; after the BRK is processed by a routine

(such as the skeleton of a routine described above), control will return to the BCC instruction, which is the second byte past the BRK opcode.

The fact that the opcode for the BRK instruction is 00 is directly related to one of its uses: patching existing programs. Patching is the process of inserting instruction data in the middle of an existing program in memory to modify (usually to correct) the program without reassembling it. This is a favored method of some programmers in debugging and testing assembly language programs, and is quite simple if you have a good machine-level monitor program that allows easy examination and modification of memory locations. However, if the program to be patched is stored in PROM (programmable read-only memory), the only way to modify a program that has already been “burned-in” is to change any remaining one bits to zeros. Once a PROM bit has been “blown” to zero, it cannot be restored to a one. The only way to modify the flow of control is to insert

BRK instructions – all zeroes – at the patch location and to have the BRK handling routine take control from there.

196

The Western Design Center

LDA $44

A5 44

00 00 90 32

BRK instruction

optional

‘signature byte’

BCC instruction control resumes here

after RTI executed

Figure 13-3Break Signature Byte Illustration

Processing Interrupts

Before an interrupt handling routine can perform a useful task, it must first know what is expected of it.

The example of distinguishing a BRK from an IRQ is just a special case of the general problem of identifying the source of an interrupt. The fact that different vectors exist for different types of interrupts – for example,

NMI would usually be reserved for some catastrophic type of interrupt, like “power failure imminent”, which demanded immediate response – solves the problem somewhat. Typically, however, in an interrupt-driven system there will be multiple sources of interrupts through a single vector. The 65802 and 65816, when in native mode, eliminate the need for a routine to distinguish between IRQ and BRK, such as the one above, by providing a separate BRK vector, as indicated in Table 13.2. Although this does simplify interrupt processing somewhat, it was done primarily to free up bit five in the status register to serve as the native memory select flag, which determines the size of the accumulator.

The interrupt source is generally determined by a software technique called polling: when an interrupt occurs, all of the devices that are known to be possible sources of interrupts are checked for an indication that they were the source of the interrupt. (I/O devices typically have a status bit for this purpose.) A hardware solution also exists, which is to externally modify the value that is apparently contained in the vector location depending on he source of interrupt. The 65816 aids the implementation of such systems by providing a

VECTOR PULL signal, which is asserted whenever the interrupt vector memory locations are being accessed in response to an interrupt.

A simple example of the polling method could be found in a system that includes the 6522 Versatile

Interface Adapter as one of its I/O controllers. The 6522 is a peripheral control IC designed for hardware compatibility with the 65x processor family. The 6522 includes two parallel I/O ports and two timer/counters.

It can be programmed to generate interrupts in response to events such as hardware handshaking signals, indicating that data has been read or written to its I/O ports, or to respond to one of its countdown timers reaching zero. The 6522 contains sixteen different control and I/O registers, each of which is typically mapped to an adjacent address in the 65x memory space. When an interrupt occurs, the processor must poll the

interrupt flag register, shown in Figure 13.4, to determine the cause of the interrupt.

197

The Western Design Center

7 6 5 4 3 2 1 0

IRQ

CB1

TIMER2

TIMER1

CB2

CA1

SHIFT REG

CA2

SET BY

CA2 active edge

CA1 active edge

Complete 8 shifts

CB2 active edge

CB1 active edge

Time-out of T2

Time-out of T-1

Any enabled interrupt

CLEARED BY

Read or write

Reg. 1 (ORA)

Read or write

Reg. 1 (ORA)

Read or write

Shift Reg.

Read or write ORB

Read or write ORB

Read T2 low or write

T2 high

Read T1 low or write

T1 high

Clear all interrupts

Figure 13-4 6522 VIA Interrupt Flag Register

If register zero of the 6522 is mapped to location $FF:B080 of a 65816 system, for example, the interrupt flag register would normally be found at $FF:B08D. The polling routine in Fragment 13.2 would be needed whenever an interrupt occurred. To keep the example simple, assume that only the two timer interrupts are enabled (for example, timer 1 to indicate, in a multi-tasking system, that a given process’ time-slice has expired and the next process must be activated; timer 2, on the other hand, to maintain a time-of-day clock).

198

The Western Design Center

0000

0000 E220

0002

0002

0002 8D1B00

0005 AF8DB0FF

0009 10F5

000B 0A

000C 0A

000D 30F1

000F

000F

000F

000F

000F 90EF

0011

0011

0011

0011

0011

0011

0011

0011 8004

0013

0013

0013

0013

0013

0013

0013 8002

0015

0015

0015

0015

0015

0015

0015 8000

0017

0017

0017

0017

0017

0017 AD1B00

001A 40

001B

001B 00

001C

IRQIN START

SEP

LONGA

STA

LDA

BPL

ASL

ASL

BMI

#$20

OFF

8-bit accumulator

SAVEA

$FFB08D save the accumulator device interrupt register

NEXTDEV branch if bit 7 clear

A

A

TIMER2 check bits 6 & 5 bit 6 to carry, 5 to sign if 5 set, timer2 caused interrupt ;

; timer2 didn’t cause interrupt; timer1?

BCC ERROR interrupt source unknown

; bit 6 set: timer1 caused interrupt

TIMER1

.

.

.

BRA RETURN timer 1 handler code

; bit 5 set: timer2 caused interrupt

TIMER2 .

.

.

BRA RETURN timer 2 handler code

; interrupt not caused by 6522: check other devices code to poll next devices NEXTDEV .

.

.

BRA

ERROR

.

.

.

RETURN LDA

RTI

RETURN

SAVEA error handling code reload saved accumulator and return

SAVEA DS

END

1

Fragment 13.2

When the interrupt flag register is loaded into the accumulator, the first thing to check is whether or not bit seven is set; bit seven is set if any 6522 interrupt is enabled. If it is clear, then the interrupt handler branches to the location NEXTDEV, which polls all other connected I/O devices looking for the interrupt.

If the 6522 was the source of the interrupt, then two shifts move the flag register’s bit six into the carry and bit five into bit seven of the accumulator. Since bit five is set by the time-out of timer 2, if the high-order bit of the accumulator is set (minus), then the source of the interrupt must be timer 2. If timer 2 did not cause the interrupt, then the carry flag is checked; if it’s set, then timer 1 caused the interrupt; if it’s clear, then timer 1 didn’t cause it either, so there has been some kind of error.

199

The Western Design Center

Control is thus assigned to the correct routine to handle the specific source of interrupt.

It is important to note that in both examples in this chapter, the accumulator was saved in memory prior to its use within the interrupt-handling routine. You should further note that in the second example, which is specific to the 65816, only the low-order byte of the accumulator was stored, because the STA SAVEA instruction was executed after the SEP #$20 instruction, which set the accumulator size to eight bits. When the

RTI instruction is executed at the end of the interrupt service routine, the m status flag will be restored to whatever value it had prior to the interrupt. If m was clear and the accumulator was in sixteen-bit mode, the high-order byte will have been preserved throughout the interrupt routine provided that none of the interrupt handling routines switch into sixteen-bit mode; if they do, the high-order part of the accumulator must be saved first, then restored before execution of the RTI.

An important concept related to interrupt handling is that of reentrancy; a reentrant program can be interrupted and literally reentered by the interrupt handling routine and return correct values for both the original invocation and the reentrant call from the interrupt handler. Reentrancy is normally achieved by using no addressable memory – only registers, which may be saved and restored on the stack each time the routine is entered. The stack relative addressing modes simplify the writing of reentrant routines considerably.

Interrupt Response Time

By saving only the essentials – the program counter, program counter bank in 65802/65816 native mode, and status register – and shifting the burden of saving and restoring user registers (those that are actually used) to the programmer of the interrupt-handler, the 65x processors provide maximum flexibility and efficiency. It is quite possible for an interrupt routine to do useful work – such as checking the status of something within the system at periodic intervals – without using any registers.

At either seven or eight cycles per interrupt – the time required to stack the program counter, pc bank, and status register, and then jump through the interrupt vectors – the interrupt response cycle is among the longest-executing 65x instructions. Since an interrupt always lets the current instruction complete execution, there is a possible seven-cycle delay between the receipt of an interrupt and the servicing of one; this delay is called the interrupt latency. Small as the delay is, it can be significant in the servicing of data acquisition and control devices operating in real time, systems in which it is important that interrupts be disabled as little as possible.

It has been the goal of the designers of the 65x series to keep interrupt latency to a minimum. To further reduce interrupt latency, the 65802 and 65816 introduced a special new instruction, the WAI or wait for

interrupt instruction. In an environment where the processor can be dedicated to serving interrupts – that is, where the interrupts provide timing or synchronization information, rather than being used to allow asynchronous I/O operations to be performed – the processor can be put into a special state where it sits and waits for an interrupt to happen. This lets any of the user registers be saved before the interrupt occurs, and eliminates the latency required to complete an existing instruction. Upon execution of a WAI instruction, the processor goes into a very low-power state, signals the outside world that it is waiting by pulling the bidirectional RDY signal low, and sits idle until an interrupt is received. When that occurs, response is immediate since no cycles are wasted completing an executing instruction.

There are two responses to an interrupt after the WAI instruction is executed. The first, as you might expect, is to release the waiting condition and transfer control to the appropriate interrupt vector, as normally takes place whenever interrupts are serviced. The second response is if maskable interrupts (on the IRQ’ line) have been disabled, in which case the normal interrupt processing does not occur. However, since the waiting condition is released, execution continues with the instruction following the WAI opcode. This means that specialized interrupt-synchronization routines can be coded with a one-cycle latency between receipt of interrupt and response.

A second, similar 65802/65816 instruction is the STP or stop the clock instruction. The STP instruction reduces on-chip power consumption to a very low level by stopping the phase two clock input.

Since power consumption of CMOS circuits increases with operating frequency, by halting the clock input the

STP instruction is able to reduce the power consumption of the 65816 to its lowest possible value. Like the

WAI instruction, the STP idles the processor after being executed. Further, the processor I/O buffers are disabled, making the bus available. The processor is powered back up in response to a RESET’ signal being asserted.

200

The Western Design Center

The RESET’ pin is an input similar to the IRQ’ and NMI’ inputs. It is used to perform system initialization or reinitialization. When a 65x system is first powered up, RESET’ must be asserted by external power-up circuitry. It can also be used to let the user force the system into a known state, for example, to break out of an infinite loop.

When RESET’ is asserted, the processor is forced to emulation mode and the registers and status flags are initialized as shown in Table 13.3. Note that the initialization of the index register high bytes to zero is really a function of x being forced to one; x = 1 always clears the high byte of the index registers.

Stack High

Direct Page Register

X Register High

Y Register High

Program Bank Register

Data Bank Register

Status Register

Emulation Flag

01

0000

00

00

00

00 m = 1, x = 1, d = 0, i = 1

1

Table 13-3 Reset Initialization

In addition to the BRK, IRQ’, RESET’, and NMI’ vectors discussed, there are two remaining interrupt-like vectors. These are the COP (co-processor) and ABORT’ vectors. The COP vector is essentially a second software interrupt, similar to BRK, with its own vector. Although it can be used in a manner similar to BRK, it is intended particularly for use with co-processors, such as floating-point processors. Like BRK, it is a two-byte instruction with the second available as a signature byte.

The ABORT’ vector contains the address of the routine which gains control when the 65816 ABORT’ signal is asserted. Prior to transferring control through the ABORT’ vector, the current instruction is completed but no registers are modified. The pc bank, program counter, and status register are pushed onto the stack in the same manner as an interrupt. The ABORT’ signal itself is only available on the 65816; although the 65802 has an ABORT’ vector, it is ineffective since no ABORT’ signal can be generated because of the need for the

65802 to be pin-compatible with the 6502. Typical application of the abort instruction feature is the implementation of hardware memory-management schemes in more sophisticated 65816 systems. When a memory-bounds violation of some kind is detected by external logic, the ABORT'’ signal is asserted, letting the operating system attempt to correct the memory-management anomaly before resuming execution.

Status Register Control Instruction

There are nine instructions that directly modify the flags of the status register; two of them are available only on the 65802 and 65816. These last two are the SEP (set the P status register) and REP (reset P) instructions, which you are already familiar with from their use in the example to set or reset the m and x flags in the status register. They can be used to set or clear any of the flags in the status register. For each bit in the immediate byte that follows the opcode, the corresponding bit in the status register is set or cleared (depending on whether SEP or REP, respectively, was used).

The other seven flag instructions set or clear individual flags in the status register. The pair SEC and

CLC set and clear the carry flag when executed. These should be familiar to you from the chapter on arithmetic, where the CLC is always used before the first of a series of ADC instructions, and SEC before the first of a series of SBC instructions. Likewise, the SED and CLD modes should also be familiar from the same chapter’s discussion of decimal-mode arithmetic; these two instructions set or clear the decimal mode. Note that reset can also affect the decimal flag: it is always initialized to zero on reset on the 65C02, 65802, and

65816; on the other hand, its value is indeterminate after reset on the 6502.

The SEI (set interrupt disable flag) and CLI (clear interrupt disable flag) instructions are new to this chapter: they are used to enable or disable the processor’s response to interrupt requests via the IRQ’ signal. If the SEI instruction has been executed, interrupts are disabled; a CLI interrupt instruction may be used to reenable interrupts. Note that the interrupt disable flag is set automatically in response to an interrupt request, whether a software interrupt or IRQ’, NMI’, or RESET’; this “locks out” other interrupts from occurring until

201

The Western Design Center

the current one has been serviced. Similarly, the interrupt disable flag is cleared automatically upon return from an interrupt via RTI due to reloading of the stacked status register, which was pushed with i clear.

The SEI lets interrupts be locked out during critical routines which should not be interrupted. An example would be a device controller that depended on software timing loops for correct operation; interrupts must be locked out for the duration of the timing loop. It is important in an environment where interrupts are supported that they not be locked out for long periods of time. Although the CLI instruction will explicitly clear the interrupt disable flag, it is rarely used because typically the processor status is saved before execution of an SEI instruction as in Fragment 13.3, which reclears the flag by restoring the entire processor status register

.

0000 08

0001 78

0002

0002

0002

0002 28

.

.

.

PHP

SEI

PLP save status disable interrupts execute time-critical code done – restore status, enable interrupts

Fragment 13.3

Since the interrupt disable flag was clear when the PHP instruction was executed, the PLP instruction restores the cleared flag. This same technique is also useful when mixing subroutine calls to routine with different default modes for accumulator and index register sizes; since saving the status with PHP is a common operation between subroutine calls anyway, the PLP instruction can be used to conveniently restore operating modes as well as status flags.

Finally, there is a CLV (clear overflow flag). There is no corresponding set overflow instruction, and, as you will recall from the chapter on arithmetic, the overflow flag does not need to be explicitly cleared before a signed operation. The arithmetic operation always change the overflow status to correctly reflect the result.

The reason for including an explicit CLV instruction in the 65x repertoire is that the 6502, 65C02, and 65802 have a SET OVERFLOW input signal; external hardware logic can set the overflow flag of the status register by pulling the SET OVERFLOW input low. Since there is no corresponding clear overflow input signal, the overflow must be cleared in software in order to regain susceptibility to the SET OVERFLOW signal.

The practical application of the SET OVERFLOW signal is generally limited to dedicated control applications; it is rarely connected on general-purpose, 6502-based computer systems. On the 65816, there is no SET OVERFLOW input; it was sacrificed to make room for some of the more generally useful new signals available on the 65816 pin configuration.

No Operation Instructions

The final two instructions to complete the 65816 instruction set are the no operation instruction. These do exactly what they sound like: nothing. They are used as place holders, or time-wasters; often they are used to patch out code during debugging. The NOP instruction – with a hexadecimal value of $EA – is the standard no operation.

As mentioned in the earlier architecture chapters, the 6502 and 65C02 have a number of unimplemented instructions – the same opcodes which, on the 65802 and 65816, correspond to the new instructions. On the

6502, the operation of the processor when these “instructions” are executed is undefined; some of them cause the processor to “hang-up.” On the 65C02, these are all “well-behaved” no-operations of either one, two, or more cycles. On the 65802 and 65816, there is only one unimplemented instruction, defined as WDM; this is reserved for future systems as an escape prefix to expand the instruction set with sixteen-bit opcodes. For this reason, it should not be used in your current programs, as it will tend to make them incompatible with future generations of the 65816.

202

The Western Design Center

Part 4

Applications

203

The Western Design Center

14) Chapter Fourteen

Selected Code Samples

This chapter contains five different types of example programs, which are examined in detail. Each focuses on a different topic of interest to the 65x programmer: multiplication and division algorithms; a 65802to-6502 mode-switching tour de force; a quick utility routine to determine which 65x processor a program is running under; high-level languages; and a popular performance benchmark.

Multiplication

Probably the most common multiply routine written for eight-bit applications is to multiply one sixteenbit number by another, returning a sixteen-bit result. While multiplying two large sixteen-bit numbers would yield a 32-bit result, much of systems programming is done with positive integers limited to sixteen bits, which is why this multiply example is so common. Be aware that a result over sixteen bits cannot be generated by the examples as coded – you’ll have to extend them if you need to handle larger numbers.

There are several methods for the sixteen-by-sixteen multiply, but all are based on the multiplication principles for multi-digit numbers you were taught in grade school: multiply the top number by the right-most digit of the bottom number; move left, digit by digit, through the bottom number, multiplying it by the top number, each time shifting the result product left one more space and adding it to the sum of the previous products:

2344

X

12211

2344

2344

4688

4688

2344

28622584

Or to better match the description:

2344

X

12211

2344

+ 2344

25784 sum of products so far

+ 4688

494584 sum of products so far

+ 4688

5182584 sum of products so far

+ 2344

28622584 final product (sum of all single-digit multiplies)

204

The Western Design Center

Binary multiplication is no different, except that, since each single-digit multiply is by zero or one, each resulting single-digit product is either the top number itself or all zeroes.

101

x 1010

000 5

101 x 10

000

101 5

0

110010 50 decimal

To have the computer do it, you have it shift the bottom operand right; if it shifts out a zero, you need do nothing, but if it shifts out a one, you add the top number to the partial product (which is initialized at zero).

Then you shift the top number left for the possible add during the next time through this loop. When there are no more ones in the bottom number, you are done.

6502 Multiplication

With only three eight-bit registers, you can’t pass two sixteen-bit operands to your multiply routine in registers. One solution, the one used below, is to pass one operand in two direct page (zero page) bytes, while passing the other in two more; the result is returned in two of the 6502’s registers. All this is carefully documented in the header of the routine in Listing 14.1.

This 6502 multiply routine takes 33 bytes.

65C02 Multiplication

With the same three eight-bit registers as the 6502, and an instruction set only somewhat enhanced, the

65C02 multiply routine is virtually the same as the 6502s. Only one byte can be saved by the substitution of an unconditional branch instruction for the jump instruction, for a total byte count of 32.

65802 and 65816 Multiplication

The 65802 and 65816, when running in native mode, have three registers, all of which can be set to sixteen bits, in addition to having many more addressing modes. As you might expect, a multiply routine for these processors is considerably shorter than the 6502 and 65C02. What you might not expect is how much shorter: the multiply routine in Listing 14.2 for the 65802 ands 65816 takes only 19 bytes – its length is less than 60 percent of each of the other two routines!

Notice the additional documentation at the beginning of the routine. The processor must have both its index registers and its accumulator in sixteen-bit modes before calling this routine.

205

The Western Design Center

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000

0008 0000

0009 0000

0010 0000

0011 0000

0012 0000

0013 0000

0014 0000 A200

0015 0002 A000

0016 0004

0017 0004 A580

0018 0006 0581

0019 0008 F016

0020 000A 4681

0021 000C 6680

0022 000E 9909

0023 0010 18

0024 0011 98

0025 0012 6582

0026 0014 A8

0027 0015 8A

0028 0016 6583

0029 0018 AA

0030 0019

0031 0019 0682

;

;

;

;

;

MULT

MCAND2

MULT1

MULT2

0032 001B 2683

0033 001D 4C0400

0034 0020

0035 0020 60

0036 0021

0037 0021

DONE

KEEP

START

GEQU

LDX

LDY

LDA

ORA

BEQ

LSR

ROR

BCC

CLC

TYA

ADC

TAY

TXA

ADC

TAX

ASL

ROL

JMP

RTS

END

KL.14.1

16 by 16 = 16-bit multiply for 6502 microprocessor operand 1: sixteen bits in direct page loc MCAND1/MCAND1+1 operand 2: sixteen bits in direct page loc MCAND2/MCAND2+2 result: returned in X-Y (hi – lo) all original register values are destroyed

MCAND1 GEQU $80

$82

#0

#0 initialize result (hi) initialize result (lo)

MCAND1 operand 1 (lo)

MCAND1+1 operand hi (hi); if 16-bit operand 1 is 0, done

DONE

MCAND1+1 get right bit, operand 1

MCAND1

MULT2

MCAND2

MCAND2+1

MCAND2

MCAND2+1

MULT1 if clear, no addition to previous products else add oprd 2 to partial result now shift oprd 2 left for poss. add next iteration

Listing 14.1

206

The Western Design Center

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000

0008 0000

0009 0000

0010 0000

0011 0000

0012 0000

0013 0000

0014 0000

0015 0000 18

0016 0001 FB

0017 0002 C230

0018 0004

0019 0004

0020 0004

0021 0004

0022 0004 A90000

0023 0007

0024 0007 A680

0025 0009 F00B

0026 000B 4680

0027 000D 9003

0028 000F 18

0029 0010 6582

0030 0012

0031 0012 0682

0032 0014 80F1

0033 0016

0034 0016 38

0035 0017 FB

0036 0018 60

0037 0019

KEEP

65816

KL.14.2.

ON

; 16 by 16 = 16 multiply

; for 65802/65816 microprocessors in native mode with

; index registers and accumulator already set to 16 bits

; operand 1: sixteen bits in direct page location MCAND1

; operand 2: sixteen bits in direct page location MCAND2

; result: sixteen bits returned in accumulator

MULT START

MCAND1 GEQU

MCAND2 GEQU

$80

$82

CLC

XCE

REP #$30

LONGA ON

LONGI ON

MULT1

MULT2

DONE

LDA

LDX

BEQ

LSR

BCC

CLC

ADC

ASL

BRA

SEC

XCE

RTS

END tell assembler about index & accum settings

#0 initialize result

MCAND1 get operand 1

DONE if operand 1 is zero, done

MCAND1 get right bit, operand 1

MULT2 if clear, no addition to previous products else add oprd 2 to partial result

MCAND2

MCAND2 now shift oprd 2 left for poss add next time

MULT1

Listing 14.2

207

The Western Design Center

Along the same lines, notice that the first two lines of the subroutine are the mode directives – LONGA

ON and LONGI ON – which inform the assembler that all three registers have been set to sixteen bits. That way, when the accumulator is loaded with immediate zero, the assembler will generate a sixteen-bit operand rather than an incorrect eight-bit one, which would cause program failure when executed.

The RTS instruction is the intra-bank return instruction. An RTL instruction could be substituted if the subroutine were intended to be called only by long jump-to-subroutine instructions, whether by code outside the bank or by code within it. You should document such a requirement in the routine’s introductory comments.

Division

Probably the most common division routine written for eight-bit applications is the converse of the multiply routine just covered – to divide one sixteen-bit number by another sixteen-bit number, returning both a sixteen-bit quotient and a sixteen-bit remainder.

There are several methods for doing this, but all are based on the division principles for multi-digit numbers that you learned in grade school. Line up the divisor under the left-most set of digits of the dividend, appending an imaginary set of zeroes out to the right, and subtract as many times as possible. Record the number of successful subtractions; then shift the divisor right one place and continue until the divisor is flush right with the dividend, and no more subtractions are possible. Any non-subtractable value remaining is called the remainder.

12211 remainder 1

2344 28622585

- 2344

5182585

-2344

2838585

-2344

494585

-2344

260185

-2344

25785

-2344

2345

-2344

1

Binary division is even easier since, with only ones and zeroes, subtraction is possible at each digit position either only once or not at all:

1100 remainder 1

101 111101

-101

10101

-101

01

12 remainder 1

5 61

-5

11

-5

6

-5

1

208

The Western Design Center

Many programs calling this division routine will need only the quotient or only the remainder, although some will require both. The routines here return both.

6502 Division

The 6502, with its three eight-bit registers, handles passing parameters to and from a division routine even less smoothly than to and from a multiplication routine: not only do you need to pass it two sixteen-bit values, but it needs to pass back two sixteen-bit results.

The solution used in Listing 14.3 is to pass the dividend and the divisor in two direct page double bytes, then pass back the remainder in a direct page double byte and the quotient in two registers.

209

The Western Design Center

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000

0008 0000

0009 0000

0010 0000

0011 0000

0012 0000

0013 0000

0014 0002 A900

0015 0003 AA

0016 0004 48

0017 0006 A001

0018 0008 A582

0019 000A 300B

0020 000A C8

0021 000B 0682

0022 000D 2683

0023 000F 3004

0024 0011 C011

0025 0013 D0F5

0026 0015

0027 0015 38

0028 0016 A580

0029 0018 E582

0030 001A 48

0031 001B A581

0032 001D E583

0033 001F E583

0034 0021

0035 0021 8581

0036 0023 68

0037 0024 8580

0038 0026 48

0039 0027 68

0040 0028 68

0041 0029 2A

0042 002A 48

0043 002B 8A

0044 002C 2A

0045 002D AA

0046 002E 4683

0047 0030 6682

0048 0032 88

0049 0033 D0E0

0050 0035

0051 0035 68

0052 0036 60

0053 0037

0054 0037

DIV

DIVDND

DIVSOR

DIV1

DONE

KEEP

LDA

TAX

PHA

LDY

LDA

BMI

INY

ASL

ROL

BMI

CPY

BNE

KL.14.3.

; 16 divided by 16 = 16 divide for 6502 microprocessor

; divide DIVDND / DIVSOR

XA (hi – lo); remainder in DIVDND

; DIVDND and DIVSOR are direct page double byte cells

; no special handling for divided by zero (returns $FFFF quotient)

START

GEQU

GEQU

PLA

RTS

END

$80

$82

#0

#1

DIVSOR initialize quotient (hi) initialize quotient (lo) initialize shift count = 1 get high byte of divisor

DIV2 bra if divisor can’t be shifted left else shift divisor to leftmost position

DIVSOR

DIVSOR+1 test divisor

DIV2

#17

DIV1 done if divisor in leftmost position max count (all zeroes in divisor) loop if not done

DIV2 SEC

LDA

SBC

PHA

DIVDND

DIVSOR now do division by subtraction subtract divisor from dividend low bytes first save to difference temporarily on stack

LDA

SBC

BCC

DIVDND+1 then subtract high bytes

DIVSOR+1

DIV3

; else carry is set to shift into quotient bra if can’t subtract divisor from dividend

DIV3

STA

PLA

STA

PHA

PLA

PLA

ROL

PHA

TXA

ROL

TAX

DIVDND+1 store high byte of difference get low subtract result from stack

DIVDND restore low subtract result

→ stack for pull throw away low subtract result

A

A bet quotient low byte from stack shift carry

→ quotient (1 for divide, 0 for not) put back on stack get quotient high byte continue shift

→ quotient (high) put back in x

LSR

ROR

DEY

BNE

DIVSOR+1 shift divisor right for next subtract

DIVSOR decrement count

DIV2 branch unless done (count is 0) get quotient (lo)

Listing 14.3

210

The Western Design Center

The label DONE is not needed (there is no branch to the location), but was added for clarity.

The routine at DIV2 may seem curious. The 6502 has no sixteen-bit compare; to compare two sixteenbit numbers, you must actually subtract them (setting the carry first, as is required before a subtract using the

65x SBC instruction). So the divisor is subtracted from the dividend, with the low result saved on the stack. If the carry is clear, the divisor is too large to be subtracted from the dividend. Thus a branch is taken to DIV3, where the low result is pulled but not used and the cleared carry is rolled into the quotient to acknowledge the unsuccessful subtraction. If the carry is set, then the high result, still in the accumulator, is stored, and the low result is pulled from the stack, stored, then restacked to be repulled atDIV3; since the carry is known to be set, it does not need to be explicitly set before rolling it into the quotient to acknowledge the successful subtraction.

The quotient is returned in register X and A.

This 6502 divide routine takes 55 bytes.

65C02 Division

The 65C02 routine is virtually the same; only three early instructions (shown in Fragment 14.1) in the

6502 routine are changed to the code in Fragment 14.2, for a net savings of one byte, because the 65C02 has instructions to push the index registers. This 65C02 divide routine takes 54 bytes, one byte fewer than the 6502 divide routine takes.

0000 A900

0002 AA

0003 48

LDA

TAX

PHA

#0

Fragment 14.1

0000 A200

0002 DA

LDX

PHX

#0

Fragment 14.2

65802/65816 Division

The 65802 and 65816 processors, with their registers extendable to sixteen bits, can handle sixteen-bit division with ease. In the divide routine in Listing 14.4, the dividend and the divisor are passed in sixteen-bit registers X and A respectively; the quotient is passed back in a sixteen-bit direct page location and the remainder in X.

211

The Western Design Center

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000

0008 0000

0009 0000

0010 0000

0011 0000

0012 0000

0013 0001

0014 0002

0015 0004

0016 0004

0017 0004

0018 0004

0019 0004 6480

0020 0006 A00100

0021 0009

0022 0009 0A

0023 000A B006

0024 000C C8

0025 000D C01100

0026 0010 D0F7

0027 0012

0028 0012 6A

0029 0013

0030 0013

0031 0013 48

0032 0014 8A

0033 0015 38

0034 0016 E301

0035 0018 9001

0036 001A AA

0037 001B

0038 001B 2680

0039 001D 68

0040 001E 4A

0041 001F 88

0042 0020 D0F1

0043 0022

0044 0022

0045 0023

0046 0024 60

0047 0025

DIV1

DIV2

KEEP

65816

; 16 divided by 16 = 16 divide for 65802/65816 microprocessor

; 16-bit divide: X /A

QUOTNT; remainder in X

; QUOTNT is a 16-bit direct page cell

; native mode: all registers set to 16-bit modes

; no special handling for divide by zero (returns $FFFF quotient)

DIV START

QUOTNT GEQU

LONGA

LONGI

STZ

LDY

ASL

BCS

INY

CPY

BNE

ROR

$80

ON

ON

QUOTNT

#1

A

DIV2

#17

DIV1

A

; now divide by subtraction

DIV4 PHA

TXA

SEC

DIV3

SBC

BCC

TAX

ROL

PLA

LSR

DEY

BNE

RTS

END

KL.14.4

ON

1,S

DIV3 tell assembler about 16-bit index & accumulator setting initialize quotient to 0 initialize shift count to 1 shift divisor: test leftmost bit branch when get leftmost bit else increment shift count max count (all zeroes in divisor) loop if not done put shifted-out bit back push divisor get dividend into accumulator subtract divisor from dividend bra if can’t subtract; dividend still in X store new dividend; carry=1 for quotient

QUOTNT shift carry

→ quotient (1 for divide, 0 for not) pull divisor

A shift divisor right for next subtract

DIV4 decrement count branch to repeat unless count is 0

Listing 14.4.

212

The Western Design Center

This divide routine for the 65802 and 65816 generates only 31 bytes, little more than half the bytes the

6502 and 65C02 divide routines generate.

As the introductory comments note, it requires the processor to be in native mode and the m and x memory select flags to be in sixteen-bit modes before the routine is called; these requirements become doubly obvious when you see in another of the comments that the values passed in the accumulator and an index register are sixteen bits, with one of the two sixteen-bit results being passed back in one of the same registers.

Assemblers, however, do not read comments; they only read instructions and directives. That’s the reason for the LONGA ON and LONGI ON directives at the beginning of the routine.

Calling an Arbitrary 6502 Routine

Particularly during the early phases of the processor’s life cycle, you might wish to mix existing 6502 code with your 65816 applications. The routine provided below provides a general purpose way of doing this.

Additionally, the context-saving code illustrated here could prove useful in other applications. You’ll find similar code in the debugger in the next chapter, where it is needed to save the context between instructions of the user program being traced.

The simplest way to call a 6502 routine from the 65802 or 65816 is found in Fragment 14.3.

0000 38

0001 FB

0002 200080

SEC

XCE

JSR D06502

Fragment 14.3

Although this will work fine in some cases, it is not guaranteed to. In order to be assured of correct functioning of an existing 6502 routine, the direct page register must be reset to zero and the stack pointer must be relocated to page one. Although a 6502 program that uses zero page addressing will technically function correctly if the direct page has been relocated, the possibility that the zero page may be addressed using some form of absolute addressing, not to mention the probability that an existing 6502 monitor or operating system routine would expect to use values previously initialized and stored in the zero page, requires that this register be given its default 6502 value.

If the stack has been relocated from page one, it will be lost when the switch to emulation mode substitutes the mandatory stack high byte of one. So first, the sixteen-bit stack pointer must be saved. Second, if the 65802/65816 program was called from a 6502 environment, then there may be 6502 values on the original

6502 page-one stack; such a program must squirrel away the 6502 stack pointer on entry so it can be restored on exit, as well as used during temporary incursions, such as this routine, into the 6502 environment.

The goal, then, is this: provide a mechanism whereby a programmer may simply pass the address of a resident 6502 routine and any registers required for the call to a utility which will transfer control to the 6502 routine; the registers should be returned with their original (potentially sixteen-bits) values intact, except as modified by the 6502 routine; and finally the operating mode must be restored to its state before the call.

When loading the registers with any needed parameters, keep in mind that only the low-order values will be passed to a 6502 subroutine, even though this routine may be entered from either eight- or sixteen-bit modes.

The call itself is simple; you push the address of the routine to be called, minus one, onto the stack, typically using the PEA instruction. Then you call the routine, which executes the subroutine call and manages all of the necessary housekeeping. Fragment 14.4 gives an example of calling the routine

.

213

The Western Design Center

0000 A94100

0003 F4ECFD

0006 200080

LDA

PEA

JSR

#’A’

$FDED-1

JSR6502

Fragment 14.4

character to be printed routine to be called

$FDED is the address of an existing Apple I I routine to print charact4ers, and JSR6502 is the routine described in Listing 14.5.

214

The Western Design Center

0036 001D 850C

0037 001F A501

0038 0021

0039 0021

0040 0021 F40000

0041 0024 2B

0042 0025

0043 0025

0044 0025 38

0045 0026 FB

0046 0027

0047 0027

0048 0027

0049 0027

0050 0027 60

0051 0028

0052 0028

0053 0028

0054 0028 08

0055 0029 EB

0056 002A 68

0057 002B 2B

0058 002C

0059 002C

0060 002C

0061 002C

0062 002C

0063 002C

0064 002C

0065 002C

0066 002C

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000

0008 0000

0009 0000 08

0010 0001

0011 0001 C230

0012 0003

0013 0003

0014 0003

0015 0003 DA

0016 0004 5A

0017 0005 0B

0018 0006 48

0019 0007

0020 0007

0021 0007 38

0022 0008 5B

0023 0009 2900FF

0024 000C C90001

0025 000F F004

0026 0011 AD4F00

0027 0014 1B

0028 0015 0B

0029 0016

0030 0016

0031 0016

0032 0016

0033 0016 F42700

0034 0019 D40C

0035 001B A50A

JSR6502

KEEP

65816

START

KL.14.5

ON

; used by 65816 program called by 6502 code before moving stack

PHP save flags, including register sizes

REP #$30

LONGA ON

LONGI ON

PHX

PHY

PHD

PHA set all registers to 16 bits then push them push index regs push direct page base push accum

; set up page-1 stack ptr, saving 65802 stack ptr in DP & on new stack

TSC save old stack pointer in

TCD

AND #$FF00 direct page register mask stack pointer to examine high byte

CMP

BEQ

LDA

TCS

USESTK PHD

#$100

USESTK

STK6502 branch if stack already in page 1 else retrieve safe 6502 stack pointer and load stack pointer with it push old stack pointer onto new stack

; set up a return-to-this-code return address on new stack

; (direct page register points to old stack with orig accum at 1)

PEA

PEI

LDA

STA

LDA

RETURN-1

(12)

10

12

1 push local return address (out exit code) push routine addr from prev stack onto this one shuffle return address to bottom of old stack restore accum from prev stack using dp reg

; set direct page to zero page

PEA 0

PLD

; switch to emulation mode

SEC

XCE

LONGA OFF

LONGI OFF

; and call 6502 routine

RTS set direct page to zero page switch to emulation mode

JSR (via RTS) to 6502 routine @ stacked addr

;

; 6502 routine returns here

RETURN PHP

XBA

PLA

PLD now save returned flag results from 6502 code save returned A accum in B accum get flags into A accum get old stack pointer

;

;

;

;

;

; address old stack values as direct page:

;

; dp (stack) offset 12.13 = return address back to 65802/65816 code

10.11 = unused (orig held addr of 6502 routine)

9 = orig P flags

7.8 = orig 16-bit X

5.6 = orig 16-bit Y

3.4 = orig DP

1.2 = orig 16-bit accum

215

The Western Design Center

0067 002C

0068 002C

0069 002C

0070 002C 29CF

0071 002E 850B

0072 0030 A509

0073 0032 2930

0074 0034 050B

0075 0036 850B

0076 0038

0077 0038

0078 0038

0079 0038 EB

0080 0039 8501

0081 003B 8405

0082 003D 8607

0083 003F

0084 003F 18

0085 0040 FB

0086 0041

0087 0041 C230

0088 0043

0089 0043

0090 0043

0091 0043 0B

0092 0044 FA

0093 0045 9A

0094 0046

0095 0046

0096 0046

0097 0046 68

0098 0047 8509

0099 0049

0100 0049

0101 0049

0102 0049 2B

0103 004A 7A

0104 004B FA

0105 004C 68

0106 004D 28

0107 004E

0108 004E 60

0109 004F

0110 004F 8001

0111 0051

0112 0051

0113 0051

0114 0051

0115 0051

;

; combine returned condition flags with 65802/816 mode flags

AND #%11001111 mask out m & x flags

STA

LDA

11

9 save for a minute; dp:11 is free get orig P value

AND

ORA

STA

#%00110000 mask out all but m & x flags

11 combine new condition flags with old m & x

11

; 9.10 in old stack now free store new P @ 11

; pull registers from stack

PLD

PLY

PLX

PLA

PLP

END

0 = was next available stack location

; save registers returned from 6502 routine

XBA

STA

STY

STX

1

5

7 swap: 6502 accum back to A save returned accumulator low save returned Y low save returned X low

CLC

XCE

REP #$30

LONGA ON

LONGI ON

PHD

PLX

TXS

; but still address old stack via direct page

PLA

STA 9

; stack was moved by PLA, but DP was not copy accum to free stack bytes @ dp:9.10.

RTS

;

;

;

STK6502 DC A’$180’ restore native mode extend register size back to 16 bits restore old stack pointer restore old direct page load accumulator again get 6502 condition flags; 65802/816 modes done!

arbitrary ‘safe’ stack in page one smart user will store last page one stack value here before switching stack out of page one

Listing 14.5

The routine is entered with the return address on the top of the stack, and the go-to address of the 6502 routine at the next location on the stack. Since you want to be able to restore the m and x mode flags, the first thing the routine does is push the status register onto the stack. The REP #$30 instruction, which follows, puts the processor into a known state, since the routine can be called from any of the four possible register-size modes. The long accumulator, long index mode is the obvious choice because it encompasses all the others.

The user registers, including the direct page register, are saved on the stack, and then the stack pointer itself is saved to the direct page register via the accumulator. This has two benefits: it preserves the value of the old stack pointer across a relocation of the stack, and provides a means of accessing all of the data on the old stack after it has been relocated. This technique is of general usefulness, and should be understood clearly. Figure

14.1, which shows the state of the machine after line 0034 (the PEI instruction), helps make this clear.

The stack must be relocated to page one only if it is not already there. If it is elsewhere, then the last

6502 page-one stack pointer should be restored from where it was cubbyholed when the 65802/65816 program

216

The Western Design Center

took control and moved the stack elsewhere. If there is no previous 6502 stack to avoid, any page one address could be used to initialize the temporary 6502 stack needed.

The first item that goes onto the new stack is the value of the old stack pointer, now found in the direct page register. Next, a local return address must be pushed on the stack for when the called 6502 routine executes an RTS.

While the direct page register was pushed onto the new stack, it retains its value, and still points to the old stack; so although the stack pointer has been relocated, you still have access to the values on the old stack via direct page addressing. One of the needed items is the go-to address, the address of the 6502 routine to be called. Since the size of all of the elements pushed on the stack is known, by referencing the direct page location 12, this value is retrieved. A PEI (push indirect) instruction is used to transfer the routine to be called from the old stack (now being referenced via the direct page) to the new stack. This frees up the double byte on the old stack dp:12.13, the bottom of the old stack; the return address is shuffled in from dp:10.11, freeing those two bytes.

217

The Western Design Center

OLD

STACK

POINTER

RETURN

ADDRESS

ADDRESS

OF

6502 ROTUINE

XH

XL

YH

YL

DPH

DPL

AH

AL

FD

EC

C3

4F

P

ADDRESS OF

6502 ROUTINE

RETURN

ADDRESS

P REGISTER

X REGISTER

Y REGISTER

DIRECT PAGE

ACCUMULATOR

40

20

30

4D

FD

EC

$4020

STACK

POINTER

STACK

DIRECT

PAGE

(OLD STACK)

Figure 14-1 Stack Snapshot after PEI (12) Instruction

The accumulator was used during these operations, and must be restored because it may contain one of the parameters required by the 6502 routine. Like the go-to address, the accumulator is loaded from the old stack using direct page addressing.

Having restored the accumulator, all that remains is to set the direct page register to zero; since no registers can be modified at this point, this is accomplished by pushing a zero onto the stack, and then pulling it into the direct page register.

When you switch the processor into emulation mode, the environment is as it should be; the new stack is now set up to transfer control to the 6502 subroutine via the execution of an RTS instruction which, rather than exiting the JSR6502 routine, performs a kind of jump indirect to the value on top of the stack, the go-to address. The use of the RTS to transfer control to the 6502 routine is the reason the address minus one is put on the stack to begin with. This requirement could be eliminated if the go-to address was decremented before being pushed on the page one stack; but this would require the execution of two additional instructions, one to load it into a register, and one to decrement. PEI moves the value directly onto the stack from the direct page.

218

The Western Design Center

When control returns from the 6502 routine, the flags, representing the 6502 routine’s results, are pushed, then pulled into the eight-bit A accumulator after its value has been saved by transferring it to the B accumulator with an XBA. The only other item left on the new stack is the old stack pointer. This is pulled into the direct page register, which immediately restores access to all of the values pushed onto the old stack.

The condition code bits in the returned status register are merged with the mode flags in the original status register. The eight-bit result is stored in the location immediately below the return address.

The register values upon return are saved into the locations where the registers were originally pushed on the stack. Since the processor is still in emulation mode, only the low bytes are stored; the high bytes of any of the 65802/65816 registers are always preserved (which means that if a low byte is unchanged, then the entire double-byte value is preserved).

The native mode is restored. The registers are extended to sixteen bits. The stack pointer is restored from the direct page register.

There remains a gap on the stack; the value of the accumulator is copied there. The registers are now restored, with the accumulator being pulled a second time from its new location.

Control is now back with the calling 65816 program, the processor never the wiser for having been transformed into a 6502.

This coding presumes that the calling code, the switching routine, and the 6502 routine are all located in the same bank, bank zero. It also assumes a data bank of zero. Should the 6502 routine be in a non-zero bank, then you should save its program bank to a safe location prior to the switch to emulation mode so that it cannot be lost in case of interrupt. You should also check your emulation mode interrupt service routines to be sure they restore the program bank from the safe location prior to returning.

Finally, should the calling code be in a bank different from the 6502 routine, you’ll have to locate the switching code in the same bank with the 6502 routine (its return will be an RTS); call the switching code with a JSL; move the pushed program bank down two bytes to the bottom of the stack before relocating the return address; and return to the calling code via an RTL.

Testing Processor Type

A related utility routine (Listing 14.6) checks the processor type, allowing code targeted for the large

6502 installed-base to take advantage of a 65C02 or 65802/65816 if available. The processor is assumed to be in emulation mode if it is a 65816 or 65802.

This routine takes advantage of the fact that the 65C02 and 65816 set the sign flag correctly in the decimal mode, while the 6502 does not. The sign flag is set (minus) after loading $99 (a negative two’scomplement number). When one is added to BCD 99, the result is BCD 0, a positive two’s-complement number. On the 6502, adding one decimal mode does not affect the sign flag. On the 65C02 and 65816, the sign flag is cleared to reflect that adding one results in a positive value (zero).

Having distinguished between the 65C02 and the 6502, the code further distinguishes between the

65C02 and 65816 by trying to execute one of the new 65816 instructions – specifically, the XCE instruction. If a 65C02 is in use, the execution of XCE has no effect; it simply performs a no-op, and the carry flag remains clear. On a 65816 in emulation mode, the carry flag would be set after exchanging.

219

The Western Design Center

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000

0008 0000

0009 0000

0010 0000

0011 0000

0012 0000

0013 0000

0014 0000 F8

0015 0001 A999

0016 0003 18

0017 0004 6901

0018 0006 3006

0019 0008

0020 0008

0021 0008

0022 0008 18

0023 0009 FB

0024 000A 9002

0025 000C FB

0026 000D 38

0027 000E D8

0028 000F 60

0029 0010

KEEP

65816

KL.14.6

ON

LONGA OFF

LONGI OFF generate ‘6502’ code

;

;

;

;

;

CHECK - -

CHECK PROCESSOR TYPE

MINUS = 6502

CARRY CLEAR = 65C02

CARRY SET = 65816

CHECK START

SED

LDA

CLC

ADC

BMI

#$99

#$01

DONE

Trick with decimal mode used set negative flag add 1 to get new accum value of 0 branch if 0 does not clear negative flag: 6502

; else 65C02 or 65802 if neg flag cleared by decimal-mode arith

CLC

XCE

BCC

XCE

SEC

DONE CLD

RTS

END

DONE

OK to execute unimplemented C02 opcodes branch if didn’t do anything:65C02 switch back to emulation mode set carry binary

Listing 14.6

Compiler-Generated 65816 Code for a RecursiveProgram

Although it is not directly relevant to assembly-language programming per se, a look at how a compiler might generate 65816 code provides another angle on 65816 program design. You may also find it helpful when you are writing in a high-level language to have some idea as to what kind of code your compiler might be generating.

For the brief example presented here, an integer-only subset of the C programming language – such as the dialect known as “small C” – is used. To understand C, it is important to understand the concept of the

pointer. Effectively, a pointer is a variable that holds the address of another data structure. C programmers are particularly known for their liberal use of pointers, primarily because they provide a method to manipulate data structures that is very close to the machine level. The concept of the variable itself is an abstraction which generally results in additional overhead.

The most notable thing about the use of pointers in the example is that they are limited to sixteen bits, even though the 65816 has an address space of sixteen megabytes. The sixteen-bit machine word size was chosen both for pointers and for the storage type int; this lets many operations be implemented using one or two

65816 instructions. As a consequence, the memory model used with this compiler limits data storage to 64K; program storage is also limited to 64K. If the loader for this hypothetical compiler supports loading of constant data and program code into separate banks, a total of 128K memory would be available to the program.

The first line of the program, shown in Listing 14.7, is the declaration of the function main. By convention, the function main is always called as the entry point to a program; it typically (but not necessarily) is the first routine coded, as it is in this example.

The curly braces define the function block; the first statement in the block is the declaration of y, which is a pointer variable. In C, pointers are typed by the type of the data object to which they point.

220

The Western Design Center

main ( );

{ char *y; y = “A string to invert”; invert (y);

} invert (yy) char *yy;

{ if (*yy)

{ invert (yy+1); putchar (*yy);

}

}

Listing 14.7

The first executable statement is the assignment of the string constant “A string to invert” to the variable y. In this context, the y appears without the asterisk, because the variable is being given a value – an address – rather than the string it points to. The C compiler always returns the address of a string and zeroterminates it when it encounters a string constant.

The next statement is a call to the function invert with a parameter of y (which is the variable that just received a value in the preceding statement). Invert is the function that actually does the work of this program, which, as you may have guessed by now, prints an inverted (backwards) string.

After the closing brace for main comes the declaration of the function invert. Invert takes a parameter

– a pointer to a character. When invert is called from main with y as the parameter, yy assumes the value of y.

The code of invert tests the value pointed to by yy; the first time invert is called, this will be the letter

“A”, the first character in the string constant. The test is whether or not the value “at yy” is non-zero or not; if it is non-zero, the statements within the braces will be executed. If (or when) the value is equal to zero, the code within the braces is skipped.

Looking at the first of the pair of lines contained within the braces, you will find that it is a call to

invert – the same function presently being defined. This calling of a routine from within itself is called

recursion, and programming languages such a C or Pascal, which allocate their local variables on the stack, make it easy to write recursive programs such as this one. The merits of using recursion for any given problem are the subject for another discussion; however, as seen in the example, it seems quite useful for the task at hand. What happens when this function calls itself will be explored in a moment, as the generated code itself is discussed.

The last executable line of the program calls the routine putchar, an I/O routine that outputs the value passed it as a character on the standard (default) output device.

Returning to the top of the program, Listing 14.8 shows the code generated by the compiler to execute the C program; it is inter-listed with the source code – each line of compiler source appears as an assemblersource comment.

Before the first statement is compiled, the compiler has already generated some code: a jump to a routine labeled CCMAIN. CCMAIN is a library routine that performs the “housekeeping” necessary to provide the right environment for the generated code to run in. At the very least, CCMAIN must make sure the processor is in the native mode, and switch into the default (for the compiler) sixteen-bit index and accumulator word sizes. If the operating system supports it, it should also initialize the variable argc and argv, which allow the programmer access to command-line parameters, although they are not used in this example. Finally,

CCMAIN will call main to begin execution of the user-writer code itself.

221

The Western Design Center

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000 4C0080

0006 0003

CC0

KEEP A.OUT

65816 ON

START

JMP

END

CCMAIN

0007 0000

0008 0000

0009 0000

0010 0000

0011 0000

0012 0000 DA

0013 0001 A90080

0014 0004 8301

0015 0006

0016 0006 A301

0017 0008 48

0018 0009 200080

0019 000C FA

0020 000D

0021 000D FA

0022 000E 60

0023 000F

; main ( ); main

;{

START

; char *y;

; y = “A string to invert”;

PHX

LDA

STA

#CCC0+0

1,S

; invert (y);

LDA

PHA

JSR

PLX

1,S invert

;}

PLX

RTS

END

0024 0000

0025 0000

0026 0000

0027 0000

0028 0000 A00000

0029 0003 B303

0030 0005 29FF00

0031 0008 D003

0032 000A 4C1F00

0033 000D

0034 000D

0035 000D A303

0036 000F 1A

0037 0010 48

0038 0011 200080

0039 0014 FA

0040 0015

0041 0015 A00000

0042 0018 B303

0043 001A 48

0044 001B 200080

0045 001E FA

0046 001F

0047 001F

0048 001F 60

0049 0020

;

; invert (yy) char *yy; invert

;{

; if (*yy)

START

LDY

LDA

AND

BNE

JMP

; {

; invert (yy+1);

LDA

INC

PHA

#0

(3,S),Y

#$FF

*+5

CC3

3,S

A

JSR

PLX invert putchar (*yy)

LDY #0

(3,S),Y LDA

PHA

JSR

PLX putchar

; }

;}

CC3 RTS

END

0050 0000

0051 0000

0052 0000 41207374

0053 0008 20746F20

0054 0010 727400

CCC0 START

DC

DC

DC

I1’$41,$20,$73,$74,$72,$69,$6E,$67’

I1’$20,$74,$6F,$20,$69,$6E,$76,$65’

I1’$72,$74,$00’

222

The Western Design Center

0055 0013 END

0056 0000

0057 0000

0058 0000

0059 0000

0060 0000

0061 0000 18

0062 0001 FB

0063 0002 C230

0064 0004 200080

0065 0007 38

0066 0008 FB

0067 0009 60

0068 000A

;

; ‘LIBRARY’ ROUTINES - - AS IF TO BE LINKED TO

SOURCE PROGRAM

CCMAIN START

CLC

XCE

REP

JSR

SEC

XCE

RTS

END

#$30

MAIN

0069 0000

0070 0000

0071 0000

0072 0000

0073 0000

0074 0000

0075 0000 A303

0076 0002

0077 0002 08

0078 0003 38

0079 0004 FB

0080 0005 20EDFD

0081 0008 18

0082 0009 FB

0083 000A

0084 000A 28

0085 000B 60

0086 000C

PUTCHA

R

COUT

START

GEQU $FDED Apple I I character output

LDA

PHP

SEC

XCE

JSR

CLC

XCE

PLP

RTS

END

3,S

COUT get parameter from stack

Listing 14.8

The declaration of main causes an assembler START statement to be output; this simply defines the beginning of the subroutine or function. The declaration char *y will cause the PHX instruction to be generated after the first line of executable code is generated; this reserves space for one variable (the pointer y) on the stack. That first executable code line is the assignment y = “A string to invert”. This causes the

address of the string constant, which will be temporarily stored at the end of the generated program, to be loaded into the accumulator. The address just loaded into the accumulator is now stored on the stack in the memory reserved for it by the PHX instruction; the value of X that was pushed onto the stack was meaningless in itself.

The next statement to be compiled is a call to the function invert with the variable y as the parameter.

This causes the value stored on the stack to be loaded back into the accumulator, where it is then pushed onto the stack. All parameters to function calls are passed on the stack.

Note that the accumulator already contained the value stored on the top of the stack; the LDA 1,S instruction was redundant. However, the hypothetical compiler in this example does not optimize across statements, so the potential optimization – elimination of the load instruction – cannot be realized. Once the parameter is on the top of the stack, the function itself is called via a JSR instruction. Since the program space is limited to 64K, only a sixteen-bit subroutine call is used. After the call returns, the PLX instruction removes the no-longer-needed parameter from the stack. The right bracket indicating the end of the function main

223

The Western Design Center

causes the compiler to generate another PLX to remove the viable storage, an RTS instruction, and an assembler END statement.

Invert is defined as having one parameter, the character pointer yy. By declaring the function in this way, the compiler knows to generate code to look for the variable yy on top of the stack whenever a reference to it is made. You can see how this is done by looking at the code generated for the first line, which tests the value

at yy (rather than the value of yy) to see whether it is true, that is, not equal to zero. To get this value, the stack relative indirect indexed addressing mode is used. First the Y register is loaded with zero, so that the first element pointed to by the indirect value on the stack is accessed. The stack offset used is three, rather than one, because when the subroutine call was made, after the parameter was pushed onto the stack, the return address was pushed onto the stack, on top of the parameter.

After the value is loaded, it must be ANDed with $FF to mask out the high-order contents, since this is a character (one-byte) type of variable.

If the character is not equal to zero, as it is not the first time through, the JMP CC3 instruction is skipped, and execution continues with the code generated for the C source statements inside the braces.

The first statement is the recursive call to invert. Similar to the call from main, a parameter is pushed onto the stack. Since an expression (yy+1) is being passed, however, it must first be evaluated. First the value of yy is loaded from the stack, and then one is added to it. Although this hypothetical compiler does not optimize across statements, it apparently does a pretty good job within them, for it has optimized the addition of one to a single increment instruction.

Invert is then called again. If you start counting them, you will find that more pushes than pulls will have been made at this point; in other words, the stack is growing. When invert is reentered, the value it finds on the stack is the starting address of the string literal plus one; in other words, the second element is being addressed. As long as the value pointed to by the parameter passed to invert is non-zero, invert will continue to be called recursively, and the stack will continue to grow. When the last element (with the value of zero) is reached, the recursive function “bottoms out”; the jump to CC3 that occurs when the value at yy is equal to zero jumps directly to an RTS instruction. This causes control to return to the next statement after the call invert.

The value of yy in the most recently called invocation (the value at 3,S) will be a pointer to the last character in the string; it is this character that is first loaded into the accumulator, then pushed, output via a call to the routine putchar, then pulled again.

Upon return from putchar, control falls through to the RTS instruction, and the next set of values on the stack are processed. This continues until all of the characters pointed to by the values on the stack have been printed, in the reverse order in which they were found. Finally, the last return executed pulls the address of the return address in main off the stack, and the program terminates.

The Same Example Hand-Coded in Assembly Language

A distinctive characteristic of the preceding high-level language programming example was that the algorithm employed involved recursion. Consider Listing 14.9, which is the same algorithm hand-coded in assembly language; it is much more efficient than the compilergenerated example.

224

The Western Design Center

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000 18

0006 0001 FB

0007 0002

0008 0002 C210

0009 0004

0010 0004 E220

0011 0006

0012 0006

0013 0006 A21900

MAIN

KEEP

65816

START

CLC

XCE

REP

SEP

LDX

0014 0009

0015 0009 B500

0016 000B F009

0017 000D 48

0018 000E E8

0019 000F 200900

0020 0012 68

0021 0013 200080

INVERT LDA

BEQ

PHA

INX

JSR

PLA

JSR

0022 0016

0023 0016 38

0024 0017 FB

0025 0018 60

DONE SEC

XCE

RTS

0026 0019

0027 0019 41207374 STRING DC

0028 002C END

KL.14.9

ON

#$10

LONGI ON

#$20

LONGA OFF

#STRING

0,X

DONE

INVERT

COUT

16-bit index registers

8-bit accumulator

C’A string to invert ‘,H’00’

0029 0000

0030 0000

0031 0000

0032 0000

0033 0000

0034 0000

0035 0000

0036 0000 48

0037 0001 DA

0038 0002 5A

0039 0003 08

0040 0004 38

0041 0005 FB

0042 0006 20EDFD

0043 0009 18

0044 000A FB

0045 000B 28

0046 000C 7A

0047 000D FA

0048 000E 68

0049 000F 60

0050 0010

; COUT

;

; machine-department routine to output a character

COUT START

ECOUT GEQU $FDED Apple / / COUT

Save registers PHA

PHX

PHY

PHP and status, switch to emulation SEC

XCE

JSR

CLC

ECOUT call 6502 routine

XCE

PLP

PLY

PLX

PLA

RTS

END restore native mode restore status restore registers return

Listing 14.9

225

The Western Design Center

Because the more elaborate parameter-passing and variable-allocation requirements of the C language can be bypassed, the example here is much more efficient. (Although some further optimization of the compiler-generated code, as noted, is possible, the code in the example would probably be a typical result.)

To start with, a more intelligent decision about the mode flags is made right from the start, rather than coping with the default sixteen-bit accumulator size of the compiler code by making out the high-order byte whenever a character is loaded.

Secondly, full use of the index register is made, both to access the data and as the parameter-passing mechanism. Rather than push successive pointers to the inverted character string on the stack, the character itself is stored.

If this routine will be used to invert a single, known string (as opposed to making INVERT a subroutine for inverting any string, the beginning character of which is pointed to by the X register), then any assembly language programmer would simply write the code found in Listing 14.10. When the assembler evaluates the LDX instruction’s operand, the “L:” function determines the length of STRING.

The Sieve of Eratosthenes Benchmark

With all of the different factors that affect system performance, it is difficult to find a clear criterion by which to judge a processor’s performance. Rightly or wrongly, the speed with which a processor runs a standard “benchmark” program is often used in forming a judgement of it. One of the most commonly used

(and cited) benchmarks is the Sieve of Eratosthenes algorithm. The use of the Sieve program first gained popularity as the result of articles written by Jim Gilbreath and Gary Gilbreath, appearing in BYTE magazine

(September 1980, page 180), and updated in January 1983 (page 283).

226

The Western Design Center

0001 0000

0002 0000

0003 0000

0004 0000 MAIN

KEEP

65816

START

KL.14.10

ON

0005 0000

0006 0000 C210

0007 0002

0008 0002 E220

0009 0004

0010 0004

0011 0004 A21700

0012 0007

0013 0007 BD1100

REP

SEP

LDX

0014 000A 200080

0015 000D CA

0016 000E 10F7

INVERT LDA

JSR

DEX

BPL

0017 0010 60 DONE RTS

0018 0011 41207374 STRING DC

0019 0024 END

#$10

LONGI ON

#$20

LONGA OFF

#L:STRING-1

STRING,X

COUT

INVERT

16-bit index registers

8-bit accumulator get length of string less one get a char from end of string and output it point to previous char and loop through all characters

C’A string to invert ‘,H’00’

0020 0000

0021 0000

0022 0000

0023 0000

0024 0000

0025 0000

0026 0000

0027 0000 48

0028 0001 DA

0029 0002 5A

0030 0003 08

0031 0004 38

0032 0005 FB

0033 0006 20EDFD

0034 0009 18

0035 000A FB

0036 000B 28

0037 000C 7A

0038 000D FA

0039 000E 68

0040 000F 60

0041 0010

;

; COUT machine-dependent routine to output a character

;

COUT START

ECOUT GEQU $FDED Apple I I COUT

Save registers PHA

PHX

PHY

PHP

SEC and status, switch to emulation

XCE

JSR

CLC

XCE

PLP

PLY

PLX

PLA

RTS

END

ECOUT call 6502 routine restore native mode restore status restore registers return

Listing 14.10

The Sieve program calculates the prime numbers between 3 and 16,381; it is based on an algorithm originally attributed to the Greek mathematician Eratosthenes. The basic procedure is to eliminate every nth number after a given number n, up to the limit of range within which primes are desired. Presumably the range of primes is itself infinite.

As well as providing a common yardstick with which to gauge the 65816, the Sieve program in Listing

14.11 provides an opportunity to examine performance-oriented programming; since the name of the game is performance, any and all techniques are valid in coding an assembly-language version of a benchmark.

Four variable locations are defined for the program. ITER counts down the number of times the routine is executed; to time it accurately, the test is repeated 100 times. COUNT holds the count of primes discovered. K is a temporary variable. And PRIME is the value of the current prime number.

The variable I has no storage reserved for it because the Y register is used; it is an index counter. Y is used instead of X because certain indexed operations need the absolute,X addressing mode.

227

The Western Design Center

The constant SIZE is equal to one-half of the range of numbers within which the primes are to be discovered; this algorithm ignores all even numbers (even numbers being non-prime). The first element in the array represents 3, the second 5, the third 7, and so on.

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000

0008 0000

0009 0000

0010 0000

0011 0000

0012 0000

0013 0000

0014 0000 18

0015 0001 FB

ERATOS

SIZE

ITER

COUNT GEQU

.K

PRIME

FLAGS

0016 0002 C230

0017 0004

0018 0004

0019 0004

0020 0004

0021 0004 A96400

0022 0007 8580

0023 0009

0024 0009 6482

0025 000B

0026 000B A0FF1F

0027 000E A9FFFF

AGAIN

0028 0011 8D0040

0029 0014

0030 0014 990040 LOOP

KEEP

65816

START

GEQU

GEQU

GEQU

GEQU

GEQU

CLC

XCE

REP

$80

$82

$84

$86

$4000

LONGI ON

LONGA

LDA

STA

STZ

LDY

LDA

STA

KL.14.11

ON

8192

#$30

ON

#100

ITER

COUNT

#SIZE-1

#$FFFF

FLAGS

FLAGS,Y STA

DEY

DEY

BPL LOOP

0031 0017 88

0032 0018 88

0033 0019 10F9

0034 001B

0035 001B A00000

0036 001E

0037 001E

;

0038 001E

0039 001E B9FF3F MAIN

0040 0021 101E

0041 0023

0042 0023 98

0043 0024 0A

0044 0025 1A

;

LDY

LDA

BPL

TYA

ASL

INC

INC

INC

STA

#0

FLAGS-1,Y

SKIP

A

A

A

A

PRIME enter native mode with 16-bit A and X do one hundred iterations in order to time zero count (# of primes) for I = 0 to size

(handle zero case) flags[I] = TRUE for i = 0 to size

(“i” stored in Y) if flags[I] then minus-one offset: to see high bit in long a mode prime = I + I + 3

0045 0026 1A

0046 0027 1A

0047 0028 8586

0048 002A

0049 002A 98

0050 002B 18

0051 002C 6586

0052 002E

0053 002E C90120 TOP

0054 0031 B00C

0055 0033

TYA

CLC

ADC

CMP

BGE

PRIME

#SIZE+1

SKIP2 k = i + prime while k <= size

228

The Western Design Center

0056 0033 AA

0057 0034

0058 0034 E220

0059 0036 9E0040

0060 0039 C221

0061 003B

0062 003B 6586

0063 003D 80EF

0064 003F

0065 003F E682

0066 0041

0067 0041 C8

0068 0042 C00120

0069 0045 D0D7

0070 0047

0071 0047 C680

0072 0049 D0BE

0073 004B

0074 004B 38

0075 004C FB

0076 004D 60

0077 004E

0078 004E

0079 004E

SKIP2

SKIP

DEC

BNE

SEC

XCE

RTS

TAX

SEP

STZ

REP

ADC

BRA

INC

INY

CPY

BNE

END

#$20

FLAGS,X

#$21

PRIME

TOP

COUNT

#SIZE+1

MAIN

ITER

AGAIN flags[k] = FALSE clear only one byte clears carry as well k = k + prime

(end while k <= size)

(end for i = 0 to size)

Listing 14.11

The program begins by entering the native mode and extending the user registers to sixteen bits. ITER is initialized for 100 iterations. An array (starting at FLAGS) of memory of size SIZE is initialized to $FF’s, two bytes at a time.

The routine proper now begins. Y is initialized with zero, and control falls into the main loop. The high-order bit of each cell of the array FLAGS is tested. Initially, they are all set, but the algorithm iteratively clears succeeding non-prime values before they are tested by this code. If the high bit is clear, this number has already been eliminated by the algorithm; it is non-prime. Notice that the high-order bit of the FLAG[I] (or

FLAG[Y]) array is desired; however, since the processor is in sixteen-bit mode, the high bit will be loaded from the memory location at the effective address plus one. To overcome this, the base of the array is specified as the actual base minus one; this calculation is performed by the assembler during generation of the object code.

If the current value has not been cleared, the algorithm calls for the number which is two times the current index value plus three (this converts the index to the array values of 3, 5, 7 . . . ) to be the next value for PRIME. This prime number is generated quickly by transferring the Y index register into the accumulator, shifting it left once to multiply by two, and incrementing it three times. Remember, this number is generated from the current index only if the index value has not already been eliminated as being non-prime.

This prime number is then added to the current index, and the array elements at this offset, and at all succeeding indices every PRIME value apart are eliminated from the array as being non-prime. They have the current prime number as one of their factors. The most significant thing to note here in the code is that only one byte can be cleared; the accumulator must temporarily be switched into the eight-bit mode to accomplish this.

However, since the next operation is an addition, an optimization is available: both the sixteen-bit mode can be restored and the carry cleared in a single REP operation.

The program now loops, checking to see if the next index value has been eliminated; this process continues until the index reaches the limit of SIZE.

You may be wondering what the result is: at 4 MHz, ten iterations are completed in 1.56 seconds, which is twice as fast as a 4MHz 6502. The January, 1983 BYTE article cites results of 4.0 seconds for a 5MHz 8088,

1.90 seconds for an 8 MHz 8086, and .49 seconds for an 8 MHz 68000; an 8 MHz 65816 would yield .78

seconds.

229

The Western Design Center

15) Chapter Fifteen

DEGUG16 – A 65816 Programming Tool

This chapter consists of a complete 65816 application example and a detailed discussion of its dozen or so routines. Where possible, different programming techniques have been employed in an effect to illustrate some of the different methods of coding that are available.

The program, DEBUG16, is a rudimentary step-and-trace debugger. A debugger is a tool used during software development to isolate and reveal sources of error in the program being tested. In other words, it helps the programmer eliminate the bugs in a program, hence the name. A step-and-trace function lets the program be halted after the execution of each single instruction and the registers and possibly other memory locations to be examined. This effectively provides a “view” into the otherwise invisible internals of the processor.

The ability to trace programs in this manner can be extremely useful: uninitialized variables, wild branches, infinite loops – all of the common flaws that normally result in your program going away to nevernever land with little clue to their reasons for departure – are made visible. In addition to display the register contents, a tracer will also list the opcode mnemonic and display the operand using the same syntax as originally specified in the source program. This process is called disassembly. Although the tracing program can accurately regenerate an approximation of the source line that resulted in a given instruction, it cannot determine any of the symbolic labels that might have been given to the address found by the tracer in the assembler source program. More sophisticated debuggers called symbolic debuggers let you load a program’s symbol table created by either the link editor or assembler; the debugger’s disassembly routine looks up each address in a disassembly in the symbol table and insert labels in place of addresses wherever a correspondence is found.

DEBUG16 also has a LIST entry point, at which its disassembler can be used apart from its tracer; this lets you re-create a listing of a program without having the source code available. Again, there is no symbolic information (labels) available. Additionally, the disassembler in its current form does not deal with variable lengths of immediate operands when in the LIST mode.

The tracer can display the dissembled instruction and register values either one instruction at a time, or allow the trace to execute in free-running mode. When only one instruction is disassembled at a time, the tracer is said to be single-stepping; pressing a key lets the next instruction be executed. Pressing RETURN toggles the tracer into free-running mode. While free-running, a single key press will pause the trace. Pressing any key except RETURN resumes tracing ; RETURN switches back to single-stepping.

The basic theory of operation of the tracer is simple. Starting with the first program instruction, the tracer calculates the length of the instruction by first determining the addressing mode associated with the opcode, and then referring to a table that gives the instruction lengths for the different addressing modes. It can therefore determine the location of the next instruction that follows the current one. It places a BRK instruction at that location, having first saved the original value stored there. Next, it executes (via a JMP instruction) the current instruction. As soon as that instruction completes, the program counter increments to the next instruction, where it encounters the insert BRK. BRK initiates an interrupt cycle that returns control back to the tracer, saves copies of all of the processor’s register contents to memory, then calls a routine which displays them, along with the disassembled instruction.

When the next step (next instruction) is to be executed, the BRK instruction is replaced with its original value, and the cycle is repeated. In this way the program is able to gain control of the processor “in between” the execution of each instruction.

The exception to this method is whenever an instruction (such as a branch or jump) is encountered which can change the flow of control; in these cases, the target location must be determined (by examining the operand of the instruction), and a BRK inserted at that location instead.

The disassembly output looks like Figure 15.1.

230

The Western Design Center

00:2000 4CCB22 JMP

00:2003 08

00:2004 18

00:2005 FB

00:2006 08

00:2007 08

00:2008 F40003

00:200B 2B

00:200C C220

00:200E E210

PHP

CLC

XCE

PHP

PHD

PEA

PLD

REP

SEP

$22CB

$0300

#$20

#$10

Figure 15-1 Disassembly Output

And the tracer output looks like Figure 15.2.

00:5000 A905 LDA #$05

A= 15 05 X= 00 11 Y= 00 13 S= 01 AA D= 00 00 B= 00 P= 7D E:1

00:5002 AB TAY

A= 15 05 X= 00 11 Y= 00 05 S= 01 AA D= 00 00 B= 00 P= 7D E: 1

00:5003 90060 STA $600,Y

A= 15 05 X= 00 11 Y= 00 05 S= 01 AA D= 00 00 B= 00 P= 7D E: 1

00:5006 88 DEY

A= 15 05 X= 00 11 Y= 00 04 S= 01 AA D= 00 00 B= 00 P=7D E:1

00:5007 D0FA BNE $5003

A= 15 05 X= 00 11 Y= 00 04 S= 01 AA D= 00 00 B= 00 P= 7D E:1

00:5003 990060 STA $600,Y

A= 15 05 X= 00 11 Y= 00 04 S= 01 AA D= 00 00 B= 00 P= 7D E:1

00:5006 88 DEY $5003

A= 15 05 X= 00 11 Y= 00 03 S= 01 AA D= 00 00 B= 00 P= 7D E:1

00:5007 D0FA BNE $6000,Y

A= 15 05 X= 00 11 Y= 00 03 S= 01 AA D= 00 00 B= 00 P= 7D E:1

00:5003 990060 STA

A= 15 05 X= 00 11 Y= 00 03 S= 01 AA D= 00 00 B= 00 P= 7D E:1

00:5006 88 DEY

A= 15 05 X= 00 11 Y= 00 02 S= 01 AA D= 00 00 B= 00 P= 7D E: 1

Figure 15-2 Tracer Output

This example was developed and tested using an AppleIIe with a 65816 processor card installed; the calls to machine-dependent locations have been isolated and are clearly as such. DEBUG16 uses the native

BRK vector. On the AppleII, this location ($FFE6, FFE7) normally contains ROM data, which varies between monitor ROM versions. Since there is no way to patch ROM, the solution opted for here is for DEBUG16 to try to patch the location pointed to by the data that is stored there. For current ROMs, these are RAM locations that happen to be more or less livable. Check the location pointed to by your ROMs, and make sure that neither your own code nor the debugger are loaded into that area. DEBUG16 will automatically read whatever value is stored there and store a vector to that address to regain control after a BRK.

Both programs are executed by putting the starting address of the routine to list or trace (which has been loaded into memory) at DPAGE+80.82 ($380.82) in low – high – bank order, and then calling either the

TRACE entry point at $2000, or the LIST entry at $2003.

231

The Western Design Center

0001 0000

0002 0000

0003 0000

0004 0000

0005 0000

0006 0000

0007 0000

0008 0000

0009 0000

0010 0000

0011 0000

0012 0000

0013 0000

0014 0000

0015 0000

0016 0000

0017 0000

0018 0000

0019 0000

0020 0000

0021 0000

0022 0000

0023 0000

0024 0000

0025 0000

0026 0000

0027 0000

0028 0000

0029 0000

0030 0000

0031 0000

0032 0000

0033 0000

0034 0000

0035 0000

0036 0000

0037 0000

0038 0000

0039 0000

0040 0000

Declarations

The listing begins with the declaration of global values by way of GEQU statements. Almost all of these are addresses of direct page memory locations that will be used; one notable exception is the label

DPAGE, a sixteen-bit value that defines the beginning of the direct page memory to be used by this program.

Because a 65816 debugger is by definition a 6502 debugger, it is wise to relocate the direct page out of the default zero page, since it will be used by 65802 programs, and you program being debugged. In the listing, a value of $300 is used; on an Apple I I , this relocates the direct page to page three, which is a convenient page to use.

Many of the direct page locations are used to store the register contents of the user program when the debugger is executing. All of the registers are represented. As you will see in the code, the adjacent positioning of some of the registers is important and must be maintained.

In addition to the direct page location used for register storage, one general-purpose temporary variable is used, called TEMP. Three other variables – ADDRMODE, MNX, and OPLEN (for address mode,

mnemonic index, and operation length, respectively) – are used primarily to access the tables used in disassembling an instruction.

The variable CODE contains the instruction opcode currently being executed in the user program. The variable NCODE contains the next instruction opcode to be executed, saved there before being replaced with the BRK instruction inserted in the code. OPRNDL, OPRNDH, and OPRNDB contain the three (possible) values of the operand of a given instruction.

;

;

;

;

DPAGE

PCREG

PCREGH

PCREGB

NCODE

OPCREG

OPCREGH

OPCREGB

KEEP DEBUG16

65816

MSB

ON

ON

LONGA OFF

LONGI OFF

***********************************************

*

*

*

DEBUG16

A 65816 DEBUGGER

*

*

*

*

*

***********************************************

*

*

$8000

MAIN

ORG

START

USING

USING

MN

ATRIBL

GEQU

DIRECT PAGE STORAGE

TRACE REGISTERS

GEQU

GEQU

GEQU

GEQU

GEQU

GEQU

GEQU

$300

$80

PCREG+1

PCREGH+1

PCREGB+1

NCODE+1

OPCREG+1

OPCREGH+1

LOCATION OF THIS APPLICATION’S

DIRECT PAGE

PROGRAM COUNTER

INCLUDING BANK

NEXT CODE TO BE TRACED

OLD PROGRAM COUNTER VALUE

232

The Western Design Center

0072 0000

0073 0000

0074 0000

0075 0000

0076 0000

0077 0000

0078 0000

0079 0000

0080 0000

0081 0000

0082 0000

0083 0000

0084 0000

0085 0000

0086 0000

0087 0000

0088 0000

0089 0000

0090 0000

0091 0000

0092 0000

0041 0000

0042 0000

0043 0000

0044 0000

0045 0000

0046 0000

0047 0000

0048 0000

0049 0000

0050 0000

0051 0000

0052 0000

0053 0000

0054 0000

0055 0000

0056 0000

0057 0000

0058 0000

0059 0000

0060 0000

0061 0000

0062 0000

0063 0000

0064 0000

0065 0000

0066 0000

0067 0000

0068 0000

0069 0000

0070 0000

0071 0000

CODE

XREG

XREGH

YREG

YREGH

AREG

AREGH

STACK

STACKH

DIRREG

DIRREGH

DBREG

PREG

EBIT

GEQU

GEQU

GEQU

GEQU

ADDRMODE GEQU

;

MNX

;

OPLEN

CR

M

X

C

OPRNDL

OPRNDH

OPRNDB

TEMP

TEMPH

TEMPB

GEQU

GEQU

GEQU

GEQU

GEQU

GEQU

GEQU

GEQU

GEQU

GEQU

GEQU

GEQU

GEQU

GEQU

GEQU

GEQU

GEQU

GEQU

GEQU

GEQU

GEQU

GEQU

0093 0000

4C008

0

JMP

OPCREGB+1

CODE+1

OPRNDL+1

OPRNDH+1

OPRNDB+1

XREG+1

XREGH+1

YREG+1

YREGH+1

AREG+1

AREGH+1

STACK+1

STACKH+1

DIRREG+1

DIRREGH+1

DBREG+1

PREG+1

EBIT+2

TEMP+1

TEMPH+1

$20

$10

$01

TRACE

CURRENT CODE TO BE TRACED

OPERANDS OF CURRENT

INSTRUCTION

X REGISTER

Y REGISTER

ACCUMULATOR

STACK POINTER

DIRECT PAGE REGISTER

DATA BANK REGISTER

P STATUS REGISTER

E BIT

TEMPORARY

TEMPB+1

MNX+2

ADDRESS MODE OF CURRENT OPCODE

ADDRMODE+1 MNEMONIC INDEX

FROM ATTRIBUTE TABLE

LENGTH OF OPERATION,

INCLUDING INSTRUCTION

$8D CARRIAGE RETURN

SYBOLIC NAMES FOR

STATUS REGISTER BITS

233

The Western Design Center

LIST

The program has two entry points, defined in the first routine. One is for listing (disassembling) a program, the other for tracing. The first entry point, at the program’s origin (default $8000), is jump to the actual entry point of the trace routine; the second, immediately past it (at $8003), is the beginning of the code for the disassembler.

Since this is a bare-bone disassembler, intended to be expanded and perhaps integrated with a general purpose machine language monitor, parameters such as the start address of the program to be traced are entered by modifying the values of the register variables; for example, to begin disassembly of a program stored at

$800, the values $00 $08, and $00 are stored staring at PCREG. Since the direct page is relocated to page three, the absolute location of this variable is $380.

Starting at the LIST entry, some basic initialization is performed: saving the status register, switching to native mode, and then saving the previous operating mode (emulation/native) by pushing the status register a second time (the carry flag now containing the previous contents of the e bit). Thus this program may be called from either native or emulation mode.

The current value of the direct page is saved in program memory, and then the new value – DPAGE – is stored to the direct page register. The native mode is entered.

Control now continues at TOP, the beginning of the main loop of the disassembler. The mode is set to long accumulator, short index. This combination allows simple manipulation of both byte and double-byte values. The value of PCREG is copied to OPCREG (old pcreg). OPCREG will contain the starting location of the current instruction throughout the loop; PCREG will be modified to point to the next instruction.

However, it hasn’t been modified yet, so it is used to load the accumulator with the opcode byte. Indirect long addressing is used, so code anywhere within the sixteen-megabyte address space may be disassembled. Since the accumulator is sixteen bits, a second byte is fetched as well, but ignored; the next instruction transfers the opcode to the X register and then stores it at the location CODE.

The utility routine UPDATE is called next. This is common to both the disassembler and the tracer, and determines the attributes of this instruction by looking the instruction up in a table; it also increments the program counter to point to the next instruction.

The routines FLIST, FRMOPRND, and PRINTLN form the disassembled line and display it. After each line is printed, the routine PAUSE is called to check the keyboard to see if a key has been pressed, signalling a pause. If PAUSE returns with the carry clear, it means the user has signalled to quit, and control falls through to QUIT; otherwise, the program loops to TOP again, where it repeats the process for the next instruction.

234

The Western Design Center

0094 0003

0095 0003

0096 0003

0097 0003

0098 0003

0099 0003

0100 0003

0101 0003

0102 0003

0103 0003

0104 0003

0105 0003 08

0106 0004 18

0107 0005 FB

0108 0006 08

0109 0007

0110 0007 0B

0111 0008 F40003

0112 000B 2B

0113 000C

0114 000C

0115 000C

0116 000C C220

0117 000E E210

0118 0010

0119 0010

0120 0010

0121 0010 649D

0122 0012 A580

0123 0014 8584

0124 0016 A682

0125 0018 8686

0126 001A A780

0127 001C AA

0128 001D 8687

0129 001F

0130 001F 200080

0131 0022

0132 0022 200080

0133 0025 200080

0134 0028 200080

0135 002B 9005

0136 002D 200080

0137 0030

0138 0030 80DA

0139 0032

0140 0032 2B

0141 0033 28

0142 0034 FB

0143 0035 28

0144 0036 60

0145 0037

0146 0037

;

;

;

;

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

LIST

MAIN LOOP OF DISASSEMBLER FUNCTION

;

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

LIST

TOP

ENTRY

PHP

CLC

XCE

PHP

PHD

PEA

PLD

ANOP

REP

SEP

LONGA

LONGI

STZ

LDA

STA

LDX

STX

LDA

TAX

STX

JSR

JSR

JSR

JSR

BCC

JSR

BRA

QUIT PLD

PLP

XCE

PLP

RTS

END

DPAGE

#M

#X

ON

OFF

MNX

PCREG

OPCREG

PCREGB

OPCREGB

[PCREG]

SAVE ORIGINAL FLAGS

SET NATIVE MODE

SAVE PREVIOUS MODE

SAVE CURRENT DP

SET TO NEW DP

CLEAR MNEMONIC INDEX

MOVE PROGRAM COUNTER

TO ‘OLD PROGRAM COUNTER’

INCLUDING BANK

GET NEXT INSTRUCTION

SAVE AS ‘CODE’ CODE

UPDATE UPDATE ATTRIBUTE VARIABLES

FLIST FORM OBJECT CODE, MNEMONIC

FRMOPRNND FORM OPERAND FIELD

PAUSE

QUIT

PRINTLN

CHECK FOR USER PAUSE

PRINT IT

TOP LOOP TIL END

RESTORE ENVIRONMET,

RETURN TO CALLER

Local Symbols

LIST 00003 QUIT 000032 TOP 0000C

235

The Western Design Center

FLIST

FLIST is called by both the disassembler and the tracer. This routine displays the current program counter value, the object code of the instruction being disassembled in hexadecimal, and the mnemonic for the opcode. The code required to do this is basically the same for any instruction, the only difference being the length of the instruction, which has already been determined by UPDATE

.

The first thing the code does is to blank the output buffer by calling CLRLN. Particularly since 6502 emulation-mode I/O routines are used, it is more efficient to build an output line first, then display it all at once, rather than output the line “on the fly.” Characters are stored in the output buffer LINE via indexed absolute addressing; the Y register contains a pointer to the current character position within the line, and is incremented every time a character is stored. Since character manipulation is the primary activity in this routine, the accumulator is set to eight bits for most of the routine.

The flow of the program proceeds to generate the line from left to right, as it is printed; the first characters stored are therefore the current program counter values. Since UPDATE has already modified the program counter variable to load the operands of the instruction, the value in the variable OPCREG is used.

The hex conversion routine, PUTHEX, converts the data in the accumulator into the ASCII characters that represents the number’s two hexadecimal digits, storing each character at the location pointed to by LINE,Y, and then incrementing Y to point to the next character. A colon is printed between the bank byte and the sixteen-bit program counter display to aid readability.

Next, some spaces are skipped by loading the Y register with a higher value, and the object code bytes are displayed in hexadecimal. These values have already been stored in direct page memory locations CODE and OPRNDL, OPRNDH, and OPNDB by the UPDATE routine, which also determined the length of the instruction and stored it at OPLEN, The length of the operand controls a loop that outputs the bytes; note that a negative displacement of one is calculated by the assembler so that the loop is not executed when OPLEN is equal to one.

All that remains is to print the instruction mnemonic. The characters for all of the mnemonics are stored in a table called MN; at three characters per mnemonic (which as you may have noticed is the standard length for all 65x mnemonics), the mnemonic index (MNX) determined by UPDATE from the instruction attribute table must be multiplied by three. This is done by shifting left once (to multiply by two), and adding the result to the original value of MNX. Note that this type of “custom” multiplication routine is much more efficient than the generalized multiplication routines described in the previous chapter. The characters in the mnemonic table are copied into the output line using the MVN instruction; the result just calculated is transferred into the X register as the source of the move. It is the line-buffered output that allows use of the block-move instruction; on-the-fly output would have required each character to be copied out of the mnemonic table in a loop.

236

The Western Design Center

0147

0148

0149

0150

0151

0152

0153

0154

0155

0156

0157

0158 200080

0159 0003

0160 0003 E230

0161 0005

0162 0005

0163 0005

0164 0005 A000

0165 0007 A586

0166 0009 200080

0167 000C A9BA

0168 000E 990080

0169 0011 C8

0170 0012 A585

0171 0014 200080

0172 0017 A584

0173 0019 200080

0174 001C

0175 001C A00A

0176 001E A587

0177 0020 20080

0178 0023 A201

0179 0025

0180 0025 E49F

0181 0027 F008

0182 0029 B587

0183 002B 200080

0184 002E E8

0185 002F 80F4

0186 0031

0187 0031 C23

0188 0033

0189 0033

0190 0033

0191 0033 A59D

0192 0035 0A

0193 0036 18

0194 0037 659D

0195 0039 18

0196 003A 690080

0197 003D AA

0198 003E A01480

0199 0041 A90200

0200 0044

0201 0044 540000

0202 0047

0203 0047 60

0204 0048

;

;

;

;

;

FLIST – FORM IMAGE OF PROGRAM COUNTER,

OBJECT CODE, AND MNEMONIC IN ‘LINE’

REQUIRES ATTRIBUTE VARIABLES TO BE PREVIOUSLY INITIALIZED

;

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

FLIST START

USING

JSR

MN

CLRLN BLANK ‘LINE’ VARIABLE

SHORT REGISTERS SEP #M+X

LONGA OFF

LONGI OFF

LDY

LDA

JSR

LDA

STA

INY

LDA

JSR

LDA

JSR

#0

OPCREGB

PUTHEX

#’:’

LINE,Y

OPCREGH

PUTHEX

OPCREG

PUTHEX

GET BANK BYTE, FORM AS HEX

STRING

BANK DELIMITER

GET BYTES OF PROGRAM COUNTER

FORM AS HEX STRING IN

LINE

LDY

LDA

JSR

LDX

MORE CPX

BEQ

LDA

JSR

INX

BRA

DONE REP #M+X

LONGA ON

LONGI ON

LDA

ASL

CLC

ADC

CLC

ADC

TAX

LDY

LDA

MOVE ENTRY

MVN

MNX

A

MNX

#MN

#LINE+20

#2

0,0

RTS

END

#10

CODE

PUTHEX

#1

OPLEN

DONE

OPRNDL-1,X

PUTHEX

MORE

STORE OPCODE AS HEX STRING

LIST OPERANDS, IF ANY

GET MNEMONIC INDEX,

MULTIPLY BY THREE

(TIMES TWO PLUS SELF)

INDEX INTO MNEMONIC TABLE

COPY INTO ‘LINE’

Local Symbols

DONE 000031 MORE 000025 MOVE 000044

237

The Western Design Center

FRMOPRND

This is the second part of the line-disassembly pair. It performs the address-mode specific generation of the disassembled operand field; the result is similar to the address mode specification syntax of a line of 65x source code.

The Y register is loaded with the starting destination in LINE, and the attribute stored at ADDRMODE is multiplied by two to form an index into a jump table. There is a separate routine for each addressing mode; the address of that routine is stored in a table called MODES in the order that corresponds to the attributes given them from the attribute table.

The JMP indirect indexed instruction is used to transfer control through the jump table MODES to the appropriate routine, whose index, times two, has been loaded into the X register.

Each of the routines is basically similar; they output any special characters and print the address of the operand found in the instruction stream. There are three relative routines, POB, PODB, and POTB (for put operand byte, put operand double byte, and put operand triple byte) which output direct page, absolute, and absolute long addresses.

The two routines FPCR and FPCRL, which handle the program counter relative instructions, however, must first calculate the destination address (which is how an assembler would specify the operand, so this is how they are disassembled) by adding the actual operand, a displacement, to the current program counter. The operand of a short program counter relative instruction is sign-extended before adding, resulting in a sixteen-bit signed displacement which is added to the program counter to find the destination address

.

238

The Western Design Center

0205 0000

0206 0000

0207 0000

0208 0000

0209 0000

0210 0000

0211 0000

0212 0000

0213 0000

0214 0000

0215 0000

0216 0000

0217 0000

0218 0000

0219 0002

0220 0002

0221 0002

0222 0002

0223 0004

E230

A01C

0224 0004 A59C

0225 0006

0226 0007

0227 0008

0228 000B

0A

AA

7C0080

0229 000B

0230 000B

0231 000B A9A3

0232 000D 990080

0233 0010

0234 0011

0235 0013

C8

A59F

C902

0236 0015 F003

0237 0017 4C0080

0238 001A 4C0080

0239 001D

0240 001D

0241 001D 4C0080

0242 0020

0243 0020

0244 0020

0245 0023

0246 0023

4C0080

0247 0023

0248 0026

0249 0026

0250 0026

0251 0028

4C0080

A9C1

990080

0252 002B 60

0253 002C

0254 002C

0255 002C 60

0256 002D

0257 002D

0258 002D 20B600

0259 0030

0260 0030

0261 0030

0262 0030

0263 0032

A9AC

990080

0264 0035

0265 0038

C8

A9D9

0266 003B 990080

;

;

;

;

;

;

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

FRMOPRND – –

FORMS OPERAND FIELD OF DISASSEMBLED INSTRUCTION

OPLEN, ADDRMODE, AND OPRND MUST HAVE BEEN

INITIALIZED BY ‘UPDATE’

;

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

;

FRMOPRND START

USING

SEP

MODES

#M+X

LONGA OFF

LONGI OFF

LDY

LDA

ASL

TAX

JMP

#28

ADDRMOD

E

A

(MODES,X)

OFF SET INTO ‘LINE’ FOR OPERAND

TO BEGIN

GET ADDRESS MODE, MULTIPLY BY

TWO, JUMP THROUGHT ADDRESS

MODE JUMP TABLE TO PROPER

HANDLER

FIMM

GOSHORT

FABS

FABSL

FDIR

FACC

FIMP

;

FINDINX

FINY

ENTRY

JMP

ENTRY

JMP

ENTRY

LDA

STA

RTS

ENTRY

LDA

STA

INY

LDA

CMP

BEQ

JMP

JMP

ENTRY

JMP

ENTRY

RTS

ENTRY

JSR

#’#’

LINE,Y

OPLEN

#2

GOSHORT

PODB

POB

PODB

POTB

POB

#’A’

LINE,Y

FIND

ENRTY

LDA

STA

INY

LDA

STA

#’,’

LINE,Y

#’Y’

LINE,Y

IMMEDIATE MODE – –

OUTPUT POUND SIGN,

ONE OR TWO

OPERAND BYTES, DEPENDING

ON OPLEN

ABSOLUTE MODE – –

JUST OUTPUT A DOUBLE BYTE

ABSOLUTEW LONG – –

OUTPUT A TRIPLE BYTE

DIRECT MODE – –

OUTPUT A SINGLE BYTE

ACCUMULATOR – –

JUST AN A

IMPLIED – –

NO OPERAND

INDIRECT INDEXED – –

CALL ‘INDIRECT’, THEN FALL

THROUGH TO INDEXED BY Y

INDEXED BY Y MODES – –

TACK ON A ‘COMMA,Y’

239

The Western Design Center

0267 003B 60

0268 003C

0269 003C

0270 003C 20C600

0271 003F

0272 0042

4C3000

0273 0042

0274

0275

0042

0044

0276 0047

0277 0048

A9A8

990080

C8

200080

0278 004B 206000

0279 004E A9A9

0280

0281

0050

0053

0282 0054

0283 0054

990080

60

0284 0054

0285 0057

0286 005A

0287 005A

200080

4C6000

0288 005A 200080

0289 005D 4C3000

0290 0060

0291 0060

0292 0060

0293 0062

0294 0065

0295 0066

A9AC

990080

C8

A9D8

0296 0068 990080

0297 006B C8

0298 006C 60

0299 006D

0300 006D

0301 006D 200080

0302 0070 4C6000

0303 0073

0304 0073

0305 0073

0306 0076

200080

4C6000

0307 0079

0308 0079

0309 0079 200080

0310 007C 4C3000

0311 007F

0312 007F

0313 007F

0314 0081

0315 0082

0316 0084

0317 0086

A9FF

EB

A588

C221

0318 0086

0319 0088

3003

297F00

0320 008B 6584

0321 008D 1A

0322

0323

008E

008F

0324 0091

0325 0091

1A

8588

E220

0326 0093

0327 0093

0328 0093

0329 0096

0330 0096

0331 0096

4C0080

FINDINXL

FINXIND

FDIRINXX

FDIRINXY

FINX

FABSX

FABSLX

FABSY

FPCR

OK

FCPRL

RTS

ENTRY

JSR

JMP

ENTRY

LDA

STA

INY

JSR

JSR

LDA

STA

RTS

ENTRY

JSR

JMP

ENTRY

JSR

JMP

FINDL

FINY

#’(’

LINE,Y

POB

FINX

#’)’

LINE,Y

POB

FINX

POB

FINY

ENTRY

LDA

STA

INY

LDA

STA

INY

RTS

ENTRY

JSR

JMP

ENTRY

JSR

JMP

#’,’

LINE,Y

#’X’

LINE,Y

PODB

FINX

POTB

FINX

ENTRY

JSR

JMP

PODB

FINY

ENTRY

LDA #$FF

XBA

LDA OPRNDL

REP #M+C

LONGA ON

BMI

AND

ADC

INC

INC

STA

OK

#$7F

OPCREG

A

A

OPRNDL

SEP #M

LONGA OFF

PODB JMP

ENTRY

INDIRECT INDEXED LONG – –

CALL ‘INDIRECT LONG’, THEN

EXIT THROUGH INDEXED BY Y

INDEX INDIRECT – –

PARENTHESIS

A SINGLE BYTE – –

COMMA, X

CLOSE.

DIRECT INDEXED BY X – –

OUTPUT A BYTE,

TACK ON COMMA, X

DIRECT INDEXED BY Y – –

OUTPUT A BYTE,

TACK ON COMMA, Y

INDEXED BY X – –

TACK ON A

COMMA, X

(USED BY SEVERAL

MODES)

ABSOLUTE INDEXED BY X – –

OUTPUT A DOUBLE BYTE,

TACK ON A COMMA, X

ABSOLUTE LONG BY X – –

OUTPUT A TRIPLE BYTE,

TACK ON COMMA, X

ABSOLUTE Y – –

OUTPUT A DOUBLE BYTE,

TACK ON COMMA,Y

PROGRAM COUNTER RELATIVE – –

SIGN EXTEND OPERAND

ADD TO PROGRAM COUNTER

ADD TWO, WITHOUT CARRY

STORE AS NEW ‘OPERAND’

NOW JUST DISPLAY A DOUBLE BYTE

PROGRAM COUNTER RELATIVE LONG

240

The Western Design Center

0332 0096

0333 0098

0334 0098

0335 0098

C221

A588

0336 009A 6584

0337 009C 18

0338 009D 690300

0339 00A0 8588

0340 00A2

0341 00A2 E220

0342 00A4

0343 00A4

0344 00A4 4C0080

0345 00A7

0346 00A7

0347 00A7 A9A8

0348 00A9 990080

0349 00AC C8

0350 00AD 200080

0351 00B0 A9A9

0352 00B2 990080

0353 00B5 60

0354 00B6

0355 00B6

0356 00B6 A9A8

0357 00B8 990080

0358 00BB C8

0359 00BC 200080

0360 00BF A9A9

0361 00C1 990080

0362 00C4 C8

0363 00C5 60

0364 00C6

0365 00C6

0366 00C6 A9DB

0367 00C8 990080

0368 00CB C8

0369 00CC 200080

0370 00CF A9DD

0371 00D1 990080

0372 00D4 C8

0373 00D5 60

0374 00D6

0375 00D6

0376 00D6 A9A8

0377 00D8 990080

0378 00DB C8

0379 00DC 206D00

0380 00DF A9A9

0381 00E1 990080

0382 00E4

0383 00E5

60

0384 00E5

0385 00E5

0386 00E6

0387 00E6

60

0388 00E6

0389 00E9

202300

A9AC

0390 00EB 990080

0391 00EE C8

0392 00EF A9D3

0393 00F1 990080

0394 00F4

0395 00F5

C8

60

FABSIND

FIND

FINDL

FABSINXIN

D

ENTRY

LDA

ST5A

INY

JSR

LDA

STA

RTS

FSTACK ENTRY

RTS

FSTACKREL ENTRY

JSR

LDA

STA

INY

LDA

STA

INY

RTS

ENTRY

LDA

STA

INY

JSR

LDA

STA

RTS

ENTRY

LDA

STA

INY

JSR

LDA

STA

INY

RTS

ENTRY

LDA

STA

INY

JSR

LDA

STA

INY

RTS

REP #M+C

LONGA ON

LDA

ADC

CLC

ADC

STA

OPRNDL

OPCREG

#3

OPRNDL

SEP #M

LONGA OFF

JMP PODB

#’(‘

LINE,Y

PODB

#’)’

LINE,Y

#’(‘

LINE,Y

POB

#’)’

LINE,Y

#’[‘

LINE,Y

POB

#’ ]’

LINE,Y

#’(‘

LINE,Y

FABSX

#’)’

LINE,Y

#’S”

LINE,Y

JUST ADD THE OPERAND

BUMP BY THREE, PAST INSTRCTION

STORE AS NEW ‘OPERAND’

PRINT A DOUBLE BYTE

ABSOLUTE INDIRECT

SURROUND A DOUBLE BYTE

WITH PARENTHESES

INDIRECT – –

SURROUND A SINGLE BYTE

WITH PARENTESES

INDIRECT LONG – –

SURROUND A SINGLE BYTE

WITH SQUARE BRACKTS

ABSOLUTE INDIRECT INDEXED

SURROUND A CALL TO ‘ABSOLUTE

INDEXED’ WITH PARENTESES

STACK – – IMPLIED

STACK RELATIVE

JUST LIKE

DIRECT INDEXED, BUT WITH

AN ‘S’

241

The Western Design Center

0396 00F6

0397 00F6

0398 00F6

0399 00F6 A9A8

0400 00F8 990080

0401 00FB C8

0402 00FC 20E600

0403 00FF

0404 0101

0405 0104

0406 0105

A9A9

990080

C8

4C3000

0407 0108

0408 0108

0409 0108

0410 0108

0411 0108 C220

0412 010A A588

0413 010C EB

0414 010D 8588

0415 010F E220

0416 0111

0417 0111 200080

0418 0114

0419 0116

A9AC

990080

0420 0119 C8

0421 011A EB

0422 011B 8588

0423 011D 4C0080

0424 0120

0425 0120

0426 0120

FSRINDINX ENTRY

LDA

STA

INY

JSR

LDA

STA

INY

JMP

FBLOCK

END

ENTRY

REP

LDA

XBA

STA

SEP

JSR

LDA

STA

INY

XBA

STA

JMP

STACK RELATIVE INDIRECT INDEX

#’(‘

LINE,Y

FSTACKREL

#’)’

LINE,Y

SURROUND STACK RELATIVE WITH

PARENTHESES, THEN

FINY TACK ON A COMMA,Y

#M

OPRNDL

OPRNDL

#M

POB

#’,’

LINE,Y

OPRNDL

POB

BLOCK MOVE

MAKE HUMAN-READABLE:

SWAP SOURCE, DEST

OUTPUT THE SOURCE

THEN COMMA

SWAP DEST INTO OPRNDL

THEN PRINT ONE BYTE

Local Symbols

FABS

FABSLX

FBLOCK

FIMM

FINDINXL

FINY

FSTACK

00001D

000073

000108

00000B

00003C

000030

0000E5

FABSIND

FABSX

FDIR

0000A7

00006D

000023

FIMP

FINDL

00002C

0000C6

FPCR 00007F

FSTACKREL 0000E6

FABSINXIND

FABSY

FDIRINXX

FIND

FINX

FPCRL

GOSHORT

0000D6

000079

000054

000086

000060

000096

00001A

FABBSL

FACC

FDIRINXY

FINDINX

FINXIND

FSRINDINX

OK

000020

000026

00005A

00002D

000042

0000F6

00008B

242

The Western Design Center

POB

This routine (put operand byte), with three entry points, outputs a dollar sign, followed by either one, two, or three operand bytes in hexadecimal form; it calls the routine PUTHEX to output the operand bytes. It is called by FRMOPRND.

Depending on the entry point, the X register is loaded with 0, 1, or 2, controlling the number of times the loop at MORE is executed; on each iteration of the loop, an operand byte is loaded by indexing into

OPRNDL and then printed by PUTHEX.

0427 0000

0428 0000

0429 0000

0430 0000

0431 0000

0432 0000

0433 0000

0434 0000

0435 0000

0436 0000

0437 0000

0438 0000

0439 0000

0440 0000

0441 0000

0442 0000

0443 0000

0444 0000

0445 0000

0446 0000

0447 0000

0448 0000 A200

0449 0002 8006

0450 0004

0451 0004 A201

0452 0006 8002

0453 0008

0454 0008 A202

0455 000A

0456 000A A9A4

0457 000C 990080

0458 000F C8

0459 0010

0460 0010 B588

0461 0012 200080

0462 0015 CA

0463 0016 10F8

0464 0018 60

0465 0019

;

;LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

; POB, PODB, POTB

; PUT OPERAND (DOUBLE, TRIPLE) BYTE

;

; PUTS OPRNDL (OPRNDH, OPRNDB) IN LINE AS HEX VALUE

;

; WITH ‘$’ PREFIX

; ASSUMES SHORT ACCUMULATOR AND INSEX REGISTERS

; (CALLED BY FOPRND)

;

;LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

POB START

LONGA OFF

LONGI OFF

;

PODB

POTB

;

IN LDA

STA

INY

MORE LDA

JSR

DEX

BPL

RTS

END

LDX

BRA

ENTRY

LDX

BRA

ENTRY

LDX

#0

IN

#1

IN

#2

#’$’

LINE,Y

OPRNDL,X

PUTHEX

MORE

PRINT:

ONE OPERAND BYTE

SKIP

TWO OPERAND BYTES

SKIP

THREE OPERAND BYTES

FALL THROUGH

PRINT LEAD-IN

LOOP THROUGH OPERAND

HIGH TO LOW

Local Symbols

IN 00000A MORE 000010 PODB 000004 POTB 000008

243

The Western Design Center

STEP

This routine also contains the PAUSE entry point called by LIST; STEP waits until a keypress,

PAUSE simply checks to see if a key has been pressed, and waits only if there has been an initial keypress. In both cases, the wait loop continues until the next keypress. If the keypress that exits the wait loop was the

ESCAPE key, the carry is cleared, signalling the calling program that the user wants to quit rather than continue. If it was RETURN, the overflow flag is cleared; the tracer uses this toggle between tracing and single stepping. Any other keypress causes the routine to return with both flags set.

The code in this listing is machine-dependent; it checks the keyboard locations of the AppleII. Since this is a relatively trivial task, in-line code is used rather than a call to one of the existing 6502 monitor routines; therefore, the processor remains in the native mode while it performs this I/O operation.

Like all utility routines, STEP saves and restores the status on entry and exit.

0466 0000

0467 0000

0468 0000

0464 0000

0465 0000

0466 0000

0467 0000

0468 0000

0469 0000

0470 0000

0471 0000

0472 0000

0473 0000

0474 0000

0475 0000

0476 0000

0477 0000

0478 0000

0479 0000

0480 0000

0481 0000

0482 0000

0483 0000

0484 0000

0485 0000

0486 0000

0487 0000

0488 0000

0489 0000

0490 0000 08

0491 0001 E230

0492 0003 800B

0493 0005

0494 0005

0495 0005 08

0496 0006 E230

0497 0008 AD00C0

0498 000B 101B

0499 000D 8D10C0

0500 0010 ;

0501 0010 AD00C0 WAIT

0502 0013 10FB

0503 0015 8D10C0

0504 0018 C998

0505 001A D004

;

;

APPEND DB. UTILITY

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

; STEP - - CHECKS FOR USER PAUSE SIGNAL

;

; (KEYSTROKE)

; CONTAINS MACHINE-DEPENDENT CODE

; FOR APPLE I I

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

STEP

KEYBD

KEYYSTB

ESC

V

PAUSE

START

EQU

EQU

EQU

EQU

$C000

$C010

$9B

$40

LONGA OFF

LONGI OFF

PHP

SEP

BRA

ENTRY

PHP

SEP

LDA

BPL

STA

LDA

BPL

STA

CMP

BNE

#M+X

WAIT

#M+X

KEYBD

RETNCR

KEYSTB

KEYBD

WAIT

KEYSTB

#ESC

RETNESC

ESCAPE KEY (HIGH BIT SET)

MASK FOR OVERFLOW FLAG

SAVE MODES

ENTRY FOR ‘PAUSE’ CALL

CHECK FOR KEYPRESS

NONE; DON’T PAUSE

CLEAR STROBE

IF KEYSTROKE

LOOP FOR NEXT KEY

CLEAR STROBE

IF ESC RETURN WITH

244

The Western Design Center

0506 001C

0507 001C 28 RETEQ PLP

0508 001D EA

0509 001E 18

0510 001F 60

0511 0020

NOP

CLC

RTS

0512

0513

0514

0515

0020

0022

0024

0025

C98D

D004

28

E241

RETNESC CMP

BNE

PLP

SEP

RTS 0516 0027 60

0517 0028

0518 0028 8D10C0 RETNCR

0519 002B 28

STA

PLP

0520 002C 38

0521 002D B8

0522 002E 60

0523 002F

SEC

CLV

RTS

END

Local Symbols

ESC

RETEQ

WAIT

00009B

00001C

000010

KEYBD

RETNCR

00C000

000028

#CR

RETNCR

#C+V

KEYSTB

CARRY CLEAR (QUIT)

ELSE SET

(CONTINUE)

KEYSTB 00C010

RETNESC 000020

PAUSE

V

000005

000040

245

The Western Design Center

PUTHEX

This utility routine, already referred to in several descriptions, is called whenever a hexadecimal value needs to be output. It converts the character in the low byte of the accumulator into two hexadecimal characters, and stores them in the buffer LINE at the position pointed to by the Y register.

PUTHEX calls and internal subroutine, MAKEHEX, which does the actual conversion. This call

(rather than in-line code) allows MAKEHEX to first call, then fall through into, an internal routine,

FORMNIB.

When MAKEHEX returns, it contains the two characters to be printed in the high and low bytes of the accumulator; MAKEHEX was processed with the accumulator eight bits wide, so the sixteen-bit mode is switched to, letting both bytes be stored in one instruction. The Y register is incremented twice, pointing it to the space immediately past the second character printed.

FORMNB is both called (for processing the first nibble) and fallen into (for processing the second).

Thus the RTS that exist exits FORMNIB returns variously to either MAKEHEX or PUTHEX. This technique results in more compact code than if FORMNIB were called twice.

The conversion itself is done by isolating the respective bits, and then adding the appropriate offset to form either the correct decimal or alphabetic (A-F) hexadecimal character.

Like all utility routines, the status is saved and restored on entry and exit.

0524 0000

0525 0000

0526 0000

0527 0000

0528 0000

0529 0000

0530 0000

0531 0000

0532 0000

0533 0000

0534 0000

0535 0000

0536 0000

0537 0000

0538 0000

0539 0000

0540 0000 08

0541 0001 200D00

0542 0004 C220

0543 0006

0544 0006 990080

0545 0009 C8

0546 000A C8

0547 000B 28

0548 000C 60

0549 000D

0550 000D E230

0551 000F

0552 000F

0553 000F

0554 000F 48

0555 0010 290F

0556 0012 201B00

0557 0015 EB

0558 0016 68

0559 0017 4A

0560 0018 4A

0561 0019 4A

0562 001A 4A

0563 001B

0564 001B

0565 001B C90A

0566 001D B004

;

;

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

; PUTHEX

;

; CONVERTS NUMBER IN ACCUMULATOR TO HEX STRING

;

; STORED AT LINE,Y

; SAVE AND RESTORED MODE FLAGS

;

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

PUTHEX

MAKEHEX

#M

LINE,Y

MAKEHEX SEP $M+X

LONGA OFF

LONGI OFF

FORMNIB

START

PHP

JSR

REP

LONGA ON

STA

INY

INY

PLP

RTS

PHA

AND

JSR

XBA

PLA

LSR

LSR

LSR

LSR

CMP

BGE

#$OF

FORMNIB

A

A

A

A

#$A

HEXDIG

SAVE MODE FLAGS

GET ASCII CODES A, B

PUT TWO BYTES AT LINE

INCREMENT Y PAST THEM

RESTORE MODE

RETURN

ALL EIGHT BIT

SAVE VALUE TO BE CONVERTED

MASK OFF LOW NIBBLE

CONVERT TO HEX

STORE IN B

RESTORE VALUE

SHIFT HIGH NIBBLE

TO LOW NIBBLE

FALL THROUGH TO CONVERT

IF GREATER THAN OR EQUAL TO

10, USE DIGITS A . . F

246

The Western Design Center

0567 001F 18

0568 0020 69B0

0569 0022 60

0570 0023

0571 0023 69B6

0572 0025 60

0573 0026

0574 0026

HEXDIG

CLC

ADC

RTS

ADC

RTS

END

#’0’

$’A’-11

ELSE SIMPLY ADD ‘0’ TO

CONVERT TO ASCII

SUBTRACT 11, ADD ‘A’

(SORT OF)

Local Symbols

FORMNIB 00001B HEXDIG 000023 MAKEHEX 00000D

247

The Western Design Center

CLRLN

CLRLN performs the very straightforward task of clearing the output buffer, LINE, to blanks. It also contains the global storage reserved for LINE.

Like the other utility routines, CLRLN saves and restores the status.

0575 0000

0576 0000

0577 0000

0578 0000

0579 0000

0580 0000

0581 0000

0582 0000

0583 0000

0584 0000

0585 0000

0586 0000

0587 0000

0588 0000

0589 0000

0590 0001

0591 0003

0592 0003

0593 0003

0594 0003

0595 0006

0596 0009

08

C230

A9A0A0

A24400

0597 0009 9D1200

0598 000C CA

0599 000D CA

0600 000E 10F9

0601 0010 28

60 0602 0011

0603 0012

0604 0012

0605 0012

0606 0012

0607 0058

0608 005A

A0A0A0A0

8D00

LINE

;

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

;

;

; CLRLN

;

; CLEARS ‘LINE’ WITH BLANKS

; SAVES AND RESTORES MODE FLAGS

;

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

CLRLN START

PHP

REP #M+X

LONGA ON

LONGI ON

LDA

LDX

#’ ‘

#68

LOOP STA

DEX

DEX

BPL

PLP

RTS

LINE,X

LOOP

ENTRY

DC

DC

END

70C’ ‘

H’8D00’

Local Symbols

LINE 000012 LOOP 000009

248

The Western Design Center

UPDATE

This routine, common to both the disassembler and the tracer, updates the program counter and other direct page variables – the address mode attribute (ADDRMODE) and the length (OPLEN) – and, using the length, reads the instruction operands into direct page memory.

The address mode and length attributes are stored in a table called ATRIBL, two bytes per instruction.

Since there are 256 different codes, the table size is 512 bytes. The current opcode itself, fetched previously, is used as the index into the table. Since the table entries are two bytes each, the index is first multiplied by two by shifting left. Since the sixteen-bit accumulator was used to calculate the index, both attribute bytes can be loaded in a single operation; since their location in direct page memory is adjacent, they can be stored in a single operation as well.

Normally, the value of OPLEN loaded from the attribute table is the correct one; in the case of the immediate addressing mode, however, the length varies with the setting of the m and x flags. The opcode for the immediate instructions are trapped using just three comparisons, an AND, and four branches to test the opcode bits. Note that the immediate operands are multiplied times two because the opcode already happens to be shifted left once. If the current instruction uses immediate addressing, the stored value of the status register is checked for the relevant flag setting; if m or x, as appropriate, is clear, then OPLEN is incremented. The routines that output the immediate operand now know the correct number of operand bytes to print, and the tracer knows where the next instruction begins.

The status is saved on entry and restored on exit.

0609 0000

0610 0000

0611 0000

0612 0000

0613 0000

0614 0000

0615 0000

0616 0000

0617 0000

0618 0000

0619 0000

0620 0000

0621 0000

0622 0000

0623 0000

0624 0000

0625 0000

0626 0000

0627 0000

0628 0000

0629 0000

0630 0000

0631 0000 08

0632 0001 C230

0633 0003

0634 0003

0635 0003

0636 0003 29FF00

0637 0006 0A

0638 0007

0639 0007 AS

0640 0008 B90080

0641 000B EB

0642 000C 859C

0643 000E

0644 000E AA

0645 000F 98

0646 0010 E210

0647 0012

0648 0012

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

;

; UPDATE

;

; UPDATES ATTRIBUTE VARIABLES BASED ON OPCODE

; PASSED IN ACCUMULATOR BY LOOKING IN ATTRIBUTE

; TABLES

;

; SAVES AND RESTORES MODE FLAGS

;

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

UPDATE START

USING ATRIBL

LDYI

LDXI

EQU

EQU

PHP

REP

LONGA

LONGI

AND

ASL

TAY

LDA

XBA

STA

TAX

TYA

SEP

LONGI

$A0+2

$A2+2

#M+X

ON

ON

#$FF

A

OPCODE VALUE TIMES TWO

SAVE STATE

MASK HIGH BYTE

TIMES TWO

ATRIBL,Y INDEX INTO ATTRIBUTE TABLE

SWAP ORDER OF ENTRIES

ADDRMODE SAVE ADDRMODE, MNEMONIC INDEX

ADDRMODE TO X (LOW)

OPCODE * 2 TO ACCUM

#X

OFF

249

The Western Design Center

0649 0012 BCFF7F

0650 0015 849F

0651 0017

0652 0017

0653 0017 A697

0654 0019 E001

0655 001B F02E

0656 001D

0657 001D 892000

0658 0020 D029

0659 0022 C94401

0660 0025 F00A

0661 0027 891E00

0662 002A D00E

0663 002C C94001

0664 002F 9009

0665 0031 A596

0666 0033 291000

0667 0036 F011

0668 0038 D011

0669 003A

0670 003A 291E00

0671 003D C91200

0672 0040 D009

0673 0042 A596

0674 0044 292000

0675 0047 D002

0676 0049

0677 0049 E69F

0678 004B

0679 004B

0680 004B A000

0681 004D 8005

0682 004F

0683 004F A780

0684 0051

0685 0051 AA

0686 0052 9687

0687 0054

0688 0054 E680

;

CHKA

;

LONG

SHORT

;

LOOP

LOOPIN

0689 0056 C8

0690 0057 C49F

0691 0059 D0F4

0692 005B

0693 005B 28

0694 005C 60

0695 005D

DONE

Local Symbols

CHKA

LDYI

SHORT

00003A CHKX

000140 LONG

000048

LDY

STY

LENS-1,X

OPLEN

LDX

CPX

BEQ

BIT

BNE

CMP

BEQ

BIT

BNE

CMP

BLT

LDA

AND

BEQ

BNE

AND

CMP

BNE

LDA

AND

BNE

INC

EBIT

#1

SHORT

#$20

SHORT

#LDXI

CHKX

#$F+2

CHKA

PREG

CHKA

PREG

#X

LONG

SHORT

#$0F+2

#$9+2

SHORT

PREG

#M

SHORT

OPLEN

EMULATION MODE?

TEST BIT ZERO

YES - - ALL IMMEDIATE ARE

SHORT

IS MSD+2 EVEN?

NO, CAN’T BE IMMEDIATE

IS IT LDX #?

IS LSD+2 ZERO?

CHECK ACCUMULATOR OPCODES

MUST = LDY# OR GREATER

NO, MAYBE ACCUMULATOR

IF IT IS, WHAT IS FLAG SETTING?

CLEAR – 16 BIT MODE

SET – 8 BIT MODE

MASK OUT MSD

IS LSD = 9?

WHAT IS FLAG SETTING?

NO, 8 BIT MODE

LONG IMMEDIATE - - LENGTH IS

ONE MORE THEN FOUND IN TABLE

LDY

BRA

[PCREG]

TAX

STX

INC

INY

CPY

BNE

PLP

RTS

END

#0

LOOPIN

ORPNDL-1,Y

PCREG

OPLEN

LOOP

LOAD 16 BITS - - 16 BIT MODE

USED TO BUMP PCREG EASILY

TRUNCATE TO EIGHT BITS

SAVE

MOVE PC PAST NEXT INSTRUCTION

BYTE

MOVED ALL OPERAND BYTES?

NO, CONTINUE

000031 DONE

000049 LOOP

GET LENGTH OF OPERATION

00005B

00004F

LDXI

LOOPIN

000144

000054

250

The Western Design Center

PRINTLN

This is the output routine. In this version, an existing 6502 output routine is called, necessitating a reversion to the emulation mode. Since this is the only place a 6502 routine is called, a simpler mode-switching routine than the generalized one of the previous chapter is used. The user registers do not need to be preserved, but zero needs to be swapped into the direct page to make it address page zero.

The main loop is in the emulation mode until the null terminal byte of LINE is encountered; on exit, the native mode, direct page, and status are restored.

0696 0000

0697 0000

0698 0000

0699 0000

0700 0000

0701 0000

0702 0000

0703 0000

0704 0000

0705 0000

0706 0000

0707 0000

0708 0000

0709 0000

0710 0000

0711 0000

0712 0000

0713 0000

0714 0000 08

0715 0001 0B

0716 0002 F40000

0717 0005 2B

0718 0006

0719 0006

0720 0006

0721 0006 38

0722 0007 FB

0723 0008

0724 0008 A000

0725 000A

0726 000A B90080

0727 000D F006

0728 000F 20EDFD

0729 0012 C8

0730 0013 80F5

0731 0015

0732 0015 18

0733 0016 FB

0734 0017 2B

0735 0018 28

0736 0019 60

0737 001A

0738 001A

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

;

; PRINTLN

;

; MACHINE-DEPENDENT CODE TO OUTPUT

; THE STRING STORED AT ‘LINE’

;

; SAVES AND RESTORED MODE FLAGS

;

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

PRINTLN

COUT

LOOP

DONE

START

EQU

PHP

PHD

PEA

PLD

LONGA

LONGI

SEC

XCE

LDY

LDA

BEQ

JSR

INY

BRA

CLC

XCE

PLD

PLP

RTS

END

$FDED

0

OFF

OFF

#0

DONE

COUT

LOOP

APPLE CHARACTER OUTPUT ROUTINE

SAVE STATUS

SAVE DIRECT PAGE

SWITCH TO PAGE ZERO

FOR EMULATION

SWITCH TO EMULATION

LINE,Y LOOP UNTIL STRING TERMINATOR

REACHED

RESTORE NATIVE MODE

RESTORE DIRECT PAGE

RESTORE MODE FLAGS

Local Symbols

COUT 00FDED DONE 000015 LOOP 0000DA

251

The Western Design Center

TRACE

This is the actual entry to the trace routine. It performs initialization similar to LIST, and additionally sets up the BRK vectors, so they can point to locations within the tracer.

The e flag, direct page register and data bank register are all given initial values of zero. The program counter and program counter bank are presumed to have been initialized by the user. The first byte of the program to be traced is loaded; since indirect long addressing is used, this program can be used with the 65816 to debug programs located in any bank. It can, of course, also be used with the 65802.

The jump to TBEGIN enters the main loop of the trace routine in the middle – in other words,

“between instructions.”

0739 0000

0740 0000

0741 0000

0742 0000

0743 0000

0744 0000

0745 0000

0746 0000

0747 0000

0748 0000

0749 0000

0750 0000

0751 0000

0752 0000

0753 0000

0754 0000 08

0755 0001 18

0756 0002 FB

0757 0003 08

0758 0004

0759 0004 C210

0760 0006

0761 0006 F40000

0762 0009

0763 0009 BA

0764 000A 8E3D00

0765 000D

0766 000D F40003

0767 0010 2B

0768 0011

0769 0011 8691

0770 0013

0771 0013 E220

0772 0015

0773 0015

0774 0014 A901

0775 0017 8597

0776 0019 6493

0777 001B 6494

0778 001D 6495

0779 001F 649E

0780 0021

0781 0021 9C0080

0782 0024

0783 0024 A20080

0784 0027 8EF003

0785 002A

0786 002A AEE6FF

0787 002D E000C0

0788 0030 9003

TRACE

USRBRKV

BRKN

APPEND DB. TRACE

;

;

; TRACE

; ENTRY POINT FOR TRACER

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

START

GEQU

GEQU

PHP

CLC

XCE

PHP

REP

LONGI

PEA

TSX

STX

PEA

PLD

STX STACK

SEP #$20

LONGA OFF

LDA

STA

STZ

STZ

STZ

STZ

#1

EBIT

DIRREG

DIRREGH

DBREG

MNX+1

STZ

LDX

STX

LDX

CPX

BLT

$3F0

$FFE6

#$10

ON

0

SAVSTACK

DPAGE

USER BRK VECTOR FOR APPLE / /

NATIVE MODE BRK VECTOR

SAVE CALLING STATE

OLD STACK BOUNDARY

INITIALIZE DIRECT PAGE

DIRECT PAGE, DATA BANK

TO POWER-UP DEFAULTS

STEPCNTRL

#EBRKN

USRBRKV

PATCH BRK VECTORS

TO POINT TO TRACE CODE

BRKN

#$C000

OK

FIND OUT WHERE BRKN POINTS TO

MAKE SURE IT’S RAM ON AN APPLE

252

The Western Design Center

0789 0032 4C0080

0790 0035 8E3F00

0791 0038

0792 0038 A780

0793 003A 4C0080

0794 003D

0795 003D

0796 003D 0000

0797 003F

0798 003F 0000

0799 0041

OK

JMP

STX

LDA

JMP

SAVSTACK ENTRY

DS

USRBRKN ENTRY

DS

SAVRAM ENTRY

2

2

QUIT

USRBRKN

[PCREG]

TBEGIN

MIGHT AS WELL GIVE UP NOW . . .

GET FIRST OPCODE

BEGIN !

0800 0041 0000

0801 0043

Local Symbols

OK 000035 SAVRAM

DS

END

2

000041 SAVSTACK 00003D USRBRKN 00003F

253

The Western Design Center

EBRKIN

This is the main loop of the tracer. It has three entry points: one each for the emulation and native mode BRK vectors to point top, and a third (TBEGIN) which is entered when then program starts tracing and there is no “last instruction.” This entry provides the logical point to begin examining the tracing process.

TRACE has performed some initialization, having loaded the opcode of the first instruction to be traced into the accumulator. As with FLIST, UPDATE is called to update the program counter and copy the instruction attributes and operand into direct page memory. The routine CHKSPLC is then called to handle the flow-altering instructions' in these cases, it will modify PCREG to reflect the target address. In either case, the opcode of the next instruction is loaded, and a BRK instruction (a zero) is stored in its place, providing a means to regain control immediately after the execution of the current instruction.

The contents of the RAM pointed to by the (arbitrary) ROM values in the native mode BRK vector are temporarily saved, and the location is patched with a jump to the NBRKIN entry point.

The registers are then loaded with their user program values: these will have been preinitialized by

TRACE, or will contain the values saved at the end of the execution of the previous instruction. Note the order in which the registers are loaded; some with direct page locations, others pushed onto the stack directly from direct page locations; then pull into the various registers. Once the user registers have been loaded with their values, they cannot be used for data movement. The P status register must be pulled last, to prevent any other instructions from modifying the flags.

The e bit is restored by loading the P register with a mask reflecting the value it should have; e is exchanged with the carry, and a second PLP instruction restores the correct status register values.

The routine exists via a jump indirect long through the “old” pcreg variable, which points to the current instruction. It will be reentered (at either EBRKIN or NBRKIN) when the BRK instruction that immediately follows the current instruction is executed.

Before this, however, the single instruction will be executed by the processor; any memory to be loaded or stored, or any registers to be changed by the instruction, will be modified.

After the BRK is executed, control returns to the tracer either at EBRKIN, if the user program was in emulation mode, or at NBRKIN if the user program was in native mode. The first thing that must be done is preserve the state of the machine as it was at the end of the instruction.

The BRK instruction has put the program counter bank (only in native mode), the program counter, and the status register on the stack. The program already knows the address of the next instruction, so the value on the stack can be disregarded. The status register is needed, however.

Entry to EBRKIN is from the Apple I I monitor user vector at $3F0 and $3F1. The Apple II monitor handles emulation mode BRK instructions by storing the register values to its own zero page locations; it pulls the program counter and status register from the stack and stores them, too. The code at EBRKIN dummies up a native mode post-BRK stack by first pushing three place-holder bytes, then loading the status register the form where the Apple Monitor stored it, and pushing it. The accumulator and X registers are re-loaded from monitor locations; Y has been left intact. A one is stored to variable EBIT, which will be used to restore the emulation mode when EBRKIN exists. The processor switches to native mode, and control falls through into

NBRKIN, the native mode break handler.

With the stack in the correct state for both emulation mode and native mode entries, the routine proceeds to save the entire machine context. The register sizes are extended to sixteen bits to provide a standard size which encompasses the maximum size possible. The data bank and direct page registers are pushed onto the stack; the DPAGE value is pushed on immediately after, and pulled into the direct page, establishing the local direct page. With this in place, the A, X, and Y registers can be stored at their direct page locations. The register values pushed on the stack are picked off using stack-relative addressing. Since control is not returned by execution of an RTI (as is usual for interrupt processing), but instead is returned by means of a JMP, the stack must be cleaned up. Since seven bytes have been pushed, seven is added to the current stack pointer, and then saved at the direct page variable STACK. This being done, a small local stack region $140 can be allocated.

The memory borrowed as a RAM native-mode BRK vector is restored.

The current line is then disassembled in the same manner as LIST. The register values just stored into memory are also displayed via the routine DUMPREGS.

254

The Western Design Center

Once this is done, the effect has been achieved and the contents of the registers between instructions has been made visible. Before resuming execution of the program being traced, a check is made to see if the user wishes to quit, pause or step, or toggle between tracing and stepping.

Before returning to the TBEGIN entry, the BRK instruction stored at the location of the new “current” instruction is replaced with the saved opcode, the current program counter is moved to the old program counter, and the cycle begins again at TBEGIN

.

255

The Western Design Center

0802 0000

0803 0000

0804 0000

0805 0000

0806 0000

0807 0000

0808 0000

0809 0000

0810 0000

0811 0000

0812 0000

0813 0000

0814 0000

0815 0000

0816 0000

0817 0000

0818 0000

0819 0000

0820 0000

0821 0000

0822 0000

0823 0003

0824 0004

0825 0006

0826 0007

0827 0009

0828 000B

0829 000B

0830 000B

0831 000B

0832 000B

F40000

4848

A548

48

A545

A646

0833 000B EE9703

0834 000E

0835 000E

0836 000F

0837 0010

18

FB

0838 0010

0839 0010

0840 0010

0841 0010

0842 0012

0843 0012

C230

0844 0012

0845 0012

0846 0013

0847 0014

0848 0017

8B

0B

F40003

2B

0849 0018

0850 0018 858F

0851 001A 868B

0852 001C 848D

0853 001E

0854 001E

0855 0020

0856 0022

0857 0022

0858 0023

0859 0024

0860 0027

A301

8593

3B

18

690700

8595

0861 0029

0862 0029 A303

0863 002B 8595

0864 002D

0865 002D A94001

0866 0030 1B

;

;

;

;

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

; EBRKIN, NBRKIN, TBGIN

;

; ENTRY POINTS FOR TRACER MAIN LOOP

; EBKIN AND NBKIN RECOVER CONTROL AFTER

; ‘BRK’ INSTRUCTION EXECUTED

;

; TBEGIN IS INITIAL ENTRY FROM ‘TRACE’

;

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

;

EBRKIN

;

NBRKIN

START

REP #M+X

LONGA ON

LONGI ON

PHB

PHD

PEA

PLD

DPAGE

STA

STX

STY

LDA

STA

TSC

CLC

ADC

STA

LDA

STA

LDA

TCS

AREG

XREG

YREG

1,S

DIRREG

#7

STACK

3,S

DBREG

#$140

ENTRY FROM EMULATION MODE

FOR TRACER

LONG

OFF

A

LONGI OFF

PEA

PHA

LDA

PHA

LDA

LDX

0

$48

$45

$46 note that if direct page is relocated in emulation mode, these locations will be used by monitor brk handler

EBIT+DPAGE INC

CLC

XCE

ENTRY

APPLE I I MONITOR

LOCATIONS

FOR P, AA

AND X

MARK AS EMULATION MODE

GO NATIVE

ENTRY FROM NATIVE MODE

FOR TRACER

SAVE DATA BANK

DIRECT PAGE

SWITCH TO APPLICATION

DIRECT PAGE

STASH USER REGISTERS

GET DIRECT PAGE VALUE

SAVED

CALCULATE TRUE STACK

(BEFORE BRK)

SAVE AS STACK

SAVE DATA BANK, STATUS

STATUS REGISTER

SET UP SMALL STACK

256

The Western Design Center

0867 0031

0868 0031

0869 0032

0870 0033

4B

AB

AE0080

0871 0036

0872 0039

AD0180

9D0100

0873 003C AD0080

0874 003F 9D0100

0875 0042

0876 0045

0877 0048

0878 0048

200080

200080

0881 004E

0882 0051

0883 0054

200080

0879 004B

0880 004B 200080

200080

200080

E220 0884 0054

0885 0056

0886 0056

0887 0056

0888 0058

C210

0889 0058

0890 0058 2CE000

0891 005B 300E

0892 005D

0893 005D 200080

0894 0060

0895 0062

9068

5011

0896 0064

0897 0066

A980

8DE000

0898 0069

0899 006B

800A

0900 006B 200080

0901

0902

0903

006E

0070

0072

0904 0075

905A

5003

9CE000

;

DOPAUSE

0905 0075

0906 0075

0907 0077

0908 0079

0909 0079

0910 0079

0911 007A

0912 007A

A583

8780

AB

0913 007A A680

0914 007C 8684

0915 007E

0916 0080

A582

8586

0917 0082

0918 0082

0919 0083

0920 0083

98

8587

200080 0921 0085

0922 0088

0923 0088

0924 0088

0925 0088

0926 008B

200080

0927 008B A780

0928 008D

0929 008D 8583

0930 008F

0931 0091

A900

8780 0932 0091

0933 0093

0934 0093

;

;

;

;

;

;

RESUME

TBEGIN

GO

LDA

STA

ENTRY

TAY

NCODE

[PCREG]

LDX

STX

LDA

STA

TYA

STA

JSR

BIT

BMI

JSR

BCC

BVC

LDA

STA

BRA

JSR

BCC

BVC

STZ

JSR

JSR

JSR

JSR

PHK

PLB

LDX

LDA

STA

LDA

STA

JSR

JSR

USRBRKN

SAVRAM+1

!1,X

SAVRAM

!0,X

FLIST

FRMOPRND

PRINTLN

CLRLN

DUMPREGS

PRINTLN

SEP #M

LONGA ON

REP

LONGI

STEPCNTRL

DOPAUSE

STEP

QUIT

RESUME

#$80

STEPCNTRL

RESUME

PAUSE

QUIT

RESUME

STEPCNTRL

PCREG

OPCREG

PCREGB

OPCREGB

CODE

UPDATE

JSR

LDA

STA

LDA

STA

ENTRY

CHKSPCL

[PCREG]

NCODE

#0

[PCREG]

MAKE DATA BANK = PROGRAM BANK

RESTORE BORROWED RAM

FORMAT DISASSEMBLY LINE

PRINT IT

OUPUT REGISTER VALUES

STEP ONE AT A TIME

USER WANTS TO QUIT

WANTS TO KEEP STEPPING

HIT CR; WANTS TO TRACE, NOT

STEP - - SET FLAG

TRACING; ONLY WAIT IF USER

HITS KEY

WANTS TO KEEP TRACING

HIT CR; WANTS TO STEP, NOT

TRACE - - CLEAR FLAG

RESTORE ONLD ‘NEXT’; IT’S ABOUT

TO BE EXECUTED

SAVE THE CURRENT (ABOUT TO BE

EXECUTED) OPCODE

REMEMBER WHERE YOU GOT IT FROM

PCREG POINTED TO IT AFTER

PREVIOUS CALL TO UPDATE

SAVE CURRENT OPCODE

UPDATE PC TO POINT PAST THIS

INSTRUCTION

UPDATE ATTRIBUTE VARIABLES

CHECK TO SEE IF THIS CAUSES A

TRANSFER

GET NEXT OPCODE TO BE EXECUTED

(ON NEXT LOOP THROUGH)

SAVE IT

PUT A BREAK ($00) THERE TO

REGAIN CONTROL

257

The Western Design Center

0935 0093

0936 0095

0937 0095

0938 0095

C230

AE0080

0939 0098 BD0000

0940 009B 8D0080

0941 009E BD0100

0942 00A1 8D0180

0943 00A4 A94C00

0944 00A7 9D0000

0945 00AA A91000

0946 00AD 9D0100

0947 00B0 A561

0948 00B2 1B

0949 00B3 D495

0950 00B5 D496

0951 00B7 D493

0952 00B9

0953 00B9 6497

0954 00BB

0955 00BB A58F

0956 00BD A48D

0957 00BF A68B

0958 00C1

0959 00C1 2B

0960 00C2

0961 00C2 28

0962 00C3 28

0963 00C4 FB

0964 00C5

0965 00C5 AB

0966 00C6 28

0967 00C7

0968 00C7 DC8403

0969 00CA

0970 00CA

0971 00CA E220

0972 00CC

0973 00CC

0974 00CC A583

0975 00CE 8780

0976 00D0

0977 00D0 C210

0978 00D2

0979 00D2

0980 00D2 AE0080

0981 00D5 E8

0982 00D6 E8

0983 00D7 9A

0984 00D8

0985 00D8 F40000

0986 00DB 2B

0987 00DC

0988 00DC 28

0989 00DD FB

0990 00DE 28

0991 00DF 60

0992 00E0

0993 00E0

0994 00E0

0995 00E1

00

QUIT

LDA

STA

LDA

STA

LDA

TCS

PEI

PEI

PEI

REP #M+X

LONGA ON

LONGI

LDX

ON

USRBRKIN

LDA

STA

LDA

STA

!0,X

SAVRAM

!1,X

SAVRAM+1

#$4C

!0,X

#NBRKIN

!1,X

STACK

(DBREG)

(EBIT-1)

(DIRREG)

STZ

LDA

LDY

LDX

PLD

PLP

PLP

XCE

PLB

PLP

JMP

LDX

INX

INX

TXS

PLP

XCE

PLP

RTS

AREG

YREG

XREG

ENTRY

SEP #$20

LONGA OFF

LDA

STA

REP

LONGI

PEA

PLD

STEPCNTRL ENTRY

DS

END

EBIT

[DPAGE+OPCREG]

NCODE

[PCREG]

#$10

ON

SAVSTACK

0

1

BORROW THIS RAM FOT A SECOND

RESTORE STACK

GET THIS STUFF ON STACK

ASSUME NATIVE MODE ON RETURN

RESTORE USER REGISTERS

POP IT AWAY!

ON TO THE NEXT!

CLEAN UP OLD PATCH

GET ORIGINAL STACK POINTER

RESTORE ZERO PAGE

Local Symbols

DOPAUSE

RESUME

00006B

000075

GO

STEPCNTRL

000093

0000E0

NBRKIN

TBEGIN

000010

000079

QUIT 0000CA

258

The Western Design Center

CHKSPCL

This routine checks the opcode about to be executed to see if it will cause a transfer of control. Is it a branch, a jump, or a call? If it is any of the three, the destination of the transfer must be calculated and stored at

PCREG so that a BRK instruction can be stored there to maintain control after the current instruction is executed.

A table that contains all of the opcodes which can cause a branch or jump (SCODES) is scanned. If a match with the current instruction is not found, the routine exists and tracing resumes.

If a match is found, the value of the index into the table is checked. The opcodes for all the branches are stored at the beginning of SCODES, so if the value of the index is less than 9, the opcode was a branch and can be handled by the same general routine.

The first thing that must be determined if the opcode is a branch is whether or not the branch will be taken. By shifting the index right (dividing by two) an index for each pair of different types of branches is obtained. This index is used to get a mask for the bit in the status register to be checked. The value shifted into the carry determines whether the branch is taken if the status bit is set or clear.

If a branch is not taken, the routine exits. If, however, a branch is taken, the new program counter value must be calculated by sign extending the operand and adding it to the current program counter.

Each of the other opcodes (jumps and calls) are dispatched to handler routines through a jump table.

Since only the new program counter values must be calculated, jumps and calls with the same addressing mode can be handled by the same routine.

Breaks, co-processor calls, and RTIs are not handled at all; a more robust tracer would handle BRKs by letting breakpoints be set and cleared. Since the software interrupts are not implemented, and software tracing of hardware interrupts is impractical, RTI is left unimplemented. The program counter is incremented by one, causing these instructions to be bypassed completely.

All of the jumps and calls are straightforward. Long addressing is used to force the stack and indirect addressing modes to access bank zero. Also notice the way the data bank register is copied to the program counter bank for indirect indexed addressing. Finally, note how the long addressing modes call their absolute analogs as subroutines, then handle the bank byte.

259

The Western Design Center

0996 0000

0997 0000

0998 0000

0999 0000

1000 0000

1001 0000

1002 0000

1003 0000

1004 0000

1005 0000

1006 0000

1007 0000

1008 0000

1009 0000

1010 0000

1011 0000

1012 0000

1013 0000 A20000

1014 0003 A587

1015 0005

1016 0005 DD0080

1017 0008 F004

1018 000A CA

1019 000B 10F8

1020 000D 60

1021 000E

1022 0003

1023 0003 E210

1024 0010

1025 0010

1026 0010 8A

1027 0011 C909

1028 0013 B00F

1029 0015

1030 0015 4A

1031 0016 AA

1032 0017 BD0080

1033 001A

1034 001A 2596

1035 001C

1036 001C B003

1037 001E

1038 001E F00B

1039 0020 60

1040 0021

1041 0021 D008

1042 0023 60

1043 0024

1044 0024 0A

1045 0025

1046 0025 AA

1047 0026

1048 0026 C210

1049 0028 7CEE7F

1050 0028

1051 0028

1052 002B A9FF

1053 002D

1054 002D EB

1055 002E

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

; CHKSPCL

;

; CHECK CURRENT OPCODE (IN CODE) FOR SPECIAL CASES

;

; - - INSTRUCTIONS WHICH TRANSFER CONTROL (JMP, BRA, ETC.)

;

; ASSUMES SHORTA, LONGI - -CALLED BY EBRKIN

;

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

CHKSPCL

LOOP

START

LONGA OFF

LONGI ON

LDX

LDA

CMP

BEQ

DEX

BPL

RTS

#SCX-SCODES

CODE

SCODES,X

HIT

LOOP

CHECK TO SEE IF CURRENT OPCODE

IS IN EXCEPTION TABLE

EXIT IF NOT

;

HIT

;

BCS

BEQ

BBS

RTS

BNE

RTS

ASL

;

NOTBR

TAX

REP

JMP

;

DOBRANCH ENTRY

LDA

XBA

SEP

LONGI

TXA

CMP

BGE

LSR

TAX

LDA

AND

#X

OFF

#9

NOTBR

A

PHASK,X

PREG

BBS

DOBRANCH

DOBRANCH

A

#X

(SPJMP-18,X)

#$FF

IF INDEX WAS LESS THAN 9, IT’S

A BRANCH

SEE IF ‘ODD OR EVEN’

GET MASK TO SELECT CORRECT

PREG BIT

IS IT SET?

IF INDEX WAS ODD, BRANCH IF

PREG BIT IS SET

ELSE IF EVEN, BRANCH IF CLEAR

“BRANCH IF BIT SET”

NOT A BRANCH INSTRUCTION;

MULTIPLY BY TWO

AND INDEX INTO HANDLER JUMP

TABLE

BIAS JUMP TABLE BY 9

SET ACCUMULATOR BYTE HIGH

(ANTICIPATE NEGATIVE)

AND SIGN EXTEND INTO X

1056 002E A588

1057 0030

LDA OPRNDL

260

The Western Design Center

1058 0030 C231

1059 0032

1060 0032

1061 0032

1062 0032 3003

1063 0034

1064 0034 297F00

1065 0037

1066 0037 6580

1067 0039 8580

1068 003B E220

1069 003D 60

1070 003E

;

OK

REP #M+X+C

LONGA ON

LONGI ON

BMI

AND

ADC

STA

SEP

RTS

END

OK

#$7F

PCREG

PCREG

#M

MAKE REGS LONG; CLEAR CARRY

(ANTICIPATE ADC)

NUMBER WAS NEGATIVE; ALL IS OK

CLEAR HIGH BYTE OF ACCUM

(POSITIVE NUMBER)

RETURN WITH ACCUM SHORT

Local Symbols

BBS

NOTBR

000021 DOBRANCH 00002B

000024 OK 000037

HIT

1071 0000

1072 0000

1073 0000

1074 0000

1075 0000 60

1076 0001

1077 0001

1078 0001

1079 0001 A688

1080 0003 8680

1081 0005 60

1082 0006

1083 0006

1084 0006 C221

1085 0008

1086 0008 A588

1087 000A 6580

1088 000C 8580

1089 000E E220

1090 0010

1091 0010 60

1092 0011

1093 0011

1094 0011

1095 0011 A688

1096 0013 8680

1097 0015 A58A

1098 0017 8582

1099 0019 60

1100 001A

1101 001A

1102 001A A691

1103 001C EC0080

1104 001F D003

1105 0021 4C0080

1106 0024 E8

1107 0025

1108 0025 C220

1109 0027 BF000000

1110 002B 1A

1111 002C 8580

1112 002E E220

1113 0030

1114 0030 60

1115 0031

1116 0031

1117 0031

SBRK

SRTI

SCOP

SJSRABS

SJMPABS

SBRL

SJSRABSL

SJMPABSL

SRTS

CONT

SRTL ENTRY

REP

LDA

INC

STA

SEP

RTS

ENTRY

ENTRY

LDX

STX

LDA

STA

RTS

ENTRY

LDX

CPX

BNE

JMP

INX

START

ENTRY

ENTRY

RTS

ENTRY

ENTRY

LDX

STX

RTS

OPRNDL

PCREG

ENTRY

REP #M+C

LONGA ON

LDA OPRNDL

ADC

STA

SEP #M

LONGA OFF

RTS

PCREG

PCREG

OPRNDL

PCREG

OPRNDB

PCREGB

STACK

SAVSTACK

CONT

QUIT

#M

>0,X

A

PCREG

#M

00000E LOOP

ABSOLUTES - -

MOVE OPERAND TO PC

LONG BRANCH

LONG ACCUM AND CLEAR CARRY

ADD DISPLACMENT TO

PROGRAM COUNTER

ABSOLUTE LONGS

MOVE OPERAND, INCLUDING BANK,

TO PROGRAM COUNTER

RETURN

PEEK ON STACK

IF ORIGINAL STACK . . .

RETURN TO MONITOR

ALWAYS IN BANK ZERO

ADD ONE TO GET TRUE RETURN

VALUE

000005

THESE ARE NOT IMPLEMENTED!

(AN EXERCISE FOR READER)

RETURN LONG

261

The Western Design Center

1118 0031 201A00

1119 0034

1120 0034 E8

1121 0035 E8

1122 0036 BF000000

1123 003A 8582

1124 003C 60

1125 003D

1126 003D

1127 003D

1128 003D A688

1129 003F

1130 003F C220

SJMPIND

JSR

INX

INX

LDA

STA

RTS

SRTS

>0,X

PCREGB

ENTRY

LDX

REP

OPRNDL

#M

1131 0041 BF000000

1132 0045 8580

1133 0047 E220

1134 0049 60

1135 004A

1136 004A

1137 004A

1138 004A 203D00

1139 004D E8

1140 004E E8

1141 004F BF000000

1142 0053 8582

1143 0055 60

1144 0056

1145 0056

1146 0056

1147 0056

1148 0056 A48B

1149 0058 A688

1150 005A 8699

1151 005C A582

1152 005E 859B

1153 0060

1154 0060 C220

1155 0062 B799

1156 0064 8680

1157 0066 E220

1158 0068

1159 0068 60

1160 0069

1161 0069

1162 0069

SJMPINDL

SJMPINDX

SJSRINDX

LDA

STA

SEP

RTS

END

>0,X

PCREG

#M

ENTRY

JSR

INX

IJNX

LDA

STA

RTS

SJMPIND

>0,X

PCREGB

ENTRY

ENTRY

LDY

LDX

STX

LDA

STA

REP

LDA

STA

SEP

RTS

XREG

OPRNDL

TEMP

RCREGB

TEMP+2

#M

[TEMP],Y

PCREG

#M

Local Symbols

CONT

SJMPABSL

SJJSRABS

SRTL

000024

000011

000001

000031

SBRL

SJMPIND

SJSRABSL

SRTS

000006

00003D

000011

00001A

SCOP

SJMPINDL

SJSRINDX

DO NORMAL RETURN,

THEN GET BANK BYTE

A IS NOW SHORT FOR BANK BYTE

INDIRECT

GET OPERAND

JMP IND ALWAYS IN BANK ZERO

SAME AS JMP INDIRECT,

PLUS BANK BYTE

ACCUM IS SHORT NOW

INDEX JUMPS

LET CPU DO ADDITION

GET INSIRECT POINTER

INDEXED JUMPS ARE IN PROGRAM

BANK

‘Y IS X’

000000

00004A

000056

SJMPABS

SJMPINDX

SRTI

000001

000056

000000

262

The Western Design Center

DUMPREGS

This routine forms an output line that will display the contents of the various registers. The routine is driven in a loop by a table containing single-character register names (“A,” “X,” and so on) and the address of the direct page variable that contains the corresponding register value. It is interesting in that a direct page pointer to a direct page address is used, since the two index registers are occupied with accessing the table entries and pointing to the next available location in the output buffer.

1163 0000

1164 0000

1165 0000

1166 0000

1167 0000

1168 0000

1169 0000

1170 0000

1171 0000

1172 0000

1173 0000

1174 0000

1175 0000

1176 0000 08

1177 0001 E230

1178 0003

1179 0003

1180 0003

1181 0003 A000

1182 0005

1183 0005 A903

1184 0007 859A

1185 0009

1186 0009 A209

1187 000B

1188 000B BD4400 LOOP

1189 000E 8599

1190 0010 CA

1191 0011 BD4400

1192 0014 200080

1193 0017 CA

1194 0018 10F1

1195 001A

1196 001A 1995

1197 001C 8599

1198 001E A9C2

1199 0020 200080

1200 0023 A996

1201 0025 8599

1202 0027 A9D0

1203 0029 200080

1204 002C A9C5

1205 002E 990080

1206 0031 C8

1207 0032 A9BA

1208 0034 990080

1209 0037 C8

1210 0038

1211 0038 A9B0

1212 003A A697

1213 003C F001

1214 003E 1A

1215 003F 990080

1216 0042

OK

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

;

; DUMPREGS

;

; DISPLAYS CONTENTS OF REGISTER VARIABLES IN ‘LINE’

;

; SAVES AND RESTORES MODE

;

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

DUMPREGS START

PHP

SEP

LONGA OFF

LONGI OFF

LDY

LDA

STA

LDX

LDA

STA

DEX

LDA

JSR

DEX

BPL

LDA

STA

LDA

JSR

LDA

STA

LDA

JSR

LDA

STA

INY

LDA

STA

INY

LDA

LDX

BEQ

INC

STA

#M+X

#0

#>DPAGE

TEMPH

#ENDTABLE-TABLE

TABLE,X

TEMP

TABLE,X

PUTREG16

LOOP

#DBREG

TEMP

#’B’

PUTREG8

#PREG

TEMP

#’P’

PUTREG8

#’E’

LINE,Y

#’:’

LINE,Y

#’0’

EBIT

OK

A

LINE,Y

STOE DPAGE HIGH IN TEMP HIGH

LENGTH OF COMMAND TABLE

GET ADDRESS OF NEXT REGISTER

GET REGISTER ‘NAME’

NOW ALL THE 8-BIT REGISTERS

‘0’ BECOMES ‘1’

263

The Western Design Center

1217 0042

1218 0042 28

1219 0043 60

1220 0044

1221 0044 C494

1222 0046 D392

1223 0048 D98E

1224 004A D88C

1225 004C C1

1226 004D 90

1227 004E

PLP

RTS

TABLE DC

DC

DC

DC

DC

ENDTABLE DC

END

Local Symbols

ENDTABLE 00004D LOOP 00000B

C’D’,I1’DIRREGH’

C’S’,I1’STACKH’

C’Y’,I1’YREGH’

C’X’,I1’XREGH’

C’A’

I1’AREGH’

DIRECT PAGE

ADDRESS OF

REGISTER

VARIABLES

OK 00003F TABLE 000044

264

The Western Design Center

PUTRTEG8

This routine, along with PUTREG16, is called by DUMPREGS to actually output a register value once its label and storage location have been loaded from the table. Naturally, it calls PUTREX to convert the register values to hexadecimal.

1228 0000

1229 0000

1230 0000

1231 0000

1232 0000

1233 0000

1234 0000

1235 0000

1236 0000

1237 0000

1238 0000

1239 0000

1240 0000 990080

1241 0003 C8

1242 0004 A9BC

1243 0006 990080

1244 0009 C8

1245 000A 8012

1246 000C

1247 000C

1248 000C 990080

1249 000F C8

1250 0010 A9BD

1251 0012 990080

1252 0015 C8

1253 0016 C8

1254 0017 B299

1255 0019 C699

1256 001B 200080

1257 001E

1258 001E C8

1259 001F B299

1260 0021 20080

1261 0024 C8

1262 0025 60

1263 0026

Local Symbols

PRIN 0000IE

;

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

;

; PUTREGS

;

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

PUTREG8 START

STA

INY

LDA

STA

INY

BRA

PUTREG16 ENTRY

STA

INY

LDA

STA

INY

INY

LDA

DEC

JSR

PRIN INY

LDA

JSR

INY

RTS

END

PUTREG16

LINE,Y

#’=’

LINE,Y

PRIN

LINE,Y

#’=’

LINE,Y

(TEMP)

TEMP

PUTHEX

(TEMP)

PUTHEX

00000C

A CONTAINS REGISTER ‘NAME’

EQUALS . .

USE PUTREG16 CODE

A CONTAINS REGISTER ‘NAME’

EQUALS . .

TEMP POINTS TO REGISTER

VARIABLE HIGH

TEMP POINTS TO REGISTER

VARIABLE LOW (OR 8 BIT)

265

The Western Design Center

TABLES

The next several pages list the tables used by the program – SPJMP, PMASK, SCODES, MN,

MODES, LENS, and ATRIBL.

SPJMP is a jump table of entry points to the trace handlers for those instructions which modify the flow of control.

PMASK contains the masks used to check the status of individual flag bits to determine if a branch will be taken.

SCODS is a table containing the opcodes of the special (flow-altering) instructions.

ATRBL is the attribute table for all 256 opcodes. Each table entry is two bytes, one is an index into the mnemonic table, the other the address mode. This information is the key to the other tables, all used by the

UPDATE routine, which puts a description of the current instruction’s attributes into the respective direct page variables. MN is the table of instruction mnemonics that the ‘mnemonic index’ attribute points into. MODES is a jump table with addresses of the disassembly routine for each addressing mode, and LENS contains the length of instructions for each addressing mode. Both of these tables are indexed into directly with the ‘address mode’ attribute.

266

The Western Design Center

1264 0000

1265 0000

1266 0000

1267 0000

1268 0000

1269 0000

1270 0000

1271 0000

1272 0000

1273 0000 0080

1274 0002 0080

1275 0004 0080

1276 0006 0080

1277 0008 0080

1278 000A 0080

1279 000C 0080

1280 000E 0080

1281 0010 0080

1282 0012 0080

1283 0014 0080

1284 0016 0080

1285 0018 0080

1286 001A 0080

1287 001C

1288 001C

;

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

; SP JMP

; JUMP TABLE FOR ‘SPECIAL’ OPCODE HANDLERS

;

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

SPJMP

DC

DC

DC

DC

DC

DC

DC

START

DC

DC

DC

DC

DC

DC

DC

A’SBRK’

A’SJSRABS’

A’SRTI’

A’SRTS’

A’SCOP’

A’SJSRABSL’

A’SBRL’

A’SRTL’

A’SJMPABS’

A’SJMPABSL’

A’SJMPIND’

A’SJMPINDX’

A’SJMPINDL’

A’SJSRINDX’

JUMP TABLE FOR

NON-BRANCH HANDLERS

SCT

END

Local Symbols

SCT 00001A

1289 0000

1290 0000

1291 0000

1292 0000

1293 0000

1294 0000

1295 0000

1296 0000

1297 0000

1298 0000

1299 0000

1300 0000 80

1301 0001 40

1302 0002 01

1303 0003 02

1304 0004 00

1305 0005

1306 0000

1307 0000

1308 0000

1309 0000

1310 0000

1311 0000

1312 0000

1313 0000 10

1314 0001 30

1315 0002 50

1316 0003 70

1317 0004 90

1318 0005 B0

1319 0006 D0

1320 0007 F0

;

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

; PMASK

; STATUS REGISTER MASKS FOR BRANCH HANDLING CODE

;

; LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL

PMASK START

DC

DC

DC

DC

DC

END

H’80’

H’40’

H’01’

H’02’

H’00’

MASKS FOR STATUS REGISTER

N FLAG

V FLAG

C FLAG

Z FLAG

BRA

SCODES START

DC

DC

DC

DC

DC

DC

DC

DC

H’10’

H’30’

H’50’

H’70’

H’90’

H’B0’

H’D0’

H’F0’

SPECIAL OPCODES

BPL

BMI

BVC

BVS

BCC

BCS

BNE

BEQ

267

The Western Design Center

1321 0008 80

1322 0009 00

1323 000A 20

1324 000B 40

1325 000C 60

1326 000D 02

1327 000E 22

1328 000F 82

1329 0010 6B

1330 0011 4C

1331 0012 5C

1332 0013 6C

1333 0014 7C

1334 0015 DC

1335 0016

1336 0016 FC

1337 0017

SCX

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

ENTRY

DC

END

H’80’

H’00’

H’20’

H’40’

H’60’

H’02’

H’22’

H’82’

H’6B’

H’4C’

H’5C’

H’6C’

H’7C’

H’DC’

H’FC’

Local Symbols

SCX 000016

1138 0000

1139 0000

1340 0000

1341 0000

1342 0000

1343 0003

1344 0006

000000

C1C4C3

C1C3C4

1345 0009 C1D3CC

1346 000C C2C3C3

1347 000F C2C3D3

1348 0012

1349 0015

C2C5D1

C2C9D4

1350 0018 C2CDC9

1351 001B C2C3C5

1352 001E C2D0CC

1353 0021

1354 0024

1355 0027

C2D2CB

C2D6C3

C2D6D3

1356 002A C3CCC3

1357 002D C3CCC4

1358 0030

1359 0033

C3CCC9

C3CCD6

1360 0036

1361 0039

C3CDD0

C3D0D8

1362 003C C3D0D9

1363 003F C4C5C3

1364 0042

1365 0045

C4C5D8

C4C5D9

1366 0048 C5CFD2

1367 004B C9CEC3

1368 004E

1369 0051

1370 0054

1371 0057

C9C3D8

C9C3D9

CACDD0

CAD3D2

1372 005A CCC4C1

1373 005D CCC4D8

1374 0060 CCC9D9

1375 0063

1376 0066

CDC3D2

CECFD0

1377 0069 CFD2C1

1378 006C D0C8C1

1379 006F D0C8D0

MN

APPEND DB. TABLE

C’BRK’

C’BVC’

C’BVS’

C’CLC’

C’CLD’

C’CLI’

C’CLV’

C’CMP’

C’CPX’

C’CPY’

C’DEC’

C’DEX’

C’DEY’

C’EOR’

C’INC’

3

C’ADC’

C’AND’

C’ASL’

C’BCC’

C’BCS’

C’BEQ’

C’BIT’

C’BMI’

C’BNE’

C’BPL’

C’INX’

C’INY’

C’JMP’

C’JSR’

C’LDA’

C’LDX’

C’LDY’

C’LSR’

C’NOP’

C’ORA’

C’PHA’

C’PHP’

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DATA

DX

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

22

23

24

25

18

19

20

21

11

12

13

14

15

16

17

6

7

8

9

10

3

4

1

2

5

31

32

33

34

26

27

28

29

30

35

36

37

RTL

JMP

JMP

JMP

JMP

JMP

BRA

BRK

JSR

RTI

RTS

COP

JSR

BRL

JSR

ABSL

ABS

ABSL

()

(,X)

[ ]

(,X)

268

The Western Design Center

1380 0072

1381 0075

D0CCC1

D0CCD0

1382 0078 D2CFCC

1383 007B D2CFD2

1384 007E

1385 0081

1386 0084

1387 0087

D2D4C9

D2D4D3

D3C2C3

D3C5C3

1388 008A D3C5C4

1389 008D D3C5C9

1390 0090

1391 0093

D3D4C1

D3D4D8

1392 0096

1393 0099

D3D4D9

D4C1D8

1394 009C D4C1D9

1395 009F D4D3D8

1396 00A2 D4D8C1

1397 00A5 D4D8D3

1398 00A8 D4D9C1

1399 00AB C2D2C1

1400 00AE D0CCD8

1401 00B1 D0CCD9

1402 00B4 D0C8D8

1403 00B7 D0D8D0

1404 00BA D3D4DA

1405 00BD D4D3C2

1406 00C0 D4D3C2

1407 00C3

1408 00C3 D0C5C1

1409 00C6 D0C5C9

1410 00C9 D0C5D2

1411 00CC D0CCC2

1412 00CF D0CCC4

1413 00D2 D0C8C2

1414 00D5 D0C8C4

1415 00D8 D0C8CB

1416 00DB

1417 00DB D2C5D0

1418 00DE D3C5D0

1419 00E1

1420 00E1

1421 00E4

D4C3C4

D4C4C3

1422 00E7 D4C3D3

1423 00EA D4D3C3

1424 00ED D4D8D9

1425

1426

1427

00F0

00F3

00F6

1428 00F9

D4D9D8

D8C2C1

D8C3C5

1429 00F9 C2D2CC

1430 00FC CAD3CC

1431 00FF D2D4CC

1432 0102

1433 0105

CDD6CE

CDD6D0

1434 0108 C3CFD0

1435 010B D7C1C9

1436

1437

010E

0111

1438 0114

D3D4D0

D7C4CD

C’PEA’

C’PEI’

C’PER’

C’PLB’

C’PLD’

C’PHB’

C’PHD’

C’PHK’

C’REP’

C’SEP’

C’TSX’

C’TXA’

C’TXS’

C’TYA’

C’BRA’

C’PLX’

C’PLY’

C’PHX’

C’PHY’

C’STZ’

C’TRB’

C’TSB’

C’PLA’

C’PLP’

C’ROL’

C’ROR’

C’RIT’

C’RTS’

C’SBC’

C’SEC’

C’SED’

C’SEI’

C’STA’

C’STX’

C’STY’

C’TAX’

C’TAY’

C’TCD’

C’TDC’

C’TCS’

C’TSC’

C’TXY’

C’TYX’

C’XBA’

C’XCE’

C’BRL’

C’JSL’

C’RTL’

C’MVN’

C’MVP’

C’COP’

C’WAI’

C’STP’

C’WDM’

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

END

1439 0000

1440 0000

1441 0000

1442 0002

1443 0004

1444 0006

0000

0080

0080

0080

MODES DATA

DS

DC

DC

DC

2

A’FIMM’

A’FABS’

A’FABSL’

1

2

3

65

66

67

68

69

70

71

72

73

74

60

61

62

63

64

53

54

55

56

57

58

59

46

47

48

49

50

51

52

42

43

44

45

38

39

40

41

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

100

101

269

The Western Design Center

1445 0008 0080

1446 000A 0080

1447 000C 0080

1448 000E 0080

1449 0010

1450 0012

1451 0014

1452 0016

0080

0080

0080

0080

1453 0018 0080

1454 001A 0080

1455 001C 0080

1456 001E 0080

1457 0020

1458 0022

1459 0024

0080

0080

0080

1460 0026

1461 0028

0080

0080

1462 002A 0080

1463 002C 0080

1464

1465

002E

0030

1466 0032

1467 0032

0080

0080

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

END

A’FDIR’

A’FACC’

A’FIMP’

A’FINDINX’

A’FINDINXL’

A’FINXIND’

A’FDIRINXX’

A’FDIRINXY’

A’FABSX’

A’FABSLX’

A’FABSY’

A’FPCR’

A’FPCRL’

A’FABSIND’

A’FIND’

A’FINDL’ 19

A’FABSINXIND’ 20

A’FSTACK’

A’FSTACKREL’

21

22

A’FSRINDINX’

A’FBLOCK’

23

24

12

13

14

15

16

17

18

8

9

10

11

6

7

4

5

1468 0000

1469 0000

1470 0000

1471 0001

1472 0002

1473 0003

1474 0004

1475 0005

1476 0006

1477 0007

1478 0008

1479 0009

1480 000A 02

1481 000B 03

1482 000C 04

1483 000D 03

01

02

02

02

02

02

03

04

02

01

1484 000E

1485 000F

1486 0010

1487 0011

1488 0012

1489 0013

1490 0014

1491 0015

1492 0016

1493 0017

1494 0018

1495 0000

1496 0000

1497 0000

1498 0000

1499 0000

1500 0000

1501

1502

1503

0002

0004

0006

0B06

2309

5804

2316

1504 0008 4004

1505 000A 2304

1506 000C 0304

1507 000E

1508 0010

1509 0012

2313

2515

2301

02

03

01

02

02

03

03

02

02

03

LENS

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

END

DC

DC

DC

DC

DC

DC

DC

DC

DC

START

DC

DC

DC

DC

DC

APPEND DB. ATRIB

ATRIBL DATA

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

I1’11,6’

I1’35,9’

I1’88,4’

I1’35,22’

I1’64,4’

I1’34,4’

I1’3,4’

I1’35,19’

I1’37,21’

I1’35,1’

H’02’

H’03’

H’04’

H’02’

H’01’

H’01’

H’02’

H’02’

H’02’

H’02’

H’02’

H’03’

H’04’

H’03’

H’02’

H’03’

H’03’

H’02’

H’02’

H’03’

H’01’

H’02’

H’02’

H’03’

IMM

ABS

ABS LONG

DIRECT

ACC

IMPLIED

DIR IND INX

DIR IND INX L

DIR INX IND

DIR INX X

DIR INX Y

ABS X

ABS L X

ABS Y

PCR

PCR L

ABS IND

DIR IND

DIR IND L

ABS INX IND

STACK

SR

SR INX

MOV

BRK

ORA D,X

COP (REALLY 2)

ORA-,X

TSB D

ORA D

ASL D

ORA [D]

PHP

ORA IMM

04

05

06

07

08

09

00

01

02

03

270

The Western Design Center

1543 0056

1544 0058

4515

0705

1545 005A 0202

1546 005C 28005

1547 005E 0203

1548 0060

1549 0062

1550 0064

1551 0066

080F

020B

0212

0217

1552 0068 070A

1553 006A 020A

1554 006C 280A

1555 006E 0208

1556 0070

1557 0072

1558 0074

1559 0076

2D06

020E

1505

4E06

1560 0078 070C

1561 007A 020C

1562 007C 280C

1563 007E 020D

1564 0080 2A06

1565 0082

1566 0084

1567 0086

1568 0088

1809

6506

1816

5718

1569 008A 1804

1570 008C 2104

1571 008E 1813

1572 0090

1573 0092

1574 0094

2406

1801

2105

1575 0096

1576 0098

4806

1C02

1577 009A 1802

1510 0014

1511 0016

0305

4715

1512 0018 4002

1513 001A 2302

1514 001C 0302

1515 001E 2303

1516 0020

1517 0022

0A0F

2307

1518 0024

1519 0026

2312

2317

1520 0028 3FO4

1521 002A 230A

1522 002C 030A

1523 002E 2308

1524 0030 0E06

1525 0032

1526 0034

1527 0036

1528 0038

230E

1905

4D06

3F02

1529 003A 230C

1530 003C 030C

1531 003E 230D

1532 0040

1533 0042

1534 0044

1D02

0207

1D03

1535 0046

1536 0048

0216

0704

1537 004A 0204

1538 004C 2804

1539 004E 0213

1540 0050

1541 0052

1542 0054

2706

0201

2805

I1’7,12’

I1’2,12’

I1’40,12’

I1’2,13’

I1’42,6’

I1’24,9’

I1’101,6’

I1’24,22’

I1’87,24’

I1’24,4’

I1’33,4’

I1’24,19’

I1’36,6’

I1’24,1’

I1’33,5’

I1’72,6’

I1’28,2’

I1’24,2’

I1’69,21’

I1’7,2’

I1’2,2’

I1’40,5’

I1’2,3’

I1’8,15’

I1’2,11’

I1’2,18’

I1’2,23’

I1’7,10’

I1’2,10’

I1’40,10’

I1’2,8’

I1’45,6’

I1’25,14’

I1’21,5’

I1’78,6’

I1’35,14’

I1’25,5’

I1’77,6’

I1’63,2’

I1’35,12’

I1’3,12’

I1’35,13’

I1’29,2’

I1’2,7’

I1’29,3’

I1’2,22’

I1’7,4’

I1’2,4’

I1’40,4’

I1’2,19’

I1’39,6’

I1’2,1’

I1’40,5’

I1’3,5’

I1’71,21’

I1’64,2’

I1’35,2’

I1’3,2’

I1’35,3’

I1’10,15’

I1’35,7’

I1’35,18’

I1’35,23’

I1’63,4’

I1’35,10’

I1’3,10’

I1’35,8’

I1’14,6’

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

48

49

4A

4B

4C

4D

41

42

43

44

3C

3D

3E

3F

40

45

46

47

38

39

3A

3B

34

35

36

37

30

31

32

33

2B

2C

2D

2E

2F

20

21

22

23

24

25

26

27

28

29

2A

19

1A

1B

1C

1D

1E

1F

12

13

14

15

16

17

18

0E

0F

10

11

0A

0B

0C

0D

BIT A,X

AND ABS,X

ROL A,X

AND AL,X

RTI

EOR (D,X)

WDM

EOR (D,X)

MVP

EOR D

LSR D

EOR (DL)

PHA

EOR IMM

LSR ABS L

PHK

JMP ABS

EOR ABS

PLD

BIT ABS

AND ABS

ROL A

AND ABS L

BMI

AND D,Y

AND (D)

AND (SR),Y

BIT D,X

AND D,X

ROL D,X

AND (DL),Y

SEC

AND ABS,Y

DEC

TSC

ASL ACC

PHD

TSB ABS

ORA ABS

ASL ABS

ORA ABS L

BPL

ORA (D),Y

ORA (D)

ORA S,Y

TRB D

ORA D,X

ASL D,X

ORA (DL),Y

CLC

ORA ABS,Y

NC ACC

TCS

TRB ABS,X

ORA ABS,X

ASL ABS,X

ORA ABSL,X

JSR ABS

AND (D, X)

JSL ABS L

AND SR

BIT D

AND D

ROL D

AND (DL)

PLP

AND IMM

ROL ACC

271

The Western Design Center

1578 009C 2102

1579 009E 1805

1580 00A0 0C0F

1581 00A2 1807

1582 00A4 1812

1583 00A6 1817

1584 00A8 56148

1585 00AA 180A

1586 00AC 210A

1587 00AE 1808

1588 00B0 1006

1589 00B2 180E

1590 00B4 3D15

1591 00B6 4B06

1592 00B8 1C03

1593 00BA 180C

1594 00BC 210C

1595 00BE 180D

1596 00C0 2B06

1597 00C2 0109

1598 00C4 4340

1599 00C6 0116

1600 00C8 3E04

1601 00CA 0104

1602 00CC 2904

1603 00CE 0113

1604 00D0 2615

1605 00D2 0101

1606 00D4 2905

1607 00D6 5506

1608 00D8 1C11

1609 00DA 0102

1610 00DC 2902

1611 00DE 0103

1612 00E0 0D0F

1613 00E2

1614 00E4

1615 00E6

0108

0112

0117

1616 00E8 3E0A

1617 00EA 010A

1618 00EC 290A

1619 00EE 0108

1620 00F0

1621 00F2

1622 00F4

1623 00F6

1624 00F8 1C14

1625 00FA 010C

1626 00FC 290C

1627 00FE 010D

1628 0100

1629 0100

2F06

010E

3B15

4C06

1630 0000

1631 0000

1632 0000

1633 0002

1634 0004

390F

3009

5310

1635 0006

1636 0008

3016

3204

1637 000A 3004

1638 000C 3104

1639 000E

1640 0010

3013

1706

1641 0012

1642 0014

1643 0016

0701

3606

4615

ATRIBH START

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

I1’57,15’

I1’48,9’

I1’83,16’

I1’48,22’

I1’50,4’

I1’48,4’

I1’49,4’

I1’48,19’

I1’23,6’

I1’7,1’

I1’54,6’

I1’70,21’

I1’24,12’

I1’33,12’

I1’24,13’

I1’43,6’

I1’1,9’

I1’67,16’

I1’1,22’

I1’62,4’

I1’1,4’

I1’41,4’

I1’1,19’

I1’38,21’

I1’1,1’

I1’41,5’

I1’85,6’

I1’28,17’

I1’1,2’

I1’41,2’

I1’33,2’

I1’24,5’

I1’12,15’

I1’24,7’

I1’24,18’

I1’24,23’

I1’86,24’

I1’24,10’

I1’33,10’

I1’24,8’

I1’16,6’

I1’24,14’

I1’61,21’

I1’75,6’

I1’28,3’

I1’1,3’

I1’13,15’

I1’1,8’

I1’1,18’

I1’1,23’

I1’62,10’

I1’1,10’

I1’41,10’

I1’1,8’

I1’47,6’

I1’1,14’

I1’59,21’

I1’76,6’

I1’28,20’

I1’1,12’

I1’41,12’

I1’1,13’

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

END

BRA

STA (D, X)

BRL

STA-,S

STY D

STA D

STX D

STA [ D ]

DEY

BIT IMM

TXA

PHB

64

65

66

67

68

69

6A

6B

6C

6D

6E

5D

5E

5F

60

61

62

63

56

57

58

59

5A

5B

5C

52

53

54

55

4E

4F

50

51

7C

7D

7E

7F

78

79

7A

7B

74

75

76

77

6F

70

71

72

73

LSR ABS

EOR ABS L

BVC

EOR (D),Y

EOR (D)

EOR (SR),Y

MVN

EOR D,X

LSR D,X

EOR (DL),Y

CLI

EOR

PHY

TCD

JMP ABSL

EOR ABS,X

LSR ABS,X

EOR ABSL,X

RTS

ADC (D, X)

PER

ADC SR

STZ D

ADC D

ROR D

ADC (DL)

PLA

ADC

ROR ABSL

RTL

JMP (A)

ADC ABS

ROR ABS

ADC ABSL

BVS

ADC (D),Y

ADC (D)

ADC (SR),Y

STZ D,X

ADC D,X

ROR D,X

ADC (DL),Y

SEI

ADC ABS,Y

PLY

TDC

JMP (A, X)

ADC ABS,X

ROR ABS,X

ADC ABSL,X

86

87

88

89

8A

8B

80

81

82

83

84

85

272

The Western Design Center

1677 005A 1E02

1678 005C 1F02

1679 005E

1680 0060

1681 0062

1E03

050F

1E07

1682 0064

1683 0066

1E12

1E17

1684 0068 200A

1685 006A 1E0A

1686 006C 1E0B

1687 006E 1E08

1688 0070

1689 0072

1106

1E0E

1690 0074

1691 0076

3506

5006

1692 0078 200C

1693 007A 1E0C

1694 007C 1F0E

1695 007E 1E0D

1696 0080

1697 0082

1698 0084

1401

1209

4901

1699 0086

1700 0088

1216

1404

1701 008A 1204

1702 008C 1504

1703 008E

1704 0090

1705 0092

1213

1B06

1201

1706 0094

1707 0096

1708 0098

1606

5906

1402

1709 009A 1202

1710 009C 1502

1711 009E 1203

1644 0018 3203

1645 001A 3002

1646 001C 3102

1647 001E 3003

1648 0020

1649 0022

1650 0024

1651 0026

040F

3007

3012

3017

1652 0028 320A

1653 002A 300A

1654 002C 310B

1655 002E 3008

1656 0030

1657 0032

1658 0034

3806

300E

3706

1659 0036

1660 0038

4F06

3E02

1661 003A 300C

1662 003C 3E0C

1663 003E

1664 0040

1665 0042

300D

2001

1E09

1666 0044

1667 0046

1668 0048

1F01

1E16

2004

1669 004A 1E04

1670 004C 1F04

1671 004E

1672 0050

1673 0052

1E13

3406

1E01

1674 0054

1675 0056

1676 0058

3306

4415

2002

I1’31,14’

I1’30,13’

I1’30,13’

I1’18,9’

I1’73,1’

I1’18,22’

I1’20,4’

I1’18,4’

I1’21,4’

I1’18,19’

I1’27,6’

I1’18,1’

I1’22,6’

I1’89,6’

I1’20,2’

I1’18,2’

I1’21,2’

I1’18,3’

I1’30,2’

I1’31,2’

I1’30,3’

I1’5,15’

I1’30,7’

I1’30,18’

I1’30,23’

I1’32,10’

I1’30,10’

I1’30,11’

I1’30,8’

I1’17,6’

I1’30,14’

I1’53,6’

I1’80,6’

I1’32,12’

I1’30,12’

I1’79,6’

I1’62,2’

I1’48,12’

I1’62,12’

I1’48,13’

I1’32,1’

I1’30,9’

I1’31,1’

I1’30,22’

I1’32,4’

I1’30,4’

I1’31,4’

I1’30,19’

I1’52,6’

I1’31,1’

I1’51,6’

I1’68,21’

I1’32,2’

I1’50,2’

I1’48,2’

I1’49,2’

I1’48,3’

I1’4,15’

I1’48,7’

I1’48,18’

I1’48,23’

I1’50,10’

I1’48,10’

I1’49,11’

I1’48,8’

I1’56,6’

I1’48,14’

I1’55,6’

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

CA

CB

CC

CD

CE

CF

C3

C4

C5

C6

BE

BF

C0

C1

C2

C7

C8

C9

B6

B7

B8

B9

BA

BB

BC

BD

B2

B3

B4

B5

AD

AE

AF

B0

B1

A2

A3

A4

A5

A6

A7

A8

A9

AA

AB

AC

9B

9C

9D

9E

9F

A0

A1

94

95

96

97

98

99

9A

90

91

92

93

8C

8D

8E

8F

LDA ABS

LDX ABS

LDA ABS L

BCS

LDA (D),Y

LDA (D)

LDA (SR),Y

LDY D,X

LDA D,X

LDX D,Y

LDA (DL),Y

CLV

LDA ABS,Y

TSX

TYX

LDY ABS,X

LDA ABS,X

LDX ABS,Y

LDA ABSL,X

CPY

CMP (D,X)

REP

CMP

CPY D

CMP D

DEC D

CMP (DL)

INY

CMP IMM

DEX

WAI

CPY ABS

CMP ABS

DEC ABS

CMP ABSL

STY ABS

STA ABS

STX ABS

STA ABS L

BC

STA (D),Y

STA (D)

STA (SR),Y

STY D,X

STA D,X

STX D,Y

STA (DL),Y

TYA

STA ABS,Y

TXS D

TXY

STZ ABS

STA ABS,X

STZ ABS,X

STA ABSL,X

LDY IMM

LDA (D,X)

LDX IMM

LDA SR

LDY D

LDA D

LDX D

LDA (DL)

TAY

LDA IMM

TAX

PLB

LDY ABS

273

The Western Design Center

1712 00A0 090F

1713 00A2 1207

1714 00A4 1212

1715 00A6 1217

1716 00A8 4204

1717 00AA 120A

1718 00AC 150A

1719 00AE 1208

1720 00B0 0F06

1721 00B2 120E

1722 00B4 3C15

1723 00B6 6406

1724 00B8 1C11

1725 00BA 120C

1726 00BC 150C

1727 00BE 120D

1728 00C0 1301

1729 00C2 2C09

1730 00C4 4A01

1731 00C6 2C16

1732 00C8 1F04

1733 00CA 2C04

1734 00CC 1904

1735 00CE 2C13

1736 00D0 1A06

1737 00D2 2C01

1738 00D4 2206

1739 00D6 5106

1740 00D8 1302

1741 00DA 2C02

1742 00DC 1902

1743 00DE 2C03

1744 00E0 060F

1745 00E2

1746 00E4

1747 00E6

1748 00E8

2C07

2C12

2C17

4102

1749 00EA 2C0A

1750 00EC 190A

1751 00EE 2C08

1752 00F0

1753 00F2

2E06

2C0E

1754 00F4

1755 00F6

3A15

5206

1756 00F8 1D14

1757 00FA 2C0C

1758 00FC 190C

1759 00FE 2C0D

1760 0100

Global Symbols

ADDRMODE

C

DIRREG

M

OPCREGB

OPRNDH

PCREGH

TEMP

X

YREGH

00009C

000001

000093

000020

000086

000089

000081

000099

000010

00008E

AREG

CODE

DIRREGH

MNX

OPCREGH

OPRNDL

PREG

TEMPB

XREG

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

DC

END

DC

DC

DC

DC

DC

DC

DC

DC

DC

00008F

000087

000094

00009D

000085

000088

000096

00009B

00008B

I1’18,13’

I1’19,1’

I1’44,9’

I1’74,1’

I1’44,22’

I1’31,4’

I1’44,4’

I1’25,4’

I1’44,19’

I1’26,6’

I1’44,1’

I1’34,6’

I1’81,6’

I1’19,2’

I1’44,2’

I1’25,2’

I1’44,3’

I1’6,15’

I1’9,15’

I1’18,7’

I1’18,18’

I1’18,23’

I1’66,4’

I1’18,10’

I1’21,10’

I1’18,8’

I1’15,6’

I1’18,14’

I1’60,21’

I1’100,6’

I1’28,17’

I1’18,12’

I1’21,12’

I1’44,7’

I1’44,18’

I1’44,23’

I1’65,2’

I1’44,10’

I1’25,10’

I1’44,8’

I1’46,6’

I1’44,14’

I1’58,21’

I1’82,6’

I1’29,20’

I1’44,12’

I1’25,12’

I1’44,13’

AREGH

CR

DPAGE

NCODE

OPLEN

PCREG

STACK

TEMPH

XREGH

1760 source lines

0 macros expanded

0 lines generated

0 page faults

BNE

CMP (D0,Y

CMP (D)

CMP

PEI D

CMP D,X

DEC D,X

CMP (DL),Y

CLD

CMP ABS,Y

PHX

STP

JMP (A)

CMP ABS,X

DEC ABS,X

CMP ABSL,X

CPX IMM

SBC (D,X)

SEP IMM

SBC SR

LDX D

SBC D

INC D

SBD (DL)

INX D

SBC IMM

NOP

XBA

CPX ABS

SBC ABS

INC ABS

SBC ABSL

BEQ

SBC (D),Y

SBC (D)

SBC (SR),Y

PEA

SBC D,X

INC D,X

SBC (DL),Y

SED

SBC ABS,Y

PLX

XCE

JSR (A,X)

SBC ABS,X

INC ABS,X

SBC ABSL,X

000090 BRKN

00008D DBREG

000300 EBIT

000083

00009F

000080

000091

OPCREG

OPRNDB

PCREGB

STACKH

00009A USRBRKV

00008C YREG

00FFE6

000095

000097

000084

00008A

000082

000092

003F0

00008D

E6

E7

E8

E9

EA

EB

EC

ED

EE

EF

F0

DF

E0

E1

E2

E3

E4

E5

D8

D9

DA

DB

DC

DD

DE

D4

D5

D6

D7

D0

D1

D2

D3

FA

FB

FC

FD

FE

FF

F6

F7

F8

F9

F1

F2

F3

F4

F5

274

The Western Design Center

Link Editor 4.0

00008000

00008037

00008106

0000814E

0000826E

00008287

00008286

000082DC

000088336

00008393

000083AD

000083FO

0000842E

00008497

000084E5

000085OB

00008527

0000852C

00008543

00008657

00008689

000086A1

000087A1

00000037

000000CF

00000048

00000120

00000019

0000002F

00000026

0000005A

0000005D

0000001A

00000043

0000003E

00000069

0000004E

00000026

0000001C

00000005

00000017

00000114

00000032

00000018

00000100

00000100

Code:

Code:

Code:

Code:

Code:

Code:

Code:

Code:

Code:

Code:

Code:

Code:

Code:

Code:

Code:

Code:

Code:

Code:

Data:

Data:

Code:

Data:

Code:

MAIN

EBRKIN

FLIST

FRMOPRND

POB

STEP

PUTHEX

CLRLN

UPDATE

PRINTLN

TRACE

CHKSPCL

SBRK

DUMPREGS

PUTREG8

SPJMP

PMASK

SCODES

MN

MODES

LENS

ATRIBL

ATRIBH

Global symbol table:

ADDRMODE 0000009C 00

ATRIBH 000087A1 00

C 00000001 00

CODE

DIRREG

DPAGE

EBRXIN

00000087

00000093

00000300

00008037

FABSINXIND 00008224

00

00

00

00

00

FABSX

FBLOCK

FDIRINXY

FIND

FINDL

FINY

FPCRL

FSTACK

LENS

M

MNX

NBRKIN

OPCREGB

000081BB

00008526

00008689

00000020

0000009D

00008047

00000086

00

00

000081A8 00

00008204

00008214

0000817E

000081E4

00008233

00

00

00

00

00

00

00

00

00

00

AREG

ATRIBL

CHKSPCL

CR

DIRREGH

DUMPREGS

FABS

FABSL

FABSY

FDIR

FIMM

FINDINX

FINX

FLIST

FRMOPRND

FSTACKREL

LINE

MAIN

MODES

NCODE

OPCREGH

0000008F 00

000086A1 03

00008DF0 00

0000008D 00

00000094 00

00008497 00

0000816B 00

0000816E 00

000081C7 00

00008171 00

00008159 00

0000817B 00

000081AE 00

00008106 00

0000814E

00008234

00

00

000082EE 00

00008000 00

00008657

00000083

00000085

02

00

00

AREGH

BRKN

CLRLN

DBREG

DOBRANCH

EBIT

FABSIND

FABSLX

FACC

FDIRINXX

FIMP

FINDINXL

FINXIND

FPCR

FSRINDINX

GO

LIST

MN

MOVE

OPCREG

OPLEN

00000090

0000FFE6

000082DC

00000095

0000841B

00000097

000081F5

000081C1

00008174

000081A2

0000817A

0000818A

00008190

000081CD

00008244

000080C4

00008003

00008543

0000814A

00000084

0000009F

00

00

00

00

00

00

00

00

00

01

00

00

00

00

00

00

00

00

00

00

00

275

The Western Design Center

16) Chapter Sixteen

Design and Debugging

Design and debugging stand on either side of the central coding phase of the development cycle. Good techniques for both are as important as skill in actual coding. This chapter provides a checklist of some commonly encountered bugs – ones you should immediately suspect – as well as some words of advice about program design and good coding practice, which may help you avoid some of the bugs to begin with.

Debugging Checklist

Program bugs fall into two categories: those specific to the particular processor you’re writing assembly code for, and those that are generic problems which can crop up in any assembly program for almost any processor. This chapter will primarily consider bugs specific to the 65x processors, but will also discuss some generic bugs as they specifically apply in 65x assembly programs.

You may want to put a checkmark beside the bugs listed here each time you find them in your programs, giving you a personalized checklist of problems to look for. You may also want to add to the list other bugs that you write frequently.

Decimal Flag

Seldom does the d decimal flag get miss set, but when it does, arithmetic results may seem to inexplicably go south. This can be the result of a typo, attempting to execute data, or some other execution error. Or it can result from coding errors in which the decimal flag is set to enable decimal arithmetic, then never reset. If branching occurs before the decimal flag is reset, be sure all paths ultimately result in the flag being cleared. Branching while in decimal mode is almost as dangerous as branching after temporarily pushing a value onto the stack; equal care must be taken to clear d and clean the stack.

This bug may be doubly hard to find on the 6502, which does not clear d on interrupt or, worse, on reset. An instruction inadvertently or mistakenly executed which sets d (only SED, RTI, or PLP have the capability on the 6502) would require you to specifically reclear the decimal flag or to power off and power back on again. As a result, it is always a good idea to clear the decimal flag at the beginning of every 6502 program

.

Adjusting Carry Prior to Add / Subtract

If you’re not used to 65x processors (and even for many programmers who are), you may tend to write an ADC instruction without first writing a CLC, or an SBC without first an SEC. After all, other processors have add and subtract instructions that do not involve the carry. But the 65x processors do not; so notice the

“C” in each of the instructions each time you code them and be sure the carry has the appropriate value.

65x Left-to-Right Syntax

Unlike some other processors’ instructions, 65x mnemonics read from left to right, just like English:

TAX, for example, means to transfer the A accumulator to the X index register, not the opposite.

276

The Western Design Center

65x Branches

There are eight 65x conditional branches, each based on one of the two states of four condition code flags. Remembering how to use them for arithmetic is necessary to code branches that work.

Keep in mind that compare instructions cannot be used for signed comparisons: they don’t affect the overflow flag. Only the subtract instruction can be used to compare two signed numbers directly (except for the relationships equal and not equal).

Remember that if the z flag is set (one), then the result was zero; and if the zero flag is clear (zero), then the result was other than zero – the opposite of most first guesses about it.

A common code sequence is to test a value, then branch on the basis of the result of the test. A common mistake is to code an instruction between the test and the branch that also affects the very flag your branch is based on (often because an instruction you don’t expect to affect the flags does indeed do so).

Note that 65x pull instructions set the negative and zero flags, unlike 68xx and 8088/8086 processors; that store instructions do not set any flags, unlike 68xx processors; that transfer and exchange instructions do set flags, unlike Motorola and Intel processors; that load instructions do set flags, unlike the 8088; and increment and decrement instructions do not affect the carry flag.

Also, in decimal mode on the 6502, the negative, overflow and zero flags are not valid.

6502 Jump Bug

There’s hardware bug on the 6502 that causes jump indirect, with an operand which ends in $FF (such as $11FF), to bomb; the new high program counter value is taken incorrectly from $1100, not the correct $1200.

Interrupt-Handling Code

To correctly handle 65x interrupts, you should generally, at the outset, save all registers and, on the

6502 and in emulation mode, clear the decimal flag (to provide a consistent binary approach to arithmetic in the interrupt handler). Returning from the interrupt restores the status register, including the previous state of the decimal flag.

During interrupt handling, once the previous environment has been saved and the new one is solid, interrupts may be enabled.

At the end of handling interrupts, restore the registers in the correct order. RTI will pull the program counter and status register from the stack, finishing the return to the previous environment, except that in

65802/65816 native mode it also pulls the program bank register from the stack. This means you must restore the mode in which the interrupt occurred (native or emulation) before executing an RTI.

65802/65816: Emulation Versus Native Mode

Emulation mode has been provided on the 65802 and 65816 to provide continuity with existing applications. Native mode provides the powerful sixteen-bit data handling registers. But mixing emulation and native modes requires careful attention to detail. You should deal with modes systematically.

Will you limit subroutines to be called only from a certain mode? All subroutines? You must carefully document each for which mode it expects.

You must be in emulation mode on the Apple II or other 6502-based system to use the monitor and operating system 6502 routines. Furthermore, you must put 0000 into D (the direct page register) before return to the monitor or operating system, because zero page addressing now addresses the direct page, but the 6502 firmware left its variables in page zero before your program switched to native mode.

Any high bytes in the index registers are lost in the switch to emulation mode.

While native mode lets you set the stack anywhere, a non-page-one stack location is lost on return to emulation mode (the high byte is thrown away, replaced by the obligatory page one high byte emulation mode).

Furthermore, when setting the stack with the TCS instruction, only the low accumulator byte is transferred to the stack pointer in emulation mode, but in native mode, the high accumulator byte, even if it is hidden, is transferred to the high stack pointer byte.

277

The Western Design Center

65802/65816: Eight-Bit Versus Sixteen-Bit Registers

Almost as potentially confusing as mixing emulation and native modes is mixing eight-bit and sixteenbit modes. Again, you should deal with modes systematically.

Will you limit subroutines to be called only from a certain mode setting? You must carefully document each for the mode it expects.

Because instructions using immediate addressing are different lengths in eight- and sixteen-bit modes, being in the wrong mode will cause the processor to grab the wrong number of operand bytes, followed by a fetch for the next opcode which will miss by one and cause it to execute, as though it were an opcode, either the last operand byte of the immediate instruction, or the first operand byte of the next instruction. Either way is sure program failure.

65802/65816: The Direct Page

Avoid inadvertently branching from code written to access one direct page code written to access another without executing an instruction to reset the direct page register to the second location first (and resetting it to the original location before returning). Remember, too, that programs run faster when the direct page register is set to a page boundary.

Pay particular attention to the peculiarities of the direct page in the emulation mode: as with the 6502 and 65C02, instructions which use direct page addressing modes will “wrap” to stay within the zero page, but

only when the direct page register is equal to zero. Opcodes which are not found on the 6502 or 65C02 will not wrap at all, even when the direct page is equal to zero in the emulation mode.

65802/65816: Stack Overruns Program or Data

No longer limited to a single page, the native-mode stack will grow downward as far as your program pushes bytes onto it. Large programs should either retrieve every byte pushed on or reset the stack periodically

(using TCS or TXS). The potential danger is when a stack grows uncontrollably until it overwrites variables, your program, or the operating system.

In this connection it is important to be aware that, although the high byte of the stack register is consistently forced to one, new 65816 opcodes executed in the emulation mode will not wrap the stack if the low byte over- or underflowed in the middle of an instruction. For example, if the stack pointer is equal to

$101, and a JSL is executed, the final byte of the three bytes pushed on the stack will be at $FF, not $1FF; but the stack pointer at the end of the instruction will point to $1FE. However, if JSR (a 6502 instruction) is executed in the emulation mode with the stack pointer equal to $100, the second of the two bytes pushed will be stored at $1FF.

65802/65816: JSR/JSL and RTS/RTL

RTL pulls one more byte off the stack than RTS: it requires that a long jump-to-subroutine (JSL) or its equivalent pushed a full 24-bit return address, not just a sixteen-bit one. Equally important is that a JSL not be made to a subroutine ended by an RTS, which pulls only sixteen of the 24 bits of return address pushed

.

65802/65816: MVN/MVP

MVN and MVP require two operands, usually code or data labels from which the assembler strips the bank bytes, in sourcebank,destbank order (opposite of object code order). Eight-bit index registers will cause these two instructions to move only zero page memory. But eight-bit accumulator mode is irrelevant to the count value; the accumulator is expanded to sixteen bits using hidden B accumulator as the high byte of the count. Finally, the count in the accumulator is one less than the count of bytes to be moved: five in the accumulator means six bytes will be moved.

278

The Western Design Center

Return Address

If your program removes the return address from the stack in order to use it in some fashion other than using an RTS or RTL instruction to return, remember that you must add one to the stacked value to form the true return address (an operation the return-from-subroutine instructions execute automatically).

Inconsistent Assembler Syntax

6502 assemblers have been wildly inconsistent in their syntax, and early 65802 assemblers have not set standard either. This book describes syntax recommended by the designers of the 65816, the Western Design Center, as implemented in the ORCA/M assembler. Others, however, do and will differ. For example, while many assemblers use the syntax of a pound sign (#) in front of a sixteen-bit immediate value to specify that the low byte be accessed, with the greater-then sign (>) being used to represent the high byte, at least one 6502 assembler uses the same two signs to mean just the opposite.

Syntax for the new block move instructions will undoubtedly vary from the recommended standard in many assemblers. Beware and keep you assembler’s manual handy.

Generic Bugs: They Can Happen Anywhere

Uninitialized Variables

Failing to initialize variables may be the most common bug committed by programmers. Its symptom is often a program which operates strangely only the first time it is run (after which the variable has at some point been given a suitable value which remains in memory for the program’s second try), or only after running a certain other program.

Sometimes the symptom appears only on computers with one brand of memory chips, and not another; they happen to power up with different initial values.

Missing Code

The code you wrote on paper is perfect. The problem is one or more lines that never got typed in, or were typed in wrong. The solution is to compare your original handwritten code with the typed-in version, or compare a disassembly with your original code.

More enigmatically, a line may be accidentally deleted or an opcode or operand inadvertently changed by a keypress during a subsequent edit (usually in a section of code which has just been proven to work flawlessly). Regular source backups and a program that can compare text to spot changes will often solve the problem. Or you can compare a disassembly with the previous source listing.

Failure to Increment the Index in a Loop

The symptoms are: everything stops, and typing at the keyboard has no effect. The problem is an endless loop – your branch out of the loop is waiting for an index to reach to some specified value, but the index is never decremented or incremented and thus never reaches the target value.

279

The Western Design Center

Failure to Clean Up Stack

This problem is typically found in code in which first a value is pushed, then there is a conditional branch, but all paths do not pull the value still on the stack. It may result in a return address being pulled off the stack which is not really a return address (one or more bytes of it are really previously pushed data bytes).

Immediate Data Versus Memory Location

Failure to use the ‘#’ sign to signify a constant (or whatever other syntax a particular assembler requires) will instruct the assembler to load, not the constant, but data from a memory location that it assumes the constant specifies. That is, #VAR means access a constant (or the address of a variable);

VAR, on the other hand, means access its contents.

Initializing the Stack Pointer from a Subroutine

It won’t take much thought to realize that you can’t just reset the stack pointer from within a subroutine and expect the return-from-subroutine instruction to work. The return address was pointed to by the previous stack pointer. Who knows where it is in relation to the newly set one?

Top-Down Design and Structured Programming

It’s wise to carefully consider the design of a program before beginning to write any of it. The goals of design are to minimize program errors, or bugs; to reduce complexity; to maximize readability; and to increase the speed and ease of coding and testing and thus the productivity of programmers.

The top-down approach to structured programming combines two major design concepts. This approach is generally recognized as the method of design which best achieves these goals, particularly when coding large programs. Top-down design suggests that programs should be broken into levels: at the top level is a statement of the goal of the program; beneath it are second-level modules, which are the main control sections of the program; the sections can be broken into their parts; and so on.

A blackjack game (twenty-one), for example, might be broken down into four second-level modules, the goals of which are to deal the cards, take and place bets on the hands dealt, respond to requests for more cards, and finally compare each player’s hand with the dealer’s to determine winnings. The dealing module might be broken down into two third-level modules, the goals of which are to shuffle the cards, and to deliver a card to each player (executed twice so that each player gets two cards). The shuffling module might be broken into two fourth-level modules which assign a number to each card and then create a random order to the numbers.

The makeup of each level is clear. At the top level, the makeup describes the program itself.

At lower levels, the makeup describes the subprocess. At the lowest levels, the work is actually done.

A top-down design is then implemented using subroutines. The top level of the program is a very short straight-line execution routine (or loop in the case of programs that start over when they reach the end), that does nothing more than call a set of subroutines, one for each second-level module of the program. The second-level subroutines may call third-level subroutines which may call fourthlevel subroutines, and so on.

Structure programming is a design concept which calls for modules to have only one entry point; jumping into the middle of a module is not permitted. (A structured approach to the problem of needing an entry point to the middle of a module is to make that portion of the module a sub-module

280

The Western Design Center

with its own single entry and exit points.) A second rule is that all exits return control to the calling module; all branches (selections) are internal; no branches are permitted to code outside the module.

One of the side benefits of modular programming is the ability to reuse previously coded modules in other programs: the dealing module could be dropped into any card game program that calls for shuffling followed by the dealing of one card at a time to each player. And its shuffling submodule could be borrowed for other card game programs which only need shuffling. This use of the modularity principle should not be confused with the top-down structured design; they are distinct but related concepts. Modular programming in itself is not the same as top-down design.

A software development team could, using top-down design, readily assign one programmer the task of coding the deck-shuffling routine, another programmer the betting module, another responsibility for the dealing routines, and a fourth with writing the code for the end-of-game comparison of hands and determination of the winner.

A new programmer trying to understand a top-down program avoids becoming mired in detail while trying to get an understanding of the structure, yet can very easily figure how to get to the degree of detail which interests him.

Finally, debugging, the process of finding and removing programming mistakes, is exceptionally straightforward with top-down design: on seeing that, after shuffling, one of the 52 cards seems to be missing, the programmer can go directly to the shuffling subroutines to fix the problem.

Top-down design sometimes seems like a waste of time to programmers anxious to get the bytes flying; complex programs can take days or weeks of concerted thinking to break down into the subparts which fit together most logically and efficiently. But the savings in time spent coding – and recoding – and in being able to understand, debug, and modify the program later well justify the time spent on design.

Documentation

One of the most important elements of good programming practice is documentation. It is remarkable how little one can recall about the nitty-gritty details of a program written just last month

(or sometimes even yesterday) – the names of the key variables, their various settings and what each means and how each interacts with other variables in various routines, and so on. “Clever” programmers, those who bend programming principles to ends never anticipated, too often find they

(not to mention their co-workers) can no longer discover the meaning behind their cleverness when it comes time to debug or modify that code.

The first principle of documentation is to make the program document itself. Choose labels which are meaningful: DELLOOP is a much better label for the beginning of a loop which deals cards in a card game than is LAB137. Substitute a label for all constants: branching if there’s a 1 in some register after writing a byte to disk is, by itself, meaningless; branching because there’s a constant named DISKFULL in the register provides clear documentation. When your program needs to determine if an ASCII value is an upper-case letter, it’s much clearer to compare with “greater than or equal to ‘A’” than with “greater than ‘@’”. Who remembers that ‘@’ precedes ‘A’ in the ASCII chart?

Variables should be commented when they’re declared with a description of their purpose, their potential settings, and any default states. And if any of that information changes during the development of the program, the comment should be changed to match.

Routines should be commented when they’re written: Note the purpose of the routine, the variables or parameters which need to be set before entry into the routine, and the variables or parameters which will be passed back. If other data structures will be affected by the routine, this, too, should be commented.

Nothing is as important both to debugging of code and to continuing development of programs as documentation: self-documentation; a comment on every important line of code that explains and

281

The Western Design Center

expands it; a comment header on every routine; and a comment on every variable. While some languages are said to be automatically “self-documenting,” no language can create documentation which is half adequate compared to what the original programmer can provide while the program is being written.

282

The Western Design Center

17) Chapter Seventeen

The Addressing Modes

There are fourteen addressing modes available to the 6502, all of those plus two more on the 65C02, and another nine categories available on the 65802 and 65816. Each mode allows the location of the data being referenced by a given instruction to be specified in a different manner. The availability of many different addressing modes on the 65x processors is one key to their power.

The data found in operand bytes of an instruction is only one part of the effective address specification; the addressing modes, expressed using the correct address-mode syntax in the operand field of an assemblylanguage statement, cause the assembler to choose from among the instruction’s possible opcodes to one specific to the addressing mode. Not all addressing modes are available for all instructions; but there is one unique opcode for each combination of addressing mode and operation.

The addressing mode is the determinant of the effective address for an operation – the memory address that the instruction will access for data or to transfer control within the program. For a few of the 65x addressing modes, the effective address is provided in the operand field of the instruction. But for most of them, formation of the effective address involves an address calculation, that is, the addition of two or more values. The addressing mode used with a given instruction indicates where these values are to come from and how they are to be added together to form the effective address. This effective address calculation has as many forms as there are addressing modes.

An important aspect of effective address calculation on the 65802 and 65816, to be considered in addition to the addressing modes themselves, is the state of the x index-register select flag and, to a lesser extent, the m memory/accumulator select flag, both in the status register. In a sense, the x flag, for example, extends the addressing mode specification part of an instruction, which uses an indexed addressing mode, by determining whether or not an eight-bit or sixteen-bit index register is to be used. For every one of the indexed addressing modes, there are two similar methods of forming an effective address, depending on the setting of the index-register select flag. Pay special attention to the status and effects of the select flags.

In the following pages are graphic and written presentations of each of the addressing modes, illustrating the effective address formation, complete with a listing of the processors on which, and the instructions to which, each addressing mode is available. A sample of the assembler syntax used to invoke each one is included as well.

The descriptions are the complete set available on the 65816. The differences between the four processors, with their various modes, are graphically noted whenever possible.

The 65816’s native mode features index registers and an accumulator which may be either eight bits or sixteen, depending on the settings of two mode select flags (x sets the index registers to eight or sixteen bits; m sets the accumulator and memory to eight or sixteen).

The 65802’s native mode differs in that, while the bank registers are part of effective address formation, bank values are not propagated to the bus, so long addressing modes have no bank effect. The bank accessed is always bank zero, so there is, essentially, no bank portion to the effective address generated.

The 6502 emulation mode on the 65802 and 65816 processors (e = 1) differs in that the stack pointer’s high byte is always $01; direct page indexed addressing always wraps around to remain in the direct page rather than crossing over into the next page (so the high direct page byte remains the high byte of all direct page addresses formed). The exception to this is that zero page stack wrapping is only enforced for 6502 and 65C02 instructions, and only when DP = 0 in the case of page zero wrapping. New opcodes will cause effective addresses to be generated outside of the zero page or the emulation mode stack page if an effective address calculation overflows the low byte.

Additionally, the index registers and the A accumulator are limited to eight bits. (There remains, however, a hidden eight-bit B accumulator, as well as a 16-bit C accumulator which is the concatenation of B and A but which is generally not accessible except to special instructions.)

The 65C02 and 6502 differ from 6502 emulation in that there are no bank registers whatsoever; direct page addressing is, instead, zero page addressing ($0000 is the zero page base to which offsets and, sometimes,

283

The Western Design Center

index values are added; there is no direct page register); and there is no hidden B accumulator nor concatenated

C accumulator.

The symbols in Table 17.1 are used to describe the kinds of operands that are used with the various addressing modes.

Figures 17.1 through 17.4 repeat the illustrations of the programming models for the four possible processor configurations: 6502/65C02, 65802 native mode, 65816 native mode, and 65816 emulation mode.

The programming model for the native mode 65816 is used in the addressing mode figures that follow; for different processors or modes, compare the addressing mode figure with the processor-mode programming model for clarification of the operation of the addressing mode for that model.

addr addr/const const destbk dp label long nearlabel sr srcebk two-byte address two-byte value: either an address or a constant one- or two-byte constant

64K bank to which string will be moved one-byte direct page offset (6502/65C02: zero page) label of code in same 64K bank as instruction three-byte address (includes bank byte) label of code close enough to instruction to be reachable by a one-byte signed offset one-byte stack relative offset

64K bank from which string will be moved

Table 17-1 Operand Symbols

6502/65C02 Programming Model

7 0

Accumulator (A)

15

0 0 0 0 0 0 0 1

X Index Register (X)

Y Index Register (Y)

Stack Pointer (S)

Program Counter (PC)

Processor Status Register (P) n v b d i z c

Carry

Zero

IRQ Disable

Decimal Mode

Break Instruction

Overflow

Negative

1= Carry

1= Result Zero

1= Disabled

1= Decimal Mode

1= Break caused interrupt

1= Overflow

1= Negative

Figure 17-1 6502/65C02 Programming Model

284

The Western Design Center

65802 Native Mode Programming Model

(16-bit accumulator & index register modes: m = 0 &x = 0)

15

Accumulator (B)

7

(A or C) Accumulator (A)

0

X Index Register (X)

Y Index Register (Y)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC)

Data Bank Register (DBR)

Program Bank Register (PBR)

Processor Status Register (P)

7 e n v m x d i z c

0

Emulation

Carry

Zero

IRQ Disable

Decimal Mode

Index Register Select

Memory/Accumulator Select

Overflow

Negative

0= Native

Mode

1= Carry

1= Result Zero

1= Disabled

1= Decimal, 0= Binary

1= 8-bit, 0= 16-bit

1= 8-bit, 0= 16-bit

1= Overflow

1= Negative

Figure 17-2. 65802 Native Mode Programming Model

285

The Western Design Center

65816 Native Mode Programming Model

23

(16-bit accumulator & index register modes: m = 0 & x = 0)

15 7

Accumulator (B) (A or C)

Data Bank Register (DBR)

0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0

Program Bank Register (PBR)

Accumulator (A)

0

X Index Register (X)

Y Index Register (Y)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC)

7 n

Processor Status Register (P) v m x d i e z c

0

Emulation

Carry

Zero

IRQ Disable

Decimal Mode

Index Register Select

Memory/Accumulator Select

Overflow

Negative

0= Native Mode

1= Carry

1= Result Zero

1= Disabled

1= Decimal, 0= Binary

1= 8-bit, 0= 16-bit

1= 8-bit, 0= 16-bit

1= Overflow

1= Negative

Figure 17-3 65816 Native Mode Programming Model

286

The Western Design Center

65816 Emulation Mode Programming Model

23 15

Accumulator (B)

7

(C)

Accumulator (A)

Data Bank Register (DBR)

X Index Register (X)

Y Index Register (Y)

Direct Page Register (D) 0 0 0 0 0 0 0 0

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1

Program Bank Register (PBR) Program

Stack Pointer (S)

Counter (PC)

0

7 n

Processor Status Register (P)

v e

0 b d i z c

Emulation 1= 6502 Emulation Mode

Carry

Zero

IRQ Disable

Decimal Mode

Break Instruction

Overflow

Negative

1= Carry

1= Result Zero

1= Disabled

1= Decimal, 0= Binary

1= Break caused interrupt

1= Overflow

1= Negative

Figure 17-4 65816 Emulation Mode Programming Model

287

The Western Design Center

Absolute Addressing

Effective Address:

Bank: Data Bank Register (DBR) if locating data: Program Bank Register (PBR) if transferring control.

High: Second operand byte.

Low: First operand byte.

Sample Syntax:

LDA addr

Effective Address:

23

Bank

15

High

7

Low

0

Instruction:

Opcode Operand Low Operand High

65816 Register:

Bank

23

Data Bank (DBR)

15

0000 0000

0000 0000

Program Bank (PBR)

High Low

7 if locating data

X Index Register (X)

0

Y Index Register (Y)

Accumulator (A or C)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC) of transferring control

Status (P)

Instructions Using It:

Effective Address Locates Data

ADC CPY

AND

ASL

DEC

EOR

BIT

CMP

CPX

INC

LDA

LDX

Transfer Control to Effective Address

JMP JSR

1 65C02 and 65802/65816 only.

LDY

LSR

ORA

ROL

ROR

SBC

STA

STX

STY

STZ

TRB

TSB

288

The Western Design Center

Absolute Indexed, X Addressing

Effective Address: The Data Bank Register is concatenated with the 16-bit Operand: the 24 bit

result is added to X (16 bits if 65802/65816 native mode, x = 0; else 8).

Sample Syntax:

LDA addr, X

Effective Address:

23

Bank

15

Instruction:

Opcode

65816 Registers:

Bank

Data Bank (DBR)

15

Operand Low

High

7

Operand High

Low

0

+

High

0000 0000

0000 0000

Program Bank (PBR)

X Index Register (X)

Y Index Register (Y)

Accumulator (A or C)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC) x-1 x 0

Status (P)

Instructions Using It:

Effective Address Locates Data

ADC DEC

AND

ASL

EOR

INC

BIT

CMP

LDA

LDY

1 65C02 and 65802/65816 only.

LSR

ORA

ROL

ROR

SBC

7

Low

STA

STZ

0

289

The Western Design Center

Absolute Indexed, Y Addressing

Effective Address: The Data Bank Register is concatenated to the 16-bit Operand: the 24-bit

result is added to Y (16 bits if 65802/65816 native mode, x = 0; else 8).

Sample Syntax:

LDA addr, Y

Effective Address:

23 15

Bank

Instruction:

Opcode

65816 Registers:

Bank

23

Data Bank (DBR)

15

Operand Low

High

7

Operand High

Low

0

0000 0000

0000 0000

Program Bank (PBR)

X Index Register (X)

Y Index Register (Y)

Accumulator (A or C)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC) x 1 x 0

+

High

7

Status (P)

Instructions Using It:

Effective Address Locates Data

ADC

AND

CMP

EOR

LDA

LDX

ORA

SBC

STA

Low

0

290

The Western Design Center

Absolute Indexed Indirect Addressing

Effective Address:

Bank:

Program Bank Register (PBR).

High/Low:

The Indirect Address.

Indirect Address: Located in the Program Bank at the sum of the Operand double byte and X (16 bits

if 65802/65816 native mode, x = 0; else 8 bits).

Sample Syntax:

JMP (addr, X)

Effective Address:

23

Bank

15

Instruction:

Opcode

65816 Registers:

Bank

23

Data Bank (DBR)

15

Operand Low

High

7

Operand High

Low

0

0000 0000

0000 0000

Program Bank (PBR)

X Index Register (X)

Y Index Register (Y)

Accumulator (A or C)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC) x=1 x=0

+

+1

High

7

Low

High Indirect Address

Low Indirect Address

Program Bank

Memory

0

Stack (P)

Instructions Using It:

Transfer Control to Effective Address

JMP

1

JSR

2

1 65C02 and 65802/65816 only.

2 65802/65816 only.

291

The Western Design Center

Absolute Indirect Addressing

Effective Address:

Bank:

High/Low:

Program Bank Register (PBR).

The Indirect Address.

Indirect Address: Located in Bank Zero, at the Operand double byte.

Sample Syntax:

JMP (addr)

Effective Address:

23

Bank

15

High

7

Low

0

Instruction:

Opcode

65816 Registers:

Bank

23

Data Bank (DBR)

15

0000 0000

0000 0000

Program Bank (PBR)

Operand Low

High

Operand High

Low

7

X Index Register (X)

Y Index Register (Y)

Accumulator (A or C)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC)

0

+1

High Indirect Address

Low Indirect Address

Bank 0 Memory

Status (P)

Instructions Using It:

Transfer Control to Effective Address

JMP

292

The Western Design Center

Absolute Indirect Long Addressing

Effective Address:

Bank/High/Low: The 24-bit Indirect Address.

Indirect Address: Located in Bank Zero, at the Operand double byte.

Sample Syntax:

JMP [addr]

Instruction:

Opcode

65816 Registers:

Bank

23

Data Bank (DBR)

15

Operand Low

High

7

Effective Address:

23

Bank

15

Operand High

+2

+1

Low

0

High

7

Bank Indirect Address

High Indirect Address

Low Indirect Address

Bank 0 Memory

Low

0000 0000

0000 0000

Program Bank (PBR)

X Index Register (X)

Y Index Register (Y)

Accumulator (A or C)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC)

0

Status (P)

Instructions Using It:

Transfer Control to Effective Address

JMP/JML

Note: 65802/65816 only;

65802: Data bank value is not propagated to the bus

(bank accessed is always bank 0).

293

The Western Design Center

Absolute Long Addressing

Effective Address:

Bank: Third operand byte.

High: Second operand byte.

Low: First operand byte.

Sample Syntax:

LDA long

Effective Address:

23

Bank

15

Instruction:

Opcode Operand Low Operand High

65816 Register:

Bank

23

Data Bank (DBR)

15

0000 0000

0000 0000

Program Bank (PBR)

High Low

7

X Index Register (X)

Y Index Register (Y)

Accumulator (A or C)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC)

Status (P)

0

Operand Bank

High

7

Low

Instruction Using It:

Effective Address Locates Data

ADC

AND

CMP

EOR

LDA

ORA

Transfer Control to Effective Address

JMP(JML) JSR(JSL)

Note: All are 65802/65816 only;

65802: Data bank value is not propagated to the bus

(bank accessed is always bank 0).

SBC

STA

0

294

The Western Design Center

Absolute Long Indexed, X Addressing

Effective Address:

The 24-bit Operand is added to (16 bits if 65802/65816 native mode, x = 0; else

8 bits)

Sample Syntax:

LDA long, X

Effective Address:

23

Bank

15

Instruction:

Opcode Operand Low Operand High Operand Bank

65816 Registers:

Bank

23

Data Bank (DBR)

15

High

7

Low

0

0000 0000

0000 0000

Program Bank (PBR)

X Index Register (X)

Y Index Register (Y)

Accumulator (A or C)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC) x 1 x 0

+

High

Stack

7

Low

Instructions Using It:

Effective Address Locates Data

ADC

AND

CMP

EOR

LDA

ORA

Note: All are 65802/65816 only;

65802: Data bank value is not propagated to the bus

(bank accessed is always bank 0).

SBC

STA

0

295

The Western Design Center

Accumulator Addressing

8-Bit Data (all processors): Data: Byte in accumulator A.

Accumulator B

7

Data

Accumulator A

0

16-Bit Data (65802/65816, native mode. 16-bit accumulator (m = 0):

Data High: High byte in accumulator A.

Data Low: Low byte in accumulator A.

Data

Accumulator (A or C)

Sample Syntax:

ASLA

Instruction:

Opcode

65816 Registers:

Bank

23

Data Bank (DBR)

15

0000 0000

0000 0000

Program Bank (PBR)

High Low

7

X Index Register (X)

Y Index Register (Y)

Accumulator (A or C)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC)

Status (P)

0 m 1 m 0

Instructions Using It:

ASL

DEC

1

INC

1

LSR

1 65C02 and 65802/65816 only.

ROL

ROR

296

The Western Design Center

Block Move Addressing

Source Effective Address:

Bank:

High/Low:

Second operand byte.

The 16-bit value in X; if X is only 8 bits (mode flag x = 1), the high byte is 0.

Destination Effective Address:

Bank: First operand byte.

High/Low: The 16-bit value in Y; if Y is only 8 bits (mode flag x = 1), the high byte is 0.

Count:

Number of bytes to be moved: 16-bit value in Accumulator C plus 1.

Sample Syntax:

MVN srcebk,destbk

Source Effective Address:

23 15

Bank High

7

Low

0

Instruction:

Opcode

65816 Registers:

Bank

23 15

Data Bank (DBR)

Destination Bank Source Bank

High

7

Low

0

0000 0000

0000 0000

Program Bank (PBR

X Index Register (X)

00000000

Y Index

00000000

Accumulator

Register (Y)

(A or C)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC) x 0 x 1 x 0 x 1

1

23

Destination Effective Address:

15

Bank High

7

16 bit count

Low

0

Status (P)

Instructions Using It:

Effective Address Locates Data

MVN MVP

Note: Both are 65802/65816 only;

65802: Data bank values are not propagated to the bus (bank accessed is always bank 0).

297

The Western Design Center

Direct Page Addressing

Effective Address:

Bank:

High/Low Direct Page Register plus Operand byte.

Sample Syntax:

LDA dp

Effective Address:

23

Bank

00000000

Instruction:

Opcode Operand

15

65816 Registers:

Bank

23

Data Bank (DBR)

15

High

7

Low

0

0000 0000

0000 0000

Program Bank (PBR)

X Index Register (X)

Y Index Register (Y)

Accumulator (A or C)

Direct Page (D)

Stack Pointer (S)

Program Counter (PC)

+

High

Status (P)

Instructions Using It:

Effective Address Locates Data

ADC CPY

AND

ASL

BIT

CMP

CPX

DEC

EOR

INC

LDA

LDX

LDY

LSR

ORA

ROL

ROR

SBC

7

1

65C02 and 65802/65816 only.

Low

0

STA

STX

STY

STZ

1

TRB

1

1

TSB

298

The Western Design Center

Direct Page Indexed, X Addressing

Effective Address:

Bank: Zero

High/Low: Direct Page Register plus Operand byte plus X (16 bits if 65802/65816 native mode, x =

0; else 8 bits).

Sample Syntax:

LDA dp, X

Effective Address:

23

Bank

15

00000000

High

7

Low

0

Instruction:

Opcode Operand

65816 Registers:

Bank

23

Data Bank (DBR)

15

High

7

Low

0

+

+

X Index Register (X) x 1 x 0

0000 0000

0000 0000

Program Bank (PBR)

Y Index Register (Y)

Accumulator (A or C)

Direct Page (D)

Stack Pointer (S)

Program Counter (PC)

Status (P)

Instruction Using It:

Effective Address Locates Data

ADC DEC

AND

ASL

1

BIT

CMP

EOR

INC

LDA

LDY

LSR

ORA

ROL

ROR

SBC

STA

STY

STZ

1

1

65C02 and 65802/65816 only.

299

The Western Design Center

Direct Page Indexed, Y Addressing

Effective Address:

Bank: Zero

High/Low: Direct Page Register plus Operand byte plus Y (16 bits if 65802/65816 native mode, x =

0; else 8 bits).

Sample Syntax:

LDA dp, Y

Effective Address:

23

Bank

15

00000000

High

7

Low

0

Instruction:

Opcode Operand

65816 Registers:

Bank

23

Data Bank (DBR)

15

High

7

Low

0

+

X Index Register (X)

+

Y Index Register (Y) x 1 x 0

0000 0000 Direct Page (D)

0000 0000

Program Bank (PBR)

Stack Pointer (S)

Program Counter (PC)

Status (P)

Instruction Using It:

Effective Address Locates Data

LDX STX

300

The Western Design Center

Direct Page Indexed Indirect, X Addressing

Effective Address:

Bank:

High/Low:

Indirect Address:

Data bank register.

The indirect address.

Located in the direct page at the sum of the direct page register, the operand byte, and X (16 bits if 65802/65816 native mode, x = 0; else 8), in bank 0.

Sample Syntax:

LDA (dp, X)

Effective Address:

23

Bank

15

High

7

Low

0

Instruction:

Opcode Operand

65816 Registers:

Bank

23

Data Bank (DBR)

15

High

7

Low

0

X Index Register (X) x 1 x 0

+

+1

High Indirect

Address

Low Indirect

Address

Bank 0 Memory

0000 0000

0000 0000

Program Bank (PBR)

Y Index Register (Y)

Accumulator (A or C)

Direct Page (D)

Stack Pointer (PC)

Program Counter (PC)

+

Status (P)

Instructions Using It:

Effective Address Locates Data

ADC CMP

AND EOR

LDA

ORA

SBC

STA

301

The Western Design Center

Direct Page Indirect Addressing

Effective Address:

Bank:

High/Low:

Indirect Address:

Data Bank Register (DBR)

The 16-bit Indirect Address

The Operand byte plus the Direct Page Register, in Bank Zero.

Sample Syntax:

LDA (dp)

Effective Address:

23

Bank

15

High

7

Low

0

Instruction:

Opcode

65816 Registers:

Bank

23

Data Bank (DBR)

15

Operand

High

7

Low

0

X Index Register (X)

+

+1

High Indirect

Address

Low Indirect

Address

Bank 0 Memory

0000 0000

0000 0000

Program Bank (PBR)

Y Index Register (Y)

Accumulator (A or C)

Direct Page (D)

Stack Pointer (S)

Program Counter (PC)

Status (P)

Note: All are 65C02 and 65802/65816 only.

Instructions Using It:

Effective Address Located Data

ADC CMP

AND EOR

LDA

ORA

SBC

STA

302

The Western Design Center

Direct Page Indirect Long Addressing

Effective Address:

Bank/High/Low:

Indirect Address:

The 24-bit Indirect Address.

The Operand byte plus the Direct Page Register, in Bank Zero.

Sample Syntax:

LDA [dp]

Effective Address:

23

Bank

15

High

7

Low

0

Instruction:

Opcode Operand

65816 Registers:

Bank

23

Data Bank (DBR)

15

High

7

Low

0

X Index Register (X)

Y Index Register (Y)

+

+2

+1

Bank Indirect

Address

High Indirect

Address

Low Indirect

Address

Bank 0 Memory

0000 0000

0000 0000

Program Bank (PBR)

Accumulator (A or C)

Direct Page (D)

Stack Pointer (S)

Program Counter (PC)

Status (P)

Instruction Using It:

Effective Address Locates Data

ADC CMP

AND EOR

LDA

ORA

Note: All are 65802/65816 only;

65802: Data bank value is not propagated to the bus

(bank accessed is always bank 0).

SBC

STA

303

The Western Design Center

Direct Page Indirect Indexed, Y Addressing

Effective Address:

Found by concatenating the data bank to the double-byte indirect address, then adding Y (16 bits if 65802/65816 native mode, x = 0; else 8).

Indirect Address:

Located in the Direct Page at the sum of the direct page register and the operand byte, in bank zero.

Sample Syntax:

LDA (dp), Y

Effective Address:

23

Bank

15

High

7

Low

0

Instruction:

Opcode Operand

65816 Registers:

Bank

23

Data Bank (DBR)

15

High

7

Low

0

0000 0000

0000 0000

Program Bank (PBR)

X Index Register (X)

Y Index Register (Y)

Accumulator (A or C)

Direct Page (D)

Stack Pointer (S)

Program Counter (PC) x=1 x=0

+

+1

High Indirect

Address

Low Indirect

Address

Bank 0 Memory

Status (P)

Instruction Using It:

Effective Address Locates Data

ADC

AND

CMP

EOR

LDA

ORA

SBC

STA

+

304

The Western Design Center

Direct Page Indirect Long Indexed, Y Addressing

Effective Address:

Found by adding to the triple-byte indirect address Y (16 bits if 65802/65816 native mode, x = 0; else 8 bits).

Indirect Address:

Located in the Direct Page at the sum of the direct page register and the operand byte in bank zero.

Sample Syntax:

LDA (dp), Y

Effective Address:

23

Bank

15

High

7

Low

0

Instruction:

Opcode Operand

65816 Registers:

Bank

23

Data Bank (DBR)

15

High

7

Low

X Index Register (X)

Y Index Register (Y)

0

+

+2

+1

Bank Indirect

Address

High Indirect

Address

Low Indirect

Address

Bank 0 Memory x 1 x 0

0000 0000

0000 0000

Program Bank (PBR)

Accumulator (A or C)

Direct Page (D)

Stack

Program

Pointer (S)

Counter (PC)

Status (P)

Instructions Using It:

Effective Address Locates Data

ADC

AND

CMP

EOR

LDA

ORA

Note: All are 65802/65816 only;

65802: Data bank value is not propagated to the bus

(bank accessed is always bank 0).

SBC

STA

+

305

The Western Design Center

Immediate Addressing

8-Bit Data (all processors): Data Operand byte.

16-Bit Data (65802/65816, native mode, applicable mode flag m or x = 0):

Data High: Second Operand byte.

Data Low: First Operand byte.

Sample Syntax:

LDA const.

Instruction:

Opcode Data Low = Operand Low Data High = Operand High

Instruction:

Opcode

65816 Registers:

Bank

23

Data Bank (DBR)

15

Data = Operand

High

7

Low

0

0000 0000

0000 0000

Program Bank (PBR)

X Index Register (X)

Y Index Register (Y)

Accumulator (A or C)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC)

Status (P)

Instructions Using It:

ADC CPX

CPY AND

1

BIT

CMP

EOR

LDA

LDX

LDY

ORA

REP

1

1.

65C02 and 65802/65816 only.

2.

65802/65816 only.

SBC

SEP

1

306

The Western Design Center

Implied Addressing

Type 1: Mnemonic specifies register(s) to be operated on

Type 2: Mnemonic specifies flag bit(s) to be operated on

Type 3: Mnemonic specifies operation; no data involved

Sample Syntax:

NOP

Instruction:

Opcode

65816 Registers:

Bank

23

Data Bank (DBR)

15

High

7

Low

0000 0000

0000 0000

Program Bank (PBR)

X Index Register (X)

Y Index Register (Y)

Accumulator (A or C)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC)

0

Status (P)

Instructions Using It:

Mnemonic Specifies Register(s)

DEX TAY

DEY

INX

INY

TAX

TCD

TCS

TDC

TSC

Mnemonics Specifies Operation

NOP STP

1

65802/65816 only.

TSX

TXA

TXS

TXY

TYA

Mnemonics Specifies Flag Bit(s)

CLC CLI

CLD CLV

SEC

SED

WAP

TYX

XBA

SEI

XCE

307

The Western Design Center

Program Counter Relative Addressing

Effective Address:

Bank:

Program Bank Register (PBR).

High/Low

The Operand byte, a two’s complement signed value, is sign-extended to 16 bits, then added to the Program Counter (its value is the address of the opcode following this one).

Sample Syntax:

BRA nearlabel

Effective Address:

23

Bank

15

High

7

Low

0

Instruction:

Opcode

65816 Registers:

Bank

23

Data Bank (DBR)

15

Operand

High

7

Low sign extended to 16 bits

0

+

X Index Register (X)

0000 0000

0000 0000

Program Bank (PBR)

Y Index Register (Y)

Accumulator (A or C)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC)

Status (PC)

Instructions Using It:

Transfer Control to Effective Address

BCC BMI BRA

1

BCS

BEQ

BNE

BPL

BVC

BVS

1

65C02 and 65802/65816 only.

308

The Western Design Center

Program Counter Relative Long Address

Effective Address:

Bank:

Program Bank Register (PBR).

High/Low:

The Operand double byte, a two’s complement signed value, is added to the Program

Counter (its value is the address of the opcode following this one).

Sample Syntax:

BRL label

Effective Address:

23

Bank

15

High

7

Low

0

Instruction:

Opcode

65816 Registers:

Bank

23

Data Bank (DBR)

15

Operand Low

High

7

Operand High

Low

0

X Index Register (X)

Y Index Register (Y)

0000 0000

0000 0000

Program Bank (PBR)

Accumulator (A or C)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC)

+

Status (P)

Instructions Using It:

Transfer Control to Effective Address

BRL

Note: 65802/65816 only.

309

The Western Design Center

Stack (Absolute) Addressing

Source of data to be pushed: The 16-bit operand, which can be either an absolute address or

immediate data.

Destination effective address: Provided by Stack Pointer.

Sample Syntax:

PEA addr/const

Instruction:

Opcode

65816 Registers:

Bank

23

Data Bank (DBR)

15

Data Low = Operand Low

(Data)

Data High = Operand High

High Low

7 0

0000 0000

X Index Register (X)

Y Index Register (Y)

Accumulator (A or C)

Direct Page Register (D)

0000 0000

Program Bank (PBR)

Stack Pointer (S)

Program Counter (PC)

Status (P)

Instruction Using It:

PEA

Note: 65802/65816 only.

310

The Western Design Center

Stack Pointer (S) before

Stack

Data High

Data Low

after

Bank 0

Data

311

The Western Design Center

Stack (Direct Page Indirect) Addressing

Source of data to be pushed: The 16-bit indirect address (or double-byte data) located at the sum of

the Operand byte plus the Direct Page Register, in Bank Zero.

Destination effective address: Provided by Stack Pointer.

Sample Syntax:

PEI dp

Effective Address:

23 15

Bank

Instruction:

Opcode

65816 Registers:

Bank

23

Data Bank (DBR)

15

Operand

High

7

0000 0000

0000 0000

Program Bank (PBR)

Low

X Index Register (X)

Y Index Register (Y)

Accumulator (A or C)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC)

0

+

Status (P)

Instruction Using It:

Effective Address Locates Data

PEI

Note: 65802/65816 only.

7

High Low

0

312

The Western Design Center

Source

Effective Address + 1

Source

Effective Address:

Stack Pointer (S) before after

High Indirect Address

Low Indirect Address

Bank 0

Stack

High Indirect Address

Low Indirect Address

Bank 0

313

The Western Design Center

Stack (Interrupt) Addressing

Effective Address: After pushing the Program Bank (65802/816 native mode only), followed by the

Program Counter and the Status Register, the Effective Address is loaded into the Program Counter and Program Bank Register, transferring control there.

Bank:

Zero

High/Low:

The contents of the instruction- and processor-specific interrupt vector.

Data: Source:

Program Bank, Program Counter, and Status Register.

Destination Effective Address: Provided by Stack Pointer.

Sample Syntax:

BRK

Instruction:

Opcode

Optimal Signature

Byte

Note: Hardware interrupt addressing differs only

in that there is no instruction involved

65816 Registers:

Bank

23

Data Bank (DBR)

15

High

7

0000 0000

0000 0000

Program Bank (PBR)

Low

X Index Register (X)

Y Index Register (Y)

Accumulator (A or C)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC)

0

Effective Address:

23

Bank

15

00000000

High

7

Interrupt Vector

Address +1

Interrupt Vector

Address

Contents of

Vector High

Contents of

Vector Low

Bank 0 Memory

Vectors 6502/C02/emulation

IRQ

RESET

NMI

ABORT

BRK

COP

00FFFE.F (with BRK)

00FFFC.D

00FFFA.B

00FFF8.9

00FFFE.F

00FFF4.5

Status (P)

Low

Instructions Using It:

Transfer Control to Effective Address

BRK COP

Native

00FFEE.F

00FFEA.B

00FFE8.9

00FFE6.7

00FFE4.5

0

314

The Western Design Center

Stack (Interrupt) Addressing

Stack Pointer (S)

Stack Pointer (S) before after

6502/65C02/Emulation Mode

Stack

PC High

PC Low

Status (P)

Bank 0 before after

65802/65816 Native Mode

Stack

Program Bank (PBR)

PC High

PC Low

Status (P)

Bank 0

Program

Status (P)

Counter (PC)

Program Bank (PBR)

Program Counter (PC)

Status (P)

315

The Western Design Center

Stack (Program Counter Relative) Addressing

Source of data to be pushed: The 16-bit sum of the 16-bit Operand plus the 16-bit Program Counter.

(Note that the 16-bit Operand which is added is the object code operand; the operand used in the instruction’s syntax required by most assemblers is a label which is converted to the object operand.)

Destination Effective Address: Provided by Stack Pointer.

Sample Syntax:

PER label

Instruction:

Opcode Operand Low Operand High

65816 Registers:

Bank

23

Data Bank (DBR)

15

High

7

Low

0

+ Data

0000 0000

0000 0000

Program Bank (PBR)

X Index Register (X)

Y Index Register (Y)

Accumulator (A or C)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC)

Status (P)

Instructions Using It:

PER

Note: 65802/65816 only.

Stack Pointer (S) before after

Stack

Data High

Data Low

Bank 0

Data

316

The Western Design Center

Stack (Pull) Addressing

Source Effective Address: Provided by Stack Pointer.

Destination of data to be pulled: Register specified by the opcode. The Stack Pointer (S) is

incremented, specifying the location from which an 8-bit register – or the low byte of a 16-bit register

– will be loaded. If the register is 16 bits, the Stack Pointer will be incremented a second time, and the register’s high byte will be loaded from this second new Stack Pointer location.

Sampler Syntax:

PLA

Instruction:

Opcode

65816 Registers:

23

Bank

Data Bank (DBR)

(also called B)

15

High

7

Low

0

0000 0000

0000 0000

Program Bank (PBR)

X Index Register (X)

Y Index Register (Y)

Accumulator (A or C)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC)

Status (P)

Instruction Using It:

Effective Address Locates Data

PLA

PLB

PLD

PLP

PLX

`PLY

1.

65802/65816 only.

2.

8 bit register, except on 65802/816 may either 8 or 16 bits, dependent on flag m.

3.

8 bit register, except on 65802/816 may be either 8 or 16 bits, dependent on flag x.

4.

16 bits always.

5.

8 bits always.

317

The Western Design Center

Pull 8-bit Register

Stack Pointer (S) after before

Stack

Register

Bank 0

Pull 16-bit Register

Stack Pointer (S) after before

Stack

Register High

Register Low

Bank 0

318

The Western Design Center

Stack (Push) Addressing

Source of data to be pushed: Register specified by the opcode.

Destination Effective Address: Provided b Stack Pointer.

The Stack Pointer (S) specifies the location to which an 8-bit register – or the high byte of a 16-bit register – will be stored. The low byte of a 16-bit register will be stored to the Stack Pointer location minus one. After storage of an 8-bit register, S is decremented by 1; after a 16-bit register, S is decremented by 2.

Sample Syntax:

PHA

Instructions:

Opcode

65816 Registers:

23

Bank

Data Bank (DBR)

(also called B)

15

High

7

Low

0

0000 0000

0000 0000

Program Bank (PBR)

(also called K)

X Index Register (X)

Y Index Register (Y)

Accumulator (A or C)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC)

Status (P)

Instruction Using It:

Effective Address Locates Data

PHA PHD

PHB PHK

PHP

PHX

1

65802/65816 only.

2

8 bit register, except on 65802/816, may be either 8 or 16 bits, dependent on flag m.

3

8 bit register, except on 65802/816, may be either 8 or 16 bits, dependent on flag x.

4

16 bit always.

5

8 bit always.

319

The Western Design Center

Push 8-bit Register

Stack Pointer (S) before after

Stack

Register

Bank 0

Push 16-bit Register before

Stack Pointer (S) after

Stack

Register High

Register Low

Bank 0

320

The Western Design Center

Stack (RTI) Addressing

Source Effective Address: Provided by Stack Pointer.

Destination of values to be pulled: First the Status Register, then the Program Counter is pulled,

followed (65802/65816 native mode only) by the Program Bank.

Control is transferred to the new Program Counter (and Program Bank) value(s).

Sample Syntax:

RTI

Instruction:

Opcode

65816 Registers:

Bank

23

Data Bank (DBR)

15

High

7

Low

0000 0000

0000 0000

Program Bank (PBR)

X Index Register (X)

Y Index Register (Y)

Accumulator (A or C)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC)

Status (P)

0

Stack Pointer (S) after before

Stack (RTI) Addressing

6502/65C02/Emulation Mode

Stack

PC High

PC Low

Status (P)

Bank 0

Instructions Using It:

RTI

Program Counter (PC)

Status (P)

Stack Pointer (S)

65802/65816 Native Mode after before

Stack

Program Bank (PBR)

PC High

PC Low

Status (P)

Bank 0

Program Bank (PBR)

Program Counter (PC)

Status (P)

321

The Western Design Center

Stack (RTL) Addressing

Source Effective Address: Provided by Stack Pointer.

Destination of values to be pulled: First the Program Counter is pulled and incremented by one.

Then the Program Bank is pulled back.

Sample Syntax:

RTL

Instruction:

Opcode

65816 Registers:

Bank

23

Data Bank (DBR)

15

High

7

Low

0

0000 0000

0000 0000

Program Bank (PBR)

X Index Register (X)

Y Index Register (Y)

Accumulator (A or C)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC)

Status (P)

Stack Pointer (S) after before

Stack (RTL) Addressing

Stack

Program Bank (PBR)

PC High

PC Low

Bank 0

+1

Program Bank (PBR)

Program Counter (PC)

322

The Western Design Center

Stack (RTS) Addressing

Source Effective Address: Provided by Stack Pointer.

Destination of values to be pulled: The Program Counter is pulled and incremented by one. The

Program Bank remains unchanged.

Control is transferred to the new Program Counter value.

Sample Syntax:

RTS

Instruction:

Opcode

65816 Registers:

Bank

23

Data Bank (DBR)

15

High

0000 0000

0000 0000

Program Bank (PBR)

Instruction Using It:

RTS

7

X Index Register (X)

Y Index Register (Y)

Accumulator (A or C)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC)

Low

Status (P)

0

Stack (RTS) Addressing

Stack Pointer (S) after befor e

Stack

PC High

PC Low

Bank 0

+1 Program

Counter

(PC)

323

The Western Design Center

Stack Relative Addressing

Effective Address:

Bank: Zero.

High/Low: The 16-bit sum of the 8-bit Operand and the 16-bit Stack Pointer.

Sample Syntax:

LDA sr,S

Effective:

23

Bank

15

00000000

7

High Low

Instruction:

Opcode

65816 Registers:

Bank

23

Data Bank (DBR)

15

Operand

High

7

Low

0

+

0000 0000

0000 0000

Program Bank (PBR)

X Index Register (X)

Y Index Register (Y)

Accumulator (A or C)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC)

Status (P)

0

Instruction Using It:

Effective Address Locates Data

ADC CMP

AND EOR

Note: All are 65802/65816 only.

324

The Western Design Center

Stack Relative Indirect Indexed, Y Addressing

Effective Address: The Data Bank Register is concatenated to the Indirect Address; the 24-bit result

is added to Y (16 bits if 65802/65816 native mode, x = 0; else 8 bits).

Indirect Address: Located at the 16-bit sum of the 8-bit Operand and the 16-bit Stack Pointer.

Sample Syntax:

LDA (sr,S),Y

Effective Address:

23

Bank

15

High

7

Low

0

Instruction:

Opcode Operand

65816 Registers:

Bank

23

Data Bank (DBR)

15

High

7

Low

0

X Index Register (X)

Y Index Register (Y) x-1 x-0

+

+1

Stack

High Indirect Address

Low Indirect Address

Bank 0

Memory

+

Accumulator (A or C)

0000 0000

0000 0000

Program Bank (PBR)

Direct Page Register (D)

Stack Pointer (S)

Program Counter (PC)

Status (P)

Instructions Using It:

Effective Address Locates Data

ADC

AND

CMP

EOR

LDA

ORA

SBC

STA

Note: All are 65802/65816 only;

65802: Data bank value is not propagated to the bus

(bank accessed is always bank 0).

325

The Western Design Center

18) Chapter Eighteen

The Instruction Sets

This chapter devotes a page to each of the 94 different 65816 operations. Each operation may have more than one addressing mode available to it; these are detailed for each instruction. The symbols in Table

18.1 are used to express the different kinds of values that instruction operands may have. The effect of each operation on the status flags varies. The symbols in Table 18.2 are used to indicate the flags that are affected by a given operation.

addr addr / const const destbk dp label long nearlabel sr srcebk two-byte address two-byte value: either an address or a constant one- or two-byte constant

64K bank to which string will be moved one-byte direct page offset (6502/65C02: zero page) label of code in same 64 bank as instruction three-byte address (includes bank byte) label of code close enough to instruction to be reachable by a one-byte signed offset one-byte stack relative offset

64K bank from which string will be moved

Table 18-1 Operand Symbols

Flags:

bits: 7 6 5 4 3 2 1 0

6502/65C02/6502 emulation:

65802/65816 native: n v - b d i z c n v m x d i z c n — negative result v — overflow m — 8-bit memory/accumulator x — 8-bit index registers b — BRK caused interrupt d — decimal mode i — IRQ interrupt disable z — zero result c — carry

Table 18-2 65x Flags

326

The Western Design Center

Add With Carry ADC

Add the data located at the effective address specified by the operand to the contents of the accumulator; add one to the result if the carry flag is set, and store the final result in the accumulator.

The 65x processors have no add instruction that does not involve the carry. To avoid adding the carry flag to the result, you must either be sure that it is already clear, or you must explicitly clear it (using CLC) prior to executing the ADC instruction

.

In a multi-precision (multi-word) addition, the carry should be cleared before the low-order words are added; the addition of the low word will generate a new carry flag value based on the addition. This new value in the carry flag is added into the next (middle-order or high-order) addition; each intermediate result will correctly reflect the carry from the previous addition.

d flag clear: Binary addition is performed.

d flag set: Binary coded decimal (BCD) addition is performed.

8-bit accumulator (all processors): Data added from memory is eight-bit.

16-bit accumulator (65802/65816 only, m = 0): Data added from memory is sixteen-bit: the low-order eight bits are located at the effective address; the high-order eight bits are located at the effective address plus one.

Flags Affected:

v z c

n v — — — — z c

n Set if most significant bit of result is set; else cleared.

Set if signed overflow; cleared if valid signed result.

Set if result is zero; else cleared.

Set if unsigned overflow; cleared if valid unsigned result.

Codes:

Addressing Mode

+ +

Syntax

Opcode

(hex) 6502

Available on:

65C02 65802/816

Immediate ADC #const 69 x x x

Absolute

Absolute Long

Direct Page (DP)

DP Indirect

DP Indirect Long

Absolute Indexed, X

Absolute Long Indexed, X

Absolute Indexed Y

DP Indexed, X

DP Indexed Indirect, X

DP Indirect Indexed, Y

DP Indirect Long Indexed, Y

Stack Relative (SR)

SR Indirect Indexed, Y

ADC addr

ADC long

ADC dp

ADC (dp)

ADC [dp]

ADC addr, X

ADC long, X

ADC addr, Y

ADC dp, X

ADC (dp, X)

ADC (dp), Y

ADC [dp], Y

ADC sr, S

ADC (sr, S), Y

6D

6F

65

72

67

7D

7F

79

75

61

71

77

63

73 x x x x x x x x x x x x x x x x x x x x x x

+ + ADC, a Primary Group Instruction, has available all of the Primary Group addressing modes and bit patterns

* Add 1 byte if m = 0 (16-bit memory/accumulator)

1

Add 1 cycle if m = 0 (16-bit memory/accumulator)

2

Add 1 cycle if low byte of Direct Page register is other than zero (DL< >0)

3

Add 1 cycle if adding index crosses a page boundary

4

Add 1 cycle if 65C02 and d = 1 (decimal mode, 65C02) x x x x x x x

# of # of

Bytes Cycles

2*

2

2

2

2

3

2

2

3

4

2

2

3

4

2

2

1,4

4

1,3,4

4

1,2,4

6

1,2,4

5

1,2,3,4

6

1,2,4

4

1,4

7

1,4

4

1,4

5

1,4

3

1,2,4

5

1,2,4

6

1,2,4

4

1,3,4

5

1,4

327

The Western Design Center

And Accumulator with Memory AND

Bitwise logical AND the data located at the effective address specified by the operand with the contents of the accumulator. Each bit in the accumulator is ANDed with the corresponding bit in memory, with the result being stored in the respective accumulator bit.

The truth table for the logical AND operation is:

First Operand

0

1

Second

0

0

0

Operand

1

0

1

Figure 18-1 AND Truth Table

That is, a 1 or logical true results in given bit being true only if both elements of the respective bits being ANDed are 1s, or logically true.

8-bit accumulator (all processors): Data ANDed from memory is eight-bit.

16-bit accumulator (65802/65816 only, m = 0): Data ANDed from memory is sixteen-bit: the loworder byte is located at the effective address; the high-order byte is located at the effective address plus one.

Flags Affected: n - - - - - z n Set if most significant bit of result is set; else cleared.

z Set if result is zero; else cleared.

Codes:

Opcode Available on: # of # of

Addressing Mode

+ +

Immediate

Absolute

Absolute Long

Direct Page (DP)

DP Indirect

DP Indirect Long

Absolute Indexed, X

Absolute Long Indexed, X

Absolute Indexed,Y

DP Indexed, X

DP Indexed Indirect, X

DP Indirect Indexed, Y

DP Indirect Long Indexed, Y

Stack Relative (SR)

SR Indirect Indexed, Y

Syntax

AND # const

AND addr

AND long

AND dp

AND(dp)

AND [dp]

AND addr, X

AND long, X

AND addr, Y

AND dp, X

AND (dp, X)

AND (dp), Y

AND [dp], Y

AND sr, S

AND (sr, S), Y

(hex) 6502 65C02 65802/816 Bytes Cycles

29 x x x 2* 2

1

2D

2F x x x x

3

4

4

1

5

1

25

32

27

3D

3F

39

35

21

31

37

23

33 x x x x x x x x x x x x x x x x x x x x x x x x x

2

2

2

3

4

3

2

2

2

2

2

2

3

1,2

5

1,2

6

1,2

4

1,3

5

1

4

1,3

4

1,2

6

1,2

5

1,2,3

6

1,2,0

4

1

7

1

+ + AND, a Primary Group Instruction, has available all of the Primary Group addressing modes and bit patterns

* Add 1 byte if m = 0 (16-bit memory/accumulator)

1

Add 1 cycle if m = 0 (16-bit memory/accumulator)

2

Add 1 cycle if low byte of Direct Page register is other than zero (DL< >0)

3

Add 1 cycle if adding index crosses a page boundary

328

The Western Design Center

Shift Memory or Accumulator Left

ASL

Shift the contents of the location specified by the operand left one bit. That is, bit one takes on the value originally found in bit zero, bit two takes the value originally in bit one, and so on; the leftmost bit (bit 7 on the 6502 and 65C02 or if m = 1 on the 65802/65816, or bit 15 if m = 0) is transferred into the carry flag; the rightmost bit, bit zero, is cleared. The arithmetic result of the operation is an unsigned multiplication by two.

ASL

1 0 1 1 0 0 1 1 0

X

Carry Flag

Figure 18-2 ASL

8-bit accumulator/memory (all processors): Data shifted is eight bits.

16-bit accumulator/memory (65802/65816 only, m = 0): Data shifted is sixteen bits: if in memory, the low-order eight bits are located at the effective address; the high-order eight bits are located at the effective address plus one.

Flags Affected: n - - - - - z c n z c

Set if most significant bit of result is set; else cleared.

Set if result is zero; else cleared.

High bit becomes carry: set if high bit was set; cleared if high bit was zero.

Codes:

Addressing Mode

Accumulator

Absolute

Direct Page (DP)

Syntax

ASL A

ASL addr

ASL dp

Absolute Indexed, X

ASL addr, X

DP Indexed, X

ASL dp, X

Opcod e

Available on: # of # of

(hex) 6502 65C02 65802/816 Bytes Cycles

0A

0E

06

1E

16 x x x x x x x x x x x x x x x

1

3

2

3

2

2

6

1

5

1,2

7

1,3

6

1,2

1 Add 2 cycles if m = 0 (16-bit memory/accumulator)

2 Add 1 cycle if low byte of Direct Page register is other than zero (DL< >0)

3 Subtract 1 cycle if 65C02 and no page boundary crossed

329

The Western Design Center

Branch if Carry Clear BCC

The carry flag in the P status register is tested. If it is clear, a branch is taken; if it is set, the instruction immediately following the two-byte BCC instruction is executed.

If the branch is taken, a one-byte signed displacement, fetched from the second byte of the instruction, is sign-extended to sixteen bits and added to the program counter. Once the branch address has been calculated, the result is loaded into the program counter, transferring control to that location.

The allowable range of the displacement is – 128 to + 127 (from the instruction immediately following the branch).

BCC may be used in several ways: to test the result of a shift into the carry; to determine if the result of a comparison is either less than (in which case a branch will be taken), or greater than or equal (which causes control to fall through the branch instruction); or to determine if further operations are needed in multi-precision arithmetic.

Because the BCC instruction causes a branch to be taken after a comparison or subtraction if the accumulator is less than the memory operand (since the carry flag will always be cleared as a result), many assemblers allow an alternate mnemonic for the BCC instruction: BLT, or Branch if Less Than.

Flags Affected :

Codes:

- - - - - - - -

Opcode Available on: # of # of

Addressing Mode +

+

Program Counter

Relative

Syntax

BCC nearlabel

(hex)

90

6502

x

65C02

x

65802/816

x

Bytes

2 2

Cycles

1,2

(or BLT

nearlabel)

1 Add 1 cycle if branch is taken.

2 Add 1 more cycle if branch taken crosses page boundary on 6502, 65C02, or 65816/65802’s 6502 emulation mode (e = 1)

330

The Western Design Center

Branch if Carry Set BCS

The carry flag in the P status register is tested. If it is set, a branch is taken; if it is clear, the instruction immediately following the two-byte BCS instruction is executed.

If the branch is taken, a one-byte signed displacement, fetched from the second byte of the instruction, is sign-extended to sixteen bits and added to the program counter. Once the branch address has been calculated, the result is loaded into the program counter, transferring control to that location.

The allowable range of the displacement is – 128 to + 127 (from the instruction immediately following the branch).

BCS is used in several ways: to test the result of a shift into the carry; to determine if the result of a comparison is either greater than or equal (which causes the branch to be taken) or less than; or to determine if further operations are needed in multi-precision arithmetic operations.

Because the BCS instruction causes a branch to be taken after a comparison or subtraction if the accumulator is greater than or equal to the memory operand (since the carry flag will always be set as a result), many assemblers allow an alternate mnemonic for the BCS instruction: BGE or Branch if Greater or Equal.

Flags Affected:

Codes:

- - - - - - - -

Addressing Mode

Program Counter

Relative

Syntax

BCS

nearlabel

(or BGE

nearlabel)

Opcode

(hex) 6502 65C02 65802/816 Bytes Cycles

B0 x

Available on:

x x

# of

2

# of

2

1,2

1 Add 1 cycle if branch is taken

2 Add 1 more cycle if branch taken crosses page boundary on 6502, 65C02, or 65816/65802’s 6502 emulation mode (e = 1).

331

The Western Design Center

Branch if Equal BEQ

The zero flag in the P status register is tested. If it is set, meaning that the last value tested (which affected the zero flag) was zero, a branch is taken; if it is clear, meaning the value tested was non-zero, the instruction immediately following the two-byte BEQ instruction is executed.

If the branch is taken, a one-byte signed displacement, fetched from the second byte of the instruction, is sign-extended to sixteen bits and added to the program counter. Once the branch address has been calculated, the result is loaded into the program counter, transferring control to that location.

The allowable range of the displacement is – 128 to + 127 (from the instruction immediately following the branch).

BEQ may be used in several ways: to determine if the result of a comparison is zero (the two values compared are equal), for example, or if a value just loaded, pulled, shifted, incremented or decremented is zero; or to determine if further operations are needed in multi-precision arithmetic operations. Because testing for equality to zero does not require a previous comparison with zero, it is generally most efficient for loop counters to count downwards, existing when zero is reached.

Flags Affected: - - - - - - - -

Codes:

Addressing Mode Syntax

Opcode

(hex) 6502

Available on:

65C02 65802/816

# of # of

Byte s

Cycle s

Program Counter

BEQ

F0 x x x 2 2

1,2

Relative

nearlabel

1 Add 1 cycle if branch is taken

2 Add 1 more cycle if branch taken crosses page boundary on 6502, 65C02, or 65816/65802’s 6502 emulation mode (e = 1).

332

The Western Design Center

Test Memory Bits against Accumulator BIT

BIT sets the P status register flags based on the result of two different operations, making it a dualpurpose instruction:

First, it sets or clears the n flag to reflect the value of the high bit of the data located at the effective address specified by the operand, and sets or clears the v flag to reflect the contents of the next-to-highest bit of the data addressed.

Second, it logically ANDs the data located at the effective address with the contents of the accumulator; it changes neither value, but sets the z flag if the result is zero, or clears it if the result is non-zero.

BIT is usually used immediately preceding a conditional branch instruction: to test a memory value’s highest or next-to-highest bits; with a mask in the accumulator, to test any bits of the memory operand; or with a constant as the mask (using immediate addressing) or a mask in memory, to test any bits in the accumulator.

All of these tests are non-destructive of the data in the accumulator or in memory. When the BIT instruction is used with the immediate addressing mode, the n and v flags are unaffected.

8-bit accumulator/memory (all processors): Data in memory is eight-bit; bit 7 is moved into the n flag; bit 6 is moved into the v flag.

16-bit accumulator/memory (65802/65816 only, m = 0): Data in memory is sixteen-bit: the low-order eight bits are located at the effective address; the high-order eight bits are located at the effective address plus one. Bit 15 is moved into the n flag; bit 14 is moved into the v flag.

Flags Affected:

n v - - - - z - (Other than immediate addressing)

- - - - - - z - (Immediate addressing only)

n Takes value of most significant bit of memory data.

v Takes value of next-to-highest bit of memory data.

z Set if logical AND of memory and accumulator is zero; else cleared.

Codes:

Addressing Mode

Immediate

Absolute

Direct Page (DP)

Syntax

BIT # const

BIT addr

BIT dp

Opcode Available on: # of # of

(hex) 6502 65C02 65802/816 Bytes Cycles

89 x x 2* 2

1

2C

24 x x x x x x

3

2

4

1

3

1,2

Absolute Indexed,

X

DP Indexed, X

BIT addr, X

3C x

BIT dp, X

34 x

*

Add 1 byte if m = 0 (16-bit memory/accumulator)

1 Add 1 cycle if m = 0 (16-bit memory/accumulator)

2 Add 1 cycle if low byte of Direct Page register is other than zero (DL< >0)

3

Add 1 cycle if adding index crosses a page boundary x x

3

2

4

4

1,3

1,2

333

The Western Design Center

Branch if Minus BMI

The negative flag in the P status register is tested. If it is set, the high bit of the value which most recently affected the n flag was set, and a branch is taken. A number with its high bit set may be interpreted as a negative two’s-complement numbers, so this instruction tests, among other things, for the sign of two’scomplement numbers. If the negative flag is clear, the high bit of the value which most recently affected the flag was clear, or, in the two’s-complement system, was a positive number, and the instruction immediately following the two-byte BMI instruction is executed.

If the branch is taken, a one-byte signed displacement, fetched from the second byte of the instruction, is sign-extended to sixteen bits and added to the program counter. Once the branch address has been calculated, the result is loaded into the program counter, transferring control to that location.

The allowable range of the displacement is – 128 to + 127 (from the instruction immediately following the branch).

BMI is primarily used to either determine, in two’s-complement arithmetic, if a value is negative or, in logic situations, if the high bit of the value is set. It can also be used when looping down through zero (the loop counter must have a positive initial value) to determine if zero has been passed and to effect an exit from the loop.

Flags Affected: - - - - - - - -

Codes:

Addressing Mode Syntax

Opcode Available on: # of # of

Cycle

(hex) 6502 65C02 65802/816 Bytes s

Program Counter

Relative

BMI

nearlabel

30 x x x 2 2

1,2

1 Add 1 cycle if branch is taken.

2 Add 1 more cycle if branch taken crosses page boundary on 6502, 65C02, or 65816/65802’s 6502 emulation mode (e = 1)

334

The Western Design Center

Branch if Not Equal BNE

The zero flag in the P status register is tested. If it is clear (meaning the value just tested is non-zero), a branch is taken; if it is set (meaning the value tested is zero), the instruction immediately following the two-byte

BNE instruction is executed.

If the branch is taken, a one-byte signed displacement, fetched from the second byte of the instruction, is sign-extended to sixteen bits and added to the program counter. Once the branch address has been calculated, the result is loaded into the program counter, transferring control to that location.

The allowable range of the displacement is – 128 to + 127 (from the instruction immediately following the branch).

BNE may be used in several ways: to determine if the result of a comparison is non-zero (the two values compared are not equal), for example, or if the value just loaded or pulled from the stack is non-zero, or to determine if further operations are needed in multi-precision arithmetic operations.

Flags Affected: - - - - - - - -

Codes:

Addressing Mode Syntax

Opcode

(hex)

Available on: # of # of

6502 65C02 65802/816 Bytes Cycles

Program Counter

Relative

BNE

nearlabe

D0 x x x 2 2

1,2

l

1 Add 1 cycle if branch is taken

2 Add 1 more cycle if branch taken crosses page boundary on 6502, 65C02, or 65816/65802’s 6502 emulation mode (e = 1)

335

The Western Design Center

Branch if Plus BPL

The negative flag in the P status register is tested. If it is clear – meaning that the last value which affected the zero flag had it’s high bit clear – a branch is taken. In the two’s complement system, values with their high bit clear are interpreted as positive numbers. If the flag is set, meaning the high bit of the last value was set, the branch is not taken; it is a two’s-complement negative number, and the instruction immediately following the two-byte BPL instruction is executed.

If the branch is taken, a one-byte signed displacement, fetched from the second byte of the instruction, is sign-extended to sixteen bits and added to the program counter. Once the branch address has been calculated, the result is loaded into the program counter, transferring control to that location.

The allowable range of the displacement is – 128 to + 127 (from the instruction immediately following the branch).

BPL is used primarily to determine, in two’s-complement arithmetic, if a value is positive or not or, in logic situations, if the high bit of the value is clear.

Flags Affected:

Codes:

- - - - - - - -

Addressing Mode

Program Counter

Syntax

BPL

nearlabel

Opcode

(hex)

10

6502

x

Available on:

65C02

x

65802/816

x 2

# of

Bytes

# of

Cycles

2

1,2

Relative

1 Add 1 cycle if branch is taken

2 Add 1 more cycle if branch taken crosses page boundary on 6502, 65C02, or 65816/65802’s 6502 emulation mode (e = 1)

336

The Western Design Center

Branch Always BRA

A branch is always taken, and no testing is done: in effect, an unconditional JMP is executed, but since signed displacements are used, the instruction is only two bytes, rather than the three bytes of a JMP.

Additionally, using displacements from the program counter makes the BRA instruction relocatable. Unlike a

JMP instruction, the BRA is limited to targets that lie within the range of the one-byte signed displacement of the conditional branches: - 128 to + 127 bytes from the first byte following the BRA instruction.

To branch, a one-byte signed displacement, fetched from the second byte of the instruction, is signextended to sixteen bits and added to the program counter. Once the branch address has been calculated, the result is loaded into the program counter, transferring control to that location.

Flags Affected:

Codes:

- - - - - - - -

Addressing Mode Syntax

Program Counter

Relative

BRA

nearlabel

Opcode

(hex)

80

6502

Available on:

65C02

x

65802/816

x 2

# of

Bytes

# of

Cycles

3

1

1 Add 1 cycle if branch crosses page boundary on 65C02 or in 65816/65802’s 6502 emulation mode (e = 1)

337

The Western Design Center

Software Break BRK

Force a software interrupt. BRK is unaffected by the i interrupt disable flag.

Although BRK is a one-byte instruction, the program counter (which is pushed onto the stack by the instruction) is incremented by two; this lets you follow the break instruction with a one-byte signature byte indicating which break caused the interrupt. Even if a signature byte is not needed, either the byte following the

BRK instruction must be padded with some value or the break-handling routine must decrement the return address on the stack to let an RTI (return from interrupt) instruction executed correctly.

6502, 65C02, and Emulation Mode (e = 1): The program counter is incremented by two, then pushed onto the stack; the status register, with the b break flag set, is pushed onto the stack; the interrupt disable flag is set; and the program counter is loaded from the interrupt vector at $FFFE-FFFF. It is up to the interrupt handling routine at this address to check the b flag in the stacked status register to determine if the interrupt was caused by a software interrupt (BRK) or by a hardware IRQ, which shares BRK vector but pushes the status register onto the stack with the b break flag clear. For example,

0000 68

0001 48

0002 2910

0004 D007

PLA

PHA

AND

BNE

#$10

ISBRK copy status from top of stack check BRK bit branch if set

Fragment 18.1

65802/65816 Native Mode (e = 0): The program counter bank register is pushed onto the stack; the program counter is incremented by two and pushed onto the stack; the status register is pushed onto the stack; the interrupt disable flag is set; the program bank register is cleared to zero; and the program counter is loaded from the break vector at $00FFE6-00FFE7.

6502: The d decimal flag is not modified after a break is executed.

65C02 and 65816/65802: The d decimal flag is reset to 0 after a break is executed.

338

The Western Design Center

Stack Pointer

Stack

Bank Address

Address High

Address Low

Contents of

Status Register

Bank 0

Figure 18-3 65802/65816 Stack After BRK

Flags Affected: - - - b - i - -

- - - b d i - -

(6502)

(65C02, 65802/65816 emulation mode e = 1)

- - - - d i - -

(65802/65816 native mode e = 0) b b in the P register value pushed onto the stack is set.

d d is reset to 0, for binary arithmetic.

i The interrupt disable flag is set, disabling hardware IRQ interrupts.

Codes:

Opcode Available on: # of # of

Addressing

Syntax (hex) 6502 65C02 65802/816 Bytes Cycles

Mode

Stack/Interrupt

BRK

00 x x x 2* 7

1

* BRK is 1 byte, but program counter value pushed onto stack is incremented by 2 allowing for optional signature byte.

1 Add 1 cycle for 65802/65816 native mode (e = 0)

339

The Western Design Center

Branch Always Long BRL

A branch is always taken, similar to the BRA instruction. However, BRL is a three-byte instruction; the two bytes immediately following the opcode form a sixteen-bit signed displacement from the program counter. Once the branch address has been calculated, the result is loaded into the program counter, transferring control to that location.

The allowable range of the displacement is anywhere within the current 64K program bank.

The long branch provides an unconditional transfer of control similar to the JMP instruction, with one major advantage: the branch instruction is relocatable while jump instructions are not. However, the (nonrelocatable) jump absolute instruction executes one cycle faster.

Flags Affected: - - - - - - - -

Codes:

Addressing Mode

Program Counter

Relative Long

Syntax

BRL label

Opcode Available on: # of # of

(hex) 6502 65C02 65802/816 Bytes Cycles

82 x 3 4

340

The Western Design Center

Branch if Overflow Clear BVC

The overflow flag in the P status register is tested. If it is clear, a branch is taken; if it is set, the instruction immediately following the two-byte BVC instruction is executed.

If the branch is taken, a one-byte signed displacement, fetched from the second byte of the instruction, is sign-extended to sixteen bits and added to the program counter. Once the branch address has been calculated, the result is loaded into the program counter, transferring control to that location.

The allowable range of the displacement is – 128 to + 127 (from the instruction immediately following the branch).

The overflow flag is altered by only four instructions on the 6502 and 65C02 – addition, subtraction, the

CLV clear-the-flag instruction, and the BIT bit-testing instruction. In addition, all the flags are restored from the stack by the PLP and RTI instructions. On the 65802/65816, however, the SEP and REP instructions can also modify the v flag.

BVC is used almost exclusively to check that a two’s-complement arithmetic calculation has not overflowed, much as the carry is used to determine if an unsigned arithmetic calculation has overflowed. (Note, however, that the compare instructions do not affect the overflow flag.) You can also use BVC to test the second – highest bit in a value by using it after the BIT instruction, which moves the second – highest bit of the tested value into the v flag.

The overflow flag can also be set by the Set Overflow hardware signal on the 6502, 65C02, and 65802; on many systems, however, there is no connection to this pin.

Flags Affected:

Codes:

- - - - - - - -

Addressing Mode Syntax

Opcode Available on: # of # of

(hex) 6502 65C02 65802/816 Bytes Cycles

Program Counter

BVC

50 x x x 2 2

1,2

Relative

nearlabel

1 Add 1 cycle if branch is taken

2 Add 1 more cycle if branch taken crosses page boundary on 6502, 65C02, or 65816/65802’s 6502 emulation mode (e = 1)

341

The Western Design Center

Branch if Overflow Set BVS

The overflow flag in the P status register is tested. If it is set, a branch is taken; if it is clear, the instruction immediately following the two-byte BVS instruction is executed.

If the branch is taken, a one-byte signed displacement, fetched from the second byte of the instruction, is sign-extended to sixteen bits and added to the program counter. Once the branch address has been calculated, the result is loaded into the program counter, transferring control to that location.

The allowable range of the displacement is – 128 to + 127 (from the instruction immediately following the branch).

The overflow flag is altered by only four instructions on the 6502 and 65C02 – addition, subtraction, the

CLV clear-the-flag instruction and the BIT bit-testing instructions. In addition, all the flags are restored from the stack by the PLP and RTI instruction. On the 65802/65816, the SEP and REP instructions can also modify the v flag.

BVS is used almost exclusively to determine if a two’s-complement arithmetic calculation has overflowed, much as the carry is used to determine if an unsigned arithmetic calculation has overflowed. (Note, however, that the compare instructions do not affect the overflow flag.) You can also use BVS to test the second-highest bit in a value by using it after the BLT instruction, which moves the second-highest bit of the tested value into the v flag.

The overflow flag can also be set by the Set Overflow hardware signal on the 6502, 65C02, and 65802; on many systems, however, there is no hardware connection to this signal.

Flags Affected:

Codes:

- - - - - - - -

Addressing Mode Syntax

Opcode

(hex) 6502

Available on:

65C02 65802/816

# of

Bytes

# of

Cycle s

Program Counter

Relative

BVS

nearlabel

70 x x x 2 2

1,2

1

1

Add 1 cycle if branch is taken

2 Add 1 more cycle if branch taken crosses page boundary on 6502, 65C02, or 65816/65802’s 6502 emulation mode (e = 1)

342

The Western Design Center

Clear Carry Flag CLC

Clear the carry flag in the status register.

CLC is used prior to addition (using the 65x’s ADC instruction) to keep the carry flag from affecting the result; prior to a BCC (branch on carry clear) instruction on the 6502 to force a branch-always; and prior to an XCE (exchange carry flag with emulation bit) instruction to put the 65802 or 65816 into native mode

.

Flags Affected: - - - - - - - c

c carry flag cleared always.

Codes:

Addressing

Mode

Implied

Syntax

CLC

Opcode Available on:

(hex) 6502 65C02 65802/816

18 x x x 1

# of

Bytes

2

# of

Cycles

343

The Western Design Center

Clear Decimal Mode Flag CLD

Clear the decimal mode flag in the status register.

CLD is used to shift 65x processors back into binary mode from decimal mode, so that the ADC and

SBC instructions will correctly operate on binary rather than BCD data.

Flags Affected: - - - - d - - -

d decimal mode flag cleared always.

Codes:

Addressing

Mode

Implied

Opcode Available on:

Syntax (hex) 6502 65C02 65802/816

CLD

D8 x x x

# of

Bytes

1

# of

Cycles

2

344

The Western Design Center

Clear Interrupt Disable Flag CLI

Clear the interrupt disable flag in the status register.

CLI is used to re-enable hardware interrupt (IRQ) processing. (When the i bit is set, hardware interrupts are ignored.) The processor itself sets the i flag when it begins servicing an interrupt, so interrupt handling routines must re-enable interrupts with CLI if the interrupt-service routine is designed to service interrupts that occur while a previous interrupt is still being handled; otherwise, the RTI instruction will restore a clear i flag from the stack, and CLI is not necessary. CLI is also used to re-enable interrupts if they have been disabled during execution of time-critical or other code which cannot be interrupted

.

Flags Affected: - - - - - i - -

i interrupt disable flag cleared always.

Codes:

Addressing

Mode

Implied

Opcode Available on:

Syntax (hex) 6502 65C02 65802/816

CLI

58 x x x

# of

Bytes

1

# of

Cycles

2

345

The Western Design Center

Clear Overflow Flag

- v - - - - - -

v overflow flag cleared always.

CLV

Clear the overflow flag in the status register.

CLV is sometimes used prior to a BVC (branch on overflow clear) to force a branch-always on the

6502. Unlike the other clear flag instructions, there is no complementary “set flag” instruction to set the overflow flag, although the overflow flag can be set by hardware via the Set Overflow input pin on the processor. This signal, however, is often unconnected. The 65802/65816 REP instruction can, of course, clear the overflow flag; on the 6502 and 65C02, a BIT instruction with a mask in memory that has bit 6 set can be used to set the overflow flag.

Flags Affected:

Codes:

Addressing

Mode

Implied

Syntax

CLV

Opcode Available on: # of

(hex) 6502 65C02 65802/816 Bytes

B8 x x x 1

# of

Cycles

2

346

The Western Design Center

Compare Accumulator with Memory CMP

Subtract the data located at the effective address specified by the operand from the contents of the accumulator, setting the carry, zero, and negative flags based on the result, but without altering the contents of either the memory location or the accumulator. That is, the result is not saved. The comparison is of unsigned binary values only.

The CMP instruction differs from the SBC instruction in several ways. First, the result is not saved.

Second, the value in the carry prior to the operation is irrelevant to the operation; that is, the carry does not have to be set prior to a compare as it is with 65x subtractions. Third, the compare instruction does not set the overflow flag, so it cannot be used for signed comparisons. Although decimal mode does not affect the CMP instruction, decimal comparisons are effective, since the equivalent binary values maintain the same magnitude relationships as the decimal values have, for example, $99 > $04 just as 99 > 4.

The primary use for the compare instruction is to set the flags so that a conditional branch can then be executed.

8-bit accumulator (all processors): Data compared is eight-bit.

16-bit accumulator (65802/65816 only, m = 0): Data compared is sixteen-bit: the low-order eight bits of the data in memory are located at the effective address; the high-order eight bits are located at the effective address plus one.

Flags Affective: n — — — — — z c

n Set if most significant bit of result is set; else cleared.

z Set if result is zero; else cleared.

c Set if no borrow required (accumulator value higher or same);

cleared if borrow required (accumulator value lower).

347

The Western Design Center

Codes:

Addressing Mode + +

Immediate

Absolute

Absolute Long

Direct Page (also DP)

DP Indirect

DP Indirect Long

Absolute Indexed, X

Syntax

CMP

#const

CMP addr

CMP long

CMP dp

CMP (dp)

CMP [dp]

CMP addr,

X

CMP long,

Absolute Long Indexed,

X

Absolute Indexed, Y

DP Indexed, X

DP Indexed Indirect, X

X

CMP addr,

Y

CMP dp, X

CMP (dp,

X)

DP Indirect Indexed, Y

DP Indirect Long

Indexed, Y

CMP (dp),

Y

CMP [dp],

Y

Stack Relative (also SR)

CMP sr, S

CMP (sr,

SR Indirect Indexed, Y

S), Y

Opcode

(hex)

C9

CD

CF

C5

D2

C7

DD

DF

D9

D5

C1

D1

D7

C3

D3

6502

x x x x x x x x

Available on:

65C02

x x x x x x x x x

65802/816

x x x x x x x x x x x x x x x

3

4

2

2

2

3

4

3

2

2

2

2

2

2

# of

Bytes

2*

# of

Cycles

2

4

5

3

5

6

4

5

4

4

6

5

6

4

7

1

1

1

1, 2

1, 2

1, 2

1, 3

1

1, 3

1, 2

1, 2

1, 2, 3

1, 2

1

1

+ + CMP, a Primary Group Instruction, has available all of the Primary Group addressing modes and bit patterns

* Add 1 byte if m = 0 (16-bit memory/accumulator)

1

Add 1 cycle if m = 0 (16-bit memory/accumulator)

2

Add 1 cycle if low byte of Direct Page register is other than zero (DL< >0)

3

Add 1 cycle if adding index crosses a page boundary

348

The Western Design Center

Co-Processor Enable COP

Execution of COP causes a software interrupt, similarly to BRK, but through the separate COP vector.

Alternatively, COP may be trapped by a co-processor, such as a floating point or graphics processor, to call a co-processor function. COP is unaffected by the i interrupt disable flag.

COP is much like BRK, with the program counter value pushed on the stack being incremented by two; this lets you follow the co-processor instruction with a signature byte to indicate to the co-processor or coprocessor handling routine which operation to execute. Unlike the BRK instruction, 65816 assemblers require you to follow the COP instruction with such a signature byte. Signature bytes in the range $80-$FF are reserved by the Western Design Center for implementation of co-processor control; signatures in the range $00-

$7F are available for use with software-implemented COP handlers

.

6502 Emulation Mode (65802/65816, e=1): The program counter is incremented by two and pushed onto the stack; the status register is pushed onto the stack; the interrupt disable flag is set; and the program counter is loaded from the emulation mode co-processor vector at $FFF4-FFF5. The d decimal flag is cleared after a COP is executed.

65802/65816 Native Mode (e = 0): The program counter bank register is pushed onto the stack; the program counter is incremented by two and pushed onto the stack; the status register is pushed onto the stack; the interrupt disable flag is set; the program bank register is cleared to zero; and the program counter is loaded from the native mode co-processor vector at $00FFE4-00FFE5. The d decimal flag is reset to 0 after a COP is executed.

Stack

Bank Address

Address High

Address Low

Contents of Status

Register

Stack Pointer

Bank 0

Figure 18-4 Stack after COP

Flag Affected: - - - - d i - -

d d is rest to 0.

i The interrupt disable flag is set, disabling hardware interrupts.

Codes:

Opcode Available on: # of # of

Addressing mode

Syntax (hex) 6502 65C02 65802/816 Bytes Cycles

Stack/Interrupt

COP const

02 x 2* 7

1

*

COP is 1 byte, but program counter value pushed onto stack is incremented by 2 allowing for optional code byte

1 Add 1 cycle for 65816/65802 native mode (e = 0)

349

The Western Design Center

Compare Index Register X with Memory CPX

Subtract the data located at the effective address specified by the operand from the contents of the X register, setting the carry, zero, and negative flags based on the result, but without altering the contents of either the memory location or the register. The result is not saved. The comparison is of unsigned values only (except for signed comparison for equality).

The primary use for the CPX instruction is to test the value of the X index register against loop boundaries, setting the flags so that a conditional branch can be executed.

8-bit index registers (all processors): Data compared is eight-bit.

16-bit index registers (65802/65816 only, x = 0): Data compared is sixteen-bit: the low-order eight bits of the data in memory are located at the effective address; the high-order eight bits are located at the effective address plus one.

Flags Affected: n - - - - - z c

n z c

Set if most significant bit of result is set; else cleared.

Set if result is zero; else cleared.

Set if no borrow required (X register value higher or same); cleared if borrow required (X register value lower).

Codes:

Opcode Available on:

Addressing Mode Syntax

CPX

Immediate

#const

CPX addr Absolute

Direct Page (also

DP)

CPX dp

E0

EC

E4 x x x x x x x x x

2*

3

2

* Add 1 byte if x = 0 (16-bit index registers)

1 Add 1 cycle if x = 0 (16-bit index registers)

2 Add 1 cycle if low byte of Direct Page register is other than zero (DL< >0)

# of

2

4

3

1

1

1, 2

# of

(hex) 6502 65C02 65802/816 Bytes Cycles

350

The Western Design Center

Compare Index Register Y with Memory CPY CPY

Subtract the data located at the effective address specified by the operand from the contents of the Y register, setting the carry, zero, and negative flags based on the result, but without altering the contents of either the memory location or the register. The comparison is of unsigned values only (expect for signed comparison for equality).

The primary use for the CPY instruction is to test the value of the Y index register against loop boundaries, setting the flags so that a conditional branch can be executed.

8-bit index registers (all processors): Data compared is eight-bit.

16-bit index registers (65802/65816 only, x = 0): Data compared is sixteen-bit: the low-order eight bits of the data in memory is located at the effective address; the high-order eight bits are located at the effective address plus one.

Flags Affected: n - - - - - z c

n Set if most significant bit of result is set; else cleared.

z Set if result is zero; else cleared.

c Set if no borrow required (Y register value higher or same);

cleared if borrow required (Y register value lower).

Codes:

Opcode Available on: # of # of

Addressing Mode +

+

Immediate

Absolute

Direct Page (also

DP)

Syntax

CPY # const

CPY addr

CPY dp

(hex)

C0

CC

C4

6502

x x x

65C02

x x x

65802/816

x x x

* Add 1 byte if x = 0 (16-bit index registers)

1 Add 1 cycle if x = 0 (16-bit index registers)

2 Add 1 cycle if low byte of Direct Page register is other than zero (DL< >0)

Bytes

2*

3

2

Cycles

3

2

4

1

1

1, 2

351

The Western Design Center

Decrement DEC

Decrement by one the contents of the location specified by the operand (subtract one from the value).

Unlike subtracting a one using the SBC instruction, the decrement instruction is neither affected by nor affected the carry flag. You can test for wraparound only by testing after every decrement to see if the value is zero or negative. On the other hand, you don’t need to set the carry before decrementing.

DEC is unaffected by the setting of the d (decimal) flag.

8-bit accumulator/memory (all processors): Data decremented is eight-bit.

16-bit accumulator/memory (65802/65816 only, m = 0): Data Decremented is sixteen-bit: if in memory, the low-order eight bits are located at the effective address; the high-order eight bits are located at the effective address plus one

.

Flags Affected: n - - - - - z -

n Set if most significant bit of result is set; else cleared.

z Set if result is zero; else cleared.

Codes:

Addressing Mode

Accumulator

Absolute

Direct Page (also

DP)

Absolute Indexed,

X

Syntax

DEC A

DEC addr

DEC dp

DEC addr, X

Opcode Available on: # of # of

(hex) 6502 65C02 65802/816 Bytes Cycles

3A

CE

C6

DE x x x x x x x x x x x

DP Indexed, X

DEC dp, X

D6 x

1 Add 2 cycles if m = 0 (16-bit memory/accumulator) x x

2 Add 1 cycle if low byte of Direct Page register is other than zero (DL<>0)

3 Subtract 1 cycle if 65C02 and no page boundary crossed

1

3

2

3

2

5

7

6

6

2

1

1, 2

1, 3

1,2

352

The Western Design Center

Decrement Index Register X DEX

Decrement by one the contents of index register X (subtract one from the value). This is a special purpose, implied addressing form of the DEC instruction.

Unlike using SBC to subtract a one from the value, the DEX instruction does not affect the carry flag; you can test for wraparound only by testing after every decrement to see if the value is zero or negative. On the other hand, you don’t need to set carry before decrementing.

DEX is unaffected by the setting of the d (decimal) flag.

8-bit index registers (all processors): Data decremented is eight-bit.

16-bit index registers (65802/65816 only, x = 0): Data decremented is sixteen-bit.

Flags Affected: n - - - - - z -

n Set if most significant bit of result is set; else cleared.

z Set if result is zero; else cleared.

Codes:

Addressing

Mode

Implied

Syntax

DEX

Opcode Available on: # of # of

(hex) 6502 65C02 65802/816 Bytes Cycles

CA x x x 1 2

353

The Western Design Center

Decrement Index Register Y DEY

Decrement by one the contents of index register Y (subtract one from the value). This is a special purpose, implied addressing form of the DEC instruction.

Unlike using SBC to subtract a one from the value, the DEY instruction does not affect the carry flag; you can test for wraparound only by testing after every decrement to see if the value is zero or negative. On the other hand, you don’t need to set the carry before decrementing.

DEY is unaffected by the setting of the d (decimal) flag.

8-bit index registers (all processors): Data decremented is eight-bit.

16-bit index registers (65802/65816 only, x = 0): Data decremented is sixteen-bit.

Flags Affected: n - - - - - z -

n Set if most significant bit of result is set; else cleared.

z Set if result is zero; else clear.

Codes:

Addressing

Mode

Implied

Syntax

DEY

Opcode Available on: # of # of

(hex) 6502 65C02 65802/816 Bytes Cycles

88 x x x 1 2

354

The Western Design Center

Exclusive-OR Accumulator with Memory EOR

Bitwise logical Exclusive-OR the data located at the effective address specified by the operand with the contents of the accumulator. Each bit in the accumulator is exclusive-ORed with the corresponding bit in memory, and the result is stored into the same accumulator bit.

The truth table for the logical exclusive-OR operation is:

First Operand

0

1

Second Operand

0 1

0

1

1

0

Figure 18-5Exclusive OR Truth Table

A 1 or logical true results only if the two elements of the Exclusive-OR operation are different.

8-bit accumulator (all processors): Data exclusive-ORed from memory is eight-bit.

16-bit accumulator (65802/65816 only, m = 0): Data exclusive-ORed from memory is sixteen-bit: the low-order eight bits are located at the effective address; the high-order eight bits are located at the effective address plus one.

Flags Affected: n - - - - - z -

n Set if most significant bit of result is set; else cleared.

z Set if result is zero; else cleared.

355

The Western Design Center

Codes:

Addressing Mode Syntax

Opcode

(hex) 6502

Available on:

65C02 65802/816

Immediate

Absolute

Absolute Long

Direct Page (also DP)

DP Indirect

DP Indirect Long

Absolute Indexed, X

Absolute Long Indexed,

X

EOR # const

EOR addr

EOR long

EOR dp

EOR (dp)

EOR [dp]

EOR addr, X

EOR long, X

49

4D

4F

45

52

47

5D

5F x x x x x x x x x x x x x x x x x

Absolute Indexed, Y

DP Indexed, X

EOR addr, Y

EOR dp, X

59

55 x x x x x x

DP Indexed Indirect, X

EOR (dp, X)

DP Indirect Indexed, Y

EOR (dp), Y

DP Indirect Long

Indexed, Y

EOR [dp], Y

Stack Relative (also SR)

EOR sr, S

41

51

57 x x x x x x x

43 x

EOR (sr, S),

SR Indirect Indexed, Y 53 x

Y

+ + EOR, a Primary Group Instruction, has available all of the Primary Group addressing modes and bit patterns

* Add 1 byte if m = 0 (16-bit memory/accumulator)

1 Add 1 cycle if m = 0 (16-bit memory/accumulator)

2 Add 1 cycle if low byte of Direct Page register is other than zero (DL<>0)

3 Add 1 cycle if adding index crosses a page boundary

3

2

2

2

3

4

2

2

2

3

# of # of

Byte s

2*

Cycle s

2

1

4

1

5

1

3

1, 2

5

1, 2

6

1, 2

4

1, 3

4 5

1

4

1, 3

4

1, 2

6

1, 2

5

1, 2, 3

2

2

2

6

1, 2

4

1

7

1

356

The Western Design Center

Increment INC

Increment by one the contents of the location specified by the operand (add one to the value).

Unlike adding a one with the ADC instruction, however, the increment instruction is neither affected by nor affects the carry flag. You can test for wraparound only by testing after every increment to see if the result is zero or positive. On the other hand, you don’t have to clear the carry before incrementing.

The INC instruction is unaffected by the d (decimal) flag.

8-bit accumulator/memory (all processors): Data incremented is eight-bit.

16-bit accumulator/memory (65802/65816 only, m=0): Data incremented is sixteen-bit: if in memory, the low-order eight bits are located at the effective address; the high-order eight-bits are located at the effective address plus one.

Flags Affected: n - - - - - z -

n Set if most significant bit of result is set; else cleared.

z Set if result is zero; else cleared.

Codes:

Addressing Mode Syntax

Accumulator

INC A

Absolute

Direct Page (also

INC addr

INC dp

DP)

Absolute Indexed,

X

DP Indexed, X

INC addr,

X

INC dp, X

Opcode

(hex) 6502 65C02 65802/816 Bytes Cycles

1A

EE

E6

FE x x x

Available on:

x x x x x x x x

F6 x x x

1 Add 2 cycles if m = 0 (16-bit memory/accumulator)

2 Add 1 cycle if low byte of Direct Page register is other than zero (DL<>0)

3 Subtract 1 cycle if 65C02 and no page boundary crossed

# of

1

3

2

3

2

# of

5

7

6

2

6

1

1, 2

1, 3

1, 2

357

The Western Design Center

Increment Index Register X INX

Increment by one the contents of index register X (add one to the value). This is a special purpose, implied addressing form of the INC instruction.

Unlike using ADC to add a one to the value, the INX instruction does not affect the carry flag. You can execute it without first clearing the carry. But you can test for wraparound only by testing after every increment to see if the result is zero or positive. The INX instruction is unaffected by the d (decimal) flag.

8-bit index registers (all processors): Data incremented is eight-bit.

16-bit index registers (65802/65816 only, x = 0): Data incremented is sixteen-bit.

Flags Affected: n - - - - - z -

n Set if most significant bit of result is set; else cleared.

z Set if result is zero; else cleared.

Codes:

Addressing

Mode

Implied

Syntax

INX

Opcode Available on: # of # of

(hex) 6502 65C02 65802/816 Bytes Cycles

E8 x x x 1 2

358

The Western Design Center

Increment Index Register Y INY

Increment by one the contents of index register Y (add one to the value). This is a special purpose, implied addressing form of the INC instruction.

Unlike using ADC to add one to the value, the INY instruction does not affect the carry flag. You can execute it without first clearing the carry. But you can test for wraparound only by testing after every increment to see if the value is zero or positive. The INY instruction is unaffected by the d (decimal) flag.

8-bit index registers (all processors): Data incremented is eight-bit.

16-bit index registers (65802/65816 only, x = 0): Data incremented is sixteen-bit.

Flags Affected: n - - - - - z -

n Set if most significant bit of result is set; else cleared.

z Set if result is zero; else cleared.

Codes:

Addressing

Mode

Implied

Syntax

INY

Opcode Available on: # of # of

(hex) 6502 65C02 65802/816 Bytes Cycles

C8 x x x 1 2

359

The Western Design Center

Jump JMP

Transfer control to the address specified by the operand field.

The program counter is loaded with the target address. If a long JMP is executed, the program counter bank is loaded from the third byte of the target address specified by the operand.

Flags Affected:

Codes:

- - - - - - - -

Opcode Available on: # of # of

Addressing Mode +

+

Absolute

Absolute Indirect

Syntax

JMP addr

JMP (addr)

(or JML

[addr])

(hex)

4C

6C

Absolute Indexed

Indirect

Absolute Long

JMP (addr,

X)

JMP long

7C

5C

Absolute Indirect

(or JML long)

JMP [addr]

DC

Long

6502

x x

65C02

x x x

65802/816

x x x x x

Bytes

3

3

3

4

3

Cycles

3

5

6

4

6

1, 2

1

1

Add 1 cycle if 65C02

2 6502: If low byte of addr is $FF (i.e., addr is $xxFF): yields incorrect result

360

The Western Design Center

Jump to Subroutine Long (Inter-Bank) JSL

Jump-to-subroutine with long (24-bit) addressing: transfer control to the subroutine at the 24-bit address which is the operand, after first pushing a 24-bit (long) return address onto the stack. This return address is the address of the last instruction byte (the fourth instruction byte, or the third operand byte), not the address of the next instruction; it is the return address minus one.

The current program counter bank is pushed onto the stack first, then the high-order byte of the return address and then the low-order byte of the address are pushed on the stack in standard 65x order (low byte in the lowest address, bank byte in the highest address). The stack pointer is adjusted after each byte is pushed to point to the next lower byte (the next available stack location). The program counter bank register and program counter are then loaded with the operand values, and control is transferred to the specified location.

Flags Affected: - - - - - - - -

Codes:

Addressing

Mode

Syntax

Absolute Long

JSL long

(or JSR

long)

Opcode

(hex)

22

6502

Available on: # of # of

65C02 65802/816 Bytes Cycles

x 4 8

361

The Western Design Center

Jump to Subroutine JSR

Transfer control to the subroutine at the location specified by the operand, after first pushing onto the stack, as a return address, the current program counter value, that is, the address of the last instruction byte (the third byte of a three-byte instruction, the fourth byte of a four-byte instruction), not the address of the next instruction.

If an absolute operand is coded and is less than or equal to $FFFF, absolute addressing is assumed by the assembler; if the value is greater than $FFFF, absolute long addressing is used.

If long addressing is used, the current program counter bank is pushed onto the stack first. Next – or first in the more normal case of intra-bank addressing – the high order byte of the return address is pushed, followed by the low order byte. This leaves it on the stack in standard 65x order (lowest byte at the lowest address, highest byte at the highest address). After the return address is pushed, the stack pointer points to the next available location (next lower byte) on the stack. Finally, the program counter (and, in the case of long addressing, the program counter bank register) is loaded with the values specified by the operand, and control is transferred to the target location.

Flags Affected:

Codes:

- - - - - - - -

Addressing Mode

Absolute

Syntax

JSR addr

Absolute Indexed

Indirect

Absolute Long

JSR (addr,

X)

JSR long

(or JSL long)

Opcode Available on: # of # of

(hex) 6502 65C02 65802/816 Bytes Cycles

20 x x x 3 6

FC

22 x x

3

4

8

8

362

The Western Design Center

Load Accumulator from Memory LDA

Load the accumulator with the data located at the effective address specified by the operand.

8-bit accumulator (all processors): Data is eight-bit

16-bit accumulator (65802/65816 only, m = 0): Data is sixteen-bit; the low-order eight bits are located at the effective address; the high-order eight bits are located at the effective address plus one.

Flags Affected: n - - - - - z -

n Set if most significant bit of loaded value is set; else cleared.

z Set if value loaded is zero; else cleared.

Codes:

Addressing Mode + +

Immediate

Absolute

Absolute Long

Direct Page (DP)

DP Indirect

DP Indirect Long

Absolute Indexed, X

Absolute Long Indexed,

X

Absolute Indexed, Y

Syntax

LDA #

const

LDA addr

LDA long

LDA dp

LDA (dp)

LDA [dp]

LDA addr,

X

LDA long,

X

LDA addr,

Y

LDA dp, X

Opcode

(hex)

A9

AD

AF

A5

B2

A7

BD

BF

B9

6502

x x x x x

Available on:

65C02

x x x x x x

65802/816

x x x x x x x x x

DP Indexed, X B5 x x x

DP Indexed Indirect, X

LDA (dp,

X)

LDA (dp),

A1 x x x

DP Indirect Indexed, Y B1 x x x

DP Indirect Long

Indexed, Y

Y

LDA [dp],

Y

B7 x

Stack Relative (also SR)

LDA sr, S

LDA (sr,

SR Indirect Indexed, Y

S), Y

A3

B3 x x

+ + LDA, a Primary Group Instruction, has available all of the Primary Group addressing modes and bit patterns

* Add 1 byte if m = 0 (16-bit memory/accumulator)

1 Add 1 cycle if m = 0 (16-bit memory/accumulator)

2 Add 1 cycle if low byte of Direct Page register is other than zero (DL< >0)

3 Add 1 cycle if adding index crosses a page boundary

# of

Bytes

2*

3

4

2

2

2

3

4

3

2

2

2

2

2

2

# of

Cycles

5

4

4

4

6

6

2

4

5

1

1

5

1

3

1, 2

5

1, 2

6

1, 2

1, 3

1

1, 3

1, 2

1, 2

1, 2, 3

4

7

1, 2

1

1

363

The Western Design Center

Load Index Register X from Memory LDX

Load index register X with the data located at the effective address specific by the operand.

8-bit index registers (all processors): Data is eight-bit.

16-bit index registers (65802/65816 only, x = 0): Data is sixteen-bit: the low-order eight bits are located at the effective address; the high-order eight bits are located at the effective address plus one.

Flags Affected: n - - - - - z n z

Set if most significant bit of loaded value is set; else cleared.

Set if value loaded is zero; else cleared.

Codes:

Addressing Mode Syntax

LDX #

Immediate

const

LDX addr

Absolute

Direct Page (also

DP)

LDX dp

Absolute Indexed,

Y

DP Indexed, Y

LDX addr,

Y

LDX dp, Y

Opcode

(hex)

A2

AE

A6

BE

6502

x x x x

Available on:

65C02

x x x x

65802/816

x x x x

B6 x x x

* Add 1 byte if x = 0 (16-bit index registers)

1 Add 1 cycle if x = 0 (16-bit index registers)

2 Add 1 cycle if low byte of Direct Page register is other than zero (DL< >0)

3 Add 1 cycle if adding index crosses a page boundary

# of

Bytes

2*

3

2

3

2

# of

Cycles

3

4

4

2

4

1

1

1, 2

1, 3

1, 2

364

The Western Design Center

Load Index Register Y from Memory LDY

Load index register Y with the data located at the effective address specified by the operand.

8-bit index registers (all processors): Data is eight-bit.

16-bit index registers (65802/65816 only, x = 0): Data is sixteen-bit: the low-order eight bits are located at the effective address; the high-order eight bits are located at the effective address plus one.

Flags Affected: n - - - - - z -

n Set if most significant bit of loaded value is set; else cleared.

z Set if value loaded is zero; else cleared.

Codes:

Addressing Mode Syntax

Opcode

(hex) 6502

Available on: # of # of

65C02 65802/816 Bytes Cycles

Immediate

LDY #

const

A0

Absolute

Direct Page (also

LDY addr

AC

LDY dp

A4

DP)

Absolute Indexed,

LDY addr,

X

BC

X

DP Indexed, X

LDY dp, X

B4

* Add 1 byte if x = 0 (16-bit index registers) x x x x x x x x x x x x x x x

1 Add 1 cycle if x = 0 (16-bit index registers)

2 Add 1 cycle if low byte of Direct Page register is other than zero (DL< >0)

3 Add 1 cycle if adding index crosses a page boundary

2*

3

2

3

2

3

4

4

2

4

1

1

1, 2

1, 3

1,2

365

The Western Design Center

Logical Shift Memory or Accumulator Right LSR

Logical shift the contents of the location specified by the operand right one bit. That is, bit zero takes on the value originally found in bit one, bit one takes the value originally found in bit two, and so on; the leftmost bit (bit 7 if the m memory select flag is one when the instruction is executed or bit 15 if it is zero) is cleared; the rightmost bit, bit zero, is transferred to the carry flag. This is the arithmetic equivalent of unsigned division by two.

0 1 0 1 1 0 0 1 1

X

Carry Flag

Figure 18-6 LSR

8-bit accumulator/memory (all processors): Data shifted is eight-bit.

16-bit accumulator/memory (65802/65816 only, m = 0): Data shifted is sixteen-bit: if in memory, the low-order eight bits are located at the effective address; the high-order eight bits are located at the effective address plus one.

Flags Affected: n - - - - - z c n Cleared.

z Set if result is zero; else cleared.

c Low bit becomes carry: set if low bit was set; cleared if low bit was zero.

Codes:

Addressing Mode Syntax

Opcode

(hex)

650

2

Available on:

65C0

2

65802/8

16

Accumulator

Absolute

Direct Page (also

DP)

Absolute Indexed,

X

LSR A

LSR addr

LSR dp

LSR addr,

X

4A

4E

46

5E x x x x

DP Indexed, X

LSR dp, X

56 x

1 Add 2 cycles if m = 0 (16-bit memory/accumulator) x x x x x x x x x x

1

3

2

3

2

2 Add 1 cycle if low byte of Direct Page register is other than zero (DL< >0)

3 Subtract 1 cycle if 65C02 and no page boundary crossed

# of

Bytes

2

6

5

7

6

1

# of

Cycles

1, 2

1, 3

1, 2

366

The Western Design Center

Block Move Next MVN

Moves (copies) a block of memory to a new location. The source, destination and length operands of this instruction are taken from the X, Y, and C (double accumulator) registers; these should be loaded with the correct values before executing the MVN instruction.

The source address for MVN, taken from the X register, should be the starting address (lowest in memory) of the block to be moved. The destination address, in the Y register, should be the new starting address for the moved block. The length, loaded into the double accumulator (the value in C is always used, regardless of the setting of the m flag) should be the length of the block to be moved minus one; if C contains

$0005, six bytes will be moved. The two operand bytes of the MVN instruction specify the banks holding the two blocks of memory: the first operand byte (of object code) specifies the destination bank; the second operand byte specifies the source bank.

The execution sequence is: the first byte is moved from the address in X to the address in Y; then X and

Y are incremented, C is decremented, and the next byte is moved; this process continues until the number of bytes specified by the value in C plus one is moved. In other words, until the value in C is $FFFF.

If the source and destination blocks do not overlap, then the source block remains intact after it has been copied to the destination.

If the source and destination blocks do overlap, then MVN should be used only if the destination is

lower than the source to avoid overwriting source bytes before they’ve been copied to the destination. If the destination is higher, then the MVP instruction should be used instead.

When execution is complete, the value in C is $FFFF, registers X and Y each point one byte past the end of the blocks to which they were pointing, and the data bank register holds the destination bank value (the first operand byte).

Assembler syntax for the block move instruction calls for the operand field to be coded as two addresses, source first, then destination – the move intuitive ordering, but the opposite of the actual operand order in the object code. The assembler strips the bank bytes from the addresses (ignoring the rest) and reverses them to object code order. If a block move instruction is interrupted, it may be resumed automatically via execution of an RTI if all of the registers are restored or intact. The value pushed onto the stack when a block move is interrupted is the address of the block move instruction. The current byte-move is completed before the interrupt is serviced.

If the index registers are in eight-bit mode (x = 1), or the processor is in 6502 emulation mode (e = 1), then the blocks being specified must necessarily be in page zero since the high bytes of the index registers will contain zeroes.

Flags Affected: - - - - - - - -

Codes:

Addressing

Mode

Syntax

Block Move

MVN

srcbk,destbk

* 7 cycles per bye moved

Opcode Available on: # of

(hex) 6502 65C02 65802/816 Bytes

54 x 3

# of

Cycles

*

367

The Western Design Center

Block Move Previous

MVP

Moves (copies) a block of memory to a new location. The source, destination and length operands of this instruction are taken from the X, Y, and C (double accumulator) registers; these should be loaded with the correct values before executing the MVP instruction.

The source address for MVP, taken from the X register, should be the ending address (highest in memory) of the block to be moved. The destination address, in the Y register, should be the new ending address for the moved block. The length, loaded into the double accumulator (the value in C is always used, regardless of the setting of the m flag) should be the length of the block to be moved minus one; if C contains $0005, six bytes will be moved. The two operand bytes of the MVP instruction specify the banks holding the two blocks of memory: the first operand byte (of object code) specifies the destination bank; the second operand byte specifies the source bank.

The execution sequence is: the first byte is moved from the address in X to the address in Y; then X and

Y are decremented, C is decremented, and the previous byte is moved; this process continues until the number of bytes specified by the value in C plus one is moved. In other words, until the value in C is $FFFF.

If the source and destination blocks do not overlap, then the source block remains intact after it has been copied to the destination

.

If the index registers are in eight-bit mode (x = 1), or the processor is in 6502 emulation mode

(e = 1), then the blocks

If the source and destination blocks do overlap, then MVP should be used only if the destination is higher than the source to avoid overwriting source bytes before they’ve been copied to the destination. If the destination is lower, then the MVN instruction should be used instead.

When execution is complete, the value in C is $FFFF, registers X and Y each point one byte past the beginning of the blocks to which they were pointing, and the data bank register holds the destination bank value (the first operand byte).

Assembler syntax for the block move instruction calls for the operand field to be coded as two addresses, source first, then destination – the more intuitive ordering, but the opposite of the actual operand order in the object code. The assembler strips the bank bytes from the addresses (ignoring the rest) and reverses them to object code order. If a block move instruction is interrupted, it may be resumed automatically via execution of an RTI if all of the registers are restored or intact. The value pushed onto the stack when a block move is interrupted is the address of the block move instruction. The current byte-move is completed before the interrupt is serviced.

being specified must necessarily be in page zero since the high bytes of the index registers will contain zeroes.

Flags Affected: - - - - - - - -

Codes:

Addressing

Mode

Syntax

Block Move

MVP

srcbk,destbk

* 7 cycles per byte moved

Opcode Available on: # of

(hex) 6502 65C02 65802/816 Bytes

44 x 3

# of

Cycles

*

368

The Western Design Center

No Operation NOP

Executing a NOP takes no action; it has no effect on any 65x registers or memory, except the program counter, which is incremented once to point to the next instruction.

Its primary uses are during debugging, where it is used to “patch out” unwanted code, or as a placeholder, included in the assembler source, where you anticipate you may have to “patch in” instructions, and want to leave a “hole” for the patch.

NOP may also be used to expand timing loops – each NOP instruction takes two cycles to execute, so adding one or more may help fine tune a timing loop.

Flags Affected:

Codes:

- - - - - - - -

Addressing

Mode

Implied

Opcode Available on: # of

Syntax (hex) 6502 65C02 65802/816 Bytes

NOP

EA x x x 1

# of

Cycles

2

369

The Western Design Center

OR Accumulator with Memory

ORA

Bitwise logical OR the data located at the effective address specified by the operand with the contents of the accumulator. Each bit in the accumulator is ORed with the corresponding bit in memory. The result is stored into the same accumulator bit.

The truth table for the logical OR operation is:

Second Operand

0 1

First Operand

0

1

0

1

1

1

Figure 18-7 Logical OR Truth Table

16-bit accumulator (65802/65816 only, m=0): Data ORed from memory is sixteen-bit: the low-order eight bits are located at the effective address; the high-order eight bits are located at the effective address plus one.

A 1 or logical true results if either of the two operands of the OR operation is true.

8-bit accumulator (all processors): Data ORed from memory is eight-bit.

Flags Affected: n - - - - - z n Set if most significant bit of result is set; else cleared.

z Set if result is zero; else cleared.

370

The Western Design Center

Codes:

Addressing Mode

+ +

Syntax

ORA #

Opcode

(hex) 6502

Available on:

65C02 65802/816

Immediate

Absolute

Absolute Long

Direct Page (also DP)

DP Indirect

09 x x x

const

ORA addr

ORA long

ORA dp

ORA (dp)

0D

0F

05

12

07 x x x x x x x x x x DP Indirect Long

ORA [dp]

ORA addr,

Absolute Indexed, X

Absolute Long Indexed,

X

X

ORA long,

X

ORA,

Absolute Indexed, Y

addr, Y

ORA, dp,

DP Indexed, X

X

ORA (dp,

DP Indexed Indirect, X

X)

ORA, (dp),

DP Indirect Indexed, Y

DP Indirect Long

Indexed, Y

Y

ORA [dp],

Y

Stack Relative (also SR)

ORA sr, S

1D

1F

19

15

01

11

17 x x x x x x x x x x x x x x x x x

03 x

SR Indirect Indexed, Y

ORA (sr,

S), Y

13 x

+ + ORA, a Primary Group Instruction, has available all of the Primary Group addressing modes and bit patterns

* Add 1 byte if m = 0 (16-bit memory/accumulator)

1 Add 1 cycle if m = 0 (16-bit memory/accumulator)

2 Add 1 cycle if low byte of Direct Page register is other than zero (DL< >0)

3 Add 1 cycle if adding index crosses a page boundary

# of

Bytes

2*

3

4

2

2

2

3

4

3

2

2

2

2

2

2

# of

Cycles

5

3

5

6

4

4

4

6

6

2

4

5

5

1

1

1

1, 2

1, 2

1, 2

1, 3

1

1, 3

1, 2

1, 2

1, 2, 3

4

7

1, 2

1

1

371

The Western Design Center

Push Effective Absolute Address PEA

Push the sixteen-bit operand (typically an absolute address) onto the stack. The stack pointer is decremented twice. This operation always pushes sixteen bits of data, irrespective of the settings of the m and x mode select flags.

Although the mnemonic suggests that the sixteen-bit value pushed on the stack be considered an address, the instruction may also be considered a “push sixteen-bit immediate data” instruction, although the syntax of immediate addressing is not used. The assembler syntax is that of the absolute addressing mode, that is, a label or sixteen-bit value in the operand field. Unlike all other instructions that use this assembler syntax, the effective address itself, rather than the data stored at the effective address, is what is accessed (and in this case, pushed onto the stack).

Flags Affected: - - - - - - - -

Codes:

Addressing

Mode

Stack

(Absolute)

Syntax

PEA addr

Opcode Available on: # of # of

(hex) 6502 65C02 65802/816 Bytes Cycles

F4 x 3 5

372

The Western Design Center

Push Effective Indirect Address PEI

Push the sixteen-bit value located at the address formed by adding the direct page offset specified by the operand to the data page register. The mnemonic implies that the sixteen-bit data pushed is considered an address, although it can be any sixteen-bit data. This operation always pushes sixteen bits of data, irrespective of the settings of the m and x mode select flags.

The first byte pushed is the byte at the direct page offset plus one (the high byte of the double byte stored at the direct page offset). The byte at the direct page offset itself (the low byte) is pushed next. The stack pointer now points to the next available stack location, directly below the last byte pushed.

The assembler syntax is that of direct page indirect; however, unlike other instructions which use this assembler syntax, the effective indirect address, rather than the data stored at that address, is what is accessed and pushed onto the stack.

Flags Affected:

Codes:

- - - - - - - -

Addressing Mode

Opcode Available on:

65802/81

Syntax (hex) 6502 65C02

6

Stack (Direct Page

Indirect)

PEI

(dp)

D4 x

1 Add 1 cycle if low byte of Direct Page register is other than zero (DL< >0)

# of

2

# of

Bytes Cycles

6

1

373

The Western Design Center

Push Effective PC Relative Indirect Address PER

Add the current value of the program counter to the sixteen-bit signed displacement in the operand, and push the result on the stack. This operation always pushes sixteen bits of data, irrespective of the settings of the

m and x mode select flags.

The high byte of the sum is pushed first, then the low byte is pushed. After the instruction is completed, the stack pointer points to the next available stack location, immediately below the last by pushed.

Because PER’s operand is a displacement relative to the current value of the program counter (as with the branch instructions), this instruction is helpful in writing self-relocatable code in which an address within the program (typically of a data area) must be accessed. The address pushed onto the stack will be the run-time address of the data area, regardless of where the program was loaded in memory; it may be pulled into a register, stored in an indirect pointer, or used on the stack with the stack relative indirect indexed addressing mode to access the data at that location.

As is the case with the branch instructions, the syntax used is to specify as the operand the label of the data area you want to reference. This location must be in the program bank, since the displacement is relative to the program counter. The assembler converts the assembly-time label into a displacement from the assembly-time address of the next instruction.

The value of the program counter used in the addition is the address of the next instruction, that is, the instruction following the PER instruction.

PER may also be used to push return addresses on the stack, either as part of a simulated branch-tosubroutine or to place the return address beneath the stacked parameters to a subroutine call; always remember that a pushed return address should be the desired return address minus one.

- - - - - - - Flags Affected:

Codes:

Addressing Mode

Stack (Program Counter Relative

Long)

Syntax

PER

label

Opcode Available on: # of # of

(hex) 6502 65C02 65802/816 Bytes Cycle

62 x 3 6

374

The Western Design Center

Push Accumulator PHA

Push the accumulator onto the stack. The accumulator itself is uncharged.

8-bit accumulator (all processors): The single byte contents of the accumulator are pushed –

they are stored to the location pointed to by the stack pointer and the stack pointer is decremented.

16-bit accumulator (65802/65816 only, m = 0): Both accumulator bytes are pushed. The

high byte is pushed first, then the low byte. The stack point now points to the next available stack location, directly below the last byte pushed.

Flags Affected: - - - - - - - -

Codes:

Opcode Available on:

Addressing

Mode

Syntax (hex) 6502

Stack (Push)

PHA

48 x

1 Add 1 cycle if m=0 (16-bit memory/accumulator)

65C02

x

65802/816

x

# of

Bytes

1

# of

Cycles

3

1

375

The Western Design Center

Push Data Bank Register PHB

Push the contents of the data bank register onto the stack.

The single-byte contents of the data bank registers are pushed onto the stack; the stack pointer now points to the next available stack location, directly below the byte pushed. The data bank register itself is unchanged. Since the data bank register is an eight-bit register, only one byte is pushed onto the stack, regardless of the settings of the m and x mode select flags.

While the 65816 always generates 24-bit addresses, most memory references are specified by a sixteenbit address. These addresses are concatenated with the contents of the data bank register to form a full 24-bit address. This instruction lets the current value of the data bank register be saved prior to loading a new value.

Flags Affected:

Codes:

- - - - - - - -

Address

Mode

Syntax

Stack (Push)

PHB

Opcode

(hex)

8B

6502

Available on:

65C02 65802/816

x

# of

Bytes

1

# of

Cycles

3

376

The Western Design Center

Push Direct Page Register PHD

Push the contents of the direct page register D onto the stack.

Since the direct page register is always a sixteen-bit register, this is always a sixteen-bit operation, regardless of the settings of the m and x mode select flags. The high byte of the direct page register is pushed first, then the low byte. The direct page register itself is unchanged. The stack pointer now points to the next available stack location, directly below the last byte pushed.

By pushing the D register onto the stack, the local environment of a calling subroutine may easily be saved a called subroutine before modifying the D register to provide itself with its own direct page memory.

Flags Affected:

Codes:

- - - - - - - -

Address

Mode

Syntax

Stack (Push)

PHD

Opcode Available on: # of # of

(hex) 6502 65C02 65802/816 Bytes Cycles

0B x 1 4

377

The Western Design Center

Push Program Bank Register PHK

Push the program bank register onto the stack.

The single-byte contents of the program bank register are pushed. The program bank register itself is unchanged. The stack pointer now points to the next available stack location, directly below the byte pushed.

Since the program bank register is an eight-bit register, only one byte is pushed onto the stack, regardless of the settings of the m and x mode select flags.

While the 65816 always generates 24-bit addresses, most jumps and branches specify only a sixteen-bit address. These addresses are concatenated with the contents of the program bank register to form a full 24-bit address. This instruction lets you determine the current value of the program bank register – for example, if you want the data bank to be set to the same value as the program bank.

Flags Affected: - - - - - - - -

Codes:

Opcode Available on: # of # of

Address Mode Syntax (hex) 6502 65C02 65802/816 Bytes Cycles

Stack (Push)

PHK

4B x 1 3

378

The Western Design Center

Push Processor Status Register PHP

Push the contents of the processor status register P onto the stack.

Since the status register is always an eight-bit register, this is always an eight-bit operation, regardless of the settings of the m and x mode select flags on the 65802/65816. The status register contents are not changed by the operation. The stack pointer now points to the next available stack location, directly below the byte pushed.

This provides the means for saving either the current mode settings or a particular set of status flags so they may be restored or in some other way used later.

Note, however, that the e bit (the 6502 emulation mode flag on the 65802/65816) is not pushed onto the stack or otherwise accessed or saved. The only access to the e flag is via the XCE instruction.

- - - - - - - Flags Affected:

Codes:

Address Mode

Stack (Push)

Syntax

PHP

Opcode Available on:

(hex) 6502 65C02 65802/816

08 x x x

# of

Bytes

1

# of

Cycles

3

379

The Western Design Center

Push Index Register PHX

Push the contents of the X index register onto the stack. The register itself is unchanged.

8-bit index registers (all processors): The eight-bit contents of the index register are pushed onto the stack. The stack pointer now points to the next available stack location, directly below the byte pushed.

16-bit index registers (65802/65816 only, x=0): The sixteen-bit contents of the index register are pushed. The high byte is pushed first, then the low byte. The stack pointer now points to the next available stack location, directly below the last byte pushed.

Flags Affected:

Codes:

- - - - - - - -

Opcode

Address Mode Syntax

Stack (Push) PHX

1 Add 1 cycle if x=0 (16-bit index registers)

Available on: # of # of

(hex) 6502 65C02 65802/816 Bytes Cycles

DA x x 1 3

1

380

The Western Design Center

Push Index Register PHY

Push the contents of the Y index register onto the stack. The register itself is unchanged.

8-bit index registers (all processors): The eight-bit contents of the index register are pushed onto the stack. The stack pointer now points to the next available stack location, directly below the byte pushed.

16-bit index registers (65802/65816 only, x = 0): The sixteen-bit contents of the index register are pushed. The high byte is pushed first, then the low byte. The stack pointer now points to the next available stack location, directly below the last byte pushed.

Flags Affected: - - - - - - - -

Codes:

Address Mode Syntax

Opcode

(hex)

Stack (Push) PHY 5A

1 Add 1 cycle if x=0 (16-bit index registers)

Available on:

6502 65C02 65802/816

x x

# of # of

Bytes Cycles

1 3

1

381

The Western Design Center

Pull Accumulator PLA

Pull the value on the top of the stack into the accumulator. The previous contents of the accumulator are destroyed.

8-bit accumulator (all processors): The stack pointer is first incremented. Then the byte pointed to by the stack pointer is loaded into the accumulator.

16-bit accumulator (65802/65816 only, m = 0): Both accumulator bytes are pulled. The accumulator’s low byte is pulled first, then the high byte is pulled.

Note that unlike some other microprocessors, the 65x pull instructions set the negative and zero flags.

Flags Affected: n - - - - - z n Set if most significant bit of pulled value is set; else cleared.

z Set if value pulled is zero; else cleared.

Codes:

Address Mode Syntax

Opcode

(hex)

Stack (Pull) PLA 68 a) Add 1 cycle if m=0 (16-bit memory/accumulator)

Available on: # of # of

6502 65C02 65802/816 Bytes Cycles

x x x 1 4

1

382

The Western Design Center

Pull Data Bank Register PLB

Pull the eight-bit value on top of the stack into the data bank register B, switching the data bank to that value. All instructions which reference data that specify only sixteen-bit addresses will get their bank address from the value pulled into the data bank register. This is the only instruction that can modify the data bank register.

Since the bank register is an eight-bit register, only one byte is pulled from the stack, regardless of the settings of the m and x mode select flags. The stack pointer is first incremented. Then the byte pointed to by the stack pointer is loaded into the register.

Flags Affected: n - - - - - z -

n Set if most significant bit of pulled value is set; else cleared.

z Set if value pulled is zero; else cleared.

Codes:

Address Mode

Stack (Pull)

Syntax

PLB

Opcode

(hex)

AB

Available on: # of # of

6502 65C02 65802/816 Bytes Cycles

x 1 4

383

The Western Design Center

Pull Direct Page Register PLD

Pull the sixteen-bit value on top of the stack into the direct page register D, switching the direct page to that value.

PLD is typically used to restore the direct page register to a previous value.

Since the direct page register is a sixteen-bit register, two byte are pulled from the stack, regardless of the settings of the m and x mode select flags. The low byte of the direct page register is pulled first, then the high byte. The stack pointer now points to where the high byte just pulled was stored; this is now the next available stack location.

Flags Affected: n - - - - - z n Set if most significant bit of pulled value is set; else cleared.

z Set if value pulled is zero; else cleared.

Codes:

Addressing Mode

Stack (Pull)

Syntax

PLD

Opcode Available on: # of # of

Cycle

(hex) 6502 65C02 65802/816 Byte s

2B x 1 5

384

The Western Design Center

Pull Status Flags PLP

Pull the eight-bit value on the top of the stack into the processor status register P, switching the status byte to that value.

Since the status register is an eight-bit register, only one byte is pulled from the stack, regardless of the settings of the m and x mode select flags on the 65802/65816. The stack pointer is first incremented. Then the byte pointed to by the stack pointer is loaded into the status register.

This provides the means for restoring either previous mode settings or a particular set of status flags that reflect the result of a previous operation.

Note, however, that the e flag–the 6502 emulation mode flag on the 65802/65816–is not on the stack so cannot be pulled from it. The only means of setting the e flag is the XCE instruction.

Flags Affected: n v - b d i z c (6502, 65C02,

65802/65816 emulation mode e=1) n v m x d i z c (65802/65816 native mode e=0)

All flags are replaced by the values in the byte pulled from the stack.

Codes:

Address Mode Syntax

Stack (Pull) PLP

Opcode Available on: # of # of

(hex) 6502 65C02 65802/816 Bytes Cycles

28 x x x 1 4

385

The Western Design Center

Pull Index Register X from Stack PLX

Pull the value on the top of the stack into the X index register. The previous contents of the register are destroyed.

8-bit index registers (all processors): The stack pointer is first incremented. Then the byte pointed to by the stack pointer is loaded into the register.

16-bit index registers (65802/65816 only, x = 0): Both bytes of the index register are pulled. First the low-order byte of the index register is pulled, then the high-order byte of the index register is pulled.

Unlike some other microprocessors, the 65x instructions to pull an index register affect the negative and zero flags.

Flags Affected: n - - - - - z n Set if most significant bit of pulled value is set; else cleared.

z Set if value pulled is zero; else cleared.

Codes:

Address Mode Syntax

Stack (Pull) PLX

Opcode

(hex)

FA

6502

1. Add 1 cycle if x = 0 (16-bit index registers)

Available on:

65C02

x

65802/816

x

# of

Bytes

1

# of

Cycles

4

1

386

The Western Design Center

Pull Index Register Y from Stack PLY

Pull the value on the top of the stack into the Y index register. The previous contents of the register are destroyed.

8-bit index registers (all processors): The stack pointer is first incremented. Then the byte pointed to by the stack pointer is loaded into the register.

16-bit index registers (65802/65816 only, x = 0): Both bytes of the index register are pulled. First the low-order byte of the index register is pulled, then the high-order byte of the index register is pulled.

Unlike some other microprocessors, the 65x instructions to pull an index register affect the negative and zero flags.

Flags Affected: n - - - - - z -

n Set if most significant bit of pulled value is set; else cleared.

z Set if value pulled is zero; else cleared.

Codes:

Addressing Mode

Stack (Pull)

Syntax

PLY

Opcode Available to: # of

(hex) 6502 65C02 65802/816 Bytes

7A

1.

1

Add 1 cycle if x = 0 (16-bit index registers) x x 1

# of

Cycles

4

1

387

The Western Design Center

Reset Status Bits REP

For each bit set to one in the operand byte, reset the corresponding bit in the status register to zero. For example, if bit three is set in the operand byte, bit three in the status register (the decimal flag) is reset to zero by this instruction. Zeroes in the operand byte cause no change to their corresponding status register bits.

This instruction lets you reset any flag or flags in the status register with a single two-byte instruction.

Further, it is the only direct means of resetting several of the flags, including the m and x mode select flags

(although instructions that pull the P status register affect the m and x mode select flags).

6502 emulation mode (65802/65816, e=1): Neither the break flag nor bit five (the 6502’s undefined flag bit) are affected by REP.

Flags Affected: n v - - d i z c (65802/65816 emulation mode e=1) n v m x d i z c (65802/65816 native mode e=0)

All flags for which an operand bit is set are reset to zero.

All other flags are unaffected by the instruction.

Codes:

Addressing Mode Syntax

Immediate REP # const

Opcode Available to: # of # of

(hex) 6502 65C02 65802/816 Bytes Cycles

C2 x 2 3

388

The Western Design Center

Rotate Memory or Accumulator Left ROL

Rotate the contents of the location specified by the operand left one bit. Bit one takes on the value originally found in bit zero, bit two takes the value originally in bit one, and so on; the rightmost bit, bit zero, takes the value in the carry flag; the leftmost bit (bit 7 on the 6502 and 65C02 or if m = 1 on the 65802/65816, or bit 15 if m = 0) is transferred into the carry flag.

1 0 1 1 0 0 1 1

X

Carry Flag

Figure 18-8 ROL

8-bit accumulator/memory (all processors): Data rotated is eight bits, plus carry.

16-bit accumulator/memory (65802/65816 only, m=0): Data rotated is sixteen bits, plus carry: if in memory, the low-order eight bits are located at the effective address; the high eight bits are located at the effective address plus one.

Flags Affected: n - - - - - z c

n Set if most significant bit of result is set; else cleared.

z Set if result is zero; else cleared.

c High bit becomes carry: set if high bit was set; cleared if high bit

was clear.

Codes:

Address Mode

Accumulator

Absolute

Direct Page (also

DP)

Syntax

ROL A

ROL addr

ROL dp

Opcode

(hex) 6502 65C02 65802/816 Bytes Cycles

2A

2E

26 x x x

Available to:

x x x x x x

Absolute Indexed,

X

ROL addr,

X

3E x

DP Indexed, X

ROL dp, X

36 x

1 Add 2 cycles if m=0 (16-bit memory/accumulator) x x x x

2 Add 1 cycle if low byte of Direct Page register is other than zero (DL< >0)

3 Subtract 1 cycle if 65C02 and no page boundary crossed

# of

1

3

2

3

2

# of

5

7

6

2

6

1

1, 2

1, 3

1, 2

389

The Western Design Center

Rotate Memory or Accumulator Right ROR

Rotate the contents of the location specified by the operand right one bit. Bit zero takes on the value originally found in bit one, bit one takes the value originally in bit two, and so on; the leftmost bit (bit 7 on the

6502 and 65C02 or if m = 1 on the 65802/65816, or bit 15 if m = 0) takes the value in the carry flag; the rightmost bit, bit zero, is transferred into the carry flag.

1 0 1 1 0 0 1 1

Figure 18-9 ROR

X

8-bit accumulator/memory (all processors): Data rotated is eight bits, plus carry.

16-bit accumulator/memory (65802/65816 only, m=0): Data rotated is sixteen bits, plus carry: if in memory, the low-order eight bits are located at the effective address; the high-order eight bits are located at the effective address plus one.

Flags Affected: n - - - - - z c n Set if most significant bit of result is set; else cleared.

z Set if result is zero; else cleared.

c Low bit becomes carry: set if low bit was set; cleared if low

bit was clear.

Codes:

Address Mode

Accumulator

Absolute

Direct Page (also

DP)

Syntax

ROR A

ROR addr

ROR dp

Opcode

(hex) 6502 65C02 65802/816 Bytes Cycles

6A

6E

66 x x x

Available to:

x x x x x x

Absolute Indexed,

X

ROR addr,

X

7E x

DP Indexed, X

ROR dp, X

76 x

1 Add 2 cycles if m = 0 (16-bit memory/accumulator) x x x x

2 Add 1 cycle if low byte of Direct Page register is other than zero (DL< >0)

3 Subtract 1 cycle if 65C02 and no page boundary crossed

# of

1

3

2

3

2

# of

5

7

6

2

6

1

1, 2

1, 3

1, 2

390

The Western Design Center

Return from Interrupt RTI

Pull the status register and the program counter from the stack. If the 65802/65816 is set to native mode (e = 0), also pull the program bank register from the stack.

RTI pulls values off the stack in the reverse order they were pushed onto it by hardware or

software interrupts. The RTI instruction, however, has no way of knowing whether the values pulled off the stack into the status register and the program counter are valid – or even, for that matter, that an interrupt has ever occurred. It blindly pulls the first three (or four) bytes off the top of the stack and stores them into the various registers.

Unlike the RTS instruction, the program counter address pulled off the stack is the exact address to return to; the value on the stack is the value loaded into the program counter. It does not need to be incremented as a subroutine’s return address does.

Pulling the status register gives the status flags the values they had immediately prior to the start of interrupt-processing.

One extra byte is pulled in the 65802/65816 native mode than in emulation mode, the same extra byte that is pushed by interrupts in native mode, the program bank register. It is therefore essential that the return from interrupt be executed in the same mode (emulation or native) as the original interrupt.

6502, 65C02, and Emulation Mode (e = 1): The status register is pulled from the stack, then

the program counter is pulled from the stack (three bytes are pulled).

65802/65816 Native Mode (e = 0): The status register is pulled from the stack, then the

program counter is pulled from the stack, then the program bank register is pulled from the stack (four bytes are pulled).

Stack

(Stack Pointer After) Old Status Register

Return Address Bank

Return Address High

Return Address Low

Stack Pointer Before

Flags Affected:

Bank 0

Figure 18-10Native Mode Stack before RTI.

n v - - d i z c (6502, 65C02,

65802/65816 emulation mode e = 1) n v m x d i z c (65802/65816 native mode e = 0)

All flags are restored to their values prior to interrupt (each flag takes the value of its corresponding bit in the stacked status byte, except that the Break flag is ignored).

391

The Western Design Center

Codes:

Addressing Mode Syntax

Stack (RTI) RTI

Opcode

(hex)

40

6502

x

1 Add 1 cycle for 65802/65816 native mode (e=0)

Available to:

65C02

x

65802/816

x

# of

Bytes

1

# of

Cycles

6

1

392

The Western Design Center

Return from Subroutine Long RTL

Pull the program counter (incrementing the stacked, sixteen-bit value by one before loading the program counter with it), then the program bank register from the stack.

When a subroutine in another bank is called (via a jump to subroutine long instruction), the current bank address is pushed onto the stack along with the return address. To return to the calling bank, a long return instruction must be executed, which first pulls the return address from the stack, increments it, and loads the program counter with it, then pulls the calling bank from the stack and loads the program bank register. This transfers control to the instruction immediately following the original jump to subroutine long.

Stack

(Stack Pointer After) Return Bank Address

Return Address High

Return Address Low

Stack Pointer Before

Bank 0

- - - - - - - -

Figure 18-11 Stack before RTL

Flags Affected:

Codes:

Address Mode Syntax

Stack (RTL) RTL

Opcode

(hex) 6502

Available to:

65C02

65802/8

16

6B x

# of # of

Bytes

Cycle s

1 6

393

The Western Design Center

Return from Subroutine RTS

Pull the program counter, incrementing the stacked, sixteen-bit value by one before loading the program counter with it.

When a subroutine is called (via a jump to subroutine instruction), the current return address is pushed onto the stack. To return to the code following the subroutine call, a return instruction must be executed, which pulls the return address from the stack, increments it, and loads the program counter with it, transferring control to the instruction immediately following the jump to subroutine.

Stack

(Stack Pointer After) Return Address High

Return Address Low

Stack Pointer Before

Bank 0

- - - - - - - -

Figure 18-12 Stack before RTS

Flags Affected:

Codes:

Addressing

Mode

Stack (RTS)

Syntax

RTS

Opcode Available to:

(hex) 6502 65C02 65802/816

60 x x x

# of

Bytes

1

# of

Cycles

6

394

The Western Design Center

Subtract with Borrow from Accumulator SBC

Subtract the data located at the effective address specified by the operand from the contents of the accumulator; subtract one more if the carry flag is clear, and store the result in the accumulator.

The 65x processors have no subtract instruction that does not involve the carry. To avoid subtracting the carry flag from the result, either you must be sure it is set or you must explicitly set it (using SEC) prior to executing the SBC instruction.

In a multi-precision (multi-word) subtract, you set the carry before the low words are subtracted. The low word subtraction generates a new carry flag value based on the subtraction. The carry is set if no borrow was required and cleared if borrow was required. The complement of the new carry flag (one if the carry is clear) is subtracted during the next subtraction, and so on. Each result thus correctly reflects the borrow from the previous subtraction.

Note that this use of the carry flag is the opposite of the way the borrow flag is used by some other processors, which clear (not set) the carry if no borrow was required.

d flag clear: Binary subtraction is performed.

d flag set: Binary coded decimal (BCD) subtraction is per