Jump to content

Recommended Posts

Hi All,

As part of my contribution to the cc65 development for the atari 8bit community,
i've decided to write a short tutorial that might help you guys if you wish to debug your code via altirra.
I have been strugling with this for a while now and it is still yet to be perfect (not as easy as debugging code in other environemtns such as visual studio) but it is definately a good starting point.

Compiler flags - add 'debug info'
If you wish to debug your cc65 code, you first need to add 'debug info' to your compiled object.
To add debug mode you need to add the following flags to the compiler:

cl65 --debug-info -Wl --dbgfile,"myapp.dbg" -t atari  main.c -o myapp.xex -C myapp.cfg -l myapp.lst -Ln myapp.lbl 

To learn about command lines you can use this reference: https://www.cc65.org/doc/cc65-2.html or yoו can use the --help argument in the cl65 command line.
What is relevant for this discussion is the debug info parameters in the command line above.
Let's review and explain what they do:

--debug-info             : Add debug info to object file (could use also -g option)
-Wl                      : Pass options to the linker
--dbgfile,"myapp.dbg"    : produce debug info file named myapp.dbg

The above will create a debug info file and will include debug info in the compiled object.

Altirra debug functions
Now that your binary file object is ready and also include debug info, the next step is to run your xex file with altirra.
here are the main functionalities you need to know for debugging in Altirra:

F8 - press this will enalbe the debugger. pressing this again will let the app continue running with no debuggin
F9 - pause the emulator. this can help tracking a specific occurred issue.
(F9 within disassembly window or c code window) - is used to toggle breakpoints
F11 - step into a routine. this option will step into your routine and debug the code of that routine
F10 - step over a routine. this option will step over your routine and move to the next command after the call to that routine

Debugging the C code
when your code runs and you wish to debug it, you press F8.
Altirra then changes its user inteface to be set in debugging mode.
on the right hand side you should see 4 tabs: disassembly, Registers, Call Stack, Memory1
if you don't see these windows or you see only some of them, you can bring them on to screen by selectng
'Debug--Window' from the menu.

Disassembly - you can explore your code in machine and assembly launguages. you have search option on the top where you can insert a memory address to view or a name of a routine to view. the name is the disaseembly name of that routine.
for example, if your code has a routine called 'void draw_screen(void)' , then to find it in the disassembly window you can search for '_draw_screen' search string. just add '_' as a prefix.

Registers - you can view all register values under this screen and also where the program counter is (would be a hex value).

Call Stack - display a stack of your program routines call as they are being called in your app. the routines are presented as a memory address location, so if you wish to know what routine is that, just search it in the disassembly window.

Memory - can be 4 memory windows to view in parallel. in the default case you bring on to screen memory1. this is the memory layout and what it holds in the current debug status. you have a search text box to search a memory location. this is powerful tool to view memory location values and see if anything is at the order.

Viewing your C code
everything so far was either machine language or assembly. to view your c code, go to the 'disassembly' window point your mouse on the assembly code you wish to view as C code. For example, if you found a routine in the disassembly window called '_draw_screen' , right click on the routine and choose 'Go to source'. you will see a new window is opened with your c code.

Toggle breakpoints
If you wish the app to debug-break at a certain point of your routine, you can set up a break point. to do that you right click on the c source code and choose 'Toggle breakpoint'. for example, if you wish to break at the beging of the routine 'draw_screen' then you right click the first command on that routine and choose 'Toggle breakpoint'. to remove the breakpoint just choose the option 'Toggle breakpoint' on that line of code again. it will clear the break point.

Run till breakpoint
By pressing F8 your app continues to run until it reaches to the breakpoint set place.
once you have breaked in the desired line, you can use the step into(F11) , step over(F10) functions to debug your code line by line.

Console
Console is the bottom window in the debug mode of altirra. if you don't see it you can bring it on by selecting 'debug--window--console'. in every step of your debug you see an output line in the console.
in that line you can see all the registers and their values, and also the current machine lagunage and assembly command that is being debugged. you can see the same thing at the disassembly window.
an example of a console output line:

 

