Log inRegister an accountBrowse CSDbHelp & documentationFacts & StatisticsThe forumsAvailable RSS-feeds on CSDbSupport CSDb Commodore 64 Scene Database
You are not logged in - nap
CSDb User Forums


Forums > C64 Coding > Code based breakpoints using ca65 and VICE
2009-08-06 07:54
JackAsser

Registered: Jun 2002
Posts: 1997
Code based breakpoints using ca65 and VICE

Recent discussions about debugging etc made me do this, much like Doynax's stuff:

Macro for ca65:
.macro breakpoint name
    .ident (.concat("br_", .string(name))):
    .export .ident(.concat("br_", .string(name)))
.endmacro

Link line in your Makefile:
ca65 -C link -m map -Ln symbols $(OBJS) && sed 's/al [0-9A-F]* \.br_\([a-z]*\)/\0\nbreak \.br_\1/' < symbols > symbols2

Basically it tells ca65 to emit all labels into a file called symbols. The sed-script then locates all symbols starting with br_ and adds a breakpoint command after it.

To run in VICE:
x64 -moncommands symbols2 whateva.d64

This enables you to add breakpoints directly into your sourcecode like:

breakpoint flashcolors
inc $d020
jmp *-3


Have fun with future debugging! :)

2009-08-06 09:17
AlexC

Registered: Jan 2008
Posts: 293
This is great tip. Thanks.
2009-08-06 15:43
doynax
Account closed

Registered: Oct 2004
Posts: 212
I still say we need an assembler pseudo-op to emit raw strings to a VICE monitor script, except perhaps with some way of embedding evaluated expressions. I mean, wouldn't it just be awesome to be able to have proper (non-intrusive) asserts in your code?

Unfortunately VICE's condition expressions aren't very powerful, but it shouldn't be very hard to extend them to handle flags, the cycle/scanline counters, and memory variables.
Just imagine setting up a check to see that the final element in a list really is zero, or that an addition didn't overflow, or even that some timed raster code always runs in the proper cycle.

Of course what we *really* need is to have a full-blown script interpreter (e.g. Lua or something) built into VICE, like some of those newfangled NES emulators have. That way you could prototype tricky functions in a high-level language, as well as verify the results of the final assembly function against the original HLL code.
2009-08-06 16:11
JackAsser

Registered: Jun 2002
Posts: 1997
Quote: I still say we need an assembler pseudo-op to emit raw strings to a VICE monitor script, except perhaps with some way of embedding evaluated expressions. I mean, wouldn't it just be awesome to be able to have proper (non-intrusive) asserts in your code?

Unfortunately VICE's condition expressions aren't very powerful, but it shouldn't be very hard to extend them to handle flags, the cycle/scanline counters, and memory variables.
Just imagine setting up a check to see that the final element in a list really is zero, or that an addition didn't overflow, or even that some timed raster code always runs in the proper cycle.

Of course what we *really* need is to have a full-blown script interpreter (e.g. Lua or something) built into VICE, like some of those newfangled NES emulators have. That way you could prototype tricky functions in a high-level language, as well as verify the results of the final assembly function against the original HLL code.


That would be awesome indeed ofcourse.
2009-08-07 11:54
Skate

Registered: Jul 2003
Posts: 492
if it goes this way, we will start creating unit tests in our c64 demo projects soon. ;)

@Nightlord: dude hear me, we are still waiting for C=++ :)
2009-08-07 12:44
doynax
Account closed

Registered: Oct 2004
Posts: 212
Quote: if it goes this way, we will start creating unit tests in our c64 demo projects soon. ;)

@Nightlord: dude hear me, we are still waiting for C=++ :)


You say that is if it would be a bad thing..

I'm perfectly serious. It shouldn't be very difficult include a Lua interpreter in VICE and add a few hook functions for it to peek and poke around in memory and CPU the registers, and then allow breakpoints/watchpoints to trigger Lua callbacks rather than normal breaks.

Just imagine that you've got an awesome new idea for an optimized line-drawer, but you don't want to bother with 6502-optimizing all of the 3D math just yet. Or, better yet, if I (or even a non-developer) could try out and tweak new enemy behaviours for my game without having to worry about an efficient implementation.
2009-08-08 09:11
andym00

Registered: Jun 2009
Posts: 44
@doynax: Why not just (ab)use an unused opcode in Vices 6510core.c which precedes a variable length string, which you can then parse in the opcode execution and spew out through debug_text() which pops out through Win32s OutputDebugString which handily arrives in your output window in VisualStudio :)
Proper formatting of the output even means a click on the outputted string will take you to the source file and line number that generated it..

I haven't done this with Vice yet (though probably will today), but have with several other emulators and then you can add whatever expression evaluation and handling you want to it..

I also want to experiment with shared memory stuff under Vice an investigate exposing the emulators memory to other processes to enable reading/writing of the memory from other applications..
2009-08-12 21:41
Slammer

Registered: Feb 2004
Posts: 416
Code based breakpoints seems really cool. I did a createFile function to support it in Kick Assembler. Here is a little program that show how it's used:
.var brkFile = createFile("breakpoints.txt") 

.macro break() {
	.eval brkFile.writeln("break " + toHexString(*))
}

.pc=$0801 "Basic"
:BasicUpstart(start)

.pc=$1000 "Code"
start:
	inc $d020
	:break()
	jmp start

NB. Use the -afo switch when assembling, otherwise filecreation is blocked
2009-08-13 10:52
Dragnet

Registered: Nov 2006
Posts: 16
Hola,

Hey, neat feature! :)

But it would be even nicer if KickAss allowed command line arguments to be passed into the code, allowing the functionality to be truly generic...

For example, I use a unique "compile.bat" file to compile a given part (in a separate dir), with content like this:

java -jar c:/c64/KickAssembler35/kickass.jar foo.asm -showmem -vicesymbols -libdir "c:/c64/includes" -log foo.log


Then, if I was allowed to add additional user-defined arguments, say something like "-break_filename foo.txt", then the scenario would then become something like:

.var brkFile = createFile(getCommandLineArgument("-break_filename")) 

.macro break(file) {
  .eval file.writeln("break " + toHexString(*))
}

..

ldx #$ff
:break(brkFile)
lda #$00

:)

Regards / Dragnet
2009-08-13 11:17
doynax
Account closed

Registered: Oct 2004
Posts: 212
Quoting Dragnet
But it would be even nicer if KickAss allowed command line arguments to be passed into the code, allowing the functionality to be truly generic...
Can't you just use an environment variable or something?
2009-08-13 13:08
Dragnet

Registered: Nov 2006
Posts: 16
Quote: Quoting Dragnet
But it would be even nicer if KickAss allowed command line arguments to be passed into the code, allowing the functionality to be truly generic...
Can't you just use an environment variable or something?


Well, not if I want to "inject" values into the KickAss script/macro code from the environment/command line - the problem is merely how to reference such values from within KickAss, e.g. using a getCommandLineArgument function or something of the like...

/Dragnet
2009-08-13 13:19
doynax
Account closed

Registered: Oct 2004
Posts: 212
Quote: Well, not if I want to "inject" values into the KickAss script/macro code from the environment/command line - the problem is merely how to reference such values from within KickAss, e.g. using a getCommandLineArgument function or something of the like...

/Dragnet


As I understand it KickAss exposes a full Java VM, so you should be able to SET a variable in your batch script just call System.getenv().get("BREAKPOINTS").

Or something along those lines anyway, though to be honest I have as little experience with Java as with KickAss.
2009-08-13 14:40
Slammer

