forked from xuos/xiuos
Add board k210-emulator
This commit is contained in:
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
SRC_FILES := drv_interrupt.c plic.c clint.c
|
||||
|
||||
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
@@ -0,0 +1,229 @@
|
||||
/* Copyright 2018 Canaan 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file clint.c
|
||||
* @brief add from Canaan k210 SDK
|
||||
* https://canaan-creative.com/developer
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "encoding.h"
|
||||
#include "clint.h"
|
||||
#include "sysctl.h"
|
||||
|
||||
volatile clint_t* const clint = (volatile clint_t*)CLINT_BASE_ADDR;
|
||||
static clint_timer_instance_t clint_timer_instance[CLINT_NUM_CORES];
|
||||
static clint_ipi_instance_t clint_ipi_instance[CLINT_NUM_CORES];
|
||||
|
||||
uint64_t clint_get_time(void)
|
||||
{
|
||||
/* No difference on cores */
|
||||
return clint->mtime;
|
||||
}
|
||||
|
||||
int clint_timer_init(void)
|
||||
{
|
||||
/* Read core id */
|
||||
unsigned long core_id = current_coreid();
|
||||
/* Clear the Machine-Timer bit in MIE */
|
||||
CLEAR_CSR(mie, MIP_MTIP);
|
||||
/* Fill core's instance with original data */
|
||||
|
||||
/* clang-format off */
|
||||
clint_timer_instance[core_id] = (const clint_timer_instance_t)
|
||||
{
|
||||
.interval = 0,
|
||||
.cycles = 0,
|
||||
.single_shot = 0,
|
||||
.callback = NULL,
|
||||
.ctx = NULL,
|
||||
};
|
||||
/* clang-format on */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clint_timer_stop(void)
|
||||
{
|
||||
/* Clear the Machine-Timer bit in MIE */
|
||||
CLEAR_CSR(mie, MIP_MTIP);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t clint_timer_get_freq(void)
|
||||
{
|
||||
/* The clock is divided by CLINT_CLOCK_DIV */
|
||||
return SysctlClockGetFreq(SYSCTL_CLOCK_CPU) / CLINT_CLOCK_DIV;
|
||||
}
|
||||
|
||||
int clint_timer_start(uint64_t interval, int single_shot)
|
||||
{
|
||||
/* Read core id */
|
||||
unsigned long core_id = current_coreid();
|
||||
/* Set timer interval */
|
||||
if (clint_timer_set_interval(interval) != 0)
|
||||
return -1;
|
||||
/* Set timer single shot */
|
||||
if (clint_timer_set_single_shot(single_shot) != 0)
|
||||
return -1;
|
||||
/* Check settings to prevent interval is 0 */
|
||||
if (clint_timer_instance[core_id].interval == 0)
|
||||
return -1;
|
||||
/* Check settings to prevent cycles is 0 */
|
||||
if (clint_timer_instance[core_id].cycles == 0)
|
||||
return -1;
|
||||
/* Add cycle interval to mtimecmp */
|
||||
uint64_t now = clint->mtime;
|
||||
uint64_t then = now + clint_timer_instance[core_id].cycles;
|
||||
/* Set mtimecmp by core id */
|
||||
clint->mtimecmp[core_id] = then;
|
||||
/* Enable interrupts in general */
|
||||
SET_CSR(mstatus, MSTATUS_MIE);
|
||||
/* Enable the Machine-Timer bit in MIE */
|
||||
SET_CSR(mie, MIP_MTIP);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t clint_timer_get_interval(void)
|
||||
{
|
||||
/* Read core id */
|
||||
unsigned long core_id = current_coreid();
|
||||
return clint_timer_instance[core_id].interval;
|
||||
}
|
||||
|
||||
int clint_timer_set_interval(uint64_t interval)
|
||||
{
|
||||
/* Read core id */
|
||||
unsigned long core_id = current_coreid();
|
||||
/* Check parameter */
|
||||
if (interval == 0)
|
||||
return -1;
|
||||
|
||||
/* Assign user interval with Millisecond(ms) */
|
||||
clint_timer_instance[core_id].interval = interval;
|
||||
/* Convert interval to cycles */
|
||||
clint_timer_instance[core_id].cycles = interval * clint_timer_get_freq() / 1000ULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clint_timer_get_single_shot(void)
|
||||
{
|
||||
/* Read core id */
|
||||
unsigned long core_id = current_coreid();
|
||||
/* Get single shot mode by core id */
|
||||
return clint_timer_instance[core_id].single_shot;
|
||||
}
|
||||
|
||||
int clint_timer_set_single_shot(int single_shot)
|
||||
{
|
||||
/* Read core id */
|
||||
unsigned long core_id = current_coreid();
|
||||
/* Set single shot mode by core id */
|
||||
clint_timer_instance[core_id].single_shot = single_shot;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clint_timer_register(clint_timer_callback_t callback, void *ctx)
|
||||
{
|
||||
/* Read core id */
|
||||
unsigned long core_id = current_coreid();
|
||||
/* Set user callback function */
|
||||
clint_timer_instance[core_id].callback = callback;
|
||||
/* Assign user context */
|
||||
clint_timer_instance[core_id].ctx = ctx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clint_timer_unregister(void)
|
||||
{
|
||||
/* Just assign NULL to user callback function and context */
|
||||
return clint_timer_register(NULL, NULL);
|
||||
}
|
||||
|
||||
int clint_ipi_init(void)
|
||||
{
|
||||
/* Read core id */
|
||||
unsigned long core_id = current_coreid();
|
||||
/* Clear the Machine-Software bit in MIE */
|
||||
CLEAR_CSR(mie, MIP_MSIP);
|
||||
/* Fill core's instance with original data */
|
||||
/* clang-format off */
|
||||
clint_ipi_instance[core_id] = (const clint_ipi_instance_t){
|
||||
.callback = NULL,
|
||||
.ctx = NULL,
|
||||
};
|
||||
/* clang-format on */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clint_ipi_enable(void)
|
||||
{
|
||||
/* Enable interrupts in general */
|
||||
SET_CSR(mstatus, MSTATUS_MIE);
|
||||
/* Set the Machine-Software bit in MIE */
|
||||
SET_CSR(mie, MIP_MSIP);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clint_ipi_disable(void)
|
||||
{
|
||||
/* Clear the Machine-Software bit in MIE */
|
||||
CLEAR_CSR(mie, MIP_MSIP);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clint_ipi_send(size_t core_id)
|
||||
{
|
||||
if (core_id >= CLINT_NUM_CORES)
|
||||
return -1;
|
||||
clint->msip[core_id].msip = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clint_ipi_clear(size_t core_id)
|
||||
{
|
||||
if (core_id >= CLINT_NUM_CORES)
|
||||
return -1;
|
||||
if (clint->msip[core_id].msip)
|
||||
{
|
||||
clint->msip[core_id].msip = 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clint_ipi_register(clint_ipi_callback_t callback, void *ctx)
|
||||
{
|
||||
/* Read core id */
|
||||
unsigned long core_id = current_coreid();
|
||||
/* Set user callback function */
|
||||
clint_ipi_instance[core_id].callback = callback;
|
||||
/* Assign user context */
|
||||
clint_ipi_instance[core_id].ctx = ctx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clint_ipi_unregister(void)
|
||||
{
|
||||
/* Just assign NULL to user callback function and context */
|
||||
return clint_ipi_register(NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/* Copyright 2018 Canaan 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file drv_interrupt.c
|
||||
* @brief add from Canaan k210 SDK
|
||||
* https://canaan-creative.com/developer
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
#include <plic.h>
|
||||
|
||||
void PlicIrqHandle(plic_irq_t irq)
|
||||
{
|
||||
plic_instance_t (*plic_instance)[IRQN_MAX] = plic_get_instance();
|
||||
if (plic_instance[0][irq].callback)
|
||||
{
|
||||
plic_instance[0][irq].callback(
|
||||
plic_instance[0][irq].ctx);
|
||||
}
|
||||
else if (plic_instance[1][irq].callback)
|
||||
{
|
||||
plic_instance[1][irq].callback(
|
||||
plic_instance[1][irq].ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,219 @@
|
||||
/* Copyright 2018 Canaan 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file plic.c
|
||||
* @brief add from Canaan k210 SDK
|
||||
* https://canaan-creative.com/developer
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-04-25
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "encoding.h"
|
||||
#include "plic.h"
|
||||
#include "syscalls.h"
|
||||
#include "syslog.h"
|
||||
|
||||
volatile plic_t* const plic = (volatile plic_t*)PLIC_BASE_ADDR;
|
||||
|
||||
static plic_instance_t plic_instance[PLIC_NUM_CORES][IRQN_MAX];
|
||||
|
||||
void plic_init(void)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
/* Get current core id */
|
||||
unsigned long core_id = current_coreid();
|
||||
|
||||
/* Disable all interrupts for the current core. */
|
||||
for (i = 0; i < ((PLIC_NUM_SOURCES + 32u) / 32u); i++)
|
||||
plic->target_enables.target[core_id].enable[i] = 0;
|
||||
|
||||
static uint8_t s_plic_priorities_init_flag = 0;
|
||||
/* Set priorities to zero. */
|
||||
if(s_plic_priorities_init_flag == 0)
|
||||
{
|
||||
for (i = 0; i < PLIC_NUM_SOURCES; i++)
|
||||
plic->source_priorities.priority[i] = 0;
|
||||
s_plic_priorities_init_flag = 1;
|
||||
}
|
||||
|
||||
/* Set the threshold to zero. */
|
||||
plic->targets.target[core_id].priority_threshold = 0;
|
||||
|
||||
/* Clear PLIC instance for every cores */
|
||||
for (i = 0; i < IRQN_MAX; i++)
|
||||
{
|
||||
/* clang-format off */
|
||||
plic_instance[core_id][i] = (const plic_instance_t){
|
||||
.callback = NULL,
|
||||
.ctx = NULL,
|
||||
};
|
||||
/* clang-format on */
|
||||
}
|
||||
|
||||
/*
|
||||
* A successful claim will also atomically clear the corresponding
|
||||
* pending bit on the interrupt source. A target can perform a claim
|
||||
* at any time, even if the EIP is not set.
|
||||
*/
|
||||
i = 0;
|
||||
while (plic->targets.target[core_id].claim_complete > 0 && i < 100)
|
||||
{
|
||||
/* This loop will clear pending bit on the interrupt source */
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Enable machine external interrupts. */
|
||||
SET_CSR(mie, MIP_MEIP);
|
||||
}
|
||||
|
||||
int plic_irq_enable(plic_irq_t irq_number)
|
||||
{
|
||||
/* Check parameters */
|
||||
if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number)
|
||||
return -1;
|
||||
unsigned long core_id = current_coreid();
|
||||
/* Get current enable bit array by IRQ number */
|
||||
uint32_t current = plic->target_enables.target[core_id].enable[irq_number / 32];
|
||||
/* Set enable bit in enable bit array */
|
||||
current |= (uint32_t)1 << (irq_number % 32);
|
||||
/* Write back the enable bit array */
|
||||
plic->target_enables.target[core_id].enable[irq_number / 32] = current;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plic_irq_disable(plic_irq_t irq_number)
|
||||
{
|
||||
/* Check parameters */
|
||||
if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number)
|
||||
return -1;
|
||||
unsigned long core_id = current_coreid();
|
||||
/* Get current enable bit array by IRQ number */
|
||||
uint32_t current = plic->target_enables.target[core_id].enable[irq_number / 32];
|
||||
/* Clear enable bit in enable bit array */
|
||||
current &= ~((uint32_t)1 << (irq_number % 32));
|
||||
/* Write back the enable bit array */
|
||||
plic->target_enables.target[core_id].enable[irq_number / 32] = current;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plic_set_priority(plic_irq_t irq_number, uint32_t priority)
|
||||
{
|
||||
/* Check parameters */
|
||||
if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number)
|
||||
return -1;
|
||||
/* Set interrupt priority by IRQ number */
|
||||
plic->source_priorities.priority[irq_number] = priority;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t plic_get_priority(plic_irq_t irq_number)
|
||||
{
|
||||
/* Check parameters */
|
||||
if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number)
|
||||
return 0;
|
||||
/* Get interrupt priority by IRQ number */
|
||||
return plic->source_priorities.priority[irq_number];
|
||||
}
|
||||
|
||||
uint32_t plic_irq_claim(void)
|
||||
{
|
||||
unsigned long core_id = current_coreid();
|
||||
/* Perform IRQ claim */
|
||||
return plic->targets.target[core_id].claim_complete;
|
||||
}
|
||||
|
||||
int plic_irq_complete(uint32_t source)
|
||||
{
|
||||
unsigned long core_id = current_coreid();
|
||||
/* Perform IRQ complete */
|
||||
plic->targets.target[core_id].claim_complete = source;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void plic_irq_register(plic_irq_t irq, plic_irq_callback_t callback, void *ctx)
|
||||
{
|
||||
/* Read core id */
|
||||
unsigned long core_id = current_coreid();
|
||||
/* Set user callback function */
|
||||
plic_instance[core_id][irq].callback = callback;
|
||||
/* Assign user context */
|
||||
plic_instance[core_id][irq].ctx = ctx;
|
||||
}
|
||||
|
||||
void plic_irq_unregister(plic_irq_t irq)
|
||||
{
|
||||
/* Just assign NULL to user callback function and context */
|
||||
plic_irq_register(irq, NULL, NULL);
|
||||
}
|
||||
|
||||
void __attribute__((weak, alias("plic_irq_unregister"))) plic_irq_deregister(plic_irq_t irq);
|
||||
|
||||
plic_instance_t (*plic_get_instance(void))[IRQN_MAX]
|
||||
{
|
||||
return plic_instance;
|
||||
}
|
||||
|
||||
/*Entry Point for PLIC Interrupt Handler*/
|
||||
uintptr_t __attribute__((weak))
|
||||
HandleIrqMExt(uintptr_t cause, uintptr_t epc)
|
||||
{
|
||||
/*
|
||||
* After the highest-priority pending interrupt is claimed by a target
|
||||
* and the corresponding IP bit is cleared, other lower-priority
|
||||
* pending interrupts might then become visible to the target, and so
|
||||
* the PLIC EIP bit might not be cleared after a claim. The interrupt
|
||||
* handler can check the local meip/heip/seip/ueip bits before exiting
|
||||
* the handler, to allow more efficient service of other interrupts
|
||||
* without first restoring the interrupted context and taking another
|
||||
* interrupt trap.
|
||||
*/
|
||||
if (READ_CSR(mip) & MIP_MEIP)
|
||||
{
|
||||
/* Get current core id */
|
||||
uint64_t core_id = current_coreid();
|
||||
/* Get primitive interrupt enable flag */
|
||||
uint64_t ie_flag = READ_CSR(mie);
|
||||
/* Get current IRQ num */
|
||||
uint32_t int_num = plic->targets.target[core_id].claim_complete;
|
||||
/* Get primitive IRQ threshold */
|
||||
uint32_t int_threshold = plic->targets.target[core_id].priority_threshold;
|
||||
/* Set new IRQ threshold = current IRQ threshold */
|
||||
plic->targets.target[core_id].priority_threshold = plic->source_priorities.priority[int_num];
|
||||
/* Disable software interrupt and timer interrupt */
|
||||
CLEAR_CSR(mie, MIP_MTIP | MIP_MSIP);
|
||||
/* Enable global interrupt */
|
||||
SET_CSR(mstatus, MSTATUS_MIE);
|
||||
if (plic_instance[core_id][int_num].callback)
|
||||
plic_instance[core_id][int_num].callback(
|
||||
plic_instance[core_id][int_num].ctx);
|
||||
/* Perform IRQ complete */
|
||||
plic->targets.target[core_id].claim_complete = int_num;
|
||||
/* Disable global interrupt */
|
||||
CLEAR_CSR(mstatus, MSTATUS_MIE);
|
||||
/* Set MPIE and MPP flag used to MRET instructions restore MIE flag */
|
||||
SET_CSR(mstatus, MSTATUS_MPIE | MSTATUS_MPP);
|
||||
/* Restore primitive interrupt enable flag */
|
||||
WRITE_CSR(mie, ie_flag);
|
||||
/* Restore primitive IRQ threshold */
|
||||
plic->targets.target[core_id].priority_threshold = int_threshold;
|
||||
}
|
||||
|
||||
return epc;
|
||||
}
|
||||
Reference in New Issue
Block a user