+------------------------------------------------------------------------+ | 02 / Memory, addressing and flags | +------------------------------------------------------------------------+ THREE SPACES, ONE NUMBER CODE is up to 64 KB of program memory, fetched by PC and read as data with MOVC. XDATA is a separate, up-to-64-KB external data space accessed with MOVX. Internal DATA contains the CPU's small RAM and its directly addressed special function registers. Thus MOV A,0x30, MOVC A,@A+DPTR and MOVX A,@DPTR can read three different physical places even if the numerical address is the same. INTERNAL MAP (128-byte 80C31) 00-07 register bank 0 (reset default) 08-0F register bank 1 10-17 register bank 2 18-1F register bank 3 20-2F 16 bytes / 128 individually addressable RAM bits 30-7F general RAM and stack, allocated by your program 80-FF directly addressed SFRs, NOT another 128 RAM bytes WHAT IS A REGISTER BANK? The working registers R0-R7 are eight names for eight bytes in internal RAM. There are four sets of those bytes, called register banks. Only one bank is selected at a time. Selecting another bank changes which RAM bytes the names refer to; it does not copy or erase their contents. For example, with bank 0 selected, MOV A,R3 reads internal RAM address 0x03. With bank 1 selected, the same instruction reads address 0x0B. R3 is register number 3 (the fourth register, because numbering starts at zero). By contrast, MOV A,0x03 always reads address 0x03, regardless of the selected bank. HOW THE CPU SELECTS A BANK PSW stands for Program Status Word. It is a special function register: a byte used by the CPU for status flags and control settings, rather than ordinary data storage. Two of its bits select the register bank: RS1 is bit 4 and RS0 is bit 3. Written as RS1:RS0, they form a two-bit number: RS1 RS0 Selected bank R0-R7 use RAM addresses R3 uses 0 0 0 00-07 03 0 1 1 08-0F 0B 1 0 2 10-17 13 1 1 3 18-1F 1B Reset selects bank 0. Other banks can give interrupt handlers their own working registers, but software must manage the selection and reserve the RAM. In DOS/51, do not casually switch banks or overwrite these bytes: the running firmware also uses internal RAM and the stack. WHAT DOES INDIRECT ADDRESSING MEAN? A direct operand names the address in the instruction itself: MOV A,0x30 reads RAM address 0x30. An indirect operand instead uses an address held in a register. After MOV R0,#0x30, MOV A,@R0 reads that same RAM byte. The @ means 'use the address stored in this register'; ordinary indirect MOV supports R0 or R1, not any arbitrary register. Addressing examples: mov a,#0x30 ; A = literal 48 mov a,0x30 ; A = RAM byte at 30 mov r0,#0x30 mov a,@r0 ; same RAM byte, indirect mov dptr,#0x1234 movx a,@dptr ; external DATA byte at 1234 clr a movc a,@a+dptr ; CODE byte at 1234 ORDINARY MOV: RAM OR A HARDWARE REGISTER? The 80C31 has only 128 bytes of internal RAM, at 00-7F. Addresses 80-FF select special function registers (SFRs) only when used as DIRECT operands. These SFRs control hardware such as ports and timers. For instance, MOV A,0x90 reads the Port 1 register, P1. Ordinary indirect MOV does not use that SFR address space. Loading R0 with 0x90 and executing MOV A,@R0 therefore does NOT read P1: it attempts to read an internal RAM byte that does not exist on this 80C31. The 80C32 is different: it adds another 128 internal RAM bytes at indirect addresses 80-FF. That extra RAM still does not turn indirect accesses into SFR accesses. Choose both the address AND the addressing mode deliberately. MOVX through @R0/@R1 uses an 8-bit low address; classic external hardware uses P2's latch for the high address. MOVX @DPTR uses all 16 address bits. Neither is the same as ordinary MOV @Ri. MOVC uses A as an unsigned index; the @A+PC base is PC AFTER the MOVC opcode. JMP @A+DPTR also uses an unsigned byte offset, not a table of pointers automatically dereferenced by hardware. BIT MEMORY Bit addresses 00-7F map to bytes 20-2F: byte = 20 + (bit_address / 8), bit = bit_address modulo 8. Bit 00 is RAM 20.0; bit 7F is RAM 2F.7. Bit addresses 80-FF select implemented bit-addressable SFRs whose BYTE address is divisible by eight. Not every SFR supports bit operations: TMOD at 89 does not. Bit address 89 is TCON.1, not TMOD. Use ANL/ORL on a whole byte for non-bit-addressable registers. FLAGS: PSW = CY AC F0 RS1 RS0 OV user P CY is carry for addition and borrow for SUBB. AC is carry/borrow across bit 3. OV signals signed arithmetic overflow. P is maintained from A: 1 for an odd number of set bits. F0 is a software flag. The classic CPU has NO zero or negative flag; JZ/JNZ inspect A itself. INC and DEC do not update CY or OV. They still affect P if they change A. For unsigned comparison, CJNE sets CY when its first unsigned operand is less than the second. For signed comparison you must account for sign/overflow yourself. Example: 0x7F + 1 becomes 0x80 with OV=1 but CY=0. Conversely 0xFF + 1 becomes 0 with CY=1 but OV=0. 16-BIT ADD / SUBTRACT mov a,0x30 ; low byte of left operand add a,0x32 ; low byte of right operand mov 0x34,a mov a,0x31 addc a,0x33 mov 0x35,a ; final CY is the 16-bit carry For subtraction start with CLR C and use SUBB on both low and high bytes. A plain SUB instruction does not exist. STACK Reset sets SP=07; a PUSH first increments SP, then writes. CALL pushes the return address low byte first, then high; RET reverses that sequence. A bare-metal MOV SP,#0x5F makes the first pushed byte land at 60, leaving 32 bytes through 7F. Reserve that area and check worst-case calls plus interrupt nesting. The stack does not automatically grow into external RAM. PUSH/POP accept direct byte addresses, not immediate data or an Rn operand. PUSH 0x00 saves bank-0 R0, not necessarily the current bank's R0. PORT READS MOV A,P1 reads pins. Read-modify-write instructions with a port destination (ANL P1,#mask, ORL P1,#mask, CPL P1.0 and friends) use the output latch. That matters when external circuitry pulls a released input low. Use masked or bit writes so unrelated outputs survive. [ DOS/51 FIELD MANUAL | IMANIA.DK | 2026-11-14 ]