6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Mon Oct 07, 2024 7:23 am

All times are UTC




Post new topic Reply to topic  [ 6 posts ] 
Author Message
PostPosted: Fri Apr 04, 2014 4:53 am 
Offline

Joined: Wed Feb 05, 2014 7:02 pm
Posts: 158
Some background: I'm most proficient in C, so even if I develop code in a high level language for the 6502, chances are I will use C instead of Forth. I also make great effort to make sure that my C code is portable, and one benchmark that I've though of to test portability for my code is the following: Will cc65 compile it for the VIC20 correctly? Well, now that I think about that benchmark, I'm asking myself: How do I process input program arguments on a VIC20 :P?

According to the cc65 mailing list, command line parsing is in fact support through bypassing the KERNAL API. While I trust that this works, it made me think- was command line parsing for C64/PET programs even contemporary to the era that these home computers were sold? Can anyone name a PET/C64/VIC20/etc program which required command line arguments written back in the 80's? I would guess there were at least some such programs; I'm aware of an XMODEM implementation for VIC20- there must've been some facility to set the baud rate, xfer params, etc at runtime to interface with other machines.

If there were such programs, was it possible to use the KERNAL API to implement a command line parser? Or, like many programmers did back in the C64/MSDOS era, was the KERNAL bypassed and the hardware and associated buffers (i.e. keyboard buffer for stdin) accessed directly?


Top
 Profile  
Reply with quote  
PostPosted: Fri Apr 04, 2014 9:42 am 
Offline

Joined: Tue Jul 24, 2012 2:27 am
Posts: 674
There is no command-line per se for launching programs on those platforms. There is just RUN, or SYS, with no parameters other than where to start execution, hence the parameters are faked using a colon in groepaz's example. Traditionally, parameters are typically gotten from runtime inputs, not assembled pre-launch like the Unix model.

_________________
WFDis Interactive 6502 Disassembler
AcheronVM: A Reconfigurable 16-bit Virtual CPU for the 6502 Microprocessor


Top
 Profile  
Reply with quote  
PostPosted: Fri Apr 04, 2014 12:02 pm 
Offline

Joined: Sun Nov 08, 2009 1:56 am
Posts: 402
Location: Minnesota
While command-line parsing was common in the Unix world at the time, it was not common on the VIC20/C64 line of computers. Most likely this is because those computers normally booted to a BASIC interpreter, which has no ability to command-line arguments. Booting to BASIC was built-in to the startup ROM code. There was no easy way to bypass it short of inserting a cartridge that took control instead of BASIC at startup time.

That said, it's not quite true that a command-line parser can't use the KERNAL. Scanning the keyboard, for instance, is a defined jump table entry which is completely agnostic as regards who or what calls it.


Top
 Profile  
Reply with quote  
PostPosted: Fri Apr 04, 2014 4:55 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8417
Location: Midwestern USA
It was possible to pass arguments to a machine language program called via SYS, for example, SYS AD,P1,P2,P3, where AD is the address of the program and P1,P2,P3 are positional parameters. What was usually done was the M/L program would invoke BASIC ROM functions that could evaluate each parameter, convert it into floating point or integer format and then store it somewhere. Similarly, something such as SYS AD,"string parameter" is possible, or even SYS AD,P1,P1$,P2,P2$, etc.

Compared to the kernel of a modern operating system, e.g., Linux, the Commodore kernel ("kernal") was extremely primitive. It had absolutely no disk management functions, as those were implemented in the floppy drive firmware, very primitive timekeeping, no memory protection, etc. As was actually quite common with machines whose genesis was in the late 1970s, the operating environment was geared to running BASIC programs. Disk I/O from machine language was arcane and primitive.

Craig Bruce wrote a UNIX-like shell for the C-128 that really did provide a command line interface that accepted arguments, as BASH does in Linux. It performed quite well, especially considering that most C-128s were hooked up to feeble-performing floppy disks. Obviously, Bruce's shell was a pretty sophisticated piece of code, well beyond the simple SYS AD,P1,P2,P3 parameter passing model.

Incidentally, C has never been a particularly good fit with the 6502/65C02 family, mostly due to the paucity of stack addressing functions. The design of the 65C816 has effaced this limitation to some extent, thanks to stack pointer relative addressing and support for relocatable code.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Fri Apr 04, 2014 5:16 pm 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1948
Location: Sacramento, CA, USA
BDD,

In a different thread at comp.sys.arch, someone was mentioning that the 65816's direct page register was utilized as a stack frame pointer; it was pushed then pointed to the beginning of the local function's variables and parameters, allowing even more flexibility with addressing, since there are tons more direct-page addressing modes than stack-relative. Have you heard of this or seen any examples of this usage?

Mike


Top
 Profile  
Reply with quote  
PostPosted: Fri Apr 04, 2014 6:05 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8417
Location: Midwestern USA
barrym95838 wrote:
In a different thread at comp.sys.arch, someone was mentioning that the 65816's direct page register was utilized as a stack frame pointer; it was pushed then pointed to the beginning of the local function's variables and parameters, allowing even more flexibility with addressing, since there are tons more direct-page addressing modes than stack-relative. Have you heard of this or seen any examples of this usage?

