CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Understanding ASM Interrupt setup

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
joshkeys



Joined: 16 Aug 2005
Posts: 37
Location: Fredericton,NB

View user's profile Send private message Send e-mail MSN Messenger

Understanding ASM Interrupt setup
PostPosted: Tue Dec 12, 2006 8:02 pm     Reply with quote

Hi there, I am using a PIC12F675 and have set up an interrupt via the timer 0 overflow. After compiling the program, I was going through the ASM code used to implement the interrupt and am a little confused by a few of the lines as below.

Code:

.
.
.
0004:  BTFSC  03.5
0005:  GOTO   00A         (1)
0006:  MOVWF  22
0007:  SWAPF  03,W        (2)
0008:  MOVWF  23
0009:  GOTO   00F
000A:  BCF    03.5
000B:  MOVWF  22
000C:  SWAPF  03,W        (2)
000D:  MOVWF  23
000E:  BSF    23.1        (3)
000F:  MOVF   0A,W
0010:  MOVWF  27
0011:  CLRF   0A
0012:  BCF    03.7
0013:  SWAPF  22,F        (2)
0014:  MOVF   04,W
0015:  MOVWF  24
0016:  MOVF   20,W
0017:  MOVWF  25
0018:  MOVF   21,W
0019:  MOVWF  26
.
.
.
(Code goes on to check for what interrupt was activated and go to the appropriate ISR, and then when returned from it to reload all of the registers to there original state)


(1) So first of all, the starting code seems like a waste of memory. It checks to see if the bank is set to 0 or 1, and does the nearly the same operation for either case (The exception being my third question). Would it not be more feasible to just set the bank to 0 and then proceed instead of setting up 2 scenarios.


(2) Basically the status register in 2 cases and W registeris in one case are copied to a temporary interrupt register, but the LSB and MSB are swapped. I cannot seem to make sense of this. Can anyone explain why this is done, i am probably staring right at the answer, but am not sure.


(3) For some reason, bit 1 of the temporary register is set. The register contains the swapped bits of the status register.


Thanks for any help in advanced!

Thanks,
Josh Keys
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Wed Dec 13, 2006 6:49 am     Reply with quote

(2) Using the swap instruction is a common used trick in PIC assembly for copying register contents without modifying the status register flags.

(1) What is happening here is that the Working and Status registers are saved for restoration at the interrupt end. A chicken and egg problem is that you will modify the W-register when saving the status register, but the W-register can only be saved to a known location by selecting the correct memory bank in the Status register first. The CCS solution is to enter different code paths, one for each bank register bit.

Maybe other solutions are possible but I don't see an obvious one.

Note: Data of the status register is saved with the two nibbles swapped, but for temporary data storage this is no problem. At the end of the interrupt handler the register is restored using a swap instruction again.

(3) In (1) the status of the bank select register was memorized by splitting the program flow in two almost identical sections. Here in (3) the bank select bit is finally written to the saved status register.
joshkeys



Joined: 16 Aug 2005
Posts: 37
Location: Fredericton,NB

View user's profile Send private message Send e-mail MSN Messenger

Thanks
PostPosted: Wed Dec 13, 2006 10:13 am     Reply with quote

It all makes sense now.. I guess I overlooked that you need to also save the status of the bank you were at when going to an interrupt, hence the need for 2 cases. And the swap thing just threw me for a loop.. clever little trick, easy once you know why they use it Razz Thanks for the help! It drives me crazy when I cannot understand why something was done!

Josh Keys
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Dec 13, 2006 10:17 am     Reply with quote

This may be helpful to you. Back in May 2000 on the old CCS board,
Stefan Daystrom wrote up an explanation of how the CCS interrupt
dispatcher code works. It used to be in the old archives, but I think
they've been taken down. However I kept a copy on my local machine,
and I've re-posted it below. The code is not exactly the same as the
modern compiler code, but his explanations should still help you.

For each section of code, his explanation is posted below the code.
It starts off with someone asking a question about the CCS interrupt
dispatcher code:
Quote:

I have to write a In Service Routine as fast as possible for PIC16C74B.
I tried to use the #INTxxx directive but it generated a long code at
address 0004. This code is too long for my application. For this reason
I have to use the #INT_GLOBAL directive, but I am afraid about it.
Have anybody used this directive ?

I tried to understand the code generate by #INTxxx directive to use in
my Global In Service Routine, but some lines seem without meaning.
Why is this code so long ? Can anybody explain this code ?

Yes. Look below for interspersed comments:

Code generated at address 0004 using the #int_rda directive
before the ISR:
Code:
: 0004 1D8A 00005 BTFSS 0A,3
: 0005 120A 00006 BCF 0A,4
: 0006 198A 00007 BTFSC 0A,3
: 0007 160A 00008 BSF 0A,4

Backs up the one bit of PCLATH that matters on
a PIC16C74 to an unused bit of PCLATH (for now).


Code:

: 0008 118A 00009 BCF 0A,3

Clears the one used bit of PCLATH, since we're on page 0.


Code:

: 0009 1A83 00010 BTFSC 03,5
: 000A 280F 00011 GOTO 00F
: 000B 00A5 00012 MOVWF 25
: 000C 0E03 00013 SWAPF 03,W
: 000D 00A6 00014 MOVWF 26
: 000E 2814 00015 GOTO 014
: 000F 1283 00016 BCF 03,5
: 0010 00A5 00017 MOVWF 25
: 0011 0E03 00018 SWAPF 03,W
: 0012 00A6 00019 MOVWF 26
: 0013 14A6 00020 BSF 26,1

