C on the Spectrum (z88dk)

The place for codemasters or beginners to talk about programming any language for the Spectrum.
dom
Berk
Posts: 3
Joined: Sun Feb 10, 2019 11:08 am

Re: C on the Spectrum (z88dk)

Post by dom » Sun Feb 10, 2019 11:27 am

FFoulkes wrote:
Thu Feb 07, 2019 4:15 pm
Well, it comes with scripts "build.sh" and "config.sh". These have to be executable ("chmod +x ./build.sh", "chmod +x ./config.sh"). It compiles ok then, when you run "./build.sh" (OpenSuSE 13.1), no severe errors. Installation goes into "/usr/local/share/z88dk" then. Sometimes it wants something in "/usr/local/lib/z88dk" instead.
That's not intended - can you let me know which ones?
FFoulkes wrote:
Thu Feb 07, 2019 4:15 pm
The build-directory with the compiler-libraries was 171 Mb in size. Quite big for a compiler targeting a simple 8 bit-platform, I would say.
Well...each target (machine) library is roughly a megabyte, and there's about 80 of them so the disc space mounts up quickly!
0 x

FFoulkes
Berk
Posts: 30
Joined: Thu Feb 07, 2019 2:42 pm

Re: C on the Spectrum (z88dk)

Post by FFoulkes » Sun Feb 10, 2019 5:06 pm

dom wrote:
Sun Feb 10, 2019 11:27 am
That's not intended - can you let me know which ones?
Ah, never mind. I think, it's ok. I was a bit confused (by the installation), when I wrote the posting.
0 x

User avatar
utz
Dizzy
Posts: 53
Joined: Wed Nov 15, 2017 9:04 am
Contact:

Re: C on the Spectrum (z88dk)

Post by utz » Sun Feb 10, 2019 7:39 pm

dom wrote:
Sun Feb 10, 2019 11:15 am
utz wrote:
Sat Feb 09, 2019 2:07 pm
Doesn't quite work for me with latest nightly. On step 'Verify the Install':

Code: Select all

$ zcc +zx -vn test.c -o test -lndos           
warning: unknown option '-iquote.'
warning: unknown option '-isystem/home/myuser/path/to/z88dk/lib/config/../..//include'
spurious duplicate filename '/tmp/tmpXXkntuNK.i2' - vs. 'test.c' 
Usage: ucpp [options] [file]
...
I think that means there's another ucpp on your path somewhere. Setup the path so that z88dk/bin is first. There is a compilation option to prefix all the commands with something unique to avoid this problem for global installations but I'm not sure it works properly for the zsdcc component.
Confirmed, I have ucpp as part of my OS (Gentoo), where it is required to build libreoffice. I'm no expert on these matters but I think that implies that changing the path is not an option. How do I apply the prefix option for a local installation? I tried setting it in the Makefile but that didn't solve the problem.

EDIT: Upon second thought, I think I can get away with overriding the path just for the user session, as I probably won't be needing the system ucpp for anything else. At least for now it works fine. So, thanks for your help :) Might still be a good idea to have those prefixes available for local installs somehow.
0 x

FFoulkes
Berk
Posts: 30
Joined: Thu Feb 07, 2019 2:42 pm

Re: C on the Spectrum (z88dk)

Post by FFoulkes » Mon Feb 11, 2019 1:16 am

Well, I'm running into a problem now. I'd like to print a UDG at a certain place on the screen.
Printing an "A" works with "-startup=1", but this has no UDG-support, meaning "printf("%c", 144);" doesn't do anything (although the UDG is defined (at address 65368)).
"-startup=30" has a certain UDG-support (printing in general does work then). But then the "PRINT AT" doesn't work:

Code: Select all

#include <stdio.h>
int main() {
    puts("\x16\x0A\x0D" "A");
    return 0;
}

Code: Select all

zcc +zx -vn -clib=sdcc_iy -startup=30 -zorg=32768 -create-app test.c
Any ideas how to get both working (UDG plus "PRINT AT")? Seems to be quite important for games, I guess.

There was a discussion about it here, but there wasn't a solution yet. Maybe we have to wait for further compiler development ...

Oh, and there is an error "Integer out of range" then, which looks just like in Basic. If the ordinary ROM-routines are called anyway, C may not be much faster than Basic, I think.
0 x

dfzx
Microbot
Posts: 168
Joined: Mon Nov 13, 2017 6:55 pm
Location: New Forest, UK
Contact:

