main gen_arm.c
  1/*
  2 Copyright 2014 Michael Pavone
  3 This file is part of BlastEm.
  4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
  5*/
  6#include "gen_arm.h"
  7#include "mem.h"
  8#include <stdio.h>
  9#include <stdlib.h>
 10
 11#define OP_FIELD_SHIFT 21u
 12
 13//Data processing format instructions
 14#define OP_AND 0x0u
 15#define OP_EOR (0x1u << OP_FIELD_SHIFT)
 16#define OP_SUB (0x2u << OP_FIELD_SHIFT)
 17#define OP_RSB (0x3u << OP_FIELD_SHIFT)
 18#define OP_ADD (0x4u << OP_FIELD_SHIFT)
 19#define OP_ADC (0x5u << OP_FIELD_SHIFT)
 20#define OP_SBC (0x6u << OP_FIELD_SHIFT)
 21#define OP_RSC (0x7u << OP_FIELD_SHIFT)
 22#define OP_TST (0x8u << OP_FIELD_SHIFT)
 23#define OP_TEQ (0x9u << OP_FIELD_SHIFT)
 24#define OP_CMP (0xAu << OP_FIELD_SHIFT)
 25#define OP_CMN (0xBu << OP_FIELD_SHIFT)
 26#define OP_ORR (0xCu << OP_FIELD_SHIFT)
 27#define OP_MOV (0xDu << OP_FIELD_SHIFT)
 28#define OP_BIC (0xEu << OP_FIELD_SHIFT)
 29#define OP_MVN (0xFu << OP_FIELD_SHIFT)
 30
 31//branch instructions
 32#define OP_B  0xA000000u
 33#define OP_BL 0xB000000u
 34#define OP_BX 0x12FFF10u
 35
 36//load/store
 37#define OP_STR   0x4000000u
 38#define OP_LDR   0x4100000u
 39#define OP_STM   0x8000000u
 40#define OP_LDM   0x8100000u
 41#define POST_IND 0u
 42#define PRE_IND  0x1000000u
 43#define DIR_DOWN 0u
 44#define DIR_UP   0x0800000u
 45#define SZ_W     0u
 46#define SZ_B     0x0400000u
 47#define WRITE_B  0x0200000u
 48#define OFF_IMM  0u
 49#define OFF_REG  0x2000000u
 50
 51#define PUSH     (OP_STR | PRE_IND | OFF_IMM | SZ_W | WRITE_B | DIR_DOWN | sizeof(uint32_t) | (sp << 16))
 52#define POP      (OP_LDR | POST_IND | OFF_IMM | SZ_W | DIR_UP | sizeof(uint32_t) | (sp << 16))
 53#define PUSHM     (OP_STM | PRE_IND | SZ_W | WRITE_B | DIR_DOWN | (sp << 16))
 54#define POPM      (OP_LDM | POST_IND | SZ_W | WRITE_B | DIR_UP | (sp << 16))
 55
 56#define IMMED    0x2000000u
 57#define REG      0u
 58
 59
 60uint32_t make_immed(uint32_t val)
 61{
 62	uint32_t rot_amount = 0;
 63	for (; rot_amount < 0x20; rot_amount += 2)
 64	{
 65		uint32_t test_mask = ~(0xFF << rot_amount | 0xFF >> (32-rot_amount));
 66		if (!(test_mask & val)) {
 67			return val << rot_amount | val >> (32-rot_amount) | rot_amount << 7;
 68		}
 69	}
 70	return INVALID_IMMED;
 71}
 72
 73void check_alloc_code(code_info *code)
 74{
 75	if (code->cur == code->last) {
 76		size_t size = CODE_ALLOC_SIZE;
 77		uint32_t *next_code = alloc_code(&size);
 78		if (!next_code) {
 79			fatal_error("Failed to allocate memory for generated code\n");
 80		}
 81		if (next_code = code->last + RESERVE_WORDS) {
 82			//new chunk is contiguous with the current one
 83			code->last = next_code + size/sizeof(code_word) - RESERVE_WORDS;
 84		} else {
 85			uint32_t * from = code->cur + 2;
 86			if (next_code - from < 0x400000 || from - next_code <= 0x400000) {
 87				*from = CC_AL | OP_B | ((next_code - from) & 0xFFFFFF);
 88			} else {
 89				//push r0 onto the stack
 90				*(from++) = CC_AL | PUSH;
 91				uint32_t immed = make_immed((uint32_t)next_code);
 92				if (immed == INVALID_IMMED) {
 93					//Load target into r0 from word after next instruction into register 0
 94					*(from++) = CC_AL | OP_LDR | OFF_IMM | DIR_DOWN | PRE_IND | SZ_W | (pc << 16) | 4;
 95					from[1] = (uint32_t)next_code;
 96				} else {
 97					//Load target into r0
 98					*(from++) = CC_AL | OP_MOV | IMMED | NO_COND | immed;
 99				}
100				//branch to address in r0
101				*from = CC_AL | OP_BX;
102				code->last = next_code + size/sizeof(code_word) - RESERVE_WORDS;
103				//pop r0
104				*(next_code++) = CC_AL | POP;
105				code->cur = next_code;
106			}
107		}
108	}
109}
110
111uint32_t data_proc(code_info *code, uint32_t cond, uint32_t op, uint32_t set_cond, uint32_t dst, uint32_t src1, uint32_t src2)
112{
113	check_alloc_code(code);
114	*(code->cur++) = cond | op | set_cond | (src1 << 16) | (dst << 12) | src2;
115
116	return CODE_OK;
117}
118
119uint32_t data_proci(code_info *code, uint32_t cond, uint32_t op, uint32_t set_cond, uint32_t dst, uint32_t src1, uint32_t immed)
120{
121	immed = make_immed(immed);
122	if (immed == INVALID_IMMED) {
123		return immed;
124	}
125	return data_proc(code, cond, op | IMMED, set_cond, dst, src1, immed);
126}
127
128//TODO: support shifted register for op2
129
130uint32_t and(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
131{
132	return data_proc(code, CC_AL, OP_AND, set_cond, dst, src1, src2);
133}
134
135uint32_t andi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
136{
137	return data_proci(code, CC_AL, OP_AND, set_cond, dst, src1, immed);
138}
139
140uint32_t and_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
141{
142	return data_proc(code, cc, OP_AND, set_cond, dst, src1, src2);
143}
144
145uint32_t andi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
146{
147	return data_proci(code, cc, OP_AND, set_cond, dst, src1, immed);
148}
149
150uint32_t eor(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
151{
152	return data_proc(code, CC_AL, OP_EOR, set_cond, dst, src1, src2);
153}
154
155uint32_t eori(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
156{
157	return data_proci(code, CC_AL, OP_EOR, set_cond, dst, src1, immed);
158}
159
160uint32_t eor_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
161{
162	return data_proc(code, cc, OP_EOR, set_cond, dst, src1, src2);
163}
164
165uint32_t eori_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
166{
167	return data_proci(code, cc, OP_EOR, set_cond, dst, src1, immed);
168}
169
170uint32_t sub(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
171{
172	return data_proc(code, CC_AL, OP_SUB, set_cond, dst, src1, src2);
173}
174
175uint32_t subi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
176{
177	return data_proci(code, CC_AL, OP_SUB, set_cond, dst, src1, immed);
178}
179
180uint32_t sub_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
181{
182	return data_proc(code, cc, OP_SUB, set_cond, dst, src1, src2);
183}
184
185uint32_t subi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
186{
187	return data_proci(code, cc, OP_SUB, set_cond, dst, src1, immed);
188}
189
190uint32_t rsb(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
191{
192	return data_proc(code, CC_AL, OP_RSB, set_cond, dst, src1, src2);
193}
194
195uint32_t rsbi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
196{
197	return data_proci(code, CC_AL, OP_RSB, set_cond, dst, src1, immed);
198}
199
200uint32_t rsb_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
201{
202	return data_proc(code, cc, OP_RSB, set_cond, dst, src1, src2);
203}
204
205uint32_t rsbi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
206{
207	return data_proci(code, cc, OP_RSB, set_cond, dst, src1, immed);
208}
209
210uint32_t add(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
211{
212	return data_proc(code, CC_AL, OP_ADD, set_cond, dst, src1, src2);
213}
214
215uint32_t addi(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
216{
217	return data_proci(code, CC_AL, OP_ADD, set_cond, dst, src1, immed);
218}
219
220uint32_t add_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
221{
222	return data_proc(code, cc, OP_ADD, set_cond, dst, src1, src2);
223}
224
225uint32_t addi_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
226{
227	return data_proci(code, cc, OP_ADD, set_cond, dst, src1, immed);
228}
229
230uint32_t adc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
231{
232	return data_proc(code, CC_AL, OP_ADC, set_cond, dst, src1, src2);
233}
234
235uint32_t adci(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
236{
237	return data_proci(code, CC_AL, OP_ADC, set_cond, dst, src1, immed);
238}
239
240uint32_t adc_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
241{
242	return data_proc(code, cc, OP_ADC, set_cond, dst, src1, src2);
243}
244
245uint32_t adci_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
246{
247	return data_proci(code, cc, OP_ADC, set_cond, dst, src1, immed);
248}
249
250uint32_t sbc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
251{
252	return data_proc(code, CC_AL, OP_SBC, set_cond, dst, src1, src2);
253}
254
255uint32_t sbci(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
256{
257	return data_proci(code, CC_AL, OP_SBC, set_cond, dst, src1, immed);
258}
259
260uint32_t sbc_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
261{
262	return data_proc(code, cc, OP_SBC, set_cond, dst, src1, src2);
263}
264
265uint32_t sbci_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
266{
267	return data_proci(code, cc, OP_SBC, set_cond, dst, src1, immed);
268}
269
270uint32_t rsc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
271{
272	return data_proc(code, CC_AL, OP_RSC, set_cond, dst, src1, src2);
273}
274
275uint32_t rsci(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
276{
277	return data_proci(code, CC_AL, OP_RSC, set_cond, dst, src1, immed);
278}
279
280uint32_t rsc_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
281{
282	return data_proc(code, cc, OP_RSC, set_cond, dst, src1, src2);
283}
284
285uint32_t rsci_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
286{
287	return data_proci(code, cc, OP_RSC, set_cond, dst, src1, immed);
288}
289
290uint32_t tst(code_info *code, uint32_t src1, uint32_t src2)
291{
292	return data_proc(code, CC_AL, OP_TST, SET_COND, r0, src1, src2);
293}
294
295uint32_t tsti(code_info *code, uint32_t src1, uint32_t immed)
296{
297	return data_proci(code, CC_AL, OP_TST, SET_COND, r0, src1, immed);
298}
299
300uint32_t tst_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc)
301{
302	return data_proc(code, cc, OP_TST, SET_COND, r0, src1, src2);
303}
304
305uint32_t tsti_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc)
306{
307	return data_proci(code, cc, OP_TST, SET_COND, r0, src1, immed);
308}
309
310uint32_t teq(code_info *code, uint32_t src1, uint32_t src2)
311{
312	return data_proc(code, CC_AL, OP_TEQ, SET_COND, r0, src1, src2);
313}
314
315uint32_t teqi(code_info *code, uint32_t src1, uint32_t immed)
316{
317	return data_proci(code, CC_AL, OP_TEQ, SET_COND, r0, src1, immed);
318}
319
320uint32_t teq_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc)
321{
322	return data_proc(code, cc, OP_TEQ, SET_COND, r0, src1, src2);
323}
324
325uint32_t teqi_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc)
326{
327	return data_proci(code, cc, OP_TEQ, SET_COND, r0, src1, immed);
328}
329
330uint32_t cmp(code_info *code, uint32_t src1, uint32_t src2)
331{
332	return data_proc(code, CC_AL, OP_CMP, SET_COND, r0, src1, src2);
333}
334
335uint32_t cmpi(code_info *code, uint32_t src1, uint32_t immed)
336{
337	return data_proci(code, CC_AL, OP_CMP, SET_COND, r0, src1, immed);
338}
339
340uint32_t cmp_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc)
341{
342	return data_proc(code, cc, OP_CMP, SET_COND, r0, src1, src2);
343}
344
345uint32_t cmpi_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc)
346{
347	return data_proci(code, cc, OP_CMP, SET_COND, r0, src1, immed);
348}
349
350uint32_t cmn(code_info *code, uint32_t src1, uint32_t src2)
351{
352	return data_proc(code, CC_AL, OP_CMN, SET_COND, r0, src1, src2);
353}
354
355uint32_t cmni(code_info *code, uint32_t src1, uint32_t immed)
356{
357	return data_proci(code, CC_AL, OP_CMN, SET_COND, r0, src1, immed);
358}
359
360uint32_t cmn_cc(code_info *code, uint32_t src1, uint32_t src2, uint32_t cc)
361{
362	return data_proc(code, cc, OP_CMN, SET_COND, r0, src1, src2);
363}
364
365uint32_t cmni_cc(code_info *code, uint32_t src1, uint32_t immed, uint32_t cc)
366{
367	return data_proci(code, cc, OP_CMN, SET_COND, r0, src1, immed);
368}
369
370uint32_t orr(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
371{
372	return data_proc(code, CC_AL, OP_ORR, set_cond, dst, src1, src2);
373}
374
375uint32_t orri(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
376{
377	return data_proci(code, CC_AL, OP_ORR, set_cond, dst, src1, immed);
378}
379
380uint32_t orr_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
381{
382	return data_proc(code, cc, OP_ORR, set_cond, dst, src1, src2);
383}
384
385uint32_t orri_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
386{
387	return data_proci(code, cc, OP_ORR, set_cond, dst, src1, immed);
388}
389
390uint32_t mov(code_info *code, uint32_t dst, uint32_t src2, uint32_t set_cond)
391{
392	return data_proc(code, CC_AL, OP_MOV, set_cond, dst, 0, src2);
393}
394
395uint32_t movi(code_info *code, uint32_t dst, uint32_t immed, uint32_t set_cond)
396{
397	return data_proci(code, CC_AL, OP_MOV, set_cond, dst, 0, immed);
398}
399
400uint32_t mov_cc(code_info *code, uint32_t dst, uint32_t src2, uint32_t cc, uint32_t set_cond)
401{
402	return data_proc(code, cc, OP_MOV, set_cond, dst, 0, src2);
403}
404
405uint32_t movi_cc(code_info *code, uint32_t dst, uint32_t immed, uint32_t cc, uint32_t set_cond)
406{
407	return data_proci(code, cc, OP_MOV, set_cond, dst, 0, immed);
408}
409
410uint32_t bic(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t set_cond)
411{
412	return data_proc(code, CC_AL, OP_BIC, set_cond, dst, src1, src2);
413}
414
415uint32_t bici(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t set_cond)
416{
417	return data_proci(code, CC_AL, OP_BIC, set_cond, dst, src1, immed);
418}
419
420uint32_t bic_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t src2, uint32_t cc, uint32_t set_cond)
421{
422	return data_proc(code, cc, OP_BIC, set_cond, dst, src1, src2);
423}
424
425uint32_t bici_cc(code_info *code, uint32_t dst, uint32_t src1, uint32_t immed, uint32_t cc, uint32_t set_cond)
426{
427	return data_proci(code, cc, OP_BIC, set_cond, dst, src1, immed);
428}
429
430uint32_t mvn(code_info *code, uint32_t dst, uint32_t src2, uint32_t set_cond)
431{
432	return data_proc(code, CC_AL, OP_MVN, set_cond, dst, 0, src2);
433}
434
435uint32_t mvni(code_info *code, uint32_t dst, uint32_t immed, uint32_t set_cond)
436{
437	return data_proci(code, CC_AL, OP_MVN, set_cond, dst, 0, immed);
438}
439
440uint32_t mvn_cc(code_info *code, uint32_t dst, uint32_t src2, uint32_t cc, uint32_t set_cond)
441{
442	return data_proc(code, cc, OP_MVN, set_cond, dst, 0, src2);
443}
444
445uint32_t mvni_cc(code_info *code, uint32_t dst, uint32_t immed, uint32_t cc, uint32_t set_cond)
446{
447	return data_proci(code, cc, OP_MVN, set_cond, dst, 0, immed);
448}
449
450uint32_t branchi(code_info *code, uint32_t cc, uint32_t op, uint32_t *dst)
451{
452	uint32_t * from = code->cur + 2;
453	if (dst - from >= 0x400000 && from - dst > 0x400000) {
454		return INVALID_IMMED;
455	}
456	check_alloc_code(code);
457	*(code->cur++) = cc | op | ((dst - from) & 0xFFFFFF);
458	return CODE_OK;
459}
460
461uint32_t b(code_info *code, uint32_t *dst)
462{
463	return branchi(code, CC_AL, OP_B, dst);
464}
465
466uint32_t b_cc(code_info *code, uint32_t *dst, uint32_t cc)
467{
468	return branchi(code, cc, OP_B, dst);
469}
470
471uint32_t bl(code_info *code, uint32_t *dst)
472{
473	return branchi(code, CC_AL, OP_BL, dst);
474}
475
476uint32_t bl_cc(code_info *code, uint32_t *dst, uint32_t cc)
477{
478	return branchi(code, cc, OP_BL, dst);
479}
480
481uint32_t bx(code_info *code, uint32_t dst)
482{
483	check_alloc_code(code);
484	*(code->cur++) = CC_AL | OP_BX | dst;
485	return CODE_OK;
486}
487
488uint32_t bx_cc(code_info *code, uint32_t dst, uint32_t cc)
489{
490	check_alloc_code(code);
491	*(code->cur++) = cc | OP_BX | dst;
492	return CODE_OK;
493}
494
495uint32_t push(code_info *code, uint32_t reg)
496{
497	check_alloc_code(code);
498	*(code->cur++) = CC_AL | PUSH | reg << 12;
499	return CODE_OK;
500}
501
502uint32_t push_cc(code_info *code, uint32_t reg, uint32_t cc)
503{
504	check_alloc_code(code);
505	*(code->cur++) = cc | PUSH | reg << 12;
506	return CODE_OK;
507}
508
509uint32_t pushm(code_info *code, uint32_t reglist)
510{
511	check_alloc_code(code);
512	*(code->cur++) = CC_AL | PUSHM | reglist;
513	return CODE_OK;
514}
515
516uint32_t pushm_cc(code_info *code, uint32_t reglist, uint32_t cc)
517{
518	check_alloc_code(code);
519	*(code->cur++) = cc | PUSHM | reglist;
520	return CODE_OK;
521}
522
523uint32_t pop(code_info *code, uint32_t reg)
524{
525	check_alloc_code(code);
526	*(code->cur++) = CC_AL | POP | reg << 12;
527	return CODE_OK;
528}
529
530uint32_t pop_cc(code_info *code, uint32_t reg, uint32_t cc)
531{
532	check_alloc_code(code);
533	*(code->cur++) = cc | POP | reg << 12;
534	return CODE_OK;
535}
536
537uint32_t popm(code_info *code, uint32_t reglist)
538{
539	check_alloc_code(code);
540	*(code->cur++) = CC_AL | POPM | reglist;
541	return CODE_OK;
542}
543
544uint32_t popm_cc(code_info *code, uint32_t reglist, uint32_t cc)
545{
546	check_alloc_code(code);
547	*(code->cur++) = cc | POPM | reglist;
548	return CODE_OK;
549}
550
551uint32_t load_store_immoff(code_info *code, uint32_t op, uint32_t dst, uint32_t base, int32_t offset, uint32_t cc)
552{
553	if (offset >= 0x1000 || offset <= -0x1000) {
554		return INVALID_IMMED;
555	}
556	check_alloc_code(code);
557	uint32_t instruction = cc | op | POST_IND | OFF_IMM | SZ_W | base << 16 | dst << 12;
558	if (offset >= 0) {
559		instruction |= offset | DIR_UP;
560	} else {
561		instruction |= (-offset) | DIR_DOWN;
562	}
563	*(code->cur++) = instruction;
564	return CODE_OK;
565}
566
567uint32_t ldr_cc(code_info *code, uint32_t dst, uint32_t base, int32_t offset, uint32_t cc)
568{
569	return load_store_immoff(code, OP_LDR, dst, base, offset, cc);
570}
571
572uint32_t ldr(code_info *code, uint32_t dst, uint32_t base, int32_t offset)
573{
574	return ldr_cc(code, dst, base, offset, CC_AL);
575}
576
577uint32_t str_cc(code_info *code, uint32_t src, uint32_t base, int32_t offset, uint32_t cc)
578{
579	return load_store_immoff(code, OP_STR, src, base, offset, cc);
580}
581
582uint32_t str(code_info *code, uint32_t src, uint32_t base, int32_t offset)
583{
584	return str_cc(code, src, base, offset, CC_AL);
585}