2023-07-24 00:01:39 -04:00
|
|
|
//! A test harness for testing if the riscv library actually works.
|
|
|
|
#include <cstdio> // I know, I know, but this is a test program. Yell later :)
|
|
|
|
#include <lucore/Assert.hpp>
|
|
|
|
#include <lucore/Logger.hpp>
|
2023-07-24 01:56:50 -04:00
|
|
|
#include <lucore/StdoutSink.hpp>
|
|
|
|
#include <riscv/System.hpp>
|
2023-07-21 06:32:04 -04:00
|
|
|
|
2023-07-24 20:17:07 -04:00
|
|
|
#include <thread>
|
|
|
|
|
2023-07-21 06:32:04 -04:00
|
|
|
/// simple 16550 UART implementation
|
|
|
|
struct SimpleUartDevice : public riscv::Bus::MmioDevice {
|
2023-07-23 18:13:03 -04:00
|
|
|
constexpr static riscv::Address BASE_ADDRESS = 0x10000000;
|
2023-07-21 06:32:04 -04:00
|
|
|
|
2023-07-23 18:13:03 -04:00
|
|
|
riscv::Address Base() const override { return BASE_ADDRESS; }
|
2023-07-21 06:32:04 -04:00
|
|
|
|
2023-07-24 00:01:39 -04:00
|
|
|
riscv::Address Size() const override { return 12; } // for now
|
2023-07-21 06:32:04 -04:00
|
|
|
|
2023-07-23 18:13:03 -04:00
|
|
|
u32 Peek(riscv::Address address) override {
|
2023-07-21 06:32:04 -04:00
|
|
|
switch(address) {
|
2023-07-24 06:50:18 -04:00
|
|
|
case BASE_ADDRESS: return '\0'; // just return 0 for the input register
|
|
|
|
case BASE_ADDRESS + 5: return 0x60; // active, but no keyboard input
|
2023-07-21 06:32:04 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-07-23 18:13:03 -04:00
|
|
|
void Poke(riscv::Address address, u32 value) override {
|
2023-07-24 00:01:39 -04:00
|
|
|
if(address == BASE_ADDRESS) {
|
|
|
|
char c = value & 0x000000ff;
|
|
|
|
fputc(c, stderr);
|
2023-07-21 06:32:04 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2023-07-22 22:46:36 -04:00
|
|
|
|
2023-07-24 00:01:39 -04:00
|
|
|
int main(int argc, char** argv) {
|
|
|
|
lucore::LoggerAttachStdout();
|
|
|
|
|
|
|
|
LUCORE_CHECK(argc == 2, "this test harness expects one argument (the file to load into riscv memory and execute). got {} arguments", argc);
|
2023-07-24 01:56:50 -04:00
|
|
|
|
2023-07-24 00:01:39 -04:00
|
|
|
// 128 KB of ram. Won't be enough to boot linux but should be good enough to test most baremetal apps
|
|
|
|
auto system = riscv::System::Create(128 * 1024);
|
2023-07-24 00:20:40 -04:00
|
|
|
LUCORE_CHECK(system, "could not create system for some reason.");
|
2023-07-24 00:01:39 -04:00
|
|
|
|
|
|
|
// Attach our UART device
|
|
|
|
system->bus->AttachDevice(new SimpleUartDevice);
|
|
|
|
|
|
|
|
auto fp = std::fopen(argv[1], "rb");
|
|
|
|
LUCORE_CHECK(fp, "could not open file \"{}\"", argv[1]);
|
|
|
|
|
2023-07-24 01:56:50 -04:00
|
|
|
std::fseek(fp, 0, SEEK_END);
|
|
|
|
auto len = std::ftell(fp);
|
|
|
|
std::fseek(fp, 0, SEEK_SET);
|
|
|
|
|
|
|
|
std::fread(system->ram->Raw(), 1, len, fp);
|
|
|
|
std::fclose(fp);
|
2023-07-24 00:01:39 -04:00
|
|
|
|
2023-07-24 01:56:50 -04:00
|
|
|
// This allows the host program running under the test
|
|
|
|
// harness to tell us to shut down.
|
|
|
|
bool shouldExit = false;
|
|
|
|
system->OnPowerOff = [&shouldExit]() { shouldExit = true; };
|
2023-07-24 00:01:39 -04:00
|
|
|
|
2023-07-24 01:56:50 -04:00
|
|
|
while(!shouldExit) {
|
2023-07-24 00:01:39 -04:00
|
|
|
system->Step();
|
2023-07-24 20:17:07 -04:00
|
|
|
//std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
2023-07-24 00:01:39 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
delete system;
|
2023-07-22 22:46:36 -04:00
|
|
|
return 0;
|
|
|
|
}
|