News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu

sdcc

Started by arnoldemu, 13:36, 31 August 12

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

arnoldemu

Ok so I've started developing a game using sdcc.

I am not using sdcc2pasmo, because I want to make my own libs and link with them.

My lib making batch file for windows looks like this:


sdasz80 -plosgff cpc_GetRRegister.s
sdasz80 -plosgff cpc_Random.s
sdasz80 -plosgff cpc_RandomInRange.s
sdasz80 -plosgff cpc_SetRandSeed.s
sdasz80 -plosgff cpc_TestKeyCode.s
sdasz80 -plosgff cpc_ScanKeyboard.s
sdasz80 -plosgff cpc_KeyMap.s
sdasz80 -plosgff cpc_InVsync.s
sdcclib mylib.lib cpc_GetRRegister.rel cpc_Random.rel cpc_RandomInRange.rel cpc_SetRandSeed.rel cpc_TestKeyCode.rel cpc_ScanKeyboard.rel cpc_KeyMap.rel cpc_InVsync.rel


which generates the sdcc mylib.lib

My sdcc compile looks like this:


sdcc --verbose -V --nostdlib --opt-code-speed --nostdinc --codeseg _CODE --no-std-crt0 -mz80 -DDISC=1 -I lib/mylib -l lib/mylib/mylib.lib game.c
hex2bin game.ihx


then my usual bits for making a dsk, cdt etc and injecting the file.

so far so good.

in the sdcc doc it says to use this to generate an interrupt handler:


void interrupt_handler(void) __interrupt(1)


great.

this is at the start:


_interrupt_handler_start::
_interrupt_handler:
    push    af
    push    bc
    push    de
    push    hl
    push    iy



this is at the end


    pop    iy
    pop    hl
    pop    de
    pop    bc
    pop    af
    reti
_interrupt_handler_end::


WTF!!!!? No ei???? Seriously???

*sigh*

I'll get there in the end ;)









My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

arnoldemu

To follow up:


void interrupt_handler(void) __critical __interrupt(1)


The "__critical" keyword will wrap the function in di/ei at the appropiate places.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

gerald

isn't the __critical keyword for NMI, returning with retn ?

arnoldemu

#3
Quote from: gerald on 14:31, 31 August 12
isn't the __critical keyword for NMI, returning with retn ?
yes and no.
for general functions it puts a di at the start and ei before the ret.


for this it does a ei/reti:

void interrupt_handler(void) __critical __interrupt(1)


this does an nmi:

void interrupt_handler(void) __critical __interrupt



it's all down to the "interrupt number" as they call it.

I am using my own crt so I must setup the interrupt to be called.

Not sure what happens if you use the default crt, perhaps you need to do the same.

My interrupt setup is my own lib that does this:


