summaryrefslogtreecommitdiffstats
path: root/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/SCATTER/README.TXT
blob: 5748912a3f2c9d21984007da2fd8f5335f868357 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
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
		Use Of The Linker For Scatter Loading
		-------------------------------------

Version 0.1 	Apr 1995	Laurence Bond
Version 1.0 	May 1995	Laurence Bond

Introduction
------------

This application note describes an example which uses uses the linker to produce
a scatter loaded application with overlays. The linker section in the Software
Development Toolkit manual should read in conjunction with this note. Other
information can be found in the Programming Techinques manual.

The example will work only with Tools 200 Beta or later.

Example Memory Structure
------------------------
In this example the memory is assumed to have the following structure

		0x00000 - 0x3FFFF - Unused
		0x40000 - 0x43FFF - SRAM
		0x44000 - 0x7FFFF - Unused
		0x80000 - 0x9FFFF - ROM

Overlays will be placed in ROM and copied into the SRAM when needed. Also the
overlay manager and all read/write initialised data will be copied into the
SRAM.

Overlay Manager
---------------
The linker does not provide the overlay manager. The overlay manager is user
supplied code which controls the overlay mechanism. The linker produces the
appropriate binary files and constructs the PCITs (Procedure Call Indirection
Tables).
The overlay manager must define two publicly visible symbols
Image$$overlay_init and Image$$load_seg.

Image$$overlay_init is used to initialise the overlay manager.
Image$$overlay_init does not get called automatically. However it should be
called just after the application has been entered. This is the case in this
example although the routine just returns to the caller. The initialisation
of the overlay manager workspace would done as part of the initialisation
of the scatter loaded image.

Image$$load_seg is the procedure that performs the functions of the overlay
manager described in the Software Development toolkit manual. 

The overlay manager listed in Appendix A works with 32 bit processor modes only.
It is operating system independent. The code area is  read-only. The flag
used to indicate whether the overlay manager has initialised its workspace is
in a read-write area of its own. The code to load a segment uses the linker
generated table that relates PCIT section addresses to the location of the
overlay segments in their load regions. The address of this table is bound to
the linker generated symbol Root$$OverlayTable.

To aid operating system independence, two routines are be called by the
overlay manager. These should could have replaced by inline code. However to aid
clarity, this has not been done. The routines are:

	MemCopy
		r0 - Destination address
		r1 - Source Address
		r2 - Block length in bytes

	This routine does not return anything.

	SevereErrorHandler
		r0 - A value indicating which error condition has occurred.

	This symbol is a weak reference and need not be resolved. In the example
	no such routine is provided. However in a real application one should be
	provided.


A Pitfall In Using The C library
--------------------------------
In this example, a the C library was found to interfere with loaded segments.
The reason is that in the default C library, the heap is initialised to start
at the address Image$$RW$$Limit.

For example, the segments could get corrupted by use of the memory
allocation package if they are located to an address greater that this. A malloc
could grab some memory from the heap which just happened to be part of an
overlayed segments code. Similarly loading an overlay segment could result in
the segment data being loaded into an area used by the heap, thereby corrupting
the heap. In this application the default libraray is used. The data allcoated
on the heap is sufficently smaller that it fits between the end of the root
read/write execution region and the start of the root read only execution
region. If one were to examine the memory immediately above the address
Image$$RW$$Limit one will find the data buffers used by the standard input and
output channels.


The Example Application
-----------------------
The example application reads a sequence of characters, terminated either by
end of file or a newline, from stdin. These characters are then UU encoded and 
output to stdout.

The application consists of 3 C source files and two assembler files excluding
the overlay manager. The C files are as follows:

	getdata.c
	This defines a function, getData, which reads the characters into a
	buffer passed to it by the main program. 

	uue.c
	This defines a function, uue, which takes an input buffer passed
	in by the main program and writes the UU encoded equivalent into 
	another buffer supplied by the main program.

	main.c
	This contains the C main program and example implementations of
	the functions LoadOverlaySegment and MemCopy needed by the overlay
	manager. Two statically allocated data buffers are also defined.

	The main program calls getData to read data into a buffer. This buffer
	is then passed to uue as the input buffer. The output buffer is zero
	terminated after uue returns and the results written to stdout.

	MemCopy is just a call to memmove - a standard C library function.

Together with the overlay manager these C files could define the whole
application. However the initialisation of the image is not done by any code in
these source modules. 

A new entry point is required which initialises the application and the overlay manager. This supplied by the file maininit.s .
The source code except for the overlay manager can be found in Appendix B.

The buffers defined in main.c will be read-write data in the root read/write
execution region.The  assembler entry point code, the functions defined in
main.c and any C library functions extracted from the library will be in the
root read only execution region. The overlay manager and its initialised data
will be moved to address 0x40000.

The function uue will be in an overlay segment named seg_1. The function getData
will be in an overlay segment named seg_2.

Testing The Application
-----------------------
The application was built big endian and linked with the following linker
options:
	armlink -bin -scatter scatdes -o app  maininit.o main.o overmgrs.o \
                uue.o getdata.o initapp.o armlib.32b -map -symbols - \
                -first maininit.o -list tS.map -v 

This command produces the subdirectory app which will contain 2 pure binary
files - one per load region.

The full Makefile and the scatter load description file (scatdes) can be found
in Appendix B. 

The application is then loaded into ARMSD. As it is not an AIF file, the
loading process is done manually.

	armsd -bi
	armsd: get app/root 0x80000
        armsd: get app/copydata 0x84800
	armsd: let pc=0x80000

The entry point is at 0x80000 by virtue of the -FIRST option on the linker and
the code structure in maininit.s

	armsd: go
	Hello World                     (The user types Hello World)
	2&5L;&\@5V]R;&0*                (The program prints this.)

This is correct when compared against UUENCODE on SunOS 4.1.3. Note that
initial encoded count byte is not output.

	Program terminated normally at PC = 0x00040248
	      0x00040248: 0xef000011    .... :    swi      0x11
	armsd: q
	Quitting

Appendix A
----------


;;; Copyright (C) Advanced RISC Machines Ltd., 1991
;;
;; For use with a scatter loaded application with embedded overlays.

        EXPORT  |Image$$overlay_init| 
        EXPORT  |Image$$load_seg| 

; pointers to start and end of workspace area supplied by the linker
        IMPORT  |Overlay$$Data$$Base| 
        IMPORT  |Overlay$$Data$$Limit| 
	IMPORT  |Root$$OverlayTable|
	IMPORT  MemCopy
        IMPORT  SevereErrorHandler, WEAK 

ZeroInitCodeOffset   EQU     64 

; Layout of workspace allocated by the linker pointed to by Overlay$$Data
; This area is automatically zero-initialised AFTER overlay_init is called
; offsets are prefixed with Work_
        ^       0 
Work_HStack   #       4 ; top of stack of allocated handlers 
Work_HFree    #       4 ; head of free-list 
Work_RSave    #       9*4 ; for R0-R8 
Work_LRSave   #       4 ; saved lr 
Work_PCSave   #       4 ; saved PC 
Work_PSRSave  #       4 ; saved CPSR
Work_ReturnHandlersArea   EQU     @ ; rest of this memory is treated as heap
                        ; space for the return handlers 
Work_MinSize   EQU     @ + 32 * RHandl_Size 

; Return handler. 1 is allocated per inter-segment procedure call
; allocated and free lists of handlers are pointed to from HStack and HFree
; offsets are prefixed with RHandl_
        ^       0 
RHandl_Branch   #       4 ; BL load_seg_and_ret 
RHandl_RealLR   #       4 ; space for the real return address 
RHandl_Segment  #       4 ; -> PCIT section of segment to load 
RHandl_Link     #       4 ; -> next in stack order 
RHandl_Size   EQU     @ 

; set up by check_for_invalidated_returns.

; PCITSection. 1 per segment stored in root segment, allocated by linker
; offsets are prefixed with PCITSect_
        ^       0 
PCITSect_Vecsize   #       4 ; .-4-EntryV ; size of entry vector 
PCITSect_Base   #       4 ; used by load_segment; not initialised 
PCITSect_Limit  #       4 ; used by load_segment; not initialised 
PCITSect_Name   #       11 ; <11 bytes> ; 10-char segment name + NUL in 11 bytes 
PCITSect_Flags   #       1 ; ...and a flag byte 
PCITSect_ClashSz #       4 ; PCITEnd-.-4 ; size of table following 
PCITSect_Clashes #       4 ; >table of pointers to clashing segments 

; Stack structure  (all offsets are negative)
; defined in procedure call standard
; offsets are prefixed with Stack_
        ^       0 
Stack_SaveMask  #       -4 
Stack_LRReturn  #       -4 
Stack_SPReturn  #       -4 
Stack_FPReturn  #       -4 

