Warning: preg_match(): Compilation failed: group name must start with a non-digit at offset 8 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 722

Warning: preg_match(): Compilation failed: group name must start with a non-digit at offset 8 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 722

Warning: preg_match_all(): Compilation failed: group name must start with a non-digit at offset 4 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 700

Warning: Invalid argument supplied for foreach() in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 701

Warning: preg_replace(): Compilation failed: group name must start with a non-digit at offset 4 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 705

Warning: preg_match_all(): Compilation failed: group name must start with a non-digit at offset 4 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 700

Warning: Invalid argument supplied for foreach() in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 701

Warning: preg_replace(): Compilation failed: group name must start with a non-digit at offset 4 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 705

Warning: preg_match(): Compilation failed: group name must start with a non-digit at offset 8 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 722

Warning: preg_match_all(): Compilation failed: group name must start with a non-digit at offset 4 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 700

Warning: Invalid argument supplied for foreach() in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 701

Warning: preg_replace(): Compilation failed: group name must start with a non-digit at offset 4 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 705

Warning: preg_match_all(): Compilation failed: group name must start with a non-digit at offset 4 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 700

Warning: Invalid argument supplied for foreach() in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 701

Warning: preg_replace(): Compilation failed: group name must start with a non-digit at offset 4 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 705

Warning: preg_match_all(): Compilation failed: group name must start with a non-digit at offset 4 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 700

Warning: Invalid argument supplied for foreach() in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 701

Warning: preg_replace(): Compilation failed: group name must start with a non-digit at offset 4 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 705

Warning: preg_match_all(): Compilation failed: group name must start with a non-digit at offset 4 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 700

Warning: Invalid argument supplied for foreach() in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 701

Warning: preg_replace(): Compilation failed: group name must start with a non-digit at offset 4 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 705

Warning: preg_match(): Compilation failed: group name must start with a non-digit at offset 8 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 722

Warning: preg_match(): Compilation failed: group name must start with a non-digit at offset 8 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 722

Warning: preg_match(): Compilation failed: group name must start with a non-digit at offset 8 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 722

Warning: preg_match(): Compilation failed: group name must start with a non-digit at offset 8 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 722

Warning: preg_match_all(): Compilation failed: group name must start with a non-digit at offset 4 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 700

Warning: Invalid argument supplied for foreach() in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 701

Warning: preg_replace(): Compilation failed: group name must start with a non-digit at offset 4 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 705

Warning: preg_match_all(): Compilation failed: group name must start with a non-digit at offset 4 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 700

Warning: Invalid argument supplied for foreach() in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 701

Warning: preg_replace(): Compilation failed: group name must start with a non-digit at offset 4 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 705

Warning: preg_match(): Compilation failed: group name must start with a non-digit at offset 8 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 722

Warning: preg_match(): Compilation failed: group name must start with a non-digit at offset 8 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 722
Introducing the Instruction Set Part 3 - Intellivision Wiki

Introducing the Instruction Set Part 3


Warning: preg_match(): Compilation failed: group name must start with a non-digit at offset 8 in /home/content/30/6867330/html/intellivision/wiki/includes/MagicWord.php on line 722
From Intellivision Wiki

Jump to: navigation, search
m (Call Chaining: Having One Function Return for Another)
(Why do we need branches?)
 
Line 1: Line 1:
 +
[[Category: Programming]][[Category: Tutorial]]
 +