Saves the W and STATUS registers in a tricky way
that's a bit differnt from Microchip's suggested
way (in "Context Saving During Interrupts" in the
PIC16C6X or PIC16C7X data book). The compiler
does it this way to save RAM over Microchip's
way, at the expense of a little more ROM used.
Microchip's way requires knowing that the place
where W is saved is one of several addresses in
the same relative place in every available bank;
since the compiler doesn't allocate memory that
way, Microchip's way would be incompatible with
compiler use, so you'd have to use the same
method that the compiler is using here.


Code:

: 0014 080A 00021 MOVF 0A,W
: 0015 00AD 00022 MOVWF 2D

Backs up PCLATH for real.


Code:

: 0016 0EA5 00023 SWAPF 25,F

Swaps the nibbles of the saved W, so that it
can restore it later with a single 'SWAPF 25,W'
instruction that won't disturb the STATUS register.


Code:

: 0017 0804 00024 MOVF 04,W
: 0018 00A7 00025 MOVWF 27

Backs up the FSR.


Code:

: 0019 0820 00026 MOVF 20,W
: 001A 00A8 00027 MOVWF 28
: 001B 0821 00028 MOVF 21,W
: 001C 00A9 00029 MOVWF 29
: 001D 0822 00030 MOVF 22,W
: 001E 00AA 00031 MOVWF 2A
: 001F 0823 00032 MOVF 23,W
: 0020 00AB 00033 MOVWF 2B
: 0021 0824 00034 MOVF 24,W
: 0022 00AC 00035 MOVWF 2C

Backs up compiler temporary variables.
How many there are can vary as you add things to
the program. If you were doing the #INT_GLOBAL,
you'd have to figure out yourself what temporary
variables the C code used in your interrupt
might be using by very carefully analyzing the
generated assembly of all code explicitly or
implicitly called from your C interrupt code,
and back those up. And, of course, make sure
you allocated the variables you back up into so
that no C memory allocation can clobber them.


Code:

: 0023 1283 00036 BCF 03,5

We're already in RAM bank 0, so the above line
seems unnecessary (unless something not shown
here can to a GOTO 023).


Code:

: 0024 1E0B 00037 BTFSS 0B,4
: 0025 2828 00038 GOTO 028
: 0026 188B 00039 BTFSC 0B,1
: 0027 2840 00040 GOTO 040

If INTE is FALSE or INTF is FALSE (both in INTCON),
there's no interrupt, so drops down to 0028 below.
Otherwise it branches to the last bit of
interrupt initialization at 0040.


Upon completion of interrupt code, it starts
returning from interrupt here:
Code:

: 0028 0827 00041 MOVF 27,W
: 0029 0084 00042 MOVWF 04
: 002A 0828 00043 MOVF 28,W
: 002B 00A0 00044 MOVWF 20
: 002C 0829 00045 MOVF 29,W
: 002D 00A1 00046 MOVWF 21
: 002E 082A 00047 MOVF 2A,W
: 002F 00A2 00048 MOVWF 22
: 0030 082B 00049 MOVF 2B,W
: 0031 00A3 00050 MOVWF 23
: 0032 082C 00051 MOVF 2C,W
: 0033 00A4 00052 MOVWF 24
: 0034 082D 00053 MOVF 2D,W
: 0035 008A 00054 MOVWF 0A
: 0036 1A0A 00055 BTFSC 0A,4
: 0037 158A 00056 BSF 0A,3
: 0038 120A 00057 BCF 0A,4
: 0039 0E26 00058 SWAPF 26,W
: 003A 0083 00059 MOVWF 03
: 003B 1283 00060 BCF 03,5
: 003C 0E25 00061 SWAPF 25,W
: 003D 18A6 00062 BTFSC 26,1
: 003E 1683 00063 BSF 03,5

The above restores all the stuff that was backed
up above. Exactly how is left as user exercise. :)


Code:
: 003F 0009 00064 RETFIE

The actual return from interrupt instruction.


The code below was jumped to from 0027 above:
Code:
: 0040 118A 00065 BCF 0A,3

For the GOTO 040 at 0027 to have worked, bit 3
of PCLATH would already have to be clear, so why
is it being recleared here? :)


Code:
: 0041 286A 00066 GOTO 06A

Goes off to run the C code you wrote in the
interrupt.


In summary: There are only two instructions
that seem totally unnecessary above. Then
depending on your specific interrupt code,
perhaps not ALL the stuff that's being backed
up would need to be backed up, but you'd have
to careful analysis to make sure of that. Besides
some of the C temporary variables, the most
likely register it backs up that MIGHT not be
used in your interrupt code is FSR.

But unless you can get rid of quite a few
temporary variables from being in need of backup,
I don't see a whole lot of tightening up of this
code you could do if your ISR is going to be
written in C. If you write it ALL in assembler
and can therefore make sure it doesn't use ANY
of C's temporary varilabes, doesn't use PCLATH,
doesn't use FSR, etc, only THEN can you shave
it down quite a bit...
joshkeys



Joined: 16 Aug 2005
Posts: 37
Location: Fredericton,NB

View user's profile Send private message Send e-mail MSN Messenger

Thanks
PostPosted: Thu Dec 14, 2006 1:01 pm     Reply with quote

Thanks PCM Programmer, excellent resource.

Josh
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group