Amstrad NC100: how to create an application?

Amstrad CPC and NC systems
bbock
Member
Posts: 11
Joined: Mon Jan 03, 2011 12:35 am

Amstrad NC100: how to create an application?

Post by bbock »

Hello,

the documentation on the NC100 support is just a single line:

Code: Select all

zcc +nc -lm application.c
Well, I've tried this on a simple program to compute prime numbers:

Code: Select all

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int z, d;
    int prim;
    int grenze;
    
    printf("Primzahlen bis 1000:\n");
    grenze = 1000;
    
    printf("  2 ");
    
    for (z = 3; z < grenze; z += 2) {
        prim = 1;
        
        for (d = 3; d < z / 2; d += 2) {
            if (z % d == 0) {
                prim = 0;
                break;
            }
        }
        
        if (prim) {
            if (z <  10) printf(" ");
            if (z < 100) printf(" ");
            printf("%d ", z);
        }
    }
    
    return 0;
}
It compiled, and I got a binary file which I renamed to Prim.com, but I did not yet succeed to run it on my NC100. I tried a BASIC loader to run the program:

Code: Select all

10 REM Prim - ROM OS loader
20 IF LOMEM>=&5400 THEN PRINT "Error - need 19k of lower memory free!":END
30 *LOAD PRIM.COM 8C00
40 VDU 4:CLS
50 CALL &8C00
60 VDU 5:CLS
Any hints on how to run a z88dk compiled C source on an Amstrad NC100?

Thanks for any comment.
Bernd
User avatar
dom
Well known member
Posts: 1194
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

I'm not sure anybody has actually tried out nc100 support.

It looks like the output is meant to be saved to a PCMCIA card, take a look at Cliff Lawson's nc100 doc at:

http://web.ukonline.co.uk/cliff.lawson/nciospec.txt

from which I seem to have take the information from.

I'm not sure that it's the best format, and I'm quite happy to see it change to something more useful.
bbock
Member
Posts: 11
Joined: Mon Jan 03, 2011 12:35 am

Post by bbock »

There's an example (game) program named "scrolly" at Tim Surtell's site:

http://www.ncus.org.uk/games.htm#scrolly_nc

It can be executed on the ROM OS through the BASIC loader program (which is what I used as a template for my prime number program above) or directly on ZCN (a CP/M clone for the NC100). I don't see any special requirements like an ASCII string "NC100PRG", a special origin or a necessary jump to a fixed location. I tested this program, and it runs fine on my NC100.

