ack
ack copied to clipboard
[question] Can I use ACK to generate raw 8080/8085 or 6800 binary from plain C (no libs)?
Can I use ACK to generate raw 8080/8085 or 6800 binary from plain C (no libs)?
A plain binary option for each supported CPU should be possible at least for Intel 8080.
Some vintage computers with 8080 were not CP/M (e.g., Olivetti M 10).
It would be great to be able to generate 6800 because no ANSI C cross compiler exists, yet.
I'm afraid the answer is 'it depends'.
The ACK's generated code requires the compiler support libraries to operate --- libem and libfp (if you want floating point); eliminating these dependencies would be almost impossible. However, these are both cross-platform; libfp is portable code, while libem is architecture-dependent but not platform-dependendent (so the same i80 libem will work on all i80 machines).
But it's certainly possible to build code without the syscall library, for ROM applications, so a binary gets generated which uses libem and libfp and nothing else. It's fiddly, and it's usually preferable to teach the ACK about the new platform instead, but it's perfectly possible. plat/cpm or plat/pc86 are good examples of this.
Re 6800: be aware that the ACK doesn't have a 6800 code generator --- there's assembler/linker support, but that's it Adding a new code generator would be cool, I'll admit, but code generators are a substantial amount of work. (The 6809 is regular enough it's probably not so bad.)
Thanks @davidgiven for your reply!
How can I use ACK to build an I80 binary? I do not need floats and the heap. I guess the .COM produced by it is more than a plain raw binary.
It would be cool to have bare-bone pseudo-targets to produce plain raw binaries. It would allow more people to use ACK. These people would then be encouraged to write some basic libs to get something working (e.g., input/output for the specific target, etc.).
I know a code generator is a lot of work... Unfortunately the 6809 is well supported by multiple projects (CMOC, WINCMOC, GCC6809, ACK, etc.) and there is no plain 6800 cross compiler. That is why it would be cool to have it one day.
In case you may wonder why I am interested in 8080 and 6800, the reason is that I am building a game and an entire cross-system and cross-toolkit tool-chain to build programs on ALL 8-bit platforms: https://github.com/Fabrizio-Caruso/CROSS-CHASE I cover more than 100 systems with either 6502, Z80 or 6809 CPUs and their derivatives.
Build a CP/M binary --- ack -mcpm something.c
--- and add -v -v
. That'll show you the raw command line used. The interesting part's the linker invocation, which will specify the startup code and assorted libraries. You'll want to replace the startup code, probably called head_em.o
, and the syscall library; you may be able to do without the latter entirely, but most likely you'll want to include some stub functions for things like _exit
.
Thanks @davidgiven! How can I specify the start address of the binary? I will try to see if I can build something usable for non-CP/M I80 targets (e.g., Olivetti M 10). Ideally, it would be nice to have in a future ACK version a simple option to generate plain binaries at a chosen address with just generic libs, no startup-code. Having such option for all supported CPU, will encourage people to use ACK on other targets and maybe build at least some initial crude lib for input and output.
To specify the start address, use the -b
option when calling em_led
(the linker) to specify the base address of segment 0 (which is the text segment). If you build a CP/M program with -v -v
you'll see all the commands the driver is using. There should be man pages for each program.
You'll probably want to build your .o
files with ack -mcpm
, for simplicity, but then manually link the result and call aslod
to turn the output file into a raw image yourself. Bear in mind that there are system variables that must be present or the generated code won't link --- look at plat/cpm/boot.s
.
The problem with 'plain binaries' is that they're never as easy as they look --- there's always _some_startup code needed (initialising system variables, pushing dummy values onto the stack for argc and argv, etc). Very quickly you end up defining a platform for your non-platform binary, which of course never matches what people actually want to do.
This could certainly be made easier, like moving the system variables out of boot.s
and putting them in a common library, but given that anyone who's going to want to do this is going to need to heavily customise the startup code anyway it's probably not worth it.
Are C libraries in ACK target-agnostic? Same code for all targets (except for getchar and putchar, etc.)? If it is not the case, one could support lots of 8080, 68k and PPC targets by using SDCC's target-agnostic libraries (if technically and legally possible), with the only effort of implementing putchar and getchar. Ideally one would also need to package the binaries into something runnable but this can be done with external tools or it can be left to the coder.
They are platform agnostic --- look in lang/cem/libcc.ansi --- but there's no such thing as platform-independent compiled code; it'll be built with a certain compiler configuration and reusing the same compiled library with a different compiler configuration is problematic. (Even for sdcc.) For a simple platform like the 8080 it'll probably work... but you can't be sure.
This could certainly be made easier, but I don't think that's the way to go.
@davidgiven By running ack -mcpm -v -v on a c file I see the commands and I am trying to guess what they do: ccp.ansi: ??? em_cemcom.ansi: ANSI C to EM compiler em_opt: EM bytecode optimizer cpm/ncg: generates Assembly from EM bytecode cpm/as: generates Intel 80 em_led: linker
What is the purpose of the command cpp.ansi? Is cpm/as a generic Assembler or a somehow CP/M one? (is it inside the cpm directory for some reason?)
cpp.ansi is the C preprocessor. You should have a man page for it; try man ncpp
.
cpm/as is, in this specific case, generic --- but the build system rebuilds all the tools for every supported platform, so they don't need to be generic. It'd be possible to update the build system to share these tools where possible but it isn't really worth it as it would make the builds much more complex.
@davidgiven no ncpp manual was installed when I installed ack. How do I install the manual?
My question about cpm/as is whether it can be used to produce Intel 8080 code that does NOT depend on CP/M. Is cpm/as a generic tool for I8080 or a specific CP/M-80 where some CP/M specific code is generated?
I am trying to understand how to compile C and produce an Intel8080 binary with no C libs (it is clear I will have to implement all input/output for the specific target).
It would be great if ack could provide a way to do this in a simplified way where the user can use the standard C lib as long as the user provides a C or Assembly file with getchar and putchar implementations.
In this specific case, cpm/as is a generic i80 assembler. You can't necessarily rely on this for other assemblers.
Thanks!
Where can I get information on the options of the above commands? I have no manual page for ncpp. How can I install it? There is no -h or --help option on those commands.
I installed ack into /opt/ack
and ...
$ printf "#define foo bar\nfoo\n" | /opt/ack/lib/ack/cpp.ansi
# 1 ""
# 2 ""
bar
...looks like a cpp
at work.
I see no man page in /opt/ack/share/man
but /opt/ack/src/ack/lang/cem/cpp.ansi/ncpp.6
looks good:
$ nroff -man /opt/ack/src/ack/lang/cem/cpp.ansi/ncpp.6 | head -6
CPP.ANSI(6) Games Manual CPP.ANSI(6)
NAME
cpp.ansi - ANSI C Pre-Processor
HTH!
Oops, yes, the man page isn't installed --- fixed. (It's installed as cpp.ansi, to match the binary name and the name actually in the man page.)
FYI: The 8080 CP/M backend has had a lot of overhauling recently; it now generates considerably smaller code and you can produce minimal binaries. However, it does this by installing a bunch of helper rsts so if you're on a platform which isn't CP/M you'll need to be aware.
There's also a raw BDOS library allowing you to talk to CP/M without having to link in stdio at all. This completely avoids the overhead of printf, stdio, etc. Of course, you don't get printf, stdio etc so you have to have your own routines to turn numbers into strings. I'm considering adding itoa()
to the standard library --- it's non-standard, but incredibly useful.
Thanks a lot for your improvements! is putchar (or something equivalent) available in CP/M without stdio?
Concerning non-CP/M 8080-targets, I am not asking for any specific support (it would be cool, though, but I do not dream to get any support for systems like Olivetti M10, TRS-80 Model 100, etc.). I was just asking for a simple user-friendly top-level command to build a raw binary that links no target-specific library (but could link target-agnostic libs like math libs) and that may use some configuration to link, relocate and/or "package" the binary.
All the BDOS entrypoints are available. For your purposes, cpm_conout(), cpm_conin() and cpm_const() are probably what you want. Of course, you'll have to deal with terminal compatibility issues yourself...