I'm aware of it and have actually played around with the concept. While the greater number of DP addressing modes seems to be an advantage, in practice I've not found that to be all that useful over and above the available stack relative modes. This is especially true when one considers code such as the following:

Code:
         PER NPTR              ;number of chars pointer
         PER IPTR              ;index pointer
         PER S2PTR             ;STRING2's pointer
         PER S1PTR             ;STRING1's pointer
         JSR STRSUB            ;execute function

The only practical way to access the function parameters that were pushed before JSRing to STRSUB is via stack pointer relative addressing. For that, the function needs to be able to work with local stack frame definitions:

Code:
strsub   ;this line intentionally has no code
;
;—————————————————————————————————————————————————————————
;EPHEMERAL DEFINITIONS
;
.s_byte  =1                    ;size of a byte
.s_word  =.s_byte*2            ;size of a word
;
;
;   65C816 register sizes...
;
.s_mpudb =.s_byte              ;data bank
.s_mpudp =.s_word              ;direct page
.s_mpupb =.s_byte              ;program bank
.s_mpupc =.s_word              ;program counter
.s_mpusp =.s_word              ;stack pointer
.s_mpusr =.s_byte              ;status
;
;
;   status register bits...
;
.sr_car  =@00000001            ;C — carry
.sr_bdm  =@00001000            ;D — decimal
.sr_irq  =@00000100            ;I — IRQ
.sr_neg  =@10000000            ;N — result negative
.sr_ovl  =@01000000            ;V — sign overflow
.sr_zer  =@00000010            ;Z — result zero
.sr_amw  =@00100000            ;m — accumulator/memory size
.sr_ixw  =@00010000            ;x — index sizes
;
;
;   stack definitions...
;
.sfbase  .= 1                  ;base stack index
.sfidx   .= .sfbase            ;workspace index
;
;—————————> workspace stack frame start <—————————
.nchar   =.sfidx               ;chars to shift
.sfidx   .= .sfidx+.s_word
.s1len   =.sfidx               ;STRING1's length
.sfidx   .= .sfidx+.s_word
;—————————> workspace stack frame end <—————————
;
.s_wsf   =.sfidx-.sfbase       ;stack workspace size
.sfbase  .= .sfidx
;
;—————————> register stack frame start <—————————
.reg_c   =.sfidx               ;.C
.sfidx   .= .sfidx+.s_word
.reg_x   =.sfidx               ;.X
.sfidx   .= .sfidx+.s_word
.reg_y   =.sfidx               ;.Y
.sfidx   .= .sfidx+.s_word
.reg_db  =.sfidx               ;DB
.sfidx   .= .sfidx+.s_mpudb
.reg_sr  =.sfidx               ;SR
.sfidx   .= .sfidx+.s_mpusr
.reg_pc  =.sfidx               ;PC
.sfidx   .= .sfidx+.s_mpupc
;—————————> register stack frame end <—————————
;
.s_rsf   =.sfidx-.sfbase       ;register stack frame size
.sfbase  .= .sfidx
;
;—————————> parameter stack frame start <—————————
.s1ptr    =.sfidx              ;STRING1's pointer
.sfidx   .= .sfidx+.s_word
.s2ptr    =.sfidx              ;STRING2's pointer
.sfidx   .= .sfidx+.s_word
.iptr    =.sfidx               ;index pointer
.sfidx   .= .sfidx+.s_word
.nptr    =.sfidx               ;number of chars pointer
.sfidx   .= .sfidx+.s_word
;—————————> parameter stack frame end <—————————
;
.s_psf   =.sfidx-.sfbase       ;parameter stack frame size
;
;
;   error flags...
;
.er_bol  =.sr_zer              ;bank span
.er_idx  =.sr_ovl              ;index range
.er_stl  =.sr_neg              ;string length
.er_bits =.er_bol|.er_idx|.er_stl ;mask
;—————————————————————————————————————————————————————————

Within STRSUB, any parameter is accessible by using its positional definition (e.g., .S2PTR) as an argument to a stack relative instruction, e.g., LDA (.S2PTR,S),Y. How would DP addressing help in this instance? I have indexed indirect addressing available in stack relative, as I do with DP.

An alternative to stack relative addressing would be to capture the entry stack pointer, which would be pointing to the stack location immediately below the return address, add .S_WSF + .S_RSF bytes to it and copy that value to the MPU's DP register—DP would also have to be pushed so it can be restored upon exit. That would cause DP to point to the start of the function parameter stack frame. Subsequently, access to any parameter could be made via DP indexed indirect addressing, e.g., LDA $00,X. However, it really doesn't gain all that much over using stack pointer relative addressing, since the same addressing modes that would be most useful (and most used) are available either way. After all, the function parameters are pointers, so indirect addressing is required, requiring that pointer arithmetic be used if addressing through an ephemeral DP.

During development of my 65C816 string library, I found it easiest to define local workspace on the stack, as shown above. This approach eliminated the use of DP entirely and all that that entails.

Something else to consider is that unless the ephemeral DP location exactly falls on a page boundary (i.e., $xx00), the speed advantage of DP addressing is lost and indexed indirect addressing would actually be slower than stack pointer relative.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 6 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 7 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: