Push
Syntax
Push Variable, {Variable, Variable etc}
Overview
Place a single variable or multiple variables onto a software stack. If the Push command is issued without a following variable, it will implement the assembler mnemonic Push, which manipulates the PICmicro's call stack.
Parameters
Variable is a user defined variable of type Bit, Pin, Byte, Word, Long, Long, Dword, Float, Array, String, or constant value.
The amount of bytes pushed on to the stack varies with the variable type used. The list below shows how many bytes are pushed for a particular variable type, and their order.
Bit 1 Byte is pushed that holds the condition of the bit.
Pin 1 Byte is pushed.
Byte 1 Byte is pushed.
Byte Array
1 Byte is pushed.
Word 2 Bytes are pushed. High Byte then Low Byte.
Long Array
3 Bytes are pushed. High Byte then Low Byte.
Long 3 Bytes are pushed. High Byte then Low Byte.
Word Array 2 Bytes are pushed. High Byte then Low Byte.
Dword Array 4 Bytes are pushed. High Byte then Low Byte.
Dword
4 Bytes are pushed. High Byte, Mid2 Byte, Mid1 Byte then Low Byte.
Float
4 Bytes are pushed. High Byte, Mid2 Byte, Mid1 Byte then Low Byte.
String
2 Bytes are pushed. High Byte then Low Byte that point to the start address of the string in memory.
- Constant
Amount of bytes varies according to the value pushed. High Byte first.
Example 1
' Push two variables on to the stack then retrieve them
Device = 18F452
' Stack only suitable for 18F devices
Declare Xtal = 16
' Tell the compiler the device is operating at 16MHz
Declare Stack_Size = 20 ' Create a small stack capable of holding 20 bytes
Dim Wrd as Word
' Create a Word variable
Dim Dwd as Dword
' Create a Dword variable
Wrd = 1234
' Load the Word variable with a value
Dwd = 567890
' Load the Dword variable with a value
Push Wrd, Dwd
' Push the Word variable then the Dword variable
Clear Wrd
' Clear the Word variable
Clear Dwd
' Clear the Dword variable
Pop Dwd, Wrd
' Pop the Dword variable then the Word variable
Print Dec Wrd, " ", Dec Dwd ' Display the variables as decimal
Stop
Example 2
' Push a String on to the stack then retrieve it
Device = 18F452
' Stack only suitable for 18F devices
Declare Stack_Size = 10
' Create a small stack capable of holding 10 bytes
Dim SourceString as String * 20 ' Create a String variable
Dim DestString as String * 20 ' Create another String variable
SourceString = "Hello World"
' Load the String variable with characters
Push SourceString
' Push the String variable's address
Pop DestString
' Pop the previously pushed String into DestString
Print DestString
' Display the string, which will be "Hello World"
Stop
Formatting a Push.
Each variable type, and more so, constant value, will push a different amount of bytes on to the stack. This can be a problem where values are concerned because it will not be known what size variable is required in order to Pop the required amount of bytes from the stack. For example, the code below will push a constant value of 200 on to the stack, which requires 1 byte.
Push 200
All well and good, but what if the recipient popped variable is of a Word or Dword type.
Pop Wrd
Popping from the stack into a Word variable will actually pull 2 bytes from the stack, however, the code above has only pushed on byte, so the stack will become out of phase with the values or variables previously pushed. This is not really a problem where variables are concerned, as each variable has a known byte count and the user knows if a Word is pushed, a Word should be popped.
The answer lies in using a formatter preceding the value or variable pushed, that will force the amount of bytes loaded on to the stack. The formatters are Byte, Word, Long, Dword or
Float.
The Byte formatter will force any variable or value following it to push only 1 byte to the stack.
Push Byte 12345
The Word formatter will force any variable or value following it to push only 2 bytes to the stack:
Push Word 123
The Long formatter will force any variable or value following it to push only 3 bytes to the stack: -
Push Long 123
The Dword formatter will force any variable or value following it to push only 4 bytes to the stack: -
Push Dword 123
The Float formatter will force any variable or value following it to push only 4 bytes to the stack, and will convert a constant value into the 4-byte floating point format: -
Push Float 123
So for the Push of 200 code above, you would use: -
Push Word 200
In order for it to be popped back into a Word variable, because the push would be the high byte of 200, then the low byte.
If using the multiple variable Push, each parameter can have a different formatter preceding it.
Push Word 200, Dword 1234, Float 1234
Note that if a floating point value is pushed, 4 bytes will be placed on the stack because this is a known format.
What is a Stack?
All microprocessors and most microcontrollers have access to a Stack, which is an area of RAM allocated for temporary data storage. But this is sadly lacking on a PICmicro™ device. However, the 18F devices have an architecture and low-level mnemonics that allow a Stack to be created and used very efficiently.
A stack is first created in high memory by issuing the Stack_Size Declare.
Declare Stack_Size = 40
The above line of code will reserve 40 bytes as a byte array that resides above Dimmed variables. This means that it is a safe place for temporary variable storage.
Taking the above line of code as an example, we can examine what happens when a variable is pushed on to the 40 byte stack, and then popped off again.
First the RAM is allocated as the byte array. For this explanation we will assume that a 18F452 PICmicro™ device is being used and the stack array starts at address 1495 within its RAM.
Pushing.
When a Word variable is pushed onto the stack, the memory map would look like the diagram below: -
Address 1535 Top of Memory ...................Empty RAM...................
Start of Stack
~ ~ ~ ~ ...................Empty RAM................... ...................Empty RAM................... Low Byte Address of Word Variable High Byte Address of Word Variable Address 1502 Address 1501 Address 1496 Address 1495 Address 1535 Top of Memory ....................Empty RAM................... ~ ~ ~ ~ ....................Empty RAM................... ....................Empty RAM................... Low Byte Address of Dword Variable Mid1 Byte Address of Dword Variable Address 1498 Address 1497 Address 1496 Address 1495 Address 1502 Address 1501 Address 1500 Address 1499 Mid2 Byte Address of Dword Variable High Byte Address of Dword Variable Low Byte Address of Word Variable High Byte Address of Word Variable
Start of Stack
Address 1535 Top of Memory ...................Empty RAM...................
Start of Stack
~ ~ ~ ~ ...................Empty RAM................... ...................Empty RAM................... Low Byte Address of Word Variable High Byte Address of Word Variable Address 1502 Address 1501 Address 1496 Address 1495 The high byte of the variable is first pushed on to the stack, then the low byte. And as you can see, the stack grows in an upward direction whenever a Push is implemented, which means it shrinks back down whenever a Pop is implemented.
If we were to Push a Dword variable on to the stack as well as the Word variable, the stack memory would look like: -
Popping.
When using the Pop command, the same variable type that was pushed last must be popped first, or the stack will become out of phase and any variables that are subsequently popped will contain invalid data. For example, using the above analogy, we need to Pop a Dword variable first. The Dword variable will be popped Low Byte first, then MID1 Byte, then MID2 Byte, then lastly the High Byte. This will ensure that the same value pushed will be reconstructed correctly when placed into its recipient variable. After the Pop, the stack memory map will look like: -
If a Word variable was then popped, the stack will be empty, however, what if we popped a Byte variable instead? the stack would contain the remnants of the Word variable previously pushed. Now what if we popped a Dword variable instead of the required Word variable? the stack would underflow by two bytes and corrupt any variables using those address's . The compiler cannot warn you of this occurring, so it is up to you, the programmer, to ensure that proper stack management is carried out. The same is true if the stack overflows. i.e. goes beyond the top of RAM. The compiler cannot give a warning.
Technical Details of Stack implementation.
The stack implemented by the compiler is known as an Incrementing Last-In First-Out Stack. Incrementing because it grows upwards in memory. Last-In First-Out because the last variable pushed, will be the first variable popped.
The stack is not circular in operation, so that a stack overflow will rollover into the PICmicro's hardware register, and an underflow will simply overwrite RAM immediately below the Start of Stack memory. If a circular operating stack is required, it will need to be coded in the main BA- SIC program, by examination and manipulation of the stack pointer (see below).
Indirect register pair FSR2L and FSR2H are used as a 16-bit stack pointer, and are incremented for every Byte pushed, and decremented for every Byte popped. Therefore checking the FSR2 registers in the BASIC program will give an indication of the stack's condition if required. This also means that the BASIC program cannot use the FSR2 register pair as part of its code, unless for manipulating the stack. Note that none of the compiler's commands, other than Push and Pop, use FSR2.
Whenever a variable is popped from the stack, the stack's memory is not actually cleared, only the stack pointer is moved. Therefore, the above diagrams are not quite true when they show empty RAM, but unless you have use of the remnants of the variable, it should be considered as empty, and will be overwritten by the next Push command.