初始提交
This commit is contained in:
52
dtest/dtest3/kl3_spinlock_test/Makefile
Normal file
52
dtest/dtest3/kl3_spinlock_test/Makefile
Normal file
@@ -0,0 +1,52 @@
|
||||
|
||||
# OUTPUT type
|
||||
# 1 - .out
|
||||
# 2 - .a
|
||||
# 3 - .so
|
||||
OUTPUT_TYPE = 1
|
||||
OUTPUT_NAME = spinlock_test
|
||||
|
||||
SUB_DIRS = $(TOPDIR)/common/os_shim/dtestos
|
||||
|
||||
EXT_SRC += ../common/dtest_printf.c
|
||||
|
||||
# .h files dir
|
||||
ADD_INCLUDE += $(TOPDIR)/inc/io_lib $(TOPDIR)/inc/driver $(TOPDIR)/driver/inc ../common
|
||||
|
||||
# predefined macro
|
||||
PRE_MARCO += _MODULE_NAME_=\"SPINLOCK\"
|
||||
PRE_MARCO += _MODULE_VERSION_=\"V1.0.0\"
|
||||
|
||||
LD_SCRIPT = link_soc.lds
|
||||
|
||||
ADD_LIB = riscv
|
||||
ADD_LIBDIR = $(TOPDIR)/startup/riscv3
|
||||
ADD_INCLUDE += $(TOPDIR)/driver/src/hw3/inc
|
||||
|
||||
# lib need to ld together
|
||||
ADD_LIB += driver io_lib
|
||||
# lib dir
|
||||
ADD_LIBDIR += $(TOPDIR)/driver $(TOPDIR)/common/io_lib
|
||||
|
||||
#####################################################
|
||||
|
||||
ifdef TOPDIR
|
||||
include $(TOPDIR)/build/makefile.cfg
|
||||
else
|
||||
include $(CURDIR)/build/makefile.cfg
|
||||
TOPDIR = $(CURDIR)
|
||||
export TOPDIR
|
||||
endif
|
||||
|
||||
dump:
|
||||
$(OBJDUMP) -D -S -l $(OUTPUT_FULL_NAME) > $(OUTPUT_FULL_NAME).dump
|
||||
|
||||
# display the obj files and output name
|
||||
debug:
|
||||
@echo TOPDIR=$(TOPDIR)
|
||||
@echo OUTPUT_LIB=$(OUTPUT_FULL_NAME)
|
||||
@echo DEPS=$(DEPS)
|
||||
@echo OBJECTS=$(OBJECTS)
|
||||
@echo SRCS=$(SRCS)
|
||||
@echo OBJECTS folder=$(foreach dirname, $(SUB_DIRS), $(addprefix $(BIN_DIR)/, $(dirname)))
|
||||
@echo output_name=$(OUTPUT_FULL_NAME)
|
49
dtest/dtest3/kl3_spinlock_test/core_start.S
Normal file
49
dtest/dtest3/kl3_spinlock_test/core_start.S
Normal file
@@ -0,0 +1,49 @@
|
||||
// See LICENSE for license details.
|
||||
#include "encoding.h"
|
||||
|
||||
.section .init
|
||||
.globl _core_start
|
||||
.type _core_start,@function
|
||||
|
||||
_core_start:
|
||||
li t0, MSTATUS_MIE
|
||||
csrc mstatus, t0
|
||||
li t0, MIP_MTIP
|
||||
csrc mie, t0
|
||||
li t0, MIP_MEIP
|
||||
csrc mie, t0
|
||||
li t0, 0
|
||||
csrc mcause, t0
|
||||
|
||||
la gp, _gp
|
||||
la sp, _sp
|
||||
|
||||
addi sp, sp, 1024
|
||||
csrr t1, mhartid
|
||||
li t0, 2
|
||||
beq t1, t0, 1f
|
||||
addi sp, sp, 1024
|
||||
|
||||
/* Call global constructors */
|
||||
//la a0, __libc_fini_array
|
||||
//call __libc_init_array
|
||||
|
||||
/* init function*/
|
||||
call _init
|
||||
1:
|
||||
#ifndef __riscv_float_abi_soft
|
||||
/* Enable FPU */
|
||||
li t0, MSTATUS_FS
|
||||
csrs mstatus, t0
|
||||
csrr t1, mstatus
|
||||
and t1, t1, t0
|
||||
beqz t1, 1f
|
||||
fssr x0
|
||||
1:
|
||||
#endif
|
||||
/* argc = argv = 0 */
|
||||
li a0, 0
|
||||
li a1, 0
|
||||
call dtest_spinlock_core12_main
|
||||
#tail exit
|
||||
1: j 1b
|
1361
dtest/dtest3/kl3_spinlock_test/encoding.h
Normal file
1361
dtest/dtest3/kl3_spinlock_test/encoding.h
Normal file
File diff suppressed because it is too large
Load Diff
41
dtest/dtest3/kl3_spinlock_test/readme.md
Normal file
41
dtest/dtest3/kl3_spinlock_test/readme.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# spinlock测试说明文档
|
||||
|
||||
## spinlock简介
|
||||
|
||||
自旋锁(spinlock)是为了实现保护共享资源而设计的一个IP,实现了在任何时刻某个共享资源只能被一个master访问。
|
||||
|
||||
在自旋锁机制中,某个master要访问某个共享资源时,首先查询该共享资源是否被其他的master访问,即是否已经被其他的master锁住,如果没有,则该master先对该共享资源上锁,然后在执行对共享资源的操作,在访问结束之后主动释放锁。如果已经被其他的master锁住,则一直查询该贡献资源是否已经被其他master释放。
|
||||
|
||||
在kl3中,自旋锁的本质是一个32bit的寄存器,一共16个自旋锁(即最多定义16个共享资源),每个自旋锁的每个bit对应一个master,这些寄存器具有如下特性:
|
||||
|
||||
* 存在保护寄存器,通过写入magic number到指定的寄存器来解除保护,仅在解除保护的情况下才能写自旋锁对应的寄存器。
|
||||
|
||||
* 在自旋锁寄存器已经有bit被置1的情况下,无法再对其他的bit进行置1操作,此时必须将所有已经置1的bit清除之后,才能重新置位其他的bit。
|
||||
|
||||
## spinlock测试例程说明
|
||||
|
||||
spinlock测试例程使用到的外设包含spinlock、uart、gp_timer。
|
||||
|
||||
* spinlock:测试对象,用于测试spinlock对贡献资源的保护功能。
|
||||
* uart:使用uart0,实现调试信息打印,接收case配置信息等与PC的交互功能。
|
||||
* gp_timer:用于定时。
|
||||
|
||||
spinlock测试例程遵循自动化测试框架,在例程执行之后,初始化串口0,通过串口发送“start”字段到PC,并等待PC发送“config”字段来获取本次需要执行的测试case。
|
||||
|
||||
在获取到case组合之后,初始化spinlock,并根据case组合开始执行测试case。
|
||||
|
||||
### case0:共享资源保护测试
|
||||
|
||||
spinlock功能比较单一,因此测试例程比较简单,仅以ram中的一个地址作为共享资源(事实上这里的串口也是共享资源),3个核同时对该地址进行读写操作,观察数据是否正确,以及core是否一直等待spinlock。具体步骤如下:
|
||||
|
||||
1. 上电后初始化外设,并将ram指定地址的数据清零。
|
||||
|
||||
2. 引导core1、core2运行测试代码,并记录此时gp_timer的计数值
|
||||
|
||||
core1、core2测试代码一致,都是运行之后马上申请spinlock,在拿到锁之后,对ram地址进行读写操作,每次在原有数据的基础上加1,每次读写操作延时100ms,在执行100次读写后释放spinlock,并将core挂起。
|
||||
|
||||
*为了保证core0最后执行,core0在启动core1、core2之后延时一段时间(这段时间比core1、core2执行的总时长要更短)*
|
||||
|
||||
3. core0申请spinlock,在拿到锁之后,读取gp_timer的时间,并判断执行时间与core1、core2延时总时长差距是否过大,同时判断ram中的数据是否为其他core累加的值。如果任意条件不满足,则判定失败。
|
||||
|
||||
测试结果符合预期。core1、core2顺序执行(先后顺序不一定),core会一直等待spinlock,并能正确的保护资源。
|
180
dtest/dtest3/kl3_spinlock_test/spinlock_test.c
Normal file
180
dtest/dtest3/kl3_spinlock_test/spinlock_test.c
Normal file
@@ -0,0 +1,180 @@
|
||||
/****************************************************************************
|
||||
|
||||
Copyright(c) 2019 by Aerospace C.Power (Chongqing) Microelectronics. ALL RIGHTS RESERVED.
|
||||
|
||||
This Information is proprietary to Aerospace C.Power (Chongqing) Microelectronics and MAY NOT
|
||||
be copied by any method or incorporated into another program without
|
||||
the express written consent of Aerospace C.Power. This Information or any portion
|
||||
thereof remains the property of Aerospace C.Power. The Information contained herein
|
||||
is believed to be accurate and Aerospace C.Power assumes no responsibility or
|
||||
liability for its use in any way and conveys no license or title under
|
||||
any patent or copyright and makes no representation or warranty that this
|
||||
Information is free from patent or copyright infringement.
|
||||
|
||||
****************************************************************************/
|
||||
#include "chip_reg_base.h"
|
||||
#include "hw_reg_api.h"
|
||||
#include "sfc_rf.h"
|
||||
#include "apb_cache_reg.h"
|
||||
|
||||
#include "ahb.h"
|
||||
#include "cpu.h"
|
||||
#include "gp_timer.h"
|
||||
#include "iot_spinlock.h"
|
||||
|
||||
#include "iot_clock.h"
|
||||
#include "dbg_io.h"
|
||||
|
||||
#include "iot_errno_api.h"
|
||||
|
||||
#include "dtest_printf.h"
|
||||
|
||||
#define DTEST_SPINLOCK_CORE0_USE_SPINLOCK 1
|
||||
|
||||
#define DTEST_SPINLOCK_RAM_ADDR_CNT AHB_RAM0_BASEADDR
|
||||
#define DTEST_SPINLOCK_RAM_ADDR_DATA (AHB_RAM0_BASEADDR + 3 * 4)
|
||||
#define DTEST_SPINLOCK_TEST_NUM SPINLOCK_INDEX_0
|
||||
#define DTEST_SPINLOCK_TEST_CNT 10000
|
||||
#define DTEST_SPINLOCK_TIME_DELAY 100
|
||||
|
||||
#define DTEST_SPINLOCK_CASE_MUTEX (1 << 0)
|
||||
|
||||
extern void _core_start(void);
|
||||
|
||||
void dtest_spinlock_core12_main()
|
||||
{
|
||||
uint8_t cpu = cpu_get_mhartid();
|
||||
|
||||
gp_timer_init();
|
||||
gp_timer_set(0, 0xffffffff, 0);
|
||||
gp_timer_start(0);
|
||||
|
||||
while (1) {
|
||||
iot_spinlock_lock(DTEST_SPINLOCK_TEST_NUM, cpu);
|
||||
// iot_printf("cpu:%d get spinlock\n", cpu);
|
||||
|
||||
*(uint32_t*)(DTEST_SPINLOCK_RAM_ADDR_DATA) = (1 << cpu);
|
||||
*(uint32_t*)(DTEST_SPINLOCK_RAM_ADDR_CNT + cpu * 4) += 1;
|
||||
iot_delay_us(DTEST_SPINLOCK_TIME_DELAY);
|
||||
|
||||
iot_spinlock_unlock(DTEST_SPINLOCK_TEST_NUM, cpu);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t dtest_spinlock_multicore_mutex_test()
|
||||
{
|
||||
uint8_t i;
|
||||
uint32_t data, cnt_0 = 0, cnt_1 = 0, cnt_2 = 0;
|
||||
uint8_t cpu = cpu_get_mhartid();
|
||||
uint32_t time_start, time_end, time_delta;
|
||||
|
||||
dcase_start("spinlock multicore access test\n");
|
||||
|
||||
dprintf("set ram data to 0\n");
|
||||
for (i = 0; i < 3; i++) {
|
||||
*(uint32_t *)(DTEST_SPINLOCK_RAM_ADDR_CNT + i * 4) = 0;
|
||||
}
|
||||
|
||||
dprintf("enable core1 and core2\n");
|
||||
time_start = gp_timer_get_current_val(0);
|
||||
ahb_core1_set_start((uint32_t)_core_start);
|
||||
ahb_core1_enable();
|
||||
ahb_core1_reset();
|
||||
ahb_core2_set_start((uint32_t)_core_start);
|
||||
ahb_core2_enable();
|
||||
ahb_core2_reset();
|
||||
|
||||
/* core0 delay sometime to make sure get spinlock last */
|
||||
iot_delay_us(DTEST_SPINLOCK_TIME_DELAY);
|
||||
|
||||
while (1) {
|
||||
#if DTEST_SPINLOCK_CORE0_USE_SPINLOCK
|
||||
iot_spinlock_lock(DTEST_SPINLOCK_TEST_NUM, cpu);
|
||||
// iot_printf("cpu:%d get spinlock\n", cpu);
|
||||
*(uint32_t*)(DTEST_SPINLOCK_RAM_ADDR_DATA) = (1 << cpu);
|
||||
*(uint32_t*)(DTEST_SPINLOCK_RAM_ADDR_CNT) += 1;
|
||||
iot_delay_us(DTEST_SPINLOCK_TIME_DELAY);
|
||||
#endif
|
||||
data = *(uint32_t*)(DTEST_SPINLOCK_RAM_ADDR_DATA);
|
||||
cnt_0 = *(uint32_t*)(DTEST_SPINLOCK_RAM_ADDR_CNT);
|
||||
cnt_1 = *(uint32_t*)(DTEST_SPINLOCK_RAM_ADDR_CNT + 4);
|
||||
cnt_2 = *(uint32_t*)(DTEST_SPINLOCK_RAM_ADDR_CNT + 8);
|
||||
|
||||
if (data != 0x1 && data != 0x2 && data != 0x4) {
|
||||
dprintf("ram access conflict, err data:0x%08x\n", data);
|
||||
i = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cnt_0 + cnt_1 + cnt_2 >= DTEST_SPINLOCK_TEST_CNT) {
|
||||
dprintf("execution complete cnt:%d, cpu0:%d, cpu1:%d, cpu2:%d\n",
|
||||
DTEST_SPINLOCK_TEST_CNT, cnt_0, cnt_1, cnt_2);
|
||||
break;
|
||||
}
|
||||
#if DTEST_SPINLOCK_CORE0_USE_SPINLOCK
|
||||
iot_spinlock_unlock(DTEST_SPINLOCK_TEST_NUM, cpu);
|
||||
#endif
|
||||
}
|
||||
|
||||
ahb_core1_disable();
|
||||
ahb_core1_reset();
|
||||
ahb_core2_disable();
|
||||
ahb_core2_reset();
|
||||
|
||||
time_end = gp_timer_get_current_val(0);
|
||||
time_delta = (time_end >= time_start) ? (time_end - time_start) :
|
||||
(0xffffffff - time_start + time_start);
|
||||
dprintf("time start:%d, end:%d, delta:%d\n", time_start, time_end, time_delta);
|
||||
|
||||
if (i == 0) {
|
||||
dcase_failed();
|
||||
return ERR_FAIL;
|
||||
}
|
||||
|
||||
dcase_success();
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static void dtest_spinlock_main()
|
||||
{
|
||||
uint32_t case_group = 0, failed_cnt = 0;
|
||||
|
||||
dbg_uart_init();
|
||||
|
||||
gp_timer_init();
|
||||
gp_timer_set(0, 0xffffffff, 0);
|
||||
gp_timer_start(0);
|
||||
|
||||
dconfig();
|
||||
dstart();
|
||||
dversion();
|
||||
|
||||
if (dtest_get_case_group(&case_group) < 0) {
|
||||
case_group = 0xffffffff;
|
||||
}
|
||||
dprintf("get case group:0x%08X\n", case_group);
|
||||
|
||||
iot_spinlock_init();
|
||||
|
||||
if (case_group & DTEST_SPINLOCK_CASE_MUTEX) {
|
||||
if (dtest_spinlock_multicore_mutex_test()) {
|
||||
failed_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
if (failed_cnt) {
|
||||
dprintf("spinlock dtest failed\n");
|
||||
} else {
|
||||
dprintf("spinlock dtest succeed\n");
|
||||
}
|
||||
|
||||
dend();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
dtest_spinlock_main();
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user