Breakpoint 0 hit
(104:  2,  2) A=20 X=50 Y=00 S=F5 P=33 (    ZC)  4700: A0 01             LDY #$01

Where:
104 - # of frame being drawn
2,2 - first 2 is the vertical line # within the frame , the second 2 is the horizontal position within the current scanline
A,X,Y - are accumulator, X and Y registers
S - The Stack register
P - The status register,
ZC - zero carry
4700: A0 01 - current program counter and machine language for LDY#$01
LDY #$01 - assembly command being executed

Variables Watch
the same way your routines have prefix '_' , your variables also have prefix '_' in their disassembly presentation.
In order to watch your variables value, you can use write in the console few commands that will show your variables values on screen.
if you type in the command line:

wb <_your variable name>  (note the prefix '_')

it will add your variables to the watch list and then you will start see it on your app screen.
wb - watch byte
ww - watch word
wc - watch clear (to remove a watch)

For example, if your c code declares:

unsigned char count;

Then to watch the value of count you will use wb _count in the console command prompt as char is byte long.
If your c code declares:

unsigned long scr_mem_addr;

Then to watch the value of count you will use ww _count in the console command prompt as long is byte word byte long.
after these command prompt the console will result with:

Watch entry 0 set.

Where 0 is the number of current variables being watched on screen.

the value doesn't appear on screen right away you need first to let the program continue running (F8) then break again to see the value appearing on screen.

To clear a variable from watch just type in:

wc <_variable name>

you can also bring on the watch window (debug--window--watch) and type a variable name to watch (again with prefix '_') but in this window you will only see the memory address of that variable, so in order to see what the value it holds you will need to type in the memory address in the memory window

 

Print variables value

you can use Altirra commands to print system variables. you simple use the .printf command as in the following example:

.printf "%02X" db(VCOUNT)

This will print to console the current vcount number (where the scanline is currently is). you can use your variables as well just remember to add the prefix '_'

 

Dump the display list

To print the current screen display list use the following example:

.dumpdlist

The result will be the display list byte array including its memory addresses:

2000: x4   blank 8
  2004:      mode.i.h 4 @ 480B
  2007:      mode.i.h 4 @ 490B
  200A:      mode.i.h 4 @ 4A0B
  200D:      mode.i.h 4 @ 4B0B
  2010:      mode.i.h 4 @ 4C0B
  2013:      mode.i.h 4 @ 4D0B
  2016:      mode.i.h 4 @ 4E0B
  2019:      mode.i.h 4 @ 4F0B
  201C:      mode.i.h 4 @ 500B
  201F:      mode.i.h 4 @ 510B
  2022:      mode.i.h 4 @ 520B
  2025:      mode.i.h 4 @ 530B
  2028:      mode.i.h 4 @ 540B
  202B:      mode.i.h 4 @ 550B
  202E:      mode.i.h 4 @ 560B
  2031:      mode.i.h 4 @ 570B
  2034:      mode.i.h 4 @ 580B
  2037:      mode.i.h 4 @ 590B
  203A:      mode.i.h 4 @ 5A0B
  203D:      mode.i.h 4 @ 5B0B
  2040:      mode.i.h 4 @ 5C0B
  2043:      mode.i.h 4 @ 5D0B
  2046:      mode.i.h 4 @ 5E0B
  2049:      mode.i.h 4 @ 5F0B
  204C:      waitvbl 200B

2000-204c - the memory address of the display list

x4 - the number of times the line appears on the screen (in this example 4 time)

blank 8 - a blank line 8 scanlines

mode.i.h 4 - ANTIC mode 4 + DLI interrupt flag + Horizontal scroll flag

480B - 5F0B - the address of the screen memory

waitvbl 200B - jumps back to the begining of the display list after VBLANK

 

note - this was taken after several screen horizontal scrolls has occurred, that is why the memory addresses doesn't look aligned.

 

Print GTIA

To print the current GTIA status use the following example:

.gtia

The resut will specify the current GTIA status which mosly includes player missile graphics status:

Altirra> .gtia
Player  0: color = 00, pos = 00, size=0, data = 00
Player  1: color = 00, pos = 00, size=0, data = 00
Player  2: color = 00, pos = 00, size=0, data = 00
Player  3: color = 00, pos = 00, size=0, data = 00
Missile 0: color = 00, pos = 00, size=0, data = 00
Missile 1: color = 00, pos = 00, size=0, data = 00
Missile 2: color = 00, pos = 00, size=0, data = 00
Missile 3: color = 00, pos = 00, size=0, data = 00
Playfield colors: 06 | 86 0c 72 00
PRIOR:  00 (pri= 0 , normal)
VDELAY: 00
GRACTL: 00
CONSOL: 08 set <-> 0f input, speaker
M0PF:
M1PF:
M2PF:
M3PF:
P0PF:
P1PF:
P2PF:
P3PF:
M0PL:
M1PL:
M2PL:
M3PL:
P0PL:
P1PL:
P2PL:
P3PL:

You can see in the result above the information about all 4 players and missiles, their priority,  and the collision between them and the playfield.

 

Print ANTIC

To print the current ANTIC status use the following example:

.antic

The resut will specify the current ANTIC status, which include information about display list, pmg address, character set address, dli

Altirra> .antic
DMACTL = 22  : normal 2-line dlist
CHACTL = 02  : invert
DLIST  = 2000
HSCROL = 0c
VSCROL = 00
PMBASE = 00
CHBASE = e0
NMIEN  = c0  : dli vbi
NMIST  = 1f  :
PENH/V = 00 ff

Go until scanline

The ability to run the debugger until it reaches a certain scanline.

to use that use the following example:

gs 100

the result will be the same breakpoint result you always get when your code breaks on a toggled breakpoint:

Altirra> gs 100
Scanline breakpoint reached.
( 64:100,  0) A=37 X=20 Y=50 S=F5 P=33 (    ZC)  8188: F0 FC             BEQ L0026

you can see the same information as we explored before.

 

Alttira debugger commands

Here is a list of ALL altirra debugger commands:

Altirra> .help
`    Bypass aliases
?    Evaluate expression
a    Assemble
a8   Set Atari800-compatible command aliases
ac   Clear all command aliases
al   List command aliases
as   Set or unset command alias
ap   Add command alias pattern
ba   Break on memory access
bc   Clear breakpoint(s)
bl   List breakpoints
bp   Set breakpoint
bt   Set breakpoint with trace (tracepoint)
bx   Break on expression (conditional breakpoint)
bs   Break on disk sector
da   Display ATASCII string
db   Display bytes
dbi  Display bytes w/ INTERNAL dump
dd   Display double words
df   Display decimal float
di   Display INTERNAL string
dw   Display words
dy   Display binary
e    Enter (alter) data in memory
f    Fill memory
fbx  Fill bytes with expression
g    Go
gf   Go until frame end
gr   Go until return (step out)
gs   Go until scanline
gt   Go with tracing enabled
h    Show CPU history
hma  Show heat map accesses
hmc  Clear heat map
hmd  Dump heat map memory status
hme  Enable or disable heat map
hmr  Show heat map register status
k    Show call stack
lfd  Disable logging channel
lfe  Enable logging channel
lfl  List logging filter settings
lft  Enable logging channel with tagging
lm   List modules
ln   List nearest symbol
m    Move memory
o    Step over
r    Registers
s    Search memory
st   Static trace
t    Trace (step one instruction) (F11)
u    Unassemble
vta  Verifier target add
vtc  Verifier target clear
vtl  Verifier target list
vtr  Verifier target reset
wb   Watch byte
wc   Watch clear
wl   Watch list
ww   Watch word
wx   Watch expression
x    Examine symbols
ya   Add manual symbol
yc   Clear manual symbols
yd   Delete manual symbol
yr   Read manual symbol table
yw   Write manual symbol table
.antic       Display ANTIC status
.bank        Show memory bank state
.base        Set numeric parsing base
.basic       Dump BASIC table pointers
.basic_dumpline  Dump BASIC program line
.basic_dumpstack  Dump BASIC runtime stack
.basic_rebuildvnt  Rebuild BASIC variable name table
.basic_save  Save BASIC program
.basic_vars  Dump BASIC variables
.batch       Run debugger batch script
.beam        Show ANTIC scan position
.caslogdata  Toggle verbose cassette data read logging
.ciodevs     Dump Central Input/Output (CIO) device list
.covox       Dump Covox sound extension status
.diskdumpsec Dump floppy disk sector data
.diskorder   Set forced phantom sector ordering
.diskreadsec Read sector from floppy disk
.disktrack   Show sector order within track
.diskwritesec Read sector from floppy disk
.dlhistory   Show ANTIC display list execution history
.ds1305      Show DS1305 real-time clock status
.dma         Show current ANTIC DMA pattern
.dmabuf      Show ANTIC DMA line buffer
.dmamap      Show ANTIC DMA activity map
.dumpdlist   Dump ANTIC display list
.dumpdsm     Dump disassembly to file
.dumpsnap    Create bootable snapshot image
.echo        Display message to console
.gtia        Display GTIA status
.ide         Display IDE emulator status
.ide_dumpsec Dump IDE raw sector
.ide_rdsec   Read IDE sector into memory
.ide_wrsec   Write IDE sector from memory
.iocb        Display CIO I/O control blocks
.loadksym    Load kernel symbols
.loadobj     Load executable object
.loadsym     Load module symbols
.map         Show memory map layers
.netstat     Display network connection status
.onexeclear  Clear queued on-executable commands
.onexelist   List queued on-executable commands
.onexeload   Queue command on executable load
.onexerun    Queue command on executable run
.pathdump    Dump disassembly of recorded paths to a file
.pathrecord  Show or change path recording setting
.pathreset   Clear recorded paths
.pathbreak   Toggle break on new path
.pbi         Display Parallel Bus Interface (PBI) status
.pclink      Display PCLink status
.pia         Display Peripheral Interface Adapter (PIA) status 
.pokey       Display POKEY status
.printf      Display message with formatted fields
.readmem     Read memory from disk
.reload      Reload symbol files
.restart     Restart emulated system
.sdx_loadsyms  Load SpartaDOS X symbols
.sio         Dump SIO device control block (DCB)
.sourcemode  Switch between source and disassembly level debugging
.sprintf     Construct message with formatted fields
.sum         Compute sum of memory range
.tape        Display cassette tape deck status
.tapedata    Display cassette tape data
.tracecio    Toggle CIO call tracing
.traceser    Toggle serial I/O port tracing
.ultimate    Dump Ultimate1MB status
.unloadsym   Unload module symbols
.vbxe        Display VBXE status
.vbxe_bl     Display VBXE blit list (BL)
.vbxe_xdl    Display VBXE extended display list (XDL)
.vbxe_traceblits    Toggle VBXE blit tracing
.vectors     Display kernel vectors
.warmreset   Warm reset simulation
.writemem    Write memory to disk

Some commands support extended memory syntax:
  $0000      CPU view of primary memory
  $01:0000   CPU view, 65C816 high memory
  n:$0000    ANTIC view of primary memory
  v:$00000   VBXE memory
  r:$0000    Main memory
  x:$00000   Extended memory

Some commands support length syntax:
  db siov L100
  db 4000 L>5FFF

Use .help <command> for detailed help on that command.
 

I think these are enough to start with. hope it would be helpful to some of you. any questions, comments, notes, additional info that i can add to this tutorial, don't hesitate and let me know


Cheers,
Yaron

Edited by Yaron Nir
  • Like 6

Share this post


Link to post
Share on other sites

Nice.

 

A note that when focused on a line in the Disassembly window, F9 can be used to toggle a breakpoint.

 

Also, within Console, "frame to be drawn" is better phrased "frame being drawn".

Share this post


Link to post
Share on other sites

Nice.

 

A note that when focused on a line in the Disassembly window, F9 can be used to toggle a breakpoint.

 

Also, within Console, "frame to be drawn" is better phrased "frame being drawn".

 

updated. thanks!

  • Like 1

Share this post


Link to post
Share on other sites

As part of my contribution to the cc65 development for the atari 8bit community,

i've decided to write a short tutorial that might help you guys if you wish to debug your code via altirra.

great topic.

many thanks

  • Like 1

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...