aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Oliver <contact@pauloliver.dev>2025-11-22 03:03:11 +0100
committerPaul Oliver <contact@pauloliver.dev>2025-11-24 16:49:04 +0100
commitc8fc429d9e5ed8ab0566729003d60ef41f578807 (patch)
treeda0c41a8e2b72ba2f32ee495440793bd73039ccb
parent0bc672fe6c263b9894af0cd211d006054215c7a9 (diff)
Improves logging system
-rw-r--r--arch/salis-v1/arch.j2.c48
-rw-r--r--bench.j2.c52
-rw-r--r--core.j2.c9
-rwxr-xr-xsalis.py54
-rw-r--r--ui/curses/ui.j2.c177
-rw-r--r--ui/daemon/ui.j2.c42
6 files changed, 310 insertions, 72 deletions
diff --git a/arch/salis-v1/arch.j2.c b/arch/salis-v1/arch.j2.c
index aaa5284..f2b9990 100644
--- a/arch/salis-v1/arch.j2.c
+++ b/arch/salis-v1/arch.j2.c
@@ -773,7 +773,7 @@ void arch_push_data_header() {
assert(g_sim_data);
const char *sql = (
- "create table data("
+ "create table trend("
"step int not null, "
{% for i in range(args.cores) %}
"cycl_{{ i }} int not null, "
@@ -791,13 +791,23 @@ void arch_push_data_header() {
");"
);
- {% set sql_call %}sqlite3_exec(g_sim_data, sql, NULL, NULL, NULL){% endset %}
+ g_info("Generating 'trend' table in SQLite database");
- {% if not args.optimized %}
- assert({{ sql_call }} == 0);
- {% else %}
- {{ sql_call }};
- {% endif %}
+ int sql_res;
+ char *sql_err;
+
+ // Only handle busy database errors
+ // Application should fail on all other error conditions
+ while ((sql_res = sqlite3_exec(g_sim_data, sql, NULL, NULL, &sql_err)) == SQLITE_BUSY) {
+ g_warn("Busy SQLite database returned error '%d' with message:", sql_res);
+ g_warn(sql_err);
+
+ sqlite3_free(sql_err);
+
+ g_info("Will retry query...");
+ }
+
+ assert(sql_res == 0);
}
void arch_push_data_line() {
@@ -835,7 +845,7 @@ void arch_push_data_line() {
asprintf(
&sql,
- "insert into data ("
+ "insert into trend ("
"step, "
{% for i in range(args.cores) %}
"cycl_{{ i }}, "
@@ -876,13 +886,23 @@ void arch_push_data_line() {
{% endfor %}
);
- {% set sql_call %}sqlite3_exec(g_sim_data, sql, NULL, NULL, NULL){% endset %}
+ g_info("Pushing row to 'trend' table in SQLite database");
- {% if not args.optimized %}
- assert({{ sql_call }} == 0);
- {% else %}
- {{ sql_call }};
- {% endif %}
+ int sql_res;
+ char *sql_err;
+
+ // Only handle busy database errors
+ // Application should fail on all other error conditions
+ while ((sql_res = sqlite3_exec(g_sim_data, sql, NULL, NULL, &sql_err)) == SQLITE_BUSY) {
+ g_warn("Busy SQLite database returned error '%d' with message:", sql_res);
+ g_warn(sql_err);
+
+ sqlite3_free(sql_err);
+
+ g_info("Will retry query...");
+ }
+
+ assert(sql_res == 0);
// Free query string returned by 'asprintf()'
free(sql);
diff --git a/bench.j2.c b/bench.j2.c
index a776892..e78861f 100644
--- a/bench.j2.c
+++ b/bench.j2.c
@@ -4,38 +4,48 @@
// Simple benchmark test helps measure simulation speed.
// Steps the simulation N times and prints part of the simulator's state.
+void log_impl(const char *format, ...) {
+ va_list args;
+ va_start(args, format);
+ vprintf(format, args);
+ va_end(args);
+}
+
int main() {
- printf("Salis Benchmark Test\n\n");
+ g_info = log_impl;
+ g_warn = log_impl;
+
+ g_info("Salis Benchmark Test\n\n");
salis_init();
salis_step({{ args.steps }});
- printf("seed => %#lx\n", {{ args.seed }});
- printf("g_steps => %#lx\n", g_steps);
- printf("g_syncs => %#lx\n", g_syncs);
+ g_info("seed => %#lx\n", {{ args.seed }});
+ g_info("g_steps => %#lx\n", g_steps);
+ g_info("g_syncs => %#lx\n", g_syncs);
for (int i = 0; i < {{ args.cores }}; ++i) {
- putchar('\n');
- printf("core %d mall => %#lx\n", i, g_cores[i].mall);
- printf("core %d mut0 => %#lx\n", i, g_cores[i].muta[0]);
- printf("core %d mut1 => %#lx\n", i, g_cores[i].muta[1]);
- printf("core %d mut2 => %#lx\n", i, g_cores[i].muta[2]);
- printf("core %d mut3 => %#lx\n", i, g_cores[i].muta[3]);
- printf("core %d pnum => %#lx\n", i, g_cores[i].pnum);
- printf("core %d pcap => %#lx\n", i, g_cores[i].pcap);
- printf("core %d pfst => %#lx\n", i, g_cores[i].pfst);
- printf("core %d plst => %#lx\n", i, g_cores[i].plst);
- printf("core %d pcur => %#lx\n", i, g_cores[i].pcur);
- printf("core %d psli => %#lx\n", i, g_cores[i].psli);
- printf("core %d cycl => %#lx\n", i, g_cores[i].cycl);
- printf("core %d ivpt => %#lx\n", i, g_cores[i].ivpt);
- putchar('\n');
+ g_info("\n");
+ g_info("core %d mall => %#lx\n", i, g_cores[i].mall);
+ g_info("core %d mut0 => %#lx\n", i, g_cores[i].muta[0]);
+ g_info("core %d mut1 => %#lx\n", i, g_cores[i].muta[1]);
+ g_info("core %d mut2 => %#lx\n", i, g_cores[i].muta[2]);
+ g_info("core %d mut3 => %#lx\n", i, g_cores[i].muta[3]);
+ g_info("core %d pnum => %#lx\n", i, g_cores[i].pnum);
+ g_info("core %d pcap => %#lx\n", i, g_cores[i].pcap);
+ g_info("core %d pfst => %#lx\n", i, g_cores[i].pfst);
+ g_info("core %d plst => %#lx\n", i, g_cores[i].plst);
+ g_info("core %d pcur => %#lx\n", i, g_cores[i].pcur);
+ g_info("core %d psli => %#lx\n", i, g_cores[i].psli);
+ g_info("core %d cycl => %#lx\n", i, g_cores[i].cycl);
+ g_info("core %d ivpt => %#lx\n", i, g_cores[i].ivpt);
+ g_info("\n");
for (int j = 0; j < 32; ++j) {
- printf("%02x ", g_cores[i].mvec[j]);
+ g_info("%02x ", g_cores[i].mvec[j]);
}
- putchar('\n');
+ g_info("\n");
}
salis_free();
diff --git a/core.j2.c b/core.j2.c
index 8aeff5d..64873d8 100644
--- a/core.j2.c
+++ b/core.j2.c
@@ -62,6 +62,11 @@ char g_asav_pbuf[{{ auto_save_name_len }}];
sqlite3 *g_sim_data;
{% endif %}
+// Before invoking salis_init(),
+// each UI must install its own logger functions
+void (*g_info)(const char *fmt, ...);
+void (*g_warn)(const char *fmt, ...);
+
// Forward declarations
// Each architecture must define these
{% if args.command in ["bench", "new"] and anc_bytes is defined %}
@@ -582,12 +587,16 @@ void salis_auto_save() {
assert(rem >= 0);
assert(rem < {{ auto_save_name_len }});
+ g_info("Saving simulation state on step '%#lx'", g_steps);
salis_save(g_asav_pbuf);
}
{% endif %}
{% if args.command in ["bench", "new"] %}
void salis_init() {
+ assert(g_info);
+ assert(g_warn);
+
uint64_t seed = {{ args.seed }};
for (int i = 0; i < {{ args.cores }}; ++i) {
diff --git a/salis.py b/salis.py
index a3281b5..76290ee 100755
--- a/salis.py
+++ b/salis.py
@@ -123,25 +123,21 @@ for parser, option in parser_map:
args = main_parser.parse_args()
-
-def log(msg, val=""):
- print(f"\033[1;34m{msg}\033[0m", val, flush=True)
-
+def info(msg, val=""):
+ print(f"\033[1;34mINFO:\033[0m {msg}", val)
def warn(msg, val=""):
- print(f"\033[1;31m{msg}\033[0m", val, flush=True)
-
+ print(f"\033[1;31mWARN:\033[0m {msg}", val)
def error(msg, val=""):
- warn(f"ERROR: {msg}", val)
+ print(f"\033[1;31mERROR:\033[0m {msg}", val)
sys.exit(1)
-
# ------------------------------------------------------------------------------
# Load configuration
# ------------------------------------------------------------------------------
-log(headline)
-log(f"Called '{script}' with the following options:")
+info(headline)
+info(f"Called '{script}' with the following options:")
for key, val in vars(args).items():
print(f"{key} = {repr(val)}")
@@ -155,7 +151,7 @@ if args.command in ["load"]:
if not os.path.isdir(sim_dir):
error("No simulation found named:", args.name)
- log(f"Sourcing configuration from '{sim_opts}':")
+ info(f"Sourcing configuration from '{sim_opts}':")
sys.path.append(sim_dir)
import opts as opts_module
@@ -178,10 +174,10 @@ if args.command in ["new"]:
if os.path.isdir(sim_dir):
error("Simulation directory found at:", sim_dir)
- log("Creating new simulation directory at:", sim_dir)
+ info("Creating new simulation directory at:", sim_dir)
os.mkdir(sim_dir)
- log("Creating configuration file at:", sim_opts)
+ info("Creating configuration file at:", sim_opts)
opts = (
option["long"].replace("-", "_")
@@ -197,13 +193,13 @@ if args.command in ["new"]:
# Load architecture and UI variables
# ------------------------------------------------------------------------------
arch_path = f"arch/{args.arch}"
-log("Loading architecture specific variables from:", f"{arch_path}/arch_vars.py")
+info("Loading architecture specific variables from:", f"{arch_path}/arch_vars.py")
sys.path.append(arch_path)
import arch_vars
if args.command in ["load", "new"]:
ui_path = f"ui/{args.ui}"
- log("Loading UI specific variables from:", f"{ui_path}/ui_vars.py")
+ info("Loading UI specific variables from:", f"{ui_path}/ui_vars.py")
sys.path.append(ui_path)
import ui_vars
@@ -215,6 +211,7 @@ ul_pow = lambda val: f"{hex(2 ** val)}ul"
includes = [
"assert.h",
+ "stdarg.h",
"stdbool.h",
"stddef.h",
"stdint.h",
@@ -249,13 +246,13 @@ if args.command in ["load", "new"]:
data_push_interval = ul_pow(args.data_push_pow)
data_push_busy_timeout = 600000
includes.append("sqlite3.h")
- log("Data will be aggregated at:", data_push_path)
+ info("Data will be aggregated at:", data_push_path)
else:
warn("Data aggregation disabled")
if args.compress:
includes.append("zlib.h")
- log("Save file compression enabled")
+ info("Save file compression enabled")
else:
warn("Save file compression disabled")
@@ -295,16 +292,16 @@ if args.command in ["bench", "new"] and args.anc is not None:
if not found:
error("Unrecognized instruction in ancestor file:", line)
- log(f"Compiled ancestor file '{anc_path}' into byte array:", anc_bytes)
+ info(f"Compiled ancestor file '{anc_path}' into byte array:", anc_bytes)
# ------------------------------------------------------------------------------
# Emit C source
# ------------------------------------------------------------------------------
tempdir = TemporaryDirectory(prefix="salis_", delete=args.delete_temp_dir)
-log("Created a temporary salis directory at:", tempdir.name)
+info("Created a temporary salis directory at:", tempdir.name)
salis_src = f"{tempdir.name}/salis.c"
-log("Emitting C source at:", salis_src)
+info("Emitting C source at:", salis_src)
jinja_env = Environment(
loader = FileSystemLoader("."),
@@ -316,7 +313,7 @@ jinja_env = Environment(
source_str = jinja_env.get_template("core.j2.c").render(**locals())
if args.print_source:
- log("Printing C source and exiting...")
+ info("Printing C source and exiting...")
print(source_str)
exit(0)
@@ -327,7 +324,7 @@ with open(salis_src, "w") as file:
# Build executable
# ------------------------------------------------------------------------------
salis_bin = f"{tempdir.name}/salis_bin"
-log("Building salis binary at:", salis_bin)
+info("Building salis binary at:", salis_bin)
build_cmd = ["gcc", salis_src, "-o", salis_bin, "-Wall", "-Wextra", "-Werror", "-Wno-overlength-strings", "-pedantic", "-std=c11"]
build_cmd.extend(["-O3", "-DNDEBUG"] if args.optimized else ["-ggdb"])
@@ -342,19 +339,19 @@ if args.command in ["load", "new"]:
# This allows managing large SQL strings more easily
build_cmd.extend(["-lsqlite3", "-D_GNU_SOURCE"] if args.data_push_pow != 0 else [])
-log("Using build command:", " ".join(build_cmd))
+info("Using build command:", " ".join(build_cmd))
subprocess.run(build_cmd, check=True)
# ------------------------------------------------------------------------------
# Run salis binary
# ------------------------------------------------------------------------------
-log("Running salis binary...")
+info("Running salis binary...")
run_cmd = [args.pre_cmd] if args.pre_cmd else []
run_cmd.append(salis_bin)
-log("Using run command:", " ".join(run_cmd))
-salis_sp = subprocess.Popen(run_cmd, stdout=sys.stdout)
+info("Using run command:", " ".join(run_cmd))
+salis_sp = subprocess.Popen(run_cmd, stdout=sys.stdout, stderr=sys.stderr)
# Ctrl-C terminates the simulator gracefully.
# When using signals (e.g. SIGTERM), they must be sent to the entire process group
@@ -364,3 +361,8 @@ try:
except KeyboardInterrupt:
salis_sp.terminate()
salis_sp.wait()
+
+code = salis_sp.returncode
+
+if code != 0:
+ error("Salis binary returned code:", code)
diff --git a/ui/curses/ui.j2.c b/ui/curses/ui.j2.c
index 4370774..9ebd387 100644
--- a/ui/curses/ui.j2.c
+++ b/ui/curses/ui.j2.c
@@ -11,6 +11,9 @@
{% set proc_field_width = 21 %}
{% set proc_page_lines = 12 %}
+{% set log_line_size = 1024 %}
+{% set log_line_count = 1024 %}
+
{% macro ctrl(x) %}('{{ x }}' & 0x1f){% endmacro %}
{% if not args.optimized %}
@@ -27,6 +30,7 @@ enum {
PAGE_PROCESS,
PAGE_WORLD,
PAGE_IPC,
+ PAGE_LOG,
PAGE_COUNT,
};
@@ -35,6 +39,7 @@ enum {
PAIR_NOUSE,
PAIR_NORMAL,
PAIR_HEADER,
+ PAIR_WARN,
PAIR_LIVE_PROC,
PAIR_SELECTED_PROC,
PAIR_FREE_CELL,
@@ -72,6 +77,12 @@ bool g_wcursor_mode;
int g_wcursor_x;
int g_wcursor_y;
uint64_t g_wcursor_pointed;
+uint64_t g_log_cnt;
+unsigned g_log_ptr;
+unsigned g_log_scroll;
+bool g_log_warns[{{ log_line_count }}];
+time_t g_log_times[{{ log_line_count }}];
+char g_logs[{{ log_line_count }}][{{ log_line_size }}];
uint64_t g_vlin;
uint64_t g_vsiz;
uint64_t g_vlin_rng;
@@ -310,7 +321,7 @@ void gfx_render(const struct Core *core, uint64_t pos, uint64_t zoom, uint64_t p
}
// ----------------------------------------------------------------------------
-// TUI functions
+// TUI generic functions
// ----------------------------------------------------------------------------
void ui_line_buff_free() {
if (g_line_buff) {
@@ -387,6 +398,9 @@ void ui_ulx_field(int l, const char *label, uint64_t value) {
ui_line(false, l, PAIR_NORMAL, A_NORMAL, "%-4s : %#18lx", label, value);
}
+// ----------------------------------------------------------------------------
+// Core page functions
+// ----------------------------------------------------------------------------
void ui_print_core(int l) {
ui_line(false, ++l, PAIR_HEADER, A_BOLD, "CORE [%d]", g_core);
ui_ulx_field(++l, "cycl", g_cores[g_core].cycl);
@@ -409,6 +423,9 @@ void ui_print_core(int l) {
{% endfor %}
}
+// ----------------------------------------------------------------------------
+// Process page functions
+// ----------------------------------------------------------------------------
int ui_proc_pair(uint64_t pix) {
if (pix == g_proc_selected) {
return PAIR_SELECTED_PROC;
@@ -566,6 +583,9 @@ void ui_print_process(int l) {
}
}
+// ----------------------------------------------------------------------------
+// World page functions
+// ----------------------------------------------------------------------------
void ui_world_resize() {
assert(g_wrld_zoom);
@@ -718,6 +738,9 @@ void ui_print_world(int l) {
}
}
+// ----------------------------------------------------------------------------
+// IPC page functions
+// ----------------------------------------------------------------------------
void ui_print_ipc_field(int l, uint64_t i, int color) {
uint8_t iinst = g_cores[g_core].iviv[i];
uint64_t iaddr = g_cores[g_core].ivav[i];
@@ -771,6 +794,118 @@ void ui_print_ipc(int l) {
ui_print_ipc_data();
}
+// ----------------------------------------------------------------------------
+// Log page functions
+// ----------------------------------------------------------------------------
+void ui_info_impl(const char *format, ...) {
+ g_log_warns[g_log_ptr] = false;
+ g_log_times[g_log_ptr] = time(NULL);
+
+ va_list args;
+ va_start(args, format);
+ vsnprintf(g_logs[g_log_ptr], {{ log_line_size }}, format, args);
+ va_end(args);
+
+ g_log_cnt++;
+ g_log_ptr = (g_log_ptr + 1) % {{ log_line_count }};
+}
+
+void ui_warn_impl(const char *format, ...) {
+ g_log_warns[g_log_ptr] = true;
+ g_log_times[g_log_ptr] = time(NULL);
+
+ va_list args;
+ va_start(args, format);
+ vsnprintf(g_logs[g_log_ptr], {{ log_line_size }}, format, args);
+ va_end(args);
+
+ g_log_cnt++;
+ g_log_ptr = (g_log_ptr + 1) % {{ log_line_count }};
+}
+
+void ui_clear_log_line(int line) {
+ assert(line >= 0 && line < LINES);
+ move(line, {{ pane_width }});
+ clrtoeol();
+}
+
+void ui_print_log_line(unsigned lptr, int line) {
+ assert(lptr < {{ log_line_count }});
+ assert(line >= 0 && line < LINES);
+ ui_clear_log_line(line);
+
+ // Prints a log entry
+ if (strlen(g_logs[lptr])) {
+ struct tm tm = *localtime(&g_log_times[lptr]);
+
+ // Timestamp
+ ui_field(
+ line,
+ {{ pane_width }},
+ PAIR_NORMAL,
+ A_NORMAL,
+ "%d-%02d-%02d %02d:%02d:%02d",
+ tm.tm_year + 1900,
+ tm.tm_mon + 1,
+ tm.tm_mday,
+ tm.tm_hour,
+ tm.tm_min,
+ tm.tm_sec
+ );
+
+ // Level
+ ui_field(
+ line,
+ {{ pane_width }} + 20,
+ g_log_warns[lptr] ? PAIR_WARN : PAIR_HEADER,
+ A_NORMAL,
+ g_log_warns[lptr] ? "WARN:" : "INFO:"
+ );
+
+ // Message
+ ui_field(
+ line,
+ {{ pane_width }} + 26,
+ PAIR_NORMAL,
+ A_NORMAL,
+ g_logs[lptr]
+ );
+ }
+}
+
+void ui_print_log(int l) {
+ l++;
+
+ ui_line(true, l++, PAIR_HEADER, A_BOLD, "LOG");
+ ui_ulx_field(l++, "lscr", g_log_scroll);
+ ui_ulx_field(l++, "lcnt", g_log_cnt);
+ ui_ulx_field(l++, "lptr", g_log_ptr);
+
+ unsigned lptr = g_log_ptr;
+ int line = LINES + g_log_scroll;
+
+ while (line) {
+ lptr = (lptr - 1 + {{ log_line_count }}) % {{ log_line_count }};
+ line--;
+
+ if (line < LINES) {
+ ui_print_log_line(lptr, line);
+ }
+
+ if (lptr == g_log_ptr) {
+ break;
+ }
+ }
+
+ while (line) {
+ line--;
+ ui_clear_log_line(line);
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Main print function
+// ----------------------------------------------------------------------------
void ui_print() {
int l = 1;
@@ -799,11 +934,17 @@ void ui_print() {
case PAGE_IPC:
ui_print_ipc(l);
break;
+ case PAGE_LOG:
+ ui_print_log(l);
+ break;
default:
break;
}
}
+// ----------------------------------------------------------------------------
+// Control function
+// ----------------------------------------------------------------------------
void ev_vscroll(int ev) {
switch (g_page) {
case PAGE_PROCESS:
@@ -879,6 +1020,28 @@ void ev_vscroll(int ev) {
}
break;
+ case PAGE_LOG:
+ switch (ev) {
+ case 'W':
+ g_log_scroll += LINES;
+ g_log_scroll = g_log_scroll >= {{ log_line_count }} ? {{ log_line_count }} - 1 : g_log_scroll;
+ break;
+ case 'S':
+ g_log_scroll -= g_log_scroll < (uint64_t)LINES ? g_log_scroll : (uint64_t)LINES;
+ break;
+ case 'w':
+ g_log_scroll += 1;
+ g_log_scroll = g_log_scroll >= {{ log_line_count }} ? {{ log_line_count }} - 1 : g_log_scroll;
+ break;
+ case 's':
+ g_log_scroll -= g_log_scroll ? 1 : 0;
+ break;
+ case 'q':
+ g_log_scroll = 0;
+ break;
+ }
+
+ break;
default:
break;
}
@@ -1037,7 +1200,7 @@ void ev_handle() {
break;
case KEY_SLEFT:
clear();
- g_core = (g_core - 1) % {{ args.cores }};
+ g_core = (g_core + {{ args.cores }} - 1) % {{ args.cores }};
break;
case KEY_SRIGHT:
clear();
@@ -1045,7 +1208,7 @@ void ev_handle() {
break;
case KEY_LEFT:
clear();
- g_page = (g_page - 1) % PAGE_COUNT;
+ g_page = (g_page + PAGE_COUNT - 1) % PAGE_COUNT;
break;
case KEY_RIGHT:
clear();
@@ -1134,6 +1297,9 @@ void ev_handle() {
}
}
+// ----------------------------------------------------------------------------
+// Main functions
+// ----------------------------------------------------------------------------
void init() {
setlocale(LC_ALL, "");
@@ -1148,6 +1314,7 @@ void init() {
init_pair(PAIR_NORMAL, COLOR_WHITE, COLOR_BLACK );
init_pair(PAIR_HEADER, COLOR_BLUE, COLOR_BLACK );
+ init_pair(PAIR_WARN, COLOR_RED, COLOR_BLACK );
init_pair(PAIR_LIVE_PROC, COLOR_BLUE, COLOR_BLACK );
init_pair(PAIR_SELECTED_PROC, COLOR_YELLOW, COLOR_BLACK );
init_pair(PAIR_FREE_CELL, COLOR_BLACK, COLOR_BLUE );
@@ -1158,6 +1325,10 @@ void init() {
init_pair(PAIR_SELECTED_IP, COLOR_BLACK, COLOR_RED );
init_pair(PAIR_SELECTED_SP, COLOR_BLACK, COLOR_MAGENTA);
+ // Install loggers
+ g_info = ui_info_impl;
+ g_warn = ui_warn_impl;
+
{% if args.command == "new" %}
salis_init();
{% elif args.command == "load" %}
diff --git a/ui/daemon/ui.j2.c b/ui/daemon/ui.j2.c
index 7d92f9d..02df79b 100644
--- a/ui/daemon/ui.j2.c
+++ b/ui/daemon/ui.j2.c
@@ -8,13 +8,36 @@
volatile bool g_running;
uint64_t g_step_block;
+void info_impl(const char *restrict fmt, ...) {
+ assert(fmt);
+ printf("\033[1;34mINFO:\033[0m ");
+
+ va_list args;
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+
+ printf("\n");
+}
+
+void warn_impl(const char *restrict fmt, ...) {
+ assert(fmt);
+ printf("\033[1;31mWARN:\033[0m ");
+
+ va_list args;
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+
+ printf("\n");
+}
+
void sig_handler(int signo) {
- switch (signo) {
- case SIGINT:
- case SIGTERM:
- printf("Signal received, will stop simulator soon...\n");
+ (void)signo;
+
+ if (g_running) {
+ g_warn("Signal received, will stop simulator soon...");
g_running = false;
- break;
}
}
@@ -31,10 +54,13 @@ void step_block() {
g_step_block >>= 1;
}
- printf("Simulator running on step '%#lx'\n", g_steps);
+ g_info("Simulator running on step '%#lx'", g_steps);
}
int main() {
+ g_info = info_impl;
+ g_warn = warn_impl;
+
{% if args.command == "new" %}
salis_init();
{% elif args.command == "load" %}
@@ -51,10 +77,10 @@ int main() {
step_block();
}
- printf("Saving simulation...\n");
+ g_info("Saving simulation...");
salis_save("{{ sim_path }}");
salis_free();
- printf("Exiting salis...\n");
+ g_info("Exiting salis...");
return 0;
}