New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
sdcc: Integer out of range #290
Comments
This is going to be normal. The classic library uses "double" for float types but sdcc only supports one float type which it wants to call "float". So it will automatically change "double" to "float" with a warning. Even though your program doesn't use doubles, there are prototype functions in the headers with doubles in them. The proper way to deal with this is to use implementation defined types "float_t" and "double_t" for all references to float and double so that they can be defined to whatever is needed for any compiler. However the classic library has a long history that extends beyond these new additions to the standard. The newlib does use these types and that's how it eliminates these warnings. tldr; you can ignore these warnings.
I haven't had time to compile your code today but I will try tomorrow. I think this is not a bug but rather an interaction with the spectrum rom that is causing a crash. If the spectrum rom's interrupt routine is running, the compiler and library cannot use the IY register. The rom interrupt routine uses it to index into a memory block and perform writes that have to do with key scanning. If the program changes IY, you will get random writes to memory which will lead to a crash. You're telling sdcc to not use IY when you add "--reserve-regs-iy" to the compile line. However, this does not stop sdcc from using IY; it only gets sdcc to make its best effort not to use IY. So actually sdcc is not stable on the spectrum without the rom interrupts being disabled or the interrupt routine being replaced. Unfortunately the classic library relies on the interrupts running because it has dependencies on the system software for key scanning, etc. So there's a bit of a pickle there for the spectrum target in particular. The newlib was written to be independent of all system software to solve all these problems but it only supports 7 or 8 targets rather than the 50 you'd want to target, and it doesn't yet have some of the generic libraries you are using (instead it prefers special portable libraries to do direct key, mouse, joystick scanning etc). Anyway I will take a look tomorrow to see if some of this can be cleared up. |
The |
Ideally I would like to target the most common computers with enough ram to run my game, i.e., at least the Spectrum, MSX1 and Amstrad CPC. My game is not strongly dependent on conio.h because I have separated the "graphic drivers" from the business logic. I only use conio as default driver for my targets that do not have specialized code for the graphics (I even wrote a sprite "driver" for the C64). So, if a portable alternative to conio.h is available, I can adapt my code to it without changing too many lines. |
What kind of graphics driver do you need? |
@aralbrec, I call "drivers" the hardware-dependent portions of my code (..._macros.h/c) which are separated from the rest of the code by an abstraction layer (APIs). |
It's the cross-platform nature that is the sticking point. Different targets have varying levels of support so if you want to go after all of them with one version of source code you have to aim at the lowest common denominator in the library. That is probably conio but as we've seen there are some issues in there and I'm not sure where the bugs are yet. Part of the issues are coming from the very rapid development over the past year and some of the bugs associated with these changes are being found now. But you're mentioning sprites and not just ascii. The zx spectrum platform is one of the best supported in z88dk. It has sprites, sound effects, input devices, and other things but they are not necessarily cross-platform. The msx and cpc are less supported as an interest has not been taken by the users to develop it further. Msx users are still doing plain asm by and large except for a few using native z80 c compilers who are unable to port libraries. The cpc has centered around sdcc and cpctelera which is a game-engine (to its detriment actually because sdcc on its own is less capable than as zsdcc in z88dk). Another very well supported system is the sega master system which has a game engine library called devkitSMS in z88dk. If you have an emulator for it, you can try some examples from the z88dk examples directory: https://github.com/z88dk/z88dk/tree/master/libsrc/_DEVELOPMENT/EXAMPLES/sms/AstroForce For other systems, the standard c library is quite complete and you'd have to add something to do non-standard things. The classic library, which you've been using, tries to provide things like conio, an ansi terminal, b&w graphics to as many targets as possible. The newlib doesn't do this yet but instead is offering target-specific libraries like devkitSMS for the sms, sp1/bifrost/nirvana for the spectrum, and non-ansi terminals with a set of control codes for text. So if you are willing to specialize those macros for each target, you can get better results for several systems. The msx too, since it has hardware sprites so you could probably knock up some simple sprite action with little code written. The cpc is like the spectrum in that everything is done in software so if you want sprites there, there is a lot of work involved or you can use cpctelera. |
Thanks for your hints! If conio.h is causing such issue and no solution can be found for the Z80 targets. I will have to find an alternative. I can use standard printf but it scrolls the text if used on the 24th line. How can I replace conio with standard C? I only need to print a character at position (x,y) and read input from the keyboard without waiting. Moreover it seems that conio is super slow on the ZX Spectrum target. Even the splash screen is printed slowly. It should appear instantly. My game runs much faster on any 6502 target by a factor of maybe 10. I think it is important to provide generic libraries in order to have portable code at least within the Z88dk targets. Even better if the code is portable even outside of the Z88dk boundary. |
sleep() is now marked as SAVEFRAME it ends up using l_long_sub which uses ix. There must be another C library function being called that uses long (internally perhaps) and isn't marked as such, or an assembler one that doesn't save ix itself.
I think that's because the ANSI screen printing for +zx isn't optimal - it's very generic code to handle the configurable widths/font packing etc. A quick switch over to the non ANSI library goes a lot quicker for +zx:
|
@suborb How do I compile my code in order to have printf work as described by you? and printf does not move the cursors. It prints garbage before the string. I also have an additional problem if I use sdcc_iy in_InKey is not found. |
You're mixing up the two libraries here. If there is To use the plain driver so that suborb's print works and with the classic library, this compile line should be used:
Btw, instead of having that long compile line, you can list your source files in a .lst file like this: zproject.lst
And then compile with:
This assumes you are compiling in the same directory those source files sit in. Otherwise you can add path to the .lst file too.
Your compile line was choosing newlib because you had Have a look at some of the links in this post. They will make things clearer about compile lines, the two libraries and the different terminals. |
Thanks a lot for your support! Unfortunately I am not still able to use in_inkey() :-( I am not sure I have understood: sdcc is a c lib which is called after the compiler. What should I include in order to have in_inkey() working in my code? If I use your command line + some other necessary options then in_inkey() is not found and the sccz80 (not sdcc) produces the following errors: sccz80:"d:\Userfiles\fcaruso\Documents\GitHub\ASCII-CHASE\main.c" L:587 Warning:#55:Implicit definit |
Thanks a lot for the support guys! I compile with sdcc compiler (and use getchar just to compile because in_inkey() is not found) the game starts but it is unplayable due to getchar() and the lack of a command to clear the screen (which should not be a problem because it may exist as a control code for printf). For in_inkey() I have tried to include: Maybe I am doing something stupid in my code... Remark: |
This compile line is using the classic library :) NEWLIB ONLY HERE These compile lines will use newlib, with "clib=new" using sccz80 as compiler and "clib=sdcc_iy" using zsdcc as compiler:
What is implied here is "-startup=0" which selects a default terminal type. The default is a 32-column driver that does not understand embedded control codes. Change this by adding "-startup=1" like this:
This will compile with a 32 column driver that does understand control codes as described here. An example using control codes can be seen here. In both zsdcc compile lines I am adding high optimization (" -SO3 --max-allocs-per-node200000") which you can eliminate to speed up the compile. zsdcc can be slow otherwise but it does lead to much better code generation. I'm not sure how big your program is but the default settings have the program compiled at address 32768, place the stack pointer at 65368 which grows downward with the heap automatically sized to extend from the end of your program to address 65368-512 (the default stack size setting is 512 bytes which is, admittedly, quite large). You can see how far your program extends from 32768 by looking at the size of the *_CODE.bin file produced. As your program size increases, available heap size shrinks so if your program is big you need to make sure the memory map stays ok, otherwise you have to do something about using ram below 32768. You can also specify which printf (and scanf) converters are compiled into the binary. By default you will get anything non-floating point like %ld %lx %o,... which, if you do not use, only increases the size of your program. If program size is not a problem you don't have to worry about these things. You control what converters are included with a pragma like If you will be printing to the screen directly, eg by using the display file manipulators, you can eliminate stdio entirely by compiling with "-startup=31". This will shrink the size of your program considerably. You can still use sprintf/sscanf and family but printf/scanf will not compile. Besides the control codes available to printf, there are functions that will clear screen and so on directly. These interact directly with the display file so they are done without the knowledge of the terminal driver. If you clear the screen, eg, the terminal driver will not move its current cursor position back to 0,0. For that to happen you should clear the terminal window using a control code \x0c IIRC or by sending an ioctl() command - These functions can be found in arch/zx.h. Some of these functions are new, as in the past few days new, so you may need to update to gain access to some of them. There are two function types - those that deal with the full screen like zx_cls() and those that deal with a window on screen like zx_cls_wc(). The "wc" indicates a window and you define a window using a struct r_Rect8 from rect.h. This coordinates in this struct are character coordinates, ie x in 0-31 and y in 0-23. There is no bounds checking for sane numbers. Besides these there tend to be things that operate on pixels only, attributes (colours) only or both. So zx_cls() will clear pixels and colours, zx_cls_pix() will clear pixels only and zx_cls_attr() will clear colours only. The scroll up functions all scroll up by character amounts except the scroll up pix ones which scroll up by a pixel amount (multiply character amounts by 8). The functions The test program I used for some of these functions is this one: zzz.c
(Again some of these functions are recent so you may need to update to compile this) These direct functions would best combine with the display file manipulators to display your text, bypassing stdio completely. However, this is not the portable solution :) CLASSIC ONLY HERE
This compile line is a classic compile. The "-D__SPECTRUM__" is unnecessary because this is defined when the target is specified ("+zx"). This compile is using the native spectrum driver which understands these control codes. It is a 32/64 column driver that comes up in 64 column mode. You can switch to 32 columns by printing the sequence 1,32 eg with In a classic compile, input.h defines in_Inkey(), not in_inkey(). Newlib is defining in_inkey() (here and here) to maintain consistency in the library (remember newlib is an opportunity for us to revisit all library code which has grown in a somewhat undisciplined manner over the years). In general you can tell what is in classic by looking at its header files in z88dk/include and what is in newlib by look at its headers in z88dk/include/_DEVELOPMENT - from here choose a sub-directory corresponding to the compiler being used (they all support the same functions). Most of the tool-related things spoken about above also apply to the classic lib. Eg, the pragmas. |
@aralbrec Thanks again! I have followed the suggestion to use printf with control codes. I have now rewritten my code so that printf with control codes is used instead of conio functions. I need to have a way to read keyboard input without waiting.. If I compile with clib=sdcc_iy: then printf stops understanding control codes for printf but I can get in_inkey. So this is not what I want if I want to use printf but it can be a solution if I use some other solution to print characters. If I compile it without sdcc_iy then printf understands contro codes but I cannot get in_inkey but I can get in_Inkey which waits for the input. :-( So it does not work either. Should I re-write my functions ditch control codes and use arch/zx.h functions? Could you please help me to get whatever solution that allows my plain C to do just:
|
There is no restriction in mixing any of the functions with normal console io but your compile line is mixed up between classic and newlib. You have to separate the two in your mind as they are completely independent and are not equivalent. As a newlib compile,
The proper compile line when using newlib would be this:
"-lmalloc -lndos" is not necessary with the newlib because everything is in the main zx.lib. "-DAMALLOC" is not necessary because newlib always does automatic malloc by default with this behaviour modified via pragma. "-compiler=sdcc" is not needed because this is already bundled in with "-clib=sdcc_iy". For this compile line, "-startup=1" is giving you a 32 column driver that understands control codes. DO NOT LOOK AT THE CLASSIC CONTROL CODES as documented for the classic driver. Although they will be similar to the newlib, there are differences. For the newlib control codes look at this page for information instead. The newlib also allows commands to be sent to the driver by ioctl() but there isn't a page fully documenting this yet (parameters, for example) but I also don't think you will need it. If you do, just ask. input.h will get you functions that directly scan the instantaneous state of the keyboard like:
arch/zx.h defines quite a few functions for interacting directly with the display. As a classic compile,
This is using a startup value for the newlib. The classic lib does not have the same crts or startup values. So a proper compile line using zsdcc would be: zcc +zx -compiler=sdcc --reserve-regs-iy -vn -DDEBUG_CHARACTERS -D__SPECTRUM__ -DAMALLOC -lmalloc -lndos -create-app -o ...c files... There may be issues with using zsdcc and interrupts being enabled in the classic compile. To get around these you should install an interrupt service routine that replaces basic's. Leave that one for later. A compile with sccz80 which should have no issues: zcc +zx -vn -DDEBUG_CHARACTERS -D__SPECTRUM__ -DAMALLOC -lmalloc -lndos -create-app -o ...c files... The classic compile gives you the 32/64 column driver with these control codes. input.h will contain in_Inkey() and other functions. Note that this is a different input.h from the newlib's input.h. Both libraries are completely independent. |
@aralbrec Thanks a lot! Your support is helping me a lot! In So the control directives suggested by suborb should not be usable on the 24th line if the doc is correct My first goal is to implement my game for as many Z80 targets as possible. That is why conio would have been the best option for me. For the moment I do not need fancy graphics. I am happy with simple character graphics. I will add fancier stuff later. P.S.: Fabrizio |
The doc means line number 24 as opposed to the 24th line. Lines 0-23 are on the display but if you move to line number 24, like if you print a \n on line 23, then the scroll will happen. The newlib grants more control over the terminal so that you can put it in page made, which means the cursor will wrap to 0,0 instead of scroll, and you can tell it not to clear the screen when it does so. I will add conio to the to-do list for newlib and hopefully the issues in classic can be sorted out. |
@aralbrec and @suborb THANKS guys! The code is pretty much standard ANSI C + classic printf directives + classic input.h. It may have some hidden bugs coming from either my code or the Z88DK libraries. I will disturb you again if some problems arise again (most likely). @suborb, my code is written for the most part in a way to separate input/output and anything hardware-specific from the business logic (95% of the code). Thanks to this design, I have been able to get my code for more than a dozen targets (mostly 6502 for the moment). |
@aralbrec , @suborb so VT100=ANSI So if I want to write my code for different Z88DK targets I should either use conio or VT100/ANSI console directives and not the console directives I have used so far. I wonder what I need to change in my code in order to port it to MSX, CPC and maybe some other targets. |
@aralbrec, @suborb NATIVE DIRECTIVES: VT100/ANSI: The main code difference is Performance-wise they are equivalent. At least I cannot tell the difference while playing the game. I would like to port my game to other Z80 computers. I would like to start with MSX and CPC. |
Another post with similar topic: #292 (comment)
The first one is the native spectrum driver using newlib. The second one is the native spectrum driver for classic. Neither is the vt100. The vt100 control codes are described on pages like this one. Not all of these codes will be supported by the vt100 driver in z88dk but the basic ones should be. To position the cursor on screen, you'll be sending: Esc[Line;Columnf | Move cursor to screen location v,h (I think vt100 coordinates are 1-based). To compile using the vt100 driver in the classic library follow instructions here:
"clib" is a shorthand for selecting a set of options from the target's cfg file. When you choose a target machine on the compile line, like CLIB ansi -Cc-standard-escape-chars -pragma-need=ansiterminal -lzx_clib That's what clib does. These clib values can vary from target to target, however, some are constant across all targets. For example, clib=sdcc_ix,sdcc_iy,new always select the newlib for all targets. clib=ansi is also present for all targets using the ansi terminal in classic compiles.
Give it a try, but try it first on the spectrum! |
Maybe I'll just add for the zx you have this: classic compile + native 32/64 column driver **** This one is supposed to be portable across machines but may be slow. |
This issue was solved long ago. Thanks a lot for the support! |
Hi
When compiling my game (https://github.com/Fabrizio-Caruso/ASCII-CHASE)
with sccz80 and sdcc I get two different results/bugs.
Remark 1: My code is probably OK because it compiles and works fine if compiled with CC65.
Remark 2: Both compilers produce lots of wrong warnings.
The game compiled with sccz80 is nearly OK. It is a very slow playable game with a crash later in the game that seems totally unrelated to the bug produced by sdcc. Moreover the crash is avoidable with a hack (e.g., inserting a sleep(1) command just before the point of the crash). This is a different issue for me and maybe I should open a different bug report.
On the other hand, with the game compiled with sdcc,
as soon as the game starts, the code produces an "integer out of range" after displaying the highscore (which is 0 stored in a long int).
I wonder whether this is a long int issue with the compiler.
I am compiling the game with:
zcc +zx -SO3 -vn -DAMALLOC -clib=ansi -lmalloc -lndos -create-app -o %deliverables%\ZXSpectrum.prg %mypath%\display_macros.c %mypath%\powerUps.c %mypath%\enemy.c %mypath%\invincible_enemy.c %mypath%\level.c %mypath%\character.c %mypath%\text.c %mypath%\missile.c %mypath%\strategy.c %mypath%\input.c %mypath%\main.c
and
zcc +zx -v -DAMALLOC -compiler=sdcc --reserve-regs-iy -clib=ansi -lmalloc -lndos -create-app -o %deliverables%\ZXSpectrum_SDCC.prg %mypath%\display_macros.c %mypath%\powerUps.c %mypath%\enemy.c %mypath%\invincible_enemy.c %mypath%\level.c %mypath%\character.c %mypath%\text.c %mypath%\missile.c %mypath%\strategy.c %mypath%\input.c %mypath%\main.c
Fabrizio
The text was updated successfully, but these errors were encountered: