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 > Kick Assembler - Removal of unused code?
2019-02-05 15:04
Taskmaster
Account closed

Registered: Feb 2018
Posts: 22
Kick Assembler - Removal of unused code?

I'm trying out Kick Assembler and I'm wondering if it has a feature I used a lot in my own assemblers over the years.

I like to collect useful subroutines and keep them in an external ASM file that I include at the top of my code. Is there a way that I can do that BUT have the assembler not compile code that I don't actually call?

I hate to eat the memory space for stuff that I won't be calling in that specific app.

How do you guys handle this sort of thing? Am I over engineering? :)
2019-02-05 15:25
Zirias

Registered: Jan 2014
Posts: 48
A feature you used a lot? How would that work? While it's relatively easy to detect definitely "dead code" in C, I don't see how an assembler could reliably do that, e.g. think about self-modification with calculated jump targets...

With ca65, you could take advantage of the linker (ld65): have each of your routines in a separate translation unit, pack them into one static library with ar65. When you link this library, the linker will only include object files with code that is actually referenced. You can have an include-file with this library that has all the ".import" statements necessary -- ca65 discards ".import"s that aren't actually used.
2019-02-05 15:38
Taskmaster
Account closed

Registered: Feb 2018
Posts: 22
In my case, I had a special way to designate routines that were optional for compilation. So something like:

.sub MyFunc
{
}

If "jsr MyFunc" never appears in the code, then it excluded that subroutine from the final compilation.


So I guess I could reframe the question to be something like:

How does someone with lots of little utility functions organize their code base? Do you simply copy/paste the stuff you need in?

I thought about some sort of system where every sub routine lived in it's own ASM file but that seems crazy.
2019-02-05 15:58
Flavioweb

Registered: Nov 2011
Posts: 463
I guess you can use IF statements with some flags in your init part where set them to 1 when used functions need to be compiled.
2019-02-05 16:00
Taskmaster
Account closed

Registered: Feb 2018
Posts: 22
I had thought of that. Seemed clunky so I was hoping maybe Kick had something to automate the process but I guess not.

Thanks for the replies! I'll work around...
2019-02-05 16:37
Erol

Registered: Jul 2003
Posts: 6
Macros and pseudo-commands in separate .asm file please check http://www.theweb.dk/KickAssembler/webhelp/content/cpt_Function.. if you don't call it via macro or pseudo command it will not get compiled, so only used macros and pseudo-commands are actually compiled and present in memory.
2019-02-05 16:51
Taskmaster
Account closed

Registered: Feb 2018
Posts: 22
Thanks! Yes, macros and pseudocommands work the way I want but that doesn't fly if the routine is somewhat large. I don't want to macro it into the code everywhere I call it ... say, for example, a memcopy routine.

In that case, I want to make it a routine that compiles once in memory BUT gets ignored if nobody calls it.

Functions don't really fly because they can't generate byte code. Just the internal scripting commands are allowed. Unless I missed something.
2019-02-05 16:57
Zirias

Registered: Jan 2014
Posts: 48
Quoting Taskmaster
I thought about some sort of system where every sub routine lived in it's own ASM file but that seems crazy.


Why? At least with something like ca65, it isn't -- you can have something "self-contained" (with code, data, bss, zeropage segments) and only link it when needed. To use it, you build a static library from all these files.

When working only at the source level, it's of course a bit more cumbersome.
2019-02-05 17:01
Taskmaster
Account closed

Registered: Feb 2018
Posts: 22
I should have been clearer - crazy for ME. :) I'm not that advanced at this point, so doing all of that is sort of beyond my scope at the moment.

But thanks, it's good to know that sort of thing is possible...
2019-02-05 17:51
chatGPZ

Registered: Dec 2001
Posts: 11386
i know its not what you ask - but 64tass can do what you want, even semi automatically.
2019-02-05 18:23
Taskmaster
Account closed

