diff --git a/artiq/coredevice/runtime.py b/artiq/coredevice/runtime.py index 28e755642..1136d41eb 100644 --- a/artiq/coredevice/runtime.py +++ b/artiq/coredevice/runtime.py @@ -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", diff --git a/artiq/transforms/lower_units.py b/artiq/transforms/lower_units.py index f86f24a90..eef71e564 100644 --- a/artiq/transforms/lower_units.py +++ b/artiq/transforms/lower_units.py @@ -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": diff --git a/artiq/transforms/quantize_time.py b/artiq/transforms/quantize_time.py index 6f8fe05e8..835dcd780 100644 --- a/artiq/transforms/quantize_time.py +++ b/artiq/transforms/quantize_time.py @@ -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) diff --git a/artiq/transforms/tools.py b/artiq/transforms/tools.py index 098458bb0..d9daf838f 100644 --- a/artiq/transforms/tools.py +++ b/artiq/transforms/tools.py @@ -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 diff --git a/soc/runtime/Makefile b/soc/runtime/Makefile index 8f5880e96..1b95bd727 100644 --- a/soc/runtime/Makefile +++ b/soc/runtime/Makefile @@ -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 diff --git a/soc/runtime/clock.c b/soc/runtime/clock.c new file mode 100644 index 000000000..6b3946790 --- /dev/null +++ b/soc/runtime/clock.c @@ -0,0 +1,81 @@ +#include + +#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)) + return; + watchdogs[id].active = 0; +} + +int watchdog_expired(void) +{ + int i; + long long int t; + + t = 0x7fffffffffffffffLL; + for(i=0;i t; +} diff --git a/soc/runtime/clock.h b/soc/runtime/clock.h new file mode 100644 index 000000000..70de5e5b7 --- /dev/null +++ b/soc/runtime/clock.h @@ -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 */ diff --git a/soc/runtime/gen_service_table.py b/soc/runtime/gen_service_table.py index 5c070848f..6d200757f 100755 --- a/soc/runtime/gen_service_table.py +++ b/soc/runtime/gen_service_table.py @@ -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"), diff --git a/soc/runtime/ksupport.c b/soc/runtime/ksupport.c index 81b5cd25c..5330c54d8 100644 --- a/soc/runtime/ksupport.c +++ b/soc/runtime/ksupport.c @@ -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; diff --git a/soc/runtime/main.c b/soc/runtime/main.c index e664c7b57..29a4fc378 100644 --- a/soc/runtime/main.c +++ b/soc/runtime/main.c @@ -21,26 +21,16 @@ #include #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) diff --git a/soc/runtime/messages.h b/soc/runtime/messages.h index 8c48a0946..6706abbf7 100644 --- a/soc/runtime/messages.h +++ b/soc/runtime/messages.h @@ -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; diff --git a/soc/runtime/services.c b/soc/runtime/services.c index 720df7afa..35cbf3f57 100644 --- a/soc/runtime/services.c +++ b/soc/runtime/services.c @@ -2,6 +2,7 @@ #include "elf_loader.h" #include "session.h" +#include "clock.h" #include "rtio.h" #include "dds.h" #include "exceptions.h" diff --git a/soc/runtime/session.c b/soc/runtime/session.c index 57436cdf2..7c116ee46 100644 --- a/soc/runtime/session.c +++ b/soc/runtime/session.c @@ -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 +#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(); } diff --git a/soc/targets/artiq_kc705.py b/soc/targets/artiq_kc705.py index 43cc69fe7..ee87eb605 100644 --- a/soc/targets/artiq_kc705.py +++ b/soc/targets/artiq_kc705.py @@ -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( diff --git a/soc/targets/artiq_pipistrello.py b/soc/targets/artiq_pipistrello.py index 38af077fb..531873a3d 100644 --- a/soc/targets/artiq_pipistrello.py +++ b/soc/targets/artiq_pipistrello.py @@ -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 """