Registered: Feb 2004
Posts: 416
No, Kick Assembler has a script language that is working much like java (but it isn't java). So Dragnet is right, a getCommandLineArgument function would be nice. I will put it on the todo list. However, a getEnvironmentVar() would also do the trick.
2009-08-13 18:16
Dragnet

Registered: Nov 2006
Posts: 16
Quote: No, Kick Assembler has a script language that is working much like java (but it isn't java). So Dragnet is right, a getCommandLineArgument function would be nice. I will put it on the todo list. However, a getEnvironmentVar() would also do the trick.

I'm probably opening up a can of worms here and being *very* nit-picking, I know, but using environment variables like this is in my humble view something not to do in the general case; here, however, the effect is arguably the same since the environment var can be set from the .bat script as well, but you are in effect forcing use of the Singleton pattern (blah blah...) instead of letting the user decide which instance (= values) to use (blah blah)... 8^)

So, to make a long boring story short, Slammer: do the getCommandLineArgument method first, then and only then consider the environment thing... How many lines of code will it take to implement in KickAss/Java - 10, max? :)

Regards /Dragnet
2009-08-14 06:14
Mr. SID

Registered: Jan 2003
Posts: 424
You could just use k2asm:

ldx #$00
{
	lda text,x
	beq _break
	sta $0400,x
	inx
	bne _cont
}
rts

text:		
.encoding "screencodes.enc"
#pybegin			
import os
print '.enc "ASSEMBLED BY USER ' + os.getenv('USER').upper() + '",0'
#pyend


It also allows access to the commandline options, but you need to run the preprocess manually for that, I guess.
The possibilities are endless, if you actually have a full language available. There's a python library for everything...
2009-08-14 07:13
Frantic

Registered: Mar 2003
Posts: 1635
Then again... Any script language could easily make some sort of pre parsing of any text file, before this text file is sent to an assembler. What is so great about having it "in" the assembler itself? It is still executed in a completely separate pass, before any labels are resolved and so on, isn't it?
2009-08-14 10:18
Slammer

Registered: Feb 2004
Posts: 416
I thinks it's a great advantage to be able to write sine curves and small graphic converters in the middle of your sourcefile.

I guess k2asm does it by a prepass (but im only guessing) while Kick Assembler assembles both the script and the Assembler commands together. The strength of the ladder is that the script and the asm code can interact both ways.

Notice that Mr. Sid didn't solve the original problem (generating breakpoints). In the Kick Assembler example it was done by:
.eval file.writeln("break " +  toHexString(*))

where the * refers to the current memory position, this couldn't have been done in a prepass.

However, Including a preparse script in an assembler is a cool thing, relative to no script, since it makes people aware of the of the advantages of scripting.
2009-08-14 11:03
Frantic

Registered: Mar 2003
Posts: 1635
@Slamsky: Just to clarify, I was referring to k2asm in my post..

...and now I just implemented some shit so I can just write ".bpc("if .A == $83")" in my code, and the VICE monitor will break on this line, if the specified condition holds true (if register A is equal to $83 at that point in the program). Very nice. :) If I just write ".bp", it will break unconditionally on this line.

I am using DreamAss for the current project.
2009-09-16 06:21
Slammer

Registered: Feb 2004
Posts: 416
Dragnet: KickAssembler now supports setting variables from the commandline. The are available from the script through the cmdLineVars hashtable.
2014-02-15 21:45
Digger

Registered: Mar 2005
Posts: 422
That macro would be super handy:
.bpc("if .A == $83")


Is is possible to do it with Vice and KickAss?

As far as I got up to, I was able to generate the breakpoints file and then manually type in the monitor:

break 8800 if .A == $83

But that's lame ;-)

I have this complex routine that fails at one point and I need to track exactly that condition – have you got any other suggestions?

I want to use the condition to stop and step the code exactly when it happens.
2014-02-23 18:25
Digger

Registered: Mar 2005
Posts: 422
Here's the macro for KickAss and VICE (thx Frantic):
.macro bpc(condarg) {
    .eval brkFile.writeln("break " + toHexString(*) + " " + condarg)
}

Example:
.var brkFile = createFile("breakpoints.txt")
:bpc("if .A == $83")

Will stop but only if A is $83.

Of course VICE has to be launched with:
-moncommands breakpoints.txt

Happy debugging :)
2014-02-24 07:40
Bitbreaker

Registered: Oct 2002
Posts: 501
To track down bugs with modern fancy tools you all would first of all need to produce code/demos :-P Also, i wonder how we survived in the past? :-)
A simple bcs *, bcc * or alike was enough to check if flags are for sure at the state we expect them or else our program will lock up. $02 is also a good opcode to use with vice, so you can trigger the monitor as soon as your wanted piece of code is reached. I mean, we have already a whole programming language on board to do complex debugging tasks and giving feedback: 6502
So far i have not crossed borders that would make me need more. There's other things that are way more interesting in my opinion, like having a proper profiler and thus be able to detect dead code (micro64 is giving some more information here in the monitor), or have cycles of certain code segments counted easily.
Just wondering.
2014-02-24 08:06
Brush

Registered: Apr 2002
Posts: 21
I think i agree with Bitbreaker.. Breakpoints are not a must in case of c64 as you can actually change the code quickly enough and recompile/restart. I think the point is that with modern tools we could save few minutes here and there.

But profiling is a different story.. The closest thing to profiling i've been using was to slam tons of watchpoints around the code part i was optimising, running it in vice, capturing the vice output into a text file and then calculating the "weight" of each instruction with some text based utilities. That was slow but sort of worked. But i would resort to it only in the worst case (that case was my worst case as it was not a simple inner loop optimization but something bigger with a complex flow and branching and i had to figure out the right mix depending on the input data)..

Anyway, you mentioned micro64 and profiling. I remember trying it out a year ago or so and although it mentioned the profiling in the changelog i was not able to turn it on and get anything sensible out.