Registered: Feb 2018
Posts: 22
No, that's super helpful, thanks!

.proc
.pend

That looks like what I want. I'll dig into 64tass a little then, maybe that's a better fit for me.
2019-02-05 20:27
Digger

Registered: Mar 2005
Posts: 437
Interesting problem... I've found this article on Macros (http://wilsonminesco.com/StructureMacros/index.html) but it seems a little bit over the top for me to code like that, code is more readable but longer and slower.

It's possible to do purely with KickAss macros:

// Address for all compiled macros
.var libAddrOffset = $2000

// Address (plus flag) for the compiled macro
.var setColorsUsedAddr = null
// Here comes the proc
.macro setColors() {
  // Store current program address
  .var currentAddr = *
  // Check if macro was used before
  .if (setColorsUsedAddr == null) {
    // Not yet, compile at lib address
    * = libAddrOffset
    // Mark the macro as used and store its address
    .eval setColorsUsedAddr = libAddrOffset
    stx $d020
    sty $d021
    rts
    // Update the library address (for additional macros)
    .eval libAddrOffset = *
  }
  // Restore program address
  * = currentAddr
  // Call the proc
  jsr setColorsUsedAddr
}

// Example: Proc called twice, compiled once
// If not used, won't compile
* = $1000

ldx #2
ldy #4
setColors()

ldx #7
ldy #8
setColors()

jmp *


Here's the result:
(C:$100e) d 1000
.C:1000  A2 02       LDX #$02
.C:1002  A0 04       LDY #$04
.C:1004  20 00 20    JSR $2000
.C:1007  A2 07       LDX #$07
.C:1009  A0 08       LDY #$08
.C:100b  20 00 20    JSR $2000
.C:100e  4C 0E 10    JMP $100E
.C:1011  00          BRK

(C:$1029) d 2000
.C:2000  8E 20 D0    STX $D020
.C:2003  8C 21 D0    STY $D021
.C:2006  60          RTS
.C:2007  00          BRK


This could be even abstracted out in a more elegant fashion, i.e. store addresses as List() and create a macro called .proc() that would wrap just the macro code. Let me know if you need help with that :)
2019-02-05 21:12
Compyx

Registered: Jan 2005
Posts: 631
Wow, that's all you need? :)
2019-02-06 10:54
Taskmaster
Account closed

Registered: Feb 2018
Posts: 22
That's really cool! Complex but cool.

I actually understand what's going on there so that's a good sign.

Kick has a lot of power, apparently. Thanks for that, I'll give it some thought. :)
2019-02-06 12:42
Taskmaster
Account closed

Registered: Feb 2018
Posts: 22
I've been trying to build on that awesome example by Digger. I'm stuck on something I'm sure is simple but I don't know enough about Kick scripting yet.

How can I create a string and then drop it into the source code, as if I had typed it? You know, for dynamic labels and things like that?

Take this code...

.macro DeclareIt( _name_ )
{
lda #0
rts

.eval _name_ + "_Var:"
.byte 0
}

Main:

DeclareIt( "MyMacro" )
lda MyMacro_Var

rts

What I want is for "MyMacro_Var:" to become a real label but while I can build the string, I can't drop it into the source for compilation ...

What am I missing?
2019-02-06 12:50
Taskmaster
Account closed

Registered: Feb 2018
Posts: 22
What I'm getting at is, once this expands out and hits the assembler, I want it to look like this:

lda #0
rts
MyMacro_Var:
.byte 0

lda MyMacro_Var

rts

(NOTE : yes, the code is total nonsense, I'm just trying to get a successful compilation at this point)

:)
2019-02-06 15:44
Digger

Registered: Mar 2005
Posts: 437
Been trying to ask Mads aka Slammer exactly about the same! ;-)
2019-02-06 15:46
Taskmaster
Account closed

Registered: Feb 2018
Posts: 22
Haha, well, please report back if he helps you. :)
2019-02-06 16:44
Digger

