Joined: Sat Feb 19, 2022 2:18 am Posts: 47
|
BigDumbDinosaur wrote: This topic seems to be going in circles (along with some occasional OT commentary), as the same tired, old tropes are being repeated about the 65C816. For instance, everyone and his pet monkey seems to be obsessed with banks and what a bad thing they are. If you understand the following, you and the MPU's banks will get along just fine.
- Hardware vectors. The 65C816's hardware vectors are seen only in bank $00. This characteristic is a byproduct of the need to maintain (mostly) backward compatibility with the 65C02.
- Program code. If the program counter (PC) wraps, the program bank (PB) will not increment. Therefore, program execution is confined to the bank defined by PB. This simply means that relative branches, 16-bit jumps and 16-bit subroutine calls cannot cross bank boundaries.
In practice, this limitation is very rarely an issue—65C816 code, like its 65C02 counterpart, can be quite compact if written by a skilled programmer. If necessary, really large programs can be built in segments, loaded into several contiguous banks and long jumps (JML) and/or long subroutine calls (JSL, with RTL to return) used to handle cross-bank execution.
- Absolute indirect jumps. An absolute indirect jump, e.g., JMP ($1234), "bounces" off a vector located in bank $00. This characteristic also applies to an absolute indirect long jump, e.g., JMP [$1234].
On the other hand, an absolute indexed indirect jump, e.g., JMP ($1234,X), bounces off a vector located in the same bank in which the indexed indirect jump instruction is located. This characteristic also applies to an indexed indirect subroutine call, e.g., JSR ($1234,X) (a very useful instruction—it's like ON - GOSUB in BASIC).
- Stack. All stack accesses are directed to bank $00. This includes both stack-relative addressing modes. As the 65C816's stack pointer (SP) is a 16-bit register, the stack may be located anywhere in bank $00.
- Direct page. All direct page (aka page zero or zero page) accesses are directed to bank $00, including the indirect direct page addressing modes. As the 816's direct page pointer (DP) is a 16-bit register, direct page may be located anywhere in bank $00. In fact, DP may be pointed to a reserved area on the stack, a very useful feature!
- Data fetch/store. Unless one of the long addressing modes is used, data will be fetched and/or stored in the bank defined in the data bank register (DB). This characteristic allows most 65C02 code to run unchanged on the 65C816 if DB is set to whatever is in PB with a PHK - PLB instruction sequence.
- Block-copy instructions. Both MVN and MVP take a source and destination bank as operands and can copy intra- or inter-bank at high speed (seven clock cycles per byte copied). DB is changed by these instructions to point to the destination bank. It is customary to surround a block-copy instruction with PHB and PLB to preserve DB.
- Long addressing. The long absolute addressing modes, e.g., LDA $AB1234 or LDA $AB1234,X, implicitly specify the target bank and hence may be used to access data outside of the bank defined in DB. The indexed form of long absolute will span bank boundaries if the sum of the address plus .X causes a carry into bits 16-23.
The long indirect addressing modes, [<dp>] and/or [<dp>],Y, where <dp> is a location on direct page of a 24-bit address (in three contiguous bytes), are completely bank-agnostic and when used with 16-bit index registers, facilitate fetch/store access to the 816's entire 16MB address space with succinct code that is easy to write. What this means is that from a data fetch/store perspective, memory accesses are completely linear.
Further to long indirect addressing, I have learned that in writing efficient 65C816 code, direct page pointers (also, long indirect jump vectors) are better handled as 32-bit quantities, even though the MPU is limited to 24-bit addresses. Programs so written tend to be more compact and also tend to run faster because the accumulator can be set to 16 bits and left that way as pointer arithmetic is carried out. Otherwise, it is necessary to repeatedly execute REP and SEP instructions to switch the accumulator size to handle the LSW or MSB of the 24-bit address being processed, at a cost of two bytes and three Ø2 cycles per REP or SEP.
Having written tens of thousands lines of 65C816 code, I will emphasize that manipulation of the bank registers is very uncommon. In the case of PB, the program bank register, there is no direct, programatic means by which it can be changed. In practice, DB (data bank register) hardly ever gets touched as well, a good thing, since doing so tends to be awkward. During initialization, my main-line programs will do a PHK followed by a PLB to set the default data bank to the program bank. Hence fetching static data that was assembled as part of the program can be conveniently accomplished with 16-bit addressing. In contrast, data that is being processed is handled with long indirect addressing, which means it can come from anywhere in memory and go to anywhere in memory.
In summary, while existing 65C02 algorithms can be made to run on the 65C816 (in either mode), that is a gross under-utilization of the MPU's capabilities. The key to developing for the '816 is to understand that it is a completely different critter in native mode than its eight-bit cousin (the 65C02) and thus programming it demands a totally different approach if the full power of the '816 is to be used. Once you come to that realization you will be amazed by what you can accomplish. Good stuff! I appreciate you sharing all this, BDD. This is helpful as I move into 65816 programming. I have so much to learn.
|
|