summaryrefslogtreecommitdiff
path: root/sim/testsuite/sim/or1k/or1k-asm-test.h
blob: 8726707493644752d91163ad7a30cef597bc9b29 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
/* Testsuite architecture macros for OpenRISC.

   Copyright (C) 2017-2018 Free Software Foundation, Inc.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

#ifndef OR1K_ASM_TEST_H
#define OR1K_ASM_TEST_H

#include "spr-defs.h"

/* Register definitions */

/* The "jump and link" instructions store the return address in R9.  */
#define LINK_REGISTER_R9 r9

/* These register definitions match the ABI.  */
#define ZERO_R0          r0
#define STACK_POINTER_R1 r1
#define FRAME_POINTER_R2 r2
#define RETURN_VALUE_R11 r11

	/* Load/move/clear helpers  */

	.macro LOAD_IMMEDIATE  reg, val
	l.movhi \reg,       hi ( \val )
	l.ori   \reg, \reg, lo ( \val )
	.endm

	.macro MOVE_REG  dest_reg, src_reg
	.ifnes "\dest_reg","\src_reg"
	l.ori \dest_reg, \src_reg, 0
	.endif
	.endm

	.macro CLEAR_REG reg
	l.movhi \reg, 0
	.endm

	.macro MOVE_FROM_SPR  reg, spr_reg
	l.mfspr \reg, ZERO_R0, \spr_reg
	.endm

	.macro MOVE_TO_SPR  spr_reg, reg
	l.mtspr ZERO_R0, \reg, \spr_reg
	.endm

	.macro SET_SPR_SR_FLAGS flag_mask, scratch_reg_1, scratch_reg_2
	/* We cannot use PUSH and POP here because some flags like Carry
	   would get overwritten.  */

	/* We could optimise this routine, as instruction l.mtspr already
	   does a logical OR.  */
	MOVE_FROM_SPR \scratch_reg_2, SPR_SR
	LOAD_IMMEDIATE \scratch_reg_1, \flag_mask
	l.or \scratch_reg_2, \scratch_reg_2, \scratch_reg_1
	MOVE_TO_SPR SPR_SR, \scratch_reg_2
	.endm

	.macro CLEAR_SPR_SR_FLAGS flag_mask, scratch_reg_1, scratch_reg_2
	/* We cannot use PUSH and POP here because some flags like Carry
	   would get overwritten.  */

	MOVE_FROM_SPR \scratch_reg_2, SPR_SR
	LOAD_IMMEDIATE \scratch_reg_1, ~\flag_mask
	l.and \scratch_reg_2, \scratch_reg_2, \scratch_reg_1
	MOVE_TO_SPR SPR_SR, \scratch_reg_2

	.endm

	/* Stack helpers  */

/* This value is defined in the OpenRISC 1000 specification.  */
#define EXCEPTION_STACK_SKIP_SIZE  128

	/* WARNING: Functions without prolog cannot use these PUSH or POP
	   macros.

	   PERFORMANCE WARNING: These PUSH/POP macros are convenient, but
	   can lead to slow code.  If you need to PUSH or POP several
	   registers, it's faster to use non-zero offsets when
	   loading/storing and then increment/decrement the stack pointer
	   just once.  */

	.macro PUSH reg
	l.addi STACK_POINTER_R1, STACK_POINTER_R1, -4
	l.sw   0(STACK_POINTER_R1), \reg
	.endm

	/* WARNING: see the warnings for PUSH.  */
	.macro POP reg
	l.lwz  \reg, 0(STACK_POINTER_R1)
	l.addi STACK_POINTER_R1, STACK_POINTER_R1, 4
	.endm

/* l.nop definitions for simulation control and console output.  */

/* Register definitions for the simulation l.nop codes.  */
#define NOP_REPORT_R3 r3
#define NOP_EXIT_R3   r3

