This information is provided for the general interest of basic programs and for programmers who might be modifying the SM32 source code. Consider the following simple program:
0010 BEGIN 0020 LET A%=5 0030 LET B%=6 0040 LET C%=C%+A%+B% 0050 IF C%<100 THEN GOTO 0040At run time the start of the compiled code for this program (all programs) will contain the following stucture:
struct pr_header
{
lwrd prog_len;
lwrd ksa_len;
lwrd total_x_level_slots;
lwrd vpl_disp; /* variable references */
lwrd vpls;
lwrd prog_refs_disp; /* Line # references */
lwrd prog_refs;
lwrd compile_rev_no;
swrd crc16;
swrd not_useda;
lwrd fnl_disp; /* field pointer list */
lwrd fnls;
lwrd data_statements;
lwrd save_time;
lwrd disk_num;
lwrd not_used[2];
};
Followed by this code prefix (all programs contain this prefix and execution always
starts here). Note the parameters that it was called with, a base_level_minus1
struct (often seen in the code as bm1 and is always contain in EDI of an
executing program) and an x_level struct(often seen in the
code as x_l and always contain in ESI of an executing program).
bm1 starts with a vector of address that point to user run time routines.
x_l is mainly used to point to program data and program addresses. The 3rd parameter is
a start address for starting somewhere other than the start of the program
(for example escape to console mode followed by a run).
prefix:
push ebp
mov ebp,esp
mov edi,[ebp+8] ;get base_level_minus1
mov esi,[ebp+12] ;get x_level
mov eax,[ebp+16] ;get start add
or eax,eax
jz end_prefix ;start at 1st statement in program
jmp eax ;start somewhere in program (from console mode)
end_prefix:
;0010 BEGIN
call dword ptr [edi] ;call system loop
mov eax,0 ;no EXCEPT list
push eax ;flag as a BEGIN not BEGIN EXCEPT
push esi ;pass in x_l
call dword ptr [edi+17Ch] ;do_begin(x_l,0);
;0020 LET A%=5
call dword ptr [edi] ;call system loop
mov edx,dword ptr [esi+34h] ;get address of A%
mov dword ptr [edx],5 ;5 to A%
;0030 LET B%=6
call dword ptr [edi] ;call system loop
mov edx,dword ptr [esi+38h] ;get address of B%
mov dword ptr [edx],6 ;6 to B%
;0040 LET C%=C%+A%+B%
call dword ptr [edi] ;call system loop
mov edx,dword ptr [esi+3Ch] ;get address of C%
mov eax,dword ptr [edx] ;get C%
mov edx,dword ptr [esi+34h] ;get address of A%
mov ecx,dword ptr [edx] ;get A%
add eax,ecx ;add A% to C%
mov edx,dword ptr [esi+38h] ;get address of B%
mov ecx,dword ptr [edx] ;get B%
add eax,ecx ;add B% to (A%+C%)
mov edx,dword ptr [esi+3Ch] ;get address of C%
mov dword ptr [edx],eax ;save C%+A%+B% to C%
;0050 IF C%<100
call dword ptr [edi] ;call system loop
sub esp,4 ;get space of stack
mov edx,dword ptr [esi+3Ch] ;get address of C%
mov eax,dword ptr [edx] ;get C%
mov dword ptr [ebp-4],eax ;save on stack
mov eax,64h ;get 100
mov edx,dword ptr [ebp-4] ;get C% from stack
mov ecx,1 ;type of compare
push ecx ;push type
push eax ;push 100
push edx ;push C%
call dword ptr [edi+138h] ;do_int_comp(C%,100,1);
call dword ptr [edi+78h] ;hw_get_logical ();
or eax,eax
je end_of_statement
;THEN GOTO 0040
call dword ptr [edi]
jmp dword ptr [esi+40h] ;jump to statement 40
end_of_statement:
All programs contain the follwing code:
;Hidden END statement
push esi
call dword ptr [edi+10Ch] ;do_end(x_l);
;Hidden error 21 statement
;any reference to an undefined TABLE or IOLIST
;comes here
push esi
call dword ptr [edi+128h] ;error_21(x_l);
The use addresses pointed to by EDI is pretty obvious. The User Run Time
routine address are simply loaded
in bm1->urts[] when SM32 comes up via:
data is slot#
where the address of statement xxx will be found [in X section] at runtime in the
x_level struct.
t=I for IOLIST or T for TABLE
xxx is a big endian binary line #.
xxx ranges $000001$ thru $FFFFFC$