; the code and private workspace area
        AREA    OverLayMgrArea, PIC, CODE , READONLY

STRLR   STR     lr, [pc, #-8] ; a word that is to be matched in PCITs 

; Store 2 words which are the addresses of the start and end of the workspace
WorkSpace   DCD     |Overlay$$Data$$Base| 
WorkSpaceEnd   DCD     |Overlay$$Data$$Limit| 
InitFlag    DCD		InitDoneFlag

|Image$$overlay_init|   ROUT    
; Initialise overlay manager. 
; In the AIF format this is is called from offset 8 in header. This routine has
; to pass control to the zero initialisation code.
; In Non AIF formats this routine has to be called explicitly e.g. from
; a customised rtstand.s .
;
; In the AIF example the entire root segment is copied to the load address.
;
; In the non AIF example only the RW part of the root is copied.
; 
	MOV	pc,lr

        DCD     0   ; Not needed for a real system but needed when using ARMSD
		    ; is used to simulate a ROM based system.
; entry point

|Image$$load_seg|   ROUT    
;
; called when segment has been called but is not loaded
; presume ip is corruptible by this
        LDR     ip, WorkSpace 
        ADD     ip, ip, #Work_RSave 
        STMIA   ip, {r0-r8} ; save working registers 
        MRS     r4, CPSR    ; Save status register -it'll get stored in the
                            ; workspace later.
; (save in my workspace because stack is untouchable during procedure call)
	LDR	r0, InitFlag
        LDRB    r1, [r0]
        CMP     r1, #0 
        BNE     InitDone 

;Initialise Return Handlers on first call to this routine
        MOV     r1, #1 
        STRB    r1, [r0] ; set InitDone flag 
        LDR     r0, WorkSpace 
; r0 points to workspace
; corrupts r0-r3,lr
; create and initialise return handler linked list
        MOV     r2, #0 
        STR     r2, [r0, #Work_HStack] ; initialise start of handler list with NULL 
        ADD     r1, r0, #Work_ReturnHandlersArea ; Start of heap space 
        STR     r1, [r0, #Work_HFree] ; Start of list of free handlers point to heap space 
        LDR     r0, WorkSpaceEnd ; for test in loop to make sure.. 
        SUBS    r0, r0, #RHandl_Size ; ..I dont overrun in init 
01      ADD     r3, r1, #RHandl_Size ; next handler 
; set up link to point to next handler (in fact consecutive locations)
        STR     r3, [r1, #RHandl_Link] 
        MOV     r1, r3 ; next handler 
        CMP     r1, r0 ; test for end of workspace 
        BLT     %BT01 
        SUB     r1, r1, #RHandl_Size ; previous handler 
        STR     r2, [r1, #RHandl_Link] ; NULL-terminate list 

InitDone
        LDR     r3, WorkSpace 
        STR     r4, [r3, #Work_PSRSave] ; CPSR read into R4 before the InitDone
					; test.
        MOV     r8,lr                   ;
        LDR     r0, [r8, #-8] ; saved r14... (is end of PCIT) 
        STR     r0, [r3, #Work_LRSave] ; ...save it here ready for retry 
        LDR     r0, STRLR ; look for this... 
        SUB     r1, r8, #8 ; ... starting at last overwrite 
01      LDR     r2, [r1, #-4]! 
        CMP     r2, r0 ; must stop on guard word... 
        BNE     %B01 
        ADD     r1, r1, #4 ; gone one too far... 
        STR     r1, [r3, #Work_PCSave] ; where to resume at 

load_segment

; ip -> the register save area; r8 -> the PCIT section of the segment to load.
; First re-initialise the PCIT section (if any) which clashes with this one...

        ADD     r1, r8, #PCITSect_Clashes 
        LDR     r0, [r8, #PCITSect_ClashSz] 
01      SUBS    r0, r0, #4 
        BLT     Done_Reinit ; nothing left to do 
        LDR     r7, [r1], #4 ; a clashing segment... 
        LDRB    r2, [r7, #PCITSect_Flags] ; its flags (0 if unloaded) 
        CMPS    r2, #0 ; is it loaded? 
        BEQ     %B01 ; no, so look again 

; clashing segment is loaded (clearly, there can only be 1 such segment)
; mark it as unloaded and reinitialise its PCIT
; r7 -> PCITSection of clashing loaded segment

        MOV     r0, #0 
        STRB    r0, [r7, #PCITSect_Flags] ; mark as unloaded 
        LDR     r0, [r7, #PCITSect_Vecsize] 
        SUB     r1, r7, #4 ; end of vector 
        LDR     r2, STRLR ; init value to store in the vector... 
02      STR     r2, [r1, #-4]! ;> 
        SUBS    r0, r0, #4 ;> loop to initialise the PCIT segment 
        BGT     %B02 ;> 
; Now we check the chain of call frames on the stack for return addresses

; which have been invalidated by loading this segment and install handlers
; for each invalidated return.
; Note: r8 identifies the segment being loaded; r7 the segment being unloaded.

        BL      check_for_invalidated_returns 
Done_Reinit

; All segment clashes have now been dealt with, as have the re-setting
; of the segment-loaded flags and the intercepting of invalidated returns.
; So, now load the required segment.

Retry
;
; Use the overlay table generated by the linker. The table format is as follows:
; The first word in the table is contains the number of entries in the table.
; The follows that number of table entries. Each entry is 3 words long:
;       Word 1  Length of the segment in bytes.
;       Word 2  Execution address of the PCIT section address. This is compared
;               against the value in R8. If the values are equal we have found
;               the entry for the called overlay.
;       Word 3  Load address of the segment.
; Segment names are not used.
;
        LDR     r0,=|Root$$OverlayTable|
	LDR	r1,[r0],#4
search_loop
	CMP	r1,#0
	MOVEQ   r0,#2              ; The end the table has been reached and the
        BEQ	SevereErrorHandler ; segemnt has not been found.
        LDMIA   r0!,{r2,r3,r4}
	CMP	r8,r3
        SUBNE	r1,r1,#1
	BNE	search_loop

	LDR	r0,[ r8, #PCITSect_Base ]
	MOV     r1,r4
        MOV	r4,r2
        BL	MemCopy

	LDR	ip,WorkSpace
	ADD	ip,ip,#Work_RSave
;
;       Mark the segment as loaded.
;
        MOV     r1,#1
        STRB    r1, [r8, #PCITSect_Flags]

        LDR	r0,[ r8, #PCITSect_Base ]
	ADD	r0,r0,r4
        
; The segment's entry vector is at the end of the segment...
; ...copy it to the PCIT section identified by r8.

        LDR     r1, [r8, #PCITSect_Vecsize] 
        SUB     r3, r8, #8 ; end of entry vector... 
        MOV     r4, #0 ; for data initialisation 
01      LDR     r2, [r0, #-4]! ;>loop to copy 
        STR     r4, [r0] ; (zero-init possible data section) 
        STR     r2, [r3], #-4 ;>the segment's PCIT 
        SUBS    r1, r1, #4 ;>section into the 
        BGT     %B01 ;>global PCIT 

; Finally, continue, unabashed...

        LDR	r3, WorkSpace
        LDR	r3, [r3,#Work_PSRSave]
        MSR	CPSR,r3
        
        LDMIA   ip, {r0-r8, lr, pc} 

load_seg_and_ret
; presume ip is corruptible by this
        LDR     ip, WorkSpace 
        ADD     ip, ip, #Work_RSave 
        STMIA   ip, {r0-r8} ; save working registers 
; (save in my workspace because stack is untouchable during procedure call)
        LDR     r3, WorkSpace 
	MRS	r8, CPSR
        STR     r8, [r3, #Work_PSRSave]

; lr points to the return handler
        MOV     r8, lr
        ;       load return handler fields RealLR, Segment, Link 
        LDMIA   r8, {r0, r1, r2} 
        SUB     r8, r8, #4 ; point to true start of return handler before BL 
        STR     r0, [r3, #Work_LRSave] 
        STR     r0, [r3, #Work_PCSave] 
; Now unchain the handler and return it to the free pool
; HStack points to this handler
        LDR     r0, [r3, #Work_HStack] 
        CMPS    r0, r8 
        MOVNE   r0, #1
        BNE     SevereErrorHandler
        STR     r2, [r3, #Work_HStack] ; new top of handler stack 
        LDR     r2, [r3, #Work_HFree] 
        STR     r2, [r8, #RHandl_Link] ; Link -> old HFree 
        STR     r8, [r3, #Work_HFree] ; new free list 
        MOV     r8, r1 ; segment to load 
        B       load_segment 

check_for_invalidated_returns
; Note: r8 identifies the segment being loaded; r7 the segment being unloaded.
; Note: check for returns invalidated by a call NOT for returns invalidated by
;	a return! In the 2nd case, the saved LR and saved PC are identical.
        LDR     r5, WorkSpace 
        ADD     r6, r5, #Work_LRSave ; 1st location to check 
        LDMIA   r6, {r0, r1} ; saved LR & PC 
        CMPS    r0, r1 
        MOVEQ   pc, lr ; identical => returning... 
        MOV     r0, fp ; temporary FP... 
01      LDR     r1, [r6] ; the saved return address... 
        LDR     r2, [r5, #Work_HStack] ; top of handler stack 
        CMPS    r1, r2 ; found the most recent handler, so 
        MOVEQ   pc, lr ; abort the search 
        LDR     r2, [r7, #PCITSect_Base] 
        CMPS    r1, r2 ; see if >= base... 
        BLT     %F02 
        LDR     r2, [r7, #PCITSect_Limit] 
        CMPS    r1, r2 ; ...and < limit ? 
        BLT     FoundClash 
02      CMPS    r0, #0 ; bottom of stack? 
        MOVEQ   pc, lr ; yes => return 
        ADD     r6, r0, #Stack_LRReturn 
        LDR     r0, [r0, #Stack_FPReturn] ; previous FP 
        B       %B01 
FoundClash
        LDR     r0, [r5, #Work_HFree] ; head of chain of free handlers 
        CMPS    r0, #0 
        MOVEQ   r0, #2
        BEQ     SevereErrorHandler
; Transfer the next free handler to head of the handler stack.
        LDR     r1, [r0, #RHandl_Link] ; next free handler 
        STR     r1, [r5, #Work_HFree] 
        LDR     r1, [r5, #Work_HStack] ; the active handler stack 
        STR     r1, [r0, #RHandl_Link] 
        STR     r0, [r5, #Work_HStack] ; now with the latest handler linked in 
; Initialise the handler with a BL load_seg_and_ret, RealLR and Segment.
        ADR     r1, load_seg_and_ret 
        SUB     r1, r1, r0 ; byte offset for BL in handler 
        SUB     r1, r1, #8 ; correct for PC off by 8 
        MOV     r1, r1, ASR #2 ; word offset 
        BIC     r1, r1, #&FF000000 
        ORR     r1, r1, #&EB000000 ; code for BL 
        STR     r1, [r0, #RHandl_Branch] 

        LDR     r1, [r6] ; LRReturn on stack 
        STR     r1, [r0, #RHandl_RealLR] ; RealLR 
        STR     r0, [r6] ; patch stack to return to handler 

        STR     r7, [r0, #RHandl_Segment] ; segment to re-load on return 
        MOV     pc, lr ; and return 

	AREA	OverlayInit, DATA
InitDoneFlag	DCD 0

        END     
Appendix B
----------
main.c
------

#include <stdio.h>
#include <string.h>
#define INBUFFSIZE 192
#define OUTBUFFSIZE 257

/*
  This is used to check whether the initialised data has been copied 
  correctly.
*/
static char IDstring[]="This is initialised data.";
static char inBuff[INBUFFSIZE];
static char outBuff[OUTBUFFSIZE];
static int charCount=0;

extern int getData(char *,int);
extern int uuencode(char *, char *, int);

int main(int argc,char **argv)
{
	int uuCount;
	charCount = getData(inBuff,sizeof(inBuff));
	if (charCount<0) {
		fprintf(stderr,"Error reading data.\n");
	}
	else {
		uuCount=uuencode(inBuff,outBuff,charCount);
		outBuff[uuCount]='\0';
		puts(outBuff);
	}
	return 0;
}

void MemCopy(void *d,void *s,int c)
{
	memmove(d,s,c);
}

getdata.c
---------

int getData(char *buffer,int length)
{
	int charsIn;
	int charRead;
	charsIn=0;
	for (charsIn=0;charsIn<length;) {
		charRead=getchar();
		if (charRead == EOF) break;
		buffer[charsIn++]=charRead;
		if (charRead == '\n' ) break;
	}
	for (;(charsIn%3)!=0; ) buffer[charsIn++]='\0';
	return charsIn;
}

uue.c
-----

/*
	A simple reoutine to UUENCODE a buffer. It does not split up the
	uuencoded data into lines and append encode count bytes though.
	It assumes that the input buffer is an integer multiple of 3 bytes long.
	The number of bytes written to the output buffer is returned.
*/
unsigned int encodedCount=0;
unsigned int uuencode(unsigned char *in,unsigned char *out,unsigned int count)
{
        unsigned char t0;
        unsigned char t1;
        unsigned char t2;
	unsigned int result=0;
        
        for (;count;count-=3,in+=3,out+=4,result+=4) {
                t0=in[0];
		*out=' '+(t0>>2);
		t1=in[1];
                out[1]=' '+((t0<<4)&0x30)+(t1>>4);
		t2=in[2];
		out[2]=' '+((t1<<2)&0x3C)+ (t2>>6);
                out[3]=' '+(t2&0x3F);
        }
        encodedCount += count;
        return result;
}

maininit.s
----------

	AREA MainWithOverlayInit, CODE, READONLY
	IMPORT	|Image$$overlay_init|
        IMPORT  InitialiseApp
	IMPORT  __entry
	EXPORT  __main

	ENTRY
__main
        BL      InitialiseApp
	BL	|Image$$overlay_init|
	BL	__entry
	END

Makefile
--------

LIB=

.c.o:
	armcc -c -bi -APCS 3/32/noswst $< 

.s.o:
	armasm -bi -APCS 3/32/noswst $<

all: app/root

app/root: main.o uue.o getdata.o overmgrs.o initapp.o maininit.o
	armlink -bin -scatter scatdes -o app  maininit.o main.o overmgrs.o \
              uue.o getdata.o initapp.o  $(LIB)/armlib.32b -map -symbols - \
              -first maininit.o -list tS.map -NOUNUSED -v > tS.log 

maininit.o: maininit.s

initapp.o: initapp.s

overmgrs.o: overmgrs.s

main.o: main.c

uue.o: uue.c

getdata.o: getdata.c

scatdes
-------

;
; Position the root load region at 0x80000. Limit the size so it does not
; overlap the overlay segments in the ROM load region.
;
ROOT 0x80000 0x4800
;
; Position the root read/write execution region .
;
ROOT-DATA 0x43000

copydata 0x84800 {
    seg_1 0x42000 OVERLAY { uue.o }
    seg_2 0x42000 OVERLAY { getdata.o }
    overmgr 0x40000 { overmgrs.o(+RO, +RW) } ; Position the overlay manager
                                             ; code and data in the SRAM
}

initapp.s
---------

       AREA InitApp, CODE , READONLY
       EXPORT InitialiseApp
InitialiseApp
       ADR    r0,ziTable
       MOV    R3,#0
ziLoop
       LDR    r1,[r0],#4
       CMP    r1,#0
       BEQ    initLoop
       LDR    r2,[r0],#4
ziFillLoop
       STR    r3,[r2],#4
       SUBS   r1,r1,#4
       BNE    ziFillLoop
       B      ziLoop

initLoop
       LDR    r1,[r0],#4
       CMP    r1,#0
       MOVEQ  pc,lr
       LDMIA  r0!,{r2,r3}
       CMP    r1,#16
       BLT    copyWords
copy4Words
       LDMIA  r3!,{r4,r5,r6,r7}
       STMIA  r2!,{r4,r5,r6,r7}
       SUBS   r1,r1,#16
       BGT    copy4Words
       BEQ    initLoop
copyWords
       SUBS r1,r1,#8
       LDMIAGE r3!,{r4,r5}
       STMIAGE r2!,{r4,r5}
       BEQ   initLoop

       LDR    r4,[r3]
       STR    r4,[r2]

       B      initLoop
       
       MACRO
       ZIEntry  $execname
       LCLS   lensym
       LCLS   basesym
       LCLS   namecp
namecp SETS "$execname"
lensym SETS   "|Image$$":CC:namecp:CC:"$$ZI$$Length|"
basesym SETS   "|Image$$":CC:namecp:CC:"$$ZI$$Base|"
       IMPORT $lensym
       IMPORT $basesym
       DCD    $lensym
       DCD    $basesym
       MEND

       MACRO
       InitEntry  $execname
       LCLS   lensym
       LCLS   basesym
       LCLS   loadsym
       LCLS   namecp
namecp SETS "$execname"
lensym SETS   "|Image$$":CC:namecp:CC:"$$Length|"
basesym SETS   "|Image$$":CC:namecp:CC:"$$Base|"
loadsym SETS   "|Load$$":CC:namecp:CC:"$$Base|"
       IMPORT $lensym
       IMPORT $basesym
       IMPORT $loadsym
       DCD    $lensym
       DCD    $basesym
       DCD    $loadsym
       MEND

ziTable
       ZIEntry root
       DCD    0

InitTable
       InitEntry root
       InitEntry overmgr
       DCD    0
       END