blog:ql_dev1

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
blog:ql_dev1 [2021/12/14 12:47] – [C68 Cross-Compiler (aka XTC68)] johnblog:ql_dev1 [2021/12/16 11:03] (current) john
Line 1: Line 1:
 ====== Sinclair QL Development Tools ====== ====== Sinclair QL Development Tools ======
  
 +There are a range of development tools and languages for the QL, including the built-in SuperBASIC. But I am more interested in using the same type of tools that I use for the NEC PC-98, MS-DOS, X68000 and more; a reasonably standards compliant C compiler, assembler and linker.
 +
 +There are a few C compiler options for the Sinclair QL - which are summarised nicely here: http://www.dilwyn.me.uk/c/index.html
 +
 +I touch on a few of them, including the one I am using (C68, in it's modern cross-compiler incarnation) below.
 ==== C68 Self-hosted on the QL ==== ==== C68 Self-hosted on the QL ====
  
Line 17: Line 22:
  
    * {{ :blog:sinclair:c68_linux64-2021_12_14.tgz |}} - Pre-compiled, with headers and runtime libraries. Unpacks to ///opt/toolchains/qdos//    * {{ :blog:sinclair:c68_linux64-2021_12_14.tgz |}} - Pre-compiled, with headers and runtime libraries. Unpacks to ///opt/toolchains/qdos//
 +   * {{ :blog:sinclair:c68.pdf |}} - C68 User Manual. For the original Sinclair QL hosted version, but most of the compiler and linker flags and options remain the same.
 +   * {{ :blog:sinclair:c68_documentation_-_dave_walker.pdf |}} - A more in-depth manual about the use of C68, including a //basic// reference of available calls.
  
 === Sample C68 Makefile === === Sample C68 Makefile ===
  
 You can of course use standard GNU Makefiles alongside C68, here's a basic one that compiles a single binary from two .C source files, as you would normally do with anything of reasonable complexity. You can of course use standard GNU Makefiles alongside C68, here's a basic one that compiles a single binary from two .C source files, as you would normally do with anything of reasonable complexity.
 +
 +Note that I specifically **do not** have my C68 toolchain directories in my path, as I have far too many compilers installed to manage them if they were all fighting for priority on the path. I tend to set things up so that I either temporarily add them to the front of the path, as per the makefile below, or have a shell script temporarily set the path for a given session.
 +
 +It's often easier to keep paths and things like that encapsulated in the Makefile, so you can see that at the top of the example below:
  
 <code> <code>
 # Sample makefile for C68 projects # Sample makefile for C68 projects
 +
 +#################################
 +# Temporarily add the cross
 +# compiler location to the path
 +#################################
 +SHELL := /bin/bash
 +PREFIX = /opt/toolchains/qdos
 +PATH := ${PREFIX}/bin:$(PATH)
  
 ################################# #################################
Line 29: Line 48:
 # and friends # and friends
 ################################# #################################
-PREFIX = /opt/toolchains/qdos +CC = qcc 
-PATH = ${PREFIX}/bin:$PATH +LD = qld 
-CC = ${PREFIX}/bin/qcc +AS = as68 
-LD = ${PREFIX}/bin/qld +CPP = qcpp
-AS = ${PREFIX}/bin/as68 +
-CPP = ${PREFIX}/bin/qcpp+
  
 ################################# #################################
Line 49: Line 66:
 ################################# #################################
 ASFLAGS =  ASFLAGS = 
-LDFLAGS = +LDFLAGS = -v
 CFLAGS = -O CFLAGS = -O
  
Line 94: Line 111:
  $(CC) $(CFLAGS) $(INCLUDES) -c other.c  $(CC) $(CFLAGS) $(INCLUDES) -c other.c
 </code> </code>
 +
 +=== Running C68 ===
 +
 +If you use a sample makefile such as the one above, you should get an output such as this:
 +
 +<code>
 +$ make
 +qcc -O  -c test.c
 +qcc -O  -c other.c
 +qld -v test.o other.o  -o game
 +ld v1.22  QL 68000 SROFF Linker
 +COMMENT: C68 crt_o v4.24f
 +COMMENT: C68 libc_a v4.24f
 +
 +---------------------------
 +SECTION      START   LENGTH
 +---------------------------
 +TEXT                 3AD6
 +DATA          3ad6      2FA
 +UDATA         3dd0      4EE
 +---------------------------
 +Program length       42be
 +Relocation table =      1ef
 +--------------------
 +Memory Usage           0%
 +Buffer Usage           0%
 +--------------------
 +game: dataspace 870 (366)
 +
 +Link completed
 +</code>
 +
 +This is mostly easy to understand - two passes of the compiler; one for each source file, then the linker takes the two object files, adds-in //crt.o// and any functions from the //standard library//. The output is a little more verbose than the usual compiler though - an important element being the //dataspace// that the resulting binary will take up in the QL memory. 
 +
 +If you hexdump the binary, you will see some trailing data that mirrors that //dataspace// number:
 +
 +<code>
 +$ hexdump -C game
 +.
 +.
 +.
 +00003fa0  04 04 04 04 04 04 04 04  04 0e 14 0c 04 04 0c 16  |................|
 +00003fb0  14 26 08 04 04 04 04 48  04 06 60 01 24 38 00 00  |.&.....H..`.$8..|
 +00003fc0  58 54 63 63 00 00 03 66                           |XTcc...f|
 +00003fc8
 +</code>
 +
 +This is referred to as the //xtcc field// and is used by the **qlzip** utility when unpacking on the QL native filesystem to restore the needed metadata about the application.
 ==== GCC Cross-Compiler ==== ==== GCC Cross-Compiler ====
  
Line 117: Line 182:
      * https://github.com/NormanDunbar/qltools      * https://github.com/NormanDunbar/qltools
      * Works with native QL floppy disks (DD 720K, HD 1440K or ED 3.2MB) or disk images to transfer files to/from those devices from Linux.      * Works with native QL floppy disks (DD 720K, HD 1440K or ED 3.2MB) or disk images to transfer files to/from those devices from Linux.
 +
 +==== Other Stuff ====
 +
 +I wrote a quick Python script to print out the value of an XTcc field in a binary produced by C68, GCC or similar. This is useful when copying an executable into a QL floppy or hard drive filesystem and you need to set the //dataspace parameter//:
 +
 +<code>
 +#!/usr/bin/env python
 +
 +####################################
 +#
 +# Prints out the value of a Sinclar
 +# QL binary XTcc field, as needed to
 +# turn it into an executable file
 +# on the QL itself, or when transferred
 +# using qltool.
 +#
 +# John Snowdon, 2021
 +#
 +####################################
 +
 +import sys
 +import os
 +
 +if len(sys.argv) < 2:
 + print("ERROR: No filename given")
 + sys.exit(-1)
 +
 +ql_filename = sys.argv[1]
 +if (os.path.exists(ql_filename)):
 + f = open(ql_filename, "rb")
 + filedata = f.read()
 + offset = filedata.find(b'\x00XTcc')
 +
 + if offset:
 + # First byte of "XTcc" is at 'offset', so jump by 4 bytes
 + f.seek(offset + 5)
 + dataspace = f.read(4)
 +
 + # Print out the value of the dataspace field
 + print(int.from_bytes(dataspace, byteorder='big'))
 +
 + f.close()
 +
 +else:
 + print("ERROR: Filename does not exist")
 + sys.exit(-1)
 +</code>
 +
 +Just call the script with the name of your C68 executable. For example:
 +
 +<code>
 +$ xtcc game.bin
 +868
 +</code>
 +
 +... the value printed is the size of the dataspace needed. So you would then copy and mark your binary with qltools as follows:
 +
 +<code>
 +$ xtcc game.bin
 +868
 +$ qltools floppy.img -W game.bin
 +$ qltools floppy.img -x game.bin 868
 +</code>
 +
 +Or even easier, embed the xtcc call in backticks:
 +
 +<code>
 +$ qltools floppy.img -W game.bin
 +$ qltools floppy.img -x game.bin `xtcc game.bin`
 +</code>
 +
  • blog/ql_dev1.1639486074.txt.gz
  • Last modified: 2021/12/14 12:47
  • by john