Microchip present full details of the instruction set in [PIC, section 9, page 51 on]. [The page, figure, and table numbers reffered to here come from an older version of the '84 datasheet which is available at http://www.piclist.com/images/piclist/30445B.PDF the current datasheet for the modern version of the '84 is available at microchip.com] They group these into 3 categories which I dont find particularly useful. These are Byte- and Bit-oriented and Literal / Control operations. I have taken the view of grouping them into what we use each command for, such as performing arithmetic. Page 52 in [PIC] gives a one-page summary of the commands; I made a copy of this page loose from the data sheet, for easy reference. A windows help file is available on the Internet from Trisys Inc: I found this very useful. It contains details- similar to those in [PIC]- on the instruction set and the special function registers. Its a normal windows help file, with the expected hypertext links & searches.
For each instruction, I have explained the operation as described in [PIC], and have expanded on [PIC]s explanations where appropriate. (For instance, I have explained what an inclusive or actually is in IORWF.) Perhaps more importantly, I have suggested exercises to use the instructions as presented, with a possible solution given in the Appendix. The exercises suggested are quite trivial, but will afford you the opportunity to use each instruction, and also practice using the simulator. Remember to use things like the watch window to see whats going on as you step your program: keep an eye on registers you decide to use, as well as W and STATUS.
Microchips grouping does keep instructions of similar format together. The instructions look like this:
byte_command f,d
where f is the file register designation and d is the destination; if d=0, the result goes to the working register, w; if d=1, the result goes to register f
bit_command f,b
where f is the file register, and b is the bit therein; bits are numbered from 0 on the right, to 7 on the left. In the text, a bit is written as FILE_REG<n>, for instance INTCON<4> means bit no 4 in the intcon register at 0B
other_command k
where k is an 8-bit constant or literal.
The 84 implements a STATUS register at 03h, which contains the arithmetic
status of the arithmetic & logic unit; see [PIC fig 4-3]. Have a glance
down the Status Affected column of [PIC table 9-2], and you will
see that many 84 instructions affect certain parts of STATUS. Many
instructions affect STATUS<2>, Z- the Zero flag, which gets set if
the result of an operation was zero. Certain operations affect the carry
bits: STATUS<0>, C- the Carry bit, is set if a carry out occurs from
the left-most bit in the result; STATUS<1>, DC- the Digit Carry bit,
is set if there is a carry between the hex digits (ie, from the right hand
nybble (bit 3) to the left hand nybble (bit 4). Two commands affect
STATUS<3>, the Power Down bit PD, and STATUS<4>, the Time Out
bit TO.
We have met some of these instructions, which do nothing other than put things in registers.
(f) -> (dest)
MOVWF f (Move W to f, PIC p58)
(w) -> (f
MOVLW k (Move literal to W, PIC p58)
k -> (W)
Exercise: Write a program to use these commands to (for instance) put something into W, move it from there to another register, put something else into W, and then move the original thing back to W. See moves .asm.
These 2 commands clear a register.
00h -> (f)
00h -> (W)
Exercise: Expand the above program to clear registers at the end. See clears .asm .
Performing arithmetic is pretty important: thats why computers are called computers after all. The 84 can only add and subtract though.
Arithmetic occurs either between W and an f register:
ADDWF f,d (Add W & f, PIC p53)
(W)+(f) -> (dest)
SUBWF f,d (Subtract W from f, PIC p61)
(f)-(W) -> (dest)
or between W and a literal:
ADDLW k (Add literal & W, PIC p53)
(W)+k -> (W)
SUBLW k (Subtract W from literal, PIC p61)
k-(W) -> (W), [PIC p61]
Exercise: Use these and previous commands to load some registers and W, and do some adding and subtracting. Keep a close eye on the carry bit and on the zero bit in the status register. See arith .asm.
Technical aside: You may see in [PIC] that subtraction is performed using the 2s complement method. ¿Que? I hear you ask. This is the normal way that subtraction occurs in binary. Ill explain, then look at an example. Express both numbers in binary. Leave the number from which you are taking away, unchanged. Form the 2s complement of the one which is being taken away thus: change all 0s to 1s and all 1s to 0s (this is the complement), add 1 to the right hand digit, carrying to the left as necessary. Now add the result to the unchanged other number. Discard the carry at the left, if there is one. Thats the answer. Lets check . .
If we want to subtract 20 from 27 we should get 7. Proceed as follows:
Convert to binary:
27 -> 11011 . . . . x
20 -> 10100 . . . . y
Make 2s complement of y by inverting each bit and adding one
10100 . . . . y
01011 complement:
+ 00001 add 1
= 01100 . . . . z
Add x and z:
01100 . . . . z
+ 11011 . . . . x
[1]00111 = 7 QED.
The 1 in brackets is the carry, which gets discarded.
At this stage, before we examine the logical functions provided by the 84, well discuss what logical functions are. Consider for the time being an electronic device of some description, with 3 wires attached. Lets say that 2 wires are inputs, and that what gets output on the 3rd wire depends on the inputs. Further, well say that this is a digital device, so that the 3 wires can only have binary values of 1 & 0.
What relationships can exist, then, between the 2 inputs and the output? The input combinations are easy: if wire/pin 1 can be 0 or 1, and so can pin 2, then the combinations are 00, 01, 10 & 11. What about pin 3: perhaps it must be a 1 if and only if the inputs are both 1 (ie 11); or perhaps a 1 if either or both inputs is 1 (ie 01, 10, 11). Or whatever!
The basic relationships are known as and and or; and
means both inputs while or means either or both. Most explanations
of this resort to the so called truth table, which I have drawn below
for the following logical operations: and, or, xor, nand, nor. Ill
explain them once youve had a look at the table.
Inputs A B | A AND B | A OR B | A XOR B | A NAND B | A NOR B |
both | either, both | either, not both | not both | neither, not both | |
00 | 0 | 0 | 0 | 1 | 1 |
01 | 0 | 1 | 1 | 1 | 0 |
10 | 0 | 1 | 1 | 1 | 0 |
11 | 1 | 1 | 0 | 0 | 0 |
The function and means that the result is 1 only when both inputs are 1. The or means that either input may be a 1 for output to be 1, but so may both. The function xor means exclusive or, and means that either input as 1 will cause a 1 to be output, and specifically excludes the situation where both inputs are 1. Lastly, the nand and nor are the negations of and and or respectively: compare the columns and youll see what this means.
By the way, the or function (as opposed to the xor function) is sometimes known as the inclusive or (ior). The 84 in fact uses this term.
The 84 provides a number of logical operations which act on 2, 8-bit values; these values are compared bit for bit. For example- without yet looking at an 84 instruction- consider the anding (is there such a word?) of the numbers H5F (equivalent to D95 and B01011111) and HA3 (which is D163 and B10100011); resulting in H03 (which is D3 or B00000011).
5F: 01011111 A3: 10100011 and: 00000011
Clearly, only in the rightmost 2 positions is the and satisfied, resulting is 1s there and 0s elsewhere. You should check this on the calculator in Windows, which has logical functions built in.
So, lets move to the instructions as provided by the 84.
Comparison occurs either between W and an f register:
ANDWF f,d (AND W with f, PIC p53)
IORWF f,d (Inclusive OR W with f, PIC p58)
XORWF f,d (Exclusive OR W with f, PIC p62)
or between W and a literal:
ANDLW k (AND literal with W, PIC p53)
IORLW k (Inclusive OR literal with W, PIC p57)
XORLW k (Exclusive OR literal with W, PIC p62)
Lastly, you may have noted that the 84 doesnt provide nand or nor functions. Rather, it provides the means of complementing (negating) a register; this means to nand you must first and and then com:
COMF f,d (Complement f, PIC p56)
complement of (f) -> (dest)
Exercise: I suggest 2 things here. First, using Windows calculator, verify the results of the examples in [PIC] with each of the above: this will ensure that you understand the concepts. Then, write an assembler program to verify the 84 instructions, by loading the appropriate registers, performing the actions, then checking the results. See logic .asm.
5: Decrementing & Incrementing
Two simple instructions can decrement or increment the contents of a register, thus:
DEC f,d (Decrement f, PIC p56)
(f)-1 -> (dest)
(f)+1 -> (dest)
Exercise: In a program, perhaps by adding to one of the previous ones in which you do some arithmetic or some logic, check out that these commands do work. Keep an eye on the Zero flag, which is set if either command causes the register in question to go to zero: well rely on this fact in 2 more commands later. See dec_int .asm
6: Bit setting & clearing
Using the following 2 commands, you can set or clear any bit b in register f. But why would we want to? Two reasons come to mind:
First, as an example, the register in question might be a port controlling some external equipment. Each bit could be switching a different device: a motor, a light or whatever. Setting and clearing each bit switches each device on or off.
Second, as well see in 8. below, we can use the fact that a bit is set or clear to skip instructions in our program. Being able to set or clear any bit gives us the ability to control this process.
BCF f,b (Bit clear f, PIC p54)
0 -> (f<b>)
1 -> (f<b>)
We read these two operations as "0 (or 1) becomes the content of bit b in register f".
Exercise: Sprinkle these commands into any of the programs above, and watch the changes to individual bits in your watch window. See bits .asm
7: Program control
For many reasons, we need to control the flow through our program. Normally, flow proceeds linearly from the top; often this is not suitable.
Firstly, we often need to loop through certain instructions: we might have a system in which one process is a continuous one. This might be the control of a bucket conveyor which continuously adds ingredients to a vat. Here, when a bucketful is added, we take it from the top and go through the same steps again, adding more on each pass.
Second, there may be part of our program which is useful in many other parts. Rather than repeating this code in many places, we separate the piece we like from the rest of the code; then we merely call it in as often as we like, from wherever. The reusable piece is called a subroutine. The subroutine returns control to the point from which it was called when its finished.
Lets look at looping first:
GOTO k (Go to address, PIC p57)
k -> (PC)
This instruction literally goes to k, which it does this by loading the address of k into the program counter, PC. In order to use goto you should start the line to which you want to go, with a label. Then you goto label. See [MPASM p15] for rules on labels.
Exercise: Modify one of the programs you have already written. You could put a label near the top, and a goto later on. As you step, youll see from the highlighted line that your program loops through the same part again and again. Look at the program counter (pcl) in a watch window and youll verify this. See goto .asm
Now we shall examine subroutines. We need to understand the concept of the stack first. Look at [PIC figure 4-1] and youll see a connection between the program counter and the stack. The stack- which has 8 levels in the 84- is the repository of where the PC was before the subroutine was invoked. This is so that the program can go back to take up where it left off when the subroutine is finished. Strictly speaking, the stack is loaded with the address of the instruction immediately after the one doing the sending; otherwise it would keep on going back and performing the instruction it had done earlier- we really want the next one. We refer to loading the stack as pushing and taking a value off later as popping. The stack is only accessible at the top: its like a pile of plates in one of those hoppers in a restaurant. The top of the stack is abbreviated as TOS.
There are 2 instructions associated with any subroutine- one to send the program off to it, the other to bring it back:
CALL k (Call subroutine, PIC p55)
(PC)+1 -> TOS, k -> (PC)
The call to a subroutine pushes the current PC+1 onto the stack, then changes the PC to the address k. This results in program flow jumping to the subroutine, but the address to come back to later is safely ensconced on the stack for later retrieval.
RETURN (Return from subroutine, PIC p60)
TOS -> (PC)
Return is the last instruction in the subroutine itself. The return instruction pops the stack, and so the program resumes in the right place. Think about the depth of the stack: it means that calls can be nested, and flow will be correct as long as the calls are matched by returns. Consider the following, which is OK:
CALL . . . . . push 1st address CALL . . . . push 2nd address RETURN. . . . pop 2nd address RETURN. . . . . pop 1st address.
But we dont want this, which is not OK:
CALL . . . . push 1st address CALL . . . push 2nd address RETURN . . . pop 1st address RETURN . . pop 2nd address.
As an alternative to the vanilla-flavoured return, you can bring a value back with you, thus:
RETLW k (Return with literal in W, PIC p59)
k -> (W), TOS -> (PC)
This is the normal return, with the k -> (W) added.
Exercise: Write a program to execute some code- anything you like- and then branch to a subroutine to do something else. Check that you return correctly. Use both types of return.
Problems? You probably had a little difficulty wondering where to put the subroutine in the source. How do you stop the subroutine being run by mistake? Because wherever you put it- either above or below the main part of the program, the programs natural flow will go through the subroutine, which is called subby here. If the stack is empty , this causes a stack underflow error, as when the subroutines return is encountered before a call has been made. If the stack has indeed been pushed by some other event- like an interrupt- then the return would be honoured but incorrectly.
;example 1 ;example 2 . . . . label subby call subby . subby code here . . and here . return label subby . . subby code here . . and here call subby return . . . .
The way around this seems to be to proceed more or less as example 1, with the subroutines at the top. But, down below where the main part of the program is, have a label like start; above the subroutines, have a goto start to hop over them in the normal course of things. When a subroutine is called, the program shoots to the top: one subroutine will not flow into another, because the return will take care of this. Thus:
goto start label subby1 . return label subby2 . return start . . call subby2 . call subby1 . . etc
Associated with these last 2 commands is another type of return, which is to do with interrupts. We will look at interrupts later, but for completeness Ive put the return from interrupt here:
RETFIE (Return from Interrupt, PIC p59)
TOS -> (PC), 1 -> GIE
When an interrupt occurs, the PC is pushed to the stack like with a subroutine call, so retfie pops it back out. Also, though, the occurrence of an interrupt disable further interrupts: one doesnt want interrupts interrupted after all. What happened was, that the interrupt caused the global interrupt enable flag, GIE (INTCON<7>) to be set to 0. Returning from an interrupt means that further interrupts should be allowed, hence retfie sets GIE back to 1.
There are 4 instructions which allow you to skip over the next instruction. Ill explain this before we look at the commands themselves.
In the conveyor example above, we dont want the vat to overflow, so lets have a level sensor in the vat (just like the ball-valve in the loo) which switches on when the vat is full. The conveyor is running, adding bucketsful; the program needs to monitor the switch, and when the vat is full (the switch closes) the program switches off the conveyor and starts some other part of the process, perhaps the mixer. This process is shown below: the dots show some or other process happening before and after the part of interest. Ive used line numbers for ease of reference. This is not in 84 assembler!
. line # 40: start conveyor . . line # 63: is the level sensor switch set? line # 64: no- go back to line # 63 and look again line # 65: yes- stop the conveyor line # 66: start the mixer and carry on . .
In this example, we need to skip line 64 when the vat is full. When the vat still has room, this code will cause more ingredient to be added; the conveyor will stop and the mixer will start when the vat full sensor has switched on.
Now we can look at the commands which do this skipping in the 84:
DECFSZ f,d (Decrement f, skip if 0, PIC p56)
(f)-1 -> (dest), skip if result = 0
INCFSZ f,d (Increment f, skip if 0, PIC p57)
(f)+1® -> (dest), skip if result = 0
The above commands are based on the decf and incf commands seen earlier: the sz part means skip if zero.
Exercise: Verify these 2 instructions by loading a start value into a register called count or something. Then use either instruction to change it, looping through this block of code. Check that the instruction following the decfsz or incfsz (probably a goto, to cause the looping) is skipped or not, as appropriate. (This approach would work if the conveyor had to add say 10 bucketsful, rather than wait for a sensor.) See skip .asm.
BTFSC f,b (Bit test f, skip if clear, PIC p54)
skip if (f<b>)=0
BTFSS f,b (Bit test f, skip if set, PIC p55)
skip if (f<b>)=1
Read these instructions as bit test f, skip if clear/set".
These commands could be used to check the vat full sensor mentioned above. The bit to be tested would be the bit of a port on the 84: it would be set or cleared by the sensor from time to time.
Exercise: Write a program with a block of code to loop through. These can be just about any instructions, and will simulate the conveyor as nonsense. Have a btfss at the bottom, followed by a goto back to the top. Have some more code then, which simulates the mixer coming on. The btfss will need to refer to one of the 84s I/O ports as its f (H05 or H06 for porta & b respectively), and you can use any pin 0-4 on porta, 0-7 on portb you wish. You should have another goto right at the bottom, to make a sort of outer loop back to the top- this might not be too real-life, but youll want the whole program to loop to test what happens when the pin changes. See bits .asm
But how do we get the pin to change its state, simulating the vat full sensor? Theres an easy way of doing this in MPLABs simulator. Go Debug > Simulator stimulus > Asynchronous stimulus; youll get a table of Stim0 to Stim12 buttons. Right click on any one, perhaps Stim7, and click Assign pin. Double click on the pin youve elected to use as the sensor, perhaps it was RA3, say. Stim7 then changes to RA3 . Now right click on the button again: you can choose to pulse, make low, make high or toggle the pin. Here, we would want to toggle the pin, since the vat sensor will be changing from time to time probably, as it empties and fills.
Now were all set to test. Step through your program. Depending on the
initial state of the pin, which [PIC table 4-1] says is unknown at power
up, the program will loop or not. (At the inner loop, that is; it will always
go back to the top from the very bottom, for testing purposes.) Any time
you like, left click on your chosen Stim button, now known as RA3 or whatever.
(If you have the port showing in a watch window, youll see the pin
change state at the next instruction boundary.) In any case, next time the
program gets to the btfss step, it should behave differently, since
weve toggled the pin and so the btfss should get a different
answer.
Three instructions allow you to manipulate the bits within a register. Of these, two slide the bits to the right or left (through the carry bit), the third switches the registers two nybbles over.
RRF f,d (Rotate right f thru carry, PIC p60)
Each bit in the f register is moved 1 to the right; the one that falls off the right is circled round to the carry, and the carry moves in from the left.
RLF f,d (Rotate left f thru carry, PIC p60)
Each bit in the f register is moved 1 to the left; the one that falls off the left moved into the carry, and the carry is circled round to the right.
SWAPF f,d (Swap nybbles in f, PIC p62)
(f<3:0) -> (dest<7:4>), (f<7:4>) -> (dest<3:0>)
Exercise: Observe the effect of these commands on the contents of some registers. See rot_swap.asm.
10: Sleep & Watchdog Timer
These 2 commands are related, in that the WDT is one of the ways of waking up from sleep. I cover the whole notion of timers later, so for now accept these instructions for what they are.
0 -> WDT, 0 -> WDT prescaler, 1 -> TObar, 0 -> PDbar
CLRWDT (Clear watchdog timer, PIC p56)
0 -> WDT, 0 -> WDT prescaler, 1 -> TObar, 1 -> PDbar
This instruction literally does nothing
You should not use the following 2 instructions, which are included to provide backward compatibility:
We have now met each 84 instruction, with the necessary background if appropriate, and used them in simple programs. Now, well move on to explore two important areas of the PIC84: interrupts and timers. It is these two areas which move the 84 into the real world.
file: /Techref/microchip/intro/slide5.htm, 30KB, , updated: 2011/7/21 12:03, local time: 2024/8/31 16:05,
owner: size111-hotmail-,
18.119.132.24:LOG IN
|
©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://massmind.org/techref/microchip/intro/slide5.htm"> begin</A> |
Did you find what you needed? |
Welcome to massmind.org! |
Welcome to massmind.org! |
.