Z88dk: [sdcc, Z80] -SO3 breaks resulting code

Created on 29 Aug 2020  路  9Comments  路  Source: z88dk/z88dk

Hi!

I'm currently porting uIP (an ethernet and TCP/IP stack) to a Z80 processor using z88dk.
Unfortunately the checksum function behaves wrongly when compiled with -SO3.
The checksum routine is a bit dirty, but it works fine on any other tested platform (x86, AVR).

Following command line results in non-working output:
zcc +rc2014 -subtype=acia -SO3 -clib=sdcc_iy --c-code-in-asm --list main.c -o main -create-app

sum: 1431 len: 0028

checksum: 0001

Following command line gives the expected result: (0xFFFF being a valid checksum for the packet)
zcc +rc2014 -subtype=acia -SO2 -clib=sdcc_iy --c-code-in-asm --list main.c -o main -create-app

sum: 1431 len: 0028

checksum: ffff

I haven't tried sccz80 and clang yet, should I try using those for my project yet? Are they stable enough for general usage?

Thanks!

Example code:

#include <stdio.h>
#include <stdint.h>
#include <string.h>

typedef uint16_t u16_t;
typedef uint8_t u8_t;

u16_t chksum(u16_t sum, const u8_t *data, u16_t len)
{
  printf("sum: %04x len: %04x\n", sum, len);
  //print_memory(data, len);
  printf("\n");

  u16_t t;
  const u8_t *dataptr;
  const u8_t *last_byte;

  dataptr = data;
  last_byte = data + len - 1;

  while(dataptr < last_byte) {  /* At least two more bytes */
    t = (dataptr[0] << 8) + dataptr[1];
    sum += t;
    if(sum < t) {
      sum++;        /* carry */
    }
    dataptr += 2;
  }

  if(dataptr == last_byte) {
    t = (dataptr[0] << 8) + 0;
    sum += t;
    if(sum < t) {
      sum++;        /* carry */
    }
  }


  printf("checksum: %04x\n", sum);
  printf("\n\n");
  /* Return sum in host byte order. */
  return sum;
}

uint8_t data[] = {
    0xb9, 0xf6, 0x03, 0xe8, 0x35, 0x1a, 0x1e, 0x8b, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0xfa, 0xf0, 0x27, 0x56, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0xd2, 0x1e, 0x2e, 0x14, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07
};
void main()
{
    chksum(0x1431, data, 0x0028);

    while (1) {}
}

Most helpful comment

No worries. Thanks for the good report in the first place.

There鈥檚 some checksum routines here: https://github.com/suborb/zsock/blob/master/kernel/z80.c that might be useful btw

All 9 comments

This one looks like there's an error in the z88dk rules which is triggered by the --allow-unsafe-reads option used by the rc2014 target.

I'll try and track down which one is causing the problem.

The clang work was always experimental - it will use sdcc as a backend in any case. sccz80 doesn't have any issues with the code you've posted.

It looks like it was rule z88dk-414l4 causing issues - I've qualified it further so it won't fire in this case.

Wow, nice, thanks for the quick fix!

No worries. Thanks for the good report in the first place.

There鈥檚 some checksum routines here: https://github.com/suborb/zsock/blob/master/kernel/z80.c that might be useful btw

Much to my surprise, my whole project idea actually works:
http://rc2014.as203478.net/

https://github.com/Manawyrm/RC2014-Ethernet-Firmware

That's great to see. I like the Ethernet Module too.

If you want to try ChaN's FATFS (rather than his PetitFS), I've a library for FF already available. Then you could serve multiple files and handle multiple sockets.

ChaN's FATFS

I'm using the full FatFs library in my serial bootloader/file transfer utility, but the lib is ~17KiB of code in a pretty minimal configuration. This and the ~30 KiB of the uIP + NE2k driver + my 16 KiB ROM is too much for the address space of the Z80...
I'd need to add paging or do some very effective optimizations on the code.

I ran into a similar issue using FatFS and the Wiznet W5100 a while ago on the Arduino UNO. There simply wasn't enough space to do both IP interface and file system. That was the genesis of the whole "Goldilocks" AVR thing, and a couple of years of fun and learning.

Was there a rational for using the RTL8019 device, over the Wiznet W5500 device?

With the W5500 the IP stack comes built-in saving a lot of library code, yet you can still use MACRAW mode to support uIP if desired.

There was some talk of building a W5500 Module, but I don't think it actually happened. So I'm interested to know why the RTL8019?

Couple of reasons:

  • W5500 do not support IPv6 (W6100 does, I'll need to get some samples of that chip)
  • It's not a classic chip, NE2k was around since the late 80's, the RTL8019 was released in ~1993.
  • I have previous bad experience with DoS/IP stack bugs in the W5100 chips. (but haven't touched W5500, W6100 after that).
  • not too bad, but they are 3.3V parts and create a lot of heat/have high power consumption. that will require a big ground plane for heat sinking and a powerful linear regulator (or even a small step down).

And well, JLC just had the RTL8019 for assembly in stock, so I thought I'd be fun. (they also have the Wiznet chips...)
So: Sure, for practical use (data transfer, etc.), I'd go with W5500, W6100 as well.
But this is more of a fun way to learn about the ISA bus, NE2000, ethernet and TCP/IP (and I learned a lot along the way :smile: )

After now getting my feet wet with ISA peripherals and designing my own hardware, the next "dream" step would be to connect an ISA VGA card to a Z80 processor. But I'm currently prototyping that using an Arduino and not getting too far. (but that's out of topic for this GitHub issue and more something for my Twitter account).

Was this page helpful?
0 / 5 - 0 ratings

Related issues

feilipu picture feilipu  路  13Comments

Fabrizio-Caruso picture Fabrizio-Caruso  路  7Comments

feilipu picture feilipu  路  9Comments

zx70 picture zx70  路  13Comments

suborb picture suborb  路  11Comments