仿真平台内核初版 -tlib库 包含<sparc arm riscv powerPC>
This commit is contained in:
191
tools/external_control_client/examples/adc/main.c
Normal file
191
tools/external_control_client/examples/adc/main.c
Normal file
@@ -0,0 +1,191 @@
|
||||
//
|
||||
// Copyright (c) 2010-2024 Antmicro
|
||||
//
|
||||
// This file is licensed under MIT License.
|
||||
// Full license text is available in 'licenses/MIT.txt' file.
|
||||
//
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "renode_api.h"
|
||||
|
||||
void exit_with_usage_info(const char *argv0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage:\n"
|
||||
" %s <PORT> <MACHINE_NAME> <ADC_NAME> <VALUE_WITH_UNIT>\n"
|
||||
" where:\n"
|
||||
" * <VALUE_WITH_UNIT> is an unsigned integer with a voltage unit, e.g.: '100mV'\n"
|
||||
" * accepted voltage units are 'V', 'mV' and 'uV' (for microvolts)\n",
|
||||
argv0);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char *get_error_message(renode_error_t *error)
|
||||
{
|
||||
if (error->message == NULL)
|
||||
{
|
||||
return "<no message>";
|
||||
}
|
||||
return error->message;
|
||||
}
|
||||
|
||||
int try_renode_disconnect(renode_t **renode)
|
||||
{
|
||||
renode_error_t *error;
|
||||
if ((error = renode_disconnect(renode)) != NO_ERROR) {
|
||||
fprintf(stderr, "Disconnecting from Renode failed with: %s\n", get_error_message(error));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *voltage_string(uint32_t value)
|
||||
{
|
||||
static char buffer[32];
|
||||
uint32_t integer, fraction;
|
||||
|
||||
if ((integer = (value / 1000000))) {
|
||||
fraction = value % 1000000;
|
||||
snprintf(buffer, 32, "%u.%06uV", integer, fraction);
|
||||
}
|
||||
else if ((integer = (value / 1000))) {
|
||||
fraction = value % 1000;
|
||||
snprintf(buffer, 32, "%u.%03umV", integer, fraction);
|
||||
}
|
||||
else {
|
||||
snprintf(buffer, 32, "%uuV", value);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 5) {
|
||||
exit_with_usage_info(argv[0]);
|
||||
}
|
||||
char *machine_name = argv[2];
|
||||
char *adc_name = argv[3];
|
||||
|
||||
char *endptr;
|
||||
// base=0 tries to figure out the number's base automatically.
|
||||
uint64_t value = strtoul(argv[4], &endptr, /* base: */ 0);
|
||||
if (errno != 0) {
|
||||
perror("conversion to uint32_t value");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (endptr == argv[4]) {
|
||||
exit_with_usage_info(argv[0]);
|
||||
}
|
||||
|
||||
switch (*endptr) {
|
||||
case 'u':
|
||||
// the unit used with the API
|
||||
break;
|
||||
case 'm':
|
||||
value *= 1000;
|
||||
break;
|
||||
case 'V':
|
||||
value *= 1000000;
|
||||
break;
|
||||
default:
|
||||
exit_with_usage_info(argv[0]);
|
||||
}
|
||||
|
||||
if (value > UINT32_MAX) {
|
||||
fprintf(stderr, "Voltage value too big\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// get Renode, machine and ADC instances
|
||||
|
||||
renode_error_t *error;
|
||||
renode_t *renode;
|
||||
if ((error = renode_connect(argv[1], &renode)) != NO_ERROR) {
|
||||
fprintf(stderr, "Connecting to Renode failed with: %s\n", get_error_message(error));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
renode_machine_t *machine;
|
||||
if ((error = renode_get_machine(renode, machine_name, &machine)) != NO_ERROR) {
|
||||
fprintf(stderr, "Getting '%s' machine object failed with: %s\n", machine_name, get_error_message(error));
|
||||
goto fail_renode;
|
||||
}
|
||||
|
||||
renode_adc_t *adc;
|
||||
if ((error = renode_get_adc(machine, adc_name, &adc)) != NO_ERROR) {
|
||||
fprintf(stderr, "Getting '%s' ADC object failed with: %s\n", adc_name, get_error_message(error));
|
||||
goto fail_machine;
|
||||
}
|
||||
|
||||
// assert that at least one channel exists
|
||||
|
||||
int32_t ch_count;
|
||||
if ((error = renode_get_adc_channel_count(adc, &ch_count)) != NO_ERROR) {
|
||||
fprintf(stderr, "Getting channel count for '%s' failed with: %s\n", adc_name, get_error_message(error));
|
||||
goto fail_adc;
|
||||
}
|
||||
|
||||
if (ch_count < 1) {
|
||||
fprintf(stderr, "Expected at least one ADC channel\n");
|
||||
goto fail_adc;
|
||||
}
|
||||
printf("[INFO] # of channels: %d\n", ch_count);
|
||||
|
||||
// get current value, set the new value and assert that new current value is set
|
||||
|
||||
uint32_t val0;
|
||||
if ((error = renode_get_adc_channel_value(adc, 0, &val0)) != NO_ERROR) {
|
||||
fprintf(stderr, "Getting channel #0 value for '%s' failed with: %s\n", adc_name, get_error_message(error));
|
||||
goto fail_adc;
|
||||
}
|
||||
|
||||
printf("ADC value: %s\n", voltage_string(val0));
|
||||
|
||||
uint32_t val1 = value;
|
||||
if ((error = renode_set_adc_channel_value(adc, 0, val1)) != NO_ERROR) {
|
||||
fprintf(stderr, "Setting channel #0 value for '%s' failed with: %s\n", adc_name, get_error_message(error));
|
||||
goto fail_adc;
|
||||
}
|
||||
|
||||
printf("ADC value set to %s\n", voltage_string(val1));
|
||||
|
||||
uint32_t val2;
|
||||
if ((error = renode_get_adc_channel_value(adc, 0, &val2)) != NO_ERROR) {
|
||||
fprintf(stderr, "Getting channel #0 value for '%s' failed with: %s\n", adc_name, get_error_message(error));
|
||||
goto fail_adc;
|
||||
}
|
||||
|
||||
printf("ADC value: %s\n", voltage_string(val2));
|
||||
|
||||
// clean up
|
||||
|
||||
free(adc);
|
||||
free(machine);
|
||||
if (try_renode_disconnect(&renode)) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (val1 != val2) {
|
||||
fprintf(stderr, "ADC value doesn't match set value\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
fail_adc:
|
||||
free(adc);
|
||||
fail_machine:
|
||||
free(machine);
|
||||
fail_renode:
|
||||
try_renode_disconnect(&renode);
|
||||
free(renode);
|
||||
fail:
|
||||
renode_free_error(error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
168
tools/external_control_client/examples/gpio/main.c
Normal file
168
tools/external_control_client/examples/gpio/main.c
Normal file
@@ -0,0 +1,168 @@
|
||||
//
|
||||
// Copyright (c) 2010-2024 Antmicro
|
||||
//
|
||||
// This file is licensed under MIT License.
|
||||
// Full license text is available in 'licenses/MIT.txt' file.
|
||||
//
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "renode_api.h"
|
||||
|
||||
void exit_with_usage_info(const char *argv0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage:\n"
|
||||
" %s <PORT> <MACHINE_NAME> <GPIO_NAME> <NUMBER> [true|false|event]",
|
||||
argv0);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char *get_error_message(renode_error_t *error)
|
||||
{
|
||||
if (error->message == NULL)
|
||||
{
|
||||
return "<no message>";
|
||||
}
|
||||
return error->message;
|
||||
}
|
||||
|
||||
int try_renode_disconnect(renode_t **renode)
|
||||
{
|
||||
renode_error_t *error;
|
||||
if ((error = renode_disconnect(renode)) != NO_ERROR) {
|
||||
fprintf(stderr, "Disconnecting from Renode failed with: %s\n", get_error_message(error));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char *machine_name;
|
||||
char *gpio_name;
|
||||
int pin_no;
|
||||
bool run;
|
||||
} gpio_event_user_data;
|
||||
|
||||
void gpio_callback(void *user_data, renode_gpio_event_data_t *event_data)
|
||||
{
|
||||
gpio_event_user_data *udata = (gpio_event_user_data *)user_data;
|
||||
printf("%s: GPIO #%d in %s %sset", udata->machine_name, udata->pin_no, udata->gpio_name, event_data->state ? "" : "un");
|
||||
printf(" at %lu us\n", event_data->timestamp_us);
|
||||
udata->run = false;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 5 || 6 < argc) {
|
||||
exit_with_usage_info(argv[0]);
|
||||
}
|
||||
char *machine_name = argv[2];
|
||||
char *gpio_name = argv[3];
|
||||
bool set = argc == 6;
|
||||
bool state = false;
|
||||
bool wait_for_event = false;
|
||||
|
||||
char *endptr;
|
||||
// base=0 tries to figure out the number's base automatically.
|
||||
int32_t number = strtol(argv[4], &endptr, /* base: */ 0);
|
||||
if (errno != 0) {
|
||||
perror("conversion to uint32_t value");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (endptr == argv[4] || *endptr != '\0') {
|
||||
exit_with_usage_info(argv[0]);
|
||||
}
|
||||
|
||||
if (set)
|
||||
{
|
||||
if (strcmp(argv[5], "true") != 0 && strcmp(argv[5], "false") != 0 && strcmp(argv[5], "event")) {
|
||||
exit_with_usage_info(argv[0]);
|
||||
}
|
||||
state = argv[5][0] == 't';
|
||||
wait_for_event = argv[5][0] == 'e';
|
||||
}
|
||||
|
||||
// get Renode, machine and GPIO instances
|
||||
|
||||
renode_error_t *error;
|
||||
renode_t *renode;
|
||||
if ((error = renode_connect(argv[1], &renode)) != NO_ERROR) {
|
||||
fprintf(stderr, "Connecting to Renode failed with: %s\n", get_error_message(error));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
renode_machine_t *machine;
|
||||
if ((error = renode_get_machine(renode, machine_name, &machine)) != NO_ERROR) {
|
||||
fprintf(stderr, "Getting '%s' machine object failed with: %s\n", machine_name, get_error_message(error));
|
||||
goto fail_renode;
|
||||
}
|
||||
|
||||
renode_gpio_t *gpio;
|
||||
if ((error = renode_get_gpio(machine, gpio_name, &gpio)) != NO_ERROR) {
|
||||
fprintf(stderr, "Getting '%s' ADC object failed with: %s\n", gpio_name, get_error_message(error));
|
||||
goto fail_machine;
|
||||
}
|
||||
|
||||
// perform get/set
|
||||
|
||||
if (wait_for_event) {
|
||||
gpio_event_user_data user_data = (gpio_event_user_data){
|
||||
.machine_name = machine_name,
|
||||
.gpio_name = gpio_name,
|
||||
.pin_no = number,
|
||||
.run = true
|
||||
};
|
||||
|
||||
if ((error = renode_register_gpio_state_change_callback(gpio, number, &user_data, gpio_callback)) != NO_ERROR) {
|
||||
fprintf(stderr, "Registering event on pin #%d for '%s' failed with: %s\n", number, gpio_name, get_error_message(error));
|
||||
goto fail_gpio;
|
||||
}
|
||||
|
||||
while (user_data.run) {
|
||||
if ((error = renode_run_for(renode, TU_SECONDS, 60)) != NO_ERROR) {
|
||||
fprintf(stderr, "Run for failed with: %s\n", get_error_message(error));
|
||||
goto fail_gpio;
|
||||
}
|
||||
}
|
||||
} else if (set) {
|
||||
if ((error = renode_set_gpio_state(gpio, number, state)) != NO_ERROR) {
|
||||
fprintf(stderr, "Setting state on pin #%d for '%s' failed with: %s\n", number, gpio_name, get_error_message(error));
|
||||
goto fail_gpio;
|
||||
}
|
||||
|
||||
printf("GPIO set to: %s\n", state ? "true" : "false");
|
||||
} else {
|
||||
if ((error = renode_get_gpio_state(gpio, number, &state)) != NO_ERROR) {
|
||||
fprintf(stderr, "Getting state on pin #%d for '%s' failed with: %s\n", number, gpio_name, get_error_message(error));
|
||||
goto fail_gpio;
|
||||
}
|
||||
|
||||
printf("GPIO state: %s\n", state ? "true" : "false");
|
||||
}
|
||||
|
||||
// clean up
|
||||
|
||||
free(gpio);
|
||||
free(machine);
|
||||
if (try_renode_disconnect(&renode)) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
fail_gpio:
|
||||
free(gpio);
|
||||
fail_machine:
|
||||
free(machine);
|
||||
fail_renode:
|
||||
try_renode_disconnect(&renode);
|
||||
free(renode);
|
||||
fail:
|
||||
renode_free_error(error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
option(LOG_PERF "Logging performance data instead of elapsed virtual time" OFF)
|
||||
|
||||
if (LOG_PERF)
|
||||
add_compile_definitions(LOG_PERF)
|
||||
endif()
|
||||
308
tools/external_control_client/examples/run_for/main.c
Normal file
308
tools/external_control_client/examples/run_for/main.c
Normal file
@@ -0,0 +1,308 @@
|
||||
//
|
||||
// Copyright (c) 2010-2024 Antmicro
|
||||
//
|
||||
// This file is licensed under MIT License.
|
||||
// Full license text is available in 'licenses/MIT.txt' file.
|
||||
//
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "renode_api.h"
|
||||
|
||||
#define LINE_BUFFER_SIZE 86
|
||||
|
||||
char *get_error_message(renode_error_t *error)
|
||||
{
|
||||
if (error->message == NULL)
|
||||
{
|
||||
return "<no message>";
|
||||
}
|
||||
return error->message;
|
||||
}
|
||||
|
||||
#ifdef LOG_PERF
|
||||
#include <time.h>
|
||||
|
||||
static int tsi;
|
||||
static struct timespec t[2];
|
||||
|
||||
static void perf_start()
|
||||
{
|
||||
clock_gettime(CLOCK_REALTIME, &t[tsi]);
|
||||
}
|
||||
|
||||
static void perf_stop(uint64_t times, uint64_t value, renode_time_unit_t time_unit)
|
||||
{
|
||||
tsi ^= 1;
|
||||
clock_gettime(CLOCK_REALTIME, &t[tsi]);
|
||||
|
||||
int64_t seconds = t[tsi].tv_sec - t[tsi ^ 1].tv_sec;
|
||||
int64_t nanoseconds = t[tsi].tv_nsec - t[tsi ^ 1].tv_nsec;
|
||||
if(nanoseconds < 0)
|
||||
{
|
||||
seconds -= 1;
|
||||
nanoseconds += 1000000000;
|
||||
}
|
||||
int64_t microseconds = (nanoseconds + 500) / 1000;
|
||||
|
||||
int64_t virt_seconds = value * times / (time_unit == TU_SECONDS ? 1 : (time_unit == TU_MICROSECONDS ? 1000000 : 1000));
|
||||
int64_t virt_microseconds = (value * times) % (time_unit == TU_SECONDS ? 1 : (time_unit == TU_MICROSECONDS ? 1000000 : 1000));
|
||||
|
||||
fprintf(stderr, "delta: %lu.%06lus real\t %lu.%06lus virt\t real / virt %lf\n", seconds, microseconds, virt_seconds, virt_microseconds, (seconds * 1e6 + microseconds) / (virt_seconds * 1e6 + virt_microseconds));
|
||||
}
|
||||
|
||||
static void start_virtual_time_check(renode_t *renode)
|
||||
{
|
||||
(void)renode;
|
||||
}
|
||||
|
||||
static void stop_virtual_time_check(renode_t *renode, uint64_t value, renode_time_unit_t time_unit)
|
||||
{
|
||||
(void)renode;
|
||||
(void)value;
|
||||
(void)time_unit;
|
||||
}
|
||||
|
||||
#else // !LOG_PERF
|
||||
|
||||
static void perf_start() {}
|
||||
|
||||
static void perf_stop(uint64_t times, uint64_t value, renode_time_unit_t time_unit)
|
||||
{
|
||||
(void)times;
|
||||
(void)value;
|
||||
(void)time_unit;
|
||||
}
|
||||
|
||||
static uint64_t vt0;
|
||||
|
||||
static uint64_t get_current_virtual_time(renode_t *renode)
|
||||
{
|
||||
renode_error_t *error;
|
||||
uint64_t current_time;
|
||||
if ((error = renode_get_current_time(renode, TU_MICROSECONDS, ¤t_time)) != NO_ERROR) {
|
||||
fprintf(stderr, "Get current time failed with: %s\n", get_error_message(error));
|
||||
renode_free_error(error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return current_time;
|
||||
}
|
||||
|
||||
static void start_virtual_time_check(renode_t *renode)
|
||||
{
|
||||
vt0 = get_current_virtual_time(renode);
|
||||
}
|
||||
|
||||
static void stop_virtual_time_check(renode_t *renode, uint64_t value, renode_time_unit_t time_unit)
|
||||
{
|
||||
uint64_t vt1 = get_current_virtual_time(renode);
|
||||
uint64_t vt_delta = vt1 - vt0;
|
||||
|
||||
int microseconds = vt1 % TU_SECONDS;
|
||||
int seconds_total = vt1 / TU_SECONDS;
|
||||
int seconds = seconds_total % 60;
|
||||
int minutes_total = seconds_total / 60;
|
||||
int minutes = minutes_total % 60;
|
||||
int hours_total = minutes_total / 60;
|
||||
|
||||
printf("Elapsed virtual time %02d:%02d:%02d.%06d\n", hours_total, minutes, seconds, microseconds);
|
||||
|
||||
if (vt_delta != value * time_unit) {
|
||||
fprintf(stderr, "Reported current virtual time doesn't match the expected virtual time after running for the requested interval\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void exit_with_usage_info(const char *argv0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage:\n"
|
||||
" %s <PORT> <VALUE_WITH_UNIT> [<REPEAT>]\n"
|
||||
" where:\n"
|
||||
" * <VALUE_WITH_UNIT> is an integer with a time unit, e.g.: '100ms'\n"
|
||||
" * accepted time units are 's', 'ms' and 'us' (for microseconds)\n"
|
||||
" * <REPEAT> is an optional number of times (default: 1) to run\n"
|
||||
" * the simulation for\n",
|
||||
argv0);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
bool read_time_value(char *buffer, char **endptr, uint64_t *value, renode_time_unit_t *time_unit)
|
||||
{
|
||||
char *noendptr;
|
||||
if (endptr == NULL) {
|
||||
endptr = &noendptr;
|
||||
}
|
||||
// base=0 tries to figure out the number's base automatically.
|
||||
uint64_t new_value = strtoull(buffer, endptr, /* base: */ 0);
|
||||
if (errno != 0) {
|
||||
perror("conversion to uint64_t value");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (*endptr == buffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
renode_time_unit_t unit = -1;
|
||||
switch (**endptr) {
|
||||
case 'u':
|
||||
unit = TU_MICROSECONDS;
|
||||
*endptr += 2;
|
||||
break;
|
||||
case 'm':
|
||||
unit = TU_MILLISECONDS;
|
||||
*endptr += 2;
|
||||
break;
|
||||
case 's':
|
||||
unit = TU_SECONDS;
|
||||
*endptr += 1;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
*value = new_value;
|
||||
*time_unit = unit;
|
||||
return true;
|
||||
}
|
||||
|
||||
void run_options_prompt(uint64_t *value, renode_time_unit_t *time_unit, uint64_t *times)
|
||||
{
|
||||
char option;
|
||||
bool retry;
|
||||
|
||||
do {
|
||||
retry = false;
|
||||
printf("Continue running for %lu%ss %lu times? [y/N/c] ", *value, *time_unit == TU_MICROSECONDS ? "u" : (*time_unit == TU_MILLISECONDS ? "m" : ""), *times);
|
||||
|
||||
if ((option = getchar()) != '\n') while(getchar() != '\n');
|
||||
|
||||
switch (option)
|
||||
{
|
||||
case 'y':
|
||||
case 'Y':
|
||||
return;
|
||||
case 'c':
|
||||
case 'C':
|
||||
printf("Enter new value: ");
|
||||
{
|
||||
char buffer[LINE_BUFFER_SIZE];
|
||||
char *endptr;
|
||||
|
||||
if (fgets(buffer, LINE_BUFFER_SIZE, stdin) != buffer) {
|
||||
fprintf(stderr, "Failed to read line\n");
|
||||
retry = true;
|
||||
break;
|
||||
}
|
||||
|
||||
size_t len = strlen(buffer);
|
||||
if (len == LINE_BUFFER_SIZE - 1 && buffer[len - 1] != '\n') {
|
||||
fprintf(stderr, "Failed to read line: line too long\n");
|
||||
retry = true;
|
||||
break;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
if (!read_time_value(buffer, &endptr, value, time_unit)) {
|
||||
fprintf(stderr, "Failed to parse time value\n");
|
||||
retry = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (*endptr != '\n' && *endptr != '\0')
|
||||
{
|
||||
*times = strtoull(endptr, NULL, /* base: */ 0);
|
||||
if (errno != 0) {
|
||||
perror("conversion to uint64_t value");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*times = 1;
|
||||
}
|
||||
}
|
||||
return;
|
||||
case '\n':
|
||||
case 'n':
|
||||
case 'N':
|
||||
*times = 0;
|
||||
return;
|
||||
default:
|
||||
retry = true;
|
||||
break;
|
||||
}
|
||||
|
||||
} while(retry);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 3 || 4 < argc) {
|
||||
exit_with_usage_info(argv[0]);
|
||||
}
|
||||
|
||||
uint64_t value;
|
||||
renode_time_unit_t time_unit;
|
||||
if (!read_time_value(argv[2], NULL, &value, &time_unit)) {
|
||||
exit_with_usage_info(argv[0]);
|
||||
}
|
||||
|
||||
uint64_t times = 1;
|
||||
if (argc == 4)
|
||||
{
|
||||
times = strtoull(argv[3], NULL, /* base: */ 0);
|
||||
if (errno != 0) {
|
||||
perror("conversion to uint64_t value");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
renode_error_t *error;
|
||||
renode_t *renode;
|
||||
if ((error = renode_connect(argv[1], &renode)) != NO_ERROR) {
|
||||
fprintf(stderr, "Connecting to Renode failed with: %s\n", get_error_message(error));
|
||||
renode_free_error(error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
perf_start();
|
||||
|
||||
uint64_t i = times;
|
||||
while(i > 0)
|
||||
{
|
||||
start_virtual_time_check(renode);
|
||||
|
||||
if ((error = renode_run_for(renode, time_unit, value)) != NO_ERROR) {
|
||||
fprintf(stderr, "Run for failed with: %s\n", get_error_message(error));
|
||||
renode_free_error(error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
stop_virtual_time_check(renode, value, time_unit);
|
||||
|
||||
i -= 1;
|
||||
if (i == 0)
|
||||
{
|
||||
perf_stop(times, value, time_unit);
|
||||
run_options_prompt(&value, &time_unit, ×);
|
||||
i = times;
|
||||
perf_start();
|
||||
}
|
||||
}
|
||||
|
||||
if ((error = renode_disconnect(&renode)) != NO_ERROR) {
|
||||
fprintf(stderr, "Disconnecting from Renode failed with: %s\n", get_error_message(error));
|
||||
renode_free_error(error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
107
tools/external_control_client/examples/sysbus/main.c
Normal file
107
tools/external_control_client/examples/sysbus/main.c
Normal file
@@ -0,0 +1,107 @@
|
||||
//
|
||||
// Copyright (c) 2010-2025 Antmicro
|
||||
//
|
||||
// This file is licensed under MIT License.
|
||||
// Full license text is available in 'licenses/MIT.txt' file.
|
||||
//
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "renode_api.h"
|
||||
|
||||
static void print_usage(const char *argv0)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage:\n"
|
||||
" %s <PORT> <MACHINE_NAME> <PERIPHERAL_NAME> <ADDRESS>\n",
|
||||
argv0);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 5) {
|
||||
print_usage(argv[0]);
|
||||
}
|
||||
|
||||
const char *port = argv[1];
|
||||
const char *machine_name = argv[2];
|
||||
const char *peripheral_name = argv[3];
|
||||
uint64_t address = strtoll(argv[4], NULL, 16);
|
||||
|
||||
renode_error_t *err;
|
||||
|
||||
renode_t *renode;
|
||||
err = renode_connect(port, &renode);
|
||||
if (err != NO_ERROR) {
|
||||
fprintf(stderr, "Failed to connect to Renode on port %s (%s)\n", port, err->message);
|
||||
renode_disconnect(&renode);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
renode_machine_t *machine;
|
||||
err = renode_get_machine(renode, machine_name, &machine);
|
||||
if (err != NO_ERROR) {
|
||||
fprintf(stderr, "Failed to obtain machine '%s' (%s)\n", machine_name, err->message);
|
||||
renode_disconnect(&renode);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Perform a bus transaction
|
||||
|
||||
renode_bus_context_t *sysbus;
|
||||
err = renode_get_sysbus(machine, &sysbus);
|
||||
if (err != NO_ERROR) {
|
||||
fprintf(stderr, "Failed to obtain the system bus '%s' (%s)\n", machine_name, err->message);
|
||||
renode_disconnect(&renode);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
uint32_t bus_data_write = 0xDDCCBBAA;
|
||||
err = renode_sysbus_write(sysbus, address, AW_MULTI_BYTE, &bus_data_write, sizeof(bus_data_write));
|
||||
if (err != NO_ERROR) {
|
||||
fprintf(stderr, "System bus write failed (%s)\n", err->message);
|
||||
renode_disconnect(&renode);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
uint32_t bus_data_read;
|
||||
err = renode_sysbus_read(sysbus, address, AW_BYTE, &bus_data_read, sizeof(bus_data_read));
|
||||
if (err != NO_ERROR) {
|
||||
fprintf(stderr, "System bus read failed (%s)\n", err->message);
|
||||
renode_disconnect(&renode);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
printf("(BUS @ 0x%lx) %s: written = 0x%x, read = 0x%x to 0x%lx\n", address, bus_data_read == bus_data_write ? "SUCCESS" : "FAILURE", bus_data_write, bus_data_read, address);
|
||||
|
||||
// Perform a bus transaction with a peripheral context (seeing the bus from the perspective of the provided peripheral)
|
||||
|
||||
renode_bus_context_t *ctx;
|
||||
err = renode_get_bus_context(machine, peripheral_name, &ctx);
|
||||
if (err != NO_ERROR) {
|
||||
fprintf(stderr, "Failed to obtain peripheral '%s' (%s)\n", peripheral_name, err->message);
|
||||
renode_disconnect(&renode);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
uint64_t context_data_write = 0xAABBCCDDEEFF8899;
|
||||
err = renode_sysbus_write(ctx, address, AW_DOUBLE_WORD, &context_data_write, 2);
|
||||
if (err != NO_ERROR) {
|
||||
fprintf(stderr, "System bus write failed (%s)\n", err->message);
|
||||
renode_disconnect(&renode);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
uint64_t context_data_read;
|
||||
err = renode_sysbus_read(ctx, address, AW_QUAD_WORD, &context_data_read, 1);
|
||||
if (err != NO_ERROR) {
|
||||
fprintf(stderr, "System bus read failed (%s)\n", err->message);
|
||||
renode_disconnect(&renode);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
printf("(CONTEXT '%s' @ 0x%lx) %s: written = 0x%lx, read = 0x%lx\n", peripheral_name, address, context_data_read == context_data_write ? "SUCCESS" : "FAILURE", context_data_write, context_data_read);
|
||||
|
||||
renode_disconnect(&renode);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
Reference in New Issue
Block a user