So maybe we just need to tell the compiler to use the origin we want, maybe using the -zorg compiler option? (Does it need its input as hex or decimal? There's no information about the format.) I guess we'd need -startup=3, too. What else? -make-app? -create-app?
bbock
Member
Posts: 11
Joined: Mon Jan 03, 2011 12:35 am

Post by bbock »

Still investigating...

Apparently the z88dk creates code at the SRAM Card location $C200, which is appropriate if you want to create a program card. I use my SRAM Card in a regular manner, i.e. to save files from the word processor, spreadsheet, BASIC, etc. Using the BASIC loader, I need to load the program to a chosen memory location (e.g. $8C00) and run it from there.

So I modified the nc100_crt0.asm file and deleted the lines between the org statement and the start label. I changed the origin to $8C00, which is appropriate for my BASIC loader (I'd prefer to be able to set it dynamically, though, maybe using -zorg?).

I'm not sure what the start and the cleanup code does, but I could at least run the prime number program. I marvelled at the correct prime number output, and then gnashed my teeth when I saw that the NC100 crashed on return...

There must be something wrong with the cleanup code, I guess (help is appreciated).
bbock
Member
Posts: 11
Joined: Mon Jan 03, 2011 12:35 am

Post by bbock »

As soon as I deleted the whole cleanup code except for the ret statement, I succeeded in running the program and returning safely to the BASIC prompt. I guess I compromised something in the file i/o area, so I'm afraid I need a deeper insight...

Here's my current nc100_crt0.asm file (didn't find a way to upload a file here):

Code: Select all

;       Kludgey startup for nc100
;
;       djm 17/4/2000
;
;         I've never used one of these brutes so I dunno if it's
;        correct at all, this is all taken from the file nciospec.doc
;        on nvg.unit.no, I assume that the PCMCIA RAM card is an
;        actual fact addressable RAM and we can overwrite variables
;        etc NB. Values of static variables are not reinitialised on
;        future entry.
;
;       $Id: nc100_crt0.asm,v 1.8 2009/06/22 21:20:05 dom Exp $
;



        MODULE  nc100_crt0

;--------
; Include zcc_opt.def to find out some info
;--------
        INCLUDE "zcc_opt.def"

;--------
; Some scope definitions
;--------

        XREF    _main                ;main() is always external to crt0 code

        XDEF    cleanup                ;jp'd to by exit()
        XDEF    l_dcal                ;jp(hl)

        XDEF    _std_seed        ;Integer rand() seed

        XDEF        _vfprintf        ;jp to the printf() core

        XDEF    exitsp                ;atexit() variables
        XDEF    exitcount

               XDEF        heaplast        ;Near malloc heap variables
        XDEF        heapblocks

        XDEF    __sgoioblk        ;stdio info block

        XDEF        base_graphics        ;Graphical variables
        XDEF        coords

    org     $8C00

start:
        call    _main                ;Call user code
cleanup:
        ret

l_dcal:        jp        (hl)

; Now, define some values for stdin, stdout, stderr

__sgoioblk:
IF DEFINED_ANSIstdio
        INCLUDE        "stdio_fp.asm"
ENDIF


;-------
; Now, which of the vfprintf routines do we need?
;-------
_vfprintf:
IF DEFINFED_floatstdio
        LIB        vfprintf_fp
        jp        vfprintf_fp
ELSE
        IF DEFINED_complexstdio
                LIB        vfprintf_comp
                jp        vfprintf_comp
        ELSE
                IF DEFINED_ministdio
                        LIB        vfprintf_mini
                        jp        vfprintf_mini
                ENDIF
        ENDIF
ENDIF


;-------
; Some variables
;-------

_std_seed:       defw    0        ;Integer rand() seed

;Atexit routine

exitsp:                defw        0        ;atexit() stack address
exitcount:        defb        0        ;Number of atexit() routines
heaplast:        defw        0        ;heap variables
heapblocks:        defw        0

base_graphics:        defw        0        ;Graphics variables
coords:                defw        0

                defm        "Small C+ nc100"
                defb        0

;-------
; Floating point
;-------
IF NEED_floatpack
        INCLUDE         "float.asm"

fp_seed:        defb    $80,$80,0,0,0,0        ;FP seed (unused ATM)
extra:          defs    6                ;FP spare register
fa:             defs    6                ;FP accumulator
fasign:         defb    0                ;FP variable

ENDIF
User avatar
dom
Well known member
Posts: 1194
Joined: Sun Jul 15, 2007 10:01 pm

Post by dom »

All the cleanup code does is to close all the open files (since there's no file support for nc100 this shouldn't do anything) and restore the stack to what it was on entry.

It's also got some dodgy code to do with restoring hl' which looks like it was a hanger on from the ZX port. Perhaps it's this that's causing the problem.
stefano
Well known member
Posts: 1534
Joined: Mon Jul 16, 2007 7:39 pm

Post by stefano »

While inserting the support for the automatic malloc() heap definition I took the opportunity to insert also the '-startup=2' option.
It will hopefully do what bbock was asking for: different location for ORG and card header removed.
If anybody is still onto the nc100, just tell.. if the program is invoked by the CP/M or another OS we can easily add support parameter parsing (argv, argc..) and more.
EtchedPixels
Member
Posts: 20
Joined: Sat Aug 30, 2014 7:08 pm

Post by EtchedPixels »

Resurrecting an old thread a bit

The Amstrad set up is a bit strange. Firstly the NC100 is a persistent system, it doesn't get rebooted unless something goes horribly wrong (and that means 'I hope your files were backed up on PCMCIA card')

Programs run from basic you really need to make space by playing with the BASIC mem ptrs and keep any heap in that area (automalloc is definitely wrong)

When you run from PCMCICA NC100PRG card ("program card") you are paged in at 0xC000, with the system in the low banks. You have a stack of about 1-2K (I forget exactly) as provided by the system. The heap memory you have available is A000-A3FF which is shared with other apps (so if you yellow button away and then get re-entered it's gone). If you don't use the file selector OS call you've also got A800-AFFF. For any other memory you need to use heapalloc, heaplock, heapaddr, heapfree. These are also persistent, so you either need to keep the handles safe to always have a clean up method, or free them.

The executable mindset is very very different though. The normal behaviour is that you switch between apps
and they keep their state, so running a program doesn't mean "starting it".

The OS itself expects 0000-BFFF to be mapped, C000-FFFF is the usual ROM/PCMCIA window which means bank switching is exciting and you either need a trampoline in Axxx somewhere or to pull the stunt where you
do an out to set the bank and then fetch the next instruction from the new bank, next IP. If you do want to map into other banks you also need to update the system variables and you need to write the variable before you do the out instruction (because NMI is used for power management)

Screen is also at 0xC000 just to be irritating.

For any kind of "normal" apps though you can just build for CP/M instead and run the CP/M clone for the box.

Summary though: the automalloc looks very wrong and will probably eat your computer.
stefano
Well known member
Posts: 1534
Joined: Mon Jul 16, 2007 7:39 pm

Post by stefano »

Got your hint, thus the current amalloc trick will be removed.. idea for a better heap location rather than a static internal block ?
EtchedPixels
Member
Posts: 20
Joined: Sat Aug 30, 2014 7:08 pm

Post by EtchedPixels »

I think you are stuck with a static block and/or A000-A3FF (if running from a card). To go beyond that you have to use the OS heap*() functions and clean them up on exit.

The system does have a real file system and memory allocators. I'll have a fiddle at some point. Need to put the PCI/PCMCIA card reader back into a PC first but I do have a real NC100..
stefano
Well known member
Posts: 1534
Joined: Mon Jul 16, 2007 7:39 pm

Post by stefano »

It's great to find someone still active on the nc100, I'm looking forward more experiment results :)
EtchedPixels
Member
Posts: 20
Joined: Sat Aug 30, 2014 7:08 pm

Post by EtchedPixels »

A bit stuck at the moment. While waiting for a chance to play with the memory card I added full stdio support to the nc100, or at least that was the plan.. but if I use say printf() I get

cp /tmp/tmpXX2xiqa7.opt /tmp/tmpXX2xiqa7.asm
zcpp -I. -DZ80 -DNC100 -D__NC100__ -DSCCZ80 -DSMALL_C -I/usr/local/lib/z88dk//include test.c /tmp/tmpXXyNJSdV.i
sccz80 -asm=z80asm /tmp/tmpXXyNJSdV.i
copt /usr/local/lib/z88dk//lib/z80rules.2 < /tmp/tmpXXyNJSdV.asm > /tmp/tmpXXyNJSdV.op1
copt /usr/local/lib/z88dk//lib/z80rules.1 < /tmp/tmpXXyNJSdV.op1 > /tmp/tmpXXyNJSdV.opt
z80asm -eopt -ns -Mo -I/usr/local/lib/z88dk//lib /tmp/tmpXXyNJSdV.opt
z80asm -a -m -Mo -L/usr/local/lib/z88dk//lib/clibs -I/usr/local/lib/z88dk//lib -oa.bin -inc100_clib -iz80_crt0 /tmp/tmpXX2xiqa7.opt /tmp/tmpXXyNJSdV.o
Error at file '/tmp/tmpXX91EreK.opt' line 71: symbol not defined
1 errors occurred during assembly
Key to filenames:
/tmp/tmpXXyNJSdV.o = test.c
Error at file '/tmp/tmpXX91EreK.opt' line 71: symbol not defined
Segmentation fault (core dumped)

Linking with -lndos works *but* as far as I can tell (and strings seems to be about the only tool to dump z88dk libraries ?) printf is in nc100_clib.lib

Bulding the same file with the uzi tree I get the rather more expected
Errors in source file test.c:
Error at file '/tmp/tmpXX4w7nDV.opt' line 57: symbol not defined
^ ---- call creat
Error at file '/tmp/tmpXX4w7nDV.opt' line 99: symbol not defined
^ ---- call close

and close and creat are in the uzi C lib as far as I can tell, but it *does* find printf, and blows up politely a step earlier

Confused at this point
EtchedPixels
Member
Posts: 20
Joined: Sat Aug 30, 2014 7:08 pm

Post by EtchedPixels »

Ok at least half of it seems to be a compiler bug

Simple demo

extern int __LIB__ close(int fd);
#ifdef BOGUS
extern int __LIB__ close(int fd);
#endif
#ifdef BOGUS2
extern int __LIB__ close(int fd);
#endif

int main()
{
close(0);
}


Build with no defines it works, build with -DBOGUS if fails, build with both defines set it works again!

Still baffled by the segfaulting case
EtchedPixels
Member
Posts: 20
Joined: Sat Aug 30, 2014 7:08 pm

Post by EtchedPixels »

Ok root caused - definitely an ugly assembler bug it doesn't report it but the trigger was

LIB writebyte
XREF write

.writebyte pop ix
pop de
ld hl, 0
add hl, sp
ld bc, 1
call 0xB8AB
push de
ld h, b
ld l, c
jp (ix)

and swapping the LIB to the correct XLIB stops the crash
EtchedPixels
Member
Posts: 20
Joined: Sat Aug 30, 2014 7:08 pm

Post by EtchedPixels »

Tested on a real NC100, I need to fix some library problems but the corrected startup code seems to work fine. In answer to the question where to put the initial malloc heap - the answer is in the startup code where it says "Waste 509 bytes" !

Unlike Axxx ranges that range is persistent so if you yellow button out and then return it is still present

Incidentally the yellow button code in the stdio code is a bit dubious - you don't want to leap randomly out of the library code but to do a controlled departure. I'll have a look at fixing that and tidying it all up a bit when I get some time next week
stefano
Well known member
Posts: 1534
Joined: Mon Jul 16, 2007 7:39 pm

Post by stefano »

Good idea, to use that space for malloc, :)
stefano
Well known member
Posts: 1534
Joined: Mon Jul 16, 2007 7:39 pm