Registered: Mar 2005
Posts: 437
You can target macro vars with dot, i.e. LDA MyMacro._Var AFAIR ;-) Don’t need dynamic labels for that.
2019-02-06 16:47
Taskmaster
Account closed

Registered: Feb 2018
Posts: 22
Right, but my question isn't about that.

I want to dynamically create, say, label names from strings being passed in.

Like ...

DeclareIt( "MyMacro" )
DeclareIt( "MySecondMacro" )
DeclareIt( "MyMacroThird" )

Gives me 3 macros using that base string as the root of their names and variable labels. Essentially, using the scripting language to generate source code from what is effectively a template ...

Does that make sense?
2019-02-06 18:10
Oswald

Registered: Apr 2002
Posts: 5094
Quote: Right, but my question isn't about that.

I want to dynamically create, say, label names from strings being passed in.

Like ...

DeclareIt( "MyMacro" )
DeclareIt( "MySecondMacro" )
DeclareIt( "MyMacroThird" )

Gives me 3 macros using that base string as the root of their names and variable labels. Essentially, using the scripting language to generate source code from what is effectively a template ...

Does that make sense?


describe what your ultimate goal is maybe there is a simpler better another solution to it.
2019-02-06 19:58
Frantic

Registered: Mar 2003
Posts: 1648
That is already described in the first post?
2019-02-06 20:06
Taskmaster
Account closed

Registered: Feb 2018
Posts: 22
To be fair, we sort of switched topics ... or side stepped, anyway.

But currently what I'm looking to do is use the Kick scripting language, or something else, to generate code.

This would allow me to write some generic wrapper macros that would auto-write the boilerplate necessary for the technique that Digger was sharing.
2019-02-06 23:29
Digger

Registered: Mar 2005
Posts: 437
Here's slightly "abstracted out" and cleaner version, using some tips from Slammer:
https://pastebin.com/print/cZqgdv7C

What remains is to figure out:
1) the ways of passing params to these lib code, a good write-up here: https://maciejmalecki.github.io/blog/macro-hosted-subroutines
2) what's the best way to utilise macro's variables
2019-02-07 00:54
Taskmaster
Account closed

Registered: Feb 2018
Posts: 22
Wow, this got a lot deeper than I was expecting ... thanks for the replies, everyone, it's been informative!
2019-02-08 10:48
Taskmaster
Account closed

Registered: Feb 2018
Posts: 22
So, to underscore what I wanted to do here in the end ... I wanted some way to boilerplate the code that Digger inspired above.

LONG STORY SHORT, I WANT TO USE THE SCRIPTING LANGUAGE TO GENERATE CODE THAT THEN GETS COMPILED AS IF I HAD TYPED IT.

Code like this gives me what I want, in terms of conditional compilation and I love it:

NOTE : SUBSYS_MasterAddr is defined elsewhere.

.var GFX_HideROMCharSet_Addr = 0

.macro GFX_HideROMCharSet()
{
	.if( GFX_HideROMCharSet_Addr == 0 )
	{
		.var save_pc = *
		* = GFX_HideROMCharSet_Addr = SUBSYS_MasterAddr
		{
			lda #$37
			sta $01
			cli

			rts
		}

		.eval SUBSYS_MasterAddr = *
		* = save_pc
	}

	jsr GFX_HideROMCharSet_Addr
}


The trouble is, this is all the code that I actually need:

			lda #$37
			sta $01
			cli


All the rest is boilerplate cruft. So I wanted a way, in Kick Assembler, to generically insert that code for me. But I need some sort of text replacement ability before compilation begins. It FEELS like it should be possible. So something like:

ProcStart(GFX_HideROMCharSet)
{
	lda #$37
	sta $01
	cli
}
ProcEnd(GFX_HideROMCharSet)


"ProcStart" and "ProcEnd" take the name I provide it and drop it into the assigned slots in the code templates and away we go. So, everywhere you see a [ARG_HERE] ...

