Jump to content
IGNORED

6502 vs Z80: Which do you prefer programming?


BillyHW

6502 vs Z80: Which processor do you prefer programming?  

26 members have voted

  1. 1. Which 8-bit processor do you prefer programming?

    • 6502
      18
    • Z80
      8

  • Please sign in to vote in this poll.

Recommended Posts

To be honest, I've only really tried to program one of them in assembly language (because that is what I think you're asking about), but I've had a look at the other and quickly took a step back because my head started to spin and I didn't have the energy at that moment to unspin it.

  • Like 1
Link to comment
Share on other sites

I really don't have a preference.
After finishing a 64 column graphics font driver for the VZ200, Acorn Atom, and MC-10, I can share some observations though. Since all the machines use the same video chip the code is doing the same work so it makes for a decent comparison.

The 6502 font code required the most radical design changes for the fastest text rendering and scrolling.
Instead of keeping bytes together for each character, I kept 1st bytes, 2nd bytes, etc... from all characters in separate tables.

This let me eliminate the multiply required to calculate the offset in the character table.
The optimization was definitely easier to follow than the optimized multiply and the final code was faster.
The screen scroll speedup required scrolling columns of characters rather than a line at a time.
Weird but significantly fewer clock cycles. It about doubled the speed of the demo.
Lack of 16 bit index registers makes the code a little more complicated but not difficult by any means.

I think it's a little easier to program the Z80 than the 6502 thanks to the 16 bit support.
Creating the most efficient code is another matter.

The Z80 font code took the longest to optimize. Every time I turned around I came up with another optimization.
Creating optimal code depends on best use of the Z80 registers and instructions.
Since many instructions only work with certain registers, redoing a section of code multiple times can result in some significant speed gains.
The optimizations weren't difficult but they weren't obvious from the start, and each new one was often a result of the previous one.
Where cutting out an instruction on the 6502 might drop 3 or 4 clock cycles, on the Z80 you are looking at more like 7 or 9, sometimes more.
A few optimizations resulted in tens of thousands of saved clock cycles when drawing a screen full of text.
The looping instructions give the Z80 and advantage but the one capable of scrolling the screen takes more cycles than others so the fastest version of the scroll is almost as much of an unrolled loop as the other cpus.

The demo of the text code prints the font endlessly. Lines are wrapped, and when it reaches the end of the screen, the demo scrolls the screen, clears the last line and continues printing.
I think the 6502 did quite well when drawing text, but scrolling the screen wasn't so fast.
Using the speed control in the different emulators so they display seemed to scroll at the same rate resulted in about a 2 to 1 speed difference between the 6502 and Z80 processors.
The 65802 and 65816 would do better here thanks to the 16 bit index registers and block memory move instructions. Ok, they could do better than the 6502 everywhere.

FWIW, the screen memory on the VZ is paged for the hi-res mod, so there is some overhead the other cpus didn't have to deal with, but it's minor.

  • Like 5
Link to comment
Share on other sites

i'm far more a 6502 bunny but i've done both, including the same picture/music/scroller demo on the Amstrad CPC in Z80 using mode 2 and the C128's 80 column VDC display with 6502; the latter was the "easier" job since the hardware helps out, so the LDIRs used for the scroller on the CPC were replaced with DMA-powered transfers for the 6502, vertical colour splits became attributes and the C128 code was so much faster overall that it ran a second, independent copy of the demo on the 40 column display!

 

The hardware wrapped around the processor matters as well because the style of programming changes based on it; i've tried using the C128's Z80 to power the VIC-IIe and it "feels" very different to writing CPC or Spectrum code in the same way that the Apple II and Atari 8-bit differ for 6502 use.

  • Like 5
Link to comment
Share on other sites

<< SNIP >>

 

I think it's a little easier to program the Z80 than the 6502 thanks to the 16 bit support.

Creating the most efficient code is another matter.

The Z80 font code took the longest to optimize. Every time I turned around I came up with another optimization.

Creating optimal code depends on best use of the Z80 registers and instructions.

Since many instructions only work with certain registers, redoing a section of code multiple times can result in some significant speed gains.

The optimizations weren't difficult but they weren't obvious from the start, and each new one was often a result of the previous one.

Where cutting out an instruction on the 6502 might drop 3 or 4 clock cycles, on the Z80 you are looking at more like 7 or 9, sometimes more.

A few optimizations resulted in tens of thousands of saved clock cycles when drawing a screen full of text.

The looping instructions give the Z80 and advantage but the one capable of scrolling the screen takes more cycles than others so the fastest version of the scroll is almost as much of an unrolled loop as the other cpus.

 

<< SNIP >>

I always found the lack of 16 Bit registers on the 6502 to be awkward too, but just recently discovered that using the Zero Page is a compromise to having more and bigger registers, and way more efficient than just using any RAM in the System..

 

MarkO

Link to comment
Share on other sites