Re: C on the Spectrum (z88dk)

Post by dfzx » Mon Feb 11, 2019 3:52 pm

FFoulkes wrote:
Mon Feb 11, 2019 1:16 am
Well, I'm running into a problem now. I'd like to print a UDG at a certain place on the screen.
I think there's a bit of a context shift required for people coming to C on the Spectrum. UDGs are largely a concept from BASIC which don't make a lot of sense in the C world. C is much closer to assembly language, so you need to think at a lower level. OTOH, the stdio stuff is a high level concept from UNIX, and although it's a useful starting point I personally have never been convinced of its value on the Spectrum. Once you get past "hello world," unless you're doing something which requires a lot of text manipulation, you'll probably just turn it off. Mixing these disparate concepts together is, as you've found, a bit of a headache. It's possible to make it work, as per Alvin's post which you found in the z88dk forum, but it doesn't really happen naturally.

So, at the risk of telling you you're asking the wrong question then answering my own, let's take a step back. :)

As soon as you start thinking about UDGs, you're thinking about graphics, and graphics, once you step outside the world of BASIC, means you need to start thinking about how to directly change the Spectrum's display. The display is memory mapped, so you change it by POKEing (to use the BASIC terminology) values into it. If you want an 8x8 pixel graphic to appear in the middle of the display you can do it like this:

Code: Select all

#include <arch/zx.h>

unsigned char hash_udg[] = { 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA };

void printc(unsigned char x, unsigned char y, unsigned char* udg)
{
   unsigned char *p;
   unsigned char i;

   p = zx_cxy2saddr(x, y);

   for (i = 0; i < 8; ++i)
   {
      *p = *udg++;
      p += 256;
   }
}

int main( void )
{
  printc(15, 12, hash_udg);
  return 0;
}
which you can compile with:

Code: Select all

zcc +zx -vn -clib=sdcc_iy -startup=31 printc.c -o printc -create-app
The zx_cxy2saddr() function is described along with all its friends here, but in essence it takes an x,y character coordinates pair and returns you the address in the Spectrum's display of the top byte of that character cell. Adding 256 to it returns the address of the byte directly below it, hence the loop POKEs the 8 UDG byte values directly into the display at the place required.

That's the simple and fast way. At the other extreme you can use the SP1 library. You're not at that level yet, and I haven't written the tutorial article which tells you how to do it, but as a peek ahead you can see the control characters of the SP1 library's very sophisticated print facility here. SP1 isn't to everyone's taste, nor the answer to all problems, but if you're after a powerful library to experiment with for graphics it's worth looking into when you're ready.

Quite where this all leaves you I'm not sure. :lol: I suppose it depends on what you're trying to learn or what problem you're trying to solve.
1 x

dom
Berk
Posts: 3
Joined: Sun Feb 10, 2019 11:08 am

Re: C on the Spectrum (z88dk)

Post by dom » Mon Feb 11, 2019 8:09 pm

dfzx wrote:
Mon Feb 11, 2019 3:52 pm
I think there's a bit of a context shift required for people coming to C on the Spectrum. UDGs are largely a concept from BASIC which don't make a lot of sense in the C world. C is much closer to assembly language, so you need to think at a lower level. OTOH, the stdio stuff is a high level concept from UNIX, and although it's a useful starting point I personally have never been convinced of its value on the Spectrum. Once you get past "hello world," unless you're doing something which requires a lot of text manipulation, you'll probably just turn it off. Mixing these disparate concepts together is, as you've found, a bit of a headache. It's possible to make it work, as per Alvin's post which you found in the z88dk forum, but it doesn't really happen naturally.
I have to admit that I've never fully got to grips with the way the newlib stdio works, it's powerful but has quite a bit of overhead.

In fact, stdio one of two areas where classic and newlib really diverge: most of the rest of the library code is shared. However, if you're looking to create a text based application that works across many platforms then classic may be the answer.

The gencon is a terrible name for the VT52+ZX Code screen driver that's supported on "most" of the classic targets. It provides a consistent way to print text (and yes, UDGs) and handle colours across many platforms. It even provides a SCREEN$ equivalent for collision detection. Cross Chase uses gencon for many of the z80 builds.
Last edited by dom on Mon Feb 11, 2019 8:18 pm, edited 1 time in total.
0 x

FFoulkes
Berk
Posts: 30
Joined: Thu Feb 07, 2019 2:42 pm

Re: C on the Spectrum (z88dk)

