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-2024 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 */
|