Jump to content
IGNORED

Assembly Language Prog - Lesson 8 - The Programming Model


Robert M

Recommended Posts


Assembly Language Programming - Lesson 8 - The Programming Model

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



   Up until now the lessons have been mostly generic only making passing references to the Atari VCS.   That was to emphasize the general nature of the topics and how they apply to assembly language programming on all platforms.  If we are going to progress, however, we need to start getting more specific.   This course will use the Atari VCS for all of its programming exercises.   This means that the  course will focus on the 650X family of microprocessors.



   The 650X family of processors was used in many classic gaming platforms so this is a good processor family to learn if you want to program for retro gaming consoles.   It was used in the Apple II, Commodore 64, all Atari home computers and game consoles, many arcade games of the 1980's and many others.   The Atari VCS uses version 6507 of  the 650X family of processors.  Throughout the course I will try to point out the differences between 650X processors that matter to programmers.  



   Below I have placed a diagram of the 650X programming model.  This diagram shows a programmer what registers are in the 650X microprocessor and how big each register is.  The 650X processor has 6 registers.  A register is a collection of bits (Lesson 1) whose "meaning" is defined by the hardware rather than the software.    There are many other circuits in the microprocessor, but from your point of view as a programmer you only need to be concerned with these 6.  The values stored in these six registers together form what I referred to as the "machine state" in the previous lesson.  Take some time to get familiar with this diagram and then we will discuss each register in more detail below.





=====================================================================

