]>
Commit | Line | Data |
---|---|---|
702d582e PG |
1 | /* Testsuite architecture macros for OpenRISC. |
2 | ||
1d506c26 | 3 | Copyright (C) 2017-2024 Free Software Foundation, Inc. |
702d582e PG |
4 | |
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 3 of the License, or | |
8 | (at your option) any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
17 | ||
18 | #ifndef OR1K_ASM_TEST_H | |
19 | #define OR1K_ASM_TEST_H | |
20 | ||
21 | #include "spr-defs.h" | |
22 | ||
23 | /* Register definitions */ | |
24 | ||
25 | /* The "jump and link" instructions store the return address in R9. */ | |
26 | #define LINK_REGISTER_R9 r9 | |
27 | ||
28 | /* These register definitions match the ABI. */ | |
29 | #define ZERO_R0 r0 | |
30 | #define STACK_POINTER_R1 r1 | |
31 | #define FRAME_POINTER_R2 r2 | |
32 | #define RETURN_VALUE_R11 r11 | |
33 | ||
34 | /* Load/move/clear helpers */ | |
35 | ||
36 | .macro LOAD_IMMEDIATE reg, val | |
37 | l.movhi \reg, hi ( \val ) | |
38 | l.ori \reg, \reg, lo ( \val ) | |
39 | .endm | |
40 | ||
41 | .macro MOVE_REG dest_reg, src_reg | |
42 | .ifnes "\dest_reg","\src_reg" | |
43 | l.ori \dest_reg, \src_reg, 0 | |
44 | .endif | |
45 | .endm | |
46 | ||
47 | .macro CLEAR_REG reg | |
48 | l.movhi \reg, 0 | |
49 | .endm | |
50 | ||
51 | .macro MOVE_FROM_SPR reg, spr_reg | |
52 | l.mfspr \reg, ZERO_R0, \spr_reg | |
53 | .endm | |
54 | ||
55 | .macro MOVE_TO_SPR spr_reg, reg | |
56 | l.mtspr ZERO_R0, \reg, \spr_reg | |
57 | .endm | |
58 | ||
59 | .macro SET_SPR_SR_FLAGS flag_mask, scratch_reg_1, scratch_reg_2 | |
60 | /* We cannot use PUSH and POP here because some flags like Carry | |
61 | would get overwritten. */ | |
62 | ||
63 | /* We could optimise this routine, as instruction l.mtspr already | |
64 | does a logical OR. */ | |
65 | MOVE_FROM_SPR \scratch_reg_2, SPR_SR | |
66 | LOAD_IMMEDIATE \scratch_reg_1, \flag_mask | |
67 | l.or \scratch_reg_2, \scratch_reg_2, \scratch_reg_1 | |
68 | MOVE_TO_SPR SPR_SR, \scratch_reg_2 | |
69 | .endm | |
70 | ||
71 | .macro CLEAR_SPR_SR_FLAGS flag_mask, scratch_reg_1, scratch_reg_2 | |
72 | /* We cannot use PUSH and POP here because some flags like Carry | |
73 | would get overwritten. */ | |
74 | ||
75 | MOVE_FROM_SPR \scratch_reg_2, SPR_SR | |
76 | LOAD_IMMEDIATE \scratch_reg_1, ~\flag_mask | |
77 | l.and \scratch_reg_2, \scratch_reg_2, \scratch_reg_1 | |
78 | MOVE_TO_SPR SPR_SR, \scratch_reg_2 | |
79 | ||
80 | .endm | |
81 | ||
82 | /* Stack helpers */ | |
83 | ||
84 | /* This value is defined in the OpenRISC 1000 specification. */ | |
85 | #define EXCEPTION_STACK_SKIP_SIZE 128 | |
86 | ||
87 | /* WARNING: Functions without prolog cannot use these PUSH or POP | |
88 | macros. | |
89 | ||
90 | PERFORMANCE WARNING: These PUSH/POP macros are convenient, but | |
91 | can lead to slow code. If you need to PUSH or POP several | |
92 | registers, it's faster to use non-zero offsets when | |
93 | loading/storing and then increment/decrement the stack pointer | |
94 | just once. */ | |
95 | ||
96 | .macro PUSH reg | |
97 | l.addi STACK_POINTER_R1, STACK_POINTER_R1, -4 | |
98 | l.sw 0(STACK_POINTER_R1), \reg | |
99 | .endm | |
100 | ||
101 | /* WARNING: see the warnings for PUSH. */ | |
102 | .macro POP reg | |
103 | l.lwz \reg, 0(STACK_POINTER_R1) | |
104 | l.addi STACK_POINTER_R1, STACK_POINTER_R1, 4 | |
105 | .endm | |
106 | ||
107 | /* l.nop definitions for simulation control and console output. */ | |
108 | ||
109 | /* Register definitions for the simulation l.nop codes. */ | |
110 | #define NOP_REPORT_R3 r3 | |
111 | #define NOP_EXIT_R3 r3 | |
112 | ||
113 | /* SEC = Simulation Exit Code */ | |
114 | #define SEC_SUCCESS 0 | |
115 | #define SEC_RETURNED_FROM_MAIN 1 | |
116 | #define SEC_GENERIC_ERROR 2 | |
117 | ||
118 | /* When running under the simulator, this l.nop code terminates the | |
119 | simulation. */ | |
120 | .macro EXIT_SIMULATION_WITH_IMMEDIATE_EXIT_CODE immediate_value | |
121 | LOAD_IMMEDIATE NOP_EXIT_R3, \immediate_value | |
122 | l.nop 1 | |
123 | .endm | |
124 | ||
125 | .macro EXIT_SIMULATION_WITH_REG_EXIT_CODE reg | |
126 | MOVE_REG NOP_EXIT_R3, \reg | |
127 | l.nop 1 | |
128 | .endm | |
129 | ||
130 | /* When running under the simulator, this l.nop code prints the | |
131 | value of R3 to the console. */ | |
132 | .macro REPORT_TO_CONSOLE | |
133 | l.nop 2 | |
134 | .endm | |
135 | ||
136 | /* NOTE: The stack must be set up, as this macro uses PUSH and POP. */ | |
137 | .macro REPORT_REG_TO_CONSOLE reg | |
138 | .ifeqs "\reg","r3" | |
139 | /* Nothing more to do here, R3 is the register that gets printed. */ | |
140 | REPORT_TO_CONSOLE | |
141 | .else | |
142 | PUSH NOP_REPORT_R3 | |
143 | MOVE_REG NOP_REPORT_R3, \reg | |
144 | REPORT_TO_CONSOLE | |
145 | POP NOP_REPORT_R3 | |
146 | .endif | |
147 | .endm | |
148 | ||
149 | /* NOTE: The stack must be set up, as this macro uses PUSH and POP. */ | |
150 | .macro REPORT_IMMEDIATE_TO_CONSOLE val | |
151 | PUSH NOP_REPORT_R3 | |
152 | LOAD_IMMEDIATE NOP_REPORT_R3, \val | |
153 | REPORT_TO_CONSOLE | |
154 | POP NOP_REPORT_R3 | |
155 | .endm | |
156 | ||
157 | .macro PRINT_NEWLINE_TO_CONSOLE | |
158 | PUSH r3 | |
159 | LOAD_IMMEDIATE r3, 0x0A | |
160 | l.nop 4 | |
161 | POP r3 | |
162 | .endm | |
163 | ||
164 | /* If SR[F] is set, writes 0x00000001 to the console, otherwise it | |
165 | writes 0x00000000. */ | |
166 | .macro REPORT_SRF_TO_CONSOLE | |
167 | OR1K_DELAYED_NOP (l.bnf \@1$) | |
168 | REPORT_IMMEDIATE_TO_CONSOLE 0x00000001 | |
169 | OR1K_DELAYED_NOP (l.j \@2$) | |
170 | \@1$: | |
171 | REPORT_IMMEDIATE_TO_CONSOLE 0x00000000 | |
172 | \@2$: | |
173 | .endm | |
174 | ||
175 | /* If the given register is 0, writes 0x00000000 to the console, | |
176 | otherwise it writes 0x00000001. */ | |
177 | .macro REPORT_BOOL_TO_CONSOLE reg | |
178 | l.sfne \reg, ZERO_R0 | |
179 | REPORT_SRF_TO_CONSOLE | |
180 | .endm | |
181 | ||
182 | /* Writes to the console the value of the given register bit. */ | |
183 | .macro REPORT_BIT_TO_CONSOLE reg, single_bit_mask | |
184 | PUSH r2 | |
185 | PUSH r3 | |
186 | PUSH r4 | |
187 | MOVE_REG r2, \reg | |
188 | LOAD_IMMEDIATE r4, \single_bit_mask | |
189 | l.and r3, r2, r4 | |
190 | REPORT_BOOL_TO_CONSOLE r3 | |
191 | POP r4 | |
192 | POP r3 | |
193 | POP r2 | |
194 | .endm | |
195 | ||
196 | /* Jump helpers */ | |
197 | ||
198 | .macro CALL overwritten_reg, subroutine_name | |
199 | LOAD_IMMEDIATE \overwritten_reg, \subroutine_name | |
200 | OR1K_DELAYED_NOP (l.jalr \overwritten_reg) | |
201 | .endm | |
202 | ||
203 | .macro RETURN_TO_LINK_REGISTER_R9 | |
204 | OR1K_DELAYED_NOP (l.jr LINK_REGISTER_R9) | |
205 | .endm | |
206 | ||
207 | /* Clear the BSS section on start-up */ | |
208 | ||
209 | .macro CLEAR_BSS overwritten_reg1, overwritten_reg2 | |
210 | LOAD_IMMEDIATE \overwritten_reg1, _bss_begin | |
211 | LOAD_IMMEDIATE \overwritten_reg2, _bss_end | |
212 | l.sfgeu \overwritten_reg1, \overwritten_reg2 | |
213 | OR1K_DELAYED_NOP (l.bf bss_is_empty) | |
214 | bss_clear_loop: | |
215 | /* Possible optimisation to investigate: | |
216 | move "l.sw 0(\overwritten_reg1), r0" to the jump delay slot as | |
217 | "l.sw -4(\overwritten_reg1), r0" or similar. But keep in mind that | |
218 | there are plans to remove the jump delay slot. */ | |
219 | l.sw 0(\overwritten_reg1), r0 | |
220 | l.addi \overwritten_reg1, \overwritten_reg1, 4 | |
221 | l.sfgtu \overwritten_reg2, \overwritten_reg1 | |
222 | OR1K_DELAYED_NOP (l.bf bss_clear_loop) | |
223 | bss_is_empty: | |
224 | .endm | |
225 | ||
226 | #endif /* OR1K_ASM_TEST_H */ |