ld a,#0xc3
ld (#0x0038),a
ld (#0x0039),hl
ret


What I didn't check is if di/ei are added to the nmi handler.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

gerald

Quote from: arnoldemu on 18:00, 31 August 12
yes and no.
for general functions it puts a di at the start and ei before the ret.
I was only considering the interrupt case  ;D
Regarding the interrupt (not NMI), the Z80 user manual explicitly state that you have to manually re-enable interrupt. Then it sound logical that SDCC does not include EI by default.

Quote from: arnoldemu on 18:00, 31 August 12
What I didn't check is if di/ei are added to the nmi handler.
Since the IRQ are automatically disabled when entering NMI (IFF2 = IFF1 IFF1=0) and restored on retn (IFF1=IFF2), except if you really want to disable IRQ when exiting the NMI handler, you should not need to use DI/EI, don't you?

arnoldemu

Quote from: gerald on 18:26, 31 August 12
I was only considering the interrupt case  ;D
Regarding the interrupt (not NMI), the Z80 user manual explicitly state that you have to manually re-enable interrupt. Then it sound logical that SDCC does not include EI by default.
Since the IRQ are automatically disabled when entering NMI (IFF2 = IFF1 IFF1=0) and restored on retn (IFF1=IFF2), except if you really want to disable IRQ when exiting the NMI handler, you should not need to use DI/EI, don't you?
true. You should not need it for NMI.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

arnoldemu

I have been continuing my development of my game that is compiled by SDCC.

And I wanted to share some more interesting things.

For some data, I had to declare it "const". e.g. const unsigned char Pal[16]={0x040,0x042....};
If I didn't do this, then the data was not always initialised as I had expected. I am using a modified CRT, so this may be the cause.

When you pass parameters to a library function you have made, they are pushed onto the stack in reverse order, that is the "top of the stack" holds the first parameter, the next item off the stack holds the next, so to access them:


ld hl,#2
add hl,sp
ld e,(hl)
inc hl
ld d,(hl)
inc hl


this will get the first parameter.

The generated assembly is not as good as I had hoped, I will need to do a little optimisations, and change my code to help guide it.

Writing library functions and interfacing them into your code is nice and easy. Yes it's assembler syntax is a bit different to what I am used to (maxam), but it's ok.

With sections the "PAG" section type is ignored by the linker. So if I had some code in a library and defined it like this:


.area PIXELDATA (PAG)


I expected it would ensure that the area is aligned to 256 bytes, but the linker ignores it, and it's not. So don't use it.
If you want to align your data to a specific boundary, at this time, the only reliable way is to enforce it through the linker script :(
So you define your area in your crt, and then give it a value in the linker script :(

Other than this, it is ok. Better than z88dk? I would say, they are about the same.


My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

jsa

By the way which version of SDCC you are using ?

db6128

Quote from: arnoldemu on 10:36, 12 December 12Better than z88dk? I would say, they are about the same.
I can't claim to know enough myself to compare, but I have read this comparison that suggests that SDCC almost always generates much faster code: SDCC vs z88dk: Comparing size and speed
Quote from: Devilmarkus on 13:04, 27 February 12
Quote from: ukmarkh on 11:38, 27 February 12[The owner of one of the few existing cartridges of Chase HQ 2] mentioned to me that unless someone could find a way to guarantee the code wouldn't be duplicated to anyone else, he wouldn't be interested.
Did he also say things like "My treasureeeeee" and is he a little grey guy?

arnoldemu

Quote from: db6128 on 21:44, 12 December 12
I can't claim to know enough myself to compare, but I have read this comparison that suggests that SDCC almost always generates much faster code: SDCC vs z88dk: Comparing size and speed
z88dk allows you to have "fastcall" on your library functions, so I think it can win here for simple functions, sdcc doesn't have this and always has to go through the stack.

So in terms of calling library functions, sdcc is not the fastest.

And for the code generation, both seem to need to be "massaged" into generating the best code, but then that is true of any compilers including ones for the pc. The amount of "massaging" is about the same for z88dk and sdcc, true z88dk often required some modifications to it's peephole rules to make it a little better.

In terms of generated c code for a particular function, then sdcc is probably better.


My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

arnoldemu

Quote from: jsa on 20:56, 12 December 12
By the way which version of SDCC you are using ?
SDCC : mcs51/gbz80/z80/z180/r2k/r3ka/ds390/TININative/ds400/hc08/s08 3.2.1 #8221 (Nov 17 2012) (Linux)

I compiled it myself, had to turn off pic because it didn't compile for me.
This is one of the "nightlies" or "snapshots" depending on what you like to call them.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

arnoldemu

const unsigned char Pal[16]...

and

static const unsigned char Pal[16]...

problems seem to be a bug to me, so I have registered it.

the static one doesn't initialise the values, when I believe it should. The static makes it local to the c file, but because it's const, it should still be initialised.

Note that, the data is initialised and put into your code segment.


So another thing got me today :(

SDCC has sections that you can use to seperate your code.

CODE is the standard code one. This is normally read-only, can be put into ROM for example. If you want it to work in ROM avoid self modifying code.

DATA is the standard data one, expect this to be read-write and could be in ram for example. The GSINIT initialises this if you set values to your variables. e.g. "int MyVar=3". GSINIT should init this variable for you.

SDCC potentially allows you to write for cartridges/ROMs where the code is in ROM and the DATA is in RAM.


So what got me?

I had a library module:


.globl _cpc_KeyMap

.area DATA
_cpc_KeyMap:
db 0x0ff,0x0ff,0x0ff,0x0ff,0x0ff,0x0ff,0x0ff,0xff


I tried to pre-initialise it, and guess what, it wasn't.
I don't know if this is a bug or not, but it's something to be aware of. Given the way SDCC is setup, perhaps the GSINIT should have initialised it. I'll note it for the sdcc developers ;)

My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

arnoldemu

I made a test case for both, and can't reproduce the fault.

It may be that I am using old data, a clean and rebuild fixes it each time.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

Powered by SMFPacks Menu Editor Mod