[bsp] add spackfun-redv bsp

This commit is contained in:
luhuadong
2020-10-31 15:40:38 +08:00
parent 06eafe3928
commit 554865a8a9
69 changed files with 5620 additions and 0 deletions
+19
View File
@@ -0,0 +1,19 @@
mainmenu "RT-Thread Configuration"
config BSP_DIR
string
option env="BSP_ROOT"
default "."
config RTT_DIR
string
option env="RTT_ROOT"
default "../.."
config PKGS_DIR
string
option env="PKGS_ROOT"
default "packages"
source "$RTT_DIR/Kconfig"
source "$PKGS_DIR/Kconfig"
+7
View File
@@ -0,0 +1,7 @@
scons := python ${SCONS}\scons.py
all:
@$(scons)
clean:
@$(scons) -c
+164
View File
@@ -0,0 +1,164 @@
# SparkFun RED-V #
## 1 简介
[SparkFun RED-V](https://www.sparkfun.com/products/15594) 是一款基于 RISC-V 架构的低成本开源开发板,核心 SoC Freedom E310-002 (FE310) 是 SiFive 的 Freedom Everywhere 可定制 SoCs 系列 FE310 的一个升级版本(兼容 HiFive1-rev-b)。最大主频提高了一倍多达到 320MHz,具有 SiFive 的高性能32位 RV32IMAC 核心,性能测试表现很突出,达到了 1.61 DMIPs/MHz,甚至超过了 Arm Cortex-M4 内核。适用于微控制器、嵌入式、物联网和可穿戴应用等领域。
![](figures/board.jpg)
### 1.1 板载资源
| 硬件 | 描述 |
| -- | -- |
|Soc| SiFive Freedom E310 (FE310-G002) |
| 内核 | SiFive E31 RISC-V Core |
| 架构 | 32-bit RV32IMAC |
| 主频 | 320+ MHz |
| 性能 | 1.61 DMIPs/MHz, 2.73 Coremark/MHz |
|SRAM| 16KB |
|Flash| 32 Mbit Off-Chip (ISSI SPI Flash) |
### 1.2 特性
- 16KB L1 指令缓存
- 16KB 数据 SRAM 暂存器
- 硬件乘/除
- 调试模块
- OTP 非易失性存储器
- 片上振荡器和 PLL 产生灵活的时钟
- 外围设备,包括 UART,QSPI,PWM 和定时器
- 多个电源域+低功耗待机模式
## 2 编译说明
### 2.2 下载 Freedom Studio
[Freedom Studio](https://www.sifive.com/software) 是 SiFive 公司推出的一个集成开发环境,用来编写和调试基于 SiFive 处理器的软件。内嵌了编译好的 RISC-V GCC 工具链、OpenOCD、以及一些示例和文档。
特别地,这里以 v2019.08.1 版本进行演示:
- [FreedomStudio-2019-08-1-lin64](https://static.dev.sifive.com/dev-tools/FreedomStudio/2019.08/FreedomStudio-2019-08-1-lin64.tar.gz)
- [FreedomStudio-2019-08-1-win64](https://static.dev.sifive.com/dev-tools/FreedomStudio/2019.08/FreedomStudio-2019-08-1-win64.zip)
- [FreedomStudio-2019-08-1-mac64](https://static.dev.sifive.com/dev-tools/FreedomStudio/2019.08/FreedomStudio-2019-08-1-mac64.tar.gz)
将 Freedom Studio 解压到非中文字符且不含空格的目录下,如果是 Windows 系统,还需要打开 `FreedomStudio-2019-08-1-win64\SiFive\Drivers` 文件夹,安装驱动文件。
- HiFive1_Driver.exe
- sifive-winusb-utility.exe
### 2.3 配置工具链
工具链的默认位置为 `SiFive/riscv64-unknown-elf-gcc-8.3.0-2019.08.0/bin/` 目录。运行 Env 工具,根据实际情况,输入以下命令设置环境变量:
```shell
set RTT_EXEC_PATH=工具链的路径
set path=%path%;工具链的路径
```
例如:
```shell
set RTT_EXEC_PATH=C:\FreedomStudio-2019-08-1-win64\SiFive\riscv64-unknown-elf-gcc-8.3.0-2019.08.0\bin
set path=%path%;C:\FreedomStudio-2019-08-1-win64\SiFive\riscv64-unknown-elf-gcc-8.3.0-2019.08.0\bin
```
### 2.4 从 Env 工具打开 IDE
在 Env 中使用 cd 命令切换到 FreedomStudio 解压后的目录中,再执行 `FreedomStudio.exe` 文件启动 IDE。例如:
```
cd C:\FreedomStudio-2019-08-1-win64
FreedomStudio.exe
```
### 2.5 导入工程
点击菜单栏左上角 `File -> Import...`,展开 `C/C++` ,选择 `Existing Code as Makefile Project` ,点击 Next 继续。
![](figures/import_makefile_project.png)
在编辑框中填入 bsp 文件所在目录,选择 `Cross GCC` ,点击 Finish 导入。
![](figures/import_makefile_project_bsp.png)
### 2.6 编译
选中要编译的工程,点击左上角的锤子图标开始编译。
![build](figures/freedomstudio_compile.png)
当窗口输出 `Build Finished` ,左侧文件列表出现 `rtthread.elf` 文件时,即为编译成功。
## 3 烧写及执行
### 3.1 配置 Debug 参数
使用 type-c usb 数据线连接电脑与开发板。右键列表中的 `rtthread.elf` 文件,选择 `Debug As->1 As JLink launch`
点击 Debugger 选项卡,选择设备名称 `FE310`
![](figures/debug_Debugger.png)
点击 Config 选项卡,在 'Target Architecture' 处选择 'riscv:cv32' ,点击 Debug 开始调试。
![](figures/debug_Config.png)
### 3.2 运行结果
下载程序之后,连接串口(115200-N-8-1),可以看到 RT-Thread 的输出信息:
![](./figures/debug_terminal_msh.png)
可以看到板载的蓝色 LED 灯以 1Hz 频率闪烁,按下 Tab 键可以查看 RT-Thread 内置的命令。
```
msh >
RT-Thread shell commands:
give_me_five - Show the SiFive logo
memcheck - check memory data
memtrace - dump memory trace information
clear - clear the terminal screen
version - show RT-Thread version information
list_thread - list thread
list_sem - list semaphore in system
list_event - list event in system
list_mutex - list mutex in system
list_mailbox - list mail box in system
list_msgqueue - list message queue in system
list_mempool - list memory pool in system
list_timer - list timer in system
list_device - list device in system
help - RT-Thread shell help.
ps - List threads in the system.
free - Show the memory usage in the system.
```
## 4 驱动支持情况及计划
| 驱动 | 支持情况 | 备注 |
| ------ | ---- | :------: |
| UART | 支持 | UART0_RX/TXGPIO 16/17 |
## 5 联系人信息
维护人:
- [luhuadong](https://github.com/luhuadong)
## 6 参考
* [RED-V Schematic](https://cdn.sparkfun.com/assets/d/d/1/e/7/RedFive.pdf)
* [RED-V Development Guide](https://learn.sparkfun.com/tutorials/red-v-development-guide)
* [Getting Started with the SparkFun Red-V](https://www.digikey.dk/da/maker/projects/getting-started-with-the-sparkfun-red-v/a28c5ce7d21a452db4aa3f4b94f345f4)
* [Freedom E310-G002 Datasheet](https://cdn.sparkfun.com/assets/5/b/e/6/2/fe310-g002-ds.pdf)
* [Freedom E310-G002 Manual](https://cdn.sparkfun.com/assets/7/f/0/2/7/fe310-g002-manual-v19p05.pdf)
* [Freedom Studio User Manual](https://static.dev.sifive.com/dev-tools/FreedomStudio/2020.06/freedom-studio-manual-4.7.2-2020-06-0.pdf)
+18
View File
@@ -0,0 +1,18 @@
# for module compiling
import os
Import('RTT_ROOT')
from building import *
cwd = str(Dir('#'))
src = Glob('*.c')
objs = []
list = os.listdir(cwd)
for d in list:
path = os.path.join(cwd, d)
if os.path.isfile(os.path.join(path, 'SConscript')):
objs = objs + SConscript(os.path.join(d, 'SConscript'))
group = DefineGroup('', src, depend = [''], CPPPATH = [])
#objs += group
Return('objs')
+30
View File
@@ -0,0 +1,30 @@
import os
import sys
import rtconfig
if os.getenv('RTT_ROOT'):
RTT_ROOT = os.getenv('RTT_ROOT')
else:
RTT_ROOT = os.path.normpath(os.getcwd() + '/../..')
sys.path = sys.path + [os.path.join(RTT_ROOT, 'tools')]
from building import *
TARGET = 'rtthread.' + rtconfig.TARGET_EXT
env = Environment(tools = ['mingw'],
AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS,
CC = rtconfig.CC, CCFLAGS = rtconfig.CFLAGS,
AR = rtconfig.AR, ARFLAGS = '-rc',
LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS)
env.PrependENVPath('PATH', rtconfig.EXEC_PATH)
env['ASCOM'] = env['ASPPCOM']
Export('RTT_ROOT')
Export('rtconfig')
# prepare building environment
objs = PrepareBuilding(env, RTT_ROOT)
# make a building
DoBuilding(TARGET, objs)
+18
View File
@@ -0,0 +1,18 @@
Import('RTT_ROOT')
Import('rtconfig')
from building import *
cwd = os.path.join(str(Dir('#')), 'applications')
src = Glob('*.c')
src.append('led/led.c')
CPPPATH = [cwd,
str(Dir('#')),
os.path.join(str(Dir('#')), 'freedom-e-sdk/bsp/env'),
os.path.join(str(Dir('#')), 'freedom-e-sdk/bsp/env/freedom-e300-hifive1'),
os.path.join(str(Dir('#')), 'freedom-e-sdk/include/sifive/devices'),
os.path.join(cwd, 'led')]
group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH)
Return('group')
+59
View File
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-10-28 luhuadong first version
*/
#include <rtdevice.h>
#include <hifive1.h>
#include <platform.h>
#include <gpio.h>
#include "led.h"
#define USER_LED_OFFSET 5
static void _led_init(rt_uint8_t offset)
{
GPIO_REG(GPIO_IOF_EN) &= ~(1UL << offset);
GPIO_REG(GPIO_OUTPUT_EN) |= (1UL << offset);
}
static void _led_set(rt_uint8_t offset, rt_uint8_t val)
{
switch (val)
{
case LED_ON:
GPIO_REG(GPIO_OUTPUT_VAL) |= (1UL << offset);
break;
case LED_OFF:
GPIO_REG(GPIO_OUTPUT_VAL) &= ~(1UL << offset);
break;
default:
break;
}
}
static void _led_toggle(rt_uint8_t offset)
{
GPIO_REG(GPIO_OUTPUT_VAL) ^= (1UL << offset);
}
void led_init(void)
{
_led_init(USER_LED_OFFSET);
}
void led_set(rt_uint8_t val)
{
_led_set(USER_LED_OFFSET, val);
}
void led_toggle(void)
{
_led_toggle(USER_LED_OFFSET);
}
+21
View File
@@ -0,0 +1,21 @@
/*
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-10-28 luhuadong first version
*/
#ifndef __LED_H__
#define __LED_H__
#define LED_ON 1
#define LED_OFF 0
void led_init(void);
void led_set(rt_uint8_t val);
void led_toggle(void);
#endif /* __LED_H__ */
+63
View File
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-10-28 luhuadong first version
*/
#include <rtthread.h>
#include "led.h"
int main(void)
{
rt_kprintf("Hello, World!\n");
led_init();
while (1)
{
led_toggle();
rt_thread_mdelay(500);
}
return 0;
}
static void give_me_five(void)
{
rt_kprintf("\n");
rt_kprintf("\n");
rt_kprintf(" SIFIVE, INC.\n");
rt_kprintf("\n");
rt_kprintf(" 5555555555555555555555555\n");
rt_kprintf(" 5555 5555\n");
rt_kprintf(" 5555 5555\n");
rt_kprintf(" 5555 5555\n");
rt_kprintf(" 5555 5555555555555555555555\n");
rt_kprintf(" 5555 555555555555555555555555\n");
rt_kprintf(" 5555 5555\n");
rt_kprintf(" 5555 5555\n");
rt_kprintf(" 5555 5555\n");
rt_kprintf(" 5555555555555555555555555555 55555\n");
rt_kprintf(" 55555 555555555 55555\n");
rt_kprintf(" 55555 55555 55555\n");
rt_kprintf(" 55555 5 55555\n");
rt_kprintf(" 55555 55555\n");
rt_kprintf(" 55555 55555\n");
rt_kprintf(" 55555 55555\n");
rt_kprintf(" 55555 55555\n");
rt_kprintf(" 55555 55555\n");
rt_kprintf(" 555555555\n");
rt_kprintf(" 55555\n");
rt_kprintf(" 5\n");
rt_kprintf("\n");
rt_kprintf("\n");
rt_kprintf(" Welcome to SiFive!\n");
}
#ifdef FINSH_USING_MSH
MSH_CMD_EXPORT(give_me_five, Show the SiFive logo)
#endif
+14
View File
@@ -0,0 +1,14 @@
Import('RTT_ROOT')
Import('rtconfig')
from building import *
cwd = os.path.join(str(Dir('#')), 'drivers')
# add the general drvers.
src = Glob("*.c")
CPPPATH = [cwd]
group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH)
Return('group')
+92
View File
@@ -0,0 +1,92 @@
/*
* File : board.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
*/
#include <interrupt.h>
#include <rthw.h>
#include <board.h>
#include <platform.h>
#include <encoding.h>
#include <interrupt.h>
extern void use_default_clocks(void);
extern void use_pll(int refsel, int bypass, int r, int f, int q);
#define TICK_COUNT (RTC_FREQ / RT_TICK_PER_SECOND)
#define MTIME (*((volatile uint64_t *)(CLINT_CTRL_ADDR + CLINT_MTIME)))
#define MTIMECMP (*((volatile uint64_t *)(CLINT_CTRL_ADDR + CLINT_MTIMECMP)))
/* system tick interrupt */
void handle_m_time_interrupt()
{
MTIMECMP = MTIME + TICK_COUNT;
rt_tick_increase();
}
/* fixed misaligned bug for qemu */
void *__wrap_memset(void *s, int c, size_t n)
{
return rt_memset(s, c, n);
}
static void rt_hw_clock_init(void)
{
use_default_clocks();
use_pll(0, 0, 1, 31, 1);
}
static void rt_hw_timer_init(void)
{
MTIMECMP = MTIME + TICK_COUNT;
/* enable timer interrupt*/
set_csr(mie, MIP_MTIP);
}
void rt_hw_board_init(void)
{
/* initialize the system clock */
rt_hw_clock_init();
/* initialize hardware interrupt */
rt_hw_interrupt_init();
/* initialize timer0 */
rt_hw_timer_init();
#ifdef RT_USING_HEAP
rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
#endif
#ifdef RT_USING_COMPONENTS_INIT
rt_components_board_init();
#endif
#ifdef RT_USING_CONSOLE
rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif
return;
}
+32
View File
@@ -0,0 +1,32 @@
/*
* File : board.h
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
*/
#ifndef __BOARD__
#define __BOARD__
extern void *_end;
extern void *_heap_end;
#define HEAP_BEGIN &_end
#define HEAP_END &_heap_end
#endif
+125
View File
@@ -0,0 +1,125 @@
/*
* File : drv_usart.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
*/
#include <rtdevice.h>
#include <encoding.h>
#include <platform.h>
#include <interrupt.h>
static void usart_handler(int vector, void *param)
{
rt_hw_serial_isr((struct rt_serial_device *)param, RT_SERIAL_EVENT_RX_IND);
}
static rt_err_t usart_configure(struct rt_serial_device *serial,
struct serial_configure *cfg)
{
RT_ASSERT(serial != RT_NULL);
RT_ASSERT(cfg != RT_NULL);
GPIO_REG(GPIO_IOF_SEL) &= ~IOF0_UART0_MASK;
GPIO_REG(GPIO_IOF_EN) |= IOF0_UART0_MASK;
UART0_REG(UART_REG_DIV) = get_cpu_freq() / cfg->baud_rate - 1;
UART0_REG(UART_REG_TXCTRL) |= UART_TXEN;
UART0_REG(UART_REG_RXCTRL) |= UART_RXEN;
UART0_REG(UART_REG_IE) = UART_IP_RXWM;
return RT_EOK;
}
static rt_err_t usart_control(struct rt_serial_device *serial,
int cmd, void *arg)
{
RT_ASSERT(serial != RT_NULL);
switch (cmd)
{
case RT_DEVICE_CTRL_CLR_INT:
break;
case RT_DEVICE_CTRL_SET_INT:
break;
}
return RT_EOK;
}
static int usart_putc(struct rt_serial_device *serial, char c)
{
while (UART0_REG(UART_REG_TXFIFO) & 0x80000000) ;
UART0_REG(UART_REG_TXFIFO) = c;
return 0;
}
static int usart_getc(struct rt_serial_device *serial)
{
rt_int32_t val = UART0_REG(UART_REG_RXFIFO);
if (val > 0)
return (rt_uint8_t)val;
else
return -1;
}
static struct rt_uart_ops ops =
{
usart_configure,
usart_control,
usart_putc,
usart_getc,
};
static struct rt_serial_device serial =
{
.ops = &ops,
.config.baud_rate = BAUD_RATE_115200,
.config.bit_order = BIT_ORDER_LSB,
.config.data_bits = DATA_BITS_8,
.config.parity = PARITY_NONE,
.config.stop_bits = STOP_BITS_1,
.config.invert = NRZ_NORMAL,
.config.bufsz = RT_SERIAL_RB_BUFSZ,
};
int rt_hw_uart_init(void)
{
rt_hw_serial_register(
&serial,
"dusart",
RT_DEVICE_FLAG_STREAM
| RT_DEVICE_FLAG_RDWR
| RT_DEVICE_FLAG_INT_RX, RT_NULL);
rt_hw_interrupt_install(
INT_UART0_BASE,
usart_handler,
(void *) & (serial.parent),
"uart interrupt");
rt_hw_interrupt_unmask(INT_UART0_BASE);
return 0;
}
INIT_BOARD_EXPORT(rt_hw_uart_init);
+158
View File
@@ -0,0 +1,158 @@
/*
* File : interrupt.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2018, RT-Thread Development Team
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
*/
#include <rthw.h>
#include <plic_driver.h>
#include <platform.h>
#include <encoding.h>
#include <interrupt.h>
#define MAX_HANDLERS PLIC_NUM_INTERRUPTS
/* exception and interrupt handler table */
static struct rt_irq_desc irq_desc[MAX_HANDLERS];
static plic_instance_t g_plic;
/**
* This function will mask a interrupt.
* @param vector the interrupt number
*/
void rt_hw_interrupt_mask(int irq)
{
PLIC_disable_interrupt(&g_plic, irq);
}
/**
* This function will un-mask a interrupt.
* @param vector the interrupt number
*/
void rt_hw_interrupt_unmask(int irq)
{
PLIC_enable_interrupt(&g_plic, irq);
PLIC_set_priority(&g_plic, irq, 1);
}
rt_isr_handler_t rt_hw_interrupt_handle(rt_uint32_t vector, void *param)
{
rt_kprintf("UN-handled interrupt %d occurred!!!\n", vector);
return RT_NULL;
}
void rt_hw_interrupt_init(void)
{
int idx;
/* config interrupt vector*/
asm volatile(
"la t0, trap_entry\n"
"csrw mtvec, t0"
);
/* enable global interrupt*/
PLIC_init(&g_plic,
PLIC_CTRL_ADDR,
PLIC_NUM_INTERRUPTS,
PLIC_NUM_PRIORITIES);
/* init exceptions table */
for (idx = 0; idx < MAX_HANDLERS; idx++)
{
rt_hw_interrupt_mask(idx);
irq_desc[idx].handler = (rt_isr_handler_t)rt_hw_interrupt_handle;
irq_desc[idx].param = RT_NULL;
#ifdef RT_USING_INTERRUPT_INFO
rt_snprintf(irq_desc[idx].name, RT_NAME_MAX - 1, "default");
irq_desc[idx].counter = 0;
#endif
}
// enable machine external interrupt
set_csr(mie, MIP_MEIP);
}
rt_uint32_t rt_hw_interrupt_get_active(rt_uint32_t fiq_irq)
{
return (rt_uint32_t)PLIC_claim_interrupt(&g_plic);;
}
void rt_hw_interrupt_ack(rt_uint32_t fiq_irq, rt_uint32_t id)
{
PLIC_complete_interrupt(&g_plic, id);
}
/**
* This function will install a interrupt service routine to a interrupt.
* @param vector the interrupt number
* @param handler the interrupt service routine to be installed
* @param param the interrupt service function parameter
* @param name the interrupt name
* @return old handler
*/
rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
void *param, const char *name)
{
rt_isr_handler_t old_handler = RT_NULL;
if(vector < MAX_HANDLERS)
{
old_handler = irq_desc[vector].handler;
if (handler != RT_NULL)
{
irq_desc[vector].handler = (rt_isr_handler_t)handler;
irq_desc[vector].param = param;
#ifdef RT_USING_INTERRUPT_INFO
rt_snprintf(irq_desc[vector].name, RT_NAME_MAX - 1, "%s", name);
irq_desc[vector].counter = 0;
#endif
}
}
return old_handler;
}
/**
* This function will be call when external machine-level
* interrupt from PLIC occurred.
*/
void handle_m_ext_interrupt(void)
{
rt_isr_handler_t isr_func;
rt_uint32_t irq;
void *param;
/* get irq number */
irq = rt_hw_interrupt_get_active(0);
/* get interrupt service routine */
isr_func = irq_desc[irq].handler;
param = irq_desc[irq].param;
/* turn to interrupt service routine */
isr_func(irq, param);
rt_hw_interrupt_ack(0, irq);
#ifdef RT_USING_INTERRUPT_INFO
irq_desc[irq].counter ++;
#endif
}
+37
View File
@@ -0,0 +1,37 @@
/*
* File : interrupt.h
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2018, RT-Thread Development Team
*
* 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 2 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, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
*/
#ifndef __INTERRUPT_H__
#define __INTERRUPT_H__
#include <rthw.h>
void rt_hw_interrupt_mask(int irq);
void rt_hw_interrupt_unmask(int irq);
rt_isr_handler_t rt_hw_interrupt_handle(rt_uint32_t vector, void *param);
void rt_hw_interrupt_init(void);
rt_uint32_t rt_hw_interrupt_get_active(rt_uint32_t fiq_irq);
void rt_hw_interrupt_ack(rt_uint32_t fiq_irq, rt_uint32_t id);
rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
void *param, const char *name);
#endif
Binary file not shown.

After

Width:  |  Height:  |  Size: 255 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

+206
View File
@@ -0,0 +1,206 @@
This software, except as otherwise noted in subrepositories,
is licensed under the Apache 2 license, quoted below.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2016 SiFive, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+143
View File
@@ -0,0 +1,143 @@
# README #
This repository, maintained by SiFive, Inc, makes it easy to get started developing software for the Freedom E RISC-V platform.
### Contents ###
* RISC-V Software Toolchain
* RISC-V Debugging Toolchain
* Board Support Packages for FE310 and Development Kits
* A Few Example Programs
### Setting up the SDK ###
First, clone this repository:
```
git clone --recursive https://github.com/sifive/freedom-e-sdk.git
```
To see Makefile options:
```
cd freedom-e-sdk
make help
```
#### Building Tools from Source ####
Ubuntu packages needed:
$ sudo apt-get install autoconf automake libmpc-dev libmpfr-dev libgmp-dev gawk bison flex texinfo libtool libusb-1.0-0-dev make g++ pkg-config libexpat1-dev zlib1g-dev
Next, build the tools:
```
cd freedom-e-sdk
make tools [BOARD=freedom-e300-hifive1]
```
If your machine has enough resources, you can speed up the build process by adding `-j n` to `make`, where `n` is the number of processors of your build system.
#### Using Pre-Built Binary Tools ####
If you would like to avoid compiling the tools from source, they are
available as pre-built binaries from
https://sifive.com/products/tools
For OpenOCD and/or RISC-V GNU Toolchain,
download the .tar.gz for your platform, and unpack it to
your desired location. Then, use the `RISC_PATH` and `RISCV_OPENOCD_PATH`
variables when attempting to use the tools:
```
cp openocd-<date>-<platform>.tar.gz /my/desired/location/
cp riscv64-unknown-elf-gcc-<date>-<platform>.tar.gz /my/desired/location
cd /my/desired/location
tar -xvf openocd-<date>-<platform>.tar.gz
tar -xvf riscv64-unknown-elf-gcc-<date>-<platform>.tar.gz
export RISCV_OPENOCD_PATH=/my/desired/location/openocd
export RISCV_PATH=/my/desired/location/riscv64-unknown-elf-gcc-<date>-<version>
```
### Updating your SDK ###
If you'd like to update your SDK to the latest version:
```
cd freedom-e-sdk
git pull origin master
git submodule update --init --recursive
```
If you would like to recompile the entire toolchain after performing the above:
```
make uninstall
make tools
```
### Using the Tools ###
To compile a bare-metal RISC-V program:
```
cd freedom-e-sdk
make software [PROGRAM=demo_gpio] [BOARD=freedom-e300-hifive1]
```
Run `make help` for more commands.
### Benchmarking ###
#### Dhrystone ####
After setting up the software and debug toolchains, you can build and
execute everyone's favorite benchmark as follows:
- Compile the benchmark with the command `make software PROGRAM=dhrystone`.
- Run on the HiFive1 board with the command `make upload PROGRAM=dhrystone`.
This will take a few minutes. Sample output is provided below.
- Compute DMIPS by dividing the Dhrystones per Second result by 1757, which
was the VAX 11/780's performance. In the example below, 729927 / 1757 =
415 DMIPS.
- Compute DMIPS/MHz by dividing by the clock rate: in the example below,
415 / 260 = 1.60 DMIPS/MHz.
```
core freq at 259830579 Hz
Dhrystone Benchmark, Version 2.1 (Language: C)
<snip>
Microseconds for one run through Dhrystone: 1.3
Dhrystones per Second: 729927.0
```
#### CoreMark ####
We cannot distribute the CoreMark benchmark, but following are instructions
to download and run the benchmark on the HiFive1 board:
- Download CoreMark from EEMBC's web site and extract the archive from
http://www.eembc.org/coremark/download.php.
- Copy the following files from the extracted archive into the
`software/coremark` directory in this repository:
- `core_list_join.c`
- `core_main.c`
- `coremark.h`
- `core_matrix.c`
- `core_state.c`
- `core_util.c`
- Compile the benchmark with the command `make software PROGRAM=coremark`.
- Run on the HiFive1 board with the command `make upload PROGRAM=coremark`.
- Divide the reported Iterations/Sec by the reported core frequency in MHz to
obtain a CoreMarks/MHz value.
### For More Information ###
Documentation, Forums, and much more available at
[dev.sifive.com](https://dev.sifive.com)
@@ -0,0 +1,20 @@
# RT-Thread building script for component
Import('rtconfig')
Import('RTT_ROOT')
from building import *
cwd = GetCurrentDir()
src = [ 'bsp/drivers/plic/plic_driver.c',
'bsp/env/start.S',
'bsp/env/freedom-e300-hifive1/init.c']
CPPPATH = [ cwd + '/bsp/drivers', cwd + '/bsp/drivers/fe300prci', cwd + '/bsp/drivers/plic',
cwd + '/bsp/env', cwd + '/bsp/env/freedom-e300-hifive1',
cwd + '/bsp/include', cwd + '/bsp/include/sifive', cwd + '/bsp/include/sifive/devices']
CPPDEFINES = []
group = DefineGroup('Libraries', src, depend = [''], CPPPATH = CPPPATH, CPPDEFINES=CPPDEFINES)
Return('group')
@@ -0,0 +1,252 @@
// See LICENSE file for license details
#include "platform.h"
#ifdef PRCI_CTRL_ADDR
#include "fe300prci/fe300prci_driver.h"
#include <unistd.h>
#define rdmcycle(x) { \
uint32_t lo, hi, hi2; \
__asm__ __volatile__ ("1:\n\t" \
"csrr %0, mcycleh\n\t" \
"csrr %1, mcycle\n\t" \
"csrr %2, mcycleh\n\t" \
"bne %0, %2, 1b\n\t" \
: "=r" (hi), "=r" (lo), "=r" (hi2)) ; \
*(x) = lo | ((uint64_t) hi << 32); \
}
uint32_t PRCI_measure_mcycle_freq(uint32_t mtime_ticks, uint32_t mtime_freq)
{
uint32_t start_mtime = CLINT_REG(CLINT_MTIME);
uint32_t end_mtime = start_mtime + mtime_ticks + 1;
// Make sure we won't get rollover.
while (end_mtime < start_mtime){
start_mtime = CLINT_REG(CLINT_MTIME);
end_mtime = start_mtime + mtime_ticks + 1;
}
// Don't start measuring until mtime edge.
uint32_t tmp = start_mtime;
do {
start_mtime = CLINT_REG(CLINT_MTIME);
} while (start_mtime == tmp);
uint64_t start_mcycle;
rdmcycle(&start_mcycle);
while (CLINT_REG(CLINT_MTIME) < end_mtime) ;
uint64_t end_mcycle;
rdmcycle(&end_mcycle);
uint32_t difference = (uint32_t) (end_mcycle - start_mcycle);
uint64_t freq = ((uint64_t) difference * mtime_freq) / mtime_ticks;
return (uint32_t) freq & 0xFFFFFFFF;
}
void PRCI_use_hfrosc(int div, int trim)
{
// Make sure the HFROSC is running at its default setting
// It is OK to change this even if we are running off of it.
PRCI_REG(PRCI_HFROSCCFG) = (ROSC_DIV(div) | ROSC_TRIM(trim) | ROSC_EN(1));
while ((PRCI_REG(PRCI_HFROSCCFG) & ROSC_RDY(1)) == 0);
PRCI_REG(PRCI_PLLCFG) &= ~PLL_SEL(1);
}
void PRCI_use_pll(int refsel, int bypass,
int r, int f, int q, int finaldiv,
int hfroscdiv, int hfrosctrim)
{
// Ensure that we aren't running off the PLL before we mess with it.
if (PRCI_REG(PRCI_PLLCFG) & PLL_SEL(1)) {
// Make sure the HFROSC is running at its default setting
PRCI_use_hfrosc(4, 16);
}
// Set PLL Source to be HFXOSC if desired.
uint32_t config_value = 0;
config_value |= PLL_REFSEL(refsel);
if (bypass) {
// Bypass
config_value |= PLL_BYPASS(1);
PRCI_REG(PRCI_PLLCFG) = config_value;
// If we don't have an HFXTAL, this doesn't really matter.
// Set our Final output divide to divide-by-1:
PRCI_REG(PRCI_PLLDIV) = (PLL_FINAL_DIV_BY_1(1) | PLL_FINAL_DIV(0));
} else {
// To overclock, use the hfrosc
if (hfrosctrim >= 0 && hfroscdiv >= 0) {
PRCI_use_hfrosc(hfroscdiv, hfrosctrim);
}
// Set DIV Settings for PLL
// (Legal values of f_REF are 6-48MHz)
// Set DIVR to divide-by-2 to get 8MHz frequency
// (legal values of f_R are 6-12 MHz)
config_value |= PLL_BYPASS(1);
config_value |= PLL_R(r);
// Set DIVF to get 512Mhz frequncy
// There is an implied multiply-by-2, 16Mhz.
// So need to write 32-1
// (legal values of f_F are 384-768 MHz)
config_value |= PLL_F(f);
// Set DIVQ to divide-by-2 to get 256 MHz frequency
// (legal values of f_Q are 50-400Mhz)
config_value |= PLL_Q(q);
// Set our Final output divide to divide-by-1:
if (finaldiv == 1){
PRCI_REG(PRCI_PLLDIV) = (PLL_FINAL_DIV_BY_1(1) | PLL_FINAL_DIV(0));
} else {
PRCI_REG(PRCI_PLLDIV) = (PLL_FINAL_DIV(finaldiv-1));
}
PRCI_REG(PRCI_PLLCFG) = config_value;
// Un-Bypass the PLL.
PRCI_REG(PRCI_PLLCFG) &= ~PLL_BYPASS(1);
// Wait for PLL Lock
// Note that the Lock signal can be glitchy.
// Need to wait 100 us
// RTC is running at 32kHz.
// So wait 4 ticks of RTC.
uint32_t now = CLINT_REG(CLINT_MTIME);
while (CLINT_REG(CLINT_MTIME) - now < 4) ;
// Now it is safe to check for PLL Lock
while ((PRCI_REG(PRCI_PLLCFG) & PLL_LOCK(1)) == 0);
}
// Switch over to PLL Clock source
PRCI_REG(PRCI_PLLCFG) |= PLL_SEL(1);
// If we're running off HFXOSC, turn off the HFROSC to
// save power.
if (refsel) {
PRCI_REG(PRCI_HFROSCCFG) &= ~ROSC_EN(1);
}
}
void PRCI_use_default_clocks()
{
// Turn off the LFROSC
AON_REG(AON_LFROSC) &= ~ROSC_EN(1);
// Use HFROSC
PRCI_use_hfrosc(4, 16);
}
void PRCI_use_hfxosc(uint32_t finaldiv)
{
PRCI_use_pll(1, // Use HFXTAL
1, // Bypass = 1
0, // PLL settings don't matter
0, // PLL settings don't matter
0, // PLL settings don't matter
finaldiv,
-1,
-1);
}
// This is a generic function, which
// doesn't span the entire range of HFROSC settings.
// It only adjusts the trim, which can span a hundred MHz or so.
// This function does not check the legality of the PLL settings
// at all, and it is quite possible to configure invalid PLL settings
// this way.
// It returns the actual measured CPU frequency.
uint32_t PRCI_set_hfrosctrim_for_f_cpu(uint32_t f_cpu, PRCI_freq_target target )
{
uint32_t hfrosctrim = 0;
uint32_t hfroscdiv = 4;
uint32_t prev_trim = 0;
// In this function we use PLL settings which
// will give us a 32x multiplier from the output
// of the HFROSC source to the output of the
// PLL. We first measure our HFROSC to get the
// right trim, then finally use it as the PLL source.
// We should really check here that the f_cpu
// requested is something in the limit of the PLL. For
// now that is up to the user.
// This will undershoot for frequencies not divisible by 16.
uint32_t desired_hfrosc_freq = (f_cpu/ 16);
PRCI_use_hfrosc(hfroscdiv, hfrosctrim);
// Ignore the first run (for icache reasons)
uint32_t cpu_freq = PRCI_measure_mcycle_freq(3000, RTC_FREQ);
cpu_freq = PRCI_measure_mcycle_freq(3000, RTC_FREQ);
uint32_t prev_freq = cpu_freq;
while ((cpu_freq < desired_hfrosc_freq) && (hfrosctrim < 0x1F)){
prev_trim = hfrosctrim;
prev_freq = cpu_freq;
hfrosctrim ++;
PRCI_use_hfrosc(hfroscdiv, hfrosctrim);
cpu_freq = PRCI_measure_mcycle_freq(3000, RTC_FREQ);
}
// We couldn't go low enough
if (prev_freq > desired_hfrosc_freq){
PRCI_use_pll(0, 0, 1, 31, 1, 1, hfroscdiv, prev_trim);
cpu_freq = PRCI_measure_mcycle_freq(1000, RTC_FREQ);
return cpu_freq;
}
// We couldn't go high enough
if (cpu_freq < desired_hfrosc_freq){
PRCI_use_pll(0, 0, 1, 31, 1, 1, hfroscdiv, prev_trim);
cpu_freq = PRCI_measure_mcycle_freq(1000, RTC_FREQ);
return cpu_freq;
}
// Check for over/undershoot
switch(target) {
case(PRCI_FREQ_CLOSEST):
if ((desired_hfrosc_freq - prev_freq) < (cpu_freq - desired_hfrosc_freq)) {
PRCI_use_pll(0, 0, 1, 31, 1, 1, hfroscdiv, prev_trim);
} else {
PRCI_use_pll(0, 0, 1, 31, 1, 1, hfroscdiv, hfrosctrim);
}
break;
case(PRCI_FREQ_UNDERSHOOT):
PRCI_use_pll(0, 0, 1, 31, 1, 1, hfroscdiv, prev_trim);
break;
default:
PRCI_use_pll(0, 0, 1, 31, 1, 1, hfroscdiv, hfrosctrim);
}
cpu_freq = PRCI_measure_mcycle_freq(1000, RTC_FREQ);
return cpu_freq;
}
#endif
@@ -0,0 +1,79 @@
// See LICENSE file for license details
#ifndef _FE300PRCI_DRIVER_H_
#define _FE300PRCI_DRIVER_H_
//__BEGIN_DECLS
#include <unistd.h>
typedef enum prci_freq_target {
PRCI_FREQ_OVERSHOOT,
PRCI_FREQ_CLOSEST,
PRCI_FREQ_UNDERSHOOT
} PRCI_freq_target;
/* Measure and return the approximate frequency of the
* CPU, as given by measuring the mcycle counter against
* the mtime ticks.
*/
uint32_t PRCI_measure_mcycle_freq(uint32_t mtime_ticks, uint32_t mtime_freq);
/* Safely switch over to the HFROSC using the given div
* and trim settings.
*/
void PRCI_use_hfrosc(int div, int trim);
/* Safely switch over to the 16MHz HFXOSC,
* applying the finaldiv clock divider (1 is the lowest
* legal value).
*/
void PRCI_use_hfxosc(uint32_t finaldiv);
/* Safely switch over to the PLL using the given
* settings.
*
* Note that not all combinations of the inputs are actually
* legal, and this function does not check for their
* legality ("safely" means that this function won't turn off
* or glitch the clock the CPU is actually running off, but
* doesn't protect against you making it too fast or slow.)
*/
void PRCI_use_pll(int refsel, int bypass,
int r, int f, int q, int finaldiv,
int hfroscdiv, int hfrosctrim);
/* Use the default clocks configured at reset.
* This is ~16Mhz HFROSC and turns off the LFROSC
* (on the current FE310 Dev Platforms, an external LFROSC is
* used as it is more power efficient).
*/
void PRCI_use_default_clocks();
/* This routine will adjust the HFROSC trim
* while using HFROSC as the clock source,
* measure the resulting frequency, then
* use it as the PLL clock source,
* in an attempt to get over, under, or close to the
* requested frequency. It returns the actual measured
* frequency.
*
* Note that the requested frequency must be within the
* range supported by the PLL so not all values are
* achievable with this function, and not all
* are guaranteed to actually work. The PLL
* is rated higher than the hardware.
*
* There is no check on the desired f_cpu frequency, it
* is up to the user to specify something reasonable.
*/
uint32_t PRCI_set_hfrosctrim_for_f_cpu(uint32_t f_cpu, PRCI_freq_target target);
//__END_DECLS
#endif
@@ -0,0 +1,127 @@
// See LICENSE for license details.
#include "sifive/devices/plic.h"
#include "plic/plic_driver.h"
#include "platform.h"
#include "encoding.h"
#include <string.h>
// Note that there are no assertions or bounds checking on these
// parameter values.
void volatile_memzero(uint8_t * base, unsigned int size)
{
volatile uint8_t * ptr;
for (ptr = base; ptr < (base + size); ptr++){
*ptr = 0;
}
}
void PLIC_init (
plic_instance_t * this_plic,
uintptr_t base_addr,
uint32_t num_sources,
uint32_t num_priorities
)
{
this_plic->base_addr = base_addr;
this_plic->num_sources = num_sources;
this_plic->num_priorities = num_priorities;
// Disable all interrupts (don't assume that these registers are reset).
unsigned long hart_id = read_csr(mhartid);
volatile_memzero((uint8_t*) (this_plic->base_addr +
PLIC_ENABLE_OFFSET +
(hart_id << PLIC_ENABLE_SHIFT_PER_TARGET)),
(num_sources + 8) / 8);
// Set all priorities to 0 (equal priority -- don't assume that these are reset).
volatile_memzero ((uint8_t *)(this_plic->base_addr +
PLIC_PRIORITY_OFFSET),
(num_sources + 1) << PLIC_PRIORITY_SHIFT_PER_SOURCE);
// Set the threshold to 0.
volatile plic_threshold* threshold = (plic_threshold*)
(this_plic->base_addr +
PLIC_THRESHOLD_OFFSET +
(hart_id << PLIC_THRESHOLD_SHIFT_PER_TARGET));
*threshold = 0;
}
void PLIC_set_threshold (plic_instance_t * this_plic,
plic_threshold threshold){
unsigned long hart_id = read_csr(mhartid);
volatile plic_threshold* threshold_ptr = (plic_threshold*) (this_plic->base_addr +
PLIC_THRESHOLD_OFFSET +
(hart_id << PLIC_THRESHOLD_SHIFT_PER_TARGET));
*threshold_ptr = threshold;
}
void PLIC_enable_interrupt (plic_instance_t * this_plic, plic_source source){
unsigned long hart_id = read_csr(mhartid);
volatile uint8_t * current_ptr = (volatile uint8_t *)(this_plic->base_addr +
PLIC_ENABLE_OFFSET +
(hart_id << PLIC_ENABLE_SHIFT_PER_TARGET) +
(source >> 3));
uint8_t current = *current_ptr;
current = current | ( 1 << (source & 0x7));
*current_ptr = current;
}
void PLIC_disable_interrupt (plic_instance_t * this_plic, plic_source source){
unsigned long hart_id = read_csr(mhartid);
volatile uint8_t * current_ptr = (volatile uint8_t *) (this_plic->base_addr +
PLIC_ENABLE_OFFSET +
(hart_id << PLIC_ENABLE_SHIFT_PER_TARGET) +
(source >> 3));
uint8_t current = *current_ptr;
current = current & ~(( 1 << (source & 0x7)));
*current_ptr = current;
}
void PLIC_set_priority (plic_instance_t * this_plic, plic_source source, plic_priority priority){
if (this_plic->num_priorities > 0) {
volatile plic_priority * priority_ptr = (volatile plic_priority *)
(this_plic->base_addr +
PLIC_PRIORITY_OFFSET +
(source << PLIC_PRIORITY_SHIFT_PER_SOURCE));
*priority_ptr = priority;
}
}
plic_source PLIC_claim_interrupt(plic_instance_t * this_plic){
unsigned long hart_id = read_csr(mhartid);
volatile plic_source * claim_addr = (volatile plic_source * )
(this_plic->base_addr +
PLIC_CLAIM_OFFSET +
(hart_id << PLIC_CLAIM_SHIFT_PER_TARGET));
return *claim_addr;
}
void PLIC_complete_interrupt(plic_instance_t * this_plic, plic_source source){
unsigned long hart_id = read_csr(mhartid);
volatile plic_source * claim_addr = (volatile plic_source *) (this_plic->base_addr +
PLIC_CLAIM_OFFSET +
(hart_id << PLIC_CLAIM_SHIFT_PER_TARGET));
*claim_addr = source;
}
@@ -0,0 +1,51 @@
// See LICENSE file for licence details
#ifndef PLIC_DRIVER_H
#define PLIC_DRIVER_H
//__BEGIN_DECLS
#include "platform.h"
typedef struct __plic_instance_t
{
uintptr_t base_addr;
uint32_t num_sources;
uint32_t num_priorities;
} plic_instance_t;
typedef uint32_t plic_source;
typedef uint32_t plic_priority;
typedef uint32_t plic_threshold;
void PLIC_init (
plic_instance_t * this_plic,
uintptr_t base_addr,
uint32_t num_sources,
uint32_t num_priorities
);
void PLIC_set_threshold (plic_instance_t * this_plic,
plic_threshold threshold);
void PLIC_enable_interrupt (plic_instance_t * this_plic,
plic_source source);
void PLIC_disable_interrupt (plic_instance_t * this_plic,
plic_source source);
void PLIC_set_priority (plic_instance_t * this_plic,
plic_source source,
plic_priority priority);
plic_source PLIC_claim_interrupt(plic_instance_t * this_plic);
void PLIC_complete_interrupt(plic_instance_t * this_plic,
plic_source source);
//__END_DECLS
#endif
@@ -0,0 +1,102 @@
// See LICENSE for license details.
#ifndef _SIFIVE_COREPLEXIP_ARTY_H
#define _SIFIVE_COREPLEXIP_ARTY_H
#include <stdint.h>
/****************************************************************************
* GPIO Connections
*****************************************************************************/
// These are the GPIO bit offsets for the directly driven
// RGB LEDs on the Freedom Exx Coreplex IP Evaluation Arty FPGA Dev Kit.
// Additional RGB LEDs are driven by the 3 PWM outputs.
#define RED_LED_OFFSET 0
#define GREEN_LED_OFFSET 1
#define BLUE_LED_OFFSET 2
// Switch 3 is used as a GPIO input. (Switch 0 is used to set
// the reset vector, the other switches are unused).
#define SW_3_OFFSET 3
// These are the buttons which are mapped as inputs.
#define HAS_BOARD_BUTTONS
#define BUTTON_0_OFFSET 4
#define BUTTON_1_OFFSET 5
#define BUTTON_2_OFFSET 6
#define BUTTON_3_OFFSET 7
// These are the bit offsets for the different GPIO pins
// mapped onto the PMOD A header.
#define JA_0_OFFSET 8
#define JA_1_OFFSET 9
#define JA_2_OFFSET 10
#define JA_3_OFFSET 11
#define JA_4_OFFSET 12
#define JA_5_OFFSET 13
#define JA_6_OFFSET 14
#define JA_7_OFFSET 15
// The below gives a mapping between global interrupt
// sources and their number. Note that on the coreplex
// deliverable, the io_global_interrupts go directly into
// the PLIC. The evaluation image on the FPGA mimics a
// system with peripheral devices which are driving the
// global interrupt lines.
// So, on this image, in order to get an interrupt from
// e.g. pressing BUTTON_0:
// 1) Steps which are external to the delivery coreplex:
// a) The corresponding GPIO pin must be configured as in input
// b) The "interrupt on fall" bit must be set for the GPIO pin
// 2) Steps which would also need to be performed for the delivery coreplex:
// a) The corresponding global interrupt, priority, and threshold must be configured in the PLIC.
// b) The external interrupt bit must be enabled in MSTATUS
// c) Interrupts must be enabled globally in the core.
// Any of the above GPIO pins can be used as global interrupt
// sources by adding their offset to the INT_GPIO_BASE.
// For example, the buttons are shown here:
#define INT_DEVICE_BUTTON_0 (GPIO_INT_BASE + BUTTON_0_OFFSET)
#define INT_DEVICE_BUTTON_1 (GPIO_INT_BASE + BUTTON_1_OFFSET)
#define INT_DEVICE_BUTTON_2 (GPIO_INT_BASE + BUTTON_2_OFFSET)
#define INT_DEVICE_BUTTON_3 (GPIO_INT_BASE + BUTTON_3_OFFSET)
// In addition, the Switches are mapped directly to
// the PLIC (without going through the GPIO Peripheral).
#define INT_EXT_DEVICE_SW_0 (EXTERNAL_INT_BASE + 0)
#define INT_EXT_DEVICE_SW_1 (EXTERNAL_INT_BASE + 1)
#define INT_EXT_DEVICE_SW_2 (EXTERNAL_INT_BASE + 2)
#define INT_EXT_DEVICE_SW_3 (EXTERNAL_INT_BASE + 3)
// This gives the mapping from inputs to LOCAL interrupts.
#define LOCAL_INT_SW_0 0
#define LOCAL_INT_SW_1 1
#define LOCAL_INT_SW_2 2
#define LOCAL_INT_SW_3 3
#define LOCAL_INT_BTN_0 4
#define LOCAL_INT_BTN_1 5
#define LOCAL_INT_BTN_2 6
#define LOCAL_INT_BTN_3 7
#define LOCAL_INT_JA_0 8
#define LOCAL_INT_JA_1 9
#define LOCAL_INT_JA_2 10
#define LOCAL_INT_JA_3 11
#define LOCAL_INT_JA_4 12
#define LOCAL_INT_JA_5 13
#define LOCAL_INT_JA_6 14
#define LOCAL_INT_JA_7 15
#define RTC_FREQ 32768
void write_hex(int fd, unsigned long int hex);
#endif /* _SIFIVE_COREPLEXIP_ARTY_H */
@@ -0,0 +1,185 @@
OUTPUT_ARCH( "riscv" )
ENTRY( _start )
MEMORY
{
flash (rxai!w) : ORIGIN = 0x40400000, LENGTH = 512M
ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = 16K
}
PHDRS
{
flash PT_LOAD;
ram_init PT_LOAD;
ram PT_NULL;
}
SECTIONS
{
__stack_size = DEFINED(__stack_size) ? __stack_size : 2K;
.init :
{
KEEP (*(SORT_NONE(.init)))
} >flash AT>flash :flash
.text :
{
*(.text.unlikely .text.unlikely.*)
*(.text.startup .text.startup.*)
*(.text .text.*)
*(.gnu.linkonce.t.*)
/* section information for finsh shell */
. = ALIGN(4);
__fsymtab_start = .;
KEEP(*(FSymTab))
__fsymtab_end = .;
. = ALIGN(4);
__vsymtab_start = .;
KEEP(*(VSymTab))
__vsymtab_end = .;
. = ALIGN(4);
. = ALIGN(4);
__rt_init_start = .;
KEEP(*(SORT(.rti_fn*)))
__rt_init_end = .;
. = ALIGN(4);
/* section information for modules */
. = ALIGN(4);
__rtmsymtab_start = .;
KEEP(*(RTMSymTab))
__rtmsymtab_end = .;
} >flash AT>flash :flash
.fini :
{
KEEP (*(SORT_NONE(.fini)))
} >flash AT>flash :flash
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata :
{
*(.rdata)
*(.rodata .rodata.*)
*(.gnu.linkonce.r.*)
} >flash AT>flash :flash
. = ALIGN(4);
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >flash AT>flash :flash
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
} >flash AT>flash :flash
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
} >flash AT>flash :flash
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
} >flash AT>flash :flash
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
} >flash AT>flash :flash
.lalign :
{
. = ALIGN(4);
PROVIDE( _data_lma = . );
} >flash AT>flash :flash
.dalign :
{
. = ALIGN(4);
PROVIDE( _data = . );
} >ram AT>flash :ram_init
.data :
{
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.*)
*(.gnu.linkonce.s.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
} >ram AT>flash :ram_init
. = ALIGN(4);
PROVIDE( _edata = . );
PROVIDE( edata = . );
PROVIDE( _fbss = . );
PROVIDE( __bss_start = . );
.bss :
{
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
} >ram AT>ram :ram
. = ALIGN(8);
PROVIDE( _end = . );
PROVIDE( end = . );
.stack ORIGIN(ram) + LENGTH(ram) - __stack_size :
{
PROVIDE( _heap_end = . );
. = __stack_size;
PROVIDE( _sp = . );
} >ram AT>ram :ram
}
@@ -0,0 +1,98 @@
//See LICENSE for license details.
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include "platform.h"
#include "encoding.h"
#define CPU_FREQ 65000000
#define XSTR(x) #x
#define STR(x) XSTR(x)
extern int main(int argc, char** argv);
extern void trap_entry();
static unsigned long get_cpu_freq()
{
return CPU_FREQ;
}
unsigned long get_timer_freq()
{
return get_cpu_freq();
}
uint64_t get_timer_value()
{
#if __riscv_xlen == 32
while (1) {
uint32_t hi = read_csr(mcycleh);
uint32_t lo = read_csr(mcycle);
if (hi == read_csr(mcycleh))
return ((uint64_t)hi << 32) | lo;
}
#else
return read_csr(mcycle);
#endif
}
static void uart_init(size_t baud_rate)
{
UART0_REG(UART_REG_DIV) = (get_cpu_freq() / 2) / baud_rate - 1;
UART0_REG(UART_REG_TXCTRL) |= UART_TXEN;
}
#ifdef USE_PLIC
extern void handle_m_ext_interrupt();
#endif
#ifdef USE_M_TIME
extern void handle_m_time_interrupt();
#endif
#ifdef USE_LOCAL_ISR
typedef void (*my_interrupt_function_ptr_t) (void);
extern my_interrupt_function_ptr_t localISR[];
#endif
uintptr_t handle_trap(uintptr_t mcause, uintptr_t epc)
{
if (0){
#ifdef USE_PLIC
// External Machine-Level interrupt from PLIC
} else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT)) {
handle_m_ext_interrupt();
#endif
#ifdef USE_M_TIME
// External Machine-Level interrupt from PLIC
} else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_TIMER)){
handle_m_time_interrupt();
#endif
#ifdef USE_LOCAL_ISR
} else if (mcause & MCAUSE_INT) {
localISR[mcause & MCAUSE_CAUSE] ();
#endif
}
else {
write(1, "Unhandled Trap:\n", 16);
_exit(1 + mcause);
}
return epc;
}
void _init()
{
#ifndef NO_INIT
uart_init(115200);
puts("core freq at " STR(CPU_FREQ) " Hz\n");
write_csr(mtvec, &trap_entry);
#endif
}
void _fini()
{
}
@@ -0,0 +1,31 @@
# JTAG adapter setup
adapter_khz 10000
interface ftdi
ftdi_device_desc "Olimex OpenOCD JTAG ARM-USB-TINY-H"
ftdi_vid_pid 0x15ba 0x002a
ftdi_layout_init 0x0808 0x0a1b
ftdi_layout_signal nSRST -oe 0x0200
#ftdi_layout_signal nTRST -data 0x0100 -oe 0x0100
ftdi_layout_signal LED -data 0x0800
set _CHIPNAME riscv
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000001
set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME
$_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1
# Un-comment these two flash lines if you have a SPI flash and want to write
# it.
flash bank spi0 fespi 0x40000000 0 0 0 $_TARGETNAME.0 0x20004000
init
if {[ info exists pulse_srst]} {
ftdi_set_signal nSRST 0
ftdi_set_signal nSRST z
}
halt
#flash protect 0 64 last off
echo "Ready for Remote Connections"
@@ -0,0 +1,90 @@
// See LICENSE for license details.
#ifndef _SIFIVE_PLATFORM_H
#define _SIFIVE_PLATFORM_H
// Some things missing from the official encoding.h
#if __riscv_xlen == 32
#define MCAUSE_INT 0x80000000UL
#define MCAUSE_CAUSE 0x7FFFFFFFUL
#else
#define MCAUSE_INT 0x8000000000000000UL
#define MCAUSE_CAUSE 0x7FFFFFFFFFFFFFFFUL
#endif
#define IRQ_M_LOCAL 16
#define MIP_MLIP(x) (1 << (IRQ_M_LOCAL + x))
#include "sifive/const.h"
#include "sifive/devices/clint.h"
#include "sifive/devices/gpio.h"
#include "sifive/devices/plic.h"
#include "sifive/devices/pwm.h"
#include "sifive/devices/spi.h"
#include "sifive/devices/uart.h"
/****************************************************************************
* Platform definitions
*****************************************************************************/
// Memory map
#define CLINT_CTRL_ADDR _AC(0x02000000,UL)
#define GPIO_CTRL_ADDR _AC(0x20002000,UL)
#define PLIC_CTRL_ADDR _AC(0x0C000000,UL)
#define PWM0_CTRL_ADDR _AC(0x20005000,UL)
#define RAM_MEM_ADDR _AC(0x80000000,UL)
#define RAM_MEM_SIZE _AC(0x10000,UL)
#define SPI0_CTRL_ADDR _AC(0x20004000,UL)
#define SPI0_MEM_ADDR _AC(0x40000000,UL)
#define SPI0_MEM_SIZE _AC(0x20000000,UL)
#define TESTBENCH_MEM_ADDR _AC(0x20000000,UL)
#define TESTBENCH_MEM_SIZE _AC(0x10000000,UL)
#define TRAPVEC_TABLE_CTRL_ADDR _AC(0x00001010,UL)
#define UART0_CTRL_ADDR _AC(0x20000000,UL)
// IOF masks
// Interrupt numbers
#define RESERVED_INT_BASE 0
#define UART0_INT_BASE 1
#define EXTERNAL_INT_BASE 2
#define SPI0_INT_BASE 6
#define GPIO_INT_BASE 7
#define PWM0_INT_BASE 23
// Helper functions
#define _REG64(p, i) (*(volatile uint64_t *)((p) + (i)))
#define _REG32(p, i) (*(volatile uint32_t *)((p) + (i)))
#define _REG16(p, i) (*(volatile uint16_t *)((p) + (i)))
// Bulk set bits in `reg` to either 0 or 1.
// E.g. SET_BITS(MY_REG, 0x00000007, 0) would generate MY_REG &= ~0x7
// E.g. SET_BITS(MY_REG, 0x00000007, 1) would generate MY_REG |= 0x7
#define SET_BITS(reg, mask, value) if ((value) == 0) { (reg) &= ~(mask); } else { (reg) |= (mask); }
#define CLINT_REG(offset) _REG32(CLINT_CTRL_ADDR, offset)
#define GPIO_REG(offset) _REG32(GPIO_CTRL_ADDR, offset)
#define PLIC_REG(offset) _REG32(PLIC_CTRL_ADDR, offset)
#define PWM0_REG(offset) _REG32(PWM0_CTRL_ADDR, offset)
#define SPI0_REG(offset) _REG32(SPI0_CTRL_ADDR, offset)
#define TRAPVEC_TABLE_REG(offset) _REG32(TRAPVEC_TABLE_CTRL_ADDR, offset)
#define UART0_REG(offset) _REG32(UART0_CTRL_ADDR, offset)
#define CLINT_REG64(offset) _REG64(CLINT_CTRL_ADDR, offset)
#define GPIO_REG64(offset) _REG64(GPIO_CTRL_ADDR, offset)
#define PLIC_REG64(offset) _REG64(PLIC_CTRL_ADDR, offset)
#define PWM0_REG64(offset) _REG64(PWM0_CTRL_ADDR, offset)
#define SPI0_REG64(offset) _REG64(SPI0_CTRL_ADDR, offset)
#define TRAPVEC_TABLE_REG64(offset) _REG64(TRAPVEC_TABLE_CTRL_ADDR, offset)
#define UART0_REG64(offset) _REG64(UART0_CTRL_ADDR, offset)
// Misc
#define NUM_GPIO 16
#define PLIC_NUM_INTERRUPTS 28
#define PLIC_NUM_PRIORITIES 7
#define HAS_BOARD_BUTTONS
#include "coreplexip-arty.h"
#endif /* _SIFIVE_PLATFORM_H */
@@ -0,0 +1,161 @@
OUTPUT_ARCH( "riscv" )
ENTRY( _start )
MEMORY
{
ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = 16K
}
PHDRS
{
ram PT_LOAD;
ram_init PT_LOAD;
ram PT_NULL;
}
SECTIONS
{
__stack_size = DEFINED(__stack_size) ? __stack_size : 1K;
.init :
{
KEEP (*(SORT_NONE(.init)))
} >ram AT>ram :ram
.text :
{
*(.text.unlikely .text.unlikely.*)
*(.text.startup .text.startup.*)
*(.text .text.*)
*(.gnu.linkonce.t.*)
} >ram AT>ram :ram
.fini :
{
KEEP (*(SORT_NONE(.fini)))
} >ram AT>ram :ram
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata :
{
*(.rdata)
*(.rodata .rodata.*)
*(.gnu.linkonce.r.*)
} >ram AT>ram :ram
. = ALIGN(4);
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >ram AT>ram :ram
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
} >ram AT>ram :ram
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
} >ram AT>ram :ram
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
} >ram AT>ram :ram
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
} >ram AT>ram :ram
.lalign :
{
. = ALIGN(4);
PROVIDE( _data_lma = . );
} >ram AT>ram :ram
.dalign :
{
. = ALIGN(4);
PROVIDE( _data = . );
} >ram AT>ram :ram_init
.data :
{
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.*)
*(.gnu.linkonce.s.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
} >ram AT>ram :ram_init
. = ALIGN(4);
PROVIDE( _edata = . );
PROVIDE( edata = . );
PROVIDE( _fbss = . );
PROVIDE( __bss_start = . );
.bss :
{
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
} >ram AT>ram :ram
. = ALIGN(8);
PROVIDE( _end = . );
PROVIDE( end = . );
.stack :
{
. = ALIGN(8);
. += __stack_size;
PROVIDE( _sp = . );
PROVIDE( _heap_end = . );
} >ram AT>ram :ram
}
@@ -0,0 +1 @@
../coreplexip-e31-arty/flash.lds
@@ -0,0 +1 @@
../coreplexip-e31-arty/init.c
@@ -0,0 +1 @@
../coreplexip-e31-arty/openocd.cfg
@@ -0,0 +1 @@
../coreplexip-e31-arty/platform.h
@@ -0,0 +1 @@
../coreplexip-e31-arty/scratchpad.lds
File diff suppressed because it is too large Load Diff
+97
View File
@@ -0,0 +1,97 @@
// See LICENSE for license details
#ifndef ENTRY_S
#define ENTRY_S
#include "encoding.h"
#include "sifive/bits.h"
.section .text.entry
.align 2
.global trap_entry
trap_entry:
addi sp, sp, -32*REGBYTES
STORE x1, 1*REGBYTES(sp)
STORE x2, 2*REGBYTES(sp)
STORE x3, 3*REGBYTES(sp)
STORE x4, 4*REGBYTES(sp)
STORE x5, 5*REGBYTES(sp)
STORE x6, 6*REGBYTES(sp)
STORE x7, 7*REGBYTES(sp)
STORE x8, 8*REGBYTES(sp)
STORE x9, 9*REGBYTES(sp)
STORE x10, 10*REGBYTES(sp)
STORE x11, 11*REGBYTES(sp)
STORE x12, 12*REGBYTES(sp)
STORE x13, 13*REGBYTES(sp)
STORE x14, 14*REGBYTES(sp)
STORE x15, 15*REGBYTES(sp)
STORE x16, 16*REGBYTES(sp)
STORE x17, 17*REGBYTES(sp)
STORE x18, 18*REGBYTES(sp)
STORE x19, 19*REGBYTES(sp)
STORE x20, 20*REGBYTES(sp)
STORE x21, 21*REGBYTES(sp)
STORE x22, 22*REGBYTES(sp)
STORE x23, 23*REGBYTES(sp)
STORE x24, 24*REGBYTES(sp)
STORE x25, 25*REGBYTES(sp)
STORE x26, 26*REGBYTES(sp)
STORE x27, 27*REGBYTES(sp)
STORE x28, 28*REGBYTES(sp)
STORE x29, 29*REGBYTES(sp)
STORE x30, 30*REGBYTES(sp)
STORE x31, 31*REGBYTES(sp)
csrr a0, mcause
csrr a1, mepc
mv a2, sp
call handle_trap
csrw mepc, a0
# Remain in M-mode after mret
li t0, MSTATUS_MPP
csrs mstatus, t0
LOAD x1, 1*REGBYTES(sp)
LOAD x2, 2*REGBYTES(sp)
LOAD x3, 3*REGBYTES(sp)
LOAD x4, 4*REGBYTES(sp)
LOAD x5, 5*REGBYTES(sp)
LOAD x6, 6*REGBYTES(sp)
LOAD x7, 7*REGBYTES(sp)
LOAD x8, 8*REGBYTES(sp)
LOAD x9, 9*REGBYTES(sp)
LOAD x10, 10*REGBYTES(sp)
LOAD x11, 11*REGBYTES(sp)
LOAD x12, 12*REGBYTES(sp)
LOAD x13, 13*REGBYTES(sp)
LOAD x14, 14*REGBYTES(sp)
LOAD x15, 15*REGBYTES(sp)
LOAD x16, 16*REGBYTES(sp)
LOAD x17, 17*REGBYTES(sp)
LOAD x18, 18*REGBYTES(sp)
LOAD x19, 19*REGBYTES(sp)
LOAD x20, 20*REGBYTES(sp)
LOAD x21, 21*REGBYTES(sp)
LOAD x22, 22*REGBYTES(sp)
LOAD x23, 23*REGBYTES(sp)
LOAD x24, 24*REGBYTES(sp)
LOAD x25, 25*REGBYTES(sp)
LOAD x26, 26*REGBYTES(sp)
LOAD x27, 27*REGBYTES(sp)
LOAD x28, 28*REGBYTES(sp)
LOAD x29, 29*REGBYTES(sp)
LOAD x30, 30*REGBYTES(sp)
LOAD x31, 31*REGBYTES(sp)
addi sp, sp, 32*REGBYTES
mret
.weak handle_trap
handle_trap:
1:
j 1b
#endif
@@ -0,0 +1 @@
../freedom-e300-hifive1/flash.lds
@@ -0,0 +1,87 @@
//See LICENSE for license details.
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include "platform.h"
#include "encoding.h"
extern int main(int argc, char** argv);
extern void trap_entry();
static unsigned long get_cpu_freq()
{
return 65000000;
}
unsigned long get_timer_freq()
{
return get_cpu_freq();
}
uint64_t get_timer_value()
{
#if __riscv_xlen == 32
while (1) {
uint32_t hi = read_csr(mcycleh);
uint32_t lo = read_csr(mcycle);
if (hi == read_csr(mcycleh))
return ((uint64_t)hi << 32) | lo;
}
#else
return read_csr(mcycle);
#endif
}
static void uart_init(size_t baud_rate)
{
GPIO_REG(GPIO_IOF_SEL) &= ~IOF0_UART0_MASK;
GPIO_REG(GPIO_IOF_EN) |= IOF0_UART0_MASK;
UART0_REG(UART_REG_DIV) = get_cpu_freq() / baud_rate - 1;
UART0_REG(UART_REG_TXCTRL) |= UART_TXEN;
}
#ifdef USE_PLIC
extern void handle_m_ext_interrupt();
#endif
#ifdef USE_M_TIME
extern void handle_m_time_interrupt();
#endif
uintptr_t handle_trap(uintptr_t mcause, uintptr_t epc)
{
if (0){
#ifdef USE_PLIC
// External Machine-Level interrupt from PLIC
} else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT)) {
handle_m_ext_interrupt();
#endif
#ifdef USE_M_TIME
// External Machine-Level interrupt from PLIC
} else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_TIMER)){
handle_m_time_interrupt();
#endif
}
else {
write(1, "Unhandled Trap:\n", 16);
_exit(1 + mcause);
}
return epc;
}
void _init()
{
#ifndef NO_INIT
uart_init(115200);
printf("core freq at %d Hz\n", get_cpu_freq());
write_csr(mtvec, &trap_entry);
#endif
}
void _fini()
{
}
@@ -0,0 +1,30 @@
adapter_khz 10000
#source [find interface/ftdi/olimex-arm-usb-tiny-h.cfg]
interface ftdi
ftdi_device_desc "Olimex OpenOCD JTAG ARM-USB-TINY-H"
ftdi_vid_pid 0x15ba 0x002a
ftdi_layout_init 0x0808 0x0a1b
ftdi_layout_signal nSRST -oe 0x0200
ftdi_layout_signal nTRST -data 0x0100 -oe 0x0100
ftdi_layout_signal LED -data 0x0800
#
set _CHIPNAME riscv
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10e31913
set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME riscv -chain-position $_TARGETNAME
$_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1
flash bank my_first_flash fespi 0x20000000 0 0 0 $_TARGETNAME
init
#reset
if {[ info exists pulse_srst]} {
ftdi_set_signal nSRST 0
ftdi_set_signal nSRST z
}
halt
#flash protect 0 64 last off
@@ -0,0 +1,124 @@
// See LICENSE for license details.
#ifndef _SIFIVE_PLATFORM_H
#define _SIFIVE_PLATFORM_H
// Some things missing from the official encoding.h
#define MCAUSE_INT 0x80000000
#define MCAUSE_CAUSE 0x7FFFFFFF
#include "sifive/const.h"
#include "sifive/devices/aon.h"
#include "sifive/devices/clint.h"
#include "sifive/devices/gpio.h"
#include "sifive/devices/plic.h"
#include "sifive/devices/pwm.h"
#include "sifive/devices/spi.h"
#include "sifive/devices/uart.h"
/****************************************************************************
* Platform definitions
*****************************************************************************/
#define TRAPVEC_TABLE_CTRL_ADDR _AC(0x00001010,UL)
#define CLINT_CTRL_ADDR _AC(0x02000000,UL)
#define PLIC_CTRL_ADDR _AC(0x0C000000,UL)
#define AON_CTRL_ADDR _AC(0x10000000,UL)
#define GPIO_CTRL_ADDR _AC(0x10012000,UL)
#define UART0_CTRL_ADDR _AC(0x10013000,UL)
#define SPI0_CTRL_ADDR _AC(0x10014000,UL)
#define PWM0_CTRL_ADDR _AC(0x10015000,UL)
#define UART1_CTRL_ADDR _AC(0x10023000,UL)
#define SPI1_CTRL_ADDR _AC(0x10024000,UL)
#define PWM1_CTRL_ADDR _AC(0x10025000,UL)
#define SPI2_CTRL_ADDR _AC(0x10034000,UL)
#define PWM2_CTRL_ADDR _AC(0x10035000,UL)
#define SPI0_MMAP_ADDR _AC(0x20000000,UL)
#define MEM_CTRL_ADDR _AC(0x80000000,UL)
// IOF Mappings
#define IOF0_SPI1_MASK _AC(0x000007FC,UL)
#define SPI11_NUM_SS (4)
#define IOF_SPI1_SS0 (2u)
#define IOF_SPI1_SS1 (8u)
#define IOF_SPI1_SS2 (9u)
#define IOF_SPI1_SS3 (10u)
#define IOF_SPI1_MOSI (3u)
#define IOF_SPI1_MISO (4u)
#define IOF_SPI1_SCK (5u)
#define IOF_SPI1_DQ0 (3u)
#define IOF_SPI1_DQ1 (4u)
#define IOF_SPI1_DQ2 (6u)
#define IOF_SPI1_DQ3 (7u)
#define IOF0_SPI2_MASK _AC(0xFC000000,UL)
#define SPI2_NUM_SS (1)
#define IOF_SPI2_SS0 (26u)
#define IOF_SPI2_MOSI (27u)
#define IOF_SPI2_MISO (28u)
#define IOF_SPI2_SCK (29u)
#define IOF_SPI2_DQ0 (27u)
#define IOF_SPI2_DQ1 (28u)
#define IOF_SPI2_DQ2 (30u)
#define IOF_SPI2_DQ3 (31u)
#define IOF0_UART0_MASK _AC(0x00030000, UL)
#define IOF_UART0_RX (16u)
#define IOF_UART0_TX (17u)
#define IOF0_UART1_MASK _AC(0x03000000, UL)
#define IOF_UART1_RX (24u)
#define IOF_UART1_TX (25u)
#define IOF1_PWM0_MASK _AC(0x0000000F, UL)
#define IOF1_PWM1_MASK _AC(0x00780000, UL)
#define IOF1_PWM2_MASK _AC(0x00003C00, UL)
// Interrupt Numbers
#define INT_RESERVED 0
#define INT_WDOGCMP 1
#define INT_RTCCMP 2
#define INT_UART0_BASE 3
#define INT_UART1_BASE 4
#define INT_SPI0_BASE 5
#define INT_SPI1_BASE 6
#define INT_SPI2_BASE 7
#define INT_GPIO_BASE 8
#define INT_PWM0_BASE 40
#define INT_PWM1_BASE 44
#define INT_PWM2_BASE 48
// Helper functions
#define _REG32(p, i) (*(volatile uint32_t *) ((p) + (i)))
#define _REG32P(p, i) ((volatile uint32_t *) ((p) + (i)))
#define AON_REG(offset) _REG32(AON_CTRL_ADDR, offset)
#define CLINT_REG(offset) _REG32(CLINT_CTRL_ADDR, offset)
#define GPIO_REG(offset) _REG32(GPIO_CTRL_ADDR, offset)
#define OTP_REG(offset) _REG32(OTP_CTRL_ADDR, offset)
#define PLIC_REG(offset) _REG32(PLIC_CTRL_ADDR, offset)
#define PWM0_REG(offset) _REG32(PWM0_CTRL_ADDR, offset)
#define PWM1_REG(offset) _REG32(PWM1_CTRL_ADDR, offset)
#define PWM2_REG(offset) _REG32(PWM2_CTRL_ADDR, offset)
#define SPI0_REG(offset) _REG32(SPI0_CTRL_ADDR, offset)
#define SPI1_REG(offset) _REG32(SPI1_CTRL_ADDR, offset)
#define SPI2_REG(offset) _REG32(SPI2_CTRL_ADDR, offset)
#define UART0_REG(offset) _REG32(UART0_CTRL_ADDR, offset)
#define UART1_REG(offset) _REG32(UART1_CTRL_ADDR, offset)
// Misc
#include <stdint.h>
#define NUM_GPIO 32
#define PLIC_NUM_INTERRUPTS 52
#define PLIC_NUM_PRIORITIES 7
#define HAS_BOARD_BUTTONS
#include "hifive1.h"
unsigned long get_timer_freq(void);
uint64_t get_timer_value(void);
#endif /* _SIFIVE_PLATFORM_H */
@@ -0,0 +1,185 @@
OUTPUT_ARCH( "riscv" )
ENTRY( _start )
MEMORY
{
flash (rxai!w) : ORIGIN = 0x20010000, LENGTH = 0x6a120
ram (wxa!ri) : ORIGIN = 0x80000000, LENGTH = 16K
}
PHDRS
{
flash PT_LOAD;
ram_init PT_LOAD;
ram PT_NULL;
}
SECTIONS
{
__stack_size = DEFINED(__stack_size) ? __stack_size : 2K;
.init :
{
KEEP (*(SORT_NONE(.init)))
} >flash AT>flash :flash
.text :
{
*(.text.unlikely .text.unlikely.*)
*(.text.startup .text.startup.*)
*(.text .text.*)
*(.gnu.linkonce.t.*)
/* section information for finsh shell */
. = ALIGN(4);
__fsymtab_start = .;
KEEP(*(FSymTab))
__fsymtab_end = .;
. = ALIGN(4);
__vsymtab_start = .;
KEEP(*(VSymTab))
__vsymtab_end = .;
. = ALIGN(4);
. = ALIGN(4);
__rt_init_start = .;
KEEP(*(SORT(.rti_fn*)))
__rt_init_end = .;
. = ALIGN(4);
/* section information for modules */
. = ALIGN(4);
__rtmsymtab_start = .;
KEEP(*(RTMSymTab))
__rtmsymtab_end = .;
} >flash AT>flash :flash
.fini :
{
KEEP (*(SORT_NONE(.fini)))
} >flash AT>flash :flash
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata :
{
*(.rdata)
*(.rodata .rodata.*)
*(.gnu.linkonce.r.*)
} >flash AT>flash :flash
. = ALIGN(4);
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >flash AT>flash :flash
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
} >flash AT>flash :flash
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
} >flash AT>flash :flash
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
} >flash AT>flash :flash
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
} >flash AT>flash :flash
.lalign :
{
. = ALIGN(4);
PROVIDE( _data_lma = . );
} >flash AT>flash :flash
.dalign :
{
. = ALIGN(4);
PROVIDE( _data = . );
} >ram AT>flash :ram_init
.data :
{
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
PROVIDE( __global_pointer$ = . + 0x800 );
*(.sdata .sdata.*)
*(.gnu.linkonce.s.*)
. = ALIGN(8);
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
} >ram AT>flash :ram_init
. = ALIGN(4);
PROVIDE( _edata = . );
PROVIDE( edata = . );
PROVIDE( _fbss = . );
PROVIDE( __bss_start = . );
.bss :
{
*(.sbss*)
*(.gnu.linkonce.sb.*)
*(.bss .bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
} >ram AT>ram :ram
. = ALIGN(8);
PROVIDE( _end = . );
PROVIDE( end = . );
.stack ORIGIN(ram) + LENGTH(ram) - __stack_size :
{
PROVIDE( _heap_end = . );
. = __stack_size;
PROVIDE( _sp = . );
} >ram AT>ram :ram
}
@@ -0,0 +1,237 @@
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "platform.h"
#include "encoding.h"
extern int main(int argc, char** argv);
extern void trap_entry();
static unsigned long mtime_lo(void)
{
return *(volatile unsigned long *)(CLINT_CTRL_ADDR + CLINT_MTIME);
}
#ifdef __riscv32
static uint32_t mtime_hi(void)
{
return *(volatile uint32_t *)(CLINT_CTRL_ADDR + CLINT_MTIME + 4);
}
uint64_t get_timer_value()
{
while (1) {
uint32_t hi = mtime_hi();
uint32_t lo = mtime_lo();
if (hi == mtime_hi())
return ((uint64_t)hi << 32) | lo;
}
}
#else /* __riscv32 */
uint64_t get_timer_value()
{
return mtime_lo();
}
#endif
unsigned long get_timer_freq()
{
return 32768;
}
static void use_hfrosc(int div, int trim)
{
// Make sure the HFROSC is running at its default setting
PRCI_REG(PRCI_HFROSCCFG) = (ROSC_DIV(div) | ROSC_TRIM(trim) | ROSC_EN(1));
while ((PRCI_REG(PRCI_HFROSCCFG) & ROSC_RDY(1)) == 0) ;
PRCI_REG(PRCI_PLLCFG) &= ~PLL_SEL(1);
}
void use_pll(int refsel, int bypass, int r, int f, int q)
{
// Ensure that we aren't running off the PLL before we mess with it.
if (PRCI_REG(PRCI_PLLCFG) & PLL_SEL(1)) {
// Make sure the HFROSC is running at its default setting
use_hfrosc(4, 16);
}
// Set PLL Source to be HFXOSC if available.
uint32_t config_value = 0;
config_value |= PLL_REFSEL(refsel);
if (bypass) {
// Bypass
config_value |= PLL_BYPASS(1);
PRCI_REG(PRCI_PLLCFG) = config_value;
// If we don't have an HFXTAL, this doesn't really matter.
// Set our Final output divide to divide-by-1:
PRCI_REG(PRCI_PLLDIV) = (PLL_FINAL_DIV_BY_1(1) | PLL_FINAL_DIV(0));
} else {
// In case we are executing from QSPI,
// (which is quite likely) we need to
// set the QSPI clock divider appropriately
// before boosting the clock frequency.
// Div = f_sck/2
SPI0_REG(SPI_REG_SCKDIV) = 8;
// Set DIV Settings for PLL
// Both HFROSC and HFXOSC are modeled as ideal
// 16MHz sources (assuming dividers are set properly for
// HFROSC).
// (Legal values of f_REF are 6-48MHz)
// Set DIVR to divide-by-2 to get 8MHz frequency
// (legal values of f_R are 6-12 MHz)
config_value |= PLL_BYPASS(1);
config_value |= PLL_R(r);
// Set DIVF to get 512Mhz frequncy
// There is an implied multiply-by-2, 16Mhz.
// So need to write 32-1
// (legal values of f_F are 384-768 MHz)
config_value |= PLL_F(f);
// Set DIVQ to divide-by-2 to get 256 MHz frequency
// (legal values of f_Q are 50-400Mhz)
config_value |= PLL_Q(q);
// Set our Final output divide to divide-by-1:
PRCI_REG(PRCI_PLLDIV) = (PLL_FINAL_DIV_BY_1(1) | PLL_FINAL_DIV(0));
PRCI_REG(PRCI_PLLCFG) = config_value;
// Un-Bypass the PLL.
PRCI_REG(PRCI_PLLCFG) &= ~PLL_BYPASS(1);
// Wait for PLL Lock
// Note that the Lock signal can be glitchy.
// Need to wait 100 us
// RTC is running at 32kHz.
// So wait 4 ticks of RTC.
uint32_t now = mtime_lo();
while (mtime_lo() - now < 4) ;
// Now it is safe to check for PLL Lock
while ((PRCI_REG(PRCI_PLLCFG) & PLL_LOCK(1)) == 0) ;
}
// Switch over to PLL Clock source
PRCI_REG(PRCI_PLLCFG) |= PLL_SEL(1);
}
void use_default_clocks()
{
// Turn off the LFROSC
AON_REG(AON_LFROSC) &= ~ROSC_EN(1);
// Use HFROSC
use_hfrosc(4, 16);
}
static unsigned long __attribute__((noinline)) measure_cpu_freq(size_t n)
{
unsigned long start_mtime, delta_mtime;
unsigned long mtime_freq = get_timer_freq();
// Don't start measuruing until we see an mtime tick
unsigned long tmp = mtime_lo();
do {
start_mtime = mtime_lo();
} while (start_mtime == tmp);
unsigned long start_mcycle = read_csr(mcycle);
do {
delta_mtime = mtime_lo() - start_mtime;
} while (delta_mtime < n);
unsigned long delta_mcycle = read_csr(mcycle) - start_mcycle;
return (delta_mcycle / delta_mtime) * mtime_freq
+ ((delta_mcycle % delta_mtime) * mtime_freq) / delta_mtime;
}
unsigned long get_cpu_freq()
{
static uint32_t cpu_freq;
if (!cpu_freq) {
// warm up I$
measure_cpu_freq(1);
// measure for real
cpu_freq = measure_cpu_freq(10);
}
return cpu_freq;
}
static void uart_init(size_t baud_rate)
{
GPIO_REG(GPIO_IOF_SEL) &= ~IOF0_UART0_MASK;
GPIO_REG(GPIO_IOF_EN) |= IOF0_UART0_MASK;
UART0_REG(UART_REG_DIV) = get_cpu_freq() / baud_rate - 1;
UART0_REG(UART_REG_TXCTRL) |= UART_TXEN;
}
#ifdef USE_PLIC
extern void handle_m_ext_interrupt();
#endif
#ifdef USE_M_TIME
extern void handle_m_time_interrupt();
#endif
uintptr_t handle_trap(uintptr_t mcause, uintptr_t epc)
{
if (0){
#ifdef USE_PLIC
// External Machine-Level interrupt from PLIC
} else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT)) {
handle_m_ext_interrupt();
#endif
#ifdef USE_M_TIME
// External Machine-Level interrupt from PLIC
} else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_TIMER)){
handle_m_time_interrupt();
#endif
}
else {
rt_kprintf("Unhandled Trap.\n");
}
return epc;
}
void _init()
{
#ifndef NO_INIT
use_default_clocks();
use_pll(0, 0, 1, 31, 1);
uart_init(115200);
rt_kprintf("core freq at %ld Hz\n", get_cpu_freq());
write_csr(mtvec, &trap_entry);
if (read_csr(misa) & (1 << ('F' - 'A'))) { // if F extension is present
write_csr(mstatus, MSTATUS_FS); // allow FPU instructions without trapping
write_csr(fcsr, 0); // initialize rounding mode, undefined at reset
}
#endif
}
void _fini()
{
}
@@ -0,0 +1,34 @@
adapter_khz 10000
interface ftdi
ftdi_device_desc "Dual RS232-HS"
ftdi_vid_pid 0x0403 0x6010
ftdi_layout_init 0x0008 0x001b
ftdi_layout_signal nSRST -oe 0x0020 -data 0x0020
#Reset Stretcher logic on FE310 is ~1 second long
#This doesn't apply if you use
# ftdi_set_signal, but still good to document
#adapter_nsrst_delay 1500
set _CHIPNAME riscv
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10e31913
set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME riscv -chain-position $_TARGETNAME
$_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1
flash bank onboard_spi_flash fespi 0x20000000 0 0 0 $_TARGETNAME
init
#reset -- This type of reset is not implemented yet
if {[ info exists pulse_srst]} {
ftdi_set_signal nSRST 0
ftdi_set_signal nSRST z
#Wait for the reset stretcher
#It will work without this, but
#will incur lots of delays for later commands.
sleep 1500
}
halt
#flash protect 0 64 last off
@@ -0,0 +1,133 @@
// See LICENSE for license details.
#ifndef _SIFIVE_PLATFORM_H
#define _SIFIVE_PLATFORM_H
// Some things missing from the official encoding.h
#define MCAUSE_INT 0x80000000
#define MCAUSE_CAUSE 0x7FFFFFFF
#include "sifive/const.h"
#include "sifive/devices/aon.h"
#include "sifive/devices/clint.h"
#include "sifive/devices/gpio.h"
#include "sifive/devices/otp.h"
#include "sifive/devices/plic.h"
#include "sifive/devices/prci.h"
#include "sifive/devices/pwm.h"
#include "sifive/devices/spi.h"
#include "sifive/devices/uart.h"
/****************************************************************************
* Platform definitions
*****************************************************************************/
// Memory map
#define MASKROM_MEM_ADDR _AC(0x00001000,UL)
#define TRAPVEC_TABLE_CTRL_ADDR _AC(0x00001010,UL)
#define OTP_MEM_ADDR _AC(0x00020000,UL)
#define CLINT_CTRL_ADDR _AC(0x02000000,UL)
#define PLIC_CTRL_ADDR _AC(0x0C000000,UL)
#define AON_CTRL_ADDR _AC(0x10000000,UL)
#define PRCI_CTRL_ADDR _AC(0x10008000,UL)
#define OTP_CTRL_ADDR _AC(0x10010000,UL)
#define GPIO_CTRL_ADDR _AC(0x10012000,UL)
#define UART0_CTRL_ADDR _AC(0x10013000,UL)
#define SPI0_CTRL_ADDR _AC(0x10014000,UL)
#define PWM0_CTRL_ADDR _AC(0x10015000,UL)
#define UART1_CTRL_ADDR _AC(0x10023000,UL)
#define SPI1_CTRL_ADDR _AC(0x10024000,UL)
#define PWM1_CTRL_ADDR _AC(0x10025000,UL)
#define SPI2_CTRL_ADDR _AC(0x10034000,UL)
#define PWM2_CTRL_ADDR _AC(0x10035000,UL)
#define SPI0_MEM_ADDR _AC(0x20000000,UL)
#define MEM_CTRL_ADDR _AC(0x80000000,UL)
// IOF masks
#define IOF0_SPI1_MASK _AC(0x000007FC,UL)
#define SPI11_NUM_SS (4)
#define IOF_SPI1_SS0 (2u)
#define IOF_SPI1_SS1 (8u)
#define IOF_SPI1_SS2 (9u)
#define IOF_SPI1_SS3 (10u)
#define IOF_SPI1_MOSI (3u)
#define IOF_SPI1_MISO (4u)
#define IOF_SPI1_SCK (5u)
#define IOF_SPI1_DQ0 (3u)
#define IOF_SPI1_DQ1 (4u)
#define IOF_SPI1_DQ2 (6u)
#define IOF_SPI1_DQ3 (7u)
#define IOF0_SPI2_MASK _AC(0xFC000000,UL)
#define SPI2_NUM_SS (1)
#define IOF_SPI2_SS0 (26u)
#define IOF_SPI2_MOSI (27u)
#define IOF_SPI2_MISO (28u)
#define IOF_SPI2_SCK (29u)
#define IOF_SPI2_DQ0 (27u)
#define IOF_SPI2_DQ1 (28u)
#define IOF_SPI2_DQ2 (30u)
#define IOF_SPI2_DQ3 (31u)
//#define IOF0_I2C_MASK _AC(0x00003000,UL)
#define IOF0_UART0_MASK _AC(0x00030000, UL)
#define IOF_UART0_RX (16u)
#define IOF_UART0_TX (17u)
#define IOF0_UART1_MASK _AC(0x03000000, UL)
#define IOF_UART1_RX (24u)
#define IOF_UART1_TX (25u)
#define IOF1_PWM0_MASK _AC(0x0000000F, UL)
#define IOF1_PWM1_MASK _AC(0x00780000, UL)
#define IOF1_PWM2_MASK _AC(0x00003C00, UL)
// Interrupt numbers
#define INT_RESERVED 0
#define INT_WDOGCMP 1
#define INT_RTCCMP 2
#define INT_UART0_BASE 3
#define INT_UART1_BASE 4
#define INT_SPI0_BASE 5
#define INT_SPI1_BASE 6
#define INT_SPI2_BASE 7
#define INT_GPIO_BASE 8
#define INT_PWM0_BASE 40
#define INT_PWM1_BASE 44
#define INT_PWM2_BASE 48
// Helper functions
#define _REG32(p, i) (*(volatile uint32_t *) ((p) + (i)))
#define _REG32P(p, i) ((volatile uint32_t *) ((p) + (i)))
#define AON_REG(offset) _REG32(AON_CTRL_ADDR, offset)
#define CLINT_REG(offset) _REG32(CLINT_CTRL_ADDR, offset)
#define GPIO_REG(offset) _REG32(GPIO_CTRL_ADDR, offset)
#define OTP_REG(offset) _REG32(OTP_CTRL_ADDR, offset)
#define PLIC_REG(offset) _REG32(PLIC_CTRL_ADDR, offset)
#define PRCI_REG(offset) _REG32(PRCI_CTRL_ADDR, offset)
#define PWM0_REG(offset) _REG32(PWM0_CTRL_ADDR, offset)
#define PWM1_REG(offset) _REG32(PWM1_CTRL_ADDR, offset)
#define PWM2_REG(offset) _REG32(PWM2_CTRL_ADDR, offset)
#define SPI0_REG(offset) _REG32(SPI0_CTRL_ADDR, offset)
#define SPI1_REG(offset) _REG32(SPI1_CTRL_ADDR, offset)
#define SPI2_REG(offset) _REG32(SPI2_CTRL_ADDR, offset)
#define UART0_REG(offset) _REG32(UART0_CTRL_ADDR, offset)
#define UART1_REG(offset) _REG32(UART1_CTRL_ADDR, offset)
// Misc
#include <stdint.h>
#define NUM_GPIO 32
#define PLIC_NUM_INTERRUPTS 52
#define PLIC_NUM_PRIORITIES 7
#include "hifive1.h"
unsigned long get_cpu_freq(void);
unsigned long get_timer_freq(void);
uint64_t get_timer_value(void);
#endif /* _SIFIVE_PLATFORM_H */

Some files were not shown because too many files have changed in this diff Show More