News:

SMF for DIYStompboxes.com!

Main Menu

Memory Pages in the 16F84

Started by gez, March 12, 2006, 04:47:13 PM

Previous topic - Next topic

gez

OK, my questions relate specifically to the following program which generates a stepped sine wave:

http://www.qsl.net/yo5ofh/pic/tonef84/stepdds.asm

According to the data sheet the 16F84 has 1024 words of program memory, which translates as 1024 instructions (or so I'm told).  The whole program falls well within that amount so why is the lookup table on a separate 'memory page'?  Is the 1024 instruction limit spread out over these pages?  If so, how many pages does the 16F84 have, how many instructions can each page handle and how does one select each page? 

From what I gather, selection is done via the PCLATH register but documents I've read are as clear as mud on all this.  In the above program 'page 2' is selected by loading a '1' into PCLATH, so does loading a '2' get you on to page 3??  Is there a diagram showing these 'pages' locations (doesn't seem to be one in the data sheet)?

And lastly, why is the table twice as long as it need be (it repeats itself after 127 steps)? 





"They always say there's nothing new under the sun.  I think that that's a big copout..."  Wayne Shorter

Peter Snowberg

        org     0xFF
; sinetbl - a table of sine wave values - 2 x 128 bytes in length
;  the values were generated with the Qbasic program: sine10.bas
;   and then inserted into this program twice to create the full table
; Question:  Why does this routine start at address FF?
; Answer:  Because the table is originally 256 entries long - the only
;       easy/quick way to access the table is to have all the entries on
;       the same 256 word memory page.
  The register PCLATH is preset
;       during initialization to always point to page 1 (address 100h) so
;       that the result of the addwf to PCL always points to page 1.
sinetbl addwf   PCL,1   ;compute the jump value
        retlw     128 ; 0    0
        retlw     134 ; 1    4.906764E-02
        retlw     140 ; 2    9.801706E-02
        retlw     146 ; 3    .1467304
        retlw     152 ; 4    .1950902
        retlw     158 ; 5    .24298

;)


The PIC is a little wanky in order to save on transistors so you see tricks like the one above. In that table they use brute-force for indirect addressing which the PIC does not really include. Pages are 256 words long with each address ranging from $00 to $FF. There are 8 pages in 1K, numbered $0 to $7.  The early PICs with would allow you to have a string of up to 512 instructions (2 pages) before they would loop back to the first one because the program counter was only 9 bits wide. You can execute code inside the $000 to $1FF range, but you need to jump if you want to get outside of that.

To make their table, they load up their indirect index into W and then call (or GOSUB) to $FF where there is an ADD instruction waiting. The ADD grabs the program counter's current value (which has already incremented to $100 from $0FF), adds W, and then dumps the result back on the program counter which makes the next instruction to run the one at address $100+W. All the instructions in the table are returns that leave their value in W on the way out.

This was described in an app note from around 1990-1991. The early books also had lots of tables to show details. You may find something of use on that early architecture device by looking in the docs for the 16C5x family.

Why is it repeating half the data? I don't know. Probably Elvis.
Eschew paradigm obfuscation

gez

Quote from: Peter Snowberg on March 12, 2006, 05:23:51 PMPages are 256 words long with each address ranging from $00 to $FF. There are 8 pages in 1K, numbered $0 to $7.

Thanks for the reply, but I'm still confused.  So I can only write a program that has a max of 256 instructions then I have to continue on another page? 

I saw the lines you highlighted, which is why I asked if the 1024 instruction limit is spread over separate pages.  If that's the case, and there's a 256 instruction limit per page, then there are only 4 pages surely?

"They always say there's nothing new under the sun.  I think that that's a big copout..."  Wayne Shorter

bioroids

Quote from: Peter Snowberg on March 12, 2006, 05:23:51 PM
        org     0xFF
; sinetbl - a table of sine wave values - 2 x 128 bytes in length
;  the values were generated with the Qbasic program: sine10.bas
;   and then inserted into this program twice to create the full table
; Question:  Why does this routine start at address FF?
; Answer:  Because the table is originally 256 entries long - the only
;       easy/quick way to access the table is to have all the entries on
;       the same 256 word memory page.
  The register PCLATH is preset
;       during initialization to always point to page 1 (address 100h) so
;       that the result of the addwf to PCL always points to page 1.
sinetbl addwf   PCL,1   ;compute the jump value
        retlw     128 ; 0    0
        retlw     134 ; 1    4.906764E-02
        retlw     140 ; 2    9.801706E-02
        retlw     146 ; 3    .1467304
        retlw     152 ; 4    .1950902
        retlw     158 ; 5    .24298

;)


The PIC is a little wanky in order to save on transistors so you see tricks like the one above. In that table they use brute-force for indirect addressing which the PIC does not really include. Pages are 256 words long with each address ranging from $00 to $FF. There are 8 pages in 1K, numbered $0 to $7.  The early PICs with would allow you to have a string of up to 512 instructions (2 pages) before they would loop back to the first one because the program counter was only 9 bits wide. You can execute code inside the $000 to $1FF range, but you need to jump if you want to get outside of that.