-----------------------
ProcStart
-----------------------
.var [ARG_HERE]_Addr = 0

.macro [ARG_HERE]()
{
	.if( [ARG_HERE]_Addr == 0 )
	{
		.var save_pc = *
		* = [ARG_HERE]_Addr = SUBSYS_MasterAddr
		{


-----------------------
ProcEnd
-----------------------
			rts
		}

		.eval SUBSYS_MasterAddr = *
		* = save_pc
	}

	jsr [ARG_HERE]_Addr
}


This feels like it SHOULD be scriptable ... is it?
2019-02-08 16:25
Digger

Registered: Mar 2005
Posts: 437
Check my pastebin code above :)
2019-02-08 16:35
Taskmaster
Account closed

Registered: Feb 2018
Posts: 22
I saw that, thanks!

And that is a way to get where I'm going but I'm now wondering about the more generic question ...

Is there a way to write code with the Kick scripting language so that it dynamically creates source that will be compiled in later passes?

I know you can use FOR loops with VARs and modify operand arguments, but ... is there any way to emit straight text or strings?

Like, if I have:

.var myCmd = "lda #0"

Can I get that "lda #0" line emitted to the source code somehow?
2019-02-08 18:45
Digger

Registered: Mar 2005
Posts: 437
Why would you like to do it?
I often use JS to generate the KickAss code that later gets compiled, but that's useful usually for speed code, for example for texture lookups.
2019-02-08 19:11
Oswald

Registered: Apr 2002
Posts: 5094
	* = $1000
	
changebackr	.proc	
	sta $d020
	rts
	.pend

	jmp * 


result in memory:

.C:1000 4C 00 10 JMP $1000

	* = $1000
	
changebackr	.proc	
	sta $d020
	rts
	.pend

	jsr changebackr
	jmp *


result in memory:

.C:1000 8D 20 D0 STA $D020
.C:1003 60 RTS
.C:1004 20 00 10 JSR .changebackr
.C:1007 4C 07 10 JMP $1007


also macros do what you want in your post #1, they only get compiled into memory when you use them.

	* = $1000
	
changebackgr	.macro
	lda #\1
	sta $d020
	.endm

	#changebackgr 0
	jmp *


result in memory:

.C:1000 A9 00 LDA #$00
.C:1002 8D 20 D0 STA $D020
.C:1005 4C 05 10 JMP $1005
2019-02-08 21:12
Compyx

Registered: Jan 2005
Posts: 631
That looks like 64tass code. The topic is about Kickassembler.
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
Flashback
MCM/ONSLAUGHT
zscs
Alakran_64
ned128
Durandal
syntaxerror
MWR/Visdom
Guests online: 96
Top Demos
1 Next Level  (9.7)
2 13:37  (9.7)
3 Mojo  (9.7)
4 Coma Light 13  (9.6)
5 Edge of Disgrace  (9.6)
6 What Is The Matrix 2  (9.6)
7 The Demo Coder  (9.6)
8 Uncensored  (9.6)
9 Comaland 100%  (9.6)
10 Wonderland XIV  (9.6)
Top onefile Demos
1 Layers  (9.6)
2 No Listen  (9.6)
3 Cubic Dream  (9.6)
4 Party Elk 2  (9.6)
5 Copper Booze  (9.6)
6 Dawnfall V1.1  (9.5)
7 Rainbow Connection  (9.5)
8 Onscreen 5k  (9.5)
9 Morph  (9.5)
10 Libertongo  (9.5)
Top Groups
1 Performers  (9.3)
2 Booze Design  (9.3)
3 Oxyron  (9.3)
4 Triad  (9.3)
5 Censor Design  (9.3)
Top Musicians
1 Rob Hubbard  (9.7)
2 Mutetus  (9.7)
3 Jeroen Tel  (9.7)
4 Linus  (9.6)
5 Stinsen  (9.6)

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