Files
OpenCellular/core/nds32/init.S
Dino Li c35fad0f2b chip: it83xx: add support for floating point unit
Because N8 CPU doesn't have floating point unit,
so we implement an extra floating point engine
(single-precision addition, subtraction, multiplication,
and division) into it8320 to improve performance of
floating point operation.

To make CPU's instruction compatible, we use register (DLMB)
to switch ALU (Arithmetic Logic Unit). eg:
Instruction 'ADD45' adds the contents of two registers then
writes the result to the source register.
But if we switch ALU to floating point operation mode,
this instruction will do a floating-point addition instead.

For the other FPU that we don't support as far,
we have to use soft float library routines of nds32.

Signed-off-by: Dino Li <dino.li@ite.com.tw>

BRANCH=none
BUG=none
TEST=add the following console command and test different
scenarios by changing variable a and b.

#define PRINTF_FLOAT(x)  ((int)((x) * 1000.0f))
static int it83xx_fpu_test(int argc, char **argv)
{
	volatile float a = 1.23f;
	volatile float b = 4.56f;
	volatile float c;

	c = a + b;
	ccprintf("__addsf3: (%d)\n", PRINTF_FLOAT(c));
	c = a - b;
	ccprintf("__subsf3: (%d)\n", PRINTF_FLOAT(c));
	c = a * b;
	ccprintf("__mulsf3: (%d)\n", PRINTF_FLOAT(c));
	c = a / b;
	ccprintf("__divsf3: (%d)\n", PRINTF_FLOAT(c));

	return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(fpu, it83xx_fpu_test, "", "");

Change-Id: I4fc1c08d8c2376156bec9f098491187675c4a88f
Reviewed-on: https://chromium-review.googlesource.com/427640
Commit-Ready: Dino Li <Dino.Li@ite.com.tw>
Tested-by: Dino Li <Dino.Li@ite.com.tw>
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
2017-05-29 21:49:05 -07:00

246 lines
6.1 KiB
ArmAsm

/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* N8 CPU initialization
*/
#include "config.h"
/* magic macro to implement IRQ prefix / exit */
.macro vector name, entry_number
.weak \name\()_handler
.set \name\()_handler, unhandled_irq
j __entry_\()\name
.pushsection .text.vectirq
.global __entry_\()\name
__entry_\()\name:
/* the context is stored on the current task stack*/
/* save r15, fp, lp and sp */
smw.adm $r15, [$sp], $r15, 0xb
/* r0-r5 are caller saved */
smw.adm $r0, [$sp], $r5, 0
/* switch to system stack if we are called from process stack */
la $r3, stack_end
mov55 $fp, $sp
slt45 $r3, $sp /* if sp > end of system stack, then r15 = 1 and */
cmovn $sp, $r3, $r15 /* point sp to the top of the system stack */
/* save entry number of HW interrupt */
movi55 $r3, \entry_number\()
swi.gp $r3, [ + cpu_int_entry_number]
/* isr entry */
jal start_irq_handler
/* C routine handler */
jal \name\()_handler
/* check whether we need to change the scheduled task */
lwi.gp $r2, [ + need_resched]
bnez $r2, __switch_task
/* isr exit */
jal end_irq_handler
/* restore r0-r5 */
lmw.bim $r0, [$fp], $r5, 0
/* restore r15, fp, lp and sp */
lmw.bi $r15, [$fp], $r15, 0xb
/* restore PC and PSW */
iret
.popsection
.pushsection .rodata.vecthandlers
.long \name\()_handler
.popsection
.endm
.section .text.vecttable
/* Exceptions vector */
vectors:
j reset /* reset / NMI */
j excep_handler /* TLB fill */
j excep_handler /* PTE not present */
j excep_handler /* TLB misc */
j excep_handler /* TLB VLPT miss */
j excep_handler /* Machine error */
j excep_handler /* Debug related */
j excep_handler /* General exception */
vector syscall, -1 /* Syscall */
vector irq_0, 0 /* HW 0 */
vector irq_1, 1 /* HW 1 */
vector irq_2, 2 /* HW 2 */
vector irq_3, 3 /* HW 3 */
vector irq_4, 4 /* HW 4 */
vector irq_5, 5 /* HW 5 */
vector irq_6, 6 /* HW 6 */
vector irq_7, 7 /* HW 7 */
vector irq_8, 8 /* HW 8 */
vector irq_9, 9 /* HW 9 */
vector irq_10, 10 /* HW 10 */
vector irq_11, 11 /* HW 11 */
vector irq_12, 12 /* HW 12 */
vector irq_13, 13 /* HW 13 */
vector irq_14, 14 /* HW 14 */
vector irq_15, 15 /* HW 15 */
/* E-flash signature */
.org 0x80
.balign 16
.global eflash_sig
eflash_sig:
.byte 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xB4
.byte 0x85, 0x12, 0x5A, 0x5A, 0xAA, 0xAA, 0x55, 0x55
/* flags: internal oscillator + implicit location */
.text
.global reset
reset:
/*
* GIE (global interrupt) is always disabled here. the first
* "iret" instruction of syscall interrupt (triggered by __task_start)
* will restore PSW from IPSW, and will enable GIE.
* Firmware will not change GIE settings (set/clear) until the next
* reset, unless there's an interrupt event.
* When there is an interrupt event, N8 CPU will save PSW register to
* IPSW register and clear GIE then jump to interrupt service routine.
* N8 will restore PSW from IPSW after "iret" instruction.
*/
setgie.d
dsb
/* GP register is used to access .data and .bss */
la $gp, _SDA_BASE_
/* Set system stack pointer. */
la $sp, stack_end
/* map/enable the 16kB of DLM at 0x00080000 */
li $r0, 0x00080005
mtsr $r0, $mr7
/* Enable DLM 8k~12K(bit2) and DLM 12k~16k(bit3) */
li $r1, 0x00F02030
lbi $r0, [$r1]
ori $r0, $r0, 0x0C
sbi $r0, [$r1]
/* Enable DLM 16k~36K bit[2-6] */
li $r1, 0x00F0203E
lbi $r0, [$r1]
ori $r0, $r0, 0x7C
sbi $r0, [$r1]
/* Enable DLM 36k~48K bit[0-2] */
li $r1, 0x00F02044
lbi $r0, [$r1]
ori $r0, $r0, 0x7
sbi $r0, [$r1]
/* Clear BSS */
la $r0, _bss_start
lwi $r1, [$r0]
la $r0, _bss_end
lwi $r2, [$r0]
movi $r0, #0
bss_loop:
swi.bi $r0, [$r1], 4
bne $r1, $r2, bss_loop
/* Copy initialized data to DLM */
la $r0, _data_start
lwi $r1, [$r0]
la $r0, _data_end
lwi $r2, [$r0]
la $r0, _ro_end
lwi $r0, [$r0]
data_loop:
lwi.bi $r3, [$r0], 4
swi.bi $r3, [$r1], 4
bne $r1, $r2, data_loop
/* we switch to our own exception vectors */
/* go back to it level 0 with HW interrupts globally disabled */
li $r4, 0x70008
mtsr $r4, $PSW
/* IT8380 specific: set vectors at 0 */
li $r5, 0x0F02041 /* IVTBAR in GCTRL */
movi $r15, 0
sbi $r15, [$r5]
/* Interrupt vectors are every 4 bytes */
li $r5, 0x00000007
mtsr $r5, $IVB
/* Jump to C routine */
jal main
/* That should not return. If it does, loop forever. */
j .
.global unhandled_irq
unhandled_irq:
mfsr $gp, $ITYPE
sethi $r15, 0xBAD0
or $r15, $r15, $gp
mtsr $r15, $ITYPE
dsb
j excep_handler /* display exception with ITYPE=bad00<irq> */
.global excep_handler
excep_handler:
/* safety: reload GP even though it should be already set */
la $gp, _SDA_BASE_
/* save r0 to free one register */
swi.gp $r0, [ + saved_regs]
/* save the remaining 15 registers */
la $r0, saved_regs + 4
smw.bim $r1, [$r0], $r10, 0
smw.bim $r15,[$r0], $r15, 0xF
#ifdef CONFIG_FPU
/*
* We have to restore ALU so that we can continue the next
* sequence if arithmetic instructions are used.
* (Apply to floating point division by zero)
*/
sethi $r4, 0x80
ori $r4, $r4,0x9
mtsr $r4, $dlmb
dsb
#endif
/* put a sane stack pointer */
la $sp, stack_end
/* add IPC, IPSW to the context */
mfsr $r1, $IPC
mfsr $r2, $IPSW
smw.bi $r1, [$r0], $r2, 0
/* pass ir6/ITYPE as the second parameter */
mfsr $r1, $ITYPE
/* exception context pointer as first parameter */
addi $r0, $r0, -16*4
/* jump to panic dump C routine */
jal report_panic
/* we never return: exceptions are fatal */
j .
.align 2
_bss_start:
.long __bss_start
_bss_end:
.long __bss_end
_data_start:
.long __data_start
_data_end:
.long __data_end
_ro_end:
.long __ro_end
/* Reserve space for system stack */
.section .bss.system_stack
stack_start:
.space CONFIG_STACK_SIZE, 0
stack_end:
.global stack_end
/* registers state at exception entry */
.global saved_regs
saved_regs:
.long 0, 0, 0, 0, 0, 0, 0, 0
.long 0, 0, 0, 0, 0, 0, 0, 0
/* IPC, IPSW for convenient access */
.long 0, 0