ROM calls and other tricks

Basic and Machine Language

Moderator: Moderators

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

Post by Mike »

Small routines for saving and loading blocks of memory:

SAVE memory block:

Code: Select all

SYS57809(N$),8,1:POKE193,start_lo:POKE194,start_hi
POKE780,193:POKE781,end_lo:POKE782,end_hi:SYS65496
'start' is inclusive, 'end' is exclusive. 'N$' contains the file name. Other device numbers than 8 can be used (also 1 for tape), but the additional ',1' must be kept.

LOAD memory block:

Code: Select all

SYS57809(N$),8,1:POKE780,0:SYS65493
Loads the file 'N$' to its correct address without restarting the BASIC program.

Michael

Edit: Removed unnecessary POKE147,0 instruction in LOAD memory block.
Last edited by Mike on Fri Mar 13, 2009 5:08 pm, edited 1 time in total.
carlsson
Class of '6502
Posts: 5516
Joined: Wed Mar 10, 2004 1:41 am

Post by carlsson »

Cool. Although I assume everyone who have ventured into machine code programming already knows, the addresses 780-783 transport the values of accumulator (A), X and Y registers and finally the status (flags) register. It is common parameter passing from Basic to ML routines.
Anders Carlsson

Image Image Image Image Image
carlsson
Class of '6502
Posts: 5516
Joined: Wed Mar 10, 2004 1:41 am

Post by carlsson »

On the topic of loading, here are another few calls that are not useful for programming, but for .. eh, getting the most out of tape files, if you see what I mean.

SYS 63407 = Reads from tape until the header of a program is found
SYS 62980 = Reads the rest of the program

It means after the first call, one can modify the contents of the tape buffer to make the program load into another address (prevent auto start etc) and then check what the program does.

I found these calls from a computer magazine in 1990, telling its readers how to hack C64 tapes (or rather, "find hidden messages"). On the C64, the SYSes are 63276 and 62828, so slightly different position than on the VIC.
Anders Carlsson

Image Image Image Image Image
carlsson
Class of '6502
Posts: 5516
Joined: Wed Mar 10, 2004 1:41 am

Post by carlsson »

Hm. For some of these calls marked by (A/Y), it seems A contains the high byte and Y the low byte, while it should be the opposite according to my source. This applies in particular to $D391, but possibly to many other routines. I never observed this before, but it is worth checking if a call doesn't give the expected result to change order of the parameters.
Anders Carlsson

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

Recovering from a tape ?LOAD ERROR

Post by Mike »

Often enough it happened to me, that I stripped off the end of a program saved on tape, because I started the SAVE too early on the tape. This destroys the copy, but the original is often untouched. Still, it causes a ?LOAD ERROR. You then can't RUN the program, because the pointers (45/46) haven't been set.

You can recover these pointers (and your program, and your state of mind) in that case with:

Code: Select all

POKE 45,PEEK(174):POKE 46,PEEK(175):CLR
Michael

P.S.: You can use VERIFY to search for the end of a program on tape.
User avatar
Schlowski
NoMess!
Posts: 892
Joined: Tue Jun 08, 2004 12:20 pm

Post by Schlowski »

Is there any (easy) possibility to save a certain area of RAM with another load address?
Saving $1000-$1800 with load address $1C00 for example.
Boray
Musical Smurf
Posts: 4064
Joined: Mon May 03, 2004 10:47 am

Post by Boray »

Schlowski wrote:Is there any (easy) possibility to save a certain area of RAM with another load address?
Saving $1000-$1800 with load address $1C00 for example.
You should be able to just open a sequencial file, save two address bytes and then save the rest of the data. Also check this: http://sleepingelephant.com/ipw-web/bul ... php?t=1270
PRG Starter - a VICE helper / Vic Software (Boray Gammon, SD2IEC music player, Vic Disk Menu, Tribbles, Mega Omega, How Many 8K etc.)
User avatar
Schlowski
NoMess!
Posts: 892
Joined: Tue Jun 08, 2004 12:20 pm

Post by Schlowski »

Ah, I knew there was something like that and I read it, but I couldn't find it anymore.
Thanks, I will have a look at it and try it.
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

BASIC auto-tokenizer for SEQ files

Post by Mike »

If the listing in charge doesn't have any control-characters inside (as it's the case here) you can 'type in' the listing as follows, provided you have VICE available:

1. Copy and paste the listing from your browser into your favorite editor. Make sure it saves with carriage returns (i.e. ASCII 13).
2. Save it to the VICE main directory, i.e. as 'text.txt'
3. Start xvic, and drag the file into the VICE main window.

This needs some explanation: the file is still ASCII, and will not work. But dragging the file into the main window is the easiest way to mount the surrounding directory as drive.

4. Do a hard-reset (Ctrl-Alt-R).
5. Type in this program (you should save it for later uses):

Code: Select all

63996 POKE812,238:OPEN2,8,2,"TEXT.TXT,P,R"
63997 PRINT"{CLR}";:IFST<>0THENPOKE812,239:CLOSE2:END
63998 GET#2,A$:PRINTA$;:IFA$<>CHR$(13)THEN63998
63999 PRINT"GOTO63997":POKE631,19:POKE632,13:POKE633,13:POKE198,3
6. RUN this program. It will type in 'TEXT.TXT' for you.
7. delete lines 63996 to 63999.
8. done. You can now mount a *.d64 file as usual, and save the program as real *.prg file.

One point to note are the POKE812,x commands. They disable the CLALL vector at the start, and re-enable it, when the program finishes. Otherwise the channel would be closed upon entering a new line.

The tokenizer (of course) also works with SEQ files. In that case the ',P,R' inside the OPEN commands must be replaced with ',S,R'. Finally, it can be used to reverse the effect of PETSCII LIST output to a file with:

Code: Select all

