blob: 35256731c30ebd3dac4074aeab5febe149ec6c17 [file] [log] [blame]
/* Testsuite architecture macros for OpenRISC.
Copyright (C) 2017-2021 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 */