To make their table, they load up their indirect index into W and then call (or GOSUB) to $FF where there is an ADD instruction waiting. The ADD grabs the program counter's current value (which has already incremented to $100 from $0FF), adds W, and then dumps the result back on the program counter which makes the next instruction to run the one at address $100+W. All the instructions in the table are returns that leave their value in W on the way out.

This was described in an app note from around 1990-1991. The early books also had lots of tables to show details. You may find something of use on that early architecture device by looking in the docs for the 16C5x family.

Why is it repeating half the data? I don't know. Probably Elvis.


You can write to the program counter on PICs? That's interesting.


Eramos tan pobres!

Peter Snowberg

I looked at the 16C84 docs and it doesn't have the 512 byte limitation that the 5x series chips had; so forget about that stuff. SOrry.  :icon_redface:

The program can span up to 8 pages in the 16C84.

Pages can also get used in some other ways to refer to pieces of memory that are larger than 256 bytes, but that's less common.

Yes, you can write to the program counter on lots of chips. It's a nice feature. :D
Eschew paradigm obfuscation

R.G.

Even Microchips is trying to steer people away from the F84 and on to the F628/629 and the F818 and F819. by making these very cheap.
R.G.

In response to the questions in the forum - PCB Layout for Musical Effects is available from The Book Patch. Search "PCB Layout" and it ought to appear.

jrem

#6
Quote from: gez on March 12, 2006, 04:47:13 PM
OK, my questions relate specifically to the following program which generates a stepped sine wave:

http://www.qsl.net/yo5ofh/pic/tonef84/stepdds.asm

According to the data sheet the 16F84 has 1024 words of program memory, which translates as 1024 instructions (or so I'm told).  The whole program falls well within that amount so why is the lookup table on a separate 'memory page'?  Is the 1024 instruction limit spread out over these pages?  If so, how many pages does the 16F84 have, how many instructions can each page handle and how does one select each page? 

From what I gather, selection is done via the PCLATH register but documents I've read are as clear as mud on all this.  In the above program 'page 2' is selected by loading a '1' into PCLATH, so does loading a '2' get you on to page 3??  Is there a diagram showing these 'pages' locations (doesn't seem to be one in the data sheet)?

And lastly, why is the table twice as long as it need be (it repeats itself after 127 steps)? 


okay, I've glanced through that program, and know why he set the org to FF for the RETLW . . .   the problem is that when you are doing a lookup on a table, if that table crosses page boundries then you have a nightmare on your hands to figure out the right address.  So, although I've been told it's not the right way to do things, what I have done (which is what's been done here) is make sure your table origin is on a new page, and make sure your table is smaller than the page limit. 

You are right, the way to do it is with PCLATH, but if you're not starved for memory (like in the day) then who cares if there are some zeros between code in the controller?

Now, I think the question is, if the memory is 1024, why the 255 page limit?  Well, the PIC's play games to get more memory access.  The word is really only eight bits wide, but they add some extra addressing bits to make it thirteen (I think, gotta check the data sheet and I've been deep into a non-PIC project the past few months) bits wide so you can access more than #FF memory locations.  Make sense?  FF = 255, crossing that barrier means dicking around with PCLATH, or just make sure your table starts at the beginning, and jump right to it.

Also, without looking too deep at the table, my guess is he's going through the table twice for a complete cycle, he probably figured it was easier just to do the complete cycle lookup than to set a bit when it swung around and do the logic to determine where he was in the cycle, if that makes any sense. 

Finally, I would strongly suggest just making the leap and buying the 16F628 instead of the 16F84, they are MUCH cheaper, and there almost exactly the same, you can debug that code very easily and make it run on the newer chip.  That way when you let the smoke out of it it will only cost you $1.25 instead of $5.50.

Regards, John.

Dave_B

Quote from: Peter Snowberg on March 12, 2006, 05:23:51 PM
Why is it repeating half the data? I don't know. Probably Elvis.
Considering the way he's counting every cycle, is it possible it was just easier to use the full 256 bytes and let it 'roll over' rather than add code to recycle after 128?  It's too early for me to process what he did, but I know I've got some things in my tables that I wouldn't offer to the world.   :)
Help build our Wiki!

gez

Thanks for all the information chaps, much appreciated.  Bit by bit I'm getting a clearer picture of the architecture of this chip (and thanks jrem for the sub recommendation).

I learnt from another forum that 'bank' is interchangeable with the term page, and all of a sudden I'm finding info via indexes in my books ( :icon_rolleyes:). 

Still confused about the finer points of PCLATH, but I'll keep reading.  Thanks again.
"They always say there's nothing new under the sun.  I think that that's a big copout..."  Wayne Shorter

Transmogrifox

Quote from: bellyflop on March 13, 2006, 11:03:29 AM
Quote from: Peter Snowberg on March 12, 2006, 05:23:51 PM
Why is it repeating half the data? I don't know. Probably Elvis.
Considering the way he's counting every cycle, is it possible it was just easier to use the full 256 bytes and let it 'roll over' rather than add code to recycle after 128?  It's too early for me to process what he did, but I know I've got some things in my tables that I wouldn't offer to the world.   :)