This segment of the tutorial introduces branches, particularly conditional branches and function calls.  This is Part 3 of a series.  If you haven't yet, you may wish to review at least [[Introducing the Instruction Set Part 1|Part 1]] and [[Introducing the Instruction Set Part 2|Part 2]].
This segment of the tutorial introduces branches, particularly conditional branches and function calls.  This is Part 3 of a series.  If you haven't yet, you may wish to review at least [[Introducing the Instruction Set Part 1|Part 1]] and [[Introducing the Instruction Set Part 2|Part 2]].
Line 44: Line 46:
That runs very fast, but it takes up a ton of ROM.  Also, it clears the screen only once.  What if you want to clear the screen many times throughout your program, perhaps from different places?  You really don't want to copy this same code everywhere you need to clear the screen.  That's where branches come in.<BR/><BR/>
That runs very fast, but it takes up a ton of ROM.  Also, it clears the screen only once.  What if you want to clear the screen many times throughout your program, perhaps from different places?  You really don't want to copy this same code everywhere you need to clear the screen.  That's where branches come in.<BR/><BR/>
-
Branches tell the CPU to start executing at a different location, rather than barreling forward.  Unconditional branches and jumps tell the CPU to always jump to that location.  Conditional branches tell the CPU to jump to a new location <I>if some condition is true.</I>  These let you skip pieces of code, or repeat them a number of times.  Jumps to subroutine tell the CPU "go do this and come back when you're done."  The following sections explore these concepts a little more closely.<BR/><BR/>
+
Branches tell the CPU to start executing at a different location, rather than barreling forward.  Unconditional branches and jumps tell the CPU to always jump to that location.  Conditional branches tell the CPU to jump to a new location <I>if some condition is true.</I>  These let you skip pieces of code, or repeat them a number of times.  Jumps to subroutines (also known as "calls") tell the CPU "go do this and come back when you're done."  The following sections explore these concepts a little more closely.<BR/><BR/>
= Branches and Labels =
= Branches and Labels =
Line 164: Line 166:
</TABLE>
</TABLE>
<BR/>
<BR/>
-
The unsigned comparisons require some additional explanation to be useful.  After comparing two unsigned numbers, the [[BC]] instruction will branch if the second number is greater than or equal to the first.  The [[BC]] instruction will branch if the second number is smaller than the first.  The CP1610 does not offer unsigned equivalents for "branch if greater than" or "branch if less than or equal."  You can get similar effects, though, by combining [[BC]] and [[BNC]] with [[BEQ]] or [[BNEQ]] to separate out the "equals", "greater-than" and "less-than" cases.
+
The unsigned comparisons require some additional explanation to be useful.  After comparing two unsigned numbers, the [[BC]] instruction will branch if the second number is greater than or equal to the first.  The [[BNC]] instruction will branch if the second number is smaller than the first.  The CP1610 does not offer unsigned equivalents for "branch if greater than" or "branch if less than or equal."  You can get similar effects, though, by combining [[BC]] and [[BNC]] with [[BEQ]] or [[BNEQ]] to separate out the "equals", "greater-than" and "less-than" cases.
=== How Unsigned Arithmetic Works With Conditional Branches ===
=== How Unsigned Arithmetic Works With Conditional Branches ===
Line 202: Line 204:
[[Image:If_then.png|center|Block diagram of an if-then statement]]
[[Image:If_then.png|center|Block diagram of an if-then statement]]
-
In this example, the CPU runs the green portion only if R1 is less than R2, as indicated in the blue square.  The other bits of code always run.  The following diagram shows how this looks as assembly language code:
+
In this example, the CPU runs the green portion only if R1 is less than R2, as indicated in the blue square.  The other bits of code always run.  The diagram shows how this looks as assembly language code:
[[Image:If_then_code.png|center|Code example for an if-then statement]]
[[Image:If_then_code.png|center|Code example for an if-then statement]]
Line 473: Line 475:
         ENDP
         ENDP
