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 > 6502 Function Parameters
2012-12-18 16:24
TBH

Registered: Mar 2010
Posts: 20
6502 Function Parameters

I've been experimenting with 6502-based functions. I searched a number of 6502 coding sites but haven't found any approaches similar to mine. Perhaps I'm missing something. Anyway, I'd appreciate some comments on efficiency and alternatives.

I've written a set of function "wrappers" that wrap a minimal structure around a subroutine, allowing the function to be fully managed with features including stack frames/local memory storage, pipes, code injection and arbitrary input parameter expressions.

A (contrived) example of a wrapped function follows. It expects three bytes passed in to the Zero-page located ParamList, the location of 11 contiguous bytes used to store the function input data:

This function expects Byte 1 to be a screen code, and Bytes 2 and 3 to be a vector to a screen location. For example, the inputs 1,0,4 would result in the letter "A" appearing in the top-left corner of the default text screen.
The two bytes following JSR FunctionManager are descriptors used by the function manager.

UFPrintChar JMP FCPrintChar ; Unmanaged jump 
MFPrintChar JSR FunctionManager
  .BYT %00000001 ; CPU Registers are used
  .BYT 3 ; Three bytes passed in if by-value
  FCPrintChar LDY #$00
  LDA MFParamList
  STA ( MFParamList + 1 ),Y
RTS


The next piece of code is the function call. The first byte after the call is a control byte that requests for certain parts of the local variables to be saved (Bit 0 indicates the CPU registers), if the parameters are passed in as a value list or a complex Parameter Expression (Bit 6), and whether the parameters are inline or remote (Bit 7). In this example a Parameter Expression is used and the parameters are inline.

The Parameter Expression ID points to a Caller-applied signature that describes how the input values are acquired. In this example there are three bytes, the first acquired using an absolute address indexed by X (as in LDA CharTable,X) followed by a 16-bit value passed in by value.

A set of common expressions are available, such as values, CPU registers, memory addresses and various forms of indexing, each resolving the expression into 8 or 16-bit values for the Parameter List, which is a series of contiguous bytes starting at MFParamList. Function code treats the Parameter List, along with many other memory locations, as local variables that can be preserved on the stack between subsequent function calls.

Parameter Expressions (for want of a better name!) negate the need to use code specifically to set up input parameter values.

...
LDX #$04
JSR MFPrintChar
  .BYT %01000001
  .WOR PE_AddrXB_ValW
  .WOR CharTable, $0400
... 


A rather contrived table of char values follows:

CharTable .BYT 4,3,2,1,0


The following is an example Parameter Expression which can be applied to any function. It is defined using an assembler label followed by single-byte list length, single-byte value data length, multi-byte list of Expressions, each representing a unique method used to extract one item of one or two-byte data for the input parameter. In the following definition, the first item of data is a single byte (our screen code!) extracted using an address (our CharTable) supplied by the Caller, followed by another two-byte value supplied by the Caller (our Screen Address).

 
PE_AddrXB_ValW .BYT 2,4, PEAddrXB, PEValW


The magic occurs inside FunctionManager, which is called from within a function to initiate the Function Management processes.
* On entry to FunctionManager the CPU registers and Processor Status are stored.
* The Function's return address is pulled from the CPU Stack and it and the following data is used to calculate the Jump to the wrapped code, which will be JSR'd to later.
* The Caller's return address is pulled from the CPU Stack and the first address after the inline parameters is calculated and pushed to the Stack.
* The Function code is JSR'd. However, this may actually be replaced with an alternate vector such as to 65816 or REU equivalent code. Also, any local user memory (various sets of Zero Page locations) may be pushed onto the Stack for preservation prior to the JSR to the function code. This simulates a stack frame using ZP memory, but preservation occurs only when the Caller requests it AND the Function indicates that it may modify the memory (done by ANDing bits together and preserving it on the stack) - this allows proper recursive functions.

So, the system features variable-sized and selective stack frames, flexible roll-your-own function input expressions, and lots more. But, am I missing something (please don't suggest using a higher-level language instead!)?

I've written a fair amount of code that uses these functions, mostly to manage exotic data structures and with the intention to minimise non-architectural elements of application code I write.

I cannot think of any other way to prepare the parameter data efficiently except by the use of Parameter Expressions. Assembler Macros? No, they are an entirely different beast. Compiler? No, I'd have written Slang if I wanted to write a C-like language. So, does anyone have any thoughts on this matter?
 
... 3 posts hidden. Click here to view all posts....
 
2012-12-19 11:51
Frantic

Registered: Mar 2003
Posts: 1628
Never really needed something like this myself, but it seems reasonable. Nice middle ground between high level and low level.

Then again you can also mix C code from cc65 with assembler (ca65) very easily, so I am not totally sure that I see the great benefit achieved in your case, or why you did not in fact use one of the already available languages. But anyway.. to each his own!

Not sure what kind of feedback you want but have you looked at how ca65 (or slang) implement these things? I guess that could provide some inspiration and ideas.
2012-12-19 15:56
chatGPZ

Registered: Dec 2001
Posts: 11135
personally i'd use BRK with some parameters instead of a jsr to call what you call function manager (saves a byte here and there at relatively low cost). i also never felt the need for such thing except when writing code for a high level language (C) =)
2012-12-19 19:31
Mace

Registered: May 2002
Posts: 1799
Let me start by saying that I don't really understand what you want, nore what you are doing.
Also, with such incredibly complicated stuff, I always wonder if you're on the right track. Most of the times there are way simpler ways of achieving what you want.

Beside all that, I'm sure there's an easy way in Kick Assembler to do whatever you want, using List(), a few if-statements and self manipulating code.
2012-12-19 21:42
S.E.S.

Registered: Apr 2010
Posts: 19
Quoting Groepaz
personally i'd use BRK with some parameters instead of a jsr to call what you call function manager (saves a byte here and there at relatively low cost).
Isn't there some problem with BRK when you've got IRQs or NMIs enabled and are using them at frequent intervals? Like, the BRK gets swallowed when it occurs exactly at the same time as the IRQ or NMI? Does anybody have a pointer to some facts about that?
2012-12-20 16:25
Graham
Account closed

Registered: Dec 2002
Posts: 990
The first problem arises with BRK because it shares the same vector as normal IRQs. Anyway, unless you don't want to do recursive code, there's hardly a reason to have function parameters on the stack. And if you do recursive code, a 256 byte stack is usually not sufficient for your average recursive algorithm.
2012-12-20 17:49
Bob

Registered: Nov 2002
Posts: 71
this looks very similait to what CRT did for Wonderland XI the realtime definer lib which does recursive stuff... (big scroller) like a painter lib,
functions with arg, and trick with stack ctrl for ret..
awesome piece of code ;)
everything i painted from scratch on that part,
has common vector routines, fillers and definer pass 1 & 2
these are extreemly complicated stuff, no wonder that hardly anyone has done this during our absence.. I recommend you to have a chat with CRT about this coding tech. Function arg is needed for such complexity ;)