Exactly.  Back to gez's question about writing programs with 256 byte length: this is not a limitation, but just something to be cautious about.  I had programmed an RS232 communication and message reply routine in the 16F84 and it was getting partially through the output message, then it would go back to reset.  I had been too lazy to look at the disassembly to discover my program was more than 256 bytes long.  What was happening is that the program crossed the 256 byte mark (the first page), and without setting PCLATH (which is your access register to the high bits of the program counter), it was just rolling over the program counter and starting back at 0 (reset).  If at that point in the table I had put some code to increment the PCLATH register, then it would have gone on as normal.

It was much easier just to locate my lookup table on a different memory page and set the PCLATH register from the main program call rather than trying to fondle it mid-table.

Basically, you need to just keep in mind when organizing your program memory, that if your program exceeds 256 bytes you will have to do memory page changes at those points.  This turns some people away from PICs because this memory page thing can get to be a worse nighmare than poorly managed "GOTO's" if you don't develop good programming habits.

Write your code so that the main program is composed of a bunch of calls and the meat of the functions are all subroutines.  Then you can strategically locate your subroutines on different memory pages, and put them in places that they don't cross boundaries so you don't have to deal with this changing between pages mid-operation.

Back to the repeating twice:
The author apparently wanted a 7-bit sine wave instead of a full 8-bit sine (allows you to get a higher pitched tone with a slower clock, yet with adequate resolution.  Instead of having to write code deal with rolling over at 7 bits, he used the memory page quirk to his advantage and just lets the program counter roll over to the beginning of the page.

So here's the deal with the program counter:
How many bits do you need to access 1024 memory locations?
8 bits = 256 memory locations
9 bits = 512
10 bits = 1024

The PIC uses 8-bit registers for the program counter.  The lower register 'PCL' I believe is direct access to the lower 8 bits, so you can access any of 256 memory locations through these bits.

You now need access to 2 additional bits somewhere to define which 256 of the 1024 you want to access.  These bits are accessed through PCLATH...and in fact, it has 4 extra bits, but you only use up to 10.

Now all that is PROGRAM MEMORY

The bank select bit (STATUS register bit 5) refers to DATA MEMORY.  These are your general purpose and special purpose registers.  For example, the TRISIO register is in bank1, so if you're in bank0 and want to set inputs/outputs on the pins you need to set the bank select bit (STATUS, 5), then reference the TRISIO register...then you need to clear STATUS, 5 to get back to bank 0.


I hope that wasn't too wordy for you. 
trans·mog·ri·fy
tr.v. trans·mog·ri·fied, trans·mog·ri·fy·ing, trans·mog·ri·fies To change into a different shape or form, especially one that is fantastic or bizarre.

Peter Snowberg

One note: Banks could mean any sized piece of memory, where as page usually refers to 256 words.
Eschew paradigm obfuscation

gez

Quote from: Transmogrifox on March 13, 2006, 11:49:25 PMI hope that wasn't too wordy for you. 

Not at all, that was brilliant T-fox!  I now understand what's going on.  Thanks for the clear, concise reply!!  :icon_biggrin:
"They always say there's nothing new under the sun.  I think that that's a big copout..."  Wayne Shorter

gez

OK, I've read through the stuff on PCLATH and now understand it better.  From what I gather bits 12&11 are used to select pages.  So, in binary, is the following right?

page 0 one would load PCLATH with 00 (if returning from another page say)
Page 1, 01
Page 2, 10
Page 3  11

Yes?  (Just a simple yes/no will do)
"They always say there's nothing new under the sun.  I think that that's a big copout..."  Wayne Shorter

Transmogrifox

yes

**************
An extra tip:

MPLAB is a great resource for learning with things such as this.  I find myself getting bogged down and thinking too much about the datasheet.  For example, if I do a SUBWF command, does it subtract W from F or does it subtract F from W?  What about SUBLW?  In MPLAB I would write a simple string of code to execute some arbitrary substraction operations, simulate it with a breakpoint at every command from loading registers with certain values through the subtraction routine and use the "view" menu to select "file registers" to view what's happening.  That way you can watch not only what is subtracted from what, but you can also watch what bits are set or cleared in the STATUS register (C, DC, Z).

Just another little tidbit that can help clarify the datasheet when in question.  You can also watch all kinds of things like program memory and EEPROM.  You can also select the "Stopwatch" from the debug menu to count instruction cycles for you so you don't have to scroll through your code with your mouse going, "one, two, three...four hundred sixty eight..does this operation take two instruction cycles or one?"
trans·mog·ri·fy
tr.v. trans·mog·ri·fied, trans·mog·ri·fy·ing, trans·mog·ri·fies To change into a different shape or form, especially one that is fantastic or bizarre.

gez

Many thanks, that's a useful tip too!
"They always say there's nothing new under the sun.  I think that that's a big copout..."  Wayne Shorter