1 /*
2 Z88DK Z80 Macro Assembler
3 
4 Copyright (C) Gunther Strube, InterLogic 1993-99
5 Copyright (C) Paulo Custodio, 2011-2020
6 License: The Artistic License 2.0, http://www.perlfoundation.org/artistic_license_2_0
7 Repository: https://github.com/z88dk/z88dk
8 
9 Define CPU opcodes
10 */
11 
12 #include "../portability.h"
13 #include "directives.h"
14 #include "expr.h"
15 #include "codearea.h"
16 #include "model.h"
17 #include "opcodes.h"
18 #include "parse.h"
19 #include "z80asm.h"
20 #include <assert.h>
21 
22 /* add 1 to 4 bytes opcode opcode to object code
23 *  bytes in big-endian format, e.g. 0xCB00 */
add_opcode(int opcode)24 void add_opcode(int opcode)
25 {
26 	bool out = false;
27 
28 	if (opcode & 0xFF000000) {
29 		out = true;
30 		append_byte( (opcode >> 24) & 0xFF );
31 	}
32 
33 	if (out || (opcode & 0xFF0000)) {
34 		out = true;
35 		append_byte( (opcode >> 16) & 0xFF );
36 	}
37 
38 	if (out || (opcode & 0xFF00)) {
39 		out = true;
40 		append_byte((opcode >> 8) & 0xFF);
41 	}
42 
43 	append_byte( opcode & 0xFF );
44 }
45 
46 /* add opcode followed by jump relative offset expression */
add_opcode_jr(int opcode,Expr * expr)47 void add_opcode_jr(int opcode, Expr *expr)
48 {
49 	add_opcode_jr_n(opcode, expr, 0);
50 }
51 
add_opcode_jr_n(int opcode,struct Expr * expr,int asmpc_offset)52 void add_opcode_jr_n(int opcode, struct Expr* expr, int asmpc_offset)
53 {
54 	expr->asmpc += asmpc_offset;		// expr is assumed to be at asmpc+1; add offset if this is not true
55 
56 	if (opts.opt_speed) {
57 		switch (opcode) {
58 		case Z80_JR:
59 			add_opcode(Z80_JP);
60 			Pass2infoExpr(RANGE_WORD, expr);
61 			break;
62 		case Z80_JR_FLAG(FLAG_NZ):
63 		case Z80_JR_FLAG(FLAG_Z):
64 		case Z80_JR_FLAG(FLAG_NC):
65 		case Z80_JR_FLAG(FLAG_C):
66 			add_opcode(opcode - Z80_JR_FLAG(0) + Z80_JP_FLAG(0));
67 			Pass2infoExpr(RANGE_WORD, expr);
68 			break;
69 		case Z80_DJNZ:		// "dec b; jp nz" is always slower
70 			add_opcode(opcode);
71 			Pass2infoExpr(RANGE_JR_OFFSET, expr);
72 			break;
73 		default:
74 			assert(0);
75 		}
76 	}
77 	else {
78 		add_opcode(opcode);
79 		Pass2infoExpr(RANGE_JR_OFFSET, expr);
80 	}
81 }
82 
83 /* add opcode followed by 8-bit unsigned expression */
add_opcode_n(int opcode,Expr * expr)84 void add_opcode_n(int opcode, Expr *expr)
85 {
86 	add_opcode(opcode);
87 	Pass2infoExpr(RANGE_BYTE_UNSIGNED, expr);
88 }
89 
90 /* add opcode followed by 8-bit unsigned expression and a zero byte */
add_opcode_n_0(int opcode,struct Expr * expr)91 void add_opcode_n_0(int opcode, struct Expr* expr)
92 {
93     add_opcode(opcode);
94     Pass2infoExpr(RANGE_BYTE_TO_WORD_UNSIGNED, expr);
95 }
96 
add_opcode_s_0(int opcode,struct Expr * expr)97 void add_opcode_s_0(int opcode, struct Expr* expr)
98 {
99     add_opcode(opcode);
100     Pass2infoExpr(RANGE_BYTE_TO_WORD_SIGNED, expr);
101 }
102 
103 /* add opcode followed by 8-bit signed expression */
add_opcode_d(int opcode,Expr * expr)104 void add_opcode_d(int opcode, Expr *expr)
105 {
106 	add_opcode(opcode);
107 	Pass2infoExpr(RANGE_BYTE_SIGNED, expr);
108 }
109 
110 /* add opcode followed by 16-bit expression */
add_opcode_nn(int opcode,Expr * expr)111 void add_opcode_nn(int opcode, Expr *expr)
112 {
113 	add_opcode(opcode);
114 	Pass2infoExpr(RANGE_WORD, expr);
115 }
116 
117 /* add opcode followed by big-endian 16-bit expression */
add_opcode_NN(int opcode,struct Expr * expr)118 void add_opcode_NN(int opcode, struct Expr *expr)
119 {
120 	add_opcode(opcode);
121 	Pass2infoExpr(RANGE_WORD_BE, expr);
122 }
123 
124 /* add opcode followed by IX/IY offset expression */
add_opcode_idx(int opcode,Expr * expr)125 void add_opcode_idx(int opcode, Expr *expr)
126 {
127 	if (opcode & 0xFF0000)
128 	{				/* 3 bytes, insert idx offset as 2nd byte */
129 		add_opcode( (opcode >> 8) & 0xFFFF );
130 		Pass2infoExpr(RANGE_BYTE_SIGNED, expr);
131 		add_opcode( opcode & 0xFF );
132 	}
133 	else
134 	{
135 		add_opcode(opcode);
136 		Pass2infoExpr(RANGE_BYTE_SIGNED, expr);
137 	}
138 }
139 
140 /* add opcode followed by IX/IY offset expression and 8 bit expression */
add_opcode_idx_n(int opcode,struct Expr * idx_expr,struct Expr * n_expr)141 void add_opcode_idx_n(int opcode, struct Expr *idx_expr,
142 								  struct Expr *n_expr )
143 {
144 	add_opcode(opcode);
145 	Pass2infoExpr(RANGE_BYTE_SIGNED, idx_expr);
146 	Pass2infoExpr(RANGE_BYTE_UNSIGNED, n_expr);
147 }
148 
149 /* add opcode followed by two 8-bit expressions */
add_opcode_n_n(int opcode,struct Expr * n1_expr,struct Expr * n2_expr)150 void add_opcode_n_n(int opcode, struct Expr *n1_expr,
151 								struct Expr *n2_expr )
152 {
153 	add_opcode(opcode);
154 	Pass2infoExpr(RANGE_BYTE_UNSIGNED, n1_expr);
155 	Pass2infoExpr(RANGE_BYTE_UNSIGNED, n2_expr);
156 }
157 
add_call_emul_func(char * emul_func)158 void add_call_emul_func(char * emul_func)
159 {
160 	declare_extern_symbol(emul_func);
161 	Expr *emul_expr = parse_expr(emul_func);
162 	add_opcode_nn(0xCD, emul_expr);
163 }
164 
165 /* add Z88's opcodes */
add_Z88_CALL_OZ(int argument)166 void add_Z88_CALL_OZ(int argument)
167 {
168 	if (argument > 0 && argument <= 255)
169 	{
170 		append_byte(Z80_RST(0x20));
171 		append_byte(argument);
172 	}
173 	else if (argument > 255)
174 	{
175 		append_byte(Z80_RST(0x20));
176 		append_word(argument);
177 	}
178 	else
179 		error_int_range(argument);
180 }
181 
add_Z88_CALL_PKG(int argument)182 void add_Z88_CALL_PKG(int argument)
183 {
184 	if (argument >= 0)
185 	{
186 		append_byte(Z80_RST(0x08));
187 		append_word(argument);
188 	}
189 	else
190 		error_int_range(argument);
191 }
192 
add_Z88_FPP(int argument)193 void add_Z88_FPP(int argument)
194 {
195 	if (argument > 0 && argument < 255)
196 	{
197 		append_byte(Z80_RST(0x18));
198 		append_byte(argument);
199 	}
200 	else
201 		error_int_range(argument);
202 }
203 
add_Z88_INVOKE(int argument)204 void add_Z88_INVOKE(int argument)
205 {
206 	int opcode;
207 
208 	if (opts.ti83plus)
209 		opcode = Z80_RST(0x28);		/* Ti83Plus: RST 28H instruction */
210 	else
211 		opcode = Z80_CALL;			/* Ti83: CALL */
212 
213 	if (argument >= 0)
214 	{
215 		append_byte(opcode);
216 		append_word(argument);
217 	}
218 	else
219 		error_int_range(argument);
220 }
221 
222 // cu.wait VER, HOR   ->  16 - bit encoding 0x8000 + (HOR << 9) + VER
223 // (0<=VER<=311, 0<=HOR<=55)  BIG ENDIAN!
add_copper_unit_wait(Expr * ver,Expr * hor)224 void add_copper_unit_wait(Expr *ver, Expr *hor)
225 {
226 	if (opts.cpu != CPU_Z80N)
227 		error_illegal_ident();
228 	else {
229 		char expr_text[MAXLINE];
230 		snprintf(expr_text, sizeof(expr_text),
231 			"0x8000 + (((%s) & 0x3F) << 9) + ((%s) & 0x1FF)", Str_data(hor->text), Str_data(ver->text));
232 		Expr *expr = parse_expr(expr_text);
233 
234 		Pass2infoExpr(RANGE_WORD_BE, expr);
235 		OBJ_DELETE(ver);
236 		OBJ_DELETE(hor);
237 	}
238 }
239 
240 // cu.move REG, VAL  -> 16 - bit encoding(REG << 8) + VAL
241 // (0<= REG <= 127, 0 <= VAL <= 255)  BIG ENDIAN!
add_copper_unit_move(Expr * reg,Expr * val)242 void add_copper_unit_move(Expr *reg, Expr *val)
243 {
244 	if (opts.cpu != CPU_Z80N)
245 		error_illegal_ident();
246 	else {
247 		char expr_text[MAXLINE];
248 		snprintf(expr_text, sizeof(expr_text),
249 			"(((%s) & 0x7F) << 8) + ((%s) & 0xFF)", Str_data(reg->text), Str_data(val->text));
250 		Expr *expr = parse_expr(expr_text);
251 
252 		Pass2infoExpr(RANGE_WORD_BE, expr);
253 		OBJ_DELETE(reg);
254 		OBJ_DELETE(val);
255 	}
256 
257 }
258 
259 // cu.stop   -> 16 - bit encoding 0xffff (impossible cu.wait)
add_copper_unit_stop()260 void add_copper_unit_stop()
261 {
262 	if (opts.cpu != CPU_Z80N)
263 		error_illegal_ident();
264 	else
265 		append_word_be(0xFFFF);
266 }
267 
268 // cu.nop  -> 16 - bit encoding 0x0000 (do nothing cu.move)
add_copper_unit_nop()269 void add_copper_unit_nop()
270 {
271 	if (opts.cpu != CPU_Z80N)
272 		error_illegal_ident();
273 	else
274 		append_word_be(0x0000);
275 }
276