Consider this part of your code:
Code:
jsr some_routine_in_another_file
args$ byte 0,0,0 ; Global for CBM prg Studio
What do you expect to happen when the called routine returns? Unfortunately, the next byte - the next instruction - is some of your data.
It feels to me you haven't quite got the picture, that your assembly source is a description of what content you want in memory. It's not like a high level language, where you would normally interleave descriptions of variables with descriptions of actions:
Code:
funcA (x) {
int y = 3;
funcB(x, y)
}
There's a lot going on in a high level language: you give names to values, and the storage for those values is allocated and managed for you. You can initialise those values. Some values are global, some are parameters, some are allocated in the stack.
None of this happens in assembly language programming! You need to decide where to store your values, and manage those allocations: whether globals or stack variables, and if global, whether stored in zero page or in main memory. Whether the storage location is known at assembly time, or only at run time.
Because zero page is limited, it's very common to use the same locations for different purposes at different times.
It's common enough for a program not to use a heap at all: for all locations to be known at assembly time.
I'm not sure what series of exercises or readings is the best way to learn this stuff - perhaps just coding, and struggling, fixing things, and eventually getting it, is the best way.
But I hope it helps to be given the message, that things are different in the land of assembly, and your program text bears a much closer relationship to the machine than you are used to.
I would in fact suggest that macros are potentially confusing you: that the beginner should write a fair amount of plain code before venturing into the use of macros. Their productivity and the efficiency of their code will then improve - macros are great, but possibly not the first thing to learn.