Login
Back to forumReply to this topicGo to last reply

Posted By

JamesD
on 2017-12-04
18:32:29
 Does the Plus/4 support some form of VARPTR() command?

I wanted to embed some machine code in a BASIC string and discovered that VARPTR doesn't appear to be a function. Is it called something else on the Plus/4 or is it not supported at all?

Posted By

SVS
on 2017-12-05
06:31:57
 Re: Does the Plus/4 support some form of VARPTR() command?

It is not supported. Since the variables are created and stored in the same order the interpreter manages them reading the source, the Basic itself performs all the times a scan inside the whole variable area to search for one. (A Basic trick is to declare a frequently-used variable in the first lines in order to speed up the search).

Posted By

JamesC
on 2017-12-05
07:15:12
 Re: Does the Plus/4 support some form of VARPTR() command?

SVS is correct, there is no Commodore BASIC equivalent to VARPTR.

Please expand on your idea of embedding "machine code in a BASIC string", as I am not sure what you want to do.

Interpretation 1: hiding a machine-language routine in MY$. If you know the location of MY$ in memory, you can SYS to that location and execute the machine-language routine. (This is how I read your request.)

Interpretation 2: passing MY$ to a machine-language routine stored elsewhere in memory. (This appears to be the purpose of VARPTR in Microsoft BASIC.)

Once we understand what you want to do, we can find another way to accomplish it. happy

Posted By

bubis
on 2017-12-05
18:51:46
 Re: Does the Plus/4 support some form of VARPTR() command?

What's the goal here? Do you want to pass on parameters?

Posted By

JamesD
on 2017-12-05
21:14:22
 Re: Does the Plus/4 support some form of VARPTR() command?

On other versions of Microsoft BASIC you can do this...
I have adapted if for the Plus/4 but i don't know if the variable descriptor is the same format as other machines.
The address of the variable is assumed to be in little endian format.