Could you post some short instruction on how to make it work? Thanks in advance!
2014-02-24 09:12
Bitbreaker

Registered: Oct 2002
Posts: 501
The micro64 has a monitor that can be accessed via a terminal/telnet, a typical output would look like:
$0030: b0 de     bcs $0110     ;   0.55% executed,  72.81% taken
$0032: 46 11     lsr $11       ;   0.15% executed
$0034: 90 ee     bcc $0124     ;   0.15% executed,  87.77% taken
$0036: a9 80     lda #$80      ;   0.07% executed
$0038: 85 11     sta $11       ;   0.07% executed
$003a: 45 13     eor $13       ;   0.07% executed
$003c: 85 13     sta $13       ;   0.07% executed
$003e: 85 16     sta $16       ;   0.07% executed
$0040: 30 e2     bmi $0124     ;   0.07% executed,  51.24% taken
$0042: e6 14     inc $14       ;   0.04% executed
$0044: e6 17     inc $17       ;   0.04% executed
$0046: d0 dc     bne $0124     ;   0.04% executed, 100.00% taken
$0048: a9 01     lda #$01      ;   1.13% executed
$004a: 19 d3 28  ora $28d3,y   ;   1.13% executed
$004d: 99 d3 28  sta $28d3,y   ;   1.13% executed


The mnemonic decoding yet showed some bugs (sta ($xxxx),y how cool would that be) BeRo is informed and has fixed those issues already. The output is not yet perfect, but gives a few interesting numbers, most of all, on how often a branch is taken.
2014-02-24 16:27
Brush

Registered: Apr 2002
Posts: 21
You ought to be kidding me :)

I've fired up micro64, even were in the monitor, even saw the command to reset the profiler stats but never actually disassembled a running piece of code.

Thanks for the tip, you've made my day!
2014-02-25 21:54
Slammer

Registered: Feb 2004
Posts: 416
DGGR: Exactly. Good to see you found the solution. Im not checking csdb that often anymore, but I just started this little facebook group , so feel free to join https://www.facebook.com/groups/RetroAssembler/ and discuss any retro assembler. There you will get a quick answer. Once I get time to make new releases it will be announced there as well.

Edit : Btw Everybody is welcome
2014-02-26 11:43
Bitbreaker

Registered: Oct 2002
Posts: 501
oldsk00l -> newsk00l -> facebook shadow scene ...
2014-02-26 13:55
Oswald

Registered: Apr 2002
Posts: 5034
"Also, i wonder how we survived in the past? :-)"

it sucked.

I remember having turn disk bug in Void while linking on a stock machine.

We spent a whole afternoon with Edhellon with this:

- load turbo ass
- load source
- change something
- save object
- load binary
- load object
- save them in one file to demo linking disk
- watch fuckin whole first side
- discover turn disk is still buggy
- goto 10

yeah, and in the end it turned out that I have deleted the turn disk routines from the binarily ripped loader, because I had no idea they are there for that :)
2014-02-26 17:24
chatGPZ

Registered: Dec 2001
Posts: 11165
Quote:
watch fuckin whole first side

thats your own fault though, loaders for side 2 could be done in 1997 too (just like part selectors) :)
2014-02-26 17:34
Oswald

Registered: Apr 2002
Posts: 5034
that wouldnt make auto disk side change detection work tho. anyway after like the 8th time we tried the loader alone, instead of watching the whole side 1, to speed things up :)
2014-02-26 17:39
chatGPZ

Registered: Dec 2001
Posts: 11165
no, but you could have tested only the last part of side 1 and the disk changing :) (you cant imagine how often i did that for artphosis.... argl)
2014-02-26 18:31
Oswald

Registered: Apr 2002
Posts: 5034
it comes back as we talk about it, things was we tested the loader seperately aswell, but that test case used a loader with disk change routines included, which was missing in the demo :P :)
2014-02-26 18:36
Bitbreaker

Registered: Oct 2002
Posts: 501
And how would breakpoints have helped with this pebcak-situation? :-P
2014-02-26 19:10
Oswald

Registered: Apr 2002
Posts: 5034
well, warpmode and modern cross asm env would have sped up the process a lot :)
2014-02-26 21:59
Slammer

Registered: Feb 2004
Posts: 416
Oswald: Just add "- Use one hour for crunching the file" and i will know what you are talking about ;-)
2016-09-04 15:30
soci

