From 0bf1c68d94b9e9ce3c07ff2df471e17127779b1f Mon Sep 17 00:00:00 2001 From: bLueriVerLHR Date: Thu, 11 May 2023 17:55:41 +0800 Subject: [PATCH] [Add] software simulator add --- CMakeLists.txt | 1 + include/common.h | 36 +++++++++++ include/devaddr.h | 22 +++++++ labus/device.cc | 1 + labus/include/device.hh | 140 ++++++++++++++++++++++++++++++++++++++++ labus/include/memory.hh | 19 ++++++ labus/include/serial.hh | 10 +++ labus/include/sysbus.hh | 34 +++++++++- labus/memory.cc | 40 ++++++++++++ labus/serial.cc | 10 +++ labus/sysbus.cc | 67 ++++++++++++++++++- lasim/include/la32r.hh | 9 +++ lasim/include/spec.hh | 0 lasim/la32r.cc | 115 +++++++++++++++++++++++++++++++++ lasim/main.cc | 41 ++++++++++-- lasim/spec.cc | 0 16 files changed, 535 insertions(+), 10 deletions(-) create mode 100644 include/common.h create mode 100644 include/devaddr.h create mode 100644 labus/device.cc create mode 100644 labus/include/device.hh create mode 100644 labus/include/memory.hh create mode 100644 labus/include/serial.hh create mode 100644 labus/memory.cc create mode 100644 labus/serial.cc create mode 100644 lasim/include/la32r.hh delete mode 100644 lasim/include/spec.hh create mode 100644 lasim/la32r.cc delete mode 100644 lasim/spec.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index a941f29..b3dd546 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,7 @@ if (${CMAKE_BUILD_TYPE} STREQUAL "Debug") add_compile_options(-D DEBUG_MODE) endif() +include_directories(${CMAKE_SOURCE_DIR}/include) # ----- ----- 构建虚拟外设 ----- ----- set(LABUS labus) diff --git a/include/common.h b/include/common.h new file mode 100644 index 0000000..3275391 --- /dev/null +++ b/include/common.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include +#include +#include + +#ifndef COMMON_H__ +#define COMMON_H__ + +#ifdef DEBUG_MODE +#define Log(fmt, ...) printf("[%s@%d %ld] " fmt "\n", __FILE__, __LINE__, clock(), ## __VA_ARGS__) + +#define panic(x) do { \ + Log(x); \ + exit(EXIT_FAILURE); \ +} while (0) + +#define panicifnot(cond) do { \ + if (!(cond)) { \ + Log(#cond " fail"); \ + exit(EXIT_FAILURE); \ + } \ +} while (0) + +#else + +#define Log(...) +#define panic(x) +#define panicifnot(cond) + +#endif + +#endif + diff --git a/include/devaddr.h b/include/devaddr.h new file mode 100644 index 0000000..3cfafd5 --- /dev/null +++ b/include/devaddr.h @@ -0,0 +1,22 @@ +#pragma once + +#ifndef DEVADDR_H__ +#define DEVADDR_H__ + +#define RAM_ADDR 0x0000'0000 +#define IMG_ADDR 0x0000'8000 +#define STK_ADDR 0x2000'0000 + +#define DEVICE_BASE 0xa0000000 +#define MMIO_BASE 0xa0000000 + +#define SERIAL_PORT (DEVICE_BASE + 0x00003f8) +#define KBD_ADDR (DEVICE_BASE + 0x0000060) +#define RTC_ADDR (DEVICE_BASE + 0x0000048) +#define VGACTL_ADDR (DEVICE_BASE + 0x0000100) +#define AUDIO_ADDR (DEVICE_BASE + 0x0000200) +#define DISK_ADDR (DEVICE_BASE + 0x0000300) +#define FB_ADDR (MMIO_BASE + 0x1000000) +#define AUDIO_SBUF_ADDR (MMIO_BASE + 0x1200000) + +#endif \ No newline at end of file diff --git a/labus/device.cc b/labus/device.cc new file mode 100644 index 0000000..78e4ba6 --- /dev/null +++ b/labus/device.cc @@ -0,0 +1 @@ +#include \ No newline at end of file diff --git a/labus/include/device.hh b/labus/include/device.hh new file mode 100644 index 0000000..a16e888 --- /dev/null +++ b/labus/include/device.hh @@ -0,0 +1,140 @@ +#pragma once + +#include +#include + +class Device { +public: + Device() = default; + + virtual const size_t &size() const = 0; + + virtual void write(char *buf, size_t addr, size_t len) = 0; + virtual void read(char *buf, size_t addr, size_t len) = 0; + + virtual void write64(uint64_t &dword, size_t addr) = 0; + virtual void read64(uint64_t &dword, size_t addr) = 0; + + virtual void write32(uint32_t &word, size_t addr) = 0; + virtual void read32(uint32_t &word, size_t addr) = 0; + + virtual void write16(uint16_t &hword, size_t addr) = 0; + virtual void read16(uint16_t &hword, size_t addr) = 0; + + virtual void write8(uint8_t &byte, size_t addr) = 0; + virtual void read8(uint8_t &byte, size_t addr) = 0; + + virtual ~Device() = default; +}; + +template +class WRDevice : public Device{ + size_t devsiz; +public: + WRDevice(size_t siz); + + virtual const size_t &size() const; + + virtual void write(char *buf, size_t addr, size_t len); + virtual void read(char *buf, size_t addr, size_t len); + + virtual void write64(uint64_t &dword, size_t addr); + virtual void read64(uint64_t &dword, size_t addr); + + virtual void write32(uint32_t &word, size_t addr); + virtual void read32(uint32_t &word, size_t addr); + + virtual void write16(uint16_t &hword, size_t addr); + virtual void read16(uint16_t &hword, size_t addr); + + virtual void write8(uint8_t &byte, size_t addr); + virtual void read8(uint8_t &byte, size_t addr); + + virtual ~WRDevice() = default; +}; + +template +WRDevice::WRDevice(size_t siz) : devsiz(siz) {} + +template +const size_t &WRDevice::size() const { return devsiz; } + +template +void WRDevice::write(char *buf, size_t addr, size_t len) {} + +template +void WRDevice::read(char *buf, size_t addr, size_t len) {} + +template +void WRDevice::write64(uint64_t &dword, size_t addr) { + uint8_t buf[sizeof(dword)]; + buf[0] = (dword >> 0) & 0xFF; + buf[1] = (dword >> 8) & 0xFF; + buf[2] = (dword >> 16) & 0xFF; + buf[3] = (dword >> 24) & 0xFF; + buf[4] = (dword >> 32) & 0xFF; + buf[5] = (dword >> 40) & 0xFF; + buf[6] = (dword >> 48) & 0xFF; + buf[7] = (dword >> 56) & 0xFF; + static_cast(this)->write((char *)buf, addr, sizeof(dword)); +} + +template +void WRDevice::read64(uint64_t &dword, size_t addr) { + uint8_t buf[sizeof(dword)]; + static_cast(this)->read((char *)buf, addr, sizeof(dword)); + dword = (uint64_t) buf[0]; + dword |= (uint64_t) buf[1] << 8; + dword |= (uint64_t) buf[2] << 16; + dword |= (uint64_t) buf[3] << 24; + dword |= (uint64_t) buf[4] << 32; + dword |= (uint64_t) buf[5] << 40; + dword |= (uint64_t) buf[6] << 48; + dword |= (uint64_t) buf[7] << 56; +} + +template +void WRDevice::write32(uint32_t &word, size_t addr) { + uint8_t buf[sizeof(word)]; + buf[0] = (word >> 0) & 0xFF; + buf[1] = (word >> 8) & 0xFF; + buf[2] = (word >> 16) & 0xFF; + buf[3] = (word >> 24) & 0xFF; + static_cast(this)->write((char *)buf, addr, sizeof(word)); +} + +template +void WRDevice::read32(uint32_t &word, size_t addr) { + uint8_t buf[sizeof(word)]; + static_cast(this)->read((char *)buf, addr, sizeof(word)); + word = (uint32_t) buf[0]; + word |= (uint32_t) buf[1] << 8; + word |= (uint32_t) buf[2] << 16; + word |= (uint32_t) buf[3] << 24; +} + +template +void WRDevice::write16(uint16_t &hword, size_t addr) { + uint8_t buf[sizeof(hword)]; + buf[0] = (hword >> 0) & 0xFF; + buf[1] = (hword >> 8) & 0xFF; + static_cast(this)->write((char *)buf, addr, sizeof(hword)); +} + +template +void WRDevice::read16(uint16_t &hword, size_t addr) { + uint8_t buf[sizeof(hword)]; + static_cast(this)->read((char *)buf, addr, sizeof(hword)); + hword = (uint16_t) buf[0]; + hword |= (uint16_t) buf[1] << 8; +} + +template +void WRDevice::write8(uint8_t &byte, size_t addr) { + static_cast(this)->write((char *)&byte, addr, sizeof(byte)); +} + +template +void WRDevice::read8(uint8_t &byte, size_t addr) { + static_cast(this)->read((char *)&byte, addr, sizeof(byte)); +} \ No newline at end of file diff --git a/labus/include/memory.hh b/labus/include/memory.hh new file mode 100644 index 0000000..95f943b --- /dev/null +++ b/labus/include/memory.hh @@ -0,0 +1,19 @@ +#pragma once + +#include + +class Memory : public WRDevice { + char *data; + bool wen; + bool ren; + bool xen; +public: + Memory(size_t siz, bool w = true, bool r = true, bool x = true); + ~Memory(); + + void load(const char *path); + void load(Memory *mem, size_t addr, size_t len); + + void write(char *buf, size_t addr, size_t len); + void read(char *buf, size_t addr, size_t len); +}; \ No newline at end of file diff --git a/labus/include/serial.hh b/labus/include/serial.hh new file mode 100644 index 0000000..70df009 --- /dev/null +++ b/labus/include/serial.hh @@ -0,0 +1,10 @@ +#pragma once + +#include + +class Serial : public WRDevice { +public: + Serial(size_t siz); + + void write(char *buf, size_t addr, size_t len); +}; \ No newline at end of file diff --git a/labus/include/sysbus.hh b/labus/include/sysbus.hh index ed99f2c..2366e09 100644 --- a/labus/include/sysbus.hh +++ b/labus/include/sysbus.hh @@ -1 +1,33 @@ -int fetch(); \ No newline at end of file +#pragma once + +#include +#include +#include + +#include + +class SystemBus { + std::map iomap; + + std::pair &finddev(uint64_t addr); + +public: + SystemBus() = default; + + void regdev(Device *dev, uint64_t addr); + + void write(char *buf, size_t addr, size_t len); + void read(char *buf, size_t addr, size_t len); + + void write64(uint64_t &dword, size_t addr); + void read64(uint64_t &dword, size_t addr); + + void write32(uint32_t &word, size_t addr); + void read32(uint32_t &word, size_t addr); + + void write16(uint16_t &hword, size_t addr); + void read16(uint16_t &hword, size_t addr); + + void write8(uint8_t &byte, size_t addr); + void read8(uint8_t &byte, size_t addr); +}; \ No newline at end of file diff --git a/labus/memory.cc b/labus/memory.cc new file mode 100644 index 0000000..a0dc33a --- /dev/null +++ b/labus/memory.cc @@ -0,0 +1,40 @@ +#include +#include + +Memory::Memory(size_t siz, bool w, bool r, bool x) + : WRDevice(siz), wen(w), ren(r), xen(x) { + data = new char[siz]; + memset((void *)data, 0, siz); +} + +Memory::~Memory() { + if (data) { + delete [] data; + } +} + +void Memory::load(const char *path) { + std::fstream ifs(path, std::ios::in | std::ios::binary); + panicifnot(ifs); + ifs.read(data, this->size()); + ifs.close(); +} + +void Memory::load(Memory *mem, size_t addr, size_t len) { + panicifnot(addr + len < this->size()); + memcpy(&data[addr], mem->data, len); +} + +void Memory::write(char *buf, size_t addr, size_t len) { + if (!wen) + panic("permission denied"); + size_t actlen = addr + len >= this->size() ? this->size() - addr : len; + memcpy(&data[addr], buf, actlen); +} + +void Memory::read(char *buf, size_t addr, size_t len) { + if (!ren) + panic("permission denied"); + size_t actlen = addr + len >= this->size() ? this->size() - addr : len; + memcpy(buf, &data[addr], actlen); +} \ No newline at end of file diff --git a/labus/serial.cc b/labus/serial.cc new file mode 100644 index 0000000..a3d94fe --- /dev/null +++ b/labus/serial.cc @@ -0,0 +1,10 @@ +#include +#include + +Serial::Serial(size_t siz) : WRDevice(siz) {} + +void Serial::write(char *buf, size_t addr, size_t len) { + for (size_t i = 0; i < len; ++i) + putc(buf[i], stdout); + fflush(stdout); +} \ No newline at end of file diff --git a/labus/sysbus.cc b/labus/sysbus.cc index 16a81ef..d547ddd 100644 --- a/labus/sysbus.cc +++ b/labus/sysbus.cc @@ -1,3 +1,66 @@ -int fetch() { - return 0; +#include +#include + +std::pair &SystemBus::finddev(uint64_t addr) { + Device *dev = nullptr; + auto &&iter = iomap.upper_bound(addr); + if (iter == iomap.begin()) + panic("device not found"); + iter--; + if (iter->first <= addr && iter->first + iter->second->size() > addr) + dev = iter->second; + panicifnot(dev); + return *iter; +} + +void SystemBus::regdev(Device *dev, uint64_t addr) { iomap.emplace(addr, dev); } + +void SystemBus::write(char *buf, size_t addr, size_t len) { + auto &&dev = finddev(addr); + dev.second->write(buf, addr - dev.first, len); +} + +void SystemBus::read(char *buf, size_t addr, size_t len) { + auto &&dev = finddev(addr); + dev.second->read(buf, addr - dev.first, len); +} + +void SystemBus::write64(uint64_t &dword, size_t addr) { + auto &&dev = finddev(addr); + dev.second->write64(dword, addr - dev.first); +} + +void SystemBus::read64(uint64_t &dword, size_t addr) { + auto &&dev = finddev(addr); + dev.second->read64(dword, addr - dev.first); +} + +void SystemBus::write32(uint32_t &word, size_t addr) { + auto &&dev = finddev(addr); + dev.second->write32(word, addr - dev.first); +} + +void SystemBus::read32(uint32_t &word, size_t addr) { + auto &&dev = finddev(addr); + dev.second->read32(word, addr - dev.first); +} + +void SystemBus::write16(uint16_t &hword, size_t addr) { + auto &&dev = finddev(addr); + dev.second->write16(hword, addr - dev.first); +} + +void SystemBus::read16(uint16_t &hword, size_t addr) { + auto &&dev = finddev(addr); + dev.second->read16(hword, addr - dev.first); +} + +void SystemBus::write8(uint8_t &byte, size_t addr) { + auto &&dev = finddev(addr); + dev.second->write8(byte, addr - dev.first); +} + +void SystemBus::read8(uint8_t &byte, size_t addr) { + auto &&dev = finddev(addr); + dev.second->read8(byte, addr - dev.first); } \ No newline at end of file diff --git a/lasim/include/la32r.hh b/lasim/include/la32r.hh new file mode 100644 index 0000000..464dfae --- /dev/null +++ b/lasim/include/la32r.hh @@ -0,0 +1,9 @@ +#pragma once + +#include + +class LA32R { +public: + LA32R(SystemBus *bus); + void Step(unsigned in); +}; \ No newline at end of file diff --git a/lasim/include/spec.hh b/lasim/include/spec.hh deleted file mode 100644 index e69de29..0000000 diff --git a/lasim/la32r.cc b/lasim/la32r.cc new file mode 100644 index 0000000..e724a03 --- /dev/null +++ b/lasim/la32r.cc @@ -0,0 +1,115 @@ +#include +#include + +namespace { +using u64 = uint64_t; +using i64 = int64_t; + +using u32 = uint32_t; +using i32 = int32_t; + +SystemBus *sysbus; + +enum regenum { + R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, + R10, R11, R12, R13, R14, R15, R16, R17, R18, R19, + R20, R21, R22, R23, R24, R25, R26, R27, R28, R29, + R30, R31, PC +}; + +enum PLV { + PLV0, + // PLV1, + // PLV2, + PLV3, +} PrivilegeLevel ; + +class Registers { +private: + u32 regs_[32] = {0}; + u32 pc_ = 0; + +public: + Registers() = default; + + u32 get(u32 idx) { + panicifnot((0 <= idx && 32 >= idx) || idx == PC); + if (idx == PC) { + return pc_; + } + + if (0 <= idx && 32 >= idx) { + return regs_[idx]; + } + + panic("Unexpected register access"); + } + + void set(u32 idx, u32 data) { + panicifnot((0 <= idx && 32 >= idx) || idx == PC); + if (idx == PC) { + pc_ = data; + } + + if (0 <= idx && 32 >= idx) { + regs_[idx] = data; + } + + panic("Unexpected register access"); + + } + + u32 &operator[](u32 idx) { + if (idx == PC) { + return pc_; + } + + if (0 <= idx && 32 >= idx) { + return regs_[idx]; + } + + panic("Unexpected register access"); + } +} Regs ; + +constexpr u32 getbits(u32 hi, u32 lo, u32 data) { + data = data >> lo; + u32 mask = ((u64) 0x1 << (hi + 1)) - 1; + return data & mask; +} + +void decode_and_exec(u32 inst) { + + if (getbits(31, 15, inst) == 0b00000000000100000) { + u32 rd = getbits( 4, 0, inst); + u32 rj = getbits( 9, 5, inst); + u32 rk = getbits(14, 10, inst); + + u32 tmp = Regs[rj] + Regs[rk]; + Regs[rd] = getbits(31, 0, tmp); + return; + } + + panic("Invalid operation or have not implemented yet."); +} + +u32 fetch() { + u32 inst; + sysbus->read32(inst, Regs[PC]); + return inst; +} + +} + + +LA32R::LA32R(SystemBus *bus) { + sysbus = bus; + + Regs[PC] = 0x0000'0000; +} + +void LA32R::Step(unsigned in) { + u32 inst = fetch(); + decode_and_exec(inst); + Regs[PC] += 4; +} \ No newline at end of file diff --git a/lasim/main.cc b/lasim/main.cc index 2f427c9..cc9ff32 100644 --- a/lasim/main.cc +++ b/lasim/main.cc @@ -1,11 +1,38 @@ -#include - #include -int main() { - fetch(); -#ifdef DEBUG_MODE - std::cout << "Hello" << std::endl; -#endif +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) { + if (argc < 2) { + std::cout << "Usage: sim "; return 0; + } + + SystemBus bus; + Memory ram(2 * 1024 * 1024); + Memory stk(256 * 1024); + + Memory flash(1024 * 1024); + flash.load(argv[1]); + ram.load(&flash, IMG_ADDR, flash.size()); + + bus.regdev(&ram, RAM_ADDR); + bus.regdev(&stk, STK_ADDR); + + Serial bios(1); + bus.regdev(&bios, SERIAL_PORT); + + auto cpu = new LA32R(&bus); + + while (true) { + cpu->Step(1); + } + + delete cpu; + return 0; } \ No newline at end of file diff --git a/lasim/spec.cc b/lasim/spec.cc deleted file mode 100644 index e69de29..0000000