-
(Note:  For a more compact way of writing <CODE>CLRSCR</CODE> and <CODE>FILLMEM</CODE>, take a look at the [http://sdk-1600.spatula-city.org/examples/library/fillmem.asm optimized implementation in SDK-1600].)
+
(Note:  For a more compact way of writing <CODE>CLRSCR</CODE> and <CODE>FILLMEM</CODE>, take a look at the [[fillmem.asm|optimized implementation in SDK-1600]].)
-
 
+
-
 
+
== Passing Arguments via Return Address ==
== Passing Arguments via Return Address ==
Line 483: Line 483:
Fortunately, the CP1610 makes it easy to pass static arguments as just plain data, without needing a block of <CODE>[[MVII]]</CODE> instructions before each call.  If a particular function is going to get called regularly with certain arguments fixed at the call site as in the example above, then it makes sense to pass arguments via the return address.
Fortunately, the CP1610 makes it easy to pass static arguments as just plain data, without needing a block of <CODE>[[MVII]]</CODE> instructions before each call.  If a particular function is going to get called regularly with certain arguments fixed at the call site as in the example above, then it makes sense to pass arguments via the return address.
<BR/><BR/>
<BR/><BR/>
-
This relies on the fact that <CODE>[[CALL]]</CODE> sets R5 to point to the word just after the <CODE>[[CALL]]</CODE> instruction.  If you put data here, then <CODE>[[MVI@]] R5</CODE> will read that data.  The [http://sdk-1600.spatula-city.org/examples/library/print.asm SDK-1600 PRINT function] uses this technique to great effect.
+
This relies on the fact that <CODE>[[CALL]]</CODE> sets R5 to point to the word just after the <CODE>[[CALL]]</CODE> instruction.  If you put data here, then <CODE>[[MVI@]] R5</CODE> will read that data.  The [[print.asm|SDK-1600 PRINT function]] uses this technique to great effect.
<BR/><BR/>
<BR/><BR/>
The following example shows a different version of <CODE>FILLMEM</CODE> and <CODE>CLRSCR</CODE> that mimic the [[Introducing_the_Instruction_Set_Part_3#Passing_Arguments_to_Functions|example above]].  The difference is that this code passes arguments as data following the <CODE>[[CALL]]</CODE> instruction.
The following example shows a different version of <CODE>FILLMEM</CODE> and <CODE>CLRSCR</CODE> that mimic the [[Introducing_the_Instruction_Set_Part_3#Passing_Arguments_to_Functions|example above]].  The difference is that this code passes arguments as data following the <CODE>[[CALL]]</CODE> instruction.
Line 528: Line 528:
As you can see, this technique provides a great deal of flexibility in how things are called.
As you can see, this technique provides a great deal of flexibility in how things are called.
-
 
-
 
== Call Chaining:  Having One Function Return for Another ==
== Call Chaining:  Having One Function Return for Another ==
Line 535: Line 533:
Sometimes, the last thing you do at the end of one function is call another.  When that function returns, the only work left to do is to return again.  While that works, it's often possible to "chain" the calls&mdash;that is, branch to the next function and let it return for you.  Note that <B>this is purely an optimization.</B>  If it is at all unclear to you, I recommend you steer clear of it unless you're in a crunch.  Feel free to skip this section and come back to it if you need it later.
Sometimes, the last thing you do at the end of one function is call another.  When that function returns, the only work left to do is to return again.  While that works, it's often possible to "chain" the calls&mdash;that is, branch to the next function and let it return for you.  Note that <B>this is purely an optimization.</B>  If it is at all unclear to you, I recommend you steer clear of it unless you're in a crunch.  Feel free to skip this section and come back to it if you need it later.
<BR/><BR/>
<BR/><BR/>
-
Suppose we write a function that spins for a moment and then clears the screen.  There are many ways to do this with different advantages and disadvantages.  The code below has the advantage of being easy to write and understand.  This first version shows a normal call/return sequence:
+
Suppose we write a function that spins for a moment and then clears the screen.  There are many ways to do this, each with different advantages and disadvantages.  The code below has the advantage of being easy to write and understand.  This first version shows a normal call/return sequence:
  ; Delay for a moment and then clear the screen
  ; Delay for a moment and then clear the screen
Line 579: Line 577:
= Indirect Branches and Jump Tables =
= Indirect Branches and Jump Tables =
-
<BLOCKQUOTE>"It was a 'Jump to Conclusions' mat. You see, it would be this mat that you would put on the floor... and would have different <B>conclusions</B> written on it that you could <B>jump to.</B>" -- Tom Smykowski, Office Space</BLOCKQUOTE>
+
<BLOCKQUOTE><I>"It was a 'Jump to Conclusions' mat. You see, it would be this mat that you would put on the floor... and would have different <B>conclusions</B> written on it that you could <B>jump to.</B>"</I> -- Tom Smykowski, Office Space</BLOCKQUOTE>
Indirect branches are branches whose destination isn't encoded into the instruction itself.  You've seen a special version of this above:  The <CODE>[[JR]] R5</CODE> and <CODE>[[PULR]] PC</CODE> sequences for returning from function calls are both forms of indirect branches.
Indirect branches are branches whose destination isn't encoded into the instruction itself.  You've seen a special version of this above:  The <CODE>[[JR]] R5</CODE> and <CODE>[[PULR]] PC</CODE> sequences for returning from function calls are both forms of indirect branches.
Line 678: Line 676:
         [[SLL]]    R0, 1
         [[SLL]]    R0, 1
-
The "MAGIC_BRANCH" is really just a sequence that adds a register to the program counter based on how many instructions we intend to skip.  Suppose R1 held the shift amount.  The fol
+
The "MAGIC_BRANCH" is really just a sequence that adds a register to the program counter based on how many instructions we intend to skip.  Suppose R1 held the shift amount.  The following example show how to use that to skip some number of SLL instructions based on that:
         [[NEGR]]    R1        ; \_ Subtract R1 from 4 so it's now 3..0
         [[NEGR]]    R1        ; \_ Subtract R1 from 4 so it's now 3..0
Line 733: Line 731:
         ; do more stuff
         ; do more stuff
   
   
 +
        [[PULR]]    PC    ; return
         ENDP
         ENDP
Line 750: Line 749:
=== Using DECR to Spin "Forever" ===
=== Using DECR to Spin "Forever" ===
-
Sometimes, your program will need to simply "sit and spin." This most often happens when trying to synchronize with an interrupt, say as part of an initialization sequence.  (This will be covered in more detail in a future tutorial.)  The <CODE>[[DECR]] PC</CODE> instruction decrements the program counter after executing the instruction.  This puts the program counter right back at the same instruction, resulting in an infinite loop.  The only thing that will break out of this infinite loop is an interrupt.  
+
Sometimes, your program will need to simply "sit and spin" when trying to synchronize with an interrupt, say as part of an initialization sequence.  (Interrupts and their uses will be covered in more detail in a future tutorial.)  The <CODE>[[DECR]] PC</CODE> instruction decrements the program counter after executing the instruction.  This puts the program counter right back at the same instruction, resulting in an infinite loop.  The only thing that will break out of this infinite loop is an interrupt.  
<BR/><BR/>
<BR/><BR/>
Here's an example:
Here's an example:

Latest revision as of 04:57, 18 November 2011

Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox