John: > > 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]. That could be handy but you could also do it in other ways, and perhaps better cause if you do it using different banks you would be forced to use the same addresses and that could get complicated if you have many arrays. I don't see it as a powerful argument. > > 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. Let me put clear what the process I'm calling "organizing a program" would be on a 17CXX. First you would program the components you need (interfaces, parsers, buffers, etc.) When you do so you'd use the same bank for each component (with the exceptions you might be thinking of.) Later on, separately, you would want to assemble a system. The first thing to do is try to compile the whole thing using only one bank. If if fits, great, but if it doesn't then you would have to decide which bank to use for each component. To do so, it would be handy to make a diagram of the relations between components and, having in consideration the RAM usage of each, "cut" the diagram into two zones of low cohesion. Then, by hand, arrange the bank switching you need for the interface between these two parts, which is not very much work cause you cared to find a low cohesion interface to do the cut. Finish by adding the three lines for saving the current bank in your interrupt routine. In my opinion, doing all this is not much work and it's fairly efficent as bank switching would only be done for a seldom used interface, but it wouldn't be that easy and efficent if pages were smaller. Now, lets consider a C compiler (or any other algol-like) that used a stack for variables and interfaces. It would be much more practical to have a large page for the stack. If the stack needed more RAM it could use more banks and the compiler would handle bank-switching at run-time, at the expense of speed. The programmer could have the option of using a small fast stack or a big slower one. This is the process I'm thinking of, it results in not much work, little bank switching, good reusability, efficency for all cases (including those when one page is enough), and you don't have to count on having all the simple variables fitting in a given number of registers. If pages got smaller all this would be less practical, and I'm not sure of being able to get all the advantages you've been talking of as often as needed to compensate for it. That's what I was talking about on my last posting. > ...... > 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. Can't you just change banks while processing the arrays? Don't forget about the MOVLB instruction. > 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. You're counting on that and I don't see a reason. I wrote a program for a 16C73 that uses about 90 registers for non-array variables, even though I'm overlapping them I believe as much as they can. If I had four times the ROM I could improve that system a lot and I'd surely exceed 96 registers. > > 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. Well, yes, I've put that on the scale already but I don't find it heavy at all. You're talking about only three cycles! > [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. I think this argument is more powerful, but you would do this only to skip a step in the process of organizing a program and if you wanted to write code that needs no changes at all when reused. That sounds ok, but on the other hand the step and the changes that would be necessary with the process I just described are a few and easy to do, and with your scheme, if 96 registers were not enough, you would still have unbanked-interface and banked-regular variables for every component and I find that hard to work with, specially considering that while programming the routines you don't know yet if the whole will fit or not in one page. I believe you won't be getting a result as efficent as with the other process. Perhaps I am overlooking something. . . > 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. It sounds right at first sight, but I'm not sure if this is so in practice. Perhaps it's because we have different methods of programming. Just think about what the equivalent of the process I described above would be if unbanked registers were a lot and we had more pages. > 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. Ok, though I guess the WREG stuff wouldn't ease things much. > 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. I think I like this idea (a separate RAM file), but I don't like having the RAM area splitted. > 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 Two BSRs would be great, and the rest we've already talked about a lot... > 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... Ok, but I in my opinion the kind of applications you're having in mind is not as general as you're thinking. Regards, Andres Djordjalian adjordj@aleph.fi.uba.ar