Post by stefano »

I'm printing your hints for malloc() to read them quietly (the CPC stuff can wait a little more :P ).

The printf() stuff, is linked in any core library but all the file stuff is kept aside, so a programmer can potentially choose between different fcntl flavours, where ndos.lib is just a do-nothing termination (see fcntl/dummy).

'close' is most probably required everytime you use printf (called on exit), but I'm not sure on 'creat': could it be inside your 'open' implementation ? Which library did you base your library on ?
stefano
Well known member
Posts: 1534
Joined: Mon Jul 16, 2007 7:39 pm

Post by stefano »

I just updated the nc100 CRT0 file with a new optional 'AMALLOC' implementation.
It uses that fixed 500 bytes area and I did not test it at all.. sorry but to get a program into an emulator was taking too long and I was risking to loose the current work, so here it is.
EtchedPixels
Member
Posts: 20
Joined: Sat Aug 30, 2014 7:08 pm

Post by EtchedPixels »

Thanks

I've been debugging the enabling bits for a full file implementation for the NC100 (the ROM methods include file I/O, rename etc). Once it's a bit more stable I'll submit it for comment.
EtchedPixels
Member
Posts: 20
Joined: Sat Aug 30, 2014 7:08 pm

Post by EtchedPixels »

The issue with close btw is the close() but the compiler