I always found the lack of 16 Bit registers on the 6502 to be awkward too, but just recently discovered that using the Zero Page is a compromise to having more and bigger registers, and way more efficient than just using any RAM in the System..

 

MarkO

Direct addressing is one of the first things you should learn when using the 6502.

 

Keep in mind I also wrote the 64 column font code for the 6803 which also has page 0 support.

I'll take the 16 bit support over page 0 for most code.

Direct addressing saves 1 clock cycle per instruction but 16 bit support eliminates a lot more in a similar instruction set and architecture.

 

One thing I didn't mention in my previous comment is that it would be fairly easy to switch fonts at runtime on the 6803 and Z80 code.

The address of the font could be loaded from a variable.

The 6502 code would require self modifying code and it would require altering at least 42 bytes. That is a key limitation to the optimization I mentioned above.

Since the 6502 code doesn't use multiply and the same font data, it technically isn't doing exactly the same thing as the other versions and it shows.

Using a multiply and the same font data would make the 6502 code slower.

 

  • Like 1
Link to comment
Share on other sites

This is derived from my Z80, 6502, and 6803 font code for reading bytes of font data and writing to the screen.

Font data is from 2 tables which are pre-masked for left or right characters and lines are cleared before writes in this example.
The Z80 has everything in registers.
The 6502 code puts the screen address on page 0, then loads hard coded screen offsets in Y, and uses the hard the coded base address of each byte table the font. X holds the current character number.
The 6803 uses the stack pointer to point to font data, and the first screen address is in X. It hard codes screen offsets from the first address inline.
The code for writing two characters at once causes the 6502 and 6803 code to grow but the Z80 code stays the same number of instructions as this.

 

;z80

...

    ld    a,(de)            ; get next font byte
    xor    (hl)             ; combine half screen and half font
    ld    (hl),a            ; write result back to screen
    inc    de               ; next font data location
    add    hl,bc            ; next line

...



;6502
...
    ldy    #BytesPerLine*1  ;point to next screen byte.
    lda    (fscreen),y
    eor    FCol21,X         ; EOR with the next byte of the font    
    sta    (fscreen),y
...


;6803
...
    pula                    ; get byte of font and point to next font data
    eora    32,x            ; read byte at destination
    staa    32,x            ; write it to the screen
...

 


 

I changed portions of the code for the Z180, 68hc11, 6809, and 6309 just to see what it would look like.

All provide better code than their original versions, however, one of the Z180 changes that is well worth mentioning is the additional multiply instruction.
For the comparison here, 20 instructions are reduced to 11 and there is a significant reduction in clock cycles even if you ignore the 30% speedup the Z180 supposedly offers. This is from the code that prints two characters at a time.
The 65816 has many enhancements but a multiply instruction isn't one of them. If I were to chose a CPU for a new system back in the day, this might be a consideration.

 

 

; Z80
    ; C contains left character, A contains right character
    ld        b,0
    ; Calculate location of the first character font data in FONT_ADDR
    ; Formula: FONT_ADDR + 7 * INT ((char-32)/2) - 1
    ld        h,b
    ld        l,c            ; now HL = char
    add        hl,hl            ; now HL = 2 * INT(char)
    add        hl,hl            ; now HL = 4 * INT(char)
    add        hl,hl            ; now HL = 8 * INT(char)
    sbc        hl,bc            ; now HL = 7 * INT(char)
    ld        bc,FONT_ADDRl-224    ;add font address - correct for missing sbc a,' '
    add        hl,bc            ; now hl = FONT_ADDR + 7 * INT(char)
    ex        de,hl            ; use DE for first character data pointer
    ; Calculate location of the second character font data in FONT_ADDR
    ; Formula: FONT_ADDR + 7 * INT ((char-32)/2) - 1
    ld        h,0
    ld        l,a            ; now HL = INT(char)
    ld        b,h
    ld        c,l            ; now BC = char
    add        hl,hl            ; now HL = 2 * INT(char)
    add        hl,hl            ; now HL = 4 * INT(char)
    add        hl,hl            ; now HL = 8 * INT(char)
    sbc        hl,bc            ; now HL = 7 * INT(char)
    ld        bc,FONT_ADDRr-224    ;add font address - correct for missing sbc a,' '
    add        hl,bc            ; now hl = FONT_ADDR + 7 * INT(char) HL is now 2nd character data pointer


;Z180 / HD61480
    ; C contains left character, A contains right character
    ld        d,7            ; for the multiply by 7
    ld        e,c            ; left character
    ld        h,d            ; for the multiply by 7
    ld        l,a            ; right character
    mlt        DE            ; multiply the left character by 7
    mlt        HL            ; multiply the right character by 7
    ld        bc,FONT_ADDRr-224    ; get the right nibble adjusted font address
    add        hl,bc            ; add it to HL
    ex        de,hl            ; put it in DE so we can us HL again
    ld        bc,FONT_ADDRl-224    ; get the left nibble adjusted font address
    add        hl,bc            ; add it to HL

 

