Compare commits
7 Commits
e150e2e78e
...
d75c373da7
Author | SHA1 | Date | |
---|---|---|---|
d75c373da7 | |||
b8f273c9b6 | |||
9487f5c2ef | |||
f21122c54b | |||
0943656548 | |||
4ca35ca18c | |||
539d2e0908 |
@ -46,6 +46,7 @@ $(BUILD_DIR)/netlist-post-synthesis.json: $(VU_FLAG) $(SOURCES_VERILOG)
|
||||
# Collect GHDL sources from VUnit
|
||||
$(eval GHDLINCDIRS=$(shell find "$(VU_DIR)/ghdl/libraries" -maxdepth 1 -mindepth 1 -type d | sed "s/^/-P/" | tr '\n' ' '))
|
||||
yosys -m ghdl -p "read_verilog $(SOURCES_VERILOG); ghdl --std=08 $(GHDLINCDIRS) design.top; synth_ice40 -abc9 -device $(YOSYS_DEVICE) -top top -json $@"
|
||||
./patch_asserts.sh $@
|
||||
|
||||
$(BUILD_DIR)/netlist-post-pnr.asc: $(BUILD_DIR)/netlist-post-synthesis.json $(CONSTRAINTS)
|
||||
nextpnr-ice40 --$(DEVICE) --package $(PACKAGE) --asc $(BUILD_DIR)/netlist-post-pnr.asc --report $(BUILD_DIR)/report.json --detailed-timing-report --json $(BUILD_DIR)/netlist-post-synthesis.json --pcf $(CONSTRAINTS)
|
||||
|
181
fpga/hdl/bench/bench_top_zephyr.vhd
Normal file
181
fpga/hdl/bench/bench_top_zephyr.vhd
Normal file
@ -0,0 +1,181 @@
|
||||
-- -------------------------------------------------------------------------- --
|
||||
-- TRASHERNET SoC - A Trashy Ethernet SoC for FPGAs --
|
||||
-- -------------------------------------------------------------------------- --
|
||||
-- Inspection-only test bench to run a larger memory image from external RAM.
|
||||
-- -------------------------------------------------------------------------- --
|
||||
-- Author : Markus Koch <markus@notsyncing.net>
|
||||
-- Contributors : None
|
||||
-- License : Mozilla Public License (MPL) Version 2
|
||||
-- -------------------------------------------------------------------------- --
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use std.textio.all;
|
||||
|
||||
library design;
|
||||
use design.all;
|
||||
|
||||
library generics;
|
||||
use generics.wishbone_pkg.all;
|
||||
|
||||
library device_models;
|
||||
use device_models.all;
|
||||
|
||||
library vunit_lib;
|
||||
context vunit_lib.vunit_context;
|
||||
|
||||
library osvvm;
|
||||
context osvvm.osvvmContext;
|
||||
use osvvm.ScoreboardPkg_slv.all;
|
||||
|
||||
entity bench_top_zephyr is
|
||||
generic(
|
||||
runner_cfg : string := runner_cfg_default
|
||||
);
|
||||
end entity bench_top_zephyr;
|
||||
|
||||
architecture RTL of bench_top_zephyr is
|
||||
constant UART_BAUD : integer := 250000;
|
||||
signal clk_in : std_logic;
|
||||
signal uart_tx : std_logic;
|
||||
signal uart_rx : std_logic;
|
||||
signal eth_rx_p : std_logic;
|
||||
signal eth_tx_p : std_logic_vector(3 downto 0);
|
||||
signal eth_tx_n : std_logic_vector(3 downto 0);
|
||||
signal eth_led_green_n : std_logic;
|
||||
signal eth_led_orange_n : std_logic;
|
||||
signal led_user : std_logic;
|
||||
signal psram_ce_n : std_logic;
|
||||
signal psram_sclk : std_logic;
|
||||
signal psram_sio : std_logic_vector(3 downto 0);
|
||||
signal flash_ce_n : std_logic;
|
||||
signal flash_sclk : std_logic;
|
||||
signal flash_sio : std_logic_vector(3 downto 0);
|
||||
signal pmod : std_logic_vector(7 downto 0);
|
||||
|
||||
begin
|
||||
top_inst : entity design.top
|
||||
generic map(
|
||||
F_IN => 50000000,
|
||||
F_CLK => 25000000,
|
||||
F_CLK_PHY => 50000000,
|
||||
UART_BAUD => UART_BAUD,
|
||||
CPU => "neorv32"
|
||||
)
|
||||
port map(
|
||||
clk_in => clk_in,
|
||||
uart_tx => uart_tx,
|
||||
uart_rx => uart_rx,
|
||||
eth_rx_p => eth_rx_p,
|
||||
eth_tx_p => eth_tx_p,
|
||||
eth_tx_n => eth_tx_n,
|
||||
eth_led_green_n => eth_led_green_n,
|
||||
eth_led_orange_n => eth_led_orange_n,
|
||||
led_user => led_user,
|
||||
psram_ce_n => psram_ce_n,
|
||||
psram_sclk => psram_sclk,
|
||||
psram_sio => psram_sio,
|
||||
flash_ce_n => flash_ce_n,
|
||||
flash_sclk => flash_sclk,
|
||||
flash_sio => flash_sio,
|
||||
pmod => pmod
|
||||
);
|
||||
|
||||
aps6404l_inst : entity device_models.aps6404l
|
||||
generic map(
|
||||
SIZE => 8 * 1024 * 1024,
|
||||
--MEMFILE => "../sw/demo/decrypt-1.vhex",
|
||||
LOG_EN => false
|
||||
)
|
||||
port map(
|
||||
ce_n => psram_ce_n,
|
||||
sclk => psram_sclk,
|
||||
sio => psram_sio
|
||||
);
|
||||
|
||||
uart_decoder : process is
|
||||
constant DELAY : time := (1 sec / UART_BAUD);
|
||||
variable d : std_logic_vector(7 downto 0);
|
||||
variable print_time : boolean := true;
|
||||
procedure print(text : character) is
|
||||
variable lb : line;
|
||||
begin
|
||||
write(lb, text);
|
||||
write(output, lb.all);
|
||||
flush(output);
|
||||
end procedure print;
|
||||
begin
|
||||
wait until falling_edge(uart_tx);
|
||||
wait for 0.5 * DELAY;
|
||||
for i in 0 to 7 loop
|
||||
wait for DELAY;
|
||||
d(i) := uart_tx;
|
||||
end loop;
|
||||
wait for 1.0 * DELAY;
|
||||
if print_time then
|
||||
write(output, "{" & time'image(now) & "} ");
|
||||
print_time := false;
|
||||
end if;
|
||||
print(character'val(to_integer(unsigned(d))));
|
||||
if character'val(to_integer(unsigned(d))) = LF then
|
||||
print_time := true;
|
||||
end if;
|
||||
--report "UART RX: " & character'val(to_integer(unsigned(d)));
|
||||
end process uart_decoder;
|
||||
|
||||
test : process is
|
||||
procedure uart_tx(d : std_logic_vector(7 downto 0)) is
|
||||
constant DELAY : time := (1 sec / UART_BAUD);
|
||||
begin
|
||||
uart_rx <= '0';
|
||||
wait for DELAY;
|
||||
for i in d'low to d'high loop
|
||||
uart_rx <= d(i);
|
||||
wait for DELAY;
|
||||
end loop;
|
||||
uart_rx <= '1';
|
||||
wait for DELAY;
|
||||
end procedure uart_tx;
|
||||
|
||||
begin
|
||||
test_runner_setup(runner, runner_cfg);
|
||||
|
||||
report "Waiting for internal reset to be complete...";
|
||||
wait for 10 us;
|
||||
report "Starting tests...";
|
||||
|
||||
while test_suite loop
|
||||
if run("run_program") then
|
||||
uart_rx <= '1';
|
||||
wait for (1 sec / UART_BAUD) * 10;
|
||||
|
||||
report ("Jumping to external RAM...");
|
||||
-- JUMP
|
||||
uart_tx(x"03");
|
||||
|
||||
-- to RAM (+4, jalr zero)
|
||||
uart_tx(x"40");
|
||||
uart_tx(x"00");
|
||||
uart_tx(x"00");
|
||||
uart_tx(x"00");
|
||||
|
||||
report ("This is a manual test. Add wait statement here and watch the output...");
|
||||
wait for 0 ns;
|
||||
report ("Stopping test.");
|
||||
end if;
|
||||
end loop;
|
||||
test_runner_cleanup(runner);
|
||||
end process test;
|
||||
|
||||
test_runner_watchdog(runner, 1000 ms);
|
||||
|
||||
clock_driver : process
|
||||
constant period : time := 20 ns;
|
||||
begin
|
||||
clk_in <= '0';
|
||||
wait for period / 2;
|
||||
clk_in <= '1';
|
||||
wait for period - (period / 2);
|
||||
end process clock_driver;
|
||||
end architecture RTL;
|
@ -237,10 +237,10 @@ begin
|
||||
|
||||
servant_rom_vhdl_inst : entity work.servant_ram_vhdl
|
||||
generic map(
|
||||
memfile => "../sw/bootrom/bootrom.vhex",
|
||||
read_only => true,
|
||||
adr_width => 9,
|
||||
force_vlog => not in_simulation -- GHDL + Yosys doesn't keep the memfile
|
||||
memfile => "../sw/bootrom/bootrom.vhex",
|
||||
read_only => true,
|
||||
adr_width => 9,
|
||||
force_vlog => not in_simulation -- GHDL + Yosys doesn't keep the memfile
|
||||
)
|
||||
port map(
|
||||
clk => clk,
|
||||
|
@ -16,7 +16,9 @@ use std.textio.all;
|
||||
|
||||
entity aps6404l is
|
||||
generic(
|
||||
LOG_EN : boolean := true
|
||||
SIZE : natural := 1024;
|
||||
LOG_EN : boolean := true;
|
||||
MEMFILE : string := ""
|
||||
);
|
||||
port(
|
||||
ce_n : in std_logic;
|
||||
@ -41,7 +43,24 @@ begin
|
||||
test : process is
|
||||
type rx_state_t is (COMMAND, READ, WRITE, COMPLETE);
|
||||
type byte_vector is array (natural range <>) of std_logic_vector(7 downto 0);
|
||||
variable mem : byte_vector(0 to 1023);
|
||||
subtype mem_t is byte_vector(0 to SIZE - 1);
|
||||
impure function init_ram_hex return mem_t is
|
||||
file text_file : text;
|
||||
variable text_line : line;
|
||||
variable ram_content : mem_t := (others => x"5A");
|
||||
begin
|
||||
if MEMFILE /= "" then
|
||||
file_open(text_file, MEMFILE, read_mode);
|
||||
for i in 0 to SIZE - 1 loop
|
||||
exit when endfile(text_file);
|
||||
readline(text_file, text_line);
|
||||
hread(text_line, ram_content(i));
|
||||
end loop;
|
||||
end if;
|
||||
|
||||
return ram_content;
|
||||
end function;
|
||||
variable mem : mem_t := init_ram_hex;
|
||||
variable bytes : byte_vector(0 to 32);
|
||||
variable cnt, bytecnt : integer;
|
||||
variable state : rx_state_t;
|
||||
@ -111,8 +130,13 @@ begin
|
||||
print(" Addr: " & to_hstring(bytes(1)) & to_hstring(bytes(2)) & to_hstring(bytes(3)));
|
||||
addr := to_integer(unsigned(std_logic_vector'(bytes(1), bytes(2), bytes(3))));
|
||||
elsif bytecnt > 4 then
|
||||
dout := mem(addr);
|
||||
print(" Read " & integer'image(addr) & ": " & to_hstring(mem(addr)));
|
||||
if addr < SIZE then
|
||||
dout := mem(addr);
|
||||
print(" Read " & integer'image(addr) & ": " & to_hstring(mem(addr)));
|
||||
else
|
||||
dout := (others => 'X');
|
||||
print(" Read " & integer'image(addr) & ": OUT-OF-BOUNDS");
|
||||
end if;
|
||||
addr := addr + 1;
|
||||
end if;
|
||||
|
||||
@ -122,8 +146,12 @@ begin
|
||||
addr := to_integer(unsigned(std_logic_vector'(bytes(1), bytes(2), bytes(3))));
|
||||
elsif bytecnt > 3 then
|
||||
print(" Write " & integer'image(addr) & ": " & to_hstring(bytes(bytecnt)));
|
||||
mem(addr) := bytes(bytecnt);
|
||||
addr := addr + 1;
|
||||
if (addr < SIZE) then
|
||||
mem(addr) := bytes(bytecnt);
|
||||
else
|
||||
print(" Error: OUT OF BOUNDS access! Ignoring write.");
|
||||
end if;
|
||||
addr := addr + 1;
|
||||
end if;
|
||||
|
||||
when COMPLETE =>
|
||||
|
14
fpga/patch_asserts.sh
Executable file
14
fpga/patch_asserts.sh
Executable file
@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
file="$1"
|
||||
echo "Removing \$assert from $file..."
|
||||
|
||||
LOCS=`grep -n '$assert' "$file" | sed 's/:.*//g'`
|
||||
|
||||
IFS=$'\n'
|
||||
for LOC in $LOCS; do
|
||||
START=$(($LOC-2))
|
||||
END=$(($LOC+14))
|
||||
echo "Deleting lines $START -> $END"
|
||||
sed -i -e "${START},${END}d" "$file"
|
||||
done
|
@ -57,6 +57,7 @@ if not "osvvm" in libs:
|
||||
vu.add_compile_option("ghdl.a_flags", ["-frelaxed", "-fsynopsys"])
|
||||
vu.add_compile_option("nvc.a_flags", ["--relaxed"])
|
||||
#vu.set_sim_option("nvc.elab_flags", ["-O3"])
|
||||
vu.set_sim_option("nvc.sim_flags", ["--format=fst", "--wave=wave.fst"])
|
||||
vu.set_sim_option("nvc.heap_size", "256M")
|
||||
vu.set_sim_option("nvc.sim_flags", ["--format=fst", "--wave=wave.fst", "--dump-arrays"])
|
||||
|
||||
vu.main()
|
||||
|
9
zephyr/west.yml
Normal file
9
zephyr/west.yml
Normal file
@ -0,0 +1,9 @@
|
||||
manifest:
|
||||
remotes:
|
||||
- name: zephyrproject-rtos
|
||||
url-base: https://github.com/zephyrproject-rtos
|
||||
projects:
|
||||
- name: zephyr
|
||||
remote: zephyrproject-rtos
|
||||
revision: v3.7.0
|
||||
import: true
|
4
zephyr/zephyr/CMakeLists.txt
Normal file
4
zephyr/zephyr/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
add_subdirectory(drivers)
|
8
zephyr/zephyr/Kconfig
Normal file
8
zephyr/zephyr/Kconfig
Normal file
@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
menu "SweRVolf"
|
||||
|
||||
rsource "drivers/Kconfig"
|
||||
|
||||
endmenu
|
8
zephyr/zephyr/boards/riscv/trashernet_soc/Kconfig.board
Normal file
8
zephyr/zephyr/boards/riscv/trashernet_soc/Kconfig.board
Normal file
@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# Copyright (c) 2024 Markus Koch <markus@notsyncing.net>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config BOARD_TRASHERNET_SOC
|
||||
bool "Trashernet SoC"
|
||||
depends on SOC_RISCV32_SERVANT
|
13
zephyr/zephyr/boards/riscv/trashernet_soc/Kconfig.defconfig
Normal file
13
zephyr/zephyr/boards/riscv/trashernet_soc/Kconfig.defconfig
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# Copyright (c) 2024 Markus Koch <markus@notsyncing.net>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config BOARD
|
||||
default "trashernet_soc"
|
||||
depends on BOARD_TRASHERNET_SOC
|
||||
|
||||
config ETH_TRASHERNET
|
||||
bool
|
||||
default y
|
||||
depends on NET_L2_ETHERNET
|
17
zephyr/zephyr/boards/riscv/trashernet_soc/trashernet.yaml
Normal file
17
zephyr/zephyr/boards/riscv/trashernet_soc/trashernet.yaml
Normal file
@ -0,0 +1,17 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# Copyright (c) 2024 Markus Koch <markus@notsyncing.net>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
identifier: trashernet_soc
|
||||
name: Trashernet SoC
|
||||
type: mcu
|
||||
arch: riscv32
|
||||
toolchain:
|
||||
- zephyr
|
||||
ram: 32
|
||||
vendor: notsyncing.net
|
||||
testing:
|
||||
ignore_tags:
|
||||
- net
|
||||
- bluetooth
|
40
zephyr/zephyr/boards/riscv/trashernet_soc/trashernet_soc.dts
Normal file
40
zephyr/zephyr/boards/riscv/trashernet_soc/trashernet_soc.dts
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
* Copyright (c) 2024 Markus Koch <markus@notsyncing.net>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
#include <serv.dtsi>
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
zephyr,sram = &ram;
|
||||
zephyr,console = &uart0;
|
||||
};
|
||||
|
||||
ram: memory@0 {
|
||||
compatible = "mmio-sram";
|
||||
reg = <0x40000000 0x800000>;
|
||||
};
|
||||
|
||||
soc {
|
||||
compatible = "olofk,serv";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
uart0: serial@0 {
|
||||
reg = <0x0 0x1>;
|
||||
compatible = "trashernet,serial";
|
||||
};
|
||||
|
||||
eth0: ethernet@0 {
|
||||
reg = <0x0 0x1>;
|
||||
compatible = "notsyncing,trashernet";
|
||||
local-mac-address = [10 b1 7d df 6f db];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -0,0 +1,13 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# Copyright (c) 2024 Markus Koch <markus@notsyncing.net>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
CONFIG_BOARD_TRASHERNET_SOC=y
|
||||
CONFIG_CONSOLE=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_UART_TRASHERNET=y
|
||||
CONFIG_NET_L2_ETHERNET=y
|
||||
CONFIG_UART_CONSOLE=y
|
||||
|
||||
CONFIG_XIP=n
|
7
zephyr/zephyr/drivers/CMakeLists.txt
Normal file
7
zephyr/zephyr/drivers/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
add_subdirectory_ifdef(CONFIG_SERIAL_HAS_DRIVER serial)
|
||||
add_subdirectory_ifdef(CONFIG_SYS_CLOCK_EXISTS timer)
|
||||
add_subdirectory_ifdef(CONFIG_ETH_TRASHERNET trashernet)
|
||||
|
12
zephyr/zephyr/drivers/Kconfig
Normal file
12
zephyr/zephyr/drivers/Kconfig
Normal file
@ -0,0 +1,12 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
menu "Device Drivers"
|
||||
|
||||
rsource "serial/Kconfig"
|
||||
|
||||
rsource "timer/Kconfig"
|
||||
|
||||
rsource "trashernet/Kconfig"
|
||||
|
||||
endmenu
|
7
zephyr/zephyr/drivers/serial/CMakeLists.txt
Normal file
7
zephyr/zephyr/drivers/serial/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# Copyright (c) 2024 Markus Koch <markus@notsyncing.net>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
set(ZEPHYR_CURRENT_LIBRARY drivers__serial)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_UART_TRASHERNET uart_trashernet.c)
|
13
zephyr/zephyr/drivers/serial/Kconfig
Normal file
13
zephyr/zephyr/drivers/serial/Kconfig
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# Copyright (c) 2024 Markus Koch <markus@notsyncing.net>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
if SERIAL
|
||||
|
||||
menuconfig UART_TRASHERNET
|
||||
bool "Trashernet serial driver"
|
||||
select SERIAL_HAS_DRIVER
|
||||
help
|
||||
Enables the Trashernet serial driver
|
||||
|
||||
endif
|
79
zephyr/zephyr/drivers/serial/uart_trashernet.c
Normal file
79
zephyr/zephyr/drivers/serial/uart_trashernet.c
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
* Copyright (c) 2024 Markus Koch <markus@notsyncing.net>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/arch/cpu.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/uart.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define UART0_BASE 0x81000000
|
||||
#define UART0_SR (*((volatile uint32_t *) (UART0_BASE + 0x00)))
|
||||
#define UART0_DR (*((volatile uint32_t *) (UART0_BASE + 0x04)))
|
||||
|
||||
#define UART0_SR_RX_DATA_EMPTY (1 << 0)
|
||||
#define UART0_SR_TX_FULL (1 << 1)
|
||||
|
||||
#define DT_DRV_COMPAT trashernet_serial
|
||||
|
||||
static struct k_spinlock lock;
|
||||
|
||||
static void uart_trashernet_poll_out(const struct device *dev, unsigned char c)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
k_spinlock_key_t key = k_spin_lock(&lock);
|
||||
|
||||
while (UART0_SR & UART0_SR_TX_FULL);
|
||||
UART0_DR = c;
|
||||
|
||||
k_spin_unlock(&lock, key);
|
||||
}
|
||||
|
||||
static int uart_trashernet_poll_in(const struct device *dev, unsigned char *c)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
*c = UART0_DR;
|
||||
|
||||
return (UART0_SR & UART0_SR_RX_DATA_EMPTY) ? -1 : 0;
|
||||
}
|
||||
|
||||
static int uart_trashernet_init(const struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct uart_driver_api uart_trashernet_driver_api = {
|
||||
.poll_in = uart_trashernet_poll_in,
|
||||
.poll_out = uart_trashernet_poll_out,
|
||||
.err_check = NULL,
|
||||
};
|
||||
|
||||
struct my_dev_data {
|
||||
|
||||
};
|
||||
|
||||
struct my_dev_cfg {
|
||||
|
||||
};
|
||||
|
||||
#define CREATE_MY_DEVICE(inst) \
|
||||
static struct my_dev_data my_data_##inst = { \
|
||||
}; \
|
||||
static const struct my_dev_cfg my_cfg_##inst = { \
|
||||
}; \
|
||||
DEVICE_DT_INST_DEFINE(inst, \
|
||||
uart_trashernet_init, \
|
||||
NULL, \
|
||||
&my_data_##inst, \
|
||||
&my_cfg_##inst, \
|
||||
PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \
|
||||
&uart_trashernet_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(CREATE_MY_DEVICE)
|
5
zephyr/zephyr/drivers/timer/CMakeLists.txt
Normal file
5
zephyr/zephyr/drivers/timer/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_SERV_TIMER serv_timer.c)
|
||||
|
9
zephyr/zephyr/drivers/timer/Kconfig
Normal file
9
zephyr/zephyr/drivers/timer/Kconfig
Normal file
@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config SERV_TIMER
|
||||
bool "SERV Timer"
|
||||
select TICKLESS_CAPABLE
|
||||
help
|
||||
This module implements a kernel device driver for the SERV
|
||||
timer driver. It provides the standard "system clock driver" interfaces.
|
142
zephyr/zephyr/drivers/timer/serv_timer.c
Normal file
142
zephyr/zephyr/drivers/timer/serv_timer.c
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
This is basically a 32-bit version of riscv_machine_timer.c for Zephyr
|
||||
*/
|
||||
#include <zephyr/drivers/timer/system_timer.h>
|
||||
#include <zephyr/sys_clock.h>
|
||||
#include <zephyr/spinlock.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <soc.h>
|
||||
|
||||
#define CYC_PER_TICK ((uint32_t)((uint32_t)sys_clock_hw_cycles_per_sec() \
|
||||
/ (uint32_t)CONFIG_SYS_CLOCK_TICKS_PER_SEC))
|
||||
#define MAX_CYC 0xffffffffu
|
||||
#define MAX_TICKS ((MAX_CYC - CYC_PER_TICK) / CYC_PER_TICK)
|
||||
#define MIN_DELAY 1000
|
||||
|
||||
#define TICKLESS IS_ENABLED(CONFIG_TICKLESS_KERNEL)
|
||||
|
||||
static struct k_spinlock lock;
|
||||
static uint32_t last_count;
|
||||
|
||||
static ALWAYS_INLINE void set_mtimecmp(uint32_t time)
|
||||
{
|
||||
//printk("set_mtimecmp to %d @ %d\n", time, sys_read32(SERV_TIMER_BASE));
|
||||
sys_write32(time, SERV_TIMER_BASE);
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE uint32_t mtime(void)
|
||||
{
|
||||
return sys_read32(SERV_TIMER_BASE);
|
||||
}
|
||||
|
||||
static void timer_isr(void *arg)
|
||||
{
|
||||
//printk("timer isr\n");
|
||||
ARG_UNUSED(arg);
|
||||
|
||||
k_spinlock_key_t key = k_spin_lock(&lock);
|
||||
uint32_t now = mtime();
|
||||
uint32_t dticks = ((now - last_count) / CYC_PER_TICK);
|
||||
|
||||
last_count += dticks * CYC_PER_TICK;
|
||||
|
||||
if (!TICKLESS) {
|
||||
uint32_t next = last_count + CYC_PER_TICK;
|
||||
|
||||
if ((int32_t)(next - now) < MIN_DELAY) {
|
||||
next += CYC_PER_TICK;
|
||||
}
|
||||
set_mtimecmp(next);
|
||||
}
|
||||
|
||||
k_spin_unlock(&lock, key);
|
||||
sys_clock_announce(IS_ENABLED(CONFIG_TICKLESS_KERNEL) ? dticks : 1);
|
||||
}
|
||||
|
||||
int irq_testy()
|
||||
{
|
||||
printk("test isr\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sys_clock_driver_init()
|
||||
{
|
||||
IRQ_CONNECT(RISCV_MACHINE_TIMER_IRQ, 0, timer_isr, NULL, 0);
|
||||
//IRQ_CONNECT(5, 0, irq_testy, NULL, 0);
|
||||
last_count = mtime();
|
||||
set_mtimecmp(last_count + (uint32_t)CYC_PER_TICK);
|
||||
//irq_enable(5);
|
||||
irq_enable(RISCV_MACHINE_TIMER_IRQ);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sys_clock_set_timeout(int32_t ticks, bool idle)
|
||||
{
|
||||
ARG_UNUSED(idle);
|
||||
|
||||
#if defined(CONFIG_TICKLESS_KERNEL)
|
||||
/* RISCV has no idle handler yet, so if we try to spin on the
|
||||
* logic below to reset the comparator, we'll always bump it
|
||||
* forward to the "next tick" due to MIN_DELAY handling and
|
||||
* the interrupt will never fire! Just rely on the fact that
|
||||
* the OS gave us the proper timeout already.
|
||||
*/
|
||||
if (idle) {
|
||||
return;
|
||||
}
|
||||
|
||||
ticks = ticks == K_TICKS_FOREVER ? MAX_TICKS : ticks;
|
||||
ticks = MAX(MIN(ticks - 1, (int32_t)MAX_TICKS), 0);
|
||||
|
||||
k_spinlock_key_t key = k_spin_lock(&lock);
|
||||
uint32_t now = mtime();
|
||||
uint32_t adj, cyc = ticks * CYC_PER_TICK;
|
||||
|
||||
/* Round up to next tick boundary. */
|
||||
adj = (now - last_count) + (CYC_PER_TICK - 1);
|
||||
if (cyc <= MAX_CYC - adj) {
|
||||
cyc += adj;
|
||||
} else {
|
||||
cyc = MAX_CYC;
|
||||
}
|
||||
cyc = (cyc / CYC_PER_TICK) * CYC_PER_TICK;
|
||||
|
||||
if ((int32_t)(cyc + last_count - now) < MIN_DELAY) {
|
||||
cyc += CYC_PER_TICK;
|
||||
}
|
||||
|
||||
set_mtimecmp(cyc + last_count);
|
||||
k_spin_unlock(&lock, key);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t sys_clock_elapsed(void)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
k_spinlock_key_t key = k_spin_lock(&lock);
|
||||
uint32_t ret = (mtime() - last_count) / CYC_PER_TICK;
|
||||
|
||||
k_spin_unlock(&lock, key);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t sys_timer_cycle_get_32(void)
|
||||
{
|
||||
return mtime();
|
||||
}
|
||||
|
||||
uint32_t sys_clock_cycle_get_32(void)
|
||||
{
|
||||
return mtime();
|
||||
}
|
||||
SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2,
|
||||
CONFIG_SYSTEM_CLOCK_INIT_PRIORITY);
|
5
zephyr/zephyr/drivers/trashernet/CMakeLists.txt
Normal file
5
zephyr/zephyr/drivers/trashernet/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
# Copyright (c) 2024 Markus Koch <markus@notsyncing.net>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_ETH_TRASHERNET trashernet.c)
|
||||
|
10
zephyr/zephyr/drivers/trashernet/Kconfig
Normal file
10
zephyr/zephyr/drivers/trashernet/Kconfig
Normal file
@ -0,0 +1,10 @@
|
||||
# Copyright (c) 2024 Markus Koch <markus@notsyncing.net>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config ETH_TRASHERNET
|
||||
bool "Trashernet 10MBit/s PHY driver"
|
||||
depends on NETWORKING
|
||||
depends on !TEST_NET
|
||||
depends on NET_L2_ETHERNET
|
||||
help
|
||||
This module implements a kernel device driver for the Trashernet 10 MBit/s PHY.
|
253
zephyr/zephyr/drivers/trashernet/trashernet.c
Normal file
253
zephyr/zephyr/drivers/trashernet/trashernet.c
Normal file
@ -0,0 +1,253 @@
|
||||
/* TRASHERNET Stand-alone Ethernet Controller with SPI
|
||||
*
|
||||
* Copyright (c) 2016 Markus Koch <markus@notsyncing.net>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT notsyncing_trashernet
|
||||
|
||||
#define LOG_MODULE_NAME eth_trashernet
|
||||
#define LOG_LEVEL CONFIG_ETHERNET_LOG_LEVEL
|
||||
|
||||
// TODO: Load this stuff from DT
|
||||
#define TRASHERNET_BASE 0x82000000
|
||||
#define TRASHERNET_SR (*((volatile uint32_t *) (TRASHERNET_BASE + 0x00)))
|
||||
#define TRASHERNET_DR (*((volatile uint8_t *) (TRASHERNET_BASE + 0x04)))
|
||||
|
||||
#define TRASHERNET_SR_LINK_UP (1 << 0)
|
||||
#define TRASHERNET_SR_RX_AVAILABLE (1 << 1)
|
||||
#define TRASHERNET_SR_TX_NOTEMPTY (1 << 2)
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
#include <zephyr/drivers/spi.h>
|
||||
#include <zephyr/net/net_pkt.h>
|
||||
#include <zephyr/net/net_if.h>
|
||||
#include <zephyr/net/ethernet.h>
|
||||
|
||||
#define ETH_TRASHERNET_RX_THREAD_STACK_SIZE 800
|
||||
#define ETH_TRASHERNET_RX_THREAD_PRIO 2
|
||||
|
||||
struct eth_trashernet_config {
|
||||
int32_t timeout;
|
||||
};
|
||||
|
||||
struct eth_trashernet_runtime {
|
||||
struct net_if *iface;
|
||||
K_KERNEL_STACK_MEMBER(thread_stack, ETH_TRASHERNET_RX_THREAD_STACK_SIZE);
|
||||
struct k_thread thread;
|
||||
struct k_sem int_sem;
|
||||
bool iface_initialized : 1;
|
||||
uint8_t mac_address[6];
|
||||
};
|
||||
|
||||
static void eth_trashernet_set_data(const struct device *dev, uint8_t *buffer, uint16_t length)
|
||||
{
|
||||
uint16_t i;
|
||||
for (i=0; i < length; ++i) {
|
||||
TRASHERNET_DR = buffer[i];
|
||||
}
|
||||
}
|
||||
|
||||
static int eth_trashernet_tx(const struct device *dev, struct net_pkt *pkt)
|
||||
{
|
||||
struct eth_trashernet_runtime *context = dev->data;
|
||||
uint16_t len = net_pkt_get_len(pkt);
|
||||
struct net_buf *frag;
|
||||
|
||||
LOG_DBG("TX %s: pkt %p (len %u)", dev->name, pkt, len);
|
||||
|
||||
while (TRASHERNET_SR & TRASHERNET_SR_TX_NOTEMPTY); // FIXME: To be fixed in HDL: We currently do not support TX packet separation, so we have to wait for the TX buffer to be completely empty before adding the next packet.
|
||||
|
||||
for (frag = pkt->frags; frag; frag = frag->frags) {
|
||||
eth_trashernet_set_data(dev, frag->data, frag->len);
|
||||
}
|
||||
TRASHERNET_SR = TRASHERNET_SR_TX_NOTEMPTY; // Frame complete, TX now
|
||||
|
||||
//LOG_DBG("%s: Tx successful", dev->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void eth_trashernet_get_data(const struct device *dev, uint8_t *buffer, uint16_t length)
|
||||
{
|
||||
for (int x = 0; x < length; ++x) {
|
||||
buffer[x] = TRASHERNET_DR;
|
||||
}
|
||||
}
|
||||
|
||||
static int eth_trashernet_rx(const struct device *dev)
|
||||
{
|
||||
struct eth_trashernet_runtime *context = dev->data;
|
||||
const struct eth_trashernet_config *config = dev->config;
|
||||
uint16_t frm_len;
|
||||
uint16_t lengthfr;
|
||||
|
||||
struct net_buf *pkt_buf;
|
||||
struct net_pkt *pkt;
|
||||
|
||||
frm_len = TRASHERNET_SR >> 16;
|
||||
TRASHERNET_SR = (1 << 1); // Confirm that we've read the length
|
||||
if (!frm_len) {
|
||||
LOG_ERR("%s: Receive called without data available!", dev->name);
|
||||
return 0;
|
||||
}
|
||||
//LOG_DBG("RX Data %d", frm_len);
|
||||
|
||||
pkt = net_pkt_rx_alloc_with_buffer(context->iface, frm_len,
|
||||
AF_UNSPEC, 0, K_MSEC(config->timeout));
|
||||
if (!pkt) {
|
||||
LOG_ERR("%s: Could not allocate rx buffer", dev->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pkt_buf = pkt->buffer;
|
||||
lengthfr = frm_len;
|
||||
|
||||
do {
|
||||
size_t frag_len;
|
||||
uint8_t *data_ptr;
|
||||
size_t spi_frame_len;
|
||||
|
||||
data_ptr = pkt_buf->data;
|
||||
|
||||
/* Review the space available for the new frag */
|
||||
frag_len = net_buf_tailroom(pkt_buf);
|
||||
|
||||
if (frm_len > frag_len) {
|
||||
spi_frame_len = frag_len;
|
||||
} else {
|
||||
spi_frame_len = frm_len;
|
||||
}
|
||||
|
||||
eth_trashernet_get_data(dev, data_ptr, spi_frame_len);
|
||||
|
||||
net_buf_add(pkt_buf, spi_frame_len);
|
||||
|
||||
/* One fragment has been written via SPI */
|
||||
frm_len -= spi_frame_len;
|
||||
pkt_buf = pkt_buf->frags;
|
||||
} while (frm_len > 0);
|
||||
|
||||
net_pkt_set_iface(pkt, context->iface);
|
||||
|
||||
LOG_DBG("%s: Received packet of length %u", dev->name, lengthfr);
|
||||
if (net_recv_data(net_pkt_iface(pkt), pkt) < 0) {
|
||||
net_pkt_unref(pkt);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void eth_trashernet_rx_thread(void *p1, void *p2, void *p3)
|
||||
{
|
||||
int status_last = 0;
|
||||
int status = 0;
|
||||
ARG_UNUSED(p2);
|
||||
ARG_UNUSED(p3);
|
||||
|
||||
const struct device *dev = p1;
|
||||
struct eth_trashernet_runtime *context = dev->data;
|
||||
|
||||
while (true) {
|
||||
//k_sem_take(&context->int_sem, K_FOREVER); // Set to wait for IRQ
|
||||
//k_sem_give(&context->int_sem); // Set in IRQ
|
||||
|
||||
status = TRASHERNET_SR;
|
||||
if ((status ^ status_last) & TRASHERNET_SR_LINK_UP) { // Link change
|
||||
if (status & TRASHERNET_SR_LINK_UP) {
|
||||
LOG_INF("%s: Link up", dev->name);
|
||||
net_eth_carrier_on(context->iface);
|
||||
} else {
|
||||
LOG_INF("%s: Link down", dev->name);
|
||||
|
||||
if (context->iface_initialized) {
|
||||
net_eth_carrier_off(context->iface);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (status & TRASHERNET_SR_RX_AVAILABLE) { // New RX data
|
||||
eth_trashernet_rx(dev);
|
||||
} else {
|
||||
k_msleep(10); // We poll
|
||||
}
|
||||
status_last = status;
|
||||
}
|
||||
}
|
||||
|
||||
static enum ethernet_hw_caps eth_trashernet_get_capabilities(const struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
return ETHERNET_LINK_10BASE_T
|
||||
#if defined(CONFIG_NET_VLAN)
|
||||
| ETHERNET_HW_VLAN
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
static void eth_trashernet_iface_init(struct net_if *iface)
|
||||
{
|
||||
const struct device *dev = net_if_get_device(iface);
|
||||
struct eth_trashernet_runtime *context = dev->data;
|
||||
|
||||
net_if_set_link_addr(iface, context->mac_address,
|
||||
sizeof(context->mac_address),
|
||||
NET_LINK_ETHERNET);
|
||||
|
||||
if (context->iface == NULL) {
|
||||
context->iface = iface;
|
||||
}
|
||||
|
||||
ethernet_init(iface);
|
||||
|
||||
net_if_carrier_off(iface);
|
||||
context->iface_initialized = true;
|
||||
}
|
||||
|
||||
static const struct ethernet_api api_funcs = {
|
||||
.iface_api.init = eth_trashernet_iface_init,
|
||||
|
||||
.get_capabilities = eth_trashernet_get_capabilities,
|
||||
.send = eth_trashernet_tx,
|
||||
};
|
||||
|
||||
static int eth_trashernet_init(const struct device *dev)
|
||||
{
|
||||
const struct eth_trashernet_config *config = dev->config;
|
||||
struct eth_trashernet_runtime *context = dev->data;
|
||||
|
||||
/* Start interruption-poll thread */
|
||||
k_thread_create(&context->thread, context->thread_stack,
|
||||
ETH_TRASHERNET_RX_THREAD_STACK_SIZE,
|
||||
eth_trashernet_rx_thread,
|
||||
(void *)dev, NULL, NULL,
|
||||
K_PRIO_COOP(ETH_TRASHERNET_RX_THREAD_PRIO),
|
||||
0, K_NO_WAIT);
|
||||
|
||||
LOG_INF("%s: Initialized", dev->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TRASHERNET_DEFINE(inst) \
|
||||
static struct eth_trashernet_runtime eth_trashernet_runtime_##inst = { \
|
||||
.mac_address = DT_INST_PROP(inst, local_mac_address), \
|
||||
.int_sem = Z_SEM_INITIALIZER((eth_trashernet_runtime_##inst).int_sem, 0, UINT_MAX), \
|
||||
}; \
|
||||
\
|
||||
static const struct eth_trashernet_config eth_trashernet_config_##inst = { \
|
||||
.timeout = 500, \
|
||||
}; \
|
||||
\
|
||||
ETH_NET_DEVICE_DT_INST_DEFINE(inst, eth_trashernet_init, NULL, ð_trashernet_runtime_##inst, \
|
||||
ð_trashernet_config_##inst, CONFIG_ETH_INIT_PRIORITY, \
|
||||
&api_funcs, NET_ETH_MTU);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(TRASHERNET_DEFINE);
|
@ -0,0 +1,14 @@
|
||||
# Copyright (c) 2024 Markus Koch <markus@notsyncing.net>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: Trashernet PHY
|
||||
|
||||
compatible: "notsyncing,trashernet"
|
||||
|
||||
include: [ethernet-controller.yaml]
|
||||
|
||||
properties:
|
||||
full-duplex:
|
||||
type: boolean
|
||||
description: |
|
||||
Optional feature flag - Enables full duplex reception and transmission.
|
24
zephyr/zephyr/dts/riscv/serv.dtsi
Normal file
24
zephyr/zephyr/dts/riscv/serv.dtsi
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
* Copyright (c) 2024 Markus Koch <markus@notsyncing.net>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "olofk,servant";
|
||||
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
cpu0: cpu@0 {
|
||||
compatible = "olofk,serv";
|
||||
riscv,isa = "rv32i_zicsr";
|
||||
reg = <0>;
|
||||
device_type = "cpu";
|
||||
};
|
||||
};
|
||||
};
|
5
zephyr/zephyr/module.yml
Normal file
5
zephyr/zephyr/module.yml
Normal file
@ -0,0 +1,5 @@
|
||||
build:
|
||||
settings:
|
||||
board_root: zephyr
|
||||
dts_root: zephyr
|
||||
soc_root: zephyr
|
8
zephyr/zephyr/soc/riscv/servant/CMakeLists.txt
Normal file
8
zephyr/zephyr/soc/riscv/servant/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
zephyr_sources(
|
||||
soc_irq.S
|
||||
vector.S
|
||||
irq.c
|
||||
cpu_idle.c)
|
26
zephyr/zephyr/soc/riscv/servant/Kconfig.defconfig
Normal file
26
zephyr/zephyr/soc/riscv/servant/Kconfig.defconfig
Normal file
@ -0,0 +1,26 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
if SOC_RISCV32_SERVANT
|
||||
|
||||
config SOC
|
||||
string
|
||||
default "servant"
|
||||
|
||||
config SYS_CLOCK_HW_CYCLES_PER_SEC
|
||||
int
|
||||
default 25000000
|
||||
|
||||
config RISCV_SOC_INTERRUPT_INIT
|
||||
bool
|
||||
default y
|
||||
|
||||
config NUM_IRQS
|
||||
int
|
||||
default 8
|
||||
|
||||
config SERV_TIMER
|
||||
bool
|
||||
default y
|
||||
|
||||
endif # SOC_RISCV32_SERVANT
|
8
zephyr/zephyr/soc/riscv/servant/Kconfig.soc
Normal file
8
zephyr/zephyr/soc/riscv/servant/Kconfig.soc
Normal file
@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config SOC_RISCV32_SERVANT
|
||||
bool "servant SoC"
|
||||
select RISCV
|
||||
select ATOMIC_OPERATIONS_C
|
||||
select RISCV_ISA_EXT_ZICSR
|
22
zephyr/zephyr/soc/riscv/servant/cpu_idle.c
Normal file
22
zephyr/zephyr/soc/riscv/servant/cpu_idle.c
Normal file
@ -0,0 +1,22 @@
|
||||
#include <zephyr/irq.h>
|
||||
#include <zephyr/tracing/tracing.h>
|
||||
|
||||
// Override arch_cpu_idle() and arch_cpu_atomic_idle() to prevent insertion
|
||||
// of `wfi` instructions which lock up our system. This was introduced in
|
||||
// Zephyr 3.6.0 with commit 5fb6e267f629dedb8382da6bcad8018b1bb8930a.
|
||||
//
|
||||
// This is probably a hardware bug in SERV. This issue is tracked as #131.
|
||||
// https://github.com/olofk/serv/issues/131
|
||||
|
||||
void arch_cpu_idle(void)
|
||||
{
|
||||
sys_trace_idle();
|
||||
irq_unlock(MSTATUS_IEN);
|
||||
}
|
||||
|
||||
void arch_cpu_atomic_idle(unsigned int key)
|
||||
{
|
||||
sys_trace_idle();
|
||||
irq_unlock(key);
|
||||
}
|
||||
|
58
zephyr/zephyr/soc/riscv/servant/irq.c
Normal file
58
zephyr/zephyr/soc/riscv/servant/irq.c
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Jean-Paul Etienne <fractalclone@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief interrupt management code for riscv SOCs supporting the riscv
|
||||
privileged architecture specification
|
||||
*/
|
||||
#include <zephyr/irq.h>
|
||||
|
||||
void arch_irq_enable(unsigned int irq)
|
||||
{
|
||||
uint32_t mie;
|
||||
|
||||
/*
|
||||
* CSR mie register is updated using atomic instruction csrrs
|
||||
* (atomic read and set bits in CSR register)
|
||||
*/
|
||||
__asm__ volatile ("csrrs %0, mie, %1\n"
|
||||
: "=r" (mie)
|
||||
: "r" (1 << irq));
|
||||
}
|
||||
|
||||
void arch_irq_disable(unsigned int irq)
|
||||
{
|
||||
uint32_t mie;
|
||||
|
||||
/*
|
||||
* Use atomic instruction csrrc to disable device interrupt in mie CSR.
|
||||
* (atomic read and clear bits in CSR register)
|
||||
*/
|
||||
__asm__ volatile ("csrrc %0, mie, %1\n"
|
||||
: "=r" (mie)
|
||||
: "r" (1 << irq));
|
||||
};
|
||||
|
||||
int arch_irq_is_enabled(unsigned int irq)
|
||||
{
|
||||
uint32_t mie;
|
||||
|
||||
__asm__ volatile ("csrr %0, mie" : "=r" (mie));
|
||||
|
||||
return !!(mie & (1 << irq));
|
||||
}
|
||||
|
||||
#if defined(CONFIG_RISCV_SOC_INTERRUPT_INIT)
|
||||
void soc_interrupt_init(void)
|
||||
{
|
||||
/* ensure that all interrupts are disabled */
|
||||
(void)irq_lock();
|
||||
|
||||
__asm__ volatile ("csrwi mie, 0\n"
|
||||
"csrwi mip, 0\n");
|
||||
}
|
||||
#endif
|
7
zephyr/zephyr/soc/riscv/servant/linker.ld
Normal file
7
zephyr/zephyr/soc/riscv/servant/linker.ld
Normal file
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Antmicro <www.antmicro.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/arch/riscv/common/linker.ld>
|
16
zephyr/zephyr/soc/riscv/servant/soc.h
Normal file
16
zephyr/zephyr/soc/riscv/servant/soc.h
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __RISCV32_SERVANT_SOC_H_
|
||||
#define __RISCV32_SERVANT_SOC_H_
|
||||
|
||||
#include <soc_common.h>
|
||||
|
||||
/* Timer configuration */
|
||||
#define SERV_TIMER_BASE 0x80000000
|
||||
#define SERV_TIMER_IRQ 7
|
||||
|
||||
#endif /* __RISCV32_SERVANT_SOC_H_ */
|
56
zephyr/zephyr/soc/riscv/servant/soc_common.h
Normal file
56
zephyr/zephyr/soc/riscv/servant/soc_common.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Jean-Paul Etienne <fractalclone@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file configuration macros for riscv SOCs supporting the riscv
|
||||
* privileged architecture specification
|
||||
*/
|
||||
|
||||
#ifndef __SOC_COMMON_H_
|
||||
#define __SOC_COMMON_H_
|
||||
|
||||
/* IRQ numbers */
|
||||
#define RISCV_MACHINE_SOFT_IRQ 3 /* Machine Software Interrupt */
|
||||
#define RISCV_MACHINE_TIMER_IRQ 7 /* Machine Timer Interrupt */
|
||||
#define RISCV_MACHINE_EXT_IRQ 11 /* Machine External Interrupt */
|
||||
|
||||
/* ECALL Exception numbers */
|
||||
#define SOC_MCAUSE_ECALL_EXP 11 /* Machine ECALL instruction */
|
||||
#define SOC_MCAUSE_USER_ECALL_EXP 8 /* User ECALL instruction */
|
||||
|
||||
/* SOC-specific MCAUSE bitfields */
|
||||
#ifdef CONFIG_64BIT
|
||||
/* Interrupt Mask */
|
||||
#define SOC_MCAUSE_IRQ_MASK (1 << 63)
|
||||
/* Exception code Mask */
|
||||
#define SOC_MCAUSE_EXP_MASK 0x7FFFFFFFFFFFFFFF
|
||||
#else
|
||||
/* Interrupt Mask */
|
||||
#define SOC_MCAUSE_IRQ_MASK (1 << 31)
|
||||
/* Exception code Mask */
|
||||
#define SOC_MCAUSE_EXP_MASK 0x7FFFFFFF
|
||||
#endif
|
||||
|
||||
/* SOC-Specific EXIT ISR command */
|
||||
#define SOC_ERET mret
|
||||
|
||||
#ifndef _ASMLANGUAGE
|
||||
|
||||
#if defined(CONFIG_RISCV_SOC_INTERRUPT_INIT)
|
||||
void soc_interrupt_init(void);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_RISCV_HAS_PLIC)
|
||||
void riscv_plic_irq_enable(uint32_t irq);
|
||||
void riscv_plic_irq_disable(uint32_t irq);
|
||||
int riscv_plic_irq_is_enabled(uint32_t irq);
|
||||
void riscv_plic_set_priority(uint32_t irq, uint32_t priority);
|
||||
int riscv_plic_get_irq(void);
|
||||
#endif
|
||||
|
||||
#endif /* !_ASMLANGUAGE */
|
||||
|
||||
#endif /* __SOC_COMMON_H_ */
|
56
zephyr/zephyr/soc/riscv/servant/soc_irq.S
Normal file
56
zephyr/zephyr/soc/riscv/servant/soc_irq.S
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Jean-Paul Etienne <fractalclone@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* common interrupt management code for riscv SOCs supporting the riscv
|
||||
* privileged architecture specification
|
||||
*/
|
||||
#include <offsets.h>
|
||||
#include <zephyr/linker/sections.h>
|
||||
#include <soc.h>
|
||||
|
||||
/* exports */
|
||||
GTEXT(__soc_handle_irq)
|
||||
|
||||
/*
|
||||
* SOC-specific function to handle pending IRQ number generating the interrupt.
|
||||
* Exception number is given as parameter via register a0.
|
||||
*/
|
||||
SECTION_FUNC(exception.other, __soc_handle_irq)
|
||||
/* Clear exception number from CSR mip register */
|
||||
li t1, 1
|
||||
sll t0, t1, a0
|
||||
csrrc t1, mip, t0
|
||||
|
||||
/* Return */
|
||||
jalr x0, ra
|
||||
|
||||
/*
|
||||
* __soc_is_irq is defined as .weak to allow re-implementation by
|
||||
* SOCs that does not truly follow the riscv privilege specification.
|
||||
*/
|
||||
WTEXT(__soc_is_irq)
|
||||
|
||||
/*
|
||||
* SOC-specific function to determine if the exception is the result of a
|
||||
* an interrupt or an exception
|
||||
* return 1 (interrupt) or 0 (exception)
|
||||
*
|
||||
*/
|
||||
SECTION_FUNC(exception.other, __soc_is_irq)
|
||||
/* Read mcause and check if interrupt bit is set */
|
||||
csrr t0, mcause
|
||||
li t1, SOC_MCAUSE_IRQ_MASK
|
||||
and t0, t0, t1
|
||||
|
||||
/* If interrupt bit is not set, return with 0 */
|
||||
addi a0, x0, 0
|
||||
beqz t0, not_interrupt
|
||||
addi a0, a0, 1
|
||||
|
||||
not_interrupt:
|
||||
/* return */
|
||||
jalr x0, ra
|
28
zephyr/zephyr/soc/riscv/servant/vector.S
Normal file
28
zephyr/zephyr/soc/riscv/servant/vector.S
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Jean-Paul Etienne <fractalclone@gmail.com>
|
||||
* Contributors: 2018 Antmicro <www.antmicro.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/toolchain.h>
|
||||
|
||||
/* exports */
|
||||
GTEXT(__start)
|
||||
|
||||
/* imports */
|
||||
GTEXT(__initialize)
|
||||
GTEXT(_isr_wrapper)
|
||||
|
||||
SECTION_FUNC(vectors, __start)
|
||||
.option norvc;
|
||||
|
||||
/*
|
||||
* Set mtvec (Machine Trap-Vector Base-Address Register)
|
||||
* to __isr_wrapper.
|
||||
*/
|
||||
la t0, _isr_wrapper
|
||||
csrw mtvec, t0
|
||||
|
||||
/* Jump to __initialize */
|
||||
tail __initialize
|
Loading…
x
Reference in New Issue
Block a user