You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
263 lines
7.6 KiB
263 lines
7.6 KiB
#include <riscv/sim.h>
|
|
#include <riscv/dtb_discovery.h>
|
|
#include <riscv/devices.h>
|
|
#include <riscv/mmu.h>
|
|
#include <fdt/libfdt.h>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <map>
|
|
#include <vector>
|
|
#include <string>
|
|
#include <filesystem>
|
|
#include <cstring>
|
|
#include <dlfcn.h>
|
|
|
|
#include "led-device.h"
|
|
|
|
struct expected_mem_t {
|
|
reg_t base;
|
|
};
|
|
|
|
struct expected_device_t {
|
|
const std::type_info* compatible;
|
|
reg_t base;
|
|
};
|
|
|
|
struct test_case_t {
|
|
std::vector<expected_mem_t> memory;
|
|
std::vector<expected_device_t> devices;
|
|
};
|
|
|
|
// Key: pair of (filename, dtb_discovery_enabled)
|
|
using test_key_t = std::pair<std::string, bool>;
|
|
|
|
static std::map<test_key_t, test_case_t> test_cases_expected_results = {
|
|
// With DTB discovery enabled
|
|
{ {"mem-64bit-single.dtb", true}, {
|
|
{{0x20000000ULL}},
|
|
{{&typeid(debug_module_t), 0x0ULL}}
|
|
}},
|
|
{ {"mem-64bit-single.dtb", false}, {
|
|
{},
|
|
{{&typeid(debug_module_t), 0x0ULL}}
|
|
}},
|
|
{ {"mem-32bit.dtb", true}, {
|
|
{{0x80000000ULL}},
|
|
{{&typeid(debug_module_t), 0x0ULL}}
|
|
}},
|
|
{ {"mem-32bit.dtb", false}, {
|
|
{},
|
|
{{&typeid(debug_module_t), 0x0ULL}}
|
|
}},
|
|
{ {"mem-multiple-nodes.dtb", true}, {
|
|
{{0x80000000ULL}, {0xA0000000ULL}},
|
|
{{&typeid(debug_module_t), 0x0ULL}}
|
|
}},
|
|
{ {"mem-multiple-nodes.dtb", false}, {
|
|
{},
|
|
{{&typeid(debug_module_t), 0x0ULL}}
|
|
}},
|
|
{ {"mem-mixed-cells-sizes.dtb", true}, {
|
|
{{0x100000000ULL}},
|
|
{{&typeid(debug_module_t), 0x0ULL}}
|
|
}},
|
|
{ {"mem-mixed-cells-sizes.dtb", false}, {
|
|
{},
|
|
{{&typeid(debug_module_t), 0x0ULL}}
|
|
}},
|
|
{ {"devices-single-led.dtb", true}, {
|
|
{},
|
|
{{&typeid(debug_module_t), 0x0ULL},
|
|
{&typeid(led_device_t), 0x10001000ULL}}
|
|
}},
|
|
{ {"devices-single-led.dtb", false}, {
|
|
{},
|
|
{{&typeid(debug_module_t), 0x0ULL}}
|
|
}},
|
|
{ {"devices-multiple-leds.dtb", true}, {
|
|
{{0x90000000ULL}},
|
|
{{&typeid(debug_module_t), 0x0ULL},
|
|
{&typeid(led_device_t), 0x10001000ULL},
|
|
{&typeid(led_device_t), 0x10002000ULL}}
|
|
}},
|
|
{ {"devices-multiple-leds.dtb", false}, {
|
|
{},
|
|
{{&typeid(debug_module_t), 0x0ULL}}
|
|
}},
|
|
{ {"devices-clint-plic-uart.dtb", true}, {
|
|
{{0x90000000ULL}},
|
|
{{&typeid(debug_module_t), 0x0ULL},
|
|
{&typeid(clint_t), 0x2000000ULL},
|
|
{&typeid(plic_t), 0xc000000ULL},
|
|
{&typeid(ns16550_t), 0x10000000ULL}}
|
|
}},
|
|
{ {"devices-clint-plic-uart.dtb", false}, {
|
|
{},
|
|
{{&typeid(debug_module_t), 0x0ULL},
|
|
{&typeid(clint_t), 0x2000000ULL},
|
|
{&typeid(plic_t), 0xc000000ULL},
|
|
{&typeid(ns16550_t), 0x10000000ULL}}
|
|
}}
|
|
};
|
|
|
|
bool check_memory_devices(const std::map<reg_t, abstract_device_t*>& devices,
|
|
const std::vector<expected_mem_t>& expected_memory) {
|
|
bool passed = true;
|
|
|
|
for (const auto& mem : expected_memory) {
|
|
auto it = devices.find(mem.base);
|
|
|
|
if (it == devices.end()) {
|
|
std::cerr << "Memory NOT found at 0x" << std::hex << mem.base << std::endl;
|
|
passed = false;
|
|
} else if (dynamic_cast<mem_t*>(it->second) == nullptr) {
|
|
std::cerr << "Device at 0x" << std::hex << mem.base
|
|
<< " is not mem_t type" << std::endl;
|
|
passed = false;
|
|
} else {
|
|
std::cout << "Memory found at 0x" << std::hex << mem.base << std::endl;
|
|
}
|
|
}
|
|
|
|
return passed;
|
|
}
|
|
|
|
bool check_devices(const std::map<reg_t, abstract_device_t*>& devices,
|
|
const std::vector<expected_device_t>& expected_devices) {
|
|
bool passed = true;
|
|
|
|
for (const auto& expected_device : expected_devices) {
|
|
auto it = devices.find(expected_device.base);
|
|
|
|
if (it == devices.end()) {
|
|
std::cerr << "Expected device not found at 0x" << std::hex << expected_device.base << std::endl;
|
|
passed = false;
|
|
continue;
|
|
}
|
|
|
|
const std::type_info& actual_type = typeid(*it->second);
|
|
|
|
if (*expected_device.compatible != actual_type) {
|
|
std::cerr << "Device at 0x" << std::hex << expected_device.base
|
|
<< " has wrong type. Expected: " << expected_device.compatible->name()
|
|
<< ", Got: " << actual_type.name() << std::endl;
|
|
passed = false;
|
|
} else {
|
|
std::cout << "Expected device found at 0x" << std::hex << expected_device.base
|
|
<< " Type: " << actual_type.name() << std::endl;
|
|
}
|
|
}
|
|
|
|
return passed;
|
|
}
|
|
|
|
bool check_no_unexpected_devices(const std::map<reg_t, abstract_device_t*>& devices,
|
|
const test_case_t& expected) {
|
|
size_t expected_count = expected.memory.size() + expected.devices.size();
|
|
|
|
if (devices.size() != expected_count) {
|
|
std::cerr << "Device count mismatch. Expected: " << expected_count
|
|
<< ", Got: " << devices.size() << std::endl;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool compare_devices(sim_t& sim, const test_case_t& expected) {
|
|
const auto& devices = sim.get_bus().get_devices();
|
|
|
|
bool no_extra_ok = check_no_unexpected_devices(devices, expected);
|
|
bool memory_ok = check_memory_devices(devices, expected.memory);
|
|
bool devices_ok= check_devices(devices, expected.devices);
|
|
|
|
return memory_ok && devices_ok && no_extra_ok;
|
|
}
|
|
|
|
bool run_test(const std::string& dtb_path, bool dtb_discovery,
|
|
const std::string& pk, const std::string& executable) {
|
|
// Extract filename from dtb path
|
|
std::filesystem::path p(dtb_path);
|
|
std::string dtb_filename = p.filename().string();
|
|
|
|
// Create test key
|
|
test_key_t test_key = {dtb_filename, dtb_discovery};
|
|
|
|
// Find expected layout
|
|
auto test_it = test_cases_expected_results.find(test_key);
|
|
if (test_it == test_cases_expected_results.end()) {
|
|
std::cout << "Error: No expected result for '" << dtb_filename
|
|
<< "' with dtb_discovery=" << (dtb_discovery ? "true" : "false") << "\n";
|
|
return false;
|
|
}
|
|
|
|
const auto& expected = test_it->second;
|
|
std::cout << "Testing: " << dtb_filename << "\n";
|
|
std::cout << "DTB Discovery: " << (dtb_discovery ? "enabled" : "disabled") << "\n";
|
|
|
|
// Setup simulator
|
|
cfg_t cfg;
|
|
std::vector<device_factory_sargs_t> devices;
|
|
std::vector<std::string> htif_args{pk, executable};
|
|
debug_module_config_t dm_config;
|
|
std::vector<std::pair<reg_t, abstract_mem_t*>> mems;
|
|
|
|
sim_t sim(&cfg, false,
|
|
mems,
|
|
devices,
|
|
dtb_discovery,
|
|
htif_args,
|
|
dm_config,
|
|
nullptr,
|
|
true,
|
|
dtb_path.c_str(),
|
|
false,
|
|
nullptr,
|
|
std::nullopt);
|
|
|
|
// Compare devices
|
|
bool result = compare_devices(sim, expected);
|
|
|
|
if (result) {
|
|
std::cout << "✓ TEST PASSED: " << dtb_filename
|
|
<< " (dtb_discovery=" << (dtb_discovery ? "enabled" : "disabled") << ")\n\n";
|
|
} else {
|
|
std::cout << "✗ TEST FAILED: " << dtb_filename
|
|
<< " (dtb_discovery=" << (dtb_discovery ? "enabled" : "disabled") << ")\n\n";
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
if (argc != 4) {
|
|
std::cerr << "Usage: " << argv[0] << " --dtb=<file> <pk> <executable>\n";
|
|
return 1;
|
|
}
|
|
|
|
std::string dtb_path;
|
|
std::string pk;
|
|
std::string executable;
|
|
|
|
// Parse arguments
|
|
int arg_idx = 1;
|
|
|
|
// First argument must be --dtb=
|
|
std::string dtb_arg = argv[arg_idx++];
|
|
if (dtb_arg.find("--dtb=") == 0) {
|
|
dtb_path = dtb_arg.substr(strlen("--dtb="));
|
|
} else {
|
|
std::cerr << "Error: First argument must be --dtb=<file>\n";
|
|
return 1;
|
|
}
|
|
|
|
// Remaining arguments are pk and executable
|
|
pk = argv[arg_idx++];
|
|
executable = argv[arg_idx];
|
|
|
|
// Run tests with both dtb_discovery values
|
|
bool test_dtb_discovery_disabled = run_test(dtb_path, false, pk, executable);
|
|
bool test_dtb_discovery_enabled = run_test(dtb_path, true, pk, executable);
|
|
|
|
return !(test_dtb_discovery_disabled && test_dtb_discovery_enabled);
|
|
}
|
|
|