/*
|
/*
|
OR1200 overflow bit checking
|
OR1200 overflow bit checking
|
|
|
Very basic, testing
|
Very basic, testing
|
|
|
TODO: Check range exception handling in delay slots
|
TODO: Check range exception handling in delay slots
|
|
|
Julius Baxter, ORSoC AB, julius.baxter@orsoc.se
|
Julius Baxter, ORSoC AB, julius.baxter@orsoc.se
|
|
|
*/
|
*/
|
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
//// ////
|
//// ////
|
//// Copyright (C) 2011 Authors and OPENCORES.ORG ////
|
//// Copyright (C) 2011 Authors and OPENCORES.ORG ////
|
//// ////
|
//// ////
|
//// This source file may be used and distributed without ////
|
//// This source file may be used and distributed without ////
|
//// restriction provided that this copyright statement is not ////
|
//// restriction provided that this copyright statement is not ////
|
//// removed from the file and that any derivative work contains ////
|
//// removed from the file and that any derivative work contains ////
|
//// the original copyright notice and the associated disclaimer. ////
|
//// the original copyright notice and the associated disclaimer. ////
|
//// ////
|
//// ////
|
//// This source file is free software; you can redistribute it ////
|
//// This source file is free software; you can redistribute it ////
|
//// and/or modify it under the terms of the GNU Lesser General ////
|
//// and/or modify it under the terms of the GNU Lesser General ////
|
//// Public License as published by the Free Software Foundation; ////
|
//// Public License as published by the Free Software Foundation; ////
|
//// either version 2.1 of the License, or (at your option) any ////
|
//// either version 2.1 of the License, or (at your option) any ////
|
//// later version. ////
|
//// later version. ////
|
//// ////
|
//// ////
|
//// This source is distributed in the hope that it will be ////
|
//// This source is distributed in the hope that it will be ////
|
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
|
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
|
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
|
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
|
//// PURPOSE. See the GNU Lesser General Public License for more ////
|
//// PURPOSE. See the GNU Lesser General Public License for more ////
|
//// details. ////
|
//// details. ////
|
//// ////
|
//// ////
|
//// You should have received a copy of the GNU Lesser General ////
|
//// You should have received a copy of the GNU Lesser General ////
|
//// Public License along with this source; if not, download it ////
|
//// Public License along with this source; if not, download it ////
|
//// from http://www.opencores.org/lgpl.shtml ////
|
//// from http://www.opencores.org/lgpl.shtml ////
|
//// ////
|
//// ////
|
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
#include "spr-defs.h"
|
#include "spr-defs.h"
|
#include "board.h"
|
#include "board.h"
|
#include "or1200-defines.h"
|
#include "or1200-defines.h"
|
|
|
|
|
/* =================================================== [ exceptions ] === */
|
/* =================================================== [ exceptions ] === */
|
.section .vectors, "ax"
|
.section .vectors, "ax"
|
|
|
|
|
/* ---[ 0x100: RESET exception ]----------------------------------------- */
|
/* ---[ 0x100: RESET exception ]----------------------------------------- */
|
.org 0x100
|
.org 0x100
|
l.movhi r0, 0
|
l.movhi r0, 0
|
/* Clear status register */
|
/* Clear status register */
|
l.ori r1, r0, SPR_SR_SM
|
l.ori r1, r0, SPR_SR_SM
|
l.mtspr r0, r1, SPR_SR
|
l.mtspr r0, r1, SPR_SR
|
/* Clear timer */
|
/* Clear timer */
|
l.mtspr r0, r0, SPR_TTMR
|
l.mtspr r0, r0, SPR_TTMR
|
|
|
/* Jump to program initialisation code */
|
/* Jump to program initialisation code */
|
.global _start
|
.global _start
|
l.movhi r4, hi(_start)
|
l.movhi r4, hi(_start)
|
l.ori r4, r4, lo(_start)
|
l.ori r4, r4, lo(_start)
|
l.jr r4
|
l.jr r4
|
l.nop
|
l.nop
|
|
|
.org 0x600
|
.org 0x600
|
l.nop 0x1
|
l.nop 0x1
|
|
|
|
|
/* ---[ 0x700: Illegal instruction exception ]-------------------------- */
|
/* ---[ 0x700: Illegal instruction exception ]-------------------------- */
|
.org 0x700
|
.org 0x700
|
#ifndef OR1200_IMPL_ADDC
|
#ifndef OR1200_IMPL_ADDC
|
// No problem - instruction not supported
|
// No problem - instruction not supported
|
l.movhi r3, hi(0x8000000d)
|
l.movhi r3, hi(0x8000000d)
|
l.ori r3, r3, lo(0x8000000d)
|
l.ori r3, r3, lo(0x8000000d)
|
l.nop 0x2
|
l.nop 0x2
|
l.ori r3, r0, 0
|
l.ori r3, r0, 0
|
#else
|
#else
|
l.ori r3, r0, 1
|
l.ori r3, r0, 1
|
#endif
|
#endif
|
l.nop 0x1
|
l.nop 0x1
|
|
|
#define INCREMENT_EXCEPTION_COUNTER l.addi r11, r11, 0x1
|
#define INCREMENT_EXCEPTION_COUNTER l.addi r11, r11, 0x1
|
#define CHECK_EXCEPTION_COUNTER \
|
#define CHECK_EXCEPTION_COUNTER \
|
l.sfne r11, r12 ; \
|
l.sfne r11, r12 ; \
|
l.bf _fail ; \
|
l.bf _fail ; \
|
l.nop ;
|
l.nop ;
|
#define EXPECT_RANGE_EXCEPT \
|
#define EXPECT_RANGE_EXCEPT \
|
l.addi r12, r12, 1 ; \
|
l.addi r12, r12, 1 ; \
|
CHECK_EXCEPTION_COUNTER
|
CHECK_EXCEPTION_COUNTER
|
|
|
/* ---[ 0xb00: Range exception ]---------------------------------------- */
|
/* ---[ 0xb00: Range exception ]---------------------------------------- */
|
.org 0xb00
|
.org 0xb00
|
l.sw 0(r0), r3 ;// Save r3 - don't disrupt it during exceptions
|
l.sw 0(r0), r3 ;// Save r3 - don't disrupt it during exceptions
|
l.ori r3, r0, 0xaaee
|
l.ori r3, r0, 0xaaee
|
l.nop 0x2
|
l.nop 0x2
|
// TODO - get instruction and decode to ensure it was an instruction
|
// TODO - get instruction and decode to ensure it was an instruction
|
// which is capable of causing a range exception. Remember delay slot!
|
// which is capable of causing a range exception. Remember delay slot!
|
INCREMENT_EXCEPTION_COUNTER
|
INCREMENT_EXCEPTION_COUNTER
|
|
|
// Clear OV in ESR
|
// Clear OV in ESR
|
l.mfspr r3,r0,SPR_ESR_BASE ;// Get ESR
|
l.mfspr r3,r0,SPR_ESR_BASE ;// Get ESR
|
l.nop 2
|
l.nop 2
|
l.xori r3, r3,SPR_SR_OV ;// Clear OV bit
|
l.xori r3, r3,SPR_SR_OV ;// Clear OV bit
|
l.mtspr r0,r3,SPR_ESR_BASE ;// Get EPC
|
l.mtspr r0,r3,SPR_ESR_BASE ;// Get EPC
|
|
|
l.mfspr r3,r0,SPR_EPCR_BASE ;// Get EPC
|
l.mfspr r3,r0,SPR_EPCR_BASE ;// Get EPC
|
l.nop 2
|
l.nop 2
|
l.addi r3, r3, 0x4 ;// Increment
|
l.addi r3, r3, 0x4 ;// Increment
|
l.mtspr r0,r3,SPR_EPCR_BASE ;// Get EPC
|
l.mtspr r0,r3,SPR_EPCR_BASE ;// Get EPC
|
// For now, increment EPCR so we step over instruction and continue
|
// For now, increment EPCR so we step over instruction and continue
|
|
|
l.lwz r3, 0(r0)
|
l.lwz r3, 0(r0)
|
l.rfe
|
l.rfe
|
|
|
/* =================================================== [ text ] === */
|
/* =================================================== [ text ] === */
|
.section .text
|
.section .text
|
|
|
/* =================================================== [ start ] === */
|
/* =================================================== [ start ] === */
|
|
|
.global _start
|
.global _start
|
_start:
|
_start:
|
// Clear all regs
|
// Clear all regs
|
l.movhi r1, 0
|
l.movhi r1, 0
|
l.movhi r2, 0
|
l.movhi r2, 0
|
l.movhi r3, 0
|
l.movhi r3, 0
|
l.movhi r4, 0
|
l.movhi r4, 0
|
l.movhi r5, 0
|
l.movhi r5, 0
|
l.movhi r6, 0
|
l.movhi r6, 0
|
l.movhi r7, 0
|
l.movhi r7, 0
|
l.movhi r8, 0
|
l.movhi r8, 0
|
l.movhi r9, 0
|
l.movhi r9, 0
|
l.movhi r10, 0
|
l.movhi r10, 0
|
l.movhi r11, 0
|
l.movhi r11, 0
|
l.movhi r12, 0
|
l.movhi r12, 0
|
l.movhi r13, 0
|
l.movhi r13, 0
|
l.movhi r14, 0
|
l.movhi r14, 0
|
l.movhi r15, 0
|
l.movhi r15, 0
|
l.movhi r16, 0
|
l.movhi r16, 0
|
l.movhi r17, 0
|
l.movhi r17, 0
|
l.movhi r18, 0
|
l.movhi r18, 0
|
l.movhi r19, 0
|
l.movhi r19, 0
|
l.movhi r20, 0
|
l.movhi r20, 0
|
l.movhi r21, 0
|
l.movhi r21, 0
|
l.movhi r22, 0
|
l.movhi r22, 0
|
l.movhi r23, 0
|
l.movhi r23, 0
|
l.movhi r24, 0
|
l.movhi r24, 0
|
l.movhi r25, 0
|
l.movhi r25, 0
|
l.movhi r26, 0
|
l.movhi r26, 0
|
l.movhi r27, 0
|
l.movhi r27, 0
|
l.movhi r28, 0
|
l.movhi r28, 0
|
l.movhi r29, 0
|
l.movhi r29, 0
|
l.movhi r30, 0
|
l.movhi r30, 0
|
l.movhi r31, 0
|
l.movhi r31, 0
|
|
|
#ifdef OR1200_IMPL_OV
|
#ifdef OR1200_IMPL_OV
|
// Kick off test
|
// Kick off test
|
l.jal _main
|
l.jal _main
|
#else
|
#else
|
// Not supported, exit test
|
// Not supported, exit test
|
l.j _finish
|
l.j _finish
|
#endif
|
#endif
|
l.nop
|
l.nop
|
|
|
|
|
/* =================================================== [ main ] === */
|
/* =================================================== [ main ] === */
|
|
|
|
|
#define CHECK_OV_CLEAR \
|
#define CHECK_OV_CLEAR \
|
l.mfspr r20, r0, SPR_SR ; \
|
l.mfspr r20, r0, SPR_SR ; \
|
l.andi r21, r20, SPR_SR_OV ; \
|
l.andi r21, r20, SPR_SR_OV ; \
|
l.sfne r21, r0 ; \
|
l.sfne r21, r0 ; \
|
l.bf _fail ; \
|
l.bf _fail ; \
|
l.nop
|
l.nop
|
|
|
#define CHECK_OV_SET \
|
#define CHECK_OV_SET \
|
l.mfspr r20, r0, SPR_SR ; \
|
l.mfspr r20, r0, SPR_SR ; \
|
l.andi r21, r20, SPR_SR_OV ; \
|
l.andi r21, r20, SPR_SR_OV ; \
|
l.sfnei r21, SPR_SR_OV ; \
|
l.sfnei r21, SPR_SR_OV ; \
|
l.bf _fail ; \
|
l.bf _fail ; \
|
l.addi r12, r12, 0x1 ; // Increment expected counter
|
l.addi r12, r12, 0x1 ; // Increment expected counter
|
|
|
.global _main
|
.global _main
|
_main:
|
_main:
|
|
|
// Set up some values, check the OV bit is cleared
|
// Set up some values, check the OV bit is cleared
|
CHECK_OV_CLEAR
|
CHECK_OV_CLEAR
|
|
|
l.movhi r4, 0x7fff
|
l.movhi r4, 0x7fff
|
l.ori r4, r4, 0xefff
|
l.ori r4, r4, 0xefff
|
|
|
l.ori r5, r0, 0xffff
|
l.ori r5, r0, 0xffff
|
|
|
l.add r3, r5, r4 ;// Should set overflow
|
l.add r3, r5, r4 ;// Should set overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_SET
|
CHECK_OV_SET
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_CLEAR
|
CHECK_OV_CLEAR
|
|
|
l.addi r3, r4, 0x7fff ;// Should set overflow
|
l.addi r3, r4, 0x7fff ;// Should set overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_SET
|
CHECK_OV_SET
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_CLEAR
|
CHECK_OV_CLEAR
|
|
|
// Now test negative numbers
|
// Now test negative numbers
|
|
|
l.movhi r4, 0x8000
|
l.movhi r4, 0x8000
|
l.ori r4, r4, 0x0000
|
l.ori r4, r4, 0x0000
|
|
|
l.movhi r5, 0xffff
|
l.movhi r5, 0xffff
|
l.ori r5, r5, 0xffff
|
l.ori r5, r5, 0xffff
|
|
|
l.add r3, r4, r5 // Biggest and smallest negative number
|
l.add r3, r4, r5 // Biggest and smallest negative number
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_SET
|
CHECK_OV_SET
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_CLEAR
|
CHECK_OV_CLEAR
|
|
|
l.addi r3, r4, 0xffff // Biggest and smallest negative number
|
l.addi r3, r4, 0xffff // Biggest and smallest negative number
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_SET
|
CHECK_OV_SET
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_CLEAR
|
CHECK_OV_CLEAR
|
|
|
l.add r3, r4, r0 // Biggest negative number, and zero
|
l.add r3, r4, r0 // Biggest negative number, and zero
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_CLEAR
|
CHECK_OV_CLEAR
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_CLEAR
|
CHECK_OV_CLEAR
|
|
|
l.movhi r5, 0xffff
|
l.movhi r5, 0xffff
|
l.ori r5, r5, 0xfffe
|
l.ori r5, r5, 0xfffe
|
|
|
l.add r3, r4, r5 // Biggest and second smallest negative number
|
l.add r3, r4, r5 // Biggest and second smallest negative number
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_SET
|
CHECK_OV_SET
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_CLEAR
|
CHECK_OV_CLEAR
|
|
|
#ifdef OR1200_IMPL_SUB
|
#ifdef OR1200_IMPL_SUB
|
|
|
// report indicator that we're at l.sub section 0x55555555
|
// report indicator that we're at l.sub section 0x55555555
|
l.movhi r3, 0x5555
|
l.movhi r3, 0x5555
|
l.ori r3, r3, 0x5555
|
l.ori r3, r3, 0x5555
|
l.nop 0x2
|
l.nop 0x2
|
|
|
// Quick subtract check
|
// Quick subtract check
|
// Check largest negative number -1 tripping overflow
|
// Check largest negative number -1 tripping overflow
|
l.ori r5, r0, 1 ; // +1
|
l.ori r5, r0, 1 ; // +1
|
l.sub r3, r4, r5 ; // -2147483647 - 1
|
l.sub r3, r4, r5 ; // -2147483647 - 1
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_SET
|
CHECK_OV_SET
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_CLEAR
|
CHECK_OV_CLEAR
|
|
|
|
// Subtract the biggest negative number from the
|
|
// biggest positive number.
|
|
l.movhi r4,0x7fff
|
|
l.ori r4,r4,0xffff
|
|
l.movhi r5,0x8000
|
|
l.sub r3,r4,r5
|
|
l.nop 2
|
|
CHECK_OV_SET
|
|
|
#endif
|
#endif
|
|
|
l.movhi r4, 0x8000
|
l.movhi r4, 0x8000
|
l.ori r4, r4, 0x0437
|
l.ori r4, r4, 0x0437
|
|
|
l.movhi r5, 0xffff
|
l.movhi r5, 0xffff
|
l.ori r5, r5, 0xfbc7
|
l.ori r5, r5, 0xfbc7
|
|
|
l.add r3, r4, r5 // Very big negative number, another one big
|
l.add r3, r4, r5 // Very big negative number, another one big
|
// enough to cause overflow hopefully
|
// enough to cause overflow hopefully
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_SET
|
CHECK_OV_SET
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_CLEAR
|
CHECK_OV_CLEAR
|
|
|
l.movhi r5, 0xffff
|
l.movhi r5, 0xffff
|
l.ori r5, r5, 0xfff7
|
l.ori r5, r5, 0xfff7
|
|
|
l.add r3, r4, r5 // Two negative numbers but shouldn't overflow
|
l.add r3, r4, r5 // Two negative numbers but shouldn't overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_CLEAR
|
CHECK_OV_CLEAR
|
|
|
#ifdef OR1200_DIV_IMPLEMENTED
|
#ifdef OR1200_DIV_IMPLEMENTED
|
|
|
// report indicator that we're at l.div section 0xdddddddd
|
// report indicator that we're at l.div section 0xdddddddd
|
l.movhi r3, 0xdddd
|
l.movhi r3, 0xdddd
|
l.ori r3, r3, 0xdddd
|
l.ori r3, r3, 0xdddd
|
l.nop 0x2
|
l.nop 0x2
|
|
|
// Test divide by zero
|
// Test divide by zero
|
l.div r3, r5, r0
|
l.div r3, r5, r0
|
l.nop 0x2
|
l.nop 0x2
|
|
|
l.sfne r3, r0 ;// Check result was 0
|
l.sfne r3, r0 ;// Check result was 0
|
l.bf _fail
|
l.bf _fail
|
|
|
CHECK_OV_SET
|
CHECK_OV_SET
|
|
|
l.add r3, r5, r0 ;// Should clear overflow
|
l.add r3, r5, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
|
|
CHECK_OV_CLEAR
|
CHECK_OV_CLEAR
|
|
|
// Test divide by zero
|
// Test divide by zero
|
l.divu r3, r0, r0
|
l.divu r3, r0, r0
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_SET
|
CHECK_OV_SET
|
|
|
l.sfne r3, r0 ;// Check result was 0
|
l.sfne r3, r0 ;// Check result was 0
|
l.bf _fail
|
l.bf _fail
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_CLEAR
|
CHECK_OV_CLEAR
|
|
|
#endif
|
#endif
|
|
|
#ifdef OR1200_MULT_IMPLEMENTED
|
#ifdef OR1200_MULT_IMPLEMENTED
|
|
|
// report indicator that we're at l.multiply section 0x11111111
|
// report indicator that we're at l.multiply section 0x11111111
|
l.movhi r3, 0x1111
|
l.movhi r3, 0x1111
|
l.ori r3, r3, 0x1111
|
l.ori r3, r3, 0x1111
|
l.nop 0x2
|
l.nop 0x2
|
|
|
// Check multiplying two large numbers, which will cause overflow,
|
// Check multiplying two large numbers, which will cause overflow,
|
// trigger the flag appropriately
|
// trigger the flag appropriately
|
|
|
// First signed multiply.
|
// First signed multiply.
|
l.movhi r4, 0xd555 ;//-(((2^32)-1)/3 + 2)
|
l.movhi r4, 0xd555 ;//-(((2^32)-1)/3 + 2)
|
l.ori r4, r4, 0x5552
|
l.ori r4, r4, 0x5552
|
l.ori r5, r0, 2
|
l.ori r5, r0, 2
|
l.ori r6, r0, 3
|
l.ori r6, r0, 3
|
|
|
// First multiply big negative number by 2 - shouldn't overflow
|
// First multiply big negative number by 2 - shouldn't overflow
|
l.mul r3, r4, r5
|
l.mul r3, r4, r5
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_CLEAR
|
CHECK_OV_CLEAR
|
|
|
// Now multiply by 3 - should just overflow negative
|
// Now multiply by 3 - should just overflow negative
|
l.mul r3, r4, r6
|
l.mul r3, r4, r6
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_SET
|
CHECK_OV_SET
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_CLEAR
|
CHECK_OV_CLEAR
|
|
|
// Now some big positive values
|
// Now some big positive values
|
l.movhi r4, 0x2aaa ;//((2^32)-1)/3 + 2
|
l.movhi r4, 0x2aaa ;//((2^32)-1)/3 + 2
|
l.ori r4, r4, 0xaaae
|
l.ori r4, r4, 0xaaae
|
l.ori r5, r0, 2
|
l.ori r5, r0, 2
|
l.ori r6, r0, 3
|
l.ori r6, r0, 3
|
|
|
// First multiply big number by 2 - shouldn't overflow
|
// First multiply big number by 2 - shouldn't overflow
|
l.mul r3, r4, r5
|
l.mul r3, r4, r5
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_CLEAR
|
CHECK_OV_CLEAR
|
|
|
// Now multiply by 3 - should only just overflow
|
// Now multiply by 3 - should only just overflow
|
l.mul r3, r4, r6
|
l.mul r3, r4, r6
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_SET
|
CHECK_OV_SET
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_CLEAR
|
CHECK_OV_CLEAR
|
|
|
// First multiply big number by 2 - shouldn't overflow
|
// First multiply big number by 2 - shouldn't overflow
|
l.muli r3, r4, 0x2
|
l.muli r3, r4, 0x2
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_CLEAR
|
CHECK_OV_CLEAR
|
|
|
// Now multiply by 3 - should just overflow negative
|
// Now multiply by 3 - should just overflow negative
|
l.muli r3, r4, 0x3
|
l.muli r3, r4, 0x3
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_SET
|
CHECK_OV_SET
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_CLEAR
|
CHECK_OV_CLEAR
|
|
|
|
|
// Now check overflow on unsigned multiply
|
// Now check overflow on unsigned multiply
|
|
|
// Some stimulus to make a 32-bit multiply overflow
|
// Some stimulus to make a 32-bit multiply overflow
|
l.movhi r4, 0x5555 ;//((2^32))/3 + 2
|
l.movhi r4, 0x5555 ;//((2^32))/3 + 2
|
l.ori r4, r4, 0x5557
|
l.ori r4, r4, 0x5557
|
l.ori r5, r0, 2
|
l.ori r5, r0, 2
|
l.ori r6, r0, 3
|
l.ori r6, r0, 3
|
|
|
// First multiply big negative number by 2 - shouldn't overflow
|
// First multiply big negative number by 2 - shouldn't overflow
|
l.mulu r3, r4, r5
|
l.mulu r3, r4, r5
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_CLEAR
|
CHECK_OV_CLEAR
|
|
|
// Now multiply by 3 - should just overflow negative
|
// Now multiply by 3 - should just overflow negative
|
l.mulu r3, r4, r6
|
l.mulu r3, r4, r6
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_SET
|
CHECK_OV_SET
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_OV_CLEAR
|
CHECK_OV_CLEAR
|
|
|
#endif
|
#endif
|
|
|
/////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////
|
// //
|
// //
|
// Range Exception Tests //
|
// Range Exception Tests //
|
// //
|
// //
|
/////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////
|
#ifdef OR1200_IMPL_OVE
|
#ifdef OR1200_IMPL_OVE
|
// report indicator that we're at exception section 0xeeeeeeee
|
// report indicator that we're at exception section 0xeeeeeeee
|
l.movhi r3, 0xeeee
|
l.movhi r3, 0xeeee
|
l.ori r3, r3, 0xeeee
|
l.ori r3, r3, 0xeeee
|
l.nop 0x2
|
l.nop 0x2
|
|
|
// First enable OV exception in SR
|
// First enable OV exception in SR
|
|
|
l.mfspr r20, r0, SPR_SR
|
l.mfspr r20, r0, SPR_SR
|
l.ori r21, r20, SPR_SR_OVE
|
l.ori r21, r20, SPR_SR_OVE
|
l.mtspr r0, r21, SPR_SR
|
l.mtspr r0, r21, SPR_SR
|
|
|
// Check it's set
|
// Check it's set
|
l.mfspr r20, r0, SPR_SR
|
l.mfspr r20, r0, SPR_SR
|
l.andi r21, r20, SPR_SR_OVE
|
l.andi r21, r20, SPR_SR_OVE
|
l.sfnei r21, SPR_SR_OVE
|
l.sfnei r21, SPR_SR_OVE
|
l.bf _fail
|
l.bf _fail
|
l.nop
|
l.nop
|
|
|
// now set r11 to r12 to know how many tests we've done so far
|
// now set r11 to r12 to know how many tests we've done so far
|
l.or r11, r12, r12
|
l.or r11, r12, r12
|
|
|
l.movhi r4, 0x7fff
|
l.movhi r4, 0x7fff
|
l.ori r4, r4, 0xefff
|
l.ori r4, r4, 0xefff
|
|
|
l.ori r5, r0, 0xffff
|
l.ori r5, r0, 0xffff
|
|
|
l.add r3, r5, r4 ;// Should set overflow
|
l.add r3, r5, r4 ;// Should set overflow
|
l.nop 0x2
|
l.nop 0x2
|
EXPECT_RANGE_EXCEPT
|
EXPECT_RANGE_EXCEPT
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_EXCEPTION_COUNTER
|
CHECK_EXCEPTION_COUNTER
|
|
|
|
|
l.addi r3, r4, 0x7fff ;// Should set overflow
|
l.addi r3, r4, 0x7fff ;// Should set overflow
|
l.nop 0x2
|
l.nop 0x2
|
EXPECT_RANGE_EXCEPT
|
EXPECT_RANGE_EXCEPT
|
|
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_EXCEPTION_COUNTER
|
CHECK_EXCEPTION_COUNTER
|
|
|
|
|
// Now test negative numbers
|
// Now test negative numbers
|
|
|
l.movhi r4, 0x8000
|
l.movhi r4, 0x8000
|
l.ori r4, r4, 0x0000
|
l.ori r4, r4, 0x0000
|
|
|
l.movhi r5, 0xffff
|
l.movhi r5, 0xffff
|
l.ori r5, r5, 0xffff
|
l.ori r5, r5, 0xffff
|
|
|
l.add r3, r4, r5 // Biggest and smallest negative number
|
l.add r3, r4, r5 // Biggest and smallest negative number
|
l.nop 0x2
|
l.nop 0x2
|
EXPECT_RANGE_EXCEPT
|
EXPECT_RANGE_EXCEPT
|
|
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_EXCEPTION_COUNTER
|
CHECK_EXCEPTION_COUNTER
|
|
|
l.addi r3, r4, 0xffff // Biggest and smallest negative number
|
l.addi r3, r4, 0xffff // Biggest and smallest negative number
|
l.nop 0x2
|
l.nop 0x2
|
EXPECT_RANGE_EXCEPT
|
EXPECT_RANGE_EXCEPT
|
|
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_EXCEPTION_COUNTER
|
CHECK_EXCEPTION_COUNTER
|
|
|
l.add r3, r4, r0 // Biggest negative number, and zero
|
l.add r3, r4, r0 // Biggest negative number, and zero
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_EXCEPTION_COUNTER
|
CHECK_EXCEPTION_COUNTER
|
|
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_EXCEPTION_COUNTER
|
CHECK_EXCEPTION_COUNTER
|
|
|
|
|
l.movhi r5, 0xffff
|
l.movhi r5, 0xffff
|
l.ori r5, r5, 0xfffe
|
l.ori r5, r5, 0xfffe
|
|
|
l.add r3, r4, r5 // Biggest and second smallest negative number
|
l.add r3, r4, r5 // Biggest and second smallest negative number
|
l.nop 0x2
|
l.nop 0x2
|
EXPECT_RANGE_EXCEPT
|
EXPECT_RANGE_EXCEPT
|
|
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_EXCEPTION_COUNTER
|
CHECK_EXCEPTION_COUNTER
|
|
|
#ifdef OR1200_IMPL_SUB
|
#ifdef OR1200_IMPL_SUB
|
|
|
// report indicator that we're at l.sub section 0x55555555
|
// report indicator that we're at l.sub section 0x55555555
|
l.movhi r3, 0x5555
|
l.movhi r3, 0x5555
|
l.ori r3, r3, 0x5555
|
l.ori r3, r3, 0x5555
|
l.nop 0x2
|
l.nop 0x2
|
|
|
// Quick subtract check
|
// Quick subtract check
|
// Check largest negative number -1 tripping overflow
|
// Check largest negative number -1 tripping overflow
|
l.ori r5, r0, 1 ; // +1
|
l.ori r5, r0, 1 ; // +1
|
l.sub r3, r4, r5 ; // -2147483647 - 1
|
l.sub r3, r4, r5 ; // -2147483647 - 1
|
l.nop 0x2
|
l.nop 0x2
|
EXPECT_RANGE_EXCEPT
|
EXPECT_RANGE_EXCEPT
|
|
|
|
|
l.sub r3, r0, r0 ;// Should clear overflow
|
l.sub r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_EXCEPTION_COUNTER
|
CHECK_EXCEPTION_COUNTER
|
|
|
#endif
|
#endif
|
|
|
l.movhi r4, 0x8000
|
l.movhi r4, 0x8000
|
l.ori r4, r4, 0x0437
|
l.ori r4, r4, 0x0437
|
|
|
l.movhi r5, 0xffff
|
l.movhi r5, 0xffff
|
l.ori r5, r5, 0xfbc7
|
l.ori r5, r5, 0xfbc7
|
|
|
l.add r3, r4, r5 // Very big negative number, another one big
|
l.add r3, r4, r5 // Very big negative number, another one big
|
// enough to cause overflow hopefully
|
// enough to cause overflow hopefully
|
l.nop 0x2
|
l.nop 0x2
|
EXPECT_RANGE_EXCEPT
|
EXPECT_RANGE_EXCEPT
|
|
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_EXCEPTION_COUNTER
|
CHECK_EXCEPTION_COUNTER
|
|
|
l.movhi r5, 0xffff
|
l.movhi r5, 0xffff
|
l.ori r5, r5, 0xfff7
|
l.ori r5, r5, 0xfff7
|
|
|
l.add r3, r4, r5 // Two negative numbers but shouldn't overflow
|
l.add r3, r4, r5 // Two negative numbers but shouldn't overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_EXCEPTION_COUNTER
|
CHECK_EXCEPTION_COUNTER
|
|
|
#ifdef OR1200_DIV_IMPLEMENTED
|
#ifdef OR1200_DIV_IMPLEMENTED
|
|
|
// report indicator that we're at l.div section 0xdddddddd
|
// report indicator that we're at l.div section 0xdddddddd
|
l.movhi r3, 0xdddd
|
l.movhi r3, 0xdddd
|
l.ori r3, r3, 0xdddd
|
l.ori r3, r3, 0xdddd
|
l.nop 0x2
|
l.nop 0x2
|
|
|
// Test divide by zero
|
// Test divide by zero
|
l.div r3, r5, r0
|
l.div r3, r5, r0
|
l.nop 0x2
|
l.nop 0x2
|
|
|
l.sfne r3, r0 ;// Check result was 0
|
l.sfne r3, r0 ;// Check result was 0
|
l.bf _fail
|
l.bf _fail
|
|
|
EXPECT_RANGE_EXCEPT
|
EXPECT_RANGE_EXCEPT
|
|
|
|
|
l.add r3, r5, r0 ;// Should clear overflow
|
l.add r3, r5, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
|
|
CHECK_EXCEPTION_COUNTER
|
CHECK_EXCEPTION_COUNTER
|
|
|
// Test divide by zero
|
// Test divide by zero
|
l.divu r3, r0, r0
|
l.divu r3, r0, r0
|
l.nop 0x2
|
l.nop 0x2
|
EXPECT_RANGE_EXCEPT
|
EXPECT_RANGE_EXCEPT
|
|
|
|
|
l.sfne r3, r0 ;// Check result was 0
|
l.sfne r3, r0 ;// Check result was 0
|
l.bf _fail
|
l.bf _fail
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_EXCEPTION_COUNTER
|
CHECK_EXCEPTION_COUNTER
|
|
|
#endif
|
#endif
|
|
|
#ifdef OR1200_MULT_IMPLEMENTED
|
#ifdef OR1200_MULT_IMPLEMENTED
|
|
|
// report indicator that we're at l.multiply section 0x11111111
|
// report indicator that we're at l.multiply section 0x11111111
|
l.movhi r3, 0x1111
|
l.movhi r3, 0x1111
|
l.ori r3, r3, 0x1111
|
l.ori r3, r3, 0x1111
|
l.nop 0x2
|
l.nop 0x2
|
|
|
// Check multiplying two large numbers, which will cause overflow,
|
// Check multiplying two large numbers, which will cause overflow,
|
// trigger the flag appropriately
|
// trigger the flag appropriately
|
|
|
// First signed multiply.
|
// First signed multiply.
|
l.movhi r4, 0xd555 ;//-(((2^32)-1)/3 + 2)
|
l.movhi r4, 0xd555 ;//-(((2^32)-1)/3 + 2)
|
l.ori r4, r4, 0x5552
|
l.ori r4, r4, 0x5552
|
l.ori r5, r0, 2
|
l.ori r5, r0, 2
|
l.ori r6, r0, 3
|
l.ori r6, r0, 3
|
|
|
// First multiply big negative number by 2 - shouldn't overflow
|
// First multiply big negative number by 2 - shouldn't overflow
|
l.mul r3, r4, r5
|
l.mul r3, r4, r5
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_EXCEPTION_COUNTER
|
CHECK_EXCEPTION_COUNTER
|
|
|
// Now multiply by 3 - should just overflow negative
|
// Now multiply by 3 - should just overflow negative
|
l.mul r3, r4, r6
|
l.mul r3, r4, r6
|
l.nop 0x2
|
l.nop 0x2
|
EXPECT_RANGE_EXCEPT
|
EXPECT_RANGE_EXCEPT
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_EXCEPTION_COUNTER
|
CHECK_EXCEPTION_COUNTER
|
|
|
// Now some big positive values
|
// Now some big positive values
|
l.movhi r4, 0x2aaa ;//((2^32)-1)/3 + 2
|
l.movhi r4, 0x2aaa ;//((2^32)-1)/3 + 2
|
l.ori r4, r4, 0xaaae
|
l.ori r4, r4, 0xaaae
|
l.ori r5, r0, 2
|
l.ori r5, r0, 2
|
l.ori r6, r0, 3
|
l.ori r6, r0, 3
|
|
|
// First multiply big number by 2 - shouldn't overflow
|
// First multiply big number by 2 - shouldn't overflow
|
l.mul r3, r4, r5
|
l.mul r3, r4, r5
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_EXCEPTION_COUNTER
|
CHECK_EXCEPTION_COUNTER
|
|
|
// Now multiply by 3 - should only just overflow
|
// Now multiply by 3 - should only just overflow
|
l.mul r3, r4, r6
|
l.mul r3, r4, r6
|
l.nop 0x2
|
l.nop 0x2
|
EXPECT_RANGE_EXCEPT
|
EXPECT_RANGE_EXCEPT
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_EXCEPTION_COUNTER
|
CHECK_EXCEPTION_COUNTER
|
|
|
// First multiply big number by 2 - shouldn't overflow
|
// First multiply big number by 2 - shouldn't overflow
|
l.muli r3, r4, 0x2
|
l.muli r3, r4, 0x2
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_EXCEPTION_COUNTER
|
CHECK_EXCEPTION_COUNTER
|
|
|
// Now multiply by 3 - should just overflow negative
|
// Now multiply by 3 - should just overflow negative
|
l.muli r3, r4, 0x3
|
l.muli r3, r4, 0x3
|
l.nop 0x2
|
l.nop 0x2
|
EXPECT_RANGE_EXCEPT
|
EXPECT_RANGE_EXCEPT
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_EXCEPTION_COUNTER
|
CHECK_EXCEPTION_COUNTER
|
|
|
|
|
// Now check overflow on unsigned multiply
|
// Now check overflow on unsigned multiply
|
|
|
// Some stimulus to make a 32-bit multiply overflow
|
// Some stimulus to make a 32-bit multiply overflow
|
l.movhi r4, 0x5555 ;//((2^32))/3 + 2
|
l.movhi r4, 0x5555 ;//((2^32))/3 + 2
|
l.ori r4, r4, 0x5557
|
l.ori r4, r4, 0x5557
|
l.ori r5, r0, 2
|
l.ori r5, r0, 2
|
l.ori r6, r0, 3
|
l.ori r6, r0, 3
|
|
|
// First multiply big negative number by 2 - shouldn't overflow
|
// First multiply big negative number by 2 - shouldn't overflow
|
l.mulu r3, r4, r5
|
l.mulu r3, r4, r5
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_EXCEPTION_COUNTER
|
CHECK_EXCEPTION_COUNTER
|
|
|
// Now multiply by 3 - should just overflow negative
|
// Now multiply by 3 - should just overflow negative
|
l.mulu r3, r4, r6
|
l.mulu r3, r4, r6
|
l.nop 0x2
|
l.nop 0x2
|
EXPECT_RANGE_EXCEPT
|
EXPECT_RANGE_EXCEPT
|
|
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.add r3, r0, r0 ;// Should clear overflow
|
l.nop 0x2
|
l.nop 0x2
|
CHECK_EXCEPTION_COUNTER
|
CHECK_EXCEPTION_COUNTER
|
|
|
#endif
|
#endif
|
|
|
#endif
|
#endif
|
|
|
|
|
_finish:
|
_finish:
|
l.movhi r3, hi(0x8000000d)
|
l.movhi r3, hi(0x8000000d)
|
l.ori r3, r3, lo(0x8000000d)
|
l.ori r3, r3, lo(0x8000000d)
|
l.nop 0x2
|
l.nop 0x2
|
l.ori r3, r0, 0
|
l.ori r3, r0, 0
|
l.nop 0x1
|
l.nop 0x1
|
|
|
_fail:
|
_fail:
|
l.or r3, r12, r0 ;// Fail and report test number we were up to
|
l.or r3, r12, r0 ;// Fail and report test number we were up to
|
l.nop 0x1
|
l.nop 0x1
|
|
|