> Hi John! Hello. > > While there are certainly exceptions to any rule, most programs that need > > a lot of RAM need it for arrays or other such constructs. Given that any > > array access has some associated setup work anyhow, having to deal with > > I agree, but those constructs can be plenty and small, instead of one > or two big ones. Right, but see below... > > array banks isn't a big deal. For simple variables, however, it's nice to > > simply *ignore* bank-switching and related concepts. If 96 bytes' worth > > of registers are non-banked, then the vast majority of applications--even > > those which use up hundreds of bytes worth of arrays--will be able to > > handle all their non-array needs without bank-switching. > I was thinking of the following. Lets say you have a set of routines that > handle some sort of calculations that use an array. Would you put the > array and the other variables in the same page or not? I might but them all in the same page, but I'd prefer to put the simple-variables in a non-banked section and the array itself in a banked section. This would allow the routine to use any of several arrays, in different banks, without any changes to the code itself [assuming the routine's caller set the appropriate array bank]. > You don't want to > limit its use to a single project, maybe you'll first use it in a small > program but later reuse it for a large one. If you switched banks the > first time it would be a waste of code and efficency, if you modified it > for the second program you would be forced to play with code you've > programmed some time ago, and if you consider both options from a start > you would have to work more. What is wrong with simply saying that whoever calls the routine should set the bank-switch register to the appropriate bank? If there is only one bank that's used for the array, that setting can simply be done at the start of the program. Otherwise, it can be done just before the routine. Admittedly, if a routine uses TWO arrays which may be in different banks then things get much more complicated. Here too, though, unless the CPU is nice enough to allow independent banking of the two FSR's (which IMHO the 17Cxx oughta be but isn't) your best bet will frequently be to put one of the arrays in non-banked space and one in banked space, or else to copy part [or all] of one array into non-banked space and then switch to the other array's bank. Both of these approaches can be practical and efficient if the non-banked area is large, but are quite impossible if the non-banked region is only 6 bytes. > I'd rather try to use not more than one bank for a component's > variables, minimizing bank-switching inside the component, and leave the > bank-switching for the interface between them. I find it easier to > plan a efficent organization if you work that way. And if RAM pages are > large this is easier to do. I don't mean to say that 224 vs. 128 bytes is > very much important, but, on the other side, would it be that handy to > have a large common area? If the common area is 96 bytes, then it's extremely likely that most or all of a program's non-array variables will be accessible *ALL THE TIME* without *ANY* bank switching. While there are certainly exceptions to this rule, it does seem to hold pretty well. Are you at all familiar with the 8x51 architecture? On that machine, there are three primary ways to access memory: Direct data: 128 bytes which can be accessed directly. Since addresses below 32 are usually reserved, this leaves 96 bytes. [note: a few CPU's in the family only implement the first 64 bytes of this] Indirect data: 256 bytes, the first 128 of which overlap direct data. These locations are harder to access (you must set up the "FSR" equiv- alent and use the "IND" equivalent) but are still on-chip. [note: some CPU's in the family only implement the first 64 or 128 bytes of this] External memory: 64K of address space entirely independent of the inter- nal 256 bytes; these locations are a pain in the tusch to access. Pretty much equivalent to the external memory on the 17Cxx. While I've done some '5x jobs which have needed more than 128 bytes of memory, I've never done one which needed more than the 96/128 bytes of direct data for non-array objects (since arrays have to be accessed indirectly anyhow, placing them in IDATA doesn't cost anything more). While I don't doubt that some jobs would require more than 96 bytes direct storage, I expect that some of that memory would be seldom-accessed and could be placed in an upper bank without significant loss of efficiency. > > Further, even for programs that do need large arrays [bigger than 128 > > bytes] the overhead of selecting the appropriate 128-byte page is really > > not severe. In fact, with arrays that span pages it's probably easier to > > deal with 128-byte pages (power of two) than 224-byte pages (not a power > > of two). For example, suppose ArrayH:ArrayL is a two-byte pointer to a > > ............... > > Ok, I'll put that on the scale too, but I still think the best choice is > not clear. I mean, how many times will you need an array that takes almost > all of the memory, not being able to spare ten or so extra machine-cycles > to access it, nor program it's client in such a way as to use a pair of > bank and offset pointers? Can't think of many, but I can think of a lot of > times when I'll be organizing a program working much more comfortably > because I have larger pages. Perhaps you can think of oodles of applications which would particularly benefit from having arrays between 128 and 224 bytes in size. I for one can think of many more applications that would benefit from the larger common area. > > I agree that a "nice" implementation (like a BANKFSR register) would > > probably have added a little silicon; IMHO the benefits from being able to > > truly bank the IND's would probably be worth it. Certainly, though, > > while we can debate about the exact best size for the banked/unbanked > > split I hope you will agree with me that there oughta be more than SIX > > unbanked registers? > > I may be, as I told you I haven't programmed the 17CXX family and I've > no experience on unbanked regs. But yeah, it sounds as if six were too > few, perhaps they could have added another bit and put sixteen more, but > before criticizing this I'd like to see more clearly what the real > drawbacks of scarce unbanked regs are. Okay, for starters... [1] If unbanked registers are at least moderately plentiful, then many interrupt service routines will be able to complete fully without having to bank-switch at all. This would save three cycles on every single interrupt service event. [2] If unbanked registers are scarce, then it becomes difficult to pass information among different modules. Suppose, for example, I have a procedure FOO which needs to call procedure BAR, giving it four bytes of parameters, and BAR then needs to call procedure BOZ. All three of these routines happen to have their variables in different banks. If unbanked memory were plentiful, then all the parameter passing could be done in unbanked memory (in fact, probably ALL of the simple variables used by the different routines would be in unbanked memory). But with unbanked memory scarce I'd have to have the first routine put the parameters into unbanked memory, then call the second routine which would have to COPY THEM OUT, then put its parameters to the third routine in unbanked memory, etc. Much less efficient than if unbanked memory is plentiful. > > those which improve programmer convenience without much cost whatsoever. > > I think placing the bank split in a better place would have fallen in the > > latter category. My choice of 128 was intended both as a compromise > > .... > > I agree, I'm just not sure if having many more unbanked regs results in > improved programmer convenience. It results in a tremendous improvement in programmer convenience because it means that you don't need to worry about banking for 90% of your variables [most programs use lots of small variables and a few big ones. If unbanked memory is reasonably plentiful, then only the [few] big ones will need to be banked. Personally, what I really would have liked to have seen would be something more or less akin to the 8x51, but with some enhancements [far too late now, though] DIRECT MODE ACCESS: Addresses 00-0F: Special-purpose registers, much as they are now, but with the timer stuff removed to make way for a new bank-switch register, and possibly PRODL and PRODH. To simplify the architecture, I'd also probably make WREG read-only and re-add the movf instruction. Addresses 10-17: General-purpose RAM (possibly with PRODL/PRODH at 10-11), accessible via movpf/movfp Addresses 18-3F: General-purpose unbanked RAM Addresses 40-7F: Eight banks of eight I/O registers. The movpf/movfp instructions would be bank-switched to select a group of eight, but other instructions could access any register directly. Address 80-FF: Bank-selected memory, using bits 3-7 of the BSR. INDIRECT MODE ACCESS via FSR0 Address 00-FF: Bank-selected memory, using bits 0-3 of IBSR INDIRECT MODE ACCESS via FSR1 Address 00-FF: Bank-selected memory, using bits 4-7 of IBSR This architecture would allow indirectly-accessed memory [arrays and such] to be accessed cleanly in banks of 256 addresses, while allowing any indirectly-accessible location to also be accessed directly. For applications that did not require direct access to all memory, a full 168 bytes of "non-banked" direct-addressed storage would be available. Oh well, too late now...