ML design patterns (calling ROM subroutines)

Basic and Machine Language

Moderator: Moderators

User avatar
toby405
Vic 20 Amateur
Posts: 40
Joined: Fri Dec 21, 2012 8:33 pm
Location: USA

ML design patterns (calling ROM subroutines)

Postby toby405 » Wed Dec 13, 2017 10:48 am

Code: Select all

        ldx #8
LOOP    ldy #1
        jsr $d3a2               ; y -> FAC
        jsr $e094               ; rnd()
        jsr $d1aa               ; FAC -> a, y
        jsr USEFULSR            ; do something useful with a, y
        dex
        bne LOOP

This code doesn't work because the subroutines change X.

Are there cases where you take the trouble to figure out if a particular ROM subroutine leaves your register untouched so you can save a few bytes or is it better to just always do something like this:

Code: Select all

        lda #8
        sta $fb
LOOP    ldy #1
        jsr $d3a2               ; y -> FAC
        jsr $e094               ; rnd()
        jsr $d1aa               ; FAC -> a, y
        jsr USEFULSR            ; do something useful with a, y
        dec $fb
        bne LOOP

User avatar
Mike
Herr VC
Posts: 3078
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: ML design patterns (calling ROM subroutines)

Postby Mike » Wed Dec 13, 2017 11:45 am

As a rule of thumb, you can assume that most routines in the BASIC interpreter and KERNAL thrash all registers. Inthusfar, holding state in uncommitted RAM space is a quite common find for 65xx routines.

For the routines in the KERNAL called by the jump table, their use of registers is well documented. In the other cases you'd need to infer this information from the available (documented) assembly listings. That also applies if you go and write replacements for the OS routines (for example, when you want to write a BASIC extension) - the surrounding/calling routines make strict assumptions about the side-effects in the registers, the flag register and memory that you have to get right first.

User avatar
srowe
Vic 20 Nerd
Posts: 510
Joined: Mon Jun 16, 2014 3:19 pm

Re: ML design patterns (calling ROM subroutines)

Postby srowe » Wed Dec 13, 2017 12:47 pm

For timing-critical code, yes, I've traced though the source code and/or run a test in VICE and used the monitor to check for register clobbering. You sometimes have to do the same for zero page locations.

CurtisP
Vic 20 Dabbler
Posts: 80
Joined: Tue Mar 08, 2005 8:24 pm

Re: ML design patterns (calling ROM subroutines)

Postby CurtisP » Sat Dec 16, 2017 9:03 pm

With the rare exception of customized ROMs to fix bugs, I think you can assume that every VIC 20 is going to have the exact same Basic ROM.

So if you want to save those few bytes, I don't see a problem with tracking the register usage.

I'm just not sure it's always worth the trouble.

User avatar
Mike
Herr VC
Posts: 3078
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: ML design patterns (calling ROM subroutines)

Postby Mike » Sun Dec 17, 2017 3:22 am

Yes and No to that.

CurtisP wrote:With the rare exception of customized ROMs to fix bugs, I think you can assume that every VIC 20 is going to have the exact same Basic ROM.

When I wrote my last post here in this thread, I did not refer to that other project, where I exchanged the BASIC ROM in my VIC-20.

Rather, I pointed to some 'standards' a wedge in the BASIC interpreter has to honor with regard to register usage, flag register usage, RAM usage and other side effects. Any such wedge should in principle behave as if it wasn't there, and from that point on carefully nudge the BASIC interpreter into doing a slightly different, but intended action.

Sadly enough, that's not the case with the USR() function you posted in another thread. You surely don't want a function to print out something during expression evaluation. The Right Thing™ would have been to return a string with the hex data.

So if you want to save those few bytes, I don't see a problem with tracking the register usage.

I'm just not sure it's always worth the trouble.

For the bug-fix I made myself exactly that trouble to make sure the replacement routine returns with exactly the same register and flag values than the original. What's different now is, that the result in FAC#1 is now correct in all cases. I did this without shuffling around code, which would have broken lots of programs. Rather, I just diverted a single jump to the (sometimes malfunctioning) routine that shifts the mantissa one whole byte, and provided a replacement in some otherwise unused space of the ROM.

CurtisP
Vic 20 Dabbler
Posts: 80
Joined: Tue Mar 08, 2005 8:24 pm

Re: ML design patterns (calling ROM subroutines)

Postby CurtisP » Sun Dec 17, 2017 3:34 pm

Mike wrote:Rather, I pointed to some 'standards' a wedge in the BASIC interpreter has to honor with regard to register usage, flag register usage, RAM usage and other side effects. Any such wedge should in principle behave as if it wasn't there, and from that point on carefully nudge the BASIC interpreter into doing a slightly different, but intended action.

Sadly enough, that's not the case with the USR() function you posted in another thread. You surely don't want a function to print out something during expression evaluation. The Right Thing™ would have been to return a string with the hex data.

I entirely agree about wedges, but a USR() function isn't quite the same as a wedge though. It's specifically designed to execute arbitrary code. And this particular code is not intended to be used inside an expression. Sometimes you just need a quick hack, and doing The Right Thing™ is more trouble than it's worth.

User avatar
Mike
Herr VC
Posts: 3078
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: ML design patterns (calling ROM subroutines)

Postby Mike » Sun Dec 17, 2017 5:04 pm

CurtisP wrote:a USR() function [is] specifically designed to execute arbitrary code. And this particular code is not intended to be used inside an expression.

I wholeheartedly disagree with that.

USR() gets called during expression evaluation, it receives a parameter in FAC#1, likewise it is expected to return a result in FAC#1.

You are misusing USR() to make side effects not expected during expression evaluation. If you want to execute arbitrary code, use SYS for that.

wimoos
Vic 20 Devotee
Posts: 248
Joined: Tue Apr 14, 2009 8:15 am
Website: http://wimbasic.webs.com
Location: Netherlands
Occupation: farmer

Re: ML design patterns (calling ROM subroutines)

Postby wimoos » Mon Dec 18, 2017 2:04 am

Refer to http://sleepingelephant.com/ipw-web/bulletin/bb/viewtopic.php?f=2&t=676&start=15#p68669 for a collection of interesting facts on interpreter subroutines. I found and used these during my development efforts on the WimBasic extension.

Also, Lee's well-document disassembly listing on https://www.mdawson.net/vic20chrome/vic20/docs/kernel_disassembly.txt is a good help.
VICE; selfwritten 65asmgen; tasm; maintainer of WimBasic


Return to “Programming”

Who is online

Users browsing this forum: Bing [Bot] and 1 guest