0 ML$="012345678901234567890123456789012345678901234567890123456789"
10 'Never put any other line ahead of that line
20 'define other variables here
30 V=VARPTR(ML$ : ;Get address of the ML$ variable descriptor
40 Z=PEEK(V+1)+256*PEEK(V+2) : 'Get address of ML$ contents
50 FOR I=0 TO 39
60 READ D:POKE Z+I,D : 'Overwrite bytes of string with machine code
70 NEXT I
80 POKE1281,PEEK(V+1):POKE1282,PEEK(V+2) : 'Point USR() to address of ML$ using variable descriptor data
90 ' Note that PEEK(V) would give us the length of ML$

100 ' rest of program goes here
110 ' to call machine language subroutine just call USR() function

10000 DATA machine language program bytes go here


In other versions of Microsoft BASIC, ML$ actually points to where the string is stored in line 0 until you modify it. So as long as you don't use any string functions to modify it, it is located at a fixed address.
This lets you assemble some code to execute at that address. Your code is limited by the maximum line length, but it's very handy for a small function.

The real advantage here, is that once you run the program, you can delete the code that reads the data and the lines with the data statements, then save the program and it will contain your USR function on load.
If you list the program, BASIC barfs out garbage for the first line (which you should never edit), but it does no harm.

I used this in high school to embed a reverse screen scroll in an application I wrote. The program let the user scroll up and down through data and it made BASIC look almost like it was written in machine code without compiling it.

Here I wanted to embed a patch to make basic only use RAM that doesn't have to be paged in and out as well as the routines used to access it so it would run much faster. It would be handy for smaller programs.

*edit*
I can probably do the same thing by directly loading the binary from a file into the address the string is at, but I'll have to use a debugger to find the address it resides at.
And yes, SYS would work here. The machines I'm used to require using USR().
But I'd have to hard code the address in this case.

FWIW, on CPUs that support relocatable code, the string doesn't have to always reside at the very start of the program.

*edit*
The string resides at $0CCF.

Posted By

JamesC
on 2017-12-06
00:56:56
 Re: Does the Plus/4 support some form of VARPTR() command?

Alright, let's not reinvent the wheel. We can do this with a very minor change.

1. Start your program with an 88-characters-long REM (two full screen lines plus 8 characters of the 3rd line):

10 REM1234567890123456789012345678901234567890123456789012345678901234567890123456789012

2. If your program resides in normal BASIC space, then it starts at $1000 (4096). Add 6 to get the address of the first '1' in Line 10. In this example, it is at 4102.

3. READ your data (up to 82 bytes), then POKE it directly into the REM statement. Same idea as the ML$ in Microsoft BASIC.

20 FOR I = 0 TO 81 : READ D : POKE 4102 + I, D
30 NEXT D
40 (program continues here)

4. Commodore BASIC does not allow us to DELETE lines while a program is running. But once the data is POKEd into the REM statement, you can DELETE the FOR-READ-POKE-NEXT lines and the DATA statements while in immediate mode (when the program is NOT running):

DELETE 20 - 30 (the FOR-NEXT loop)
DELETE 10000 - 10020 (the DATA statements)

5. AND THEN SAVE THE PROGRAM. This will give you a program with your machine language routine ALREADY IN THE REM STATEMENT, which saves you from READing and POKEing every time you load and run it! happy

DSAVE "MY PROGRAM.BAS"

6. Within your program, anytime you want to execute your machine-language routine, simply SYS 4102. happy




Posted By

JamesD
on 2017-12-06
02:15:02
 Re: Does the Plus/4 support some form of VARPTR() command?

I already have it working the other way, but REM takes less space so I switched it.
When I first found the address of the string, I found it printed on the screen from when I typed LIST.
It was kinda funny to see the program poked into screen RAM.
I immediately knew what I messed up. LOL


I already knew about DELETE etc... I planned on just typing it at the command line.
Actually, you could probably insert STOP on a line right after the code that POKEs it in RAM.
Then DELETE those lines before continuing.

Posted By

Csabo
on 2017-12-06
08:45:44
 Re: Does the Plus/4 support some form of VARPTR() command?

Cool, you guys said it all, except this one minor detail - which I think is worth mentioning: the code cannot contain a $00 byte, since that will break the BASIC interpreter. This is usually not a big deal though and can be worked around easily. (E.g. instead of LDX#$00, one can write LDX#$01/DEX, or just re-work how that loop works, etc.)

Posted By

JamesC
on 2017-12-11
09:25:44
 Re: Does the Plus/4 support some form of VARPTR() command?

Csabo - JamesD noted a similar risk of BASIC going haywire when LISTing the program, once the ML has been POKEd, from his experience with Microsoft BASIC.

JamesD - If you want to save a bit more effort, write Line 10 with the REM statement, then hop into MONITOR and write your ML starting at $1006. This saves you from changing your ML back to decimal values, writing DATA lines to hold the decimal values, and READ-POKEing them into Line 10.

But as far as your original question (how to POKE ML into a BASIC line) ... I'm happy that this worked for you. Apologies if I was a little wordy in how to do it, but I wanted to be thorough in case someone else stumbles upon this thread a few months (or a year or more) from now. happy

Posted By

JamesD
on 2017-12-06
12:09:20
 Re: Does the Plus/4 support some form of VARPTR() command?

As for $00 breaking the interpreter, that is just treated as a line terminator.
The pointer to the next line will still have the original address.
The only risk is that BASIC will try to compress the program and will overwrite the code starting after $00 with the next line of BASIC.



*edit*
Here is the patch for CHRGOT, and the benchmark code that prompted it's creation
My patch for CHRGOT speeds up the benchmark by about 4%.
Technically, once the patch is installed, all these lines can be deleted until the machine is reset.
This does nothing to prevent a program from extending until part of it is below ROM, so don't try to use it with large programs or the system will crash miserably.

CHRGOT patch:

0 REM012345678901234567890123456789012
5 A=4102:FORI=0 TO 30:READ T:POKE A+I,T :NEXT I:SYS A

10000 DATA 160,18,185,18,16,153,121,4,136,16,247,96
10010 DATA 160,0,177,59,201,58,144,1,96,233,47,201
10020 DATA 240,240,235,56,233,208,96



Benchmark code:

10 K=0:I=0:T=0:P=0
30 SCNCLR
100 PRINT "Prime Number Generator"
110 INPUT "Upper Limit";N

120 eTime=TIME
130 T=(N-3)/2
140 DIMA(T+1)

160 FORI=0TOT:A(I)=0:NEXT
200 FORI=0TOT:IFA(I)THENPRINT"..";:NEXT:GOTO330
210P=I+I+3:PRINTP;".";:K=I+P:IFK<=TTHENFORK=KTOTSTEPP:A(K)=1:NEXT:NEXT:GOTO330
260 NEXT

330 eTime=(TIME-eTime)/60
340 PRINT
350 PRINT "Total: ";eTime
360 END



Additional code to disable/enable screen for more speed.

115 POKE65286,PEEK(65286)AND239
335 POKE65286,PEEK(65286)OR16


Related thread on Atariage.com:

http://atariage.com/forums/topic/272023-basic-interpreter-speed-comparison-prime-number-generation/

Posted By

Csabo
on 2017-12-06
12:38:09
 Re: Does the Plus/4 support some form of VARPTR() command?

Meh, okay, I just wanted to bring it to your attention in case you didn't know about it, but apparently you do.

It does break things, you can even try with your own example. In the above post; the part marked "CHRGOT patch:", 5 lines of code. Run it, then try to type this: 6 ?"hello":end, then RUN 6.

Posted By

JamesD
on 2017-12-06
13:38:00
 Re: Does the Plus/4 support some form of VARPTR() command?

You have to delete lines 0 and 5 after the first time you run the code. The patch is already installed at that point.

The embedded code in line zero causes the interpreter to barf.
The interpreter doesn't jump to the next line using the next line pointer stored at the start of a line, it seeks the 0 at the end of the line and assumes the next line starts after it.
I forgot about that. I ran into that bit of stupidity when I patched the MC-10's BASIC.
Saving the next line pointer would make the interpreter faster and that was one of the optimizations I worked on.

Posted By

Csabo
on 2017-12-06
14:26:34
 Re: Does the Plus/4 support some form of VARPTR() command?

"You have to delete lines 0 and 5 after the first time you run the code." Then why on earth would you POKE your code into the BASIC in the first place? o_O

Posted By

JamesD
on 2017-12-06
15:09:52
 Re: Does the Plus/4 support some form of VARPTR() command?

If I change it so there are no zeros, that won't be a problem.
Why do you care so much anyway?

Posted By

Csabo
on 2017-12-06
16:39:14
 Re: Does the Plus/4 support some form of VARPTR() command?

OK, that's cool then.

I guess I must have misunderstood the whole point. To sum it up: If one wants to keep ML code in a BASIC line, while the BASIC program is running, then this is all good, just avoid zeros. If one does NOT want to keep the ML code, just POKE it to any other free memory area and avoid the whole issue.

Posted By

JamesD
on 2017-12-07
00:12:22
 Re: Does the Plus/4 support some form of VARPTR() command?

well, the idea here was that the patch could automatically load without having to POKE it into memory every time you run the program. I have a fix but it's got a bug I have to track down before posting it.

It's only about a 4% speedup on the benchmark, so it's not earth shattering, but every little bit helps.

*edit*
Found my bug... I used decimal math instead of hex to set the address to patch to $00. Du-Oh!

This fixes the code so you don't have to delete line 0.
Just delete line 1 and the lines with data statements after the first time you run your program and save it.
Then every time you run it, the patch will be installed without having to POKE the patch into memory.
Please remember that any program that exceeds the size of available RAM that isn't paged in and out with ROM will break.
This makes no attempt to patch the code used to access variables or system variables indicating what RAM is available.

Just an FYI, the first DATA line contains the code that installs the patch.
The other two lines are the actual replacement code for CHRGOT.
The 2nd number in the CHRGOT code shows 01, but it's actually supposed to be 0.
That was what caused the need to delete the original code after running it the first time.


0 REM012345678901234567890123456789012345
1 FORI=0 TO 35:READ T:POKE 4102+I,T :NEXT I
2 SYS 4102

10000 DATA 160,18,185,23,16,153,121,4,136,16,247,200,152,153,122,4,96
10010 DATA 160,01,177,59,201,58,144,1,96,233,47,201
10020 DATA 240,240,235,56,233,208,96


Posted By

Csabo
on 2017-12-07
09:52:54
 Re: Does the Plus/4 support some form of VARPTR() command?

Nicely done!

Still, it's easier to just POKE it to any free unused location, right? It's one less line.

1 FORI=0 TO 35:READ T:POKE 291+I,T :NEXT I
2 SYS 291

10000 DATA 160,18,185,52,1,153,121,4,136,16,247,200,152,153,122,4,96
10010 DATA 160,01,177,59,201,58,144,1,96,233,47,201
10020 DATA 240,240,235,56,233,208,96

Posted By

Mad
on 2017-12-07
13:36:20
 Re: Does the Plus/4 support some form of VARPTR() command?

I am not sure about this. But for me it seems, that this code from CHRGOT/CHRGET:

SEC ; prepare subtraction ...
SBC #$30 ; Petscii "0"
SEC ; now invert carry... (letters are >=0)
SBC #$D0 ; subtraction retour, lesser "0", Carry-Flag=1
RTS ; Zero-Flag=1 end of instruction, Carry-Flag=1 no digit

could be replaced by a slightly faster version..

this takes 8 cycles without the rts

perhaps it can be replaced with this:


cmp #$30 ; 2 cycles
bcc invertcarry ; 2 cycles if >= $30, 3 cycles if < $30
cmp #$ff ; set carry to 0 and zero flag to 0 (bytes should not be $ff); 2 cycles
rts ; 6 cycles here
invertcarry:
cmp #$00 ; 2 + (2+3) cycles; carry is now 1 and zero flag is only 1 if a zero byte was encountered (like above)
rts ; 7 cycles here


I don't know if it's an improvement perhaps it's not worth the hussle anyways.. I hope I did not make a mistake there..

Have fun! happy

p.s.: Seems a $ff cannot occur there because of a bcs directly before:
CMP #$3A ; ":" (colon)
BCS L8143 ; if colon, exit

edit: i think you can rewrite the routine like this, sparing some more bytes and gain some performance:
edit2: perhaps it's not a good idea to use this version here below. The cmp #$3a comes later in the code path, so most probably it's slower in most cases, the version above should be cool anyways.

LDY #$00
LDA (LastBasicLineNo),y ; $3b
CMP #$20 ; " " (space)
BEQ $0473 ; if space, get NEXT byte from basic
cmp #$30 ; 2 cycles
bcc invertcarry ; 2 cycles if >= $30, 3 cycles if < $30
cmp #$3a ; set carry to 0 and zero flag to 0 (if not $3a, if below $3a then the >=$3a procedure from the old code is processed here); 2 cycles
rts ; 6 cycles here
invertcarry:
cmp #$00 ; 2 + (2+3) cycles; carry is now 1 and zero flag is only 1 if a zero byte was encountered (like above)
rts ; 7 cycles here

so the $3a call is also included in this.. I hope it works.. It's just a quick guess at optimizing it..

Just some thoughts... Don't take this to serious!

Posted By

JamesD
on 2017-12-07
15:24:48
 Re: Does the Plus/4 support some form of VARPTR() command?

Still, it's easier to just POKE it to any free unused location, right? It's one less line.

But it has to POKE it into RAM every time the code is loaded after startup, and that requires the data statements.

Once you've loaded it into the REM, you don't need the data statements or the loop that pokes the code into memory. Yeah, the SYS call is made every time you execute the code but that's so fast it really doesn't matter.
You could attach the resulting line 0 and SYS call to any program small enough to meet the memory limits that need a little speed boost. The REM line plus SYS call only takes around 52 bytes.

You do have to perform a hard reset to restore the original CHRGOT code, but that could also be done with a SYS call when you exit a program.

If there is empty space in the ROM, the patch could be placed there and the default USR function address could point to it. Then programs could just add USR(0) to the first line. Or they could just use SYS with the address of the patch routine in ROM.

FWIW, the CHRGOT code is designed to exit with the most likely type of byte to be found without taking any jumps. This saves a clock cycle for every byte it finds meeting the requirements and that doesn't even count the other tests that are skipped in the process.
At least that's the theory behind it. I haven't performed any tests to confirm that assumption.

Posted By

Mad
on 2017-12-08
00:21:11
 Re: Does the Plus/4 support some form of VARPTR() command?

Haha nice! Now at home. Looked at the machine code of your data lines. It's even more optimized. Seems the original version somehow wasn't a extremely big deal for you. Good one. ( There was some code posted in another thread here in the forum from an older version of this which looked somehow improvable to me, sorry (I didn't look at the routine as a whole, your version is cool this way.)! happy ) Sorry for spamming your thread.

edit: I couldn't stop.. :/ it was just too tempting to continue with this.. I measured it first with the REM approach, but Csabos approach is better for actually comparing two different routines. In both cases this slightly "optimized" routine was a little faster. But your routine already is ace anyways! I think some people more into this can squeeze even more out of this (illegal opcodes and so on).

This one is slightly faster (0.36% in my test cases with your benchmark.bas and csabos poke to somewhere on the stack)

ldy #$00
lda ($3b),y
cmp #$3a
bcc .do
rts
.do
cmp #$30
bcs .digit
cmp #$20
beq $100c
cmp #$00
rts
.digit
cmp #$ff
rts

5 A=291:FORI=0 TO 34:READ T:POKE A+I,T :NEXT I:SYS A

10000 DATA 160,26,185,47,1,153,121,4,136,16,247,96
10010 DATA 160,0,177,59,201,58,144,1,96,201,48,176
10020 DATA 7,201,32,240,233,201,0,96,201,255,96


The best site for me for cycle counting is this one: http://www.oxyron.de/html/opcodes02.html there you can see all the opcodes with the number of cycles they take in a nice diagram. I know you already have your own cycle measurements but this one is really good and handy for it..

All the best.. And keep rocking.. :)

And yes, you asked for the VARPTR command.. :/ The idea with improving the CHRGET is ultranice anyways. Perhaps there are other routines which also can be patched in order to gain more speed..

Posted By

JamesD
on 2017-12-08
00:54:16
 Re: Does the Plus/4 support some form of VARPTR() command?

just an FYI, run it several times each way when you test it.
I get slightly different results from one run to the next depending on when the code is stared.
I'm not sure if it's related to the length of clock tic, when the screen is updated, or both.

Posted By

Mad
on 2017-12-08
05:10:34
 Re: Does the Plus/4 support some form of VARPTR() command?

Yes i tried this already.. happy Most probably it's the starting and ending time which is not aligned with the timer irq. I am no specialist on how the basic timers are implemented on plus/4, though.. I think your assumption is right.

If you use an emulator you can use fast forward and a big number of iterations. That should work out more precise, atleast in the theory.

Posted By

KiCHY
on 2017-12-08
05:47:38
 Re: Does the Plus/4 support some form of VARPTR() command?

Perhaps you can wait until TI$ changes, then set to "000000" and start measuring.

10 MT$=TI$
20 DO UNTIL MT$<>TI$:LOOP
30 TI$="000000"

Posted By

JamesD
on 2017-12-08
19:54:11
 Re: Does the Plus/4 support some form of VARPTR() command?

I honestly didn't do any cycle counting.
Most of the speedup was due to dumping the paging and handling the most likely case first so I left it at that.
The first version was more of a proof of concept to get it working and see if it was worth further effort.

As for the .36% improvement, I think the ultimate goal is providing the most speed possible, but that's not going to make much difference on the benchmarks. Dropping a second or two when setting the prime limit to 20000 isn't going to impress anyone. Especially when the Plus/4 is still turning in dismal numbers compared to several machines.

There is definitely room for further optimization. There is a function that immediately follows this in RAM that gets bytes under ROM. If we patch the memory pointers BASIC uses to keep track of where free memory is, we can patch the the function that gets bytes under ROM. It should provide a similar speedup, though I'm hoping it's more.

The math library uses floating point registers in low memory already, but the code that copies values to and from those registers is probably where the greatest inefficiency is. Since writes to addresses in the ROM range automatically go to RAM already, it's the reads that are the issue.
If BASIC reads 1 byte at a time, it's no wonder the interpreter is so slow. If it has a function that moves a full floating point value at a time, then we won't see as much of a speedup. Topping a combined 10% while still running BASIC out of ROM would definitely be worth the effort Especially if all we have to do is copy some bytes. But I'm not sure if the patch would still fit in a single REM.

The limiting factor here is ultimately the ROM. Rewrite that so it directly accesses RAM instead of through the intermediate RAM functions and you dump JSR, SEI, STA, LDA, CLI RTS for RAM accesses.


*edit*
The faster version of the patch was good for 1 second on Ahl's Benchmark. Just defining variables at the top was good for for more.
But that spends a lot of time performing floating point operations.

Posted By

JamesC
on 2017-12-11
09:47:24
 Re: Does the Plus/4 support some form of VARPTR() command?

If you are trying to benchmark in a way that others can rely on and replicate (basic Scientific Method stuff from high school), then consider copying ROM to RAM and then paging ROM out.

This allows you to either overwrite unwanted code, or insert jumps to patches elsewhere in the system ... and any other Plus/4 owner, or anyone running an emulator, can replicate your results without modifying their own setup.

Though I don't know how fair it is to benchmark the Plus/4 against other computers. Benchmarking against another Commodore 8-bit is fine, benchmarking against other 1MHz-ish CPUs is fine. But once you start optimizing the test system's OS, then someone running on a different CPU should be allowed to optimize their OS too ... which would skew the benchmarks, they are no longer a fair and reliable comparison.

Just my two cents, feel free to ignore. happy

Posted By

JamesD
on 2017-12-11
22:19:42
 Re: Does the Plus/4 support some form of VARPTR() command?

I really don't see there being any demand for a new ROM that wouldn't run all existing BASIC programs, so coping ROM to RAM or loading a new ROM into RAM is the most logical solution. It's not like BASIC would be using that RAM anyway. I don't see myself making a heavily modified ROM like I did for the MC-10. At the most just make a handful of patches. That wouldn't justify a new ROM.

FWIW, I grew up with a Tandy CoCo... we were copying ROM to RAM to modify it even before the C64 existed. I remember doing it for something when I was in high school, but I have no idea what it was.
On the CoCo it might actually make sense to burn a new ROM since it can run code out of the ROM address range faster than RAM, but it's the only machine I know of with that capability.

*edit*

I tested exiting if it was a digit instead of branching, but it was slower than the first approach.


0 REM01234567890123456789012345678901234567890123
1 FORI=0 TO 42:READ T:POKE 4102+I,T :NEXT I
2 SYS 4102


10000 DATA160,22,185,26,16,153,121,4,136,16,247,200,152,153,122,4,153,142,4,96
10010 DATA160,01,177,59,201,58,144,1,96,201,48,144,3,201,255,96,201,32,240
10020 DATA 230,201,1,96

*edit*
Actually, that turned in identical times to the first version once lines 1, 2, and the DATA lines are deleted after the first run.


For additional speed improvements, each of these addresses need patched with the code shown, and at the very least, the end of RAM value needs patched.

0497 LDA ($43),Y
RTS
04A5 LDA ($3B),Y
RTS
04B0 LDA ($22),Y
RTS
04BB LDA ($24),Y
RTS
04C6 LDA ($6F),Y
RTS
04D1 LDA ($5F),Y
RTS
04DC LDA ($64),Y
RTS

Patch end of RAM?
LDX #$FF
LDY #$7F
JSR $FF99 ; MEMTOP'


Posted By

JamesC
on 2017-12-12
13:40:54
 Re: Does the Plus/4 support some form of VARPTR() command?

If you absolutely NEED a little more space in your REM statement, we can find it. wink

You could also assemble your changes into a cartridge ROM (as opposed to replacing BASIC and Kernal ROMS). The emulator version would be a .crt file, loaded into the emulator configuration as though it were an add-on cartridge. This is how 3-plus-1 on Key F1 works.



Posted By

KiCHY
on 2017-12-12
14:52:06
 Re: Does the Plus/4 support some form of VARPTR() command?

Instead of patching this:
0497 LDA ($43),Y
0499 RTS

you should patch all "JSR $0497" (3 bytes) to
Lda ($43), Y ; 2 bytes
NOP ; 1 bytes

This way you save a JSR call. And this is naturally true for all the other similar subroutines. I also did this in that hacked ROM.

Posted By

JamesD
on 2017-12-13
01:45:52
 Re: Does the Plus/4 support some form of VARPTR() command?

Actually, I had something else in mind.

I'd have stub routines call a piece of code that patches the ROM like that.
The stubs would do something like this:
LDA #address ; load A with address normally used by LDA (address),Y
JMP PATCHER ; call the patcher


And the patcher would do something like this, but itprobably needs work as I've been using a lot of Motorola assembly lately. If the code is only called from a handful of places, it's overkill. But if it's called all over the place, it would be the fastest way to patch everything.

STA #temp ; save page zero address to use
LDY #0 ; zero y
PLA ; get LSB of return address
SBC #3 ; subtract 3 (point to address of JSR)
STA RETURNADDRESS ; store it in our own page 0 pointer
PLA ; get MSB of return address
BCC NEXT ; deal with carry from MSB
DEC
NEXT:
PHA ; restore it onto the stack
STA RETURNADDRESS+1 ; save it in our pointer
LDA #OPCODE4LDA(),Y ; load the opcode we want to patch with
STA (RETURNADDRESS),Y ; patch BASIC
INY ; next address
LDA TEMP ; get the address that was passed to us
STA (RETURNADDRESS),Y ; patch BASIC
INY ; next address
LDA #OPCODE4NOP ; NOP to finish the patch
STA (RETURNADDRESS),Y ; patch it
LDA RETURNADDRESS ; get LSB of JSR
PHA ; push it to the stack
RTS ; call the patched code



Back to topReply to this topic


Copyright © Plus/4 World Team, 2001-2024. Support Plus/4 World on Patreon