Writing the Same Program in Both
8-Bit CPUs — 6502/6510 & Z80
Chapter 8 · Writing the Same Program in Both
Chapters 2–7 studied each chip in isolation. This chapter puts them side by side for the first time — one identical task, written twice, so every difference on the page is a real difference in the chips themselves, not an accident of two separate examples. The task: sum five bytes stored in an array into a single running total.
The 6502 Version
ARRAY and SUM are both placed in zero page (cpu8bit1-4), so ARRAY,X below is genuinely zero-page,X indexed addressing, not the more expensive absolute,X form:
LDX #0 ; X = array index = 0 LDA #0 ; A = 0 STA SUM ; SUM = 0 LOOP LDA SUM CLC ; NEW — clear Carry before ADC (see warn-box below) ADC ARRAY,X ; SUM += ARRAY[X] — zero-page,X (cpu8bit1-4) STA SUM INX ; NEW — increment X (X++) CPX #5 ; NEW — compare X against 5, setting flags BNE LOOP ; NEW — branch if the comparison found "not equal" DONE JMP DONE ; the 6502 has no HALT — loop on itself forever ARRAY .BYTE 10,20,30,40,50 ; zero page, e.g. $10 SUM .BYTE 0 ; zero page, e.g. $20
Three genuinely new instructions here: INX (increment X), CPX (compare X against a value, setting the same flags cpu8bit1-3 already introduced), and BNE (branch if the Z flag is clear — "not equal"). Notice the loop needs three separate instructions — INX, CPX #5, BNE LOOP — just to advance and test the loop counter.
ADC always folds the current Carry flag into its addition, per cpu8bit1-3's own Carry explanation. If Carry happens to be set from something earlier in the program, an unguarded ADC silently adds one extra — a famous, well-documented source of off-by-one bugs in real 6502 code. CLC immediately before ADC (when you want ordinary, uncontaminated addition) is close to a reflex among 6502 programmers.
The Z80 Version
LD HL, ARRAY ; HL = pointer to the array's start (cpu8bit1-6) LD B, 5 ; B = remaining count = 5 LD A, 0 ; A = 0 LOOP ADD A, (HL) ; A += the byte HL points to — register-indirect (cpu8bit1-7) INC HL ; advance the pointer to the next byte DJNZ LOOP ; NEW — decrement B, loop if B != 0, all in ONE instruction LD (SUM), A ; store the final sum DONE JR DONE ; the Z80 has no HALT either — loop on itself ARRAY DEFB 10,20,30,40,50 SUM DEFB 0
One genuinely new instruction: DJNZ ("Decrement and Jump if Not Zero") — decrements B and branches back to the target in a single instruction if the result isn't zero, falling straight through if it is. It's a famous, well-known Z80 instruction, and this routine is exactly the pattern it exists for.
The Comparison
This is the concrete payoff cpu8bit1-5 and cpu8bit1-6 only described in the abstract. The 6502 needs three separate instructions (INX, CPX #5, BNE) to manage its loop counter every single iteration; the Z80's DJNZ folds decrement-compare-and-branch into one. That's the "richness" from cpu8bit1-5, made visible in real code rather than described as a slogan.
| 6502 | Z80 | |
|---|---|---|
| Instructions in the loop body | 7 (LDA, CLC, ADC, STA, INX, CPX, BNE) | 3 (ADD, INC, DJNZ) |
| Cycles per iteration (approx.) | 19 | 26 |
Fewer instructions on the Z80 side — but more total cycles per iteration, not fewer. Richness bought real code-density here, not raw speed.
cpu8bit1-9 returns to this same minimalism-vs-richness contrast one more time, applied specifically to interrupt handling — including the shadow register set's own real payoff from cpu8bit1-6. cpu8bit1-11 is where this chapter's own concrete evidence gets formally tied back into the RISC-vs-CISC preview cpu8bit1-1 opened the whole course with.
Hands-On Exercises
Trace the 6502 version's loop for X = 0 through 4. After the fifth pass through the loop body, X becomes 5. Identify exactly which single instruction is responsible for actually ending the loop at that point, and explain what condition it's checking.
📄 View solutionExplain, in your own words, exactly what three separate jobs DJNZ combines into one instruction, and what specific consequence that has for the "7 instructions vs. 3 instructions" comparison this chapter draws between the two loop bodies.
📄 View solutionUsing this chapter's own cycle counts (19 for the 6502, 26 for the Z80) and the real historical clock speeds of a 6502 running at roughly 1MHz and a Z80 running at roughly 3.5MHz, calculate the real wall-clock time each chip takes to complete one loop iteration, and state which one is actually faster in practice.
📄 View solutionChapter 8 Quick Reference
- Same task (sum 5 bytes) implemented on both chips, using only addressing modes and registers already covered in Chapters 2–7
- New 6502 instructions: INX (increment X), CPX (compare X), BNE (branch if not equal) — three instructions to manage one loop counter
- New Z80 instruction: DJNZ — decrement B and branch, all in one instruction
- Loop body: 7 instructions / 19 cycles (6502) vs. 3 instructions / 26 cycles (Z80) — fewer instructions didn't mean fewer cycles here
- Cycle counts alone can't tell you which chip is actually faster in real time — clock speed matters too, and the two chips didn't run at the same speed
- Always CLC before ADC on the 6502 unless you specifically want the current Carry folded into the addition — a classic, well-known bug source
- Neither chip has a dedicated HALT — both loop on themselves (JMP DONE / JR DONE) to stop, unlike LC-3's own TRAP-based HALT (assembly1-8)