one usage we had was to tell the lib where the screen memory was and what type of opimize type to use for color overflows, nibble vs d800 storage prio order etc. to gain most speed or minimal memory

or simply define a vectored array area to be filled ;) the usage was very dynamic due to this function argument type..
2012-12-20 17:54
chatGPZ

Registered: Dec 2001
Posts: 11135
apropos, if you want to see some crazyass code that does similar stuff, look at mahoneys "mp3" player. have a beer or two handy before you try to understand the wrapping stack shit =D
2012-12-21 04:28
TBH

Registered: Mar 2010
Posts: 20
Thanks for the comments and suggestions. My project is self-indulgent and, to a degree, contrived; the reason being I've not done much 6502 coding in the past decade (my time was taken up with Pascal, C# and various scripting languages) and so have decided to take on a complex task in order to improve my skills in planning, organising and programming in pure 6502 assembly.

I hadn't thought of using the IRQ/BRK vector in the manner Groepaz suggested. The hardware interrupt issue introduces a few difficulties which prevent its adoption, but it's another useful technique I'll keep in mind for other projects.

And thanks for the heads-up, Mace, regarding unnecessary complexity. That's one of my bad habits, something I always have to be conscious of.
2012-12-21 06:30
JackAsser

Registered: Jun 2002
Posts: 1989
In the hidden line vector in the demo 1991 I use a recursive algorithm to calculate how to clip a line against previously rendered polygons. In that code I simply push the function parameters onto the stack and be done with it. As for returning, the function itself is responsible for poping the parameters before calling rts, much like any interrupt service routine would do. I don't use any fancy function manager or so because I wanted to keep the overhead at a minimum.

For the 3D-part in Andropolis I also use a recursive algorithm called portals which employs a similar scheme.

As for local stack frames I simply "emulate" this by pushing pseudo function parameters.
2013-01-10 00:25
TBH

Registered: Mar 2010
Posts: 20
Since my last post I've rewritten the function manager from scratch, simplifying the way parameters were accessed. The code libraries using it (mostly to do with data structure management in 24-bit address space) have grown and have become quite usable (at least, from my perspective).

One of the more useful concepts I've adapted from other systems I've worked on is a set of generic handle routines.

The handles are a finite set of zero-based indices (actually, any arbitrary set of unique values) that can be allocated and deallocated as required from a static pool of memory.

A handle pool is organised thus:
.BYT Total, Handles..., Counter

So for say, a set of sprite handles, it would be:
SPRHDL .BYT 8,7,6,5,4,3,2,1,0,8

So, load .X/.Y with the address and JSR the Allocate routine to provide the next available handle in .A, or JSR Deallocate to pass the handle back to the pool. Over a period of usage the pool content will tend to get all jumbled up because any currently allocated handle may be deallocated (ie not just the most recent).

I've found this method simplifies dealing with temporary indexed data that occupies statically defined memory areas.
Previous - 1 | 2 - Next
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
The Phantom
Jazzcat/Onslaught
Guests online: 87
Top Demos
1 Next Level  (9.8)
2 Mojo  (9.7)
3 Coma Light 13  (9.7)
4 Edge of Disgrace  (9.6)
5 Comaland 100%  (9.6)
6 No Bounds  (9.6)
7 Uncensored  (9.6)
8 Wonderland XIV  (9.6)
9 Memento Mori  (9.6)
10 Bromance  (9.5)
Top onefile Demos
1 It's More Fun to Com..  (9.7)
2 Party Elk 2  (9.7)
3 Cubic Dream  (9.6)
4 Copper Booze  (9.5)
5 TRSAC, Gabber & Pebe..  (9.5)
6 Rainbow Connection  (9.5)
7 Dawnfall V1.1  (9.5)
8 Quadrants  (9.5)
9 Daah, Those Acid Pil..  (9.5)
10 Birth of a Flower  (9.5)
Top Groups
1 Nostalgia  (9.3)
2 Oxyron  (9.3)
3 Booze Design  (9.3)
4 Censor Design  (9.3)
5 Crest  (9.3)
Top Swappers
1 Derbyshire Ram  (10)
2 Jerry  (9.8)
3 Violator  (9.8)
4 Acidchild  (9.7)
5 Starlight  (9.6)

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