OPEN2,8,2,"TEXT,S,W":CMD2:LIST
PRINT#2:CLOSE2
except that the final 'READY.' will either lead to an '?OUT OF DATA' or '?SYNTAX' error. Just type in another 'GOTO63997' + RETURN to finish the process correctly (i.e. with restoring the CLALL vector, and closing channel #2).

Michael
Last edited by Mike on Tue Jan 13, 2009 1:33 am, edited 2 times in total.
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

A replacement for INPUT#, especially useable for reading records in REL files. Here's an example.

Greetings,

Michael

Code: Select all

*=$033c

; REL file READ RECORD written 2008 by Michael Kircher

; writing a record into a REL file with PRINT# is okay, but reading it
; back with INPUT# is a bit of a nuisance, since INPUT# is restricted to
; 88 (on the 64: 80) chars, and also barfs at anything unexpected, like
; commas, quotes, and colons.

; this pair of routines reads in a complete record up to (but not including)
; the terminating CR, and assigns it to a string, without any those problems.

; - if the USR vector is not at 828, lower RAMTOP with POKE56,PEEK(56)-1:CLR
; - prepare Z$ once: Z$="I'M 17 CHARS LONG":Z$=Z$+Z$+Z$+Z$+Z$:Z$=Z$+Z$+Z$
; - POKE the following code to address 828
; - set up the USR vector with: POKE1,60:POKE2,3

; INPUT#channel,R$ is now replaced by: R$=LEFT$(Z$,USR(channel)):SYS873,R$

; which calls ...
.GetLine
 JSR $D7F7       ; FAC#1 to Integer in $14/$15
 LDA $15
 BNE GetLine_02  ; sec. address >= 256 -> error
 LDX $14
 JSR $E11B       ; CHKIN for channel in $14
 LDY #$00
 STY $FE         ; reset buffer pointer
.GetLine_00
 JSR $E10F       ; CHRIN
 CMP #$0D
 BEQ GetLine_01  ; exit loop, if CR
 LDY $FE
 STA ($37),Y     ; store into buffer
 INY
 STY $FE
 CPY #$FF        ; maximum length reached?
 BNE GetLine_00  ; no
.GetLine_01
 JSR $FFCC       ; restore I/O
 LDY $FE
 JMP $D3A2       ; return string length in FAC#1
.GetLine_02
 JMP $D248       ; flag error

; ... and is completed with:
.Assign
 JSR $CEFD       ; check for ','
 JSR $D08B       ; get variable address
 STA $14         ; which is the descriptor
 STY $15         ; for a string
 LDY #$00
 LDA ($14),Y
 PHA             ; push length
 INY
 LDA ($14),Y
 PHA             ; push low byte
 INY
 LDA ($14),Y
 STA $15         ; store high byte
 PLA
 STA $14         ; store low byte
 PLA
 STA $FE         ; store length
 LDY #$00
.Assign_00
 CPY $FE
 BEQ Assign_01
 LDA ($37),Y     ; copy from buffer to string
 STA ($14),Y
 INY
 BNE Assign_00
.Assign_01
 RTS             ; scary, but it works.
User avatar
Ghislain
Realms of Quest
Posts: 1279
Joined: Sun Aug 08, 2004 12:54 am

Post by Ghislain »

To do < = > you can do the following:

JSR $DC5B ;compare floating point pointed to by A:Y with FAC1; if FAC1=mem then A=0, if FAC1<mem then A=255, if FAC1>mem then A=1

Source:

http://www.experts-exchange.com/Program ... 19228.html

(which refers to BC5B in the C64 BASIC ROM, but the VIC-20 location for this is DC5B)
"A slave is one who waits for someone to come and free him." -- Ezra Pound
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Coding small time-delays

Post by Mike »

This small sub-routine may be useful for coding a small time delay up to 4 seconds:

Code: Select all

.Delay
 LDA $A2
 STA $FB
.Delay_00
 SEC
 LDA $A2
 SBC $FB
 CMP #xx
 BCC Delay_00
 RTS
... where xx gives the delay in 1/60 seconds, and $FB could also be another free (ZP) address. There's a small inaccuracy of up to 1/60 second, depending on whether the jiffy-clock has been updated right before, or is after the first LDA $A2 - but this shouldn't be important, if a delay of half a second (xx=30) or more is specified.
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

CHRIN patch sub-routine

Post by Mike »

Normally, CHRIN is supposed to set the C flag when that operation didn't succeed. However, I found with serial transfers the routine would always return with C cleared. But at least the status byte ST at $90 is set correctly, and I designed this patch sub-routine to get the desired behaviour:

Code: Select all

.GetByte
 JSR $FFCF ; call CHRIN
 PHA
 LDA $90
 CMP #$01  ; set C, if ST >= 1 (i.e. ST != 0)
 PLA       ; restore Accu, keep C flag, and set Z flag, if A=0
 RTS
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

PRIMM

Post by Mike »

I just dug this out from the depths of my HD:

It's a small (30 bytes) and relocatable PRIMM routine. The data loader below allows the ZP address be freely chosen, where PRIMM keeps the pointer to the next char to be printed:

Code: Select all

1 AD=673:ZP=251
2 FORT=0TO29:READA
3 IFA<0THENA=ZP-A-1
4 POKEAD+T,A:NEXT
5 :
6 DATA 104,133,-1,104,133,-2,230,-1,208,2,230,-2,160,0,177
7 DATA -1,240,5,32,210,255,144,239,165,-2,72,165,-1,72,96
The routine does not bother to stack the registers. Here's the source code:

Code: Select all

.Primm
 PLA
 STA zp
 PLA
 STA zp+1
.Primm_00
 INC zp
 BNE Primm_01
 INC zp+1
.Primm_01
 LDY #0
 LDA (zp),Y
 BEQ Primm_02
 JSR $FFD2
 BCC Primm_00 
.Primm_02
 LDA zp+1
 PHA
 LDA zp
 PHA
 RTS
User avatar
Wilson
Vic 20 Enthusiast
Posts: 190
Joined: Mon Sep 28, 2009 7:19 am
Location: Brooklyn, NY

Post by Wilson »

$E5BB (58811): The KERNAL's routine to initialize the VIC registers ($9000-$900F)
$E5B5 (58805): Sets the cursor to the home position and calls $E5BB.
Post Reply