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: 21
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?
 
... 10 posts hidden. Click here to view all posts....
 
2012-12-21 04:28
TBH

Registered: Mar 2010
Posts: 21
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: 2014
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: 21
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
MCM/ONSLAUGHT
Mike
icon/The Silents, Sp..
Peacemaker/CENSOR/Hi..
MWR/Visdom
DeMOSic/MS^LSD^ONS
Magic/Nah-Kolor
rambo/Therapy/ Resou..
Raf/Vulture Design
Guests online: 92
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 No Listen  (9.6)
2 Layers  (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 Censor Design  (9.3)
5 Triad  (9.3)
Top NTSC-Fixers
1 Pudwerx  (10)
2 Booze  (9.7)
3 Stormbringer  (9.7)
4 Fungus  (9.6)
5 Grim Reaper  (9.3)

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