home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 2
/
Apprentice-Release2.iso
/
Tools
/
Languages
/
MacMETH 3.2.1
/
Sources
/
MacC2.6
/
M2HM40.MOD
< prev
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
Macintosh to JP
NeXTSTEP
RISC OS/Acorn
Shift JIS
UTF-8
Wrap
Modula Implementation
|
1992-05-29
|
83.9 KB
|
2,311 lines
|
[
TEXT/MEDT
]
IMPLEMENTATION MODULE M2HM; (* Hermann Seiler, 1.7.86 / 7.5.87 / 19.12.91 / 29.5.92 *)
(* Implementation is specific for the MOTOROLA MC68040 processor. *)
FROM SYSTEM IMPORT
WORD, LONG, SHIFT, VAL;
FROM M2SM IMPORT
Symbol, Mark;
FROM M2DM IMPORT
ObjPtr, StrPtr, StrForm, ConstValue, PDesc,
Object, Structure, Standard,
notyp, undftyp, booltyp, chartyp,
inttyp, cardtyp, bitstyp, dbltyp, realtyp, lrltyp,
proctyp, stringtyp, addrtyp, wordtyp, bytetyp,
WordSize, MinInt, MaxInt,
rngchk, ovflchk;
FROM M2LM IMPORT
pc, maxP, maxM, PutWord, PutLong, FixLink;
CONST
(* Register usage and dedicated registers : *)
(* D-Register pool for expression evaluation. *)
(* D0 = 0; (* freely used, never reserved *)
D1 = 1; (* freely used, never reserved *) *)
D2 = 2; (* D-pool, reserved when used *)
D3 = 3; (* D-pool, reserved when used *)
D4 = 4; (* D-pool, reserved when used *)
D5 = 5; (* D-pool, reserved when used *)
D6 = 6; (* D-pool, reserved when used *)
D7 = 7; (* D-pool, reserved when used *)
(* F-Register pool for floating point arith. *)
(* F0 = 0; (* freely used, never reserved *)
F1 = 1; (* freely used, never reserved *) *)
F2 = 2; (* F2 - F7 reserved when used *)
F7 = 7;
(* A-Register pool for address calculations. *)
A0 = 0; (* A-pool, reserved when used *)
A1 = 1; (* A-pool, reserved when used *)
A2 = 2; (* A-pool, reserved when used *)
A3 = 3; (* A-pool, reserved when used *)
(*
(* Dedicated A-Registers. *)
SB = 4; (* SB = A4 : static base pointer *)
A5 = 5; (* A5 is n e v e r used ! *)
MP = 6; (* MP = A6 : procedure mark *)
SP = 7; (* SP = A7 : active stack pointer *)
(* Instruction size for simple types. *)
byte = 0; word = 1; long = 2;
(* Descriptor size dynamic array parameters. *)
DynArrDesSize = 6;
*)
(* Addressing Mode Categories. *)
DDIR = 0; (* D-Reg. direct *)
ADIR = 10B; (* A-Reg. direct *)
AIDR = 20B; (* (An) *)
AINC = 30B; (* (An)+ *)
ADEC = 40B; (* -(An) *)
AOFF = 50B; (* d16(An) *)
AIDX = 60B; (* d8(An,Rx) *)
XXXW = 70B; (* absolute short *)
XXXL = 71B; (* absolute long *)
PREL = 72B; (* d16(PC) *)
IMM = 74B; (* immediate or SR*)
(* MC68000 instruction mnemonics. *)
(* _____________________________ *)
(* Special purpose. *)
UNLK = 047136B; (* UNLK MP *)
LINK = 047126B; (* LINK MP,#d16 *)
LEASP = 047757B; (* LEA d16(SP),SP *)
INCSP = 050217B; (* ADDQ.L #n,SP *)
DECSP = 050617B; (* SUBQ.L #n,SP *)
MOVEMDEC = 044347B; (* MOVEM.L registers,-(SP) *)
MOVEMINC = 046337B; (* MOVEM.L (SP)+,registers *)
MVEMSP = 027400B; (* MOVE.L ea,-(SP) : push *)
MVESPP = 020037B; (* MOVE.L (SP)+,ea : pop *)
PUSHSB = 027410B + SB; (* MOVE.L SB,-(SP) *)
POPSB = 020137B + SB*1000B; (* MOVEA.L (SP)+,SB *)
(* Instructions without operand. *)
NOP = 047161B; RTE = 047163B;
RTS = 047165B; RTD = 047164B; (* MC68010 *)
TRAPV= 047166B; ILL = 045374B;
(* Branches : with a displacement. *)
BRA = 060000B; BSR = 060400B;
BHI = 061000B; BLS = 061400B; BCC = 062000B; BCS = 062400B;
BNE = 063000B; BEQ = 063400B; BVC = 064000B; BVS = 064400B;
BPL = 065000B; BMI = 065400B; BGE = 066000B; BLT = 066400B;
BGT = 067000B; BLE = 067400B;
(* Branches : a register and a displacement. *)
DBT = 050310B; DBRA = 050710B;
DBHI = 051310B; DBLS = 051710B; DBCC = 052310B; DBCS = 052710B;
DBNE = 053310B; DBEQ = 053710B; DBVC = 054310B; DBVS = 054710B;
DBPL = 055310B; DBMI = 055710B; DBGE = 056310B; DBLT = 056710B;
DBGT = 057310B; DBLE = 057710B;
(* Set according to condition an effective address. *)
ST = 050300B;
(* Operand is a specific register. *)
SWAP = 044100B;
EXTW = 044200B; (* EXT.W byte to word *)
EXTL = 044300B; (* EXT.L word to long *)
(* Operand is an effective address. *)
CLR = 041000B; NEG = 042000B;
TST = 045000B; COM = 043000B; (* synonym for NOT *)
JMP = 047300B; JSR = 047200B;
PEA = 044100B; TAS = 045300B;
INC1 = 051000B; (* ADDQ #1,ea *)
DEC1 = 051400B; (* SUBQ #1,ea *)
(* Operand is an immediate value. *)
TRAP = 047100B; (* TRAP #vector *)
EMUF = 170000B; (* Line F *)
EMUA = 120000B; (* Line A *)
(* Operands are a register and an effective address. *)
ADD = 150000B; SUB = 110000B;
CMP = 130000B; EORL = 130400B; (* synonym for exclusive OR *)
ANDL = 140000B; (* synonym for AND *)
ORL = 100000B; (* synonym for inclusive OR *)
CHK = 040600B; LEA = 040700B;
DIVS = 100700B; DIVU = 100300B;
MULS = 140700B; MULU = 140300B;
ADDAW= 150300B; (* ADDA.W ea,An *)
ADDAL= 150700B; (* ADDA.L ea,An *)
CMPAL= 130700B; (* CMPA.L ea,An *)
SUBAL= 110700B; (* SUBA.L ea,An *)
EXGL = 140500B; (* EXG.L Dn,Dm *)
(* Immediate data within op. and an effective address. *)
ADDQ = 050000B; SUBQ = 050400B;
(* Shift register by count. *)
ASL = 160400B; ASR = 160000B; LSL = 160410B; LSR = 160010B;
ROL = 160430B; ROR = 160030B;
(* Immediate data within extension and an effective address. *)
ADDI = 003000B; ANDI = 001000B; CMPI = 006000B;
EORI = 005000B; ORI = 000000B; SUBI = 002000B;
(* Bit manipulation. *)
BTST = 000400B; BCHG = 000500B; BCLR = 000600B; BSET = 000700B;
(* Move groups. *)
MOVEB = 010000B; (* group 1 *)
MOVEW = 030000B; (* group 3 *)
MOVEL = 020000B; (* group 2 *)
MOVEAW = 030100B; (* MOVEA.W ea,An *)
MOVEAL = 020100B; (* MOVEA.L ea,An *)
MOVEQ = 070000B; (* MOVE.L #imm,Dn *)
MOVEFRCCR = 041300B; (* MOVE.W CCR,ea *)
MOVETOCCR = 042300B; (* MOVE.W ea,CCR *)
(* MC68040 instruction supplement for integer unit. *)
CHKL = 040400B; (* CHK long *)
DIVL = 046100B; (* 32/32 --> 32r:32q *)
EXTBL = 044700B; (* extend byte to long *)
MULL = 046000B; (* 32*32 --> 32 *)
TRAPEQ = 053774B; (* TRAP on EQ *)
(* MC68040 instruction supplement for floating-point unit. *)
FGEN = 171000B; (* general operation *)
FTRAPcc = 171174B; (* no operand following *)
FST = 171100B; (* FScc *)
FBRA = 171200B; (* FBcc, size = word *)
FMOVEMDEC = 171047B; (* FMOVEM regs,-(SP) *)
FMOVEMD2 = 160000B; (* static list, predecrement *)
FMOVEMINC = 171037B; (* FMOVEM (SP)+,regs *)
FMOVEMI2 = 150000B; (* static list, postincrement *)
FMOVEtoCR = 110000B; (* op-code/op-class for FMOVE to FPCR *)
(* MC68040 instruction op-classes. *)
FtoF = 0; (* FPm to FPn *)
EAtoF = 40000B; (* <ea> to FPn *)
FtoEA = 60000B; (* FPn to <ea> *)
EAtoCR = 110000B; (* <ea> to FPCR *)
CRtoEA = 130000B; (* FPCR to <ea> *)
(* MC68040 floating point operation codes. *)
FMOVE = 0; FABS = 18H; FNEG = 1AH; FSQRT = 04H;
FADD = 22H; FSUB = 28H; FMUL = 23H; FDIV = 20H;
FTST = 3AH; FCMP = 38H;
(* concerning the STATUS register. *)
NBIT = 8; (* negative bit *)
ZBIT = 4; (* zero bit *)
VBIT = 2; (* overflow bit *)
CBIT = 1; (* carry bit *)
(* Left shift constants. *)
LS3 = 10B; LS4 = 20B; LS5 = 40B; LS6 = 100B;
LS7 = 200B; LS8 = 400B; LS9 = 1000B; LS10 = 2000B;
LS11 = 4000B; LS12 = 10000B;
(* System procedure numbers used by the compiler : *)
BodyOfSystem = 0; (* 0 is reserved for module body *)
HALTX = 1; (* System.HALTX = HALT-statement *)
VAR
Rpool, Rbusy, Rlock : BITSET;
FRpool, FRbusy : BITSET;
MoveCode : ARRAY WidType OF CARDINAL;
ShiCode : ARRAY [ Asl .. Ror ] OF CARDINAL;
mask : ARRAY [ 0 .. 32 ] OF LONGINT;
hightyp : StrPtr;
PROCEDURE ProcessorID(VAR id: Processor);
BEGIN
id := "MC68040"
END ProcessorID;
PROCEDURE err(n : CARDINAL);
(* local synonym for M2SM.Mark to save space! *)
BEGIN
Mark(n);
END err;
PROCEDURE Put16(w : WORD);
(* local synonym for M2LM.PutWord to save space! *)
BEGIN
PutWord(w);
END Put16;
PROCEDURE Put32(l : LONGINT);
(* local synonym for M2LM.PutLong to save space! *)
BEGIN
PutLong(l);
END Put32;
PROCEDURE SignedT(VAR x : Item) : BOOLEAN;
(* is x a signed type ? *)
(* Note : Real/LongReal excluded! *)
VAR s : StrPtr;
BEGIN
s := x.typ; (* let x.typ unchanged *)
IF s^.form = Range THEN s := s^.RBaseTyp END;
RETURN (s = inttyp) OR (s = dbltyp)
END SignedT;
PROCEDURE SimpleT(VAR x : Item) : BOOLEAN;
(* is x a simple type of size *)
(* byte/word/long ? *)
(* Note : Real/LongReal excluded! *)
VAR f : StrForm; s : StrPtr; sz : CARDINAL;
BEGIN
s := x.typ; (* let x.typ unchanged *)
IF s^.form = Range THEN s := s^.RBaseTyp END;
f := s^.form; sz := VAL(CARDINAL,s^.size);
RETURN (sz IN {1,2,4}) AND ((f <= Double) OR (f = Pointer) OR
(f = Set) OR (f = ProcTyp) OR (f = Opaque))
END SimpleT;
PROCEDURE RealT(VAR x : Item) : BOOLEAN;
(* is x a floating-point-type ? *)
(* (REAL or LONGREAL) *)
(* Note: floating-point-types are *)
(* NOT considered as simple *)
VAR s : StrPtr;
BEGIN
s := x.typ; (* let x.typ unchanged *)
RETURN (s = realtyp) OR (s = lrltyp)
END RealT;
PROCEDURE SimpleC(VAR x : Item) : BOOLEAN;
(* is x a simple constant of size *)
(* byte/word/long ? *)
(* Note : Real/LongReal excluded! *)
BEGIN
RETURN (x.mode = conMd) & SimpleT(x)
END SimpleC;
PROCEDURE LongVal(VAR x : Item) : LONGINT;
VAR r : LONGINT;
BEGIN r := 0D;
WITH x DO
IF typ^.form = Range THEN typ := typ^.RBaseTyp END;
CASE typ^.form OF
Undef : IF typ^.size = 1 THEN r := LONG(val.Ch)
ELSIF typ^.size = 2 THEN r := LONG(val.C)
ELSE r := val.U END;
| Bool : r := LONG(val.B);
| Char : r := LONG(val.Ch);
| Card, CardInt: r := LONG(val.C);
| Int : r := LONG(val.I);
| Enum : r := LONG(val.Ch);
| Set : r := VAL(LONGINT, val.S);
| LCard,Double : r := val.D;
| Real : r := VAL(LONGINT, val.R);
ELSE r := val.D; (* String, etc. *)
END;
END (*WITH*);
RETURN r
END LongVal;
PROCEDURE WordVal(VAR x : Item) : INTEGER;
VAR r : INTEGER;
BEGIN r := 0;
WITH x DO
IF typ^.form = Range THEN typ := typ^.RBaseTyp END;
CASE typ^.form OF
Undef : IF typ^.size = 1 THEN r := ORD(val.Ch)
ELSIF typ^.size=2 THEN r := VAL(INTEGER,val.C)
ELSE r := VAL(INTEGER, val.U) END;
| Bool : r := ORD(val.B);
| Char : r := ORD(val.Ch);
| Card, CardInt: r := VAL(INTEGER, val.C);
| Int : r := val.I;
| Enum : r := ORD(val.Ch);
| Set : r := VAL(INTEGER, val.S);
| LCard,Double : r := VAL(INTEGER, val.D);
| Real : r := VAL(INTEGER, VAL(LONGINT, val.R));
ELSE r := VAL(INTEGER, val.D); (* String, etc. *)
END;
END (*WITH*);
RETURN r
END WordVal;
PROCEDURE ZeroVal(VAR x : Item) : BOOLEAN;
VAR b : BOOLEAN;
BEGIN b := FALSE;
IF x.mode = conMd THEN
IF x.typ = realtyp THEN b := x.val.R = FLOAT(0)
ELSIF x.typ = lrltyp THEN b := x.val.X = FLOATD(0)
END;
END;
RETURN b
END ZeroVal;
PROCEDURE Iea(fea : CARDINAL) : CARDINAL;
(* invert the 'mode/register' effective address *)
(* to 'register/mode' representation. *)
BEGIN
RETURN (fea MOD 8)*8 + (fea DIV 8)
END Iea;
PROCEDURE Isz(VAR x : Item; VAR fsz : WidType);
(* instruction size for item x : byte/word/long. *)
(* Note : callable only for simple types ! *)
VAR s : INTEGER; sz : WidType;
BEGIN
s := x.typ^.size;
IF s = 1 THEN sz := byte
ELSIF s = 2 THEN sz := word
ELSIF s = 4 THEN sz := long
ELSE sz := long; err(238); (* invalid instruction size *)
END;
fsz := sz
END Isz;
PROCEDURE SetglbMd(VAR x : Item; fadr : INTEGER; ftyp : StrPtr);
(* setup of an item designating a global variable *)
BEGIN
WITH x DO
IF ftyp <> NIL THEN typ := ftyp ELSE typ := undftyp END;
mode := RindMd; mod := 0; lev := 0;
adr := fadr; off := 0; indir := FALSE;
R := SB + 8;
END (*WITH*);
END SetglbMd;
PROCEDURE SetlocMd(VAR x : Item; fadr : INTEGER; ftyp : StrPtr);
(* setup of an item which is relative to the Marker MP *)
BEGIN
WITH x DO
IF ftyp <> NIL THEN typ := ftyp ELSE typ := undftyp END;
mode := RindMd; mod := 0; lev := curLev;
adr := fadr; off := 0; indir := FALSE;
R := MP + 8;
END (*WITH*);
END SetlocMd;
PROCEDURE SetregMd(VAR x : Item; freg : Register; ftyp : StrPtr);
(* setup of an item designating a (long) register. *)
BEGIN
WITH x DO
IF ftyp <> NIL THEN typ := ftyp ELSE typ := undftyp END;
IF freg <= D7 THEN mode := DregMd ELSE mode := AregMd END;
mod := 0; lev := curLev;
adr := 0; off := 0; indir := FALSE;
R := freg; wid := long;
END (*WITH*);
END SetregMd;
PROCEDURE SetstkMd(VAR x : Item; ftyp : StrPtr);
(* setup of an item on top of stack. *)
BEGIN
WITH x DO
IF ftyp <> NIL THEN typ := ftyp ELSE typ := undftyp END;
mode := stkMd; mod := 0; lev := curLev;
adr := 0; off := 0; indir := FALSE;
R := SP + 8;
END (*WITH*);
END SetstkMd;
PROCEDURE SetfltMd(VAR x : Item; fR : Register; ftyp : StrPtr);
(* setup of an item designating a floating-point register. *)
BEGIN
WITH x DO
mode := fltMd; FR := fR; typ := ftyp;
END (*WITH*);
END SetfltMd;
PROCEDURE SetconMd(VAR x : Item; fval : LONGINT; ftyp : StrPtr);
VAR v : ConstValue;
BEGIN
WITH x DO
IF ftyp <> NIL THEN typ := ftyp ELSE typ := undftyp END;
IF typ^.form = Range THEN typ := typ^.RBaseTyp END;
mode := conMd;
CASE typ^.form OF
Undef : IF typ^.size = 1 THEN v.Ch := VAL(CHAR, fval)
ELSIF typ^.size = 2 THEN v.C := VAL(CARDINAL, fval)
ELSE v.U := fval END;
| Bool : v.B := VAL(BOOLEAN, fval);
| Char : v.Ch := VAL(CHAR, fval);
| Card,
CardInt : v.C := VAL(CARDINAL, fval);
| Int : v.I := VAL(INTEGER, fval);
| Enum : v.Ch := VAL(CHAR, fval);
| LCard : v.D := fval;
| Double : v.D := fval;
| Real : v.R := VAL(REAL, fval);
| Set : v.S := VAL(BITSET, fval);
ELSE v.D := fval; (* String, etc. *)
END;
val := v;
END (*WITH*);
END SetconMd;
PROCEDURE SetbusyReg(r : Register);
BEGIN
IF r IN Rpool THEN INCL(Rbusy,r) END;
END SetbusyReg;
PROCEDURE SetbusyFReg(r : Register);
BEGIN
IF r IN FRpool THEN INCL(FRbusy,r) END;
END SetbusyFReg;
PROCEDURE SaveRegs(VAR save : LONGINT);
(* save the busy registers and return the list *)
(* of the saved registers in 'save'. *)
(* *)
(* Note : the saved registers are NOT released *)
(* ---- and remain busy ! *)
(* SP is never saved nor restored ! *)
(* *)
VAR r, lr : Register; x, reglist, n : CARDINAL;
regs : RECORD
CASE :BOOLEAN OF
TRUE : All : LONGINT
| FALSE: FPU, CPU : CARDINAL
END
END;
BEGIN regs.All := 0D;
(* the global (CPU) registers : *)
x := 1; reglist := 0; r := SP + 8; n := 0;
REPEAT (* from SP-1 downto D0 *)
DEC(r); x := x + x;
IF (r IN Rpool) & (r IN Rbusy) THEN
INC(n); lr := r;
reglist := reglist + x;
END;
UNTIL r = D0;
IF reglist <> 0 THEN
IF n = 1 THEN Put16(MVEMSP + lr)
ELSE Put16(MOVEMDEC); Put16(reglist) END; cond
END InvertCC;
PROCEDURE Jf(cond : Condition; VAR l : CARDINAL);
(* jump forward, build chain. *)
VAR c : CARDINAL;
BEGIN c := ORD(cond);
IF c < 16 THEN
(* MC68000 does NOT have a 'Branch on Never True' ! *)
IF c = 1 THEN Put16(CMPI) ELSE Put16(BRA + c*LS8) END;
Put16(l);
ELSE
(* MC68040's FNOP is equal to 'Branch on Never True' ! *)
Put16(FBRA + c); (* use Non-Aware Test *)
Put16(l);
END;
l := pc - 2; (* location of word-displacement *)
END Jf;
PROCEDURE Jb(cond : Condition; l : CARDINAL);
(* jump backward, no chain. *)
VAR c, dd : CARDINAL; d : INTEGER;
BEGIN c := ORD(cond);
d := VAL(INTEGER,l) - VAL(INTEGER,pc) - 2;
dd := VAL(CARDINAL,d);
IF (d >= -128) & (c <> 1) & (c < 16) THEN (* short branch *)
Put16(BRA + c*LS8 + (dd MOD 256))
ELSE
Jf(cond,dd)
END;
END Jb;
PROCEDURE Scc(cond : Condition; Dn : Register);
(* set D-Register according to condition. *)
VAR c : CARDINAL;
BEGIN c := ORD(cond);
IF c < 16 THEN
Put16(ST + c*LS8 + DDIR + Dn);
ELSE
Put16(FST + DDIR + Dn);
Put16(c); (* use Non-Aware Test *)
END;
Put16(NEG + byte*LS6 + DDIR + Dn);
END Scc;
PROCEDURE LoadCC(VAR x : Item);
(* convert from 'cocMd' to 'DregMd' while *)
(* generating conditional code. *)
VAR Dn : Register;
BEGIN
WITH x DO
GetReg(Dn,Dreg);
IF (Tjmp = 0) & (Fjmp = 0) THEN
Scc(InvertCC(CC), Dn);
(* transform 'cocMd' to 'DregMd' *)
SetregMd(x, Dn, booltyp);
wid := byte;
ELSE
Jf(CC, Fjmp);
FixLink(Tjmp);
Put16(MOVEQ + Dn*LS9 + 1);
Put16(BRA + 2);
FixLink(Fjmp);
Put16(MOVEQ + Dn*LS9 + 0);
(* transform 'cocMd' to 'DregMd' *)
SetregMd(x, Dn, booltyp);
wid := long;
END;
END (*WITH*);
END LoadCC;
PROCEDURE ExternalCall(mno, pno : CARDINAL);
(* call of the external procedure #pno in module #mno. *)
VAR An : Register;
BEGIN
GetReg(An,Areg); (* An IN { 8 .. 15 } *)
An := An MOD 8;
Put16(MOVEAL + An*LS9 + AOFF + SB); (* MOVEA.L (maxP+mno)*4(SB),An *)
Put16((maxP + mno)*4);
IF pno = 0 THEN
Put16(MOVEAL + An*LS9 + AIDR + An); (* MOVEA.L (An),An *)
ELSE
Put16(MOVEAL + An*LS9 + AOFF + An); (* MOVEA.L pno*4(An),An *)
Put16(pno*4);
END;
Put16(JSR + AIDR + An); (* JSR (An) *)
ReleaseReg(An + 8);
END ExternalCall;
PROCEDURE downlevel(VAR x : Item);
(* for level difference >= 1. *)
CONST offSL = 8; (* offset of Static Link *)
VAR N,An : Register; n : CARDINAL;
BEGIN
GetReg(N,Areg); (* N IN { 8..15 } *)
An := N MOD 8;
Put16(MOVEAL + An*LS9 + AOFF + MP); (* MOVEA.L offSL(MP),An *)
Put16(offSL);
n := curLev - x.lev;
WHILE n > 1 DO
DEC(n);
Put16(MOVEAL + An*LS9 + AOFF + An); (* MOVEA.L offSL(An),An *)
Put16(offSL);
END;
ReleaseReg(x.R);
x.R := N;
END downlevel;
PROCEDURE Ext(VAR x : Item);
(* effective address extension of x. *)
VAR ext : CARDINAL; sz : INTEGER;
BEGIN
WITH x DO
CASE mode OF
absMd : Put32(adr);
| RindMd : IF adr <> 0 THEN Put16(adr) END;
| RidxMd : IF wid = word THEN ext := RX*LS12 + scl*LS9
ELSE ext := RX*LS12 + LS11 + scl*LS9 END;
Put16(ext + (VAL(CARDINAL,adr) MOD 256));
| conMd : IF typ = stringtyp THEN
Put16(val.D0 + VAL(INTEGER, maxP+maxM)*4)
ELSE sz := typ^.size;
IF sz = 1 THEN Put16(WordVal(x))
ELSIF sz = 2 THEN Put16(WordVal(x))
ELSIF sz = 4 THEN Put32(LongVal(x))
ELSIF sz = 8 THEN
Put16(val.D0); Put16(val.D1);
Put16(val.D2); Put16(val.D3);
END;
END;
| stkMd : (* no extension *)
| AregMd,DregMd : (* no extension *)
| procMd : IF (proc <> NIL) & (proc^.pd <> NIL) &
(proc^.pd^.adr <> 0) THEN
(* local procedure *)
Put16(proc^.pd^.adr - VAL(INTEGER,pc));
ELSE (* external procedure *)
(* no extension *)
END;
| prgMd : Put16(VAL(INTEGER,where) - VAL(INTEGER,pc));
| typMd,codMd : (* no extension *)
| cocMd,fltMd : (* no extension *)
END (*CASE*);
END (*WITH*);
END Ext;
PROCEDURE ReduceIndir(VAR x : Item; ea : CARDINAL);
(* Note : A-Registers internally numbered from 8 .. 15! *)
VAR src, dst : Register;
BEGIN
WITH x DO
CASE mode OF
absMd :
GetReg(dst,Areg);
Put16(MOVEAL + (dst MOD 8)*LS9 + ea);
Ext(x);
| RindMd,RidxMd :
src := R;
IF Islocked(src) THEN GetReg(dst,Areg)
ELSE dst := src END;
Put16(MOVEAL + (dst MOD 8)*LS9 + ea);
Ext(x);
IF dst <> src THEN ReleaseReg(src) END;
IF mode = RidxMd THEN ReleaseReg(RX) END;
END (*CASE*);
(* transform all modes to 'RindMd' *)
mode := RindMd; R := dst; (* R IN { 8..15 } *)
indir := FALSE; adr := off; off := 0;
END (*WITH*);
END ReduceIndir;
PROCEDURE GeaP(VAR x : Item; VAR fea : CARDINAL);
(* effective address of an item designating a procedure. *)
VAR An : Register;
BEGIN
WITH x DO
IF (proc <> NIL) & (proc^.pd <> NIL) &
(proc^.pd^.adr <> 0) THEN (* local procedure *)
fea := PREL;
ELSE (* external procedure *)
GetReg(An,Areg);
Put16(MOVEAL + (An MOD 8)*LS9 + AOFF + SB);
Put16((maxP + VAL(CARDINAL,proc^.pmod))*4);
Put16(MOVEAL + (An MOD 8)*LS9 + AOFF + (An MOD 8));
Put16(proc^.pd^.num*4);
(* transform 'procMd' to 'AregMd' *)
SetregMd(x, An, typ);
fea := ADIR + (An MOD 8);
END;
END (*WITH*);
END GeaP;
PROCEDURE Gea(VAR x : Item; VAR fea : CARDINAL);
(* give effective address of x. *)
VAR ea : CARDINAL; An : Register;
BEGIN
WITH x DO
CASE mode OF
absMd : ea := XXXL;
| RindMd : IF R = (MP + 8) THEN
IF lev <> curLev THEN downlevel(x) END;
END;
IF adr <> 0 THEN ea := AOFF + (R MOD 8)
ELSE ea := AIDR + (R MOD 8) END;
| RidxMd : IF (-128 <= adr) & (adr <= 127) THEN
ea := AIDX + (R MOD 8)
ELSE (* adr out of 8-bit range *)
IF Islocked(R) THEN GetReg(An,Areg)
ELSE An := R END;
Put16(LEA + (An MOD 8)*LS9 + AIDX + (R MOD 8));
IF wid = word THEN Put16(RX*LS12 + scl*LS9)
ELSE Put16(RX*LS12 + LS11 + scl*LS9) END;
IF R <> An THEN ReleaseReg(R) END;
ReleaseReg(RX);
(* transform 'RidxMd' to 'RindMd' *)
mode := RindMd; ea := AOFF + (An MOD 8);
R := An;
END (*RidxMd*);
| conMd : IF typ = stringtyp THEN
ea := AOFF + SB (* SB-relative *)
ELSE
ea := IMM (* for all sizes *)
END;
| stkMd : ea := AINC + SP; (* gives (SP)+ *)
| AregMd : ea := ADIR + (R MOD 8);
| DregMd : ea := DDIR + (R MOD 8);
| prgMd : ea := PREL;
| typMd, codMd : ea := DDIR + D0; (* dummy effective address *)
err(232); (* NO address equivalent ! *)
| procMd, cocMd,
fltMd : ea := DDIR + D0; (* dummy effective address *)
err(233); (* should never occur here!*)
END (*CASE*);
IF (mode < conMd) & indir THEN
ReduceIndir(x,ea);
IF adr <> 0 THEN ea := AOFF + (R MOD 8)
ELSE ea := AIDR + (R MOD 8) END;
END;
END (*WITH*);
fea := ea ; (* resulting effective address *)
END Gea;
PROCEDURE OvflTrap(signed : BOOLEAN);
(* overflow-check thru TRAPV for signed arithmetic : *)
BEGIN
IF NOT ovflchk THEN RETURN END;
IF signed THEN Put16(TRAPV) END;
END OvflTrap;
PROCEDURE OvflCheck(R : Register; signed : BOOLEAN);
(* overflow-check for 16*16bit signed multiplication : *)
VAR Dn : Register;
BEGIN
IF NOT ovflchk THEN RETURN END;
IF signed THEN
GetReg(Dn,Dreg); (* scratch reg. *)
Put16(MOVEW + Dn*LS9 + R); (* copy wordpart *)
Put16(EXTL + Dn); (* EXT.L Dn *)
Put16(CMP + R*LS9 + long*LS6 + Dn); (* CMP.L Dn,R *)
Put16(BEQ + 6); (* BEQ.S 6 *)
Put16(ORI + IMM); (* ORI.W #VBIT,SR*)
Put16(VBIT);
Put16(TRAPV); (* TRAPV *)
ReleaseReg(Dn);
END;
END OvflCheck;
PROCEDURE StackTop(i : INTEGER);
(* increment/decrement stack pointer SP : *)
(* i > 0 : increment SP, reset stack *)
(* i < 0 : decrement SP, reserve stack *)
VAR neg : BOOLEAN; c : CARDINAL;
BEGIN
IF i <> 0 THEN
neg := (i < 0);
IF ODD(i) THEN
IF neg THEN DEC(i) ELSE INC(i) END;
END;
IF (-8 <= i) & (i <= 8) THEN
c := (VAL(CARDINAL,ABS(i)) MOD 8)*LS9;
IF neg THEN Put16(DECSP + c)
ELSE Put16(INCSP + c) END;
ELSE
Put16(LEASP);
Put16(i);
END;
END (*i <> 0*);
END StackTop;
PROCEDURE SetupSL(plev : CARDINAL);
(* push Static Link onto stack. *)
CONST offSL = 8; (* offset of Static Link relative to MP *)
VAR N, An : Register; n : CARDINAL;
BEGIN
IF plev <> 0 THEN
IF plev = curLev THEN
(* level difference = 0 *)
Put16(PEA + AIDR + MP); (* PEA (MP) *)
ELSIF plev + 1 = curLev THEN
(* level difference = 1 *)
Put16(MVEMSP + AOFF + MP); (* MOVE.L offSL(MP),-(SP) *)
Put16(offSL);
ELSE
(* level difference >= 2 *)
GetReg(N,Areg); An := N MOD 8;
Put16(MOVEAL + An*LS9 + AOFF + MP); (* MOVEA.L offSL(MP),An *)
Put16(offSL);
n := curLev - plev;
WHILE n > 2 DO
DEC(n);
Put16(MOVEAL + An*LS9 + AOFF+An); (* MOVEA.L offSL(An),An *)
Put16(offSL);
END;
Put16(MVEMSP + AOFF + An); (* MOVE.L offSL(An),-(SP) *)
Put16(offSL);
ReleaseReg(N);
END;
END (*plev <> 0*);
END SetupSL;
PROCEDURE InitM2HM;
VAR k : CARDINAL; exp : LONGINT;
BEGIN
curLev := 0;
MoveCode[byte] := MOVEB; MoveCode[word] := MOVEW;
MoveCode[long] := MOVEL;
ShiCode [Asl] := ASL; ShiCode [Asr] := ASR;
ShiCode [Lsl] := LSL; ShiCode [Lsr] := LSR;
ShiCode [Rol] := ROL; ShiCode [Ror] := ROR;
exp := 0D; mask[0] := 0D; mask[32] := -1D;
FOR k := 1 TO 31 DO exp := exp + exp + 1D; mask[k] := exp END;
IF DynArrDesSize = 6 THEN hightyp := inttyp
ELSE hightyp := dbltyp END;
InitRegs;
END InitM2HM;
PROCEDURE LoadAdr(VAR x : Item);
(* ADR(x) --->>> pointer/address-register. *)
VAR ea, am, op : CARDINAL; An : Register; newA, loaded : BOOLEAN;
BEGIN op := LEA;
WITH x DO
IF (mode IN ItSet{stkMd,AregMd,DregMd,cocMd,typMd,codMd,fltMd})
OR ((mode = conMd) & (typ <> stringtyp)) THEN
err(231); (* no effective address possible *)
Release(x); SetregMd(x, A0+8, undftyp);
END;
IF (mode < conMd) & indir & (off=0) THEN op := MOVEAL; indir := FALSE END;
IF mode = procMd THEN GeaP(x,ea) ELSE Gea(x,ea) END;
am := (ea DIV 8)*8;