A megabyte of flash in a 48-pin package is the defining oddity of the GD32F303CG. The body is the same nine-millimetre square used by the quarter-megabyte members, the pin functions are identical, and yet the array is four times larger and the device has crossed the line where the flash controller stops treating memory as a single uniform block. Cloning one is therefore less about capacity than about the two discontinuities that a megabyte introduces: a bank seam at 0x08080000 and a change of page size exactly at that seam.
Bank zero runs from 0x08000000 to 0x0807FFFF and holds 256 pages of two kilobytes. Bank one begins at 0x08080000 and holds the remaining 512 KB as 128 pages of four kilobytes, ending at 0x080FFFFF. Two control registers govern the two halves, each with its own lock bit and its own pair of magic keys, and the mass erase bit is per bank. An operator who erases bank zero and assumes the device is clean will find half a megabyte of program still sitting above the seam, which is the single most common mistake on this density.
Page indices continue across the seam rather than restarting, so page 256 is the first four-kilobyte page at 0x08080000. Any tool that computes a page address as index times two kilobytes will place every page above the seam at half its true address and read the wrong region without reporting an error. The fix is trivial once known: pages 0 to 255 use two-kilobyte steps from the base, pages 256 and above use four-kilobyte steps from 0x08080000. The the STM32F101CB unlock note report describes the same arithmetic on a smaller part, where it never becomes visible.
Erase behaviour differs across the seam as well. A two-kilobyte page erase and a four-kilobyte page erase are separate operations with separate durations, and a script that issues one kind of command against the other half will either fail or, worse, succeed on a neighbouring page. The practical approach is to build an explicit page table at the start of the session: index, base address, size, and bank number. Every later operation indexes into that table instead of recomputing addresses on the fly.
The option block is the same sixteen bytes at 0x1FFFF800, the security byte still reads 0xA5 on an open part, and the first four kilobytes are still locked to code running on the chip once protection is applied. What changes is the cost of getting it wrong: on a protected CG the exit still works, the option block is still writable, and clearing the security byte still mass-erases both banks before releasing the array. Nothing about the recovery route depends on density. Only the amount of work after release does.
Instruction fetch from the first 256 KB of the array runs with no wait states at 120 MHz; beyond that address the controller inserts delays, and the further the fetch the more visible the penalty. That single sentence explains a lot about how firmware on this part is laid out. Time-critical loops, interrupt handlers and the vector table are pushed into the bottom quarter of the array, while fonts, audio tables and communication stacks are placed high, sometimes deliberately in bank one. When a recovered image is being rebuilt, the split between the two regions is a good clue to which parts of the code were performance-sensitive and which were storage.
It also affects the dump. Reading bank one is slower per byte than reading bank zero, so a session that appears to stall halfway through is often just crossing the seam. Timing the first and second halves separately and comparing them is a quick way to confirm that the read is progressing rather than hanging. The STM32F103VET6 work write-up shows the same effect on a hundred-pin device with the same controller, and cloning an STM32F103RCT shows it on a part where the program was deliberately laid out around the cliff.
For a clone, the sequence that matters is not the erase but the reproduction. The image has to be written back with the same bank allocation, because the linker script of the original build assumed a particular address for each section. Writing a megabyte image linearly from 0x08000000 into a device configured with a different split will produce a board that boots and then fails at the first call into a table placed above the seam. Compare the recovered page map against the map of the target device before writing anything, and treat any mismatch as a stop condition rather than something to fix later.
The finished package for a CG is a binary, a bank-aware page map, the two control-register states at the time of release, and a linker-compatible address listing so that the customer can rebuild without guessing. Verification means two independent reads with matching hashes and a third read after the image has been programmed into a blank device. rebuilding source from a dump covers the reconstruction side, and IC reverse engineering the verification side. Related work on the STM32F103CB write-up and on cloning an STM32F100C8 program used the same page-table approach and the same stop condition.
What makes this density worth its own procedure is not the extra capacity but the seam. Once the seam is modelled correctly, a CG behaves like any other member of the family; until it is, every second operation lands in the wrong half of the array.