ROM calls and other tricks

Basic and Machine Language

Moderator: Moderators

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

Comparing two registers

Post by Mike »

Normally, comparing two registers would involve (usually a zero-page) temporary:

Code: Select all

 STA aa
 CPX aa
... which does a "CPX A" or "CXA" (as in: calculate X-A, discard the result, and just reflect the result in the flags).

If you don't want to "spoil" a ZP address, but OTOH can afford a 1 byte longer and self-modifying code, the store instruction can instead write to the operand field of a CMP/CPX/CPY #imm instruction that follows:

Code: Select all

 STA compare+1
.compare
 CPX #$00
This also takes the same number of cycles (4+2 vs. 3+3) than the zp-temporary version.
User avatar
Mike
Herr VC
Posts: 4888
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Divide 16-bit value by 8-bit constant

Post by Mike »

During a WIP, I (re-)discovered this handy routine to do an unsigned division of a 16-bit value by an 8-bit constant:

Code: Select all

 LDA #0
 LDX #16
.loop
 ASL zp
 ROL zp+1
 ROL A
 BCS subtract
 CMP #xx
 BCC skip
.subtract
 SBC #xx
 INC zp
.skip
 DEX
 BNE loop
zp and zp+1 contain the 16-bit value to be divided, and the result afterwards. The 8-bit divisor constant is encoded in the immediate fields of CMP #xx and SBC #xx. The remainder ends up in the Accumulator.

Of course, for divisors that are powers of 2, shifting/masking is shorter and faster. :)

The routine includes the bugfix suggested by J.E.E.K. for divisors >= $80 (see discussion). Constant divisors < $80 can omit the two lines "BCS subtract" and ".subtract".
User avatar
R'zo
Vic 20 Nerd
Posts: 514
Joined: Fri Jan 16, 2015 11:48 pm

Re: SAVEing and LOADing memory blocks

Post by R'zo »

Mike wrote:SAVE memory block:

Code: Select all

SYS57809(N$),<device>:POKE193,<start_lo>:POKE194,<start_hi>
POKE780,193:POKE781,<end_lo>:POKE782,<end_hi>:SYS65496
[...]
Is there any way to scratch or overwrite these files? Specifically using string input from user for the filename.
Last edited by Mike on Sat Jun 13, 2020 12:31 pm, edited 1 time in total.
Reason: quote shortened - please refer to the original post in the thread here for details
R'zo
I do not believe in obsolete...
User avatar
Mike
Herr VC
Posts: 4888
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: SAVEing and LOADing memory blocks

Post by Mike »

R'zo wrote:Is there any way to scratch or overwrite these files? Specifically using string input from user for the filename.
You'd use the standard CBM DOS commands for this, e.g.:

OPEN15,8,15,"S0:"+N$:CLOSE15

deletes file N$ on disk.

You should *not* use the save-and-replace variant of the filename, i.e. prepend "@" or "@0:", as the implementation of this function is bugged on many 15xx disk drives and can corrupt the disk contents.
User avatar
Mike
Herr VC
Posts: 4888
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

BIT #imm using the VIC-20 BASIC ROM

Post by Mike »

Hi, y'all!

As yet another follow-up to a discussion concerning the BIT instruction I wrote this small program to find the first occurence of each byte value in the VIC-20 BASIC ROM:

Code: Select all

1 DIMS(255):R=49152:FORT=0TO8191:A=PEEK(R+T):IFS(A)=0THENS(A)=R+T
2 NEXT:OPEN2,8,2,"BIT.TXT,S,W":FORA=0TO255:B=A:GOSUB4:P$="$"+H$:B=INT(S(A)/256):GOSUB4
3 P$=P$+"  $"+H$:B=S(A)-256*B:GOSUB4:P$=P$+H$:PRINT#2,P$:NEXT:CLOSE2:END
4 H$="":P=INT(B/16):GOSUB5:P=B-16*P
5 H$=H$+CHR$(48+P-7*(P>9)):RETURN
This now allows to rewrite a BIT #imm instruction (which is not available on the NMOS 6502!) as BIT ABS instruction pointing into the BASIC ROM. The BIT instruction sets the Z flag corresponding to the AND result (and N, V directly from bits 7 and 6 of the tested address), but leaves the accumulator unaltered, which allows to perform several bit tests on a given value in A without the necessity to restore A in-between!

The most interesting values are probably the powers of 2, they're given here:

Code: Select all

$01  $C390
$02  $C39B
$04  $C3E7
$08  $C3B9
$10  $C338
$20  $C1A1
$40  $CB5A
$80  $C018
The whole list comprises:

Code: Select all

$00  $C058
$01  $C390
$02  $C39B
$03  $C3A0
$04  $C3E7
$05  $C01A
$06  $C42D
$07  $C3A8
$08  $C3B9
$09  $C414
$0A  $C377
$0B  $C06C
$0C  $C634
$0D  $C06E
$0E  $C35C
$0F  $C563
$10  $C338
$11  $C08A
$12  $C3B3
$13  $C44D
$14  $C50E
$15  $C09C
$16  $C67D
$17  $C572
$18  $C3B1
$19  $C67B
$1A  $C85A
$1B  $C9C5
$1C  $C024
$1D  $C010
$1E  $C35E
$1F  $C620
$20  $C1A1
$21  $C395
$22  $C3C5
$23  $C03A
$24  $C360
$25  $C33A
$26  $C048
$27  $C022
$28  $C40B
$29  $C459
$2A  $C087
$2B  $C534
$2C  $C030
$2D  $C4B0
$2E  $C02C
$2F  $C670
$30  $C00C
$31  $C3BC
$32  $C3BE
$33  $C40F
$34  $C409
$35  $C33C
$36  $C5D2
$37  $C07E
$38  $C3BF
$39  $C052
$3A  $C02A
$3B  $C33E
$3C  $C5A9
$3D  $C7BB
$3E  $C3FD
$3F  $C59D
$40  $CB5A
$41  $C008
$42  $C005
$43  $C004
$44  $C0A8
$45  $C09E
$46  $C092
$47  $C0C1
$48  $C136
$49  $C00A
$4A  $C02E
$4B  $C0FC
$4C  $C0BE
$4D  $C006
$4E  $C09F
$4F  $C0A2
$50  $C08F
$51  $C160
$52  $C034
$53  $C009
$54  $C0AA
$55  $C0AF
$56  $C040
$57  $C0E5
$58  $C056
$59  $C118
$5A  $C098
$5B  $C3C8
$5C  $DBC8
$5D  $C044
$5E  $CAB4
$5F  $C3C3
$60  $C3B7
$61  $C036
$62  $C77D
$63  $CA17
$64  $C032
$65  $C072
$66  $C779
$67  $C002
$68  $C068
$69  $C081
$6A  $C344
$6B  $C49D
$6C  $C437
$6D  $CE78
$6E  $CE7B
$6F  $CA5E
$70  $C020
$71  $C05E
$72  $C346
$73  $C48B
$74  $C715
$75  $CA57
$76  $C475
$77  $CDE0
$78  $C000
$79  $C080
$7A  $C04E
$7B  $C086
$7C  $C070
$7D  $C05A
$7E  $CA2A
$7F  $C03C
$80  $C018
$81  $C393
$82  $C026
$83  $C362
$84  $C3BD
$85  $C046
$86  $C486
$87  $CAC0
$88  $C3EC
$89  $C92F
$8A  $C3B0
$8B  $C076
$8C  $C514
$8D  $C511
$8E  $C65A
$8F  $CFAE
$90  $C34A
$91  $C3EA
$92  $D3EB
$93  $D377
$94  $C060
$95  $C422
$96  $DF1C
$97  $C881
$98  $C3CD
$99  $C5A1
$9A  $C683
$9B  $C042
$9C  $DF31
$9D  $C34C
$9E  $C05C
$9F  $C01E
$A0  $C389
$A1  $CEAC
$A2  $C413
$A3  $C0B1
$A4  $C014
$A5  $C396
$A6  $C57C
$A7  $C933
$A8  $C12C
$A9  $C44A
$AA  $C142
$AB  $C140
$AC  $C32A
$AD  $C074
$AE  $C7EB
$AF  $C143
$B0  $C3D7
$B1  $C06A
$B2  $C038
$B3  $C096
$B4  $C603
$B5  $C32C
$B6  $D51B
$B7  $CBDE
$B8  $C50B
$B9  $C522
$BA  $C04A
$BB  $C93F
$BC  $C14C
$BD  $C14B
$BE  $C016
$BF  $C9C8
$C0  $C5BE
$C1  $C0AB
$C2  $C0D5
$C3  $C04C
$C4  $C0A0
$C5  $C0D0
$C6  $C043
$C7  $C00F
$C8  $C00D
$C9  $C01D
$CA  $C03D
$CB  $C015
$CC  $C01B
$CD  $C011
$CE  $C09A
$CF  $C091
$D0  $C019
$D1  $C028
$D2  $C0A3
$D3  $C039
$D4  $C073
$D5  $C354
$D6  $C079
$D7  $C071
$D8  $C031
$D9  $C063
$DA  $C088
$DB  $C08B
$DC  $C053
$DD  $C3A4
$DE  $C144
$DF  $C05F
$E0  $C061
$E1  $C033
$E2  $C067
$E3  $C001
$E4  $C003
$E5  $C093
$E6  $C4E6
$E7  $C661
$E8  $C090
$E9  $C5D4
$EA  $C062
$EB  $CFDC
$EC  $C078
$ED  $C064
$EE  $C968
$EF  $C95D
$F0  $C334
$F1  $C4BA
$F2  $C3F9
$F3  $C925
$F4  $C461
$F5  $C5C0
$F6  $D0B9
$F7  $C012
$F8  $C529
$F9  $C3EE
$FA  $C41B
$FB  $C548
$FC  $C523
$FD  $C60A
$FE  $C512
$FF  $C336
$00 is probably not that useful, but has been included for completeness. :wink:

PAL and NTSC VIC-20s share the same BASIC ROM, so this method works for both types of VIC-20s. The list is also valid for the bug-fixed BASIC ROM that I devised a few years ago (see here).

Greetings,

Michael

(mod: follow-up discussion split off into own thread.)
User avatar
J.E.E.K.
Vic 20 Drifter
Posts: 23
Joined: Wed Jan 25, 2017 12:31 pm
Website: http://klasek.at/8bit
Location: AT

Re: ML Optimization tips and tricks

Post by J.E.E.K. »

wimoos wrote: Wed Dec 12, 2012 4:27 amRemove NOP’s
[...]
This list could be extended by
  • Hold flag in bit 7 of a location, so you can check the flag by "BIT flag" followed by "BMI/BPL destination" keeping A untouched, clear the flag with "LSR flag". If carry is set by an condition before, use "ROR flag" to set the flag.
  • Operations without temporarily save the accumulator to memory:
    • To subtract the value in A from location's value ( (mem)-A ) use EOR #$FF; SEC; ADC mem (negate A with two's complement and simply add).
    • Merge some bits from A into a memory location using EOR mem; AND #mask_bits_taken_from_acc; EOR mem; STA mem.
Last edited by Mike on Sat Oct 24, 2020 2:34 pm, edited 1 time in total.
Reason: (near) full-quote shortened. Please refer to the OP by following the blue arrow link.
User avatar
bjonte
Vic 20 Hobbyist
Posts: 110
Joined: Sun Jan 22, 2017 5:47 am
Location: Gothenburg

Handy toggle

Post by bjonte »

Sometimes you want to toggle a memory location between two values. This can be done using EOR. The value to use for EOR can be constructed with eor in the assembler (operator ^ in this example).

Code: Select all

// constants to toggle between
const value1 = 55
const value2 = 170

// set initial value
lda #value1
sta memaddr

// toggle
lda memaddr
eor #value1 ^ value2
sta memaddr
User avatar
MrSterlingBS
Vic 20 Enthusiast
Posts: 195
Joined: Tue Jan 31, 2023 2:56 am
Location: Germany,Braunschweig

Re: ROM calls and other tricks

Post by MrSterlingBS »

Sometimes I used

STY $ZP
… some code
LDY $ZP

instead of
TYA
PHA
… some code
PLA
TAY

A little bit faster and shorter code if you have some ZP registers free.
wimoos
Vic 20 Afficionado
Posts: 352
Joined: Tue Apr 14, 2009 8:15 am
Website: http://wimbasic.webs.com
Location: Netherlands
Occupation: farmer

Re: Handy toggle

Post by wimoos »

bjonte wrote: Mon Jul 04, 2022 2:34 pm Sometimes you want to toggle a memory location between two values. This can be done using EOR. The value to use for EOR can be constructed with eor in the assembler (operator ^ in this example)

To elaborate on this, consider the following code snippet that I used in WimBasic:

Code: Select all

	EOR  #$82      	 ; token NEXT ?
	BEQ  LA3D6     	 
	EOR  #$9C ^ $82  ; token CLR
	BEQ  LA3F3     	 
	EOR  #$8E ^ $9C  ; token RETURN
	BEQ  LA46C     	 
	JMP  $CF08 ; ?SYNTAX ERROR
;
LA3D6	TAY ; clear Y
		...
		
LA46C	
The code is entered with a tokenized value in A, that needs to be checked against three possible values. The code, following the selection benefits from having a value of zero in A (or could benefit from the carry-flag not having been changed).

Regards,

Wim.
VICE; selfwritten 65asmgen; tasm; maintainer of WimBasic
Post Reply