仿真平台内核初版 -tlib库 包含<sparc arm riscv powerPC>

This commit is contained in:
liuwb
2026-02-07 20:43:43 +08:00
parent de61f9e2b0
commit b3117648be
9748 changed files with 4309137 additions and 0 deletions

View 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);
}

View 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);
}

View File

@@ -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()

View 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, &current_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, &times);
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);
}

View 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;
}