650X Processor Programming Model:



         7      0  -> (each bit of a register is refered to by a #)

        +--------+    

        |   A    |  Accumulator

        +--------+



         7      0

        +--------+

        |   Y    |  Index Register Y

        +--------+



         7      0

        +--------+

        |   X    |  Index Register X

        +--------+



15      8 7      0

+--------+--------+

|  PCHi  |  PCLo  |  Program Counter

+--------+--------+



15      8 7      0

+--------+--------+

|00000001|   SP   |  Stack Pointer

+--------+--------+



         7      0

        +--------+

        |NV_BDIZC|  Status Register

        +--------+

         ||||||||

         |||||||+----> Carry:         1 = TRUE

         ||||||+-----> Zero:          1 = result is zero

         |||||+------> IRQ Disable:   1 = DISABLE

         ||||+-------> Decimal Mode:  1 = Binary Coded Decimal mode

         |||+--------> BRK Command:   1 = Yes

         ||+---------> {not used}

         |+----------> Overflow:      1 = TRUE

         +-----------> Negative:      1 = result is negative



=====================================================================



Accumulator:  

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

The accumulator is the work-horse register for all your programs.  It is in the accumulator that you will perform nearly all binary math operations, and logical binary operations.  You can say that the answers to math problems "accumulate" in the accumulator.   When you aren't performing math operation your program is usually copying data from one place in memory to another.  Your program will move data by reading it into the accumulator and then writing it out again.  Often times you will use an index register in tandem with the accumulator to make the task easier.  The shorthand name for this register is "A" or "Acc"



Index Register Y:  

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

The shorthand name for this register is "Y".  The primary use of index registers is counting up or down one at a time to access data tables in memory.   In programs you frequently need to perform the same action over and over again on a list of similar data items.  You can use the Y index register to count through the list of items: 1, 2, 3, 4, etc.  or alternately count backwards: 5, 4, 3, 2, 1, 0, etc. Using the Y register to "index" a list is so common that is why it is in the register's name.  There are different kinds of lists which use different "modes" of indexing.  We don't want to cover that now as it will take at least one whole lesson if not 2 to cover the different indexing modes.  You can also use the Y register as a temporary holding place for a result from the Accumulator or in tandem with the X index register to read and write from tables in memory, thus freeing the accumulator for use to solve another problem at the same time.    



Index Register X:

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

Index register X is nearly identical to index register Y.  It serves the same purpose in most programs.  There are 2 major differences between X and Y.  First the X register is connected to the Stack Pointer register (see Stack Pointer below) so that the contents of one can be copied to the other and vise versa.  The Y index is not connected to the Stack Pointer register.  Also, the modes of indexing that can be performed with X and Y are not the same.  They share some modes, but other modes are unique to X or Y.   Later lessons will describe these differences in detail.    



********************************************************************

NOTE:  With 2 indexing registers, your program can access 2 separate lists of items at the same time without needing to shuffle the contents of the registers with main memory which takes precious time to do.   In a VCS game for example, you often will use the Y index register to access the tables of sprite graphic data for your game.  At the same time a different index in X will access the table of Playfield/Background graphics data.  

********************************************************************



Program Counter:

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

The A, X, and Y registers are all 8-bit (one byte) registers.  The program counter register is a 16-bit (two bytes) register.  The shorthand name for the program counter is PC.  The 650X family of processors can read and write data 8-bits (one byte) at a time.  They can read and write data from a memory space up to 65,536 bytes in size.  Note from our previous lessons, 65,536 is 2 to the 16th power. So the address (a unique name akin to a street addresses on houses) of each memeory location is 16-bits wide.  The program instructions are stored in memory.  The Program Counter holds the memory address of the next instruction in the program.  Therefore, the PC needs to be 16-bits wide so that a program can be located anywhere in memory.  After executing each instruction the PC is automatically incremented by the logic of the microporcessor to point at the next instruction in your program.   There are instructions that allow you to change the PC to point at any address in memory and the processor will continue executing instructions starting at the new address.  That's all you need to know for now.





Stack Pointer:

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

The shorthand name for the Stack Pointer register is the SP.  The SP is an 8-bit register that acts like a 16-bit address for which the 8 most-significant bits of the 16-bit value are hardcoded as %00000001 as shown in the diagram above.  The SP gives the programmer hardware support for a type of data/memory structure known as a stack.  With normal memory in a computer you can read or write from any memory location.  With a stack, however, you can only read and write at the top of the stack.  Think of a stack like a serving plate dispenser at a cafeteria.  Patrons of the cafeteria take the top plate from the stack of plates.  Removing the top plate causes the remaining plates to rise and the plate that was below the top plate to now be on top.  If a cafeteria worker adds more plates to the stack, the new plates go on top of the old plates and push them down.   This "pushing down" effect is often referred to as Last-In-First-Out (LIFO).   The last item placed on the stack is the first one to be removed.



The action of putting an item on top of a stack is called pushing.  The action of removing the top item from a stack is called pulling or popping.  There are instructions in the 650X assembly language that push and pull 8-bit bytes or 16-bit addresses to and from the stack.  The items on the stack are stored in the normal memory of the computer, the FIFO behavior of the stack is completely a function of using the stack instructions in the 650X processor in conjunction with the value in SP.  You can copy the value of the SP (lo-byte only since the hi-byte is always the same) into the X register and access the contents of the stack in a non-FIFO manner if it would be an advantage in your code.



The stack in the VCS is both a curse and a boon.  It is a curse because the VCS has only 128 bytes of RAM memory.   The stack and normal memory are completely overlapped so you must be careful as you push things onto the stack that you to not overwrite other data stored in the same 128 bytes of RAM.  The boon, is that the stack also overlaps with all of the TIA video control registers.  There are some neat tricks you can do with the stack to quickly write to the ball and missle enable registers in your game kernel and other TIA registers as well.  Learning the details of such tricks is far in the future for this course.



Here is a quick review of how the stack works in a 650X based system. The SP is usually initialized by a program to point at the last available memory address of the first page of memory (I will explain memory pages in lesson 9) which in the VCS is the address 511 or in binary %0000000111111111.   When your program executes a PUSH instruction, the byte is written in to the memory address pointed at by SP, and then the SP is decremented to point at the next lowest memory location.  When you pop a byte off of the stack the opposite set of steps occur.  The SP is incremented by 1 and the value of the byte is copied from the memory location pointed at by the SP.   Pushing and popping a 16-bit address from the stack is done by repeating the process for a single byte twice.   The hi-byte of an address is always pushed onto the stack first and then the lo-byte.  



That's plenty of introduction for the stack, we will come back to it again in earnest in a few lessons.  





Status Register: (a.k.a) Condition Code Register.

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

There is no shorthand name for the status register, but it is sometimes referred to as the condition code register which can be abbreviated as CC.  The status register is a single byte.  Seven of the eight bits in the status register are used as flags to indicate the state of the microprocessor or special results of the last instruction executed.  The one bit is not used and should be ignored by the programmer (see the diagram above).  Every time an instruction is executed by the microprocessor it will set or clear none to all of the status register flags.  Some instructions test the state of one of the flags and based on its state the PC is either incremented to point at the next instruction as is normal, or it is changed to another location in memory where execution continues.  This mechanism allows your code to detect conditions and change behavior accordingly. 



There are instructions to set or clear individual flags in the status register.  There are also instructions to push and pull the status register to and from the stack.  Now lets take a brief look at each flag in the status register:



bit 7 = N flag = Negative?

**************************

The N flag is set if bit 7 is set in the result of the instruction.  It is clear if that bit 7 is clear.  It is called the Negative flag because you may recall from our binary math lesson that a signed binary number is negative when its MSB (bit 7) is set (1), and it is positive when its MSB is clear (0).  So N flag is (almost) always the same value as the bit 7 of the last byte processed, and if you are processing a signed binary number you can tell if it is a negative or positive number and jump to the correct code for each case. 



bit 6 = V flag = Overflow?

**************************

The next flag is the overflow flag.  When you perform a binary addition or subtraction operation the V flag is set if the conditions for 8-bit binary overflow occurred.  Otherwise, the V flag is cleared.  Besides addition and subtraction only one other instruction, used to test the state of bits in memory, will affect the V flag.  As a VCS programmer you will find the unchanging nature of the V flag useful in your code becuase it means that you can often set or clear the V flag to indicate something in your program and then execute hundreds of instructions and the V flag will not be changed.  You can then use instructions that jump to different parts of your code based on the V flag without needing to repeat the original test that set or clear the V flag.  You can save oodles of time in your code using such a trick.  In the game "Venture" by Coleco for example, the V flag is set or cleared at the start of the kernel to draw the game screen.  It indicates whether or not the room being drawn is a symetrical or assymetrical design.  The V flag remains unchanged for the next 160 television scan lines as the room is drawn either symetrically or asymetrically based on the V flag state.



bit 5 = not used

****************

Ignore this bit, do not try to use this bit for storage it is not usable.



bit 4 = B flag = BRK Command?

*****************************

There is an instruction in 650X assembly language called BRK.  BRK is a mnemonic for Break.  When the BRK instruction is executed the processor pushes the current PC value onto the stack to save a copy of it for the program to use if it wants to go back to where it was.  It then pushes the status regsister onto the stack with the B flag set and reads the 16-bit address stored in a specific (hardwired in the processor) location 65534 (lo-byte) and 65535 (hi-byte) in the program memory and puts it into the PC.  Program execution begins at this new address.  



Why would you want to do such a thing?  There are 2 main possible reasons.  First, if you have a 650X based computer with an operating system you can use the BRK instruction as a means for user programs to call the operating system for services.  Second, you may have a debugging tool that can replace an existing instruction in your program with a BRK instruction (it remembers what was there so it can put the old instruction back).  This technique is called "placing a breakpoint".  If you run your program with the BRK breakpoint in place and the BRK instruction is executed then the processor control exits your program at the breakpoint and passes control to the debugging program which will show you the state of your program when the breakpoint was reached.  That way you can see if what you thought your code was doing matches what it really is doing.  



The BRK instruction is of limited use on the VCS due to its highly limited resources which make an Operating System or a Debugger tool impractical.  There has been some discussion on the Stella mailing list as to whether one might exploit the BRK instruction on the VCS because it writes 3 bytes to the stack in 6 cycles.  Rather than the normally needed 9 clock cycles, but no one has demonstrated a use for this in a real program and such a topic is too advanced for a newbie programming course so just pretend I didn't even mention it.;)



bit 3 = D flag = Decimal Mode

*****************************



One of the features of the 650X microprocessors is that they have built-in support for performing addition and subtraction of numbers stored in Binary Coded Decimal (BCD) as well as the more common addition and subtraction of signed and unsigned binary numbers.  Many VCS programs make use of BCD formated numbers because it is an easy task in a program to load a BCD digit into the X or Y register and use it to copy the graphics data to display a digit on the screen as part of a score or other indicator.  Your code should never need to test the D flag it is included in the status register mainly for the use of an operating system or debugging tool to know if the calling program was in decimal math mode or not so that if control is passed back to the calling program the correct math mode will be re-enabled.



bit 2 = I flag = Interrupt Disable

**********************************



In the 650X family of processors there are 2 kinds of interrupts: maskable and unmaskable.  An interrupt is an external digital signal input to a pin on the microprocessor.  When the interrupt signal is detected by the processor, the processor finishes its current instruction and then like a BRK instruction the processor pushes the current PC onto the stack and begins executing instructions at the location pointed to by an address stored in a hardwired location (a.k.a. Interrupt vector).  Interrupts are handy because they allow the processor to stop what it is currently doing and deal with a situation that needs to be dealt with immediately or something bad will happen.  For example, an interrupt could be generated every second by a hardware timer circuit so that a real time clock can be updated.  Or a input port may generate an interrupt when a byte of data is received from an external device like a floppy disk drive.  The processor services the interrupt and then pulls the interrupted program's PC from the stack and continues where it left off.  A handy feature to be sure.



As a programmer you might not want your program interrupted.  By setting the I flag you can disable all maskable interrupts in the system you are writing code for.  Clearing the I-flag re-enables maskable interrupts.  Note, the I-flag does not disable non-maskable interrupts (hence the non part of the name).  Nothing can stop a non-maskable interrupt. Non-maskable interrupts are handy for a  soft-reset button on a system.  For example on the C64, pressing the RUNSTOP and RESTORE keys together will generate a non-maskable interrupt.  If the program running did not change the interrupt vector for non-maskable interrupts, then the C64 will kill any program currently running display the READY prompt. 



Now the bad news.  The Atari VCS uses the 6507 version of the 650X family of processors.  One of the features of the 6507 is that it has no interrupts of any kind either maskable or non-maskable.  As a result, this flag has almost no meaning for VCS programmers.  I say almost because the Atari 7800 uses a version of the 650X processor that does have interrupts.  Therefore as a VCS programmer it behooves you to ALWAYS set the I-flag near the beginning of your program code so that your game will work correctly on both Atari 2600 and Atari 7800 consoles.  I will teach you how to set the I-flag in a later lesson.



bit 1 = Z flag = Zero result? Equal result

******************************************



The Z flag is similar to the N flag.  If the result of the last instruction is zero (all 8 bits of the byte are zero), then the Z flag is set to 1.  Otherwise, it is cleared to zero.  As an assembly language programmer you will find that the Z-flag is your good friend.  You will be testing the Z flag throughout your code and deciding what to do based on its state.   For example, every time you compare two bytes the Z flag is set if they are equal.  This is because a processor performs a comparison as a subtraction operation (byte1 - byte2 = 0 = Z flag set).   That's enough for now, the Z flag will be coming up frequently in later lessons.





bit 0 = C flag = Carry/Borrow?

******************************



The C flag is similar to the V flag in that is it set or cleared after an addition or subtraction instruction to indicate whether the addition resulted in a carry, or if a subtraction required a borrow.  Unlike the V flag which can not be used to cause an overflow, the C flag can be set or cleared by your program to force an addition to include an addtional carry of 1, or a subtraction to borrow an additional 1.  Also, the C flag is used in conjunction with instructions that perform bit rotations and shifts as the bit to be shifted in and/or the bit shifted out of the byte.  I will explain bit rotations and shifts in a later lesson.  A main point to take away is that the C flag changes more often then the V, but not as often as the N flag or Z flag.  So sometimes you can set or clear the C flag and it will still be set or clear a few instructions later which can be a useful side effect.  Sort of a V flag junior. 



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



Whew!  Sorry if that was long, but it was worth it! Trust me.



Exercises:



I really can't think of a useful exercise for this lesson.  That should not imply that the content is not important.  I hope that starting with this lesson my reasoning for covering all the other topics before this one is becoming clear.  I really felt I needed to introduce that other material first.  With this and future lessons we will be diving into the meat and bones of assembly language programming.   Hopefully,  I will have you writing actual code by lesson 12 or 13.  



Do not be afraid to ask questions or point out what you think might be errors.

Link to comment
Share on other sites

Rob:

 

I'm halfway though my first read-through .. Under Stack Pointer you talk about LIFO .. then in the next paragraph you talk about FIFO.  Did you mean LIFO then?

 

BTW: great tutoral!

 

Rob Mitchell, Atlanta, GA

 

 

Argh! Nice catch. Yes it should be LIFO. FIFO is a different data structure "First-In-First-Out". Another name for FIFO is a queue. Its just like any line you might stand in. The first person into the line gets served first. There is no hardware support in a VCS for a LIFO, but I will probably show you in some later lesson how to make one in software.

 

Cheers!

Link to comment
Share on other sites

I had no idea inventory costing terms had any application to assembly language programming.  Pretty cool.

 

Hi, could you explain to me the similarities. I might be able to make it into a programming assignment in a later lesson.

 

Cheers!

 

Sure. I'm not sure if LIFO and FIFO first started as accounting terms, but here goes. This is going to take me back eleven years to when I took the CPA exam, as I haven't used these in my working life. The concept is simple though and is covered in the first weeks of any introductory accounting course.

 

LIFO and FIFO are used when you are have differently prices lots of the same items in your inventory. The method is used for inventory items that are interchangeable. For this example, we will be in business selling new boxed VCS's.

 

You just bought a lot of 20 VCS's for $20 each from a supplier. You already have 10 VCS's in your inventory that you purchased for $10 a piece.

 

You get an order for 15 VCS's from a customer. For your financial records, what is going to be the cost of goods sold? And then, after the sale, what is the value of your remaining inventory? You will have different values for each, depending on which method you use.

 

With LIFO, the last costs in are the first ones out. So this lot of VCS's is going in the expense accounts at $300 (15 X $20) using the new price. The cost of the VCS's you have left is $200 (5 X $20) + (10 X $10) a mix of 5 new VCS's and the 10 VCS's you already had.

 

If you used FIFO, now the first costs in are the first costs out. The expense of those 15 VCS's is $200 (10 X $10) + (5 X $20). The 10 old VCS's and 5 of the new ones. Your inventory is now valued at $300 (15 X $20) the 15 new VCS's that were left over.

 

This the terms LIFO and FIFO applies to costs, not the physical items in inventory. If we were selling a perishable item like fish, we would sell the oldest ones in inventory first, even if we were using LIFO. Otherwise our business would stink really quickly.

 

I don't know if this will help you for any of your future lessons, or if it even makes any sense. I've tried to keep the example simple.

 

Here's a link with a further example.

 

http://www.swcollege.com/vircomm/gita/gita...a12-2_main.html

Link to comment
Share on other sites

I had no idea inventory costing terms had any application to assembly language programming.  Pretty cool.

 

Hi, could you explain to me the similarities. I might be able to make it into a programming assignment in a later lesson.

 

Cheers!

 

Sure... {snip}

 

Hey, thanks! That is very interesting. I think I could make that into a programming lesson at some point in the future. Thanks again for the info.

 

Cheers!

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...