Edited by JamesD
Link to comment
Share on other sites

6502 was my first and favorite assembly language. There are few enough instructions to memorize and they are more consistent.

 

When programming in Z80 I always need to keep the instruction reference handy to see what registers are available and whether flags are affected. Z80 lasted longer than 6502 - I used it professionally into the mid '90s.

 

Oh, and 6502 feels more RISCy. ;)

  • Like 4
Link to comment
Share on other sites

6502 was my first and favorite assembly language. There are few enough instructions to memorize and they are more consistent.

 

When programming in Z80 I always need to keep the instruction reference handy to see what registers are available and whether flags are affected. Z80 lasted longer than 6502 - I used it professionally into the mid '90s.

Yeah, I keep Leventhal's book close at hand when I'm coding for the Z80.

I ran across a voting machine that still uses some form of Z80 about 6 years ago.

 

Oh, and 6502 feels more RISCy. ;)

Where is a barf emoticon when you need one? Edited by JamesD
Link to comment
Share on other sites

6502 was my first and favorite assembly language. There are few enough instructions to memorize and they are more consistent.

 

When programming in Z80 I always need to keep the instruction reference handy to see what registers are available and whether flags are affected. Z80 lasted longer than 6502 - I used it professionally into the mid '90s.

 

Oh, and 6502 feels more RISCy. ;)

I totally agree....

 

 

I first learned the 6502, then a little Z80 and then some 80x86.. The Zilog and Intel chips seemed so Cumbersome, Wordy and Verbose with ALL the Neumonics.. The 6502 made it very easy to Build onto what you Already knew, Very Incremental..

 

MarkO

Link to comment
Share on other sites

One odd thing about Z80 is that there are two different sets of mnemonics for the same instructions. Zilog expanded on Intel's 8080 instruction set but they created new mnemonics for both old and new instructions. CP/M coders tended to use the Intel mnemonics they already knew and added similar ones for the Z80's new instructions.

 

I preferred Zilog's mnemonics over Intel's. They were more explicit about register usage. Intel eventually saw the light and made the 8086 mnemonics more Zilogish.

Link to comment
Share on other sites

Another oddity is that the Z80 has a 4-bit ALU inside, so 8-bit data have to clock through twice. That's usually hidden in parallel with instruction processing, so, for example, ADD A,B takes 4 cycles on either the Z80 or the 8080. However, 16-bit data need 4 passes, so ADD HL,BC and INC HL take one more clock cycle on the Z80 than on the 8080 (where they are called DAD BC and INX H in Intelese).

Edited by ClausB
Link to comment
Share on other sites

Was the Z80 first to use prefix instructions? Those are single-byte instructions that change the behavior of the following instruction. Z80 uses four of them to extend the 8080 instruction set beyond a maximum of 256 opcodes.

 

Two of the prefixes merely modify HL instructions to use IX or IY (plus displacement) instead. For example, opcode 7E is LD A,(HL) and DD 7E is LD A,(IX+d). Although original instruction references never mentioned it, those prefixes also change H or L instructions to access the high or low bytes of IX or IY. For example, 67 is LD H,A and DD 67 is LD HX,A. HX means high byte of IX. Many assemblers don't support such unofficial use of prefixes. My favorite cross assembler for PC-DOS is table-driven so I can add those instructions myself.

  • Like 1
Link to comment
Share on other sites

I'm one of those who have owned 68K based computers for more than 20 years and took two courses in 68K assembly language at the university, but never even begun dabbling at home with machine code on the 68K based (Amiga in my case) computers in my collection. Every time I mention that, I feel guilty and that I really should have a try, and while I found the courses and labs rather easy to complete, it never compelled me to use my newly won knowledge for hobbyist purposes.

Link to comment
Share on other sites

I wrote some 68K assembly for the Amiga and embedded systems. The 68K was a joy to program for the most part.
The separate address and data registers, lack of instructions that involve two source registers and one destination register, and non-load and store design makes compiler support a little more complicated than for RISC CPUs, but the code is more efficient space wise than RISC CPUs of the day. The only significant improvement I can think of instruction wise would be to have all instructions work with all registers.

Since the 6502 mnemonics are based on Motorola syntax, I think it looks pretty familiar to people migrating from that CPU. Some of the features would feel much more familiar to a 6809 programmer.

While the Z80 is a little different, I don't think it's especially difficult for someone migrating from that processor to adapt. The more general purpose nature of registers (all data instructions work on all data registers and all addressing is done with address registers) is much easier to adapt to than going in the other direction.

FWIW, the Z8000 mnemonics look like it would have been more familiar to Z80 programmers, but instructions were more general purpose.
It was well suited to optimization with RISC type features (pipelining, cache, etc...), and was better than the X86 IMHO.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...