PIC18F6410: 16 KB, One Protect Bit, No EEPROM

The PIC18F6410 is the 16 KB half of the DS39635 pair: 8,192 instructions running from 0x0000 to 0x3FFF, in a 64-pin TQFP that is pin-for-pin identical to its 8 KB sibling. Same 768 bytes of RAM, same parallel slave port, same 12-channel 10-bit ADC, same 40 MHz ceiling. The array is the only meaningful difference, and it changes the read-out arithmetic without changing the protection model.

Still one bit

The 6410 keeps the single CP bit that covers the whole array. There is no block subdivision, no boot block, and no CPB or CPD — the latter because, like the 6310, the part carries zero bytes of data EEPROM. A locked 6410 returns 0x0000 for all of 0x0000–0x3FFF over ICSP; an unlocked blank one returns 0xFFFF. There is no intermediate state to interpret, which makes the protection report short and makes misreadings rare: any file that is part firmware and part zeros was not produced by a locked 6410.

The twin problem

The risk with this part is not partial reads — it is identity. The 6410 and the PIC18F6310 share a package, a pinout, a peripheral set and a marking style, and a 6310 image occupies the low half of a 6410 array and runs correctly until code or a table reaches above 0x1FFF, which a 6310 build never places there. In the other direction it fails immediately: 16 KB of firmware does not fit an 8 KB array, and a programmer will refuse or truncate it.

The device ID at 0x3FFFFE settles which die is on the board, and it matters before any flash image is judged complete. A 6410 hex ends at 0x3FFF. A file that ends at 0x1FFF is either a 6310 image or a truncated 6410 read, and the two look identical without the ID to anchor them.

Where the firmware lives

Sixteen kilobytes is enough for XC8 to separate concerns: application code low, constant tables and strings at the top of the array. That top region — 0x3800–0x3FFF in a typical build — is also where a truncated read loses the most, because lookup tables are referenced by computed addresses rather than by fall-through execution. A dump that disassembles cleanly can still be missing the tables, and the failure shows up at runtime as garbage values from any routine that indexes a table, not as a crash. This is the same trap the readout protection guide describes generally: “it disassembles” is not evidence of completeness.

With no data EEPROM, there is also no hidden second file. Per-unit calibration, if the firmware keeps any, is in the array itself. That removes the classic clone failure where flash copies cleanly and EEPROM is left blank — here there is nothing to leave blank.

Assessment and routes

The workflow is the same as for the 6310: read the device ID, attempt the ICSP read, and expect a uniform answer. A locked part yields 0x0000 everywhere; the code protection is then a die-level matter, and the services page describes what that adds over a programmer-only attempt. Units that arrive damaged — cracked packages, lifted pads on a 64-pin TQFP — can often still be assessed first; the damaged-chip FAQ covers what changes when the part is not intact. For a 6410 in any condition, the deliverable is one file: the array from 0x0000 to 0x3FFF, plus the config words from 0x300000 and the ID from 0x3FFFFE.

The config words are the third file

The array is the headline item, but the twelve configuration bytes at 0x300000 decide whether a rebuilt 6410 behaves like the original. Oscillator mode, watchdog, brown-out threshold and code-protect state are all set there, and they travel in the hex file as type-04 records that sit after the last array record — exactly where truncating tools stop. A rebuild with the array but not the config words boots into whatever oscillator mode the blank device defaults to, which on a crystal-driven board is the wrong one. Checking for the type-04 records takes seconds and separates a complete image from a plausible one. The device ID at 0x3FFFFE rounds out the set and is always readable, locked or not.