The PIC18F6622 is the 64 KB member of the PIC18F8722 family (DS39646): 3,936 bytes of RAM, 1,024 bytes of data EEPROM, PSP, dual enhanced USARTs and a 40 MHz ceiling in a 64-pin TQFP. What makes it interesting for read-outs is not the array — it is that the code-protection map moves depending on a configuration bit.
BBSIZ moves Block 0
CONFIG4L at 0x300006 carries the BBSIZ bits, which select a 2, 4 or 8 KB boot block. Block 0 then runs from the end of the boot block to 0x3FFF, and above it sit three fixed 16 KB blocks: 0x4000–0x7FFF, 0x8000–0xBFFF, and 0xC000–0xFFFF under CP1–CP3. CP0 covers Block 0; CPB covers the boot block.
The same physical dump therefore has three valid interpretations. With BBSIZ at 2 KB, Block 0 starts at 0x0800; at 4 KB, 0x1000; at 8 KB, 0x2000. A reader that assumes the default reports the first protected boundary 6 KB wrong on a unit programmed with the 8 KB boot — and reports the wrong ranges as locked. The config words, including CONFIG4L, live at 0x300000 outside the array and travel in the hex file as type-04 records. If those records were dropped by the reading tool, the one piece of information that fixes the block map is missing exactly when it is needed. This is why the completeness check on this family includes the config words as a first-class item, not a footnote.
The rest of the map
The array ends at 0xFFFF. RAM is 3,936 bytes — the larger allocation in the family — and the peripheral set points at firmware that buffers and communicates, so constant tables tend to live in the upper blocks. A read that covers the low half and reports the top 16 KB as zeros may be missing Block 3, and since 0x0000 is a legal instruction on this core, the zeros disassemble into plausible padding rather than announcing themselves.
The device ID at 0x3FFFFE separates the 6622 from its 96 KB sibling the PIC18F6627, which adds CP4 and CP5 above 0xFFFF, and from the 48 KB PIC18F6527, which lacks CP3 entirely. All three share the package and the BBSIZ mechanism. The ID is readable regardless of protection state, so there is no excuse for interpreting a dump before reading it.
The EEPROM and the full deliverable
The 1,024 EEPROM bytes at 0xF00000 sit under their own CPD bit. On communication-heavy boards this is where node parameters and per-unit trim live, and a rebuild with a blank EEPROM fails the way these failures always fail: correctly on the bench, wrong in the field.
A complete 6622 read-out is therefore: the array to 0xFFFF with a per-block report interpreted at the right BBSIZ, the twelve config bytes including CONFIG4L, the EEPROM, and the ID. Where blocks read as zeros, the pattern states the lock condition without opening the package; where the array is locked wholesale, the code protection work moves to the die and the services page sets out the routes. The block map is never guessed on this part — it is read out of CONFIG4L.
What the firmware tends to look like
Dual enhanced USARTs and 3,936 bytes of RAM put the 6622 on boards that talk: gateways, panels, monitoring front ends. Firmware of that shape keeps its message strings and protocol tables in flash, indexed by computed offsets, and on a 64 KB array those tables climb into Block 3. The user ID locations — four bytes the firmware often fills with a production date code or a serial — sit in the configuration space and ride along with the config words on every read, locked or not. They cost nothing to collect and give the rebuilt unit a way to be matched to its source later, which matters on fleets where several units of the same model have drifted apart in calibration. The completeness test remains arithmetic: 65,536 array bytes ending at 0xFFFF, twelve config bytes including CONFIG4L, 1,024 EEPROM bytes, the device ID, and the user IDs — checked against 0xFFFF, not against how the file looks.