Pristine Ack-5.5
[Ack-5.5.git] / mach / z8000 / as / mach5.c
1 /*
2  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
3  * See the copyright notice in the ACK home directory, in the file "Copyright".
4  */
5 #define RCSID5 "$Id: mach5.c,v 0.4 1994/06/24 13:56:30 ceriel Exp $"
6
7 settype( type )
8 int     type;
9 {       oprtype[ operand ] = type;      }
10
11
12 int     twolog( s )
13 int     s;
14 {       int     twopower = 0;
15         while ( (s>>=1) != 0 )  twopower++;
16         return( twopower );
17 }
18
19
20 setmode( opr )
21 int     opr;
22 {       mode = modetbl[ twolog( oprtype[opr] ) ] << 12; }
23
24
25 chtype( opr, typerange )
26 int     opr,
27         typerange;
28 /* Check type of 'opr' with given 'typerange' and
29 ** set the global var 'mode'.
30 */
31 {       if ( (oprtype[opr] & typerange) != oprtype[opr] )  argerr();
32         else /* We have a permitted type for 'opr'. */  setmode( opr );
33 }
34
35
36 chreg( opc, reg )
37 int     opc, reg;
38 {       switch( opc ) {
39         case 0xB10A: case 0x1B00: case 0x1900:
40                 /* R32 expected */  if (reg & 1) regerr();  break;
41         case 0xB107: case 0x1A00: case 0x1800:
42                 /* R64 expected */  if (reg & 3) regerr();  break;
43         }
44 }
45
46 ATYPE   checkaddr( addr )
47 valu_t  addr;
48 /* Called by functions emit_ad() and branch().  */
49 {       ATYPE   addr_struct;
50
51         addr_struct.seg = addr >> 16;
52         addr_struct.off = addr & 0xFFFF;
53         if ( addr_struct.seg < 0 )  addr_struct.seg = 0;
54 #ifdef ASLD
55         else  fit(fit7(addr_struct.seg));
56 #endif
57         return( addr_struct );
58 }
59
60 emit_ad( ad_inf )
61 expr_t  ad_inf;
62 /* When the type of an operand is 'da' or 'x' this function
63 ** emits the address.
64 */
65 {       ATYPE   addr;
66
67         addr = checkaddr( ad_inf.val );
68                 /* Always the long format is emitted, because the binary
69                 ** will be downloaded into one z8000-segment with offset
70                 ** 0x0000 upto 0xFFFF,so the chance we can use the short
71                 ** format is very small.
72                 */
73         emit2( 1<<15 | addr.seg<<8 );
74         emit2( addr.off );              /* ??? relocation information ??? */
75 }
76
77
78 ldmcode( wrd1, wrd2, num )
79 int     wrd1, wrd2, num;
80 {       fit(fit4(num-1));
81         emit2( mode | wrd1 );
82         emit2( wrd2<<8 | num-1 );
83         if ( mode>>12 == 4 ) emit_ad( addr_inf );
84 }
85
86
87 valu_t  adjust( absval )
88 valu_t  absval;
89 {       valu_t  val = absval - DOTVAL - 2;
90
91         if ( pass == PASS_2 && val > 0 ) val -= DOTGAIN;
92         return( val );
93 }
94
95
96 branch( opc, exp )
97 int     opc;
98 expr_t  exp;
99 /* This routine determines for the F3 format instructions whether the
100 ** relative address is small enough to fit in normal code; If this is
101 ** so normal code is emitted otherwise 'long' code is emitted contai-
102 ** ning the direct address.
103 */
104 {       int     longopc = 0, reladdr = 0, sm2, sm4;
105         valu_t  val;
106         ATYPE   addr;
107
108         val = adjust(exp.val) >> 1;
109         if ( (exp.typ & ~S_DOT) != DOTTYP )  sm2 = sm4 = 0;
110         else
111         {   switch ( opc & 0xF000 )
112             {   case DJNZ_: sm2 = fit7( -val );
113                             reladdr = -val;
114                             break;
115                 case JR_:   sm2 = fits8( val );
116                             reladdr = low8( val );
117                             longopc = 0x5E00 | (opc>>8 & 0xF);
118                             break;
119                 case CALR_: sm2 = fits12( -val );
120                             reladdr = low12( -val );
121                             longopc = 0x5F00;
122                             break;
123             }
124             sm4 = sm2 || fit8( (int)exp.val );
125         }
126         switch ( opc & 0xF000 )
127         {   case DJNZ_: fit( sm2 );  /* djnz must be short */
128                         emit2( opc | reladdr );
129                         break;
130             case JR_: case CALR_:
131                         sm4 = small(sm4, 2);
132                         sm2 = small(sm2, 2);
133                         if ( sm2 )  emit2( opc | reladdr );
134                         else  /* replace by jp/call da */
135                         {   emit2( longopc );
136                             addr = checkaddr( exp.val );
137                             if ( sm4 )  /* short-offset */
138                                 emit2( addr.seg<<8 | addr.off );
139                             else
140                             {   emit2( 1<<15 | addr.seg<<8 );
141                                 emit2( addr.off );
142                             }
143                         }
144         }
145 }
146
147
148 ldrel( opc, exp )
149 int     opc;
150 expr_t  exp;
151 /* This routine determines for the F4 format instructions whether the
152 ** address is within the same segment  (meaning a relative address of
153 ** less than 16 bits); If this is so normal code is emitted otherwise
154 ** an error message is given.
155 */
156 {       if ( pass >= PASS_2 && (exp.typ & ~S_DOT) != DOTTYP )
157                                 serror( "relative too far" );
158         emit2( opc );
159         emit2( (int)adjust(exp.val) );
160 }
161
162
163 shiftcode( w1, w2 )
164 int     w1, w2;
165 {   switch( w1 & 0x0F04 )
166     {   /* Remember: w2 negative means right shift !   */
167         case 0x200: /*byte*/  fit( w2>=-8 && w2<=8 );  break;
168         case 0x300: /*word*/  fit( w2>=-16 && w2<=16 );  break;
169         case 0x304: /*long*/  fit( w2>=-32 && w2<=32 );  break;
170     }
171     emit2( w1 );
172     emit2( w2 );
173 }
174
175
176 argerr()
177 {       serror( "illegal operand" );    }