-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathspigot.asm
1437 lines (1409 loc) · 25.5 KB
/
spigot.asm
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
// Initial array fill
//
// rr0 - RAM bank iterator
// rr1 - RAM bank index
// rr2 - RAM register index
// rr3 - RAM character index
FIM r0, 0x80
process_bank:
// select current bank
LD rr1
DCL
// iterate from register #0
CLB
XCH rr2
process_register:
// iterate from character #0
CLB
XCH rr3
process_character:
// write 2 to selected bank/register/character set
SRC r1
LDM 2
WRM
ISZ rr3, process_character
// write 2 to status characters at selected bank/register
WR0
WR1
WR2
WR3
ISZ rr2, process_register
INC rr1
ISZ rr0, process_bank
// Main loop
//
// bank #7, reg #F, main characters 5, 6, 7 - pi digits in c-base loop iterator and numerator for corresponding digit
// rr8/rr9/rr10/rr11 - carry for pi digits in c-base
// rr12 - pre-computed digit, that could be corrected
// rr13 - count of 9s after pre-computed digit
// rr14/rr15 - amount of computed pi digits
FIM r6, 0x00
// compute 255 digits, not 256 ;)
FIM r7, 0x10
main_loop:
// set carry to zero
FIM r4, 0x00
FIM r5, 0x00
// set initial numerator to 1701 == 0x006A5
LDM 7
DCL
FIM r0, 0xF5
SRC r0
LDM 0x5
WRM
INC rr1
SRC r0
LDM 0xA
WRM
INC rr1
SRC r0
LDM 0x6
WRM
INC rr1
SRC r0
LDM 0x0
WRM
INC rr1
SRC r0
LDM 0x0
WRM
normalization_loop:
JMS get_denominator_by_numerator
// rr0/rr1/rr2 would contain denominator
JMS get_linear_address_by_denominator
// rr5/rr6/rr7 would contain linear address
JMS read_element_to_buffer
JMS mul_buf_by_10
JMS sum_carry_with_buf
JMS div_buf_by_numerator
// rr8/rr9 would contain quotient
JMS get_denominator_by_numerator
// rr0/rr1/rr2 would contain denominator
JMS mul_denominator_by_quotient
// rr8/rr9/rr10/rr11 would contain carry
JMS get_linear_address_by_denominator
// rr5/rr6/rr7 would contain linear address
JMS write_buffer_to_element
// decrease numerator by 2, and check if loop is done
LDM 2
XCH rr2
LDM 0
XCH rr3
LDM 7
DCL
FIM r0, 0xF5
SRC r0
RDM
CMC
SUB rr2
WRM
INC rr1
SRC r0
RDM
CMC
SUB rr3
WRM
INC rr1
SRC r0
RDM
SUB rr3
WRM
JCN c, normalization_loop
// carry could be in range [0..19], so only rr8/rr9 contains data
LD rr9
XCH rr0
LD rr8
XCH rr1
LDM 10
XCH rr2
// div carry by 10, rr0 would be first digit of carry (0 or 1), rr1 - 2nd digit
JMS div8bitBy4bit
// check if first digit of carry is 1, then we need to print X0000 instead of X9999, coz of cascade carry
LD rr0
JCN z, carry_first_digit_is_zero
LDM 0
JUN set_printed_digit_instead_of_nines
carry_first_digit_is_zero:
LDM 9
set_printed_digit_instead_of_nines:
XCH rr6
// check if digit is 9
LDM 9
SUB rr1
JCN nz, next_digit_is_not_nine
INC rr13
JUN main_loop
next_digit_is_not_nine:
LD rr0
ADD rr12
XCH rr0
// update nextDigit before calling function, because rr1 could be updated in subroutine
LD rr1
XCH rr12
JMS send_computed_digit
ISZ rr14, digit_is_printed
ISZ rr15, digit_is_printed
JUN work_is_done
digit_is_printed:
// now print buffered 9s
CLB
SUB rr13
JCN z, nines_are_printed
XCH rr13
print_nine:
LD rr6
XCH rr0
JMS send_computed_digit
ISZ rr14, nine_is_printed
ISZ rr15, nine_is_printed
JUN work_is_done
nine_is_printed:
ISZ rr13, print_nine
nines_are_printed:
JUN main_loop
work_is_done:
// halt
JUN work_is_done
// divide 8bit number by 4bit number
// INPUT:
// rr0 - high word of dividend, rr1 - low word of dividend, rr2 - divisor
// OUTPUT:
// rr0 - quotient, rr1 - reminder, CARRY flag would be set in case of overflow (quotient > 15)
// REGISTERS MODIFIED:
// rr3 - temporal quotient
// rr6 - zero
div8bitBy4bit:
CLB
XCH rr3
CLB
XCH rr6
div8bitBy4bit_subtract:
CLC
LD rr1
SUB rr2
XCH rr1
CMC
LD rr0
SUB rr6
XCH rr0
JCN nc, div8bitBy4bit_return
ISZ rr3, div8bitBy4bit_subtract
// overflow occurs
BBL 0
div8bitBy4bit_return:
LD rr1
ADD rr2
XCH rr1
LD rr3
XCH rr0
CLC
BBL 0
// get word count for number (detected by 0 at most significant word)
// INPUT:
// rr1 - index for last character in memory allocated for number + 1
// rr2 - max possible length of number + 1
// OUTPUT:
// rr2 - word count
div_buf_by_numerator_number_len:
LDM 0xF
XCH rr0
div_buf_by_numerator_number_len_check_prev_word:
LD rr1
DAC
XCH rr1
LD rr2
DAC
XCH rr2
SRC r0
RDM
JCN z, div_buf_by_numerator_number_len_check_prev_word
CLC
BBL 0
// check if dividend bigger or equal than divisor
// OUTPUT:
// CARRY is set if dividend is bigger or equal than divisor
div_buf_by_numerator_is_dividend_bigger_or_equal_than_divisor:
FIM r0, 0xF0
FIM r1, 0xF5
LDM 0xB
XCH rr5
STC
div_buf_by_numerator_is_dividend_bigger_or_equal_than_divisor_next_word:
SRC r0
RDM
SRC r1
CMC
SBM
INC rr1
INC rr3
ISZ rr5, div_buf_by_numerator_is_dividend_bigger_or_equal_than_divisor_next_word
BBL 0
// divide N-word by 1-word
// REGISTER MODIFIED:
// rr6/rr7 - dividend digit RAM address
// rr2 - divisor
// INPUT:
// dividend - bank #7, register #F, main characters [0..4], LSW at #0 character
// divisor - bank #7, register #F, main characters [5..9]
// OUTPUT:
// quotient - rr8/rr9
// reminder - bank #7, register #F, main characters [0..4]
// NOTES:
// quotient is always 1 or 2 digits, so we know that if dividend is 3-word number, then MSW < divisor
div_buf_by_numerator_one_word_divisor:
// load divisor
FIM r3, 0xF5
SRC r3
RDM
XCH rr2
// calculate MSW for quotient
LDM 2
XCH rr7
SRC r3
RDM
XCH rr0
LDM 0
WRM
LDM 1
XCH rr7
SRC r3
RDM
XCH rr1
LDM 0
WRM
// call div8bitBy4bit(dividend[2], dividend[1], divisor)
JMS div8bitBy4bit
// rr0 - quotient, rr1 - reminder
LD rr0
XCH rr9
// calculate LSW for quotient
LD rr1
XCH rr0
FIM r3, 0xF0
SRC r3
RDM
XCH rr1
// call div8bitBy4bit(reminder, dividend[0], divisor)
JMS div8bitBy4bit
// rr0 - quotient, rr1 - reminder
LD rr0
XCH rr8
LD rr1
WRM
BBL 0
// determine on how many bits we need to shift divisor left to set MSB to 1
// OUTPUT:
// shift value - rr6
div_buf_by_numerator_normalize_get_shift_value:
LDM 0x0
XCH rr6
LDM 0xC
XCH rr5
// read MSW for divisor
FIM r0, 0xF4
LD rr11
ADD rr1
XCH rr1
SRC r0
RDM
div_buf_by_numerator_normalize_get_shift_value_check_binary_digit:
RAL
JCN c, div_buf_by_numerator_normalize_get_shift_value_return
INC rr6
ISZ rr5, div_buf_by_numerator_normalize_get_shift_value_check_binary_digit
div_buf_by_numerator_normalize_get_shift_value_return:
CLC
BBL 0
// shift left 4bit number
// INPUT:
// rr6 - shift value
// rr3 - value
// OUTPUT:
// rr3 - shifter value
shift_left:
LD rr6
CMA
IAC
XCH rr5
LD rr3
shift_left_bit:
RAL
CLC
ISZ rr5, shift_left_bit
XCH rr3
BBL 0
// shift right 4bit number
// INPUT:
// rr7 - shift value
// rr4 - value
// OUTPUT:
// rr4 - shifter value
shift_right:
LD rr7
CMA
IAC
XCH rr5
LD rr4
shift_right_bit:
RAR
CLC
ISZ rr5, shift_right_bit
XCH rr4
BBL 0
// shift left multiword number
// INPUT:
// rr6 - shift value
// rr7 - (4 - shift value)
// rr1 - (character index in memory for MSW shifting number) + 1
// rr2 - number of words
div_buf_by_numerator_shift_number_left:
LDM 0xF
XCH rr0
LD rr2
CMA
IAC
XCH rr2
div_buf_by_numerator_shift_number_left_shift_digit:
// shift right next digit, some bits would be transferred to current difit
LD rr1
DAC
XCH rr1
SRC r0
RDM
XCH rr4
JMS shift_right
// shift left current digit
INC rr1
SRC r0
RDM
XCH rr3
JMS shift_left
LD rr3
ADD rr4
WRM
LD rr1
DAC
XCH rr1
ISZ rr2, div_buf_by_numerator_shift_number_left_shift_digit
// shift left LSW
SRC r0
RDM
XCH rr3
JMS shift_left
LD rr3
WRM
BBL 0
// multiply 1-word number by 1-word number, output is 2-word
// INPUT:
// rr0 - multiplier
// rr1 - multiplicand
// OUTPUT:
// rr2 - low word
// rr3 - high word
mul4bitBy4bit:
FIM r1, 0x00
LD rr1
JCN z, mul4bitBy4bit_return
CMA
IAC
XCH rr1
mul4bitBy4bit_add:
LD rr2
ADD rr0
XCH rr2
LDM 0
ADD rr3
XCH rr3
ISZ rr1, mul4bitBy4bit_add
mul4bitBy4bit_return:
BBL 0
// get single quotient digit at specified position
// INPUT:
// rr7 - quotient digit idx
// rr10 - number of words for dividend
// rr11 - number of words for divisor
// dividend - bank #7, register #F, main characters [0..4], LSW at #0 character
// divisor - bank #7, register #F, main characters [5..9]
// OUTPUT:
// rr6 - quotient digit
// REGISTER MODIFIED:
// rr0/rr1/rr2/rr3/rr4/rr5
// rr8 - temporal variable, we can use it because it would be overwritten by low quotient digit after call
div_buf_by_numerator_get_quotient_digit:
FIM r2, 0xF4
LD rr11
ADD rr5
XCH rr5
SRC r2
RDM
// divisor[divisorDigits - 1]
XCH rr2
LD rr11
DAC
CLC
ADD rr7
XCH rr5
SRC r2
RDM
// dividend[divisorDigits + quotentDigitIdx - 1]
XCH rr1
INC rr5
SRC r2
RDM
// dividend[divisorDigits + quotentDigitIdx]
XCH rr0
JMS div8bitBy4bit
LD rr1
XCH rr8
LD rr0
XCH rr6
// quotient digit should be in range [0..F]
JCN nc, div_buf_by_numerator_get_quotient_digit_quotient_is_not_overflown
LDM 0xF
XCH rr6
JUN div_buf_by_numerator_get_quotient_digit_mulsub
div_buf_by_numerator_get_quotient_digit_quotient_is_not_overflown:
LDM 3
ADD rr11
XCH rr5
SRC r2
// divisor[divisorDigits - 2]
RDM
XCH rr1
LD rr6
XCH rr0
JMS mul4bitBy4bit
LD rr8
SUB rr3
JCN nc, div_buf_by_numerator_get_quotient_digit_rough_tune_estimated_quotient
JCN nz, div_buf_by_numerator_get_quotient_digit_mulsub
// we have carry flag there, so it would be added to rr7, take it into account
LDM 3
XCH rr0
LD rr11
ADD rr7
SUB rr0
CLC
XCH rr5
SRC r2
// dividend[divisorDigits + quotentDigitIdx - 2]
RDM
SUB rr2
JCN c, div_buf_by_numerator_get_quotient_digit_mulsub
div_buf_by_numerator_get_quotient_digit_rough_tune_estimated_quotient:
LD rr6
DAC
CLC
XCH rr6
LDM 4
ADD rr11
XCH rr5
SRC r2
// divisor[divisorDigits - 1]
RDM
ADD rr8
XCH rr8
JCN nc, div_buf_by_numerator_get_quotient_digit_quotient_is_not_overflown
div_buf_by_numerator_get_quotient_digit_mulsub:
// rr4 - carry
// rr5 - digit idx
// rr8 - loop iterator
LDM 0
XCH rr4
LDM 0
XCH rr5
LD rr11
CMA
IAC
XCH rr8
div_buf_by_numerator_get_quotient_digit_mulsub_digit:
FIM r0, 0xF5
LDM 0x5
ADD rr5
XCH rr1
SRC r0
// divisor[divisorDigitIdx]
RDM
XCH rr1
LD rr6
XCH rr0
JMS mul4bitBy4bit
// rr2 = product[0], rr3 = product[1]
FIM r0, 0xF0
LD rr5
ADD rr7
XCH rr1
SRC r0
// dividend[divisorDigitIdx + quotentDigitIdx]
RDM
SUB rr4
XCH rr0
CMC
TCC
XCH rr4
LD rr0
SUB rr2
CMC
JCN nc, div_buf_by_numerator_get_quotient_digit_mulsub_digit_no_more_carry
INC rr4
CLC
div_buf_by_numerator_get_quotient_digit_mulsub_digit_no_more_carry:
WRM
LD rr4
ADD rr3
XCH rr4
INC rr5
ISZ rr8, div_buf_by_numerator_get_quotient_digit_mulsub_digit
div_buf_by_numerator_get_quotient_digit_mulsub_last_digit:
FIM r0, 0xF0
LD rr11
ADD rr7
XCH rr1
SRC r0
// dividend[dividendDigitIdx]
RDM
SUB rr4
CMC
WRM
JCN nc, div_buf_by_numerator_get_quotient_digit_return
// compensate if current reminder is negative now
LD rr6
DAC
XCH rr6
// rr4 - carry
// rr5 - digit idx
// rr8 - loop iterator
LDM 0
XCH rr4
LDM 0
XCH rr5
LD rr11
CMA
IAC
XCH rr8
div_buf_by_numerator_get_quotient_digit_add_digit:
FIM r0, 0xF0
LDM 0x5
ADD rr5
XCH rr1
SRC r0
// divisor[divisorDigitIdx]
RDM
XCH rr2
LD rr5
ADD rr7
XCH rr1
SRC r0
// dividend[divisorDigitIdx + quotentDigitIdx]
RDM
ADD rr2
XCH rr3
TCC
XCH rr0
LD rr3
ADD rr4
WRM
TCC
ADD rr0
XCH rr4
INC rr5
ISZ rr8, div_buf_by_numerator_get_quotient_digit_add_digit
div_buf_by_numerator_get_quotient_digit_add_digit_last_digit:
FIM r0, 0xF0
LD rr11
ADD rr7
XCH rr1
SRC r0
// dividend[dividendDigitIdx]
RDM
ADD rr4
WRM
CLC
div_buf_by_numerator_get_quotient_digit_return:
BBL 0
// shift right multiword number
// INPUT:
// rr7 - shift value
// rr6 - (4 - shift value)
// rr1 - character index in memory for LSW
// rr2 - number of words
div_buf_by_numerator_shift_number_right:
LDM 0xF
XCH rr0
LD rr2
CMA
IAC
XCH rr2
div_buf_by_numerator_shift_number_right_digit:
SRC r0
RDM
XCH rr4
JMS shift_right
INC rr1
SRC r0
RDM
XCH rr3
JMS shift_left
LD rr1
DAC
XCH rr1
SRC r0
CLC
LD rr3
ADD rr4
WRM
INC rr1
ISZ rr2, div_buf_by_numerator_shift_number_right_digit
BBL 0
// divide N-word number from buffer by M-word number
// INPUT:
// dividend - bank #7, register #F, main characters [0..4], LSW at #0 character
// divisor - bank #7, register #F, main characters [5..9]
// OUTPUT:
// quotient - rr8/rr9
// reminder - bank #7, register #F, main characters [0..4]
// REGISTER UNMODIFIED:
// rr12/rr13/rr14/rr15
// REGISTER MODIFIED:
// rr10 - number of words for dividend
// rr11 - number of words for divisor
div_buf_by_numerator:
// get word count for dividend
LDM 0x5
XCH rr1
LDM 0x6
XCH rr2
JMS div_buf_by_numerator_number_len
LD rr2
XCH rr10
// get word count for divisor
LDM 0xA
XCH rr1
LDM 0x6
XCH rr2
JMS div_buf_by_numerator_number_len
LD rr2
XCH rr11
// check if dividend >= divisor, otherwise return quotient = 0
JMS div_buf_by_numerator_is_dividend_bigger_or_equal_than_divisor
JCN c, div_buf_by_numerator_dividend_is_bigger_or_equal_than_divisor
FIM r4, 0x00
BBL 0
div_buf_by_numerator_dividend_is_bigger_or_equal_than_divisor:
// check if we have 4bit divisor, in that case we use faster and simpler calculations
CLC
LDM 1
SUB rr11
JCN z, div_buf_by_numerator_one_word_divisor
// shift divisor and dividend to X bits to make sure that MSB for divisor is set
// in that case we can estimate quotient digit with high probability to match real digit
JMS div_buf_by_numerator_normalize_get_shift_value
FIM r0, 0xF9
SRC r0
LD rr6
WRM
JCN z, div_buf_by_numerator_normalize_finish
LDM 4
SUB rr6
CLC
XCH rr7
LD rr10
XCH rr2
LDM 0
ADD rr2
XCH rr1
JMS div_buf_by_numerator_shift_number_left
LD rr11
XCH rr2
LDM 5
ADD rr2
XCH rr1
JMS div_buf_by_numerator_shift_number_left
div_buf_by_numerator_normalize_finish:
LD rr10
SUB rr11
CLC
JCN z, div_buf_by_numerator_get_lsw_for_quotient
// 2nd digit for quotient, if necessary
LDM 1
XCH rr7
JMS div_buf_by_numerator_get_quotient_digit
LD rr6
XCH rr9
div_buf_by_numerator_get_lsw_for_quotient:
// 1st digit for quotient
LDM 0
XCH rr7
JMS div_buf_by_numerator_get_quotient_digit
LD rr6
XCH rr8
// denormalization
FIM r0, 0xF9
SRC r0
RDM
JCN z, div_buf_by_numerator_return
XCH rr7
LDM 4
SUB rr7
CLC
XCH rr6
LDM 0x0
XCH rr1
LD rr11
XCH rr2
JMS div_buf_by_numerator_shift_number_right
LDM 0x5
XCH rr1
LD rr11
XCH rr2
JMS div_buf_by_numerator_shift_number_right
FIM r0, 0xF9
SRC r0
LDM 0x0
WRM
div_buf_by_numerator_return:
BBL 0
// return corresponding denominator for specified numerator
// INPUT:
// numerator - bank #7, register #F, main characters [5..9]
// OUTPUT:
// denominator - rr0/rr1/rr2
// NOTES:
// denominator = (numerator - 1) / 2
get_denominator_by_numerator:
FIM r2, 0xF5
SRC r2
RDM
XCH rr0
INC rr5
SRC r02
RDM
XCH rr1
INC rr5
SRC r2
RDM
XCH rr2
// subtract 1
FIM r2, 0x10
LD rr0
SUB rr4
CMC
XCH rr0
LD rr1
SUB rr5
XCH rr1
CMC
LD rr2
SUB rr5
XCH rr2
CMC
// divide by 2 (shift right by 1)
// 1st digit
LD rr1
RAR
JCN nc, get_denominator_by_numerator_2nd_word_1st_bit_iz_zero
LDM 0x8
XCH rr6
CLC
get_denominator_by_numerator_2nd_word_1st_bit_iz_zero:
LD rr0
RAR
CLC
ADD rr6
XCH rr0
// 2nd digit
LDM 0x00
XCH rr6
LD rr2
RAR
JCN nc, get_denominator_by_numerator_3rd_word_1st_bit_iz_zero
LDM 0x8
XCH rr6
CLC
get_denominator_by_numerator_3rd_word_1st_bit_iz_zero:
LD rr1
RAR
CLC
ADD rr6
XCH rr1
// 3rd digit
LD rr2
RAR
XCH rr2
BBL 0
// return linear address for digit in mixed-radix pi
// INPUT:
// rr0/rr1/rr2 - denominator
// OUTPUT:
// rr5/rr6/rr7 - linear address
// NOTES:
// address = (denominator - 1) * 3
get_linear_address_by_denominator:
// subtract 1
LDM 0x1
XCH rr3
LDM 0x0
XCH rr4
LD rr0
SUB rr3
CMC
XCH rr5
LD rr1
SUB rr4
XCH rr6
CMC
LD rr2
SUB rr4
XCH rr7
CMC
// multiply by 3
// 1-st digit
LD rr5
ADD rr5
XCH rr3
TCC
XCH rr4
LD rr3
ADD rr5
XCH rr5
TCC
ADD rr4
// 2-nd digit
ADD rr6
XCH rr3
TCC
XCH rr4
LD rr3
ADD rr6
XCH rr3
TCC
ADD rr4
XCH rr4
LD rr3
ADD rr6
XCH rr6
TCC
ADD rr4
// 3-rd digit
ADD rr7
ADD rr7
ADD rr7
XCH rr7
BBL 0
// select bank/register by specified word address and calculate character index inside register
// INPUT:
// rr5/rr6/rr7 - linear address of word
// OUTPUT:
// CARRY - if set, status character should be used, and rr2 would contain status character index (in 0-3 range)
// NOTES:
// bankIdx = address / 320
// regIdx = (address % 320) / 20
// charIdx = ((address % 320) % 20)
select_word_at_memory:
// *** BANK SELECTION ***
// save rr6, because div8bitBy4bit() would change it
LD rr6
XCH rr4
// shift address right by 6 (to divide by 2**6 = 64)
LD rr6
RAR
CLC
RAR
CLC
XCH rr1
LD rr7
RAL
CLC
RAL
CLC
ADD rr1
XCH rr1
LD rr7
RAR
CLC
RAR
CLC
XCH rr0
// additionally divide by 5 to receive bank index = (address / 320)
LDM 0x5
XCH rr2
JMS div8bitBy4bit
// restore register
LD rr4
XCH rr6
// select bank
LD rr0
DCL
XCH rr4
// *** CALCULATE OFFSET FOR WORD AT SELECTED BANK ***
// bank offset = address - (bank index * 0x140)
// because first digit of divisor is 0x0, we can use first digit of dividend (rr5) as first digit of reminder
// second digit of divisor is 0x4
LD rr4
RAL
CLC
RAL
CLC
XCH rr3
LD rr6
SUB rr3
XCH rr1
CMC
TCC
XCH rr3
LD rr4
RAR
CLC
RAR
CLC
ADD rr3
XCH rr3
LD rr7
SUB rr3
CLC
XCH rr2
// third digit is 0x1
LD rr2
SUB rr4
CLC
XCH rr2
// *** CALCULATE REGISTER INDEX ***
// shift bank offset right by 2 (to divide by 2**2 = 4)
LD rr5
RAR
CLC
RAR
CLC
XCH rr3
LD rr1
RAL
CLC