Registered: Sep 2003
Posts: 474
Quoting Brush
But profiling is a different story.. The closest thing to profiling i've been using was to slam tons of watchpoints around the code part i was optimising, running it in vice, capturing the vice output into a text file and then calculating the "weight" of each instruction with some text based utilities. That was slow but sort of worked. But i would resort to it only in the worst case (that case was my worst case as it was not a simple inner loop optimization but something bigger with a complex flow and branching and i had to figure out the right mix depending on the input data)..


I know it's old thread, but whatever.

The closest I've got to profiling was using kcachegrind like this:
http://singularcrew.hu/temp/2016-09-04-160615_3840x1600_scrot.p..

It shows ~28 seconds of game play on second level as it's less boring than optimizing CFSfsck down from 6:46 to 5:16 for a test set of ~8200 files (147MiB).

But the majority of code here can be "profiled" with border colour changes easily and that's what actually was used for the game.
2016-10-05 19:50
Brush

Registered: Apr 2002
Posts: 21
@soci would you be so kind to explain a little more what are we having here? How are you feeding kcachegrind?
2016-10-06 19:50
soci

Registered: Sep 2003
Posts: 474
So what happens is this:

At compile time I write a label file and a line number annotated listing with 64tass. These are used to map instruction addresses and labels to source files and line numbers.

Then I run the binary in VICE and start a trace at the place of interest for as long as necessary. This gets me the usual address, cycle, instruction information along with DMAs and interrupts. No special hacks where done to VICE.

This trace is processed, cycle counts are assigned to instruction locations and branch taken/not taken, jump and call counts are calculated.

In case of a subroutine call all cycles spent in the subroutine are assigned to "functions" whose names are determined from the labels. This works by stack tracking.

Character and sprite DMAs are not counted against the affected instructions otherwise this would be a huge source of error.

Interrupt "entry" cycles are handled specially or else these are wrongly assigned. Also cycles spent in interrupts are assigned to interrupt functions only, but not to the interrupted functions. Unlike simple subroutine calls, where called routine cycles are included.

There's a special case for the automatic "long" branches. For these the taken/not taken counts would be mixed up if naively processed.

With all these stats a ~200 line python script can produce the callgrind.out file. This contains cycle counts for instructions, line number and file assignment, calls/jumps statistics and function locations.

Based on this input kcachegrind can figure out a call graph and how much cycles are spent in routines and how these are used in it's subroutines.

Also it can display spent cycle counts, branches, jump, call numbers and jump arrows right in the source files. This comes especially handy in macro heavy cases, where the source is much different from the disassembly. And of course stuff is clickable and can be navigated through source files.

So that's it. Kcachegrind is a rather nice environment for figuring out where optimization is likely to make a difference and where not.

But apparently it's a massive overkill for optimizing regular 6502 code at least that's what I blame the low interest on.

Anyway, here's a sample callgrind.out file you can try with the Kobo64 source files (r157, sourceforge):
http://singularcrew.hu/temp/callgrind.zip
RefreshSubscribe to this thread:

You need to be logged in to post in the forum.

Search the forum:
Search   for   in  
All times are CET.
Search CSDb
Advanced
Users Online
wil
jmin
Almighty God/Level 6..
Slaxx/Q/HF/MYD!
Joodas/Albion Crew
Yogibear/Protovision
FABS/HF
rexbeng
Shogoon/Elysium/MSL
Guests online: 70
Top Demos
1 Next Level  (9.7)
2 13:37  (9.7)
3 Mojo  (9.7)
4 Coma Light 13  (9.7)
5 Edge of Disgrace  (9.6)
6 Uncensored  (9.6)
7 Comaland 100%  (9.6)
8 No Bounds  (9.6)
9 Aliens in Wonderland  (9.6)
10 Wonderland XIV  (9.6)
Top onefile Demos
1 Layers  (9.6)
2 Cubic Dream  (9.6)
3 Party Elk 2  (9.6)
4 Copper Booze  (9.6)
5 Rainbow Connection  (9.5)
6 It's More Fun to Com..  (9.5)
7 Dawnfall V1.1  (9.5)
8 Birth of a Flower  (9.5)
9 Daah, Those Acid Pil..  (9.5)
10 Morph  (9.5)
Top Groups
1 Nostalgia  (9.4)
2 Oxyron  (9.3)
3 Booze Design  (9.3)
4 Censor Design  (9.3)
5 Offence  (9.3)
Top Graphicians
1 Mirage  (9.8)
2 Archmage  (9.7)
3 Talent  (9.6)
4 Facet  (9.6)
5 Mermaid  (9.6)

Home - Disclaimer
Copyright © No Name 2001-2024
Page generated in: 0.089 sec.