Post by FFoulkes » Mon Feb 11, 2019 8:17 pm

Thank you, dfzx. I think, this is a very good answer!
Because probably more people starting with C on the Spectrum will come to the point, where they need to think beyond Basic.
At the moment, I wasn't sure about going for C or assembly directly, so I watched a tutorial about Spectrum's assembly. Quite a good one, actually. There was some homework, so I wondered, if I could do that in C. That was, what got me there.
Next step would be to get that colour (white on blue). The control codes won't be the answer, I guess. :)
0 x

FFoulkes
Berk
Posts: 30
Joined: Thu Feb 07, 2019 2:42 pm

Re: C on the Spectrum (z88dk)

Post by FFoulkes » Mon Feb 11, 2019 9:15 pm

Consider this. "PRINT AT" again ... :) :

Code: Select all

#include <arch/zx.h>
#include <stdio.h>
#include <string.h>

void cls() {
    zx_cls(PAPER_WHITE);
}

void printCharAt(unsigned char x, unsigned char y, unsigned char c) {
   unsigned char *p;
   unsigned char *dat;
   long int temp;
   unsigned char i;
   temp = 15360 + c * 8;
   dat = (unsigned char *) temp;
   p = zx_cxy2saddr(x, y);
   for (i = 0; i < 8; ++i) {
      *p = *dat;
      dat++;
      p += 256;
   }
}

void printUdgAt(unsigned char x, unsigned char y, unsigned char *udg) {
   unsigned char *p;
   unsigned char i;
   p = zx_cxy2saddr(x, y);
   for (i = 0; i < 8; ++i) {
      *p = *udg;
      udg++;
      p += 256;
   }
}

unsigned char printAt(unsigned char x, unsigned char y, unsigned char *mystring) {
    unsigned char slen = strlen(mystring);
    if (x + slen > 32) {
        puts("Warning: Integer out of range. Nothing printed.");
        printf("x: %d  string: %s\n", x, mystring);
        return 1;
    }
    if (y > 21) {
        puts("Warning: Integer out of range. Nothing printed.");
        printf("y: %d\n", y);
        return 2;
    }
    unsigned char i;
    for (i=0; i < slen; i++) {
        printCharAt(x, y, mystring[i]);
        x++;
    }
    return 0;
}

int main() {
    cls();
    unsigned char a[] = "CONNECT 4";
    unsigned char udg1[] = {0, 24, 60, 126, 126, 60, 24, 0};
    printAt(12, 4, a);
    unsigned char i;
    unsigned char u;
    unsigned char fieldstart_x = 13;
    unsigned char fieldstart_y = 10;
    for (i=0; i<6; i++) {
        for (u=0; u<7; u++) {
            printUdgAt(fieldstart_x + u, fieldstart_y + i, udg1);
        } 
    }
    return 0;
}
0 x

FFoulkes
Berk
Posts: 30
Joined: Thu Feb 07, 2019 2:42 pm

Re: C on the Spectrum (z88dk)

Post by FFoulkes » Mon Feb 11, 2019 10:33 pm

Ok, I got colours now, too:

Code: Select all

#define BLACK   0
#define BLUE    1
#define RED     2
#define MAGENTA 3
#define GREEN   4
#define CYAN    5
#define YELLOW  6
#define WHITE   7

void setColour(unsigned char x, unsigned char y, unsigned char paper, unsigned char ink) {
    unsigned char *p = zx_cxy2aaddr(x, y); 
    *p = 8 * paper + ink;
}
0 x

dfzx
Microbot
Posts: 168
Joined: Mon Nov 13, 2017 6:55 pm
Location: New Forest, UK
Contact:

Re: C on the Spectrum (z88dk)

Post by dfzx » Tue Feb 12, 2019 9:46 am

FFoulkes wrote:
Mon Feb 11, 2019 10:33 pm
Ok, I got colours now, too:

Code: Select all

#define BLACK   0
#define BLUE    1
#define RED     2
#define MAGENTA 3
#define GREEN   4
#define CYAN    5
#define YELLOW  6
#define WHITE   7

void setColour(unsigned char x, unsigned char y, unsigned char paper, unsigned char ink) {
    unsigned char *p = zx_cxy2aaddr(x, y); 
    *p = 8 * paper + ink;
}
Yes, that's the idea! When do we get to play the final game? :)

Have a look in arch/zx.h though - all the colour macros are in there, plus other stuff you're likely to need.
0 x

Post Reply