-
Notifications
You must be signed in to change notification settings - Fork 1
/
project.kmd
3118 lines (3117 loc) · 174 KB
/
project.kmd
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
KMD
00000000: ; ;------------------------------------------------------------------------------
00000000: ; ; Project
00000000: ; ; Ted John
00000000: ; ; Version 1.0
00000000: ; ; 16 April 2013
00000000: ; ;
00000000: ; ; This programme is an audio player.
00000000: ; ;
00000000: ; ;------------------------------------------------------------------------------
00000000: ; ; Includes os.s
00000000: ; ;------------------------------------------------------------------------------
00000000: ; INCLUDE ./os.s
00000000: ; ;------------------------------------------------------------------------------
00000000: ; ; Project
00000000: ; ; Ted John
00000000: ; ; Version 1.4
00000000: ; ; 16 April 2013
00000000: ; ;
00000000: ; ; Operating system
00000000: ; ;
00000000: ; ;------------------------------------------------------------------------------
00000000: ; ;
00000000: ; ;------------------------------------------------------------------------------
00000000: ;
00000000: ; ;------------------------------------------------------------------------------
00000000: ; ; Generic constants
00000000: ; ;------------------------------------------------------------------------------
00000000: ; FALSE EQU 0
00000000: ; TRUE EQU 1
00000000: ;
00000000: ;
00000000: ;
00000000: ; ;------------------------------------------------------------------------------
00000000: ; ; Sector division offsets
00000000: ; ;------------------------------------------------------------------------------
00000000: ; OFFSET_OS EQU &0 ; start address for the OS (code
; in supervisor mode)
00000000: ; OFFSET_IRQ EQU &7900 ; start address for interupt cod
; e (IRQ mode)
00000000: ; OFFSET_USER EQU &8000 ; start address for the user cod
; e (user mode)
00000000: ; OFFSET_ENDRAM EQU &27C00 ; the last available RAM address
00000000: ;
00000000: ; ;------------------------------------------------------------------------------
00000000: ; ; Architecture constants
00000000: ; ;------------------------------------------------------------------------------
00000000: ; PSR_CLR_MODE EQU &1F
00000000: ; PSR_USR EQU &10
00000000: ; PSR_FIQ EQU &11
00000000: ; PSR_IRQ EQU &12
00000000: ; PSR_SVC EQU &13
00000000: ; PSR_ABT EQU &17
00000000: ; PSR_UND EQU &1B
00000000: ; PSR_SYS EQU &1F
00000000: ;
00000000: ; ;------------------------------------------------------------------------------
00000000: ; ; I/O constants
00000000: ; ;------------------------------------------------------------------------------
00000000: ; port_area EQU &10000000
00000000: ; port_LCD_DATA EQU &0
00000000: ; port_LCD_CTRL EQU &4
00000000: ; port_BUTTONS EQU &4
00000000: ; port_TIMER EQU &8
00000000: ; port_TIMER_CMP EQU &C
00000000: ; port_INT_REQ EQU &18
00000000: ; port_INT_EN EQU &1C
00000000: ;
00000000: ; fpga_area EQU &20000000
00000000: ;
00000000: ; ;------------------------------------------------------------------------------
00000000: ; ; BUTTON constants
00000000: ; ;------------------------------------------------------------------------------
00000000: ; BTN_1 EQU (1 << 3)
00000000: ; BTN_2 EQU (1 << 7)
00000000: ; BTN_3 EQU (1 << 6)
00000000: ; BTN_MASK EQU (BTN_1 | BTN_2 | BTN_3)
00000000: ; ;------------------------------------------------------------------------------
00000000: ;
00000000: ; ;------------------------------------------------------------------------------
00000000: ; ; Interrupt constants
00000000: ; ;------------------------------------------------------------------------------
00000000: ; INT_TIMER_CMP EQU (1 << 0)
00000000: ; INT_SPARTAN EQU (1 << 1)
00000000: ; INT_VIRTEX EQU (1 << 2)
00000000: ; INT_ETHERNET EQU (1 << 3)
00000000: ; INT_SERIAL_RR EQU (1 << 4)
00000000: ; INT_SERIAL_TR EQU (1 << 5)
00000000: ; INT_BTN_UPPER EQU (1 << 6)
00000000: ; INT_BTN_LOWER EQU (1 << 7)
00000000: ;
00000000: ; ;------------------------------------------------------------------------------
00000000: ; ; Buzzer constants
00000000: ; ;------------------------------------------------------------------------------
00000000: ; BUZZER_ENABLE_MASK EQU &8000
00000000: ;
00000000: ; ;------------------------------------------------------------------------------
00000000: ; ORG 0
00000000: ; ;------------------------------------------------------------------------------
00000000: ; ; Exception table
00000000: ; ;------------------------------------------------------------------------------
00000000: ; os_exception_table
00000000: EA000029 ; B os_reset ; reset
00000004: EA000006 ; B os_undefined_instruction ; undefined instruction
00000008: EA00000A ; B os_svc ; SVC
0000000C: EA000005 ; B os_prefetch_abort ; prefetch abort
00000010: EA000005 ; B os_data_abort ; data abort
00000014: EA000005 ; B os_trapper_exception ; -
00000018: EA00001A ; B os_irq ; IRQ
0000001C: EA000004 ; B os_fiq ; FIQ
00000020: ;
00000020: ; ;------------------------------------------------------------------------------
00000020: ; ; Operating system variables
00000020: ; ;------------------------------------------------------------------------------
00000020: 00000000 ; os_tick_count DEFW 0 ; the number of elapsed ms
00000024: ;
00000024: ; ;------------------------------------------------------------------------------
00000024: ; ; os_undefined_instruction() - trapper
00000024: ; ;------------------------------------------------------------------------------
00000024: ; os_undefined_instruction
00000024: EAFFFFFE ; B os_undefined_instruction
00000028: ;
00000028: ; ;------------------------------------------------------------------------------
00000028: ; ; os_prefetch_abort() - trapper
00000028: ; ;------------------------------------------------------------------------------
00000028: ; os_prefetch_abort
00000028: EAFFFFFE ; B os_prefetch_abort
0000002C: ;
0000002C: ; ;------------------------------------------------------------------------------
0000002C: ; ; os_data_abort() - trapper
0000002C: ; ;------------------------------------------------------------------------------
0000002C: ; os_data_abort
0000002C: EAFFFFFE ; B os_data_abort
00000030: ;
00000030: ; ;------------------------------------------------------------------------------
00000030: ; ; os_trapper_exception() - trapper
00000030: ; ;------------------------------------------------------------------------------
00000030: ; os_trapper_exception
00000030: EAFFFFFE ; B os_trapper_exception
00000034: ;
00000034: ; ;------------------------------------------------------------------------------
00000034: ; ; os_fiq() - trapper
00000034: ; ;------------------------------------------------------------------------------
00000034: ; os_fiq
00000034: EAFFFFFE ; B os_fiq
00000038: ;
00000038: ; ;------------------------------------------------------------------------------
00000038: ; ; SVC CALL TYPES
00000038: ; ;------------------------------------------------------------------------------
00000038: ; SVC_EXIT EQU 0
00000038: ; SVC_LCD_LIGHT EQU 1
00000038: ; SVC_LCD_CLEAR EQU 2
00000038: ; SVC_LCD_WRITE EQU 3
00000038: ; SVC_LCD_WRITE_CHAR EQU 4
00000038: ; SVC_LCD_SET_CURSOR EQU 5
00000038: ; SVC_LCD_COMMAND EQU 6
00000038: ; SVC_BUZZ_SET EQU 7
00000038: ; SVC_KEYPAD_SCAN EQU 8
00000038: ;
00000038: ; SVC_SVC_COUNT EQU 9
00000038: ; ;------------------------------------------------------------------------------
00000038: ; ; os_svc() - Runs a supervisor instruction
00000038: ; ;
00000038: ; ; R14 - mode
00000038: ; ;------------------------------------------------------------------------------
00000038: ; os_svc
00000038: E92D4000 ; PUSH {R14} ; push scratch register
0000003C: E51EE004 ; LDR R14, [R14, #-4] ; read SVC instruction
00000040: E3CEE4FF ; BIC R14, R14, #&FF000000 ; mask off opcode
00000044: E35E0009 ; CMP R14, #SVC_SVC_COUNT ; check if SVC instruction exist
; s
00000048: 2AFFFFF5 ; BHS os_undefined_instruction
0000004C: ; os_svc_jump ; SVC switch
0000004C: E08FE10E ; ADD R14, PC, R14, LSL #2
00000050: E59EE010 ; LDR R14, [R14, #(os_svc_jumptable-os_svc_jump-8)]
00000054: E92D4000 ; PUSH {R14}
00000058: E3A0E060 ; MOV R14, #os_svc_return
0000005C: E8BD8000 ; POP {PC}
00000060: ; os_svc_return
00000060: E8FD8000 ; POP {PC}^
00000064: ; os_svc_jumptable ; SVC case jump table
00000064: 00000108 ; DEFW os_exit
00000068: 00000278 ; DEFW lcd_setlight
0000006C: 00000298 ; DEFW lcd_clear
00000070: 000002A8 ; DEFW lcd_putstring
00000074: 000002C4 ; DEFW lcd_putchar
00000078: 000002EC ; DEFW lcd_setcursor
0000007C: 00000308 ; DEFW lcd_command
00000080: 00000130 ; DEFW buzz_set
00000084: 000003F8 ; DEFW keypad_scan
00000088: ;
00000088: ; ;------------------------------------------------------------------------------
00000088: ; ; os_irq() - interrupt handler
00000088: ; ;------------------------------------------------------------------------------
00000088: ; os_irq
00000088: E24EE004 ; SUB LR, LR, #4 ; Convert return address to inte
; rrupted instruction address
0000008C: E92D4007 ; PUSH {R0, R1, R2, LR}
00000090: E3A00201 ; MOV R0, #port_area
00000094: E5901018 ; LDR R1, [R0, #port_INT_REQ] ; Obtain the interrupt request
00000098: E3110001 ; TST R1, #INT_TIMER_CMP ; Test if timer compare
0000009C: 1B00001A ; BLNE os_update_tick_count
000000A0: E3A01000 ; MOV R1, #0 ; Clear the interrupt requests
000000A4: E5801018 ; STR R1, [R0, #port_INT_REQ]
000000A8: E8FD8007 ; POP {R0, R1, R2, PC}^ ; Return to last code and mode
000000AC: ;
000000AC: ; ;------------------------------------------------------------------------------
000000AC: ; ; os_reset() - reset the operating system
000000AC: ; ;
000000AC: ; ; R14 - mode
000000AC: ; ;------------------------------------------------------------------------------
000000AC: ; os_reset
000000AC: E3A0DC79 ; MOV SP, #OFFSET_IRQ ; initialise supervisor stack
000000B0: ;
000000B0: E3A00000 ; MOV R0, #0 ; initialise os variables
000000B4: E3A01020 ; MOV R1, #os_tick_count
000000B8: E5010000 ; STR R0, [R1]
000000BC: ;
000000BC: E3A01000 ; MOV R1, #0
000000C0: E3A00201 ; MOV R0, #port_area
000000C4: E5C01004 ; STRB R1, [R0, #port_LCD_CTRL] ; store port value
000000C8: E3A00202 ; MOV R0, #fpga_area
000000CC: E14010B0 ; STRH R1, [R0] ; store buzzer output
000000D0: ;
000000D0: E321F0D2 ; MSR CPSR_c, #&D2 ; change to IRQ mode
000000D4: E3A0D902 ; MOV SP, #OFFSET_USER ; initialise interrupt stack
000000D8: E3A00201 ; MOV R0, #port_area
000000DC: E3A01000 ; MOV R1, #0 ; clear the interrupt requests
000000E0: E5801018 ; STR R1, [R0, #port_INT_REQ]
000000E4: E3A01001 ; MOV R1, #INT_TIMER_CMP ; enable the timer compare inter
; rupt
000000E8: E580101C ; STR R1, [R0, #port_INT_EN]
000000EC: E3A01001 ; MOV R1, #1 ; set the timer compare to be 1m
; s
000000F0: E580100C ; STR R1, [R0, #port_TIMER_CMP]
000000F4: ;
000000F4: E3A0E050 ; MOV R14, #&50 ; user mode, with interrupts
000000F8: E16FF00E ; MSR SPSR, R14
000000FC: E3A0E902 ; MOV LR, #OFFSET_USER ; set main as the user code entr
; y point
00000100: E28EEFE7 ; ADD LR, LR, #(main-OFFSET_USER)
00000104: E1B0F00E ; MOVS PC, LR ; switch to user code
00000108: ;
00000108: ; ;------------------------------------------------------------------------------
00000108: ; ; os_exit() - ends the program and operating system
00000108: ; ;------------------------------------------------------------------------------
00000108: ; os_exit
00000108: EAFFFFFE ; B os_exit
0000010C: ;
0000010C: ; ;------------------------------------------------------------------------------
0000010C: ; ; os_update_tick_count() - increments the tick count and resets the timer
0000010C: ; ;
0000010C: ; ; R0 - port area address
0000010C: ; ; R1 - ticks
0000010C: ; ; R2 - os tick count variable reference
0000010C: ; ;------------------------------------------------------------------------------
0000010C: ; os_update_tick_count
0000010C: E92D4007 ; PUSH {R0, R1, R2, LR}
00000110: E3A02020 ; MOV R2, #os_tick_count
00000114: E3A00201 ; MOV R0, #port_area
00000118: E3A01000 ; MOV R1, #0 ; Clear the timer
0000011C: E5801008 ; STR R1, [R0, #port_TIMER]
00000120: E5121000 ; LDR R1, [R2] ; Increment the OS tick count
00000124: E2811001 ; ADD R1, R1, #1
00000128: E5021000 ; STR R1, [R2]
0000012C: E8BD8007 ; POP {R0, R1, R2, PC}
00000130: ;
00000130: ; ;------------------------------------------------------------------------------
00000130: ; ; buzz_set() - sets the buzzer to play a certain frequency
00000130: ; ;
00000130: ; ; I R0 - time period
00000130: ; ; I R1 - port
00000130: ; ; R2 - general purpose value
00000130: ; ;------------------------------------------------------------------------------
00000130: ; buzz_set
00000130: E92D400C ; PUSH {R2, R3, LR}
00000134: E3A02202 ; MOV R2, #fpga_area ; get port address
00000138: E0822101 ; ADD R2, R2, R1 LSL #2
0000013C: E1A03420 ; MOV R3, R0, LSR #8 ; store high
00000140: E5C23001 ; STRB R3, [R2, #1]
00000144: E5C20000 ; STRB R0, [R2, #0]
00000148: E8BD800C ; POP {R2, R3, PC}
0000014C: ;
0000014C: ; ;------------------------------------------------------------------------------
0000014C: ; ; memset() - sets a number of bytes to a value
0000014C: ; ; I R0 - address
0000014C: ; ; I R1 - value
0000014C: ; ; I R2 - length
0000014C: ; ;------------------------------------------------------------------------------
0000014C: ; memset
0000014C: E92D4005 ; PUSH {R0, R2, LR}
00000150: ;
00000150: ; memset_loop
00000150: E3520001 ; CMP R2, #1
00000154: A4C01001 ; STRGEB R1, [R0], #1
00000158: A2422001 ; SUBGE R2, R2, #1
0000015C: AAFFFFFB ; BGE memset_loop
00000160: E8BD8005 ; POP {R0, R2, PC}
00000164: ;
00000164: ; ;------------------------------------------------------------------------------
00000164: ; ; has_elapsed_by()
00000164: ; ;
00000164: ; ; IO R0 - address of tick save, output true if so otherwise false
00000164: ; ; I R1 - number of ticks
00000164: ; ;
00000164: ; ; R2 - current tick count
00000164: ; ; R3 - last tick count / elapsed
00000164: ; ;------------------------------------------------------------------------------
00000164: ; has_elapsed_by
00000164: E92D400C ; PUSH {R2, R3, LR}
00000168: E3A02020 ; MOV R2, #os_tick_count ; get current tick
0000016C: E5122000 ; LDR R2, [R2]
00000170: E5103000 ; LDR R3, [R0] ; get last tick
00000174: E0423003 ; SUB R3, R2, R3 ; get elapsed ticks
00000178: E1530001 ; CMP R3, R1 ; check if elapsed ticks > R1
0000017C: B3A00000 ; MOVLT R0, #FALSE
00000180: BA000001 ; BLT has_elapsed_by_return
00000184: E5002000 ; STR R2, [R0] ; set last tick
00000188: E3A00001 ; MOV R0, #TRUE
0000018C: ; has_elapsed_by_return
0000018C: E8BD800C ; POP {R2, R3, PC}
00000190: ;
00000190: ; ;------------------------------------------------------------------------------
00000190: ; INCLUDE lcd.s
00000190: ; ;------------------------------------------------------------------------------
00000190: ; ; LCD functions
00000190: ; ; Ted John
00000190: ; ; Version 1.2
00000190: ; ; 16 April 2013
00000190: ; ;
00000190: ; ; Functions for interfacing with the LCD.
00000190: ; ;
00000190: ; ;------------------------------------------------------------------------------
00000190: ; ; Requires os.s
00000190: ; ;------------------------------------------------------------------------------
00000190: ;
00000190: ; ;------------------------------------------------------------------------------
00000190: ; ; LCD constants
00000190: ; ;------------------------------------------------------------------------------
00000190: ; LCD_E EQU (1 << 0)
00000190: ; LCD_RS EQU (1 << 1)
00000190: ; LCD_RW EQU (1 << 2)
00000190: ; LCD_BACKLIGHT EQU (1 << 5)
00000190: ; LCD_BUSY EQU (1 << 7)
00000190: ;
00000190: ; LCD_CMD_CLEAR EQU &1
00000190: ; LCD_CMD_SETCUR EQU &80
00000190: ;
00000190: ; LCD_CHARS_VISIBLE_PER_LINE EQU 16
00000190: ; LCD_CHARS_PER_LINE EQU 64
00000190: ;
00000190: ; LCD_CHARWRITE EQU (1 << 31)
00000190: ;
00000190: ; ;------------------------------------------------------------------------------
00000190: ; ; LCD_SCROLLER - structure for scrolling text along a line in the LCD
00000190: ; ;------------------------------------------------------------------------------
00000190: ; RECORD
00000190: ; LCD_SCROLLER_TEXT BYTE 256
00000190: ; LCD_SCROLLER_BUFFER BYTE LCD_CHARS_VISIBLE_PER_LINE
00000190: ; LCD_SCROLLER_X WORD
00000190: ; LCD_SCROLLER_Y WORD
00000190: ; LCD_SCROLLER_TEXT_LEN WORD
00000190: ; LCD_SCROLLER_SIZE WORD
00000190: ;
00000190: ; ;------------------------------------------------------------------------------
00000190: ; ; lcd_scroller_set_text()
00000190: ; ;
00000190: ; ; I R0 - lcd_scroller address
00000190: ; ; I R1 - y
00000190: ; ;------------------------------------------------------------------------------
00000190: ; lcd_scroller_init
00000190: E92D400E ; PUSH {R1, R2, R3, LR}
00000194: E1A03001 ; MOV R3, R1
00000198: E3A01000 ; MOV R1, #0
0000019C: E3A02F47 ; MOV R2, #LCD_SCROLLER_SIZE
000001A0: EBFFFFE9 ; BL memset
000001A4: E5803114 ; STR R3, [R0, #LCD_SCROLLER_Y]
000001A8: E8BD800E ; POP {R1, R2, R3, PC}
000001AC: ;
000001AC: ; ;------------------------------------------------------------------------------
000001AC: ; ; lcd_scroller_set_text()
000001AC: ; ;
000001AC: ; ; I R0 - lcd_scroller address
000001AC: ; ; I R1 - source text address
000001AC: ; ;------------------------------------------------------------------------------
000001AC: ; lcd_scroller_set_text
000001AC: E92D400F ; PUSH {R0, R1, R2, R3, LR}
000001B0: E1A03000 ; MOV R3, R0
000001B4: ;
000001B4: E2832000 ; ADD R2, R3, #LCD_SCROLLER_TEXT ; destination text
000001B8: ;
000001B8: E1A00002 ; MOV R0, R2
000001BC: EB0000BF ; BL strcpy
000001C0: EB0000A9 ; BL strlen ; save text length
000001C4: E1A01000 ; MOV R1, R0
000001C8: E5821118 ; STR R1, [R2, #LCD_SCROLLER_TEXT_LEN]
000001CC: ;
000001CC: E0810002 ; ADD R0, R1, R2 ; end of string address
000001D0: E2612C01 ; RSB R2, R1, #&100 ; length of memory
000001D4: E3A01000 ; MOV R1, #0 ; value
000001D8: EBFFFFDB ; BL memset
000001DC: ;
000001DC: E3A00000 ; MOV R0, #0 ; reset x position
000001E0: E5830110 ; STR R0, [R3, #LCD_SCROLLER_X]
000001E4: E1A00003 ; MOV R0, R3 ; update the scroller
000001E8: EB000000 ; BL lcd_scroller_update
000001EC: E8BD800F ; POP {R0, R1, R2, R3, PC}
000001F0: ;
000001F0: ; ;------------------------------------------------------------------------------
000001F0: ; ; lcd_scroller_update()
000001F0: ; ;
000001F0: ; ; I R0 - lcd_scroller address
000001F0: ; ;
000001F0: ; ; R0 - general purpose
000001F0: ; ; R1 - destination character
000001F0: ; ; R2 - text address
000001F0: ; ; R3 - buffer address
000001F0: ; ; R4 - lcd_scoller address
000001F0: ; ; R5 - buffer x position
000001F0: ; ; R6 - buffer y position
000001F0: ; ; R7 - source character
000001F0: ; ;------------------------------------------------------------------------------
000001F0: ; lcd_scroller_update
000001F0: E92D40FF ; PUSH {R0, R1, R2, R3, R4, R5, R6, R7, LR}
000001F4: E1A04000 ; MOV R4, R0
000001F8: ;
000001F8: E3A05000 ; MOV R5, #0 ; set buffer x to 0
000001FC: E5946114 ; LDR R6, [R4, #LCD_SCROLLER_Y] ; get y position (line index)
00000200: E2842000 ; ADD R2, R4, #LCD_SCROLLER_TEXT ; get text address (R2)
00000204: E5940110 ; LDR R0, [R4, #LCD_SCROLLER_X] ; skip x characters
00000208: E0822000 ; ADD R2, R2, R0
0000020C: E2843C01 ; ADD R3, R4, #LCD_SCROLLER_BUFFER ; get buffer cache address (R3)
00000210: ;
00000210: ; lcd_scroller_update_loop
00000210: E5527000 ; LDRB R7, [R2] ; get source character
00000214: E5531000 ; LDRB R1, [R3] ; get destination character
00000218: E1570001 ; CMP R7, R1 ; check if we need to update buf
; fer
0000021C: 0A000005 ; BEQ lcd_scroller_update_next
00000220: ;
00000220: E1A00005 ; MOV R0, R5 ; x position
00000224: E1A01006 ; MOV R1, R6
00000228: EF000005 ; SVC SVC_LCD_SET_CURSOR
0000022C: E1A00007 ; MOV R0, R7 ; character to write
00000230: EF000004 ; SVC SVC_LCD_WRITE_CHAR
00000234: E5437000 ; STRB R7, [R3] ; update buffer cache
00000238: ;
00000238: ; lcd_scroller_update_next
00000238: E2822001 ; ADD R2, R2, #1 ; next character
0000023C: E2833001 ; ADD R3, R3, #1
00000240: E2855001 ; ADD R5, R5, #1
00000244: E3550010 ; CMP R5, #LCD_CHARS_VISIBLE_PER_LINE ; check if whole buffer has been
; updated
00000248: BAFFFFF0 ; BLT lcd_scroller_update_loop
0000024C: ;
0000024C: ; lcd_scroller_update_end
0000024C: E5940118 ; LDR R0, [R4, #LCD_SCROLLER_TEXT_LEN] ; get string length
00000250: E3500010 ; CMP R0, #LCD_CHARS_VISIBLE_PER_LINE ; no scrolling if text length <
; LCD_CHARS_VISIBLE_PER_LINE
00000254: DA000006 ; BLE lcd_scroller_update_return
00000258: ;
00000258: E240000F ; SUB R0, R0, #(LCD_CHARS_VISIBLE_PER_LINE-1) ; give some spaces after the str
; ing when scrolling
0000025C: E5941110 ; LDR R1, [R4, #LCD_SCROLLER_X] ; get current x
00000260: E2811001 ; ADD R1, R1, #1 ; increment current x
00000264: E1510000 ; CMP R1, R0 ; check if ready to reset x
00000268: BA000000 ; BLT lcd_scroller_update_save_x
0000026C: E3A01000 ; MOV R1, #0 ; reset x
00000270: ; lcd_scroller_update_save_x
00000270: E5841110 ; STR R1, [R4, #LCD_SCROLLER_X] ; set current x
00000274: ; lcd_scroller_update_return
00000274: E8BD80FF ; POP {R0, R1, R2, R3, R4, R5, R6, R7, PC}
00000278: ;
00000278: ; ;------------------------------------------------------------------------------
00000278: ; ; lcd_setlight() - sets the backlight of the LCD to either on or off
00000278: ; ;
00000278: ; ; I R0 - TRUE to turn the backlight on, FALSE to turn it off
00000278: ; ; R1 - port area
00000278: ; ; R2 - port area value
00000278: ; ;------------------------------------------------------------------------------
00000278: ; lcd_setlight
00000278: E92D4006 ; PUSH {R1, R2, LR}
0000027C: E3A01201 ; MOV R1, #port_area
00000280: E5D12004 ; LDRB R2, [R1, #port_LCD_CTRL] ; load port value
00000284: E3500000 ; CMP R0, #FALSE ; set backlight bit based on argu
; ment
00000288: 13822020 ; ORRNE R2, R2, #LCD_BACKLIGHT
0000028C: 03C22020 ; BICEQ R2, R2, #LCD_BACKLIGHT
00000290: E5C12004 ; STRB R2, [R1, #port_LCD_CTRL] ; store port value
00000294: E8BD8006 ; POP {R1, R2, PC}
00000298: ;
00000298: ; ;------------------------------------------------------------------------------
00000298: ; ; lcd_clear() - clears the LCD display
00000298: ; ;
00000298: ; ; R0 - command
00000298: ; ;------------------------------------------------------------------------------
00000298: ; lcd_clear
00000298: E92D4001 ; PUSH {R0, LR}
0000029C: E3A00001 ; MOV R0, #LCD_CMD_CLEAR
000002A0: EB000018 ; BL lcd_command
000002A4: E8BD8001 ; POP {R0, PC}
000002A8: ;
000002A8: ; ;------------------------------------------------------------------------------
000002A8: ; ; lcd_putstring() - writes a null terminated string to the LCD
000002A8: ; ;
000002A8: ; ; I R0 - address of string (first character)
000002A8: ; ; R0 - current character value
000002A8: ; ; R1 - address of character position
000002A8: ; ;------------------------------------------------------------------------------
000002A8: ; lcd_putstring
000002A8: E92D4003 ; PUSH {R0, R1, LR}
000002AC: E1A01000 ; MOV R1, R0 ; use another register for strin
; g address
000002B0: ; lcd_putstring_loop
000002B0: E4D10001 ; LDRB R0, [R1], #1 ; read character
000002B4: E3500000 ; CMP R0, #0 ; check if null terminator reach
; ed
000002B8: 08BD8003 ; POPEQ {R0, R1, PC} ; return
000002BC: E24FE014 ; ADR LR, lcd_putstring_loop ; write the character and then l
; oop
000002C0: EAFFFFFF ; B lcd_putchar
000002C4: ;
000002C4: ; ;------------------------------------------------------------------------------
000002C4: ; ; lcd_putchar() - writes an ascii character to the LCD
000002C4: ; ;
000002C4: ; ; I R0 - ascii character to write
000002C4: ; ;------------------------------------------------------------------------------
000002C4: ; lcd_putchar
000002C4: E92D4001 ; PUSH {R0, LR}
000002C8: E3500000 ; CMP R0, #0 ; change char 0 to space
000002CC: 03A00020 ; MOVEQ R0, #' '
000002D0: E3800102 ; ORR R0, R0, #LCD_CHARWRITE ; set write character flag
000002D4: EB00000B ; BL lcd_command
000002D8: E8BD8001 ; POP {R0, PC}
000002DC: ;
000002DC: ; ;------------------------------------------------------------------------------
000002DC: ; ; lcd_setcursor() - sets the LCD cursor position
000002DC: ; ;
000002DC: ; ; I R0 - x position
000002DC: ; ; I R1 - y position
000002DC: ; ;------------------------------------------------------------------------------
000002DC: ; lcd_setcursor_line_offsets ; lookup table for line start of
; fsets
000002DC: 00000000 ; DEFW (LCD_CHARS_PER_LINE * 0)
000002E0: 00000040 ; DEFW (LCD_CHARS_PER_LINE * 1)
000002E4: 00000080 ; DEFW (LCD_CHARS_PER_LINE * 2)
000002E8: 000000C0 ; DEFW (LCD_CHARS_PER_LINE * 3)
000002EC: ; lcd_setcursor
000002EC: E92D4005 ; PUSH {R0, R2, LR}
000002F0: E24F201C ; ADRL R2, lcd_setcursor_line_offsets ; get line start offset
000002F4: E7922101 ; LDR R2, [R2, R1 LSL #2]
000002F8: E0822000 ; ADD R2, R2, R0 ; add x position
000002FC: E2820080 ; ADD R0, R2, #LCD_CMD_SETCUR ; produce lcd command
00000300: EB000000 ; BL lcd_command
00000304: E8BD8005 ; POP {R0, R2, PC}
00000308: ;
00000308: ; ;------------------------------------------------------------------------------
00000308: ; ; lcd_command() - sends a command or character to the LCD
00000308: ; ;
00000308: ; ; I R0 - command (set bit LCD_CHARWRITE for character write)
00000308: ; ; R1 - port area address
00000308: ; ; R2 - data register
00000308: ; ;------------------------------------------------------------------------------
00000308: ; lcd_command
00000308: E92D4006 ; PUSH {R1, R2, LR}
0000030C: E3A01201 ; MOV R1, #port_area ; keep port address in R1
00000310: EB00000B ; BL lcd_wait_until_ready
00000314: E5D12004 ; LDRB R2, [R1, #port_LCD_CTRL] ; read from control port
00000318: E3C22004 ; BIC R2, R2, #LCD_RW ; set write signal
0000031C: ;
0000031C: E3100102 ; TST R0, #LCD_CHARWRITE ; test command / character flag
00000320: 13822002 ; ORRNE R2, R2, #LCD_RS ; set data port IO
00000324: 03C22002 ; BICEQ R2, R2, #LCD_RS ; set control port IO
00000328: ;
00000328: E5C12004 ; STRB R2, [R1, #port_LCD_CTRL] ; write to control port
0000032C: E5C10000 ; STRB R0, [R1, #port_LCD_DATA] ; write data port
00000330: E3822001 ; ORR R2, R2, #LCD_E ; enable bus
00000334: E5C12004 ; STRB R2, [R1, #port_LCD_CTRL] ; write to control port
00000338: E3C22001 ; BIC R2, R2, #LCD_E ; disable bus
0000033C: E5C12004 ; STRB R2, [R1, #port_LCD_CTRL] ; write to control port
00000340: E8BD8006 ; POP {R1, R2, PC}
00000344: ;
00000344: ; ;------------------------------------------------------------------------------
00000344: ; ; lcd_wait_until_ready() - waits until the LCD display is ready
00000344: ; ;
00000344: ; ; R0 - port area address
00000344: ; ; R1 - control register
00000344: ; ; R2 - data register
00000344: ; ;------------------------------------------------------------------------------
00000344: ; lcd_wait_until_ready
00000344: E92D4007 ; PUSH {R0, R1, R2, LR}
00000348: E3A00201 ; MOV R0, #port_area ; keep port address in R0
0000034C: E5D01004 ; LDRB R1, [R0, #port_LCD_CTRL] ; read control port
00000350: E3811004 ; ORR R1, R1, #LCD_RW ; set read signal
00000354: E3C11002 ; BIC R1, R1, #LCD_RS ; set control register
00000358: E5C01004 ; STRB R1, [R0, #port_LCD_CTRL] ; write control port
0000035C: ; lcd_wait_until_ready_loop
0000035C: E3811001 ; ORR R1, R1, #LCD_E ; enable bus
00000360: E5C01004 ; STRB R1, [R0, #port_LCD_CTRL] ; write control port
00000364: E5D02000 ; LDRB R2, [R0, #port_LCD_DATA] ; read data port
00000368: E3C11001 ; BIC R1, R1, #LCD_E ; disable bus
0000036C: E5C01004 ; STRB R1, [R0, #port_LCD_CTRL] ; write control port
00000370: E3120080 ; TST R2, #LCD_BUSY ; test busy bit
00000374: 1AFFFFF8 ; BNE lcd_wait_until_ready_loop
00000378: E8BD8007 ; POP {R0, R1, R2, PC}
0000037C: ;
0000037C: ; INCLUDE keypad.s
0000037C: ; ;------------------------------------------------------------------------------
0000037C: ; ; Keypad peripheral functions
0000037C: ; ; Ted John
0000037C: ; ; Version 1.0
0000037C: ; ; 26th February 2013
0000037C: ; ;
0000037C: ; ; Functions for reading the keys.
0000037C: ; ;
0000037C: ; ;------------------------------------------------------------------------------
0000037C: ; ; Requires os.s
0000037C: ; ;------------------------------------------------------------------------------
0000037C: ;
0000037C: ; ;------------------------------------------------------------------------------
0000037C: ; ; Keypad constants
0000037C: ; ;------------------------------------------------------------------------------
0000037C: ; KEYPAD_ROW_1 EQU (1 << 0)
0000037C: ; KEYPAD_ROW_2 EQU (1 << 1)
0000037C: ; KEYPAD_ROW_3 EQU (1 << 2)
0000037C: ; KEYPAD_ROW_4 EQU (1 << 3)
0000037C: ; KEYPAD_UNKOWN EQU (1 << 4)
0000037C: ; KEYPAD_COL_3 EQU (1 << 5)
0000037C: ; KEYPAD_COL_2 EQU (1 << 6)
0000037C: ; KEYPAD_COL_1 EQU (1 << 7)
0000037C: ; KEYPAD_ROWS EQU (KEYPAD_ROW_1 | KEYPAD_ROW_2 | KEYPAD_ROW_3 | KEYPAD_ROW_4)
0000037C: ; KEYPAD_COLS EQU (KEYPAD_COL_1 | KEYPAD_COL_2 | KEYPAD_COL_3)
0000037C: ;
0000037C: ; KEYPAD_NOBUTTON EQU -1
0000037C: ; KEYPAD_IDX_ASTERISK EQU 9
0000037C: ; KEYPAD_IDX_0 EQU 10
0000037C: ; KEYPAD_IDX_HASH EQU 11
0000037C: ;
0000037C: ; ;------------------------------------------------------------------------------
0000037C: ; keypad_variables
0000037C: 20000000 ; keypad_port DEFW fpga_area
00000380: ;
00000380: ; keypad_button_index_table
00000380: 00 03 06 09 ; DEFB 0, 3, 6, 9
00000384: 01 04 07 0A ; DEFB 1, 4, 7, 10
00000388: 02 05 08 0B ; DEFB 2, 5, 8, 11
0000038C: ;
0000038C: ; keypad_ascii_table
0000038C: 31 32 33 ; DEFB '1', '2', '3'
0000038F: 34 35 36 ; DEFB '4', '5', '6'
00000392: 37 38 39 ; DEFB '7', '8', '9'
00000395: 2A 30 23 ; DEFB '*', '0', '#'
00000398: ;
00000398: ; ;------------------------------------------------------------------------------
00000398: ; ; keypad_get_new_presses()
00000398: ; ;
00000398: ; ; IO R0 - last scan (output new keys)
00000398: ; ; I R1 - new scan
00000398: ; ;------------------------------------------------------------------------------
00000398: ; keypad_get_new_presses
00000398: E0200001 ; EOR R0, R0, R1
0000039C: E0000001 ; AND R0, R0, R1
000003A0: E1A0F00E ; MOV PC, LR
000003A4: ;
000003A4: ; ;------------------------------------------------------------------------------
000003A4: ; ; keypad_button_index_to_ascii() - returns the ascii character for the
000003A4: ; ; specified button index
000003A4: ; ;
000003A4: ; ; IO R0 - index (ouput ascii)
000003A4: ; ;------------------------------------------------------------------------------
000003A4: ; keypad_button_index_to_ascii
000003A4: E3700001 ; CMP R0, #KEYPAD_NOBUTTON
000003A8: 03A00000 ; MOVEQ R0, #0
000003AC: 01A0F00E ; MOVEQ PC, LR
000003B0: E2800FE3 ; ADD R0, R0, #keypad_ascii_table
000003B4: E5500000 ; LDRB R0, [R0]
000003B8: E1A0F00E ; MOV PC, LR
000003BC: ;
000003BC: ; ;------------------------------------------------------------------------------
000003BC: ; ; keypad_scan_read_index() - returns the button index for the first found
000003BC: ; ; corresponding bit, the bit is then cleared
000003BC: ; ;
000003BC: ; ; IO R0 - scan (output with first found bit cleared)
000003BC: ; ; O R1 - bit index (output button index)
000003BC: ; ; R2 - bit mask
000003BC: ; ;------------------------------------------------------------------------------
000003BC: ; keypad_scan_read_index
000003BC: E92D4004 ; PUSH {R2, LR}
000003C0: E3A01000 ; MOV R1, #0 ; initialise index and mask
000003C4: E3A02001 ; MOV R2, #1
000003C8: ; keypad_scan_read_ascii_loop
000003C8: E1100002 ; TST R0, R2 ; test scan bit
000003CC: 1A000005 ; BNE keypad_scan_read_ascii_found
000003D0: E351000B ; CMP R1, #11 ; check if all bits have been te
; sted
000003D4: 03E01000 ; MOVEQ R1, #KEYPAD_NOBUTTON
000003D8: 08BD8004 ; POPEQ {R2, PC}
000003DC: E2811001 ; ADD R1, R1, #1 ; increment index and mask
000003E0: E1A02082 ; MOV R2, R2, LSL #1
000003E4: EAFFFFF7 ; B keypad_scan_read_ascii_loop
000003E8: ; keypad_scan_read_ascii_found
000003E8: E1C00002 ; BIC R0, R0, R2 ; clear tested bit
000003EC: E2811D0E ; ADD R1, R1, #keypad_button_index_table
000003F0: E5511000 ; LDRB R1, [R1]
000003F4: E8BD8004 ; POP {R2, PC}
000003F8: ;
000003F8: ; ;------------------------------------------------------------------------------
000003F8: ; ; keypad_scan() - scans the keypad and updates the changed key states
000003F8: ; ;
000003F8: ; ; O R0 - result scan (output)
000003F8: ;
000003F8: ; ; R1 - scan shift
000003F8: ; ; R2 - control bits
000003F8: ; ; R3 - port
000003F8: ; ; R4 - data bits
000003F8: ; ;------------------------------------------------------------------------------
000003F8: ; keypad_scan
000003F8: E92D401E ; PUSH {R1, R2, R3, R4, LR}
000003FC: ;
000003FC: E51F3088 ; LDR R3, keypad_port
00000400: E3A0201F ; MOV R2, #(KEYPAD_ROWS | KEYPAD_UNKOWN) ; Set everything to input apart
; from the column selectors
00000404: E5C32003 ; STRB R2, [R3, #3]
00000408: ;
00000408: E3A00000 ; MOV R0, #0 ; Initialise result scan
0000040C: E3A01000 ; MOV R1, #0
00000410: E3A02080 ; MOV R2, #KEYPAD_COL_1
00000414: ; keypad_scan_loop
00000414: E5C32002 ; STRB R2, [R3, #2] ; Store output control bits (col
; umn selector)
00000418: E5D34002 ; LDRB R4, [R3, #2] ; Load data bits
0000041C: E204400F ; AND R4, R4, #KEYPAD_ROWS ; Place it into the scan result
00000420: E1A04114 ; MOV R4, R4, LSL R1
00000424: E1800004 ; ORR R0, R0, R4
00000428: E3520020 ; CMP R2, #KEYPAD_COL_3 ; Check if all columns have been
; scanned
0000042C: 11A020A2 ; MOVNE R2, R2, LSR #1 ; Select next column
00000430: 12811004 ; ADDNE R1, R1, #4
00000434: 1AFFFFF6 ; BNE keypad_scan_loop
00000438: E8BD801E ; POP {R1, R2, R3, R4, PC}
0000043C: ;
0000043C: ; INCLUDE math.s
0000043C: ; ;------------------------------------------------------------------------------
0000043C: ; ; Maths functions
0000043C: ; ; Ted John
0000043C: ; ; Version 1.0
0000043C: ; ; 12th February 2013
0000043C: ; ;
0000043C: ; ; Functions for any mathematical functions.
0000043C: ; ;
0000043C: ; ;------------------------------------------------------------------------------
0000043C: ;
0000043C: ; ;------------------------------------------------------------------------------
0000043C: ; ; udivision() - performs an unsigned division, taken from example
0000043C: ; ; by J.G.
0000043C: ; ;
0000043C: ; ; IO R0 - numerator (updated to quotient)
0000043C: ; ; I R1 - denominator
0000043C: ; ; O R2 - remainder (output only)
0000043C: ; ;
0000043C: ; ; R3 - loop counter
0000043C: ; ;------------------------------------------------------------------------------
0000043C: ; udivision
0000043C: E92D4008 ; PUSH {R3, LR}
00000440: ;
00000440: E3A02000 ; MOV R2, #0 ; AccH
00000444: E3A03020 ; MOV R3, #32 ; Number of bits in division
00000448: E0900000 ; ADDS R0, R0, R0 ; Shift dividend
0000044C: ; udivision_loop
0000044C: E0A22002 ; ADC R2, R2, R2 ; Shift AccH, carry into LSB
00000450: E1520001 ; CMP R2, R1 ; Will it go?
00000454: 20422001 ; SUBHS R2, R2, R1 ; If so, subtract
00000458: E0B00000 ; ADCS R0, R0, R0 ; Shift dividend & Acc. result
0000045C: E2433001 ; SUB R3, R3, #1 ; Loop count
00000460: E1130003 ; TST R3, R3 ; Leaves carry alone
00000464: 1AFFFFF8 ; BNE udivision_loop ; Repeat as required
00000468: E8BD8008 ; POP {R3, PC}
0000046C: ;
0000046C: ;
0000046C: ; INCLUDE string.s
0000046C: ; ;------------------------------------------------------------------------------
0000046C: ; ; String and LCD functions
0000046C: ; ; Ted John
0000046C: ; ; Version 1.1
0000046C: ; ; 24th February 2013
0000046C: ; ;
0000046C: ; ; Functions for manipulating strings and interfacing with the LCD.
0000046C: ; ;
0000046C: ; ;------------------------------------------------------------------------------
0000046C: ; ; Requires math.s
0000046C: ; ;------------------------------------------------------------------------------
0000046C: ;
0000046C: ; INT2STR_SPACES EQU &80000000
0000046C: ;
0000046C: ; ;------------------------------------------------------------------------------
0000046C: ; ; strlen() - gets the length of a string
0000046C: ; ;
0000046C: ; ; IO R0 - source string address, changed to length of string
0000046C: ; ;------------------------------------------------------------------------------
0000046C: ; strlen
0000046C: E92D4002 ; PUSH {R1, LR}
00000470: E1A01000 ; MOV R1, R0 ; save start address
00000474: EB000001 ; BL strend ; find end address
00000478: E0400001 ; SUB R0, R0, R1 ; return difference
0000047C: E8BD8002 ; POP {R1, PC}
00000480: ;
00000480: ; ;------------------------------------------------------------------------------
00000480: ; ; strend() - gets the address of the string terminator character
00000480: ; ;
00000480: ; ; IO R0 - source string / terminator address
00000480: ; ;------------------------------------------------------------------------------
00000480: ; strend
00000480: E92D4002 ; PUSH {R1, LR}
00000484: ; strend_loop
00000484: E4D01001 ; LDRB R1, [R0], #1 ; find string terminator
00000488: E3510000 ; CMP R1, #0
0000048C: 1AFFFFFC ; BNE strend_loop
00000490: E2400001 ; SUB R0, R0, #1
00000494: E8BD8002 ; POP {R1, PC}
00000498: ;
00000498: ; ;------------------------------------------------------------------------------
00000498: ; ; appendchar() - appends an ascii character to the end of a string
00000498: ; ;
00000498: ; ; I R0 - destination string address
00000498: ; ; I R1 - ascii character to append
00000498: ; ;------------------------------------------------------------------------------
00000498: ; appendchar
00000498: E92D4003 ; PUSH {R0, R1, LR}
0000049C: ; appendchar_loop
0000049C: EBFFFFF7 ; BL strend
000004A0: E5401000 ; STRB R1, [R0] ; overwrite the terminator with
; the character
000004A4: E3A01000 ; MOV R1, #0 ; write a new terminator
000004A8: E5C01001 ; STRB R1, [R0, #1]
000004AC: E8BD8003 ; POP {R0, R1, PC}
000004B0: ;
000004B0: ; ;------------------------------------------------------------------------------
000004B0: ; ; strcat() - appends a source string to the end of a destination string
000004B0: ; ;
000004B0: ; ; I R0 - destination string address
000004B0: ; ; I R1 - source string address
000004B0: ; ;------------------------------------------------------------------------------
000004B0: ; strcat
000004B0: E92D4001 ; PUSH {R0, LR}
000004B4: EBFFFFF1 ; BL strend
000004B8: EB000000 ; BL strcpy
000004BC: E8BD8001 ; POP {R0, PC}
000004C0: ;
000004C0: ; ;------------------------------------------------------------------------------
000004C0: ; ; strcpy() - copies a source string to a destination address
000004C0: ; ;
000004C0: ; ; I R0 - destination string address
000004C0: ; ; I R1 - source string address
000004C0: ; ;------------------------------------------------------------------------------
000004C0: ; strcpy
000004C0: E92D4007 ; PUSH {R0, R1, R2, LR}
000004C4: ; strcpy_loop
000004C4: E4D12001 ; LDRB R2, [R1], #1 ; copy character
000004C8: E4C02001 ; STRB R2, [R0], #1
000004CC: E3520000 ; CMP R2, #0 ; check if string terminator
000004D0: 1AFFFFFB ; BNE strcpy_loop
000004D4: E8BD8007 ; POP {R0, R1, R2, PC}
000004D8: ;
000004D8: ; ;------------------------------------------------------------------------------
000004D8: ; ; int2str() - converts a 32-bit integer from a register and writes it to
000004D8: ; ; a string buffer with a specified number width (0s or spaces)
000004D8: ; ;
000004D8: ; ; IO R0 - string buffer (updated to address of character directly after the last digit)
000004D8: ; ; I R1 - integer
000004D8: ; ; I R2 - minimum length (INT2STR_SPACES specifies whether to use spaces (set) or numbers (clea
; r))
000004D8: ; ;
000004D8: ; ; R0 - integer as its divided or temp
000004D8: ; ; R1 - divisor (always 10)
000004D8: ; ; R2 - remainder (digit)
000004D8: ; ; R3 - string start address (after negative sign)
000004D8: ; ; R4 - string current address
000004D8: ; ; R5 - string end address
000004D8: ; ; R6 - minimum length (backup)
000004D8: ; ;------------------------------------------------------------------------------
000004D8: ; int2str
000004D8: E92D407E ; PUSH {R1, R2, R3, R4, R5, R6, LR}
000004DC: ;
000004DC: E1A03000 ; MOV R3, R0 ; set the string address pointer
; s
000004E0: E1A04000 ; MOV R4, R0
000004E4: E1A06002 ; MOV R6, R2 ; move minimum length to a diffe
; rent register
000004E8: ;
000004E8: E3510000 ; CMP R1, #0 ; check if input number is 0 (sp
; ecial case)
000004EC: 1A000002 ; BNE int2str_negative_check
000004F0: E3A00030 ; MOV R0, #'0' ; just append a single ascii 0
000004F4: E4C40001 ; STRB R0, [R4], #1
000004F8: EA00000D ; B int2str_digit_finalise ; jump to the finalise code
000004FC: ;
000004FC: ; int2str_negative_check
000004FC: E1110001 ; TST R1, R1 ; check if input number is negat
; ive
00000500: 5A000003 ; BPL int2str_digit_write
00000504: E3A0002D ; MOV R0, #'-' ; store ascii negative sign, inc
; rement address
00000508: E4C40001 ; STRB R0, [R4], #1
0000050C: E2611000 ; RSB R1, R1, #0 ; perform 2's complement, (inver
; t bits and add 1)
00000510: E1A03004 ; MOV R3, R4 ; set start of string address as
; well, (negative sign is not included in reorder)
00000514: ;
00000514: ; int2str_digit_write
00000514: E1A00001 ; MOV R0, R1 ; set left over digits to input
; number
00000518: E3A0100A ; MOV R1, #10
0000051C: ; int2str_digit_write_loop
0000051C: E3500000 ; CMP R0, #0 ; check if there are any left ov
; er digits
00000520: 0A000003 ; BEQ int2str_digit_finalise
00000524: EBFFFFC4 ; BL udivision
00000528: E2822030 ; ADD R2, R2, #'0' ; convert remainder to ascii
0000052C: E4C42001 ; STRB R2, [R4], #1 ; store ascii digit, increment a
; ddress
00000530: EAFFFFF9 ; B int2str_digit_write_loop
00000534: ;
00000534: ; int2str_digit_finalise
00000534: E3C65102 ; BIC R5, R6, #INT2STR_SPACES ; get minimum length of string
00000538: E0855003 ; ADD R5, R5, R3 ; add string start address
0000053C: E1550004 ; CMP R5, R4 ; check if end address is less t
; han current address
00000540: B1A05004 ; MOVLT R5, R4 ; if so then set end address t
; o current address
00000544: ;
00000544: ; int2str_digit_fill
00000544: DA000006 ; BLE int2str_digit_reverse ; skip this step if number was l
; onger than minimum length
00000548: E3A00030 ; MOV R0, #'0'
0000054C: E3160102 ; TST R6, #INT2STR_SPACES ; if sign bit set, use spaces in
; stead of zeros
00000550: 13A00020 ; MOVNE R0, #' '
00000554: E3C66102 ; BIC R6, R6, #INT2STR_SPACES ; clear sign bit so it is just t
; he length
00000558: ; int2str_digit_fill_loop
00000558: E4C40001 ; STRB R0, [R4], #1 ; append the padding ascii value
; until we have reached the minimum length
0000055C: E1540005 ; CMP R4, R5
00000560: BAFFFFFC ; BLT int2str_digit_fill_loop
00000564: ;
00000564: ; int2str_digit_reverse
00000564: E2444001 ; SUB R4, R4, #1
00000568: ; int2str_digit_reverse_loop
00000568: E5530000 ; LDRB R0, [R3] ; load character a and b
0000056C: E5541000 ; LDRB R1, [R4]
00000570: E4440001 ; STRB R0, [R4], #-1 ; store characters in swapped lo
; cations and adjust pointers
00000574: E4C31001 ; STRB R1, [R3], #1
00000578: E1530004 ; CMP R3, R4 ; check if left pointer and righ
; t pointer have met up or crossed over
0000057C: BAFFFFF9 ; BLT int2str_digit_reverse_loop
00000580: ;
00000580: E3A00000 ; MOV R0, #0
00000584: E5450000 ; STRB R0, [R5] ; null terminate
00000588: E1A00005 ; MOV R0, R5 ; set R0 to address of character
; after number
0000058C: E8BD807E ; POP {R1, R2, R3, R4, R5, R6, PC}
00000590: ;
00000590: ;
00000590: ;
00000590: ;
00000590: ;
00000590: ; ;------------------------------------------------------------------------------
00008000: ; ORG OFFSET_USER
00008000: ;
00008000: ; ;------------------------------------------------------------------------------
00008000: ; ;
00008000: ; ;------------------------------------------------------------------------------
00008000: ; STATE_ABOUT EQU 0
00008000: ; STATE_STOPPED EQU 1
00008000: ; STATE_PLAYING EQU 2
00008000: ; STATE_FINISHED EQU 3
00008000: ; STATE_END EQU 4
00008000: ;
00008000: ; ;------------------------------------------------------------------------------
00008000: ; ; Program variables
00008000: ; ;------------------------------------------------------------------------------
00008000: ; module_project DEFS MODULE_PROJECT_SIZE
00008010: ; module_ui DEFS MODULE_UI_SIZE
00008358: ; module_player DEFS MODULE_PLAYER_SIZE
0000839C: ; ALIGN
0000839C: ;
0000839C: ; ;------------------------------------------------------------------------------
0000839C: ; ; main() - user program entry point
0000839C: ; ;
0000839C: ; ; R7 - port i/o
0000839C: ; ;------------------------------------------------------------------------------
0000839C: ; main
0000839C: E3A0DB9F ; MOV SP, #OFFSET_ENDRAM ; initialise user stack pointer
000083A0: ;
000083A0: E3A03902 ; MOV R3, #OFFSET_USER
000083A4: E2830000 ; ADD R0, R3, #(module_project-OFFSET_USER)
000083A8: E2831010 ; ADD R1, R3, #(module_ui-OFFSET_USER)
000083AC: E2832FD6 ; ADD R2, R3, #(module_player-OFFSET_USER)
000083B0: EB000002 ; BL project_init ; initialise the project module