/* THIS IS THE BCPL CODE GENERATOR FOR THE INTEL 8086 MICROPROCESSOR,
(FOR THE 1M (MAX) VERSION OF TRIPOS).
IT HAS BEEN ADAPTED FROM THAT FOR THE PDP11
( COPYRIGHT TRIPOS RESEARCH GROUP, CAMBRIDGE ).
THIS VERSION ASSUMES ES=DS=SS.
EACH SECTION STARTS IN A NEW CODE SEGMENT SETTING.
THE 8086 REGISTERS ARE USED AS FOLLOWS:-
. ES, DS AND SS ARE NOT CHANGED, CS CHANGES WITH SECTION
. IP IS THE INSTRUCTION POINTER WHICH IS CHANGED ONLY IMPLICITLY
BY NORMAL EXECUTION OF INSTRUCTIONS
. SP IS THE MACHINE STACK POINTER USED BY CALL,RET,PUSH,POP ETC
. BP IS THE BCPL STACK FRAME BASE POINTER
. DI HOLDS THE ADDRESS OF THE GLOBAL VECTOR
. THE OTHER 5 REGISTERS ARE USED FOR TEMPORARY STORAGE OF
DATA ITEMS. FOR MANY OPERATIONS ANY OF THESE REGISTERS MAY BE
USED, BUT FOR OTHERS OPERANDS ARE RESTRICTED TO ONE OR TWO
POSSIBLE REGISTERS.
. R0 = R.BX = REGISTER BX GENERAL, INDEX, FUNCTION AND VALOF RESULT, ARG1
R1 = R.AX = REGISTER AX GENERAL, MULTIPLICAND, LS PRODUCT,
LS DIVIDEND, ARG2
R2 = R.CX = REGISTER CX GENERAL, SHIFT COUNTER, ARG3
R3 = R.DX = REGISTER DX GENERAL, REMAINDER, MS DIVIDEND, SIZE OF
CALLING ROUTINE'S FRAME
R4 = R.SI = REGISTER SI GENERAL, INDEX, ADDRESS OF CALLED ROUTINE'S
DESCRIPTOR
R5 = R.BP = REGISTER BP
R6 = R.SP = REGISTER SP
R7 = R.DI = REGISTER DI
*/
/* THE FOLLOWING STREAMS ARE USED FOR THE CROSS-COMPILER VERSION
SYSPRINT (OUT) HEADING, DEBUGGING AND ERROR INFO
OCODE (IN) OCODE FROM PHASE 1
CODE (OUT) A REPRESENTATION OF THE COMPILED M/C CODE
*/
/* THE CROSS VERSION CROSS-COMPILES ON 360/370/303X IBM MACHINES */
/* (UNDER K. MOODY'S IMPLEMENTATION OF BCPL) */
SECTION "CG1"
GET "CGHDR"
LET START(PARMS) BE
$(1 LET V = 0
//*<3032
LET SYSP = FINDOUTPUT("SYSPRINT")
LET VDA = DATE()
OCODEFILE := "OCODE"
CODEFILE := "CODE"
CGWORKSIZE := 5000
DATVEC := GETVEC(14)
FOR I = 1 TO 9 DO PUTBYTE(DATVEC,I,ASKII(GETBYTE(VDA,I+2)))
PUTBYTE(DATVEC,3,ASKII('-'))
PUTBYTE(DATVEC,7,ASKII('-'))
PUTBYTE(DATVEC,5,GETBYTE(DATVEC,5) | #X20)
PUTBYTE(DATVEC,6,GETBYTE(DATVEC,6) | #X20) // TO LOWER CASE
PROFILING := FALSE
STKCHKING := FALSE
CALLCOUNTING := FALSE
NAMING := TRUE
DEBUGGING := FALSE
CGLISTING := FALSE
IF SYSP=0 THEN
$( WRITETOLOG("NO PRINT STREAM SELECTED - CG ABORTED")
STOP(16)
$)
SELECTOUTPUT(SYSP)
VERSTREAM := SYSP
FOR I = 1 TO GETBYTE(PARMS, 0) DO
SWITCHON GETBYTE(PARMS, I) INTO
$(2 DEFAULT: LOOP
CASE 'P': PROFILING := TRUE
CASE 'K': CALLCOUNTING := TRUE; LOOP
CASE 'N': NAMING := FALSE; LOOP
CASE 'C': STKCHKING := TRUE; LOOP
CASE 'D': DEBUGGING := TRUE; LOOP
CASE 'L': CGLISTING := TRUE; LOOP
CASE 'W': CGWORKSIZE := 0
$( LET CH = ?
UNLESS I+1<=GETBYTE(PARMS, 0) DO BREAK
CH := GETBYTE(PARMS, I+1)
UNLESS '0'<=CH<='9' DO BREAK
CGWORKSIZE := CGWORKSIZE*10 + CH - '0'
I := I+1
$) REPEAT
$)2
/*3032>*/
ERR.P, ERR.L := LEVEL(), FAIL
WRITES("RAL 8086 cg*N")
//*<3032
CODESTREAM := FINDOUTPUT(CODEFILE)
IF CODESTREAM=0 DO CGERROR("CAN'T OPEN %S", TRUE, CODEFILE)
/*3032>*/
OCODESTREAM := FINDINPUT(OCODEFILE)
IF OCODESTREAM=0 DO CGERROR("CAN'T OPEN %S", TRUE, OCODEFILE)
SELECTINPUT(OCODESTREAM)
V := GETVEC(CGWORKSIZE)
IF V=0 DO CGERROR("CAN'T GET WORKSPACE OF %N", TRUE, CGWORKSIZE)
IF CGWORKSIZE<500 DO CGERROR("GIVE MORE WORKSPACE TO CG", TRUE)
PROGSIZE := 0
//*<3032
WRITEWCOUNT := 0
LISTCHAN := TRUE
IF CGLISTING DO
$( ORDCH := RDCH
RDCH := MYRDCH
$)
/*3032>*/
L: OP := RDN()
IF OP=0 GOTO X
FOR I = 0 TO CGWORKSIZE DO V!I := 0
TEMPV, TEMPT := V, V+150
BREFV, BREFP := TEMPT, TEMPT
PROCSTK, PROCSTKP := BREFV+129, 0
REG.K := PROCSTK+20
REG.N := REG.K+5
LABV := REG.N+5
DP := V+CGWORKSIZE
PARAMNUMBER := (DP-LABV)/10 + 10
STV := LABV+PARAMNUMBER
FOR P = LABV TO STV-1 DO !P := -1
FORGETALL() // INIT. REGISTERS
STVP := 0
INITDATALISTS()
INCODE := FALSE
MAXGN := 0
MAXLAB := 0
MAXSSP := 0
RETURN.SET := 0
INITSTACK(SAVESPACESIZE)
CODE(0, 0) // FIRST WORD WILL HOLD NO. OF WORDS OF CODE COMPILED
TEST OP=S.SECTION THEN
$( CGNAME(S.SECTION, RDN())
OP := RDN()
$)
OR CGNAME(S.SECTION, 0)
SCAN()
EVEN()
UNLESS MAXGN=0 DO OUTPUTSECTION()
PROGSIZE := PROGSIZE + STVP
GOTO L
X: WRITEF("PROGRAM SIZE %N BYTES*N", PROGSIZE)
FAIL: UNLESS V=0 DO FREEVEC(V)
UNLESS OCODESTREAM=0 DO ENDREAD()
OCODESTREAM := 0
//*<3032
UNLESS RC=0 DO STOP(RC)
/*3032>*/
$)1
//*<3032
AND MYRDCH() = VALOF
$( LET CH = ORDCH()
IF LISTCHAN DO
$( WRITES("*N** ")
LISTCNT := 0
LISTCHAN := FALSE
$)
IF CH=ENDSTREAMCH RESULTIS 0
WRCH(CH='*N'->'*S',CH)
LISTCNT := LISTCNT + 1
IF LISTCNT>60 DO LISTCHAN := TRUE
RESULTIS CH
$)
/*3032>*/
AND RDN() = VALOF
$( LET A, SIGN = 0, FALSE
LET CH = ?
CH := RDCH() REPEATWHILE
CH='*S' | CH='*N' | CH='L'
IF CH=ENDSTREAMCH RESULTIS 0
IF CH='-' DO $( SIGN := TRUE
CH := RDCH() $)
WHILE '0'<=CH<='9' DO $( A := 10*A + CH - '0'
CH := RDCH() $)
IF SIGN DO A := -A
RESULTIS A
$)
// READ IN AN OCODE LABEL
AND RDL() = VALOF
$( LET L = RDN()
IF MAXLAB<L DO
$( MAXLAB := L
CHECKPARAM() $)
RESULTIS L $)
// READ IN A GLOBAL NUMBER
AND RDGN() = VALOF
$( LET G = RDN()
IF MAXGN<G DO MAXGN := G
RESULTIS G $)
// GENERATE NEXT LABEL PARAMETER
AND NEXTPARAM() = VALOF
$( PARAMNUMBER := PARAMNUMBER-1
CHECKPARAM()
RESULTIS PARAMNUMBER $)
AND CHECKPARAM() BE
IF MAXLAB>=PARAMNUMBER DO
$( CGERROR("TOO MANY LABELS -*
* INCREASE WORKSPACE", TRUE) $)
AND CGERROR(N,F,A) BE
$( WRITES("*NERROR. ")
WRITEF(N,A)
NEWLINE()
RC := 10
IF F DO
$( RC := 20
LONGJUMP(ERR.P, ERR.L) $)
$)
.