📄 ccout.c
字号:
outtab ();
outtab ();
outnum (p->Pdouble2);
outc (']');
}
if (!delete) /* If keeping asm file around, */
fprintf (out,"\t; %.20g",p->Pdouble); /* add comment for humans */
break;
default:
int_error ("outinstr: bad adrmode %d", (p->Ptype & PTF_ADRMODE));
}
outnl (); /* Done with instruction, finish off! */
if (vrbfun)
_word_cnt++;
}
/* ONEINSTR (p) - See if an instruction is safe to skip over.
**
** Takes an instruction as argument and returns true if that
** instruction will expand to one machine code word.
** This routine is in CCOUT because it must accurately reflect what
** CCOUT will actually do for a given pseudo-instruction.
*/
int
oneinstr (PCODE *p)
{
switch (p->Pop & POF_OPCODE)
{
/* Simulated ops always expand out. */
case P_PTRCNV:
case P_SMOVE:
case P_UIDIV:
case P_UFLTR:
case P_SUBBP:
case P_DFIX:
case P_DSNGL:
return 0;
/* These instructions may or may not expand out, depending on the
** target machine. If unsupported, they are actually macros defined
** by the assembler header.
** None of them have an "immediate" form, so PTV_IINDEXED can never happen.
*/
case P_DMOVE:
case P_DMOVN:
case P_DMOVEM:
return 1; /* TRUE if machine has DMOVx */
case P_ADJBP:
return 1; /* TRUE if machine has ADJBP */
case P_DFAD:
case P_DFSB:
case P_DFMP:
case P_DFDV:
return 1; /* TRUE if machine has hardware dbls */
case P_FLTR:
return 1; /* TRUE if machine has hardware FLTR */
case P_TRN:
case P_TRO:
case P_TRC:
case P_TRZ: /* RH tests */
case P_TLN:
case P_TLO:
case P_TLC:
case P_TLZ: /* LH tests */
case P_CAI:
case P_LSH:
case P_ASH:
return (p->Ptype != PTA_MINDEXED); /* PTV_IINDEXED for implicit immed op */
/* All other (standard) instructions.
*/
default: /* OPI R,addr expands to */
return (p->Ptype != PTV_IINDEXED); /* MOVEI 16,addr ? OP r,16 */
/* Special case of above, which always wins */
case P_MOVE:
case P_MOVEI:
return 1; /* OK even for PTV_IINDEXED */
}
}
static int
directop (int op)
{
switch (op & POF_OPCODE)
{
case P_CAI:
return op ^ (P_CAI ^ P_CAM);
case P_TRN:
return op ^ (P_TRN ^ P_TDN);
case P_TRO:
return op ^ (P_TRO ^ P_TDO);
case P_TRC:
return op ^ (P_TRC ^ P_TDC);
case P_TRZ:
return op ^ (P_TRZ ^ P_TDZ);
default:
return 0;
}
}
/* SIMUFLTR - Output expansion of P_UFLTR unsigned float "instruction".
** UFLTR R,M
** R = register to leave single-precision float in.
** M = any memory reference to single-word integer operand
**
** Note that for machines without the FLTR instruction, we don't even
** bother to get things right since the usual substitute (FSC R,233) won't
** work. Need a fancy KA-10 float routine.
**
** Expands into:
** if R == M if R != M
** SKIPGE 16,M SKIPGE R,M ; Fetch or copy the float
** LSH R,-1 LSH R,-1 ; If sign bit set, shift down
** FLTR R,R FLTR R,R ; Float the positive integer!
** CAIGE 16, SKIPGE M ; If number was shifted,
** FSC R,1 FSC R,1 ; adjust exponent accordingly.
*/
static void
simufltr (PCODE *p)
{
int r = p->Preg;
int mr = ((p->Ptype&PTF_ADRMODE) == PTA_REGIS) ? p->Pr2 : 0;
p->Pop = P_SKIP+POF_ISSKIP+POS_SKPGE;
if (r == mr)
p->Preg = R_SCRREG; /* 16 */
outinstr (p); /* SKIPGE R,M or SKIPGE 16,R */
fprintf (out,"\t LSH\t%o,-1\n", r); /* LSH R,-1 */
fprintf (out,"\tFLTR\t%o,%o\n", r, r); /* FLTR R,R */
if (r == mr)
fprintf (out,"\tCAIGE\t%o,\n", R_SCRREG); /* CAIGE 16, */
else /* or */
{
if (mr)
fprintf (out,"\tCAIGE\t%o,\n", R_SCRREG); /* CAIGE R, */
else
{
outstr ("\tSKIPGE "); /* SKIPGE M */
outaddress (p);
outnl ();
}
}
fprintf (out,"\t FSC\t%o,1\n", r); /* FSC R,1 */
}
/* SIMDFIX - Output expansion of P_DFIX double-to-integer conversion "instr"
** P_DFIX reg,M
** reg = register pair, integer will be left in 1st reg.
** M = any memory ref to double-word float operand.
**
** Note that reg+1 is clobbered!
** Expands into:
** DMOVE R,M
** HLRE 16,R ;This mattered when shifts were bit-at-a-time
** ASH 16,-11 ;Get just exponent (9 bits)
** JUMPGE 16,.+3 ;Positive?
** DMOVN R,R ;No, negate, orig sign still in 1B0[A]
** ; For KA-10 format this is DFN R,R+1.
** TRC 16,777777 ;Watch for diff between twos and ones comp
** TLZ R,777000 ;Bash exponent and sign ... now positive
** ; For KA-10 format, LSH R+1,10 goes here.
** ASHC R,-233 (16) ;Make an integer (may overflow)
** CAIGE 16, ;Original negative? Check its sign.
** MOVN R,R ;Yup, negate result.
*/
static void
simdfix (PCODE *p)
{
int r = p->Preg;
/* Check for DFIX R,R and skip the DMOVE if that's what we have */
if ((p->Ptype&PTF_ADRMODE) != PTA_REGIS || r != p->Pr2)
{
p->Pop = P_DMOVE; /* Make DMOVE R,M to get double */
outinstr (p);
}
fprintf (out, "\tHLRE\t16,%o\n\tASH\t16,-11\n\tJUMPGE\t16,.+3\n", r);
fprintf (out, "\tDMOVN\t%o,%o\n", r, r);
outstr ("\tTRC\t16,-1\n");
fprintf (out, "\tTLZ\t%o,777000\n", r);
fprintf (out, "\tASHC\t%o,-233 (16)\n", r);
outstr ("\tCAIGE\t16,\n"); /* Check sign bit of original # */
fprintf (out, "\t MOVNS\t%o\n", r); /* Negate result */
}
/* SIMDSNGL - Output expansion of P_DSNGL double-to-float conversion "instr"
** P_DSNGL reg,M
** reg = register pair, float will be left in 1st reg.
** M = any memory ref to double-word float operand.
**
** Note that reg+1 is clobbered!
** Expands into:
** DMOVE R,M ; Get double value
** SKIPGE 16,R ; Check sign, save indicator
** DMOVN R,R ; Negative, make positive temporarily.
** TLNE R+1,200000 ; If low word >= .5
** TRON R,1 ; then must round high wd, try fast hack
** JRST .+4 ; Won!
** MOVE R+1,R ; Ugh, have to do it hard way. Copy high wd
** AND R+1,[777000000001] ; Zap all but exp and low-order bit
** FADR R,R+1 ; Add low bit to effect rounding
** CAIGE 16, ; Now if original was negative,
** MOVN R,R ; make it negative again.
*/
static void
simdsngl (PCODE *p)
{
int r = p->Preg;
/* Check for DSNGL R,R and skip the DMOVE if that's what we have */
if ((p->Ptype&PTF_ADRMODE) != PTA_REGIS || r != p->Pr2)
{
p->Pop = P_DMOVE; /* Make DMOVE R,M to get double */
outinstr (p);
}
fprintf (out, "\tSKIPGE\t16,%o\n", r);
fprintf (out, "\t DMOVN\t%o,%o\n", r, r);
fprintf (out, "\tTLNE\t%o,200000\n", r+1);
fprintf (out, "\t TRON\t%o,1\n\t JRST\t.+4\n", r);
fprintf (out, "\tMOVE\t%o,%o\n\tAND\t%o,[777000,,1]\n\tFADR\t%o,%o\n",
r+1, r,
r+1,
r, r+1);
outstr ("\tCAIGE\t16,\n"); /* Check sign bit of original # */
fprintf (out, "\t MOVNS\t%o\n", r); /* Negate result */
}
/* SIMSUBBP - Output expansion of P_SUBBP byte-pointer subtraction "instr".
** P_SUBBP reg,M [plus Pbsize set to bytesize if known]
** reg = register pair, 1st reg contains minuend BP
** M = any memory ref to subtrahend BP
** Pbsize = bytesize of pointers (> 0 if known)
** This is currently only used if M operand is P_CONST.
** Leaves resulting # in 2nd reg!
**
** This makes use of 2 special symbols from CPU.C and
** some tables in CRT.C, and expands into:
** Known size Unknown size
** LDB 16,[$$BPSZ,,R] ; get PS from R
** SUB R,M SUB R,M
** MULI R,$$BMPn MUL R,$BPMUL (16)
** ASH R+1,$$BSHF ASH R+1,$$BSHF
** ADD R,$BPADT (16)
** ADD R+1,$BPADn (A) ADD R+1, (A)
*/
static void
simsubbp (PCODE *p)
{
int siz, typ, tbidx;
if ((typ = (p->Ptype&PTF_ADRMODE)) == PTA_PCONST)
siz = (int) p->Pbsize; /* Aha, size is known! */
else
siz = 0;
switch (siz)
{
case 6:
tbidx = 0;
break;
case 7:
tbidx = 1;
break;
case 8:
tbidx = 2;
break;
case 9:
tbidx = 3;
break;
case 18:
tbidx = 4;
break;
default:
int_error ("simsubbp: bad Pbsize: %ld", (INT) siz);
siz = 0;
case 0:
fprintf (out, "\tLDB\t16,[%s,,%o]\n", crtsnam[CRT_BPSZ], p->Preg);
crtref[CRT_BPSZ]++;
}
/* Simple check to verify addressing mode is OK */
switch (typ)
{
case PTA_PCONST:
case PTA_REGIS:
case PTA_MINDEXED:
break;
default:
int_error ("simsubbp: bad adrmode: %ld", (INT) typ);
}
p->Pop = P_SUB; /* Make SUB R,M */
outinstr (p);
if (siz)
{
fprintf (out, "\tMULI\t%o,%s\n", p->Preg, crtsnam[CRT_BMP6+tbidx]);
crtref[CRT_BMP6+tbidx]++;
}
else
{
fprintf (out, "\tMUL\t%o,%s (16)\n", p->Preg, crtsnam[CRT_BPMUL]);
crtref[CRT_BPMUL]++;
}
fprintf (out, "\tASH\t%o,-%s\n", p->Preg+1, crtsnam[CRT_BSHF]);
crtref[CRT_BSHF]++;
if (!siz)
{
fprintf (out, "\tADD\t%o,%s (16)\n", p->Preg, crtsnam[CRT_BPADT]);
crtref[CRT_BPADT]++;
fprintf (out, "\tADD\t%o, (%o)\n", p->Preg+1, p->Preg);
}
else
{
fprintf (out, "\tADD\t%o,%s (%o)\n",
p->Preg+1, crtsnam[CRT_BPAD6+tbidx], p->Preg);
crtref[CRT_BPAD6+tbidx]++;
}
}
/*
** NOTE:
** Byte pointer comparison used to be simulated too but now is done
** with explicit instructions by CCGEN2.
*/
/* NOTE:
** Some PDP-10 architecture machines have no ADJBP instruction.
** We used to expand a sequence for P_ADJBP similar to that for
** P_SUBBP, but now we always just output P_ADJBP
** as ADJBP R,X and it is up to the C-HDR preamble file to redefine
** ADJBP as a macro (in a form similar to the above) if the machine
** does not support ADJBP. This allows machine-language library routines
** to use ADJBP in their code.
*/
/* SIMPTRCNV - Output expansion of P_PTRCNV pointer conversion "instruction".
** P_PTRCNV reg,offset [plus Pbsize set to desired bytesize]
** reg = register containing pointer to convert
** offset = bytesize of old pointer
** Pbsize = desired bytesize of new pointer
**
** Currently this only supports 9<->18 bit conversions, and the
** code generator shouldn't give us anything else.
** The interaction between the special instruction symbols defined in the
** library $$$CPU module and the code here has been carefully arranged.
** In particular the instructions must take up the same amount of space
** whether being loaded for zero-section or multi-section operation, and
** they must NOT change the value of a NULL (zero) pointer.
**
** The conversions to and from word pointers are done by the code
** generator (with TDZ/TLZ or SKIPE+IOR/TLO) because it may be possible
** for the peephole optimizer to do something with those instructions.
*/
static void
simptrcnv (PCODE *p)
{
int *ip;
#ifdef MULTI_SECTION /* FW 2A (51) */
static INT cvH_9[] = {CRT_PH90, CRT_PH91, 0};
static INT cv9_H[] = {CRT_P9H0, CRT_P9H1, CRT_P9H2, 0};
#endif
/* Switch depending on original size plus desired size */
switch ((int) (TGSIZ_WORD* p->Poffset + p->Pbsize))
{
case TGSIZ_WORD* 9 + 18: /* 9-bit to 18-bit */
fprintf (out, "\tTLZE\t%o,117700\n", p->Preg);
fprintf (out, "\t TLO\t%o,002200\n", p->Preg);
return;
case TGSIZ_WORD* 18 + 9: /* 18-bit to 9-bit */
fprintf (out, "\tTLZE\t%o,007700\n", p->Preg);
fprintf (out, "\t TLO\t%o,111100\n", p->Preg);
return;
default:
int_error ("simptrcnv: bad bsize: %ld", (INT) p->Pbsize);
return;
}
/* Wrap up with special instructions the value of which depends
** on whether the code is being loaded for a zero-section or
** multi-section program. The specified register is added into
** the symbols in such a way that it fits into the AC field.
*/
for (; *ip; ++ip)
{
fprintf (out,"\t%s+<%lo>\n", crtsnam[*ip], (INT) p->Preg<<23);
++crtref[*ip];
}
}
/* SIMSMOVE - Output expansion of P_SMOVE structure copy "instruction".
** P_SMOVE reg,addr+offset (idx) [plus Pbsize set to # words]
** reg = register containing destination word address
** addr+offset (idx) = source address
** Pbsize = # words to copy
*/
static void
simsmove (PCODE *p)
{
INT size;
if ((p->Ptype&PTF_ADRMODE) != PTA_MINDEXED)
{
int_error ("simsmove: bad adrmode:\t%o", p->Ptype);
return;
}
switch ((int) (size = p->Pbsize))
{
case 1:
case 2:
fprintf (out,"\tMOVEI\t16,-1 (%o)\n", p->Preg); /* dest <addr-1> */
while (--size >= 0)
{
outstr ("\tPUSH\t16,");
outaddress (p);
outnl ();
++ (p->Poffset);
}
return;
default:
if (size <= 0)
{
int_error ("simsmove: bad size %ld", (INT) size);
return;
}
fprintf (out,"\tMOVEI\t16, (%o)\n\tHRLI\t16,",p->Preg);
outaddress (p); /* for HRLI\t16,<source-addr> */
fprintf (out,"\n\tBLT\t16,%lo (%o)\n", (INT) size-1, p->Preg);
return;
}
}
/* SIMUIDIV - Output expansion of P_UIDIV unsigned division "instruction".
** P_UIDIV reg,<addr>
** reg = register containing dividend (two-word register)
** addr = divisor
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -