-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.a
1108 lines (930 loc) · 30.7 KB
/
main.a
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
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
!to "mandelbr.prg", cbm
!cpu 65c02
;TESTS = 1
;ITER_COUNT = 1
*=$0801
!byte $0c,$08,$e6,$07,$9e,$20,$32,$30,$36,$32,$00,$00,$00
RES_X = 320
RES_Y = 240
MAX_ZOOM_LEVEL = 16
KEY_DO_ZOOM = $87
KEY_DO_SAVE = $88
ITER_DEFAULT = 24
ENTRY_POINT
jmp progStart
!source "zeropage.a"
!zone arith
!source "arith16.a"
!source "arith32.a"
!zone string
!source "string.a"
; The emulator has to be started with the -rtc option for
; these routines to work
!zone rtc
!source "rtc.a"
!zone disk_io
!source "disk_io.a"
!zone vera
!source "vera.a"
!source "memory.a"
!zone main
!source "mandelhelp.a"
; **************************************************
; The following 6 values have to be contiguously laid out
; in memory. The load and save routines expect this.
; x offset to move in complex plane for next point
STEP_X
!byte 0, $66, $66, $02, $00
; Y offset to move in complex plane for next line of picture
STEP_Y
!byte 1, $11, $71, $02, $00
; real part of upper left point of picture
INIT_REAL
!byte 1, 0, 0, 0, 2
; imaginary part of upper left point of picture
INIT_IMAG
!byte 0, 0, 0, $25, 1
ZOOM_LEVEL
!byte 0
; maximum number of iterations
MAX_ITER
!byte ITER_DEFAULT
; **************************************************
!ifdef ITER_COUNT {
ITER_CTR
!byte 0, 0, 0, 0, 0
CONST_UINT_ONE
!byte 0, 1, 0, 0, 0
TXT_ITERATIONS
!byte 18
!tx "ITERATIONS : $"
}
; Number of points (resolution) in x direction
MAX_X
!byte <RES_X, >RES_X
; Number of points (resolution) in y direction
MAX_Y
!byte RES_Y
; current X position
COUNT_X
!byte 0, 0
; current y position
COUNT_Y
!byte 0
TIMESTAMP_CALC_START
!byte 0, 0, 0
TIMESTAMP_CALC_END
!byte 0, 0, 0
; --------------------------------------------------
; variables used for calculation
; --------------------------------------------------
; The number of iterations used for the current point
NUM_ITER
!byte 0
REAL
!byte 0,2,0,0,0
IMAG
!byte 0,3,0,0,0
XN
!byte 0,0,0,0,0
YN
!byte 0,0,0,0,0
XN_OLD
!byte 0,0,0,0,0
TEMP_MAX
!byte 0,0,0,0,0
YN_SQUARE
!byte 0,0,0,0,0
XN_SQUARE
!byte 0,0,0,0,0
; --------------------------------------------------
; constants
; --------------------------------------------------
; The fixed value 4. When a sequence's value is greater or equal to this number
; the sequence defined by the current point diverges
VAL_MAX
!byte 0,0,0,0,4
; x offset to move in complex plane default picture (full resolution)
DEFAULT_STEP_X
!byte 0, $66, $66, $02, $00
; Y offset to move in complex plane for next line of default picture
DEFAULT_STEP_Y
!byte 1, $11, $71, $02, $00
; real part of upper left point of default picture
DEFAULT_INIT_REAL
!byte 1, 0, 0, 0, 2
; imaginary part of upper left point of picture default picture
DEFAULT_INIT_IMAG
!byte 0, 0, 0, $25, 1
; **************************************************
!zone main
; --------------------------------------------------
; This routine test if calculation of the Mandelbrot sequence should be stopped.
; It is stopped, when the iteration count reached MAX_ITER of the absolute value
; of the current sequence value is larger than 4
;
; This routine returns a nonzero value if computation has to be stopped. The zero
; flag is cleared in this case.
; --------------------------------------------------
testMandelbrotDone
lda NUM_ITER
cmp MAX_ITER
bne .testLimit
jmp .stopCalc
.testLimit
; *****************************
; abs_val = xn*xn + yn*yn
; *****************************
; XN_SQUARE <= XN
+move32BitInline XN, XN_SQUARE
; XN_SQUARE <= XN_SQUARE * XN_SQUARE
+callFuncMono square32BitNormalized, XN_SQUARE
; YN_SQUARE <= YN
+move32BitInline YN, YN_SQUARE
; YN_SQUARE <= YN_SQUARE * YN_SQUARE
+callFuncMono square32BitNormalized, YN_SQUARE
; TEMP_MAX <= XN_SQUARE
+move32BitInline XN_SQUARE, TEMP_MAX
; TEMP_MAX <= YN_SQUARE + TEMP_MAX
+callFunc add32Bit, YN_SQUARE, TEMP_MAX
; Stop if TEMP_MAX > 4
; continue if TEMP_MAX <= 4
; Carry is set if TEMP_MAX >= 4
; Zero flag is set if TEMP_MAX == 4
+callFunc cmp32BitUnsigned, TEMP_MAX, VAL_MAX
bcs .greaterPerhapsEqual
.continueCalc ; TEMP_MAX < 4
lda #0
rts
.greaterPerhapsEqual ; TEMP_MAX >= 4
beq .continueCalc ; TEMP_MAX == 4? => If yes continue
.stopCalc
lda #1 ; TEMP_MAX > 4 => Stop
rts
; --------------------------------------------------
; This routine calculates the Mandelbrot sequence for the complex value given through
; REAL und IMAG.
;
; The number of iterations performed is returned in NUM_ITER
; --------------------------------------------------
calcOneMandelbrotSequence
lda #1
sta NUM_ITER
; REAL <= XN
+callFunc move32Bit, REAL, XN
; YN <= IMAG
+callFunc move32Bit, IMAG, YN
.loopMandelbrot
!ifdef ITER_COUNT {
+callFunc add32BitUnsigned, CONST_UINT_ONE, ITER_CTR
}
jsr testMandelbrotDone
beq .continueMandelbrot
jmp .endMandelbrot
.continueMandelbrot
; XN_OLD <= XN
+move32BitInline XN, XN_OLD
; *****************************
; xn+1 = xn*xn - yn*yn + real
; *****************************
; XN <= XN_SQUARE
+move32BitInline XN_SQUARE, XN
; YN_SQUARE <= -YN_SQUARE
+neg32Inline YN_SQUARE
; XN <= YN_SQUARE + XN
+callFunc add32Bit, YN_SQUARE, XN
; XN <= REAL + XN
+callFunc add32Bit, REAL, XN
; *****************************
; yn+1 = 2*xn*yn + imag
; *****************************
; YN <= XN_OLD * YN
+callFunc mul32BitNormalized, XN_OLD, YN
; YN <= 2*YN
+callFuncMono double32Bit, YN
; YN <= IMAG + YN
+callFunc add32Bit, IMAG, YN
inc NUM_ITER
jmp .loopMandelbrot
.endMandelbrot
rts
; --------------------------------------------------
; This routine initialises the data needed for computation
;
; initMandel has no return value.
; --------------------------------------------------
initMandel
+load16BitImmediate 0, COUNT_X
lda #0
sta COUNT_Y
!ifdef ITER_COUNT {
+callFuncMono clear32Bit, ITER_CTR
}
; reset complex numbers
+callFunc move32Bit, INIT_REAL, REAL
+callFunc move32Bit, INIT_IMAG, IMAG
rts
; --------------------------------------------------
; This routine performs all necessary calculations for one point in the
; complex plane. Calling this routine repeatedly calculates and draws the
; selected rectangular part of the Mandelbrot set. If COUNT_Y reaches 240
; all pixels have been drawn.
;
; nextMandel has no return value.
; --------------------------------------------------
nextMandel
jsr calcOneMandelbrotSequence
jsr drawPoint
; REAL <= STEP_X + REAL
+callFunc add32Bit, STEP_X, REAL
+inc16Bit COUNT_X
+cmp16Bit COUNT_X, MAX_X
bne .done
+load16BitImmediate 0, COUNT_X
; REAL <= INIT_REAL
+callFunc move32Bit, INIT_REAL, REAL
; IMAG <= STEP_Y + IMAG
+callFunc add32Bit, STEP_Y, IMAG
inc COUNT_Y
.done
rts
.INTERRUPTED
!byte 0
; --------------------------------------------------
; This routine visualizes the Mandelbrot set
; --------------------------------------------------
mandelLoop
lda .INTERRUPTED
bne .resetInterruped
jsr initMandel
.resetInterruped
stz .INTERRUPTED
.loopUntilFinished
jsr nextMandel
jsr checkKey
sta .INTERRUPTED
bne .doneMandel
lda COUNT_Y
cmp MAX_Y
bne .loopUntilFinished
bra .doneMandel
.doneMandel
rts
!ifndef TESTS {
.TXT_REAL_PART
!byte 18
!tx "REAL PART : $"
.TXT_IMAGINARY_PART
!byte 18
!tx "IMAGINARY PART : $"
.TXT_ZOOM_LEVEL
!byte 17
!tx "ZOOM LEVEL : "
.TXT_ITERATION_DEPTH
!byte 17
!tx "ITERATION DEPTH: "
.TXT_STEPPING_X
!byte 18
!tx "STEP X : $"
.TXT_STEPPING_Y
!byte 18
!tx "STEP Y : $"
; --------------------------------------------------
; This routine performs all neccessary steps for selecting
; a new upper left corner in the set and a new stepping width
; in X and Y direction (i.e. zomming into the set).
;
; This routine does not return any values.
; --------------------------------------------------
.processZoomResult
+move16Bit ZOOM_X_POS, COUNT_X
lda ZOOM_Y_POS
sta COUNT_Y
jsr deriveParametersFromPixel
ldx ZOOM_DIFF
beq .zoomingDone
.zoomInMore
jsr increaseZoomLevel
dex
bne .zoomInMore
.zoomingDone
rts
.STR_CONV
!byte 3
!byte 0,0,0
VEC_SPECIAL_PRINT
!byte 0, 0
!macro withPrinterCall .func, .printer {
+load16BitImmediate .printer, VEC_SPECIAL_PRINT
jsr .func
}
.specialWrapper
jmp (VEC_SPECIAL_PRINT)
!macro printLastValuesAt .xpos, .ypos {
lda #.xpos
sta ORIGIN_X
lda #.ypos
sta ORIGIN_Y
jsr printLastValuesAtCall
}
.TXT_VALUES_NO_CR
!byte 27
!tx "VALUES USED FOR CALCULATION"
ORIGIN_X
!byte 0
ORIGIN_Y
!byte 0
; --------------------------------------------------
; This routine prints the current values uses for calculation. Output
; begins at the posotion defined by the values stored at ORIGIN_X and
; ORIGIN_Y. The last line of output is generated by a user defined routine
; the address of which has to be stored in the jmp vector VEC_SPECIAL_PRINT
; before calling this routine.
;
; This routine does not return a value.
; --------------------------------------------------
printLastValuesAtCall
+locateAddr ORIGIN_X, ORIGIN_Y
+printStr .TXT_VALUES_NO_CR
inc ORIGIN_Y
inc ORIGIN_Y
+locateAddr ORIGIN_X, ORIGIN_Y
+printStr .TXT_REAL_PART
+printFixedPoint INIT_REAL
inc ORIGIN_Y
+locateAddr ORIGIN_X, ORIGIN_Y
+printStr .TXT_IMAGINARY_PART
+printFixedPoint INIT_IMAG
inc ORIGIN_Y
+locateAddr ORIGIN_X, ORIGIN_Y
+printStr .TXT_ZOOM_LEVEL
+itoa ZOOM_LEVEL, .STR_CONV
+printStr .STR_CONV
inc ORIGIN_Y
+locateAddr ORIGIN_X, ORIGIN_Y
+printStr .TXT_ITERATION_DEPTH
+itoa MAX_ITER, .STR_CONV
+printStr .STR_CONV
inc ORIGIN_Y
+locateAddr ORIGIN_X, ORIGIN_Y
+printStr .TXT_STEPPING_X
+printFixedPoint STEP_X
inc ORIGIN_Y
+locateAddr ORIGIN_X, ORIGIN_Y
+printStr .TXT_STEPPING_Y
+printFixedPoint STEP_Y
inc ORIGIN_Y
+locateAddr ORIGIN_X, ORIGIN_Y
jsr .specialWrapper
rts
.TXT_SELECT_DEPTH
!byte 40
!tx "SELECT ITERATION DEPTH (24 IS DEFAULT): "
DEC_CHARS
!byte 10
!tx "0123456789"
.BUFFER_DEPTH
!byte 3
!tx 0,0,0
.NEW_DEPTH_RAW
!byte 0,0
SELECT_ITER_POS_X = MAIN_MENU_X
SELECT_ITER_POS_Y = MAIN_MENU_Y + MAIN_MENU_HEIGHT + 9
SELECT_ITER_HEIGHT = 2
; --------------------------------------------------
; This routine allows the user to select an iteration depth
;
; It does not return a value but modifies MAX_ITER.
; --------------------------------------------------
selectIterationDepth
lda #3
sta .BUFFER_DEPTH ; set number of bytes available in input string
+locate SELECT_ITER_POS_X, SELECT_ITER_POS_Y + 1
+inputStr .BUFFER_DEPTH, DEC_CHARS ; Get input string, as string of digits
pha ; save length of entered string
jsr printCRLF
pla ; restore string length
cmp #0 ; check for empty string
beq .defaultDepth ; User only pressed return => Use default
+atoi .BUFFER_DEPTH, .NEW_DEPTH_RAW ; Convert string to a number
+cmp16BitImmediate 254, .NEW_DEPTH_RAW ; Value entered was too big => Let's try that again
bcc selectIterationDepth
lda .NEW_DEPTH_RAW
sta MAX_ITER ; Store new value entered by the user
bra .selectionDone
.defaultDepth
lda #ITER_DEFAULT
sta MAX_ITER ; (Re)store default value
.selectionDone
rts
.TXT_FILE_NAME
!byte 10
!tx "FILENAME: "
.TXT_LOADING
!byte 11
!tx "LOADING ..."
.TXT_SAVING
!byte 10
!tx "SAVING ..."
.TXT_SAVING_SUCCESS
!byte 22
!tx "SAVING WAS SUCCESSFULL"
.TXT_SAVING_FAILED
!byte 13
!tx "SAVING FAILED"
.TXT_STORE_SD
!byte 24
!tx "STORE PICTURE ON SD CARD"
.TXT_STORE_SD_2
!byte 37
!tx "PRESS ANY KEY TO GO BACK TO MAIN MENU"
ALLOWED_FILE_CHARS
!byte 38
!tx "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ."
; --------------------------------------------------
; This routine saves a picture and the corresponding parameters to disk
;
; It returns DISK_IO_OK if saving was successfull.
; --------------------------------------------------
savePicture
+printStrAt MAIN_MENU_X, MAIN_MENU_Y, .TXT_STORE_SD
+printStrAt MAIN_MENU_X, MAIN_MENU_Y + 2, .TXT_STORE_SD_2
+petsciiRect MAIN_MENU_X - 1, MAIN_MENU_Y - 1, MAIN_MENU_WIDTH, 3, RECT_NO_CLEAR
+printStrAt MAIN_MENU_X, MAIN_MENU_Y + 6, .TXT_FILE_NAME
+petsciiRect MAIN_MENU_X - 1, MAIN_MENU_Y + 5, MAIN_MENU_WIDTH, 3, RECT_NO_CLEAR
+locate MAIN_MENU_X, MAIN_MENU_Y + 7
lda #MAX_FILE_NAME_LENGTH ; restore input buffer cpacity
sta FILE_NAME_SAVE_LOAD
+inputStr FILE_NAME_SAVE_LOAD, ALLOWED_FILE_CHARS
cmp #0
beq .noSave ; do nothing if user entered an empty string
+printStrAt MAIN_MENU_X, MAIN_MENU_Y + 8, .TXT_SAVING
jsr saveHiresDataToDisk ; save data from banked RAM to disk
cmp #DISK_IO_OK
beq .saveIsDone
+printStrAt MAIN_MENU_X, MAIN_MENU_Y + 8, .TXT_SAVING_FAILED ; print error message
bra .returnFromSave
.saveIsDone
+printStrAt MAIN_MENU_X, MAIN_MENU_Y + 8, .TXT_SAVING_SUCCESS
.returnFromSave
rts
.noSave
rts
LOAD_FILE_EDIT_POS_X = MAIN_MENU_X
LOAD_FILE_EDIT_POS_Y = MAIN_MENU_Y + MAIN_MENU_HEIGHT + 3
LOAD_FILE_EDIT_HEIGHT = 3
; --------------------------------------------------
; This routine loads a picture and the corresponding parameters from disk
;
; It returns DISK_IO_OK if loading was successfull.
; --------------------------------------------------
loadPicture
lda #MAX_FILE_NAME_LENGTH ; restore input buffer cpacity
sta FILE_NAME_SAVE_LOAD
+locate LOAD_FILE_EDIT_POS_X, LOAD_FILE_EDIT_POS_Y + 1
+inputStr FILE_NAME_SAVE_LOAD, ALLOWED_FILE_CHARS
cmp #0
beq .noLoad ; do nothing if user entered empty string
+printStrAt LOAD_FILE_EDIT_POS_X, LOAD_FILE_EDIT_POS_Y + 2, .TXT_LOADING
jsr loadHiresDataFromDisk ; load data and store it in banked RAM
rts
.noLoad
lda #DISK_IO_ERR
rts
; --------------------------------------------------
; This routine loads a picture, shows it and handles keyboard input
; for zooming in and showing values. If the user decides to zoom into
; the picture this routine jumps (jmp(!!)) into the main routine.
; The main routine therefore calls loadAndShowPicture also with a jmp
; in order to keep the stack clean. This also means that if this routine
; executes rts the program ends.
;
; The routine has no return values.
; --------------------------------------------------
loadAndShowPicture
jsr loadPicture
cmp #DISK_IO_OK
beq .doShowAfterLoad ; do nothing if load failed
jsr readAndEvalErrorChannel ; read error channel
+printStrAt LOAD_FILE_EDIT_POS_X, LOAD_FILE_EDIT_POS_Y + 2, ERR_BYTE_COUNTER ; print error message
jmp .mainMenuInputSelect
.doShowAfterLoad
jsr bitMapOn ; This also clears Video RAM
jsr restoreHiresData ; Move loaded data to video RAM
.waitForCommand
jsr waitForKey
cmp #KEY_DO_ZOOM
bne .showValues
;
stz .INTERRUPTED
jsr showZoomRect ; Perform selection of zoomed in section
lda ZOOM_RESULT
cmp #ZOOM_ESCAPE ; Did user cancel the operation?
beq .waitForCommand ; Yes, User escaped from zoom selection
jsr .processZoomResult ; Modify state and start values for calculation
jmp .restart ; draw visualization
.showValues
stz .INTERRUPTED
+withPrinterCall showCalcParameters, .printNothing
cmp #CONST_CONTINUE ; Does user want to end the program?
beq .waitForCommand ; No => continue showing picture
jmp .mainMenu
; --------------------------------------------------
; This routine reads the error channel and prints the result in the FILNAME
; area of the main menu.
;
; The routine has no return values. The disk error read from the error channel
; is stored at address DISK_ERROR.
; --------------------------------------------------
.loadHelper
jsr readAndEvalErrorChannel ; read error channel
+clearLineAt MAIN_MENU_X, LOAD_FILE_EDIT_POS_Y + 2, MAIN_MENU_WIDTH
+printStrAt MAIN_MENU_X, LOAD_FILE_EDIT_POS_Y + 2, ERR_BYTE_COUNTER ; print error message
rts
; --------------------------------------------------
; This routine loads a parameter set from disk.
;
; The routine has no return values.
; --------------------------------------------------
loadParameters
+clearLineAt MAIN_MENU_X, LOAD_FILE_EDIT_POS_Y + 2, MAIN_MENU_WIDTH
lda #MAX_FILE_NAME_LENGTH ; restore input buffer cpacity
sta FILE_NAME_SAVE_LOAD
+locate LOAD_FILE_EDIT_POS_X, LOAD_FILE_EDIT_POS_Y + 1 ; place cursor at input area
+inputStr FILE_NAME_SAVE_LOAD, ALLOWED_FILE_CHARS ; let user enter a string
cmp #0
beq .noLoadParam ; do nothing if user entered empty string
+printStrAt LOAD_FILE_EDIT_POS_X, LOAD_FILE_EDIT_POS_Y + 2, .TXT_LOADING ; show loading ... message
jsr loadParametersFromDisk ; load parameters from disk
cmp #DISK_IO_OK
bne .noLoadParam
+petsciiRect MAIN_MENU_X - 1, SELECT_ITER_POS_Y + 4, MAIN_MENU_WIDTH, 9, RECT_CLEAR ; clear output area
+load16BitImmediate .printNothing, VEC_SPECIAL_PRINT ; set vector for special output routine
+printLastValuesAt MAIN_MENU_X + 6, SELECT_ITER_POS_Y + 5 ; print new parameters
jsr .loadHelper
lda DISK_ERROR
bne .paramLoadError
jmp .restart
.noLoadParam
jsr .loadHelper
.paramLoadError
jmp .mainMenuInputSelect
; --------------------------------------------------
; This routine saves the current parameter set to disk.
;
; The routine has no return values.
; --------------------------------------------------
saveParameters
+clearLineAt MAIN_MENU_X, LOAD_FILE_EDIT_POS_Y + 2, MAIN_MENU_WIDTH
lda #MAX_FILE_NAME_LENGTH ; restore input buffer cpacity
sta FILE_NAME_SAVE_LOAD
+locate LOAD_FILE_EDIT_POS_X, LOAD_FILE_EDIT_POS_Y + 1 ; place cursor at input area
+inputStr FILE_NAME_SAVE_LOAD, ALLOWED_FILE_CHARS ; let user enter a string
cmp #0
beq .noSaveParam ; do nothing if user entered empty string
+printStrAt LOAD_FILE_EDIT_POS_X, LOAD_FILE_EDIT_POS_Y + 2, .TXT_SAVING ; show saving ... message
jsr saveParametersToDisk ; save parameters to disk
.noSaveParam
jsr .loadHelper
jmp .mainMenuInputSelect
CONST_CONTINUE = 1
CONST_FINISH = 0
.TXT_CONTINUE_1
!byte 36
!tx "PRESS RETURN TO GO BACK TO MAIN MENU"
.TXT_CONTINUE_2
!byte 31
!tx "PRESS ANY OTHER KEY TO CONTINUE"
; --------------------------------------------------
; This routine shows the values used for calculation.
;
; It returns CONST_CONTINUE in the accu if the user has chosen to
; continue the program and CONST_FINISH in case the user
; wants to end the program.
; --------------------------------------------------
showCalcParameters
jsr saveHiresData ; save bitmap in banked RAM
showCalcNoSaveHires
jsr bitMapOff
+printLastValuesAt MAIN_MENU_X + 6, 16
+printStrAt MAIN_MENU_X, MAIN_MENU_Y, .TXT_CONTINUE_1
+printStrAt MAIN_MENU_X, MAIN_MENU_Y + 2, .TXT_CONTINUE_2
+petsciiRect MAIN_MENU_X - 1, MAIN_MENU_Y - 1, MAIN_MENU_WIDTH, 3, RECT_NO_CLEAR
+petsciiRect MAIN_MENU_X - 1, 15, MAIN_MENU_WIDTH, 9, RECT_NO_CLEAR
jsr waitForKey
cmp #13 ; user pressed return?
beq .endShowContinue ; Yes => Tell caller user wants to stop
jsr bitMapOn
jsr restoreHiresData ; restore bitmap from banked RAM
lda #CONST_CONTINUE
rts
.endShowContinue
lda #CONST_FINISH
rts
; --------------------------------------------------
; This routine handles the UI operations that occur after the calculation
; has ended. If the user decides to zoom into the picture this routine jumps
; (jmp(!!)) into the main routine. The main routine therefore calls
; loadAndShowPicture also with a jmp in order to keep the stack clean.
; This also means that if this routine executes rts the program ends.
;
; The routine has no return values.
; --------------------------------------------------
handlePicDone
+getTimestamp TIMESTAMP_CALC_END
jsr saveHiresData ; save current picture in banked RAM
.checkForKeyPress
jsr waitForKey
cmp #KEY_DO_ZOOM
bne .checkForSave
; try to zoom in
jsr showZoomRect ; Perform selection of zoomed in section
lda ZOOM_RESULT
cmp #ZOOM_ESCAPE
beq .checkForKeyPress ; User has aborted zoom selection
; user has selected a new section
jsr .processZoomResult
jmp .restart
.checkForSave
cmp #KEY_DO_SAVE
bne .showValuesAtEnd
jsr bitMapOff
jsr savePicture ; save picture if user pressed F7. No error check. The routine generates error messages
jsr readAndEvalErrorChannel ; read error channel
+clearLineAt MAIN_MENU_X, MAIN_MENU_Y + 8, MAIN_MENU_WIDTH
+printStrAt MAIN_MENU_X, MAIN_MENU_Y + 8, ERR_BYTE_COUNTER ; print error message
jsr waitForKey
jmp .mainMenu
.showValuesAtEnd
+withPrinterCall showCalcNoSaveHires, .printFinishedTime
cmp #CONST_CONTINUE
beq .checkForKeyPress
jmp .mainMenu
TIMESTAMP_RUNNING
!byte 0, 0, 0
.TXT_TIMESTAMP
!byte 8
!byte 0,0,0,0,0,0,0,0
.TXT_RUNNING_TIME
!byte 17
!tx "RUNNING FOR : "
.TXT_FINISHED_TIME
!byte 17
!tx "DONE AFTER : "
; --------------------------------------------------
; This routine prints the time needed for an ongoing calculation up
; to this point in time. It is intended to be used as a parameter
; for the printLastValuesAtCall routine by assigning it to the
; VEC_SPECIAL_PRINT jmp vector.
; --------------------------------------------------
.printRunningTime
!ifdef ITER_COUNT {
+printStr TXT_ITERATIONS
+printUnsigned ITER_CTR
} else {
+getTimestamp TIMESTAMP_RUNNING
+diffTime TIMESTAMP_CALC_START, TIMESTAMP_RUNNING
+getTimeStr .TXT_TIMESTAMP, TIMESTAMP_RUNNING
+printStr .TXT_RUNNING_TIME
+printStr .TXT_TIMESTAMP
}
rts
.TIMESTAMP_END_TEMP
!byte 0, 0, 0
; --------------------------------------------------
; This routine prints the total time used for a calculation.
; It is intended to be used as a parameter for the printLastValuesAtCall
; routine by assigning it to the VEC_SPECIAL_PRINT jmp vector.
; --------------------------------------------------
.printFinishedTime
!ifdef ITER_COUNT {
+printStr TXT_ITERATIONS
+printUnsigned ITER_CTR
} else {
+copyTs TIMESTAMP_CALC_END, .TIMESTAMP_END_TEMP
+diffTime TIMESTAMP_CALC_START, .TIMESTAMP_END_TEMP
+getTimeStr .TXT_TIMESTAMP, .TIMESTAMP_END_TEMP
+printStr .TXT_FINISHED_TIME
+printStr .TXT_TIMESTAMP
}
rts
; --------------------------------------------------
; This routine prints nothing. It is intended to be used as a
; parameter for the printLastValuesAtCall routine by assigning it to the
; VEC_SPECIAL_PRINT jmp vector. It is used when a picture has been
; loaded and not calculated.
; --------------------------------------------------
.printNothing
rts
.TXT_SELECT
!byte 73
.MENU_1
!byte 15
!tx "1. LOAD PICTURE"
.MENU_2
!byte 25
!tx "2. CHANGE ITERATION DEPTH"
.MENU_3
!byte 21
!tx "3. USE DEFAULT VALUES"
.MENU_4
!byte 21
!tx "4. USE CURRENT VALUES"
.MENU_7
!byte 18
!tx "5. LOAD PARAMETERS"
.MENU_8
!byte 18
!tx "6. SAVE PARAMETERS"
.MENU_5
!byte 7
!tx "7. EXIT"
.MENU_6
!byte 31
!tx "PRESS KEY 1, 2, 3, 4, 5, 6 OR 7"
.MENU_TXT_PROG_NAME
!byte 32
!tx "******** MANDELBROT X16 ********"
.MENU_TXT_AUTHOR_NAME
!byte 22
!tx "WRITTEN BY MARTIN GRAP"
.MENU_WRITTEN_IN
!byte 12
!tx "IN 2022/2023"
MAIN_MENU_X = 20
MAIN_MENU_Y = 10
MAIN_MENU_WIDTH = 40
MAIN_MENU_HEIGHT = 12
; --------------------------------------------------
; This routine shows the main menu and handles its input.
; --------------------------------------------------
showMainMenu
lda #147
jsr CHAROUT ; clear screen
+printStrAt MAIN_MENU_X + 4, 2, .MENU_TXT_PROG_NAME
+printStrAt MAIN_MENU_X + 9, 4, .MENU_TXT_AUTHOR_NAME
+printStrAt MAIN_MENU_X + 13, 6, .MENU_WRITTEN_IN
+printStrAt MAIN_MENU_X, MAIN_MENU_Y, .MENU_1
+printStrAt MAIN_MENU_X, MAIN_MENU_Y + 1, .MENU_2
+printStrAt MAIN_MENU_X, MAIN_MENU_Y + 2, .MENU_3
+printStrAt MAIN_MENU_X, MAIN_MENU_Y + 3, .MENU_4
+printStrAt MAIN_MENU_X, MAIN_MENU_Y + 5, .MENU_7
+printStrAt MAIN_MENU_X, MAIN_MENU_Y + 6, .MENU_8
+printStrAt MAIN_MENU_X, MAIN_MENU_Y + 9, .MENU_5
+printStrAt MAIN_MENU_X, MAIN_MENU_Y + 11, .MENU_6
+printStrAt LOAD_FILE_EDIT_POS_X, LOAD_FILE_EDIT_POS_Y, .TXT_FILE_NAME
+printStrAt SELECT_ITER_POS_X, SELECT_ITER_POS_Y, .TXT_SELECT_DEPTH
+petsciiRect MAIN_MENU_X - 1, MAIN_MENU_Y - 1, MAIN_MENU_WIDTH, MAIN_MENU_HEIGHT, RECT_NO_CLEAR
+petsciiRect LOAD_FILE_EDIT_POS_X - 1, LOAD_FILE_EDIT_POS_Y - 1, MAIN_MENU_WIDTH, LOAD_FILE_EDIT_HEIGHT, RECT_NO_CLEAR
+petsciiRect SELECT_ITER_POS_X - 1, SELECT_ITER_POS_Y - 1, MAIN_MENU_WIDTH, SELECT_ITER_HEIGHT, RECT_NO_CLEAR
+load16BitImmediate .printNothing, VEC_SPECIAL_PRINT
+printLastValuesAt MAIN_MENU_X + 6, SELECT_ITER_POS_Y + 5
+petsciiRect MAIN_MENU_X - 1, SELECT_ITER_POS_Y + 4, MAIN_MENU_WIDTH, 9, RECT_NO_CLEAR
jsr printHelpMessage
.mainMenuInputSelect
; Handle initial menu
jsr waitForKey
cmp #49 ; 1. pressed?
bne .checkFor2 ; No
+clearLineAt LOAD_FILE_EDIT_POS_X, LOAD_FILE_EDIT_POS_Y + 2, MAIN_MENU_WIDTH
jmp loadAndShowPicture ; yes => load and show picture
.checkFor2
cmp #50 ; 2. pressed?
bne .checkFor3
jmp .changeIterDepth ; yes
.checkFor3
cmp #51 ; 3. pressed?
bne .checkFor4
jmp .resetCalcParms ; Yes
.checkFor4
cmp #52 ; 4. pressed ?
bne .checkFor5
jmp .restart ; yes
.checkFor5
cmp #53 ; 5. pressed ?
bne .checkFor6
jmp loadParameters ; yes
.checkFor6
cmp #54 ; 6. pressed ?
bne .checkFor7
jmp saveParameters ; yes
.checkFor7
cmp #55 ; 7. pressed ?
beq .exitProgram
jmp .mainMenuInputSelect ; No => try again
; 7. was pressed
.exitProgram
lda #147
jsr CHAROUT ; clear screen
rts
.TXT_HELP_1
!byte 36
!tx "PRESS F5 TO ZOOM INTO THE MANDELBROT"
.TXT_HELP_2
!byte 35
!tx "SET AT ANY TIME. USE F1, F3 AND THE"
.TXT_HELP_3
!byte 36
!tx "CURSOR KEYS TO SELECT A NEW SECTION."
.TXT_HELP_4
!byte 33
!tx "RETURN STARTS THE CALCULATION. F2"
.TXT_HELP_5
!byte 21
!tx "ABORTS THE SELECTION."
.TXT_HELP_6
!byte 32
!tx "IF A CALCULATION IS FINISHED YOU"
.TXT_HELP_7