; BCPL Standard Startup Code ; -------------------------- CODE L000001: ; findSegArray() 000000 286A 0164 MOVEA.L 356(A2),A4 000004 700C MOVEQ.L #12,D0 000006 4E95 JSR (A5) ; save pointer 000008 2401 MOVE.L D1,D2 ; minimum size of global vector required 00000A 223C 0000 0095 MOVE.L #$00000095,D1 ; get pointer to second segment 000010 49FA FFEE LEA.L L000001(PC),A4 000014 286C FFFC MOVEA.L -4(A4),A4 ; save segArray pointer and pointer to program's second segment ; on the stack. 000018 2F0C MOVE.L A4,-(A7) 00001A 2F02 MOVE.L D2,-(A7) L000002: ; compute machine address of segment 00001C D9CC ADDA.L A4,A4 00001E D9CC ADDA.L A4,A4 ; if no more segments, exit from loop 000020 200C MOVE.L A4,D0 000022 6714 BEQ.S L000004 ; get length of segment from first word 000024 202C 0004 MOVE.L 4(A4),D0 000028 E580 ASL.L #2,D0 ; check global vector size required for this module, and if greater ; than current maximum value, copy to maximum value. 00002A B2B4 0800 CMP.L 0(A4,D0.L),D1 00002E 6C04 BGE.S L000003 000030 2234 0800 MOVE.L 0(A4,D0.L),D1 ; get pointer to next module, and loop back to process it. L000003: 000034 2854 MOVEA.L (A4),A4 000036 60E4 BRA.S L000002 ; global vector size required is now in D1 ; do a getvec(size+50) to create private global vector L000004: 000038 2C01 MOVE.L D1,D6 00003A 0681 0000 0032 ADDI.L #$00000032,D1 000040 91C8 SUBA.L A0,A0 000042 286A 0074 MOVEA.L 116(A2),A4 000046 700C MOVEQ.L #12,D0 000048 4E95 JSR (A5) ; if no memory obtained, return -1 and exit 00004A 4A81 TST.L D1 00004C 6700 00E0 BEQ L00000D ; save pointer to installSeg() function, then set A2 to point to ; the private global vector. 000050 0681 0000 0032 ADDI.L #$00000032,D1 000056 2A2A 0070 MOVE.L 112(A2),D5 00005A 2441 MOVEA.L D1,A2 00005C D5CA ADDA.L A2,A2 00005E D5CA ADDA.L A2,A2 ; save base address of new global vector as a BPTR 000060 2E01 MOVE.L D1,D7 ; store size of new global vector 000062 204A MOVEA.L A2,A0 000064 20C6 MOVE.L D6,(A0)+ ; compute end address of global vector by adding size to base, then ; converting to a machine address 000066 2846 MOVEA.L D6,A4 000068 D9C7 ADDA.L D7,A4 00006A D9CC ADDA.L A4,A4 00006C D9CC ADDA.L A4,A4 ; fill the new global vector with entries of the form ; "GL <16 bit number>" where the number is 3, 5, 7 ... ; Presumably this will generate an easy to recognize odd-address ; trap if an unfilled entry is accidentally jumped to. 00006E 203C 474C 0003 MOVE.L #$474C0003,D0 L000005: 000074 20C0 MOVE.L D0,(A0)+ 000076 5480 ADDQ.L #2,D0 000078 B1CC CMPA.L A4,A0 00007A 6FF8 BLE.S L000005 00007C 91C8 SUBA.L A0,A0 ; Get stack size into D0 00007E 202F 000C MOVE.L 12(A7),D0 ; Compute the base address of the stack and store in A1 ; (initialize BCPL "frame pointer") 000082 43EF 0010 LEA.L 16(A7),A1 000086 93C0 SUBA.L D0,A1 ; Store -1 into "second local variable" 000088 237C FFFF FFFF 0004 MOVE.L #$FFFFFFFF,4(A1) ; Compute highest useable stack address by taking stack size, ; subtracting 160 bytes for exec context saves and such, and adding ; the result to the current frame pointer. 000090 2209 MOVE.L A1,D1 000092 0480 0000 00A0 SUBI.L #$000000A0,D0 000098 D081 ADD.L D1,D0 ; Store result in "third local variable" 00009A 2340 0008 MOVE.L D0,8(A1) ; Convert frame pointer to a BPTR, and store in "coroutine chain" ; field of the global vector 00009E E481 ASR.L #2,D1 0000A0 2541 0030 MOVE.L D1,48(A2) ; Get pointer to the segArray from the stack 0000A4 2E1F MOVE.L (A7)+,D7 0000A6 2C07 MOVE.L D7,D6 ; get segArray[0] (length field) and add to segArray BPTR 0000A8 E586 ASL.L #2,D6 0000AA DEB0 6800 ADD.L 0(A0,D6.L),D7 ; Compute machine address of first word after current segArray 0000AE E587 ASL.L #2,D7 ; loop through all entries in the segArray L000006: 0000B0 5886 ADDQ.L #4,D6 0000B2 BE86 CMP.L D6,D7 0000B4 6D12 BLT.S L000007 ; get current segArray entry (BPTR to a segList) 0000B6 2230 6800 MOVE.L 0(A0,D6.L),D1 ; installSeg(current segList). Use the installSeg pointer obtained ; from the system global vector. ; This fills in the global vector entries defined by each segList. 0000BA 2845 MOVEA.L D5,A4 0000BC 700C MOVEQ.L #12,D0 0000BE 4E95 JSR (A5) 0000C0 4A81 TST.L D1 ; If zero returned, return -1 and exit from program, otherwise ; loop to install the next segList. 0000C2 6700 006C BEQ L00000E 0000C6 60E8 BRA.S L000006 L000007: ; get BPTR to second segment from stack, then installSeg it ; also (installs all of the program except for this segment) 0000C8 221F MOVE.L (A7)+,D1 0000CA 2845 MOVEA.L D5,A4 0000CC 700C MOVEQ.L #12,D0 0000CE 4E95 JSR (A5) ; if zero returned, return -1 and exit from program. 0000D0 4A81 TST.L D1 0000D2 675E BEQ.S L00000F ; findCLI() 0000D4 286A 0218 MOVEA.L 536(A2),A4 0000D8 700C MOVEQ.L #12,D0 0000DA 4E95 JSR (A5) ; convert result to machine address 0000DC E581 ASL.L #2,D1 0000DE 2641 MOVEA.L D1,A3 ; save on the stack for now. 0000E0 2F0B MOVE.L A3,-(A7) ; bypass the following if the CLI pointer is zero 0000E2 670C BEQ.S L000009 ; copy the whole CLI structure (16 longwords) into the global ; vector starting at element 134 ; (just after the findCLI() entry) 0000E4 49EA 0218 LEA.L 536(A2),A4 0000E8 700F MOVEQ.L #15,D0 L000008: 0000EA 28DB MOVE.L (A3)+,(A4)+ 0000EC 51C8 FFFC DBF D0,L000008(PC) L000009: ; store address of Exit() routine in the global vector 0000F0 49FA 0044 LEA.L L000010(PC),A4 0000F4 254C 0008 MOVE.L A4,8(A2) ; run the program by calling its start() function in proper BCPL ; fashion. The start() address is in the global vector from the ; installSeg calls. 0000F8 286A 0004 MOVEA.L 4(A2),A4 0000FC 7020 MOVEQ.L #32,D0 0000FE 7200 MOVEQ.L #0,D1 000100 4E95 JSR (A5) ; if the program "fell of the end of the world", i.e. did a BCPL ; return without calling Exit(), pretend it returned zero. 000102 7000 MOVEQ.L #0,D0 L00000A: ; the program has finished, and its return code is in D0. Save ; it in D7. 000104 2E00 MOVE.L D0,D7 ; get the address of the CLI structure from the stack. Skip the ; following if no CLI structure 000106 221F MOVE.L (A7)+,D1 000108 670E BEQ.S L00000C ; copy the CLI structure from the global vector back into place 00010A 2641 MOVEA.L D1,A3 00010C 49EA 0218 LEA.L 536(A2),A4 000110 700F MOVEQ.L #15,D0 L00000B: 000112 26DC MOVE.L (A4)+,(A3)+ 000114 51C8 FFFC DBF D0,L00000B(PC) L00000C: ; get the global vector pointer 000118 220A MOVE.L A2,D1 ; convert back to a BPTR 00011A E481 ASR.L #2,D1 ; subtract negative size to compute base address (as BPTR), then ; freevec() the whole thing 00011C 0481 0000 0032 SUBI.L #$00000032,D1 000122 286A 0078 MOVEA.L 120(A2),A4 000126 700C MOVEQ.L #12,D0 000128 4E95 JSR (A5) ; get the return code back and exit 00012A 2007 MOVE.L D7,D0 00012C 4E75 RTS ; error exits (return -1). Call one of the following labels to ; pop 2, 1, or no longwords from the stack first. L00000D: 00012E 4A9F TST.L (A7)+ L00000E: 000130 4A9F TST.L (A7)+ L00000F: 000132 70FF MOVEQ.L #-1,D0 000134 4E75 RTS ; The Exit() function: Get the return value and jump ; to the exit code. L000010: 000136 2001 MOVE.L D1,D0 000138 60CA BRA.S L00000A ; Padding. 00013A 0000 DC.W $0000 ; Code for the "Echo" command ; --------------------------- CODE ; Size of this module is 48 longwords 000000 0000 0030 DC.L $00000030 ; Padding 000004 0000 DC.W $0000 ; Version 000006 3039 DC.B '09' ; Name, as a BSTR 000008 114543484F2020202020... DC.B 17, 'ECHO ' ; Padding 00001A 0000 DC.W $0000 ; Function label: "start ", stored as a BSTR. 00001C 0773746172742020 DC.B 7, 'start ' ; The code starts here. ; Make "first local variable" into a BPTR to "second local variable" ; Obviously, the first local variable is a pointer to a vector of ; longwords, which is the rest of the local variable space 000024 7204 MOVEQ.L #4,D1 000026 D289 ADD.L A1,D1 000028 E489 LSR.L #2,D1 00002A 2281 MOVE.L D1,(A1) ; Buffer size = 80 longwords, I think 00002C 7650 MOVEQ.L #80,D3 ; Move "first local variable" (address of buffer) to D2. 00002E 2401 MOVE.L D1,D2 ; Get pointer to format string into D1. This is a null string, ; meaning, anything will be accepted 000030 47EC 006C LEA.L 108(A4),A3 000034 220B MOVE.L A3,D1 000036 E489 LSR.L #2,D1 ; Read arguments according to template 000038 203C 0000 0154 MOVE.L #$00000154,D0 00003E 286A 0138 MOVEA.L 312(A2),A4 000042 4E95 JSR (A5) ; Check if there was an error 000044 4A81 TST.L D1 000046 6600 001A BNE L000011 ; There was an error. Point to error message BSTR 00004A 47EC 0070 LEA.L 112(A4),A3 00004E 220B MOVE.L A3,D1 000050 E489 LSR.L #2,D1 ; and print it, using the writes() function, then exit. 000052 203C 0000 0154 MOVE.L #$00000154,D0 000058 286A 0124 MOVEA.L 292(A2),A4 00005C 4E95 JSR (A5) 00005E 6000 002C BRA L000012 ; Continue here if argument parsing was successful L000011: ; Get BPTR to parse result array 000062 2211 MOVE.L (A1),D1 000064 E589 LSL.L #2,D1 ; If first element is zero, exit 000066 4AB0 1800 TST.L 0(A0,D1.L) 00006A 6700 0020 BEQ L000012 ; Use writes() to print the first element 00006E 2230 1800 MOVE.L 0(A0,D1.L),D1 000072 203C 0000 0154 MOVE.L #$00000154,D0 000078 286A 0124 MOVEA.L 292(A2),A4 00007C 4E95 JSR (A5) ; wrch(10) - writes a newline. 00007E 720A MOVEQ.L #10,D1 000080 203C 0000 0154 MOVE.L #$00000154,D0 000086 286A 00E0 MOVEA.L 224(A2),A4 00008A 4E95 JSR (A5) ; Exit by doing a BCPL return. This will cause the program to ; return error code zero. L000012: 00008C 4ED6 JMP (A6) ; Padding 00008E 4E71 NOP ; A null BSTR (format string for argument parser) 000090 0000 0000 DC.L 0 ; Error message 000094 19496E76616C69642061... DC.B 19, 'Invalid argument ' 0000A6 746F204543484F0A DC.B 'to ECHO', 10 ; Padding 0000AE 0000 ; Global vector initialization table 0000B0 0000 0000 ; End of table marker 0000B4 0000 0001 ; Function #1 in global vector ("start" function) 0000B8 0000 0024 ; is at offset $24 in this segment. ; Global vector size required ; This means the highest global vector element this program will ; use is entry $4E, at positive offset 312. 0000BC 0000 004E