/* SEC = Simulation Exit Code  */
#define SEC_SUCCESS            0
#define SEC_RETURNED_FROM_MAIN 1
#define SEC_GENERIC_ERROR      2

	/* When running under the simulator, this l.nop code terminates the
	   simulation.  */
	.macro EXIT_SIMULATION_WITH_IMMEDIATE_EXIT_CODE immediate_value
	LOAD_IMMEDIATE NOP_EXIT_R3, \immediate_value
	l.nop 1
	.endm

	.macro EXIT_SIMULATION_WITH_REG_EXIT_CODE reg
	MOVE_REG NOP_EXIT_R3, \reg
	l.nop 1
	.endm

	/* When running under the simulator, this l.nop code prints the
	   value of R3 to the console.  */
	.macro REPORT_TO_CONSOLE
	l.nop 2
	.endm

	/* NOTE: The stack must be set up, as this macro uses PUSH and POP.  */
	.macro REPORT_REG_TO_CONSOLE reg
	.ifeqs "\reg","r3"
	 /* Nothing more to do here, R3 is the register that gets printed.  */
	 REPORT_TO_CONSOLE
	.else
	 PUSH     NOP_REPORT_R3
	 MOVE_REG NOP_REPORT_R3, \reg
	 REPORT_TO_CONSOLE
	 POP      NOP_REPORT_R3
	.endif
	.endm

	/* NOTE: The stack must be set up, as this macro uses PUSH and POP.  */
	.macro REPORT_IMMEDIATE_TO_CONSOLE val
	PUSH     NOP_REPORT_R3
	LOAD_IMMEDIATE NOP_REPORT_R3, \val
	REPORT_TO_CONSOLE
	POP      NOP_REPORT_R3
	.endm

	.macro PRINT_NEWLINE_TO_CONSOLE
	PUSH  r3
	LOAD_IMMEDIATE r3, 0x0A
	l.nop 4
	POP   r3
	.endm

	/* If SR[F] is set, writes 0x00000001 to the console, otherwise it
	   writes 0x00000000.  */
	.macro REPORT_SRF_TO_CONSOLE
	OR1K_DELAYED_NOP (l.bnf \@1$)
	REPORT_IMMEDIATE_TO_CONSOLE 0x00000001
	OR1K_DELAYED_NOP (l.j \@2$)
\@1$:
	REPORT_IMMEDIATE_TO_CONSOLE 0x00000000
\@2$:
	.endm

	/* If the given register is 0, writes 0x00000000 to the console,
	   otherwise it writes 0x00000001.  */
	.macro REPORT_BOOL_TO_CONSOLE  reg
	l.sfne \reg, ZERO_R0
	REPORT_SRF_TO_CONSOLE
	.endm

	/* Writes to the console the value of the given register bit.  */
	.macro REPORT_BIT_TO_CONSOLE  reg, single_bit_mask
	PUSH r2
	PUSH r3
	PUSH r4
	MOVE_REG r2, \reg
	LOAD_IMMEDIATE r4, \single_bit_mask
	l.and   r3, r2, r4
	REPORT_BOOL_TO_CONSOLE r3
	POP r4
	POP r3
	POP r2
	.endm

	/* Jump helpers */

	.macro CALL overwritten_reg, subroutine_name
	LOAD_IMMEDIATE \overwritten_reg, \subroutine_name
	OR1K_DELAYED_NOP (l.jalr  \overwritten_reg)
	.endm

	.macro RETURN_TO_LINK_REGISTER_R9
	OR1K_DELAYED_NOP (l.jr LINK_REGISTER_R9)
	.endm

	/* Clear the BSS section on start-up */

	.macro CLEAR_BSS overwritten_reg1, overwritten_reg2
	LOAD_IMMEDIATE \overwritten_reg1, _bss_begin
	LOAD_IMMEDIATE \overwritten_reg2, _bss_end
	l.sfgeu \overwritten_reg1, \overwritten_reg2
	OR1K_DELAYED_NOP (l.bf    bss_is_empty)
bss_clear_loop:
	/* Possible optimisation to investigate:
	   move "l.sw 0(\overwritten_reg1), r0" to the jump delay slot as
	   "l.sw -4(\overwritten_reg1), r0" or similar. But keep in mind that
	   there are plans to remove the jump delay slot.  */
	l.sw    0(\overwritten_reg1), r0
	l.addi  \overwritten_reg1, \overwritten_reg1, 4
	l.sfgtu \overwritten_reg2, \overwritten_reg1
	OR1K_DELAYED_NOP (l.bf    bss_clear_loop)
bss_is_empty:
	.endm

#endif /* OR1K_ASM_TEST_H */