summaryrefslogtreecommitdiff
path: root/tests/examplefiles/ca65_example
blob: 67c6313e668d538ef03e9d07e65f89e3425fa012 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
;--------------------------------------
; Lychrel numbers.
; 
; :author: Marc 'BlackJack' Rintsch
; :date: 2008-03-07
; :version: 0.1
; 
; Prints all `Lychrel numbers`_ between 1 and 100000.
; 
; The numbers are stored as array of "digits" in little endian
; order.  Each digit is a byte with a value between 0 and 9.
; 
; Runtime on C64: 00:21:01
; 
; .. _Lychrel numbers: http://en.wikipedia.org/wiki/Lychrel_number
; 
; .. cl65 -l -tnone -C simple.cfg lychrel.s -o lychrel.prg
;--------------------------------------

;--------------------------------------
; External addresses.
;--------------------------------------
	chrout	= $ffd2

;--------------------------------------
; Constants.
;--------------------------------------
	TO		= 100000
	TO_DIGITS	= 10
	ITERATIONS	= 100
	MAX_DIGITS	= TO_DIGITS + ITERATIONS

;--------------------------------------
; Global variables.
;--------------------------------------
.zeropage
; 
; Length of the currently tested `n` in digits.
; 
n_length:
	.res 1
; 
; Length of the number(s) `xa` and `xb` while testing.
; 
length:
	.res 1

.bss
; 
; Number to be tested as digits i.e. bytes with values between
; 0 and 9.  The length is stored in `n_length`.
; 
n:
	.res TO_DIGITS
; 
; Space for calculating the reversed and added values.
; In the `main` code the current number is copied into `xa`
; and then repeatedly `reverse_add`\ed to itself with the
; result of that adding stored in `xb`.
; 
xa:
	.res MAX_DIGITS
xb:
	.res MAX_DIGITS

;--------------------------------------
; BASIC header.
;--------------------------------------
.code
	.word 0800h		; Load address.
	.byte 0
	.word @line_end
	.word 2008		; Line number.
	.byte $9e		; SYS token.
	.byte "2080 "		; SYS argument.
	.byte "LYCHREL NUMBERS/BJ"
@line_end:
	.byte 0, 0, 0		; Line and program end marker.

;--------------------------------------
; Main program.
;--------------------------------------
.proc main

.zeropage
; 
; Three byte counter for `TO` iterations (100000 = $0186a0).
; 
i:
	.res 3

.code
; 
; Clear and set `n` and `i` to 1.
; 
	lda #0		; n := 0; n := 1; i := 1
	sta i+1
	sta i+2
	ldx #TO_DIGITS
clear_n:
	sta n-1,x
	dex
	bne clear_n
	inx
	stx i
	stx n
	stx n_length
	
mainloop:
	jsr is_lychrel
	bcc no_lychrel
	jsr print_n
no_lychrel:
	jsr increase_n
	
	inc i		; INC(i)
	bne skip
	inc i+1
	bne skip
	inc i+2
skip:
	lda i
	cmp #<TO
	bne mainloop
	lda i+1
	cmp #>TO
	bne mainloop
	lda i+2
	cmp #^TO
	bne mainloop
	
	rts
.endproc

;--------------------------------------
; Print `n` and a trailing newline.
;
; :in: `n_length`, `n`
;--------------------------------------
.proc print_n
	ldy n_length
L1:
	lda n-1,y
	ora #%110000    ; = '0'
	jsr chrout
	dey
	bne L1
	
	lda #13
	jmp chrout
.endproc

;--------------------------------------
; Increase `n` by one.
; 
; This procedure expects n[n_length] == 0 in case the number gets
; one digit longer.
; 
; :in: `n`, `n_length`
; :out: `n`, `n_length`
;--------------------------------------
.proc increase_n
	ldx #0
L1:
	inc n,x		; Increase digit.
	lda n,x
	cmp #10		; If "carry", store 0 and go to next digit.
	bne return
	lda #0
	sta n,x
	inx
	bne L1
return:
	cpx n_length	; If "carry" after last digit, increase length.
	bcc skip
	inc n_length
skip:
	rts
.endproc

;--------------------------------------
; Tests if `n` is a Lychrel number.
; 
; :in: `n`, `n_length`
; :out: C is set if yes, cleared otherwise.
; :uses: `length`, `xa`, `xb`
;--------------------------------------
.proc is_lychrel
.zeropage
i:
	.res 1

.code
	ldx n_length		; xa := n; length := n_length
	stx length
L1:
	lda n-1,x
	sta xa-1,x
	dex
	bne L1
	
	lda #ITERATIONS		; i := ITERATIONS
	sta i
L2:
	jsr reverse_add
	jsr is_palindrome
	bne no_palindrome
	clc
	rts
no_palindrome:
	ldx length		; a := b
L3:
	lda xb-1,x
	sta xa-1,x
	dex
	bne L3
	
	dec i			; Loop body end.
	bne L2
	
	sec
	rts
.endproc

;--------------------------------------
; Add the reverse to `xa` to itself and store the result in `xb`.
; 
; :in: `length`, `xa`
; :out: `length`, `xb`
;--------------------------------------
.proc reverse_add
.code
	ldx #0
	ldy length
	clc
L1:
	lda xa,x
	adc xa-1,y
	
	cmp #10
	bcc no_adjust
	sbc #10
no_adjust:
	sta xb,x
	
	dey
	inx
	txa		; ``eor`` instead of ``cpx`` to keep the carry flag
	eor length	; of the addition above.
	bne L1
	
	bcc no_carry
	lda #1
	sta xb,x
	inc length
no_carry:
	rts
.endproc

;--------------------------------------
; Checks if `xb` is a palindrome.
; 
; :in: `length`, `xb`
; :out: Z flag set if `xb` is a palindrome, cleared otherwise.
;--------------------------------------
.proc is_palindrome
.code
	ldx #0
	lda length
	tay
	lsr
	sta L1+1	; Self modifying code!
L1:
	cpx #0		; <<< 0 replaced by (`length` / 2).
	beq return
	lda xb,x
	cmp xb-1,y
	bne return
	dey
	inx
	bne L1
return:
	rts
.endproc