mirror of
https://github.com/m-labs/artiq.git
synced 2024-12-25 11:18:27 +08:00
watchdog support on core device (broken by bug similar to issue #19)
This commit is contained in:
parent
f60868f084
commit
967145f2dc
@ -12,6 +12,8 @@ llvm.initialize_all_targets()
|
||||
llvm.initialize_all_asmprinters()
|
||||
|
||||
_syscalls = {
|
||||
"watchdog_set": "i:i",
|
||||
"watchdog_clear": "i:n",
|
||||
"rtio_set_o": "Iii:n",
|
||||
"rtio_set_oe": "Iib:n",
|
||||
"rtio_set_sensitivity": "Iii:n",
|
||||
|
@ -120,7 +120,7 @@ class _UnitsLowerer(ast.NodeTransformer):
|
||||
else:
|
||||
if any(hasattr(arg, "unit") for arg in node.args):
|
||||
raise units.DimensionError
|
||||
elif node.func.id in ("delay", "at", "time_to_cycles"):
|
||||
elif node.func.id in ("delay", "at", "time_to_cycles", "watchdog"):
|
||||
if getattr(node.args[0], "unit", None) != "s":
|
||||
raise units.DimensionError
|
||||
elif node.func.id == "check_unit":
|
||||
|
@ -7,8 +7,7 @@ It does so by inserting multiplication/division/rounding operations around
|
||||
those calls.
|
||||
|
||||
The time_to_cycles and cycles_to_time core language functions are also
|
||||
implemented here.
|
||||
|
||||
implemented here, as well as watchdog to syscall conversion.
|
||||
"""
|
||||
|
||||
import ast
|
||||
@ -47,6 +46,7 @@ def _cycles_to_time(ref_period, node):
|
||||
class _TimeQuantizer(ast.NodeTransformer):
|
||||
def __init__(self, ref_period):
|
||||
self.ref_period = ref_period
|
||||
self.watchdog_id_counter = 0
|
||||
|
||||
def visit_Call(self, node):
|
||||
funcname = node.func.id
|
||||
@ -78,6 +78,51 @@ class _TimeQuantizer(ast.NodeTransformer):
|
||||
self.generic_visit(node)
|
||||
return node
|
||||
|
||||
def visit_With(self, node):
|
||||
self.generic_visit(node)
|
||||
if (isinstance(node.items[0].context_expr, ast.Call)
|
||||
and node.items[0].context_expr.func.id == "watchdog"):
|
||||
|
||||
idname = "__watchdog_id_" + str(self.watchdog_id_counter)
|
||||
self.watchdog_id_counter += 1
|
||||
|
||||
time = ast.BinOp(left=node.items[0].context_expr.args[0],
|
||||
op=ast.Mult(),
|
||||
right=ast.Num(1000))
|
||||
time_int = ast.Call(
|
||||
func=ast.Name("round", ast.Load()),
|
||||
args=[time],
|
||||
keywords=[], starargs=None, kwargs=None)
|
||||
syscall_set = ast.Call(
|
||||
func=ast.Name("syscall", ast.Load()),
|
||||
args=[ast.Str("watchdog_set"), time_int],
|
||||
keywords=[], starargs=None, kwargs=None)
|
||||
stmt_set = ast.copy_location(
|
||||
ast.Assign(targets=[ast.Name(idname, ast.Store())],
|
||||
value=syscall_set),
|
||||
node)
|
||||
|
||||
syscall_clear = ast.Call(
|
||||
func=ast.Name("syscall", ast.Load()),
|
||||
args=[ast.Str("watchdog_clear"),
|
||||
ast.Name(idname, ast.Load())],
|
||||
keywords=[], starargs=None, kwargs=None)
|
||||
stmt_clear = ast.copy_location(ast.Expr(syscall_clear), node)
|
||||
|
||||
node.items[0] = ast.withitem(
|
||||
context_expr=ast.Name(id="sequential",
|
||||
ctx=ast.Load()),
|
||||
optional_vars=None)
|
||||
node.body = [
|
||||
stmt_set,
|
||||
ast.Try(body=node.body,
|
||||
handlers=[],
|
||||
orelse=[],
|
||||
finalbody=[stmt_clear])
|
||||
]
|
||||
return node
|
||||
|
||||
|
||||
|
||||
def quantize_time(func_def, ref_period):
|
||||
_TimeQuantizer(ref_period).visit(func_def)
|
||||
|
@ -8,7 +8,7 @@ from artiq.language import units
|
||||
embeddable_funcs = (
|
||||
core_language.delay, core_language.at, core_language.now,
|
||||
core_language.time_to_cycles, core_language.cycles_to_time,
|
||||
core_language.syscall,
|
||||
core_language.syscall, core_language.watchdog,
|
||||
range, bool, int, float, round, len,
|
||||
core_language.int64, core_language.round64,
|
||||
Fraction, units.Quantity, units.check_unit, core_language.EncodedException
|
||||
|
@ -1,6 +1,6 @@
|
||||
include $(MSCDIR)/software/common.mak
|
||||
|
||||
OBJECTS := isr.o flash_storage.o elf_loader.o services.o session.o log.o test_mode.o kloader.o mailbox.o ksupport_data.o main.o
|
||||
OBJECTS := isr.o flash_storage.o clock.o elf_loader.o services.o session.o log.o test_mode.o kloader.o mailbox.o ksupport_data.o main.o
|
||||
OBJECTS_KSUPPORT := ksupport.o exception_jmp.o exceptions.o mailbox.o bridge.o rtio.o dds.o
|
||||
|
||||
CFLAGS += -Ilwip/src/include -Iliblwip
|
||||
|
81
soc/runtime/clock.c
Normal file
81
soc/runtime/clock.c
Normal file
@ -0,0 +1,81 @@
|
||||
#include <generated/csr.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "clock.h"
|
||||
|
||||
static int clkdiv;
|
||||
|
||||
void clock_init(void)
|
||||
{
|
||||
timer0_en_write(0);
|
||||
timer0_load_write(0x7fffffffffffffffLL);
|
||||
timer0_reload_write(0x7fffffffffffffffLL);
|
||||
timer0_en_write(1);
|
||||
clkdiv = identifier_frequency_read()/1000;
|
||||
}
|
||||
|
||||
long long int clock_get_ms(void)
|
||||
{
|
||||
long long int clock_sys;
|
||||
long long int clock_ms;
|
||||
|
||||
timer0_update_value_write(1);
|
||||
clock_sys = 0x7fffffffffffffffLL - timer0_value_read();
|
||||
|
||||
clock_ms = clock_sys/clkdiv;
|
||||
return clock_ms;
|
||||
}
|
||||
|
||||
struct watchdog {
|
||||
int active;
|
||||
long long int threshold;
|
||||
};
|
||||
|
||||
static struct watchdog watchdogs[MAX_WATCHDOGS];
|
||||
|
||||
void watchdog_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0;i<MAX_WATCHDOGS;i++)
|
||||
watchdogs[i].active = 0;
|
||||
}
|
||||
|
||||
int watchdog_set(int ms)
|
||||
{
|
||||
int i, id;
|
||||
|
||||
id = -1;
|
||||
for(i=0;i<MAX_WATCHDOGS;i++)
|
||||
if(!watchdogs[i].active) {
|
||||
id = i;
|
||||
break;
|
||||
}
|
||||
if(id < 0) {
|
||||
log("Failed to add watchdog");
|
||||
return id;
|
||||
}
|
||||
|
||||
watchdogs[id].active = 1;
|
||||
watchdogs[id].threshold = clock_get_ms() + ms;
|
||||
return id;
|
||||
}
|
||||
|
||||
void watchdog_clear(int id)
|
||||
{
|
||||
if((id < 0) || (id >= MAX_WATCHDOGS))
|
||||
return;
|
||||
watchdogs[id].active = 0;
|
||||
}
|
||||
|
||||
int watchdog_expired(void)
|
||||
{
|
||||
int i;
|
||||
long long int t;
|
||||
|
||||
t = 0x7fffffffffffffffLL;
|
||||
for(i=0;i<MAX_WATCHDOGS;i++)
|
||||
if(watchdogs[i].active && (watchdogs[i].threshold < t))
|
||||
t = watchdogs[i].threshold;
|
||||
return clock_get_ms() > t;
|
||||
}
|
14
soc/runtime/clock.h
Normal file
14
soc/runtime/clock.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef __CLOCK_H
|
||||
#define __CLOCK_H
|
||||
|
||||
void clock_init(void);
|
||||
long long int clock_get_ms(void);
|
||||
|
||||
#define MAX_WATCHDOGS 16
|
||||
|
||||
void watchdog_init(void);
|
||||
int watchdog_set(int ms);
|
||||
void watchdog_clear(int id);
|
||||
int watchdog_expired(void);
|
||||
|
||||
#endif /* __CLOCK_H */
|
@ -8,6 +8,8 @@ from elftools.elf.elffile import ELFFile
|
||||
services = [
|
||||
("syscalls", [
|
||||
("rpc", "rpc"),
|
||||
("watchdog_set", "watchdog_set"),
|
||||
("watchdog_clear", "watchdog_clear"),
|
||||
("rtio_set_o", "rtio_set_o"),
|
||||
("rtio_set_oe", "rtio_set_oe"),
|
||||
("rtio_set_sensitivity", "rtio_set_sensitivity"),
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include "rtio.h"
|
||||
#include "dds.h"
|
||||
|
||||
/* for the prototypes for watchdog_set() and watchdog_clear() */
|
||||
#include "clock.h"
|
||||
/* for the prototype for rpc() */
|
||||
#include "session.h"
|
||||
/* for the prototype for log() */
|
||||
@ -61,6 +63,34 @@ int main(void)
|
||||
while(1);
|
||||
}
|
||||
|
||||
int watchdog_set(int ms)
|
||||
{
|
||||
struct msg_watchdog_set_request request;
|
||||
struct msg_watchdog_set_reply *reply;
|
||||
int id;
|
||||
|
||||
request.type = MESSAGE_TYPE_WATCHDOG_SET_REQUEST;
|
||||
request.ms = ms;
|
||||
mailbox_send_and_wait(&request);
|
||||
|
||||
reply = mailbox_wait_and_receive();
|
||||
if(reply->type != MESSAGE_TYPE_WATCHDOG_SET_REPLY)
|
||||
exception_raise(EID_INTERNAL_ERROR);
|
||||
id = reply->id;
|
||||
mailbox_acknowledge();
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void watchdog_clear(int id)
|
||||
{
|
||||
struct msg_watchdog_clear request;
|
||||
|
||||
request.type = MESSAGE_TYPE_WATCHDOG_CLEAR;
|
||||
request.id = id;
|
||||
mailbox_send_and_wait(&request);
|
||||
}
|
||||
|
||||
int rpc(int rpc_num, ...)
|
||||
{
|
||||
struct msg_rpc_request request;
|
||||
|
@ -21,26 +21,16 @@
|
||||
#include <lwip/timers.h>
|
||||
#endif
|
||||
|
||||
#include "clock.h"
|
||||
#include "test_mode.h"
|
||||
#include "session.h"
|
||||
|
||||
#ifdef CSR_ETHMAC_BASE
|
||||
unsigned char macadr[6] = {0x10, 0xe2, 0xd5, 0x00, 0x00, 0x00};
|
||||
|
||||
static int clkdiv;
|
||||
|
||||
u32_t sys_now(void)
|
||||
{
|
||||
static unsigned long long int clock_sys;
|
||||
u32_t clock_ms;
|
||||
|
||||
timer0_update_value_write(1);
|
||||
clock_sys += 0xffffffff - timer0_value_read();
|
||||
timer0_en_write(0);
|
||||
timer0_en_write(1);
|
||||
|
||||
clock_ms = clock_sys/clkdiv;
|
||||
return clock_ms;
|
||||
return clock_get_ms();
|
||||
}
|
||||
|
||||
static struct netif netif;
|
||||
@ -60,12 +50,6 @@ static void network_init(void)
|
||||
struct ip4_addr netmask;
|
||||
struct ip4_addr gateway_ip;
|
||||
|
||||
timer0_en_write(0);
|
||||
timer0_load_write(0xffffffff);
|
||||
timer0_reload_write(0xffffffff);
|
||||
timer0_en_write(1);
|
||||
clkdiv = identifier_frequency_read()/1000;
|
||||
|
||||
IP4_ADDR(&local_ip, 192, 168, 0, 42);
|
||||
IP4_ADDR(&netmask, 255, 255, 255, 0);
|
||||
IP4_ADDR(&gateway_ip, 192, 168, 0, 1);
|
||||
@ -276,6 +260,7 @@ static void kserver_service(void)
|
||||
|
||||
static void regular_main(void)
|
||||
{
|
||||
clock_init();
|
||||
network_init();
|
||||
kserver_init();
|
||||
|
||||
@ -332,6 +317,8 @@ static void serial_service(void)
|
||||
|
||||
static void regular_main(void)
|
||||
{
|
||||
clock_init();
|
||||
|
||||
/* Open the session for the serial control. */
|
||||
session_start();
|
||||
while(1)
|
||||
|
@ -6,6 +6,9 @@
|
||||
enum {
|
||||
MESSAGE_TYPE_FINISHED,
|
||||
MESSAGE_TYPE_EXCEPTION,
|
||||
MESSAGE_TYPE_WATCHDOG_SET_REQUEST,
|
||||
MESSAGE_TYPE_WATCHDOG_SET_REPLY,
|
||||
MESSAGE_TYPE_WATCHDOG_CLEAR,
|
||||
MESSAGE_TYPE_RPC_REQUEST,
|
||||
MESSAGE_TYPE_RPC_REPLY,
|
||||
MESSAGE_TYPE_LOG,
|
||||
@ -32,6 +35,21 @@ struct msg_exception {
|
||||
long long int eparams[3];
|
||||
};
|
||||
|
||||
struct msg_watchdog_set_request {
|
||||
int type;
|
||||
int ms;
|
||||
};
|
||||
|
||||
struct msg_watchdog_set_reply {
|
||||
int type;
|
||||
int id;
|
||||
};
|
||||
|
||||
struct msg_watchdog_clear {
|
||||
int type;
|
||||
int id;
|
||||
};
|
||||
|
||||
struct msg_rpc_request {
|
||||
int type;
|
||||
int rpc_num;
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "elf_loader.h"
|
||||
#include "session.h"
|
||||
#include "clock.h"
|
||||
#include "rtio.h"
|
||||
#include "dds.h"
|
||||
#include "exceptions.h"
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "mailbox.h"
|
||||
#include "messages.h"
|
||||
|
||||
#include "clock.h"
|
||||
#include "log.h"
|
||||
#include "kloader.h"
|
||||
#include "exceptions.h"
|
||||
@ -282,6 +283,7 @@ static int process_input(void)
|
||||
break;
|
||||
}
|
||||
|
||||
watchdog_init();
|
||||
kloader_start_user_kernel(k);
|
||||
user_kernel_state = USER_KERNEL_RUNNING;
|
||||
break;
|
||||
@ -364,6 +366,9 @@ int session_input(void *data, int len)
|
||||
return consumed;
|
||||
}
|
||||
|
||||
#include <generated/mem.h>
|
||||
#define KERNELCPU_MAILBOX MMPTR(MAILBOX_BASE)
|
||||
|
||||
/* assumes output buffer is empty when called */
|
||||
static int process_kmsg(struct msg_base *umsg)
|
||||
{
|
||||
@ -379,6 +384,7 @@ static int process_kmsg(struct msg_base *umsg)
|
||||
|
||||
kloader_stop_kernel();
|
||||
user_kernel_state = USER_KERNEL_LOADED;
|
||||
mailbox_acknowledge();
|
||||
break;
|
||||
case MESSAGE_TYPE_EXCEPTION: {
|
||||
struct msg_exception *msg = (struct msg_exception *)umsg;
|
||||
@ -390,6 +396,23 @@ static int process_kmsg(struct msg_base *umsg)
|
||||
|
||||
kloader_stop_kernel();
|
||||
user_kernel_state = USER_KERNEL_LOADED;
|
||||
mailbox_acknowledge();
|
||||
break;
|
||||
}
|
||||
case MESSAGE_TYPE_WATCHDOG_SET_REQUEST: {
|
||||
struct msg_watchdog_set_request *msg = (struct msg_watchdog_set_request *)umsg;
|
||||
struct msg_watchdog_set_reply reply;
|
||||
|
||||
reply.type = MESSAGE_TYPE_WATCHDOG_SET_REPLY;
|
||||
reply.id = watchdog_set(msg->ms);
|
||||
mailbox_send_and_wait(&reply);
|
||||
break;
|
||||
}
|
||||
case MESSAGE_TYPE_WATCHDOG_CLEAR: {
|
||||
struct msg_watchdog_clear *msg = (struct msg_watchdog_clear *)umsg;
|
||||
|
||||
watchdog_clear(msg->id);
|
||||
mailbox_acknowledge();
|
||||
break;
|
||||
}
|
||||
case MESSAGE_TYPE_RPC_REQUEST: {
|
||||
@ -398,12 +421,14 @@ static int process_kmsg(struct msg_base *umsg)
|
||||
if(!send_rpc_request(msg->rpc_num, msg->args))
|
||||
return 0;
|
||||
user_kernel_state = USER_KERNEL_WAIT_RPC;
|
||||
mailbox_acknowledge();
|
||||
break;
|
||||
}
|
||||
case MESSAGE_TYPE_LOG: {
|
||||
struct msg_log *msg = (struct msg_log *)umsg;
|
||||
|
||||
log(msg->fmt, msg->args);
|
||||
mailbox_acknowledge();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@ -421,6 +446,12 @@ void session_poll(void **data, int *len)
|
||||
{
|
||||
int l;
|
||||
|
||||
if((user_kernel_state == USER_KERNEL_RUNNING) && watchdog_expired()) {
|
||||
log("Watchdog expired");
|
||||
*len = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
l = get_out_packet_len();
|
||||
|
||||
/* If the output buffer is available,
|
||||
@ -435,7 +466,6 @@ void session_poll(void **data, int *len)
|
||||
*len = -1;
|
||||
return;
|
||||
}
|
||||
mailbox_acknowledge();
|
||||
}
|
||||
l = get_out_packet_len();
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ from mibuild.xilinx.vivado import XilinxVivadoToolchain
|
||||
|
||||
from misoclib.com import gpio
|
||||
from misoclib.soc import mem_decoder
|
||||
from misoclib.cpu.peripherals import timer
|
||||
from targets.kc705 import MiniSoC
|
||||
|
||||
from artiq.gateware import amp, rtio, ad9858, nist_qc1
|
||||
@ -46,7 +47,8 @@ class Top(MiniSoC):
|
||||
|
||||
def __init__(self, platform, cpu_type="or1k", **kwargs):
|
||||
MiniSoC.__init__(self, platform,
|
||||
cpu_type=cpu_type, **kwargs)
|
||||
cpu_type=cpu_type, with_timer=False, **kwargs)
|
||||
self.submodules.timer0 = timer.Timer(width=64)
|
||||
platform.add_extension(nist_qc1.fmc_adapter_io)
|
||||
|
||||
self.submodules.leds = gpio.GPIOOut(Cat(
|
||||
|
@ -4,6 +4,7 @@ from migen.bank import wbgen
|
||||
|
||||
from misoclib.com import gpio
|
||||
from misoclib.soc import mem_decoder
|
||||
from misoclib.cpu.peripherals import timer
|
||||
from targets.pipistrello import BaseSoC
|
||||
|
||||
from artiq.gateware import amp, rtio, ad9858, nist_qc1
|
||||
@ -66,7 +67,9 @@ class Top(BaseSoC):
|
||||
mem_map.update(BaseSoC.mem_map)
|
||||
|
||||
def __init__(self, platform, cpu_type="or1k", **kwargs):
|
||||
BaseSoC.__init__(self, platform, cpu_type=cpu_type, **kwargs)
|
||||
BaseSoC.__init__(self, platform,
|
||||
cpu_type=cpu_type, with_timer=False, **kwargs)
|
||||
self.submodules.timer0 = timer.Timer(width=64)
|
||||
platform.toolchain.ise_commands += """
|
||||
trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd {build_name}.pcf
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user