00 C0 20 9E AD 20 A3 B6 A8 88 A9 05 4A 90 02 49 B1 71 22 88 10 F6 29 1F C9 07
B0 02 69 0D A8 BE 32 C0 B9 1E C0 4C CD BD 00 00 00 00 03 00 0A 00 06 10 01 00
FF 00 02 00 00 00 00 00 08 00 15 0D DB 02 18 90 3D 55 79 05 FF E9 62 22 01 59
01 37 FF 03
This uses hashing (of course), but optimized for short implementation on the 6502, taking advantage of the carry flag set by shifting and used in addition. Magic numbers for hashing were found by brute forcing with a little C program; the FF
bytes are unfortunate holes in the hash table ;)
Byte count: 2 bytes load address, 38 bytes code, 42 bytes hashtable for values.
Usage: SYS49152"[ordinal]"
, for example SYS49152"DUODECIMUS"
. (note the letters appear upper case in the default C64 configuration).
Important: Before the first start, issue a NEW
command. This is needed because the C64 BASIC LOAD
command fiddles with some BASIC vectors, even when loading a machine program to some absolute address (like here $C000
/49152
).
Commented disassembly:
00 C0 ; load address
.C:c000 20 9E AD JSR $AD9E ; evaluate expression
.C:c003 20 A3 B6 JSR $B6A3 ; evaluate as string
.C:c006 A8 TAY ; length to y register
.C:c007 88 DEY ; decrement (start at last char)
.C:c008 A9 05 LDA #$05 ; start value for hash
.C:c00a .hashloop:
.C:c00a 4A LSR A ; shift right
.C:c00b 90 02 BCC .skip ; shifted bit zero? -> skip xor
.C:c00d 49 B1 EOR #$B1 ; xor "magic" value
.C:c00f .skip:
.C:c00f 71 22 ADC ($22),Y ; add current character (plus carry)
.C:c011 88 DEY ; previous character
.C:c012 10 F6 BPL .hashloop ; pos >= 0? -> repeat
.C:c014 29 1F AND #$1F ; mask lowest 5 bits
.C:c016 C9 07 CMP #$07 ; larger than 7 ?
.C:c018 B0 02 BCS .output ; -> to output
.C:c01a 69 0D ADC #$0D ; add 13
.C:c01c .output:
.C:c01c A8 TAY ; hash to y register
.C:c01d BE 32 C0 LDX .lb-8,Y ; load low byte from hashtable
.C:c020 B9 1E C0 LDA .hb-8,Y ; load high byte from hashtable
.C:c023 4C CD BD JMP $BDCD ; to output of 16bit number
.C:c026 .hb:
.C:c026 00 00 00 00 .BYTE $00,$00,$00,$00
.C:c02a 03 00 0A 00 .BYTE $03,$00,$0A,$00
.C:c02e 06 10 01 00 .BYTE $06,$10,$01,$00
.C:c032 FF 00 02 00 .BYTE $FF,$00,$02,$00
.C:c036 00 00 00 00 .BYTE $00,$00,$00,$00
.C:c03a .lb:
.C:c03a 08 00 15 0D .BYTE $08,$00,$15,$0D ; second byte used in .hb as well
.C:c03e DB 02 18 90 .BYTE $DB,$02,$18,$90
.C:c042 3D 55 79 05 .BYTE $3D,$55,$79,$05
.C:c046 FF E9 62 22 .BYTE $FF,$E9,$62,$22
.C:c04a 01 59 01 37 .BYTE $01,$59,$01,$37
.C:c04e FF 03 .BYTE $FF,$03
C64 BASIC V2 test suite
(containing the machine program in DATA
lines)
0fOa=49152to49231:rEb:pOa,b:nE
1?"primus",:sY49152"primus":?
2?"secundus",:sY49152"secundus":?
3?"tertius",:sY49152"tertius":?
4?"quartus",:sY49152"quartus":?
5?"quintus",:sY49152"quintus":?
6?"sextus",:sY49152"sextus":?
7?"septimus",:sY49152"septimus":?
8?"octavus",:sY49152"octavus":?
9?"nonus",:sY49152"nonus":?
10?"decimus",:sY49152"decimus":?
11?"undecimus",:sY49152"undecimus":?
12?"duodecimus",:sY49152"duodecimus":?
13?"tertius decimus",:sY49152"tertius decimus":?
14?"quartus decimus",:sY49152"quartus decimus":?
15?"quintus decimus",:sY49152"quintus decimus":?
16?"sextus decimus",:sY49152"sextus decimus":?
17?"septimus decimus",:sY49152"septimus decimus":?
18?"duodevicesimus",:sY49152"duodevicesimus":?
19?"undevicesimus",:sY49152"undevicesimus":?
20?"vicesimus",:sY49152"vicesimus":?
21dA32,158,173,32,163,182,168,136,169,5,74,144,2,73,177,113,34,136,16,246,41,31
22dA201,7,176,2,105,13,168,190,50,192,185,30,192,76,205,189,0,0,0,0,3,0,10,0,6
23dA16,1,0,255,0,2,0,0,0,0,0,8,0,21,13,219,2,24,144,61,85,121,5,255,233,98,34,1
24dA89,1,55,255,3