/* 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) $)
    $)

.