If you define a function
extern int __LIB__ close(int fd);

the it is found

If you define it again then it is not found

If you define it a third time it is found

ie the code somewhere is doing a +1 every time it finds an external definition of it, but an & 1 when checking for it ???
EtchedPixels
Member
Posts: 20
Joined: Sat Aug 30, 2014 7:08 pm

Post by EtchedPixels »

Amstrad bits uploaded to

http://www.fuzix.org/downloads/z88dk/
EtchedPixels
Member
Posts: 20
Joined: Sat Aug 30, 2014 7:08 pm

Post by EtchedPixels »

Web site fixed (had some ISP problems but should now be downloadable)
stefano
Well known member
Posts: 1534
Joined: Mon Jul 16, 2007 7:39 pm

Post by stefano »

Got it.
Some element seems to be missing, though:

Error: cannot read file 'stdio/nc100/fgets_cons.asm'
Error: cannot read file 'fcntl/nc100/lseek.asm'
Error: cannot read file 'fcntl/nc100/open_z88.asm'
Error: cannot read file 'fcntl/nc100/opendir.asm'

I also suppose you prepared a target specific header file right ?
EtchedPixels
Member
Posts: 20
Joined: Sat Aug 30, 2014 7:08 pm

Post by EtchedPixels »

Those are the C bits and are included

nc100/nc100.h was missing - I've uploaded nc100.h as a separate header file to the same dir.

My NC200 arrived a few days ago so I hope to test if the NC100 code works on the 200 soon - it ought to.
stefano
Well known member
Posts: 1534
Joined: Mon Jul 16, 2007 7:39 pm

Post by stefano »

No it wasnt ! :)
By the way things were not so bad as I thought, most of the problem went away when I included the fcntl portions written in C in the compilation loop.
I had only to exclude "opendir.c" (probably the culript is a missing declaration for 'DIR') and to replace "puts_cons" with its generic equivalent.
Looking forward the nightly build ..
Post Reply