Hi, There is instruction from Jakub Ladman on how to debug programs on the Amstrad(Sinclair) ZX Spectrum +2B computer using GDB. Sources are attached as an archive to the email. howtouse.txt Created on: 4. 10. 2020 Author: ladmanj This is demonstration how to use Small Devices C Compiler, with GNU AS assembler and GDB to debug Z80 code Only assembler instructions stepping is possible at the time of writing this text, because SDCC can't provide the symbols (and maybe other information) in the way gdb needs. The code being debugged is compiled and linked together with GDB-STUB, which is relatively small piece of code running on the target machine and provides interface between it and the GDB itself. This presentation is performed on the Amstrad(Sinclair) ZX Spectrum +2B computer. The tools used are: z80-unknown-elf-as, z80-unknown-elf-ld z80-unknown-elf-objcopy from the Sergey Belyashov's source tree from https://github.com/b-s-a/binutils-gdb bin2tap from https://sourceforge.net/projects/zxspectrumutils/ taptoser From Pavel Vymetálek's https://vym.cz/download/taptoser.tar.gz to be used with Paul Farrow's modified 48k ROM-RS232 http://www.fruitcake.plus.com which redirects tape in&out to one of the three possible (software emulated serial) ports. The taptoser and the modified ROM isn't needed, the GDB-STUB and the program to be debugged can also be loaded from the physical tape if you are not equipped with some user modifiable ROM cartridge, but because the serial connection has to be used anyway for the stub/gdb communication it's a shame not to use it also for the boot-up. The z80-stub.c file which comes from the gdb source tree is connected with the serial channel via extern int getDebugChar (void) and extern void putDebugChar (int ch) functions. These are in the thin wrapper file io.c, and from this place assembly routines for the RS-232 serial line are called. The serial routines used here (rs232.s) are from this site: https://cygnus.speccy.cz/download/zx128k_rs232/rs232_paul_farrow_57600_data_sequence_with_cts_flow_control.html The binary file is built, converted to ZX Spectrum TAP file and loaded to the target machine: $ make upload Reset ZX spectrum with Paul Farrow's RS232 ROM Press any key to continue Now run LOAD "" taptoser gdbstub.tap -d /dev/ttyUSB0 Serial device: /dev/ttyUSB0, communication speed is: 57600 Bd Filename: gdbstub Flag: 0 Type: 0 => program Program length: 93 bytes Runs from line 10 Length without variables: 93 bytes Proceed bytes: 95/ 95 [==================================================================================================] 100 % Filename: gdbstub Flag: 0 Type: 3 => bytes Start address: 32768 Length: 3056 bytes 3rd param: 32768 Proceed bytes: 3058/ 3058 [==================================================================================================] 100 % The whole code is started by the code in mycrt0.s. The bin2tap utility has appended a machine code loader in basic to the tape file. The basic loader places the code at the address 0x8000 and there the machine code is run from, the ROM cartridge (if present) is then switched off, the whole code is copied from 0x8000 (bank 2 where we are running now) to 0xc000 (bank 0) the ZX Spectrum +2 memory is switched to all-ram mode in such way, the bank 0 is then at address 0x0000. Then the program jumps to address 0x0000 and is initialized as any other sdcc compiled program. After initialization but before thi final jump to _main (to C main function), the debug_exception function is called and there the gdb-stub is finally waiting for the connection of the gdb. When the z80-unknown-elf-gdb is run, the .gdbinit file is examined and following commands are executed from it: set remoteflow on target remote /dev/ttyUSB0 Note: The software emulated serial port in the remote can't work without hardware handshake enabled on the PC side. The gdb prompt then looks like this: $ z80-unknown-elf-gdb GNU gdb (GDB) 10.0.50.20200317-git Copyright (C) 2020 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "--host=x86_64-pc-linux-gnu --target=z80-unknown-elf". Type "show configuration" for configuration details. For bug reporting instructions, please see: . Find the GDB manual and other documentation resources online at: . For help, type "help". Type "apropos word" to search for commands related to "word". warning: No executable has been specified and target does not support determining executable automatically. Try using the "file" command. 0x0000010d in ?? () (gdb) Then the memory can be examined this way: (gdb) x/20i 0x100 0x100: ld sp,0xff00 0x103: call 0x0146 0x106: ld hl,0x0005 0x109: push hl 0x10a: call 0x0210 => 0x10d: call 0x0af2 0x110: jp 0x015a 0x113: nop 0x114: nop 0x115: nop 0x116: nop 0x117: nop 0x118: nop 0x119: nop 0x11a: nop 0x11b: nop 0x11c: nop 0x11d: nop 0x11e: nop 0x11f: nop Displaying of the current instruction can be switched on: (gdb) display/i $pc 1: x/i $pc => 0x10d: call 0x0af2 And then the instruction by instruction can be performed: (gdb) si warning: Unable to determine inferior's software breakpoint type: couldn't find `_break_handler' function in the executable. Will be used default software breakpoint instruction RST 0x08. 0x00000af2 in ?? () 1: x/i $pc => 0xaf2: call 0x0af8 (gdb) 0x00000af8 in ?? () 1: x/i $pc => 0xaf8: ld b,0x00 (gdb) 0x00000afa in ?? () 1: x/i $pc => 0xafa: ld a,b (gdb) 0x00000afb in ?? () 1: x/i $pc => 0xafb: out (0xfe),a (gdb) 0x00000afd in ?? () 1: x/i $pc => 0xafd: inc b (gdb) 0x00000afe in ?? () 1: x/i $pc => 0xafe: xor a (gdb) 0x00000aff in ?? () 1: x/i $pc => 0xaff: in a,(0xfe) (gdb) 0x00000b01 in ?? () 1: x/i $pc => 0xb01: cpl (gdb) 0x00000b02 in ?? () 1: x/i $pc => 0xb02: and 0x1f (gdb) 0x00000b04 in ?? () 1: x/i $pc => 0xb04: jp z,0x0afa (gdb) 0x00000afa in ?? () 1: x/i $pc => 0xafa: ld a,b (gdb) You can load your binary to any free location of the RAM and do the debugging. If you lose control of the program (and it didn't overwrite anything important), you can interrupt it by the NMI button, if your machine or ROM cartridge is equipped with one. (gdb) c Continuing. Program received signal SIGTRAP, Trace/breakpoint trap. 0x00000aff in ?? () 1: x/i $pc => 0xaff: in a,(0xfe) That's all folks!