From efe12ca6bfe090cc73110ace1e8c24ab92b394a7 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Wed, 5 Jun 2024 11:19:06 -0400 Subject: [PATCH 01/75] Update README.md --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6eeb1ccfa..f0cfe45fe 100644 --- a/README.md +++ b/README.md @@ -57,9 +57,13 @@ More detailed build instructions can be found [here](docs/install_vortex.md). $ cd Vortex ### Configure your build folder # By default, the toolchain default install location is the /opt folder and can be overridden by setting --tooldir. - $ mkdir build - $ cd build - $ ../configure --xlen=32 --tooldir=$HOME/tools + # This is the example for volvo server +``` + mkdir build + cd build + ../configure --xlen=32 --tooldir=/software/vortex-toolchain-2024-05-22 + source ./ci/toolchain_env.sh +``` ### Install prebuilt toolchain $ ./ci/toolchain_install.sh --all ### set environment variables From 54af5eb1861a6d636c89313816245bde4a22cd05 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Wed, 5 Jun 2024 11:23:47 -0400 Subject: [PATCH 02/75] Update README.md --- README.md | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index f0cfe45fe..135dab466 100644 --- a/README.md +++ b/README.md @@ -47,14 +47,18 @@ More detailed build instructions can be found [here](docs/install_vortex.md). - [Yosys](https://github.com/YosysHQ/yosys) - [Sv2v](https://github.com/zachjs/sv2v) ### Install development tools - $ sudo apt-get install build-essential - $ sudo apt-get install binutils - $ sudo apt-get install python - $ sudo apt-get install uuid-dev - $ sudo apt-get install git +``` + sudo apt-get install build-essential + sudo apt-get install binutils + sudo apt-get install python + sudo apt-get install uuid-dev + sudo apt-get install git +``` ### Install Vortex codebase - $ git clone --depth=1 --recursive https://github.com/vortexgpgpu/vortex.git - $ cd Vortex +``` + git clone --depth=1 --recursive https://github.com/vortexgpgpu/vortex.git + cd Vortex +``` ### Configure your build folder # By default, the toolchain default install location is the /opt folder and can be overridden by setting --tooldir. # This is the example for volvo server @@ -62,16 +66,17 @@ More detailed build instructions can be found [here](docs/install_vortex.md). mkdir build cd build ../configure --xlen=32 --tooldir=/software/vortex-toolchain-2024-05-22 - source ./ci/toolchain_env.sh + source ./ci/toolchain_env.sh -all ``` ### Install prebuilt toolchain - $ ./ci/toolchain_install.sh --all + # We will use the precomipled tools in volvo toolchanin directory ### set environment variables # should always run before using the toolchain! - $ source ./ci/toolchain_env.sh + source ./ci/toolchain_env.sh ### Building Vortex - $ make -s + make -s ### Quick demo running vecadd OpenCL kernel on 2 cores +<<<<<<< HEAD $ ./ci/blackbox.sh --cores=2 --app=vecadd ### Common Developer Tips From cf3f2d4f6fdde32fa114b6c006da91ab6e88f471 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Wed, 5 Jun 2024 11:24:49 -0400 Subject: [PATCH 03/75] Update README.md --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 135dab466..0618b0c89 100644 --- a/README.md +++ b/README.md @@ -62,12 +62,9 @@ More detailed build instructions can be found [here](docs/install_vortex.md). ### Configure your build folder # By default, the toolchain default install location is the /opt folder and can be overridden by setting --tooldir. # This is the example for volvo server -``` mkdir build cd build ../configure --xlen=32 --tooldir=/software/vortex-toolchain-2024-05-22 - source ./ci/toolchain_env.sh -all -``` ### Install prebuilt toolchain # We will use the precomipled tools in volvo toolchanin directory ### set environment variables From 2b426693f525bd53a60336885e0a0326a7ffd19f Mon Sep 17 00:00:00 2001 From: Hanran Wu Date: Wed, 5 Jun 2024 16:11:51 -0400 Subject: [PATCH 04/75] expand MemoryUnit class defs and add some tlb-related functions --- hw/rtl/VX_config.vh | 16 ++++++ sim/common/mem.cpp | 41 +++++++++++++- sim/common/mem.h | 131 ++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 181 insertions(+), 7 deletions(-) diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index 7fc8d1464..5bb5720e8 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -14,6 +14,22 @@ `ifndef VX_CONFIG_VH `define VX_CONFIG_VH +`ifndef VM_ADDR_MODE +`define VM_ADDR_MODE SV32 +`endif + +`ifndef PTE_SIZE +`define PTE_SIZE 8 +`endif + +`ifndef TLB_SIZE +`define TLB_SIZE 32 +`endif + +`ifndef SUPER_PAGING +`define SUPER_PAGING false +`endif + `ifndef MIN `define MIN(x, y) (((x) < (y)) ? (x) : (y)) `endif diff --git a/sim/common/mem.cpp b/sim/common/mem.cpp index ed4bcc522..92a983410 100644 --- a/sim/common/mem.cpp +++ b/sim/common/mem.cpp @@ -17,9 +17,22 @@ #include #include #include "util.h" +#include +#include using namespace vortex; +uint64_t bits(uint64_t addr, uint8_t s_idx, uint8_t e_idx) +{ + return (addr >> s_idx) & ((1 << (e_idx - s_idx + 1)) - 1); +} + +bool bit(uint64_t addr, uint8_t idx) +{ + return (addr) & (1 << idx); +} + + RamMemDevice::RamMemDevice(const char *filename, uint32_t wordSize) : wordSize_(wordSize) { std::ifstream input(filename); @@ -158,12 +171,12 @@ uint64_t MemoryUnit::toPhyAddr(uint64_t addr, uint32_t flagMask) { return pAddr; } -void MemoryUnit::read(void* data, uint64_t addr, uint64_t size, bool sup) { +void MemoryUnit::read(void* data, uint64_t addr, uint64_t size, bool sup, ACCESS_TYPE type) { uint64_t pAddr = this->toPhyAddr(addr, sup ? 8 : 1); return decoder_.read(data, pAddr, size); } -void MemoryUnit::write(const void* data, uint64_t addr, uint64_t size, bool sup) { +void MemoryUnit::write(const void* data, uint64_t addr, uint64_t size, bool sup, ACCESS_TYPE type) { uint64_t pAddr = this->toPhyAddr(addr, sup ? 16 : 1); decoder_.write(data, pAddr, size); amo_reservation_.valid = false; @@ -179,10 +192,34 @@ bool MemoryUnit::amo_check(uint64_t addr) { uint64_t pAddr = this->toPhyAddr(addr, 1); return amo_reservation_.valid && (amo_reservation_.addr == pAddr); } + void MemoryUnit::tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags) { tlb_[virt / pageSize_] = TLBEntry(phys / pageSize_, flags); } +void MemoryUnit::tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags, uint64_t size_bits) { + // HW: evict TLB by Most Recently Used + if (tlb_.size() == TLB_SIZE - 1) { + for (auto& entry : tlb_) + { + entry.second.mru_bit = false; + } + + } else if (tlb_.size() == TLB_SIZE) { + uint64_t del; + for (auto entry : tlb_) { + if (!entry.second.mru_bit) + { + del = entry.first; + break; + } + } + tlb_.erase(tlb_.find(del)); + TLB_EVICT++; + } + tlb_[virt / pageSize_] = TLBEntry(phys / pageSize_, flags, size_bits); +} + void MemoryUnit::tlbRm(uint64_t va) { if (tlb_.find(va / pageSize_) != tlb_.end()) tlb_.erase(tlb_.find(va / pageSize_)); diff --git a/sim/common/mem.h b/sim/common/mem.h index 1f5196113..76e2f2ae5 100644 --- a/sim/common/mem.h +++ b/sim/common/mem.h @@ -18,8 +18,22 @@ #include #include #include +#include +#include namespace vortex { + +enum VA_MODE { + BARE, + SV32 +}; + +enum ACCESS_TYPE { + LOAD, + STORE, + FETCH +}; + struct BadAddress {}; struct OutOfRange {}; @@ -73,31 +87,39 @@ public: class MemoryUnit { public: +// HW: Expand PageFault struct to contain access_type info for debug purposes struct PageFault { PageFault(uint64_t a, bool nf) : faultAddr(a) , notFound(nf) + , access_type(ACCESS_TYPE::LOAD) {} - uint64_t faultAddr; - bool notFound; + uint64_t faultAddr; + bool notFound; + ACCESS_TYPE access_type; }; MemoryUnit(uint64_t pageSize = 0); void attach(MemDevice &m, uint64_t start, uint64_t end); - void read(void* data, uint64_t addr, uint64_t size, bool sup); - void write(const void* data, uint64_t addr, uint64_t size, bool sup); + void read(void* data, uint64_t addr, uint64_t size, bool sup, ACCESS_TYPE type = ACCESS_TYPE::LOAD); + void write(const void* data, uint64_t addr, uint64_t size, bool sup, ACCESS_TYPE type = ACCESS_TYPE::LOAD); void amo_reserve(uint64_t addr); bool amo_check(uint64_t addr); void tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags); + void tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags, uint64_t size_bits); + void tlbRm(uint64_t vaddr); void tlbFlush() { tlb_.clear(); } + uint32_t get_satp(); + void set_satp(uint32_t satp); + private: struct amo_reservation_t { @@ -137,11 +159,41 @@ private: TLBEntry(uint32_t pfn, uint32_t flags) : pfn(pfn) , flags(flags) - {} + , mru_bit(true) + {}; + TLBEntry(uint32_t pfn, uint32_t flags, uint64_t size_bits) + : pfn(pfn) + , flags(flags) + , mru_bit(true) + , size_bits (size_bits) + { + d = bit(7); + a = bit(6); + g = bit(5); + u = bit(4); + x = bit(3); + w = bit(2); + r = bit(1); + v = bit(0); + } + bool bit(uint8_t idx) + { + return (flags) & (1 << idx); + } + uint32_t pfn; + bool d, a, g, u, x, w, r, v; + bool mru_bit; + uint64_t size_bits; uint32_t flags; }; + std::pair tlbLookup(uint64_t vAddr, ACCESS_TYPE type, uint64_t* size_bits); + + uint64_t vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type); + + std::pair page_table_walk(uint64_t vAddr_bits, ACCESS_TYPE type, uint64_t* size_bits); + TLBEntry tlbLookup(uint64_t vAddr, uint32_t flagMask); uint64_t toPhyAddr(uint64_t vAddr, uint32_t flagMask); @@ -151,6 +203,13 @@ private: ADecoder decoder_; bool enableVM_; + uint32_t satp; + VA_MODE mode; + uint32_t ptbr; + + std::unordered_set unique_translations; + uint64_t TLB_HIT, TLB_MISS, TLB_EVICT, PTW, PERF_UNIQUE_PTW; + amo_reservation_t amo_reservation_; }; @@ -219,4 +278,66 @@ private: bool check_acl_; }; +class PTE_SV32_t +{ + + private: + uint64_t address; + uint64_t bits(uint64_t addr, uint8_t s_idx, uint8_t e_idx) + { + return (addr >> s_idx) & ((1 << (e_idx - s_idx + 1)) - 1); + } + bool bit(uint8_t idx) + { + return (address) & (1 << idx); + } + + public: + uint64_t ppn[2]; + uint32_t rsw; + uint32_t flags; + bool d, a, g, u, x, w, r, v; + PTE_SV32_t(uint64_t address) : address(address) + { + flags = bits(address,0,7); + rsw = bits(address,8,9); + ppn[0] = bits(address,10,19); + ppn[1] = bits(address,20,31); + + d = bit(7); + a = bit(6); + g = bit(5); + u = bit(4); + x = bit(3); + w = bit(2); + r = bit(1); + v = bit(0); + } +}; + +class vAddr_SV32_t +{ + + private: + uint64_t address; + uint64_t bits(uint64_t addr, uint8_t s_idx, uint8_t e_idx) + { + return (addr >> s_idx) & ((1 << (e_idx - s_idx + 1)) - 1); + } + bool bit(uint64_t addr, uint8_t idx) + { + return (addr) & (1 << idx); + } + + public: + uint64_t vpn[2]; + uint64_t pgoff; + vAddr_SV32_t(uint64_t address) : address(address) + { + vpn[0] = bits(address,12,21); + vpn[1] = bits(address,22,31); + pgoff = bits(address,0,11); + } +}; + } // namespace vortex From 6f0af066e8e982dce5358a72acfd03d99477fc01 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Fri, 7 Jun 2024 10:38:41 -0400 Subject: [PATCH 05/75] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0618b0c89..4141ec8fb 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ More detailed build instructions can be found [here](docs/install_vortex.md). ``` ### Install Vortex codebase ``` - git clone --depth=1 --recursive https://github.com/vortexgpgpu/vortex.git + git clone --depth=1 --recursive git@github.com:gthparch/vortex_vm.git cd Vortex ``` ### Configure your build folder From 2f2974ee721afa88baaba5979254f336bf70435f Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Fri, 7 Jun 2024 10:53:25 -0400 Subject: [PATCH 06/75] Ignore the changed on ramulator --- .gitmodules | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitmodules b/.gitmodules index af1d1a476..1a002355f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,4 @@ [submodule "third_party/ramulator"] path = third_party/ramulator url = https://github.com/CMU-SAFARI/ramulator.git + ignore = dirty From d8a6ac748a83b6258548b506c89d0c08d8528f52 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Fri, 7 Jun 2024 10:52:43 -0400 Subject: [PATCH 07/75] Update README.md --- README.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4141ec8fb..3994bf942 100644 --- a/README.md +++ b/README.md @@ -57,14 +57,24 @@ More detailed build instructions can be found [here](docs/install_vortex.md). ### Install Vortex codebase ``` git clone --depth=1 --recursive git@github.com:gthparch/vortex_vm.git - cd Vortex + cd vortex_vm ``` + ### Configure your build folder + # # By default, the toolchain default install location is the /opt folder and can be overridden by setting --tooldir. # This is the example for volvo server mkdir build + mkdir out + export OUT_DIR=`pwd`/out cd build - ../configure --xlen=32 --tooldir=/software/vortex-toolchain-2024-05-22 + ../configure --xlen=32 --tooldir=/software/vortex-toolchain-2024-05-22 --prefix=$OUT_DIR +### Ignore the commit for ramulator when it is compiled + # Please add ignore = dirty entry on .gitmodules + [submodule "third_party/ramulator"] + path = third_party/ramulator + url = https://github.com/CMU-SAFARI/ramulator.git + ignore = dirty ### Install prebuilt toolchain # We will use the precomipled tools in volvo toolchanin directory ### set environment variables From cfcece940ed28eed574eeeecbe2d1a6d08bbe8bb Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Tue, 11 Jun 2024 23:06:48 -0400 Subject: [PATCH 08/75] Merge Austin's code (Preliminary) --- hw/rtl/VX_config.vh | 33 ++-- runtime/simx/vortex.cpp | 372 ++++++++++++++++++++++++++++++++++++-- sim/common/mem.cpp | 250 ++++++++++++++++++++++++- sim/common/mem.h | 68 +++++-- sim/simx/cluster.cpp | 8 + sim/simx/cluster.h | 4 + sim/simx/core.cpp | 7 + sim/simx/core.h | 4 + sim/simx/emulator.cpp | 82 ++++++++- sim/simx/emulator.h | 6 + sim/simx/processor.cpp | 22 ++- sim/simx/processor.h | 10 + sim/simx/processor_impl.h | 5 + sim/simx/socket.cpp | 8 + sim/simx/socket.h | 4 + 15 files changed, 830 insertions(+), 53 deletions(-) diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index 5bb5720e8..98dcdd16e 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -14,21 +14,28 @@ `ifndef VX_CONFIG_VH `define VX_CONFIG_VH -`ifndef VM_ADDR_MODE -`define VM_ADDR_MODE SV32 +`ifndef VM_DISABLE +`define VM_ENABLE +`endif +`ifdef VM_ENABLE + `ifndef VM_ADDR_MODE + `define VM_ADDR_MODE SV32 + `endif + + `ifndef PTE_SIZE + `define PTE_SIZE 8 + `endif + + `ifndef TLB_SIZE + `define TLB_SIZE 32 + `endif + + `ifndef SUPER_PAGING + `define SUPER_PAGING 0 + `endif + `endif -`ifndef PTE_SIZE -`define PTE_SIZE 8 -`endif - -`ifndef TLB_SIZE -`define TLB_SIZE 32 -`endif - -`ifndef SUPER_PAGING -`define SUPER_PAGING false -`endif `ifndef MIN `define MIN(x, y) (((x) < (y)) ? (x) : (y)) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 89856f3a0..6e5cafc38 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -29,6 +29,38 @@ using namespace vortex; +#ifdef VM_ENABLE + +#ifndef NDEBUG +#define DBGPRINT(format, ...) do { printf("[VXDRV] " format "", ##__VA_ARGS__); } while (0) +#else +#define DBGPRINT(format, ...) ((void)0) +#endif + +#define CHECK_ERR(_expr, _cleanup) \ + do { \ + auto err = _expr; \ + if (err == 0) \ + break; \ + printf("[VXDRV] Error: '%s' returned %d!\n", #_expr, (int)err); \ + _cleanup \ + } while (false) + +/////////////////////////////////////////////////////////////////////////////// +// +#include +#include + +uint64_t bits(uint64_t addr, uint8_t s_idx, uint8_t e_idx) +{ + return (addr >> s_idx) & ((1 << (e_idx - s_idx + 1)) - 1); +} +bool bit(uint64_t addr, uint8_t idx) +{ + return (addr) & (1 << idx); +} +#endif + class vx_device { public: vx_device() @@ -42,6 +74,10 @@ public: { // attach memory module processor_.attach_ram(&ram_); +#ifdef VM_ENABLE + //Set + processor_.set_processor_satp(VM_ADDR_MODE); +#endif } ~vx_device() { @@ -90,18 +126,75 @@ public: return 0; } - int mem_alloc(uint64_t size, int flags, uint64_t* dev_addr) { - uint64_t addr; - CHECK_ERR(global_mem_.allocate(size, &addr), { - return err; - }); - CHECK_ERR(this->mem_access(addr, size, flags), { - global_mem_.release(addr); - return err; - }); - *dev_addr = addr; - return 0; - } +#ifdef VM_ENABLE + // VM SUPPORT + uint64_t map_local_mem(uint64_t size, uint64_t* dev_maddr) + { + bool is_pc = false; + std::cout << "startup addr: " << std::hex << STARTUP_ADDR << std::endl; + std::cout << "bit mode: " << std::dec << XLEN << std::endl; + if (*dev_maddr == STARTUP_ADDR || *dev_maddr == 0x7FFFF000) { + is_pc = true; + } + + if (get_mode() == VA_MODE::BARE) + return 0; + + uint64_t ppn = *dev_maddr >> 12; + uint64_t init_pAddr = *dev_maddr; + uint64_t init_vAddr = *dev_maddr + 0xf0000000; // vpn will change, but we want to return the vpn of the beginning of the virtual allocation + init_vAddr = (init_vAddr >> 12) << 12; + uint64_t vpn; + + //dev_maddr can be of size greater than a page, but we have to map and update + //page tables on a page table granularity. So divide the allocation into pages. + for (ppn = (*dev_maddr) >> 12; ppn < ((*dev_maddr) >> 12) + (size/RAM_PAGE_SIZE) + 1; ppn++) + { + //Currently a 1-1 mapping is used, this can be changed here to support different + //mapping schemes + vpn = is_pc ? ppn : ppn + 0xf0000; + //vpn = ppn; + + //If ppn to vpn mapping doesnt exist. + if (addr_mapping.find(vpn) == addr_mapping.end()) + { + //Create mapping. + update_page_table(ppn, vpn); + addr_mapping[vpn] = ppn; + } + } + + std::cout << "mapped virtual addr: " << init_vAddr << " to physical addr: " << init_pAddr << std::endl; + uint64_t size_bits; + if (is_pc) { + std::cout << "not returning virtual address because it is PC or stack" << std::endl; + std::pair ptw_access = page_table_walk(init_vAddr - 0xf0000000, &size_bits); + return 0; + } else { + std::pair ptw_access = page_table_walk(init_vAddr, &size_bits); + } + *dev_maddr = init_vAddr; // commit vpn to be returned to host + return 0; + } +#endif + + int mem_alloc(uint64_t size, int flags, uint64_t* dev_addr) { + uint64_t addr; + CHECK_ERR(global_mem_.allocate(size, &addr), { + return err; + }); + CHECK_ERR(this->mem_access(addr, size, flags), { + global_mem_.release(addr); + return err; + }); +#ifdef VM_ENABLE + // VM address translation + std::cout << "physical addr: " << std::hex << *dev_addr << std::endl; + map_local_mem(size, dev_addr); +#endif + *dev_addr = addr; + return 0; + } int mem_reserve(uint64_t dev_addr, uint64_t size, int flags) { CHECK_ERR(global_mem_.reserve(dev_addr, size), { @@ -140,6 +233,18 @@ public: if (dest_addr + asize > GLOBAL_MEM_SIZE) return -1; +#ifdef VM_ENABLE + uint64_t pAddr = dest_addr; // map_local_mem overwrites the provided dest_addr, so store away physical destination address + if (dest_addr >= STARTUP_ADDR) { + map_local_mem(asize,&dest_addr); + } else if (dest_addr >= 0x7fff0000) + { + map_local_mem(asize,&dest_addr); + } + std::cout << "uploading to 0x" << pAddr << "(VA)" << std::endl; + dest_addr = pAddr; +#endif + ram_.enable_acl(false); ram_.write((const uint8_t*)src, dest_addr, size); ram_.enable_acl(true); @@ -235,6 +340,244 @@ public: return 0; } +#ifdef VM_ENABLE + /* VM Management */ + void set_processor_satp(VA_MODE mode) + { + uint32_t satp; + if (mode == VA_MODE::BARE) + satp = 0; + else if (mode == VA_MODE::SV32) + { + satp = (alloc_page_table() >> 10) | 0x80000000; + // satp = 0xFEBFE000 ; + } + processor_.set_satp(satp); + } + + uint32_t get_ptbr() + { + // return processor_.get_satp(); + return processor_.get_satp() & 0x003fffff; + } + + VA_MODE get_mode() + { + return processor_.get_satp() & 0x80000000 ? VA_MODE::SV32 : VA_MODE::BARE; + // return VA_MODE::SV32; + } + + void update_page_table(uint64_t pAddr, uint64_t vAddr) { + std::cout << "mapping vpn: " << vAddr << " to ppn:" << pAddr << std::endl; + //Updating page table with the following mapping of (vAddr) to (pAddr). + uint64_t ppn_1, pte_addr, pte_bytes; + uint64_t vpn_1 = bits(vAddr, 10, 19); + uint64_t vpn_0 = bits(vAddr, 0, 9); + + //Read first level PTE. + pte_addr = (get_ptbr() << 12) + (vpn_1 * PTE_SIZE); + pte_bytes = read_pte(pte_addr); + std::cout << "[PTE] addr 0x" << std::hex << pte_addr << ", PTE 0x" << std::hex << pte_bytes << std::endl; + + + if ( bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) + { + //If valid bit set, proceed to next level using new ppn form PTE. + std::cout << "PTE valid, continuing the walk..." << std::endl; + ppn_1 = (pte_bytes >> 10); + } + else + { + //If valid bit not set, allocate a second level page table + // in device memory and store ppn in PTE. Set rwx = 000 in PTE + //to indicate this is a pointer to the next level of the page table. + ppn_1 = (alloc_page_table() >> 12); + pte_bytes = ( (ppn_1 << 10) | 0b0000000001) ; + write_pte(pte_addr, pte_bytes); + } + + //Read second level PTE. + pte_addr = (ppn_1 << 12) + (vpn_0 * PTE_SIZE); + pte_bytes = read_pte(pte_addr); + std::cout << "got pte: " << std::hex << pte_bytes << std::endl; + + if ( bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) + { + std::cout << "ERROR, shouldn't be here" << std::endl; + //If valid bit is set, then the page is already allocated. + //Should not reach this point, a sanity check. + } + else + { + //If valid bit not set, write ppn of pAddr in PTE. Set rwx = 111 in PTE + //to indicate this is a leaf PTE and has the stated permissions. + pte_bytes = ( (pAddr << 10) | 0b0000001111) ; + write_pte(pte_addr, pte_bytes); + + //If super paging is enabled. + if (SUPER_PAGING) + { + //Check if this second level Page Table can be promoted to a super page. Brute force + //method is used to iterate over all PTE entries of the table and check if they have + //their valid bit set. + bool superpage = true; + for(int i = 0; i < 1024; i++) + { + pte_addr = (ppn_1 << 12) + (i * PTE_SIZE); + pte_bytes = read_pte(pte_addr); + + if (!bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) + { + superpage = false; + break; + } + } + if (superpage) + { + //This can be promoted to a super page. Set root PTE to the first PTE of the + //second level. This is because the first PTE of the second level already has the + //correct PPN1, PPN0 set to zero and correct access bits. + pte_addr = (ppn_1 << 12); + pte_bytes = read_pte(pte_addr); + pte_addr = (get_ptbr() << 12) + (vpn_1 * PTE_SIZE); + write_pte(pte_addr, pte_bytes); + } + } + } + } + + std::pair page_table_walk(uint64_t vAddr_bits, uint64_t* size_bits) + { + uint64_t LEVELS = 2; + vAddr_SV32_t vAddr(vAddr_bits); + uint64_t pte_bytes; + + std::cout << "PTW on vAddr: 0x" << std::hex << vAddr_bits << std::endl; + + //Get base page table. + uint64_t a = this->processor_.get_satp() << 12; + std::cout << "PTW SATP: 0x" << a << std::endl; + int i = LEVELS - 1; + + while(true) + { + + //Read PTE. + std::cout << "reading PTE from RAM addr 0x" << std::hex << (a+vAddr.vpn[i]*PTE_SIZE) << std::endl; + ram_.read(&pte_bytes, a+vAddr.vpn[i]*PTE_SIZE, sizeof(uint64_t)); + //pte_bytes &= 0x00000000FFFFFFFF; + PTE_SV32_t pte(pte_bytes); + std::cout << "got pte: " << std::hex << pte_bytes << std::endl; + + //Check if it has invalid flag bits. + if ( (pte.v == 0) | ( (pte.r == 0) & (pte.w == 1) ) ) + { + std::cout << "Error on vAddr 0x" << std::hex << vAddr_bits << std::endl; + throw Page_Fault_Exception("Page Fault : Attempted to access invalid entry. Entry: 0x"); + } + + if ( (pte.r == 0) & (pte.w == 0) & (pte.x == 0)) + { + //Not a leaf node as rwx == 000 + i--; + if (i < 0) + { + throw Page_Fault_Exception("Page Fault : No leaf node found."); + } + else + { + //Continue on to next level. + a = (pte_bytes >> 10 ) << 12; + std::cout << "next a: " << a << std::endl; + } + } + else + { + //Leaf node found, finished walking. + a = (pte_bytes >> 10 ) << 12; + break; + } + } + + PTE_SV32_t pte(pte_bytes); + + //Check RWX permissions according to access type. + if (pte.r == 0) + { + throw Page_Fault_Exception("Page Fault : TYPE LOAD, Incorrect permissions."); + } + + uint64_t pfn; + if (i > 0) + { + //It is a super page. + if (pte.ppn[0] != 0) + { + //Misss aligned super page. + throw Page_Fault_Exception("Page Fault : Miss Aligned Super Page."); + + } + else + { + //Valid super page. + pfn = pte.ppn[1]; + *size_bits = 22; + } + } + else + { + //Regular page. + *size_bits = 12; + pfn = a >> 12; + } + return std::make_pair(pfn, pte_bytes & 0xff); + } + + uint64_t alloc_page_table() { + uint64_t addr; + global_mem_.allocate(RAM_PAGE_SIZE, &addr); + std::cout << "address of page table 0x" << std::hex << addr << std::endl; + init_page_table(addr); + return addr; + } + + + void init_page_table(uint64_t addr) { + uint64_t asize = aligned_size(RAM_PAGE_SIZE, CACHE_BLOCK_SIZE); + uint8_t *src = new uint8_t[RAM_PAGE_SIZE]; + for (uint64_t i = 0; i < RAM_PAGE_SIZE; ++i) { + src[i] = (0x00000000 >> ((i & 0x3) * 8)) & 0xff; + } + ram_.write((const uint8_t*)src, addr, asize); + } + + void read_page_table(uint64_t addr) { + uint8_t *dest = new uint8_t[RAM_PAGE_SIZE]; + download(dest, addr, RAM_PAGE_SIZE); + printf("VXDRV: download %d bytes from 0x%x\n", RAM_PAGE_SIZE, addr); + for (int i = 0; i < RAM_PAGE_SIZE; i += 4) { + printf("mem-read: 0x%x -> 0x%x\n", addr + i, *(uint64_t*)((uint8_t*)dest + i)); + } + } + + void write_pte(uint64_t addr, uint64_t value = 0xbaadf00d) { + std::cout << "writing pte " << std::hex << value << " to pAddr: " << std::hex << addr << std::endl; + uint8_t *src = new uint8_t[PTE_SIZE]; + for (uint64_t i = 0; i < PTE_SIZE; ++i) { + src[i] = (value >> ((i & 0x3) * 8)) & 0xff; + } + //std::cout << "writing PTE to RAM addr 0x" << std::hex << addr << std::endl; + ram_.write((const uint8_t*)src, addr, PTE_SIZE); + } + + uint64_t read_pte(uint64_t addr) { + uint8_t *dest = new uint8_t[PTE_SIZE]; + std::cout << "[read_pte] reading PTE from RAM addr 0x" << std::hex << addr << std::endl; + ram_.read((uint8_t*)dest, addr, PTE_SIZE); + return *(uint64_t*)((uint8_t*)dest); + } +#endif // JAEWON + private: Arch arch_; RAM ram_; @@ -243,6 +586,9 @@ private: DeviceConfig dcrs_; std::future future_; std::unordered_map> mpm_cache_; +#ifdef VM_ENABLE + std::unordered_map addr_mapping; +#endif }; -#include \ No newline at end of file +#include diff --git a/sim/common/mem.cpp b/sim/common/mem.cpp index 92a983410..b55d0de9a 100644 --- a/sim/common/mem.cpp +++ b/sim/common/mem.cpp @@ -137,16 +137,90 @@ void MemoryUnit::ADecoder::write(const void* data, uint64_t addr, uint64_t size) MemoryUnit::MemoryUnit(uint64_t pageSize) : pageSize_(pageSize) , enableVM_(pageSize != 0) - , amo_reservation_({0x0, false}) { - if (pageSize != 0) { - tlb_[0] = TLBEntry(0, 077); + , amo_reservation_({0x0, false}) +#ifdef VM_ENABLE + , TLB_HIT(0) + , TLB_MISS(0) + , TLB_EVICT(0) + , PTW(0) {}; +#else + { + if (pageSize != 0) + { + tlb_[0] = TLBEntry(0, 077); + } } -} +#endif void MemoryUnit::attach(MemDevice &m, uint64_t start, uint64_t end) { decoder_.map(start, end, m); } +#ifdef VM_ENABLE +std::pair MemoryUnit::tlbLookup(uint64_t vAddr, ACCESS_TYPE type, uint64_t* size_bits) { + + //Find entry while accounting for different sizes. + for (auto entry : tlb_) + { + if(entry.first == vAddr >> entry.second.size_bits) + { + *size_bits = entry.second.size_bits; + vAddr = vAddr >> (*size_bits); + } + } + + + auto iter = tlb_.find(vAddr); + if (iter != tlb_.end()) { + TLBEntry e = iter->second; + + //Set mru bit if it is a hit. + iter->second.mru_bit = true; + + //If at full capacity and no other unset bits. + // Clear all bits except the one we just looked up. + if (tlb_.size() == TLB_SIZE) + { + // bool no_cleared = true; + // for (auto& entry : tlb_) + // { + // no_cleared = no_cleared & entry.second.mru_bit; + // } + + // if(no_cleared) + // { + for (auto& entry : tlb_) + { + entry.second.mru_bit = false; + } + iter->second.mru_bit = true; + //} + + } + //Check access permissions. + if ( (type == ACCESS_TYPE::FETCH) & ((e.r == 0) | (e.x == 0)) ) + { + throw Page_Fault_Exception("Page Fault : Incorrect permissions."); + } + else if ( (type == ACCESS_TYPE::LOAD) & (e.r == 0) ) + { + throw Page_Fault_Exception("Page Fault : Incorrect permissions."); + } + else if ( (type == ACCESS_TYPE::STORE) & (e.w == 0) ) + { + throw Page_Fault_Exception("Page Fault : Incorrect permissions."); + } + else + { + //TLB Hit + return std::make_pair(true, iter->second.pfn); + } + } else { + //TLB Miss + return std::make_pair(false, 0); + } +} +#endif //JAEWON MemoryUnit::TLBEntry MemoryUnit::tlbLookup(uint64_t vAddr, uint32_t flagMask) { auto iter = tlb_.find(vAddr / pageSize_); if (iter != tlb_.end()) { @@ -171,16 +245,40 @@ uint64_t MemoryUnit::toPhyAddr(uint64_t addr, uint32_t flagMask) { return pAddr; } -void MemoryUnit::read(void* data, uint64_t addr, uint64_t size, bool sup, ACCESS_TYPE type) { +#ifdef VM_ENABLE +void MemoryUnit::read(void* data, uint64_t addr, uint64_t size, ACCESS_TYPE type) { + uint64_t pAddr; + if (this->mode == VA_MODE::BARE) { + pAddr = addr; + } else { + pAddr = vAddr_to_pAddr(addr, type); + } + return decoder_.read(data, pAddr, size); +} +#else +void MemoryUnit::read(void* data, uint64_t addr, uint64_t size, bool sup) { uint64_t pAddr = this->toPhyAddr(addr, sup ? 8 : 1); return decoder_.read(data, pAddr, size); } - -void MemoryUnit::write(const void* data, uint64_t addr, uint64_t size, bool sup, ACCESS_TYPE type) { +#endif +#ifdef VM_ENABLE +void MemoryUnit::write(const void* data, uint64_t addr, uint64_t size, ACCESS_TYPE type) { + uint64_t pAddr; + if ( (this->mode == VA_MODE::BARE) | (addr >= IO_BASE_ADDR) ) { + pAddr = addr; + } else { + pAddr = vAddr_to_pAddr(addr, type); + } + decoder_.write(data, pAddr, size); + amo_reservation_.valid = false; +} +#else +void MemoryUnit::write(const void* data, uint64_t addr, uint64_t size, bool sup) { uint64_t pAddr = this->toPhyAddr(addr, sup ? 16 : 1); decoder_.write(data, pAddr, size); amo_reservation_.valid = false; } +#endif void MemoryUnit::amo_reserve(uint64_t addr) { uint64_t pAddr = this->toPhyAddr(addr, 1); @@ -193,9 +291,8 @@ bool MemoryUnit::amo_check(uint64_t addr) { return amo_reservation_.valid && (amo_reservation_.addr == pAddr); } -void MemoryUnit::tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags) { - tlb_[virt / pageSize_] = TLBEntry(phys / pageSize_, flags); -} + +#ifdef VM_ENABLE void MemoryUnit::tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags, uint64_t size_bits) { // HW: evict TLB by Most Recently Used @@ -219,6 +316,12 @@ void MemoryUnit::tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags, uint64_t s } tlb_[virt / pageSize_] = TLBEntry(phys / pageSize_, flags, size_bits); } +#else + +void MemoryUnit::tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags) { + tlb_[virt / pageSize_] = TLBEntry(phys / pageSize_, flags); +} +#endif void MemoryUnit::tlbRm(uint64_t va) { if (tlb_.find(va / pageSize_) != tlb_.end()) @@ -472,3 +575,130 @@ void RAM::loadHexImage(const char* filename) { --size; } } + +#ifdef VM_ENABLE +uint64_t MemoryUnit::vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type) +{ + uint64_t pfn; + uint64_t size_bits; + + //First lookup TLB. + std::pair tlb_access = tlbLookup(vAddr, type, &size_bits); + if (tlb_access.first) + { + pfn = tlb_access.second; + TLB_HIT++; + } + else //Else walk the PT. + { + std::pair ptw_access = page_table_walk(vAddr, type, &size_bits); + tlbAdd(vAddr>>size_bits, ptw_access.first, ptw_access.second,size_bits); + pfn = ptw_access.first; TLB_MISS++; PTW++; + unique_translations.insert(vAddr>>size_bits); + PERF_UNIQUE_PTW = unique_translations.size(); + } + + //Construct final address using pfn and offset. + std::cout << "[MemoryUnit] translated vAddr: 0x" << std::hex << vAddr << " to pAddr: 0x" << std::hex << ((pfn << size_bits) + (vAddr & ((1 << size_bits) - 1))) << std::endl; + return (pfn << size_bits) + (vAddr & ((1 << size_bits) - 1)); +} + +std::pair MemoryUnit::page_table_walk(uint64_t vAddr_bits, ACCESS_TYPE type, uint64_t* size_bits) +{ + uint64_t LEVELS = 2; + vAddr_SV32_t vAddr(vAddr_bits); + uint64_t pte_bytes; + + //Get base page table. + uint64_t a = this->ptbr << 12; + int i = LEVELS - 1; + + while(true) + { + + //Read PTE. + decoder_.read(&pte_bytes, a+vAddr.vpn[i]*PTE_SIZE, sizeof(uint64_t)); + PTE_SV32_t pte(pte_bytes); + + //Check if it has invalid flag bits. + if ( (pte.v == 0) | ( (pte.r == 0) & (pte.w == 1) ) ) + { + throw Page_Fault_Exception("Page Fault : Attempted to access invalid entry."); + } + + if ( (pte.r == 0) & (pte.w == 0) & (pte.x == 0)) + { + //Not a leaf node as rwx == 000 + i--; + if (i < 0) + { + throw Page_Fault_Exception("Page Fault : No leaf node found."); + } + else + { + //Continue on to next level. + a = (pte_bytes >> 10 ) << 12; + } + } + else + { + //Leaf node found, finished walking. + a = (pte_bytes >> 10 ) << 12; + break; + } + } + + PTE_SV32_t pte(pte_bytes); + + //Check RWX permissions according to access type. + if ( (type == ACCESS_TYPE::FETCH) & ((pte.r == 0) | (pte.x == 0)) ) + { + throw Page_Fault_Exception("Page Fault : TYPE FETCH, Incorrect permissions."); + } + else if ( (type == ACCESS_TYPE::LOAD) & (pte.r == 0) ) + { + throw Page_Fault_Exception("Page Fault : TYPE LOAD, Incorrect permissions."); + } + else if ( (type == ACCESS_TYPE::STORE) & (pte.w == 0) ) + { + throw Page_Fault_Exception("Page Fault : TYPE STORE, Incorrect permissions."); + } + + uint64_t pfn; + if (i > 0) + { + //It is a super page. + if (pte.ppn[0] != 0) + { + //Misss aligned super page. + throw Page_Fault_Exception("Page Fault : Miss Aligned Super Page."); + + } + else + { + //Valid super page. + pfn = pte.ppn[1]; + *size_bits = 22; + } + } + else + { + //Regular page. + *size_bits = 12; + pfn = a >> 12; + } + return std::make_pair(pfn, pte_bytes & 0xff); +} + + +uint32_t MemoryUnit::get_satp() +{ + return satp; +} +void MemoryUnit::set_satp(uint32_t satp) +{ + this->satp = satp; + this->ptbr = satp & 0x003fffff; //22 bits + this->mode = satp & 0x80000000 ? VA_MODE::SV32 : VA_MODE::BARE; +} +#endif \ No newline at end of file diff --git a/sim/common/mem.h b/sim/common/mem.h index 76e2f2ae5..8477fb800 100644 --- a/sim/common/mem.h +++ b/sim/common/mem.h @@ -20,9 +20,18 @@ #include #include #include +#include "VX_config.h" +#ifdef VM_ENABLE +#include +#include +#include +#endif + namespace vortex { + +#ifdef VM_ENABLE enum VA_MODE { BARE, SV32 @@ -34,6 +43,14 @@ enum ACCESS_TYPE { FETCH }; +class Page_Fault_Exception : public std::runtime_error /* or logic_error */ +{ +public: + Page_Fault_Exception(const std::string& what = "") : std::runtime_error(what) {} + uint64_t addr; + ACCESS_TYPE type; +}; +#endif struct BadAddress {}; struct OutOfRange {}; @@ -92,34 +109,42 @@ public: PageFault(uint64_t a, bool nf) : faultAddr(a) , notFound(nf) - , access_type(ACCESS_TYPE::LOAD) + // , access_type(ACCESS_TYPE::LOAD) {} uint64_t faultAddr; bool notFound; - ACCESS_TYPE access_type; + // ACCESS_TYPE access_type; }; MemoryUnit(uint64_t pageSize = 0); void attach(MemDevice &m, uint64_t start, uint64_t end); - void read(void* data, uint64_t addr, uint64_t size, bool sup, ACCESS_TYPE type = ACCESS_TYPE::LOAD); - void write(const void* data, uint64_t addr, uint64_t size, bool sup, ACCESS_TYPE type = ACCESS_TYPE::LOAD); + +#ifdef VM_ENABLE + void read(void* data, uint64_t addr, uint64_t size, ACCESS_TYPE type = ACCESS_TYPE::LOAD); + void write(const void* data, uint64_t addr, uint64_t size, ACCESS_TYPE type = ACCESS_TYPE::STORE); +#else + void read(void* data, uint64_t addr, uint64_t size, bool sup); + void write(const void* data, uint64_t addr, uint64_t size, bool sup); +#endif void amo_reserve(uint64_t addr); bool amo_check(uint64_t addr); - void tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags); +#ifdef VM_ENABLE void tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags, uint64_t size_bits); + uint32_t get_satp(); + void set_satp(uint32_t satp); +#else + void tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags); +#endif void tlbRm(uint64_t vaddr); void tlbFlush() { tlb_.clear(); } - uint32_t get_satp(); - void set_satp(uint32_t satp); - private: struct amo_reservation_t { @@ -156,11 +181,7 @@ private: struct TLBEntry { TLBEntry() {} - TLBEntry(uint32_t pfn, uint32_t flags) - : pfn(pfn) - , flags(flags) - , mru_bit(true) - {}; + #ifdef VM_ENABLE TLBEntry(uint32_t pfn, uint32_t flags, uint64_t size_bits) : pfn(pfn) , flags(flags) @@ -182,17 +203,27 @@ private: } uint32_t pfn; - bool d, a, g, u, x, w, r, v; + uint32_t flags; bool mru_bit; uint64_t size_bits; + bool d, a, g, u, x, w, r, v; + #else + TLBEntry(uint32_t pfn, uint32_t flags) + : pfn(pfn) + , flags(flags) + {} + uint32_t pfn; uint32_t flags; + #endif }; +#ifdef VM_ENABLE std::pair tlbLookup(uint64_t vAddr, ACCESS_TYPE type, uint64_t* size_bits); uint64_t vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type); std::pair page_table_walk(uint64_t vAddr_bits, ACCESS_TYPE type, uint64_t* size_bits); +#endif TLBEntry tlbLookup(uint64_t vAddr, uint32_t flagMask); @@ -203,14 +234,17 @@ private: ADecoder decoder_; bool enableVM_; + amo_reservation_t amo_reservation_; +#ifdef VM_ENABLE + uint32_t satp; VA_MODE mode; uint32_t ptbr; std::unordered_set unique_translations; uint64_t TLB_HIT, TLB_MISS, TLB_EVICT, PTW, PERF_UNIQUE_PTW; +#endif - amo_reservation_t amo_reservation_; }; /////////////////////////////////////////////////////////////////////////////// @@ -278,6 +312,7 @@ private: bool check_acl_; }; +#ifdef VM_ENABLE class PTE_SV32_t { @@ -299,6 +334,7 @@ class PTE_SV32_t bool d, a, g, u, x, w, r, v; PTE_SV32_t(uint64_t address) : address(address) { + assert((address>> 32) == 0 && "Upper 32 bits are not zero!"); flags = bits(address,0,7); rsw = bits(address,8,9); ppn[0] = bits(address,10,19); @@ -334,10 +370,12 @@ class vAddr_SV32_t uint64_t pgoff; vAddr_SV32_t(uint64_t address) : address(address) { + assert((address>> 32) == 0 && "Upper 32 bits are not zero!"); vpn[0] = bits(address,12,21); vpn[1] = bits(address,22,31); pgoff = bits(address,0,11); } }; +#endif } // namespace vortex diff --git a/sim/simx/cluster.cpp b/sim/simx/cluster.cpp index 4b9048867..2ca12f411 100644 --- a/sim/simx/cluster.cpp +++ b/sim/simx/cluster.cpp @@ -106,6 +106,14 @@ void Cluster::attach_ram(RAM* ram) { } } +#ifdef VM_ENABLE +void Cluster::set_satp(uint32_t satp) { + for (auto& socket : sockets_) { + socket->set_satp(satp); + } +} +#endif + bool Cluster::running() const { for (auto& socket : sockets_) { if (socket->running()) diff --git a/sim/simx/cluster.h b/sim/simx/cluster.h index 253c54fb4..113ac04f7 100644 --- a/sim/simx/cluster.h +++ b/sim/simx/cluster.h @@ -57,6 +57,10 @@ public: void attach_ram(RAM* ram); + #ifdef VM_ENABLE + void set_satp(uint32_t satp); + #endif + bool running() const; int get_exitcode() const; diff --git a/sim/simx/core.cpp b/sim/simx/core.cpp index 0bd72524d..29d77f5df 100644 --- a/sim/simx/core.cpp +++ b/sim/simx/core.cpp @@ -396,3 +396,10 @@ bool Core::wspawn(uint32_t num_warps, Word nextPC) { void Core::attach_ram(RAM* ram) { emulator_.attach_ram(ram); } + +#ifdef VM_ENABLE +void Core::set_satp(uint32_t satp) { + emulator_.set_satp(satp); //JAEWON wit, tid??? + // emulator_.set_csr(VX_CSR_SATP,satp,0,0); //JAEWON wit, tid??? +} +#endif \ No newline at end of file diff --git a/sim/simx/core.h b/sim/simx/core.h index cc0e46c8c..6d305f7e2 100644 --- a/sim/simx/core.h +++ b/sim/simx/core.h @@ -26,6 +26,7 @@ #include "dispatcher.h" #include "func_unit.h" #include "mem_coalescer.h" +#include "VX_config.h" namespace vortex { @@ -96,6 +97,9 @@ public: void tick(); void attach_ram(RAM* ram); +#ifdef VM_ENABLE + void set_satp(uint32_t satp); +#endif bool running() const; diff --git a/sim/simx/emulator.cpp b/sim/simx/emulator.cpp index 5850bfd56..417ef83aa 100644 --- a/sim/simx/emulator.cpp +++ b/sim/simx/emulator.cpp @@ -268,10 +268,51 @@ bool Emulator::barrier(uint32_t bar_id, uint32_t count, uint32_t wid) { return false; } +#ifdef VM_ENABLE void Emulator::icache_read(void *data, uint64_t addr, uint32_t size) { - mmu_.read(data, addr, size, 0); + try + { + mmu_.read(data, addr, size, ACCESS_TYPE::LOAD); + } + catch (Page_Fault_Exception& page_fault) + { + std::cout<local_mem()->read(data, addr, size); + } else { + try + { + // mmu_.read(data, addr, size, 0); + mmu_.read(data, addr, size, ACCESS_TYPE::LOAD); + } + catch (Page_Fault_Exception& page_fault) + { + std::cout<= uint64_t(IO_COUT_ADDR) + && addr < (uint64_t(IO_COUT_ADDR) + IO_COUT_SIZE)) { + this->writeToStdOut(data, addr, size); + } else { + if (type == AddrType::Shared) { + core_->local_mem()->write(data, addr, size); + } else { + try + { + // mmu_.write(data, addr, size, 0); + mmu_.write(data, addr, size, ACCESS_TYPE::STORE); + } + catch (Page_Fault_Exception& page_fault) + { + std::cout<= uint64_t(IO_COUT_ADDR) @@ -297,6 +364,7 @@ void Emulator::dcache_write(const void* data, uint64_t addr, uint32_t size) { } DPH(2, "Mem Write: addr=0x" << std::hex << addr << ", data=0x" << ByteStream(data, size) << " (size=" << size << ", type=" << type << ")" << std::endl); } +#endif void Emulator::dcache_amo_reserve(uint64_t addr) { auto type = get_addr_type(addr); @@ -348,6 +416,10 @@ Word Emulator::get_csr(uint32_t addr, uint32_t tid, uint32_t wid) { auto core_perf = core_->perf_stats(); switch (addr) { case VX_CSR_SATP: +#ifdef VM_ENABLE + // return csrs_.at(wid).at(tid)[addr]; + return mmu_.get_satp(); +#endif case VX_CSR_PMPCFG0: case VX_CSR_PMPADDR0: case VX_CSR_MSTATUS: @@ -473,6 +545,12 @@ void Emulator::set_csr(uint32_t addr, Word value, uint32_t tid, uint32_t wid) { csr_mscratch_ = value; break; case VX_CSR_SATP: + #ifdef VM_ENABLE + // warps_.at(wid).fcsr = (warps_.at(wid).fcsr & ~0x1F) | (value & 0x1F); + // csrs_.at(wid).at(tid)[addr] = value; //what is wid and tid? + mmu_.set_satp(value); + break; + #endif case VX_CSR_MSTATUS: case VX_CSR_MEDELEG: case VX_CSR_MIDELEG: @@ -491,6 +569,8 @@ void Emulator::set_csr(uint32_t addr, Word value, uint32_t tid, uint32_t wid) { } } + + uint32_t Emulator::get_fpu_rm(uint32_t func3, uint32_t tid, uint32_t wid) { return (func3 == 0x7) ? this->get_csr(VX_CSR_FRM, tid, wid) : func3; } diff --git a/sim/simx/emulator.h b/sim/simx/emulator.h index 81dcecd83..15708f3c4 100644 --- a/sim/simx/emulator.h +++ b/sim/simx/emulator.h @@ -39,6 +39,9 @@ public: void clear(); void attach_ram(RAM* ram); +#ifdef VM_ENABLE + void set_satp(uint32_t satp) ; +#endif instr_trace_t* step(); @@ -121,6 +124,9 @@ private: MemoryUnit mmu_; Word csr_mscratch_; wspawn_t wspawn_; +#ifdef VM_ENABLE + Word ptbr_; +#endif }; } diff --git a/sim/simx/processor.cpp b/sim/simx/processor.cpp index 2627de0b3..f6deaeec8 100644 --- a/sim/simx/processor.cpp +++ b/sim/simx/processor.cpp @@ -82,6 +82,13 @@ void ProcessorImpl::attach_ram(RAM* ram) { cluster->attach_ram(ram); } } +#ifdef VM_ENABLE +void ProcessorImpl::set_satp(uint32_t satp) { + for (auto cluster : clusters_) { + cluster->set_satp(satp); + } +} +#endif void ProcessorImpl::run() { SimPlatform::instance().reset(); @@ -141,4 +148,17 @@ void Processor::run() { void Processor::dcr_write(uint32_t addr, uint32_t value) { return impl_->dcr_write(addr, value); -} \ No newline at end of file +} + +#ifdef VM_ENABLE +uint32_t Processor::get_satp() { + std::cout << "get SATP: 0x" << std::hex << this->satp << std::endl; + return this->satp; +} + +void Processor::set_satp(uint32_t satp) { + std::cout << "set SATP: 0x" << std::hex << this->satp << std::endl; + impl_->set_satp(satp); + this->satp = satp; +} +#endif diff --git a/sim/simx/processor.h b/sim/simx/processor.h index 003af6b0a..17340cf2c 100644 --- a/sim/simx/processor.h +++ b/sim/simx/processor.h @@ -14,6 +14,8 @@ #pragma once #include +#include +#include namespace vortex { @@ -31,9 +33,17 @@ public: void run(); void dcr_write(uint32_t addr, uint32_t value); +#ifdef VM_ENABLE + void set_processor_satp(VA_MODE mode); + uint32_t get_satp(); + void set_satp(uint32_t satp); +#endif private: ProcessorImpl* impl_; +#ifdef VM_ENABLE + uint32_t satp; +#endif }; } diff --git a/sim/simx/processor_impl.h b/sim/simx/processor_impl.h index dcfba84d7..e6e9a4cf1 100644 --- a/sim/simx/processor_impl.h +++ b/sim/simx/processor_impl.h @@ -39,6 +39,11 @@ public: void dcr_write(uint32_t addr, uint32_t value); +#ifdef VM_ENABLE + // 32bit satp + void set_satp(uint32_t satp); +#endif + PerfStats perf_stats() const; private: diff --git a/sim/simx/socket.cpp b/sim/simx/socket.cpp index 1ef4b1689..4fa3636e1 100644 --- a/sim/simx/socket.cpp +++ b/sim/simx/socket.cpp @@ -107,6 +107,14 @@ void Socket::attach_ram(RAM* ram) { } } +#ifdef VM_ENABLE +void Socket::set_satp(uint32_t satp) { + for (auto core : cores_) { + core->set_satp(satp); + } +} +#endif + bool Socket::running() const { for (auto& core : cores_) { if (core->running()) diff --git a/sim/simx/socket.h b/sim/simx/socket.h index ed38dce67..a09f73e8b 100644 --- a/sim/simx/socket.h +++ b/sim/simx/socket.h @@ -60,6 +60,10 @@ public: void attach_ram(RAM* ram); +#ifdef VM_ENABLE + void set_satp(uint32_t satp); +#endif + bool running() const; int get_exitcode() const; From 01c7b5e3840987b0ea1f1d1b33fd502830051e00 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Thu, 13 Jun 2024 11:30:54 -0400 Subject: [PATCH 09/75] Change the declaration of set_processor_satp function --- runtime/simx/vortex.cpp | 21 +++++++++++++-------- sim/simx/processor.h | 1 - 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 6e5cafc38..2d1168179 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -75,8 +75,8 @@ public: // attach memory module processor_.attach_ram(&ram_); #ifdef VM_ENABLE - //Set - processor_.set_processor_satp(VM_ADDR_MODE); + //Set + set_processor_satp(VM_ADDR_MODE); #endif } @@ -133,13 +133,13 @@ public: bool is_pc = false; std::cout << "startup addr: " << std::hex << STARTUP_ADDR << std::endl; std::cout << "bit mode: " << std::dec << XLEN << std::endl; + if (get_mode() == VA_MODE::BARE) + return 0; + if (*dev_maddr == STARTUP_ADDR || *dev_maddr == 0x7FFFF000) { is_pc = true; } - if (get_mode() == VA_MODE::BARE) - return 0; - uint64_t ppn = *dev_maddr >> 12; uint64_t init_pAddr = *dev_maddr; uint64_t init_vAddr = *dev_maddr + 0xf0000000; // vpn will change, but we want to return the vpn of the beginning of the virtual allocation @@ -188,9 +188,10 @@ public: return err; }); #ifdef VM_ENABLE - // VM address translation std::cout << "physical addr: " << std::hex << *dev_addr << std::endl; + // VM address translation map_local_mem(size, dev_addr); + std::cout << "virtual addr: " << std::hex << *dev_addr << std::endl; #endif *dev_addr = addr; return 0; @@ -342,7 +343,7 @@ public: #ifdef VM_ENABLE /* VM Management */ - void set_processor_satp(VA_MODE mode) + void set_processor_satp(VA_MODE mode) { uint32_t satp; if (mode == VA_MODE::BARE) @@ -546,9 +547,11 @@ public: uint64_t asize = aligned_size(RAM_PAGE_SIZE, CACHE_BLOCK_SIZE); uint8_t *src = new uint8_t[RAM_PAGE_SIZE]; for (uint64_t i = 0; i < RAM_PAGE_SIZE; ++i) { - src[i] = (0x00000000 >> ((i & 0x3) * 8)) & 0xff; + src[i] = (0x00000000 >> ((i & 0x3) << 3)) & 0xff; } + ram_.enable_acl(false); ram_.write((const uint8_t*)src, addr, asize); + ram_.enable_acl(true); } void read_page_table(uint64_t addr) { @@ -567,7 +570,9 @@ public: src[i] = (value >> ((i & 0x3) * 8)) & 0xff; } //std::cout << "writing PTE to RAM addr 0x" << std::hex << addr << std::endl; + ram_.enable_acl(false); ram_.write((const uint8_t*)src, addr, PTE_SIZE); + ram_.enable_acl(true); } uint64_t read_pte(uint64_t addr) { diff --git a/sim/simx/processor.h b/sim/simx/processor.h index 17340cf2c..e22f11569 100644 --- a/sim/simx/processor.h +++ b/sim/simx/processor.h @@ -34,7 +34,6 @@ public: void dcr_write(uint32_t addr, uint32_t value); #ifdef VM_ENABLE - void set_processor_satp(VA_MODE mode); uint32_t get_satp(); void set_satp(uint32_t satp); #endif From 62673b4b720d47681518de36631879ad85d44e61 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Fri, 14 Jun 2024 17:03:43 -0400 Subject: [PATCH 10/75] Update upload and download function in simx runtime --- hw/rtl/VX_config.vh | 52 ++++--- runtime/simx/vortex.cpp | 299 ++++++++++++++++++++++------------------ sim/simx/processor.cpp | 2 +- 3 files changed, 194 insertions(+), 159 deletions(-) diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index 98dcdd16e..e0fab021d 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -14,27 +14,6 @@ `ifndef VX_CONFIG_VH `define VX_CONFIG_VH -`ifndef VM_DISABLE -`define VM_ENABLE -`endif -`ifdef VM_ENABLE - `ifndef VM_ADDR_MODE - `define VM_ADDR_MODE SV32 - `endif - - `ifndef PTE_SIZE - `define PTE_SIZE 8 - `endif - - `ifndef TLB_SIZE - `define TLB_SIZE 32 - `endif - - `ifndef SUPER_PAGING - `define SUPER_PAGING 0 - `endif - -`endif `ifndef MIN @@ -275,6 +254,37 @@ `define DEBUG_LEVEL 3 `endif +// Virtual Memory Configuration /////////////////////////////////////////////////////// +`ifndef VM_DISABLE +`define VM_ENABLE +`endif +`ifdef VM_ENABLE + `ifndef VM_ADDR_MODE + `define VM_ADDR_MODE SV32 + `endif + + `ifndef PTE_SIZE + `ifdef XLEN_32 + `define PTE_SIZE 4 + `else + `ifdef XLEN_64 + `define PTE_SIZE 8 + `else + `define PTE_SIZE 8 + `endif + `endif + `endif + + `ifndef TLB_SIZE + `define TLB_SIZE 32 + `endif + + `ifndef SUPER_PAGING + `define SUPER_PAGING 0 + `endif + +`endif + // Pipeline Configuration ///////////////////////////////////////////////////// // Issue width diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 2d1168179..64ba1653d 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -27,6 +27,26 @@ #include #include +#ifdef VM_ENABLE +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#endif + using namespace vortex; #ifdef VM_ENABLE @@ -128,32 +148,37 @@ public: #ifdef VM_ENABLE // VM SUPPORT - uint64_t map_local_mem(uint64_t size, uint64_t* dev_maddr) + uint64_t map_local_mem(uint64_t size, uint64_t* dev_pAddr) { - bool is_pc = false; - std::cout << "startup addr: " << std::hex << STARTUP_ADDR << std::endl; + bool no_trans = false; + std::cout << __PRETTY_FUNCTION__ << std::endl; + // std::cout << "startup addr: 0x" << std::hex << STARTUP_ADDR << std::endl; + std::cout << "Input device physical addr: 0x" << std::hex << *dev_pAddr<< std::endl; std::cout << "bit mode: " << std::dec << XLEN << std::endl; - if (get_mode() == VA_MODE::BARE) - return 0; - if (*dev_maddr == STARTUP_ADDR || *dev_maddr == 0x7FFFF000) { - is_pc = true; + // if (*dev_pAddr == STARTUP_ADDR || *dev_pAddr == 0x7FFFF000) { + if (*dev_pAddr >= 0xF0000000 ) + no_trans = true; } - uint64_t ppn = *dev_maddr >> 12; - uint64_t init_pAddr = *dev_maddr; - uint64_t init_vAddr = *dev_maddr + 0xf0000000; // vpn will change, but we want to return the vpn of the beginning of the virtual allocation - init_vAddr = (init_vAddr >> 12) << 12; - uint64_t vpn; + if (get_mode() == VA_MODE::BARE || no_trans == true) + { + std::cout << "No Translation is needed." << std::endl; + return 0; + } - //dev_maddr can be of size greater than a page, but we have to map and update + uint64_t init_pAddr = *dev_pAddr; + uint64_t init_vAddr = *dev_pAddr + 0xf000000; // vpn will change, but we want to return the vpn of the beginning of the virtual allocation + uint64_t ppn = 0, vpn = 0 ; + + + //dev_pAddr can be of size greater than a page, but we have to map and update //page tables on a page table granularity. So divide the allocation into pages. - for (ppn = (*dev_maddr) >> 12; ppn < ((*dev_maddr) >> 12) + (size/RAM_PAGE_SIZE) + 1; ppn++) + for (ppn = (*dev_pAddr) >> 12; ppn < ((*dev_pAddr) >> 12) + (size/RAM_PAGE_SIZE) + 1; ppn++) { //Currently a 1-1 mapping is used, this can be changed here to support different //mapping schemes - vpn = is_pc ? ppn : ppn + 0xf0000; - //vpn = ppn; + vpn = ppn + (0xf000000 >> 12); //If ppn to vpn mapping doesnt exist. if (addr_mapping.find(vpn) == addr_mapping.end()) @@ -164,21 +189,23 @@ public: } } - std::cout << "mapped virtual addr: " << init_vAddr << " to physical addr: " << init_pAddr << std::endl; - uint64_t size_bits; - if (is_pc) { - std::cout << "not returning virtual address because it is PC or stack" << std::endl; - std::pair ptw_access = page_table_walk(init_vAddr - 0xf0000000, &size_bits); - return 0; - } else { - std::pair ptw_access = page_table_walk(init_vAddr, &size_bits); + std::cout << "Mapped virtual addr: " << init_vAddr << " to physical addr: " << init_pAddr << std::endl; + // sanity check + uint64_t pAddr = page_table_walk(init_vAddr); + if (pAddr != init_pAddr) + { + std::cout << "ERROR" << pAddr << "and" << init_pAddr << " is not the same" < GLOBAL_MEM_SIZE) - return -1; - + int upload(uint64_t dest_addr, const void* src, uint64_t size) { + std::cout << __PRETTY_FUNCTION__ << std::endl; + uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); + if (dest_addr + asize > GLOBAL_MEM_SIZE) + return -1; #ifdef VM_ENABLE - uint64_t pAddr = dest_addr; // map_local_mem overwrites the provided dest_addr, so store away physical destination address - if (dest_addr >= STARTUP_ADDR) { - map_local_mem(asize,&dest_addr); - } else if (dest_addr >= 0x7fff0000) - { - map_local_mem(asize,&dest_addr); - } - std::cout << "uploading to 0x" << pAddr << "(VA)" << std::endl; - dest_addr = pAddr; + uint64_t pAddr = page_table_walk(dest_addr); + std::cout << "== Upload data to vAddr = 0x" << std::hex < GLOBAL_MEM_SIZE) return -1; +#ifdef VM_ENABLE + uint64_t pAddr = page_table_walk(src_addr); + std::cout << "== Download data to vAddr = 0x" << std::hex <> 10) | 0x80000000; - // satp = 0xFEBFE000 ; + satp = (alloc_first_level_page_table() >> 12) | 0x80000000; } processor_.set_satp(satp); } @@ -365,22 +391,23 @@ public: VA_MODE get_mode() { return processor_.get_satp() & 0x80000000 ? VA_MODE::SV32 : VA_MODE::BARE; - // return VA_MODE::SV32; } - void update_page_table(uint64_t pAddr, uint64_t vAddr) { - std::cout << "mapping vpn: " << vAddr << " to ppn:" << pAddr << std::endl; + void update_page_table(uint64_t ppn, uint64_t vpn) { + std::cout << __PRETTY_FUNCTION__ << std::endl; + std::cout << "mapping vpn: " << std::hex << vpn << " to ppn:" << ppn << std::endl; //Updating page table with the following mapping of (vAddr) to (pAddr). + // uint32_t page_bit_shift = log2ceil(PTE_SIZE*NUM_PTE_ENTRY); + uint32_t page_bit_shift = 12; uint64_t ppn_1, pte_addr, pte_bytes; - uint64_t vpn_1 = bits(vAddr, 10, 19); - uint64_t vpn_0 = bits(vAddr, 0, 9); + uint64_t vpn_1 = bits(vpn, 10, 19); + uint64_t vpn_0 = bits(vpn, 0, 9); //Read first level PTE. pte_addr = (get_ptbr() << 12) + (vpn_1 * PTE_SIZE); pte_bytes = read_pte(pte_addr); std::cout << "[PTE] addr 0x" << std::hex << pte_addr << ", PTE 0x" << std::hex << pte_bytes << std::endl; - if ( bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) { //If valid bit set, proceed to next level using new ppn form PTE. @@ -392,13 +419,14 @@ public: //If valid bit not set, allocate a second level page table // in device memory and store ppn in PTE. Set rwx = 000 in PTE //to indicate this is a pointer to the next level of the page table. - ppn_1 = (alloc_page_table() >> 12); - pte_bytes = ( (ppn_1 << 10) | 0b0000000001) ; + std::cout << "PTE invalid, get second page table..." << std::endl; + ppn_1 = (alloc_second_level_page_table() >> 12); + pte_bytes = ((ppn_1 << 10) | 0b0000000001) ; write_pte(pte_addr, pte_bytes); } //Read second level PTE. - pte_addr = (ppn_1 << 12) + (vpn_0 * PTE_SIZE); + pte_addr = (ppn_1 << page_bit_shift) + (vpn_0 * PTE_SIZE); pte_bytes = read_pte(pte_addr); std::cout << "got pte: " << std::hex << pte_bytes << std::endl; @@ -412,10 +440,11 @@ public: { //If valid bit not set, write ppn of pAddr in PTE. Set rwx = 111 in PTE //to indicate this is a leaf PTE and has the stated permissions. - pte_bytes = ( (pAddr << 10) | 0b0000001111) ; + pte_bytes = ( (ppn << 10) | 0b0000001111) ; write_pte(pte_addr, pte_bytes); //If super paging is enabled. + /* if (SUPER_PAGING) { //Check if this second level Page Table can be promoted to a super page. Brute force @@ -444,130 +473,118 @@ public: write_pte(pte_addr, pte_bytes); } } + */ } } - std::pair page_table_walk(uint64_t vAddr_bits, uint64_t* size_bits) + uint64_t page_table_walk(uint64_t vAddr_bits) { + + std::cout << "PTW on vAddr: 0x" << std::hex << vAddr_bits << std::endl; uint64_t LEVELS = 2; vAddr_SV32_t vAddr(vAddr_bits); - uint64_t pte_bytes; + uint64_t pte_addr, pte_bytes; + uint64_t pt_ba = get_ptbr() << 12; - std::cout << "PTW on vAddr: 0x" << std::hex << vAddr_bits << std::endl; //Get base page table. - uint64_t a = this->processor_.get_satp() << 12; - std::cout << "PTW SATP: 0x" << a << std::endl; - int i = LEVELS - 1; - while(true) + for ( i = LEVELS-1 ; i >= 0 ; i--) { - - //Read PTE. - std::cout << "reading PTE from RAM addr 0x" << std::hex << (a+vAddr.vpn[i]*PTE_SIZE) << std::endl; - ram_.read(&pte_bytes, a+vAddr.vpn[i]*PTE_SIZE, sizeof(uint64_t)); - //pte_bytes &= 0x00000000FFFFFFFF; - PTE_SV32_t pte(pte_bytes); - std::cout << "got pte: " << std::hex << pte_bytes << std::endl; - - //Check if it has invalid flag bits. - if ( (pte.v == 0) | ( (pte.r == 0) & (pte.w == 1) ) ) - { - std::cout << "Error on vAddr 0x" << std::hex << vAddr_bits << std::endl; - throw Page_Fault_Exception("Page Fault : Attempted to access invalid entry. Entry: 0x"); - } - - if ( (pte.r == 0) & (pte.w == 0) & (pte.x == 0)) - { - //Not a leaf node as rwx == 000 - i--; - if (i < 0) + //Read PTE. + pte_addr = pt_ba+vAddr.vpn[i]*PTE_SIZE; + std::cout << "reading PTE from RAM addr 0x" << std::hex << (pte_addr) << std::endl; + pte_bytes = read_pte(pte_addr); + pte_bytes &= 0x00000000FFFFFFFF; // Only for 32 bit + PTE_SV32_t pte(pte_bytes); + std::cout << "got pte: " << std::hex << pte_bytes << std::endl; + + //Check if it has invalid flag bits. + if ( (pte.v == 0) | ( (pte.r == 0) & (pte.w == 1) ) ) { - throw Page_Fault_Exception("Page Fault : No leaf node found."); + std::cout << "Error on vAddr 0x" << std::hex << vAddr_bits << std::endl; + throw Page_Fault_Exception("Page Fault : Attempted to access invalid entry. Entry: 0x"); + } + + if ( (pte.r == 0) & (pte.w == 0) & (pte.x == 0)) + { + //Not a leaf node as rwx == 000 + if (i == 0) + throw Page_Fault_Exception("Page Fault : No leaf node found."); + else + { + //Continue on to next level. + pt_ba = (pte_bytes >> 10 ) << 12; + std::cout << "next pt_ba: " << pt_ba << std::endl; + } } else { - //Continue on to next level. - a = (pte_bytes >> 10 ) << 12; - std::cout << "next a: " << a << std::endl; + //Leaf node found, finished walking. + pt_ba = (pte_bytes >> 10 ) << 12; + std::cout << "Found PPN 0 = 0x" << pt_ba << std::endl; + break; } - } - else - { - //Leaf node found, finished walking. - a = (pte_bytes >> 10 ) << 12; - break; - } + } + // pte_bytes is final leaf PTE_SV32_t pte(pte_bytes); - //Check RWX permissions according to access type. if (pte.r == 0) { - throw Page_Fault_Exception("Page Fault : TYPE LOAD, Incorrect permissions."); + throw Page_Fault_Exception("Page Fault : TYPE LOAD, Incorrect permissions."); } - - uint64_t pfn; - if (i > 0) - { - //It is a super page. - if (pte.ppn[0] != 0) - { - //Misss aligned super page. - throw Page_Fault_Exception("Page Fault : Miss Aligned Super Page."); - - } - else - { - //Valid super page. - pfn = pte.ppn[1]; - *size_bits = 22; - } - } - else - { //Regular page. - *size_bits = 12; - pfn = a >> 12; - } - return std::make_pair(pfn, pte_bytes & 0xff); + + uint64_t paddr = pt_ba << 12 + vAddr.pgoff; + return paddr } - uint64_t alloc_page_table() { - uint64_t addr; - global_mem_.allocate(RAM_PAGE_SIZE, &addr); + uint64_t alloc_first_level_page_table() { + uint64_t addr=0xF0000000; + uint64_t size=1<<23; + CHECK_ERR(this->mem_reserve(addr, size, VX_MEM_READ_WRITE), { + return err; + }); + // global_mem_.allocate(RAM_PAGE_SIZE, &addr); + std::cout << "address of page table 0x" << std::hex << addr << std::endl; + init_page_table(addr,size); + return addr; + } + uint64_t alloc_second_level_page_table(uint64_t vpn_1) { + uint64_t addr = 0xF0000000 + PTE_SIZE * NUM_PTE_ENTRY*(1+vpn_1) std::cout << "address of page table 0x" << std::hex << addr << std::endl; - init_page_table(addr); return addr; } - - void init_page_table(uint64_t addr) { - uint64_t asize = aligned_size(RAM_PAGE_SIZE, CACHE_BLOCK_SIZE); + void init_page_table(uint64_t addr, uint64_t size) { + // uint64_t asize = aligned_size(RAM_PAGE_SIZE, CACHE_BLOCK_SIZE); + uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); uint8_t *src = new uint8_t[RAM_PAGE_SIZE]; for (uint64_t i = 0; i < RAM_PAGE_SIZE; ++i) { - src[i] = (0x00000000 >> ((i & 0x3) << 3)) & 0xff; + // src[i] = (value >> (i << 3)) & 0xff; + src[i] = 0; } ram_.enable_acl(false); ram_.write((const uint8_t*)src, addr, asize); ram_.enable_acl(true); } - void read_page_table(uint64_t addr) { - uint8_t *dest = new uint8_t[RAM_PAGE_SIZE]; - download(dest, addr, RAM_PAGE_SIZE); - printf("VXDRV: download %d bytes from 0x%x\n", RAM_PAGE_SIZE, addr); - for (int i = 0; i < RAM_PAGE_SIZE; i += 4) { - printf("mem-read: 0x%x -> 0x%x\n", addr + i, *(uint64_t*)((uint8_t*)dest + i)); - } - } + // void read_page_table(uint64_t addr) { + // uint8_t *dest = new uint8_t[RAM_PAGE_SIZE]; + // download(dest, addr, RAM_PAGE_SIZE); + // printf("VXDRV: download %d bytes from 0x%x\n", RAM_PAGE_SIZE, addr); + // for (int i = 0; i < RAM_PAGE_SIZE; i += 4) { + // printf("mem-read: 0x%x -> 0x%x\n", addr + i, *(uint64_t*)((uint8_t*)dest + i)); + // } + // } void write_pte(uint64_t addr, uint64_t value = 0xbaadf00d) { - std::cout << "writing pte " << std::hex << value << " to pAddr: " << std::hex << addr << std::endl; + std::cout << "writing pte 0x" << std::hex << value << " to pAddr: 0x" << std::hex << addr << std::endl; uint8_t *src = new uint8_t[PTE_SIZE]; for (uint64_t i = 0; i < PTE_SIZE; ++i) { - src[i] = (value >> ((i & 0x3) * 8)) & 0xff; + src[i] = (value >> (i << 3)) & 0xff; } //std::cout << "writing PTE to RAM addr 0x" << std::hex << addr << std::endl; ram_.enable_acl(false); @@ -577,9 +594,17 @@ public: uint64_t read_pte(uint64_t addr) { uint8_t *dest = new uint8_t[PTE_SIZE]; + uint64_t mask = 0; + if (XLEN == 32) + mask = 0xFFFFFFFF; + else if (XLEN == 64) + mask = 0xFFFFFFFFFFFFFFFF; + else + assert(0, "XLEN is not either 32 or 64") + std::cout << "[read_pte] reading PTE from RAM addr 0x" << std::hex << addr << std::endl; ram_.read((uint8_t*)dest, addr, PTE_SIZE); - return *(uint64_t*)((uint8_t*)dest); + return (*(uint64_t*)((uint8_t*)dest)) & mask; } #endif // JAEWON diff --git a/sim/simx/processor.cpp b/sim/simx/processor.cpp index f6deaeec8..c3241a207 100644 --- a/sim/simx/processor.cpp +++ b/sim/simx/processor.cpp @@ -152,7 +152,7 @@ void Processor::dcr_write(uint32_t addr, uint32_t value) { #ifdef VM_ENABLE uint32_t Processor::get_satp() { - std::cout << "get SATP: 0x" << std::hex << this->satp << std::endl; + // std::cout << "get SATP: 0x" << std::hex << this->satp << std::endl; return this->satp; } From 862997fc9456b647dc224c4ada2c65a7a701d87c Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Sun, 16 Jun 2024 19:05:38 -0400 Subject: [PATCH 11/75] Virtual Memory Support --- hw/rtl/VX_config.vh | 22 ++- runtime/simx/vortex.cpp | 299 ++++++++++++++++++++++------------------ sim/common/mem.cpp | 116 ++++++++++------ sim/common/mem.h | 25 ++-- sim/simx/emulator.cpp | 4 + sim/simx/processor.cpp | 1 - 6 files changed, 275 insertions(+), 192 deletions(-) diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index e0fab021d..3a8242379 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -172,7 +172,15 @@ `define IO_BASE_ADDR 64'h000000040 `endif -`else +`ifndef PAGE_TABLE_BASE_ADDR +`define PAGE_TABLE_BASE_ADDR 64'h1F0000000 +`endif + +`ifndef PAGE_TABLE_SIZE +`define PAGE_TABLE_SIZE 4096 +`endif + +`else # XLEN_32 `ifndef STACK_BASE_ADDR `define STACK_BASE_ADDR 32'hFFFF0000 @@ -190,6 +198,14 @@ `define IO_BASE_ADDR 32'h00000040 `endif +`ifndef PAGE_TABLE_BASE_ADDR +`define PAGE_TABLE_BASE_ADDR 32'hF0000000 +`endif + +`ifndef PAGE_TABLE_SIZE +`define PAGE_TABLE_SIZE 4096 +`endif + `endif `define IO_END_ADDR `USER_BASE_ADDR @@ -266,13 +282,17 @@ `ifndef PTE_SIZE `ifdef XLEN_32 `define PTE_SIZE 4 + `define NUM_PTE_ENTRY 1024 `else `ifdef XLEN_64 `define PTE_SIZE 8 + `define NUM_PTE_ENTRY 1024 `else `define PTE_SIZE 8 + `define NUM_PTE_ENTRY 1024 `endif `endif + `define PT_SIZE (PTE_SIZE * NUM_PTE_ENTRY) `endif `ifndef TLB_SIZE diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 64ba1653d..816ca3081 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -83,17 +83,18 @@ bool bit(uint64_t addr, uint8_t idx) class vx_device { public: - vx_device() - : arch_(NUM_THREADS, NUM_WARPS, NUM_CORES) - , ram_(0, RAM_PAGE_SIZE) - , processor_(arch_) - , global_mem_(ALLOC_BASE_ADDR, - GLOBAL_MEM_SIZE - ALLOC_BASE_ADDR, - RAM_PAGE_SIZE, - CACHE_BLOCK_SIZE) - { - // attach memory module - processor_.attach_ram(&ram_); + vx_device() + : arch_(NUM_THREADS, NUM_WARPS, NUM_CORES) +#ifdef VM_ENABLE + , ram_(0, RAM_PAGE_SIZE<<11) +#else + , ram_(0, RAM_PAGE_SIZE) +#endif + , processor_(arch_) + , global_mem_(ALLOC_BASE_ADDR, GLOBAL_MEM_SIZE - ALLOC_BASE_ADDR, RAM_PAGE_SIZE, CACHE_BLOCK_SIZE) + { + // attach memory module + processor_.attach_ram(&ram_); #ifdef VM_ENABLE //Set set_processor_satp(VM_ADDR_MODE); @@ -101,6 +102,9 @@ public: } ~vx_device() { +#ifdef VM_ENABLE + this->mem_free(PAGE_TABLE_BASE_ADDR); // Right position? +#endif if (future_.valid()) { future_.wait(); } @@ -147,66 +151,90 @@ public: } #ifdef VM_ENABLE - // VM SUPPORT - uint64_t map_local_mem(uint64_t size, uint64_t* dev_pAddr) + // virtual to phycial mapping + uint64_t map_p2v(uint64_t pAddr) { - bool no_trans = false; - std::cout << __PRETTY_FUNCTION__ << std::endl; - // std::cout << "startup addr: 0x" << std::hex << STARTUP_ADDR << std::endl; - std::cout << "Input device physical addr: 0x" << std::hex << *dev_pAddr<< std::endl; - std::cout << "bit mode: " << std::dec << XLEN << std::endl; + return pAddr + 0xf000000; + } + bool need_trans(uint64_t dev_pAddr) + { + // Check if the this is the BARE mode + bool isBAREMode = (get_mode() == VA_MODE::BARE); + // Check if the address is reserved + bool isReserved = (dev_pAddr >= PAGE_TABLE_BASE_ADDR); + // Check if the address falls within the startup address range + bool isStartAddress = (STARTUP_ADDR <= dev_pAddr) && (dev_pAddr <= (STARTUP_ADDR + 0x40000)); + + // Print the boolean results for debugging purposes + // printf("%p, %u, %u\n", (void *)dev_pAddr, isReserved, isStartAddress); + + // Return true if the address needs translation (i.e., it's not reserved and not a start address) + return (!isBAREMode && !isReserved && !isStartAddress); + } + + uint64_t phy_to_virt_map(uint64_t size, uint64_t* dev_pAddr, uint32_t flags) + { + // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); + DBGPRINT("(size = 0x%lx, dev_pAddr= 0x%lx, flags = 0x%x)\n", size, *dev_pAddr, flags); + DBGPRINT("bit mode: %d\n", XLEN); // if (*dev_pAddr == STARTUP_ADDR || *dev_pAddr == 0x7FFFF000) { - if (*dev_pAddr >= 0xF0000000 ) - no_trans = true; - } - if (get_mode() == VA_MODE::BARE || no_trans == true) + if (!need_trans(*dev_pAddr)) { - std::cout << "No Translation is needed." << std::endl; + DBGPRINT("Translation is not needed.\n"); return 0; } uint64_t init_pAddr = *dev_pAddr; - uint64_t init_vAddr = *dev_pAddr + 0xf000000; // vpn will change, but we want to return the vpn of the beginning of the virtual allocation + uint64_t init_vAddr = map_p2v(init_pAddr); uint64_t ppn = 0, vpn = 0 ; - //dev_pAddr can be of size greater than a page, but we have to map and update //page tables on a page table granularity. So divide the allocation into pages. + bool is_start = false; for (ppn = (*dev_pAddr) >> 12; ppn < ((*dev_pAddr) >> 12) + (size/RAM_PAGE_SIZE) + 1; ppn++) { + vpn = map_p2v(ppn << 12) >> 12; + if (is_start == false) { + DBGPRINT("**Search vpn in page table:0x%lx\n", vpn); + is_start = true; + } + else { + DBGPRINT("Next vpn: 0x%lx\n",vpn); + } + //Currently a 1-1 mapping is used, this can be changed here to support different //mapping schemes - vpn = ppn + (0xf000000 >> 12); //If ppn to vpn mapping doesnt exist. if (addr_mapping.find(vpn) == addr_mapping.end()) { //Create mapping. - update_page_table(ppn, vpn); + update_page_table(ppn, vpn, flags); addr_mapping[vpn] = ppn; } } + DBGPRINT("Mapped virtual addr: 0x%lx to physical addr: %lx\n", init_vAddr, init_pAddr); - std::cout << "Mapped virtual addr: " << init_vAddr << " to physical addr: " << init_pAddr << std::endl; - // sanity check + // Sanity check uint64_t pAddr = page_table_walk(init_vAddr); if (pAddr != init_pAddr) { - std::cout << "ERROR" << pAddr << "and" << init_pAddr << " is not the same" <mem_access(dev_addr, size, flags), { - global_mem_.release(dev_addr); - return err; - }); - return 0; - } + int mem_reserve(uint64_t dev_addr, uint64_t size, int flags) { + CHECK_ERR(global_mem_.reserve(dev_addr, size), { + return err; + }); + DBGPRINT("mem_reserve: addr: 0x%lx, size: 0x%lx\n",dev_addr, size); + CHECK_ERR(this->mem_access(dev_addr, size, flags), { + global_mem_.release(dev_addr); + return err; + }); +#ifdef VM_ENABLE + uint64_t paddr = dev_addr; + phy_to_virt_map(size, &paddr, flags); +#endif + return 0; + } - int mem_free(uint64_t dev_addr) { - return global_mem_.release(dev_addr); - } + int mem_free(uint64_t dev_addr) { +#ifdef VM_ENABLE + uint64_t pAddr = page_table_walk(dev_addr); + // VM address translation + return global_mem_.release(pAddr); +#else + return global_mem_.release(dev_addr); +#endif + } int mem_access(uint64_t dev_addr, uint64_t size, int flags) { uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); @@ -255,17 +294,13 @@ public: } int upload(uint64_t dest_addr, const void* src, uint64_t size) { - std::cout << __PRETTY_FUNCTION__ << std::endl; + // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); if (dest_addr + asize > GLOBAL_MEM_SIZE) return -1; #ifdef VM_ENABLE uint64_t pAddr = page_table_walk(dest_addr); - std::cout << "== Upload data to vAddr = 0x" << std::hex <> 12) | 0x80000000; + satp = (alloc_2nd_level_page_table() >> 12) | 0x80000000; + DBGPRINT("VA_MODE = SV32 MODE(satp = 0x%x)\n",satp); } processor_.set_satp(satp); } @@ -387,52 +427,62 @@ public: // return processor_.get_satp(); return processor_.get_satp() & 0x003fffff; } + uint64_t get_pte_address(uint64_t base_page, uint64_t vpn) + { + return (base_page << 12) + (vpn * PTE_SIZE); + } VA_MODE get_mode() { return processor_.get_satp() & 0x80000000 ? VA_MODE::SV32 : VA_MODE::BARE; } - void update_page_table(uint64_t ppn, uint64_t vpn) { - std::cout << __PRETTY_FUNCTION__ << std::endl; - std::cout << "mapping vpn: " << std::hex << vpn << " to ppn:" << ppn << std::endl; + void update_page_table(uint64_t ppn, uint64_t vpn, uint32_t flag) { + // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); + DBGPRINT("Mapping vpn 0x%05lx to ppn 0x%05lx(flags = %u)\n", vpn, ppn,flag); + assert((((ppn>> 20) == 0) && ((vpn >> 20) == 0)) && "Upper 12 bits are not zero!"); //Updating page table with the following mapping of (vAddr) to (pAddr). // uint32_t page_bit_shift = log2ceil(PTE_SIZE*NUM_PTE_ENTRY); - uint32_t page_bit_shift = 12; - uint64_t ppn_1, pte_addr, pte_bytes; + uint64_t ppn_1 = 0, pte_addr = 0, pte_bytes = 0; uint64_t vpn_1 = bits(vpn, 10, 19); uint64_t vpn_0 = bits(vpn, 0, 9); //Read first level PTE. - pte_addr = (get_ptbr() << 12) + (vpn_1 * PTE_SIZE); + DBGPRINT("Start second-level page table\n"); + pte_addr = get_pte_address(get_ptbr(), vpn_1); pte_bytes = read_pte(pte_addr); - std::cout << "[PTE] addr 0x" << std::hex << pte_addr << ", PTE 0x" << std::hex << pte_bytes << std::endl; + DBGPRINT("[PTE] addr 0x%lx, PTE 0x%lx\n", pte_addr, pte_bytes); + ppn_1 = (pte_bytes >> 10); if ( bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) { //If valid bit set, proceed to next level using new ppn form PTE. - std::cout << "PTE valid, continuing the walk..." << std::endl; - ppn_1 = (pte_bytes >> 10); + DBGPRINT("PTE valid (ppn 0x%lx), continuing the walk...\n",ppn_1); } else { //If valid bit not set, allocate a second level page table // in device memory and store ppn in PTE. Set rwx = 000 in PTE //to indicate this is a pointer to the next level of the page table. - std::cout << "PTE invalid, get second page table..." << std::endl; - ppn_1 = (alloc_second_level_page_table() >> 12); + DBGPRINT("PTE Invalid (ppn 0x%lx), continuing the walk...\n",ppn_1); + ppn_1 = (alloc_1st_level_page_table(vpn_1) >> 12); pte_bytes = ((ppn_1 << 10) | 0b0000000001) ; + assert((pte_addr>> 32) == 0 && "Upper 32 bits are not zero!"); write_pte(pte_addr, pte_bytes); + // if (pte_bytes != read_pte(pte_addr)) + // DBGPRINT("Read/write values are different!\n"); } + + DBGPRINT("Move to first-level page table\n"); //Read second level PTE. - pte_addr = (ppn_1 << page_bit_shift) + (vpn_0 * PTE_SIZE); + pte_addr = get_pte_address(ppn_1, vpn_0); pte_bytes = read_pte(pte_addr); - std::cout << "got pte: " << std::hex << pte_bytes << std::endl; if ( bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) { - std::cout << "ERROR, shouldn't be here" << std::endl; + DBGPRINT("ERROR, shouldn't be here\n"); + exit(1); //If valid bit is set, then the page is already allocated. //Should not reach this point, a sanity check. } @@ -442,87 +492,62 @@ public: //to indicate this is a leaf PTE and has the stated permissions. pte_bytes = ( (ppn << 10) | 0b0000001111) ; write_pte(pte_addr, pte_bytes); - - //If super paging is enabled. - /* - if (SUPER_PAGING) - { - //Check if this second level Page Table can be promoted to a super page. Brute force - //method is used to iterate over all PTE entries of the table and check if they have - //their valid bit set. - bool superpage = true; - for(int i = 0; i < 1024; i++) - { - pte_addr = (ppn_1 << 12) + (i * PTE_SIZE); - pte_bytes = read_pte(pte_addr); - - if (!bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) - { - superpage = false; - break; - } - } - if (superpage) - { - //This can be promoted to a super page. Set root PTE to the first PTE of the - //second level. This is because the first PTE of the second level already has the - //correct PPN1, PPN0 set to zero and correct access bits. - pte_addr = (ppn_1 << 12); - pte_bytes = read_pte(pte_addr); - pte_addr = (get_ptbr() << 12) + (vpn_1 * PTE_SIZE); - write_pte(pte_addr, pte_bytes); - } - } - */ + if (pte_bytes != read_pte(pte_addr)) + DBGPRINT("Read/write values are different!\n"); } } uint64_t page_table_walk(uint64_t vAddr_bits) { - - std::cout << "PTW on vAddr: 0x" << std::hex << vAddr_bits << std::endl; + // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); + DBGPRINT("PTW on vAddr: 0x%lx\n", vAddr_bits); + if (!need_trans(vAddr_bits)) + { + DBGPRINT("Translation is not needed.\n"); + return vAddr_bits; + } uint64_t LEVELS = 2; vAddr_SV32_t vAddr(vAddr_bits); uint64_t pte_addr, pte_bytes; uint64_t pt_ba = get_ptbr() << 12; - //Get base page table. - for ( i = LEVELS-1 ; i >= 0 ; i--) + for ( int i = LEVELS-1 ; i >= 0 ; i--) { //Read PTE. pte_addr = pt_ba+vAddr.vpn[i]*PTE_SIZE; - std::cout << "reading PTE from RAM addr 0x" << std::hex << (pte_addr) << std::endl; pte_bytes = read_pte(pte_addr); - pte_bytes &= 0x00000000FFFFFFFF; // Only for 32 bit PTE_SV32_t pte(pte_bytes); - std::cout << "got pte: " << std::hex << pte_bytes << std::endl; + DBGPRINT("pte_bytes = 0x%lx, pte flags = %u)\n", pte.ppn , pte.flags); //Check if it has invalid flag bits. if ( (pte.v == 0) | ( (pte.r == 0) & (pte.w == 1) ) ) { - std::cout << "Error on vAddr 0x" << std::hex << vAddr_bits << std::endl; - throw Page_Fault_Exception("Page Fault : Attempted to access invalid entry. Entry: 0x"); + std::string msg= "Page Fault : Attempted to access invalid entry. Entry: 0x"; + throw Page_Fault_Exception(msg); } if ( (pte.r == 0) & (pte.w == 0) & (pte.x == 0)) { //Not a leaf node as rwx == 000 if (i == 0) + { throw Page_Fault_Exception("Page Fault : No leaf node found."); + } else { //Continue on to next level. - pt_ba = (pte_bytes >> 10 ) << 12; - std::cout << "next pt_ba: " << pt_ba << std::endl; + pt_ba = pte.ppn << 12; + DBGPRINT("next pt_ba: %p\n", (void *)pt_ba); + } } else { //Leaf node found, finished walking. - pt_ba = (pte_bytes >> 10 ) << 12; - std::cout << "Found PPN 0 = 0x" << pt_ba << std::endl; + pt_ba = pte.ppn << 12; + DBGPRINT("Found PT_Base_Address [%d] = %lx\n", i, pt_ba); break; } @@ -535,35 +560,35 @@ public: { throw Page_Fault_Exception("Page Fault : TYPE LOAD, Incorrect permissions."); } - //Regular page. - uint64_t paddr = pt_ba << 12 + vAddr.pgoff; - return paddr + uint64_t paddr = pt_ba + vAddr.pgoff; + return paddr; } - uint64_t alloc_first_level_page_table() { - uint64_t addr=0xF0000000; - uint64_t size=1<<23; + uint64_t alloc_2nd_level_page_table() { + // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); + uint64_t addr=PAGE_TABLE_BASE_ADDR; + uint64_t size=1<<23; // 8MB !!!FIXME!!! CHECK_ERR(this->mem_reserve(addr, size, VX_MEM_READ_WRITE), { return err; }); - // global_mem_.allocate(RAM_PAGE_SIZE, &addr); - std::cout << "address of page table 0x" << std::hex << addr << std::endl; - init_page_table(addr,size); + init_page_table(addr); return addr; } - uint64_t alloc_second_level_page_table(uint64_t vpn_1) { - uint64_t addr = 0xF0000000 + PTE_SIZE * NUM_PTE_ENTRY*(1+vpn_1) - std::cout << "address of page table 0x" << std::hex << addr << std::endl; + uint64_t alloc_1st_level_page_table(uint64_t vpn_1) { + // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); + uint64_t addr = PAGE_TABLE_BASE_ADDR + PTE_SIZE * NUM_PTE_ENTRY*(1+vpn_1); + init_page_table(addr); return addr; } - void init_page_table(uint64_t addr, uint64_t size) { - // uint64_t asize = aligned_size(RAM_PAGE_SIZE, CACHE_BLOCK_SIZE); - uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); + void init_page_table(uint64_t addr) { + // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); + DBGPRINT("int_page_table (addr=0x%lx)\n", addr); + uint64_t asize = aligned_size(RAM_PAGE_SIZE, CACHE_BLOCK_SIZE); + // uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); uint8_t *src = new uint8_t[RAM_PAGE_SIZE]; for (uint64_t i = 0; i < RAM_PAGE_SIZE; ++i) { - // src[i] = (value >> (i << 3)) & 0xff; src[i] = 0; } ram_.enable_acl(false); @@ -574,14 +599,14 @@ public: // void read_page_table(uint64_t addr) { // uint8_t *dest = new uint8_t[RAM_PAGE_SIZE]; // download(dest, addr, RAM_PAGE_SIZE); - // printf("VXDRV: download %d bytes from 0x%x\n", RAM_PAGE_SIZE, addr); + // DBGPRINT("VXDRV: download %d bytes from 0x%x\n", RAM_PAGE_SIZE, addr); // for (int i = 0; i < RAM_PAGE_SIZE; i += 4) { - // printf("mem-read: 0x%x -> 0x%x\n", addr + i, *(uint64_t*)((uint8_t*)dest + i)); + // DBGPRINT("mem-read: 0x%x -> 0x%x\n", addr + i, *(uint64_t*)((uint8_t*)dest + i)); // } // } void write_pte(uint64_t addr, uint64_t value = 0xbaadf00d) { - std::cout << "writing pte 0x" << std::hex << value << " to pAddr: 0x" << std::hex << addr << std::endl; + DBGPRINT("[Write_pte] writing pte 0x%lx to pAddr: 0x%lx\n", value, addr); uint8_t *src = new uint8_t[PTE_SIZE]; for (uint64_t i = 0; i < PTE_SIZE; ++i) { src[i] = (value >> (i << 3)) & 0xff; @@ -596,15 +621,17 @@ public: uint8_t *dest = new uint8_t[PTE_SIZE]; uint64_t mask = 0; if (XLEN == 32) - mask = 0xFFFFFFFF; + mask = 0x00000000FFFFFFFF; else if (XLEN == 64) mask = 0xFFFFFFFFFFFFFFFF; else - assert(0, "XLEN is not either 32 or 64") + assert(0 && "XLEN is not either 32 or 64"); - std::cout << "[read_pte] reading PTE from RAM addr 0x" << std::hex << addr << std::endl; ram_.read((uint8_t*)dest, addr, PTE_SIZE); - return (*(uint64_t*)((uint8_t*)dest)) & mask; + uint64_t ret = (*(uint64_t*)((uint8_t*)dest)) & mask; + DBGPRINT("[read_pte] reading PTE 0x%lx from RAM addr 0x%lx\n", ret, addr); + + return ret; } #endif // JAEWON diff --git a/sim/common/mem.cpp b/sim/common/mem.cpp index b55d0de9a..98eefdaf2 100644 --- a/sim/common/mem.cpp +++ b/sim/common/mem.cpp @@ -115,6 +115,7 @@ void MemoryUnit::ADecoder::map(uint64_t start, uint64_t end, MemDevice &md) { } void MemoryUnit::ADecoder::read(void* data, uint64_t addr, uint64_t size) { + // printf("====%s (addr= 0x%lx, size= 0x%lx) ====\n", __PRETTY_FUNCTION__,addr,size); mem_accessor_t ma; if (!this->lookup(addr, size, &ma)) { std::cout << "lookup of 0x" << std::hex << addr << " failed.\n"; @@ -124,6 +125,7 @@ void MemoryUnit::ADecoder::read(void* data, uint64_t addr, uint64_t size) { } void MemoryUnit::ADecoder::write(const void* data, uint64_t addr, uint64_t size) { + // printf("====%s====\n", __PRETTY_FUNCTION__); mem_accessor_t ma; if (!this->lookup(addr, size, &ma)) { std::cout << "lookup of 0x" << std::hex << addr << " failed.\n"; @@ -158,6 +160,7 @@ void MemoryUnit::attach(MemDevice &m, uint64_t start, uint64_t end) { #ifdef VM_ENABLE std::pair MemoryUnit::tlbLookup(uint64_t vAddr, ACCESS_TYPE type, uint64_t* size_bits) { + // printf("====%s====\n", __PRETTY_FUNCTION__); //Find entry while accounting for different sizes. for (auto entry : tlb_) @@ -220,7 +223,7 @@ std::pair MemoryUnit::tlbLookup(uint64_t vAddr, ACCESS_TYPE type return std::make_pair(false, 0); } } -#endif //JAEWON +#else MemoryUnit::TLBEntry MemoryUnit::tlbLookup(uint64_t vAddr, uint32_t flagMask) { auto iter = tlb_.find(vAddr / pageSize_); if (iter != tlb_.end()) { @@ -244,52 +247,62 @@ uint64_t MemoryUnit::toPhyAddr(uint64_t addr, uint32_t flagMask) { } return pAddr; } +#endif #ifdef VM_ENABLE -void MemoryUnit::read(void* data, uint64_t addr, uint64_t size, ACCESS_TYPE type) { +void MemoryUnit::read(void* data, uint64_t addr, uint32_t size, ACCESS_TYPE type) { + // printf("====%s====\n", __PRETTY_FUNCTION__); uint64_t pAddr; - if (this->mode == VA_MODE::BARE) { - pAddr = addr; - } else { - pAddr = vAddr_to_pAddr(addr, type); - } + pAddr = vAddr_to_pAddr(addr, type); return decoder_.read(data, pAddr, size); } #else -void MemoryUnit::read(void* data, uint64_t addr, uint64_t size, bool sup) { +void MemoryUnit::read(void* data, uint64_t addr, uint32_t size, bool sup) { uint64_t pAddr = this->toPhyAddr(addr, sup ? 8 : 1); return decoder_.read(data, pAddr, size); } #endif #ifdef VM_ENABLE -void MemoryUnit::write(const void* data, uint64_t addr, uint64_t size, ACCESS_TYPE type) { +void MemoryUnit::write(const void* data, uint64_t addr, uint32_t size, ACCESS_TYPE type) { + // printf("====%s====\n", __PRETTY_FUNCTION__); uint64_t pAddr; - if ( (this->mode == VA_MODE::BARE) | (addr >= IO_BASE_ADDR) ) { - pAddr = addr; - } else { - pAddr = vAddr_to_pAddr(addr, type); - } + pAddr = vAddr_to_pAddr(addr, type); decoder_.write(data, pAddr, size); amo_reservation_.valid = false; } #else -void MemoryUnit::write(const void* data, uint64_t addr, uint64_t size, bool sup) { +void MemoryUnit::write(const void* data, uint64_t addr, uint32_t size, bool sup) { uint64_t pAddr = this->toPhyAddr(addr, sup ? 16 : 1); decoder_.write(data, pAddr, size); amo_reservation_.valid = false; } #endif +#ifdef VM_ENABLE +void MemoryUnit::amo_reserve(uint64_t addr) { + uint64_t pAddr = this->vAddr_to_pAddr(addr,ACCESS_TYPE::LOAD); + amo_reservation_.addr = pAddr; + amo_reservation_.valid = true; +} +#else void MemoryUnit::amo_reserve(uint64_t addr) { uint64_t pAddr = this->toPhyAddr(addr, 1); amo_reservation_.addr = pAddr; amo_reservation_.valid = true; } +#endif +#ifdef VM_ENABLE +bool MemoryUnit::amo_check(uint64_t addr) { + uint64_t pAddr = this->vAddr_to_pAddr(addr, ACCESS_TYPE::LOAD); + return amo_reservation_.valid && (amo_reservation_.addr == pAddr); +} +#else bool MemoryUnit::amo_check(uint64_t addr) { uint64_t pAddr = this->toPhyAddr(addr, 1); return amo_reservation_.valid && (amo_reservation_.addr == pAddr); } +#endif #ifdef VM_ENABLE @@ -465,6 +478,7 @@ uint8_t *RAM::get(uint64_t address) const { } void RAM::read(void* data, uint64_t addr, uint64_t size) { + // printf("====%s (addr= 0x%lx, size= 0x%lx) ====\n", __PRETTY_FUNCTION__,addr,size); if (check_acl_ && acl_mngr_.check(addr, size, 0x1) == false) { throw BadAddress(); } @@ -577,15 +591,41 @@ void RAM::loadHexImage(const char* filename) { } #ifdef VM_ENABLE + +bool MemoryUnit::need_trans(uint64_t dev_pAddr) +{ + // Check if the this is the BARE mode + bool isBAREMode = (this->mode == VA_MODE::BARE); + // Check if the address is reserved + bool isReserved = (dev_pAddr >= PAGE_TABLE_BASE_ADDR); + // Check if the address falls within the startup address range + bool isStartAddress = (STARTUP_ADDR <= dev_pAddr) && (dev_pAddr < (STARTUP_ADDR + 0x40000)); + + // Print the boolean results for debugging purposes + // printf("0x%lx, %u, %u, %u \n", dev_pAddr,isBAREMode, isReserved, isStartAddress); + + // Return true if the address needs translation (i.e., it's not reserved and not a start address) + return (!isBAREMode && !isReserved && !isStartAddress); +} + uint64_t MemoryUnit::vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type) { uint64_t pfn; uint64_t size_bits; + // printf("====%s====\n", __PRETTY_FUNCTION__); + // printf("vaddr = 0x%lx, type = 0x%u\n",vAddr,type); + if (!need_trans(vAddr)) + { + // printf("Translation is not needed.\n"); + return vAddr; + } //First lookup TLB. std::pair tlb_access = tlbLookup(vAddr, type, &size_bits); if (tlb_access.first) { + + // printf("Found pfn %lx in TLB\n",tlb_access.second); pfn = tlb_access.second; TLB_HIT++; } @@ -596,33 +636,37 @@ uint64_t MemoryUnit::vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type) pfn = ptw_access.first; TLB_MISS++; PTW++; unique_translations.insert(vAddr>>size_bits); PERF_UNIQUE_PTW = unique_translations.size(); + } //Construct final address using pfn and offset. - std::cout << "[MemoryUnit] translated vAddr: 0x" << std::hex << vAddr << " to pAddr: 0x" << std::hex << ((pfn << size_bits) + (vAddr & ((1 << size_bits) - 1))) << std::endl; + // std::cout << "[MemoryUnit] translated vAddr: 0x" << std::hex << vAddr << " to pAddr: 0x" << std::hex << ((pfn << size_bits) + (vAddr & ((1 << size_bits) - 1))) << std::endl; return (pfn << size_bits) + (vAddr & ((1 << size_bits) - 1)); } std::pair MemoryUnit::page_table_walk(uint64_t vAddr_bits, ACCESS_TYPE type, uint64_t* size_bits) { + // printf("====%s====\n", __PRETTY_FUNCTION__); + // printf("vaddr = 0x%lx, type = %u, size_bits %lu\n", vAddr_bits, type, *size_bits); uint64_t LEVELS = 2; vAddr_SV32_t vAddr(vAddr_bits); - uint64_t pte_bytes; + uint64_t pte_bytes = 0; //Get base page table. - uint64_t a = this->ptbr << 12; + uint64_t pt_ba = this->ptbr << 12; int i = LEVELS - 1; while(true) { //Read PTE. - decoder_.read(&pte_bytes, a+vAddr.vpn[i]*PTE_SIZE, sizeof(uint64_t)); + decoder_.read(&pte_bytes, pt_ba+vAddr.vpn[i]*PTE_SIZE, PTE_SIZE); PTE_SV32_t pte(pte_bytes); //Check if it has invalid flag bits. if ( (pte.v == 0) | ( (pte.r == 0) & (pte.w == 1) ) ) { + printf("Error: PTE FLAGS=0x%x\n",pte.flags); throw Page_Fault_Exception("Page Fault : Attempted to access invalid entry."); } @@ -632,18 +676,19 @@ std::pair MemoryUnit::page_table_walk(uint64_t vAddr_bits, AC i--; if (i < 0) { + printf("Error: PTE FLAGS=0x%x\n",pte.flags); throw Page_Fault_Exception("Page Fault : No leaf node found."); } else { //Continue on to next level. - a = (pte_bytes >> 10 ) << 12; + pt_ba = (pte_bytes >> 10 ) << 12; } } else { //Leaf node found, finished walking. - a = (pte_bytes >> 10 ) << 12; + pt_ba = (pte_bytes >> 10 ) << 12; break; } } @@ -653,40 +698,21 @@ std::pair MemoryUnit::page_table_walk(uint64_t vAddr_bits, AC //Check RWX permissions according to access type. if ( (type == ACCESS_TYPE::FETCH) & ((pte.r == 0) | (pte.x == 0)) ) { + printf("Error: PTE FLAGS=0x%x\n",pte.flags); throw Page_Fault_Exception("Page Fault : TYPE FETCH, Incorrect permissions."); } else if ( (type == ACCESS_TYPE::LOAD) & (pte.r == 0) ) { + printf("Error: PTE FLAGS=0x%x\n",pte.flags); throw Page_Fault_Exception("Page Fault : TYPE LOAD, Incorrect permissions."); } else if ( (type == ACCESS_TYPE::STORE) & (pte.w == 0) ) { + printf("Error: PTE FLAGS=0x%x\n",pte.flags); throw Page_Fault_Exception("Page Fault : TYPE STORE, Incorrect permissions."); } - - uint64_t pfn; - if (i > 0) - { - //It is a super page. - if (pte.ppn[0] != 0) - { - //Misss aligned super page. - throw Page_Fault_Exception("Page Fault : Miss Aligned Super Page."); - - } - else - { - //Valid super page. - pfn = pte.ppn[1]; - *size_bits = 22; - } - } - else - { - //Regular page. - *size_bits = 12; - pfn = a >> 12; - } + *size_bits = 12; + uint64_t pfn = pt_ba >> *size_bits; return std::make_pair(pfn, pte_bytes & 0xff); } diff --git a/sim/common/mem.h b/sim/common/mem.h index 8477fb800..a655a6d3c 100644 --- a/sim/common/mem.h +++ b/sim/common/mem.h @@ -116,17 +116,21 @@ public: // ACCESS_TYPE access_type; }; +#ifdef VM_ENABLE + MemoryUnit(uint64_t pageSize = PAGE_TABLE_SIZE); +#else MemoryUnit(uint64_t pageSize = 0); +#endif void attach(MemDevice &m, uint64_t start, uint64_t end); #ifdef VM_ENABLE - void read(void* data, uint64_t addr, uint64_t size, ACCESS_TYPE type = ACCESS_TYPE::LOAD); - void write(const void* data, uint64_t addr, uint64_t size, ACCESS_TYPE type = ACCESS_TYPE::STORE); + void read(void* data, uint64_t addr, uint32_t size, ACCESS_TYPE type = ACCESS_TYPE::LOAD); + void write(const void* data, uint64_t addr, uint32_t size, ACCESS_TYPE type = ACCESS_TYPE::STORE); #else - void read(void* data, uint64_t addr, uint64_t size, bool sup); - void write(const void* data, uint64_t addr, uint64_t size, bool sup); + void read(void* data, uint64_t addr, uint32_t size, bool sup); + void write(const void* data, uint64_t addr, uint32_t size, bool sup); #endif void amo_reserve(uint64_t addr); @@ -220,14 +224,16 @@ private: #ifdef VM_ENABLE std::pair tlbLookup(uint64_t vAddr, ACCESS_TYPE type, uint64_t* size_bits); + bool need_trans(uint64_t dev_pAddr); uint64_t vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type); std::pair page_table_walk(uint64_t vAddr_bits, ACCESS_TYPE type, uint64_t* size_bits); +#else + uint64_t toPhyAddr(uint64_t vAddr, uint32_t flagMask); + TLBEntry tlbLookup(uint64_t vAddr, uint32_t flagMask); #endif - TLBEntry tlbLookup(uint64_t vAddr, uint32_t flagMask); - uint64_t toPhyAddr(uint64_t vAddr, uint32_t flagMask); std::unordered_map tlb_; uint64_t pageSize_; @@ -328,7 +334,7 @@ class PTE_SV32_t } public: - uint64_t ppn[2]; + uint64_t ppn; uint32_t rsw; uint32_t flags; bool d, a, g, u, x, w, r, v; @@ -337,8 +343,7 @@ class PTE_SV32_t assert((address>> 32) == 0 && "Upper 32 bits are not zero!"); flags = bits(address,0,7); rsw = bits(address,8,9); - ppn[0] = bits(address,10,19); - ppn[1] = bits(address,20,31); + ppn = bits(address,10,31); d = bit(7); a = bit(6); @@ -348,6 +353,7 @@ class PTE_SV32_t w = bit(2); r = bit(1); v = bit(0); + // printf("ppn = 0x%lx, flags= 0x%x, rsw= 0x%x\n",ppn,flags,rsw); } }; @@ -374,6 +380,7 @@ class vAddr_SV32_t vpn[0] = bits(address,12,21); vpn[1] = bits(address,22,31); pgoff = bits(address,0,11); + // printf("vpn[0] = 0x%lx, vpn[1] = 0x%lx, pgoff = 0x%lx\n",vpn[0],vpn[1],pgoff); } }; #endif diff --git a/sim/simx/emulator.cpp b/sim/simx/emulator.cpp index 417ef83aa..63473cfd8 100644 --- a/sim/simx/emulator.cpp +++ b/sim/simx/emulator.cpp @@ -270,6 +270,8 @@ bool Emulator::barrier(uint32_t bar_id, uint32_t count, uint32_t wid) { #ifdef VM_ENABLE void Emulator::icache_read(void *data, uint64_t addr, uint32_t size) { + DPH(3, "*** icache_read 0x" << std::hex << addr << ", size = 0x " << size); + try { mmu_.read(data, addr, size, ACCESS_TYPE::LOAD); @@ -288,6 +290,7 @@ void Emulator::icache_read(void *data, uint64_t addr, uint32_t size) { #ifdef VM_ENABLE void Emulator::set_satp(uint32_t satp) { + DPH(3, "set satp 0x" << std::hex << satp << " in emulator module\n"); set_csr(VX_CSR_SATP,satp,0,0); } #endif @@ -327,6 +330,7 @@ void Emulator::dcache_read(void *data, uint64_t addr, uint32_t size) { #ifdef VM_ENABLE void Emulator::dcache_write(const void* data, uint64_t addr, uint32_t size) { + DP(1, "*** dcache_write 0x" << std::hex << addr << ", size = 0x " << size); auto type = get_addr_type(addr); if (addr >= uint64_t(IO_COUT_ADDR) && addr < (uint64_t(IO_COUT_ADDR) + IO_COUT_SIZE)) { diff --git a/sim/simx/processor.cpp b/sim/simx/processor.cpp index c3241a207..3ae99fa4e 100644 --- a/sim/simx/processor.cpp +++ b/sim/simx/processor.cpp @@ -157,7 +157,6 @@ uint32_t Processor::get_satp() { } void Processor::set_satp(uint32_t satp) { - std::cout << "set SATP: 0x" << std::hex << this->satp << std::endl; impl_->set_satp(satp); this->satp = satp; } From 2271d2b286f13b18519e162a8ca12ee0b4f3cc46 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Wed, 19 Jun 2024 02:04:24 -0400 Subject: [PATCH 12/75] remove # --- hw/rtl/VX_config.vh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index 3a8242379..2d01f2bf2 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -180,7 +180,7 @@ `define PAGE_TABLE_SIZE 4096 `endif -`else # XLEN_32 +`else // XLEN_32 `ifndef STACK_BASE_ADDR `define STACK_BASE_ADDR 32'hFFFF0000 From 02091f3d4436cb17c09cc5d9a8ab306298ddd997 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Sat, 22 Jun 2024 23:55:01 -0400 Subject: [PATCH 13/75] Merge Vortex 2.2 --- hw/rtl/VX_config.vh | 77 ++-- runtime/simx/vortex.cpp | 749 +++++++++++++++++++------------------- sim/common/mem.cpp | 95 ++--- sim/common/mem.h | 19 +- sim/simx/cluster.cpp | 2 +- sim/simx/cluster.h | 2 +- sim/simx/core.cpp | 2 +- sim/simx/core.h | 2 +- sim/simx/emulator.cpp | 5 +- sim/simx/emulator.h | 2 +- sim/simx/processor.cpp | 6 +- sim/simx/processor.h | 6 +- sim/simx/processor_impl.h | 3 +- sim/simx/socket.cpp | 2 +- sim/simx/socket.h | 2 +- 15 files changed, 512 insertions(+), 462 deletions(-) diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index 2d01f2bf2..4ff4dc9eb 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -33,6 +33,9 @@ `endif /////////////////////////////////////////////////////////////////////////////// +`ifndef VM_DISABLE +`define VM_ENABLE +`endif `ifndef EXT_M_DISABLE `define EXT_M_ENABLE @@ -172,12 +175,11 @@ `define IO_BASE_ADDR 64'h000000040 `endif +`ifdef VM_ENABLE `ifndef PAGE_TABLE_BASE_ADDR `define PAGE_TABLE_BASE_ADDR 64'h1F0000000 `endif -`ifndef PAGE_TABLE_SIZE -`define PAGE_TABLE_SIZE 4096 `endif `else // XLEN_32 @@ -198,12 +200,11 @@ `define IO_BASE_ADDR 32'h00000040 `endif +`ifdef VM_ENABLE `ifndef PAGE_TABLE_BASE_ADDR `define PAGE_TABLE_BASE_ADDR 32'hF0000000 `endif -`ifndef PAGE_TABLE_SIZE -`define PAGE_TABLE_SIZE 4096 `endif `endif @@ -271,40 +272,58 @@ `endif // Virtual Memory Configuration /////////////////////////////////////////////////////// -`ifndef VM_DISABLE -`define VM_ENABLE -`endif `ifdef VM_ENABLE - `ifndef VM_ADDR_MODE - `define VM_ADDR_MODE SV32 - `endif - - `ifndef PTE_SIZE - `ifdef XLEN_32 - `define PTE_SIZE 4 - `define NUM_PTE_ENTRY 1024 - `else - `ifdef XLEN_64 - `define PTE_SIZE 8 - `define NUM_PTE_ENTRY 1024 - `else - `define PTE_SIZE 8 - `define NUM_PTE_ENTRY 1024 - `endif + `ifdef XLEN_32 + `ifndef VM_ADDR_MODE + `define VM_ADDR_MODE SV32 //or BARE + `endif + `ifndef PTE_SIZE + `define PTE_SIZE (4) + `endif + `ifndef SATP_MODE_IDX + `define SATP_MODE_IDX (31) + `endif + `ifndef SATP_PPN_WIDTH + `define SATP_PPN_WIDTH (22) + `endif + `else + `ifndef VM_ADDR_MODE + `define VM_ADDR_MODE SV64 //or BARE + `endif + `ifndef PTE_SIZE + `define PTE_SIZE (8) + `endif + `ifndef SATP_MODE_IDX + `define SATP_MODE_IDX (63) + `endif + `ifndef SATP_PPN_WIDTH + `define SATP_PPN_WIDTH (44) `endif - `define PT_SIZE (PTE_SIZE * NUM_PTE_ENTRY) `endif + `ifndef NUM_PTE_ENTRY + `define NUM_PTE_ENTRY (1024) + `endif + + `ifndef PT_SIZE + `define PT_SIZE (PTE_SIZE * NUM_PTE_ENTRY) + `endif + + `ifndef PT_TOTAL_SIZE + `define PT_TOTAL_SIZE (PT_SIZE*(1+NUM_PTE_ENTRY)) + `endif + + `ifndef TLB_SIZE - `define TLB_SIZE 32 - `endif - - `ifndef SUPER_PAGING - `define SUPER_PAGING 0 + `define TLB_SIZE (32) `endif `endif +`ifndef MEM_PAGE_SIZE +`define MEM_PAGE_SIZE (4096) +`endif + // Pipeline Configuration ///////////////////////////////////////////////////// // Issue width diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 816ca3081..1a5da088a 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -28,11 +28,11 @@ #include #ifdef VM_ENABLE -#include -#include +#include +// #include +//#include #include -#include #include #include @@ -50,7 +50,6 @@ using namespace vortex; #ifdef VM_ENABLE - #ifndef NDEBUG #define DBGPRINT(format, ...) do { printf("[VXDRV] " format "", ##__VA_ARGS__); } while (0) #else @@ -85,13 +84,9 @@ class vx_device { public: vx_device() : arch_(NUM_THREADS, NUM_WARPS, NUM_CORES) -#ifdef VM_ENABLE - , ram_(0, RAM_PAGE_SIZE<<11) -#else - , ram_(0, RAM_PAGE_SIZE) -#endif + , ram_(0, MEM_PAGE_SIZE) , processor_(arch_) - , global_mem_(ALLOC_BASE_ADDR, GLOBAL_MEM_SIZE - ALLOC_BASE_ADDR, RAM_PAGE_SIZE, CACHE_BLOCK_SIZE) + , global_mem_(ALLOC_BASE_ADDR, GLOBAL_MEM_SIZE - ALLOC_BASE_ADDR, MEM_PAGE_SIZE, CACHE_BLOCK_SIZE) { // attach memory module processor_.attach_ram(&ram_); @@ -150,133 +145,141 @@ public: return 0; } -#ifdef VM_ENABLE - // virtual to phycial mapping - uint64_t map_p2v(uint64_t pAddr) - { - return pAddr + 0xf000000; - } - bool need_trans(uint64_t dev_pAddr) - { - // Check if the this is the BARE mode - bool isBAREMode = (get_mode() == VA_MODE::BARE); - // Check if the address is reserved - bool isReserved = (dev_pAddr >= PAGE_TABLE_BASE_ADDR); - // Check if the address falls within the startup address range - bool isStartAddress = (STARTUP_ADDR <= dev_pAddr) && (dev_pAddr <= (STARTUP_ADDR + 0x40000)); - - // Print the boolean results for debugging purposes - // printf("%p, %u, %u\n", (void *)dev_pAddr, isReserved, isStartAddress); - - // Return true if the address needs translation (i.e., it's not reserved and not a start address) - return (!isBAREMode && !isReserved && !isStartAddress); - } - - uint64_t phy_to_virt_map(uint64_t size, uint64_t* dev_pAddr, uint32_t flags) - { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); - DBGPRINT("(size = 0x%lx, dev_pAddr= 0x%lx, flags = 0x%x)\n", size, *dev_pAddr, flags); - DBGPRINT("bit mode: %d\n", XLEN); - - // if (*dev_pAddr == STARTUP_ADDR || *dev_pAddr == 0x7FFFF000) { - - if (!need_trans(*dev_pAddr)) - { - DBGPRINT("Translation is not needed.\n"); - return 0; - } - - uint64_t init_pAddr = *dev_pAddr; - uint64_t init_vAddr = map_p2v(init_pAddr); - uint64_t ppn = 0, vpn = 0 ; - - //dev_pAddr can be of size greater than a page, but we have to map and update - //page tables on a page table granularity. So divide the allocation into pages. - bool is_start = false; - for (ppn = (*dev_pAddr) >> 12; ppn < ((*dev_pAddr) >> 12) + (size/RAM_PAGE_SIZE) + 1; ppn++) - { - vpn = map_p2v(ppn << 12) >> 12; - if (is_start == false) { - DBGPRINT("**Search vpn in page table:0x%lx\n", vpn); - is_start = true; - } - else { - DBGPRINT("Next vpn: 0x%lx\n",vpn); - } - - //Currently a 1-1 mapping is used, this can be changed here to support different - //mapping schemes - - //If ppn to vpn mapping doesnt exist. - if (addr_mapping.find(vpn) == addr_mapping.end()) - { - //Create mapping. - update_page_table(ppn, vpn, flags); - addr_mapping[vpn] = ppn; - } - } - DBGPRINT("Mapped virtual addr: 0x%lx to physical addr: %lx\n", init_vAddr, init_pAddr); - - // Sanity check - uint64_t pAddr = page_table_walk(init_vAddr); - if (pAddr != init_pAddr) - { - assert(pAddr == init_pAddr && "ERROR: translated virtual Addresses are not the same with physical Address"); - } - - *dev_pAddr = init_vAddr; // commit vpn to be returned to host - DBGPRINT("Translated device virtual addr: 0x%lx\n", *dev_pAddr); - - return 0; - } -#endif - - int mem_alloc(uint64_t size, int flags, uint64_t* dev_addr) { - - uint64_t addr; - DBGPRINT("mem_alloc size: 0x%lx\n",size); - CHECK_ERR(global_mem_.allocate(size, &addr), { - return err; - }); - CHECK_ERR(this->mem_access(addr, size, flags), { - global_mem_.release(addr); - return err; - }); - *dev_addr = addr; #ifdef VM_ENABLE - // VM address translation - phy_to_virt_map(size, dev_addr,flags); + // virtual to phycial mapping + uint64_t map_p2v(uint64_t pAddr) + { + return pAddr + 0xf000000; + } + bool need_trans(uint64_t dev_pAddr) + { + // Check if the this is the BARE mode + bool isBAREMode = (get_mode() == VA_MODE::BARE); + // Check if the address is reserved for system usage + bool isReserved = (dev_pAddr >= PAGE_TABLE_BASE_ADDR); + // Check if the address is reserved for IO usage + bool isIO = (dev_pAddr < USER_BASE_ADDR); + // Check if the address falls within the startup address range + bool isStartAddress = (STARTUP_ADDR <= dev_pAddr) && (dev_pAddr <= (STARTUP_ADDR + 0x40000)); + + // Print the boolean results for debugging purposes + // printf("%p, %u, %u\n", (void *)dev_pAddr, isReserved, isStartAddress); + + // Return true if the address needs translation (i.e., it's not reserved and not a start address) + return (!isBAREMode && !isReserved && !isIO && !isStartAddress); + } + + uint64_t phy_to_virt_map(uint64_t size, uint64_t *dev_pAddr, uint32_t flags) + { + // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); + DBGPRINT(" [RT:PTV_MAP] size = 0x%lx, dev_pAddr= 0x%lx, flags = 0x%x\n", size, *dev_pAddr, flags); + DBGPRINT(" [RT:PTV_MAP] bit mode: %d\n", XLEN); + + // if (*dev_pAddr == STARTUP_ADDR || *dev_pAddr == 0x7FFFF000) { + + if (!need_trans(*dev_pAddr)) + { + DBGPRINT(" [RT:PTV_MAP] Translation is not needed.\n"); + return 0; + } + + uint64_t init_pAddr = *dev_pAddr; + uint64_t init_vAddr = map_p2v(init_pAddr); + uint64_t ppn = 0, vpn = 0; + + // dev_pAddr can be of size greater than a page, but we have to map and update + // page tables on a page table granularity. So divide the allocation into pages. + bool is_start = false; + for (ppn = (*dev_pAddr) >> 12; ppn < ((*dev_pAddr) >> 12) + (size / MEM_PAGE_SIZE) + 1; ppn++) + { + vpn = map_p2v(ppn << 12) >> 12; + if (is_start == false) + { + DBGPRINT(" [RT:PTV_MAP] Search vpn in page table:0x%lx\n", vpn); + is_start = true; + } + else + { + DBGPRINT(" [RT:PTV_MAP] Next vpn: 0x%lx\n", vpn); + } + + // Currently a 1-1 mapping is used, this can be changed here to support different + // mapping schemes + + // If ppn to vpn mapping doesnt exist. + if (addr_mapping.find(vpn) == addr_mapping.end()) + { + // Create mapping. + update_page_table(ppn, vpn, flags); + addr_mapping[vpn] = ppn; + } + } + DBGPRINT(" [RT:PTV_MAP] Mapped virtual addr: 0x%lx to physical addr: %lx\n", init_vAddr, init_pAddr); + + // Sanity check + uint64_t pAddr = page_table_walk(init_vAddr); + if (pAddr != init_pAddr) + { + assert(pAddr == init_pAddr && "ERROR: translated virtual Addresses are not the same with physical Address"); + } + + *dev_pAddr = init_vAddr; // commit vpn to be returned to host + DBGPRINT(" [RT:PTV_MAP] Translated device virtual addr: 0x%lx\n", *dev_pAddr); + + return 0; + } #endif - return 0; - } - int mem_reserve(uint64_t dev_addr, uint64_t size, int flags) { - CHECK_ERR(global_mem_.reserve(dev_addr, size), { - return err; - }); - DBGPRINT("mem_reserve: addr: 0x%lx, size: 0x%lx\n",dev_addr, size); - CHECK_ERR(this->mem_access(dev_addr, size, flags), { - global_mem_.release(dev_addr); - return err; - }); + int mem_alloc(uint64_t size, int flags, uint64_t *dev_addr) + { + + uint64_t addr; + DBGPRINT(" [RT:mem_alloc] mem_alloc size: 0x%lx\n", size); + CHECK_ERR(global_mem_.allocate(size, &addr), { + return err; + }); + CHECK_ERR(this->mem_access(addr, size, flags), { + global_mem_.release(addr); + return err; + }); + *dev_addr = addr; #ifdef VM_ENABLE - uint64_t paddr = dev_addr; - phy_to_virt_map(size, &paddr, flags); + // VM address translation + phy_to_virt_map(size, dev_addr, flags); #endif - return 0; - } + return 0; + } - int mem_free(uint64_t dev_addr) { + int mem_reserve(uint64_t dev_addr, uint64_t size, int flags) + { + CHECK_ERR(global_mem_.reserve(dev_addr, size), { + return err; + }); + DBGPRINT(" [RT:mem_reserve] mem_reserve: addr: 0x%lx, size: 0x%lx\n", dev_addr, size); + CHECK_ERR(this->mem_access(dev_addr, size, flags), { + global_mem_.release(dev_addr); + return err; + }); #ifdef VM_ENABLE - uint64_t pAddr = page_table_walk(dev_addr); - // VM address translation - return global_mem_.release(pAddr); + uint64_t paddr = dev_addr; + phy_to_virt_map(size, &paddr, flags); +#endif + return 0; + } + + int mem_free(uint64_t dev_addr) + { +#ifdef VM_ENABLE + uint64_t pAddr = page_table_walk(dev_addr); + // VM address translation + return global_mem_.release(pAddr); #else - return global_mem_.release(dev_addr); + return global_mem_.release(dev_addr); #endif - } + } - int mem_access(uint64_t dev_addr, uint64_t size, int flags) { + int mem_access(uint64_t dev_addr, uint64_t size, int flags) + { uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); if (dev_addr + asize > GLOBAL_MEM_SIZE) return -1; @@ -285,7 +288,8 @@ public: return 0; } - int mem_info(uint64_t* mem_free, uint64_t* mem_used) const { + int mem_info(uint64_t *mem_free, uint64_t *mem_used) const + { if (mem_free) *mem_free = global_mem_.free(); if (mem_used) @@ -293,21 +297,23 @@ public: return 0; } - int upload(uint64_t dest_addr, const void* src, uint64_t size) { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); - uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); - if (dest_addr + asize > GLOBAL_MEM_SIZE) - return -1; + int upload(uint64_t dest_addr, const void *src, uint64_t size) + { + // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); + uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); + if (dest_addr + asize > GLOBAL_MEM_SIZE) + return -1; #ifdef VM_ENABLE - uint64_t pAddr = page_table_walk(dest_addr); - DBGPRINT("Upload data to vAddr = 0x%lx (pAddr=0x%lx)\n", dest_addr, pAddr); - + uint64_t pAddr = page_table_walk(dest_addr); + DBGPRINT(" [RT:upload] Upload data to vAddr = 0x%lx (pAddr=0x%lx)\n", dest_addr, pAddr); + dest_addr = pAddr; //Overwirte #endif ram_.enable_acl(false); - ram_.write((const uint8_t*)src, dest_addr, size); + ram_.write((const uint8_t *)src, dest_addr, size); ram_.enable_acl(true); + /*DBGPRINT("upload %ld bytes to 0x%lx\n", size, dest_addr); for (uint64_t i = 0; i < size && i < 1024; i += 4) { DBGPRINT(" 0x%lx <- 0x%x\n", dest_addr + i, *(uint32_t*)((uint8_t*)src + i)); @@ -316,17 +322,19 @@ public: return 0; } - int download(void* dest, uint64_t src_addr, uint64_t size) { + int download(void *dest, uint64_t src_addr, uint64_t size) + { uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); if (src_addr + asize > GLOBAL_MEM_SIZE) return -1; #ifdef VM_ENABLE - uint64_t pAddr = page_table_walk(src_addr); - DBGPRINT("Download data to vAddr = 0x%lx (pAddr=0x%lx)\n", src_addr, pAddr); + uint64_t pAddr = page_table_walk(src_addr); + DBGPRINT(" [RT:download] Download data to vAddr = 0x%lx (pAddr=0x%lx)\n", src_addr, pAddr); + src_addr = pAddr; //Overwirte #endif ram_.enable_acl(false); - ram_.read((uint8_t*)dest, src_addr, size); + ram_.read((uint8_t *)dest, src_addr, size); ram_.enable_acl(true); /*DBGPRINT("download %ld bytes from 0x%lx\n", size, src_addr); @@ -337,9 +345,11 @@ public: return 0; } - int start(uint64_t krnl_addr, uint64_t args_addr) { + int start(uint64_t krnl_addr, uint64_t args_addr) + { // ensure prior run completed - if (future_.valid()) { + if (future_.valid()) + { future_.wait(); } @@ -350,9 +360,8 @@ public: this->dcr_write(VX_DCR_BASE_STARTUP_ARG1, args_addr >> 32); // start new run - future_ = std::async(std::launch::async, [&]{ - processor_.run(); - }); + future_ = std::async(std::launch::async, [&] + { processor_.run(); }); // clear mpm cache mpm_cache_.clear(); @@ -360,12 +369,14 @@ public: return 0; } - int ready_wait(uint64_t timeout) { + int ready_wait(uint64_t timeout) + { if (!future_.valid()) return 0; uint64_t timeout_sec = timeout / 1000; std::chrono::seconds wait_time(1); - for (;;) { + for (;;) + { // wait for 1 sec and check status auto status = future_.wait_for(wait_time); if (status == std::future_status::ready) @@ -376,8 +387,10 @@ public: return 0; } - int dcr_write(uint32_t addr, uint32_t value) { - if (future_.valid()) { + int dcr_write(uint32_t addr, uint32_t value) + { + if (future_.valid()) + { future_.wait(); // ensure prior run completed } processor_.dcr_write(addr, value); @@ -385,15 +398,18 @@ public: return 0; } - int dcr_read(uint32_t addr, uint32_t* value) const { + int dcr_read(uint32_t addr, uint32_t *value) const + { return dcrs_.read(addr, value); } - int mpm_query(uint32_t addr, uint32_t core_id, uint64_t* value) { + int mpm_query(uint32_t addr, uint32_t core_id, uint64_t *value) + { uint32_t offset = addr - VX_CSR_MPM_BASE; if (offset > 31) return -1; - if (mpm_cache_.count(core_id) == 0) { + if (mpm_cache_.count(core_id) == 0) + { uint64_t mpm_mem_addr = IO_MPM_ADDR + core_id * 32 * sizeof(uint64_t); CHECK_ERR(this->download(mpm_cache_[core_id].data(), mpm_mem_addr, 32 * sizeof(uint64_t)), { return err; @@ -404,247 +420,250 @@ public: } #ifdef VM_ENABLE - /* VM Management */ - void set_processor_satp(VA_MODE mode) + /* VM Management */ + void set_processor_satp(VA_MODE mode) + { + // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); + uint64_t satp = 0; + if (mode == VA_MODE::BARE) { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); - uint32_t satp; - if (mode == VA_MODE::BARE) - { - DBGPRINT("VA_MODE = BARE MODE"); - satp = 0; - } - else if (mode == VA_MODE::SV32) - { - satp = (alloc_2nd_level_page_table() >> 12) | 0x80000000; - DBGPRINT("VA_MODE = SV32 MODE(satp = 0x%x)\n",satp); - } - processor_.set_satp(satp); + DBGPRINT(" [RT:set_satp] VA_MODE = BARE MODE"); + } + else + { + satp = (alloc_2nd_level_page_table() / MEM_PAGE_SIZE) | (1 << SATP_MODE_IDX); + DBGPRINT(" [RT:set_satp] VA_MODE = SV mode (satp = 0x%lx)\n", satp); + } + processor_.set_satp(satp); + } + + uint64_t get_ptbr() + { + // return processor_.get_satp(); + return processor_.get_satp() & ((1 << SATP_PPN_WIDTH) - 1); + } + uint64_t get_pte_address(uint64_t base_page, uint64_t vpn) + { + return (base_page * MEM_PAGE_SIZE) + (vpn * PTE_SIZE); + } + + VA_MODE get_mode() + { +#ifdef XLEN_32 + return processor_.get_satp() & (1 << SATP_MODE_IDX) ? VA_MODE::SV32 : VA_MODE::BARE; +#else // 64 bit + return processor_.get_satp() & (1 << SATP_MODE_IDX) ? VA_MODE::SV64 : VA_MODE::BARE; +#endif + } + + void update_page_table(uint64_t ppn, uint64_t vpn, uint32_t flag) + { + // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); + DBGPRINT(" [RT:Update PT] Mapping vpn 0x%05lx to ppn 0x%05lx(flags = %u)\n", vpn, ppn, flag); + assert((((ppn >> 20) == 0) && ((vpn >> 20) == 0)) && "Upper 12 bits are not zero!"); + // Updating page table with the following mapping of (vAddr) to (pAddr). + // uint32_t page_bit_shift = log2ceil(PTE_SIZE*NUM_PTE_ENTRY); + uint64_t ppn_1 = 0, pte_addr = 0, pte_bytes = 0; + uint64_t vpn_1 = bits(vpn, 10, 19); + uint64_t vpn_0 = bits(vpn, 0, 9); + + // Read first level PTE. + DBGPRINT(" [RT:Update PT]Start second-level page table\n"); + pte_addr = get_pte_address(get_ptbr(), vpn_1); + pte_bytes = read_pte(pte_addr); + DBGPRINT(" [RT:Update PT] PTE addr 0x%lx, PTE bytes 0x%lx\n", pte_addr, pte_bytes); + ppn_1 = (pte_bytes >> 10); + + if (bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) + { + // If valid bit set, proceed to next level using new ppn form PTE. + DBGPRINT(" [RT:Update PT] PTE valid (ppn 0x%lx), continuing the walk...\n", ppn_1); + } + else + { + // If valid bit not set, allocate a second level page table + // in device memory and store ppn in PTE. Set rwx = 000 in PTE + // to indicate this is a pointer to the next level of the page table. + DBGPRINT(" [RT:Update PT] PTE Invalid (ppn 0x%lx), continuing the walk...\n", ppn_1); + ppn_1 = (alloc_1st_level_page_table(vpn_1) >> 12); + pte_bytes = ((ppn_1 << 10) | 0b0000000001); + assert((pte_addr >> 32) == 0 && "Upper 32 bits are not zero!"); + write_pte(pte_addr, pte_bytes); + // if (pte_bytes != read_pte(pte_addr)) + // DBGPRINT("Read/write values are different!\n"); } - uint32_t get_ptbr() - { - // return processor_.get_satp(); - return processor_.get_satp() & 0x003fffff; + DBGPRINT(" [RT:Update PT] Move to first-level page table\n"); + // Read second level PTE. + pte_addr = get_pte_address(ppn_1, vpn_0); + pte_bytes = read_pte(pte_addr); + + if (bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) + { + DBGPRINT(" [RT:Update PT] ERROR, shouldn't be here\n"); + exit(1); + // If valid bit is set, then the page is already allocated. + // Should not reach this point, a sanity check. } - uint64_t get_pte_address(uint64_t base_page, uint64_t vpn) + else { - return (base_page << 12) + (vpn * PTE_SIZE); - } + // If valid bit not set, write ppn of pAddr in PTE. Set rwx = 111 in PTE + // to indicate this is a leaf PTE and has the stated permissions. + pte_bytes = ((ppn << 10) | 0b0000001111); + write_pte(pte_addr, pte_bytes); + if (pte_bytes != read_pte(pte_addr)) + DBGPRINT(" [RT:Update PT] PTE write value and read value are not matched!\n"); + } + } - VA_MODE get_mode() + uint64_t page_table_walk(uint64_t vAddr_bits) + { + // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); + DBGPRINT(" [RT:PTW] start vAddr: 0x%lx\n", vAddr_bits); + if (!need_trans(vAddr_bits)) { - return processor_.get_satp() & 0x80000000 ? VA_MODE::SV32 : VA_MODE::BARE; - } + DBGPRINT(" [RT:PTW] Translation is not needed.\n"); + return vAddr_bits; + } + uint64_t LEVELS = 2; + vAddr_SV32_t vAddr(vAddr_bits); + uint64_t pte_addr, pte_bytes; + uint64_t pt_ba = get_ptbr() << 12; - void update_page_table(uint64_t ppn, uint64_t vpn, uint32_t flag) { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); - DBGPRINT("Mapping vpn 0x%05lx to ppn 0x%05lx(flags = %u)\n", vpn, ppn,flag); - assert((((ppn>> 20) == 0) && ((vpn >> 20) == 0)) && "Upper 12 bits are not zero!"); - //Updating page table with the following mapping of (vAddr) to (pAddr). - // uint32_t page_bit_shift = log2ceil(PTE_SIZE*NUM_PTE_ENTRY); - uint64_t ppn_1 = 0, pte_addr = 0, pte_bytes = 0; - uint64_t vpn_1 = bits(vpn, 10, 19); - uint64_t vpn_0 = bits(vpn, 0, 9); + // Get base page table. - //Read first level PTE. - DBGPRINT("Start second-level page table\n"); - pte_addr = get_pte_address(get_ptbr(), vpn_1); - pte_bytes = read_pte(pte_addr); - DBGPRINT("[PTE] addr 0x%lx, PTE 0x%lx\n", pte_addr, pte_bytes); - ppn_1 = (pte_bytes >> 10); + for (int i = LEVELS - 1; i >= 0; i--) + { + // Read PTE. + pte_addr = pt_ba + vAddr.vpn[i] * PTE_SIZE; + pte_bytes = read_pte(pte_addr); + PTE_SV32_t pte(pte_bytes); + DBGPRINT(" [RT:PTW] Level[%u] pte_bytes = 0x%lx, pte flags = %u)\n", i, pte.ppn, pte.flags); - if ( bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) + // Check if it has invalid flag bits. + if ((pte.v == 0) | ((pte.r == 0) & (pte.w == 1))) + { + std::string msg = " [RT:PTW] Page Fault : Attempted to access invalid entry. Entry: 0x"; + throw Page_Fault_Exception(msg); + } + + if ((pte.r == 0) & (pte.w == 0) & (pte.x == 0)) + { + // Not a leaf node as rwx == 000 + if (i == 0) { - //If valid bit set, proceed to next level using new ppn form PTE. - DBGPRINT("PTE valid (ppn 0x%lx), continuing the walk...\n",ppn_1); + throw Page_Fault_Exception(" [RT:PTW] Page Fault : No leaf node found."); } else { - //If valid bit not set, allocate a second level page table - // in device memory and store ppn in PTE. Set rwx = 000 in PTE - //to indicate this is a pointer to the next level of the page table. - DBGPRINT("PTE Invalid (ppn 0x%lx), continuing the walk...\n",ppn_1); - ppn_1 = (alloc_1st_level_page_table(vpn_1) >> 12); - pte_bytes = ((ppn_1 << 10) | 0b0000000001) ; - assert((pte_addr>> 32) == 0 && "Upper 32 bits are not zero!"); - write_pte(pte_addr, pte_bytes); - // if (pte_bytes != read_pte(pte_addr)) - // DBGPRINT("Read/write values are different!\n"); - } - - - DBGPRINT("Move to first-level page table\n"); - //Read second level PTE. - pte_addr = get_pte_address(ppn_1, vpn_0); - pte_bytes = read_pte(pte_addr); - - if ( bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) - { - DBGPRINT("ERROR, shouldn't be here\n"); - exit(1); - //If valid bit is set, then the page is already allocated. - //Should not reach this point, a sanity check. - } - else - { - //If valid bit not set, write ppn of pAddr in PTE. Set rwx = 111 in PTE - //to indicate this is a leaf PTE and has the stated permissions. - pte_bytes = ( (ppn << 10) | 0b0000001111) ; - write_pte(pte_addr, pte_bytes); - if (pte_bytes != read_pte(pte_addr)) - DBGPRINT("Read/write values are different!\n"); + // Continue on to next level. + pt_ba = pte.ppn << 12; + DBGPRINT(" [RT:PTW] next pt_ba: %p\n", (void *)pt_ba); } + } + else + { + // Leaf node found, finished walking. + pt_ba = pte.ppn << 12; + DBGPRINT(" [RT:PTW] Found PT_Base_Address [%d] = %lx\n", i, pt_ba); + break; + } } - uint64_t page_table_walk(uint64_t vAddr_bits) - { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); - DBGPRINT("PTW on vAddr: 0x%lx\n", vAddr_bits); - if (!need_trans(vAddr_bits)) - { - DBGPRINT("Translation is not needed.\n"); - return vAddr_bits; - } - uint64_t LEVELS = 2; - vAddr_SV32_t vAddr(vAddr_bits); - uint64_t pte_addr, pte_bytes; - uint64_t pt_ba = get_ptbr() << 12; - - //Get base page table. - - for ( int i = LEVELS-1 ; i >= 0 ; i--) - { - //Read PTE. - pte_addr = pt_ba+vAddr.vpn[i]*PTE_SIZE; - pte_bytes = read_pte(pte_addr); - PTE_SV32_t pte(pte_bytes); - DBGPRINT("pte_bytes = 0x%lx, pte flags = %u)\n", pte.ppn , pte.flags); - - //Check if it has invalid flag bits. - if ( (pte.v == 0) | ( (pte.r == 0) & (pte.w == 1) ) ) - { - std::string msg= "Page Fault : Attempted to access invalid entry. Entry: 0x"; - throw Page_Fault_Exception(msg); - } - - if ( (pte.r == 0) & (pte.w == 0) & (pte.x == 0)) - { - //Not a leaf node as rwx == 000 - if (i == 0) - { - throw Page_Fault_Exception("Page Fault : No leaf node found."); - } - else - { - //Continue on to next level. - pt_ba = pte.ppn << 12; - DBGPRINT("next pt_ba: %p\n", (void *)pt_ba); - - } - } - else - { - //Leaf node found, finished walking. - pt_ba = pte.ppn << 12; - DBGPRINT("Found PT_Base_Address [%d] = %lx\n", i, pt_ba); - break; - } - - } - - // pte_bytes is final leaf - PTE_SV32_t pte(pte_bytes); - //Check RWX permissions according to access type. - if (pte.r == 0) - { - throw Page_Fault_Exception("Page Fault : TYPE LOAD, Incorrect permissions."); - } - - uint64_t paddr = pt_ba + vAddr.pgoff; - return paddr; + // pte_bytes is final leaf + PTE_SV32_t pte(pte_bytes); + // Check RWX permissions according to access type. + if (pte.r == 0) + { + throw Page_Fault_Exception(" [RT:PTW] Page Fault : TYPE LOAD, Incorrect permissions."); } - uint64_t alloc_2nd_level_page_table() { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); - uint64_t addr=PAGE_TABLE_BASE_ADDR; - uint64_t size=1<<23; // 8MB !!!FIXME!!! - CHECK_ERR(this->mem_reserve(addr, size, VX_MEM_READ_WRITE), { - return err; - }); - init_page_table(addr); - return addr; + uint64_t paddr = pt_ba + vAddr.pgoff; + return paddr; + } + + uint64_t alloc_2nd_level_page_table() + { + uint64_t addr = PAGE_TABLE_BASE_ADDR; + uint64_t size = PT_TOTAL_SIZE; + CHECK_ERR(this->mem_reserve(addr, size, VX_MEM_READ_WRITE), { + return err; + }); + init_page_table(addr); + return addr; + } + uint64_t alloc_1st_level_page_table(uint64_t vpn_1) + { + uint64_t addr = PAGE_TABLE_BASE_ADDR + PT_SIZE * (1 + vpn_1); + init_page_table(addr); + return addr; + } + + // Initialize to zero the target page table area. 32bit 4K, 64bit 8K + void init_page_table(uint64_t addr) + { + uint64_t asize = aligned_size(PT_SIZE, CACHE_BLOCK_SIZE); + DBGPRINT(" [RT:init_page_table] (addr=0x%lx, size=0x%lx)\n", addr, asize); + uint8_t *src = new uint8_t[asize]; + for (uint64_t i = 0; i < PT_SIZE; ++i) + { + src[i] = 0; } - uint64_t alloc_1st_level_page_table(uint64_t vpn_1) { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); - uint64_t addr = PAGE_TABLE_BASE_ADDR + PTE_SIZE * NUM_PTE_ENTRY*(1+vpn_1); - init_page_table(addr); - return addr; + ram_.enable_acl(false); + ram_.write((const uint8_t *)src, addr, asize); + ram_.enable_acl(true); + } + + // void read_page_table(uint64_t addr) { + // uint8_t *dest = new uint8_t[MEM_PAGE_SIZE]; + // download(dest, addr, MEM_PAGE_SIZE); + // DBGPRINT("VXDRV: download %d bytes from 0x%x\n", MEM_PAGE_SIZE, addr); + // for (int i = 0; i < MEM_PAGE_SIZE; i += 4) { + // DBGPRINT("mem-read: 0x%x -> 0x%x\n", addr + i, *(uint64_t*)((uint8_t*)dest + i)); + // } + // } + + void write_pte(uint64_t addr, uint64_t value = 0xbaadf00d) + { + DBGPRINT(" [RT:Write_pte] writing pte 0x%lx to pAddr: 0x%lx\n", value, addr); + uint8_t *src = new uint8_t[PTE_SIZE]; + for (uint64_t i = 0; i < PTE_SIZE; ++i) + { + src[i] = (value >> (i << 3)) & 0xff; } + // std::cout << "writing PTE to RAM addr 0x" << std::hex << addr << std::endl; + ram_.enable_acl(false); + ram_.write((const uint8_t *)src, addr, PTE_SIZE); + ram_.enable_acl(true); + } - void init_page_table(uint64_t addr) { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); - DBGPRINT("int_page_table (addr=0x%lx)\n", addr); - uint64_t asize = aligned_size(RAM_PAGE_SIZE, CACHE_BLOCK_SIZE); - // uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); - uint8_t *src = new uint8_t[RAM_PAGE_SIZE]; - for (uint64_t i = 0; i < RAM_PAGE_SIZE; ++i) { - src[i] = 0; - } - ram_.enable_acl(false); - ram_.write((const uint8_t*)src, addr, asize); - ram_.enable_acl(true); - } + uint64_t read_pte(uint64_t addr) + { + uint8_t *dest = new uint8_t[PTE_SIZE]; +#ifdef XLEN_32 + uint64_t mask = 0x00000000FFFFFFFF; +#else // 64bit + uint64_t mask = 0xFFFFFFFFFFFFFFFF; +#endif - // void read_page_table(uint64_t addr) { - // uint8_t *dest = new uint8_t[RAM_PAGE_SIZE]; - // download(dest, addr, RAM_PAGE_SIZE); - // DBGPRINT("VXDRV: download %d bytes from 0x%x\n", RAM_PAGE_SIZE, addr); - // for (int i = 0; i < RAM_PAGE_SIZE; i += 4) { - // DBGPRINT("mem-read: 0x%x -> 0x%x\n", addr + i, *(uint64_t*)((uint8_t*)dest + i)); - // } - // } + ram_.read((uint8_t *)dest, addr, PTE_SIZE); + uint64_t ret = (*(uint64_t *)((uint8_t *)dest)) & mask; + DBGPRINT(" [RT:read_pte] reading PTE 0x%lx from RAM addr 0x%lx\n", ret, addr); - void write_pte(uint64_t addr, uint64_t value = 0xbaadf00d) { - DBGPRINT("[Write_pte] writing pte 0x%lx to pAddr: 0x%lx\n", value, addr); - uint8_t *src = new uint8_t[PTE_SIZE]; - for (uint64_t i = 0; i < PTE_SIZE; ++i) { - src[i] = (value >> (i << 3)) & 0xff; - } - //std::cout << "writing PTE to RAM addr 0x" << std::hex << addr << std::endl; - ram_.enable_acl(false); - ram_.write((const uint8_t*)src, addr, PTE_SIZE); - ram_.enable_acl(true); - } - - uint64_t read_pte(uint64_t addr) { - uint8_t *dest = new uint8_t[PTE_SIZE]; - uint64_t mask = 0; - if (XLEN == 32) - mask = 0x00000000FFFFFFFF; - else if (XLEN == 64) - mask = 0xFFFFFFFFFFFFFFFF; - else - assert(0 && "XLEN is not either 32 or 64"); - - ram_.read((uint8_t*)dest, addr, PTE_SIZE); - uint64_t ret = (*(uint64_t*)((uint8_t*)dest)) & mask; - DBGPRINT("[read_pte] reading PTE 0x%lx from RAM addr 0x%lx\n", ret, addr); - - return ret; - } + return ret; + } #endif // JAEWON private: - Arch arch_; - RAM ram_; - Processor processor_; - MemoryAllocator global_mem_; - DeviceConfig dcrs_; - std::future future_; + Arch arch_; + RAM ram_; + Processor processor_; + MemoryAllocator global_mem_; + DeviceConfig dcrs_; + std::future future_; std::unordered_map> mpm_cache_; #ifdef VM_ENABLE - std::unordered_map addr_mapping; + std::unordered_map addr_mapping; #endif }; diff --git a/sim/common/mem.cpp b/sim/common/mem.cpp index 98eefdaf2..eebd2cde3 100644 --- a/sim/common/mem.cpp +++ b/sim/common/mem.cpp @@ -21,6 +21,13 @@ #include using namespace vortex; +#ifdef VM_ENABLE +#ifndef NDEBUG +#define DBGPRINT(format, ...) do { printf("[VXDRV] " format "", ##__VA_ARGS__); } while (0) +#else +#define DBGPRINT(format, ...) ((void)0) +#endif +#endif uint64_t bits(uint64_t addr, uint8_t s_idx, uint8_t e_idx) { @@ -115,7 +122,6 @@ void MemoryUnit::ADecoder::map(uint64_t start, uint64_t end, MemDevice &md) { } void MemoryUnit::ADecoder::read(void* data, uint64_t addr, uint64_t size) { - // printf("====%s (addr= 0x%lx, size= 0x%lx) ====\n", __PRETTY_FUNCTION__,addr,size); mem_accessor_t ma; if (!this->lookup(addr, size, &ma)) { std::cout << "lookup of 0x" << std::hex << addr << " failed.\n"; @@ -125,7 +131,6 @@ void MemoryUnit::ADecoder::read(void* data, uint64_t addr, uint64_t size) { } void MemoryUnit::ADecoder::write(const void* data, uint64_t addr, uint64_t size) { - // printf("====%s====\n", __PRETTY_FUNCTION__); mem_accessor_t ma; if (!this->lookup(addr, size, &ma)) { std::cout << "lookup of 0x" << std::hex << addr << " failed.\n"; @@ -138,7 +143,9 @@ void MemoryUnit::ADecoder::write(const void* data, uint64_t addr, uint64_t size) MemoryUnit::MemoryUnit(uint64_t pageSize) : pageSize_(pageSize) +#ifndef VM_ENABLE , enableVM_(pageSize != 0) +#endif , amo_reservation_({0x0, false}) #ifdef VM_ENABLE , TLB_HIT(0) @@ -158,9 +165,9 @@ void MemoryUnit::attach(MemDevice &m, uint64_t start, uint64_t end) { decoder_.map(start, end, m); } + #ifdef VM_ENABLE std::pair MemoryUnit::tlbLookup(uint64_t vAddr, ACCESS_TYPE type, uint64_t* size_bits) { - // printf("====%s====\n", __PRETTY_FUNCTION__); //Find entry while accounting for different sizes. for (auto entry : tlb_) @@ -201,7 +208,7 @@ std::pair MemoryUnit::tlbLookup(uint64_t vAddr, ACCESS_TYPE type } //Check access permissions. - if ( (type == ACCESS_TYPE::FETCH) & ((e.r == 0) | (e.x == 0)) ) + if ( (type == ACCESS_TYPE::FENCE) & ((e.r == 0) | (e.x == 0)) ) { throw Page_Fault_Exception("Page Fault : Incorrect permissions."); } @@ -251,7 +258,7 @@ uint64_t MemoryUnit::toPhyAddr(uint64_t addr, uint32_t flagMask) { #ifdef VM_ENABLE void MemoryUnit::read(void* data, uint64_t addr, uint32_t size, ACCESS_TYPE type) { - // printf("====%s====\n", __PRETTY_FUNCTION__); + DBGPRINT(" [MMU:read] 0x%lx, 0x%x, %u\n",addr,size,type); uint64_t pAddr; pAddr = vAddr_to_pAddr(addr, type); return decoder_.read(data, pAddr, size); @@ -264,7 +271,7 @@ void MemoryUnit::read(void* data, uint64_t addr, uint32_t size, bool sup) { #endif #ifdef VM_ENABLE void MemoryUnit::write(const void* data, uint64_t addr, uint32_t size, ACCESS_TYPE type) { - // printf("====%s====\n", __PRETTY_FUNCTION__); + DBGPRINT(" [MMU:Write] 0x%lx, 0x%x, %u\n",addr,size,type); uint64_t pAddr; pAddr = vAddr_to_pAddr(addr, type); decoder_.write(data, pAddr, size); @@ -280,6 +287,7 @@ void MemoryUnit::write(const void* data, uint64_t addr, uint32_t size, bool sup) #ifdef VM_ENABLE void MemoryUnit::amo_reserve(uint64_t addr) { + DBGPRINT(" [MMU:amo_reserve] 0x%lx\n",addr); uint64_t pAddr = this->vAddr_to_pAddr(addr,ACCESS_TYPE::LOAD); amo_reservation_.addr = pAddr; amo_reservation_.valid = true; @@ -294,6 +302,7 @@ void MemoryUnit::amo_reserve(uint64_t addr) { #ifdef VM_ENABLE bool MemoryUnit::amo_check(uint64_t addr) { + DBGPRINT(" [MMU:amo_check] 0x%lx\n",addr); uint64_t pAddr = this->vAddr_to_pAddr(addr, ACCESS_TYPE::LOAD); return amo_reservation_.valid && (amo_reservation_.addr == pAddr); } @@ -593,30 +602,30 @@ void RAM::loadHexImage(const char* filename) { #ifdef VM_ENABLE bool MemoryUnit::need_trans(uint64_t dev_pAddr) -{ - // Check if the this is the BARE mode - bool isBAREMode = (this->mode == VA_MODE::BARE); - // Check if the address is reserved - bool isReserved = (dev_pAddr >= PAGE_TABLE_BASE_ADDR); - // Check if the address falls within the startup address range - bool isStartAddress = (STARTUP_ADDR <= dev_pAddr) && (dev_pAddr < (STARTUP_ADDR + 0x40000)); - - // Print the boolean results for debugging purposes - // printf("0x%lx, %u, %u, %u \n", dev_pAddr,isBAREMode, isReserved, isStartAddress); - - // Return true if the address needs translation (i.e., it's not reserved and not a start address) - return (!isBAREMode && !isReserved && !isStartAddress); -} + { + // Check if the this is the BARE mode + bool isBAREMode = (this->mode == VA_MODE::BARE); + // Check if the address is reserved for system usage + bool isReserved = (dev_pAddr >= PAGE_TABLE_BASE_ADDR); + // Check if the address is reserved for IO usage + bool isIO= (dev_pAddr < USER_BASE_ADDR); + // Check if the address falls within the startup address range + bool isStartAddress = (STARTUP_ADDR <= dev_pAddr) && (dev_pAddr <= (STARTUP_ADDR + 0x40000)); + + // Print the boolean results for debugging purposes + // printf("%p, %u, %u\n", (void *)dev_pAddr, isReserved, isStartAddress); + // Return true if the address needs translation (i.e., it's not reserved and not a start address) + return (!isBAREMode && !isReserved && !isIO && !isStartAddress); + } uint64_t MemoryUnit::vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type) { uint64_t pfn; uint64_t size_bits; - // printf("====%s====\n", __PRETTY_FUNCTION__); - // printf("vaddr = 0x%lx, type = 0x%u\n",vAddr,type); + DBGPRINT(" [MMU: V2P] vaddr = 0x%lx, type = 0x%u\n",vAddr,type); if (!need_trans(vAddr)) { - // printf("Translation is not needed.\n"); + DBGPRINT(" [MMU: V2P] Translation is not needed.\n"); return vAddr; } @@ -640,18 +649,18 @@ uint64_t MemoryUnit::vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type) } //Construct final address using pfn and offset. - // std::cout << "[MemoryUnit] translated vAddr: 0x" << std::hex << vAddr << " to pAddr: 0x" << std::hex << ((pfn << size_bits) + (vAddr & ((1 << size_bits) - 1))) << std::endl; + DBGPRINT(" [MMU: V2P] translated vAddr: 0x%lx to pAddr 0x%lx",vAddr,((pfn << size_bits) + (vAddr & ((1 << size_bits) - 1)))); return (pfn << size_bits) + (vAddr & ((1 << size_bits) - 1)); } std::pair MemoryUnit::page_table_walk(uint64_t vAddr_bits, ACCESS_TYPE type, uint64_t* size_bits) { - // printf("====%s====\n", __PRETTY_FUNCTION__); - // printf("vaddr = 0x%lx, type = %u, size_bits %lu\n", vAddr_bits, type, *size_bits); + DBGPRINT(" [MMU:PTW] Start: vaddr = 0x%lx, type = %u, size_bits %lu\n", vAddr_bits, type, *size_bits); uint64_t LEVELS = 2; vAddr_SV32_t vAddr(vAddr_bits); uint64_t pte_bytes = 0; + uint64_t pte_addr =0; //Get base page table. uint64_t pt_ba = this->ptbr << 12; int i = LEVELS - 1; @@ -660,14 +669,15 @@ std::pair MemoryUnit::page_table_walk(uint64_t vAddr_bits, AC { //Read PTE. - decoder_.read(&pte_bytes, pt_ba+vAddr.vpn[i]*PTE_SIZE, PTE_SIZE); + pte_addr = pt_ba+vAddr.vpn[i] * PTE_SIZE; + decoder_.read(&pte_bytes, pte_addr, PTE_SIZE); PTE_SV32_t pte(pte_bytes); + DBGPRINT(" [MMU:PTW] Level[%u] pte_bytes = 0x%lx, pte flags = %u)\n", i, pte.ppn , pte.flags); //Check if it has invalid flag bits. if ( (pte.v == 0) | ( (pte.r == 0) & (pte.w == 1) ) ) { - printf("Error: PTE FLAGS=0x%x\n",pte.flags); - throw Page_Fault_Exception("Page Fault : Attempted to access invalid entry."); + throw Page_Fault_Exception(" [MMU:PTW] Page Fault : Attempted to access invalid entry."); } if ( (pte.r == 0) & (pte.w == 0) & (pte.x == 0)) @@ -676,8 +686,7 @@ std::pair MemoryUnit::page_table_walk(uint64_t vAddr_bits, AC i--; if (i < 0) { - printf("Error: PTE FLAGS=0x%x\n",pte.flags); - throw Page_Fault_Exception("Page Fault : No leaf node found."); + throw Page_Fault_Exception(" [MMU:PTW] Page Fault : No leaf node found."); } else { @@ -696,35 +705,35 @@ std::pair MemoryUnit::page_table_walk(uint64_t vAddr_bits, AC PTE_SV32_t pte(pte_bytes); //Check RWX permissions according to access type. - if ( (type == ACCESS_TYPE::FETCH) & ((pte.r == 0) | (pte.x == 0)) ) + if ( (type == ACCESS_TYPE::FENCE) & ((pte.r == 0) | (pte.x == 0)) ) { - printf("Error: PTE FLAGS=0x%x\n",pte.flags); - throw Page_Fault_Exception("Page Fault : TYPE FETCH, Incorrect permissions."); + throw Page_Fault_Exception(" [MMU:PTW] Page Fault : TYPE FENCE, Incorrect permissions."); } else if ( (type == ACCESS_TYPE::LOAD) & (pte.r == 0) ) { - printf("Error: PTE FLAGS=0x%x\n",pte.flags); - throw Page_Fault_Exception("Page Fault : TYPE LOAD, Incorrect permissions."); + throw Page_Fault_Exception(" [MMU:PTW] Page Fault : TYPE LOAD, Incorrect permissions."); } else if ( (type == ACCESS_TYPE::STORE) & (pte.w == 0) ) { - printf("Error: PTE FLAGS=0x%x\n",pte.flags); - throw Page_Fault_Exception("Page Fault : TYPE STORE, Incorrect permissions."); + throw Page_Fault_Exception(" [MMU:PTW] Page Fault : TYPE STORE, Incorrect permissions."); } *size_bits = 12; uint64_t pfn = pt_ba >> *size_bits; return std::make_pair(pfn, pte_bytes & 0xff); } - -uint32_t MemoryUnit::get_satp() +uint64_t MemoryUnit::get_satp() { return satp; } -void MemoryUnit::set_satp(uint32_t satp) +void MemoryUnit::set_satp(uint64_t satp) { this->satp = satp; - this->ptbr = satp & 0x003fffff; //22 bits - this->mode = satp & 0x80000000 ? VA_MODE::SV32 : VA_MODE::BARE; + this->ptbr = satp & ( (1<< SATP_PPN_WIDTH) - 1); +#ifdef XLEN_32 + this->mode = satp & (1<< SATP_MODE_IDX) ? VA_MODE::SV32 : VA_MODE::BARE; +#else // 64 bit + this->mode = satp & (1<< SATP_MODE_IDX) ? VA_MODE::SV64 : VA_MODE::BARE; +#endif } #endif \ No newline at end of file diff --git a/sim/common/mem.h b/sim/common/mem.h index a655a6d3c..4b7744c2b 100644 --- a/sim/common/mem.h +++ b/sim/common/mem.h @@ -34,13 +34,14 @@ namespace vortex { #ifdef VM_ENABLE enum VA_MODE { BARE, - SV32 + SV32, + SV64 }; enum ACCESS_TYPE { LOAD, STORE, - FETCH + FENCE }; class Page_Fault_Exception : public std::runtime_error /* or logic_error */ @@ -117,7 +118,7 @@ public: }; #ifdef VM_ENABLE - MemoryUnit(uint64_t pageSize = PAGE_TABLE_SIZE); + MemoryUnit(uint64_t pageSize = MEM_PAGE_SIZE); #else MemoryUnit(uint64_t pageSize = 0); #endif @@ -138,8 +139,8 @@ public: #ifdef VM_ENABLE void tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags, uint64_t size_bits); - uint32_t get_satp(); - void set_satp(uint32_t satp); + uint64_t get_satp(); + void set_satp(uint64_t satp); #else void tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags); #endif @@ -238,14 +239,16 @@ private: std::unordered_map tlb_; uint64_t pageSize_; ADecoder decoder_; +#ifndef VM_ENABLE bool enableVM_; +#endif amo_reservation_t amo_reservation_; #ifdef VM_ENABLE - uint32_t satp; + uint64_t satp; VA_MODE mode; - uint32_t ptbr; + uint64_t ptbr; std::unordered_set unique_translations; uint64_t TLB_HIT, TLB_MISS, TLB_EVICT, PTW, PERF_UNIQUE_PTW; @@ -380,7 +383,7 @@ class vAddr_SV32_t vpn[0] = bits(address,12,21); vpn[1] = bits(address,22,31); pgoff = bits(address,0,11); - // printf("vpn[0] = 0x%lx, vpn[1] = 0x%lx, pgoff = 0x%lx\n",vpn[0],vpn[1],pgoff); + // printf("vpn[1] = 0x%lx, vpn[0] = 0x%lx, pgoff = 0x%lx\n",vpn[1],vpn[0],pgoff); } }; #endif diff --git a/sim/simx/cluster.cpp b/sim/simx/cluster.cpp index 2ca12f411..cb6c3c9d6 100644 --- a/sim/simx/cluster.cpp +++ b/sim/simx/cluster.cpp @@ -107,7 +107,7 @@ void Cluster::attach_ram(RAM* ram) { } #ifdef VM_ENABLE -void Cluster::set_satp(uint32_t satp) { +void Cluster::set_satp(uint64_t satp) { for (auto& socket : sockets_) { socket->set_satp(satp); } diff --git a/sim/simx/cluster.h b/sim/simx/cluster.h index 113ac04f7..df96031c3 100644 --- a/sim/simx/cluster.h +++ b/sim/simx/cluster.h @@ -58,7 +58,7 @@ public: void attach_ram(RAM* ram); #ifdef VM_ENABLE - void set_satp(uint32_t satp); + void set_satp(uint64_t satp); #endif bool running() const; diff --git a/sim/simx/core.cpp b/sim/simx/core.cpp index 29d77f5df..efaa19133 100644 --- a/sim/simx/core.cpp +++ b/sim/simx/core.cpp @@ -398,7 +398,7 @@ void Core::attach_ram(RAM* ram) { } #ifdef VM_ENABLE -void Core::set_satp(uint32_t satp) { +void Core::set_satp(uint64_t satp) { emulator_.set_satp(satp); //JAEWON wit, tid??? // emulator_.set_csr(VX_CSR_SATP,satp,0,0); //JAEWON wit, tid??? } diff --git a/sim/simx/core.h b/sim/simx/core.h index 6d305f7e2..42f72e552 100644 --- a/sim/simx/core.h +++ b/sim/simx/core.h @@ -98,7 +98,7 @@ public: void attach_ram(RAM* ram); #ifdef VM_ENABLE - void set_satp(uint32_t satp); + void set_satp(uint64_t satp); #endif bool running() const; diff --git a/sim/simx/emulator.cpp b/sim/simx/emulator.cpp index 63473cfd8..a15bdae43 100644 --- a/sim/simx/emulator.cpp +++ b/sim/simx/emulator.cpp @@ -270,7 +270,7 @@ bool Emulator::barrier(uint32_t bar_id, uint32_t count, uint32_t wid) { #ifdef VM_ENABLE void Emulator::icache_read(void *data, uint64_t addr, uint32_t size) { - DPH(3, "*** icache_read 0x" << std::hex << addr << ", size = 0x " << size); + // DP(1, "*** icache_read 0x" << std::hex << addr << ", size = 0x " << size); try { @@ -289,7 +289,7 @@ void Emulator::icache_read(void *data, uint64_t addr, uint32_t size) { #endif #ifdef VM_ENABLE -void Emulator::set_satp(uint32_t satp) { +void Emulator::set_satp(uint64_t satp) { DPH(3, "set satp 0x" << std::hex << satp << " in emulator module\n"); set_csr(VX_CSR_SATP,satp,0,0); } @@ -298,6 +298,7 @@ void Emulator::set_satp(uint32_t satp) { #ifdef VM_ENABLE void Emulator::dcache_read(void *data, uint64_t addr, uint32_t size) { + DP(1, "*** dcache_read 0x" << std::hex << addr << ", size = 0x " << size); auto type = get_addr_type(addr); if (type == AddrType::Shared) { core_->local_mem()->read(data, addr, size); diff --git a/sim/simx/emulator.h b/sim/simx/emulator.h index 15708f3c4..f9e250768 100644 --- a/sim/simx/emulator.h +++ b/sim/simx/emulator.h @@ -40,7 +40,7 @@ public: void attach_ram(RAM* ram); #ifdef VM_ENABLE - void set_satp(uint32_t satp) ; + void set_satp(uint64_t satp) ; #endif instr_trace_t* step(); diff --git a/sim/simx/processor.cpp b/sim/simx/processor.cpp index 3ae99fa4e..305fb410b 100644 --- a/sim/simx/processor.cpp +++ b/sim/simx/processor.cpp @@ -83,7 +83,7 @@ void ProcessorImpl::attach_ram(RAM* ram) { } } #ifdef VM_ENABLE -void ProcessorImpl::set_satp(uint32_t satp) { +void ProcessorImpl::set_satp(uint64_t satp) { for (auto cluster : clusters_) { cluster->set_satp(satp); } @@ -151,12 +151,12 @@ void Processor::dcr_write(uint32_t addr, uint32_t value) { } #ifdef VM_ENABLE -uint32_t Processor::get_satp() { +uint64_t Processor::get_satp() { // std::cout << "get SATP: 0x" << std::hex << this->satp << std::endl; return this->satp; } -void Processor::set_satp(uint32_t satp) { +void Processor::set_satp(uint64_t satp) { impl_->set_satp(satp); this->satp = satp; } diff --git a/sim/simx/processor.h b/sim/simx/processor.h index e22f11569..d2b575421 100644 --- a/sim/simx/processor.h +++ b/sim/simx/processor.h @@ -34,14 +34,14 @@ public: void dcr_write(uint32_t addr, uint32_t value); #ifdef VM_ENABLE - uint32_t get_satp(); - void set_satp(uint32_t satp); + uint64_t get_satp(); + void set_satp(uint64_t satp); #endif private: ProcessorImpl* impl_; #ifdef VM_ENABLE - uint32_t satp; + uint64_t satp; #endif }; diff --git a/sim/simx/processor_impl.h b/sim/simx/processor_impl.h index e6e9a4cf1..511c0cad6 100644 --- a/sim/simx/processor_impl.h +++ b/sim/simx/processor_impl.h @@ -40,8 +40,7 @@ public: void dcr_write(uint32_t addr, uint32_t value); #ifdef VM_ENABLE - // 32bit satp - void set_satp(uint32_t satp); + void set_satp(uint64_t satp); #endif PerfStats perf_stats() const; diff --git a/sim/simx/socket.cpp b/sim/simx/socket.cpp index 4fa3636e1..afda924d8 100644 --- a/sim/simx/socket.cpp +++ b/sim/simx/socket.cpp @@ -108,7 +108,7 @@ void Socket::attach_ram(RAM* ram) { } #ifdef VM_ENABLE -void Socket::set_satp(uint32_t satp) { +void Socket::set_satp(uint64_t satp) { for (auto core : cores_) { core->set_satp(satp); } diff --git a/sim/simx/socket.h b/sim/simx/socket.h index a09f73e8b..104d53292 100644 --- a/sim/simx/socket.h +++ b/sim/simx/socket.h @@ -61,7 +61,7 @@ public: void attach_ram(RAM* ram); #ifdef VM_ENABLE - void set_satp(uint32_t satp); + void set_satp(uint64_t satp); #endif bool running() const; From 3d98121ab6d2e6e430a1877469a98a4a15335162 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Sun, 23 Jun 2024 11:24:10 -0400 Subject: [PATCH 14/75] Update README.md --- README.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 3994bf942..bab81ddcb 100644 --- a/README.md +++ b/README.md @@ -56,8 +56,8 @@ More detailed build instructions can be found [here](docs/install_vortex.md). ``` ### Install Vortex codebase ``` - git clone --depth=1 --recursive git@github.com:gthparch/vortex_vm.git - cd vortex_vm + git clone --depth=1 --recursive git@github.com:vortexgpgpu/vortex.git -b vortex_vm + cd vortex ``` ### Configure your build folder @@ -69,21 +69,18 @@ More detailed build instructions can be found [here](docs/install_vortex.md). export OUT_DIR=`pwd`/out cd build ../configure --xlen=32 --tooldir=/software/vortex-toolchain-2024-05-22 --prefix=$OUT_DIR -### Ignore the commit for ramulator when it is compiled - # Please add ignore = dirty entry on .gitmodules - [submodule "third_party/ramulator"] - path = third_party/ramulator - url = https://github.com/CMU-SAFARI/ramulator.git - ignore = dirty + ### Install prebuilt toolchain # We will use the precomipled tools in volvo toolchanin directory + ### set environment variables # should always run before using the toolchain! source ./ci/toolchain_env.sh + ### Building Vortex make -s + ### Quick demo running vecadd OpenCL kernel on 2 cores -<<<<<<< HEAD $ ./ci/blackbox.sh --cores=2 --app=vecadd ### Common Developer Tips From 4ab015ddd9b921a2ada6f7d53b95ae49c2c0ac99 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Fri, 28 Jun 2024 09:48:04 -0400 Subject: [PATCH 15/75] Update README.md Update TOOLDIR to vortex-toolchain-2024-6-14/ --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bab81ddcb..704883e30 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ More detailed build instructions can be found [here](docs/install_vortex.md). mkdir out export OUT_DIR=`pwd`/out cd build - ../configure --xlen=32 --tooldir=/software/vortex-toolchain-2024-05-22 --prefix=$OUT_DIR + ../configure --xlen=32 --tooldir=/software/vortex-toolchain-2024-6-14 --prefix=$OUT_DIR ### Install prebuilt toolchain # We will use the precomipled tools in volvo toolchanin directory From d531fa6b26816e53066ccff6e7145bed35f8766d Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Sat, 29 Jun 2024 17:43:20 -0400 Subject: [PATCH 16/75] 64bit support --- .gitignore | 3 +- hw/rtl/VX_config.vh | 48 +-- runtime/common/common.h | 2 +- runtime/common/malloc.h | 26 +- runtime/simx/vortex.cpp | 482 +++++++++++++--------------- sim/common/mem.cpp | 176 +++++----- sim/common/mem.h | 232 ++++++++++--- sim/simx/emulator.cpp | 9 +- sim/simx/main.cpp | 2 +- sim/simx/processor.cpp | 23 +- sim/simx/processor.h | 10 +- tests/regression/diverge/kernel.cpp | 2 +- 12 files changed, 572 insertions(+), 443 deletions(-) diff --git a/.gitignore b/.gitignore index d1571b535..ca68f0eb2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /build* -/.vscode \ No newline at end of file +/.vscode +*.code-workspace diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index 4ff4dc9eb..5dbcb96b4 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -164,7 +164,7 @@ `endif `ifndef STARTUP_ADDR -`define STARTUP_ADDR 64'h080000000 +`define STARTUP_ADDR 64'h180000000 `endif `ifndef USER_BASE_ADDR @@ -271,59 +271,59 @@ `define DEBUG_LEVEL 3 `endif +`ifndef MEM_PAGE_SIZE +`define MEM_PAGE_SIZE (4096) +`endif +`ifndef MEM_PAGE_LOG2_SIZE +`define MEM_PAGE_LOG2_SIZE (12) +`endif + // Virtual Memory Configuration /////////////////////////////////////////////////////// `ifdef VM_ENABLE `ifdef XLEN_32 `ifndef VM_ADDR_MODE `define VM_ADDR_MODE SV32 //or BARE `endif + `ifndef PT_LEVEL + `define PT_LEVEL (2) + `endif `ifndef PTE_SIZE `define PTE_SIZE (4) `endif - `ifndef SATP_MODE_IDX - `define SATP_MODE_IDX (31) + `ifndef NUM_PTE_ENTRY + `define NUM_PTE_ENTRY (1024) `endif - `ifndef SATP_PPN_WIDTH - `define SATP_PPN_WIDTH (22) + `ifndef PT_SIZE_LIMIT + `define PT_SIZE_LIMIT (1<<23) `endif `else `ifndef VM_ADDR_MODE - `define VM_ADDR_MODE SV64 //or BARE + `define VM_ADDR_MODE SV39 //or BARE + `endif + `ifndef PT_LEVEL + `define PT_LEVEL (3) `endif `ifndef PTE_SIZE `define PTE_SIZE (8) `endif - `ifndef SATP_MODE_IDX - `define SATP_MODE_IDX (63) + `ifndef NUM_PTE_ENTRY + `define NUM_PTE_ENTRY (512) `endif - `ifndef SATP_PPN_WIDTH - `define SATP_PPN_WIDTH (44) + `ifndef PT_SIZE_LIMIT + `define PT_SIZE_LIMIT (1<<25) `endif `endif - `ifndef NUM_PTE_ENTRY - `define NUM_PTE_ENTRY (1024) - `endif - `ifndef PT_SIZE - `define PT_SIZE (PTE_SIZE * NUM_PTE_ENTRY) + `define PT_SIZE MEM_PAGE_SIZE `endif - `ifndef PT_TOTAL_SIZE - `define PT_TOTAL_SIZE (PT_SIZE*(1+NUM_PTE_ENTRY)) - `endif - - `ifndef TLB_SIZE `define TLB_SIZE (32) `endif `endif -`ifndef MEM_PAGE_SIZE -`define MEM_PAGE_SIZE (4096) -`endif - // Pipeline Configuration ///////////////////////////////////////////////////// // Issue width diff --git a/runtime/common/common.h b/runtime/common/common.h index f7125064e..37fec4846 100644 --- a/runtime/common/common.h +++ b/runtime/common/common.h @@ -24,7 +24,7 @@ #define CACHE_BLOCK_SIZE 64 -#define RAM_PAGE_SIZE 4096 +#define RAM_PAGE_SIZE 4096 // Please use MEM_PAGE_SIZE in VX_config.h #define ALLOC_BASE_ADDR USER_BASE_ADDR diff --git a/runtime/common/malloc.h b/runtime/common/malloc.h index 480c198a6..ca386031a 100644 --- a/runtime/common/malloc.h +++ b/runtime/common/malloc.h @@ -39,6 +39,15 @@ public: page_t* currPage = pages_; while (currPage) { auto nextPage = currPage->next; + #ifdef VM_ENABLE + block_t* currblock = currPage->findfirstUsedBlock(); + block_t* nextblock; + while (currblock) { + nextblock= currblock->nextUsed; + currPage->release(currblock); + currblock = nextblock; + } + #endif delete currPage; currPage = nextPage; } @@ -70,7 +79,7 @@ public: size = alignSize(size, pageAlign_); // Check if the reservation is within memory capacity bounds - if (addr + size > capacity_) { + if (addr + size > baseAddress_ + capacity_) { printf("error: address range out of bounds\n"); return -1; } @@ -118,12 +127,12 @@ public: auto pageSize = alignSize(size, pageAlign_); uint64_t pageAddr; if (!this->findNextAddress(pageSize, &pageAddr)) { - printf("error: out of memory\n"); + printf("error: out of memory (Can't find next address)\n"); return -1; } currPage = this->createPage(pageAddr, pageSize); if (nullptr == currPage) { - printf("error: out of memory\n"); + printf("error: out of memory (Can't create a page)\n"); return -1; } freeBlock = currPage->findFreeBlock(size); @@ -335,6 +344,11 @@ private: } return nullptr; } +#ifdef VM_ENABLE + block_t* findfirstUsedBlock() { + return usedList_; + } +#endif private: @@ -480,7 +494,7 @@ private: bool findNextAddress(uint64_t size, uint64_t* addr) { if (pages_ == nullptr) { - *addr = baseAddress_; + *addr = baseAddress_; return true; } @@ -498,10 +512,10 @@ private: endOfLastPage = current->addr + current->size; current = current->next; } - + // If no suitable gap is found, place the new page at the end of the last page // Check if the allocator has enough capacity - if ((endOfLastPage + size) <= capacity_) { + if ((endOfLastPage + size) <= (baseAddress_ + capacity_)) { *addr = endOfLastPage; return true; } diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 1a5da088a..ae9fe5bb5 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -27,10 +27,8 @@ #include #include -#ifdef VM_ENABLE #include -// #include -//#include +#ifdef VM_ENABLE #include #include @@ -44,42 +42,10 @@ #include #include #include -#include #endif using namespace vortex; -#ifdef VM_ENABLE -#ifndef NDEBUG -#define DBGPRINT(format, ...) do { printf("[VXDRV] " format "", ##__VA_ARGS__); } while (0) -#else -#define DBGPRINT(format, ...) ((void)0) -#endif - -#define CHECK_ERR(_expr, _cleanup) \ - do { \ - auto err = _expr; \ - if (err == 0) \ - break; \ - printf("[VXDRV] Error: '%s' returned %d!\n", #_expr, (int)err); \ - _cleanup \ - } while (false) - -/////////////////////////////////////////////////////////////////////////////// -// -#include -#include - -uint64_t bits(uint64_t addr, uint8_t s_idx, uint8_t e_idx) -{ - return (addr >> s_idx) & ((1 << (e_idx - s_idx + 1)) - 1); -} -bool bit(uint64_t addr, uint8_t idx) -{ - return (addr) & (1 << idx); -} -#endif - class vx_device { public: vx_device() @@ -91,14 +57,16 @@ public: // attach memory module processor_.attach_ram(&ram_); #ifdef VM_ENABLE - //Set - set_processor_satp(VM_ADDR_MODE); + CHECK_ERR(init_VM(), ); #endif - } + } ~vx_device() { #ifdef VM_ENABLE - this->mem_free(PAGE_TABLE_BASE_ADDR); // Right position? + global_mem_.release(PAGE_TABLE_BASE_ADDR); + // for (auto i = addr_mapping.begin(); i != addr_mapping.end(); i++) + // page_table_mem_->release(i->second << MEM_PAGE_SIZE); + delete page_table_mem_; #endif if (future_.valid()) { future_.wait(); @@ -154,9 +122,10 @@ public: bool need_trans(uint64_t dev_pAddr) { // Check if the this is the BARE mode - bool isBAREMode = (get_mode() == VA_MODE::BARE); + bool isBAREMode = (get_mode() == BARE); // Check if the address is reserved for system usage - bool isReserved = (dev_pAddr >= PAGE_TABLE_BASE_ADDR); + // bool isReserved = (PAGE_TABLE_BASE_ADDR <= dev_pAddr && dev_pAddr < PAGE_TABLE_BASE_ADDR + PT_SIZE_LIMIT); + bool isReserved = (PAGE_TABLE_BASE_ADDR <= dev_pAddr); // Check if the address is reserved for IO usage bool isIO = (dev_pAddr < USER_BASE_ADDR); // Check if the address falls within the startup address range @@ -172,14 +141,12 @@ public: uint64_t phy_to_virt_map(uint64_t size, uint64_t *dev_pAddr, uint32_t flags) { // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); - DBGPRINT(" [RT:PTV_MAP] size = 0x%lx, dev_pAddr= 0x%lx, flags = 0x%x\n", size, *dev_pAddr, flags); - DBGPRINT(" [RT:PTV_MAP] bit mode: %d\n", XLEN); - - // if (*dev_pAddr == STARTUP_ADDR || *dev_pAddr == 0x7FFFF000) { + DBGPRINT(" [RT:PTV_MAP] size = 0x%lx, dev_pAddr= 0x%lx, flags = 0x%x\n", size, *dev_pAddr, flags); + DBGPRINT(" [RT:PTV_MAP] bit mode: %d\n", XLEN); if (!need_trans(*dev_pAddr)) { - DBGPRINT(" [RT:PTV_MAP] Translation is not needed.\n"); + DBGPRINT(" [RT:PTV_MAP] Translation is not needed.\n"); return 0; } @@ -189,42 +156,30 @@ public: // dev_pAddr can be of size greater than a page, but we have to map and update // page tables on a page table granularity. So divide the allocation into pages. - bool is_start = false; - for (ppn = (*dev_pAddr) >> 12; ppn < ((*dev_pAddr) >> 12) + (size / MEM_PAGE_SIZE) + 1; ppn++) + // FUTURE Work: Super Page + for (ppn = (*dev_pAddr >> MEM_PAGE_LOG2_SIZE); ppn < ((*dev_pAddr) >> MEM_PAGE_LOG2_SIZE) + (size >> MEM_PAGE_LOG2_SIZE) ; ppn++) { - vpn = map_p2v(ppn << 12) >> 12; - if (is_start == false) - { - DBGPRINT(" [RT:PTV_MAP] Search vpn in page table:0x%lx\n", vpn); - is_start = true; - } - else - { - DBGPRINT(" [RT:PTV_MAP] Next vpn: 0x%lx\n", vpn); - } - + vpn = map_p2v(ppn << MEM_PAGE_LOG2_SIZE) >> MEM_PAGE_LOG2_SIZE; + DBGPRINT(" [RT:PTV_MAP] Search vpn in page table:0x%lx\n", vpn); // Currently a 1-1 mapping is used, this can be changed here to support different // mapping schemes - // If ppn to vpn mapping doesnt exist. if (addr_mapping.find(vpn) == addr_mapping.end()) { // Create mapping. - update_page_table(ppn, vpn, flags); + DBGPRINT(" [RT:PTV_MAP] Not found. Allocate new page table or update a PTE.\n"); + CHECK_ERR(update_page_table(ppn, vpn, flags),); addr_mapping[vpn] = ppn; } } - DBGPRINT(" [RT:PTV_MAP] Mapped virtual addr: 0x%lx to physical addr: %lx\n", init_vAddr, init_pAddr); - + DBGPRINT(" [RT:PTV_MAP] Mapped virtual addr: 0x%lx to physical addr: 0x%lx\n", init_vAddr, init_pAddr); // Sanity check uint64_t pAddr = page_table_walk(init_vAddr); - if (pAddr != init_pAddr) - { - assert(pAddr == init_pAddr && "ERROR: translated virtual Addresses are not the same with physical Address"); - } + DBGPRINT(" [RT:PTV_MAP] physical addr from PTW: 0x%lx\n", pAddr); + assert(pAddr == init_pAddr && "ERROR: translated virtual Addresses are not the same with physical Address\n"); *dev_pAddr = init_vAddr; // commit vpn to be returned to host - DBGPRINT(" [RT:PTV_MAP] Translated device virtual addr: 0x%lx\n", *dev_pAddr); + DBGPRINT(" [RT:PTV_MAP] Translated device virtual addr: 0x%lx\n", *dev_pAddr); return 0; } @@ -232,47 +187,44 @@ public: int mem_alloc(uint64_t size, int flags, uint64_t *dev_addr) { + uint64_t asize = aligned_size(size, MEM_PAGE_SIZE); + uint64_t addr = 0; - uint64_t addr; - DBGPRINT(" [RT:mem_alloc] mem_alloc size: 0x%lx\n", size); - CHECK_ERR(global_mem_.allocate(size, &addr), { + DBGPRINT("[RT:mem_alloc] size: 0x%lx, asize, 0x%lx,flag : 0x%d\n", size, asize, flags); + CHECK_ERR(global_mem_.allocate(asize, &addr), { return err; }); - CHECK_ERR(this->mem_access(addr, size, flags), { + CHECK_ERR(this->mem_access(addr, asize, flags), { global_mem_.release(addr); return err; }); *dev_addr = addr; #ifdef VM_ENABLE // VM address translation - phy_to_virt_map(size, dev_addr, flags); + phy_to_virt_map(asize, dev_addr, flags); #endif return 0; } int mem_reserve(uint64_t dev_addr, uint64_t size, int flags) { - CHECK_ERR(global_mem_.reserve(dev_addr, size), { + uint64_t asize = aligned_size(size, MEM_PAGE_SIZE); + CHECK_ERR(global_mem_.reserve(dev_addr, asize), { return err; }); - DBGPRINT(" [RT:mem_reserve] mem_reserve: addr: 0x%lx, size: 0x%lx\n", dev_addr, size); - CHECK_ERR(this->mem_access(dev_addr, size, flags), { + DBGPRINT("[RT:mem_reserve] addr: 0x%lx, asize:0x%lx, size: 0x%lx\n", dev_addr, asize, size); + CHECK_ERR(this->mem_access(dev_addr, asize, flags), { global_mem_.release(dev_addr); return err; }); -#ifdef VM_ENABLE - uint64_t paddr = dev_addr; - phy_to_virt_map(size, &paddr, flags); -#endif return 0; } int mem_free(uint64_t dev_addr) { #ifdef VM_ENABLE - uint64_t pAddr = page_table_walk(dev_addr); - // VM address translation - return global_mem_.release(pAddr); + uint64_t paddr= page_table_walk(dev_addr); + return global_mem_.release(paddr); #else return global_mem_.release(dev_addr); #endif @@ -313,8 +265,8 @@ public: ram_.write((const uint8_t *)src, dest_addr, size); ram_.enable_acl(true); - - /*DBGPRINT("upload %ld bytes to 0x%lx\n", size, dest_addr); + /* + DBGPRINT("upload %ld bytes to 0x%lx\n", size, dest_addr); for (uint64_t i = 0; i < size && i < 1024; i += 4) { DBGPRINT(" 0x%lx <- 0x%x\n", dest_addr + i, *(uint32_t*)((uint8_t*)src + i)); }*/ @@ -418,200 +370,195 @@ public: *value = mpm_cache_.at(core_id).at(offset); return 0; } - #ifdef VM_ENABLE /* VM Management */ - void set_processor_satp(VA_MODE mode) - { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); - uint64_t satp = 0; - if (mode == VA_MODE::BARE) - { - DBGPRINT(" [RT:set_satp] VA_MODE = BARE MODE"); - } - else - { - satp = (alloc_2nd_level_page_table() / MEM_PAGE_SIZE) | (1 << SATP_MODE_IDX); - DBGPRINT(" [RT:set_satp] VA_MODE = SV mode (satp = 0x%lx)\n", satp); - } - processor_.set_satp(satp); - } - - uint64_t get_ptbr() - { - // return processor_.get_satp(); - return processor_.get_satp() & ((1 << SATP_PPN_WIDTH) - 1); - } - uint64_t get_pte_address(uint64_t base_page, uint64_t vpn) - { - return (base_page * MEM_PAGE_SIZE) + (vpn * PTE_SIZE); - } - - VA_MODE get_mode() - { -#ifdef XLEN_32 - return processor_.get_satp() & (1 << SATP_MODE_IDX) ? VA_MODE::SV32 : VA_MODE::BARE; -#else // 64 bit - return processor_.get_satp() & (1 << SATP_MODE_IDX) ? VA_MODE::SV64 : VA_MODE::BARE; -#endif - } - - void update_page_table(uint64_t ppn, uint64_t vpn, uint32_t flag) - { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); - DBGPRINT(" [RT:Update PT] Mapping vpn 0x%05lx to ppn 0x%05lx(flags = %u)\n", vpn, ppn, flag); - assert((((ppn >> 20) == 0) && ((vpn >> 20) == 0)) && "Upper 12 bits are not zero!"); - // Updating page table with the following mapping of (vAddr) to (pAddr). - // uint32_t page_bit_shift = log2ceil(PTE_SIZE*NUM_PTE_ENTRY); - uint64_t ppn_1 = 0, pte_addr = 0, pte_bytes = 0; - uint64_t vpn_1 = bits(vpn, 10, 19); - uint64_t vpn_0 = bits(vpn, 0, 9); - - // Read first level PTE. - DBGPRINT(" [RT:Update PT]Start second-level page table\n"); - pte_addr = get_pte_address(get_ptbr(), vpn_1); - pte_bytes = read_pte(pte_addr); - DBGPRINT(" [RT:Update PT] PTE addr 0x%lx, PTE bytes 0x%lx\n", pte_addr, pte_bytes); - ppn_1 = (pte_bytes >> 10); - - if (bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) - { - // If valid bit set, proceed to next level using new ppn form PTE. - DBGPRINT(" [RT:Update PT] PTE valid (ppn 0x%lx), continuing the walk...\n", ppn_1); - } - else - { - // If valid bit not set, allocate a second level page table - // in device memory and store ppn in PTE. Set rwx = 000 in PTE - // to indicate this is a pointer to the next level of the page table. - DBGPRINT(" [RT:Update PT] PTE Invalid (ppn 0x%lx), continuing the walk...\n", ppn_1); - ppn_1 = (alloc_1st_level_page_table(vpn_1) >> 12); - pte_bytes = ((ppn_1 << 10) | 0b0000000001); - assert((pte_addr >> 32) == 0 && "Upper 32 bits are not zero!"); - write_pte(pte_addr, pte_bytes); - // if (pte_bytes != read_pte(pte_addr)) - // DBGPRINT("Read/write values are different!\n"); - } - - DBGPRINT(" [RT:Update PT] Move to first-level page table\n"); - // Read second level PTE. - pte_addr = get_pte_address(ppn_1, vpn_0); - pte_bytes = read_pte(pte_addr); - - if (bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) - { - DBGPRINT(" [RT:Update PT] ERROR, shouldn't be here\n"); - exit(1); - // If valid bit is set, then the page is already allocated. - // Should not reach this point, a sanity check. - } - else - { - // If valid bit not set, write ppn of pAddr in PTE. Set rwx = 111 in PTE - // to indicate this is a leaf PTE and has the stated permissions. - pte_bytes = ((ppn << 10) | 0b0000001111); - write_pte(pte_addr, pte_bytes); - if (pte_bytes != read_pte(pte_addr)) - DBGPRINT(" [RT:Update PT] PTE write value and read value are not matched!\n"); - } - } - - uint64_t page_table_walk(uint64_t vAddr_bits) - { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); - DBGPRINT(" [RT:PTW] start vAddr: 0x%lx\n", vAddr_bits); - if (!need_trans(vAddr_bits)) - { - DBGPRINT(" [RT:PTW] Translation is not needed.\n"); - return vAddr_bits; - } - uint64_t LEVELS = 2; - vAddr_SV32_t vAddr(vAddr_bits); - uint64_t pte_addr, pte_bytes; - uint64_t pt_ba = get_ptbr() << 12; - - // Get base page table. - - for (int i = LEVELS - 1; i >= 0; i--) - { - // Read PTE. - pte_addr = pt_ba + vAddr.vpn[i] * PTE_SIZE; - pte_bytes = read_pte(pte_addr); - PTE_SV32_t pte(pte_bytes); - DBGPRINT(" [RT:PTW] Level[%u] pte_bytes = 0x%lx, pte flags = %u)\n", i, pte.ppn, pte.flags); - - // Check if it has invalid flag bits. - if ((pte.v == 0) | ((pte.r == 0) & (pte.w == 1))) - { - std::string msg = " [RT:PTW] Page Fault : Attempted to access invalid entry. Entry: 0x"; - throw Page_Fault_Exception(msg); - } - - if ((pte.r == 0) & (pte.w == 0) & (pte.x == 0)) - { - // Not a leaf node as rwx == 000 - if (i == 0) - { - throw Page_Fault_Exception(" [RT:PTW] Page Fault : No leaf node found."); - } - else - { - // Continue on to next level. - pt_ba = pte.ppn << 12; - DBGPRINT(" [RT:PTW] next pt_ba: %p\n", (void *)pt_ba); - } - } - else - { - // Leaf node found, finished walking. - pt_ba = pte.ppn << 12; - DBGPRINT(" [RT:PTW] Found PT_Base_Address [%d] = %lx\n", i, pt_ba); - break; - } - } - - // pte_bytes is final leaf - PTE_SV32_t pte(pte_bytes); - // Check RWX permissions according to access type. - if (pte.r == 0) - { - throw Page_Fault_Exception(" [RT:PTW] Page Fault : TYPE LOAD, Incorrect permissions."); - } - - uint64_t paddr = pt_ba + vAddr.pgoff; - return paddr; - } - - uint64_t alloc_2nd_level_page_table() - { - uint64_t addr = PAGE_TABLE_BASE_ADDR; - uint64_t size = PT_TOTAL_SIZE; - CHECK_ERR(this->mem_reserve(addr, size, VX_MEM_READ_WRITE), { - return err; - }); - init_page_table(addr); - return addr; - } - uint64_t alloc_1st_level_page_table(uint64_t vpn_1) - { - uint64_t addr = PAGE_TABLE_BASE_ADDR + PT_SIZE * (1 + vpn_1); - init_page_table(addr); - return addr; - } // Initialize to zero the target page table area. 32bit 4K, 64bit 8K - void init_page_table(uint64_t addr) + uint16_t init_page_table(uint64_t addr, uint64_t size) { - uint64_t asize = aligned_size(PT_SIZE, CACHE_BLOCK_SIZE); + uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); DBGPRINT(" [RT:init_page_table] (addr=0x%lx, size=0x%lx)\n", addr, asize); uint8_t *src = new uint8_t[asize]; - for (uint64_t i = 0; i < PT_SIZE; ++i) + if (src == NULL) + return 1; + + for (uint64_t i = 0; i < asize; ++i) { src[i] = 0; } ram_.enable_acl(false); ram_.write((const uint8_t *)src, addr, asize); ram_.enable_acl(true); + return 0; + } + + uint8_t alloc_page_table (uint64_t * pt_addr) + { + CHECK_ERR(page_table_mem_->allocate(PT_SIZE, pt_addr), { return err; }); + CHECK_ERR(init_page_table(*pt_addr, PT_SIZE), { return err; }); + DBGPRINT(" [RT:alloc_page_table] addr= 0x%lx\n", *pt_addr); + return 0; + } + + int16_t init_VM() + { + uint64_t pt_addr = 0; + // Reserve space for PT + DBGPRINT("[RT:init_VM] Initialize VM\n"); + CHECK_ERR(mem_reserve(PAGE_TABLE_BASE_ADDR, PT_SIZE_LIMIT, VX_MEM_READ_WRITE), { + return err; + }); + page_table_mem_ = new MemoryAllocator (PAGE_TABLE_BASE_ADDR, PT_SIZE_LIMIT, MEM_PAGE_SIZE, CACHE_BLOCK_SIZE); + if (page_table_mem_ == NULL) + { + CHECK_ERR(this->mem_free(PAGE_TABLE_BASE_ADDR),); + return 1; + } + + if (VM_ADDR_MODE == BARE) + DBGPRINT("[RT:init_VM] VA_MODE = BARE MODE(addr= 0x0)"); + else + CHECK_ERR(alloc_page_table(&pt_addr),{return err;}); + + CHECK_ERR(processor_.set_satp_by_addr(pt_addr),{return err;}); + return 0; + } + + // Return value in in ptbr + uint64_t get_base_ppn() + { + return processor_.get_base_ppn(); + } + uint64_t get_pte_address(uint64_t base_ppn, uint64_t vpn) + { + return (base_ppn * PT_SIZE) + (vpn * PTE_SIZE); + } + + uint8_t get_mode() + { + return processor_.get_satp_mode(); + } + + int16_t update_page_table(uint64_t ppn, uint64_t vpn, uint32_t flag) + { + DBGPRINT(" [RT:Update PT] Mapping vpn 0x%05lx to ppn 0x%05lx(flags = %u)\n", vpn, ppn, flag); + // sanity check +#if VM_ADDR_MODE == SV39 + assert((((ppn >> 44) == 0) && ((vpn >> 27) == 0)) && "Upper bits are not zero!"); + uint8_t level = 3; +#else // Default is SV32, BARE will not reach this point. + assert((((ppn >> 20) == 0) && ((vpn >> 20) == 0)) && "Upper 12 bits are not zero!"); + uint8_t level = 2; +#endif + int i = level - 1; + vAddr_t vaddr(vpn << MEM_PAGE_LOG2_SIZE); + uint64_t pte_addr = 0, pte_bytes = 0; + uint64_t pt_addr = 0; + uint64_t cur_base_ppn = get_base_ppn(); + + while (i >= 0) + { + DBGPRINT(" [RT:Update PT]Start %u-level page table\n", i); + pte_addr = get_pte_address(cur_base_ppn, vaddr.vpn[i]); + pte_bytes = read_pte(pte_addr); + PTE_t pte_chk(pte_bytes); + DBGPRINT(" [RT:Update PT] PTE addr 0x%lx, PTE bytes 0x%lx\n", pte_addr, pte_bytes); + if (pte_chk.v == 1 && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) + { + DBGPRINT(" [RT:Update PT] PTE valid (ppn 0x%lx), continuing the walk...\n", pte_chk.ppn); + cur_base_ppn = pte_chk.ppn; + } + else + { + // If valid bit not set, allocate a next level page table + DBGPRINT(" [RT:Update PT] PTE Invalid (ppn 0x%lx) ...\n", pte_chk.ppn); + if (i == 0) + { + // Reach to leaf + DBGPRINT(" [RT:Update PT] Reached to level 0. This should be a leaf node(flag = %x) \n",flag); + uint32_t pte_flag = (flag << 1) | 0x3; + PTE_t new_pte(ppn <> mpm_cache_; #ifdef VM_ENABLE std::unordered_map addr_mapping; + MemoryAllocator* page_table_mem_; #endif }; diff --git a/sim/common/mem.cpp b/sim/common/mem.cpp index eebd2cde3..f3c1025a2 100644 --- a/sim/common/mem.cpp +++ b/sim/common/mem.cpp @@ -21,6 +21,7 @@ #include using namespace vortex; + #ifdef VM_ENABLE #ifndef NDEBUG #define DBGPRINT(format, ...) do { printf("[VXDRV] " format "", ##__VA_ARGS__); } while (0) @@ -29,16 +30,6 @@ using namespace vortex; #endif #endif -uint64_t bits(uint64_t addr, uint8_t s_idx, uint8_t e_idx) -{ - return (addr >> s_idx) & ((1 << (e_idx - s_idx + 1)) - 1); -} - -bool bit(uint64_t addr, uint8_t idx) -{ - return (addr) & (1 << idx); -} - RamMemDevice::RamMemDevice(const char *filename, uint32_t wordSize) : wordSize_(wordSize) { @@ -124,6 +115,7 @@ void MemoryUnit::ADecoder::map(uint64_t start, uint64_t end, MemDevice &md) { void MemoryUnit::ADecoder::read(void* data, uint64_t addr, uint64_t size) { mem_accessor_t ma; if (!this->lookup(addr, size, &ma)) { + assert(0); std::cout << "lookup of 0x" << std::hex << addr << " failed.\n"; throw BadAddress(); } @@ -133,6 +125,7 @@ void MemoryUnit::ADecoder::read(void* data, uint64_t addr, uint64_t size) { void MemoryUnit::ADecoder::write(const void* data, uint64_t addr, uint64_t size) { mem_accessor_t ma; if (!this->lookup(addr, size, &ma)) { + assert(0); std::cout << "lookup of 0x" << std::hex << addr << " failed.\n"; throw BadAddress(); } @@ -208,7 +201,7 @@ std::pair MemoryUnit::tlbLookup(uint64_t vAddr, ACCESS_TYPE type } //Check access permissions. - if ( (type == ACCESS_TYPE::FENCE) & ((e.r == 0) | (e.x == 0)) ) + if ( (type == ACCESS_TYPE::FETCH) & ((e.r == 0) | (e.x == 0)) ) { throw Page_Fault_Exception("Page Fault : Incorrect permissions."); } @@ -601,12 +594,33 @@ void RAM::loadHexImage(const char* filename) { #ifdef VM_ENABLE +uint64_t MemoryUnit::get_base_ppn() +{ + return satp_->get_base_ppn(); +} + +uint64_t MemoryUnit::get_satp() +{ + return satp_->get_satp(); +} + +uint8_t MemoryUnit::get_mode() +{ + return satp_->get_mode(); +} +void MemoryUnit::set_satp(uint64_t satp) +{ + // uint16_t asid = 0; // set asid for different process + satp_ = new SATP_t (satp ); +} + bool MemoryUnit::need_trans(uint64_t dev_pAddr) { // Check if the this is the BARE mode - bool isBAREMode = (this->mode == VA_MODE::BARE); + bool isBAREMode = (get_mode() == BARE); // Check if the address is reserved for system usage - bool isReserved = (dev_pAddr >= PAGE_TABLE_BASE_ADDR); + // bool isReserved = (PAGE_TABLE_BASE_ADDR <= dev_pAddr && dev_pAddr < PAGE_TABLE_BASE_ADDR + PT_SIZE_LIMIT); + bool isReserved = (PAGE_TABLE_BASE_ADDR <= dev_pAddr); // Check if the address is reserved for IO usage bool isIO= (dev_pAddr < USER_BASE_ADDR); // Check if the address falls within the startup address range @@ -634,7 +648,6 @@ uint64_t MemoryUnit::vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type) if (tlb_access.first) { - // printf("Found pfn %lx in TLB\n",tlb_access.second); pfn = tlb_access.second; TLB_HIT++; } @@ -649,91 +662,86 @@ uint64_t MemoryUnit::vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type) } //Construct final address using pfn and offset. - DBGPRINT(" [MMU: V2P] translated vAddr: 0x%lx to pAddr 0x%lx",vAddr,((pfn << size_bits) + (vAddr & ((1 << size_bits) - 1)))); + DBGPRINT(" [MMU: V2P] translated vAddr: 0x%lx to pAddr 0x%lx\n",vAddr,((pfn << size_bits) + (vAddr & ((1 << size_bits) - 1)))); return (pfn << size_bits) + (vAddr & ((1 << size_bits) - 1)); } -std::pair MemoryUnit::page_table_walk(uint64_t vAddr_bits, ACCESS_TYPE type, uint64_t* size_bits) -{ - DBGPRINT(" [MMU:PTW] Start: vaddr = 0x%lx, type = %u, size_bits %lu\n", vAddr_bits, type, *size_bits); - uint64_t LEVELS = 2; - vAddr_SV32_t vAddr(vAddr_bits); - uint64_t pte_bytes = 0; +uint64_t MemoryUnit::get_pte_address(uint64_t base_ppn, uint64_t vpn) +{ + return (base_ppn * PT_SIZE) + (vpn * PTE_SIZE); +} - uint64_t pte_addr =0; - //Get base page table. - uint64_t pt_ba = this->ptbr << 12; - int i = LEVELS - 1; +std::pair MemoryUnit::page_table_walk(uint64_t vAddr_bits, ACCESS_TYPE type, uint64_t *size_bits) +{ + DBGPRINT(" [MMU:PTW] Start: vaddr = 0x%lx, type = %u.\n", vAddr_bits, type); + uint8_t level = PT_LEVEL; + int i = level-1; + vAddr_t vaddr(vAddr_bits); + uint32_t flags =0; + uint64_t pte_addr = 0, pte_bytes = 0; + uint64_t cur_base_ppn = get_base_ppn(); + // Need to fix for super page + *size_bits = 12; - while(true) + while (true) + { + // Read PTE. + pte_addr = get_pte_address(cur_base_ppn, vaddr.vpn[i]); + decoder_.read(&pte_bytes, pte_addr, PTE_SIZE); + PTE_t pte(pte_bytes); + DBGPRINT(" [MMU:PTW] Level[%u] pte_addr=0x%lx, pte_bytes =0x%lx, pte.ppn= 0x%lx, pte.flags = %u)\n", i, pte_addr, pte_bytes, pte.ppn, pte.flags); + + assert(((pte.pte_bytes & 0xFFFFFFFF) != 0xbaadf00d) && "ERROR: uninitialzed PTE\n" ); + + // Check if it has invalid flag bits. + if ((pte.v == 0) | ((pte.r == 0) & (pte.w == 1))) { + assert(0); + throw Page_Fault_Exception(" [MMU:PTW] Page Fault : Attempted to access invalid entry."); + } - //Read PTE. - pte_addr = pt_ba+vAddr.vpn[i] * PTE_SIZE; - decoder_.read(&pte_bytes, pte_addr, PTE_SIZE); - PTE_SV32_t pte(pte_bytes); - DBGPRINT(" [MMU:PTW] Level[%u] pte_bytes = 0x%lx, pte flags = %u)\n", i, pte.ppn , pte.flags); - - //Check if it has invalid flag bits. - if ( (pte.v == 0) | ( (pte.r == 0) & (pte.w == 1) ) ) + if ((pte.r == 0) & (pte.w == 0) & (pte.x == 0)) + { + // Not a leaf node as rwx == 000 + i--; + if (i < 0) { - throw Page_Fault_Exception(" [MMU:PTW] Page Fault : Attempted to access invalid entry."); - } - - if ( (pte.r == 0) & (pte.w == 0) & (pte.x == 0)) - { - //Not a leaf node as rwx == 000 - i--; - if (i < 0) - { - throw Page_Fault_Exception(" [MMU:PTW] Page Fault : No leaf node found."); - } - else - { - //Continue on to next level. - pt_ba = (pte_bytes >> 10 ) << 12; - } + assert(0); + throw Page_Fault_Exception(" [MMU:PTW] Page Fault : No leaf node found."); } else { - //Leaf node found, finished walking. - pt_ba = (pte_bytes >> 10 ) << 12; - break; + // Continue on to next level. + cur_base_ppn= pte.ppn; + DBGPRINT(" [MMU:PTW] next base_ppn: 0x%lx\n", cur_base_ppn); + continue; } } - - PTE_SV32_t pte(pte_bytes); - - //Check RWX permissions according to access type. - if ( (type == ACCESS_TYPE::FENCE) & ((pte.r == 0) | (pte.x == 0)) ) + else { - throw Page_Fault_Exception(" [MMU:PTW] Page Fault : TYPE FENCE, Incorrect permissions."); + // Leaf node found, finished walking. + // Check RWX permissions according to access type. + if ((type == ACCESS_TYPE::FETCH) & ((pte.r == 0) | (pte.x == 0))) + { + assert(0); + throw Page_Fault_Exception(" [MMU:PTW] Page Fault : TYPE FETCH, Incorrect permissions."); + } + else if ((type == ACCESS_TYPE::LOAD) & (pte.r == 0)) + { + assert(0); + throw Page_Fault_Exception(" [MMU:PTW] Page Fault : TYPE LOAD, Incorrect permissions."); + } + else if ((type == ACCESS_TYPE::STORE) & (pte.w == 0)) + { + assert(0); + throw Page_Fault_Exception(" [MMU:PTW] Page Fault : TYPE STORE, Incorrect permissions."); + } + cur_base_ppn = pte.ppn; + flags = pte.flags; + break; } - else if ( (type == ACCESS_TYPE::LOAD) & (pte.r == 0) ) - { - throw Page_Fault_Exception(" [MMU:PTW] Page Fault : TYPE LOAD, Incorrect permissions."); - } - else if ( (type == ACCESS_TYPE::STORE) & (pte.w == 0) ) - { - throw Page_Fault_Exception(" [MMU:PTW] Page Fault : TYPE STORE, Incorrect permissions."); - } - *size_bits = 12; - uint64_t pfn = pt_ba >> *size_bits; - return std::make_pair(pfn, pte_bytes & 0xff); + } + return std::make_pair(cur_base_ppn, flags); } -uint64_t MemoryUnit::get_satp() -{ - return satp; -} -void MemoryUnit::set_satp(uint64_t satp) -{ - this->satp = satp; - this->ptbr = satp & ( (1<< SATP_PPN_WIDTH) - 1); -#ifdef XLEN_32 - this->mode = satp & (1<< SATP_MODE_IDX) ? VA_MODE::SV32 : VA_MODE::BARE; -#else // 64 bit - this->mode = satp & (1<< SATP_MODE_IDX) ? VA_MODE::SV64 : VA_MODE::BARE; -#endif -} #endif \ No newline at end of file diff --git a/sim/common/mem.h b/sim/common/mem.h index 4b7744c2b..9f212e184 100644 --- a/sim/common/mem.h +++ b/sim/common/mem.h @@ -32,17 +32,85 @@ namespace vortex { #ifdef VM_ENABLE -enum VA_MODE { - BARE, - SV32, - SV64 -}; + +// VA MODE +#define BARE 0x0 +#define SV32 0x1 +#define SV39 0x8 enum ACCESS_TYPE { LOAD, STORE, - FENCE + FETCH }; +class SATP_t +{ + private: + uint64_t address; + uint16_t asid; + uint8_t mode; + uint64_t ppn; + uint64_t satp; + + uint64_t bits(uint64_t input, uint8_t s_idx, uint8_t e_idx) + { + return (input>> s_idx) & (((uint64_t)1 << (e_idx - s_idx + 1)) - 1); + } + bool bit(uint64_t input , uint8_t idx) + { + return (input ) & ((uint64_t)1 << idx); + } + + public: + SATP_t(uint64_t satp) : satp(satp) + { +#ifdef XLEN_32 + mode = bit(satp, 31); + asid = bits(satp, 22, 30); + ppn = bits(satp, 0,21); +#else + mode = bits(satp, 60,63); + asid = bits(satp, 44, 59); + ppn = bits(satp, 0,43); +#endif + address = ppn << MEM_PAGE_LOG2_SIZE; + } + + SATP_t(uint64_t address, uint16_t asid) : address(address), asid(asid) + { +#ifdef XLEN_32 + assert((address >> 32) == 0 && "Upper 32 bits are not zero!"); +#endif + mode= VM_ADDR_MODE; + // asid = 0 ; + ppn = address >> MEM_PAGE_LOG2_SIZE; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshift-count-overflow" +#ifdef XLEN_32 + satp = (((uint64_t)mode << 31) | ((uint64_t)asid << 22) | ppn); +#else + satp = (((uint64_t)mode << 60) | ((uint64_t)asid << 44) | ppn); +#endif +#pragma GCC diagnostic pop + } + uint8_t get_mode() + { + return mode; + } + uint16_t get_asid() + { + return asid; + } + uint64_t get_base_ppn() + { + return ppn; + } + uint64_t get_satp() + { + return satp; + } +}; + class Page_Fault_Exception : public std::runtime_error /* or logic_error */ { @@ -119,6 +187,7 @@ public: #ifdef VM_ENABLE MemoryUnit(uint64_t pageSize = MEM_PAGE_SIZE); + ~MemoryUnit(){delete this->satp_;}; #else MemoryUnit(uint64_t pageSize = 0); #endif @@ -139,7 +208,9 @@ public: #ifdef VM_ENABLE void tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags, uint64_t size_bits); - uint64_t get_satp(); + uint64_t get_satp(); + uint8_t get_mode(); + uint64_t get_base_ppn(); void set_satp(uint64_t satp); #else void tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags); @@ -228,6 +299,7 @@ private: bool need_trans(uint64_t dev_pAddr); uint64_t vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type); + uint64_t get_pte_address(uint64_t base_ppn, uint64_t vpn); std::pair page_table_walk(uint64_t vAddr_bits, ACCESS_TYPE type, uint64_t* size_bits); #else uint64_t toPhyAddr(uint64_t vAddr, uint32_t flagMask); @@ -245,13 +317,9 @@ private: amo_reservation_t amo_reservation_; #ifdef VM_ENABLE - - uint64_t satp; - VA_MODE mode; - uint64_t ptbr; - std::unordered_set unique_translations; uint64_t TLB_HIT, TLB_MISS, TLB_EVICT, PTW, PERF_UNIQUE_PTW; + SATP_t *satp_; #endif }; @@ -322,68 +390,146 @@ private: }; #ifdef VM_ENABLE -class PTE_SV32_t +class PTE_t { private: uint64_t address; - uint64_t bits(uint64_t addr, uint8_t s_idx, uint8_t e_idx) + uint64_t bits(uint64_t input, uint8_t s_idx, uint8_t e_idx) { - return (addr >> s_idx) & ((1 << (e_idx - s_idx + 1)) - 1); + return (input>> s_idx) & (((uint64_t)1 << (e_idx - s_idx + 1)) - 1); } - bool bit(uint8_t idx) + bool bit(uint64_t input, uint8_t idx) { - return (address) & (1 << idx); + return (input) & ((uint64_t)1 << idx); } public: +#if VM_ADDR_MODE == SV39 + bool N; + uint8_t PBMT; +#endif uint64_t ppn; uint32_t rsw; uint32_t flags; + uint8_t level; bool d, a, g, u, x, w, r, v; - PTE_SV32_t(uint64_t address) : address(address) - { - assert((address>> 32) == 0 && "Upper 32 bits are not zero!"); - flags = bits(address,0,7); - rsw = bits(address,8,9); - ppn = bits(address,10,31); + uint64_t pte_bytes; - d = bit(7); - a = bit(6); - g = bit(5); - u = bit(4); - x = bit(3); - w = bit(2); - r = bit(1); - v = bit(0); - // printf("ppn = 0x%lx, flags= 0x%x, rsw= 0x%x\n",ppn,flags,rsw); + void set_flags (uint32_t flag) + { + this->flags = flag; + d = bit(flags,7); + a = bit(flags,6); + g = bit(flags,5); + u = bit(flags,4); + x = bit(flags,3); + w = bit(flags,2); + r = bit(flags,1); + v = bit(flags,0); + } + + PTE_t(uint64_t address, uint32_t flags) : address(address) + { +#if VM_ADDR_MODE == SV39 + N = 0; + PBMT = 0; + level = 3; + ppn = address >> MEM_PAGE_LOG2_SIZE; + // Reserve for Super page support + // ppn = new uint32_t [level]; + // ppn[2]=bits(address,28,53); + // ppn[1]=bits(address,19,27); + // ppn[0]=bits(address,10,18); + set_flags(flags); + // pte_bytes = (N << 63) | (PBMT << 61) | (ppn <<10) | flags ; + pte_bytes = (ppn <<10) | flags ; +#else // if VM_ADDR_MODE == SV32 + assert((address>> 32) == 0 && "Upper 32 bits are not zero!"); + level = 2; + ppn = address >> MEM_PAGE_LOG2_SIZE; + // Reserve for Super page support + // ppn = new uint32_t[level]; + // ppn[1]=bits(address,20,31); + // ppn[0]=bits(address,10,19); + set_flags(flags); + pte_bytes = ppn <<10 | flags ; +#endif + } + + PTE_t(uint64_t pte_bytes) : pte_bytes(pte_bytes) + { +#if VM_ADDR_MODE == SV39 + N = bit(pte_bytes,63); + PBMT = bits(pte_bytes,61,62); + level = 3; + ppn=bits(pte_bytes,10,53); + address = ppn << MEM_PAGE_LOG2_SIZE; + // Reserve for Super page support + // ppn = new uint32_t [level]; + // ppn[2]=bits(pte_bytes,28,53); + // ppn[1]=bits(pte_bytes,19,27); + // ppn[0]=bits(pte_bytes,10,18); +#else //#if VM_ADDR_MODE == SV32 + assert((pte_bytes >> 32) == 0 && "Upper 32 bits are not zero!"); + level = 2; + ppn=bits(pte_bytes,10, 31); + address = ppn << MEM_PAGE_LOG2_SIZE; + // Reserve for Super page support + // ppn = new uint32_t[level]; + // ppn[1]=bits(address, 20,31); + // ppn[0]=bits(address, 10,19); +#endif + rsw = bits(pte_bytes,8,9); + set_flags((uint32_t)(bits(pte_bytes,0,7))); + } + ~PTE_t() + { + // Reserve for Super page support + // delete ppn; } }; -class vAddr_SV32_t +class vAddr_t { private: uint64_t address; - uint64_t bits(uint64_t addr, uint8_t s_idx, uint8_t e_idx) + uint64_t bits(uint8_t s_idx, uint8_t e_idx) { - return (addr >> s_idx) & ((1 << (e_idx - s_idx + 1)) - 1); + return (address>> s_idx) & (((uint64_t)1 << (e_idx - s_idx + 1)) - 1); } - bool bit(uint64_t addr, uint8_t idx) + bool bit( uint8_t idx) { - return (addr) & (1 << idx); + return (address) & ((uint64_t)1 << idx); } public: - uint64_t vpn[2]; + uint64_t *vpn; uint64_t pgoff; - vAddr_SV32_t(uint64_t address) : address(address) + uint8_t level; + vAddr_t(uint64_t address) : address(address) { +#if VM_ADDR_MODE == SV39 + level = 3; + vpn = new uint64_t [level]; + vpn[2] = bits(30,38); + vpn[1] = bits(21,29); + vpn[0] = bits(12,20); + pgoff = bits(0,11); +#else //#if VM_ADDR_MODE == SV32 assert((address>> 32) == 0 && "Upper 32 bits are not zero!"); - vpn[0] = bits(address,12,21); - vpn[1] = bits(address,22,31); - pgoff = bits(address,0,11); - // printf("vpn[1] = 0x%lx, vpn[0] = 0x%lx, pgoff = 0x%lx\n",vpn[1],vpn[0],pgoff); + level = 2; + vpn = new uint64_t [level]; + vpn[1] = bits(22,31); + vpn[0] = bits(12,21); + pgoff = bits(0,11); +#endif + } + + ~vAddr_t() + { + delete vpn; } }; #endif diff --git a/sim/simx/emulator.cpp b/sim/simx/emulator.cpp index a15bdae43..9e96bef2f 100644 --- a/sim/simx/emulator.cpp +++ b/sim/simx/emulator.cpp @@ -115,7 +115,7 @@ void Emulator::clear() { void Emulator::attach_ram(RAM* ram) { // bind RAM to memory unit #if (XLEN == 64) - mmu_.attach(*ram, 0, 0xFFFFFFFFFFFFFFFF); + mmu_.attach(*ram, 0, 0x7FFFFFFFFF); //39bit SV39 #else mmu_.attach(*ram, 0, 0xFFFFFFFF); #endif @@ -270,11 +270,11 @@ bool Emulator::barrier(uint32_t bar_id, uint32_t count, uint32_t wid) { #ifdef VM_ENABLE void Emulator::icache_read(void *data, uint64_t addr, uint32_t size) { - // DP(1, "*** icache_read 0x" << std::hex << addr << ", size = 0x " << size); + DP(3, "*** icache_read 0x" << std::hex << addr << ", size = 0x " << size); try { - mmu_.read(data, addr, size, ACCESS_TYPE::LOAD); + mmu_.read(data, addr, size, ACCESS_TYPE::FETCH); } catch (Page_Fault_Exception& page_fault) { @@ -305,8 +305,7 @@ void Emulator::dcache_read(void *data, uint64_t addr, uint32_t size) { } else { try { - // mmu_.read(data, addr, size, 0); - mmu_.read(data, addr, size, ACCESS_TYPE::LOAD); + mmu_.read(data, addr, size, ACCESS_TYPE::LOAD); } catch (Page_Fault_Exception& page_fault) { diff --git a/sim/simx/main.cpp b/sim/simx/main.cpp index 0f61de6f4..be1505610 100644 --- a/sim/simx/main.cpp +++ b/sim/simx/main.cpp @@ -84,7 +84,7 @@ int main(int argc, char **argv) { Arch arch(num_threads, num_warps, num_cores); // create memory module - RAM ram(0, RAM_PAGE_SIZE); + RAM ram(0, MEM_PAGE_SIZE); // create processor Processor processor(arch); diff --git a/sim/simx/processor.cpp b/sim/simx/processor.cpp index 305fb410b..23406be98 100644 --- a/sim/simx/processor.cpp +++ b/sim/simx/processor.cpp @@ -136,6 +136,9 @@ Processor::Processor(const Arch& arch) Processor::~Processor() { delete impl_; +#ifdef VM_ENABLE + delete satp_; +#endif } void Processor::attach_ram(RAM* mem) { @@ -151,13 +154,19 @@ void Processor::dcr_write(uint32_t addr, uint32_t value) { } #ifdef VM_ENABLE -uint64_t Processor::get_satp() { - // std::cout << "get SATP: 0x" << std::hex << this->satp << std::endl; - return this->satp; -} - -void Processor::set_satp(uint64_t satp) { +int16_t Processor::set_satp_by_addr(uint64_t base_addr) { + uint16_t asid = 0; + satp_ = new SATP_t (base_addr,asid); + if (satp_ == NULL) + return 1; + uint64_t satp = satp_->get_satp(); impl_->set_satp(satp); - this->satp = satp; + return 0; +} +uint8_t Processor::get_satp_mode() { + return satp_->get_mode(); +} +uint64_t Processor::get_base_ppn() { + return satp_->get_base_ppn(); } #endif diff --git a/sim/simx/processor.h b/sim/simx/processor.h index d2b575421..a20cfff0b 100644 --- a/sim/simx/processor.h +++ b/sim/simx/processor.h @@ -22,6 +22,9 @@ namespace vortex { class Arch; class RAM; class ProcessorImpl; +#ifdef VM_ENABLE +class SATP_t; +#endif class Processor { public: @@ -34,14 +37,15 @@ public: void dcr_write(uint32_t addr, uint32_t value); #ifdef VM_ENABLE - uint64_t get_satp(); - void set_satp(uint64_t satp); + uint8_t get_satp_mode(); + uint64_t get_base_ppn(); + int16_t set_satp_by_addr(uint64_t addr); #endif private: ProcessorImpl* impl_; #ifdef VM_ENABLE - uint64_t satp; + SATP_t *satp_; #endif }; diff --git a/tests/regression/diverge/kernel.cpp b/tests/regression/diverge/kernel.cpp index f0380e0e4..70b27fa79 100644 --- a/tests/regression/diverge/kernel.cpp +++ b/tests/regression/diverge/kernel.cpp @@ -62,7 +62,7 @@ void kernel_body(kernel_arg_t* __UNIFORM__ arg) { value *= 5; break; default: - assert(task_id < arg->num_points); + //assert(task_id < arg->num_points); break; } From 3caeeeea132bdd94237a5f5507bbbe088b9fcfd1 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Sun, 30 Jun 2024 00:35:26 -0400 Subject: [PATCH 17/75] satp_ is not set, then we skip VAT --- runtime/simx/vortex.cpp | 24 ++++++++++++---------- sim/common/mem.cpp | 44 +++++++++++++++++++++++++++-------------- sim/common/mem.h | 9 +++++++-- sim/simx/emulator.h | 3 --- sim/simx/processor.cpp | 14 +++++++++++-- sim/simx/processor.h | 1 + 6 files changed, 63 insertions(+), 32 deletions(-) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index ae9fe5bb5..fc686ca76 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -121,21 +121,25 @@ public: } bool need_trans(uint64_t dev_pAddr) { - // Check if the this is the BARE mode - bool isBAREMode = (get_mode() == BARE); + + // Check if the satp is set and BARE mode + if (processor_.is_satp_unset() || get_mode() == BARE) + return 0; + // Check if the address is reserved for system usage // bool isReserved = (PAGE_TABLE_BASE_ADDR <= dev_pAddr && dev_pAddr < PAGE_TABLE_BASE_ADDR + PT_SIZE_LIMIT); - bool isReserved = (PAGE_TABLE_BASE_ADDR <= dev_pAddr); + if (PAGE_TABLE_BASE_ADDR <= dev_pAddr) + return 0; + // Check if the address is reserved for IO usage - bool isIO = (dev_pAddr < USER_BASE_ADDR); + if (dev_pAddr < USER_BASE_ADDR) + return 0; // Check if the address falls within the startup address range - bool isStartAddress = (STARTUP_ADDR <= dev_pAddr) && (dev_pAddr <= (STARTUP_ADDR + 0x40000)); + if ((STARTUP_ADDR <= dev_pAddr) && (dev_pAddr <= (STARTUP_ADDR + 0x40000))) + return 0; - // Print the boolean results for debugging purposes - // printf("%p, %u, %u\n", (void *)dev_pAddr, isReserved, isStartAddress); - - // Return true if the address needs translation (i.e., it's not reserved and not a start address) - return (!isBAREMode && !isReserved && !isIO && !isStartAddress); + // Now all conditions are not met. Return true because the address needs translation + return 1; } uint64_t phy_to_virt_map(uint64_t size, uint64_t *dev_pAddr, uint32_t flags) diff --git a/sim/common/mem.cpp b/sim/common/mem.cpp index f3c1025a2..a5339be6e 100644 --- a/sim/common/mem.cpp +++ b/sim/common/mem.cpp @@ -596,16 +596,26 @@ void RAM::loadHexImage(const char* filename) { uint64_t MemoryUnit::get_base_ppn() { + assert(satp_!= NULL); return satp_->get_base_ppn(); } uint64_t MemoryUnit::get_satp() { - return satp_->get_satp(); + if (is_satp_unset()) + return 0; + else + return satp_->get_satp(); +} + +uint8_t MemoryUnit::is_satp_unset() +{ + return (satp_==NULL); } uint8_t MemoryUnit::get_mode() { + assert(satp_!= NULL); return satp_->get_mode(); } void MemoryUnit::set_satp(uint64_t satp) @@ -616,22 +626,26 @@ void MemoryUnit::set_satp(uint64_t satp) bool MemoryUnit::need_trans(uint64_t dev_pAddr) { - // Check if the this is the BARE mode - bool isBAREMode = (get_mode() == BARE); - // Check if the address is reserved for system usage - // bool isReserved = (PAGE_TABLE_BASE_ADDR <= dev_pAddr && dev_pAddr < PAGE_TABLE_BASE_ADDR + PT_SIZE_LIMIT); - bool isReserved = (PAGE_TABLE_BASE_ADDR <= dev_pAddr); - // Check if the address is reserved for IO usage - bool isIO= (dev_pAddr < USER_BASE_ADDR); - // Check if the address falls within the startup address range - bool isStartAddress = (STARTUP_ADDR <= dev_pAddr) && (dev_pAddr <= (STARTUP_ADDR + 0x40000)); - - // Print the boolean results for debugging purposes - // printf("%p, %u, %u\n", (void *)dev_pAddr, isReserved, isStartAddress); + // Check if the satp is set and BARE mode + if ( is_satp_unset() || (get_mode() == BARE)) + return 0; - // Return true if the address needs translation (i.e., it's not reserved and not a start address) - return (!isBAREMode && !isReserved && !isIO && !isStartAddress); + // Check if the address is reserved for system usage + // bool isReserved = (PAGE_TABLE_BASE_ADDR <= dev_pAddr && dev_pAddr < PAGE_TABLE_BASE_ADDR + PT_SIZE_LIMIT); + if (PAGE_TABLE_BASE_ADDR <= dev_pAddr) + return 0; + + // Check if the address is reserved for IO usage + if (dev_pAddr < USER_BASE_ADDR) + return 0; + // Check if the address falls within the startup address range + if ((STARTUP_ADDR <= dev_pAddr) && (dev_pAddr <= (STARTUP_ADDR + 0x40000))) + return 0; + + // Now all conditions are not met. Return true because the address needs translation + return 1; } + uint64_t MemoryUnit::vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type) { uint64_t pfn; diff --git a/sim/common/mem.h b/sim/common/mem.h index 9f212e184..7ef13393a 100644 --- a/sim/common/mem.h +++ b/sim/common/mem.h @@ -186,8 +186,12 @@ public: }; #ifdef VM_ENABLE - MemoryUnit(uint64_t pageSize = MEM_PAGE_SIZE); - ~MemoryUnit(){delete this->satp_;}; + MemoryUnit(uint64_t pageSize = MEM_PAGE_SIZE) :satp_(NULL) + {}; + ~MemoryUnit(){ + if ( this->satp_ != NULL) + delete this->satp_; + }; #else MemoryUnit(uint64_t pageSize = 0); #endif @@ -208,6 +212,7 @@ public: #ifdef VM_ENABLE void tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags, uint64_t size_bits); + uint8_t is_satp_unset(); uint64_t get_satp(); uint8_t get_mode(); uint64_t get_base_ppn(); diff --git a/sim/simx/emulator.h b/sim/simx/emulator.h index f9e250768..47744c6d5 100644 --- a/sim/simx/emulator.h +++ b/sim/simx/emulator.h @@ -124,9 +124,6 @@ private: MemoryUnit mmu_; Word csr_mscratch_; wspawn_t wspawn_; -#ifdef VM_ENABLE - Word ptbr_; -#endif }; } diff --git a/sim/simx/processor.cpp b/sim/simx/processor.cpp index 23406be98..7c78218ff 100644 --- a/sim/simx/processor.cpp +++ b/sim/simx/processor.cpp @@ -132,12 +132,17 @@ ProcessorImpl::PerfStats ProcessorImpl::perf_stats() const { Processor::Processor(const Arch& arch) : impl_(new ProcessorImpl(arch)) -{} +{ +#ifdef VM_ENABLE + satp_ = NULL; +#endif +} Processor::~Processor() { delete impl_; #ifdef VM_ENABLE - delete satp_; + if (satp_ != NULL) + delete satp_; #endif } @@ -163,10 +168,15 @@ int16_t Processor::set_satp_by_addr(uint64_t base_addr) { impl_->set_satp(satp); return 0; } +bool Processor::is_satp_unset() { + return (satp_== NULL); +} uint8_t Processor::get_satp_mode() { + assert (satp_!=NULL); return satp_->get_mode(); } uint64_t Processor::get_base_ppn() { + assert (satp_!=NULL); return satp_->get_base_ppn(); } #endif diff --git a/sim/simx/processor.h b/sim/simx/processor.h index a20cfff0b..8315eedba 100644 --- a/sim/simx/processor.h +++ b/sim/simx/processor.h @@ -37,6 +37,7 @@ public: void dcr_write(uint32_t addr, uint32_t value); #ifdef VM_ENABLE + bool is_satp_unset(); uint8_t get_satp_mode(); uint64_t get_base_ppn(); int16_t set_satp_by_addr(uint64_t addr); From ccbb2243cc87de7c275cf3d061a25ac7dd296271 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Sun, 30 Jun 2024 00:54:22 -0400 Subject: [PATCH 18/75] fixed compile error --- sim/common/mem.cpp | 3 ++- sim/common/mem.h | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sim/common/mem.cpp b/sim/common/mem.cpp index a5339be6e..e3c9b5cc4 100644 --- a/sim/common/mem.cpp +++ b/sim/common/mem.cpp @@ -144,7 +144,8 @@ MemoryUnit::MemoryUnit(uint64_t pageSize) , TLB_HIT(0) , TLB_MISS(0) , TLB_EVICT(0) - , PTW(0) {}; + , PTW(0) + , satp_(NULL) {}; #else { if (pageSize != 0) diff --git a/sim/common/mem.h b/sim/common/mem.h index 7ef13393a..617e83d69 100644 --- a/sim/common/mem.h +++ b/sim/common/mem.h @@ -186,8 +186,7 @@ public: }; #ifdef VM_ENABLE - MemoryUnit(uint64_t pageSize = MEM_PAGE_SIZE) :satp_(NULL) - {}; + MemoryUnit(uint64_t pageSize = MEM_PAGE_SIZE); ~MemoryUnit(){ if ( this->satp_ != NULL) delete this->satp_; From c13e02b19f6ad3c8e670f19555a4b7c7b46b7688 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Sun, 30 Jun 2024 03:10:36 -0400 Subject: [PATCH 19/75] Change STARTUP_ADDR from 0x40000000 to 0x80000000(32b) and 0x180000000(64b) --- ci/regression.sh.in | 6 +++++- runtime/simx/vortex.cpp | 6 +----- sim/common/mem.cpp | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ci/regression.sh.in b/ci/regression.sh.in index a5f1bffdb..ce3f9bb43 100755 --- a/ci/regression.sh.in +++ b/ci/regression.sh.in @@ -240,7 +240,11 @@ config() # custom program startup address make -C tests/regression/dogfood clean-kernel - STARTUP_ADDR=0x40000000 make -C tests/regression/dogfood + if [ "$XLEN" == "64" ]; then + STARTUP_ADDR=0x180000000 make -C tests/regression/dogfood + else + STARTUP_ADDR=0x80000000 make -C tests/regression/dogfood + fi ./ci/blackbox.sh --driver=simx --app=dogfood ./ci/blackbox.sh --driver=rtlsim --app=dogfood diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index fc686ca76..08261fcd7 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -144,7 +144,6 @@ public: uint64_t phy_to_virt_map(uint64_t size, uint64_t *dev_pAddr, uint32_t flags) { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); DBGPRINT(" [RT:PTV_MAP] size = 0x%lx, dev_pAddr= 0x%lx, flags = 0x%x\n", size, *dev_pAddr, flags); DBGPRINT(" [RT:PTV_MAP] bit mode: %d\n", XLEN); @@ -178,10 +177,8 @@ public: } DBGPRINT(" [RT:PTV_MAP] Mapped virtual addr: 0x%lx to physical addr: 0x%lx\n", init_vAddr, init_pAddr); // Sanity check - uint64_t pAddr = page_table_walk(init_vAddr); - DBGPRINT(" [RT:PTV_MAP] physical addr from PTW: 0x%lx\n", pAddr); + assert(page_table_walk(init_vAddr) == init_pAddr && "ERROR: translated virtual Addresses are not the same with physical Address\n"); - assert(pAddr == init_pAddr && "ERROR: translated virtual Addresses are not the same with physical Address\n"); *dev_pAddr = init_vAddr; // commit vpn to be returned to host DBGPRINT(" [RT:PTV_MAP] Translated device virtual addr: 0x%lx\n", *dev_pAddr); @@ -255,7 +252,6 @@ public: int upload(uint64_t dest_addr, const void *src, uint64_t size) { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); if (dest_addr + asize > GLOBAL_MEM_SIZE) return -1; diff --git a/sim/common/mem.cpp b/sim/common/mem.cpp index e3c9b5cc4..e6e998fce 100644 --- a/sim/common/mem.cpp +++ b/sim/common/mem.cpp @@ -23,11 +23,11 @@ using namespace vortex; #ifdef VM_ENABLE -#ifndef NDEBUG -#define DBGPRINT(format, ...) do { printf("[VXDRV] " format "", ##__VA_ARGS__); } while (0) -#else +// #ifndef NDEBUG +// #define DBGPRINT(format, ...) do { printf("[VXDRV] " format "", ##__VA_ARGS__); } while (0) +// #else #define DBGPRINT(format, ...) ((void)0) -#endif +// #endif #endif From f0ea1acaa2d32210ea54eede1063ee3203ac06de Mon Sep 17 00:00:00 2001 From: Hanran Wu Date: Mon, 8 Jul 2024 17:07:30 -0400 Subject: [PATCH 20/75] vpn allocator added but doesn't pass any tests --- runtime/simx/vortex.cpp | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 08261fcd7..6f31a7ef6 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -114,10 +114,21 @@ public: } #ifdef VM_ENABLE - // virtual to phycial mapping - uint64_t map_p2v(uint64_t pAddr) + // virtual (vpn) to phycial (ppn) mapping + uint64_t map_p2v(uint64_t ppn, uint32_t flags) { - return pAddr + 0xf000000; + DBGPRINT(" [RT:MAP_P2V] ppn: %x\n", ppn); + // std::cout << std::hex << pAddr << std::endl; + // return pAddr + 0xf000000; + if (addr_mapping.find(ppn) != addr_mapping.end()) return addr_mapping[ppn]; + + // If ppn to vpn mapping doesnt exist, create mapping + DBGPRINT(" [RT:MAP_P2V] Not found. Allocate new page table or update a PTE.\n"); + uint64_t vpn; + virtual_mem_->allocate(MEM_PAGE_SIZE, &vpn); + CHECK_ERR(update_page_table(ppn, vpn, flags),); + addr_mapping[ppn] = vpn; + return vpn; } bool need_trans(uint64_t dev_pAddr) { @@ -154,7 +165,7 @@ public: } uint64_t init_pAddr = *dev_pAddr; - uint64_t init_vAddr = map_p2v(init_pAddr); + uint64_t init_vAddr = (map_p2v(init_pAddr >> MEM_PAGE_LOG2_SIZE, flags) << MEM_PAGE_LOG2_SIZE) & ((1 << MEM_PAGE_LOG2_SIZE) - 1); uint64_t ppn = 0, vpn = 0; // dev_pAddr can be of size greater than a page, but we have to map and update @@ -162,18 +173,11 @@ public: // FUTURE Work: Super Page for (ppn = (*dev_pAddr >> MEM_PAGE_LOG2_SIZE); ppn < ((*dev_pAddr) >> MEM_PAGE_LOG2_SIZE) + (size >> MEM_PAGE_LOG2_SIZE) ; ppn++) { - vpn = map_p2v(ppn << MEM_PAGE_LOG2_SIZE) >> MEM_PAGE_LOG2_SIZE; + + vpn = map_p2v(ppn << MEM_PAGE_LOG2_SIZE, flags) >> MEM_PAGE_LOG2_SIZE; DBGPRINT(" [RT:PTV_MAP] Search vpn in page table:0x%lx\n", vpn); // Currently a 1-1 mapping is used, this can be changed here to support different // mapping schemes - // If ppn to vpn mapping doesnt exist. - if (addr_mapping.find(vpn) == addr_mapping.end()) - { - // Create mapping. - DBGPRINT(" [RT:PTV_MAP] Not found. Allocate new page table or update a PTE.\n"); - CHECK_ERR(update_page_table(ppn, vpn, flags),); - addr_mapping[vpn] = ppn; - } } DBGPRINT(" [RT:PTV_MAP] Mapped virtual addr: 0x%lx to physical addr: 0x%lx\n", init_vAddr, init_pAddr); // Sanity check @@ -415,6 +419,13 @@ public: return 1; } + // HW: virtual mem allocator has the same address range as global_mem. next step is to adjust it + virtual_mem_ = new MemoryAllocator(ALLOC_BASE_ADDR >> MEM_PAGE_LOG2_SIZE, (GLOBAL_MEM_SIZE - ALLOC_BASE_ADDR) >> MEM_PAGE_LOG2_SIZE, MEM_PAGE_SIZE, CACHE_BLOCK_SIZE); + if (virtual_mem_ == nullptr) { + // virtual_mem_ does not intefere with physical mem, so no need to free space + return 1; + } + if (VM_ADDR_MODE == BARE) DBGPRINT("[RT:init_VM] VA_MODE = BARE MODE(addr= 0x0)"); else @@ -606,11 +617,12 @@ private: RAM ram_; Processor processor_; MemoryAllocator global_mem_; + MemoryAllocator* virtual_mem_; DeviceConfig dcrs_; std::future future_; std::unordered_map> mpm_cache_; #ifdef VM_ENABLE - std::unordered_map addr_mapping; + std::unordered_map addr_mapping; // HW: key: ppn; value: vpn MemoryAllocator* page_table_mem_; #endif }; From 31837dd7c3a59546eaef7561cba073d2c681a37c Mon Sep 17 00:00:00 2001 From: Hanran Wu Date: Mon, 8 Jul 2024 17:10:19 -0400 Subject: [PATCH 21/75] vpn allocator debug complete, now pass demo&vecadd tests --- runtime/simx/vortex.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 6f31a7ef6..3f82e647d 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -165,7 +165,7 @@ public: } uint64_t init_pAddr = *dev_pAddr; - uint64_t init_vAddr = (map_p2v(init_pAddr >> MEM_PAGE_LOG2_SIZE, flags) << MEM_PAGE_LOG2_SIZE) & ((1 << MEM_PAGE_LOG2_SIZE) - 1); + uint64_t init_vAddr = (map_p2v(init_pAddr >> MEM_PAGE_LOG2_SIZE, flags) << MEM_PAGE_LOG2_SIZE) | (init_pAddr & ((1 << MEM_PAGE_LOG2_SIZE) - 1)); uint64_t ppn = 0, vpn = 0; // dev_pAddr can be of size greater than a page, but we have to map and update From 314ad3ff8a591cd9213cc6f84ae01a31bf69dcd6 Mon Sep 17 00:00:00 2001 From: Hanran Wu Date: Tue, 9 Jul 2024 13:42:57 -0400 Subject: [PATCH 22/75] update destructor of vx_device --- runtime/simx/vortex.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 3f82e647d..6757bffbf 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -66,6 +66,7 @@ public: global_mem_.release(PAGE_TABLE_BASE_ADDR); // for (auto i = addr_mapping.begin(); i != addr_mapping.end(); i++) // page_table_mem_->release(i->second << MEM_PAGE_SIZE); + delete virtual_mem_; delete page_table_mem_; #endif if (future_.valid()) { @@ -114,6 +115,7 @@ public: } #ifdef VM_ENABLE + // virtual (vpn) to phycial (ppn) mapping uint64_t map_p2v(uint64_t ppn, uint32_t flags) { @@ -130,6 +132,7 @@ public: addr_mapping[ppn] = vpn; return vpn; } + bool need_trans(uint64_t dev_pAddr) { @@ -423,6 +426,7 @@ public: virtual_mem_ = new MemoryAllocator(ALLOC_BASE_ADDR >> MEM_PAGE_LOG2_SIZE, (GLOBAL_MEM_SIZE - ALLOC_BASE_ADDR) >> MEM_PAGE_LOG2_SIZE, MEM_PAGE_SIZE, CACHE_BLOCK_SIZE); if (virtual_mem_ == nullptr) { // virtual_mem_ does not intefere with physical mem, so no need to free space + return 1; } From b8757c539ded97619d1913780418746438cf62a1 Mon Sep 17 00:00:00 2001 From: Hanran Wu Date: Wed, 10 Jul 2024 22:39:00 -0400 Subject: [PATCH 23/75] add virtual mem allocator addr spacereservation --- runtime/simx/vortex.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 6757bffbf..92ae2362d 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -407,6 +407,21 @@ public: return 0; } + // reserve IO space, startup space, and local mem area + int virtual_mem_reserve(uint64_t dev_addr, uint64_t size, int flags) + { + // uint64_t asize = aligned_size(size, MEM_PAGE_SIZE); + CHECK_ERR(virtual_mem_->reserve(dev_addr, size), { + return err; + }); + DBGPRINT("[RT:mem_reserve] addr: 0x%lx, size:0x%lx, size: 0x%lx\n", dev_addr, size, size); + // CHECK_ERR(this->mem_access(dev_addr, asize, flags), { + // global_mem_.release(dev_addr); + // return err; + // }); + return 0; + } + int16_t init_VM() { uint64_t pt_addr = 0; @@ -424,6 +439,16 @@ public: // HW: virtual mem allocator has the same address range as global_mem. next step is to adjust it virtual_mem_ = new MemoryAllocator(ALLOC_BASE_ADDR >> MEM_PAGE_LOG2_SIZE, (GLOBAL_MEM_SIZE - ALLOC_BASE_ADDR) >> MEM_PAGE_LOG2_SIZE, MEM_PAGE_SIZE, CACHE_BLOCK_SIZE); + CHECK_ERR(virtual_mem_reserve(PAGE_TABLE_BASE_ADDR >> MEM_PAGE_LOG2_SIZE, (GLOBAL_MEM_SIZE - PAGE_TABLE_BASE_ADDR) >> MEM_PAGE_LOG2_SIZE, VX_MEM_READ_WRITE), { + return err; + }); + CHECK_ERR(virtual_mem_reserve(0, USER_BASE_ADDR >> MEM_PAGE_LOG2_SIZE, VX_MEM_READ_WRITE), { + return err; + }); + CHECK_ERR(virtual_mem_reserve(STARTUP_ADDR >> MEM_PAGE_LOG2_SIZE, (STARTUP_ADDR + 0x40000) >> MEM_PAGE_LOG2_SIZE, VX_MEM_READ_WRITE), { + return err; + }); + if (virtual_mem_ == nullptr) { // virtual_mem_ does not intefere with physical mem, so no need to free space From 91a1f41f9932f18b073f03d0bf029bf0d5fc29e4 Mon Sep 17 00:00:00 2001 From: Hanran Wu Date: Thu, 11 Jul 2024 14:49:00 -0400 Subject: [PATCH 24/75] debugged virtual memory allocator --- runtime/simx/vortex.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 92ae2362d..01c84fab6 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -119,7 +119,7 @@ public: // virtual (vpn) to phycial (ppn) mapping uint64_t map_p2v(uint64_t ppn, uint32_t flags) { - DBGPRINT(" [RT:MAP_P2V] ppn: %x\n", ppn); + DBGPRINT(" [RT:MAP_P2V] ppn: %lx\n", ppn); // std::cout << std::hex << pAddr << std::endl; // return pAddr + 0xf000000; if (addr_mapping.find(ppn) != addr_mapping.end()) return addr_mapping[ppn]; @@ -128,6 +128,7 @@ public: DBGPRINT(" [RT:MAP_P2V] Not found. Allocate new page table or update a PTE.\n"); uint64_t vpn; virtual_mem_->allocate(MEM_PAGE_SIZE, &vpn); + vpn = vpn >> MEM_PAGE_LOG2_SIZE; CHECK_ERR(update_page_table(ppn, vpn, flags),); addr_mapping[ppn] = vpn; return vpn; @@ -176,8 +177,7 @@ public: // FUTURE Work: Super Page for (ppn = (*dev_pAddr >> MEM_PAGE_LOG2_SIZE); ppn < ((*dev_pAddr) >> MEM_PAGE_LOG2_SIZE) + (size >> MEM_PAGE_LOG2_SIZE) ; ppn++) { - - vpn = map_p2v(ppn << MEM_PAGE_LOG2_SIZE, flags) >> MEM_PAGE_LOG2_SIZE; + vpn = map_p2v(ppn, flags) >> MEM_PAGE_LOG2_SIZE; DBGPRINT(" [RT:PTV_MAP] Search vpn in page table:0x%lx\n", vpn); // Currently a 1-1 mapping is used, this can be changed here to support different // mapping schemes @@ -438,14 +438,11 @@ public: } // HW: virtual mem allocator has the same address range as global_mem. next step is to adjust it - virtual_mem_ = new MemoryAllocator(ALLOC_BASE_ADDR >> MEM_PAGE_LOG2_SIZE, (GLOBAL_MEM_SIZE - ALLOC_BASE_ADDR) >> MEM_PAGE_LOG2_SIZE, MEM_PAGE_SIZE, CACHE_BLOCK_SIZE); - CHECK_ERR(virtual_mem_reserve(PAGE_TABLE_BASE_ADDR >> MEM_PAGE_LOG2_SIZE, (GLOBAL_MEM_SIZE - PAGE_TABLE_BASE_ADDR) >> MEM_PAGE_LOG2_SIZE, VX_MEM_READ_WRITE), { + virtual_mem_ = new MemoryAllocator(ALLOC_BASE_ADDR, (GLOBAL_MEM_SIZE - ALLOC_BASE_ADDR), MEM_PAGE_SIZE, CACHE_BLOCK_SIZE); + CHECK_ERR(virtual_mem_reserve(PAGE_TABLE_BASE_ADDR, (GLOBAL_MEM_SIZE - PAGE_TABLE_BASE_ADDR), VX_MEM_READ_WRITE), { return err; }); - CHECK_ERR(virtual_mem_reserve(0, USER_BASE_ADDR >> MEM_PAGE_LOG2_SIZE, VX_MEM_READ_WRITE), { - return err; - }); - CHECK_ERR(virtual_mem_reserve(STARTUP_ADDR >> MEM_PAGE_LOG2_SIZE, (STARTUP_ADDR + 0x40000) >> MEM_PAGE_LOG2_SIZE, VX_MEM_READ_WRITE), { + CHECK_ERR(virtual_mem_reserve(STARTUP_ADDR, 0x40000, VX_MEM_READ_WRITE), { return err; }); @@ -646,13 +643,13 @@ private: RAM ram_; Processor processor_; MemoryAllocator global_mem_; - MemoryAllocator* virtual_mem_; DeviceConfig dcrs_; std::future future_; std::unordered_map> mpm_cache_; #ifdef VM_ENABLE std::unordered_map addr_mapping; // HW: key: ppn; value: vpn MemoryAllocator* page_table_mem_; + MemoryAllocator* virtual_mem_; #endif }; From a4ee8dfa7fbbeac214ac54485c1f35948c68d288 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Sat, 20 Jul 2024 10:25:33 -0400 Subject: [PATCH 25/75] Update runtime/simx/vortex.cpp Co-authored-by: Martin Troiber <34752929+troibe@users.noreply.github.com> --- runtime/simx/vortex.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 01c84fab6..821fb057f 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -120,8 +120,6 @@ public: uint64_t map_p2v(uint64_t ppn, uint32_t flags) { DBGPRINT(" [RT:MAP_P2V] ppn: %lx\n", ppn); - // std::cout << std::hex << pAddr << std::endl; - // return pAddr + 0xf000000; if (addr_mapping.find(ppn) != addr_mapping.end()) return addr_mapping[ppn]; // If ppn to vpn mapping doesnt exist, create mapping From a23fb26a8b2559e19b83368f587505238fcbb4c2 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Sat, 20 Jul 2024 10:34:24 -0400 Subject: [PATCH 26/75] Update runtime/simx/vortex.cpp Co-authored-by: Martin Troiber <34752929+troibe@users.noreply.github.com> --- runtime/simx/vortex.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 821fb057f..3657912da 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -413,10 +413,6 @@ public: return err; }); DBGPRINT("[RT:mem_reserve] addr: 0x%lx, size:0x%lx, size: 0x%lx\n", dev_addr, size, size); - // CHECK_ERR(this->mem_access(dev_addr, asize, flags), { - // global_mem_.release(dev_addr); - // return err; - // }); return 0; } From 0f8e5505d3cdf5ca229834fb78c9323161df76d5 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Sat, 20 Jul 2024 10:36:58 -0400 Subject: [PATCH 27/75] Update runtime/simx/vortex.cpp Co-authored-by: Martin Troiber <34752929+troibe@users.noreply.github.com> --- runtime/simx/vortex.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 3657912da..fcf9f83ec 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -120,7 +120,7 @@ public: uint64_t map_p2v(uint64_t ppn, uint32_t flags) { DBGPRINT(" [RT:MAP_P2V] ppn: %lx\n", ppn); - if (addr_mapping.find(ppn) != addr_mapping.end()) return addr_mapping[ppn]; + if (addr_mapping.contains(ppn)) return addr_mapping[ppn]; // If ppn to vpn mapping doesnt exist, create mapping DBGPRINT(" [RT:MAP_P2V] Not found. Allocate new page table or update a PTE.\n"); From c3e657f201a641f02879e329617b933c2057016b Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Sat, 20 Jul 2024 10:39:40 -0400 Subject: [PATCH 28/75] Update runtime/simx/vortex.cpp Co-authored-by: Martin Troiber <34752929+troibe@users.noreply.github.com> --- runtime/simx/vortex.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index fcf9f83ec..1c22e3d36 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -116,7 +116,7 @@ public: #ifdef VM_ENABLE - // virtual (vpn) to phycial (ppn) mapping + // physical (ppn) to virtual (vpn) mapping uint64_t map_p2v(uint64_t ppn, uint32_t flags) { DBGPRINT(" [RT:MAP_P2V] ppn: %lx\n", ppn); From 90b4a16c9b70762f87146eb2c71b9a21341d6889 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Sat, 20 Jul 2024 11:20:27 -0400 Subject: [PATCH 29/75] Apply suggestions from code review Co-authored-by: Martin Troiber <34752929+troibe@users.noreply.github.com> --- runtime/simx/vortex.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 1c22e3d36..6a8457e99 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -408,7 +408,6 @@ public: // reserve IO space, startup space, and local mem area int virtual_mem_reserve(uint64_t dev_addr, uint64_t size, int flags) { - // uint64_t asize = aligned_size(size, MEM_PAGE_SIZE); CHECK_ERR(virtual_mem_->reserve(dev_addr, size), { return err; }); From de66a1b86131cd74dd4303a6da4df08eb6177831 Mon Sep 17 00:00:00 2001 From: Hanran Wu Date: Mon, 29 Jul 2024 14:35:11 -0400 Subject: [PATCH 30/75] save work before pull --- .travis.yml | 18 +++++++++++++++++- ci/regression.sh.in | 2 ++ runtime/include/vortex.h | 1 + runtime/simx/vortex.cpp | 11 ++++++++++- 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d43abb153..57098c8f0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -99,4 +99,20 @@ jobs: env: XLEN=32 script: - ./ci/travis_run.py ./ci/regression.sh --debug - - ./ci/travis_run.py ./ci/regression.sh --stress \ No newline at end of file + - ./ci/travis_run.py ./ci/regression.sh --stress + + - stage: test + name: virtual_memory + env: XLEN=32 + env: VM_DISABLE=1 + script: + - ./ci/travis_run.py ./ci/regression.sh --regression + - ./ci/travis_run.py ./ci/regression.sh --opencl + + - stage: test + name: virtual_memory + env: XLEN=64 + env: VM_DISABLE=1 + script: + - ./ci/travis_run.py ./ci/regression.sh --regression + - ./ci/travis_run.py ./ci/regression.sh --opencl \ No newline at end of file diff --git a/ci/regression.sh.in b/ci/regression.sh.in index ce3f9bb43..dffd91502 100755 --- a/ci/regression.sh.in +++ b/ci/regression.sh.in @@ -19,6 +19,8 @@ set -e # clear blackbox cache rm -f blackbox.*.cache +# HW: add a test "VM Test" to make sure VM feature is enabled + XLEN=${XLEN:=@XLEN@} echo "Vortex Regression Test: XLEN=$XLEN" diff --git a/runtime/include/vortex.h b/runtime/include/vortex.h index c9dd6ec36..6f57c7de8 100644 --- a/runtime/include/vortex.h +++ b/runtime/include/vortex.h @@ -61,6 +61,7 @@ typedef void* vx_buffer_h; #define VX_MEM_READ 0x1 #define VX_MEM_WRITE 0x2 #define VX_MEM_READ_WRITE 0x3 +#define VX_MEM_PIN_MEMORY 0x4 // open the device and connect to it int vx_dev_open(vx_device_h* hdevice); diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 01c84fab6..5e54576a5 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -199,6 +199,7 @@ public: uint64_t addr = 0; DBGPRINT("[RT:mem_alloc] size: 0x%lx, asize, 0x%lx,flag : 0x%d\n", size, asize, flags); + // HW: when vm is supported this global_mem_ should be virtual memory allocator CHECK_ERR(global_mem_.allocate(asize, &addr), { return err; }); @@ -231,7 +232,7 @@ public: int mem_free(uint64_t dev_addr) { #ifdef VM_ENABLE - uint64_t paddr= page_table_walk(dev_addr); + uint64_t paddr = page_table_walk(dev_addr); return global_mem_.release(paddr); #else return global_mem_.release(dev_addr); @@ -264,6 +265,14 @@ public: return -1; #ifdef VM_ENABLE uint64_t pAddr = page_table_walk(dest_addr); + // uint64_t pAddr; + // try { + // pAddr = page_table_walk(dest_addr); + // } catch ( Page_Fault_Exception ) { + // // HW: place holder + // // should be virt_to_phy_map here + // phy_to_virt_map(0, dest_addr, 0); + // } DBGPRINT(" [RT:upload] Upload data to vAddr = 0x%lx (pAddr=0x%lx)\n", dest_addr, pAddr); dest_addr = pAddr; //Overwirte #endif From e20a610e67d380adc6766b583481c413232ef9ed Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Wed, 5 Jun 2024 11:19:06 -0400 Subject: [PATCH 31/75] Update README.md --- third_party/ramulator | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/ramulator b/third_party/ramulator index e62c84a6f..214f63584 160000 --- a/third_party/ramulator +++ b/third_party/ramulator @@ -1 +1 @@ -Subproject commit e62c84a6f0e06566ba6e182d308434b4532068a5 +Subproject commit 214f635845214adf030367939655d172ef0fed5f From ae312f902213a760c5e64066c652378e24fab824 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Wed, 5 Jun 2024 11:23:47 -0400 Subject: [PATCH 32/75] Update README.md --- README.md | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 97484ff57..27cef6b6e 100644 --- a/README.md +++ b/README.md @@ -47,26 +47,31 @@ More detailed build instructions can be found [here](docs/install_vortex.md). - [Yosys](https://github.com/YosysHQ/yosys) - [Sv2v](https://github.com/zachjs/sv2v) ### Install development tools - $ sudo apt-get install build-essential - $ sudo apt-get install binutils - $ sudo apt-get install python - $ sudo apt-get install uuid-dev - $ sudo apt-get install git +``` + sudo apt-get install build-essential + sudo apt-get install binutils + sudo apt-get install python + sudo apt-get install uuid-dev + sudo apt-get install git +``` ### Install Vortex codebase - $ git clone --depth=1 --recursive https://github.com/vortexgpgpu/vortex.git - $ cd Vortex +``` + git clone --depth=1 --recursive https://github.com/vortexgpgpu/vortex.git + cd Vortex +``` ### Configure your build folder $ mkdir build $ cd build $ ../configure --xlen=32 --tooldir=$HOME/tools ### Install prebuilt toolchain - $ ./ci/toolchain_install.sh --all + # We will use the precomipled tools in volvo toolchanin directory ### set environment variables # should always run before using the toolchain! - $ source ./ci/toolchain_env.sh + source ./ci/toolchain_env.sh ### Building Vortex - $ make -s + make -s ### Quick demo running vecadd OpenCL kernel on 2 cores +<<<<<<< HEAD $ ./ci/blackbox.sh --cores=2 --app=vecadd ### Common Developer Tips From 768c9666817b6ef012f87674543a6a41abd3b391 Mon Sep 17 00:00:00 2001 From: Hanran Wu Date: Wed, 5 Jun 2024 16:11:51 -0400 Subject: [PATCH 33/75] expand MemoryUnit class defs and add some tlb-related functions --- hw/rtl/VX_config.vh | 16 ++++++ sim/common/mem.cpp | 41 +++++++++++++- sim/common/mem.h | 131 ++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 181 insertions(+), 7 deletions(-) diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index 804715aad..740748b76 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -14,6 +14,22 @@ `ifndef VX_CONFIG_VH `define VX_CONFIG_VH +`ifndef VM_ADDR_MODE +`define VM_ADDR_MODE SV32 +`endif + +`ifndef PTE_SIZE +`define PTE_SIZE 8 +`endif + +`ifndef TLB_SIZE +`define TLB_SIZE 32 +`endif + +`ifndef SUPER_PAGING +`define SUPER_PAGING false +`endif + `ifndef MIN `define MIN(x, y) (((x) < (y)) ? (x) : (y)) `endif diff --git a/sim/common/mem.cpp b/sim/common/mem.cpp index ed4bcc522..92a983410 100644 --- a/sim/common/mem.cpp +++ b/sim/common/mem.cpp @@ -17,9 +17,22 @@ #include #include #include "util.h" +#include +#include using namespace vortex; +uint64_t bits(uint64_t addr, uint8_t s_idx, uint8_t e_idx) +{ + return (addr >> s_idx) & ((1 << (e_idx - s_idx + 1)) - 1); +} + +bool bit(uint64_t addr, uint8_t idx) +{ + return (addr) & (1 << idx); +} + + RamMemDevice::RamMemDevice(const char *filename, uint32_t wordSize) : wordSize_(wordSize) { std::ifstream input(filename); @@ -158,12 +171,12 @@ uint64_t MemoryUnit::toPhyAddr(uint64_t addr, uint32_t flagMask) { return pAddr; } -void MemoryUnit::read(void* data, uint64_t addr, uint64_t size, bool sup) { +void MemoryUnit::read(void* data, uint64_t addr, uint64_t size, bool sup, ACCESS_TYPE type) { uint64_t pAddr = this->toPhyAddr(addr, sup ? 8 : 1); return decoder_.read(data, pAddr, size); } -void MemoryUnit::write(const void* data, uint64_t addr, uint64_t size, bool sup) { +void MemoryUnit::write(const void* data, uint64_t addr, uint64_t size, bool sup, ACCESS_TYPE type) { uint64_t pAddr = this->toPhyAddr(addr, sup ? 16 : 1); decoder_.write(data, pAddr, size); amo_reservation_.valid = false; @@ -179,10 +192,34 @@ bool MemoryUnit::amo_check(uint64_t addr) { uint64_t pAddr = this->toPhyAddr(addr, 1); return amo_reservation_.valid && (amo_reservation_.addr == pAddr); } + void MemoryUnit::tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags) { tlb_[virt / pageSize_] = TLBEntry(phys / pageSize_, flags); } +void MemoryUnit::tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags, uint64_t size_bits) { + // HW: evict TLB by Most Recently Used + if (tlb_.size() == TLB_SIZE - 1) { + for (auto& entry : tlb_) + { + entry.second.mru_bit = false; + } + + } else if (tlb_.size() == TLB_SIZE) { + uint64_t del; + for (auto entry : tlb_) { + if (!entry.second.mru_bit) + { + del = entry.first; + break; + } + } + tlb_.erase(tlb_.find(del)); + TLB_EVICT++; + } + tlb_[virt / pageSize_] = TLBEntry(phys / pageSize_, flags, size_bits); +} + void MemoryUnit::tlbRm(uint64_t va) { if (tlb_.find(va / pageSize_) != tlb_.end()) tlb_.erase(tlb_.find(va / pageSize_)); diff --git a/sim/common/mem.h b/sim/common/mem.h index 1f5196113..76e2f2ae5 100644 --- a/sim/common/mem.h +++ b/sim/common/mem.h @@ -18,8 +18,22 @@ #include #include #include +#include +#include namespace vortex { + +enum VA_MODE { + BARE, + SV32 +}; + +enum ACCESS_TYPE { + LOAD, + STORE, + FETCH +}; + struct BadAddress {}; struct OutOfRange {}; @@ -73,31 +87,39 @@ public: class MemoryUnit { public: +// HW: Expand PageFault struct to contain access_type info for debug purposes struct PageFault { PageFault(uint64_t a, bool nf) : faultAddr(a) , notFound(nf) + , access_type(ACCESS_TYPE::LOAD) {} - uint64_t faultAddr; - bool notFound; + uint64_t faultAddr; + bool notFound; + ACCESS_TYPE access_type; }; MemoryUnit(uint64_t pageSize = 0); void attach(MemDevice &m, uint64_t start, uint64_t end); - void read(void* data, uint64_t addr, uint64_t size, bool sup); - void write(const void* data, uint64_t addr, uint64_t size, bool sup); + void read(void* data, uint64_t addr, uint64_t size, bool sup, ACCESS_TYPE type = ACCESS_TYPE::LOAD); + void write(const void* data, uint64_t addr, uint64_t size, bool sup, ACCESS_TYPE type = ACCESS_TYPE::LOAD); void amo_reserve(uint64_t addr); bool amo_check(uint64_t addr); void tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags); + void tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags, uint64_t size_bits); + void tlbRm(uint64_t vaddr); void tlbFlush() { tlb_.clear(); } + uint32_t get_satp(); + void set_satp(uint32_t satp); + private: struct amo_reservation_t { @@ -137,11 +159,41 @@ private: TLBEntry(uint32_t pfn, uint32_t flags) : pfn(pfn) , flags(flags) - {} + , mru_bit(true) + {}; + TLBEntry(uint32_t pfn, uint32_t flags, uint64_t size_bits) + : pfn(pfn) + , flags(flags) + , mru_bit(true) + , size_bits (size_bits) + { + d = bit(7); + a = bit(6); + g = bit(5); + u = bit(4); + x = bit(3); + w = bit(2); + r = bit(1); + v = bit(0); + } + bool bit(uint8_t idx) + { + return (flags) & (1 << idx); + } + uint32_t pfn; + bool d, a, g, u, x, w, r, v; + bool mru_bit; + uint64_t size_bits; uint32_t flags; }; + std::pair tlbLookup(uint64_t vAddr, ACCESS_TYPE type, uint64_t* size_bits); + + uint64_t vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type); + + std::pair page_table_walk(uint64_t vAddr_bits, ACCESS_TYPE type, uint64_t* size_bits); + TLBEntry tlbLookup(uint64_t vAddr, uint32_t flagMask); uint64_t toPhyAddr(uint64_t vAddr, uint32_t flagMask); @@ -151,6 +203,13 @@ private: ADecoder decoder_; bool enableVM_; + uint32_t satp; + VA_MODE mode; + uint32_t ptbr; + + std::unordered_set unique_translations; + uint64_t TLB_HIT, TLB_MISS, TLB_EVICT, PTW, PERF_UNIQUE_PTW; + amo_reservation_t amo_reservation_; }; @@ -219,4 +278,66 @@ private: bool check_acl_; }; +class PTE_SV32_t +{ + + private: + uint64_t address; + uint64_t bits(uint64_t addr, uint8_t s_idx, uint8_t e_idx) + { + return (addr >> s_idx) & ((1 << (e_idx - s_idx + 1)) - 1); + } + bool bit(uint8_t idx) + { + return (address) & (1 << idx); + } + + public: + uint64_t ppn[2]; + uint32_t rsw; + uint32_t flags; + bool d, a, g, u, x, w, r, v; + PTE_SV32_t(uint64_t address) : address(address) + { + flags = bits(address,0,7); + rsw = bits(address,8,9); + ppn[0] = bits(address,10,19); + ppn[1] = bits(address,20,31); + + d = bit(7); + a = bit(6); + g = bit(5); + u = bit(4); + x = bit(3); + w = bit(2); + r = bit(1); + v = bit(0); + } +}; + +class vAddr_SV32_t +{ + + private: + uint64_t address; + uint64_t bits(uint64_t addr, uint8_t s_idx, uint8_t e_idx) + { + return (addr >> s_idx) & ((1 << (e_idx - s_idx + 1)) - 1); + } + bool bit(uint64_t addr, uint8_t idx) + { + return (addr) & (1 << idx); + } + + public: + uint64_t vpn[2]; + uint64_t pgoff; + vAddr_SV32_t(uint64_t address) : address(address) + { + vpn[0] = bits(address,12,21); + vpn[1] = bits(address,22,31); + pgoff = bits(address,0,11); + } +}; + } // namespace vortex From da1f4baa5ddcce241e6a9f275faa43d9c77d9d3a Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Fri, 7 Jun 2024 10:38:41 -0400 Subject: [PATCH 34/75] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 27cef6b6e..cbe7b13cd 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ More detailed build instructions can be found [here](docs/install_vortex.md). ``` ### Install Vortex codebase ``` - git clone --depth=1 --recursive https://github.com/vortexgpgpu/vortex.git + git clone --depth=1 --recursive git@github.com:gthparch/vortex_vm.git cd Vortex ``` ### Configure your build folder From 2662b6bcab42e1efa05450fd68a70f28b22271f8 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Fri, 7 Jun 2024 10:52:43 -0400 Subject: [PATCH 35/75] Update README.md --- README.md | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index cbe7b13cd..cd517b2b5 100644 --- a/README.md +++ b/README.md @@ -57,12 +57,23 @@ More detailed build instructions can be found [here](docs/install_vortex.md). ### Install Vortex codebase ``` git clone --depth=1 --recursive git@github.com:gthparch/vortex_vm.git - cd Vortex + cd vortex_vm ``` + ### Configure your build folder - $ mkdir build - $ cd build - $ ../configure --xlen=32 --tooldir=$HOME/tools + # By default, the toolchain default install location is the /opt folder and can be overridden by setting --tooldir. + # This is the example for volvo server + mkdir build + mkdir out + export OUT_DIR=`pwd`/out + cd build + ../configure --xlen=32 --tooldir=/software/vortex-toolchain-2024-05-22 --prefix=$OUT_DIR +### Ignore the commit for ramulator when it is compiled + # Please add ignore = dirty entry on .gitmodules + [submodule "third_party/ramulator"] + path = third_party/ramulator + url = https://github.com/CMU-SAFARI/ramulator.git + ignore = dirty ### Install prebuilt toolchain # We will use the precomipled tools in volvo toolchanin directory ### set environment variables From 43a90071e111b440f870ae4319cf34aaffb9488f Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Tue, 11 Jun 2024 23:06:48 -0400 Subject: [PATCH 36/75] Merge Austin's code (Preliminary) --- hw/rtl/VX_config.vh | 33 ++-- runtime/simx/vortex.cpp | 372 ++++++++++++++++++++++++++++++++++++-- sim/common/mem.cpp | 250 ++++++++++++++++++++++++- sim/common/mem.h | 68 +++++-- sim/simx/cluster.cpp | 8 + sim/simx/cluster.h | 4 + sim/simx/core.cpp | 7 + sim/simx/core.h | 4 + sim/simx/emulator.cpp | 82 ++++++++- sim/simx/emulator.h | 6 + sim/simx/processor.cpp | 22 ++- sim/simx/processor.h | 10 + sim/simx/processor_impl.h | 5 + sim/simx/socket.cpp | 8 + sim/simx/socket.h | 4 + 15 files changed, 830 insertions(+), 53 deletions(-) diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index 740748b76..a73de1d10 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -14,21 +14,28 @@ `ifndef VX_CONFIG_VH `define VX_CONFIG_VH -`ifndef VM_ADDR_MODE -`define VM_ADDR_MODE SV32 +`ifndef VM_DISABLE +`define VM_ENABLE +`endif +`ifdef VM_ENABLE + `ifndef VM_ADDR_MODE + `define VM_ADDR_MODE SV32 + `endif + + `ifndef PTE_SIZE + `define PTE_SIZE 8 + `endif + + `ifndef TLB_SIZE + `define TLB_SIZE 32 + `endif + + `ifndef SUPER_PAGING + `define SUPER_PAGING 0 + `endif + `endif -`ifndef PTE_SIZE -`define PTE_SIZE 8 -`endif - -`ifndef TLB_SIZE -`define TLB_SIZE 32 -`endif - -`ifndef SUPER_PAGING -`define SUPER_PAGING false -`endif `ifndef MIN `define MIN(x, y) (((x) < (y)) ? (x) : (y)) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 89856f3a0..6e5cafc38 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -29,6 +29,38 @@ using namespace vortex; +#ifdef VM_ENABLE + +#ifndef NDEBUG +#define DBGPRINT(format, ...) do { printf("[VXDRV] " format "", ##__VA_ARGS__); } while (0) +#else +#define DBGPRINT(format, ...) ((void)0) +#endif + +#define CHECK_ERR(_expr, _cleanup) \ + do { \ + auto err = _expr; \ + if (err == 0) \ + break; \ + printf("[VXDRV] Error: '%s' returned %d!\n", #_expr, (int)err); \ + _cleanup \ + } while (false) + +/////////////////////////////////////////////////////////////////////////////// +// +#include +#include + +uint64_t bits(uint64_t addr, uint8_t s_idx, uint8_t e_idx) +{ + return (addr >> s_idx) & ((1 << (e_idx - s_idx + 1)) - 1); +} +bool bit(uint64_t addr, uint8_t idx) +{ + return (addr) & (1 << idx); +} +#endif + class vx_device { public: vx_device() @@ -42,6 +74,10 @@ public: { // attach memory module processor_.attach_ram(&ram_); +#ifdef VM_ENABLE + //Set + processor_.set_processor_satp(VM_ADDR_MODE); +#endif } ~vx_device() { @@ -90,18 +126,75 @@ public: return 0; } - int mem_alloc(uint64_t size, int flags, uint64_t* dev_addr) { - uint64_t addr; - CHECK_ERR(global_mem_.allocate(size, &addr), { - return err; - }); - CHECK_ERR(this->mem_access(addr, size, flags), { - global_mem_.release(addr); - return err; - }); - *dev_addr = addr; - return 0; - } +#ifdef VM_ENABLE + // VM SUPPORT + uint64_t map_local_mem(uint64_t size, uint64_t* dev_maddr) + { + bool is_pc = false; + std::cout << "startup addr: " << std::hex << STARTUP_ADDR << std::endl; + std::cout << "bit mode: " << std::dec << XLEN << std::endl; + if (*dev_maddr == STARTUP_ADDR || *dev_maddr == 0x7FFFF000) { + is_pc = true; + } + + if (get_mode() == VA_MODE::BARE) + return 0; + + uint64_t ppn = *dev_maddr >> 12; + uint64_t init_pAddr = *dev_maddr; + uint64_t init_vAddr = *dev_maddr + 0xf0000000; // vpn will change, but we want to return the vpn of the beginning of the virtual allocation + init_vAddr = (init_vAddr >> 12) << 12; + uint64_t vpn; + + //dev_maddr can be of size greater than a page, but we have to map and update + //page tables on a page table granularity. So divide the allocation into pages. + for (ppn = (*dev_maddr) >> 12; ppn < ((*dev_maddr) >> 12) + (size/RAM_PAGE_SIZE) + 1; ppn++) + { + //Currently a 1-1 mapping is used, this can be changed here to support different + //mapping schemes + vpn = is_pc ? ppn : ppn + 0xf0000; + //vpn = ppn; + + //If ppn to vpn mapping doesnt exist. + if (addr_mapping.find(vpn) == addr_mapping.end()) + { + //Create mapping. + update_page_table(ppn, vpn); + addr_mapping[vpn] = ppn; + } + } + + std::cout << "mapped virtual addr: " << init_vAddr << " to physical addr: " << init_pAddr << std::endl; + uint64_t size_bits; + if (is_pc) { + std::cout << "not returning virtual address because it is PC or stack" << std::endl; + std::pair ptw_access = page_table_walk(init_vAddr - 0xf0000000, &size_bits); + return 0; + } else { + std::pair ptw_access = page_table_walk(init_vAddr, &size_bits); + } + *dev_maddr = init_vAddr; // commit vpn to be returned to host + return 0; + } +#endif + + int mem_alloc(uint64_t size, int flags, uint64_t* dev_addr) { + uint64_t addr; + CHECK_ERR(global_mem_.allocate(size, &addr), { + return err; + }); + CHECK_ERR(this->mem_access(addr, size, flags), { + global_mem_.release(addr); + return err; + }); +#ifdef VM_ENABLE + // VM address translation + std::cout << "physical addr: " << std::hex << *dev_addr << std::endl; + map_local_mem(size, dev_addr); +#endif + *dev_addr = addr; + return 0; + } int mem_reserve(uint64_t dev_addr, uint64_t size, int flags) { CHECK_ERR(global_mem_.reserve(dev_addr, size), { @@ -140,6 +233,18 @@ public: if (dest_addr + asize > GLOBAL_MEM_SIZE) return -1; +#ifdef VM_ENABLE + uint64_t pAddr = dest_addr; // map_local_mem overwrites the provided dest_addr, so store away physical destination address + if (dest_addr >= STARTUP_ADDR) { + map_local_mem(asize,&dest_addr); + } else if (dest_addr >= 0x7fff0000) + { + map_local_mem(asize,&dest_addr); + } + std::cout << "uploading to 0x" << pAddr << "(VA)" << std::endl; + dest_addr = pAddr; +#endif + ram_.enable_acl(false); ram_.write((const uint8_t*)src, dest_addr, size); ram_.enable_acl(true); @@ -235,6 +340,244 @@ public: return 0; } +#ifdef VM_ENABLE + /* VM Management */ + void set_processor_satp(VA_MODE mode) + { + uint32_t satp; + if (mode == VA_MODE::BARE) + satp = 0; + else if (mode == VA_MODE::SV32) + { + satp = (alloc_page_table() >> 10) | 0x80000000; + // satp = 0xFEBFE000 ; + } + processor_.set_satp(satp); + } + + uint32_t get_ptbr() + { + // return processor_.get_satp(); + return processor_.get_satp() & 0x003fffff; + } + + VA_MODE get_mode() + { + return processor_.get_satp() & 0x80000000 ? VA_MODE::SV32 : VA_MODE::BARE; + // return VA_MODE::SV32; + } + + void update_page_table(uint64_t pAddr, uint64_t vAddr) { + std::cout << "mapping vpn: " << vAddr << " to ppn:" << pAddr << std::endl; + //Updating page table with the following mapping of (vAddr) to (pAddr). + uint64_t ppn_1, pte_addr, pte_bytes; + uint64_t vpn_1 = bits(vAddr, 10, 19); + uint64_t vpn_0 = bits(vAddr, 0, 9); + + //Read first level PTE. + pte_addr = (get_ptbr() << 12) + (vpn_1 * PTE_SIZE); + pte_bytes = read_pte(pte_addr); + std::cout << "[PTE] addr 0x" << std::hex << pte_addr << ", PTE 0x" << std::hex << pte_bytes << std::endl; + + + if ( bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) + { + //If valid bit set, proceed to next level using new ppn form PTE. + std::cout << "PTE valid, continuing the walk..." << std::endl; + ppn_1 = (pte_bytes >> 10); + } + else + { + //If valid bit not set, allocate a second level page table + // in device memory and store ppn in PTE. Set rwx = 000 in PTE + //to indicate this is a pointer to the next level of the page table. + ppn_1 = (alloc_page_table() >> 12); + pte_bytes = ( (ppn_1 << 10) | 0b0000000001) ; + write_pte(pte_addr, pte_bytes); + } + + //Read second level PTE. + pte_addr = (ppn_1 << 12) + (vpn_0 * PTE_SIZE); + pte_bytes = read_pte(pte_addr); + std::cout << "got pte: " << std::hex << pte_bytes << std::endl; + + if ( bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) + { + std::cout << "ERROR, shouldn't be here" << std::endl; + //If valid bit is set, then the page is already allocated. + //Should not reach this point, a sanity check. + } + else + { + //If valid bit not set, write ppn of pAddr in PTE. Set rwx = 111 in PTE + //to indicate this is a leaf PTE and has the stated permissions. + pte_bytes = ( (pAddr << 10) | 0b0000001111) ; + write_pte(pte_addr, pte_bytes); + + //If super paging is enabled. + if (SUPER_PAGING) + { + //Check if this second level Page Table can be promoted to a super page. Brute force + //method is used to iterate over all PTE entries of the table and check if they have + //their valid bit set. + bool superpage = true; + for(int i = 0; i < 1024; i++) + { + pte_addr = (ppn_1 << 12) + (i * PTE_SIZE); + pte_bytes = read_pte(pte_addr); + + if (!bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) + { + superpage = false; + break; + } + } + if (superpage) + { + //This can be promoted to a super page. Set root PTE to the first PTE of the + //second level. This is because the first PTE of the second level already has the + //correct PPN1, PPN0 set to zero and correct access bits. + pte_addr = (ppn_1 << 12); + pte_bytes = read_pte(pte_addr); + pte_addr = (get_ptbr() << 12) + (vpn_1 * PTE_SIZE); + write_pte(pte_addr, pte_bytes); + } + } + } + } + + std::pair page_table_walk(uint64_t vAddr_bits, uint64_t* size_bits) + { + uint64_t LEVELS = 2; + vAddr_SV32_t vAddr(vAddr_bits); + uint64_t pte_bytes; + + std::cout << "PTW on vAddr: 0x" << std::hex << vAddr_bits << std::endl; + + //Get base page table. + uint64_t a = this->processor_.get_satp() << 12; + std::cout << "PTW SATP: 0x" << a << std::endl; + int i = LEVELS - 1; + + while(true) + { + + //Read PTE. + std::cout << "reading PTE from RAM addr 0x" << std::hex << (a+vAddr.vpn[i]*PTE_SIZE) << std::endl; + ram_.read(&pte_bytes, a+vAddr.vpn[i]*PTE_SIZE, sizeof(uint64_t)); + //pte_bytes &= 0x00000000FFFFFFFF; + PTE_SV32_t pte(pte_bytes); + std::cout << "got pte: " << std::hex << pte_bytes << std::endl; + + //Check if it has invalid flag bits. + if ( (pte.v == 0) | ( (pte.r == 0) & (pte.w == 1) ) ) + { + std::cout << "Error on vAddr 0x" << std::hex << vAddr_bits << std::endl; + throw Page_Fault_Exception("Page Fault : Attempted to access invalid entry. Entry: 0x"); + } + + if ( (pte.r == 0) & (pte.w == 0) & (pte.x == 0)) + { + //Not a leaf node as rwx == 000 + i--; + if (i < 0) + { + throw Page_Fault_Exception("Page Fault : No leaf node found."); + } + else + { + //Continue on to next level. + a = (pte_bytes >> 10 ) << 12; + std::cout << "next a: " << a << std::endl; + } + } + else + { + //Leaf node found, finished walking. + a = (pte_bytes >> 10 ) << 12; + break; + } + } + + PTE_SV32_t pte(pte_bytes); + + //Check RWX permissions according to access type. + if (pte.r == 0) + { + throw Page_Fault_Exception("Page Fault : TYPE LOAD, Incorrect permissions."); + } + + uint64_t pfn; + if (i > 0) + { + //It is a super page. + if (pte.ppn[0] != 0) + { + //Misss aligned super page. + throw Page_Fault_Exception("Page Fault : Miss Aligned Super Page."); + + } + else + { + //Valid super page. + pfn = pte.ppn[1]; + *size_bits = 22; + } + } + else + { + //Regular page. + *size_bits = 12; + pfn = a >> 12; + } + return std::make_pair(pfn, pte_bytes & 0xff); + } + + uint64_t alloc_page_table() { + uint64_t addr; + global_mem_.allocate(RAM_PAGE_SIZE, &addr); + std::cout << "address of page table 0x" << std::hex << addr << std::endl; + init_page_table(addr); + return addr; + } + + + void init_page_table(uint64_t addr) { + uint64_t asize = aligned_size(RAM_PAGE_SIZE, CACHE_BLOCK_SIZE); + uint8_t *src = new uint8_t[RAM_PAGE_SIZE]; + for (uint64_t i = 0; i < RAM_PAGE_SIZE; ++i) { + src[i] = (0x00000000 >> ((i & 0x3) * 8)) & 0xff; + } + ram_.write((const uint8_t*)src, addr, asize); + } + + void read_page_table(uint64_t addr) { + uint8_t *dest = new uint8_t[RAM_PAGE_SIZE]; + download(dest, addr, RAM_PAGE_SIZE); + printf("VXDRV: download %d bytes from 0x%x\n", RAM_PAGE_SIZE, addr); + for (int i = 0; i < RAM_PAGE_SIZE; i += 4) { + printf("mem-read: 0x%x -> 0x%x\n", addr + i, *(uint64_t*)((uint8_t*)dest + i)); + } + } + + void write_pte(uint64_t addr, uint64_t value = 0xbaadf00d) { + std::cout << "writing pte " << std::hex << value << " to pAddr: " << std::hex << addr << std::endl; + uint8_t *src = new uint8_t[PTE_SIZE]; + for (uint64_t i = 0; i < PTE_SIZE; ++i) { + src[i] = (value >> ((i & 0x3) * 8)) & 0xff; + } + //std::cout << "writing PTE to RAM addr 0x" << std::hex << addr << std::endl; + ram_.write((const uint8_t*)src, addr, PTE_SIZE); + } + + uint64_t read_pte(uint64_t addr) { + uint8_t *dest = new uint8_t[PTE_SIZE]; + std::cout << "[read_pte] reading PTE from RAM addr 0x" << std::hex << addr << std::endl; + ram_.read((uint8_t*)dest, addr, PTE_SIZE); + return *(uint64_t*)((uint8_t*)dest); + } +#endif // JAEWON + private: Arch arch_; RAM ram_; @@ -243,6 +586,9 @@ private: DeviceConfig dcrs_; std::future future_; std::unordered_map> mpm_cache_; +#ifdef VM_ENABLE + std::unordered_map addr_mapping; +#endif }; -#include \ No newline at end of file +#include diff --git a/sim/common/mem.cpp b/sim/common/mem.cpp index 92a983410..b55d0de9a 100644 --- a/sim/common/mem.cpp +++ b/sim/common/mem.cpp @@ -137,16 +137,90 @@ void MemoryUnit::ADecoder::write(const void* data, uint64_t addr, uint64_t size) MemoryUnit::MemoryUnit(uint64_t pageSize) : pageSize_(pageSize) , enableVM_(pageSize != 0) - , amo_reservation_({0x0, false}) { - if (pageSize != 0) { - tlb_[0] = TLBEntry(0, 077); + , amo_reservation_({0x0, false}) +#ifdef VM_ENABLE + , TLB_HIT(0) + , TLB_MISS(0) + , TLB_EVICT(0) + , PTW(0) {}; +#else + { + if (pageSize != 0) + { + tlb_[0] = TLBEntry(0, 077); + } } -} +#endif void MemoryUnit::attach(MemDevice &m, uint64_t start, uint64_t end) { decoder_.map(start, end, m); } +#ifdef VM_ENABLE +std::pair MemoryUnit::tlbLookup(uint64_t vAddr, ACCESS_TYPE type, uint64_t* size_bits) { + + //Find entry while accounting for different sizes. + for (auto entry : tlb_) + { + if(entry.first == vAddr >> entry.second.size_bits) + { + *size_bits = entry.second.size_bits; + vAddr = vAddr >> (*size_bits); + } + } + + + auto iter = tlb_.find(vAddr); + if (iter != tlb_.end()) { + TLBEntry e = iter->second; + + //Set mru bit if it is a hit. + iter->second.mru_bit = true; + + //If at full capacity and no other unset bits. + // Clear all bits except the one we just looked up. + if (tlb_.size() == TLB_SIZE) + { + // bool no_cleared = true; + // for (auto& entry : tlb_) + // { + // no_cleared = no_cleared & entry.second.mru_bit; + // } + + // if(no_cleared) + // { + for (auto& entry : tlb_) + { + entry.second.mru_bit = false; + } + iter->second.mru_bit = true; + //} + + } + //Check access permissions. + if ( (type == ACCESS_TYPE::FETCH) & ((e.r == 0) | (e.x == 0)) ) + { + throw Page_Fault_Exception("Page Fault : Incorrect permissions."); + } + else if ( (type == ACCESS_TYPE::LOAD) & (e.r == 0) ) + { + throw Page_Fault_Exception("Page Fault : Incorrect permissions."); + } + else if ( (type == ACCESS_TYPE::STORE) & (e.w == 0) ) + { + throw Page_Fault_Exception("Page Fault : Incorrect permissions."); + } + else + { + //TLB Hit + return std::make_pair(true, iter->second.pfn); + } + } else { + //TLB Miss + return std::make_pair(false, 0); + } +} +#endif //JAEWON MemoryUnit::TLBEntry MemoryUnit::tlbLookup(uint64_t vAddr, uint32_t flagMask) { auto iter = tlb_.find(vAddr / pageSize_); if (iter != tlb_.end()) { @@ -171,16 +245,40 @@ uint64_t MemoryUnit::toPhyAddr(uint64_t addr, uint32_t flagMask) { return pAddr; } -void MemoryUnit::read(void* data, uint64_t addr, uint64_t size, bool sup, ACCESS_TYPE type) { +#ifdef VM_ENABLE +void MemoryUnit::read(void* data, uint64_t addr, uint64_t size, ACCESS_TYPE type) { + uint64_t pAddr; + if (this->mode == VA_MODE::BARE) { + pAddr = addr; + } else { + pAddr = vAddr_to_pAddr(addr, type); + } + return decoder_.read(data, pAddr, size); +} +#else +void MemoryUnit::read(void* data, uint64_t addr, uint64_t size, bool sup) { uint64_t pAddr = this->toPhyAddr(addr, sup ? 8 : 1); return decoder_.read(data, pAddr, size); } - -void MemoryUnit::write(const void* data, uint64_t addr, uint64_t size, bool sup, ACCESS_TYPE type) { +#endif +#ifdef VM_ENABLE +void MemoryUnit::write(const void* data, uint64_t addr, uint64_t size, ACCESS_TYPE type) { + uint64_t pAddr; + if ( (this->mode == VA_MODE::BARE) | (addr >= IO_BASE_ADDR) ) { + pAddr = addr; + } else { + pAddr = vAddr_to_pAddr(addr, type); + } + decoder_.write(data, pAddr, size); + amo_reservation_.valid = false; +} +#else +void MemoryUnit::write(const void* data, uint64_t addr, uint64_t size, bool sup) { uint64_t pAddr = this->toPhyAddr(addr, sup ? 16 : 1); decoder_.write(data, pAddr, size); amo_reservation_.valid = false; } +#endif void MemoryUnit::amo_reserve(uint64_t addr) { uint64_t pAddr = this->toPhyAddr(addr, 1); @@ -193,9 +291,8 @@ bool MemoryUnit::amo_check(uint64_t addr) { return amo_reservation_.valid && (amo_reservation_.addr == pAddr); } -void MemoryUnit::tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags) { - tlb_[virt / pageSize_] = TLBEntry(phys / pageSize_, flags); -} + +#ifdef VM_ENABLE void MemoryUnit::tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags, uint64_t size_bits) { // HW: evict TLB by Most Recently Used @@ -219,6 +316,12 @@ void MemoryUnit::tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags, uint64_t s } tlb_[virt / pageSize_] = TLBEntry(phys / pageSize_, flags, size_bits); } +#else + +void MemoryUnit::tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags) { + tlb_[virt / pageSize_] = TLBEntry(phys / pageSize_, flags); +} +#endif void MemoryUnit::tlbRm(uint64_t va) { if (tlb_.find(va / pageSize_) != tlb_.end()) @@ -472,3 +575,130 @@ void RAM::loadHexImage(const char* filename) { --size; } } + +#ifdef VM_ENABLE +uint64_t MemoryUnit::vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type) +{ + uint64_t pfn; + uint64_t size_bits; + + //First lookup TLB. + std::pair tlb_access = tlbLookup(vAddr, type, &size_bits); + if (tlb_access.first) + { + pfn = tlb_access.second; + TLB_HIT++; + } + else //Else walk the PT. + { + std::pair ptw_access = page_table_walk(vAddr, type, &size_bits); + tlbAdd(vAddr>>size_bits, ptw_access.first, ptw_access.second,size_bits); + pfn = ptw_access.first; TLB_MISS++; PTW++; + unique_translations.insert(vAddr>>size_bits); + PERF_UNIQUE_PTW = unique_translations.size(); + } + + //Construct final address using pfn and offset. + std::cout << "[MemoryUnit] translated vAddr: 0x" << std::hex << vAddr << " to pAddr: 0x" << std::hex << ((pfn << size_bits) + (vAddr & ((1 << size_bits) - 1))) << std::endl; + return (pfn << size_bits) + (vAddr & ((1 << size_bits) - 1)); +} + +std::pair MemoryUnit::page_table_walk(uint64_t vAddr_bits, ACCESS_TYPE type, uint64_t* size_bits) +{ + uint64_t LEVELS = 2; + vAddr_SV32_t vAddr(vAddr_bits); + uint64_t pte_bytes; + + //Get base page table. + uint64_t a = this->ptbr << 12; + int i = LEVELS - 1; + + while(true) + { + + //Read PTE. + decoder_.read(&pte_bytes, a+vAddr.vpn[i]*PTE_SIZE, sizeof(uint64_t)); + PTE_SV32_t pte(pte_bytes); + + //Check if it has invalid flag bits. + if ( (pte.v == 0) | ( (pte.r == 0) & (pte.w == 1) ) ) + { + throw Page_Fault_Exception("Page Fault : Attempted to access invalid entry."); + } + + if ( (pte.r == 0) & (pte.w == 0) & (pte.x == 0)) + { + //Not a leaf node as rwx == 000 + i--; + if (i < 0) + { + throw Page_Fault_Exception("Page Fault : No leaf node found."); + } + else + { + //Continue on to next level. + a = (pte_bytes >> 10 ) << 12; + } + } + else + { + //Leaf node found, finished walking. + a = (pte_bytes >> 10 ) << 12; + break; + } + } + + PTE_SV32_t pte(pte_bytes); + + //Check RWX permissions according to access type. + if ( (type == ACCESS_TYPE::FETCH) & ((pte.r == 0) | (pte.x == 0)) ) + { + throw Page_Fault_Exception("Page Fault : TYPE FETCH, Incorrect permissions."); + } + else if ( (type == ACCESS_TYPE::LOAD) & (pte.r == 0) ) + { + throw Page_Fault_Exception("Page Fault : TYPE LOAD, Incorrect permissions."); + } + else if ( (type == ACCESS_TYPE::STORE) & (pte.w == 0) ) + { + throw Page_Fault_Exception("Page Fault : TYPE STORE, Incorrect permissions."); + } + + uint64_t pfn; + if (i > 0) + { + //It is a super page. + if (pte.ppn[0] != 0) + { + //Misss aligned super page. + throw Page_Fault_Exception("Page Fault : Miss Aligned Super Page."); + + } + else + { + //Valid super page. + pfn = pte.ppn[1]; + *size_bits = 22; + } + } + else + { + //Regular page. + *size_bits = 12; + pfn = a >> 12; + } + return std::make_pair(pfn, pte_bytes & 0xff); +} + + +uint32_t MemoryUnit::get_satp() +{ + return satp; +} +void MemoryUnit::set_satp(uint32_t satp) +{ + this->satp = satp; + this->ptbr = satp & 0x003fffff; //22 bits + this->mode = satp & 0x80000000 ? VA_MODE::SV32 : VA_MODE::BARE; +} +#endif \ No newline at end of file diff --git a/sim/common/mem.h b/sim/common/mem.h index 76e2f2ae5..8477fb800 100644 --- a/sim/common/mem.h +++ b/sim/common/mem.h @@ -20,9 +20,18 @@ #include #include #include +#include "VX_config.h" +#ifdef VM_ENABLE +#include +#include +#include +#endif + namespace vortex { + +#ifdef VM_ENABLE enum VA_MODE { BARE, SV32 @@ -34,6 +43,14 @@ enum ACCESS_TYPE { FETCH }; +class Page_Fault_Exception : public std::runtime_error /* or logic_error */ +{ +public: + Page_Fault_Exception(const std::string& what = "") : std::runtime_error(what) {} + uint64_t addr; + ACCESS_TYPE type; +}; +#endif struct BadAddress {}; struct OutOfRange {}; @@ -92,34 +109,42 @@ public: PageFault(uint64_t a, bool nf) : faultAddr(a) , notFound(nf) - , access_type(ACCESS_TYPE::LOAD) + // , access_type(ACCESS_TYPE::LOAD) {} uint64_t faultAddr; bool notFound; - ACCESS_TYPE access_type; + // ACCESS_TYPE access_type; }; MemoryUnit(uint64_t pageSize = 0); void attach(MemDevice &m, uint64_t start, uint64_t end); - void read(void* data, uint64_t addr, uint64_t size, bool sup, ACCESS_TYPE type = ACCESS_TYPE::LOAD); - void write(const void* data, uint64_t addr, uint64_t size, bool sup, ACCESS_TYPE type = ACCESS_TYPE::LOAD); + +#ifdef VM_ENABLE + void read(void* data, uint64_t addr, uint64_t size, ACCESS_TYPE type = ACCESS_TYPE::LOAD); + void write(const void* data, uint64_t addr, uint64_t size, ACCESS_TYPE type = ACCESS_TYPE::STORE); +#else + void read(void* data, uint64_t addr, uint64_t size, bool sup); + void write(const void* data, uint64_t addr, uint64_t size, bool sup); +#endif void amo_reserve(uint64_t addr); bool amo_check(uint64_t addr); - void tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags); +#ifdef VM_ENABLE void tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags, uint64_t size_bits); + uint32_t get_satp(); + void set_satp(uint32_t satp); +#else + void tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags); +#endif void tlbRm(uint64_t vaddr); void tlbFlush() { tlb_.clear(); } - uint32_t get_satp(); - void set_satp(uint32_t satp); - private: struct amo_reservation_t { @@ -156,11 +181,7 @@ private: struct TLBEntry { TLBEntry() {} - TLBEntry(uint32_t pfn, uint32_t flags) - : pfn(pfn) - , flags(flags) - , mru_bit(true) - {}; + #ifdef VM_ENABLE TLBEntry(uint32_t pfn, uint32_t flags, uint64_t size_bits) : pfn(pfn) , flags(flags) @@ -182,17 +203,27 @@ private: } uint32_t pfn; - bool d, a, g, u, x, w, r, v; + uint32_t flags; bool mru_bit; uint64_t size_bits; + bool d, a, g, u, x, w, r, v; + #else + TLBEntry(uint32_t pfn, uint32_t flags) + : pfn(pfn) + , flags(flags) + {} + uint32_t pfn; uint32_t flags; + #endif }; +#ifdef VM_ENABLE std::pair tlbLookup(uint64_t vAddr, ACCESS_TYPE type, uint64_t* size_bits); uint64_t vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type); std::pair page_table_walk(uint64_t vAddr_bits, ACCESS_TYPE type, uint64_t* size_bits); +#endif TLBEntry tlbLookup(uint64_t vAddr, uint32_t flagMask); @@ -203,14 +234,17 @@ private: ADecoder decoder_; bool enableVM_; + amo_reservation_t amo_reservation_; +#ifdef VM_ENABLE + uint32_t satp; VA_MODE mode; uint32_t ptbr; std::unordered_set unique_translations; uint64_t TLB_HIT, TLB_MISS, TLB_EVICT, PTW, PERF_UNIQUE_PTW; +#endif - amo_reservation_t amo_reservation_; }; /////////////////////////////////////////////////////////////////////////////// @@ -278,6 +312,7 @@ private: bool check_acl_; }; +#ifdef VM_ENABLE class PTE_SV32_t { @@ -299,6 +334,7 @@ class PTE_SV32_t bool d, a, g, u, x, w, r, v; PTE_SV32_t(uint64_t address) : address(address) { + assert((address>> 32) == 0 && "Upper 32 bits are not zero!"); flags = bits(address,0,7); rsw = bits(address,8,9); ppn[0] = bits(address,10,19); @@ -334,10 +370,12 @@ class vAddr_SV32_t uint64_t pgoff; vAddr_SV32_t(uint64_t address) : address(address) { + assert((address>> 32) == 0 && "Upper 32 bits are not zero!"); vpn[0] = bits(address,12,21); vpn[1] = bits(address,22,31); pgoff = bits(address,0,11); } }; +#endif } // namespace vortex diff --git a/sim/simx/cluster.cpp b/sim/simx/cluster.cpp index ec5e3f2b6..0c5ff9f3f 100644 --- a/sim/simx/cluster.cpp +++ b/sim/simx/cluster.cpp @@ -106,6 +106,14 @@ void Cluster::attach_ram(RAM* ram) { } } +#ifdef VM_ENABLE +void Cluster::set_satp(uint32_t satp) { + for (auto& socket : sockets_) { + socket->set_satp(satp); + } +} +#endif + bool Cluster::running() const { for (auto& socket : sockets_) { if (socket->running()) diff --git a/sim/simx/cluster.h b/sim/simx/cluster.h index 253c54fb4..113ac04f7 100644 --- a/sim/simx/cluster.h +++ b/sim/simx/cluster.h @@ -57,6 +57,10 @@ public: void attach_ram(RAM* ram); + #ifdef VM_ENABLE + void set_satp(uint32_t satp); + #endif + bool running() const; int get_exitcode() const; diff --git a/sim/simx/core.cpp b/sim/simx/core.cpp index 75aa47670..9a134b6ca 100644 --- a/sim/simx/core.cpp +++ b/sim/simx/core.cpp @@ -428,3 +428,10 @@ bool Core::wspawn(uint32_t num_warps, Word nextPC) { void Core::attach_ram(RAM* ram) { emulator_.attach_ram(ram); } + +#ifdef VM_ENABLE +void Core::set_satp(uint32_t satp) { + emulator_.set_satp(satp); //JAEWON wit, tid??? + // emulator_.set_csr(VX_CSR_SATP,satp,0,0); //JAEWON wit, tid??? +} +#endif \ No newline at end of file diff --git a/sim/simx/core.h b/sim/simx/core.h index c0e3d5de8..c18498a52 100644 --- a/sim/simx/core.h +++ b/sim/simx/core.h @@ -26,6 +26,7 @@ #include "dispatcher.h" #include "func_unit.h" #include "mem_coalescer.h" +#include "VX_config.h" namespace vortex { @@ -98,6 +99,9 @@ public: void tick(); void attach_ram(RAM* ram); +#ifdef VM_ENABLE + void set_satp(uint32_t satp); +#endif bool running() const; diff --git a/sim/simx/emulator.cpp b/sim/simx/emulator.cpp index cd305bb0d..0214dbddd 100644 --- a/sim/simx/emulator.cpp +++ b/sim/simx/emulator.cpp @@ -269,10 +269,51 @@ bool Emulator::barrier(uint32_t bar_id, uint32_t count, uint32_t wid) { return false; } +#ifdef VM_ENABLE void Emulator::icache_read(void *data, uint64_t addr, uint32_t size) { - mmu_.read(data, addr, size, 0); + try + { + mmu_.read(data, addr, size, ACCESS_TYPE::LOAD); + } + catch (Page_Fault_Exception& page_fault) + { + std::cout<local_mem()->read(data, addr, size); + } else { + try + { + // mmu_.read(data, addr, size, 0); + mmu_.read(data, addr, size, ACCESS_TYPE::LOAD); + } + catch (Page_Fault_Exception& page_fault) + { + std::cout<= uint64_t(IO_COUT_ADDR) + && addr < (uint64_t(IO_COUT_ADDR) + IO_COUT_SIZE)) { + this->writeToStdOut(data, addr, size); + } else { + if (type == AddrType::Shared) { + core_->local_mem()->write(data, addr, size); + } else { + try + { + // mmu_.write(data, addr, size, 0); + mmu_.write(data, addr, size, ACCESS_TYPE::STORE); + } + catch (Page_Fault_Exception& page_fault) + { + std::cout<= uint64_t(IO_COUT_ADDR) @@ -298,6 +365,7 @@ void Emulator::dcache_write(const void* data, uint64_t addr, uint32_t size) { } DPH(2, "Mem Write: addr=0x" << std::hex << addr << ", data=0x" << ByteStream(data, size) << " (size=" << size << ", type=" << type << ")" << std::endl); } +#endif void Emulator::dcache_amo_reserve(uint64_t addr) { auto type = get_addr_type(addr); @@ -349,6 +417,10 @@ Word Emulator::get_csr(uint32_t addr, uint32_t tid, uint32_t wid) { auto core_perf = core_->perf_stats(); switch (addr) { case VX_CSR_SATP: +#ifdef VM_ENABLE + // return csrs_.at(wid).at(tid)[addr]; + return mmu_.get_satp(); +#endif case VX_CSR_PMPCFG0: case VX_CSR_PMPADDR0: case VX_CSR_MSTATUS: @@ -475,6 +547,12 @@ void Emulator::set_csr(uint32_t addr, Word value, uint32_t tid, uint32_t wid) { csr_mscratch_ = value; break; case VX_CSR_SATP: + #ifdef VM_ENABLE + // warps_.at(wid).fcsr = (warps_.at(wid).fcsr & ~0x1F) | (value & 0x1F); + // csrs_.at(wid).at(tid)[addr] = value; //what is wid and tid? + mmu_.set_satp(value); + break; + #endif case VX_CSR_MSTATUS: case VX_CSR_MEDELEG: case VX_CSR_MIDELEG: @@ -493,6 +571,8 @@ void Emulator::set_csr(uint32_t addr, Word value, uint32_t tid, uint32_t wid) { } } + + uint32_t Emulator::get_fpu_rm(uint32_t func3, uint32_t tid, uint32_t wid) { return (func3 == 0x7) ? this->get_csr(VX_CSR_FRM, tid, wid) : func3; } diff --git a/sim/simx/emulator.h b/sim/simx/emulator.h index de466d352..9ee42812a 100644 --- a/sim/simx/emulator.h +++ b/sim/simx/emulator.h @@ -39,6 +39,9 @@ public: void clear(); void attach_ram(RAM* ram); +#ifdef VM_ENABLE + void set_satp(uint32_t satp) ; +#endif instr_trace_t* step(); @@ -122,6 +125,9 @@ private: uint32_t ipdom_size_; Word csr_mscratch_; wspawn_t wspawn_; +#ifdef VM_ENABLE + Word ptbr_; +#endif }; } diff --git a/sim/simx/processor.cpp b/sim/simx/processor.cpp index 3807fa5e8..9644c2efb 100644 --- a/sim/simx/processor.cpp +++ b/sim/simx/processor.cpp @@ -95,6 +95,13 @@ void ProcessorImpl::attach_ram(RAM* ram) { cluster->attach_ram(ram); } } +#ifdef VM_ENABLE +void ProcessorImpl::set_satp(uint32_t satp) { + for (auto cluster : clusters_) { + cluster->set_satp(satp); + } +} +#endif void ProcessorImpl::run() { SimPlatform::instance().reset(); @@ -154,4 +161,17 @@ void Processor::run() { void Processor::dcr_write(uint32_t addr, uint32_t value) { return impl_->dcr_write(addr, value); -} \ No newline at end of file +} + +#ifdef VM_ENABLE +uint32_t Processor::get_satp() { + std::cout << "get SATP: 0x" << std::hex << this->satp << std::endl; + return this->satp; +} + +void Processor::set_satp(uint32_t satp) { + std::cout << "set SATP: 0x" << std::hex << this->satp << std::endl; + impl_->set_satp(satp); + this->satp = satp; +} +#endif diff --git a/sim/simx/processor.h b/sim/simx/processor.h index 003af6b0a..17340cf2c 100644 --- a/sim/simx/processor.h +++ b/sim/simx/processor.h @@ -14,6 +14,8 @@ #pragma once #include +#include +#include namespace vortex { @@ -31,9 +33,17 @@ public: void run(); void dcr_write(uint32_t addr, uint32_t value); +#ifdef VM_ENABLE + void set_processor_satp(VA_MODE mode); + uint32_t get_satp(); + void set_satp(uint32_t satp); +#endif private: ProcessorImpl* impl_; +#ifdef VM_ENABLE + uint32_t satp; +#endif }; } diff --git a/sim/simx/processor_impl.h b/sim/simx/processor_impl.h index dcfba84d7..e6e9a4cf1 100644 --- a/sim/simx/processor_impl.h +++ b/sim/simx/processor_impl.h @@ -39,6 +39,11 @@ public: void dcr_write(uint32_t addr, uint32_t value); +#ifdef VM_ENABLE + // 32bit satp + void set_satp(uint32_t satp); +#endif + PerfStats perf_stats() const; private: diff --git a/sim/simx/socket.cpp b/sim/simx/socket.cpp index d7e421b4b..9374bbc59 100644 --- a/sim/simx/socket.cpp +++ b/sim/simx/socket.cpp @@ -107,6 +107,14 @@ void Socket::attach_ram(RAM* ram) { } } +#ifdef VM_ENABLE +void Socket::set_satp(uint32_t satp) { + for (auto core : cores_) { + core->set_satp(satp); + } +} +#endif + bool Socket::running() const { for (auto& core : cores_) { if (core->running()) diff --git a/sim/simx/socket.h b/sim/simx/socket.h index ed38dce67..a09f73e8b 100644 --- a/sim/simx/socket.h +++ b/sim/simx/socket.h @@ -60,6 +60,10 @@ public: void attach_ram(RAM* ram); +#ifdef VM_ENABLE + void set_satp(uint32_t satp); +#endif + bool running() const; int get_exitcode() const; From 53c547f9de0d97e5c543f71bab728a89b785413f Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Thu, 13 Jun 2024 11:30:54 -0400 Subject: [PATCH 37/75] Change the declaration of set_processor_satp function --- runtime/simx/vortex.cpp | 21 +++++++++++++-------- sim/simx/processor.h | 1 - 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 6e5cafc38..2d1168179 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -75,8 +75,8 @@ public: // attach memory module processor_.attach_ram(&ram_); #ifdef VM_ENABLE - //Set - processor_.set_processor_satp(VM_ADDR_MODE); + //Set + set_processor_satp(VM_ADDR_MODE); #endif } @@ -133,13 +133,13 @@ public: bool is_pc = false; std::cout << "startup addr: " << std::hex << STARTUP_ADDR << std::endl; std::cout << "bit mode: " << std::dec << XLEN << std::endl; + if (get_mode() == VA_MODE::BARE) + return 0; + if (*dev_maddr == STARTUP_ADDR || *dev_maddr == 0x7FFFF000) { is_pc = true; } - if (get_mode() == VA_MODE::BARE) - return 0; - uint64_t ppn = *dev_maddr >> 12; uint64_t init_pAddr = *dev_maddr; uint64_t init_vAddr = *dev_maddr + 0xf0000000; // vpn will change, but we want to return the vpn of the beginning of the virtual allocation @@ -188,9 +188,10 @@ public: return err; }); #ifdef VM_ENABLE - // VM address translation std::cout << "physical addr: " << std::hex << *dev_addr << std::endl; + // VM address translation map_local_mem(size, dev_addr); + std::cout << "virtual addr: " << std::hex << *dev_addr << std::endl; #endif *dev_addr = addr; return 0; @@ -342,7 +343,7 @@ public: #ifdef VM_ENABLE /* VM Management */ - void set_processor_satp(VA_MODE mode) + void set_processor_satp(VA_MODE mode) { uint32_t satp; if (mode == VA_MODE::BARE) @@ -546,9 +547,11 @@ public: uint64_t asize = aligned_size(RAM_PAGE_SIZE, CACHE_BLOCK_SIZE); uint8_t *src = new uint8_t[RAM_PAGE_SIZE]; for (uint64_t i = 0; i < RAM_PAGE_SIZE; ++i) { - src[i] = (0x00000000 >> ((i & 0x3) * 8)) & 0xff; + src[i] = (0x00000000 >> ((i & 0x3) << 3)) & 0xff; } + ram_.enable_acl(false); ram_.write((const uint8_t*)src, addr, asize); + ram_.enable_acl(true); } void read_page_table(uint64_t addr) { @@ -567,7 +570,9 @@ public: src[i] = (value >> ((i & 0x3) * 8)) & 0xff; } //std::cout << "writing PTE to RAM addr 0x" << std::hex << addr << std::endl; + ram_.enable_acl(false); ram_.write((const uint8_t*)src, addr, PTE_SIZE); + ram_.enable_acl(true); } uint64_t read_pte(uint64_t addr) { diff --git a/sim/simx/processor.h b/sim/simx/processor.h index 17340cf2c..e22f11569 100644 --- a/sim/simx/processor.h +++ b/sim/simx/processor.h @@ -34,7 +34,6 @@ public: void dcr_write(uint32_t addr, uint32_t value); #ifdef VM_ENABLE - void set_processor_satp(VA_MODE mode); uint32_t get_satp(); void set_satp(uint32_t satp); #endif From 7b80da25382e8e4e23f0d6335b714ea752f7c918 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Fri, 14 Jun 2024 17:03:43 -0400 Subject: [PATCH 38/75] Update upload and download function in simx runtime --- hw/rtl/VX_config.vh | 52 ++++--- runtime/simx/vortex.cpp | 299 ++++++++++++++++++++++------------------ sim/simx/processor.cpp | 2 +- 3 files changed, 194 insertions(+), 159 deletions(-) diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index a73de1d10..55ad0f113 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -14,27 +14,6 @@ `ifndef VX_CONFIG_VH `define VX_CONFIG_VH -`ifndef VM_DISABLE -`define VM_ENABLE -`endif -`ifdef VM_ENABLE - `ifndef VM_ADDR_MODE - `define VM_ADDR_MODE SV32 - `endif - - `ifndef PTE_SIZE - `define PTE_SIZE 8 - `endif - - `ifndef TLB_SIZE - `define TLB_SIZE 32 - `endif - - `ifndef SUPER_PAGING - `define SUPER_PAGING 0 - `endif - -`endif `ifndef MIN @@ -274,6 +253,37 @@ `define DEBUG_LEVEL 3 `endif +// Virtual Memory Configuration /////////////////////////////////////////////////////// +`ifndef VM_DISABLE +`define VM_ENABLE +`endif +`ifdef VM_ENABLE + `ifndef VM_ADDR_MODE + `define VM_ADDR_MODE SV32 + `endif + + `ifndef PTE_SIZE + `ifdef XLEN_32 + `define PTE_SIZE 4 + `else + `ifdef XLEN_64 + `define PTE_SIZE 8 + `else + `define PTE_SIZE 8 + `endif + `endif + `endif + + `ifndef TLB_SIZE + `define TLB_SIZE 32 + `endif + + `ifndef SUPER_PAGING + `define SUPER_PAGING 0 + `endif + +`endif + // Pipeline Configuration ///////////////////////////////////////////////////// // Issue width diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 2d1168179..64ba1653d 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -27,6 +27,26 @@ #include #include +#ifdef VM_ENABLE +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#endif + using namespace vortex; #ifdef VM_ENABLE @@ -128,32 +148,37 @@ public: #ifdef VM_ENABLE // VM SUPPORT - uint64_t map_local_mem(uint64_t size, uint64_t* dev_maddr) + uint64_t map_local_mem(uint64_t size, uint64_t* dev_pAddr) { - bool is_pc = false; - std::cout << "startup addr: " << std::hex << STARTUP_ADDR << std::endl; + bool no_trans = false; + std::cout << __PRETTY_FUNCTION__ << std::endl; + // std::cout << "startup addr: 0x" << std::hex << STARTUP_ADDR << std::endl; + std::cout << "Input device physical addr: 0x" << std::hex << *dev_pAddr<< std::endl; std::cout << "bit mode: " << std::dec << XLEN << std::endl; - if (get_mode() == VA_MODE::BARE) - return 0; - if (*dev_maddr == STARTUP_ADDR || *dev_maddr == 0x7FFFF000) { - is_pc = true; + // if (*dev_pAddr == STARTUP_ADDR || *dev_pAddr == 0x7FFFF000) { + if (*dev_pAddr >= 0xF0000000 ) + no_trans = true; } - uint64_t ppn = *dev_maddr >> 12; - uint64_t init_pAddr = *dev_maddr; - uint64_t init_vAddr = *dev_maddr + 0xf0000000; // vpn will change, but we want to return the vpn of the beginning of the virtual allocation - init_vAddr = (init_vAddr >> 12) << 12; - uint64_t vpn; + if (get_mode() == VA_MODE::BARE || no_trans == true) + { + std::cout << "No Translation is needed." << std::endl; + return 0; + } - //dev_maddr can be of size greater than a page, but we have to map and update + uint64_t init_pAddr = *dev_pAddr; + uint64_t init_vAddr = *dev_pAddr + 0xf000000; // vpn will change, but we want to return the vpn of the beginning of the virtual allocation + uint64_t ppn = 0, vpn = 0 ; + + + //dev_pAddr can be of size greater than a page, but we have to map and update //page tables on a page table granularity. So divide the allocation into pages. - for (ppn = (*dev_maddr) >> 12; ppn < ((*dev_maddr) >> 12) + (size/RAM_PAGE_SIZE) + 1; ppn++) + for (ppn = (*dev_pAddr) >> 12; ppn < ((*dev_pAddr) >> 12) + (size/RAM_PAGE_SIZE) + 1; ppn++) { //Currently a 1-1 mapping is used, this can be changed here to support different //mapping schemes - vpn = is_pc ? ppn : ppn + 0xf0000; - //vpn = ppn; + vpn = ppn + (0xf000000 >> 12); //If ppn to vpn mapping doesnt exist. if (addr_mapping.find(vpn) == addr_mapping.end()) @@ -164,21 +189,23 @@ public: } } - std::cout << "mapped virtual addr: " << init_vAddr << " to physical addr: " << init_pAddr << std::endl; - uint64_t size_bits; - if (is_pc) { - std::cout << "not returning virtual address because it is PC or stack" << std::endl; - std::pair ptw_access = page_table_walk(init_vAddr - 0xf0000000, &size_bits); - return 0; - } else { - std::pair ptw_access = page_table_walk(init_vAddr, &size_bits); + std::cout << "Mapped virtual addr: " << init_vAddr << " to physical addr: " << init_pAddr << std::endl; + // sanity check + uint64_t pAddr = page_table_walk(init_vAddr); + if (pAddr != init_pAddr) + { + std::cout << "ERROR" << pAddr << "and" << init_pAddr << " is not the same" < GLOBAL_MEM_SIZE) - return -1; - + int upload(uint64_t dest_addr, const void* src, uint64_t size) { + std::cout << __PRETTY_FUNCTION__ << std::endl; + uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); + if (dest_addr + asize > GLOBAL_MEM_SIZE) + return -1; #ifdef VM_ENABLE - uint64_t pAddr = dest_addr; // map_local_mem overwrites the provided dest_addr, so store away physical destination address - if (dest_addr >= STARTUP_ADDR) { - map_local_mem(asize,&dest_addr); - } else if (dest_addr >= 0x7fff0000) - { - map_local_mem(asize,&dest_addr); - } - std::cout << "uploading to 0x" << pAddr << "(VA)" << std::endl; - dest_addr = pAddr; + uint64_t pAddr = page_table_walk(dest_addr); + std::cout << "== Upload data to vAddr = 0x" << std::hex < GLOBAL_MEM_SIZE) return -1; +#ifdef VM_ENABLE + uint64_t pAddr = page_table_walk(src_addr); + std::cout << "== Download data to vAddr = 0x" << std::hex <> 10) | 0x80000000; - // satp = 0xFEBFE000 ; + satp = (alloc_first_level_page_table() >> 12) | 0x80000000; } processor_.set_satp(satp); } @@ -365,22 +391,23 @@ public: VA_MODE get_mode() { return processor_.get_satp() & 0x80000000 ? VA_MODE::SV32 : VA_MODE::BARE; - // return VA_MODE::SV32; } - void update_page_table(uint64_t pAddr, uint64_t vAddr) { - std::cout << "mapping vpn: " << vAddr << " to ppn:" << pAddr << std::endl; + void update_page_table(uint64_t ppn, uint64_t vpn) { + std::cout << __PRETTY_FUNCTION__ << std::endl; + std::cout << "mapping vpn: " << std::hex << vpn << " to ppn:" << ppn << std::endl; //Updating page table with the following mapping of (vAddr) to (pAddr). + // uint32_t page_bit_shift = log2ceil(PTE_SIZE*NUM_PTE_ENTRY); + uint32_t page_bit_shift = 12; uint64_t ppn_1, pte_addr, pte_bytes; - uint64_t vpn_1 = bits(vAddr, 10, 19); - uint64_t vpn_0 = bits(vAddr, 0, 9); + uint64_t vpn_1 = bits(vpn, 10, 19); + uint64_t vpn_0 = bits(vpn, 0, 9); //Read first level PTE. pte_addr = (get_ptbr() << 12) + (vpn_1 * PTE_SIZE); pte_bytes = read_pte(pte_addr); std::cout << "[PTE] addr 0x" << std::hex << pte_addr << ", PTE 0x" << std::hex << pte_bytes << std::endl; - if ( bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) { //If valid bit set, proceed to next level using new ppn form PTE. @@ -392,13 +419,14 @@ public: //If valid bit not set, allocate a second level page table // in device memory and store ppn in PTE. Set rwx = 000 in PTE //to indicate this is a pointer to the next level of the page table. - ppn_1 = (alloc_page_table() >> 12); - pte_bytes = ( (ppn_1 << 10) | 0b0000000001) ; + std::cout << "PTE invalid, get second page table..." << std::endl; + ppn_1 = (alloc_second_level_page_table() >> 12); + pte_bytes = ((ppn_1 << 10) | 0b0000000001) ; write_pte(pte_addr, pte_bytes); } //Read second level PTE. - pte_addr = (ppn_1 << 12) + (vpn_0 * PTE_SIZE); + pte_addr = (ppn_1 << page_bit_shift) + (vpn_0 * PTE_SIZE); pte_bytes = read_pte(pte_addr); std::cout << "got pte: " << std::hex << pte_bytes << std::endl; @@ -412,10 +440,11 @@ public: { //If valid bit not set, write ppn of pAddr in PTE. Set rwx = 111 in PTE //to indicate this is a leaf PTE and has the stated permissions. - pte_bytes = ( (pAddr << 10) | 0b0000001111) ; + pte_bytes = ( (ppn << 10) | 0b0000001111) ; write_pte(pte_addr, pte_bytes); //If super paging is enabled. + /* if (SUPER_PAGING) { //Check if this second level Page Table can be promoted to a super page. Brute force @@ -444,130 +473,118 @@ public: write_pte(pte_addr, pte_bytes); } } + */ } } - std::pair page_table_walk(uint64_t vAddr_bits, uint64_t* size_bits) + uint64_t page_table_walk(uint64_t vAddr_bits) { + + std::cout << "PTW on vAddr: 0x" << std::hex << vAddr_bits << std::endl; uint64_t LEVELS = 2; vAddr_SV32_t vAddr(vAddr_bits); - uint64_t pte_bytes; + uint64_t pte_addr, pte_bytes; + uint64_t pt_ba = get_ptbr() << 12; - std::cout << "PTW on vAddr: 0x" << std::hex << vAddr_bits << std::endl; //Get base page table. - uint64_t a = this->processor_.get_satp() << 12; - std::cout << "PTW SATP: 0x" << a << std::endl; - int i = LEVELS - 1; - while(true) + for ( i = LEVELS-1 ; i >= 0 ; i--) { - - //Read PTE. - std::cout << "reading PTE from RAM addr 0x" << std::hex << (a+vAddr.vpn[i]*PTE_SIZE) << std::endl; - ram_.read(&pte_bytes, a+vAddr.vpn[i]*PTE_SIZE, sizeof(uint64_t)); - //pte_bytes &= 0x00000000FFFFFFFF; - PTE_SV32_t pte(pte_bytes); - std::cout << "got pte: " << std::hex << pte_bytes << std::endl; - - //Check if it has invalid flag bits. - if ( (pte.v == 0) | ( (pte.r == 0) & (pte.w == 1) ) ) - { - std::cout << "Error on vAddr 0x" << std::hex << vAddr_bits << std::endl; - throw Page_Fault_Exception("Page Fault : Attempted to access invalid entry. Entry: 0x"); - } - - if ( (pte.r == 0) & (pte.w == 0) & (pte.x == 0)) - { - //Not a leaf node as rwx == 000 - i--; - if (i < 0) + //Read PTE. + pte_addr = pt_ba+vAddr.vpn[i]*PTE_SIZE; + std::cout << "reading PTE from RAM addr 0x" << std::hex << (pte_addr) << std::endl; + pte_bytes = read_pte(pte_addr); + pte_bytes &= 0x00000000FFFFFFFF; // Only for 32 bit + PTE_SV32_t pte(pte_bytes); + std::cout << "got pte: " << std::hex << pte_bytes << std::endl; + + //Check if it has invalid flag bits. + if ( (pte.v == 0) | ( (pte.r == 0) & (pte.w == 1) ) ) { - throw Page_Fault_Exception("Page Fault : No leaf node found."); + std::cout << "Error on vAddr 0x" << std::hex << vAddr_bits << std::endl; + throw Page_Fault_Exception("Page Fault : Attempted to access invalid entry. Entry: 0x"); + } + + if ( (pte.r == 0) & (pte.w == 0) & (pte.x == 0)) + { + //Not a leaf node as rwx == 000 + if (i == 0) + throw Page_Fault_Exception("Page Fault : No leaf node found."); + else + { + //Continue on to next level. + pt_ba = (pte_bytes >> 10 ) << 12; + std::cout << "next pt_ba: " << pt_ba << std::endl; + } } else { - //Continue on to next level. - a = (pte_bytes >> 10 ) << 12; - std::cout << "next a: " << a << std::endl; + //Leaf node found, finished walking. + pt_ba = (pte_bytes >> 10 ) << 12; + std::cout << "Found PPN 0 = 0x" << pt_ba << std::endl; + break; } - } - else - { - //Leaf node found, finished walking. - a = (pte_bytes >> 10 ) << 12; - break; - } + } + // pte_bytes is final leaf PTE_SV32_t pte(pte_bytes); - //Check RWX permissions according to access type. if (pte.r == 0) { - throw Page_Fault_Exception("Page Fault : TYPE LOAD, Incorrect permissions."); + throw Page_Fault_Exception("Page Fault : TYPE LOAD, Incorrect permissions."); } - - uint64_t pfn; - if (i > 0) - { - //It is a super page. - if (pte.ppn[0] != 0) - { - //Misss aligned super page. - throw Page_Fault_Exception("Page Fault : Miss Aligned Super Page."); - - } - else - { - //Valid super page. - pfn = pte.ppn[1]; - *size_bits = 22; - } - } - else - { //Regular page. - *size_bits = 12; - pfn = a >> 12; - } - return std::make_pair(pfn, pte_bytes & 0xff); + + uint64_t paddr = pt_ba << 12 + vAddr.pgoff; + return paddr } - uint64_t alloc_page_table() { - uint64_t addr; - global_mem_.allocate(RAM_PAGE_SIZE, &addr); + uint64_t alloc_first_level_page_table() { + uint64_t addr=0xF0000000; + uint64_t size=1<<23; + CHECK_ERR(this->mem_reserve(addr, size, VX_MEM_READ_WRITE), { + return err; + }); + // global_mem_.allocate(RAM_PAGE_SIZE, &addr); + std::cout << "address of page table 0x" << std::hex << addr << std::endl; + init_page_table(addr,size); + return addr; + } + uint64_t alloc_second_level_page_table(uint64_t vpn_1) { + uint64_t addr = 0xF0000000 + PTE_SIZE * NUM_PTE_ENTRY*(1+vpn_1) std::cout << "address of page table 0x" << std::hex << addr << std::endl; - init_page_table(addr); return addr; } - - void init_page_table(uint64_t addr) { - uint64_t asize = aligned_size(RAM_PAGE_SIZE, CACHE_BLOCK_SIZE); + void init_page_table(uint64_t addr, uint64_t size) { + // uint64_t asize = aligned_size(RAM_PAGE_SIZE, CACHE_BLOCK_SIZE); + uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); uint8_t *src = new uint8_t[RAM_PAGE_SIZE]; for (uint64_t i = 0; i < RAM_PAGE_SIZE; ++i) { - src[i] = (0x00000000 >> ((i & 0x3) << 3)) & 0xff; + // src[i] = (value >> (i << 3)) & 0xff; + src[i] = 0; } ram_.enable_acl(false); ram_.write((const uint8_t*)src, addr, asize); ram_.enable_acl(true); } - void read_page_table(uint64_t addr) { - uint8_t *dest = new uint8_t[RAM_PAGE_SIZE]; - download(dest, addr, RAM_PAGE_SIZE); - printf("VXDRV: download %d bytes from 0x%x\n", RAM_PAGE_SIZE, addr); - for (int i = 0; i < RAM_PAGE_SIZE; i += 4) { - printf("mem-read: 0x%x -> 0x%x\n", addr + i, *(uint64_t*)((uint8_t*)dest + i)); - } - } + // void read_page_table(uint64_t addr) { + // uint8_t *dest = new uint8_t[RAM_PAGE_SIZE]; + // download(dest, addr, RAM_PAGE_SIZE); + // printf("VXDRV: download %d bytes from 0x%x\n", RAM_PAGE_SIZE, addr); + // for (int i = 0; i < RAM_PAGE_SIZE; i += 4) { + // printf("mem-read: 0x%x -> 0x%x\n", addr + i, *(uint64_t*)((uint8_t*)dest + i)); + // } + // } void write_pte(uint64_t addr, uint64_t value = 0xbaadf00d) { - std::cout << "writing pte " << std::hex << value << " to pAddr: " << std::hex << addr << std::endl; + std::cout << "writing pte 0x" << std::hex << value << " to pAddr: 0x" << std::hex << addr << std::endl; uint8_t *src = new uint8_t[PTE_SIZE]; for (uint64_t i = 0; i < PTE_SIZE; ++i) { - src[i] = (value >> ((i & 0x3) * 8)) & 0xff; + src[i] = (value >> (i << 3)) & 0xff; } //std::cout << "writing PTE to RAM addr 0x" << std::hex << addr << std::endl; ram_.enable_acl(false); @@ -577,9 +594,17 @@ public: uint64_t read_pte(uint64_t addr) { uint8_t *dest = new uint8_t[PTE_SIZE]; + uint64_t mask = 0; + if (XLEN == 32) + mask = 0xFFFFFFFF; + else if (XLEN == 64) + mask = 0xFFFFFFFFFFFFFFFF; + else + assert(0, "XLEN is not either 32 or 64") + std::cout << "[read_pte] reading PTE from RAM addr 0x" << std::hex << addr << std::endl; ram_.read((uint8_t*)dest, addr, PTE_SIZE); - return *(uint64_t*)((uint8_t*)dest); + return (*(uint64_t*)((uint8_t*)dest)) & mask; } #endif // JAEWON diff --git a/sim/simx/processor.cpp b/sim/simx/processor.cpp index 9644c2efb..ecc1474e1 100644 --- a/sim/simx/processor.cpp +++ b/sim/simx/processor.cpp @@ -165,7 +165,7 @@ void Processor::dcr_write(uint32_t addr, uint32_t value) { #ifdef VM_ENABLE uint32_t Processor::get_satp() { - std::cout << "get SATP: 0x" << std::hex << this->satp << std::endl; + // std::cout << "get SATP: 0x" << std::hex << this->satp << std::endl; return this->satp; } From da9c51aa3f3f5655b4c08d79e5b6a2e87d5d72fb Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Sun, 16 Jun 2024 19:05:38 -0400 Subject: [PATCH 39/75] Virtual Memory Support --- hw/rtl/VX_config.vh | 22 ++- runtime/simx/vortex.cpp | 299 ++++++++++++++++++++++------------------ sim/common/mem.cpp | 116 ++++++++++------ sim/common/mem.h | 25 ++-- sim/simx/emulator.cpp | 4 + sim/simx/processor.cpp | 1 - 6 files changed, 275 insertions(+), 192 deletions(-) diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index 55ad0f113..6d3738489 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -171,7 +171,15 @@ `define IO_BASE_ADDR 64'h000000040 `endif -`else +`ifndef PAGE_TABLE_BASE_ADDR +`define PAGE_TABLE_BASE_ADDR 64'h1F0000000 +`endif + +`ifndef PAGE_TABLE_SIZE +`define PAGE_TABLE_SIZE 4096 +`endif + +`else # XLEN_32 `ifndef STACK_BASE_ADDR `define STACK_BASE_ADDR 32'hFFFF0000 @@ -189,6 +197,14 @@ `define IO_BASE_ADDR 32'h00000040 `endif +`ifndef PAGE_TABLE_BASE_ADDR +`define PAGE_TABLE_BASE_ADDR 32'hF0000000 +`endif + +`ifndef PAGE_TABLE_SIZE +`define PAGE_TABLE_SIZE 4096 +`endif + `endif `define IO_END_ADDR `USER_BASE_ADDR @@ -265,13 +281,17 @@ `ifndef PTE_SIZE `ifdef XLEN_32 `define PTE_SIZE 4 + `define NUM_PTE_ENTRY 1024 `else `ifdef XLEN_64 `define PTE_SIZE 8 + `define NUM_PTE_ENTRY 1024 `else `define PTE_SIZE 8 + `define NUM_PTE_ENTRY 1024 `endif `endif + `define PT_SIZE (PTE_SIZE * NUM_PTE_ENTRY) `endif `ifndef TLB_SIZE diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 64ba1653d..816ca3081 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -83,17 +83,18 @@ bool bit(uint64_t addr, uint8_t idx) class vx_device { public: - vx_device() - : arch_(NUM_THREADS, NUM_WARPS, NUM_CORES) - , ram_(0, RAM_PAGE_SIZE) - , processor_(arch_) - , global_mem_(ALLOC_BASE_ADDR, - GLOBAL_MEM_SIZE - ALLOC_BASE_ADDR, - RAM_PAGE_SIZE, - CACHE_BLOCK_SIZE) - { - // attach memory module - processor_.attach_ram(&ram_); + vx_device() + : arch_(NUM_THREADS, NUM_WARPS, NUM_CORES) +#ifdef VM_ENABLE + , ram_(0, RAM_PAGE_SIZE<<11) +#else + , ram_(0, RAM_PAGE_SIZE) +#endif + , processor_(arch_) + , global_mem_(ALLOC_BASE_ADDR, GLOBAL_MEM_SIZE - ALLOC_BASE_ADDR, RAM_PAGE_SIZE, CACHE_BLOCK_SIZE) + { + // attach memory module + processor_.attach_ram(&ram_); #ifdef VM_ENABLE //Set set_processor_satp(VM_ADDR_MODE); @@ -101,6 +102,9 @@ public: } ~vx_device() { +#ifdef VM_ENABLE + this->mem_free(PAGE_TABLE_BASE_ADDR); // Right position? +#endif if (future_.valid()) { future_.wait(); } @@ -147,66 +151,90 @@ public: } #ifdef VM_ENABLE - // VM SUPPORT - uint64_t map_local_mem(uint64_t size, uint64_t* dev_pAddr) + // virtual to phycial mapping + uint64_t map_p2v(uint64_t pAddr) { - bool no_trans = false; - std::cout << __PRETTY_FUNCTION__ << std::endl; - // std::cout << "startup addr: 0x" << std::hex << STARTUP_ADDR << std::endl; - std::cout << "Input device physical addr: 0x" << std::hex << *dev_pAddr<< std::endl; - std::cout << "bit mode: " << std::dec << XLEN << std::endl; + return pAddr + 0xf000000; + } + bool need_trans(uint64_t dev_pAddr) + { + // Check if the this is the BARE mode + bool isBAREMode = (get_mode() == VA_MODE::BARE); + // Check if the address is reserved + bool isReserved = (dev_pAddr >= PAGE_TABLE_BASE_ADDR); + // Check if the address falls within the startup address range + bool isStartAddress = (STARTUP_ADDR <= dev_pAddr) && (dev_pAddr <= (STARTUP_ADDR + 0x40000)); + + // Print the boolean results for debugging purposes + // printf("%p, %u, %u\n", (void *)dev_pAddr, isReserved, isStartAddress); + + // Return true if the address needs translation (i.e., it's not reserved and not a start address) + return (!isBAREMode && !isReserved && !isStartAddress); + } + + uint64_t phy_to_virt_map(uint64_t size, uint64_t* dev_pAddr, uint32_t flags) + { + // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); + DBGPRINT("(size = 0x%lx, dev_pAddr= 0x%lx, flags = 0x%x)\n", size, *dev_pAddr, flags); + DBGPRINT("bit mode: %d\n", XLEN); // if (*dev_pAddr == STARTUP_ADDR || *dev_pAddr == 0x7FFFF000) { - if (*dev_pAddr >= 0xF0000000 ) - no_trans = true; - } - if (get_mode() == VA_MODE::BARE || no_trans == true) + if (!need_trans(*dev_pAddr)) { - std::cout << "No Translation is needed." << std::endl; + DBGPRINT("Translation is not needed.\n"); return 0; } uint64_t init_pAddr = *dev_pAddr; - uint64_t init_vAddr = *dev_pAddr + 0xf000000; // vpn will change, but we want to return the vpn of the beginning of the virtual allocation + uint64_t init_vAddr = map_p2v(init_pAddr); uint64_t ppn = 0, vpn = 0 ; - //dev_pAddr can be of size greater than a page, but we have to map and update //page tables on a page table granularity. So divide the allocation into pages. + bool is_start = false; for (ppn = (*dev_pAddr) >> 12; ppn < ((*dev_pAddr) >> 12) + (size/RAM_PAGE_SIZE) + 1; ppn++) { + vpn = map_p2v(ppn << 12) >> 12; + if (is_start == false) { + DBGPRINT("**Search vpn in page table:0x%lx\n", vpn); + is_start = true; + } + else { + DBGPRINT("Next vpn: 0x%lx\n",vpn); + } + //Currently a 1-1 mapping is used, this can be changed here to support different //mapping schemes - vpn = ppn + (0xf000000 >> 12); //If ppn to vpn mapping doesnt exist. if (addr_mapping.find(vpn) == addr_mapping.end()) { //Create mapping. - update_page_table(ppn, vpn); + update_page_table(ppn, vpn, flags); addr_mapping[vpn] = ppn; } } + DBGPRINT("Mapped virtual addr: 0x%lx to physical addr: %lx\n", init_vAddr, init_pAddr); - std::cout << "Mapped virtual addr: " << init_vAddr << " to physical addr: " << init_pAddr << std::endl; - // sanity check + // Sanity check uint64_t pAddr = page_table_walk(init_vAddr); if (pAddr != init_pAddr) { - std::cout << "ERROR" << pAddr << "and" << init_pAddr << " is not the same" <mem_access(dev_addr, size, flags), { - global_mem_.release(dev_addr); - return err; - }); - return 0; - } + int mem_reserve(uint64_t dev_addr, uint64_t size, int flags) { + CHECK_ERR(global_mem_.reserve(dev_addr, size), { + return err; + }); + DBGPRINT("mem_reserve: addr: 0x%lx, size: 0x%lx\n",dev_addr, size); + CHECK_ERR(this->mem_access(dev_addr, size, flags), { + global_mem_.release(dev_addr); + return err; + }); +#ifdef VM_ENABLE + uint64_t paddr = dev_addr; + phy_to_virt_map(size, &paddr, flags); +#endif + return 0; + } - int mem_free(uint64_t dev_addr) { - return global_mem_.release(dev_addr); - } + int mem_free(uint64_t dev_addr) { +#ifdef VM_ENABLE + uint64_t pAddr = page_table_walk(dev_addr); + // VM address translation + return global_mem_.release(pAddr); +#else + return global_mem_.release(dev_addr); +#endif + } int mem_access(uint64_t dev_addr, uint64_t size, int flags) { uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); @@ -255,17 +294,13 @@ public: } int upload(uint64_t dest_addr, const void* src, uint64_t size) { - std::cout << __PRETTY_FUNCTION__ << std::endl; + // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); if (dest_addr + asize > GLOBAL_MEM_SIZE) return -1; #ifdef VM_ENABLE uint64_t pAddr = page_table_walk(dest_addr); - std::cout << "== Upload data to vAddr = 0x" << std::hex <> 12) | 0x80000000; + satp = (alloc_2nd_level_page_table() >> 12) | 0x80000000; + DBGPRINT("VA_MODE = SV32 MODE(satp = 0x%x)\n",satp); } processor_.set_satp(satp); } @@ -387,52 +427,62 @@ public: // return processor_.get_satp(); return processor_.get_satp() & 0x003fffff; } + uint64_t get_pte_address(uint64_t base_page, uint64_t vpn) + { + return (base_page << 12) + (vpn * PTE_SIZE); + } VA_MODE get_mode() { return processor_.get_satp() & 0x80000000 ? VA_MODE::SV32 : VA_MODE::BARE; } - void update_page_table(uint64_t ppn, uint64_t vpn) { - std::cout << __PRETTY_FUNCTION__ << std::endl; - std::cout << "mapping vpn: " << std::hex << vpn << " to ppn:" << ppn << std::endl; + void update_page_table(uint64_t ppn, uint64_t vpn, uint32_t flag) { + // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); + DBGPRINT("Mapping vpn 0x%05lx to ppn 0x%05lx(flags = %u)\n", vpn, ppn,flag); + assert((((ppn>> 20) == 0) && ((vpn >> 20) == 0)) && "Upper 12 bits are not zero!"); //Updating page table with the following mapping of (vAddr) to (pAddr). // uint32_t page_bit_shift = log2ceil(PTE_SIZE*NUM_PTE_ENTRY); - uint32_t page_bit_shift = 12; - uint64_t ppn_1, pte_addr, pte_bytes; + uint64_t ppn_1 = 0, pte_addr = 0, pte_bytes = 0; uint64_t vpn_1 = bits(vpn, 10, 19); uint64_t vpn_0 = bits(vpn, 0, 9); //Read first level PTE. - pte_addr = (get_ptbr() << 12) + (vpn_1 * PTE_SIZE); + DBGPRINT("Start second-level page table\n"); + pte_addr = get_pte_address(get_ptbr(), vpn_1); pte_bytes = read_pte(pte_addr); - std::cout << "[PTE] addr 0x" << std::hex << pte_addr << ", PTE 0x" << std::hex << pte_bytes << std::endl; + DBGPRINT("[PTE] addr 0x%lx, PTE 0x%lx\n", pte_addr, pte_bytes); + ppn_1 = (pte_bytes >> 10); if ( bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) { //If valid bit set, proceed to next level using new ppn form PTE. - std::cout << "PTE valid, continuing the walk..." << std::endl; - ppn_1 = (pte_bytes >> 10); + DBGPRINT("PTE valid (ppn 0x%lx), continuing the walk...\n",ppn_1); } else { //If valid bit not set, allocate a second level page table // in device memory and store ppn in PTE. Set rwx = 000 in PTE //to indicate this is a pointer to the next level of the page table. - std::cout << "PTE invalid, get second page table..." << std::endl; - ppn_1 = (alloc_second_level_page_table() >> 12); + DBGPRINT("PTE Invalid (ppn 0x%lx), continuing the walk...\n",ppn_1); + ppn_1 = (alloc_1st_level_page_table(vpn_1) >> 12); pte_bytes = ((ppn_1 << 10) | 0b0000000001) ; + assert((pte_addr>> 32) == 0 && "Upper 32 bits are not zero!"); write_pte(pte_addr, pte_bytes); + // if (pte_bytes != read_pte(pte_addr)) + // DBGPRINT("Read/write values are different!\n"); } + + DBGPRINT("Move to first-level page table\n"); //Read second level PTE. - pte_addr = (ppn_1 << page_bit_shift) + (vpn_0 * PTE_SIZE); + pte_addr = get_pte_address(ppn_1, vpn_0); pte_bytes = read_pte(pte_addr); - std::cout << "got pte: " << std::hex << pte_bytes << std::endl; if ( bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) { - std::cout << "ERROR, shouldn't be here" << std::endl; + DBGPRINT("ERROR, shouldn't be here\n"); + exit(1); //If valid bit is set, then the page is already allocated. //Should not reach this point, a sanity check. } @@ -442,87 +492,62 @@ public: //to indicate this is a leaf PTE and has the stated permissions. pte_bytes = ( (ppn << 10) | 0b0000001111) ; write_pte(pte_addr, pte_bytes); - - //If super paging is enabled. - /* - if (SUPER_PAGING) - { - //Check if this second level Page Table can be promoted to a super page. Brute force - //method is used to iterate over all PTE entries of the table and check if they have - //their valid bit set. - bool superpage = true; - for(int i = 0; i < 1024; i++) - { - pte_addr = (ppn_1 << 12) + (i * PTE_SIZE); - pte_bytes = read_pte(pte_addr); - - if (!bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) - { - superpage = false; - break; - } - } - if (superpage) - { - //This can be promoted to a super page. Set root PTE to the first PTE of the - //second level. This is because the first PTE of the second level already has the - //correct PPN1, PPN0 set to zero and correct access bits. - pte_addr = (ppn_1 << 12); - pte_bytes = read_pte(pte_addr); - pte_addr = (get_ptbr() << 12) + (vpn_1 * PTE_SIZE); - write_pte(pte_addr, pte_bytes); - } - } - */ + if (pte_bytes != read_pte(pte_addr)) + DBGPRINT("Read/write values are different!\n"); } } uint64_t page_table_walk(uint64_t vAddr_bits) { - - std::cout << "PTW on vAddr: 0x" << std::hex << vAddr_bits << std::endl; + // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); + DBGPRINT("PTW on vAddr: 0x%lx\n", vAddr_bits); + if (!need_trans(vAddr_bits)) + { + DBGPRINT("Translation is not needed.\n"); + return vAddr_bits; + } uint64_t LEVELS = 2; vAddr_SV32_t vAddr(vAddr_bits); uint64_t pte_addr, pte_bytes; uint64_t pt_ba = get_ptbr() << 12; - //Get base page table. - for ( i = LEVELS-1 ; i >= 0 ; i--) + for ( int i = LEVELS-1 ; i >= 0 ; i--) { //Read PTE. pte_addr = pt_ba+vAddr.vpn[i]*PTE_SIZE; - std::cout << "reading PTE from RAM addr 0x" << std::hex << (pte_addr) << std::endl; pte_bytes = read_pte(pte_addr); - pte_bytes &= 0x00000000FFFFFFFF; // Only for 32 bit PTE_SV32_t pte(pte_bytes); - std::cout << "got pte: " << std::hex << pte_bytes << std::endl; + DBGPRINT("pte_bytes = 0x%lx, pte flags = %u)\n", pte.ppn , pte.flags); //Check if it has invalid flag bits. if ( (pte.v == 0) | ( (pte.r == 0) & (pte.w == 1) ) ) { - std::cout << "Error on vAddr 0x" << std::hex << vAddr_bits << std::endl; - throw Page_Fault_Exception("Page Fault : Attempted to access invalid entry. Entry: 0x"); + std::string msg= "Page Fault : Attempted to access invalid entry. Entry: 0x"; + throw Page_Fault_Exception(msg); } if ( (pte.r == 0) & (pte.w == 0) & (pte.x == 0)) { //Not a leaf node as rwx == 000 if (i == 0) + { throw Page_Fault_Exception("Page Fault : No leaf node found."); + } else { //Continue on to next level. - pt_ba = (pte_bytes >> 10 ) << 12; - std::cout << "next pt_ba: " << pt_ba << std::endl; + pt_ba = pte.ppn << 12; + DBGPRINT("next pt_ba: %p\n", (void *)pt_ba); + } } else { //Leaf node found, finished walking. - pt_ba = (pte_bytes >> 10 ) << 12; - std::cout << "Found PPN 0 = 0x" << pt_ba << std::endl; + pt_ba = pte.ppn << 12; + DBGPRINT("Found PT_Base_Address [%d] = %lx\n", i, pt_ba); break; } @@ -535,35 +560,35 @@ public: { throw Page_Fault_Exception("Page Fault : TYPE LOAD, Incorrect permissions."); } - //Regular page. - uint64_t paddr = pt_ba << 12 + vAddr.pgoff; - return paddr + uint64_t paddr = pt_ba + vAddr.pgoff; + return paddr; } - uint64_t alloc_first_level_page_table() { - uint64_t addr=0xF0000000; - uint64_t size=1<<23; + uint64_t alloc_2nd_level_page_table() { + // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); + uint64_t addr=PAGE_TABLE_BASE_ADDR; + uint64_t size=1<<23; // 8MB !!!FIXME!!! CHECK_ERR(this->mem_reserve(addr, size, VX_MEM_READ_WRITE), { return err; }); - // global_mem_.allocate(RAM_PAGE_SIZE, &addr); - std::cout << "address of page table 0x" << std::hex << addr << std::endl; - init_page_table(addr,size); + init_page_table(addr); return addr; } - uint64_t alloc_second_level_page_table(uint64_t vpn_1) { - uint64_t addr = 0xF0000000 + PTE_SIZE * NUM_PTE_ENTRY*(1+vpn_1) - std::cout << "address of page table 0x" << std::hex << addr << std::endl; + uint64_t alloc_1st_level_page_table(uint64_t vpn_1) { + // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); + uint64_t addr = PAGE_TABLE_BASE_ADDR + PTE_SIZE * NUM_PTE_ENTRY*(1+vpn_1); + init_page_table(addr); return addr; } - void init_page_table(uint64_t addr, uint64_t size) { - // uint64_t asize = aligned_size(RAM_PAGE_SIZE, CACHE_BLOCK_SIZE); - uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); + void init_page_table(uint64_t addr) { + // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); + DBGPRINT("int_page_table (addr=0x%lx)\n", addr); + uint64_t asize = aligned_size(RAM_PAGE_SIZE, CACHE_BLOCK_SIZE); + // uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); uint8_t *src = new uint8_t[RAM_PAGE_SIZE]; for (uint64_t i = 0; i < RAM_PAGE_SIZE; ++i) { - // src[i] = (value >> (i << 3)) & 0xff; src[i] = 0; } ram_.enable_acl(false); @@ -574,14 +599,14 @@ public: // void read_page_table(uint64_t addr) { // uint8_t *dest = new uint8_t[RAM_PAGE_SIZE]; // download(dest, addr, RAM_PAGE_SIZE); - // printf("VXDRV: download %d bytes from 0x%x\n", RAM_PAGE_SIZE, addr); + // DBGPRINT("VXDRV: download %d bytes from 0x%x\n", RAM_PAGE_SIZE, addr); // for (int i = 0; i < RAM_PAGE_SIZE; i += 4) { - // printf("mem-read: 0x%x -> 0x%x\n", addr + i, *(uint64_t*)((uint8_t*)dest + i)); + // DBGPRINT("mem-read: 0x%x -> 0x%x\n", addr + i, *(uint64_t*)((uint8_t*)dest + i)); // } // } void write_pte(uint64_t addr, uint64_t value = 0xbaadf00d) { - std::cout << "writing pte 0x" << std::hex << value << " to pAddr: 0x" << std::hex << addr << std::endl; + DBGPRINT("[Write_pte] writing pte 0x%lx to pAddr: 0x%lx\n", value, addr); uint8_t *src = new uint8_t[PTE_SIZE]; for (uint64_t i = 0; i < PTE_SIZE; ++i) { src[i] = (value >> (i << 3)) & 0xff; @@ -596,15 +621,17 @@ public: uint8_t *dest = new uint8_t[PTE_SIZE]; uint64_t mask = 0; if (XLEN == 32) - mask = 0xFFFFFFFF; + mask = 0x00000000FFFFFFFF; else if (XLEN == 64) mask = 0xFFFFFFFFFFFFFFFF; else - assert(0, "XLEN is not either 32 or 64") + assert(0 && "XLEN is not either 32 or 64"); - std::cout << "[read_pte] reading PTE from RAM addr 0x" << std::hex << addr << std::endl; ram_.read((uint8_t*)dest, addr, PTE_SIZE); - return (*(uint64_t*)((uint8_t*)dest)) & mask; + uint64_t ret = (*(uint64_t*)((uint8_t*)dest)) & mask; + DBGPRINT("[read_pte] reading PTE 0x%lx from RAM addr 0x%lx\n", ret, addr); + + return ret; } #endif // JAEWON diff --git a/sim/common/mem.cpp b/sim/common/mem.cpp index b55d0de9a..98eefdaf2 100644 --- a/sim/common/mem.cpp +++ b/sim/common/mem.cpp @@ -115,6 +115,7 @@ void MemoryUnit::ADecoder::map(uint64_t start, uint64_t end, MemDevice &md) { } void MemoryUnit::ADecoder::read(void* data, uint64_t addr, uint64_t size) { + // printf("====%s (addr= 0x%lx, size= 0x%lx) ====\n", __PRETTY_FUNCTION__,addr,size); mem_accessor_t ma; if (!this->lookup(addr, size, &ma)) { std::cout << "lookup of 0x" << std::hex << addr << " failed.\n"; @@ -124,6 +125,7 @@ void MemoryUnit::ADecoder::read(void* data, uint64_t addr, uint64_t size) { } void MemoryUnit::ADecoder::write(const void* data, uint64_t addr, uint64_t size) { + // printf("====%s====\n", __PRETTY_FUNCTION__); mem_accessor_t ma; if (!this->lookup(addr, size, &ma)) { std::cout << "lookup of 0x" << std::hex << addr << " failed.\n"; @@ -158,6 +160,7 @@ void MemoryUnit::attach(MemDevice &m, uint64_t start, uint64_t end) { #ifdef VM_ENABLE std::pair MemoryUnit::tlbLookup(uint64_t vAddr, ACCESS_TYPE type, uint64_t* size_bits) { + // printf("====%s====\n", __PRETTY_FUNCTION__); //Find entry while accounting for different sizes. for (auto entry : tlb_) @@ -220,7 +223,7 @@ std::pair MemoryUnit::tlbLookup(uint64_t vAddr, ACCESS_TYPE type return std::make_pair(false, 0); } } -#endif //JAEWON +#else MemoryUnit::TLBEntry MemoryUnit::tlbLookup(uint64_t vAddr, uint32_t flagMask) { auto iter = tlb_.find(vAddr / pageSize_); if (iter != tlb_.end()) { @@ -244,52 +247,62 @@ uint64_t MemoryUnit::toPhyAddr(uint64_t addr, uint32_t flagMask) { } return pAddr; } +#endif #ifdef VM_ENABLE -void MemoryUnit::read(void* data, uint64_t addr, uint64_t size, ACCESS_TYPE type) { +void MemoryUnit::read(void* data, uint64_t addr, uint32_t size, ACCESS_TYPE type) { + // printf("====%s====\n", __PRETTY_FUNCTION__); uint64_t pAddr; - if (this->mode == VA_MODE::BARE) { - pAddr = addr; - } else { - pAddr = vAddr_to_pAddr(addr, type); - } + pAddr = vAddr_to_pAddr(addr, type); return decoder_.read(data, pAddr, size); } #else -void MemoryUnit::read(void* data, uint64_t addr, uint64_t size, bool sup) { +void MemoryUnit::read(void* data, uint64_t addr, uint32_t size, bool sup) { uint64_t pAddr = this->toPhyAddr(addr, sup ? 8 : 1); return decoder_.read(data, pAddr, size); } #endif #ifdef VM_ENABLE -void MemoryUnit::write(const void* data, uint64_t addr, uint64_t size, ACCESS_TYPE type) { +void MemoryUnit::write(const void* data, uint64_t addr, uint32_t size, ACCESS_TYPE type) { + // printf("====%s====\n", __PRETTY_FUNCTION__); uint64_t pAddr; - if ( (this->mode == VA_MODE::BARE) | (addr >= IO_BASE_ADDR) ) { - pAddr = addr; - } else { - pAddr = vAddr_to_pAddr(addr, type); - } + pAddr = vAddr_to_pAddr(addr, type); decoder_.write(data, pAddr, size); amo_reservation_.valid = false; } #else -void MemoryUnit::write(const void* data, uint64_t addr, uint64_t size, bool sup) { +void MemoryUnit::write(const void* data, uint64_t addr, uint32_t size, bool sup) { uint64_t pAddr = this->toPhyAddr(addr, sup ? 16 : 1); decoder_.write(data, pAddr, size); amo_reservation_.valid = false; } #endif +#ifdef VM_ENABLE +void MemoryUnit::amo_reserve(uint64_t addr) { + uint64_t pAddr = this->vAddr_to_pAddr(addr,ACCESS_TYPE::LOAD); + amo_reservation_.addr = pAddr; + amo_reservation_.valid = true; +} +#else void MemoryUnit::amo_reserve(uint64_t addr) { uint64_t pAddr = this->toPhyAddr(addr, 1); amo_reservation_.addr = pAddr; amo_reservation_.valid = true; } +#endif +#ifdef VM_ENABLE +bool MemoryUnit::amo_check(uint64_t addr) { + uint64_t pAddr = this->vAddr_to_pAddr(addr, ACCESS_TYPE::LOAD); + return amo_reservation_.valid && (amo_reservation_.addr == pAddr); +} +#else bool MemoryUnit::amo_check(uint64_t addr) { uint64_t pAddr = this->toPhyAddr(addr, 1); return amo_reservation_.valid && (amo_reservation_.addr == pAddr); } +#endif #ifdef VM_ENABLE @@ -465,6 +478,7 @@ uint8_t *RAM::get(uint64_t address) const { } void RAM::read(void* data, uint64_t addr, uint64_t size) { + // printf("====%s (addr= 0x%lx, size= 0x%lx) ====\n", __PRETTY_FUNCTION__,addr,size); if (check_acl_ && acl_mngr_.check(addr, size, 0x1) == false) { throw BadAddress(); } @@ -577,15 +591,41 @@ void RAM::loadHexImage(const char* filename) { } #ifdef VM_ENABLE + +bool MemoryUnit::need_trans(uint64_t dev_pAddr) +{ + // Check if the this is the BARE mode + bool isBAREMode = (this->mode == VA_MODE::BARE); + // Check if the address is reserved + bool isReserved = (dev_pAddr >= PAGE_TABLE_BASE_ADDR); + // Check if the address falls within the startup address range + bool isStartAddress = (STARTUP_ADDR <= dev_pAddr) && (dev_pAddr < (STARTUP_ADDR + 0x40000)); + + // Print the boolean results for debugging purposes + // printf("0x%lx, %u, %u, %u \n", dev_pAddr,isBAREMode, isReserved, isStartAddress); + + // Return true if the address needs translation (i.e., it's not reserved and not a start address) + return (!isBAREMode && !isReserved && !isStartAddress); +} + uint64_t MemoryUnit::vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type) { uint64_t pfn; uint64_t size_bits; + // printf("====%s====\n", __PRETTY_FUNCTION__); + // printf("vaddr = 0x%lx, type = 0x%u\n",vAddr,type); + if (!need_trans(vAddr)) + { + // printf("Translation is not needed.\n"); + return vAddr; + } //First lookup TLB. std::pair tlb_access = tlbLookup(vAddr, type, &size_bits); if (tlb_access.first) { + + // printf("Found pfn %lx in TLB\n",tlb_access.second); pfn = tlb_access.second; TLB_HIT++; } @@ -596,33 +636,37 @@ uint64_t MemoryUnit::vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type) pfn = ptw_access.first; TLB_MISS++; PTW++; unique_translations.insert(vAddr>>size_bits); PERF_UNIQUE_PTW = unique_translations.size(); + } //Construct final address using pfn and offset. - std::cout << "[MemoryUnit] translated vAddr: 0x" << std::hex << vAddr << " to pAddr: 0x" << std::hex << ((pfn << size_bits) + (vAddr & ((1 << size_bits) - 1))) << std::endl; + // std::cout << "[MemoryUnit] translated vAddr: 0x" << std::hex << vAddr << " to pAddr: 0x" << std::hex << ((pfn << size_bits) + (vAddr & ((1 << size_bits) - 1))) << std::endl; return (pfn << size_bits) + (vAddr & ((1 << size_bits) - 1)); } std::pair MemoryUnit::page_table_walk(uint64_t vAddr_bits, ACCESS_TYPE type, uint64_t* size_bits) { + // printf("====%s====\n", __PRETTY_FUNCTION__); + // printf("vaddr = 0x%lx, type = %u, size_bits %lu\n", vAddr_bits, type, *size_bits); uint64_t LEVELS = 2; vAddr_SV32_t vAddr(vAddr_bits); - uint64_t pte_bytes; + uint64_t pte_bytes = 0; //Get base page table. - uint64_t a = this->ptbr << 12; + uint64_t pt_ba = this->ptbr << 12; int i = LEVELS - 1; while(true) { //Read PTE. - decoder_.read(&pte_bytes, a+vAddr.vpn[i]*PTE_SIZE, sizeof(uint64_t)); + decoder_.read(&pte_bytes, pt_ba+vAddr.vpn[i]*PTE_SIZE, PTE_SIZE); PTE_SV32_t pte(pte_bytes); //Check if it has invalid flag bits. if ( (pte.v == 0) | ( (pte.r == 0) & (pte.w == 1) ) ) { + printf("Error: PTE FLAGS=0x%x\n",pte.flags); throw Page_Fault_Exception("Page Fault : Attempted to access invalid entry."); } @@ -632,18 +676,19 @@ std::pair MemoryUnit::page_table_walk(uint64_t vAddr_bits, AC i--; if (i < 0) { + printf("Error: PTE FLAGS=0x%x\n",pte.flags); throw Page_Fault_Exception("Page Fault : No leaf node found."); } else { //Continue on to next level. - a = (pte_bytes >> 10 ) << 12; + pt_ba = (pte_bytes >> 10 ) << 12; } } else { //Leaf node found, finished walking. - a = (pte_bytes >> 10 ) << 12; + pt_ba = (pte_bytes >> 10 ) << 12; break; } } @@ -653,40 +698,21 @@ std::pair MemoryUnit::page_table_walk(uint64_t vAddr_bits, AC //Check RWX permissions according to access type. if ( (type == ACCESS_TYPE::FETCH) & ((pte.r == 0) | (pte.x == 0)) ) { + printf("Error: PTE FLAGS=0x%x\n",pte.flags); throw Page_Fault_Exception("Page Fault : TYPE FETCH, Incorrect permissions."); } else if ( (type == ACCESS_TYPE::LOAD) & (pte.r == 0) ) { + printf("Error: PTE FLAGS=0x%x\n",pte.flags); throw Page_Fault_Exception("Page Fault : TYPE LOAD, Incorrect permissions."); } else if ( (type == ACCESS_TYPE::STORE) & (pte.w == 0) ) { + printf("Error: PTE FLAGS=0x%x\n",pte.flags); throw Page_Fault_Exception("Page Fault : TYPE STORE, Incorrect permissions."); } - - uint64_t pfn; - if (i > 0) - { - //It is a super page. - if (pte.ppn[0] != 0) - { - //Misss aligned super page. - throw Page_Fault_Exception("Page Fault : Miss Aligned Super Page."); - - } - else - { - //Valid super page. - pfn = pte.ppn[1]; - *size_bits = 22; - } - } - else - { - //Regular page. - *size_bits = 12; - pfn = a >> 12; - } + *size_bits = 12; + uint64_t pfn = pt_ba >> *size_bits; return std::make_pair(pfn, pte_bytes & 0xff); } diff --git a/sim/common/mem.h b/sim/common/mem.h index 8477fb800..a655a6d3c 100644 --- a/sim/common/mem.h +++ b/sim/common/mem.h @@ -116,17 +116,21 @@ public: // ACCESS_TYPE access_type; }; +#ifdef VM_ENABLE + MemoryUnit(uint64_t pageSize = PAGE_TABLE_SIZE); +#else MemoryUnit(uint64_t pageSize = 0); +#endif void attach(MemDevice &m, uint64_t start, uint64_t end); #ifdef VM_ENABLE - void read(void* data, uint64_t addr, uint64_t size, ACCESS_TYPE type = ACCESS_TYPE::LOAD); - void write(const void* data, uint64_t addr, uint64_t size, ACCESS_TYPE type = ACCESS_TYPE::STORE); + void read(void* data, uint64_t addr, uint32_t size, ACCESS_TYPE type = ACCESS_TYPE::LOAD); + void write(const void* data, uint64_t addr, uint32_t size, ACCESS_TYPE type = ACCESS_TYPE::STORE); #else - void read(void* data, uint64_t addr, uint64_t size, bool sup); - void write(const void* data, uint64_t addr, uint64_t size, bool sup); + void read(void* data, uint64_t addr, uint32_t size, bool sup); + void write(const void* data, uint64_t addr, uint32_t size, bool sup); #endif void amo_reserve(uint64_t addr); @@ -220,14 +224,16 @@ private: #ifdef VM_ENABLE std::pair tlbLookup(uint64_t vAddr, ACCESS_TYPE type, uint64_t* size_bits); + bool need_trans(uint64_t dev_pAddr); uint64_t vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type); std::pair page_table_walk(uint64_t vAddr_bits, ACCESS_TYPE type, uint64_t* size_bits); +#else + uint64_t toPhyAddr(uint64_t vAddr, uint32_t flagMask); + TLBEntry tlbLookup(uint64_t vAddr, uint32_t flagMask); #endif - TLBEntry tlbLookup(uint64_t vAddr, uint32_t flagMask); - uint64_t toPhyAddr(uint64_t vAddr, uint32_t flagMask); std::unordered_map tlb_; uint64_t pageSize_; @@ -328,7 +334,7 @@ class PTE_SV32_t } public: - uint64_t ppn[2]; + uint64_t ppn; uint32_t rsw; uint32_t flags; bool d, a, g, u, x, w, r, v; @@ -337,8 +343,7 @@ class PTE_SV32_t assert((address>> 32) == 0 && "Upper 32 bits are not zero!"); flags = bits(address,0,7); rsw = bits(address,8,9); - ppn[0] = bits(address,10,19); - ppn[1] = bits(address,20,31); + ppn = bits(address,10,31); d = bit(7); a = bit(6); @@ -348,6 +353,7 @@ class PTE_SV32_t w = bit(2); r = bit(1); v = bit(0); + // printf("ppn = 0x%lx, flags= 0x%x, rsw= 0x%x\n",ppn,flags,rsw); } }; @@ -374,6 +380,7 @@ class vAddr_SV32_t vpn[0] = bits(address,12,21); vpn[1] = bits(address,22,31); pgoff = bits(address,0,11); + // printf("vpn[0] = 0x%lx, vpn[1] = 0x%lx, pgoff = 0x%lx\n",vpn[0],vpn[1],pgoff); } }; #endif diff --git a/sim/simx/emulator.cpp b/sim/simx/emulator.cpp index 0214dbddd..a2c8e06d4 100644 --- a/sim/simx/emulator.cpp +++ b/sim/simx/emulator.cpp @@ -271,6 +271,8 @@ bool Emulator::barrier(uint32_t bar_id, uint32_t count, uint32_t wid) { #ifdef VM_ENABLE void Emulator::icache_read(void *data, uint64_t addr, uint32_t size) { + DPH(3, "*** icache_read 0x" << std::hex << addr << ", size = 0x " << size); + try { mmu_.read(data, addr, size, ACCESS_TYPE::LOAD); @@ -289,6 +291,7 @@ void Emulator::icache_read(void *data, uint64_t addr, uint32_t size) { #ifdef VM_ENABLE void Emulator::set_satp(uint32_t satp) { + DPH(3, "set satp 0x" << std::hex << satp << " in emulator module\n"); set_csr(VX_CSR_SATP,satp,0,0); } #endif @@ -328,6 +331,7 @@ void Emulator::dcache_read(void *data, uint64_t addr, uint32_t size) { #ifdef VM_ENABLE void Emulator::dcache_write(const void* data, uint64_t addr, uint32_t size) { + DP(1, "*** dcache_write 0x" << std::hex << addr << ", size = 0x " << size); auto type = get_addr_type(addr); if (addr >= uint64_t(IO_COUT_ADDR) && addr < (uint64_t(IO_COUT_ADDR) + IO_COUT_SIZE)) { diff --git a/sim/simx/processor.cpp b/sim/simx/processor.cpp index ecc1474e1..1d4779b3a 100644 --- a/sim/simx/processor.cpp +++ b/sim/simx/processor.cpp @@ -170,7 +170,6 @@ uint32_t Processor::get_satp() { } void Processor::set_satp(uint32_t satp) { - std::cout << "set SATP: 0x" << std::hex << this->satp << std::endl; impl_->set_satp(satp); this->satp = satp; } From 9942f251e02b792f648da211f6c6bf408cc48c55 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Wed, 19 Jun 2024 02:04:24 -0400 Subject: [PATCH 40/75] remove # --- hw/rtl/VX_config.vh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index 6d3738489..e130ae49b 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -179,7 +179,7 @@ `define PAGE_TABLE_SIZE 4096 `endif -`else # XLEN_32 +`else // XLEN_32 `ifndef STACK_BASE_ADDR `define STACK_BASE_ADDR 32'hFFFF0000 From e21bf9afbd650ec1e0b0ba5a4b91146332850046 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Sat, 22 Jun 2024 23:55:01 -0400 Subject: [PATCH 41/75] Merge Vortex 2.2 --- hw/rtl/VX_config.vh | 77 ++-- runtime/simx/vortex.cpp | 749 +++++++++++++++++++------------------- sim/common/mem.cpp | 95 ++--- sim/common/mem.h | 19 +- sim/simx/cluster.cpp | 2 +- sim/simx/cluster.h | 2 +- sim/simx/core.cpp | 2 +- sim/simx/core.h | 2 +- sim/simx/emulator.cpp | 5 +- sim/simx/emulator.h | 2 +- sim/simx/processor.cpp | 6 +- sim/simx/processor.h | 6 +- sim/simx/processor_impl.h | 3 +- sim/simx/socket.cpp | 2 +- sim/simx/socket.h | 2 +- 15 files changed, 512 insertions(+), 462 deletions(-) diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index e130ae49b..e0b170373 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -33,6 +33,9 @@ `endif /////////////////////////////////////////////////////////////////////////////// +`ifndef VM_DISABLE +`define VM_ENABLE +`endif `ifndef EXT_M_DISABLE `define EXT_M_ENABLE @@ -171,12 +174,11 @@ `define IO_BASE_ADDR 64'h000000040 `endif +`ifdef VM_ENABLE `ifndef PAGE_TABLE_BASE_ADDR `define PAGE_TABLE_BASE_ADDR 64'h1F0000000 `endif -`ifndef PAGE_TABLE_SIZE -`define PAGE_TABLE_SIZE 4096 `endif `else // XLEN_32 @@ -197,12 +199,11 @@ `define IO_BASE_ADDR 32'h00000040 `endif +`ifdef VM_ENABLE `ifndef PAGE_TABLE_BASE_ADDR `define PAGE_TABLE_BASE_ADDR 32'hF0000000 `endif -`ifndef PAGE_TABLE_SIZE -`define PAGE_TABLE_SIZE 4096 `endif `endif @@ -270,40 +271,58 @@ `endif // Virtual Memory Configuration /////////////////////////////////////////////////////// -`ifndef VM_DISABLE -`define VM_ENABLE -`endif `ifdef VM_ENABLE - `ifndef VM_ADDR_MODE - `define VM_ADDR_MODE SV32 - `endif - - `ifndef PTE_SIZE - `ifdef XLEN_32 - `define PTE_SIZE 4 - `define NUM_PTE_ENTRY 1024 - `else - `ifdef XLEN_64 - `define PTE_SIZE 8 - `define NUM_PTE_ENTRY 1024 - `else - `define PTE_SIZE 8 - `define NUM_PTE_ENTRY 1024 - `endif + `ifdef XLEN_32 + `ifndef VM_ADDR_MODE + `define VM_ADDR_MODE SV32 //or BARE + `endif + `ifndef PTE_SIZE + `define PTE_SIZE (4) + `endif + `ifndef SATP_MODE_IDX + `define SATP_MODE_IDX (31) + `endif + `ifndef SATP_PPN_WIDTH + `define SATP_PPN_WIDTH (22) + `endif + `else + `ifndef VM_ADDR_MODE + `define VM_ADDR_MODE SV64 //or BARE + `endif + `ifndef PTE_SIZE + `define PTE_SIZE (8) + `endif + `ifndef SATP_MODE_IDX + `define SATP_MODE_IDX (63) + `endif + `ifndef SATP_PPN_WIDTH + `define SATP_PPN_WIDTH (44) `endif - `define PT_SIZE (PTE_SIZE * NUM_PTE_ENTRY) `endif + `ifndef NUM_PTE_ENTRY + `define NUM_PTE_ENTRY (1024) + `endif + + `ifndef PT_SIZE + `define PT_SIZE (PTE_SIZE * NUM_PTE_ENTRY) + `endif + + `ifndef PT_TOTAL_SIZE + `define PT_TOTAL_SIZE (PT_SIZE*(1+NUM_PTE_ENTRY)) + `endif + + `ifndef TLB_SIZE - `define TLB_SIZE 32 - `endif - - `ifndef SUPER_PAGING - `define SUPER_PAGING 0 + `define TLB_SIZE (32) `endif `endif +`ifndef MEM_PAGE_SIZE +`define MEM_PAGE_SIZE (4096) +`endif + // Pipeline Configuration ///////////////////////////////////////////////////// // Issue width diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 816ca3081..1a5da088a 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -28,11 +28,11 @@ #include #ifdef VM_ENABLE -#include -#include +#include +// #include +//#include #include -#include #include #include @@ -50,7 +50,6 @@ using namespace vortex; #ifdef VM_ENABLE - #ifndef NDEBUG #define DBGPRINT(format, ...) do { printf("[VXDRV] " format "", ##__VA_ARGS__); } while (0) #else @@ -85,13 +84,9 @@ class vx_device { public: vx_device() : arch_(NUM_THREADS, NUM_WARPS, NUM_CORES) -#ifdef VM_ENABLE - , ram_(0, RAM_PAGE_SIZE<<11) -#else - , ram_(0, RAM_PAGE_SIZE) -#endif + , ram_(0, MEM_PAGE_SIZE) , processor_(arch_) - , global_mem_(ALLOC_BASE_ADDR, GLOBAL_MEM_SIZE - ALLOC_BASE_ADDR, RAM_PAGE_SIZE, CACHE_BLOCK_SIZE) + , global_mem_(ALLOC_BASE_ADDR, GLOBAL_MEM_SIZE - ALLOC_BASE_ADDR, MEM_PAGE_SIZE, CACHE_BLOCK_SIZE) { // attach memory module processor_.attach_ram(&ram_); @@ -150,133 +145,141 @@ public: return 0; } -#ifdef VM_ENABLE - // virtual to phycial mapping - uint64_t map_p2v(uint64_t pAddr) - { - return pAddr + 0xf000000; - } - bool need_trans(uint64_t dev_pAddr) - { - // Check if the this is the BARE mode - bool isBAREMode = (get_mode() == VA_MODE::BARE); - // Check if the address is reserved - bool isReserved = (dev_pAddr >= PAGE_TABLE_BASE_ADDR); - // Check if the address falls within the startup address range - bool isStartAddress = (STARTUP_ADDR <= dev_pAddr) && (dev_pAddr <= (STARTUP_ADDR + 0x40000)); - - // Print the boolean results for debugging purposes - // printf("%p, %u, %u\n", (void *)dev_pAddr, isReserved, isStartAddress); - - // Return true if the address needs translation (i.e., it's not reserved and not a start address) - return (!isBAREMode && !isReserved && !isStartAddress); - } - - uint64_t phy_to_virt_map(uint64_t size, uint64_t* dev_pAddr, uint32_t flags) - { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); - DBGPRINT("(size = 0x%lx, dev_pAddr= 0x%lx, flags = 0x%x)\n", size, *dev_pAddr, flags); - DBGPRINT("bit mode: %d\n", XLEN); - - // if (*dev_pAddr == STARTUP_ADDR || *dev_pAddr == 0x7FFFF000) { - - if (!need_trans(*dev_pAddr)) - { - DBGPRINT("Translation is not needed.\n"); - return 0; - } - - uint64_t init_pAddr = *dev_pAddr; - uint64_t init_vAddr = map_p2v(init_pAddr); - uint64_t ppn = 0, vpn = 0 ; - - //dev_pAddr can be of size greater than a page, but we have to map and update - //page tables on a page table granularity. So divide the allocation into pages. - bool is_start = false; - for (ppn = (*dev_pAddr) >> 12; ppn < ((*dev_pAddr) >> 12) + (size/RAM_PAGE_SIZE) + 1; ppn++) - { - vpn = map_p2v(ppn << 12) >> 12; - if (is_start == false) { - DBGPRINT("**Search vpn in page table:0x%lx\n", vpn); - is_start = true; - } - else { - DBGPRINT("Next vpn: 0x%lx\n",vpn); - } - - //Currently a 1-1 mapping is used, this can be changed here to support different - //mapping schemes - - //If ppn to vpn mapping doesnt exist. - if (addr_mapping.find(vpn) == addr_mapping.end()) - { - //Create mapping. - update_page_table(ppn, vpn, flags); - addr_mapping[vpn] = ppn; - } - } - DBGPRINT("Mapped virtual addr: 0x%lx to physical addr: %lx\n", init_vAddr, init_pAddr); - - // Sanity check - uint64_t pAddr = page_table_walk(init_vAddr); - if (pAddr != init_pAddr) - { - assert(pAddr == init_pAddr && "ERROR: translated virtual Addresses are not the same with physical Address"); - } - - *dev_pAddr = init_vAddr; // commit vpn to be returned to host - DBGPRINT("Translated device virtual addr: 0x%lx\n", *dev_pAddr); - - return 0; - } -#endif - - int mem_alloc(uint64_t size, int flags, uint64_t* dev_addr) { - - uint64_t addr; - DBGPRINT("mem_alloc size: 0x%lx\n",size); - CHECK_ERR(global_mem_.allocate(size, &addr), { - return err; - }); - CHECK_ERR(this->mem_access(addr, size, flags), { - global_mem_.release(addr); - return err; - }); - *dev_addr = addr; #ifdef VM_ENABLE - // VM address translation - phy_to_virt_map(size, dev_addr,flags); + // virtual to phycial mapping + uint64_t map_p2v(uint64_t pAddr) + { + return pAddr + 0xf000000; + } + bool need_trans(uint64_t dev_pAddr) + { + // Check if the this is the BARE mode + bool isBAREMode = (get_mode() == VA_MODE::BARE); + // Check if the address is reserved for system usage + bool isReserved = (dev_pAddr >= PAGE_TABLE_BASE_ADDR); + // Check if the address is reserved for IO usage + bool isIO = (dev_pAddr < USER_BASE_ADDR); + // Check if the address falls within the startup address range + bool isStartAddress = (STARTUP_ADDR <= dev_pAddr) && (dev_pAddr <= (STARTUP_ADDR + 0x40000)); + + // Print the boolean results for debugging purposes + // printf("%p, %u, %u\n", (void *)dev_pAddr, isReserved, isStartAddress); + + // Return true if the address needs translation (i.e., it's not reserved and not a start address) + return (!isBAREMode && !isReserved && !isIO && !isStartAddress); + } + + uint64_t phy_to_virt_map(uint64_t size, uint64_t *dev_pAddr, uint32_t flags) + { + // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); + DBGPRINT(" [RT:PTV_MAP] size = 0x%lx, dev_pAddr= 0x%lx, flags = 0x%x\n", size, *dev_pAddr, flags); + DBGPRINT(" [RT:PTV_MAP] bit mode: %d\n", XLEN); + + // if (*dev_pAddr == STARTUP_ADDR || *dev_pAddr == 0x7FFFF000) { + + if (!need_trans(*dev_pAddr)) + { + DBGPRINT(" [RT:PTV_MAP] Translation is not needed.\n"); + return 0; + } + + uint64_t init_pAddr = *dev_pAddr; + uint64_t init_vAddr = map_p2v(init_pAddr); + uint64_t ppn = 0, vpn = 0; + + // dev_pAddr can be of size greater than a page, but we have to map and update + // page tables on a page table granularity. So divide the allocation into pages. + bool is_start = false; + for (ppn = (*dev_pAddr) >> 12; ppn < ((*dev_pAddr) >> 12) + (size / MEM_PAGE_SIZE) + 1; ppn++) + { + vpn = map_p2v(ppn << 12) >> 12; + if (is_start == false) + { + DBGPRINT(" [RT:PTV_MAP] Search vpn in page table:0x%lx\n", vpn); + is_start = true; + } + else + { + DBGPRINT(" [RT:PTV_MAP] Next vpn: 0x%lx\n", vpn); + } + + // Currently a 1-1 mapping is used, this can be changed here to support different + // mapping schemes + + // If ppn to vpn mapping doesnt exist. + if (addr_mapping.find(vpn) == addr_mapping.end()) + { + // Create mapping. + update_page_table(ppn, vpn, flags); + addr_mapping[vpn] = ppn; + } + } + DBGPRINT(" [RT:PTV_MAP] Mapped virtual addr: 0x%lx to physical addr: %lx\n", init_vAddr, init_pAddr); + + // Sanity check + uint64_t pAddr = page_table_walk(init_vAddr); + if (pAddr != init_pAddr) + { + assert(pAddr == init_pAddr && "ERROR: translated virtual Addresses are not the same with physical Address"); + } + + *dev_pAddr = init_vAddr; // commit vpn to be returned to host + DBGPRINT(" [RT:PTV_MAP] Translated device virtual addr: 0x%lx\n", *dev_pAddr); + + return 0; + } #endif - return 0; - } - int mem_reserve(uint64_t dev_addr, uint64_t size, int flags) { - CHECK_ERR(global_mem_.reserve(dev_addr, size), { - return err; - }); - DBGPRINT("mem_reserve: addr: 0x%lx, size: 0x%lx\n",dev_addr, size); - CHECK_ERR(this->mem_access(dev_addr, size, flags), { - global_mem_.release(dev_addr); - return err; - }); + int mem_alloc(uint64_t size, int flags, uint64_t *dev_addr) + { + + uint64_t addr; + DBGPRINT(" [RT:mem_alloc] mem_alloc size: 0x%lx\n", size); + CHECK_ERR(global_mem_.allocate(size, &addr), { + return err; + }); + CHECK_ERR(this->mem_access(addr, size, flags), { + global_mem_.release(addr); + return err; + }); + *dev_addr = addr; #ifdef VM_ENABLE - uint64_t paddr = dev_addr; - phy_to_virt_map(size, &paddr, flags); + // VM address translation + phy_to_virt_map(size, dev_addr, flags); #endif - return 0; - } + return 0; + } - int mem_free(uint64_t dev_addr) { + int mem_reserve(uint64_t dev_addr, uint64_t size, int flags) + { + CHECK_ERR(global_mem_.reserve(dev_addr, size), { + return err; + }); + DBGPRINT(" [RT:mem_reserve] mem_reserve: addr: 0x%lx, size: 0x%lx\n", dev_addr, size); + CHECK_ERR(this->mem_access(dev_addr, size, flags), { + global_mem_.release(dev_addr); + return err; + }); #ifdef VM_ENABLE - uint64_t pAddr = page_table_walk(dev_addr); - // VM address translation - return global_mem_.release(pAddr); + uint64_t paddr = dev_addr; + phy_to_virt_map(size, &paddr, flags); +#endif + return 0; + } + + int mem_free(uint64_t dev_addr) + { +#ifdef VM_ENABLE + uint64_t pAddr = page_table_walk(dev_addr); + // VM address translation + return global_mem_.release(pAddr); #else - return global_mem_.release(dev_addr); + return global_mem_.release(dev_addr); #endif - } + } - int mem_access(uint64_t dev_addr, uint64_t size, int flags) { + int mem_access(uint64_t dev_addr, uint64_t size, int flags) + { uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); if (dev_addr + asize > GLOBAL_MEM_SIZE) return -1; @@ -285,7 +288,8 @@ public: return 0; } - int mem_info(uint64_t* mem_free, uint64_t* mem_used) const { + int mem_info(uint64_t *mem_free, uint64_t *mem_used) const + { if (mem_free) *mem_free = global_mem_.free(); if (mem_used) @@ -293,21 +297,23 @@ public: return 0; } - int upload(uint64_t dest_addr, const void* src, uint64_t size) { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); - uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); - if (dest_addr + asize > GLOBAL_MEM_SIZE) - return -1; + int upload(uint64_t dest_addr, const void *src, uint64_t size) + { + // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); + uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); + if (dest_addr + asize > GLOBAL_MEM_SIZE) + return -1; #ifdef VM_ENABLE - uint64_t pAddr = page_table_walk(dest_addr); - DBGPRINT("Upload data to vAddr = 0x%lx (pAddr=0x%lx)\n", dest_addr, pAddr); - + uint64_t pAddr = page_table_walk(dest_addr); + DBGPRINT(" [RT:upload] Upload data to vAddr = 0x%lx (pAddr=0x%lx)\n", dest_addr, pAddr); + dest_addr = pAddr; //Overwirte #endif ram_.enable_acl(false); - ram_.write((const uint8_t*)src, dest_addr, size); + ram_.write((const uint8_t *)src, dest_addr, size); ram_.enable_acl(true); + /*DBGPRINT("upload %ld bytes to 0x%lx\n", size, dest_addr); for (uint64_t i = 0; i < size && i < 1024; i += 4) { DBGPRINT(" 0x%lx <- 0x%x\n", dest_addr + i, *(uint32_t*)((uint8_t*)src + i)); @@ -316,17 +322,19 @@ public: return 0; } - int download(void* dest, uint64_t src_addr, uint64_t size) { + int download(void *dest, uint64_t src_addr, uint64_t size) + { uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); if (src_addr + asize > GLOBAL_MEM_SIZE) return -1; #ifdef VM_ENABLE - uint64_t pAddr = page_table_walk(src_addr); - DBGPRINT("Download data to vAddr = 0x%lx (pAddr=0x%lx)\n", src_addr, pAddr); + uint64_t pAddr = page_table_walk(src_addr); + DBGPRINT(" [RT:download] Download data to vAddr = 0x%lx (pAddr=0x%lx)\n", src_addr, pAddr); + src_addr = pAddr; //Overwirte #endif ram_.enable_acl(false); - ram_.read((uint8_t*)dest, src_addr, size); + ram_.read((uint8_t *)dest, src_addr, size); ram_.enable_acl(true); /*DBGPRINT("download %ld bytes from 0x%lx\n", size, src_addr); @@ -337,9 +345,11 @@ public: return 0; } - int start(uint64_t krnl_addr, uint64_t args_addr) { + int start(uint64_t krnl_addr, uint64_t args_addr) + { // ensure prior run completed - if (future_.valid()) { + if (future_.valid()) + { future_.wait(); } @@ -350,9 +360,8 @@ public: this->dcr_write(VX_DCR_BASE_STARTUP_ARG1, args_addr >> 32); // start new run - future_ = std::async(std::launch::async, [&]{ - processor_.run(); - }); + future_ = std::async(std::launch::async, [&] + { processor_.run(); }); // clear mpm cache mpm_cache_.clear(); @@ -360,12 +369,14 @@ public: return 0; } - int ready_wait(uint64_t timeout) { + int ready_wait(uint64_t timeout) + { if (!future_.valid()) return 0; uint64_t timeout_sec = timeout / 1000; std::chrono::seconds wait_time(1); - for (;;) { + for (;;) + { // wait for 1 sec and check status auto status = future_.wait_for(wait_time); if (status == std::future_status::ready) @@ -376,8 +387,10 @@ public: return 0; } - int dcr_write(uint32_t addr, uint32_t value) { - if (future_.valid()) { + int dcr_write(uint32_t addr, uint32_t value) + { + if (future_.valid()) + { future_.wait(); // ensure prior run completed } processor_.dcr_write(addr, value); @@ -385,15 +398,18 @@ public: return 0; } - int dcr_read(uint32_t addr, uint32_t* value) const { + int dcr_read(uint32_t addr, uint32_t *value) const + { return dcrs_.read(addr, value); } - int mpm_query(uint32_t addr, uint32_t core_id, uint64_t* value) { + int mpm_query(uint32_t addr, uint32_t core_id, uint64_t *value) + { uint32_t offset = addr - VX_CSR_MPM_BASE; if (offset > 31) return -1; - if (mpm_cache_.count(core_id) == 0) { + if (mpm_cache_.count(core_id) == 0) + { uint64_t mpm_mem_addr = IO_MPM_ADDR + core_id * 32 * sizeof(uint64_t); CHECK_ERR(this->download(mpm_cache_[core_id].data(), mpm_mem_addr, 32 * sizeof(uint64_t)), { return err; @@ -404,247 +420,250 @@ public: } #ifdef VM_ENABLE - /* VM Management */ - void set_processor_satp(VA_MODE mode) + /* VM Management */ + void set_processor_satp(VA_MODE mode) + { + // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); + uint64_t satp = 0; + if (mode == VA_MODE::BARE) { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); - uint32_t satp; - if (mode == VA_MODE::BARE) - { - DBGPRINT("VA_MODE = BARE MODE"); - satp = 0; - } - else if (mode == VA_MODE::SV32) - { - satp = (alloc_2nd_level_page_table() >> 12) | 0x80000000; - DBGPRINT("VA_MODE = SV32 MODE(satp = 0x%x)\n",satp); - } - processor_.set_satp(satp); + DBGPRINT(" [RT:set_satp] VA_MODE = BARE MODE"); + } + else + { + satp = (alloc_2nd_level_page_table() / MEM_PAGE_SIZE) | (1 << SATP_MODE_IDX); + DBGPRINT(" [RT:set_satp] VA_MODE = SV mode (satp = 0x%lx)\n", satp); + } + processor_.set_satp(satp); + } + + uint64_t get_ptbr() + { + // return processor_.get_satp(); + return processor_.get_satp() & ((1 << SATP_PPN_WIDTH) - 1); + } + uint64_t get_pte_address(uint64_t base_page, uint64_t vpn) + { + return (base_page * MEM_PAGE_SIZE) + (vpn * PTE_SIZE); + } + + VA_MODE get_mode() + { +#ifdef XLEN_32 + return processor_.get_satp() & (1 << SATP_MODE_IDX) ? VA_MODE::SV32 : VA_MODE::BARE; +#else // 64 bit + return processor_.get_satp() & (1 << SATP_MODE_IDX) ? VA_MODE::SV64 : VA_MODE::BARE; +#endif + } + + void update_page_table(uint64_t ppn, uint64_t vpn, uint32_t flag) + { + // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); + DBGPRINT(" [RT:Update PT] Mapping vpn 0x%05lx to ppn 0x%05lx(flags = %u)\n", vpn, ppn, flag); + assert((((ppn >> 20) == 0) && ((vpn >> 20) == 0)) && "Upper 12 bits are not zero!"); + // Updating page table with the following mapping of (vAddr) to (pAddr). + // uint32_t page_bit_shift = log2ceil(PTE_SIZE*NUM_PTE_ENTRY); + uint64_t ppn_1 = 0, pte_addr = 0, pte_bytes = 0; + uint64_t vpn_1 = bits(vpn, 10, 19); + uint64_t vpn_0 = bits(vpn, 0, 9); + + // Read first level PTE. + DBGPRINT(" [RT:Update PT]Start second-level page table\n"); + pte_addr = get_pte_address(get_ptbr(), vpn_1); + pte_bytes = read_pte(pte_addr); + DBGPRINT(" [RT:Update PT] PTE addr 0x%lx, PTE bytes 0x%lx\n", pte_addr, pte_bytes); + ppn_1 = (pte_bytes >> 10); + + if (bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) + { + // If valid bit set, proceed to next level using new ppn form PTE. + DBGPRINT(" [RT:Update PT] PTE valid (ppn 0x%lx), continuing the walk...\n", ppn_1); + } + else + { + // If valid bit not set, allocate a second level page table + // in device memory and store ppn in PTE. Set rwx = 000 in PTE + // to indicate this is a pointer to the next level of the page table. + DBGPRINT(" [RT:Update PT] PTE Invalid (ppn 0x%lx), continuing the walk...\n", ppn_1); + ppn_1 = (alloc_1st_level_page_table(vpn_1) >> 12); + pte_bytes = ((ppn_1 << 10) | 0b0000000001); + assert((pte_addr >> 32) == 0 && "Upper 32 bits are not zero!"); + write_pte(pte_addr, pte_bytes); + // if (pte_bytes != read_pte(pte_addr)) + // DBGPRINT("Read/write values are different!\n"); } - uint32_t get_ptbr() - { - // return processor_.get_satp(); - return processor_.get_satp() & 0x003fffff; + DBGPRINT(" [RT:Update PT] Move to first-level page table\n"); + // Read second level PTE. + pte_addr = get_pte_address(ppn_1, vpn_0); + pte_bytes = read_pte(pte_addr); + + if (bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) + { + DBGPRINT(" [RT:Update PT] ERROR, shouldn't be here\n"); + exit(1); + // If valid bit is set, then the page is already allocated. + // Should not reach this point, a sanity check. } - uint64_t get_pte_address(uint64_t base_page, uint64_t vpn) + else { - return (base_page << 12) + (vpn * PTE_SIZE); - } + // If valid bit not set, write ppn of pAddr in PTE. Set rwx = 111 in PTE + // to indicate this is a leaf PTE and has the stated permissions. + pte_bytes = ((ppn << 10) | 0b0000001111); + write_pte(pte_addr, pte_bytes); + if (pte_bytes != read_pte(pte_addr)) + DBGPRINT(" [RT:Update PT] PTE write value and read value are not matched!\n"); + } + } - VA_MODE get_mode() + uint64_t page_table_walk(uint64_t vAddr_bits) + { + // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); + DBGPRINT(" [RT:PTW] start vAddr: 0x%lx\n", vAddr_bits); + if (!need_trans(vAddr_bits)) { - return processor_.get_satp() & 0x80000000 ? VA_MODE::SV32 : VA_MODE::BARE; - } + DBGPRINT(" [RT:PTW] Translation is not needed.\n"); + return vAddr_bits; + } + uint64_t LEVELS = 2; + vAddr_SV32_t vAddr(vAddr_bits); + uint64_t pte_addr, pte_bytes; + uint64_t pt_ba = get_ptbr() << 12; - void update_page_table(uint64_t ppn, uint64_t vpn, uint32_t flag) { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); - DBGPRINT("Mapping vpn 0x%05lx to ppn 0x%05lx(flags = %u)\n", vpn, ppn,flag); - assert((((ppn>> 20) == 0) && ((vpn >> 20) == 0)) && "Upper 12 bits are not zero!"); - //Updating page table with the following mapping of (vAddr) to (pAddr). - // uint32_t page_bit_shift = log2ceil(PTE_SIZE*NUM_PTE_ENTRY); - uint64_t ppn_1 = 0, pte_addr = 0, pte_bytes = 0; - uint64_t vpn_1 = bits(vpn, 10, 19); - uint64_t vpn_0 = bits(vpn, 0, 9); + // Get base page table. - //Read first level PTE. - DBGPRINT("Start second-level page table\n"); - pte_addr = get_pte_address(get_ptbr(), vpn_1); - pte_bytes = read_pte(pte_addr); - DBGPRINT("[PTE] addr 0x%lx, PTE 0x%lx\n", pte_addr, pte_bytes); - ppn_1 = (pte_bytes >> 10); + for (int i = LEVELS - 1; i >= 0; i--) + { + // Read PTE. + pte_addr = pt_ba + vAddr.vpn[i] * PTE_SIZE; + pte_bytes = read_pte(pte_addr); + PTE_SV32_t pte(pte_bytes); + DBGPRINT(" [RT:PTW] Level[%u] pte_bytes = 0x%lx, pte flags = %u)\n", i, pte.ppn, pte.flags); - if ( bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) + // Check if it has invalid flag bits. + if ((pte.v == 0) | ((pte.r == 0) & (pte.w == 1))) + { + std::string msg = " [RT:PTW] Page Fault : Attempted to access invalid entry. Entry: 0x"; + throw Page_Fault_Exception(msg); + } + + if ((pte.r == 0) & (pte.w == 0) & (pte.x == 0)) + { + // Not a leaf node as rwx == 000 + if (i == 0) { - //If valid bit set, proceed to next level using new ppn form PTE. - DBGPRINT("PTE valid (ppn 0x%lx), continuing the walk...\n",ppn_1); + throw Page_Fault_Exception(" [RT:PTW] Page Fault : No leaf node found."); } else { - //If valid bit not set, allocate a second level page table - // in device memory and store ppn in PTE. Set rwx = 000 in PTE - //to indicate this is a pointer to the next level of the page table. - DBGPRINT("PTE Invalid (ppn 0x%lx), continuing the walk...\n",ppn_1); - ppn_1 = (alloc_1st_level_page_table(vpn_1) >> 12); - pte_bytes = ((ppn_1 << 10) | 0b0000000001) ; - assert((pte_addr>> 32) == 0 && "Upper 32 bits are not zero!"); - write_pte(pte_addr, pte_bytes); - // if (pte_bytes != read_pte(pte_addr)) - // DBGPRINT("Read/write values are different!\n"); - } - - - DBGPRINT("Move to first-level page table\n"); - //Read second level PTE. - pte_addr = get_pte_address(ppn_1, vpn_0); - pte_bytes = read_pte(pte_addr); - - if ( bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) - { - DBGPRINT("ERROR, shouldn't be here\n"); - exit(1); - //If valid bit is set, then the page is already allocated. - //Should not reach this point, a sanity check. - } - else - { - //If valid bit not set, write ppn of pAddr in PTE. Set rwx = 111 in PTE - //to indicate this is a leaf PTE and has the stated permissions. - pte_bytes = ( (ppn << 10) | 0b0000001111) ; - write_pte(pte_addr, pte_bytes); - if (pte_bytes != read_pte(pte_addr)) - DBGPRINT("Read/write values are different!\n"); + // Continue on to next level. + pt_ba = pte.ppn << 12; + DBGPRINT(" [RT:PTW] next pt_ba: %p\n", (void *)pt_ba); } + } + else + { + // Leaf node found, finished walking. + pt_ba = pte.ppn << 12; + DBGPRINT(" [RT:PTW] Found PT_Base_Address [%d] = %lx\n", i, pt_ba); + break; + } } - uint64_t page_table_walk(uint64_t vAddr_bits) - { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); - DBGPRINT("PTW on vAddr: 0x%lx\n", vAddr_bits); - if (!need_trans(vAddr_bits)) - { - DBGPRINT("Translation is not needed.\n"); - return vAddr_bits; - } - uint64_t LEVELS = 2; - vAddr_SV32_t vAddr(vAddr_bits); - uint64_t pte_addr, pte_bytes; - uint64_t pt_ba = get_ptbr() << 12; - - //Get base page table. - - for ( int i = LEVELS-1 ; i >= 0 ; i--) - { - //Read PTE. - pte_addr = pt_ba+vAddr.vpn[i]*PTE_SIZE; - pte_bytes = read_pte(pte_addr); - PTE_SV32_t pte(pte_bytes); - DBGPRINT("pte_bytes = 0x%lx, pte flags = %u)\n", pte.ppn , pte.flags); - - //Check if it has invalid flag bits. - if ( (pte.v == 0) | ( (pte.r == 0) & (pte.w == 1) ) ) - { - std::string msg= "Page Fault : Attempted to access invalid entry. Entry: 0x"; - throw Page_Fault_Exception(msg); - } - - if ( (pte.r == 0) & (pte.w == 0) & (pte.x == 0)) - { - //Not a leaf node as rwx == 000 - if (i == 0) - { - throw Page_Fault_Exception("Page Fault : No leaf node found."); - } - else - { - //Continue on to next level. - pt_ba = pte.ppn << 12; - DBGPRINT("next pt_ba: %p\n", (void *)pt_ba); - - } - } - else - { - //Leaf node found, finished walking. - pt_ba = pte.ppn << 12; - DBGPRINT("Found PT_Base_Address [%d] = %lx\n", i, pt_ba); - break; - } - - } - - // pte_bytes is final leaf - PTE_SV32_t pte(pte_bytes); - //Check RWX permissions according to access type. - if (pte.r == 0) - { - throw Page_Fault_Exception("Page Fault : TYPE LOAD, Incorrect permissions."); - } - - uint64_t paddr = pt_ba + vAddr.pgoff; - return paddr; + // pte_bytes is final leaf + PTE_SV32_t pte(pte_bytes); + // Check RWX permissions according to access type. + if (pte.r == 0) + { + throw Page_Fault_Exception(" [RT:PTW] Page Fault : TYPE LOAD, Incorrect permissions."); } - uint64_t alloc_2nd_level_page_table() { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); - uint64_t addr=PAGE_TABLE_BASE_ADDR; - uint64_t size=1<<23; // 8MB !!!FIXME!!! - CHECK_ERR(this->mem_reserve(addr, size, VX_MEM_READ_WRITE), { - return err; - }); - init_page_table(addr); - return addr; + uint64_t paddr = pt_ba + vAddr.pgoff; + return paddr; + } + + uint64_t alloc_2nd_level_page_table() + { + uint64_t addr = PAGE_TABLE_BASE_ADDR; + uint64_t size = PT_TOTAL_SIZE; + CHECK_ERR(this->mem_reserve(addr, size, VX_MEM_READ_WRITE), { + return err; + }); + init_page_table(addr); + return addr; + } + uint64_t alloc_1st_level_page_table(uint64_t vpn_1) + { + uint64_t addr = PAGE_TABLE_BASE_ADDR + PT_SIZE * (1 + vpn_1); + init_page_table(addr); + return addr; + } + + // Initialize to zero the target page table area. 32bit 4K, 64bit 8K + void init_page_table(uint64_t addr) + { + uint64_t asize = aligned_size(PT_SIZE, CACHE_BLOCK_SIZE); + DBGPRINT(" [RT:init_page_table] (addr=0x%lx, size=0x%lx)\n", addr, asize); + uint8_t *src = new uint8_t[asize]; + for (uint64_t i = 0; i < PT_SIZE; ++i) + { + src[i] = 0; } - uint64_t alloc_1st_level_page_table(uint64_t vpn_1) { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); - uint64_t addr = PAGE_TABLE_BASE_ADDR + PTE_SIZE * NUM_PTE_ENTRY*(1+vpn_1); - init_page_table(addr); - return addr; + ram_.enable_acl(false); + ram_.write((const uint8_t *)src, addr, asize); + ram_.enable_acl(true); + } + + // void read_page_table(uint64_t addr) { + // uint8_t *dest = new uint8_t[MEM_PAGE_SIZE]; + // download(dest, addr, MEM_PAGE_SIZE); + // DBGPRINT("VXDRV: download %d bytes from 0x%x\n", MEM_PAGE_SIZE, addr); + // for (int i = 0; i < MEM_PAGE_SIZE; i += 4) { + // DBGPRINT("mem-read: 0x%x -> 0x%x\n", addr + i, *(uint64_t*)((uint8_t*)dest + i)); + // } + // } + + void write_pte(uint64_t addr, uint64_t value = 0xbaadf00d) + { + DBGPRINT(" [RT:Write_pte] writing pte 0x%lx to pAddr: 0x%lx\n", value, addr); + uint8_t *src = new uint8_t[PTE_SIZE]; + for (uint64_t i = 0; i < PTE_SIZE; ++i) + { + src[i] = (value >> (i << 3)) & 0xff; } + // std::cout << "writing PTE to RAM addr 0x" << std::hex << addr << std::endl; + ram_.enable_acl(false); + ram_.write((const uint8_t *)src, addr, PTE_SIZE); + ram_.enable_acl(true); + } - void init_page_table(uint64_t addr) { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); - DBGPRINT("int_page_table (addr=0x%lx)\n", addr); - uint64_t asize = aligned_size(RAM_PAGE_SIZE, CACHE_BLOCK_SIZE); - // uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); - uint8_t *src = new uint8_t[RAM_PAGE_SIZE]; - for (uint64_t i = 0; i < RAM_PAGE_SIZE; ++i) { - src[i] = 0; - } - ram_.enable_acl(false); - ram_.write((const uint8_t*)src, addr, asize); - ram_.enable_acl(true); - } + uint64_t read_pte(uint64_t addr) + { + uint8_t *dest = new uint8_t[PTE_SIZE]; +#ifdef XLEN_32 + uint64_t mask = 0x00000000FFFFFFFF; +#else // 64bit + uint64_t mask = 0xFFFFFFFFFFFFFFFF; +#endif - // void read_page_table(uint64_t addr) { - // uint8_t *dest = new uint8_t[RAM_PAGE_SIZE]; - // download(dest, addr, RAM_PAGE_SIZE); - // DBGPRINT("VXDRV: download %d bytes from 0x%x\n", RAM_PAGE_SIZE, addr); - // for (int i = 0; i < RAM_PAGE_SIZE; i += 4) { - // DBGPRINT("mem-read: 0x%x -> 0x%x\n", addr + i, *(uint64_t*)((uint8_t*)dest + i)); - // } - // } + ram_.read((uint8_t *)dest, addr, PTE_SIZE); + uint64_t ret = (*(uint64_t *)((uint8_t *)dest)) & mask; + DBGPRINT(" [RT:read_pte] reading PTE 0x%lx from RAM addr 0x%lx\n", ret, addr); - void write_pte(uint64_t addr, uint64_t value = 0xbaadf00d) { - DBGPRINT("[Write_pte] writing pte 0x%lx to pAddr: 0x%lx\n", value, addr); - uint8_t *src = new uint8_t[PTE_SIZE]; - for (uint64_t i = 0; i < PTE_SIZE; ++i) { - src[i] = (value >> (i << 3)) & 0xff; - } - //std::cout << "writing PTE to RAM addr 0x" << std::hex << addr << std::endl; - ram_.enable_acl(false); - ram_.write((const uint8_t*)src, addr, PTE_SIZE); - ram_.enable_acl(true); - } - - uint64_t read_pte(uint64_t addr) { - uint8_t *dest = new uint8_t[PTE_SIZE]; - uint64_t mask = 0; - if (XLEN == 32) - mask = 0x00000000FFFFFFFF; - else if (XLEN == 64) - mask = 0xFFFFFFFFFFFFFFFF; - else - assert(0 && "XLEN is not either 32 or 64"); - - ram_.read((uint8_t*)dest, addr, PTE_SIZE); - uint64_t ret = (*(uint64_t*)((uint8_t*)dest)) & mask; - DBGPRINT("[read_pte] reading PTE 0x%lx from RAM addr 0x%lx\n", ret, addr); - - return ret; - } + return ret; + } #endif // JAEWON private: - Arch arch_; - RAM ram_; - Processor processor_; - MemoryAllocator global_mem_; - DeviceConfig dcrs_; - std::future future_; + Arch arch_; + RAM ram_; + Processor processor_; + MemoryAllocator global_mem_; + DeviceConfig dcrs_; + std::future future_; std::unordered_map> mpm_cache_; #ifdef VM_ENABLE - std::unordered_map addr_mapping; + std::unordered_map addr_mapping; #endif }; diff --git a/sim/common/mem.cpp b/sim/common/mem.cpp index 98eefdaf2..eebd2cde3 100644 --- a/sim/common/mem.cpp +++ b/sim/common/mem.cpp @@ -21,6 +21,13 @@ #include using namespace vortex; +#ifdef VM_ENABLE +#ifndef NDEBUG +#define DBGPRINT(format, ...) do { printf("[VXDRV] " format "", ##__VA_ARGS__); } while (0) +#else +#define DBGPRINT(format, ...) ((void)0) +#endif +#endif uint64_t bits(uint64_t addr, uint8_t s_idx, uint8_t e_idx) { @@ -115,7 +122,6 @@ void MemoryUnit::ADecoder::map(uint64_t start, uint64_t end, MemDevice &md) { } void MemoryUnit::ADecoder::read(void* data, uint64_t addr, uint64_t size) { - // printf("====%s (addr= 0x%lx, size= 0x%lx) ====\n", __PRETTY_FUNCTION__,addr,size); mem_accessor_t ma; if (!this->lookup(addr, size, &ma)) { std::cout << "lookup of 0x" << std::hex << addr << " failed.\n"; @@ -125,7 +131,6 @@ void MemoryUnit::ADecoder::read(void* data, uint64_t addr, uint64_t size) { } void MemoryUnit::ADecoder::write(const void* data, uint64_t addr, uint64_t size) { - // printf("====%s====\n", __PRETTY_FUNCTION__); mem_accessor_t ma; if (!this->lookup(addr, size, &ma)) { std::cout << "lookup of 0x" << std::hex << addr << " failed.\n"; @@ -138,7 +143,9 @@ void MemoryUnit::ADecoder::write(const void* data, uint64_t addr, uint64_t size) MemoryUnit::MemoryUnit(uint64_t pageSize) : pageSize_(pageSize) +#ifndef VM_ENABLE , enableVM_(pageSize != 0) +#endif , amo_reservation_({0x0, false}) #ifdef VM_ENABLE , TLB_HIT(0) @@ -158,9 +165,9 @@ void MemoryUnit::attach(MemDevice &m, uint64_t start, uint64_t end) { decoder_.map(start, end, m); } + #ifdef VM_ENABLE std::pair MemoryUnit::tlbLookup(uint64_t vAddr, ACCESS_TYPE type, uint64_t* size_bits) { - // printf("====%s====\n", __PRETTY_FUNCTION__); //Find entry while accounting for different sizes. for (auto entry : tlb_) @@ -201,7 +208,7 @@ std::pair MemoryUnit::tlbLookup(uint64_t vAddr, ACCESS_TYPE type } //Check access permissions. - if ( (type == ACCESS_TYPE::FETCH) & ((e.r == 0) | (e.x == 0)) ) + if ( (type == ACCESS_TYPE::FENCE) & ((e.r == 0) | (e.x == 0)) ) { throw Page_Fault_Exception("Page Fault : Incorrect permissions."); } @@ -251,7 +258,7 @@ uint64_t MemoryUnit::toPhyAddr(uint64_t addr, uint32_t flagMask) { #ifdef VM_ENABLE void MemoryUnit::read(void* data, uint64_t addr, uint32_t size, ACCESS_TYPE type) { - // printf("====%s====\n", __PRETTY_FUNCTION__); + DBGPRINT(" [MMU:read] 0x%lx, 0x%x, %u\n",addr,size,type); uint64_t pAddr; pAddr = vAddr_to_pAddr(addr, type); return decoder_.read(data, pAddr, size); @@ -264,7 +271,7 @@ void MemoryUnit::read(void* data, uint64_t addr, uint32_t size, bool sup) { #endif #ifdef VM_ENABLE void MemoryUnit::write(const void* data, uint64_t addr, uint32_t size, ACCESS_TYPE type) { - // printf("====%s====\n", __PRETTY_FUNCTION__); + DBGPRINT(" [MMU:Write] 0x%lx, 0x%x, %u\n",addr,size,type); uint64_t pAddr; pAddr = vAddr_to_pAddr(addr, type); decoder_.write(data, pAddr, size); @@ -280,6 +287,7 @@ void MemoryUnit::write(const void* data, uint64_t addr, uint32_t size, bool sup) #ifdef VM_ENABLE void MemoryUnit::amo_reserve(uint64_t addr) { + DBGPRINT(" [MMU:amo_reserve] 0x%lx\n",addr); uint64_t pAddr = this->vAddr_to_pAddr(addr,ACCESS_TYPE::LOAD); amo_reservation_.addr = pAddr; amo_reservation_.valid = true; @@ -294,6 +302,7 @@ void MemoryUnit::amo_reserve(uint64_t addr) { #ifdef VM_ENABLE bool MemoryUnit::amo_check(uint64_t addr) { + DBGPRINT(" [MMU:amo_check] 0x%lx\n",addr); uint64_t pAddr = this->vAddr_to_pAddr(addr, ACCESS_TYPE::LOAD); return amo_reservation_.valid && (amo_reservation_.addr == pAddr); } @@ -593,30 +602,30 @@ void RAM::loadHexImage(const char* filename) { #ifdef VM_ENABLE bool MemoryUnit::need_trans(uint64_t dev_pAddr) -{ - // Check if the this is the BARE mode - bool isBAREMode = (this->mode == VA_MODE::BARE); - // Check if the address is reserved - bool isReserved = (dev_pAddr >= PAGE_TABLE_BASE_ADDR); - // Check if the address falls within the startup address range - bool isStartAddress = (STARTUP_ADDR <= dev_pAddr) && (dev_pAddr < (STARTUP_ADDR + 0x40000)); - - // Print the boolean results for debugging purposes - // printf("0x%lx, %u, %u, %u \n", dev_pAddr,isBAREMode, isReserved, isStartAddress); - - // Return true if the address needs translation (i.e., it's not reserved and not a start address) - return (!isBAREMode && !isReserved && !isStartAddress); -} + { + // Check if the this is the BARE mode + bool isBAREMode = (this->mode == VA_MODE::BARE); + // Check if the address is reserved for system usage + bool isReserved = (dev_pAddr >= PAGE_TABLE_BASE_ADDR); + // Check if the address is reserved for IO usage + bool isIO= (dev_pAddr < USER_BASE_ADDR); + // Check if the address falls within the startup address range + bool isStartAddress = (STARTUP_ADDR <= dev_pAddr) && (dev_pAddr <= (STARTUP_ADDR + 0x40000)); + + // Print the boolean results for debugging purposes + // printf("%p, %u, %u\n", (void *)dev_pAddr, isReserved, isStartAddress); + // Return true if the address needs translation (i.e., it's not reserved and not a start address) + return (!isBAREMode && !isReserved && !isIO && !isStartAddress); + } uint64_t MemoryUnit::vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type) { uint64_t pfn; uint64_t size_bits; - // printf("====%s====\n", __PRETTY_FUNCTION__); - // printf("vaddr = 0x%lx, type = 0x%u\n",vAddr,type); + DBGPRINT(" [MMU: V2P] vaddr = 0x%lx, type = 0x%u\n",vAddr,type); if (!need_trans(vAddr)) { - // printf("Translation is not needed.\n"); + DBGPRINT(" [MMU: V2P] Translation is not needed.\n"); return vAddr; } @@ -640,18 +649,18 @@ uint64_t MemoryUnit::vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type) } //Construct final address using pfn and offset. - // std::cout << "[MemoryUnit] translated vAddr: 0x" << std::hex << vAddr << " to pAddr: 0x" << std::hex << ((pfn << size_bits) + (vAddr & ((1 << size_bits) - 1))) << std::endl; + DBGPRINT(" [MMU: V2P] translated vAddr: 0x%lx to pAddr 0x%lx",vAddr,((pfn << size_bits) + (vAddr & ((1 << size_bits) - 1)))); return (pfn << size_bits) + (vAddr & ((1 << size_bits) - 1)); } std::pair MemoryUnit::page_table_walk(uint64_t vAddr_bits, ACCESS_TYPE type, uint64_t* size_bits) { - // printf("====%s====\n", __PRETTY_FUNCTION__); - // printf("vaddr = 0x%lx, type = %u, size_bits %lu\n", vAddr_bits, type, *size_bits); + DBGPRINT(" [MMU:PTW] Start: vaddr = 0x%lx, type = %u, size_bits %lu\n", vAddr_bits, type, *size_bits); uint64_t LEVELS = 2; vAddr_SV32_t vAddr(vAddr_bits); uint64_t pte_bytes = 0; + uint64_t pte_addr =0; //Get base page table. uint64_t pt_ba = this->ptbr << 12; int i = LEVELS - 1; @@ -660,14 +669,15 @@ std::pair MemoryUnit::page_table_walk(uint64_t vAddr_bits, AC { //Read PTE. - decoder_.read(&pte_bytes, pt_ba+vAddr.vpn[i]*PTE_SIZE, PTE_SIZE); + pte_addr = pt_ba+vAddr.vpn[i] * PTE_SIZE; + decoder_.read(&pte_bytes, pte_addr, PTE_SIZE); PTE_SV32_t pte(pte_bytes); + DBGPRINT(" [MMU:PTW] Level[%u] pte_bytes = 0x%lx, pte flags = %u)\n", i, pte.ppn , pte.flags); //Check if it has invalid flag bits. if ( (pte.v == 0) | ( (pte.r == 0) & (pte.w == 1) ) ) { - printf("Error: PTE FLAGS=0x%x\n",pte.flags); - throw Page_Fault_Exception("Page Fault : Attempted to access invalid entry."); + throw Page_Fault_Exception(" [MMU:PTW] Page Fault : Attempted to access invalid entry."); } if ( (pte.r == 0) & (pte.w == 0) & (pte.x == 0)) @@ -676,8 +686,7 @@ std::pair MemoryUnit::page_table_walk(uint64_t vAddr_bits, AC i--; if (i < 0) { - printf("Error: PTE FLAGS=0x%x\n",pte.flags); - throw Page_Fault_Exception("Page Fault : No leaf node found."); + throw Page_Fault_Exception(" [MMU:PTW] Page Fault : No leaf node found."); } else { @@ -696,35 +705,35 @@ std::pair MemoryUnit::page_table_walk(uint64_t vAddr_bits, AC PTE_SV32_t pte(pte_bytes); //Check RWX permissions according to access type. - if ( (type == ACCESS_TYPE::FETCH) & ((pte.r == 0) | (pte.x == 0)) ) + if ( (type == ACCESS_TYPE::FENCE) & ((pte.r == 0) | (pte.x == 0)) ) { - printf("Error: PTE FLAGS=0x%x\n",pte.flags); - throw Page_Fault_Exception("Page Fault : TYPE FETCH, Incorrect permissions."); + throw Page_Fault_Exception(" [MMU:PTW] Page Fault : TYPE FENCE, Incorrect permissions."); } else if ( (type == ACCESS_TYPE::LOAD) & (pte.r == 0) ) { - printf("Error: PTE FLAGS=0x%x\n",pte.flags); - throw Page_Fault_Exception("Page Fault : TYPE LOAD, Incorrect permissions."); + throw Page_Fault_Exception(" [MMU:PTW] Page Fault : TYPE LOAD, Incorrect permissions."); } else if ( (type == ACCESS_TYPE::STORE) & (pte.w == 0) ) { - printf("Error: PTE FLAGS=0x%x\n",pte.flags); - throw Page_Fault_Exception("Page Fault : TYPE STORE, Incorrect permissions."); + throw Page_Fault_Exception(" [MMU:PTW] Page Fault : TYPE STORE, Incorrect permissions."); } *size_bits = 12; uint64_t pfn = pt_ba >> *size_bits; return std::make_pair(pfn, pte_bytes & 0xff); } - -uint32_t MemoryUnit::get_satp() +uint64_t MemoryUnit::get_satp() { return satp; } -void MemoryUnit::set_satp(uint32_t satp) +void MemoryUnit::set_satp(uint64_t satp) { this->satp = satp; - this->ptbr = satp & 0x003fffff; //22 bits - this->mode = satp & 0x80000000 ? VA_MODE::SV32 : VA_MODE::BARE; + this->ptbr = satp & ( (1<< SATP_PPN_WIDTH) - 1); +#ifdef XLEN_32 + this->mode = satp & (1<< SATP_MODE_IDX) ? VA_MODE::SV32 : VA_MODE::BARE; +#else // 64 bit + this->mode = satp & (1<< SATP_MODE_IDX) ? VA_MODE::SV64 : VA_MODE::BARE; +#endif } #endif \ No newline at end of file diff --git a/sim/common/mem.h b/sim/common/mem.h index a655a6d3c..4b7744c2b 100644 --- a/sim/common/mem.h +++ b/sim/common/mem.h @@ -34,13 +34,14 @@ namespace vortex { #ifdef VM_ENABLE enum VA_MODE { BARE, - SV32 + SV32, + SV64 }; enum ACCESS_TYPE { LOAD, STORE, - FETCH + FENCE }; class Page_Fault_Exception : public std::runtime_error /* or logic_error */ @@ -117,7 +118,7 @@ public: }; #ifdef VM_ENABLE - MemoryUnit(uint64_t pageSize = PAGE_TABLE_SIZE); + MemoryUnit(uint64_t pageSize = MEM_PAGE_SIZE); #else MemoryUnit(uint64_t pageSize = 0); #endif @@ -138,8 +139,8 @@ public: #ifdef VM_ENABLE void tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags, uint64_t size_bits); - uint32_t get_satp(); - void set_satp(uint32_t satp); + uint64_t get_satp(); + void set_satp(uint64_t satp); #else void tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags); #endif @@ -238,14 +239,16 @@ private: std::unordered_map tlb_; uint64_t pageSize_; ADecoder decoder_; +#ifndef VM_ENABLE bool enableVM_; +#endif amo_reservation_t amo_reservation_; #ifdef VM_ENABLE - uint32_t satp; + uint64_t satp; VA_MODE mode; - uint32_t ptbr; + uint64_t ptbr; std::unordered_set unique_translations; uint64_t TLB_HIT, TLB_MISS, TLB_EVICT, PTW, PERF_UNIQUE_PTW; @@ -380,7 +383,7 @@ class vAddr_SV32_t vpn[0] = bits(address,12,21); vpn[1] = bits(address,22,31); pgoff = bits(address,0,11); - // printf("vpn[0] = 0x%lx, vpn[1] = 0x%lx, pgoff = 0x%lx\n",vpn[0],vpn[1],pgoff); + // printf("vpn[1] = 0x%lx, vpn[0] = 0x%lx, pgoff = 0x%lx\n",vpn[1],vpn[0],pgoff); } }; #endif diff --git a/sim/simx/cluster.cpp b/sim/simx/cluster.cpp index 0c5ff9f3f..25669e26b 100644 --- a/sim/simx/cluster.cpp +++ b/sim/simx/cluster.cpp @@ -107,7 +107,7 @@ void Cluster::attach_ram(RAM* ram) { } #ifdef VM_ENABLE -void Cluster::set_satp(uint32_t satp) { +void Cluster::set_satp(uint64_t satp) { for (auto& socket : sockets_) { socket->set_satp(satp); } diff --git a/sim/simx/cluster.h b/sim/simx/cluster.h index 113ac04f7..df96031c3 100644 --- a/sim/simx/cluster.h +++ b/sim/simx/cluster.h @@ -58,7 +58,7 @@ public: void attach_ram(RAM* ram); #ifdef VM_ENABLE - void set_satp(uint32_t satp); + void set_satp(uint64_t satp); #endif bool running() const; diff --git a/sim/simx/core.cpp b/sim/simx/core.cpp index 9a134b6ca..6f817a3ae 100644 --- a/sim/simx/core.cpp +++ b/sim/simx/core.cpp @@ -430,7 +430,7 @@ void Core::attach_ram(RAM* ram) { } #ifdef VM_ENABLE -void Core::set_satp(uint32_t satp) { +void Core::set_satp(uint64_t satp) { emulator_.set_satp(satp); //JAEWON wit, tid??? // emulator_.set_csr(VX_CSR_SATP,satp,0,0); //JAEWON wit, tid??? } diff --git a/sim/simx/core.h b/sim/simx/core.h index c18498a52..339d76fb8 100644 --- a/sim/simx/core.h +++ b/sim/simx/core.h @@ -100,7 +100,7 @@ public: void attach_ram(RAM* ram); #ifdef VM_ENABLE - void set_satp(uint32_t satp); + void set_satp(uint64_t satp); #endif bool running() const; diff --git a/sim/simx/emulator.cpp b/sim/simx/emulator.cpp index a2c8e06d4..a1ee0072d 100644 --- a/sim/simx/emulator.cpp +++ b/sim/simx/emulator.cpp @@ -271,7 +271,7 @@ bool Emulator::barrier(uint32_t bar_id, uint32_t count, uint32_t wid) { #ifdef VM_ENABLE void Emulator::icache_read(void *data, uint64_t addr, uint32_t size) { - DPH(3, "*** icache_read 0x" << std::hex << addr << ", size = 0x " << size); + // DP(1, "*** icache_read 0x" << std::hex << addr << ", size = 0x " << size); try { @@ -290,7 +290,7 @@ void Emulator::icache_read(void *data, uint64_t addr, uint32_t size) { #endif #ifdef VM_ENABLE -void Emulator::set_satp(uint32_t satp) { +void Emulator::set_satp(uint64_t satp) { DPH(3, "set satp 0x" << std::hex << satp << " in emulator module\n"); set_csr(VX_CSR_SATP,satp,0,0); } @@ -299,6 +299,7 @@ void Emulator::set_satp(uint32_t satp) { #ifdef VM_ENABLE void Emulator::dcache_read(void *data, uint64_t addr, uint32_t size) { + DP(1, "*** dcache_read 0x" << std::hex << addr << ", size = 0x " << size); auto type = get_addr_type(addr); if (type == AddrType::Shared) { core_->local_mem()->read(data, addr, size); diff --git a/sim/simx/emulator.h b/sim/simx/emulator.h index 9ee42812a..f5c785581 100644 --- a/sim/simx/emulator.h +++ b/sim/simx/emulator.h @@ -40,7 +40,7 @@ public: void attach_ram(RAM* ram); #ifdef VM_ENABLE - void set_satp(uint32_t satp) ; + void set_satp(uint64_t satp) ; #endif instr_trace_t* step(); diff --git a/sim/simx/processor.cpp b/sim/simx/processor.cpp index 1d4779b3a..972792bfb 100644 --- a/sim/simx/processor.cpp +++ b/sim/simx/processor.cpp @@ -96,7 +96,7 @@ void ProcessorImpl::attach_ram(RAM* ram) { } } #ifdef VM_ENABLE -void ProcessorImpl::set_satp(uint32_t satp) { +void ProcessorImpl::set_satp(uint64_t satp) { for (auto cluster : clusters_) { cluster->set_satp(satp); } @@ -164,12 +164,12 @@ void Processor::dcr_write(uint32_t addr, uint32_t value) { } #ifdef VM_ENABLE -uint32_t Processor::get_satp() { +uint64_t Processor::get_satp() { // std::cout << "get SATP: 0x" << std::hex << this->satp << std::endl; return this->satp; } -void Processor::set_satp(uint32_t satp) { +void Processor::set_satp(uint64_t satp) { impl_->set_satp(satp); this->satp = satp; } diff --git a/sim/simx/processor.h b/sim/simx/processor.h index e22f11569..d2b575421 100644 --- a/sim/simx/processor.h +++ b/sim/simx/processor.h @@ -34,14 +34,14 @@ public: void dcr_write(uint32_t addr, uint32_t value); #ifdef VM_ENABLE - uint32_t get_satp(); - void set_satp(uint32_t satp); + uint64_t get_satp(); + void set_satp(uint64_t satp); #endif private: ProcessorImpl* impl_; #ifdef VM_ENABLE - uint32_t satp; + uint64_t satp; #endif }; diff --git a/sim/simx/processor_impl.h b/sim/simx/processor_impl.h index e6e9a4cf1..511c0cad6 100644 --- a/sim/simx/processor_impl.h +++ b/sim/simx/processor_impl.h @@ -40,8 +40,7 @@ public: void dcr_write(uint32_t addr, uint32_t value); #ifdef VM_ENABLE - // 32bit satp - void set_satp(uint32_t satp); + void set_satp(uint64_t satp); #endif PerfStats perf_stats() const; diff --git a/sim/simx/socket.cpp b/sim/simx/socket.cpp index 9374bbc59..cef8a3908 100644 --- a/sim/simx/socket.cpp +++ b/sim/simx/socket.cpp @@ -108,7 +108,7 @@ void Socket::attach_ram(RAM* ram) { } #ifdef VM_ENABLE -void Socket::set_satp(uint32_t satp) { +void Socket::set_satp(uint64_t satp) { for (auto core : cores_) { core->set_satp(satp); } diff --git a/sim/simx/socket.h b/sim/simx/socket.h index a09f73e8b..104d53292 100644 --- a/sim/simx/socket.h +++ b/sim/simx/socket.h @@ -61,7 +61,7 @@ public: void attach_ram(RAM* ram); #ifdef VM_ENABLE - void set_satp(uint32_t satp); + void set_satp(uint64_t satp); #endif bool running() const; From 3a5278a62e3f2231a880458163f69aae6d6cb60c Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Sat, 29 Jun 2024 17:43:20 -0400 Subject: [PATCH 42/75] 64bit support --- .gitignore | 3 +- hw/rtl/VX_config.vh | 48 +-- runtime/common/common.h | 2 +- runtime/common/malloc.h | 26 +- runtime/simx/vortex.cpp | 482 +++++++++++++--------------- sim/common/mem.cpp | 176 +++++----- sim/common/mem.h | 232 ++++++++++--- sim/simx/emulator.cpp | 9 +- sim/simx/main.cpp | 2 +- sim/simx/processor.cpp | 23 +- sim/simx/processor.h | 10 +- tests/regression/diverge/kernel.cpp | 2 +- 12 files changed, 572 insertions(+), 443 deletions(-) diff --git a/.gitignore b/.gitignore index 039456040..43388e9cb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /build* /.vscode -*.cache \ No newline at end of file +*.cache +*.code-workspace diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index e0b170373..ed2afc900 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -163,7 +163,7 @@ `endif `ifndef STARTUP_ADDR -`define STARTUP_ADDR 64'h080000000 +`define STARTUP_ADDR 64'h180000000 `endif `ifndef USER_BASE_ADDR @@ -270,59 +270,59 @@ `define DEBUG_LEVEL 3 `endif +`ifndef MEM_PAGE_SIZE +`define MEM_PAGE_SIZE (4096) +`endif +`ifndef MEM_PAGE_LOG2_SIZE +`define MEM_PAGE_LOG2_SIZE (12) +`endif + // Virtual Memory Configuration /////////////////////////////////////////////////////// `ifdef VM_ENABLE `ifdef XLEN_32 `ifndef VM_ADDR_MODE `define VM_ADDR_MODE SV32 //or BARE `endif + `ifndef PT_LEVEL + `define PT_LEVEL (2) + `endif `ifndef PTE_SIZE `define PTE_SIZE (4) `endif - `ifndef SATP_MODE_IDX - `define SATP_MODE_IDX (31) + `ifndef NUM_PTE_ENTRY + `define NUM_PTE_ENTRY (1024) `endif - `ifndef SATP_PPN_WIDTH - `define SATP_PPN_WIDTH (22) + `ifndef PT_SIZE_LIMIT + `define PT_SIZE_LIMIT (1<<23) `endif `else `ifndef VM_ADDR_MODE - `define VM_ADDR_MODE SV64 //or BARE + `define VM_ADDR_MODE SV39 //or BARE + `endif + `ifndef PT_LEVEL + `define PT_LEVEL (3) `endif `ifndef PTE_SIZE `define PTE_SIZE (8) `endif - `ifndef SATP_MODE_IDX - `define SATP_MODE_IDX (63) + `ifndef NUM_PTE_ENTRY + `define NUM_PTE_ENTRY (512) `endif - `ifndef SATP_PPN_WIDTH - `define SATP_PPN_WIDTH (44) + `ifndef PT_SIZE_LIMIT + `define PT_SIZE_LIMIT (1<<25) `endif `endif - `ifndef NUM_PTE_ENTRY - `define NUM_PTE_ENTRY (1024) - `endif - `ifndef PT_SIZE - `define PT_SIZE (PTE_SIZE * NUM_PTE_ENTRY) + `define PT_SIZE MEM_PAGE_SIZE `endif - `ifndef PT_TOTAL_SIZE - `define PT_TOTAL_SIZE (PT_SIZE*(1+NUM_PTE_ENTRY)) - `endif - - `ifndef TLB_SIZE `define TLB_SIZE (32) `endif `endif -`ifndef MEM_PAGE_SIZE -`define MEM_PAGE_SIZE (4096) -`endif - // Pipeline Configuration ///////////////////////////////////////////////////// // Issue width diff --git a/runtime/common/common.h b/runtime/common/common.h index f7125064e..37fec4846 100644 --- a/runtime/common/common.h +++ b/runtime/common/common.h @@ -24,7 +24,7 @@ #define CACHE_BLOCK_SIZE 64 -#define RAM_PAGE_SIZE 4096 +#define RAM_PAGE_SIZE 4096 // Please use MEM_PAGE_SIZE in VX_config.h #define ALLOC_BASE_ADDR USER_BASE_ADDR diff --git a/runtime/common/malloc.h b/runtime/common/malloc.h index 480c198a6..ca386031a 100644 --- a/runtime/common/malloc.h +++ b/runtime/common/malloc.h @@ -39,6 +39,15 @@ public: page_t* currPage = pages_; while (currPage) { auto nextPage = currPage->next; + #ifdef VM_ENABLE + block_t* currblock = currPage->findfirstUsedBlock(); + block_t* nextblock; + while (currblock) { + nextblock= currblock->nextUsed; + currPage->release(currblock); + currblock = nextblock; + } + #endif delete currPage; currPage = nextPage; } @@ -70,7 +79,7 @@ public: size = alignSize(size, pageAlign_); // Check if the reservation is within memory capacity bounds - if (addr + size > capacity_) { + if (addr + size > baseAddress_ + capacity_) { printf("error: address range out of bounds\n"); return -1; } @@ -118,12 +127,12 @@ public: auto pageSize = alignSize(size, pageAlign_); uint64_t pageAddr; if (!this->findNextAddress(pageSize, &pageAddr)) { - printf("error: out of memory\n"); + printf("error: out of memory (Can't find next address)\n"); return -1; } currPage = this->createPage(pageAddr, pageSize); if (nullptr == currPage) { - printf("error: out of memory\n"); + printf("error: out of memory (Can't create a page)\n"); return -1; } freeBlock = currPage->findFreeBlock(size); @@ -335,6 +344,11 @@ private: } return nullptr; } +#ifdef VM_ENABLE + block_t* findfirstUsedBlock() { + return usedList_; + } +#endif private: @@ -480,7 +494,7 @@ private: bool findNextAddress(uint64_t size, uint64_t* addr) { if (pages_ == nullptr) { - *addr = baseAddress_; + *addr = baseAddress_; return true; } @@ -498,10 +512,10 @@ private: endOfLastPage = current->addr + current->size; current = current->next; } - + // If no suitable gap is found, place the new page at the end of the last page // Check if the allocator has enough capacity - if ((endOfLastPage + size) <= capacity_) { + if ((endOfLastPage + size) <= (baseAddress_ + capacity_)) { *addr = endOfLastPage; return true; } diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 1a5da088a..ae9fe5bb5 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -27,10 +27,8 @@ #include #include -#ifdef VM_ENABLE #include -// #include -//#include +#ifdef VM_ENABLE #include #include @@ -44,42 +42,10 @@ #include #include #include -#include #endif using namespace vortex; -#ifdef VM_ENABLE -#ifndef NDEBUG -#define DBGPRINT(format, ...) do { printf("[VXDRV] " format "", ##__VA_ARGS__); } while (0) -#else -#define DBGPRINT(format, ...) ((void)0) -#endif - -#define CHECK_ERR(_expr, _cleanup) \ - do { \ - auto err = _expr; \ - if (err == 0) \ - break; \ - printf("[VXDRV] Error: '%s' returned %d!\n", #_expr, (int)err); \ - _cleanup \ - } while (false) - -/////////////////////////////////////////////////////////////////////////////// -// -#include -#include - -uint64_t bits(uint64_t addr, uint8_t s_idx, uint8_t e_idx) -{ - return (addr >> s_idx) & ((1 << (e_idx - s_idx + 1)) - 1); -} -bool bit(uint64_t addr, uint8_t idx) -{ - return (addr) & (1 << idx); -} -#endif - class vx_device { public: vx_device() @@ -91,14 +57,16 @@ public: // attach memory module processor_.attach_ram(&ram_); #ifdef VM_ENABLE - //Set - set_processor_satp(VM_ADDR_MODE); + CHECK_ERR(init_VM(), ); #endif - } + } ~vx_device() { #ifdef VM_ENABLE - this->mem_free(PAGE_TABLE_BASE_ADDR); // Right position? + global_mem_.release(PAGE_TABLE_BASE_ADDR); + // for (auto i = addr_mapping.begin(); i != addr_mapping.end(); i++) + // page_table_mem_->release(i->second << MEM_PAGE_SIZE); + delete page_table_mem_; #endif if (future_.valid()) { future_.wait(); @@ -154,9 +122,10 @@ public: bool need_trans(uint64_t dev_pAddr) { // Check if the this is the BARE mode - bool isBAREMode = (get_mode() == VA_MODE::BARE); + bool isBAREMode = (get_mode() == BARE); // Check if the address is reserved for system usage - bool isReserved = (dev_pAddr >= PAGE_TABLE_BASE_ADDR); + // bool isReserved = (PAGE_TABLE_BASE_ADDR <= dev_pAddr && dev_pAddr < PAGE_TABLE_BASE_ADDR + PT_SIZE_LIMIT); + bool isReserved = (PAGE_TABLE_BASE_ADDR <= dev_pAddr); // Check if the address is reserved for IO usage bool isIO = (dev_pAddr < USER_BASE_ADDR); // Check if the address falls within the startup address range @@ -172,14 +141,12 @@ public: uint64_t phy_to_virt_map(uint64_t size, uint64_t *dev_pAddr, uint32_t flags) { // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); - DBGPRINT(" [RT:PTV_MAP] size = 0x%lx, dev_pAddr= 0x%lx, flags = 0x%x\n", size, *dev_pAddr, flags); - DBGPRINT(" [RT:PTV_MAP] bit mode: %d\n", XLEN); - - // if (*dev_pAddr == STARTUP_ADDR || *dev_pAddr == 0x7FFFF000) { + DBGPRINT(" [RT:PTV_MAP] size = 0x%lx, dev_pAddr= 0x%lx, flags = 0x%x\n", size, *dev_pAddr, flags); + DBGPRINT(" [RT:PTV_MAP] bit mode: %d\n", XLEN); if (!need_trans(*dev_pAddr)) { - DBGPRINT(" [RT:PTV_MAP] Translation is not needed.\n"); + DBGPRINT(" [RT:PTV_MAP] Translation is not needed.\n"); return 0; } @@ -189,42 +156,30 @@ public: // dev_pAddr can be of size greater than a page, but we have to map and update // page tables on a page table granularity. So divide the allocation into pages. - bool is_start = false; - for (ppn = (*dev_pAddr) >> 12; ppn < ((*dev_pAddr) >> 12) + (size / MEM_PAGE_SIZE) + 1; ppn++) + // FUTURE Work: Super Page + for (ppn = (*dev_pAddr >> MEM_PAGE_LOG2_SIZE); ppn < ((*dev_pAddr) >> MEM_PAGE_LOG2_SIZE) + (size >> MEM_PAGE_LOG2_SIZE) ; ppn++) { - vpn = map_p2v(ppn << 12) >> 12; - if (is_start == false) - { - DBGPRINT(" [RT:PTV_MAP] Search vpn in page table:0x%lx\n", vpn); - is_start = true; - } - else - { - DBGPRINT(" [RT:PTV_MAP] Next vpn: 0x%lx\n", vpn); - } - + vpn = map_p2v(ppn << MEM_PAGE_LOG2_SIZE) >> MEM_PAGE_LOG2_SIZE; + DBGPRINT(" [RT:PTV_MAP] Search vpn in page table:0x%lx\n", vpn); // Currently a 1-1 mapping is used, this can be changed here to support different // mapping schemes - // If ppn to vpn mapping doesnt exist. if (addr_mapping.find(vpn) == addr_mapping.end()) { // Create mapping. - update_page_table(ppn, vpn, flags); + DBGPRINT(" [RT:PTV_MAP] Not found. Allocate new page table or update a PTE.\n"); + CHECK_ERR(update_page_table(ppn, vpn, flags),); addr_mapping[vpn] = ppn; } } - DBGPRINT(" [RT:PTV_MAP] Mapped virtual addr: 0x%lx to physical addr: %lx\n", init_vAddr, init_pAddr); - + DBGPRINT(" [RT:PTV_MAP] Mapped virtual addr: 0x%lx to physical addr: 0x%lx\n", init_vAddr, init_pAddr); // Sanity check uint64_t pAddr = page_table_walk(init_vAddr); - if (pAddr != init_pAddr) - { - assert(pAddr == init_pAddr && "ERROR: translated virtual Addresses are not the same with physical Address"); - } + DBGPRINT(" [RT:PTV_MAP] physical addr from PTW: 0x%lx\n", pAddr); + assert(pAddr == init_pAddr && "ERROR: translated virtual Addresses are not the same with physical Address\n"); *dev_pAddr = init_vAddr; // commit vpn to be returned to host - DBGPRINT(" [RT:PTV_MAP] Translated device virtual addr: 0x%lx\n", *dev_pAddr); + DBGPRINT(" [RT:PTV_MAP] Translated device virtual addr: 0x%lx\n", *dev_pAddr); return 0; } @@ -232,47 +187,44 @@ public: int mem_alloc(uint64_t size, int flags, uint64_t *dev_addr) { + uint64_t asize = aligned_size(size, MEM_PAGE_SIZE); + uint64_t addr = 0; - uint64_t addr; - DBGPRINT(" [RT:mem_alloc] mem_alloc size: 0x%lx\n", size); - CHECK_ERR(global_mem_.allocate(size, &addr), { + DBGPRINT("[RT:mem_alloc] size: 0x%lx, asize, 0x%lx,flag : 0x%d\n", size, asize, flags); + CHECK_ERR(global_mem_.allocate(asize, &addr), { return err; }); - CHECK_ERR(this->mem_access(addr, size, flags), { + CHECK_ERR(this->mem_access(addr, asize, flags), { global_mem_.release(addr); return err; }); *dev_addr = addr; #ifdef VM_ENABLE // VM address translation - phy_to_virt_map(size, dev_addr, flags); + phy_to_virt_map(asize, dev_addr, flags); #endif return 0; } int mem_reserve(uint64_t dev_addr, uint64_t size, int flags) { - CHECK_ERR(global_mem_.reserve(dev_addr, size), { + uint64_t asize = aligned_size(size, MEM_PAGE_SIZE); + CHECK_ERR(global_mem_.reserve(dev_addr, asize), { return err; }); - DBGPRINT(" [RT:mem_reserve] mem_reserve: addr: 0x%lx, size: 0x%lx\n", dev_addr, size); - CHECK_ERR(this->mem_access(dev_addr, size, flags), { + DBGPRINT("[RT:mem_reserve] addr: 0x%lx, asize:0x%lx, size: 0x%lx\n", dev_addr, asize, size); + CHECK_ERR(this->mem_access(dev_addr, asize, flags), { global_mem_.release(dev_addr); return err; }); -#ifdef VM_ENABLE - uint64_t paddr = dev_addr; - phy_to_virt_map(size, &paddr, flags); -#endif return 0; } int mem_free(uint64_t dev_addr) { #ifdef VM_ENABLE - uint64_t pAddr = page_table_walk(dev_addr); - // VM address translation - return global_mem_.release(pAddr); + uint64_t paddr= page_table_walk(dev_addr); + return global_mem_.release(paddr); #else return global_mem_.release(dev_addr); #endif @@ -313,8 +265,8 @@ public: ram_.write((const uint8_t *)src, dest_addr, size); ram_.enable_acl(true); - - /*DBGPRINT("upload %ld bytes to 0x%lx\n", size, dest_addr); + /* + DBGPRINT("upload %ld bytes to 0x%lx\n", size, dest_addr); for (uint64_t i = 0; i < size && i < 1024; i += 4) { DBGPRINT(" 0x%lx <- 0x%x\n", dest_addr + i, *(uint32_t*)((uint8_t*)src + i)); }*/ @@ -418,200 +370,195 @@ public: *value = mpm_cache_.at(core_id).at(offset); return 0; } - #ifdef VM_ENABLE /* VM Management */ - void set_processor_satp(VA_MODE mode) - { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); - uint64_t satp = 0; - if (mode == VA_MODE::BARE) - { - DBGPRINT(" [RT:set_satp] VA_MODE = BARE MODE"); - } - else - { - satp = (alloc_2nd_level_page_table() / MEM_PAGE_SIZE) | (1 << SATP_MODE_IDX); - DBGPRINT(" [RT:set_satp] VA_MODE = SV mode (satp = 0x%lx)\n", satp); - } - processor_.set_satp(satp); - } - - uint64_t get_ptbr() - { - // return processor_.get_satp(); - return processor_.get_satp() & ((1 << SATP_PPN_WIDTH) - 1); - } - uint64_t get_pte_address(uint64_t base_page, uint64_t vpn) - { - return (base_page * MEM_PAGE_SIZE) + (vpn * PTE_SIZE); - } - - VA_MODE get_mode() - { -#ifdef XLEN_32 - return processor_.get_satp() & (1 << SATP_MODE_IDX) ? VA_MODE::SV32 : VA_MODE::BARE; -#else // 64 bit - return processor_.get_satp() & (1 << SATP_MODE_IDX) ? VA_MODE::SV64 : VA_MODE::BARE; -#endif - } - - void update_page_table(uint64_t ppn, uint64_t vpn, uint32_t flag) - { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); - DBGPRINT(" [RT:Update PT] Mapping vpn 0x%05lx to ppn 0x%05lx(flags = %u)\n", vpn, ppn, flag); - assert((((ppn >> 20) == 0) && ((vpn >> 20) == 0)) && "Upper 12 bits are not zero!"); - // Updating page table with the following mapping of (vAddr) to (pAddr). - // uint32_t page_bit_shift = log2ceil(PTE_SIZE*NUM_PTE_ENTRY); - uint64_t ppn_1 = 0, pte_addr = 0, pte_bytes = 0; - uint64_t vpn_1 = bits(vpn, 10, 19); - uint64_t vpn_0 = bits(vpn, 0, 9); - - // Read first level PTE. - DBGPRINT(" [RT:Update PT]Start second-level page table\n"); - pte_addr = get_pte_address(get_ptbr(), vpn_1); - pte_bytes = read_pte(pte_addr); - DBGPRINT(" [RT:Update PT] PTE addr 0x%lx, PTE bytes 0x%lx\n", pte_addr, pte_bytes); - ppn_1 = (pte_bytes >> 10); - - if (bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) - { - // If valid bit set, proceed to next level using new ppn form PTE. - DBGPRINT(" [RT:Update PT] PTE valid (ppn 0x%lx), continuing the walk...\n", ppn_1); - } - else - { - // If valid bit not set, allocate a second level page table - // in device memory and store ppn in PTE. Set rwx = 000 in PTE - // to indicate this is a pointer to the next level of the page table. - DBGPRINT(" [RT:Update PT] PTE Invalid (ppn 0x%lx), continuing the walk...\n", ppn_1); - ppn_1 = (alloc_1st_level_page_table(vpn_1) >> 12); - pte_bytes = ((ppn_1 << 10) | 0b0000000001); - assert((pte_addr >> 32) == 0 && "Upper 32 bits are not zero!"); - write_pte(pte_addr, pte_bytes); - // if (pte_bytes != read_pte(pte_addr)) - // DBGPRINT("Read/write values are different!\n"); - } - - DBGPRINT(" [RT:Update PT] Move to first-level page table\n"); - // Read second level PTE. - pte_addr = get_pte_address(ppn_1, vpn_0); - pte_bytes = read_pte(pte_addr); - - if (bit(pte_bytes, 0) && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) - { - DBGPRINT(" [RT:Update PT] ERROR, shouldn't be here\n"); - exit(1); - // If valid bit is set, then the page is already allocated. - // Should not reach this point, a sanity check. - } - else - { - // If valid bit not set, write ppn of pAddr in PTE. Set rwx = 111 in PTE - // to indicate this is a leaf PTE and has the stated permissions. - pte_bytes = ((ppn << 10) | 0b0000001111); - write_pte(pte_addr, pte_bytes); - if (pte_bytes != read_pte(pte_addr)) - DBGPRINT(" [RT:Update PT] PTE write value and read value are not matched!\n"); - } - } - - uint64_t page_table_walk(uint64_t vAddr_bits) - { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); - DBGPRINT(" [RT:PTW] start vAddr: 0x%lx\n", vAddr_bits); - if (!need_trans(vAddr_bits)) - { - DBGPRINT(" [RT:PTW] Translation is not needed.\n"); - return vAddr_bits; - } - uint64_t LEVELS = 2; - vAddr_SV32_t vAddr(vAddr_bits); - uint64_t pte_addr, pte_bytes; - uint64_t pt_ba = get_ptbr() << 12; - - // Get base page table. - - for (int i = LEVELS - 1; i >= 0; i--) - { - // Read PTE. - pte_addr = pt_ba + vAddr.vpn[i] * PTE_SIZE; - pte_bytes = read_pte(pte_addr); - PTE_SV32_t pte(pte_bytes); - DBGPRINT(" [RT:PTW] Level[%u] pte_bytes = 0x%lx, pte flags = %u)\n", i, pte.ppn, pte.flags); - - // Check if it has invalid flag bits. - if ((pte.v == 0) | ((pte.r == 0) & (pte.w == 1))) - { - std::string msg = " [RT:PTW] Page Fault : Attempted to access invalid entry. Entry: 0x"; - throw Page_Fault_Exception(msg); - } - - if ((pte.r == 0) & (pte.w == 0) & (pte.x == 0)) - { - // Not a leaf node as rwx == 000 - if (i == 0) - { - throw Page_Fault_Exception(" [RT:PTW] Page Fault : No leaf node found."); - } - else - { - // Continue on to next level. - pt_ba = pte.ppn << 12; - DBGPRINT(" [RT:PTW] next pt_ba: %p\n", (void *)pt_ba); - } - } - else - { - // Leaf node found, finished walking. - pt_ba = pte.ppn << 12; - DBGPRINT(" [RT:PTW] Found PT_Base_Address [%d] = %lx\n", i, pt_ba); - break; - } - } - - // pte_bytes is final leaf - PTE_SV32_t pte(pte_bytes); - // Check RWX permissions according to access type. - if (pte.r == 0) - { - throw Page_Fault_Exception(" [RT:PTW] Page Fault : TYPE LOAD, Incorrect permissions."); - } - - uint64_t paddr = pt_ba + vAddr.pgoff; - return paddr; - } - - uint64_t alloc_2nd_level_page_table() - { - uint64_t addr = PAGE_TABLE_BASE_ADDR; - uint64_t size = PT_TOTAL_SIZE; - CHECK_ERR(this->mem_reserve(addr, size, VX_MEM_READ_WRITE), { - return err; - }); - init_page_table(addr); - return addr; - } - uint64_t alloc_1st_level_page_table(uint64_t vpn_1) - { - uint64_t addr = PAGE_TABLE_BASE_ADDR + PT_SIZE * (1 + vpn_1); - init_page_table(addr); - return addr; - } // Initialize to zero the target page table area. 32bit 4K, 64bit 8K - void init_page_table(uint64_t addr) + uint16_t init_page_table(uint64_t addr, uint64_t size) { - uint64_t asize = aligned_size(PT_SIZE, CACHE_BLOCK_SIZE); + uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); DBGPRINT(" [RT:init_page_table] (addr=0x%lx, size=0x%lx)\n", addr, asize); uint8_t *src = new uint8_t[asize]; - for (uint64_t i = 0; i < PT_SIZE; ++i) + if (src == NULL) + return 1; + + for (uint64_t i = 0; i < asize; ++i) { src[i] = 0; } ram_.enable_acl(false); ram_.write((const uint8_t *)src, addr, asize); ram_.enable_acl(true); + return 0; + } + + uint8_t alloc_page_table (uint64_t * pt_addr) + { + CHECK_ERR(page_table_mem_->allocate(PT_SIZE, pt_addr), { return err; }); + CHECK_ERR(init_page_table(*pt_addr, PT_SIZE), { return err; }); + DBGPRINT(" [RT:alloc_page_table] addr= 0x%lx\n", *pt_addr); + return 0; + } + + int16_t init_VM() + { + uint64_t pt_addr = 0; + // Reserve space for PT + DBGPRINT("[RT:init_VM] Initialize VM\n"); + CHECK_ERR(mem_reserve(PAGE_TABLE_BASE_ADDR, PT_SIZE_LIMIT, VX_MEM_READ_WRITE), { + return err; + }); + page_table_mem_ = new MemoryAllocator (PAGE_TABLE_BASE_ADDR, PT_SIZE_LIMIT, MEM_PAGE_SIZE, CACHE_BLOCK_SIZE); + if (page_table_mem_ == NULL) + { + CHECK_ERR(this->mem_free(PAGE_TABLE_BASE_ADDR),); + return 1; + } + + if (VM_ADDR_MODE == BARE) + DBGPRINT("[RT:init_VM] VA_MODE = BARE MODE(addr= 0x0)"); + else + CHECK_ERR(alloc_page_table(&pt_addr),{return err;}); + + CHECK_ERR(processor_.set_satp_by_addr(pt_addr),{return err;}); + return 0; + } + + // Return value in in ptbr + uint64_t get_base_ppn() + { + return processor_.get_base_ppn(); + } + uint64_t get_pte_address(uint64_t base_ppn, uint64_t vpn) + { + return (base_ppn * PT_SIZE) + (vpn * PTE_SIZE); + } + + uint8_t get_mode() + { + return processor_.get_satp_mode(); + } + + int16_t update_page_table(uint64_t ppn, uint64_t vpn, uint32_t flag) + { + DBGPRINT(" [RT:Update PT] Mapping vpn 0x%05lx to ppn 0x%05lx(flags = %u)\n", vpn, ppn, flag); + // sanity check +#if VM_ADDR_MODE == SV39 + assert((((ppn >> 44) == 0) && ((vpn >> 27) == 0)) && "Upper bits are not zero!"); + uint8_t level = 3; +#else // Default is SV32, BARE will not reach this point. + assert((((ppn >> 20) == 0) && ((vpn >> 20) == 0)) && "Upper 12 bits are not zero!"); + uint8_t level = 2; +#endif + int i = level - 1; + vAddr_t vaddr(vpn << MEM_PAGE_LOG2_SIZE); + uint64_t pte_addr = 0, pte_bytes = 0; + uint64_t pt_addr = 0; + uint64_t cur_base_ppn = get_base_ppn(); + + while (i >= 0) + { + DBGPRINT(" [RT:Update PT]Start %u-level page table\n", i); + pte_addr = get_pte_address(cur_base_ppn, vaddr.vpn[i]); + pte_bytes = read_pte(pte_addr); + PTE_t pte_chk(pte_bytes); + DBGPRINT(" [RT:Update PT] PTE addr 0x%lx, PTE bytes 0x%lx\n", pte_addr, pte_bytes); + if (pte_chk.v == 1 && ((pte_bytes & 0xFFFFFFFF) != 0xbaadf00d)) + { + DBGPRINT(" [RT:Update PT] PTE valid (ppn 0x%lx), continuing the walk...\n", pte_chk.ppn); + cur_base_ppn = pte_chk.ppn; + } + else + { + // If valid bit not set, allocate a next level page table + DBGPRINT(" [RT:Update PT] PTE Invalid (ppn 0x%lx) ...\n", pte_chk.ppn); + if (i == 0) + { + // Reach to leaf + DBGPRINT(" [RT:Update PT] Reached to level 0. This should be a leaf node(flag = %x) \n",flag); + uint32_t pte_flag = (flag << 1) | 0x3; + PTE_t new_pte(ppn <> mpm_cache_; #ifdef VM_ENABLE std::unordered_map addr_mapping; + MemoryAllocator* page_table_mem_; #endif }; diff --git a/sim/common/mem.cpp b/sim/common/mem.cpp index eebd2cde3..f3c1025a2 100644 --- a/sim/common/mem.cpp +++ b/sim/common/mem.cpp @@ -21,6 +21,7 @@ #include using namespace vortex; + #ifdef VM_ENABLE #ifndef NDEBUG #define DBGPRINT(format, ...) do { printf("[VXDRV] " format "", ##__VA_ARGS__); } while (0) @@ -29,16 +30,6 @@ using namespace vortex; #endif #endif -uint64_t bits(uint64_t addr, uint8_t s_idx, uint8_t e_idx) -{ - return (addr >> s_idx) & ((1 << (e_idx - s_idx + 1)) - 1); -} - -bool bit(uint64_t addr, uint8_t idx) -{ - return (addr) & (1 << idx); -} - RamMemDevice::RamMemDevice(const char *filename, uint32_t wordSize) : wordSize_(wordSize) { @@ -124,6 +115,7 @@ void MemoryUnit::ADecoder::map(uint64_t start, uint64_t end, MemDevice &md) { void MemoryUnit::ADecoder::read(void* data, uint64_t addr, uint64_t size) { mem_accessor_t ma; if (!this->lookup(addr, size, &ma)) { + assert(0); std::cout << "lookup of 0x" << std::hex << addr << " failed.\n"; throw BadAddress(); } @@ -133,6 +125,7 @@ void MemoryUnit::ADecoder::read(void* data, uint64_t addr, uint64_t size) { void MemoryUnit::ADecoder::write(const void* data, uint64_t addr, uint64_t size) { mem_accessor_t ma; if (!this->lookup(addr, size, &ma)) { + assert(0); std::cout << "lookup of 0x" << std::hex << addr << " failed.\n"; throw BadAddress(); } @@ -208,7 +201,7 @@ std::pair MemoryUnit::tlbLookup(uint64_t vAddr, ACCESS_TYPE type } //Check access permissions. - if ( (type == ACCESS_TYPE::FENCE) & ((e.r == 0) | (e.x == 0)) ) + if ( (type == ACCESS_TYPE::FETCH) & ((e.r == 0) | (e.x == 0)) ) { throw Page_Fault_Exception("Page Fault : Incorrect permissions."); } @@ -601,12 +594,33 @@ void RAM::loadHexImage(const char* filename) { #ifdef VM_ENABLE +uint64_t MemoryUnit::get_base_ppn() +{ + return satp_->get_base_ppn(); +} + +uint64_t MemoryUnit::get_satp() +{ + return satp_->get_satp(); +} + +uint8_t MemoryUnit::get_mode() +{ + return satp_->get_mode(); +} +void MemoryUnit::set_satp(uint64_t satp) +{ + // uint16_t asid = 0; // set asid for different process + satp_ = new SATP_t (satp ); +} + bool MemoryUnit::need_trans(uint64_t dev_pAddr) { // Check if the this is the BARE mode - bool isBAREMode = (this->mode == VA_MODE::BARE); + bool isBAREMode = (get_mode() == BARE); // Check if the address is reserved for system usage - bool isReserved = (dev_pAddr >= PAGE_TABLE_BASE_ADDR); + // bool isReserved = (PAGE_TABLE_BASE_ADDR <= dev_pAddr && dev_pAddr < PAGE_TABLE_BASE_ADDR + PT_SIZE_LIMIT); + bool isReserved = (PAGE_TABLE_BASE_ADDR <= dev_pAddr); // Check if the address is reserved for IO usage bool isIO= (dev_pAddr < USER_BASE_ADDR); // Check if the address falls within the startup address range @@ -634,7 +648,6 @@ uint64_t MemoryUnit::vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type) if (tlb_access.first) { - // printf("Found pfn %lx in TLB\n",tlb_access.second); pfn = tlb_access.second; TLB_HIT++; } @@ -649,91 +662,86 @@ uint64_t MemoryUnit::vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type) } //Construct final address using pfn and offset. - DBGPRINT(" [MMU: V2P] translated vAddr: 0x%lx to pAddr 0x%lx",vAddr,((pfn << size_bits) + (vAddr & ((1 << size_bits) - 1)))); + DBGPRINT(" [MMU: V2P] translated vAddr: 0x%lx to pAddr 0x%lx\n",vAddr,((pfn << size_bits) + (vAddr & ((1 << size_bits) - 1)))); return (pfn << size_bits) + (vAddr & ((1 << size_bits) - 1)); } -std::pair MemoryUnit::page_table_walk(uint64_t vAddr_bits, ACCESS_TYPE type, uint64_t* size_bits) -{ - DBGPRINT(" [MMU:PTW] Start: vaddr = 0x%lx, type = %u, size_bits %lu\n", vAddr_bits, type, *size_bits); - uint64_t LEVELS = 2; - vAddr_SV32_t vAddr(vAddr_bits); - uint64_t pte_bytes = 0; +uint64_t MemoryUnit::get_pte_address(uint64_t base_ppn, uint64_t vpn) +{ + return (base_ppn * PT_SIZE) + (vpn * PTE_SIZE); +} - uint64_t pte_addr =0; - //Get base page table. - uint64_t pt_ba = this->ptbr << 12; - int i = LEVELS - 1; +std::pair MemoryUnit::page_table_walk(uint64_t vAddr_bits, ACCESS_TYPE type, uint64_t *size_bits) +{ + DBGPRINT(" [MMU:PTW] Start: vaddr = 0x%lx, type = %u.\n", vAddr_bits, type); + uint8_t level = PT_LEVEL; + int i = level-1; + vAddr_t vaddr(vAddr_bits); + uint32_t flags =0; + uint64_t pte_addr = 0, pte_bytes = 0; + uint64_t cur_base_ppn = get_base_ppn(); + // Need to fix for super page + *size_bits = 12; - while(true) + while (true) + { + // Read PTE. + pte_addr = get_pte_address(cur_base_ppn, vaddr.vpn[i]); + decoder_.read(&pte_bytes, pte_addr, PTE_SIZE); + PTE_t pte(pte_bytes); + DBGPRINT(" [MMU:PTW] Level[%u] pte_addr=0x%lx, pte_bytes =0x%lx, pte.ppn= 0x%lx, pte.flags = %u)\n", i, pte_addr, pte_bytes, pte.ppn, pte.flags); + + assert(((pte.pte_bytes & 0xFFFFFFFF) != 0xbaadf00d) && "ERROR: uninitialzed PTE\n" ); + + // Check if it has invalid flag bits. + if ((pte.v == 0) | ((pte.r == 0) & (pte.w == 1))) { + assert(0); + throw Page_Fault_Exception(" [MMU:PTW] Page Fault : Attempted to access invalid entry."); + } - //Read PTE. - pte_addr = pt_ba+vAddr.vpn[i] * PTE_SIZE; - decoder_.read(&pte_bytes, pte_addr, PTE_SIZE); - PTE_SV32_t pte(pte_bytes); - DBGPRINT(" [MMU:PTW] Level[%u] pte_bytes = 0x%lx, pte flags = %u)\n", i, pte.ppn , pte.flags); - - //Check if it has invalid flag bits. - if ( (pte.v == 0) | ( (pte.r == 0) & (pte.w == 1) ) ) + if ((pte.r == 0) & (pte.w == 0) & (pte.x == 0)) + { + // Not a leaf node as rwx == 000 + i--; + if (i < 0) { - throw Page_Fault_Exception(" [MMU:PTW] Page Fault : Attempted to access invalid entry."); - } - - if ( (pte.r == 0) & (pte.w == 0) & (pte.x == 0)) - { - //Not a leaf node as rwx == 000 - i--; - if (i < 0) - { - throw Page_Fault_Exception(" [MMU:PTW] Page Fault : No leaf node found."); - } - else - { - //Continue on to next level. - pt_ba = (pte_bytes >> 10 ) << 12; - } + assert(0); + throw Page_Fault_Exception(" [MMU:PTW] Page Fault : No leaf node found."); } else { - //Leaf node found, finished walking. - pt_ba = (pte_bytes >> 10 ) << 12; - break; + // Continue on to next level. + cur_base_ppn= pte.ppn; + DBGPRINT(" [MMU:PTW] next base_ppn: 0x%lx\n", cur_base_ppn); + continue; } } - - PTE_SV32_t pte(pte_bytes); - - //Check RWX permissions according to access type. - if ( (type == ACCESS_TYPE::FENCE) & ((pte.r == 0) | (pte.x == 0)) ) + else { - throw Page_Fault_Exception(" [MMU:PTW] Page Fault : TYPE FENCE, Incorrect permissions."); + // Leaf node found, finished walking. + // Check RWX permissions according to access type. + if ((type == ACCESS_TYPE::FETCH) & ((pte.r == 0) | (pte.x == 0))) + { + assert(0); + throw Page_Fault_Exception(" [MMU:PTW] Page Fault : TYPE FETCH, Incorrect permissions."); + } + else if ((type == ACCESS_TYPE::LOAD) & (pte.r == 0)) + { + assert(0); + throw Page_Fault_Exception(" [MMU:PTW] Page Fault : TYPE LOAD, Incorrect permissions."); + } + else if ((type == ACCESS_TYPE::STORE) & (pte.w == 0)) + { + assert(0); + throw Page_Fault_Exception(" [MMU:PTW] Page Fault : TYPE STORE, Incorrect permissions."); + } + cur_base_ppn = pte.ppn; + flags = pte.flags; + break; } - else if ( (type == ACCESS_TYPE::LOAD) & (pte.r == 0) ) - { - throw Page_Fault_Exception(" [MMU:PTW] Page Fault : TYPE LOAD, Incorrect permissions."); - } - else if ( (type == ACCESS_TYPE::STORE) & (pte.w == 0) ) - { - throw Page_Fault_Exception(" [MMU:PTW] Page Fault : TYPE STORE, Incorrect permissions."); - } - *size_bits = 12; - uint64_t pfn = pt_ba >> *size_bits; - return std::make_pair(pfn, pte_bytes & 0xff); + } + return std::make_pair(cur_base_ppn, flags); } -uint64_t MemoryUnit::get_satp() -{ - return satp; -} -void MemoryUnit::set_satp(uint64_t satp) -{ - this->satp = satp; - this->ptbr = satp & ( (1<< SATP_PPN_WIDTH) - 1); -#ifdef XLEN_32 - this->mode = satp & (1<< SATP_MODE_IDX) ? VA_MODE::SV32 : VA_MODE::BARE; -#else // 64 bit - this->mode = satp & (1<< SATP_MODE_IDX) ? VA_MODE::SV64 : VA_MODE::BARE; -#endif -} #endif \ No newline at end of file diff --git a/sim/common/mem.h b/sim/common/mem.h index 4b7744c2b..9f212e184 100644 --- a/sim/common/mem.h +++ b/sim/common/mem.h @@ -32,17 +32,85 @@ namespace vortex { #ifdef VM_ENABLE -enum VA_MODE { - BARE, - SV32, - SV64 -}; + +// VA MODE +#define BARE 0x0 +#define SV32 0x1 +#define SV39 0x8 enum ACCESS_TYPE { LOAD, STORE, - FENCE + FETCH }; +class SATP_t +{ + private: + uint64_t address; + uint16_t asid; + uint8_t mode; + uint64_t ppn; + uint64_t satp; + + uint64_t bits(uint64_t input, uint8_t s_idx, uint8_t e_idx) + { + return (input>> s_idx) & (((uint64_t)1 << (e_idx - s_idx + 1)) - 1); + } + bool bit(uint64_t input , uint8_t idx) + { + return (input ) & ((uint64_t)1 << idx); + } + + public: + SATP_t(uint64_t satp) : satp(satp) + { +#ifdef XLEN_32 + mode = bit(satp, 31); + asid = bits(satp, 22, 30); + ppn = bits(satp, 0,21); +#else + mode = bits(satp, 60,63); + asid = bits(satp, 44, 59); + ppn = bits(satp, 0,43); +#endif + address = ppn << MEM_PAGE_LOG2_SIZE; + } + + SATP_t(uint64_t address, uint16_t asid) : address(address), asid(asid) + { +#ifdef XLEN_32 + assert((address >> 32) == 0 && "Upper 32 bits are not zero!"); +#endif + mode= VM_ADDR_MODE; + // asid = 0 ; + ppn = address >> MEM_PAGE_LOG2_SIZE; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshift-count-overflow" +#ifdef XLEN_32 + satp = (((uint64_t)mode << 31) | ((uint64_t)asid << 22) | ppn); +#else + satp = (((uint64_t)mode << 60) | ((uint64_t)asid << 44) | ppn); +#endif +#pragma GCC diagnostic pop + } + uint8_t get_mode() + { + return mode; + } + uint16_t get_asid() + { + return asid; + } + uint64_t get_base_ppn() + { + return ppn; + } + uint64_t get_satp() + { + return satp; + } +}; + class Page_Fault_Exception : public std::runtime_error /* or logic_error */ { @@ -119,6 +187,7 @@ public: #ifdef VM_ENABLE MemoryUnit(uint64_t pageSize = MEM_PAGE_SIZE); + ~MemoryUnit(){delete this->satp_;}; #else MemoryUnit(uint64_t pageSize = 0); #endif @@ -139,7 +208,9 @@ public: #ifdef VM_ENABLE void tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags, uint64_t size_bits); - uint64_t get_satp(); + uint64_t get_satp(); + uint8_t get_mode(); + uint64_t get_base_ppn(); void set_satp(uint64_t satp); #else void tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags); @@ -228,6 +299,7 @@ private: bool need_trans(uint64_t dev_pAddr); uint64_t vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type); + uint64_t get_pte_address(uint64_t base_ppn, uint64_t vpn); std::pair page_table_walk(uint64_t vAddr_bits, ACCESS_TYPE type, uint64_t* size_bits); #else uint64_t toPhyAddr(uint64_t vAddr, uint32_t flagMask); @@ -245,13 +317,9 @@ private: amo_reservation_t amo_reservation_; #ifdef VM_ENABLE - - uint64_t satp; - VA_MODE mode; - uint64_t ptbr; - std::unordered_set unique_translations; uint64_t TLB_HIT, TLB_MISS, TLB_EVICT, PTW, PERF_UNIQUE_PTW; + SATP_t *satp_; #endif }; @@ -322,68 +390,146 @@ private: }; #ifdef VM_ENABLE -class PTE_SV32_t +class PTE_t { private: uint64_t address; - uint64_t bits(uint64_t addr, uint8_t s_idx, uint8_t e_idx) + uint64_t bits(uint64_t input, uint8_t s_idx, uint8_t e_idx) { - return (addr >> s_idx) & ((1 << (e_idx - s_idx + 1)) - 1); + return (input>> s_idx) & (((uint64_t)1 << (e_idx - s_idx + 1)) - 1); } - bool bit(uint8_t idx) + bool bit(uint64_t input, uint8_t idx) { - return (address) & (1 << idx); + return (input) & ((uint64_t)1 << idx); } public: +#if VM_ADDR_MODE == SV39 + bool N; + uint8_t PBMT; +#endif uint64_t ppn; uint32_t rsw; uint32_t flags; + uint8_t level; bool d, a, g, u, x, w, r, v; - PTE_SV32_t(uint64_t address) : address(address) - { - assert((address>> 32) == 0 && "Upper 32 bits are not zero!"); - flags = bits(address,0,7); - rsw = bits(address,8,9); - ppn = bits(address,10,31); + uint64_t pte_bytes; - d = bit(7); - a = bit(6); - g = bit(5); - u = bit(4); - x = bit(3); - w = bit(2); - r = bit(1); - v = bit(0); - // printf("ppn = 0x%lx, flags= 0x%x, rsw= 0x%x\n",ppn,flags,rsw); + void set_flags (uint32_t flag) + { + this->flags = flag; + d = bit(flags,7); + a = bit(flags,6); + g = bit(flags,5); + u = bit(flags,4); + x = bit(flags,3); + w = bit(flags,2); + r = bit(flags,1); + v = bit(flags,0); + } + + PTE_t(uint64_t address, uint32_t flags) : address(address) + { +#if VM_ADDR_MODE == SV39 + N = 0; + PBMT = 0; + level = 3; + ppn = address >> MEM_PAGE_LOG2_SIZE; + // Reserve for Super page support + // ppn = new uint32_t [level]; + // ppn[2]=bits(address,28,53); + // ppn[1]=bits(address,19,27); + // ppn[0]=bits(address,10,18); + set_flags(flags); + // pte_bytes = (N << 63) | (PBMT << 61) | (ppn <<10) | flags ; + pte_bytes = (ppn <<10) | flags ; +#else // if VM_ADDR_MODE == SV32 + assert((address>> 32) == 0 && "Upper 32 bits are not zero!"); + level = 2; + ppn = address >> MEM_PAGE_LOG2_SIZE; + // Reserve for Super page support + // ppn = new uint32_t[level]; + // ppn[1]=bits(address,20,31); + // ppn[0]=bits(address,10,19); + set_flags(flags); + pte_bytes = ppn <<10 | flags ; +#endif + } + + PTE_t(uint64_t pte_bytes) : pte_bytes(pte_bytes) + { +#if VM_ADDR_MODE == SV39 + N = bit(pte_bytes,63); + PBMT = bits(pte_bytes,61,62); + level = 3; + ppn=bits(pte_bytes,10,53); + address = ppn << MEM_PAGE_LOG2_SIZE; + // Reserve for Super page support + // ppn = new uint32_t [level]; + // ppn[2]=bits(pte_bytes,28,53); + // ppn[1]=bits(pte_bytes,19,27); + // ppn[0]=bits(pte_bytes,10,18); +#else //#if VM_ADDR_MODE == SV32 + assert((pte_bytes >> 32) == 0 && "Upper 32 bits are not zero!"); + level = 2; + ppn=bits(pte_bytes,10, 31); + address = ppn << MEM_PAGE_LOG2_SIZE; + // Reserve for Super page support + // ppn = new uint32_t[level]; + // ppn[1]=bits(address, 20,31); + // ppn[0]=bits(address, 10,19); +#endif + rsw = bits(pte_bytes,8,9); + set_flags((uint32_t)(bits(pte_bytes,0,7))); + } + ~PTE_t() + { + // Reserve for Super page support + // delete ppn; } }; -class vAddr_SV32_t +class vAddr_t { private: uint64_t address; - uint64_t bits(uint64_t addr, uint8_t s_idx, uint8_t e_idx) + uint64_t bits(uint8_t s_idx, uint8_t e_idx) { - return (addr >> s_idx) & ((1 << (e_idx - s_idx + 1)) - 1); + return (address>> s_idx) & (((uint64_t)1 << (e_idx - s_idx + 1)) - 1); } - bool bit(uint64_t addr, uint8_t idx) + bool bit( uint8_t idx) { - return (addr) & (1 << idx); + return (address) & ((uint64_t)1 << idx); } public: - uint64_t vpn[2]; + uint64_t *vpn; uint64_t pgoff; - vAddr_SV32_t(uint64_t address) : address(address) + uint8_t level; + vAddr_t(uint64_t address) : address(address) { +#if VM_ADDR_MODE == SV39 + level = 3; + vpn = new uint64_t [level]; + vpn[2] = bits(30,38); + vpn[1] = bits(21,29); + vpn[0] = bits(12,20); + pgoff = bits(0,11); +#else //#if VM_ADDR_MODE == SV32 assert((address>> 32) == 0 && "Upper 32 bits are not zero!"); - vpn[0] = bits(address,12,21); - vpn[1] = bits(address,22,31); - pgoff = bits(address,0,11); - // printf("vpn[1] = 0x%lx, vpn[0] = 0x%lx, pgoff = 0x%lx\n",vpn[1],vpn[0],pgoff); + level = 2; + vpn = new uint64_t [level]; + vpn[1] = bits(22,31); + vpn[0] = bits(12,21); + pgoff = bits(0,11); +#endif + } + + ~vAddr_t() + { + delete vpn; } }; #endif diff --git a/sim/simx/emulator.cpp b/sim/simx/emulator.cpp index a1ee0072d..503e21cd9 100644 --- a/sim/simx/emulator.cpp +++ b/sim/simx/emulator.cpp @@ -116,7 +116,7 @@ void Emulator::clear() { void Emulator::attach_ram(RAM* ram) { // bind RAM to memory unit #if (XLEN == 64) - mmu_.attach(*ram, 0, 0xFFFFFFFFFFFFFFFF); + mmu_.attach(*ram, 0, 0x7FFFFFFFFF); //39bit SV39 #else mmu_.attach(*ram, 0, 0xFFFFFFFF); #endif @@ -271,11 +271,11 @@ bool Emulator::barrier(uint32_t bar_id, uint32_t count, uint32_t wid) { #ifdef VM_ENABLE void Emulator::icache_read(void *data, uint64_t addr, uint32_t size) { - // DP(1, "*** icache_read 0x" << std::hex << addr << ", size = 0x " << size); + DP(3, "*** icache_read 0x" << std::hex << addr << ", size = 0x " << size); try { - mmu_.read(data, addr, size, ACCESS_TYPE::LOAD); + mmu_.read(data, addr, size, ACCESS_TYPE::FETCH); } catch (Page_Fault_Exception& page_fault) { @@ -306,8 +306,7 @@ void Emulator::dcache_read(void *data, uint64_t addr, uint32_t size) { } else { try { - // mmu_.read(data, addr, size, 0); - mmu_.read(data, addr, size, ACCESS_TYPE::LOAD); + mmu_.read(data, addr, size, ACCESS_TYPE::LOAD); } catch (Page_Fault_Exception& page_fault) { diff --git a/sim/simx/main.cpp b/sim/simx/main.cpp index a8883c696..cd375b516 100644 --- a/sim/simx/main.cpp +++ b/sim/simx/main.cpp @@ -84,7 +84,7 @@ int main(int argc, char **argv) { Arch arch(num_threads, num_warps, num_cores); // create memory module - RAM ram(0, RAM_PAGE_SIZE); + RAM ram(0, MEM_PAGE_SIZE); // create processor Processor processor(arch); diff --git a/sim/simx/processor.cpp b/sim/simx/processor.cpp index 972792bfb..751db635e 100644 --- a/sim/simx/processor.cpp +++ b/sim/simx/processor.cpp @@ -149,6 +149,9 @@ Processor::Processor(const Arch& arch) Processor::~Processor() { delete impl_; +#ifdef VM_ENABLE + delete satp_; +#endif } void Processor::attach_ram(RAM* mem) { @@ -164,13 +167,19 @@ void Processor::dcr_write(uint32_t addr, uint32_t value) { } #ifdef VM_ENABLE -uint64_t Processor::get_satp() { - // std::cout << "get SATP: 0x" << std::hex << this->satp << std::endl; - return this->satp; -} - -void Processor::set_satp(uint64_t satp) { +int16_t Processor::set_satp_by_addr(uint64_t base_addr) { + uint16_t asid = 0; + satp_ = new SATP_t (base_addr,asid); + if (satp_ == NULL) + return 1; + uint64_t satp = satp_->get_satp(); impl_->set_satp(satp); - this->satp = satp; + return 0; +} +uint8_t Processor::get_satp_mode() { + return satp_->get_mode(); +} +uint64_t Processor::get_base_ppn() { + return satp_->get_base_ppn(); } #endif diff --git a/sim/simx/processor.h b/sim/simx/processor.h index d2b575421..a20cfff0b 100644 --- a/sim/simx/processor.h +++ b/sim/simx/processor.h @@ -22,6 +22,9 @@ namespace vortex { class Arch; class RAM; class ProcessorImpl; +#ifdef VM_ENABLE +class SATP_t; +#endif class Processor { public: @@ -34,14 +37,15 @@ public: void dcr_write(uint32_t addr, uint32_t value); #ifdef VM_ENABLE - uint64_t get_satp(); - void set_satp(uint64_t satp); + uint8_t get_satp_mode(); + uint64_t get_base_ppn(); + int16_t set_satp_by_addr(uint64_t addr); #endif private: ProcessorImpl* impl_; #ifdef VM_ENABLE - uint64_t satp; + SATP_t *satp_; #endif }; diff --git a/tests/regression/diverge/kernel.cpp b/tests/regression/diverge/kernel.cpp index f0380e0e4..70b27fa79 100644 --- a/tests/regression/diverge/kernel.cpp +++ b/tests/regression/diverge/kernel.cpp @@ -62,7 +62,7 @@ void kernel_body(kernel_arg_t* __UNIFORM__ arg) { value *= 5; break; default: - assert(task_id < arg->num_points); + //assert(task_id < arg->num_points); break; } From c99e4b37b6ca6d60c91f40402847a099b55c5541 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Sun, 23 Jun 2024 11:24:10 -0400 Subject: [PATCH 43/75] Update README.md --- .travis.yml | 102 + ci/toolchain_env.sh.in | 9 +- docs/fpga_setup.md | 74 + hw/rtl/core/VX_gpr_slice.sv | 286 + hw/rtl/core/VX_pending_instr.sv | 79 + hw/rtl/core/VX_trace.vh | 387 + miscs/patches/ramulator.patch | 46 + tests/opencl/bfs/graph4096.txt | 28677 ++++++++++++++++++++++++++++++ 8 files changed, 29656 insertions(+), 4 deletions(-) create mode 100644 .travis.yml create mode 100644 docs/fpga_setup.md create mode 100644 hw/rtl/core/VX_gpr_slice.sv create mode 100644 hw/rtl/core/VX_pending_instr.sv create mode 100644 hw/rtl/core/VX_trace.vh create mode 100644 miscs/patches/ramulator.patch create mode 100755 tests/opencl/bfs/graph4096.txt diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..d43abb153 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,102 @@ +language: cpp +dist: focal +os: linux +compiler: gcc + +addons: + apt: + packages: + - build-essential + - valgrind + - libstdc++6 + - binutils + - python + - uuid-dev + +env: + global: + - TOOLDIR=$HOME/tools + +cache: + directories: + - $TOOLDIR + - $HOME/third_party + - $HOME/build32 + - $HOME/build64 + +before_install: + - if [ ! -d "$TOOLDIR" ] || [ -z "$(ls -A $TOOLDIR)" ] || [ "$(cat "$TOOLDIR/version.txt")" != "v0.4" ]; then + rm -rf $TOOLDIR; + mkdir -p $TRAVIS_BUILD_DIR/build && cd $TRAVIS_BUILD_DIR/build; + ../configure --tooldir=$TOOLDIR; + ci/toolchain_install.sh --all; + echo "v0.3" > "$TOOLDIR/version.txt"; + else + echo "using existing tooldir build"; + fi + - if [ ! -d "$HOME/third_party" ] || [ -z "$(ls -A $HOME/third_party)" ] || [ "$(cat "$HOME/third_party/version.txt")" != "v0.2" ]; then + cd $TRAVIS_BUILD_DIR; + make -C third_party > /dev/null; + echo "v0.2" > "third_party/version.txt"; + cp -rf third_party $HOME; + else + echo "using existing third_party build"; + cp -rf $HOME/third_party $TRAVIS_BUILD_DIR; + fi + +install: + - if [ ! -d "$HOME/build$XLEN" ] || [ -z "$(ls -A $HOME/build$XLEN)" ] || [ "$(cat "$HOME/build$XLEN/version.txt")" != "$TRAVIS_COMMIT" ]; then + mkdir -p $TRAVIS_BUILD_DIR/build$XLEN && cd $TRAVIS_BUILD_DIR/build$XLEN; + ../configure --tooldir=$TOOLDIR --xlen=$XLEN; + source ci/toolchain_env.sh; + make build -s > /dev/null; + echo "$TRAVIS_COMMIT" > version.txt; + cp -rf $TRAVIS_BUILD_DIR/build$XLEN $HOME; + else + echo "using existing build for commit $TRAVIS_COMMIT"; + cp -rf $HOME/build$XLEN $TRAVIS_BUILD_DIR; + fi + +before_script: + - cd $TRAVIS_BUILD_DIR/build$XLEN + - source ci/toolchain_env.sh + +stages: + - test + +jobs: + include: + - stage: test + name: regression32 + env: XLEN=32 + script: + - ./ci/travis_run.py ./ci/regression.sh --unittest + - ./ci/travis_run.py ./ci/regression.sh --isa + - ./ci/travis_run.py ./ci/regression.sh --kernel + - ./ci/travis_run.py ./ci/regression.sh --synthesis + - ./ci/travis_run.py ./ci/regression.sh --regression + - ./ci/travis_run.py ./ci/regression.sh --opencl + + - stage: test + name: regression64 + env: XLEN=64 + script: + - ./ci/travis_run.py ./ci/regression.sh --isa + - ./ci/travis_run.py ./ci/regression.sh --kernel + - ./ci/travis_run.py ./ci/regression.sh --synthesis + - ./ci/travis_run.py ./ci/regression.sh --regression + - ./ci/travis_run.py ./ci/regression.sh --opencl + + - stage: test + name: config + env: XLEN=32 + script: + - ./ci/travis_run.py ./ci/regression.sh --cluster + - ./ci/travis_run.py ./ci/regression.sh --config + + - stage: test + name: debug + env: XLEN=32 + script: + - ./ci/travis_run.py ./ci/regression.sh --debug + - ./ci/travis_run.py ./ci/regression.sh --stress \ No newline at end of file diff --git a/ci/toolchain_env.sh.in b/ci/toolchain_env.sh.in index 9fcfdbb89..dc50389a9 100755 --- a/ci/toolchain_env.sh.in +++ b/ci/toolchain_env.sh.in @@ -1,13 +1,13 @@ #!/bin/sh # Copyright 2019-2023 -# +# # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at -# +# # http://www.apache.org/licenses/LICENSE-2.0 -# +# # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,7 +16,8 @@ TOOLDIR=${TOOLDIR:=@TOOLDIR@} -export PATH=$TOOLDIR/verilator/bin:$PATH +export VERILATOR_ROOT=$TOOLDIR/verilator +export PATH=$VERILATOR_ROOT/bin:$PATH export SV2V_PATH=$TOOLDIR/sv2v export PATH=$SV2V_PATH/bin:$PATH diff --git a/docs/fpga_setup.md b/docs/fpga_setup.md new file mode 100644 index 000000000..80d71e45f --- /dev/null +++ b/docs/fpga_setup.md @@ -0,0 +1,74 @@ +# FPGA Startup and Configuration Guide + +OPAE Environment Setup +---------------------- + + $ source /opt/inteldevstack/init_env_user.sh + $ export OPAE_HOME=/opt/opae/1.1.2 + $ export PATH=$OPAE_HOME/bin:$PATH + $ export C_INCLUDE_PATH=$OPAE_HOME/include:$C_INCLUDE_PATH + $ export LIBRARY_PATH=$OPAE_HOME/lib:$LIBRARY_PATH + $ export LD_LIBRARY_PATH=$OPAE_HOME/lib:$LD_LIBRARY_PATH + +OPAE Build +------------------ + +The FPGA has to following configuration options: +- DEVICE_FAMILY=arria10 | stratix10 +- NUM_CORES=#n + +Command line: + + $ cd hw/syn/altera/opae + $ PREFIX=test1 TARGET=fpga NUM_CORES=4 make + +A new folder (ex: `test1_xxx_4c`) will be created and the build will start and take ~30-480 min to complete. +Setting TARGET=ase will build the project for simulation using Intel ASE. + + +OPAE Build Configuration +------------------------ + +The hardware configuration file `/hw/rtl/VX_config.vh` defines all the hardware parameters that can be modified when build the processor.For example, have the following parameters that can be configured: +- `NUM_WARPS`: Number of warps per cores +- `NUM_THREADS`: Number of threads per warps +- `PERF_ENABLE`: enable the use of all profile counters + +You configure the syntesis build from the command line: + + $ CONFIGS="-DPERF_ENABLE -DNUM_THREADS=8" make + +OPAE Build Progress +------------------- + +You could check the last 10 lines in the build log for possible errors until build completion. + + $ tail -n 10 /build.log + +Check if the build is still running by looking for quartus_sh, quartus_syn, or quartus_fit programs. + + $ ps -u + +If the build fails and you need to restart it, clean up the build folder using the following command: + + $ make clean + +The file `vortex_afu.gbs` should exist when the build is done: + + $ ls -lsa /synth/vortex_afu.gbs + + +Signing the bitstream and Programming the FPGA +---------------------------------------------- + + $ cd + $ PACSign PR -t UPDATE -H openssl_manager -i vortex_afu.gbs -o vortex_afu_unsigned_ssl.gbs + $ fpgasupdate vortex_afu_unsigned_ssl.gbs + +FPGA sample test running OpenCL sgemm kernel +-------------------------------------------- + +Run the following from the Vortex root directory + + $ TARGET=fpga ./ci/blackbox.sh --driver=opae --app=sgemm --args="-n128" + diff --git a/hw/rtl/core/VX_gpr_slice.sv b/hw/rtl/core/VX_gpr_slice.sv new file mode 100644 index 000000000..b036fc555 --- /dev/null +++ b/hw/rtl/core/VX_gpr_slice.sv @@ -0,0 +1,286 @@ +// Copyright © 2019-2023 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +`include "VX_define.vh" + +module VX_gpr_slice import VX_gpu_pkg::*; #( + parameter CORE_ID = 0, + parameter CACHE_ENABLE = 0 +) ( + input wire clk, + input wire reset, + + VX_writeback_if.slave writeback_if, + VX_scoreboard_if.slave scoreboard_if, + VX_operands_if.master operands_if +); + `UNUSED_PARAM (CORE_ID) + localparam DATAW = `UUID_WIDTH + ISSUE_WIS_W + `NUM_THREADS + `PC_BITS + 1 + `EX_BITS + `INST_OP_BITS + `INST_ARGS_BITS + `NR_BITS; + localparam RAM_ADDRW = `LOG2UP(`NUM_REGS * ISSUE_RATIO); + + localparam STATE_IDLE = 2'd0; + localparam STATE_FETCH1 = 2'd1; + localparam STATE_FETCH2 = 2'd2; + localparam STATE_FETCH3 = 2'd3; + localparam STATE_BITS = 2; + + wire [`NUM_THREADS-1:0][`XLEN-1:0] gpr_rd_data; + reg [`NR_BITS-1:0] gpr_rd_rid, gpr_rd_rid_n; + reg [ISSUE_WIS_W-1:0] gpr_rd_wis, gpr_rd_wis_n; + + reg [`NUM_THREADS-1:0][`XLEN-1:0] cache_data [ISSUE_RATIO-1:0]; + reg [`NUM_THREADS-1:0][`XLEN-1:0] cache_data_n [ISSUE_RATIO-1:0]; + reg [`NR_BITS-1:0] cache_reg [ISSUE_RATIO-1:0]; + reg [`NR_BITS-1:0] cache_reg_n [ISSUE_RATIO-1:0]; + reg [`NUM_THREADS-1:0] cache_tmask [ISSUE_RATIO-1:0]; + reg [`NUM_THREADS-1:0] cache_tmask_n [ISSUE_RATIO-1:0]; + reg [ISSUE_RATIO-1:0] cache_eop, cache_eop_n; + + reg [`NUM_THREADS-1:0][`XLEN-1:0] rs1_data, rs1_data_n; + reg [`NUM_THREADS-1:0][`XLEN-1:0] rs2_data, rs2_data_n; + reg [`NUM_THREADS-1:0][`XLEN-1:0] rs3_data, rs3_data_n; + + reg [STATE_BITS-1:0] state, state_n; + reg [`NR_BITS-1:0] rs2, rs2_n; + reg [`NR_BITS-1:0] rs3, rs3_n; + reg rs2_ready, rs2_ready_n; + reg rs3_ready, rs3_ready_n; + reg data_ready, data_ready_n; + + wire stg_valid_in, stg_ready_in; + + wire is_rs1_zero = (scoreboard_if.data.rs1 == 0); + wire is_rs2_zero = (scoreboard_if.data.rs2 == 0); + wire is_rs3_zero = (scoreboard_if.data.rs3 == 0); + + always @(*) begin + state_n = state; + rs2_n = rs2; + rs3_n = rs3; + rs2_ready_n = rs2_ready; + rs3_ready_n = rs3_ready; + rs1_data_n = rs1_data; + rs2_data_n = rs2_data; + rs3_data_n = rs3_data; + cache_data_n = cache_data; + cache_reg_n = cache_reg; + cache_tmask_n= cache_tmask; + cache_eop_n = cache_eop; + gpr_rd_rid_n = gpr_rd_rid; + gpr_rd_wis_n = gpr_rd_wis; + data_ready_n = data_ready; + + case (state) + STATE_IDLE: begin + if (operands_if.valid && operands_if.ready) begin + data_ready_n = 0; + end + if (scoreboard_if.valid && data_ready_n == 0) begin + data_ready_n = 1; + if (is_rs3_zero || (CACHE_ENABLE != 0 && + scoreboard_if.data.rs3 == cache_reg[scoreboard_if.data.wis] && + (scoreboard_if.data.tmask & cache_tmask[scoreboard_if.data.wis]) == scoreboard_if.data.tmask)) begin + rs3_data_n = (is_rs3_zero || CACHE_ENABLE == 0) ? '0 : cache_data[scoreboard_if.data.wis]; + rs3_ready_n = 1; + end else begin + rs3_ready_n = 0; + gpr_rd_rid_n = scoreboard_if.data.rs3; + data_ready_n = 0; + state_n = STATE_FETCH3; + end + if (is_rs2_zero || (CACHE_ENABLE != 0 && + scoreboard_if.data.rs2 == cache_reg[scoreboard_if.data.wis] && + (scoreboard_if.data.tmask & cache_tmask[scoreboard_if.data.wis]) == scoreboard_if.data.tmask)) begin + rs2_data_n = (is_rs2_zero || CACHE_ENABLE == 0) ? '0 : cache_data[scoreboard_if.data.wis]; + rs2_ready_n = 1; + end else begin + rs2_ready_n = 0; + gpr_rd_rid_n = scoreboard_if.data.rs2; + data_ready_n = 0; + state_n = STATE_FETCH2; + end + if (is_rs1_zero || (CACHE_ENABLE != 0 && + scoreboard_if.data.rs1 == cache_reg[scoreboard_if.data.wis] && + (scoreboard_if.data.tmask & cache_tmask[scoreboard_if.data.wis]) == scoreboard_if.data.tmask)) begin + rs1_data_n = (is_rs1_zero || CACHE_ENABLE == 0) ? '0 : cache_data[scoreboard_if.data.wis]; + end else begin + gpr_rd_rid_n = scoreboard_if.data.rs1; + data_ready_n = 0; + state_n = STATE_FETCH1; + end + end + gpr_rd_wis_n = scoreboard_if.data.wis; + rs2_n = scoreboard_if.data.rs2; + rs3_n = scoreboard_if.data.rs3; + end + STATE_FETCH1: begin + rs1_data_n = gpr_rd_data; + if (~rs2_ready) begin + gpr_rd_rid_n = rs2; + state_n = STATE_FETCH2; + end else if (~rs3_ready) begin + gpr_rd_rid_n = rs3; + state_n = STATE_FETCH3; + end else begin + data_ready_n = 1; + state_n = STATE_IDLE; + end + end + STATE_FETCH2: begin + rs2_data_n = gpr_rd_data; + if (~rs3_ready) begin + gpr_rd_rid_n = rs3; + state_n = STATE_FETCH3; + end else begin + data_ready_n = 1; + state_n = STATE_IDLE; + end + end + STATE_FETCH3: begin + rs3_data_n = gpr_rd_data; + data_ready_n = 1; + state_n = STATE_IDLE; + end + endcase + + if (CACHE_ENABLE != 0 && writeback_if.valid) begin + if ((cache_reg[writeback_if.data.wis] == writeback_if.data.rd) + || (cache_eop[writeback_if.data.wis] && writeback_if.data.sop)) begin + for (integer j = 0; j < `NUM_THREADS; ++j) begin + if (writeback_if.data.tmask[j]) begin + cache_data_n[writeback_if.data.wis][j] = writeback_if.data.data[j]; + end + end + cache_reg_n[writeback_if.data.wis] = writeback_if.data.rd; + cache_eop_n[writeback_if.data.wis] = writeback_if.data.eop; + cache_tmask_n[writeback_if.data.wis] = writeback_if.data.sop ? writeback_if.data.tmask : + (cache_tmask_n[writeback_if.data.wis] | writeback_if.data.tmask); + end + end + end + + always @(posedge clk) begin + if (reset) begin + state <= STATE_IDLE; + cache_eop <= {ISSUE_RATIO{1'b1}}; + data_ready <= 0; + end else begin + state <= state_n; + cache_eop <= cache_eop_n; + data_ready <= data_ready_n; + end + gpr_rd_rid <= gpr_rd_rid_n; + gpr_rd_wis <= gpr_rd_wis_n; + rs2_ready <= rs2_ready_n; + rs3_ready <= rs3_ready_n; + rs2 <= rs2_n; + rs3 <= rs3_n; + rs1_data <= rs1_data_n; + rs2_data <= rs2_data_n; + rs3_data <= rs3_data_n; + cache_data <= cache_data_n; + cache_reg <= cache_reg_n; + cache_tmask <= cache_tmask_n; + end + + assign stg_valid_in = scoreboard_if.valid && data_ready; + assign scoreboard_if.ready = stg_ready_in && data_ready; + + VX_toggle_buffer #( + .DATAW (DATAW) + ) toggle_buffer ( + .clk (clk), + .reset (reset), + .valid_in (stg_valid_in), + .data_in ({ + scoreboard_if.data.uuid, + scoreboard_if.data.wis, + scoreboard_if.data.tmask, + scoreboard_if.data.PC, + scoreboard_if.data.wb, + scoreboard_if.data.ex_type, + scoreboard_if.data.op_type, + scoreboard_if.data.op_args, + scoreboard_if.data.rd + }), + .ready_in (stg_ready_in), + .valid_out (operands_if.valid), + .data_out ({ + operands_if.data.uuid, + operands_if.data.wis, + operands_if.data.tmask, + operands_if.data.PC, + operands_if.data.wb, + operands_if.data.ex_type, + operands_if.data.op_type, + operands_if.data.op_args, + operands_if.data.rd + }), + .ready_out (operands_if.ready) + ); + + assign operands_if.data.rs1_data = rs1_data; + assign operands_if.data.rs2_data = rs2_data; + assign operands_if.data.rs3_data = rs3_data; + + // GPR banks + + reg [RAM_ADDRW-1:0] gpr_rd_addr; + wire [RAM_ADDRW-1:0] gpr_wr_addr; + if (ISSUE_WIS != 0) begin + assign gpr_wr_addr = {writeback_if.data.wis, writeback_if.data.rd}; + always @(posedge clk) begin + gpr_rd_addr <= {gpr_rd_wis_n, gpr_rd_rid_n}; + end + end else begin + assign gpr_wr_addr = writeback_if.data.rd; + always @(posedge clk) begin + gpr_rd_addr <= gpr_rd_rid_n; + end + end + +`ifdef GPR_RESET + reg wr_enabled = 0; + always @(posedge clk) begin + if (reset) begin + wr_enabled <= 1; + end + end +`endif + + for (genvar j = 0; j < `NUM_THREADS; ++j) begin + VX_dp_ram #( + .DATAW (`XLEN), + .SIZE (`NUM_REGS * ISSUE_RATIO), + `ifdef GPR_RESET + .INIT_ENABLE (1), + .INIT_VALUE (0), + `endif + .NO_RWCHECK (1) + ) gpr_ram ( + .clk (clk), + .read (1'b1), + `UNUSED_PIN (wren), + `ifdef GPR_RESET + .write (wr_enabled && writeback_if.valid && writeback_if.data.tmask[j]), + `else + .write (writeback_if.valid && writeback_if.data.tmask[j]), + `endif + .waddr (gpr_wr_addr), + .wdata (writeback_if.data.data[j]), + .raddr (gpr_rd_addr), + .rdata (gpr_rd_data[j]) + ); + end + +endmodule diff --git a/hw/rtl/core/VX_pending_instr.sv b/hw/rtl/core/VX_pending_instr.sv new file mode 100644 index 000000000..af87b53e0 --- /dev/null +++ b/hw/rtl/core/VX_pending_instr.sv @@ -0,0 +1,79 @@ +// Copyright © 2019-2023 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +`include "VX_define.vh" + +module VX_pending_instr #( + parameter CTR_WIDTH = 12, + parameter ALM_EMPTY = 1, + parameter DECR_COUNT = 1 +) ( + input wire clk, + input wire reset, + input wire incr, + input wire [`NW_WIDTH-1:0] incr_wid, + input wire [DECR_COUNT-1:0] decr, + input wire [DECR_COUNT-1:0][`NW_WIDTH-1:0] decr_wid, + input wire [`NW_WIDTH-1:0] alm_empty_wid, + output wire empty, + output wire alm_empty +); + localparam COUNTW = `CLOG2(DECR_COUNT+1); + + reg [`NUM_WARPS-1:0][CTR_WIDTH-1:0] pending_instrs; + reg [`NUM_WARPS-1:0][COUNTW-1:0] decr_cnt; + reg [`NUM_WARPS-1:0][DECR_COUNT-1:0] decr_mask; + reg [`NUM_WARPS-1:0] incr_cnt, incr_cnt_n; + reg [`NUM_WARPS-1:0] alm_empty_r, empty_r; + + always @(*) begin + incr_cnt_n = 0; + decr_mask = 0; + if (incr) begin + incr_cnt_n[incr_wid] = 1; + end + for (integer i = 0; i < DECR_COUNT; ++i) begin + if (decr[i]) begin + decr_mask[decr_wid[i]][i] = 1; + end + end + end + + for (genvar i = 0; i < `NUM_WARPS; ++i) begin + + wire [COUNTW-1:0] decr_cnt_n; + `POP_COUNT(decr_cnt_n, decr_mask[i]); + + wire [CTR_WIDTH-1:0] pending_instrs_n = pending_instrs[i] + CTR_WIDTH'(incr_cnt[i]) - CTR_WIDTH'(decr_cnt[i]); + + always @(posedge clk) begin + if (reset) begin + incr_cnt[i] <= '0; + decr_cnt[i] <= '0; + pending_instrs[i] <= '0; + alm_empty_r[i] <= 0; + empty_r[i] <= 1; + end else begin + incr_cnt[i] <= incr_cnt_n[i]; + decr_cnt[i] <= decr_cnt_n; + pending_instrs[i] <= pending_instrs_n; + alm_empty_r[i] <= (pending_instrs_n == ALM_EMPTY); + empty_r[i] <= (pending_instrs_n == 0); + end + end + end + + assign alm_empty = alm_empty_r[alm_empty_wid]; + assign empty = (& empty_r); + +endmodule diff --git a/hw/rtl/core/VX_trace.vh b/hw/rtl/core/VX_trace.vh new file mode 100644 index 000000000..5dc4bc304 --- /dev/null +++ b/hw/rtl/core/VX_trace.vh @@ -0,0 +1,387 @@ +// Copyright © 2019-2023 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +`ifndef VX_TRACE_VH +`define VX_TRACE_VH + +`ifdef SIMULATION + + task trace_ex_type(input int level, input [`EX_BITS-1:0] ex_type); + case (ex_type) + `EX_ALU: `TRACE(level, ("ALU")); + `EX_LSU: `TRACE(level, ("LSU")); + `EX_FPU: `TRACE(level, ("FPU")); + `EX_SFU: `TRACE(level, ("SFU")); + default: `TRACE(level, ("?")); + endcase + endtask + + task trace_ex_op(input int level, + input [`EX_BITS-1:0] ex_type, + input [`INST_OP_BITS-1:0] op_type, + input VX_gpu_pkg::op_args_t op_args + ); + case (ex_type) + `EX_ALU: begin + case (op_args.alu.xtype) + `ALU_TYPE_ARITH: begin + if (op_args.alu.is_w) begin + if (op_args.alu.use_imm) begin + case (`INST_ALU_BITS'(op_type)) + `INST_ALU_ADD: `TRACE(level, ("ADDIW")); + `INST_ALU_SLL: `TRACE(level, ("SLLIW")); + `INST_ALU_SRL: `TRACE(level, ("SRLIW")); + `INST_ALU_SRA: `TRACE(level, ("SRAIW")); + default: `TRACE(level, ("?")); + endcase + end else begin + case (`INST_ALU_BITS'(op_type)) + `INST_ALU_ADD: `TRACE(level, ("ADDW")); + `INST_ALU_SUB: `TRACE(level, ("SUBW")); + `INST_ALU_SLL: `TRACE(level, ("SLLW")); + `INST_ALU_SRL: `TRACE(level, ("SRLW")); + `INST_ALU_SRA: `TRACE(level, ("SRAW")); + default: `TRACE(level, ("?")); + endcase + end + end else begin + if (op_args.alu.use_imm) begin + case (`INST_ALU_BITS'(op_type)) + `INST_ALU_ADD: `TRACE(level, ("ADDI")); + `INST_ALU_SLL: `TRACE(level, ("SLLI")); + `INST_ALU_SRL: `TRACE(level, ("SRLI")); + `INST_ALU_SRA: `TRACE(level, ("SRAI")); + `INST_ALU_SLT: `TRACE(level, ("SLTI")); + `INST_ALU_SLTU: `TRACE(level, ("SLTIU")); + `INST_ALU_XOR: `TRACE(level, ("XORI")); + `INST_ALU_OR: `TRACE(level, ("ORI")); + `INST_ALU_AND: `TRACE(level, ("ANDI")); + `INST_ALU_LUI: `TRACE(level, ("LUI")); + `INST_ALU_AUIPC: `TRACE(level, ("AUIPC")); + default: `TRACE(level, ("?")); + endcase + end else begin + case (`INST_ALU_BITS'(op_type)) + `INST_ALU_ADD: `TRACE(level, ("ADD")); + `INST_ALU_SUB: `TRACE(level, ("SUB")); + `INST_ALU_SLL: `TRACE(level, ("SLL")); + `INST_ALU_SRL: `TRACE(level, ("SRL")); + `INST_ALU_SRA: `TRACE(level, ("SRA")); + `INST_ALU_SLT: `TRACE(level, ("SLT")); + `INST_ALU_SLTU: `TRACE(level, ("SLTU")); + `INST_ALU_XOR: `TRACE(level, ("XOR")); + `INST_ALU_OR: `TRACE(level, ("OR")); + `INST_ALU_AND: `TRACE(level, ("AND")); + `INST_ALU_CZEQ: `TRACE(level, ("CZERO.EQZ")); + `INST_ALU_CZNE: `TRACE(level, ("CZERO.NEZ")); + default: `TRACE(level, ("?")); + endcase + end + end + end + `ALU_TYPE_BRANCH: begin + case (`INST_BR_BITS'(op_type)) + `INST_BR_EQ: `TRACE(level, ("BEQ")); + `INST_BR_NE: `TRACE(level, ("BNE")); + `INST_BR_LT: `TRACE(level, ("BLT")); + `INST_BR_GE: `TRACE(level, ("BGE")); + `INST_BR_LTU: `TRACE(level, ("BLTU")); + `INST_BR_GEU: `TRACE(level, ("BGEU")); + `INST_BR_JAL: `TRACE(level, ("JAL")); + `INST_BR_JALR: `TRACE(level, ("JALR")); + `INST_BR_ECALL: `TRACE(level, ("ECALL")); + `INST_BR_EBREAK:`TRACE(level, ("EBREAK")); + `INST_BR_URET: `TRACE(level, ("URET")); + `INST_BR_SRET: `TRACE(level, ("SRET")); + `INST_BR_MRET: `TRACE(level, ("MRET")); + default: `TRACE(level, ("?")); + endcase + end + `ALU_TYPE_MULDIV: begin + if (op_args.alu.is_w) begin + case (`INST_M_BITS'(op_type)) + `INST_M_MUL: `TRACE(level, ("MULW")); + `INST_M_DIV: `TRACE(level, ("DIVW")); + `INST_M_DIVU: `TRACE(level, ("DIVUW")); + `INST_M_REM: `TRACE(level, ("REMW")); + `INST_M_REMU: `TRACE(level, ("REMUW")); + default: `TRACE(level, ("?")); + endcase + end else begin + case (`INST_M_BITS'(op_type)) + `INST_M_MUL: `TRACE(level, ("MUL")); + `INST_M_MULH: `TRACE(level, ("MULH")); + `INST_M_MULHSU:`TRACE(level, ("MULHSU")); + `INST_M_MULHU: `TRACE(level, ("MULHU")); + `INST_M_DIV: `TRACE(level, ("DIV")); + `INST_M_DIVU: `TRACE(level, ("DIVU")); + `INST_M_REM: `TRACE(level, ("REM")); + `INST_M_REMU: `TRACE(level, ("REMU")); + default: `TRACE(level, ("?")); + endcase + end + end + default: `TRACE(level, ("?")); + endcase + end + `EX_LSU: begin + if (op_args.lsu.is_float) begin + case (`INST_LSU_BITS'(op_type)) + `INST_LSU_LW: `TRACE(level, ("FLW")); + `INST_LSU_LD: `TRACE(level, ("FLD")); + `INST_LSU_SW: `TRACE(level, ("FSW")); + `INST_LSU_SD: `TRACE(level, ("FSD")); + default: `TRACE(level, ("?")); + endcase + end else begin + case (`INST_LSU_BITS'(op_type)) + `INST_LSU_LB: `TRACE(level, ("LB")); + `INST_LSU_LH: `TRACE(level, ("LH")); + `INST_LSU_LW: `TRACE(level, ("LW")); + `INST_LSU_LD: `TRACE(level, ("LD")); + `INST_LSU_LBU:`TRACE(level, ("LBU")); + `INST_LSU_LHU:`TRACE(level, ("LHU")); + `INST_LSU_LWU:`TRACE(level, ("LWU")); + `INST_LSU_SB: `TRACE(level, ("SB")); + `INST_LSU_SH: `TRACE(level, ("SH")); + `INST_LSU_SW: `TRACE(level, ("SW")); + `INST_LSU_SD: `TRACE(level, ("SD")); + `INST_LSU_FENCE:`TRACE(level,("FENCE")); + default: `TRACE(level, ("?")); + endcase + end + end + `EX_FPU: begin + case (`INST_FPU_BITS'(op_type)) + `INST_FPU_ADD: begin + if (op_args.fpu.fmt[0]) + `TRACE(level, ("FADD.D")); + else + `TRACE(level, ("FADD.S")); + end + `INST_FPU_SUB: begin + if (op_args.fpu.fmt[0]) + `TRACE(level, ("FSUB.D")); + else + `TRACE(level, ("FSUB.S")); + end + `INST_FPU_MUL: begin + if (op_args.fpu.fmt[0]) + `TRACE(level, ("FMUL.D")); + else + `TRACE(level, ("FMUL.S")); + end + `INST_FPU_DIV: begin + if (op_args.fpu.fmt[0]) + `TRACE(level, ("FDIV.D")); + else + `TRACE(level, ("FDIV.S")); + end + `INST_FPU_SQRT: begin + if (op_args.fpu.fmt[0]) + `TRACE(level, ("FSQRT.D")); + else + `TRACE(level, ("FSQRT.S")); + end + `INST_FPU_MADD: begin + if (op_args.fpu.fmt[0]) + `TRACE(level, ("FMADD.D")); + else + `TRACE(level, ("FMADD.S")); + end + `INST_FPU_MSUB: begin + if (op_args.fpu.fmt[0]) + `TRACE(level, ("FMSUB.D")); + else + `TRACE(level, ("FMSUB.S")); + end + `INST_FPU_NMADD: begin + if (op_args.fpu.fmt[0]) + `TRACE(level, ("FNMADD.D")); + else + `TRACE(level, ("FNMADD.S")); + end + `INST_FPU_NMSUB: begin + if (op_args.fpu.fmt[0]) + `TRACE(level, ("FNMSUB.D")); + else + `TRACE(level, ("FNMSUB.S")); + end + `INST_FPU_CMP: begin + if (op_args.fpu.fmt[0]) begin + case (op_args.fpu.frm[1:0]) + 0: `TRACE(level, ("FLE.D")); + 1: `TRACE(level, ("FLT.D")); + 2: `TRACE(level, ("FEQ.D")); + default: `TRACE(level, ("?")); + endcase + end else begin + case (op_args.fpu.frm[1:0]) + 0: `TRACE(level, ("FLE.S")); + 1: `TRACE(level, ("FLT.S")); + 2: `TRACE(level, ("FEQ.S")); + default: `TRACE(level, ("?")); + endcase + end + end + `INST_FPU_F2F: begin + if (op_args.fpu.fmt[0]) begin + `TRACE(level, ("FCVT.D.S")); + end else begin + `TRACE(level, ("FCVT.S.D")); + end + end + `INST_FPU_F2I: begin + if (op_args.fpu.fmt[0]) begin + if (op_args.fpu.fmt[1]) begin + `TRACE(level, ("FCVT.L.D")); + end else begin + `TRACE(level, ("FCVT.W.D")); + end + end else begin + if (op_args.fpu.fmt[1]) begin + `TRACE(level, ("FCVT.L.S")); + end else begin + `TRACE(level, ("FCVT.W.S")); + end + end + end + `INST_FPU_F2U: begin + if (op_args.fpu.fmt[0]) begin + if (op_args.fpu.fmt[1]) begin + `TRACE(level, ("FCVT.LU.D")); + end else begin + `TRACE(level, ("FCVT.WU.D")); + end + end else begin + if (op_args.fpu.fmt[1]) begin + `TRACE(level, ("FCVT.LU.S")); + end else begin + `TRACE(level, ("FCVT.WU.S")); + end + end + end + `INST_FPU_I2F: begin + if (op_args.fpu.fmt[0]) begin + if (op_args.fpu.fmt[1]) begin + `TRACE(level, ("FCVT.D.L")); + end else begin + `TRACE(level, ("FCVT.D.W")); + end + end else begin + if (op_args.fpu.fmt[1]) begin + `TRACE(level, ("FCVT.S.L")); + end else begin + `TRACE(level, ("FCVT.S.W")); + end + end + end + `INST_FPU_U2F: begin + if (op_args.fpu.fmt[0]) begin + if (op_args.fpu.fmt[1]) begin + `TRACE(level, ("FCVT.D.LU")); + end else begin + `TRACE(level, ("FCVT.D.WU")); + end + end else begin + if (op_args.fpu.fmt[1]) begin + `TRACE(level, ("FCVT.S.LU")); + end else begin + `TRACE(level, ("FCVT.S.WU")); + end + end + end + `INST_FPU_MISC: begin + if (op_args.fpu.fmt[0]) begin + case (op_args.fpu.frm) + 0: `TRACE(level, ("FSGNJ.D")); + 1: `TRACE(level, ("FSGNJN.D")); + 2: `TRACE(level, ("FSGNJX.D")); + 3: `TRACE(level, ("FCLASS.D")); + 4: `TRACE(level, ("FMV.X.D")); + 5: `TRACE(level, ("FMV.D.X")); + 6: `TRACE(level, ("FMIN.D")); + 7: `TRACE(level, ("FMAX.D")); + endcase + end else begin + case (op_args.fpu.frm) + 0: `TRACE(level, ("FSGNJ.S")); + 1: `TRACE(level, ("FSGNJN.S")); + 2: `TRACE(level, ("FSGNJX.S")); + 3: `TRACE(level, ("FCLASS.S")); + 4: `TRACE(level, ("FMV.X.S")); + 5: `TRACE(level, ("FMV.S.X")); + 6: `TRACE(level, ("FMIN.S")); + 7: `TRACE(level, ("FMAX.S")); + endcase + end + end + default: `TRACE(level, ("?")); + endcase + end + `EX_SFU: begin + case (`INST_SFU_BITS'(op_type)) + `INST_SFU_TMC: `TRACE(level, ("TMC")); + `INST_SFU_WSPAWN:`TRACE(level, ("WSPAWN")); + `INST_SFU_SPLIT: begin if (op_args.wctl.is_neg) `TRACE(level, ("SPLIT.N")); else `TRACE(level, ("SPLIT")); end + `INST_SFU_JOIN: `TRACE(level, ("JOIN")); + `INST_SFU_BAR: `TRACE(level, ("BAR")); + `INST_SFU_PRED: begin if (op_args.wctl.is_neg) `TRACE(level, ("PRED.N")); else `TRACE(level, ("PRED")); end + `INST_SFU_CSRRW: begin if (op_args.csr.use_imm) `TRACE(level, ("CSRRWI")); else `TRACE(level, ("CSRRW")); end + `INST_SFU_CSRRS: begin if (op_args.csr.use_imm) `TRACE(level, ("CSRRSI")); else `TRACE(level, ("CSRRS")); end + `INST_SFU_CSRRC: begin if (op_args.csr.use_imm) `TRACE(level, ("CSRRCI")); else `TRACE(level, ("CSRRC")); end + default: `TRACE(level, ("?")); + endcase + end + default: `TRACE(level, ("?")); + endcase + endtask + + task trace_op_args(input int level, + input [`EX_BITS-1:0] ex_type, + input [`INST_OP_BITS-1:0] op_type, + input VX_gpu_pkg::op_args_t op_args + ); + case (ex_type) + `EX_ALU: begin + `TRACE(level, (", use_PC=%b, use_imm=%b, imm=0x%0h", op_args.alu.use_PC, op_args.alu.use_imm, op_args.alu.imm)); + end + `EX_LSU: begin + `TRACE(level, (", offset=0x%0h", op_args.lsu.offset)); + end + `EX_FPU: begin + `TRACE(level, (", fmt=0x%0h, frm=0x%0h", op_args.fpu.fmt, op_args.fpu.frm)); + end + `EX_SFU: begin + if (`INST_SFU_IS_CSR(op_type)) begin + `TRACE(level, (", addr=0x%0h, use_imm=%b, imm=0x%0h", op_args.csr.addr, op_args.csr.use_imm, op_args.csr.imm)); + end + end + default:; + endcase + endtask + + task trace_base_dcr(input int level, input [`VX_DCR_ADDR_WIDTH-1:0] addr); + case (addr) + `VX_DCR_BASE_STARTUP_ADDR0: `TRACE(level, ("STARTUP_ADDR0")); + `VX_DCR_BASE_STARTUP_ADDR1: `TRACE(level, ("STARTUP_ADDR1")); + `VX_DCR_BASE_STARTUP_ARG0: `TRACE(level, ("STARTUP_ARG0")); + `VX_DCR_BASE_STARTUP_ARG1: `TRACE(level, ("STARTUP_ARG1")); + `VX_DCR_BASE_MPM_CLASS: `TRACE(level, ("MPM_CLASS")); + default: `TRACE(level, ("?")); + endcase + endtask + +`endif + +`endif // VX_TRACE_VH diff --git a/miscs/patches/ramulator.patch b/miscs/patches/ramulator.patch new file mode 100644 index 000000000..e24b5d230 --- /dev/null +++ b/miscs/patches/ramulator.patch @@ -0,0 +1,46 @@ +diff --git a/Makefile b/Makefile +index ea340c8..d2aac5b 100644 +--- a/Makefile ++++ b/Makefile +@@ -7,16 +7,16 @@ OBJS := $(patsubst $(SRCDIR)/%.cpp, $(OBJDIR)/%.o, $(SRCS)) + + # Ramulator currently supports g++ 5.1+ or clang++ 3.4+. It will NOT work with + # g++ 4.x due to an internal compiler error when processing lambda functions. +-CXX := clang++ ++#CXX := clang++ + # CXX := g++-5 +-CXXFLAGS := -O3 -std=c++11 -g -Wall ++CXXFLAGS := -std=c++11 -O3 -g -Wall -fPIC + + .PHONY: all clean depend + + all: depend ramulator + + clean: +- rm -f ramulator ++ rm -f ramulator libramulator.a + rm -rf $(OBJDIR) + + depend: $(OBJDIR)/.depend +@@ -36,7 +36,7 @@ ramulator: $(MAIN) $(OBJS) $(SRCDIR)/*.h | depend + $(CXX) $(CXXFLAGS) -DRAMULATOR -o $@ $(MAIN) $(OBJS) + + libramulator.a: $(OBJS) $(OBJDIR)/Gem5Wrapper.o +- libtool -static -o $@ $(OBJS) $(OBJDIR)/Gem5Wrapper.o ++ $(AR) rcs $@ $^ + + $(OBJS): | $(OBJDIR) + +diff --git a/src/Request.h b/src/Request.h +index 57abd0d..a5ce061 100644 +--- a/src/Request.h ++++ b/src/Request.h +@@ -36,7 +36,7 @@ public: + + Request(long addr, Type type, int coreid = 0) + : is_first_command(true), addr(addr), coreid(coreid), type(type), +- callback([](Request& req){}) {} ++ callback([](Request&){}) {} + + Request(long addr, Type type, function callback, int coreid = 0) + : is_first_command(true), addr(addr), coreid(coreid), type(type), callback(callback) {} diff --git a/tests/opencl/bfs/graph4096.txt b/tests/opencl/bfs/graph4096.txt new file mode 100755 index 000000000..567432612 --- /dev/null +++ b/tests/opencl/bfs/graph4096.txt @@ -0,0 +1,28677 @@ +4096 +0 10 +10 6 +16 2 +18 5 +23 7 +30 7 +37 4 +41 4 +45 3 +48 5 +53 7 +60 4 +64 4 +68 6 +74 7 +81 5 +86 11 +97 5 +102 5 +107 8 +115 4 +119 4 +123 6 +129 4 +133 5 +138 7 +145 4 +149 2 +151 12 +163 3 +166 6 +172 6 +178 7 +185 5 +190 11 +201 4 +205 6 +211 9 +220 3 +223 4 +227 5 +232 4 +236 5 +241 6 +247 10 +257 4 +261 5 +266 7 +273 5 +278 4 +282 8 +290 5 +295 8 +303 9 +312 4 +316 5 +321 5 +326 3 +329 8 +337 5 +342 10 +352 6 +358 4 +362 5 +367 5 +372 10 +382 6 +388 8 +396 8 +404 5 +409 5 +414 5 +419 8 +427 6 +433 8 +441 9 +450 5 +455 10 +465 5 +470 11 +481 5 +486 7 +493 8 +501 9 +510 4 +514 10 +524 9 +533 5 +538 5 +543 7 +550 3 +553 3 +556 2 +558 6 +564 8 +572 3 +575 4 +579 5 +584 11 +595 8 +603 7 +610 5 +615 7 +622 4 +626 7 +633 6 +639 5 +644 4 +648 5 +653 4 +657 8 +665 8 +673 10 +683 2 +685 5 +690 5 +695 6 +701 3 +704 5 +709 9 +718 10 +728 7 +735 7 +742 9 +751 3 +754 4 +758 9 +767 6 +773 10 +783 7 +790 4 +794 8 +802 4 +806 5 +811 5 +816 8 +824 7 +831 8 +839 10 +849 5 +854 5 +859 4 +863 4 +867 7 +874 9 +883 2 +885 10 +895 8 +903 5 +908 6 +914 5 +919 11 +930 2 +932 6 +938 2 +940 4 +944 6 +950 6 +956 5 +961 4 +965 3 +968 4 +972 1 +973 10 +983 7 +990 4 +994 6 +1000 9 +1009 6 +1015 10 +1025 7 +1032 7 +1039 5 +1044 5 +1049 9 +1058 4 +1062 5 +1067 4 +1071 6 +1077 6 +1083 7 +1090 9 +1099 2 +1101 4 +1105 3 +1108 9 +1117 7 +1124 4 +1128 9 +1137 9 +1146 4 +1150 11 +1161 6 +1167 8 +1175 6 +1181 7 +1188 8 +1196 4 +1200 7 +1207 8 +1215 10 +1225 3 +1228 6 +1234 3 +1237 4 +1241 5 +1246 3 +1249 1 +1250 4 +1254 6 +1260 4 +1264 11 +1275 7 +1282 9 +1291 8 +1299 5 +1304 6 +1310 8 +1318 9 +1327 6 +1333 7 +1340 10 +1350 7 +1357 8 +1365 10 +1375 6 +1381 2 +1383 10 +1393 5 +1398 8 +1406 9 +1415 4 +1419 5 +1424 3 +1427 4 +1431 4 +1435 9 +1444 6 +1450 9 +1459 6 +1465 4 +1469 6 +1475 9 +1484 8 +1492 7 +1499 9 +1508 2 +1510 3 +1513 8 +1521 6 +1527 5 +1532 9 +1541 6 +1547 5 +1552 9 +1561 12 +1573 2 +1575 3 +1578 7 +1585 6 +1591 5 +1596 10 +1606 9 +1615 9 +1624 1 +1625 4 +1629 6 +1635 2 +1637 14 +1651 2 +1653 4 +1657 4 +1661 5 +1666 7 +1673 6 +1679 3 +1682 13 +1695 5 +1700 7 +1707 8 +1715 3 +1718 5 +1723 6 +1729 7 +1736 6 +1742 7 +1749 2 +1751 7 +1758 5 +1763 4 +1767 4 +1771 6 +1777 2 +1779 3 +1782 9 +1791 7 +1798 4 +1802 8 +1810 7 +1817 6 +1823 6 +1829 4 +1833 7 +1840 8 +1848 2 +1850 14 +1864 9 +1873 6 +1879 6 +1885 6 +1891 2 +1893 8 +1901 5 +1906 8 +1914 4 +1918 4 +1922 3 +1925 8 +1933 4 +1937 4 +1941 6 +1947 3 +1950 8 +1958 7 +1965 6 +1971 4 +1975 5 +1980 6 +1986 4 +1990 6 +1996 10 +2006 5 +2011 5 +2016 5 +2021 7 +2028 5 +2033 6 +2039 7 +2046 4 +2050 6 +2056 16 +2072 6 +2078 11 +2089 11 +2100 3 +2103 5 +2108 8 +2116 4 +2120 7 +2127 2 +2129 10 +2139 6 +2145 7 +2152 8 +2160 6 +2166 5 +2171 5 +2176 2 +2178 4 +2182 5 +2187 5 +2192 1 +2193 7 +2200 8 +2208 7 +2215 8 +2223 8 +2231 5 +2236 9 +2245 3 +2248 5 +2253 6 +2259 2 +2261 4 +2265 4 +2269 8 +2277 5 +2282 8 +2290 6 +2296 6 +2302 4 +2306 5 +2311 7 +2318 5 +2323 4 +2327 8 +2335 12 +2347 1 +2348 5 +2353 8 +2361 3 +2364 6 +2370 4 +2374 7 +2381 4 +2385 8 +2393 4 +2397 2 +2399 5 +2404 5 +2409 6 +2415 6 +2421 5 +2426 8 +2434 5 +2439 6 +2445 6 +2451 6 +2457 2 +2459 4 +2463 3 +2466 6 +2472 5 +2477 5 +2482 10 +2492 6 +2498 4 +2502 9 +2511 4 +2515 4 +2519 6 +2525 9 +2534 7 +2541 6 +2547 4 +2551 6 +2557 5 +2562 3 +2565 6 +2571 6 +2577 7 +2584 4 +2588 10 +2598 8 +2606 6 +2612 6 +2618 4 +2622 7 +2629 7 +2636 6 +2642 2 +2644 4 +2648 12 +2660 6 +2666 13 +2679 11 +2690 9 +2699 2 +2701 5 +2706 6 +2712 6 +2718 3 +2721 7 +2728 3 +2731 6 +2737 11 +2748 2 +2750 7 +2757 4 +2761 5 +2766 4 +2770 6 +2776 4 +2780 6 +2786 5 +2791 6 +2797 4 +2801 9 +2810 7 +2817 6 +2823 8 +2831 8 +2839 13 +2852 7 +2859 6 +2865 6 +2871 4 +2875 7 +2882 9 +2891 11 +2902 5 +2907 9 +2916 4 +2920 5 +2925 3 +2928 4 +2932 4 +2936 5 +2941 2 +2943 9 +2952 3 +2955 13 +2968 4 +2972 5 +2977 4 +2981 8 +2989 10 +2999 5 +3004 8 +3012 5 +3017 4 +3021 4 +3025 11 +3036 5 +3041 6 +3047 7 +3054 5 +3059 5 +3064 6 +3070 9 +3079 2 +3081 4 +3085 5 +3090 11 +3101 5 +3106 3 +3109 5 +3114 5 +3119 6 +3125 8 +3133 6 +3139 4 +3143 5 +3148 7 +3155 6 +3161 8 +3169 5 +3174 4 +3178 6 +3184 6 +3190 6 +3196 5 +3201 4 +3205 6 +3211 8 +3219 7 +3226 6 +3232 3 +3235 5 +3240 7 +3247 6 +3253 11 +3264 6 +3270 4 +3274 3 +3277 1 +3278 2 +3280 8 +3288 7 +3295 8 +3303 8 +3311 5 +3316 9 +3325 9 +3334 7 +3341 3 +3344 7 +3351 8 +3359 5 +3364 1 +3365 4 +3369 2 +3371 5 +3376 7 +3383 8 +3391 2 +3393 5 +3398 5 +3403 12 +3415 4 +3419 6 +3425 5 +3430 4 +3434 8 +3442 6 +3448 4 +3452 3 +3455 7 +3462 4 +3466 6 +3472 5 +3477 7 +3484 8 +3492 6 +3498 6 +3504 11 +3515 6 +3521 2 +3523 10 +3533 3 +3536 7 +3543 8 +3551 4 +3555 11 +3566 5 +3571 8 +3579 6 +3585 8 +3593 6 +3599 5 +3604 7 +3611 2 +3613 5 +3618 2 +3620 4 +3624 10 +3634 4 +3638 8 +3646 5 +3651 4 +3655 6 +3661 5 +3666 11 +3677 10 +3687 4 +3691 6 +3697 2 +3699 6 +3705 6 +3711 4 +3715 7 +3722 4 +3726 6 +3732 9 +3741 4 +3745 6 +3751 7 +3758 10 +3768 3 +3771 12 +3783 2 +3785 7 +3792 4 +3796 8 +3804 8 +3812 4 +3816 5 +3821 10 +3831 6 +3837 6 +3843 5 +3848 6 +3854 7 +3861 6 +3867 3 +3870 5 +3875 5 +3880 7 +3887 12 +3899 9 +3908 4 +3912 6 +3918 3 +3921 6 +3927 4 +3931 8 +3939 6 +3945 9 +3954 11 +3965 10 +3975 7 +3982 7 +3989 8 +3997 8 +4005 6 +4011 3 +4014 6 +4020 10 +4030 5 +4035 9 +4044 6 +4050 3 +4053 7 +4060 2 +4062 4 +4066 3 +4069 4 +4073 7 +4080 11 +4091 3 +4094 6 +4100 7 +4107 4 +4111 7 +4118 7 +4125 7 +4132 9 +4141 6 +4147 5 +4152 3 +4155 9 +4164 8 +4172 5 +4177 5 +4182 7 +4189 7 +4196 7 +4203 7 +4210 4 +4214 6 +4220 3 +4223 4 +4227 3 +4230 4 +4234 4 +4238 8 +4246 5 +4251 5 +4256 3 +4259 7 +4266 5 +4271 3 +4274 4 +4278 6 +4284 5 +4289 4 +4293 9 +4302 9 +4311 5 +4316 5 +4321 6 +4327 5 +4332 9 +4341 5 +4346 5 +4351 4 +4355 5 +4360 8 +4368 6 +4374 15 +4389 7 +4396 2 +4398 7 +4405 7 +4412 9 +4421 4 +4425 8 +4433 6 +4439 6 +4445 5 +4450 6 +4456 7 +4463 5 +4468 4 +4472 9 +4481 4 +4485 7 +4492 9 +4501 3 +4504 15 +4519 8 +4527 10 +4537 5 +4542 2 +4544 6 +4550 3 +4553 5 +4558 5 +4563 8 +4571 9 +4580 8 +4588 7 +4595 10 +4605 9 +4614 10 +4624 7 +4631 3 +4634 5 +4639 6 +4645 5 +4650 5 +4655 10 +4665 10 +4675 9 +4684 3 +4687 6 +4693 7 +4700 5 +4705 9 +4714 6 +4720 7 +4727 6 +4733 8 +4741 12 +4753 7 +4760 5 +4765 9 +4774 4 +4778 5 +4783 5 +4788 9 +4797 7 +4804 6 +4810 5 +4815 9 +4824 3 +4827 5 +4832 5 +4837 3 +4840 7 +4847 3 +4850 4 +4854 7 +4861 9 +4870 7 +4877 8 +4885 6 +4891 6 +4897 5 +4902 10 +4912 4 +4916 4 +4920 4 +4924 3 +4927 5 +4932 7 +4939 4 +4943 3 +4946 5 +4951 5 +4956 3 +4959 3 +4962 1 +4963 6 +4969 4 +4973 10 +4983 4 +4987 7 +4994 4 +4998 4 +5002 4 +5006 6 +5012 7 +5019 7 +5026 8 +5034 12 +5046 7 +5053 5 +5058 7 +5065 8 +5073 3 +5076 6 +5082 5 +5087 3 +5090 6 +5096 3 +5099 4 +5103 4 +5107 6 +5113 7 +5120 5 +5125 3 +5128 2 +5130 5 +5135 6 +5141 6 +5147 2 +5149 7 +5156 9 +5165 8 +5173 6 +5179 4 +5183 6 +5189 6 +5195 8 +5203 3 +5206 9 +5215 3 +5218 6 +5224 13 +5237 9 +5246 6 +5252 7 +5259 11 +5270 5 +5275 9 +5284 6 +5290 4 +5294 6 +5300 9 +5309 7 +5316 4 +5320 5 +5325 3 +5328 1 +5329 4 +5333 4 +5337 3 +5340 3 +5343 2 +5345 4 +5349 7 +5356 5 +5361 11 +5372 6 +5378 8 +5386 7 +5393 5 +5398 2 +5400 9 +5409 8 +5417 2 +5419 5 +5424 3 +5427 9 +5436 6 +5442 7 +5449 5 +5454 7 +5461 6 +5467 4 +5471 4 +5475 8 +5483 3 +5486 4 +5490 13 +5503 7 +5510 6 +5516 2 +5518 6 +5524 8 +5532 8 +5540 7 +5547 9 +5556 4 +5560 4 +5564 7 +5571 2 +5573 10 +5583 2 +5585 8 +5593 4 +5597 7 +5604 8 +5612 8 +5620 5 +5625 3 +5628 6 +5634 5 +5639 9 +5648 6 +5654 6 +5660 3 +5663 9 +5672 9 +5681 7 +5688 8 +5696 6 +5702 7 +5709 2 +5711 8 +5719 4 +5723 6 +5729 3 +5732 9 +5741 7 +5748 6 +5754 8 +5762 6 +5768 4 +5772 6 +5778 8 +5786 3 +5789 10 +5799 10 +5809 5 +5814 9 +5823 5 +5828 10 +5838 9 +5847 7 +5854 5 +5859 4 +5863 7 +5870 4 +5874 5 +5879 6 +5885 8 +5893 8 +5901 7 +5908 4 +5912 2 +5914 6 +5920 5 +5925 7 +5932 6 +5938 3 +5941 6 +5947 7 +5954 5 +5959 8 +5967 5 +5972 7 +5979 6 +5985 4 +5989 5 +5994 5 +5999 3 +6002 2 +6004 5 +6009 7 +6016 11 +6027 7 +6034 6 +6040 3 +6043 6 +6049 11 +6060 10 +6070 2 +6072 9 +6081 5 +6086 2 +6088 4 +6092 7 +6099 6 +6105 5 +6110 5 +6115 5 +6120 3 +6123 3 +6126 5 +6131 7 +6138 5 +6143 11 +6154 4 +6158 8 +6166 8 +6174 9 +6183 4 +6187 6 +6193 5 +6198 4 +6202 6 +6208 5 +6213 6 +6219 8 +6227 6 +6233 6 +6239 5 +6244 4 +6248 4 +6252 4 +6256 6 +6262 7 +6269 4 +6273 6 +6279 11 +6290 5 +6295 9 +6304 2 +6306 8 +6314 4 +6318 3 +6321 2 +6323 9 +6332 9 +6341 2 +6343 8 +6351 9 +6360 5 +6365 4 +6369 5 +6374 3 +6377 6 +6383 12 +6395 7 +6402 3 +6405 9 +6414 7 +6421 7 +6428 5 +6433 6 +6439 5 +6444 6 +6450 2 +6452 6 +6458 3 +6461 9 +6470 6 +6476 7 +6483 11 +6494 9 +6503 5 +6508 8 +6516 4 +6520 7 +6527 5 +6532 2 +6534 4 +6538 4 +6542 7 +6549 5 +6554 6 +6560 3 +6563 4 +6567 7 +6574 5 +6579 6 +6585 5 +6590 7 +6597 11 +6608 8 +6616 5 +6621 16 +6637 5 +6642 12 +6654 7 +6661 6 +6667 10 +6677 5 +6682 7 +6689 1 +6690 6 +6696 8 +6704 5 +6709 10 +6719 5 +6724 3 +6727 6 +6733 5 +6738 2 +6740 4 +6744 5 +6749 12 +6761 5 +6766 10 +6776 8 +6784 7 +6791 6 +6797 6 +6803 3 +6806 5 +6811 6 +6817 2 +6819 11 +6830 7 +6837 7 +6844 8 +6852 6 +6858 8 +6866 6 +6872 4 +6876 3 +6879 7 +6886 8 +6894 6 +6900 6 +6906 3 +6909 8 +6917 5 +6922 7 +6929 4 +6933 6 +6939 7 +6946 5 +6951 5 +6956 5 +6961 9 +6970 8 +6978 5 +6983 8 +6991 5 +6996 6 +7002 7 +7009 3 +7012 8 +7020 10 +7030 3 +7033 6 +7039 6 +7045 8 +7053 5 +7058 7 +7065 5 +7070 4 +7074 9 +7083 10 +7093 6 +7099 5 +7104 4 +7108 12 +7120 8 +7128 2 +7130 3 +7133 2 +7135 11 +7146 12 +7158 6 +7164 9 +7173 12 +7185 8 +7193 5 +7198 4 +7202 7 +7209 3 +7212 4 +7216 8 +7224 3 +7227 4 +7231 5 +7236 7 +7243 5 +7248 7 +7255 3 +7258 10 +7268 8 +7276 3 +7279 8 +7287 11 +7298 2 +7300 8 +7308 6 +7314 6 +7320 9 +7329 4 +7333 11 +7344 6 +7350 4 +7354 5 +7359 4 +7363 9 +7372 1 +7373 10 +7383 4 +7387 8 +7395 7 +7402 8 +7410 9 +7419 4 +7423 3 +7426 6 +7432 5 +7437 7 +7444 9 +7453 8 +7461 6 +7467 10 +7477 8 +7485 13 +7498 4 +7502 6 +7508 7 +7515 10 +7525 7 +7532 4 +7536 3 +7539 3 +7542 10 +7552 5 +7557 6 +7563 6 +7569 3 +7572 7 +7579 9 +7588 5 +7593 8 +7601 7 +7608 7 +7615 7 +7622 5 +7627 5 +7632 6 +7638 7 +7645 6 +7651 6 +7657 10 +7667 6 +7673 4 +7677 5 +7682 8 +7690 6 +7696 8 +7704 9 +7713 2 +7715 3 +7718 9 +7727 4 +7731 4 +7735 6 +7741 6 +7747 9 +7756 6 +7762 3 +7765 4 +7769 12 +7781 4 +7785 4 +7789 6 +7795 7 +7802 3 +7805 1 +7806 7 +7813 2 +7815 4 +7819 3 +7822 5 +7827 9 +7836 8 +7844 9 +7853 8 +7861 6 +7867 2 +7869 4 +7873 8 +7881 5 +7886 9 +7895 3 +7898 10 +7908 2 +7910 8 +7918 6 +7924 7 +7931 4 +7935 7 +7942 3 +7945 6 +7951 8 +7959 6 +7965 11 +7976 6 +7982 9 +7991 4 +7995 2 +7997 7 +8004 5 +8009 5 +8014 7 +8021 8 +8029 7 +8036 4 +8040 4 +8044 11 +8055 11 +8066 6 +8072 6 +8078 9 +8087 3 +8090 6 +8096 9 +8105 6 +8111 4 +8115 6 +8121 4 +8125 4 +8129 5 +8134 8 +8142 10 +8152 5 +8157 4 +8161 6 +8167 7 +8174 6 +8180 3 +8183 6 +8189 5 +8194 10 +8204 4 +8208 6 +8214 5 +8219 3 +8222 5 +8227 8 +8235 8 +8243 4 +8247 4 +8251 4 +8255 11 +8266 10 +8276 6 +8282 6 +8288 8 +8296 3 +8299 4 +8303 6 +8309 5 +8314 9 +8323 3 +8326 3 +8329 9 +8338 6 +8344 7 +8351 5 +8356 4 +8360 7 +8367 11 +8378 4 +8382 6 +8388 9 +8397 8 +8405 8 +8413 4 +8417 6 +8423 9 +8432 1 +8433 3 +8436 7 +8443 5 +8448 4 +8452 6 +8458 3 +8461 4 +8465 4 +8469 5 +8474 5 +8479 4 +8483 5 +8488 5 +8493 3 +8496 7 +8503 5 +8508 9 +8517 6 +8523 3 +8526 3 +8529 6 +8535 4 +8539 7 +8546 8 +8554 7 +8561 4 +8565 5 +8570 6 +8576 6 +8582 6 +8588 6 +8594 6 +8600 6 +8606 4 +8610 3 +8613 5 +8618 4 +8622 8 +8630 2 +8632 8 +8640 5 +8645 6 +8651 4 +8655 5 +8660 4 +8664 7 +8671 3 +8674 7 +8681 3 +8684 5 +8689 7 +8696 3 +8699 5 +8704 5 +8709 5 +8714 6 +8720 9 +8729 5 +8734 6 +8740 2 +8742 4 +8746 9 +8755 5 +8760 8 +8768 4 +8772 10 +8782 5 +8787 7 +8794 7 +8801 3 +8804 4 +8808 5 +8813 10 +8823 4 +8827 8 +8835 8 +8843 5 +8848 4 +8852 4 +8856 5 +8861 7 +8868 10 +8878 5 +8883 3 +8886 2 +8888 4 +8892 8 +8900 5 +8905 3 +8908 4 +8912 7 +8919 12 +8931 9 +8940 6 +8946 5 +8951 5 +8956 7 +8963 12 +8975 10 +8985 8 +8993 9 +9002 10 +9012 6 +9018 11 +9029 5 +9034 4 +9038 9 +9047 6 +9053 12 +9065 6 +9071 6 +9077 2 +9079 1 +9080 6 +9086 3 +9089 6 +9095 8 +9103 5 +9108 6 +9114 10 +9124 2 +9126 10 +9136 5 +9141 4 +9145 4 +9149 4 +9153 4 +9157 8 +9165 7 +9172 12 +9184 2 +9186 5 +9191 6 +9197 4 +9201 4 +9205 5 +9210 5 +9215 5 +9220 14 +9234 5 +9239 4 +9243 5 +9248 3 +9251 3 +9254 7 +9261 5 +9266 6 +9272 7 +9279 6 +9285 5 +9290 6 +9296 4 +9300 7 +9307 8 +9315 5 +9320 2 +9322 4 +9326 7 +9333 9 +9342 7 +9349 4 +9353 7 +9360 3 +9363 2 +9365 3 +9368 7 +9375 5 +9380 4 +9384 4 +9388 4 +9392 3 +9395 3 +9398 5 +9403 9 +9412 7 +9419 4 +9423 5 +9428 3 +9431 6 +9437 6 +9443 2 +9445 7 +9452 4 +9456 9 +9465 4 +9469 5 +9474 6 +9480 4 +9484 12 +9496 6 +9502 7 +9509 8 +9517 6 +9523 1 +9524 5 +9529 5 +9534 5 +9539 5 +9544 4 +9548 3 +9551 11 +9562 4 +9566 6 +9572 4 +9576 6 +9582 5 +9587 4 +9591 3 +9594 3 +9597 3 +9600 9 +9609 6 +9615 4 +9619 7 +9626 5 +9631 4 +9635 4 +9639 8 +9647 6 +9653 9 +9662 5 +9667 7 +9674 6 +9680 8 +9688 2 +9690 6 +9696 4 +9700 5 +9705 8 +9713 6 +9719 4 +9723 9 +9732 9 +9741 9 +9750 2 +9752 3 +9755 6 +9761 8 +9769 4 +9773 7 +9780 3 +9783 5 +9788 4 +9792 1 +9793 8 +9801 6 +9807 11 +9818 4 +9822 8 +9830 5 +9835 8 +9843 6 +9849 6 +9855 8 +9863 9 +9872 7 +9879 2 +9881 5 +9886 6 +9892 5 +9897 4 +9901 14 +9915 5 +9920 5 +9925 8 +9933 10 +9943 5 +9948 5 +9953 5 +9958 5 +9963 5 +9968 7 +9975 3 +9978 4 +9982 6 +9988 5 +9993 6 +9999 11 +10010 7 +10017 5 +10022 4 +10026 6 +10032 7 +10039 5 +10044 6 +10050 4 +10054 7 +10061 9 +10070 7 +10077 4 +10081 6 +10087 3 +10090 5 +10095 6 +10101 4 +10105 13 +10118 5 +10123 4 +10127 10 +10137 8 +10145 6 +10151 9 +10160 3 +10163 2 +10165 12 +10177 10 +10187 9 +10196 3 +10199 11 +10210 13 +10223 5 +10228 7 +10235 6 +10241 5 +10246 2 +10248 3 +10251 6 +10257 9 +10266 6 +10272 6 +10278 8 +10286 7 +10293 2 +10295 3 +10298 9 +10307 5 +10312 5 +10317 6 +10323 5 +10328 9 +10337 6 +10343 7 +10350 9 +10359 7 +10366 5 +10371 7 +10378 9 +10387 4 +10391 7 +10398 6 +10404 2 +10406 4 +10410 10 +10420 9 +10429 10 +10439 4 +10443 4 +10447 4 +10451 3 +10454 6 +10460 5 +10465 8 +10473 6 +10479 6 +10485 6 +10491 7 +10498 7 +10505 11 +10516 6 +10522 9 +10531 4 +10535 5 +10540 7 +10547 6 +10553 3 +10556 5 +10561 4 +10565 11 +10576 6 +10582 7 +10589 3 +10592 4 +10596 5 +10601 8 +10609 3 +10612 7 +10619 9 +10628 5 +10633 3 +10636 11 +10647 5 +10652 5 +10657 8 +10665 5 +10670 8 +10678 5 +10683 2 +10685 9 +10694 7 +10701 6 +10707 5 +10712 5 +10717 7 +10724 5 +10729 3 +10732 3 +10735 7 +10742 5 +10747 4 +10751 9 +10760 7 +10767 11 +10778 9 +10787 5 +10792 6 +10798 6 +10804 5 +10809 5 +10814 6 +10820 5 +10825 5 +10830 11 +10841 6 +10847 5 +10852 5 +10857 7 +10864 5 +10869 12 +10881 7 +10888 7 +10895 4 +10899 2 +10901 5 +10906 6 +10912 9 +10921 2 +10923 7 +10930 5 +10935 4 +10939 7 +10946 10 +10956 10 +10966 4 +10970 7 +10977 6 +10983 7 +10990 6 +10996 2 +10998 3 +11001 5 +11006 4 +11010 6 +11016 5 +11021 5 +11026 6 +11032 6 +11038 3 +11041 9 +11050 7 +11057 5 +11062 2 +11064 5 +11069 5 +11074 8 +11082 9 +11091 4 +11095 6 +11101 6 +11107 9 +11116 5 +11121 5 +11126 4 +11130 2 +11132 7 +11139 4 +11143 6 +11149 7 +11156 3 +11159 5 +11164 4 +11168 1 +11169 8 +11177 7 +11184 5 +11189 6 +11195 2 +11197 7 +11204 4 +11208 8 +11216 4 +11220 5 +11225 8 +11233 9 +11242 3 +11245 5 +11250 11 +11261 6 +11267 4 +11271 9 +11280 11 +11291 4 +11295 5 +11300 6 +11306 9 +11315 1 +11316 5 +11321 7 +11328 4 +11332 3 +11335 3 +11338 5 +11343 5 +11348 7 +11355 2 +11357 5 +11362 5 +11367 9 +11376 7 +11383 6 +11389 9 +11398 8 +11406 9 +11415 5 +11420 16 +11436 1 +11437 8 +11445 7 +11452 6 +11458 11 +11469 7 +11476 5 +11481 11 +11492 3 +11495 3 +11498 5 +11503 3 +11506 7 +11513 7 +11520 5 +11525 7 +11532 5 +11537 11 +11548 3 +11551 2 +11553 6 +11559 7 +11566 6 +11572 6 +11578 8 +11586 7 +11593 7 +11600 6 +11606 7 +11613 9 +11622 10 +11632 7 +11639 10 +11649 8 +11657 6 +11663 7 +11670 5 +11675 11 +11686 10 +11696 13 +11709 6 +11715 6 +11721 12 +11733 5 +11738 3 +11741 4 +11745 6 +11751 6 +11757 13 +11770 6 +11776 6 +11782 5 +11787 2 +11789 6 +11795 5 +11800 4 +11804 7 +11811 8 +11819 3 +11822 7 +11829 7 +11836 7 +11843 9 +11852 2 +11854 2 +11856 7 +11863 5 +11868 6 +11874 4 +11878 7 +11885 2 +11887 4 +11891 4 +11895 3 +11898 5 +11903 6 +11909 3 +11912 7 +11919 6 +11925 8 +11933 2 +11935 9 +11944 5 +11949 6 +11955 5 +11960 3 +11963 13 +11976 8 +11984 6 +11990 3 +11993 4 +11997 3 +12000 7 +12007 6 +12013 9 +12022 4 +12026 11 +12037 4 +12041 6 +12047 6 +12053 9 +12062 4 +12066 3 +12069 6 +12075 7 +12082 3 +12085 5 +12090 8 +12098 6 +12104 4 +12108 8 +12116 4 +12120 11 +12131 6 +12137 7 +12144 3 +12147 8 +12155 8 +12163 3 +12166 6 +12172 5 +12177 3 +12180 5 +12185 6 +12191 3 +12194 7 +12201 8 +12209 3 +12212 2 +12214 5 +12219 4 +12223 2 +12225 8 +12233 4 +12237 5 +12242 3 +12245 5 +12250 6 +12256 5 +12261 8 +12269 4 +12273 6 +12279 4 +12283 7 +12290 5 +12295 8 +12303 5 +12308 3 +12311 6 +12317 6 +12323 4 +12327 7 +12334 7 +12341 1 +12342 8 +12350 4 +12354 4 +12358 6 +12364 5 +12369 13 +12382 3 +12385 7 +12392 4 +12396 7 +12403 10 +12413 8 +12421 9 +12430 9 +12439 6 +12445 6 +12451 10 +12461 6 +12467 8 +12475 3 +12478 9 +12487 11 +12498 4 +12502 6 +12508 4 +12512 4 +12516 4 +12520 5 +12525 8 +12533 4 +12537 5 +12542 5 +12547 6 +12553 4 +12557 8 +12565 8 +12573 6 +12579 5 +12584 5 +12589 6 +12595 4 +12599 4 +12603 2 +12605 8 +12613 4 +12617 5 +12622 4 +12626 6 +12632 5 +12637 12 +12649 5 +12654 6 +12660 9 +12669 5 +12674 5 +12679 7 +12686 6 +12692 5 +12697 4 +12701 6 +12707 5 +12712 5 +12717 6 +12723 5 +12728 8 +12736 10 +12746 6 +12752 7 +12759 6 +12765 4 +12769 6 +12775 6 +12781 13 +12794 6 +12800 11 +12811 4 +12815 8 +12823 7 +12830 7 +12837 6 +12843 6 +12849 7 +12856 5 +12861 10 +12871 10 +12881 8 +12889 9 +12898 4 +12902 6 +12908 9 +12917 8 +12925 9 +12934 4 +12938 4 +12942 7 +12949 2 +12951 7 +12958 1 +12959 9 +12968 8 +12976 8 +12984 1 +12985 4 +12989 4 +12993 4 +12997 8 +13005 4 +13009 4 +13013 8 +13021 9 +13030 6 +13036 8 +13044 3 +13047 8 +13055 5 +13060 7 +13067 8 +13075 7 +13082 2 +13084 5 +13089 9 +13098 5 +13103 7 +13110 6 +13116 6 +13122 6 +13128 6 +13134 7 +13141 5 +13146 8 +13154 12 +13166 4 +13170 6 +13176 4 +13180 6 +13186 5 +13191 3 +13194 6 +13200 9 +13209 4 +13213 5 +13218 8 +13226 6 +13232 3 +13235 8 +13243 7 +13250 8 +13258 5 +13263 5 +13268 4 +13272 7 +13279 3 +13282 11 +13293 7 +13300 6 +13306 5 +13311 5 +13316 6 +13322 9 +13331 2 +13333 6 +13339 7 +13346 7 +13353 6 +13359 6 +13365 5 +13370 4 +13374 6 +13380 9 +13389 11 +13400 5 +13405 8 +13413 4 +13417 4 +13421 9 +13430 4 +13434 9 +13443 3 +13446 7 +13453 6 +13459 6 +13465 1 +13466 7 +13473 7 +13480 6 +13486 5 +13491 7 +13498 3 +13501 6 +13507 5 +13512 4 +13516 8 +13524 2 +13526 4 +13530 5 +13535 3 +13538 5 +13543 5 +13548 5 +13553 3 +13556 4 +13560 7 +13567 4 +13571 4 +13575 8 +13583 9 +13592 6 +13598 7 +13605 1 +13606 9 +13615 9 +13624 10 +13634 4 +13638 3 +13641 9 +13650 8 +13658 5 +13663 7 +13670 4 +13674 12 +13686 2 +13688 3 +13691 5 +13696 5 +13701 10 +13711 4 +13715 4 +13719 7 +13726 5 +13731 4 +13735 9 +13744 7 +13751 5 +13756 4 +13760 8 +13768 8 +13776 9 +13785 7 +13792 7 +13799 6 +13805 6 +13811 7 +13818 11 +13829 7 +13836 6 +13842 5 +13847 6 +13853 7 +13860 10 +13870 4 +13874 3 +13877 4 +13881 4 +13885 6 +13891 6 +13897 8 +13905 10 +13915 9 +13924 6 +13930 2 +13932 4 +13936 6 +13942 10 +13952 8 +13960 4 +13964 12 +13976 6 +13982 5 +13987 6 +13993 5 +13998 3 +14001 7 +14008 7 +14015 10 +14025 3 +14028 6 +14034 6 +14040 2 +14042 3 +14045 5 +14050 6 +14056 4 +14060 7 +14067 9 +14076 1 +14077 6 +14083 5 +14088 4 +14092 7 +14099 9 +14108 2 +14110 14 +14124 7 +14131 4 +14135 7 +14142 8 +14150 3 +14153 5 +14158 7 +14165 11 +14176 6 +14182 8 +14190 5 +14195 8 +14203 6 +14209 5 +14214 5 +14219 2 +14221 4 +14225 3 +14228 4 +14232 5 +14237 5 +14242 5 +14247 3 +14250 9 +14259 7 +14266 4 +14270 6 +14276 6 +14282 3 +14285 2 +14287 8 +14295 6 +14301 6 +14307 2 +14309 7 +14316 6 +14322 5 +14327 9 +14336 3 +14339 6 +14345 7 +14352 2 +14354 7 +14361 6 +14367 8 +14375 6 +14381 6 +14387 2 +14389 3 +14392 4 +14396 5 +14401 3 +14404 6 +14410 7 +14417 4 +14421 4 +14425 5 +14430 4 +14434 11 +14445 8 +14453 5 +14458 5 +14463 8 +14471 3 +14474 5 +14479 5 +14484 15 +14499 6 +14505 7 +14512 5 +14517 5 +14522 2 +14524 3 +14527 2 +14529 9 +14538 9 +14547 6 +14553 4 +14557 11 +14568 6 +14574 7 +14581 5 +14586 2 +14588 3 +14591 8 +14599 3 +14602 5 +14607 5 +14612 6 +14618 2 +14620 4 +14624 3 +14627 9 +14636 5 +14641 2 +14643 12 +14655 7 +14662 4 +14666 8 +14674 4 +14678 9 +14687 5 +14692 6 +14698 9 +14707 3 +14710 9 +14719 4 +14723 5 +14728 5 +14733 2 +14735 5 +14740 4 +14744 11 +14755 7 +14762 7 +14769 12 +14781 4 +14785 8 +14793 8 +14801 5 +14806 4 +14810 4 +14814 6 +14820 8 +14828 9 +14837 4 +14841 4 +14845 6 +14851 3 +14854 6 +14860 9 +14869 7 +14876 8 +14884 7 +14891 6 +14897 6 +14903 5 +14908 6 +14914 8 +14922 5 +14927 3 +14930 7 +14937 4 +14941 8 +14949 8 +14957 7 +14964 7 +14971 7 +14978 7 +14985 8 +14993 6 +14999 6 +15005 10 +15015 5 +15020 4 +15024 8 +15032 7 +15039 3 +15042 6 +15048 7 +15055 5 +15060 9 +15069 13 +15082 6 +15088 5 +15093 4 +15097 5 +15102 6 +15108 6 +15114 6 +15120 10 +15130 7 +15137 9 +15146 5 +15151 8 +15159 9 +15168 10 +15178 10 +15188 4 +15192 4 +15196 4 +15200 7 +15207 6 +15213 12 +15225 3 +15228 7 +15235 3 +15238 6 +15244 8 +15252 5 +15257 10 +15267 7 +15274 6 +15280 2 +15282 5 +15287 2 +15289 4 +15293 3 +15296 5 +15301 8 +15309 9 +15318 4 +15322 3 +15325 4 +15329 5 +15334 3 +15337 5 +15342 2 +15344 4 +15348 11 +15359 3 +15362 8 +15370 7 +15377 4 +15381 7 +15388 7 +15395 5 +15400 6 +15406 9 +15415 4 +15419 10 +15429 9 +15438 4 +15442 2 +15444 6 +15450 6 +15456 12 +15468 7 +15475 5 +15480 6 +15486 3 +15489 5 +15494 6 +15500 5 +15505 3 +15508 3 +15511 1 +15512 10 +15522 8 +15530 6 +15536 4 +15540 3 +15543 8 +15551 5 +15556 4 +15560 9 +15569 10 +15579 6 +15585 11 +15596 10 +15606 9 +15615 12 +15627 9 +15636 4 +15640 4 +15644 4 +15648 11 +15659 4 +15663 5 +15668 4 +15672 5 +15677 5 +15682 1 +15683 3 +15686 4 +15690 7 +15697 7 +15704 6 +15710 6 +15716 4 +15720 4 +15724 10 +15734 7 +15741 5 +15746 8 +15754 5 +15759 5 +15764 4 +15768 6 +15774 8 +15782 2 +15784 6 +15790 5 +15795 4 +15799 5 +15804 5 +15809 9 +15818 6 +15824 6 +15830 3 +15833 10 +15843 7 +15850 4 +15854 5 +15859 6 +15865 9 +15874 4 +15878 4 +15882 5 +15887 7 +15894 5 +15899 6 +15905 8 +15913 8 +15921 4 +15925 6 +15931 10 +15941 7 +15948 4 +15952 5 +15957 7 +15964 10 +15974 1 +15975 1 +15976 6 +15982 2 +15984 11 +15995 6 +16001 3 +16004 4 +16008 5 +16013 6 +16019 6 +16025 11 +16036 4 +16040 3 +16043 4 +16047 4 +16051 4 +16055 6 +16061 3 +16064 4 +16068 3 +16071 7 +16078 10 +16088 11 +16099 5 +16104 7 +16111 8 +16119 8 +16127 6 +16133 3 +16136 3 +16139 8 +16147 4 +16151 4 +16155 11 +16166 6 +16172 4 +16176 12 +16188 5 +16193 2 +16195 2 +16197 2 +16199 7 +16206 1 +16207 8 +16215 7 +16222 4 +16226 6 +16232 6 +16238 7 +16245 8 +16253 6 +16259 6 +16265 4 +16269 5 +16274 5 +16279 7 +16286 3 +16289 9 +16298 4 +16302 5 +16307 7 +16314 6 +16320 5 +16325 4 +16329 8 +16337 6 +16343 5 +16348 7 +16355 3 +16358 3 +16361 4 +16365 6 +16371 4 +16375 9 +16384 4 +16388 5 +16393 3 +16396 7 +16403 5 +16408 9 +16417 9 +16426 7 +16433 7 +16440 9 +16449 3 +16452 5 +16457 1 +16458 10 +16468 10 +16478 9 +16487 4 +16491 6 +16497 9 +16506 11 +16517 7 +16524 9 +16533 6 +16539 9 +16548 8 +16556 8 +16564 5 +16569 8 +16577 4 +16581 4 +16585 5 +16590 5 +16595 9 +16604 7 +16611 8 +16619 3 +16622 12 +16634 13 +16647 3 +16650 2 +16652 4 +16656 7 +16663 7 +16670 4 +16674 3 +16677 6 +16683 6 +16689 6 +16695 5 +16700 10 +16710 3 +16713 7 +16720 6 +16726 6 +16732 6 +16738 12 +16750 5 +16755 3 +16758 4 +16762 4 +16766 10 +16776 6 +16782 10 +16792 5 +16797 5 +16802 4 +16806 4 +16810 7 +16817 2 +16819 6 +16825 7 +16832 8 +16840 9 +16849 5 +16854 3 +16857 10 +16867 6 +16873 8 +16881 7 +16888 8 +16896 10 +16906 9 +16915 6 +16921 3 +16924 7 +16931 5 +16936 6 +16942 7 +16949 11 +16960 3 +16963 8 +16971 6 +16977 8 +16985 4 +16989 8 +16997 8 +17005 5 +17010 3 +17013 6 +17019 5 +17024 4 +17028 7 +17035 2 +17037 7 +17044 3 +17047 5 +17052 5 +17057 3 +17060 8 +17068 6 +17074 8 +17082 4 +17086 6 +17092 9 +17101 5 +17106 4 +17110 6 +17116 6 +17122 7 +17129 8 +17137 7 +17144 7 +17151 9 +17160 6 +17166 3 +17169 3 +17172 4 +17176 5 +17181 4 +17185 4 +17189 4 +17193 7 +17200 14 +17214 6 +17220 4 +17224 5 +17229 5 +17234 8 +17242 10 +17252 8 +17260 4 +17264 6 +17270 12 +17282 7 +17289 9 +17298 10 +17308 6 +17314 5 +17319 5 +17324 4 +17328 4 +17332 7 +17339 4 +17343 8 +17351 4 +17355 7 +17362 8 +17370 5 +17375 4 +17379 5 +17384 4 +17388 8 +17396 5 +17401 5 +17406 6 +17412 4 +17416 6 +17422 6 +17428 9 +17437 7 +17444 8 +17452 4 +17456 3 +17459 4 +17463 9 +17472 5 +17477 8 +17485 5 +17490 6 +17496 6 +17502 8 +17510 6 +17516 8 +17524 5 +17529 8 +17537 5 +17542 6 +17548 7 +17555 5 +17560 4 +17564 5 +17569 6 +17575 4 +17579 4 +17583 3 +17586 4 +17590 13 +17603 4 +17607 8 +17615 2 +17617 19 +17636 7 +17643 3 +17646 6 +17652 7 +17659 6 +17665 3 +17668 5 +17673 7 +17680 5 +17685 7 +17692 8 +17700 4 +17704 5 +17709 2 +17711 4 +17715 5 +17720 11 +17731 5 +17736 11 +17747 6 +17753 3 +17756 5 +17761 5 +17766 13 +17779 4 +17783 5 +17788 8 +17796 5 +17801 10 +17811 6 +17817 9 +17826 3 +17829 7 +17836 7 +17843 4 +17847 3 +17850 6 +17856 6 +17862 8 +17870 3 +17873 5 +17878 4 +17882 7 +17889 5 +17894 11 +17905 6 +17911 4 +17915 5 +17920 7 +17927 3 +17930 9 +17939 7 +17946 9 +17955 4 +17959 7 +17966 5 +17971 5 +17976 5 +17981 18 +17999 8 +18007 3 +18010 6 +18016 7 +18023 3 +18026 8 +18034 7 +18041 8 +18049 5 +18054 4 +18058 10 +18068 2 +18070 9 +18079 5 +18084 5 +18089 6 +18095 4 +18099 3 +18102 11 +18113 5 +18118 6 +18124 4 +18128 2 +18130 9 +18139 5 +18144 11 +18155 7 +18162 3 +18165 5 +18170 4 +18174 4 +18178 5 +18183 6 +18189 6 +18195 6 +18201 6 +18207 9 +18216 4 +18220 9 +18229 3 +18232 5 +18237 6 +18243 7 +18250 8 +18258 4 +18262 11 +18273 5 +18278 7 +18285 3 +18288 3 +18291 7 +18298 6 +18304 4 +18308 2 +18310 2 +18312 10 +18322 5 +18327 6 +18333 3 +18336 9 +18345 3 +18348 5 +18353 9 +18362 6 +18368 5 +18373 6 +18379 5 +18384 10 +18394 6 +18400 3 +18403 4 +18407 7 +18414 5 +18419 6 +18425 6 +18431 5 +18436 4 +18440 5 +18445 8 +18453 11 +18464 10 +18474 10 +18484 5 +18489 3 +18492 9 +18501 9 +18510 3 +18513 8 +18521 7 +18528 4 +18532 3 +18535 5 +18540 7 +18547 6 +18553 3 +18556 7 +18563 7 +18570 8 +18578 4 +18582 3 +18585 12 +18597 6 +18603 8 +18611 7 +18618 5 +18623 4 +18627 5 +18632 10 +18642 5 +18647 5 +18652 4 +18656 7 +18663 9 +18672 8 +18680 5 +18685 5 +18690 3 +18693 7 +18700 8 +18708 6 +18714 10 +18724 6 +18730 7 +18737 2 +18739 4 +18743 9 +18752 6 +18758 5 +18763 8 +18771 3 +18774 13 +18787 8 +18795 9 +18804 5 +18809 4 +18813 5 +18818 5 +18823 5 +18828 4 +18832 8 +18840 2 +18842 7 +18849 6 +18855 8 +18863 8 +18871 6 +18877 5 +18882 9 +18891 5 +18896 11 +18907 8 +18915 3 +18918 5 +18923 8 +18931 7 +18938 6 +18944 5 +18949 2 +18951 4 +18955 7 +18962 6 +18968 5 +18973 5 +18978 5 +18983 10 +18993 6 +18999 9 +19008 9 +19017 5 +19022 6 +19028 4 +19032 7 +19039 5 +19044 4 +19048 7 +19055 7 +19062 2 +19064 12 +19076 6 +19082 5 +19087 3 +19090 8 +19098 3 +19101 5 +19106 7 +19113 3 +19116 5 +19121 4 +19125 6 +19131 4 +19135 5 +19140 8 +19148 5 +19153 7 +19160 9 +19169 4 +19173 8 +19181 2 +19183 5 +19188 6 +19194 5 +19199 7 +19206 1 +19207 3 +19210 2 +19212 6 +19218 7 +19225 3 +19228 4 +19232 8 +19240 6 +19246 10 +19256 5 +19261 8 +19269 9 +19278 9 +19287 3 +19290 6 +19296 3 +19299 2 +19301 9 +19310 3 +19313 8 +19321 4 +19325 6 +19331 7 +19338 8 +19346 5 +19351 10 +19361 2 +19363 6 +19369 4 +19373 5 +19378 8 +19386 10 +19396 4 +19400 8 +19408 7 +19415 5 +19420 7 +19427 6 +19433 5 +19438 6 +19444 5 +19449 6 +19455 7 +19462 5 +19467 4 +19471 8 +19479 2 +19481 6 +19487 4 +19491 3 +19494 4 +19498 3 +19501 2 +19503 7 +19510 6 +19516 2 +19518 8 +19526 9 +19535 8 +19543 2 +19545 3 +19548 10 +19558 4 +19562 7 +19569 5 +19574 5 +19579 5 +19584 6 +19590 3 +19593 6 +19599 6 +19605 4 +19609 6 +19615 8 +19623 5 +19628 7 +19635 6 +19641 6 +19647 4 +19651 8 +19659 6 +19665 4 +19669 3 +19672 9 +19681 6 +19687 6 +19693 4 +19697 6 +19703 8 +19711 6 +19717 6 +19723 7 +19730 3 +19733 5 +19738 4 +19742 5 +19747 5 +19752 11 +19763 8 +19771 6 +19777 9 +19786 6 +19792 11 +19803 4 +19807 8 +19815 6 +19821 8 +19829 7 +19836 9 +19845 3 +19848 5 +19853 5 +19858 10 +19868 3 +19871 4 +19875 10 +19885 5 +19890 8 +19898 5 +19903 5 +19908 5 +19913 4 +19917 6 +19923 4 +19927 5 +19932 6 +19938 3 +19941 8 +19949 7 +19956 6 +19962 7 +19969 4 +19973 6 +19979 4 +19983 10 +19993 8 +20001 16 +20017 5 +20022 6 +20028 11 +20039 6 +20045 6 +20051 8 +20059 5 +20064 4 +20068 9 +20077 9 +20086 10 +20096 9 +20105 6 +20111 4 +20115 5 +20120 3 +20123 7 +20130 9 +20139 4 +20143 2 +20145 7 +20152 7 +20159 6 +20165 7 +20172 10 +20182 6 +20188 2 +20190 5 +20195 7 +20202 6 +20208 6 +20214 5 +20219 3 +20222 2 +20224 4 +20228 7 +20235 4 +20239 5 +20244 8 +20252 3 +20255 6 +20261 9 +20270 9 +20279 2 +20281 8 +20289 2 +20291 3 +20294 3 +20297 3 +20300 4 +20304 7 +20311 7 +20318 6 +20324 4 +20328 4 +20332 4 +20336 10 +20346 7 +20353 3 +20356 5 +20361 3 +20364 6 +20370 4 +20374 4 +20378 3 +20381 5 +20386 5 +20391 4 +20395 5 +20400 4 +20404 5 +20409 1 +20410 5 +20415 2 +20417 5 +20422 7 +20429 4 +20433 2 +20435 6 +20441 5 +20446 4 +20450 7 +20457 8 +20465 2 +20467 10 +20477 5 +20482 5 +20487 8 +20495 11 +20506 5 +20511 4 +20515 3 +20518 6 +20524 12 +20536 3 +20539 12 +20551 8 +20559 4 +20563 10 +20573 8 +20581 3 +20584 7 +20591 6 +20597 4 +20601 10 +20611 7 +20618 5 +20623 4 +20627 5 +20632 8 +20640 6 +20646 3 +20649 9 +20658 2 +20660 7 +20667 4 +20671 5 +20676 7 +20683 8 +20691 4 +20695 6 +20701 4 +20705 8 +20713 8 +20721 4 +20725 5 +20730 7 +20737 4 +20741 5 +20746 4 +20750 2 +20752 8 +20760 8 +20768 10 +20778 7 +20785 7 +20792 10 +20802 3 +20805 3 +20808 10 +20818 4 +20822 6 +20828 7 +20835 4 +20839 8 +20847 5 +20852 12 +20864 2 +20866 7 +20873 3 +20876 5 +20881 3 +20884 8 +20892 4 +20896 7 +20903 5 +20908 4 +20912 10 +20922 5 +20927 10 +20937 10 +20947 6 +20953 3 +20956 6 +20962 4 +20966 5 +20971 8 +20979 4 +20983 7 +20990 5 +20995 10 +21005 7 +21012 10 +21022 3 +21025 7 +21032 5 +21037 12 +21049 8 +21057 4 +21061 5 +21066 2 +21068 10 +21078 3 +21081 4 +21085 5 +21090 4 +21094 9 +21103 4 +21107 7 +21114 7 +21121 6 +21127 1 +21128 9 +21137 7 +21144 10 +21154 4 +21158 5 +21163 6 +21169 5 +21174 4 +21178 4 +21182 5 +21187 6 +21193 11 +21204 7 +21211 7 +21218 10 +21228 5 +21233 13 +21246 10 +21256 3 +21259 5 +21264 9 +21273 6 +21279 11 +21290 8 +21298 3 +21301 3 +21304 12 +21316 7 +21323 5 +21328 6 +21334 4 +21338 7 +21345 7 +21352 6 +21358 3 +21361 8 +21369 6 +21375 5 +21380 5 +21385 6 +21391 6 +21397 6 +21403 6 +21409 9 +21418 6 +21424 12 +21436 5 +21441 3 +21444 7 +21451 9 +21460 9 +21469 10 +21479 5 +21484 5 +21489 8 +21497 6 +21503 4 +21507 2 +21509 5 +21514 4 +21518 4 +21522 6 +21528 11 +21539 6 +21545 6 +21551 6 +21557 11 +21568 3 +21571 4 +21575 3 +21578 6 +21584 7 +21591 3 +21594 8 +21602 7 +21609 9 +21618 4 +21622 7 +21629 8 +21637 8 +21645 4 +21649 4 +21653 2 +21655 6 +21661 6 +21667 5 +21672 5 +21677 8 +21685 6 +21691 6 +21697 4 +21701 4 +21705 3 +21708 12 +21720 6 +21726 9 +21735 5 +21740 6 +21746 5 +21751 6 +21757 12 +21769 5 +21774 6 +21780 4 +21784 8 +21792 3 +21795 3 +21798 6 +21804 7 +21811 5 +21816 11 +21827 7 +21834 3 +21837 6 +21843 9 +21852 8 +21860 6 +21866 4 +21870 5 +21875 6 +21881 9 +21890 3 +21893 5 +21898 4 +21902 5 +21907 8 +21915 6 +21921 3 +21924 5 +21929 6 +21935 5 +21940 5 +21945 7 +21952 7 +21959 4 +21963 8 +21971 4 +21975 6 +21981 3 +21984 9 +21993 6 +21999 5 +22004 6 +22010 9 +22019 8 +22027 2 +22029 7 +22036 3 +22039 5 +22044 3 +22047 7 +22054 10 +22064 3 +22067 2 +22069 5 +22074 6 +22080 4 +22084 5 +22089 7 +22096 4 +22100 8 +22108 4 +22112 10 +22122 4 +22126 6 +22132 3 +22135 4 +22139 9 +22148 5 +22153 4 +22157 5 +22162 5 +22167 8 +22175 5 +22180 4 +22184 5 +22189 4 +22193 4 +22197 5 +22202 10 +22212 8 +22220 5 +22225 4 +22229 8 +22237 8 +22245 8 +22253 2 +22255 4 +22259 9 +22268 10 +22278 3 +22281 9 +22290 4 +22294 4 +22298 7 +22305 6 +22311 4 +22315 7 +22322 3 +22325 6 +22331 3 +22334 5 +22339 9 +22348 4 +22352 5 +22357 6 +22363 5 +22368 4 +22372 5 +22377 7 +22384 2 +22386 7 +22393 8 +22401 7 +22408 9 +22417 8 +22425 3 +22428 4 +22432 7 +22439 6 +22445 4 +22449 9 +22458 6 +22464 5 +22469 7 +22476 10 +22486 5 +22491 5 +22496 10 +22506 8 +22514 8 +22522 8 +22530 8 +22538 5 +22543 9 +22552 2 +22554 2 +22556 6 +22562 7 +22569 9 +22578 3 +22581 7 +22588 8 +22596 3 +22599 6 +22605 3 +22608 4 +22612 6 +22618 13 +22631 7 +22638 5 +22643 8 +22651 8 +22659 9 +22668 7 +22675 2 +22677 12 +22689 14 +22703 10 +22713 4 +22717 7 +22724 3 +22727 5 +22732 9 +22741 9 +22750 11 +22761 4 +22765 5 +22770 12 +22782 4 +22786 8 +22794 4 +22798 7 +22805 6 +22811 4 +22815 8 +22823 4 +22827 7 +22834 2 +22836 7 +22843 9 +22852 2 +22854 10 +22864 6 +22870 7 +22877 8 +22885 7 +22892 2 +22894 4 +22898 9 +22907 7 +22914 8 +22922 7 +22929 5 +22934 5 +22939 4 +22943 7 +22950 8 +22958 3 +22961 7 +22968 5 +22973 4 +22977 5 +22982 7 +22989 4 +22993 4 +22997 7 +23004 4 +23008 5 +23013 7 +23020 6 +23026 3 +23029 7 +23036 9 +23045 3 +23048 3 +23051 5 +23056 5 +23061 5 +23066 6 +23072 7 +23079 4 +23083 4 +23087 9 +23096 4 +23100 6 +23106 5 +23111 6 +23117 7 +23124 5 +23129 5 +23134 3 +23137 2 +23139 8 +23147 13 +23160 6 +23166 4 +23170 5 +23175 4 +23179 3 +23182 6 +23188 6 +23194 5 +23199 4 +23203 6 +23209 4 +23213 12 +23225 4 +23229 7 +23236 10 +23246 9 +23255 6 +23261 9 +23270 9 +23279 8 +23287 3 +23290 7 +23297 5 +23302 3 +23305 2 +23307 7 +23314 7 +23321 6 +23327 10 +23337 4 +23341 9 +23350 6 +23356 6 +23362 7 +23369 12 +23381 4 +23385 5 +23390 3 +23393 10 +23403 10 +23413 4 +23417 6 +23423 3 +23426 9 +23435 6 +23441 7 +23448 5 +23453 6 +23459 5 +23464 3 +23467 8 +23475 2 +23477 10 +23487 3 +23490 4 +23494 5 +23499 8 +23507 4 +23511 7 +23518 8 +23526 4 +23530 6 +23536 8 +23544 6 +23550 7 +23557 3 +23560 7 +23567 2 +23569 6 +23575 9 +23584 12 +23596 5 +23601 8 +23609 7 +23616 6 +23622 6 +23628 4 +23632 10 +23642 8 +23650 7 +23657 1 +23658 8 +23666 8 +23674 4 +23678 8 +23686 6 +23692 9 +23701 8 +23709 7 +23716 9 +23725 8 +23733 9 +23742 5 +23747 4 +23751 5 +23756 10 +23766 6 +23772 4 +23776 6 +23782 3 +23785 6 +23791 7 +23798 9 +23807 9 +23816 13 +23829 10 +23839 6 +23845 3 +23848 6 +23854 7 +23861 6 +23867 4 +23871 11 +23882 12 +23894 3 +23897 2 +23899 8 +23907 3 +23910 8 +23918 7 +23925 6 +23931 5 +23936 6 +23942 11 +23953 6 +23959 4 +23963 4 +23967 5 +23972 7 +23979 8 +23987 5 +23992 5 +23997 6 +24003 4 +24007 8 +24015 9 +24024 5 +24029 4 +24033 3 +24036 4 +24040 2 +24042 7 +24049 2 +24051 6 +24057 1 +24058 9 +24067 8 +24075 6 +24081 3 +24084 9 +24093 6 +24099 8 +24107 9 +24116 6 +24122 5 +24127 4 +24131 8 +24139 6 +24145 7 +24152 3 +24155 8 +24163 5 +24168 6 +24174 6 +24180 4 +24184 8 +24192 5 +24197 5 +24202 6 +24208 7 +24215 5 +24220 3 +24223 11 +24234 12 +24246 12 +24258 3 +24261 9 +24270 6 +24276 5 +24281 5 +24286 8 +24294 4 +24298 8 +24306 5 +24311 7 +24318 3 +24321 8 +24329 5 +24334 3 +24337 7 +24344 7 +24351 5 +24356 7 +24363 4 +24367 6 +24373 3 +24376 8 +24384 3 +24387 7 +24394 10 +24404 3 +24407 5 +24412 6 +24418 4 +24422 4 +24426 2 +24428 3 +24431 9 +24440 8 +24448 7 +24455 5 +24460 11 +24471 7 +24478 7 +24485 5 +24490 10 +24500 4 +24504 7 +24511 6 +24517 13 +24530 10 +24540 7 +24547 8 +24555 4 +24559 2 +24561 9 +24570 2 +24572 4 + +0 + +24576 +2539 2 +1187 5 +3911 2 +585 8 +1498 10 +1681 2 +2115 7 +2424 1 +3708 7 +196 1 +1852 10 +3555 8 +2134 1 +1064 9 +1293 8 +944 9 +2413 3 +1678 2 +839 9 +297 1 +174 7 +2217 9 +51 8 +3195 6 +3215 5 +332 3 +2077 7 +1214 2 +2367 10 +1947 10 +2350 6 +3441 1 +3246 7 +1999 1 +2037 5 +2227 8 +101 7 +3340 9 +3713 7 +3013 4 +1001 3 +444 6 +3306 2 +4043 1 +1361 1 +3916 6 +365 4 +1485 8 +251 8 +234 2 +4042 2 +870 7 +3803 9 +3874 4 +1058 5 +831 3 +2331 6 +1328 1 +2525 4 +255 3 +381 1 +2521 1 +3946 5 +2449 4 +285 2 +3848 4 +2669 9 +3949 3 +1050 4 +2855 9 +1974 3 +349 7 +2874 6 +192 6 +3442 4 +265 1 +2281 4 +403 6 +2359 5 +319 8 +39 1 +3893 3 +1176 1 +3154 10 +866 9 +2670 9 +3934 6 +3799 5 +393 8 +2722 10 +2107 4 +185 3 +69 1 +1958 4 +1613 2 +1908 10 +3867 5 +2950 2 +3397 10 +3737 1 +1074 9 +234 2 +2795 8 +1452 8 +1437 2 +768 7 +3400 1 +1212 6 +2675 7 +989 4 +1338 6 +764 5 +216 3 +2186 3 +2210 9 +2194 1 +1703 3 +2668 5 +3684 3 +3636 6 +3939 5 +3718 2 +3954 10 +4009 10 +703 8 +2990 8 +2162 4 +3980 1 +1245 8 +2488 1 +2391 3 +3774 9 +3238 5 +1534 4 +3440 3 +2611 6 +2878 7 +1931 8 +3668 9 +3139 10 +3822 10 +2184 3 +82 6 +3317 1 +1702 3 +4087 10 +519 3 +1944 1 +3830 9 +3563 10 +2150 5 +3735 9 +1158 2 +3265 9 +2571 6 +2587 4 +2073 3 +405 6 +3865 3 +42 4 +2358 9 +2632 1 +1629 5 +2968 10 +3160 8 +1934 7 +1108 3 +2324 9 +1923 4 +2536 10 +3112 3 +3817 1 +4008 3 +2118 10 +1034 6 +3094 8 +3868 9 +2484 6 +3791 7 +1456 5 +2643 5 +462 9 +1481 8 +1788 10 +811 5 +1441 10 +2258 6 +3559 5 +2816 2 +3886 1 +428 9 +2442 8 +873 2 +3460 2 +989 7 +2897 9 +1464 7 +1525 4 +685 7 +3906 4 +678 7 +1824 2 +2256 8 +1016 9 +3705 1 +3368 10 +136 1 +1154 8 +2478 10 +3323 2 +104 10 +932 7 +3100 8 +2465 5 +491 9 +1735 3 +1031 3 +2790 1 +1423 5 +2939 6 +1829 9 +1241 3 +386 4 +1934 8 +2883 9 +14 1 +686 2 +992 5 +3564 8 +551 10 +2074 3 +2344 1 +3593 9 +1103 6 +2668 6 +696 5 +4019 4 +1708 1 +2519 3 +3455 8 +28 4 +3639 8 +1977 7 +2429 5 +3549 7 +468 10 +2801 10 +848 7 +959 9 +2410 6 +3898 9 +2059 3 +1938 9 +3544 1 +3513 9 +1136 1 +302 4 +1589 7 +305 1 +3199 2 +847 4 +3900 6 +2632 6 +2193 6 +442 7 +3972 1 +3426 4 +1500 3 +1723 5 +2849 1 +2498 4 +3104 4 +3131 5 +1198 2 +1492 10 +2112 6 +1202 2 +2284 10 +1672 10 +3115 3 +2934 4 +990 4 +434 8 +3372 6 +1974 6 +2729 9 +3517 3 +2286 6 +1761 1 +3637 3 +3058 4 +1178 2 +985 4 +3 8 +939 6 +445 3 +1807 9 +2728 7 +1861 5 +2716 5 +3316 3 +2836 5 +174 3 +1190 4 +1061 9 +2375 6 +3599 9 +1048 3 +3021 8 +1421 5 +2090 10 +1289 6 +971 1 +3560 4 +1817 2 +3691 1 +2572 6 +1938 9 +576 6 +3178 3 +3265 6 +3747 6 +1332 1 +2812 9 +3574 5 +2033 7 +1103 4 +2806 4 +2506 5 +686 3 +3917 3 +350 5 +2609 6 +1906 7 +3969 10 +3419 10 +3338 10 +1448 9 +1050 3 +1080 5 +3620 4 +1286 10 +2202 5 +4079 7 +3722 3 +1210 7 +3678 2 +1323 7 +2341 7 +320 2 +3506 7 +649 4 +2993 5 +1165 6 +1384 9 +335 7 +2002 2 +302 7 +1502 1 +4049 9 +2628 3 +259 2 +2500 1 +2022 9 +541 9 +2910 2 +4089 6 +3356 1 +2474 9 +1941 2 +1025 2 +3026 10 +2314 6 +2102 6 +1122 7 +1833 10 +1692 1 +1372 3 +1302 4 +3883 10 +2310 9 +3151 9 +2447 2 +1205 5 +276 2 +2431 8 +611 3 +512 8 +1134 10 +758 2 +2418 6 +276 10 +2592 1 +1655 8 +2181 1 +3243 10 +2191 3 +455 4 +1130 5 +2880 8 +740 1 +635 6 +932 9 +3178 8 +1032 9 +89 6 +414 1 +730 9 +16 1 +3631 9 +1411 6 +2356 5 +2474 5 +3025 4 +3876 8 +2897 7 +957 5 +2621 6 +1568 8 +2610 8 +3253 7 +1169 1 +3292 4 +1035 2 +1417 5 +3613 10 +1063 5 +1779 7 +360 2 +208 3 +1014 7 +894 8 +2599 7 +4076 3 +3329 6 +2497 10 +1110 5 +803 8 +3322 10 +3100 7 +1921 8 +3077 2 +1052 7 +2808 5 +3802 9 +2708 9 +3412 1 +690 9 +2266 3 +112 3 +765 4 +3276 3 +3823 5 +181 9 +457 1 +299 6 +934 5 +3422 7 +3718 4 +1793 6 +3672 8 +2858 2 +3801 3 +1693 8 +3711 4 +2917 1 +291 6 +3209 1 +334 10 +3287 6 +626 5 +915 3 +2886 6 +236 3 +1390 10 +2523 8 +1386 10 +3340 2 +4047 7 +303 8 +230 2 +2390 8 +1983 5 +2897 2 +3922 3 +954 3 +3004 4 +3912 10 +393 1 +1768 3 +2783 2 +1522 6 +4055 8 +3429 6 +3884 2 +25 6 +3606 3 +3813 7 +2176 9 +2774 10 +2829 1 +2858 7 +3722 8 +1468 6 +1208 5 +3466 7 +446 2 +1824 4 +4056 8 +1036 5 +985 4 +2979 3 +3919 6 +479 3 +3896 5 +128 3 +2928 9 +1208 1 +1356 10 +928 10 +787 5 +3418 6 +421 8 +1985 3 +2218 3 +3452 1 +2255 3 +405 7 +3265 4 +2763 4 +641 10 +3202 1 +3754 8 +1949 3 +3120 10 +2017 9 +1932 9 +2302 9 +2060 9 +773 5 +3294 1 +2044 2 +2277 10 +3755 10 +3620 6 +69 6 +2237 4 +3696 3 +2141 7 +1698 7 +2629 7 +2951 1 +1211 8 +3830 3 +1858 3 +2153 10 +2512 9 +3088 10 +3996 3 +423 8 +584 7 +383 10 +2355 1 +2140 5 +954 4 +99 4 +1575 4 +2552 2 +405 4 +1175 10 +1124 10 +3839 8 +1711 6 +3475 8 +1104 5 +2724 4 +1185 4 +1081 9 +2892 8 +1177 10 +2260 8 +1362 1 +1979 3 +2161 4 +3940 7 +694 3 +254 1 +966 6 +3083 5 +920 6 +3555 6 +1233 6 +947 6 +3804 6 +1611 2 +951 1 +3524 10 +94 4 +3332 5 +3542 10 +152 7 +289 1 +539 9 +566 10 +3745 8 +2949 10 +2114 8 +2206 1 +364 5 +3081 4 +2286 9 +3450 1 +2703 10 +5 7 +1851 3 +2618 6 +1958 1 +550 3 +2220 3 +375 7 +3322 10 +3901 10 +2296 4 +732 1 +3721 8 +3064 1 +3315 5 +2066 10 +2566 7 +593 10 +36 10 +1177 2 +2225 9 +1485 8 +392 6 +3144 7 +2170 5 +2052 5 +1235 7 +801 2 +3439 1 +2565 9 +3646 7 +893 3 +1991 3 +2220 1 +1540 5 +1493 4 +3384 5 +1115 4 +488 6 +568 8 +1240 3 +4030 2 +3376 2 +3660 1 +2790 5 +3528 8 +1131 10 +1932 7 +2690 10 +3852 7 +2833 3 +785 1 +705 10 +2183 9 +3411 6 +2966 6 +2765 1 +3756 1 +199 4 +817 3 +3221 1 +1154 9 +1610 9 +1224 6 +3511 6 +3245 5 +75 3 +1353 8 +2848 7 +2353 4 +268 10 +374 8 +2591 9 +2501 8 +953 5 +2335 3 +1304 1 +407 1 +1556 9 +2965 3 +1263 7 +2258 4 +138 3 +1237 5 +1719 6 +1272 6 +1867 6 +3052 9 +2829 10 +515 10 +1874 9 +1699 8 +3351 2 +1303 10 +2853 9 +866 6 +3533 1 +895 2 +2287 9 +1954 9 +3352 9 +3760 2 +1026 9 +2074 6 +1529 4 +868 2 +3551 9 +3603 8 +1589 3 +2230 3 +1141 7 +3914 8 +3396 3 +1997 6 +898 10 +3176 8 +3063 7 +2957 5 +194 10 +2959 2 +1616 9 +686 1 +921 9 +2578 10 +3986 4 +2293 3 +2529 6 +722 7 +1783 3 +594 1 +2188 7 +1317 6 +992 1 +2754 3 +3113 7 +205 4 +3815 5 +3076 8 +1205 9 +1703 4 +3901 4 +1627 8 +2490 6 +524 4 +4031 10 +3070 1 +4004 9 +652 8 +891 8 +765 2 +248 9 +836 4 +2567 7 +1083 8 +1743 7 +3716 7 +2978 9 +2097 6 +3205 10 +310 4 +907 4 +2378 6 +85 3 +1268 1 +1250 4 +1745 4 +3608 4 +948 6 +3799 2 +552 4 +2391 9 +758 7 +2703 6 +2951 6 +2674 5 +3839 2 +1778 4 +3064 8 +2392 7 +1312 9 +798 6 +391 5 +3602 3 +1346 7 +2819 7 +3549 2 +476 8 +1661 5 +2335 8 +963 5 +3882 4 +2778 6 +521 9 +353 4 +1534 2 +3229 1 +2011 3 +3422 8 +757 9 +2851 1 +180 10 +584 10 +3797 4 +2092 8 +237 10 +2797 7 +3207 10 +3546 9 +1225 9 +282 3 +1545 2 +2111 7 +3439 1 +2231 5 +1814 3 +36 1 +1513 4 +1803 10 +2642 3 +2749 4 +3608 7 +2702 4 +1331 8 +3867 6 +883 3 +2695 6 +3879 1 +2200 10 +1720 4 +2801 5 +1463 1 +250 2 +3074 8 +1938 8 +115 3 +1161 5 +835 10 +962 7 +2543 10 +1828 7 +1488 7 +3860 1 +1497 2 +413 1 +3003 7 +3593 9 +3711 7 +1680 2 +2586 7 +3164 4 +1227 1 +2124 9 +2302 10 +541 7 +1123 7 +1261 10 +2938 9 +3420 3 +1604 3 +3772 10 +3921 10 +3518 4 +194 3 +456 2 +3212 4 +3898 5 +1158 7 +186 3 +449 3 +620 7 +330 8 +3579 1 +1214 2 +1598 2 +160 2 +3430 4 +2579 5 +2321 6 +3585 7 +1710 5 +4037 2 +3234 6 +3245 5 +3139 2 +2571 4 +536 9 +358 3 +378 8 +383 8 +1575 5 +432 5 +2731 1 +2298 2 +2600 1 +1525 5 +2324 9 +2883 4 +473 4 +934 3 +641 7 +3351 7 +1225 4 +1535 3 +2448 7 +3853 3 +1055 1 +2545 5 +3337 2 +1247 1 +2846 4 +681 2 +1495 2 +3803 4 +1023 7 +2533 8 +338 10 +3061 5 +2127 9 +1459 6 +99 7 +3569 7 +1724 8 +2816 4 +351 7 +2074 7 +193 5 +3012 7 +2078 6 +3269 10 +2182 1 +3485 10 +685 8 +2592 5 +2970 10 +170 1 +1314 7 +1342 7 +3914 8 +761 1 +3823 3 +2388 1 +3280 10 +2773 6 +3930 3 +1338 3 +895 8 +1576 3 +1445 8 +221 8 +415 6 +2915 1 +3712 2 +2374 6 +146 2 +333 10 +1369 1 +2909 10 +1699 4 +2560 8 +982 4 +716 3 +3109 4 +2823 5 +1810 2 +2582 8 +3314 3 +1875 4 +3040 1 +3229 7 +2454 6 +2690 4 +2880 4 +203 2 +3240 9 +639 6 +3636 10 +4025 5 +3986 3 +3159 8 +2873 1 +1798 1 +3724 2 +1942 6 +3947 2 +1767 8 +2916 3 +1358 8 +3242 4 +1710 2 +3440 9 +2958 4 +427 3 +1003 1 +2351 7 +2339 10 +3991 2 +3758 1 +3229 3 +2572 5 +297 4 +1987 4 +1033 4 +2941 10 +1582 1 +1775 7 +1510 1 +1216 8 +2154 6 +2178 5 +2009 10 +1887 8 +1090 10 +1213 9 +867 5 +1604 4 +3968 3 +2542 1 +156 1 +2056 6 +2008 4 +1882 1 +3508 5 +3603 10 +195 7 +226 7 +1070 8 +1523 3 +3067 10 +2665 6 +639 3 +3369 6 +3750 7 +1326 10 +3019 2 +261 2 +3191 7 +1692 9 +1403 1 +3822 8 +3 7 +1215 5 +2335 4 +52 3 +2325 8 +1872 2 +3000 4 +399 9 +962 4 +3591 5 +3366 9 +1774 8 +2512 10 +2805 7 +1001 4 +3962 8 +318 9 +2789 7 +3299 4 +1140 10 +1234 9 +1301 10 +2402 2 +2978 4 +494 1 +2857 9 +2856 8 +1970 1 +3511 8 +2335 6 +907 5 +730 5 +2194 2 +1785 10 +134 10 +4045 9 +872 5 +2925 5 +353 10 +3690 9 +3147 9 +2525 9 +1087 6 +2143 9 +1301 8 +76 9 +412 7 +2266 6 +2772 1 +1253 5 +2786 2 +186 10 +354 2 +3073 6 +1807 6 +2720 10 +496 5 +1936 9 +4044 9 +333 4 +3080 3 +2030 5 +831 8 +1824 10 +16 3 +3371 3 +3971 6 +1671 8 +183 10 +716 9 +144 3 +824 3 +1499 2 +288 7 +379 9 +2076 3 +1418 10 +3787 1 +549 2 +1904 1 +939 4 +1841 3 +2637 1 +1448 7 +420 1 +382 6 +2592 1 +2591 2 +1298 2 +2238 9 +3599 1 +2705 9 +3938 7 +2700 10 +2881 10 +3331 7 +1130 2 +3909 10 +2516 6 +1695 2 +196 7 +3700 1 +2510 7 +1838 8 +3886 8 +4041 7 +3904 4 +3272 8 +426 3 +3851 9 +1539 1 +2457 2 +2890 10 +968 9 +13 6 +613 3 +282 7 +1110 2 +2559 7 +1913 5 +153 5 +515 2 +2026 6 +2985 8 +144 3 +3929 4 +121 10 +478 6 +713 4 +1204 3 +2721 9 +171 7 +659 5 +3872 5 +719 4 +1651 4 +2765 3 +1370 10 +191 7 +3359 4 +3869 4 +900 6 +2104 2 +0 1 +3350 1 +2890 9 +305 7 +1997 7 +2885 8 +2138 9 +3940 2 +3704 8 +1379 9 +908 3 +1249 9 +1286 1 +1632 1 +2438 4 +2000 5 +1237 3 +1797 6 +3789 8 +111 4 +668 1 +3502 2 +1338 5 +1617 7 +4067 4 +2203 1 +2924 7 +2009 2 +1903 4 +3918 6 +1857 3 +1062 8 +2212 10 +1847 4 +671 8 +3686 1 +1788 1 +1578 10 +3501 1 +2554 1 +164 2 +2886 10 +1318 10 +570 5 +2649 10 +2581 4 +1103 4 +3748 7 +2504 5 +123 4 +3156 5 +1737 10 +1594 3 +667 3 +3426 7 +2117 10 +1626 9 +73 3 +933 7 +3979 9 +2199 3 +1885 2 +2168 2 +1276 8 +2458 7 +591 3 +1502 3 +2454 1 +471 2 +2918 1 +3221 4 +1135 8 +3922 4 +239 6 +723 6 +3865 8 +1145 2 +2640 7 +812 1 +3977 6 +2318 3 +558 8 +1479 7 +1248 9 +377 1 +2986 9 +3356 2 +2964 9 +2967 6 +3212 9 +2455 6 +3254 1 +933 1 +3326 3 +464 10 +4003 4 +3246 5 +2883 6 +3568 7 +3578 7 +3045 4 +1516 4 +3131 3 +2759 2 +2942 6 +1211 3 +3201 1 +333 1 +2319 6 +2033 10 +3489 6 +704 5 +1242 7 +1327 1 +1596 6 +19 3 +552 6 +4031 7 +4060 9 +3793 7 +978 3 +3817 1 +2194 4 +3677 6 +1684 10 +227 7 +2985 8 +2105 6 +3677 2 +1486 2 +3993 5 +1698 5 +3903 9 +2048 4 +568 10 +2101 2 +1272 4 +1358 10 +3457 10 +1460 7 +3763 3 +1066 8 +2459 2 +1117 5 +712 6 +4018 1 +425 8 +3698 5 +3277 2 +2648 8 +226 7 +1201 7 +158 8 +503 2 +1517 10 +803 9 +1582 4 +637 9 +3550 9 +2803 7 +2130 1 +2199 6 +1682 10 +3393 8 +352 8 +1107 2 +1994 8 +1894 7 +3787 2 +2311 9 +2262 3 +3517 1 +3867 9 +1868 2 +856 10 +4029 8 +2769 5 +253 1 +832 4 +3702 2 +468 9 +1984 8 +2524 1 +767 4 +2701 3 +4086 4 +660 4 +171 7 +221 7 +218 7 +2965 2 +3286 8 +1200 10 +3434 4 +1969 8 +1625 4 +501 10 +1701 9 +2440 7 +3201 1 +1870 8 +3934 4 +3252 9 +2169 2 +3959 5 +2629 4 +2557 10 +557 9 +817 3 +745 9 +3575 10 +651 10 +2591 5 +2432 1 +1689 9 +1173 7 +1743 5 +1163 3 +1320 3 +79 2 +1370 2 +2077 8 +3964 9 +1021 1 +1484 9 +1551 6 +3956 3 +2222 7 +3843 5 +347 10 +841 5 +3810 1 +3443 9 +9 2 +2063 9 +17 2 +3938 3 +1839 4 +1233 2 +2308 1 +2941 10 +1598 2 +1287 1 +79 3 +1377 4 +3143 7 +3366 2 +2660 2 +2225 10 +2731 3 +1070 5 +3581 7 +135 10 +1704 7 +1314 1 +1309 5 +3273 8 +3207 5 +4037 7 +1014 2 +3825 6 +2835 7 +3363 4 +3895 6 +2554 8 +1121 9 +3166 5 +211 6 +3249 2 +1744 10 +3165 10 +1191 2 +1054 10 +3828 10 +3761 3 +2625 4 +765 8 +3157 8 +3575 2 +3196 8 +577 10 +1460 7 +1447 5 +2756 6 +1208 7 +1100 5 +857 4 +1808 7 +4018 9 +2670 6 +3445 10 +3564 10 +3854 8 +3476 10 +2565 6 +1536 3 +3436 9 +2842 7 +423 3 +2912 7 +271 7 +1992 6 +883 5 +1287 6 +3277 1 +3560 9 +2265 3 +900 8 +2009 7 +2644 3 +1288 5 +2997 2 +329 2 +2344 4 +1900 5 +532 9 +2821 2 +3858 7 +1644 7 +2114 8 +848 10 +2820 6 +126 9 +2006 6 +2471 10 +3260 2 +2660 5 +3745 6 +1105 9 +3301 3 +2592 6 +3313 1 +1388 3 +2828 10 +138 2 +3765 6 +1882 3 +1552 10 +2130 8 +2421 1 +9 8 +1084 1 +1615 8 +2619 7 +1831 6 +3940 9 +1596 9 +1127 9 +1718 1 +814 5 +2365 9 +1654 4 +279 10 +3360 9 +4025 6 +224 1 +2529 2 +2277 10 +286 3 +1781 3 +2429 3 +98 1 +1214 4 +3920 2 +2300 6 +1818 10 +2490 1 +2674 10 +2767 4 +3042 9 +3007 1 +3082 6 +1264 6 +738 3 +2078 6 +3111 6 +10 3 +2939 3 +2420 9 +3298 6 +472 10 +3383 6 +3041 1 +557 2 +2520 5 +3695 4 +1487 10 +3723 3 +317 10 +3442 10 +574 8 +2151 7 +3178 1 +1727 9 +62 2 +3282 10 +564 6 +1492 6 +948 3 +3745 3 +3866 6 +749 6 +1150 2 +691 4 +1023 4 +2960 4 +173 2 +1170 5 +3284 7 +808 6 +4088 1 +2320 6 +1876 1 +1171 9 +3202 5 +1899 9 +3775 8 +1090 6 +881 1 +2486 9 +1102 10 +3164 2 +3261 7 +1200 3 +3738 10 +1250 3 +3947 10 +1409 3 +2226 5 +2599 8 +1847 3 +14 1 +587 8 +2833 8 +3511 8 +2348 5 +3814 3 +734 6 +1469 3 +3521 6 +1980 7 +2075 3 +675 3 +2818 3 +3436 7 +1169 10 +3998 8 +3268 4 +373 6 +2090 1 +1641 5 +1220 9 +502 3 +1103 1 +1907 6 +956 4 +112 10 +1229 6 +3587 4 +3008 10 +3458 5 +1991 3 +3781 9 +1335 1 +244 7 +1054 3 +1566 1 +1325 5 +3153 3 +4069 10 +318 1 +3883 6 +2088 9 +446 1 +2397 2 +2999 5 +3668 9 +2764 8 +1962 4 +2531 3 +348 4 +2445 2 +1730 2 +4070 9 +3439 9 +1430 7 +2819 7 +2225 4 +553 2 +2429 9 +1763 2 +503 4 +2692 7 +2899 1 +67 10 +3106 5 +2896 9 +66 2 +2111 3 +4061 7 +1103 8 +3469 3 +612 4 +1922 7 +300 8 +3712 10 +1386 9 +3626 4 +2924 3 +3897 4 +1149 5 +2435 6 +480 7 +2695 6 +1772 5 +1140 8 +2930 8 +2593 3 +252 10 +574 7 +648 2 +321 10 +3347 1 +391 7 +2755 6 +2834 8 +3028 8 +1339 10 +943 2 +3139 3 +193 7 +3133 6 +932 8 +135 3 +1621 4 +1837 6 +409 1 +3328 9 +3938 4 +2062 9 +3383 5 +3584 9 +1646 9 +3074 3 +1945 1 +734 10 +2558 5 +2644 4 +2850 1 +12 2 +1033 7 +1612 8 +3555 2 +3520 4 +1176 4 +254 3 +3906 6 +2661 10 +489 8 +3828 10 +2171 6 +2611 10 +1502 7 +622 5 +1913 4 +2033 6 +187 7 +1307 8 +3612 7 +2677 3 +1813 6 +3700 2 +99 1 +3300 6 +3535 7 +931 1 +3119 5 +3010 4 +78 6 +2386 7 +3633 5 +1706 7 +647 9 +669 9 +3026 4 +2259 3 +3716 3 +1337 5 +1813 8 +580 4 +3163 10 +2789 5 +3971 2 +1466 8 +1120 2 +2384 7 +4079 8 +1253 4 +428 5 +2713 10 +3247 3 +1031 1 +1398 6 +2114 6 +3392 3 +308 4 +1008 3 +655 7 +3483 8 +3 1 +418 8 +2071 4 +1238 2 +168 4 +642 4 +1031 6 +915 5 +742 4 +2101 2 +1627 9 +1593 4 +419 5 +1763 9 +77 6 +3463 6 +2740 4 +4000 2 +1192 5 +1959 2 +3150 8 +528 8 +1751 7 +1639 2 +2363 7 +277 8 +3790 7 +688 8 +1667 8 +1870 1 +3122 5 +795 7 +2150 9 +61 7 +44 4 +1213 7 +2420 3 +1355 4 +430 7 +1115 3 +3473 3 +2992 2 +2787 9 +789 6 +79 8 +786 6 +305 4 +1054 6 +2507 3 +197 7 +1296 1 +3126 2 +3274 1 +2143 3 +45 1 +4077 8 +1909 7 +304 4 +2444 5 +2457 3 +1388 5 +4003 3 +3304 7 +1671 9 +2554 6 +3080 2 +1004 8 +1610 9 +475 9 +597 9 +1984 3 +2096 9 +3046 4 +2725 6 +1141 10 +3287 10 +2049 10 +296 4 +439 2 +1424 10 +1080 9 +2884 5 +2767 1 +1619 3 +645 3 +2259 6 +866 5 +3559 10 +2414 9 +127 4 +1380 1 +1180 5 +2342 9 +467 2 +1500 7 +616 7 +2511 7 +1714 9 +828 3 +3509 4 +1002 2 +1340 7 +1886 10 +1203 3 +2010 2 +3289 10 +3963 4 +992 2 +1669 6 +1405 1 +3342 2 +1421 7 +2761 7 +459 4 +2007 5 +2400 5 +1601 4 +3057 2 +1086 9 +3956 2 +786 7 +1401 4 +1036 2 +1095 1 +258 10 +864 10 +402 6 +3880 7 +3268 2 +3968 6 +177 9 +450 1 +3520 9 +272 1 +474 4 +2195 8 +3049 4 +14 8 +1920 10 +964 7 +2409 10 +454 5 +716 1 +60 2 +280 10 +4013 10 +1825 2 +1639 10 +2149 10 +3730 4 +1631 4 +1600 1 +707 2 +765 3 +924 6 +2011 3 +3304 3 +3267 10 +1280 10 +2467 3 +3621 7 +2970 10 +3119 8 +834 1 +504 7 +2209 5 +1593 8 +2914 1 +2123 6 +2951 8 +3075 4 +3518 6 +2102 6 +1899 9 +2574 9 +4077 3 +1850 7 +3734 4 +2330 1 +2680 3 +1216 2 +3915 4 +3361 5 +358 3 +1317 8 +794 9 +1513 2 +2065 4 +3161 2 +893 1 +4062 7 +2286 7 +245 2 +4088 9 +3214 4 +4020 1 +1723 5 +1462 2 +2652 6 +2549 3 +144 8 +2646 2 +685 4 +3242 3 +2633 5 +2625 5 +2366 5 +2019 3 +3369 5 +1350 7 +4 3 +2019 10 +663 9 +2373 1 +160 10 +185 4 +215 1 +1706 3 +2565 1 +1158 1 +78 10 +2433 5 +1543 4 +1704 8 +3098 8 +832 7 +61 7 +433 7 +705 2 +837 3 +1622 3 +1025 1 +4074 2 +1897 6 +3598 2 +2113 2 +3735 5 +1622 10 +3517 5 +3540 1 +3656 6 +1388 8 +1985 7 +2284 2 +1937 1 +2800 5 +151 10 +3823 7 +2937 10 +3100 1 +2566 4 +1157 4 +1848 6 +3122 3 +2065 10 +2890 1 +869 5 +2450 1 +634 7 +661 8 +726 3 +3599 1 +1099 3 +2725 1 +1513 1 +1176 1 +3474 9 +3643 5 +627 1 +2773 4 +2173 4 +544 10 +2950 5 +1047 1 +2535 3 +2821 10 +3929 10 +3770 6 +477 1 +765 5 +3666 9 +1929 7 +715 10 +1941 4 +1299 9 +1912 7 +375 6 +1481 9 +774 1 +1516 5 +577 3 +1373 2 +2822 6 +3694 10 +3338 2 +1915 2 +2461 2 +673 7 +3165 6 +2635 5 +1900 5 +1264 7 +1580 5 +1310 8 +2815 1 +2053 2 +2750 7 +1522 5 +1601 5 +953 10 +3764 3 +4033 4 +3763 1 +3167 6 +630 10 +232 10 +3228 7 +3190 7 +1512 8 +274 4 +1299 5 +377 5 +1327 8 +860 5 +1489 3 +13 7 +1350 10 +3046 4 +3254 3 +1946 8 +2996 1 +395 7 +3068 6 +58 5 +2429 9 +1987 9 +2124 4 +2714 3 +3312 2 +153 7 +2558 3 +3051 3 +223 8 +2167 1 +2974 7 +3793 10 +918 6 +479 6 +3151 3 +2875 1 +3343 8 +132 4 +2995 1 +3006 9 +180 10 +3996 4 +3742 3 +3899 10 +3751 6 +2976 3 +1914 9 +183 2 +3004 5 +579 3 +766 7 +3381 7 +2072 9 +1223 8 +1063 1 +3020 5 +3778 4 +4055 2 +1371 4 +3756 4 +588 3 +328 3 +147 3 +2082 10 +1860 10 +3077 8 +2936 10 +3445 9 +2795 7 +3513 5 +2763 7 +73 2 +1480 7 +1475 5 +966 7 +2178 7 +4075 8 +3541 5 +3507 3 +2097 4 +1313 2 +2648 10 +3037 3 +668 3 +3828 3 +1366 9 +899 5 +1948 10 +1540 3 +2020 1 +1136 4 +3771 3 +3581 3 +1604 9 +3648 9 +3838 9 +3980 1 +100 5 +3022 9 +2117 3 +1617 2 +1856 4 +8 4 +4057 6 +2708 6 +3392 1 +764 3 +3595 5 +2560 3 +3670 2 +456 6 +542 3 +2333 3 +1134 7 +3643 3 +2835 6 +1091 2 +1616 2 +1525 2 +2960 5 +1424 1 +762 10 +2380 1 +1932 3 +377 3 +703 2 +2384 3 +1916 7 +429 7 +1986 10 +1064 4 +3871 3 +947 10 +1510 7 +1722 5 +3972 6 +442 7 +2630 4 +3923 9 +701 4 +878 2 +2700 1 +609 10 +2911 4 +2702 4 +925 9 +2769 9 +268 6 +113 8 +923 8 +1044 2 +1163 6 +3896 8 +1770 6 +343 6 +785 8 +102 7 +3757 6 +2902 3 +2140 2 +2897 1 +1369 7 +853 4 +3715 3 +3842 10 +2289 2 +3955 8 +1795 5 +2428 6 +212 1 +348 5 +368 3 +2240 3 +956 4 +3489 8 +1081 3 +1098 7 +2015 5 +147 8 +4028 2 +1067 8 +187 9 +1350 6 +1201 1 +2986 1 +2236 10 +722 3 +1902 6 +2518 1 +11 1 +407 7 +718 3 +3125 6 +1605 9 +1577 2 +1349 5 +899 7 +3277 4 +188 6 +2315 9 +2535 8 +2148 8 +2422 9 +93 10 +3583 2 +147 8 +507 7 +1484 5 +2812 6 +1520 6 +1901 10 +475 8 +1402 4 +1454 3 +2988 10 +2328 10 +2863 5 +1956 5 +1655 8 +988 3 +421 3 +3287 9 +3223 7 +2255 3 +1825 5 +2010 6 +2240 7 +2655 1 +38 4 +968 10 +3451 10 +759 1 +1362 7 +421 5 +1943 8 +1099 3 +1756 10 +513 7 +3683 10 +2108 9 +1000 7 +1072 3 +2710 6 +3839 1 +3884 9 +2408 8 +3533 10 +2453 7 +1253 3 +130 5 +280 7 +3464 3 +1994 6 +105 6 +3473 2 +1407 1 +3019 9 +1820 7 +3278 9 +16 8 +81 1 +1135 10 +2509 7 +2685 4 +1252 3 +585 1 +526 8 +1689 4 +3582 9 +350 7 +2432 4 +683 2 +437 6 +2594 4 +1520 5 +4041 9 +612 9 +2342 1 +2657 7 +1893 3 +528 1 +657 3 +1296 9 +4046 9 +1828 4 +2444 3 +1655 7 +175 9 +648 6 +1541 5 +2987 10 +944 1 +3777 2 +691 1 +1904 6 +1786 8 +1663 6 +1423 7 +597 7 +480 3 +2398 2 +417 10 +2610 9 +3464 7 +593 6 +2428 6 +2220 10 +317 6 +1135 7 +2762 3 +1943 4 +1736 3 +975 1 +14 6 +3681 6 +633 6 +2505 4 +3971 5 +2618 10 +3902 10 +618 2 +3249 9 +495 4 +4030 3 +86 7 +3327 2 +28 6 +94 4 +1717 5 +783 8 +2521 10 +4018 8 +2156 5 +1331 10 +958 2 +3362 3 +3351 2 +381 7 +114 1 +1805 7 +1903 2 +2663 9 +2542 3 +283 1 +3931 7 +1115 3 +563 3 +2584 8 +1400 6 +3584 5 +2605 10 +3338 8 +4029 5 +1157 1 +1828 3 +1982 2 +2276 6 +1531 4 +626 6 +181 7 +3734 5 +140 1 +2835 1 +3805 7 +3094 8 +2553 10 +1948 1 +69 1 +732 5 +786 2 +2152 4 +3992 10 +2884 9 +611 8 +2053 1 +3132 1 +159 6 +3376 4 +3846 2 +2703 1 +2660 4 +583 8 +3563 3 +3421 5 +2081 8 +1372 8 +3802 7 +3927 2 +1332 1 +401 10 +3164 10 +640 6 +665 6 +3261 4 +1292 4 +2037 10 +297 8 +607 7 +2218 8 +3101 1 +298 5 +709 3 +472 3 +1995 1 +1475 7 +3289 2 +1152 10 +188 1 +2554 3 +2655 8 +388 5 +386 3 +3997 5 +933 9 +2941 1 +4047 3 +85 8 +3850 5 +1757 3 +3920 3 +1611 4 +1817 6 +2138 1 +2944 4 +244 3 +3902 4 +93 8 +1614 9 +1851 3 +621 9 +3211 9 +503 4 +3034 3 +2328 6 +4021 9 +1839 6 +221 8 +908 9 +2417 7 +819 7 +590 8 +1940 1 +1652 1 +3750 3 +191 3 +2247 8 +167 3 +1034 5 +34 9 +295 5 +1149 7 +1762 6 +1853 1 +2450 5 +1682 3 +369 7 +3726 1 +613 4 +3931 5 +2214 3 +303 7 +1091 2 +642 5 +1675 8 +743 4 +1176 5 +2579 1 +2473 5 +3862 3 +3672 1 +1129 8 +1191 6 +3790 3 +2537 10 +1950 3 +2653 6 +3653 3 +1212 4 +1082 10 +147 5 +1468 5 +730 6 +2640 1 +335 7 +2568 8 +2719 1 +689 3 +686 3 +2145 6 +50 8 +2911 8 +3260 5 +3244 5 +3703 1 +577 8 +2192 6 +1459 7 +759 10 +2185 10 +895 6 +3981 4 +1420 3 +2161 5 +2529 7 +2943 10 +778 3 +828 10 +4087 7 +2416 8 +692 2 +3985 6 +395 6 +3628 10 +3951 7 +3089 8 +2571 2 +2867 2 +982 5 +1022 1 +442 4 +2390 2 +3345 1 +308 2 +3818 7 +3433 6 +3896 1 +694 6 +3157 2 +2557 7 +2151 9 +2786 1 +751 8 +371 7 +4051 2 +1717 5 +439 4 +2833 3 +3278 8 +1070 4 +459 2 +2349 3 +46 7 +588 4 +539 3 +3371 6 +1310 8 +2531 5 +2075 1 +2766 2 +3242 8 +3066 4 +2900 10 +3021 3 +7 6 +3311 6 +2171 8 +3750 1 +1550 1 +756 1 +1849 1 +2649 6 +1134 10 +2693 2 +52 3 +2004 3 +1782 10 +3076 2 +1586 7 +3650 9 +1705 5 +3287 9 +2025 8 +1077 9 +2233 3 +1816 2 +1850 7 +273 1 +3458 9 +2606 6 +83 2 +2657 10 +2486 4 +4052 7 +2874 10 +520 4 +2485 6 +2587 7 +3806 7 +4024 4 +3391 10 +2760 6 +3009 2 +144 3 +1414 5 +3565 8 +3128 9 +3192 7 +3333 8 +318 1 +3937 7 +2027 2 +951 10 +2610 9 +1260 10 +3343 9 +3218 6 +3079 9 +1587 3 +1032 5 +658 8 +868 10 +1085 10 +749 5 +4028 6 +1029 3 +3979 10 +4001 9 +1181 8 +1281 6 +320 5 +68 4 +4085 2 +1857 3 +3240 1 +1193 2 +525 5 +3535 7 +2438 6 +1771 9 +2812 1 +3815 8 +144 2 +366 6 +1847 2 +1434 3 +3170 6 +76 1 +3522 7 +3703 1 +2016 10 +1516 1 +1804 2 +1727 8 +2682 6 +2672 5 +687 1 +442 2 +314 4 +2553 3 +2489 5 +1319 9 +2001 2 +2297 1 +935 8 +3378 6 +2472 4 +1358 4 +1640 4 +1958 10 +1719 7 +32 9 +3620 10 +2455 9 +1186 8 +3283 8 +1937 2 +2787 3 +2208 6 +1680 8 +3348 5 +886 5 +213 10 +3651 6 +2328 5 +3140 1 +783 1 +3679 2 +486 3 +3997 6 +2420 2 +3116 7 +2596 6 +651 1 +594 8 +1197 5 +1954 5 +2844 1 +2550 5 +311 2 +3818 4 +3099 7 +4072 10 +4085 9 +1618 9 +2572 6 +3031 8 +43 10 +224 9 +1515 2 +1248 2 +3187 6 +2950 8 +3835 5 +2238 4 +4030 2 +2980 10 +2152 8 +1105 5 +1238 5 +3564 10 +1892 3 +1019 10 +1351 8 +2964 9 +2191 9 +4058 7 +1366 7 +1843 10 +2136 7 +210 2 +1870 3 +2307 8 +1405 4 +2098 2 +420 3 +3166 9 +3400 1 +2946 9 +1210 6 +850 6 +906 3 +256 10 +2817 7 +2319 10 +1367 8 +717 5 +149 4 +1035 4 +964 3 +1747 2 +3494 1 +3187 1 +1071 8 +2716 1 +319 4 +3392 7 +851 2 +1355 4 +1907 2 +385 8 +958 1 +933 2 +4004 7 +306 9 +637 4 +2620 10 +131 8 +3138 7 +3146 5 +3665 10 +342 1 +2361 7 +3332 7 +1153 4 +1208 3 +3453 5 +2285 2 +1692 9 +1565 9 +3932 5 +1129 2 +1282 4 +1323 7 +194 6 +1363 1 +1288 3 +4087 2 +3244 2 +1408 4 +3278 9 +3000 8 +84 3 +3788 6 +3777 9 +352 6 +3082 2 +3815 8 +401 3 +278 7 +1410 6 +736 4 +1051 2 +2683 8 +2580 3 +2862 5 +769 5 +3626 5 +4006 7 +618 5 +1977 1 +771 7 +4026 8 +3212 4 +1323 5 +2699 8 +3683 7 +4081 10 +4042 10 +2115 5 +2221 1 +1006 6 +3965 7 +1466 5 +2782 7 +3883 10 +465 3 +3280 1 +1152 10 +557 9 +1061 10 +1181 1 +1449 3 +2154 9 +3221 10 +108 6 +1115 10 +2308 6 +287 8 +1775 5 +1918 5 +978 6 +1054 9 +848 9 +1469 8 +729 4 +2086 4 +2710 6 +3468 2 +2673 3 +676 9 +3198 4 +985 1 +3647 8 +1025 7 +1461 5 +3741 7 +3780 10 +2885 8 +37 9 +3114 1 +1704 4 +2775 3 +3515 7 +2277 9 +2176 1 +3196 7 +3231 10 +2693 4 +2855 8 +1774 1 +3426 6 +1097 9 +2088 8 +178 1 +405 4 +3199 9 +2633 8 +1241 1 +3782 8 +3637 2 +2732 9 +1295 10 +2952 8 +585 2 +1605 6 +1753 6 +3015 5 +184 5 +872 3 +4030 4 +1418 5 +2318 7 +3813 7 +2012 6 +574 7 +2574 10 +2898 2 +1492 3 +3735 7 +2882 9 +1446 10 +1671 10 +1146 3 +2947 5 +3150 8 +2796 4 +872 8 +3915 10 +2135 5 +1806 4 +3748 9 +3824 10 +3866 4 +2236 9 +3597 7 +3421 7 +608 9 +227 10 +1735 10 +674 10 +2621 8 +2742 8 +2056 7 +3717 3 +2211 10 +2546 2 +2210 6 +2756 5 +268 3 +2698 2 +276 4 +424 4 +3217 3 +221 2 +660 7 +1626 4 +2158 10 +324 7 +609 3 +3056 1 +2207 8 +1253 7 +1224 3 +2636 9 +3560 6 +3137 7 +3178 5 +3879 3 +2797 5 +2394 9 +550 8 +3610 2 +384 7 +1668 7 +3456 4 +1876 5 +1874 1 +1244 8 +3161 6 +1389 6 +1097 7 +743 3 +3599 9 +2129 2 +3620 7 +858 3 +3993 4 +1686 6 +2561 3 +3456 7 +656 6 +3245 1 +734 5 +849 1 +897 2 +2861 1 +1711 8 +1549 3 +1081 3 +1208 6 +4063 3 +66 8 +2047 7 +2031 6 +704 3 +1293 5 +2441 8 +2816 9 +3667 10 +709 10 +1702 8 +3080 9 +389 7 +1949 1 +3887 7 +1712 2 +3273 10 +3876 2 +1662 6 +117 10 +923 6 +193 2 +3301 10 +3128 6 +2148 5 +2265 6 +3990 7 +2615 3 +3310 7 +2775 5 +3110 10 +2657 9 +1001 7 +1065 1 +1793 7 +533 9 +2986 6 +2089 9 +26 3 +2384 5 +3568 8 +969 2 +3062 3 +2330 6 +661 8 +956 7 +1684 3 +448 4 +2293 1 +2192 8 +3401 1 +1961 2 +869 3 +132 9 +902 9 +3533 6 +2493 5 +2162 2 +1644 7 +2240 1 +2152 6 +1617 9 +1023 5 +1934 10 +3861 3 +2532 1 +2440 2 +3584 6 +1317 1 +1939 8 +931 7 +125 4 +2073 4 +1806 3 +2377 2 +2070 3 +532 2 +741 10 +1092 6 +2350 1 +455 5 +2687 1 +2664 4 +3497 4 +1812 6 +1456 1 +394 8 +3347 3 +937 10 +3880 2 +1317 9 +3140 4 +300 8 +397 1 +2059 5 +2476 9 +1608 1 +3288 5 +2640 2 +1757 3 +2641 6 +2603 5 +2545 2 +3159 9 +3387 7 +3987 8 +1645 5 +2049 1 +2995 1 +1532 1 +2478 3 +2599 7 +3035 2 +768 6 +525 2 +3308 10 +246 9 +1723 5 +2727 9 +518 9 +1222 5 +677 2 +1196 2 +1824 3 +3310 4 +1129 5 +2665 2 +2004 6 +862 2 +1190 2 +2075 5 +2657 9 +2618 7 +3337 7 +3113 9 +1970 4 +1988 1 +863 8 +2625 10 +147 9 +1395 6 +2187 2 +1039 5 +1843 6 +1805 10 +1913 1 +2793 9 +2420 3 +1987 7 +1233 8 +3491 4 +3761 6 +2967 2 +443 3 +1502 6 +1586 10 +99 9 +2373 7 +3045 2 +945 7 +1145 2 +658 8 +682 2 +2717 2 +3663 1 +3178 1 +1558 10 +3148 3 +1159 2 +968 8 +3862 8 +2476 6 +63 9 +142 7 +2412 3 +2505 3 +4079 7 +3113 9 +1160 8 +1234 5 +2604 6 +3123 4 +366 3 +2954 1 +2298 9 +3526 7 +3071 2 +1579 2 +3108 10 +341 10 +3385 8 +3201 2 +4024 3 +3989 1 +2840 3 +803 10 +1698 8 +1100 10 +2982 9 +1657 7 +3584 8 +3626 3 +1983 1 +1765 10 +3843 4 +3101 10 +2972 8 +1692 9 +1874 4 +188 2 +1425 10 +2366 2 +3314 1 +2063 9 +2354 1 +2565 4 +1190 10 +3072 7 +945 6 +2670 10 +102 3 +3070 7 +1750 5 +506 8 +3060 2 +3108 9 +40 10 +1995 4 +2963 2 +217 6 +1585 5 +661 5 +769 4 +3476 9 +1583 7 +128 4 +1154 1 +3485 3 +276 2 +2850 4 +4026 9 +1551 8 +3113 3 +1887 5 +1895 7 +653 4 +960 4 +4060 9 +2873 8 +1374 3 +2762 2 +2336 5 +2954 4 +3048 7 +3791 9 +2818 3 +2544 9 +2364 6 +1081 8 +1369 3 +2397 9 +3635 8 +3219 2 +1811 4 +1532 2 +2492 4 +229 9 +1725 8 +1608 8 +257 2 +486 9 +2756 5 +212 8 +3191 9 +1855 4 +3752 8 +2958 4 +1134 3 +3533 3 +1951 10 +2131 4 +2610 9 +2919 4 +3949 2 +3292 2 +1456 1 +2276 4 +3196 5 +3501 8 +1020 10 +1175 5 +3252 3 +3757 5 +2920 4 +1755 9 +410 3 +605 7 +1207 8 +2536 5 +3803 4 +972 9 +259 6 +2712 3 +1886 6 +1610 10 +3107 5 +100 10 +1551 1 +2627 8 +876 6 +979 1 +3767 7 +1682 4 +3011 10 +1346 3 +4060 2 +749 2 +985 4 +1607 7 +2158 9 +219 10 +1320 10 +989 8 +2288 9 +4002 9 +3639 3 +2251 6 +108 8 +3571 5 +1871 4 +1798 8 +3303 9 +830 10 +204 5 +2710 4 +690 1 +871 2 +3513 7 +1718 6 +1493 8 +2766 2 +2847 7 +3304 4 +1122 5 +4016 9 +3035 3 +3626 7 +1202 3 +2422 2 +2267 9 +2837 2 +1253 10 +2135 4 +2592 7 +895 1 +497 7 +258 8 +2515 9 +3309 7 +1945 10 +279 7 +807 7 +750 4 +2745 7 +3154 2 +1091 1 +55 6 +3749 2 +2469 8 +1771 1 +434 8 +935 8 +3013 3 +241 10 +343 3 +3839 7 +2967 4 +2877 9 +729 1 +2844 2 +1627 1 +1805 6 +355 3 +3715 3 +3513 3 +294 4 +3911 8 +1748 6 +3890 10 +1027 1 +3646 7 +1210 8 +3549 3 +882 4 +2439 8 +3578 7 +606 3 +3881 6 +2532 6 +1396 8 +3425 10 +778 8 +3003 10 +1838 10 +1596 5 +416 8 +2314 4 +2755 9 +2133 6 +3384 1 +3039 10 +2575 8 +93 7 +134 10 +2137 3 +1431 2 +1299 6 +1745 8 +943 5 +496 2 +394 1 +0 8 +693 5 +3931 3 +3976 10 +3829 10 +3181 7 +1338 5 +3057 10 +2894 9 +2043 1 +3121 10 +2248 10 +1188 8 +265 8 +3422 3 +3565 4 +649 9 +2980 1 +2923 4 +3570 8 +357 3 +442 4 +1470 4 +2726 10 +4003 8 +1331 5 +3786 7 +2368 3 +3113 8 +902 3 +426 8 +1570 10 +1944 2 +4049 7 +3548 1 +728 5 +1047 7 +3482 10 +2645 2 +928 9 +1986 1 +209 3 +2623 2 +3860 4 +1380 8 +4026 7 +3918 5 +1051 10 +3944 3 +3250 2 +694 10 +402 6 +1707 7 +4037 10 +1283 5 +1261 1 +104 10 +2859 1 +1262 7 +3877 8 +466 8 +122 1 +3346 9 +3570 8 +1921 8 +3987 3 +1670 10 +2598 2 +3718 10 +2091 5 +3745 9 +1009 5 +2823 3 +2506 3 +2945 4 +1941 1 +2372 4 +833 7 +2509 4 +3358 1 +401 7 +3688 8 +3441 4 +306 9 +3991 7 +1636 5 +789 9 +3662 6 +728 2 +3376 3 +2619 7 +3994 8 +3485 1 +1844 4 +2819 3 +1027 9 +1267 7 +2068 4 +1659 6 +1878 4 +3620 8 +778 3 +3801 8 +1354 1 +1967 5 +3829 7 +1123 5 +3990 9 +3199 3 +2923 3 +1366 1 +3516 10 +1228 4 +1367 4 +3435 7 +1213 4 +564 7 +3668 7 +1730 5 +2317 6 +1688 4 +1647 1 +3429 6 +1080 4 +721 1 +1795 8 +3204 9 +3529 8 +581 3 +1833 6 +2435 2 +3641 4 +3085 9 +1569 6 +2799 6 +1389 7 +418 7 +3103 6 +2438 6 +3126 5 +501 9 +2675 9 +750 1 +504 3 +372 10 +1741 4 +3746 6 +4075 10 +2654 8 +622 10 +633 5 +2107 10 +869 3 +66 3 +1724 8 +2734 7 +3801 2 +414 8 +2164 1 +2812 2 +396 9 +2526 7 +3088 1 +277 4 +3455 4 +2535 8 +3039 6 +2670 3 +762 3 +2842 4 +3746 1 +1691 4 +429 4 +3319 2 +192 3 +3180 4 +3633 10 +1232 10 +2420 2 +622 8 +1721 1 +3665 8 +2476 1 +2432 5 +2419 7 +1778 6 +2852 8 +3101 5 +948 2 +1896 6 +311 7 +3321 8 +1686 3 +3126 2 +2589 5 +3920 6 +3499 3 +404 2 +1581 6 +3045 4 +3363 4 +481 5 +3439 8 +2868 8 +2306 2 +1331 1 +1352 4 +797 3 +2136 7 +2222 5 +1796 10 +1541 3 +144 7 +3522 1 +3608 5 +3480 2 +423 9 +1621 1 +3896 3 +614 8 +610 10 +975 6 +287 5 +1651 6 +4087 7 +1979 10 +1406 3 +2786 2 +2682 8 +901 6 +2356 1 +1623 9 +1311 10 +3431 6 +873 7 +2216 4 +3918 1 +3801 4 +2766 8 +4005 10 +767 1 +1933 2 +1532 3 +79 5 +2101 3 +2366 8 +412 6 +2925 9 +3375 3 +1773 4 +4009 8 +3572 8 +1512 5 +1188 2 +3942 7 +3366 6 +1544 6 +3548 10 +340 1 +678 6 +3557 6 +922 6 +3996 5 +1672 7 +1910 5 +1099 2 +3570 9 +4029 2 +3950 6 +1599 10 +1841 9 +3785 5 +3981 6 +3063 9 +986 9 +347 10 +1832 5 +2273 1 +2509 8 +2470 5 +2067 10 +719 6 +1269 8 +2941 1 +4031 7 +3032 3 +2822 5 +916 7 +1781 4 +2107 1 +3950 2 +2227 7 +3153 4 +610 5 +913 3 +403 6 +340 7 +3573 10 +1325 9 +881 7 +3903 4 +799 9 +1249 8 +2114 3 +3648 1 +4076 4 +3782 10 +68 6 +3936 9 +2202 9 +3932 4 +1467 4 +2978 5 +476 4 +222 9 +2747 1 +1227 9 +1823 8 +2387 10 +1440 4 +2887 10 +943 4 +875 5 +1401 1 +1615 10 +3520 2 +2384 10 +2884 8 +3669 5 +2387 9 +164 6 +172 3 +2510 2 +2926 9 +3235 6 +1881 5 +1950 7 +3728 6 +1128 1 +417 6 +836 6 +149 7 +1300 6 +3946 8 +86 10 +3291 8 +1233 3 +3856 1 +3118 1 +1761 1 +430 5 +938 6 +297 4 +1548 1 +2995 4 +1048 3 +3783 5 +3499 7 +3868 2 +2272 10 +4007 10 +3906 10 +309 3 +1660 10 +2925 3 +2792 7 +773 4 +3786 1 +3468 5 +2748 1 +1680 6 +978 7 +815 5 +1632 6 +291 9 +3937 1 +1277 1 +4071 2 +3781 5 +1858 3 +399 6 +1108 8 +3145 6 +2173 9 +3652 6 +1588 4 +1241 7 +2724 5 +2344 6 +279 2 +2602 8 +588 9 +3281 5 +742 2 +3824 3 +2506 9 +60 4 +2815 4 +3679 1 +2121 7 +755 9 +3033 1 +1025 3 +1265 10 +1513 2 +1802 3 +2800 9 +1695 1 +229 10 +466 1 +126 8 +4027 5 +943 7 +4066 8 +2329 5 +3925 2 +3970 6 +553 4 +3589 3 +1504 10 +939 2 +829 8 +3608 4 +3197 9 +1613 4 +2219 3 +2744 10 +296 7 +3970 6 +3902 5 +1915 2 +3423 4 +3305 9 +3303 9 +1819 5 +3765 3 +509 6 +1146 9 +2902 6 +4035 4 +950 9 +1946 7 +3092 3 +397 3 +2952 4 +870 7 +3611 6 +2213 10 +2894 3 +540 8 +1944 3 +1879 8 +2040 4 +1552 10 +2498 2 +823 4 +452 8 +3351 1 +3025 7 +3241 5 +2244 7 +3168 4 +2072 6 +195 5 +880 6 +1257 7 +3455 2 +504 7 +1848 2 +2660 4 +2317 8 +1884 3 +225 4 +1809 10 +552 5 +1112 5 +340 8 +3021 2 +3084 3 +2140 6 +519 8 +1879 2 +2878 5 +1785 10 +1589 2 +1259 2 +3609 5 +2048 10 +2345 10 +670 8 +3944 6 +1773 9 +1612 7 +4076 4 +2856 9 +332 9 +2127 8 +1091 2 +3606 6 +751 3 +4036 9 +3866 9 +1326 3 +1120 9 +3361 8 +417 6 +1075 2 +1459 6 +1269 5 +3602 5 +2276 1 +678 3 +3846 9 +206 3 +1592 5 +1677 4 +2752 4 +2158 1 +2350 6 +2931 8 +2294 1 +1215 1 +363 3 +1423 3 +1526 10 +199 1 +3893 7 +3443 1 +2004 1 +1796 3 +292 9 +3030 5 +1002 7 +1657 4 +717 4 +1567 3 +663 8 +4037 10 +1253 9 +2510 4 +1699 4 +2198 6 +202 8 +777 10 +3846 3 +2196 5 +2910 2 +2246 9 +3640 9 +1491 5 +1503 10 +1670 4 +344 7 +3988 9 +1347 2 +502 10 +2808 3 +3885 5 +2786 2 +267 3 +3512 3 +3211 10 +491 9 +2175 7 +2833 3 +3513 6 +3403 9 +973 10 +1560 3 +734 4 +533 2 +1839 1 +1926 4 +2975 1 +2156 3 +3377 2 +2299 4 +666 3 +3981 2 +2857 6 +627 6 +34 7 +3789 7 +2067 3 +751 6 +2819 9 +1311 9 +1113 5 +2389 1 +2600 9 +1820 6 +1090 9 +3392 3 +2987 2 +2031 2 +2522 2 +4004 1 +151 2 +3816 3 +2188 6 +2184 7 +540 2 +2076 6 +3861 10 +3289 2 +1024 6 +2344 1 +1880 4 +1704 3 +395 2 +3616 3 +3136 4 +2388 5 +3016 3 +3086 8 +2745 3 +2143 7 +1009 9 +3566 9 +155 8 +330 4 +3616 3 +2777 5 +34 7 +3824 2 +58 3 +1069 9 +1959 6 +1326 10 +121 1 +39 2 +708 8 +433 3 +2002 3 +1537 9 +459 1 +2062 1 +2212 1 +1689 2 +301 8 +785 9 +1777 4 +2689 4 +2614 5 +3668 7 +3096 8 +433 3 +3618 1 +902 10 +760 3 +1181 10 +570 1 +3705 6 +2119 1 +2040 7 +75 9 +945 8 +1652 2 +261 4 +1925 5 +400 1 +1630 4 +3873 6 +3964 3 +3633 10 +2434 6 +3058 9 +437 2 +1939 4 +1577 1 +585 5 +3775 1 +3825 3 +3629 7 +98 3 +593 10 +2123 9 +2668 9 +1845 8 +440 6 +3140 4 +1397 8 +2796 6 +1974 10 +2409 7 +1383 6 +3167 9 +3146 2 +3175 1 +2007 2 +4083 2 +782 9 +2423 7 +41 5 +2687 9 +1083 5 +2213 6 +1865 10 +1077 2 +770 4 +3067 1 +2747 3 +3136 5 +2861 7 +2093 4 +3547 4 +3509 10 +3388 2 +3252 6 +2245 10 +2690 1 +915 7 +2760 2 +2304 10 +1416 3 +1226 10 +2056 7 +371 4 +1700 4 +1080 3 +722 8 +1133 4 +1915 7 +22 8 +368 2 +1223 5 +513 3 +216 5 +923 10 +4081 6 +1186 7 +2072 10 +335 2 +3573 6 +1543 8 +1825 3 +110 10 +2327 1 +1010 6 +1954 4 +3420 2 +1862 4 +3075 10 +2937 9 +3747 3 +322 2 +2944 9 +3751 6 +2462 10 +3596 9 +686 8 +2853 1 +2072 1 +2941 9 +513 10 +3508 4 +419 3 +1327 2 +1594 10 +3150 7 +3013 1 +3214 3 +2671 5 +3782 10 +3802 1 +3958 10 +3795 6 +1522 6 +1401 4 +220 6 +2269 10 +3654 3 +755 1 +1803 6 +3780 2 +194 4 +4057 1 +2433 1 +856 7 +3131 5 +3963 6 +1949 6 +1643 7 +3594 6 +342 10 +3132 8 +1849 3 +2588 5 +3774 9 +186 9 +2446 4 +162 3 +1681 8 +320 1 +473 5 +1648 8 +809 5 +1421 6 +1656 7 +2678 4 +3269 2 +2563 7 +669 4 +921 2 +3819 10 +1546 6 +2286 9 +381 3 +3492 5 +1230 3 +195 4 +3236 9 +631 6 +1848 8 +2904 2 +3668 2 +1794 8 +3286 1 +3144 4 +1830 7 +1039 8 +3926 6 +3408 5 +605 1 +3806 10 +2356 3 +2266 1 +1520 5 +702 8 +380 3 +122 7 +1726 4 +1139 4 +3062 3 +2496 7 +3760 10 +211 6 +2970 4 +1211 3 +2315 9 +2739 6 +1137 9 +1725 6 +3946 4 +3446 10 +1218 10 +3736 5 +3246 1 +3816 7 +3051 6 +340 3 +3934 8 +2177 8 +963 4 +1978 9 +1076 5 +3329 7 +2824 6 +900 7 +1077 7 +591 5 +809 5 +1175 2 +598 2 +3882 2 +1753 1 +3796 1 +2958 7 +2551 5 +2574 7 +2240 1 +578 1 +2462 10 +2082 9 +4043 2 +489 4 +2008 7 +3176 4 +2675 9 +3178 2 +1655 7 +3293 3 +433 6 +3353 2 +2230 7 +179 5 +2290 5 +69 9 +2822 4 +908 1 +1488 3 +103 1 +1803 10 +3633 5 +1447 5 +1165 2 +414 5 +3311 5 +1882 8 +3396 10 +2937 9 +1823 2 +1895 2 +3746 9 +1409 3 +677 4 +266 6 +2961 3 +3229 2 +284 10 +510 5 +1385 4 +1105 9 +1481 10 +2218 7 +3113 9 +1185 10 +481 4 +3427 4 +859 5 +3885 8 +2238 5 +1933 10 +3188 7 +3824 2 +3712 2 +3336 7 +1127 8 +3648 5 +2894 9 +1370 4 +2276 2 +2952 6 +3528 10 +3977 6 +3714 3 +255 3 +1946 4 +2867 10 +978 8 +3391 1 +3137 6 +3584 6 +3170 1 +1441 6 +3988 2 +68 1 +2842 1 +2574 5 +525 10 +2742 6 +873 7 +3436 9 +836 2 +1320 4 +298 4 +3559 1 +3008 2 +2519 5 +649 2 +3098 6 +1217 9 +430 4 +508 3 +3641 8 +2941 8 +1172 7 +3938 8 +987 10 +2640 7 +2175 7 +1589 1 +3858 6 +1799 7 +2386 5 +2921 5 +229 9 +1875 8 +3662 5 +3382 5 +1457 8 +2667 1 +1020 4 +1529 8 +2273 3 +3537 9 +2486 3 +3058 8 +3500 4 +3907 2 +4023 8 +2301 5 +875 10 +853 4 +1284 10 +1577 7 +568 2 +3351 9 +3747 8 +1624 8 +3734 1 +1924 2 +453 5 +2140 10 +2486 6 +886 4 +1088 4 +1911 8 +1722 3 +260 6 +1655 1 +1627 10 +575 4 +2477 5 +3718 5 +1236 2 +1886 10 +608 1 +2025 10 +442 8 +664 3 +3810 7 +802 6 +1433 1 +1700 8 +1823 7 +3167 3 +679 6 +2025 9 +3808 7 +1765 9 +2703 1 +2508 6 +1762 5 +1219 4 +2483 10 +3182 7 +3739 2 +1473 6 +1270 1 +3942 2 +3869 10 +650 9 +713 1 +2696 6 +2817 7 +2214 9 +3339 8 +3379 2 +444 1 +837 9 +3325 6 +3605 7 +133 9 +3903 5 +129 7 +919 9 +67 2 +1519 6 +2093 2 +863 9 +2481 10 +2267 4 +388 1 +4034 5 +2236 2 +2963 8 +2563 10 +2641 10 +1925 7 +435 10 +946 2 +1408 3 +1672 9 +1064 10 +690 3 +1566 6 +3434 1 +2659 9 +3511 9 +157 1 +1768 6 +3980 2 +3126 4 +1763 7 +1494 1 +956 9 +1267 4 +1485 1 +368 10 +3108 5 +1683 9 +2098 5 +2746 6 +612 3 +1994 5 +3867 5 +2411 9 +3485 4 +3200 6 +807 3 +2942 5 +3652 6 +3093 5 +1102 9 +3343 5 +1669 7 +366 3 +2797 6 +1969 3 +3297 4 +2688 10 +3444 6 +1576 8 +2409 4 +19 5 +76 4 +241 8 +126 2 +342 5 +2267 8 +322 3 +1458 3 +771 5 +355 7 +1012 6 +1410 2 +225 4 +625 1 +1537 5 +3643 4 +4017 7 +1681 10 +18 7 +988 9 +531 6 +3340 1 +3715 5 +552 4 +481 5 +2289 9 +2799 2 +1854 9 +3959 4 +3941 7 +697 4 +3044 5 +3879 10 +823 2 +482 7 +766 5 +1611 2 +1186 1 +1063 5 +3696 4 +3997 4 +1121 2 +1532 4 +3565 2 +3844 8 +3642 2 +2298 8 +3612 4 +3319 6 +2730 3 +1361 9 +2790 3 +2653 10 +3237 4 +2719 2 +88 5 +894 1 +4048 3 +645 4 +2641 7 +970 9 +3808 3 +3216 3 +343 1 +2582 9 +3595 5 +2230 10 +2953 10 +2343 8 +2333 5 +2659 3 +3320 10 +2310 9 +3659 1 +2166 6 +1147 7 +3420 6 +3912 1 +2932 6 +4095 5 +815 3 +671 10 +1709 10 +437 3 +2612 7 +948 10 +582 8 +600 3 +2057 10 +1943 1 +3193 6 +1005 5 +2603 2 +1975 6 +1551 7 +861 9 +805 4 +2556 8 +2980 8 +1150 9 +2859 8 +3236 10 +2504 7 +3151 2 +2432 10 +1337 8 +3581 5 +2099 6 +2249 1 +2755 9 +3959 9 +2478 4 +1950 2 +696 9 +783 8 +3474 10 +1250 4 +1640 4 +406 8 +1045 2 +2403 10 +465 1 +2555 10 +867 6 +932 5 +782 8 +991 1 +3450 4 +2163 7 +4014 5 +2548 10 +2088 9 +2206 8 +2695 2 +2360 8 +3681 2 +1849 7 +2659 4 +688 9 +375 8 +1702 10 +110 1 +2464 1 +3988 5 +1309 4 +316 7 +3777 2 +304 6 +3448 1 +3484 3 +414 2 +2171 3 +2190 5 +1234 6 +85 5 +4036 8 +2928 8 +832 9 +800 10 +799 9 +598 9 +3154 3 +3829 10 +2183 9 +303 6 +2100 3 +3751 2 +1404 2 +2872 3 +3529 10 +3178 3 +3184 5 +2229 4 +2452 1 +4064 3 +2624 4 +1858 5 +4038 9 +2116 3 +3140 5 +1762 2 +1278 7 +3472 5 +3779 9 +3487 8 +1745 1 +904 3 +1487 9 +1532 8 +1159 2 +2898 1 +1408 10 +2516 10 +2320 1 +3764 3 +2506 7 +1887 2 +1457 6 +2111 3 +1434 8 +328 9 +302 7 +3819 6 +1137 3 +2846 9 +1432 1 +3129 8 +2929 5 +1912 5 +1461 10 +3630 5 +620 3 +3217 5 +3176 10 +2691 5 +923 9 +130 6 +3075 8 +3104 2 +634 9 +1953 5 +840 10 +788 9 +2142 7 +788 10 +3641 10 +2398 10 +106 2 +2817 9 +2196 2 +1266 10 +4091 1 +2069 1 +751 6 +3077 5 +2497 6 +1919 8 +2524 6 +547 10 +3896 2 +3216 6 +2263 1 +74 8 +3736 4 +2958 7 +221 9 +2353 1 +3987 7 +3894 2 +3556 3 +1661 3 +1270 4 +3749 6 +3599 1 +2712 6 +1776 8 +1370 1 +1757 9 +3157 4 +2404 10 +779 4 +3029 2 +3154 8 +1503 2 +1166 8 +1657 9 +1727 9 +2278 2 +575 7 +3046 5 +2276 1 +763 3 +3781 5 +1355 6 +2091 4 +3323 9 +904 9 +2388 8 +261 6 +1099 2 +827 10 +1204 4 +728 5 +717 5 +1425 1 +1017 5 +3516 9 +1395 3 +1883 1 +3193 8 +1838 1 +1226 10 +1646 6 +2328 1 +2603 6 +32 5 +2660 6 +3992 7 +977 5 +3369 2 +211 1 +1526 5 +3302 10 +3332 3 +1422 3 +3467 5 +252 5 +4001 10 +3832 3 +647 5 +1311 8 +2676 7 +777 3 +1459 8 +3346 1 +3498 3 +4042 10 +2097 1 +928 8 +1523 6 +1179 8 +229 3 +111 3 +3898 5 +1932 9 +1413 1 +2283 7 +3192 3 +3533 7 +3581 1 +3549 4 +425 7 +2740 2 +2600 2 +4006 3 +1513 8 +4017 5 +3449 6 +3751 5 +3518 3 +771 2 +2254 5 +3596 4 +1826 9 +1265 4 +658 4 +1015 2 +3840 2 +186 3 +1904 4 +988 6 +2508 4 +3309 9 +1553 6 +1894 7 +4064 10 +2256 1 +1399 6 +3120 9 +3891 3 +2364 1 +3351 2 +3364 9 +3724 8 +3279 7 +809 10 +3446 1 +1057 3 +3114 9 +3952 5 +2817 3 +312 3 +437 10 +1690 10 +2620 2 +2785 7 +3914 2 +654 8 +2473 5 +570 10 +1857 8 +2927 3 +3633 8 +2586 10 +1979 9 +3221 10 +185 8 +3094 3 +10 3 +335 7 +3610 7 +3820 9 +3210 9 +788 9 +224 4 +2623 5 +2714 6 +1288 6 +597 7 +1995 9 +1699 7 +2072 6 +3344 6 +2649 5 +1779 6 +324 1 +1018 1 +2155 7 +869 7 +1636 2 +3612 5 +2360 5 +1043 10 +2716 10 +1962 7 +1923 8 +2994 10 +1160 3 +138 10 +1379 4 +942 1 +2718 5 +3565 5 +1245 5 +641 6 +1953 2 +1186 4 +126 4 +3651 1 +741 2 +4026 7 +1044 1 +3329 6 +335 3 +757 9 +1959 1 +970 10 +1374 6 +1372 3 +2080 6 +3134 5 +2353 9 +3 9 +2327 3 +3715 9 +2304 7 +3320 2 +3035 2 +954 6 +3934 10 +2073 2 +2233 2 +799 10 +1736 1 +3663 9 +985 4 +233 5 +3515 2 +993 6 +2173 6 +3041 6 +2718 7 +3604 5 +1238 3 +2604 4 +3032 8 +3675 8 +905 7 +3644 2 +1388 7 +3322 1 +3798 1 +3338 4 +1194 7 +2614 3 +1600 8 +2937 8 +1452 10 +893 4 +4077 9 +2633 10 +3024 2 +45 4 +2351 1 +44 7 +248 10 +2566 1 +2282 8 +2721 6 +489 9 +2994 10 +3121 7 +3316 1 +2512 2 +2221 7 +510 1 +3000 3 +2551 5 +3512 4 +3770 5 +472 6 +1555 1 +1540 8 +474 2 +3574 1 +3385 9 +1272 3 +3225 3 +1225 8 +748 4 +1122 1 +376 4 +1160 3 +1260 2 +2478 6 +3236 4 +1873 9 +2811 2 +2034 1 +2712 3 +3957 7 +1364 4 +1303 1 +3264 5 +224 10 +714 7 +2487 8 +2272 6 +1067 9 +1252 3 +242 4 +3523 5 +3954 5 +2360 7 +1939 8 +3576 5 +1035 2 +509 3 +1477 6 +3307 8 +3731 6 +2372 7 +736 5 +1469 1 +3459 1 +3949 7 +2502 5 +2273 7 +1007 8 +2756 7 +1486 1 +2849 4 +976 1 +2354 3 +348 5 +3211 4 +3659 9 +3949 2 +1305 10 +779 9 +1559 4 +1827 8 +3133 6 +534 2 +2501 5 +1378 6 +2656 10 +4060 10 +758 9 +2607 8 +535 8 +3398 6 +1572 6 +4092 2 +2856 2 +317 10 +1333 3 +2024 4 +2912 7 +1334 10 +2471 3 +1186 7 +1027 2 +1139 1 +3857 1 +118 6 +15 9 +309 5 +2691 10 +1855 7 +3243 9 +3972 5 +170 5 +783 6 +1648 10 +2250 1 +3008 10 +452 10 +119 2 +2175 8 +2432 2 +3369 9 +340 5 +1207 2 +521 3 +3438 10 +2126 8 +3333 3 +3293 7 +610 3 +1504 9 +3487 5 +3962 8 +834 7 +3231 1 +3834 5 +2801 7 +2515 3 +3627 4 +2839 4 +1796 10 +657 7 +9 7 +1298 1 +2113 1 +2261 4 +1215 4 +570 2 +2509 3 +499 8 +1675 2 +1159 8 +1633 6 +2181 5 +180 5 +496 3 +3674 9 +1866 10 +2576 4 +2640 10 +2986 7 +741 7 +34 2 +4050 10 +624 7 +2524 2 +3795 9 +1544 8 +3232 1 +2544 7 +3116 8 +1180 9 +3784 9 +2335 1 +2941 7 +2329 8 +637 5 +1408 5 +974 6 +747 10 +2873 9 +2754 10 +1682 2 +1962 3 +3132 7 +3578 5 +566 6 +1152 6 +2729 4 +3160 9 +1700 4 +1789 5 +2309 4 +1773 4 +371 2 +3821 6 +3587 7 +2523 3 +993 9 +2604 5 +3284 7 +3117 2 +3249 6 +1839 5 +1228 6 +1835 8 +3598 2 +1284 7 +3343 1 +659 6 +2633 4 +1227 8 +2996 9 +1224 3 +634 7 +3985 4 +262 1 +2655 9 +581 4 +3039 10 +2723 1 +1957 1 +2528 2 +244 5 +137 3 +4075 3 +3436 2 +4087 7 +3641 10 +2620 2 +3511 3 +464 5 +1857 4 +749 4 +2694 7 +3515 2 +3285 4 +2205 5 +1417 8 +1834 10 +3335 9 +2735 2 +2596 5 +4057 6 +3832 2 +3595 10 +126 8 +2982 1 +2578 1 +1442 6 +3415 5 +2849 8 +2145 9 +3870 3 +3082 1 +3210 10 +3737 1 +1449 7 +1304 3 +2853 7 +329 1 +1904 3 +3690 2 +3711 2 +2568 9 +846 4 +1446 2 +106 3 +3568 9 +1030 5 +2394 10 +773 1 +3241 8 +73 8 +2778 6 +119 2 +2873 4 +158 8 +2655 4 +2269 10 +573 1 +3776 8 +435 6 +1733 8 +2862 7 +3845 2 +3189 8 +3969 1 +3108 1 +1215 2 +511 2 +2863 5 +3713 2 +3127 4 +3081 6 +1419 10 +120 10 +2843 6 +3079 7 +382 7 +2755 8 +2196 9 +363 5 +3175 7 +3447 9 +4021 1 +2999 3 +2210 4 +245 8 +3486 6 +196 6 +4055 7 +4083 5 +727 7 +623 6 +1936 1 +590 3 +690 10 +1327 1 +2046 8 +521 9 +3709 8 +1357 8 +3306 4 +2909 9 +808 9 +2466 10 +2968 7 +792 3 +1565 10 +1199 3 +977 7 +2759 7 +2836 5 +1631 9 +844 7 +1675 9 +1770 6 +1131 5 +3687 1 +2869 7 +3020 9 +2215 10 +3912 10 +3568 5 +472 3 +3801 2 +2739 1 +179 5 +127 4 +1912 5 +198 3 +2111 5 +1162 7 +425 9 +731 1 +1410 10 +3101 9 +1103 5 +1485 7 +1555 8 +2825 9 +3312 8 +1881 1 +3349 1 +3721 2 +1049 5 +2363 8 +3727 2 +2794 10 +2658 5 +3487 1 +2979 10 +2119 10 +1466 3 +3963 2 +3181 1 +1866 8 +1646 3 +2777 2 +2483 8 +3825 9 +633 3 +3489 8 +2970 7 +1956 4 +3246 3 +298 5 +79 3 +2958 10 +1600 6 +3610 7 +1230 3 +2683 6 +2687 5 +4054 2 +699 7 +3400 10 +1956 4 +1907 4 +3961 3 +3709 4 +3893 8 +2588 8 +632 7 +3859 6 +1001 3 +1108 10 +3667 8 +1009 3 +3586 9 +3187 10 +1790 8 +2542 3 +352 6 +2829 2 +758 9 +3788 8 +1950 8 +1995 2 +3562 4 +1812 3 +3072 4 +973 7 +98 6 +2162 10 +2251 7 +1984 8 +1871 8 +2085 10 +3638 3 +2192 3 +718 2 +3932 2 +2416 7 +121 9 +1394 3 +1053 4 +3505 5 +1671 9 +3121 8 +1205 3 +2068 1 +628 6 +704 10 +515 6 +798 9 +3251 1 +374 8 +2594 8 +3858 4 +2619 5 +2191 7 +1986 10 +322 6 +2839 10 +2546 6 +1236 9 +1752 8 +3056 5 +373 9 +2983 8 +2264 6 +2325 8 +2959 3 +3631 7 +1979 3 +3088 5 +3082 2 +2863 2 +2681 8 +3473 7 +816 8 +85 10 +955 7 +591 9 +3790 6 +1168 3 +2321 9 +1923 2 +2731 3 +2146 8 +2847 1 +2206 9 +1113 2 +3631 7 +2177 7 +2281 3 +2262 5 +3129 2 +2149 4 +524 7 +2552 7 +290 1 +37 7 +1938 10 +1799 9 +4080 5 +783 5 +282 8 +68 9 +2637 2 +2539 9 +213 1 +475 2 +208 7 +421 9 +1530 6 +2418 5 +3953 6 +3985 1 +3000 10 +77 5 +149 3 +2218 4 +1826 1 +2212 2 +461 8 +4087 7 +2039 5 +1590 3 +577 8 +1191 5 +2466 4 +3361 5 +527 10 +3358 1 +2079 4 +2798 5 +3990 2 +2835 6 +2139 10 +2979 7 +2117 8 +3185 3 +642 6 +188 4 +654 2 +2128 1 +3288 4 +3134 10 +51 6 +3496 9 +2883 10 +1077 7 +3069 6 +1204 10 +1396 2 +2541 1 +2317 7 +4090 7 +3539 5 +3235 4 +1110 3 +1790 6 +1968 10 +1076 7 +2311 2 +3495 9 +835 1 +585 5 +2294 5 +2840 3 +1028 4 +652 7 +1619 6 +3608 10 +281 2 +637 4 +1123 8 +1155 6 +2604 6 +2203 3 +2420 7 +3215 7 +399 1 +1 9 +1436 6 +691 8 +550 6 +2629 1 +539 7 +1001 7 +3453 6 +2965 4 +2098 5 +1789 5 +3621 6 +3958 4 +1681 3 +759 2 +1172 3 +1126 7 +3477 3 +370 10 +1318 9 +98 6 +2313 2 +1291 6 +993 4 +3593 3 +128 6 +778 10 +1473 7 +615 2 +260 3 +3651 1 +3334 8 +4042 5 +657 9 +3542 7 +2233 7 +1956 4 +2133 8 +2782 4 +3889 5 +99 1 +2578 3 +451 10 +2484 9 +1947 4 +2212 2 +2284 6 +1371 2 +3921 5 +2002 3 +114 5 +4084 1 +346 10 +4070 2 +2330 10 +2200 10 +94 4 +3099 4 +1497 7 +1740 9 +80 3 +839 6 +2305 7 +928 7 +1369 3 +2532 8 +995 9 +1568 1 +1773 3 +378 4 +2271 5 +761 9 +519 7 +3151 2 +268 4 +3857 4 +71 5 +2831 10 +2903 3 +3173 4 +3630 6 +2258 5 +1272 7 +475 1 +407 2 +1433 2 +2624 8 +1492 10 +4013 6 +2006 5 +44 9 +3647 9 +3104 1 +3251 9 +4090 1 +4053 9 +2748 6 +553 4 +2964 8 +3234 4 +2097 4 +2762 10 +3947 7 +2941 3 +3343 9 +1872 1 +3647 2 +139 7 +175 4 +1573 1 +2708 3 +2525 4 +727 4 +1281 9 +2165 6 +3119 6 +131 5 +2162 7 +2469 3 +1384 6 +1382 6 +3262 10 +2898 2 +1168 10 +320 7 +1772 4 +473 3 +3529 8 +2740 2 +3866 10 +1730 9 +1447 8 +2700 1 +1340 1 +1161 4 +1811 4 +3582 5 +98 6 +3185 1 +1405 9 +3288 4 +1797 9 +360 7 +3764 6 +1722 4 +3924 4 +2621 9 +1187 6 +1487 10 +2761 9 +541 8 +2024 6 +192 9 +3758 6 +3311 9 +2768 8 +3336 7 +386 10 +1103 5 +2229 1 +519 2 +1819 4 +2215 8 +2053 1 +1345 4 +3518 1 +1189 7 +3789 8 +1794 9 +1995 3 +2693 9 +838 10 +1363 3 +773 9 +2361 8 +1417 3 +54 1 +2915 1 +3216 8 +3374 7 +1153 7 +564 9 +3772 6 +3009 4 +920 7 +677 10 +979 3 +2910 3 +1048 2 +3011 1 +2728 9 +2689 5 +1947 9 +3480 3 +875 6 +2501 6 +403 1 +622 6 +1937 7 +1144 1 +1928 2 +3868 5 +860 1 +2372 10 +2503 8 +1345 10 +3113 10 +3953 7 +1961 4 +812 5 +3080 1 +2311 7 +3193 7 +904 7 +3556 6 +2952 4 +739 8 +217 3 +2240 4 +489 6 +646 7 +2897 2 +4053 4 +973 3 +1981 7 +1990 4 +566 1 +3001 2 +3480 7 +2082 1 +2792 4 +3419 5 +3024 8 +1277 3 +1510 9 +2498 1 +3858 4 +1157 1 +1254 2 +161 4 +438 5 +3650 4 +3831 5 +4020 3 +1006 6 +2614 3 +1326 6 +1373 1 +3721 3 +1020 1 +3233 9 +1749 10 +3807 5 +84 4 +568 4 +491 1 +841 4 +1034 6 +51 4 +3602 10 +629 9 +3973 8 +1868 9 +1446 6 +2989 9 +744 10 +1532 2 +2925 10 +825 6 +386 3 +2393 4 +4035 6 +768 9 +2040 6 +2832 10 +2975 7 +568 8 +19 4 +3984 4 +34 7 +3284 8 +3156 3 +1019 9 +2933 10 +49 4 +4077 2 +1355 3 +2545 2 +1996 10 +2248 3 +1017 5 +4089 5 +783 1 +1172 3 +40 5 +123 1 +2792 1 +2268 9 +2753 3 +313 2 +948 4 +2304 8 +879 9 +1166 6 +841 6 +3261 10 +2327 2 +3126 7 +2692 10 +3446 6 +1215 4 +3609 8 +3941 5 +1542 1 +955 9 +2203 10 +3357 6 +1738 5 +1091 1 +3621 6 +3578 2 +4064 1 +3219 5 +1585 7 +1567 6 +1242 10 +1678 3 +2076 9 +3229 6 +2482 1 +2001 5 +1968 2 +4086 8 +1474 8 +1595 7 +3949 8 +389 7 +518 7 +3353 5 +1771 5 +176 4 +3143 7 +1062 1 +3723 6 +2526 9 +6 3 +916 3 +945 7 +2457 6 +1225 7 +1501 5 +312 2 +2929 8 +669 7 +1425 6 +2928 5 +3538 6 +1444 9 +3465 8 +3437 2 +167 1 +3190 5 +2577 8 +306 8 +4033 2 +2328 5 +779 5 +1500 7 +2871 2 +1743 4 +2576 9 +1528 9 +1617 3 +2812 3 +2018 9 +3726 10 +1503 8 +3606 9 +3525 6 +484 6 +983 6 +1851 5 +2362 9 +2500 8 +2253 10 +1238 2 +859 8 +3411 2 +2654 10 +2875 10 +3981 6 +296 3 +3343 10 +2490 7 +596 5 +1242 4 +917 3 +685 9 +3037 8 +4062 8 +3358 4 +2020 4 +3051 1 +706 6 +3352 6 +3930 2 +2514 4 +2324 2 +1957 4 +1550 9 +3652 3 +766 6 +3272 9 +2208 8 +2373 7 +1449 1 +4076 3 +3757 6 +2161 2 +1279 7 +2691 5 +3233 8 +238 2 +73 7 +3186 7 +2862 5 +2711 3 +824 2 +4048 8 +3774 6 +3607 8 +1511 8 +4085 7 +1144 6 +2260 4 +35 9 +3432 7 +991 5 +1808 9 +2489 2 +809 5 +3806 8 +1757 7 +834 1 +990 9 +1455 9 +470 10 +563 10 +2445 5 +984 1 +2935 6 +746 4 +1113 5 +3351 5 +1597 7 +231 1 +3145 9 +2295 4 +2004 6 +2916 10 +3419 2 +438 1 +3711 6 +1064 5 +2075 4 +523 5 +261 4 +2574 1 +2443 7 +2812 2 +151 7 +3046 3 +3699 5 +1677 8 +1185 7 +683 6 +3300 10 +2144 7 +2628 8 +491 7 +4084 4 +2199 1 +1684 7 +336 1 +650 3 +4048 10 +64 2 +1623 7 +2228 7 +3790 5 +1977 2 +119 9 +2063 9 +1127 5 +2145 8 +1158 4 +1100 5 +3564 7 +865 2 +580 1 +3794 10 +1621 6 +599 9 +3026 8 +3182 1 +943 4 +3462 4 +3390 1 +1672 1 +454 3 +1599 1 +3866 1 +1925 10 +3973 3 +894 5 +2404 5 +3911 2 +1974 4 +2769 2 +295 1 +2131 4 +297 6 +37 3 +1655 10 +1706 8 +1380 9 +69 9 +1261 1 +452 5 +285 7 +2702 4 +2808 6 +2288 4 +168 4 +2535 4 +1179 8 +31 6 +985 6 +427 5 +1793 1 +3950 2 +4050 6 +473 4 +3749 10 +858 2 +2783 6 +2865 5 +72 2 +317 2 +83 5 +2835 10 +2970 8 +2445 4 +1907 7 +3755 7 +3220 5 +1212 9 +1866 8 +2923 7 +3425 2 +2185 9 +2268 10 +1101 1 +2508 4 +2412 6 +2231 1 +1086 10 +721 8 +536 5 +3132 9 +1583 9 +2922 4 +1733 2 +2003 8 +2151 6 +3964 4 +2653 1 +3929 6 +3772 2 +3549 8 +1585 7 +2414 9 +1398 9 +835 10 +2111 1 +1921 6 +1625 10 +4035 9 +2153 5 +2544 8 +1419 7 +837 1 +3674 10 +374 2 +783 2 +3037 1 +2860 7 +3361 9 +2160 6 +3610 5 +3669 1 +1462 9 +2179 2 +3097 8 +2400 8 +1703 2 +2742 9 +1445 10 +3308 2 +2933 3 +3671 6 +2688 1 +591 7 +2597 7 +2615 1 +341 1 +3323 10 +3673 9 +643 3 +1500 10 +2765 9 +53 3 +973 2 +2733 7 +4044 8 +3912 4 +910 5 +2219 4 +13 4 +59 3 +3989 8 +1989 6 +2264 1 +1981 4 +3312 7 +593 10 +481 2 +3357 1 +3309 4 +75 7 +3573 3 +3416 1 +922 4 +1912 9 +305 6 +1347 2 +240 10 +1340 8 +271 3 +1489 9 +4017 9 +2196 10 +489 9 +2553 9 +3552 3 +2211 4 +1707 2 +2026 6 +150 1 +2019 1 +3302 6 +1103 3 +2928 8 +1932 8 +2849 9 +3964 3 +3316 2 +827 3 +2539 6 +3906 8 +3010 2 +2978 7 +2238 10 +3688 1 +2970 4 +10 5 +3763 1 +3845 8 +1236 8 +3027 1 +1103 3 +2121 3 +1697 1 +3316 1 +3389 6 +3338 5 +3791 5 +3895 6 +1110 1 +3670 1 +53 9 +3283 1 +487 10 +1793 10 +1809 8 +1611 2 +201 8 +1001 1 +356 1 +2754 3 +771 5 +3793 10 +72 5 +2873 9 +4020 5 +2492 5 +2004 8 +760 10 +3015 9 +3595 2 +1 9 +3636 8 +369 4 +1022 5 +2738 1 +1189 3 +1904 7 +2150 3 +518 1 +2067 6 +1944 6 +1358 4 +2897 4 +3545 2 +220 8 +1115 1 +1379 3 +1382 5 +3269 6 +3510 8 +379 8 +857 9 +3631 2 +1696 3 +2309 9 +1116 4 +3279 5 +2990 8 +3186 6 +2864 5 +4065 9 +2127 1 +1925 3 +1841 3 +686 9 +1404 1 +2371 1 +3340 4 +2080 10 +237 5 +442 4 +171 8 +1959 3 +2504 1 +474 8 +1761 7 +3057 3 +2051 3 +1657 7 +2597 3 +3463 5 +2334 2 +2562 4 +2527 4 +389 3 +1929 4 +2744 7 +2109 9 +1918 9 +3515 4 +2994 6 +17 9 +2022 7 +2678 8 +666 2 +2000 1 +4083 10 +1281 5 +2689 7 +1294 7 +941 7 +727 5 +697 2 +1586 5 +445 9 +3879 4 +727 7 +939 7 +3630 10 +3746 4 +2241 10 +2441 4 +1151 2 +3696 9 +2023 2 +3502 7 +2415 4 +3238 8 +2079 10 +2813 7 +2555 8 +2569 6 +3950 3 +3784 3 +3371 10 +3265 3 +702 3 +605 4 +1510 3 +59 5 +2396 2 +3647 6 +3203 4 +2946 9 +308 9 +2141 6 +512 3 +2231 3 +556 8 +378 3 +96 9 +3837 10 +3878 3 +1685 8 +3786 2 +2974 2 +1466 5 +1173 5 +432 10 +697 5 +1109 6 +3939 2 +2166 5 +1616 2 +1415 5 +1878 10 +126 8 +251 1 +2404 6 +3118 7 +4083 9 +453 10 +2851 4 +3353 1 +3906 9 +3452 2 +1691 2 +2531 9 +1595 5 +1039 10 +3183 9 +315 9 +3580 10 +181 6 +3034 1 +3822 10 +2217 7 +1096 1 +749 4 +2775 3 +3722 3 +4013 8 +1745 6 +3560 10 +3450 6 +2212 10 +3302 5 +262 6 +680 9 +169 10 +664 2 +367 2 +576 1 +430 2 +996 1 +525 6 +2879 9 +3893 10 +2596 2 +3926 9 +3063 10 +2092 1 +3535 2 +1753 1 +1747 4 +1647 3 +1658 9 +1391 9 +317 1 +1265 3 +2018 1 +1849 9 +2974 7 +3643 8 +1490 10 +2818 8 +1796 3 +1410 8 +3495 3 +1088 1 +1461 1 +3197 3 +3555 2 +1569 2 +508 7 +494 9 +1578 10 +1367 7 +2708 4 +378 7 +3221 2 +809 2 +2226 5 +629 2 +1460 3 +2908 6 +388 3 +340 3 +3437 3 +2596 2 +3018 1 +2073 8 +1027 5 +242 5 +1226 2 +547 10 +1672 10 +3843 7 +2941 2 +2178 4 +3964 2 +1038 1 +2925 2 +2741 9 +3659 9 +1679 9 +3098 9 +3096 4 +2846 4 +262 10 +2609 10 +763 9 +909 5 +41 6 +3771 6 +3756 1 +57 4 +2278 6 +204 4 +3135 4 +1058 3 +2430 7 +968 5 +276 8 +1055 3 +1567 8 +2034 7 +268 1 +3712 1 +3462 4 +2625 9 +95 5 +2386 1 +249 9 +3086 3 +470 5 +2357 7 +4042 9 +3577 10 +1269 3 +2582 2 +2707 3 +3259 5 +734 9 +2531 2 +2497 5 +3346 7 +1471 6 +3556 8 +3881 7 +1671 5 +3761 1 +2011 3 +2994 9 +223 2 +2469 9 +2715 2 +3925 3 +917 10 +3700 5 +30 3 +648 8 +2711 8 +3955 10 +3434 9 +1332 7 +2426 1 +3265 7 +1384 10 +2200 2 +1769 6 +1083 6 +3487 4 +193 2 +74 5 +3120 10 +941 3 +1060 1 +1519 5 +3053 6 +1646 1 +3081 8 +661 5 +2178 9 +3945 8 +3594 4 +1176 9 +1021 5 +3169 2 +1224 6 +930 2 +680 5 +2877 6 +1515 2 +2755 1 +2377 4 +1256 6 +2793 3 +2184 7 +2921 8 +108 4 +303 3 +1066 1 +409 3 +2237 7 +1752 2 +488 10 +2851 8 +3101 6 +2210 9 +1068 4 +3060 6 +2083 5 +1977 6 +3496 2 +3604 2 +3007 6 +220 5 +2910 3 +1332 9 +3795 5 +3497 1 +1609 2 +3805 7 +2249 3 +2971 2 +1280 1 +1194 8 +2004 8 +294 2 +665 9 +239 9 +1689 8 +771 2 +3960 2 +572 5 +65 7 +2085 7 +853 1 +3924 9 +3364 9 +3237 6 +944 8 +3086 5 +1720 1 +3034 6 +2514 6 +602 5 +4044 4 +3773 3 +142 7 +1902 1 +3840 6 +1561 3 +1389 5 +3355 2 +94 10 +2979 9 +3224 10 +2206 6 +1175 9 +1217 10 +1768 9 +3629 10 +1207 2 +1773 2 +2941 1 +1801 6 +2920 9 +3735 6 +2572 5 +946 7 +1615 2 +3680 9 +3007 9 +1459 1 +252 9 +737 8 +2263 3 +2456 6 +4026 5 +1026 5 +2208 8 +1939 8 +2444 5 +3747 9 +1262 10 +640 1 +534 5 +3660 3 +478 2 +1703 3 +431 8 +1659 10 +68 5 +190 2 +1733 7 +110 10 +3610 1 +2266 5 +905 5 +1865 6 +2530 5 +2071 5 +3889 2 +2860 5 +1433 3 +3908 6 +702 4 +1659 4 +67 10 +3952 5 +559 3 +3869 8 +1320 2 +3978 10 +366 7 +444 10 +1468 3 +3896 3 +2353 3 +211 8 +1387 5 +2750 6 +393 10 +2379 6 +402 7 +3495 3 +2281 7 +1455 4 +1900 1 +4067 3 +1552 1 +363 4 +44 1 +2135 5 +3643 4 +2082 4 +3434 10 +724 9 +3372 2 +795 3 +1808 3 +1346 4 +3392 9 +2935 4 +1442 7 +3227 1 +2113 3 +3294 10 +866 1 +3571 10 +2258 4 +4040 6 +2070 4 +722 4 +2599 7 +3078 4 +3663 10 +279 8 +2693 10 +177 10 +1750 3 +1413 1 +307 10 +120 7 +3970 8 +3789 2 +3036 8 +2813 10 +1443 9 +1426 1 +3281 10 +3566 1 +3280 5 +3835 1 +2545 4 +1627 4 +1230 10 +2529 1 +2831 2 +4071 7 +975 1 +2329 2 +1016 6 +1995 4 +1584 2 +3436 8 +540 2 +3267 9 +211 2 +657 9 +3683 4 +3075 5 +4041 5 +498 3 +3189 1 +1738 7 +1929 5 +776 7 +1280 1 +3997 4 +2958 2 +1564 10 +2375 4 +3536 6 +2832 5 +3732 9 +1368 5 +428 7 +2208 8 +3588 2 +278 5 +1875 5 +261 2 +3375 9 +3267 9 +1845 7 +780 9 +3185 5 +2191 2 +1078 2 +2833 9 +3954 7 +3592 4 +877 6 +486 10 +420 10 +1564 3 +3518 4 +3898 7 +3228 1 +972 7 +2566 4 +3063 3 +3849 2 +477 4 +112 9 +36 8 +3299 9 +1266 3 +552 1 +1731 10 +944 6 +1160 4 +2160 5 +1836 1 +3098 5 +1702 6 +2884 3 +1573 10 +1829 4 +2323 5 +1910 4 +982 1 +3032 2 +2733 2 +339 4 +411 1 +2426 10 +1185 8 +28 2 +334 1 +1027 4 +3008 4 +2466 6 +144 7 +3098 8 +3518 4 +541 2 +872 8 +2515 2 +2123 9 +793 2 +2938 1 +1735 10 +854 3 +542 8 +1155 4 +3691 4 +3799 10 +835 3 +1495 8 +2996 1 +965 4 +2538 7 +138 5 +2403 4 +3501 6 +2046 5 +908 7 +1509 6 +3389 6 +3451 6 +230 3 +3665 9 +374 6 +3430 3 +1955 7 +1965 1 +4067 9 +3337 10 +1903 4 +61 6 +3001 8 +3400 9 +1552 4 +2890 6 +2014 3 +3231 9 +732 2 +1638 5 +3526 5 +3355 6 +806 8 +3530 9 +2698 9 +993 6 +2242 4 +3945 8 +2827 7 +1787 3 +2816 2 +3444 10 +1199 9 +964 10 +3934 8 +2028 6 +2205 10 +928 3 +72 1 +1366 7 +2770 10 +3320 3 +3434 9 +268 10 +1259 6 +3804 4 +2391 5 +2655 9 +261 5 +2951 1 +3333 2 +2649 2 +1383 10 +3011 6 +3529 10 +262 9 +2760 3 +2393 3 +992 3 +744 7 +2178 3 +3969 8 +3762 1 +946 3 +3910 1 +1213 8 +230 7 +3888 5 +1082 5 +2835 3 +3770 7 +2887 6 +1892 1 +2151 3 +2481 9 +2803 10 +563 5 +1125 9 +728 2 +3036 5 +2200 3 +94 10 +2274 8 +15 1 +430 5 +1112 9 +285 4 +1846 6 +2473 5 +1890 4 +1992 2 +340 1 +97 10 +2422 6 +1589 6 +1530 4 +1777 5 +104 2 +3022 9 +51 2 +2948 1 +2136 9 +1652 8 +1034 8 +817 8 +3157 8 +2614 3 +3735 10 +2900 10 +4014 6 +311 5 +4075 1 +3524 9 +2788 3 +2604 5 +2365 7 +3145 9 +874 9 +3140 6 +3587 6 +454 8 +1569 10 +690 10 +487 1 +1516 2 +3034 1 +3883 5 +2120 3 +3346 4 +3525 5 +2542 7 +3544 10 +2820 6 +3519 8 +96 4 +3883 7 +3115 2 +2645 8 +735 10 +1023 7 +3211 1 +3155 9 +1157 8 +2861 6 +1951 6 +836 4 +705 7 +4090 1 +1653 9 +3096 9 +463 8 +2961 10 +771 1 +1297 6 +3135 4 +865 7 +3926 8 +2438 7 +0 5 +1622 2 +1711 7 +3380 9 +967 6 +1702 5 +3013 5 +3885 4 +3042 5 +3200 8 +627 2 +2182 6 +586 8 +2083 10 +3043 2 +1938 8 +2783 10 +1891 1 +2245 8 +4068 7 +1064 3 +1700 4 +1970 4 +1818 3 +3096 6 +969 7 +550 10 +53 4 +1766 1 +2308 9 +534 2 +3906 8 +1279 5 +3918 4 +432 6 +936 5 +240 2 +2454 5 +2711 4 +1968 5 +3954 1 +2262 9 +299 5 +3757 8 +455 2 +3607 5 +3765 8 +3919 10 +2766 2 +2870 8 +845 7 +3687 4 +1119 8 +3413 8 +3969 5 +3192 9 +2188 5 +1756 2 +2089 7 +2293 8 +2774 5 +2074 2 +533 2 +3081 2 +2759 9 +467 5 +1546 6 +3195 8 +48 2 +2498 6 +1850 4 +1870 2 +3295 6 +1997 5 +3000 9 +1168 9 +904 3 +263 3 +1497 8 +227 10 +3893 3 +2863 7 +1361 9 +2345 3 +1367 3 +3590 2 +1776 1 +379 1 +221 7 +3299 1 +573 3 +48 2 +2177 6 +1485 7 +1889 10 +1443 5 +313 3 +2093 9 +1254 4 +3912 1 +809 4 +940 10 +1804 8 +2271 3 +1416 4 +1500 5 +1392 2 +194 3 +2746 9 +2724 6 +2185 9 +66 5 +1306 4 +2646 5 +922 3 +123 9 +3413 5 +2813 9 +1778 5 +1907 8 +564 8 +2539 9 +869 2 +1251 4 +3291 8 +2513 7 +3115 9 +1125 2 +2143 5 +242 7 +83 5 +3453 8 +85 1 +2734 2 +512 6 +2486 9 +3014 1 +477 3 +2338 2 +3110 5 +1220 1 +581 8 +1492 9 +3588 10 +3617 8 +472 6 +60 7 +2922 4 +2516 5 +724 3 +215 3 +90 8 +2686 5 +3807 5 +3392 1 +2021 9 +19 6 +1037 9 +2861 4 +3148 2 +432 4 +1173 8 +3121 5 +2566 6 +1968 10 +2094 2 +604 4 +1384 1 +169 9 +302 7 +254 4 +2904 5 +145 2 +4 2 +995 4 +3739 1 +3665 5 +1737 9 +1416 6 +174 5 +871 4 +667 1 +4011 5 +896 2 +2247 8 +2252 3 +2656 2 +2104 1 +169 8 +327 2 +1791 10 +1561 8 +3759 4 +743 9 +1125 10 +3357 9 +3114 9 +2583 7 +725 10 +1940 7 +3874 8 +1521 2 +1673 9 +753 4 +3418 5 +2984 2 +1502 7 +3818 3 +2957 5 +1209 1 +2764 9 +3916 4 +268 9 +1777 2 +1827 4 +3680 9 +3945 7 +533 5 +2775 8 +2880 9 +2636 8 +2401 3 +2517 2 +3195 9 +2959 8 +355 8 +703 5 +2513 8 +1113 6 +881 3 +505 3 +3941 8 +1304 10 +2610 2 +3170 7 +112 6 +1002 7 +1582 7 +853 8 +135 9 +2418 9 +149 4 +3195 1 +3857 2 +701 10 +3513 4 +3004 6 +3643 4 +3163 5 +1100 2 +810 10 +3498 10 +1793 8 +3248 4 +3043 2 +637 9 +1930 8 +1924 9 +141 1 +880 8 +1345 8 +604 4 +2442 8 +879 6 +2970 8 +3477 4 +269 6 +719 3 +2915 2 +1144 10 +3399 7 +3813 9 +915 3 +2708 9 +1565 1 +3066 7 +2478 4 +3048 7 +1340 4 +2150 2 +1241 6 +1247 2 +3721 2 +2853 8 +613 10 +642 3 +2411 9 +1623 6 +1522 9 +3000 5 +235 2 +98 6 +538 8 +1609 10 +2392 8 +1724 10 +178 9 +1825 10 +787 6 +542 5 +3492 6 +1480 6 +1532 8 +1512 1 +2820 6 +3357 6 +105 7 +2710 5 +3553 4 +925 9 +2745 3 +3180 5 +750 2 +3860 5 +3783 2 +1058 8 +3367 2 +1284 1 +1993 7 +4040 9 +3683 6 +116 5 +1362 1 +2484 6 +199 3 +1447 10 +1710 5 +2240 1 +470 5 +2704 1 +3296 1 +297 2 +1007 2 +1796 3 +842 3 +1976 10 +3880 9 +2491 8 +1334 10 +2149 1 +1534 6 +2323 9 +1435 2 +1619 1 +3436 5 +2073 5 +2741 7 +108 3 +1309 7 +38 3 +3474 10 +495 1 +1232 6 +2524 2 +648 7 +3154 8 +1669 10 +1009 4 +999 10 +2451 10 +2534 2 +216 7 +2487 8 +3495 6 +2558 6 +3902 7 +2454 3 +2625 2 +2715 3 +3779 9 +2179 8 +3318 4 +1567 9 +508 8 +1481 9 +3080 6 +2339 7 +836 5 +22 8 +3879 7 +3326 9 +2984 2 +2428 1 +151 1 +1614 2 +1930 9 +2412 3 +1842 4 +3349 1 +1232 2 +3240 8 +4036 10 +2171 8 +3873 10 +212 9 +2231 10 +468 2 +2121 10 +2691 1 +3477 6 +3542 8 +634 8 +3735 9 +198 9 +2641 1 +128 4 +2774 1 +263 3 +3531 5 +782 4 +2886 3 +1207 4 +2718 3 +394 3 +2200 7 +857 3 +2340 9 +3493 1 +1822 1 +2077 7 +295 4 +2825 6 +505 7 +3461 7 +670 9 +1836 2 +573 10 +182 5 +391 3 +982 2 +2516 2 +2574 5 +1203 4 +3513 6 +3486 3 +2267 4 +3695 9 +2363 1 +2244 8 +3503 7 +3423 3 +3999 3 +2658 7 +3913 6 +2541 3 +3290 5 +1114 6 +3576 4 +3647 4 +1646 3 +2216 2 +2457 9 +3703 5 +2746 5 +3376 3 +659 7 +2114 10 +1343 9 +2086 4 +3319 3 +2971 6 +4005 4 +1375 6 +1170 6 +3319 2 +3937 4 +2050 4 +662 2 +854 2 +3402 4 +451 10 +3349 3 +2126 3 +143 10 +2287 2 +2887 3 +593 1 +1032 1 +1656 2 +594 7 +1989 1 +1128 10 +3319 7 +1998 5 +3071 7 +2069 10 +1554 3 +1792 4 +115 7 +2918 9 +2782 4 +3855 8 +345 7 +2797 2 +2905 4 +3841 5 +3733 2 +255 6 +3498 4 +1095 3 +3065 5 +3957 2 +2924 3 +823 4 +650 10 +2729 2 +3253 3 +1513 9 +2839 6 +1538 6 +3243 7 +1154 3 +801 10 +2688 10 +762 4 +600 7 +2105 7 +2626 6 +128 1 +1377 1 +2296 9 +2118 10 +3178 7 +3396 7 +3852 4 +666 5 +1785 7 +1105 3 +3982 7 +1368 10 +631 8 +1472 5 +1935 9 +754 1 +2291 6 +2324 9 +804 4 +3661 7 +3148 9 +1855 10 +1930 6 +3434 2 +3554 6 +3591 10 +2791 6 +2845 2 +2105 3 +2015 5 +3662 1 +219 4 +116 6 +852 3 +957 7 +2338 7 +3987 5 +2602 6 +3737 4 +3056 4 +2303 5 +3697 10 +2528 6 +2937 3 +3162 9 +1836 3 +3827 8 +1876 8 +3800 7 +1712 5 +1305 5 +3222 1 +209 8 +1320 6 +981 3 +3637 5 +1975 9 +647 1 +792 7 +1507 2 +3234 2 +1938 10 +1483 4 +3101 1 +3970 4 +1582 7 +3444 1 +2949 3 +1013 7 +1190 5 +1148 1 +1817 1 +3502 3 +323 10 +3436 8 +1119 1 +3362 2 +2291 7 +1896 8 +2170 10 +1342 6 +454 6 +2343 9 +963 9 +1075 5 +1703 2 +478 4 +4009 10 +593 5 +2653 6 +2372 7 +3176 7 +1526 3 +4082 3 +2465 6 +748 10 +880 7 +3472 7 +1581 7 +2809 10 +1236 1 +3494 3 +4079 4 +3407 2 +3818 2 +2293 5 +3369 3 +2813 2 +1801 6 +59 10 +198 1 +3992 9 +2334 6 +236 1 +244 6 +3316 5 +2990 6 +3544 9 +479 3 +833 6 +2926 6 +245 5 +2019 4 +2979 7 +2851 5 +1305 10 +53 6 +2415 9 +1931 5 +3764 2 +2032 1 +2663 2 +1748 8 +947 6 +2500 2 +2854 8 +418 4 +3297 3 +513 5 +2257 10 +4082 1 +1 8 +1076 7 +2937 7 +1751 8 +3295 1 +3346 4 +1350 4 +495 10 +2518 9 +398 9 +3429 3 +3256 4 +3573 7 +305 1 +3082 7 +1754 9 +1465 5 +2276 2 +3530 5 +2678 8 +1407 5 +2504 9 +1186 6 +3854 2 +2879 3 +1378 10 +871 1 +2331 8 +3056 3 +2363 9 +1795 5 +189 2 +3143 5 +2159 4 +2537 8 +2757 6 +348 5 +2527 9 +1724 1 +3451 8 +2327 7 +584 6 +342 9 +2580 6 +2925 4 +641 6 +4050 10 +1828 1 +3155 8 +181 8 +178 10 +1668 1 +3853 1 +2350 3 +65 4 +1608 3 +2429 8 +118 10 +1882 3 +3825 1 +855 1 +2590 2 +1762 6 +893 3 +2457 3 +1224 10 +3890 10 +114 1 +1276 5 +2060 8 +3195 4 +3085 1 +2277 7 +861 10 +1500 7 +2524 7 +1289 10 +3868 6 +1205 4 +1915 2 +2565 9 +2526 6 +288 8 +2945 3 +1622 5 +1458 5 +2813 3 +3097 4 +2671 9 +2965 6 +2969 5 +3544 4 +786 4 +2405 5 +1560 1 +1605 2 +1240 7 +3215 10 +237 5 +3595 10 +3233 5 +443 8 +2368 6 +345 8 +2747 6 +1713 3 +680 9 +815 8 +2224 9 +2214 2 +623 10 +2742 6 +1951 5 +2759 7 +130 9 +2820 4 +2879 5 +1896 8 +1725 3 +4080 8 +362 2 +2954 1 +1689 3 +2461 4 +3068 8 +156 7 +237 1 +2958 7 +2694 2 +1914 6 +2391 3 +3577 6 +2343 8 +1681 4 +2299 3 +2720 2 +2622 6 +3710 2 +2106 1 +3216 10 +3716 3 +524 1 +123 6 +328 8 +3297 10 +527 9 +2020 7 +2610 10 +3599 8 +2014 3 +1796 3 +947 9 +1644 8 +3298 1 +203 10 +1728 1 +1879 9 +2273 10 +2632 6 +2498 1 +3808 2 +3092 2 +2795 2 +460 9 +3496 8 +568 10 +2417 7 +230 3 +741 4 +2318 5 +2703 7 +1276 6 +1134 2 +2665 4 +3746 2 +1546 9 +1687 4 +2365 2 +2681 1 +3724 7 +483 5 +3656 3 +3289 8 +1582 4 +478 7 +60 7 +3636 9 +2142 3 +2531 8 +3973 5 +2122 5 +272 5 +1378 5 +634 9 +1973 5 +2293 8 +173 10 +3989 1 +3287 6 +984 6 +686 10 +664 3 +3921 9 +2940 9 +216 1 +902 1 +348 8 +1656 4 +709 2 +1518 8 +1756 1 +3267 6 +1794 7 +3961 7 +1596 5 +1725 9 +2792 5 +10 1 +2822 7 +3586 2 +3986 7 +3343 5 +2071 8 +2378 9 +2608 7 +2873 7 +589 5 +2954 2 +2562 5 +137 8 +619 1 +2262 10 +406 10 +2433 4 +3242 7 +3350 5 +1676 2 +2181 3 +2854 5 +1424 8 +1790 6 +1862 4 +56 1 +1118 9 +417 1 +2873 3 +3482 7 +1108 7 +3103 8 +2080 4 +3055 1 +864 3 +3334 6 +2351 5 +1335 9 +2175 5 +1751 1 +864 10 +1238 10 +3039 6 +3767 5 +1334 9 +3747 5 +271 1 +3364 3 +3302 8 +2454 5 +3737 1 +3664 2 +1568 2 +3853 6 +3464 1 +3464 2 +781 8 +1655 9 +293 5 +2728 6 +2496 3 +3812 2 +158 3 +200 5 +1915 7 +3365 8 +1803 10 +2644 9 +585 5 +19 6 +1802 5 +3980 8 +3278 2 +2766 1 +3032 7 +281 10 +1232 4 +965 1 +1054 8 +312 7 +2148 10 +2197 2 +3863 1 +4036 4 +1551 3 +2651 4 +1281 6 +4052 8 +2956 2 +156 7 +3504 4 +2777 3 +1258 9 +2271 8 +2162 7 +3594 2 +1735 8 +4085 7 +2516 7 +1228 8 +3534 6 +1860 9 +2620 9 +3304 2 +2466 8 +976 10 +969 4 +131 7 +1138 4 +2071 3 +3482 4 +567 3 +1497 5 +1373 10 +3594 7 +2551 9 +1982 7 +674 2 +1054 2 +1821 2 +1390 8 +2456 4 +3786 5 +2738 6 +3436 10 +2349 5 +382 5 +3676 6 +3791 4 +3447 5 +4019 7 +3866 10 +350 10 +3081 7 +3204 10 +3545 9 +332 7 +379 6 +1295 4 +1439 8 +1693 3 +3008 2 +1867 5 +2420 1 +470 8 +1832 3 +619 4 +1928 4 +3900 7 +1544 10 +1451 3 +3721 7 +1719 3 +112 8 +601 1 +3971 7 +2247 8 +1774 9 +2851 7 +3945 6 +3478 2 +2522 7 +3630 9 +303 4 +2171 1 +2024 2 +807 6 +474 4 +990 3 +85 10 +3668 4 +3823 9 +2731 9 +2748 7 +2283 10 +903 8 +1807 10 +1521 10 +3026 6 +2902 10 +219 10 +461 4 +166 8 +1065 4 +2325 3 +2922 3 +2572 7 +3034 4 +3694 10 +3552 7 +3554 4 +3189 10 +1805 2 +3953 9 +4033 7 +2154 6 +772 9 +7 1 +2616 10 +1200 9 +1237 1 +388 7 +2052 2 +2777 9 +3131 9 +97 1 +1592 2 +1940 1 +479 1 +2770 3 +970 3 +1553 7 +1531 3 +855 4 +2157 2 +3786 2 +3221 7 +2133 8 +1558 4 +2759 6 +2627 10 +603 1 +3477 5 +1714 2 +1945 5 +1936 10 +471 7 +363 9 +1169 7 +1871 5 +2078 3 +1201 3 +1098 7 +2291 4 +604 4 +3558 8 +472 8 +3770 3 +3595 5 +2432 6 +2848 2 +2941 2 +1473 2 +1149 5 +3522 8 +3365 9 +1269 10 +556 3 +2778 9 +955 3 +376 7 +160 1 +2626 2 +4069 7 +196 10 +805 1 +2185 5 +3577 8 +737 4 +230 2 +3555 4 +3601 3 +356 4 +952 2 +417 8 +838 3 +65 3 +3658 8 +3607 4 +3113 6 +984 1 +1346 10 +4080 7 +343 2 +838 6 +554 3 +2613 7 +2947 2 +3981 8 +2537 10 +2894 1 +3578 9 +3568 1 +2281 8 +3941 8 +1258 6 +1634 5 +3416 3 +2580 2 +4076 3 +3048 8 +1268 1 +236 4 +3117 9 +1713 1 +1325 5 +3635 1 +1436 8 +2985 10 +862 6 +2911 6 +1297 10 +2873 1 +2195 6 +1067 3 +2452 8 +2752 3 +198 9 +835 4 +311 1 +592 8 +3676 3 +1032 9 +1838 10 +1533 7 +2586 8 +2980 1 +2646 2 +4033 3 +4062 9 +2260 1 +964 6 +1067 5 +1824 5 +1485 9 +1171 10 +4033 3 +695 6 +2703 10 +4010 9 +3927 5 +2241 9 +1109 10 +3056 10 +3626 10 +61 9 +1710 10 +2030 7 +3077 3 +3519 7 +963 6 +2565 1 +1213 1 +1956 7 +3302 2 +2640 1 +734 4 +278 9 +1605 3 +3712 9 +79 10 +2378 4 +3653 1 +3507 6 +2289 1 +3629 6 +3080 8 +1135 5 +2556 9 +3448 3 +3102 2 +2958 1 +2878 9 +1598 4 +844 7 +3508 4 +2452 7 +305 5 +249 3 +337 8 +1641 6 +1915 9 +2099 8 +1124 5 +508 6 +3461 4 +2096 10 +607 7 +79 10 +1347 8 +2840 5 +2491 6 +2309 9 +3572 3 +3204 7 +1094 9 +2553 1 +2535 6 +2120 6 +2207 1 +1486 10 +1682 2 +2187 5 +3376 5 +1829 5 +1204 2 +4088 10 +3167 7 +2291 4 +921 3 +1800 10 +2773 4 +3553 8 +536 6 +1550 7 +1631 10 +3619 1 +809 3 +2196 6 +2749 3 +940 2 +582 8 +3589 1 +695 8 +3115 3 +2531 8 +1852 9 +2842 7 +295 6 +3658 5 +1991 1 +1042 9 +2772 1 +2378 2 +2002 9 +825 6 +2908 2 +3467 3 +410 6 +3261 7 +638 1 +4001 5 +316 4 +712 4 +3943 5 +1604 1 +2972 1 +385 4 +1485 1 +174 1 +3712 8 +2121 1 +2263 2 +3527 6 +790 2 +3648 5 +1447 4 +1069 1 +472 4 +966 9 +3321 4 +2305 8 +313 1 +3054 8 +2207 10 +623 3 +2843 1 +2223 3 +1297 5 +392 1 +2024 4 +760 3 +479 4 +2098 8 +3766 1 +3740 1 +793 10 +875 5 +734 3 +2361 9 +1495 1 +2583 9 +263 3 +3311 5 +3924 4 +767 2 +1096 8 +3657 5 +1454 5 +1506 1 +480 6 +908 10 +1903 4 +70 6 +1783 3 +3006 2 +2745 1 +2778 2 +2075 1 +2682 5 +3534 5 +1141 1 +3527 8 +818 1 +3067 9 +3208 2 +3677 4 +2850 8 +3719 7 +449 5 +3184 7 +1759 3 +3547 9 +1083 5 +3088 10 +2089 10 +1204 4 +1215 6 +700 3 +2188 3 +3500 4 +3283 2 +888 8 +971 3 +2164 10 +1459 4 +2657 10 +1880 5 +72 5 +3540 6 +2516 7 +3183 2 +3925 4 +187 10 +1757 4 +496 5 +1044 7 +1674 8 +1910 5 +898 10 +436 3 +2711 10 +3553 7 +2242 7 +4093 5 +314 7 +1779 1 +717 6 +2834 4 +53 5 +3642 9 +814 3 +2008 5 +3764 8 +1903 8 +3104 8 +2883 3 +1923 2 +668 3 +3264 7 +2084 9 +400 7 +37 5 +1332 8 +2382 1 +368 1 +2821 6 +308 10 +2080 4 +549 10 +3131 9 +3545 7 +809 1 +1002 6 +3954 2 +1143 1 +2762 10 +1695 1 +2516 6 +3886 2 +2544 4 +3984 3 +3258 10 +1750 6 +3175 7 +1876 9 +1631 9 +2125 6 +1821 10 +1693 3 +2199 8 +1857 8 +3561 9 +4041 6 +275 7 +3431 9 +1890 4 +3510 9 +1703 2 +2084 6 +1740 3 +584 2 +2044 6 +3370 8 +2047 4 +796 1 +3790 2 +2454 1 +751 1 +2693 9 +2581 9 +1504 9 +1132 3 +3271 8 +958 2 +1435 6 +3812 1 +2015 2 +457 3 +794 8 +3842 10 +3216 3 +2042 9 +1434 6 +1239 2 +2127 6 +1875 3 +944 6 +3891 4 +1378 8 +3079 4 +18 2 +3976 3 +1541 5 +3214 5 +3051 7 +3073 2 +1602 2 +3425 4 +1351 8 +1690 2 +1897 3 +1664 9 +3108 10 +3148 2 +1947 9 +1882 8 +2122 10 +637 4 +2600 9 +33 10 +740 6 +4052 2 +3853 2 +2945 10 +3184 10 +1138 7 +891 6 +4046 10 +1143 9 +2222 1 +3773 4 +1202 5 +2821 10 +2819 5 +3248 10 +1468 1 +1003 9 +2874 4 +2326 3 +3856 4 +2754 9 +1046 10 +158 8 +987 6 +498 10 +1450 9 +2469 6 +893 2 +242 5 +965 8 +1404 4 +1237 10 +732 5 +1851 10 +2109 7 +59 9 +188 7 +2796 6 +1013 1 +487 3 +2324 5 +3743 8 +892 7 +4064 7 +4045 3 +3782 10 +1446 9 +2252 3 +3909 1 +2342 5 +3848 4 +2927 4 +1566 9 +2926 10 +1353 3 +2182 6 +3307 1 +3550 9 +2691 10 +2161 5 +18 8 +846 10 +3044 2 +3781 10 +3874 5 +1806 3 +3004 7 +3706 4 +1410 5 +385 3 +2192 3 +2394 5 +1136 4 +3317 4 +2178 10 +4041 5 +2993 8 +4040 9 +1019 9 +2970 6 +562 1 +32 5 +2279 10 +526 1 +2837 1 +2567 2 +3052 6 +1494 9 +4057 7 +746 8 +794 6 +2297 8 +1915 3 +2059 2 +765 3 +1307 5 +1127 1 +152 6 +2790 6 +3288 4 +666 6 +1417 4 +4066 10 +435 7 +815 8 +3398 5 +242 7 +220 7 +1099 3 +3662 1 +4005 5 +797 10 +1097 1 +2316 1 +491 5 +3261 6 +2273 7 +2782 9 +1929 3 +1046 9 +330 2 +4046 1 +3587 4 +3946 4 +3234 6 +138 1 +3011 3 +1700 6 +2820 6 +2043 1 +3290 6 +34 7 +1907 10 +1689 5 +2015 3 +3168 9 +1296 5 +485 5 +2642 9 +912 3 +3574 5 +2187 6 +294 8 +1082 5 +2047 2 +2364 8 +3798 2 +2315 10 +636 4 +3260 7 +3611 1 +83 6 +2147 6 +1444 1 +3128 4 +2620 8 +1805 8 +432 5 +1134 3 +3839 6 +3958 6 +859 1 +3553 10 +1860 10 +266 3 +3831 9 +489 8 +3482 5 +1726 5 +2778 10 +3276 1 +588 4 +1106 6 +3010 10 +1904 10 +2911 1 +1270 5 +1933 7 +1668 3 +2371 2 +1368 2 +1935 2 +754 6 +948 7 +4086 9 +1736 6 +2621 6 +3620 5 +3147 9 +2652 7 +3169 6 +1000 8 +3131 10 +3956 10 +3640 2 +1964 8 +2045 5 +3052 7 +360 5 +420 7 +3965 4 +2531 9 +1693 4 +1793 6 +3131 4 +3668 8 +3973 2 +1992 1 +858 6 +2315 3 +2248 4 +3981 5 +212 7 +2446 6 +1943 2 +2335 3 +1932 6 +2896 9 +360 7 +4019 6 +3330 10 +1234 6 +1792 7 +3785 5 +735 10 +343 9 +1244 9 +32 8 +2145 9 +2048 3 +2638 6 +2376 3 +1678 6 +1517 1 +3968 5 +1278 4 +2850 8 +384 5 +3305 4 +1696 8 +231 9 +3208 9 +2345 9 +3380 8 +105 8 +2586 4 +909 7 +762 1 +2857 6 +3035 6 +1202 7 +8 8 +1402 1 +1382 9 +3977 4 +860 1 +1392 10 +2480 10 +1663 2 +218 2 +2324 8 +3023 2 +3539 5 +1883 10 +3576 9 +258 10 +793 9 +2534 4 +967 10 +2851 4 +732 3 +3340 10 +139 7 +1777 4 +4067 4 +1892 4 +1651 6 +1054 9 +1563 5 +349 3 +1987 6 +4087 7 +1945 5 +1990 4 +1095 10 +2507 2 +2146 6 +2975 4 +2503 9 +4011 2 +2523 1 +3597 6 +2361 6 +2883 7 +4058 5 +2580 5 +672 5 +2903 3 +3705 7 +3364 7 +498 3 +3776 6 +1210 9 +260 6 +48 10 +1825 2 +3355 6 +2966 10 +958 10 +2739 3 +571 8 +2246 5 +1647 8 +107 4 +2268 7 +3306 7 +2320 3 +3845 7 +4052 7 +3121 5 +3152 8 +1457 9 +1899 4 +2679 3 +2272 4 +761 1 +1511 9 +3331 9 +2836 3 +1161 8 +1409 1 +151 2 +4039 5 +2306 10 +3518 1 +2878 1 +3216 1 +2136 3 +3066 1 +2002 8 +1853 7 +2803 8 +3575 3 +2766 10 +140 2 +2380 7 +1638 7 +954 7 +1200 8 +2932 2 +1346 5 +1628 9 +1527 2 +2214 6 +0 10 +3101 6 +3820 1 +2960 8 +3712 2 +3644 2 +186 2 +4003 2 +1005 7 +1048 10 +47 3 +1204 5 +1305 7 +311 7 +3553 5 +2177 9 +2134 4 +2156 6 +3213 6 +1712 3 +4077 4 +1002 5 +3338 9 +3790 3 +210 3 +1744 8 +2771 6 +3089 9 +2018 6 +3079 2 +539 6 +62 1 +287 7 +1220 7 +2632 9 +806 2 +2889 10 +2385 10 +1006 8 +1598 7 +672 10 +654 10 +2968 5 +2954 3 +2647 4 +1433 9 +869 9 +2516 9 +2641 4 +1410 1 +2263 4 +1278 2 +3487 1 +4044 8 +3472 8 +3228 4 +2269 6 +4083 10 +3930 9 +1976 1 +1729 3 +2474 1 +1162 6 +3393 2 +3206 10 +3661 6 +370 7 +1080 3 +169 1 +981 9 +2977 7 +1833 2 +3547 4 +1495 9 +1016 8 +2064 7 +2971 6 +3397 8 +348 8 +627 5 +3026 5 +3692 6 +3596 3 +1235 1 +651 2 +2084 7 +2432 5 +136 4 +4040 8 +820 8 +1265 9 +3425 3 +328 2 +340 1 +3161 7 +3849 5 +3448 2 +3869 8 +2734 1 +1776 7 +1113 2 +3366 9 +2128 1 +2368 5 +1645 5 +468 2 +458 1 +214 4 +1181 2 +3903 10 +343 5 +1483 1 +2450 10 +3092 5 +221 10 +3226 7 +4064 10 +3592 8 +1327 8 +758 6 +2094 7 +1110 5 +2272 8 +722 5 +3483 9 +384 6 +395 5 +1219 2 +2729 6 +2917 7 +2913 6 +2956 10 +1940 1 +4057 2 +1357 10 +712 6 +2062 4 +1233 9 +3567 1 +81 6 +346 5 +3885 8 +3340 7 +4041 2 +2606 5 +3324 2 +171 3 +3975 1 +816 6 +1556 9 +1761 3 +1811 7 +4042 8 +3559 5 +3349 5 +2184 10 +1882 1 +2481 6 +148 5 +367 2 +34 4 +813 5 +1284 3 +668 10 +3340 2 +2051 7 +1805 2 +2500 8 +3417 4 +1497 2 +2223 8 +1964 1 +3321 3 +1006 9 +1753 4 +2029 9 +3651 1 +746 8 +2755 6 +119 4 +2076 5 +1177 4 +2112 5 +2475 9 +933 6 +2400 8 +1364 3 +1998 1 +412 4 +2651 8 +2481 7 +772 4 +557 2 +3258 9 +531 1 +3685 9 +793 8 +1235 8 +3974 10 +987 2 +3499 7 +625 3 +2313 6 +3913 2 +2427 5 +3794 2 +1380 7 +2446 5 +3385 9 +133 2 +24 4 +1239 6 +1955 2 +1911 1 +150 3 +4015 2 +3292 6 +1926 3 +243 3 +3738 6 +3500 4 +687 9 +1642 9 +767 5 +1266 6 +3112 6 +3385 10 +3271 1 +3338 1 +2876 5 +4054 10 +2204 3 +1925 8 +3738 8 +192 1 +1907 5 +851 8 +3311 6 +107 5 +3225 10 +3890 5 +363 3 +2629 9 +2460 3 +399 5 +3622 5 +3672 7 +620 3 +1437 5 +3439 8 +2697 3 +3867 4 +995 1 +2512 9 +1818 1 +2488 10 +705 8 +2226 3 +334 4 +2080 3 +3440 3 +874 8 +1353 10 +2539 9 +3699 8 +627 6 +2928 5 +2244 1 +3730 9 +135 2 +3463 4 +2835 5 +1197 6 +3428 8 +1321 9 +718 6 +3813 10 +3435 4 +2379 7 +3080 2 +3083 6 +3480 1 +1848 10 +1903 7 +2182 7 +2115 7 +643 1 +2700 6 +3730 9 +2113 3 +511 3 +2279 1 +3577 6 +1012 9 +444 1 +1395 7 +232 6 +553 8 +3936 6 +3674 10 +779 7 +566 1 +1341 3 +1673 8 +1165 4 +2998 10 +658 10 +2941 6 +3713 10 +250 10 +3088 8 +1136 1 +1677 9 +2568 4 +825 6 +1363 7 +3803 10 +2531 4 +3493 6 +1263 3 +2768 1 +3134 6 +3503 5 +2271 4 +909 8 +2723 7 +3863 10 +850 1 +3385 2 +3789 3 +115 9 +3542 4 +1523 9 +2715 5 +1936 4 +541 10 +1673 1 +1365 4 +3649 5 +862 4 +1903 1 +3088 2 +2062 8 +2391 5 +2111 5 +2398 3 +677 3 +2665 1 +2741 9 +1309 1 +1217 8 +1124 3 +2501 2 +3134 3 +2086 4 +2115 3 +2170 5 +3180 6 +1963 8 +2031 3 +1489 5 +2129 2 +3046 7 +1148 10 +1152 3 +1231 1 +478 9 +904 10 +760 6 +1973 10 +271 1 +1450 9 +1904 2 +4028 3 +3952 4 +4031 2 +998 6 +3397 6 +1798 2 +1243 9 +669 3 +1103 8 +2561 9 +1336 2 +1898 10 +3757 6 +71 8 +2191 3 +955 1 +1181 10 +1097 2 +607 6 +3789 8 +2397 3 +3731 7 +590 10 +3673 1 +3001 2 +3464 6 +2933 5 +1798 7 +864 6 +3376 7 +2628 9 +2012 8 +1778 9 +4004 10 +2607 1 +2224 8 +3822 6 +1640 6 +962 1 +1156 10 +2197 2 +2335 6 +3502 3 +3850 1 +94 4 +2836 1 +3545 2 +3568 2 +147 5 +3812 9 +2883 2 +158 3 +764 8 +382 2 +3227 10 +1902 9 +693 1 +2808 6 +2778 3 +3224 7 +748 7 +3291 10 +1098 10 +202 10 +3440 3 +1715 5 +1676 5 +544 2 +2446 2 +2419 4 +2003 10 +345 5 +2569 8 +3645 9 +3442 3 +3336 5 +2466 8 +3894 9 +618 6 +2501 5 +1284 7 +2334 9 +3551 4 +222 4 +1225 7 +3703 3 +169 1 +1279 7 +1323 4 +3785 2 +1942 3 +2301 10 +1616 8 +2266 8 +3885 2 +1626 1 +552 7 +1040 9 +3796 1 +1145 2 +3568 3 +2973 1 +2361 4 +1690 5 +3478 9 +2362 1 +2586 7 +2335 6 +552 5 +1042 7 +998 7 +2295 4 +3080 3 +3340 7 +539 10 +445 7 +2453 3 +3289 10 +2697 10 +1077 5 +452 3 +3538 3 +2971 7 +2351 8 +648 4 +2591 9 +1177 6 +45 7 +120 3 +662 2 +744 1 +2748 7 +2016 5 +3566 4 +3063 2 +935 3 +2375 8 +3382 9 +3709 3 +3150 1 +2717 7 +667 5 +1362 2 +3286 6 +2738 5 +298 4 +324 8 +1649 10 +2800 8 +1823 6 +206 3 +2642 1 +710 10 +2488 5 +2058 8 +2183 5 +3690 1 +2807 3 +3797 4 +3972 10 +1086 5 +2752 2 +1000 7 +2083 8 +2655 2 +1328 5 +251 9 +582 5 +216 6 +2669 6 +1021 7 +1870 5 +2365 7 +1388 4 +236 2 +146 2 +3013 10 +1503 7 +3728 8 +1029 1 +3445 3 +3721 3 +629 10 +2488 5 +2878 10 +322 1 +845 8 +915 6 +3599 10 +315 4 +346 5 +3467 2 +1438 2 +3752 6 +2755 4 +2422 1 +3026 4 +170 4 +1402 1 +2791 8 +143 3 +364 9 +2751 1 +3433 8 +1617 10 +2479 1 +1790 4 +1386 3 +496 6 +2842 9 +381 9 +1309 2 +2860 6 +3872 4 +3481 3 +4042 1 +2633 2 +568 7 +3264 1 +1935 5 +1879 5 +3712 8 +3549 7 +1303 3 +3758 7 +557 8 +528 1 +2361 4 +3533 7 +1118 2 +1233 10 +1692 10 +565 10 +112 9 +2924 4 +306 9 +1062 2 +771 2 +422 4 +3627 6 +3759 7 +98 2 +3618 1 +2167 1 +3920 2 +3831 10 +3358 2 +285 8 +663 7 +2211 6 +1940 10 +2724 10 +2462 5 +3231 7 +4059 1 +655 4 +3209 4 +1967 2 +16 2 +2907 6 +1247 2 +423 9 +2550 8 +2504 8 +3717 6 +638 10 +3612 9 +251 8 +1957 2 +2920 8 +1126 2 +4066 6 +3226 9 +367 2 +121 9 +1582 8 +1083 2 +523 9 +2216 7 +365 2 +1006 3 +200 7 +2057 6 +2091 1 +1604 10 +468 9 +1648 10 +1240 1 +2192 8 +2788 9 +309 3 +2429 1 +943 6 +2749 7 +2008 7 +3065 3 +3963 9 +3473 2 +1899 4 +282 4 +621 1 +1027 6 +4082 2 +336 3 +3997 10 +337 10 +1187 2 +2267 1 +3160 9 +1307 5 +1026 7 +1905 10 +1233 6 +3477 7 +623 9 +1811 4 +2416 9 +749 8 +2941 7 +4067 2 +2988 9 +2802 9 +3350 10 +2006 9 +1948 8 +2569 9 +1043 10 +227 4 +2570 4 +208 9 +504 4 +2605 6 +1583 1 +2863 7 +2535 2 +1898 5 +2526 4 +1958 3 +750 10 +1144 4 +3770 10 +2773 1 +579 1 +298 9 +2876 5 +124 8 +3938 6 +2761 6 +1497 9 +2385 3 +28 5 +1902 1 +2215 1 +2232 4 +691 4 +3335 3 +1653 9 +2574 5 +905 9 +2089 1 +4054 2 +322 4 +1428 9 +3986 7 +3064 1 +1395 10 +199 1 +1969 8 +647 6 +2922 2 +3846 6 +3710 1 +2717 7 +872 6 +3434 9 +2872 5 +3901 5 +3798 1 +3308 2 +1375 5 +2324 5 +3747 1 +1766 10 +4054 1 +3359 8 +3596 1 +598 5 +1763 5 +834 2 +2993 6 +2178 8 +1166 5 +1497 7 +3001 2 +3940 1 +3314 7 +2921 9 +3621 2 +322 10 +3712 10 +1826 9 +2031 3 +300 2 +1676 9 +2713 10 +3797 4 +3538 5 +1714 8 +1573 6 +461 4 +2638 8 +3952 8 +2699 3 +782 4 +2420 9 +1389 6 +3213 9 +2469 8 +268 5 +1800 3 +3283 9 +2168 6 +2790 1 +2303 5 +1537 9 +2811 9 +2176 1 +4047 4 +4057 8 +2859 4 +715 7 +3273 8 +522 7 +2281 3 +3620 4 +1318 8 +2615 8 +247 7 +3388 4 +2357 9 +1736 4 +2903 10 +3366 2 +530 5 +4067 7 +1515 5 +1257 3 +284 9 +2575 8 +810 6 +1111 1 +912 3 +2310 5 +1689 6 +605 1 +1094 3 +1493 8 +1956 1 +2774 2 +1818 4 +717 8 +3409 7 +3451 6 +2795 10 +2000 9 +867 10 +1618 10 +3671 8 +2327 7 +3069 3 +3664 7 +3641 8 +1703 4 +1593 10 +2346 4 +2062 2 +2366 7 +2835 9 +3325 5 +1489 6 +3933 7 +622 6 +195 4 +2799 2 +691 2 +426 1 +1178 8 +2160 1 +3000 9 +3391 6 +1186 9 +3507 10 +2895 10 +1630 9 +3024 3 +2015 9 +2312 5 +252 4 +1032 10 +386 8 +1337 9 +4041 8 +67 8 +4058 2 +2072 8 +1684 8 +1896 6 +1753 4 +398 7 +749 1 +729 7 +2602 10 +2766 8 +2777 5 +717 7 +1261 2 +1327 4 +806 9 +2775 6 +1071 7 +669 4 +547 7 +2400 6 +3094 3 +3333 5 +1094 9 +2456 5 +2750 2 +3026 8 +2710 9 +3808 8 +1996 10 +3515 3 +3116 4 +600 6 +1129 10 +2806 7 +1133 4 +3239 4 +3498 8 +3927 3 +3119 6 +645 10 +3976 7 +3000 7 +1941 8 +2398 2 +804 3 +2801 9 +131 5 +3908 1 +3488 6 +2652 9 +514 6 +3429 8 +1486 2 +2305 2 +3119 6 +3841 8 +400 6 +3821 10 +1439 9 +3818 5 +3814 6 +3004 2 +2864 7 +2671 5 +2987 4 +3497 1 +2841 10 +3223 10 +2353 7 +2602 2 +2515 10 +2764 6 +3647 6 +301 8 +3496 1 +2796 1 +507 7 +3450 4 +1967 3 +1302 1 +1883 7 +1472 3 +764 7 +1242 10 +3043 2 +2329 3 +313 6 +2454 1 +595 10 +2469 7 +2829 1 +672 4 +2318 10 +3829 3 +306 9 +2391 6 +186 8 +922 9 +498 10 +2596 4 +4041 7 +3766 3 +2092 1 +1106 5 +1029 1 +760 9 +629 7 +2972 7 +49 10 +1723 1 +1100 10 +1552 8 +2948 7 +3257 6 +1219 9 +1558 1 +2476 5 +1419 8 +3284 8 +3402 6 +872 2 +905 9 +1830 6 +3549 6 +430 8 +2495 5 +1579 5 +2147 6 +3292 4 +1639 9 +1331 2 +2285 3 +1700 6 +3407 4 +1553 9 +667 4 +3829 7 +1023 8 +999 3 +2571 8 +1483 6 +4059 9 +2 2 +3736 4 +3863 6 +1784 10 +3006 6 +1101 9 +1805 7 +141 2 +4044 6 +646 6 +1909 1 +463 8 +4083 8 +3321 2 +1316 4 +2416 4 +768 10 +2575 9 +0 2 +946 3 +2547 9 +716 8 +876 2 +567 4 +429 3 +3650 3 +1392 2 +222 10 +3304 3 +1999 8 +3132 5 +2022 5 +762 9 +520 3 +218 10 +3536 7 +1025 7 +3440 10 +1655 8 +2431 4 +1081 8 +2069 3 +617 3 +2451 6 +3468 4 +2915 8 +509 6 +3601 1 +3734 1 +1848 10 +3266 5 +1321 4 +3339 1 +3907 3 +605 4 +2670 5 +3700 5 +1465 5 +230 9 +1647 6 +1121 8 +1702 10 +1313 3 +3437 7 +687 2 +394 4 +3413 7 +3785 1 +3701 7 +2420 1 +1439 2 +3617 1 +2377 7 +828 10 +1584 5 +2105 10 +613 4 +1703 9 +1085 2 +3265 7 +2187 10 +65 1 +478 9 +1802 2 +548 9 +173 9 +1609 10 +2362 1 +2078 8 +3227 8 +1351 3 +1476 4 +4030 3 +77 8 +1429 3 +2230 1 +2267 4 +3761 7 +2482 3 +3695 2 +2715 10 +1950 8 +3214 3 +191 2 +1426 1 +4025 9 +2288 1 +651 1 +3778 8 +3558 2 +3037 4 +2204 6 +1067 3 +3070 9 +1484 8 +3005 3 +1059 1 +3446 3 +4014 4 +3870 8 +547 8 +2775 6 +3845 8 +1804 4 +2908 1 +218 5 +3093 3 +89 7 +3684 6 +3658 9 +833 7 +1967 6 +161 4 +670 4 +2866 3 +117 8 +3446 3 +2549 1 +1795 3 +2873 8 +1846 1 +751 8 +701 4 +1463 6 +3840 2 +877 4 +1676 6 +1189 4 +2423 10 +2994 3 +227 9 +1188 5 +3373 3 +513 8 +1689 10 +1156 6 +2272 9 +785 10 +2816 1 +25 3 +3238 8 +2060 2 +2353 2 +1282 2 +2330 5 +2565 4 +124 4 +1431 2 +1046 2 +20 3 +1129 3 +3634 7 +1691 9 +2914 1 +1649 4 +2172 2 +237 7 +683 3 +491 4 +334 8 +2083 10 +3861 6 +2302 2 +3605 8 +4050 2 +2811 1 +445 5 +1032 8 +2550 3 +3586 7 +291 7 +333 3 +2188 10 +593 7 +3659 7 +1753 4 +1055 2 +2025 4 +42 1 +3533 3 +778 10 +3235 8 +3881 5 +167 2 +2373 7 +4031 6 +1238 5 +1384 10 +146 5 +2762 5 +95 6 +2201 3 +2946 7 +1187 7 +3056 5 +2049 6 +1761 4 +511 8 +1501 3 +2194 4 +514 2 +1275 5 +2585 9 +1824 4 +2886 6 +1378 1 +1310 3 +3751 8 +1893 6 +2449 5 +1366 2 +1640 8 +1890 2 +3838 9 +3109 8 +311 9 +2731 4 +3516 4 +4013 3 +2313 10 +2471 7 +3221 3 +3547 7 +1578 5 +2093 8 +3201 7 +3212 2 +406 5 +442 5 +2052 2 +3781 7 +3699 5 +571 6 +2319 7 +252 1 +2511 8 +2334 8 +3676 10 +3033 5 +462 7 +3261 4 +116 6 +3862 4 +1353 3 +138 4 +2869 9 +3701 5 +1123 1 +2054 4 +1928 6 +2355 5 +614 1 +2389 7 +2568 7 +3382 10 +967 4 +1844 6 +2337 4 +370 5 +749 3 +3739 3 +2660 9 +330 5 +3931 9 +2422 6 +47 5 +1672 1 +532 5 +2381 1 +153 8 +1234 10 +611 8 +1299 1 +3473 1 +3457 3 +1313 3 +557 8 +1826 8 +1328 9 +2872 10 +724 6 +3361 4 +1470 5 +2960 5 +2399 2 +3695 3 +2674 6 +2528 1 +1879 5 +3290 5 +722 4 +458 8 +3622 6 +2228 6 +2952 9 +259 9 +4081 10 +806 9 +3096 5 +1874 1 +2058 3 +2194 2 +1318 1 +3759 10 +3080 10 +1509 3 +1823 2 +2253 1 +4087 4 +3684 5 +1961 7 +965 9 +605 5 +3052 10 +274 2 +3743 9 +3707 5 +2463 6 +2156 10 +3623 5 +1155 10 +3838 2 +4078 1 +2192 2 +3102 3 +1773 1 +3948 9 +2377 8 +2888 5 +2136 3 +2060 5 +896 8 +3079 9 +1040 2 +1130 7 +3937 6 +3076 6 +3555 3 +1160 10 +502 10 +1344 8 +37 3 +1474 6 +2152 6 +3943 6 +2839 6 +3575 5 +841 1 +1645 4 +403 3 +3421 2 +2622 3 +2038 7 +1854 8 +1215 9 +2510 3 +3126 5 +2836 2 +205 10 +2493 5 +2828 7 +2832 1 +1147 7 +2746 2 +3423 1 +996 5 +3615 8 +2340 4 +3044 2 +2626 6 +1859 3 +2203 9 +2429 1 +3878 1 +1973 3 +3902 1 +1947 6 +1431 3 +954 9 +2126 9 +1750 5 +3783 7 +609 4 +3544 9 +3000 2 +3231 9 +230 5 +1005 4 +2676 3 +1779 8 +126 7 +3815 9 +1502 8 +3379 7 +239 10 +1746 8 +3556 1 +585 8 +128 4 +2657 8 +3755 6 +792 1 +3560 10 +1089 6 +1759 1 +2366 10 +3763 9 +3904 4 +3946 4 +2756 6 +1744 8 +1094 4 +2773 9 +2866 10 +473 2 +3495 1 +2644 6 +2988 4 +580 6 +3062 9 +1291 8 +3403 1 +2381 8 +3605 4 +2384 4 +2624 6 +2276 5 +3504 6 +1794 3 +984 10 +2298 4 +1741 5 +3294 1 +1427 6 +550 5 +1140 3 +3464 5 +3081 8 +2807 3 +2306 1 +1334 1 +2968 4 +300 7 +3997 5 +3240 9 +1294 8 +3015 7 +3973 6 +3172 7 +2599 10 +4076 10 +925 8 +4002 8 +1115 2 +2096 6 +2261 3 +1707 4 +496 6 +2034 5 +728 1 +1528 4 +1093 1 +1655 4 +2484 7 +2747 7 +1296 9 +3705 8 +2130 5 +2688 6 +3843 1 +3428 6 +563 9 +1196 2 +2313 8 +389 10 +2293 2 +2089 9 +1327 1 +2247 1 +1018 7 +422 3 +2384 2 +529 3 +805 9 +1418 4 +2608 5 +2303 1 +3074 1 +2861 6 +2880 3 +1415 3 +1745 1 +3101 2 +3574 1 +2530 7 +3120 1 +2466 2 +3287 6 +1071 7 +642 1 +50 1 +2096 3 +1810 4 +3897 6 +1711 4 +2236 10 +3087 1 +1523 3 +428 6 +3090 2 +752 5 +1303 6 +791 2 +3772 5 +3060 3 +276 2 +3836 6 +1636 5 +3260 9 +298 9 +761 7 +3539 10 +3033 2 +2710 5 +548 10 +2236 10 +752 9 +3956 3 +3436 4 +1190 1 +2438 8 +1635 10 +2186 5 +2279 7 +2011 2 +3246 9 +166 8 +3613 5 +2767 3 +3310 10 +3182 5 +761 6 +81 3 +1125 9 +2079 9 +2713 6 +2949 8 +1109 6 +1802 6 +3473 5 +3316 7 +1995 1 +2101 1 +3781 8 +375 6 +3845 4 +905 6 +2920 1 +2864 10 +2161 3 +2636 5 +3050 5 +1001 5 +577 1 +455 9 +279 5 +964 4 +3290 1 +3165 6 +3941 7 +663 9 +878 4 +3683 2 +1732 1 +2821 3 +626 4 +955 3 +3228 9 +1125 2 +176 8 +3467 1 +2231 1 +493 1 +1354 9 +3457 7 +489 5 +2915 6 +169 7 +2606 2 +3155 7 +1887 7 +805 8 +1201 1 +2784 7 +1515 7 +3404 2 +3131 5 +688 4 +2514 1 +1177 5 +1221 2 +1488 4 +3282 9 +3540 9 +615 6 +1572 9 +2183 8 +1206 5 +2648 5 +129 4 +73 7 +834 6 +1421 1 +3000 3 +1743 8 +3202 7 +3561 10 +254 3 +2436 2 +633 4 +2914 4 +3341 3 +2957 9 +2326 8 +3617 2 +3928 7 +2087 6 +1948 4 +3483 7 +3571 2 +445 10 +3758 6 +2060 8 +1411 3 +3633 10 +2902 3 +2883 1 +2072 9 +122 3 +3060 1 +3294 1 +1679 10 +2728 1 +2040 6 +662 10 +180 10 +1269 7 +1840 8 +2469 10 +3559 5 +2778 6 +2144 10 +2363 3 +2205 4 +2284 7 +400 8 +1167 3 +2692 8 +3226 8 +1845 4 +2370 7 +202 1 +2413 6 +32 10 +878 5 +946 5 +3493 6 +1605 4 +1332 6 +941 6 +3075 6 +2886 2 +917 8 +3930 4 +3052 9 +2986 7 +3234 3 +1216 10 +2660 2 +1263 4 +4093 10 +4015 9 +1480 7 +1227 8 +518 7 +1476 6 +2073 9 +77 6 +1061 10 +3768 1 +1034 1 +3905 3 +1328 7 +2601 8 +970 9 +2644 1 +2034 10 +720 8 +1749 3 +1298 5 +2304 10 +377 5 +3482 1 +2233 7 +3569 10 +605 8 +2151 10 +3546 4 +1699 3 +3277 1 +2573 2 +1318 3 +1096 3 +669 3 +1930 10 +620 10 +3123 4 +870 10 +1238 3 +2084 3 +2368 3 +966 9 +199 6 +3942 6 +2792 1 +569 8 +165 1 +1571 7 +2859 6 +1567 2 +3782 4 +932 9 +2540 3 +3627 1 +745 7 +2420 4 +3761 7 +3870 9 +1642 3 +1394 10 +3151 5 +1286 6 +3902 9 +1126 6 +2171 3 +2645 2 +651 3 +1339 5 +3791 7 +3945 9 +1769 6 +1692 2 +1338 10 +732 10 +2410 7 +713 6 +136 10 +2966 3 +458 2 +1204 8 +1698 4 +2628 9 +1680 7 +1361 2 +579 6 +1948 4 +3507 10 +4019 10 +3171 7 +536 10 +407 7 +1526 2 +1468 8 +3874 8 +3144 8 +499 4 +1453 3 +524 3 +2746 1 +184 6 +1811 1 +52 9 +3121 1 +1357 10 +1017 9 +2192 2 +2987 6 +1137 3 +242 7 +2761 9 +2075 10 +3275 5 +1061 8 +2137 8 +660 10 +1996 5 +163 2 +1761 4 +2318 2 +3570 5 +2478 3 +966 4 +3212 10 +2345 9 +3321 5 +1807 1 +3326 4 +2135 2 +3927 8 +2992 4 +556 4 +1623 4 +1523 7 +920 3 +526 6 +3249 1 +3437 1 +3043 8 +2877 7 +3945 4 +294 8 +289 6 +2722 7 +3440 3 +3979 1 +3144 1 +1985 3 +3975 9 +3826 8 +136 3 +3342 2 +3679 6 +3088 5 +446 2 +2292 4 +3041 10 +2656 3 +3513 6 +1280 1 +2610 9 +2661 4 +422 6 +54 2 +2021 5 +3864 2 +254 10 +1542 1 +1647 4 +3368 1 +3790 5 +3016 7 +3277 4 +1189 3 +969 4 +656 5 +3823 6 +4081 4 +393 7 +3358 1 +2825 9 +3544 1 +680 6 +1429 10 +1347 2 +3018 6 +2662 2 +3516 3 +4074 3 +3215 7 +3970 7 +1252 1 +1594 6 +1729 2 +3765 7 +637 8 +751 7 +2482 4 +733 2 +3850 10 +2449 4 +1382 5 +185 10 +83 4 +3644 8 +2661 1 +1712 4 +533 3 +35 2 +3955 4 +3133 4 +3064 10 +3728 10 +1492 2 +1234 10 +2203 2 +705 3 +321 2 +386 5 +1639 9 +1725 8 +823 9 +934 1 +1222 4 +862 8 +2665 4 +2998 4 +2214 5 +2306 3 +3735 7 +3509 5 +139 7 +398 4 +411 3 +3341 4 +1300 1 +38 9 +1877 5 +1392 5 +1156 4 +3161 1 +3027 3 +2939 10 +721 7 +3238 9 +2148 9 +1675 6 +1853 5 +1912 7 +251 6 +3098 4 +1352 3 +630 5 +3370 1 +65 10 +2325 8 +3688 8 +606 6 +1510 2 +3982 1 +3867 10 +888 10 +2874 7 +2560 7 +2199 2 +1996 5 +2965 4 +879 8 +3151 2 +1253 2 +1275 3 +1155 1 +2036 10 +3880 3 +3907 6 +283 6 +3319 7 +3543 7 +3446 9 +810 1 +2069 9 +2928 4 +191 8 +1380 10 +582 10 +425 6 +235 4 +1995 6 +677 1 +3967 9 +879 5 +3179 3 +3038 7 +1785 8 +1906 10 +4095 3 +3679 9 +2749 7 +1069 3 +188 3 +3307 2 +629 9 +2304 5 +2244 5 +1247 4 +2603 1 +3044 9 +2567 8 +3285 2 +3387 10 +2907 1 +471 10 +2077 9 +3257 10 +536 6 +1722 6 +599 4 +3487 10 +1150 7 +694 8 +1787 4 +3202 6 +3354 5 +2059 4 +1700 1 +2012 7 +1176 6 +2306 5 +2052 5 +2118 1 +1998 3 +457 2 +201 4 +264 3 +1911 6 +3168 4 +720 8 +3410 4 +2493 5 +1687 10 +660 2 +3167 3 +339 6 +1547 10 +716 3 +1095 9 +784 7 +444 1 +446 7 +2945 4 +1198 4 +2037 8 +326 7 +3370 3 +1448 10 +1007 5 +3943 6 +423 3 +101 3 +2099 3 +1 10 +2841 2 +2516 1 +4060 6 +2563 5 +1963 8 +3989 3 +1397 9 +2786 8 +3013 4 +428 1 +1830 5 +2502 3 +1496 7 +770 9 +1737 8 +2612 9 +2542 3 +3154 9 +3661 5 +1271 10 +558 4 +866 7 +365 4 +3517 3 +830 8 +455 3 +3380 8 +886 4 +1429 8 +200 3 +3908 8 +648 3 +91 3 +791 5 +3998 8 +3420 7 +3604 9 +1988 4 +1927 7 +1738 3 +3145 4 +4017 1 +3732 1 +1345 9 +1469 10 +2896 4 +358 10 +1905 5 +2025 6 +52 5 +2466 1 +1332 4 +706 4 +3153 2 +2509 10 +3789 4 +2525 6 +2994 9 +3386 9 +2353 2 +1970 8 +3150 10 +697 10 +3628 4 +3735 1 +2902 1 +2916 8 +1131 6 +2449 7 +2256 2 +1037 8 +873 10 +2524 9 +3729 7 +3510 9 +912 8 +1351 5 +3213 7 +116 6 +2781 9 +3781 7 +987 9 +224 2 +2170 7 +2957 10 +3753 8 +2546 1 +2295 6 +2162 5 +228 8 +2825 8 +471 3 +1198 2 +3532 1 +301 1 +1597 5 +569 4 +1366 5 +920 8 +1937 3 +3212 1 +2528 8 +2803 3 +961 1 +2705 3 +3672 7 +2234 9 +174 2 +854 9 +2816 5 +2280 2 +3101 2 +549 4 +2064 1 +117 9 +507 1 +1728 1 +1150 5 +3312 8 +746 8 +163 4 +1436 3 +2183 5 +3464 2 +3702 2 +1428 9 +262 1 +3486 6 +3200 10 +2428 7 +507 5 +1275 8 +3160 8 +3044 6 +3909 1 +1829 5 +2082 6 +600 4 +2011 8 +3697 8 +1983 4 +1083 10 +2200 10 +662 2 +3974 4 +2660 5 +3007 2 +2732 10 +658 8 +1607 5 +1726 5 +2072 7 +1318 9 +2327 6 +683 4 +1417 5 +4019 2 +2298 10 +2468 5 +2484 1 +640 5 +909 1 +3383 1 +733 8 +171 1 +1525 1 +3995 3 +3358 1 +1303 3 +1440 8 +2982 5 +250 3 +3681 3 +3585 7 +1668 7 +4028 10 +3734 9 +1486 10 +809 1 +2895 8 +3498 1 +1937 9 +3426 5 +4067 8 +3358 1 +2379 1 +660 3 +2233 5 +209 2 +2433 7 +2579 10 +3888 5 +3581 10 +2047 10 +3382 4 +312 10 +564 6 +750 10 +2459 7 +3991 10 +3691 6 +1776 7 +553 5 +794 2 +1928 2 +4032 5 +169 8 +2668 2 +3603 6 +3673 7 +3554 1 +3810 4 +1202 10 +1714 2 +3415 9 +4059 7 +3495 1 +3524 7 +1430 4 +1176 4 +4055 1 +1189 1 +3876 8 +3357 1 +1489 4 +1174 1 +470 3 +396 3 +3206 2 +1713 6 +3938 2 +223 7 +825 7 +3377 4 +4002 5 +2301 7 +3428 4 +3796 3 +553 7 +733 2 +1313 8 +3271 2 +616 6 +2533 7 +3916 6 +1280 8 +1655 6 +1439 3 +336 6 +4030 4 +3584 6 +1626 5 +1568 10 +2000 1 +1621 4 +326 9 +262 9 +1494 4 +3936 9 +345 5 +2071 8 +2090 4 +246 5 +2059 2 +2962 7 +2860 10 +3029 7 +1136 1 +2354 7 +2352 7 +2727 1 +385 10 +3312 9 +4075 5 +3319 7 +2917 8 +1577 9 +3490 4 +1629 1 +1123 1 +380 6 +1411 4 +1559 1 +3765 7 +408 2 +1422 8 +200 4 +1164 4 +3994 7 +1547 7 +3982 1 +188 1 +1065 7 +893 3 +400 6 +824 4 +1566 2 +1471 10 +3063 10 +1623 10 +3839 10 +2209 4 +1860 5 +3279 10 +4000 4 +3763 7 +1994 10 +1841 10 +3347 5 +58 7 +3053 10 +2020 3 +1465 10 +475 2 +3230 2 +1539 5 +1206 8 +3910 7 +3428 3 +915 4 +2602 2 +1036 7 +2873 3 +3426 2 +3789 9 +3867 10 +2420 7 +268 6 +16 10 +4072 2 +2510 4 +1975 9 +4075 6 +1680 1 +2231 6 +3514 6 +305 7 +629 5 +1157 4 +4079 8 +3085 6 +3667 1 +2830 3 +1419 5 +1535 1 +3703 7 +3475 9 +2563 5 +1847 6 +749 8 +2222 2 +3356 1 +1830 7 +1053 9 +3040 3 +907 5 +342 7 +2002 7 +2554 8 +796 5 +2960 8 +288 4 +4091 5 +537 1 +3772 4 +2944 8 +2436 5 +193 5 +4017 7 +3813 9 +1315 6 +354 9 +2268 2 +1458 3 +1338 7 +703 7 +1389 9 +3459 5 +2492 2 +1306 2 +3739 7 +3081 7 +655 2 +343 2 +2127 6 +368 7 +1965 3 +2220 4 +2810 1 +1996 10 +2980 4 +1073 9 +489 5 +2625 10 +3867 4 +3131 5 +2048 5 +802 8 +320 10 +2852 1 +3911 7 +3585 4 +1991 8 +4002 8 +2146 1 +2301 2 +595 8 +3298 9 +1043 6 +74 8 +3826 9 +3145 5 +2067 8 +2972 1 +3083 3 +2167 8 +277 7 +1423 2 +30 4 +835 8 +2595 6 +928 2 +3105 7 +2777 7 +3550 7 +749 2 +2206 6 +3923 5 +1227 9 +2410 6 +1069 3 +1539 8 +691 5 +1029 10 +759 7 +3185 1 +2948 7 +2047 1 +3145 3 +2602 10 +678 4 +1535 3 +3244 2 +2659 4 +1859 7 +1721 6 +976 2 +3808 3 +2188 10 +1352 4 +1887 2 +1073 4 +1462 3 +3347 9 +342 7 +1147 5 +3310 2 +2879 10 +1247 9 +1796 10 +1271 6 +1227 8 +2907 9 +3342 7 +3470 5 +3974 10 +3227 7 +24 8 +1290 5 +3966 3 +1480 6 +818 9 +110 7 +368 3 +2331 3 +2793 7 +1056 8 +87 9 +2185 8 +2437 5 +3128 10 +2431 1 +1472 7 +736 10 +625 2 +2524 8 +2896 6 +523 10 +3900 2 +39 8 +29 7 +3419 10 +1473 2 +3676 3 +1270 9 +1607 5 +2863 10 +2489 1 +185 9 +1366 10 +2688 8 +2721 2 +1557 4 +901 1 +3999 8 +463 2 +338 1 +975 7 +2213 9 +3579 4 +1871 3 +2407 6 +2121 5 +1883 9 +2673 2 +932 10 +1189 8 +55 9 +3505 2 +1278 10 +3984 1 +138 8 +3847 4 +44 9 +1128 8 +524 8 +3695 8 +858 8 +3998 9 +692 4 +3851 5 +1613 10 +3202 4 +2119 4 +1521 1 +2611 7 +3324 6 +426 1 +1362 1 +1218 7 +1994 6 +3575 6 +1661 8 +64 2 +3758 10 +2322 9 +3765 3 +596 1 +342 4 +2811 9 +166 6 +3821 8 +2317 7 +1582 3 +3898 2 +388 8 +403 4 +2876 4 +3466 9 +1479 2 +2638 10 +778 1 +2175 5 +26 1 +658 3 +590 2 +1065 6 +4014 1 +3093 8 +3340 1 +3835 6 +1366 5 +2207 2 +3634 10 +284 1 +1490 5 +2578 5 +574 10 +3098 5 +2438 6 +739 4 +350 8 +3544 9 +657 7 +2999 1 +2611 10 +2105 8 +3416 7 +952 4 +3886 3 +3437 2 +1740 6 +3627 4 +2275 7 +2992 8 +974 9 +3900 8 +4 10 +3258 5 +1439 9 +3007 6 +1782 4 +1625 8 +414 1 +1805 4 +2885 9 +363 10 +2635 8 +715 6 +87 3 +2050 1 +513 1 +2020 10 +2294 4 +3713 3 +3611 8 +640 7 +2474 6 +782 2 +432 3 +2424 9 +2661 6 +919 8 +2453 7 +1694 8 +560 10 +1311 5 +3812 8 +1185 6 +3277 8 +2681 3 +3695 8 +2804 10 +836 2 +2331 7 +799 5 +2602 3 +119 9 +467 5 +3483 4 +706 4 +2544 8 +2491 10 +2124 6 +3472 5 +2085 10 +3649 1 +1534 2 +1163 7 +2186 9 +1385 7 +914 4 +2603 8 +950 4 +3991 4 +1647 1 +2278 8 +385 5 +2320 3 +3261 8 +2689 7 +915 4 +1615 2 +2722 4 +1011 4 +882 1 +2544 7 +3906 3 +102 1 +3270 2 +2172 8 +461 10 +1626 3 +16 4 +686 6 +838 1 +2327 4 +299 2 +1070 3 +3076 7 +2740 3 +1730 7 +3560 8 +3786 2 +977 4 +520 2 +2333 8 +835 7 +3915 3 +876 3 +273 4 +2967 7 +1563 8 +1852 8 +3721 3 +3859 8 +1528 1 +1475 8 +3293 9 +3165 8 +3501 9 +2396 3 +3608 9 +2272 6 +2165 8 +3257 9 +2610 4 +1163 1 +3509 3 +1916 3 +3182 3 +2371 4 +2451 1 +3350 1 +2898 3 +2300 5 +1668 3 +2103 10 +1699 6 +601 5 +1613 2 +1192 5 +2242 5 +1992 4 +1000 2 +941 10 +1213 10 +3913 1 +3555 2 +1632 8 +2423 2 +227 8 +764 3 +2619 7 +3879 5 +179 1 +3913 9 +2466 4 +535 4 +2936 7 +1864 8 +2765 7 +3059 4 +1189 4 +2223 3 +2341 5 +2939 2 +3941 6 +3223 9 +1994 9 +3308 1 +3122 9 +1325 5 +1739 3 +1566 10 +50 6 +695 10 +2593 9 +13 3 +1030 4 +2702 10 +1909 9 +779 6 +3447 3 +3263 1 +1277 9 +1509 1 +3466 7 +2193 7 +1238 10 +482 1 +1026 2 +3504 5 +43 7 +1116 6 +3103 10 +3342 9 +3338 2 +727 9 +623 10 +831 9 +97 3 +926 3 +3812 1 +3470 8 +266 7 +3445 8 +2394 3 +979 7 +1050 4 +2067 2 +3617 3 +412 2 +1346 7 +3277 10 +548 1 +80 5 +3596 9 +3072 1 +2583 5 +1878 4 +307 3 +225 8 +920 8 +3260 5 +3237 4 +1813 3 +337 7 +85 3 +2357 8 +2327 4 +369 10 +924 10 +4089 1 +2310 9 +3379 2 +591 1 +2988 5 +1490 6 +4028 5 +538 7 +168 4 +2168 4 +350 9 +3798 2 +535 1 +1859 4 +2186 8 +4011 5 +3635 6 +1262 1 +2529 4 +1050 6 +2014 9 +2269 6 +3534 10 +2635 8 +1490 4 +979 4 +2981 4 +3493 9 +3085 2 +107 3 +3336 8 +270 3 +1920 8 +1398 1 +1968 4 +1477 1 +244 6 +3898 1 +1176 2 +1237 7 +3657 4 +3846 1 +3963 1 +1973 9 +223 8 +2640 8 +2148 8 +3957 8 +1940 6 +391 6 +2694 5 +2599 10 +2327 6 +1905 10 +762 5 +1770 1 +1145 4 +833 9 +420 1 +970 3 +551 4 +919 2 +1839 6 +2596 4 +991 10 +1659 10 +1917 10 +1809 5 +1835 5 +197 7 +1199 5 +120 6 +1531 1 +1847 3 +3539 7 +1262 5 +1683 8 +5 1 +3279 6 +1075 1 +199 5 +3986 7 +1648 9 +3929 9 +1898 1 +3873 5 +3550 5 +2803 7 +2429 8 +1000 5 +2265 9 +460 2 +2657 1 +687 3 +61 2 +1399 9 +1496 8 +952 3 +3675 7 +3212 1 +1912 7 +3953 2 +1041 8 +1579 10 +2090 5 +2472 10 +2296 6 +1064 8 +534 6 +669 1 +445 3 +2713 5 +1119 8 +1021 6 +3815 2 +2857 2 +2602 3 +3713 9 +2803 2 +3275 8 +959 5 +1625 9 +2189 4 +248 6 +2983 7 +3182 4 +696 2 +3458 6 +2456 10 +314 5 +3712 7 +2531 3 +3989 3 +1422 5 +1620 7 +170 4 +3562 5 +2963 7 +2518 7 +3555 2 +729 7 +3397 7 +245 7 +200 2 +169 10 +2027 8 +313 2 +386 6 +1107 3 +133 3 +323 3 +1767 2 +1878 8 +2341 2 +2469 2 +3722 4 +497 6 +1572 8 +3332 5 +3172 6 +1846 7 +3105 5 +2239 10 +3140 5 +2168 9 +1318 3 +3639 10 +1989 9 +1165 3 +2288 3 +1654 9 +1272 5 +1434 2 +1465 3 +378 5 +2543 8 +3443 7 +2578 6 +1590 5 +3397 6 +457 10 +2220 8 +3763 7 +3461 5 +87 9 +2351 3 +2952 6 +4072 1 +1095 1 +1502 6 +1006 9 +2466 1 +3924 10 +3303 5 +3884 1 +332 10 +1288 4 +331 3 +1055 1 +3754 5 +2886 8 +2959 8 +4087 6 +2734 2 +1949 10 +1009 4 +4041 4 +1906 3 +1317 7 +363 1 +1212 9 +3142 3 +1817 5 +2246 10 +3563 5 +2756 5 +63 9 +3101 4 +3782 7 +2576 7 +3221 10 +1074 7 +1683 5 +3955 2 +3645 8 +1078 2 +4021 4 +968 6 +4093 4 +1355 2 +2889 8 +1407 4 +2986 7 +864 4 +1861 6 +2654 2 +3886 1 +1707 4 +2580 10 +751 9 +750 10 +445 8 +1055 6 +2636 1 +193 6 +2010 8 +2950 3 +3717 1 +2744 6 +450 2 +3456 10 +3531 9 +3257 10 +2757 10 +1168 6 +4041 5 +1529 9 +3601 5 +2412 7 +2878 10 +3562 3 +185 5 +2563 8 +1384 7 +513 6 +1563 3 +681 2 +1639 3 +2177 1 +2432 6 +1291 1 +3617 6 +2337 7 +2274 7 +288 6 +3436 5 +3898 2 +56 7 +215 10 +2701 7 +3097 9 +855 1 +1753 5 +1794 10 +2737 4 +3033 7 +2635 3 +1103 7 +4051 5 +2734 3 +2594 8 +3391 4 +1836 10 +3074 1 +418 10 +3174 6 +5 5 +1850 8 +1737 7 +2913 2 +3168 10 +3044 9 +935 5 +3529 1 +3447 10 +658 4 +2834 5 +3690 9 +988 6 +1784 6 +2519 3 +690 7 +2426 4 +3790 9 +2893 10 +3717 3 +3165 6 +1435 9 +3512 10 +3094 6 +2585 6 +586 1 +1464 1 +2347 8 +2402 3 +4045 6 +88 2 +3054 2 +1431 6 +3923 1 +4063 4 +1475 5 +4034 9 +2639 9 +3836 8 +2603 1 +3079 9 +1162 5 +902 8 +3504 9 +3122 10 +1886 10 +1466 2 +512 7 +2840 8 +1431 4 +2923 9 +1925 1 +219 4 +1482 3 +1919 5 +662 10 +308 10 +2537 2 +3087 1 +1711 6 +2778 6 +530 1 +2722 4 +1949 1 +1259 4 +3334 7 +3745 3 +2895 8 +3042 7 +2625 10 +1071 3 +3360 1 +1526 7 +1847 5 +1362 2 +4024 1 +1717 2 +105 5 +3761 3 +3243 8 +346 2 +2754 8 +3591 1 +3572 9 +414 1 +969 1 +2714 9 +3558 3 +2297 5 +1720 4 +3720 8 +3150 4 +4073 8 +3303 2 +2692 1 +3429 5 +701 7 +170 6 +2121 2 +502 7 +2172 1 +3261 4 +1617 6 +2151 6 +778 10 +2683 1 +2626 8 +2822 3 +1594 8 +1728 3 +3762 10 +1846 4 +1900 2 +3599 10 +528 5 +1458 2 +44 3 +1305 8 +1733 5 +88 9 +1782 8 +3755 1 +1702 2 +4083 10 +3911 9 +3894 7 +3036 2 +1522 4 +3683 10 +1559 8 +687 1 +1649 2 +283 9 +3725 1 +1026 9 +234 9 +549 9 +1874 1 +3716 6 +2385 8 +1511 7 +340 10 +329 4 +3227 4 +3500 4 +3021 8 +3928 9 +3675 10 +2745 10 +4024 9 +104 10 +4067 7 +2514 4 +1982 2 +1922 8 +2539 9 +3064 2 +1065 6 +2145 4 +2365 8 +679 3 +631 10 +3391 3 +2604 3 +3610 4 +3968 5 +600 4 +922 1 +802 1 +1838 9 +3124 4 +2142 8 +1262 10 +1685 3 +2353 10 +2134 5 +525 3 +1139 4 +2110 8 +1900 8 +1330 8 +1132 5 +1346 3 +2477 3 +297 4 +2994 9 +709 1 +705 10 +3144 2 +659 6 +3842 1 +355 9 +1783 9 +1655 8 +833 6 +1879 7 +1793 9 +840 2 +2880 7 +1100 8 +1240 5 +28 3 +524 4 +3320 2 +3918 10 +3232 10 +3721 4 +2752 1 +3469 9 +119 6 +40 3 +1196 2 +153 7 +1412 1 +1023 4 +2199 6 +4020 1 +3339 1 +267 3 +534 5 +1809 10 +443 1 +3047 4 +1530 5 +999 9 +187 3 +682 6 +2101 1 +231 8 +1843 9 +4 7 +1252 7 +2628 6 +2873 7 +3224 9 +3350 2 +2356 3 +3838 10 +2271 8 +154 6 +4091 1 +1366 3 +1692 8 +255 6 +3856 3 +1769 9 +937 4 +2600 4 +1079 10 +2209 4 +1333 4 +838 6 +1543 3 +1424 4 +3972 3 +1069 10 +3741 6 +2895 4 +3091 6 +416 8 +2310 1 +3449 5 +980 1 +1137 4 +3295 1 +2537 10 +358 10 +1877 6 +3183 9 +729 9 +1705 10 +1596 8 +3885 9 +3740 2 +3226 9 +1116 5 +3267 8 +1188 10 +2489 8 +3964 10 +2518 5 +1513 7 +1431 6 +1797 3 +1423 9 +921 10 +3562 2 +1955 10 +1122 7 +3990 3 +3960 5 +1562 4 +1258 4 +490 4 +2236 2 +3664 4 +1782 6 +2973 3 +2473 6 +273 9 +784 9 +2434 2 +494 8 +1196 7 +1416 10 +1631 1 +518 9 +1756 9 +3957 7 +1900 4 +2754 9 +3777 1 +53 10 +2003 5 +4001 8 +268 1 +3237 7 +808 4 +595 5 +1617 1 +1093 1 +2162 10 +2289 8 +134 8 +1671 1 +758 2 +698 4 +1203 9 +1715 8 +2787 5 +3170 4 +3987 8 +4067 10 +1519 7 +2314 4 +1213 2 +3345 2 +3304 1 +3792 9 +3340 5 +2579 6 +307 9 +1753 6 +3547 10 +1761 3 +2886 3 +3110 10 +1389 10 +961 4 +2207 3 +2827 4 +362 4 +816 1 +127 6 +2450 10 +3879 5 +3620 9 +472 2 +946 5 +1408 8 +2322 1 +762 5 +3162 3 +1389 8 +781 6 +1851 3 +3896 10 +790 3 +3365 2 +2820 8 +3210 5 +2584 9 +626 3 +298 2 +1770 1 +219 2 +2076 1 +3885 3 +65 6 +326 6 +4068 3 +2359 7 +1967 10 +3458 8 +2498 5 +3206 6 +1216 1 +196 2 +218 6 +1272 3 +1691 10 +2849 10 +3830 7 +1267 7 +3000 1 +1946 8 +3059 8 +3379 3 +2818 10 +1316 1 +3641 7 +16 4 +633 1 +3907 6 +610 10 +2836 2 +2250 7 +3507 6 +389 9 +3438 2 +1448 7 +1073 9 +3074 8 +3004 1 +3705 6 +3537 2 +2689 8 +2070 8 +2138 7 +2334 3 +3404 2 +1043 1 +3487 2 +908 5 +276 3 +2628 4 +794 3 +2567 2 +135 7 +1559 5 +3642 1 +3973 4 +2905 4 +48 6 +1530 5 +3659 6 +3210 1 +2520 9 +871 1 +1138 3 +1548 3 +336 2 +3684 1 +248 8 +1258 10 +3858 1 +100 8 +3501 10 +3897 10 +295 6 +634 3 +4079 10 +484 5 +1548 7 +3748 9 +1562 3 +0 7 +2139 7 +4024 2 +3352 6 +2749 3 +791 3 +365 3 +3835 10 +2872 6 +2305 4 +938 8 +207 10 +2934 2 +1847 1 +3662 5 +31 10 +3231 7 +2673 2 +1268 10 +2885 5 +912 10 +1940 4 +3632 6 +690 1 +1182 3 +1392 6 +2486 4 +2463 4 +1059 3 +1403 1 +2056 2 +1248 10 +649 7 +1937 5 +3522 6 +3588 9 +3004 4 +1324 5 +1440 10 +694 9 +325 6 +2231 3 +1159 9 +2821 7 +351 4 +1955 6 +3836 4 +142 9 +3406 8 +3108 7 +2828 4 +2230 1 +3395 10 +1428 6 +3546 2 +1741 9 +2505 3 +869 8 +2601 4 +2991 10 +2413 5 +1260 3 +3700 9 +1916 6 +3677 5 +2240 8 +663 8 +1068 1 +151 9 +2250 8 +1435 6 +3274 10 +3595 1 +939 1 +3649 4 +3862 1 +3945 1 +1515 1 +4066 3 +3597 2 +509 2 +3024 1 +2732 1 +2575 3 +1563 2 +3899 1 +251 8 +3423 8 +1755 5 +222 1 +2286 1 +3037 3 +3884 2 +3108 4 +560 4 +1031 4 +2828 10 +3025 1 +3672 8 +2637 5 +2769 10 +2879 10 +2525 10 +950 8 +3348 9 +3913 3 +1365 8 +583 6 +2070 5 +2147 6 +3622 7 +2350 10 +1 1 +2998 1 +3268 6 +2171 5 +2428 5 +1500 4 +4086 2 +3881 9 +2854 1 +2452 7 +1137 5 +1811 2 +3475 7 +573 4 +499 5 +3365 2 +1496 3 +620 7 +1178 9 +471 7 +3491 9 +3427 4 +3926 2 +1732 3 +3207 3 +3701 8 +3904 6 +584 3 +2269 3 +1809 8 +198 9 +2839 1 +2380 3 +3147 4 +3633 4 +3938 5 +422 1 +2110 7 +938 10 +2953 3 +2375 9 +2152 10 +2116 7 +3214 1 +3381 9 +3935 9 +749 10 +93 5 +375 2 +3235 7 +2273 5 +661 6 +1081 6 +2591 10 +2980 4 +3576 9 +2685 6 +89 7 +3791 5 +1324 3 +799 7 +3817 2 +3597 8 +2069 8 +1208 5 +181 9 +2470 4 +305 3 +3769 7 +684 7 +3530 1 +3045 6 +1786 10 +2674 10 +3354 3 +1024 7 +3725 10 +2067 4 +3786 6 +2834 3 +1481 9 +1026 8 +433 6 +891 9 +2960 9 +2241 2 +3283 10 +3755 5 +3801 2 +2694 8 +2519 8 +3572 8 +929 8 +1920 1 +1490 6 +2965 10 +2134 6 +4094 9 +1676 6 +3291 2 +1468 6 +2697 4 +2374 2 +2226 10 +3168 1 +1341 10 +2267 5 +383 8 +1830 9 +516 5 +3775 6 +2244 5 +1994 8 +322 10 +931 4 +1239 1 +3771 3 +1065 3 +2158 1 +302 9 +1232 2 +27 5 +2198 5 +1175 3 +259 7 +1041 6 +441 9 +2057 6 +4025 7 +2997 6 +2612 3 +1795 10 +1736 6 +470 8 +2139 10 +2292 5 +3877 5 +2182 9 +522 6 +414 4 +3480 9 +2813 6 +3846 9 +2364 8 +3167 1 +3545 5 +91 10 +3297 3 +1043 5 +1361 6 +3509 10 +169 6 +487 9 +4011 2 +2829 3 +2796 7 +834 7 +1501 6 +2302 2 +678 3 +406 5 +2282 9 +1730 10 +3180 7 +2823 9 +1364 2 +2150 1 +568 9 +504 10 +3665 1 +667 1 +2582 8 +3717 9 +1298 4 +3866 6 +2818 8 +2768 5 +1045 6 +3522 3 +1155 5 +2573 7 +4050 4 +1652 1 +1452 5 +436 5 +3847 3 +3607 4 +3792 10 +97 4 +1770 3 +1013 2 +1344 7 +522 2 +2092 10 +920 10 +22 4 +1869 5 +2956 3 +963 7 +783 7 +612 1 +1417 10 +2938 2 +2513 1 +3969 8 +1965 8 +3341 3 +963 6 +2776 2 +776 6 +3961 10 +1083 5 +352 1 +2796 2 +2380 3 +3073 1 +1922 8 +3254 4 +1611 1 +2675 9 +2014 9 +1642 6 +209 2 +1987 4 +3961 2 +2989 4 +228 2 +3609 6 +3115 2 +1281 10 +1868 7 +3282 9 +105 5 +2738 3 +2689 10 +1562 5 +787 3 +287 6 +1355 1 +2487 4 +2232 8 +444 8 +2134 5 +1247 8 +1801 3 +2057 1 +1704 2 +3722 8 +3354 6 +3517 7 +1958 8 +2941 5 +341 4 +842 6 +648 9 +3942 8 +3992 1 +3825 3 +2476 9 +3122 9 +2830 9 +3434 10 +3584 6 +1944 5 +1334 5 +2300 9 +676 7 +744 7 +3021 8 +868 8 +2813 4 +82 9 +492 1 +1642 1 +3024 1 +2654 5 +727 8 +3168 1 +930 7 +2031 1 +1202 6 +1500 9 +1101 4 +1638 8 +2348 8 +1172 3 +1112 9 +1455 10 +361 7 +169 5 +2766 8 +1046 2 +3022 5 +3446 4 +2985 2 +2579 6 +1243 8 +2563 9 +3524 9 +1332 3 +872 5 +3511 7 +3603 7 +67 1 +3095 2 +1451 6 +2152 9 +1188 6 +155 1 +2701 10 +2184 9 +1547 7 +3630 1 +111 9 +1875 5 +1778 8 +789 9 +1594 5 +2222 2 +682 7 +25 3 +1114 7 +3784 10 +1524 10 +2182 9 +1933 8 +2809 3 +1038 9 +1370 5 +1205 9 +435 10 +3227 7 +1956 9 +1989 8 +3017 10 +1766 5 +19 3 +3860 5 +1692 10 +1392 5 +1466 6 +536 2 +3076 2 +682 6 +123 7 +1928 10 +1195 5 +1706 10 +1416 3 +2377 3 +2701 2 +2497 4 +2006 4 +4042 7 +3047 10 +2885 4 +787 5 +3125 10 +3153 1 +2396 8 +4022 2 +68 3 +471 9 +1151 2 +2424 10 +2315 10 +2647 6 +923 7 +1568 3 +1455 3 +1732 2 +1619 8 +2236 10 +3652 2 +921 3 +435 6 +520 8 +3827 10 +3811 9 +1808 2 +3463 1 +2904 1 +46 6 +3775 9 +1976 7 +1712 4 +180 2 +3792 4 +20 1 +217 4 +1728 2 +1379 6 +2227 7 +319 8 +4018 6 +672 5 +1396 6 +3473 8 +899 9 +801 2 +1054 10 +2683 10 +2972 4 +1341 2 +1574 2 +2958 9 +670 6 +2150 5 +3907 8 +2075 6 +209 3 +222 6 +1025 1 +1429 8 +1835 2 +138 10 +1879 10 +3717 2 +954 10 +1109 2 +1252 7 +2263 9 +1175 3 +2932 7 +1711 3 +2417 8 +2768 3 +3771 3 +60 5 +636 9 +4044 10 +3915 7 +3548 3 +1739 9 +3539 1 +996 10 +3690 2 +200 1 +944 3 +1825 2 +2821 1 +1539 3 +3258 4 +2918 2 +3429 5 +1695 6 +3019 7 +888 5 +1786 4 +1168 10 +2416 4 +930 9 +3907 1 +784 8 +1125 6 +3627 3 +1924 6 +100 1 +505 8 +1406 10 +1392 1 +2097 3 +1945 2 +3977 9 +3696 1 +3151 6 +1128 8 +1013 8 +3398 10 +3087 1 +3777 3 +1149 8 +463 6 +2299 6 +324 5 +1905 4 +2079 4 +3758 1 +900 4 +2406 7 +1115 9 +19 9 +502 6 +1055 4 +1612 6 +3175 10 +502 10 +952 2 +1090 10 +3677 8 +2921 3 +201 10 +934 2 +687 1 +697 6 +658 10 +1937 9 +1498 6 +3684 5 +2529 7 +2345 6 +2650 5 +756 9 +3051 7 +1827 5 +2805 3 +429 3 +1311 2 +1630 1 +906 10 +3972 2 +2267 9 +2787 3 +2854 8 +969 8 +3208 5 +1617 7 +1257 2 +2686 1 +3185 1 +624 4 +2806 1 +3 9 +2281 10 +1088 7 +3706 8 +86 3 +2751 6 +419 8 +934 4 +735 7 +1050 4 +2650 8 +2974 7 +3507 2 +3378 3 +655 3 +3938 10 +3890 5 +2810 6 +107 1 +402 10 +102 3 +2569 10 +1917 4 +2016 8 +484 1 +849 7 +2184 2 +2664 2 +1443 1 +620 5 +232 7 +1912 2 +3987 3 +2452 10 +1971 3 +3443 3 +1406 3 +1527 8 +3127 9 +3006 2 +1573 8 +2734 6 +2642 6 +3673 4 +3856 7 +1311 9 +3227 3 +2793 10 +104 9 +275 4 +3607 6 +236 10 +1099 5 +2699 9 +1543 3 +3014 4 +2147 10 +263 5 +2195 7 +2457 1 +3089 9 +633 7 +5 8 +1026 7 +1727 6 +3000 7 +2407 7 +2481 4 +969 1 +790 4 +2650 8 +2250 6 +3364 4 +2342 6 +2125 1 +3487 5 +3962 8 +775 10 +120 3 +2409 7 +1693 1 +730 7 +2123 3 +1081 3 +3430 7 +1039 1 +136 5 +1774 1 +1909 6 +3608 2 +2798 9 +2919 10 +1248 10 +3346 3 +1630 4 +2171 8 +3063 10 +2248 7 +446 3 +1885 5 +2906 9 +840 2 +3376 5 +950 7 +1795 7 +3019 7 +3991 5 +3399 2 +2402 8 +1872 9 +2271 9 +2391 4 +3594 3 +3902 1 +2192 10 +759 2 +2296 7 +1765 10 +380 10 +3552 2 +2086 2 +500 9 +1761 10 +3501 4 +3029 1 +89 4 +1115 7 +1058 10 +189 9 +3543 9 +2984 10 +4076 3 +3110 5 +469 4 +736 5 +3463 1 +2013 10 +3046 4 +3498 2 +1238 1 +522 1 +2127 8 +978 4 +729 1 +377 3 +386 7 +1383 9 +2361 4 +2909 3 +2145 2 +1077 10 +2420 9 +1968 5 +2732 6 +3160 9 +1420 7 +1166 4 +3797 4 +3500 1 +1842 5 +3906 4 +1545 1 +659 7 +1255 8 +2148 5 +2412 5 +4032 9 +3519 7 +2829 3 +3433 4 +1189 8 +2520 9 +699 10 +2471 1 +1493 5 +3088 5 +672 9 +2447 10 +2021 10 +3618 1 +427 8 +1215 8 +1756 1 +1354 8 +1478 4 +991 3 +586 10 +3611 2 +2232 7 +3246 3 +3589 5 +2253 1 +1119 3 +781 1 +2485 6 +2108 7 +3947 10 +2229 6 +868 1 +2127 8 +2896 3 +920 7 +4081 4 +3772 5 +568 6 +1216 3 +3173 4 +1450 3 +4033 1 +2249 1 +3957 10 +3035 1 +1729 1 +3325 5 +1007 10 +2506 3 +3994 2 +823 5 +3192 6 +86 3 +386 3 +4008 1 +2620 4 +1866 2 +3206 3 +3073 10 +825 1 +35 8 +2494 7 +1293 10 +3960 2 +1139 4 +2794 1 +33 6 +115 4 +957 5 +293 3 +2879 8 +309 6 +2931 1 +2406 4 +97 8 +2860 8 +1381 1 +3990 5 +1016 4 +1753 3 +871 4 +3896 7 +930 5 +1331 10 +223 3 +1192 9 +1507 4 +3316 9 +2379 4 +803 1 +1127 3 +2200 9 +1403 2 +3959 9 +926 6 +1050 1 +3988 7 +245 3 +3801 7 +2001 9 +516 6 +1583 8 +3727 7 +1131 5 +722 1 +181 6 +3062 2 +2831 9 +75 3 +1255 4 +2148 5 +573 9 +1622 1 +3778 8 +765 8 +1693 4 +758 4 +2215 9 +2774 2 +2932 1 +1038 10 +992 9 +1914 2 +1493 7 +713 10 +1508 6 +3977 8 +3845 8 +895 10 +2137 3 +1989 6 +3691 7 +1555 4 +2778 4 +1204 3 +2078 8 +2235 9 +956 5 +3698 10 +1343 8 +3365 5 +644 10 +4054 8 +2758 8 +1965 6 +857 6 +1702 9 +2673 2 +1519 8 +1494 4 +747 3 +631 1 +2729 9 +859 7 +1461 7 +3917 1 +2298 10 +3868 4 +1318 10 +2140 5 +2033 7 +1176 8 +2504 1 +2810 4 +2413 8 +1947 7 +3616 10 +2610 4 +738 2 +3708 8 +1749 5 +807 1 +412 6 +562 4 +1296 2 +666 1 +3297 10 +3071 1 +3072 10 +1305 7 +492 9 +88 10 +253 10 +2293 7 +3578 9 +3010 3 +1103 6 +806 2 +1956 8 +1767 7 +3676 9 +3808 10 +1456 10 +1549 1 +3459 6 +2544 6 +3331 5 +3148 4 +3730 1 +1873 2 +3367 2 +14 4 +1136 7 +3946 9 +1644 3 +2633 6 +4002 3 +930 3 +4034 7 +3655 4 +2217 10 +1375 8 +848 8 +2156 9 +1357 10 +2487 10 +818 7 +2854 5 +338 2 +1786 7 +48 10 +952 6 +478 2 +4026 5 +2973 1 +2365 10 +1676 3 +101 9 +3287 10 +3129 1 +50 6 +2367 5 +329 7 +2130 1 +3216 8 +2411 9 +718 9 +119 9 +1261 2 +2742 4 +2537 7 +2015 3 +568 9 +1695 1 +1033 4 +1387 1 +377 2 +769 9 +3557 7 +3682 4 +2298 10 +2092 8 +2861 9 +4058 9 +3866 8 +2392 5 +730 5 +1367 4 +1270 6 +1394 4 +1280 7 +3716 9 +3628 2 +3724 3 +2152 5 +3150 7 +1816 4 +3361 7 +3881 2 +2687 3 +1196 8 +520 1 +1285 5 +122 3 +1325 8 +2277 7 +1756 2 +1950 4 +943 5 +3063 9 +3271 5 +667 1 +1585 4 +1869 6 +3748 1 +1021 4 +2974 2 +3761 4 +2004 6 +2236 7 +103 4 +3308 3 +3345 7 +1268 9 +3402 9 +2054 5 +3611 7 +1457 8 +2644 5 +3963 1 +460 1 +4003 5 +1750 4 +772 8 +148 2 +543 9 +3123 5 +1880 10 +2289 10 +3171 10 +2273 10 +3375 3 +2209 6 +2851 2 +1316 3 +3785 6 +3668 8 +678 4 +3604 7 +3133 10 +1967 5 +254 6 +2175 9 +2619 10 +3425 8 +1921 2 +1895 7 +2781 7 +747 5 +3027 8 +1582 10 +2156 2 +1705 2 +142 10 +2922 9 +87 9 +2535 6 +2624 3 +2596 3 +3152 3 +1758 1 +1642 5 +1274 5 +2318 3 +2609 9 +1795 10 +993 8 +839 7 +700 10 +2971 2 +3278 1 +3266 1 +2900 4 +1841 5 +2338 4 +2353 7 +2718 8 +2117 4 +955 7 +1663 2 +2930 8 +1405 8 +1751 1 +1847 5 +2888 5 +619 2 +1495 10 +1827 3 +2583 4 +4059 2 +2441 10 +471 8 +3001 5 +489 6 +2922 8 +3143 1 +1190 9 +235 1 +3849 8 +1391 9 +2917 8 +3836 9 +3760 3 +878 4 +1067 9 +3887 7 +2617 9 +2885 6 +1647 5 +776 9 +1986 9 +2081 1 +3772 4 +2516 3 +2760 10 +65 9 +942 2 +223 9 +3817 9 +977 7 +1654 5 +2963 7 +2599 7 +1756 8 +1715 10 +947 2 +1532 6 +65 6 +3133 10 +583 4 +2094 4 +724 9 +2191 10 +1467 10 +3013 9 +1477 3 +382 9 +1461 1 +3658 7 +2626 9 +3200 1 +3371 6 +4079 5 +3058 3 +605 6 +2811 7 +3553 1 +1942 7 +3466 4 +940 7 +660 8 +2888 5 +3090 6 +1810 2 +2963 1 +3239 7 +2303 3 +1670 10 +496 7 +211 3 +1320 5 +3672 10 +2720 2 +3976 4 +1718 7 +3166 5 +3829 1 +215 6 +2918 9 +472 10 +2736 2 +794 1 +2494 1 +1493 3 +261 6 +1956 3 +146 6 +928 9 +3493 10 +2533 8 +1941 9 +2098 1 +4090 2 +1157 5 +3283 5 +2744 1 +1239 9 +3837 2 +1011 2 +1635 5 +30 9 +1449 5 +3137 2 +3188 8 +3621 6 +1270 9 +148 9 +1486 8 +3255 1 +1833 8 +3170 5 +1359 3 +3614 6 +926 8 +3692 6 +174 8 +3870 8 +3559 9 +1444 3 +1781 8 +994 2 +839 3 +1880 6 +3972 4 +1959 4 +1299 7 +3647 2 +2337 1 +1985 4 +1648 7 +705 1 +1994 6 +1005 5 +811 1 +3310 7 +464 5 +424 6 +385 10 +653 5 +1669 3 +3109 4 +875 8 +1144 2 +954 10 +1703 5 +327 1 +3600 8 +3006 1 +519 6 +1298 8 +3093 5 +1932 3 +1953 7 +10 6 +3606 1 +2383 3 +2947 9 +3537 3 +2803 7 +2514 4 +775 5 +3214 4 +1961 8 +366 3 +1582 9 +1287 6 +2457 3 +1072 2 +2354 4 +2110 3 +1718 8 +1585 6 +3362 7 +875 1 +114 3 +179 6 +174 4 +1479 3 +2347 7 +1574 6 +131 8 +2819 1 +4066 6 +554 5 +3660 1 +3713 8 +1722 4 +2032 7 +4040 4 +2327 1 +3218 9 +2304 4 +1208 2 +1272 7 +3973 2 +2546 8 +1244 7 +167 10 +1252 9 +4012 8 +1738 4 +3182 2 +3331 7 +1971 5 +2011 2 +60 7 +2230 6 +311 9 +3097 3 +3544 1 +396 1 +1450 5 +1281 9 +3761 1 +1315 8 +775 8 +3120 7 +683 1 +2369 7 +245 4 +40 1 +3887 5 +648 6 +3911 8 +1811 9 +2978 10 +2214 6 +1200 3 +662 10 +3517 5 +1484 9 +2694 1 +1649 4 +3097 1 +3759 7 +3353 7 +2757 5 +2043 8 +2335 7 +2178 8 +266 5 +2378 3 +3650 3 +3902 10 +3780 2 +442 3 +1348 5 +3576 4 +3674 1 +5 6 +2134 10 +525 1 +2398 8 +667 6 +1302 3 +2670 4 +3730 7 +3069 1 +1588 8 +2017 3 +3600 5 +847 1 +1333 5 +167 7 +1901 7 +3950 6 +1703 2 +2472 10 +2305 7 +3644 10 +838 9 +3468 2 +1665 7 +1863 2 +2069 10 +803 1 +2941 10 +3930 6 +1134 3 +112 4 +1901 7 +2829 9 +4032 2 +3564 7 +2334 4 +860 3 +549 1 +1721 5 +2537 1 +2876 7 +93 1 +2836 5 +2078 3 +70 5 +722 3 +623 1 +3732 8 +2760 8 +3092 8 +3557 5 +1105 7 +2407 1 +2697 7 +3798 6 +1644 9 +1985 8 +3751 6 +3006 3 +28 9 +2503 3 +3489 10 +14 5 +2102 7 +2773 7 +835 5 +858 7 +3046 6 +2470 7 +2434 4 +784 8 +2623 8 +1409 9 +1491 6 +1584 4 +477 7 +3550 2 +3638 7 +3988 7 +970 8 +1608 4 +2364 3 +2241 4 +3477 3 +3306 1 +1007 9 +3152 7 +1584 1 +1692 1 +3136 7 +1298 9 +1255 1 +1786 3 +300 7 +3535 9 +910 8 +3595 3 +826 1 +2153 8 +556 6 +1466 8 +2361 3 +3294 7 +1322 2 +2067 8 +252 9 +1180 7 +2591 9 +1597 7 +2285 10 +1746 10 +1650 7 +549 2 +626 8 +3492 6 +331 5 +2286 5 +3405 7 +2605 10 +3475 7 +4 10 +2768 8 +1310 6 +1797 3 +589 3 +1515 5 +3233 9 +2344 7 +2541 2 +1787 7 +4045 7 +2420 1 +1966 4 +1472 2 +1069 1 +1283 7 +858 7 +596 4 +976 10 +1710 7 +333 1 +1013 7 +4034 1 +539 7 +4080 5 +3437 8 +2147 2 +159 6 +2971 3 +2139 9 +1591 8 +53 6 +2390 5 +1148 4 +2909 2 +1482 3 +3832 4 +525 2 +2189 3 +2575 4 +1690 7 +3861 10 +3784 7 +1114 4 +2781 2 +1732 8 +128 6 +1399 2 +3284 2 +2348 3 +3542 9 +1330 9 +1386 4 +1547 7 +2263 4 +1135 6 +1884 1 +3998 5 +1497 7 +2167 3 +368 1 +2138 3 +4037 5 +2597 9 +2724 3 +2630 4 +1723 1 +1748 8 +2450 2 +3249 4 +1424 1 +3584 8 +4089 8 +2332 3 +2750 2 +1749 4 +3349 2 +1757 2 +519 5 +638 10 +294 7 +368 3 +3166 8 +1629 3 +1503 10 +3487 6 +2064 8 +3065 8 +745 5 +291 7 +3601 6 +1104 1 +3720 10 +2689 8 +639 9 +637 10 +3459 6 +684 5 +157 1 +2870 2 +3527 10 +2917 4 +808 8 +3481 3 +3827 7 +2632 10 +1721 7 +3048 8 +680 1 +80 8 +439 2 +2997 9 +2375 5 +3000 7 +23 3 +1671 6 +1170 5 +2412 4 +1315 3 +1559 5 +3466 3 +128 9 +2235 4 +1234 8 +130 7 +2290 5 +1172 3 +988 4 +3293 6 +3955 5 +3742 2 +3341 5 +1981 3 +3863 1 +1455 5 +3057 2 +2747 2 +894 10 +506 9 +3800 3 +3837 1 +3078 5 +1080 2 +2605 8 +2867 3 +2190 8 +3406 10 +1964 3 +1570 3 +3135 6 +273 2 +3114 8 +556 9 +3506 8 +3403 4 +1560 3 +1661 2 +2350 8 +401 2 +800 10 +3005 1 +3493 1 +1726 2 +3423 10 +2471 7 +2887 5 +3444 8 +3666 6 +315 5 +1658 6 +1531 8 +1046 8 +3627 6 +3978 7 +3622 4 +1222 3 +2234 8 +2044 3 +178 2 +783 10 +1162 4 +3791 1 +2718 2 +3112 9 +2532 1 +1030 5 +1084 6 +805 10 +4067 2 +2768 2 +1309 5 +3937 1 +3020 3 +3393 5 +2259 4 +2650 2 +2210 7 +3125 1 +2915 6 +2796 9 +2357 1 +2228 7 +3486 3 +1937 6 +2562 7 +2534 5 +3545 9 +390 8 +695 7 +320 10 +2230 7 +764 4 +1925 6 +2854 7 +1803 7 +2432 5 +44 6 +763 9 +1233 9 +3689 4 +2286 9 +1247 3 +2391 4 +3349 6 +541 3 +3030 5 +2707 9 +2244 5 +2029 7 +3454 3 +1038 6 +2677 7 +3681 6 +2450 6 +2275 8 +1788 6 +3029 6 +2 3 +3667 1 +2126 5 +310 9 +1042 9 +4090 8 +3951 6 +3556 6 +3841 8 +3691 7 +1078 4 +1289 9 +2909 2 +2206 4 +3091 1 +1624 9 +1681 4 +437 8 +3112 9 +2679 9 +921 7 +1320 7 +2201 8 +425 7 +2930 2 +67 6 +1225 9 +933 5 +3952 5 +3123 1 +615 7 +3958 7 +1579 4 +3453 6 +944 7 +1351 1 +537 3 +1799 4 +2370 1 +2540 7 +1640 9 +3705 3 +1689 1 +302 3 +255 9 +613 2 +2241 9 +465 2 +1907 7 +251 1 +3398 6 +3306 7 +2646 9 +3697 7 +2996 10 +1177 6 +2513 5 +573 2 +383 9 +1723 6 +2759 2 +1603 1 +1701 10 +1969 2 +3900 2 +2828 4 +696 7 +2191 10 +3280 7 +3241 6 +1950 9 +0 1 +3352 5 +3994 8 +2041 4 +1157 10 +1108 1 +1533 5 +3628 6 +402 6 +377 6 +3321 4 +1876 7 +2851 8 +2439 8 +2134 5 +1246 1 +2580 1 +254 3 +276 9 +1739 1 +2001 8 +1303 8 +3666 3 +43 5 +350 9 +1619 1 +2449 3 +3991 4 +3133 4 +2754 2 +2808 2 +1103 7 +1933 1 +66 8 +3431 3 +1685 4 +781 10 +615 5 +1513 5 +230 1 +395 4 +2410 5 +3608 6 +2031 6 +3742 3 +868 2 +1367 6 +3929 6 +714 1 +1885 7 +3334 5 +334 5 +1331 4 +3245 5 +2617 1 +2360 4 +692 6 +2537 1 +2088 2 +2656 9 +607 2 +2924 1 +2619 6 +3043 4 +278 6 +1781 2 +1913 5 +1933 5 +2976 8 +3063 6 +1946 6 +608 6 +1187 7 +4070 8 +199 4 +1766 8 +455 6 +2961 1 +581 8 +2428 8 +3609 7 +3068 5 +3723 10 +3046 9 +227 7 +523 2 +1078 4 +2307 10 +513 8 +3658 1 +2901 4 +34 8 +2467 1 +2915 8 +3072 7 +3147 10 +1228 8 +1023 7 +2446 4 +1128 5 +398 3 +4016 5 +305 5 +274 2 +1020 5 +1036 4 +3663 10 +3575 10 +1579 2 +1479 6 +3604 2 +2575 3 +716 4 +2443 4 +1533 5 +3364 8 +66 2 +2500 3 +3487 9 +2246 10 +150 7 +4006 9 +4040 4 +2430 3 +4087 9 +1824 4 +11 4 +3395 6 +1865 7 +2906 6 +1713 5 +3445 1 +3127 5 +2756 6 +2413 6 +340 1 +3958 4 +2097 10 +428 5 +2381 2 +1517 10 +1242 10 +1686 6 +1966 1 +3688 3 +2135 7 +2223 10 +1379 8 +3244 3 +3215 7 +3005 4 +790 1 +1388 7 +391 7 +2936 9 +1950 7 +1586 3 +210 1 +1433 1 +3135 8 +1670 1 +1243 3 +1335 5 +163 6 +1191 5 +3350 7 +213 6 +4045 9 +3476 10 +462 9 +3248 4 +3436 3 +1127 6 +1658 5 +1347 4 +2932 5 +2007 10 +1002 6 +1304 3 +2334 3 +192 2 +1257 9 +2227 1 +3308 1 +2814 3 +305 3 +4038 7 +2605 8 +209 7 +1887 7 +3522 1 +2492 4 +3894 7 +3459 6 +3142 10 +3991 1 +3256 3 +220 2 +1541 3 +2844 3 +3940 1 +3425 6 +1313 4 +2499 5 +3559 9 +343 2 +3789 5 +3440 10 +708 10 +1613 5 +4054 10 +729 10 +2120 4 +1730 6 +2600 10 +786 1 +3192 9 +3450 4 +2610 6 +1284 6 +37 5 +2563 4 +2821 6 +2018 1 +1970 4 +3072 10 +1158 6 +904 10 +936 4 +1861 1 +1580 8 +2758 6 +1760 2 +1345 8 +2884 1 +2442 1 +3824 6 +323 3 +3813 10 +3198 2 +3754 10 +3437 6 +3739 5 +3834 8 +2605 10 +2936 2 +1880 5 +3439 3 +2012 2 +2602 9 +2743 6 +1670 7 +1107 9 +577 8 +1446 6 +1641 8 +4044 8 +1785 10 +4063 3 +963 3 +2360 7 +2143 4 +631 5 +2770 8 +2246 1 +2591 7 +1715 7 +2399 7 +865 3 +248 10 +2736 4 +3382 2 +2004 10 +2353 10 +3988 7 +461 4 +3776 6 +3037 8 +3479 2 +2953 9 +431 5 +3361 9 +2087 6 +829 5 +1176 5 +1509 1 +64 9 +1950 6 +70 5 +2499 10 +1530 9 +3704 8 +2965 1 +1674 5 +541 6 +2724 1 +614 1 +2173 9 +528 9 +750 5 +2849 5 +4054 6 +2821 7 +2071 3 +3121 9 +3567 1 +2906 5 +2923 9 +854 6 +3856 3 +782 4 +531 3 +36 10 +1231 4 +1810 3 +3397 8 +3603 2 +3463 4 +1604 1 +3527 9 +3197 3 +1486 10 +2829 5 +4009 1 +1532 7 +1175 9 +2229 4 +758 10 +1525 6 +3036 3 +1694 3 +999 1 +1823 4 +913 8 +3362 6 +2952 9 +3089 7 +753 10 +2687 7 +1754 7 +1881 1 +1237 6 +3456 10 +3011 4 +3430 6 +31 6 +951 9 +3084 8 +2250 6 +448 6 +3423 4 +2852 5 +2908 9 +4023 3 +3381 8 +4050 7 +747 3 +749 6 +1208 9 +2120 4 +2983 2 +446 4 +262 9 +2805 5 +857 8 +2171 4 +1242 8 +3981 7 +2653 6 +2283 10 +1543 10 +23 1 +1594 5 +4005 5 +1599 5 +2883 3 +3549 2 +460 5 +1017 2 +2773 8 +1935 1 +2083 8 +125 6 +1009 7 +2563 1 +254 1 +2960 10 +2676 1 +1954 10 +3727 5 +1390 6 +2767 6 +1238 8 +1064 5 +3526 5 +3394 4 +2459 4 +3292 8 +557 4 +1915 2 +2885 4 +522 5 +1848 5 +2737 3 +3946 7 +1737 5 +2257 7 +3592 4 +2320 1 +3302 10 +3434 4 +3461 7 +3007 8 +2558 10 +1675 5 +2523 1 +723 7 +3009 5 +1337 3 +3338 7 +1106 5 +2530 5 +2830 4 +2189 4 +74 10 +3974 10 +802 6 +3327 9 +982 1 +3260 3 +1319 1 +1198 6 +658 2 +2103 5 +4028 8 +47 4 +3675 2 +3015 10 +2475 10 +2789 1 +3871 8 +4089 6 +2461 5 +63 1 +1527 8 +1007 8 +3740 6 +2447 3 +3136 4 +1291 2 +975 6 +114 8 +3956 1 +1561 2 +1581 5 +3008 1 +862 5 +3916 9 +2829 2 +3533 9 +859 5 +3800 5 +2568 3 +1853 3 +1491 9 +2359 3 +2750 2 +2781 10 +2605 9 +2696 4 +2885 10 +976 8 +205 5 +1297 9 +2274 1 +1614 8 +1070 1 +780 7 +2903 3 +2126 3 +2811 8 +2572 3 +403 4 +541 3 +3383 2 +596 3 +3481 3 +794 7 +2605 7 +2808 9 +2253 3 +57 5 +3523 9 +649 9 +305 3 +3719 2 +2525 9 +3789 4 +1490 2 +3408 1 +825 4 +1038 4 +752 6 +597 4 +631 8 +3349 5 +3790 6 +3775 6 +393 7 +871 3 +1862 10 +2850 7 +1909 4 +3082 7 +670 4 +191 7 +1737 3 +639 2 +4018 8 +1718 8 +311 7 +4081 7 +176 10 +92 9 +849 2 +3130 5 +1542 9 +2422 5 +3978 9 +2606 3 +2164 1 +2940 10 +1223 8 +1207 7 +2067 4 +1123 6 +1777 1 +1010 4 +2333 4 +3535 1 +1159 2 +3640 10 +3455 10 +870 3 +1666 10 +4002 4 +3374 7 +574 9 +794 10 +1852 1 +3033 9 +3344 7 +1505 9 +1418 7 +1254 2 +1426 6 +1210 5 +1344 7 +3439 2 +190 6 +2310 3 +3417 1 +3218 1 +3767 3 +2740 3 +3469 5 +1222 2 +2083 5 +1295 9 +380 1 +4024 2 +2008 7 +2146 8 +42 3 +742 5 +2040 3 +258 5 +3952 7 +2113 9 +2801 4 +2245 9 +2645 4 +406 10 +11 1 +3805 8 +4021 1 +3852 1 +4009 9 +1355 7 +681 2 +3999 1 +3860 7 +3918 2 +1491 1 +879 3 +79 8 +2761 1 +2495 1 +3212 9 +1934 8 +2688 6 +225 1 +3301 1 +3774 5 +1241 2 +1866 9 +1305 7 +802 6 +873 2 +1863 6 +181 9 +2133 10 +963 4 +2507 9 +3048 10 +10 4 +3178 8 +1307 6 +3644 6 +3295 4 +3342 1 +612 7 +1626 4 +3110 4 +1001 9 +3538 8 +3001 3 +1299 9 +3974 4 +1072 4 +3947 10 +1275 6 +883 2 +1872 8 +2996 8 +1726 1 +2986 9 +3383 10 +3697 10 +2214 7 +1144 1 +3011 10 +122 6 +1989 4 +253 2 +3604 2 +436 7 +3439 9 +3014 9 +1132 5 +2497 5 +1760 7 +3698 5 +3682 8 +2715 8 +2697 6 +2802 3 +274 3 +1324 8 +1397 8 +443 5 +1475 9 +3836 5 +1105 2 +2007 3 +1085 9 +1553 4 +2404 1 +582 6 +955 8 +523 1 +3553 9 +2322 8 +1896 7 +151 8 +2408 5 +1242 2 +3562 4 +1487 4 +1034 4 +1626 2 +1391 6 +341 3 +382 8 +2302 6 +612 8 +2868 8 +3886 9 +564 5 +30 10 +3082 1 +3902 10 +2355 1 +2595 5 +1375 10 +432 10 +2434 1 +2049 2 +3927 6 +2082 10 +3262 6 +2287 7 +1298 8 +2777 8 +2651 9 +2951 8 +1161 7 +0 2 +2067 9 +1207 9 +933 9 +3419 6 +1057 6 +1544 9 +3706 1 +1799 3 +2420 7 +1256 3 +2686 6 +940 1 +3258 2 +3531 9 +2370 2 +2615 3 +409 3 +3640 1 +170 1 +918 3 +1854 3 +3581 5 +1183 7 +139 10 +2701 5 +3094 8 +2015 8 +2730 10 +3635 8 +3753 1 +1954 8 +2684 3 +874 7 +2279 6 +1426 4 +1043 8 +555 9 +1957 7 +529 2 +150 5 +3874 6 +1143 4 +3684 9 +990 2 +2689 5 +3365 7 +1868 1 +3312 1 +924 6 +2338 8 +502 2 +1681 9 +3819 8 +784 10 +3578 6 +3793 8 +3022 2 +3336 1 +330 3 +1699 1 +1706 3 +467 5 +3085 5 +1614 8 +850 5 +729 5 +1346 9 +2587 9 +3329 8 +931 7 +3438 9 +94 2 +414 10 +1055 9 +2744 9 +2746 3 +3793 3 +3996 3 +459 3 +1391 1 +421 3 +2880 5 +3881 4 +306 6 +3279 6 +238 8 +2838 8 +202 1 +1912 8 +783 10 +1079 8 +3410 3 +3103 3 +780 8 +1387 9 +3247 5 +441 7 +3453 1 +229 10 +4071 5 +351 3 +1242 6 +4071 5 +284 5 +2495 10 +3582 6 +193 7 +3878 7 +1835 7 +3920 10 +366 3 +161 8 +3202 7 +1568 9 +509 3 +2408 7 +1331 5 +1072 4 +3296 8 +2598 2 +759 10 +2490 1 +2180 9 +1852 5 +2030 8 +2465 4 +1911 5 +3244 3 +2681 3 +717 7 +2784 4 +3661 9 +3235 8 +2862 1 +1307 9 +334 1 +1703 4 +106 9 +243 6 +549 4 +1384 1 +339 4 +3729 10 +848 1 +104 7 +1213 6 +2601 5 +1153 4 +1457 2 +126 7 +1842 8 +2111 2 +1553 4 +433 8 +1721 7 +893 9 +2502 3 +4031 7 +3887 2 +3853 6 +3518 8 +1580 8 +1625 9 +3938 1 +2220 10 +1079 6 +3787 4 +3303 4 +3085 2 +1625 4 +4088 9 +147 4 +1678 8 +438 2 +28 6 +2776 6 +3305 10 +55 6 +3237 8 +468 6 +2505 3 +168 5 +2744 7 +3060 5 +1359 7 +1126 5 +1796 2 +3179 2 +2160 7 +2788 6 +741 5 +2774 3 +2626 5 +1023 1 +326 9 +1254 5 +729 7 +497 10 +1630 5 +2799 7 +2377 4 +584 8 +2909 3 +2738 8 +3993 9 +1646 8 +2446 3 +1681 9 +2129 3 +1006 9 +873 4 +2022 7 +3591 10 +3020 6 +1004 8 +122 10 +2016 6 +951 3 +3229 3 +891 1 +1945 5 +2096 6 +3140 8 +146 5 +1885 10 +430 1 +2179 6 +1376 2 +3049 8 +3672 7 +4058 5 +1300 6 +2697 4 +481 3 +1491 5 +3664 2 +2914 6 +2428 1 +2025 10 +3740 5 +3495 5 +3522 6 +204 4 +1433 9 +3559 5 +3491 8 +775 9 +163 8 +4026 3 +1105 2 +2158 8 +2307 4 +3052 8 +1218 7 +1409 9 +2749 3 +1983 5 +3082 1 +2100 9 +410 8 +3202 2 +2886 2 +2837 5 +2042 6 +1712 9 +1585 7 +831 10 +141 7 +1485 4 +1380 8 +3328 4 +2552 9 +3442 10 +28 4 +3295 5 +448 7 +716 5 +3798 7 +916 8 +4084 7 +617 5 +4088 2 +1303 2 +230 5 +189 2 +2141 10 +2471 7 +3445 7 +3267 9 +3805 2 +1588 9 +113 9 +2365 9 +189 1 +156 5 +3652 10 +3773 8 +67 1 +249 6 +573 7 +3179 8 +4062 5 +2733 6 +1974 9 +3021 9 +3017 5 +279 3 +3550 4 +923 8 +2035 8 +395 4 +4089 8 +2537 5 +1923 6 +890 5 +1996 4 +3414 7 +2303 3 +1100 2 +1671 4 +1092 2 +466 6 +2381 9 +3742 1 +1047 7 +1071 3 +4085 9 +3150 4 +2563 2 +595 2 +3896 8 +3174 8 +3984 2 +1752 10 +531 7 +73 7 +1139 7 +2312 7 +263 8 +1994 10 +1441 9 +2464 10 +2079 4 +3827 8 +820 2 +3448 10 +148 1 +3872 9 +3197 6 +680 9 +3229 3 +1794 8 +3952 6 +3950 6 +2566 5 +2126 4 +1666 2 +3131 2 +2469 9 +2005 3 +1953 3 +3515 2 +1273 6 +648 8 +1925 10 +1655 10 +1907 2 +3675 6 +811 6 +779 2 +1842 1 +2046 1 +3744 3 +1956 8 +529 5 +3925 6 +2731 10 +3582 7 +843 4 +3598 7 +944 6 +879 5 +1180 5 +542 6 +3156 4 +2067 3 +411 10 +1626 6 +3324 5 +4093 7 +2506 7 +2458 8 +2468 10 +2396 8 +2503 9 +2367 10 +3787 6 +2803 2 +4077 2 +1523 5 +2728 1 +446 6 +2513 3 +3613 10 +1775 2 +3457 3 +3930 4 +1573 1 +2969 2 +863 8 +3207 2 +1758 5 +3306 4 +3130 2 +1330 7 +3733 4 +2304 9 +58 6 +1102 10 +2276 4 +1318 10 +72 8 +1817 9 +1224 2 +2639 1 +451 9 +401 9 +2464 6 +560 9 +1965 4 +287 10 +1940 7 +24 6 +1946 10 +3108 9 +778 7 +1854 9 +3398 1 +2151 3 +2923 5 +2725 9 +3378 8 +1374 7 +845 3 +688 5 +983 3 +1179 3 +3101 9 +517 3 +2542 3 +2735 10 +1047 1 +1644 8 +1361 10 +2310 9 +2434 1 +3206 3 +535 7 +102 6 +404 10 +3868 5 +3149 5 +2435 6 +251 7 +2300 10 +1969 7 +598 7 +923 5 +1468 8 +476 10 +2255 4 +828 2 +3250 8 +885 2 +1345 9 +1474 6 +3764 1 +502 8 +71 6 +967 9 +3653 10 +3014 4 +3569 7 +2820 4 +1316 6 +1736 3 +2992 3 +2360 8 +591 2 +832 5 +3902 10 +2303 3 +791 4 +1749 6 +958 8 +2051 10 +2864 3 +2891 4 +241 4 +1918 10 +331 5 +1104 9 +1243 2 +535 10 +2948 8 +2058 8 +2574 5 +2316 9 +2937 5 +1369 2 +1267 6 +1738 6 +1366 10 +2937 5 +2859 6 +566 8 +3383 4 +3538 2 +1572 9 +62 3 +3980 8 +2111 4 +1024 8 +1804 9 +2077 6 +1541 9 +229 4 +3343 5 +90 7 +945 1 +2381 4 +371 4 +2661 2 +3672 6 +3246 6 +2902 8 +3771 5 +3020 6 +3744 3 +1319 6 +3197 6 +2389 10 +46 6 +1502 9 +28 1 +2857 7 +331 5 +1607 2 +2794 10 +495 8 +2281 6 +880 4 +847 10 +3205 8 +4019 5 +1949 8 +3477 6 +1990 8 +344 5 +2752 8 +2034 3 +3588 7 +1771 5 +505 9 +2026 1 +1222 8 +933 2 +188 1 +2132 5 +3767 9 +3484 4 +2768 5 +1482 6 +1943 10 +1640 8 +2812 5 +3279 6 +3959 7 +2610 1 +2045 9 +433 1 +529 2 +873 10 +1385 1 +1994 8 +744 7 +2665 9 +3311 6 +211 7 +1250 1 +529 6 +759 10 +3624 8 +1505 4 +773 7 +1594 1 +3429 9 +1466 9 +2224 6 +136 3 +3932 4 +4086 8 +32 5 +3534 7 +245 3 +3196 7 +1338 9 +1794 1 +3218 10 +284 4 +1747 6 +3710 7 +3343 8 +2297 5 +2521 4 +3802 10 +3643 10 +591 2 +4093 3 +1801 2 +1185 8 +2421 9 +1381 2 +1205 5 +330 2 +3644 5 +1504 4 +3281 9 +3169 9 +2191 6 +3037 3 +3072 6 +1778 5 +221 8 +362 10 +3549 8 +834 5 +2804 7 +204 10 +3044 6 +3720 1 +3166 8 +1170 2 +3210 2 +444 6 +2219 8 +2214 5 +2229 8 +2406 2 +2538 9 +1531 8 +1341 4 +4000 5 +1662 9 +330 6 +3485 6 +1474 7 +2921 1 +773 10 +3340 8 +432 6 +1283 6 +2487 6 +1041 1 +3626 7 +2177 5 +610 8 +2025 2 +2665 2 +1007 10 +882 9 +421 8 +895 4 +1596 2 +1170 9 +386 1 +863 10 +1216 2 +3614 4 +2822 3 +1816 3 +2434 9 +3923 8 +2717 7 +2002 1 +1745 8 +1417 10 +446 10 +396 7 +517 9 +534 9 +2942 6 +1256 7 +4068 10 +911 5 +2907 2 +1927 4 +776 3 +3477 1 +785 4 +2842 2 +760 9 +3268 6 +3425 1 +1723 9 +1879 5 +660 4 +415 4 +1791 2 +811 6 +248 5 +236 2 +287 10 +1817 4 +2630 2 +2992 2 +1950 6 +3474 5 +1824 1 +3571 2 +2758 5 +3343 7 +1821 2 +2972 6 +1291 2 +2746 7 +408 9 +4042 10 +526 4 +3311 1 +2222 2 +3155 1 +3408 5 +3727 9 +3716 7 +1321 4 +172 6 +534 2 +1827 4 +1560 1 +2654 2 +2937 3 +3102 1 +2640 9 +3527 8 +2810 8 +746 1 +3423 9 +694 9 +41 6 +20 5 +1888 2 +2831 3 +1597 6 +12 9 +2351 4 +550 10 +1688 5 +4070 3 +3345 4 +15 9 +242 6 +2823 4 +2870 6 +3587 3 +612 3 +3067 4 +1665 5 +3909 7 +3483 9 +710 5 +1307 9 +459 5 +3370 10 +3711 6 +491 3 +1938 2 +2272 2 +2118 2 +255 10 +129 5 +1726 6 +2144 10 +3655 1 +3228 1 +19 7 +608 9 +2167 9 +3599 10 +729 9 +3547 8 +2491 1 +3318 4 +815 7 +3745 8 +1743 3 +3102 5 +3946 7 +289 3 +3352 8 +4042 4 +3943 7 +3786 1 +2910 8 +2412 7 +3851 8 +3896 10 +1297 8 +1075 8 +3520 5 +717 4 +2416 9 +3535 2 +1494 3 +3614 4 +327 3 +3272 7 +3078 7 +1952 3 +928 8 +1322 1 +2563 3 +1412 5 +623 8 +458 6 +3754 8 +2197 10 +481 8 +3081 2 +2712 6 +2057 1 +915 6 +3583 9 +2544 3 +2841 5 +3389 1 +2732 8 +393 4 +2141 6 +2216 1 +2541 6 +1211 5 +3478 10 +525 1 +2292 3 +2483 7 +696 9 +2828 1 +915 5 +1047 1 +1755 6 +2524 6 +2721 10 +1936 8 +764 10 +2789 7 +3012 3 +1266 10 +4085 8 +3797 2 +2110 8 +2170 10 +688 4 +974 5 +2386 8 +1075 7 +3606 7 +3612 2 +2545 5 +1956 7 +3552 5 +3585 1 +110 10 +163 4 +699 1 +798 5 +1452 10 +3588 10 +1014 5 +1249 1 +3817 9 +866 10 +3177 10 +276 7 +2056 1 +1787 8 +4024 4 +3284 10 +2852 9 +994 10 +3106 7 +445 2 +970 9 +1140 10 +493 4 +1433 9 +3762 2 +3608 3 +887 7 +1315 2 +2146 8 +3944 1 +2345 1 +1994 5 +279 6 +784 2 +137 6 +3041 3 +755 6 +2503 4 +2778 3 +3646 9 +2580 4 +2147 4 +1542 3 +2530 6 +2357 7 +1586 10 +503 2 +3471 4 +1166 9 +3133 8 +2226 9 +483 8 +3475 6 +1640 3 +3188 10 +1548 6 +3520 5 +965 1 +3348 1 +189 10 +3796 9 +3653 1 +3804 6 +371 1 +3046 8 +2189 2 +2543 5 +3253 2 +225 3 +2033 7 +2182 10 +1975 10 +373 4 +137 4 +1033 4 +3898 8 +129 6 +101 10 +3114 9 +3741 10 +415 1 +752 1 +1383 10 +3232 3 +3534 6 +2786 6 +1320 7 +3762 9 +3929 9 +1238 1 +3353 7 +3911 7 +189 9 +1872 3 +3941 3 +3292 1 +2412 9 +1105 3 +1231 9 +963 3 +1098 4 +3351 6 +3409 4 +75 9 +365 6 +4088 2 +570 4 +3450 7 +490 6 +3582 3 +1764 5 +1658 9 +1235 5 +389 6 +1015 3 +1108 8 +4009 7 +1420 10 +4007 3 +1191 4 +3350 10 +805 6 +855 3 +2683 6 +564 3 +1640 10 +3632 7 +1769 6 +295 10 +2004 5 +3962 4 +3720 7 +833 6 +2054 9 +351 3 +3162 6 +3564 8 +1557 5 +2737 2 +2530 8 +1694 10 +3637 9 +1107 2 +1243 3 +474 1 +835 10 +3981 4 +3722 8 +52 5 +2942 3 +3461 9 +3959 10 +4080 1 +3554 6 +1633 7 +1591 7 +2656 7 +540 2 +2305 8 +842 7 +3146 10 +1251 3 +2403 2 +835 5 +773 2 +3458 7 +3165 4 +433 1 +2319 2 +184 10 +3171 4 +1316 2 +3103 5 +195 9 +3694 4 +2688 10 +1936 2 +848 6 +3991 7 +3714 7 +16 10 +2050 4 +1957 4 +1813 7 +3883 3 +3129 10 +1555 7 +882 1 +3957 1 +1613 10 +2381 3 +1205 6 +96 4 +3400 2 +2476 1 +3132 6 +648 5 +2613 9 +307 6 +3069 2 +340 1 +4033 7 +3613 3 +3821 6 +3658 7 +588 10 +3796 5 +1901 1 +2932 8 +533 9 +2864 1 +2976 6 +4058 5 +4000 6 +52 7 +2606 1 +1784 1 +973 9 +1337 6 +1521 6 +2273 9 +50 9 +877 4 +1265 2 +3981 9 +772 3 +2543 10 +2910 10 +148 1 +929 3 +3817 10 +1356 9 +2603 10 +3064 10 +236 3 +1714 4 +2242 6 +2907 4 +1879 10 +2685 8 +2129 1 +495 9 +3688 3 +2593 6 +1157 2 +1048 7 +3763 5 +2224 6 +3561 4 +2035 3 +1208 2 +1515 1 +611 7 +2020 2 +2615 10 +889 2 +3331 2 +2320 2 +2471 4 +3194 7 +2715 2 +3911 3 +2493 3 +2034 4 +2575 8 +2170 3 +1348 6 +1592 5 +3146 3 +1064 1 +1493 3 +724 6 +907 1 +3502 3 +3672 7 +299 4 +2517 3 +3487 6 +3732 2 +964 2 +819 2 +1960 3 +2892 7 +2993 6 +1101 9 +1240 7 +1560 9 +741 6 +1046 9 +2287 4 +502 8 +1311 6 +3071 8 +2469 6 +2760 1 +2553 9 +1073 7 +3543 2 +2323 1 +2572 7 +2027 6 +655 10 +575 7 +2066 10 +1236 3 +1411 1 +684 3 +1738 2 +1257 5 +2553 3 +2663 7 +3251 4 +1204 9 +1806 1 +3003 8 +762 6 +3163 7 +1754 7 +4040 9 +2394 2 +2892 3 +637 1 +1310 6 +697 3 +3016 2 +3237 7 +1357 7 +1590 7 +646 1 +4003 10 +3500 8 +960 6 +1841 7 +1620 7 +1396 3 +137 4 +2583 3 +3340 8 +2116 3 +4047 9 +2384 2 +2503 2 +2827 5 +1135 6 +346 7 +3504 3 +3738 8 +1658 2 +2218 6 +3144 2 +1604 1 +2074 1 +1379 3 +667 4 +1595 2 +2635 8 +992 3 +876 10 +1063 3 +3065 10 +1445 9 +2430 2 +2090 9 +123 3 +3695 1 +3168 5 +2053 8 +281 6 +899 8 +1603 4 +3085 4 +583 9 +3737 8 +1113 1 +3894 10 +781 9 +1529 6 +242 6 +1746 6 +859 7 +557 5 +4039 2 +2021 5 +3493 9 +2449 6 +502 5 +2792 10 +2028 10 +1299 6 +2347 5 +2662 5 +4015 8 +2272 8 +3546 3 +3687 2 +2466 6 +1312 7 +2764 9 +3068 4 +2422 2 +1196 9 +3139 6 +904 7 +1365 6 +214 2 +700 2 +449 6 +3611 3 +3476 8 +4069 10 +2743 1 +1171 3 +4075 10 +2356 8 +3758 8 +2310 10 +1809 9 +1628 6 +3410 3 +968 9 +3434 6 +314 7 +2523 1 +3429 9 +1426 10 +961 10 +1711 5 +403 3 +3823 7 +554 2 +3537 9 +3062 3 +360 7 +3181 7 +86 4 +3597 10 +3837 3 +3963 4 +3378 10 +2796 2 +2759 9 +273 8 +1666 6 +3315 1 +3729 6 +3574 7 +1220 9 +2887 9 +2860 5 +3324 6 +1048 9 +111 1 +3535 5 +195 3 +1970 7 +1497 10 +1656 8 +2179 8 +625 8 +1339 1 +571 2 +443 2 +1193 2 +309 1 +255 4 +2777 10 +1767 3 +2491 6 +1554 1 +3238 7 +2368 8 +2160 5 +2638 5 +2201 3 +2405 2 +968 8 +224 5 +2132 10 +1030 2 +373 9 +1363 3 +1169 10 +2470 8 +3607 7 +3155 7 +1502 6 +3687 9 +2833 5 +3829 1 +3777 10 +2998 5 +182 1 +1398 1 +3701 6 +1395 4 +341 4 +1627 1 +1747 9 +3265 6 +2489 8 +3944 6 +2359 7 +157 6 +2268 2 +1250 1 +2574 3 +4020 10 +1196 5 +82 10 +1647 2 +4038 10 +1089 3 +492 3 +3633 8 +1657 6 +517 5 +1698 6 +1222 8 +3172 4 +2166 2 +2571 6 +1656 5 +1343 3 +1362 9 +3554 9 +2941 2 +2767 10 +3191 7 +3471 6 +2537 8 +912 2 +1923 7 +685 5 +2697 3 +4048 4 +2929 6 +2271 4 +1786 6 +1470 10 +132 6 +4013 10 +1369 9 +1577 3 +894 6 +1411 2 +2049 6 +3885 7 +3098 8 +3958 8 +2841 3 +3300 4 +2503 10 +2301 7 +2377 2 +1867 9 +3131 9 +485 7 +3578 7 +1263 4 +2950 9 +1461 9 +950 4 +3771 8 +1189 10 +3455 7 +81 2 +1035 6 +3512 10 +3572 6 +2891 5 +2564 4 +1776 7 +3028 4 +829 7 +2937 8 +4088 9 +183 2 +623 2 +675 2 +441 1 +1852 8 +2703 6 +2825 6 +463 3 +303 9 +2953 8 +2093 5 +2215 3 +1619 9 +2906 8 +1180 3 +3956 1 +2573 6 +3032 3 +294 5 +2959 2 +177 7 +2688 7 +2499 1 +4038 1 +3699 3 +3859 7 +1459 6 +1642 1 +3293 2 +109 5 +772 3 +3819 6 +37 1 +1604 8 +1271 6 +3470 1 +2858 10 +2757 10 +1798 1 +992 1 +980 4 +645 7 +1328 5 +4002 10 +2225 10 +1932 7 +537 9 +1114 3 +3522 4 +911 10 +2633 10 +3001 8 +2258 1 +3882 1 +3206 9 +18 8 +3612 2 +1648 10 +1319 2 +3573 4 +359 7 +499 4 +3158 10 +695 6 +3165 10 +2167 2 +3646 4 +2764 2 +2407 9 +2155 7 +1448 6 +1667 1 +3127 1 +135 7 +1264 2 +764 6 +506 5 +3105 8 +937 5 +4010 2 +2231 9 +1652 2 +769 2 +2574 7 +607 6 +1594 8 +651 9 +338 5 +3642 7 +3371 1 +3527 3 +138 5 +3833 3 +870 7 +2520 4 +3068 3 +1661 9 +43 10 +3234 4 +3111 6 +1625 9 +2898 8 +3525 1 +2530 3 +2917 7 +2001 7 +1175 10 +4027 9 +222 7 +2333 7 +1872 3 +2005 2 +1496 8 +2605 2 +3973 1 +2975 9 +2649 7 +1952 10 +3835 9 +3390 10 +2487 5 +3693 8 +3397 7 +176 7 +2214 3 +3599 2 +2217 1 +57 4 +1659 7 +1751 3 +3714 3 +2875 10 +1594 3 +3245 7 +1577 6 +75 5 +2430 2 +2506 9 +674 3 +1033 6 +2185 3 +1284 10 +2220 6 +3269 7 +1917 1 +2666 8 +2274 4 +3643 8 +1942 9 +3126 3 +2317 7 +2505 8 +1705 1 +854 2 +1642 9 +2639 5 +612 2 +1006 3 +56 9 +1023 2 +384 6 +3366 8 +455 1 +2153 6 +1079 7 +2176 4 +1206 9 +4081 6 +1285 2 +4094 2 +1142 10 +1307 3 +3587 4 +2844 7 +3226 7 +2457 3 +2921 6 +3132 2 +345 1 +649 4 +4065 10 +3693 3 +3563 5 +513 9 +1167 2 +33 2 +153 4 +3185 8 +1873 5 +1702 1 +3799 10 +756 7 +801 9 +3801 2 +827 3 +472 7 +1096 8 +268 3 +2160 8 +2931 4 +3145 5 +555 3 +3863 6 +2106 10 +2336 1 +1444 5 +3832 2 +131 7 +275 7 +679 9 +599 3 +1184 6 +1464 6 +2622 4 +248 6 +1312 4 +2100 8 +3531 7 +1235 6 +342 10 +2477 7 +247 2 +1424 6 +2989 6 +2123 7 +2465 6 +2203 1 +1443 10 +1773 3 +2058 3 +3027 10 +1329 7 +3578 7 +731 4 +632 5 +2656 3 +2901 5 +343 6 +2157 9 +596 3 +163 5 +3700 8 +2955 8 +2670 4 +3695 1 +3428 5 +727 6 +3111 7 +1253 6 +1870 8 +2787 6 +909 9 +1820 9 +3830 3 +3126 6 +3118 5 +3670 7 +3757 8 +3454 7 +2750 5 +2097 4 +3445 4 +1166 7 +3947 4 +3770 5 +2125 4 +2132 10 +3089 7 +250 10 +2423 4 +1737 7 +2687 1 +2502 2 +919 2 +2354 9 +3074 7 +2245 3 +2155 3 +3640 4 +1670 1 +82 1 +116 10 +2480 5 +2174 9 +2497 4 +1910 3 +3481 8 +957 10 +3011 3 +3902 9 +1144 2 +3894 10 +2668 3 +2266 9 +1738 1 +3002 6 +3280 6 +988 10 +3073 8 +1148 5 +3624 8 +3011 3 +442 3 +2771 5 +265 8 +1151 9 +676 3 +110 3 +1421 4 +2040 5 +281 8 +2145 3 +1174 3 +1546 5 +367 6 +413 1 +238 7 +1650 9 +937 6 +1036 10 +905 5 +2108 2 +2969 9 +2356 5 +1495 3 +1575 1 +52 5 +1737 2 +1457 1 +573 2 +3489 1 +3301 5 +2585 5 +3978 4 +3945 4 +2554 8 +1266 6 +1736 6 +2138 1 +870 4 +4036 10 +924 10 +547 3 +943 3 +3859 4 +1390 5 +2047 8 +1852 2 +2780 3 +2684 5 +1665 10 +613 4 +1398 7 +3509 7 +1605 9 +740 1 +243 7 +2659 2 +899 6 +1406 1 +579 2 +3301 8 +2814 7 +467 1 +2460 3 +3172 7 +3746 5 +3238 2 +1272 2 +3292 9 +796 9 +151 4 +3114 9 +1102 4 +4072 7 +3927 5 +930 1 +3501 3 +3166 2 +571 7 +4062 2 +1367 2 +112 7 +2477 5 +860 4 +1057 9 +2105 10 +3283 5 +47 1 +3477 5 +891 8 +553 4 +2510 7 +285 1 +1484 8 +4022 2 +1414 8 +134 1 +1085 4 +2299 2 +2428 8 +1288 5 +1487 4 +1354 7 +1115 8 +1920 1 +615 8 +2485 5 +2692 9 +709 1 +893 7 +2945 3 +118 9 +1232 8 +3262 7 +1332 5 +2284 5 +2410 7 +3191 5 +3808 6 +3573 2 +2134 1 +1291 8 +2215 8 +4017 2 +13 9 +3263 8 +3875 10 +493 8 +864 2 +179 8 +2933 7 +663 9 +2633 7 +1485 6 +2004 2 +178 9 +3816 3 +678 6 +3019 7 +2792 10 +83 7 +3328 3 +77 2 +2991 6 +1643 4 +780 8 +2627 6 +3422 10 +4085 8 +593 1 +1798 6 +1606 6 +1045 7 +2765 5 +3186 2 +2260 8 +3972 7 +1132 5 +1900 10 +1759 6 +2290 9 +1212 4 +698 7 +511 1 +3331 7 +1185 6 +2565 1 +481 5 +896 7 +3301 7 +3907 7 +1014 5 +3916 1 +3628 3 +897 5 +1626 7 +1935 10 +1200 7 +3970 8 +3287 6 +927 2 +385 5 +1665 7 +2625 3 +1068 5 +3819 1 +2727 1 +1770 10 +3401 4 +1035 5 +3934 7 +1747 10 +3304 5 +1699 3 +739 10 +2396 3 +438 2 +3852 10 +2536 8 +619 8 +3535 3 +3758 3 +3889 1 +2887 6 +1720 9 +906 7 +3930 2 +3424 8 +2388 2 +1193 8 +2670 6 +3415 6 +3748 5 +1005 2 +3621 1 +2117 6 +3173 1 +3138 4 +3527 6 +790 3 +1633 5 +1725 10 +1700 8 +895 4 +3164 10 +3433 1 +165 1 +554 8 +1332 3 +1330 7 +1063 9 +2077 7 +875 9 +1378 1 +3839 9 +1907 3 +3274 8 +1444 4 +3809 1 +1834 7 +447 10 +13 6 +353 1 +2807 10 +3759 2 +1007 10 +3404 7 +1943 4 +1538 5 +1627 5 +2355 7 +1113 6 +578 9 +3056 3 +4034 8 +1812 7 +1388 9 +662 5 +2030 10 +24 7 +1600 10 +3051 7 +1495 1 +3155 4 +2911 7 +3017 3 +3764 7 +3561 7 +2259 8 +1092 9 +1312 5 +2132 10 +1929 10 +1297 3 +164 4 +1759 3 +2554 5 +3570 9 +2073 7 +68 8 +3225 1 +1222 9 +3001 8 +189 10 +3512 8 +3954 1 +4007 10 +498 9 +3559 7 +4052 3 +4066 5 +3914 10 +214 6 +149 4 +3949 7 +1491 7 +1783 1 +39 9 +1576 2 +3915 6 +1422 3 +2488 3 +3578 5 +939 10 +2467 1 +3742 10 +3990 3 +1156 3 +638 8 +308 5 +414 9 +2119 5 +2310 6 +491 8 +1948 9 +3551 1 +197 8 +2189 4 +2492 4 +2503 10 +3930 9 +3180 3 +1251 3 +1713 6 +203 10 +79 6 +2020 8 +2585 2 +2096 3 +1790 2 +2869 6 +1174 6 +2765 9 +1261 3 +2399 5 +637 10 +2318 5 +2306 5 +3370 7 +3379 1 +1732 5 +1503 10 +3555 8 +2024 8 +3905 6 +3491 5 +197 9 +340 1 +192 10 +1165 6 +3663 2 +2625 4 +2784 5 +3138 10 +3624 2 +3707 4 +2747 3 +96 8 +3822 6 +2740 7 +4083 7 +3339 8 +2041 10 +3050 7 +3165 7 +3096 9 +1375 1 +658 3 +3089 7 +586 9 +737 9 +2962 8 +3511 4 +2051 8 +1653 10 +2080 4 +1883 8 +2251 3 +1934 6 +1480 9 +3874 6 +276 9 +3255 8 +1860 4 +376 1 +71 7 +3753 2 +80 2 +3707 6 +1065 4 +978 2 +34 9 +1967 3 +964 2 +2802 8 +497 2 +793 1 +3976 9 +276 1 +3541 7 +2997 6 +444 10 +1180 10 +3008 1 +4091 10 +2304 4 +2965 6 +3270 5 +2441 4 +2822 5 +657 6 +2631 8 +1358 10 +1783 3 +3165 3 +1865 1 +3323 6 +375 3 +3779 5 +2505 3 +1645 10 +957 3 +1491 3 +1214 5 +3670 3 +2193 1 +720 2 +3241 10 +3819 8 +2112 4 +3301 10 +1264 4 +3937 3 +3991 9 +2233 9 +2788 8 +2477 5 +2449 6 +3996 10 +1614 6 +1843 1 +2732 4 +2658 2 +1930 9 +1400 2 +3464 10 +3043 7 +1099 6 +1698 1 +2485 9 +904 9 +3305 1 +161 10 +3368 3 +2575 3 +2376 2 +3414 10 +2415 2 +2241 3 +1118 3 +672 2 +973 3 +63 2 +3909 10 +2730 10 +2677 8 +2879 7 +434 8 +3328 1 +372 4 +3892 9 +3724 3 +1471 1 +1378 6 +3369 9 +244 7 +3068 4 +864 7 +1521 6 +2038 2 +3124 2 +1781 4 +2580 6 +324 1 +1703 1 +1230 2 +2407 6 +3972 9 +1775 6 +3082 4 +2442 8 +159 1 +971 1 +1686 8 +1022 10 +166 3 +3153 3 +3406 10 +1865 8 +1902 8 +2309 8 +78 1 +1521 7 +3207 10 +3637 2 +2802 7 +2388 4 +2204 2 +1263 9 +3758 7 +210 1 +2319 9 +561 4 +3534 9 +3902 2 +3460 8 +3392 4 +2231 10 +3718 9 +3019 5 +1126 9 +563 4 +1770 1 +1615 8 +2212 3 +3923 4 +745 5 +1638 9 +2814 6 +2652 1 +1114 8 +3194 5 +2302 9 +2308 8 +1040 4 +1210 4 +1632 2 +1359 3 +2478 9 +2613 5 +1037 7 +588 4 +602 3 +4014 7 +2961 4 +2047 9 +2435 1 +200 7 +1265 3 +278 3 +1610 4 +3825 10 +3239 6 +1101 2 +1300 4 +645 3 +180 5 +987 10 +626 9 +1288 6 +4017 3 +1451 10 +3465 6 +639 9 +830 3 +3332 1 +2983 10 +3702 5 +3877 10 +1450 4 +1003 5 +1545 5 +85 9 +1838 4 +788 8 +3927 10 +1056 8 +2778 6 +3679 3 +1002 8 +3338 5 +796 5 +2418 2 +3877 6 +279 8 +2305 8 +3895 4 +3515 1 +2818 4 +667 8 +2259 1 +2268 1 +2727 8 +1497 2 +777 6 +2200 7 +2456 5 +2856 7 +1571 5 +990 10 +1046 3 +3554 2 +3317 2 +2117 2 +49 4 +3251 5 +1138 4 +1020 6 +359 10 +2453 9 +2468 2 +1970 7 +3781 8 +339 10 +707 9 +1294 7 +3950 1 +846 8 +3362 9 +1275 3 +2627 5 +2665 3 +2785 8 +2626 5 +733 9 +1160 1 +3159 6 +143 9 +2164 2 +3928 2 +1972 2 +3856 7 +3888 7 +3983 8 +1829 10 +37 6 +255 3 +1327 9 +2513 10 +1368 2 +744 8 +709 9 +3809 9 +2173 5 +2777 2 +961 3 +421 1 +875 7 +1552 6 +1624 7 +3938 4 +1100 2 +631 1 +235 10 +1125 1 +168 10 +3547 7 +2353 10 +3006 10 +763 5 +2716 3 +2657 6 +3549 9 +214 6 +3547 7 +3270 6 +436 10 +3474 8 +3223 6 +4019 3 +4083 4 +1913 8 +422 4 +707 9 +2853 3 +1850 4 +596 4 +3455 10 +1307 3 +3706 8 +1441 10 +3879 8 +3858 3 +472 9 +1711 7 +3057 7 +1080 9 +498 5 +2332 9 +1374 2 +1178 1 +1673 7 +3260 5 +2625 8 +1925 7 +1769 8 +100 10 +3527 10 +3042 7 +3425 8 +3027 6 +1279 3 +2027 3 +469 8 +17 2 +2782 9 +341 5 +129 6 +2538 8 +325 8 +3066 3 +4047 6 +90 1 +1170 1 +496 8 +3767 3 +738 6 +978 4 +1727 9 +2483 9 +2017 6 +657 4 +2139 3 +775 10 +2472 9 +2787 8 +1504 3 +543 1 +1331 2 +1313 1 +554 4 +3997 6 +2823 8 +1521 10 +1342 2 +3175 5 +2162 3 +2970 2 +1781 9 +121 5 +1868 10 +1220 5 +1315 7 +3619 1 +729 7 +1148 2 +167 4 +915 10 +2197 9 +1387 1 +558 4 +3475 5 +803 7 +1223 8 +2789 2 +2020 8 +121 2 +926 3 +368 5 +1726 5 +261 4 +3162 3 +2490 10 +3168 3 +3301 10 +3438 5 +1498 8 +1912 8 +2145 9 +3118 4 +3638 1 +1186 10 +734 3 +2438 1 +2923 4 +1900 7 +2894 8 +3372 2 +759 8 +2318 1 +2312 7 +551 2 +2008 7 +3030 8 +960 8 +212 9 +470 9 +4042 1 +115 3 +3981 1 +2901 6 +227 2 +3460 6 +3819 8 +2974 2 +945 4 +3000 9 +2475 1 +2146 10 +1307 6 +1835 4 +3016 9 +111 6 +1804 3 +1492 10 +213 6 +578 4 +1962 7 +538 2 +3498 7 +1504 5 +3276 1 +29 10 +1751 4 +3691 8 +3940 7 +3590 5 +904 7 +1308 5 +2836 9 +2607 2 +3977 4 +3483 5 +914 7 +3591 8 +2957 2 +1456 6 +1058 4 +156 10 +1229 8 +723 4 +323 10 +1036 8 +1588 7 +1119 2 +2304 2 +1258 6 +2374 3 +1511 6 +3309 8 +2197 4 +1922 1 +2663 6 +1672 7 +3887 5 +3053 6 +1402 1 +548 8 +1584 1 +2087 3 +2285 1 +2296 2 +2219 7 +352 7 +1082 2 +1095 7 +3190 3 +2965 2 +1491 4 +3628 2 +678 1 +989 7 +3992 8 +2804 9 +3427 10 +2437 8 +354 3 +3931 2 +2727 6 +3545 6 +3365 5 +1510 7 +2345 10 +127 9 +3498 10 +636 5 +1057 7 +178 4 +912 10 +1125 9 +3365 5 +84 3 +938 7 +1288 7 +1381 1 +1918 4 +2141 4 +780 8 +3992 8 +588 1 +469 10 +3797 1 +3704 4 +3692 6 +1990 4 +891 1 +4079 7 +547 9 +1882 5 +3816 10 +926 8 +2927 10 +2006 7 +2486 2 +3632 3 +1220 2 +2238 10 +3433 9 +1246 2 +3886 4 +3922 3 +218 8 +2179 2 +3334 1 +193 8 +1378 10 +3579 7 +1791 7 +3787 4 +873 7 +2528 9 +518 6 +212 9 +3299 9 +3114 10 +379 1 +2024 7 +681 2 +3421 8 +399 10 +3187 5 +1665 4 +1808 6 +1987 5 +1748 4 +1625 9 +385 10 +987 9 +3359 7 +2821 6 +2169 4 +3375 9 +3512 9 +3189 7 +1068 8 +3790 4 +3807 2 +22 8 +1287 6 +3718 9 +2858 6 +2126 10 +4011 5 +3800 10 +2661 2 +1947 8 +3834 2 +303 2 +2622 3 +3913 1 +1811 4 +61 5 +3661 5 +2741 6 +3856 9 +1455 8 +1637 6 +3822 1 +849 10 +1107 9 +4017 7 +1863 9 +835 10 +1701 3 +2071 9 +1073 6 +3155 9 +3832 10 +643 4 +530 1 +353 1 +1161 1 +350 1 +2528 8 +3713 9 +880 9 +2421 10 +3781 1 +2390 9 +2151 6 +245 2 +2899 6 +3547 9 +2772 5 +2134 1 +1827 4 +1552 10 +3487 4 +900 3 +273 5 +1946 1 +3128 2 +3301 9 +3175 5 +934 10 +1779 3 +1199 9 +1233 5 +2228 7 +2105 1 +479 8 +3535 1 +1742 2 +2390 7 +3399 2 +1660 7 +849 3 +1652 9 +3332 8 +174 4 +2965 9 +1165 8 +2794 8 +1638 2 +2881 8 +2527 3 +1570 2 +2307 5 +979 2 +2832 6 +3507 8 +3430 1 +3962 7 +140 7 +3207 2 +3306 10 +582 10 +2746 8 +81 4 +2122 4 +1226 6 +1454 7 +354 5 +1664 2 +2109 1 +1697 3 +2452 4 +2398 1 +2224 2 +1679 6 +2330 1 +2358 3 +2942 10 +3842 2 +1411 2 +353 9 +1879 2 +1117 6 +255 1 +2495 8 +1126 9 +1947 6 +3705 6 +270 10 +1351 2 +2900 1 +3427 7 +742 2 +1158 4 +2501 1 +868 10 +3810 5 +449 2 +2496 5 +972 4 +3187 9 +291 4 +2278 3 +1057 2 +1471 10 +3238 2 +1171 6 +1463 3 +2833 3 +2529 10 +2831 3 +567 10 +2484 4 +973 1 +3606 5 +154 7 +2688 3 +1188 5 +1853 4 +3407 6 +710 1 +1598 10 +6 4 +2315 9 +3218 10 +577 3 +2530 9 +2622 4 +4048 1 +1208 1 +2226 4 +1064 9 +2499 10 +3998 7 +496 5 +1751 7 +4021 7 +2966 9 +684 3 +3805 7 +2747 2 +1818 7 +2879 3 +3599 6 +2593 5 +2186 10 +3511 10 +1100 1 +1821 6 +3472 4 +2858 7 +2920 5 +173 2 +3517 4 +3322 9 +3410 4 +2233 7 +392 9 +2204 7 +3584 3 +356 5 +2406 3 +906 9 +2577 6 +2631 6 +444 3 +2593 9 +2065 8 +53 8 +661 2 +2175 8 +365 9 +1178 9 +2179 5 +2548 2 +4022 7 +1486 2 +3648 5 +1654 3 +2129 1 +3787 1 +3637 2 +980 8 +3142 1 +2176 1 +847 2 +659 7 +2132 1 +3193 6 +70 4 +3333 7 +3145 4 +1512 5 +292 4 +1357 6 +1603 4 +64 10 +4048 3 +1027 8 +3850 2 +3056 4 +1658 8 +3884 7 +2822 10 +2949 6 +1058 1 +2301 8 +3666 1 +1829 3 +3148 8 +2784 4 +281 8 +3434 1 +2237 1 +2413 6 +805 2 +1900 7 +669 5 +2412 5 +2964 8 +3704 3 +468 8 +3184 5 +3394 3 +3059 1 +632 3 +843 8 +1157 2 +2788 3 +1339 7 +2516 9 +650 1 +1764 2 +3082 10 +1718 5 +2034 7 +1360 4 +4023 7 +1123 6 +424 3 +1087 1 +1181 1 +2253 1 +531 2 +1485 6 +572 3 +3615 8 +839 2 +2062 2 +1142 8 +1175 5 +3997 2 +2481 3 +3086 5 +3060 4 +3474 1 +1045 1 +1009 8 +2648 3 +2472 8 +2130 3 +362 3 +1695 4 +3669 8 +3233 8 +1840 7 +3803 3 +3042 3 +882 10 +3123 1 +3752 8 +3475 2 +3648 4 +583 10 +1334 6 +612 6 +163 1 +3764 5 +1912 3 +1816 10 +2696 3 +842 6 +257 1 +4033 6 +3039 3 +2051 7 +1188 5 +2949 7 +255 9 +3385 1 +1189 2 +3189 9 +1669 2 +1227 2 +2908 7 +1812 8 +2435 4 +1842 9 +1452 2 +2649 6 +1876 6 +770 5 +2038 9 +3784 10 +1738 2 +2144 6 +214 4 +618 4 +539 2 +2360 6 +350 4 +307 4 +807 5 +1564 7 +3877 2 +3824 10 +1023 3 +2440 9 +2700 8 +2239 4 +2076 4 +3086 9 +3480 5 +2189 10 +3143 5 +3434 4 +2389 8 +3170 4 +1231 7 +1376 8 +554 7 +2525 10 +2580 8 +4069 5 +319 4 +1771 5 +2893 7 +3742 6 +1438 7 +1010 1 +726 6 +3146 9 +2214 7 +351 3 +2878 7 +1791 9 +1475 7 +1457 6 +2583 8 +1730 10 +116 9 +2972 6 +3886 9 +1110 6 +1906 10 +1406 8 +2044 2 +1333 1 +3736 5 +1384 10 +1298 3 +2877 3 +1274 4 +1711 5 +3467 9 +925 5 +504 1 +3689 6 +3026 4 +1071 3 +586 10 +2394 2 +315 2 +2946 7 +747 8 +51 4 +2317 3 +692 9 +3653 10 +3718 10 +2106 8 +3031 1 +1970 4 +1763 3 +3037 4 +1116 6 +1784 1 +3486 1 +551 2 +3451 8 +3809 2 +2572 5 +3576 1 +3229 1 +151 5 +723 3 +1748 9 +519 3 +2762 3 +2266 2 +121 7 +1905 10 +2294 9 +629 9 +2232 10 +1590 2 +2437 6 +1092 10 +1153 3 +2067 2 +1825 10 +1631 1 +103 1 +129 8 +2731 10 +1265 5 +2754 10 +3176 2 +2385 8 +1620 3 +444 4 +1231 7 +1496 1 +3681 10 +2951 3 +3148 10 +172 10 +1414 9 +3775 9 +2671 4 +697 1 +3632 5 +2440 5 +3099 2 +350 6 +3080 10 +1314 8 +2759 4 +2801 3 +3304 4 +2912 4 +2351 1 +940 6 +2725 2 +3543 9 +3971 3 +1649 3 +550 7 +125 1 +1696 9 +2743 8 +2277 1 +543 2 +1262 7 +550 7 +920 4 +2277 10 +2466 10 +2648 6 +2442 7 +1983 1 +1438 2 +2167 1 +2256 10 +183 6 +2832 8 +2037 1 +2829 7 +284 3 +138 8 +1758 1 +2109 8 +1146 5 +3817 10 +799 8 +325 4 +706 10 +1790 6 +445 2 +1734 6 +123 8 +2187 2 +1960 7 +75 2 +359 8 +802 5 +1384 3 +1140 4 +2396 5 +4087 7 +2680 7 +3182 8 +3436 6 +899 7 +1437 4 +1502 2 +2046 9 +452 9 +3709 5 +1733 9 +1547 2 +1729 10 +3826 7 +1387 8 +185 3 +513 9 +3068 10 +306 2 +1585 3 +1244 6 +977 1 +1751 8 +1350 7 +1112 8 +2683 2 +3677 6 +1196 2 +100 4 +4058 3 +897 6 +1915 7 +927 2 +480 2 +892 1 +3033 10 +2510 7 +2915 4 +1296 7 +2536 1 +255 6 +2584 1 +98 5 +1922 3 +1547 6 +3939 6 +3795 10 +3628 6 +2484 8 +661 3 +3160 1 +1991 2 +607 9 +1305 1 +1910 6 +3274 4 +2755 4 +2570 2 +2550 5 +3805 3 +3987 3 +1123 5 +1105 3 +3047 9 +3404 1 +684 8 +3036 5 +3368 8 +2208 1 +2049 1 +1761 1 +1416 10 +1559 2 +2246 5 +612 1 +92 10 +1815 5 +926 5 +1552 8 +438 8 +2828 7 +1502 9 +2894 7 +3200 4 +2227 9 +2483 7 +3918 5 +3274 3 +2318 6 +1762 2 +2416 1 +2081 6 +3583 6 +2357 8 +1319 2 +657 3 +4073 7 +1517 5 +3633 10 +1945 8 +2331 5 +3289 6 +763 5 +3895 6 +1698 3 +1658 3 +31 8 +2042 6 +2543 8 +413 8 +831 3 +2182 2 +3657 2 +3790 4 +2894 9 +1186 9 +3197 2 +1102 4 +1728 5 +689 8 +1189 6 +2347 1 +2034 9 +1046 8 +2342 3 +3731 8 +3407 5 +1307 4 +1156 5 +1946 5 +2779 8 +743 6 +334 8 +1101 9 +1831 4 +1158 8 +3068 2 +954 4 +3810 2 +467 7 +37 8 +339 1 +74 7 +2022 4 +419 1 +615 5 +1498 6 +548 10 +1759 2 +1873 2 +3670 4 +2614 9 +1278 1 +908 9 +1115 6 +2677 5 +1732 3 +3546 4 +3924 1 +2665 1 +1387 2 +3622 6 +1333 8 +1977 10 +4051 5 +2720 5 +2555 3 +607 6 +3498 4 +799 2 +3439 1 +1422 8 +3862 6 +959 1 +4029 2 +47 4 +2013 5 +3339 10 +2797 8 +3463 10 +1923 7 +2693 7 +276 5 +3223 2 +3887 6 +4060 1 +3765 3 +3480 6 +565 5 +3616 10 +3576 5 +2612 9 +4049 9 +762 5 +551 9 +1439 10 +2131 4 +544 10 +2124 7 +896 1 +163 4 +4021 5 +3887 4 +2329 4 +1714 8 +1209 5 +2238 5 +2096 10 +517 10 +2526 4 +2825 7 +2802 6 +3625 2 +255 6 +3419 7 +2404 9 +1538 6 +3235 2 +2416 9 +30 3 +3790 6 +977 10 +590 8 +535 9 +542 9 +553 3 +3670 5 +1373 6 +123 7 +735 9 +1218 9 +2397 8 +2703 9 +2846 9 +827 9 +491 1 +2986 10 +3797 3 +2170 2 +1397 3 +1185 2 +49 3 +1207 9 +3167 1 +466 7 +1659 4 +3479 9 +874 8 +3136 2 +1377 9 +879 2 +2961 4 +4020 10 +642 1 +2826 5 +3641 8 +3631 5 +1084 7 +324 8 +1660 6 +3774 10 +1663 6 +3907 1 +4027 1 +290 5 +963 6 +2344 7 +3325 9 +87 10 +1110 10 +1760 1 +825 9 +3647 9 +1213 5 +849 7 +1494 5 +3980 6 +922 8 +586 10 +1807 1 +3755 6 +2477 9 +302 5 +2174 9 +340 3 +2047 10 +1973 9 +3168 5 +2419 1 +3039 1 +4020 9 +2298 5 +1796 4 +3313 6 +542 4 +2913 2 +2069 4 +2407 1 +3566 7 +2190 10 +381 6 +2826 6 +2811 3 +305 2 +608 5 +3637 10 +617 2 +994 7 +1737 5 +761 4 +3223 2 +4070 3 +897 4 +2223 9 +2796 1 +2449 5 +1933 10 +450 9 +516 6 +1468 4 +2999 2 +3656 1 +3197 5 +2286 1 +3695 7 +3210 6 +2723 10 +930 2 +796 8 +2608 2 +3529 10 +2512 5 +3975 10 +1475 10 +1425 9 +2602 2 +2782 9 +1919 5 +1362 9 +214 3 +1476 4 +3714 4 +47 5 +1776 5 +714 5 +2815 2 +716 8 +1040 9 +415 1 +1683 5 +3396 1 +876 7 +2724 6 +1825 4 +2314 10 +3581 2 +2430 4 +282 6 +862 6 +2300 10 +2698 8 +3704 9 +1554 6 +939 10 +3315 9 +1561 3 +838 5 +2454 8 +2397 6 +1186 4 +1103 4 +2363 7 +698 5 +684 4 +3117 2 +2500 4 +3798 4 +4080 2 +2324 2 +739 6 +505 7 +2872 4 +476 7 +2891 10 +3213 10 +3634 4 +147 2 +282 3 +25 10 +2759 6 +465 1 +528 4 +2579 8 +2013 5 +3811 3 +694 4 +1180 6 +791 5 +3556 4 +3981 2 +3378 5 +3526 7 +2021 3 +2459 10 +3528 10 +3855 10 +3024 1 +3266 8 +1298 5 +2308 1 +236 7 +3047 5 +1001 7 +3633 3 +105 7 +2072 2 +2751 2 +1806 8 +4014 9 +720 4 +1813 1 +3026 4 +648 6 +2818 5 +1021 9 +1180 9 +1859 4 +1921 5 +1925 3 +477 5 +3051 9 +3474 4 +2718 10 +695 2 +2738 3 +181 9 +2138 4 +1474 9 +3440 10 +2442 10 +3753 7 +541 3 +1271 9 +2280 4 +1212 2 +3028 8 +3066 10 +3241 5 +1439 2 +3323 9 +3958 10 +2619 5 +4056 6 +3306 2 +2598 4 +1865 10 +300 8 +3693 7 +2055 4 +710 7 +2292 7 +3443 1 +498 8 +3295 3 +1591 1 +2208 6 +4032 7 +1800 5 +352 3 +780 2 +1835 2 +65 9 +956 2 +2303 3 +1494 8 +2362 7 +272 3 +2916 3 +2190 1 +633 4 +1862 2 +806 8 +3214 7 +15 10 +789 3 +1854 9 +575 2 +1241 8 +3633 7 +2771 7 +1776 7 +2664 1 +2994 9 +1300 8 +2878 4 +1185 9 +3652 2 +990 3 +205 5 +3316 5 +3237 9 +2604 4 +441 2 +241 8 +805 4 +3357 5 +1179 8 +2796 10 +3949 2 +530 9 +2938 6 +165 8 +3716 1 +3697 6 +3085 1 +29 8 +2242 9 +1622 9 +877 9 +1876 8 +329 2 +508 6 +3600 10 +1514 7 +3301 10 +1829 1 +2099 3 +2960 3 +3851 6 +1275 9 +2714 6 +2747 7 +294 10 +1226 5 +3453 2 +3326 8 +263 2 +2873 10 +3305 2 +417 10 +141 4 +1773 6 +3875 7 +2042 6 +2796 10 +1964 8 +2719 4 +2902 3 +2893 7 +239 10 +344 6 +2385 8 +472 9 +239 5 +2319 5 +2847 2 +2649 8 +3116 1 +347 6 +1848 3 +3705 4 +3340 8 +751 3 +695 9 +1393 7 +2153 1 +2148 1 +1848 4 +659 4 +2177 1 +2038 10 +2754 5 +1465 9 +3122 5 +2960 3 +1113 2 +3649 3 +3225 6 +2647 9 +1474 6 +2094 4 +740 1 +2325 5 +1224 7 +3048 4 +457 6 +2720 4 +3779 6 +2298 10 +1805 7 +1752 7 +3417 3 +3801 4 +2776 4 +2012 6 +3307 3 +2844 7 +2872 1 +957 4 +2252 4 +3174 9 +3675 1 +2599 8 +2037 6 +3173 9 +3304 3 +3000 5 +696 1 +3583 10 +2956 5 +899 7 +1427 7 +2211 10 +3065 2 +3351 3 +797 10 +1283 7 +120 8 +3194 3 +729 4 +2692 10 +3422 7 +2526 8 +3354 9 +790 3 +259 1 +55 3 +505 5 +68 8 +540 1 +3416 8 +3584 3 +1268 7 +729 2 +1840 3 +2573 2 +3843 3 +3823 9 +2592 8 +3453 4 +2886 3 +1236 5 +1562 6 +2156 7 +613 4 +2763 7 +912 1 +585 7 +2341 2 +754 7 +1028 1 +2006 4 +1767 5 +1965 3 +3078 8 +3587 2 +1418 2 +1086 9 +2082 9 +1415 7 +790 5 +3031 5 +1441 10 +3496 7 +966 1 +3562 5 +2816 8 +938 3 +2216 1 +1150 5 +1925 1 +1068 6 +2860 2 +1014 7 +469 6 +2987 5 +473 1 +3009 9 +917 10 +2700 10 +3394 3 +2324 8 +736 7 +2990 7 +3043 9 +896 8 +1146 1 +1360 10 +3906 6 +348 7 +3786 8 +1004 5 +2974 3 +558 9 +2854 5 +2777 7 +173 7 +3332 4 +450 7 +2464 9 +1195 9 +3235 7 +3336 2 +2254 6 +818 3 +3798 1 +810 8 +3606 2 +3025 6 +778 6 +977 7 +3549 2 +4015 3 +2736 7 +3550 6 +3889 4 +2921 5 +3176 3 +4 6 +1305 4 +4040 1 +1225 1 +3314 6 +1222 9 +1197 8 +3932 5 +3991 6 +493 7 +2644 7 +241 8 +562 5 +1097 3 +2632 6 +2480 3 +3129 5 +3096 2 +3585 8 +655 9 +2600 6 +491 4 +2467 2 +495 9 +3969 6 +3467 10 +45 2 +602 3 +763 6 +1876 10 +1188 8 +3089 4 +2316 1 +3761 10 +228 1 +3596 9 +215 1 +546 2 +1716 7 +1940 4 +2585 2 +1780 7 +262 5 +2560 7 +1845 6 +86 1 +1080 4 +1350 10 +606 9 +1391 7 +2634 8 +127 10 +2256 3 +2794 9 +2617 3 +1509 10 +2103 6 +1893 2 +238 5 +135 10 +3003 2 +2917 10 +3425 2 +2607 2 +2136 3 +2216 5 +1414 2 +1484 9 +3474 6 +3871 3 +78 1 +1613 4 +892 10 +3655 9 +3129 6 +832 9 +2100 5 +4092 3 +2112 1 +2649 2 +676 10 +3347 10 +424 9 +860 4 +3666 4 +1185 1 +1872 1 +1811 10 +213 9 +144 4 +3984 8 +3748 4 +1716 2 +2523 9 +482 4 +2002 1 +1501 6 +3333 5 +1641 9 +1867 7 +3138 10 +330 4 +3154 7 +710 3 +2139 1 +3269 3 +1694 3 +1437 5 +2333 4 +3433 4 +4 5 +2452 7 +3848 10 +944 7 +1822 7 +4025 6 +3936 9 +1309 10 +1496 1 +3341 6 +1435 3 +803 6 +3276 4 +971 8 +774 3 +2286 8 +1316 10 +3276 1 +797 5 +503 3 +4020 8 +2517 1 +452 6 +2644 10 +2338 9 +3013 10 +997 5 +3485 3 +556 2 +1037 5 +3610 9 +211 4 +4015 10 +831 10 +1715 3 +1365 7 +1098 2 +487 10 +111 1 +2022 10 +3957 7 +1276 1 +3879 9 +3127 2 +1973 9 +3891 10 +2944 6 +3106 2 +3939 3 +386 7 +1665 10 +2078 9 +1125 10 +1577 7 +3543 7 +853 3 +3798 8 +3801 7 +3169 6 +2880 1 +1540 10 +1518 7 +2083 9 +1616 9 +2814 7 +1787 8 +3727 4 +3708 6 +2186 7 +1693 8 +1577 10 +2225 3 +2065 4 +1931 7 +1138 1 +3381 3 +2675 1 +1153 1 +1507 4 +347 7 +1773 9 +2601 3 +133 1 +3813 10 +3061 1 +163 7 +168 3 +2578 3 +4076 2 +734 2 +999 6 +1907 2 +3972 4 +493 10 +870 1 +1613 7 +2118 7 +1742 9 +1165 9 +2074 10 +3320 3 +874 1 +2703 3 +1014 8 +1310 5 +3038 8 +2369 9 +984 9 +3684 4 +961 4 +1278 2 +1791 3 +3968 9 +1462 6 +2801 4 +146 6 +3717 8 +3445 10 +941 4 +1709 8 +3112 2 +3192 7 +3353 4 +2564 8 +639 6 +2140 7 +4056 4 +854 4 +719 9 +780 10 +2091 7 +2748 7 +1123 6 +773 4 +2572 8 +3240 6 +3156 9 +1985 4 +2845 2 +3011 2 +1830 9 +2768 7 +1079 8 +23 5 +1702 8 +3920 7 +2925 6 +2318 7 +3833 2 +1659 4 +164 9 +455 1 +3237 6 +3397 7 +1751 9 +1247 8 +3951 8 +659 5 +2424 6 +894 8 +4082 7 +2904 10 +3148 5 +444 8 +331 3 +3653 4 +166 4 +1331 7 +2053 8 +3411 6 +1266 7 +3971 1 +67 10 +866 9 +479 2 +2452 3 +434 5 +1926 2 +2563 3 +2434 5 +2808 7 +3612 4 +509 1 +146 5 +112 5 +726 1 +5 7 +1767 9 +213 5 +2630 6 +914 3 +2248 3 +295 3 +3251 10 +3771 3 +2556 5 +3851 3 +1227 4 +1444 10 +2455 4 +3500 9 +2382 4 +3745 1 +4040 10 +239 2 +3552 2 +1812 1 +404 9 +879 6 +593 2 +2620 8 +960 9 +2935 5 +3247 10 +923 1 +3362 4 +2746 4 +563 3 +228 9 +3501 6 +699 6 +72 7 +2701 2 +1265 3 +350 3 +213 1 +3267 7 +2167 4 +2325 1 +2896 8 +3789 9 +1296 4 +2459 3 +3485 3 +3459 7 +2028 10 +3655 4 +1965 9 +1673 6 +1843 10 +3491 5 +1532 9 +2204 4 +1427 10 +2541 2 +1947 5 +3718 6 +1105 5 +2498 3 +3322 6 +1985 5 +434 5 +2948 5 +1763 9 +248 2 +1467 7 +1719 4 +263 7 +3514 8 +2057 4 +1461 6 +993 10 +417 4 +1400 7 +1956 8 +3824 6 +964 10 +3822 8 +3459 8 +3676 1 +2537 6 +2853 7 +3629 1 +2855 8 +1975 1 +1607 1 +855 5 +1423 7 +1692 7 +1080 3 +28 9 +86 4 +3955 8 +2773 6 +1108 7 +55 6 +3905 7 +3796 7 +3143 8 +3808 8 +1687 5 +2304 1 +1328 6 +1150 9 +323 10 +2591 9 +2083 8 +1145 9 +3254 7 +2660 6 +2134 6 +317 2 +3971 6 +268 4 +155 10 +1067 6 +2810 7 +3214 3 +717 2 +3692 4 +3479 2 +2901 5 +2943 6 +1958 2 +3965 10 +1896 2 +1538 1 +2294 5 +3815 7 +1433 8 +2680 7 +1012 9 +191 8 +238 8 +3300 5 +514 10 +1643 8 +3348 8 +3547 7 +2874 8 +3090 3 +305 1 +3842 6 +3085 4 +2127 10 +3843 10 +3473 7 +2005 8 +1809 5 +3217 1 +2968 1 +3422 7 +76 3 +3216 4 +1470 1 +3350 2 +221 2 +382 4 +1982 10 +244 1 +1795 1 +1951 8 +1818 4 +393 9 +1339 2 +442 8 +479 9 +2304 1 +1068 5 +827 7 +2639 6 +2554 6 +1999 6 +4078 6 +1905 10 +3957 3 +2424 7 +1143 5 +486 1 +2832 6 +157 10 +4082 9 +1143 10 +649 5 +2647 9 +3693 2 +3595 4 +1778 9 +2170 9 +3830 2 +259 10 +1417 2 +1061 1 +2146 10 +1642 9 +463 8 +2849 5 +2323 5 +3355 5 +2378 2 +990 8 +2692 10 +879 7 +1674 8 +261 7 +3914 10 +1842 2 +887 4 +4036 7 +227 8 +1592 6 +720 1 +1761 6 +1326 6 +2286 10 +386 9 +2863 6 +78 6 +3986 9 +307 10 +445 9 +3940 7 +529 5 +939 4 +1459 4 +966 4 +3798 9 +683 2 +1323 8 +313 10 +3093 6 +420 2 +1586 10 +1256 5 +1726 5 +1772 1 +1464 6 +3980 10 +2147 2 +3727 8 +641 8 +1577 10 +1207 8 +4035 4 +562 2 +2492 8 +72 4 +1535 6 +2706 1 +2845 9 +1676 4 +730 3 +1964 9 +3894 9 +2393 6 +2790 2 +869 7 +1139 10 +1784 1 +2365 7 +1750 1 +88 1 +3565 5 +1199 6 +2526 4 +3472 9 +1295 1 +2082 1 +2587 5 +3150 3 +1238 1 +2562 8 +3926 5 +2277 10 +1317 10 +764 4 +1292 3 +2153 3 +3582 2 +1921 9 +256 6 +1318 1 +1202 1 +177 4 +1154 9 +2986 9 +3936 6 +3273 5 +290 6 +1024 10 +2780 4 +3986 5 +516 10 +249 3 +2905 10 +2844 8 +2862 7 +2524 1 +2837 5 +3402 8 +3161 10 +2999 9 +2960 10 +3824 3 +2495 10 +1385 2 +1335 8 +813 10 +1090 5 +3901 7 +1055 6 +656 9 +2570 4 +3329 5 +569 9 +2055 2 +2018 5 +306 7 +323 3 +2866 5 +2095 1 +3068 4 +3174 3 +571 4 +1682 3 +1345 2 +2909 1 +656 9 +1484 4 +3164 2 +2571 10 +3966 10 +3340 10 +3728 8 +7 2 +2608 4 +2421 7 +2362 1 +3003 10 +3149 2 +903 4 +3827 6 +1493 7 +1841 2 +858 8 +1451 1 +3172 3 +1973 1 +3439 3 +2296 3 +1634 2 +2457 1 +532 10 +1046 2 +3357 2 +2972 8 +825 9 +3344 4 +3911 4 +1051 4 +574 7 +3352 3 +534 4 +3882 1 +2328 7 +517 7 +3393 4 +1929 2 +1767 10 +733 5 +2664 1 +1410 5 +444 6 +1540 6 +968 9 +2640 6 +1875 8 +1901 9 +3463 6 +3969 6 +351 2 +3927 9 +909 8 +1050 7 +2546 1 +3510 4 +249 1 +3123 6 +163 3 +549 1 +3607 10 +1638 7 +3195 6 +3973 1 +104 5 +3502 9 +3134 9 +2764 1 +2263 9 +3943 7 +52 3 +849 1 +1057 2 +1287 5 +3156 5 +1769 7 +3908 3 +1059 1 +1455 4 +2934 2 +25 1 +2676 4 +3981 6 +3527 7 +1243 4 +1259 2 +3833 8 +1258 3 +772 6 +1262 7 +1837 7 +3722 5 +1901 7 +3677 10 +613 2 +3232 3 +776 10 +1169 3 +2073 2 +839 2 +617 8 +1811 5 +3395 1 +1528 3 +1681 2 +2428 4 +1405 4 +3810 3 +3260 6 +3019 9 +844 1 +74 10 +102 10 +3149 9 +1048 10 +808 9 +36 2 +2902 6 +2605 5 +1523 2 +2765 6 +1940 6 +3654 5 +3120 9 +2253 5 +1651 5 +757 6 +1246 9 +3442 2 +1811 4 +213 3 +3163 8 +3938 9 +405 2 +3465 10 +2497 9 +3963 4 +2858 3 +2911 1 +2586 4 +4093 9 +283 9 +3429 5 +74 6 +2552 8 +837 6 +3303 5 +727 7 +3844 5 +3646 2 +1480 10 +190 7 +1495 9 +2341 7 +2280 5 +3956 4 +3860 5 +2735 2 +2861 7 +2927 1 +2012 5 +477 7 +99 5 +3191 4 +813 3 +3000 8 +3213 5 +1658 5 +450 8 +869 3 +3025 7 +1170 2 +3437 6 +3514 5 +2433 5 +1333 6 +2050 7 +949 8 +2985 1 +3727 5 +889 9 +1630 3 +3443 4 +737 7 +1991 8 +1580 5 +3192 2 +2548 1 +968 7 +151 2 +535 7 +3856 5 +1164 10 +411 8 +1538 1 +2929 5 +1978 2 +58 10 +844 4 +1501 9 +1059 5 +2496 7 +343 2 +2893 8 +3966 7 +2075 1 +3105 10 +756 8 +1687 1 +3754 4 +3947 3 +3306 10 +1523 7 +3955 9 +6 9 +1945 1 +1488 10 +2653 8 +3688 8 +2749 8 +3167 8 +79 2 +1526 2 +1585 7 +2095 5 +768 1 +1069 4 +3216 6 +1781 3 +2165 3 +2393 5 +1828 4 +2526 1 +1814 2 +1977 9 +313 2 +1930 7 +3803 3 +2629 5 +452 9 +353 8 +961 9 +880 1 +2662 7 +3725 4 +1329 5 +1008 10 +763 5 +2644 8 +4013 5 +2516 7 +3550 5 +3797 7 +833 6 +3309 4 +2095 2 +439 1 +3984 2 +2296 7 +2670 4 +3352 8 +1106 7 +2232 3 +3932 4 +3922 10 +1295 4 +1182 4 +594 9 +815 1 +527 3 +3211 10 +1929 9 +1906 5 +280 1 +464 5 +2700 1 +2133 9 +3273 8 +4053 2 +2384 2 +2509 5 +1247 1 +3745 2 +910 1 +1524 5 +2412 6 +1260 3 +3277 2 +2078 2 +1625 10 +3767 10 +1966 1 +2711 10 +2454 7 +196 1 +1331 5 +659 1 +118 2 +3428 1 +749 9 +826 2 +2708 6 +1021 5 +407 2 +149 7 +3176 3 +3310 3 +3951 1 +2425 5 +1010 6 +119 9 +2677 8 +3760 8 +3345 8 +2116 6 +1001 5 +730 2 +1085 1 +2347 7 +2704 7 +3235 4 +3178 9 +2172 6 +1846 5 +2144 3 +1166 6 +1492 6 +3283 5 +3655 8 +1124 2 +64 1 +212 2 +1912 1 +1218 9 +1051 1 +996 6 +3157 5 +3308 2 +1891 1 +1235 6 +937 1 +1820 1 +597 1 +3382 1 +1882 1 +4090 3 +1612 2 +1884 1 +1009 4 +2989 7 +196 4 +1635 8 +3632 4 +253 9 +2051 1 +1045 9 +2473 9 +2292 7 +936 5 +1725 4 +327 5 +665 8 +2335 7 +2937 9 +2483 6 +3251 4 +407 3 +1280 2 +3407 10 +3574 10 +3480 7 +238 4 +3999 6 +618 4 +3899 5 +1123 9 +1492 7 +2447 8 +1335 3 +826 9 +2229 4 +3643 10 +2979 5 +4025 1 +2136 2 +2100 2 +1338 8 +2546 7 +3854 10 +1368 9 +2271 5 +2977 5 +1645 2 +1515 9 +236 2 +2812 8 +175 9 +627 6 +2281 2 +1236 2 +36 10 +2909 3 +3086 8 +3846 1 +1818 1 +332 5 +2912 9 +869 9 +3898 4 +1285 3 +172 6 +812 2 +2672 10 +2888 7 +1850 3 +3499 8 +1832 1 +1431 8 +2801 1 +1080 10 +443 6 +3893 5 +185 3 +2316 6 +50 6 +3849 9 +1137 2 +2962 2 +4079 10 +4014 3 +1702 3 +4055 9 +971 7 +2515 7 +2299 3 +1150 9 +2989 9 +626 3 +1572 7 +2233 5 +1392 5 +1257 3 +415 4 +598 3 +109 2 +3403 6 +3411 9 +1894 4 +678 2 +461 6 +2764 10 +3142 5 +2613 8 +2219 3 +3810 8 +3510 9 +1744 7 +3700 8 +1986 2 +2106 3 +756 2 +2888 1 +1485 8 +1857 8 +1187 9 +355 7 +3227 3 +4019 3 +2485 8 +2139 9 +3517 3 +3665 10 +3618 2 +3358 1 +1591 9 +1886 4 +746 5 +1721 10 +2471 2 +3938 9 +2506 2 +257 6 +3861 3 +3588 4 +3619 4 +2627 4 +2528 10 +1881 1 +283 5 +108 5 +583 1 +852 9 +3783 10 +1538 10 +3931 5 +545 8 +3042 1 +1533 9 +1555 2 +3840 5 +1863 9 +530 7 +1842 10 +3966 10 +699 2 +3960 2 +1644 4 +2685 1 +1162 6 +1059 6 +3406 3 +2804 10 +1028 1 +3754 2 +3937 2 +4020 10 +2036 4 +1653 6 +449 10 +739 1 +2067 3 +681 3 +296 3 +1138 9 +474 7 +365 1 +1211 1 +2919 4 +223 8 +3724 7 +3490 6 +3310 4 +1509 2 +2406 5 +3450 9 +3188 3 +2492 4 +3031 3 +3321 1 +2125 10 +4070 4 +2449 6 +1269 7 +3132 1 +733 10 +120 3 +2009 7 +4013 5 +17 10 +2805 7 +2016 6 +3240 7 +2478 8 +3622 8 +1511 8 +1567 6 +2208 10 +2421 6 +3722 8 +2612 1 +1459 5 +863 6 +3812 10 +2234 2 +1230 7 +3000 2 +1165 9 +472 1 +2724 2 +18 1 +915 10 +3744 8 +2865 4 +520 1 +2297 9 +3469 8 +3748 6 +3301 8 +1674 6 +1260 4 +677 9 +2398 4 +3377 6 +1748 1 +2111 2 +2876 7 +3086 1 +1776 2 +3505 7 +2367 7 +3830 8 +3390 3 +2124 8 +3984 7 +2916 10 +2396 10 +1677 4 +3013 6 +3362 10 +1284 2 +3097 5 +2508 1 +2664 5 +721 5 +3878 2 +3689 9 +1648 7 +2708 4 +3937 7 +3415 10 +2761 3 +1848 4 +3019 4 +2555 3 +111 6 +3243 6 +3377 9 +1007 2 +3769 3 +75 1 +1195 8 +3968 1 +1205 5 +3756 2 +1689 7 +2596 7 +2909 10 +3807 2 +2871 6 +891 5 +3409 10 +1890 9 +3724 9 +3611 6 +1052 1 +1946 7 +1375 3 +3432 3 +3178 8 +2517 1 +3172 3 +3873 8 +1527 4 +1220 5 +85 6 +3112 7 +2539 6 +980 5 +1022 2 +1934 10 +58 10 +1859 7 +143 3 +706 2 +776 6 +4088 7 +2987 8 +1736 2 +501 7 +416 5 +3276 7 +77 7 +133 8 +3566 8 +3177 7 +587 3 +2859 10 +656 4 +2130 8 +2668 9 +1738 1 +2399 10 +2485 4 +3758 8 +1255 3 +2870 8 +3970 9 +2660 1 +2949 8 +582 10 +3207 2 +2460 6 +1037 2 +2300 8 +1438 4 +4064 2 +1513 3 +47 4 +494 6 +206 7 +1883 5 +1907 2 +736 4 +4037 3 +3008 7 +2975 10 +2136 4 +3351 1 +1895 4 +2824 5 +1546 8 +1755 6 +3513 5 +3462 5 +1907 3 +3329 5 +1296 3 +2762 9 +2642 9 +82 6 +2056 5 +3469 9 +605 6 +3834 3 +1662 8 +2204 5 +2231 7 +146 4 +2484 6 +3002 1 +1163 3 +624 6 +3993 2 +2431 3 +1430 9 +1017 7 +3450 2 +3416 3 +3215 4 +2245 4 +2873 1 +2984 9 +439 6 +1604 8 +2761 6 +3029 1 +3048 4 +1137 10 +1633 9 +227 4 +1271 2 +2495 4 +1169 9 +1108 9 +2174 10 +760 1 +1547 4 +3924 9 +604 7 +3079 6 +885 2 +2456 3 +1240 5 +1766 4 +1145 8 +2033 5 +243 9 +741 9 +1280 8 +268 7 +1348 10 +2468 6 +1947 2 +3334 6 +2374 8 +1100 3 +1003 2 +1812 1 +1689 7 +2109 2 +869 10 +2552 9 +2960 5 +2530 9 +1542 8 +136 1 +106 1 +3308 3 +3104 1 +618 8 +2468 3 +274 9 +2516 2 +2462 10 +167 9 +1544 3 +24 3 +3147 10 +1578 3 +1684 10 +1813 3 +5 1 +3684 4 +597 4 +14 4 +3326 2 +3728 1 +3867 3 +1580 3 +2587 10 +258 10 +669 1 +3150 1 +2015 7 +3335 4 +233 9 +2223 3 +1279 1 +2399 8 +1167 10 +764 6 +243 10 +3235 10 +2591 7 +1599 3 +359 9 +2827 4 +3682 1 +1980 8 +3899 7 +2449 1 +1698 3 +2179 4 +827 1 +725 10 +1837 9 +994 6 +1699 3 +2040 10 +1349 5 +3794 6 +1975 3 +899 9 +1515 2 +2600 10 +786 1 +1387 3 +2082 5 +3476 8 +821 6 +3768 2 +3541 4 +3394 9 +101 1 +1668 4 +3432 2 +1090 6 +2710 7 +2464 4 +783 4 +1648 6 +1163 6 +3060 8 +1299 8 +387 10 +3744 6 +86 1 +3529 8 +1085 2 +478 5 +2557 1 +1208 8 +3767 4 +3163 2 +3179 4 +2419 6 +4022 9 +945 6 +2826 7 +2412 3 +2783 7 +2515 10 +3818 5 +42 8 +2945 10 +659 2 +612 4 +2484 10 +507 4 +2027 10 +509 7 +1775 7 +219 10 +3733 5 +1724 3 +2606 3 +270 5 +3653 1 +446 9 +2719 7 +4095 9 +2103 8 +2007 6 +3257 7 +859 1 +3995 6 +2388 6 +1915 5 +3262 8 +2459 6 +2279 6 +3530 2 +2919 8 +2965 6 +34 2 +2017 5 +1253 7 +3971 4 +2495 7 +2716 9 +1389 4 +4077 1 +1104 4 +1028 4 +3428 5 +1546 4 +299 6 +3312 6 +1072 5 +2479 4 +2192 1 +2238 1 +3105 10 +1571 6 +1337 2 +2908 10 +1875 2 +1750 5 +401 7 +1336 1 +391 3 +2926 6 +1003 8 +4024 3 +3327 10 +1976 7 +83 7 +2317 4 +1943 9 +2391 3 +1602 2 +3199 10 +814 5 +1774 1 +3056 9 +3815 3 +1400 3 +646 5 +1686 4 +490 2 +2353 2 +277 3 +2074 9 +3402 8 +3429 9 +2517 5 +1931 5 +1980 8 +2791 1 +3549 2 +2698 4 +2777 6 +3019 4 +4079 9 +792 5 +1955 5 +3295 9 +1284 7 +3477 1 +1507 8 +1621 2 +392 2 +3275 7 +928 7 +2196 8 +303 3 +1769 5 +1724 1 +3960 1 +3209 6 +3037 1 +1241 10 +3146 4 +782 10 +2661 5 +2943 8 +3586 6 +340 9 +2135 7 +1911 9 +2699 6 +95 8 +3039 2 +2367 7 +2958 5 +3882 9 +3449 8 +243 10 +552 9 +2760 8 +2455 10 +3781 10 +947 3 +2362 3 +1366 5 +2659 1 +1249 6 +2635 6 +1623 7 +3472 1 +2849 5 +1229 4 +2687 10 +1355 2 +1584 9 +3270 2 +3116 9 +2472 2 +2153 9 +3907 7 +621 2 +3047 5 +3107 6 +3363 7 +3685 2 +1547 1 +979 7 +974 3 +2389 3 +2831 8 +2506 3 +1606 3 +1470 5 +1346 4 +591 10 +1795 1 +1332 7 +4040 6 +297 8 +1954 4 +3511 6 +1782 7 +1520 9 +2969 5 +2671 9 +3977 7 +2638 4 +3619 7 +786 3 +3257 3 +763 4 +2652 6 +155 10 +599 1 +3494 7 +552 3 +3219 3 +1255 3 +1876 6 +3060 1 +900 6 +2407 3 +1507 1 +792 8 +1845 10 +2111 2 +2230 5 +2385 6 +2740 6 +2447 9 +911 1 +2998 4 +1109 4 +869 5 +1662 6 +4048 9 +914 8 +2359 10 +216 6 +378 8 +2837 1 +3926 10 +3501 3 +3393 6 +4007 1 +1902 4 +3258 5 +538 4 +2889 5 +2581 8 +2136 9 +719 5 +2366 6 +1234 6 +2322 10 +3818 3 +1252 1 +1789 6 +1990 9 +2398 1 +1553 6 +2756 9 +473 1 +3485 7 +3505 6 +1284 3 +2581 5 +1242 6 +1747 1 +942 9 +1096 3 +1135 3 +1890 1 +1320 8 +1667 1 +1116 2 +3184 7 +939 9 +3598 3 +526 4 +1118 1 +1665 1 +1227 10 +1265 4 +3687 10 +2978 10 +2239 2 +815 3 +2967 7 +1659 8 +3103 4 +1883 1 +3833 8 +1532 7 +643 7 +617 3 +3370 8 +3932 8 +747 4 +2065 4 +3693 10 +2748 8 +2243 1 +1536 4 +3248 9 +1416 4 +3548 5 +2847 3 +2237 4 +1162 6 +3825 5 +2114 10 +3252 6 +1964 9 +3489 3 +562 8 +202 1 +1575 3 +200 2 +3315 9 +1280 3 +2739 3 +1078 7 +3897 2 +1554 5 +1255 7 +1343 4 +1977 5 +1749 6 +2750 3 +2046 9 +3983 10 +3405 7 +922 5 +1938 2 +3494 6 +3635 2 +3980 3 +2397 8 +3953 1 +60 7 +1387 6 +362 3 +2219 2 +1653 10 +1805 10 +3002 8 +2108 6 +3855 7 +171 5 +3775 4 +1388 4 +709 4 +699 10 +1828 5 +3516 8 +312 4 +2154 10 +2842 7 +1965 3 +1431 9 +1067 8 +3379 9 +3313 4 +1866 9 +886 3 +3556 9 +3018 10 +179 8 +3483 6 +2181 7 +265 8 +2894 4 +760 9 +112 6 +2990 9 +850 4 +2042 10 +3815 5 +2783 10 +675 3 +2881 8 +677 6 +1226 4 +3428 5 +359 5 +579 3 +1254 6 +1816 6 +570 7 +3744 4 +44 9 +3334 5 +3261 8 +1909 6 +2931 1 +1659 3 +492 7 +1073 4 +887 2 +841 2 +2602 2 +3509 8 +603 10 +1714 4 +1821 3 +809 9 +224 1 +3666 3 +3812 6 +3970 3 +3649 6 +50 3 +3019 4 +337 5 +2172 7 +1856 3 +3381 3 +2345 5 +2569 8 +1495 1 +143 4 +822 3 +1152 4 +325 6 +1158 4 +969 1 +2245 7 +4003 2 +1184 8 +1384 7 +2700 5 +638 2 +2678 5 +318 9 +285 4 +266 6 +4054 4 +2122 6 +2459 1 +3677 8 +2581 6 +1368 8 +2160 3 +3780 4 +620 1 +2793 4 +457 7 +3707 3 +857 5 +2506 9 +99 10 +1180 9 +2180 9 +1890 7 +4050 3 +1183 5 +2802 1 +3624 2 +1006 6 +2492 5 +1166 5 +3142 7 +543 7 +2801 3 +2949 10 +1413 8 +2872 6 +2388 10 +1403 6 +2665 8 +2479 9 +3318 7 +110 8 +3980 6 +738 10 +3142 10 +1171 10 +790 10 +3130 10 +964 8 +606 8 +2039 1 +3452 8 +1297 5 +3460 2 +3782 6 +1166 9 +4016 10 +2143 1 +4041 10 +2028 9 +3978 6 +3559 7 +1250 5 +2541 9 +2820 7 +1870 1 +560 3 +819 7 +1609 7 +2502 9 +390 10 +1708 3 +118 1 +521 6 +3816 6 +3859 4 +1345 6 +2919 9 +2643 7 +1412 5 +1989 10 +2703 6 +2515 1 +2868 3 +3693 7 +455 7 +1093 2 +2679 2 +2363 9 +3000 1 +2765 5 +290 7 +1684 7 +3626 6 +3971 5 +1148 6 +2333 3 +747 9 +2110 2 +3879 6 +2762 9 +2628 2 +1588 3 +1640 5 +2527 8 +1003 6 +3761 8 +2203 1 +941 5 +1764 10 +1998 7 +1486 5 +1778 9 +1418 6 +337 1 +3546 9 +362 5 +2899 7 +3449 4 +3803 8 +950 7 +1249 8 +2378 9 +99 10 +1556 4 +2744 2 +3619 2 +2238 9 +3069 9 +3224 7 +1837 7 +2342 1 +1946 9 +4086 6 +1742 9 +1820 1 +1183 10 +1308 4 +3928 6 +1287 9 +3580 8 +44 1 +2977 6 +1350 9 +1425 7 +1066 2 +2408 9 +1575 2 +2153 5 +3102 4 +135 9 +2758 3 +3540 9 +2125 2 +3796 5 +1795 4 +2676 8 +2096 10 +1415 9 +1715 7 +698 4 +3273 7 +1510 4 +2942 7 +2997 9 +2941 7 +2202 3 +4062 10 +590 1 +3500 5 +627 10 +2489 2 +581 3 +1042 8 +1675 6 +43 7 +131 2 +3194 2 +819 4 +1607 7 +3809 1 +2648 8 +3470 2 +2942 9 +2001 5 +1924 7 +3722 5 +222 9 +3344 5 +3909 2 +2361 2 +2594 4 +1451 9 +3194 6 +1582 4 +120 9 +2885 1 +2690 5 +1055 3 +2236 2 +3249 2 +1360 7 +2533 9 +1395 8 +3741 7 +1236 4 +2317 1 +1469 10 +3676 5 +1420 7 +1500 5 +2717 6 +2934 2 +2777 9 +1271 6 +1889 1 +1360 4 +1969 2 +1 8 +1097 2 +285 2 +3900 9 +98 6 +2889 8 +1734 3 +1370 4 +3999 2 +2008 2 +3511 9 +978 6 +3747 7 +1106 8 +804 3 +2414 6 +1744 1 +3141 4 +2357 5 +2289 7 +628 6 +2054 3 +1367 8 +1695 2 +4061 4 +1786 5 +3531 7 +33 5 +742 1 +2882 7 +2326 9 +3730 8 +2581 5 +309 10 +1523 5 +2461 9 +1090 10 +245 9 +1961 8 +3826 4 +54 4 +1745 10 +505 6 +2734 4 +2879 7 +1429 9 +1780 10 +3763 8 +2085 2 +3185 5 +2030 3 +2534 4 +919 4 +2008 5 +2816 5 +27 10 +416 3 +2021 5 +243 10 +40 8 +2354 7 +1027 7 +4095 2 +2714 8 +470 10 +588 4 +772 2 +3791 7 +3294 5 +835 5 +449 8 +3746 3 +3762 4 +1143 1 +3125 7 +3422 8 +1590 4 +685 9 +4014 7 +1522 1 +2477 1 +214 7 +1584 3 +519 8 +906 5 +1375 1 +1575 2 +893 9 +3991 2 +4075 3 +2622 7 +153 7 +3756 6 +3697 7 +1795 10 +595 8 +629 9 +2880 9 +1810 5 +588 8 +2662 2 +1139 10 +569 5 +1782 2 +3787 7 +3767 1 +1391 3 +627 8 +2146 8 +2783 6 +2053 9 +1052 3 +1296 7 +634 10 +705 6 +2795 4 +2854 2 +1760 1 +3363 10 +1466 5 +56 5 +851 1 +2764 7 +1497 3 +1736 5 +1941 6 +2446 10 +241 2 +229 10 +3804 6 +3108 5 +1487 9 +3061 1 +858 5 +2141 9 +2349 4 +3767 9 +1256 4 +1550 6 +3940 3 +1370 8 +1105 10 +3710 8 +1315 6 +2278 9 +997 2 +214 7 +2548 6 +2822 7 +1375 9 +2782 7 +3766 9 +581 7 +876 5 +3832 4 +2883 5 +2986 7 +4065 7 +3648 8 +145 1 +1937 4 +4011 3 +1086 10 +3544 8 +1886 10 +237 7 +3133 2 +364 3 +819 1 +781 5 +2542 5 +2604 7 +2559 6 +3899 10 +3298 2 +966 5 +395 9 +3784 1 +4078 8 +2710 3 +4042 7 +3175 10 +2684 9 +3774 7 +383 2 +3091 6 +4046 1 +3959 8 +3781 1 +2175 6 +740 6 +411 5 +1898 6 +2382 8 +547 8 +3019 3 +523 6 +283 9 +3178 3 +1883 7 +2690 1 +3197 8 +1920 4 +146 7 +3725 7 +1329 2 +917 9 +1706 7 +3474 6 +1181 6 +2814 4 +3708 7 +1462 4 +878 7 +269 4 +3182 2 +2670 3 +2691 10 +2122 9 +2636 7 +1210 10 +3383 4 +1149 2 +653 3 +1396 1 +2248 5 +3643 1 +1201 2 +2968 5 +2970 8 +175 5 +1271 10 +2576 10 +2053 1 +1152 4 +2494 4 +1518 8 +3679 3 +41 9 +948 3 +3693 10 +140 9 +1344 2 +4017 4 +1112 4 +1346 7 +715 6 +2235 3 +775 5 +3889 4 +366 5 +1064 2 +890 10 +2363 3 +3281 4 +1309 10 +3842 9 +2127 1 +1367 5 +1636 1 +3201 9 +823 4 +708 9 +1983 9 +1512 3 +2129 2 +501 7 +1491 6 +3694 4 +2763 10 +2142 8 +4078 10 +3497 3 +880 2 +2604 7 +3884 5 +336 2 +2806 2 +1601 10 +1318 8 +189 1 +3017 6 +2059 10 +53 9 +340 1 +804 1 +508 9 +2675 10 +2330 8 +3161 10 +2351 5 +1687 1 +1371 3 +2029 5 +2386 6 +131 3 +986 10 +666 5 +2479 2 +3762 3 +1889 6 +120 8 +171 10 +2181 7 +2300 7 +1117 2 +3836 3 +1859 9 +2446 2 +842 5 +2529 2 +1749 4 +1705 8 +757 7 +664 6 +3193 2 +82 3 +1006 9 +2332 1 +3011 5 +4090 7 +2689 7 +1373 4 +2161 4 +3314 10 +1193 5 +1015 8 +2770 7 +2225 6 +621 5 +128 4 +137 7 +2432 6 +2231 2 +2693 3 +1964 9 +654 4 +943 10 +995 8 +2439 7 +2169 6 +662 5 +832 7 +1131 1 +1045 5 +3220 9 +506 2 +2067 4 +915 7 +658 6 +3416 6 +1950 8 +2760 3 +2297 7 +4051 10 +1467 1 +2248 2 +2795 2 +1615 9 +772 4 +3245 4 +288 7 +834 5 +3795 4 +2689 2 +2726 3 +2606 10 +1767 5 +72 10 +2680 4 +2656 4 +2325 6 +3643 8 +3035 8 +1738 8 +684 3 +3832 8 +3728 1 +2275 10 +3107 10 +685 3 +3846 4 +1982 3 +1690 1 +2032 6 +1210 8 +1781 2 +3382 2 +2247 1 +690 1 +3735 1 +1611 1 +2958 1 +3543 2 +3484 7 +3383 4 +1395 1 +2098 9 +1474 5 +89 6 +509 7 +1644 4 +600 8 +462 10 +59 4 +946 6 +2324 6 +2871 1 +996 6 +1638 2 +323 7 +3103 6 +2134 7 +1541 5 +2401 4 +1727 6 +3397 8 +1731 5 +3671 1 +3651 8 +3635 6 +2892 2 +2833 8 +2641 8 +3525 2 +3738 2 +3686 10 +3111 2 +278 4 +1384 10 +548 3 +3772 7 +3536 6 +481 5 +3748 10 +4052 7 +572 7 +2653 7 +3797 4 +3867 10 +1799 1 +2206 3 +1947 4 +870 4 +1611 6 +2400 6 +438 10 +2292 2 +2975 2 +2863 3 +3747 10 +3738 2 +1865 4 +2427 6 +3084 6 +4044 4 +1387 6 +3262 1 +693 7 +1125 10 +797 5 +1355 9 +957 6 +3781 10 +2182 1 +1077 10 +70 9 +930 7 +3118 5 +1067 2 +926 7 +3068 5 +2984 3 +2713 7 +3882 1 +3359 4 +2119 6 +692 10 +3093 10 +3144 3 +1783 10 +2775 8 +732 5 +2138 4 +291 5 +830 8 +3752 5 +3154 7 +613 10 +1945 10 +1703 7 +3138 4 +3954 8 +3963 5 +1989 6 +3506 2 +2544 8 +556 8 +3623 6 +1378 1 +1324 9 +21 6 +164 10 +1064 8 +1277 5 +3024 2 +3754 8 +2917 2 +3126 10 +2715 9 +50 3 +495 2 +2961 1 +921 3 +2361 7 +43 8 +2014 10 +568 3 +2542 1 +1475 2 +2515 10 +2829 4 +672 9 +3836 1 +607 4 +744 8 +2107 7 +3118 8 +885 10 +800 10 +1649 8 +772 2 +3713 10 +2800 7 +1421 9 +2111 1 +367 3 +1137 4 +2645 10 +1226 4 +1095 8 +3364 10 +2810 8 +3614 8 +767 4 +3589 1 +340 5 +2647 5 +3762 7 +2526 6 +844 2 +2353 10 +1499 2 +1824 8 +4043 8 +1580 9 +2023 8 +581 7 +2697 9 +3806 7 +3330 2 +2796 4 +106 7 +1667 6 +3121 9 +491 8 +1080 6 +959 9 +961 2 +3875 9 +1256 4 +2327 2 +3024 5 +3579 8 +635 1 +4051 8 +364 9 +737 5 +1404 5 +3039 4 +1559 5 +3169 3 +3517 6 +2128 4 +3883 4 +1955 1 +983 4 +1682 3 +2348 3 +445 9 +949 1 +1529 1 +3623 8 +836 1 +464 6 +2192 2 +3156 2 +2592 10 +648 6 +763 6 +1012 3 +3458 1 +3242 4 +2700 1 +3724 10 +3058 10 +432 3 +2621 10 +1386 1 +3954 8 +713 3 +3324 5 +3680 9 +3210 9 +3257 4 +2281 4 +2674 1 +3355 8 +3129 1 +1323 3 +3924 10 +337 6 +1993 4 +1410 5 +3095 2 +3873 10 +3867 4 +3841 9 +1699 9 +2316 7 +2441 1 +1398 5 +1372 8 +3995 4 +2726 7 +861 9 +1707 7 +3939 10 +776 1 +1101 9 +2112 6 +2337 1 +1129 3 +109 1 +2993 5 +1271 7 +1855 5 +1510 6 +2564 9 +1272 1 +2118 5 +746 5 +598 6 +1460 1 +3752 4 +2891 2 +841 9 +2446 10 +1140 10 +540 1 +3855 5 +2087 4 +2580 2 +1335 2 +1649 7 +4039 5 +3382 10 +477 10 +1215 5 +2158 1 +1163 9 +614 8 +3517 3 +2429 3 +3744 5 +342 9 +3027 1 +2399 6 +3211 4 +917 8 +513 10 +1910 1 +2413 1 +25 9 +605 7 +689 7 +273 9 +2299 8 +720 2 +1356 4 +1476 8 +3038 8 +1046 1 +638 5 +3954 7 +3113 5 +2904 3 +2826 7 +366 2 +1060 1 +3101 4 +3623 1 +1046 6 +1648 8 +2319 10 +2580 7 +2740 7 +2132 8 +77 8 +1541 7 +431 1 +2630 6 +1872 7 +1048 9 +3717 2 +1889 7 +2224 4 +1570 1 +3920 3 +2350 1 +1044 10 +873 9 +1551 10 +3882 1 +2499 2 +2603 6 +2066 10 +843 8 +3173 1 +2002 7 +1935 3 +1349 6 +2279 9 +3933 8 +4052 6 +1380 3 +3553 5 +3262 1 +1718 10 +2127 5 +3522 8 +218 2 +3081 6 +2212 8 +1414 4 +217 6 +3319 10 +4093 9 +60 2 +1841 9 +2929 3 +465 2 +3793 6 +1815 6 +3592 3 +649 1 +1222 9 +3654 9 +1126 9 +1883 3 +2413 6 +3066 10 +784 2 +403 6 +2530 8 +2289 4 +3445 1 +3904 1 +1237 6 +1146 4 +2062 10 +1773 2 +483 7 +389 10 +3913 9 +3234 4 +2214 5 +3441 4 +3730 3 +1729 5 +20 3 +1698 6 +2113 1 +2545 9 +1532 9 +3480 2 +3967 10 +202 1 +3625 10 +906 1 +2771 9 +1194 4 +3498 10 +2758 2 +1058 1 +2733 3 +1833 8 +3340 8 +2451 3 +597 8 +3409 9 +3920 5 +2411 4 +3056 6 +181 9 +2203 2 +893 2 +2040 9 +1594 1 +1887 6 +2415 7 +2968 8 +1160 4 +54 1 +2270 7 +3801 8 +3270 4 +2981 6 +1512 6 +2325 6 +2816 3 +3150 7 +4048 2 +2805 8 +3535 7 +3593 10 +3500 10 +3281 2 +1360 10 +3597 4 +2721 4 +343 10 +258 4 +1255 9 +1939 8 +2824 1 +1726 3 +3129 7 +2754 1 +1694 2 +1952 8 +4061 2 +89 3 +1078 9 +2207 1 +771 4 +3160 6 +2529 10 +1275 10 +3569 7 +2421 7 +1878 8 +221 5 +2530 5 +2271 10 +1718 5 +2790 3 +1023 5 +1544 8 +1108 5 +191 1 +2823 8 +3379 8 +289 2 +1688 5 +4060 3 +2126 9 +3701 2 +1720 5 +2772 6 +3700 2 +2136 8 +1689 7 +3815 4 +224 2 +1875 2 +2927 5 +1911 7 +1582 3 +1257 5 +434 1 +457 1 +2981 4 +198 8 +3030 3 +3133 9 +2475 8 +3167 4 +690 6 +1754 8 +2109 6 +35 1 +3007 6 +1491 7 +2420 3 +2540 1 +3714 3 +1454 4 +2217 8 +2945 8 +3523 3 +2892 4 +2897 6 +1730 5 +4003 4 +2276 8 +3587 7 +3226 6 +0 7 +916 4 +903 8 +3079 5 +1591 3 +1633 1 +1316 2 +3577 8 +2644 7 +893 2 +77 4 +140 7 +2672 6 +1022 6 +1499 2 +1639 10 +1104 1 +737 2 +1403 8 +159 2 +1386 9 +1607 8 +277 10 +2007 7 +1950 3 +6 7 +3642 10 +897 2 +2337 8 +2005 9 +1552 10 +2996 9 +2807 3 +3706 3 +2722 7 +738 3 +3131 4 +769 5 +839 9 +579 3 +376 3 +127 7 +2292 9 +2064 6 +293 3 +2664 7 +3159 1 +1316 3 +3741 10 +2200 2 +3235 8 +1615 6 +3673 2 +2027 1 +2041 3 +2158 9 +502 3 +3259 6 +2920 9 +2991 9 +750 5 +595 10 +77 4 +3058 10 +21 2 +2507 2 +1414 7 +2714 7 +2649 1 +2054 8 +2386 10 +2074 4 +3972 9 +1599 3 +984 3 +910 2 +1353 7 +103 8 +1232 2 +1963 3 +3550 5 +1089 3 +83 8 +2172 8 +2716 8 +2012 4 +3828 4 +3398 8 +60 3 +3319 5 +258 3 +2440 10 +1001 6 +1323 7 +3974 5 +3416 9 +2292 3 +3393 7 +3653 10 +826 8 +165 2 +2911 3 +2145 10 +3586 7 +2063 1 +3343 4 +429 1 +1006 10 +3920 10 +3762 8 +3335 5 +911 2 +2266 7 +3226 4 +3291 8 +2664 9 +2491 5 +3306 8 +3442 1 +1825 10 +640 6 +1598 8 +3616 1 +3793 3 +2566 10 +1866 7 +2764 6 +2351 7 +1548 9 +322 4 +2280 1 +3559 8 +1545 9 +3684 3 +1570 7 +3097 8 +858 6 +3959 6 +1860 1 +2740 2 +1148 9 +3830 1 +2356 8 +2609 4 +1264 2 +3457 5 +413 5 +327 4 +1687 1 +749 1 +1883 9 +1180 10 +337 5 +498 7 +28 9 +1865 1 +3618 1 +1249 9 +1827 7 +1126 6 +725 5 +3055 5 +1678 4 +803 4 +1274 4 +892 1 +1335 1 +17 1 +2755 8 +1539 8 +263 10 +3628 2 +1536 6 +3625 2 +2750 8 +1723 3 +754 2 +1215 1 +2468 5 +1915 7 +2581 5 +2083 2 +2500 6 +1408 1 +3553 7 +491 7 +2703 10 +3716 10 +2080 6 +3910 6 +2597 1 +2884 10 +2393 2 +3050 6 +353 3 +2432 3 +1449 8 +1730 9 +3401 8 +2603 3 +3666 5 +3757 7 +3451 6 +2631 3 +3513 4 +2051 3 +249 6 +100 8 +3249 1 +2676 8 +3349 2 +595 9 +260 3 +1321 2 +613 1 +609 6 +733 9 +3565 3 +2844 5 +1077 4 +1335 5 +56 6 +1635 1 +749 8 +3556 7 +3628 10 +707 3 +1128 9 +4037 8 +2115 9 +500 9 +205 7 +3402 6 +3212 4 +2871 5 +3626 10 +2295 1 +1035 10 +576 2 +804 6 +3995 8 +444 1 +172 7 +426 3 +2358 6 +790 2 +354 6 +707 6 +821 5 +3885 2 +1713 8 +3784 6 +3039 8 +558 8 +3662 4 +1602 6 +3633 5 +3148 7 +2544 1 +2897 2 +1868 8 +2020 5 +4075 9 +3637 8 +3963 6 +2467 10 +2682 8 +86 8 +3390 2 +3339 4 +1037 7 +89 10 +2146 5 +1745 6 +3121 6 +2060 1 +3569 6 +357 4 +1103 1 +111 1 +3413 2 +1193 8 +563 5 +2826 8 +3744 7 +375 6 +1013 6 +1568 6 +2868 3 +1608 7 +1941 10 +968 6 +3423 8 +2918 7 +1782 6 +2209 1 +167 1 +2760 8 +1729 10 +1217 4 +2875 2 +2347 7 +1611 7 +2309 3 +119 2 +723 10 +3352 8 +4079 1 +1694 7 +1800 7 +2296 4 +2053 3 +2343 1 +3538 8 +1106 1 +240 3 +3200 10 +538 6 +2704 9 +3566 4 +3644 7 +3603 3 +2059 10 +1172 1 +3726 8 +2693 2 +1746 9 +220 3 +1058 1 +2733 5 +346 1 +3561 8 +2016 7 +1905 7 +1291 2 +794 3 +2621 1 +2879 7 +1422 8 +3040 5 +966 6 +346 3 +4074 8 +3107 3 +250 6 +1903 7 +1823 7 +1941 3 +1193 8 +656 3 +3856 10 +3578 9 +1671 3 +1408 1 +3973 4 +1335 5 +2952 3 +3572 1 +567 7 +2517 3 +3453 4 +3350 10 +2637 9 +3576 9 +3449 2 +1793 1 +3411 3 +2143 7 +1627 10 +1174 7 +342 6 +850 5 +2827 5 +1367 3 +2783 8 +364 3 +1103 6 +3247 3 +2149 3 +2201 3 +2631 5 +4090 3 +3626 7 +1042 2 +972 6 +1913 4 +143 10 +2251 5 +1762 5 +2310 4 +2592 8 +1443 4 +1123 3 +716 9 +3583 7 +2524 5 +3119 10 +23 9 +1015 6 +3945 4 +4069 3 +3508 4 +3067 9 +693 1 +262 8 +2509 6 +2148 6 +2193 9 +1492 6 +2472 6 +895 8 +2772 10 +400 2 +786 2 +2090 1 +2208 3 +479 9 +356 4 +2267 8 +1695 8 +792 9 +2903 5 +3171 6 +1243 9 +2349 2 +3895 10 +491 10 +3972 7 +713 2 +3522 4 +2937 8 +1718 7 +1770 8 +807 5 +3955 1 +270 9 +2996 1 +647 5 +1867 7 +3583 1 +3476 10 +1452 10 +3630 10 +1799 4 +711 10 +1450 10 +3530 6 +635 10 +2022 7 +495 8 +3385 10 +1741 7 +1236 2 +643 5 +4066 5 +3752 6 +875 9 +3582 1 +2377 7 +2184 10 +3864 5 +1079 3 +3044 10 +3813 2 +3966 9 +629 5 +2299 6 +1582 2 +1480 5 +3984 1 +1689 1 +1082 2 +3190 8 +646 1 +1348 5 +589 7 +1961 2 +2145 6 +1364 2 +2677 1 +188 1 +2570 4 +2986 4 +3024 1 +223 2 +3571 7 +2605 6 +919 8 +479 6 +1142 2 +199 8 +2507 4 +3255 9 +1555 3 +1862 4 +1569 8 +4003 2 +969 8 +2461 5 +678 7 +1907 9 +1502 3 +2990 4 +1026 5 +3877 6 +2041 9 +3876 1 +301 7 +432 3 +2509 6 +928 6 +1432 2 +3112 6 +3095 4 +1818 5 +2142 5 +3986 1 +32 7 +1349 4 +2403 1 +1060 5 +1802 7 +555 9 +4018 4 +3565 7 +2161 10 +2194 4 +3926 7 +2095 9 +3729 3 +217 7 +352 10 +2548 8 +3679 6 +2553 3 +1063 10 +1533 2 +3447 6 +1027 10 +712 6 +1118 5 +3083 10 +873 9 +3612 4 +2727 5 +729 1 +1895 3 +2700 9 +4078 6 +4089 7 +3265 7 +1583 1 +3546 5 +2689 2 +1640 4 +3344 7 +134 4 +3114 3 +2242 4 +2980 1 +1594 4 +3626 4 +3225 8 +3137 4 +1634 1 +2588 7 +3933 1 +844 1 +1466 2 +3288 9 +3192 1 +1987 2 +2357 6 +16 5 +2817 10 +128 2 +1160 10 +2992 10 +2502 5 +3972 9 +2395 3 +1275 7 +625 4 +907 2 +2265 7 +3172 4 +3225 7 +77 3 +2146 2 +2817 2 +3845 9 +3691 8 +600 8 +611 2 +417 7 +2645 10 +75 9 +711 1 +564 4 +151 4 +3541 8 +3038 3 +3912 9 +3342 3 +9 9 +1553 10 +3576 6 +1170 4 +98 6 +2700 6 +3086 3 +2591 2 +413 7 +2521 8 +3016 7 +1118 7 +4000 10 +1018 8 +722 10 +3952 1 +3646 7 +3920 4 +448 7 +3415 2 +2990 2 +984 5 +1211 5 +1659 8 +1928 3 +1319 2 +774 3 +3266 8 +752 7 +2279 10 +2854 6 +2941 9 +3060 2 +2874 1 +3549 1 +3379 8 +751 7 +3009 5 +3099 2 +233 1 +3321 3 +1889 4 +2192 9 +3140 3 +1338 2 +1980 1 +3517 6 +1434 1 +1576 9 +3398 10 +1951 8 +3785 2 +3229 10 +497 7 +1914 9 +82 7 +2467 10 +1546 10 +3857 9 +1230 9 +266 3 +1664 6 +3702 4 +480 8 +3512 5 +123 5 +3271 7 +3467 3 +3861 9 +455 8 +1743 9 +2004 2 +726 7 +4059 6 +2982 10 +681 3 +3533 6 +2857 3 +2731 10 +3075 10 +217 1 +2691 9 +2311 9 +30 1 +2142 2 +3943 6 +1285 2 +1664 5 +3455 5 +3493 3 +467 4 +1220 3 +439 7 +2905 8 +718 10 +795 6 +2965 8 +2864 1 +2547 8 +2790 6 +832 9 +1498 1 +1664 10 +1942 8 +878 6 +2726 6 +1088 10 +174 8 +25 10 +3262 8 +1573 6 +3861 3 +2993 1 +3965 1 +2892 6 +1820 6 +339 7 +157 3 +2762 7 +76 5 +3179 9 +1356 9 +686 2 +3302 3 +3262 6 +2467 6 +500 10 +3046 10 +736 2 +649 3 +2925 10 +3501 5 +238 6 +1303 1 +913 9 +693 3 +2173 3 +1814 8 +3080 7 +3560 4 +3904 2 +1921 9 +2389 7 +2600 8 +2192 10 +1275 8 +3306 6 +287 10 +3722 4 +363 3 +240 10 +602 7 +1671 3 +1677 7 +789 10 +2319 1 +2771 1 +585 10 +91 3 +2105 7 +3282 2 +3942 9 +2825 3 +26 9 +3405 8 +3732 1 +1612 10 +983 5 +1469 9 +2819 2 +2995 10 +890 2 +3616 8 +814 3 +2376 4 +3578 4 +3499 8 +3319 8 +2801 3 +3953 6 +3239 2 +870 5 +2468 8 +2992 2 +3429 3 +2117 10 +1945 6 +1143 1 +469 5 +2804 9 +2309 9 +2124 4 +1763 6 +3604 3 +3640 1 +2045 8 +2531 5 +2763 3 +2395 1 +2323 2 +1081 10 +2078 10 +1731 2 +364 9 +1714 9 +578 7 +1469 6 +1905 10 +129 2 +389 1 +94 8 +2873 9 +1124 6 +824 2 +3386 5 +1700 2 +3658 9 +2415 8 +1264 5 +4028 8 +1663 8 +1435 10 +4002 5 +3274 6 +2072 1 +3006 2 +376 10 +3595 9 +3275 10 +1755 1 +548 4 +232 5 +3179 3 +1100 7 +772 8 +3330 5 +3967 3 +1494 7 +1770 4 +2269 8 +896 2 +1058 8 +1698 8 +3801 9 +1633 6 +667 9 +2153 9 +3867 1 +3617 4 +415 2 +671 3 +1993 1 +3368 1 +2161 3 +3957 3 +1938 4 +3215 10 +12 4 +1450 4 +3852 3 +3372 9 +1514 5 +2308 8 +1153 2 +422 5 +1824 10 +1575 1 +3979 9 +3026 2 +3162 6 +3247 3 +1939 5 +191 9 +2677 8 +3849 3 +3871 9 +1269 4 +2867 10 +2521 1 +110 7 +2569 6 +3901 9 +1302 1 +1441 2 +150 3 +4029 10 +1336 6 +243 8 +3365 10 +3901 9 +1297 2 +3664 5 +3507 7 +1263 8 +3142 10 +2079 3 +642 1 +2478 3 +3766 10 +2993 9 +3337 5 +2224 7 +1444 4 +2939 7 +1226 2 +866 1 +957 4 +3813 9 +982 4 +2114 1 +247 7 +2946 3 +744 6 +923 4 +3534 4 +2790 7 +2840 4 +1963 8 +916 6 +592 4 +2187 5 +1236 5 +2522 7 +139 1 +3331 5 +1705 6 +683 10 +3383 3 +2377 10 +523 3 +3815 9 +3822 3 +541 8 +2128 1 +431 3 +1719 4 +3104 6 +2394 1 +1679 6 +1341 1 +1555 10 +2818 6 +1818 2 +3978 6 +3784 5 +211 8 +28 3 +2160 6 +2290 8 +1029 1 +500 4 +664 9 +964 10 +1349 10 +260 6 +3889 1 +224 9 +3846 1 +3442 3 +1542 4 +1834 10 +137 6 +1918 4 +3657 4 +16 5 +3626 10 +762 5 +1907 10 +1306 6 +976 5 +31 9 +2618 5 +643 2 +2273 4 +1515 8 +196 4 +754 10 +1134 8 +892 3 +1800 9 +1698 8 +2326 8 +4061 4 +370 3 +3209 3 +3852 9 +2499 8 +195 5 +1606 4 +2600 9 +1248 10 +3417 8 +691 6 +3882 9 +2000 5 +3657 10 +1219 8 +1453 5 +1806 8 +2896 6 +10 4 +2545 6 +3165 7 +3882 2 +2855 10 +3935 1 +3647 9 +71 8 +3790 1 +1891 8 +514 2 +3790 6 +2152 5 +3046 2 +594 8 +2930 6 +2927 10 +1739 1 +2559 7 +3408 2 +1081 3 +771 10 +506 3 +3537 6 +2946 8 +3995 7 +1245 7 +2097 5 +3222 9 +137 1 +3918 9 +1969 5 +1077 4 +527 2 +317 7 +1836 3 +1238 9 +582 6 +2554 4 +2292 2 +1106 7 +1709 5 +3980 2 +2134 9 +3310 1 +3476 9 +132 4 +3924 6 +3875 2 +2794 1 +3632 1 +728 2 +3674 1 +3873 9 +3649 4 +1185 7 +2722 3 +485 10 +272 6 +1181 5 +3942 6 +4013 5 +65 10 +3027 7 +2131 2 +390 9 +82 2 +2018 1 +3598 5 +2083 9 +1188 4 +1583 2 +736 8 +2779 7 +2101 3 +1522 8 +674 5 +3751 2 +1947 3 +4044 9 +2536 9 +191 8 +3053 9 +2025 1 +2984 4 +33 1 +1426 2 +514 7 +2972 5 +3109 4 +3106 6 +2568 2 +2309 7 +3966 7 +2344 5 +1173 5 +1885 5 +2939 7 +3867 1 +3595 4 +4083 5 +1132 2 +2868 1 +950 5 +3194 4 +2220 5 +3917 4 +580 10 +1304 10 +1540 5 +3223 10 +825 3 +1436 4 +3907 1 +2911 9 +15 3 +3371 5 +1200 3 +1092 10 +916 8 +668 7 +4035 6 +2062 7 +1581 9 +804 2 +3293 9 +2459 7 +2831 10 +2755 10 +2931 4 +3780 10 +4013 1 +1060 6 +3093 6 +238 6 +440 1 +85 5 +375 8 +622 3 +803 2 +2099 10 +2261 7 +2677 10 +2598 8 +1134 3 +3503 2 +1761 6 +2114 10 +278 4 +2703 8 +1153 7 +818 5 +3369 4 +144 5 +1992 1 +2033 2 +1942 2 +44 9 +3582 10 +354 10 +4004 1 +3363 5 +2129 1 +3445 7 +1353 7 +46 6 +1934 2 +3555 9 +2423 2 +1947 8 +3976 7 +3853 9 +124 4 +3854 9 +1633 5 +102 10 +3302 7 +1801 9 +423 4 +1740 1 +2919 2 +404 10 +2831 9 +2348 10 +2235 1 +1242 7 +2536 10 +2623 10 +655 5 +634 4 +218 9 +757 5 +1516 10 +3683 1 +1746 4 +3826 2 +2137 6 +191 4 +2889 6 +1793 3 +3265 7 +2244 4 +1057 8 +1190 8 +1085 9 +286 6 +644 10 +3189 6 +3934 1 +1957 3 +34 4 +1837 6 +3480 7 +2206 1 +747 2 +1688 3 +2107 6 +3892 1 +3119 1 +2198 8 +2862 7 +1662 1 +1857 8 +1132 6 +3316 3 +1877 1 +3550 2 +2671 7 +190 10 +1450 1 +2910 10 +1173 1 +3742 6 +1907 7 +2345 8 +580 8 +0 2 +1920 7 +2737 3 +1030 2 +2061 9 +2704 7 +3309 4 +1204 1 +777 1 +81 10 +906 10 +1049 4 +3803 9 +3684 9 +1256 6 +1970 9 +2133 3 +1968 1 +1532 2 +2992 1 +3285 10 +829 2 +156 8 +2882 10 +120 8 +499 10 +1962 3 +2202 7 +4015 8 +2883 6 +327 4 +2502 9 +8 6 +1896 6 +2862 1 +1220 4 +3890 4 +58 3 +2273 1 +2074 10 +3090 5 +200 6 +2522 2 +624 1 +592 5 +1190 4 +3879 9 +84 6 +1193 10 +1612 2 +3239 7 +254 2 +3689 5 +2560 10 +422 3 +3726 10 +617 6 +3673 3 +3806 4 +143 10 +1326 9 +952 5 +211 4 +3346 10 +2984 3 +80 3 +2045 1 +371 9 +2921 4 +1924 5 +2656 8 +3435 9 +3882 6 +1410 4 +967 4 +3102 1 +2018 10 +1122 9 +3656 10 +653 2 +1418 4 +1107 3 +2603 6 +3792 7 +721 6 +3489 10 +1092 9 +1186 8 +3296 5 +2136 2 +2847 5 +1660 3 +417 2 +3312 9 +1811 8 +2537 6 +2928 10 +1383 5 +2939 2 +2065 9 +1781 7 +3544 6 +1042 6 +342 10 +2704 9 +2433 6 +194 4 +2000 9 +2886 9 +1010 2 +2869 2 +1508 9 +157 3 +2606 4 +1790 4 +2353 6 +1723 9 +429 5 +3385 5 +2976 2 +409 7 +585 3 +3346 4 +3500 8 +636 4 +478 5 +921 2 +2642 4 +3195 5 +3676 8 +3798 1 +1651 7 +16 6 +228 4 +1168 8 +2865 7 +726 8 +839 10 +3906 1 +2140 9 +3875 1 +636 9 +4087 1 +1551 6 +3299 6 +1899 9 +3215 9 +2406 1 +3391 2 +4087 1 +1259 4 +3409 7 +450 7 +2905 3 +1733 6 +647 1 +2220 10 +1894 2 +744 8 +189 7 +2138 5 +2569 1 +2941 4 +1627 6 +234 3 +3382 9 +3326 9 +283 4 +3659 10 +3223 3 +1083 2 +21 5 +3083 6 +98 7 +3288 7 +198 2 +3577 3 +1638 1 +2968 7 +251 9 +2460 1 +2706 3 +1224 8 +1773 7 +995 5 +770 7 +1972 6 +1375 8 +3830 9 +754 2 +2173 8 +627 7 +1797 6 +3883 6 +1402 5 +1736 6 +3818 6 +1851 6 +3316 7 +2677 7 +663 6 +593 3 +2773 6 +2694 1 +1355 6 +2838 4 +1222 7 +4049 4 +2128 1 +1802 9 +1112 8 +1812 4 +3774 4 +1166 8 +725 4 +2677 7 +2281 9 +1746 4 +2493 7 +641 8 +11 5 +1462 4 +2250 10 +166 2 +2528 10 +961 7 +263 10 +3339 3 +2827 4 +1732 9 +2883 7 +859 7 +861 2 +3158 2 +561 2 +12 3 +4009 3 +1000 8 +1035 2 +2937 1 +629 6 +4084 6 +633 2 +2601 6 +2352 6 +1079 3 +438 7 +3352 1 +3240 8 +2414 6 +2520 7 +3806 1 +1134 5 +1567 4 +2601 6 +827 5 +2418 5 +1640 8 +934 6 +2003 2 +1361 9 +977 7 +3833 6 +3506 1 +1192 1 +857 5 +1151 7 +21 10 +3669 7 +3653 8 +2881 1 +1425 2 +3634 8 +2023 2 +1825 4 +3340 9 +377 8 +3265 8 +1108 10 +2393 5 +3781 1 +316 2 +1475 10 +2501 1 +232 3 +3331 4 +1765 3 +2788 1 +3280 3 +2253 10 +2090 7 +3222 7 +2724 1 +1265 2 +3847 3 +855 7 +1994 8 +3149 10 +1469 6 +2450 4 +2419 7 +946 4 +2779 8 +711 10 +3970 3 +229 5 +782 9 +2264 9 +3732 6 +3980 8 +770 4 +2639 7 +2716 10 +3583 8 +3474 1 +2085 5 +1121 2 +2257 2 +3388 2 +1328 7 +916 3 +2169 2 +2166 10 +3003 7 +2230 8 +2713 4 +176 8 +869 8 +1994 1 +912 2 +313 4 +3754 6 +2763 4 +714 6 +3634 5 +3327 4 +1620 9 +2297 1 +231 9 +1057 3 +1101 2 +1041 4 +691 3 +2083 10 +485 7 +3271 10 +1475 4 +3822 1 +3339 7 +3785 9 +3305 10 +1931 3 +3387 10 +3887 7 +3685 10 +3844 3 +1839 9 +2068 5 +170 3 +3234 9 +3413 1 +317 6 +1483 5 +2165 8 +3199 6 +3312 6 +1195 5 +1172 8 +896 1 +58 10 +3517 3 +1279 4 +653 6 +1822 7 +2863 8 +1141 8 +3424 9 +3958 3 +655 6 +404 5 +294 2 +186 6 +3461 4 +1354 7 +3243 1 +3536 5 +3069 3 +3268 6 +1595 10 +2915 9 +3721 9 +2327 4 +3800 9 +2860 7 +2215 2 +3780 7 +3230 4 +46 1 +370 6 +866 5 +2080 3 +3315 1 +1324 5 +1029 3 +3766 4 +1751 6 +1476 2 +986 8 +2803 1 +2111 4 +2338 2 +3724 5 +1879 4 +1931 10 +2497 10 +1532 10 +2527 4 +3131 10 +1814 9 +1523 1 +3901 7 +2319 4 +2899 9 +1437 3 +1660 7 +585 10 +3484 7 +2269 8 +738 6 +2207 9 +2969 4 +1485 4 +211 6 +2838 4 +3531 6 +2513 9 +3864 6 +2400 7 +1134 10 +454 10 +3850 9 +208 9 +1813 1 +3291 10 +3528 6 +3959 8 +1339 8 +3506 3 +3121 6 +761 2 +22 1 +364 1 +2628 8 +3881 2 +2965 1 +2716 4 +2487 7 +2730 9 +3318 6 +629 6 +1007 6 +435 4 +1478 5 +3141 2 +1374 8 +678 2 +1904 1 +1834 1 +1269 7 +3504 10 +2939 8 +2599 2 +1427 3 +3212 8 +3345 2 +3406 7 +1938 1 +989 4 +3785 1 +934 1 +437 6 +881 4 +122 4 +3791 1 +2000 7 +1631 7 +1329 7 +164 3 +3300 5 +3287 9 +3086 3 +2094 8 +804 7 +2223 3 +595 3 +530 8 +1273 5 +786 5 +2472 7 +740 2 +2264 7 +673 9 +2361 7 +1326 1 +547 1 +2008 3 +1050 8 +1852 3 +2884 3 +602 9 +937 2 +2085 3 +516 7 +2260 5 +2234 5 +1887 10 +2430 4 +2722 7 +1956 4 +2459 1 +2905 9 +3195 6 +3568 2 +597 7 +167 2 +2975 8 +812 7 +2980 8 +2173 1 +1286 9 +414 10 +2575 9 +3431 2 +218 5 +509 4 +599 8 +2253 2 +2425 8 +1903 7 +1882 3 +3459 6 +3750 8 +3879 7 +3658 4 +93 3 +2907 10 +4093 5 +4046 10 +2553 3 +628 5 +353 4 +2955 6 +1148 4 +1622 10 +421 5 +1751 5 +3036 2 +465 6 +771 4 +2380 5 +1939 9 +3015 7 +1858 8 +268 8 +2522 1 +3363 6 +1936 8 +1255 3 +3555 2 +2728 6 +4022 1 +299 2 +3805 10 +2651 5 +1905 4 +1401 5 +454 9 +814 10 +2090 8 +2793 10 +568 9 +3842 5 +2281 3 +2515 4 +1920 8 +1894 5 +1752 8 +306 3 +3519 2 +3708 4 +213 4 +2748 10 +588 8 +1499 2 +2297 5 +3789 2 +126 9 +681 1 +3899 1 +1572 10 +475 7 +625 10 +1258 4 +1460 5 +2488 5 +481 7 +2448 9 +820 3 +2882 10 +3490 1 +2711 3 +644 10 +31 3 +2255 1 +2522 9 +627 8 +22 10 +2711 7 +1282 10 +2480 1 +3949 3 +2798 2 +1383 9 +2992 5 +1491 2 +1989 5 +2155 2 +3580 3 +1215 5 +2340 8 +1715 3 +3344 5 +3397 5 +1089 8 +2778 10 +3895 1 +321 10 +958 6 +3883 5 +1945 1 +3373 3 +1180 6 +1698 4 +3567 7 +3144 9 +783 5 +2923 7 +3221 10 +2758 8 +3915 8 +1535 2 +3194 3 +1792 9 +572 9 +3530 10 +2444 5 +2855 2 +768 7 +1914 7 +821 5 +1860 1 +2994 7 +2926 3 +3594 4 +1054 9 +406 8 +2511 8 +3791 4 +220 1 +2195 6 +242 9 +42 4 +1349 7 +2944 3 +1880 2 +1480 6 +1805 10 +2634 5 +3381 3 +1064 5 +3218 8 +3391 10 +3118 10 +330 1 +2075 1 +2774 10 +3123 9 +983 3 +2024 4 +3016 7 +425 9 +3109 5 +899 1 +2521 1 +4000 1 +2850 2 +3023 7 +2190 2 +3453 9 +4093 7 +3034 7 +747 8 +2485 3 +2066 9 +2052 1 +3465 3 +2692 4 +2116 2 +546 3 +448 4 +2518 2 +3365 1 +1695 9 +253 6 +164 5 +2151 7 +3215 6 +837 7 +553 9 +2582 3 +2285 5 +592 7 +1127 5 +482 8 +2803 9 +652 5 +3119 1 +1567 3 +1987 5 +379 2 +1883 10 +3841 8 +4038 6 +453 6 +2498 8 +224 8 +629 2 +411 5 +3853 10 +3104 2 +405 3 +1898 4 +1693 3 +109 2 +469 2 +496 4 +217 7 +632 7 +1710 6 +125 10 +1567 2 +2568 7 +2245 9 +3151 7 +2354 2 +1887 5 +1005 2 +2726 7 +1361 7 +1381 3 +1383 3 +3041 6 +2252 1 +346 4 +759 5 +2045 9 +2877 8 +2281 7 +2373 1 +3292 4 +657 4 +988 6 +3893 6 +1043 9 +788 8 +1341 4 +664 9 +1247 10 +3285 7 +2839 10 +670 10 +593 10 +3427 3 +238 7 +3747 8 +2380 5 +146 2 +2775 10 +2790 1 +2458 7 +791 9 +4028 6 +3665 5 +1495 5 +2756 2 +1237 9 +2449 4 +1139 6 +3249 10 +2747 9 +1513 8 +4050 1 +3195 1 +1455 9 +3482 6 +2337 4 +1523 2 +1430 6 +1146 5 +1655 8 +4057 6 +1455 5 +191 7 +1671 7 +2028 5 +3530 10 +395 9 +2020 4 +3583 7 +950 5 +1105 9 +816 10 +2189 7 +2677 4 +9 2 +483 10 +1606 1 +2663 10 +2964 1 +1523 8 +3645 8 +7 1 +729 2 +185 9 +1680 6 +3629 4 +3886 9 +1507 8 +2202 10 +1123 4 +1048 8 +2469 8 +2455 9 +1450 3 +4064 10 +2044 6 +180 9 +2370 7 +3996 10 +398 9 +1462 1 +1442 10 +3583 1 +2750 9 +1643 4 +2951 6 +79 7 +421 3 +2778 4 +3693 2 +1015 8 +773 3 +3014 1 +1025 10 +3488 9 +3026 3 +3108 9 +3945 4 +62 9 +590 7 +2486 7 +1035 6 +3525 3 +1705 2 +2160 4 +873 10 +4040 1 +1300 10 +442 2 +3648 8 +2035 5 +3611 10 +3103 5 +447 7 +1494 7 +1342 8 +3676 6 +1441 2 +2882 3 +3626 7 +3349 2 +979 4 +960 9 +2272 8 +2477 6 +1631 2 +2462 10 +1635 1 +3521 4 +1538 10 +915 2 +1891 1 +356 2 +3373 9 +81 8 +900 7 +3236 4 +3149 6 +83 8 +890 6 +1643 8 +714 1 +4041 6 +365 6 +1457 7 +1521 2 +2580 5 +2290 9 +471 7 +1491 5 +1655 2 +2727 5 +3081 3 +2307 2 +3816 6 +1678 9 +1613 1 +1890 7 +3107 1 +217 9 +863 10 +1852 6 +554 9 +567 2 +3700 3 +3559 4 +3870 4 +3695 2 +276 7 +2593 5 +1009 8 +329 7 +1381 9 +2848 2 +3548 10 +2045 4 +512 3 +2469 3 +791 3 +1518 10 +4088 10 +997 1 +4045 10 +825 10 +1449 7 +3425 2 +2816 10 +3579 7 +1068 9 +653 8 +1616 6 +2336 6 +1459 10 +3783 5 +2128 3 +2882 5 +2405 2 +200 4 +1164 9 +2094 10 +1884 8 +1645 7 +1624 2 +2066 7 +1488 4 +1136 3 +2658 10 +2102 3 +1189 7 +3775 3 +1370 7 +3049 5 +272 10 +2760 10 +954 2 +3127 3 +2438 8 +2670 3 +3395 4 +274 9 +2558 5 +1144 7 +2557 5 +647 2 +2018 1 +1909 2 +2846 7 +467 10 +2055 8 +3092 7 +1822 3 +3765 8 +336 2 +610 10 +362 8 +3569 3 +1180 1 +3754 9 +1901 5 +1909 6 +884 3 +2760 10 +74 3 +635 4 +1752 10 +2238 3 +663 4 +3229 2 +1013 3 +1376 3 +1501 4 +2606 2 +3462 1 +326 3 +305 8 +846 9 +990 2 +3598 10 +3582 8 +3796 6 +1731 1 +3279 6 +3472 9 +60 7 +1910 8 +2982 7 +3372 10 +2114 10 +541 7 +294 8 +2316 5 +3760 1 +1284 4 +2374 5 +2717 1 +1313 8 +932 5 +3137 2 +1373 7 +4088 5 +1820 4 +2512 7 +2813 6 +2251 4 +1727 10 +704 6 +483 10 +3281 9 +1622 2 +1284 3 +1293 1 +3241 7 +1508 10 +696 2 +2944 4 +3889 5 +1075 10 +1680 8 +1084 9 +2060 10 +2892 7 +900 5 +2589 7 +1025 4 +3950 6 +953 1 +455 2 +1016 7 +1344 7 +2688 8 +467 9 +2597 9 +2859 8 +2643 8 +3544 6 +1000 8 +225 4 +1473 9 +2134 2 +26 10 +623 7 +2449 9 +479 2 +3936 1 +935 7 +1490 7 +885 7 +437 7 +3937 1 +1729 4 +3078 7 +2020 6 +330 9 +4064 10 +1392 10 +2589 2 +4080 5 +2785 9 +2570 9 +3420 7 +2709 2 +261 1 +2595 8 +2383 8 +1986 1 +991 5 +3796 7 +63 6 +2499 6 +2323 2 +3772 3 +960 1 +1186 1 +3358 3 +2414 8 +940 7 +3606 7 +802 1 +1913 5 +2900 10 +2078 1 +864 2 +3210 3 +4023 7 +3678 9 +1792 10 +3996 5 +2024 4 +2605 7 +2645 3 +1420 5 +3328 9 +2147 9 +2813 2 +1841 3 +3458 9 +777 5 +3564 2 From 2e61dad11faeff4b9d2f6d53de46fc1eaacbcbbd Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Fri, 28 Jun 2024 09:48:04 -0400 Subject: [PATCH 44/75] Update README.md Update TOOLDIR to vortex-toolchain-2024-6-14/ --- README.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index cd517b2b5..aebbed455 100644 --- a/README.md +++ b/README.md @@ -67,13 +67,8 @@ More detailed build instructions can be found [here](docs/install_vortex.md). mkdir out export OUT_DIR=`pwd`/out cd build - ../configure --xlen=32 --tooldir=/software/vortex-toolchain-2024-05-22 --prefix=$OUT_DIR -### Ignore the commit for ramulator when it is compiled - # Please add ignore = dirty entry on .gitmodules - [submodule "third_party/ramulator"] - path = third_party/ramulator - url = https://github.com/CMU-SAFARI/ramulator.git - ignore = dirty + ../configure --xlen=32 --tooldir=/software/vortex-toolchain-2024-6-14 --prefix=$OUT_DIR + ### Install prebuilt toolchain # We will use the precomipled tools in volvo toolchanin directory ### set environment variables From 6d480b3da1587ee3fadc958fa0292bec2f86140d Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Sun, 30 Jun 2024 00:35:26 -0400 Subject: [PATCH 45/75] satp_ is not set, then we skip VAT --- runtime/simx/vortex.cpp | 24 ++++++++++++---------- sim/common/mem.cpp | 44 +++++++++++++++++++++++++++-------------- sim/common/mem.h | 9 +++++++-- sim/simx/emulator.h | 3 --- sim/simx/processor.cpp | 14 +++++++++++-- sim/simx/processor.h | 1 + 6 files changed, 63 insertions(+), 32 deletions(-) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index ae9fe5bb5..fc686ca76 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -121,21 +121,25 @@ public: } bool need_trans(uint64_t dev_pAddr) { - // Check if the this is the BARE mode - bool isBAREMode = (get_mode() == BARE); + + // Check if the satp is set and BARE mode + if (processor_.is_satp_unset() || get_mode() == BARE) + return 0; + // Check if the address is reserved for system usage // bool isReserved = (PAGE_TABLE_BASE_ADDR <= dev_pAddr && dev_pAddr < PAGE_TABLE_BASE_ADDR + PT_SIZE_LIMIT); - bool isReserved = (PAGE_TABLE_BASE_ADDR <= dev_pAddr); + if (PAGE_TABLE_BASE_ADDR <= dev_pAddr) + return 0; + // Check if the address is reserved for IO usage - bool isIO = (dev_pAddr < USER_BASE_ADDR); + if (dev_pAddr < USER_BASE_ADDR) + return 0; // Check if the address falls within the startup address range - bool isStartAddress = (STARTUP_ADDR <= dev_pAddr) && (dev_pAddr <= (STARTUP_ADDR + 0x40000)); + if ((STARTUP_ADDR <= dev_pAddr) && (dev_pAddr <= (STARTUP_ADDR + 0x40000))) + return 0; - // Print the boolean results for debugging purposes - // printf("%p, %u, %u\n", (void *)dev_pAddr, isReserved, isStartAddress); - - // Return true if the address needs translation (i.e., it's not reserved and not a start address) - return (!isBAREMode && !isReserved && !isIO && !isStartAddress); + // Now all conditions are not met. Return true because the address needs translation + return 1; } uint64_t phy_to_virt_map(uint64_t size, uint64_t *dev_pAddr, uint32_t flags) diff --git a/sim/common/mem.cpp b/sim/common/mem.cpp index f3c1025a2..a5339be6e 100644 --- a/sim/common/mem.cpp +++ b/sim/common/mem.cpp @@ -596,16 +596,26 @@ void RAM::loadHexImage(const char* filename) { uint64_t MemoryUnit::get_base_ppn() { + assert(satp_!= NULL); return satp_->get_base_ppn(); } uint64_t MemoryUnit::get_satp() { - return satp_->get_satp(); + if (is_satp_unset()) + return 0; + else + return satp_->get_satp(); +} + +uint8_t MemoryUnit::is_satp_unset() +{ + return (satp_==NULL); } uint8_t MemoryUnit::get_mode() { + assert(satp_!= NULL); return satp_->get_mode(); } void MemoryUnit::set_satp(uint64_t satp) @@ -616,22 +626,26 @@ void MemoryUnit::set_satp(uint64_t satp) bool MemoryUnit::need_trans(uint64_t dev_pAddr) { - // Check if the this is the BARE mode - bool isBAREMode = (get_mode() == BARE); - // Check if the address is reserved for system usage - // bool isReserved = (PAGE_TABLE_BASE_ADDR <= dev_pAddr && dev_pAddr < PAGE_TABLE_BASE_ADDR + PT_SIZE_LIMIT); - bool isReserved = (PAGE_TABLE_BASE_ADDR <= dev_pAddr); - // Check if the address is reserved for IO usage - bool isIO= (dev_pAddr < USER_BASE_ADDR); - // Check if the address falls within the startup address range - bool isStartAddress = (STARTUP_ADDR <= dev_pAddr) && (dev_pAddr <= (STARTUP_ADDR + 0x40000)); - - // Print the boolean results for debugging purposes - // printf("%p, %u, %u\n", (void *)dev_pAddr, isReserved, isStartAddress); + // Check if the satp is set and BARE mode + if ( is_satp_unset() || (get_mode() == BARE)) + return 0; - // Return true if the address needs translation (i.e., it's not reserved and not a start address) - return (!isBAREMode && !isReserved && !isIO && !isStartAddress); + // Check if the address is reserved for system usage + // bool isReserved = (PAGE_TABLE_BASE_ADDR <= dev_pAddr && dev_pAddr < PAGE_TABLE_BASE_ADDR + PT_SIZE_LIMIT); + if (PAGE_TABLE_BASE_ADDR <= dev_pAddr) + return 0; + + // Check if the address is reserved for IO usage + if (dev_pAddr < USER_BASE_ADDR) + return 0; + // Check if the address falls within the startup address range + if ((STARTUP_ADDR <= dev_pAddr) && (dev_pAddr <= (STARTUP_ADDR + 0x40000))) + return 0; + + // Now all conditions are not met. Return true because the address needs translation + return 1; } + uint64_t MemoryUnit::vAddr_to_pAddr(uint64_t vAddr, ACCESS_TYPE type) { uint64_t pfn; diff --git a/sim/common/mem.h b/sim/common/mem.h index 9f212e184..7ef13393a 100644 --- a/sim/common/mem.h +++ b/sim/common/mem.h @@ -186,8 +186,12 @@ public: }; #ifdef VM_ENABLE - MemoryUnit(uint64_t pageSize = MEM_PAGE_SIZE); - ~MemoryUnit(){delete this->satp_;}; + MemoryUnit(uint64_t pageSize = MEM_PAGE_SIZE) :satp_(NULL) + {}; + ~MemoryUnit(){ + if ( this->satp_ != NULL) + delete this->satp_; + }; #else MemoryUnit(uint64_t pageSize = 0); #endif @@ -208,6 +212,7 @@ public: #ifdef VM_ENABLE void tlbAdd(uint64_t virt, uint64_t phys, uint32_t flags, uint64_t size_bits); + uint8_t is_satp_unset(); uint64_t get_satp(); uint8_t get_mode(); uint64_t get_base_ppn(); diff --git a/sim/simx/emulator.h b/sim/simx/emulator.h index f5c785581..0b2d6ac03 100644 --- a/sim/simx/emulator.h +++ b/sim/simx/emulator.h @@ -125,9 +125,6 @@ private: uint32_t ipdom_size_; Word csr_mscratch_; wspawn_t wspawn_; -#ifdef VM_ENABLE - Word ptbr_; -#endif }; } diff --git a/sim/simx/processor.cpp b/sim/simx/processor.cpp index 751db635e..01023125b 100644 --- a/sim/simx/processor.cpp +++ b/sim/simx/processor.cpp @@ -145,12 +145,17 @@ ProcessorImpl::PerfStats ProcessorImpl::perf_stats() const { Processor::Processor(const Arch& arch) : impl_(new ProcessorImpl(arch)) -{} +{ +#ifdef VM_ENABLE + satp_ = NULL; +#endif +} Processor::~Processor() { delete impl_; #ifdef VM_ENABLE - delete satp_; + if (satp_ != NULL) + delete satp_; #endif } @@ -176,10 +181,15 @@ int16_t Processor::set_satp_by_addr(uint64_t base_addr) { impl_->set_satp(satp); return 0; } +bool Processor::is_satp_unset() { + return (satp_== NULL); +} uint8_t Processor::get_satp_mode() { + assert (satp_!=NULL); return satp_->get_mode(); } uint64_t Processor::get_base_ppn() { + assert (satp_!=NULL); return satp_->get_base_ppn(); } #endif diff --git a/sim/simx/processor.h b/sim/simx/processor.h index a20cfff0b..8315eedba 100644 --- a/sim/simx/processor.h +++ b/sim/simx/processor.h @@ -37,6 +37,7 @@ public: void dcr_write(uint32_t addr, uint32_t value); #ifdef VM_ENABLE + bool is_satp_unset(); uint8_t get_satp_mode(); uint64_t get_base_ppn(); int16_t set_satp_by_addr(uint64_t addr); From 52233fe13a25ef8d3de0e1c1816bcb944193a6ac Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Sun, 30 Jun 2024 00:54:22 -0400 Subject: [PATCH 46/75] fixed compile error --- sim/common/mem.cpp | 3 ++- sim/common/mem.h | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sim/common/mem.cpp b/sim/common/mem.cpp index a5339be6e..e3c9b5cc4 100644 --- a/sim/common/mem.cpp +++ b/sim/common/mem.cpp @@ -144,7 +144,8 @@ MemoryUnit::MemoryUnit(uint64_t pageSize) , TLB_HIT(0) , TLB_MISS(0) , TLB_EVICT(0) - , PTW(0) {}; + , PTW(0) + , satp_(NULL) {}; #else { if (pageSize != 0) diff --git a/sim/common/mem.h b/sim/common/mem.h index 7ef13393a..617e83d69 100644 --- a/sim/common/mem.h +++ b/sim/common/mem.h @@ -186,8 +186,7 @@ public: }; #ifdef VM_ENABLE - MemoryUnit(uint64_t pageSize = MEM_PAGE_SIZE) :satp_(NULL) - {}; + MemoryUnit(uint64_t pageSize = MEM_PAGE_SIZE); ~MemoryUnit(){ if ( this->satp_ != NULL) delete this->satp_; From 5877cfe8aef4479137079d678b84dbf6a6f11db6 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Sun, 30 Jun 2024 03:10:36 -0400 Subject: [PATCH 47/75] Change STARTUP_ADDR from 0x40000000 to 0x80000000(32b) and 0x180000000(64b) --- ci/regression.sh.in | 6 +++++- runtime/simx/vortex.cpp | 6 +----- sim/common/mem.cpp | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ci/regression.sh.in b/ci/regression.sh.in index 4c7e9967a..600fffe91 100755 --- a/ci/regression.sh.in +++ b/ci/regression.sh.in @@ -219,7 +219,11 @@ config2() # custom program startup address make -C tests/regression/dogfood clean-kernel - STARTUP_ADDR=0x40000000 make -C tests/regression/dogfood + if [ "$XLEN" == "64" ]; then + STARTUP_ADDR=0x180000000 make -C tests/regression/dogfood + else + STARTUP_ADDR=0x80000000 make -C tests/regression/dogfood + fi ./ci/blackbox.sh --driver=simx --app=dogfood ./ci/blackbox.sh --driver=rtlsim --app=dogfood make -C tests/regression/dogfood clean-kernel diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index fc686ca76..08261fcd7 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -144,7 +144,6 @@ public: uint64_t phy_to_virt_map(uint64_t size, uint64_t *dev_pAddr, uint32_t flags) { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); DBGPRINT(" [RT:PTV_MAP] size = 0x%lx, dev_pAddr= 0x%lx, flags = 0x%x\n", size, *dev_pAddr, flags); DBGPRINT(" [RT:PTV_MAP] bit mode: %d\n", XLEN); @@ -178,10 +177,8 @@ public: } DBGPRINT(" [RT:PTV_MAP] Mapped virtual addr: 0x%lx to physical addr: 0x%lx\n", init_vAddr, init_pAddr); // Sanity check - uint64_t pAddr = page_table_walk(init_vAddr); - DBGPRINT(" [RT:PTV_MAP] physical addr from PTW: 0x%lx\n", pAddr); + assert(page_table_walk(init_vAddr) == init_pAddr && "ERROR: translated virtual Addresses are not the same with physical Address\n"); - assert(pAddr == init_pAddr && "ERROR: translated virtual Addresses are not the same with physical Address\n"); *dev_pAddr = init_vAddr; // commit vpn to be returned to host DBGPRINT(" [RT:PTV_MAP] Translated device virtual addr: 0x%lx\n", *dev_pAddr); @@ -255,7 +252,6 @@ public: int upload(uint64_t dest_addr, const void *src, uint64_t size) { - // DBGPRINT("====%s====\n", __PRETTY_FUNCTION__); uint64_t asize = aligned_size(size, CACHE_BLOCK_SIZE); if (dest_addr + asize > GLOBAL_MEM_SIZE) return -1; diff --git a/sim/common/mem.cpp b/sim/common/mem.cpp index e3c9b5cc4..e6e998fce 100644 --- a/sim/common/mem.cpp +++ b/sim/common/mem.cpp @@ -23,11 +23,11 @@ using namespace vortex; #ifdef VM_ENABLE -#ifndef NDEBUG -#define DBGPRINT(format, ...) do { printf("[VXDRV] " format "", ##__VA_ARGS__); } while (0) -#else +// #ifndef NDEBUG +// #define DBGPRINT(format, ...) do { printf("[VXDRV] " format "", ##__VA_ARGS__); } while (0) +// #else #define DBGPRINT(format, ...) ((void)0) -#endif +// #endif #endif From aa45f55126af5f5b08383f8a01c1f7ea679a5e4e Mon Sep 17 00:00:00 2001 From: Hanran Wu Date: Mon, 8 Jul 2024 17:07:30 -0400 Subject: [PATCH 48/75] vpn allocator added but doesn't pass any tests --- runtime/simx/vortex.cpp | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 08261fcd7..6f31a7ef6 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -114,10 +114,21 @@ public: } #ifdef VM_ENABLE - // virtual to phycial mapping - uint64_t map_p2v(uint64_t pAddr) + // virtual (vpn) to phycial (ppn) mapping + uint64_t map_p2v(uint64_t ppn, uint32_t flags) { - return pAddr + 0xf000000; + DBGPRINT(" [RT:MAP_P2V] ppn: %x\n", ppn); + // std::cout << std::hex << pAddr << std::endl; + // return pAddr + 0xf000000; + if (addr_mapping.find(ppn) != addr_mapping.end()) return addr_mapping[ppn]; + + // If ppn to vpn mapping doesnt exist, create mapping + DBGPRINT(" [RT:MAP_P2V] Not found. Allocate new page table or update a PTE.\n"); + uint64_t vpn; + virtual_mem_->allocate(MEM_PAGE_SIZE, &vpn); + CHECK_ERR(update_page_table(ppn, vpn, flags),); + addr_mapping[ppn] = vpn; + return vpn; } bool need_trans(uint64_t dev_pAddr) { @@ -154,7 +165,7 @@ public: } uint64_t init_pAddr = *dev_pAddr; - uint64_t init_vAddr = map_p2v(init_pAddr); + uint64_t init_vAddr = (map_p2v(init_pAddr >> MEM_PAGE_LOG2_SIZE, flags) << MEM_PAGE_LOG2_SIZE) & ((1 << MEM_PAGE_LOG2_SIZE) - 1); uint64_t ppn = 0, vpn = 0; // dev_pAddr can be of size greater than a page, but we have to map and update @@ -162,18 +173,11 @@ public: // FUTURE Work: Super Page for (ppn = (*dev_pAddr >> MEM_PAGE_LOG2_SIZE); ppn < ((*dev_pAddr) >> MEM_PAGE_LOG2_SIZE) + (size >> MEM_PAGE_LOG2_SIZE) ; ppn++) { - vpn = map_p2v(ppn << MEM_PAGE_LOG2_SIZE) >> MEM_PAGE_LOG2_SIZE; + + vpn = map_p2v(ppn << MEM_PAGE_LOG2_SIZE, flags) >> MEM_PAGE_LOG2_SIZE; DBGPRINT(" [RT:PTV_MAP] Search vpn in page table:0x%lx\n", vpn); // Currently a 1-1 mapping is used, this can be changed here to support different // mapping schemes - // If ppn to vpn mapping doesnt exist. - if (addr_mapping.find(vpn) == addr_mapping.end()) - { - // Create mapping. - DBGPRINT(" [RT:PTV_MAP] Not found. Allocate new page table or update a PTE.\n"); - CHECK_ERR(update_page_table(ppn, vpn, flags),); - addr_mapping[vpn] = ppn; - } } DBGPRINT(" [RT:PTV_MAP] Mapped virtual addr: 0x%lx to physical addr: 0x%lx\n", init_vAddr, init_pAddr); // Sanity check @@ -415,6 +419,13 @@ public: return 1; } + // HW: virtual mem allocator has the same address range as global_mem. next step is to adjust it + virtual_mem_ = new MemoryAllocator(ALLOC_BASE_ADDR >> MEM_PAGE_LOG2_SIZE, (GLOBAL_MEM_SIZE - ALLOC_BASE_ADDR) >> MEM_PAGE_LOG2_SIZE, MEM_PAGE_SIZE, CACHE_BLOCK_SIZE); + if (virtual_mem_ == nullptr) { + // virtual_mem_ does not intefere with physical mem, so no need to free space + return 1; + } + if (VM_ADDR_MODE == BARE) DBGPRINT("[RT:init_VM] VA_MODE = BARE MODE(addr= 0x0)"); else @@ -606,11 +617,12 @@ private: RAM ram_; Processor processor_; MemoryAllocator global_mem_; + MemoryAllocator* virtual_mem_; DeviceConfig dcrs_; std::future future_; std::unordered_map> mpm_cache_; #ifdef VM_ENABLE - std::unordered_map addr_mapping; + std::unordered_map addr_mapping; // HW: key: ppn; value: vpn MemoryAllocator* page_table_mem_; #endif }; From 7916684c3631148c0a0576dfe98e3ca347b64b3a Mon Sep 17 00:00:00 2001 From: Hanran Wu Date: Mon, 8 Jul 2024 17:10:19 -0400 Subject: [PATCH 49/75] vpn allocator debug complete, now pass demo&vecadd tests --- runtime/simx/vortex.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 6f31a7ef6..3f82e647d 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -165,7 +165,7 @@ public: } uint64_t init_pAddr = *dev_pAddr; - uint64_t init_vAddr = (map_p2v(init_pAddr >> MEM_PAGE_LOG2_SIZE, flags) << MEM_PAGE_LOG2_SIZE) & ((1 << MEM_PAGE_LOG2_SIZE) - 1); + uint64_t init_vAddr = (map_p2v(init_pAddr >> MEM_PAGE_LOG2_SIZE, flags) << MEM_PAGE_LOG2_SIZE) | (init_pAddr & ((1 << MEM_PAGE_LOG2_SIZE) - 1)); uint64_t ppn = 0, vpn = 0; // dev_pAddr can be of size greater than a page, but we have to map and update From 31133ae6e98ebe5b76552f830a938d116ebb7f55 Mon Sep 17 00:00:00 2001 From: Hanran Wu Date: Tue, 9 Jul 2024 13:42:57 -0400 Subject: [PATCH 50/75] update destructor of vx_device --- runtime/simx/vortex.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 3f82e647d..6757bffbf 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -66,6 +66,7 @@ public: global_mem_.release(PAGE_TABLE_BASE_ADDR); // for (auto i = addr_mapping.begin(); i != addr_mapping.end(); i++) // page_table_mem_->release(i->second << MEM_PAGE_SIZE); + delete virtual_mem_; delete page_table_mem_; #endif if (future_.valid()) { @@ -114,6 +115,7 @@ public: } #ifdef VM_ENABLE + // virtual (vpn) to phycial (ppn) mapping uint64_t map_p2v(uint64_t ppn, uint32_t flags) { @@ -130,6 +132,7 @@ public: addr_mapping[ppn] = vpn; return vpn; } + bool need_trans(uint64_t dev_pAddr) { @@ -423,6 +426,7 @@ public: virtual_mem_ = new MemoryAllocator(ALLOC_BASE_ADDR >> MEM_PAGE_LOG2_SIZE, (GLOBAL_MEM_SIZE - ALLOC_BASE_ADDR) >> MEM_PAGE_LOG2_SIZE, MEM_PAGE_SIZE, CACHE_BLOCK_SIZE); if (virtual_mem_ == nullptr) { // virtual_mem_ does not intefere with physical mem, so no need to free space + return 1; } From 49255bfa69c9435e70116f5629e8a90ec61f4c27 Mon Sep 17 00:00:00 2001 From: Hanran Wu Date: Wed, 10 Jul 2024 22:39:00 -0400 Subject: [PATCH 51/75] add virtual mem allocator addr spacereservation --- runtime/simx/vortex.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 6757bffbf..92ae2362d 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -407,6 +407,21 @@ public: return 0; } + // reserve IO space, startup space, and local mem area + int virtual_mem_reserve(uint64_t dev_addr, uint64_t size, int flags) + { + // uint64_t asize = aligned_size(size, MEM_PAGE_SIZE); + CHECK_ERR(virtual_mem_->reserve(dev_addr, size), { + return err; + }); + DBGPRINT("[RT:mem_reserve] addr: 0x%lx, size:0x%lx, size: 0x%lx\n", dev_addr, size, size); + // CHECK_ERR(this->mem_access(dev_addr, asize, flags), { + // global_mem_.release(dev_addr); + // return err; + // }); + return 0; + } + int16_t init_VM() { uint64_t pt_addr = 0; @@ -424,6 +439,16 @@ public: // HW: virtual mem allocator has the same address range as global_mem. next step is to adjust it virtual_mem_ = new MemoryAllocator(ALLOC_BASE_ADDR >> MEM_PAGE_LOG2_SIZE, (GLOBAL_MEM_SIZE - ALLOC_BASE_ADDR) >> MEM_PAGE_LOG2_SIZE, MEM_PAGE_SIZE, CACHE_BLOCK_SIZE); + CHECK_ERR(virtual_mem_reserve(PAGE_TABLE_BASE_ADDR >> MEM_PAGE_LOG2_SIZE, (GLOBAL_MEM_SIZE - PAGE_TABLE_BASE_ADDR) >> MEM_PAGE_LOG2_SIZE, VX_MEM_READ_WRITE), { + return err; + }); + CHECK_ERR(virtual_mem_reserve(0, USER_BASE_ADDR >> MEM_PAGE_LOG2_SIZE, VX_MEM_READ_WRITE), { + return err; + }); + CHECK_ERR(virtual_mem_reserve(STARTUP_ADDR >> MEM_PAGE_LOG2_SIZE, (STARTUP_ADDR + 0x40000) >> MEM_PAGE_LOG2_SIZE, VX_MEM_READ_WRITE), { + return err; + }); + if (virtual_mem_ == nullptr) { // virtual_mem_ does not intefere with physical mem, so no need to free space From 6add1e16f65e437471ab4028df8c260a72fbffd4 Mon Sep 17 00:00:00 2001 From: Hanran Wu Date: Thu, 11 Jul 2024 14:49:00 -0400 Subject: [PATCH 52/75] debugged virtual memory allocator --- runtime/simx/vortex.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 92ae2362d..01c84fab6 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -119,7 +119,7 @@ public: // virtual (vpn) to phycial (ppn) mapping uint64_t map_p2v(uint64_t ppn, uint32_t flags) { - DBGPRINT(" [RT:MAP_P2V] ppn: %x\n", ppn); + DBGPRINT(" [RT:MAP_P2V] ppn: %lx\n", ppn); // std::cout << std::hex << pAddr << std::endl; // return pAddr + 0xf000000; if (addr_mapping.find(ppn) != addr_mapping.end()) return addr_mapping[ppn]; @@ -128,6 +128,7 @@ public: DBGPRINT(" [RT:MAP_P2V] Not found. Allocate new page table or update a PTE.\n"); uint64_t vpn; virtual_mem_->allocate(MEM_PAGE_SIZE, &vpn); + vpn = vpn >> MEM_PAGE_LOG2_SIZE; CHECK_ERR(update_page_table(ppn, vpn, flags),); addr_mapping[ppn] = vpn; return vpn; @@ -176,8 +177,7 @@ public: // FUTURE Work: Super Page for (ppn = (*dev_pAddr >> MEM_PAGE_LOG2_SIZE); ppn < ((*dev_pAddr) >> MEM_PAGE_LOG2_SIZE) + (size >> MEM_PAGE_LOG2_SIZE) ; ppn++) { - - vpn = map_p2v(ppn << MEM_PAGE_LOG2_SIZE, flags) >> MEM_PAGE_LOG2_SIZE; + vpn = map_p2v(ppn, flags) >> MEM_PAGE_LOG2_SIZE; DBGPRINT(" [RT:PTV_MAP] Search vpn in page table:0x%lx\n", vpn); // Currently a 1-1 mapping is used, this can be changed here to support different // mapping schemes @@ -438,14 +438,11 @@ public: } // HW: virtual mem allocator has the same address range as global_mem. next step is to adjust it - virtual_mem_ = new MemoryAllocator(ALLOC_BASE_ADDR >> MEM_PAGE_LOG2_SIZE, (GLOBAL_MEM_SIZE - ALLOC_BASE_ADDR) >> MEM_PAGE_LOG2_SIZE, MEM_PAGE_SIZE, CACHE_BLOCK_SIZE); - CHECK_ERR(virtual_mem_reserve(PAGE_TABLE_BASE_ADDR >> MEM_PAGE_LOG2_SIZE, (GLOBAL_MEM_SIZE - PAGE_TABLE_BASE_ADDR) >> MEM_PAGE_LOG2_SIZE, VX_MEM_READ_WRITE), { + virtual_mem_ = new MemoryAllocator(ALLOC_BASE_ADDR, (GLOBAL_MEM_SIZE - ALLOC_BASE_ADDR), MEM_PAGE_SIZE, CACHE_BLOCK_SIZE); + CHECK_ERR(virtual_mem_reserve(PAGE_TABLE_BASE_ADDR, (GLOBAL_MEM_SIZE - PAGE_TABLE_BASE_ADDR), VX_MEM_READ_WRITE), { return err; }); - CHECK_ERR(virtual_mem_reserve(0, USER_BASE_ADDR >> MEM_PAGE_LOG2_SIZE, VX_MEM_READ_WRITE), { - return err; - }); - CHECK_ERR(virtual_mem_reserve(STARTUP_ADDR >> MEM_PAGE_LOG2_SIZE, (STARTUP_ADDR + 0x40000) >> MEM_PAGE_LOG2_SIZE, VX_MEM_READ_WRITE), { + CHECK_ERR(virtual_mem_reserve(STARTUP_ADDR, 0x40000, VX_MEM_READ_WRITE), { return err; }); @@ -646,13 +643,13 @@ private: RAM ram_; Processor processor_; MemoryAllocator global_mem_; - MemoryAllocator* virtual_mem_; DeviceConfig dcrs_; std::future future_; std::unordered_map> mpm_cache_; #ifdef VM_ENABLE std::unordered_map addr_mapping; // HW: key: ppn; value: vpn MemoryAllocator* page_table_mem_; + MemoryAllocator* virtual_mem_; #endif }; From 78fc053ad56672fe8622bb55c1fb09800c611053 Mon Sep 17 00:00:00 2001 From: Hanran Wu Date: Mon, 29 Jul 2024 14:35:11 -0400 Subject: [PATCH 53/75] save work before pull --- .travis.yml | 18 +++++++++++++++++- ci/regression.sh.in | 2 ++ runtime/include/vortex.h | 1 + runtime/simx/vortex.cpp | 11 ++++++++++- 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d43abb153..57098c8f0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -99,4 +99,20 @@ jobs: env: XLEN=32 script: - ./ci/travis_run.py ./ci/regression.sh --debug - - ./ci/travis_run.py ./ci/regression.sh --stress \ No newline at end of file + - ./ci/travis_run.py ./ci/regression.sh --stress + + - stage: test + name: virtual_memory + env: XLEN=32 + env: VM_DISABLE=1 + script: + - ./ci/travis_run.py ./ci/regression.sh --regression + - ./ci/travis_run.py ./ci/regression.sh --opencl + + - stage: test + name: virtual_memory + env: XLEN=64 + env: VM_DISABLE=1 + script: + - ./ci/travis_run.py ./ci/regression.sh --regression + - ./ci/travis_run.py ./ci/regression.sh --opencl \ No newline at end of file diff --git a/ci/regression.sh.in b/ci/regression.sh.in index 600fffe91..b3bf798cb 100755 --- a/ci/regression.sh.in +++ b/ci/regression.sh.in @@ -19,6 +19,8 @@ set -e # clear blackbox cache rm -f blackbox.*.cache +# HW: add a test "VM Test" to make sure VM feature is enabled + XLEN=${XLEN:=@XLEN@} echo "Vortex Regression Test: XLEN=$XLEN" diff --git a/runtime/include/vortex.h b/runtime/include/vortex.h index 8481002e1..957e5d62a 100644 --- a/runtime/include/vortex.h +++ b/runtime/include/vortex.h @@ -65,6 +65,7 @@ typedef void* vx_buffer_h; #define VX_MEM_READ 0x1 #define VX_MEM_WRITE 0x2 #define VX_MEM_READ_WRITE 0x3 +#define VX_MEM_PIN_MEMORY 0x4 // open the device and connect to it int vx_dev_open(vx_device_h* hdevice); diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 01c84fab6..5e54576a5 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -199,6 +199,7 @@ public: uint64_t addr = 0; DBGPRINT("[RT:mem_alloc] size: 0x%lx, asize, 0x%lx,flag : 0x%d\n", size, asize, flags); + // HW: when vm is supported this global_mem_ should be virtual memory allocator CHECK_ERR(global_mem_.allocate(asize, &addr), { return err; }); @@ -231,7 +232,7 @@ public: int mem_free(uint64_t dev_addr) { #ifdef VM_ENABLE - uint64_t paddr= page_table_walk(dev_addr); + uint64_t paddr = page_table_walk(dev_addr); return global_mem_.release(paddr); #else return global_mem_.release(dev_addr); @@ -264,6 +265,14 @@ public: return -1; #ifdef VM_ENABLE uint64_t pAddr = page_table_walk(dest_addr); + // uint64_t pAddr; + // try { + // pAddr = page_table_walk(dest_addr); + // } catch ( Page_Fault_Exception ) { + // // HW: place holder + // // should be virt_to_phy_map here + // phy_to_virt_map(0, dest_addr, 0); + // } DBGPRINT(" [RT:upload] Upload data to vAddr = 0x%lx (pAddr=0x%lx)\n", dest_addr, pAddr); dest_addr = pAddr; //Overwirte #endif From 8d978f23ce4eecb7f60411fdc2321df418b064d6 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Sat, 20 Jul 2024 10:25:33 -0400 Subject: [PATCH 54/75] Update runtime/simx/vortex.cpp Co-authored-by: Martin Troiber <34752929+troibe@users.noreply.github.com> --- runtime/simx/vortex.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 5e54576a5..7faae8bdd 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -120,8 +120,6 @@ public: uint64_t map_p2v(uint64_t ppn, uint32_t flags) { DBGPRINT(" [RT:MAP_P2V] ppn: %lx\n", ppn); - // std::cout << std::hex << pAddr << std::endl; - // return pAddr + 0xf000000; if (addr_mapping.find(ppn) != addr_mapping.end()) return addr_mapping[ppn]; // If ppn to vpn mapping doesnt exist, create mapping From 735b71361314683e01986b97f6a8b2e040a2dbf0 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Sat, 20 Jul 2024 10:34:24 -0400 Subject: [PATCH 55/75] Update runtime/simx/vortex.cpp Co-authored-by: Martin Troiber <34752929+troibe@users.noreply.github.com> --- runtime/simx/vortex.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 7faae8bdd..ea110e57a 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -422,10 +422,6 @@ public: return err; }); DBGPRINT("[RT:mem_reserve] addr: 0x%lx, size:0x%lx, size: 0x%lx\n", dev_addr, size, size); - // CHECK_ERR(this->mem_access(dev_addr, asize, flags), { - // global_mem_.release(dev_addr); - // return err; - // }); return 0; } From 34ef5009107e0a1736e8a085840ee6518348511c Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Sat, 20 Jul 2024 10:36:58 -0400 Subject: [PATCH 56/75] Update runtime/simx/vortex.cpp Co-authored-by: Martin Troiber <34752929+troibe@users.noreply.github.com> --- runtime/simx/vortex.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index ea110e57a..c8b7033e0 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -120,7 +120,7 @@ public: uint64_t map_p2v(uint64_t ppn, uint32_t flags) { DBGPRINT(" [RT:MAP_P2V] ppn: %lx\n", ppn); - if (addr_mapping.find(ppn) != addr_mapping.end()) return addr_mapping[ppn]; + if (addr_mapping.contains(ppn)) return addr_mapping[ppn]; // If ppn to vpn mapping doesnt exist, create mapping DBGPRINT(" [RT:MAP_P2V] Not found. Allocate new page table or update a PTE.\n"); From 9db3870309740bf26224849bf7f903ad66442293 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Sat, 20 Jul 2024 10:39:40 -0400 Subject: [PATCH 57/75] Update runtime/simx/vortex.cpp Co-authored-by: Martin Troiber <34752929+troibe@users.noreply.github.com> --- runtime/simx/vortex.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index c8b7033e0..b560d20d1 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -116,7 +116,7 @@ public: #ifdef VM_ENABLE - // virtual (vpn) to phycial (ppn) mapping + // physical (ppn) to virtual (vpn) mapping uint64_t map_p2v(uint64_t ppn, uint32_t flags) { DBGPRINT(" [RT:MAP_P2V] ppn: %lx\n", ppn); From 30258c04d216e674963e528fd2a44b752f186ed0 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Sat, 20 Jul 2024 11:20:27 -0400 Subject: [PATCH 58/75] Apply suggestions from code review Co-authored-by: Martin Troiber <34752929+troibe@users.noreply.github.com> --- runtime/simx/vortex.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index b560d20d1..f9143cf0f 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -417,7 +417,6 @@ public: // reserve IO space, startup space, and local mem area int virtual_mem_reserve(uint64_t dev_addr, uint64_t size, int flags) { - // uint64_t asize = aligned_size(size, MEM_PAGE_SIZE); CHECK_ERR(virtual_mem_->reserve(dev_addr, size), { return err; }); From 34f7e3c982929f5c148ff063ac83c234f44458c5 Mon Sep 17 00:00:00 2001 From: Hanran Wu Date: Tue, 30 Jul 2024 00:18:28 -0400 Subject: [PATCH 59/75] config ramulator2 --- third_party/ramulator | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/ramulator b/third_party/ramulator index 214f63584..e62c84a6f 160000 --- a/third_party/ramulator +++ b/third_party/ramulator @@ -1 +1 @@ -Subproject commit 214f635845214adf030367939655d172ef0fed5f +Subproject commit e62c84a6f0e06566ba6e182d308434b4532068a5 From 19b5496f00a31b77aba1e3169e9e68381f390efa Mon Sep 17 00:00:00 2001 From: Hanran Wu Date: Tue, 13 Aug 2024 17:54:06 -0400 Subject: [PATCH 60/75] modify makefile to only compile simx --- Makefile.in | 8 ++++++++ ci/toolchain_env.sh.in | 4 ++-- runtime/Makefile | 2 ++ sim/Makefile | 3 +++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Makefile.in b/Makefile.in index 82a2ebdb5..7f594747a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -2,6 +2,14 @@ include config.mk .PHONY: build software tests +vm: + $(MAKE) -C $(VORTEX_HOME)/third_party + $(MAKE) -C hw + $(MAKE) -C sim simx + $(MAKE) -C kernel + $(MAKE) -C runtime vm + $(MAKE) -C tests + all: $(MAKE) -C $(VORTEX_HOME)/third_party $(MAKE) -C hw diff --git a/ci/toolchain_env.sh.in b/ci/toolchain_env.sh.in index dc50389a9..be140d28d 100755 --- a/ci/toolchain_env.sh.in +++ b/ci/toolchain_env.sh.in @@ -16,8 +16,8 @@ TOOLDIR=${TOOLDIR:=@TOOLDIR@} -export VERILATOR_ROOT=$TOOLDIR/verilator -export PATH=$VERILATOR_ROOT/bin:$PATH +# export VERILATOR_ROOT=$TOOLDIR/verilator +# export PATH=$VERILATOR_ROOT/bin:$PATH export SV2V_PATH=$TOOLDIR/sv2v export PATH=$SV2V_PATH/bin:$PATH diff --git a/runtime/Makefile b/runtime/Makefile index e5f8af74c..aecac00e1 100644 --- a/runtime/Makefile +++ b/runtime/Makefile @@ -3,6 +3,8 @@ include $(ROOT_DIR)/config.mk all: stub rtlsim simx opae xrt +vm: stub simx + stub: $(MAKE) -C stub diff --git a/sim/Makefile b/sim/Makefile index e16486e8f..4d5ea89c1 100644 --- a/sim/Makefile +++ b/sim/Makefile @@ -1,6 +1,9 @@ ROOT_DIR := $(realpath ..) include $(ROOT_DIR)/config.mk +simx: + $(MAKE) -C simx + all: $(MAKE) -C simx $(MAKE) -C rtlsim From 7528dd9c0fc9cd7eb3bff92d427c0f765c88cab7 Mon Sep 17 00:00:00 2001 From: Hanran Wu Date: Tue, 13 Aug 2024 18:18:54 -0400 Subject: [PATCH 61/75] debug and remove travis.yml --- .travis.yml | 118 ---------------------------------------- runtime/simx/vortex.cpp | 2 +- 2 files changed, 1 insertion(+), 119 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 57098c8f0..000000000 --- a/.travis.yml +++ /dev/null @@ -1,118 +0,0 @@ -language: cpp -dist: focal -os: linux -compiler: gcc - -addons: - apt: - packages: - - build-essential - - valgrind - - libstdc++6 - - binutils - - python - - uuid-dev - -env: - global: - - TOOLDIR=$HOME/tools - -cache: - directories: - - $TOOLDIR - - $HOME/third_party - - $HOME/build32 - - $HOME/build64 - -before_install: - - if [ ! -d "$TOOLDIR" ] || [ -z "$(ls -A $TOOLDIR)" ] || [ "$(cat "$TOOLDIR/version.txt")" != "v0.4" ]; then - rm -rf $TOOLDIR; - mkdir -p $TRAVIS_BUILD_DIR/build && cd $TRAVIS_BUILD_DIR/build; - ../configure --tooldir=$TOOLDIR; - ci/toolchain_install.sh --all; - echo "v0.3" > "$TOOLDIR/version.txt"; - else - echo "using existing tooldir build"; - fi - - if [ ! -d "$HOME/third_party" ] || [ -z "$(ls -A $HOME/third_party)" ] || [ "$(cat "$HOME/third_party/version.txt")" != "v0.2" ]; then - cd $TRAVIS_BUILD_DIR; - make -C third_party > /dev/null; - echo "v0.2" > "third_party/version.txt"; - cp -rf third_party $HOME; - else - echo "using existing third_party build"; - cp -rf $HOME/third_party $TRAVIS_BUILD_DIR; - fi - -install: - - if [ ! -d "$HOME/build$XLEN" ] || [ -z "$(ls -A $HOME/build$XLEN)" ] || [ "$(cat "$HOME/build$XLEN/version.txt")" != "$TRAVIS_COMMIT" ]; then - mkdir -p $TRAVIS_BUILD_DIR/build$XLEN && cd $TRAVIS_BUILD_DIR/build$XLEN; - ../configure --tooldir=$TOOLDIR --xlen=$XLEN; - source ci/toolchain_env.sh; - make build -s > /dev/null; - echo "$TRAVIS_COMMIT" > version.txt; - cp -rf $TRAVIS_BUILD_DIR/build$XLEN $HOME; - else - echo "using existing build for commit $TRAVIS_COMMIT"; - cp -rf $HOME/build$XLEN $TRAVIS_BUILD_DIR; - fi - -before_script: - - cd $TRAVIS_BUILD_DIR/build$XLEN - - source ci/toolchain_env.sh - -stages: - - test - -jobs: - include: - - stage: test - name: regression32 - env: XLEN=32 - script: - - ./ci/travis_run.py ./ci/regression.sh --unittest - - ./ci/travis_run.py ./ci/regression.sh --isa - - ./ci/travis_run.py ./ci/regression.sh --kernel - - ./ci/travis_run.py ./ci/regression.sh --synthesis - - ./ci/travis_run.py ./ci/regression.sh --regression - - ./ci/travis_run.py ./ci/regression.sh --opencl - - - stage: test - name: regression64 - env: XLEN=64 - script: - - ./ci/travis_run.py ./ci/regression.sh --isa - - ./ci/travis_run.py ./ci/regression.sh --kernel - - ./ci/travis_run.py ./ci/regression.sh --synthesis - - ./ci/travis_run.py ./ci/regression.sh --regression - - ./ci/travis_run.py ./ci/regression.sh --opencl - - - stage: test - name: config - env: XLEN=32 - script: - - ./ci/travis_run.py ./ci/regression.sh --cluster - - ./ci/travis_run.py ./ci/regression.sh --config - - - stage: test - name: debug - env: XLEN=32 - script: - - ./ci/travis_run.py ./ci/regression.sh --debug - - ./ci/travis_run.py ./ci/regression.sh --stress - - - stage: test - name: virtual_memory - env: XLEN=32 - env: VM_DISABLE=1 - script: - - ./ci/travis_run.py ./ci/regression.sh --regression - - ./ci/travis_run.py ./ci/regression.sh --opencl - - - stage: test - name: virtual_memory - env: XLEN=64 - env: VM_DISABLE=1 - script: - - ./ci/travis_run.py ./ci/regression.sh --regression - - ./ci/travis_run.py ./ci/regression.sh --opencl \ No newline at end of file diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index f9143cf0f..e5ec36b60 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -120,7 +120,7 @@ public: uint64_t map_p2v(uint64_t ppn, uint32_t flags) { DBGPRINT(" [RT:MAP_P2V] ppn: %lx\n", ppn); - if (addr_mapping.contains(ppn)) return addr_mapping[ppn]; + if (addr_mapping.find(ppn) != addr_mapping.end()) return addr_mapping[ppn]; // If ppn to vpn mapping doesnt exist, create mapping DBGPRINT(" [RT:MAP_P2V] Not found. Allocate new page table or update a PTE.\n"); From 48ff4ee4e091981e5b046e6fda2ed16d2e198c41 Mon Sep 17 00:00:00 2001 From: Hanran Wu Date: Thu, 15 Aug 2024 16:34:36 -0400 Subject: [PATCH 62/75] add VM_ENABLE flag to configure&compilation --- config.mk.in | 4 +++- configure | 9 ++++++++- hw/rtl/VX_config.vh | 4 ---- kernel/Makefile | 4 ++++ runtime/simx/Makefile | 4 ++++ sim/simx/Makefile | 4 ++++ 6 files changed, 23 insertions(+), 6 deletions(-) diff --git a/config.mk.in b/config.mk.in index c1f67e5a9..6b20a3050 100644 --- a/config.mk.in +++ b/config.mk.in @@ -34,4 +34,6 @@ RISCV_SYSROOT ?= $(RISCV_TOOLCHAIN_PATH)/$(RISCV_PREFIX) VORTEX_RT_PATH ?= $(VORTEX_HOME)/runtime VORTEX_KN_PATH ?= $(VORTEX_HOME)/kernel -THIRD_PARTY_DIR ?= $(VORTEX_HOME)/third_party \ No newline at end of file +THIRD_PARTY_DIR ?= $(VORTEX_HOME)/third_party + +VM_ENABLE ?= @VM_ENABLE@ \ No newline at end of file diff --git a/configure b/configure index 643c27150..2c0811ec3 100755 --- a/configure +++ b/configure @@ -63,7 +63,7 @@ copy_files() { filename_no_ext="${filename%.in}" dest_file="$dest_dir/$filename_no_ext" mkdir -p "$dest_dir" - sed "s|@VORTEX_HOME@|$SCRIPT_DIR|g; s|@XLEN@|$XLEN|g; s|@TOOLDIR@|$TOOLDIR|g; s|@OSVERSION@|$OSVERSION|g; s|@PREFIX@|$PREFIX|g" "$file" > "$dest_file" + sed "s|@VORTEX_HOME@|$SCRIPT_DIR|g; s|@XLEN@|$XLEN|g; s|@TOOLDIR@|$TOOLDIR|g; s|@OSVERSION@|$OSVERSION|g; s|@PREFIX@|$PREFIX|g; s|@VM_ENABLE@|$VM_ENABLE|g" "$file" > "$dest_file" # apply permissions to bash scripts read -r firstline < "$dest_file" if [[ "$firstline" =~ ^#!.*bash ]]; then @@ -114,6 +114,7 @@ default_xlen=32 default_tooldir=$HOME/tools default_osversion=$(detect_osversion) default_prefix=$CURRENT_DIR +default_vm=0 # load default configuration parameters from existing config.mk if [ -f "config.mk" ]; then @@ -126,6 +127,7 @@ if [ -f "config.mk" ]; then TOOLDIR\ ?*) default_tooldir=${value//\?=/} ;; OSVERSION\ ?*) default_osversion=${value//\?=/} ;; PREFIX\ ?*) default_prefix=${value//\?=/} ;; + VM_ENABLE\ ?*) default_vm=${value//\?=/} ;; esac done < config.mk fi @@ -135,6 +137,7 @@ XLEN=${XLEN:=$default_xlen} TOOLDIR=${TOOLDIR:=$default_tooldir} OSVERSION=${OSVERSION:=$default_osversion} PREFIX=${PREFIX:=$default_prefix} +VM_ENABLE=${VM_ENABLE:=$default_vm} # parse command line arguments usage() { @@ -143,6 +146,7 @@ usage() { echo " --tooldir= Set the TOOLDIR path (default: $HOME/tools)" echo " --osversion= Set the OS Version (default: $(detect_osversion))" echo " --prefix= Set installation directory" + echo " --vm_enable= Enable Virtual Memory support (default: 0)" exit 1 } while [[ "$#" -gt 0 ]]; do @@ -151,6 +155,7 @@ while [[ "$#" -gt 0 ]]; do --tooldir=*) TOOLDIR="${1#*=}" ;; --osversion=*) OSVERSION="${1#*=}" ;; --prefix=*) PREFIX="${1#*=}" ;; + --vm_enable=*) VM_ENABLE="${1#*=}" ;; -h|--help) usage ;; *) echo "Unknown parameter passed: $1"; usage ;; esac @@ -172,3 +177,5 @@ SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) THIRD_PARTY_DIR=$SCRIPT_DIR/third_party copy_files "$SCRIPT_DIR" "$CURRENT_DIR" + +echo "VM Enable: "$VM_ENABLE \ No newline at end of file diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index ed2afc900..45041ac4a 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -33,10 +33,6 @@ `endif /////////////////////////////////////////////////////////////////////////////// -`ifndef VM_DISABLE -`define VM_ENABLE -`endif - `ifndef EXT_M_DISABLE `define EXT_M_ENABLE `endif diff --git a/kernel/Makefile b/kernel/Makefile index 201ebc200..16d279fa0 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -32,6 +32,10 @@ CFLAGS += -O3 -mcmodel=medany -fno-exceptions -fdata-sections -ffunction-section CFLAGS += -I$(INC_DIR) -I$(ROOT_DIR)/hw CFLAGS += -DXLEN_$(XLEN) +ifeq ($(VM_ENABLE), 1) +CFLAGS += -DVM_ENABLE +endif + PROJECT := libvortex SRCS = $(SRC_DIR)/vx_start.S $(SRC_DIR)/vx_syscalls.c $(SRC_DIR)/vx_print.S $(SRC_DIR)/tinyprintf.c $(SRC_DIR)/vx_print.c $(SRC_DIR)/vx_spawn.c $(SRC_DIR)/vx_serial.S $(SRC_DIR)/vx_perf.c diff --git a/runtime/simx/Makefile b/runtime/simx/Makefile index 7c73ca66d..7615f72b2 100644 --- a/runtime/simx/Makefile +++ b/runtime/simx/Makefile @@ -10,6 +10,10 @@ CXXFLAGS += -I$(INC_DIR) -I../common -I$(ROOT_DIR)/hw -I$(SIM_DIR)/simx -I$(COMM CXXFLAGS += $(CONFIGS) CXXFLAGS += -DXLEN_$(XLEN) +ifeq ($(VM_ENABLE), 1) +CXXFLAGS += -DVM_ENABLE +endif + LDFLAGS += -shared -pthread LDFLAGS += -L$(DESTDIR) -lsimx diff --git a/sim/simx/Makefile b/sim/simx/Makefile index 622f653dd..8520e5191 100644 --- a/sim/simx/Makefile +++ b/sim/simx/Makefile @@ -14,6 +14,10 @@ CXXFLAGS += -I$(THIRD_PARTY_DIR)/ramulator/src CXXFLAGS += -DXLEN_$(XLEN) CXXFLAGS += $(CONFIGS) +ifeq ($(VM_ENABLE), 1) +CXXFLAGS += -DVM_ENABLE +endif + LDFLAGS += $(THIRD_PARTY_DIR)/softfloat/build/Linux-x86_64-GCC/softfloat.a LDFLAGS += -Wl,-rpath,$(THIRD_PARTY_DIR)/ramulator -L$(THIRD_PARTY_DIR)/ramulator -lramulator From 26df47d6e28679a2513b6a11d272b3c3d93bb898 Mon Sep 17 00:00:00 2001 From: Hanran Wu Date: Thu, 15 Aug 2024 22:55:29 -0400 Subject: [PATCH 63/75] add a subset of tests for vm and update ci --- .github/workflows/ci.yml | 95 ++++++++++++++++++++++++++++++++++++++++ ci/regression.sh.in | 27 ++++++++++++ 2 files changed, 122 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 386ad0ba1..691226e3f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -166,6 +166,101 @@ jobs: ./ci/regression.sh --${{ matrix.name }} fi + build_vm: + runs-on: ubuntu-20.04 + needs: setup + strategy: + matrix: + xlen: [32, 64] + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Install Dependencies + run: | + sudo bash ./ci/system_updates.sh + + - name: Cache Toolchain Directory + id: cache-toolchain + uses: actions/cache@v2 + with: + path: tools + key: ${{ runner.os }}-toolchain-v0.1 + restore-keys: | + ${{ runner.os }}-toolchain- + + - name: Cache Third Party Directory + id: cache-thirdparty + uses: actions/cache@v2 + with: + path: third_party + key: ${{ runner.os }}-thirdparty-v0.1 + restore-keys: | + ${{ runner.os }}-thirdparty- + + - name: Run Build + run: | + TOOLDIR=$PWD/tools + mkdir -p build${{ matrix.xlen }} + cd build${{ matrix.xlen }} + ../configure --tooldir=$TOOLDIR --xlen=${{ matrix.xlen }} --vm_enable=1 + source ci/toolchain_env.sh + make software -s > /dev/null + make tests -s > /dev/null + + - name: Upload Build Artifact + uses: actions/upload-artifact@v2 + with: + name: build-${{ matrix.xlen }}-vm + path: build${{ matrix.xlen }}-vm + + test_vm: + runs-on: ubuntu-20.04 + needs: build + strategy: + matrix: + xlen: [32, 64] + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Install Dependencies + run: | + sudo bash ./ci/system_updates.sh + + - name: Cache Toolchain Directory + id: cache-toolchain + uses: actions/cache@v2 + with: + path: tools + key: ${{ runner.os }}-toolchain-v0.1 + restore-keys: | + ${{ runner.os }}-toolchain- + + - name: Cache Third Party Directory + id: cache-thirdparty + uses: actions/cache@v2 + with: + path: third_party + key: ${{ runner.os }}-thirdparty-v0.1 + restore-keys: | + ${{ runner.os }}-thirdparty- + + - name: Download Build Artifact + uses: actions/download-artifact@v2 + with: + name: build-${{ matrix.xlen }}-vm + path: build${{ matrix.xlen }}-vm + + - name: Run tests + run: | + cd build${{ matrix.xlen }}-vm + source ci/toolchain_env.sh + chmod -R +x . # Ensure all files have executable permissions + ./ci/regression.sh --vm + complete: runs-on: ubuntu-20.04 needs: tests diff --git a/ci/regression.sh.in b/ci/regression.sh.in index b3bf798cb..57c021a70 100755 --- a/ci/regression.sh.in +++ b/ci/regression.sh.in @@ -124,6 +124,30 @@ opencl() echo "opencl tests done!" } +vm(){ + echo "begin vm tests..." + + make -C sim/simx + make -C runtime/simx + + make -C tests/kernel run-simx + + # Regression tests + make -C tests/regression run-simx + + # test global barrier + CONFIGS="-DGBAR_ENABLE" ./ci/blackbox.sh --driver=simx --app=dogfood --args="-n1 -tgbar" --cores=2 + + # test local barrier + ./ci/blackbox.sh --driver=simx --app=dogfood --args="-n1 -tbar" + + # OpenCL tests + make -C tests/opencl run-simx + ./ci/blackbox.sh --driver=simx --app=lbm --warps=8 + + echo "vm tests done!" +} + test_csv_trace() { # test CSV trace generation @@ -315,6 +339,9 @@ clean=0 while [ "$1" != "" ]; do case $1 in + --vm ) + tests+=("vm") + ;; --clean ) clean=1 ;; From 4a213e7c20c59c5e9906e87676e391fd2af7d386 Mon Sep 17 00:00:00 2001 From: Hanran Wu Date: Thu, 15 Aug 2024 23:00:14 -0400 Subject: [PATCH 64/75] update readme --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index aebbed455..fa1e7d839 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,10 @@ More detailed build instructions can be found [here](docs/install_vortex.md). mkdir out export OUT_DIR=`pwd`/out cd build - ../configure --xlen=32 --tooldir=/software/vortex-toolchain-2024-6-14 --prefix=$OUT_DIR + # Run the following to disble virtual memory feature in compilation + ../configure --xlen=32 --tooldir=/software/vortex-toolchain-2024-2024-08-09 --prefix=$OUT_DIR + # Run the following instead to enable virtual memory feature in compilation + ../configure --xlen=32 --tooldir=/software/vortex-toolchain-2024-2024-08-09 --prefix=$OUT_DIR --vm_enable=1 ### Install prebuilt toolchain # We will use the precomipled tools in volvo toolchanin directory @@ -77,7 +80,6 @@ More detailed build instructions can be found [here](docs/install_vortex.md). ### Building Vortex make -s ### Quick demo running vecadd OpenCL kernel on 2 cores -<<<<<<< HEAD $ ./ci/blackbox.sh --cores=2 --app=vecadd ### Common Developer Tips From bc936c67a37ecb4e112dcde2b255abd82633ef90 Mon Sep 17 00:00:00 2001 From: Hanran Wu Date: Thu, 15 Aug 2024 23:02:03 -0400 Subject: [PATCH 65/75] update ci --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 691226e3f..52210694e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -217,7 +217,7 @@ jobs: test_vm: runs-on: ubuntu-20.04 - needs: build + needs: build_vm strategy: matrix: xlen: [32, 64] From 54045fa05b070f973071da802abd915e15224467 Mon Sep 17 00:00:00 2001 From: Hanran Wu Date: Thu, 15 Aug 2024 23:04:08 -0400 Subject: [PATCH 66/75] skip build and tests ci stages for vm_disable due to verilator dependency --- .github/workflows/ci.yml | 182 +++++++++++++++++++-------------------- 1 file changed, 91 insertions(+), 91 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 52210694e..203612974 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -62,109 +62,109 @@ jobs: run: | make -C third_party > /dev/null - build: - runs-on: ubuntu-20.04 - needs: setup - strategy: - matrix: - xlen: [32, 64] + # build: + # runs-on: ubuntu-20.04 + # needs: setup + # strategy: + # matrix: + # xlen: [32, 64] - steps: - - name: Checkout code - uses: actions/checkout@v2 + # steps: + # - name: Checkout code + # uses: actions/checkout@v2 - - name: Install Dependencies - run: | - sudo bash ./ci/system_updates.sh + # - name: Install Dependencies + # run: | + # sudo bash ./ci/system_updates.sh - - name: Cache Toolchain Directory - id: cache-toolchain - uses: actions/cache@v2 - with: - path: tools - key: ${{ runner.os }}-toolchain-v0.1 - restore-keys: | - ${{ runner.os }}-toolchain- + # - name: Cache Toolchain Directory + # id: cache-toolchain + # uses: actions/cache@v2 + # with: + # path: tools + # key: ${{ runner.os }}-toolchain-v0.1 + # restore-keys: | + # ${{ runner.os }}-toolchain- - - name: Cache Third Party Directory - id: cache-thirdparty - uses: actions/cache@v2 - with: - path: third_party - key: ${{ runner.os }}-thirdparty-v0.1 - restore-keys: | - ${{ runner.os }}-thirdparty- + # - name: Cache Third Party Directory + # id: cache-thirdparty + # uses: actions/cache@v2 + # with: + # path: third_party + # key: ${{ runner.os }}-thirdparty-v0.1 + # restore-keys: | + # ${{ runner.os }}-thirdparty- - - name: Run Build - run: | - TOOLDIR=$PWD/tools - mkdir -p build${{ matrix.xlen }} - cd build${{ matrix.xlen }} - ../configure --tooldir=$TOOLDIR --xlen=${{ matrix.xlen }} - source ci/toolchain_env.sh - make software -s > /dev/null - make tests -s > /dev/null + # - name: Run Build + # run: | + # TOOLDIR=$PWD/tools + # mkdir -p build${{ matrix.xlen }} + # cd build${{ matrix.xlen }} + # ../configure --tooldir=$TOOLDIR --xlen=${{ matrix.xlen }} + # source ci/toolchain_env.sh + # make software -s > /dev/null + # make tests -s > /dev/null - - name: Upload Build Artifact - uses: actions/upload-artifact@v2 - with: - name: build-${{ matrix.xlen }} - path: build${{ matrix.xlen }} + # - name: Upload Build Artifact + # uses: actions/upload-artifact@v2 + # with: + # name: build-${{ matrix.xlen }} + # path: build${{ matrix.xlen }} - tests: - runs-on: ubuntu-20.04 - needs: build - strategy: - matrix: - name: [regression, opencl, config1, config2, debug, stress] - xlen: [32, 64] + # tests: + # runs-on: ubuntu-20.04 + # needs: build + # strategy: + # matrix: + # name: [regression, opencl, config1, config2, debug, stress] + # xlen: [32, 64] - steps: - - name: Checkout code - uses: actions/checkout@v2 + # steps: + # - name: Checkout code + # uses: actions/checkout@v2 - - name: Install Dependencies - run: | - sudo bash ./ci/system_updates.sh + # - name: Install Dependencies + # run: | + # sudo bash ./ci/system_updates.sh - - name: Cache Toolchain Directory - id: cache-toolchain - uses: actions/cache@v2 - with: - path: tools - key: ${{ runner.os }}-toolchain-v0.1 - restore-keys: | - ${{ runner.os }}-toolchain- + # - name: Cache Toolchain Directory + # id: cache-toolchain + # uses: actions/cache@v2 + # with: + # path: tools + # key: ${{ runner.os }}-toolchain-v0.1 + # restore-keys: | + # ${{ runner.os }}-toolchain- - - name: Cache Third Party Directory - id: cache-thirdparty - uses: actions/cache@v2 - with: - path: third_party - key: ${{ runner.os }}-thirdparty-v0.1 - restore-keys: | - ${{ runner.os }}-thirdparty- + # - name: Cache Third Party Directory + # id: cache-thirdparty + # uses: actions/cache@v2 + # with: + # path: third_party + # key: ${{ runner.os }}-thirdparty-v0.1 + # restore-keys: | + # ${{ runner.os }}-thirdparty- - - name: Download Build Artifact - uses: actions/download-artifact@v2 - with: - name: build-${{ matrix.xlen }} - path: build${{ matrix.xlen }} + # - name: Download Build Artifact + # uses: actions/download-artifact@v2 + # with: + # name: build-${{ matrix.xlen }} + # path: build${{ matrix.xlen }} - - name: Run tests - run: | - cd build${{ matrix.xlen }} - source ci/toolchain_env.sh - chmod -R +x . # Ensure all files have executable permissions - if [ "${{ matrix.name }}" == "regression" ]; then - ./ci/regression.sh --unittest - ./ci/regression.sh --isa - ./ci/regression.sh --kernel - ./ci/regression.sh --synthesis - ./ci/regression.sh --regression - else - ./ci/regression.sh --${{ matrix.name }} - fi + # - name: Run tests + # run: | + # cd build${{ matrix.xlen }} + # source ci/toolchain_env.sh + # chmod -R +x . # Ensure all files have executable permissions + # if [ "${{ matrix.name }}" == "regression" ]; then + # ./ci/regression.sh --unittest + # ./ci/regression.sh --isa + # ./ci/regression.sh --kernel + # ./ci/regression.sh --synthesis + # ./ci/regression.sh --regression + # else + # ./ci/regression.sh --${{ matrix.name }} + # fi build_vm: runs-on: ubuntu-20.04 @@ -263,7 +263,7 @@ jobs: complete: runs-on: ubuntu-20.04 - needs: tests + needs: test_vm steps: - name: Check Completion From 66fd2d4e2d19dde471f2089d644fc882e7e68014 Mon Sep 17 00:00:00 2001 From: Hanran Wu Date: Fri, 23 Aug 2024 16:42:31 -0400 Subject: [PATCH 67/75] update ci --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 203612974..c51abf4e3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -202,8 +202,8 @@ jobs: - name: Run Build run: | TOOLDIR=$PWD/tools - mkdir -p build${{ matrix.xlen }} - cd build${{ matrix.xlen }} + mkdir -p build${{ matrix.xlen }}-vm + cd build${{ matrix.xlen }}-vm ../configure --tooldir=$TOOLDIR --xlen=${{ matrix.xlen }} --vm_enable=1 source ci/toolchain_env.sh make software -s > /dev/null From ea9560b33b863918f5cc3f1f6309d9b54baebdbf Mon Sep 17 00:00:00 2001 From: Hanran Wu Date: Fri, 23 Aug 2024 17:44:24 -0400 Subject: [PATCH 68/75] merge --- .github/workflows/ci.yml | 270 + .gitignore | 1 + .gitmodules | 3 +- .travis.yml | 118 - Makefile.in | 23 +- README.md | 10 +- ci/regression.sh.in | 232 +- ci/system_updates.sh | 27 + ci/toolchain_env.sh.in | 4 +- ci/trace_csv.py | 310 +- config.mk.in | 6 +- configure | 15 +- docs/altera_fpga_guide.md | 79 + docs/index.md | 5 +- docs/xilinx_fpga_guide.md | 36 + hw/Makefile | 5 +- hw/dpi/float_dpi.vh | 6 +- hw/dpi/util_dpi.vh | 2 - hw/rtl/VX_cluster.sv | 20 +- hw/rtl/VX_config.vh | 29 +- hw/rtl/VX_define.vh | 70 +- hw/rtl/VX_gpu_pkg.sv | 136 +- hw/rtl/VX_platform.vh | 10 +- hw/rtl/VX_socket.sv | 33 +- hw/rtl/VX_types.vh | 47 +- hw/rtl/Vortex.sv | 20 +- hw/rtl/afu/opae/ccip_std_afu.sv | 9 +- hw/rtl/afu/opae/vortex_afu.sv | 12 +- hw/rtl/afu/xrt/VX_afu_wrap.sv | 37 +- hw/rtl/cache/VX_bank_flush.sv | 109 + hw/rtl/cache/VX_cache.sv | 348 +- hw/rtl/cache/VX_cache_bank.sv | 355 +- hw/rtl/cache/VX_cache_bypass.sv | 91 +- hw/rtl/cache/VX_cache_cluster.sv | 35 +- hw/rtl/cache/VX_cache_data.sv | 128 +- hw/rtl/cache/VX_cache_define.vh | 26 +- hw/rtl/cache/VX_cache_flush.sv | 154 + hw/rtl/cache/VX_cache_init.sv | 1 + hw/rtl/cache/VX_cache_mshr.sv | 27 +- hw/rtl/cache/VX_cache_tags.sv | 90 +- hw/rtl/cache/VX_cache_wrap.sv | 54 +- hw/rtl/core/VX_alu_int.sv | 14 +- hw/rtl/core/VX_alu_muldiv.sv | 8 +- hw/rtl/core/VX_alu_unit.sv | 38 +- hw/rtl/core/VX_commit.sv | 53 +- hw/rtl/core/VX_core.sv | 92 +- hw/rtl/core/VX_core_top.sv | 1 + hw/rtl/core/VX_csr_data.sv | 28 +- hw/rtl/core/VX_csr_unit.sv | 6 +- hw/rtl/core/VX_dcr_data.sv | 3 +- hw/rtl/core/VX_decode.sv | 15 +- hw/rtl/core/VX_dispatch.sv | 136 +- hw/rtl/core/VX_execute.sv | 8 +- hw/rtl/core/VX_fetch.sv | 82 +- hw/rtl/core/VX_fpu_unit.sv | 12 +- hw/rtl/core/VX_ibuffer.sv | 48 +- hw/rtl/core/VX_issue.sv | 193 +- hw/rtl/core/VX_issue_slice.sv | 159 + hw/rtl/core/VX_issue_top.sv | 132 + hw/rtl/core/VX_lmem_unit.sv | 143 +- hw/rtl/core/VX_lsu_adapter.sv | 24 +- hw/rtl/core/VX_lsu_slice.sv | 84 +- hw/rtl/core/VX_lsu_unit.sv | 26 +- hw/rtl/core/VX_operands.sv | 293 +- hw/rtl/core/VX_schedule.sv | 64 +- hw/rtl/core/VX_scoreboard.sv | 286 +- hw/rtl/core/VX_sfu_unit.sv | 6 +- hw/rtl/core/VX_split_join.sv | 4 +- hw/rtl/core/VX_trace_pkg.sv | 399 + hw/rtl/core/VX_wctl_unit.sv | 4 +- hw/rtl/fpu/VX_fpu_dpi.sv | 160 +- hw/rtl/fpu/VX_fpu_dsp.sv | 4 +- hw/rtl/fpu/VX_fpu_fma.sv | 48 +- hw/rtl/fpu/VX_fpu_fpnew.sv | 2 +- hw/rtl/interfaces/VX_commit_sched_if.sv | 13 +- hw/rtl/interfaces/VX_decode_if.sv | 9 +- hw/rtl/interfaces/VX_pipeline_perf_if.sv | 42 +- hw/rtl/libs/VX_avs_adapter.sv | 50 +- hw/rtl/libs/VX_cyclic_arbiter.sv | 25 +- hw/rtl/libs/VX_dp_ram.sv | 57 +- hw/rtl/libs/VX_dp_ram_rst.sv | 115 + hw/rtl/libs/VX_elastic_buffer.sv | 24 +- hw/rtl/libs/VX_fair_arbiter.sv | 41 +- hw/rtl/libs/VX_fifo_queue.sv | 84 +- hw/rtl/libs/VX_generic_arbiter.sv | 52 +- hw/rtl/libs/VX_matrix_arbiter.sv | 56 +- hw/rtl/libs/VX_mem_coalescer.sv | 222 +- hw/rtl/libs/VX_mem_scheduler.sv | 119 +- hw/rtl/libs/VX_onehot_mux.sv | 141 +- hw/rtl/libs/VX_pe_serializer.sv | 65 +- hw/rtl/libs/VX_pending_size.sv | 96 +- hw/rtl/libs/VX_priority_arbiter.sv | 10 +- hw/rtl/libs/VX_rr_arbiter.sv | 319 +- hw/rtl/libs/VX_sp_ram.sv | 14 +- hw/rtl/libs/VX_stream_arb.sv | 96 +- hw/rtl/libs/VX_stream_pack.sv | 73 +- hw/rtl/libs/VX_stream_xbar.sv | 29 +- hw/rtl/mem/VX_local_mem.sv | 65 +- hw/rtl/mem/VX_mem_switch.sv | 27 +- hw/syn/altera/opae/Makefile | 15 +- hw/syn/altera/opae/run_ase.sh | 12 +- hw/syn/altera/quartus/Makefile | 7 +- hw/syn/altera/quartus/common.mk | 5 +- hw/syn/altera/quartus/issue/Makefile | 14 + hw/syn/altera/quartus/project.sdc | 2 +- hw/syn/altera/quartus/top/Makefile | 14 + hw/syn/xilinx/README | 12 +- hw/syn/xilinx/test/Makefile | 1 - hw/syn/xilinx/xrt/Makefile | 16 +- hw/syn/yosys/Makefile | 12 +- hw/syn/yosys/synth.sh | 26 +- hw/unittest/Makefile | 5 +- hw/unittest/cache/cachesim.cpp | 103 +- hw/unittest/cache/cachesim.h | 37 +- hw/unittest/common.mk | 10 +- hw/unittest/core_top/Makefile | 2 +- hw/unittest/issue_top/Makefile | 26 + hw/unittest/issue_top/main.cpp | 49 + hw/unittest/mem_streamer/memsim.cpp | 25 +- hw/unittest/mem_streamer/memsim.h | 8 +- kernel/Makefile | 4 + miscs/docker/Dockerfile.ubuntu | 11 +- runtime/Makefile | 2 + runtime/include/vortex.h | 38 +- runtime/opae/Makefile | 8 +- runtime/opae/driver.cpp | 8 +- runtime/opae/driver.h | 23 +- runtime/opae/vortex.cpp | 4 +- runtime/rtlsim/vortex.cpp | 4 + runtime/simx/Makefile | 4 + runtime/simx/vortex.cpp | 2 +- runtime/stub/utils.cpp | 102 +- runtime/stub/vortex.cpp | 19 +- runtime/xrt/vortex.cpp | 10 +- sim/Makefile | 3 + sim/common.mk | 5 +- sim/common/bitvector.h | 314 + sim/common/dram_sim.cpp | 120 + sim/common/dram_sim.h | 36 + sim/common/util.h | 9 +- sim/opaesim/Makefile | 17 +- sim/opaesim/opae_sim.cpp | 175 +- sim/rtlsim/Makefile | 14 +- sim/rtlsim/main.cpp | 4 +- sim/rtlsim/processor.cpp | 231 +- sim/simx/Makefile | 16 +- sim/simx/arch.h | 24 - sim/simx/cache_sim.cpp | 33 +- sim/simx/cache_sim.h | 14 +- sim/simx/cluster.cpp | 28 +- sim/simx/constants.h | 18 +- sim/simx/core.cpp | 174 +- sim/simx/core.h | 8 +- sim/simx/decode.cpp | 2 +- sim/simx/emulator.cpp | 10 +- sim/simx/emulator.h | 1 + sim/simx/execute.cpp | 153 +- sim/simx/func_unit.cpp | 149 +- sim/simx/func_unit.h | 28 +- sim/simx/instr_trace.h | 41 +- sim/simx/local_mem.cpp | 4 +- sim/simx/main.cpp | 4 +- sim/simx/mem_coalescer.cpp | 185 +- sim/simx/mem_coalescer.h | 25 +- sim/simx/mem_sim.cpp | 103 +- sim/simx/operand.h | 52 +- sim/simx/processor.cpp | 15 +- sim/simx/scoreboard.h | 102 +- sim/simx/socket.cpp | 16 +- sim/simx/types.cpp | 155 +- sim/simx/types.h | 108 +- sim/xrtsim/Makefile | 17 +- sim/xrtsim/vortex_afu_shim.sv | 1 - sim/xrtsim/xrt_sim.cpp | 160 +- tests/opencl/Makefile | 21 - tests/opencl/bfs/Makefile | 2 +- tests/opencl/bfs/graph32.txt | 225 + tests/opencl/bfs/graph4k.txt | 28677 +++++++++++++++++++++ tests/opencl/lbm/main.cc | 11 +- tests/regression/Makefile | 21 +- tests/regression/stencil3d/Makefile | 14 + tests/regression/stencil3d/common.h | 18 + tests/regression/stencil3d/kernel.cpp | 58 + tests/regression/stencil3d/main.cpp | 328 + third_party/Makefile | 8 +- third_party/ramulator | 2 +- 186 files changed, 36003 insertions(+), 4008 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .travis.yml create mode 100755 ci/system_updates.sh create mode 100644 docs/altera_fpga_guide.md create mode 100644 docs/xilinx_fpga_guide.md create mode 100644 hw/rtl/cache/VX_bank_flush.sv create mode 100644 hw/rtl/cache/VX_cache_flush.sv create mode 100644 hw/rtl/core/VX_issue_slice.sv create mode 100644 hw/rtl/core/VX_issue_top.sv create mode 100644 hw/rtl/core/VX_trace_pkg.sv create mode 100644 hw/rtl/libs/VX_dp_ram_rst.sv create mode 100644 hw/syn/altera/quartus/issue/Makefile create mode 100644 hw/unittest/issue_top/Makefile create mode 100644 hw/unittest/issue_top/main.cpp create mode 100644 sim/common/bitvector.h create mode 100644 sim/common/dram_sim.cpp create mode 100644 sim/common/dram_sim.h create mode 100644 tests/opencl/bfs/graph32.txt create mode 100755 tests/opencl/bfs/graph4k.txt create mode 100644 tests/regression/stencil3d/Makefile create mode 100644 tests/regression/stencil3d/common.h create mode 100644 tests/regression/stencil3d/kernel.cpp create mode 100644 tests/regression/stencil3d/main.cpp diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..c51abf4e3 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,270 @@ +# Copyright © 2019-2023 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: CI + +on: [push, pull_request] + +jobs: + setup: + runs-on: ubuntu-20.04 + + steps: + - name: Checkout code + uses: actions/checkout@v2 + with: + submodules: recursive + + - name: Cache Toolchain Directory + id: cache-toolchain + uses: actions/cache@v2 + with: + path: tools + key: ${{ runner.os }}-toolchain-v0.1 + restore-keys: | + ${{ runner.os }}-toolchain- + + - name: Cache Third Party Directory + id: cache-thirdparty + uses: actions/cache@v2 + with: + path: third_party + key: ${{ runner.os }}-thirdparty-v0.1 + restore-keys: | + ${{ runner.os }}-thirdparty- + + - name: Install Dependencies + if: steps.cache-toolchain.outputs.cache-hit != 'true' || steps.cache-thirdparty.outputs.cache-hit != 'true' + run: | + sudo bash ./ci/system_updates.sh + + - name: Setup Toolchain + if: steps.cache-toolchain.outputs.cache-hit != 'true' + run: | + TOOLDIR=$PWD/tools + mkdir -p build + cd build + ../configure --tooldir=$TOOLDIR + ci/toolchain_install.sh --all + + - name: Setup Third Party + if: steps.cache-thirdparty.outputs.cache-hit != 'true' + run: | + make -C third_party > /dev/null + + # build: + # runs-on: ubuntu-20.04 + # needs: setup + # strategy: + # matrix: + # xlen: [32, 64] + + # steps: + # - name: Checkout code + # uses: actions/checkout@v2 + + # - name: Install Dependencies + # run: | + # sudo bash ./ci/system_updates.sh + + # - name: Cache Toolchain Directory + # id: cache-toolchain + # uses: actions/cache@v2 + # with: + # path: tools + # key: ${{ runner.os }}-toolchain-v0.1 + # restore-keys: | + # ${{ runner.os }}-toolchain- + + # - name: Cache Third Party Directory + # id: cache-thirdparty + # uses: actions/cache@v2 + # with: + # path: third_party + # key: ${{ runner.os }}-thirdparty-v0.1 + # restore-keys: | + # ${{ runner.os }}-thirdparty- + + # - name: Run Build + # run: | + # TOOLDIR=$PWD/tools + # mkdir -p build${{ matrix.xlen }} + # cd build${{ matrix.xlen }} + # ../configure --tooldir=$TOOLDIR --xlen=${{ matrix.xlen }} + # source ci/toolchain_env.sh + # make software -s > /dev/null + # make tests -s > /dev/null + + # - name: Upload Build Artifact + # uses: actions/upload-artifact@v2 + # with: + # name: build-${{ matrix.xlen }} + # path: build${{ matrix.xlen }} + + # tests: + # runs-on: ubuntu-20.04 + # needs: build + # strategy: + # matrix: + # name: [regression, opencl, config1, config2, debug, stress] + # xlen: [32, 64] + + # steps: + # - name: Checkout code + # uses: actions/checkout@v2 + + # - name: Install Dependencies + # run: | + # sudo bash ./ci/system_updates.sh + + # - name: Cache Toolchain Directory + # id: cache-toolchain + # uses: actions/cache@v2 + # with: + # path: tools + # key: ${{ runner.os }}-toolchain-v0.1 + # restore-keys: | + # ${{ runner.os }}-toolchain- + + # - name: Cache Third Party Directory + # id: cache-thirdparty + # uses: actions/cache@v2 + # with: + # path: third_party + # key: ${{ runner.os }}-thirdparty-v0.1 + # restore-keys: | + # ${{ runner.os }}-thirdparty- + + # - name: Download Build Artifact + # uses: actions/download-artifact@v2 + # with: + # name: build-${{ matrix.xlen }} + # path: build${{ matrix.xlen }} + + # - name: Run tests + # run: | + # cd build${{ matrix.xlen }} + # source ci/toolchain_env.sh + # chmod -R +x . # Ensure all files have executable permissions + # if [ "${{ matrix.name }}" == "regression" ]; then + # ./ci/regression.sh --unittest + # ./ci/regression.sh --isa + # ./ci/regression.sh --kernel + # ./ci/regression.sh --synthesis + # ./ci/regression.sh --regression + # else + # ./ci/regression.sh --${{ matrix.name }} + # fi + + build_vm: + runs-on: ubuntu-20.04 + needs: setup + strategy: + matrix: + xlen: [32, 64] + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Install Dependencies + run: | + sudo bash ./ci/system_updates.sh + + - name: Cache Toolchain Directory + id: cache-toolchain + uses: actions/cache@v2 + with: + path: tools + key: ${{ runner.os }}-toolchain-v0.1 + restore-keys: | + ${{ runner.os }}-toolchain- + + - name: Cache Third Party Directory + id: cache-thirdparty + uses: actions/cache@v2 + with: + path: third_party + key: ${{ runner.os }}-thirdparty-v0.1 + restore-keys: | + ${{ runner.os }}-thirdparty- + + - name: Run Build + run: | + TOOLDIR=$PWD/tools + mkdir -p build${{ matrix.xlen }}-vm + cd build${{ matrix.xlen }}-vm + ../configure --tooldir=$TOOLDIR --xlen=${{ matrix.xlen }} --vm_enable=1 + source ci/toolchain_env.sh + make software -s > /dev/null + make tests -s > /dev/null + + - name: Upload Build Artifact + uses: actions/upload-artifact@v2 + with: + name: build-${{ matrix.xlen }}-vm + path: build${{ matrix.xlen }}-vm + + test_vm: + runs-on: ubuntu-20.04 + needs: build_vm + strategy: + matrix: + xlen: [32, 64] + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Install Dependencies + run: | + sudo bash ./ci/system_updates.sh + + - name: Cache Toolchain Directory + id: cache-toolchain + uses: actions/cache@v2 + with: + path: tools + key: ${{ runner.os }}-toolchain-v0.1 + restore-keys: | + ${{ runner.os }}-toolchain- + + - name: Cache Third Party Directory + id: cache-thirdparty + uses: actions/cache@v2 + with: + path: third_party + key: ${{ runner.os }}-thirdparty-v0.1 + restore-keys: | + ${{ runner.os }}-thirdparty- + + - name: Download Build Artifact + uses: actions/download-artifact@v2 + with: + name: build-${{ matrix.xlen }}-vm + path: build${{ matrix.xlen }}-vm + + - name: Run tests + run: | + cd build${{ matrix.xlen }}-vm + source ci/toolchain_env.sh + chmod -R +x . # Ensure all files have executable permissions + ./ci/regression.sh --vm + + complete: + runs-on: ubuntu-20.04 + needs: test_vm + + steps: + - name: Check Completion + run: echo "All matrix jobs passed" \ No newline at end of file diff --git a/.gitignore b/.gitignore index ca68f0eb2..43388e9cb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /build* /.vscode +*.cache *.code-workspace diff --git a/.gitmodules b/.gitmodules index 1a002355f..df3ca47e2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,5 +6,4 @@ url = https://github.com/ucb-bar/berkeley-softfloat-3.git [submodule "third_party/ramulator"] path = third_party/ramulator - url = https://github.com/CMU-SAFARI/ramulator.git - ignore = dirty + url = https://github.com/CMU-SAFARI/ramulator2.git diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 57098c8f0..000000000 --- a/.travis.yml +++ /dev/null @@ -1,118 +0,0 @@ -language: cpp -dist: focal -os: linux -compiler: gcc - -addons: - apt: - packages: - - build-essential - - valgrind - - libstdc++6 - - binutils - - python - - uuid-dev - -env: - global: - - TOOLDIR=$HOME/tools - -cache: - directories: - - $TOOLDIR - - $HOME/third_party - - $HOME/build32 - - $HOME/build64 - -before_install: - - if [ ! -d "$TOOLDIR" ] || [ -z "$(ls -A $TOOLDIR)" ] || [ "$(cat "$TOOLDIR/version.txt")" != "v0.4" ]; then - rm -rf $TOOLDIR; - mkdir -p $TRAVIS_BUILD_DIR/build && cd $TRAVIS_BUILD_DIR/build; - ../configure --tooldir=$TOOLDIR; - ci/toolchain_install.sh --all; - echo "v0.3" > "$TOOLDIR/version.txt"; - else - echo "using existing tooldir build"; - fi - - if [ ! -d "$HOME/third_party" ] || [ -z "$(ls -A $HOME/third_party)" ] || [ "$(cat "$HOME/third_party/version.txt")" != "v0.2" ]; then - cd $TRAVIS_BUILD_DIR; - make -C third_party > /dev/null; - echo "v0.2" > "third_party/version.txt"; - cp -rf third_party $HOME; - else - echo "using existing third_party build"; - cp -rf $HOME/third_party $TRAVIS_BUILD_DIR; - fi - -install: - - if [ ! -d "$HOME/build$XLEN" ] || [ -z "$(ls -A $HOME/build$XLEN)" ] || [ "$(cat "$HOME/build$XLEN/version.txt")" != "$TRAVIS_COMMIT" ]; then - mkdir -p $TRAVIS_BUILD_DIR/build$XLEN && cd $TRAVIS_BUILD_DIR/build$XLEN; - ../configure --tooldir=$TOOLDIR --xlen=$XLEN; - source ci/toolchain_env.sh; - make build -s > /dev/null; - echo "$TRAVIS_COMMIT" > version.txt; - cp -rf $TRAVIS_BUILD_DIR/build$XLEN $HOME; - else - echo "using existing build for commit $TRAVIS_COMMIT"; - cp -rf $HOME/build$XLEN $TRAVIS_BUILD_DIR; - fi - -before_script: - - cd $TRAVIS_BUILD_DIR/build$XLEN - - source ci/toolchain_env.sh - -stages: - - test - -jobs: - include: - - stage: test - name: regression32 - env: XLEN=32 - script: - - ./ci/travis_run.py ./ci/regression.sh --unittest - - ./ci/travis_run.py ./ci/regression.sh --isa - - ./ci/travis_run.py ./ci/regression.sh --kernel - - ./ci/travis_run.py ./ci/regression.sh --synthesis - - ./ci/travis_run.py ./ci/regression.sh --regression - - ./ci/travis_run.py ./ci/regression.sh --opencl - - - stage: test - name: regression64 - env: XLEN=64 - script: - - ./ci/travis_run.py ./ci/regression.sh --isa - - ./ci/travis_run.py ./ci/regression.sh --kernel - - ./ci/travis_run.py ./ci/regression.sh --synthesis - - ./ci/travis_run.py ./ci/regression.sh --regression - - ./ci/travis_run.py ./ci/regression.sh --opencl - - - stage: test - name: config - env: XLEN=32 - script: - - ./ci/travis_run.py ./ci/regression.sh --cluster - - ./ci/travis_run.py ./ci/regression.sh --config - - - stage: test - name: debug - env: XLEN=32 - script: - - ./ci/travis_run.py ./ci/regression.sh --debug - - ./ci/travis_run.py ./ci/regression.sh --stress - - - stage: test - name: virtual_memory - env: XLEN=32 - env: VM_DISABLE=1 - script: - - ./ci/travis_run.py ./ci/regression.sh --regression - - ./ci/travis_run.py ./ci/regression.sh --opencl - - - stage: test - name: virtual_memory - env: XLEN=64 - env: VM_DISABLE=1 - script: - - ./ci/travis_run.py ./ci/regression.sh --regression - - ./ci/travis_run.py ./ci/regression.sh --opencl \ No newline at end of file diff --git a/Makefile.in b/Makefile.in index ea572e70e..7f594747a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,5 +1,15 @@ include config.mk +.PHONY: build software tests + +vm: + $(MAKE) -C $(VORTEX_HOME)/third_party + $(MAKE) -C hw + $(MAKE) -C sim simx + $(MAKE) -C kernel + $(MAKE) -C runtime vm + $(MAKE) -C tests + all: $(MAKE) -C $(VORTEX_HOME)/third_party $(MAKE) -C hw @@ -15,13 +25,24 @@ build: $(MAKE) -C runtime $(MAKE) -C tests -clean: +software: + $(MAKE) -C hw + $(MAKE) -C kernel + $(MAKE) -C runtime/stub + +tests: + $(MAKE) -C tests + +clean-build: $(MAKE) -C hw clean $(MAKE) -C sim clean $(MAKE) -C kernel clean $(MAKE) -C runtime clean $(MAKE) -C tests clean +clean: clean-build + $(MAKE) -C $(VORTEX_HOME)/third_party clean + # Install setup KERNEL_INC_DST = $(PREFIX)/kernel/include KERNEL_LIB_DST = $(PREFIX)/kernel/lib$(XLEN) diff --git a/README.md b/README.md index 704883e30..6cabdeee5 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ More detailed build instructions can be found [here](docs/install_vortex.md). ``` ### Install Vortex codebase ``` - git clone --depth=1 --recursive git@github.com:vortexgpgpu/vortex.git -b vortex_vm + git clone --depth=1 --recursive https://github.com/vortexgpgpu/vortex.git -b vortex_vm cd vortex ``` @@ -68,18 +68,18 @@ More detailed build instructions can be found [here](docs/install_vortex.md). mkdir out export OUT_DIR=`pwd`/out cd build - ../configure --xlen=32 --tooldir=/software/vortex-toolchain-2024-6-14 --prefix=$OUT_DIR + # Run the following to disble virtual memory feature in compilation + ../configure --xlen=32 --tooldir=/software/vortex-toolchain-2024-2024-08-09 --prefix=$OUT_DIR + # Run the following instead to enable virtual memory feature in compilation + ../configure --xlen=32 --tooldir=/software/vortex-toolchain-2024-2024-08-09 --prefix=$OUT_DIR --vm_enable=1 ### Install prebuilt toolchain # We will use the precomipled tools in volvo toolchanin directory - ### set environment variables # should always run before using the toolchain! source ./ci/toolchain_env.sh - ### Building Vortex make -s - ### Quick demo running vecadd OpenCL kernel on 2 cores $ ./ci/blackbox.sh --cores=2 --app=vecadd diff --git a/ci/regression.sh.in b/ci/regression.sh.in index dffd91502..57c021a70 100755 --- a/ci/regression.sh.in +++ b/ci/regression.sh.in @@ -25,37 +25,6 @@ XLEN=${XLEN:=@XLEN@} echo "Vortex Regression Test: XLEN=$XLEN" -split_file() { - if [[ $# -ne 2 ]]; then - echo "Usage: $0 " - return 1 - fi - input_file="$1" - start_with="$2" - if [[ ! -r "$input_file" ]]; then - echo "Error: File '$input_file' is not readable or does not exist." - return 1 - fi - count=0 - output_file="" - while IFS= read -r line; do - if [[ $line == $start_with* ]]; then - count=$((count + 1)) - output_file="$input_file.part$count" - > "$output_file" # ensure empty - fi - if [[ -n "$output_file" ]]; then - echo "$line" >> "$output_file" - fi - done < "$input_file" - - if [[ $count -eq 0 ]]; then - echo "No lines starting with '$start_with' were found in '$input_file'." - fi -} - -############################################################################### - unittest() { make -C tests/unittest run @@ -66,6 +35,9 @@ isa() { echo "begin isa tests..." + make -C sim/simx + make -C sim/rtlsim + make -C tests/riscv/isa run-simx make -C tests/riscv/isa run-rtlsim @@ -96,8 +68,8 @@ isa() make -C tests/riscv/isa run-rtlsim-64fx fi - # restore default prebuilt configuration - make -C sim/rtlsim clean && make -C sim/rtlsim > /dev/null + # clean build + make -C sim/rtlsim clean echo "isa tests done!" } @@ -106,6 +78,9 @@ kernel() { echo "begin kernel tests..." + make -C sim/simx + make -C sim/rtlsim + make -C tests/kernel run-simx make -C tests/kernel run-rtlsim @@ -116,6 +91,9 @@ regression() { echo "begin regression tests..." + make -C runtime/simx + make -C runtime/rtlsim + make -C tests/regression run-simx make -C tests/regression run-rtlsim @@ -134,6 +112,9 @@ opencl() { echo "begin opencl tests..." + make -C runtime/simx + make -C runtime/rtlsim + make -C tests/opencl run-simx make -C tests/opencl run-rtlsim @@ -143,24 +124,28 @@ opencl() echo "opencl tests done!" } -cluster() -{ - echo "begin clustering tests..." +vm(){ + echo "begin vm tests..." - # cores clustering - ./ci/blackbox.sh --driver=rtlsim --cores=4 --clusters=1 --app=diverge --args="-n1" - ./ci/blackbox.sh --driver=rtlsim --cores=2 --clusters=2 --app=diverge --args="-n1" - ./ci/blackbox.sh --driver=simx --cores=4 --clusters=1 --app=diverge --args="-n1" - ./ci/blackbox.sh --driver=simx --cores=4 --clusters=2 --app=diverge --args="-n1" + make -C sim/simx + make -C runtime/simx - # L2/L3 - ./ci/blackbox.sh --driver=rtlsim --cores=2 --l2cache --app=diverge --args="-n1" - ./ci/blackbox.sh --driver=rtlsim --cores=2 --clusters=2 --l3cache --app=diverge --args="-n1" - ./ci/blackbox.sh --driver=rtlsim --cores=2 --clusters=2 --l2cache --l3cache --app=io_addr --args="-n1" - ./ci/blackbox.sh --driver=simx --cores=4 --clusters=2 --l2cache --app=diverge --args="-n1" - ./ci/blackbox.sh --driver=simx --cores=4 --clusters=4 --l2cache --l3cache --app=diverge --args="-n1" + make -C tests/kernel run-simx + + # Regression tests + make -C tests/regression run-simx - echo "clustering tests done!" + # test global barrier + CONFIGS="-DGBAR_ENABLE" ./ci/blackbox.sh --driver=simx --app=dogfood --args="-n1 -tgbar" --cores=2 + + # test local barrier + ./ci/blackbox.sh --driver=simx --app=dogfood --args="-n1 -tbar" + + # OpenCL tests + make -C tests/opencl run-simx + ./ci/blackbox.sh --driver=simx --app=lbm --warps=8 + + echo "vm tests done!" } test_csv_trace() @@ -170,29 +155,20 @@ test_csv_trace() make -C sim/rtlsim clean && DEBUG=3 CONFIGS="-DGPR_RESET" make -C sim/rtlsim > /dev/null make -C tests/riscv/isa run-simx-32im > run_simx.log make -C tests/riscv/isa run-rtlsim-32im > run_rtlsim.log - split_file run_simx.log "Running " - split_file run_rtlsim.log "Running " - for file in ./run_simx.log.part*; do - if [[ -f "$file" ]]; then - file2="${file//simx/rtlsim}" - if [[ -f "$file2" ]]; then - ./ci/trace_csv.py -tsimx $file -otrace_simx.csv - ./ci/trace_csv.py -trtlsim $file2 -otrace_rtlsim.csv - diff trace_rtlsim.csv trace_simx.csv - else - echo "File $file2 not found." - fi - fi - done - # restore default prebuilt configuration - make -C sim/simx clean && make -C sim/simx > /dev/null - make -C sim/rtlsim clean && make -C sim/rtlsim > /dev/null + ./ci/trace_csv.py -tsimx run_simx.log -otrace_simx.csv + ./ci/trace_csv.py -trtlsim run_rtlsim.log -otrace_rtlsim.csv + diff trace_rtlsim.csv trace_simx.csv + # clean build + make -C sim/simx clean + make -C sim/rtlsim clean } debug() { echo "begin debugging tests..." + test_csv_trace + ./ci/blackbox.sh --driver=opae --cores=2 --clusters=2 --l2cache --debug=1 --perf=1 --app=demo --args="-n1" ./ci/blackbox.sh --driver=simx --cores=2 --clusters=2 --l2cache --debug=1 --perf=1 --app=demo --args="-n1" ./ci/blackbox.sh --driver=opae --cores=1 --scope --app=demo --args="-n1" @@ -200,21 +176,23 @@ debug() echo "debugging tests done!" } -config() +config1() { - echo "begin configuration tests..." + echo "begin configuration-1 tests..." - # warp/threads configurations - ./ci/blackbox.sh --driver=rtlsim --cores=1 --warps=1 --threads=1 --app=diverge - ./ci/blackbox.sh --driver=rtlsim --cores=1 --warps=2 --threads=2 --app=diverge - ./ci/blackbox.sh --driver=rtlsim --cores=1 --warps=2 --threads=8 --app=diverge - ./ci/blackbox.sh --driver=rtlsim --cores=1 --warps=8 --threads=2 --app=diverge - ./ci/blackbox.sh --driver=simx --cores=1 --warps=1 --threads=1 --app=diverge - ./ci/blackbox.sh --driver=simx --cores=1 --warps=8 --threads=16 --app=diverge + # warp/threads + ./ci/blackbox.sh --driver=rtlsim --warps=1 --threads=1 --app=diverge + ./ci/blackbox.sh --driver=rtlsim --warps=2 --threads=2 --app=diverge + ./ci/blackbox.sh --driver=rtlsim --warps=2 --threads=8 --app=diverge + ./ci/blackbox.sh --driver=rtlsim --warps=8 --threads=2 --app=diverge + ./ci/blackbox.sh --driver=simx --warps=1 --threads=1 --app=diverge + ./ci/blackbox.sh --driver=simx --warps=8 --threads=16 --app=diverge - # disable DPI - CONFIGS="-DDPI_DISABLE -DFPU_FPNEW" ./ci/blackbox.sh --driver=rtlsim --app=dogfood - CONFIGS="-DDPI_DISABLE -DFPU_FPNEW" ./ci/blackbox.sh --driver=opae --app=dogfood + # cores clustering + ./ci/blackbox.sh --driver=rtlsim --cores=4 --clusters=1 --app=diverge --args="-n1" + ./ci/blackbox.sh --driver=rtlsim --cores=2 --clusters=2 --app=diverge --args="-n1" + ./ci/blackbox.sh --driver=simx --cores=4 --clusters=1 --app=diverge --args="-n1" + ./ci/blackbox.sh --driver=simx --cores=4 --clusters=2 --app=diverge --args="-n1" # issue width CONFIGS="-DISSUE_WIDTH=2" ./ci/blackbox.sh --driver=rtlsim --app=diverge @@ -240,6 +218,31 @@ config() CONFIGS="-DISSUE_WIDTH=2 -DNUM_LSU_BLOCK=1 -DNUM_LSU_LANES=2" ./ci/blackbox.sh --driver=simx --app=vecaddx CONFIGS="-DISSUE_WIDTH=4 -DNUM_LSU_BLOCK=4 -DNUM_LSU_LANES=4" ./ci/blackbox.sh --driver=simx --app=vecaddx + # L2/L3 + ./ci/blackbox.sh --driver=rtlsim --cores=2 --l2cache --app=diverge --args="-n1" + ./ci/blackbox.sh --driver=rtlsim --cores=2 --clusters=2 --l3cache --app=diverge --args="-n1" + ./ci/blackbox.sh --driver=rtlsim --cores=2 --clusters=2 --l2cache --l3cache --app=io_addr --args="-n1" + ./ci/blackbox.sh --driver=simx --cores=4 --clusters=2 --l2cache --app=diverge --args="-n1" + ./ci/blackbox.sh --driver=simx --cores=4 --clusters=4 --l2cache --l3cache --app=diverge --args="-n1" + + # multiple L1 caches per socket + CONFIGS="-DSOCKET_SIZE=4 -DNUM_DCACHES=2 -DNUM_ICACHES=2" ./ci/blackbox.sh --driver=rtlsim --app=sgemmx --cores=8 --warps=1 --threads=2 + + echo "configuration-1 tests done!" +} + +config2() +{ + echo "begin configuration-2 tests..." + + # test opaesim + ./ci/blackbox.sh --driver=opae --app=printf + ./ci/blackbox.sh --driver=opae --app=diverge + + # disable DPI + CONFIGS="-DDPI_DISABLE -DFPU_FPNEW" ./ci/blackbox.sh --driver=rtlsim --app=dogfood + CONFIGS="-DDPI_DISABLE -DFPU_FPNEW" ./ci/blackbox.sh --driver=opae --app=dogfood + # custom program startup address make -C tests/regression/dogfood clean-kernel if [ "$XLEN" == "64" ]; then @@ -249,55 +252,57 @@ config() fi ./ci/blackbox.sh --driver=simx --app=dogfood ./ci/blackbox.sh --driver=rtlsim --app=dogfood + make -C tests/regression/dogfood clean-kernel # disabling M & F extensions make -C sim/rtlsim clean && CONFIGS="-DEXT_M_DISABLE -DEXT_F_DISABLE" make -C sim/rtlsim > /dev/null make -C tests/riscv/isa run-rtlsim-32i - make -C sim/rtlsim clean && make -C sim/rtlsim > /dev/null + make -C sim/rtlsim clean # disabling ZICOND extension CONFIGS="-DEXT_ZICOND_DISABLE" ./ci/blackbox.sh --driver=rtlsim --app=demo # disable local memory - CONFIGS="-DLMEM_DISABLE" ./ci/blackbox.sh --driver=rtlsim --cores=1 --app=demo --perf=1 - CONFIGS="-DLMEM_DISABLE" ./ci/blackbox.sh --driver=simx --cores=1 --app=demo --perf=1 - - # disable L1 cache - CONFIGS="-DL1_DISABLE -DLMEM_DISABLE" ./ci/blackbox.sh --driver=rtlsim --cores=1 --app=sgemmx - CONFIGS="-DL1_DISABLE" ./ci/blackbox.sh --driver=rtlsim --cores=1 --app=sgemmx - CONFIGS="-DDCACHE_DISABLE" ./ci/blackbox.sh --driver=rtlsim --cores=1 --app=sgemmx - CONFIGS="-DICACHE_DISABLE" ./ci/blackbox.sh --driver=rtlsim --cores=1 --app=sgemmx - - # multiple L1 caches per socket - CONFIGS="-DSOCKET_SIZE=4 -DNUM_DCACHES=2 -DNUM_ICACHES=2" ./ci/blackbox.sh --driver=rtlsim --app=sgemmx --cores=8 --warps=1 --threads=2 + CONFIGS="-DLMEM_DISABLE" ./ci/blackbox.sh --driver=rtlsim --app=demo --perf=1 + CONFIGS="-DLMEM_DISABLE" ./ci/blackbox.sh --driver=simx --app=demo --perf=1 # test AXI bus - AXI_BUS=1 ./ci/blackbox.sh --driver=rtlsim --cores=1 --app=demo + AXI_BUS=1 ./ci/blackbox.sh --driver=rtlsim --app=demo + + # disable L1 cache + CONFIGS="-DL1_DISABLE -DLMEM_DISABLE" ./ci/blackbox.sh --driver=rtlsim --app=sgemmx + CONFIGS="-DL1_DISABLE" ./ci/blackbox.sh --driver=rtlsim --app=sgemmx + CONFIGS="-DDCACHE_DISABLE" ./ci/blackbox.sh --driver=rtlsim --app=sgemmx + CONFIGS="-DICACHE_DISABLE" ./ci/blackbox.sh --driver=rtlsim --app=sgemmx # reduce l1 line size - CONFIGS="-DL1_LINE_SIZE=4" ./ci/blackbox.sh --driver=rtlsim --app=io_addr - CONFIGS="-DL1_LINE_SIZE=4" ./ci/blackbox.sh --driver=simx --app=io_addr - CONFIGS="-DL1_LINE_SIZE=4 -DLMEM_DISABLE" ./ci/blackbox.sh --driver=rtlsim --app=sgemmx - CONFIGS="-DL1_LINE_SIZE=4 -DLMEM_DISABLE" ./ci/blackbox.sh --driver=simx --app=sgemmx + CONFIGS="-DL1_LINE_SIZE=$XLEN/8" ./ci/blackbox.sh --driver=rtlsim --app=io_addr + CONFIGS="-DL1_LINE_SIZE=$XLEN/8" ./ci/blackbox.sh --driver=simx --app=io_addr + CONFIGS="-DL1_LINE_SIZE=$XLEN/8 -DLMEM_DISABLE" ./ci/blackbox.sh --driver=rtlsim --app=sgemmx + CONFIGS="-DL1_LINE_SIZE=$XLEN/8 -DLMEM_DISABLE" ./ci/blackbox.sh --driver=simx --app=sgemmx + + # test cache ways + CONFIGS="-DICACHE_NUM_WAYS=8 -DDCACHE_NUM_WAYS=8" ./ci/blackbox.sh --driver=rtlsim --app=sgemmx + CONFIGS="-DICACHE_NUM_WAYS=8 -DDCACHE_NUM_WAYS=8" ./ci/blackbox.sh --driver=simx --app=sgemmx # test cache banking CONFIGS="-DLMEM_NUM_BANKS=4 -DDCACHE_NUM_BANKS=1" ./ci/blackbox.sh --driver=rtlsim --app=sgemmx CONFIGS="-DLMEM_NUM_BANKS=2 -DDCACHE_NUM_BANKS=2" ./ci/blackbox.sh --driver=rtlsim --app=sgemmx CONFIGS="-DLMEM_NUM_BANKS=2 -DDCACHE_NUM_BANKS=2" ./ci/blackbox.sh --driver=simx --app=sgemmx - CONFIGS="-DDCACHE_NUM_BANKS=1" ./ci/blackbox.sh --driver=rtlsim --cores=1 --app=sgemmx - CONFIGS="-DDCACHE_NUM_BANKS=2" ./ci/blackbox.sh --driver=rtlsim --cores=1 --app=sgemmx - CONFIGS="-DDCACHE_NUM_BANKS=2" ./ci/blackbox.sh --driver=simx --cores=1 --app=sgemmx + CONFIGS="-DDCACHE_NUM_BANKS=1" ./ci/blackbox.sh --driver=rtlsim --app=sgemmx + CONFIGS="-DDCACHE_NUM_BANKS=2" ./ci/blackbox.sh --driver=rtlsim --app=sgemmx + CONFIGS="-DDCACHE_NUM_BANKS=2" ./ci/blackbox.sh --driver=simx --app=sgemmx # test 128-bit MEM block - CONFIGS="-DMEM_BLOCK_SIZE=16" ./ci/blackbox.sh --driver=opae --cores=1 --app=demo + CONFIGS="-DMEM_BLOCK_SIZE=16" ./ci/blackbox.sh --driver=opae --app=demo # test single-bank DRAM - CONFIGS="-DPLATFORM_PARAM_LOCAL_MEMORY_BANKS=1" ./ci/blackbox.sh --driver=opae --cores=1 --app=demo + CONFIGS="-DPLATFORM_PARAM_LOCAL_MEMORY_BANKS=1" ./ci/blackbox.sh --driver=opae --app=demo # test 27-bit DRAM address - CONFIGS="-DPLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH=27" ./ci/blackbox.sh --driver=opae --cores=1 --app=demo + CONFIGS="-DPLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH=27" ./ci/blackbox.sh --driver=opae --app=demo - echo "configuration tests done!" + echo "configuration-2 tests done!" } stress() @@ -306,9 +311,7 @@ stress() # test verilator reset values CONFIGS="-DVERILATOR_RESET_VALUE=1" ./ci/blackbox.sh --driver=opae --cores=2 --clusters=2 --l2cache --l3cache --app=dogfood - CONFIGS="-DVERILATOR_RESET_VALUE=1" ./ci/blackbox.sh --driver=opae --cores=2 --clusters=2 --l2cache --l3cache --app=io_addr - CONFIGS="-DVERILATOR_RESET_VALUE=1" ./ci/blackbox.sh --driver=opae --app=printf - ./ci/blackbox.sh --driver=rtlsim --app=sgemm --args="-n128" --l2cache + CONFIGS="-DVERILATOR_RESET_VALUE=1" ./ci/blackbox.sh --driver=rtlsim --app=sgemmx --args="-n128" --l2cache echo "stress tests done!" } @@ -318,7 +321,7 @@ synthesis() echo "begin synthesis tests..." PREFIX=build_base make -C hw/syn/yosys clean - PREFIX=build_base CONFIGS="-DDPI_DISABLE -DEXT_F_DISABLE" make -C hw/syn/yosys elaborate + PREFIX=build_base CONFIGS="-DDPI_DISABLE -DEXT_F_DISABLE" make -C hw/syn/yosys synthesis echo "synthesis tests done!" } @@ -326,7 +329,7 @@ synthesis() show_usage() { echo "Vortex Regression Test" - echo "Usage: $0 [--clean] [--unittest] [--isa] [--kernel] [--regression] [--opencl] [--cluster] [--debug] [--config] [--stress] [--synthesis] [--all] [--h|--help]" + echo "Usage: $0 [--clean] [--unittest] [--isa] [--kernel] [--regression] [--opencl] [--config1] [--config2] [--debug] [--stress] [--synthesis] [--all] [--h|--help]" } start=$SECONDS @@ -336,6 +339,9 @@ clean=0 while [ "$1" != "" ]; do case $1 in + --vm ) + tests+=("vm") + ;; --clean ) clean=1 ;; @@ -354,15 +360,15 @@ while [ "$1" != "" ]; do --opencl ) tests+=("opencl") ;; - --cluster ) - tests+=("cluster") + --config1 ) + tests+=("config1") + ;; + --config2 ) + tests+=("config2") ;; --debug ) tests+=("debug") ;; - --config ) - tests+=("config") - ;; --stress ) tests+=("stress") ;; @@ -376,9 +382,9 @@ while [ "$1" != "" ]; do tests+=("kernel") tests+=("regression") tests+=("opencl") - tests+=("cluster") + tests+=("config1") + tests+=("config2") tests+=("debug") - tests+=("config") tests+=("stress") tests+=("synthesis") ;; diff --git a/ci/system_updates.sh b/ci/system_updates.sh new file mode 100755 index 000000000..43abbe5ab --- /dev/null +++ b/ci/system_updates.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +# Copyright 2019-2023 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e + +apt-get update -y + +add-apt-repository -y ppa:ubuntu-toolchain-r/test +apt-get update +apt-get install -y g++-11 gcc-11 +update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-11 100 +update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 100 + +apt-get install -y build-essential valgrind libstdc++6 binutils python uuid-dev ccache diff --git a/ci/toolchain_env.sh.in b/ci/toolchain_env.sh.in index dc50389a9..be140d28d 100755 --- a/ci/toolchain_env.sh.in +++ b/ci/toolchain_env.sh.in @@ -16,8 +16,8 @@ TOOLDIR=${TOOLDIR:=@TOOLDIR@} -export VERILATOR_ROOT=$TOOLDIR/verilator -export PATH=$VERILATOR_ROOT/bin:$PATH +# export VERILATOR_ROOT=$TOOLDIR/verilator +# export PATH=$VERILATOR_ROOT/bin:$PATH export SV2V_PATH=$TOOLDIR/sv2v export PATH=$SV2V_PATH/bin:$PATH diff --git a/ci/trace_csv.py b/ci/trace_csv.py index b8cafe379..c3113de85 100755 --- a/ci/trace_csv.py +++ b/ci/trace_csv.py @@ -26,7 +26,7 @@ def parse_args(): parser.add_argument('log', help='Input log file') return parser.parse_args() -def parse_simx(log_filename): +def parse_simx(log_lines): pc_pattern = r"PC=(0x[0-9a-fA-F]+)" instr_pattern = r"Instr (0x[0-9a-fA-F]+):" opcode_pattern = r"Instr 0x[0-9a-fA-F]+: ([0-9a-zA-Z_\.]+)" @@ -37,32 +37,31 @@ def parse_simx(log_filename): destination_pattern = r"Dest Reg: (.+)" uuid_pattern = r"#(\d+)" entries = [] - with open(log_filename, 'r') as log_file: - instr_data = None - for lineno, line in enumerate(log_file, start=1): - try: - if line.startswith("DEBUG Fetch:"): - if instr_data: - entries.append(instr_data) - instr_data = {} - instr_data["lineno"] = lineno - instr_data["PC"] = re.search(pc_pattern, line).group(1) - instr_data["core_id"] = re.search(core_id_pattern, line).group(1) - instr_data["warp_id"] = re.search(warp_id_pattern, line).group(1) - instr_data["tmask"] = re.search(tmask_pattern, line).group(1) - instr_data["uuid"] = re.search(uuid_pattern, line).group(1) - elif line.startswith("DEBUG Instr"): - instr_data["instr"] = re.search(instr_pattern, line).group(1) - instr_data["opcode"] = re.search(opcode_pattern, line).group(1) - elif line.startswith("DEBUG Src"): - src_reg = re.search(operands_pattern, line).group(1) - instr_data["operands"] = (instr_data["operands"] + ', ' + src_reg) if 'operands' in instr_data else src_reg - elif line.startswith("DEBUG Dest"): - instr_data["destination"] = re.search(destination_pattern, line).group(1) - except Exception as e: - print("Error at line {}: {}".format(lineno, e)) - if instr_data: - entries.append(instr_data) + instr_data = None + for lineno, line in enumerate(log_lines, start=1): + try: + if line.startswith("DEBUG Fetch:"): + if instr_data: + entries.append(instr_data) + instr_data = {} + instr_data["lineno"] = lineno + instr_data["PC"] = re.search(pc_pattern, line).group(1) + instr_data["core_id"] = re.search(core_id_pattern, line).group(1) + instr_data["warp_id"] = re.search(warp_id_pattern, line).group(1) + instr_data["tmask"] = re.search(tmask_pattern, line).group(1) + instr_data["uuid"] = re.search(uuid_pattern, line).group(1) + elif line.startswith("DEBUG Instr"): + instr_data["instr"] = re.search(instr_pattern, line).group(1) + instr_data["opcode"] = re.search(opcode_pattern, line).group(1) + elif line.startswith("DEBUG Src"): + src_reg = re.search(operands_pattern, line).group(1) + instr_data["operands"] = (instr_data["operands"] + ', ' + src_reg) if 'operands' in instr_data else src_reg + elif line.startswith("DEBUG Dest"): + instr_data["destination"] = re.search(destination_pattern, line).group(1) + except Exception as e: + print("Error at line {}: {}".format(lineno, e)) + if instr_data: + entries.append(instr_data) return entries def reverse_binary(bin_str): @@ -95,8 +94,9 @@ def append_value(text, reg, value, tmask_arr, sep): text += "}" return text, sep -def parse_rtlsim(log_filename): - line_pattern = r"\d+: core(\d+)-(decode|issue|commit)" +def parse_rtlsim(log_lines): + config_pattern = r"CONFIGS: num_threads=(\d+), num_warps=(\d+), num_cores=(\d+), num_clusters=(\d+), socket_size=(\d+), local_mem_base=(\d+), num_barriers=(\d+)" + line_pattern = r"\d+: cluster(\d+)-socket(\d+)-core(\d+)-(decode|issue|commit)" pc_pattern = r"PC=(0x[0-9a-fA-F]+)" instr_pattern = r"instr=(0x[0-9a-fA-F]+)" ex_pattern = r"ex=([a-zA-Z]+)" @@ -116,124 +116,166 @@ def parse_rtlsim(log_filename): eop_pattern = r"eop=(\d)" uuid_pattern = r"#(\d+)" entries = [] - with open(log_filename, 'r') as log_file: - instr_data = {} - for lineno, line in enumerate(log_file, start=1): - try: - line_match = re.search(line_pattern, line) - if line_match: - PC = re.search(pc_pattern, line).group(1) - warp_id = re.search(warp_id_pattern, line).group(1) - tmask = re.search(tmask_pattern, line).group(1) - uuid = re.search(uuid_pattern, line).group(1) - core_id = line_match.group(1) - stage = line_match.group(2) - if stage == "decode": - trace = {} - trace["uuid"] = uuid - trace["PC"] = PC - trace["core_id"] = core_id - trace["warp_id"] = warp_id - trace["tmask"] = reverse_binary(tmask) - trace["instr"] = re.search(instr_pattern, line).group(1) - trace["opcode"] = re.search(op_pattern, line).group(1) - trace["opds"] = bin_to_array(re.search(opds_pattern, line).group(1)) - trace["rd"] = re.search(rd_pattern, line).group(1) - trace["rs1"] = re.search(rs1_pattern, line).group(1) - trace["rs2"] = re.search(rs2_pattern, line).group(1) - trace["rs3"] = re.search(rs3_pattern, line).group(1) + instr_data = {} + num_threads = 0 + num_warps = 0 + num_cores = 0 + num_clusters = 0 + socket_size = 0 + local_mem_base = 0 + num_barriers = 0 + num_sockets = 0 + for lineno, line in enumerate(log_lines, start=1): + try: + config_match = re.search(config_pattern, line) + if config_match: + num_threads = int(config_match.group(1)) + num_warps = int(config_match.group(2)) + num_cores = int(config_match.group(3)) + num_clusters = int(config_match.group(4)) + socket_size = int(config_match.group(5)) + local_mem_base = int(config_match.group(6)) + num_barriers = int(config_match.group(7)) + num_sockets = (num_cores + socket_size - 1) // socket_size + continue + line_match = re.search(line_pattern, line) + if line_match: + PC = re.search(pc_pattern, line).group(1) + warp_id = re.search(warp_id_pattern, line).group(1) + tmask = re.search(tmask_pattern, line).group(1) + uuid = re.search(uuid_pattern, line).group(1) + cluster_id = line_match.group(1) + socket_id = line_match.group(2) + core_id = line_match.group(3) + stage = line_match.group(4) + if stage == "decode": + trace = {} + trace["uuid"] = uuid + trace["PC"] = PC + trace["core_id"] = ((((cluster_id * num_sockets) + socket_id) * socket_size) + core_id) + trace["warp_id"] = warp_id + trace["tmask"] = reverse_binary(tmask) + trace["instr"] = re.search(instr_pattern, line).group(1) + trace["opcode"] = re.search(op_pattern, line).group(1) + trace["opds"] = bin_to_array(re.search(opds_pattern, line).group(1)) + trace["rd"] = re.search(rd_pattern, line).group(1) + trace["rs1"] = re.search(rs1_pattern, line).group(1) + trace["rs2"] = re.search(rs2_pattern, line).group(1) + trace["rs3"] = re.search(rs3_pattern, line).group(1) + instr_data[uuid] = trace + elif stage == "issue": + if uuid in instr_data: + trace = instr_data[uuid] + trace["lineno"] = lineno + opds = trace["opds"] + if opds[1]: + trace["rs1_data"] = re.search(rs1_data_pattern, line).group(1).split(', ')[::-1] + if opds[2]: + trace["rs2_data"] = re.search(rs2_data_pattern, line).group(1).split(', ')[::-1] + if opds[3]: + trace["rs3_data"] = re.search(rs3_data_pattern, line).group(1).split(', ')[::-1] + trace["issued"] = True instr_data[uuid] = trace - elif stage == "issue": - if uuid in instr_data: - trace = instr_data[uuid] - trace["lineno"] = lineno + elif stage == "commit": + if uuid in instr_data: + trace = instr_data[uuid] + if "issued" in trace: opds = trace["opds"] - if opds[1]: - trace["rs1_data"] = re.search(rs1_data_pattern, line).group(1).split(', ')[::-1] - if opds[2]: - trace["rs2_data"] = re.search(rs2_data_pattern, line).group(1).split(', ')[::-1] - if opds[3]: - trace["rs3_data"] = re.search(rs3_data_pattern, line).group(1).split(', ')[::-1] - trace["issued"] = True + dst_tmask_arr = bin_to_array(tmask)[::-1] + wb = re.search(wb_pattern, line).group(1) == "1" + if wb: + rd_data = re.search(rd_data_pattern, line).group(1).split(', ')[::-1] + if 'rd_data' in trace: + merged_rd_data = trace['rd_data'] + for i in range(len(dst_tmask_arr)): + if dst_tmask_arr[i] == 1: + merged_rd_data[i] = rd_data[i] + trace['rd_data'] = merged_rd_data + else: + trace['rd_data'] = rd_data instr_data[uuid] = trace - elif stage == "commit": - if uuid in instr_data: - trace = instr_data[uuid] - if "issued" in trace: - opds = trace["opds"] - dst_tmask_arr = bin_to_array(tmask)[::-1] - wb = re.search(wb_pattern, line).group(1) == "1" + eop = re.search(eop_pattern, line).group(1) == "1" + if eop: + tmask_arr = bin_to_array(trace["tmask"]) + destination = '' if wb: - rd_data = re.search(rd_data_pattern, line).group(1).split(', ')[::-1] - if 'rd_data' in trace: - merged_rd_data = trace['rd_data'] - for i in range(len(dst_tmask_arr)): - if dst_tmask_arr[i] == 1: - merged_rd_data[i] = rd_data[i] - trace['rd_data'] = merged_rd_data - else: - trace['rd_data'] = rd_data - instr_data[uuid] = trace - eop = re.search(eop_pattern, line).group(1) == "1" - if eop: - tmask_arr = bin_to_array(trace["tmask"]) - destination = '' - if wb: - destination, sep = append_value(destination, trace["rd"], trace['rd_data'], tmask_arr, False) - del trace['rd_data'] - trace["destination"] = destination - operands = '' - sep = False - if opds[1]: - operands, sep = append_value(operands, trace["rs1"], trace["rs1_data"], tmask_arr, sep) - del trace["rs1_data"] - if opds[2]: - operands, sep = append_value(operands, trace["rs2"], trace["rs2_data"], tmask_arr, sep) - del trace["rs2_data"] - if opds[3]: - operands, sep = append_value(operands, trace["rs3"], trace["rs3_data"], tmask_arr, sep) - del trace["rs3_data"] - trace["operands"] = operands - del trace["opds"] - del trace["rd"] - del trace["rs1"] - del trace["rs2"] - del trace["rs3"] - del trace["issued"] - del instr_data[uuid] - entries.append(trace) - except Exception as e: - print("Error at line {}: {}".format(lineno, e)) + destination, sep = append_value(destination, trace["rd"], trace['rd_data'], tmask_arr, False) + del trace['rd_data'] + trace["destination"] = destination + operands = '' + sep = False + if opds[1]: + operands, sep = append_value(operands, trace["rs1"], trace["rs1_data"], tmask_arr, sep) + del trace["rs1_data"] + if opds[2]: + operands, sep = append_value(operands, trace["rs2"], trace["rs2_data"], tmask_arr, sep) + del trace["rs2_data"] + if opds[3]: + operands, sep = append_value(operands, trace["rs3"], trace["rs3_data"], tmask_arr, sep) + del trace["rs3_data"] + trace["operands"] = operands + del trace["opds"] + del trace["rd"] + del trace["rs1"] + del trace["rs2"] + del trace["rs3"] + del trace["issued"] + del instr_data[uuid] + entries.append(trace) + except Exception as e: + print("Error at line {}: {}".format(lineno, e)) return entries -def write_csv(log_filename, csv_filename, log_type): - entries = None - - # parse log file - if log_type == "rtlsim": - entries = parse_rtlsim(log_filename) - elif log_type == "simx": - entries = parse_simx(log_filename) - else: - print('Error: invalid log type') - sys.exit() - - # sort entries by uuid - entries.sort(key=lambda x: (int(x['uuid']))) - for entry in entries: - del entry['lineno'] - - # write to CSV +def write_csv(sublogs, csv_filename, log_type): with open(csv_filename, 'w', newline='') as csv_file: fieldnames = ["uuid", "PC", "opcode", "instr", "core_id", "warp_id", "tmask", "destination", "operands"] writer = csv.DictWriter(csv_file, fieldnames=fieldnames) writer.writeheader() - for entry in entries: - writer.writerow(entry) + + for sublog in sublogs: + entries = None + + # parse sublog + if log_type == "rtlsim": + entries = parse_rtlsim(sublog) + elif log_type == "simx": + entries = parse_simx(sublog) + else: + print('Error: invalid log type') + sys.exit() + + # sort entries by uuid + entries.sort(key=lambda x: (int(x['uuid']))) + for entry in entries: + del entry['lineno'] + + for entry in entries: + writer.writerow(entry) + +def split_log_file(log_filename): + with open(log_filename, 'r') as log_file: + log_lines = log_file.readlines() + + sublogs = [] + current_sublog = None + + for line in log_lines: + if line.startswith("[VXDRV] START"): + if current_sublog is not None: + sublogs.append(current_sublog) + current_sublog = [line] + elif current_sublog is not None: + current_sublog.append(line) + + if current_sublog is not None: + sublogs.append(current_sublog) + + return sublogs def main(): args = parse_args() - write_csv(args.log, args.csv, args.type) + sublogs = split_log_file(args.log) + write_csv(sublogs, args.csv, args.type) if __name__ == "__main__": main() diff --git a/config.mk.in b/config.mk.in index 534f47ed6..6b20a3050 100644 --- a/config.mk.in +++ b/config.mk.in @@ -32,4 +32,8 @@ RISCV_PREFIX ?= riscv$(XLEN)-unknown-elf RISCV_SYSROOT ?= $(RISCV_TOOLCHAIN_PATH)/$(RISCV_PREFIX) VORTEX_RT_PATH ?= $(VORTEX_HOME)/runtime -VORTEX_KN_PATH ?= $(VORTEX_HOME)/kernel \ No newline at end of file +VORTEX_KN_PATH ?= $(VORTEX_HOME)/kernel + +THIRD_PARTY_DIR ?= $(VORTEX_HOME)/third_party + +VM_ENABLE ?= @VM_ENABLE@ \ No newline at end of file diff --git a/configure b/configure index 5e96ab59e..2c0811ec3 100755 --- a/configure +++ b/configure @@ -63,7 +63,7 @@ copy_files() { filename_no_ext="${filename%.in}" dest_file="$dest_dir/$filename_no_ext" mkdir -p "$dest_dir" - sed "s|@VORTEX_HOME@|$SCRIPT_DIR|g; s|@XLEN@|$XLEN|g; s|@TOOLDIR@|$TOOLDIR|g; s|@OSVERSION@|$OSVERSION|g; s|@PREFIX@|$PREFIX|g" "$file" > "$dest_file" + sed "s|@VORTEX_HOME@|$SCRIPT_DIR|g; s|@XLEN@|$XLEN|g; s|@TOOLDIR@|$TOOLDIR|g; s|@OSVERSION@|$OSVERSION|g; s|@PREFIX@|$PREFIX|g; s|@VM_ENABLE@|$VM_ENABLE|g" "$file" > "$dest_file" # apply permissions to bash scripts read -r firstline < "$dest_file" if [[ "$firstline" =~ ^#!.*bash ]]; then @@ -111,9 +111,10 @@ copy_files() { # default configuration parameters default_xlen=32 -default_tooldir=/opt +default_tooldir=$HOME/tools default_osversion=$(detect_osversion) default_prefix=$CURRENT_DIR +default_vm=0 # load default configuration parameters from existing config.mk if [ -f "config.mk" ]; then @@ -126,6 +127,7 @@ if [ -f "config.mk" ]; then TOOLDIR\ ?*) default_tooldir=${value//\?=/} ;; OSVERSION\ ?*) default_osversion=${value//\?=/} ;; PREFIX\ ?*) default_prefix=${value//\?=/} ;; + VM_ENABLE\ ?*) default_vm=${value//\?=/} ;; esac done < config.mk fi @@ -135,14 +137,16 @@ XLEN=${XLEN:=$default_xlen} TOOLDIR=${TOOLDIR:=$default_tooldir} OSVERSION=${OSVERSION:=$default_osversion} PREFIX=${PREFIX:=$default_prefix} +VM_ENABLE=${VM_ENABLE:=$default_vm} # parse command line arguments usage() { echo "Usage: $0 [--xlen=] [--tooldir=] [--osversion=]" echo " --xlen= Set the XLEN value (default: 32)" - echo " --tooldir= Set the TOOLDIR path (default: /opt)" - echo " --osversion= Set the OS Version (default: $(detect_os))" + echo " --tooldir= Set the TOOLDIR path (default: $HOME/tools)" + echo " --osversion= Set the OS Version (default: $(detect_osversion))" echo " --prefix= Set installation directory" + echo " --vm_enable= Enable Virtual Memory support (default: 0)" exit 1 } while [[ "$#" -gt 0 ]]; do @@ -151,6 +155,7 @@ while [[ "$#" -gt 0 ]]; do --tooldir=*) TOOLDIR="${1#*=}" ;; --osversion=*) OSVERSION="${1#*=}" ;; --prefix=*) PREFIX="${1#*=}" ;; + --vm_enable=*) VM_ENABLE="${1#*=}" ;; -h|--help) usage ;; *) echo "Unknown parameter passed: $1"; usage ;; esac @@ -172,3 +177,5 @@ SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) THIRD_PARTY_DIR=$SCRIPT_DIR/third_party copy_files "$SCRIPT_DIR" "$CURRENT_DIR" + +echo "VM Enable: "$VM_ENABLE \ No newline at end of file diff --git a/docs/altera_fpga_guide.md b/docs/altera_fpga_guide.md new file mode 100644 index 000000000..61d1ae26e --- /dev/null +++ b/docs/altera_fpga_guide.md @@ -0,0 +1,79 @@ +# FPGA Startup and Configuration Guide + +OPAE Environment Setup +---------------------- + + $ source /opt/inteldevstack/init_env_user.sh + $ export OPAE_HOME=/opt/opae/1.1.2 + $ export PATH=$OPAE_HOME/bin:$PATH + $ export C_INCLUDE_PATH=$OPAE_HOME/include:$C_INCLUDE_PATH + $ export LIBRARY_PATH=$OPAE_HOME/lib:$LIBRARY_PATH + $ export LD_LIBRARY_PATH=$OPAE_HOME/lib:$LD_LIBRARY_PATH + +OPAE Build +------------------ + +The FPGA has to following configuration options: +- DEVICE_FAMILY=arria10 | stratix10 +- NUM_CORES=#n + +Command line: + + $ cd hw/syn/altera/opae + $ PREFIX=test1 TARGET=fpga NUM_CORES=4 make + +A new folder (ex: `test1_xxx_4c`) will be created and the build will start and take ~30-480 min to complete. +Setting TARGET=ase will build the project for simulation using Intel ASE. + + +OPAE Build Configuration +------------------------ + +The hardware configuration file `/hw/rtl/VX_config.vh` defines all the hardware parameters that can be modified when build the processor.For example, have the following parameters that can be configured: +- `NUM_WARPS`: Number of warps per cores +- `NUM_THREADS`: Number of threads per warps +- `PERF_ENABLE`: enable the use of all profile counters + +You configure the syntesis build from the command line: + + $ CONFIGS="-DPERF_ENABLE -DNUM_THREADS=8" make + +OPAE Build Progress +------------------- + +You could check the last 10 lines in the build log for possible errors until build completion. + + $ tail -n 10 /build.log + +Check if the build is still running by looking for quartus_sh, quartus_syn, or quartus_fit programs. + + $ ps -u + +If the build fails and you need to restart it, clean up the build folder using the following command: + + $ make clean + +The bitstream file `vortex_afu.gbs` should exist when the build is done: + + $ ls -lsa /synth/vortex_afu.gbs + + +Signing the bitstream and Programming the FPGA +---------------------------------------------- + + $ cd + $ PACSign PR -t UPDATE -H openssl_manager -i vortex_afu.gbs -o vortex_afu_unsigned_ssl.gbs + $ fpgasupdate vortex_afu_unsigned_ssl.gbs + +Sample FPGA Run Test +-------------------- + +Ensure you have the correct opae runtime for the FPGA target + + $ make -C runtime/opae clean + $ TARGET=FPGA make -C runtime/opae + +Run the following from your Vortex build directory + + $ TARGET=fpga ./ci/blackbox.sh --driver=opae --app=sgemm --args="-n128" + diff --git a/docs/index.md b/docs/index.md index 07faa2927..14a45f335 100644 --- a/docs/index.md +++ b/docs/index.md @@ -7,7 +7,8 @@ - [Cache Subsystem](cache_subsystem.md) - [Software](software.md) - [Simulation](simulation.md) -- [FPGA Setup Guide](fpga_setup.md) +- [Altera FPGA Setup Guide](altera_fpga_guide.md) +- [Xilinx FPGA Setup Guide](xilinx_fpga_guide.md) - [Debugging](debugging.md) - [Useful Links](references.md) @@ -27,6 +28,6 @@ Running Vortex simulators with different configurations: $ ./ci/blackbox.sh --driver=opae --clusters=1 --cores=4 --warps=4 --threads=2 --app=demo -- Run dogfood driver test with simx driver and Vortex config of 4 cluster, 4 cores, 8 warps, 6 threads +- Run dogfood driver test with simx driver and Vortex config of 4 cluster, 4 cores, 8 warps, 6 threads $ ./ci/blackbox.sh --driver=simx --clusters=4 --cores=4 --warps=8 --threads=6 --app=dogfood diff --git a/docs/xilinx_fpga_guide.md b/docs/xilinx_fpga_guide.md new file mode 100644 index 000000000..f2960deb6 --- /dev/null +++ b/docs/xilinx_fpga_guide.md @@ -0,0 +1,36 @@ +# FPGA Startup and Configuration Guide + +XRT Environment Setup +---------------------- + + $ source /opt/xilinx/Vitis/2023.1/settings64.sh + $ source /opt/xilinx/xrt/setup.sh + + +Check Installed FPGA Platforms +------------------------------ + + $ platforminfo -l + + +Build FPGA image +---------------- + + $ cd hw/syn/xilinx/xrt + $ PREFIX=test1 PLATFORM=xilinx_u50_gen3x16_xdma_5_202210_1 TARGET=hw NUM_CORES=4 make + +Will run the synthesis under new build directory: BUILD_DIR := "\\_\\_\" + +The generated bitstream will be located under /bin/vortex_afu.xclbin + +Sample FPGA Run Test +-------------------- + +Ensure you have the correct opae runtime for the FPGA target + + $ make -C runtime/xrt clean + $ TARGET=hw make -C runtime/xrt + +Run the following from your Vortex build directory + + $ TARGET=hw FPGA_BIN_DIR=/bin ./ci/blackbox.sh --driver=xrt --app=sgemm --args="-n128" \ No newline at end of file diff --git a/hw/Makefile b/hw/Makefile index f3aa5b651..6db654202 100644 --- a/hw/Makefile +++ b/hw/Makefile @@ -9,13 +9,14 @@ all: config config: VX_config.h VX_types.h -VX_config.h: $(RTL_DIR)/VX_config.vh +VX_config.h: $(RTL_DIR)/VX_config.vh $(SCRIPT_DIR)/gen_config.py -i $(RTL_DIR)/VX_config.vh -o VX_config.h -VX_types.h: $(RTL_DIR)/VX_types.vh +VX_types.h: $(RTL_DIR)/VX_types.vh $(SCRIPT_DIR)/gen_config.py -i $(RTL_DIR)/VX_types.vh -o VX_types.h clean: + $(MAKE) -C unittest clean rm -f VX_config.h VX_types.h .PHONY: VX_config.h VX_types.h \ No newline at end of file diff --git a/hw/dpi/float_dpi.vh b/hw/dpi/float_dpi.vh index 135807650..26bd10933 100644 --- a/hw/dpi/float_dpi.vh +++ b/hw/dpi/float_dpi.vh @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -14,8 +14,6 @@ `ifndef FLOAT_DPI_VH `define FLOAT_DPI_VH -`include "VX_config.vh" - import "DPI-C" function void dpi_fadd(input logic enable, input int dst_fmt, input longint a, input longint b, input bit[2:0] frm, output longint result, output bit[4:0] fflags); import "DPI-C" function void dpi_fsub(input logic enable, input int dst_fmt, input longint a, input longint b, input bit[2:0] frm, output longint result, output bit[4:0] fflags); import "DPI-C" function void dpi_fmul(input logic enable, input int dst_fmt, input longint a, input longint b, input bit[2:0] frm, output longint result, output bit[4:0] fflags); diff --git a/hw/dpi/util_dpi.vh b/hw/dpi/util_dpi.vh index dfd411c94..0da62b041 100644 --- a/hw/dpi/util_dpi.vh +++ b/hw/dpi/util_dpi.vh @@ -14,8 +14,6 @@ `ifndef UTIL_DPI_VH `define UTIL_DPI_VH -`include "VX_config.vh" - `ifdef XLEN_64 `define INT_TYPE longint `else diff --git a/hw/rtl/VX_cluster.sv b/hw/rtl/VX_cluster.sv index 98ca3e96a..108e95073 100644 --- a/hw/rtl/VX_cluster.sv +++ b/hw/rtl/VX_cluster.sv @@ -14,7 +14,8 @@ `include "VX_define.vh" module VX_cluster import VX_gpu_pkg::*; #( - parameter CLUSTER_ID = 0 + parameter CLUSTER_ID = 0, + parameter `STRING INSTANCE_ID = "" ) ( `SCOPE_IO_DECL @@ -85,7 +86,7 @@ module VX_cluster import VX_gpu_pkg::*; #( `RESET_RELAY (l2_reset, reset); VX_cache_wrap #( - .INSTANCE_ID ("l2cache"), + .INSTANCE_ID ($sformatf("%s-l2cache", INSTANCE_ID)), .CACHE_SIZE (`L2_CACHE_SIZE), .LINE_SIZE (`L2_LINE_SIZE), .NUM_BANKS (`L2_NUM_BANKS), @@ -98,6 +99,7 @@ module VX_cluster import VX_gpu_pkg::*; #( .MREQ_SIZE (`L2_MREQ_SIZE), .TAG_WIDTH (L2_TAG_WIDTH), .WRITE_ENABLE (1), + .WRITEBACK (`L2_WRITEBACK), .UUID_WIDTH (`UUID_WIDTH), .CORE_OUT_BUF (2), .MEM_OUT_BUF (2), @@ -122,17 +124,19 @@ module VX_cluster import VX_gpu_pkg::*; #( wire [`NUM_SOCKETS-1:0] per_socket_busy; + VX_dcr_bus_if socket_dcr_bus_if(); `BUFFER_DCR_BUS_IF (socket_dcr_bus_if, socket_dcr_bus_tmp_if, (`NUM_SOCKETS > 1)); // Generate all sockets - for (genvar i = 0; i < `NUM_SOCKETS; ++i) begin + for (genvar socket_id = 0; socket_id < `NUM_SOCKETS; ++socket_id) begin : sockets `RESET_RELAY (socket_reset, reset); VX_socket #( - .SOCKET_ID ((CLUSTER_ID * `NUM_SOCKETS) + i) + .SOCKET_ID ((CLUSTER_ID * `NUM_SOCKETS) + socket_id), + .INSTANCE_ID ($sformatf("%s-socket%0d", INSTANCE_ID, socket_id)) ) socket ( - `SCOPE_IO_BIND (scope_socket+i) + `SCOPE_IO_BIND (scope_socket+socket_id) .clk (clk), .reset (socket_reset), @@ -143,13 +147,13 @@ module VX_cluster import VX_gpu_pkg::*; #( .dcr_bus_if (socket_dcr_bus_if), - .mem_bus_if (per_socket_mem_bus_if[i]), + .mem_bus_if (per_socket_mem_bus_if[socket_id]), `ifdef GBAR_ENABLE - .gbar_bus_if (per_socket_gbar_bus_if[i]), + .gbar_bus_if (per_socket_gbar_bus_if[socket_id]), `endif - .busy (per_socket_busy[i]) + .busy (per_socket_busy[socket_id]) ); end diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index 5dbcb96b4..45041ac4a 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -33,10 +33,6 @@ `endif /////////////////////////////////////////////////////////////////////////////// -`ifndef VM_DISABLE -`define VM_ENABLE -`endif - `ifndef EXT_M_DISABLE `define EXT_M_ENABLE `endif @@ -114,7 +110,6 @@ `ifndef SOCKET_SIZE `define SOCKET_SIZE `MIN(4, `NUM_CORES) `endif -`define NUM_SOCKETS `UP(`NUM_CORES / `SOCKET_SIZE) `ifdef L2_ENABLE `define L2_ENABLED 1 @@ -357,7 +352,7 @@ // Number of SFU units `ifndef NUM_SFU_LANES -`define NUM_SFU_LANES `MIN(`NUM_THREADS, 4) +`define NUM_SFU_LANES `NUM_THREADS `endif `ifndef NUM_SFU_BLOCKS `define NUM_SFU_BLOCKS 1 @@ -481,22 +476,27 @@ `define LATENCY_FCVT 5 `endif +// FMA Bandwidth ratio `ifndef FMA_PE_RATIO `define FMA_PE_RATIO 1 `endif +// FDIV Bandwidth ratio `ifndef FDIV_PE_RATIO `define FDIV_PE_RATIO 8 `endif +// FSQRT Bandwidth ratio `ifndef FSQRT_PE_RATIO `define FSQRT_PE_RATIO 8 `endif +// FCVT Bandwidth ratio `ifndef FCVT_PE_RATIO `define FCVT_PE_RATIO 8 `endif +// FNCP Bandwidth ratio `ifndef FNCP_PE_RATIO `define FNCP_PE_RATIO 2 `endif @@ -603,7 +603,12 @@ `define DCACHE_NUM_WAYS 1 `endif -// SM Configurable Knobs ////////////////////////////////////////////////////// +// Enable Cache Writeback +`ifndef DCACHE_WRITEBACK +`define DCACHE_WRITEBACK 0 +`endif + +// LMEM Configurable Knobs //////////////////////////////////////////////////// `ifndef LMEM_DISABLE `define LMEM_ENABLE @@ -662,6 +667,11 @@ `define L2_NUM_WAYS 2 `endif +// Enable Cache Writeback +`ifndef L2_WRITEBACK +`define L2_WRITEBACK 0 +`endif + // L3cache Configurable Knobs ///////////////////////////////////////////////// // Cache Size @@ -703,6 +713,11 @@ `define L3_NUM_WAYS 4 `endif +// Enable Cache Writeback +`ifndef L3_WRITEBACK +`define L3_WRITEBACK 0 +`endif + // ISA Extensions ///////////////////////////////////////////////////////////// `ifdef EXT_A_ENABLE diff --git a/hw/rtl/VX_define.vh b/hw/rtl/VX_define.vh index d7d38a930..686124c16 100644 --- a/hw/rtl/VX_define.vh +++ b/hw/rtl/VX_define.vh @@ -59,6 +59,8 @@ `define OFFSET_BITS 12 `define IMM_BITS `XLEN +`define NUM_SOCKETS `UP(`NUM_CORES / `SOCKET_SIZE) + /////////////////////////////////////////////////////////////////////////////// `define EX_ALU 0 @@ -296,6 +298,7 @@ `ifdef ICACHE_ENABLE `define L1_ENABLE `endif + `ifdef DCACHE_ENABLE `define L1_ENABLE `endif @@ -322,7 +325,7 @@ .DATAW ($bits(dst)), \ .RESETW ($bits(dst)), \ .DEPTH (latency) \ - ) __``dst ( \ + ) __``dst``__ ( \ .clk (clk), \ .reset (reset), \ .enable (ena), \ @@ -336,13 +339,18 @@ VX_popcount #( \ .N ($bits(in)), \ .MODEL (model) \ - ) __``out ( \ + ) __``out``__ ( \ .data_in (in), \ .data_out (out) \ ) `define POP_COUNT(out, in) `POP_COUNT_EX(out, in, 1) +`define ASSIGN_VX_IF(dst, src) \ + assign dst.valid = src.valid; \ + assign dst.data = src.data; \ + assign src.ready = dst.ready + `define ASSIGN_VX_MEM_BUS_IF(dst, src) \ assign dst.req_valid = src.req_valid; \ assign dst.req_data = src.req_data; \ @@ -377,42 +385,42 @@ assign dst.rsp_ready = src.rsp_ready `define BUFFER_DCR_BUS_IF(dst, src, enable) \ - logic [(1 + `VX_DCR_ADDR_WIDTH + `VX_DCR_DATA_WIDTH)-1:0] __``dst; \ if (enable) begin \ + reg [(1 + `VX_DCR_ADDR_WIDTH + `VX_DCR_DATA_WIDTH)-1:0] __dst; \ always @(posedge clk) begin \ - __``dst <= {src.write_valid, src.write_addr, src.write_data}; \ + __dst <= {src.write_valid, src.write_addr, src.write_data}; \ end \ + assign {dst.write_valid, dst.write_addr, dst.write_data} = __dst; \ end else begin \ - assign __``dst = {src.write_valid, src.write_addr, src.write_data}; \ - end \ - VX_dcr_bus_if dst(); \ - assign {dst.write_valid, dst.write_addr, dst.write_data} = __``dst + assign {dst.write_valid, dst.write_addr, dst.write_data} = {src.write_valid, src.write_addr, src.write_data}; \ + end -`define PERF_COUNTER_ADD(dst, src, field, width, dst_count, src_count, reg_enable) \ - for (genvar __d = 0; __d < dst_count; ++__d) begin \ - localparam __count = ((src_count > dst_count) ? `CDIV(src_count, dst_count) : 1); \ - wire [__count-1:0][width-1:0] __reduce_add_i_``src``field; \ - wire [width-1:0] __reduce_add_o_``dst``field; \ - for (genvar __i = 0; __i < __count; ++__i) begin \ - assign __reduce_add_i_``src``field[__i] = ``src[__d * __count + __i].``field; \ +`define PERF_COUNTER_ADD(dst, src, field, width, count, reg_enable) \ + if (count > 1) begin \ + wire [count-1:0][width-1:0] __reduce_add_i_field; \ + wire [width-1:0] __reduce_add_o_field; \ + for (genvar __i = 0; __i < count; ++__i) begin \ + assign __reduce_add_i_field[__i] = src[__i].``field; \ end \ - VX_reduce #(.DATAW_IN(width), .N(__count), .OP("+")) __reduce_add_``dst``field ( \ - __reduce_add_i_``src``field, \ - __reduce_add_o_``dst``field \ + VX_reduce #(.DATAW_IN(width), .N(count), .OP("+")) __reduce_add_field ( \ + __reduce_add_i_field, \ + __reduce_add_o_field \ ); \ if (reg_enable) begin \ - reg [width-1:0] __reduce_add_r_``dst``field; \ + reg [width-1:0] __reduce_add_r_field; \ always @(posedge clk) begin \ if (reset) begin \ - __reduce_add_r_``dst``field <= '0; \ + __reduce_add_r_field <= '0; \ end else begin \ - __reduce_add_r_``dst``field <= __reduce_add_o_``dst``field; \ + __reduce_add_r_field <= __reduce_add_o_field; \ end \ end \ - assign ``dst[__d].``field = __reduce_add_r_``dst``field; \ + assign dst.``field = __reduce_add_r_field; \ end else begin \ - assign ``dst[__d].``field = __reduce_add_o_``dst``field; \ + assign dst.``field = __reduce_add_o_field; \ end \ + end else begin \ + assign dst.``field = src[0].``field; \ end `define ASSIGN_BLOCKED_WID(dst, src, block_idx, block_size) \ @@ -426,20 +434,4 @@ assign dst = src; \ end -`define TO_DISPATCH_DATA(data, tid) { \ - data.uuid, \ - data.wis, \ - data.tmask, \ - data.PC, \ - data.op_type, \ - data.op_args, \ - data.wb, \ - data.rd, \ - tid, \ - data.rs1_data, \ - data.rs2_data, \ - data.rs3_data} - -/////////////////////////////////////////////////////////////////////////////// - `endif // VX_DEFINE_VH diff --git a/hw/rtl/VX_gpu_pkg.sv b/hw/rtl/VX_gpu_pkg.sv index 6de25f139..393f2a66f 100644 --- a/hw/rtl/VX_gpu_pkg.sv +++ b/hw/rtl/VX_gpu_pkg.sv @@ -60,6 +60,8 @@ package VX_gpu_pkg; logic [7:0] mpm_class; } base_dcrs_t; + //////////////////////////// Perf counter types /////////////////////////// + typedef struct packed { logic [`PERF_CTR_BITS-1:0] reads; logic [`PERF_CTR_BITS-1:0] writes; @@ -77,48 +79,63 @@ package VX_gpu_pkg; logic [`PERF_CTR_BITS-1:0] latency; } mem_perf_t; + typedef struct packed { + logic [`PERF_CTR_BITS-1:0] idles; + logic [`PERF_CTR_BITS-1:0] stalls; + } sched_perf_t; + + typedef struct packed { + logic [`PERF_CTR_BITS-1:0] ibf_stalls; + logic [`PERF_CTR_BITS-1:0] scb_stalls; + logic [`PERF_CTR_BITS-1:0] opd_stalls; + logic [`NUM_EX_UNITS-1:0][`PERF_CTR_BITS-1:0] units_uses; + logic [`NUM_SFU_UNITS-1:0][`PERF_CTR_BITS-1:0] sfu_uses; + } issue_perf_t; + + //////////////////////// instruction arguments //////////////////////////// + typedef struct packed { logic use_PC; logic use_imm; logic is_w; logic [`ALU_TYPE_BITS-1:0] xtype; logic [`IMM_BITS-1:0] imm; - } alu_mod_t; + } alu_args_t; typedef struct packed { - logic [($bits(alu_mod_t)-`INST_FRM_BITS-`INST_FMT_BITS)-1:0] __padding; + logic [($bits(alu_args_t)-`INST_FRM_BITS-`INST_FMT_BITS)-1:0] __padding; logic [`INST_FRM_BITS-1:0] frm; logic [`INST_FMT_BITS-1:0] fmt; - } fpu_mod_t; + } fpu_args_t; typedef struct packed { - logic [($bits(alu_mod_t)-1-1-`OFFSET_BITS)-1:0] __padding; + logic [($bits(alu_args_t)-1-1-`OFFSET_BITS)-1:0] __padding; logic is_store; logic is_float; logic [`OFFSET_BITS-1:0] offset; - } lsu_mod_t; + } lsu_args_t; typedef struct packed { - logic [($bits(alu_mod_t)-1-`VX_CSR_ADDR_BITS-5)-1:0] __padding; + logic [($bits(alu_args_t)-1-`VX_CSR_ADDR_BITS-5)-1:0] __padding; logic use_imm; logic [`VX_CSR_ADDR_BITS-1:0] addr; logic [4:0] imm; - } csr_mod_t; + } csr_args_t; typedef struct packed { - logic [($bits(alu_mod_t)-1)-1:0] __padding; + logic [($bits(alu_args_t)-1)-1:0] __padding; logic is_neg; - } wctl_mod_t; + } wctl_args_t; typedef union packed { - alu_mod_t alu; - fpu_mod_t fpu; - lsu_mod_t lsu; - csr_mod_t csr; - wctl_mod_t wctl; + alu_args_t alu; + fpu_args_t fpu; + lsu_args_t lsu; + csr_args_t csr; + wctl_args_t wctl; } op_args_t; - /* verilator lint_off UNUSED */ +`IGNORE_UNUSED_BEGIN ///////////////////////// LSU memory Parameters /////////////////////////// @@ -129,6 +146,31 @@ package VX_gpu_pkg; localparam LSU_TAG_WIDTH = (`UUID_WIDTH + LSU_TAG_ID_BITS); localparam LSU_NUM_REQS = `NUM_LSU_BLOCKS * `NUM_LSU_LANES; + ////////////////////////// Icache Parameters ////////////////////////////// + + // Word size in bytes + localparam ICACHE_WORD_SIZE = 4; + localparam ICACHE_ADDR_WIDTH = (`MEM_ADDR_WIDTH - `CLOG2(ICACHE_WORD_SIZE)); + + // Block size in bytes + localparam ICACHE_LINE_SIZE = `L1_LINE_SIZE; + + // Core request tag Id bits + localparam ICACHE_TAG_ID_BITS = `NW_WIDTH; + + // Core request tag bits + localparam ICACHE_TAG_WIDTH = (`UUID_WIDTH + ICACHE_TAG_ID_BITS); + + // Memory request data bits + localparam ICACHE_MEM_DATA_WIDTH = (ICACHE_LINE_SIZE * 8); + + // Memory request tag bits +`ifdef ICACHE_ENABLE + localparam ICACHE_MEM_TAG_WIDTH = `CACHE_CLUSTER_MEM_TAG_WIDTH(`ICACHE_MSHR_SIZE, 1, `NUM_ICACHES); +`else + localparam ICACHE_MEM_TAG_WIDTH = `CACHE_CLUSTER_BYPASS_MEM_TAG_WIDTH(1, ICACHE_LINE_SIZE, ICACHE_WORD_SIZE, ICACHE_TAG_WIDTH, `SOCKET_SIZE, `NUM_ICACHES); +`endif + ////////////////////////// Dcache Parameters ////////////////////////////// // Word size in bytes @@ -154,36 +196,11 @@ package VX_gpu_pkg; localparam DCACHE_MEM_DATA_WIDTH = (DCACHE_LINE_SIZE * 8); // Memory request tag bits - `ifdef DCACHE_ENABLE +`ifdef DCACHE_ENABLE localparam DCACHE_MEM_TAG_WIDTH = `CACHE_CLUSTER_NC_MEM_TAG_WIDTH(`DCACHE_MSHR_SIZE, `DCACHE_NUM_BANKS, DCACHE_NUM_REQS, DCACHE_LINE_SIZE, DCACHE_WORD_SIZE, DCACHE_TAG_WIDTH, `SOCKET_SIZE, `NUM_DCACHES); - `else +`else localparam DCACHE_MEM_TAG_WIDTH = `CACHE_CLUSTER_BYPASS_MEM_TAG_WIDTH(DCACHE_NUM_REQS, DCACHE_LINE_SIZE, DCACHE_WORD_SIZE, DCACHE_TAG_WIDTH, `SOCKET_SIZE, `NUM_DCACHES); - `endif - - ////////////////////////// Icache Parameters ////////////////////////////// - - // Word size in bytes - localparam ICACHE_WORD_SIZE = 4; - localparam ICACHE_ADDR_WIDTH = (`MEM_ADDR_WIDTH - `CLOG2(ICACHE_WORD_SIZE)); - - // Block size in bytes - localparam ICACHE_LINE_SIZE = `L1_LINE_SIZE; - - // Core request tag Id bits - localparam ICACHE_TAG_ID_BITS = `NW_WIDTH; - - // Core request tag bits - localparam ICACHE_TAG_WIDTH = (`UUID_WIDTH + ICACHE_TAG_ID_BITS); - - // Memory request data bits - localparam ICACHE_MEM_DATA_WIDTH = (ICACHE_LINE_SIZE * 8); - - // Memory request tag bits - `ifdef ICACHE_ENABLE - localparam ICACHE_MEM_TAG_WIDTH = `CACHE_CLUSTER_MEM_TAG_WIDTH(`ICACHE_MSHR_SIZE, 1, `NUM_ICACHES); - `else - localparam ICACHE_MEM_TAG_WIDTH = `CACHE_CLUSTER_BYPASS_MEM_TAG_WIDTH(1, ICACHE_LINE_SIZE, ICACHE_WORD_SIZE, ICACHE_TAG_WIDTH, `SOCKET_SIZE, `NUM_ICACHES); - `endif +`endif /////////////////////////////// L1 Parameters ///////////////////////////// @@ -208,11 +225,11 @@ package VX_gpu_pkg; localparam L2_MEM_DATA_WIDTH = (`L2_LINE_SIZE * 8); // Memory request tag bits - `ifdef L2_ENABLE +`ifdef L2_ENABLE localparam L2_MEM_TAG_WIDTH = `CACHE_NC_MEM_TAG_WIDTH(`L2_MSHR_SIZE, `L2_NUM_BANKS, L2_NUM_REQS, `L2_LINE_SIZE, L2_WORD_SIZE, L2_TAG_WIDTH); - `else +`else localparam L2_MEM_TAG_WIDTH = `CACHE_BYPASS_TAG_WIDTH(L2_NUM_REQS, `L2_LINE_SIZE, L2_WORD_SIZE, L2_TAG_WIDTH); - `endif +`endif /////////////////////////////// L3 Parameters ///////////////////////////// @@ -229,23 +246,20 @@ package VX_gpu_pkg; localparam L3_MEM_DATA_WIDTH = (`L3_LINE_SIZE * 8); // Memory request tag bits - `ifdef L3_ENABLE +`ifdef L3_ENABLE localparam L3_MEM_TAG_WIDTH = `CACHE_NC_MEM_TAG_WIDTH(`L3_MSHR_SIZE, `L3_NUM_BANKS, L3_NUM_REQS, `L3_LINE_SIZE, L3_WORD_SIZE, L3_TAG_WIDTH); - `else +`else localparam L3_MEM_TAG_WIDTH = `CACHE_BYPASS_TAG_WIDTH(L3_NUM_REQS, `L3_LINE_SIZE, L3_WORD_SIZE, L3_TAG_WIDTH); - `endif - - /* verilator lint_on UNUSED */ +`endif /////////////////////////////// Issue parameters ////////////////////////// localparam ISSUE_ISW = `CLOG2(`ISSUE_WIDTH); localparam ISSUE_ISW_W = `UP(ISSUE_ISW); - localparam ISSUE_RATIO = `NUM_WARPS / `ISSUE_WIDTH; - localparam ISSUE_WIS = `CLOG2(ISSUE_RATIO); + localparam PER_ISSUE_WARPS = `NUM_WARPS / `ISSUE_WIDTH; + localparam ISSUE_WIS = `CLOG2(PER_ISSUE_WARPS); localparam ISSUE_WIS_W = `UP(ISSUE_WIS); -`IGNORE_UNUSED_BEGIN function logic [`NW_WIDTH-1:0] wis_to_wid( input logic [ISSUE_WIS_W-1:0] wis, input logic [ISSUE_ISW_W-1:0] isw @@ -278,6 +292,20 @@ package VX_gpu_pkg; wid_to_wis = 0; end endfunction + + ///////////////////////// Miscaellaneous functions //////////////////////// + + function logic [`SFU_WIDTH-1:0] op_to_sfu_type( + input logic [`INST_OP_BITS-1:0] op_type + ); + case (op_type) + `INST_SFU_CSRRW, + `INST_SFU_CSRRS, + `INST_SFU_CSRRC: op_to_sfu_type = `SFU_CSRS; + default: op_to_sfu_type = `SFU_WCTL; + endcase + endfunction + `IGNORE_UNUSED_END endpackage diff --git a/hw/rtl/VX_platform.vh b/hw/rtl/VX_platform.vh index 9769d81f7..73a6edd78 100644 --- a/hw/rtl/VX_platform.vh +++ b/hw/rtl/VX_platform.vh @@ -47,7 +47,7 @@ `define UNUSED_VAR(x) `define UNUSED_PIN(x) . x () `define UNUSED_ARG(x) x -`define TRACE(level, args) $write args +`define TRACE(level, args) if (level <= `DEBUG_LEVEL) $write args `else `ifdef VERILATOR `define TRACING_ON /* verilator tracing_on */ @@ -112,8 +112,14 @@ `define UNUSED_ARG(x) /* verilator lint_off UNUSED */ \ x \ /* verilator lint_on UNUSED */ -`define TRACE(level, args) dpi_trace(level, $sformatf args) `endif + +`ifdef SV_DPI +`define TRACE(level, args) dpi_trace(level, $sformatf args) +`else +`define TRACE(level, args) if (level <= `DEBUG_LEVEL) $write args +`endif + `endif `ifdef SIMULATION diff --git a/hw/rtl/VX_socket.sv b/hw/rtl/VX_socket.sv index 0f329a72b..abdf67612 100644 --- a/hw/rtl/VX_socket.sv +++ b/hw/rtl/VX_socket.sv @@ -14,7 +14,8 @@ `include "VX_define.vh" module VX_socket import VX_gpu_pkg::*; #( - parameter SOCKET_ID = 0 + parameter SOCKET_ID = 0, + parameter `STRING INSTANCE_ID = "" ) ( `SCOPE_IO_DECL @@ -40,6 +41,11 @@ module VX_socket import VX_gpu_pkg::*; #( output wire busy ); +`ifdef SCOPE + localparam scope_core = 0; + `SCOPE_IO_SWITCH (`SOCKET_SIZE); +`endif + `ifdef GBAR_ENABLE VX_gbar_bus_if per_core_gbar_bus_if[`SOCKET_SIZE](); @@ -81,7 +87,7 @@ module VX_socket import VX_gpu_pkg::*; #( `RESET_RELAY (icache_reset, reset); VX_cache_cluster #( - .INSTANCE_ID ($sformatf("socket%0d-icache", SOCKET_ID)), + .INSTANCE_ID ($sformatf("%s-icache", INSTANCE_ID)), .NUM_UNITS (`NUM_ICACHES), .NUM_INPUTS (`SOCKET_SIZE), .TAG_SEL_IDX (0), @@ -126,7 +132,7 @@ module VX_socket import VX_gpu_pkg::*; #( `RESET_RELAY (dcache_reset, reset); VX_cache_cluster #( - .INSTANCE_ID ($sformatf("socket%0d-dcache", SOCKET_ID)), + .INSTANCE_ID ($sformatf("%s-dcache", INSTANCE_ID)), .NUM_UNITS (`NUM_DCACHES), .NUM_INPUTS (`SOCKET_SIZE), .TAG_SEL_IDX (0), @@ -143,8 +149,9 @@ module VX_socket import VX_gpu_pkg::*; #( .TAG_WIDTH (DCACHE_TAG_WIDTH), .UUID_WIDTH (`UUID_WIDTH), .WRITE_ENABLE (1), + .WRITEBACK (`DCACHE_WRITEBACK), .NC_ENABLE (1), - .CORE_OUT_BUF (`LMEM_ENABLED ? 2 : 1), + .CORE_OUT_BUF (2), .MEM_OUT_BUF (2) ) dcache ( `ifdef PERF_ENABLE @@ -194,19 +201,19 @@ module VX_socket import VX_gpu_pkg::*; #( wire [`SOCKET_SIZE-1:0] per_core_busy; + VX_dcr_bus_if core_dcr_bus_if(); `BUFFER_DCR_BUS_IF (core_dcr_bus_if, dcr_bus_if, (`SOCKET_SIZE > 1)); - `SCOPE_IO_SWITCH (`SOCKET_SIZE) - // Generate all cores - for (genvar i = 0; i < `SOCKET_SIZE; ++i) begin + for (genvar core_id = 0; core_id < `SOCKET_SIZE; ++core_id) begin : cores `RESET_RELAY (core_reset, reset); VX_core #( - .CORE_ID ((SOCKET_ID * `SOCKET_SIZE) + i) + .CORE_ID ((SOCKET_ID * `SOCKET_SIZE) + core_id), + .INSTANCE_ID ($sformatf("%s-core%0d", INSTANCE_ID, core_id)) ) core ( - `SCOPE_IO_BIND (i) + `SCOPE_IO_BIND (scope_core + core_id) .clk (clk), .reset (core_reset), @@ -217,15 +224,15 @@ module VX_socket import VX_gpu_pkg::*; #( .dcr_bus_if (core_dcr_bus_if), - .dcache_bus_if (per_core_dcache_bus_if[i * DCACHE_NUM_REQS +: DCACHE_NUM_REQS]), + .dcache_bus_if (per_core_dcache_bus_if[core_id * DCACHE_NUM_REQS +: DCACHE_NUM_REQS]), - .icache_bus_if (per_core_icache_bus_if[i]), + .icache_bus_if (per_core_icache_bus_if[core_id]), `ifdef GBAR_ENABLE - .gbar_bus_if (per_core_gbar_bus_if[i]), + .gbar_bus_if (per_core_gbar_bus_if[core_id]), `endif - .busy (per_core_busy[i]) + .busy (per_core_busy[core_id]) ); end diff --git a/hw/rtl/VX_types.vh b/hw/rtl/VX_types.vh index e744a26f9..927ffae96 100644 --- a/hw/rtl/VX_types.vh +++ b/hw/rtl/VX_types.vh @@ -85,30 +85,31 @@ `define VX_CSR_MPM_IBUF_ST_H 12'hB85 `define VX_CSR_MPM_SCRB_ST 12'hB06 `define VX_CSR_MPM_SCRB_ST_H 12'hB86 -`define VX_CSR_MPM_SCRB_ALU 12'hB07 -`define VX_CSR_MPM_SCRB_ALU_H 12'hB87 -`define VX_CSR_MPM_SCRB_FPU 12'hB08 -`define VX_CSR_MPM_SCRB_FPU_H 12'hB88 -`define VX_CSR_MPM_SCRB_LSU 12'hB09 -`define VX_CSR_MPM_SCRB_LSU_H 12'hB89 -`define VX_CSR_MPM_SCRB_SFU 12'hB0A -`define VX_CSR_MPM_SCRB_SFU_H 12'hB8A +`define VX_CSR_MPM_OPDS_ST 12'hB07 +`define VX_CSR_MPM_OPDS_ST_H 12'hB87 +`define VX_CSR_MPM_SCRB_ALU 12'hB08 +`define VX_CSR_MPM_SCRB_ALU_H 12'hB88 +`define VX_CSR_MPM_SCRB_FPU 12'hB09 +`define VX_CSR_MPM_SCRB_FPU_H 12'hB89 +`define VX_CSR_MPM_SCRB_LSU 12'hB0A +`define VX_CSR_MPM_SCRB_LSU_H 12'hB8A +`define VX_CSR_MPM_SCRB_SFU 12'hB0B +`define VX_CSR_MPM_SCRB_SFU_H 12'hB8B +`define VX_CSR_MPM_SCRB_CSRS 12'hB0C +`define VX_CSR_MPM_SCRB_CSRS_H 12'hB8C +`define VX_CSR_MPM_SCRB_WCTL 12'hB0D +`define VX_CSR_MPM_SCRB_WCTL_H 12'hB8D // PERF: memory -`define VX_CSR_MPM_IFETCHES 12'hB0B -`define VX_CSR_MPM_IFETCHES_H 12'hB8B -`define VX_CSR_MPM_LOADS 12'hB0C -`define VX_CSR_MPM_LOADS_H 12'hB8C -`define VX_CSR_MPM_STORES 12'hB0D -`define VX_CSR_MPM_STORES_H 12'hB8D -`define VX_CSR_MPM_IFETCH_LT 12'hB0E -`define VX_CSR_MPM_IFETCH_LT_H 12'hB8E -`define VX_CSR_MPM_LOAD_LT 12'hB0F -`define VX_CSR_MPM_LOAD_LT_H 12'hB8F -// SFU: scoreboard -`define VX_CSR_MPM_SCRB_WCTL 12'hB10 -`define VX_CSR_MPM_SCRB_WCTL_H 12'hB90 -`define VX_CSR_MPM_SCRB_CSRS 12'hB11 -`define VX_CSR_MPM_SCRB_CSRS_H 12'hB91 +`define VX_CSR_MPM_IFETCHES 12'hB0E +`define VX_CSR_MPM_IFETCHES_H 12'hB8E +`define VX_CSR_MPM_LOADS 12'hB0F +`define VX_CSR_MPM_LOADS_H 12'hB8F +`define VX_CSR_MPM_STORES 12'hB10 +`define VX_CSR_MPM_STORES_H 12'hB90 +`define VX_CSR_MPM_IFETCH_LT 12'hB11 +`define VX_CSR_MPM_IFETCH_LT_H 12'hB91 +`define VX_CSR_MPM_LOAD_LT 12'hB12 +`define VX_CSR_MPM_LOAD_LT_H 12'hB92 // Machine Performance-monitoring memory counters (class 2) /////////////////// diff --git a/hw/rtl/Vortex.sv b/hw/rtl/Vortex.sv index 2c8b3389f..d3ef57c72 100644 --- a/hw/rtl/Vortex.sv +++ b/hw/rtl/Vortex.sv @@ -44,6 +44,11 @@ module Vortex import VX_gpu_pkg::*; ( output wire busy ); +`ifdef SCOPE + localparam scope_cluster = 0; + `SCOPE_IO_SWITCH (`NUM_CLUSTERS); +`endif + `ifdef PERF_ENABLE VX_mem_perf_if mem_perf_if(); assign mem_perf_if.icache = 'x; @@ -78,6 +83,7 @@ module Vortex import VX_gpu_pkg::*; ( .MREQ_SIZE (`L3_MREQ_SIZE), .TAG_WIDTH (L2_MEM_TAG_WIDTH), .WRITE_ENABLE (1), + .WRITEBACK (`L3_WRITEBACK), .UUID_WIDTH (`UUID_WIDTH), .CORE_OUT_BUF (2), .MEM_OUT_BUF (2), @@ -121,19 +127,19 @@ module Vortex import VX_gpu_pkg::*; ( wire [`NUM_CLUSTERS-1:0] per_cluster_busy; - `SCOPE_IO_SWITCH (`NUM_CLUSTERS) - // Generate all clusters - for (genvar i = 0; i < `NUM_CLUSTERS; ++i) begin + for (genvar cluster_id = 0; cluster_id < `NUM_CLUSTERS; ++cluster_id) begin : clusters `RESET_RELAY (cluster_reset, reset); + VX_dcr_bus_if cluster_dcr_bus_if(); `BUFFER_DCR_BUS_IF (cluster_dcr_bus_if, dcr_bus_if, (`NUM_CLUSTERS > 1)); VX_cluster #( - .CLUSTER_ID (i) + .CLUSTER_ID (cluster_id), + .INSTANCE_ID ($sformatf("cluster%0d", cluster_id)) ) cluster ( - `SCOPE_IO_BIND (i) + `SCOPE_IO_BIND (scope_cluster + cluster_id) .clk (clk), .reset (cluster_reset), @@ -144,9 +150,9 @@ module Vortex import VX_gpu_pkg::*; ( .dcr_bus_if (cluster_dcr_bus_if), - .mem_bus_if (per_cluster_mem_bus_if[i]), + .mem_bus_if (per_cluster_mem_bus_if[cluster_id]), - .busy (per_cluster_busy[i]) + .busy (per_cluster_busy[cluster_id]) ); end diff --git a/hw/rtl/afu/opae/ccip_std_afu.sv b/hw/rtl/afu/opae/ccip_std_afu.sv index 2adea591f..b042ba61d 100644 --- a/hw/rtl/afu/opae/ccip_std_afu.sv +++ b/hw/rtl/afu/opae/ccip_std_afu.sv @@ -5,6 +5,7 @@ // To be done: // Check how to run this with OPAE. Looks like setup issue +`ifndef NOPAE `include "platform_if.vh" @@ -85,7 +86,7 @@ module ccip_std_afu #( t_local_mem_data avs_writedata [NUM_LOCAL_MEM_BANKS]; t_local_mem_addr avs_address [NUM_LOCAL_MEM_BANKS]; logic avs_write [NUM_LOCAL_MEM_BANKS]; - logic avs_read [NUM_LOCAL_MEM_BANKS]; + logic avs_read [NUM_LOCAL_MEM_BANKS]; for (genvar b = 0; b < NUM_LOCAL_MEM_BANKS; b++) begin assign local_mem[b].burstcount = avs_burstcount[b]; @@ -94,7 +95,7 @@ module ccip_std_afu #( assign local_mem[b].byteenable = avs_byteenable[b]; assign local_mem[b].write = avs_write[b]; assign local_mem[b].read = avs_read[b]; - + assign avs_waitrequest[b] = local_mem[b].waitrequest; assign avs_readdata[b] = local_mem[b].readdata; assign avs_readdatavalid[b] = local_mem[b].readdatavalid; @@ -107,7 +108,7 @@ module ccip_std_afu #( .reset (reset_T1), .cp2af_sRxPort (cp2af_sRx_T1), - .af2cp_sTxPort (af2cp_sTx_T0), + .af2cp_sTxPort (af2cp_sTx_T0), .avs_writedata (avs_writedata), .avs_readdata (avs_readdata), @@ -121,3 +122,5 @@ module ccip_std_afu #( ); endmodule + +`endif diff --git a/hw/rtl/afu/opae/vortex_afu.sv b/hw/rtl/afu/opae/vortex_afu.sv index e7b63e731..cd49e7ddd 100644 --- a/hw/rtl/afu/opae/vortex_afu.sv +++ b/hw/rtl/afu/opae/vortex_afu.sv @@ -587,7 +587,7 @@ module vortex_afu import ccip_if_pkg::*; import local_mem_cfg_pkg::*; import VX_ .DATA_SIZE (LMEM_DATA_SIZE), .ADDR_WIDTH (LMEM_ADDR_WIDTH), .TAG_WIDTH (AVS_REQ_TAGW), - .ARBITER ("P"), + .ARBITER ("P"), // prioritize VX requests .REQ_OUT_BUF (0), .RSP_OUT_BUF (0) ) mem_arb ( @@ -692,9 +692,11 @@ module vortex_afu import ccip_if_pkg::*; import local_mem_cfg_pkg::*; import VX_ .reset (reset), .incr (cci_rd_req_fire), .decr (cci_rdq_pop), + `UNUSED_PIN (empty), + `UNUSED_PIN (alm_empty), .full (cci_pending_reads_full), - .size (cci_pending_reads), - `UNUSED_PIN (empty) + `UNUSED_PIN (alm_full), + .size (cci_pending_reads) ); `UNUSED_VAR (cci_pending_reads) @@ -852,7 +854,9 @@ module vortex_afu import ccip_if_pkg::*; import local_mem_cfg_pkg::*; import VX_ .incr (cci_mem_rd_rsp_fire), .decr (cci_wr_rsp_fire), .empty (cci_pending_writes_empty), + `UNUSED_PIN (alm_empty), .full (cci_pending_writes_full), + `UNUSED_PIN (alm_full), .size (cci_pending_writes) ); @@ -1010,7 +1014,6 @@ module vortex_afu import ccip_if_pkg::*; import local_mem_cfg_pkg::*; import VX_ // SCOPE ////////////////////////////////////////////////////////////////////// `ifdef DBG_SCOPE_AFU -`ifdef SCOPE wire mem_req_fire = mem_bus_if[0].req_valid && mem_bus_if[0].req_ready; wire mem_rsp_fire = mem_bus_if[0].rsp_valid && mem_bus_if[0].rsp_ready; wire avs_write_fire = avs_write[0] && ~avs_waitrequest[0]; @@ -1080,7 +1083,6 @@ module vortex_afu import ccip_if_pkg::*; import local_mem_cfg_pkg::*; import VX_ .bus_in(scope_bus_in_w[0]), .bus_out(scope_bus_out_w[0]) ); -`endif `else `SCOPE_IO_UNUSED_W(0) `endif diff --git a/hw/rtl/afu/xrt/VX_afu_wrap.sv b/hw/rtl/afu/xrt/VX_afu_wrap.sv index 69dbbe5f5..15be69007 100644 --- a/hw/rtl/afu/xrt/VX_afu_wrap.sv +++ b/hw/rtl/afu/xrt/VX_afu_wrap.sv @@ -311,7 +311,6 @@ module VX_afu_wrap #( // SCOPE ////////////////////////////////////////////////////////////////////// `ifdef DBG_SCOPE_AFU -`ifdef SCOPE `define TRIGGERS { \ reset, \ ap_start, \ @@ -330,35 +329,17 @@ module VX_afu_wrap #( VX_scope_tap #( .SCOPE_ID (0), .TRIGGERW ($bits(`TRIGGERS)), - .PROBEW ($bits(`PROBES)) + .PROBEW ($bits(`PROBES)) ) scope_tap ( - .clk(clk), - .reset(scope_reset_w[0]), - .start(1'b0), - .stop(1'b0), - .triggers(`TRIGGERS), - .probes(`PROBES), - .bus_in(scope_bus_in_w[0]), - .bus_out(scope_bus_out_w[0]) + .clk (clk), + .reset (scope_reset_w[0]), + .start (1'b0), + .stop (1'b0), + .triggers (`TRIGGERS), + .probes (`PROBES), + .bus_in (scope_bus_in_w[0]), + .bus_out (scope_bus_out_w[0]) ); -`endif -`ifdef CHIPSCOPE - ila_afu ila_afu_inst ( - .clk (ap_clk), - .probe0 ({ - ap_start, - ap_done, - ap_idle, - interrupt - }), - .probe1 ({ - vx_pending_writes, - vx_busy_wait, - vx_busy, - vx_running - }) - ); -`endif `else `SCOPE_IO_UNUSED_W(0) `endif diff --git a/hw/rtl/cache/VX_bank_flush.sv b/hw/rtl/cache/VX_bank_flush.sv new file mode 100644 index 000000000..15d1e8379 --- /dev/null +++ b/hw/rtl/cache/VX_bank_flush.sv @@ -0,0 +1,109 @@ +// Copyright © 2019-2023 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +`include "VX_cache_define.vh" + +module VX_bank_flush #( + // Size of cache in bytes + parameter CACHE_SIZE = 1024, + // Size of line inside a bank in bytes + parameter LINE_SIZE = 64, + // Number of banks + parameter NUM_BANKS = 1, + // Number of associative ways + parameter NUM_WAYS = 1, + // Enable cache writeback + parameter WRITEBACK = 0 +) ( + input wire clk, + input wire reset, + input wire flush_in_valid, + output wire flush_in_ready, + output wire flush_out_init, + output wire flush_out_valid, + output wire [`CS_LINE_SEL_BITS-1:0] flush_out_line, + output wire [NUM_WAYS-1:0] flush_out_way, + input wire flush_out_ready, + input wire mshr_empty +); + parameter CTR_WIDTH = `CS_LINE_SEL_BITS + (WRITEBACK ? `CS_WAY_SEL_BITS : 0); + + parameter STATE_IDLE = 2'd0; + parameter STATE_INIT = 2'd1; + parameter STATE_FLUSH = 2'd2; + + reg [CTR_WIDTH-1:0] counter_r; + reg [1:0] state_r, state_n; + reg flush_in_ready_r, flush_in_ready_n; + + always @(*) begin + state_n = state_r; + flush_in_ready_n = 0; + case (state_r) + // STATE_IDLE + default: begin + if (flush_in_valid && mshr_empty) begin + state_n = STATE_FLUSH; + end + end + STATE_INIT: begin + if (counter_r == ((2 ** `CS_LINE_SEL_BITS)-1)) begin + state_n = STATE_IDLE; + end + end + STATE_FLUSH: begin + if (counter_r == ((2 ** CTR_WIDTH)-1)) begin + state_n = STATE_IDLE; + flush_in_ready_n = 1; + end + end + endcase + end + + always @(posedge clk) begin + if (reset) begin + state_r <= STATE_INIT; + counter_r <= '0; + flush_in_ready_r <= '0; + end else begin + state_r <= state_n; + flush_in_ready_r <= flush_in_ready_n; + if (state_r != STATE_IDLE) begin + if ((state_r == STATE_INIT) || flush_out_ready) begin + counter_r <= counter_r + CTR_WIDTH'(1); + end + end else begin + counter_r <= '0; + end + end + end + + assign flush_in_ready = flush_in_ready_r; + + assign flush_out_init = (state_r == STATE_INIT); + + assign flush_out_valid = (state_r == STATE_FLUSH); + assign flush_out_line = counter_r[`CS_LINE_SEL_BITS-1:0]; + + if (WRITEBACK && `CS_WAY_SEL_BITS > 0) begin + reg [NUM_WAYS-1:0] flush_out_way_r; + always @(*) begin + flush_out_way_r = '0; + flush_out_way_r[counter_r[`CS_LINE_SEL_BITS +: `CS_WAY_SEL_BITS]] = 1; + end + assign flush_out_way = flush_out_way_r; + end else begin + assign flush_out_way = {NUM_WAYS{1'b1}}; + end + +endmodule diff --git a/hw/rtl/cache/VX_cache.sv b/hw/rtl/cache/VX_cache.sv index 298efe2f9..acaa1dac3 100644 --- a/hw/rtl/cache/VX_cache.sv +++ b/hw/rtl/cache/VX_cache.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -14,15 +14,15 @@ `include "VX_cache_define.vh" module VX_cache import VX_gpu_pkg::*; #( - parameter `STRING INSTANCE_ID = "", + parameter `STRING INSTANCE_ID = "", // Number of Word requests per cycle parameter NUM_REQS = 4, // Size of cache in bytes - parameter CACHE_SIZE = 4096, + parameter CACHE_SIZE = 4096, // Size of line inside a bank in bytes - parameter LINE_SIZE = 64, + parameter LINE_SIZE = 64, // Number of banks parameter NUM_BANKS = 1, // Number of associative ways @@ -33,7 +33,7 @@ module VX_cache import VX_gpu_pkg::*; #( // Core Response Queue Size parameter CRSQ_SIZE = 2, // Miss Reserv Queue Knob - parameter MSHR_SIZE = 8, + parameter MSHR_SIZE = 8, // Memory Response Queue Size parameter MRSQ_SIZE = 0, // Memory Request Queue Size @@ -42,6 +42,9 @@ module VX_cache import VX_gpu_pkg::*; #( // Enable cache writeable parameter WRITE_ENABLE = 1, + // Enable cache writeback + parameter WRITEBACK = 0, + // Request debug identifier parameter UUID_WIDTH = 0, @@ -53,12 +56,12 @@ module VX_cache import VX_gpu_pkg::*; #( // Memory request output register parameter MEM_OUT_BUF = 0 - ) ( + ) ( // PERF `ifdef PERF_ENABLE output cache_perf_t cache_perf, `endif - + input wire clk, input wire reset, @@ -67,6 +70,7 @@ module VX_cache import VX_gpu_pkg::*; #( ); `STATIC_ASSERT(NUM_BANKS == (1 << `CLOG2(NUM_BANKS)), ("invalid parameter")) + `STATIC_ASSERT(WRITE_ENABLE || !WRITEBACK, ("invalid parameter")) localparam REQ_SEL_WIDTH = `UP(`CS_REQ_SEL_BITS); localparam WORD_SEL_WIDTH = `UP(`CS_WORD_SEL_BITS); @@ -78,36 +82,46 @@ module VX_cache import VX_gpu_pkg::*; #( localparam BANK_SEL_BITS = `CLOG2(NUM_BANKS); localparam BANK_SEL_WIDTH = `UP(BANK_SEL_BITS); localparam LINE_ADDR_WIDTH = (`CS_WORD_ADDR_WIDTH - BANK_SEL_BITS - WORD_SEL_BITS); - localparam CORE_REQ_DATAW = LINE_ADDR_WIDTH + 1 + WORD_SEL_WIDTH + WORD_SIZE + WORD_WIDTH + TAG_WIDTH; + localparam CORE_REQ_DATAW = LINE_ADDR_WIDTH + 1 + WORD_SEL_WIDTH + WORD_SIZE + WORD_WIDTH + TAG_WIDTH + 1; localparam CORE_RSP_DATAW = WORD_WIDTH + TAG_WIDTH; localparam CORE_REQ_BUF_ENABLE = (NUM_BANKS != 1) || (NUM_REQS != 1); localparam MEM_REQ_BUF_ENABLE = (NUM_BANKS != 1); + localparam REQ_XBAR_BUF = (NUM_REQS > 4) ? 2 : 0; + `ifdef PERF_ENABLE wire [NUM_BANKS-1:0] perf_read_miss_per_bank; wire [NUM_BANKS-1:0] perf_write_miss_per_bank; wire [NUM_BANKS-1:0] perf_mshr_stall_per_bank; `endif - wire [NUM_REQS-1:0] core_req_valid; - wire [NUM_REQS-1:0][`CS_WORD_ADDR_WIDTH-1:0] core_req_addr; - wire [NUM_REQS-1:0] core_req_rw; - wire [NUM_REQS-1:0][WORD_SIZE-1:0] core_req_byteen; - wire [NUM_REQS-1:0][`CS_WORD_WIDTH-1:0] core_req_data; - wire [NUM_REQS-1:0][TAG_WIDTH-1:0] core_req_tag; - wire [NUM_REQS-1:0] core_req_ready; + VX_mem_bus_if #( + .DATA_SIZE (WORD_SIZE), + .TAG_WIDTH (TAG_WIDTH) + ) core_bus2_if[NUM_REQS](); - for (genvar i = 0; i < NUM_REQS; ++i) begin - assign core_req_valid[i] = core_bus_if[i].req_valid; - assign core_req_rw[i] = core_bus_if[i].req_data.rw; - assign core_req_byteen[i] = core_bus_if[i].req_data.byteen; - assign core_req_addr[i] = core_bus_if[i].req_data.addr; - assign core_req_data[i] = core_bus_if[i].req_data.data; - assign core_req_tag[i] = core_bus_if[i].req_data.tag; - assign core_bus_if[i].req_ready = core_req_ready[i]; - `UNUSED_VAR (core_bus_if[i].req_data.atype) - end + wire [NUM_BANKS-1:0] per_bank_flush_valid; + wire [NUM_BANKS-1:0] per_bank_flush_ready; + + wire [NUM_BANKS-1:0] per_bank_core_req_fire; + + // this reset relay is required to sync with bank initialization + `RESET_RELAY (flush_reset, reset); + + VX_cache_flush #( + .NUM_REQS (NUM_REQS), + .NUM_BANKS (NUM_BANKS), + .BANK_SEL_LATENCY (`TO_OUT_BUF_REG(REQ_XBAR_BUF)) // bank xbar latency + ) flush_unit ( + .clk (clk), + .reset (flush_reset), + .core_bus_in_if (core_bus_if), + .core_bus_out_if (core_bus2_if), + .bank_req_fire (per_bank_core_req_fire), + .flush_valid (per_bank_flush_valid), + .flush_ready (per_bank_flush_ready) + ); /////////////////////////////////////////////////////////////////////////// @@ -117,10 +131,10 @@ module VX_cache import VX_gpu_pkg::*; #( wire [NUM_REQS-1:0][TAG_WIDTH-1:0] core_rsp_tag_s; wire [NUM_REQS-1:0] core_rsp_ready_s; - `RESET_RELAY (core_rsp_reset, reset); - for (genvar i = 0; i < NUM_REQS; ++i) begin + `RESET_RELAY (core_rsp_reset, reset); + VX_elastic_buffer #( .DATAW (`CS_WORD_WIDTH + TAG_WIDTH), .SIZE (CORE_REQ_BUF_ENABLE ? `TO_OUT_BUF_SIZE(CORE_OUT_BUF) : 0), @@ -131,9 +145,9 @@ module VX_cache import VX_gpu_pkg::*; #( .valid_in (core_rsp_valid_s[i]), .ready_in (core_rsp_ready_s[i]), .data_in ({core_rsp_data_s[i], core_rsp_tag_s[i]}), - .data_out ({core_bus_if[i].rsp_data.data, core_bus_if[i].rsp_data.tag}), - .valid_out (core_bus_if[i].rsp_valid), - .ready_out (core_bus_if[i].rsp_ready) + .data_out ({core_bus2_if[i].rsp_data.data, core_bus2_if[i].rsp_data.tag}), + .valid_out (core_bus2_if[i].rsp_valid), + .ready_out (core_bus2_if[i].rsp_ready) ); end @@ -146,24 +160,29 @@ module VX_cache import VX_gpu_pkg::*; #( wire [LINE_SIZE-1:0] mem_req_byteen_s; wire [`CS_LINE_WIDTH-1:0] mem_req_data_s; wire [MEM_TAG_WIDTH-1:0] mem_req_tag_s; + wire mem_req_flush_s; wire mem_req_ready_s; + wire mem_bus_if_flush; + + `RESET_RELAY (mem_req_reset, reset); + VX_elastic_buffer #( - .DATAW (1 + LINE_SIZE + `CS_MEM_ADDR_WIDTH + `CS_LINE_WIDTH + MEM_TAG_WIDTH), + .DATAW (1 + LINE_SIZE + `CS_MEM_ADDR_WIDTH + `CS_LINE_WIDTH + MEM_TAG_WIDTH + 1), .SIZE (MEM_REQ_BUF_ENABLE ? `TO_OUT_BUF_SIZE(MEM_OUT_BUF) : 0), .OUT_REG (`TO_OUT_BUF_REG(MEM_OUT_BUF)) ) mem_req_buf ( .clk (clk), - .reset (reset), - .valid_in (mem_req_valid_s), - .ready_in (mem_req_ready_s), - .data_in ({mem_req_rw_s, mem_req_byteen_s, mem_req_addr_s, mem_req_data_s, mem_req_tag_s}), - .data_out ({mem_bus_if.req_data.rw, mem_bus_if.req_data.byteen, mem_bus_if.req_data.addr, mem_bus_if.req_data.data, mem_bus_if.req_data.tag}), - .valid_out (mem_bus_if.req_valid), + .reset (mem_req_reset), + .valid_in (mem_req_valid_s), + .ready_in (mem_req_ready_s), + .data_in ({mem_req_rw_s, mem_req_byteen_s, mem_req_addr_s, mem_req_data_s, mem_req_tag_s, mem_req_flush_s}), + .data_out ({mem_bus_if.req_data.rw, mem_bus_if.req_data.byteen, mem_bus_if.req_data.addr, mem_bus_if.req_data.data, mem_bus_if.req_data.tag, mem_bus_if_flush}), + .valid_out (mem_bus_if.req_valid), .ready_out (mem_bus_if.req_ready) ); - - assign mem_bus_if.req_data.atype = '0; + + assign mem_bus_if.req_data.atype = mem_bus_if_flush ? `ADDR_TYPE_WIDTH'(1 << `ADDR_TYPE_FLUSH) : '0; /////////////////////////////////////////////////////////////////////////// @@ -172,44 +191,26 @@ module VX_cache import VX_gpu_pkg::*; #( wire [`CS_LINE_WIDTH-1:0] mem_rsp_data_s; wire [MEM_TAG_WIDTH-1:0] mem_rsp_tag_s; wire mem_rsp_ready_s; - + + `RESET_RELAY (mem_rsp_reset, reset); + VX_elastic_buffer #( - .DATAW (MEM_TAG_WIDTH + `CS_LINE_WIDTH), + .DATAW (MEM_TAG_WIDTH + `CS_LINE_WIDTH), .SIZE (MRSQ_SIZE), .OUT_REG (MRSQ_SIZE > 2) ) mem_rsp_queue ( .clk (clk), - .reset (reset), + .reset (mem_rsp_reset), .valid_in (mem_bus_if.rsp_valid), .ready_in (mem_bus_if.rsp_ready), - .data_in ({mem_bus_if.rsp_data.tag, mem_bus_if.rsp_data.data}), - .data_out ({mem_rsp_tag_s, mem_rsp_data_s}), + .data_in ({mem_bus_if.rsp_data.tag, mem_bus_if.rsp_data.data}), + .data_out ({mem_rsp_tag_s, mem_rsp_data_s}), .valid_out (mem_rsp_valid_s), .ready_out (mem_rsp_ready_s) ); - /////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// - wire [`CS_LINE_SEL_BITS-1:0] init_line_sel; - wire init_enable; - - // this reset relay is required to sync with bank initialization - `RESET_RELAY (init_reset, reset); - - VX_cache_init #( - .CACHE_SIZE (CACHE_SIZE), - .LINE_SIZE (LINE_SIZE), - .NUM_BANKS (NUM_BANKS), - .NUM_WAYS (NUM_WAYS) - ) cache_init ( - .clk (clk), - .reset (init_reset), - .addr_out (init_line_sel), - .valid_out (init_enable) - ); - - /////////////////////////////////////////////////////////////////////// - wire [NUM_BANKS-1:0] per_bank_core_req_valid; wire [NUM_BANKS-1:0][`CS_LINE_ADDR_WIDTH-1:0] per_bank_core_req_addr; wire [NUM_BANKS-1:0] per_bank_core_req_rw; @@ -218,25 +219,28 @@ module VX_cache import VX_gpu_pkg::*; #( wire [NUM_BANKS-1:0][`CS_WORD_WIDTH-1:0] per_bank_core_req_data; wire [NUM_BANKS-1:0][TAG_WIDTH-1:0] per_bank_core_req_tag; wire [NUM_BANKS-1:0][REQ_SEL_WIDTH-1:0] per_bank_core_req_idx; + wire [NUM_BANKS-1:0] per_bank_core_req_flush; wire [NUM_BANKS-1:0] per_bank_core_req_ready; - + wire [NUM_BANKS-1:0] per_bank_core_rsp_valid; wire [NUM_BANKS-1:0][`CS_WORD_WIDTH-1:0] per_bank_core_rsp_data; wire [NUM_BANKS-1:0][TAG_WIDTH-1:0] per_bank_core_rsp_tag; wire [NUM_BANKS-1:0][REQ_SEL_WIDTH-1:0] per_bank_core_rsp_idx; wire [NUM_BANKS-1:0] per_bank_core_rsp_ready; - wire [NUM_BANKS-1:0] per_bank_mem_req_valid; + wire [NUM_BANKS-1:0] per_bank_mem_req_valid; wire [NUM_BANKS-1:0][`CS_MEM_ADDR_WIDTH-1:0] per_bank_mem_req_addr; wire [NUM_BANKS-1:0] per_bank_mem_req_rw; - wire [NUM_BANKS-1:0][WORD_SEL_WIDTH-1:0] per_bank_mem_req_wsel; - wire [NUM_BANKS-1:0][WORD_SIZE-1:0] per_bank_mem_req_byteen; - wire [NUM_BANKS-1:0][`CS_WORD_WIDTH-1:0] per_bank_mem_req_data; + wire [NUM_BANKS-1:0][LINE_SIZE-1:0] per_bank_mem_req_byteen; + wire [NUM_BANKS-1:0][`CS_LINE_WIDTH-1:0] per_bank_mem_req_data; wire [NUM_BANKS-1:0][MSHR_ADDR_WIDTH-1:0] per_bank_mem_req_id; + wire [NUM_BANKS-1:0] per_bank_mem_req_flush; wire [NUM_BANKS-1:0] per_bank_mem_req_ready; wire [NUM_BANKS-1:0] per_bank_mem_rsp_ready; - + + assign per_bank_core_req_fire = per_bank_core_req_valid & per_bank_mem_req_ready; + if (NUM_BANKS == 1) begin assign mem_rsp_ready_s = per_bank_mem_rsp_ready; end else begin @@ -245,12 +249,33 @@ module VX_cache import VX_gpu_pkg::*; #( // Bank requests dispatch - wire [NUM_REQS-1:0][CORE_REQ_DATAW-1:0] core_req_data_in; - wire [NUM_BANKS-1:0][CORE_REQ_DATAW-1:0] core_req_data_out; + wire [NUM_REQS-1:0] core_req_valid; + wire [NUM_REQS-1:0][`CS_WORD_ADDR_WIDTH-1:0] core_req_addr; + wire [NUM_REQS-1:0] core_req_rw; + wire [NUM_REQS-1:0][WORD_SIZE-1:0] core_req_byteen; + wire [NUM_REQS-1:0][`CS_WORD_WIDTH-1:0] core_req_data; + wire [NUM_REQS-1:0][TAG_WIDTH-1:0] core_req_tag; + wire [NUM_REQS-1:0] core_req_flush; + wire [NUM_REQS-1:0] core_req_ready; + wire [NUM_REQS-1:0][LINE_ADDR_WIDTH-1:0] core_req_line_addr; wire [NUM_REQS-1:0][BANK_SEL_WIDTH-1:0] core_req_bid; wire [NUM_REQS-1:0][WORD_SEL_WIDTH-1:0] core_req_wsel; + wire [NUM_REQS-1:0][CORE_REQ_DATAW-1:0] core_req_data_in; + wire [NUM_BANKS-1:0][CORE_REQ_DATAW-1:0] core_req_data_out; + + for (genvar i = 0; i < NUM_REQS; ++i) begin + assign core_req_valid[i] = core_bus2_if[i].req_valid; + assign core_req_rw[i] = core_bus2_if[i].req_data.rw; + assign core_req_byteen[i] = core_bus2_if[i].req_data.byteen; + assign core_req_addr[i] = core_bus2_if[i].req_data.addr; + assign core_req_data[i] = core_bus2_if[i].req_data.data; + assign core_req_tag[i] = core_bus2_if[i].req_data.tag; + assign core_req_flush[i] = core_bus2_if[i].req_data.atype[`ADDR_TYPE_FLUSH]; + assign core_bus2_if[i].req_ready = core_req_ready[i]; + end + for (genvar i = 0; i < NUM_REQS; ++i) begin if (WORDS_PER_LINE > 1) begin assign core_req_wsel[i] = core_req_addr[i][0 +: WORD_SEL_BITS]; @@ -273,9 +298,11 @@ module VX_cache import VX_gpu_pkg::*; #( core_req_line_addr[i], core_req_rw[i], core_req_wsel[i], - core_req_byteen[i], + core_req_byteen[i], core_req_data[i], - core_req_tag[i]}; + core_req_tag[i], + core_req_flush[i] + }; end `ifdef PERF_ENABLE @@ -284,12 +311,12 @@ module VX_cache import VX_gpu_pkg::*; #( `RESET_RELAY (req_xbar_reset, reset); - VX_stream_xbar #( + VX_stream_xbar #( .NUM_INPUTS (NUM_REQS), .NUM_OUTPUTS (NUM_BANKS), .DATAW (CORE_REQ_DATAW), .PERF_CTR_BITS (`PERF_CTR_BITS), - .OUT_BUF ((NUM_REQS > 4) ? 2 : 0) + .OUT_BUF (REQ_XBAR_BUF) ) req_xbar ( .clk (clk), .reset (req_xbar_reset), @@ -313,27 +340,29 @@ module VX_cache import VX_gpu_pkg::*; #( per_bank_core_req_addr[i], per_bank_core_req_rw[i], per_bank_core_req_wsel[i], - per_bank_core_req_byteen[i], + per_bank_core_req_byteen[i], per_bank_core_req_data[i], - per_bank_core_req_tag[i]} = core_req_data_out[i]; + per_bank_core_req_tag[i], + per_bank_core_req_flush[i] + } = core_req_data_out[i]; end - + // Banks access - for (genvar i = 0; i < NUM_BANKS; ++i) begin + for (genvar bank_id = 0; bank_id < NUM_BANKS; ++bank_id) begin : banks wire [`CS_LINE_ADDR_WIDTH-1:0] curr_bank_mem_req_addr; wire curr_bank_mem_rsp_valid; if (NUM_BANKS == 1) begin assign curr_bank_mem_rsp_valid = mem_rsp_valid_s; end else begin - assign curr_bank_mem_rsp_valid = mem_rsp_valid_s && (`CS_MEM_TAG_TO_BANK_ID(mem_rsp_tag_s) == i); + assign curr_bank_mem_rsp_valid = mem_rsp_valid_s && (`CS_MEM_TAG_TO_BANK_ID(mem_rsp_tag_s) == bank_id); end `RESET_RELAY (bank_reset, reset); - - VX_cache_bank #( - .BANK_ID (i), - .INSTANCE_ID (INSTANCE_ID), + + VX_cache_bank #( + .BANK_ID (bank_id), + .INSTANCE_ID ($sformatf("%s-bank%0d", INSTANCE_ID, bank_id)), .CACHE_SIZE (CACHE_SIZE), .LINE_SIZE (LINE_SIZE), .NUM_BANKS (NUM_BANKS), @@ -344,65 +373,66 @@ module VX_cache import VX_gpu_pkg::*; #( .MSHR_SIZE (MSHR_SIZE), .MREQ_SIZE (MREQ_SIZE), .WRITE_ENABLE (WRITE_ENABLE), + .WRITEBACK (WRITEBACK), .UUID_WIDTH (UUID_WIDTH), .TAG_WIDTH (TAG_WIDTH), .CORE_OUT_BUF (CORE_REQ_BUF_ENABLE ? 0 : CORE_OUT_BUF), .MEM_OUT_BUF (MEM_REQ_BUF_ENABLE ? 0 : MEM_OUT_BUF) - ) bank ( + ) bank ( .clk (clk), .reset (bank_reset), `ifdef PERF_ENABLE - .perf_read_misses (perf_read_miss_per_bank[i]), - .perf_write_misses (perf_write_miss_per_bank[i]), - .perf_mshr_stalls (perf_mshr_stall_per_bank[i]), + .perf_read_misses (perf_read_miss_per_bank[bank_id]), + .perf_write_misses (perf_write_miss_per_bank[bank_id]), + .perf_mshr_stalls (perf_mshr_stall_per_bank[bank_id]), `endif - - // Core request - .core_req_valid (per_bank_core_req_valid[i]), - .core_req_addr (per_bank_core_req_addr[i]), - .core_req_rw (per_bank_core_req_rw[i]), - .core_req_wsel (per_bank_core_req_wsel[i]), - .core_req_byteen (per_bank_core_req_byteen[i]), - .core_req_data (per_bank_core_req_data[i]), - .core_req_tag (per_bank_core_req_tag[i]), - .core_req_idx (per_bank_core_req_idx[i]), - .core_req_ready (per_bank_core_req_ready[i]), - // Core response - .core_rsp_valid (per_bank_core_rsp_valid[i]), - .core_rsp_data (per_bank_core_rsp_data[i]), - .core_rsp_tag (per_bank_core_rsp_tag[i]), - .core_rsp_idx (per_bank_core_rsp_idx[i]), - .core_rsp_ready (per_bank_core_rsp_ready[i]), + // Core request + .core_req_valid (per_bank_core_req_valid[bank_id]), + .core_req_addr (per_bank_core_req_addr[bank_id]), + .core_req_rw (per_bank_core_req_rw[bank_id]), + .core_req_wsel (per_bank_core_req_wsel[bank_id]), + .core_req_byteen (per_bank_core_req_byteen[bank_id]), + .core_req_data (per_bank_core_req_data[bank_id]), + .core_req_tag (per_bank_core_req_tag[bank_id]), + .core_req_idx (per_bank_core_req_idx[bank_id]), + .core_req_flush (per_bank_core_req_flush[bank_id]), + .core_req_ready (per_bank_core_req_ready[bank_id]), + + // Core response + .core_rsp_valid (per_bank_core_rsp_valid[bank_id]), + .core_rsp_data (per_bank_core_rsp_data[bank_id]), + .core_rsp_tag (per_bank_core_rsp_tag[bank_id]), + .core_rsp_idx (per_bank_core_rsp_idx[bank_id]), + .core_rsp_ready (per_bank_core_rsp_ready[bank_id]), // Memory request - .mem_req_valid (per_bank_mem_req_valid[i]), + .mem_req_valid (per_bank_mem_req_valid[bank_id]), .mem_req_addr (curr_bank_mem_req_addr), - .mem_req_rw (per_bank_mem_req_rw[i]), - .mem_req_wsel (per_bank_mem_req_wsel[i]), - .mem_req_byteen (per_bank_mem_req_byteen[i]), - .mem_req_data (per_bank_mem_req_data[i]), - .mem_req_id (per_bank_mem_req_id[i]), - .mem_req_ready (per_bank_mem_req_ready[i]), + .mem_req_rw (per_bank_mem_req_rw[bank_id]), + .mem_req_byteen (per_bank_mem_req_byteen[bank_id]), + .mem_req_data (per_bank_mem_req_data[bank_id]), + .mem_req_id (per_bank_mem_req_id[bank_id]), + .mem_req_flush (per_bank_mem_req_flush[bank_id]), + .mem_req_ready (per_bank_mem_req_ready[bank_id]), // Memory response .mem_rsp_valid (curr_bank_mem_rsp_valid), .mem_rsp_data (mem_rsp_data_s), .mem_rsp_id (`CS_MEM_TAG_TO_REQ_ID(mem_rsp_tag_s)), - .mem_rsp_ready (per_bank_mem_rsp_ready[i]), + .mem_rsp_ready (per_bank_mem_rsp_ready[bank_id]), - // initialization - .init_enable (init_enable), - .init_line_sel (init_line_sel) + .flush_valid (per_bank_flush_valid[bank_id]), + .flush_ready (per_bank_flush_ready[bank_id]) ); if (NUM_BANKS == 1) begin - assign per_bank_mem_req_addr[i] = curr_bank_mem_req_addr; + assign per_bank_mem_req_addr[bank_id] = curr_bank_mem_req_addr; end else begin - assign per_bank_mem_req_addr[i] = `CS_LINE_TO_MEM_ADDR(curr_bank_mem_req_addr, i); + assign per_bank_mem_req_addr[bank_id] = `CS_LINE_TO_MEM_ADDR(curr_bank_mem_req_addr, bank_id); end - end + end // Bank responses gather @@ -442,37 +472,41 @@ module VX_cache import VX_gpu_pkg::*; #( wire mem_req_valid_p; wire [`CS_MEM_ADDR_WIDTH-1:0] mem_req_addr_p; wire mem_req_rw_p; - wire [WORD_SEL_WIDTH-1:0] mem_req_wsel_p; - wire [WORD_SIZE-1:0] mem_req_byteen_p; - wire [`CS_WORD_WIDTH-1:0] mem_req_data_p; + wire [LINE_SIZE-1:0] mem_req_byteen_p; + wire [`CS_LINE_WIDTH-1:0] mem_req_data_p; wire [MEM_TAG_WIDTH-1:0] mem_req_tag_p; wire [MSHR_ADDR_WIDTH-1:0] mem_req_id_p; + wire mem_req_flush_p; wire mem_req_ready_p; // Memory request arbitration - wire [NUM_BANKS-1:0][(`CS_MEM_ADDR_WIDTH + MSHR_ADDR_WIDTH + 1 + WORD_SIZE + WORD_SEL_WIDTH + `CS_WORD_WIDTH)-1:0] data_in; + wire [NUM_BANKS-1:0][(`CS_MEM_ADDR_WIDTH + MSHR_ADDR_WIDTH + 1 + LINE_SIZE + `CS_LINE_WIDTH + 1)-1:0] data_in; for (genvar i = 0; i < NUM_BANKS; ++i) begin - assign data_in[i] = {per_bank_mem_req_addr[i], - per_bank_mem_req_rw[i], - per_bank_mem_req_wsel[i], - per_bank_mem_req_byteen[i], - per_bank_mem_req_data[i], - per_bank_mem_req_id[i]}; + assign data_in[i] = { + per_bank_mem_req_addr[i], + per_bank_mem_req_rw[i], + per_bank_mem_req_byteen[i], + per_bank_mem_req_data[i], + per_bank_mem_req_id[i], + per_bank_mem_req_flush[i] + }; end + `RESET_RELAY (mem_arb_reset, reset); + VX_stream_arb #( .NUM_INPUTS (NUM_BANKS), - .DATAW (`CS_MEM_ADDR_WIDTH + 1 + WORD_SEL_WIDTH + WORD_SIZE + `CS_WORD_WIDTH + MSHR_ADDR_WIDTH), - .ARBITER ("R") + .DATAW (`CS_MEM_ADDR_WIDTH + 1 + LINE_SIZE + `CS_LINE_WIDTH + MSHR_ADDR_WIDTH + 1), + .ARBITER ("F") ) mem_req_arb ( .clk (clk), - .reset (reset), + .reset (mem_arb_reset), .valid_in (per_bank_mem_req_valid), .ready_in (per_bank_mem_req_ready), .data_in (data_in), - .data_out ({mem_req_addr_p, mem_req_rw_p, mem_req_wsel_p, mem_req_byteen_p, mem_req_data_p, mem_req_id_p}), + .data_out ({mem_req_addr_p, mem_req_rw_p, mem_req_byteen_p, mem_req_data_p, mem_req_id_p, mem_req_flush_p}), .valid_out (mem_req_valid_p), .ready_out (mem_req_ready_p), `UNUSED_PIN (sel_out) @@ -480,44 +514,28 @@ module VX_cache import VX_gpu_pkg::*; #( if (NUM_BANKS > 1) begin wire [`CS_BANK_SEL_BITS-1:0] mem_req_bank_id = `CS_MEM_ADDR_TO_BANK_ID(mem_req_addr_p); - assign mem_req_tag_p = MEM_TAG_WIDTH'({mem_req_bank_id, mem_req_id_p}); + assign mem_req_tag_p = MEM_TAG_WIDTH'({mem_req_bank_id, mem_req_id_p}); end else begin assign mem_req_tag_p = MEM_TAG_WIDTH'(mem_req_id_p); - end + end // Memory request multi-port handling assign mem_req_valid_s = mem_req_valid_p; assign mem_req_addr_s = mem_req_addr_p; assign mem_req_tag_s = mem_req_tag_p; + assign mem_req_flush_s = mem_req_flush_p; assign mem_req_ready_p = mem_req_ready_s; if (WRITE_ENABLE != 0) begin - if (`CS_WORDS_PER_LINE > 1) begin - reg [LINE_SIZE-1:0] mem_req_byteen_r; - reg [`CS_LINE_WIDTH-1:0] mem_req_data_r; - - always @(*) begin - mem_req_byteen_r = '0; - mem_req_data_r = 'x; - mem_req_byteen_r[mem_req_wsel_p * WORD_SIZE +: WORD_SIZE] = mem_req_byteen_p; - mem_req_data_r[mem_req_wsel_p * `CS_WORD_WIDTH +: `CS_WORD_WIDTH] = mem_req_data_p; - end - assign mem_req_rw_s = mem_req_rw_p; - assign mem_req_byteen_s = mem_req_byteen_r; - assign mem_req_data_s = mem_req_data_r; - end else begin - `UNUSED_VAR (mem_req_wsel_p) - assign mem_req_rw_s = mem_req_rw_p; - assign mem_req_byteen_s = mem_req_byteen_p; - assign mem_req_data_s = mem_req_data_p; - end + assign mem_req_rw_s = mem_req_rw_p; + assign mem_req_byteen_s = mem_req_byteen_p; + assign mem_req_data_s = mem_req_data_p; end else begin `UNUSED_VAR (mem_req_byteen_p) - `UNUSED_VAR (mem_req_wsel_p) `UNUSED_VAR (mem_req_data_p) `UNUSED_VAR (mem_req_rw_p) - + assign mem_req_rw_s = 0; assign mem_req_byteen_s = {LINE_SIZE{1'b1}}; assign mem_req_data_s = '0; @@ -527,10 +545,10 @@ module VX_cache import VX_gpu_pkg::*; #( // per cycle: core_reads, core_writes wire [`CLOG2(NUM_REQS+1)-1:0] perf_core_reads_per_cycle; wire [`CLOG2(NUM_REQS+1)-1:0] perf_core_writes_per_cycle; - + wire [NUM_REQS-1:0] perf_core_reads_per_req; wire [NUM_REQS-1:0] perf_core_writes_per_req; - + // per cycle: read misses, write misses, msrq stalls, pipeline stalls wire [`CLOG2(NUM_BANKS+1)-1:0] perf_read_miss_per_cycle; wire [`CLOG2(NUM_BANKS+1)-1:0] perf_write_miss_per_cycle; @@ -539,16 +557,16 @@ module VX_cache import VX_gpu_pkg::*; #( `BUFFER(perf_core_reads_per_req, core_req_valid & core_req_ready & ~core_req_rw); `BUFFER(perf_core_writes_per_req, core_req_valid & core_req_ready & core_req_rw); - + `POP_COUNT(perf_core_reads_per_cycle, perf_core_reads_per_req); `POP_COUNT(perf_core_writes_per_cycle, perf_core_writes_per_req); `POP_COUNT(perf_read_miss_per_cycle, perf_read_miss_per_bank); `POP_COUNT(perf_write_miss_per_cycle, perf_write_miss_per_bank); `POP_COUNT(perf_mshr_stall_per_cycle, perf_mshr_stall_per_bank); - + wire [NUM_REQS-1:0] perf_crsp_stall_per_req; for (genvar i = 0; i < NUM_REQS; ++i) begin - assign perf_crsp_stall_per_req[i] = core_bus_if[i].rsp_valid && ~core_bus_if[i].rsp_ready; + assign perf_crsp_stall_per_req[i] = core_bus2_if[i].rsp_valid && ~core_bus2_if[i].rsp_ready; end `POP_COUNT(perf_crsp_stall_per_cycle, perf_crsp_stall_per_req); @@ -561,7 +579,7 @@ module VX_cache import VX_gpu_pkg::*; #( reg [`PERF_CTR_BITS-1:0] perf_write_misses; reg [`PERF_CTR_BITS-1:0] perf_mshr_stalls; reg [`PERF_CTR_BITS-1:0] perf_mem_stalls; - reg [`PERF_CTR_BITS-1:0] perf_crsp_stalls; + reg [`PERF_CTR_BITS-1:0] perf_crsp_stalls; always @(posedge clk) begin if (reset) begin diff --git a/hw/rtl/cache/VX_cache_bank.sv b/hw/rtl/cache/VX_cache_bank.sv index 0db783066..03f3efd41 100644 --- a/hw/rtl/cache/VX_cache_bank.sv +++ b/hw/rtl/cache/VX_cache_bank.sv @@ -41,6 +41,9 @@ module VX_cache_bank #( // Enable cache writeable parameter WRITE_ENABLE = 1, + // Enable cache writeback + parameter WRITEBACK = 0, + // Request debug identifier parameter UUID_WIDTH = 0, @@ -69,12 +72,13 @@ module VX_cache_bank #( // Core Request input wire core_req_valid, input wire [`CS_LINE_ADDR_WIDTH-1:0] core_req_addr, - input wire core_req_rw, - input wire [WORD_SEL_WIDTH-1:0] core_req_wsel, - input wire [WORD_SIZE-1:0] core_req_byteen, - input wire [`CS_WORD_WIDTH-1:0] core_req_data, - input wire [TAG_WIDTH-1:0] core_req_tag, - input wire [REQ_SEL_WIDTH-1:0] core_req_idx, + input wire core_req_rw, // write enable + input wire [WORD_SEL_WIDTH-1:0] core_req_wsel, // select the word in a cacheline, e.g. word size = 4 bytes, cacheline size = 64 bytes, it should have log(64/4)= 4 bits + input wire [WORD_SIZE-1:0] core_req_byteen,// which bytes in data to write + input wire [`CS_WORD_WIDTH-1:0] core_req_data, // data to be written + input wire [TAG_WIDTH-1:0] core_req_tag, // identifier of the request (request id) + input wire [REQ_SEL_WIDTH-1:0] core_req_idx, // index of the request in the core request array + input wire core_req_flush, // flush enable output wire core_req_ready, // Core Response @@ -88,10 +92,10 @@ module VX_cache_bank #( output wire mem_req_valid, output wire [`CS_LINE_ADDR_WIDTH-1:0] mem_req_addr, output wire mem_req_rw, - output wire [WORD_SEL_WIDTH-1:0] mem_req_wsel, - output wire [WORD_SIZE-1:0] mem_req_byteen, - output wire [`CS_WORD_WIDTH-1:0] mem_req_data, - output wire [MSHR_ADDR_WIDTH-1:0] mem_req_id, + output wire [LINE_SIZE-1:0] mem_req_byteen, + output wire [`CS_LINE_WIDTH-1:0] mem_req_data, + output wire [MSHR_ADDR_WIDTH-1:0] mem_req_id, // index of the head entry in the mshr + output wire mem_req_flush, input wire mem_req_ready, // Memory response @@ -100,9 +104,9 @@ module VX_cache_bank #( input wire [MSHR_ADDR_WIDTH-1:0] mem_rsp_id, output wire mem_rsp_ready, - // initialization - input wire init_enable, - input wire [`CS_LINE_SEL_BITS-1:0] init_line_sel + // flush + input wire flush_valid, + output wire flush_ready ); localparam PIPELINE_STAGES = 2; @@ -128,23 +132,56 @@ module VX_cache_bank #( wire [MSHR_ADDR_WIDTH-1:0] replay_id; wire replay_ready; + wire is_init_st0; + wire is_flush_st0, is_flush_st1; + wire [NUM_WAYS-1:0] flush_way_st0; + wire [`CS_LINE_ADDR_WIDTH-1:0] addr_sel, addr_st0, addr_st1; - wire rw_st0, rw_st1; - wire [WORD_SEL_WIDTH-1:0] wsel_st0, wsel_st1; - wire [WORD_SIZE-1:0] byteen_st0, byteen_st1; - wire [REQ_SEL_WIDTH-1:0] req_idx_st0, req_idx_st1; - wire [TAG_WIDTH-1:0] tag_st0, tag_st1; + wire rw_sel, rw_st0, rw_st1; + wire [WORD_SEL_WIDTH-1:0] wsel_sel, wsel_st0, wsel_st1; + wire [WORD_SIZE-1:0] byteen_sel, byteen_st0, byteen_st1; + wire [REQ_SEL_WIDTH-1:0] req_idx_sel, req_idx_st0, req_idx_st1; + wire [TAG_WIDTH-1:0] tag_sel, tag_st0, tag_st1; wire [`CS_WORD_WIDTH-1:0] read_data_st1; wire [`CS_LINE_WIDTH-1:0] data_sel, data_st0, data_st1; wire [MSHR_ADDR_WIDTH-1:0] replay_id_st0, mshr_id_st0, mshr_id_st1; wire valid_sel, valid_st0, valid_st1; - wire is_init_st0; wire is_creq_st0, is_creq_st1; wire is_fill_st0, is_fill_st1; wire is_replay_st0, is_replay_st1; + wire creq_flush_st0, creq_flush_st1; + wire [NUM_WAYS-1:0] way_sel_st0, way_sel_st1; + wire [NUM_WAYS-1:0] tag_matches_st0; wire [MSHR_ADDR_WIDTH-1:0] mshr_alloc_id_st0; wire [MSHR_ADDR_WIDTH-1:0] mshr_prev_st0, mshr_prev_st1; wire mshr_pending_st0, mshr_pending_st1; + wire mshr_empty; + + wire line_flush_valid; + wire line_flush_init; + wire [`CS_LINE_SEL_BITS-1:0] line_flush_sel; + wire [NUM_WAYS-1:0] line_flush_way; + wire line_flush_ready; + + // flush unit + VX_bank_flush #( + .CACHE_SIZE (CACHE_SIZE), + .LINE_SIZE (LINE_SIZE), + .NUM_BANKS (NUM_BANKS), + .NUM_WAYS (NUM_WAYS), + .WRITEBACK (WRITEBACK) + ) flush_unit ( + .clk (clk), + .reset (reset), + .flush_in_valid (flush_valid), + .flush_in_ready (flush_ready), + .flush_out_init (line_flush_init), + .flush_out_valid (line_flush_valid), + .flush_out_line (line_flush_sel), + .flush_out_way (line_flush_way), + .flush_out_ready (line_flush_ready), + .mshr_empty (mshr_empty) + ); wire rdw_hazard_st0; reg rdw_hazard_st1; @@ -154,76 +191,77 @@ module VX_cache_bank #( // inputs arbitration: // mshr replay has highest priority to maximize utilization since there is no miss. // handle memory responses next to prevent deadlock with potential memory request from a miss. - wire replay_grant = ~init_enable; + // flush has precedence over core requests to ensure that the cache is in a consistent state. + wire replay_grant = ~line_flush_init; wire replay_enable = replay_grant && replay_valid; - wire fill_grant = ~init_enable && ~replay_enable; + wire fill_grant = ~line_flush_init && ~replay_enable; wire fill_enable = fill_grant && mem_rsp_valid; - wire creq_grant = ~init_enable && ~replay_enable && ~fill_enable; + wire flush_grant = ~line_flush_init && ~replay_enable && ~fill_enable; + wire flush_enable = flush_grant && line_flush_valid; + + wire creq_grant = ~line_flush_init && ~replay_enable && ~fill_enable && ~flush_enable; wire creq_enable = creq_grant && core_req_valid; assign replay_ready = replay_grant - && ~rdw_hazard_st0 - && ~pipe_stall; + && ~rdw_hazard_st0 + && ~pipe_stall; assign mem_rsp_ready = fill_grant && ~pipe_stall; - assign core_req_ready = creq_grant - && ~mreq_queue_alm_full - && ~mshr_alm_full - && ~pipe_stall; + assign line_flush_ready = flush_grant + && ~mreq_queue_alm_full + && ~pipe_stall; - wire init_fire = init_enable; + assign core_req_ready = creq_grant + && ~mreq_queue_alm_full + && ~mshr_alm_full + && ~pipe_stall; + + wire init_fire = line_flush_init; wire replay_fire = replay_valid && replay_ready; wire mem_rsp_fire = mem_rsp_valid && mem_rsp_ready; + wire flush_fire = line_flush_valid && line_flush_ready; wire core_req_fire = core_req_valid && core_req_ready; - wire [TAG_WIDTH-1:0] mshr_creq_tag = replay_enable ? replay_tag : core_req_tag; + assign valid_sel = init_fire || replay_fire || mem_rsp_fire || flush_fire || core_req_fire; + assign rw_sel = replay_valid ? replay_rw : core_req_rw; + assign byteen_sel = replay_valid ? replay_byteen : core_req_byteen; + assign wsel_sel = replay_valid ? replay_wsel : core_req_wsel; + assign req_idx_sel = replay_valid ? replay_idx : core_req_idx; + assign tag_sel = replay_valid ? replay_tag : core_req_tag; + + assign addr_sel = (line_flush_init | line_flush_valid) ? `CS_LINE_ADDR_WIDTH'(line_flush_sel) : + (replay_valid ? replay_addr : (mem_rsp_valid ? mem_rsp_addr : core_req_addr)); + + if (WRITE_ENABLE) begin + assign data_sel[`CS_WORD_WIDTH-1:0] = replay_valid ? replay_data : (mem_rsp_valid ? mem_rsp_data[`CS_WORD_WIDTH-1:0] : core_req_data); + end else begin + assign data_sel[`CS_WORD_WIDTH-1:0] = mem_rsp_data[`CS_WORD_WIDTH-1:0]; + `UNUSED_VAR (core_req_data) + `UNUSED_VAR (replay_data) + end + for (genvar i = `CS_WORD_WIDTH; i < `CS_LINE_WIDTH; ++i) begin + assign data_sel[i] = mem_rsp_data[i]; // only the memory response fills the upper words of data_sel + end if (UUID_WIDTH != 0) begin - assign req_uuid_sel = mshr_creq_tag[TAG_WIDTH-1 -: UUID_WIDTH]; + assign req_uuid_sel = tag_sel[TAG_WIDTH-1 -: UUID_WIDTH]; end else begin assign req_uuid_sel = 0; end - `UNUSED_VAR (mshr_creq_tag) - - assign valid_sel = init_fire || replay_fire || mem_rsp_fire || core_req_fire; - - assign addr_sel = init_enable ? `CS_LINE_ADDR_WIDTH'(init_line_sel) : - (replay_valid ? replay_addr : - (mem_rsp_valid ? mem_rsp_addr : core_req_addr)); - - assign data_sel[`CS_WORD_WIDTH-1:0] = (mem_rsp_valid || !WRITE_ENABLE) ? mem_rsp_data[`CS_WORD_WIDTH-1:0] : (replay_valid ? replay_data : core_req_data); - for (genvar i = `CS_WORD_WIDTH; i < `CS_LINE_WIDTH; ++i) begin - assign data_sel[i] = mem_rsp_data[i]; - end - VX_pipe_register #( - .DATAW (1 + 1 + 1 + 1 + 1 + `CS_LINE_ADDR_WIDTH + `CS_LINE_WIDTH + 1 + WORD_SIZE + WORD_SEL_WIDTH + REQ_SEL_WIDTH + TAG_WIDTH + MSHR_ADDR_WIDTH), + .DATAW (1 + 1 + 1 + 1 + 1 + 1 + 1 + NUM_WAYS + `CS_LINE_ADDR_WIDTH + `CS_LINE_WIDTH + 1 + WORD_SIZE + WORD_SEL_WIDTH + REQ_SEL_WIDTH + TAG_WIDTH + MSHR_ADDR_WIDTH), .RESETW (1) ) pipe_reg0 ( .clk (clk), .reset (reset), .enable (~pipe_stall), - .data_in ({ - valid_sel, - init_enable, - replay_enable, - fill_enable, - creq_enable, - addr_sel, - data_sel, - replay_valid ? replay_rw : core_req_rw, - replay_valid ? replay_byteen : core_req_byteen, - replay_valid ? replay_wsel : core_req_wsel, - replay_valid ? replay_idx : core_req_idx, - replay_valid ? replay_tag : core_req_tag, - replay_id - }), - .data_out ({valid_st0, is_init_st0, is_replay_st0, is_fill_st0, is_creq_st0, addr_st0, data_st0, rw_st0, byteen_st0, wsel_st0, req_idx_st0, tag_st0, replay_id_st0}) + .data_in ({valid_sel, line_flush_init, replay_enable, fill_enable, flush_enable, creq_enable, core_req_flush, line_flush_way, addr_sel, data_sel, rw_sel, byteen_sel, wsel_sel, req_idx_sel, tag_sel, replay_id}), + .data_out ({valid_st0, is_init_st0, is_replay_st0, is_fill_st0, is_flush_st0, is_creq_st0, creq_flush_st0, flush_way_st0, addr_st0, data_st0, rw_st0, byteen_st0, wsel_st0, req_idx_st0, tag_st0, replay_id_st0}) ); if (UUID_WIDTH != 0) begin @@ -232,20 +270,24 @@ module VX_cache_bank #( assign req_uuid_st0 = 0; end - wire do_creq_rd_st0 = valid_st0 && is_creq_st0 && ~rw_st0; - wire do_fill_st0 = valid_st0 && is_fill_st0; wire do_init_st0 = valid_st0 && is_init_st0; + wire do_flush_st0 = valid_st0 && is_flush_st0; + wire do_creq_rd_st0 = valid_st0 && is_creq_st0 && ~rw_st0; + wire do_replay_rd_st0 = valid_st0 && is_replay_st0 && ~rw_st0; + wire do_fill_st0 = valid_st0 && is_fill_st0; wire do_lookup_st0 = valid_st0 && ~(is_fill_st0 || is_init_st0); + wire do_cache_rd_st0 = do_creq_rd_st0 || do_replay_rd_st0; + wire [`CS_WORD_WIDTH-1:0] write_data_st0 = data_st0[`CS_WORD_WIDTH-1:0]; - wire [NUM_WAYS-1:0] tag_matches_st0, tag_matches_st1; - wire [NUM_WAYS-1:0] way_sel_st0, way_sel_st1; + wire [NUM_WAYS-1:0] repl_way_st0; + wire [`CS_TAG_SEL_BITS-1:0] repl_tag_st0; `RESET_RELAY (tag_reset, reset); VX_cache_tags #( - .INSTANCE_ID(INSTANCE_ID), + .INSTANCE_ID($sformatf("%s-tags", INSTANCE_ID)), .BANK_ID (BANK_ID), .CACHE_SIZE (CACHE_SIZE), .LINE_SIZE (LINE_SIZE), @@ -261,30 +303,37 @@ module VX_cache_bank #( .stall (pipe_stall), - // read/Fill + // init/fill/lookup/flush + .init (do_init_st0 || do_flush_st0), + .fill (do_fill_st0), .lookup (do_lookup_st0), .line_addr (addr_st0), - .fill (do_fill_st0), - .init (do_init_st0), - .way_sel (way_sel_st0), - .tag_matches(tag_matches_st0) + .tag_matches(tag_matches_st0), + + // replacement + .repl_way (repl_way_st0), + .repl_tag (repl_tag_st0) ); assign mshr_id_st0 = is_creq_st0 ? mshr_alloc_id_st0 : replay_id_st0; + assign way_sel_st0 = is_fill_st0 ? repl_way_st0 : (is_flush_st0 ? flush_way_st0 : tag_matches_st0); + + wire [`CS_LINE_ADDR_WIDTH-1:0] addr_r_st0 = (is_fill_st0 || is_flush_st0) ? {repl_tag_st0, addr_st0[`CS_LINE_SEL_BITS-1:0]} : addr_st0; + VX_pipe_register #( - .DATAW (1 + 1 + 1 + 1 + 1 + `CS_LINE_ADDR_WIDTH + `CS_LINE_WIDTH + WORD_SIZE + WORD_SEL_WIDTH + REQ_SEL_WIDTH + TAG_WIDTH + MSHR_ADDR_WIDTH + MSHR_ADDR_WIDTH + NUM_WAYS + NUM_WAYS + 1), + .DATAW (1 + 1 + 1 + 1 + 1 + 1 + 1 + `CS_LINE_ADDR_WIDTH + `CS_LINE_WIDTH + WORD_SIZE + WORD_SEL_WIDTH + REQ_SEL_WIDTH + TAG_WIDTH + MSHR_ADDR_WIDTH + MSHR_ADDR_WIDTH + NUM_WAYS + 1), .RESETW (1) ) pipe_reg1 ( .clk (clk), .reset (reset), .enable (~pipe_stall), - .data_in ({valid_st0, is_replay_st0, is_fill_st0, is_creq_st0, rw_st0, addr_st0, data_st0, byteen_st0, wsel_st0, req_idx_st0, tag_st0, mshr_id_st0, mshr_prev_st0, tag_matches_st0, way_sel_st0, mshr_pending_st0}), - .data_out ({valid_st1, is_replay_st1, is_fill_st1, is_creq_st1, rw_st1, addr_st1, data_st1, byteen_st1, wsel_st1, req_idx_st1, tag_st1, mshr_id_st1, mshr_prev_st1, tag_matches_st1, way_sel_st1, mshr_pending_st1}) + .data_in ({valid_st0, is_flush_st0, is_replay_st0, is_fill_st0, is_creq_st0, creq_flush_st0, rw_st0, addr_r_st0, data_st0, byteen_st0, wsel_st0, req_idx_st0, tag_st0, mshr_id_st0, mshr_prev_st0, way_sel_st0, mshr_pending_st0}), + .data_out ({valid_st1, is_flush_st1, is_replay_st1, is_fill_st1, is_creq_st1, creq_flush_st1, rw_st1, addr_st1, data_st1, byteen_st1, wsel_st1, req_idx_st1, tag_st1, mshr_id_st1, mshr_prev_st1, way_sel_st1, mshr_pending_st1}) ); // we have a tag hit - wire is_hit_st1 = (| tag_matches_st1); + wire is_hit_st1 = (| way_sel_st1); if (UUID_WIDTH != 0) begin assign req_uuid_st1 = tag_st1[TAG_WIDTH-1 -: UUID_WIDTH]; @@ -292,37 +341,62 @@ module VX_cache_bank #( assign req_uuid_st1 = 0; end - wire do_creq_rd_st1 = valid_st1 && is_creq_st1 && ~rw_st1; - wire do_creq_wr_st1 = valid_st1 && is_creq_st1 && rw_st1; + wire is_read_st1 = is_creq_st1 && ~rw_st1; + wire is_write_st1 = is_creq_st1 && rw_st1; + wire do_creq_rd_st1 = valid_st1 && is_read_st1; + wire do_creq_wr_st1 = valid_st1 && is_write_st1; wire do_fill_st1 = valid_st1 && is_fill_st1; wire do_replay_rd_st1 = valid_st1 && is_replay_st1 && ~rw_st1; wire do_replay_wr_st1 = valid_st1 && is_replay_st1 && rw_st1; + wire do_cache_rd_st1 = do_read_hit_st1 || do_replay_rd_st1; + wire do_cache_wr_st1 = do_write_hit_st1 || do_replay_wr_st1; + wire do_read_hit_st1 = do_creq_rd_st1 && is_hit_st1; wire do_read_miss_st1 = do_creq_rd_st1 && ~is_hit_st1; wire do_write_hit_st1 = do_creq_wr_st1 && is_hit_st1; wire do_write_miss_st1= do_creq_wr_st1 && ~is_hit_st1; + wire do_flush_st1 = valid_st1 && is_flush_st1; + `UNUSED_VAR (do_write_miss_st1) // ensure mshr replay always get a hit `RUNTIME_ASSERT (~(valid_st1 && is_replay_st1) || is_hit_st1, ("runtime error: invalid mshr replay")); // detect BRAM's read-during-write hazard - assign rdw_hazard_st0 = do_fill_st0; // after a fill - always @(posedge clk) begin - rdw_hazard_st1 <= (do_creq_rd_st0 && do_write_hit_st1 && (addr_st0 == addr_st1)) - && ~rdw_hazard_st1; // after a write to same address + assign rdw_hazard_st0 = do_fill_st0; // stall cycle after a fill + wire rdw_case1 = do_cache_rd_st0 && do_cache_wr_st1 && (addr_st0 == addr_st1); // standard cache access + wire rdw_case2 = WRITEBACK && (do_flush_st0 || do_fill_st0) && do_cache_wr_st1; // a writeback can evict preceeding write + always @(posedge clk) begin // after a write to same address + rdw_hazard_st1 <= (rdw_case1 || rdw_case2) + && ~rdw_hazard_st1; // invalidate if pipeline stalled to avoid repeats end - wire [`CS_WORD_WIDTH-1:0] write_data_st1 = data_st1[`CS_WORD_WIDTH-1:0]; + wire [`CS_LINE_WIDTH-1:0] write_data_st1 = {`CS_WORDS_PER_LINE{data_st1[`CS_WORD_WIDTH-1:0]}}; wire [`CS_LINE_WIDTH-1:0] fill_data_st1 = data_st1; + wire [LINE_SIZE-1:0] write_byteen_st1; + + wire [`CS_LINE_WIDTH-1:0] dirty_data_st1; + wire [LINE_SIZE-1:0] dirty_byteen_st1; + wire dirty_valid_st1; + + if (`CS_WORDS_PER_LINE > 1) begin + reg [LINE_SIZE-1:0] write_byteen_r; + always @(*) begin + write_byteen_r = '0; + write_byteen_r[wsel_st1 * WORD_SIZE +: WORD_SIZE] = byteen_st1; + end + assign write_byteen_st1 = write_byteen_r; + end else begin + assign write_byteen_st1 = byteen_st1; + end `RESET_RELAY (data_reset, reset); VX_cache_data #( - .INSTANCE_ID (INSTANCE_ID), + .INSTANCE_ID ($sformatf("%s-data", INSTANCE_ID)), .BANK_ID (BANK_ID), .CACHE_SIZE (CACHE_SIZE), .LINE_SIZE (LINE_SIZE), @@ -330,6 +404,7 @@ module VX_cache_bank #( .NUM_WAYS (NUM_WAYS), .WORD_SIZE (WORD_SIZE), .WRITE_ENABLE (WRITE_ENABLE), + .WRITEBACK (WRITEBACK), .UUID_WIDTH (UUID_WIDTH) ) cache_data ( .clk (clk), @@ -339,23 +414,38 @@ module VX_cache_bank #( .stall (pipe_stall), - .read (do_read_hit_st1 || do_replay_rd_st1), - .fill (do_fill_st1), - .write (do_write_hit_st1 || do_replay_wr_st1), - .way_sel (way_sel_st1 | tag_matches_st1), + .read (do_cache_rd_st1), + .fill (do_fill_st1 && ~rdw_hazard_st1), + .flush (do_flush_st1), + .write (do_cache_wr_st1), + .way_sel (way_sel_st1), .line_addr (addr_st1), .wsel (wsel_st1), - .byteen (byteen_st1), .fill_data (fill_data_st1), .write_data (write_data_st1), - .read_data (read_data_st1) + .write_byteen(write_byteen_st1), + .read_data (read_data_st1), + .dirty_valid(dirty_valid_st1), + .dirty_data (dirty_data_st1), + .dirty_byteen(dirty_byteen_st1) ); - wire [MSHR_SIZE-1:0] mshr_matches_st0; + wire [MSHR_SIZE-1:0] mshr_lookup_pending_st0; + wire [MSHR_SIZE-1:0] mshr_lookup_rw_st0; wire mshr_allocate_st0 = valid_st0 && is_creq_st0 && ~pipe_stall; wire mshr_lookup_st0 = mshr_allocate_st0; wire mshr_finalize_st1 = valid_st1 && is_creq_st1 && ~pipe_stall; - wire mshr_release_st1 = is_hit_st1 || (rw_st1 && ~mshr_pending_st1); + + // release allocated mshr entry if we had a hit + wire mshr_release_st1; + if (WRITEBACK) begin + assign mshr_release_st1 = is_hit_st1; + end else begin + // we need to keep missed write requests in MSHR if there is already a pending entry to the same address + // this ensures that missed write requests are replayed locally in case a pending fill arrives without the write content + // this can happen when writes are sent late, when the fill was already in flight. + assign mshr_release_st1 = is_hit_st1 || (rw_st1 && ~mshr_pending_st1); + end VX_pending_size #( .SIZE (MSHR_SIZE) @@ -364,15 +454,17 @@ module VX_cache_bank #( .reset (reset), .incr (core_req_fire), .decr (replay_fire || (mshr_finalize_st1 && mshr_release_st1)), + .empty (mshr_empty), + `UNUSED_PIN (alm_empty), .full (mshr_alm_full), - `UNUSED_PIN (size), - `UNUSED_PIN (empty) + `UNUSED_PIN (alm_full), + `UNUSED_PIN (size) ); `RESET_RELAY (mshr_reset, reset); VX_cache_mshr #( - .INSTANCE_ID (INSTANCE_ID), + .INSTANCE_ID ($sformatf("%s-mshr", INSTANCE_ID)), .BANK_ID (BANK_ID), .LINE_SIZE (LINE_SIZE), .NUM_BANKS (NUM_BANKS), @@ -412,7 +504,8 @@ module VX_cache_bank #( // lookup .lookup_valid (mshr_lookup_st0), .lookup_addr (addr_st0), - .lookup_matches (mshr_matches_st0), + .lookup_pending (mshr_lookup_pending_st0), + .lookup_rw (mshr_lookup_rw_st0), // finalize .finalize_valid (mshr_finalize_st1), @@ -422,10 +515,12 @@ module VX_cache_bank #( .finalize_prev (mshr_prev_st1) ); - // ignore allocated id from mshr matches + // check if there are pending requests to same line in the MSHR wire [MSHR_SIZE-1:0] lookup_matches; for (genvar i = 0; i < MSHR_SIZE; ++i) begin - assign lookup_matches[i] = (i != mshr_alloc_id_st0) && mshr_matches_st0[i]; + assign lookup_matches[i] = mshr_lookup_pending_st0[i] + && (i != mshr_alloc_id_st0) // exclude current mshr id + && (WRITEBACK || ~mshr_lookup_rw_st0[i]); // exclude write requests if writethrough end assign mshr_pending_st0 = (| lookup_matches); @@ -436,7 +531,7 @@ module VX_cache_bank #( wire [REQ_SEL_WIDTH-1:0] crsp_queue_idx; wire [TAG_WIDTH-1:0] crsp_queue_tag; - assign crsp_queue_valid = do_read_hit_st1 || do_replay_rd_st1; + assign crsp_queue_valid = do_cache_rd_st1; assign crsp_queue_idx = req_idx_st1; assign crsp_queue_data = read_data_st1; assign crsp_queue_tag = tag_st1; @@ -463,29 +558,40 @@ module VX_cache_bank #( // schedule memory request wire mreq_queue_push, mreq_queue_pop, mreq_queue_empty; - wire [`CS_WORD_WIDTH-1:0] mreq_queue_data; - wire [WORD_SIZE-1:0] mreq_queue_byteen; - wire [WORD_SEL_WIDTH-1:0] mreq_queue_wsel; + wire [`CS_LINE_WIDTH-1:0] mreq_queue_data; + wire [LINE_SIZE-1:0] mreq_queue_byteen; wire [`CS_LINE_ADDR_WIDTH-1:0] mreq_queue_addr; wire [MSHR_ADDR_WIDTH-1:0] mreq_queue_id; wire mreq_queue_rw; + wire mreq_queue_flush; - assign mreq_queue_push = (do_read_miss_st1 && ~mshr_pending_st1) - || do_creq_wr_st1; + wire is_evict_st1 = (is_fill_st1 || is_flush_st1) && dirty_valid_st1; + wire do_writeback_st1 = valid_st1 && is_evict_st1; + `UNUSED_VAR (do_writeback_st1) + + if (WRITEBACK) begin + assign mreq_queue_push = (((do_read_miss_st1 || do_write_miss_st1) && ~mshr_pending_st1) + || do_writeback_st1) + && ~rdw_hazard_st1; + end else begin + `UNUSED_VAR (dirty_valid_st1) + assign mreq_queue_push = ((do_read_miss_st1 && ~mshr_pending_st1) + || do_creq_wr_st1) + && ~rdw_hazard_st1; + end assign mreq_queue_pop = mem_req_valid && mem_req_ready; - - assign mreq_queue_rw = WRITE_ENABLE && rw_st1; + assign mreq_queue_rw = WRITE_ENABLE && (WRITEBACK ? is_evict_st1 : rw_st1); assign mreq_queue_addr = addr_st1; assign mreq_queue_id = mshr_id_st1; - assign mreq_queue_wsel = wsel_st1; - assign mreq_queue_byteen = byteen_st1; - assign mreq_queue_data = write_data_st1; + assign mreq_queue_data = is_write_st1 ? write_data_st1 : dirty_data_st1; + assign mreq_queue_byteen = is_write_st1 ? write_byteen_st1 : dirty_byteen_st1; + assign mreq_queue_flush = creq_flush_st1; `RESET_RELAY (mreq_queue_reset, reset); VX_fifo_queue #( - .DATAW (1 + `CS_LINE_ADDR_WIDTH + MSHR_ADDR_WIDTH + WORD_SIZE + WORD_SEL_WIDTH + `CS_WORD_WIDTH), + .DATAW (1 + `CS_LINE_ADDR_WIDTH + MSHR_ADDR_WIDTH + LINE_SIZE + `CS_LINE_WIDTH + 1), .DEPTH (MREQ_SIZE), .ALM_FULL (MREQ_SIZE-PIPELINE_STAGES), .OUT_REG (`TO_OUT_BUF_REG(MEM_OUT_BUF)) @@ -494,8 +600,8 @@ module VX_cache_bank #( .reset (mreq_queue_reset), .push (mreq_queue_push), .pop (mreq_queue_pop), - .data_in ({mreq_queue_rw, mreq_queue_addr, mreq_queue_id, mreq_queue_byteen, mreq_queue_wsel, mreq_queue_data}), - .data_out ({mem_req_rw, mem_req_addr, mem_req_id, mem_req_byteen, mem_req_wsel, mem_req_data}), + .data_in ({mreq_queue_rw, mreq_queue_addr, mreq_queue_id, mreq_queue_byteen, mreq_queue_data, mreq_queue_flush}), + .data_out ({mem_req_rw, mem_req_addr, mem_req_id, mem_req_byteen, mem_req_data, mem_req_flush}), .empty (mreq_queue_empty), .alm_full (mreq_queue_alm_full), `UNUSED_PIN (full), @@ -515,35 +621,34 @@ module VX_cache_bank #( `ifdef DBG_TRACE_CACHE wire crsp_queue_fire = crsp_queue_valid && crsp_queue_ready; - wire pipeline_stall = (replay_valid || mem_rsp_valid || core_req_valid) - && ~(replay_fire || mem_rsp_fire || core_req_fire); + wire pipeline_stall = (replay_valid || mem_rsp_valid || core_req_valid || line_flush_valid) + && ~(replay_fire || mem_rsp_fire || core_req_fire || line_flush_valid); always @(posedge clk) begin if (pipeline_stall) begin - `TRACE(3, ("%d: *** %s-bank%0d stall: crsq=%b, mreq=%b, mshr=%b\n", $time, INSTANCE_ID, BANK_ID, crsp_queue_stall, mreq_queue_alm_full, mshr_alm_full)); - end - if (init_enable) begin - `TRACE(2, ("%d: %s-bank%0d init: addr=0x%0h\n", $time, INSTANCE_ID, BANK_ID, `CS_LINE_TO_FULL_ADDR(init_line_sel, BANK_ID))); + `TRACE(3, ("%d: *** %s stall: crsq=%b, mreq=%b, mshr=%b, rdw_st0=%b\n", $time, INSTANCE_ID, crsp_queue_stall, mreq_queue_alm_full, mshr_alm_full, rdw_hazard_st0)); end if (mem_rsp_fire) begin - `TRACE(2, ("%d: %s-bank%0d fill-rsp: addr=0x%0h, mshr_id=%0d, data=0x%0h\n", $time, INSTANCE_ID, BANK_ID, `CS_LINE_TO_FULL_ADDR(mem_rsp_addr, BANK_ID), mem_rsp_id, mem_rsp_data)); + `TRACE(2, ("%d: %s fill-rsp: addr=0x%0h, mshr_id=%0d, data=0x%0h\n", $time, INSTANCE_ID, `CS_LINE_TO_FULL_ADDR(mem_rsp_addr, BANK_ID), mem_rsp_id, mem_rsp_data)); end if (replay_fire) begin - `TRACE(2, ("%d: %s-bank%0d mshr-pop: addr=0x%0h, tag=0x%0h, req_idx=%0d (#%0d)\n", $time, INSTANCE_ID, BANK_ID, `CS_LINE_TO_FULL_ADDR(replay_addr, BANK_ID), replay_tag, replay_idx, req_uuid_sel)); + `TRACE(2, ("%d: %s mshr-pop: addr=0x%0h, tag=0x%0h, req_idx=%0d (#%0d)\n", $time, INSTANCE_ID, `CS_LINE_TO_FULL_ADDR(replay_addr, BANK_ID), replay_tag, replay_idx, req_uuid_sel)); end if (core_req_fire) begin if (core_req_rw) - `TRACE(2, ("%d: %s-bank%0d core-wr-req: addr=0x%0h, tag=0x%0h, req_idx=%0d, byteen=%b, data=0x%0h (#%0d)\n", $time, INSTANCE_ID, BANK_ID, `CS_LINE_TO_FULL_ADDR(core_req_addr, BANK_ID), core_req_tag, core_req_idx, core_req_byteen, core_req_data, req_uuid_sel)); + `TRACE(2, ("%d: %s core-wr-req: addr=0x%0h, tag=0x%0h, req_idx=%0d, byteen=%b, data=0x%0h (#%0d)\n", $time, INSTANCE_ID, `CS_LINE_TO_FULL_ADDR(core_req_addr, BANK_ID), core_req_tag, core_req_idx, core_req_byteen, core_req_data, req_uuid_sel)); else - `TRACE(2, ("%d: %s-bank%0d core-rd-req: addr=0x%0h, tag=0x%0h, req_idx=%0d (#%0d)\n", $time, INSTANCE_ID, BANK_ID, `CS_LINE_TO_FULL_ADDR(core_req_addr, BANK_ID), core_req_tag, core_req_idx, req_uuid_sel)); + `TRACE(2, ("%d: %s core-rd-req: addr=0x%0h, tag=0x%0h, req_idx=%0d (#%0d)\n", $time, INSTANCE_ID, `CS_LINE_TO_FULL_ADDR(core_req_addr, BANK_ID), core_req_tag, core_req_idx, req_uuid_sel)); end if (crsp_queue_fire) begin - `TRACE(2, ("%d: %s-bank%0d core-rd-rsp: addr=0x%0h, tag=0x%0h, req_idx=%0d, data=0x%0h (#%0d)\n", $time, INSTANCE_ID, BANK_ID, `CS_LINE_TO_FULL_ADDR(addr_st1, BANK_ID), crsp_queue_tag, crsp_queue_idx, crsp_queue_data, req_uuid_st1)); + `TRACE(2, ("%d: %s core-rd-rsp: addr=0x%0h, tag=0x%0h, req_idx=%0d, data=0x%0h (#%0d)\n", $time, INSTANCE_ID, `CS_LINE_TO_FULL_ADDR(addr_st1, BANK_ID), crsp_queue_tag, crsp_queue_idx, crsp_queue_data, req_uuid_st1)); end if (mreq_queue_push) begin - if (do_creq_wr_st1) - `TRACE(2, ("%d: %s-bank%0d writethrough: addr=0x%0h, byteen=%b, data=0x%0h (#%0d)\n", $time, INSTANCE_ID, BANK_ID, `CS_LINE_TO_FULL_ADDR(mreq_queue_addr, BANK_ID), mreq_queue_byteen, mreq_queue_data, req_uuid_st1)); + if (do_creq_wr_st1 && !WRITEBACK) + `TRACE(2, ("%d: %s writethrough: addr=0x%0h, byteen=%b, data=0x%0h (#%0d)\n", $time, INSTANCE_ID, `CS_LINE_TO_FULL_ADDR(mreq_queue_addr, BANK_ID), mreq_queue_byteen, mreq_queue_data, req_uuid_st1)); + else if (do_writeback_st1) + `TRACE(2, ("%d: %s writeback: addr=0x%0h, byteen=%b, data=0x%0h\n", $time, INSTANCE_ID, `CS_LINE_TO_FULL_ADDR(mreq_queue_addr, BANK_ID), mreq_queue_byteen, mreq_queue_data)); else - `TRACE(2, ("%d: %s-bank%0d fill-req: addr=0x%0h, mshr_id=%0d (#%0d)\n", $time, INSTANCE_ID, BANK_ID, `CS_LINE_TO_FULL_ADDR(mreq_queue_addr, BANK_ID), mreq_queue_id, req_uuid_st1)); + `TRACE(2, ("%d: %s fill-req: addr=0x%0h, mshr_id=%0d (#%0d)\n", $time, INSTANCE_ID, `CS_LINE_TO_FULL_ADDR(mreq_queue_addr, BANK_ID), mreq_queue_id, req_uuid_st1)); end end `endif diff --git a/hw/rtl/cache/VX_cache_bypass.sv b/hw/rtl/cache/VX_cache_bypass.sv index 6b211830f..379d33e8a 100644 --- a/hw/rtl/cache/VX_cache_bypass.sv +++ b/hw/rtl/cache/VX_cache_bypass.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,16 +18,16 @@ module VX_cache_bypass #( parameter TAG_SEL_IDX = 0, parameter PASSTHRU = 0, - parameter NC_ENABLE = 0, + parameter NC_ENABLE = 0, parameter WORD_SIZE = 1, - parameter LINE_SIZE = 1, + parameter LINE_SIZE = 1, parameter CORE_ADDR_WIDTH = 1, - + parameter CORE_TAG_WIDTH = 1, - - parameter MEM_ADDR_WIDTH = 1, + + parameter MEM_ADDR_WIDTH = 1, parameter MEM_TAG_IN_WIDTH = 1, parameter MEM_TAG_OUT_WIDTH = 1, @@ -35,9 +35,9 @@ module VX_cache_bypass #( parameter CORE_OUT_BUF = 0, parameter MEM_OUT_BUF = 0, - + parameter CORE_DATA_WIDTH = WORD_SIZE * 8 - ) ( + ) ( input wire clk, input wire reset, @@ -71,40 +71,39 @@ module VX_cache_bypass #( wire core_req_nc_valid; wire [NUM_REQS-1:0] core_req_nc_valids; - wire [NUM_REQS-1:0] core_req_nc_idxs; + wire [NUM_REQS-1:0] core_req_nc_idxs; wire [`UP(REQ_SEL_BITS)-1:0] core_req_nc_idx; - wire [NUM_REQS-1:0] core_req_nc_sel; + wire [NUM_REQS-1:0] core_req_nc_sel; wire core_req_nc_ready; - - for (genvar i = 0; i < NUM_REQS; ++i) begin + + for (genvar i = 0; i < NUM_REQS; ++i) begin if (PASSTHRU != 0) begin assign core_req_nc_idxs[i] = 1'b1; end else if (NC_ENABLE) begin assign core_req_nc_idxs[i] = core_bus_in_if[i].req_data.atype[`ADDR_TYPE_IO]; end else begin assign core_req_nc_idxs[i] = 1'b0; - end + end assign core_req_nc_valids[i] = core_bus_in_if[i].req_valid && core_req_nc_idxs[i]; - end + end VX_generic_arbiter #( .NUM_REQS (NUM_REQS), - .TYPE (PASSTHRU ? "R" : "P"), - .LOCK_ENABLE (1) + .TYPE (PASSTHRU ? "R" : "P") ) core_req_nc_arb ( .clk (clk), - .reset (reset), - .requests (core_req_nc_valids), + .reset (reset), + .requests (core_req_nc_valids), .grant_index (core_req_nc_idx), .grant_onehot (core_req_nc_sel), .grant_valid (core_req_nc_valid), - .grant_unlock (core_req_nc_ready) + .grant_ready (core_req_nc_ready) ); for (genvar i = 0; i < NUM_REQS; ++i) begin assign core_bus_out_if[i].req_valid = core_bus_in_if[i].req_valid && ~core_req_nc_idxs[i]; assign core_bus_out_if[i].req_data = core_bus_in_if[i].req_data; - assign core_bus_in_if[i].req_ready = core_req_nc_valids[i] ? (core_req_nc_ready && core_req_nc_sel[i]) + assign core_bus_in_if[i].req_ready = core_req_nc_valids[i] ? (core_req_nc_ready && core_req_nc_sel[i]) : core_bus_out_if[i].req_ready; end @@ -118,7 +117,7 @@ module VX_cache_bypass #( wire [`CS_LINE_WIDTH-1:0] mem_req_out_data; wire [MEM_TAG_OUT_WIDTH-1:0] mem_req_out_tag; wire mem_req_out_ready; - + wire core_req_nc_sel_rw; wire [WORD_SIZE-1:0] core_req_nc_sel_byteen; wire [CORE_ADDR_WIDTH-1:0] core_req_nc_sel_addr; @@ -129,22 +128,22 @@ module VX_cache_bypass #( wire [NUM_REQS-1:0][MUX_DATAW-1:0] core_req_nc_mux_in; for (genvar i = 0; i < NUM_REQS; ++i) begin assign core_req_nc_mux_in[i] = { - core_bus_in_if[i].req_data.rw, + core_bus_in_if[i].req_data.rw, core_bus_in_if[i].req_data.byteen, core_bus_in_if[i].req_data.addr, core_bus_in_if[i].req_data.atype, core_bus_in_if[i].req_data.data, - core_bus_in_if[i].req_data.tag + core_bus_in_if[i].req_data.tag }; end - + assign { core_req_nc_sel_rw, core_req_nc_sel_byteen, core_req_nc_sel_addr, core_req_nc_sel_atype, core_req_nc_sel_data, - core_req_nc_sel_tag + core_req_nc_sel_tag } = core_req_nc_mux_in[core_req_nc_idx]; assign core_req_nc_ready = ~mem_bus_in_if.req_valid && mem_req_out_ready; @@ -157,11 +156,11 @@ module VX_cache_bypass #( wire [MEM_TAG_ID_BITS-1:0] mem_req_tag_id_bypass; wire [CORE_TAG_ID_BITS-1:0] core_req_in_id = core_req_nc_sel_tag[CORE_TAG_ID_BITS-1:0]; - + if (WORDS_PER_LINE > 1) begin reg [WORDS_PER_LINE-1:0][WORD_SIZE-1:0] mem_req_byteen_in_r; reg [WORDS_PER_LINE-1:0][CORE_DATA_WIDTH-1:0] mem_req_data_in_r; - + wire [WSEL_BITS-1:0] req_wsel = core_req_nc_sel_addr[WSEL_BITS-1:0]; always @(*) begin @@ -176,7 +175,7 @@ module VX_cache_bypass #( assign mem_req_out_data = mem_bus_in_if.req_valid ? mem_bus_in_if.req_data.data : mem_req_data_in_r; if (NUM_REQS > 1) begin assign mem_req_tag_id_bypass = MEM_TAG_ID_BITS'({core_req_nc_idx, req_wsel, core_req_in_id}); - end else begin + end else begin assign mem_req_tag_id_bypass = MEM_TAG_ID_BITS'({req_wsel, core_req_in_id}); end end else begin @@ -189,7 +188,7 @@ module VX_cache_bypass #( end end - wire [MEM_TAG_BYPASS_BITS-1:0] mem_req_tag_bypass; + wire [MEM_TAG_BYPASS_BITS-1:0] mem_req_tag_bypass; if (UUID_WIDTH != 0) begin assign mem_req_tag_bypass = {core_req_nc_sel_tag[CORE_TAG_ID_BITS +: UUID_WIDTH], mem_req_tag_id_bypass}; @@ -202,7 +201,7 @@ module VX_cache_bypass #( `UNUSED_VAR (mem_bus_in_if.req_data.tag) end else begin if (NC_ENABLE) begin - VX_bits_insert #( + VX_bits_insert #( .N (MEM_TAG_OUT_WIDTH-1), .S (1), .POS (TAG_SEL_IDX) @@ -213,8 +212,8 @@ module VX_cache_bypass #( ); end else begin assign mem_req_out_tag = mem_bus_in_if.req_data.tag; - end - end + end + end assign mem_bus_in_if.req_ready = mem_req_out_ready; @@ -225,11 +224,11 @@ module VX_cache_bypass #( ) mem_req_buf ( .clk (clk), .reset (reset), - .valid_in (mem_req_out_valid), - .ready_in (mem_req_out_ready), + .valid_in (mem_req_out_valid), + .ready_in (mem_req_out_ready), .data_in ({mem_req_out_rw, mem_req_out_byteen, mem_req_out_addr, mem_req_out_atype, mem_req_out_data, mem_req_out_tag}), .data_out ({mem_bus_out_if.req_data.rw, mem_bus_out_if.req_data.byteen, mem_bus_out_if.req_data.addr, mem_bus_out_if.req_data.atype, mem_bus_out_if.req_data.data, mem_bus_out_if.req_data.tag}), - .valid_out (mem_bus_out_if.req_valid), + .valid_out (mem_bus_out_if.req_valid), .ready_out (mem_bus_out_if.req_ready) ); @@ -253,7 +252,7 @@ module VX_cache_bypass #( wire [(MEM_TAG_OUT_WIDTH - NC_ENABLE)-1:0] mem_rsp_tag_id_nc; - VX_bits_remove #( + VX_bits_remove #( .N (MEM_TAG_OUT_WIDTH), .S (NC_ENABLE), .POS (TAG_SEL_IDX) @@ -265,10 +264,10 @@ module VX_cache_bypass #( wire [`UP(REQ_SEL_BITS)-1:0] rsp_idx; if (NUM_REQS > 1) begin assign rsp_idx = mem_rsp_tag_id_nc[(CORE_TAG_ID_BITS + WSEL_BITS) +: REQ_SEL_BITS]; - end else begin + end else begin assign rsp_idx = 1'b0; end - + reg [NUM_REQS-1:0] rsp_nc_valid_r; always @(*) begin rsp_nc_valid_r = '0; @@ -277,13 +276,13 @@ module VX_cache_bypass #( for (genvar i = 0; i < NUM_REQS; ++i) begin assign core_rsp_in_valid[i] = core_bus_out_if[i].rsp_valid || rsp_nc_valid_r[i]; - assign core_bus_out_if[i].rsp_ready = core_rsp_in_ready[i]; + assign core_bus_out_if[i].rsp_ready = core_rsp_in_ready[i]; end - + if (WORDS_PER_LINE > 1) begin - wire [WSEL_BITS-1:0] rsp_wsel = mem_rsp_tag_id_nc[CORE_TAG_ID_BITS +: WSEL_BITS]; + wire [WSEL_BITS-1:0] rsp_wsel = mem_rsp_tag_id_nc[CORE_TAG_ID_BITS +: WSEL_BITS]; for (genvar i = 0; i < NUM_REQS; ++i) begin - assign core_rsp_in_data[i] = core_bus_out_if[i].rsp_valid ? + assign core_rsp_in_data[i] = core_bus_out_if[i].rsp_valid ? core_bus_out_if[i].rsp_data.data : mem_bus_out_if.rsp_data.data[rsp_wsel * CORE_DATA_WIDTH +: CORE_DATA_WIDTH]; end end else begin @@ -306,7 +305,7 @@ module VX_cache_bypass #( assign core_rsp_in_tag[i] = core_bus_out_if[i].rsp_valid ? core_bus_out_if[i].rsp_data.tag : mem_rsp_tag_in_nc2; end else begin assign core_rsp_in_tag[i] = core_bus_out_if[i].rsp_data.tag; - end + end end for (genvar i = 0; i < NUM_REQS; ++i) begin @@ -320,7 +319,7 @@ module VX_cache_bypass #( .valid_in (core_rsp_in_valid[i]), .ready_in (core_rsp_in_ready[i]), .data_in ({core_rsp_in_data[i], core_rsp_in_tag[i]}), - .data_out ({core_bus_in_if[i].rsp_data.data, core_bus_in_if[i].rsp_data.tag}), + .data_out ({core_bus_in_if[i].rsp_data.data, core_bus_in_if[i].rsp_data.tag}), .valid_out (core_bus_in_if[i].rsp_valid), .ready_out (core_bus_in_if[i].rsp_ready) ); @@ -341,7 +340,7 @@ module VX_cache_bypass #( assign mem_bus_in_if.rsp_data.data = mem_bus_out_if.rsp_data.data; assign mem_bus_in_if.rsp_data.tag = mem_rsp_tag_id_nc; end - + wire [NUM_REQS-1:0] core_rsp_out_valid; for (genvar i = 0; i < NUM_REQS; ++i) begin assign core_rsp_out_valid[i] = core_bus_out_if[i].rsp_valid; diff --git a/hw/rtl/cache/VX_cache_cluster.sv b/hw/rtl/cache/VX_cache_cluster.sv index a132f9b67..c567ddbc5 100644 --- a/hw/rtl/cache/VX_cache_cluster.sv +++ b/hw/rtl/cache/VX_cache_cluster.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -24,20 +24,20 @@ module VX_cache_cluster import VX_gpu_pkg::*; #( parameter NUM_REQS = 4, // Size of cache in bytes - parameter CACHE_SIZE = 16384, + parameter CACHE_SIZE = 16384, // Size of line inside a bank in bytes - parameter LINE_SIZE = 64, + parameter LINE_SIZE = 64, // Number of banks parameter NUM_BANKS = 1, // Number of associative ways parameter NUM_WAYS = 4, // Size of a word in bytes - parameter WORD_SIZE = 4, + parameter WORD_SIZE = 4, // Core Response Queue Size parameter CRSQ_SIZE = 2, // Miss Reserv Queue Knob - parameter MSHR_SIZE = 8, + parameter MSHR_SIZE = 8, // Memory Response Queue Size parameter MRSQ_SIZE = 0, // Memory Request Queue Size @@ -46,6 +46,9 @@ module VX_cache_cluster import VX_gpu_pkg::*; #( // Enable cache writeable parameter WRITE_ENABLE = 1, + // Enable cache writeback + parameter WRITEBACK = 0, + // Request debug identifier parameter UUID_WIDTH = 0, @@ -60,7 +63,7 @@ module VX_cache_cluster import VX_gpu_pkg::*; #( // Memory request output buffer parameter MEM_OUT_BUF = 0 - ) ( + ) ( input wire clk, input wire reset, @@ -74,17 +77,16 @@ module VX_cache_cluster import VX_gpu_pkg::*; #( ); localparam NUM_CACHES = `UP(NUM_UNITS); localparam PASSTHRU = (NUM_UNITS == 0); - localparam ARB_TAG_WIDTH = TAG_WIDTH + `ARB_SEL_BITS(NUM_INPUTS, NUM_CACHES); - localparam MEM_TAG_WIDTH = PASSTHRU ? `CACHE_BYPASS_TAG_WIDTH(NUM_REQS, LINE_SIZE, WORD_SIZE, ARB_TAG_WIDTH) : + localparam ARB_TAG_WIDTH = TAG_WIDTH + `ARB_SEL_BITS(NUM_INPUTS, NUM_CACHES); + localparam MEM_TAG_WIDTH = PASSTHRU ? `CACHE_BYPASS_TAG_WIDTH(NUM_REQS, LINE_SIZE, WORD_SIZE, ARB_TAG_WIDTH) : (NC_ENABLE ? `CACHE_NC_MEM_TAG_WIDTH(MSHR_SIZE, NUM_BANKS, NUM_REQS, LINE_SIZE, WORD_SIZE, ARB_TAG_WIDTH) : `CACHE_MEM_TAG_WIDTH(MSHR_SIZE, NUM_BANKS)); `STATIC_ASSERT(NUM_INPUTS >= NUM_CACHES, ("invalid parameter")) `ifdef PERF_ENABLE - cache_perf_t perf_cache_tmp[1], perf_cache_unit[NUM_CACHES]; - `PERF_CACHE_ADD (perf_cache_tmp, perf_cache_unit, 1, NUM_CACHES) - assign cache_perf = perf_cache_tmp[0]; + cache_perf_t perf_cache_unit[NUM_CACHES]; + `PERF_CACHE_ADD (cache_perf, perf_cache_unit, NUM_CACHES) `endif VX_mem_bus_if #( @@ -97,8 +99,6 @@ module VX_cache_cluster import VX_gpu_pkg::*; #( .TAG_WIDTH (ARB_TAG_WIDTH) ) arb_core_bus_if[NUM_CACHES * NUM_REQS](); - `RESET_RELAY (arb_reset, reset); - for (genvar i = 0; i < NUM_REQS; ++i) begin VX_mem_bus_if #( .DATA_SIZE (WORD_SIZE), @@ -114,6 +114,8 @@ module VX_cache_cluster import VX_gpu_pkg::*; #( `ASSIGN_VX_MEM_BUS_IF (core_bus_tmp_if[j], core_bus_if[j * NUM_REQS + i]); end + `RESET_RELAY (arb_reset, reset); + VX_mem_arb #( .NUM_INPUTS (NUM_INPUTS), .NUM_OUTPUTS (NUM_CACHES), @@ -135,9 +137,9 @@ module VX_cache_cluster import VX_gpu_pkg::*; #( end end - `RESET_RELAY (cache_reset, reset); + for (genvar i = 0; i < NUM_CACHES; ++i) begin : caches - for (genvar i = 0; i < NUM_CACHES; ++i) begin + `RESET_RELAY (cache_reset, reset); VX_cache_wrap #( .INSTANCE_ID ($sformatf("%s%0d", INSTANCE_ID, i)), @@ -152,6 +154,7 @@ module VX_cache_cluster import VX_gpu_pkg::*; #( .MRSQ_SIZE (MRSQ_SIZE), .MREQ_SIZE (MREQ_SIZE), .WRITE_ENABLE (WRITE_ENABLE), + .WRITEBACK (WRITEBACK), .UUID_WIDTH (UUID_WIDTH), .TAG_WIDTH (ARB_TAG_WIDTH), .TAG_SEL_IDX (TAG_SEL_IDX), diff --git a/hw/rtl/cache/VX_cache_data.sv b/hw/rtl/cache/VX_cache_data.sv index 08df15e4c..6bf8f1c3e 100644 --- a/hw/rtl/cache/VX_cache_data.sv +++ b/hw/rtl/cache/VX_cache_data.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -17,17 +17,19 @@ module VX_cache_data #( parameter `STRING INSTANCE_ID= "", parameter BANK_ID = 0, // Size of cache in bytes - parameter CACHE_SIZE = 1024, + parameter CACHE_SIZE = 1024, // Size of line inside a bank in bytes - parameter LINE_SIZE = 16, + parameter LINE_SIZE = 16, // Number of banks - parameter NUM_BANKS = 1, + parameter NUM_BANKS = 1, // Number of associative ways parameter NUM_WAYS = 1, // Size of a word in bytes parameter WORD_SIZE = 1, // Enable cache writeable parameter WRITE_ENABLE = 1, + // Enable cache writeback + parameter WRITEBACK = 0, // Request debug identifier parameter UUID_WIDTH = 0 ) ( @@ -41,59 +43,100 @@ module VX_cache_data #( input wire stall, input wire read, - input wire fill, + input wire fill, + input wire flush, input wire write, input wire [`CS_LINE_ADDR_WIDTH-1:0] line_addr, input wire [`UP(`CS_WORD_SEL_BITS)-1:0] wsel, - input wire [WORD_SIZE-1:0] byteen, input wire [`CS_WORDS_PER_LINE-1:0][`CS_WORD_WIDTH-1:0] fill_data, - input wire [`CS_WORD_WIDTH-1:0] write_data, + input wire [`CS_WORDS_PER_LINE-1:0][`CS_WORD_WIDTH-1:0] write_data, + input wire [`CS_WORDS_PER_LINE-1:0][WORD_SIZE-1:0] write_byteen, input wire [NUM_WAYS-1:0] way_sel, - - output wire [`CS_WORD_WIDTH-1:0] read_data + output wire [`CS_WORD_WIDTH-1:0] read_data, + output wire dirty_valid, + output wire [`CS_LINE_WIDTH-1:0] dirty_data, + output wire [LINE_SIZE-1:0] dirty_byteen ); `UNUSED_SPARAM (INSTANCE_ID) `UNUSED_PARAM (BANK_ID) `UNUSED_PARAM (WORD_SIZE) `UNUSED_VAR (reset) + `UNUSED_VAR (stall) `UNUSED_VAR (line_addr) `UNUSED_VAR (read) + `UNUSED_VAR (flush) localparam BYTEENW = (WRITE_ENABLE != 0 || (NUM_WAYS > 1)) ? (LINE_SIZE * NUM_WAYS) : 1; + wire [`CS_LINE_SEL_BITS-1:0] line_sel = line_addr[`CS_LINE_SEL_BITS-1:0]; + wire [`LOG2UP(NUM_WAYS)-1:0] way_idx; + + if (WRITEBACK) begin + reg [`CS_LINES_PER_BANK * NUM_WAYS-1:0][LINE_SIZE-1:0] dirty_bytes_r; + reg [`CS_LINES_PER_BANK * NUM_WAYS-1:0] dirty_blocks_r; + + wire [`CLOG2(`CS_LINES_PER_BANK * NUM_WAYS)-1:0] way_addr; + if (NUM_WAYS > 1) begin + assign way_addr = {line_sel, way_idx}; + end else begin + assign way_addr = line_sel; + end + + always @(posedge clk) begin + if (fill) begin + dirty_bytes_r[way_addr] <= '0; + end else if (write) begin + dirty_bytes_r[way_addr] <= dirty_bytes_r[way_addr] | write_byteen; + end + end + + always @(posedge clk) begin + if (reset) begin + for (integer i = 0; i < `CS_LINES_PER_BANK * NUM_WAYS; ++i) begin + dirty_blocks_r[i] <= 0; + end + end else begin + if (fill) begin + dirty_blocks_r[way_addr] <= 0; + end else if (write) begin + dirty_blocks_r[way_addr] <= 1; + end + end + end + + assign dirty_byteen = dirty_bytes_r[way_addr]; + assign dirty_valid = dirty_blocks_r[way_addr]; + end else begin + assign dirty_byteen = '0; + assign dirty_valid = 0; + end + + // order the data layout to perform ways multiplexing last. + // this allows converting way index to binary in parallel with BRAM read. + wire [`CS_WORDS_PER_LINE-1:0][NUM_WAYS-1:0][`CS_WORD_WIDTH-1:0] wdata; wire [BYTEENW-1:0] wren; if (WRITE_ENABLE != 0 || (NUM_WAYS > 1)) begin - reg [`CS_WORDS_PER_LINE-1:0][`CS_WORD_WIDTH-1:0] wdata_r; - reg [`CS_WORDS_PER_LINE-1:0][WORD_SIZE-1:0] wren_r; - - always @(*) begin - wdata_r = {`CS_WORDS_PER_LINE{write_data}}; - wren_r = '0; - wren_r[wsel] = byteen; + for (genvar i = 0; i < `CS_WORDS_PER_LINE; ++i) begin + assign wdata[i] = (fill || !WRITE_ENABLE) ? {NUM_WAYS{fill_data[i]}} : {NUM_WAYS{write_data[i]}}; end - - // order the data layout to perform ways multiplexing last - // this allows performing onehot encoding of the way index in parallel with BRAM read. + wire [`CS_WORDS_PER_LINE-1:0][NUM_WAYS-1:0][WORD_SIZE-1:0] wren_w; for (genvar i = 0; i < `CS_WORDS_PER_LINE; ++i) begin - assign wdata[i] = fill ? {NUM_WAYS{fill_data[i]}} : {NUM_WAYS{wdata_r[i]}}; for (genvar j = 0; j < NUM_WAYS; ++j) begin - assign wren_w[i][j] = (fill ? {WORD_SIZE{1'b1}} : wren_r[i]) - & {WORD_SIZE{((NUM_WAYS == 1) || way_sel[j])}}; + assign wren_w[i][j] = ((fill || !WRITE_ENABLE) ? {WORD_SIZE{1'b1}} : write_byteen[i]) + & {WORD_SIZE{(way_sel[j] || (NUM_WAYS == 1))}}; end end assign wren = wren_w; end else begin `UNUSED_VAR (write) - `UNUSED_VAR (byteen) + `UNUSED_VAR (write_byteen) `UNUSED_VAR (write_data) assign wdata = fill_data; assign wren = fill; end - - wire [`LOG2UP(NUM_WAYS)-1:0] way_idx; VX_onehot_encoder #( .N (NUM_WAYS) @@ -105,8 +148,6 @@ module VX_cache_data #( wire [`CS_WORDS_PER_LINE-1:0][NUM_WAYS-1:0][`CS_WORD_WIDTH-1:0] rdata; - wire [`CS_LINE_SEL_BITS-1:0] line_sel = line_addr[`CS_LINE_SEL_BITS-1:0]; - VX_sp_ram #( .DATAW (`CS_LINE_WIDTH * NUM_WAYS), .SIZE (`CS_LINES_PER_BANK), @@ -119,34 +160,41 @@ module VX_cache_data #( .wren (wren), .addr (line_sel), .wdata (wdata), - .rdata (rdata) + .rdata (rdata) ); wire [NUM_WAYS-1:0][`CS_WORD_WIDTH-1:0] per_way_rdata; - if (`CS_WORDS_PER_LINE > 1) begin assign per_way_rdata = rdata[wsel]; end else begin `UNUSED_VAR (wsel) assign per_way_rdata = rdata; - end - + end assign read_data = per_way_rdata[way_idx]; - `UNUSED_VAR (stall) + wire [NUM_WAYS-1:0][`CS_WORDS_PER_LINE-1:0][`CS_WORD_WIDTH-1:0] dirty_data_w; + for (genvar i = 0; i < `CS_WORDS_PER_LINE; ++i) begin + for (genvar j = 0; j < NUM_WAYS; ++j) begin + assign dirty_data_w[j][i] = rdata[i][j]; + end + end + assign dirty_data = dirty_data_w[way_idx]; `ifdef DBG_TRACE_CACHE - always @(posedge clk) begin + always @(posedge clk) begin if (fill && ~stall) begin - `TRACE(3, ("%d: %s-bank%0d data-fill: addr=0x%0h, way=%b, blk_addr=%0d, data=0x%0h\n", $time, INSTANCE_ID, BANK_ID, `CS_LINE_TO_FULL_ADDR(line_addr, BANK_ID), way_sel, line_sel, fill_data)); + `TRACE(3, ("%d: %s fill: addr=0x%0h, way=%b, blk_addr=%0d, data=0x%0h\n", $time, INSTANCE_ID, `CS_LINE_TO_FULL_ADDR(line_addr, BANK_ID), way_sel, line_sel, fill_data)); + end + if (flush && ~stall) begin + `TRACE(3, ("%d: %s flush: addr=0x%0h, way=%b, blk_addr=%0d, dirty=%b, byteen=%b\n", $time, INSTANCE_ID, `CS_LINE_TO_FULL_ADDR(line_addr, BANK_ID), way_sel, line_sel, dirty_valid, dirty_byteen)); end if (read && ~stall) begin - `TRACE(3, ("%d: %s-bank%0d data-read: addr=0x%0h, way=%b, blk_addr=%0d, data=0x%0h (#%0d)\n", $time, INSTANCE_ID, BANK_ID, `CS_LINE_TO_FULL_ADDR(line_addr, BANK_ID), way_sel, line_sel, read_data, req_uuid)); - end + `TRACE(3, ("%d: %s read: addr=0x%0h, way=%b, blk_addr=%0d, wsel=%0d, data=0x%0h (#%0d)\n", $time, INSTANCE_ID, `CS_LINE_TO_FULL_ADDR(line_addr, BANK_ID), way_sel, line_sel, wsel, read_data, req_uuid)); + end if (write && ~stall) begin - `TRACE(3, ("%d: %s-bank%0d data-write: addr=0x%0h, way=%b, blk_addr=%0d, byteen=%b, data=0x%0h (#%0d)\n", $time, INSTANCE_ID, BANK_ID, `CS_LINE_TO_FULL_ADDR(line_addr, BANK_ID), way_sel, line_sel, byteen, write_data, req_uuid)); - end - end + `TRACE(3, ("%d: %s write: addr=0x%0h, way=%b, blk_addr=%0d, wsel=%0d, byteen=%b, data=0x%0h (#%0d)\n", $time, INSTANCE_ID, `CS_LINE_TO_FULL_ADDR(line_addr, BANK_ID), way_sel, line_sel, wsel, write_byteen[wsel], write_data[wsel], req_uuid)); + end + end `endif endmodule diff --git a/hw/rtl/cache/VX_cache_define.vh b/hw/rtl/cache/VX_cache_define.vh index a9c10f3fb..e6d7da167 100644 --- a/hw/rtl/cache/VX_cache_define.vh +++ b/hw/rtl/cache/VX_cache_define.vh @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -14,7 +14,7 @@ `ifndef VX_CACHE_DEFINE_VH `define VX_CACHE_DEFINE_VH -`include "VX_define.vh" +`include "VX_define.vh" `define CS_REQ_SEL_BITS `CLOG2(NUM_REQS) @@ -50,7 +50,7 @@ `define CS_TAG_SEL_ADDR_START (1+`CS_LINE_SEL_ADDR_END) `define CS_TAG_SEL_ADDR_END (`CS_WORD_ADDR_WIDTH-1) -`define CS_LINE_TAG_ADDR(x) x[`CS_LINE_ADDR_WIDTH-1 : `CS_LINE_SEL_BITS] +`define CS_LINE_ADDR_TAG(x) x[`CS_LINE_ADDR_WIDTH-1 : `CS_LINE_SEL_BITS] /////////////////////////////////////////////////////////////////////////////// @@ -64,14 +64,14 @@ /////////////////////////////////////////////////////////////////////////////// -`define PERF_CACHE_ADD(dst, src, dcount, scount) \ - `PERF_COUNTER_ADD (dst, src, reads, `PERF_CTR_BITS, dcount, scount, (`CDIV(scount, dcount) > 1)) \ - `PERF_COUNTER_ADD (dst, src, writes, `PERF_CTR_BITS, dcount, scount, (`CDIV(scount, dcount) > 1)) \ - `PERF_COUNTER_ADD (dst, src, read_misses, `PERF_CTR_BITS, dcount, scount, (`CDIV(scount, dcount) > 1)) \ - `PERF_COUNTER_ADD (dst, src, write_misses, `PERF_CTR_BITS, dcount, scount, (`CDIV(scount, dcount) > 1)) \ - `PERF_COUNTER_ADD (dst, src, bank_stalls, `PERF_CTR_BITS, dcount, scount, (`CDIV(scount, dcount) > 1)) \ - `PERF_COUNTER_ADD (dst, src, mshr_stalls, `PERF_CTR_BITS, dcount, scount, (`CDIV(scount, dcount) > 1)) \ - `PERF_COUNTER_ADD (dst, src, mem_stalls, `PERF_CTR_BITS, dcount, scount, (`CDIV(scount, dcount) > 1)) \ - `PERF_COUNTER_ADD (dst, src, crsp_stalls, `PERF_CTR_BITS, dcount, scount, (`CDIV(scount, dcount) > 1)) +`define PERF_CACHE_ADD(dst, src, count) \ + `PERF_COUNTER_ADD (dst, src, reads, `PERF_CTR_BITS, count, (count > 1)) \ + `PERF_COUNTER_ADD (dst, src, writes, `PERF_CTR_BITS, count, (count > 1)) \ + `PERF_COUNTER_ADD (dst, src, read_misses, `PERF_CTR_BITS, count, (count > 1)) \ + `PERF_COUNTER_ADD (dst, src, write_misses, `PERF_CTR_BITS, count, (count > 1)) \ + `PERF_COUNTER_ADD (dst, src, bank_stalls, `PERF_CTR_BITS, count, (count > 1)) \ + `PERF_COUNTER_ADD (dst, src, mshr_stalls, `PERF_CTR_BITS, count, (count > 1)) \ + `PERF_COUNTER_ADD (dst, src, mem_stalls, `PERF_CTR_BITS, count, (count > 1)) \ + `PERF_COUNTER_ADD (dst, src, crsp_stalls, `PERF_CTR_BITS, count, (count > 1)) `endif // VX_CACHE_DEFINE_VH diff --git a/hw/rtl/cache/VX_cache_flush.sv b/hw/rtl/cache/VX_cache_flush.sv new file mode 100644 index 000000000..7c46a48f0 --- /dev/null +++ b/hw/rtl/cache/VX_cache_flush.sv @@ -0,0 +1,154 @@ +// Copyright © 2019-2023 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +`include "VX_cache_define.vh" + +module VX_cache_flush #( + // Number of Word requests per cycle + parameter NUM_REQS = 4, + // Number of banks + parameter NUM_BANKS = 1, + // Bank select latency + parameter BANK_SEL_LATENCY = 1 +) ( + input wire clk, + input wire reset, + VX_mem_bus_if.slave core_bus_in_if [NUM_REQS], + VX_mem_bus_if.master core_bus_out_if [NUM_REQS], + input wire [NUM_BANKS-1:0] bank_req_fire, + output wire [NUM_BANKS-1:0] flush_valid, + input wire [NUM_BANKS-1:0] flush_ready +); + localparam STATE_IDLE = 0; + localparam STATE_WAIT = 1; + localparam STATE_FLUSH = 2; + localparam STATE_DONE = 3; + + // track in-flight core requests + + wire no_inflight_reqs; + + if (BANK_SEL_LATENCY != 0) begin + + localparam NUM_REQS_W = `CLOG2(NUM_REQS+1); + localparam NUM_BANKS_W = `CLOG2(NUM_BANKS+1); + + wire [NUM_REQS-1:0] core_bus_out_fire; + for (genvar i = 0; i < NUM_REQS; ++i) begin + assign core_bus_out_fire[i] = core_bus_out_if[i].req_valid && core_bus_out_if[i].req_ready; + end + + wire [NUM_REQS_W-1:0] core_bus_out_cnt; + wire [NUM_BANKS_W-1:0] bank_req_cnt; + + `POP_COUNT(core_bus_out_cnt, core_bus_out_fire); + `POP_COUNT(bank_req_cnt, bank_req_fire); + `UNUSED_VAR (core_bus_out_cnt) + + VX_pending_size #( + .SIZE (BANK_SEL_LATENCY * NUM_BANKS), + .INCRW (NUM_BANKS_W), + .DECRW (NUM_BANKS_W) + ) pending_size ( + .clk (clk), + .reset (reset), + .incr (NUM_BANKS_W'(core_bus_out_cnt)), + .decr (bank_req_cnt), + .empty (no_inflight_reqs), + `UNUSED_PIN (alm_empty), + `UNUSED_PIN (full), + `UNUSED_PIN (alm_full), + `UNUSED_PIN (size) + ); + + end else begin + assign no_inflight_reqs = 0; + `UNUSED_VAR (bank_req_fire) + end + + + reg [1:0] state, state_n; + reg [NUM_BANKS-1:0] flush_done, flush_done_n; + + wire [NUM_REQS-1:0] flush_req_mask; + for (genvar i = 0; i < NUM_REQS; ++i) begin + assign flush_req_mask[i] = core_bus_in_if[i].req_valid && core_bus_in_if[i].req_data.atype[`ADDR_TYPE_FLUSH]; + end + wire flush_req_enable = (| flush_req_mask); + + reg [NUM_REQS-1:0] lock_released, lock_released_n; + + for (genvar i = 0; i < NUM_REQS; ++i) begin + wire input_enable = ~flush_req_enable || lock_released[i]; + assign core_bus_out_if[i].req_valid = core_bus_in_if[i].req_valid && input_enable; + assign core_bus_out_if[i].req_data = core_bus_in_if[i].req_data; + assign core_bus_in_if[i].req_ready = core_bus_out_if[i].req_ready && input_enable; + end + + for (genvar i = 0; i < NUM_REQS; ++i) begin + assign core_bus_in_if[i].rsp_valid = core_bus_out_if[i].rsp_valid; + assign core_bus_in_if[i].rsp_data = core_bus_out_if[i].rsp_data; + assign core_bus_out_if[i].rsp_ready = core_bus_in_if[i].rsp_ready; + end + + wire [NUM_REQS-1:0] core_bus_out_ready; + for (genvar i = 0; i < NUM_REQS; ++i) begin + assign core_bus_out_ready[i] = core_bus_out_if[i].req_ready; + end + + always @(*) begin + state_n = state; + flush_done_n = flush_done; + lock_released_n = lock_released; + case (state) + STATE_IDLE: begin + if (flush_req_enable) begin + state_n = (BANK_SEL_LATENCY != 0) ? STATE_WAIT : STATE_FLUSH; + end + end + STATE_WAIT: begin + if (no_inflight_reqs) begin + state_n = STATE_FLUSH; + end + end + STATE_FLUSH: begin + flush_done_n = flush_done | flush_ready; + if (flush_done_n == 0) begin + state_n = STATE_DONE; + lock_released_n = flush_req_mask; + end + end + STATE_DONE: begin + lock_released_n = lock_released & ~core_bus_out_ready; + if (lock_released_n == 0) begin + state_n = STATE_IDLE; + end + end + endcase + end + + always @(posedge clk) begin + if (reset) begin + state <= STATE_IDLE; + flush_done <= '0; + lock_released <= '0; + end else begin + state <= state_n; + flush_done <= flush_done_n; + lock_released <= lock_released_n; + end + end + + assign flush_valid = {NUM_BANKS{state == STATE_FLUSH}}; + +endmodule diff --git a/hw/rtl/cache/VX_cache_init.sv b/hw/rtl/cache/VX_cache_init.sv index 7aa4b3ae4..3cccdcdae 100644 --- a/hw/rtl/cache/VX_cache_init.sv +++ b/hw/rtl/cache/VX_cache_init.sv @@ -13,6 +13,7 @@ `include "VX_cache_define.vh" +// cache flush unit module VX_cache_init #( // Size of cache in bytes parameter CACHE_SIZE = 1024, diff --git a/hw/rtl/cache/VX_cache_mshr.sv b/hw/rtl/cache/VX_cache_mshr.sv index 912bd4d7f..b0e577283 100644 --- a/hw/rtl/cache/VX_cache_mshr.sv +++ b/hw/rtl/cache/VX_cache_mshr.sv @@ -104,7 +104,8 @@ module VX_cache_mshr #( // lookup input wire lookup_valid, input wire [`CS_LINE_ADDR_WIDTH-1:0] lookup_addr, - output wire [MSHR_SIZE-1:0] lookup_matches, + output wire [MSHR_SIZE-1:0] lookup_pending, + output wire [MSHR_SIZE-1:0] lookup_rw, // finalize input wire finalize_valid, @@ -216,13 +217,13 @@ module VX_cache_mshr #( next_table <= next_table_n; end - `RUNTIME_ASSERT((~allocate_fire || ~valid_table[allocate_id_r]), ("%t: *** %s-bank%0d inuse allocation: addr=0x%0h, id=%0d (#%0d)", $time, INSTANCE_ID, BANK_ID, + `RUNTIME_ASSERT((~allocate_fire || ~valid_table[allocate_id_r]), ("%t: *** %s inuse allocation: addr=0x%0h, id=%0d (#%0d)", $time, INSTANCE_ID, `CS_LINE_TO_FULL_ADDR(allocate_addr, BANK_ID), allocate_id_r, lkp_req_uuid)) - `RUNTIME_ASSERT((~finalize_valid || valid_table[finalize_id]), ("%t: *** %s-bank%0d invalid release: addr=0x%0h, id=%0d (#%0d)", $time, INSTANCE_ID, BANK_ID, + `RUNTIME_ASSERT((~finalize_valid || valid_table[finalize_id]), ("%t: *** %s invalid release: addr=0x%0h, id=%0d (#%0d)", $time, INSTANCE_ID, `CS_LINE_TO_FULL_ADDR(addr_table[finalize_id], BANK_ID), finalize_id, fin_req_uuid)) - `RUNTIME_ASSERT((~fill_valid || valid_table[fill_id]), ("%t: *** %s-bank%0d invalid fill: addr=0x%0h, id=%0d", $time, INSTANCE_ID, BANK_ID, + `RUNTIME_ASSERT((~fill_valid || valid_table[fill_id]), ("%t: *** %s invalid fill: addr=0x%0h, id=%0d", $time, INSTANCE_ID, `CS_LINE_TO_FULL_ADDR(addr_table[fill_id], BANK_ID), fill_id)) VX_dp_ram #( @@ -251,7 +252,9 @@ module VX_cache_mshr #( assign dequeue_rw = write_table[dequeue_id_r]; assign dequeue_id = dequeue_id_r; - assign lookup_matches = addr_matches & ~write_table; + // return pending entries for the given cache line + assign lookup_pending = addr_matches; + assign lookup_rw = write_table; `UNUSED_VAR (lookup_valid) @@ -264,22 +267,22 @@ module VX_cache_mshr #( show_table <= allocate_fire || lookup_valid || finalize_valid || fill_valid || dequeue_fire; end if (allocate_fire) - `TRACE(3, ("%d: %s-bank%0d mshr-allocate: addr=0x%0h, prev=%0d, id=%0d (#%0d)\n", $time, INSTANCE_ID, BANK_ID, + `TRACE(3, ("%d: %s allocate: addr=0x%0h, prev=%0d, id=%0d (#%0d)\n", $time, INSTANCE_ID, `CS_LINE_TO_FULL_ADDR(allocate_addr, BANK_ID), allocate_prev, allocate_id, lkp_req_uuid)); if (lookup_valid) - `TRACE(3, ("%d: %s-bank%0d mshr-lookup: addr=0x%0h, matches=%b (#%0d)\n", $time, INSTANCE_ID, BANK_ID, - `CS_LINE_TO_FULL_ADDR(lookup_addr, BANK_ID), lookup_matches, lkp_req_uuid)); + `TRACE(3, ("%d: %s lookup: addr=0x%0h, matches=%b (#%0d)\n", $time, INSTANCE_ID, + `CS_LINE_TO_FULL_ADDR(lookup_addr, BANK_ID), lookup_pending, lkp_req_uuid)); if (finalize_valid) - `TRACE(3, ("%d: %s-bank%0d mshr-finalize release=%b, pending=%b, prev=%0d, id=%0d (#%0d)\n", $time, INSTANCE_ID, BANK_ID, + `TRACE(3, ("%d: %s finalize release=%b, pending=%b, prev=%0d, id=%0d (#%0d)\n", $time, INSTANCE_ID, finalize_release, finalize_pending, finalize_prev, finalize_id, fin_req_uuid)); if (fill_valid) - `TRACE(3, ("%d: %s-bank%0d mshr-fill: addr=0x%0h, addr=0x%0h, id=%0d\n", $time, INSTANCE_ID, BANK_ID, + `TRACE(3, ("%d: %s fill: addr=0x%0h, addr=0x%0h, id=%0d\n", $time, INSTANCE_ID, `CS_LINE_TO_FULL_ADDR(addr_table[fill_id], BANK_ID), `CS_LINE_TO_FULL_ADDR(fill_addr, BANK_ID), fill_id)); if (dequeue_fire) - `TRACE(3, ("%d: %s-bank%0d mshr-dequeue: addr=0x%0h, id=%0d (#%0d)\n", $time, INSTANCE_ID, BANK_ID, + `TRACE(3, ("%d: %s dequeue: addr=0x%0h, id=%0d (#%0d)\n", $time, INSTANCE_ID, `CS_LINE_TO_FULL_ADDR(dequeue_addr, BANK_ID), dequeue_id_r, deq_req_uuid)); if (show_table) begin - `TRACE(3, ("%d: %s-bank%0d mshr-table", $time, INSTANCE_ID, BANK_ID)); + `TRACE(3, ("%d: %s table", $time, INSTANCE_ID)); for (integer i = 0; i < MSHR_SIZE; ++i) begin if (valid_table[i]) begin `TRACE(3, (" %0d=0x%0h", i, `CS_LINE_TO_FULL_ADDR(addr_table[i], BANK_ID))); diff --git a/hw/rtl/cache/VX_cache_tags.sv b/hw/rtl/cache/VX_cache_tags.sv index 274f55136..4595bdbcf 100644 --- a/hw/rtl/cache/VX_cache_tags.sv +++ b/hw/rtl/cache/VX_cache_tags.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -17,15 +17,15 @@ module VX_cache_tags #( parameter `STRING INSTANCE_ID = "", parameter BANK_ID = 0, // Size of cache in bytes - parameter CACHE_SIZE = 1024, + parameter CACHE_SIZE = 1024, // Size of line inside a bank in bytes - parameter LINE_SIZE = 16, + parameter LINE_SIZE = 16, // Number of banks - parameter NUM_BANKS = 1, + parameter NUM_BANKS = 1, // Number of associative ways - parameter NUM_WAYS = 1, + parameter NUM_WAYS = 1, // Size of a word in bytes - parameter WORD_SIZE = 1, + parameter WORD_SIZE = 1, // Request debug identifier parameter UUID_WIDTH = 0 ) ( @@ -38,45 +38,63 @@ module VX_cache_tags #( input wire stall, - // read/fill + // init/fill/lookup + input wire init, + input wire fill, input wire lookup, input wire [`CS_LINE_ADDR_WIDTH-1:0] line_addr, - input wire fill, - input wire init, - output wire [NUM_WAYS-1:0] way_sel, - output wire [NUM_WAYS-1:0] tag_matches + output wire [NUM_WAYS-1:0] tag_matches, + + // replacement + output wire [NUM_WAYS-1:0] repl_way, + output wire [`CS_TAG_SEL_BITS-1:0] repl_tag ); `UNUSED_SPARAM (INSTANCE_ID) `UNUSED_PARAM (BANK_ID) `UNUSED_VAR (reset) `UNUSED_VAR (lookup) + // valid, tag localparam TAG_WIDTH = 1 + `CS_TAG_SEL_BITS; wire [`CS_LINE_SEL_BITS-1:0] line_sel = line_addr[`CS_LINE_SEL_BITS-1:0]; - wire [`CS_TAG_SEL_BITS-1:0] line_tag = `CS_LINE_TAG_ADDR(line_addr); + wire [`CS_TAG_SEL_BITS-1:0] line_tag = `CS_LINE_ADDR_TAG(line_addr); + + wire [NUM_WAYS-1:0][`CS_TAG_SEL_BITS-1:0] read_tag; + wire [NUM_WAYS-1:0] read_valid; if (NUM_WAYS > 1) begin - reg [NUM_WAYS-1:0] repl_way; + reg [NUM_WAYS-1:0] repl_way_r; // cyclic assignment of replacement way always @(posedge clk) begin if (reset) begin - repl_way <= 1; + repl_way_r <= 1; end else if (~stall) begin // hold the value on stalls prevent filling different slots twice - repl_way <= {repl_way[NUM_WAYS-2:0], repl_way[NUM_WAYS-1]}; + repl_way_r <= {repl_way_r[NUM_WAYS-2:0], repl_way_r[NUM_WAYS-1]}; end - end - for (genvar i = 0; i < NUM_WAYS; ++i) begin - assign way_sel[i] = fill && repl_way[i]; end + + assign repl_way = repl_way_r; + + VX_onehot_mux #( + .DATAW (`CS_TAG_SEL_BITS), + .N (NUM_WAYS) + ) repl_tag_sel ( + .data_in (read_tag), + .sel_in (repl_way_r), + .data_out (repl_tag) + ); end else begin `UNUSED_VAR (stall) - assign way_sel = fill; + assign repl_way = 1'b1; + assign repl_tag = read_tag; end for (genvar i = 0; i < NUM_WAYS; ++i) begin - wire [`CS_TAG_SEL_BITS-1:0] read_tag; - wire read_valid; + + wire do_fill = fill && repl_way[i]; + wire do_write = init || do_fill; + wire line_valid = ~init; VX_sp_ram #( .DATAW (TAG_WIDTH), @@ -85,32 +103,34 @@ module VX_cache_tags #( ) tag_store ( .clk (clk), .read (1'b1), - .write (way_sel[i] || init), - `UNUSED_PIN (wren), + .write (do_write), + `UNUSED_PIN (wren), .addr (line_sel), - .wdata ({~init, line_tag}), - .rdata ({read_valid, read_tag}) + .wdata ({line_valid, line_tag}), + .rdata ({read_valid[i], read_tag[i]}) ); - - assign tag_matches[i] = read_valid && (line_tag == read_tag); end - + + for (genvar i = 0; i < NUM_WAYS; ++i) begin + assign tag_matches[i] = read_valid[i] && (line_tag == read_tag[i]); + end + `ifdef DBG_TRACE_CACHE always @(posedge clk) begin if (fill && ~stall) begin - `TRACE(3, ("%d: %s-bank%0d tag-fill: addr=0x%0h, way=%b, blk_addr=%0d, tag_id=0x%0h\n", $time, INSTANCE_ID, BANK_ID, `CS_LINE_TO_FULL_ADDR(line_addr, BANK_ID), way_sel, line_sel, line_tag)); + `TRACE(3, ("%d: %s fill: addr=0x%0h, way=%b, blk_addr=%0d, tag_id=0x%0h\n", $time, INSTANCE_ID, `CS_LINE_TO_FULL_ADDR(line_addr, BANK_ID), repl_way, line_sel, line_tag)); end if (init) begin - `TRACE(3, ("%d: %s-bank%0d tag-init: addr=0x%0h, blk_addr=%0d\n", $time, INSTANCE_ID, BANK_ID, `CS_LINE_TO_FULL_ADDR(line_addr, BANK_ID), line_sel)); + `TRACE(3, ("%d: %s init: addr=0x%0h, blk_addr=%0d\n", $time, INSTANCE_ID, `CS_LINE_TO_FULL_ADDR(line_addr, BANK_ID), line_sel)); end if (lookup && ~stall) begin if (tag_matches != 0) begin - `TRACE(3, ("%d: %s-bank%0d tag-hit: addr=0x%0h, way=%b, blk_addr=%0d, tag_id=0x%0h (#%0d)\n", $time, INSTANCE_ID, BANK_ID, `CS_LINE_TO_FULL_ADDR(line_addr, BANK_ID), way_sel, line_sel, line_tag, req_uuid)); + `TRACE(3, ("%d: %s hit: addr=0x%0h, way=%b, blk_addr=%0d, tag_id=0x%0h (#%0d)\n", $time, INSTANCE_ID, `CS_LINE_TO_FULL_ADDR(line_addr, BANK_ID), tag_matches, line_sel, line_tag, req_uuid)); end else begin - `TRACE(3, ("%d: %s-bank%0d tag-miss: addr=0x%0h, blk_addr=%0d, tag_id=0x%0h, (#%0d)\n", $time, INSTANCE_ID, BANK_ID, `CS_LINE_TO_FULL_ADDR(line_addr, BANK_ID), line_sel, line_tag, req_uuid)); + `TRACE(3, ("%d: %s miss: addr=0x%0h, blk_addr=%0d, tag_id=0x%0h, (#%0d)\n", $time, INSTANCE_ID, `CS_LINE_TO_FULL_ADDR(line_addr, BANK_ID), line_sel, line_tag, req_uuid)); end - end - end + end + end `endif endmodule diff --git a/hw/rtl/cache/VX_cache_wrap.sv b/hw/rtl/cache/VX_cache_wrap.sv index 019a213a1..082d8b4e1 100644 --- a/hw/rtl/cache/VX_cache_wrap.sv +++ b/hw/rtl/cache/VX_cache_wrap.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -23,20 +23,20 @@ module VX_cache_wrap import VX_gpu_pkg::*; #( // Size of cache in bytes - parameter CACHE_SIZE = 4096, + parameter CACHE_SIZE = 4096, // Size of line inside a bank in bytes - parameter LINE_SIZE = 64, + parameter LINE_SIZE = 64, // Number of banks parameter NUM_BANKS = 1, // Number of associative ways parameter NUM_WAYS = 1, // Size of a word in bytes - parameter WORD_SIZE = 4, + parameter WORD_SIZE = 4, // Core Response Queue Size parameter CRSQ_SIZE = 2, // Miss Reserv Queue Knob - parameter MSHR_SIZE = 8, + parameter MSHR_SIZE = 8, // Memory Response Queue Size parameter MRSQ_SIZE = 0, // Memory Request Queue Size @@ -45,6 +45,9 @@ module VX_cache_wrap import VX_gpu_pkg::*; #( // Enable cache writeable parameter WRITE_ENABLE = 1, + // Enable cache writeback + parameter WRITEBACK = 0, + // Request debug identifier parameter UUID_WIDTH = 0, @@ -63,7 +66,7 @@ module VX_cache_wrap import VX_gpu_pkg::*; #( // Memory request output buffer parameter MEM_OUT_BUF = 0 ) ( - + input wire clk, input wire reset, @@ -80,7 +83,7 @@ module VX_cache_wrap import VX_gpu_pkg::*; #( localparam MSHR_ADDR_WIDTH = `LOG2UP(MSHR_SIZE); localparam CACHE_MEM_TAG_WIDTH = MSHR_ADDR_WIDTH + `CS_BANK_SEL_BITS; - + localparam MEM_TAG_WIDTH = PASSTHRU ? `CACHE_BYPASS_TAG_WIDTH(NUM_REQS, LINE_SIZE, WORD_SIZE, TAG_WIDTH) : (NC_ENABLE ? `CACHE_NC_MEM_TAG_WIDTH(MSHR_SIZE, NUM_BANKS, NUM_REQS, LINE_SIZE, WORD_SIZE, TAG_WIDTH) : `CACHE_MEM_TAG_WIDTH(MSHR_SIZE, NUM_BANKS)); @@ -98,7 +101,7 @@ module VX_cache_wrap import VX_gpu_pkg::*; #( ) mem_bus_cache_if(); if (NC_OR_BYPASS) begin - + `RESET_RELAY (nc_bypass_reset, reset); VX_cache_bypass #( @@ -108,13 +111,13 @@ module VX_cache_wrap import VX_gpu_pkg::*; #( .PASSTHRU (PASSTHRU), .NC_ENABLE (PASSTHRU ? 0 : NC_ENABLE), - .WORD_SIZE (WORD_SIZE), + .WORD_SIZE (WORD_SIZE), .LINE_SIZE (LINE_SIZE), - .CORE_ADDR_WIDTH (`CS_WORD_ADDR_WIDTH), + .CORE_ADDR_WIDTH (`CS_WORD_ADDR_WIDTH), .CORE_TAG_WIDTH (TAG_WIDTH), - - .MEM_ADDR_WIDTH (`CS_MEM_ADDR_WIDTH), + + .MEM_ADDR_WIDTH (`CS_MEM_ADDR_WIDTH), .MEM_TAG_IN_WIDTH (CACHE_MEM_TAG_WIDTH), .MEM_TAG_OUT_WIDTH (MEM_TAG_WIDTH), @@ -132,15 +135,15 @@ module VX_cache_wrap import VX_gpu_pkg::*; #( .mem_bus_in_if (mem_bus_cache_if), .mem_bus_out_if (mem_bus_if) ); - + end else begin for (genvar i = 0; i < NUM_REQS; ++i) begin - `ASSIGN_VX_MEM_BUS_IF (core_bus_cache_if[i], core_bus_if[i]); + `ASSIGN_VX_MEM_BUS_IF (core_bus_cache_if[i], core_bus_if[i]); end `ASSIGN_VX_MEM_BUS_IF (mem_bus_if, mem_bus_cache_if); - end + end if (PASSTHRU != 0) begin @@ -152,7 +155,7 @@ module VX_cache_wrap import VX_gpu_pkg::*; #( assign core_bus_cache_if[i].rsp_valid = 0; assign core_bus_cache_if[i].rsp_data = '0; `UNUSED_VAR (core_bus_cache_if[i].rsp_ready) - end + end assign mem_bus_cache_if.req_valid = 0; assign mem_bus_cache_if.req_data = '0; @@ -183,6 +186,7 @@ module VX_cache_wrap import VX_gpu_pkg::*; #( .MRSQ_SIZE (MRSQ_SIZE), .MREQ_SIZE (MREQ_SIZE), .WRITE_ENABLE (WRITE_ENABLE), + .WRITEBACK (WRITEBACK), .UUID_WIDTH (UUID_WIDTH), .TAG_WIDTH (TAG_WIDTH), .CORE_OUT_BUF (NC_OR_BYPASS ? 1 : CORE_OUT_BUF), @@ -195,8 +199,8 @@ module VX_cache_wrap import VX_gpu_pkg::*; #( `endif .core_bus_if (core_bus_cache_if), .mem_bus_if (mem_bus_cache_if) - ); - + ); + end `ifdef DBG_TRACE_CACHE @@ -225,9 +229,9 @@ module VX_cache_wrap import VX_gpu_pkg::*; #( end if (core_rsp_fire) begin `TRACE(1, ("%d: %s core-rd-rsp: tag=0x%0h, req_idx=%0d, data=0x%0h (#%0d)\n", $time, INSTANCE_ID, core_bus_if[i].rsp_data.tag, i, core_bus_if[i].rsp_data.data, core_rsp_uuid)); - end + end end - end + end wire [`UP(UUID_WIDTH)-1:0] mem_req_uuid; wire [`UP(UUID_WIDTH)-1:0] mem_rsp_uuid; @@ -246,17 +250,17 @@ module VX_cache_wrap import VX_gpu_pkg::*; #( always @(posedge clk) begin if (mem_req_fire) begin if (mem_bus_if.req_data.rw) - `TRACE(1, ("%d: %s mem-wr-req: addr=0x%0h, tag=0x%0h, byteen=%b, data=0x%0h (#%0d)\n", + `TRACE(1, ("%d: %s mem-wr-req: addr=0x%0h, tag=0x%0h, byteen=%b, data=0x%0h (#%0d)\n", $time, INSTANCE_ID, `TO_FULL_ADDR(mem_bus_if.req_data.addr), mem_bus_if.req_data.tag, mem_bus_if.req_data.byteen, mem_bus_if.req_data.data, mem_req_uuid)); else - `TRACE(1, ("%d: %s mem-rd-req: addr=0x%0h, tag=0x%0h (#%0d)\n", + `TRACE(1, ("%d: %s mem-rd-req: addr=0x%0h, tag=0x%0h (#%0d)\n", $time, INSTANCE_ID, `TO_FULL_ADDR(mem_bus_if.req_data.addr), mem_bus_if.req_data.tag, mem_req_uuid)); end if (mem_rsp_fire) begin - `TRACE(1, ("%d: %s mem-rd-rsp: tag=0x%0h, data=0x%0h (#%0d)\n", + `TRACE(1, ("%d: %s mem-rd-rsp: tag=0x%0h, data=0x%0h (#%0d)\n", $time, INSTANCE_ID, mem_bus_if.rsp_data.tag, mem_bus_if.rsp_data.data, mem_rsp_uuid)); end - end + end `endif endmodule diff --git a/hw/rtl/core/VX_alu_int.sv b/hw/rtl/core/VX_alu_int.sv index d84ff0a07..47bfcc6bf 100644 --- a/hw/rtl/core/VX_alu_int.sv +++ b/hw/rtl/core/VX_alu_int.sv @@ -14,7 +14,7 @@ `include "VX_define.vh" module VX_alu_int #( - parameter CORE_ID = 0, + parameter `STRING INSTANCE_ID = "", parameter BLOCK_IDX = 0, parameter NUM_LANES = 1 ) ( @@ -29,7 +29,7 @@ module VX_alu_int #( VX_branch_ctl_if.master branch_ctl_if ); - `UNUSED_PARAM (CORE_ID) + `UNUSED_SPARAM (INSTANCE_ID) localparam LANE_BITS = `CLOG2(NUM_LANES); localparam LANE_WIDTH = `UP(LANE_BITS); localparam PID_BITS = `CLOG2(`NUM_THREADS / NUM_LANES); @@ -121,7 +121,7 @@ module VX_alu_int #( case ({is_alu_w, op_class}) 3'b000: alu_result[i] = add_result[i]; // ADD, LUI, AUIPC 3'b001: alu_result[i] = sub_slt_br_result; // SUB, SLTU, SLTI, BR* - 3'b010: alu_result[i] = shr_zic_result[i]; // SRL, SRA, SRLI, SRAI, CZERO* + 3'b010: alu_result[i] = shr_zic_result[i]; // SRL, SRA, SRLI, SRAI, CZERO* 3'b011: alu_result[i] = msc_result[i]; // AND, OR, XOR, SLL, SLLI 3'b100: alu_result[i] = add_result_w[i]; // ADDIW, ADDW 3'b101: alu_result[i] = sub_result_w[i]; // SUBW @@ -181,7 +181,7 @@ module VX_alu_int #( .clk (clk), .reset (reset), .enable (1'b1), - .data_in ({br_enable, br_wid, br_taken, br_dest}), + .data_in ({br_enable, br_wid, br_taken, br_dest}), .data_out ({branch_ctl_if.valid, branch_ctl_if.wid, branch_ctl_if.taken, branch_ctl_if.dest}) ); @@ -193,9 +193,9 @@ module VX_alu_int #( `ifdef DBG_TRACE_PIPELINE always @(posedge clk) begin - if (branch_ctl_if.valid) begin - `TRACE(1, ("%d: core%0d-branch: wid=%0d, PC=0x%0h, taken=%b, dest=0x%0h (#%0d)\n", - $time, CORE_ID, branch_ctl_if.wid, {commit_if.data.PC, 1'b0}, branch_ctl_if.taken, {branch_ctl_if.dest, 1'b0}, commit_if.data.uuid)); + if (br_enable) begin + `TRACE(1, ("%d: %s-branch: wid=%0d, PC=0x%0h, taken=%b, dest=0x%0h (#%0d)\n", + $time, INSTANCE_ID, br_wid, {commit_if.data.PC, 1'b0}, br_taken, {br_dest, 1'b0}, commit_if.data.uuid)); end end `endif diff --git a/hw/rtl/core/VX_alu_muldiv.sv b/hw/rtl/core/VX_alu_muldiv.sv index 492625874..460295463 100644 --- a/hw/rtl/core/VX_alu_muldiv.sv +++ b/hw/rtl/core/VX_alu_muldiv.sv @@ -14,7 +14,7 @@ `include "VX_define.vh" module VX_alu_muldiv #( - parameter CORE_ID = 0, + parameter `STRING INSTANCE_ID = "", parameter NUM_LANES = 1 ) ( input wire clk, @@ -26,7 +26,7 @@ module VX_alu_muldiv #( // Outputs VX_commit_if.master commit_if ); - `UNUSED_PARAM (CORE_ID) + `UNUSED_SPARAM (INSTANCE_ID) localparam PID_BITS = `CLOG2(`NUM_THREADS / NUM_LANES); localparam PID_WIDTH = `UP(PID_BITS); localparam TAG_WIDTH = `UUID_WIDTH + `NW_WIDTH + NUM_LANES + `PC_BITS + `NR_BITS + 1 + PID_WIDTH + 1 + 1; @@ -69,7 +69,7 @@ module VX_alu_muldiv #( wire mul_fire_in = mul_valid_in && mul_ready_in; for (genvar i = 0; i < NUM_LANES; ++i) begin - wire [`XLEN-1:0] mul_resultl, mul_resulth; + reg [`XLEN-1:0] mul_resultl, mul_resulth; wire [`XLEN-1:0] mul_in1 = is_alu_w ? (execute_if.data.rs1_data[i] & `XLEN'hFFFFFFFF) : execute_if.data.rs1_data[i]; wire [`XLEN-1:0] mul_in2 = is_alu_w ? (execute_if.data.rs2_data[i] & `XLEN'hFFFFFFFF) : execute_if.data.rs2_data[i]; always @(*) begin @@ -235,7 +235,7 @@ module VX_alu_muldiv #( wire div_fire_in = div_valid_in && div_ready_in; for (genvar i = 0; i < NUM_LANES; ++i) begin - wire [`XLEN-1:0] div_quotient, div_remainder; + reg [`XLEN-1:0] div_quotient, div_remainder; always @(*) begin dpi_idiv (div_fire_in, is_signed_op, div_in1[i], div_in2[i], div_quotient, div_remainder); end diff --git a/hw/rtl/core/VX_alu_unit.sv b/hw/rtl/core/VX_alu_unit.sv index f3e0a39b2..d8c131838 100644 --- a/hw/rtl/core/VX_alu_unit.sv +++ b/hw/rtl/core/VX_alu_unit.sv @@ -14,7 +14,7 @@ `include "VX_define.vh" module VX_alu_unit #( - parameter CORE_ID = 0 + parameter `STRING INSTANCE_ID = "" ) ( input wire clk, input wire reset, @@ -27,7 +27,7 @@ module VX_alu_unit #( VX_branch_ctl_if.master branch_ctl_if [`NUM_ALU_BLOCKS] ); - `UNUSED_PARAM (CORE_ID) + `UNUSED_SPARAM (INSTANCE_ID) localparam BLOCK_SIZE = `NUM_ALU_BLOCKS; localparam NUM_LANES = `NUM_ALU_LANES; localparam PID_BITS = `CLOG2(`NUM_THREADS / NUM_LANES); @@ -75,7 +75,7 @@ module VX_alu_unit #( `RESET_RELAY (int_reset, block_reset); VX_alu_int #( - .CORE_ID (CORE_ID), + .INSTANCE_ID ($sformatf("%s-int%0d", INSTANCE_ID, block_idx)), .BLOCK_IDX (block_idx), .NUM_LANES (NUM_LANES) ) alu_int ( @@ -90,59 +90,61 @@ module VX_alu_unit #( VX_execute_if #( .NUM_LANES (NUM_LANES) - ) mdv_execute_if(); + ) muldiv_execute_if(); VX_commit_if #( .NUM_LANES (NUM_LANES) - ) mdv_commit_if(); + ) muldiv_commit_if(); - assign mdv_execute_if.valid = per_block_execute_if[block_idx].valid && is_muldiv_op; - assign mdv_execute_if.data = per_block_execute_if[block_idx].data; + assign muldiv_execute_if.valid = per_block_execute_if[block_idx].valid && is_muldiv_op; + assign muldiv_execute_if.data = per_block_execute_if[block_idx].data; - `RESET_RELAY (mdv_reset, block_reset); + `RESET_RELAY (muldiv_reset, block_reset); VX_alu_muldiv #( - .CORE_ID (CORE_ID), + .INSTANCE_ID ($sformatf("%s-muldiv%0d", INSTANCE_ID, block_idx)), .NUM_LANES (NUM_LANES) - ) mdv_unit ( + ) muldiv_unit ( .clk (clk), - .reset (mdv_reset), - .execute_if (mdv_execute_if), - .commit_if (mdv_commit_if) + .reset (muldiv_reset), + .execute_if (muldiv_execute_if), + .commit_if (muldiv_commit_if) ); `endif assign per_block_execute_if[block_idx].ready = `ifdef EXT_M_ENABLE - is_muldiv_op ? mdv_execute_if.ready : + is_muldiv_op ? muldiv_execute_if.ready : `endif int_execute_if.ready; // send response + `RESET_RELAY (arb_reset, block_reset); + VX_stream_arb #( .NUM_INPUTS (RSP_ARB_SIZE), .DATAW (RSP_ARB_DATAW), .OUT_BUF (PARTIAL_BW ? 1 : 3) ) rsp_arb ( .clk (clk), - .reset (block_reset), + .reset (arb_reset), .valid_in ({ `ifdef EXT_M_ENABLE - mdv_commit_if.valid, + muldiv_commit_if.valid, `endif int_commit_if.valid }), .ready_in ({ `ifdef EXT_M_ENABLE - mdv_commit_if.ready, + muldiv_commit_if.ready, `endif int_commit_if.ready }), .data_in ({ `ifdef EXT_M_ENABLE - mdv_commit_if.data, + muldiv_commit_if.data, `endif int_commit_if.data }), diff --git a/hw/rtl/core/VX_commit.sv b/hw/rtl/core/VX_commit.sv index 3726622aa..d78c2ec89 100644 --- a/hw/rtl/core/VX_commit.sv +++ b/hw/rtl/core/VX_commit.sv @@ -13,8 +13,8 @@ `include "VX_define.vh" -module VX_commit import VX_gpu_pkg::*; #( - parameter CORE_ID = 0 +module VX_commit import VX_gpu_pkg::*, VX_trace_pkg::*; #( + parameter `STRING INSTANCE_ID = "" ) ( input wire clk, input wire reset, @@ -27,7 +27,7 @@ module VX_commit import VX_gpu_pkg::*; #( VX_commit_csr_if.master commit_csr_if, VX_commit_sched_if.master commit_sched_if ); - `UNUSED_PARAM (CORE_ID) + `UNUSED_SPARAM (INSTANCE_ID) localparam DATAW = `UUID_WIDTH + `NW_WIDTH + `NUM_THREADS + `PC_BITS + 1 + `NR_BITS + `NUM_THREADS * `XLEN + 1 + 1 + 1; localparam COMMIT_SIZEW = `CLOG2(`NUM_THREADS + 1); localparam COMMIT_ALL_SIZEW = COMMIT_SIZEW + `ISSUE_WIDTH - 1; @@ -36,12 +36,10 @@ module VX_commit import VX_gpu_pkg::*; #( VX_commit_if commit_arb_if[`ISSUE_WIDTH](); - wire [`ISSUE_WIDTH-1:0] commit_fire; - wire [`ISSUE_WIDTH-1:0][`NW_WIDTH-1:0] commit_wid; - wire [`ISSUE_WIDTH-1:0][`NUM_THREADS-1:0] commit_tmask; - wire [`ISSUE_WIDTH-1:0] commit_eop; - - `RESET_RELAY (arb_reset, reset); + wire [`ISSUE_WIDTH-1:0] per_issue_commit_fire; + wire [`ISSUE_WIDTH-1:0][`NW_WIDTH-1:0] per_issue_commit_wid; + wire [`ISSUE_WIDTH-1:0][`NUM_THREADS-1:0] per_issue_commit_tmask; + wire [`ISSUE_WIDTH-1:0] per_issue_commit_eop; for (genvar i = 0; i < `ISSUE_WIDTH; ++i) begin @@ -55,6 +53,8 @@ module VX_commit import VX_gpu_pkg::*; #( assign commit_if[j * `ISSUE_WIDTH + i].ready = ready_in[j]; end + `RESET_RELAY (arb_reset, reset); + VX_stream_arb #( .NUM_INPUTS (`NUM_EX_UNITS), .DATAW (DATAW), @@ -72,10 +72,10 @@ module VX_commit import VX_gpu_pkg::*; #( `UNUSED_PIN (sel_out) ); - assign commit_fire[i] = commit_arb_if[i].valid && commit_arb_if[i].ready; - assign commit_tmask[i]= {`NUM_THREADS{commit_fire[i]}} & commit_arb_if[i].data.tmask; - assign commit_wid[i] = commit_arb_if[i].data.wid; - assign commit_eop[i] = commit_arb_if[i].data.eop; + assign per_issue_commit_fire[i] = commit_arb_if[i].valid && commit_arb_if[i].ready; + assign per_issue_commit_tmask[i]= {`NUM_THREADS{per_issue_commit_fire[i]}} & commit_arb_if[i].data.tmask; + assign per_issue_commit_wid[i] = commit_arb_if[i].data.wid; + assign per_issue_commit_eop[i] = commit_arb_if[i].data.eop; end // CSRs update @@ -84,11 +84,11 @@ module VX_commit import VX_gpu_pkg::*; #( wire [COMMIT_ALL_SIZEW-1:0] commit_size_all_r, commit_size_all_rr; wire commit_fire_any, commit_fire_any_r, commit_fire_any_rr; - assign commit_fire_any = (| commit_fire); + assign commit_fire_any = (| per_issue_commit_fire); for (genvar i = 0; i < `ISSUE_WIDTH; ++i) begin wire [COMMIT_SIZEW-1:0] count; - `POP_COUNT(count, commit_tmask[i]); + `POP_COUNT(count, per_issue_commit_tmask[i]); assign commit_size[i] = count; end @@ -136,19 +136,28 @@ module VX_commit import VX_gpu_pkg::*; #( end assign commit_csr_if.instret = instret; - // Committed instructions + // Track committed instructions - wire [`ISSUE_WIDTH-1:0] committed = commit_fire & commit_eop; + reg [`NUM_WARPS-1:0] committed_warps; + + always @(*) begin + committed_warps = 0; + for (integer i = 0; i < `ISSUE_WIDTH; ++i) begin + if (per_issue_commit_fire[i] && per_issue_commit_eop[i]) begin + committed_warps[per_issue_commit_wid[i]] = 1; + end + end + end VX_pipe_register #( - .DATAW (`ISSUE_WIDTH * (1 + `NW_WIDTH)), - .RESETW (`ISSUE_WIDTH) + .DATAW (`NUM_WARPS), + .RESETW (`NUM_WARPS) ) committed_pipe_reg ( .clk (clk), .reset (reset), .enable (1'b1), - .data_in ({committed, commit_wid}), - .data_out ({commit_sched_if.committed, commit_sched_if.committed_wid}) + .data_in (committed_warps), + .data_out ({commit_sched_if.committed_warps}) ); // Writeback @@ -171,7 +180,7 @@ module VX_commit import VX_gpu_pkg::*; #( for (genvar j = 0; j < `NUM_EX_UNITS; ++j) begin always @(posedge clk) begin if (commit_if[j * `ISSUE_WIDTH + i].valid && commit_if[j * `ISSUE_WIDTH + i].ready) begin - `TRACE(1, ("%d: core%0d-commit: wid=%0d, PC=0x%0h, ex=", $time, CORE_ID, commit_if[j * `ISSUE_WIDTH + i].data.wid, {commit_if[j * `ISSUE_WIDTH + i].data.PC, 1'b0})); + `TRACE(1, ("%d: %s: wid=%0d, PC=0x%0h, ex=", $time, INSTANCE_ID, commit_if[j * `ISSUE_WIDTH + i].data.wid, {commit_if[j * `ISSUE_WIDTH + i].data.PC, 1'b0})); trace_ex_type(1, j); `TRACE(1, (", tmask=%b, wb=%0d, rd=%0d, sop=%b, eop=%b, data=", commit_if[j * `ISSUE_WIDTH + i].data.tmask, commit_if[j * `ISSUE_WIDTH + i].data.wb, commit_if[j * `ISSUE_WIDTH + i].data.rd, commit_if[j * `ISSUE_WIDTH + i].data.sop, commit_if[j * `ISSUE_WIDTH + i].data.eop)); `TRACE_ARRAY1D(1, "0x%0h", commit_if[j * `ISSUE_WIDTH + i].data.data, `NUM_THREADS); diff --git a/hw/rtl/core/VX_core.sv b/hw/rtl/core/VX_core.sv index c923e2ef0..090f47199 100644 --- a/hw/rtl/core/VX_core.sv +++ b/hw/rtl/core/VX_core.sv @@ -18,7 +18,8 @@ `endif module VX_core import VX_gpu_pkg::*; #( - parameter CORE_ID = 0 + parameter CORE_ID = 0, + parameter `STRING INSTANCE_ID = "" ) ( `SCOPE_IO_DECL @@ -94,13 +95,14 @@ module VX_core import VX_gpu_pkg::*; #( `SCOPE_IO_SWITCH (3) VX_schedule #( + .INSTANCE_ID ($sformatf("%s-schedule", INSTANCE_ID)), .CORE_ID (CORE_ID) ) schedule ( .clk (clk), .reset (schedule_reset), `ifdef PERF_ENABLE - .perf_schedule_if (pipeline_perf_if.schedule), + .sched_perf (pipeline_perf_if.sched), `endif .base_dcrs (base_dcrs), @@ -121,7 +123,7 @@ module VX_core import VX_gpu_pkg::*; #( ); VX_fetch #( - .CORE_ID (CORE_ID) + .INSTANCE_ID ($sformatf("%s-fetch", INSTANCE_ID)) ) fetch ( `SCOPE_IO_BIND (0) .clk (clk), @@ -132,7 +134,7 @@ module VX_core import VX_gpu_pkg::*; #( ); VX_decode #( - .CORE_ID (CORE_ID) + .INSTANCE_ID ($sformatf("%s-decode", INSTANCE_ID)) ) decode ( .clk (clk), .reset (decode_reset), @@ -142,7 +144,7 @@ module VX_core import VX_gpu_pkg::*; #( ); VX_issue #( - .CORE_ID (CORE_ID) + .INSTANCE_ID ($sformatf("%s-issue", INSTANCE_ID)) ) issue ( `SCOPE_IO_BIND (1) @@ -150,7 +152,7 @@ module VX_core import VX_gpu_pkg::*; #( .reset (issue_reset), `ifdef PERF_ENABLE - .perf_issue_if (pipeline_perf_if.issue), + .issue_perf (pipeline_perf_if.issue), `endif .decode_if (decode_if), @@ -159,6 +161,7 @@ module VX_core import VX_gpu_pkg::*; #( ); VX_execute #( + .INSTANCE_ID ($sformatf("%s-execute", INSTANCE_ID)), .CORE_ID (CORE_ID) ) execute ( `SCOPE_IO_BIND (2) @@ -186,7 +189,7 @@ module VX_core import VX_gpu_pkg::*; #( ); VX_commit #( - .CORE_ID (CORE_ID) + .INSTANCE_ID ($sformatf("%s-commit", INSTANCE_ID)) ) commit ( .clk (clk), .reset (commit_reset), @@ -210,7 +213,7 @@ module VX_core import VX_gpu_pkg::*; #( `RESET_RELAY (lmem_unit_reset, reset); VX_lmem_unit #( - .CORE_ID (CORE_ID) + .INSTANCE_ID (INSTANCE_ID) ) lmem_unit ( .clk (clk), .reset (lmem_unit_reset), @@ -229,20 +232,20 @@ module VX_core import VX_gpu_pkg::*; #( `endif - VX_lsu_mem_if #( - .NUM_LANES (DCACHE_CHANNELS), - .DATA_SIZE (DCACHE_WORD_SIZE), - .TAG_WIDTH (DCACHE_TAG_WIDTH) - ) dcache_coalesced_if[`NUM_LSU_BLOCKS](); + for (genvar i = 0; i < `NUM_LSU_BLOCKS; ++i) begin - if (LSU_WORD_SIZE != DCACHE_WORD_SIZE) begin + VX_lsu_mem_if #( + .NUM_LANES (DCACHE_CHANNELS), + .DATA_SIZE (DCACHE_WORD_SIZE), + .TAG_WIDTH (DCACHE_TAG_WIDTH) + ) dcache_coalesced_if(); - `RESET_RELAY (coalescer_reset, reset); + if (LSU_WORD_SIZE != DCACHE_WORD_SIZE) begin - for (genvar i = 0; i < `NUM_LSU_BLOCKS; ++i) begin + `RESET_RELAY (mem_coalescer_reset, reset); VX_mem_coalescer #( - .INSTANCE_ID ($sformatf("core%0d-coalescer", CORE_ID)), + .INSTANCE_ID ($sformatf("%s-coalescer%0d", INSTANCE_ID, i)), .NUM_REQS (`NUM_LSU_LANES), .DATA_IN_SIZE (LSU_WORD_SIZE), .DATA_OUT_SIZE (DCACHE_WORD_SIZE), @@ -251,9 +254,9 @@ module VX_core import VX_gpu_pkg::*; #( .TAG_WIDTH (LSU_TAG_WIDTH), .UUID_WIDTH (`UUID_WIDTH), .QUEUE_SIZE (`LSUQ_OUT_SIZE) - ) coalescer ( + ) mem_coalescer ( .clk (clk), - .reset (coalescer_reset), + .reset (mem_coalescer_reset), // Input request .in_req_valid (lsu_dcache_if[i].req_valid), @@ -274,42 +277,37 @@ module VX_core import VX_gpu_pkg::*; #( .in_rsp_ready (lsu_dcache_if[i].rsp_ready), // Output request - .out_req_valid (dcache_coalesced_if[i].req_valid), - .out_req_mask (dcache_coalesced_if[i].req_data.mask), - .out_req_rw (dcache_coalesced_if[i].req_data.rw), - .out_req_byteen (dcache_coalesced_if[i].req_data.byteen), - .out_req_addr (dcache_coalesced_if[i].req_data.addr), - .out_req_atype (dcache_coalesced_if[i].req_data.atype), - .out_req_data (dcache_coalesced_if[i].req_data.data), - .out_req_tag (dcache_coalesced_if[i].req_data.tag), - .out_req_ready (dcache_coalesced_if[i].req_ready), + .out_req_valid (dcache_coalesced_if.req_valid), + .out_req_mask (dcache_coalesced_if.req_data.mask), + .out_req_rw (dcache_coalesced_if.req_data.rw), + .out_req_byteen (dcache_coalesced_if.req_data.byteen), + .out_req_addr (dcache_coalesced_if.req_data.addr), + .out_req_atype (dcache_coalesced_if.req_data.atype), + .out_req_data (dcache_coalesced_if.req_data.data), + .out_req_tag (dcache_coalesced_if.req_data.tag), + .out_req_ready (dcache_coalesced_if.req_ready), // Output response - .out_rsp_valid (dcache_coalesced_if[i].rsp_valid), - .out_rsp_mask (dcache_coalesced_if[i].rsp_data.mask), - .out_rsp_data (dcache_coalesced_if[i].rsp_data.data), - .out_rsp_tag (dcache_coalesced_if[i].rsp_data.tag), - .out_rsp_ready (dcache_coalesced_if[i].rsp_ready) + .out_rsp_valid (dcache_coalesced_if.rsp_valid), + .out_rsp_mask (dcache_coalesced_if.rsp_data.mask), + .out_rsp_data (dcache_coalesced_if.rsp_data.data), + .out_rsp_tag (dcache_coalesced_if.rsp_data.tag), + .out_rsp_ready (dcache_coalesced_if.rsp_ready) ); + + end else begin + + `ASSIGN_VX_LSU_MEM_IF (dcache_coalesced_if, lsu_dcache_if[i]); + end - end else begin - - for (genvar i = 0; i < `NUM_LSU_BLOCKS; ++i) begin - `ASSIGN_VX_LSU_MEM_IF (dcache_coalesced_if[i], lsu_dcache_if[i]); - end - - end - - `RESET_RELAY (lsu_adapter_reset, reset); - - for (genvar i = 0; i < `NUM_LSU_BLOCKS; ++i) begin - VX_mem_bus_if #( .DATA_SIZE (DCACHE_WORD_SIZE), .TAG_WIDTH (DCACHE_TAG_WIDTH) ) dcache_bus_tmp_if[DCACHE_CHANNELS](); + `RESET_RELAY (lsu_adapter_reset, reset); + VX_lsu_adapter #( .NUM_LANES (DCACHE_CHANNELS), .DATA_SIZE (DCACHE_WORD_SIZE), @@ -320,15 +318,17 @@ module VX_core import VX_gpu_pkg::*; #( ) lsu_adapter ( .clk (clk), .reset (lsu_adapter_reset), - .lsu_mem_if (dcache_coalesced_if[i]), + .lsu_mem_if (dcache_coalesced_if), .mem_bus_if (dcache_bus_tmp_if) ); for (genvar j = 0; j < DCACHE_CHANNELS; ++j) begin `ASSIGN_VX_MEM_BUS_IF (dcache_bus_if[i * DCACHE_CHANNELS + j], dcache_bus_tmp_if[j]); end + end + `ifdef PERF_ENABLE wire [`CLOG2(LSU_NUM_REQS+1)-1:0] perf_dcache_rd_req_per_cycle; diff --git a/hw/rtl/core/VX_core_top.sv b/hw/rtl/core/VX_core_top.sv index db6485564..420ae7b67 100644 --- a/hw/rtl/core/VX_core_top.sv +++ b/hw/rtl/core/VX_core_top.sv @@ -144,6 +144,7 @@ module VX_core_top import VX_gpu_pkg::*; #( `endif VX_core #( + .INSTANCE_ID ($sformatf("core")), .CORE_ID (CORE_ID) ) core ( `SCOPE_IO_BIND (0) diff --git a/hw/rtl/core/VX_csr_data.sv b/hw/rtl/core/VX_csr_data.sv index 7f781cbf5..a2b0741ad 100644 --- a/hw/rtl/core/VX_csr_data.sv +++ b/hw/rtl/core/VX_csr_data.sv @@ -26,13 +26,13 @@ addr+12'h80 : dst = 32'(src[$bits(src)-1:32]) `endif - module VX_csr_data import VX_gpu_pkg::*; `ifdef EXT_F_ENABLE import VX_fpu_pkg::*; `endif #( + parameter `STRING INSTANCE_ID = "", parameter CORE_ID = 0 ) ( input wire clk, @@ -147,7 +147,7 @@ import VX_fpu_pkg::*; mscratch <= write_data; end default: begin - `ASSERT(0, ("%t: *** invalid CSR write address: %0h (#%0d)", $time, write_addr, write_uuid)); + `ASSERT(0, ("%t: *** %s invalid CSR write address: %0h (#%0d)", $time, INSTANCE_ID, write_addr, write_uuid)); end endcase end @@ -212,21 +212,21 @@ import VX_fpu_pkg::*; `VX_DCR_MPM_CLASS_CORE: begin case (read_addr) // PERF: pipeline - `CSR_READ_64(`VX_CSR_MPM_SCHED_ID, read_data_ro_r, pipeline_perf_if.sched_idles); - `CSR_READ_64(`VX_CSR_MPM_SCHED_ST, read_data_ro_r, pipeline_perf_if.sched_stalls); - `CSR_READ_64(`VX_CSR_MPM_IBUF_ST, read_data_ro_r, pipeline_perf_if.ibf_stalls); - `CSR_READ_64(`VX_CSR_MPM_SCRB_ST, read_data_ro_r, pipeline_perf_if.scb_stalls); - `CSR_READ_64(`VX_CSR_MPM_SCRB_ALU, read_data_ro_r, pipeline_perf_if.units_uses[`EX_ALU]); + `CSR_READ_64(`VX_CSR_MPM_SCHED_ID, read_data_ro_r, pipeline_perf_if.sched.idles); + `CSR_READ_64(`VX_CSR_MPM_SCHED_ST, read_data_ro_r, pipeline_perf_if.sched.stalls); + `CSR_READ_64(`VX_CSR_MPM_IBUF_ST, read_data_ro_r, pipeline_perf_if.issue.ibf_stalls); + `CSR_READ_64(`VX_CSR_MPM_SCRB_ST, read_data_ro_r, pipeline_perf_if.issue.scb_stalls); + `CSR_READ_64(`VX_CSR_MPM_OPDS_ST, read_data_ro_r, pipeline_perf_if.issue.opd_stalls); + `CSR_READ_64(`VX_CSR_MPM_SCRB_ALU, read_data_ro_r, pipeline_perf_if.issue.units_uses[`EX_ALU]); `ifdef EXT_F_ENABLE - `CSR_READ_64(`VX_CSR_MPM_SCRB_FPU, read_data_ro_r, pipeline_perf_if.units_uses[`EX_FPU]); + `CSR_READ_64(`VX_CSR_MPM_SCRB_FPU, read_data_ro_r, pipeline_perf_if.issue.units_uses[`EX_FPU]); `else - `VX_CSR_MPM_SCRB_FPU : read_data_ro_r = '0; - `VX_CSR_MPM_SCRB_FPU_H : read_data_ro_r = '0; + `CSR_READ_64(`VX_CSR_MPM_SCRB_FPU, read_data_ro_r, `PERF_CTR_BITS'(0)); `endif - `CSR_READ_64(`VX_CSR_MPM_SCRB_LSU, read_data_ro_r, pipeline_perf_if.units_uses[`EX_LSU]); - `CSR_READ_64(`VX_CSR_MPM_SCRB_SFU, read_data_ro_r, pipeline_perf_if.units_uses[`EX_SFU]); - `CSR_READ_64(`VX_CSR_MPM_SCRB_CSRS, read_data_ro_r, pipeline_perf_if.sfu_uses[`SFU_CSRS]); - `CSR_READ_64(`VX_CSR_MPM_SCRB_WCTL, read_data_ro_r, pipeline_perf_if.sfu_uses[`SFU_WCTL]); + `CSR_READ_64(`VX_CSR_MPM_SCRB_LSU, read_data_ro_r, pipeline_perf_if.issue.units_uses[`EX_LSU]); + `CSR_READ_64(`VX_CSR_MPM_SCRB_SFU, read_data_ro_r, pipeline_perf_if.issue.units_uses[`EX_SFU]); + `CSR_READ_64(`VX_CSR_MPM_SCRB_CSRS, read_data_ro_r, pipeline_perf_if.issue.sfu_uses[`SFU_CSRS]); + `CSR_READ_64(`VX_CSR_MPM_SCRB_WCTL, read_data_ro_r, pipeline_perf_if.issue.sfu_uses[`SFU_WCTL]); // PERF: memory `CSR_READ_64(`VX_CSR_MPM_IFETCHES, read_data_ro_r, pipeline_perf_if.ifetches); `CSR_READ_64(`VX_CSR_MPM_LOADS, read_data_ro_r, pipeline_perf_if.loads); diff --git a/hw/rtl/core/VX_csr_unit.sv b/hw/rtl/core/VX_csr_unit.sv index 4bc552374..999c9c416 100644 --- a/hw/rtl/core/VX_csr_unit.sv +++ b/hw/rtl/core/VX_csr_unit.sv @@ -14,6 +14,7 @@ `include "VX_define.vh" module VX_csr_unit import VX_gpu_pkg::*; #( + parameter `STRING INSTANCE_ID = "", parameter CORE_ID = 0, parameter NUM_LANES = 1 ) ( @@ -36,7 +37,7 @@ module VX_csr_unit import VX_gpu_pkg::*; #( VX_execute_if.slave execute_if, VX_commit_if.master commit_if ); - `UNUSED_PARAM (CORE_ID) + `UNUSED_SPARAM (INSTANCE_ID) localparam PID_BITS = `CLOG2(`NUM_THREADS / NUM_LANES); localparam PID_WIDTH = `UP(PID_BITS); localparam DATAW = `UUID_WIDTH + `NW_WIDTH + NUM_LANES + `PC_BITS + `NR_BITS + 1 + NUM_LANES * `XLEN + PID_WIDTH + 1 + 1; @@ -72,7 +73,8 @@ module VX_csr_unit import VX_gpu_pkg::*; #( wire csr_write_enable = (execute_if.data.op_type == `INST_SFU_CSRRW); VX_csr_data #( - .CORE_ID (CORE_ID) + .INSTANCE_ID (INSTANCE_ID), + .CORE_ID (CORE_ID) ) csr_data ( .clk (clk), .reset (reset), diff --git a/hw/rtl/core/VX_dcr_data.sv b/hw/rtl/core/VX_dcr_data.sv index 5218fb86a..58e51efc5 100644 --- a/hw/rtl/core/VX_dcr_data.sv +++ b/hw/rtl/core/VX_dcr_data.sv @@ -12,9 +12,8 @@ // limitations under the License. `include "VX_define.vh" -`include "VX_trace.vh" -module VX_dcr_data import VX_gpu_pkg::*; ( +module VX_dcr_data import VX_gpu_pkg::*, VX_trace_pkg::*; ( input wire clk, input wire reset, diff --git a/hw/rtl/core/VX_decode.sv b/hw/rtl/core/VX_decode.sv index 3fad20b75..9660859ce 100644 --- a/hw/rtl/core/VX_decode.sv +++ b/hw/rtl/core/VX_decode.sv @@ -12,7 +12,6 @@ // limitations under the License. `include "VX_define.vh" -`include "VX_trace.vh" `ifdef EXT_F_ENABLE `define USED_IREG(x) \ @@ -28,8 +27,8 @@ use_``x = 1 `endif -module VX_decode import VX_gpu_pkg::*; #( - parameter CORE_ID = 0 +module VX_decode import VX_gpu_pkg::*, VX_trace_pkg::*; #( + parameter `STRING INSTANCE_ID = "" ) ( input wire clk, input wire reset, @@ -44,7 +43,7 @@ module VX_decode import VX_gpu_pkg::*; #( localparam DATAW = `UUID_WIDTH + `NW_WIDTH + `NUM_THREADS + `PC_BITS + `EX_BITS + `INST_OP_BITS + `INST_ARGS_BITS + 1 + (`NR_BITS * 4); - `UNUSED_PARAM (CORE_ID) + `UNUSED_SPARAM (INSTANCE_ID) `UNUSED_VAR (clk) `UNUSED_VAR (reset) @@ -145,6 +144,12 @@ module VX_decode import VX_gpu_pkg::*; #( end `endif + `STATIC_ASSERT($bits(alu_args_t) == $bits(op_args_t), ("alu_args_t size mismatch: current=%0d, expected=%0d", $bits(alu_args_t), $bits(op_args_t))); + `STATIC_ASSERT($bits(fpu_args_t) == $bits(op_args_t), ("fpu_args_t size mismatch: current=%0d, expected=%0d", $bits(fpu_args_t), $bits(op_args_t))); + `STATIC_ASSERT($bits(lsu_args_t) == $bits(op_args_t), ("lsu_args_t size mismatch: current=%0d, expected=%0d", $bits(lsu_args_t), $bits(op_args_t))); + `STATIC_ASSERT($bits(csr_args_t) == $bits(op_args_t), ("csr_args_t size mismatch: current=%0d, expected=%0d", $bits(csr_args_t), $bits(op_args_t))); + `STATIC_ASSERT($bits(wctl_args_t) == $bits(op_args_t), ("wctl_args_t size mismatch: current=%0d, expected=%0d", $bits(wctl_args_t), $bits(op_args_t))); + always @(*) begin ex_type = '0; @@ -552,7 +557,7 @@ module VX_decode import VX_gpu_pkg::*; #( `ifdef DBG_TRACE_PIPELINE always @(posedge clk) begin if (decode_if.valid && decode_if.ready) begin - `TRACE(1, ("%d: core%0d-decode: wid=%0d, PC=0x%0h, instr=0x%0h, ex=", $time, CORE_ID, decode_if.data.wid, {decode_if.data.PC, 1'd0}, instr)); + `TRACE(1, ("%d: %s: wid=%0d, PC=0x%0h, instr=0x%0h, ex=", $time, INSTANCE_ID, decode_if.data.wid, {decode_if.data.PC, 1'd0}, instr)); trace_ex_type(1, decode_if.data.ex_type); `TRACE(1, (", op=")); trace_ex_op(1, decode_if.data.ex_type, decode_if.data.op_type, decode_if.data.op_args); diff --git a/hw/rtl/core/VX_dispatch.sv b/hw/rtl/core/VX_dispatch.sv index 77a5ed449..8ea3a6125 100644 --- a/hw/rtl/core/VX_dispatch.sv +++ b/hw/rtl/core/VX_dispatch.sv @@ -12,10 +12,9 @@ // limitations under the License. `include "VX_define.vh" -`include "VX_trace.vh" module VX_dispatch import VX_gpu_pkg::*; #( - parameter CORE_ID = 0 + parameter `STRING INSTANCE_ID = "" ) ( input wire clk, input wire reset, @@ -24,12 +23,12 @@ module VX_dispatch import VX_gpu_pkg::*; #( output wire [`PERF_CTR_BITS-1:0] perf_stalls [`NUM_EX_UNITS], `endif // inputs - VX_operands_if.slave operands_if [`ISSUE_WIDTH], + VX_operands_if.slave operands_if, // outputs - VX_dispatch_if.master dispatch_if [`NUM_EX_UNITS * `ISSUE_WIDTH] + VX_dispatch_if.master dispatch_if [`NUM_EX_UNITS] ); - `UNUSED_PARAM (CORE_ID) + `UNUSED_SPARAM (INSTANCE_ID) localparam DATAW = `UUID_WIDTH + ISSUE_WIS_W + `NUM_THREADS + `PC_BITS + `INST_OP_BITS + `INST_ARGS_BITS + 1 + `NR_BITS + (3 * `NUM_THREADS * `XLEN) + `NT_WIDTH; @@ -38,104 +37,71 @@ module VX_dispatch import VX_gpu_pkg::*; #( assign tids[i] = `NT_WIDTH'(i); end - for (genvar i = 0; i < `ISSUE_WIDTH; ++i) begin + wire [`NT_WIDTH-1:0] last_active_tid; - wire [`NT_WIDTH-1:0] last_active_tid; + VX_find_first #( + .N (`NUM_THREADS), + .DATAW (`NT_WIDTH), + .REVERSE (1) + ) last_tid_select ( + .valid_in (operands_if.data.tmask), + .data_in (tids), + .data_out (last_active_tid), + `UNUSED_PIN (valid_out) + ); - VX_find_first #( - .N (`NUM_THREADS), - .DATAW (`NT_WIDTH), - .REVERSE (1) - ) last_tid_select ( - .valid_in (operands_if[i].data.tmask), - .data_in (tids), - .data_out (last_active_tid), - `UNUSED_PIN (valid_out) + wire [`NUM_EX_UNITS-1:0] operands_reset; + assign operands_if.ready = operands_reset[operands_if.data.ex_type]; + + for (genvar i = 0; i < `NUM_EX_UNITS; ++i) begin + + `RESET_RELAY (buffer_reset, reset); + + VX_elastic_buffer #( + .DATAW (DATAW), + .SIZE (2), + .OUT_REG (2), // 2-cycle EB for area reduction + .LUTRAM (1) + ) buffer ( + .clk (clk), + .reset (buffer_reset), + .valid_in (operands_if.valid && (operands_if.data.ex_type == `EX_BITS'(i))), + .ready_in (operands_reset[i]), + .data_in ({ + operands_if.data.uuid, + operands_if.data.wis, + operands_if.data.tmask, + operands_if.data.PC, + operands_if.data.op_type, + operands_if.data.op_args, + operands_if.data.wb, + operands_if.data.rd, + last_active_tid, + operands_if.data.rs1_data, + operands_if.data.rs2_data, + operands_if.data.rs3_data + }), + .data_out (dispatch_if[i].data), + .valid_out (dispatch_if[i].valid), + .ready_out (dispatch_if[i].ready) ); - - wire [`NUM_EX_UNITS-1:0] operands_reset; - - `RESET_RELAY (buf_reset, reset); - - for (genvar j = 0; j < `NUM_EX_UNITS; ++j) begin - VX_elastic_buffer #( - .DATAW (DATAW), - .SIZE (2), - .OUT_REG (2) - ) buffer ( - .clk (clk), - .reset (buf_reset), - .valid_in (operands_if[i].valid && (operands_if[i].data.ex_type == j)), - .ready_in (operands_reset[j]), - .data_in (`TO_DISPATCH_DATA(operands_if[i].data, last_active_tid)), - .data_out (dispatch_if[j * `ISSUE_WIDTH + i].data), - .valid_out (dispatch_if[j * `ISSUE_WIDTH + i].valid), - .ready_out (dispatch_if[j * `ISSUE_WIDTH + i].ready) - ); - end - - assign operands_if[i].ready = operands_reset[operands_if[i].data.ex_type]; end `ifdef PERF_ENABLE - wire [`NUM_EX_UNITS-1:0] perf_unit_stalls_per_cycle, perf_unit_stalls_per_cycle_r; - reg [`ISSUE_WIDTH-1:0][`NUM_EX_UNITS-1:0] perf_issue_unit_stalls_per_cycle; reg [`NUM_EX_UNITS-1:0][`PERF_CTR_BITS-1:0] perf_stalls_r; - for (genvar i=0; i < `ISSUE_WIDTH; ++i) begin - always @(*) begin - perf_issue_unit_stalls_per_cycle[i] = '0; - if (operands_if[i].valid && ~operands_if[i].ready) begin - perf_issue_unit_stalls_per_cycle[i][operands_if[i].data.ex_type] = 1; - end - end - end - - VX_reduce #( - .DATAW_IN (`NUM_EX_UNITS), - .N (`ISSUE_WIDTH), - .OP ("|") - ) reduce ( - .data_in (perf_issue_unit_stalls_per_cycle), - .data_out (perf_unit_stalls_per_cycle) - ); - - `BUFFER(perf_unit_stalls_per_cycle_r, perf_unit_stalls_per_cycle); + wire operands_if_stall = operands_if.valid && ~operands_if.ready; for (genvar i = 0; i < `NUM_EX_UNITS; ++i) begin always @(posedge clk) begin if (reset) begin perf_stalls_r[i] <= '0; end else begin - perf_stalls_r[i] <= perf_stalls_r[i] + `PERF_CTR_BITS'(perf_unit_stalls_per_cycle_r[i]); + perf_stalls_r[i] <= perf_stalls_r[i] + `PERF_CTR_BITS'(operands_if_stall && operands_if.data.ex_type == `EX_BITS'(i)); end end - end - - for (genvar i=0; i < `NUM_EX_UNITS; ++i) begin assign perf_stalls[i] = perf_stalls_r[i]; end `endif -`ifdef DBG_TRACE_PIPELINE - for (genvar i=0; i < `ISSUE_WIDTH; ++i) begin - always @(posedge clk) begin - if (operands_if[i].valid && operands_if[i].ready) begin - `TRACE(1, ("%d: core%0d-issue: wid=%0d, PC=0x%0h, ex=", $time, CORE_ID, wis_to_wid(operands_if[i].data.wis, i), {operands_if[i].data.PC, 1'b0})); - trace_ex_type(1, operands_if[i].data.ex_type); - `TRACE(1, (", op=")); - trace_ex_op(1, operands_if[i].data.ex_type, operands_if[i].data.op_type, operands_if[i].data.op_args); - `TRACE(1, (", tmask=%b, wb=%b, rd=%0d, rs1_data=", operands_if[i].data.tmask, operands_if[i].data.wb, operands_if[i].data.rd)); - `TRACE_ARRAY1D(1, "0x%0h", operands_if[i].data.rs1_data, `NUM_THREADS); - `TRACE(1, (", rs2_data=")); - `TRACE_ARRAY1D(1, "0x%0h", operands_if[i].data.rs2_data, `NUM_THREADS); - `TRACE(1, (", rs3_data=")); - `TRACE_ARRAY1D(1, "0x%0h", operands_if[i].data.rs3_data, `NUM_THREADS); - trace_op_args(1, operands_if[i].data.ex_type, operands_if[i].data.op_type, operands_if[i].data.op_args); - `TRACE(1, (" (#%0d)\n", operands_if[i].data.uuid)); - end - end - end -`endif - endmodule diff --git a/hw/rtl/core/VX_execute.sv b/hw/rtl/core/VX_execute.sv index 5bc9b5566..ded25918c 100644 --- a/hw/rtl/core/VX_execute.sv +++ b/hw/rtl/core/VX_execute.sv @@ -14,6 +14,7 @@ `include "VX_define.vh" module VX_execute import VX_gpu_pkg::*; #( + parameter `STRING INSTANCE_ID = "", parameter CORE_ID = 0 ) ( `SCOPE_IO_DECL @@ -55,7 +56,7 @@ module VX_execute import VX_gpu_pkg::*; #( `RESET_RELAY (sfu_reset, reset); VX_alu_unit #( - .CORE_ID (CORE_ID) + .INSTANCE_ID ($sformatf("%s-alu", INSTANCE_ID)) ) alu_unit ( .clk (clk), .reset (alu_reset), @@ -67,7 +68,7 @@ module VX_execute import VX_gpu_pkg::*; #( `SCOPE_IO_SWITCH (1) VX_lsu_unit #( - .CORE_ID (CORE_ID) + .INSTANCE_ID ($sformatf("%s-lsu", INSTANCE_ID)) ) lsu_unit ( `SCOPE_IO_BIND (0) .clk (clk), @@ -81,7 +82,7 @@ module VX_execute import VX_gpu_pkg::*; #( `RESET_RELAY (fpu_reset, reset); VX_fpu_unit #( - .CORE_ID (CORE_ID) + .INSTANCE_ID ($sformatf("%s-fpu", INSTANCE_ID)) ) fpu_unit ( .clk (clk), .reset (fpu_reset), @@ -92,6 +93,7 @@ module VX_execute import VX_gpu_pkg::*; #( `endif VX_sfu_unit #( + .INSTANCE_ID ($sformatf("%s-sfu", INSTANCE_ID)), .CORE_ID (CORE_ID) ) sfu_unit ( .clk (clk), diff --git a/hw/rtl/core/VX_fetch.sv b/hw/rtl/core/VX_fetch.sv index 7f3dc61ba..59c419a83 100644 --- a/hw/rtl/core/VX_fetch.sv +++ b/hw/rtl/core/VX_fetch.sv @@ -14,7 +14,7 @@ `include "VX_define.vh" module VX_fetch import VX_gpu_pkg::*; #( - parameter CORE_ID = 0 + parameter `STRING INSTANCE_ID = "" ) ( `SCOPE_IO_DECL @@ -30,7 +30,7 @@ module VX_fetch import VX_gpu_pkg::*; #( // outputs VX_fetch_if.master fetch_if ); - `UNUSED_PARAM (CORE_ID) + `UNUSED_SPARAM (INSTANCE_ID) `UNUSED_VAR (reset) wire icache_req_valid; @@ -78,9 +78,11 @@ module VX_fetch import VX_gpu_pkg::*; #( .reset (reset), .incr (icache_req_fire && schedule_if.data.wid == i), .decr (fetch_if.ibuf_pop[i]), + `UNUSED_PIN (empty), + `UNUSED_PIN (alm_empty), .full (pending_ibuf_full[i]), - `UNUSED_PIN (size), - `UNUSED_PIN (empty) + `UNUSED_PIN (alm_full), + `UNUSED_PIN (size) ); end wire ibuf_ready = ~pending_ibuf_full[schedule_if.data.wid]; @@ -89,7 +91,7 @@ module VX_fetch import VX_gpu_pkg::*; #( `endif `RUNTIME_ASSERT((!schedule_if.valid || schedule_if.data.PC != 0), - ("%t: *** invalid PC=0x%0h, wid=%0d, tmask=%b (#%0d)", $time, {schedule_if.data.PC, 1'b0}, schedule_if.data.wid, schedule_if.data.tmask, schedule_if.data.uuid)) + ("%t: *** %s invalid PC=0x%0h, wid=%0d, tmask=%b (#%0d)", $time, INSTANCE_ID, {schedule_if.data.PC, 1'b0}, schedule_if.data.wid, schedule_if.data.tmask, schedule_if.data.uuid)) // Icache Request @@ -129,45 +131,33 @@ module VX_fetch import VX_gpu_pkg::*; #( assign icache_bus_if.rsp_ready = fetch_if.ready; `ifdef DBG_SCOPE_FETCH - if (CORE_ID == 0) begin - `ifdef SCOPE - wire schedule_fire = schedule_if.valid && schedule_if.ready; - wire icache_rsp_fire = icache_bus_if.rsp_valid && icache_bus_if.rsp_ready; - VX_scope_tap #( - .SCOPE_ID (1), - .TRIGGERW (4), - .PROBEW (`UUID_WIDTH + `NW_WIDTH + `NUM_THREADS + `PC_BITS + - ICACHE_TAG_WIDTH + ICACHE_WORD_SIZE + ICACHE_ADDR_WIDTH + - (ICACHE_WORD_SIZE*8) + ICACHE_TAG_WIDTH) - ) scope_tap ( - .clk(clk), - .reset(scope_reset), - .start(1'b0), - .stop(1'b0), - .triggers({ - reset, - schedule_fire, - icache_req_fire, - icache_rsp_fire - }), - .probes({ - schedule_if.data.uuid, schedule_if.data.wid, schedule_if.data.tmask, schedule_if.data.PC, - icache_bus_if.req_data.tag, icache_bus_if.req_data.byteen, icache_bus_if.req_data.addr, - icache_bus_if.rsp_data.data, icache_bus_if.rsp_data.tag - }), - .bus_in(scope_bus_in), - .bus_out(scope_bus_out) - ); - `endif - `ifdef CHIPSCOPE - ila_fetch ila_fetch_inst ( - .clk (clk), - .probe0 ({reset, schedule_if.data.uuid, schedule_if.data.wid, schedule_if.data.tmask, schedule_if.data.PC, schedule_if.ready, schedule_if.valid}), - .probe1 ({icache_bus_if.req_data.tag, icache_bus_if.req_data.byteen, icache_bus_if.req_data.addr, icache_bus_if.req_ready, icache_bus_if.req_valid}), - .probe2 ({icache_bus_if.rsp_data.data, icache_bus_if.rsp_data.tag, icache_bus_if.rsp_ready, icache_bus_if.rsp_valid}) - ); - `endif - end + wire schedule_fire = schedule_if.valid && schedule_if.ready; + wire icache_rsp_fire = icache_bus_if.rsp_valid && icache_bus_if.rsp_ready; + VX_scope_tap #( + .SCOPE_ID (1), + .TRIGGERW (4), + .PROBEW (`UUID_WIDTH + `NW_WIDTH + `NUM_THREADS + `PC_BITS + + ICACHE_TAG_WIDTH + ICACHE_WORD_SIZE + ICACHE_ADDR_WIDTH + + (ICACHE_WORD_SIZE*8) + ICACHE_TAG_WIDTH) + ) scope_tap ( + .clk (clk), + .reset (scope_reset), + .start (1'b0), + .stop (1'b0), + .triggers ({ + reset, + schedule_fire, + icache_req_fire, + icache_rsp_fire + }), + .probes ({ + schedule_if.data.uuid, schedule_if.data.wid, schedule_if.data.tmask, schedule_if.data.PC, + icache_bus_if.req_data.tag, icache_bus_if.req_data.byteen, icache_bus_if.req_data.addr, + icache_bus_if.rsp_data.data, icache_bus_if.rsp_data.tag + }), + .bus_in (scope_bus_in), + .bus_out (scope_bus_out) + ); `else `SCOPE_IO_UNUSED() `endif @@ -177,10 +167,10 @@ module VX_fetch import VX_gpu_pkg::*; #( wire fetch_fire = fetch_if.valid && fetch_if.ready; always @(posedge clk) begin if (schedule_fire) begin - `TRACE(1, ("%d: I$%0d req: wid=%0d, PC=0x%0h, tmask=%b (#%0d)\n", $time, CORE_ID, schedule_if.data.wid, {schedule_if.data.PC, 1'b0}, schedule_if.data.tmask, schedule_if.data.uuid)); + `TRACE(1, ("%d: %s req: wid=%0d, PC=0x%0h, tmask=%b (#%0d)\n", $time, INSTANCE_ID, schedule_if.data.wid, {schedule_if.data.PC, 1'b0}, schedule_if.data.tmask, schedule_if.data.uuid)); end if (fetch_fire) begin - `TRACE(1, ("%d: I$%0d rsp: wid=%0d, PC=0x%0h, tmask=%b, instr=0x%0h (#%0d)\n", $time, CORE_ID, fetch_if.data.wid, {fetch_if.data.PC, 1'b0}, fetch_if.data.tmask, fetch_if.data.instr, fetch_if.data.uuid)); + `TRACE(1, ("%d: %s rsp: wid=%0d, PC=0x%0h, tmask=%b, instr=0x%0h (#%0d)\n", $time, INSTANCE_ID, fetch_if.data.wid, {fetch_if.data.PC, 1'b0}, fetch_if.data.tmask, fetch_if.data.instr, fetch_if.data.uuid)); end end `endif diff --git a/hw/rtl/core/VX_fpu_unit.sv b/hw/rtl/core/VX_fpu_unit.sv index b90208719..8622db490 100644 --- a/hw/rtl/core/VX_fpu_unit.sv +++ b/hw/rtl/core/VX_fpu_unit.sv @@ -14,7 +14,7 @@ `include "VX_fpu_define.vh" module VX_fpu_unit import VX_fpu_pkg::*; #( - parameter CORE_ID = 0 + parameter `STRING INSTANCE_ID = "" ) ( input wire clk, input wire reset, @@ -26,7 +26,7 @@ module VX_fpu_unit import VX_fpu_pkg::*; #( VX_commit_if.master commit_if [`ISSUE_WIDTH], VX_fpu_csr_if.master fpu_csr_if[`NUM_FPU_BLOCKS] ); - `UNUSED_PARAM (CORE_ID) + `UNUSED_SPARAM (INSTANCE_ID) localparam BLOCK_SIZE = `NUM_FPU_BLOCKS; localparam NUM_LANES = `NUM_FPU_LANES; localparam PID_BITS = `CLOG2(`NUM_THREADS / NUM_LANES); @@ -84,12 +84,14 @@ module VX_fpu_unit import VX_fpu_pkg::*; #( wire execute_fire = per_block_execute_if[block_idx].valid && per_block_execute_if[block_idx].ready; wire fpu_rsp_fire = fpu_rsp_valid && fpu_rsp_ready; + `RESET_RELAY (ibuf_reset, block_reset); + VX_index_buffer #( .DATAW (`UUID_WIDTH + `NW_WIDTH + NUM_LANES + `PC_BITS + `NR_BITS + PID_WIDTH + 1 + 1), .SIZE (`FPUQ_SIZE) ) tag_store ( .clk (clk), - .reset (block_reset), + .reset (ibuf_reset), .acquire_en (execute_fire), .write_addr (fpu_req_tag), .write_data ({per_block_execute_if[block_idx].data.uuid, per_block_execute_if[block_idx].data.wid, per_block_execute_if[block_idx].data.tmask, per_block_execute_if[block_idx].data.PC, per_block_execute_if[block_idx].data.rd, per_block_execute_if[block_idx].data.pid, per_block_execute_if[block_idx].data.sop, per_block_execute_if[block_idx].data.eop}), @@ -226,12 +228,14 @@ module VX_fpu_unit import VX_fpu_pkg::*; #( // send response + `RESET_RELAY (rsp_reset, block_reset); + VX_elastic_buffer #( .DATAW (`UUID_WIDTH + `NW_WIDTH + NUM_LANES + `PC_BITS + `NR_BITS + (NUM_LANES * `XLEN) + PID_WIDTH + 1 + 1), .SIZE (0) ) rsp_buf ( .clk (clk), - .reset (block_reset), + .reset (rsp_reset), .valid_in (fpu_rsp_valid), .ready_in (fpu_rsp_ready), .data_in ({fpu_rsp_uuid, fpu_rsp_wid, fpu_rsp_tmask, fpu_rsp_PC, fpu_rsp_rd, fpu_rsp_result, fpu_rsp_pid, fpu_rsp_sop, fpu_rsp_eop}), diff --git a/hw/rtl/core/VX_ibuffer.sv b/hw/rtl/core/VX_ibuffer.sv index cf10e688c..e8edf64c7 100644 --- a/hw/rtl/core/VX_ibuffer.sv +++ b/hw/rtl/core/VX_ibuffer.sv @@ -14,33 +14,36 @@ `include "VX_define.vh" module VX_ibuffer import VX_gpu_pkg::*; #( - parameter CORE_ID = 0 + parameter `STRING INSTANCE_ID = "" ) ( input wire clk, input wire reset, +`ifdef PERF_ENABLE + output wire [`PERF_CTR_BITS-1:0] perf_stalls, +`endif + // inputs VX_decode_if.slave decode_if, // outputs - VX_ibuffer_if.master ibuffer_if [`NUM_WARPS] + VX_ibuffer_if.master ibuffer_if [PER_ISSUE_WARPS] ); - `UNUSED_PARAM (CORE_ID) + `UNUSED_SPARAM (INSTANCE_ID) localparam DATAW = `UUID_WIDTH + `NUM_THREADS + `PC_BITS + 1 + `EX_BITS + `INST_OP_BITS + `INST_ARGS_BITS + (`NR_BITS * 4); - wire [`NUM_WARPS-1:0] ibuf_ready_in; - + wire [PER_ISSUE_WARPS-1:0] ibuf_ready_in; assign decode_if.ready = ibuf_ready_in[decode_if.data.wid]; - for (genvar i = 0; i < `NUM_WARPS; ++i) begin + for (genvar w = 0; w < PER_ISSUE_WARPS; ++w) begin VX_elastic_buffer #( .DATAW (DATAW), .SIZE (`IBUF_SIZE), - .OUT_REG (2) // use a 2-cycle FIFO + .OUT_REG (2) // 2-cycle EB for area reduction ) instr_buf ( .clk (clk), .reset (reset), - .valid_in (decode_if.valid && decode_if.data.wid == i), + .valid_in (decode_if.valid && decode_if.data.wid == ISSUE_WIS_W'(w)), .data_in ({ decode_if.data.uuid, decode_if.data.tmask, @@ -52,15 +55,32 @@ module VX_ibuffer import VX_gpu_pkg::*; #( decode_if.data.rd, decode_if.data.rs1, decode_if.data.rs2, - decode_if.data.rs3}), - .ready_in (ibuf_ready_in[i]), - .valid_out(ibuffer_if[i].valid), - .data_out (ibuffer_if[i].data), - .ready_out(ibuffer_if[i].ready) + decode_if.data.rs3 + }), + .ready_in (ibuf_ready_in[w]), + .valid_out(ibuffer_if[w].valid), + .data_out (ibuffer_if[w].data), + .ready_out(ibuffer_if[w].ready) ); `ifndef L1_ENABLE - assign decode_if.ibuf_pop[i] = ibuffer_if[i].valid && ibuffer_if[i].ready; + assign decode_if.ibuf_pop[w] = ibuffer_if[w].valid && ibuffer_if[w].ready; `endif end +`ifdef PERF_ENABLE + reg [`PERF_CTR_BITS-1:0] perf_ibf_stalls; + + wire decode_if_stall = decode_if.valid && ~decode_if.ready; + + always @(posedge clk) begin + if (reset) begin + perf_ibf_stalls <= '0; + end else begin + perf_ibf_stalls <= perf_ibf_stalls + `PERF_CTR_BITS'(decode_if_stall); + end + end + + assign perf_stalls = perf_ibf_stalls; +`endif + endmodule diff --git a/hw/rtl/core/VX_issue.sv b/hw/rtl/core/VX_issue.sv index c999502de..1480e6649 100644 --- a/hw/rtl/core/VX_issue.sv +++ b/hw/rtl/core/VX_issue.sv @@ -12,10 +12,9 @@ // limitations under the License. `include "VX_define.vh" -`include "VX_trace.vh" -module VX_issue #( - parameter CORE_ID = 0 +module VX_issue import VX_gpu_pkg::*; #( + parameter `STRING INSTANCE_ID = "" ) ( `SCOPE_IO_DECL @@ -23,137 +22,81 @@ module VX_issue #( input wire reset, `ifdef PERF_ENABLE - VX_pipeline_perf_if.issue perf_issue_if, + output issue_perf_t issue_perf, `endif VX_decode_if.slave decode_if, VX_writeback_if.slave writeback_if [`ISSUE_WIDTH], VX_dispatch_if.master dispatch_if [`NUM_EX_UNITS * `ISSUE_WIDTH] ); - VX_ibuffer_if ibuffer_if [`NUM_WARPS](); - VX_scoreboard_if scoreboard_if [`ISSUE_WIDTH](); - VX_operands_if operands_if [`ISSUE_WIDTH](); - - `RESET_RELAY (ibuf_reset, reset); - `RESET_RELAY (scoreboard_reset, reset); - `RESET_RELAY (operands_reset, reset); - `RESET_RELAY (dispatch_reset, reset); - - VX_ibuffer #( - .CORE_ID (CORE_ID) - ) ibuffer ( - .clk (clk), - .reset (ibuf_reset), - .decode_if (decode_if), - .ibuffer_if (ibuffer_if) - ); - - VX_scoreboard #( - .CORE_ID (CORE_ID) - ) scoreboard ( - .clk (clk), - .reset (scoreboard_reset), - `ifdef PERF_ENABLE - .perf_scb_stalls(perf_issue_if.scb_stalls), - .perf_units_uses(perf_issue_if.units_uses), - .perf_sfu_uses (perf_issue_if.sfu_uses), - `endif - .writeback_if (writeback_if), - .ibuffer_if (ibuffer_if), - .scoreboard_if (scoreboard_if) - ); - - VX_operands #( - .CORE_ID (CORE_ID) - ) operands ( - .clk (clk), - .reset (operands_reset), - .writeback_if (writeback_if), - .scoreboard_if (scoreboard_if), - .operands_if (operands_if) - ); - - VX_dispatch #( - .CORE_ID (CORE_ID) - ) dispatch ( - .clk (clk), - .reset (dispatch_reset), - `ifdef PERF_ENABLE - `UNUSED_PIN (perf_stalls), - `endif - .operands_if (operands_if), - .dispatch_if (dispatch_if) - ); - -`ifdef DBG_SCOPE_ISSUE - if (CORE_ID == 0) begin - `ifdef SCOPE - wire operands_if_fire = operands_if[0].valid && operands_if[0].ready; - wire operands_if_not_ready = ~operands_if[0].ready; - wire writeback_if_valid = writeback_if[0].valid; - VX_scope_tap #( - .SCOPE_ID (2), - .TRIGGERW (4), - .PROBEW (`UUID_WIDTH + `NUM_THREADS + `EX_BITS + `INST_OP_BITS + - 1 + `NR_BITS + (`NUM_THREADS * 3 * `XLEN) + - `UUID_WIDTH + `NUM_THREADS + `NR_BITS + (`NUM_THREADS*`XLEN) + 1) - ) scope_tap ( - .clk(clk), - .reset(scope_reset), - .start(1'b0), - .stop(1'b0), - .triggers({ - reset, - operands_if_fire, - operands_if_not_ready, - writeback_if_valid - }), - .probes({ - operands_if[0].data.uuid, - operands_if[0].data.tmask, - operands_if[0].data.ex_type, - operands_if[0].data.op_type, - operands_if[0].data.wb, - operands_if[0].data.rd, - operands_if[0].data.rs1_data, - operands_if[0].data.rs2_data, - operands_if[0].data.rs3_data, - writeback_if[0].data.uuid, - writeback_if[0].data.tmask, - writeback_if[0].data.rd, - writeback_if[0].data.data, - writeback_if[0].data.eop - }), - .bus_in(scope_bus_in), - .bus_out(scope_bus_out) - ); - `endif - `ifdef CHIPSCOPE - ila_issue ila_issue_inst ( - .clk (clk), - .probe0 ({operands_if.uuid, ibuffer.rs3, ibuffer.rs2, ibuffer.rs1, operands_if.PC, operands_if.tmask, operands_if.wid, operands_if.ex_type, operands_if.op_type, operands_if.ready, operands_if.valid}), - .probe1 ({writeback_if.uuid, writeback_if.data[0], writeback_if.PC, writeback_if.tmask, writeback_if.wid, writeback_if.eop, writeback_if.valid}) - ); - `endif - end -`else - `SCOPE_IO_UNUSED() -`endif `ifdef PERF_ENABLE - reg [`PERF_CTR_BITS-1:0] perf_ibf_stalls; - - wire decode_stall = decode_if.valid && ~decode_if.ready; - - always @(posedge clk) begin - if (reset) begin - perf_ibf_stalls <= '0; - end else begin - perf_ibf_stalls <= perf_ibf_stalls + `PERF_CTR_BITS'(decode_stall); - end + issue_perf_t per_issue_perf [`ISSUE_WIDTH]; + `PERF_COUNTER_ADD (issue_perf, per_issue_perf, ibf_stalls, `PERF_CTR_BITS, `ISSUE_WIDTH, (`ISSUE_WIDTH > 2)) + `PERF_COUNTER_ADD (issue_perf, per_issue_perf, scb_stalls, `PERF_CTR_BITS, `ISSUE_WIDTH, (`ISSUE_WIDTH > 2)) + `PERF_COUNTER_ADD (issue_perf, per_issue_perf, opd_stalls, `PERF_CTR_BITS, `ISSUE_WIDTH, (`ISSUE_WIDTH > 2)) + for (genvar i = 0; i < `NUM_EX_UNITS; ++i) begin + `PERF_COUNTER_ADD (issue_perf, per_issue_perf, units_uses[i], `PERF_CTR_BITS, `ISSUE_WIDTH, (`ISSUE_WIDTH > 2)) + end + for (genvar i = 0; i < `NUM_SFU_UNITS; ++i) begin + `PERF_COUNTER_ADD (issue_perf, per_issue_perf, sfu_uses[i], `PERF_CTR_BITS, `ISSUE_WIDTH, (`ISSUE_WIDTH > 2)) end - - assign perf_issue_if.ibf_stalls = perf_ibf_stalls; `endif + wire [ISSUE_ISW_W-1:0] decode_isw = wid_to_isw(decode_if.data.wid); + wire [ISSUE_WIS_W-1:0] decode_wis = wid_to_wis(decode_if.data.wid); + + wire [`ISSUE_WIDTH-1:0] decode_ready_in; + assign decode_if.ready = decode_ready_in[decode_isw]; + + `SCOPE_IO_SWITCH (`ISSUE_WIDTH) + + for (genvar issue_id = 0; issue_id < `ISSUE_WIDTH; ++issue_id) begin : issue_slices + VX_decode_if #( + .NUM_WARPS (PER_ISSUE_WARPS) + ) per_issue_decode_if(); + + VX_dispatch_if per_issue_dispatch_if[`NUM_EX_UNITS](); + + assign per_issue_decode_if.valid = decode_if.valid && (decode_isw == ISSUE_ISW_W'(issue_id)); + assign per_issue_decode_if.data.uuid = decode_if.data.uuid; + assign per_issue_decode_if.data.wid = decode_wis; + assign per_issue_decode_if.data.tmask = decode_if.data.tmask; + assign per_issue_decode_if.data.PC = decode_if.data.PC; + assign per_issue_decode_if.data.ex_type = decode_if.data.ex_type; + assign per_issue_decode_if.data.op_type = decode_if.data.op_type; + assign per_issue_decode_if.data.op_args = decode_if.data.op_args; + assign per_issue_decode_if.data.wb = decode_if.data.wb; + assign per_issue_decode_if.data.rd = decode_if.data.rd; + assign per_issue_decode_if.data.rs1 = decode_if.data.rs1; + assign per_issue_decode_if.data.rs2 = decode_if.data.rs2; + assign per_issue_decode_if.data.rs3 = decode_if.data.rs3; + assign decode_ready_in[issue_id] = per_issue_decode_if.ready; + `ifndef L1_ENABLE + assign decode_if.ibuf_pop[issue_id * PER_ISSUE_WARPS +: PER_ISSUE_WARPS] = per_issue_decode_if.ibuf_pop; + `endif + + `RESET_RELAY (slice_reset, reset); + + VX_issue_slice #( + .INSTANCE_ID ($sformatf("%s%0d", INSTANCE_ID, issue_id)), + .ISSUE_ID (issue_id) + ) issue_slice ( + `SCOPE_IO_BIND(issue_id) + .clk (clk), + .reset (slice_reset), + `ifdef PERF_ENABLE + .issue_perf (per_issue_perf[issue_id]), + `endif + .decode_if (per_issue_decode_if), + .writeback_if (writeback_if[issue_id]), + .dispatch_if (per_issue_dispatch_if) + ); + + // Assign transposed dispatch_if + for (genvar ex_id = 0; ex_id < `NUM_EX_UNITS; ++ex_id) begin + `ASSIGN_VX_IF(dispatch_if[ex_id * `ISSUE_WIDTH + issue_id], per_issue_dispatch_if[ex_id]); + end + end + endmodule diff --git a/hw/rtl/core/VX_issue_slice.sv b/hw/rtl/core/VX_issue_slice.sv new file mode 100644 index 000000000..03b91b5fe --- /dev/null +++ b/hw/rtl/core/VX_issue_slice.sv @@ -0,0 +1,159 @@ +// Copyright © 2019-2023 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +`include "VX_define.vh" + +module VX_issue_slice import VX_gpu_pkg::*, VX_trace_pkg::*; #( + parameter `STRING INSTANCE_ID = "", + parameter ISSUE_ID = 0 +) ( + `SCOPE_IO_DECL + + input wire clk, + input wire reset, + +`ifdef PERF_ENABLE + output issue_perf_t issue_perf, +`endif + + VX_decode_if.slave decode_if, + VX_writeback_if.slave writeback_if, + VX_dispatch_if.master dispatch_if [`NUM_EX_UNITS] +); + `UNUSED_PARAM (ISSUE_ID) + + VX_ibuffer_if ibuffer_if [PER_ISSUE_WARPS](); + VX_scoreboard_if scoreboard_if(); + VX_operands_if operands_if(); + + `RESET_RELAY (ibuf_reset, reset); + `RESET_RELAY (scoreboard_reset, reset); + `RESET_RELAY (operands_reset, reset); + `RESET_RELAY (dispatch_reset, reset); + + VX_ibuffer #( + .INSTANCE_ID ($sformatf("%s-ibuffer", INSTANCE_ID)) + ) ibuffer ( + .clk (clk), + .reset (ibuf_reset), + `ifdef PERF_ENABLE + .perf_stalls (issue_perf.ibf_stalls), + `endif + .decode_if (decode_if), + .ibuffer_if (ibuffer_if) + ); + + VX_scoreboard #( + .INSTANCE_ID ($sformatf("%s-scoreboard", INSTANCE_ID)) + ) scoreboard ( + .clk (clk), + .reset (scoreboard_reset), + `ifdef PERF_ENABLE + .perf_stalls (issue_perf.scb_stalls), + .perf_units_uses(issue_perf.units_uses), + .perf_sfu_uses (issue_perf.sfu_uses), + `endif + .writeback_if (writeback_if), + .ibuffer_if (ibuffer_if), + .scoreboard_if (scoreboard_if) + ); + + VX_operands #( + .INSTANCE_ID ($sformatf("%s-operands", INSTANCE_ID)) + ) operands ( + .clk (clk), + .reset (operands_reset), + `ifdef PERF_ENABLE + .perf_stalls (issue_perf.opd_stalls), + `endif + .writeback_if (writeback_if), + .scoreboard_if (scoreboard_if), + .operands_if (operands_if) + ); + + VX_dispatch #( + .INSTANCE_ID ($sformatf("%s-dispatch", INSTANCE_ID)) + ) dispatch ( + .clk (clk), + .reset (dispatch_reset), + `ifdef PERF_ENABLE + `UNUSED_PIN (perf_stalls), + `endif + .operands_if (operands_if), + .dispatch_if (dispatch_if) + ); + +`ifdef DBG_SCOPE_ISSUE + wire operands_if_fire = operands_if.valid && operands_if.ready; + wire operands_if_not_ready = ~operands_if.ready; + wire writeback_if_valid = writeback_if.valid; + VX_scope_tap #( + .SCOPE_ID (2), + .TRIGGERW (4), + .PROBEW (`UUID_WIDTH + `NUM_THREADS + `EX_BITS + `INST_OP_BITS + + 1 + `NR_BITS + (`NUM_THREADS * 3 * `XLEN) + + `UUID_WIDTH + `NUM_THREADS + `NR_BITS + (`NUM_THREADS*`XLEN) + 1) + ) scope_tap ( + .clk (clk), + .reset (scope_reset), + .start (1'b0), + .stop (1'b0), + .triggers ({ + reset, + operands_if_fire, + operands_if_not_ready, + writeback_if_valid + }), + .probes ({ + operands_if.data.uuid, + operands_if.data.tmask, + operands_if.data.ex_type, + operands_if.data.op_type, + operands_if.data.wb, + operands_if.data.rd, + operands_if.data.rs1_data, + operands_if.data.rs2_data, + operands_if.data.rs3_data, + writeback_if.data.uuid, + writeback_if.data.tmask, + writeback_if.data.rd, + writeback_if.data.data, + writeback_if.data.eop + }), + .bus_in (scope_bus_in), + .bus_out (scope_bus_out) + ); +`else + `SCOPE_IO_UNUSED() +`endif + +`ifdef DBG_TRACE_PIPELINE + always @(posedge clk) begin + if (operands_if.valid && operands_if.ready) begin + `TRACE(1, ("%d: %s wid=%0d, PC=0x%0h, ex=", $time, INSTANCE_ID, wis_to_wid(operands_if.data.wis, ISSUE_ID), {operands_if.data.PC, 1'b0})); + trace_ex_type(1, operands_if.data.ex_type); + `TRACE(1, (", op=")); + trace_ex_op(1, operands_if.data.ex_type, operands_if.data.op_type, operands_if.data.op_args); + `TRACE(1, (", tmask=%b, wb=%b, rd=%0d, rs1_data=", operands_if.data.tmask, operands_if.data.wb, operands_if.data.rd)); + `TRACE_ARRAY1D(1, "0x%0h", operands_if.data.rs1_data, `NUM_THREADS); + `TRACE(1, (", rs2_data=")); + `TRACE_ARRAY1D(1, "0x%0h", operands_if.data.rs2_data, `NUM_THREADS); + `TRACE(1, (", rs3_data=")); + `TRACE_ARRAY1D(1, "0x%0h", operands_if.data.rs3_data, `NUM_THREADS); + trace_op_args(1, operands_if.data.ex_type, operands_if.data.op_type, operands_if.data.op_args); + `TRACE(1, (" (#%0d)\n", operands_if.data.uuid)); + end + end +`endif + +endmodule diff --git a/hw/rtl/core/VX_issue_top.sv b/hw/rtl/core/VX_issue_top.sv new file mode 100644 index 000000000..0166cf770 --- /dev/null +++ b/hw/rtl/core/VX_issue_top.sv @@ -0,0 +1,132 @@ +// Copyright © 2019-2023 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +`include "VX_define.vh" + +module VX_issue_top import VX_gpu_pkg::*; #( + parameter `STRING INSTANCE_ID = "issue" +) ( + // Clock + input wire clk, + input wire reset, + + input wire decode_valid, + input wire [`UUID_WIDTH-1:0] decode_uuid, + input wire [`NW_WIDTH-1:0] decode_wid, + input wire [`NUM_THREADS-1:0] decode_tmask, + input wire [`PC_BITS-1:0] decode_PC, + input wire [`EX_BITS-1:0] decode_ex_type, + input wire [`INST_OP_BITS-1:0] decode_op_type, + input op_args_t decode_op_args, + input wire decode_wb, + input wire [`NR_BITS-1:0] decode_rd, + input wire [`NR_BITS-1:0] decode_rs1, + input wire [`NR_BITS-1:0] decode_rs2, + input wire [`NR_BITS-1:0] decode_rs3, + output wire decode_ready, + + input wire writeback_valid[`ISSUE_WIDTH], + input wire [`UUID_WIDTH-1:0] writeback_uuid[`ISSUE_WIDTH], + input wire [ISSUE_WIS_W-1:0] writeback_wis[`ISSUE_WIDTH], + input wire [`NUM_THREADS-1:0] writeback_tmask[`ISSUE_WIDTH], + input wire [`PC_BITS-1:0] writeback_PC[`ISSUE_WIDTH], + input wire [`NR_BITS-1:0] writeback_rd[`ISSUE_WIDTH], + input wire [`NUM_THREADS-1:0][`XLEN-1:0] writeback_data[`ISSUE_WIDTH], + input wire writeback_sop[`ISSUE_WIDTH], + input wire writeback_eop[`ISSUE_WIDTH], + + output wire dispatch_valid[`NUM_EX_UNITS * `ISSUE_WIDTH], + output wire [`UUID_WIDTH-1:0] dispatch_uuid[`NUM_EX_UNITS * `ISSUE_WIDTH], + output wire [ISSUE_WIS_W-1:0] dispatch_wis[`NUM_EX_UNITS * `ISSUE_WIDTH], + output wire [`NUM_THREADS-1:0] dispatch_tmask[`NUM_EX_UNITS * `ISSUE_WIDTH], + output wire [`PC_BITS-1:0] dispatch_PC[`NUM_EX_UNITS * `ISSUE_WIDTH], + output wire [`INST_ALU_BITS-1:0] dispatch_op_type[`NUM_EX_UNITS * `ISSUE_WIDTH], + output op_args_t dispatch_op_args[`NUM_EX_UNITS * `ISSUE_WIDTH], + output wire dispatch_wb[`NUM_EX_UNITS * `ISSUE_WIDTH], + output wire [`NR_BITS-1:0] dispatch_rd[`NUM_EX_UNITS * `ISSUE_WIDTH], + output wire [`NT_WIDTH-1:0] dispatch_tid[`NUM_EX_UNITS * `ISSUE_WIDTH], + output wire [`NUM_THREADS-1:0][`XLEN-1:0] dispatch_rs1_data[`NUM_EX_UNITS * `ISSUE_WIDTH], + output wire [`NUM_THREADS-1:0][`XLEN-1:0] dispatch_rs2_data[`NUM_EX_UNITS * `ISSUE_WIDTH], + output wire [`NUM_THREADS-1:0][`XLEN-1:0] dispatch_rs3_data[`NUM_EX_UNITS * `ISSUE_WIDTH], + input wire dispatch_ready[`NUM_EX_UNITS * `ISSUE_WIDTH] +); + + VX_decode_if decode_if(); + VX_dispatch_if dispatch_if[`NUM_EX_UNITS * `ISSUE_WIDTH](); + VX_writeback_if writeback_if[`ISSUE_WIDTH](); + + assign decode_if.valid = decode_valid; + assign decode_if.data.uuid = decode_uuid; + assign decode_if.data.wid = decode_wid; + assign decode_if.data.tmask = decode_tmask; + assign decode_if.data.PC = decode_PC; + assign decode_if.data.ex_type = decode_ex_type; + assign decode_if.data.op_type = decode_op_type; + assign decode_if.data.op_args = decode_op_args; + assign decode_if.data.wb = decode_wb; + assign decode_if.data.rd = decode_rd; + assign decode_if.data.rs1 = decode_rs1; + assign decode_if.data.rs2 = decode_rs2; + assign decode_if.data.rs3 = decode_rs3; + assign decode_ready = decode_if.ready; + + for (genvar i = 0; i < `ISSUE_WIDTH; ++i) begin + assign writeback_if[i].valid = writeback_valid[i]; + assign writeback_if[i].data.uuid = writeback_uuid[i]; + assign writeback_if[i].data.wis = writeback_wis[i]; + assign writeback_if[i].data.tmask = writeback_tmask[i]; + assign writeback_if[i].data.PC = writeback_PC[i]; + assign writeback_if[i].data.rd = writeback_rd[i]; + assign writeback_if[i].data.data = writeback_data[i]; + assign writeback_if[i].data.sop = writeback_sop[i]; + assign writeback_if[i].data.eop = writeback_eop[i]; + end + + for (genvar i = 0; i < `NUM_EX_UNITS * `ISSUE_WIDTH; ++i) begin + assign dispatch_valid[i] = dispatch_if[i].valid; + assign dispatch_uuid[i] = dispatch_if[i].data.uuid; + assign dispatch_wis[i] = dispatch_if[i].data.wis; + assign dispatch_tmask[i] = dispatch_if[i].data.tmask; + assign dispatch_PC[i] = dispatch_if[i].data.PC; + assign dispatch_op_type[i] = dispatch_if[i].data.op_type; + assign dispatch_op_args[i] = dispatch_if[i].data.op_args; + assign dispatch_wb[i] = dispatch_if[i].data.wb; + assign dispatch_rd[i] = dispatch_if[i].data.rd; + assign dispatch_tid[i] = dispatch_if[i].data.tid; + assign dispatch_rs1_data[i] = dispatch_if[i].data.rs1_data; + assign dispatch_rs2_data[i] = dispatch_if[i].data.rs2_data; + assign dispatch_rs3_data[i] = dispatch_if[i].data.rs3_data; + assign dispatch_if[i].ready = dispatch_ready[i]; + end + +`ifdef PERF_ENABLE + issue_perf_t issue_perf = '0; +`endif + + VX_issue #( + .INSTANCE_ID (INSTANCE_ID) + ) issue ( + `SCOPE_IO_BIND (0) + .clk (clk), + .reset (reset), + + `ifdef PERF_ENABLE + .issue_perf (issue_perf), + `endif + + .decode_if (decode_if), + .writeback_if (writeback_if), + .dispatch_if (dispatch_if) + ); + +endmodule diff --git a/hw/rtl/core/VX_lmem_unit.sv b/hw/rtl/core/VX_lmem_unit.sv index 8c1f3993e..e896b4000 100644 --- a/hw/rtl/core/VX_lmem_unit.sv +++ b/hw/rtl/core/VX_lmem_unit.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -14,11 +14,11 @@ `include "VX_define.vh" module VX_lmem_unit import VX_gpu_pkg::*; #( - parameter CORE_ID = 0 + parameter `STRING INSTANCE_ID = "" ) ( input wire clk, input wire reset, - + `ifdef PERF_ENABLE output cache_perf_t cache_perf, `endif @@ -37,31 +37,31 @@ module VX_lmem_unit import VX_gpu_pkg::*; #( .NUM_LANES (`NUM_LSU_LANES), .DATA_SIZE (LSU_WORD_SIZE), .TAG_WIDTH (LSU_TAG_WIDTH) - ) lmem_lsu_if[`NUM_LSU_BLOCKS](); - - `RESET_RELAY (req_reset, reset); + ) lsu_switch_if[`NUM_LSU_BLOCKS](); for (genvar i = 0; i < `NUM_LSU_BLOCKS; ++i) begin - + wire [`NUM_LSU_LANES-1:0] is_addr_local_mask; for (genvar j = 0; j < `NUM_LSU_LANES; ++j) begin assign is_addr_local_mask[j] = lsu_mem_in_if[i].req_data.atype[j][`ADDR_TYPE_LOCAL]; end - + wire is_addr_global = | (lsu_mem_in_if[i].req_data.mask & ~is_addr_local_mask); - wire is_addr_local = | (lsu_mem_in_if[i].req_data.mask & is_addr_local_mask); + wire is_addr_local = | (lsu_mem_in_if[i].req_data.mask & is_addr_local_mask); wire req_global_ready; wire req_local_ready; + `RESET_RELAY (switch_reset, reset); + VX_elastic_buffer #( .DATAW (REQ_DATAW), .SIZE (2), .OUT_REG (1) ) req_global_buf ( .clk (clk), - .reset (req_reset), - .valid_in (lsu_mem_in_if[i].req_valid && is_addr_global), + .reset (switch_reset), + .valid_in (lsu_mem_in_if[i].req_valid && is_addr_global), .data_in ({ lsu_mem_in_if[i].req_data.mask & ~is_addr_local_mask, lsu_mem_in_if[i].req_data.rw, @@ -81,7 +81,7 @@ module VX_lmem_unit import VX_gpu_pkg::*; #( lsu_mem_out_if[i].req_data.atype, lsu_mem_out_if[i].req_data.data, lsu_mem_out_if[i].req_data.tag - }), + }), .ready_out (lsu_mem_out_if[i].req_ready) ); @@ -91,8 +91,8 @@ module VX_lmem_unit import VX_gpu_pkg::*; #( .OUT_REG (0) ) req_local_buf ( .clk (clk), - .reset (req_reset), - .valid_in (lsu_mem_in_if[i].req_valid && is_addr_local), + .reset (switch_reset), + .valid_in (lsu_mem_in_if[i].req_valid && is_addr_local), .data_in ({ lsu_mem_in_if[i].req_data.mask & is_addr_local_mask, lsu_mem_in_if[i].req_data.rw, @@ -103,73 +103,47 @@ module VX_lmem_unit import VX_gpu_pkg::*; #( lsu_mem_in_if[i].req_data.tag }), .ready_in (req_local_ready), - .valid_out (lmem_lsu_if[i].req_valid), + .valid_out (lsu_switch_if[i].req_valid), .data_out ({ - lmem_lsu_if[i].req_data.mask, - lmem_lsu_if[i].req_data.rw, - lmem_lsu_if[i].req_data.byteen, - lmem_lsu_if[i].req_data.addr, - lmem_lsu_if[i].req_data.atype, - lmem_lsu_if[i].req_data.data, - lmem_lsu_if[i].req_data.tag - }), - .ready_out (lmem_lsu_if[i].req_ready) + lsu_switch_if[i].req_data.mask, + lsu_switch_if[i].req_data.rw, + lsu_switch_if[i].req_data.byteen, + lsu_switch_if[i].req_data.addr, + lsu_switch_if[i].req_data.atype, + lsu_switch_if[i].req_data.data, + lsu_switch_if[i].req_data.tag + }), + .ready_out (lsu_switch_if[i].req_ready) ); - assign lsu_mem_in_if[i].req_ready = (req_global_ready && is_addr_global) + assign lsu_mem_in_if[i].req_ready = (req_global_ready && is_addr_global) || (req_local_ready && is_addr_local); - end - `RESET_RELAY (rsp_reset, reset); - - for (genvar i = 0; i < `NUM_LSU_BLOCKS; ++i) begin - - wire rsp_arb_valid; - wire rsp_arb_index; - wire rsp_arb_ready; - - VX_generic_arbiter #( - .NUM_REQS (2), - .LOCK_ENABLE (1), - .TYPE ("R") - ) arbiter ( - .clk (clk), - .reset (rsp_reset), - .requests ({ - lmem_lsu_if[i].rsp_valid, + VX_stream_arb #( + .NUM_INPUTS (2), + .DATAW (RSP_DATAW), + .ARBITER ("R"), + .OUT_BUF (1) + ) rsp_arb ( + .clk (clk), + .reset (switch_reset), + .valid_in ({ + lsu_switch_if[i].rsp_valid, lsu_mem_out_if[i].rsp_valid }), - .grant_valid (rsp_arb_valid), - .grant_index (rsp_arb_index), - `UNUSED_PIN (grant_onehot), - .grant_unlock(rsp_arb_ready) - ); - - VX_elastic_buffer #( - .DATAW (RSP_DATAW), - .SIZE (2), - .OUT_REG (0) - ) rsp_buf ( - .clk (clk), - .reset (rsp_reset), - .valid_in (rsp_arb_valid), - .data_in ({ - rsp_arb_index ? lmem_lsu_if[i].rsp_data.mask : lsu_mem_out_if[i].rsp_data.mask, - rsp_arb_index ? lmem_lsu_if[i].rsp_data.data : lsu_mem_out_if[i].rsp_data.data, - rsp_arb_index ? lmem_lsu_if[i].rsp_data.tag : lsu_mem_out_if[i].rsp_data.tag + .ready_in ({ + lsu_switch_if[i].rsp_ready, + lsu_mem_out_if[i].rsp_ready }), - .ready_in (rsp_arb_ready), + .data_in ({ + lsu_switch_if[i].rsp_data, + lsu_mem_out_if[i].rsp_data + }), + .data_out (lsu_mem_in_if[i].rsp_data), .valid_out (lsu_mem_in_if[i].rsp_valid), - .data_out ({ - lsu_mem_in_if[i].rsp_data.mask, - lsu_mem_in_if[i].rsp_data.data, - lsu_mem_in_if[i].rsp_data.tag - }), - .ready_out (lsu_mem_in_if[i].rsp_ready) + .ready_out (lsu_mem_in_if[i].rsp_ready), + `UNUSED_PIN (sel_out) ); - - assign lsu_mem_out_if[i].rsp_ready = rsp_arb_ready && ~rsp_arb_index; - assign lmem_lsu_if[i].rsp_ready = rsp_arb_ready && rsp_arb_index; end VX_mem_bus_if #( @@ -177,25 +151,25 @@ module VX_lmem_unit import VX_gpu_pkg::*; #( .TAG_WIDTH (LSU_TAG_WIDTH) ) lmem_bus_if[LSU_NUM_REQS](); - `RESET_RELAY (adapter_reset, reset); - - for (genvar i = 0; i < `NUM_LSU_BLOCKS; ++i) begin + for (genvar i = 0; i < `NUM_LSU_BLOCKS; ++i) begin VX_mem_bus_if #( .DATA_SIZE (LSU_WORD_SIZE), .TAG_WIDTH (LSU_TAG_WIDTH) ) lmem_bus_tmp_if[`NUM_LSU_LANES](); + `RESET_RELAY (adapter_reset, reset); + VX_lsu_adapter #( .NUM_LANES (`NUM_LSU_LANES), - .DATA_SIZE (LSU_WORD_SIZE), + .DATA_SIZE (LSU_WORD_SIZE), .TAG_WIDTH (LSU_TAG_WIDTH), .TAG_SEL_BITS (LSU_TAG_WIDTH - `UUID_WIDTH), - .REQ_OUT_BUF (2), - .RSP_OUT_BUF (1) + .REQ_OUT_BUF (3), + .RSP_OUT_BUF (0) ) lsu_adapter ( .clk (clk), .reset (adapter_reset), - .lsu_mem_if (lmem_lsu_if[i]), + .lsu_mem_if (lsu_switch_if[i]), .mem_bus_if (lmem_bus_tmp_if) ); @@ -205,17 +179,18 @@ module VX_lmem_unit import VX_gpu_pkg::*; #( end `RESET_RELAY (lmem_reset, reset); - + VX_local_mem #( - .INSTANCE_ID($sformatf("core%0d-lmem", CORE_ID)), + .INSTANCE_ID($sformatf("%s-lmem", INSTANCE_ID)), .SIZE (1 << `LMEM_LOG_SIZE), .NUM_REQS (LSU_NUM_REQS), .NUM_BANKS (`LMEM_NUM_BANKS), .WORD_SIZE (LSU_WORD_SIZE), .ADDR_WIDTH (LMEM_ADDR_WIDTH), - .UUID_WIDTH (`UUID_WIDTH), - .TAG_WIDTH (LSU_TAG_WIDTH) - ) local_mem ( + .UUID_WIDTH (`UUID_WIDTH), + .TAG_WIDTH (LSU_TAG_WIDTH), + .OUT_BUF (3) + ) local_mem ( .clk (clk), .reset (lmem_reset), `ifdef PERF_ENABLE diff --git a/hw/rtl/core/VX_lsu_adapter.sv b/hw/rtl/core/VX_lsu_adapter.sv index a981b27b0..21d43d280 100644 --- a/hw/rtl/core/VX_lsu_adapter.sv +++ b/hw/rtl/core/VX_lsu_adapter.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -14,10 +14,10 @@ `include "VX_define.vh" module VX_lsu_adapter import VX_gpu_pkg::*; #( - parameter NUM_LANES = 1, - parameter DATA_SIZE = 1, - parameter TAG_WIDTH = 1, - parameter TAG_SEL_BITS = 0, + parameter NUM_LANES = 1, + parameter DATA_SIZE = 1, + parameter TAG_WIDTH = 1, + parameter TAG_SEL_BITS = 0, parameter `STRING ARBITER = "P", parameter REQ_OUT_BUF = 0, parameter RSP_OUT_BUF = 0 @@ -63,12 +63,12 @@ module VX_lsu_adapter import VX_gpu_pkg::*; #( assign mem_bus_if[i].req_data.tag = req_tag_out[i]; assign req_ready_out[i] = mem_bus_if[i].req_ready; end - + VX_stream_unpack #( - .NUM_REQS (NUM_LANES), - .DATA_WIDTH (REQ_DATA_WIDTH), - .TAG_WIDTH (TAG_WIDTH), - .OUT_BUF (REQ_OUT_BUF) + .NUM_REQS (NUM_LANES), + .DATA_WIDTH (REQ_DATA_WIDTH), + .TAG_WIDTH (TAG_WIDTH), + .OUT_BUF (REQ_OUT_BUF) ) stream_unpack ( .clk (clk), .reset (reset), @@ -77,7 +77,7 @@ module VX_lsu_adapter import VX_gpu_pkg::*; #( .data_in (req_data_in), .tag_in (lsu_mem_if.req_data.tag), .ready_in (lsu_mem_if.req_ready), - .valid_out (req_valid_out), + .valid_out (req_valid_out), .data_out (req_data_out), .tag_out (req_tag_out), .ready_out (req_ready_out) diff --git a/hw/rtl/core/VX_lsu_slice.sv b/hw/rtl/core/VX_lsu_slice.sv index 2425cdc28..120dc9f8e 100644 --- a/hw/rtl/core/VX_lsu_slice.sv +++ b/hw/rtl/core/VX_lsu_slice.sv @@ -13,9 +13,8 @@ `include "VX_define.vh" -module VX_lsu_slice import VX_gpu_pkg::*; #( - parameter CORE_ID = 0, - parameter BLOCK_ID = 0 +module VX_lsu_slice import VX_gpu_pkg::*, VX_trace_pkg::*; #( + parameter `STRING INSTANCE_ID = "" ) ( `SCOPE_IO_DECL @@ -88,7 +87,7 @@ module VX_lsu_slice import VX_gpu_pkg::*; #( wire [NUM_LANES-1:0] mem_req_mask; wire mem_req_rw; wire [NUM_LANES-1:0][LSU_ADDR_WIDTH-1:0] mem_req_addr; - reg [NUM_LANES-1:0][LSU_WORD_SIZE-1:0] mem_req_byteen; + wire [NUM_LANES-1:0][LSU_WORD_SIZE-1:0] mem_req_byteen; reg [NUM_LANES-1:0][LSU_WORD_SIZE*8-1:0] mem_req_data; wire [TAG_WIDTH-1:0] mem_req_tag; wire mem_req_ready; @@ -159,27 +158,30 @@ module VX_lsu_slice import VX_gpu_pkg::*; #( // byte enable formatting for (genvar i = 0; i < NUM_LANES; ++i) begin + reg [LSU_WORD_SIZE-1:0] mem_req_byteen_r; always @(*) begin - mem_req_byteen[i] = '0; + mem_req_byteen_r = '0; case (`INST_LSU_WSIZE(execute_if.data.op_type)) 0: begin // 8-bit - mem_req_byteen[i][req_align[i]] = 1'b1; + mem_req_byteen_r[req_align[i]] = 1'b1; end 1: begin // 16 bit - mem_req_byteen[i][{req_align[i][REQ_ASHIFT-1:1], 1'b0}] = 1'b1; - mem_req_byteen[i][{req_align[i][REQ_ASHIFT-1:1], 1'b1}] = 1'b1; + mem_req_byteen_r[{req_align[i][REQ_ASHIFT-1:1], 1'b0}] = 1'b1; + mem_req_byteen_r[{req_align[i][REQ_ASHIFT-1:1], 1'b1}] = 1'b1; end `ifdef XLEN_64 2: begin // 32 bit - mem_req_byteen[i][{req_align[i][REQ_ASHIFT-1:2], 2'b00}] = 1'b1; - mem_req_byteen[i][{req_align[i][REQ_ASHIFT-1:2], 2'b01}] = 1'b1; - mem_req_byteen[i][{req_align[i][REQ_ASHIFT-1:2], 2'b10}] = 1'b1; - mem_req_byteen[i][{req_align[i][REQ_ASHIFT-1:2], 2'b11}] = 1'b1; + mem_req_byteen_r[{req_align[i][REQ_ASHIFT-1:2], 2'b00}] = 1'b1; + mem_req_byteen_r[{req_align[i][REQ_ASHIFT-1:2], 2'b01}] = 1'b1; + mem_req_byteen_r[{req_align[i][REQ_ASHIFT-1:2], 2'b10}] = 1'b1; + mem_req_byteen_r[{req_align[i][REQ_ASHIFT-1:2], 2'b11}] = 1'b1; end `endif - default : mem_req_byteen[i] = {LSU_WORD_SIZE{1'b1}}; + // 3: 64 bit + default : mem_req_byteen_r = {LSU_WORD_SIZE{1'b1}}; endcase end + assign mem_req_byteen[i] = mem_req_byteen_r; end // memory misalignment not supported! @@ -312,7 +314,7 @@ module VX_lsu_slice import VX_gpu_pkg::*; #( `RESET_RELAY (mem_scheduler_reset, reset); VX_mem_scheduler #( - .INSTANCE_ID ($sformatf("core%0d-lsu-memsched%0d", CORE_ID, BLOCK_ID)), + .INSTANCE_ID ($sformatf("%s-scheduler", INSTANCE_ID)), .CORE_REQS (NUM_LANES), .MEM_CHANNELS(NUM_LANES), .WORD_SIZE (LSU_WORD_SIZE), @@ -504,11 +506,11 @@ module VX_lsu_slice import VX_gpu_pkg::*; #( `ifdef DBG_TRACE_MEM always @(posedge clk) begin if (execute_if.valid && fence_lock) begin - `TRACE(1, ("%d: *** D$%0d fence wait\n", $time, CORE_ID)); + `TRACE(1, ("%d: *** %s fence wait\n", $time, INSTANCE_ID)); end if (mem_req_fire) begin if (mem_req_rw) begin - `TRACE(1, ("%d: D$%0d Wr Req: wid=%0d, PC=0x%0h, tmask=%b, addr=", $time, CORE_ID, execute_if.data.wid, {execute_if.data.PC, 1'b0}, mem_req_mask)); + `TRACE(1, ("%d: %s Wr Req: wid=%0d, PC=0x%0h, tmask=%b, addr=", $time, INSTANCE_ID, execute_if.data.wid, {execute_if.data.PC, 1'b0}, mem_req_mask)); `TRACE_ARRAY1D(1, "0x%h", full_addr, NUM_LANES); `TRACE(1, (", atype=")); `TRACE_ARRAY1D(1, "%b", mem_req_atype, NUM_LANES); @@ -516,7 +518,7 @@ module VX_lsu_slice import VX_gpu_pkg::*; #( `TRACE_ARRAY1D(1, "0x%0h", mem_req_data, NUM_LANES); `TRACE(1, (", tag=0x%0h (#%0d)\n", mem_req_tag, execute_if.data.uuid)); end else begin - `TRACE(1, ("%d: D$%0d Rd Req: wid=%0d, PC=0x%0h, tmask=%b, addr=", $time, CORE_ID, execute_if.data.wid, {execute_if.data.PC, 1'b0}, mem_req_mask)); + `TRACE(1, ("%d: %s Rd Req: wid=%0d, PC=0x%0h, tmask=%b, addr=", $time, INSTANCE_ID, execute_if.data.wid, {execute_if.data.PC, 1'b0}, mem_req_mask)); `TRACE_ARRAY1D(1, "0x%h", full_addr, NUM_LANES); `TRACE(1, (", atype=")); `TRACE_ARRAY1D(1, "%b", mem_req_atype, NUM_LANES); @@ -524,8 +526,8 @@ module VX_lsu_slice import VX_gpu_pkg::*; #( end end if (mem_rsp_fire) begin - `TRACE(1, ("%d: D$%0d Rsp: wid=%0d, PC=0x%0h, tmask=%b, rd=%0d, sop=%b, eop=%b, data=", - $time, CORE_ID, rsp_wid, {rsp_pc, 1'b0}, mem_rsp_mask, rsp_rd, mem_rsp_sop, mem_rsp_eop)); + `TRACE(1, ("%d: %s Rsp: wid=%0d, PC=0x%0h, tmask=%b, rd=%0d, sop=%b, eop=%b, data=", + $time, INSTANCE_ID, rsp_wid, {rsp_pc, 1'b0}, mem_rsp_mask, rsp_rd, mem_rsp_sop, mem_rsp_eop)); `TRACE_ARRAY1D(1, "0x%0h", mem_rsp_data, NUM_LANES); `TRACE(1, (", tag=0x%0h (#%0d)\n", mem_rsp_tag, rsp_uuid)); end @@ -533,36 +535,20 @@ module VX_lsu_slice import VX_gpu_pkg::*; #( `endif `ifdef DBG_SCOPE_LSU - if (CORE_ID == 0 && BLOCK_ID == 0) begin - `ifdef SCOPE - VX_scope_tap #( - .SCOPE_ID (3), - .TRIGGERW (3), - .PROBEW (`UUID_WIDTH+NUM_LANES*(`XLEN+4+`XLEN)+1+`UUID_WIDTH+NUM_LANES*`XLEN) - ) scope_tap ( - .clk(clk), - .reset(scope_reset), - .start(1'b0), - .stop(1'b0), - .triggers({reset, mem_req_fire, mem_rsp_fire}), - .probes({execute_if.data.uuid, full_addr, mem_req_rw, mem_req_byteen, mem_req_data, rsp_uuid, rsp_data}), - .bus_in(scope_bus_in), - .bus_out(scope_bus_out) - ); - `endif - `ifdef CHIPSCOPE - wire [31:0] full_addr_0 = full_addr[0]; - wire [31:0] mem_req_data_0 = mem_req_data[0]; - wire [31:0] rsp_data_0 = rsp_data[0]; - ila_lsu ila_lsu_inst ( - .clk (clk), - .probe0 ({mem_req_data_0, execute_if.data.uuid, execute_if.data.wid, execute_if.data.PC, mem_req_mask, full_addr_0, mem_req_byteen, mem_req_rw, mem_req_ready, mem_req_valid}), - .probe1 ({rsp_data_0, rsp_uuid, mem_rsp_eop, rsp_pc, rsp_rd, mem_rsp_mask, rsp_wid, mem_rsp_ready, mem_rsp_valid}), - .probe2 ({lsu_mem_if.req_data.data, lsu_mem_if.req_data.tag, lsu_mem_if.req_data.byteen, lsu_mem_if.req_data.addr, lsu_mem_if.req_data.rw, lsu_mem_if.req_ready, lsu_mem_if.req_valid}), - .probe3 ({lsu_mem_if.rsp_data.data, lsu_mem_if.rsp_data.tag, lsu_mem_if.rsp_ready, lsu_mem_if.rsp_valid}) - ); - `endif - end + VX_scope_tap #( + .SCOPE_ID (3), + .TRIGGERW (3), + .PROBEW (1 + NUM_LANES*(`XLEN + LSU_WORD_SIZE + LSU_WORD_SIZE*8) + `UUID_WIDTH + NUM_LANES*LSU_WORD_SIZE*8 + `UUID_WIDTH) + ) scope_tap ( + .clk (clk), + .reset (scope_reset), + .start (1'b0), + .stop (1'b0), + .triggers({reset, mem_req_fire, mem_rsp_fire}), + .probes ({mem_req_rw, full_addr, mem_req_byteen, mem_req_data, execute_if.data.uuid, rsp_data, rsp_uuid}), + .bus_in (scope_bus_in), + .bus_out(scope_bus_out) + ); `else `SCOPE_IO_UNUSED() `endif diff --git a/hw/rtl/core/VX_lsu_unit.sv b/hw/rtl/core/VX_lsu_unit.sv index e7dbe602b..d40f5fcfb 100644 --- a/hw/rtl/core/VX_lsu_unit.sv +++ b/hw/rtl/core/VX_lsu_unit.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -14,8 +14,8 @@ `include "VX_define.vh" module VX_lsu_unit import VX_gpu_pkg::*; #( - parameter CORE_ID = 0 -) ( + parameter `STRING INSTANCE_ID = "" +) ( `SCOPE_IO_DECL input wire clk, @@ -24,7 +24,7 @@ module VX_lsu_unit import VX_gpu_pkg::*; #( // Inputs VX_dispatch_if.slave dispatch_if [`ISSUE_WIDTH], - // Outputs + // Outputs VX_commit_if.master commit_if [`ISSUE_WIDTH], VX_lsu_mem_if.master lsu_mem_if [`NUM_LSU_BLOCKS] ); @@ -32,10 +32,9 @@ module VX_lsu_unit import VX_gpu_pkg::*; #( localparam NUM_LANES = `NUM_LSU_LANES; `ifdef SCOPE - localparam scope_lsu = 0; `SCOPE_IO_SWITCH (BLOCK_SIZE); `endif - + VX_execute_if #( .NUM_LANES (NUM_LANES) ) per_block_execute_if[BLOCK_SIZE](); @@ -55,17 +54,16 @@ module VX_lsu_unit import VX_gpu_pkg::*; #( .NUM_LANES (NUM_LANES) ) per_block_commit_if[BLOCK_SIZE](); - for (genvar block_idx = 0; block_idx < BLOCK_SIZE; ++block_idx) begin + for (genvar block_idx = 0; block_idx < BLOCK_SIZE; ++block_idx) begin : lsu_slices - `RESET_RELAY (block_reset, reset); + `RESET_RELAY (slice_reset, reset); VX_lsu_slice #( - .CORE_ID (CORE_ID), - .BLOCK_ID (block_idx) + .INSTANCE_ID ($sformatf("%s%0d", INSTANCE_ID, block_idx)) ) lsu_slice( - `SCOPE_IO_BIND (scope_lsu+block_idx) + `SCOPE_IO_BIND (block_idx) .clk (clk), - .reset (block_reset), + .reset (slice_reset), .execute_if (per_block_execute_if[block_idx]), .commit_if (per_block_commit_if[block_idx]), .lsu_mem_if (lsu_mem_if[block_idx]) @@ -82,5 +80,5 @@ module VX_lsu_unit import VX_gpu_pkg::*; #( .commit_in_if (per_block_commit_if), .commit_out_if (commit_if) ); - + endmodule diff --git a/hw/rtl/core/VX_operands.sv b/hw/rtl/core/VX_operands.sv index 811237195..17d8a9d0c 100644 --- a/hw/rtl/core/VX_operands.sv +++ b/hw/rtl/core/VX_operands.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -14,29 +14,288 @@ `include "VX_define.vh" module VX_operands import VX_gpu_pkg::*; #( - parameter CORE_ID = 0 + parameter `STRING INSTANCE_ID = "", + parameter NUM_BANKS = 4, + parameter OUT_BUF = 4 // using 2-cycle EB for area reduction ) ( input wire clk, input wire reset, - VX_writeback_if.slave writeback_if [`ISSUE_WIDTH], - VX_scoreboard_if.slave scoreboard_if [`ISSUE_WIDTH], - VX_operands_if.master operands_if [`ISSUE_WIDTH] +`ifdef PERF_ENABLE + output wire [`PERF_CTR_BITS-1:0] perf_stalls, +`endif + + VX_writeback_if.slave writeback_if, + VX_scoreboard_if.slave scoreboard_if, + VX_operands_if.master operands_if ); + `UNUSED_SPARAM (INSTANCE_ID) + localparam NUM_SRC_REGS = 3; + localparam REQ_SEL_BITS = `CLOG2(NUM_SRC_REGS); + localparam REQ_SEL_WIDTH = `UP(REQ_SEL_BITS); + localparam BANK_SEL_BITS = `CLOG2(NUM_BANKS); + localparam BANK_SEL_WIDTH = `UP(BANK_SEL_BITS); + localparam PER_BANK_REGS = `NUM_REGS / NUM_BANKS; + localparam METADATAW = ISSUE_WIS_W + `NUM_THREADS + `PC_BITS + 1 + `EX_BITS + `INST_OP_BITS + `INST_ARGS_BITS + `NR_BITS; + localparam DATAW = `UUID_WIDTH + METADATAW + 3 * `NUM_THREADS * `XLEN; + localparam RAM_ADDRW = `LOG2UP(`NUM_REGS * PER_ISSUE_WARPS); + localparam PER_BANK_ADDRW = RAM_ADDRW - BANK_SEL_BITS; + localparam XLEN_SIZE = `XLEN / 8; + localparam BYTEENW = `NUM_THREADS * XLEN_SIZE; - for (genvar i = 0; i < `ISSUE_WIDTH; ++i) begin - - `RESET_RELAY (slice_reset, reset); + `UNUSED_VAR (writeback_if.data.sop) - VX_gpr_slice #( - .CORE_ID (CORE_ID) - ) gpr_slice ( - .clk (clk), - .reset (slice_reset), - .writeback_if (writeback_if[i]), - .scoreboard_if(scoreboard_if[i]), - .operands_if (operands_if[i]) + wire [NUM_SRC_REGS-1:0] src_valid; + wire [NUM_SRC_REGS-1:0] req_in_valid; + wire [NUM_SRC_REGS-1:0] req_in_ready; + wire [NUM_SRC_REGS-1:0][PER_BANK_ADDRW-1:0] req_in_data; + wire [NUM_SRC_REGS-1:0][BANK_SEL_WIDTH-1:0] req_bank_idx; + + wire [NUM_BANKS-1:0] gpr_rd_valid_n, gpr_rd_ready; + reg [NUM_BANKS-1:0] gpr_rd_valid; + wire [NUM_BANKS-1:0][PER_BANK_ADDRW-1:0] gpr_rd_addr_n; + reg [NUM_BANKS-1:0][PER_BANK_ADDRW-1:0] gpr_rd_addr; + wire [NUM_BANKS-1:0][`NUM_THREADS-1:0][`XLEN-1:0] gpr_rd_data; + wire [NUM_BANKS-1:0][REQ_SEL_WIDTH-1:0] gpr_rd_req_idx_n; + reg [NUM_BANKS-1:0][REQ_SEL_WIDTH-1:0] gpr_rd_req_idx; + + wire pipe_in_ready; + reg pipe_out_valid; + wire pipe_out_ready; + reg [`UUID_WIDTH-1:0] pipe_out_uuid; + reg [METADATAW-1:0] pipe_out_data; + + reg [NUM_SRC_REGS-1:0][`NUM_THREADS-1:0][`XLEN-1:0] src_data, src_data_n; + reg [NUM_SRC_REGS-1:0] data_fetched; + reg has_collision, has_collision_n; + + wire stg_in_valid, stg_in_ready; + + wire [NUM_SRC_REGS-1:0][`NR_BITS-1:0] src_regs = {scoreboard_if.data.rs3, + scoreboard_if.data.rs2, + scoreboard_if.data.rs1}; + + for (genvar i = 0; i < NUM_SRC_REGS; ++i) begin + if (ISSUE_WIS != 0) begin + assign req_in_data[i] = {src_regs[i][`NR_BITS-1:BANK_SEL_BITS], scoreboard_if.data.wis}; + end else begin + assign req_in_data[i] = src_regs[i][`NR_BITS-1:BANK_SEL_BITS]; + end + if (NUM_BANKS != 1) begin + assign req_bank_idx[i] = src_regs[i][BANK_SEL_BITS-1:0]; + end else begin + assign req_bank_idx[i] = '0; + end + end + + for (genvar i = 0; i < NUM_SRC_REGS; ++i) begin + assign src_valid[i] = (src_regs[i] != 0) && ~data_fetched[i]; + end + + assign req_in_valid = {NUM_SRC_REGS{scoreboard_if.valid}} & src_valid; + + VX_stream_xbar #( + .NUM_INPUTS (NUM_SRC_REGS), + .NUM_OUTPUTS (NUM_BANKS), + .DATAW (PER_BANK_ADDRW), + .ARBITER ("P"), // use priority arbiter + .PERF_CTR_BITS(`PERF_CTR_BITS), + .OUT_BUF (0) // no output buffering + ) req_xbar ( + .clk (clk), + .reset (reset), + `UNUSED_PIN(collisions), + .valid_in (req_in_valid), + .data_in (req_in_data), + .sel_in (req_bank_idx), + .ready_in (req_in_ready), + .valid_out (gpr_rd_valid_n), + .data_out (gpr_rd_addr_n), + .sel_out (gpr_rd_req_idx_n), + .ready_out (gpr_rd_ready) + ); + + assign gpr_rd_ready = {NUM_BANKS{stg_in_ready}}; + + always @(*) begin + has_collision_n = 0; + for (integer i = 0; i < NUM_SRC_REGS; ++i) begin + for (integer j = 1; j < (NUM_SRC_REGS-i); ++j) begin + has_collision_n |= src_valid[i] + && src_valid[j+i] + && (req_bank_idx[i] == req_bank_idx[j+i]); + end + end + end + + always @(*) begin + src_data_n = src_data; + for (integer b = 0; b < NUM_BANKS; ++b) begin + if (gpr_rd_valid[b]) begin + src_data_n[gpr_rd_req_idx[b]] = gpr_rd_data[b]; + end + end + end + + wire pipe_stall = pipe_out_valid && ~pipe_out_ready; + assign pipe_in_ready = ~pipe_stall; + + assign scoreboard_if.ready = pipe_in_ready && ~has_collision_n; + + wire stg_in_fire = stg_in_valid && stg_in_ready; + + always @(posedge clk) begin + if (reset) begin + pipe_out_valid <= 0; + gpr_rd_valid <= '0; + data_fetched <= '0; + src_data <= '0; + end else begin + if (~pipe_stall) begin + pipe_out_valid <= scoreboard_if.valid; + gpr_rd_valid <= gpr_rd_valid_n; + if (scoreboard_if.ready) begin + data_fetched <= '0; + end else begin + data_fetched <= data_fetched | req_in_ready; + end + if (stg_in_fire) begin + src_data <= '0; + end else begin + src_data <= src_data_n; + end + end + end + if (~pipe_stall) begin + pipe_out_uuid <= scoreboard_if.data.uuid; + pipe_out_data <= { + scoreboard_if.data.wis, + scoreboard_if.data.tmask, + scoreboard_if.data.PC, + scoreboard_if.data.wb, + scoreboard_if.data.ex_type, + scoreboard_if.data.op_type, + scoreboard_if.data.op_args, + scoreboard_if.data.rd + }; + has_collision <= has_collision_n; + gpr_rd_addr <= gpr_rd_addr_n; + gpr_rd_req_idx <= gpr_rd_req_idx_n; + end + end + + assign pipe_out_ready = stg_in_ready; + assign stg_in_valid = pipe_out_valid && ~has_collision; + + VX_elastic_buffer #( + .DATAW (DATAW), + .SIZE (`TO_OUT_BUF_SIZE(OUT_BUF)), + .OUT_REG (`TO_OUT_BUF_REG(OUT_BUF)), + .LUTRAM (1) + ) out_buffer ( + .clk (clk), + .reset (reset), + .valid_in (stg_in_valid), + .ready_in (stg_in_ready), + .data_in ({ + pipe_out_uuid, + pipe_out_data, + src_data_n[0], + src_data_n[1], + src_data_n[2] + }), + .data_out ({ + operands_if.data.uuid, + operands_if.data.wis, + operands_if.data.tmask, + operands_if.data.PC, + operands_if.data.wb, + operands_if.data.ex_type, + operands_if.data.op_type, + operands_if.data.op_args, + operands_if.data.rd, + operands_if.data.rs1_data, + operands_if.data.rs2_data, + operands_if.data.rs3_data + }), + .valid_out (operands_if.valid), + .ready_out (operands_if.ready) + ); + + wire [PER_BANK_ADDRW-1:0] gpr_wr_addr; + if (ISSUE_WIS != 0) begin + assign gpr_wr_addr = {writeback_if.data.rd[`NR_BITS-1:BANK_SEL_BITS], writeback_if.data.wis}; + end else begin + assign gpr_wr_addr = writeback_if.data.rd[`NR_BITS-1:BANK_SEL_BITS]; + end + + wire [BANK_SEL_WIDTH-1:0] gpr_wr_bank_idx; + if (NUM_BANKS != 1) begin + assign gpr_wr_bank_idx = writeback_if.data.rd[BANK_SEL_BITS-1:0]; + end else begin + assign gpr_wr_bank_idx = '0; + end + + `ifdef GPR_RESET + reg wr_enabled = 0; + always @(posedge clk) begin + if (reset) begin + wr_enabled <= 1; + end + end + `else + wire wr_enabled = 1; + `endif + + for (genvar b = 0; b < NUM_BANKS; ++b) begin + wire gpr_wr_enabled; + if (BANK_SEL_BITS != 0) begin + assign gpr_wr_enabled = wr_enabled + && writeback_if.valid + && (gpr_wr_bank_idx == BANK_SEL_BITS'(b)); + end else begin + assign gpr_wr_enabled = wr_enabled && writeback_if.valid; + end + + wire [BYTEENW-1:0] wren; + for (genvar i = 0; i < `NUM_THREADS; ++i) begin + assign wren[i*XLEN_SIZE+:XLEN_SIZE] = {XLEN_SIZE{writeback_if.data.tmask[i]}}; + end + + `ifdef GPR_RESET + VX_dp_ram_rst #( + `else + VX_dp_ram #( + `endif + .DATAW (`XLEN * `NUM_THREADS), + .SIZE (PER_BANK_REGS * PER_ISSUE_WARPS), + .WRENW (BYTEENW), + .NO_RWCHECK (1) + ) gpr_ram ( + .clk (clk), + `ifdef GPR_RESET + .reset (reset), + `endif + .read (1'b1), + .wren (wren), + .write (gpr_wr_enabled), + .waddr (gpr_wr_addr), + .wdata (writeback_if.data.data), + .raddr (gpr_rd_addr[b]), + .rdata (gpr_rd_data[b]) ); end +`ifdef PERF_ENABLE + reg [`PERF_CTR_BITS-1:0] collisions_r; + always @(posedge clk) begin + if (reset) begin + collisions_r <= '0; + end else begin + collisions_r <= collisions_r + `PERF_CTR_BITS'(scoreboard_if.valid && pipe_in_ready && has_collision_n); + end + end + assign perf_stalls = collisions_r; +`endif + endmodule diff --git a/hw/rtl/core/VX_schedule.sv b/hw/rtl/core/VX_schedule.sv index b76610a80..6bc748745 100644 --- a/hw/rtl/core/VX_schedule.sv +++ b/hw/rtl/core/VX_schedule.sv @@ -14,13 +14,14 @@ `include "VX_define.vh" module VX_schedule import VX_gpu_pkg::*; #( + parameter `STRING INSTANCE_ID = "", parameter CORE_ID = 0 ) ( input wire clk, input wire reset, `ifdef PERF_ENABLE - VX_pipeline_perf_if.schedule perf_schedule_if, + output sched_perf_t sched_perf, `endif // configuration @@ -42,6 +43,7 @@ module VX_schedule import VX_gpu_pkg::*; #( // status output wire busy ); + `UNUSED_SPARAM (INSTANCE_ID) `UNUSED_PARAM (CORE_ID) reg [`NUM_WARPS-1:0] active_warps, active_warps_n; // updated when a warp is activated or disabled @@ -290,7 +292,7 @@ module VX_schedule import VX_gpu_pkg::*; #( `RESET_RELAY (split_join_reset, reset); VX_split_join #( - .CORE_ID (CORE_ID) + .INSTANCE_ID ($sformatf("%s-splitjoin", INSTANCE_ID)) ) split_join ( .clk (clk), .reset (split_join_reset), @@ -368,24 +370,42 @@ module VX_schedule import VX_gpu_pkg::*; #( assign schedule_if.data.uuid = instr_uuid; - `RESET_RELAY (pending_instr_reset, reset); + // Track pending instructions per warp - wire no_pending_instr; - VX_pending_instr #( - .CTR_WIDTH (12), - .DECR_COUNT (`ISSUE_WIDTH), - .ALM_EMPTY (1) - ) pending_instr( - .clk (clk), - .reset (pending_instr_reset), - .incr (schedule_if_fire), - .incr_wid (schedule_if.data.wid), - .decr (commit_sched_if.committed), - .decr_wid (commit_sched_if.committed_wid), - .alm_empty_wid (sched_csr_if.alm_empty_wid), - .alm_empty (sched_csr_if.alm_empty), - .empty (no_pending_instr) - ); + reg [`NUM_WARPS-1:0] per_warp_incr; + always @(*) begin + per_warp_incr = 0; + if (schedule_if_fire) begin + per_warp_incr[schedule_if.data.wid] = 1; + end + end + + wire [`NUM_WARPS-1:0] pending_warp_empty; + wire [`NUM_WARPS-1:0] pending_warp_alm_empty; + + for (genvar i = 0; i < `NUM_WARPS; ++i) begin + + `RESET_RELAY (pending_instr_reset, reset); + + VX_pending_size #( + .SIZE (4096), + .ALM_EMPTY (1) + ) counter ( + .clk (clk), + .reset (pending_instr_reset), + .incr (per_warp_incr[i]), + .decr (commit_sched_if.committed_warps[i]), + .empty (pending_warp_empty[i]), + .alm_empty (pending_warp_alm_empty[i]), + `UNUSED_PIN (full), + `UNUSED_PIN (alm_full), + `UNUSED_PIN (size) + ); + end + + assign sched_csr_if.alm_empty = pending_warp_alm_empty[sched_csr_if.alm_empty_wid]; + + wire no_pending_instr = (& pending_warp_empty); `BUFFER_EX(busy, (active_warps != 0 || ~no_pending_instr), 1'b1, 1); @@ -412,7 +432,7 @@ module VX_schedule import VX_gpu_pkg::*; #( end end end - `RUNTIME_ASSERT(timeout_ctr < `STALL_TIMEOUT, ("%t: *** core%0d-scheduler-timeout: stalled_warps=%b", $time, CORE_ID, stalled_warps)) + `RUNTIME_ASSERT(timeout_ctr < `STALL_TIMEOUT, ("%t: *** %s timeout: stalled_warps=%b", $time, INSTANCE_ID, stalled_warps)) `ifdef PERF_ENABLE reg [`PERF_CTR_BITS-1:0] perf_sched_idles; @@ -431,8 +451,8 @@ module VX_schedule import VX_gpu_pkg::*; #( end end - assign perf_schedule_if.sched_idles = perf_sched_idles; - assign perf_schedule_if.sched_stalls = perf_sched_stalls; + assign sched_perf.idles = perf_sched_idles; + assign sched_perf.stalls = perf_sched_stalls; `endif endmodule diff --git a/hw/rtl/core/VX_scoreboard.sv b/hw/rtl/core/VX_scoreboard.sv index 770ad7c1c..9b3a146c6 100644 --- a/hw/rtl/core/VX_scoreboard.sv +++ b/hw/rtl/core/VX_scoreboard.sv @@ -14,39 +14,37 @@ `include "VX_define.vh" module VX_scoreboard import VX_gpu_pkg::*; #( - parameter CORE_ID = 0 + parameter `STRING INSTANCE_ID = "" ) ( input wire clk, input wire reset, `ifdef PERF_ENABLE - output reg [`PERF_CTR_BITS-1:0] perf_scb_stalls, - output reg [`PERF_CTR_BITS-1:0] perf_units_uses [`NUM_EX_UNITS], - output reg [`PERF_CTR_BITS-1:0] perf_sfu_uses [`NUM_SFU_UNITS], + output reg [`PERF_CTR_BITS-1:0] perf_stalls, + output reg [`NUM_EX_UNITS-1:0][`PERF_CTR_BITS-1:0] perf_units_uses, + output reg [`NUM_SFU_UNITS-1:0][`PERF_CTR_BITS-1:0] perf_sfu_uses, `endif - VX_writeback_if.slave writeback_if [`ISSUE_WIDTH], - VX_ibuffer_if.slave ibuffer_if [`NUM_WARPS], - VX_scoreboard_if.master scoreboard_if [`ISSUE_WIDTH] + VX_writeback_if.slave writeback_if, + VX_ibuffer_if.slave ibuffer_if [PER_ISSUE_WARPS], + VX_scoreboard_if.master scoreboard_if ); - `UNUSED_PARAM (CORE_ID) + `UNUSED_SPARAM (INSTANCE_ID) localparam DATAW = `UUID_WIDTH + `NUM_THREADS + `PC_BITS + `EX_BITS + `INST_OP_BITS + `INST_ARGS_BITS + (`NR_BITS * 4) + 1; + VX_ibuffer_if staging_if [PER_ISSUE_WARPS](); + reg [PER_ISSUE_WARPS-1:0] operands_ready; + `ifdef PERF_ENABLE - reg [`NUM_WARPS-1:0][`NUM_EX_UNITS-1:0] perf_inuse_units_per_cycle; + reg [PER_ISSUE_WARPS-1:0][`NUM_EX_UNITS-1:0] perf_inuse_units_per_cycle; wire [`NUM_EX_UNITS-1:0] perf_units_per_cycle, perf_units_per_cycle_r; - reg [`NUM_WARPS-1:0][`NUM_SFU_UNITS-1:0] perf_inuse_sfu_per_cycle; + reg [PER_ISSUE_WARPS-1:0][`NUM_SFU_UNITS-1:0] perf_inuse_sfu_per_cycle; wire [`NUM_SFU_UNITS-1:0] perf_sfu_per_cycle, perf_sfu_per_cycle_r; - wire [`NUM_WARPS-1:0] perf_issue_stalls_per_cycle; - wire [`CLOG2(`NUM_WARPS+1)-1:0] perf_stalls_per_cycle, perf_stalls_per_cycle_r; - - `POP_COUNT(perf_stalls_per_cycle, perf_issue_stalls_per_cycle); - VX_reduce #( .DATAW_IN (`NUM_EX_UNITS), - .N (`NUM_WARPS), + .N (PER_ISSUE_WARPS), .OP ("|") ) perf_units_reduce ( .data_in (perf_inuse_units_per_cycle), @@ -55,22 +53,28 @@ module VX_scoreboard import VX_gpu_pkg::*; #( VX_reduce #( .DATAW_IN (`NUM_SFU_UNITS), - .N (`NUM_WARPS), + .N (PER_ISSUE_WARPS), .OP ("|") ) perf_sfu_reduce ( .data_in (perf_inuse_sfu_per_cycle), .data_out (perf_sfu_per_cycle) ); - `BUFFER(perf_stalls_per_cycle_r, perf_stalls_per_cycle); - `BUFFER_EX(perf_units_per_cycle_r, perf_units_per_cycle, 1'b1, `CDIV(`NUM_WARPS, `MAX_FANOUT)); - `BUFFER_EX(perf_sfu_per_cycle_r, perf_sfu_per_cycle, 1'b1, `CDIV(`NUM_WARPS, `MAX_FANOUT)); + `BUFFER_EX(perf_units_per_cycle_r, perf_units_per_cycle, 1'b1, `CDIV(PER_ISSUE_WARPS, `MAX_FANOUT)); + `BUFFER_EX(perf_sfu_per_cycle_r, perf_sfu_per_cycle, 1'b1, `CDIV(PER_ISSUE_WARPS, `MAX_FANOUT)); + + wire [PER_ISSUE_WARPS-1:0] stg_valid_in; + for (genvar w = 0; w < PER_ISSUE_WARPS; ++w) begin + assign stg_valid_in[w] = staging_if[w].valid; + end + + wire perf_stall_per_cycle = (|stg_valid_in) && ~(|(stg_valid_in & operands_ready)); always @(posedge clk) begin if (reset) begin - perf_scb_stalls <= '0; + perf_stalls <= '0; end else begin - perf_scb_stalls <= perf_scb_stalls + `PERF_CTR_BITS'(perf_stalls_per_cycle_r); + perf_stalls <= perf_stalls + `PERF_CTR_BITS'(perf_stall_per_cycle); end end @@ -95,138 +99,121 @@ module VX_scoreboard import VX_gpu_pkg::*; #( end `endif - VX_ibuffer_if staging_if [`NUM_WARPS](); - wire [`NUM_WARPS-1:0][3:0] staging_opds_busy; - - for (genvar i = 0; i < `NUM_WARPS; ++i) begin + for (genvar w = 0; w < PER_ISSUE_WARPS; ++w) begin VX_elastic_buffer #( .DATAW (DATAW), .SIZE (1) ) stanging_buf ( .clk (clk), .reset (reset), - .valid_in (ibuffer_if[i].valid), - .data_in (ibuffer_if[i].data), - .ready_in (ibuffer_if[i].ready), - .valid_out(staging_if[i].valid), - .data_out (staging_if[i].data), - .ready_out(staging_if[i].ready) + .valid_in (ibuffer_if[w].valid), + .data_in (ibuffer_if[w].data), + .ready_in (ibuffer_if[w].ready), + .valid_out(staging_if[w].valid), + .data_out (staging_if[w].data), + .ready_out(staging_if[w].ready) ); end - for (genvar i = 0; i < `NUM_WARPS; ++i) begin + for (genvar w = 0; w < PER_ISSUE_WARPS; ++w) begin reg [`NUM_REGS-1:0] inuse_regs; - reg [3:0] operands_busy_r, operands_busy_n; + reg [3:0] operands_busy, operands_busy_n; - localparam iw = i % `ISSUE_WIDTH; - localparam wis = i / `ISSUE_WIDTH; + wire ibuffer_fire = ibuffer_if[w].valid && ibuffer_if[w].ready; - wire ibuffer_fire = ibuffer_if[i].valid && ibuffer_if[i].ready; + wire staging_fire = staging_if[w].valid && staging_if[w].ready; - wire staging_fire = staging_if[i].valid && staging_if[i].ready; - - wire writeback_fire = writeback_if[iw].valid - && (writeback_if[iw].data.wis == ISSUE_WIS_W'(wis)) - && writeback_if[iw].data.eop; + wire writeback_fire = writeback_if.valid + && (writeback_if.data.wis == ISSUE_WIS_W'(w)) + && writeback_if.data.eop; `ifdef PERF_ENABLE reg [`NUM_REGS-1:0][`EX_WIDTH-1:0] inuse_units; reg [`NUM_REGS-1:0][`SFU_WIDTH-1:0] inuse_sfu; - reg [`SFU_WIDTH-1:0] sfu_type; always @(*) begin - case (staging_if[i].data.op_type) - `INST_SFU_CSRRW, - `INST_SFU_CSRRS, - `INST_SFU_CSRRC: sfu_type = `SFU_CSRS; - default: sfu_type = `SFU_WCTL; - endcase - end - - always @(*) begin - perf_inuse_units_per_cycle[i] = '0; - perf_inuse_sfu_per_cycle[i] = '0; - if (staging_if[i].valid) begin - if (operands_busy_r[0]) begin - perf_inuse_units_per_cycle[i][inuse_units[staging_if[i].data.rd]] = 1; - if (inuse_units[staging_if[i].data.rd] == `EX_SFU) begin - perf_inuse_sfu_per_cycle[i][inuse_sfu[staging_if[i].data.rd]] = 1; + perf_inuse_units_per_cycle[w] = '0; + perf_inuse_sfu_per_cycle[w] = '0; + if (staging_if[w].valid) begin + if (operands_busy[0]) begin + perf_inuse_units_per_cycle[w][inuse_units[staging_if[w].data.rd]] = 1; + if (inuse_units[staging_if[w].data.rd] == `EX_SFU) begin + perf_inuse_sfu_per_cycle[w][inuse_sfu[staging_if[w].data.rd]] = 1; end end - if (operands_busy_r[1]) begin - perf_inuse_units_per_cycle[i][inuse_units[staging_if[i].data.rs1]] = 1; - if (inuse_units[staging_if[i].data.rs1] == `EX_SFU) begin - perf_inuse_sfu_per_cycle[i][inuse_sfu[staging_if[i].data.rs1]] = 1; + if (operands_busy[1]) begin + perf_inuse_units_per_cycle[w][inuse_units[staging_if[w].data.rs1]] = 1; + if (inuse_units[staging_if[w].data.rs1] == `EX_SFU) begin + perf_inuse_sfu_per_cycle[w][inuse_sfu[staging_if[w].data.rs1]] = 1; end end - if (operands_busy_r[2]) begin - perf_inuse_units_per_cycle[i][inuse_units[staging_if[i].data.rs2]] = 1; - if (inuse_units[staging_if[i].data.rs2] == `EX_SFU) begin - perf_inuse_sfu_per_cycle[i][inuse_sfu[staging_if[i].data.rs2]] = 1; + if (operands_busy[2]) begin + perf_inuse_units_per_cycle[w][inuse_units[staging_if[w].data.rs2]] = 1; + if (inuse_units[staging_if[w].data.rs2] == `EX_SFU) begin + perf_inuse_sfu_per_cycle[w][inuse_sfu[staging_if[w].data.rs2]] = 1; end end - if (operands_busy_r[3]) begin - perf_inuse_units_per_cycle[i][inuse_units[staging_if[i].data.rs3]] = 1; - if (inuse_units[staging_if[i].data.rs3] == `EX_SFU) begin - perf_inuse_sfu_per_cycle[i][inuse_sfu[staging_if[i].data.rs3]] = 1; + if (operands_busy[3]) begin + perf_inuse_units_per_cycle[w][inuse_units[staging_if[w].data.rs3]] = 1; + if (inuse_units[staging_if[w].data.rs3] == `EX_SFU) begin + perf_inuse_sfu_per_cycle[w][inuse_sfu[staging_if[w].data.rs3]] = 1; end end end end - assign perf_issue_stalls_per_cycle[i] = staging_if[i].valid && ~staging_if[i].ready; `endif always @(*) begin - operands_busy_n = operands_busy_r; + operands_busy_n = operands_busy; if (ibuffer_fire) begin operands_busy_n = { - inuse_regs[ibuffer_if[i].data.rs3], - inuse_regs[ibuffer_if[i].data.rs2], - inuse_regs[ibuffer_if[i].data.rs1], - inuse_regs[ibuffer_if[i].data.rd] + inuse_regs[ibuffer_if[w].data.rs3], + inuse_regs[ibuffer_if[w].data.rs2], + inuse_regs[ibuffer_if[w].data.rs1], + inuse_regs[ibuffer_if[w].data.rd] }; end if (writeback_fire) begin if (ibuffer_fire) begin - if (writeback_if[iw].data.rd == ibuffer_if[i].data.rd) begin + if (writeback_if.data.rd == ibuffer_if[w].data.rd) begin operands_busy_n[0] = 0; end - if (writeback_if[iw].data.rd == ibuffer_if[i].data.rs1) begin + if (writeback_if.data.rd == ibuffer_if[w].data.rs1) begin operands_busy_n[1] = 0; end - if (writeback_if[iw].data.rd == ibuffer_if[i].data.rs2) begin + if (writeback_if.data.rd == ibuffer_if[w].data.rs2) begin operands_busy_n[2] = 0; end - if (writeback_if[iw].data.rd == ibuffer_if[i].data.rs3) begin + if (writeback_if.data.rd == ibuffer_if[w].data.rs3) begin operands_busy_n[3] = 0; end end else begin - if (writeback_if[iw].data.rd == staging_if[i].data.rd) begin + if (writeback_if.data.rd == staging_if[w].data.rd) begin operands_busy_n[0] = 0; end - if (writeback_if[iw].data.rd == staging_if[i].data.rs1) begin + if (writeback_if.data.rd == staging_if[w].data.rs1) begin operands_busy_n[1] = 0; end - if (writeback_if[iw].data.rd == staging_if[i].data.rs2) begin + if (writeback_if.data.rd == staging_if[w].data.rs2) begin operands_busy_n[2] = 0; end - if (writeback_if[iw].data.rd == staging_if[i].data.rs3) begin + if (writeback_if.data.rd == staging_if[w].data.rs3) begin operands_busy_n[3] = 0; end end end - if (staging_fire && staging_if[i].data.wb) begin - if (staging_if[i].data.rd == ibuffer_if[i].data.rd) begin + if (staging_fire && staging_if[w].data.wb) begin + if (staging_if[w].data.rd == ibuffer_if[w].data.rd) begin operands_busy_n[0] = 1; end - if (staging_if[i].data.rd == ibuffer_if[i].data.rs1) begin + if (staging_if[w].data.rd == ibuffer_if[w].data.rs1) begin operands_busy_n[1] = 1; end - if (staging_if[i].data.rd == ibuffer_if[i].data.rs2) begin + if (staging_if[w].data.rd == ibuffer_if[w].data.rs2) begin operands_busy_n[2] = 1; end - if (staging_if[i].data.rd == ibuffer_if[i].data.rs3) begin + if (staging_if[w].data.rd == ibuffer_if[w].data.rs3) begin operands_busy_n[3] = 1; end end @@ -237,25 +224,24 @@ module VX_scoreboard import VX_gpu_pkg::*; #( inuse_regs <= '0; end else begin if (writeback_fire) begin - inuse_regs[writeback_if[iw].data.rd] <= 0; + inuse_regs[writeback_if.data.rd] <= 0; end - if (staging_fire && staging_if[i].data.wb) begin - inuse_regs[staging_if[i].data.rd] <= 1; + if (staging_fire && staging_if[w].data.wb) begin + inuse_regs[staging_if[w].data.rd] <= 1; end end - operands_busy_r <= operands_busy_n; + operands_busy <= operands_busy_n; + operands_ready[w] <= ~(| operands_busy_n); `ifdef PERF_ENABLE - if (staging_fire && staging_if[i].data.wb) begin - inuse_units[staging_if[i].data.rd] <= staging_if[i].data.ex_type; - if (staging_if[i].data.ex_type == `EX_SFU) begin - inuse_sfu[staging_if[i].data.rd] <= sfu_type; + if (staging_fire && staging_if[w].data.wb) begin + inuse_units[staging_if[w].data.rd] <= staging_if[w].data.ex_type; + if (staging_if[w].data.ex_type == `EX_SFU) begin + inuse_sfu[staging_if[w].data.rd] <= op_to_sfu_type(staging_if[w].data.op_type); end end `endif end - assign staging_opds_busy[i] = operands_busy_r; - `ifdef SIMULATION reg [31:0] timeout_ctr; @@ -263,11 +249,11 @@ module VX_scoreboard import VX_gpu_pkg::*; #( if (reset) begin timeout_ctr <= '0; end else begin - if (staging_if[i].valid && ~staging_if[i].ready) begin + if (staging_if[w].valid && ~staging_if[w].ready) begin `ifdef DBG_TRACE_PIPELINE - `TRACE(3, ("%d: *** core%0d-scoreboard-stall: wid=%0d, PC=0x%0h, tmask=%b, cycles=%0d, inuse=%b (#%0d)\n", - $time, CORE_ID, i, {staging_if[i].data.PC, 1'b0}, staging_if[i].data.tmask, timeout_ctr, - operands_busy_r, staging_if[i].data.uuid)); + `TRACE(3, ("%d: *** %s-stall: wid=%0d, PC=0x%0h, tmask=%b, cycles=%0d, inuse=%b (#%0d)\n", + $time, INSTANCE_ID, w, {staging_if[w].data.PC, 1'b0}, staging_if[w].data.tmask, timeout_ctr, + operands_busy, staging_if[w].data.uuid)); `endif timeout_ctr <= timeout_ctr + 1; end else if (ibuffer_fire) begin @@ -277,59 +263,57 @@ module VX_scoreboard import VX_gpu_pkg::*; #( end `RUNTIME_ASSERT((timeout_ctr < `STALL_TIMEOUT), - ("%t: *** core%0d-scoreboard-timeout: wid=%0d, PC=0x%0h, tmask=%b, cycles=%0d, inuse=%b (#%0d)", - $time, CORE_ID, i, {staging_if[i].data.PC, 1'b0}, staging_if[i].data.tmask, timeout_ctr, - operands_busy_r, staging_if[i].data.uuid)); + ("%t: *** %s timeout: wid=%0d, PC=0x%0h, tmask=%b, cycles=%0d, inuse=%b (#%0d)", + $time, INSTANCE_ID, w, {staging_if[w].data.PC, 1'b0}, staging_if[w].data.tmask, timeout_ctr, + operands_busy, staging_if[w].data.uuid)); - `RUNTIME_ASSERT(~writeback_fire || inuse_regs[writeback_if[iw].data.rd] != 0, - ("%t: *** core%0d: invalid writeback register: wid=%0d, PC=0x%0h, tmask=%b, rd=%0d (#%0d)", - $time, CORE_ID, i, {writeback_if[iw].data.PC, 1'b0}, writeback_if[iw].data.tmask, writeback_if[iw].data.rd, writeback_if[iw].data.uuid)); + `RUNTIME_ASSERT(~writeback_fire || inuse_regs[writeback_if.data.rd] != 0, + ("%t: *** %s invalid writeback register: wid=%0d, PC=0x%0h, tmask=%b, rd=%0d (#%0d)", + $time, INSTANCE_ID, w, {writeback_if.data.PC, 1'b0}, writeback_if.data.tmask, writeback_if.data.rd, writeback_if.data.uuid)); `endif end - `RESET_RELAY (arb_reset, reset); + wire [PER_ISSUE_WARPS-1:0] arb_valid_in; + wire [PER_ISSUE_WARPS-1:0][DATAW-1:0] arb_data_in; + wire [PER_ISSUE_WARPS-1:0] arb_ready_in; - for (genvar i = 0; i < `ISSUE_WIDTH; ++i) begin - wire [ISSUE_RATIO-1:0] valid_in; - wire [ISSUE_RATIO-1:0][DATAW-1:0] data_in; - wire [ISSUE_RATIO-1:0] ready_in; - - for (genvar j = 0; j < ISSUE_RATIO; ++j) begin - wire operands_ready = ~(| staging_opds_busy[j * `ISSUE_WIDTH + i]); - assign valid_in[j] = staging_if[j * `ISSUE_WIDTH + i].valid && operands_ready; - assign data_in[j] = staging_if[j * `ISSUE_WIDTH + i].data; - assign staging_if[j * `ISSUE_WIDTH + i].ready = ready_in[j] && operands_ready; - end - - VX_stream_arb #( - .NUM_INPUTS (ISSUE_RATIO), - .DATAW (DATAW), - .ARBITER ("R"), - .OUT_BUF (2) - ) out_arb ( - .clk (clk), - .reset (arb_reset), - .valid_in (valid_in), - .ready_in (ready_in), - .data_in (data_in), - .data_out ({ - scoreboard_if[i].data.uuid, - scoreboard_if[i].data.tmask, - scoreboard_if[i].data.PC, - scoreboard_if[i].data.ex_type, - scoreboard_if[i].data.op_type, - scoreboard_if[i].data.op_args, - scoreboard_if[i].data.wb, - scoreboard_if[i].data.rd, - scoreboard_if[i].data.rs1, - scoreboard_if[i].data.rs2, - scoreboard_if[i].data.rs3 - }), - .valid_out (scoreboard_if[i].valid), - .ready_out (scoreboard_if[i].ready), - .sel_out (scoreboard_if[i].data.wis) - ); + for (genvar w = 0; w < PER_ISSUE_WARPS; ++w) begin + assign arb_valid_in[w] = staging_if[w].valid && operands_ready[w]; + assign arb_data_in[w] = staging_if[w].data; + assign staging_if[w].ready = arb_ready_in[w] && operands_ready[w]; end + `RESET_RELAY (arb_reset, reset); + + VX_stream_arb #( + .NUM_INPUTS (PER_ISSUE_WARPS), + .DATAW (DATAW), + .ARBITER ("F"), + .LUTRAM (1), + .OUT_BUF (4) // using 2-cycle EB for area reduction + ) out_arb ( + .clk (clk), + .reset (arb_reset), + .valid_in (arb_valid_in), + .ready_in (arb_ready_in), + .data_in (arb_data_in), + .data_out ({ + scoreboard_if.data.uuid, + scoreboard_if.data.tmask, + scoreboard_if.data.PC, + scoreboard_if.data.ex_type, + scoreboard_if.data.op_type, + scoreboard_if.data.op_args, + scoreboard_if.data.wb, + scoreboard_if.data.rd, + scoreboard_if.data.rs1, + scoreboard_if.data.rs2, + scoreboard_if.data.rs3 + }), + .valid_out (scoreboard_if.valid), + .ready_out (scoreboard_if.ready), + .sel_out (scoreboard_if.data.wis) + ); + endmodule diff --git a/hw/rtl/core/VX_sfu_unit.sv b/hw/rtl/core/VX_sfu_unit.sv index 6dc52c883..add229893 100644 --- a/hw/rtl/core/VX_sfu_unit.sv +++ b/hw/rtl/core/VX_sfu_unit.sv @@ -14,6 +14,7 @@ `include "VX_define.vh" module VX_sfu_unit import VX_gpu_pkg::*; #( + parameter `STRING INSTANCE_ID = "", parameter CORE_ID = 0 ) ( input wire clk, @@ -39,7 +40,7 @@ module VX_sfu_unit import VX_gpu_pkg::*; #( VX_commit_if.master commit_if [`ISSUE_WIDTH], VX_warp_ctl_if.master warp_ctl_if ); - `UNUSED_PARAM (CORE_ID) + `UNUSED_SPARAM (INSTANCE_ID) localparam BLOCK_SIZE = 1; localparam NUM_LANES = `NUM_SFU_LANES; localparam PID_BITS = `CLOG2(`NUM_THREADS / NUM_LANES); @@ -83,7 +84,7 @@ module VX_sfu_unit import VX_gpu_pkg::*; #( `RESET_RELAY (wctl_reset, reset); VX_wctl_unit #( - .CORE_ID (CORE_ID), + .INSTANCE_ID ($sformatf("%s-wctl", INSTANCE_ID)), .NUM_LANES (NUM_LANES) ) wctl_unit ( .clk (clk), @@ -111,6 +112,7 @@ module VX_sfu_unit import VX_gpu_pkg::*; #( `RESET_RELAY (csr_reset, reset); VX_csr_unit #( + .INSTANCE_ID ($sformatf("%s-csr", INSTANCE_ID)), .CORE_ID (CORE_ID), .NUM_LANES (NUM_LANES) ) csr_unit ( diff --git a/hw/rtl/core/VX_split_join.sv b/hw/rtl/core/VX_split_join.sv index 077ba61c6..7f887e602 100644 --- a/hw/rtl/core/VX_split_join.sv +++ b/hw/rtl/core/VX_split_join.sv @@ -14,7 +14,7 @@ `include "VX_define.vh" module VX_split_join import VX_gpu_pkg::*; #( - parameter CORE_ID = 0 + parameter `STRING INSTANCE_ID = "" ) ( input wire clk, input wire reset, @@ -31,7 +31,7 @@ module VX_split_join import VX_gpu_pkg::*; #( input wire [`NW_WIDTH-1:0] stack_wid, output wire [`DV_STACK_SIZEW-1:0] stack_ptr ); - `UNUSED_PARAM (CORE_ID) + `UNUSED_SPARAM (INSTANCE_ID) wire [(`NUM_THREADS+`PC_BITS)-1:0] ipdom_data [`NUM_WARPS-1:0]; wire [`DV_STACK_SIZEW-1:0] ipdom_q_ptr [`NUM_WARPS-1:0]; diff --git a/hw/rtl/core/VX_trace_pkg.sv b/hw/rtl/core/VX_trace_pkg.sv new file mode 100644 index 000000000..b4eae96fe --- /dev/null +++ b/hw/rtl/core/VX_trace_pkg.sv @@ -0,0 +1,399 @@ +// Copyright © 2019-2023 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +`ifndef VX_TRACE_PKG_VH +`define VX_TRACE_PKG_VH + +`include "VX_define.vh" + +package VX_trace_pkg; + +`ifdef SIMULATION + +`ifdef SV_DPI + import "DPI-C" function void dpi_trace(input int level, input string format /*verilator sformat*/); +`endif + + import VX_gpu_pkg::*; + + task trace_ex_type(input int level, input [`EX_BITS-1:0] ex_type); + case (ex_type) + `EX_ALU: `TRACE(level, ("ALU")); + `EX_LSU: `TRACE(level, ("LSU")); + `EX_FPU: `TRACE(level, ("FPU")); + `EX_SFU: `TRACE(level, ("SFU")); + default: `TRACE(level, ("?")); + endcase + endtask + + task trace_ex_op(input int level, + input [`EX_BITS-1:0] ex_type, + input [`INST_OP_BITS-1:0] op_type, + input VX_gpu_pkg::op_args_t op_args + ); + case (ex_type) + `EX_ALU: begin + case (op_args.alu.xtype) + `ALU_TYPE_ARITH: begin + if (op_args.alu.is_w) begin + if (op_args.alu.use_imm) begin + case (`INST_ALU_BITS'(op_type)) + `INST_ALU_ADD: `TRACE(level, ("ADDIW")); + `INST_ALU_SLL: `TRACE(level, ("SLLIW")); + `INST_ALU_SRL: `TRACE(level, ("SRLIW")); + `INST_ALU_SRA: `TRACE(level, ("SRAIW")); + default: `TRACE(level, ("?")); + endcase + end else begin + case (`INST_ALU_BITS'(op_type)) + `INST_ALU_ADD: `TRACE(level, ("ADDW")); + `INST_ALU_SUB: `TRACE(level, ("SUBW")); + `INST_ALU_SLL: `TRACE(level, ("SLLW")); + `INST_ALU_SRL: `TRACE(level, ("SRLW")); + `INST_ALU_SRA: `TRACE(level, ("SRAW")); + default: `TRACE(level, ("?")); + endcase + end + end else begin + if (op_args.alu.use_imm) begin + case (`INST_ALU_BITS'(op_type)) + `INST_ALU_ADD: `TRACE(level, ("ADDI")); + `INST_ALU_SLL: `TRACE(level, ("SLLI")); + `INST_ALU_SRL: `TRACE(level, ("SRLI")); + `INST_ALU_SRA: `TRACE(level, ("SRAI")); + `INST_ALU_SLT: `TRACE(level, ("SLTI")); + `INST_ALU_SLTU: `TRACE(level, ("SLTIU")); + `INST_ALU_XOR: `TRACE(level, ("XORI")); + `INST_ALU_OR: `TRACE(level, ("ORI")); + `INST_ALU_AND: `TRACE(level, ("ANDI")); + `INST_ALU_LUI: `TRACE(level, ("LUI")); + `INST_ALU_AUIPC: `TRACE(level, ("AUIPC")); + default: `TRACE(level, ("?")); + endcase + end else begin + case (`INST_ALU_BITS'(op_type)) + `INST_ALU_ADD: `TRACE(level, ("ADD")); + `INST_ALU_SUB: `TRACE(level, ("SUB")); + `INST_ALU_SLL: `TRACE(level, ("SLL")); + `INST_ALU_SRL: `TRACE(level, ("SRL")); + `INST_ALU_SRA: `TRACE(level, ("SRA")); + `INST_ALU_SLT: `TRACE(level, ("SLT")); + `INST_ALU_SLTU: `TRACE(level, ("SLTU")); + `INST_ALU_XOR: `TRACE(level, ("XOR")); + `INST_ALU_OR: `TRACE(level, ("OR")); + `INST_ALU_AND: `TRACE(level, ("AND")); + `INST_ALU_CZEQ: `TRACE(level, ("CZERO.EQZ")); + `INST_ALU_CZNE: `TRACE(level, ("CZERO.NEZ")); + default: `TRACE(level, ("?")); + endcase + end + end + end + `ALU_TYPE_BRANCH: begin + case (`INST_BR_BITS'(op_type)) + `INST_BR_EQ: `TRACE(level, ("BEQ")); + `INST_BR_NE: `TRACE(level, ("BNE")); + `INST_BR_LT: `TRACE(level, ("BLT")); + `INST_BR_GE: `TRACE(level, ("BGE")); + `INST_BR_LTU: `TRACE(level, ("BLTU")); + `INST_BR_GEU: `TRACE(level, ("BGEU")); + `INST_BR_JAL: `TRACE(level, ("JAL")); + `INST_BR_JALR: `TRACE(level, ("JALR")); + `INST_BR_ECALL: `TRACE(level, ("ECALL")); + `INST_BR_EBREAK:`TRACE(level, ("EBREAK")); + `INST_BR_URET: `TRACE(level, ("URET")); + `INST_BR_SRET: `TRACE(level, ("SRET")); + `INST_BR_MRET: `TRACE(level, ("MRET")); + default: `TRACE(level, ("?")); + endcase + end + `ALU_TYPE_MULDIV: begin + if (op_args.alu.is_w) begin + case (`INST_M_BITS'(op_type)) + `INST_M_MUL: `TRACE(level, ("MULW")); + `INST_M_DIV: `TRACE(level, ("DIVW")); + `INST_M_DIVU: `TRACE(level, ("DIVUW")); + `INST_M_REM: `TRACE(level, ("REMW")); + `INST_M_REMU: `TRACE(level, ("REMUW")); + default: `TRACE(level, ("?")); + endcase + end else begin + case (`INST_M_BITS'(op_type)) + `INST_M_MUL: `TRACE(level, ("MUL")); + `INST_M_MULH: `TRACE(level, ("MULH")); + `INST_M_MULHSU:`TRACE(level, ("MULHSU")); + `INST_M_MULHU: `TRACE(level, ("MULHU")); + `INST_M_DIV: `TRACE(level, ("DIV")); + `INST_M_DIVU: `TRACE(level, ("DIVU")); + `INST_M_REM: `TRACE(level, ("REM")); + `INST_M_REMU: `TRACE(level, ("REMU")); + default: `TRACE(level, ("?")); + endcase + end + end + default: `TRACE(level, ("?")); + endcase + end + `EX_LSU: begin + if (op_args.lsu.is_float) begin + case (`INST_LSU_BITS'(op_type)) + `INST_LSU_LW: `TRACE(level, ("FLW")); + `INST_LSU_LD: `TRACE(level, ("FLD")); + `INST_LSU_SW: `TRACE(level, ("FSW")); + `INST_LSU_SD: `TRACE(level, ("FSD")); + default: `TRACE(level, ("?")); + endcase + end else begin + case (`INST_LSU_BITS'(op_type)) + `INST_LSU_LB: `TRACE(level, ("LB")); + `INST_LSU_LH: `TRACE(level, ("LH")); + `INST_LSU_LW: `TRACE(level, ("LW")); + `INST_LSU_LD: `TRACE(level, ("LD")); + `INST_LSU_LBU:`TRACE(level, ("LBU")); + `INST_LSU_LHU:`TRACE(level, ("LHU")); + `INST_LSU_LWU:`TRACE(level, ("LWU")); + `INST_LSU_SB: `TRACE(level, ("SB")); + `INST_LSU_SH: `TRACE(level, ("SH")); + `INST_LSU_SW: `TRACE(level, ("SW")); + `INST_LSU_SD: `TRACE(level, ("SD")); + `INST_LSU_FENCE:`TRACE(level,("FENCE")); + default: `TRACE(level, ("?")); + endcase + end + end + `EX_FPU: begin + case (`INST_FPU_BITS'(op_type)) + `INST_FPU_ADD: begin + if (op_args.fpu.fmt[0]) + `TRACE(level, ("FADD.D")); + else + `TRACE(level, ("FADD.S")); + end + `INST_FPU_SUB: begin + if (op_args.fpu.fmt[0]) + `TRACE(level, ("FSUB.D")); + else + `TRACE(level, ("FSUB.S")); + end + `INST_FPU_MUL: begin + if (op_args.fpu.fmt[0]) + `TRACE(level, ("FMUL.D")); + else + `TRACE(level, ("FMUL.S")); + end + `INST_FPU_DIV: begin + if (op_args.fpu.fmt[0]) + `TRACE(level, ("FDIV.D")); + else + `TRACE(level, ("FDIV.S")); + end + `INST_FPU_SQRT: begin + if (op_args.fpu.fmt[0]) + `TRACE(level, ("FSQRT.D")); + else + `TRACE(level, ("FSQRT.S")); + end + `INST_FPU_MADD: begin + if (op_args.fpu.fmt[0]) + `TRACE(level, ("FMADD.D")); + else + `TRACE(level, ("FMADD.S")); + end + `INST_FPU_MSUB: begin + if (op_args.fpu.fmt[0]) + `TRACE(level, ("FMSUB.D")); + else + `TRACE(level, ("FMSUB.S")); + end + `INST_FPU_NMADD: begin + if (op_args.fpu.fmt[0]) + `TRACE(level, ("FNMADD.D")); + else + `TRACE(level, ("FNMADD.S")); + end + `INST_FPU_NMSUB: begin + if (op_args.fpu.fmt[0]) + `TRACE(level, ("FNMSUB.D")); + else + `TRACE(level, ("FNMSUB.S")); + end + `INST_FPU_CMP: begin + if (op_args.fpu.fmt[0]) begin + case (op_args.fpu.frm[1:0]) + 0: `TRACE(level, ("FLE.D")); + 1: `TRACE(level, ("FLT.D")); + 2: `TRACE(level, ("FEQ.D")); + default: `TRACE(level, ("?")); + endcase + end else begin + case (op_args.fpu.frm[1:0]) + 0: `TRACE(level, ("FLE.S")); + 1: `TRACE(level, ("FLT.S")); + 2: `TRACE(level, ("FEQ.S")); + default: `TRACE(level, ("?")); + endcase + end + end + `INST_FPU_F2F: begin + if (op_args.fpu.fmt[0]) begin + `TRACE(level, ("FCVT.D.S")); + end else begin + `TRACE(level, ("FCVT.S.D")); + end + end + `INST_FPU_F2I: begin + if (op_args.fpu.fmt[0]) begin + if (op_args.fpu.fmt[1]) begin + `TRACE(level, ("FCVT.L.D")); + end else begin + `TRACE(level, ("FCVT.W.D")); + end + end else begin + if (op_args.fpu.fmt[1]) begin + `TRACE(level, ("FCVT.L.S")); + end else begin + `TRACE(level, ("FCVT.W.S")); + end + end + end + `INST_FPU_F2U: begin + if (op_args.fpu.fmt[0]) begin + if (op_args.fpu.fmt[1]) begin + `TRACE(level, ("FCVT.LU.D")); + end else begin + `TRACE(level, ("FCVT.WU.D")); + end + end else begin + if (op_args.fpu.fmt[1]) begin + `TRACE(level, ("FCVT.LU.S")); + end else begin + `TRACE(level, ("FCVT.WU.S")); + end + end + end + `INST_FPU_I2F: begin + if (op_args.fpu.fmt[0]) begin + if (op_args.fpu.fmt[1]) begin + `TRACE(level, ("FCVT.D.L")); + end else begin + `TRACE(level, ("FCVT.D.W")); + end + end else begin + if (op_args.fpu.fmt[1]) begin + `TRACE(level, ("FCVT.S.L")); + end else begin + `TRACE(level, ("FCVT.S.W")); + end + end + end + `INST_FPU_U2F: begin + if (op_args.fpu.fmt[0]) begin + if (op_args.fpu.fmt[1]) begin + `TRACE(level, ("FCVT.D.LU")); + end else begin + `TRACE(level, ("FCVT.D.WU")); + end + end else begin + if (op_args.fpu.fmt[1]) begin + `TRACE(level, ("FCVT.S.LU")); + end else begin + `TRACE(level, ("FCVT.S.WU")); + end + end + end + `INST_FPU_MISC: begin + if (op_args.fpu.fmt[0]) begin + case (op_args.fpu.frm) + 0: `TRACE(level, ("FSGNJ.D")); + 1: `TRACE(level, ("FSGNJN.D")); + 2: `TRACE(level, ("FSGNJX.D")); + 3: `TRACE(level, ("FCLASS.D")); + 4: `TRACE(level, ("FMV.X.D")); + 5: `TRACE(level, ("FMV.D.X")); + 6: `TRACE(level, ("FMIN.D")); + 7: `TRACE(level, ("FMAX.D")); + endcase + end else begin + case (op_args.fpu.frm) + 0: `TRACE(level, ("FSGNJ.S")); + 1: `TRACE(level, ("FSGNJN.S")); + 2: `TRACE(level, ("FSGNJX.S")); + 3: `TRACE(level, ("FCLASS.S")); + 4: `TRACE(level, ("FMV.X.S")); + 5: `TRACE(level, ("FMV.S.X")); + 6: `TRACE(level, ("FMIN.S")); + 7: `TRACE(level, ("FMAX.S")); + endcase + end + end + default: `TRACE(level, ("?")); + endcase + end + `EX_SFU: begin + case (`INST_SFU_BITS'(op_type)) + `INST_SFU_TMC: `TRACE(level, ("TMC")); + `INST_SFU_WSPAWN:`TRACE(level, ("WSPAWN")); + `INST_SFU_SPLIT: begin if (op_args.wctl.is_neg) `TRACE(level, ("SPLIT.N")); else `TRACE(level, ("SPLIT")); end + `INST_SFU_JOIN: `TRACE(level, ("JOIN")); + `INST_SFU_BAR: `TRACE(level, ("BAR")); + `INST_SFU_PRED: begin if (op_args.wctl.is_neg) `TRACE(level, ("PRED.N")); else `TRACE(level, ("PRED")); end + `INST_SFU_CSRRW: begin if (op_args.csr.use_imm) `TRACE(level, ("CSRRWI")); else `TRACE(level, ("CSRRW")); end + `INST_SFU_CSRRS: begin if (op_args.csr.use_imm) `TRACE(level, ("CSRRSI")); else `TRACE(level, ("CSRRS")); end + `INST_SFU_CSRRC: begin if (op_args.csr.use_imm) `TRACE(level, ("CSRRCI")); else `TRACE(level, ("CSRRC")); end + default: `TRACE(level, ("?")); + endcase + end + default: `TRACE(level, ("?")); + endcase + endtask + + task trace_op_args(input int level, + input [`EX_BITS-1:0] ex_type, + input [`INST_OP_BITS-1:0] op_type, + input VX_gpu_pkg::op_args_t op_args + ); + case (ex_type) + `EX_ALU: begin + `TRACE(level, (", use_PC=%b, use_imm=%b, imm=0x%0h", op_args.alu.use_PC, op_args.alu.use_imm, op_args.alu.imm)); + end + `EX_LSU: begin + `TRACE(level, (", offset=0x%0h", op_args.lsu.offset)); + end + `EX_FPU: begin + `TRACE(level, (", fmt=0x%0h, frm=0x%0h", op_args.fpu.fmt, op_args.fpu.frm)); + end + `EX_SFU: begin + if (`INST_SFU_IS_CSR(op_type)) begin + `TRACE(level, (", addr=0x%0h, use_imm=%b, imm=0x%0h", op_args.csr.addr, op_args.csr.use_imm, op_args.csr.imm)); + end + end + default:; + endcase + endtask + + task trace_base_dcr(input int level, input [`VX_DCR_ADDR_WIDTH-1:0] addr); + case (addr) + `VX_DCR_BASE_STARTUP_ADDR0: `TRACE(level, ("STARTUP_ADDR0")); + `VX_DCR_BASE_STARTUP_ADDR1: `TRACE(level, ("STARTUP_ADDR1")); + `VX_DCR_BASE_STARTUP_ARG0: `TRACE(level, ("STARTUP_ARG0")); + `VX_DCR_BASE_STARTUP_ARG1: `TRACE(level, ("STARTUP_ARG1")); + `VX_DCR_BASE_MPM_CLASS: `TRACE(level, ("MPM_CLASS")); + default: `TRACE(level, ("?")); + endcase + endtask + +`endif + +endpackage + +`endif // VX_TRACE_PKG_VH diff --git a/hw/rtl/core/VX_wctl_unit.sv b/hw/rtl/core/VX_wctl_unit.sv index c59260809..132f679d4 100644 --- a/hw/rtl/core/VX_wctl_unit.sv +++ b/hw/rtl/core/VX_wctl_unit.sv @@ -14,7 +14,7 @@ `include "VX_define.vh" module VX_wctl_unit import VX_gpu_pkg::*; #( - parameter CORE_ID = 0, + parameter `STRING INSTANCE_ID = "", parameter NUM_LANES = 1 ) ( input wire clk, @@ -27,7 +27,7 @@ module VX_wctl_unit import VX_gpu_pkg::*; #( VX_warp_ctl_if.master warp_ctl_if, VX_commit_if.master commit_if ); - `UNUSED_PARAM (CORE_ID) + `UNUSED_SPARAM (INSTANCE_ID) localparam LANE_BITS = `CLOG2(NUM_LANES); localparam PID_BITS = `CLOG2(`NUM_THREADS / NUM_LANES); localparam PID_WIDTH = `UP(PID_BITS); diff --git a/hw/rtl/fpu/VX_fpu_dpi.sv b/hw/rtl/fpu/VX_fpu_dpi.sv index 0d5dbb1fb..781b5b88e 100644 --- a/hw/rtl/fpu/VX_fpu_dpi.sv +++ b/hw/rtl/fpu/VX_fpu_dpi.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,7 +15,7 @@ `ifdef FPU_DPI -module VX_fpu_dpi import VX_fpu_pkg::*; #( +module VX_fpu_dpi import VX_fpu_pkg::*; #( parameter NUM_LANES = 1, parameter TAG_WIDTH = 1, parameter OUT_BUF = 0 @@ -29,7 +29,7 @@ module VX_fpu_dpi import VX_fpu_pkg::*; #( input wire [NUM_LANES-1:0] mask_in, input wire [TAG_WIDTH-1:0] tag_in, - + input wire [`INST_FPU_BITS-1:0] op_type, input wire [`INST_FMT_BITS-1:0] fmt, input wire [`INST_FRM_BITS-1:0] frm, @@ -37,7 +37,7 @@ module VX_fpu_dpi import VX_fpu_pkg::*; #( input wire [NUM_LANES-1:0][`XLEN-1:0] dataa, input wire [NUM_LANES-1:0][`XLEN-1:0] datab, input wire [NUM_LANES-1:0][`XLEN-1:0] datac, - output wire [NUM_LANES-1:0][`XLEN-1:0] result, + output wire [NUM_LANES-1:0][`XLEN-1:0] result, output wire has_fflags, output wire [`FP_FLAGS_BITS-1:0] fflags, @@ -55,31 +55,31 @@ module VX_fpu_dpi import VX_fpu_pkg::*; #( localparam FPC_BITS = `LOG2UP(NUM_FPC); localparam RSP_DATAW = (NUM_LANES * `XLEN) + 1 + $bits(fflags_t) + TAG_WIDTH; - + wire [NUM_FPC-1:0] per_core_ready_in; wire [NUM_FPC-1:0][NUM_LANES-1:0][`XLEN-1:0] per_core_result; wire [NUM_FPC-1:0][TAG_WIDTH-1:0] per_core_tag_out; reg [NUM_FPC-1:0] per_core_ready_out; - wire [NUM_FPC-1:0] per_core_valid_out; - wire [NUM_FPC-1:0] per_core_has_fflags; - fflags_t [NUM_FPC-1:0] per_core_fflags; + wire [NUM_FPC-1:0] per_core_valid_out; + wire [NUM_FPC-1:0] per_core_has_fflags; + fflags_t [NUM_FPC-1:0] per_core_fflags; wire div_ready_in, sqrt_ready_in; wire [NUM_LANES-1:0][`XLEN-1:0] div_result, sqrt_result; wire [TAG_WIDTH-1:0] div_tag_out, sqrt_tag_out; wire div_ready_out, sqrt_ready_out; - wire div_valid_out, sqrt_valid_out; - wire div_has_fflags, sqrt_has_fflags; + wire div_valid_out, sqrt_valid_out; + wire div_has_fflags, sqrt_has_fflags; fflags_t div_fflags, sqrt_fflags; reg [FPC_BITS-1:0] core_select; reg is_fadd, is_fsub, is_fmul, is_fmadd, is_fmsub, is_fnmadd, is_fnmsub; - reg is_div, is_fcmp, is_itof, is_utof, is_ftoi, is_ftou, is_f2f; + reg is_div, is_fcmp, is_itof, is_utof, is_ftoi, is_ftou, is_f2f; reg dst_fmt, int_fmt; reg [NUM_LANES-1:0][63:0] operands [3]; - + always @(*) begin for (integer i = 0; i < NUM_LANES; ++i) begin operands[0][i] = 64'(dataa[i]); @@ -92,23 +92,23 @@ module VX_fpu_dpi import VX_fpu_pkg::*; #( always @(*) begin is_fadd = 0; - is_fsub = 0; - is_fmul = 0; + is_fsub = 0; + is_fmul = 0; is_fmadd = 0; is_fmsub = 0; - is_fnmadd = 0; - is_fnmsub = 0; - is_div = 0; + is_fnmadd = 0; + is_fnmsub = 0; + is_div = 0; is_fcmp = 0; is_itof = 0; is_utof = 0; is_ftoi = 0; is_ftou = 0; is_f2f = 0; - + dst_fmt = 0; int_fmt = 0; - + `ifdef FLEN_64 dst_fmt = fmt[0]; `endif @@ -132,23 +132,23 @@ module VX_fpu_dpi import VX_fpu_pkg::*; #( `INST_FPU_F2U: begin core_select = FPU_CVT; is_ftou = 1; end `INST_FPU_I2F: begin core_select = FPU_CVT; is_itof = 1; end `INST_FPU_U2F: begin core_select = FPU_CVT; is_utof = 1; end - `INST_FPU_F2F: begin core_select = FPU_CVT; is_f2f = 1; end + `INST_FPU_F2F: begin core_select = FPU_CVT; is_f2f = 1; end default: begin core_select = FPU_NCP; end endcase end - generate + generate begin : fma - + reg [NUM_LANES-1:0][`XLEN-1:0] result_fma; - wire [NUM_LANES-1:0][63:0] result_fadd; - wire [NUM_LANES-1:0][63:0] result_fsub; - wire [NUM_LANES-1:0][63:0] result_fmul; - wire [NUM_LANES-1:0][63:0] result_fmadd; - wire [NUM_LANES-1:0][63:0] result_fmsub; - wire [NUM_LANES-1:0][63:0] result_fnmadd; - wire [NUM_LANES-1:0][63:0] result_fnmsub; - + reg [NUM_LANES-1:0][63:0] result_fadd; + reg [NUM_LANES-1:0][63:0] result_fsub; + reg [NUM_LANES-1:0][63:0] result_fmul; + reg [NUM_LANES-1:0][63:0] result_fmadd; + reg [NUM_LANES-1:0][63:0] result_fmsub; + reg [NUM_LANES-1:0][63:0] result_fnmadd; + reg [NUM_LANES-1:0][63:0] result_fnmsub; + fflags_t [NUM_LANES-1:0] fflags_fma; fflags_t [NUM_LANES-1:0] fflags_fadd; fflags_t [NUM_LANES-1:0] fflags_fsub; @@ -162,7 +162,7 @@ module VX_fpu_dpi import VX_fpu_pkg::*; #( wire fma_ready = per_core_ready_out[FPU_FMA] || ~per_core_valid_out[FPU_FMA]; wire fma_fire = fma_valid && fma_ready; - always @(*) begin + always @(*) begin for (integer i = 0; i < NUM_LANES; ++i) begin dpi_fadd (fma_fire, int'(dst_fmt), operands[0][i], operands[1][i], frm, result_fadd[i], fflags_fadd[i]); dpi_fsub (fma_fire, int'(dst_fmt), operands[0][i], operands[1][i], frm, result_fsub[i], fflags_fsub[i]); @@ -175,20 +175,20 @@ module VX_fpu_dpi import VX_fpu_pkg::*; #( result_fma[i] = is_fadd ? result_fadd[i][`XLEN-1:0] : is_fsub ? result_fsub[i][`XLEN-1:0] : is_fmul ? result_fmul[i][`XLEN-1:0] : - is_fmadd ? result_fmadd[i][`XLEN-1:0] : + is_fmadd ? result_fmadd[i][`XLEN-1:0] : is_fmsub ? result_fmsub[i][`XLEN-1:0] : - is_fnmadd ? result_fnmadd[i][`XLEN-1:0] : + is_fnmadd ? result_fnmadd[i][`XLEN-1:0] : is_fnmsub ? result_fnmsub[i][`XLEN-1:0] : '0; fflags_fma[i] = is_fadd ? fflags_fadd[i] : is_fsub ? fflags_fsub[i] : is_fmul ? fflags_fmul[i] : - is_fmadd ? fflags_fmadd[i] : + is_fmadd ? fflags_fmadd[i] : is_fmsub ? fflags_fmsub[i] : - is_fnmadd ? fflags_fnmadd[i] : - is_fnmsub ? fflags_fnmsub[i] : - '0; + is_fnmadd ? fflags_fnmadd[i] : + is_fnmsub ? fflags_fnmsub[i] : + '0; end end @@ -213,19 +213,19 @@ module VX_fpu_dpi import VX_fpu_pkg::*; #( end endgenerate - generate + generate begin : fdiv reg [NUM_LANES-1:0][`XLEN-1:0] result_fdiv_r; - wire [NUM_LANES-1:0][63:0] result_fdiv; + reg [NUM_LANES-1:0][63:0] result_fdiv; fflags_t [NUM_LANES-1:0] fflags_fdiv; wire fdiv_valid = (valid_in && core_select == FPU_DIVSQRT) && is_div; wire fdiv_ready = div_ready_out || ~div_valid_out; wire fdiv_fire = fdiv_valid && fdiv_ready; - - always @(*) begin - for (integer i = 0; i < NUM_LANES; ++i) begin + + always @(*) begin + for (integer i = 0; i < NUM_LANES; ++i) begin dpi_fdiv (fdiv_fire, int'(dst_fmt), operands[0][i], operands[1][i], frm, result_fdiv[i], fflags_fdiv[i]); result_fdiv_r[i] = result_fdiv[i][`XLEN-1:0]; end @@ -252,18 +252,18 @@ module VX_fpu_dpi import VX_fpu_pkg::*; #( end endgenerate - generate + generate begin : fsqrt reg [NUM_LANES-1:0][`XLEN-1:0] result_fsqrt_r; - wire [NUM_LANES-1:0][63:0] result_fsqrt; + reg [NUM_LANES-1:0][63:0] result_fsqrt; fflags_t [NUM_LANES-1:0] fflags_fsqrt; wire fsqrt_valid = (valid_in && core_select == FPU_DIVSQRT) && ~is_div; - wire fsqrt_ready = sqrt_ready_out || ~sqrt_valid_out; + wire fsqrt_ready = sqrt_ready_out || ~sqrt_valid_out; wire fsqrt_fire = fsqrt_valid && fsqrt_ready; - - always @(*) begin + + always @(*) begin for (integer i = 0; i < NUM_LANES; ++i) begin dpi_fsqrt (fsqrt_fire, int'(dst_fmt), operands[0][i], frm, result_fsqrt[i], fflags_fsqrt[i]); result_fsqrt_r[i] = result_fsqrt[i][`XLEN-1:0]; @@ -295,12 +295,12 @@ module VX_fpu_dpi import VX_fpu_pkg::*; #( begin : fcvt reg [NUM_LANES-1:0][`XLEN-1:0] result_fcvt; - wire [NUM_LANES-1:0][63:0] result_itof; - wire [NUM_LANES-1:0][63:0] result_utof; - wire [NUM_LANES-1:0][63:0] result_ftoi; - wire [NUM_LANES-1:0][63:0] result_ftou; - wire [NUM_LANES-1:0][63:0] result_f2f; - + reg [NUM_LANES-1:0][63:0] result_itof; + reg [NUM_LANES-1:0][63:0] result_utof; + reg [NUM_LANES-1:0][63:0] result_ftoi; + reg [NUM_LANES-1:0][63:0] result_ftou; + reg [NUM_LANES-1:0][63:0] result_f2f; + fflags_t [NUM_LANES-1:0] fflags_fcvt; fflags_t [NUM_LANES-1:0] fflags_itof; fflags_t [NUM_LANES-1:0] fflags_utof; @@ -310,20 +310,20 @@ module VX_fpu_dpi import VX_fpu_pkg::*; #( wire fcvt_valid = (valid_in && core_select == FPU_CVT); wire fcvt_ready = per_core_ready_out[FPU_CVT] || ~per_core_valid_out[FPU_CVT]; wire fcvt_fire = fcvt_valid && fcvt_ready; - - always @(*) begin + + always @(*) begin for (integer i = 0; i < NUM_LANES; ++i) begin dpi_itof (fcvt_fire, int'(dst_fmt), int'(int_fmt), operands[0][i], frm, result_itof[i], fflags_itof[i]); dpi_utof (fcvt_fire, int'(dst_fmt), int'(int_fmt), operands[0][i], frm, result_utof[i], fflags_utof[i]); dpi_ftoi (fcvt_fire, int'(int_fmt), int'(dst_fmt), operands[0][i], frm, result_ftoi[i], fflags_ftoi[i]); dpi_ftou (fcvt_fire, int'(int_fmt), int'(dst_fmt), operands[0][i], frm, result_ftou[i], fflags_ftou[i]); - dpi_f2f (fcvt_fire, int'(dst_fmt), operands[0][i], result_f2f[i]); + dpi_f2f (fcvt_fire, int'(dst_fmt), operands[0][i], result_f2f[i]); result_fcvt[i] = is_itof ? result_itof[i][`XLEN-1:0] : is_utof ? result_utof[i][`XLEN-1:0] : is_ftoi ? result_ftoi[i][`XLEN-1:0] : - is_ftou ? result_ftou[i][`XLEN-1:0] : - is_f2f ? result_f2f[i][`XLEN-1:0] : + is_ftou ? result_ftou[i][`XLEN-1:0] : + is_f2f ? result_f2f[i][`XLEN-1:0] : '0; fflags_fcvt[i] = is_itof ? fflags_itof[i] : @@ -355,19 +355,19 @@ module VX_fpu_dpi import VX_fpu_pkg::*; #( end endgenerate - generate + generate begin : fncp reg [NUM_LANES-1:0][`XLEN-1:0] result_fncp; - wire [NUM_LANES-1:0][63:0] result_fclss; - wire [NUM_LANES-1:0][63:0] result_flt; - wire [NUM_LANES-1:0][63:0] result_fle; - wire [NUM_LANES-1:0][63:0] result_feq; - wire [NUM_LANES-1:0][63:0] result_fmin; - wire [NUM_LANES-1:0][63:0] result_fmax; - wire [NUM_LANES-1:0][63:0] result_fsgnj; - wire [NUM_LANES-1:0][63:0] result_fsgnjn; - wire [NUM_LANES-1:0][63:0] result_fsgnjx; + reg [NUM_LANES-1:0][63:0] result_fclss; + reg [NUM_LANES-1:0][63:0] result_flt; + reg [NUM_LANES-1:0][63:0] result_fle; + reg [NUM_LANES-1:0][63:0] result_feq; + reg [NUM_LANES-1:0][63:0] result_fmin; + reg [NUM_LANES-1:0][63:0] result_fmax; + reg [NUM_LANES-1:0][63:0] result_fsgnj; + reg [NUM_LANES-1:0][63:0] result_fsgnjn; + reg [NUM_LANES-1:0][63:0] result_fsgnjx; reg [NUM_LANES-1:0][63:0] result_fmvx; reg [NUM_LANES-1:0][63:0] result_fmvf; @@ -381,15 +381,15 @@ module VX_fpu_dpi import VX_fpu_pkg::*; #( wire fncp_valid = (valid_in && core_select == FPU_NCP); wire fncp_ready = per_core_ready_out[FPU_NCP] || ~per_core_valid_out[FPU_NCP]; wire fncp_fire = fncp_valid && fncp_ready; - - always @(*) begin + + always @(*) begin for (integer i = 0; i < NUM_LANES; ++i) begin dpi_fclss (fncp_fire, int'(dst_fmt), operands[0][i], result_fclss[i]); dpi_fle (fncp_fire, int'(dst_fmt), operands[0][i], operands[1][i], result_fle[i], fflags_fle[i]); - dpi_flt (fncp_fire, int'(dst_fmt), operands[0][i], operands[1][i], result_flt[i], fflags_flt[i]); + dpi_flt (fncp_fire, int'(dst_fmt), operands[0][i], operands[1][i], result_flt[i], fflags_flt[i]); dpi_feq (fncp_fire, int'(dst_fmt), operands[0][i], operands[1][i], result_feq[i], fflags_feq[i]); dpi_fmin (fncp_fire, int'(dst_fmt), operands[0][i], operands[1][i], result_fmin[i], fflags_fmin[i]); - dpi_fmax (fncp_fire, int'(dst_fmt), operands[0][i], operands[1][i], result_fmax[i], fflags_fmax[i]); + dpi_fmax (fncp_fire, int'(dst_fmt), operands[0][i], operands[1][i], result_fmax[i], fflags_fmax[i]); dpi_fsgnj (fncp_fire, int'(dst_fmt), operands[0][i], operands[1][i], result_fsgnj[i]); dpi_fsgnjn (fncp_fire, int'(dst_fmt), operands[0][i], operands[1][i], result_fsgnjn[i]); dpi_fsgnjx (fncp_fire, int'(dst_fmt), operands[0][i], operands[1][i], result_fsgnjx[i]); @@ -431,7 +431,7 @@ module VX_fpu_dpi import VX_fpu_pkg::*; #( .data_in ({fncp_valid, tag_in, has_fflags_fncp, result_fncp, fflags_merged}), .data_out ({per_core_valid_out[FPU_NCP], per_core_tag_out[FPU_NCP], per_core_has_fflags[FPU_NCP], per_core_result[FPU_NCP], per_core_fflags[FPU_NCP]}) ); - + assign per_core_ready_in[FPU_NCP] = fncp_ready; end @@ -443,15 +443,15 @@ module VX_fpu_dpi import VX_fpu_pkg::*; #( VX_stream_arb #( .NUM_INPUTS (2), - .DATAW (RSP_DATAW), + .DATAW (RSP_DATAW), .ARBITER ("R"), .OUT_BUF (0) ) div_sqrt_arb ( .clk (clk), .reset (reset), - .valid_in ({sqrt_valid_out, div_valid_out}), + .valid_in ({sqrt_valid_out, div_valid_out}), .ready_in ({sqrt_ready_out, div_ready_out}), - .data_in ({{sqrt_result, sqrt_has_fflags, sqrt_fflags, sqrt_tag_out}, + .data_in ({{sqrt_result, sqrt_has_fflags, sqrt_fflags, sqrt_tag_out}, {div_result, div_has_fflags, div_fflags, div_tag_out}}), .data_out ({per_core_result[FPU_DIVSQRT], per_core_has_fflags[FPU_DIVSQRT], per_core_fflags[FPU_DIVSQRT], per_core_tag_out[FPU_DIVSQRT]}), .valid_out (per_core_valid_out[FPU_DIVSQRT]), @@ -469,13 +469,13 @@ module VX_fpu_dpi import VX_fpu_pkg::*; #( VX_stream_arb #( .NUM_INPUTS (NUM_FPC), - .DATAW (RSP_DATAW), - .ARBITER ("R"), + .DATAW (RSP_DATAW), + .ARBITER ("F"), .OUT_BUF (OUT_BUF) ) rsp_arb ( .clk (clk), .reset (reset), - .valid_in (per_core_valid_out), + .valid_in (per_core_valid_out), .ready_in (per_core_ready_out), .data_in (per_core_data_out), .data_out ({result, has_fflags, fflags, tag_out}), diff --git a/hw/rtl/fpu/VX_fpu_dsp.sv b/hw/rtl/fpu/VX_fpu_dsp.sv index a219ce771..ad398dcd7 100644 --- a/hw/rtl/fpu/VX_fpu_dsp.sv +++ b/hw/rtl/fpu/VX_fpu_dsp.sv @@ -289,14 +289,14 @@ module VX_fpu_dsp import VX_fpu_pkg::*; #( end wire [NUM_LANES-1:0][31:0] result_s; - + wire [1:0] op_ret_int_out; `UNUSED_VAR (op_ret_int_out) VX_stream_arb #( .NUM_INPUTS (NUM_FPC), .DATAW (RSP_DATAW + 2), - .ARBITER ("R"), + .ARBITER ("F"), .OUT_BUF (OUT_BUF) ) rsp_arb ( .clk (clk), diff --git a/hw/rtl/fpu/VX_fpu_fma.sv b/hw/rtl/fpu/VX_fpu_fma.sv index bfbb6458c..8151fbf55 100644 --- a/hw/rtl/fpu/VX_fpu_fma.sv +++ b/hw/rtl/fpu/VX_fpu_fma.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,7 +21,7 @@ module VX_fpu_fma import VX_fpu_pkg::*; #( parameter TAG_WIDTH = 1 ) ( input wire clk, - input wire reset, + input wire reset, output wire ready_in, input wire valid_in, @@ -29,7 +29,7 @@ module VX_fpu_fma import VX_fpu_pkg::*; #( input wire [NUM_LANES-1:0] mask_in, input wire [TAG_WIDTH-1:0] tag_in, - + input wire [`INST_FRM_BITS-1:0] frm, input wire is_madd, @@ -39,7 +39,7 @@ module VX_fpu_fma import VX_fpu_pkg::*; #( input wire [NUM_LANES-1:0][31:0] dataa, input wire [NUM_LANES-1:0][31:0] datab, input wire [NUM_LANES-1:0][31:0] datac, - output wire [NUM_LANES-1:0][31:0] result, + output wire [NUM_LANES-1:0][31:0] result, output wire has_fflags, output wire [`FP_FLAGS_BITS-1:0] fflags, @@ -52,11 +52,11 @@ module VX_fpu_fma import VX_fpu_pkg::*; #( `UNUSED_VAR (frm) wire [NUM_LANES-1:0][3*32-1:0] data_in; - wire [NUM_LANES-1:0] mask_out; + wire [NUM_LANES-1:0] mask_out; wire [NUM_LANES-1:0][(`FP_FLAGS_BITS+32)-1:0] data_out; wire [NUM_LANES-1:0][`FP_FLAGS_BITS-1:0] fflags_out; - wire pe_enable; + wire pe_enable; wire [NUM_PES-1:0][3*32-1:0] pe_data_in; wire [NUM_PES-1:0][(`FP_FLAGS_BITS+32)-1:0] pe_data_out; @@ -66,7 +66,7 @@ module VX_fpu_fma import VX_fpu_pkg::*; #( always @(*) begin if (is_madd) begin // MADD / MSUB / NMADD / NMSUB - a[i] = is_neg ? {~dataa[i][31], dataa[i][30:0]} : dataa[i]; + a[i] = is_neg ? {~dataa[i][31], dataa[i][30:0]} : dataa[i]; b[i] = datab[i]; c[i] = (is_neg ^ is_sub) ? {~datac[i][31], datac[i][30:0]} : datac[i]; end else begin @@ -81,7 +81,7 @@ module VX_fpu_fma import VX_fpu_pkg::*; #( b[i] = dataa[i]; c[i] = is_sub ? {~datab[i][31], datab[i][30:0]} : datab[i]; end - end + end end end @@ -90,15 +90,15 @@ module VX_fpu_fma import VX_fpu_pkg::*; #( assign data_in[i][32 +: 32] = b[i]; assign data_in[i][64 +: 32] = c[i]; end - + VX_pe_serializer #( - .NUM_LANES (NUM_LANES), - .NUM_PES (NUM_PES), + .NUM_LANES (NUM_LANES), + .NUM_PES (NUM_PES), .LATENCY (`LATENCY_FMA), .DATA_IN_WIDTH(3*32), .DATA_OUT_WIDTH(`FP_FLAGS_BITS + 32), .TAG_WIDTH (NUM_LANES + TAG_WIDTH), - .PE_REG (1) + .PE_REG ((NUM_LANES != NUM_PES) ? 1 : 0) ) pe_serializer ( .clk (clk), .reset (reset), @@ -123,7 +123,7 @@ module VX_fpu_fma import VX_fpu_pkg::*; #( fflags_t [NUM_LANES-1:0] per_lane_fflags; `ifdef QUARTUS - + for (genvar i = 0; i < NUM_PES; ++i) begin acl_fmadd fmadd ( .clk (clk), @@ -136,7 +136,7 @@ module VX_fpu_fma import VX_fpu_pkg::*; #( ); assign pe_data_out[i][32 +: `FP_FLAGS_BITS] = 'x; end - + assign has_fflags = 0; assign per_lane_fflags = 'x; @@ -144,7 +144,7 @@ module VX_fpu_fma import VX_fpu_pkg::*; #( for (genvar i = 0; i < NUM_PES; ++i) begin wire [2:0] tuser; - + xil_fma fma ( .aclk (clk), .aclken (pe_enable), @@ -172,15 +172,15 @@ module VX_fpu_fma import VX_fpu_pkg::*; #( `UNUSED_VAR (r) fflags_t f; - always @(*) begin + always @(*) begin dpi_fmadd ( - pe_enable, - int'(0), - {32'hffffffff, pe_data_in[i][0 +: 32]}, - {32'hffffffff, pe_data_in[i][32 +: 32]}, - {32'hffffffff, pe_data_in[i][64 +: 32]}, - frm, - r, + pe_enable, + int'(0), + {32'hffffffff, pe_data_in[i][0 +: 32]}, + {32'hffffffff, pe_data_in[i][32 +: 32]}, + {32'hffffffff, pe_data_in[i][64 +: 32]}, + frm, + r, f ); end diff --git a/hw/rtl/fpu/VX_fpu_fpnew.sv b/hw/rtl/fpu/VX_fpu_fpnew.sv index cb8dddfb0..9ee7f1a2c 100644 --- a/hw/rtl/fpu/VX_fpu_fpnew.sv +++ b/hw/rtl/fpu/VX_fpu_fpnew.sv @@ -105,7 +105,7 @@ module VX_fpu_fpnew `UNUSED_VAR (fmt) always @(*) begin - fpu_op = 'x; + fpu_op = fpnew_pkg::operation_e'('x); fpu_rnd = frm; fpu_op_mod = 0; fpu_has_fflags = 1; diff --git a/hw/rtl/interfaces/VX_commit_sched_if.sv b/hw/rtl/interfaces/VX_commit_sched_if.sv index 487a3c6c0..eab794c93 100644 --- a/hw/rtl/interfaces/VX_commit_sched_if.sv +++ b/hw/rtl/interfaces/VX_commit_sched_if.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,17 +15,14 @@ interface VX_commit_sched_if (); - wire [`ISSUE_WIDTH-1:0] committed; - wire [`ISSUE_WIDTH-1:0][`NW_WIDTH-1:0] committed_wid; + wire [`NUM_WARPS-1:0] committed_warps; modport master ( - output committed, - output committed_wid + output committed_warps ); modport slave ( - input committed, - input committed_wid + input committed_warps ); endinterface diff --git a/hw/rtl/interfaces/VX_decode_if.sv b/hw/rtl/interfaces/VX_decode_if.sv index b35fe002f..e99e073fd 100644 --- a/hw/rtl/interfaces/VX_decode_if.sv +++ b/hw/rtl/interfaces/VX_decode_if.sv @@ -13,11 +13,14 @@ `include "VX_define.vh" -interface VX_decode_if import VX_gpu_pkg::*; (); +interface VX_decode_if import VX_gpu_pkg::*; #( + parameter NUM_WARPS = `NUM_WARPS, + parameter NW_WIDTH = `LOG2UP(NUM_WARPS) +); typedef struct packed { logic [`UUID_WIDTH-1:0] uuid; - logic [`NW_WIDTH-1:0] wid; + logic [NW_WIDTH-1:0] wid; logic [`NUM_THREADS-1:0] tmask; logic [`PC_BITS-1:0] PC; logic [`EX_BITS-1:0] ex_type; @@ -34,7 +37,7 @@ interface VX_decode_if import VX_gpu_pkg::*; (); data_t data; logic ready; `ifndef L1_ENABLE - wire [`NUM_WARPS-1:0] ibuf_pop; + wire [NUM_WARPS-1:0] ibuf_pop; `endif modport master ( diff --git a/hw/rtl/interfaces/VX_pipeline_perf_if.sv b/hw/rtl/interfaces/VX_pipeline_perf_if.sv index 7d4218759..840630353 100644 --- a/hw/rtl/interfaces/VX_pipeline_perf_if.sv +++ b/hw/rtl/interfaces/VX_pipeline_perf_if.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -13,39 +13,29 @@ `include "VX_define.vh" -interface VX_pipeline_perf_if (); - wire [`PERF_CTR_BITS-1:0] sched_idles; - wire [`PERF_CTR_BITS-1:0] sched_stalls; - wire [`PERF_CTR_BITS-1:0] ibf_stalls; - wire [`PERF_CTR_BITS-1:0] scb_stalls; - wire [`PERF_CTR_BITS-1:0] units_uses [`NUM_EX_UNITS]; - wire [`PERF_CTR_BITS-1:0] sfu_uses [`NUM_SFU_UNITS]; +interface VX_pipeline_perf_if import VX_gpu_pkg::*; (); + sched_perf_t sched; + issue_perf_t issue; wire [`PERF_CTR_BITS-1:0] ifetches; wire [`PERF_CTR_BITS-1:0] loads; - wire [`PERF_CTR_BITS-1:0] stores; + wire [`PERF_CTR_BITS-1:0] stores; wire [`PERF_CTR_BITS-1:0] ifetch_latency; wire [`PERF_CTR_BITS-1:0] load_latency; - modport schedule ( - output sched_idles, - output sched_stalls - ); - - modport issue ( - output ibf_stalls, - output scb_stalls, - output units_uses, - output sfu_uses + modport master ( + output sched, + output issue, + output ifetches, + output loads, + output stores, + output ifetch_latency, + output load_latency ); modport slave ( - input sched_idles, - input sched_stalls, - input ibf_stalls, - input scb_stalls, - input units_uses, - input sfu_uses, + input sched, + input issue, input ifetches, input loads, input stores, diff --git a/hw/rtl/libs/VX_avs_adapter.sv b/hw/rtl/libs/VX_avs_adapter.sv index 6c70770cb..6e9abf597 100644 --- a/hw/rtl/libs/VX_avs_adapter.sv +++ b/hw/rtl/libs/VX_avs_adapter.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -14,11 +14,11 @@ `include "VX_define.vh" `TRACING_OFF -module VX_avs_adapter #( - parameter DATA_WIDTH = 1, - parameter ADDR_WIDTH = 1, +module VX_avs_adapter #( + parameter DATA_WIDTH = 1, + parameter ADDR_WIDTH = 1, parameter BURST_WIDTH = 1, - parameter NUM_BANKS = 1, + parameter NUM_BANKS = 1, parameter TAG_WIDTH = 1, parameter RD_QUEUE_SIZE = 1, parameter REQ_OUT_BUF = 0, @@ -29,15 +29,15 @@ module VX_avs_adapter #( // Memory request input wire mem_req_valid, - input wire mem_req_rw, - input wire [DATA_WIDTH/8-1:0] mem_req_byteen, + input wire mem_req_rw, + input wire [DATA_WIDTH/8-1:0] mem_req_byteen, input wire [ADDR_WIDTH-1:0] mem_req_addr, input wire [DATA_WIDTH-1:0] mem_req_data, input wire [TAG_WIDTH-1:0] mem_req_tag, output wire mem_req_ready, - // Memory response - output wire mem_rsp_valid, + // Memory response + output wire mem_rsp_valid, output wire [DATA_WIDTH-1:0] mem_rsp_data, output wire [TAG_WIDTH-1:0] mem_rsp_tag, input wire mem_rsp_ready, @@ -60,7 +60,7 @@ module VX_avs_adapter #( localparam BANK_OFFSETW = ADDR_WIDTH - LOG2_NUM_BANKS; // Requests handling ////////////////////////////////////////////////////// - + wire [NUM_BANKS-1:0] req_queue_push, req_queue_pop; wire [NUM_BANKS-1:0][TAG_WIDTH-1:0] req_queue_tag_out; wire [NUM_BANKS-1:0] req_queue_going_full; @@ -70,38 +70,40 @@ module VX_avs_adapter #( wire [NUM_BANKS-1:0] bank_req_ready; if (NUM_BANKS > 1) begin - assign req_bank_sel = mem_req_addr[BANK_ADDRW-1:0]; + assign req_bank_sel = mem_req_addr[BANK_ADDRW-1:0]; end else begin assign req_bank_sel = '0; end assign req_bank_off = mem_req_addr[ADDR_WIDTH-1:LOG2_NUM_BANKS]; - for (genvar i = 0; i < NUM_BANKS; ++i) begin + for (genvar i = 0; i < NUM_BANKS; ++i) begin assign req_queue_push[i] = mem_req_valid && ~mem_req_rw && bank_req_ready[i] && (req_bank_sel == i); end for (genvar i = 0; i < NUM_BANKS; ++i) begin - VX_pending_size #( + VX_pending_size #( .SIZE (RD_QUEUE_SIZE) ) pending_size ( .clk (clk), .reset (reset), .incr (req_queue_push[i]), - .decr (req_queue_pop[i]), + .decr (req_queue_pop[i]), + `UNUSED_PIN (empty), + `UNUSED_PIN (alm_empty), .full (req_queue_going_full[i]), - .size (req_queue_size[i]), - `UNUSED_PIN (empty) - ); + `UNUSED_PIN (alm_full), + .size (req_queue_size[i]) + ); `UNUSED_VAR (req_queue_size) - + VX_fifo_queue #( .DATAW (TAG_WIDTH), .DEPTH (RD_QUEUE_SIZE) ) rd_req_queue ( .clk (clk), .reset (reset), - .push (req_queue_push[i]), + .push (req_queue_push[i]), .pop (req_queue_pop[i]), .data_in (mem_req_tag), .data_out (req_queue_tag_out[i]), @@ -111,9 +113,9 @@ module VX_avs_adapter #( `UNUSED_PIN (alm_full), `UNUSED_PIN (size) ); - end + end - for (genvar i = 0; i < NUM_BANKS; ++i) begin + for (genvar i = 0; i < NUM_BANKS; ++i) begin wire valid_out; wire rw_out; wire [DATA_SIZE-1:0] byteen_out; @@ -174,7 +176,7 @@ module VX_avs_adapter #( .reset (reset), .push (avs_readdatavalid[i]), .pop (req_queue_pop[i]), - .data_in (avs_readdata[i]), + .data_in (avs_readdata[i]), .data_out (rsp_queue_data_out[i]), .empty (rsp_queue_empty[i]), `UNUSED_PIN (full), @@ -183,7 +185,7 @@ module VX_avs_adapter #( `UNUSED_PIN (size) ); end - + for (genvar i = 0; i < NUM_BANKS; ++i) begin assign rsp_arb_valid_in[i] = !rsp_queue_empty[i]; assign rsp_arb_data_in[i] = {rsp_queue_data_out[i], req_queue_tag_out[i]}; diff --git a/hw/rtl/libs/VX_cyclic_arbiter.sv b/hw/rtl/libs/VX_cyclic_arbiter.sv index 63b621361..c4a42da14 100644 --- a/hw/rtl/libs/VX_cyclic_arbiter.sv +++ b/hw/rtl/libs/VX_cyclic_arbiter.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,22 +16,21 @@ `TRACING_OFF module VX_cyclic_arbiter #( parameter NUM_REQS = 1, - parameter LOCK_ENABLE = 0, parameter LOG_NUM_REQS = `LOG2UP(NUM_REQS) ) ( input wire clk, input wire reset, - input wire [NUM_REQS-1:0] requests, + input wire [NUM_REQS-1:0] requests, output wire [LOG_NUM_REQS-1:0] grant_index, - output wire [NUM_REQS-1:0] grant_onehot, + output wire [NUM_REQS-1:0] grant_onehot, output wire grant_valid, - input wire grant_unlock + input wire grant_ready ); - if (NUM_REQS == 1) begin + if (NUM_REQS == 1) begin `UNUSED_VAR (clk) - `UNUSED_VAR (reset) - + `UNUSED_VAR (reset) + assign grant_index = '0; assign grant_onehot = requests; assign grant_valid = requests[0]; @@ -45,10 +44,10 @@ module VX_cyclic_arbiter #( always @(posedge clk) begin if (reset) begin grant_index_r <= '0; - end else begin + end else begin if (!IS_POW2 && grant_index_r == LOG_NUM_REQS'(NUM_REQS-1)) begin grant_index_r <= '0; - end else if (!LOCK_ENABLE || ~grant_valid || grant_unlock) begin + end else if (~grant_valid || grant_ready) begin grant_index_r <= grant_index_r + LOG_NUM_REQS'(1); end end @@ -60,11 +59,11 @@ module VX_cyclic_arbiter #( grant_onehot_r[grant_index_r] = 1'b1; end - assign grant_index = grant_index_r; + assign grant_index = grant_index_r; assign grant_onehot = grant_onehot_r; assign grant_valid = requests[grant_index_r]; end - + endmodule `TRACING_ON diff --git a/hw/rtl/libs/VX_dp_ram.sv b/hw/rtl/libs/VX_dp_ram.sv index 8ecfd8378..fa11a541f 100644 --- a/hw/rtl/libs/VX_dp_ram.sv +++ b/hw/rtl/libs/VX_dp_ram.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -17,20 +17,21 @@ module VX_dp_ram #( parameter DATAW = 1, parameter SIZE = 1, + parameter ADDR_MIN = 0, parameter WRENW = 1, parameter OUT_REG = 0, parameter NO_RWCHECK = 0, - parameter LUTRAM = 0, + parameter LUTRAM = 0, parameter INIT_ENABLE = 0, parameter INIT_FILE = "", parameter [DATAW-1:0] INIT_VALUE = 0, parameter ADDRW = `LOG2UP(SIZE) -) ( +) ( input wire clk, input wire read, input wire write, input wire [WRENW-1:0] wren, - input wire [ADDRW-1:0] waddr, + input wire [ADDRW-1:0] waddr, input wire [DATAW-1:0] wdata, input wire [ADDRW-1:0] raddr, output wire [DATAW-1:0] rdata @@ -48,16 +49,16 @@ module VX_dp_ram #( ram[i] = INIT_VALUE; \ end \ end - + `UNUSED_VAR (read) `ifdef SYNTHESIS if (WRENW > 1) begin `ifdef QUARTUS if (LUTRAM != 0) begin - if (OUT_REG != 0) begin + if (OUT_REG != 0) begin reg [DATAW-1:0] rdata_r; - `USE_FAST_BRAM reg [WRENW-1:0][WSELW-1:0] ram [SIZE-1:0]; + `USE_FAST_BRAM reg [WRENW-1:0][WSELW-1:0] ram [ADDR_MIN:SIZE-1]; `RAM_INITIALIZATION always @(posedge clk) begin if (write) begin @@ -72,7 +73,7 @@ module VX_dp_ram #( end assign rdata = rdata_r; end else begin - `USE_FAST_BRAM reg [WRENW-1:0][WSELW-1:0] ram [SIZE-1:0]; + `USE_FAST_BRAM reg [WRENW-1:0][WSELW-1:0] ram [ADDR_MIN:SIZE-1]; `RAM_INITIALIZATION always @(posedge clk) begin if (write) begin @@ -87,7 +88,7 @@ module VX_dp_ram #( end else begin if (OUT_REG != 0) begin reg [DATAW-1:0] rdata_r; - reg [WRENW-1:0][WSELW-1:0] ram [SIZE-1:0]; + reg [WRENW-1:0][WSELW-1:0] ram [ADDR_MIN:SIZE-1]; `RAM_INITIALIZATION always @(posedge clk) begin if (write) begin @@ -103,7 +104,7 @@ module VX_dp_ram #( assign rdata = rdata_r; end else begin if (NO_RWCHECK != 0) begin - `NO_RW_RAM_CHECK reg [WRENW-1:0][WSELW-1:0] ram [SIZE-1:0]; + `NO_RW_RAM_CHECK reg [WRENW-1:0][WSELW-1:0] ram [ADDR_MIN:SIZE-1]; `RAM_INITIALIZATION always @(posedge clk) begin if (write) begin @@ -115,7 +116,7 @@ module VX_dp_ram #( end assign rdata = ram[raddr]; end else begin - reg [WRENW-1:0][WSELW-1:0] ram [SIZE-1:0]; + reg [WRENW-1:0][WSELW-1:0] ram [ADDR_MIN:SIZE-1]; `RAM_INITIALIZATION always @(posedge clk) begin if (write) begin @@ -132,9 +133,9 @@ module VX_dp_ram #( `else // default synthesis if (LUTRAM != 0) begin - `USE_FAST_BRAM reg [DATAW-1:0] ram [SIZE-1:0]; + `USE_FAST_BRAM reg [DATAW-1:0] ram [ADDR_MIN:SIZE-1]; `RAM_INITIALIZATION - if (OUT_REG != 0) begin + if (OUT_REG != 0) begin reg [DATAW-1:0] rdata_r; always @(posedge clk) begin if (write) begin @@ -161,7 +162,7 @@ module VX_dp_ram #( end end else begin if (OUT_REG != 0) begin - reg [DATAW-1:0] ram [SIZE-1:0]; + reg [DATAW-1:0] ram [ADDR_MIN:SIZE-1]; reg [DATAW-1:0] rdata_r; `RAM_INITIALIZATION always @(posedge clk) begin @@ -178,7 +179,7 @@ module VX_dp_ram #( assign rdata = rdata_r; end else begin if (NO_RWCHECK != 0) begin - `NO_RW_RAM_CHECK reg [DATAW-1:0] ram [SIZE-1:0]; + `NO_RW_RAM_CHECK reg [DATAW-1:0] ram [ADDR_MIN:SIZE-1]; `RAM_INITIALIZATION always @(posedge clk) begin if (write) begin @@ -190,7 +191,7 @@ module VX_dp_ram #( end assign rdata = ram[raddr]; end else begin - reg [DATAW-1:0] ram [SIZE-1:0]; + reg [DATAW-1:0] ram [ADDR_MIN:SIZE-1]; `RAM_INITIALIZATION always @(posedge clk) begin if (write) begin @@ -208,9 +209,9 @@ module VX_dp_ram #( end else begin // (WRENW == 1) if (LUTRAM != 0) begin - `USE_FAST_BRAM reg [DATAW-1:0] ram [SIZE-1:0]; + `USE_FAST_BRAM reg [DATAW-1:0] ram [ADDR_MIN:SIZE-1]; `RAM_INITIALIZATION - if (OUT_REG != 0) begin + if (OUT_REG != 0) begin reg [DATAW-1:0] rdata_r; always @(posedge clk) begin if (write) begin @@ -231,7 +232,7 @@ module VX_dp_ram #( end end else begin if (OUT_REG != 0) begin - reg [DATAW-1:0] ram [SIZE-1:0]; + reg [DATAW-1:0] ram [ADDR_MIN:SIZE-1]; reg [DATAW-1:0] rdata_r; `RAM_INITIALIZATION always @(posedge clk) begin @@ -245,7 +246,7 @@ module VX_dp_ram #( assign rdata = rdata_r; end else begin if (NO_RWCHECK != 0) begin - `NO_RW_RAM_CHECK reg [DATAW-1:0] ram [SIZE-1:0]; + `NO_RW_RAM_CHECK reg [DATAW-1:0] ram [ADDR_MIN:SIZE-1]; `RAM_INITIALIZATION always @(posedge clk) begin if (write) begin @@ -254,7 +255,7 @@ module VX_dp_ram #( end assign rdata = ram[raddr]; end else begin - reg [DATAW-1:0] ram [SIZE-1:0]; + reg [DATAW-1:0] ram [ADDR_MIN:SIZE-1]; `RAM_INITIALIZATION always @(posedge clk) begin if (write) begin @@ -265,10 +266,10 @@ module VX_dp_ram #( end end end - end + end `else // RAM emulation - reg [DATAW-1:0] ram [SIZE-1:0]; + reg [DATAW-1:0] ram [ADDR_MIN:SIZE-1]; `RAM_INITIALIZATION wire [DATAW-1:0] ram_n; @@ -276,8 +277,8 @@ module VX_dp_ram #( assign ram_n[i * WSELW +: WSELW] = ((WRENW == 1) | wren[i]) ? wdata[i * WSELW +: WSELW] : ram[waddr][i * WSELW +: WSELW]; end - if (OUT_REG != 0) begin - reg [DATAW-1:0] rdata_r; + if (OUT_REG != 0) begin + reg [DATAW-1:0] rdata_r; always @(posedge clk) begin if (write) begin ram[waddr] <= ram_n; @@ -287,7 +288,7 @@ module VX_dp_ram #( end end assign rdata = rdata_r; - end else begin + end else begin reg [DATAW-1:0] prev_data; reg [ADDRW-1:0] prev_waddr; reg prev_write; @@ -298,7 +299,7 @@ module VX_dp_ram #( prev_write <= (| wren); prev_data <= ram[waddr]; prev_waddr <= waddr; - end + end if (LUTRAM || !NO_RWCHECK) begin `UNUSED_VAR (prev_write) `UNUSED_VAR (prev_data) diff --git a/hw/rtl/libs/VX_dp_ram_rst.sv b/hw/rtl/libs/VX_dp_ram_rst.sv new file mode 100644 index 000000000..e7598dbe6 --- /dev/null +++ b/hw/rtl/libs/VX_dp_ram_rst.sv @@ -0,0 +1,115 @@ +// Copyright © 2019-2023 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +`include "VX_platform.vh" + +`TRACING_OFF +module VX_dp_ram_rst #( + parameter DATAW = 1, + parameter SIZE = 1, + parameter ADDR_MIN = 0, + parameter WRENW = 1, + parameter OUT_REG = 0, + parameter NO_RWCHECK = 0, + parameter LUTRAM = 0, + parameter INIT_ENABLE = 0, + parameter INIT_FILE = "", + parameter [DATAW-1:0] INIT_VALUE = 0, + parameter ADDRW = `LOG2UP(SIZE) +) ( + input wire clk, + input wire reset, + input wire read, + input wire write, + input wire [WRENW-1:0] wren, + input wire [ADDRW-1:0] waddr, + input wire [DATAW-1:0] wdata, + input wire [ADDRW-1:0] raddr, + output wire [DATAW-1:0] rdata +); + localparam WSELW = DATAW / WRENW; + `STATIC_ASSERT((WRENW * WSELW == DATAW), ("invalid parameter")) + +`define RAM_INITIALIZATION \ + if (INIT_ENABLE != 0) begin \ + if (INIT_FILE != "") begin \ + initial $readmemh(INIT_FILE, ram); \ + end else begin \ + initial \ + for (integer i = 0; i < SIZE; ++i) \ + ram[i] = INIT_VALUE; \ + end \ + end + + `UNUSED_VAR (read) + + // RAM emulation + reg [DATAW-1:0] ram [ADDR_MIN:SIZE-1]; + `RAM_INITIALIZATION + + wire [DATAW-1:0] ram_n; + for (genvar i = 0; i < WRENW; ++i) begin + assign ram_n[i * WSELW +: WSELW] = ((WRENW == 1) | wren[i]) ? wdata[i * WSELW +: WSELW] : ram[waddr][i * WSELW +: WSELW]; + end + + if (OUT_REG != 0) begin + reg [DATAW-1:0] rdata_r; + always @(posedge clk) begin + if (reset) begin + for (integer i = 0; i < SIZE; ++i) begin + ram[i] <= DATAW'(INIT_VALUE); + end + rdata_r <= '0; + end else begin + if (write) begin + ram[waddr] <= ram_n; + end + if (read) begin + rdata_r <= ram[raddr]; + end + end + end + assign rdata = rdata_r; + end else begin + reg [DATAW-1:0] prev_data; + reg [ADDRW-1:0] prev_waddr; + reg prev_write; + always @(posedge clk) begin + if (reset) begin + for (integer i = 0; i < SIZE; ++i) begin + ram[i] <= DATAW'(INIT_VALUE); + end + prev_write <= 0; + prev_data <= '0; + prev_waddr <= '0; + end else begin + if (write) begin + ram[waddr] <= ram_n; + end + prev_write <= (| wren); + prev_data <= ram[waddr]; + prev_waddr <= waddr; + end + end + if (LUTRAM || !NO_RWCHECK) begin + `UNUSED_VAR (prev_write) + `UNUSED_VAR (prev_data) + `UNUSED_VAR (prev_waddr) + assign rdata = ram[raddr]; + end else begin + assign rdata = (prev_write && (prev_waddr == raddr)) ? prev_data : ram[raddr]; + end + end + +endmodule +`TRACING_ON diff --git a/hw/rtl/libs/VX_elastic_buffer.sv b/hw/rtl/libs/VX_elastic_buffer.sv index b2153b6f3..01464840c 100644 --- a/hw/rtl/libs/VX_elastic_buffer.sv +++ b/hw/rtl/libs/VX_elastic_buffer.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -19,14 +19,14 @@ module VX_elastic_buffer #( parameter SIZE = 1, parameter OUT_REG = 0, parameter LUTRAM = 0 -) ( +) ( input wire clk, input wire reset, input wire valid_in, - output wire ready_in, + output wire ready_in, input wire [DATAW-1:0] data_in, - + output wire [DATAW-1:0] data_out, input wire ready_out, output wire valid_out @@ -55,7 +55,7 @@ module VX_elastic_buffer #( .ready_out (ready_out) ); - end else if (SIZE == 2) begin + end else if (SIZE == 2 && LUTRAM == 0) begin VX_skid_buffer #( .DATAW (DATAW), @@ -71,9 +71,9 @@ module VX_elastic_buffer #( .data_out (data_out), .ready_out (ready_out) ); - + end else begin - + wire empty, full; wire [DATAW-1:0] data_out_t; @@ -93,7 +93,7 @@ module VX_elastic_buffer #( .push (push), .pop (pop), .data_in(data_in), - .data_out(data_out_t), + .data_out(data_out_t), .empty (empty), .full (full), `UNUSED_PIN (alm_empty), @@ -105,15 +105,15 @@ module VX_elastic_buffer #( VX_elastic_buffer #( .DATAW (DATAW), - .SIZE (OUT_REG == 2) + .SIZE ((OUT_REG == 2) ? 1 : 0) ) out_buf ( .clk (clk), .reset (reset), .valid_in (~empty), .data_in (data_out_t), - .ready_in (ready_out_t), + .ready_in (ready_out_t), .valid_out (valid_out), - .data_out (data_out), + .data_out (data_out), .ready_out (ready_out) ); diff --git a/hw/rtl/libs/VX_fair_arbiter.sv b/hw/rtl/libs/VX_fair_arbiter.sv index c063b2fbc..838563dd8 100644 --- a/hw/rtl/libs/VX_fair_arbiter.sv +++ b/hw/rtl/libs/VX_fair_arbiter.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,53 +16,52 @@ `TRACING_OFF module VX_fair_arbiter #( parameter NUM_REQS = 1, - parameter LOCK_ENABLE = 0, parameter LOG_NUM_REQS = `LOG2UP(NUM_REQS) ) ( input wire clk, input wire reset, - input wire [NUM_REQS-1:0] requests, + input wire [NUM_REQS-1:0] requests, output wire [LOG_NUM_REQS-1:0] grant_index, - output wire [NUM_REQS-1:0] grant_onehot, + output wire [NUM_REQS-1:0] grant_onehot, output wire grant_valid, - input wire grant_unlock + input wire grant_ready ); - if (NUM_REQS == 1) begin - + if (NUM_REQS == 1) begin + `UNUSED_VAR (clk) - `UNUSED_VAR (reset) - `UNUSED_VAR (grant_unlock) + `UNUSED_VAR (reset) + `UNUSED_VAR (grant_ready) assign grant_index = '0; assign grant_onehot = requests; assign grant_valid = requests[0]; - end else begin + end else begin - reg [NUM_REQS-1:0] buffer; + reg [NUM_REQS-1:0] grant_mask; - wire [NUM_REQS-1:0] buffer_qual = buffer & requests; - wire [NUM_REQS-1:0] requests_qual = (| buffer) ? buffer_qual : requests; - wire [NUM_REQS-1:0] buffer_n = requests_qual & ~grant_onehot; + wire [NUM_REQS-1:0] requests_rem = requests & ~grant_mask; + wire rem_valid = (| requests_rem); + wire [NUM_REQS-1:0] requests_qual = rem_valid ? requests_rem : requests; always @(posedge clk) begin if (reset) begin - buffer <= '0; - end else if (!LOCK_ENABLE || grant_unlock) begin - buffer <= buffer_n; + grant_mask <= '0; + end else if (grant_ready) begin + grant_mask <= rem_valid ? (grant_mask | grant_onehot) : grant_onehot; end end - + VX_priority_arbiter #( .NUM_REQS (NUM_REQS) ) priority_arbiter ( - .requests (requests_qual), + .requests (requests_qual), .grant_index (grant_index), .grant_onehot (grant_onehot), .grant_valid (grant_valid) ); end - + endmodule `TRACING_ON diff --git a/hw/rtl/libs/VX_fifo_queue.sv b/hw/rtl/libs/VX_fifo_queue.sv index 3a29410a9..a430d32f7 100644 --- a/hw/rtl/libs/VX_fifo_queue.sv +++ b/hw/rtl/libs/VX_fifo_queue.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -22,28 +22,28 @@ module VX_fifo_queue #( parameter OUT_REG = 0, parameter LUTRAM = 1, parameter SIZEW = `CLOG2(DEPTH+1) -) ( +) ( input wire clk, - input wire reset, + input wire reset, input wire push, - input wire pop, + input wire pop, input wire [DATAW-1:0] data_in, output wire [DATAW-1:0] data_out, - output wire empty, + output wire empty, output wire alm_empty, - output wire full, + output wire full, output wire alm_full, output wire [SIZEW-1:0] size -); - - localparam ADDRW = `CLOG2(DEPTH); +); + + localparam ADDRW = `CLOG2(DEPTH); `STATIC_ASSERT(ALM_FULL > 0, ("alm_full must be greater than 0!")) `STATIC_ASSERT(ALM_FULL < DEPTH, ("alm_full must be smaller than size!")) `STATIC_ASSERT(ALM_EMPTY > 0, ("alm_empty must be greater than 0!")) `STATIC_ASSERT(ALM_EMPTY < DEPTH, ("alm_empty must be smaller than size!")) `STATIC_ASSERT(`IS_POW2(DEPTH), ("size must be a power of 2!")) - + if (DEPTH == 1) begin reg [DATAW-1:0] head_r; @@ -52,7 +52,7 @@ module VX_fifo_queue #( always @(posedge clk) begin if (reset) begin head_r <= '0; - size_r <= '0; + size_r <= '0; end else begin `ASSERT(~push || ~full, ("runtime error: writing to a full queue")); `ASSERT(~pop || ~empty, ("runtime error: reading an empty queue")); @@ -63,11 +63,11 @@ module VX_fifo_queue #( end else if (pop) begin size_r <= '0; end - if (push) begin + if (push) begin head_r <= data_in; end end - end + end assign data_out = head_r; assign empty = (size_r == 0); @@ -77,7 +77,7 @@ module VX_fifo_queue #( assign size = size_r; end else begin - + reg empty_r, alm_empty_r; reg full_r, alm_full_r; reg [ADDRW-1:0] used_r; @@ -86,8 +86,8 @@ module VX_fifo_queue #( always @(posedge clk) begin if (reset) begin empty_r <= 1; - alm_empty_r <= 1; - full_r <= 0; + alm_empty_r <= 1; + full_r <= 0; alm_full_r <= 0; used_r <= '0; end else begin @@ -106,21 +106,21 @@ module VX_fifo_queue #( end else if (pop) begin full_r <= 0; if (used_r == ADDRW'(ALM_FULL)) - alm_full_r <= 0; + alm_full_r <= 0; if (used_r == ADDRW'(1)) empty_r <= 1; if (used_r == ADDRW'(ALM_EMPTY+1)) alm_empty_r <= 1; - end - used_r <= used_n; - end + end + used_r <= used_n; + end end - if (DEPTH == 2) begin + if (DEPTH == 2 && LUTRAM == 0) begin assign used_n = used_r ^ (push ^ pop); - if (0 == OUT_REG) begin + if (0 == OUT_REG) begin reg [1:0][DATAW-1:0] shift_reg; @@ -131,8 +131,8 @@ module VX_fifo_queue #( end end - assign data_out = shift_reg[!used_r[0]]; - + assign data_out = shift_reg[!used_r[0]]; + end else begin reg [DATAW-1:0] data_out_r; @@ -152,16 +152,16 @@ module VX_fifo_queue #( assign data_out = data_out_r; end - + end else begin - + assign used_n = $signed(used_r) + ADDRW'($signed(2'(push) - 2'(pop))); - if (0 == OUT_REG) begin + if (0 == OUT_REG) begin reg [ADDRW-1:0] rd_ptr_r; reg [ADDRW-1:0] wr_ptr_r; - + always @(posedge clk) begin if (reset) begin rd_ptr_r <= '0; @@ -169,7 +169,7 @@ module VX_fifo_queue #( end else begin wr_ptr_r <= wr_ptr_r + ADDRW'(push); rd_ptr_r <= rd_ptr_r + ADDRW'(pop); - end + end end VX_dp_ram #( @@ -179,8 +179,8 @@ module VX_fifo_queue #( ) dp_ram ( .clk(clk), .read (1'b1), - .write (push), - `UNUSED_PIN (wren), + .write (push), + `UNUSED_PIN (wren), .waddr (wr_ptr_r), .wdata (data_in), .raddr (rd_ptr_r), @@ -196,18 +196,18 @@ module VX_fifo_queue #( reg [ADDRW-1:0] rd_ptr_n_r; always @(posedge clk) begin - if (reset) begin + if (reset) begin wr_ptr_r <= '0; rd_ptr_r <= '0; rd_ptr_n_r <= 1; end else begin wr_ptr_r <= wr_ptr_r + ADDRW'(push); if (pop) begin - rd_ptr_r <= rd_ptr_n_r; - if (DEPTH > 2) begin + rd_ptr_r <= rd_ptr_n_r; + if (DEPTH > 2) begin rd_ptr_n_r <= rd_ptr_r + ADDRW'(2); end else begin // (DEPTH == 2); - rd_ptr_n_r <= ~rd_ptr_n_r; + rd_ptr_n_r <= ~rd_ptr_n_r; end end end @@ -227,13 +227,13 @@ module VX_fifo_queue #( ) dp_ram ( .clk (clk), .read (1'b1), - .write (push), - `UNUSED_PIN (wren), + .write (push), + `UNUSED_PIN (wren), .waddr (wr_ptr_r), .wdata (data_in), .raddr (rd_ptr_n_r), .rdata (dout) - ); + ); always @(posedge clk) begin if (push && (empty_r || (going_empty && pop))) begin @@ -246,12 +246,12 @@ module VX_fifo_queue #( assign data_out = dout_r; end end - - assign empty = empty_r; + + assign empty = empty_r; assign alm_empty = alm_empty_r; assign full = full_r; assign alm_full = alm_full_r; - assign size = {full_r, used_r}; + assign size = {full_r, used_r}; end endmodule diff --git a/hw/rtl/libs/VX_generic_arbiter.sv b/hw/rtl/libs/VX_generic_arbiter.sv index 4573efb3e..a1f7be4a0 100644 --- a/hw/rtl/libs/VX_generic_arbiter.sv +++ b/hw/rtl/libs/VX_generic_arbiter.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,29 +16,27 @@ `TRACING_OFF module VX_generic_arbiter #( parameter NUM_REQS = 1, - parameter LOCK_ENABLE = 0, - parameter `STRING TYPE = "P", + parameter `STRING TYPE = "P", parameter LOG_NUM_REQS = `LOG2UP(NUM_REQS) ) ( input wire clk, - input wire reset, + input wire reset, input wire [NUM_REQS-1:0] requests, output wire [LOG_NUM_REQS-1:0] grant_index, - output wire [NUM_REQS-1:0] grant_onehot, + output wire [NUM_REQS-1:0] grant_onehot, output wire grant_valid, - input wire grant_unlock + input wire grant_ready ); if (TYPE == "P") begin - `UNUSED_PARAM (LOCK_ENABLE) `UNUSED_VAR (clk) `UNUSED_VAR (reset) - `UNUSED_VAR (grant_unlock) + `UNUSED_VAR (grant_ready) VX_priority_arbiter #( .NUM_REQS (NUM_REQS) ) priority_arbiter ( - .requests (requests), + .requests (requests), .grant_valid (grant_valid), .grant_index (grant_index), .grant_onehot (grant_onehot) @@ -47,68 +45,64 @@ module VX_generic_arbiter #( end else if (TYPE == "R") begin VX_rr_arbiter #( - .NUM_REQS (NUM_REQS), - .LOCK_ENABLE (LOCK_ENABLE) + .NUM_REQS (NUM_REQS) ) rr_arbiter ( .clk (clk), - .reset (reset), - .requests (requests), + .reset (reset), + .requests (requests), .grant_valid (grant_valid), .grant_index (grant_index), .grant_onehot (grant_onehot), - .grant_unlock (grant_unlock) + .grant_ready (grant_ready) ); end else if (TYPE == "F") begin VX_fair_arbiter #( - .NUM_REQS (NUM_REQS), - .LOCK_ENABLE (LOCK_ENABLE) + .NUM_REQS (NUM_REQS) ) fair_arbiter ( .clk (clk), .reset (reset), - .requests (requests), + .requests (requests), .grant_valid (grant_valid), .grant_index (grant_index), .grant_onehot (grant_onehot), - .grant_unlock (grant_unlock) + .grant_ready (grant_ready) ); end else if (TYPE == "M") begin VX_matrix_arbiter #( - .NUM_REQS (NUM_REQS), - .LOCK_ENABLE (LOCK_ENABLE) + .NUM_REQS (NUM_REQS) ) matrix_arbiter ( .clk (clk), .reset (reset), - .requests (requests), + .requests (requests), .grant_valid (grant_valid), .grant_index (grant_index), .grant_onehot (grant_onehot), - .grant_unlock (grant_unlock) + .grant_ready (grant_ready) ); end else if (TYPE == "C") begin VX_cyclic_arbiter #( - .NUM_REQS (NUM_REQS), - .LOCK_ENABLE (LOCK_ENABLE) + .NUM_REQS (NUM_REQS) ) cyclic_arbiter ( .clk (clk), .reset (reset), - .requests (requests), + .requests (requests), .grant_valid (grant_valid), .grant_index (grant_index), .grant_onehot (grant_onehot), - .grant_unlock (grant_unlock) + .grant_ready (grant_ready) ); end else begin `ERROR(("invalid parameter")); - + end - + endmodule `TRACING_ON diff --git a/hw/rtl/libs/VX_matrix_arbiter.sv b/hw/rtl/libs/VX_matrix_arbiter.sv index 9333c1ac5..23f9ea2a0 100644 --- a/hw/rtl/libs/VX_matrix_arbiter.sv +++ b/hw/rtl/libs/VX_matrix_arbiter.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,52 +16,51 @@ `TRACING_OFF module VX_matrix_arbiter #( parameter NUM_REQS = 1, - parameter LOCK_ENABLE = 0, parameter LOG_NUM_REQS = `LOG2UP(NUM_REQS) ) ( input wire clk, - input wire reset, + input wire reset, input wire [NUM_REQS-1:0] requests, output wire [LOG_NUM_REQS-1:0] grant_index, - output wire [NUM_REQS-1:0] grant_onehot, + output wire [NUM_REQS-1:0] grant_onehot, output wire grant_valid, - input wire grant_unlock + input wire grant_ready ); if (NUM_REQS == 1) begin `UNUSED_VAR (clk) `UNUSED_VAR (reset) - `UNUSED_VAR (grant_unlock) - + `UNUSED_VAR (grant_ready) + assign grant_index = '0; assign grant_onehot = requests; assign grant_valid = requests[0]; end else begin - reg [NUM_REQS-1:1] state [NUM_REQS-1:0]; + reg [NUM_REQS-1:1] state [NUM_REQS-1:0]; wire [NUM_REQS-1:0] pri [NUM_REQS-1:0]; wire [NUM_REQS-1:0] grant_unqual; - - for (genvar i = 0; i < NUM_REQS; ++i) begin + + for (genvar i = 0; i < NUM_REQS; ++i) begin for (genvar j = 0; j < NUM_REQS; ++j) begin if (j > i) begin assign pri[j][i] = requests[i] && state[i][j]; - end + end else if (j < i) begin assign pri[j][i] = requests[i] && !state[j][i]; - end + end else begin - assign pri[j][i] = 0; + assign pri[j][i] = 0; end end assign grant_unqual[i] = requests[i] && !(| pri[i]); end - - for (genvar i = 0; i < NUM_REQS; ++i) begin + + for (genvar i = 0; i < NUM_REQS; ++i) begin for (genvar j = i + 1; j < NUM_REQS; ++j) begin - always @(posedge clk) begin - if (reset) begin + always @(posedge clk) begin + if (reset) begin state[i][j] <= '0; end else begin state[i][j] <= (state[i][j] || grant_unqual[j]) && !grant_unqual[i]; @@ -70,20 +69,15 @@ module VX_matrix_arbiter #( end end - if (LOCK_ENABLE == 0) begin - `UNUSED_VAR (grant_unlock) - assign grant_onehot = grant_unqual; - end else begin - reg [NUM_REQS-1:0] grant_unqual_prev; - always @(posedge clk) begin - if (reset) begin - grant_unqual_prev <= '0; - end else if (grant_unlock) begin - grant_unqual_prev <= grant_unqual; - end + reg [NUM_REQS-1:0] grant_unqual_prev; + always @(posedge clk) begin + if (reset) begin + grant_unqual_prev <= '0; + end else if (grant_ready) begin + grant_unqual_prev <= grant_unqual; end - assign grant_onehot = grant_unlock ? grant_unqual : grant_unqual_prev; end + assign grant_onehot = grant_ready ? grant_unqual : grant_unqual_prev; VX_onehot_encoder #( .N (NUM_REQS) @@ -96,6 +90,6 @@ module VX_matrix_arbiter #( assign grant_valid = (| requests); end - + endmodule `TRACING_ON diff --git a/hw/rtl/libs/VX_mem_coalescer.sv b/hw/rtl/libs/VX_mem_coalescer.sv index 79ee9fa5f..17eb01642 100644 --- a/hw/rtl/libs/VX_mem_coalescer.sv +++ b/hw/rtl/libs/VX_mem_coalescer.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -24,13 +24,13 @@ module VX_mem_coalescer #( parameter TAG_WIDTH = 8, parameter UUID_WIDTH = 0, // upper section of the request tag contains the UUID parameter QUEUE_SIZE = 8, - + parameter DATA_IN_WIDTH = DATA_IN_SIZE * 8, parameter DATA_OUT_WIDTH= DATA_OUT_SIZE * 8, - parameter OUT_REQS = (NUM_REQS * DATA_IN_WIDTH) / DATA_OUT_WIDTH, - parameter BATCH_SIZE = DATA_OUT_SIZE / DATA_IN_SIZE, - parameter BATCH_SIZE_W = `LOG2UP(BATCH_SIZE), - parameter OUT_ADDR_WIDTH= ADDR_WIDTH - BATCH_SIZE_W, + parameter DATA_RATIO = DATA_OUT_SIZE / DATA_IN_SIZE, + parameter DATA_RATIO_W = `LOG2UP(DATA_RATIO), + parameter OUT_REQS = NUM_REQS / DATA_RATIO, + parameter OUT_ADDR_WIDTH= ADDR_WIDTH - DATA_RATIO_W, parameter QUEUE_ADDRW = `CLOG2(QUEUE_SIZE), parameter OUT_TAG_WIDTH = UUID_WIDTH + QUEUE_ADDRW ) ( @@ -45,7 +45,7 @@ module VX_mem_coalescer #( input wire [NUM_REQS-1:0][ADDR_WIDTH-1:0] in_req_addr, input wire [NUM_REQS-1:0][ATYPE_WIDTH-1:0] in_req_atype, input wire [NUM_REQS-1:0][DATA_IN_WIDTH-1:0] in_req_data, - input wire [TAG_WIDTH-1:0] in_req_tag, + input wire [TAG_WIDTH-1:0] in_req_tag, output wire in_req_ready, // Input response @@ -58,7 +58,7 @@ module VX_mem_coalescer #( // Output request output wire out_req_valid, output wire out_req_rw, - output wire [OUT_REQS-1:0] out_req_mask, + output wire [OUT_REQS-1:0] out_req_mask, output wire [OUT_REQS-1:0][DATA_OUT_SIZE-1:0] out_req_byteen, output wire [OUT_REQS-1:0][OUT_ADDR_WIDTH-1:0] out_req_addr, output wire [OUT_REQS-1:0][ATYPE_WIDTH-1:0] out_req_atype, @@ -78,27 +78,27 @@ module VX_mem_coalescer #( `STATIC_ASSERT ((NUM_REQS * DATA_IN_WIDTH >= DATA_OUT_WIDTH), ("invalid parameter")) `RUNTIME_ASSERT ((~in_req_valid || in_req_mask != 0), ("invalid request mask")); `RUNTIME_ASSERT ((~out_rsp_valid || out_rsp_mask != 0), ("invalid request mask")); - - localparam TAG_ID_WIDTH = TAG_WIDTH - UUID_WIDTH; - localparam NUM_REQS_W = `LOG2UP(NUM_REQS); + + localparam TAG_ID_WIDTH = TAG_WIDTH - UUID_WIDTH; + localparam NUM_REQS_W = `LOG2UP(NUM_REQS); // tag + mask + offest - localparam IBUF_DATA_WIDTH = TAG_ID_WIDTH + NUM_REQS + (NUM_REQS * BATCH_SIZE_W); + localparam IBUF_DATA_WIDTH = TAG_ID_WIDTH + NUM_REQS + (NUM_REQS * DATA_RATIO_W); localparam STATE_SETUP = 0; localparam STATE_SEND = 1; - - logic state_r, state_n; - - logic out_req_valid_r, out_req_valid_n; - logic out_req_rw_r, out_req_rw_n; - logic [OUT_REQS-1:0] out_req_mask_r, out_req_mask_n; - logic [OUT_REQS-1:0][DATA_OUT_SIZE-1:0] out_req_byteen_r, out_req_byteen_n; - logic [OUT_REQS-1:0][OUT_ADDR_WIDTH-1:0] out_req_addr_r, out_req_addr_n; - logic [OUT_REQS-1:0][ATYPE_WIDTH-1:0] out_req_atype_r, out_req_atype_n; - logic [OUT_REQS-1:0][DATA_OUT_WIDTH-1:0] out_req_data_r, out_req_data_n; - logic [OUT_TAG_WIDTH-1:0] out_req_tag_r, out_req_tag_n; - logic in_req_ready_n; + reg state_r, state_n; + + reg out_req_valid_r, out_req_valid_n; + reg out_req_rw_r, out_req_rw_n; + reg [OUT_REQS-1:0] out_req_mask_r, out_req_mask_n; + reg [OUT_REQS-1:0][OUT_ADDR_WIDTH-1:0] out_req_addr_r, out_req_addr_n; + reg [OUT_REQS-1:0][ATYPE_WIDTH-1:0] out_req_atype_r, out_req_atype_n; + reg [OUT_REQS-1:0][DATA_RATIO-1:0][DATA_IN_SIZE-1:0] out_req_byteen_r, out_req_byteen_n; + reg [OUT_REQS-1:0][DATA_RATIO-1:0][DATA_IN_WIDTH-1:0] out_req_data_r, out_req_data_n; + reg [OUT_TAG_WIDTH-1:0] out_req_tag_r, out_req_tag_n; + + reg in_req_ready_n; wire ibuf_push; wire ibuf_pop; @@ -108,33 +108,45 @@ module VX_mem_coalescer #( wire ibuf_empty; wire [IBUF_DATA_WIDTH-1:0] ibuf_din; wire [IBUF_DATA_WIDTH-1:0] ibuf_dout; - + logic [OUT_REQS-1:0] batch_valid_r, batch_valid_n; logic [OUT_REQS-1:0][OUT_ADDR_WIDTH-1:0] seed_addr_r, seed_addr_n; logic [OUT_REQS-1:0][ATYPE_WIDTH-1:0] seed_atype_r, seed_atype_n; + logic [NUM_REQS-1:0] addr_matches_r, addr_matches_n; logic [NUM_REQS-1:0] processed_mask_r, processed_mask_n; wire [OUT_REQS-1:0][NUM_REQS_W-1:0] seed_idx; wire [NUM_REQS-1:0][OUT_ADDR_WIDTH-1:0] in_addr_base; - wire [NUM_REQS-1:0][BATCH_SIZE_W-1:0] in_addr_offset; + wire [NUM_REQS-1:0][DATA_RATIO_W-1:0] in_addr_offset; for (genvar i = 0; i < NUM_REQS; i++) begin - assign in_addr_base[i] = in_req_addr[i][ADDR_WIDTH-1:BATCH_SIZE_W]; - assign in_addr_offset[i] = in_req_addr[i][BATCH_SIZE_W-1:0]; + assign in_addr_base[i] = in_req_addr[i][ADDR_WIDTH-1:DATA_RATIO_W]; + assign in_addr_offset[i] = in_req_addr[i][DATA_RATIO_W-1:0]; end for (genvar i = 0; i < OUT_REQS; ++i) begin - wire [BATCH_SIZE-1:0] batch_mask = in_req_mask[BATCH_SIZE * i +: BATCH_SIZE] & ~processed_mask_r[BATCH_SIZE * i +: BATCH_SIZE]; - wire [BATCH_SIZE_W-1:0] batch_idx; + wire [DATA_RATIO-1:0] batch_mask = in_req_mask[i * DATA_RATIO +: DATA_RATIO] & ~processed_mask_r[i * DATA_RATIO +: DATA_RATIO]; + wire [DATA_RATIO_W-1:0] batch_idx; VX_priority_encoder #( - .N (BATCH_SIZE) + .N (DATA_RATIO) ) priority_encoder ( .data_in (batch_mask), - .index (batch_idx), + .index (batch_idx), `UNUSED_PIN (onehot), .valid_out (batch_valid_n[i]) ); - assign seed_idx[i] = NUM_REQS_W'(BATCH_SIZE * i) + NUM_REQS_W'(batch_idx); + assign seed_idx[i] = NUM_REQS_W'(i * DATA_RATIO) + NUM_REQS_W'(batch_idx); + end + + for (genvar i = 0; i < OUT_REQS; ++i) begin + assign seed_addr_n[i] = in_addr_base[seed_idx[i]]; + assign seed_atype_n[i] = in_req_atype[seed_idx[i]]; + end + + for (genvar i = 0; i < OUT_REQS; ++i) begin + for (genvar j = 0; j < DATA_RATIO; ++j) begin + assign addr_matches_n[i * DATA_RATIO + j] = (in_addr_base[i * DATA_RATIO + j] == seed_addr_n[i]); + end end always @(posedge clk) begin @@ -144,12 +156,13 @@ module VX_mem_coalescer #( out_req_valid_r <= 0; end else begin state_r <= state_n; - out_req_valid_r <= out_req_valid_n; batch_valid_r <= batch_valid_n; seed_addr_r <= seed_addr_n; - seed_atype_r <= seed_atype_n; - out_req_rw_r <= out_req_rw_n; - out_req_mask_r <= out_req_mask_n; + seed_atype_r <= seed_atype_n; + addr_matches_r <= addr_matches_n; + out_req_valid_r <= out_req_valid_n; + out_req_mask_r <= out_req_mask_n; + out_req_rw_r <= out_req_rw_n; out_req_addr_r <= out_req_addr_n; out_req_atype_r <= out_req_atype_n; out_req_byteen_r <= out_req_byteen_n; @@ -159,84 +172,77 @@ module VX_mem_coalescer #( end end - logic [NUM_REQS-1:0] addr_matches; + wire [NUM_REQS-1:0] current_pmask = in_req_mask & addr_matches_r; + + reg [OUT_REQS-1:0][DATA_RATIO-1:0][DATA_IN_SIZE-1:0] req_byteen_merged; + reg [OUT_REQS-1:0][DATA_RATIO-1:0][DATA_IN_WIDTH-1:0] req_data_merged; always @(*) begin - addr_matches = '0; + req_byteen_merged = '0; + req_data_merged = 'x; for (integer i = 0; i < OUT_REQS; ++i) begin - for (integer j = 0; j < BATCH_SIZE; j++) begin - if (in_addr_base[BATCH_SIZE * i + j] == seed_addr_r[i]) begin - addr_matches[BATCH_SIZE * i + j] = 1; + for (integer j = 0; j < DATA_RATIO; ++j) begin + if (current_pmask[i * DATA_RATIO + j]) begin + for (integer k = 0; k < DATA_IN_SIZE; ++k) begin + if (in_req_byteen[DATA_RATIO * i + j][k]) begin + req_byteen_merged[i][in_addr_offset[DATA_RATIO * i + j]][k] = 1'b1; + req_data_merged[i][in_addr_offset[DATA_RATIO * i + j]][k * 8 +: 8] = in_req_data[DATA_RATIO * i + j][k * 8 +: 8]; + end + end end end end end - wire [NUM_REQS-1:0] current_pmask = in_req_mask & addr_matches; + wire [OUT_REQS * DATA_RATIO - 1:0] pending_mask; + for (genvar i = 0; i < OUT_REQS * DATA_RATIO; ++i) begin + assign pending_mask[i] = in_req_mask[i] && ~addr_matches_r[i] && ~processed_mask_r[i]; + end + wire batch_completed = ~(| pending_mask); always @(*) begin state_n = state_r; + out_req_valid_n = out_req_valid_r; - seed_addr_n = seed_addr_r; - seed_atype_n = seed_atype_r; - out_req_rw_n = out_req_rw_r; - out_req_mask_n = out_req_mask_r; + out_req_mask_n = out_req_mask_r; + out_req_rw_n = out_req_rw_r; out_req_addr_n = out_req_addr_r; out_req_atype_n = out_req_atype_r; out_req_byteen_n = out_req_byteen_r; out_req_data_n = out_req_data_r; out_req_tag_n = out_req_tag_r; + processed_mask_n = processed_mask_r; in_req_ready_n = 0; case (state_r) - STATE_SETUP: begin - // find the next seed address - for (integer i = 0; i < OUT_REQS; ++i) begin - seed_addr_n[i] = in_addr_base[seed_idx[i]]; - seed_atype_n[i] = in_req_atype[seed_idx[i]]; - end + STATE_SETUP: begin // wait for pending outgoing request to submit if (out_req_valid && out_req_ready) begin out_req_valid_n = 0; end - if (in_req_valid && ~out_req_valid_n && ~ibuf_full) begin + if (in_req_valid && ~out_req_valid_n && ~ibuf_full) begin state_n = STATE_SEND; end end default/*STATE_SEND*/: begin out_req_valid_n = 1; - out_req_rw_n = in_req_rw; - out_req_tag_n = {in_req_tag[TAG_WIDTH-1 -: UUID_WIDTH], ibuf_waddr}; - in_req_ready_n = 1; - out_req_byteen_n = '0; - out_req_data_n = 'x; - for (integer i = 0; i < OUT_REQS; ++i) begin - for (integer j = 0; j < BATCH_SIZE; j++) begin - if (in_req_mask[BATCH_SIZE * i + j]) begin - if (addr_matches[BATCH_SIZE * i + j]) begin - for (integer k = 0; k < DATA_IN_SIZE; ++k) begin - if (in_req_byteen[BATCH_SIZE * i + j][k]) begin - out_req_byteen_n[i][in_addr_offset[BATCH_SIZE * i + j] * DATA_IN_SIZE + k +: 1] = 1'b1; - out_req_data_n[i][in_addr_offset[BATCH_SIZE * i + j] * DATA_IN_WIDTH + k * 8 +: 8] = in_req_data[BATCH_SIZE * i + j][k * 8 +: 8]; - end - end - end else begin - if (!processed_mask_r[BATCH_SIZE * i + j]) begin - in_req_ready_n = 0; - end - end - end - end - out_req_mask_n[i] = batch_valid_r[i]; - out_req_addr_n[i] = seed_addr_r[i]; - out_req_atype_n[i]= seed_atype_r[i]; - end - if (in_req_ready_n) begin + out_req_mask_n = batch_valid_r; + out_req_rw_n = in_req_rw; + out_req_addr_n = seed_addr_r; + out_req_atype_n = seed_atype_r; + out_req_byteen_n= req_byteen_merged; + out_req_data_n = req_data_merged; + out_req_tag_n = {in_req_tag[TAG_WIDTH-1 -: UUID_WIDTH], ibuf_waddr}; + + in_req_ready_n = batch_completed; + + if (batch_completed) begin processed_mask_n = '0; end else begin processed_mask_n = processed_mask_r | current_pmask; end + state_n = STATE_SETUP; end endcase @@ -246,13 +252,15 @@ module VX_mem_coalescer #( wire out_rsp_eop; - assign ibuf_push = (state_r == STATE_SEND) && ~in_req_rw; + wire req_sent = (state_r == STATE_SEND); + + assign ibuf_push = req_sent && ~in_req_rw; assign ibuf_pop = out_rsp_fire && out_rsp_eop; - assign ibuf_raddr = out_rsp_tag[QUEUE_ADDRW-1:0]; + assign ibuf_raddr = out_rsp_tag[QUEUE_ADDRW-1:0]; wire [TAG_ID_WIDTH-1:0] ibuf_din_tag = in_req_tag[TAG_ID_WIDTH-1:0]; - wire [NUM_REQS-1:0][BATCH_SIZE_W-1:0] ibuf_din_offset = in_addr_offset; - wire [NUM_REQS-1:0] ibuf_din_pmask = current_pmask; + wire [NUM_REQS-1:0][DATA_RATIO_W-1:0] ibuf_din_offset = in_addr_offset; + wire [NUM_REQS-1:0] ibuf_din_pmask = current_pmask; assign ibuf_din = {ibuf_din_tag, ibuf_din_pmask, ibuf_din_offset}; @@ -286,7 +294,7 @@ module VX_mem_coalescer #( // unmerge responses - reg [QUEUE_SIZE-1:0][OUT_REQS-1:0] rsp_rem_mask; + reg [QUEUE_SIZE-1:0][OUT_REQS-1:0] rsp_rem_mask; wire [OUT_REQS-1:0] rsp_rem_mask_n = rsp_rem_mask[ibuf_raddr] & ~out_rsp_mask; assign out_rsp_eop = ~(| rsp_rem_mask_n); @@ -299,21 +307,19 @@ module VX_mem_coalescer #( end end - wire [NUM_REQS-1:0][BATCH_SIZE_W-1:0] ibuf_dout_offset; - reg [NUM_REQS-1:0] ibuf_dout_pmask; + wire [NUM_REQS-1:0][DATA_RATIO_W-1:0] ibuf_dout_offset; + wire [NUM_REQS-1:0] ibuf_dout_pmask; wire [TAG_ID_WIDTH-1:0] ibuf_dout_tag; assign {ibuf_dout_tag, ibuf_dout_pmask, ibuf_dout_offset} = ibuf_dout; - - logic [NUM_REQS-1:0][DATA_IN_WIDTH-1:0] in_rsp_data_n; - logic [NUM_REQS-1:0] in_rsp_mask_n; - always @(*) begin - for (integer i = 0; i < OUT_REQS; ++i) begin - for (integer j = 0; j < BATCH_SIZE; j++) begin - in_rsp_mask_n[BATCH_SIZE * i + j] = out_rsp_mask[i] && ibuf_dout_pmask[BATCH_SIZE * i + j]; - in_rsp_data_n[BATCH_SIZE * i + j] = out_rsp_data[i][ibuf_dout_offset[BATCH_SIZE * i + j] * DATA_IN_WIDTH +: DATA_IN_WIDTH]; - end + wire [NUM_REQS-1:0][DATA_IN_WIDTH-1:0] in_rsp_data_n; + wire [NUM_REQS-1:0] in_rsp_mask_n; + + for (genvar i = 0; i < OUT_REQS; ++i) begin + for (genvar j = 0; j < DATA_RATIO; ++j) begin + assign in_rsp_mask_n[i * DATA_RATIO + j] = out_rsp_mask[i] && ibuf_dout_pmask[i * DATA_RATIO + j]; + assign in_rsp_data_n[i * DATA_RATIO + j] = out_rsp_data[i][ibuf_dout_offset[i * DATA_RATIO + j] * DATA_IN_WIDTH +: DATA_IN_WIDTH]; end end @@ -335,11 +341,11 @@ module VX_mem_coalescer #( assign out_rsp_uuid = '0; end - reg [NUM_REQS-1:0][BATCH_SIZE_W-1:0] out_req_offset; + reg [NUM_REQS-1:0][DATA_RATIO_W-1:0] out_req_offset; reg [NUM_REQS-1:0] out_req_pmask; always @(posedge clk) begin - if (ibuf_push) begin + if (req_sent) begin out_req_offset <= ibuf_din_offset; out_req_pmask <= ibuf_din_pmask; end @@ -351,30 +357,30 @@ module VX_mem_coalescer #( if (out_req_fire) begin if (out_req_rw) begin `TRACE(1, ("%d: %s-out-req-wr: valid=%b, addr=", $time, INSTANCE_ID, out_req_mask)); - `TRACE_ARRAY1D(1, "0x%h", out_req_addr, OUT_REQS); + `TRACE_ARRAY1D(1, "0x%h", out_req_addr, OUT_REQS); `TRACE(1, (", atype=")); - `TRACE_ARRAY1D(1, "%b", out_req_atype, OUT_REQS); + `TRACE_ARRAY1D(1, "%b", out_req_atype, OUT_REQS); `TRACE(1, (", byteen=")); `TRACE_ARRAY1D(1, "0x%h", out_req_byteen, OUT_REQS); `TRACE(1, (", data=")); - `TRACE_ARRAY1D(1, "0x%0h", out_req_data, OUT_REQS); + `TRACE_ARRAY1D(1, "0x%0h", out_req_data, OUT_REQS); end else begin `TRACE(1, ("%d: %s-out-req-rd: valid=%b, addr=", $time, INSTANCE_ID, out_req_mask)); `TRACE_ARRAY1D(1, "0x%h", out_req_addr, OUT_REQS); `TRACE(1, (", atype=")); `TRACE_ARRAY1D(1, "%b", out_req_atype, OUT_REQS); end - `TRACE(1, (", offset=")); + `TRACE(1, (", offset=")); `TRACE_ARRAY1D(1, "%0d", out_req_offset, NUM_REQS); - `TRACE(1, (", pmask=%b, tag=0x%0h (#%0d)\n", out_req_pmask, out_req_tag, out_req_uuid)); + `TRACE(1, (", pmask=%b, tag=0x%0h (#%0d)\n", out_req_pmask, out_req_tag, out_req_uuid)); if ($countones(out_req_pmask) > 1) begin - `TRACE(1, ("%t: *** %s: coalescing=%b (#%0d)\n", $time, INSTANCE_ID, out_req_pmask, out_req_uuid)); - end + `TRACE(1, ("%t: *** %s: coalesced=%d (#%0d)\n", $time, INSTANCE_ID, $countones(out_req_pmask), out_req_uuid)); + end end if (out_rsp_fire) begin `TRACE(1, ("%d: %s-out-rsp: valid=%b, data=", $time, INSTANCE_ID, out_rsp_mask)); `TRACE_ARRAY1D(1, "0x%0h", out_rsp_data, OUT_REQS); - `TRACE(1, (", offset=")); + `TRACE(1, (", offset=")); `TRACE_ARRAY1D(1, "%0d", ibuf_dout_offset, NUM_REQS); `TRACE(1, (", eop=%b, pmask=%b, tag=0x%0h (#%0d)\n", out_rsp_eop, ibuf_dout_pmask, out_rsp_tag, out_rsp_uuid)); end diff --git a/hw/rtl/libs/VX_mem_scheduler.sv b/hw/rtl/libs/VX_mem_scheduler.sv index b05492231..aa3ef9b2f 100644 --- a/hw/rtl/libs/VX_mem_scheduler.sv +++ b/hw/rtl/libs/VX_mem_scheduler.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -23,7 +23,7 @@ module VX_mem_scheduler #( parameter ADDR_WIDTH = 32 - `CLOG2(WORD_SIZE), parameter ATYPE_WIDTH = 1, parameter TAG_WIDTH = 8, - parameter UUID_WIDTH = 0, // upper section of the request tag contains the UUID + parameter UUID_WIDTH = 0, // upper section of the request tag contains the UUID parameter CORE_QUEUE_SIZE= 8, parameter MEM_QUEUE_SIZE= CORE_QUEUE_SIZE, parameter RSP_PARTIAL = 0, @@ -54,7 +54,7 @@ module VX_mem_scheduler #( input wire [CORE_REQS-1:0][WORD_WIDTH-1:0] core_req_data, input wire [TAG_WIDTH-1:0] core_req_tag, output wire core_req_ready, - output wire core_req_empty, + output wire core_req_empty, output wire core_req_sent, // Core response @@ -81,7 +81,7 @@ module VX_mem_scheduler #( input wire mem_rsp_valid, input wire [MEM_CHANNELS-1:0] mem_rsp_mask, input wire [MEM_CHANNELS-1:0][LINE_WIDTH-1:0] mem_rsp_data, - input wire [MEM_TAG_WIDTH-1:0] mem_rsp_tag, + input wire [MEM_TAG_WIDTH-1:0] mem_rsp_tag, output wire mem_rsp_ready ); localparam BATCH_SEL_WIDTH = `UP(MEM_BATCH_BITS); @@ -110,7 +110,7 @@ module VX_mem_scheduler #( wire reqq_valid; wire [CORE_REQS-1:0] reqq_mask; - wire reqq_rw; + wire reqq_rw; wire [CORE_REQS-1:0][WORD_SIZE-1:0] reqq_byteen; wire [CORE_REQS-1:0][ADDR_WIDTH-1:0] reqq_addr; wire [CORE_REQS-1:0][ATYPE_WIDTH-1:0] reqq_atype; @@ -118,7 +118,7 @@ module VX_mem_scheduler #( wire [REQQ_TAG_WIDTH-1:0] reqq_tag; wire reqq_ready; - wire reqq_valid_s; + wire reqq_valid_s; wire [MERGED_REQS-1:0] reqq_mask_s; wire reqq_rw_s; wire [MERGED_REQS-1:0][LINE_SIZE-1:0] reqq_byteen_s; @@ -139,9 +139,9 @@ module VX_mem_scheduler #( wire mem_req_ready_s; wire mem_rsp_valid_s; - wire [CORE_REQS-1:0] mem_rsp_mask_s; - wire [CORE_REQS-1:0][WORD_WIDTH-1:0] mem_rsp_data_s; - wire [REQQ_TAG_WIDTH-1:0] mem_rsp_tag_s; + wire [CORE_CHANNELS-1:0] mem_rsp_mask_s; + wire [CORE_CHANNELS-1:0][WORD_WIDTH-1:0] mem_rsp_data_s; + wire [MEM_TAG_WIDTH-1:0] mem_rsp_tag_s; wire mem_rsp_ready_s; wire crsp_valid; @@ -159,7 +159,7 @@ module VX_mem_scheduler #( wire ibuf_ready = (core_req_rw || ~ibuf_full); wire reqq_valid_in = core_req_valid && ibuf_ready; wire reqq_ready_in; - + wire [REQQ_TAG_WIDTH-1:0] reqq_tag_u; if (UUID_WIDTH != 0) begin assign reqq_tag_u = {core_req_tag[TAG_WIDTH-1 -: UUID_WIDTH], ibuf_waddr}; @@ -169,7 +169,7 @@ module VX_mem_scheduler #( VX_elastic_buffer #( .DATAW (1 + CORE_REQS * (1 + WORD_SIZE + ADDR_WIDTH + ATYPE_WIDTH + WORD_WIDTH) + REQQ_TAG_WIDTH), - .SIZE (CORE_QUEUE_SIZE), + .SIZE (CORE_QUEUE_SIZE), .OUT_REG (1) ) req_queue ( .clk (clk), @@ -188,7 +188,7 @@ module VX_mem_scheduler #( // no pending requests assign core_req_empty = !reqq_valid && ibuf_empty; - // notify request submisison + // notify request submisison assign core_req_sent = reqq_valid && reqq_ready; // Index buffer /////////////////////////////////////////////////////////// @@ -219,15 +219,15 @@ module VX_mem_scheduler #( `UNUSED_VAR (ibuf_empty) - // Handle memory coalescing /////////////////////////////////////////////// + // Handle memory coalescing /////////////////////////////////////////////// if (COALESCE_ENABLE) begin - + `RESET_RELAY (coalescer_reset, reset); VX_mem_coalescer #( .INSTANCE_ID ($sformatf("%s-coalescer", INSTANCE_ID)), - .NUM_REQS (CORE_REQS), + .NUM_REQS (CORE_REQS), .DATA_IN_SIZE (WORD_SIZE), .DATA_OUT_SIZE (LINE_SIZE), .ADDR_WIDTH (ADDR_WIDTH), @@ -238,7 +238,7 @@ module VX_mem_scheduler #( ) coalescer ( .clk (clk), .reset (coalescer_reset), - + // Input request .in_req_valid (reqq_valid), .in_req_mask (reqq_mask), @@ -280,7 +280,7 @@ module VX_mem_scheduler #( assign reqq_valid_s = reqq_valid; assign reqq_mask_s = reqq_mask; - assign reqq_rw_s = reqq_rw; + assign reqq_rw_s = reqq_rw; assign reqq_byteen_s= reqq_byteen; assign reqq_addr_s = reqq_addr; assign reqq_atype_s = reqq_atype; @@ -292,18 +292,18 @@ module VX_mem_scheduler #( assign mem_rsp_mask_s = mem_rsp_mask; assign mem_rsp_data_s = mem_rsp_data; assign mem_rsp_tag_s = mem_rsp_tag; - assign mem_rsp_ready = mem_rsp_ready_s; + assign mem_rsp_ready = mem_rsp_ready_s; end // Handle memory requests ///////////////////////////////////////////////// wire [MEM_BATCHES-1:0][MEM_CHANNELS-1:0] mem_req_mask_b; - wire [MEM_BATCHES-1:0][MEM_CHANNELS-1:0][LINE_SIZE-1:0] mem_req_byteen_b; + wire [MEM_BATCHES-1:0][MEM_CHANNELS-1:0][LINE_SIZE-1:0] mem_req_byteen_b; wire [MEM_BATCHES-1:0][MEM_CHANNELS-1:0][MEM_ADDR_WIDTH-1:0] mem_req_addr_b; wire [MEM_BATCHES-1:0][MEM_CHANNELS-1:0][ATYPE_WIDTH-1:0] mem_req_atype_b; wire [MEM_BATCHES-1:0][MEM_CHANNELS-1:0][LINE_WIDTH-1:0] mem_req_data_b; - + wire [BATCH_SEL_WIDTH-1:0] req_batch_idx; for (genvar i = 0; i < MEM_BATCHES; ++i) begin @@ -331,14 +331,19 @@ module VX_mem_scheduler #( assign mem_req_addr_s = mem_req_addr_b[req_batch_idx]; assign mem_req_atype_s = mem_req_atype_b[req_batch_idx]; assign mem_req_data_s = mem_req_data_b[req_batch_idx]; - + if (MEM_BATCHES != 1) begin reg [MEM_BATCH_BITS-1:0] req_batch_idx_r; + + wire is_degenerate_batch = ~(| mem_req_mask_s); + wire mem_req_valid_b = reqq_valid_s && ~is_degenerate_batch; + wire mem_req_ready_b = mem_req_ready_s || is_degenerate_batch; + always @(posedge clk) begin if (reset) begin req_batch_idx_r <= '0; end else begin - if (reqq_valid_s && mem_req_ready_s) begin + if (reqq_valid_s && mem_req_ready_b) begin if (req_sent_all) begin req_batch_idx_r <= '0; end else begin @@ -352,10 +357,10 @@ module VX_mem_scheduler #( wire [MEM_BATCHES-1:0][MEM_BATCH_BITS-1:0] req_batch_idxs; wire [MEM_BATCH_BITS-1:0] req_batch_idx_last; - for (genvar i = 0; i < MEM_BATCHES; ++i) begin + for (genvar i = 0; i < MEM_BATCHES; ++i) begin assign req_batch_valids[i] = (| mem_req_mask_b[i]); assign req_batch_idxs[i] = MEM_BATCH_BITS'(i); - end + end VX_find_first #( .N (MEM_BATCHES), @@ -368,21 +373,22 @@ module VX_mem_scheduler #( `UNUSED_PIN (valid_out) ); - assign req_batch_idx = req_batch_idx_r; - assign req_sent_all = mem_req_ready_s && (req_batch_idx_r == req_batch_idx_last); + assign mem_req_valid_s = mem_req_valid_b; + assign req_batch_idx = req_batch_idx_r; + assign req_sent_all = mem_req_ready_b && (req_batch_idx_r == req_batch_idx_last); assign mem_req_tag_s = {reqq_tag_s, req_batch_idx}; end else begin + assign mem_req_valid_s = reqq_valid_s; assign req_batch_idx = '0; assign req_sent_all = mem_req_ready_s; assign mem_req_tag_s = reqq_tag_s; end - assign mem_req_valid_s = reqq_valid_s; assign reqq_ready_s = req_sent_all; - + VX_elastic_buffer #( .DATAW (MEM_CHANNELS + 1 + MEM_CHANNELS * (LINE_SIZE + MEM_ADDR_WIDTH + ATYPE_WIDTH + LINE_WIDTH) + MEM_TAG_WIDTH), .SIZE (`TO_OUT_BUF_SIZE(MEM_OUT_BUF)), @@ -415,7 +421,7 @@ module VX_mem_scheduler #( localparam j = r % CORE_CHANNELS; assign curr_mask[r] = (BATCH_SEL_WIDTH'(i) == rsp_batch_idx) && mem_rsp_mask_s[j]; end - + assign rsp_rem_mask_n = rsp_rem_mask[ibuf_raddr] & ~curr_mask; wire rsp_complete = ~(| rsp_rem_mask_n); @@ -457,19 +463,19 @@ module VX_mem_scheduler #( end else begin - reg [CORE_BATCHES*CORE_CHANNELS*WORD_WIDTH-1:0] rsp_store [CORE_QUEUE_SIZE-1:0]; - reg [CORE_BATCHES*CORE_CHANNELS*WORD_WIDTH-1:0] rsp_store_n; - reg [CORE_REQS-1:0] rsp_orig_mask [CORE_QUEUE_SIZE-1:0]; + reg [CORE_BATCHES*CORE_CHANNELS*WORD_WIDTH-1:0] rsp_store [CORE_QUEUE_SIZE-1:0]; + reg [CORE_BATCHES*CORE_CHANNELS*WORD_WIDTH-1:0] rsp_store_n; + reg [CORE_REQS-1:0] rsp_orig_mask [CORE_QUEUE_SIZE-1:0]; always @(*) begin - rsp_store_n = rsp_store[ibuf_raddr]; + rsp_store_n = rsp_store[ibuf_raddr]; for (integer i = 0; i < CORE_CHANNELS; ++i) begin if ((CORE_CHANNELS == 1) || mem_rsp_mask_s[i]) begin rsp_store_n[(rsp_batch_idx * CORE_CHANNELS + i) * WORD_WIDTH +: WORD_WIDTH] = mem_rsp_data_s[i]; end end - end - + end + always @(posedge clk) begin if (ibuf_push) begin rsp_orig_mask[ibuf_waddr] <= core_req_mask; @@ -490,10 +496,11 @@ module VX_mem_scheduler #( end assign mem_rsp_ready_s = crsp_ready || ~rsp_complete; + end if (UUID_WIDTH != 0) begin - assign crsp_tag = {mem_rsp_tag_s[REQQ_TAG_WIDTH-1 -: UUID_WIDTH], ibuf_dout}; + assign crsp_tag = {mem_rsp_tag_s[MEM_TAG_WIDTH-1 -: UUID_WIDTH], ibuf_dout}; end else begin assign crsp_tag = ibuf_dout; end @@ -509,11 +516,11 @@ module VX_mem_scheduler #( ) rsp_buf ( .clk (clk), .reset (reset), - .valid_in (crsp_valid), + .valid_in (crsp_valid), .ready_in (crsp_ready), .data_in ({crsp_mask, crsp_sop, crsp_eop, crsp_data, crsp_tag}), .data_out ({core_rsp_mask, core_rsp_sop, core_rsp_eop, core_rsp_data, core_rsp_tag}), - .valid_out (core_rsp_valid), + .valid_out (core_rsp_valid), .ready_out (core_rsp_ready) ); @@ -541,14 +548,14 @@ module VX_mem_scheduler #( end end - if (ibuf_push) begin + if (ibuf_push) begin pending_reqs_time[ibuf_waddr] <= {req_dbg_uuid, ibuf_din, $time}; end for (integer i = 0; i < CORE_QUEUE_SIZE; ++i) begin if (pending_reqs_valid[i]) begin `ASSERT(($time - pending_reqs_time[i][63:0]) < STALL_TIMEOUT, - ("%t: *** %s response timeout: tag=0x%0h (#%0d)", + ("%t: *** %s response timeout: tag=0x%0h (#%0d)", $time, INSTANCE_ID, pending_reqs_time[i][64 +: TAG_ID_WIDTH], pending_reqs_time[i][64+TAG_ID_WIDTH +: `UP(UUID_WIDTH)])); end end @@ -563,8 +570,8 @@ module VX_mem_scheduler #( wire [`UP(UUID_WIDTH)-1:0] rsp_dbg_uuid; if (UUID_WIDTH != 0) begin - assign mem_req_dbg_uuid = mem_req_tag_s[REQQ_TAG_WIDTH-1 -: UUID_WIDTH]; - assign mem_rsp_dbg_uuid = mem_rsp_tag_s[REQQ_TAG_WIDTH-1 -: UUID_WIDTH]; + assign mem_req_dbg_uuid = mem_req_tag_s[MEM_TAG_WIDTH-1 -: UUID_WIDTH]; + assign mem_rsp_dbg_uuid = mem_rsp_tag_s[MEM_TAG_WIDTH-1 -: UUID_WIDTH]; assign rsp_dbg_uuid = core_rsp_tag[TAG_WIDTH-1 -: UUID_WIDTH]; end else begin assign mem_req_dbg_uuid = '0; @@ -572,25 +579,27 @@ module VX_mem_scheduler #( assign rsp_dbg_uuid = '0; end + wire [CORE_QUEUE_ADDRW-1:0] ibuf_waddr_s = mem_req_tag_s[MEM_BATCH_BITS +: CORE_QUEUE_ADDRW]; + wire mem_req_fire_s = mem_req_valid_s && mem_req_ready_s; always @(posedge clk) begin if (core_req_fire) begin if (core_req_rw) begin `TRACE(1, ("%d: %s-core-req-wr: valid=%b, addr=", $time, INSTANCE_ID, core_req_mask)); - `TRACE_ARRAY1D(1, "0x%h", core_req_addr, CORE_REQS); + `TRACE_ARRAY1D(1, "0x%h", core_req_addr, CORE_REQS); `TRACE(1, (", byteen=")); `TRACE_ARRAY1D(1, "0x%h", core_req_byteen, CORE_REQS); `TRACE(1, (", data=")); - `TRACE_ARRAY1D(1, "0x%0h", core_req_data, CORE_REQS); + `TRACE_ARRAY1D(1, "0x%0h", core_req_data, CORE_REQS); end else begin `TRACE(1, ("%d: %s-core-req-rd: valid=%b, addr=", $time, INSTANCE_ID, core_req_mask)); - `TRACE_ARRAY1D(1, "0x%h", core_req_addr, CORE_REQS); - end - `TRACE(1, (", tag=0x%0h (#%0d)\n", core_req_tag, req_dbg_uuid)); + `TRACE_ARRAY1D(1, "0x%h", core_req_addr, CORE_REQS); + end + `TRACE(1, (", tag=0x%0h (#%0d)\n", core_req_tag, req_dbg_uuid)); end if (core_rsp_valid && core_rsp_ready) begin - `TRACE(1, ("%d: %s-rsp: valid=%b, sop=%b, eop=%b, data=", $time, INSTANCE_ID, core_rsp_mask, core_rsp_sop, core_rsp_eop)); + `TRACE(1, ("%d: %s-core-rsp: valid=%b, sop=%b, eop=%b, data=", $time, INSTANCE_ID, core_rsp_mask, core_rsp_sop, core_rsp_eop)); `TRACE_ARRAY1D(1, "0x%0h", core_rsp_data, CORE_REQS); `TRACE(1, (", tag=0x%0h (#%0d)\n", core_rsp_tag, rsp_dbg_uuid)); end @@ -601,20 +610,20 @@ module VX_mem_scheduler #( `TRACE(1, (", byteen=")); `TRACE_ARRAY1D(1, "0x%h", mem_req_byteen_s, CORE_CHANNELS); `TRACE(1, (", data=")); - `TRACE_ARRAY1D(1, "0x%0h", mem_req_data_s, CORE_CHANNELS); + `TRACE_ARRAY1D(1, "0x%0h", mem_req_data_s, CORE_CHANNELS); end else begin `TRACE(1, ("%d: %s-mem-req-rd: valid=%b, addr=", $time, INSTANCE_ID, mem_req_mask_s)); - `TRACE_ARRAY1D(1, "0x%h", mem_req_addr_s, CORE_CHANNELS); + `TRACE_ARRAY1D(1, "0x%h", mem_req_addr_s, CORE_CHANNELS); end - `TRACE(1, (", ibuf_idx=%0d, batch_idx=%0d (#%0d)\n", ibuf_waddr, req_batch_idx, mem_req_dbg_uuid)); - end + `TRACE(1, (", ibuf_idx=%0d, batch_idx=%0d (#%0d)\n", ibuf_waddr_s, req_batch_idx, mem_req_dbg_uuid)); + end if (mem_rsp_fire_s) begin - `TRACE(1, ("%d: %s-mem-rsp: valid=%b, data=", $time, INSTANCE_ID, mem_rsp_mask_s)); + `TRACE(1, ("%d: %s-mem-rsp: valid=%b, data=", $time, INSTANCE_ID, mem_rsp_mask_s)); `TRACE_ARRAY1D(1, "0x%0h", mem_rsp_data_s, CORE_CHANNELS); `TRACE(1, (", ibuf_idx=%0d, batch_idx=%0d (#%0d)\n", ibuf_raddr, rsp_batch_idx, mem_rsp_dbg_uuid)); end end `endif - + endmodule `TRACING_ON diff --git a/hw/rtl/libs/VX_onehot_mux.sv b/hw/rtl/libs/VX_onehot_mux.sv index 9c8fdb9cf..8d9b87c8e 100644 --- a/hw/rtl/libs/VX_onehot_mux.sv +++ b/hw/rtl/libs/VX_onehot_mux.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -19,131 +19,36 @@ module VX_onehot_mux #( parameter N = 1, parameter MODEL = 1 ) ( - input wire [N-1:0][DATAW-1:0] data_in, - input wire [N-1:0] sel_in, + input wire [N-1:0][DATAW-1:0] data_in, + input wire [N-1:0] sel_in, output wire [DATAW-1:0] data_out -); +); if (N == 1) begin `UNUSED_VAR (sel_in) assign data_out = data_in; - end else if (N == 2) begin - `UNUSED_VAR (sel_in) - assign data_out = sel_in[0] ? data_in[0] : data_in[1]; - end else if (N == 3) begin + end else if (MODEL == 1) begin + wire [N-1:0][DATAW-1:0] mask; + for (genvar i = 0; i < N; ++i) begin + assign mask[i] = {DATAW{sel_in[i]}} & data_in[i]; + end + for (genvar i = 0; i < DATAW; ++i) begin + wire [N-1:0] gather; + for (genvar j = 0; j < N; ++j) begin + assign gather[j] = mask[j][i]; + end + assign data_out[i] = (| gather); + end + end else if (MODEL == 2) begin reg [DATAW-1:0] data_out_r; always @(*) begin - case (sel_in) - 3'b001: data_out_r = data_in[0]; - 3'b010: data_out_r = data_in[1]; - 3'b100: data_out_r = data_in[2]; - default: data_out_r = 'x; - endcase - end - assign data_out = data_out_r; - end else if (N == 4) begin - reg [DATAW-1:0] data_out_r; - always @(*) begin - case (sel_in) - 4'b0001: data_out_r = data_in[0]; - 4'b0010: data_out_r = data_in[1]; - 4'b0100: data_out_r = data_in[2]; - 4'b1000: data_out_r = data_in[3]; - default: data_out_r = 'x; - endcase - end - assign data_out = data_out_r; - end else if (N == 5) begin - reg [DATAW-1:0] data_out_r; - always @(*) begin - case (sel_in) - 5'b00001: data_out_r = data_in[0]; - 5'b00010: data_out_r = data_in[1]; - 5'b00100: data_out_r = data_in[2]; - 5'b01000: data_out_r = data_in[3]; - 5'b10000: data_out_r = data_in[4]; - default: data_out_r = 'x; - endcase - end - assign data_out = data_out_r; - end else if (N == 6) begin - reg [DATAW-1:0] data_out_r; - always @(*) begin - case (sel_in) - 6'b000001: data_out_r = data_in[0]; - 6'b000010: data_out_r = data_in[1]; - 6'b000100: data_out_r = data_in[2]; - 6'b001000: data_out_r = data_in[3]; - 6'b010000: data_out_r = data_in[4]; - 6'b100000: data_out_r = data_in[5]; - default: data_out_r = 'x; - endcase - end - assign data_out = data_out_r; - end else if (N == 7) begin - reg [DATAW-1:0] data_out_r; - always @(*) begin - case (sel_in) - 7'b0000001: data_out_r = data_in[0]; - 7'b0000010: data_out_r = data_in[1]; - 7'b0000100: data_out_r = data_in[2]; - 7'b0001000: data_out_r = data_in[3]; - 7'b0010000: data_out_r = data_in[4]; - 7'b0100000: data_out_r = data_in[5]; - 7'b1000000: data_out_r = data_in[6]; - default: data_out_r = 'x; - endcase - end - assign data_out = data_out_r; - end else if (N == 8) begin - reg [DATAW-1:0] data_out_r; - always @(*) begin - case (sel_in) - 8'b00000001: data_out_r = data_in[0]; - 8'b00000010: data_out_r = data_in[1]; - 8'b00000100: data_out_r = data_in[2]; - 8'b00001000: data_out_r = data_in[3]; - 8'b00010000: data_out_r = data_in[4]; - 8'b00100000: data_out_r = data_in[5]; - 8'b01000000: data_out_r = data_in[6]; - 8'b10000000: data_out_r = data_in[7]; - default: data_out_r = 'x; - endcase - end - assign data_out = data_out_r; - end else begin - if (MODEL == 1) begin - reg [DATAW-1:0] data_out_r; - always @(*) begin - data_out_r = 'x; - for (integer i = 0; i < N; ++i) begin - if (sel_in[i]) begin - data_out_r = data_in[i]; - end + data_out_r = 'x; + for (integer i = 0; i < N; ++i) begin + if (sel_in[i]) begin + data_out_r = data_in[i]; end end - assign data_out = data_out_r; - end else if (MODEL == 2) begin - reg [DATAW-1:0] data_out_r; - always @(*) begin - data_out_r = '0; - for (integer i = 0; i < N; ++i) begin - data_out_r |= {DATAW{sel_in[i]}} & data_in[i]; - end - end - assign data_out = data_out_r; - end else if (MODEL == 3) begin - wire [N-1:0][DATAW-1:0] mask; - for (genvar i = 0; i < N; ++i) begin - assign mask[i] = {DATAW{sel_in[i]}} & data_in[i]; - end - for (genvar i = 0; i < DATAW; ++i) begin - wire [N-1:0] gather; - for (genvar j = 0; j < N; ++j) begin - assign gather[j] = mask[j][i]; - end - assign data_out[i] = (| gather); - end end + assign data_out = data_out_r; end endmodule diff --git a/hw/rtl/libs/VX_pe_serializer.sv b/hw/rtl/libs/VX_pe_serializer.sv index 54de665ed..7060c258c 100644 --- a/hw/rtl/libs/VX_pe_serializer.sv +++ b/hw/rtl/libs/VX_pe_serializer.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,8 +15,8 @@ `TRACING_OFF module VX_pe_serializer #( - parameter NUM_LANES = 1, - parameter NUM_PES = 1, + parameter NUM_LANES = 1, + parameter NUM_PES = 1, parameter LATENCY = 1, parameter DATA_IN_WIDTH = 1, parameter DATA_OUT_WIDTH = 1, @@ -28,12 +28,12 @@ module VX_pe_serializer #( // input input wire valid_in, - input wire [NUM_LANES-1:0][DATA_IN_WIDTH-1:0] data_in, + input wire [NUM_LANES-1:0][DATA_IN_WIDTH-1:0] data_in, input wire [TAG_WIDTH-1:0] tag_in, output wire ready_in, // PE - output wire pe_enable, + output wire pe_enable, output wire [NUM_PES-1:0][DATA_IN_WIDTH-1:0] pe_data_in, input wire [NUM_PES-1:0][DATA_OUT_WIDTH-1:0] pe_data_out, @@ -43,6 +43,7 @@ module VX_pe_serializer #( output wire [TAG_WIDTH-1:0] tag_out, input wire ready_out ); + wire [NUM_PES-1:0][DATA_IN_WIDTH-1:0] pe_data_in_s; wire valid_out_s; wire [TAG_WIDTH-1:0] tag_out_s; wire enable; @@ -59,6 +60,17 @@ module VX_pe_serializer #( .data_out ({valid_out_s, tag_out_s}) ); + VX_pipe_register #( + .DATAW (NUM_PES * DATA_IN_WIDTH), + .DEPTH (PE_REG) + ) pe_reg ( + .clk (clk), + .reset (reset), + .enable (enable), + .data_in (pe_data_in_s), + .data_out (pe_data_in) + ); + if (NUM_LANES != NUM_PES) begin localparam BATCH_SIZE = NUM_LANES / NUM_PES; @@ -67,6 +79,10 @@ module VX_pe_serializer #( reg [BATCH_SIZEW-1:0] batch_in_idx; reg [BATCH_SIZEW-1:0] batch_out_idx; + for (genvar i = 0; i < NUM_PES; ++i) begin + assign pe_data_in_s[i] = data_in[batch_in_idx * NUM_PES + i]; + end + always @(posedge clk) begin if (reset) begin batch_in_idx <= '0; @@ -81,45 +97,29 @@ module VX_pe_serializer #( end end - wire batch_in_done = (batch_in_idx == BATCH_SIZEW'(BATCH_SIZE-1)); + wire batch_in_done = (batch_in_idx == BATCH_SIZEW'(BATCH_SIZE-1)); wire batch_out_done = (batch_out_idx == BATCH_SIZEW'(BATCH_SIZE-1)); - wire [NUM_PES-1:0][DATA_IN_WIDTH-1:0] pe_data_in_s; - for (genvar i = 0; i < NUM_PES; ++i) begin - assign pe_data_in_s[i] = data_in[batch_in_idx * NUM_PES + i]; - end - - VX_pipe_register #( - .DATAW (NUM_PES * DATA_IN_WIDTH), - .DEPTH (PE_REG) - ) pe_reg ( - .clk (clk), - .reset (reset), - .enable (enable), - .data_in (pe_data_in_s), - .data_out (pe_data_in) - ); - reg valid_out_r; reg [BATCH_SIZE-1:0][NUM_PES-1:0][DATA_OUT_WIDTH-1:0] data_out_r; reg [TAG_WIDTH-1:0] tag_out_r; - wire valid_out_b = valid_out_s && batch_out_done; - wire enable_r = ready_out || ~valid_out; + wire valid_out_b = valid_out_s && batch_out_done; + wire ready_out_b = ready_out || ~valid_out; always @(posedge clk) begin if (reset) begin valid_out_r <= 1'b0; - end else if (enable_r) begin + end else if (ready_out_b) begin valid_out_r <= valid_out_b; end - if (enable_r) begin + if (ready_out_b) begin data_out_r[batch_out_idx] <= pe_data_out; tag_out_r <= tag_out_s; end end - - assign enable = (enable_r || ~valid_out_b); + + assign enable = ready_out_b || ~valid_out_b; assign ready_in = enable && batch_in_done; assign pe_enable = enable; @@ -130,16 +130,17 @@ module VX_pe_serializer #( end else begin + assign pe_data_in_s = data_in; + assign enable = ready_out || ~valid_out; assign ready_in = enable; assign pe_enable = enable; - assign pe_data_in= data_in; - assign valid_out = valid_out_s; + assign valid_out = valid_out_s; assign data_out = pe_data_out; assign tag_out = tag_out_s; - + end endmodule diff --git a/hw/rtl/libs/VX_pending_size.sv b/hw/rtl/libs/VX_pending_size.sv index 4f4006179..031e57695 100644 --- a/hw/rtl/libs/VX_pending_size.sv +++ b/hw/rtl/libs/VX_pending_size.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -13,44 +13,53 @@ `include "VX_platform.vh" -`TRACING_OFF +//`TRACING_OFF module VX_pending_size #( - parameter SIZE = 1, - parameter INCRW = 1, - parameter DECRW = 1, - parameter SIZEW = `CLOG2(SIZE+1) + parameter SIZE = 1, + parameter INCRW = 1, + parameter DECRW = 1, + parameter ALM_FULL = (SIZE - 1), + parameter ALM_EMPTY = 1, + parameter SIZEW = `CLOG2(SIZE+1) ) ( input wire clk, input wire reset, input wire [INCRW-1:0] incr, input wire [DECRW-1:0] decr, output wire empty, + output wire alm_empty, output wire full, + output wire alm_full, output wire [SIZEW-1:0] size ); - `STATIC_ASSERT(INCRW <= SIZEW, ("invalid parameter")) - `STATIC_ASSERT(DECRW <= SIZEW, ("invalid parameter")) + `STATIC_ASSERT(INCRW <= SIZEW, ("invalid parameter: %d vs %d", INCRW, SIZEW)) + `STATIC_ASSERT(DECRW <= SIZEW, ("invalid parameter: %d vs %d", DECRW, SIZEW)) localparam ADDRW = `LOG2UP(SIZE); - reg empty_r; - reg full_r; + reg empty_r, alm_empty_r; + reg full_r, alm_full_r; if (INCRW != 1 || DECRW != 1) begin reg [SIZEW-1:0] size_r; - wire [SIZEW-1:0] size_n; - assign size_n = size_r + SIZEW'(incr) - SIZEW'(decr); + wire [SIZEW-1:0] size_n = size_r + SIZEW'(incr) - SIZEW'(decr); always @(posedge clk) begin - if (reset) begin - size_r <= '0; - empty_r <= 1; - full_r <= 0; + if (reset) begin + empty_r <= 1; + alm_empty_r <= 1; + alm_full_r <= 0; + full_r <= 0; + size_r <= '0; end else begin - size_r <= size_n; - empty_r <= (size_n == SIZEW'(0)); - full_r <= (size_n == SIZEW'(SIZE)); + `ASSERT((SIZEW'(incr) >= SIZEW'(decr)) || (size_n >= size_r), ("runtime error: counter overflow")); + `ASSERT((SIZEW'(incr) <= SIZEW'(decr)) || (size_n <= size_r), ("runtime error: counter underflow")); + size_r <= size_n; + empty_r <= (size_n == SIZEW'(0)); + alm_empty_r <= (size_n == SIZEW'(ALM_EMPTY)); + full_r <= (size_n == SIZEW'(SIZE)); + alm_full_r <= (size_n == SIZEW'(ALM_FULL)); end end @@ -59,30 +68,47 @@ module VX_pending_size #( end else begin reg [ADDRW-1:0] used_r; + wire [ADDRW-1:0] used_n; always @(posedge clk) begin - if (reset) begin - used_r <= '0; - empty_r <= 1; - full_r <= 0; - end else begin - `ASSERT(~(incr && ~decr) || ~full, ("runtime error: incrementing full counter")); - `ASSERT(~(decr && ~incr) || ~empty, ("runtime error: decrementing empty counter")); + if (reset) begin + empty_r <= 1; + alm_empty_r <= 1; + full_r <= 0; + alm_full_r <= 0; + used_r <= '0; + end else begin + `ASSERT(~(incr && ~decr) || ~full, ("runtime error: counter overflow")); + `ASSERT(~(decr && ~incr) || ~empty, ("runtime error: counter underflow")); if (incr) begin if (~decr) begin empty_r <= 0; + if (used_r == ADDRW'(ALM_EMPTY)) + alm_empty_r <= 0; if (used_r == ADDRW'(SIZE-1)) full_r <= 1; + if (used_r == ADDRW'(ALM_FULL-1)) + alm_full_r <= 1; end end else if (decr) begin - full_r <= 0; if (used_r == ADDRW'(1)) - empty_r <= 1; + empty_r <= 1; + if (used_r == ADDRW'(ALM_EMPTY+1)) + alm_empty_r <= 1; + full_r <= 0; + if (used_r == ADDRW'(ALM_FULL)) + alm_full_r <= 0; end - used_r <= $signed(used_r) + ADDRW'($signed(2'(incr) - 2'(decr))); + used_r <= used_n; end end + if (SIZE == 2) begin + assign used_n = used_r ^ (incr ^ decr); + end else begin + assign used_n = $signed(used_r) + ADDRW'($signed(2'(incr) - 2'(decr))); + end + if (SIZE > 1) begin if (SIZEW > ADDRW) begin assign size = {full_r, used_r}; @@ -95,8 +121,10 @@ module VX_pending_size #( end - assign empty = empty_r; - assign full = full_r; - + assign empty = empty_r; + assign alm_empty = alm_empty_r; + assign alm_full = alm_full_r; + assign full = full_r; + endmodule -`TRACING_ON +//`TRACING_ON diff --git a/hw/rtl/libs/VX_priority_arbiter.sv b/hw/rtl/libs/VX_priority_arbiter.sv index e807d860b..cd4844d25 100644 --- a/hw/rtl/libs/VX_priority_arbiter.sv +++ b/hw/rtl/libs/VX_priority_arbiter.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -23,8 +23,8 @@ module VX_priority_arbiter #( output wire [NUM_REQS-1:0] grant_onehot, output wire grant_valid ); - if (NUM_REQS == 1) begin - + if (NUM_REQS == 1) begin + assign grant_index = '0; assign grant_onehot = requests; assign grant_valid = requests[0]; @@ -41,6 +41,6 @@ module VX_priority_arbiter #( ); end - + endmodule `TRACING_ON diff --git a/hw/rtl/libs/VX_rr_arbiter.sv b/hw/rtl/libs/VX_rr_arbiter.sv index c1ee4d770..5c5f7b3b4 100644 --- a/hw/rtl/libs/VX_rr_arbiter.sv +++ b/hw/rtl/libs/VX_rr_arbiter.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,24 +16,23 @@ `TRACING_OFF module VX_rr_arbiter #( parameter NUM_REQS = 1, - parameter LOCK_ENABLE = 0, parameter MODEL = 1, parameter LOG_NUM_REQS = `LOG2UP(NUM_REQS) ) ( input wire clk, - input wire reset, - input wire [NUM_REQS-1:0] requests, + input wire reset, + input wire [NUM_REQS-1:0] requests, output wire [LOG_NUM_REQS-1:0] grant_index, - output wire [NUM_REQS-1:0] grant_onehot, + output wire [NUM_REQS-1:0] grant_onehot, output wire grant_valid, - input wire grant_unlock + input wire grant_ready ); if (NUM_REQS == 1) begin `UNUSED_VAR (clk) `UNUSED_VAR (reset) - `UNUSED_VAR (grant_unlock) - + `UNUSED_VAR (grant_ready) + assign grant_index = '0; assign grant_onehot = requests; assign grant_valid = requests[0]; @@ -41,7 +40,7 @@ module VX_rr_arbiter #( end else if (NUM_REQS == 2) begin reg [LOG_NUM_REQS-1:0] grant_index_r; - reg [NUM_REQS-1:0] grant_onehot_r; + reg [NUM_REQS-1:0] grant_onehot_r; reg [LOG_NUM_REQS-1:0] state; always @(*) begin @@ -52,279 +51,279 @@ module VX_rr_arbiter #( endcase end - always @(posedge clk) begin - if (reset) begin + always @(posedge clk) begin + if (reset) begin state <= '0; - end else if (!LOCK_ENABLE || grant_unlock) begin + end else if (grant_ready) begin state <= grant_index_r; end end assign grant_index = grant_index_r; assign grant_onehot = grant_onehot_r; - assign grant_valid = (| requests); + assign grant_valid = (| requests); end /*else if (NUM_REQS == 3) begin reg [LOG_NUM_REQS-1:0] grant_index_r; - reg [NUM_REQS-1:0] grant_onehot_r; + reg [NUM_REQS-1:0] grant_onehot_r; reg [LOG_NUM_REQS-1:0] state; always @(*) begin casez ({state, requests}) 5'b00_001, - 5'b01_0?1, + 5'b01_0?1, 5'b10_??1: begin grant_onehot_r = 3'b001; grant_index_r = LOG_NUM_REQS'(0); end - 5'b00_?1?, - 5'b01_010, + 5'b00_?1?, + 5'b01_010, 5'b10_?10: begin grant_onehot_r = 3'b010; grant_index_r = LOG_NUM_REQS'(1); end default: begin grant_onehot_r = 3'b100; grant_index_r = LOG_NUM_REQS'(2); end endcase end - always @(posedge clk) begin - if (reset) begin + always @(posedge clk) begin + if (reset) begin state <= '0; - end else if (!LOCK_ENABLE || grant_unlock) begin + end else if (grant_ready) begin state <= grant_index_r; end end assign grant_index = grant_index_r; assign grant_onehot = grant_onehot_r; - assign grant_valid = (| requests); + assign grant_valid = (| requests); end */else if (NUM_REQS == 4) begin reg [LOG_NUM_REQS-1:0] grant_index_r; - reg [NUM_REQS-1:0] grant_onehot_r; + reg [NUM_REQS-1:0] grant_onehot_r; reg [LOG_NUM_REQS-1:0] state; always @(*) begin casez ({state, requests}) - 6'b00_0001, - 6'b01_00?1, + 6'b00_0001, + 6'b01_00?1, 6'b10_0??1, 6'b11_???1: begin grant_onehot_r = 4'b0001; grant_index_r = LOG_NUM_REQS'(0); end - 6'b00_??1?, - 6'b01_0010, - 6'b10_0?10, + 6'b00_??1?, + 6'b01_0010, + 6'b10_0?10, 6'b11_??10: begin grant_onehot_r = 4'b0010; grant_index_r = LOG_NUM_REQS'(1); end - 6'b00_?10?, - 6'b01_?1??, - 6'b10_0100, + 6'b00_?10?, + 6'b01_?1??, + 6'b10_0100, 6'b11_?100: begin grant_onehot_r = 4'b0100; grant_index_r = LOG_NUM_REQS'(2); end default: begin grant_onehot_r = 4'b1000; grant_index_r = LOG_NUM_REQS'(3); end endcase end - always @(posedge clk) begin - if (reset) begin + always @(posedge clk) begin + if (reset) begin state <= '0; - end else if (!LOCK_ENABLE || grant_unlock) begin + end else if (grant_ready) begin state <= grant_index_r; end end assign grant_index = grant_index_r; assign grant_onehot = grant_onehot_r; - assign grant_valid = (| requests); + assign grant_valid = (| requests); end /*else if (NUM_REQS == 5) begin reg [LOG_NUM_REQS-1:0] grant_index_r; - reg [NUM_REQS-1:0] grant_onehot_r; + reg [NUM_REQS-1:0] grant_onehot_r; reg [LOG_NUM_REQS-1:0] state; always @(*) begin casez ({state, requests}) - 8'b000_00001, - 8'b001_000?1, - 8'b010_00??1, + 8'b000_00001, + 8'b001_000?1, + 8'b010_00??1, 8'b011_0???1, 8'b100_????1: begin grant_onehot_r = 5'b00001; grant_index_r = LOG_NUM_REQS'(0); end - 8'b000_???1?, - 8'b001_00010, - 8'b010_00?10, - 8'b011_0??10, + 8'b000_???1?, + 8'b001_00010, + 8'b010_00?10, + 8'b011_0??10, 8'b100_???10: begin grant_onehot_r = 5'b00010; grant_index_r = LOG_NUM_REQS'(1); end - 8'b000_??10?, - 8'b001_??1??, - 8'b010_00100, + 8'b000_??10?, + 8'b001_??1??, + 8'b010_00100, 8'b011_0?100, 8'b100_??100: begin grant_onehot_r = 5'b00100; grant_index_r = LOG_NUM_REQS'(2); end - 8'b000_?100?, - 8'b001_?10??, + 8'b000_?100?, + 8'b001_?10??, 8'b010_?1???, - 8'b011_01000, + 8'b011_01000, 8'b100_?1000: begin grant_onehot_r = 5'b01000; grant_index_r = LOG_NUM_REQS'(3); end default: begin grant_onehot_r = 5'b10000; grant_index_r = LOG_NUM_REQS'(4); end endcase end - always @(posedge clk) begin - if (reset) begin + always @(posedge clk) begin + if (reset) begin state <= '0; - end else if (!LOCK_ENABLE || grant_unlock) begin + end else if (grant_ready) begin state <= grant_index_r; end end assign grant_index = grant_index_r; assign grant_onehot = grant_onehot_r; - assign grant_valid = (| requests); + assign grant_valid = (| requests); end else if (NUM_REQS == 6) begin reg [LOG_NUM_REQS-1:0] grant_index_r; - reg [NUM_REQS-1:0] grant_onehot_r; + reg [NUM_REQS-1:0] grant_onehot_r; reg [LOG_NUM_REQS-1:0] state; always @(*) begin casez ({state, requests}) - 9'b000_000001, - 9'b001_0000?1, - 9'b010_000??1, - 9'b011_00???1, - 9'b100_0????1, + 9'b000_000001, + 9'b001_0000?1, + 9'b010_000??1, + 9'b011_00???1, + 9'b100_0????1, 9'b101_?????1: begin grant_onehot_r = 6'b000001; grant_index_r = LOG_NUM_REQS'(0); end - 9'b000_????1?, - 9'b001_000010, - 9'b010_000?10, - 9'b011_00??10, - 9'b100_0???10, + 9'b000_????1?, + 9'b001_000010, + 9'b010_000?10, + 9'b011_00??10, + 9'b100_0???10, 9'b101_????10: begin grant_onehot_r = 6'b000010; grant_index_r = LOG_NUM_REQS'(1); end - 9'b000_???10?, - 9'b001_???1??, - 9'b010_000100, + 9'b000_???10?, + 9'b001_???1??, + 9'b010_000100, 9'b011_00?100, - 9'b100_0??100, + 9'b100_0??100, 9'b101_???100: begin grant_onehot_r = 6'b000100; grant_index_r = LOG_NUM_REQS'(2); end - 9'b000_??100?, - 9'b001_??10??, + 9'b000_??100?, + 9'b001_??10??, 9'b010_??1???, - 9'b011_001000, - 9'b100_0?1000, + 9'b011_001000, + 9'b100_0?1000, 9'b101_??1000: begin grant_onehot_r = 6'b001000; grant_index_r = LOG_NUM_REQS'(3); end - 9'b000_?1000?, - 9'b001_?100??, + 9'b000_?1000?, + 9'b001_?100??, 9'b010_?10???, - 9'b011_?1????, - 9'b100_010000, + 9'b011_?1????, + 9'b100_010000, 9'b101_?10000: begin grant_onehot_r = 6'b010000; grant_index_r = LOG_NUM_REQS'(4); end default: begin grant_onehot_r = 6'b100000; grant_index_r = LOG_NUM_REQS'(5); end endcase end - always @(posedge clk) begin - if (reset) begin + always @(posedge clk) begin + if (reset) begin state <= '0; - end else if (!LOCK_ENABLE || grant_unlock) begin + end else if (grant_ready) begin state <= grant_index_r; end end assign grant_index = grant_index_r; assign grant_onehot = grant_onehot_r; - assign grant_valid = (| requests); + assign grant_valid = (| requests); end else if (NUM_REQS == 7) begin reg [LOG_NUM_REQS-1:0] grant_index_r; - reg [NUM_REQS-1:0] grant_onehot_r; + reg [NUM_REQS-1:0] grant_onehot_r; reg [LOG_NUM_REQS-1:0] state; always @(*) begin casez ({state, requests}) - 10'b000_000001, - 10'b001_0000?1, - 10'b010_000??1, - 10'b011_00???1, - 10'b100_00???1, - 10'b101_0????1, + 10'b000_000001, + 10'b001_0000?1, + 10'b010_000??1, + 10'b011_00???1, + 10'b100_00???1, + 10'b101_0????1, 10'b110_?????1: begin grant_onehot_r = 7'b0000001; grant_index_r = LOG_NUM_REQS'(0); end - 10'b000_?????1?, - 10'b001_0000010, - 10'b010_0000?10, - 10'b011_000??10, - 10'b100_00???10, - 10'b101_0????10, + 10'b000_?????1?, + 10'b001_0000010, + 10'b010_0000?10, + 10'b011_000??10, + 10'b100_00???10, + 10'b101_0????10, 10'b110_?????10: begin grant_onehot_r = 7'b0000010; grant_index_r = LOG_NUM_REQS'(1); end - 10'b000_????10?, - 10'b001_????1??, - 10'b010_0000100, + 10'b000_????10?, + 10'b001_????1??, + 10'b010_0000100, 10'b011_000?100, - 10'b100_00??100, - 10'b101_0???100, + 10'b100_00??100, + 10'b101_0???100, 10'b110_????100: begin grant_onehot_r = 7'b0000100; grant_index_r = LOG_NUM_REQS'(2); end - 10'b000_???100?, - 10'b001_???10??, + 10'b000_???100?, + 10'b001_???10??, 10'b010_???1???, - 10'b011_0001000, - 10'b100_00?1000, - 10'b101_0??1000, + 10'b011_0001000, + 10'b100_00?1000, + 10'b101_0??1000, 10'b110_???1000: begin grant_onehot_r = 7'b0001000; grant_index_r = LOG_NUM_REQS'(3); end - 10'b000_??1000?, - 10'b001_??100??, + 10'b000_??1000?, + 10'b001_??100??, 10'b010_??10???, - 10'b011_??1????, - 10'b100_0010000, - 10'b101_0?10000, + 10'b011_??1????, + 10'b100_0010000, + 10'b101_0?10000, 10'b110_??10000: begin grant_onehot_r = 7'b0010000; grant_index_r = LOG_NUM_REQS'(4); end - 10'b000_?10000?, - 10'b001_?1000??, + 10'b000_?10000?, + 10'b001_?1000??, 10'b010_?100???, - 10'b011_?10????, - 10'b100_?1?????, - 10'b101_0100000, + 10'b011_?10????, + 10'b100_?1?????, + 10'b101_0100000, 10'b110_?100000: begin grant_onehot_r = 7'b0100000; grant_index_r = LOG_NUM_REQS'(5); end default: begin grant_onehot_r = 7'b1000000; grant_index_r = LOG_NUM_REQS'(6); end endcase end - always @(posedge clk) begin - if (reset) begin + always @(posedge clk) begin + if (reset) begin state <= '0; - end else if (!LOCK_ENABLE || grant_unlock) begin + end else if (grant_ready) begin state <= grant_index_r; end end assign grant_index = grant_index_r; assign grant_onehot = grant_onehot_r; - assign grant_valid = (| requests); + assign grant_valid = (| requests); end */else if (NUM_REQS == 8) begin reg [LOG_NUM_REQS-1:0] grant_index_r; - reg [NUM_REQS-1:0] grant_onehot_r; + reg [NUM_REQS-1:0] grant_onehot_r; reg [LOG_NUM_REQS-1:0] state; always @(*) begin casez ({state, requests}) - 11'b000_00000001, - 11'b001_000000?1, - 11'b010_00000??1, + 11'b000_00000001, + 11'b001_000000?1, + 11'b010_00000??1, 11'b011_0000???1, - 11'b100_000????1, - 11'b101_00?????1, - 11'b110_0??????1, + 11'b100_000????1, + 11'b101_00?????1, + 11'b110_0??????1, 11'b111_???????1: begin grant_onehot_r = 8'b00000001; grant_index_r = LOG_NUM_REQS'(0); end - 11'b000_??????1?, - 11'b001_00000010, - 11'b010_00000?10, + 11'b000_??????1?, + 11'b001_00000010, + 11'b010_00000?10, 11'b011_0000??10, - 11'b100_000???10, - 11'b101_00????10, - 11'b110_0?????10, + 11'b100_000???10, + 11'b101_00????10, + 11'b110_0?????10, 11'b111_??????10: begin grant_onehot_r = 8'b00000010; grant_index_r = LOG_NUM_REQS'(1); end - 11'b000_?????10?, - 11'b001_?????1??, - 11'b010_00000100, + 11'b000_?????10?, + 11'b001_?????1??, + 11'b010_00000100, 11'b011_0000?100, - 11'b100_000??100, - 11'b101_00???100, - 11'b110_0????100, + 11'b100_000??100, + 11'b101_00???100, + 11'b110_0????100, 11'b111_?????100: begin grant_onehot_r = 8'b00000100; grant_index_r = LOG_NUM_REQS'(2); end 11'b000_????100?, 11'b001_????10??, @@ -362,20 +361,20 @@ module VX_rr_arbiter #( endcase end - always @(posedge clk) begin - if (reset) begin + always @(posedge clk) begin + if (reset) begin state <= '0; - end else if (!LOCK_ENABLE || grant_unlock) begin + end else if (grant_ready) begin state <= grant_index_r; end end assign grant_index = grant_index_r; assign grant_onehot = grant_onehot_r; - assign grant_valid = (| requests); - + assign grant_valid = (| requests); + end else if (MODEL == 1) begin - + `IGNORE_UNOPTFLAT_BEGIN wire [NUM_REQS-1:0] mask_higher_pri_regs, unmask_higher_pri_regs; `IGNORE_UNOPTFLAT_END @@ -385,12 +384,18 @@ module VX_rr_arbiter #( wire [NUM_REQS-1:0] req_masked = requests & pointer_reg; - assign mask_higher_pri_regs[NUM_REQS-1:1] = mask_higher_pri_regs[NUM_REQS-2:0] | req_masked[NUM_REQS-2:0]; assign mask_higher_pri_regs[0] = 1'b0; + for (genvar i = 1; i < NUM_REQS; ++i) begin + assign mask_higher_pri_regs[i] = mask_higher_pri_regs[i-1] | req_masked[i-1]; + end + assign grant_masked[NUM_REQS-1:0] = req_masked[NUM_REQS-1:0] & ~mask_higher_pri_regs[NUM_REQS-1:0]; - assign unmask_higher_pri_regs[NUM_REQS-1:1] = unmask_higher_pri_regs[NUM_REQS-2:0] | requests[NUM_REQS-2:0]; assign unmask_higher_pri_regs[0] = 1'b0; + for (genvar i = 1; i < NUM_REQS; ++i) begin + assign unmask_higher_pri_regs[i] = unmask_higher_pri_regs[i-1] | requests[i-1]; + end + assign grant_unmasked[NUM_REQS-1:0] = requests[NUM_REQS-1:0] & ~unmask_higher_pri_regs[NUM_REQS-1:0]; wire no_req_masked = ~(|req_masked); @@ -399,7 +404,7 @@ module VX_rr_arbiter #( always @(posedge clk) begin if (reset) begin pointer_reg <= {NUM_REQS{1'b1}}; - end else if (!LOCK_ENABLE || grant_unlock) begin + end else if (grant_ready) begin if (|req_masked) begin pointer_reg <= mask_higher_pri_regs; end else if (|requests) begin @@ -410,22 +415,22 @@ module VX_rr_arbiter #( end end - assign grant_valid = (| requests); + assign grant_valid = (| requests); VX_onehot_encoder #( .N (NUM_REQS) ) onehot_encoder ( .data_in (grant_onehot), - .data_out (grant_index), + .data_out (grant_index), `UNUSED_PIN (valid_out) ); - + end else begin - + reg [LOG_NUM_REQS-1:0] grant_index_r; - reg [NUM_REQS-1:0] grant_onehot_r; - reg [NUM_REQS-1:0] state; - + reg [NUM_REQS-1:0] grant_onehot_r; + reg [NUM_REQS-1:0] state; + always @(*) begin grant_index_r = 'x; grant_onehot_r = 'x; @@ -440,18 +445,18 @@ module VX_rr_arbiter #( end end - always @(posedge clk) begin - if (reset) begin + always @(posedge clk) begin + if (reset) begin state <= '0; - end else if (!LOCK_ENABLE || grant_unlock) begin + end else if (grant_ready) begin state <= grant_index_r; end end assign grant_index = grant_index_r; assign grant_onehot = grant_onehot_r; - assign grant_valid = (| requests); + assign grant_valid = (| requests); end - + endmodule `TRACING_ON diff --git a/hw/rtl/libs/VX_sp_ram.sv b/hw/rtl/libs/VX_sp_ram.sv index 1496d448e..297a23d20 100644 --- a/hw/rtl/libs/VX_sp_ram.sv +++ b/hw/rtl/libs/VX_sp_ram.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -17,17 +17,18 @@ module VX_sp_ram #( parameter DATAW = 1, parameter SIZE = 1, + parameter ADDR_MIN = 0, parameter WRENW = 1, parameter OUT_REG = 0, parameter NO_RWCHECK = 0, - parameter LUTRAM = 0, + parameter LUTRAM = 0, parameter INIT_ENABLE = 0, parameter INIT_FILE = "", parameter [DATAW-1:0] INIT_VALUE = 0, parameter ADDRW = `LOG2UP(SIZE) -) ( - input wire clk, - input wire read, +) ( + input wire clk, + input wire read, input wire write, input wire [WRENW-1:0] wren, input wire [ADDRW-1:0] addr, @@ -37,6 +38,7 @@ module VX_sp_ram #( VX_dp_ram #( .DATAW (DATAW), .SIZE (SIZE), + .ADDR_MIN (ADDR_MIN), .WRENW (WRENW), .OUT_REG (OUT_REG), .NO_RWCHECK (NO_RWCHECK), diff --git a/hw/rtl/libs/VX_stream_arb.sv b/hw/rtl/libs/VX_stream_arb.sv index a687c9337..f9bb24f3d 100644 --- a/hw/rtl/libs/VX_stream_arb.sv +++ b/hw/rtl/libs/VX_stream_arb.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,7 +20,8 @@ module VX_stream_arb #( parameter DATAW = 1, parameter `STRING ARBITER = "P", parameter MAX_FANOUT = `MAX_FANOUT, - parameter OUT_BUF = 0 , + parameter OUT_BUF = 0, + parameter LUTRAM = 0, parameter NUM_REQS = `CDIV(NUM_INPUTS, NUM_OUTPUTS), parameter LOG_NUM_REQS = `CLOG2(NUM_REQS), parameter NUM_REQS_W = `UP(LOG_NUM_REQS) @@ -42,7 +43,7 @@ module VX_stream_arb #( if (NUM_OUTPUTS > 1) begin // (#inputs > #outputs) and (#outputs > 1) - + for (genvar i = 0; i < NUM_OUTPUTS; ++i) begin localparam BATCH_BEGIN = i * NUM_REQS; @@ -57,7 +58,8 @@ module VX_stream_arb #( .DATAW (DATAW), .ARBITER (ARBITER), .MAX_FANOUT (MAX_FANOUT), - .OUT_BUF (OUT_BUF) + .OUT_BUF (OUT_BUF), + .LUTRAM (LUTRAM) ) arb_slice ( .clk (clk), .reset (slice_reset), @@ -81,8 +83,8 @@ module VX_stream_arb #( wire [NUM_BATCHES-1:0] valid_tmp; wire [NUM_BATCHES-1:0][DATAW+LOG_NUM_REQS2-1:0] data_tmp; - wire [NUM_BATCHES-1:0] ready_tmp; - + wire [NUM_BATCHES-1:0] ready_tmp; + for (genvar i = 0; i < NUM_BATCHES; ++i) begin localparam BATCH_BEGIN = i * MAX_FANOUT; @@ -97,18 +99,19 @@ module VX_stream_arb #( if (MAX_FANOUT != 1) begin VX_stream_arb #( .NUM_INPUTS (BATCH_SIZE), - .NUM_OUTPUTS (1), + .NUM_OUTPUTS (1), .DATAW (DATAW), .ARBITER (ARBITER), .MAX_FANOUT (MAX_FANOUT), - .OUT_BUF (OUT_BUF) + .OUT_BUF (3), // registered output + .LUTRAM (LUTRAM) ) fanout_slice_arb ( .clk (clk), .reset (slice_reset), .valid_in (valid_in[BATCH_END-1: BATCH_BEGIN]), .data_in (data_in[BATCH_END-1: BATCH_BEGIN]), - .ready_in (ready_in[BATCH_END-1: BATCH_BEGIN]), - .valid_out (valid_tmp[i]), + .ready_in (ready_in[BATCH_END-1: BATCH_BEGIN]), + .valid_out (valid_tmp[i]), .data_out (data_tmp_u), .sel_out (sel_tmp_u), .ready_out (ready_tmp[i]) @@ -123,11 +126,12 @@ module VX_stream_arb #( VX_stream_arb #( .NUM_INPUTS (NUM_BATCHES), - .NUM_OUTPUTS (1), + .NUM_OUTPUTS (1), .DATAW (DATAW + LOG_NUM_REQS2), .ARBITER (ARBITER), .MAX_FANOUT (MAX_FANOUT), - .OUT_BUF (OUT_BUF) + .OUT_BUF (OUT_BUF), + .LUTRAM (LUTRAM) ) fanout_join_arb ( .clk (clk), .reset (reset), @@ -150,16 +154,15 @@ module VX_stream_arb #( wire valid_in_r; wire [DATAW-1:0] data_in_r; wire ready_in_r; - + wire arb_valid; wire [NUM_REQS_W-1:0] arb_index; wire [NUM_REQS-1:0] arb_onehot; wire arb_ready; VX_generic_arbiter #( - .NUM_REQS (NUM_REQS), - .LOCK_ENABLE (1), - .TYPE (ARBITER) + .NUM_REQS (NUM_REQS), + .TYPE (ARBITER) ) arbiter ( .clk (clk), .reset (reset), @@ -167,21 +170,30 @@ module VX_stream_arb #( .grant_valid (arb_valid), .grant_index (arb_index), .grant_onehot (arb_onehot), - .grant_unlock (arb_ready) + .grant_ready (arb_ready) ); assign valid_in_r = arb_valid; - assign data_in_r = data_in[arb_index]; assign arb_ready = ready_in_r; + VX_onehot_mux #( + .DATAW (DATAW), + .N (NUM_REQS) + ) onehot_mux ( + .data_in (data_in), + .sel_in (arb_onehot), + .data_out (data_in_r) + ); + for (genvar i = 0; i < NUM_REQS; ++i) begin - assign ready_in[i] = ready_in_r & arb_onehot[i]; + assign ready_in[i] = ready_in_r && arb_onehot[i]; end VX_elastic_buffer #( .DATAW (LOG_NUM_REQS + DATAW), .SIZE (`TO_OUT_BUF_SIZE(OUT_BUF)), - .OUT_REG (`TO_OUT_BUF_REG(OUT_BUF)) + .OUT_REG (`TO_OUT_BUF_REG(OUT_BUF)), + .LUTRAM (LUTRAM) ) out_buf ( .clk (clk), .reset (reset), @@ -214,7 +226,8 @@ module VX_stream_arb #( .DATAW (DATAW), .ARBITER (ARBITER), .MAX_FANOUT (MAX_FANOUT), - .OUT_BUF (OUT_BUF) + .OUT_BUF (OUT_BUF), + .LUTRAM (LUTRAM) ) arb_slice ( .clk (clk), .reset (slice_reset), @@ -248,19 +261,20 @@ module VX_stream_arb #( .DATAW (DATAW), .ARBITER (ARBITER), .MAX_FANOUT (MAX_FANOUT), - .OUT_BUF (OUT_BUF) + .OUT_BUF (3), // registered output + .LUTRAM (LUTRAM) ) fanout_fork_arb ( .clk (clk), .reset (reset), .valid_in (valid_in), .ready_in (ready_in), - .data_in (data_in), + .data_in (data_in), .data_out (data_tmp), .valid_out (valid_tmp), .ready_out (ready_tmp), `UNUSED_PIN (sel_out) ); - + for (genvar i = 0; i < NUM_BATCHES; ++i) begin localparam BATCH_BEGIN = i * MAX_FANOUT; @@ -271,11 +285,12 @@ module VX_stream_arb #( VX_stream_arb #( .NUM_INPUTS (1), - .NUM_OUTPUTS (BATCH_SIZE), + .NUM_OUTPUTS (BATCH_SIZE), .DATAW (DATAW), .ARBITER (ARBITER), .MAX_FANOUT (MAX_FANOUT), - .OUT_BUF (OUT_BUF) + .OUT_BUF (OUT_BUF), + .LUTRAM (LUTRAM) ) fanout_slice_arb ( .clk (clk), .reset (slice_reset), @@ -293,25 +308,24 @@ module VX_stream_arb #( // (#inputs == 1) and (#outputs <= max_fanout) - wire [NUM_OUTPUTS-1:0] ready_in_r; - + wire [NUM_OUTPUTS-1:0] ready_in_r; + wire [NUM_OUTPUTS-1:0] arb_requests; wire arb_valid; wire [NUM_OUTPUTS-1:0] arb_onehot; wire arb_ready; VX_generic_arbiter #( - .NUM_REQS (NUM_OUTPUTS), - .LOCK_ENABLE (1), - .TYPE (ARBITER) + .NUM_REQS (NUM_OUTPUTS), + .TYPE (ARBITER) ) arbiter ( .clk (clk), .reset (reset), .requests (arb_requests), .grant_valid (arb_valid), - `UNUSED_PIN (grant_index), + `UNUSED_PIN (grant_index), .grant_onehot (arb_onehot), - .grant_unlock (arb_ready) + .grant_ready (arb_ready) ); assign arb_requests = ready_in_r; @@ -320,9 +334,10 @@ module VX_stream_arb #( for (genvar i = 0; i < NUM_OUTPUTS; ++i) begin VX_elastic_buffer #( - .DATAW (DATAW), - .SIZE (`TO_OUT_BUF_SIZE(OUT_BUF)), - .OUT_REG (`TO_OUT_BUF_REG(OUT_BUF)) + .DATAW (DATAW), + .SIZE (`TO_OUT_BUF_SIZE(OUT_BUF)), + .OUT_REG (`TO_OUT_BUF_REG(OUT_BUF)), + .LUTRAM (LUTRAM) ) out_buf ( .clk (clk), .reset (reset), @@ -337,7 +352,7 @@ module VX_stream_arb #( end assign sel_out = 0; - + end else begin // #Inputs == #Outputs @@ -349,7 +364,8 @@ module VX_stream_arb #( VX_elastic_buffer #( .DATAW (DATAW), .SIZE (`TO_OUT_BUF_SIZE(OUT_BUF)), - .OUT_REG (`TO_OUT_BUF_REG(OUT_BUF)) + .OUT_REG (`TO_OUT_BUF_REG(OUT_BUF)), + .LUTRAM (LUTRAM) ) out_buf ( .clk (clk), .reset (out_buf_reset), @@ -363,6 +379,6 @@ module VX_stream_arb #( assign sel_out[i] = NUM_REQS_W'(i); end end - + endmodule `TRACING_ON diff --git a/hw/rtl/libs/VX_stream_pack.sv b/hw/rtl/libs/VX_stream_pack.sv index 3c1bbdbe6..df0000307 100644 --- a/hw/rtl/libs/VX_stream_pack.sv +++ b/hw/rtl/libs/VX_stream_pack.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,9 +15,9 @@ `TRACING_OFF module VX_stream_pack #( - parameter NUM_REQS = 1, - parameter DATA_WIDTH = 1, - parameter TAG_WIDTH = 1, + parameter NUM_REQS = 1, + parameter DATA_WIDTH = 1, + parameter TAG_WIDTH = 1, parameter TAG_SEL_BITS = 0, parameter `STRING ARBITER = "P", parameter OUT_BUF = 0 @@ -38,47 +38,48 @@ module VX_stream_pack #( output wire [TAG_WIDTH-1:0] tag_out, input wire ready_out ); - localparam LOG_NUM_REQS = `CLOG2(NUM_REQS); - if (NUM_REQS > 1) begin - wire [LOG_NUM_REQS-1:0] grant_index; + wire [NUM_REQS-1:0] grant_onehot; wire grant_valid; wire grant_ready; VX_generic_arbiter #( .NUM_REQS (NUM_REQS), - .LOCK_ENABLE (1), - .TYPE (ARBITER) + .TYPE (ARBITER) ) arbiter ( .clk (clk), .reset (reset), - .requests (valid_in), + .requests (valid_in), .grant_valid (grant_valid), - .grant_index (grant_index), - `UNUSED_PIN (grant_onehot), - .grant_unlock(grant_ready) + `UNUSED_PIN (grant_index), + .grant_onehot(grant_onehot), + .grant_ready (grant_ready) ); - reg [NUM_REQS-1:0] valid_sel; - reg [NUM_REQS-1:0] ready_sel; - wire ready_unqual; + wire [TAG_WIDTH-1:0] tag_sel; - wire [TAG_WIDTH-1:0] tag_sel = tag_in[grant_index]; - - always @(*) begin - valid_sel = '0; - ready_sel = '0; - for (integer i = 0; i < NUM_REQS; ++i) begin - if (tag_in[i][TAG_SEL_BITS-1:0] == tag_sel[TAG_SEL_BITS-1:0]) begin - valid_sel[i] = valid_in[i]; - ready_sel[i] = ready_unqual; - end - end - end + VX_onehot_mux #( + .DATAW (TAG_WIDTH), + .N (NUM_REQS) + ) onehot_mux ( + .data_in (tag_in), + .sel_in (grant_onehot), + .data_out (tag_sel) + ); + + wire [NUM_REQS-1:0] tag_matches; + + for (genvar i = 0; i < NUM_REQS; ++i) begin + assign tag_matches[i] = (tag_in[i][TAG_SEL_BITS-1:0] == tag_sel[TAG_SEL_BITS-1:0]); + end + + for (genvar i = 0; i < NUM_REQS; ++i) begin + assign ready_in[i] = grant_ready & tag_matches[i]; + end + + wire [NUM_REQS-1:0] mask_sel = valid_in & tag_matches; - assign grant_ready = ready_unqual; - VX_elastic_buffer #( .DATAW (NUM_REQS + TAG_WIDTH + (NUM_REQS * DATA_WIDTH)), .SIZE (`TO_OUT_BUF_SIZE(OUT_BUF)), @@ -86,16 +87,14 @@ module VX_stream_pack #( ) out_buf ( .clk (clk), .reset (reset), - .valid_in (grant_valid), - .data_in ({valid_sel, tag_sel, data_in}), - .ready_in (ready_unqual), + .valid_in (grant_valid), + .data_in ({mask_sel, tag_sel, data_in}), + .ready_in (grant_ready), .valid_out (valid_out), .data_out ({mask_out, tag_out, data_out}), .ready_out (ready_out) - ); + ); - assign ready_in = ready_sel; - end else begin `UNUSED_VAR (clk) diff --git a/hw/rtl/libs/VX_stream_xbar.sv b/hw/rtl/libs/VX_stream_xbar.sv index 735ec8474..cb0d9a179 100644 --- a/hw/rtl/libs/VX_stream_xbar.sv +++ b/hw/rtl/libs/VX_stream_xbar.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -22,6 +22,7 @@ module VX_stream_xbar #( parameter OUT_WIDTH = `LOG2UP(NUM_OUTPUTS), parameter ARBITER = "P", parameter OUT_BUF = 0, + parameter LUTRAM = 0, parameter MAX_FANOUT = `MAX_FANOUT, parameter PERF_CTR_BITS = `CLOG2(NUM_INPUTS+1) ) ( @@ -36,7 +37,7 @@ module VX_stream_xbar #( output wire [NUM_INPUTS-1:0] ready_in, output wire [NUM_OUTPUTS-1:0] valid_out, - output wire [NUM_OUTPUTS-1:0][DATAW-1:0] data_out, + output wire [NUM_OUTPUTS-1:0][DATAW-1:0] data_out, output wire [NUM_OUTPUTS-1:0][IN_WIDTH-1:0] sel_out, input wire [NUM_OUTPUTS-1:0] ready_out ); @@ -66,7 +67,8 @@ module VX_stream_xbar #( .DATAW (DATAW), .ARBITER (ARBITER), .MAX_FANOUT (MAX_FANOUT), - .OUT_BUF (OUT_BUF) + .OUT_BUF (OUT_BUF), + .LUTRAM (LUTRAM) ) xbar_arb ( .clk (clk), .reset (slice_reset), @@ -94,7 +96,8 @@ module VX_stream_xbar #( .DATAW (DATAW), .ARBITER (ARBITER), .MAX_FANOUT (MAX_FANOUT), - .OUT_BUF (OUT_BUF) + .OUT_BUF (OUT_BUF), + .LUTRAM (LUTRAM) ) xbar_arb ( .clk (clk), .reset (reset), @@ -124,13 +127,14 @@ module VX_stream_xbar #( assign ready_in = ready_out_r[sel_in]; for (genvar i = 0; i < NUM_OUTPUTS; ++i) begin - + `RESET_RELAY (out_buf_reset, reset); VX_elastic_buffer #( .DATAW (DATAW), .SIZE (`TO_OUT_BUF_SIZE(OUT_BUF)), - .OUT_REG (`TO_OUT_BUF_REG(OUT_BUF)) + .OUT_REG (`TO_OUT_BUF_REG(OUT_BUF)), + .LUTRAM (LUTRAM) ) out_buf ( .clk (clk), .reset (out_buf_reset), @@ -152,7 +156,8 @@ module VX_stream_xbar #( VX_elastic_buffer #( .DATAW (DATAW), .SIZE (`TO_OUT_BUF_SIZE(OUT_BUF)), - .OUT_REG (`TO_OUT_BUF_REG(OUT_BUF)) + .OUT_REG (`TO_OUT_BUF_REG(OUT_BUF)), + .LUTRAM (LUTRAM) ) out_buf ( .clk (clk), .reset (reset), @@ -172,7 +177,7 @@ module VX_stream_xbar #( // compute inputs collision // we have a collision when there exists a valid transfer with multiple input candicates // we count the unique duplicates each cycle. - + reg [NUM_INPUTS-1:0] per_cycle_collision, per_cycle_collision_r; wire [`CLOG2(NUM_INPUTS+1)-1:0] collision_count; reg [PERF_CTR_BITS-1:0] collisions_r; @@ -182,14 +187,14 @@ module VX_stream_xbar #( for (integer i = 0; i < NUM_INPUTS; ++i) begin for (integer j = 1; j < (NUM_INPUTS-i); ++j) begin per_cycle_collision[i] |= valid_in[i] - && valid_in[j+i] + && valid_in[j+i] && (sel_in[i] == sel_in[j+i]) && (ready_in[i] | ready_in[j+i]); end end end - - `BUFFER(per_cycle_collision_r, per_cycle_collision); + + `BUFFER(per_cycle_collision_r, per_cycle_collision); `POP_COUNT(collision_count, per_cycle_collision_r); always @(posedge clk) begin diff --git a/hw/rtl/mem/VX_local_mem.sv b/hw/rtl/mem/VX_local_mem.sv index 4a6562dcb..f59ebae5b 100644 --- a/hw/rtl/mem/VX_local_mem.sv +++ b/hw/rtl/mem/VX_local_mem.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -17,10 +17,10 @@ module VX_local_mem import VX_gpu_pkg::*; #( parameter `STRING INSTANCE_ID = "", // Size of cache in bytes - parameter SIZE = (1024*16*8), - + parameter SIZE = (1024*16*8), + // Number of Word requests per cycle - parameter NUM_REQS = 4, + parameter NUM_REQS = 4, // Number of banks parameter NUM_BANKS = 4, @@ -33,8 +33,11 @@ module VX_local_mem import VX_gpu_pkg::*; #( parameter UUID_WIDTH = 0, // Request tag size - parameter TAG_WIDTH = 16 - ) ( + parameter TAG_WIDTH = 16, + + // Response buffer + parameter OUT_BUF = 0 + ) ( input wire clk, input wire reset, @@ -59,7 +62,7 @@ module VX_local_mem import VX_gpu_pkg::*; #( localparam REQ_DATAW = 1 + BANK_ADDR_WIDTH + WORD_SIZE + WORD_WIDTH + TAG_WIDTH; localparam RSP_DATAW = WORD_WIDTH + TAG_WIDTH; - `STATIC_ASSERT(ADDR_WIDTH == (BANK_ADDR_WIDTH + `CLOG2(NUM_BANKS)), ("invalid parameter")) + `STATIC_ASSERT(ADDR_WIDTH == (BANK_ADDR_WIDTH + `CLOG2(NUM_BANKS)), ("invalid parameter")) // bank selection @@ -70,7 +73,7 @@ module VX_local_mem import VX_gpu_pkg::*; #( end end else begin assign req_bank_idx = 0; - end + end // bank addressing @@ -83,18 +86,18 @@ module VX_local_mem import VX_gpu_pkg::*; #( // bank requests dispatch wire [NUM_BANKS-1:0] per_bank_req_valid; - wire [NUM_BANKS-1:0] per_bank_req_rw; + wire [NUM_BANKS-1:0] per_bank_req_rw; wire [NUM_BANKS-1:0][BANK_ADDR_WIDTH-1:0] per_bank_req_addr; wire [NUM_BANKS-1:0][WORD_SIZE-1:0] per_bank_req_byteen; wire [NUM_BANKS-1:0][WORD_WIDTH-1:0] per_bank_req_data; wire [NUM_BANKS-1:0][TAG_WIDTH-1:0] per_bank_req_tag; wire [NUM_BANKS-1:0][REQ_SEL_WIDTH-1:0] per_bank_req_idx; wire [NUM_BANKS-1:0] per_bank_req_ready; - + wire [NUM_BANKS-1:0][REQ_DATAW-1:0] per_bank_req_data_all; wire [NUM_REQS-1:0] req_valid_in; - wire [NUM_REQS-1:0][REQ_DATAW-1:0] req_data_in; + wire [NUM_REQS-1:0][REQ_DATAW-1:0] req_data_in; wire [NUM_REQS-1:0] req_ready_in; `ifdef PERF_ENABLE @@ -104,13 +107,13 @@ module VX_local_mem import VX_gpu_pkg::*; #( for (genvar i = 0; i < NUM_REQS; ++i) begin assign req_valid_in[i] = mem_bus_if[i].req_valid; assign req_data_in[i] = { - mem_bus_if[i].req_data.rw, + mem_bus_if[i].req_data.rw, req_bank_addr[i], mem_bus_if[i].req_data.byteen, mem_bus_if[i].req_data.data, mem_bus_if[i].req_data.tag}; assign mem_bus_if[i].req_ready = req_ready_in[i]; - end + end VX_stream_xbar #( .NUM_INPUTS (NUM_REQS), @@ -138,10 +141,10 @@ module VX_local_mem import VX_gpu_pkg::*; #( for (genvar i = 0; i < NUM_BANKS; ++i) begin assign { - per_bank_req_rw[i], + per_bank_req_rw[i], per_bank_req_addr[i], - per_bank_req_byteen[i], - per_bank_req_data[i], + per_bank_req_byteen[i], + per_bank_req_data[i], per_bank_req_tag[i]} = per_bank_req_data_all[i]; end @@ -149,13 +152,13 @@ module VX_local_mem import VX_gpu_pkg::*; #( wire [NUM_BANKS-1:0] per_bank_rsp_valid; wire [NUM_BANKS-1:0][WORD_WIDTH-1:0] per_bank_rsp_data; - wire [NUM_BANKS-1:0][REQ_SEL_WIDTH-1:0] per_bank_rsp_idx; - wire [NUM_BANKS-1:0][TAG_WIDTH-1:0] per_bank_rsp_tag; + wire [NUM_BANKS-1:0][REQ_SEL_WIDTH-1:0] per_bank_rsp_idx; + wire [NUM_BANKS-1:0][TAG_WIDTH-1:0] per_bank_rsp_tag; wire [NUM_BANKS-1:0] per_bank_rsp_ready; `RESET_RELAY (bank_reset, reset); - for (genvar i = 0; i < NUM_BANKS; ++i) begin + for (genvar i = 0; i < NUM_BANKS; ++i) begin VX_sp_ram #( .DATAW (WORD_WIDTH), .SIZE (WORDS_PER_BANK), @@ -165,7 +168,7 @@ module VX_local_mem import VX_gpu_pkg::*; #( .read (1'b1), .write (per_bank_req_valid[i] && per_bank_req_ready[i] && per_bank_req_rw[i]), .wren (per_bank_req_byteen[i]), - .addr (per_bank_req_addr[i]), + .addr (per_bank_req_addr[i]), .wdata (per_bank_req_data[i]), .rdata (per_bank_rsp_data[i]) ); @@ -193,7 +196,7 @@ module VX_local_mem import VX_gpu_pkg::*; #( // bank responses gather wire [NUM_BANKS-1:0][RSP_DATAW-1:0] per_bank_rsp_data_all; - + for (genvar i = 0; i < NUM_BANKS; ++i) begin assign per_bank_rsp_data_all[i] = {per_bank_rsp_data[i], per_bank_rsp_tag[i]}; end @@ -206,7 +209,7 @@ module VX_local_mem import VX_gpu_pkg::*; #( .NUM_INPUTS (NUM_BANKS), .NUM_OUTPUTS (NUM_REQS), .DATAW (RSP_DATAW), - .OUT_BUF (2) + .OUT_BUF (OUT_BUF) ) rsp_xbar ( .clk (clk), .reset (reset), @@ -302,38 +305,38 @@ module VX_local_mem import VX_gpu_pkg::*; #( assign per_bank_rsp_uuid[i] = 0; end end - + for (genvar i = 0; i < NUM_REQS; ++i) begin always @(posedge clk) begin if (mem_bus_if[i].req_valid && mem_bus_if[i].req_ready) begin if (mem_bus_if[i].req_data.rw) begin - `TRACE(1, ("%d: %s wr-req: req_idx=%0d, addr=0x%0h, tag=0x%0h, byteen=%b, data=0x%0h (#%0d)\n", + `TRACE(1, ("%d: %s wr-req: req_idx=%0d, addr=0x%0h, tag=0x%0h, byteen=%b, data=0x%0h (#%0d)\n", $time, INSTANCE_ID, i, mem_bus_if[i].req_data.addr, mem_bus_if[i].req_data.tag, mem_bus_if[i].req_data.byteen, mem_bus_if[i].req_data.data, req_uuid[i])); end else begin - `TRACE(1, ("%d: %s rd-req: req_idx=%0d, addr=0x%0h, tag=0x%0h (#%0d)\n", + `TRACE(1, ("%d: %s rd-req: req_idx=%0d, addr=0x%0h, tag=0x%0h (#%0d)\n", $time, INSTANCE_ID, i, mem_bus_if[i].req_data.addr, mem_bus_if[i].req_data.tag, req_uuid[i])); end end if (mem_bus_if[i].rsp_valid && mem_bus_if[i].rsp_ready) begin - `TRACE(1, ("%d: %s rd-rsp: req_idx=%0d, tag=0x%0h, data=0x%0h (#%0d)\n", + `TRACE(1, ("%d: %s rd-rsp: req_idx=%0d, tag=0x%0h, data=0x%0h (#%0d)\n", $time, INSTANCE_ID, i, mem_bus_if[i].rsp_data.tag, mem_bus_if[i].rsp_data.data[i], rsp_uuid[i])); end end end - + for (genvar i = 0; i < NUM_BANKS; ++i) begin always @(posedge clk) begin if (per_bank_req_valid[i] && per_bank_req_ready[i]) begin if (per_bank_req_rw[i]) begin - `TRACE(2, ("%d: %s-bank%0d wr-req: addr=0x%0h, tag=0x%0h, byteen=%b, data=0x%0h (#%0d)\n", + `TRACE(2, ("%d: %s-bank%0d wr-req: addr=0x%0h, tag=0x%0h, byteen=%b, data=0x%0h (#%0d)\n", $time, INSTANCE_ID, i, per_bank_req_addr[i], per_bank_req_tag[i], per_bank_req_byteen[i], per_bank_req_data[i], per_bank_req_uuid[i])); end else begin - `TRACE(2, ("%d: %s-bank%0d rd-req: addr=0x%0h, tag=0x%0h (#%0d)\n", + `TRACE(2, ("%d: %s-bank%0d rd-req: addr=0x%0h, tag=0x%0h (#%0d)\n", $time, INSTANCE_ID, i, per_bank_req_addr[i], per_bank_req_tag[i], per_bank_req_uuid[i])); end end if (per_bank_rsp_valid[i] && per_bank_rsp_ready[i]) begin - `TRACE(2, ("%d: %s-bank%0d rd-rsp: tag=0x%0h, data=0x%0h (#%0d)\n", + `TRACE(2, ("%d: %s-bank%0d rd-rsp: tag=0x%0h, data=0x%0h (#%0d)\n", $time, INSTANCE_ID, i, per_bank_rsp_tag[i], per_bank_rsp_data[i], per_bank_rsp_uuid[i])); end end diff --git a/hw/rtl/mem/VX_mem_switch.sv b/hw/rtl/mem/VX_mem_switch.sv index 7ae91ca8e..fd26c2aa8 100644 --- a/hw/rtl/mem/VX_mem_switch.sv +++ b/hw/rtl/mem/VX_mem_switch.sv @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -17,20 +17,19 @@ module VX_mem_switch import VX_gpu_pkg::*; #( parameter NUM_REQS = 1, parameter DATA_SIZE = 1, parameter TAG_WIDTH = 1, - parameter MEM_ADDR_WIDTH = `MEM_ADDR_WIDTH, + parameter ADDR_WIDTH = 1, parameter REQ_OUT_BUF = 0, parameter RSP_OUT_BUF = 0, - parameter `STRING ARBITER = "R", + parameter `STRING ARBITER = "R", parameter LOG_NUM_REQS = `CLOG2(NUM_REQS) ) ( input wire clk, input wire reset, - + input wire [`UP(LOG_NUM_REQS)-1:0] bus_sel, VX_mem_bus_if.slave bus_in_if, VX_mem_bus_if.master bus_out_if [NUM_REQS] -); - localparam ADDR_WIDTH = (MEM_ADDR_WIDTH-`CLOG2(DATA_SIZE)); +); localparam DATA_WIDTH = (8 * DATA_SIZE); localparam REQ_DATAW = TAG_WIDTH + ADDR_WIDTH + `ADDR_TYPE_WIDTH + 1 + DATA_SIZE + DATA_WIDTH; localparam RSP_DATAW = TAG_WIDTH + DATA_WIDTH; @@ -40,7 +39,7 @@ module VX_mem_switch import VX_gpu_pkg::*; #( wire [NUM_REQS-1:0] req_valid_out; wire [NUM_REQS-1:0][REQ_DATAW-1:0] req_data_out; wire [NUM_REQS-1:0] req_ready_out; - + VX_stream_switch #( .NUM_OUTPUTS (NUM_REQS), .DATAW (REQ_DATAW), @@ -49,7 +48,7 @@ module VX_mem_switch import VX_gpu_pkg::*; #( .clk (clk), .reset (reset), .sel_in (bus_sel), - .valid_in (bus_in_if.req_valid), + .valid_in (bus_in_if.req_valid), .data_in (bus_in_if.req_data), .ready_in (bus_in_if.req_ready), .valid_out (req_valid_out), @@ -68,7 +67,7 @@ module VX_mem_switch import VX_gpu_pkg::*; #( wire [NUM_REQS-1:0] rsp_valid_in; wire [NUM_REQS-1:0][RSP_DATAW-1:0] rsp_data_in; wire [NUM_REQS-1:0] rsp_ready_in; - + for (genvar i = 0; i < NUM_REQS; ++i) begin assign rsp_valid_in[i] = bus_out_if[i].rsp_valid; assign rsp_data_in[i] = bus_out_if[i].rsp_data; @@ -77,15 +76,15 @@ module VX_mem_switch import VX_gpu_pkg::*; #( VX_stream_arb #( .NUM_INPUTS (NUM_REQS), - .DATAW (RSP_DATAW), + .DATAW (RSP_DATAW), .ARBITER (ARBITER), .OUT_BUF (RSP_OUT_BUF) ) rsp_arb ( .clk (clk), .reset (reset), - .valid_in (rsp_valid_in), - .data_in (rsp_data_in), - .ready_in (rsp_ready_in), + .valid_in (rsp_valid_in), + .data_in (rsp_data_in), + .ready_in (rsp_ready_in), .valid_out (bus_in_if.rsp_valid), .data_out (bus_in_if.rsp_data), .ready_out (bus_in_if.rsp_ready), diff --git a/hw/syn/altera/opae/Makefile b/hw/syn/altera/opae/Makefile index 4a54b0cdf..235c79c8d 100644 --- a/hw/syn/altera/opae/Makefile +++ b/hw/syn/altera/opae/Makefile @@ -12,7 +12,6 @@ SRC_DIR := $(VORTEX_HOME)/hw/syn/altera/opae RTL_DIR := $(VORTEX_HOME)/hw/rtl DPI_DIR := $(VORTEX_HOME)/hw/dpi AFU_DIR := $(RTL_DIR)/afu/opae -THIRD_PARTY_DIR := $(VORTEX_HOME)/third_party SCRIPT_DIR := $(VORTEX_HOME)/hw/scripts IP_CACHE_DIR := $(ROOT_DIR)/hw/syn/altera/ip_cache/$(DEVICE_FAMILY) @@ -76,19 +75,19 @@ endif # Debugigng ifdef DEBUG - ifeq ($(TARGET), fpga) - CFLAGS += -DNDEBUG -DSCOPE $(DBG_SCOPE_FLAGS) - SCOPE_JSON += $(BUILD_DIR)/scope.json + ifneq ($(TARGET), fpga) + CFLAGS += -DNDEBUG else CFLAGS += $(DBG_TRACE_FLAGS) endif -else +else CFLAGS += -DNDEBUG endif # Enable scope analyzer ifdef SCOPE - CFLAGS += -DSCOPE + CFLAGS += -DSCOPE $(DBG_SCOPE_FLAGS) + SCOPE_JSON += $(BUILD_DIR)/scope.json endif # Enable perf counters @@ -128,7 +127,7 @@ ifeq ($(TARGET), asesim) afu_sim_setup -s $(BUILD_DIR)/setup.cfg $(BUILD_DIR)/synth else afu_synth_setup -s $(BUILD_DIR)/setup.cfg $(BUILD_DIR)/synth -endif +endif build: ip-gen setup $(SCOPE_JSON) ifeq ($(TARGET), asesim) @@ -145,5 +144,5 @@ scope-json: $(BUILD_DIR)/scope.json $(BUILD_DIR)/scope.json: $(BUILD_DIR)/vortex.xml $(SCRIPT_DIR)/scope.py $(BUILD_DIR)/vortex.xml -o $(BUILD_DIR)/scope.json -clean: +clean: rm -rf vortex_afu.h $(BUILD_DIR) diff --git a/hw/syn/altera/opae/run_ase.sh b/hw/syn/altera/opae/run_ase.sh index 16c92f459..04fd27540 100755 --- a/hw/syn/altera/opae/run_ase.sh +++ b/hw/syn/altera/opae/run_ase.sh @@ -1,12 +1,12 @@ #!/bin/bash # Copyright © 2019-2023 -# +# # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 -# +# # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,19 +20,19 @@ BUILD_DIR=$(realpath $1) PROGRAM=$(basename "$2") PROGRAM_DIR=`dirname $2` -POCL_RT_PATH=$TOOLDIR/pocl/runtime +POCL_PATH=$TOOLDIR/pocl VORTEX_RT_PATH=$SCRIPT_DIR/../../../../runtime # Export ASE_WORKDIR variable export ASE_WORKDIR=$BUILD_DIR/synth/work # cleanup incomplete runs -rm -f $ASE_WORKDIR/.app_lock.pid +rm -f $ASE_WORKDIR/.app_lock.pid rm -f $ASE_WORKDIR/.ase_ready.pid rm -f $BUILD_DIR/synth/nohup.out # Start Simulator in background (capture processs group pid) -pushd $BUILD_DIR/synth +pushd $BUILD_DIR/synth echo " [DBG] starting ASE simnulator (stdout saved to '$BUILD_DIR/synth/nohup.out')" setsid make sim &> /dev/null & SIM_PID=$! @@ -49,7 +49,7 @@ done pushd $PROGRAM_DIR shift 2 echo " [DBG] running ./$PROGRAM $*" -ASE_LOG=0 LD_LIBRARY_PATH=$POCL_RT_PATH/lib:$VORTEX_RT_PATH/opae:$LD_LIBRARY_PATH ./$PROGRAM $* +ASE_LOG=0 LD_LIBRARY_PATH=$POCL_PATH/lib:$VORTEX_RT_PATH/opae:$LD_LIBRARY_PATH ./$PROGRAM $* popd # stop the simulator (kill process group) diff --git a/hw/syn/altera/quartus/Makefile b/hw/syn/altera/quartus/Makefile index d79109a90..d0a2999bd 100644 --- a/hw/syn/altera/quartus/Makefile +++ b/hw/syn/altera/quartus/Makefile @@ -9,7 +9,7 @@ SCRIPT_DIR := $(VORTEX_HOME)/hw/scripts IP_CACHE_DIR := $(ROOT_DIR)/hw/syn/altera/ip_cache/$(DEVICE_FAMILY) -.PHONY: dogfood unittest pipeline lmem cache fpu core vortex top test +.PHONY: dogfood unittest pipeline lmem cache fpu core issue vortex top test ip-gen: $(IP_CACHE_DIR)/ip_gen.log $(IP_CACHE_DIR)/ip_gen.log: @@ -50,6 +50,11 @@ core: cp core/Makefile core/$(BUILD_DIR) $(MAKE) -C core/$(BUILD_DIR) clean && $(MAKE) -C core/$(BUILD_DIR) > core/$(BUILD_DIR)/build.log 2>&1 & +issue: + mkdir -p issue/$(BUILD_DIR) + cp issue/Makefile issue/$(BUILD_DIR) + $(MAKE) -C issue/$(BUILD_DIR) clean && $(MAKE) -C issue/$(BUILD_DIR) > issue/$(BUILD_DIR)/build.log 2>&1 & + vortex: ip-gen mkdir -p vortex/$(BUILD_DIR) cp vortex/Makefile vortex/$(BUILD_DIR) diff --git a/hw/syn/altera/quartus/common.mk b/hw/syn/altera/quartus/common.mk index 16105b7e2..3890dcfe8 100644 --- a/hw/syn/altera/quartus/common.mk +++ b/hw/syn/altera/quartus/common.mk @@ -5,7 +5,6 @@ SRC_DIR := $(VORTEX_HOME)/hw/syn/altera/quartus RTL_DIR := $(VORTEX_HOME)/hw/rtl AFU_DIR := $(RTL_DIR)/afu/opae -THIRD_PARTY_DIR := $(VORTEX_HOME)/third_party SCRIPT_DIR := $(VORTEX_HOME)/hw/scripts IP_CACHE_DIR := $(ROOT_DIR)/hw/syn/altera/ip_cache/$(DEVICE_FAMILY) @@ -81,7 +80,7 @@ smart.log: $(PROJECT_FILES) # Project initialization $(PROJECT_FILES): gen-sources quartus_sh -t $(SRC_DIR)/project.tcl -project $(PROJECT) -family $(FAMILY) -device $(DEVICE) -top $(TOP_LEVEL_ENTITY) -src "$(SRC_FILE)" -sdc $(SRC_DIR)/project.sdc -inc "src" - + syn.chg: $(STAMP) syn.chg @@ -99,6 +98,6 @@ pow.chg: program: $(PROJECT).sof quartus_pgm --no_banner --mode=jtag -o "$(PROJECT).sof" - + clean: rm -rf src bin *.rpt *.chg *.qsf *.qpf *.qws *.log *.htm *.eqn *.pin *.sof *.pof qdb incremental_db tmp-clearbox diff --git a/hw/syn/altera/quartus/issue/Makefile b/hw/syn/altera/quartus/issue/Makefile new file mode 100644 index 000000000..c1804a398 --- /dev/null +++ b/hw/syn/altera/quartus/issue/Makefile @@ -0,0 +1,14 @@ +PROJECT = VX_issue_top +TOP_LEVEL_ENTITY = $(PROJECT) +SRC_FILE = $(PROJECT).sv + +include ../../common.mk + +#CONFIGS += -DNUM_WARPS=32 +#CONFIGS += -DNUM_THREADS=32 + +FPU_INCLUDE = -I$(RTL_DIR)/fpu +ifneq (,$(findstring FPU_FPNEW,$(CONFIGS))) + FPU_INCLUDE += -J$(THIRD_PARTY_DIR)/fpnew/src/common_cells/include -J$(THIRD_PARTY_DIR)/fpnew/src/common_cells/src -J$(THIRD_PARTY_DIR)/fpnew/src/fpu_div_sqrt_mvp/hdl -J$(THIRD_PARTY_DIR)/fpnew/src +endif +RTL_INCLUDE = -I$(RTL_DIR) -I$(RTL_DIR)/libs -I$(RTL_DIR)/interfaces -I$(RTL_DIR)/core -I$(RTL_DIR)/mem $(FPU_INCLUDE) -I$(IP_CACHE_DIR) $(FPU_INCLUDE) \ No newline at end of file diff --git a/hw/syn/altera/quartus/project.sdc b/hw/syn/altera/quartus/project.sdc index 6ea508531..f6373a643 100644 --- a/hw/syn/altera/quartus/project.sdc +++ b/hw/syn/altera/quartus/project.sdc @@ -1 +1 @@ -create_clock -name {clk} -period "200 MHz" -waveform { 0.000 1.0 } [get_ports {clk}] \ No newline at end of file +create_clock -name {clk} -period "220 MHz" -waveform { 0.000 1.0 } [get_ports {clk}] \ No newline at end of file diff --git a/hw/syn/altera/quartus/top/Makefile b/hw/syn/altera/quartus/top/Makefile index a47389d70..341690206 100644 --- a/hw/syn/altera/quartus/top/Makefile +++ b/hw/syn/altera/quartus/top/Makefile @@ -4,7 +4,21 @@ SRC_FILE = $(PROJECT).sv include ../../common.mk +# AFU parameters CONFIGS += -DNOPAE +CONFIGS += -DPLATFORM_PROVIDES_LOCAL_MEMORY +ifeq (,$(findstring PLATFORM_PARAM_LOCAL_MEMORY_BANKS,$(CONFIGS))) + CONFIGS += -DPLATFORM_PARAM_LOCAL_MEMORY_BANKS=2 +endif +ifeq (,$(findstring PLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH,$(CONFIGS))) + CONFIGS += -DPLATFORM_PARAM_LOCAL_MEMORY_ADDR_WIDTH=26 +endif +ifeq (,$(findstring PLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH,$(CONFIGS))) + CONFIGS += -DPLATFORM_PARAM_LOCAL_MEMORY_DATA_WIDTH=512 +endif +ifeq (,$(findstring PLATFORM_PARAM_LOCAL_MEMORY_BURST_CNT_WIDTH,$(CONFIGS))) + CONFIGS += -DPLATFORM_PARAM_LOCAL_MEMORY_BURST_CNT_WIDTH=4 +endif #CONFIGS += -DNUM_CORES=2 #CONFIGS += -DNUM_WARPS=32 diff --git a/hw/syn/xilinx/README b/hw/syn/xilinx/README index f436cf869..b2218e65e 100644 --- a/hw/syn/xilinx/README +++ b/hw/syn/xilinx/README @@ -38,14 +38,10 @@ make chipscope TARGET=hw PLATFORM=xilinx_u50_gen3x16_xdma_5_202210_1 vitis_analyzer build_xilinx_u50_gen3x16_xdma_5_202210_1_hw_4c/bin/vortex_afu.xclbin.link_summary # running test -TARGET=hw PLATFORM=xilinx_u50_gen3x16_xdma_5_202210_1 ./ci/blackbox.sh --driver=xrt --app=demo -TARGET=hw_emu PLATFORM=xilinx_u50_gen3x16_xdma_5_202210_1 ./ci/blackbox.sh --driver=xrt --app=demo -TARGET=hw PLATFORM=xilinx_vck5000_gen3x16_xdma_1_202120_1 ./ci/blackbox.sh --driver=xrt --app=demo -TARGET=hw_emu PLATFORM=xilinx_vck5000_gen3x16_xdma_1_202120_1 ./ci/blackbox.sh --driver=xrt --app=demo -FPGA_BIN_DIR= TARGET=hw_emu PLATFORM=xilinx_u50_gen3x16_xdma_5_202210_1 ./ci/blackbox.sh --driver=xrt --app=demo -FPGA_BIN_DIR= TARGET=hw PLATFORM=xilinx_u50_gen3x16_xdma_5_202210_1 ./ci/blackbox.sh --driver=xrt --app=demo -FPGA_BIN_DIR= TARGET=hw_emu PLATFORM=xilinx_u280_gen3x16_xdma_1_202211_1 ./ci/blackbox.sh --driver=xrt --app=demo -FPGA_BIN_DIR= XRT_DEVICE_INDEX=1 TARGET=hw PLATFORM=xilinx_u280_gen3x16_xdma_1_202211_1 ./ci/blackbox.sh --driver=xrt --app=demo +FPGA_BIN_DIR= TARGET=hw_emu ./ci/blackbox.sh --driver=xrt --app=demo +FPGA_BIN_DIR= TARGET=hw ./ci/blackbox.sh --driver=xrt --app=demo +FPGA_BIN_DIR= TARGET=hw_emu ./ci/blackbox.sh --driver=xrt --app=demo +FPGA_BIN_DIR= XRT_DEVICE_INDEX=1 TARGET=hw ./ci/blackbox.sh --driver=xrt --app=demo # build report logs /bin/vortex_afu.xclbin.info diff --git a/hw/syn/xilinx/test/Makefile b/hw/syn/xilinx/test/Makefile index b2d49c161..e15789516 100644 --- a/hw/syn/xilinx/test/Makefile +++ b/hw/syn/xilinx/test/Makefile @@ -8,7 +8,6 @@ SRC_DIR := $(VORTEX_HOME)/hw/syn/xilinx/test RTL_DIR := $(VORTEX_HOME)/hw/rtl DPI_DIR := $(VORTEX_HOME)/hw/dpi AFU_DIR := $(RTL_DIR)/afu/opae -THIRD_PARTY_DIR := $(VORTEX_HOME)/third_party SCRIPT_DIR := $(VORTEX_HOME)/hw/scripts # include paths diff --git a/hw/syn/xilinx/xrt/Makefile b/hw/syn/xilinx/xrt/Makefile index b5f00f1cc..f8f0f5cb0 100644 --- a/hw/syn/xilinx/xrt/Makefile +++ b/hw/syn/xilinx/xrt/Makefile @@ -24,7 +24,6 @@ SRC_DIR := $(VORTEX_HOME)/hw/syn/xilinx/xrt RTL_DIR := $(VORTEX_HOME)/hw/rtl DPI_DIR := $(VORTEX_HOME)/hw/dpi AFU_DIR := $(RTL_DIR)/afu/xrt -THIRD_PARTY_DIR := $(VORTEX_HOME)/third_party SCRIPT_DIR := $(VORTEX_HOME)/hw/scripts VIVADO := $(XILINX_VIVADO)/bin/vivado @@ -34,7 +33,7 @@ CP = cp -rf RMDIR = rm -rf ECHO = @echo -NCPUS := $(shell grep -c ^processor /proc/cpuinfo) +NCPUS := $(shell lscpu | grep "^Core(s) per socket:" | awk '{print $$4}') JOBS ?= $(shell echo $$(( $(NCPUS) > $(MAX_JOBS) ? $(MAX_JOBS) : $(NCPUS) ))) PLATFORM_TO_XSA = $(strip $(patsubst %.xpfm, % , $(shell basename $(PLATFORM)))) @@ -115,11 +114,8 @@ endif # Debugigng ifdef DEBUG VPP_FLAGS += -g --debug.protocol all - ifeq ($(TARGET), hw) - CFLAGS += -DNDEBUG -DSCOPE $(DBG_SCOPE_FLAGS) - SCOPE_JSON += $(BUILD_DIR)/scope.json - #CFLAGS += -DNDEBUG -DCHIPSCOPE $(DBG_SCOPE_FLAGS) - #VPP_FLAGS += --debug.chipscope vortex_afu_1 + ifneq ($(TARGET), hw) + CFLAGS += -DNDEBUG else VPP_FLAGS += --vivado.prop fileset.sim_1.xsim.elaborate.debug_level=all CFLAGS += $(DBG_TRACE_FLAGS) @@ -129,6 +125,12 @@ else CFLAGS += -DNDEBUG endif +# Enable scope analyzer +ifdef SCOPE + CFLAGS += -DSCOPE $(DBG_SCOPE_FLAGS) + SCOPE_JSON += $(BUILD_DIR)/scope.json +endif + # compilation flags CFLAGS += -DSYNTHESIS -DVIVADO CFLAGS += -DXLEN_$(XLEN) diff --git a/hw/syn/yosys/Makefile b/hw/syn/yosys/Makefile index 2b89d2421..a0c4fdcc9 100644 --- a/hw/syn/yosys/Makefile +++ b/hw/syn/yosys/Makefile @@ -9,7 +9,6 @@ NUM_CORES ?= 1 SCRIPT_DIR := $(VORTEX_HOME)/hw/scripts RTL_DIR := $(VORTEX_HOME)/hw/rtl -THIRD_PARTY_DIR := $(VORTEX_HOME)/third_party CP = cp -rf RMDIR = rm -rf @@ -52,15 +51,15 @@ RTL_INCLUDE += $(FPU_INCLUDE) # Debugigng ifdef DEBUG - CFLAGS += -DNDEBUG -DSCOPE $(DBG_SCOPE_FLAGS) - SCOPE_JSON += $(BUILD_DIR)/scope.json -else + CFLAGS += $(DBG_TRACE_FLAGS) +else CFLAGS += -DNDEBUG endif # Enable scope analyzer ifdef SCOPE - CFLAGS += -DSCOPE + CFLAGS += -DSCOPE $(DBG_SCOPE_FLAGS) + SCOPE_JSON += $(BUILD_DIR)/scope.json endif # Enable perf counters @@ -90,5 +89,8 @@ build: $(BUILD_DIR)/project.v elaborate: $(BUILD_DIR)/project.v cd $(BUILD_DIR); $(SRC_DIR)/synth.sh -t$(TOP_LEVEL_ENTITY) -sproject.v -P="elaborate" +synthesis: $(BUILD_DIR)/project.v + cd $(BUILD_DIR); $(SRC_DIR)/synth.sh -t$(TOP_LEVEL_ENTITY) -sproject.v -P="synthesis" + clean: $(RMDIR) $(BUILD_DIR) diff --git a/hw/syn/yosys/synth.sh b/hw/syn/yosys/synth.sh index 79f68aafc..79708b189 100755 --- a/hw/syn/yosys/synth.sh +++ b/hw/syn/yosys/synth.sh @@ -1,12 +1,12 @@ #!/bin/bash # Copyright © 2019-2023 -# +# # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 -# +# # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -87,18 +87,18 @@ while getopts "s:t:I:D:P:Wh" arg; do W) # allow warnings no_warnings=0 ;; - h | *) + h | *) usage exit 0 ;; esac done -{ +{ # read design sources - for dir in "${dir_list[@]}" + for dir in "${dir_list[@]}" do - for file in $(find $dir -maxdepth 1 -name '*.v' -o -name '*.sv' -type f) + for file in $(find $dir -maxdepth 1 -name '*.v' -o -name '*.sv' -type f) do echo "read_verilog -defer -nolatches $macro_args $inc_args -sv $file" done @@ -111,11 +111,16 @@ done if echo "$process" | grep -q "elaborate"; then echo "hierarchy -top $top_level" fi - + + # synthesize design + if echo "$process" | grep -q "synthesis"; then + echo "synth -top $top_level" + fi + # convert to netlist if echo "$process" | grep -q "netlist"; then echo "proc; opt" - fi + fi # convert to gate logic if echo "$process" | grep -q "techmap"; then @@ -126,8 +131,11 @@ done if echo "$process" | grep -q "verilog"; then echo "write_verilog synth.v" fi + + # Generate a summary report + echo "stat" } > synth.ys -yosys -l yosys.log synth.ys +yosys -l yosys.log -s synth.ys checkErrors yosys.log diff --git a/hw/unittest/Makefile b/hw/unittest/Makefile index 5a8ac941e..5722ec9bc 100644 --- a/hw/unittest/Makefile +++ b/hw/unittest/Makefile @@ -4,6 +4,7 @@ all: $(MAKE) -C mem_streamer $(MAKE) -C cache_top $(MAKE) -C core_top + $(MAKE) -C issue_top run: $(MAKE) -C cache run @@ -11,10 +12,12 @@ run: $(MAKE) -C mem_streamer run $(MAKE) -C cache_top run $(MAKE) -C core_top run + $(MAKE) -C issue_top run clean: $(MAKE) -C cache clean $(MAKE) -C generic_queue clean $(MAKE) -C mem_streamer clean $(MAKE) -C cache_top clean - $(MAKE) -C core_top clean \ No newline at end of file + $(MAKE) -C core_top clean + $(MAKE) -C issue_top clean \ No newline at end of file diff --git a/hw/unittest/cache/cachesim.cpp b/hw/unittest/cache/cachesim.cpp index 2c35f5e05..acd68419b 100644 --- a/hw/unittest/cache/cachesim.cpp +++ b/hw/unittest/cache/cachesim.cpp @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -31,12 +31,12 @@ static bool trace_enabled = false; static uint64_t trace_start_time = TRACE_START_TIME; static uint64_t trace_stop_time = TRACE_STOP_TIME; -double sc_time_stamp() { +double sc_time_stamp() { return timestamp; } bool sim_trace_enabled() { - if (timestamp >= trace_start_time + if (timestamp >= trace_start_time && timestamp < trace_stop_time) return true; return trace_enabled; @@ -47,26 +47,27 @@ void sim_trace_enable(bool enable) { } CacheSim::CacheSim() { - // force random values for uninitialized signals + // force random values for uninitialized signals Verilated::randReset(2); - ram_ = nullptr; + // create RTL module instance cache_ = new VVX_cache_top(); - mem_rsp_active_ = false; - snp_req_active_ = false; - #ifdef VCD_OUTPUT Verilated::traceEverOn(true); - trace_ = new VerilatedVcdC; - cache_->trace(trace_, 99); - trace_->open("trace.vcd"); + tfp_ = new VerilatedVcdC; + cache_->trace(tfp_, 99); + tfp_->open("trace.vcd"); #endif + + ram_ = nullptr; + mem_rsp_active_ = false; + snp_req_active_ = false; } CacheSim::~CacheSim() { #ifdef VCD_OUTPUT - trace_->close(); + tfp_->close(); #endif delete cache_; //need to delete the req and rsp vectors @@ -89,7 +90,7 @@ void CacheSim::reset() { mem_rsp_vec_.clear(); //clear req and rsp vecs - + } void CacheSim::step() { @@ -111,43 +112,43 @@ void CacheSim::step() { void CacheSim::eval() { cache_->eval(); #ifdef VCD_OUTPUT - trace_->dump(timestamp); + tfp_->dump(timestamp); #endif ++timestamp; } void CacheSim::run(){ //#ifndef NDEBUG - + //#endif this->step(); - int valid = 300; - int stalls = 20 + 10; - + int valid = 300; + int stalls = 20 + 10; + while (valid > -1) { this->step(); - display_miss(); + display_miss(); if(cache_->core_rsp_valid){ get_core_rsp(); } - + if(!cache_->core_req_valid && !cache_->core_rsp_valid){ - valid--; - + valid--; + } - stalls--; + stalls--; if (stalls == 20){ - //stall_mem(); - //send_snoop_req(); - stalls--; + //stall_mem(); + //send_snoop_req(); + stalls--; } } } void CacheSim::clear_req(){ - cache_->core_req_valid = 0; + cache_->core_req_valid = 0; } void CacheSim::send_req(core_req_t *req){ @@ -157,11 +158,11 @@ void CacheSim::send_req(core_req_t *req){ } bool CacheSim::get_core_req_ready(){ - return cache_->core_req_ready; + return cache_->core_req_ready; } bool CacheSim::get_core_rsp_ready(){ - return cache_->core_rsp_ready; + return cache_->core_rsp_ready; } void CacheSim::eval_reqs(){ @@ -170,7 +171,7 @@ void CacheSim::eval_reqs(){ core_req_t *req = core_req_vec_.front(); cache_->core_req_valid = req->valid; - cache_->core_req_rw = req->rw; + cache_->core_req_rw = req->rw; cache_->core_req_byteen = req->byteen; cache_->core_req_addr[0] = req->addr[0]; @@ -183,10 +184,10 @@ void CacheSim::eval_reqs(){ cache_->core_req_data[2] = req->data[2]; cache_->core_req_data[3] = req->data[3]; - cache_->core_req_tag = req->tag; + cache_->core_req_tag = req->tag; core_req_vec_.pop(); - + } else { clear_req(); } @@ -209,7 +210,7 @@ void CacheSim::stall_mem(){ void CacheSim::send_snoop_req(){ /*cache_->snp_req_valid = 1; cache_->snp_req_addr = 0x12222222; - cache_->snp_req_invalidate = 1; + cache_->snp_req_invalidate = 1; cache_->snp_req_tag = 0xff; */ } @@ -225,15 +226,15 @@ void CacheSim::eval_mem_bus() { if (mem_rsp_vec_[i].cycles_left > 0) { mem_rsp_vec_[i].cycles_left -= 1; } - if ((dequeue_index == -1) + if ((dequeue_index == -1) && (mem_rsp_vec_[i].cycles_left == 0)) { dequeue_index = i; } } - // send memory response + // send memory response if (mem_rsp_active_ - && cache_->mem_rsp_valid + && cache_->mem_rsp_valid && cache_->mem_rsp_ready) { mem_rsp_active_ = false; } @@ -244,7 +245,7 @@ void CacheSim::eval_mem_bus() { //copy data from the rsp queue to the cache module memcpy(cache_->mem_rsp_data.data(), mem_rsp_vec_[dequeue_index].data, MEM_BLOCK_SIZE); - cache_->mem_rsp_tag = mem_rsp_vec_[dequeue_index].tag; + cache_->mem_rsp_tag = mem_rsp_vec_[dequeue_index].tag; free(mem_rsp_vec_[dequeue_index].data); //take data out of the queue mem_rsp_vec_.erase(mem_rsp_vec_.begin() + dequeue_index); mem_rsp_active_ = true; @@ -256,7 +257,7 @@ void CacheSim::eval_mem_bus() { // handle memory stalls bool mem_stalled = false; #ifdef ENABLE_MEM_STALLS - if (0 == ((timestamp/2) % MEM_STALLS_MODULO)) { + if (0 == ((timestamp/2) % MEM_STALLS_MODULO)) { mem_stalled = true; } else if (mem_rsp_vec_.size() >= MEM_RQ_SIZE) { @@ -272,19 +273,19 @@ void CacheSim::eval_mem_bus() { uint64_t base_addr = (cache_->mem_req_addr * MEM_BLOCK_SIZE); uint8_t* data = reinterpret_cast(cache_->mem_req_data.data()); for (int i = 0; i < MEM_BLOCK_SIZE; i++) { - if ((byteen >> i) & 0x1) { + if ((byteen >> i) & 0x1) { (*ram_)[base_addr + i] = data[i]; } } } else { mem_req_t mem_req; - mem_req.cycles_left = MEM_LATENCY; + mem_req.cycles_left = MEM_LATENCY; mem_req.data = (uint8_t*)malloc(MEM_BLOCK_SIZE); mem_req.tag = cache_->mem_req_tag; ram_->read(cache_->mem_req_addr * MEM_BLOCK_SIZE, MEM_BLOCK_SIZE, mem_req.data); mem_rsp_vec_.push_back(mem_req); - } - } + } + } } cache_->mem_req_ready = ~mem_stalled; @@ -301,15 +302,15 @@ bool CacheSim::assert_equal(unsigned int* data, unsigned int tag){ } } - return check; + return check; } //DEBUG void CacheSim::display_miss(){ - //int i = (unsigned int)cache_->miss_vec; - //std::bitset<8> x(i); + //int i = (unsigned int)cache_->miss_vec; + //std::bitset<8> x(i); //if (i) std::cout << "Miss Vec " << x << std::endl; //std::cout << "Miss Vec 0" << cache_->miss_vec[0] << std::endl; } @@ -322,18 +323,18 @@ void CacheSim::get_core_req(unsigned int (&rsp)[4]){ //std::cout << std::hex << "core_rsp_valid: " << cache_->core_rsp_valid << std::endl; //std::cout << std::hex << "core_rsp_data: " << cache_->core_rsp_data << std::endl; - //std::cout << std::hex << "core_rsp_tag: " << cache_->core_rsp_tag << std::endl; + //std::cout << std::hex << "core_rsp_tag: " << cache_->core_rsp_tag << std::endl; } void CacheSim::get_core_rsp(){ - //std::cout << cache_->genblk5_BRA_0_KET_->bank->is_fill_in_pipe<< std::endl; + //std::cout << cache_->genblk5_BRA_0_KET_->bank->is_fill_in_pipe<< std::endl; char check = cache_->core_rsp_valid; std::cout << std::hex << "core_rsp_valid: " << (unsigned int) check << std::endl; std::cout << std::hex << "core_rsp_data[0]: " << cache_->core_rsp_data[0] << std::endl; std::cout << std::hex << "core_rsp_data[1]: " << cache_->core_rsp_data[1] << std::endl; std::cout << std::hex << "core_rsp_data[2]: " << cache_->core_rsp_data[2] << std::endl; std::cout << std::hex << "core_rsp_data[3]: " << cache_->core_rsp_data[3] << std::endl; - std::cout << std::hex << "core_rsp_tag: " << cache_->core_rsp_tag << std::endl; + std::cout << std::hex << "core_rsp_tag: " << cache_->core_rsp_tag << std::endl; } void CacheSim::get_mem_req(){ @@ -341,13 +342,13 @@ void CacheSim::get_mem_req(){ std::cout << std::hex << "mem_req_rw: " << cache_->mem_req_rw << std::endl; std::cout << std::hex << "mem_req_byteen: " << cache_->mem_req_byteen << std::endl; std::cout << std::hex << "mem_req_addr: " << cache_->mem_req_addr << std::endl; - std::cout << std::hex << "mem_req_data: " << cache_->mem_req_data << std::endl; + std::cout << std::hex << "mem_req_data: " << cache_->mem_req_data << std::endl; std::cout << std::hex << "mem_req_tag: " << cache_->mem_req_tag << std::endl; } void CacheSim::get_mem_rsp(){ std::cout << std::hex << "mem_rsp_valid: " << cache_->mem_rsp_valid << std::endl; - std::cout << std::hex << "mem_rsp_data: " << cache_->mem_rsp_data << std::endl; + std::cout << std::hex << "mem_rsp_data: " << cache_->mem_rsp_data << std::endl; std::cout << std::hex << "mem_rsp_tag: " << cache_->mem_rsp_tag << std::endl; std::cout << std::hex << "mem_rsp_ready: " << cache_->mem_rsp_ready << std::endl; } diff --git a/hw/unittest/cache/cachesim.h b/hw/unittest/cache/cachesim.h index a38ed774b..5235735d6 100644 --- a/hw/unittest/cache/cachesim.h +++ b/hw/unittest/cache/cachesim.h @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -31,7 +31,6 @@ #define MEM_LATENCY 100 #define MEM_RQ_SIZE 16 #define MEM_STALLS_MODULO 16 -#define MEM_BLOCK_SIZE 16 typedef struct { int cycles_left; @@ -41,7 +40,7 @@ typedef struct { typedef struct { char valid; - char rw; + char rw; unsigned byteen; unsigned *addr; unsigned *data; @@ -50,24 +49,24 @@ typedef struct { class CacheSim { public: - + CacheSim(); virtual ~CacheSim(); - - bool busy(); + + bool busy(); void reset(); void step(); - void wait(uint32_t cycles); + void wait(uint32_t cycles); void attach_ram(RAM* ram); void run(); //run until all reqs are empty - + //req/rsp void send_req(core_req_t *req); - void clear_req(); + void clear_req(); void stall_mem(); void send_snoop_req(); - void send_snp_fwd_in(); + void send_snp_fwd_in(); //assert funcs bool assert_equal(unsigned int* data, unsigned int tag); @@ -81,14 +80,14 @@ public: void get_mem_rsp(); void display_miss(); -private: +private: - void eval(); - void eval_reqs(); + void eval(); + void eval_reqs(); void eval_rsps(); void eval_mem_bus(); - - std::queue core_req_vec_; + + std::queue core_req_vec_; std::vector mem_rsp_vec_; std::map core_rsp_vec_; int mem_rsp_active_; @@ -97,9 +96,9 @@ private: uint32_t snp_req_size_; uint32_t pending_snp_reqs_; - VVX_cache_top *cache_; - RAM *ram_; + VVX_cache_top* cache_; + RAM* ram_; #ifdef VCD_OUTPUT - VerilatedVcdC *trace_; + VerilatedVcdC* tfp_; #endif }; diff --git a/hw/unittest/common.mk b/hw/unittest/common.mk index a9ca50660..ac3e6b4ff 100644 --- a/hw/unittest/common.mk +++ b/hw/unittest/common.mk @@ -3,19 +3,19 @@ DESTDIR ?= . CONFIGS += PARAMS += -CXXFLAGS += -std=c++11 -Wall -Wextra -Wfatal-errors -Wno-array-bounds +CXXFLAGS += -std=c++17 -Wall -Wextra -Wfatal-errors -Wno-array-bounds CXXFLAGS += -fPIC -Wno-maybe-uninitialized CXXFLAGS += $(CONFIGS) LDFLAGS += RTL_PKGS += -RTL_INCLUDE += +RTL_INCLUDE += DBG_FLAGS += -DDEBUG_LEVEL=$(DEBUG) -DVCD_OUTPUT $(DBG_TRACE_FLAGS) VL_FLAGS = --exe VL_FLAGS += --language 1800-2009 --assert -Wall -Wpedantic -VL_FLAGS += -Wno-DECLFILENAME -Wno-REDEFMACRO +VL_FLAGS += -Wno-DECLFILENAME -Wno-REDEFMACRO -Wno-GENUNNAMED VL_FLAGS += --x-initial unique --x-assign unique VL_FLAGS += -DSIMULATION -DSV_DPI VL_FLAGS += $(CONFIGS) @@ -33,7 +33,7 @@ VL_FLAGS += -j $(THREADS) ifdef DEBUG VL_FLAGS += --trace --trace-structs $(DBG_FLAGS) CXXFLAGS += -g -O0 $(DBG_FLAGS) -else +else VL_FLAGS += -DNDEBUG CXXFLAGS += -O2 -DNDEBUG endif @@ -45,7 +45,7 @@ ifdef PERF endif all: $(DESTDIR)/$(PROJECT) - + $(DESTDIR)/$(PROJECT): $(SRCS) verilator --build $(VL_FLAGS) $^ -CFLAGS '$(CXXFLAGS)' -o ../$@ diff --git a/hw/unittest/core_top/Makefile b/hw/unittest/core_top/Makefile index b2a0cce13..d9fbf40f6 100644 --- a/hw/unittest/core_top/Makefile +++ b/hw/unittest/core_top/Makefile @@ -16,7 +16,7 @@ SRCS += $(SRC_DIR)/main.cpp DBG_TRACE_FLAGS := -DDBG_TRACE_CACHE -RTL_PKGS := $(RTL_DIR)/VX_gpu_pkg.sv $(RTL_DIR)/fpu/VX_fpu_pkg.sv +RTL_PKGS := $(RTL_DIR)/VX_gpu_pkg.sv $(RTL_DIR)/fpu/VX_fpu_pkg.sv $(RTL_DIR)/core/VX_trace_pkg.sv RTL_INCLUDE := -I$(RTL_DIR) -I$(DPI_DIR) -I$(RTL_DIR)/libs RTL_INCLUDE += -I$(RTL_DIR)/interfaces -I$(RTL_DIR)/mem -I$(RTL_DIR)/fpu -I$(RTL_DIR)/core diff --git a/hw/unittest/issue_top/Makefile b/hw/unittest/issue_top/Makefile new file mode 100644 index 000000000..7e298849c --- /dev/null +++ b/hw/unittest/issue_top/Makefile @@ -0,0 +1,26 @@ +ROOT_DIR := $(realpath ../../..) +include $(ROOT_DIR)/config.mk + +PROJECT := issue_top + +RTL_DIR := $(VORTEX_HOME)/hw/rtl +DPI_DIR := $(VORTEX_HOME)/hw/dpi + +SRC_DIR := $(VORTEX_HOME)/hw/unittest/$(PROJECT) + +CXXFLAGS := -I$(SRC_DIR) -I$(VORTEX_HOME)/hw/unittest/common -I$(VORTEX_HOME)/sim/common +CXXFLAGS += -I$(ROOT_DIR)/hw + +SRCS := $(DPI_DIR)/util_dpi.cpp +SRCS += $(SRC_DIR)/main.cpp + +DBG_TRACE_FLAGS := -DDBG_TRACE_CACHE + +RTL_PKGS := $(RTL_DIR)/VX_gpu_pkg.sv $(RTL_DIR)/core/VX_trace_pkg.sv + +RTL_INCLUDE := -I$(RTL_DIR) -I$(DPI_DIR) -I$(RTL_DIR)/libs +RTL_INCLUDE += -I$(RTL_DIR)/interfaces -I$(RTL_DIR)/mem -I$(RTL_DIR)/core + +TOP := VX_issue_top + +include ../common.mk \ No newline at end of file diff --git a/hw/unittest/issue_top/main.cpp b/hw/unittest/issue_top/main.cpp new file mode 100644 index 000000000..5191b4433 --- /dev/null +++ b/hw/unittest/issue_top/main.cpp @@ -0,0 +1,49 @@ +// Copyright © 2019-2023 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "vl_simulator.h" + +#ifndef TRACE_START_TIME +#define TRACE_START_TIME 0ull +#endif + +#ifndef TRACE_STOP_TIME +#define TRACE_STOP_TIME -1ull +#endif + +static uint64_t timestamp = 0; +static bool trace_enabled = false; +static uint64_t trace_start_time = TRACE_START_TIME; +static uint64_t trace_stop_time = TRACE_STOP_TIME; + +double sc_time_stamp() { + return timestamp; +} + +bool sim_trace_enabled() { + if (timestamp >= trace_start_time + && timestamp < trace_stop_time) + return true; + return trace_enabled; +} + +void sim_trace_enable(bool enable) { + trace_enabled = enable; +} + +int main(int argc, char **argv) { + // Initialize Verilators variables + Verilated::commandArgs(argc, argv); + + return 0; +} \ No newline at end of file diff --git a/hw/unittest/mem_streamer/memsim.cpp b/hw/unittest/mem_streamer/memsim.cpp index a54a512d3..329c01708 100644 --- a/hw/unittest/mem_streamer/memsim.cpp +++ b/hw/unittest/mem_streamer/memsim.cpp @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -28,12 +28,12 @@ static uint64_t trace_start_time = 0; static uint64_t trace_stop_time = -1ull; static uint64_t timestamp = 0; -double sc_time_stamp() { +double sc_time_stamp() { return timestamp; } bool sim_trace_enabled() { - if (timestamp >= trace_start_time + if (timestamp >= trace_start_time && timestamp < trace_stop_time) return true; return trace_enabled; @@ -61,22 +61,23 @@ int generate_rand_mask (int mask) { } MemSim::MemSim() { - msu_ = new VVX_mem_scheduler(); + // force random values for uninitialized signals + Verilated::randReset(2); - // Enable tracing - Verilated::traceEverOn(true); + // create RTL module instance + msu_ = new VVX_mem_scheduler(); #ifdef VCD_OUTPUT Verilated::traceEverOn(true); - trace_ = new VerilatedVcdC; - cache_->trace(trace_, 99); + tfp_ = new VerilatedVcdC; + cache_->trace(tfp_, 99); race_->open("trace.vcd"); #endif } MemSim::~MemSim() { #ifdef VCD_OUTPUT - trace_->close(); + tfp_->close(); #endif delete msu_; } @@ -84,7 +85,7 @@ MemSim::~MemSim() { void MemSim::eval() { msu_->eval(); #ifdef VCD_OUTPUT - trace_->dump(timestamp++); + tfp_->dump(timestamp++); #endif } @@ -158,7 +159,7 @@ int main (int argc, char** argv, char** env) { Verilated::commandArgs(argc, argv); MemSim memsim; - RAM ram; + RAM ram; memsim.run(&ram); diff --git a/hw/unittest/mem_streamer/memsim.h b/hw/unittest/mem_streamer/memsim.h index 482572bb2..5c08c97b7 100644 --- a/hw/unittest/mem_streamer/memsim.h +++ b/hw/unittest/mem_streamer/memsim.h @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,10 +16,8 @@ #include #include #include -#include #include #include "VVX_mem_scheduler.h" -#include "VVX_mem_scheduler__Syms.h" #include "ram.h" #define SIM_TIME 5000 @@ -37,7 +35,7 @@ public: private: VVX_mem_scheduler *msu_; #ifdef VCD_OUTPUT - VerilatedVcdC *trace_; + VerilatedVcdC* tfp_; #endif void eval(); diff --git a/kernel/Makefile b/kernel/Makefile index 201ebc200..16d279fa0 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -32,6 +32,10 @@ CFLAGS += -O3 -mcmodel=medany -fno-exceptions -fdata-sections -ffunction-section CFLAGS += -I$(INC_DIR) -I$(ROOT_DIR)/hw CFLAGS += -DXLEN_$(XLEN) +ifeq ($(VM_ENABLE), 1) +CFLAGS += -DVM_ENABLE +endif + PROJECT := libvortex SRCS = $(SRC_DIR)/vx_start.S $(SRC_DIR)/vx_syscalls.c $(SRC_DIR)/vx_print.S $(SRC_DIR)/tinyprintf.c $(SRC_DIR)/vx_print.c $(SRC_DIR)/vx_spawn.c $(SRC_DIR)/vx_serial.S $(SRC_DIR)/vx_perf.c diff --git a/miscs/docker/Dockerfile.ubuntu b/miscs/docker/Dockerfile.ubuntu index 1e8485e75..c3e72a0f4 100644 --- a/miscs/docker/Dockerfile.ubuntu +++ b/miscs/docker/Dockerfile.ubuntu @@ -17,13 +17,12 @@ FROM ubuntu:20.04 # Set non-interactive installation to avoid user input during build ARG DEBIAN_FRONTEND=noninteractive -# Update and install basic and necessary dependencies +# Update and install necessary dependencies RUN apt-get update && apt-get install -y \ + software-properties-common \ build-essential \ - binutils \ python \ python3 \ - uuid-dev \ git \ wget \ curl \ @@ -39,9 +38,11 @@ RUN git clone --depth=1 --recursive https://github.com/vortexgpgpu/vortex.git /v # Set the initial working directory WORKDIR /vortex +# install system dependencies +RUN ./ci/system_updates.sh + # Configure the build folder -RUN mkdir build && cd build && \ - ../configure --tooldir=$HOME/tools +RUN mkdir build && cd build && ../configure # Install prebuilt toolchain RUN cd build && ./ci/toolchain_install.sh --all diff --git a/runtime/Makefile b/runtime/Makefile index e5f8af74c..aecac00e1 100644 --- a/runtime/Makefile +++ b/runtime/Makefile @@ -3,6 +3,8 @@ include $(ROOT_DIR)/config.mk all: stub rtlsim simx opae xrt +vm: stub simx + stub: $(MAKE) -C stub diff --git a/runtime/include/vortex.h b/runtime/include/vortex.h index 6f57c7de8..957e5d62a 100644 --- a/runtime/include/vortex.h +++ b/runtime/include/vortex.h @@ -36,23 +36,27 @@ typedef void* vx_buffer_h; #define VX_CAPS_ISA_FLAGS 0x7 // device isa flags -#define VX_ISA_STD_A (1ull << 0) -#define VX_ISA_STD_C (1ull << 2) -#define VX_ISA_STD_D (1ull << 3) -#define VX_ISA_STD_E (1ull << 4) -#define VX_ISA_STD_F (1ull << 5) -#define VX_ISA_STD_H (1ull << 7) -#define VX_ISA_STD_I (1ull << 8) -#define VX_ISA_STD_N (1ull << 13) -#define VX_ISA_STD_Q (1ull << 16) -#define VX_ISA_STD_S (1ull << 18) -#define VX_ISA_STD_U (1ull << 20) -#define VX_ISA_ARCH(flags) (1 << (((flags >> 30) & 0x3) + 4)) -#define VX_ISA_EXT_ICACHE (1ull << 32) -#define VX_ISA_EXT_DCACHE (1ull << 33) -#define VX_ISA_EXT_L2CACHE (1ull << 34) -#define VX_ISA_EXT_L3CACHE (1ull << 35) -#define VX_ISA_EXT_LMEM (1ull << 36) +#define VX_ISA_STD_A (1ull << ISA_STD_A) +#define VX_ISA_STD_C (1ull << ISA_STD_C) +#define VX_ISA_STD_D (1ull << ISA_STD_D) +#define VX_ISA_STD_E (1ull << ISA_STD_E) +#define VX_ISA_STD_F (1ull << ISA_STD_F) +#define VX_ISA_STD_H (1ull << ISA_STD_H) +#define VX_ISA_STD_I (1ull << ISA_STD_I) +#define VX_ISA_STD_N (1ull << ISA_STD_N) +#define VX_ISA_STD_Q (1ull << ISA_STD_Q) +#define VX_ISA_STD_S (1ull << ISA_STD_S) +#define VX_ISA_STD_U (1ull << ISA_STD_U) +#define VX_ISA_ARCH(flags) (1ull << (((flags >> 30) & 0x3) + 4)) +#define VX_ISA_EXT_ICACHE (1ull << (32+ISA_EXT_ICACHE)) +#define VX_ISA_EXT_DCACHE (1ull << (32+ISA_EXT_DCACHE)) +#define VX_ISA_EXT_L2CACHE (1ull << (32+ISA_EXT_L2CACHE)) +#define VX_ISA_EXT_L3CACHE (1ull << (32+ISA_EXT_L3CACHE)) +#define VX_ISA_EXT_LMEM (1ull << (32+ISA_EXT_LMEM)) +#define VX_ISA_EXT_ZICOND (1ull << (32+ISA_EXT_ZICOND)) +#define VX_ISA_EXT_TEX (1ull << (32+ISA_EXT_TEX)) +#define VX_ISA_EXT_RASTER (1ull << (32+ISA_EXT_RASTER)) +#define VX_ISA_EXT_OM (1ull << (32+ISA_EXT_OM)) // ready wait timeout #define VX_MAX_TIMEOUT (24*60*60*1000) // 24 Hr diff --git a/runtime/opae/Makefile b/runtime/opae/Makefile index 4eb410406..3954d3f19 100644 --- a/runtime/opae/Makefile +++ b/runtime/opae/Makefile @@ -25,15 +25,9 @@ SRCS = $(SRC_DIR)/vortex.cpp $(SRC_DIR)/driver.cpp # set up target types ifeq ($(TARGET), opaesim) OPAESIM = $(DESTDIR)/libopae-c-sim.so - CXXFLAGS += -DOPAESIM -I$(SIM_DIR)/opaesim - LDFLAGS += -L$(DESTDIR) -lopae-c-sim + CXXFLAGS += -I$(SIM_DIR)/opaesim else CXXFLAGS += -I$(SYN_DIR) - ifeq ($(TARGET), asesim) - CXXFLAGS += -DASESIM - else - CXXFLAGS += -DFPGA - endif endif # Debugigng diff --git a/runtime/opae/driver.cpp b/runtime/opae/driver.cpp index a01f1e5e8..5048cf754 100644 --- a/runtime/opae/driver.cpp +++ b/runtime/opae/driver.cpp @@ -22,13 +22,7 @@ #include #include -#ifdef OPAESIM -#define DEFAULT_OPAE_DRV_PATHS "libopae-c-sim.so" -#elif ASESIM -#define DEFAULT_OPAE_DRV_PATHS "libopae-c-ase.so" -#else #define DEFAULT_OPAE_DRV_PATHS "libopae-c.so" -#endif #define SET_API(func) \ opae_drv_funcs->func = (pfn_##func)dlsym(dl_handle, #func); \ @@ -64,7 +58,7 @@ int drv_init(opae_drv_api_t* opae_drv_funcs) { if (dl_handle) break; } - + if (dl_handle == nullptr) { printf("dlopen failed: %s\n", dlerror()); return -1; diff --git a/runtime/opae/driver.h b/runtime/opae/driver.h index d2a933d75..0d1d4daa7 100644 --- a/runtime/opae/driver.h +++ b/runtime/opae/driver.h @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -13,12 +13,7 @@ #pragma once -#ifndef OPAESIM -#include -#include -#else #include -#endif typedef fpga_result (*pfn_fpgaGetProperties)(fpga_token token, fpga_properties *prop); typedef fpga_result (*pfn_fpgaPropertiesSetObjectType)(fpga_properties prop, fpga_objtype objtype); @@ -38,7 +33,7 @@ typedef fpga_result (*pfn_fpgaReadMMIO64)(fpga_handle handle, uint32_t mmio_num, typedef const char *(*pfn_fpgaErrStr)(fpga_result e); struct opae_drv_api_t { - pfn_fpgaGetProperties fpgaGetProperties; + pfn_fpgaGetProperties fpgaGetProperties; pfn_fpgaPropertiesSetObjectType fpgaPropertiesSetObjectType; pfn_fpgaPropertiesSetGUID fpgaPropertiesSetGUID; pfn_fpgaDestroyProperties fpgaDestroyProperties; @@ -46,14 +41,14 @@ struct opae_drv_api_t { pfn_fpgaDestroyToken fpgaDestroyToken; pfn_fpgaPropertiesGetLocalMemorySize fpgaPropertiesGetLocalMemorySize; - pfn_fpgaOpen fpgaOpen; - pfn_fpgaClose fpgaClose; - pfn_fpgaPrepareBuffer fpgaPrepareBuffer; - pfn_fpgaReleaseBuffer fpgaReleaseBuffer; + pfn_fpgaOpen fpgaOpen; + pfn_fpgaClose fpgaClose; + pfn_fpgaPrepareBuffer fpgaPrepareBuffer; + pfn_fpgaReleaseBuffer fpgaReleaseBuffer; pfn_fpgaGetIOAddress fpgaGetIOAddress; pfn_fpgaWriteMMIO64 fpgaWriteMMIO64; - pfn_fpgaReadMMIO64 fpgaReadMMIO64; - pfn_fpgaErrStr fpgaErrStr; + pfn_fpgaReadMMIO64 fpgaReadMMIO64; + pfn_fpgaErrStr fpgaErrStr; }; int drv_init(opae_drv_api_t* opae_drv_funcs); diff --git a/runtime/opae/vortex.cpp b/runtime/opae/vortex.cpp index 0237ecd30..390d5acc4 100755 --- a/runtime/opae/vortex.cpp +++ b/runtime/opae/vortex.cpp @@ -12,9 +12,11 @@ // limitations under the License. #include -#include #include "driver.h" + +#include + #ifdef SCOPE #include "scope.h" #endif diff --git a/runtime/rtlsim/vortex.cpp b/runtime/rtlsim/vortex.cpp index a920cbeca..c75a6c12f 100644 --- a/runtime/rtlsim/vortex.cpp +++ b/runtime/rtlsim/vortex.cpp @@ -119,6 +119,10 @@ public: if (dev_addr + asize > GLOBAL_MEM_SIZE) return -1; + if (flags | VX_MEM_WRITE) { + flags |= VX_MEM_READ; // ensure caches can handle fill requests + } + ram_.set_acl(dev_addr, size, flags); return 0; diff --git a/runtime/simx/Makefile b/runtime/simx/Makefile index 7c73ca66d..7615f72b2 100644 --- a/runtime/simx/Makefile +++ b/runtime/simx/Makefile @@ -10,6 +10,10 @@ CXXFLAGS += -I$(INC_DIR) -I../common -I$(ROOT_DIR)/hw -I$(SIM_DIR)/simx -I$(COMM CXXFLAGS += $(CONFIGS) CXXFLAGS += -DXLEN_$(XLEN) +ifeq ($(VM_ENABLE), 1) +CXXFLAGS += -DVM_ENABLE +endif + LDFLAGS += -shared -pthread LDFLAGS += -L$(DESTDIR) -lsimx diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index f9143cf0f..e5ec36b60 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -120,7 +120,7 @@ public: uint64_t map_p2v(uint64_t ppn, uint32_t flags) { DBGPRINT(" [RT:MAP_P2V] ppn: %lx\n", ppn); - if (addr_mapping.contains(ppn)) return addr_mapping[ppn]; + if (addr_mapping.find(ppn) != addr_mapping.end()) return addr_mapping[ppn]; // If ppn to vpn mapping doesnt exist, create mapping DBGPRINT(" [RT:MAP_P2V] Not found. Allocate new page table or update a PTE.\n"); diff --git a/runtime/stub/utils.cpp b/runtime/stub/utils.cpp index 26b119608..eea7691f5 100644 --- a/runtime/stub/utils.cpp +++ b/runtime/stub/utils.cpp @@ -182,12 +182,12 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { uint64_t sched_stalls = 0; uint64_t ibuffer_stalls = 0; uint64_t scrb_stalls = 0; + uint64_t opds_stalls = 0; uint64_t scrb_alu = 0; uint64_t scrb_fpu = 0; uint64_t scrb_lsu = 0; - uint64_t scrb_sfu = 0; - uint64_t scrb_wctl = 0; uint64_t scrb_csrs = 0; + uint64_t scrb_wctl = 0; uint64_t ifetches = 0; uint64_t loads = 0; uint64_t stores = 0; @@ -268,7 +268,7 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { } sched_stalls += sched_stalls_per_core; } - // ibuffer_stalls + // ibuffer stalls { uint64_t ibuffer_stalls_per_core; CHECK_ERR(vx_mpm_query(hdevice, VX_CSR_MPM_IBUF_ST, core_id, &ibuffer_stalls_per_core), { @@ -280,7 +280,7 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { } ibuffer_stalls += ibuffer_stalls_per_core; } - // issue_stalls + // scoreboard stalls { uint64_t scrb_stalls_per_core; CHECK_ERR(vx_mpm_query(hdevice, VX_CSR_MPM_SCRB_ST, core_id, &scrb_stalls_per_core), { @@ -298,49 +298,46 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { CHECK_ERR(vx_mpm_query(hdevice, VX_CSR_MPM_SCRB_LSU, core_id, &scrb_lsu_per_core), { return err; }); - uint64_t scrb_sfu_per_core; - CHECK_ERR(vx_mpm_query(hdevice, VX_CSR_MPM_SCRB_SFU, core_id, &scrb_sfu_per_core), { - return err; - }); - scrb_alu += scrb_alu_per_core; - scrb_fpu += scrb_fpu_per_core; - scrb_lsu += scrb_lsu_per_core; - scrb_sfu += scrb_sfu_per_core; - if (num_cores > 1) { - uint64_t scrb_total = scrb_alu_per_core + scrb_fpu_per_core + scrb_lsu_per_core + scrb_sfu_per_core; - fprintf(stream, "PERF: core%d: issue stalls=%ld (alu=%d%%, fpu=%d%%, lsu=%d%%, sfu=%d%%)\n", core_id, scrb_stalls_per_core, - calcAvgPercent(scrb_alu_per_core, scrb_total), - calcAvgPercent(scrb_fpu_per_core, scrb_total), - calcAvgPercent(scrb_lsu_per_core, scrb_total), - calcAvgPercent(scrb_sfu_per_core, scrb_total)); - } - scrb_stalls += scrb_stalls_per_core; - } - // sfu_stalls - { - uint64_t scrb_sfu_per_core; - CHECK_ERR(vx_mpm_query(hdevice, VX_CSR_MPM_SCRB_SFU, core_id, &scrb_sfu_per_core), { + uint64_t scrb_csrs_per_core; + CHECK_ERR(vx_mpm_query(hdevice, VX_CSR_MPM_SCRB_CSRS, core_id, &scrb_csrs_per_core), { return err; }); uint64_t scrb_wctl_per_core; CHECK_ERR(vx_mpm_query(hdevice, VX_CSR_MPM_SCRB_WCTL, core_id, &scrb_wctl_per_core), { return err; }); - uint64_t scrb_csrs_per_core; - CHECK_ERR(vx_mpm_query(hdevice, VX_CSR_MPM_SCRB_CSRS, core_id, &scrb_csrs_per_core), { + scrb_alu += scrb_alu_per_core; + scrb_fpu += scrb_fpu_per_core; + scrb_lsu += scrb_lsu_per_core; + scrb_csrs += scrb_csrs_per_core; + scrb_wctl += scrb_wctl_per_core; + if (num_cores > 1) { + uint64_t scrb_total = scrb_alu_per_core + scrb_fpu_per_core + scrb_lsu_per_core + scrb_csrs_per_core + scrb_wctl_per_core; + int scrb_percent_per_core = calcAvgPercent(scrb_stalls_per_core, cycles_per_core); + fprintf(stream, "PERF: core%d: scoreboard stalls=%ld (%d%%) (alu=%d%%, fpu=%d%%, lsu=%d%%, scrs=%d%%, wctl=%d%%)\n" + , core_id + , scrb_stalls_per_core + , scrb_percent_per_core + , calcAvgPercent(scrb_alu_per_core, scrb_total) + , calcAvgPercent(scrb_fpu_per_core, scrb_total) + , calcAvgPercent(scrb_lsu_per_core, scrb_total) + , calcAvgPercent(scrb_csrs_per_core, scrb_total) + , calcAvgPercent(scrb_wctl_per_core, scrb_total) + ); + } + scrb_stalls += scrb_stalls_per_core; + } + // operands stalls + { + uint64_t opds_stalls_per_core; + CHECK_ERR(vx_mpm_query(hdevice, VX_CSR_MPM_OPDS_ST, core_id, &opds_stalls_per_core), { return err; }); if (num_cores > 1) { - uint64_t sfu_total = scrb_wctl_per_core + scrb_csrs_per_core; - fprintf(stream, "PERF: core%d: sfu stalls=%ld (scrs=%d%%, wctl=%d%%)\n" - , core_id - , scrb_sfu_per_core - , calcAvgPercent(scrb_csrs_per_core, sfu_total) - , calcAvgPercent(scrb_wctl_per_core, sfu_total) - ); + int opds_percent_per_core = calcAvgPercent(opds_stalls_per_core, cycles_per_core); + fprintf(stream, "PERF: core%d: operands stalls=%ld (%d%%)\n", core_id, opds_stalls_per_core, opds_percent_per_core); } - scrb_wctl += scrb_wctl_per_core; - scrb_csrs += scrb_csrs_per_core; + opds_stalls += opds_stalls_per_core; } // PERF: memory // ifetches @@ -542,7 +539,7 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { break; } - float IPC = (float)(double(instrs_per_core) / double(cycles_per_core)); + float IPC = caclAverage(instrs_per_core, cycles_per_core); if (num_cores > 1) fprintf(stream, "PERF: core%d: instrs=%ld, cycles=%ld, IPC=%f\n", core_id, instrs_per_core, cycles_per_core, IPC); total_instrs += instrs_per_core; total_cycles += cycles_per_core; @@ -554,23 +551,24 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { int sched_idles_percent = calcAvgPercent(sched_idles, total_cycles); int sched_stalls_percent = calcAvgPercent(sched_stalls, total_cycles); int ibuffer_percent = calcAvgPercent(ibuffer_stalls, total_cycles); - int ifetch_avg_lat = (int)(double(ifetch_lat) / double(ifetches)); - int load_avg_lat = (int)(double(load_lat) / double(loads)); - uint64_t scrb_total = scrb_alu + scrb_fpu + scrb_lsu + scrb_sfu; - uint64_t sfu_total = scrb_wctl + scrb_csrs; + int scrb_percent = calcAvgPercent(scrb_stalls, total_cycles); + int opds_percent = calcAvgPercent(opds_stalls, total_cycles); + int ifetch_avg_lat = caclAverage(ifetch_lat, ifetches); + int load_avg_lat = caclAverage(load_lat, loads); + uint64_t scrb_total = scrb_alu + scrb_fpu + scrb_lsu + scrb_csrs + scrb_wctl; fprintf(stream, "PERF: scheduler idle=%ld (%d%%)\n", sched_idles, sched_idles_percent); fprintf(stream, "PERF: scheduler stalls=%ld (%d%%)\n", sched_stalls, sched_stalls_percent); fprintf(stream, "PERF: ibuffer stalls=%ld (%d%%)\n", ibuffer_stalls, ibuffer_percent); - fprintf(stream, "PERF: issue stalls=%ld (alu=%d%%, fpu=%d%%, lsu=%d%%, sfu=%d%%)\n", scrb_stalls, - calcAvgPercent(scrb_alu, scrb_total), - calcAvgPercent(scrb_fpu, scrb_total), - calcAvgPercent(scrb_lsu, scrb_total), - calcAvgPercent(scrb_sfu, scrb_total)); - fprintf(stream, "PERF: sfu stalls=%ld (scrs=%d%%, wctl=%d%%)\n" - , scrb_sfu - , calcAvgPercent(scrb_csrs, sfu_total) - , calcAvgPercent(scrb_wctl, sfu_total) + fprintf(stream, "PERF: scoreboard stalls=%ld (%d%%) (alu=%d%%, fpu=%d%%, lsu=%d%%, scrs=%d%%, wctl=%d%%)\n" + , scrb_stalls + , scrb_percent + , calcAvgPercent(scrb_alu, scrb_total) + , calcAvgPercent(scrb_fpu, scrb_total) + , calcAvgPercent(scrb_lsu, scrb_total) + , calcAvgPercent(scrb_csrs, scrb_total) + , calcAvgPercent(scrb_wctl, scrb_total) ); + fprintf(stream, "PERF: operands stalls=%ld (%d%%)\n", opds_stalls, opds_percent); fprintf(stream, "PERF: ifetches=%ld\n", ifetches); fprintf(stream, "PERF: loads=%ld\n", loads); fprintf(stream, "PERF: stores=%ld\n", stores); @@ -618,7 +616,7 @@ extern int vx_dump_perf(vx_device_h hdevice, FILE* stream) { break; } - float IPC = (float)(double(total_instrs) / double(max_cycles)); + float IPC = caclAverage(total_instrs, max_cycles); fprintf(stream, "PERF: instrs=%ld, cycles=%ld, IPC=%f\n", total_instrs, max_cycles, IPC); fflush(stream); diff --git a/runtime/stub/vortex.cpp b/runtime/stub/vortex.cpp index 2e9a85f89..70b95dcbc 100644 --- a/runtime/stub/vortex.cpp +++ b/runtime/stub/vortex.cpp @@ -162,5 +162,22 @@ extern int vx_dcr_write(vx_device_h hdevice, uint32_t addr, uint32_t value) { } extern int vx_mpm_query(vx_device_h hdevice, uint32_t addr, uint32_t core_id, uint64_t* value) { - return (g_callbacks.mpm_query)(hdevice, addr, core_id, value); + if (core_id == 0xffffffff) { + uint64_t num_cores; + CHECK_ERR((g_callbacks.dev_caps)(hdevice, VX_CAPS_NUM_CORES, &num_cores), { + return err; + }); + uint64_t sum_value = 0; + uint64_t cur_value; + for (uint32_t i = 0; i < num_cores; ++i) { + CHECK_ERR((g_callbacks.mpm_query)(hdevice, addr, i, &cur_value), { + return err; + }); + sum_value += cur_value; + } + *value = sum_value; + return 0; + } else { + return (g_callbacks.mpm_query)(hdevice, addr, core_id, value); + } } \ No newline at end of file diff --git a/runtime/xrt/vortex.cpp b/runtime/xrt/vortex.cpp index 29f4aeeea..408bf23ed 100644 --- a/runtime/xrt/vortex.cpp +++ b/runtime/xrt/vortex.cpp @@ -134,12 +134,14 @@ static void wait_for_enter(const std::string &msg) { class vx_device { public: vx_device() - : xrtDevice_(nullptr) - , xrtKernel_(nullptr) - , global_mem_(ALLOC_BASE_ADDR, + : global_mem_(ALLOC_BASE_ADDR, GLOBAL_MEM_SIZE - ALLOC_BASE_ADDR, RAM_PAGE_SIZE, CACHE_BLOCK_SIZE) + #ifndef CPP_API + , xrtDevice_(nullptr) + , xrtKernel_(nullptr) + #endif {} ~vx_device() { @@ -715,10 +717,10 @@ public: private: + MemoryAllocator global_mem_; xrt_device_t xrtDevice_; xrt_kernel_t xrtKernel_; platform_info_t platform_; - MemoryAllocator global_mem_; uint64_t dev_caps_; uint64_t isa_caps_; uint64_t global_mem_size_; diff --git a/sim/Makefile b/sim/Makefile index e16486e8f..4d5ea89c1 100644 --- a/sim/Makefile +++ b/sim/Makefile @@ -1,6 +1,9 @@ ROOT_DIR := $(realpath ..) include $(ROOT_DIR)/config.mk +simx: + $(MAKE) -C simx + all: $(MAKE) -C simx $(MAKE) -C rtlsim diff --git a/sim/common.mk b/sim/common.mk index 93c902a31..ab017effe 100644 --- a/sim/common.mk +++ b/sim/common.mk @@ -5,7 +5,4 @@ HW_DIR := $(VORTEX_HOME)/hw RTL_DIR := $(HW_DIR)/rtl DPI_DIR := $(HW_DIR)/dpi SCRIPT_DIR := $(HW_DIR)/scripts - -COMMON_DIR := $(VORTEX_HOME)/sim/common - -THIRD_PARTY_DIR := $(VORTEX_HOME)/third_party \ No newline at end of file +COMMON_DIR := $(VORTEX_HOME)/sim/common \ No newline at end of file diff --git a/sim/common/bitvector.h b/sim/common/bitvector.h new file mode 100644 index 000000000..9fcf22c62 --- /dev/null +++ b/sim/common/bitvector.h @@ -0,0 +1,314 @@ +// Copyright © 2019-2023 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +namespace vortex { + +template +class BitVector { +private: + static constexpr size_t BITS_PER_WORD = sizeof(T) * 8; + std::vector bits_; + size_t size_; + bool all_zero_; + + size_t wordIndex(size_t pos) const { + return pos / BITS_PER_WORD; + } + + T bitMask(size_t pos) const { + return T(1) << (pos % BITS_PER_WORD); + } + + void updateAllZero() { + all_zero_ = std::all_of(bits_.begin(), bits_.end(), [](T word) { return word == 0; }); + } + +public: + explicit BitVector(size_t size = 0) + : bits_((size + (BITS_PER_WORD - 1)) / BITS_PER_WORD) + , size_(size) + , all_zero_(true) + {} + + void set(size_t pos) { + if (pos >= size_) throw std::out_of_range("Index out of range"); + bits_[this->wordIndex(pos)] |= this->bitMask(pos); + all_zero_ = false; + } + + void set(size_t pos, bool value) { + if (value) { + this->set(pos); + } else { + this->reset(pos); + } + } + + void reset() { + std::fill(bits_.begin(), bits_.end(), 0); + all_zero_ = true; + } + + void reset(size_t pos) { + if (pos >= size_) throw std::out_of_range("Index out of range"); + bits_[this->wordIndex(pos)] &= ~this->bitMask(pos); + this->updateAllZero(); + } + + bool test(size_t pos) const { + if (pos >= size_) throw std::out_of_range("Index out of range"); + return bits_[this->wordIndex(pos)] & this->bitMask(pos); + } + + size_t size() const { + return size_; + } + + void resize(size_t new_size) { + size_ = new_size; + bits_.resize((new_size + (BITS_PER_WORD - 1)) / BITS_PER_WORD, 0); + this->updateAllZero(); + } + + bool operator==(const BitVector& other) const { + return (size_ == other.size_) && (bits_ == other.bits_); + } + + bool operator!=(const BitVector& other) const { + return !(*this == other); + } + + bool operator[](size_t pos) const { + return test(pos); + } + + BitVector& operator&=(const BitVector& other) { + if (size_ != other.size_) throw std::invalid_argument("Bit sizes must match"); + for (size_t i = 0; i < bits_.size(); ++i) { + bits_[i] &= other.bits_[i]; + } + this->updateAllZero(); + return *this; + } + + BitVector& operator|=(const BitVector& other) { + if (size_ != other.size_) throw std::invalid_argument("Bit sizes must match"); + for (size_t i = 0; i < bits_.size(); ++i) { + bits_[i] |= other.bits_[i]; + } + this->updateAllZero(); + return *this; + } + + BitVector& operator^=(const BitVector& other) { + if (size_ != other.size_) throw std::invalid_argument("Bit sizes must match"); + for (size_t i = 0; i < bits_.size(); ++i) { + bits_[i] ^= other.bits_[i]; + } + this->updateAllZero(); + return *this; + } + + BitVector operator~() const { + BitVector result(size_); + for (size_t i = 0; i < bits_.size(); ++i) { + result.bits_[i] = ~bits_[i]; + } + result.updateAllZero(); + return result; + } + + void flip() { + for (auto &word : bits_) { + word = ~word; + } + this->updateAllZero(); + } + + size_t count() const { + size_t count = 0; + for (const auto &word : bits_) { + count += std::bitset(word).count(); + } + return count; + } + + bool none() const { + return all_zero_; + } + + bool any() const { + return !all_zero_; + } + + bool all() const { + size_t full_bits = size_ / BITS_PER_WORD; + size_t remaining_bits = size_ % BITS_PER_WORD; + T full_mask = ~T(0); + for (size_t i = 0; i < full_bits; ++i) { + if (bits_[i] != full_mask) + return false; + } + if (remaining_bits > 0) { + T partial_mask = (T(1) << remaining_bits) - 1; + if ((bits_[full_bits] & partial_mask) != partial_mask) + return false; + } + return true; + } + + BitVector& operator<<=(size_t pos) { + if (pos >= size_) { + reset(); + return *this; + } + + size_t word_shift = pos / BITS_PER_WORD; + size_t bit_shift = pos % BITS_PER_WORD; + + if (word_shift > 0) { + for (size_t i = bits_.size() - 1; i >= word_shift; --i) { + bits_[i] = bits_[i - word_shift]; + } + std::fill(bits_.begin(), bits_.begin() + word_shift, 0); + } + + if (bit_shift > 0) { + for (size_t i = bits_.size() - 1; i > 0; --i) { + bits_[i] = (bits_[i] << bit_shift) | (bits_[i - 1] >> (BITS_PER_WORD - bit_shift)); + } + bits_[0] <<= bit_shift; + } + + this->updateAllZero(); + return *this; + } + + BitVector& operator>>=(size_t pos) { + if (pos >= size_) { + reset(); + return *this; + } + + size_t word_shift = pos / BITS_PER_WORD; + size_t bit_shift = pos % BITS_PER_WORD; + + if (word_shift > 0) { + for (size_t i = 0; i < bits_.size() - word_shift; ++i) { + bits_[i] = bits_[i + word_shift]; + } + std::fill(bits_.end() - word_shift, bits_.end(), 0); + } + + if (bit_shift > 0) { + for (size_t i = 0; i < bits_.size() - 1; ++i) { + bits_[i] = (bits_[i] >> bit_shift) | (bits_[i + 1] << (BITS_PER_WORD - bit_shift)); + } + bits_.back() >>= bit_shift; + } + + this->updateAllZero(); + return *this; + } + + std::string to_string() const { + std::string result; + for (size_t i = 0; i < size_; ++i) { + result.push_back(test(i) ? '1' : '0'); + } + return result; + } + + unsigned long to_ulong() const { + if (size_ > sizeof(unsigned long) * 8) { + throw std::overflow_error("BitVector size exceeds unsigned long capacity"); + } + + unsigned long result = 0; + for (size_t i = 0; i < size_; ++i) { + if (test(i)) { + result |= (1UL << i); + } + } + return result; + } + + unsigned long long to_ullong() const { + if (size_ > sizeof(unsigned long long) * 8) { + throw std::overflow_error("BitVector size exceeds unsigned long long capacity"); + } + + unsigned long long result = 0; + for (size_t i = 0; i < size_; ++i) { + if (test(i)) { + result |= (1ULL << i); + } + } + return result; + } + + friend std::ostream& operator<<(std::ostream& os, const BitVector& bv) { + for (size_t i = 0; i < bv.size_; ++i) { + os << bv.test(i); + } + return os; + } + + friend BitVector operator&(const BitVector& lhs, const BitVector& rhs) { + BitVector result(lhs); + result &= rhs; + return result; + } + + friend BitVector operator|(const BitVector& lhs, const BitVector& rhs) { + BitVector result(lhs); + result |= rhs; + return result; + } + + friend BitVector operator^(const BitVector& lhs, const BitVector& rhs) { + BitVector result(lhs); + result ^= rhs; + return result; + } + + friend BitVector operator<<(const BitVector& lhs, size_t pos) { + BitVector result(lhs); + result <<= pos; + return result; + } + + friend BitVector operator>>(const BitVector& lhs, size_t pos) { + BitVector result(lhs); + result >>= pos; + return result; + } +}; + +} + +// std::hash specialization for BitVector +namespace std { + +template +struct hash> { + size_t operator()(const vortex::BitVector& bv) const { + return hash()(bv.to_string()); + } +}; + +} \ No newline at end of file diff --git a/sim/common/dram_sim.cpp b/sim/common/dram_sim.cpp new file mode 100644 index 000000000..f7cfa8a32 --- /dev/null +++ b/sim/common/dram_sim.cpp @@ -0,0 +1,120 @@ +// Copyright © 2019-2023 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "dram_sim.h" +#include "util.h" +#include + +DISABLE_WARNING_PUSH +DISABLE_WARNING_UNUSED_PARAMETER +DISABLE_WARNING_MISSING_FIELD_INITIALIZERS +#include +#include +#include +#include +#include +DISABLE_WARNING_POP + +using namespace vortex; + +class DramSim::Impl { +private: + Ramulator::IFrontEnd* ramulator_frontend_; + Ramulator::IMemorySystem* ramulator_memorysystem_; + +public: + Impl(int clock_ratio) { + YAML::Node dram_config; + dram_config["Frontend"]["impl"] = "GEM5"; + dram_config["MemorySystem"]["impl"] = "GenericDRAM"; + dram_config["MemorySystem"]["clock_ratio"] = clock_ratio; + dram_config["MemorySystem"]["DRAM"]["impl"] = "HBM2"; + dram_config["MemorySystem"]["DRAM"]["org"]["preset"] = "HBM2_8Gb"; + dram_config["MemorySystem"]["DRAM"]["org"]["density"] = 8192; + dram_config["MemorySystem"]["DRAM"]["timing"]["preset"] = "HBM2_2Gbps"; + dram_config["MemorySystem"]["Controller"]["impl"] = "Generic"; + dram_config["MemorySystem"]["Controller"]["Scheduler"]["impl"] = "FRFCFS"; + dram_config["MemorySystem"]["Controller"]["RefreshManager"]["impl"] = "AllBank"; + dram_config["MemorySystem"]["Controller"]["RefreshManager"]["impl"] = "AllBank"; + dram_config["MemorySystem"]["Controller"]["RowPolicy"]["impl"] = "OpenRowPolicy"; + { + YAML::Node draw_plugin; + draw_plugin["ControllerPlugin"]["impl"] = "TraceRecorder"; + draw_plugin["ControllerPlugin"]["path"] = "./trace/ramulator.log"; + dram_config["MemorySystem"]["Controller"]["plugins"].push_back(draw_plugin); + } + dram_config["MemorySystem"]["AddrMapper"]["impl"] = "RoBaRaCoCh"; + + ramulator_frontend_ = Ramulator::Factory::create_frontend(dram_config); + ramulator_memorysystem_ = Ramulator::Factory::create_memory_system(dram_config); + ramulator_frontend_->connect_memory_system(ramulator_memorysystem_); + ramulator_memorysystem_->connect_frontend(ramulator_frontend_); + } + + ~Impl() { + std::ofstream nullstream("ramulator.stats.log"); + auto original_buf = std::cout.rdbuf(); + std::cout.rdbuf(nullstream.rdbuf()); + ramulator_frontend_->finalize(); + ramulator_memorysystem_->finalize(); + std::cout.rdbuf(original_buf); + } + + void reset() { + //-- + } + + void tick() { + ramulator_memorysystem_->tick(); + } + + bool send_request(bool is_write, uint64_t addr, int source_id, ResponseCallback callback, void* arg) { + if (!ramulator_frontend_->receive_external_requests( + is_write ? Ramulator::Request::Type::Write : Ramulator::Request::Type::Read, + addr, + source_id, + [callback_ = std::move(callback), arg_ = std::move(arg)](Ramulator::Request& /*dram_req*/) { + callback_(arg_); + } + )) { + return false; + } + if (is_write) { + // Ramulator does not handle write responses, so we call the callback ourselves + callback(arg); + } + return true; + } +}; + +/////////////////////////////////////////////////////////////////////////////// + +DramSim::DramSim(int clock_ratio) + : impl_(new Impl(clock_ratio)) +{} + +DramSim::~DramSim() { + delete impl_; +} + +void DramSim::reset() { + impl_->reset(); +} + +void DramSim::tick() { + impl_->tick(); +} + +bool DramSim::send_request(bool is_write, uint64_t addr, int source_id, ResponseCallback callback, void* arg) { + return impl_->send_request(is_write, addr, source_id, callback, arg); +} \ No newline at end of file diff --git a/sim/common/dram_sim.h b/sim/common/dram_sim.h new file mode 100644 index 000000000..5fea3f27c --- /dev/null +++ b/sim/common/dram_sim.h @@ -0,0 +1,36 @@ +// Copyright © 2019-2023 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +namespace vortex { + +class DramSim { +public: + typedef void (*ResponseCallback)(void *arg); + + DramSim(int clock_ratio); + ~DramSim(); + + void reset(); + + void tick(); + + bool send_request(bool is_write, uint64_t addr, int source_id, ResponseCallback callback, void* arg); + +private: + class Impl; + Impl* impl_; +}; + +} \ No newline at end of file diff --git a/sim/common/util.h b/sim/common/util.h index c8c63854f..83fdee7df 100644 --- a/sim/common/util.h +++ b/sim/common/util.h @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -34,6 +34,7 @@ const char* fileExtension(const char* filepath); #define DISABLE_WARNING_UNREFERENCED_FUNCTION __pragma(warning(disable : 4505)) #define DISABLE_WARNING_ANONYMOUS_STRUCT __pragma(warning(disable : 4201)) #define DISABLE_WARNING_UNUSED_VARIABLE __pragma(warning(disable : 4189)) +#define DISABLE_WARNING_MISSING_FIELD_INITIALIZERS __pragma(warning(disable : 4351)) #elif defined(__GNUC__) #define DISABLE_WARNING_PUSH _Pragma("GCC diagnostic push") #define DISABLE_WARNING_POP _Pragma("GCC diagnostic pop") @@ -45,6 +46,8 @@ const char* fileExtension(const char* filepath); _Pragma("GCC diagnostic ignored \"-Wpedantic\"") #define DISABLE_WARNING_UNUSED_VARIABLE \ _Pragma("GCC diagnostic ignored \"-Wunused-but-set-variable\"") +#define DISABLE_WARNING_MISSING_FIELD_INITIALIZERS \ + _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"") #elif defined(__clang__) #define DISABLE_WARNING_PUSH _Pragma("clang diagnostic push") #define DISABLE_WARNING_POP _Pragma("clang diagnostic pop") @@ -56,6 +59,8 @@ const char* fileExtension(const char* filepath); _Pragma("clang diagnostic ignored \"-Wgnu-anonymous-struct\"") #define DISABLE_WARNING_UNUSED_VARIABLE \ _Pragma("clang diagnostic ignored \"-Wunused-but-set-variable\"") +#define DISABLE_WARNING_MISSING_FIELD_INITIALIZERS \ + _Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"") #else #define DISABLE_WARNING_PUSH #define DISABLE_WARNING_POP diff --git a/sim/opaesim/Makefile b/sim/opaesim/Makefile index 2dd99cf92..7b0d543d2 100644 --- a/sim/opaesim/Makefile +++ b/sim/opaesim/Makefile @@ -5,15 +5,17 @@ DESTDIR ?= $(CURDIR) SRC_DIR := $(VORTEX_HOME)/sim/opaesim AFU_DIR := $(RTL_DIR)/afu/opae -CXXFLAGS += -std=c++11 -Wall -Wextra -Wfatal-errors -Wno-array-bounds +CXXFLAGS += -std=c++17 -Wall -Wextra -Wfatal-errors -Wno-array-bounds CXXFLAGS += -fPIC -Wno-maybe-uninitialized CXXFLAGS += -I$(SRC_DIR) -I$(ROOT_DIR)/hw -I$(COMMON_DIR) -I$(DESTDIR) CXXFLAGS += -I/$(THIRD_PARTY_DIR)/softfloat/source/include -CXXFLAGS += -I/$(THIRD_PARTY_DIR) +CXXFLAGS += -I$(THIRD_PARTY_DIR)/ramulator/ext/spdlog/include +CXXFLAGS += -I$(THIRD_PARTY_DIR)/ramulator/ext/yaml-cpp/include +CXXFLAGS += -I$(THIRD_PARTY_DIR)/ramulator/src CXXFLAGS += -DXLEN_$(XLEN) LDFLAGS += -shared $(THIRD_PARTY_DIR)/softfloat/build/Linux-x86_64-GCC/softfloat.a -LDFLAGS += -L$(THIRD_PARTY_DIR)/ramulator -lramulator -pthread +LDFLAGS += -Wl,-rpath,$(THIRD_PARTY_DIR)/ramulator -L$(THIRD_PARTY_DIR)/ramulator -lramulator -pthread # control RTL debug tracing states DBG_TRACE_FLAGS += -DDBG_TRACE_PIPELINE @@ -47,12 +49,12 @@ endif DBG_FLAGS += -DDEBUG_LEVEL=$(DEBUG) -DVCD_OUTPUT $(DBG_TRACE_FLAGS) -SRCS = $(COMMON_DIR)/util.cpp $(COMMON_DIR)/mem.cpp $(COMMON_DIR)/rvfloats.cpp +SRCS = $(COMMON_DIR)/util.cpp $(COMMON_DIR)/mem.cpp $(COMMON_DIR)/rvfloats.cpp $(COMMON_DIR)/dram_sim.cpp SRCS += $(DPI_DIR)/util_dpi.cpp $(DPI_DIR)/float_dpi.cpp SRCS += $(SRC_DIR)/fpga.cpp $(SRC_DIR)/opae_sim.cpp RTL_PKGS = $(AFU_DIR)/local_mem_cfg_pkg.sv $(AFU_DIR)/ccip/ccip_if_pkg.sv -RTL_PKGS += $(RTL_DIR)/VX_gpu_pkg.sv $(RTL_DIR)/fpu/VX_fpu_pkg.sv +RTL_PKGS += $(RTL_DIR)/VX_gpu_pkg.sv $(RTL_DIR)/fpu/VX_fpu_pkg.sv $(RTL_DIR)/core/VX_trace_pkg.sv FPU_INCLUDE = -I$(RTL_DIR)/fpu ifneq (,$(findstring FPU_FPNEW,$(CONFIGS))) @@ -65,7 +67,7 @@ RTL_INCLUDE += -I$(AFU_DIR) -I$(AFU_DIR)/ccip TOP = vortex_afu_shim VL_FLAGS += --language 1800-2009 --assert -Wall -Wpedantic -VL_FLAGS += -Wno-DECLFILENAME -Wno-REDEFMACRO +VL_FLAGS += -Wno-DECLFILENAME -Wno-REDEFMACRO -Wno-GENUNNAMED VL_FLAGS += --x-initial unique --x-assign unique VL_FLAGS += -DSIMULATION -DSV_DPI VL_FLAGS += -DXLEN_$(XLEN) @@ -73,7 +75,6 @@ VL_FLAGS += $(CONFIGS) VL_FLAGS += $(SRC_DIR)/verilator.vlt VL_FLAGS += $(RTL_INCLUDE) VL_FLAGS += $(RTL_PKGS) -VL_FLAGS += $(DBG_SCOPE_FLAGS) CXXFLAGS += $(CONFIGS) @@ -93,7 +94,7 @@ endif # Enable scope analyzer ifdef SCOPE - VL_FLAGS += -DSCOPE + VL_FLAGS += -DSCOPE $(DBG_SCOPE_FLAGS) CXXFLAGS += -DSCOPE SCOPE_JSON = $(DESTDIR)/scope.json endif diff --git a/sim/opaesim/opae_sim.cpp b/sim/opaesim/opae_sim.cpp index 368f8aa04..d6e06721d 100644 --- a/sim/opaesim/opae_sim.cpp +++ b/sim/opaesim/opae_sim.cpp @@ -13,9 +13,7 @@ #include "opae_sim.h" -#include #include "Vvortex_afu_shim.h" -#include "Vvortex_afu_shim__Syms.h" #ifdef VCD_OUTPUT #include @@ -26,10 +24,7 @@ #include #include -#define RAMULATOR -#include -#include -#include +#include #include #include @@ -48,8 +43,8 @@ #endif #endif -#ifndef MEM_CYCLE_RATIO -#define MEM_CYCLE_RATIO -1 +#ifndef MEM_CLOCK_RATIO +#define MEM_CLOCK_RATIO 1 #endif #undef MEM_BLOCK_SIZE @@ -108,11 +103,11 @@ public: Impl() : device_(nullptr) , ram_(nullptr) - , ramulator_(nullptr) + , dram_sim_(MEM_CLOCK_RATIO) , stop_(false) , host_buffer_ids_(0) #ifdef VCD_OUTPUT - , trace_(nullptr) + , tfp_(nullptr) #endif {} @@ -125,9 +120,9 @@ public: aligned_free(buffer.second.data); } #ifdef VCD_OUTPUT - if (trace_) { - trace_->close(); - delete trace_; + if (tfp_) { + tfp_->close(); + delete tfp_; } #endif if (device_) { @@ -136,11 +131,6 @@ public: if (ram_) { delete ram_; } - if (ramulator_) { - ramulator_->finish(); - Stats::statlist.printall(); - delete ramulator_; - } } int init() { @@ -156,25 +146,25 @@ public: #ifdef VCD_OUTPUT Verilated::traceEverOn(true); - trace_ = new VerilatedVcdC(); - device_->trace(trace_, 99); - trace_->open("trace.vcd"); + tfp_ = new VerilatedVcdC(); + device_->trace(tfp_, 99); + tfp_->open("trace.vcd"); #endif ram_ = new RAM(0, RAM_PAGE_SIZE); - // initialize dram simulator - ramulator::Config ram_config; - ram_config.add("standard", "DDR4"); - ram_config.add("channels", std::to_string(MEMORY_BANKS)); - ram_config.add("ranks", "1"); - ram_config.add("speed", "DDR4_2400R"); - ram_config.add("org", "DDR4_4Gb_x8"); - ram_config.add("mapping", "defaultmapping"); - ram_config.set_core_num(1); - ramulator_ = new ramulator::Gem5Wrapper(ram_config, MEM_BLOCK_SIZE); - Stats::statlist.output("ramulator.ddr4.log"); - + #ifndef NDEBUG + // dump device configuration + std::cout << "CONFIGS:" + << " num_threads=" << NUM_THREADS + << ", num_warps=" << NUM_WARPS + << ", num_cores=" << NUM_CORES + << ", num_clusters=" << NUM_CLUSTERS + << ", socket_size=" << SOCKET_SIZE + << ", local_mem_base=0x" << std::hex << LMEM_BASE_ADDR << std::dec + << ", num_barriers=" << NUM_BARRIERS + << std::endl; + #endif // reset the device this->reset(); @@ -258,19 +248,16 @@ public: private: void reset() { - cci_reads_.clear(); - cci_writes_.clear(); - device_->vcp2af_sRxPort_c0_mmioRdValid = 0; - device_->vcp2af_sRxPort_c0_mmioWrValid = 0; - device_->vcp2af_sRxPort_c0_rspValid = 0; - device_->vcp2af_sRxPort_c1_rspValid = 0; - device_->vcp2af_sRxPort_c0_TxAlmFull = 0; - device_->vcp2af_sRxPort_c1_TxAlmFull = 0; + this->cci_bus_reset(); + this->avs_bus_reset(); - for (int b = 0; b < MEMORY_BANKS; ++b) { - pending_mem_reqs_[b].clear(); - device_->avs_readdatavalid[b] = 0; - device_->avs_waitrequest[b] = 0; + for (auto& reqs : pending_mem_reqs_) { + reqs.clear(); + } + + { + std::queue empty; + std::swap(dram_queue_, empty); } device_->reset = 1; @@ -296,13 +283,21 @@ private: } void tick() { - this->sRxPort_bus(); - this->sTxPort_bus(); - this->avs_bus(); + this->cci_bus_eval(); + this->avs_bus_eval(); if (!dram_queue_.empty()) { - if (ramulator_->send(dram_queue_.front())) + auto mem_req = dram_queue_.front(); + if (dram_sim_.send_request(mem_req->write, mem_req->addr, mem_req->bank_id, [](void* arg) { + auto orig_req = reinterpret_cast(arg); + if (orig_req->ready) { + delete orig_req; + } else { + orig_req->ready = true; + } + }, mem_req)) { dram_queue_.pop(); + } } device_->clk = 0; @@ -310,14 +305,7 @@ private: device_->clk = 1; this->eval(); - if (MEM_CYCLE_RATIO > 0) { - auto cycle = timestamp / 2; - if ((cycle % MEM_CYCLE_RATIO) == 0) - ramulator_->tick(); - } else { - for (int i = MEM_CYCLE_RATIO; i <= 0; ++i) - ramulator_->tick(); - } + dram_sim_.tick(); #ifndef NDEBUG fflush(stdout); @@ -328,13 +316,29 @@ private: device_->eval(); #ifdef VCD_OUTPUT if (sim_trace_enabled()) { - trace_->dump(timestamp); + tfp_->dump(timestamp); } #endif ++timestamp; } - void sRxPort_bus() { + void cci_bus_reset() { + cci_reads_.clear(); + cci_writes_.clear(); + device_->vcp2af_sRxPort_c0_mmioRdValid = 0; + device_->vcp2af_sRxPort_c0_mmioWrValid = 0; + device_->vcp2af_sRxPort_c0_rspValid = 0; + device_->vcp2af_sRxPort_c1_rspValid = 0; + device_->vcp2af_sRxPort_c0_TxAlmFull = 0; + device_->vcp2af_sRxPort_c1_TxAlmFull = 0; + } + + void cci_bus_eval() { + this->sRxPort_bus_eval(); + this->sTxPort_bus_eval(); + } + + void sRxPort_bus_eval() { // check mmio request bool mmio_req_enabled = device_->vcp2af_sRxPort_c0_mmioRdValid || device_->vcp2af_sRxPort_c0_mmioWrValid; @@ -384,7 +388,7 @@ private: } } - void sTxPort_bus() { + void sTxPort_bus_eval() { // process read requests if (device_->af2cp_sTxPort_c0_valid) { assert(!device_->vcp2af_sRxPort_c0_TxAlmFull); @@ -414,7 +418,15 @@ private: device_->vcp2af_sRxPort_c1_TxAlmFull = (cci_writes_.size() >= (CCI_WQ_SIZE-1)); } - void avs_bus() { + void avs_bus_reset() { + for (int b = 0; b < MEMORY_BANKS; ++b) { + pending_mem_reqs_[b].clear(); + device_->avs_readdatavalid[b] = 0; + device_->avs_waitrequest[b] = 0; + } + } + + void avs_bus_eval() { for (int b = 0; b < MEMORY_BANKS; ++b) { // process memory responses device_->avs_readdatavalid[b] = 0; @@ -448,17 +460,20 @@ private: printf("\n");*/ // send dram request - ramulator::Request dram_req( - byte_addr, - ramulator::Request::Type::WRITE, - 0 - ); - dram_queue_.push(dram_req); + auto mem_req = new mem_req_t(); + mem_req->addr = device_->avs_address[b]; + mem_req->bank_id = b; + mem_req->write = true; + mem_req->ready = true; + + dram_queue_.push(mem_req); } else if (device_->avs_read[b]) { - auto mem_req = new mem_rd_req_t(); + auto mem_req = new mem_req_t(); mem_req->addr = device_->avs_address[b]; + mem_req->bank_id = b; ram_->read(mem_req->data.data(), byte_addr, MEM_BLOCK_SIZE); + mem_req->write = false; mem_req->ready = false; pending_mem_reqs_[b].emplace_back(mem_req); @@ -472,15 +487,7 @@ private: printf("}\n");*/ // send dram request - ramulator::Request dram_req( - byte_addr, - ramulator::Request::Type::READ, - std::bind([](ramulator::Request& dram_req, mem_rd_req_t* mem_req) { - mem_req->ready = true; - }, placeholders::_1, mem_req), - 0 - ); - dram_queue_.push(dram_req); + dram_queue_.push(mem_req); } device_->avs_waitrequest[b] = false; @@ -488,10 +495,12 @@ private: } typedef struct { - bool ready; std::array data; uint32_t addr; - } mem_rd_req_t; + uint32_t bank_id; + bool write; + bool ready; + } mem_req_t; typedef struct { int cycles_left; @@ -513,7 +522,7 @@ private: Vvortex_afu_shim *device_; RAM* ram_; - ramulator::Gem5Wrapper* ramulator_; + DramSim dram_sim_; std::future future_; bool stop_; @@ -521,17 +530,17 @@ private: std::unordered_map host_buffers_; int64_t host_buffer_ids_; - std::list pending_mem_reqs_[MEMORY_BANKS]; + std::list pending_mem_reqs_[MEMORY_BANKS]; std::list cci_reads_; std::list cci_writes_; std::mutex mutex_; - std::queue dram_queue_; + std::queue dram_queue_; #ifdef VCD_OUTPUT - VerilatedVcdC *trace_; + VerilatedVcdC *tfp_; #endif }; diff --git a/sim/rtlsim/Makefile b/sim/rtlsim/Makefile index 42a28cc54..e9487a2f4 100644 --- a/sim/rtlsim/Makefile +++ b/sim/rtlsim/Makefile @@ -4,15 +4,17 @@ DESTDIR ?= $(CURDIR) SRC_DIR = $(VORTEX_HOME)/sim/rtlsim -CXXFLAGS += -std=c++11 -Wall -Wextra -Wfatal-errors -Wno-array-bounds +CXXFLAGS += -std=c++17 -Wall -Wextra -Wfatal-errors -Wno-array-bounds CXXFLAGS += -fPIC -Wno-maybe-uninitialized CXXFLAGS += -I$(ROOT_DIR)/hw -I$(COMMON_DIR) CXXFLAGS += -I$(THIRD_PARTY_DIR)/softfloat/source/include -CXXFLAGS += -I$(THIRD_PARTY_DIR) +CXXFLAGS += -I$(THIRD_PARTY_DIR)/ramulator/ext/spdlog/include +CXXFLAGS += -I$(THIRD_PARTY_DIR)/ramulator/ext/yaml-cpp/include +CXXFLAGS += -I$(THIRD_PARTY_DIR)/ramulator/src CXXFLAGS += -DXLEN_$(XLEN) LDFLAGS += $(THIRD_PARTY_DIR)/softfloat/build/Linux-x86_64-GCC/softfloat.a -LDFLAGS += -L$(THIRD_PARTY_DIR)/ramulator -lramulator +LDFLAGS += -Wl,-rpath,$(THIRD_PARTY_DIR)/ramulator -L$(THIRD_PARTY_DIR)/ramulator -lramulator # control RTL debug tracing states DBG_TRACE_FLAGS += -DDBG_TRACE_PIPELINE @@ -24,7 +26,7 @@ DBG_TRACE_FLAGS += -DDBG_TRACE_GBAR DBG_FLAGS += -DDEBUG_LEVEL=$(DEBUG) -DVCD_OUTPUT $(DBG_TRACE_FLAGS) -RTL_PKGS = $(RTL_DIR)/VX_gpu_pkg.sv $(RTL_DIR)/fpu/VX_fpu_pkg.sv +RTL_PKGS = $(RTL_DIR)/VX_gpu_pkg.sv $(RTL_DIR)/fpu/VX_fpu_pkg.sv $(RTL_DIR)/core/VX_trace_pkg.sv FPU_INCLUDE = -I$(RTL_DIR)/fpu ifneq (,$(findstring FPU_FPNEW,$(CONFIGS))) @@ -33,7 +35,7 @@ ifneq (,$(findstring FPU_FPNEW,$(CONFIGS))) endif RTL_INCLUDE = -I$(RTL_DIR) -I$(DPI_DIR) -I$(RTL_DIR)/libs -I$(RTL_DIR)/interfaces -I$(RTL_DIR)/core -I$(RTL_DIR)/mem -I$(RTL_DIR)/cache $(FPU_INCLUDE) -SRCS = $(COMMON_DIR)/util.cpp $(COMMON_DIR)/mem.cpp $(COMMON_DIR)/rvfloats.cpp +SRCS = $(COMMON_DIR)/util.cpp $(COMMON_DIR)/mem.cpp $(COMMON_DIR)/rvfloats.cpp $(COMMON_DIR)/dram_sim.cpp SRCS += $(DPI_DIR)/util_dpi.cpp $(DPI_DIR)/float_dpi.cpp SRCS += $(SRC_DIR)/processor.cpp @@ -46,7 +48,7 @@ endif VL_FLAGS = --exe VL_FLAGS += --language 1800-2009 --assert -Wall -Wpedantic -VL_FLAGS += -Wno-DECLFILENAME -Wno-REDEFMACRO +VL_FLAGS += -Wno-DECLFILENAME -Wno-REDEFMACRO -Wno-GENUNNAMED VL_FLAGS += --x-initial unique --x-assign unique VL_FLAGS += $(SRC_DIR)/verilator.vlt VL_FLAGS += -DSIMULATION -DSV_DPI diff --git a/sim/rtlsim/main.cpp b/sim/rtlsim/main.cpp index 46fd7637d..ea0ba9b95 100644 --- a/sim/rtlsim/main.cpp +++ b/sim/rtlsim/main.cpp @@ -89,7 +89,9 @@ int main(int argc, char **argv) { return -1; } } - +#ifndef NDEBUG + std::cout << "[VXDRV] START: program=" << program << std::endl; +#endif // run simulation processor.run(); diff --git a/sim/rtlsim/processor.cpp b/sim/rtlsim/processor.cpp index acedde614..2c31f939b 100644 --- a/sim/rtlsim/processor.cpp +++ b/sim/rtlsim/processor.cpp @@ -13,14 +13,12 @@ #include "processor.h" -#include - #ifdef AXI_BUS #include "VVortex_axi.h" -#include "VVortex_axi__Syms.h" +typedef VVortex_axi Device; #else #include "VVortex.h" -#include "VVortex__Syms.h" +typedef VVortex Device; #endif #ifdef VCD_OUTPUT @@ -40,10 +38,7 @@ #include #include -#define RAMULATOR -#include -#include -#include +#include #ifndef MEMORY_BANKS #ifdef PLATFORM_PARAM_LOCAL_MEMORY_BANKS @@ -53,8 +48,8 @@ #endif #endif -#ifndef MEM_CYCLE_RATIO -#define MEM_CYCLE_RATIO -1 +#ifndef MEM_CLOCK_RATIO +#define MEM_CLOCK_RATIO 1 #endif #ifndef TRACE_START_TIME @@ -109,7 +104,7 @@ void sim_trace_enable(bool enable) { class Processor::Impl { public: - Impl() { + Impl() : dram_sim_(MEM_CLOCK_RATIO) { // force random values for unitialized signals Verilated::randReset(VERILATOR_RESET_VALUE); Verilated::randSeed(50); @@ -118,33 +113,29 @@ public: Verilated::assertOn(false); // create RTL module instance - #ifdef AXI_BUS - device_ = new VVortex_axi(); - #else - device_ = new VVortex(); - #endif + device_ = new Device(); #ifdef VCD_OUTPUT Verilated::traceEverOn(true); - trace_ = new VerilatedVcdC(); - device_->trace(trace_, 99); - trace_->open("trace.vcd"); + tfp_ = new VerilatedVcdC(); + device_->trace(tfp_, 99); + tfp_->open("trace.vcd"); #endif ram_ = nullptr; - // initialize dram simulator - ramulator::Config ram_config; - ram_config.add("standard", "DDR4"); - ram_config.add("channels", std::to_string(MEMORY_BANKS)); - ram_config.add("ranks", "1"); - ram_config.add("speed", "DDR4_2400R"); - ram_config.add("org", "DDR4_4Gb_x8"); - ram_config.add("mapping", "defaultmapping"); - ram_config.set_core_num(1); - dram_ = new ramulator::Gem5Wrapper(ram_config, MEM_BLOCK_SIZE); - Stats::statlist.output("ramulator.ddr4.log"); - + #ifndef NDEBUG + // dump device configuration + std::cout << "CONFIGS:" + << " num_threads=" << NUM_THREADS + << ", num_warps=" << NUM_WARPS + << ", num_cores=" << NUM_CORES + << ", num_clusters=" << NUM_CLUSTERS + << ", socket_size=" << SOCKET_SIZE + << ", local_mem_base=0x" << std::hex << LMEM_BASE_ADDR << std::dec + << ", num_barriers=" << NUM_BARRIERS + << std::endl; + #endif // reset the device this->reset(); @@ -156,17 +147,11 @@ public: this->cout_flush(); #ifdef VCD_OUTPUT - trace_->close(); - delete trace_; + tfp_->close(); + delete tfp_; #endif delete device_; - - if (dram_) { - dram_->finish(); - Stats::statlist.printall(); - delete dram_; - } } void cout_flush() { @@ -226,16 +211,17 @@ private: pending_mem_reqs_.clear(); + { + std::queue empty; + std::swap(dram_queue_, empty); + } + mem_rd_rsp_active_ = false; mem_wr_rsp_active_ = false; - #ifdef AXI_BUS - this->reset_axi_bus(); - #else - this->reset_avs_bus(); - #endif + this->mem_bus_reset(); - this->reset_dcr_bus(); + this->dcr_bus_reset(); device_->reset = 1; @@ -252,35 +238,29 @@ private: device_->clk = 0; this->eval(); - #ifdef AXI_BUS - this->eval_axi_bus(0); - #else - this->eval_avs_bus(0); - #endif - this->eval_dcr_bus(0); + this->mem_bus_eval(0); + this->dcr_bus_eval(0); device_->clk = 1; this->eval(); - #ifdef AXI_BUS - this->eval_axi_bus(1); - #else - this->eval_avs_bus(1); - #endif - this->eval_dcr_bus(1); + this->mem_bus_eval(1); + this->dcr_bus_eval(1); - if (MEM_CYCLE_RATIO > 0) { - auto cycle = timestamp / 2; - if ((cycle % MEM_CYCLE_RATIO) == 0) - dram_->tick(); - } else { - for (int i = MEM_CYCLE_RATIO; i <= 0; ++i) - dram_->tick(); - } + dram_sim_.tick(); if (!dram_queue_.empty()) { - if (dram_->send(dram_queue_.front())) + auto mem_req = dram_queue_.front(); + if (dram_sim_.send_request(mem_req->write, mem_req->addr, 0, [](void* arg) { + auto orig_req = reinterpret_cast(arg); + if (orig_req->ready) { + delete orig_req; + } else { + orig_req->ready = true; + } + }, mem_req)) { dram_queue_.pop(); + } } #ifndef NDEBUG @@ -292,7 +272,7 @@ private: device_->eval(); #ifdef VCD_OUTPUT if (sim_trace_enabled()) { - trace_->dump(timestamp); + tfp_->dump(timestamp); } else { exit(-1); } @@ -302,7 +282,7 @@ private: #ifdef AXI_BUS - void reset_axi_bus() { + void mem_bus_reset() { device_->m_axi_wready[0] = 0; device_->m_axi_awready[0] = 0; device_->m_axi_arready[0] = 0; @@ -310,7 +290,7 @@ private: device_->m_axi_bvalid[0] = 0; } - void eval_axi_bus(bool clk) { + void mem_bus_eval(bool clk) { if (!clk) { mem_rd_rsp_ready_ = device_->m_axi_rready[0]; mem_wr_rsp_ready_ = device_->m_axi_bready[0]; @@ -324,9 +304,9 @@ private: return; } - // process memory responses + // process memory read responses if (mem_rd_rsp_active_ - && device_->m_axi_rvalid[0] && mem_rd_rsp_ready_) { + && device_->m_axi_rvalid[0] && mem_rd_rsp_ready_) { mem_rd_rsp_active_ = false; } if (!mem_rd_rsp_active_) { @@ -336,7 +316,7 @@ private: auto mem_rsp_it = pending_mem_reqs_.begin(); auto mem_rsp = *mem_rsp_it; /* - printf("%0ld: [sim] MEM Rd Rsp: bank=%d, addr=%0lx, data=", timestamp, last_mem_rsp_bank_, mem_rsp->addr); + printf("%0ld: [sim] MEM Rd Rsp: addr=%0lx, data=", timestamp, mem_rsp->addr); for (int i = 0; i < MEM_BLOCK_SIZE; i++) { printf("%02x", mem_rsp->block[(MEM_BLOCK_SIZE-1)-i]); } @@ -355,9 +335,9 @@ private: } } - // send memory write response + // process memory write responses if (mem_wr_rsp_active_ - && device_->m_axi_bvalid[0] && mem_wr_rsp_ready_) { + && device_->m_axi_bvalid[0] && mem_wr_rsp_ready_) { mem_wr_rsp_active_ = false; } if (!mem_wr_rsp_active_) { @@ -367,7 +347,7 @@ private: auto mem_rsp_it = pending_mem_reqs_.begin(); auto mem_rsp = *mem_rsp_it; /* - printf("%0ld: [sim] MEM Wr Rsp: bank=%d, addr=%0lx\n", timestamp, last_mem_rsp_bank_, mem_rsp->addr); + printf("%0ld: [sim] MEM Wr Rsp: addr=%0lx\n", timestamp, mem_rsp->addr); */ device_->m_axi_bvalid[0] = 1; device_->m_axi_bid[0] = mem_rsp->tag; @@ -386,13 +366,13 @@ private: // process memory requests if ((device_->m_axi_wvalid[0] || device_->m_axi_arvalid[0]) && running_) { if (device_->m_axi_wvalid[0]) { - uint64_t byteen = device_->m_axi_wstrb[0]; - uint64_t base_addr = device_->m_axi_awaddr[0]; - uint8_t* data = (uint8_t*)device_->m_axi_wdata[0].data(); + auto byteen = device_->m_axi_wstrb[0]; + auto base_addr = device_->m_axi_awaddr[0]; + auto data = (uint8_t*)device_->m_axi_wdata[0].data(); - // check console output if (base_addr >= uint64_t(IO_COUT_ADDR) && base_addr < (uint64_t(IO_COUT_ADDR) + IO_COUT_SIZE)) { + // process console output for (int i = 0; i < MEM_BLOCK_SIZE; i++) { if ((byteen >> i) & 0x1) { auto& ss_buf = print_bufs_[i]; @@ -405,6 +385,7 @@ private: } } } else { + // process writes /* printf("%0ld: [sim] MEM Wr: addr=%0x, byteen=%0lx, data=", timestamp, base_addr, byteen); for (int i = 0; i < MEM_BLOCK_SIZE; i++) { @@ -422,16 +403,11 @@ private: mem_req->tag = device_->m_axi_awid[0]; mem_req->addr = device_->m_axi_awaddr[0]; mem_req->write = true; - mem_req->ready = true; + mem_req->ready = false; pending_mem_reqs_.emplace_back(mem_req); // send dram request - ramulator::Request dram_req( - device_->m_axi_awaddr[0], - ramulator::Request::Type::WRITE, - 0 - ); - dram_queue_.push(dram_req); + dram_queue_.push(mem_req); } } else { // process reads @@ -444,15 +420,7 @@ private: pending_mem_reqs_.emplace_back(mem_req); // send dram request - ramulator::Request dram_req( - device_->m_axi_araddr[0], - ramulator::Request::Type::READ, - std::bind([&](ramulator::Request& dram_req, mem_req_t* mem_req) { - mem_req->ready = true; - }, placeholders::_1, mem_req), - 0 - ); - dram_queue_.push(dram_req); + dram_queue_.push(mem_req); } } @@ -463,12 +431,12 @@ private: #else - void reset_avs_bus() { + void mem_bus_reset() { device_->mem_req_ready = 0; device_->mem_rsp_valid = 0; } - void eval_avs_bus(bool clk) { + void mem_bus_eval(bool clk) { if (!clk) { mem_rd_rsp_ready_ = device_->mem_rsp_ready; return; @@ -479,7 +447,7 @@ private: return; } - // process memory responses + // process memory read responses if (mem_rd_rsp_active_ && device_->mem_rsp_valid && mem_rd_rsp_ready_) { mem_rd_rsp_active_ = false; @@ -491,7 +459,7 @@ private: auto mem_rsp_it = pending_mem_reqs_.begin(); auto mem_rsp = *mem_rsp_it; /* - printf("%0ld: [sim] MEM Rd: bank=%d, tag=%0lx, addr=%0lx, data=", timestamp, last_mem_rsp_bank_, mem_rsp->tag, mem_rsp->addr); + printf("%0ld: [sim] MEM Rd: tag=%0lx, addr=%0lx, data=", timestamp, mem_rsp->tag, mem_rsp->addr); for (int i = 0; i < MEM_BLOCK_SIZE; i++) { printf("%02x", mem_rsp->block[(MEM_BLOCK_SIZE-1)-i]); } @@ -511,13 +479,12 @@ private: if (device_->mem_req_valid && running_) { uint64_t byte_addr = (device_->mem_req_addr * MEM_BLOCK_SIZE); if (device_->mem_req_rw) { - // process writes - uint64_t byteen = device_->mem_req_byteen; - uint8_t* data = (uint8_t*)(device_->mem_req_data.data()); + auto byteen = device_->mem_req_byteen; + auto data = (uint8_t*)(device_->mem_req_data.data()); - // check console output if (byte_addr >= uint64_t(IO_COUT_ADDR) && byte_addr < (uint64_t(IO_COUT_ADDR) + IO_COUT_SIZE)) { + // process console output for (int i = 0; i < IO_COUT_SIZE; i++) { if ((byteen >> i) & 0x1) { auto& ss_buf = print_bufs_[i]; @@ -530,6 +497,7 @@ private: } } } else { + // process writes /* printf("%0ld: [sim] MEM Wr: tag=%0lx, addr=%0x, byteen=%0lx, data=", timestamp, device_->mem_req_tag, byte_addr, byteen); for (int i = 0; i < MEM_BLOCK_SIZE; i++) { @@ -543,13 +511,14 @@ private: } } + auto mem_req = new mem_req_t(); + mem_req->tag = device_->mem_req_tag; + mem_req->addr = byte_addr; + mem_req->write = true; + mem_req->ready = true; + // send dram request - ramulator::Request dram_req( - byte_addr, - ramulator::Request::Type::WRITE, - 0 - ); - dram_queue_.push(dram_req); + dram_queue_.push(mem_req); } } else { // process reads @@ -564,15 +533,7 @@ private: //printf("%0ld: [sim] MEM Rd Req: addr=%0x, tag=%0lx\n", timestamp, byte_addr, device_->mem_req_tag); // send dram request - ramulator::Request dram_req( - byte_addr, - ramulator::Request::Type::READ, - std::bind([&](ramulator::Request& dram_req, mem_req_t* mem_req) { - mem_req->ready = true; - }, placeholders::_1, mem_req), - 0 - ); - dram_queue_.push(dram_req); + dram_queue_.push(mem_req); } } @@ -581,11 +542,11 @@ private: #endif - void reset_dcr_bus() { + void dcr_bus_reset() { device_->dcr_wr_valid = 0; } - void eval_dcr_bus(bool clk) { + void dcr_bus_eval(bool clk) { if (!clk) { return; } @@ -603,38 +564,36 @@ private: private: typedef struct { - bool ready; + Device* device; std::array block; uint64_t addr; uint64_t tag; bool write; + bool ready; } mem_req_t; -#ifdef AXI_BUS - VVortex_axi *device_; -#else - VVortex *device_; -#endif -#ifdef VCD_OUTPUT - VerilatedVcdC *trace_; -#endif - std::unordered_map print_bufs_; std::list pending_mem_reqs_; + std::queue dram_queue_; + + DramSim dram_sim_; + + Device* device_; + +#ifdef VCD_OUTPUT + VerilatedVcdC *tfp_; +#endif + + RAM* ram_; + bool mem_rd_rsp_active_; bool mem_rd_rsp_ready_; bool mem_wr_rsp_active_; bool mem_wr_rsp_ready_; - RAM *ram_; - - ramulator::Gem5Wrapper* dram_; - - std::queue dram_queue_; - bool running_; }; diff --git a/sim/simx/Makefile b/sim/simx/Makefile index 4feb2c77a..8520e5191 100644 --- a/sim/simx/Makefile +++ b/sim/simx/Makefile @@ -4,18 +4,24 @@ DESTDIR ?= $(CURDIR) SRC_DIR = $(VORTEX_HOME)/sim/simx -CXXFLAGS += -std=c++11 -Wall -Wextra -Wfatal-errors +CXXFLAGS += -std=c++17 -Wall -Wextra -Wfatal-errors CXXFLAGS += -fPIC -Wno-maybe-uninitialized CXXFLAGS += -I$(SRC_DIR) -I$(COMMON_DIR) -I$(ROOT_DIR)/hw CXXFLAGS += -I$(THIRD_PARTY_DIR)/softfloat/source/include -CXXFLAGS += -I$(THIRD_PARTY_DIR) +CXXFLAGS += -I$(THIRD_PARTY_DIR)/ramulator/ext/spdlog/include +CXXFLAGS += -I$(THIRD_PARTY_DIR)/ramulator/ext/yaml-cpp/include +CXXFLAGS += -I$(THIRD_PARTY_DIR)/ramulator/src CXXFLAGS += -DXLEN_$(XLEN) CXXFLAGS += $(CONFIGS) -LDFLAGS += $(THIRD_PARTY_DIR)/softfloat/build/Linux-x86_64-GCC/softfloat.a -LDFLAGS += -L$(THIRD_PARTY_DIR)/ramulator -lramulator +ifeq ($(VM_ENABLE), 1) +CXXFLAGS += -DVM_ENABLE +endif -SRCS = $(COMMON_DIR)/util.cpp $(COMMON_DIR)/mem.cpp $(COMMON_DIR)/rvfloats.cpp +LDFLAGS += $(THIRD_PARTY_DIR)/softfloat/build/Linux-x86_64-GCC/softfloat.a +LDFLAGS += -Wl,-rpath,$(THIRD_PARTY_DIR)/ramulator -L$(THIRD_PARTY_DIR)/ramulator -lramulator + +SRCS = $(COMMON_DIR)/util.cpp $(COMMON_DIR)/mem.cpp $(COMMON_DIR)/rvfloats.cpp $(COMMON_DIR)/dram_sim.cpp SRCS += $(SRC_DIR)/processor.cpp $(SRC_DIR)/cluster.cpp $(SRC_DIR)/socket.cpp $(SRC_DIR)/core.cpp $(SRC_DIR)/emulator.cpp $(SRC_DIR)/decode.cpp $(SRC_DIR)/execute.cpp $(SRC_DIR)/func_unit.cpp $(SRC_DIR)/cache_sim.cpp $(SRC_DIR)/mem_sim.cpp $(SRC_DIR)/local_mem.cpp $(SRC_DIR)/mem_coalescer.cpp $(SRC_DIR)/dcrs.cpp $(SRC_DIR)/types.cpp # Debugigng diff --git a/sim/simx/arch.h b/sim/simx/arch.h index 2507bf28f..d72b4ce11 100644 --- a/sim/simx/arch.h +++ b/sim/simx/arch.h @@ -29,11 +29,7 @@ private: uint16_t num_cores_; uint16_t num_clusters_; uint16_t socket_size_; - uint16_t vsize_; - uint16_t num_regs_; - uint16_t num_csrs_; uint16_t num_barriers_; - uint16_t ipdom_size_; uint64_t local_mem_base_; public: @@ -43,26 +39,10 @@ public: , num_cores_(num_cores) , num_clusters_(NUM_CLUSTERS) , socket_size_(SOCKET_SIZE) - , vsize_(16) - , num_regs_(32) - , num_csrs_(4096) , num_barriers_(NUM_BARRIERS) - , ipdom_size_((num_threads-1) * 2) , local_mem_base_(LMEM_BASE_ADDR) {} - uint16_t vsize() const { - return vsize_; - } - - uint16_t num_regs() const { - return num_regs_; - } - - uint16_t num_csrs() const { - return num_csrs_; - } - uint16_t num_barriers() const { return num_barriers_; } @@ -71,10 +51,6 @@ public: return local_mem_base_; } - uint16_t ipdom_size() const { - return ipdom_size_; - } - uint16_t num_threads() const { return num_threads_; } diff --git a/sim/simx/cache_sim.cpp b/sim/simx/cache_sim.cpp index d92c83a03..65a8da70b 100644 --- a/sim/simx/cache_sim.cpp +++ b/sim/simx/cache_sim.cpp @@ -400,7 +400,7 @@ public: continue; auto& mem_rsp = mem_rsp_port.front(); - DT(3, simobject_->name() << "-dram-" << mem_rsp); + DT(3, simobject_->name() << "-bank" << bank_id << " fill-rsp: " << mem_rsp); pipeline_req.type = bank_req_t::Fill; pipeline_req.tag = mem_rsp.tag; mem_rsp_port.pop(); @@ -436,7 +436,7 @@ public: auto port_id = req_id % config_.ports_per_bank; // check MSHR capacity - if ((!core_req.write || !config_.write_through) + if ((!core_req.write || config_.write_back) && bank.mshr.full()) { ++perf_stats_.mshr_stalls; continue; @@ -473,7 +473,6 @@ public: ++perf_stats_.reads; // remove request - DT(3, simobject_->name() << "-core-" << core_req); auto time = core_req_port.pop(); perf_stats_.pipeline_stalls += (SimPlatform::instance().cycles() - time); } @@ -493,23 +492,21 @@ private: uint64_t tag = mem_rsp.tag >> params_.log2_num_inputs; MemRsp core_rsp{tag, mem_rsp.cid, mem_rsp.uuid}; simobject_->CoreRspPorts.at(req_id).push(core_rsp, config_.latency); - DT(3, simobject_->name() << "-core-" << core_rsp); + DT(3, simobject_->name() << " core-rsp: " << core_rsp); } void processBypassRequest(const MemReq& core_req, uint32_t req_id) { - DT(3, simobject_->name() << "-core-" << core_req); - { MemReq mem_req(core_req); mem_req.tag = (core_req.tag << params_.log2_num_inputs) + req_id; bypass_switch_->ReqIn.at(1).push(mem_req, 1); - DT(3, simobject_->name() << "-dram-" << mem_req); + DT(3, simobject_->name() << " dram-req: " << mem_req); } if (core_req.write && config_.write_reponse) { MemRsp core_rsp{core_req.tag, core_req.cid, core_req.uuid}; simobject_->CoreRspPorts.at(req_id).push(core_rsp, 1); - DT(3, simobject_->name() << "-core-" << core_rsp); + DT(3, simobject_->name() << " core-rsp: " << core_rsp); } } @@ -539,7 +536,7 @@ private: continue; MemRsp core_rsp{info.req_tag, pipeline_req.cid, pipeline_req.uuid}; simobject_->CoreRspPorts.at(info.req_id).push(core_rsp, config_.latency); - DT(3, simobject_->name() << "-core-" << core_rsp); + DT(3, simobject_->name() << "-bank" << bank_id << " replay: " << core_rsp); } } } break; @@ -575,7 +572,7 @@ private: if (pipeline_req.write) { // handle write has_hit auto& hit_line = set.lines.at(hit_line_id); - if (config_.write_through) { + if (!config_.write_back) { // forward write request to memory MemReq mem_req; mem_req.addr = params_.mem_addr(bank_id, pipeline_req.set_id, pipeline_req.tag); @@ -583,7 +580,7 @@ private: mem_req.cid = pipeline_req.cid; mem_req.uuid = pipeline_req.uuid; mem_req_ports_.at(bank_id).push(mem_req, 1); - DT(3, simobject_->name() << "-dram-" << mem_req); + DT(3, simobject_->name() << "-bank" << bank_id << " writethrough: " << mem_req); } else { // mark line as dirty hit_line.dirty = true; @@ -596,7 +593,7 @@ private: continue; MemRsp core_rsp{info.req_tag, pipeline_req.cid, pipeline_req.uuid}; simobject_->CoreRspPorts.at(info.req_id).push(core_rsp, config_.latency); - DT(3, simobject_->name() << "-core-" << core_rsp); + DT(3, simobject_->name() << "-bank" << bank_id << " core-rsp: " << core_rsp); } } } else { @@ -606,7 +603,7 @@ private: else ++perf_stats_.read_misses; - if (free_line_id == -1 && !config_.write_through) { + if (free_line_id == -1 && config_.write_back) { // write back dirty line auto& repl_line = set.lines.at(repl_line_id); if (repl_line.dirty) { @@ -615,12 +612,12 @@ private: mem_req.write = true; mem_req.cid = pipeline_req.cid; mem_req_ports_.at(bank_id).push(mem_req, 1); - DT(3, simobject_->name() << "-dram-" << mem_req); + DT(3, simobject_->name() << "-bank" << bank_id << " writeback: " << mem_req); ++perf_stats_.evictions; } } - if (pipeline_req.write && config_.write_through) { + if (pipeline_req.write && !config_.write_back) { // forward write request to memory { MemReq mem_req; @@ -629,7 +626,7 @@ private: mem_req.cid = pipeline_req.cid; mem_req.uuid = pipeline_req.uuid; mem_req_ports_.at(bank_id).push(mem_req, 1); - DT(3, simobject_->name() << "-dram-" << mem_req); + DT(3, simobject_->name() << "-bank" << bank_id << " writethrough: " << mem_req); } // send core response if (config_.write_reponse) { @@ -638,7 +635,7 @@ private: continue; MemRsp core_rsp{info.req_tag, pipeline_req.cid, pipeline_req.uuid}; simobject_->CoreRspPorts.at(info.req_id).push(core_rsp, config_.latency); - DT(3, simobject_->name() << "-core-" << core_rsp); + DT(3, simobject_->name() << "-bank" << bank_id << " core-rsp: " << core_rsp); } } } else { @@ -657,7 +654,7 @@ private: mem_req.cid = pipeline_req.cid; mem_req.uuid = pipeline_req.uuid; mem_req_ports_.at(bank_id).push(mem_req, 1); - DT(3, simobject_->name() << "-dram-" << mem_req); + DT(3, simobject_->name() << "-bank" << bank_id << " fill: " << mem_req); ++pending_fill_reqs_; } } diff --git a/sim/simx/cache_sim.h b/sim/simx/cache_sim.h index eacad86af..df62bf854 100644 --- a/sim/simx/cache_sim.h +++ b/sim/simx/cache_sim.h @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -30,12 +30,12 @@ public: uint8_t addr_width; // word address bits uint8_t ports_per_bank; // number of ports per bank uint8_t num_inputs; // number of inputs - bool write_through; // is write-through + bool write_back; // is write-back bool write_reponse; // enable write response uint16_t mshr_size; // MSHR buffer size uint8_t latency; // pipeline latency }; - + struct PerfStats { uint64_t reads; uint64_t writes; @@ -47,7 +47,7 @@ public: uint64_t mshr_stalls; uint64_t mem_latency; - PerfStats() + PerfStats() : reads(0) , writes(0) , read_misses(0) @@ -82,11 +82,11 @@ public: ~CacheSim(); void reset(); - + void tick(); const PerfStats& perf_stats() const; - + private: class Impl; Impl* impl_; diff --git a/sim/simx/cluster.cpp b/sim/simx/cluster.cpp index cb6c3c9d6..25669e26b 100644 --- a/sim/simx/cluster.cpp +++ b/sim/simx/cluster.cpp @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,11 +15,11 @@ using namespace vortex; -Cluster::Cluster(const SimContext& ctx, +Cluster::Cluster(const SimContext& ctx, uint32_t cluster_id, - ProcessorImpl* processor, - const Arch &arch, - const DCRS &dcrs) + ProcessorImpl* processor, + const Arch &arch, + const DCRS &dcrs) : SimObject(ctx, "cluster") , mem_req_port(this) , mem_rsp_port(this) @@ -43,9 +43,9 @@ Cluster::Cluster(const SimContext& ctx, for (uint32_t i = 0; i < sockets_per_cluster; ++i) { uint32_t socket_id = cluster_id * sockets_per_cluster + i; - auto socket = Socket::Create(socket_id, - this, - arch, + auto socket = Socket::Create(socket_id, + this, + arch, dcrs); socket->icache_mem_req_port.bind(&icache_switch->ReqIn.at(i)); @@ -58,7 +58,7 @@ Cluster::Cluster(const SimContext& ctx, } // Create l2cache - + snprintf(sname, 100, "cluster%d-l2cache", cluster_id); l2cache_ = CacheSim::Create(sname, CacheSim::Config{ !L2_ENABLED, @@ -67,10 +67,10 @@ Cluster::Cluster(const SimContext& ctx, log2ceil(L1_LINE_SIZE), // W log2ceil(L2_NUM_WAYS), // A log2ceil(L2_NUM_BANKS), // B - XLEN, // address bits + XLEN, // address bits 1, // number of ports - 2, // request size - true, // write-through + 2, // request size + L2_WRITEBACK, // write-back false, // write response L2_MSHR_SIZE, // mshr size 2, // pipeline latency @@ -90,7 +90,7 @@ Cluster::~Cluster() { //-- } -void Cluster::reset() { +void Cluster::reset() { for (auto& barrier : barriers_) { barrier.reset(); } diff --git a/sim/simx/constants.h b/sim/simx/constants.h index d72cafa17..09a509ce1 100644 --- a/sim/simx/constants.h +++ b/sim/simx/constants.h @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -14,15 +14,15 @@ #pragma once #ifndef RAM_PAGE_SIZE -#define RAM_PAGE_SIZE 4096 +#define RAM_PAGE_SIZE 4096 #endif -#ifndef MEM_CYCLE_RATIO -#define MEM_CYCLE_RATIO -1 +#ifndef MEM_CLOCK_RATIO +#define MEM_CLOCK_RATIO 1 #endif #ifndef MEMORY_BANKS -#define MEMORY_BANKS 2 +#define MEMORY_BANKS 2 #endif #define LSU_WORD_SIZE (XLEN / 8) @@ -31,4 +31,8 @@ #define DCACHE_WORD_SIZE LSU_LINE_SIZE #define DCACHE_CHANNELS UP((NUM_LSU_LANES * (XLEN / 8)) / DCACHE_WORD_SIZE) -#define DCACHE_NUM_REQS (NUM_LSU_BLOCKS * DCACHE_CHANNELS) \ No newline at end of file +#define DCACHE_NUM_REQS (NUM_LSU_BLOCKS * DCACHE_CHANNELS) + +#define NUM_SOCKETS UP(NUM_CORES / SOCKET_SIZE) + +#define PER_ISSUE_WARPS NUM_WARPS / ISSUE_WIDTH \ No newline at end of file diff --git a/sim/simx/core.cpp b/sim/simx/core.cpp index efaa19133..6f817a3ae 100644 --- a/sim/simx/core.cpp +++ b/sim/simx/core.cpp @@ -44,8 +44,10 @@ Core::Core(const SimContext& ctx, , operands_(ISSUE_WIDTH) , dispatchers_((uint32_t)FUType::Count) , func_units_((uint32_t)FUType::Count) - , lsu_demux_(LSU_NUM_REQS) + , lsu_demux_(NUM_LSU_BLOCKS) , mem_coalescers_(NUM_LSU_BLOCKS) + , lsu_dcache_adapter_(NUM_LSU_BLOCKS) + , lsu_lmem_adapter_(NUM_LSU_BLOCKS) , pending_icache_(arch_.num_warps()) , commit_arbs_(ISSUE_WIDTH) { @@ -72,31 +74,53 @@ Core::Core(const SimContext& ctx, }); // create lsu demux - for (uint32_t i = 0; i < LSU_NUM_REQS; ++i) { + for (uint32_t i = 0; i < NUM_LSU_BLOCKS; ++i) { snprintf(sname, 100, "core%d-lsu_demux%d", core_id, i); lsu_demux_.at(i) = LocalMemDemux::Create(sname, 1); } - // connect dcache-coalescer - for (uint32_t b = 0; b < NUM_LSU_BLOCKS; ++b) { - for (uint32_t c = 0; c < DCACHE_CHANNELS; ++c) { - uint32_t i = b * DCACHE_CHANNELS + c; - mem_coalescers_.at(b)->ReqOut.at(c).bind(&dcache_req_ports.at(i)); - dcache_rsp_ports.at(i).bind(&mem_coalescers_.at(b)->RspOut.at(c)); - } + // create lsu dcache adapter + for (uint32_t i = 0; i < NUM_LSU_BLOCKS; ++i) { + snprintf(sname, 100, "core%d-lsu_dcache_adapter%d", core_id, i); + lsu_dcache_adapter_.at(i) = LsuMemAdapter::Create(sname, DCACHE_CHANNELS, 1); + } + + // create lsu lmem adapter + for (uint32_t i = 0; i < NUM_LSU_BLOCKS; ++i) { + snprintf(sname, 100, "core%d-lsu_lmem_adapter%d", core_id, i); + lsu_lmem_adapter_.at(i) = LsuMemAdapter::Create(sname, LSU_CHANNELS, 1); } // connect lsu demux + for (uint32_t b = 0; b < NUM_LSU_BLOCKS; ++b) { + lsu_demux_.at(b)->ReqDC.bind(&mem_coalescers_.at(b)->ReqIn); + mem_coalescers_.at(b)->RspIn.bind(&lsu_demux_.at(b)->RspDC); + + lsu_demux_.at(b)->ReqLmem.bind(&lsu_lmem_adapter_.at(b)->ReqIn); + lsu_lmem_adapter_.at(b)->RspIn.bind(&lsu_demux_.at(b)->RspLmem); + } + + // connect coalescer-adapter + for (uint32_t b = 0; b < NUM_LSU_BLOCKS; ++b) { + mem_coalescers_.at(b)->ReqOut.bind(&lsu_dcache_adapter_.at(b)->ReqIn); + lsu_dcache_adapter_.at(b)->RspIn.bind(&mem_coalescers_.at(b)->RspOut); + } + + // connect adapter-dcache + for (uint32_t b = 0; b < NUM_LSU_BLOCKS; ++b) { + for (uint32_t c = 0; c < DCACHE_CHANNELS; ++c) { + uint32_t i = b * DCACHE_CHANNELS + c; + lsu_dcache_adapter_.at(b)->ReqOut.at(c).bind(&dcache_req_ports.at(i)); + dcache_rsp_ports.at(i).bind(&lsu_dcache_adapter_.at(b)->RspOut.at(c)); + } + } + + // connect adapter-lmem for (uint32_t b = 0; b < NUM_LSU_BLOCKS; ++b) { for (uint32_t c = 0; c < LSU_CHANNELS; ++c) { uint32_t i = b * LSU_CHANNELS + c; - auto lmem_demux = lsu_demux_.at(i); - - lmem_demux->ReqDC.bind(&mem_coalescers_.at(b)->ReqIn.at(c)); - mem_coalescers_.at(b)->RspIn.at(c).bind(&lmem_demux->RspDC); - - lmem_demux->ReqSM.bind(&local_mem_->Inputs.at(i)); - local_mem_->Outputs.at(i).bind(&lmem_demux->RspSM); + lsu_lmem_adapter_.at(b)->ReqOut.at(c).bind(&local_mem_->Inputs.at(i)); + local_mem_->Outputs.at(i).bind(&lsu_lmem_adapter_.at(b)->RspOut.at(c)); } } @@ -264,69 +288,72 @@ void Core::issue() { // issue ibuffer instructions for (uint32_t i = 0; i < ISSUE_WIDTH; ++i) { - uint32_t ii = (ibuffer_idx_ + i) % ibuffers_.size(); - auto& ibuffer = ibuffers_.at(ii); - if (ibuffer.empty()) - continue; - - auto trace = ibuffer.top(); - - // check scoreboard - if (scoreboard_.in_use(trace)) { - auto uses = scoreboard_.get_uses(trace); - if (!trace->log_once(true)) { - DTH(4, "*** scoreboard-stall: dependents={"); + bool has_instrs = false; + bool found_match = false; + for (uint32_t w = 0; w < PER_ISSUE_WARPS; ++w) { + uint32_t kk = (ibuffer_idx_ + w) % PER_ISSUE_WARPS; + uint32_t ii = kk * ISSUE_WIDTH + i; + auto& ibuffer = ibuffers_.at(ii); + if (ibuffer.empty()) + continue; + // check scoreboard + has_instrs = true; + auto trace = ibuffer.top(); + if (scoreboard_.in_use(trace)) { + auto uses = scoreboard_.get_uses(trace); + if (!trace->log_once(true)) { + DTH(4, "*** scoreboard-stall: dependents={"); + for (uint32_t j = 0, n = uses.size(); j < n; ++j) { + auto& use = uses.at(j); + __unused (use); + if (j) DTN(4, ", "); + DTN(4, use.reg_type << use.reg_id << "(#" << use.uuid << ")"); + } + DTN(4, "}, " << *trace << std::endl); + } for (uint32_t j = 0, n = uses.size(); j < n; ++j) { auto& use = uses.at(j); - __unused (use); - if (j) DTN(4, ", "); - DTN(4, use.reg_type << use.reg_id << "(#" << use.uuid << ")"); - } - DTN(4, "}, " << *trace << std::endl); - } - for (uint32_t j = 0, n = uses.size(); j < n; ++j) { - auto& use = uses.at(j); - switch (use.fu_type) { - case FUType::ALU: ++perf_stats_.scrb_alu; break; - case FUType::FPU: ++perf_stats_.scrb_fpu; break; - case FUType::LSU: ++perf_stats_.scrb_lsu; break; - case FUType::SFU: { - ++perf_stats_.scrb_sfu; - switch (use.sfu_type) { - case SfuType::TMC: - case SfuType::WSPAWN: - case SfuType::SPLIT: - case SfuType::JOIN: - case SfuType::BAR: - case SfuType::PRED: ++perf_stats_.scrb_wctl; break; - case SfuType::CSRRW: - case SfuType::CSRRS: - case SfuType::CSRRC: ++perf_stats_.scrb_csrs; break; + switch (use.fu_type) { + case FUType::ALU: ++perf_stats_.scrb_alu; break; + case FUType::FPU: ++perf_stats_.scrb_fpu; break; + case FUType::LSU: ++perf_stats_.scrb_lsu; break; + case FUType::SFU: { + ++perf_stats_.scrb_sfu; + switch (use.sfu_type) { + case SfuType::TMC: + case SfuType::WSPAWN: + case SfuType::SPLIT: + case SfuType::JOIN: + case SfuType::BAR: + case SfuType::PRED: ++perf_stats_.scrb_wctl; break; + case SfuType::CSRRW: + case SfuType::CSRRS: + case SfuType::CSRRC: ++perf_stats_.scrb_csrs; break; + default: assert(false); + } + } break; default: assert(false); } - } break; - default: assert(false); } + } else { + trace->log_once(false); + // update scoreboard + DT(3, "pipeline-scoreboard: " << *trace); + if (trace->wb) { + scoreboard_.reserve(trace); + } + // to operand stage + operands_.at(i)->Input.push(trace, 2); + ibuffer.pop(); + found_match = true; + break; } + } + if (has_instrs && !found_match) { ++perf_stats_.scrb_stalls; - continue; - } else { - trace->log_once(false); } - - // update scoreboard - if (trace->wb) { - scoreboard_.reserve(trace); - } - - DT(3, "pipeline-scoreboard: " << *trace); - - // to operand stage - operands_.at(i)->Input.push(trace, 1); - - ibuffer.pop(); } - ibuffer_idx_ += ISSUE_WIDTH; + ++ibuffer_idx_; } void Core::execute() { @@ -337,7 +364,7 @@ void Core::execute() { if (dispatch->Outputs.at(j).empty()) continue; auto trace = dispatch->Outputs.at(j).front(); - func_unit->Inputs.at(j).push(trace, 1); + func_unit->Inputs.at(j).push(trace, 2); dispatch->Outputs.at(j).pop(); } } @@ -366,6 +393,11 @@ void Core::commit() { perf_stats_.instrs += trace->tmask.count(); } + perf_stats_.opds_stalls = 0; + for (uint32_t i = 0; i < ISSUE_WIDTH; ++i) { + perf_stats_.opds_stalls += operands_.at(i)->total_stalls(); + } + commit_arb->Outputs.at(0).pop(); // delete the trace diff --git a/sim/simx/core.h b/sim/simx/core.h index 42f72e552..339d76fb8 100644 --- a/sim/simx/core.h +++ b/sim/simx/core.h @@ -45,12 +45,13 @@ public: uint64_t sched_stalls; uint64_t ibuf_stalls; uint64_t scrb_stalls; + uint64_t opds_stalls; uint64_t scrb_alu; uint64_t scrb_fpu; uint64_t scrb_lsu; uint64_t scrb_sfu; - uint64_t scrb_wctl; uint64_t scrb_csrs; + uint64_t scrb_wctl; uint64_t ifetches; uint64_t loads; uint64_t stores; @@ -64,12 +65,13 @@ public: , sched_stalls(0) , ibuf_stalls(0) , scrb_stalls(0) + , opds_stalls(0) , scrb_alu(0) , scrb_fpu(0) , scrb_lsu(0) , scrb_sfu(0) - , scrb_wctl(0) , scrb_csrs(0) + , scrb_wctl(0) , ifetches(0) , loads(0) , stores(0) @@ -154,6 +156,8 @@ private: LocalMem::Ptr local_mem_; std::vector lsu_demux_; std::vector mem_coalescers_; + std::vector lsu_dcache_adapter_; + std::vector lsu_lmem_adapter_; PipelineLatch fetch_latch_; PipelineLatch decode_latch_; diff --git a/sim/simx/decode.cpp b/sim/simx/decode.cpp index f934524c3..6cefe378f 100644 --- a/sim/simx/decode.cpp +++ b/sim/simx/decode.cpp @@ -623,7 +623,7 @@ std::shared_ptr Emulator::decode(uint32_t code) const { instr->setDestReg(rd, RegType::Integer); auto imm = (code >> shift_func3) << shift_func3; instr->setImm(imm); - } break; + } break; case InstType::J: { instr->setDestReg(rd, RegType::Integer); diff --git a/sim/simx/emulator.cpp b/sim/simx/emulator.cpp index 9e96bef2f..503e21cd9 100644 --- a/sim/simx/emulator.cpp +++ b/sim/simx/emulator.cpp @@ -42,8 +42,8 @@ Emulator::ipdom_entry_t::ipdom_entry_t(const ThreadMask &tmask) {} Emulator::warp_t::warp_t(const Arch& arch) - : ireg_file(arch.num_threads(), std::vector(arch.num_regs())) - , freg_file(arch.num_threads(), std::vector(arch.num_regs())) + : ireg_file(arch.num_threads(), std::vector(MAX_NUM_REGS)) + , freg_file(arch.num_threads(), std::vector(MAX_NUM_REGS)) , uuid(0) {} @@ -74,6 +74,7 @@ Emulator::Emulator(const Arch &arch, const DCRS &dcrs, Core* core) , core_(core) , warps_(arch.num_warps(), arch) , barriers_(arch.num_barriers(), 0) + , ipdom_size_((arch.num_threads()-1) * 2) { this->clear(); } @@ -186,7 +187,7 @@ instr_trace_t* Emulator::step() { this->execute(*instr, scheduled_warp, trace); DP(5, "Register state:"); - for (uint32_t i = 0; i < arch_.num_regs(); ++i) { + for (uint32_t i = 0; i < MAX_NUM_REGS; ++i) { DPN(5, " %r" << std::setfill('0') << std::setw(2) << std::dec << i << ':'); // Integer register file for (uint32_t j = 0; j < arch_.num_threads(); ++j) { @@ -467,12 +468,13 @@ Word Emulator::get_csr(uint32_t addr, uint32_t tid, uint32_t wid) { CSR_READ_64(VX_CSR_MPM_SCHED_ST, core_perf.sched_stalls); CSR_READ_64(VX_CSR_MPM_IBUF_ST, core_perf.ibuf_stalls); CSR_READ_64(VX_CSR_MPM_SCRB_ST, core_perf.scrb_stalls); + CSR_READ_64(VX_CSR_MPM_OPDS_ST, core_perf.opds_stalls); CSR_READ_64(VX_CSR_MPM_SCRB_ALU, core_perf.scrb_alu); CSR_READ_64(VX_CSR_MPM_SCRB_FPU, core_perf.scrb_fpu); CSR_READ_64(VX_CSR_MPM_SCRB_LSU, core_perf.scrb_lsu); CSR_READ_64(VX_CSR_MPM_SCRB_SFU, core_perf.scrb_sfu); - CSR_READ_64(VX_CSR_MPM_SCRB_WCTL, core_perf.scrb_wctl); CSR_READ_64(VX_CSR_MPM_SCRB_CSRS, core_perf.scrb_csrs); + CSR_READ_64(VX_CSR_MPM_SCRB_WCTL, core_perf.scrb_wctl); CSR_READ_64(VX_CSR_MPM_IFETCHES, core_perf.ifetches); CSR_READ_64(VX_CSR_MPM_LOADS, core_perf.loads); CSR_READ_64(VX_CSR_MPM_STORES, core_perf.stores); diff --git a/sim/simx/emulator.h b/sim/simx/emulator.h index 47744c6d5..0b2d6ac03 100644 --- a/sim/simx/emulator.h +++ b/sim/simx/emulator.h @@ -122,6 +122,7 @@ private: std::vector barriers_; std::unordered_map print_bufs_; MemoryUnit mmu_; + uint32_t ipdom_size_; Word csr_mscratch_; wspawn_t wspawn_; }; diff --git a/sim/simx/execute.cpp b/sim/simx/execute.cpp index e0fc2b94a..a037d995c 100644 --- a/sim/simx/execute.cpp +++ b/sim/simx/execute.cpp @@ -63,8 +63,7 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { trace->wid = wid; trace->PC = warp.PC; trace->tmask = warp.tmask; - trace->rdest = instr.getRDest(); - trace->rdest_type = instr.getRDType(); + trace->dst_reg = {instr.getRDType(), instr.getRDest()}; auto next_pc = warp.PC + 4; auto next_tmask = warp.tmask; @@ -128,7 +127,7 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { } DPN(2, "}" << std::endl); break; - case RegType::None: + default: break; } } @@ -164,8 +163,8 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { case Opcode::R: { trace->fu_type = FUType::ALU; trace->alu_type = AluType::ARITH; - trace->used_iregs.set(rsrc0); - trace->used_iregs.set(rsrc1); + trace->src_regs[0] = {RegType::Integer, rsrc0}; + trace->src_regs[1] = {RegType::Integer, rsrc1}; for (uint32_t t = thread_start; t < num_threads; ++t) { if (!warp.tmask.test(t)) continue; @@ -341,7 +340,7 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { case Opcode::I: { trace->fu_type = FUType::ALU; trace->alu_type = AluType::ARITH; - trace->used_iregs.set(rsrc0); + trace->src_regs[0] = {RegType::Integer, rsrc0}; for (uint32_t t = thread_start; t < num_threads; ++t) { if (!warp.tmask.test(t)) continue; @@ -401,8 +400,8 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { case Opcode::R_W: { trace->fu_type = FUType::ALU; trace->alu_type = AluType::ARITH; - trace->used_iregs.set(rsrc0); - trace->used_iregs.set(rsrc1); + trace->src_regs[0] = {RegType::Integer, rsrc0}; + trace->src_regs[1] = {RegType::Integer, rsrc1}; for (uint32_t t = thread_start; t < num_threads; ++t) { if (!warp.tmask.test(t)) continue; @@ -528,7 +527,7 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { case Opcode::I_W: { trace->fu_type = FUType::ALU; trace->alu_type = AluType::ARITH; - trace->used_iregs.set(rsrc0); + trace->src_regs[0] = {RegType::Integer, rsrc0}; for (uint32_t t = thread_start; t < num_threads; ++t) { if (!warp.tmask.test(t)) continue; @@ -571,8 +570,8 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { case Opcode::B: { trace->fu_type = FUType::ALU; trace->alu_type = AluType::BRANCH; - trace->used_iregs.set(rsrc0); - trace->used_iregs.set(rsrc1); + trace->src_regs[0] = {RegType::Integer, rsrc0}; + trace->src_regs[1] = {RegType::Integer, rsrc1}; bool all_taken = false; for (uint32_t t = thread_start; t < num_threads; ++t) { if (!warp.tmask.test(t)) @@ -660,7 +659,7 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { // RV32I: JALR trace->fu_type = FUType::ALU; trace->alu_type = AluType::BRANCH; - trace->used_iregs.set(rsrc0); + trace->src_regs[0] = {RegType::Integer, rsrc0}; for (uint32_t t = thread_start; t < num_threads; ++t) { if (!warp.tmask.test(t)) continue; @@ -675,7 +674,7 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { case Opcode::FL: { trace->fu_type = FUType::LSU; trace->lsu_type = LsuType::LOAD; - trace->used_iregs.set(rsrc0); + trace->src_regs[0] = {RegType::Integer, rsrc0}; auto trace_data = std::make_shared(num_threads); trace->data = trace_data; uint32_t data_bytes = 1 << (func3 & 0x3); @@ -719,8 +718,9 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { case Opcode::FS: { trace->fu_type = FUType::LSU; trace->lsu_type = LsuType::STORE; - trace->used_iregs.set(rsrc0); - trace->used_iregs.set(rsrc1); + auto data_type = (opcode == Opcode::FS) ? RegType::Float : RegType::Integer; + trace->src_regs[0] = {RegType::Integer, rsrc0}; + trace->src_regs[1] = {data_type, rsrc1}; auto trace_data = std::make_shared(num_threads); trace->data = trace_data; uint32_t data_bytes = 1 << (func3 & 0x3); @@ -746,8 +746,8 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { case Opcode::AMO: { trace->fu_type = FUType::LSU; trace->lsu_type = LsuType::LOAD; - trace->used_iregs.set(rsrc0); - trace->used_iregs.set(rsrc1); + trace->src_regs[0] = {RegType::Integer, rsrc0}; + trace->src_regs[1] = {RegType::Integer, rsrc1}; auto trace_data = std::make_shared(num_threads); trace->data = trace_data; auto amo_type = func7 >> 2; @@ -839,14 +839,15 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { } } else { trace->fu_type = FUType::SFU; - trace->fetch_stall = true; + // stall the fetch stage for FPU CSRs + trace->fetch_stall = (csr_addr <= VX_CSR_FCSR); csr_value = this->get_csr(csr_addr, t, wid); switch (func3) { case 1: { // RV32I: CSRRW rddata[t].i = csr_value; this->set_csr(csr_addr, rsdata[t][0].i, t, wid); - trace->used_iregs.set(rsrc0); + trace->src_regs[0] = {RegType::Integer, rsrc0}; trace->sfu_type = SfuType::CSRRW; rd_write = true; break; @@ -857,7 +858,7 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { if (rsdata[t][0].i != 0) { this->set_csr(csr_addr, csr_value | rsdata[t][0].i, t, wid); } - trace->used_iregs.set(rsrc0); + trace->src_regs[0] = {RegType::Integer, rsrc0}; trace->sfu_type = SfuType::CSRRS; rd_write = true; break; @@ -868,7 +869,7 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { if (rsdata[t][0].i != 0) { this->set_csr(csr_addr, csr_value & ~rsdata[t][0].i, t, wid); } - trace->used_iregs.set(rsrc0); + trace->src_regs[0] = {RegType::Integer, rsrc0}; trace->sfu_type = SfuType::CSRRC; rd_write = true; break; @@ -925,57 +926,57 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { case 0x00: { // RV32F: FADD.S rddata[t].u64 = nan_box(rv_fadd_s(check_boxing(rsdata[t][0].u64), check_boxing(rsdata[t][1].u64), frm, &fflags)); trace->fpu_type = FpuType::FMA; - trace->used_fregs.set(rsrc0); - trace->used_fregs.set(rsrc1); + trace->src_regs[0] = {RegType::Float, rsrc0}; + trace->src_regs[1] = {RegType::Float, rsrc1}; break; } case 0x01: { // RV32D: FADD.D rddata[t].u64 = rv_fadd_d(rsdata[t][0].u64, rsdata[t][1].u64, frm, &fflags); trace->fpu_type = FpuType::FMA; - trace->used_fregs.set(rsrc0); - trace->used_fregs.set(rsrc1); + trace->src_regs[0] = {RegType::Float, rsrc0}; + trace->src_regs[1] = {RegType::Float, rsrc1}; break; } case 0x04: { // RV32F: FSUB.S rddata[t].u64 = nan_box(rv_fsub_s(check_boxing(rsdata[t][0].u64), check_boxing(rsdata[t][1].u64), frm, &fflags)); trace->fpu_type = FpuType::FMA; - trace->used_fregs.set(rsrc0); - trace->used_fregs.set(rsrc1); + trace->src_regs[0] = {RegType::Float, rsrc0}; + trace->src_regs[1] = {RegType::Float, rsrc1}; break; } case 0x05: { // RV32D: FSUB.D rddata[t].u64 = rv_fsub_d(rsdata[t][0].u64, rsdata[t][1].u64, frm, &fflags); trace->fpu_type = FpuType::FMA; - trace->used_fregs.set(rsrc0); - trace->used_fregs.set(rsrc1); + trace->src_regs[0] = {RegType::Float, rsrc0}; + trace->src_regs[1] = {RegType::Float, rsrc1}; break; } case 0x08: { // RV32F: FMUL.S rddata[t].u64 = nan_box(rv_fmul_s(check_boxing(rsdata[t][0].u64), check_boxing(rsdata[t][1].u64), frm, &fflags)); trace->fpu_type = FpuType::FMA; - trace->used_fregs.set(rsrc0); - trace->used_fregs.set(rsrc1); + trace->src_regs[0] = {RegType::Float, rsrc0}; + trace->src_regs[1] = {RegType::Float, rsrc1}; break; } case 0x09: { // RV32D: FMUL.D rddata[t].u64 = rv_fmul_d(rsdata[t][0].u64, rsdata[t][1].u64, frm, &fflags); trace->fpu_type = FpuType::FMA; - trace->used_fregs.set(rsrc0); - trace->used_fregs.set(rsrc1); + trace->src_regs[0] = {RegType::Float, rsrc0}; + trace->src_regs[1] = {RegType::Float, rsrc1}; break; } case 0x0c: { // RV32F: FDIV.S rddata[t].u64 = nan_box(rv_fdiv_s(check_boxing(rsdata[t][0].u64), check_boxing(rsdata[t][1].u64), frm, &fflags)); trace->fpu_type = FpuType::FDIV; - trace->used_fregs.set(rsrc0); - trace->used_fregs.set(rsrc1); + trace->src_regs[0] = {RegType::Float, rsrc0}; + trace->src_regs[1] = {RegType::Float, rsrc1}; break; } case 0x0d: { // RV32D: FDIV.D rddata[t].u64 = rv_fdiv_d(rsdata[t][0].u64, rsdata[t][1].u64, frm, &fflags); trace->fpu_type = FpuType::FDIV; - trace->used_fregs.set(rsrc0); - trace->used_fregs.set(rsrc1); + trace->src_regs[0] = {RegType::Float, rsrc0}; + trace->src_regs[1] = {RegType::Float, rsrc1}; break; } case 0x10: { @@ -991,8 +992,8 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { break; } trace->fpu_type = FpuType::FNCP; - trace->used_fregs.set(rsrc0); - trace->used_fregs.set(rsrc1); + trace->src_regs[0] = {RegType::Float, rsrc0}; + trace->src_regs[1] = {RegType::Float, rsrc1}; break; } case 0x11: { @@ -1008,8 +1009,8 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { break; } trace->fpu_type = FpuType::FNCP; - trace->used_fregs.set(rsrc0); - trace->used_fregs.set(rsrc1); + trace->src_regs[0] = {RegType::Float, rsrc0}; + trace->src_regs[1] = {RegType::Float, rsrc1}; break; } case 0x14: { @@ -1021,8 +1022,8 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { rddata[t].u64 = nan_box(rv_fmin_s(check_boxing(rsdata[t][0].u64), check_boxing(rsdata[t][1].u64), &fflags)); } trace->fpu_type = FpuType::FNCP; - trace->used_fregs.set(rsrc0); - trace->used_fregs.set(rsrc1); + trace->src_regs[0] = {RegType::Float, rsrc0}; + trace->src_regs[1] = {RegType::Float, rsrc1}; break; } case 0x15: { @@ -1034,34 +1035,34 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { rddata[t].u64 = rv_fmin_d(rsdata[t][0].u64, rsdata[t][1].u64, &fflags); } trace->fpu_type = FpuType::FNCP; - trace->used_fregs.set(rsrc0); - trace->used_fregs.set(rsrc1); + trace->src_regs[0] = {RegType::Float, rsrc0}; + trace->src_regs[1] = {RegType::Float, rsrc1}; break; } case 0x20: { // RV32D: FCVT.S.D rddata[t].u64 = nan_box(rv_dtof(rsdata[t][0].u64)); trace->fpu_type = FpuType::FNCP; - trace->used_fregs.set(rsrc0); + trace->src_regs[0] = {RegType::Float, rsrc0}; break; } case 0x21: { // RV32D: FCVT.D.S rddata[t].u64 = rv_ftod(check_boxing(rsdata[t][0].u64)); trace->fpu_type = FpuType::FNCP; - trace->used_fregs.set(rsrc0); + trace->src_regs[0] = {RegType::Float, rsrc0}; break; } case 0x2c: { // RV32F: FSQRT.S rddata[t].u64 = nan_box(rv_fsqrt_s(check_boxing(rsdata[t][0].u64), frm, &fflags)); trace->fpu_type = FpuType::FSQRT; - trace->used_fregs.set(rsrc0); + trace->src_regs[0] = {RegType::Float, rsrc0}; break; } case 0x2d: { // RV32D: FSQRT.D rddata[t].u64 = rv_fsqrt_d(rsdata[t][0].u64, frm, &fflags); trace->fpu_type = FpuType::FSQRT; - trace->used_fregs.set(rsrc0); + trace->src_regs[0] = {RegType::Float, rsrc0}; break; } case 0x50: { @@ -1080,8 +1081,8 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { break; } trace->fpu_type = FpuType::FNCP; - trace->used_fregs.set(rsrc0); - trace->used_fregs.set(rsrc1); + trace->src_regs[0] = {RegType::Float, rsrc0}; + trace->src_regs[1] = {RegType::Float, rsrc1}; break; } case 0x51: { @@ -1100,8 +1101,8 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { break; } trace->fpu_type = FpuType::FNCP; - trace->used_fregs.set(rsrc0); - trace->used_fregs.set(rsrc1); + trace->src_regs[0] = {RegType::Float, rsrc0}; + trace->src_regs[1] = {RegType::Float, rsrc1}; break; } case 0x60: { @@ -1124,7 +1125,7 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { break; } trace->fpu_type = FpuType::FCVT; - trace->used_fregs.set(rsrc0); + trace->src_regs[0] = {RegType::Float, rsrc0}; break; } case 0x61: { @@ -1147,7 +1148,7 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { break; } trace->fpu_type = FpuType::FCVT; - trace->used_fregs.set(rsrc0); + trace->src_regs[0] = {RegType::Float, rsrc0}; break; } case 0x68: { @@ -1170,7 +1171,7 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { break; } trace->fpu_type = FpuType::FCVT; - trace->used_iregs.set(rsrc0); + trace->src_regs[0] = {RegType::Integer, rsrc0}; break; } case 0x69: { @@ -1193,7 +1194,7 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { break; } trace->fpu_type = FpuType::FCVT; - trace->used_iregs.set(rsrc0); + trace->src_regs[0] = {RegType::Integer, rsrc0}; break; } case 0x70: { @@ -1206,7 +1207,7 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { rddata[t].i = sext((uint64_t)result, 32); } trace->fpu_type = FpuType::FNCP; - trace->used_fregs.set(rsrc0); + trace->src_regs[0] = {RegType::Float, rsrc0}; break; } case 0x71: { @@ -1218,19 +1219,19 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { rddata[t].i = rsdata[t][0].u64; } trace->fpu_type = FpuType::FNCP; - trace->used_fregs.set(rsrc0); + trace->src_regs[0] = {RegType::Float, rsrc0}; break; } case 0x78: { // RV32F: FMV.S.X rddata[t].u64 = nan_box((uint32_t)rsdata[t][0].i); trace->fpu_type = FpuType::FNCP; - trace->used_iregs.set(rsrc0); + trace->src_regs[0] = {RegType::Integer, rsrc0}; break; } case 0x79: { // RV64D: FMV.D.X rddata[t].u64 = rsdata[t][0].i; trace->fpu_type = FpuType::FNCP; - trace->used_iregs.set(rsrc0); + trace->src_regs[0] = {RegType::Integer, rsrc0}; break; } } @@ -1244,9 +1245,9 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { case Opcode::FMNMADD: case Opcode::FMNMSUB: { trace->fpu_type = FpuType::FMA; - trace->used_fregs.set(rsrc0); - trace->used_fregs.set(rsrc1); - trace->used_fregs.set(rsrc2); + trace->src_regs[0] = {RegType::Float, rsrc0}; + trace->src_regs[1] = {RegType::Float, rsrc1}; + trace->src_regs[2] = {RegType::Float, rsrc2}; for (uint32_t t = thread_start; t < num_threads; ++t) { if (!warp.tmask.test(t)) continue; @@ -1301,7 +1302,7 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { // TMC trace->fu_type = FUType::SFU; trace->sfu_type = SfuType::TMC; - trace->used_iregs.set(rsrc0); + trace->src_regs[0] = {RegType::Integer, rsrc0}; trace->fetch_stall = true; next_tmask.reset(); for (uint32_t t = 0; t < num_threads; ++t) { @@ -1312,8 +1313,8 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { // WSPAWN trace->fu_type = FUType::SFU; trace->sfu_type = SfuType::WSPAWN; - trace->used_iregs.set(rsrc0); - trace->used_iregs.set(rsrc1); + trace->src_regs[0] = {RegType::Integer, rsrc0}; + trace->src_regs[1] = {RegType::Integer, rsrc1}; trace->fetch_stall = true; trace->data = std::make_shared(rsdata.at(thread_last)[0].i, rsdata.at(thread_last)[1].i); } break; @@ -1321,7 +1322,7 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { // SPLIT trace->fu_type = FUType::SFU; trace->sfu_type = SfuType::SPLIT; - trace->used_iregs.set(rsrc0); + trace->src_regs[0] = {RegType::Integer, rsrc0}; trace->fetch_stall = true; auto stack_size = warp.ipdom_stack.size(); @@ -1336,7 +1337,7 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { bool is_divergent = then_tmask.any() && else_tmask.any(); if (is_divergent) { - if (stack_size == arch_.ipdom_size()) { + if (stack_size == ipdom_size_) { std::cout << "IPDOM stack is full! size=" << std::dec << stack_size << ", PC=0x" << std::hex << warp.PC << " (#" << std::dec << trace->uuid << ")\n" << std::flush; std::abort(); } @@ -1362,7 +1363,7 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { // JOIN trace->fu_type = FUType::SFU; trace->sfu_type = SfuType::JOIN; - trace->used_iregs.set(rsrc0); + trace->src_regs[0] = {RegType::Integer, rsrc0}; trace->fetch_stall = true; auto stack_ptr = warp.ireg_file.at(thread_last).at(rsrc0); @@ -1382,8 +1383,8 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { // BAR trace->fu_type = FUType::SFU; trace->sfu_type = SfuType::BAR; - trace->used_iregs.set(rsrc0); - trace->used_iregs.set(rsrc1); + trace->src_regs[0] = {RegType::Integer, rsrc0}; + trace->src_regs[1] = {RegType::Integer, rsrc1}; trace->fetch_stall = true; trace->data = std::make_shared(rsdata[thread_last][0].i, rsdata[thread_last][1].i); } break; @@ -1391,8 +1392,8 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { // PRED trace->fu_type = FUType::SFU; trace->sfu_type = SfuType::PRED; - trace->used_iregs.set(rsrc0); - trace->used_iregs.set(rsrc1); + trace->src_regs[0] = {RegType::Integer, rsrc0}; + trace->src_regs[1] = {RegType::Integer, rsrc1}; trace->fetch_stall = true; ThreadMask pred; auto not_pred = rdest & 0x1; @@ -1435,7 +1436,7 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { DPN(2, "0x" << std::hex << rddata[t].i); } DPN(2, "}" << std::endl); - trace->used_iregs[rdest] = 1; + trace->dst_reg = {type, rdest}; assert(rdest != 0); } else { // disable writes to x0 @@ -1454,7 +1455,7 @@ void Emulator::execute(const Instr &instr, uint32_t wid, instr_trace_t *trace) { DPN(2, "0x" << std::hex << rddata[t].f); } DPN(2, "}" << std::endl); - trace->used_fregs[rdest] = 1; + trace->dst_reg = {type, rdest}; break; default: std::abort(); diff --git a/sim/simx/func_unit.cpp b/sim/simx/func_unit.cpp index c9a3f0fc7..b03551e08 100644 --- a/sim/simx/func_unit.cpp +++ b/sim/simx/func_unit.cpp @@ -24,7 +24,7 @@ using namespace vortex; -AluUnit::AluUnit(const SimContext& ctx, Core* core) : FuncUnit(ctx, core, "ALU") {} +AluUnit::AluUnit(const SimContext& ctx, Core* core) : FuncUnit(ctx, core, "alu-unit") {} void AluUnit::tick() { for (uint32_t iw = 0; iw < ISSUE_WIDTH; ++iw) { @@ -33,20 +33,23 @@ void AluUnit::tick() { continue; auto& output = Outputs.at(iw); auto trace = input.front(); + int delay = 2; switch (trace->alu_type) { case AluType::ARITH: case AluType::BRANCH: case AluType::SYSCALL: + output.push(trace, 2+delay); + break; case AluType::IMUL: - output.push(trace, LATENCY_IMUL+1); + output.push(trace, LATENCY_IMUL+delay); break; case AluType::IDIV: - output.push(trace, XLEN+1); + output.push(trace, XLEN+delay); break; default: std::abort(); } - DT(3, "pipeline-execute: op=" << trace->alu_type << ", " << *trace); + DT(3, this->name() << ": op=" << trace->alu_type << ", " << *trace); if (trace->eop && trace->fetch_stall) { core_->resume(trace->wid); } @@ -56,7 +59,7 @@ void AluUnit::tick() { /////////////////////////////////////////////////////////////////////////////// -FpuUnit::FpuUnit(const SimContext& ctx, Core* core) : FuncUnit(ctx, core, "FPU") {} +FpuUnit::FpuUnit(const SimContext& ctx, Core* core) : FuncUnit(ctx, core, "fpu-unit") {} void FpuUnit::tick() { for (uint32_t iw = 0; iw < ISSUE_WIDTH; ++iw) { @@ -65,26 +68,27 @@ void FpuUnit::tick() { continue; auto& output = Outputs.at(iw); auto trace = input.front(); + int delay = 2; switch (trace->fpu_type) { case FpuType::FNCP: - output.push(trace, 2); + output.push(trace, 2+delay); break; case FpuType::FMA: - output.push(trace, LATENCY_FMA+1); + output.push(trace, LATENCY_FMA+delay); break; case FpuType::FDIV: - output.push(trace, LATENCY_FDIV+1); + output.push(trace, LATENCY_FDIV+delay); break; case FpuType::FSQRT: - output.push(trace, LATENCY_FSQRT+1); + output.push(trace, LATENCY_FSQRT+delay); break; case FpuType::FCVT: - output.push(trace, LATENCY_FCVT+1); + output.push(trace, LATENCY_FCVT+delay); break; default: std::abort(); } - DT(3, "pipeline-execute: op=" << trace->fpu_type << ", " << *trace); + DT(3,this->name() << ": op=" << trace->fpu_type << ", " << *trace); input.pop(); } } @@ -92,7 +96,7 @@ void FpuUnit::tick() { /////////////////////////////////////////////////////////////////////////////// LsuUnit::LsuUnit(const SimContext& ctx, Core* core) - : FuncUnit(ctx, core, "LSU") + : FuncUnit(ctx, core, "lsu-unit") , pending_loads_(0) {} @@ -110,25 +114,25 @@ void LsuUnit::tick() { core_->perf_stats_.load_latency += pending_loads_; // handle memory responses - for (uint32_t r = 0; r < LSU_NUM_REQS; ++r) { - auto& dcache_rsp_port = core_->lsu_demux_.at(r)->RspIn; - if (dcache_rsp_port.empty()) + for (uint32_t b = 0; b < NUM_LSU_BLOCKS; ++b) { + auto& lsu_rsp_port = core_->lsu_demux_.at(b)->RspIn; + if (lsu_rsp_port.empty()) continue; - uint32_t block_idx = r / LSU_CHANNELS; - auto& state = states_.at(block_idx); - auto& mem_rsp = dcache_rsp_port.front(); - auto& entry = state.pending_rd_reqs.at(mem_rsp.tag); + auto& state = states_.at(b); + auto& lsu_rsp = lsu_rsp_port.front(); + DT(3, this->name() << " mem-rsp: " << lsu_rsp); + auto& entry = state.pending_rd_reqs.at(lsu_rsp.tag); auto trace = entry.trace; - DT(3, "mem-rsp: tag=" << mem_rsp.tag << ", type=" << trace->lsu_type << ", rid=" << r << ", " << *trace); - assert(entry.count); - --entry.count; // track remaining addresses - if (0 == entry.count) { + assert(!entry.mask.none()); + entry.mask &= ~lsu_rsp.mask; // track remaining + if (entry.mask.none()) { + // whole response received, release trace int iw = trace->wid % ISSUE_WIDTH; Outputs.at(iw).push(trace, 1); - state.pending_rd_reqs.release(mem_rsp.tag); + state.pending_rd_reqs.release(lsu_rsp.tag); } - dcache_rsp_port.pop(); - --pending_loads_; + pending_loads_ -= lsu_rsp.mask.count(); + lsu_rsp_port.pop(); } // handle LSU requests @@ -141,7 +145,7 @@ void LsuUnit::tick() { continue; Outputs.at(iw).push(state.fence_trace, 1); state.fence_lock = false; - DT(3, "fence-unlock: " << state.fence_trace); + DT(3, this->name() << " fence-unlock: " << state.fence_trace); } // check input queue @@ -149,14 +153,13 @@ void LsuUnit::tick() { if (input.empty()) continue; - auto& output = Outputs.at(iw); auto trace = input.front(); if (trace->lsu_type == LsuType::FENCE) { // schedule fence lock state.fence_trace = trace; state.fence_lock = true; - DT(3, "fence-lock: " << *trace); + DT(3, this->name() << " fence-lock: " << *trace); // remove input input.pop(); continue; @@ -167,28 +170,50 @@ void LsuUnit::tick() { // check pending queue capacity if (!is_write && state.pending_rd_reqs.full()) { if (!trace->log_once(true)) { - DT(4, "*** " << this->name() << "-queue-full: " << *trace); + DT(4, "*** " << this->name() << " queue-full: " << *trace); } continue; } else { trace->log_once(false); } + // build memory request + LsuReq lsu_req(NUM_LSU_LANES); + lsu_req.write = is_write; + { + auto trace_data = std::dynamic_pointer_cast(trace->data); + auto t0 = trace->pid * NUM_LSU_LANES; + for (uint32_t i = 0; i < NUM_LSU_LANES; ++i) { + if (trace->tmask.test(t0 + i)) { + lsu_req.mask.set(i); + lsu_req.addrs.at(i) = trace_data->mem_addrs.at(t0 + i).addr; + } + } + } uint32_t tag = 0; if (!is_write) { - tag = state.pending_rd_reqs.allocate({trace, 0}); + tag = state.pending_rd_reqs.allocate({trace, lsu_req.mask}); } + lsu_req.tag = tag; + lsu_req.cid = trace->cid; + lsu_req.uuid = trace->uuid; // send memory request - auto num_reqs = this->send_requests(trace, block_idx, tag); + core_->lsu_demux_.at(block_idx)->ReqIn.push(lsu_req); + DT(3, this->name() << " mem-req: " << lsu_req); - if (!is_write) { - state.pending_rd_reqs.at(tag).count = num_reqs; + // update stats + auto num_addrs = lsu_req.mask.count(); + if (is_write) { + core_->perf_stats_.stores += num_addrs; + } else { + core_->perf_stats_.loads += num_addrs; + pending_loads_ += num_addrs; } // do not wait on writes if (is_write) { - output.push(trace, 1); + Outputs.at(iw).push(trace, 1); } // remove input @@ -196,52 +221,10 @@ void LsuUnit::tick() { } } -int LsuUnit::send_requests(instr_trace_t* trace, int block_idx, int tag) { - int count = 0; - - auto trace_data = std::dynamic_pointer_cast(trace->data); - bool is_write = (trace->lsu_type == LsuType::STORE); - auto t0 = trace->pid * NUM_LSU_LANES; - - for (uint32_t i = 0; i < NUM_LSU_LANES; ++i) { - uint32_t t = t0 + i; - if (!trace->tmask.test(t)) - continue; - - int req_idx = block_idx * LSU_CHANNELS + (i % LSU_CHANNELS); - auto& dcache_req_port = core_->lsu_demux_.at(req_idx)->ReqIn; - - auto mem_addr = trace_data->mem_addrs.at(t); - auto type = get_addr_type(mem_addr.addr); - - MemReq mem_req; - mem_req.addr = mem_addr.addr; - mem_req.write = is_write; - mem_req.type = type; - mem_req.tag = tag; - mem_req.cid = trace->cid; - mem_req.uuid = trace->uuid; - - dcache_req_port.push(mem_req, 1); - DT(3, "mem-req: addr=0x" << std::hex << mem_req.addr << ", tag=" << tag - << ", lsu_type=" << trace->lsu_type << ", rid=" << req_idx << ", addr_type=" << mem_req.type << ", " << *trace); - - if (is_write) { - ++core_->perf_stats_.stores; - } else { - ++core_->perf_stats_.loads; - ++pending_loads_; - } - - ++count; - } - return count; -} - /////////////////////////////////////////////////////////////////////////////// SfuUnit::SfuUnit(const SimContext& ctx, Core* core) - : FuncUnit(ctx, core, "SFU") + : FuncUnit(ctx, core, "sfu-unit") {} void SfuUnit::tick() { @@ -254,10 +237,10 @@ void SfuUnit::tick() { auto trace = input.front(); auto sfu_type = trace->sfu_type; bool release_warp = trace->fetch_stall; - + int delay = 2; switch (sfu_type) { case SfuType::WSPAWN: - output.push(trace, 1); + output.push(trace, 2+delay); if (trace->eop) { auto trace_data = std::dynamic_pointer_cast(trace->data); release_warp = core_->wspawn(trace_data->arg1, trace_data->arg2); @@ -270,10 +253,10 @@ void SfuUnit::tick() { case SfuType::CSRRW: case SfuType::CSRRS: case SfuType::CSRRC: - output.push(trace, 1); + output.push(trace, 2+delay); break; case SfuType::BAR: { - output.push(trace, 1); + output.push(trace, 2+delay); if (trace->eop) { auto trace_data = std::dynamic_pointer_cast(trace->data); release_warp = core_->barrier(trace_data->arg1, trace_data->arg2, trace->wid); @@ -283,7 +266,7 @@ void SfuUnit::tick() { std::abort(); } - DT(3, "pipeline-execute: op=" << trace->sfu_type << ", " << *trace); + DT(3, this->name() << ": op=" << trace->sfu_type << ", " << *trace); if (trace->eop && release_warp) { core_->resume(trace->wid); } diff --git a/sim/simx/func_unit.h b/sim/simx/func_unit.h index 45f0152ff..76dd16173 100644 --- a/sim/simx/func_unit.h +++ b/sim/simx/func_unit.h @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -26,13 +26,13 @@ public: std::vector> Inputs; std::vector> Outputs; - FuncUnit(const SimContext& ctx, Core* core, const char* name) - : SimObject(ctx, name) + FuncUnit(const SimContext& ctx, Core* core, const char* name) + : SimObject(ctx, name) , Inputs(ISSUE_WIDTH, this) , Outputs(ISSUE_WIDTH, this) , core_(core) {} - + virtual ~FuncUnit() {} virtual void reset() {} @@ -73,28 +73,26 @@ public: private: - int send_requests(instr_trace_t* trace, int block_idx, int tag); - - struct pending_req_t { + struct pending_req_t { instr_trace_t* trace; - uint32_t count; + BitVector<> mask; }; - struct lsu_state_t { + struct lsu_state_t { HashTable pending_rd_reqs; - instr_trace_t* fence_trace; + instr_trace_t* fence_trace; bool fence_lock; lsu_state_t() : pending_rd_reqs(LSUQ_IN_SIZE) {} - + void clear() { this->pending_rd_reqs.clear(); this->fence_trace = nullptr; this->fence_lock = false; } }; - - std::array states_; + + std::array states_; uint64_t pending_loads_; }; @@ -103,7 +101,7 @@ private: class SfuUnit : public FuncUnit { public: SfuUnit(const SimContext& ctx, Core*); - + void tick(); }; diff --git a/sim/simx/instr_trace.h b/sim/simx/instr_trace.h index 532b736f5..7f6b37580 100644 --- a/sim/simx/instr_trace.h +++ b/sim/simx/instr_trace.h @@ -45,6 +45,11 @@ struct SFUTraceData : public ITraceData { struct instr_trace_t { public: + struct reg_t { + RegType type; + uint32_t idx; + }; + //-- const uint64_t uuid; const Arch& arch; @@ -54,16 +59,13 @@ public: uint32_t wid; ThreadMask tmask; Word PC; - - //-- - uint32_t rdest; - RegType rdest_type; bool wb; //-- - RegMask used_iregs; - RegMask used_fregs; - RegMask used_vregs; + reg_t dst_reg; + + //-- + std::vector src_regs; //- FUType fu_type; @@ -79,7 +81,7 @@ public: ITraceData::Ptr data; - int pid; + int pid; bool sop; bool eop; @@ -92,12 +94,9 @@ public: , wid(0) , tmask(0) , PC(0) - , rdest(0) - , rdest_type(RegType::None) , wb(false) - , used_iregs(0) - , used_fregs(0) - , used_vregs(0) + , dst_reg({RegType::None, 0}) + , src_regs(NUM_SRC_REGS, {RegType::None, 0}) , fu_type(FUType::ALU) , unit_type(0) , data(nullptr) @@ -115,12 +114,9 @@ public: , wid(rhs.wid) , tmask(rhs.tmask) , PC(rhs.PC) - , rdest(rhs.rdest) - , rdest_type(rhs.rdest_type) , wb(rhs.wb) - , used_iregs(rhs.used_iregs) - , used_fregs(rhs.used_fregs) - , used_vregs(rhs.used_vregs) + , dst_reg(rhs.dst_reg) + , src_regs(rhs.src_regs) , fu_type(rhs.fu_type) , unit_type(rhs.unit_type) , data(rhs.data) @@ -152,8 +148,13 @@ inline std::ostream &operator<<(std::ostream &os, const instr_trace_t& trace) { } os << ", PC=0x" << std::hex << trace.PC; os << ", wb=" << trace.wb; - if (trace.wb) { - os << ", rd=" << trace.rdest_type << std::dec << trace.rdest; + if (trace.dst_reg.type != RegType::None) { + os << ", rd=" << trace.dst_reg.type << std::dec << trace.dst_reg.idx; + } + for (uint32_t i = 0; i < trace.src_regs.size(); ++i) { + if (trace.src_regs[i].type != RegType::None) { + os << ", rs" << i << "=" << trace.src_regs[i].type << std::dec << trace.src_regs[i].idx; + } } os << ", ex=" << trace.fu_type; if (trace.pid != -1) { diff --git a/sim/simx/local_mem.cpp b/sim/simx/local_mem.cpp index ca2238473..195fe5300 100644 --- a/sim/simx/local_mem.cpp +++ b/sim/simx/local_mem.cpp @@ -82,11 +82,13 @@ public: continue; } + DT(4, simobject_->name() << " mem-req" << req_id << ": "<< core_req); + in_used_banks.at(bank_id) = true; if (!core_req.write || config_.write_reponse) { // send response - MemRsp core_rsp{core_req.tag, core_req.cid}; + MemRsp core_rsp{core_req.tag, core_req.cid, core_req.uuid}; simobject_->Outputs.at(req_id).push(core_rsp, 1); } diff --git a/sim/simx/main.cpp b/sim/simx/main.cpp index be1505610..cd375b516 100644 --- a/sim/simx/main.cpp +++ b/sim/simx/main.cpp @@ -112,7 +112,9 @@ int main(int argc, char **argv) { return -1; } } - +#ifndef NDEBUG + std::cout << "[VXDRV] START: program=" << program << std::endl; +#endif // run simulation processor.run(); diff --git a/sim/simx/mem_coalescer.cpp b/sim/simx/mem_coalescer.cpp index 390fd5f01..8af567985 100644 --- a/sim/simx/mem_coalescer.cpp +++ b/sim/simx/mem_coalescer.cpp @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,100 +16,141 @@ using namespace vortex; MemCoalescer::MemCoalescer( - const SimContext& ctx, - const char* name, + const SimContext& ctx, + const char* name, uint32_t input_size, uint32_t output_size, uint32_t line_size, uint32_t queue_size, uint32_t delay -) : SimObject(ctx, name) - , ReqIn(input_size, this) - , RspIn(input_size, this) - , ReqOut(output_size, this) - , RspOut(output_size, this) +) : SimObject(ctx, name) + , ReqIn(this) + , RspIn(this) + , ReqOut(this) + , RspOut(this) + , input_size_(input_size) + , output_size_(output_size) + , output_ratio_(input_size / output_size) , pending_rd_reqs_(queue_size) + , sent_mask_(input_size) , line_size_(line_size) , delay_(delay) {} void MemCoalescer::reset() { - last_index_ = 0; sent_mask_.reset(); } -void MemCoalescer::tick() { - uint32_t I = ReqIn.size(); - uint32_t O = ReqOut.size(); - +void MemCoalescer::tick() { // process incoming responses - for (uint32_t o = 0; o < O; ++o) { - if (RspOut.at(o).empty()) - continue; - auto& mem_rsp = RspOut.at(o).front(); - DT(3, this->name() << "-" << mem_rsp); - auto& entry = pending_rd_reqs_.at(mem_rsp.tag); - for (uint32_t i = 0; i < I; ++i) { - if (entry.mask.test(i)) { - MemRsp rsp(mem_rsp); - rsp.tag = entry.tag; - RspIn.at(i).push(rsp, 1); + if (!RspOut.empty()) { + auto& out_rsp = RspOut.front(); + DT(4, this->name() << " mem-rsp: " << out_rsp); + auto& entry = pending_rd_reqs_.at(out_rsp.tag); + + BitVector<> rsp_mask(input_size_); + for (uint32_t o = 0; o < output_size_; ++o) { + if (!out_rsp.mask.test(o)) + continue; + for (uint32_t r = 0; r < output_ratio_; ++r) { + uint32_t i = o * output_ratio_ + r; + if (entry.mask.test(i)) + rsp_mask.set(i); } } - pending_rd_reqs_.release(mem_rsp.tag); - RspOut.at(o).pop(); + + // build memory response + LsuRsp in_rsp(input_size_); + in_rsp.mask = rsp_mask; + in_rsp.tag = entry.tag; + in_rsp.cid = out_rsp.cid; + in_rsp.uuid = out_rsp.uuid; + + // send memory response + RspIn.push(in_rsp, 1); + + // track remaining responses + assert(!entry.mask.none()); + entry.mask &= ~rsp_mask; + if (entry.mask.none()) { + // whole response received, release tag + pending_rd_reqs_.release(out_rsp.tag); + } + RspOut.pop(); } // process incoming requests - uint64_t addr_mask = ~uint64_t(line_size_-1); - bool completed = true; - for (uint32_t i = last_index_; i < I; ++i) { - if (sent_mask_.test(i) || ReqIn.at(i).empty()) - continue; + if (ReqIn.empty()) + return; - auto& seed = ReqIn.at(i).front(); + auto& in_req = ReqIn.front(); + assert(in_req.mask.size() == input_size_); + assert(!in_req.mask.none()); - // ensure we can allocate a response tag - if (!seed.write && pending_rd_reqs_.full()) { - DT(4, "*** " << this->name() << "-queue-full: " << seed); - last_index_ = i; - completed = false; - break; - } - - std::bitset<64> mask(0); - mask.set(i); - - // coalesce matching requests - uint64_t seed_addr = seed.addr & addr_mask; - for (uint32_t j = i + 1; j < I; ++j) { - if (sent_mask_.test(j) || ReqIn.at(j).empty()) - continue; - auto& match = ReqIn.at(j).front(); - uint64_t match_addr = match.addr & addr_mask; - if (match_addr == seed_addr) { - mask.set(j); - ReqIn.at(j).pop(); - } - } - - uint32_t tag = 0; - if (!seed.write) { - tag = pending_rd_reqs_.allocate(pending_req_t{seed.tag, mask}); - } - - MemReq mem_req{seed}; - mem_req.tag = tag; - DT(3, this->name() << "-" << mem_req << ", coalesced=" << mask.count()); - uint32_t c = i % O; - ReqOut.at(c).push(mem_req, delay_); - ReqIn.at(i).pop(); - - sent_mask_ |= mask; + // ensure we can allocate a response tag + if (pending_rd_reqs_.full()) { + DT(4, "*** " << this->name() << " queue-full: " << in_req); + return; } - if (completed) { - last_index_ = 0; + uint64_t addr_mask = ~uint64_t(line_size_-1); + + BitVector<> out_mask(output_size_); + std::vector out_addrs(output_size_); + + BitVector<> cur_mask(input_size_); + + for (uint32_t o = 0; o < output_size_; ++o) { + for (uint32_t r = 0; r < output_ratio_; ++r) { + uint32_t i = o * output_ratio_ + r; + if (sent_mask_.test(i) || !in_req.mask.test(i)) + continue; + + uint64_t seed_addr = in_req.addrs.at(i) & addr_mask; + cur_mask.set(i); + + // coalesce matching requests + for (uint32_t s = r + 1; s < output_ratio_; ++s) { + uint32_t j = o * output_ratio_ + s; + if (sent_mask_.test(j) || !in_req.mask.test(j)) + continue; + uint64_t match_addr = in_req.addrs.at(j) & addr_mask; + if (match_addr == seed_addr) { + cur_mask.set(j); + } + } + + out_mask.set(o); + out_addrs.at(o) = seed_addr; + break; + } + } + + assert(!out_mask.none()); + + uint32_t tag = 0; + if (!in_req.write) { + // allocate a response tag for read requests + tag = pending_rd_reqs_.allocate(pending_req_t{in_req.tag, cur_mask}); + } + + // build memory request + LsuReq out_req{output_size_}; + out_req.mask = out_mask; + out_req.tag = tag; + out_req.write = in_req.write; + out_req.addrs = out_addrs; + out_req.cid = in_req.cid; + out_req.uuid = in_req.uuid; + + // send memory request + ReqOut.push(out_req, delay_); + DT(4, this->name() << " mem-req: coalesced=" << cur_mask.count() << ", " << out_req); + + // update sent mask + sent_mask_ |= cur_mask; + if (sent_mask_ == in_req.mask) { + ReqIn.pop(); sent_mask_.reset(); } } \ No newline at end of file diff --git a/sim/simx/mem_coalescer.h b/sim/simx/mem_coalescer.h index 1a38dd3ac..f0e3935aa 100644 --- a/sim/simx/mem_coalescer.h +++ b/sim/simx/mem_coalescer.h @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -17,15 +17,15 @@ namespace vortex { class MemCoalescer : public SimObject { public: - std::vector> ReqIn; - std::vector> RspIn; + SimPort ReqIn; + SimPort RspIn; - std::vector> ReqOut; - std::vector> RspOut; + SimPort ReqOut; + SimPort RspOut; MemCoalescer( - const SimContext& ctx, - const char* name, + const SimContext& ctx, + const char* name, uint32_t input_size, uint32_t output_size, uint32_t line_size, @@ -41,14 +41,17 @@ private: struct pending_req_t { uint32_t tag; - std::bitset<64> mask; + BitVector<> mask; }; + uint32_t input_size_; + uint32_t output_size_; + uint32_t output_ratio_; + HashTable pending_rd_reqs_; + BitVector<> sent_mask_; uint32_t line_size_; uint32_t delay_; - uint32_t last_index_; - std::bitset<64> sent_mask_; }; } \ No newline at end of file diff --git a/sim/simx/mem_sim.cpp b/sim/simx/mem_sim.cpp index df3860daa..a12713fea 100644 --- a/sim/simx/mem_sim.cpp +++ b/sim/simx/mem_sim.cpp @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,14 +15,7 @@ #include #include #include - -DISABLE_WARNING_PUSH -DISABLE_WARNING_UNUSED_PARAMETER -#define RAMULATOR -#include -#include -#include -DISABLE_WARNING_POP +#include #include "constants.h" #include "types.h" @@ -32,83 +25,75 @@ using namespace vortex; class MemSim::Impl { private: - MemSim* simobject_; - Config config_; + MemSim* simobject_; + Config config_; + DramSim dram_sim_; PerfStats perf_stats_; - ramulator::Gem5Wrapper* dram_; + + struct DramCallbackArgs { + MemSim* simobject; + MemReq request; + }; public: - - Impl(MemSim* simobject, const Config& config) + Impl(MemSim* simobject, const Config& config) : simobject_(simobject) , config_(config) - { - ramulator::Config ram_config; - ram_config.add("standard", "DDR4"); - ram_config.add("channels", std::to_string(config.channels)); - ram_config.add("ranks", "1"); - ram_config.add("speed", "DDR4_2400R"); - ram_config.add("org", "DDR4_4Gb_x8"); - ram_config.add("mapping", "defaultmapping"); - ram_config.set_core_num(config.num_cores); - dram_ = new ramulator::Gem5Wrapper(ram_config, MEM_BLOCK_SIZE); - Stats::statlist.output("ramulator.ddr4.log"); - } + , dram_sim_(MEM_CLOCK_RATIO) + {} ~Impl() { - dram_->finish(); - Stats::statlist.printall(); - delete dram_; + //-- } const PerfStats& perf_stats() const { return perf_stats_; } - void dram_callback(ramulator::Request& req, uint32_t tag, uint64_t uuid) { - if (req.type == ramulator::Request::Type::WRITE) - return; - MemRsp mem_rsp{tag, (uint32_t)req.coreid, uuid}; - simobject_->MemRspPort.push(mem_rsp, 1); - DT(3, simobject_->name() << "-" << mem_rsp); - } - void reset() { - perf_stats_ = PerfStats(); + dram_sim_.reset(); } void tick() { - if (MEM_CYCLE_RATIO > 0) { - auto cycle = SimPlatform::instance().cycles(); - if ((cycle % MEM_CYCLE_RATIO) == 0) - dram_->tick(); - } else { - for (int i = MEM_CYCLE_RATIO; i <= 0; ++i) - dram_->tick(); - } - + dram_sim_.tick(); + if (simobject_->MemReqPort.empty()) return; - + auto& mem_req = simobject_->MemReqPort.front(); - ramulator::Request dram_req( + // try to enqueue the request to the memory system + auto req_args = new DramCallbackArgs{simobject_, mem_req}; + auto enqueue_success = dram_sim_.send_request( + mem_req.write, mem_req.addr, - mem_req.write ? ramulator::Request::Type::WRITE : ramulator::Request::Type::READ, - std::bind(&Impl::dram_callback, this, placeholders::_1, mem_req.tag, mem_req.uuid), - mem_req.cid + 0, + [](void* arg) { + auto rsp_args = reinterpret_cast(arg); + // only send a response for read requests + if (!rsp_args->request.write) { + MemRsp mem_rsp{rsp_args->request.tag, rsp_args->request.cid, rsp_args->request.uuid}; + rsp_args->simobject->MemRspPort.push(mem_rsp, 1); + DT(3, rsp_args->simobject->name() << " mem-rsp: " << mem_rsp); + } + delete rsp_args; + }, + req_args ); - if (!dram_->send(dram_req)) + // check if the request was enqueued successfully + if (!enqueue_success) { + delete req_args; return; - + } + if (mem_req.write) { ++perf_stats_.writes; } else { ++perf_stats_.reads; } - - DT(3, simobject_->name() << "-" << mem_req); + + DT(3, simobject_->name() << " mem-req: " << mem_req); simobject_->MemReqPort.pop(); } @@ -116,9 +101,9 @@ public: /////////////////////////////////////////////////////////////////////////////// -MemSim::MemSim(const SimContext& ctx, const char* name, const Config& config) +MemSim::MemSim(const SimContext& ctx, const char* name, const Config& config) : SimObject(ctx, name) - , MemReqPort(this) + , MemReqPort(this) , MemRspPort(this) , impl_(new Impl(this, config)) {} diff --git a/sim/simx/operand.h b/sim/simx/operand.h index 53483792f..065f7d03d 100644 --- a/sim/simx/operand.h +++ b/sim/simx/operand.h @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,43 +18,61 @@ namespace vortex { class Operand : public SimObject { +private: + static constexpr uint32_t NUM_BANKS = 4; + uint32_t total_stalls_ = 0; + public: SimPort Input; SimPort Output; - Operand(const SimContext& ctx) - : SimObject(ctx, "Operand") + Operand(const SimContext& ctx) + : SimObject(ctx, "Operand") , Input(this) , Output(this) - {} + { + total_stalls_ = 0; + } virtual ~Operand() {} - virtual void reset() {} + virtual void reset() { + total_stalls_ = 0; + } virtual void tick() { if (Input.empty()) return; auto trace = Input.front(); - int delay = 1; - for (int i = 0; i < MAX_NUM_REGS; ++i) { - bool is_iregs = trace->used_iregs.test(i); - bool is_fregs = trace->used_fregs.test(i); - bool is_vregs = trace->used_vregs.test(i); - if (is_iregs || is_fregs || is_vregs) { - if (is_iregs && i == 0) - continue; - ++delay; + uint32_t stalls = 0; + + for (int i = 0; i < NUM_SRC_REGS; ++i) { + for (int j = i + 1; j < NUM_SRC_REGS; ++j) { + int bank_i = trace->src_regs[i].idx % NUM_BANKS; + int bank_j = trace->src_regs[j].idx % NUM_BANKS; + if ((trace->src_regs[i].type != RegType::None) + && (trace->src_regs[j].type != RegType::None) + && (trace->src_regs[i].idx != 0) + && (trace->src_regs[j].idx != 0) + && bank_i == bank_j) { + ++stalls; + } } } - Output.push(trace, delay); - + total_stalls_ += stalls; + + Output.push(trace, 2 + stalls); + DT(3, "pipeline-operands: " << *trace); Input.pop(); }; + + uint32_t total_stalls() const { + return total_stalls_; + } }; } \ No newline at end of file diff --git a/sim/simx/processor.cpp b/sim/simx/processor.cpp index 7c78218ff..01023125b 100644 --- a/sim/simx/processor.cpp +++ b/sim/simx/processor.cpp @@ -39,7 +39,7 @@ ProcessorImpl::ProcessorImpl(const Arch& arch) XLEN, // address bits 1, // number of ports uint8_t(arch.num_clusters()), // request size - true, // write-through + L3_WRITEBACK, // write-back false, // write response L3_MSHR_SIZE, // mshr size 2, // pipeline latency @@ -70,6 +70,19 @@ ProcessorImpl::ProcessorImpl(const Arch& arch) --perf_mem_pending_reads_; }); +#ifndef NDEBUG + // dump device configuration + std::cout << "CONFIGS:" + << " num_threads=" << arch.num_threads() + << ", num_warps=" << arch.num_warps() + << ", num_cores=" << arch.num_cores() + << ", num_clusters=" << arch.num_clusters() + << ", socket_size=" << arch.socket_size() + << ", local_mem_base=0x" << std::hex << arch.local_mem_base() << std::dec + << ", num_barriers=" << arch.num_barriers() + << std::endl; +#endif + // reset the device this->reset(); } diff --git a/sim/simx/scoreboard.h b/sim/simx/scoreboard.h index ee42c3427..0be79eb9e 100644 --- a/sim/simx/scoreboard.h +++ b/sim/simx/scoreboard.h @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -24,95 +24,87 @@ public: struct reg_use_t { RegType reg_type; - uint32_t reg_id; - FUType fu_type; + uint32_t reg_id; + FUType fu_type; SfuType sfu_type; uint64_t uuid; }; - - Scoreboard(const Arch &arch) - : in_use_iregs_(arch.num_warps()) - , in_use_fregs_(arch.num_warps()) - { + + Scoreboard(const Arch &arch) + : in_use_regs_(arch.num_warps()) { + for (auto& in_use_reg : in_use_regs_) { + in_use_reg.resize((int)RegType::Count); + } this->clear(); } void clear() { - for (uint32_t i = 0, n = in_use_iregs_.size(); i < n; ++i) { - in_use_iregs_.at(i).reset(); - in_use_fregs_.at(i).reset(); + for (auto& in_use_reg : in_use_regs_) { + for (auto& mask : in_use_reg) { + mask.reset(); + } } owners_.clear(); } bool in_use(instr_trace_t* trace) const { - return (trace->used_iregs & in_use_iregs_.at(trace->wid)) != 0 - || (trace->used_fregs & in_use_fregs_.at(trace->wid)) != 0; + if (trace->wb) { + assert(trace->dst_reg.type != RegType::None); + if (in_use_regs_.at(trace->wid).at((int)trace->dst_reg.type).test(trace->dst_reg.idx)) { + return true; + } + } + for (uint32_t i = 0; i < trace->src_regs.size(); ++i) { + if (trace->src_regs[i].type != RegType::None) { + if (in_use_regs_.at(trace->wid).at((int)trace->src_regs[i].type).test(trace->src_regs[i].idx)) { + return true; + } + } + } + return false; } std::vector get_uses(instr_trace_t* trace) const { std::vector out; - - auto used_iregs = trace->used_iregs & in_use_iregs_.at(trace->wid); - auto used_fregs = trace->used_fregs & in_use_fregs_.at(trace->wid); - - for (uint32_t r = 0; r < MAX_NUM_REGS; ++r) { - if (used_iregs.test(r)) { - uint32_t tag = (r << 16) | (trace->wid << 4) | (int)RegType::Integer; + if (trace->wb) { + assert(trace->dst_reg.type != RegType::None); + if (in_use_regs_.at(trace->wid).at((int)trace->dst_reg.type).test(trace->dst_reg.idx)) { + uint32_t tag = (trace->dst_reg.idx << 16) | (trace->wid << 4) | (int)trace->dst_reg.type; auto owner = owners_.at(tag); - out.push_back({RegType::Integer, r, owner->fu_type, owner->sfu_type, owner->uuid}); + out.push_back({trace->dst_reg.type, trace->dst_reg.idx, owner->fu_type, owner->sfu_type, owner->uuid}); } } - - for (uint32_t r = 0; r < MAX_NUM_REGS; ++r) { - if (used_fregs.test(r)) { - uint32_t tag = (r << 16) | (trace->wid << 4) | (int)RegType::Float; - auto owner = owners_.at(tag); - out.push_back({RegType::Float, r, owner->fu_type, owner->sfu_type, owner->uuid}); + for (uint32_t i = 0; i < trace->src_regs.size(); ++i) { + if (trace->src_regs[i].type != RegType::None) { + if (in_use_regs_.at(trace->wid).at((int)trace->src_regs[i].type).test(trace->src_regs[i].idx)) { + uint32_t tag = (trace->src_regs[i].idx << 16) | (trace->wid << 4) | (int)trace->src_regs[i].type; + auto owner = owners_.at(tag); + out.push_back({trace->src_regs[i].type, trace->src_regs[i].idx, owner->fu_type, owner->sfu_type, owner->uuid}); + } } } - return out; } - + void reserve(instr_trace_t* trace) { assert(trace->wb); - switch (trace->rdest_type) { - case RegType::Integer: - in_use_iregs_.at(trace->wid).set(trace->rdest); - break; - case RegType::Float: - in_use_fregs_.at(trace->wid).set(trace->rdest); - break; - default: - assert(false); - } - uint32_t tag = (trace->rdest << 16) | (trace->wid << 4) | (int)trace->rdest_type; + in_use_regs_.at(trace->wid).at((int)trace->dst_reg.type).set(trace->dst_reg.idx); + uint32_t tag = (trace->dst_reg.idx << 16) | (trace->wid << 4) | (int)trace->dst_reg.type; assert(owners_.count(tag) == 0); owners_[tag] = trace; - assert((int)trace->fu_type < 5); } void release(instr_trace_t* trace) { assert(trace->wb); - switch (trace->rdest_type) { - case RegType::Integer: - in_use_iregs_.at(trace->wid).reset(trace->rdest); - break; - case RegType::Float: - in_use_fregs_.at(trace->wid).reset(trace->rdest); - break; - default: - assert(false); - } - uint32_t tag = (trace->rdest << 16) | (trace->wid << 4) | (int)trace->rdest_type; + in_use_regs_.at(trace->wid).at((int)trace->dst_reg.type).reset(trace->dst_reg.idx); + uint32_t tag = (trace->dst_reg.idx << 16) | (trace->wid << 4) | (int)trace->dst_reg.type; + assert(owners_.count(tag) != 0); owners_.erase(tag); } private: - std::vector in_use_iregs_; - std::vector in_use_fregs_; + std::vector> in_use_regs_; std::unordered_map owners_; }; diff --git a/sim/simx/socket.cpp b/sim/simx/socket.cpp index afda924d8..cef8a3908 100644 --- a/sim/simx/socket.cpp +++ b/sim/simx/socket.cpp @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,11 +16,11 @@ using namespace vortex; -Socket::Socket(const SimContext& ctx, +Socket::Socket(const SimContext& ctx, uint32_t socket_id, - Cluster* cluster, - const Arch &arch, - const DCRS &dcrs) + Cluster* cluster, + const Arch &arch, + const DCRS &dcrs) : SimObject(ctx, "socket") , icache_mem_req_port(this) , icache_mem_rsp_port(this) @@ -44,7 +44,7 @@ Socket::Socket(const SimContext& ctx, XLEN, // address bits 1, // number of ports 1, // number of inputs - false, // write-through + false, // write-back false, // write response (uint8_t)arch.num_warps(), // mshr size 2, // pipeline latency @@ -64,7 +64,7 @@ Socket::Socket(const SimContext& ctx, XLEN, // address bits 1, // number of ports DCACHE_NUM_REQS, // number of inputs - true, // write-through + DCACHE_WRITEBACK, // write-back false, // write response DCACHE_MSHR_SIZE, // mshr size 2, // pipeline latency diff --git a/sim/simx/types.cpp b/sim/simx/types.cpp index b32a0cee6..3e6c5960f 100644 --- a/sim/simx/types.cpp +++ b/sim/simx/types.cpp @@ -1,10 +1,10 @@ // Copyright © 2019-2023 -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,14 +16,14 @@ using namespace vortex; LocalMemDemux::LocalMemDemux( - const SimContext& ctx, - const char* name, + const SimContext& ctx, + const char* name, uint32_t delay -) : SimObject(ctx, name) +) : SimObject(ctx, name) , ReqIn(this) , RspIn(this) - , ReqSM(this) - , RspSM(this) + , ReqLmem(this) + , RspLmem(this) , ReqDC(this) , RspDC(this) , delay_(delay) @@ -31,30 +31,133 @@ LocalMemDemux::LocalMemDemux( void LocalMemDemux::reset() {} -void LocalMemDemux::tick() { +void LocalMemDemux::tick() { // process incoming responses - if (!RspSM.empty()) { - auto& rsp = RspSM.front(); - DT(4, this->name() << "-" << rsp); - RspIn.push(rsp, 1); - RspSM.pop(); + if (!RspLmem.empty()) { + auto& out_rsp = RspLmem.front(); + DT(4, this->name() << " lmem-rsp: " << out_rsp); + RspIn.push(out_rsp, 1); + RspLmem.pop(); } if (!RspDC.empty()) { - auto& rsp = RspDC.front(); - DT(4, this->name() << "-" << rsp); - RspIn.push(rsp, 1); - RspDC - .pop(); + auto& out_rsp = RspDC.front(); + DT(4, this->name() << " dc-rsp: " << out_rsp); + RspIn.push(out_rsp, 1); + RspDC.pop(); } - // process incoming requests + + // process incoming requests if (!ReqIn.empty()) { - auto& req = ReqIn.front(); - DT(4, this->name() << "-" << req); - if (req.type == AddrType::Shared) { - ReqSM.push(req, delay_); - } else { - ReqDC.push(req, delay_); + auto& in_req = ReqIn.front(); + + LsuReq out_dc_req(in_req.mask.size()); + out_dc_req.write = in_req.write; + out_dc_req.tag = in_req.tag; + out_dc_req.cid = in_req.cid; + out_dc_req.uuid = in_req.uuid; + + LsuReq out_lmem_req(out_dc_req); + + for (uint32_t i = 0; i < in_req.mask.size(); ++i) { + if (in_req.mask.test(i)) { + auto type = get_addr_type(in_req.addrs.at(i)); + if (type == AddrType::Shared) { + out_lmem_req.mask.set(i); + out_lmem_req.addrs.at(i) = in_req.addrs.at(i); + } else { + out_dc_req.mask.set(i); + out_dc_req.addrs.at(i) = in_req.addrs.at(i); + } + } + } + + if (!out_dc_req.mask.none()) { + ReqDC.push(out_dc_req, delay_); + DT(4, this->name() << " dc-req: " << out_dc_req); + } + + if (!out_lmem_req.mask.none()) { + ReqLmem.push(out_lmem_req, delay_); + DT(4, this->name() << " lmem-req: " << out_lmem_req); } ReqIn.pop(); - } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +LsuMemAdapter::LsuMemAdapter( + const SimContext& ctx, + const char* name, + uint32_t num_inputs, + uint32_t delay +) : SimObject(ctx, name) + , ReqIn(this) + , RspIn(this) + , ReqOut(num_inputs, this) + , RspOut(num_inputs, this) + , delay_(delay) +{} + +void LsuMemAdapter::reset() {} + +void LsuMemAdapter::tick() { + uint32_t input_size = ReqOut.size(); + + // process incoming responses + for (uint32_t i = 0; i < input_size; ++i) { + if (RspOut.at(i).empty()) + continue; + auto& out_rsp = RspOut.at(i).front(); + DT(4, this->name() << " rsp" << i << ": " << out_rsp); + + // build memory response + LsuRsp in_rsp(input_size); + in_rsp.mask.set(i); + in_rsp.tag = out_rsp.tag; + in_rsp.cid = out_rsp.cid; + in_rsp.uuid = out_rsp.uuid; + + // include other responses with the same tag + for (uint32_t j = i + 1; j < input_size; ++j) { + if (RspOut.at(j).empty()) + continue; + auto& other_rsp = RspOut.at(j).front(); + if (out_rsp.tag == other_rsp.tag) { + in_rsp.mask.set(j); + RspOut.at(j).pop(); + } + } + + // send memory response + RspIn.push(in_rsp, 1); + + // remove input + RspOut.at(i).pop(); + break; + } + + // process incoming requests + if (!ReqIn.empty()) { + auto& in_req = ReqIn.front(); + assert(in_req.mask.size() == input_size); + + for (uint32_t i = 0; i < input_size; ++i) { + if (in_req.mask.test(i)) { + // build memory request + MemReq out_req; + out_req.write = in_req.write; + out_req.addr = in_req.addrs.at(i); + out_req.type = get_addr_type(in_req.addrs.at(i)); + out_req.tag = in_req.tag; + out_req.cid = in_req.cid; + out_req.uuid = in_req.uuid; + + // send memory request + ReqOut.at(i).push(out_req, delay_); + DT(4, this->name() << " req" << i << ": " << out_req); + } + } + ReqIn.pop(); + } } \ No newline at end of file diff --git a/sim/simx/types.h b/sim/simx/types.h index a84216ae1..385015cc9 100644 --- a/sim/simx/types.h +++ b/sim/simx/types.h @@ -21,7 +21,9 @@ #include #include #include +#include #include +#include #include "debug.h" namespace vortex { @@ -47,6 +49,7 @@ typedef uint64_t WordF; #define MAX_NUM_THREADS 32 #define MAX_NUM_WARPS 32 #define MAX_NUM_REGS 32 +#define NUM_SRC_REGS 3 typedef std::bitset CoreMask; typedef std::bitset RegMask; @@ -58,7 +61,8 @@ typedef std::bitset WarpMask; enum class RegType { None, Integer, - Float + Float, + Count }; inline std::ostream &operator<<(std::ostream &os, const RegType& type) { @@ -235,6 +239,62 @@ inline std::ostream &operator<<(std::ostream &os, const ArbiterType& type) { default: assert(false); } return os; +}/////////////////////////////////////////////////////////////////////////////// + +struct LsuReq { + BitVector<> mask; + std::vector addrs; + bool write; + uint32_t tag; + uint32_t cid; + uint64_t uuid; + + LsuReq(uint32_t size) + : mask(size) + , addrs(size, 0) + , write(false) + , tag(0) + , cid(0) + , uuid(0) + {} +}; + +inline std::ostream &operator<<(std::ostream &os, const LsuReq& req) { + os << "rw=" << req.write << ", mask=" << req.mask << ", "; + for (size_t i = 0; i < req.mask.size(); ++i) { + os << "addr" << i << "="; + if (req.mask.test(i)) { + os << "0x" << std::hex << req.addrs.at(i); + } else { + os << "-"; + } + os << ", "; + } + os << std::dec << "tag=" << req.tag << ", cid=" << req.cid; + os << " (#" << std::dec << req.uuid << ")"; + return os; +} + +/////////////////////////////////////////////////////////////////////////////// + +struct LsuRsp { + BitVector<> mask; + uint64_t tag; + uint32_t cid; + uint64_t uuid; + + LsuRsp(uint32_t size) + : mask(size) + , tag (0) + , cid(0) + , uuid(0) + {} +}; + +inline std::ostream &operator<<(std::ostream &os, const LsuRsp& rsp) { + os << "mask=" << rsp.mask << ", tag=" << rsp.tag << ", cid=" << rsp.cid; + os << " (#" << std::dec << rsp.uuid << ")"; + return os; } /////////////////////////////////////////////////////////////////////////////// @@ -263,7 +323,7 @@ struct MemReq { }; inline std::ostream &operator<<(std::ostream &os, const MemReq& req) { - os << "mem-" << (req.write ? "wr" : "rd") << ": "; + os << "rw=" << req.write << ", "; os << "addr=0x" << std::hex << req.addr << ", type=" << req.type; os << std::dec << ", tag=" << req.tag << ", cid=" << req.cid; os << " (#" << std::dec << req.uuid << ")"; @@ -285,7 +345,7 @@ struct MemRsp { }; inline std::ostream &operator<<(std::ostream &os, const MemRsp& rsp) { - os << "mem-rsp: tag=" << rsp.tag << ", cid=" << rsp.cid; + os << "tag=" << rsp.tag << ", cid=" << rsp.cid; os << " (#" << std::dec << rsp.uuid << ")"; return os; } @@ -424,7 +484,6 @@ public: auto& req_in = Inputs.at(j); if (!req_in.empty()) { auto& req = req_in.front(); - DT(4, this->name() << "-" << req); Outputs.at(o).push(req, delay_); req_in.pop(); this->update_cursor(o, i); @@ -515,7 +574,7 @@ public: i = rsp.tag & (R-1); rsp.tag >>= lg_num_reqs_; } - DT(4, this->name() << "-" << rsp); + DT(4, this->name() << " rsp" << o << ": " << rsp); uint32_t j = o * R + i; RspIn.at(j).push(rsp, 1); RspOut.at(o).pop(); @@ -534,7 +593,7 @@ public: if (lg_num_reqs_ != 0) { req.tag = (req.tag << lg_num_reqs_) | i; } - DT(4, this->name() << "-" << req); + DT(4, this->name() << " req" << j << ": " << req); ReqOut.at(o).push(req, delay_); req_in.pop(); this->update_cursor(o, i); @@ -563,14 +622,14 @@ using MemSwitch = Switch; class LocalMemDemux : public SimObject { public: - SimPort ReqIn; - SimPort RspIn; + SimPort ReqIn; + SimPort RspIn; - SimPort ReqSM; - SimPort RspSM; + SimPort ReqLmem; + SimPort RspLmem; - SimPort ReqDC; - SimPort RspDC; + SimPort ReqDC; + SimPort RspDC; LocalMemDemux( const SimContext& ctx, @@ -586,4 +645,29 @@ private: uint32_t delay_; }; +/////////////////////////////////////////////////////////////////////////////// + +class LsuMemAdapter : public SimObject { +public: + SimPort ReqIn; + SimPort RspIn; + + std::vector> ReqOut; + std::vector> RspOut; + + LsuMemAdapter( + const SimContext& ctx, + const char* name, + uint32_t num_inputs, + uint32_t delay + ); + + void reset(); + + void tick(); + +private: + uint32_t delay_; +}; + } diff --git a/sim/xrtsim/Makefile b/sim/xrtsim/Makefile index 5c0191368..dd11c8d64 100644 --- a/sim/xrtsim/Makefile +++ b/sim/xrtsim/Makefile @@ -5,15 +5,17 @@ DESTDIR ?= $(CURDIR) SRC_DIR := $(VORTEX_HOME)/sim/xrtsim AFU_DIR := $(RTL_DIR)/afu/xrt -CXXFLAGS += -std=c++11 -Wall -Wextra -Wfatal-errors -Wno-array-bounds +CXXFLAGS += -std=c++17 -Wall -Wextra -Wfatal-errors -Wno-array-bounds CXXFLAGS += -fPIC -Wno-maybe-uninitialized CXXFLAGS += -I$(SRC_DIR) -I$(ROOT_DIR)/hw -I$(COMMON_DIR) -I$(DESTDIR) CXXFLAGS += -I/$(THIRD_PARTY_DIR)/softfloat/source/include -CXXFLAGS += -I/$(THIRD_PARTY_DIR) +CXXFLAGS += -I$(THIRD_PARTY_DIR)/ramulator/ext/spdlog/include +CXXFLAGS += -I$(THIRD_PARTY_DIR)/ramulator/ext/yaml-cpp/include +CXXFLAGS += -I$(THIRD_PARTY_DIR)/ramulator/src CXXFLAGS += -DXLEN_$(XLEN) LDFLAGS += -shared $(THIRD_PARTY_DIR)/softfloat/build/Linux-x86_64-GCC/softfloat.a -LDFLAGS += -L$(THIRD_PARTY_DIR)/ramulator -lramulator -pthread +LDFLAGS += -Wl,-rpath,$(THIRD_PARTY_DIR)/ramulator -L$(THIRD_PARTY_DIR)/ramulator -lramulator -pthread # control RTL debug tracing states DBG_TRACE_FLAGS += -DDBG_TRACE_PIPELINE @@ -47,11 +49,11 @@ endif DBG_FLAGS += -DDEBUG_LEVEL=$(DEBUG) -DVCD_OUTPUT $(DBG_TRACE_FLAGS) -SRCS = $(COMMON_DIR)/util.cpp $(COMMON_DIR)/mem.cpp $(COMMON_DIR)/rvfloats.cpp +SRCS = $(COMMON_DIR)/util.cpp $(COMMON_DIR)/mem.cpp $(COMMON_DIR)/rvfloats.cpp $(COMMON_DIR)/dram_sim.cpp SRCS += $(DPI_DIR)/util_dpi.cpp $(DPI_DIR)/float_dpi.cpp SRCS += $(SRC_DIR)/fpga.cpp $(SRC_DIR)/xrt_sim.cpp -RTL_PKGS += $(RTL_DIR)/VX_gpu_pkg.sv $(RTL_DIR)/fpu/VX_fpu_pkg.sv +RTL_PKGS += $(RTL_DIR)/VX_gpu_pkg.sv $(RTL_DIR)/fpu/VX_fpu_pkg.sv $(RTL_DIR)/core/VX_trace_pkg.sv FPU_INCLUDE = -I$(RTL_DIR)/fpu ifneq (,$(findstring FPU_FPNEW,$(CONFIGS))) @@ -64,7 +66,7 @@ RTL_INCLUDE += -I$(AFU_DIR) TOP = vortex_afu_shim VL_FLAGS += --language 1800-2009 --assert -Wall -Wpedantic -VL_FLAGS += -Wno-DECLFILENAME -Wno-REDEFMACRO +VL_FLAGS += -Wno-DECLFILENAME -Wno-REDEFMACRO -Wno-GENUNNAMED VL_FLAGS += --x-initial unique --x-assign unique VL_FLAGS += -DSIMULATION -DSV_DPI VL_FLAGS += -DXLEN_$(XLEN) @@ -72,7 +74,6 @@ VL_FLAGS += $(CONFIGS) VL_FLAGS += $(SRC_DIR)/verilator.vlt VL_FLAGS += $(RTL_INCLUDE) VL_FLAGS += $(RTL_PKGS) -VL_FLAGS += $(DBG_SCOPE_FLAGS) CXXFLAGS += $(CONFIGS) @@ -92,7 +93,7 @@ endif # Enable scope analyzer ifdef SCOPE - VL_FLAGS += -DSCOPE + VL_FLAGS += -DSCOPE $(DBG_SCOPE_FLAGS) CXXFLAGS += -DSCOPE SCOPE_JSON = $(DESTDIR)/scope.json endif diff --git a/sim/xrtsim/vortex_afu_shim.sv b/sim/xrtsim/vortex_afu_shim.sv index 901acd582..648e25e7a 100644 --- a/sim/xrtsim/vortex_afu_shim.sv +++ b/sim/xrtsim/vortex_afu_shim.sv @@ -50,7 +50,6 @@ module vortex_afu_shim #( output wire interrupt `IGNORE_WARNINGS_END ); - vortex_afu #( .C_S_AXI_CTRL_ADDR_WIDTH(C_S_AXI_CTRL_ADDR_WIDTH), .C_S_AXI_CTRL_DATA_WIDTH(C_S_AXI_CTRL_DATA_WIDTH), diff --git a/sim/xrtsim/xrt_sim.cpp b/sim/xrtsim/xrt_sim.cpp index 1f246051e..880983bf1 100644 --- a/sim/xrtsim/xrt_sim.cpp +++ b/sim/xrtsim/xrt_sim.cpp @@ -13,9 +13,7 @@ #include "xrt_sim.h" -#include #include "Vvortex_afu_shim.h" -#include "Vvortex_afu_shim__Syms.h" #ifdef VCD_OUTPUT #include @@ -26,10 +24,7 @@ #include #include -#define RAMULATOR -#include -#include -#include +#include #include #include @@ -46,8 +41,8 @@ #endif #endif -#ifndef MEM_CYCLE_RATIO -#define MEM_CYCLE_RATIO -1 +#ifndef MEM_CLOCK_RATIO +#define MEM_CLOCK_RATIO 1 #endif #undef MEM_BLOCK_SIZE @@ -101,10 +96,10 @@ public: Impl() : device_(nullptr) , ram_(nullptr) - , ramulator_(nullptr) + , dram_sim_(MEM_CLOCK_RATIO) , stop_(false) #ifdef VCD_OUTPUT - , trace_(nullptr) + , tfp_(nullptr) #endif {} @@ -114,9 +109,9 @@ public: future_.wait(); } #ifdef VCD_OUTPUT - if (trace_) { - trace_->close(); - delete trace_; + if (tfp_) { + tfp_->close(); + delete tfp_; } #endif if (device_) { @@ -125,11 +120,6 @@ public: if (ram_) { delete ram_; } - if (ramulator_) { - ramulator_->finish(); - Stats::statlist.printall(); - delete ramulator_; - } } int init() { @@ -145,25 +135,25 @@ public: #ifdef VCD_OUTPUT Verilated::traceEverOn(true); - trace_ = new VerilatedVcdC(); - device_->trace(trace_, 99); - trace_->open("trace.vcd"); + tfp_ = new VerilatedVcdC(); + device_->trace(tfp_, 99); + tfp_->open("trace.vcd"); #endif ram_ = new RAM(0, RAM_PAGE_SIZE); - // initialize dram simulator - ramulator::Config ram_config; - ram_config.add("standard", "DDR4"); - ram_config.add("channels", std::to_string(MEMORY_BANKS)); - ram_config.add("ranks", "1"); - ram_config.add("speed", "DDR4_2400R"); - ram_config.add("org", "DDR4_4Gb_x8"); - ram_config.add("mapping", "defaultmapping"); - ram_config.set_core_num(1); - ramulator_ = new ramulator::Gem5Wrapper(ram_config, MEM_BLOCK_SIZE); - Stats::statlist.output("ramulator.ddr4.log"); - + #ifndef NDEBUG + // dump device configuration + std::cout << "CONFIGS:" + << " num_threads=" << NUM_THREADS + << ", num_warps=" << NUM_WARPS + << ", num_cores=" << NUM_CORES + << ", num_clusters=" << NUM_CLUSTERS + << ", socket_size=" << SOCKET_SIZE + << ", local_mem_base=0x" << std::hex << LMEM_BASE_ADDR << std::dec + << ", num_barriers=" << NUM_BARRIERS + << std::endl; + #endif // reset the device this->reset(); @@ -181,7 +171,17 @@ public: private: void reset() { - //-- + this->axi_ctrl_bus_reset(); + this->axi_mem_bus_reset(); + + for (auto& reqs : pending_mem_reqs_) { + reqs.clear(); + } + + { + std::queue empty; + std::swap(dram_queue_, empty); + } device_->ap_rst_n = 0; @@ -206,11 +206,21 @@ private: } void tick() { - //-- + this->axi_ctrl_bus_eval(); + this->axi_mem_bus_eval(); if (!dram_queue_.empty()) { - if (ramulator_->send(dram_queue_.front())) + auto mem_req = dram_queue_.front(); + if (dram_sim_.send_request(mem_req->write, mem_req->addr, 0, [](void* arg) { + auto orig_req = reinterpret_cast(arg); + if (orig_req->ready) { + delete orig_req; + } else { + orig_req->ready = true; + } + }, mem_req)) { dram_queue_.pop(); + } } device_->ap_clk = 0; @@ -218,14 +228,7 @@ private: device_->ap_clk = 1; this->eval(); - if (MEM_CYCLE_RATIO > 0) { - auto cycle = timestamp / 2; - if ((cycle % MEM_CYCLE_RATIO) == 0) - ramulator_->tick(); - } else { - for (int i = MEM_CYCLE_RATIO; i <= 0; ++i) - ramulator_->tick(); - } + dram_sim_.tick(); #ifndef NDEBUG fflush(stdout); @@ -236,25 +239,86 @@ private: device_->eval(); #ifdef VCD_OUTPUT if (sim_trace_enabled()) { - trace_->dump(timestamp); + tfp_->dump(timestamp); } #endif ++timestamp; } + void axi_ctrl_bus_reset() { + // address write request + device_->s_axi_ctrl_awvalid = 0; + //device_->s_axi_ctrl_awaddr = 0; + + // data write request + device_->s_axi_ctrl_wvalid = 0; + //device_->s_axi_ctrl_wdata = 0; + //device_->s_axi_ctrl_wstrb = 0; + + // address read request + device_->s_axi_ctrl_arvalid = 0; + //device_->s_axi_ctrl_araddr = 0; + + // data read response + device_->s_axi_ctrl_rready = 0; + + // data write response + device_->s_axi_ctrl_bready = 0; + } + + void axi_ctrl_bus_eval() { + //-- + } + + void axi_mem_bus_reset() { + // address write request + device_->m_axi_mem_0_awready = 0; + + // data write request + device_->m_axi_mem_0_wready = 0; + + // address read request + device_->m_axi_mem_0_arready = 0; + + // data read response + device_->m_axi_mem_0_rvalid = 0; + //device_->m_axi_mem_0_rdata = 0; + //device_->m_axi_mem_0_rlast = 0; + //device_->m_axi_mem_0_rid = 0; + //device_->m_axi_mem_0_rresp = 0; + + // data write response + device_->m_axi_mem_0_bvalid = 0; + //device_->m_axi_mem_0_bresp = 0; + //device_->m_axi_mem_0_bid = 0; + } + + void axi_mem_bus_eval() { + //-- + } + + typedef struct { + std::array data; + uint32_t addr; + bool write; + bool ready; + } mem_req_t; + Vvortex_afu_shim *device_; RAM* ram_; - ramulator::Gem5Wrapper* ramulator_; + DramSim dram_sim_; std::future future_; bool stop_; std::mutex mutex_; - std::queue dram_queue_; + std::list pending_mem_reqs_[MEMORY_BANKS]; + + std::queue dram_queue_; #ifdef VCD_OUTPUT - VerilatedVcdC *trace_; + VerilatedVcdC* tfp_; #endif }; diff --git a/tests/opencl/Makefile b/tests/opencl/Makefile index db8366795..e4be7e712 100644 --- a/tests/opencl/Makefile +++ b/tests/opencl/Makefile @@ -65,27 +65,6 @@ run-rtlsim: $(MAKE) -C sgemm3 run-rtlsim $(MAKE) -C psum run-rtlsim -run-opae: - $(MAKE) -C vecadd run-opae - $(MAKE) -C sgemm run-opae - $(MAKE) -C conv3 run-opae - $(MAKE) -C psort run-opae - $(MAKE) -C saxpy run-opae - $(MAKE) -C sfilter run-opae - $(MAKE) -C oclprintf run-opae - $(MAKE) -C dotproduct run-opae - $(MAKE) -C transpose run-opae - $(MAKE) -C spmv run-opae - $(MAKE) -C stencil run-opae - $(MAKE) -C nearn run-opae - $(MAKE) -C guassian run-opae - $(MAKE) -C kmeans run-opae - $(MAKE) -C blackscholes run-opae - $(MAKE) -C bfs run-opae - $(MAKE) -C sgemm2 run-opae - $(MAKE) -C sgemm3 run-opae - $(MAKE) -C psum run-opae - clean: $(MAKE) -C vecadd clean $(MAKE) -C sgemm clean diff --git a/tests/opencl/bfs/Makefile b/tests/opencl/bfs/Makefile index 1f8414189..c4b140f66 100644 --- a/tests/opencl/bfs/Makefile +++ b/tests/opencl/bfs/Makefile @@ -12,6 +12,6 @@ kernel.cl: $(SRC_DIR)/kernel.cl KERNEL_SRCS := kernel.cl -OPTS ?= $(SRC_DIR)/graph4096.txt +OPTS ?= $(SRC_DIR)/graph4k.txt include ../common.mk diff --git a/tests/opencl/bfs/graph32.txt b/tests/opencl/bfs/graph32.txt new file mode 100644 index 000000000..e22254c9c --- /dev/null +++ b/tests/opencl/bfs/graph32.txt @@ -0,0 +1,225 @@ +32 +0 6 +6 7 +13 5 +18 6 +24 4 +28 6 +34 6 +40 4 +44 7 +51 5 +56 6 +62 10 +72 4 +76 8 +84 3 +87 7 +94 6 +100 9 +109 7 +116 5 +121 5 +126 7 +133 5 +138 6 +144 4 +148 7 +155 4 +159 7 +166 6 +172 7 +179 5 +184 4 + +9 + +188 +0 6 +0 6 +6 4 +5 3 +2 2 +7 8 +1 2 +1 2 +25 8 +20 4 +13 6 +18 5 +31 4 +11 1 +18 7 +0 2 +12 5 +24 3 +10 3 +21 5 +7 10 +5 7 +8 5 +21 5 +17 1 +17 2 +20 1 +27 9 +0 3 +17 6 +3 7 +6 1 +10 7 +15 6 +0 4 +8 10 +5 1 +28 7 +12 6 +15 10 +3 10 +26 2 +0 8 +16 7 +6 10 +3 5 +31 10 +28 10 +21 8 +23 9 +27 2 +22 3 +13 7 +23 10 +17 2 +20 8 +3 3 +15 8 +5 7 +29 7 +15 3 +19 9 +2 1 +30 6 +11 2 +11 2 +21 8 +11 6 +11 6 +12 10 +13 7 +20 3 +2 5 +11 10 +25 9 +6 6 +9 7 +1 6 +30 6 +11 7 +16 2 +20 3 +25 7 +29 7 +29 5 +22 4 +19 9 +10 8 +6 10 +10 3 +5 6 +18 10 +22 9 +29 6 +7 7 +16 4 +16 4 +13 2 +25 2 +26 6 +4 1 +4 2 +5 6 +28 1 +9 2 +25 9 +18 6 +23 10 +26 10 +2 7 +15 10 +17 6 +1 5 +21 4 +26 9 +31 7 +14 9 +10 9 +29 4 +28 10 +30 1 +1 4 +13 3 +11 3 +4 1 +9 8 +3 5 +11 8 +8 8 +21 6 +21 6 +18 4 +3 5 +9 3 +14 4 +15 9 +23 3 +27 1 +9 10 +22 3 +8 9 +25 7 +17 10 +28 1 +24 1 +24 1 +30 4 +2 3 +1 8 +12 9 +17 9 +23 7 +13 7 +27 2 +16 2 +7 2 +18 9 +16 6 +17 10 +25 2 +4 9 +8 2 +29 1 +22 1 +30 4 +31 2 +6 7 +8 10 +17 1 +23 1 +19 10 +29 5 +10 7 +14 5 +19 4 +27 1 +15 6 +28 5 +13 7 +11 6 +13 6 +24 4 +27 4 +19 1 +8 10 +1 4 +18 7 +27 2 diff --git a/tests/opencl/bfs/graph4k.txt b/tests/opencl/bfs/graph4k.txt new file mode 100755 index 000000000..567432612 --- /dev/null +++ b/tests/opencl/bfs/graph4k.txt @@ -0,0 +1,28677 @@ +4096 +0 10 +10 6 +16 2 +18 5 +23 7 +30 7 +37 4 +41 4 +45 3 +48 5 +53 7 +60 4 +64 4 +68 6 +74 7 +81 5 +86 11 +97 5 +102 5 +107 8 +115 4 +119 4 +123 6 +129 4 +133 5 +138 7 +145 4 +149 2 +151 12 +163 3 +166 6 +172 6 +178 7 +185 5 +190 11 +201 4 +205 6 +211 9 +220 3 +223 4 +227 5 +232 4 +236 5 +241 6 +247 10 +257 4 +261 5 +266 7 +273 5 +278 4 +282 8 +290 5 +295 8 +303 9 +312 4 +316 5 +321 5 +326 3 +329 8 +337 5 +342 10 +352 6 +358 4 +362 5 +367 5 +372 10 +382 6 +388 8 +396 8 +404 5 +409 5 +414 5 +419 8 +427 6 +433 8 +441 9 +450 5 +455 10 +465 5 +470 11 +481 5 +486 7 +493 8 +501 9 +510 4 +514 10 +524 9 +533 5 +538 5 +543 7 +550 3 +553 3 +556 2 +558 6 +564 8 +572 3 +575 4 +579 5 +584 11 +595 8 +603 7 +610 5 +615 7 +622 4 +626 7 +633 6 +639 5 +644 4 +648 5 +653 4 +657 8 +665 8 +673 10 +683 2 +685 5 +690 5 +695 6 +701 3 +704 5 +709 9 +718 10 +728 7 +735 7 +742 9 +751 3 +754 4 +758 9 +767 6 +773 10 +783 7 +790 4 +794 8 +802 4 +806 5 +811 5 +816 8 +824 7 +831 8 +839 10 +849 5 +854 5 +859 4 +863 4 +867 7 +874 9 +883 2 +885 10 +895 8 +903 5 +908 6 +914 5 +919 11 +930 2 +932 6 +938 2 +940 4 +944 6 +950 6 +956 5 +961 4 +965 3 +968 4 +972 1 +973 10 +983 7 +990 4 +994 6 +1000 9 +1009 6 +1015 10 +1025 7 +1032 7 +1039 5 +1044 5 +1049 9 +1058 4 +1062 5 +1067 4 +1071 6 +1077 6 +1083 7 +1090 9 +1099 2 +1101 4 +1105 3 +1108 9 +1117 7 +1124 4 +1128 9 +1137 9 +1146 4 +1150 11 +1161 6 +1167 8 +1175 6 +1181 7 +1188 8 +1196 4 +1200 7 +1207 8 +1215 10 +1225 3 +1228 6 +1234 3 +1237 4 +1241 5 +1246 3 +1249 1 +1250 4 +1254 6 +1260 4 +1264 11 +1275 7 +1282 9 +1291 8 +1299 5 +1304 6 +1310 8 +1318 9 +1327 6 +1333 7 +1340 10 +1350 7 +1357 8 +1365 10 +1375 6 +1381 2 +1383 10 +1393 5 +1398 8 +1406 9 +1415 4 +1419 5 +1424 3 +1427 4 +1431 4 +1435 9 +1444 6 +1450 9 +1459 6 +1465 4 +1469 6 +1475 9 +1484 8 +1492 7 +1499 9 +1508 2 +1510 3 +1513 8 +1521 6 +1527 5 +1532 9 +1541 6 +1547 5 +1552 9 +1561 12 +1573 2 +1575 3 +1578 7 +1585 6 +1591 5 +1596 10 +1606 9 +1615 9 +1624 1 +1625 4 +1629 6 +1635 2 +1637 14 +1651 2 +1653 4 +1657 4 +1661 5 +1666 7 +1673 6 +1679 3 +1682 13 +1695 5 +1700 7 +1707 8 +1715 3 +1718 5 +1723 6 +1729 7 +1736 6 +1742 7 +1749 2 +1751 7 +1758 5 +1763 4 +1767 4 +1771 6 +1777 2 +1779 3 +1782 9 +1791 7 +1798 4 +1802 8 +1810 7 +1817 6 +1823 6 +1829 4 +1833 7 +1840 8 +1848 2 +1850 14 +1864 9 +1873 6 +1879 6 +1885 6 +1891 2 +1893 8 +1901 5 +1906 8 +1914 4 +1918 4 +1922 3 +1925 8 +1933 4 +1937 4 +1941 6 +1947 3 +1950 8 +1958 7 +1965 6 +1971 4 +1975 5 +1980 6 +1986 4 +1990 6 +1996 10 +2006 5 +2011 5 +2016 5 +2021 7 +2028 5 +2033 6 +2039 7 +2046 4 +2050 6 +2056 16 +2072 6 +2078 11 +2089 11 +2100 3 +2103 5 +2108 8 +2116 4 +2120 7 +2127 2 +2129 10 +2139 6 +2145 7 +2152 8 +2160 6 +2166 5 +2171 5 +2176 2 +2178 4 +2182 5 +2187 5 +2192 1 +2193 7 +2200 8 +2208 7 +2215 8 +2223 8 +2231 5 +2236 9 +2245 3 +2248 5 +2253 6 +2259 2 +2261 4 +2265 4 +2269 8 +2277 5 +2282 8 +2290 6 +2296 6 +2302 4 +2306 5 +2311 7 +2318 5 +2323 4 +2327 8 +2335 12 +2347 1 +2348 5 +2353 8 +2361 3 +2364 6 +2370 4 +2374 7 +2381 4 +2385 8 +2393 4 +2397 2 +2399 5 +2404 5 +2409 6 +2415 6 +2421 5 +2426 8 +2434 5 +2439 6 +2445 6 +2451 6 +2457 2 +2459 4 +2463 3 +2466 6 +2472 5 +2477 5 +2482 10 +2492 6 +2498 4 +2502 9 +2511 4 +2515 4 +2519 6 +2525 9 +2534 7 +2541 6 +2547 4 +2551 6 +2557 5 +2562 3 +2565 6 +2571 6 +2577 7 +2584 4 +2588 10 +2598 8 +2606 6 +2612 6 +2618 4 +2622 7 +2629 7 +2636 6 +2642 2 +2644 4 +2648 12 +2660 6 +2666 13 +2679 11 +2690 9 +2699 2 +2701 5 +2706 6 +2712 6 +2718 3 +2721 7 +2728 3 +2731 6 +2737 11 +2748 2 +2750 7 +2757 4 +2761 5 +2766 4 +2770 6 +2776 4 +2780 6 +2786 5 +2791 6 +2797 4 +2801 9 +2810 7 +2817 6 +2823 8 +2831 8 +2839 13 +2852 7 +2859 6 +2865 6 +2871 4 +2875 7 +2882 9 +2891 11 +2902 5 +2907 9 +2916 4 +2920 5 +2925 3 +2928 4 +2932 4 +2936 5 +2941 2 +2943 9 +2952 3 +2955 13 +2968 4 +2972 5 +2977 4 +2981 8 +2989 10 +2999 5 +3004 8 +3012 5 +3017 4 +3021 4 +3025 11 +3036 5 +3041 6 +3047 7 +3054 5 +3059 5 +3064 6 +3070 9 +3079 2 +3081 4 +3085 5 +3090 11 +3101 5 +3106 3 +3109 5 +3114 5 +3119 6 +3125 8 +3133 6 +3139 4 +3143 5 +3148 7 +3155 6 +3161 8 +3169 5 +3174 4 +3178 6 +3184 6 +3190 6 +3196 5 +3201 4 +3205 6 +3211 8 +3219 7 +3226 6 +3232 3 +3235 5 +3240 7 +3247 6 +3253 11 +3264 6 +3270 4 +3274 3 +3277 1 +3278 2 +3280 8 +3288 7 +3295 8 +3303 8 +3311 5 +3316 9 +3325 9 +3334 7 +3341 3 +3344 7 +3351 8 +3359 5 +3364 1 +3365 4 +3369 2 +3371 5 +3376 7 +3383 8 +3391 2 +3393 5 +3398 5 +3403 12 +3415 4 +3419 6 +3425 5 +3430 4 +3434 8 +3442 6 +3448 4 +3452 3 +3455 7 +3462 4 +3466 6 +3472 5 +3477 7 +3484 8 +3492 6 +3498 6 +3504 11 +3515 6 +3521 2 +3523 10 +3533 3 +3536 7 +3543 8 +3551 4 +3555 11 +3566 5 +3571 8 +3579 6 +3585 8 +3593 6 +3599 5 +3604 7 +3611 2 +3613 5 +3618 2 +3620 4 +3624 10 +3634 4 +3638 8 +3646 5 +3651 4 +3655 6 +3661 5 +3666 11 +3677 10 +3687 4 +3691 6 +3697 2 +3699 6 +3705 6 +3711 4 +3715 7 +3722 4 +3726 6 +3732 9 +3741 4 +3745 6 +3751 7 +3758 10 +3768 3 +3771 12 +3783 2 +3785 7 +3792 4 +3796 8 +3804 8 +3812 4 +3816 5 +3821 10 +3831 6 +3837 6 +3843 5 +3848 6 +3854 7 +3861 6 +3867 3 +3870 5 +3875 5 +3880 7 +3887 12 +3899 9 +3908 4 +3912 6 +3918 3 +3921 6 +3927 4 +3931 8 +3939 6 +3945 9 +3954 11 +3965 10 +3975 7 +3982 7 +3989 8 +3997 8 +4005 6 +4011 3 +4014 6 +4020 10 +4030 5 +4035 9 +4044 6 +4050 3 +4053 7 +4060 2 +4062 4 +4066 3 +4069 4 +4073 7 +4080 11 +4091 3 +4094 6 +4100 7 +4107 4 +4111 7 +4118 7 +4125 7 +4132 9 +4141 6 +4147 5 +4152 3 +4155 9 +4164 8 +4172 5 +4177 5 +4182 7 +4189 7 +4196 7 +4203 7 +4210 4 +4214 6 +4220 3 +4223 4 +4227 3 +4230 4 +4234 4 +4238 8 +4246 5 +4251 5 +4256 3 +4259 7 +4266 5 +4271 3 +4274 4 +4278 6 +4284 5 +4289 4 +4293 9 +4302 9 +4311 5 +4316 5 +4321 6 +4327 5 +4332 9 +4341 5 +4346 5 +4351 4 +4355 5 +4360 8 +4368 6 +4374 15 +4389 7 +4396 2 +4398 7 +4405 7 +4412 9 +4421 4 +4425 8 +4433 6 +4439 6 +4445 5 +4450 6 +4456 7 +4463 5 +4468 4 +4472 9 +4481 4 +4485 7 +4492 9 +4501 3 +4504 15 +4519 8 +4527 10 +4537 5 +4542 2 +4544 6 +4550 3 +4553 5 +4558 5 +4563 8 +4571 9 +4580 8 +4588 7 +4595 10 +4605 9 +4614 10 +4624 7 +4631 3 +4634 5 +4639 6 +4645 5 +4650 5 +4655 10 +4665 10 +4675 9 +4684 3 +4687 6 +4693 7 +4700 5 +4705 9 +4714 6 +4720 7 +4727 6 +4733 8 +4741 12 +4753 7 +4760 5 +4765 9 +4774 4 +4778 5 +4783 5 +4788 9 +4797 7 +4804 6 +4810 5 +4815 9 +4824 3 +4827 5 +4832 5 +4837 3 +4840 7 +4847 3 +4850 4 +4854 7 +4861 9 +4870 7 +4877 8 +4885 6 +4891 6 +4897 5 +4902 10 +4912 4 +4916 4 +4920 4 +4924 3 +4927 5 +4932 7 +4939 4 +4943 3 +4946 5 +4951 5 +4956 3 +4959 3 +4962 1 +4963 6 +4969 4 +4973 10 +4983 4 +4987 7 +4994 4 +4998 4 +5002 4 +5006 6 +5012 7 +5019 7 +5026 8 +5034 12 +5046 7 +5053 5 +5058 7 +5065 8 +5073 3 +5076 6 +5082 5 +5087 3 +5090 6 +5096 3 +5099 4 +5103 4 +5107 6 +5113 7 +5120 5 +5125 3 +5128 2 +5130 5 +5135 6 +5141 6 +5147 2 +5149 7 +5156 9 +5165 8 +5173 6 +5179 4 +5183 6 +5189 6 +5195 8 +5203 3 +5206 9 +5215 3 +5218 6 +5224 13 +5237 9 +5246 6 +5252 7 +5259 11 +5270 5 +5275 9 +5284 6 +5290 4 +5294 6 +5300 9 +5309 7 +5316 4 +5320 5 +5325 3 +5328 1 +5329 4 +5333 4 +5337 3 +5340 3 +5343 2 +5345 4 +5349 7 +5356 5 +5361 11 +5372 6 +5378 8 +5386 7 +5393 5 +5398 2 +5400 9 +5409 8 +5417 2 +5419 5 +5424 3 +5427 9 +5436 6 +5442 7 +5449 5 +5454 7 +5461 6 +5467 4 +5471 4 +5475 8 +5483 3 +5486 4 +5490 13 +5503 7 +5510 6 +5516 2 +5518 6 +5524 8 +5532 8 +5540 7 +5547 9 +5556 4 +5560 4 +5564 7 +5571 2 +5573 10 +5583 2 +5585 8 +5593 4 +5597 7 +5604 8 +5612 8 +5620 5 +5625 3 +5628 6 +5634 5 +5639 9 +5648 6 +5654 6 +5660 3 +5663 9 +5672 9 +5681 7 +5688 8 +5696 6 +5702 7 +5709 2 +5711 8 +5719 4 +5723 6 +5729 3 +5732 9 +5741 7 +5748 6 +5754 8 +5762 6 +5768 4 +5772 6 +5778 8 +5786 3 +5789 10 +5799 10 +5809 5 +5814 9 +5823 5 +5828 10 +5838 9 +5847 7 +5854 5 +5859 4 +5863 7 +5870 4 +5874 5 +5879 6 +5885 8 +5893 8 +5901 7 +5908 4 +5912 2 +5914 6 +5920 5 +5925 7 +5932 6 +5938 3 +5941 6 +5947 7 +5954 5 +5959 8 +5967 5 +5972 7 +5979 6 +5985 4 +5989 5 +5994 5 +5999 3 +6002 2 +6004 5 +6009 7 +6016 11 +6027 7 +6034 6 +6040 3 +6043 6 +6049 11 +6060 10 +6070 2 +6072 9 +6081 5 +6086 2 +6088 4 +6092 7 +6099 6 +6105 5 +6110 5 +6115 5 +6120 3 +6123 3 +6126 5 +6131 7 +6138 5 +6143 11 +6154 4 +6158 8 +6166 8 +6174 9 +6183 4 +6187 6 +6193 5 +6198 4 +6202 6 +6208 5 +6213 6 +6219 8 +6227 6 +6233 6 +6239 5 +6244 4 +6248 4 +6252 4 +6256 6 +6262 7 +6269 4 +6273 6 +6279 11 +6290 5 +6295 9 +6304 2 +6306 8 +6314 4 +6318 3 +6321 2 +6323 9 +6332 9 +6341 2 +6343 8 +6351 9 +6360 5 +6365 4 +6369 5 +6374 3 +6377 6 +6383 12 +6395 7 +6402 3 +6405 9 +6414 7 +6421 7 +6428 5 +6433 6 +6439 5 +6444 6 +6450 2 +6452 6 +6458 3 +6461 9 +6470 6 +6476 7 +6483 11 +6494 9 +6503 5 +6508 8 +6516 4 +6520 7 +6527 5 +6532 2 +6534 4 +6538 4 +6542 7 +6549 5 +6554 6 +6560 3 +6563 4 +6567 7 +6574 5 +6579 6 +6585 5 +6590 7 +6597 11 +6608 8 +6616 5 +6621 16 +6637 5 +6642 12 +6654 7 +6661 6 +6667 10 +6677 5 +6682 7 +6689 1 +6690 6 +6696 8 +6704 5 +6709 10 +6719 5 +6724 3 +6727 6 +6733 5 +6738 2 +6740 4 +6744 5 +6749 12 +6761 5 +6766 10 +6776 8 +6784 7 +6791 6 +6797 6 +6803 3 +6806 5 +6811 6 +6817 2 +6819 11 +6830 7 +6837 7 +6844 8 +6852 6 +6858 8 +6866 6 +6872 4 +6876 3 +6879 7 +6886 8 +6894 6 +6900 6 +6906 3 +6909 8 +6917 5 +6922 7 +6929 4 +6933 6 +6939 7 +6946 5 +6951 5 +6956 5 +6961 9 +6970 8 +6978 5 +6983 8 +6991 5 +6996 6 +7002 7 +7009 3 +7012 8 +7020 10 +7030 3 +7033 6 +7039 6 +7045 8 +7053 5 +7058 7 +7065 5 +7070 4 +7074 9 +7083 10 +7093 6 +7099 5 +7104 4 +7108 12 +7120 8 +7128 2 +7130 3 +7133 2 +7135 11 +7146 12 +7158 6 +7164 9 +7173 12 +7185 8 +7193 5 +7198 4 +7202 7 +7209 3 +7212 4 +7216 8 +7224 3 +7227 4 +7231 5 +7236 7 +7243 5 +7248 7 +7255 3 +7258 10 +7268 8 +7276 3 +7279 8 +7287 11 +7298 2 +7300 8 +7308 6 +7314 6 +7320 9 +7329 4 +7333 11 +7344 6 +7350 4 +7354 5 +7359 4 +7363 9 +7372 1 +7373 10 +7383 4 +7387 8 +7395 7 +7402 8 +7410 9 +7419 4 +7423 3 +7426 6 +7432 5 +7437 7 +7444 9 +7453 8 +7461 6 +7467 10 +7477 8 +7485 13 +7498 4 +7502 6 +7508 7 +7515 10 +7525 7 +7532 4 +7536 3 +7539 3 +7542 10 +7552 5 +7557 6 +7563 6 +7569 3 +7572 7 +7579 9 +7588 5 +7593 8 +7601 7 +7608 7 +7615 7 +7622 5 +7627 5 +7632 6 +7638 7 +7645 6 +7651 6 +7657 10 +7667 6 +7673 4 +7677 5 +7682 8 +7690 6 +7696 8 +7704 9 +7713 2 +7715 3 +7718 9 +7727 4 +7731 4 +7735 6 +7741 6 +7747 9 +7756 6 +7762 3 +7765 4 +7769 12 +7781 4 +7785 4 +7789 6 +7795 7 +7802 3 +7805 1 +7806 7 +7813 2 +7815 4 +7819 3 +7822 5 +7827 9 +7836 8 +7844 9 +7853 8 +7861 6 +7867 2 +7869 4 +7873 8 +7881 5 +7886 9 +7895 3 +7898 10 +7908 2 +7910 8 +7918 6 +7924 7 +7931 4 +7935 7 +7942 3 +7945 6 +7951 8 +7959 6 +7965 11 +7976 6 +7982 9 +7991 4 +7995 2 +7997 7 +8004 5 +8009 5 +8014 7 +8021 8 +8029 7 +8036 4 +8040 4 +8044 11 +8055 11 +8066 6 +8072 6 +8078 9 +8087 3 +8090 6 +8096 9 +8105 6 +8111 4 +8115 6 +8121 4 +8125 4 +8129 5 +8134 8 +8142 10 +8152 5 +8157 4 +8161 6 +8167 7 +8174 6 +8180 3 +8183 6 +8189 5 +8194 10 +8204 4 +8208 6 +8214 5 +8219 3 +8222 5 +8227 8 +8235 8 +8243 4 +8247 4 +8251 4 +8255 11 +8266 10 +8276 6 +8282 6 +8288 8 +8296 3 +8299 4 +8303 6 +8309 5 +8314 9 +8323 3 +8326 3 +8329 9 +8338 6 +8344 7 +8351 5 +8356 4 +8360 7 +8367 11 +8378 4 +8382 6 +8388 9 +8397 8 +8405 8 +8413 4 +8417 6 +8423 9 +8432 1 +8433 3 +8436 7 +8443 5 +8448 4 +8452 6 +8458 3 +8461 4 +8465 4 +8469 5 +8474 5 +8479 4 +8483 5 +8488 5 +8493 3 +8496 7 +8503 5 +8508 9 +8517 6 +8523 3 +8526 3 +8529 6 +8535 4 +8539 7 +8546 8 +8554 7 +8561 4 +8565 5 +8570 6 +8576 6 +8582 6 +8588 6 +8594 6 +8600 6 +8606 4 +8610 3 +8613 5 +8618 4 +8622 8 +8630 2 +8632 8 +8640 5 +8645 6 +8651 4 +8655 5 +8660 4 +8664 7 +8671 3 +8674 7 +8681 3 +8684 5 +8689 7 +8696 3 +8699 5 +8704 5 +8709 5 +8714 6 +8720 9 +8729 5 +8734 6 +8740 2 +8742 4 +8746 9 +8755 5 +8760 8 +8768 4 +8772 10 +8782 5 +8787 7 +8794 7 +8801 3 +8804 4 +8808 5 +8813 10 +8823 4 +8827 8 +8835 8 +8843 5 +8848 4 +8852 4 +8856 5 +8861 7 +8868 10 +8878 5 +8883 3 +8886 2 +8888 4 +8892 8 +8900 5 +8905 3 +8908 4 +8912 7 +8919 12 +8931 9 +8940 6 +8946 5 +8951 5 +8956 7 +8963 12 +8975 10 +8985 8 +8993 9 +9002 10 +9012 6 +9018 11 +9029 5 +9034 4 +9038 9 +9047 6 +9053 12 +9065 6 +9071 6 +9077 2 +9079 1 +9080 6 +9086 3 +9089 6 +9095 8 +9103 5 +9108 6 +9114 10 +9124 2 +9126 10 +9136 5 +9141 4 +9145 4 +9149 4 +9153 4 +9157 8 +9165 7 +9172 12 +9184 2 +9186 5 +9191 6 +9197 4 +9201 4 +9205 5 +9210 5 +9215 5 +9220 14 +9234 5 +9239 4 +9243 5 +9248 3 +9251 3 +9254 7 +9261 5 +9266 6 +9272 7 +9279 6 +9285 5 +9290 6 +9296 4 +9300 7 +9307 8 +9315 5 +9320 2 +9322 4 +9326 7 +9333 9 +9342 7 +9349 4 +9353 7 +9360 3 +9363 2 +9365 3 +9368 7 +9375 5 +9380 4 +9384 4 +9388 4 +9392 3 +9395 3 +9398 5 +9403 9 +9412 7 +9419 4 +9423 5 +9428 3 +9431 6 +9437 6 +9443 2 +9445 7 +9452 4 +9456 9 +9465 4 +9469 5 +9474 6 +9480 4 +9484 12 +9496 6 +9502 7 +9509 8 +9517 6 +9523 1 +9524 5 +9529 5 +9534 5 +9539 5 +9544 4 +9548 3 +9551 11 +9562 4 +9566 6 +9572 4 +9576 6 +9582 5 +9587 4 +9591 3 +9594 3 +9597 3 +9600 9 +9609 6 +9615 4 +9619 7 +9626 5 +9631 4 +9635 4 +9639 8 +9647 6 +9653 9 +9662 5 +9667 7 +9674 6 +9680 8 +9688 2 +9690 6 +9696 4 +9700 5 +9705 8 +9713 6 +9719 4 +9723 9 +9732 9 +9741 9 +9750 2 +9752 3 +9755 6 +9761 8 +9769 4 +9773 7 +9780 3 +9783 5 +9788 4 +9792 1 +9793 8 +9801 6 +9807 11 +9818 4 +9822 8 +9830 5 +9835 8 +9843 6 +9849 6 +9855 8 +9863 9 +9872 7 +9879 2 +9881 5 +9886 6 +9892 5 +9897 4 +9901 14 +9915 5 +9920 5 +9925 8 +9933 10 +9943 5 +9948 5 +9953 5 +9958 5 +9963 5 +9968 7 +9975 3 +9978 4 +9982 6 +9988 5 +9993 6 +9999 11 +10010 7 +10017 5 +10022 4 +10026 6 +10032 7 +10039 5 +10044 6 +10050 4 +10054 7 +10061 9 +10070 7 +10077 4 +10081 6 +10087 3 +10090 5 +10095 6 +10101 4 +10105 13 +10118 5 +10123 4 +10127 10 +10137 8 +10145 6 +10151 9 +10160 3 +10163 2 +10165 12 +10177 10 +10187 9 +10196 3 +10199 11 +10210 13 +10223 5 +10228 7 +10235 6 +10241 5 +10246 2 +10248 3 +10251 6 +10257 9 +10266 6 +10272 6 +10278 8 +10286 7 +10293 2 +10295 3 +10298 9 +10307 5 +10312 5 +10317 6 +10323 5 +10328 9 +10337 6 +10343 7 +10350 9 +10359 7 +10366 5 +10371 7 +10378 9 +10387 4 +10391 7 +10398 6 +10404 2 +10406 4 +10410 10 +10420 9 +10429 10 +10439 4 +10443 4 +10447 4 +10451 3 +10454 6 +10460 5 +10465 8 +10473 6 +10479 6 +10485 6 +10491 7 +10498 7 +10505 11 +10516 6 +10522 9 +10531 4 +10535 5 +10540 7 +10547 6 +10553 3 +10556 5 +10561 4 +10565 11 +10576 6 +10582 7 +10589 3 +10592 4 +10596 5 +10601 8 +10609 3 +10612 7 +10619 9 +10628 5 +10633 3 +10636 11 +10647 5 +10652 5 +10657 8 +10665 5 +10670 8 +10678 5 +10683 2 +10685 9 +10694 7 +10701 6 +10707 5 +10712 5 +10717 7 +10724 5 +10729 3 +10732 3 +10735 7 +10742 5 +10747 4 +10751 9 +10760 7 +10767 11 +10778 9 +10787 5 +10792 6 +10798 6 +10804 5 +10809 5 +10814 6 +10820 5 +10825 5 +10830 11 +10841 6 +10847 5 +10852 5 +10857 7 +10864 5 +10869 12 +10881 7 +10888 7 +10895 4 +10899 2 +10901 5 +10906 6 +10912 9 +10921 2 +10923 7 +10930 5 +10935 4 +10939 7 +10946 10 +10956 10 +10966 4 +10970 7 +10977 6 +10983 7 +10990 6 +10996 2 +10998 3 +11001 5 +11006 4 +11010 6 +11016 5 +11021 5 +11026 6 +11032 6 +11038 3 +11041 9 +11050 7 +11057 5 +11062 2 +11064 5 +11069 5 +11074 8 +11082 9 +11091 4 +11095 6 +11101 6 +11107 9 +11116 5 +11121 5 +11126 4 +11130 2 +11132 7 +11139 4 +11143 6 +11149 7 +11156 3 +11159 5 +11164 4 +11168 1 +11169 8 +11177 7 +11184 5 +11189 6 +11195 2 +11197 7 +11204 4 +11208 8 +11216 4 +11220 5 +11225 8 +11233 9 +11242 3 +11245 5 +11250 11 +11261 6 +11267 4 +11271 9 +11280 11 +11291 4 +11295 5 +11300 6 +11306 9 +11315 1 +11316 5 +11321 7 +11328 4 +11332 3 +11335 3 +11338 5 +11343 5 +11348 7 +11355 2 +11357 5 +11362 5 +11367 9 +11376 7 +11383 6 +11389 9 +11398 8 +11406 9 +11415 5 +11420 16 +11436 1 +11437 8 +11445 7 +11452 6 +11458 11 +11469 7 +11476 5 +11481 11 +11492 3 +11495 3 +11498 5 +11503 3 +11506 7 +11513 7 +11520 5 +11525 7 +11532 5 +11537 11 +11548 3 +11551 2 +11553 6 +11559 7 +11566 6 +11572 6 +11578 8 +11586 7 +11593 7 +11600 6 +11606 7 +11613 9 +11622 10 +11632 7 +11639 10 +11649 8 +11657 6 +11663 7 +11670 5 +11675 11 +11686 10 +11696 13 +11709 6 +11715 6 +11721 12 +11733 5 +11738 3 +11741 4 +11745 6 +11751 6 +11757 13 +11770 6 +11776 6 +11782 5 +11787 2 +11789 6 +11795 5 +11800 4 +11804 7 +11811 8 +11819 3 +11822 7 +11829 7 +11836 7 +11843 9 +11852 2 +11854 2 +11856 7 +11863 5 +11868 6 +11874 4 +11878 7 +11885 2 +11887 4 +11891 4 +11895 3 +11898 5 +11903 6 +11909 3 +11912 7 +11919 6 +11925 8 +11933 2 +11935 9 +11944 5 +11949 6 +11955 5 +11960 3 +11963 13 +11976 8 +11984 6 +11990 3 +11993 4 +11997 3 +12000 7 +12007 6 +12013 9 +12022 4 +12026 11 +12037 4 +12041 6 +12047 6 +12053 9 +12062 4 +12066 3 +12069 6 +12075 7 +12082 3 +12085 5 +12090 8 +12098 6 +12104 4 +12108 8 +12116 4 +12120 11 +12131 6 +12137 7 +12144 3 +12147 8 +12155 8 +12163 3 +12166 6 +12172 5 +12177 3 +12180 5 +12185 6 +12191 3 +12194 7 +12201 8 +12209 3 +12212 2 +12214 5 +12219 4 +12223 2 +12225 8 +12233 4 +12237 5 +12242 3 +12245 5 +12250 6 +12256 5 +12261 8 +12269 4 +12273 6 +12279 4 +12283 7 +12290 5 +12295 8 +12303 5 +12308 3 +12311 6 +12317 6 +12323 4 +12327 7 +12334 7 +12341 1 +12342 8 +12350 4 +12354 4 +12358 6 +12364 5 +12369 13 +12382 3 +12385 7 +12392 4 +12396 7 +12403 10 +12413 8 +12421 9 +12430 9 +12439 6 +12445 6 +12451 10 +12461 6 +12467 8 +12475 3 +12478 9 +12487 11 +12498 4 +12502 6 +12508 4 +12512 4 +12516 4 +12520 5 +12525 8 +12533 4 +12537 5 +12542 5 +12547 6 +12553 4 +12557 8 +12565 8 +12573 6 +12579 5 +12584 5 +12589 6 +12595 4 +12599 4 +12603 2 +12605 8 +12613 4 +12617 5 +12622 4 +12626 6 +12632 5 +12637 12 +12649 5 +12654 6 +12660 9 +12669 5 +12674 5 +12679 7 +12686 6 +12692 5 +12697 4 +12701 6 +12707 5 +12712 5 +12717 6 +12723 5 +12728 8 +12736 10 +12746 6 +12752 7 +12759 6 +12765 4 +12769 6 +12775 6 +12781 13 +12794 6 +12800 11 +12811 4 +12815 8 +12823 7 +12830 7 +12837 6 +12843 6 +12849 7 +12856 5 +12861 10 +12871 10 +12881 8 +12889 9 +12898 4 +12902 6 +12908 9 +12917 8 +12925 9 +12934 4 +12938 4 +12942 7 +12949 2 +12951 7 +12958 1 +12959 9 +12968 8 +12976 8 +12984 1 +12985 4 +12989 4 +12993 4 +12997 8 +13005 4 +13009 4 +13013 8 +13021 9 +13030 6 +13036 8 +13044 3 +13047 8 +13055 5 +13060 7 +13067 8 +13075 7 +13082 2 +13084 5 +13089 9 +13098 5 +13103 7 +13110 6 +13116 6 +13122 6 +13128 6 +13134 7 +13141 5 +13146 8 +13154 12 +13166 4 +13170 6 +13176 4 +13180 6 +13186 5 +13191 3 +13194 6 +13200 9 +13209 4 +13213 5 +13218 8 +13226 6 +13232 3 +13235 8 +13243 7 +13250 8 +13258 5 +13263 5 +13268 4 +13272 7 +13279 3 +13282 11 +13293 7 +13300 6 +13306 5 +13311 5 +13316 6 +13322 9 +13331 2 +13333 6 +13339 7 +13346 7 +13353 6 +13359 6 +13365 5 +13370 4 +13374 6 +13380 9 +13389 11 +13400 5 +13405 8 +13413 4 +13417 4 +13421 9 +13430 4 +13434 9 +13443 3 +13446 7 +13453 6 +13459 6 +13465 1 +13466 7 +13473 7 +13480 6 +13486 5 +13491 7 +13498 3 +13501 6 +13507 5 +13512 4 +13516 8 +13524 2 +13526 4 +13530 5 +13535 3 +13538 5 +13543 5 +13548 5 +13553 3 +13556 4 +13560 7 +13567 4 +13571 4 +13575 8 +13583 9 +13592 6 +13598 7 +13605 1 +13606 9 +13615 9 +13624 10 +13634 4 +13638 3 +13641 9 +13650 8 +13658 5 +13663 7 +13670 4 +13674 12 +13686 2 +13688 3 +13691 5 +13696 5 +13701 10 +13711 4 +13715 4 +13719 7 +13726 5 +13731 4 +13735 9 +13744 7 +13751 5 +13756 4 +13760 8 +13768 8 +13776 9 +13785 7 +13792 7 +13799 6 +13805 6 +13811 7 +13818 11 +13829 7 +13836 6 +13842 5 +13847 6 +13853 7 +13860 10 +13870 4 +13874 3 +13877 4 +13881 4 +13885 6 +13891 6 +13897 8 +13905 10 +13915 9 +13924 6 +13930 2 +13932 4 +13936 6 +13942 10 +13952 8 +13960 4 +13964 12 +13976 6 +13982 5 +13987 6 +13993 5 +13998 3 +14001 7 +14008 7 +14015 10 +14025 3 +14028 6 +14034 6 +14040 2 +14042 3 +14045 5 +14050 6 +14056 4 +14060 7 +14067 9 +14076 1 +14077 6 +14083 5 +14088 4 +14092 7 +14099 9 +14108 2 +14110 14 +14124 7 +14131 4 +14135 7 +14142 8 +14150 3 +14153 5 +14158 7 +14165 11 +14176 6 +14182 8 +14190 5 +14195 8 +14203 6 +14209 5 +14214 5 +14219 2 +14221 4 +14225 3 +14228 4 +14232 5 +14237 5 +14242 5 +14247 3 +14250 9 +14259 7 +14266 4 +14270 6 +14276 6 +14282 3 +14285 2 +14287 8 +14295 6 +14301 6 +14307 2 +14309 7 +14316 6 +14322 5 +14327 9 +14336 3 +14339 6 +14345 7 +14352 2 +14354 7 +14361 6 +14367 8 +14375 6 +14381 6 +14387 2 +14389 3 +14392 4 +14396 5 +14401 3 +14404 6 +14410 7 +14417 4 +14421 4 +14425 5 +14430 4 +14434 11 +14445 8 +14453 5 +14458 5 +14463 8 +14471 3 +14474 5 +14479 5 +14484 15 +14499 6 +14505 7 +14512 5 +14517 5 +14522 2 +14524 3 +14527 2 +14529 9 +14538 9 +14547 6 +14553 4 +14557 11 +14568 6 +14574 7 +14581 5 +14586 2 +14588 3 +14591 8 +14599 3 +14602 5 +14607 5 +14612 6 +14618 2 +14620 4 +14624 3 +14627 9 +14636 5 +14641 2 +14643 12 +14655 7 +14662 4 +14666 8 +14674 4 +14678 9 +14687 5 +14692 6 +14698 9 +14707 3 +14710 9 +14719 4 +14723 5 +14728 5 +14733 2 +14735 5 +14740 4 +14744 11 +14755 7 +14762 7 +14769 12 +14781 4 +14785 8 +14793 8 +14801 5 +14806 4 +14810 4 +14814 6 +14820 8 +14828 9 +14837 4 +14841 4 +14845 6 +14851 3 +14854 6 +14860 9 +14869 7 +14876 8 +14884 7 +14891 6 +14897 6 +14903 5 +14908 6 +14914 8 +14922 5 +14927 3 +14930 7 +14937 4 +14941 8 +14949 8 +14957 7 +14964 7 +14971 7 +14978 7 +14985 8 +14993 6 +14999 6 +15005 10 +15015 5 +15020 4 +15024 8 +15032 7 +15039 3 +15042 6 +15048 7 +15055 5 +15060 9 +15069 13 +15082 6 +15088 5 +15093 4 +15097 5 +15102 6 +15108 6 +15114 6 +15120 10 +15130 7 +15137 9 +15146 5 +15151 8 +15159 9 +15168 10 +15178 10 +15188 4 +15192 4 +15196 4 +15200 7 +15207 6 +15213 12 +15225 3 +15228 7 +15235 3 +15238 6 +15244 8 +15252 5 +15257 10 +15267 7 +15274 6 +15280 2 +15282 5 +15287 2 +15289 4 +15293 3 +15296 5 +15301 8 +15309 9 +15318 4 +15322 3 +15325 4 +15329 5 +15334 3 +15337 5 +15342 2 +15344 4 +15348 11 +15359 3 +15362 8 +15370 7 +15377 4 +15381 7 +15388 7 +15395 5 +15400 6 +15406 9 +15415 4 +15419 10 +15429 9 +15438 4 +15442 2 +15444 6 +15450 6 +15456 12 +15468 7 +15475 5 +15480 6 +15486 3 +15489 5 +15494 6 +15500 5 +15505 3 +15508 3 +15511 1 +15512 10 +15522 8 +15530 6 +15536 4 +15540 3 +15543 8 +15551 5 +15556 4 +15560 9 +15569 10 +15579 6 +15585 11 +15596 10 +15606 9 +15615 12 +15627 9 +15636 4 +15640 4 +15644 4 +15648 11 +15659 4 +15663 5 +15668 4 +15672 5 +15677 5 +15682 1 +15683 3 +15686 4 +15690 7 +15697 7 +15704 6 +15710 6 +15716 4 +15720 4 +15724 10 +15734 7 +15741 5 +15746 8 +15754 5 +15759 5 +15764 4 +15768 6 +15774 8 +15782 2 +15784 6 +15790 5 +15795 4 +15799 5 +15804 5 +15809 9 +15818 6 +15824 6 +15830 3 +15833 10 +15843 7 +15850 4 +15854 5 +15859 6 +15865 9 +15874 4 +15878 4 +15882 5 +15887 7 +15894 5 +15899 6 +15905 8 +15913 8 +15921 4 +15925 6 +15931 10 +15941 7 +15948 4 +15952 5 +15957 7 +15964 10 +15974 1 +15975 1 +15976 6 +15982 2 +15984 11 +15995 6 +16001 3 +16004 4 +16008 5 +16013 6 +16019 6 +16025 11 +16036 4 +16040 3 +16043 4 +16047 4 +16051 4 +16055 6 +16061 3 +16064 4 +16068 3 +16071 7 +16078 10 +16088 11 +16099 5 +16104 7 +16111 8 +16119 8 +16127 6 +16133 3 +16136 3 +16139 8 +16147 4 +16151 4 +16155 11 +16166 6 +16172 4 +16176 12 +16188 5 +16193 2 +16195 2 +16197 2 +16199 7 +16206 1 +16207 8 +16215 7 +16222 4 +16226 6 +16232 6 +16238 7 +16245 8 +16253 6 +16259 6 +16265 4 +16269 5 +16274 5 +16279 7 +16286 3 +16289 9 +16298 4 +16302 5 +16307 7 +16314 6 +16320 5 +16325 4 +16329 8 +16337 6 +16343 5 +16348 7 +16355 3 +16358 3 +16361 4 +16365 6 +16371 4 +16375 9 +16384 4 +16388 5 +16393 3 +16396 7 +16403 5 +16408 9 +16417 9 +16426 7 +16433 7 +16440 9 +16449 3 +16452 5 +16457 1 +16458 10 +16468 10 +16478 9 +16487 4 +16491 6 +16497 9 +16506 11 +16517 7 +16524 9 +16533 6 +16539 9 +16548 8 +16556 8 +16564 5 +16569 8 +16577 4 +16581 4 +16585 5 +16590 5 +16595 9 +16604 7 +16611 8 +16619 3 +16622 12 +16634 13 +16647 3 +16650 2 +16652 4 +16656 7 +16663 7 +16670 4 +16674 3 +16677 6 +16683 6 +16689 6 +16695 5 +16700 10 +16710 3 +16713 7 +16720 6 +16726 6 +16732 6 +16738 12 +16750 5 +16755 3 +16758 4 +16762 4 +16766 10 +16776 6 +16782 10 +16792 5 +16797 5 +16802 4 +16806 4 +16810 7 +16817 2 +16819 6 +16825 7 +16832 8 +16840 9 +16849 5 +16854 3 +16857 10 +16867 6 +16873 8 +16881 7 +16888 8 +16896 10 +16906 9 +16915 6 +16921 3 +16924 7 +16931 5 +16936 6 +16942 7 +16949 11 +16960 3 +16963 8 +16971 6 +16977 8 +16985 4 +16989 8 +16997 8 +17005 5 +17010 3 +17013 6 +17019 5 +17024 4 +17028 7 +17035 2 +17037 7 +17044 3 +17047 5 +17052 5 +17057 3 +17060 8 +17068 6 +17074 8 +17082 4 +17086 6 +17092 9 +17101 5 +17106 4 +17110 6 +17116 6 +17122 7 +17129 8 +17137 7 +17144 7 +17151 9 +17160 6 +17166 3 +17169 3 +17172 4 +17176 5 +17181 4 +17185 4 +17189 4 +17193 7 +17200 14 +17214 6 +17220 4 +17224 5 +17229 5 +17234 8 +17242 10 +17252 8 +17260 4 +17264 6 +17270 12 +17282 7 +17289 9 +17298 10 +17308 6 +17314 5 +17319 5 +17324 4 +17328 4 +17332 7 +17339 4 +17343 8 +17351 4 +17355 7 +17362 8 +17370 5 +17375 4 +17379 5 +17384 4 +17388 8 +17396 5 +17401 5 +17406 6 +17412 4 +17416 6 +17422 6 +17428 9 +17437 7 +17444 8 +17452 4 +17456 3 +17459 4 +17463 9 +17472 5 +17477 8 +17485 5 +17490 6 +17496 6 +17502 8 +17510 6 +17516 8 +17524 5 +17529 8 +17537 5 +17542 6 +17548 7 +17555 5 +17560 4 +17564 5 +17569 6 +17575 4 +17579 4 +17583 3 +17586 4 +17590 13 +17603 4 +17607 8 +17615 2 +17617 19 +17636 7 +17643 3 +17646 6 +17652 7 +17659 6 +17665 3 +17668 5 +17673 7 +17680 5 +17685 7 +17692 8 +17700 4 +17704 5 +17709 2 +17711 4 +17715 5 +17720 11 +17731 5 +17736 11 +17747 6 +17753 3 +17756 5 +17761 5 +17766 13 +17779 4 +17783 5 +17788 8 +17796 5 +17801 10 +17811 6 +17817 9 +17826 3 +17829 7 +17836 7 +17843 4 +17847 3 +17850 6 +17856 6 +17862 8 +17870 3 +17873 5 +17878 4 +17882 7 +17889 5 +17894 11 +17905 6 +17911 4 +17915 5 +17920 7 +17927 3 +17930 9 +17939 7 +17946 9 +17955 4 +17959 7 +17966 5 +17971 5 +17976 5 +17981 18 +17999 8 +18007 3 +18010 6 +18016 7 +18023 3 +18026 8 +18034 7 +18041 8 +18049 5 +18054 4 +18058 10 +18068 2 +18070 9 +18079 5 +18084 5 +18089 6 +18095 4 +18099 3 +18102 11 +18113 5 +18118 6 +18124 4 +18128 2 +18130 9 +18139 5 +18144 11 +18155 7 +18162 3 +18165 5 +18170 4 +18174 4 +18178 5 +18183 6 +18189 6 +18195 6 +18201 6 +18207 9 +18216 4 +18220 9 +18229 3 +18232 5 +18237 6 +18243 7 +18250 8 +18258 4 +18262 11 +18273 5 +18278 7 +18285 3 +18288 3 +18291 7 +18298 6 +18304 4 +18308 2 +18310 2 +18312 10 +18322 5 +18327 6 +18333 3 +18336 9 +18345 3 +18348 5 +18353 9 +18362 6 +18368 5 +18373 6 +18379 5 +18384 10 +18394 6 +18400 3 +18403 4 +18407 7 +18414 5 +18419 6 +18425 6 +18431 5 +18436 4 +18440 5 +18445 8 +18453 11 +18464 10 +18474 10 +18484 5 +18489 3 +18492 9 +18501 9 +18510 3 +18513 8 +18521 7 +18528 4 +18532 3 +18535 5 +18540 7 +18547 6 +18553 3 +18556 7 +18563 7 +18570 8 +18578 4 +18582 3 +18585 12 +18597 6 +18603 8 +18611 7 +18618 5 +18623 4 +18627 5 +18632 10 +18642 5 +18647 5 +18652 4 +18656 7 +18663 9 +18672 8 +18680 5 +18685 5 +18690 3 +18693 7 +18700 8 +18708 6 +18714 10 +18724 6 +18730 7 +18737 2 +18739 4 +18743 9 +18752 6 +18758 5 +18763 8 +18771 3 +18774 13 +18787 8 +18795 9 +18804 5 +18809 4 +18813 5 +18818 5 +18823 5 +18828 4 +18832 8 +18840 2 +18842 7 +18849 6 +18855 8 +18863 8 +18871 6 +18877 5 +18882 9 +18891 5 +18896 11 +18907 8 +18915 3 +18918 5 +18923 8 +18931 7 +18938 6 +18944 5 +18949 2 +18951 4 +18955 7 +18962 6 +18968 5 +18973 5 +18978 5 +18983 10 +18993 6 +18999 9 +19008 9 +19017 5 +19022 6 +19028 4 +19032 7 +19039 5 +19044 4 +19048 7 +19055 7 +19062 2 +19064 12 +19076 6 +19082 5 +19087 3 +19090 8 +19098 3 +19101 5 +19106 7 +19113 3 +19116 5 +19121 4 +19125 6 +19131 4 +19135 5 +19140 8 +19148 5 +19153 7 +19160 9 +19169 4 +19173 8 +19181 2 +19183 5 +19188 6 +19194 5 +19199 7 +19206 1 +19207 3 +19210 2 +19212 6 +19218 7 +19225 3 +19228 4 +19232 8 +19240 6 +19246 10 +19256 5 +19261 8 +19269 9 +19278 9 +19287 3 +19290 6 +19296 3 +19299 2 +19301 9 +19310 3 +19313 8 +19321 4 +19325 6 +19331 7 +19338 8 +19346 5 +19351 10 +19361 2 +19363 6 +19369 4 +19373 5 +19378 8 +19386 10 +19396 4 +19400 8 +19408 7 +19415 5 +19420 7 +19427 6 +19433 5 +19438 6 +19444 5 +19449 6 +19455 7 +19462 5 +19467 4 +19471 8 +19479 2 +19481 6 +19487 4 +19491 3 +19494 4 +19498 3 +19501 2 +19503 7 +19510 6 +19516 2 +19518 8 +19526 9 +19535 8 +19543 2 +19545 3 +19548 10 +19558 4 +19562 7 +19569 5 +19574 5 +19579 5 +19584 6 +19590 3 +19593 6 +19599 6 +19605 4 +19609 6 +19615 8 +19623 5 +19628 7 +19635 6 +19641 6 +19647 4 +19651 8 +19659 6 +19665 4 +19669 3 +19672 9 +19681 6 +19687 6 +19693 4 +19697 6 +19703 8 +19711 6 +19717 6 +19723 7 +19730 3 +19733 5 +19738 4 +19742 5 +19747 5 +19752 11 +19763 8 +19771 6 +19777 9 +19786 6 +19792 11 +19803 4 +19807 8 +19815 6 +19821 8 +19829 7 +19836 9 +19845 3 +19848 5 +19853 5 +19858 10 +19868 3 +19871 4 +19875 10 +19885 5 +19890 8 +19898 5 +19903 5 +19908 5 +19913 4 +19917 6 +19923 4 +19927 5 +19932 6 +19938 3 +19941 8 +19949 7 +19956 6 +19962 7 +19969 4 +19973 6 +19979 4 +19983 10 +19993 8 +20001 16 +20017 5 +20022 6 +20028 11 +20039 6 +20045 6 +20051 8 +20059 5 +20064 4 +20068 9 +20077 9 +20086 10 +20096 9 +20105 6 +20111 4 +20115 5 +20120 3 +20123 7 +20130 9 +20139 4 +20143 2 +20145 7 +20152 7 +20159 6 +20165 7 +20172 10 +20182 6 +20188 2 +20190 5 +20195 7 +20202 6 +20208 6 +20214 5 +20219 3 +20222 2 +20224 4 +20228 7 +20235 4 +20239 5 +20244 8 +20252 3 +20255 6 +20261 9 +20270 9 +20279 2 +20281 8 +20289 2 +20291 3 +20294 3 +20297 3 +20300 4 +20304 7 +20311 7 +20318 6 +20324 4 +20328 4 +20332 4 +20336 10 +20346 7 +20353 3 +20356 5 +20361 3 +20364 6 +20370 4 +20374 4 +20378 3 +20381 5 +20386 5 +20391 4 +20395 5 +20400 4 +20404 5 +20409 1 +20410 5 +20415 2 +20417 5 +20422 7 +20429 4 +20433 2 +20435 6 +20441 5 +20446 4 +20450 7 +20457 8 +20465 2 +20467 10 +20477 5 +20482 5 +20487 8 +20495 11 +20506 5 +20511 4 +20515 3 +20518 6 +20524 12 +20536 3 +20539 12 +20551 8 +20559 4 +20563 10 +20573 8 +20581 3 +20584 7 +20591 6 +20597 4 +20601 10 +20611 7 +20618 5 +20623 4 +20627 5 +20632 8 +20640 6 +20646 3 +20649 9 +20658 2 +20660 7 +20667 4 +20671 5 +20676 7 +20683 8 +20691 4 +20695 6 +20701 4 +20705 8 +20713 8 +20721 4 +20725 5 +20730 7 +20737 4 +20741 5 +20746 4 +20750 2 +20752 8 +20760 8 +20768 10 +20778 7 +20785 7 +20792 10 +20802 3 +20805 3 +20808 10 +20818 4 +20822 6 +20828 7 +20835 4 +20839 8 +20847 5 +20852 12 +20864 2 +20866 7 +20873 3 +20876 5 +20881 3 +20884 8 +20892 4 +20896 7 +20903 5 +20908 4 +20912 10 +20922 5 +20927 10 +20937 10 +20947 6 +20953 3 +20956 6 +20962 4 +20966 5 +20971 8 +20979 4 +20983 7 +20990 5 +20995 10 +21005 7 +21012 10 +21022 3 +21025 7 +21032 5 +21037 12 +21049 8 +21057 4 +21061 5 +21066 2 +21068 10 +21078 3 +21081 4 +21085 5 +21090 4 +21094 9 +21103 4 +21107 7 +21114 7 +21121 6 +21127 1 +21128 9 +21137 7 +21144 10 +21154 4 +21158 5 +21163 6 +21169 5 +21174 4 +21178 4 +21182 5 +21187 6 +21193 11 +21204 7 +21211 7 +21218 10 +21228 5 +21233 13 +21246 10 +21256 3 +21259 5 +21264 9 +21273 6 +21279 11 +21290 8 +21298 3 +21301 3 +21304 12 +21316 7 +21323 5 +21328 6 +21334 4 +21338 7 +21345 7 +21352 6 +21358 3 +21361 8 +21369 6 +21375 5 +21380 5 +21385 6 +21391 6 +21397 6 +21403 6 +21409 9 +21418 6 +21424 12 +21436 5 +21441 3 +21444 7 +21451 9 +21460 9 +21469 10 +21479 5 +21484 5 +21489 8 +21497 6 +21503 4 +21507 2 +21509 5 +21514 4 +21518 4 +21522 6 +21528 11 +21539 6 +21545 6 +21551 6 +21557 11 +21568 3 +21571 4 +21575 3 +21578 6 +21584 7 +21591 3 +21594 8 +21602 7 +21609 9 +21618 4 +21622 7 +21629 8 +21637 8 +21645 4 +21649 4 +21653 2 +21655 6 +21661 6 +21667 5 +21672 5 +21677 8 +21685 6 +21691 6 +21697 4 +21701 4 +21705 3 +21708 12 +21720 6 +21726 9 +21735 5 +21740 6 +21746 5 +21751 6 +21757 12 +21769 5 +21774 6 +21780 4 +21784 8 +21792 3 +21795 3 +21798 6 +21804 7 +21811 5 +21816 11 +21827 7 +21834 3 +21837 6 +21843 9 +21852 8 +21860 6 +21866 4 +21870 5 +21875 6 +21881 9 +21890 3 +21893 5 +21898 4 +21902 5 +21907 8 +21915 6 +21921 3 +21924 5 +21929 6 +21935 5 +21940 5 +21945 7 +21952 7 +21959 4 +21963 8 +21971 4 +21975 6 +21981 3 +21984 9 +21993 6 +21999 5 +22004 6 +22010 9 +22019 8 +22027 2 +22029 7 +22036 3 +22039 5 +22044 3 +22047 7 +22054 10 +22064 3 +22067 2 +22069 5 +22074 6 +22080 4 +22084 5 +22089 7 +22096 4 +22100 8 +22108 4 +22112 10 +22122 4 +22126 6 +22132 3 +22135 4 +22139 9 +22148 5 +22153 4 +22157 5 +22162 5 +22167 8 +22175 5 +22180 4 +22184 5 +22189 4 +22193 4 +22197 5 +22202 10 +22212 8 +22220 5 +22225 4 +22229 8 +22237 8 +22245 8 +22253 2 +22255 4 +22259 9 +22268 10 +22278 3 +22281 9 +22290 4 +22294 4 +22298 7 +22305 6 +22311 4 +22315 7 +22322 3 +22325 6 +22331 3 +22334 5 +22339 9 +22348 4 +22352 5 +22357 6 +22363 5 +22368 4 +22372 5 +22377 7 +22384 2 +22386 7 +22393 8 +22401 7 +22408 9 +22417 8 +22425 3 +22428 4 +22432 7 +22439 6 +22445 4 +22449 9 +22458 6 +22464 5 +22469 7 +22476 10 +22486 5 +22491 5 +22496 10 +22506 8 +22514 8 +22522 8 +22530 8 +22538 5 +22543 9 +22552 2 +22554 2 +22556 6 +22562 7 +22569 9 +22578 3 +22581 7 +22588 8 +22596 3 +22599 6 +22605 3 +22608 4 +22612 6 +22618 13 +22631 7 +22638 5 +22643 8 +22651 8 +22659 9 +22668 7 +22675 2 +22677 12 +22689 14 +22703 10 +22713 4 +22717 7 +22724 3 +22727 5 +22732 9 +22741 9 +22750 11 +22761 4 +22765 5 +22770 12 +22782 4 +22786 8 +22794 4 +22798 7 +22805 6 +22811 4 +22815 8 +22823 4 +22827 7 +22834 2 +22836 7 +22843 9 +22852 2 +22854 10 +22864 6 +22870 7 +22877 8 +22885 7 +22892 2 +22894 4 +22898 9 +22907 7 +22914 8 +22922 7 +22929 5 +22934 5 +22939 4 +22943 7 +22950 8 +22958 3 +22961 7 +22968 5 +22973 4 +22977 5 +22982 7 +22989 4 +22993 4 +22997 7 +23004 4 +23008 5 +23013 7 +23020 6 +23026 3 +23029 7 +23036 9 +23045 3 +23048 3 +23051 5 +23056 5 +23061 5 +23066 6 +23072 7 +23079 4 +23083 4 +23087 9 +23096 4 +23100 6 +23106 5 +23111 6 +23117 7 +23124 5 +23129 5 +23134 3 +23137 2 +23139 8 +23147 13 +23160 6 +23166 4 +23170 5 +23175 4 +23179 3 +23182 6 +23188 6 +23194 5 +23199 4 +23203 6 +23209 4 +23213 12 +23225 4 +23229 7 +23236 10 +23246 9 +23255 6 +23261 9 +23270 9 +23279 8 +23287 3 +23290 7 +23297 5 +23302 3 +23305 2 +23307 7 +23314 7 +23321 6 +23327 10 +23337 4 +23341 9 +23350 6 +23356 6 +23362 7 +23369 12 +23381 4 +23385 5 +23390 3 +23393 10 +23403 10 +23413 4 +23417 6 +23423 3 +23426 9 +23435 6 +23441 7 +23448 5 +23453 6 +23459 5 +23464 3 +23467 8 +23475 2 +23477 10 +23487 3 +23490 4 +23494 5 +23499 8 +23507 4 +23511 7 +23518 8 +23526 4 +23530 6 +23536 8 +23544 6 +23550 7 +23557 3 +23560 7 +23567 2 +23569 6 +23575 9 +23584 12 +23596 5 +23601 8 +23609 7 +23616 6 +23622 6 +23628 4 +23632 10 +23642 8 +23650 7 +23657 1 +23658 8 +23666 8 +23674 4 +23678 8 +23686 6 +23692 9 +23701 8 +23709 7 +23716 9 +23725 8 +23733 9 +23742 5 +23747 4 +23751 5 +23756 10 +23766 6 +23772 4 +23776 6 +23782 3 +23785 6 +23791 7 +23798 9 +23807 9 +23816 13 +23829 10 +23839 6 +23845 3 +23848 6 +23854 7 +23861 6 +23867 4 +23871 11 +23882 12 +23894 3 +23897 2 +23899 8 +23907 3 +23910 8 +23918 7 +23925 6 +23931 5 +23936 6 +23942 11 +23953 6 +23959 4 +23963 4 +23967 5 +23972 7 +23979 8 +23987 5 +23992 5 +23997 6 +24003 4 +24007 8 +24015 9 +24024 5 +24029 4 +24033 3 +24036 4 +24040 2 +24042 7 +24049 2 +24051 6 +24057 1 +24058 9 +24067 8 +24075 6 +24081 3 +24084 9 +24093 6 +24099 8 +24107 9 +24116 6 +24122 5 +24127 4 +24131 8 +24139 6 +24145 7 +24152 3 +24155 8 +24163 5 +24168 6 +24174 6 +24180 4 +24184 8 +24192 5 +24197 5 +24202 6 +24208 7 +24215 5 +24220 3 +24223 11 +24234 12 +24246 12 +24258 3 +24261 9 +24270 6 +24276 5 +24281 5 +24286 8 +24294 4 +24298 8 +24306 5 +24311 7 +24318 3 +24321 8 +24329 5 +24334 3 +24337 7 +24344 7 +24351 5 +24356 7 +24363 4 +24367 6 +24373 3 +24376 8 +24384 3 +24387 7 +24394 10 +24404 3 +24407 5 +24412 6 +24418 4 +24422 4 +24426 2 +24428 3 +24431 9 +24440 8 +24448 7 +24455 5 +24460 11 +24471 7 +24478 7 +24485 5 +24490 10 +24500 4 +24504 7 +24511 6 +24517 13 +24530 10 +24540 7 +24547 8 +24555 4 +24559 2 +24561 9 +24570 2 +24572 4 + +0 + +24576 +2539 2 +1187 5 +3911 2 +585 8 +1498 10 +1681 2 +2115 7 +2424 1 +3708 7 +196 1 +1852 10 +3555 8 +2134 1 +1064 9 +1293 8 +944 9 +2413 3 +1678 2 +839 9 +297 1 +174 7 +2217 9 +51 8 +3195 6 +3215 5 +332 3 +2077 7 +1214 2 +2367 10 +1947 10 +2350 6 +3441 1 +3246 7 +1999 1 +2037 5 +2227 8 +101 7 +3340 9 +3713 7 +3013 4 +1001 3 +444 6 +3306 2 +4043 1 +1361 1 +3916 6 +365 4 +1485 8 +251 8 +234 2 +4042 2 +870 7 +3803 9 +3874 4 +1058 5 +831 3 +2331 6 +1328 1 +2525 4 +255 3 +381 1 +2521 1 +3946 5 +2449 4 +285 2 +3848 4 +2669 9 +3949 3 +1050 4 +2855 9 +1974 3 +349 7 +2874 6 +192 6 +3442 4 +265 1 +2281 4 +403 6 +2359 5 +319 8 +39 1 +3893 3 +1176 1 +3154 10 +866 9 +2670 9 +3934 6 +3799 5 +393 8 +2722 10 +2107 4 +185 3 +69 1 +1958 4 +1613 2 +1908 10 +3867 5 +2950 2 +3397 10 +3737 1 +1074 9 +234 2 +2795 8 +1452 8 +1437 2 +768 7 +3400 1 +1212 6 +2675 7 +989 4 +1338 6 +764 5 +216 3 +2186 3 +2210 9 +2194 1 +1703 3 +2668 5 +3684 3 +3636 6 +3939 5 +3718 2 +3954 10 +4009 10 +703 8 +2990 8 +2162 4 +3980 1 +1245 8 +2488 1 +2391 3 +3774 9 +3238 5 +1534 4 +3440 3 +2611 6 +2878 7 +1931 8 +3668 9 +3139 10 +3822 10 +2184 3 +82 6 +3317 1 +1702 3 +4087 10 +519 3 +1944 1 +3830 9 +3563 10 +2150 5 +3735 9 +1158 2 +3265 9 +2571 6 +2587 4 +2073 3 +405 6 +3865 3 +42 4 +2358 9 +2632 1 +1629 5 +2968 10 +3160 8 +1934 7 +1108 3 +2324 9 +1923 4 +2536 10 +3112 3 +3817 1 +4008 3 +2118 10 +1034 6 +3094 8 +3868 9 +2484 6 +3791 7 +1456 5 +2643 5 +462 9 +1481 8 +1788 10 +811 5 +1441 10 +2258 6 +3559 5 +2816 2 +3886 1 +428 9 +2442 8 +873 2 +3460 2 +989 7 +2897 9 +1464 7 +1525 4 +685 7 +3906 4 +678 7 +1824 2 +2256 8 +1016 9 +3705 1 +3368 10 +136 1 +1154 8 +2478 10 +3323 2 +104 10 +932 7 +3100 8 +2465 5 +491 9 +1735 3 +1031 3 +2790 1 +1423 5 +2939 6 +1829 9 +1241 3 +386 4 +1934 8 +2883 9 +14 1 +686 2 +992 5 +3564 8 +551 10 +2074 3 +2344 1 +3593 9 +1103 6 +2668 6 +696 5 +4019 4 +1708 1 +2519 3 +3455 8 +28 4 +3639 8 +1977 7 +2429 5 +3549 7 +468 10 +2801 10 +848 7 +959 9 +2410 6 +3898 9 +2059 3 +1938 9 +3544 1 +3513 9 +1136 1 +302 4 +1589 7 +305 1 +3199 2 +847 4 +3900 6 +2632 6 +2193 6 +442 7 +3972 1 +3426 4 +1500 3 +1723 5 +2849 1 +2498 4 +3104 4 +3131 5 +1198 2 +1492 10 +2112 6 +1202 2 +2284 10 +1672 10 +3115 3 +2934 4 +990 4 +434 8 +3372 6 +1974 6 +2729 9 +3517 3 +2286 6 +1761 1 +3637 3 +3058 4 +1178 2 +985 4 +3 8 +939 6 +445 3 +1807 9 +2728 7 +1861 5 +2716 5 +3316 3 +2836 5 +174 3 +1190 4 +1061 9 +2375 6 +3599 9 +1048 3 +3021 8 +1421 5 +2090 10 +1289 6 +971 1 +3560 4 +1817 2 +3691 1 +2572 6 +1938 9 +576 6 +3178 3 +3265 6 +3747 6 +1332 1 +2812 9 +3574 5 +2033 7 +1103 4 +2806 4 +2506 5 +686 3 +3917 3 +350 5 +2609 6 +1906 7 +3969 10 +3419 10 +3338 10 +1448 9 +1050 3 +1080 5 +3620 4 +1286 10 +2202 5 +4079 7 +3722 3 +1210 7 +3678 2 +1323 7 +2341 7 +320 2 +3506 7 +649 4 +2993 5 +1165 6 +1384 9 +335 7 +2002 2 +302 7 +1502 1 +4049 9 +2628 3 +259 2 +2500 1 +2022 9 +541 9 +2910 2 +4089 6 +3356 1 +2474 9 +1941 2 +1025 2 +3026 10 +2314 6 +2102 6 +1122 7 +1833 10 +1692 1 +1372 3 +1302 4 +3883 10 +2310 9 +3151 9 +2447 2 +1205 5 +276 2 +2431 8 +611 3 +512 8 +1134 10 +758 2 +2418 6 +276 10 +2592 1 +1655 8 +2181 1 +3243 10 +2191 3 +455 4 +1130 5 +2880 8 +740 1 +635 6 +932 9 +3178 8 +1032 9 +89 6 +414 1 +730 9 +16 1 +3631 9 +1411 6 +2356 5 +2474 5 +3025 4 +3876 8 +2897 7 +957 5 +2621 6 +1568 8 +2610 8 +3253 7 +1169 1 +3292 4 +1035 2 +1417 5 +3613 10 +1063 5 +1779 7 +360 2 +208 3 +1014 7 +894 8 +2599 7 +4076 3 +3329 6 +2497 10 +1110 5 +803 8 +3322 10 +3100 7 +1921 8 +3077 2 +1052 7 +2808 5 +3802 9 +2708 9 +3412 1 +690 9 +2266 3 +112 3 +765 4 +3276 3 +3823 5 +181 9 +457 1 +299 6 +934 5 +3422 7 +3718 4 +1793 6 +3672 8 +2858 2 +3801 3 +1693 8 +3711 4 +2917 1 +291 6 +3209 1 +334 10 +3287 6 +626 5 +915 3 +2886 6 +236 3 +1390 10 +2523 8 +1386 10 +3340 2 +4047 7 +303 8 +230 2 +2390 8 +1983 5 +2897 2 +3922 3 +954 3 +3004 4 +3912 10 +393 1 +1768 3 +2783 2 +1522 6 +4055 8 +3429 6 +3884 2 +25 6 +3606 3 +3813 7 +2176 9 +2774 10 +2829 1 +2858 7 +3722 8 +1468 6 +1208 5 +3466 7 +446 2 +1824 4 +4056 8 +1036 5 +985 4 +2979 3 +3919 6 +479 3 +3896 5 +128 3 +2928 9 +1208 1 +1356 10 +928 10 +787 5 +3418 6 +421 8 +1985 3 +2218 3 +3452 1 +2255 3 +405 7 +3265 4 +2763 4 +641 10 +3202 1 +3754 8 +1949 3 +3120 10 +2017 9 +1932 9 +2302 9 +2060 9 +773 5 +3294 1 +2044 2 +2277 10 +3755 10 +3620 6 +69 6 +2237 4 +3696 3 +2141 7 +1698 7 +2629 7 +2951 1 +1211 8 +3830 3 +1858 3 +2153 10 +2512 9 +3088 10 +3996 3 +423 8 +584 7 +383 10 +2355 1 +2140 5 +954 4 +99 4 +1575 4 +2552 2 +405 4 +1175 10 +1124 10 +3839 8 +1711 6 +3475 8 +1104 5 +2724 4 +1185 4 +1081 9 +2892 8 +1177 10 +2260 8 +1362 1 +1979 3 +2161 4 +3940 7 +694 3 +254 1 +966 6 +3083 5 +920 6 +3555 6 +1233 6 +947 6 +3804 6 +1611 2 +951 1 +3524 10 +94 4 +3332 5 +3542 10 +152 7 +289 1 +539 9 +566 10 +3745 8 +2949 10 +2114 8 +2206 1 +364 5 +3081 4 +2286 9 +3450 1 +2703 10 +5 7 +1851 3 +2618 6 +1958 1 +550 3 +2220 3 +375 7 +3322 10 +3901 10 +2296 4 +732 1 +3721 8 +3064 1 +3315 5 +2066 10 +2566 7 +593 10 +36 10 +1177 2 +2225 9 +1485 8 +392 6 +3144 7 +2170 5 +2052 5 +1235 7 +801 2 +3439 1 +2565 9 +3646 7 +893 3 +1991 3 +2220 1 +1540 5 +1493 4 +3384 5 +1115 4 +488 6 +568 8 +1240 3 +4030 2 +3376 2 +3660 1 +2790 5 +3528 8 +1131 10 +1932 7 +2690 10 +3852 7 +2833 3 +785 1 +705 10 +2183 9 +3411 6 +2966 6 +2765 1 +3756 1 +199 4 +817 3 +3221 1 +1154 9 +1610 9 +1224 6 +3511 6 +3245 5 +75 3 +1353 8 +2848 7 +2353 4 +268 10 +374 8 +2591 9 +2501 8 +953 5 +2335 3 +1304 1 +407 1 +1556 9 +2965 3 +1263 7 +2258 4 +138 3 +1237 5 +1719 6 +1272 6 +1867 6 +3052 9 +2829 10 +515 10 +1874 9 +1699 8 +3351 2 +1303 10 +2853 9 +866 6 +3533 1 +895 2 +2287 9 +1954 9 +3352 9 +3760 2 +1026 9 +2074 6 +1529 4 +868 2 +3551 9 +3603 8 +1589 3 +2230 3 +1141 7 +3914 8 +3396 3 +1997 6 +898 10 +3176 8 +3063 7 +2957 5 +194 10 +2959 2 +1616 9 +686 1 +921 9 +2578 10 +3986 4 +2293 3 +2529 6 +722 7 +1783 3 +594 1 +2188 7 +1317 6 +992 1 +2754 3 +3113 7 +205 4 +3815 5 +3076 8 +1205 9 +1703 4 +3901 4 +1627 8 +2490 6 +524 4 +4031 10 +3070 1 +4004 9 +652 8 +891 8 +765 2 +248 9 +836 4 +2567 7 +1083 8 +1743 7 +3716 7 +2978 9 +2097 6 +3205 10 +310 4 +907 4 +2378 6 +85 3 +1268 1 +1250 4 +1745 4 +3608 4 +948 6 +3799 2 +552 4 +2391 9 +758 7 +2703 6 +2951 6 +2674 5 +3839 2 +1778 4 +3064 8 +2392 7 +1312 9 +798 6 +391 5 +3602 3 +1346 7 +2819 7 +3549 2 +476 8 +1661 5 +2335 8 +963 5 +3882 4 +2778 6 +521 9 +353 4 +1534 2 +3229 1 +2011 3 +3422 8 +757 9 +2851 1 +180 10 +584 10 +3797 4 +2092 8 +237 10 +2797 7 +3207 10 +3546 9 +1225 9 +282 3 +1545 2 +2111 7 +3439 1 +2231 5 +1814 3 +36 1 +1513 4 +1803 10 +2642 3 +2749 4 +3608 7 +2702 4 +1331 8 +3867 6 +883 3 +2695 6 +3879 1 +2200 10 +1720 4 +2801 5 +1463 1 +250 2 +3074 8 +1938 8 +115 3 +1161 5 +835 10 +962 7 +2543 10 +1828 7 +1488 7 +3860 1 +1497 2 +413 1 +3003 7 +3593 9 +3711 7 +1680 2 +2586 7 +3164 4 +1227 1 +2124 9 +2302 10 +541 7 +1123 7 +1261 10 +2938 9 +3420 3 +1604 3 +3772 10 +3921 10 +3518 4 +194 3 +456 2 +3212 4 +3898 5 +1158 7 +186 3 +449 3 +620 7 +330 8 +3579 1 +1214 2 +1598 2 +160 2 +3430 4 +2579 5 +2321 6 +3585 7 +1710 5 +4037 2 +3234 6 +3245 5 +3139 2 +2571 4 +536 9 +358 3 +378 8 +383 8 +1575 5 +432 5 +2731 1 +2298 2 +2600 1 +1525 5 +2324 9 +2883 4 +473 4 +934 3 +641 7 +3351 7 +1225 4 +1535 3 +2448 7 +3853 3 +1055 1 +2545 5 +3337 2 +1247 1 +2846 4 +681 2 +1495 2 +3803 4 +1023 7 +2533 8 +338 10 +3061 5 +2127 9 +1459 6 +99 7 +3569 7 +1724 8 +2816 4 +351 7 +2074 7 +193 5 +3012 7 +2078 6 +3269 10 +2182 1 +3485 10 +685 8 +2592 5 +2970 10 +170 1 +1314 7 +1342 7 +3914 8 +761 1 +3823 3 +2388 1 +3280 10 +2773 6 +3930 3 +1338 3 +895 8 +1576 3 +1445 8 +221 8 +415 6 +2915 1 +3712 2 +2374 6 +146 2 +333 10 +1369 1 +2909 10 +1699 4 +2560 8 +982 4 +716 3 +3109 4 +2823 5 +1810 2 +2582 8 +3314 3 +1875 4 +3040 1 +3229 7 +2454 6 +2690 4 +2880 4 +203 2 +3240 9 +639 6 +3636 10 +4025 5 +3986 3 +3159 8 +2873 1 +1798 1 +3724 2 +1942 6 +3947 2 +1767 8 +2916 3 +1358 8 +3242 4 +1710 2 +3440 9 +2958 4 +427 3 +1003 1 +2351 7 +2339 10 +3991 2 +3758 1 +3229 3 +2572 5 +297 4 +1987 4 +1033 4 +2941 10 +1582 1 +1775 7 +1510 1 +1216 8 +2154 6 +2178 5 +2009 10 +1887 8 +1090 10 +1213 9 +867 5 +1604 4 +3968 3 +2542 1 +156 1 +2056 6 +2008 4 +1882 1 +3508 5 +3603 10 +195 7 +226 7 +1070 8 +1523 3 +3067 10 +2665 6 +639 3 +3369 6 +3750 7 +1326 10 +3019 2 +261 2 +3191 7 +1692 9 +1403 1 +3822 8 +3 7 +1215 5 +2335 4 +52 3 +2325 8 +1872 2 +3000 4 +399 9 +962 4 +3591 5 +3366 9 +1774 8 +2512 10 +2805 7 +1001 4 +3962 8 +318 9 +2789 7 +3299 4 +1140 10 +1234 9 +1301 10 +2402 2 +2978 4 +494 1 +2857 9 +2856 8 +1970 1 +3511 8 +2335 6 +907 5 +730 5 +2194 2 +1785 10 +134 10 +4045 9 +872 5 +2925 5 +353 10 +3690 9 +3147 9 +2525 9 +1087 6 +2143 9 +1301 8 +76 9 +412 7 +2266 6 +2772 1 +1253 5 +2786 2 +186 10 +354 2 +3073 6 +1807 6 +2720 10 +496 5 +1936 9 +4044 9 +333 4 +3080 3 +2030 5 +831 8 +1824 10 +16 3 +3371 3 +3971 6 +1671 8 +183 10 +716 9 +144 3 +824 3 +1499 2 +288 7 +379 9 +2076 3 +1418 10 +3787 1 +549 2 +1904 1 +939 4 +1841 3 +2637 1 +1448 7 +420 1 +382 6 +2592 1 +2591 2 +1298 2 +2238 9 +3599 1 +2705 9 +3938 7 +2700 10 +2881 10 +3331 7 +1130 2 +3909 10 +2516 6 +1695 2 +196 7 +3700 1 +2510 7 +1838 8 +3886 8 +4041 7 +3904 4 +3272 8 +426 3 +3851 9 +1539 1 +2457 2 +2890 10 +968 9 +13 6 +613 3 +282 7 +1110 2 +2559 7 +1913 5 +153 5 +515 2 +2026 6 +2985 8 +144 3 +3929 4 +121 10 +478 6 +713 4 +1204 3 +2721 9 +171 7 +659 5 +3872 5 +719 4 +1651 4 +2765 3 +1370 10 +191 7 +3359 4 +3869 4 +900 6 +2104 2 +0 1 +3350 1 +2890 9 +305 7 +1997 7 +2885 8 +2138 9 +3940 2 +3704 8 +1379 9 +908 3 +1249 9 +1286 1 +1632 1 +2438 4 +2000 5 +1237 3 +1797 6 +3789 8 +111 4 +668 1 +3502 2 +1338 5 +1617 7 +4067 4 +2203 1 +2924 7 +2009 2 +1903 4 +3918 6 +1857 3 +1062 8 +2212 10 +1847 4 +671 8 +3686 1 +1788 1 +1578 10 +3501 1 +2554 1 +164 2 +2886 10 +1318 10 +570 5 +2649 10 +2581 4 +1103 4 +3748 7 +2504 5 +123 4 +3156 5 +1737 10 +1594 3 +667 3 +3426 7 +2117 10 +1626 9 +73 3 +933 7 +3979 9 +2199 3 +1885 2 +2168 2 +1276 8 +2458 7 +591 3 +1502 3 +2454 1 +471 2 +2918 1 +3221 4 +1135 8 +3922 4 +239 6 +723 6 +3865 8 +1145 2 +2640 7 +812 1 +3977 6 +2318 3 +558 8 +1479 7 +1248 9 +377 1 +2986 9 +3356 2 +2964 9 +2967 6 +3212 9 +2455 6 +3254 1 +933 1 +3326 3 +464 10 +4003 4 +3246 5 +2883 6 +3568 7 +3578 7 +3045 4 +1516 4 +3131 3 +2759 2 +2942 6 +1211 3 +3201 1 +333 1 +2319 6 +2033 10 +3489 6 +704 5 +1242 7 +1327 1 +1596 6 +19 3 +552 6 +4031 7 +4060 9 +3793 7 +978 3 +3817 1 +2194 4 +3677 6 +1684 10 +227 7 +2985 8 +2105 6 +3677 2 +1486 2 +3993 5 +1698 5 +3903 9 +2048 4 +568 10 +2101 2 +1272 4 +1358 10 +3457 10 +1460 7 +3763 3 +1066 8 +2459 2 +1117 5 +712 6 +4018 1 +425 8 +3698 5 +3277 2 +2648 8 +226 7 +1201 7 +158 8 +503 2 +1517 10 +803 9 +1582 4 +637 9 +3550 9 +2803 7 +2130 1 +2199 6 +1682 10 +3393 8 +352 8 +1107 2 +1994 8 +1894 7 +3787 2 +2311 9 +2262 3 +3517 1 +3867 9 +1868 2 +856 10 +4029 8 +2769 5 +253 1 +832 4 +3702 2 +468 9 +1984 8 +2524 1 +767 4 +2701 3 +4086 4 +660 4 +171 7 +221 7 +218 7 +2965 2 +3286 8 +1200 10 +3434 4 +1969 8 +1625 4 +501 10 +1701 9 +2440 7 +3201 1 +1870 8 +3934 4 +3252 9 +2169 2 +3959 5 +2629 4 +2557 10 +557 9 +817 3 +745 9 +3575 10 +651 10 +2591 5 +2432 1 +1689 9 +1173 7 +1743 5 +1163 3 +1320 3 +79 2 +1370 2 +2077 8 +3964 9 +1021 1 +1484 9 +1551 6 +3956 3 +2222 7 +3843 5 +347 10 +841 5 +3810 1 +3443 9 +9 2 +2063 9 +17 2 +3938 3 +1839 4 +1233 2 +2308 1 +2941 10 +1598 2 +1287 1 +79 3 +1377 4 +3143 7 +3366 2 +2660 2 +2225 10 +2731 3 +1070 5 +3581 7 +135 10 +1704 7 +1314 1 +1309 5 +3273 8 +3207 5 +4037 7 +1014 2 +3825 6 +2835 7 +3363 4 +3895 6 +2554 8 +1121 9 +3166 5 +211 6 +3249 2 +1744 10 +3165 10 +1191 2 +1054 10 +3828 10 +3761 3 +2625 4 +765 8 +3157 8 +3575 2 +3196 8 +577 10 +1460 7 +1447 5 +2756 6 +1208 7 +1100 5 +857 4 +1808 7 +4018 9 +2670 6 +3445 10 +3564 10 +3854 8 +3476 10 +2565 6 +1536 3 +3436 9 +2842 7 +423 3 +2912 7 +271 7 +1992 6 +883 5 +1287 6 +3277 1 +3560 9 +2265 3 +900 8 +2009 7 +2644 3 +1288 5 +2997 2 +329 2 +2344 4 +1900 5 +532 9 +2821 2 +3858 7 +1644 7 +2114 8 +848 10 +2820 6 +126 9 +2006 6 +2471 10 +3260 2 +2660 5 +3745 6 +1105 9 +3301 3 +2592 6 +3313 1 +1388 3 +2828 10 +138 2 +3765 6 +1882 3 +1552 10 +2130 8 +2421 1 +9 8 +1084 1 +1615 8 +2619 7 +1831 6 +3940 9 +1596 9 +1127 9 +1718 1 +814 5 +2365 9 +1654 4 +279 10 +3360 9 +4025 6 +224 1 +2529 2 +2277 10 +286 3 +1781 3 +2429 3 +98 1 +1214 4 +3920 2 +2300 6 +1818 10 +2490 1 +2674 10 +2767 4 +3042 9 +3007 1 +3082 6 +1264 6 +738 3 +2078 6 +3111 6 +10 3 +2939 3 +2420 9 +3298 6 +472 10 +3383 6 +3041 1 +557 2 +2520 5 +3695 4 +1487 10 +3723 3 +317 10 +3442 10 +574 8 +2151 7 +3178 1 +1727 9 +62 2 +3282 10 +564 6 +1492 6 +948 3 +3745 3 +3866 6 +749 6 +1150 2 +691 4 +1023 4 +2960 4 +173 2 +1170 5 +3284 7 +808 6 +4088 1 +2320 6 +1876 1 +1171 9 +3202 5 +1899 9 +3775 8 +1090 6 +881 1 +2486 9 +1102 10 +3164 2 +3261 7 +1200 3 +3738 10 +1250 3 +3947 10 +1409 3 +2226 5 +2599 8 +1847 3 +14 1 +587 8 +2833 8 +3511 8 +2348 5 +3814 3 +734 6 +1469 3 +3521 6 +1980 7 +2075 3 +675 3 +2818 3 +3436 7 +1169 10 +3998 8 +3268 4 +373 6 +2090 1 +1641 5 +1220 9 +502 3 +1103 1 +1907 6 +956 4 +112 10 +1229 6 +3587 4 +3008 10 +3458 5 +1991 3 +3781 9 +1335 1 +244 7 +1054 3 +1566 1 +1325 5 +3153 3 +4069 10 +318 1 +3883 6 +2088 9 +446 1 +2397 2 +2999 5 +3668 9 +2764 8 +1962 4 +2531 3 +348 4 +2445 2 +1730 2 +4070 9 +3439 9 +1430 7 +2819 7 +2225 4 +553 2 +2429 9 +1763 2 +503 4 +2692 7 +2899 1 +67 10 +3106 5 +2896 9 +66 2 +2111 3 +4061 7 +1103 8 +3469 3 +612 4 +1922 7 +300 8 +3712 10 +1386 9 +3626 4 +2924 3 +3897 4 +1149 5 +2435 6 +480 7 +2695 6 +1772 5 +1140 8 +2930 8 +2593 3 +252 10 +574 7 +648 2 +321 10 +3347 1 +391 7 +2755 6 +2834 8 +3028 8 +1339 10 +943 2 +3139 3 +193 7 +3133 6 +932 8 +135 3 +1621 4 +1837 6 +409 1 +3328 9 +3938 4 +2062 9 +3383 5 +3584 9 +1646 9 +3074 3 +1945 1 +734 10 +2558 5 +2644 4 +2850 1 +12 2 +1033 7 +1612 8 +3555 2 +3520 4 +1176 4 +254 3 +3906 6 +2661 10 +489 8 +3828 10 +2171 6 +2611 10 +1502 7 +622 5 +1913 4 +2033 6 +187 7 +1307 8 +3612 7 +2677 3 +1813 6 +3700 2 +99 1 +3300 6 +3535 7 +931 1 +3119 5 +3010 4 +78 6 +2386 7 +3633 5 +1706 7 +647 9 +669 9 +3026 4 +2259 3 +3716 3 +1337 5 +1813 8 +580 4 +3163 10 +2789 5 +3971 2 +1466 8 +1120 2 +2384 7 +4079 8 +1253 4 +428 5 +2713 10 +3247 3 +1031 1 +1398 6 +2114 6 +3392 3 +308 4 +1008 3 +655 7 +3483 8 +3 1 +418 8 +2071 4 +1238 2 +168 4 +642 4 +1031 6 +915 5 +742 4 +2101 2 +1627 9 +1593 4 +419 5 +1763 9 +77 6 +3463 6 +2740 4 +4000 2 +1192 5 +1959 2 +3150 8 +528 8 +1751 7 +1639 2 +2363 7 +277 8 +3790 7 +688 8 +1667 8 +1870 1 +3122 5 +795 7 +2150 9 +61 7 +44 4 +1213 7 +2420 3 +1355 4 +430 7 +1115 3 +3473 3 +2992 2 +2787 9 +789 6 +79 8 +786 6 +305 4 +1054 6 +2507 3 +197 7 +1296 1 +3126 2 +3274 1 +2143 3 +45 1 +4077 8 +1909 7 +304 4 +2444 5 +2457 3 +1388 5 +4003 3 +3304 7 +1671 9 +2554 6 +3080 2 +1004 8 +1610 9 +475 9 +597 9 +1984 3 +2096 9 +3046 4 +2725 6 +1141 10 +3287 10 +2049 10 +296 4 +439 2 +1424 10 +1080 9 +2884 5 +2767 1 +1619 3 +645 3 +2259 6 +866 5 +3559 10 +2414 9 +127 4 +1380 1 +1180 5 +2342 9 +467 2 +1500 7 +616 7 +2511 7 +1714 9 +828 3 +3509 4 +1002 2 +1340 7 +1886 10 +1203 3 +2010 2 +3289 10 +3963 4 +992 2 +1669 6 +1405 1 +3342 2 +1421 7 +2761 7 +459 4 +2007 5 +2400 5 +1601 4 +3057 2 +1086 9 +3956 2 +786 7 +1401 4 +1036 2 +1095 1 +258 10 +864 10 +402 6 +3880 7 +3268 2 +3968 6 +177 9 +450 1 +3520 9 +272 1 +474 4 +2195 8 +3049 4 +14 8 +1920 10 +964 7 +2409 10 +454 5 +716 1 +60 2 +280 10 +4013 10 +1825 2 +1639 10 +2149 10 +3730 4 +1631 4 +1600 1 +707 2 +765 3 +924 6 +2011 3 +3304 3 +3267 10 +1280 10 +2467 3 +3621 7 +2970 10 +3119 8 +834 1 +504 7 +2209 5 +1593 8 +2914 1 +2123 6 +2951 8 +3075 4 +3518 6 +2102 6 +1899 9 +2574 9 +4077 3 +1850 7 +3734 4 +2330 1 +2680 3 +1216 2 +3915 4 +3361 5 +358 3 +1317 8 +794 9 +1513 2 +2065 4 +3161 2 +893 1 +4062 7 +2286 7 +245 2 +4088 9 +3214 4 +4020 1 +1723 5 +1462 2 +2652 6 +2549 3 +144 8 +2646 2 +685 4 +3242 3 +2633 5 +2625 5 +2366 5 +2019 3 +3369 5 +1350 7 +4 3 +2019 10 +663 9 +2373 1 +160 10 +185 4 +215 1 +1706 3 +2565 1 +1158 1 +78 10 +2433 5 +1543 4 +1704 8 +3098 8 +832 7 +61 7 +433 7 +705 2 +837 3 +1622 3 +1025 1 +4074 2 +1897 6 +3598 2 +2113 2 +3735 5 +1622 10 +3517 5 +3540 1 +3656 6 +1388 8 +1985 7 +2284 2 +1937 1 +2800 5 +151 10 +3823 7 +2937 10 +3100 1 +2566 4 +1157 4 +1848 6 +3122 3 +2065 10 +2890 1 +869 5 +2450 1 +634 7 +661 8 +726 3 +3599 1 +1099 3 +2725 1 +1513 1 +1176 1 +3474 9 +3643 5 +627 1 +2773 4 +2173 4 +544 10 +2950 5 +1047 1 +2535 3 +2821 10 +3929 10 +3770 6 +477 1 +765 5 +3666 9 +1929 7 +715 10 +1941 4 +1299 9 +1912 7 +375 6 +1481 9 +774 1 +1516 5 +577 3 +1373 2 +2822 6 +3694 10 +3338 2 +1915 2 +2461 2 +673 7 +3165 6 +2635 5 +1900 5 +1264 7 +1580 5 +1310 8 +2815 1 +2053 2 +2750 7 +1522 5 +1601 5 +953 10 +3764 3 +4033 4 +3763 1 +3167 6 +630 10 +232 10 +3228 7 +3190 7 +1512 8 +274 4 +1299 5 +377 5 +1327 8 +860 5 +1489 3 +13 7 +1350 10 +3046 4 +3254 3 +1946 8 +2996 1 +395 7 +3068 6 +58 5 +2429 9 +1987 9 +2124 4 +2714 3 +3312 2 +153 7 +2558 3 +3051 3 +223 8 +2167 1 +2974 7 +3793 10 +918 6 +479 6 +3151 3 +2875 1 +3343 8 +132 4 +2995 1 +3006 9 +180 10 +3996 4 +3742 3 +3899 10 +3751 6 +2976 3 +1914 9 +183 2 +3004 5 +579 3 +766 7 +3381 7 +2072 9 +1223 8 +1063 1 +3020 5 +3778 4 +4055 2 +1371 4 +3756 4 +588 3 +328 3 +147 3 +2082 10 +1860 10 +3077 8 +2936 10 +3445 9 +2795 7 +3513 5 +2763 7 +73 2 +1480 7 +1475 5 +966 7 +2178 7 +4075 8 +3541 5 +3507 3 +2097 4 +1313 2 +2648 10 +3037 3 +668 3 +3828 3 +1366 9 +899 5 +1948 10 +1540 3 +2020 1 +1136 4 +3771 3 +3581 3 +1604 9 +3648 9 +3838 9 +3980 1 +100 5 +3022 9 +2117 3 +1617 2 +1856 4 +8 4 +4057 6 +2708 6 +3392 1 +764 3 +3595 5 +2560 3 +3670 2 +456 6 +542 3 +2333 3 +1134 7 +3643 3 +2835 6 +1091 2 +1616 2 +1525 2 +2960 5 +1424 1 +762 10 +2380 1 +1932 3 +377 3 +703 2 +2384 3 +1916 7 +429 7 +1986 10 +1064 4 +3871 3 +947 10 +1510 7 +1722 5 +3972 6 +442 7 +2630 4 +3923 9 +701 4 +878 2 +2700 1 +609 10 +2911 4 +2702 4 +925 9 +2769 9 +268 6 +113 8 +923 8 +1044 2 +1163 6 +3896 8 +1770 6 +343 6 +785 8 +102 7 +3757 6 +2902 3 +2140 2 +2897 1 +1369 7 +853 4 +3715 3 +3842 10 +2289 2 +3955 8 +1795 5 +2428 6 +212 1 +348 5 +368 3 +2240 3 +956 4 +3489 8 +1081 3 +1098 7 +2015 5 +147 8 +4028 2 +1067 8 +187 9 +1350 6 +1201 1 +2986 1 +2236 10 +722 3 +1902 6 +2518 1 +11 1 +407 7 +718 3 +3125 6 +1605 9 +1577 2 +1349 5 +899 7 +3277 4 +188 6 +2315 9 +2535 8 +2148 8 +2422 9 +93 10 +3583 2 +147 8 +507 7 +1484 5 +2812 6 +1520 6 +1901 10 +475 8 +1402 4 +1454 3 +2988 10 +2328 10 +2863 5 +1956 5 +1655 8 +988 3 +421 3 +3287 9 +3223 7 +2255 3 +1825 5 +2010 6 +2240 7 +2655 1 +38 4 +968 10 +3451 10 +759 1 +1362 7 +421 5 +1943 8 +1099 3 +1756 10 +513 7 +3683 10 +2108 9 +1000 7 +1072 3 +2710 6 +3839 1 +3884 9 +2408 8 +3533 10 +2453 7 +1253 3 +130 5 +280 7 +3464 3 +1994 6 +105 6 +3473 2 +1407 1 +3019 9 +1820 7 +3278 9 +16 8 +81 1 +1135 10 +2509 7 +2685 4 +1252 3 +585 1 +526 8 +1689 4 +3582 9 +350 7 +2432 4 +683 2 +437 6 +2594 4 +1520 5 +4041 9 +612 9 +2342 1 +2657 7 +1893 3 +528 1 +657 3 +1296 9 +4046 9 +1828 4 +2444 3 +1655 7 +175 9 +648 6 +1541 5 +2987 10 +944 1 +3777 2 +691 1 +1904 6 +1786 8 +1663 6 +1423 7 +597 7 +480 3 +2398 2 +417 10 +2610 9 +3464 7 +593 6 +2428 6 +2220 10 +317 6 +1135 7 +2762 3 +1943 4 +1736 3 +975 1 +14 6 +3681 6 +633 6 +2505 4 +3971 5 +2618 10 +3902 10 +618 2 +3249 9 +495 4 +4030 3 +86 7 +3327 2 +28 6 +94 4 +1717 5 +783 8 +2521 10 +4018 8 +2156 5 +1331 10 +958 2 +3362 3 +3351 2 +381 7 +114 1 +1805 7 +1903 2 +2663 9 +2542 3 +283 1 +3931 7 +1115 3 +563 3 +2584 8 +1400 6 +3584 5 +2605 10 +3338 8 +4029 5 +1157 1 +1828 3 +1982 2 +2276 6 +1531 4 +626 6 +181 7 +3734 5 +140 1 +2835 1 +3805 7 +3094 8 +2553 10 +1948 1 +69 1 +732 5 +786 2 +2152 4 +3992 10 +2884 9 +611 8 +2053 1 +3132 1 +159 6 +3376 4 +3846 2 +2703 1 +2660 4 +583 8 +3563 3 +3421 5 +2081 8 +1372 8 +3802 7 +3927 2 +1332 1 +401 10 +3164 10 +640 6 +665 6 +3261 4 +1292 4 +2037 10 +297 8 +607 7 +2218 8 +3101 1 +298 5 +709 3 +472 3 +1995 1 +1475 7 +3289 2 +1152 10 +188 1 +2554 3 +2655 8 +388 5 +386 3 +3997 5 +933 9 +2941 1 +4047 3 +85 8 +3850 5 +1757 3 +3920 3 +1611 4 +1817 6 +2138 1 +2944 4 +244 3 +3902 4 +93 8 +1614 9 +1851 3 +621 9 +3211 9 +503 4 +3034 3 +2328 6 +4021 9 +1839 6 +221 8 +908 9 +2417 7 +819 7 +590 8 +1940 1 +1652 1 +3750 3 +191 3 +2247 8 +167 3 +1034 5 +34 9 +295 5 +1149 7 +1762 6 +1853 1 +2450 5 +1682 3 +369 7 +3726 1 +613 4 +3931 5 +2214 3 +303 7 +1091 2 +642 5 +1675 8 +743 4 +1176 5 +2579 1 +2473 5 +3862 3 +3672 1 +1129 8 +1191 6 +3790 3 +2537 10 +1950 3 +2653 6 +3653 3 +1212 4 +1082 10 +147 5 +1468 5 +730 6 +2640 1 +335 7 +2568 8 +2719 1 +689 3 +686 3 +2145 6 +50 8 +2911 8 +3260 5 +3244 5 +3703 1 +577 8 +2192 6 +1459 7 +759 10 +2185 10 +895 6 +3981 4 +1420 3 +2161 5 +2529 7 +2943 10 +778 3 +828 10 +4087 7 +2416 8 +692 2 +3985 6 +395 6 +3628 10 +3951 7 +3089 8 +2571 2 +2867 2 +982 5 +1022 1 +442 4 +2390 2 +3345 1 +308 2 +3818 7 +3433 6 +3896 1 +694 6 +3157 2 +2557 7 +2151 9 +2786 1 +751 8 +371 7 +4051 2 +1717 5 +439 4 +2833 3 +3278 8 +1070 4 +459 2 +2349 3 +46 7 +588 4 +539 3 +3371 6 +1310 8 +2531 5 +2075 1 +2766 2 +3242 8 +3066 4 +2900 10 +3021 3 +7 6 +3311 6 +2171 8 +3750 1 +1550 1 +756 1 +1849 1 +2649 6 +1134 10 +2693 2 +52 3 +2004 3 +1782 10 +3076 2 +1586 7 +3650 9 +1705 5 +3287 9 +2025 8 +1077 9 +2233 3 +1816 2 +1850 7 +273 1 +3458 9 +2606 6 +83 2 +2657 10 +2486 4 +4052 7 +2874 10 +520 4 +2485 6 +2587 7 +3806 7 +4024 4 +3391 10 +2760 6 +3009 2 +144 3 +1414 5 +3565 8 +3128 9 +3192 7 +3333 8 +318 1 +3937 7 +2027 2 +951 10 +2610 9 +1260 10 +3343 9 +3218 6 +3079 9 +1587 3 +1032 5 +658 8 +868 10 +1085 10 +749 5 +4028 6 +1029 3 +3979 10 +4001 9 +1181 8 +1281 6 +320 5 +68 4 +4085 2 +1857 3 +3240 1 +1193 2 +525 5 +3535 7 +2438 6 +1771 9 +2812 1 +3815 8 +144 2 +366 6 +1847 2 +1434 3 +3170 6 +76 1 +3522 7 +3703 1 +2016 10 +1516 1 +1804 2 +1727 8 +2682 6 +2672 5 +687 1 +442 2 +314 4 +2553 3 +2489 5 +1319 9 +2001 2 +2297 1 +935 8 +3378 6 +2472 4 +1358 4 +1640 4 +1958 10 +1719 7 +32 9 +3620 10 +2455 9 +1186 8 +3283 8 +1937 2 +2787 3 +2208 6 +1680 8 +3348 5 +886 5 +213 10 +3651 6 +2328 5 +3140 1 +783 1 +3679 2 +486 3 +3997 6 +2420 2 +3116 7 +2596 6 +651 1 +594 8 +1197 5 +1954 5 +2844 1 +2550 5 +311 2 +3818 4 +3099 7 +4072 10 +4085 9 +1618 9 +2572 6 +3031 8 +43 10 +224 9 +1515 2 +1248 2 +3187 6 +2950 8 +3835 5 +2238 4 +4030 2 +2980 10 +2152 8 +1105 5 +1238 5 +3564 10 +1892 3 +1019 10 +1351 8 +2964 9 +2191 9 +4058 7 +1366 7 +1843 10 +2136 7 +210 2 +1870 3 +2307 8 +1405 4 +2098 2 +420 3 +3166 9 +3400 1 +2946 9 +1210 6 +850 6 +906 3 +256 10 +2817 7 +2319 10 +1367 8 +717 5 +149 4 +1035 4 +964 3 +1747 2 +3494 1 +3187 1 +1071 8 +2716 1 +319 4 +3392 7 +851 2 +1355 4 +1907 2 +385 8 +958 1 +933 2 +4004 7 +306 9 +637 4 +2620 10 +131 8 +3138 7 +3146 5 +3665 10 +342 1 +2361 7 +3332 7 +1153 4 +1208 3 +3453 5 +2285 2 +1692 9 +1565 9 +3932 5 +1129 2 +1282 4 +1323 7 +194 6 +1363 1 +1288 3 +4087 2 +3244 2 +1408 4 +3278 9 +3000 8 +84 3 +3788 6 +3777 9 +352 6 +3082 2 +3815 8 +401 3 +278 7 +1410 6 +736 4 +1051 2 +2683 8 +2580 3 +2862 5 +769 5 +3626 5 +4006 7 +618 5 +1977 1 +771 7 +4026 8 +3212 4 +1323 5 +2699 8 +3683 7 +4081 10 +4042 10 +2115 5 +2221 1 +1006 6 +3965 7 +1466 5 +2782 7 +3883 10 +465 3 +3280 1 +1152 10 +557 9 +1061 10 +1181 1 +1449 3 +2154 9 +3221 10 +108 6 +1115 10 +2308 6 +287 8 +1775 5 +1918 5 +978 6 +1054 9 +848 9 +1469 8 +729 4 +2086 4 +2710 6 +3468 2 +2673 3 +676 9 +3198 4 +985 1 +3647 8 +1025 7 +1461 5 +3741 7 +3780 10 +2885 8 +37 9 +3114 1 +1704 4 +2775 3 +3515 7 +2277 9 +2176 1 +3196 7 +3231 10 +2693 4 +2855 8 +1774 1 +3426 6 +1097 9 +2088 8 +178 1 +405 4 +3199 9 +2633 8 +1241 1 +3782 8 +3637 2 +2732 9 +1295 10 +2952 8 +585 2 +1605 6 +1753 6 +3015 5 +184 5 +872 3 +4030 4 +1418 5 +2318 7 +3813 7 +2012 6 +574 7 +2574 10 +2898 2 +1492 3 +3735 7 +2882 9 +1446 10 +1671 10 +1146 3 +2947 5 +3150 8 +2796 4 +872 8 +3915 10 +2135 5 +1806 4 +3748 9 +3824 10 +3866 4 +2236 9 +3597 7 +3421 7 +608 9 +227 10 +1735 10 +674 10 +2621 8 +2742 8 +2056 7 +3717 3 +2211 10 +2546 2 +2210 6 +2756 5 +268 3 +2698 2 +276 4 +424 4 +3217 3 +221 2 +660 7 +1626 4 +2158 10 +324 7 +609 3 +3056 1 +2207 8 +1253 7 +1224 3 +2636 9 +3560 6 +3137 7 +3178 5 +3879 3 +2797 5 +2394 9 +550 8 +3610 2 +384 7 +1668 7 +3456 4 +1876 5 +1874 1 +1244 8 +3161 6 +1389 6 +1097 7 +743 3 +3599 9 +2129 2 +3620 7 +858 3 +3993 4 +1686 6 +2561 3 +3456 7 +656 6 +3245 1 +734 5 +849 1 +897 2 +2861 1 +1711 8 +1549 3 +1081 3 +1208 6 +4063 3 +66 8 +2047 7 +2031 6 +704 3 +1293 5 +2441 8 +2816 9 +3667 10 +709 10 +1702 8 +3080 9 +389 7 +1949 1 +3887 7 +1712 2 +3273 10 +3876 2 +1662 6 +117 10 +923 6 +193 2 +3301 10 +3128 6 +2148 5 +2265 6 +3990 7 +2615 3 +3310 7 +2775 5 +3110 10 +2657 9 +1001 7 +1065 1 +1793 7 +533 9 +2986 6 +2089 9 +26 3 +2384 5 +3568 8 +969 2 +3062 3 +2330 6 +661 8 +956 7 +1684 3 +448 4 +2293 1 +2192 8 +3401 1 +1961 2 +869 3 +132 9 +902 9 +3533 6 +2493 5 +2162 2 +1644 7 +2240 1 +2152 6 +1617 9 +1023 5 +1934 10 +3861 3 +2532 1 +2440 2 +3584 6 +1317 1 +1939 8 +931 7 +125 4 +2073 4 +1806 3 +2377 2 +2070 3 +532 2 +741 10 +1092 6 +2350 1 +455 5 +2687 1 +2664 4 +3497 4 +1812 6 +1456 1 +394 8 +3347 3 +937 10 +3880 2 +1317 9 +3140 4 +300 8 +397 1 +2059 5 +2476 9 +1608 1 +3288 5 +2640 2 +1757 3 +2641 6 +2603 5 +2545 2 +3159 9 +3387 7 +3987 8 +1645 5 +2049 1 +2995 1 +1532 1 +2478 3 +2599 7 +3035 2 +768 6 +525 2 +3308 10 +246 9 +1723 5 +2727 9 +518 9 +1222 5 +677 2 +1196 2 +1824 3 +3310 4 +1129 5 +2665 2 +2004 6 +862 2 +1190 2 +2075 5 +2657 9 +2618 7 +3337 7 +3113 9 +1970 4 +1988 1 +863 8 +2625 10 +147 9 +1395 6 +2187 2 +1039 5 +1843 6 +1805 10 +1913 1 +2793 9 +2420 3 +1987 7 +1233 8 +3491 4 +3761 6 +2967 2 +443 3 +1502 6 +1586 10 +99 9 +2373 7 +3045 2 +945 7 +1145 2 +658 8 +682 2 +2717 2 +3663 1 +3178 1 +1558 10 +3148 3 +1159 2 +968 8 +3862 8 +2476 6 +63 9 +142 7 +2412 3 +2505 3 +4079 7 +3113 9 +1160 8 +1234 5 +2604 6 +3123 4 +366 3 +2954 1 +2298 9 +3526 7 +3071 2 +1579 2 +3108 10 +341 10 +3385 8 +3201 2 +4024 3 +3989 1 +2840 3 +803 10 +1698 8 +1100 10 +2982 9 +1657 7 +3584 8 +3626 3 +1983 1 +1765 10 +3843 4 +3101 10 +2972 8 +1692 9 +1874 4 +188 2 +1425 10 +2366 2 +3314 1 +2063 9 +2354 1 +2565 4 +1190 10 +3072 7 +945 6 +2670 10 +102 3 +3070 7 +1750 5 +506 8 +3060 2 +3108 9 +40 10 +1995 4 +2963 2 +217 6 +1585 5 +661 5 +769 4 +3476 9 +1583 7 +128 4 +1154 1 +3485 3 +276 2 +2850 4 +4026 9 +1551 8 +3113 3 +1887 5 +1895 7 +653 4 +960 4 +4060 9 +2873 8 +1374 3 +2762 2 +2336 5 +2954 4 +3048 7 +3791 9 +2818 3 +2544 9 +2364 6 +1081 8 +1369 3 +2397 9 +3635 8 +3219 2 +1811 4 +1532 2 +2492 4 +229 9 +1725 8 +1608 8 +257 2 +486 9 +2756 5 +212 8 +3191 9 +1855 4 +3752 8 +2958 4 +1134 3 +3533 3 +1951 10 +2131 4 +2610 9 +2919 4 +3949 2 +3292 2 +1456 1 +2276 4 +3196 5 +3501 8 +1020 10 +1175 5 +3252 3 +3757 5 +2920 4 +1755 9 +410 3 +605 7 +1207 8 +2536 5 +3803 4 +972 9 +259 6 +2712 3 +1886 6 +1610 10 +3107 5 +100 10 +1551 1 +2627 8 +876 6 +979 1 +3767 7 +1682 4 +3011 10 +1346 3 +4060 2 +749 2 +985 4 +1607 7 +2158 9 +219 10 +1320 10 +989 8 +2288 9 +4002 9 +3639 3 +2251 6 +108 8 +3571 5 +1871 4 +1798 8 +3303 9 +830 10 +204 5 +2710 4 +690 1 +871 2 +3513 7 +1718 6 +1493 8 +2766 2 +2847 7 +3304 4 +1122 5 +4016 9 +3035 3 +3626 7 +1202 3 +2422 2 +2267 9 +2837 2 +1253 10 +2135 4 +2592 7 +895 1 +497 7 +258 8 +2515 9 +3309 7 +1945 10 +279 7 +807 7 +750 4 +2745 7 +3154 2 +1091 1 +55 6 +3749 2 +2469 8 +1771 1 +434 8 +935 8 +3013 3 +241 10 +343 3 +3839 7 +2967 4 +2877 9 +729 1 +2844 2 +1627 1 +1805 6 +355 3 +3715 3 +3513 3 +294 4 +3911 8 +1748 6 +3890 10 +1027 1 +3646 7 +1210 8 +3549 3 +882 4 +2439 8 +3578 7 +606 3 +3881 6 +2532 6 +1396 8 +3425 10 +778 8 +3003 10 +1838 10 +1596 5 +416 8 +2314 4 +2755 9 +2133 6 +3384 1 +3039 10 +2575 8 +93 7 +134 10 +2137 3 +1431 2 +1299 6 +1745 8 +943 5 +496 2 +394 1 +0 8 +693 5 +3931 3 +3976 10 +3829 10 +3181 7 +1338 5 +3057 10 +2894 9 +2043 1 +3121 10 +2248 10 +1188 8 +265 8 +3422 3 +3565 4 +649 9 +2980 1 +2923 4 +3570 8 +357 3 +442 4 +1470 4 +2726 10 +4003 8 +1331 5 +3786 7 +2368 3 +3113 8 +902 3 +426 8 +1570 10 +1944 2 +4049 7 +3548 1 +728 5 +1047 7 +3482 10 +2645 2 +928 9 +1986 1 +209 3 +2623 2 +3860 4 +1380 8 +4026 7 +3918 5 +1051 10 +3944 3 +3250 2 +694 10 +402 6 +1707 7 +4037 10 +1283 5 +1261 1 +104 10 +2859 1 +1262 7 +3877 8 +466 8 +122 1 +3346 9 +3570 8 +1921 8 +3987 3 +1670 10 +2598 2 +3718 10 +2091 5 +3745 9 +1009 5 +2823 3 +2506 3 +2945 4 +1941 1 +2372 4 +833 7 +2509 4 +3358 1 +401 7 +3688 8 +3441 4 +306 9 +3991 7 +1636 5 +789 9 +3662 6 +728 2 +3376 3 +2619 7 +3994 8 +3485 1 +1844 4 +2819 3 +1027 9 +1267 7 +2068 4 +1659 6 +1878 4 +3620 8 +778 3 +3801 8 +1354 1 +1967 5 +3829 7 +1123 5 +3990 9 +3199 3 +2923 3 +1366 1 +3516 10 +1228 4 +1367 4 +3435 7 +1213 4 +564 7 +3668 7 +1730 5 +2317 6 +1688 4 +1647 1 +3429 6 +1080 4 +721 1 +1795 8 +3204 9 +3529 8 +581 3 +1833 6 +2435 2 +3641 4 +3085 9 +1569 6 +2799 6 +1389 7 +418 7 +3103 6 +2438 6 +3126 5 +501 9 +2675 9 +750 1 +504 3 +372 10 +1741 4 +3746 6 +4075 10 +2654 8 +622 10 +633 5 +2107 10 +869 3 +66 3 +1724 8 +2734 7 +3801 2 +414 8 +2164 1 +2812 2 +396 9 +2526 7 +3088 1 +277 4 +3455 4 +2535 8 +3039 6 +2670 3 +762 3 +2842 4 +3746 1 +1691 4 +429 4 +3319 2 +192 3 +3180 4 +3633 10 +1232 10 +2420 2 +622 8 +1721 1 +3665 8 +2476 1 +2432 5 +2419 7 +1778 6 +2852 8 +3101 5 +948 2 +1896 6 +311 7 +3321 8 +1686 3 +3126 2 +2589 5 +3920 6 +3499 3 +404 2 +1581 6 +3045 4 +3363 4 +481 5 +3439 8 +2868 8 +2306 2 +1331 1 +1352 4 +797 3 +2136 7 +2222 5 +1796 10 +1541 3 +144 7 +3522 1 +3608 5 +3480 2 +423 9 +1621 1 +3896 3 +614 8 +610 10 +975 6 +287 5 +1651 6 +4087 7 +1979 10 +1406 3 +2786 2 +2682 8 +901 6 +2356 1 +1623 9 +1311 10 +3431 6 +873 7 +2216 4 +3918 1 +3801 4 +2766 8 +4005 10 +767 1 +1933 2 +1532 3 +79 5 +2101 3 +2366 8 +412 6 +2925 9 +3375 3 +1773 4 +4009 8 +3572 8 +1512 5 +1188 2 +3942 7 +3366 6 +1544 6 +3548 10 +340 1 +678 6 +3557 6 +922 6 +3996 5 +1672 7 +1910 5 +1099 2 +3570 9 +4029 2 +3950 6 +1599 10 +1841 9 +3785 5 +3981 6 +3063 9 +986 9 +347 10 +1832 5 +2273 1 +2509 8 +2470 5 +2067 10 +719 6 +1269 8 +2941 1 +4031 7 +3032 3 +2822 5 +916 7 +1781 4 +2107 1 +3950 2 +2227 7 +3153 4 +610 5 +913 3 +403 6 +340 7 +3573 10 +1325 9 +881 7 +3903 4 +799 9 +1249 8 +2114 3 +3648 1 +4076 4 +3782 10 +68 6 +3936 9 +2202 9 +3932 4 +1467 4 +2978 5 +476 4 +222 9 +2747 1 +1227 9 +1823 8 +2387 10 +1440 4 +2887 10 +943 4 +875 5 +1401 1 +1615 10 +3520 2 +2384 10 +2884 8 +3669 5 +2387 9 +164 6 +172 3 +2510 2 +2926 9 +3235 6 +1881 5 +1950 7 +3728 6 +1128 1 +417 6 +836 6 +149 7 +1300 6 +3946 8 +86 10 +3291 8 +1233 3 +3856 1 +3118 1 +1761 1 +430 5 +938 6 +297 4 +1548 1 +2995 4 +1048 3 +3783 5 +3499 7 +3868 2 +2272 10 +4007 10 +3906 10 +309 3 +1660 10 +2925 3 +2792 7 +773 4 +3786 1 +3468 5 +2748 1 +1680 6 +978 7 +815 5 +1632 6 +291 9 +3937 1 +1277 1 +4071 2 +3781 5 +1858 3 +399 6 +1108 8 +3145 6 +2173 9 +3652 6 +1588 4 +1241 7 +2724 5 +2344 6 +279 2 +2602 8 +588 9 +3281 5 +742 2 +3824 3 +2506 9 +60 4 +2815 4 +3679 1 +2121 7 +755 9 +3033 1 +1025 3 +1265 10 +1513 2 +1802 3 +2800 9 +1695 1 +229 10 +466 1 +126 8 +4027 5 +943 7 +4066 8 +2329 5 +3925 2 +3970 6 +553 4 +3589 3 +1504 10 +939 2 +829 8 +3608 4 +3197 9 +1613 4 +2219 3 +2744 10 +296 7 +3970 6 +3902 5 +1915 2 +3423 4 +3305 9 +3303 9 +1819 5 +3765 3 +509 6 +1146 9 +2902 6 +4035 4 +950 9 +1946 7 +3092 3 +397 3 +2952 4 +870 7 +3611 6 +2213 10 +2894 3 +540 8 +1944 3 +1879 8 +2040 4 +1552 10 +2498 2 +823 4 +452 8 +3351 1 +3025 7 +3241 5 +2244 7 +3168 4 +2072 6 +195 5 +880 6 +1257 7 +3455 2 +504 7 +1848 2 +2660 4 +2317 8 +1884 3 +225 4 +1809 10 +552 5 +1112 5 +340 8 +3021 2 +3084 3 +2140 6 +519 8 +1879 2 +2878 5 +1785 10 +1589 2 +1259 2 +3609 5 +2048 10 +2345 10 +670 8 +3944 6 +1773 9 +1612 7 +4076 4 +2856 9 +332 9 +2127 8 +1091 2 +3606 6 +751 3 +4036 9 +3866 9 +1326 3 +1120 9 +3361 8 +417 6 +1075 2 +1459 6 +1269 5 +3602 5 +2276 1 +678 3 +3846 9 +206 3 +1592 5 +1677 4 +2752 4 +2158 1 +2350 6 +2931 8 +2294 1 +1215 1 +363 3 +1423 3 +1526 10 +199 1 +3893 7 +3443 1 +2004 1 +1796 3 +292 9 +3030 5 +1002 7 +1657 4 +717 4 +1567 3 +663 8 +4037 10 +1253 9 +2510 4 +1699 4 +2198 6 +202 8 +777 10 +3846 3 +2196 5 +2910 2 +2246 9 +3640 9 +1491 5 +1503 10 +1670 4 +344 7 +3988 9 +1347 2 +502 10 +2808 3 +3885 5 +2786 2 +267 3 +3512 3 +3211 10 +491 9 +2175 7 +2833 3 +3513 6 +3403 9 +973 10 +1560 3 +734 4 +533 2 +1839 1 +1926 4 +2975 1 +2156 3 +3377 2 +2299 4 +666 3 +3981 2 +2857 6 +627 6 +34 7 +3789 7 +2067 3 +751 6 +2819 9 +1311 9 +1113 5 +2389 1 +2600 9 +1820 6 +1090 9 +3392 3 +2987 2 +2031 2 +2522 2 +4004 1 +151 2 +3816 3 +2188 6 +2184 7 +540 2 +2076 6 +3861 10 +3289 2 +1024 6 +2344 1 +1880 4 +1704 3 +395 2 +3616 3 +3136 4 +2388 5 +3016 3 +3086 8 +2745 3 +2143 7 +1009 9 +3566 9 +155 8 +330 4 +3616 3 +2777 5 +34 7 +3824 2 +58 3 +1069 9 +1959 6 +1326 10 +121 1 +39 2 +708 8 +433 3 +2002 3 +1537 9 +459 1 +2062 1 +2212 1 +1689 2 +301 8 +785 9 +1777 4 +2689 4 +2614 5 +3668 7 +3096 8 +433 3 +3618 1 +902 10 +760 3 +1181 10 +570 1 +3705 6 +2119 1 +2040 7 +75 9 +945 8 +1652 2 +261 4 +1925 5 +400 1 +1630 4 +3873 6 +3964 3 +3633 10 +2434 6 +3058 9 +437 2 +1939 4 +1577 1 +585 5 +3775 1 +3825 3 +3629 7 +98 3 +593 10 +2123 9 +2668 9 +1845 8 +440 6 +3140 4 +1397 8 +2796 6 +1974 10 +2409 7 +1383 6 +3167 9 +3146 2 +3175 1 +2007 2 +4083 2 +782 9 +2423 7 +41 5 +2687 9 +1083 5 +2213 6 +1865 10 +1077 2 +770 4 +3067 1 +2747 3 +3136 5 +2861 7 +2093 4 +3547 4 +3509 10 +3388 2 +3252 6 +2245 10 +2690 1 +915 7 +2760 2 +2304 10 +1416 3 +1226 10 +2056 7 +371 4 +1700 4 +1080 3 +722 8 +1133 4 +1915 7 +22 8 +368 2 +1223 5 +513 3 +216 5 +923 10 +4081 6 +1186 7 +2072 10 +335 2 +3573 6 +1543 8 +1825 3 +110 10 +2327 1 +1010 6 +1954 4 +3420 2 +1862 4 +3075 10 +2937 9 +3747 3 +322 2 +2944 9 +3751 6 +2462 10 +3596 9 +686 8 +2853 1 +2072 1 +2941 9 +513 10 +3508 4 +419 3 +1327 2 +1594 10 +3150 7 +3013 1 +3214 3 +2671 5 +3782 10 +3802 1 +3958 10 +3795 6 +1522 6 +1401 4 +220 6 +2269 10 +3654 3 +755 1 +1803 6 +3780 2 +194 4 +4057 1 +2433 1 +856 7 +3131 5 +3963 6 +1949 6 +1643 7 +3594 6 +342 10 +3132 8 +1849 3 +2588 5 +3774 9 +186 9 +2446 4 +162 3 +1681 8 +320 1 +473 5 +1648 8 +809 5 +1421 6 +1656 7 +2678 4 +3269 2 +2563 7 +669 4 +921 2 +3819 10 +1546 6 +2286 9 +381 3 +3492 5 +1230 3 +195 4 +3236 9 +631 6 +1848 8 +2904 2 +3668 2 +1794 8 +3286 1 +3144 4 +1830 7 +1039 8 +3926 6 +3408 5 +605 1 +3806 10 +2356 3 +2266 1 +1520 5 +702 8 +380 3 +122 7 +1726 4 +1139 4 +3062 3 +2496 7 +3760 10 +211 6 +2970 4 +1211 3 +2315 9 +2739 6 +1137 9 +1725 6 +3946 4 +3446 10 +1218 10 +3736 5 +3246 1 +3816 7 +3051 6 +340 3 +3934 8 +2177 8 +963 4 +1978 9 +1076 5 +3329 7 +2824 6 +900 7 +1077 7 +591 5 +809 5 +1175 2 +598 2 +3882 2 +1753 1 +3796 1 +2958 7 +2551 5 +2574 7 +2240 1 +578 1 +2462 10 +2082 9 +4043 2 +489 4 +2008 7 +3176 4 +2675 9 +3178 2 +1655 7 +3293 3 +433 6 +3353 2 +2230 7 +179 5 +2290 5 +69 9 +2822 4 +908 1 +1488 3 +103 1 +1803 10 +3633 5 +1447 5 +1165 2 +414 5 +3311 5 +1882 8 +3396 10 +2937 9 +1823 2 +1895 2 +3746 9 +1409 3 +677 4 +266 6 +2961 3 +3229 2 +284 10 +510 5 +1385 4 +1105 9 +1481 10 +2218 7 +3113 9 +1185 10 +481 4 +3427 4 +859 5 +3885 8 +2238 5 +1933 10 +3188 7 +3824 2 +3712 2 +3336 7 +1127 8 +3648 5 +2894 9 +1370 4 +2276 2 +2952 6 +3528 10 +3977 6 +3714 3 +255 3 +1946 4 +2867 10 +978 8 +3391 1 +3137 6 +3584 6 +3170 1 +1441 6 +3988 2 +68 1 +2842 1 +2574 5 +525 10 +2742 6 +873 7 +3436 9 +836 2 +1320 4 +298 4 +3559 1 +3008 2 +2519 5 +649 2 +3098 6 +1217 9 +430 4 +508 3 +3641 8 +2941 8 +1172 7 +3938 8 +987 10 +2640 7 +2175 7 +1589 1 +3858 6 +1799 7 +2386 5 +2921 5 +229 9 +1875 8 +3662 5 +3382 5 +1457 8 +2667 1 +1020 4 +1529 8 +2273 3 +3537 9 +2486 3 +3058 8 +3500 4 +3907 2 +4023 8 +2301 5 +875 10 +853 4 +1284 10 +1577 7 +568 2 +3351 9 +3747 8 +1624 8 +3734 1 +1924 2 +453 5 +2140 10 +2486 6 +886 4 +1088 4 +1911 8 +1722 3 +260 6 +1655 1 +1627 10 +575 4 +2477 5 +3718 5 +1236 2 +1886 10 +608 1 +2025 10 +442 8 +664 3 +3810 7 +802 6 +1433 1 +1700 8 +1823 7 +3167 3 +679 6 +2025 9 +3808 7 +1765 9 +2703 1 +2508 6 +1762 5 +1219 4 +2483 10 +3182 7 +3739 2 +1473 6 +1270 1 +3942 2 +3869 10 +650 9 +713 1 +2696 6 +2817 7 +2214 9 +3339 8 +3379 2 +444 1 +837 9 +3325 6 +3605 7 +133 9 +3903 5 +129 7 +919 9 +67 2 +1519 6 +2093 2 +863 9 +2481 10 +2267 4 +388 1 +4034 5 +2236 2 +2963 8 +2563 10 +2641 10 +1925 7 +435 10 +946 2 +1408 3 +1672 9 +1064 10 +690 3 +1566 6 +3434 1 +2659 9 +3511 9 +157 1 +1768 6 +3980 2 +3126 4 +1763 7 +1494 1 +956 9 +1267 4 +1485 1 +368 10 +3108 5 +1683 9 +2098 5 +2746 6 +612 3 +1994 5 +3867 5 +2411 9 +3485 4 +3200 6 +807 3 +2942 5 +3652 6 +3093 5 +1102 9 +3343 5 +1669 7 +366 3 +2797 6 +1969 3 +3297 4 +2688 10 +3444 6 +1576 8 +2409 4 +19 5 +76 4 +241 8 +126 2 +342 5 +2267 8 +322 3 +1458 3 +771 5 +355 7 +1012 6 +1410 2 +225 4 +625 1 +1537 5 +3643 4 +4017 7 +1681 10 +18 7 +988 9 +531 6 +3340 1 +3715 5 +552 4 +481 5 +2289 9 +2799 2 +1854 9 +3959 4 +3941 7 +697 4 +3044 5 +3879 10 +823 2 +482 7 +766 5 +1611 2 +1186 1 +1063 5 +3696 4 +3997 4 +1121 2 +1532 4 +3565 2 +3844 8 +3642 2 +2298 8 +3612 4 +3319 6 +2730 3 +1361 9 +2790 3 +2653 10 +3237 4 +2719 2 +88 5 +894 1 +4048 3 +645 4 +2641 7 +970 9 +3808 3 +3216 3 +343 1 +2582 9 +3595 5 +2230 10 +2953 10 +2343 8 +2333 5 +2659 3 +3320 10 +2310 9 +3659 1 +2166 6 +1147 7 +3420 6 +3912 1 +2932 6 +4095 5 +815 3 +671 10 +1709 10 +437 3 +2612 7 +948 10 +582 8 +600 3 +2057 10 +1943 1 +3193 6 +1005 5 +2603 2 +1975 6 +1551 7 +861 9 +805 4 +2556 8 +2980 8 +1150 9 +2859 8 +3236 10 +2504 7 +3151 2 +2432 10 +1337 8 +3581 5 +2099 6 +2249 1 +2755 9 +3959 9 +2478 4 +1950 2 +696 9 +783 8 +3474 10 +1250 4 +1640 4 +406 8 +1045 2 +2403 10 +465 1 +2555 10 +867 6 +932 5 +782 8 +991 1 +3450 4 +2163 7 +4014 5 +2548 10 +2088 9 +2206 8 +2695 2 +2360 8 +3681 2 +1849 7 +2659 4 +688 9 +375 8 +1702 10 +110 1 +2464 1 +3988 5 +1309 4 +316 7 +3777 2 +304 6 +3448 1 +3484 3 +414 2 +2171 3 +2190 5 +1234 6 +85 5 +4036 8 +2928 8 +832 9 +800 10 +799 9 +598 9 +3154 3 +3829 10 +2183 9 +303 6 +2100 3 +3751 2 +1404 2 +2872 3 +3529 10 +3178 3 +3184 5 +2229 4 +2452 1 +4064 3 +2624 4 +1858 5 +4038 9 +2116 3 +3140 5 +1762 2 +1278 7 +3472 5 +3779 9 +3487 8 +1745 1 +904 3 +1487 9 +1532 8 +1159 2 +2898 1 +1408 10 +2516 10 +2320 1 +3764 3 +2506 7 +1887 2 +1457 6 +2111 3 +1434 8 +328 9 +302 7 +3819 6 +1137 3 +2846 9 +1432 1 +3129 8 +2929 5 +1912 5 +1461 10 +3630 5 +620 3 +3217 5 +3176 10 +2691 5 +923 9 +130 6 +3075 8 +3104 2 +634 9 +1953 5 +840 10 +788 9 +2142 7 +788 10 +3641 10 +2398 10 +106 2 +2817 9 +2196 2 +1266 10 +4091 1 +2069 1 +751 6 +3077 5 +2497 6 +1919 8 +2524 6 +547 10 +3896 2 +3216 6 +2263 1 +74 8 +3736 4 +2958 7 +221 9 +2353 1 +3987 7 +3894 2 +3556 3 +1661 3 +1270 4 +3749 6 +3599 1 +2712 6 +1776 8 +1370 1 +1757 9 +3157 4 +2404 10 +779 4 +3029 2 +3154 8 +1503 2 +1166 8 +1657 9 +1727 9 +2278 2 +575 7 +3046 5 +2276 1 +763 3 +3781 5 +1355 6 +2091 4 +3323 9 +904 9 +2388 8 +261 6 +1099 2 +827 10 +1204 4 +728 5 +717 5 +1425 1 +1017 5 +3516 9 +1395 3 +1883 1 +3193 8 +1838 1 +1226 10 +1646 6 +2328 1 +2603 6 +32 5 +2660 6 +3992 7 +977 5 +3369 2 +211 1 +1526 5 +3302 10 +3332 3 +1422 3 +3467 5 +252 5 +4001 10 +3832 3 +647 5 +1311 8 +2676 7 +777 3 +1459 8 +3346 1 +3498 3 +4042 10 +2097 1 +928 8 +1523 6 +1179 8 +229 3 +111 3 +3898 5 +1932 9 +1413 1 +2283 7 +3192 3 +3533 7 +3581 1 +3549 4 +425 7 +2740 2 +2600 2 +4006 3 +1513 8 +4017 5 +3449 6 +3751 5 +3518 3 +771 2 +2254 5 +3596 4 +1826 9 +1265 4 +658 4 +1015 2 +3840 2 +186 3 +1904 4 +988 6 +2508 4 +3309 9 +1553 6 +1894 7 +4064 10 +2256 1 +1399 6 +3120 9 +3891 3 +2364 1 +3351 2 +3364 9 +3724 8 +3279 7 +809 10 +3446 1 +1057 3 +3114 9 +3952 5 +2817 3 +312 3 +437 10 +1690 10 +2620 2 +2785 7 +3914 2 +654 8 +2473 5 +570 10 +1857 8 +2927 3 +3633 8 +2586 10 +1979 9 +3221 10 +185 8 +3094 3 +10 3 +335 7 +3610 7 +3820 9 +3210 9 +788 9 +224 4 +2623 5 +2714 6 +1288 6 +597 7 +1995 9 +1699 7 +2072 6 +3344 6 +2649 5 +1779 6 +324 1 +1018 1 +2155 7 +869 7 +1636 2 +3612 5 +2360 5 +1043 10 +2716 10 +1962 7 +1923 8 +2994 10 +1160 3 +138 10 +1379 4 +942 1 +2718 5 +3565 5 +1245 5 +641 6 +1953 2 +1186 4 +126 4 +3651 1 +741 2 +4026 7 +1044 1 +3329 6 +335 3 +757 9 +1959 1 +970 10 +1374 6 +1372 3 +2080 6 +3134 5 +2353 9 +3 9 +2327 3 +3715 9 +2304 7 +3320 2 +3035 2 +954 6 +3934 10 +2073 2 +2233 2 +799 10 +1736 1 +3663 9 +985 4 +233 5 +3515 2 +993 6 +2173 6 +3041 6 +2718 7 +3604 5 +1238 3 +2604 4 +3032 8 +3675 8 +905 7 +3644 2 +1388 7 +3322 1 +3798 1 +3338 4 +1194 7 +2614 3 +1600 8 +2937 8 +1452 10 +893 4 +4077 9 +2633 10 +3024 2 +45 4 +2351 1 +44 7 +248 10 +2566 1 +2282 8 +2721 6 +489 9 +2994 10 +3121 7 +3316 1 +2512 2 +2221 7 +510 1 +3000 3 +2551 5 +3512 4 +3770 5 +472 6 +1555 1 +1540 8 +474 2 +3574 1 +3385 9 +1272 3 +3225 3 +1225 8 +748 4 +1122 1 +376 4 +1160 3 +1260 2 +2478 6 +3236 4 +1873 9 +2811 2 +2034 1 +2712 3 +3957 7 +1364 4 +1303 1 +3264 5 +224 10 +714 7 +2487 8 +2272 6 +1067 9 +1252 3 +242 4 +3523 5 +3954 5 +2360 7 +1939 8 +3576 5 +1035 2 +509 3 +1477 6 +3307 8 +3731 6 +2372 7 +736 5 +1469 1 +3459 1 +3949 7 +2502 5 +2273 7 +1007 8 +2756 7 +1486 1 +2849 4 +976 1 +2354 3 +348 5 +3211 4 +3659 9 +3949 2 +1305 10 +779 9 +1559 4 +1827 8 +3133 6 +534 2 +2501 5 +1378 6 +2656 10 +4060 10 +758 9 +2607 8 +535 8 +3398 6 +1572 6 +4092 2 +2856 2 +317 10 +1333 3 +2024 4 +2912 7 +1334 10 +2471 3 +1186 7 +1027 2 +1139 1 +3857 1 +118 6 +15 9 +309 5 +2691 10 +1855 7 +3243 9 +3972 5 +170 5 +783 6 +1648 10 +2250 1 +3008 10 +452 10 +119 2 +2175 8 +2432 2 +3369 9 +340 5 +1207 2 +521 3 +3438 10 +2126 8 +3333 3 +3293 7 +610 3 +1504 9 +3487 5 +3962 8 +834 7 +3231 1 +3834 5 +2801 7 +2515 3 +3627 4 +2839 4 +1796 10 +657 7 +9 7 +1298 1 +2113 1 +2261 4 +1215 4 +570 2 +2509 3 +499 8 +1675 2 +1159 8 +1633 6 +2181 5 +180 5 +496 3 +3674 9 +1866 10 +2576 4 +2640 10 +2986 7 +741 7 +34 2 +4050 10 +624 7 +2524 2 +3795 9 +1544 8 +3232 1 +2544 7 +3116 8 +1180 9 +3784 9 +2335 1 +2941 7 +2329 8 +637 5 +1408 5 +974 6 +747 10 +2873 9 +2754 10 +1682 2 +1962 3 +3132 7 +3578 5 +566 6 +1152 6 +2729 4 +3160 9 +1700 4 +1789 5 +2309 4 +1773 4 +371 2 +3821 6 +3587 7 +2523 3 +993 9 +2604 5 +3284 7 +3117 2 +3249 6 +1839 5 +1228 6 +1835 8 +3598 2 +1284 7 +3343 1 +659 6 +2633 4 +1227 8 +2996 9 +1224 3 +634 7 +3985 4 +262 1 +2655 9 +581 4 +3039 10 +2723 1 +1957 1 +2528 2 +244 5 +137 3 +4075 3 +3436 2 +4087 7 +3641 10 +2620 2 +3511 3 +464 5 +1857 4 +749 4 +2694 7 +3515 2 +3285 4 +2205 5 +1417 8 +1834 10 +3335 9 +2735 2 +2596 5 +4057 6 +3832 2 +3595 10 +126 8 +2982 1 +2578 1 +1442 6 +3415 5 +2849 8 +2145 9 +3870 3 +3082 1 +3210 10 +3737 1 +1449 7 +1304 3 +2853 7 +329 1 +1904 3 +3690 2 +3711 2 +2568 9 +846 4 +1446 2 +106 3 +3568 9 +1030 5 +2394 10 +773 1 +3241 8 +73 8 +2778 6 +119 2 +2873 4 +158 8 +2655 4 +2269 10 +573 1 +3776 8 +435 6 +1733 8 +2862 7 +3845 2 +3189 8 +3969 1 +3108 1 +1215 2 +511 2 +2863 5 +3713 2 +3127 4 +3081 6 +1419 10 +120 10 +2843 6 +3079 7 +382 7 +2755 8 +2196 9 +363 5 +3175 7 +3447 9 +4021 1 +2999 3 +2210 4 +245 8 +3486 6 +196 6 +4055 7 +4083 5 +727 7 +623 6 +1936 1 +590 3 +690 10 +1327 1 +2046 8 +521 9 +3709 8 +1357 8 +3306 4 +2909 9 +808 9 +2466 10 +2968 7 +792 3 +1565 10 +1199 3 +977 7 +2759 7 +2836 5 +1631 9 +844 7 +1675 9 +1770 6 +1131 5 +3687 1 +2869 7 +3020 9 +2215 10 +3912 10 +3568 5 +472 3 +3801 2 +2739 1 +179 5 +127 4 +1912 5 +198 3 +2111 5 +1162 7 +425 9 +731 1 +1410 10 +3101 9 +1103 5 +1485 7 +1555 8 +2825 9 +3312 8 +1881 1 +3349 1 +3721 2 +1049 5 +2363 8 +3727 2 +2794 10 +2658 5 +3487 1 +2979 10 +2119 10 +1466 3 +3963 2 +3181 1 +1866 8 +1646 3 +2777 2 +2483 8 +3825 9 +633 3 +3489 8 +2970 7 +1956 4 +3246 3 +298 5 +79 3 +2958 10 +1600 6 +3610 7 +1230 3 +2683 6 +2687 5 +4054 2 +699 7 +3400 10 +1956 4 +1907 4 +3961 3 +3709 4 +3893 8 +2588 8 +632 7 +3859 6 +1001 3 +1108 10 +3667 8 +1009 3 +3586 9 +3187 10 +1790 8 +2542 3 +352 6 +2829 2 +758 9 +3788 8 +1950 8 +1995 2 +3562 4 +1812 3 +3072 4 +973 7 +98 6 +2162 10 +2251 7 +1984 8 +1871 8 +2085 10 +3638 3 +2192 3 +718 2 +3932 2 +2416 7 +121 9 +1394 3 +1053 4 +3505 5 +1671 9 +3121 8 +1205 3 +2068 1 +628 6 +704 10 +515 6 +798 9 +3251 1 +374 8 +2594 8 +3858 4 +2619 5 +2191 7 +1986 10 +322 6 +2839 10 +2546 6 +1236 9 +1752 8 +3056 5 +373 9 +2983 8 +2264 6 +2325 8 +2959 3 +3631 7 +1979 3 +3088 5 +3082 2 +2863 2 +2681 8 +3473 7 +816 8 +85 10 +955 7 +591 9 +3790 6 +1168 3 +2321 9 +1923 2 +2731 3 +2146 8 +2847 1 +2206 9 +1113 2 +3631 7 +2177 7 +2281 3 +2262 5 +3129 2 +2149 4 +524 7 +2552 7 +290 1 +37 7 +1938 10 +1799 9 +4080 5 +783 5 +282 8 +68 9 +2637 2 +2539 9 +213 1 +475 2 +208 7 +421 9 +1530 6 +2418 5 +3953 6 +3985 1 +3000 10 +77 5 +149 3 +2218 4 +1826 1 +2212 2 +461 8 +4087 7 +2039 5 +1590 3 +577 8 +1191 5 +2466 4 +3361 5 +527 10 +3358 1 +2079 4 +2798 5 +3990 2 +2835 6 +2139 10 +2979 7 +2117 8 +3185 3 +642 6 +188 4 +654 2 +2128 1 +3288 4 +3134 10 +51 6 +3496 9 +2883 10 +1077 7 +3069 6 +1204 10 +1396 2 +2541 1 +2317 7 +4090 7 +3539 5 +3235 4 +1110 3 +1790 6 +1968 10 +1076 7 +2311 2 +3495 9 +835 1 +585 5 +2294 5 +2840 3 +1028 4 +652 7 +1619 6 +3608 10 +281 2 +637 4 +1123 8 +1155 6 +2604 6 +2203 3 +2420 7 +3215 7 +399 1 +1 9 +1436 6 +691 8 +550 6 +2629 1 +539 7 +1001 7 +3453 6 +2965 4 +2098 5 +1789 5 +3621 6 +3958 4 +1681 3 +759 2 +1172 3 +1126 7 +3477 3 +370 10 +1318 9 +98 6 +2313 2 +1291 6 +993 4 +3593 3 +128 6 +778 10 +1473 7 +615 2 +260 3 +3651 1 +3334 8 +4042 5 +657 9 +3542 7 +2233 7 +1956 4 +2133 8 +2782 4 +3889 5 +99 1 +2578 3 +451 10 +2484 9 +1947 4 +2212 2 +2284 6 +1371 2 +3921 5 +2002 3 +114 5 +4084 1 +346 10 +4070 2 +2330 10 +2200 10 +94 4 +3099 4 +1497 7 +1740 9 +80 3 +839 6 +2305 7 +928 7 +1369 3 +2532 8 +995 9 +1568 1 +1773 3 +378 4 +2271 5 +761 9 +519 7 +3151 2 +268 4 +3857 4 +71 5 +2831 10 +2903 3 +3173 4 +3630 6 +2258 5 +1272 7 +475 1 +407 2 +1433 2 +2624 8 +1492 10 +4013 6 +2006 5 +44 9 +3647 9 +3104 1 +3251 9 +4090 1 +4053 9 +2748 6 +553 4 +2964 8 +3234 4 +2097 4 +2762 10 +3947 7 +2941 3 +3343 9 +1872 1 +3647 2 +139 7 +175 4 +1573 1 +2708 3 +2525 4 +727 4 +1281 9 +2165 6 +3119 6 +131 5 +2162 7 +2469 3 +1384 6 +1382 6 +3262 10 +2898 2 +1168 10 +320 7 +1772 4 +473 3 +3529 8 +2740 2 +3866 10 +1730 9 +1447 8 +2700 1 +1340 1 +1161 4 +1811 4 +3582 5 +98 6 +3185 1 +1405 9 +3288 4 +1797 9 +360 7 +3764 6 +1722 4 +3924 4 +2621 9 +1187 6 +1487 10 +2761 9 +541 8 +2024 6 +192 9 +3758 6 +3311 9 +2768 8 +3336 7 +386 10 +1103 5 +2229 1 +519 2 +1819 4 +2215 8 +2053 1 +1345 4 +3518 1 +1189 7 +3789 8 +1794 9 +1995 3 +2693 9 +838 10 +1363 3 +773 9 +2361 8 +1417 3 +54 1 +2915 1 +3216 8 +3374 7 +1153 7 +564 9 +3772 6 +3009 4 +920 7 +677 10 +979 3 +2910 3 +1048 2 +3011 1 +2728 9 +2689 5 +1947 9 +3480 3 +875 6 +2501 6 +403 1 +622 6 +1937 7 +1144 1 +1928 2 +3868 5 +860 1 +2372 10 +2503 8 +1345 10 +3113 10 +3953 7 +1961 4 +812 5 +3080 1 +2311 7 +3193 7 +904 7 +3556 6 +2952 4 +739 8 +217 3 +2240 4 +489 6 +646 7 +2897 2 +4053 4 +973 3 +1981 7 +1990 4 +566 1 +3001 2 +3480 7 +2082 1 +2792 4 +3419 5 +3024 8 +1277 3 +1510 9 +2498 1 +3858 4 +1157 1 +1254 2 +161 4 +438 5 +3650 4 +3831 5 +4020 3 +1006 6 +2614 3 +1326 6 +1373 1 +3721 3 +1020 1 +3233 9 +1749 10 +3807 5 +84 4 +568 4 +491 1 +841 4 +1034 6 +51 4 +3602 10 +629 9 +3973 8 +1868 9 +1446 6 +2989 9 +744 10 +1532 2 +2925 10 +825 6 +386 3 +2393 4 +4035 6 +768 9 +2040 6 +2832 10 +2975 7 +568 8 +19 4 +3984 4 +34 7 +3284 8 +3156 3 +1019 9 +2933 10 +49 4 +4077 2 +1355 3 +2545 2 +1996 10 +2248 3 +1017 5 +4089 5 +783 1 +1172 3 +40 5 +123 1 +2792 1 +2268 9 +2753 3 +313 2 +948 4 +2304 8 +879 9 +1166 6 +841 6 +3261 10 +2327 2 +3126 7 +2692 10 +3446 6 +1215 4 +3609 8 +3941 5 +1542 1 +955 9 +2203 10 +3357 6 +1738 5 +1091 1 +3621 6 +3578 2 +4064 1 +3219 5 +1585 7 +1567 6 +1242 10 +1678 3 +2076 9 +3229 6 +2482 1 +2001 5 +1968 2 +4086 8 +1474 8 +1595 7 +3949 8 +389 7 +518 7 +3353 5 +1771 5 +176 4 +3143 7 +1062 1 +3723 6 +2526 9 +6 3 +916 3 +945 7 +2457 6 +1225 7 +1501 5 +312 2 +2929 8 +669 7 +1425 6 +2928 5 +3538 6 +1444 9 +3465 8 +3437 2 +167 1 +3190 5 +2577 8 +306 8 +4033 2 +2328 5 +779 5 +1500 7 +2871 2 +1743 4 +2576 9 +1528 9 +1617 3 +2812 3 +2018 9 +3726 10 +1503 8 +3606 9 +3525 6 +484 6 +983 6 +1851 5 +2362 9 +2500 8 +2253 10 +1238 2 +859 8 +3411 2 +2654 10 +2875 10 +3981 6 +296 3 +3343 10 +2490 7 +596 5 +1242 4 +917 3 +685 9 +3037 8 +4062 8 +3358 4 +2020 4 +3051 1 +706 6 +3352 6 +3930 2 +2514 4 +2324 2 +1957 4 +1550 9 +3652 3 +766 6 +3272 9 +2208 8 +2373 7 +1449 1 +4076 3 +3757 6 +2161 2 +1279 7 +2691 5 +3233 8 +238 2 +73 7 +3186 7 +2862 5 +2711 3 +824 2 +4048 8 +3774 6 +3607 8 +1511 8 +4085 7 +1144 6 +2260 4 +35 9 +3432 7 +991 5 +1808 9 +2489 2 +809 5 +3806 8 +1757 7 +834 1 +990 9 +1455 9 +470 10 +563 10 +2445 5 +984 1 +2935 6 +746 4 +1113 5 +3351 5 +1597 7 +231 1 +3145 9 +2295 4 +2004 6 +2916 10 +3419 2 +438 1 +3711 6 +1064 5 +2075 4 +523 5 +261 4 +2574 1 +2443 7 +2812 2 +151 7 +3046 3 +3699 5 +1677 8 +1185 7 +683 6 +3300 10 +2144 7 +2628 8 +491 7 +4084 4 +2199 1 +1684 7 +336 1 +650 3 +4048 10 +64 2 +1623 7 +2228 7 +3790 5 +1977 2 +119 9 +2063 9 +1127 5 +2145 8 +1158 4 +1100 5 +3564 7 +865 2 +580 1 +3794 10 +1621 6 +599 9 +3026 8 +3182 1 +943 4 +3462 4 +3390 1 +1672 1 +454 3 +1599 1 +3866 1 +1925 10 +3973 3 +894 5 +2404 5 +3911 2 +1974 4 +2769 2 +295 1 +2131 4 +297 6 +37 3 +1655 10 +1706 8 +1380 9 +69 9 +1261 1 +452 5 +285 7 +2702 4 +2808 6 +2288 4 +168 4 +2535 4 +1179 8 +31 6 +985 6 +427 5 +1793 1 +3950 2 +4050 6 +473 4 +3749 10 +858 2 +2783 6 +2865 5 +72 2 +317 2 +83 5 +2835 10 +2970 8 +2445 4 +1907 7 +3755 7 +3220 5 +1212 9 +1866 8 +2923 7 +3425 2 +2185 9 +2268 10 +1101 1 +2508 4 +2412 6 +2231 1 +1086 10 +721 8 +536 5 +3132 9 +1583 9 +2922 4 +1733 2 +2003 8 +2151 6 +3964 4 +2653 1 +3929 6 +3772 2 +3549 8 +1585 7 +2414 9 +1398 9 +835 10 +2111 1 +1921 6 +1625 10 +4035 9 +2153 5 +2544 8 +1419 7 +837 1 +3674 10 +374 2 +783 2 +3037 1 +2860 7 +3361 9 +2160 6 +3610 5 +3669 1 +1462 9 +2179 2 +3097 8 +2400 8 +1703 2 +2742 9 +1445 10 +3308 2 +2933 3 +3671 6 +2688 1 +591 7 +2597 7 +2615 1 +341 1 +3323 10 +3673 9 +643 3 +1500 10 +2765 9 +53 3 +973 2 +2733 7 +4044 8 +3912 4 +910 5 +2219 4 +13 4 +59 3 +3989 8 +1989 6 +2264 1 +1981 4 +3312 7 +593 10 +481 2 +3357 1 +3309 4 +75 7 +3573 3 +3416 1 +922 4 +1912 9 +305 6 +1347 2 +240 10 +1340 8 +271 3 +1489 9 +4017 9 +2196 10 +489 9 +2553 9 +3552 3 +2211 4 +1707 2 +2026 6 +150 1 +2019 1 +3302 6 +1103 3 +2928 8 +1932 8 +2849 9 +3964 3 +3316 2 +827 3 +2539 6 +3906 8 +3010 2 +2978 7 +2238 10 +3688 1 +2970 4 +10 5 +3763 1 +3845 8 +1236 8 +3027 1 +1103 3 +2121 3 +1697 1 +3316 1 +3389 6 +3338 5 +3791 5 +3895 6 +1110 1 +3670 1 +53 9 +3283 1 +487 10 +1793 10 +1809 8 +1611 2 +201 8 +1001 1 +356 1 +2754 3 +771 5 +3793 10 +72 5 +2873 9 +4020 5 +2492 5 +2004 8 +760 10 +3015 9 +3595 2 +1 9 +3636 8 +369 4 +1022 5 +2738 1 +1189 3 +1904 7 +2150 3 +518 1 +2067 6 +1944 6 +1358 4 +2897 4 +3545 2 +220 8 +1115 1 +1379 3 +1382 5 +3269 6 +3510 8 +379 8 +857 9 +3631 2 +1696 3 +2309 9 +1116 4 +3279 5 +2990 8 +3186 6 +2864 5 +4065 9 +2127 1 +1925 3 +1841 3 +686 9 +1404 1 +2371 1 +3340 4 +2080 10 +237 5 +442 4 +171 8 +1959 3 +2504 1 +474 8 +1761 7 +3057 3 +2051 3 +1657 7 +2597 3 +3463 5 +2334 2 +2562 4 +2527 4 +389 3 +1929 4 +2744 7 +2109 9 +1918 9 +3515 4 +2994 6 +17 9 +2022 7 +2678 8 +666 2 +2000 1 +4083 10 +1281 5 +2689 7 +1294 7 +941 7 +727 5 +697 2 +1586 5 +445 9 +3879 4 +727 7 +939 7 +3630 10 +3746 4 +2241 10 +2441 4 +1151 2 +3696 9 +2023 2 +3502 7 +2415 4 +3238 8 +2079 10 +2813 7 +2555 8 +2569 6 +3950 3 +3784 3 +3371 10 +3265 3 +702 3 +605 4 +1510 3 +59 5 +2396 2 +3647 6 +3203 4 +2946 9 +308 9 +2141 6 +512 3 +2231 3 +556 8 +378 3 +96 9 +3837 10 +3878 3 +1685 8 +3786 2 +2974 2 +1466 5 +1173 5 +432 10 +697 5 +1109 6 +3939 2 +2166 5 +1616 2 +1415 5 +1878 10 +126 8 +251 1 +2404 6 +3118 7 +4083 9 +453 10 +2851 4 +3353 1 +3906 9 +3452 2 +1691 2 +2531 9 +1595 5 +1039 10 +3183 9 +315 9 +3580 10 +181 6 +3034 1 +3822 10 +2217 7 +1096 1 +749 4 +2775 3 +3722 3 +4013 8 +1745 6 +3560 10 +3450 6 +2212 10 +3302 5 +262 6 +680 9 +169 10 +664 2 +367 2 +576 1 +430 2 +996 1 +525 6 +2879 9 +3893 10 +2596 2 +3926 9 +3063 10 +2092 1 +3535 2 +1753 1 +1747 4 +1647 3 +1658 9 +1391 9 +317 1 +1265 3 +2018 1 +1849 9 +2974 7 +3643 8 +1490 10 +2818 8 +1796 3 +1410 8 +3495 3 +1088 1 +1461 1 +3197 3 +3555 2 +1569 2 +508 7 +494 9 +1578 10 +1367 7 +2708 4 +378 7 +3221 2 +809 2 +2226 5 +629 2 +1460 3 +2908 6 +388 3 +340 3 +3437 3 +2596 2 +3018 1 +2073 8 +1027 5 +242 5 +1226 2 +547 10 +1672 10 +3843 7 +2941 2 +2178 4 +3964 2 +1038 1 +2925 2 +2741 9 +3659 9 +1679 9 +3098 9 +3096 4 +2846 4 +262 10 +2609 10 +763 9 +909 5 +41 6 +3771 6 +3756 1 +57 4 +2278 6 +204 4 +3135 4 +1058 3 +2430 7 +968 5 +276 8 +1055 3 +1567 8 +2034 7 +268 1 +3712 1 +3462 4 +2625 9 +95 5 +2386 1 +249 9 +3086 3 +470 5 +2357 7 +4042 9 +3577 10 +1269 3 +2582 2 +2707 3 +3259 5 +734 9 +2531 2 +2497 5 +3346 7 +1471 6 +3556 8 +3881 7 +1671 5 +3761 1 +2011 3 +2994 9 +223 2 +2469 9 +2715 2 +3925 3 +917 10 +3700 5 +30 3 +648 8 +2711 8 +3955 10 +3434 9 +1332 7 +2426 1 +3265 7 +1384 10 +2200 2 +1769 6 +1083 6 +3487 4 +193 2 +74 5 +3120 10 +941 3 +1060 1 +1519 5 +3053 6 +1646 1 +3081 8 +661 5 +2178 9 +3945 8 +3594 4 +1176 9 +1021 5 +3169 2 +1224 6 +930 2 +680 5 +2877 6 +1515 2 +2755 1 +2377 4 +1256 6 +2793 3 +2184 7 +2921 8 +108 4 +303 3 +1066 1 +409 3 +2237 7 +1752 2 +488 10 +2851 8 +3101 6 +2210 9 +1068 4 +3060 6 +2083 5 +1977 6 +3496 2 +3604 2 +3007 6 +220 5 +2910 3 +1332 9 +3795 5 +3497 1 +1609 2 +3805 7 +2249 3 +2971 2 +1280 1 +1194 8 +2004 8 +294 2 +665 9 +239 9 +1689 8 +771 2 +3960 2 +572 5 +65 7 +2085 7 +853 1 +3924 9 +3364 9 +3237 6 +944 8 +3086 5 +1720 1 +3034 6 +2514 6 +602 5 +4044 4 +3773 3 +142 7 +1902 1 +3840 6 +1561 3 +1389 5 +3355 2 +94 10 +2979 9 +3224 10 +2206 6 +1175 9 +1217 10 +1768 9 +3629 10 +1207 2 +1773 2 +2941 1 +1801 6 +2920 9 +3735 6 +2572 5 +946 7 +1615 2 +3680 9 +3007 9 +1459 1 +252 9 +737 8 +2263 3 +2456 6 +4026 5 +1026 5 +2208 8 +1939 8 +2444 5 +3747 9 +1262 10 +640 1 +534 5 +3660 3 +478 2 +1703 3 +431 8 +1659 10 +68 5 +190 2 +1733 7 +110 10 +3610 1 +2266 5 +905 5 +1865 6 +2530 5 +2071 5 +3889 2 +2860 5 +1433 3 +3908 6 +702 4 +1659 4 +67 10 +3952 5 +559 3 +3869 8 +1320 2 +3978 10 +366 7 +444 10 +1468 3 +3896 3 +2353 3 +211 8 +1387 5 +2750 6 +393 10 +2379 6 +402 7 +3495 3 +2281 7 +1455 4 +1900 1 +4067 3 +1552 1 +363 4 +44 1 +2135 5 +3643 4 +2082 4 +3434 10 +724 9 +3372 2 +795 3 +1808 3 +1346 4 +3392 9 +2935 4 +1442 7 +3227 1 +2113 3 +3294 10 +866 1 +3571 10 +2258 4 +4040 6 +2070 4 +722 4 +2599 7 +3078 4 +3663 10 +279 8 +2693 10 +177 10 +1750 3 +1413 1 +307 10 +120 7 +3970 8 +3789 2 +3036 8 +2813 10 +1443 9 +1426 1 +3281 10 +3566 1 +3280 5 +3835 1 +2545 4 +1627 4 +1230 10 +2529 1 +2831 2 +4071 7 +975 1 +2329 2 +1016 6 +1995 4 +1584 2 +3436 8 +540 2 +3267 9 +211 2 +657 9 +3683 4 +3075 5 +4041 5 +498 3 +3189 1 +1738 7 +1929 5 +776 7 +1280 1 +3997 4 +2958 2 +1564 10 +2375 4 +3536 6 +2832 5 +3732 9 +1368 5 +428 7 +2208 8 +3588 2 +278 5 +1875 5 +261 2 +3375 9 +3267 9 +1845 7 +780 9 +3185 5 +2191 2 +1078 2 +2833 9 +3954 7 +3592 4 +877 6 +486 10 +420 10 +1564 3 +3518 4 +3898 7 +3228 1 +972 7 +2566 4 +3063 3 +3849 2 +477 4 +112 9 +36 8 +3299 9 +1266 3 +552 1 +1731 10 +944 6 +1160 4 +2160 5 +1836 1 +3098 5 +1702 6 +2884 3 +1573 10 +1829 4 +2323 5 +1910 4 +982 1 +3032 2 +2733 2 +339 4 +411 1 +2426 10 +1185 8 +28 2 +334 1 +1027 4 +3008 4 +2466 6 +144 7 +3098 8 +3518 4 +541 2 +872 8 +2515 2 +2123 9 +793 2 +2938 1 +1735 10 +854 3 +542 8 +1155 4 +3691 4 +3799 10 +835 3 +1495 8 +2996 1 +965 4 +2538 7 +138 5 +2403 4 +3501 6 +2046 5 +908 7 +1509 6 +3389 6 +3451 6 +230 3 +3665 9 +374 6 +3430 3 +1955 7 +1965 1 +4067 9 +3337 10 +1903 4 +61 6 +3001 8 +3400 9 +1552 4 +2890 6 +2014 3 +3231 9 +732 2 +1638 5 +3526 5 +3355 6 +806 8 +3530 9 +2698 9 +993 6 +2242 4 +3945 8 +2827 7 +1787 3 +2816 2 +3444 10 +1199 9 +964 10 +3934 8 +2028 6 +2205 10 +928 3 +72 1 +1366 7 +2770 10 +3320 3 +3434 9 +268 10 +1259 6 +3804 4 +2391 5 +2655 9 +261 5 +2951 1 +3333 2 +2649 2 +1383 10 +3011 6 +3529 10 +262 9 +2760 3 +2393 3 +992 3 +744 7 +2178 3 +3969 8 +3762 1 +946 3 +3910 1 +1213 8 +230 7 +3888 5 +1082 5 +2835 3 +3770 7 +2887 6 +1892 1 +2151 3 +2481 9 +2803 10 +563 5 +1125 9 +728 2 +3036 5 +2200 3 +94 10 +2274 8 +15 1 +430 5 +1112 9 +285 4 +1846 6 +2473 5 +1890 4 +1992 2 +340 1 +97 10 +2422 6 +1589 6 +1530 4 +1777 5 +104 2 +3022 9 +51 2 +2948 1 +2136 9 +1652 8 +1034 8 +817 8 +3157 8 +2614 3 +3735 10 +2900 10 +4014 6 +311 5 +4075 1 +3524 9 +2788 3 +2604 5 +2365 7 +3145 9 +874 9 +3140 6 +3587 6 +454 8 +1569 10 +690 10 +487 1 +1516 2 +3034 1 +3883 5 +2120 3 +3346 4 +3525 5 +2542 7 +3544 10 +2820 6 +3519 8 +96 4 +3883 7 +3115 2 +2645 8 +735 10 +1023 7 +3211 1 +3155 9 +1157 8 +2861 6 +1951 6 +836 4 +705 7 +4090 1 +1653 9 +3096 9 +463 8 +2961 10 +771 1 +1297 6 +3135 4 +865 7 +3926 8 +2438 7 +0 5 +1622 2 +1711 7 +3380 9 +967 6 +1702 5 +3013 5 +3885 4 +3042 5 +3200 8 +627 2 +2182 6 +586 8 +2083 10 +3043 2 +1938 8 +2783 10 +1891 1 +2245 8 +4068 7 +1064 3 +1700 4 +1970 4 +1818 3 +3096 6 +969 7 +550 10 +53 4 +1766 1 +2308 9 +534 2 +3906 8 +1279 5 +3918 4 +432 6 +936 5 +240 2 +2454 5 +2711 4 +1968 5 +3954 1 +2262 9 +299 5 +3757 8 +455 2 +3607 5 +3765 8 +3919 10 +2766 2 +2870 8 +845 7 +3687 4 +1119 8 +3413 8 +3969 5 +3192 9 +2188 5 +1756 2 +2089 7 +2293 8 +2774 5 +2074 2 +533 2 +3081 2 +2759 9 +467 5 +1546 6 +3195 8 +48 2 +2498 6 +1850 4 +1870 2 +3295 6 +1997 5 +3000 9 +1168 9 +904 3 +263 3 +1497 8 +227 10 +3893 3 +2863 7 +1361 9 +2345 3 +1367 3 +3590 2 +1776 1 +379 1 +221 7 +3299 1 +573 3 +48 2 +2177 6 +1485 7 +1889 10 +1443 5 +313 3 +2093 9 +1254 4 +3912 1 +809 4 +940 10 +1804 8 +2271 3 +1416 4 +1500 5 +1392 2 +194 3 +2746 9 +2724 6 +2185 9 +66 5 +1306 4 +2646 5 +922 3 +123 9 +3413 5 +2813 9 +1778 5 +1907 8 +564 8 +2539 9 +869 2 +1251 4 +3291 8 +2513 7 +3115 9 +1125 2 +2143 5 +242 7 +83 5 +3453 8 +85 1 +2734 2 +512 6 +2486 9 +3014 1 +477 3 +2338 2 +3110 5 +1220 1 +581 8 +1492 9 +3588 10 +3617 8 +472 6 +60 7 +2922 4 +2516 5 +724 3 +215 3 +90 8 +2686 5 +3807 5 +3392 1 +2021 9 +19 6 +1037 9 +2861 4 +3148 2 +432 4 +1173 8 +3121 5 +2566 6 +1968 10 +2094 2 +604 4 +1384 1 +169 9 +302 7 +254 4 +2904 5 +145 2 +4 2 +995 4 +3739 1 +3665 5 +1737 9 +1416 6 +174 5 +871 4 +667 1 +4011 5 +896 2 +2247 8 +2252 3 +2656 2 +2104 1 +169 8 +327 2 +1791 10 +1561 8 +3759 4 +743 9 +1125 10 +3357 9 +3114 9 +2583 7 +725 10 +1940 7 +3874 8 +1521 2 +1673 9 +753 4 +3418 5 +2984 2 +1502 7 +3818 3 +2957 5 +1209 1 +2764 9 +3916 4 +268 9 +1777 2 +1827 4 +3680 9 +3945 7 +533 5 +2775 8 +2880 9 +2636 8 +2401 3 +2517 2 +3195 9 +2959 8 +355 8 +703 5 +2513 8 +1113 6 +881 3 +505 3 +3941 8 +1304 10 +2610 2 +3170 7 +112 6 +1002 7 +1582 7 +853 8 +135 9 +2418 9 +149 4 +3195 1 +3857 2 +701 10 +3513 4 +3004 6 +3643 4 +3163 5 +1100 2 +810 10 +3498 10 +1793 8 +3248 4 +3043 2 +637 9 +1930 8 +1924 9 +141 1 +880 8 +1345 8 +604 4 +2442 8 +879 6 +2970 8 +3477 4 +269 6 +719 3 +2915 2 +1144 10 +3399 7 +3813 9 +915 3 +2708 9 +1565 1 +3066 7 +2478 4 +3048 7 +1340 4 +2150 2 +1241 6 +1247 2 +3721 2 +2853 8 +613 10 +642 3 +2411 9 +1623 6 +1522 9 +3000 5 +235 2 +98 6 +538 8 +1609 10 +2392 8 +1724 10 +178 9 +1825 10 +787 6 +542 5 +3492 6 +1480 6 +1532 8 +1512 1 +2820 6 +3357 6 +105 7 +2710 5 +3553 4 +925 9 +2745 3 +3180 5 +750 2 +3860 5 +3783 2 +1058 8 +3367 2 +1284 1 +1993 7 +4040 9 +3683 6 +116 5 +1362 1 +2484 6 +199 3 +1447 10 +1710 5 +2240 1 +470 5 +2704 1 +3296 1 +297 2 +1007 2 +1796 3 +842 3 +1976 10 +3880 9 +2491 8 +1334 10 +2149 1 +1534 6 +2323 9 +1435 2 +1619 1 +3436 5 +2073 5 +2741 7 +108 3 +1309 7 +38 3 +3474 10 +495 1 +1232 6 +2524 2 +648 7 +3154 8 +1669 10 +1009 4 +999 10 +2451 10 +2534 2 +216 7 +2487 8 +3495 6 +2558 6 +3902 7 +2454 3 +2625 2 +2715 3 +3779 9 +2179 8 +3318 4 +1567 9 +508 8 +1481 9 +3080 6 +2339 7 +836 5 +22 8 +3879 7 +3326 9 +2984 2 +2428 1 +151 1 +1614 2 +1930 9 +2412 3 +1842 4 +3349 1 +1232 2 +3240 8 +4036 10 +2171 8 +3873 10 +212 9 +2231 10 +468 2 +2121 10 +2691 1 +3477 6 +3542 8 +634 8 +3735 9 +198 9 +2641 1 +128 4 +2774 1 +263 3 +3531 5 +782 4 +2886 3 +1207 4 +2718 3 +394 3 +2200 7 +857 3 +2340 9 +3493 1 +1822 1 +2077 7 +295 4 +2825 6 +505 7 +3461 7 +670 9 +1836 2 +573 10 +182 5 +391 3 +982 2 +2516 2 +2574 5 +1203 4 +3513 6 +3486 3 +2267 4 +3695 9 +2363 1 +2244 8 +3503 7 +3423 3 +3999 3 +2658 7 +3913 6 +2541 3 +3290 5 +1114 6 +3576 4 +3647 4 +1646 3 +2216 2 +2457 9 +3703 5 +2746 5 +3376 3 +659 7 +2114 10 +1343 9 +2086 4 +3319 3 +2971 6 +4005 4 +1375 6 +1170 6 +3319 2 +3937 4 +2050 4 +662 2 +854 2 +3402 4 +451 10 +3349 3 +2126 3 +143 10 +2287 2 +2887 3 +593 1 +1032 1 +1656 2 +594 7 +1989 1 +1128 10 +3319 7 +1998 5 +3071 7 +2069 10 +1554 3 +1792 4 +115 7 +2918 9 +2782 4 +3855 8 +345 7 +2797 2 +2905 4 +3841 5 +3733 2 +255 6 +3498 4 +1095 3 +3065 5 +3957 2 +2924 3 +823 4 +650 10 +2729 2 +3253 3 +1513 9 +2839 6 +1538 6 +3243 7 +1154 3 +801 10 +2688 10 +762 4 +600 7 +2105 7 +2626 6 +128 1 +1377 1 +2296 9 +2118 10 +3178 7 +3396 7 +3852 4 +666 5 +1785 7 +1105 3 +3982 7 +1368 10 +631 8 +1472 5 +1935 9 +754 1 +2291 6 +2324 9 +804 4 +3661 7 +3148 9 +1855 10 +1930 6 +3434 2 +3554 6 +3591 10 +2791 6 +2845 2 +2105 3 +2015 5 +3662 1 +219 4 +116 6 +852 3 +957 7 +2338 7 +3987 5 +2602 6 +3737 4 +3056 4 +2303 5 +3697 10 +2528 6 +2937 3 +3162 9 +1836 3 +3827 8 +1876 8 +3800 7 +1712 5 +1305 5 +3222 1 +209 8 +1320 6 +981 3 +3637 5 +1975 9 +647 1 +792 7 +1507 2 +3234 2 +1938 10 +1483 4 +3101 1 +3970 4 +1582 7 +3444 1 +2949 3 +1013 7 +1190 5 +1148 1 +1817 1 +3502 3 +323 10 +3436 8 +1119 1 +3362 2 +2291 7 +1896 8 +2170 10 +1342 6 +454 6 +2343 9 +963 9 +1075 5 +1703 2 +478 4 +4009 10 +593 5 +2653 6 +2372 7 +3176 7 +1526 3 +4082 3 +2465 6 +748 10 +880 7 +3472 7 +1581 7 +2809 10 +1236 1 +3494 3 +4079 4 +3407 2 +3818 2 +2293 5 +3369 3 +2813 2 +1801 6 +59 10 +198 1 +3992 9 +2334 6 +236 1 +244 6 +3316 5 +2990 6 +3544 9 +479 3 +833 6 +2926 6 +245 5 +2019 4 +2979 7 +2851 5 +1305 10 +53 6 +2415 9 +1931 5 +3764 2 +2032 1 +2663 2 +1748 8 +947 6 +2500 2 +2854 8 +418 4 +3297 3 +513 5 +2257 10 +4082 1 +1 8 +1076 7 +2937 7 +1751 8 +3295 1 +3346 4 +1350 4 +495 10 +2518 9 +398 9 +3429 3 +3256 4 +3573 7 +305 1 +3082 7 +1754 9 +1465 5 +2276 2 +3530 5 +2678 8 +1407 5 +2504 9 +1186 6 +3854 2 +2879 3 +1378 10 +871 1 +2331 8 +3056 3 +2363 9 +1795 5 +189 2 +3143 5 +2159 4 +2537 8 +2757 6 +348 5 +2527 9 +1724 1 +3451 8 +2327 7 +584 6 +342 9 +2580 6 +2925 4 +641 6 +4050 10 +1828 1 +3155 8 +181 8 +178 10 +1668 1 +3853 1 +2350 3 +65 4 +1608 3 +2429 8 +118 10 +1882 3 +3825 1 +855 1 +2590 2 +1762 6 +893 3 +2457 3 +1224 10 +3890 10 +114 1 +1276 5 +2060 8 +3195 4 +3085 1 +2277 7 +861 10 +1500 7 +2524 7 +1289 10 +3868 6 +1205 4 +1915 2 +2565 9 +2526 6 +288 8 +2945 3 +1622 5 +1458 5 +2813 3 +3097 4 +2671 9 +2965 6 +2969 5 +3544 4 +786 4 +2405 5 +1560 1 +1605 2 +1240 7 +3215 10 +237 5 +3595 10 +3233 5 +443 8 +2368 6 +345 8 +2747 6 +1713 3 +680 9 +815 8 +2224 9 +2214 2 +623 10 +2742 6 +1951 5 +2759 7 +130 9 +2820 4 +2879 5 +1896 8 +1725 3 +4080 8 +362 2 +2954 1 +1689 3 +2461 4 +3068 8 +156 7 +237 1 +2958 7 +2694 2 +1914 6 +2391 3 +3577 6 +2343 8 +1681 4 +2299 3 +2720 2 +2622 6 +3710 2 +2106 1 +3216 10 +3716 3 +524 1 +123 6 +328 8 +3297 10 +527 9 +2020 7 +2610 10 +3599 8 +2014 3 +1796 3 +947 9 +1644 8 +3298 1 +203 10 +1728 1 +1879 9 +2273 10 +2632 6 +2498 1 +3808 2 +3092 2 +2795 2 +460 9 +3496 8 +568 10 +2417 7 +230 3 +741 4 +2318 5 +2703 7 +1276 6 +1134 2 +2665 4 +3746 2 +1546 9 +1687 4 +2365 2 +2681 1 +3724 7 +483 5 +3656 3 +3289 8 +1582 4 +478 7 +60 7 +3636 9 +2142 3 +2531 8 +3973 5 +2122 5 +272 5 +1378 5 +634 9 +1973 5 +2293 8 +173 10 +3989 1 +3287 6 +984 6 +686 10 +664 3 +3921 9 +2940 9 +216 1 +902 1 +348 8 +1656 4 +709 2 +1518 8 +1756 1 +3267 6 +1794 7 +3961 7 +1596 5 +1725 9 +2792 5 +10 1 +2822 7 +3586 2 +3986 7 +3343 5 +2071 8 +2378 9 +2608 7 +2873 7 +589 5 +2954 2 +2562 5 +137 8 +619 1 +2262 10 +406 10 +2433 4 +3242 7 +3350 5 +1676 2 +2181 3 +2854 5 +1424 8 +1790 6 +1862 4 +56 1 +1118 9 +417 1 +2873 3 +3482 7 +1108 7 +3103 8 +2080 4 +3055 1 +864 3 +3334 6 +2351 5 +1335 9 +2175 5 +1751 1 +864 10 +1238 10 +3039 6 +3767 5 +1334 9 +3747 5 +271 1 +3364 3 +3302 8 +2454 5 +3737 1 +3664 2 +1568 2 +3853 6 +3464 1 +3464 2 +781 8 +1655 9 +293 5 +2728 6 +2496 3 +3812 2 +158 3 +200 5 +1915 7 +3365 8 +1803 10 +2644 9 +585 5 +19 6 +1802 5 +3980 8 +3278 2 +2766 1 +3032 7 +281 10 +1232 4 +965 1 +1054 8 +312 7 +2148 10 +2197 2 +3863 1 +4036 4 +1551 3 +2651 4 +1281 6 +4052 8 +2956 2 +156 7 +3504 4 +2777 3 +1258 9 +2271 8 +2162 7 +3594 2 +1735 8 +4085 7 +2516 7 +1228 8 +3534 6 +1860 9 +2620 9 +3304 2 +2466 8 +976 10 +969 4 +131 7 +1138 4 +2071 3 +3482 4 +567 3 +1497 5 +1373 10 +3594 7 +2551 9 +1982 7 +674 2 +1054 2 +1821 2 +1390 8 +2456 4 +3786 5 +2738 6 +3436 10 +2349 5 +382 5 +3676 6 +3791 4 +3447 5 +4019 7 +3866 10 +350 10 +3081 7 +3204 10 +3545 9 +332 7 +379 6 +1295 4 +1439 8 +1693 3 +3008 2 +1867 5 +2420 1 +470 8 +1832 3 +619 4 +1928 4 +3900 7 +1544 10 +1451 3 +3721 7 +1719 3 +112 8 +601 1 +3971 7 +2247 8 +1774 9 +2851 7 +3945 6 +3478 2 +2522 7 +3630 9 +303 4 +2171 1 +2024 2 +807 6 +474 4 +990 3 +85 10 +3668 4 +3823 9 +2731 9 +2748 7 +2283 10 +903 8 +1807 10 +1521 10 +3026 6 +2902 10 +219 10 +461 4 +166 8 +1065 4 +2325 3 +2922 3 +2572 7 +3034 4 +3694 10 +3552 7 +3554 4 +3189 10 +1805 2 +3953 9 +4033 7 +2154 6 +772 9 +7 1 +2616 10 +1200 9 +1237 1 +388 7 +2052 2 +2777 9 +3131 9 +97 1 +1592 2 +1940 1 +479 1 +2770 3 +970 3 +1553 7 +1531 3 +855 4 +2157 2 +3786 2 +3221 7 +2133 8 +1558 4 +2759 6 +2627 10 +603 1 +3477 5 +1714 2 +1945 5 +1936 10 +471 7 +363 9 +1169 7 +1871 5 +2078 3 +1201 3 +1098 7 +2291 4 +604 4 +3558 8 +472 8 +3770 3 +3595 5 +2432 6 +2848 2 +2941 2 +1473 2 +1149 5 +3522 8 +3365 9 +1269 10 +556 3 +2778 9 +955 3 +376 7 +160 1 +2626 2 +4069 7 +196 10 +805 1 +2185 5 +3577 8 +737 4 +230 2 +3555 4 +3601 3 +356 4 +952 2 +417 8 +838 3 +65 3 +3658 8 +3607 4 +3113 6 +984 1 +1346 10 +4080 7 +343 2 +838 6 +554 3 +2613 7 +2947 2 +3981 8 +2537 10 +2894 1 +3578 9 +3568 1 +2281 8 +3941 8 +1258 6 +1634 5 +3416 3 +2580 2 +4076 3 +3048 8 +1268 1 +236 4 +3117 9 +1713 1 +1325 5 +3635 1 +1436 8 +2985 10 +862 6 +2911 6 +1297 10 +2873 1 +2195 6 +1067 3 +2452 8 +2752 3 +198 9 +835 4 +311 1 +592 8 +3676 3 +1032 9 +1838 10 +1533 7 +2586 8 +2980 1 +2646 2 +4033 3 +4062 9 +2260 1 +964 6 +1067 5 +1824 5 +1485 9 +1171 10 +4033 3 +695 6 +2703 10 +4010 9 +3927 5 +2241 9 +1109 10 +3056 10 +3626 10 +61 9 +1710 10 +2030 7 +3077 3 +3519 7 +963 6 +2565 1 +1213 1 +1956 7 +3302 2 +2640 1 +734 4 +278 9 +1605 3 +3712 9 +79 10 +2378 4 +3653 1 +3507 6 +2289 1 +3629 6 +3080 8 +1135 5 +2556 9 +3448 3 +3102 2 +2958 1 +2878 9 +1598 4 +844 7 +3508 4 +2452 7 +305 5 +249 3 +337 8 +1641 6 +1915 9 +2099 8 +1124 5 +508 6 +3461 4 +2096 10 +607 7 +79 10 +1347 8 +2840 5 +2491 6 +2309 9 +3572 3 +3204 7 +1094 9 +2553 1 +2535 6 +2120 6 +2207 1 +1486 10 +1682 2 +2187 5 +3376 5 +1829 5 +1204 2 +4088 10 +3167 7 +2291 4 +921 3 +1800 10 +2773 4 +3553 8 +536 6 +1550 7 +1631 10 +3619 1 +809 3 +2196 6 +2749 3 +940 2 +582 8 +3589 1 +695 8 +3115 3 +2531 8 +1852 9 +2842 7 +295 6 +3658 5 +1991 1 +1042 9 +2772 1 +2378 2 +2002 9 +825 6 +2908 2 +3467 3 +410 6 +3261 7 +638 1 +4001 5 +316 4 +712 4 +3943 5 +1604 1 +2972 1 +385 4 +1485 1 +174 1 +3712 8 +2121 1 +2263 2 +3527 6 +790 2 +3648 5 +1447 4 +1069 1 +472 4 +966 9 +3321 4 +2305 8 +313 1 +3054 8 +2207 10 +623 3 +2843 1 +2223 3 +1297 5 +392 1 +2024 4 +760 3 +479 4 +2098 8 +3766 1 +3740 1 +793 10 +875 5 +734 3 +2361 9 +1495 1 +2583 9 +263 3 +3311 5 +3924 4 +767 2 +1096 8 +3657 5 +1454 5 +1506 1 +480 6 +908 10 +1903 4 +70 6 +1783 3 +3006 2 +2745 1 +2778 2 +2075 1 +2682 5 +3534 5 +1141 1 +3527 8 +818 1 +3067 9 +3208 2 +3677 4 +2850 8 +3719 7 +449 5 +3184 7 +1759 3 +3547 9 +1083 5 +3088 10 +2089 10 +1204 4 +1215 6 +700 3 +2188 3 +3500 4 +3283 2 +888 8 +971 3 +2164 10 +1459 4 +2657 10 +1880 5 +72 5 +3540 6 +2516 7 +3183 2 +3925 4 +187 10 +1757 4 +496 5 +1044 7 +1674 8 +1910 5 +898 10 +436 3 +2711 10 +3553 7 +2242 7 +4093 5 +314 7 +1779 1 +717 6 +2834 4 +53 5 +3642 9 +814 3 +2008 5 +3764 8 +1903 8 +3104 8 +2883 3 +1923 2 +668 3 +3264 7 +2084 9 +400 7 +37 5 +1332 8 +2382 1 +368 1 +2821 6 +308 10 +2080 4 +549 10 +3131 9 +3545 7 +809 1 +1002 6 +3954 2 +1143 1 +2762 10 +1695 1 +2516 6 +3886 2 +2544 4 +3984 3 +3258 10 +1750 6 +3175 7 +1876 9 +1631 9 +2125 6 +1821 10 +1693 3 +2199 8 +1857 8 +3561 9 +4041 6 +275 7 +3431 9 +1890 4 +3510 9 +1703 2 +2084 6 +1740 3 +584 2 +2044 6 +3370 8 +2047 4 +796 1 +3790 2 +2454 1 +751 1 +2693 9 +2581 9 +1504 9 +1132 3 +3271 8 +958 2 +1435 6 +3812 1 +2015 2 +457 3 +794 8 +3842 10 +3216 3 +2042 9 +1434 6 +1239 2 +2127 6 +1875 3 +944 6 +3891 4 +1378 8 +3079 4 +18 2 +3976 3 +1541 5 +3214 5 +3051 7 +3073 2 +1602 2 +3425 4 +1351 8 +1690 2 +1897 3 +1664 9 +3108 10 +3148 2 +1947 9 +1882 8 +2122 10 +637 4 +2600 9 +33 10 +740 6 +4052 2 +3853 2 +2945 10 +3184 10 +1138 7 +891 6 +4046 10 +1143 9 +2222 1 +3773 4 +1202 5 +2821 10 +2819 5 +3248 10 +1468 1 +1003 9 +2874 4 +2326 3 +3856 4 +2754 9 +1046 10 +158 8 +987 6 +498 10 +1450 9 +2469 6 +893 2 +242 5 +965 8 +1404 4 +1237 10 +732 5 +1851 10 +2109 7 +59 9 +188 7 +2796 6 +1013 1 +487 3 +2324 5 +3743 8 +892 7 +4064 7 +4045 3 +3782 10 +1446 9 +2252 3 +3909 1 +2342 5 +3848 4 +2927 4 +1566 9 +2926 10 +1353 3 +2182 6 +3307 1 +3550 9 +2691 10 +2161 5 +18 8 +846 10 +3044 2 +3781 10 +3874 5 +1806 3 +3004 7 +3706 4 +1410 5 +385 3 +2192 3 +2394 5 +1136 4 +3317 4 +2178 10 +4041 5 +2993 8 +4040 9 +1019 9 +2970 6 +562 1 +32 5 +2279 10 +526 1 +2837 1 +2567 2 +3052 6 +1494 9 +4057 7 +746 8 +794 6 +2297 8 +1915 3 +2059 2 +765 3 +1307 5 +1127 1 +152 6 +2790 6 +3288 4 +666 6 +1417 4 +4066 10 +435 7 +815 8 +3398 5 +242 7 +220 7 +1099 3 +3662 1 +4005 5 +797 10 +1097 1 +2316 1 +491 5 +3261 6 +2273 7 +2782 9 +1929 3 +1046 9 +330 2 +4046 1 +3587 4 +3946 4 +3234 6 +138 1 +3011 3 +1700 6 +2820 6 +2043 1 +3290 6 +34 7 +1907 10 +1689 5 +2015 3 +3168 9 +1296 5 +485 5 +2642 9 +912 3 +3574 5 +2187 6 +294 8 +1082 5 +2047 2 +2364 8 +3798 2 +2315 10 +636 4 +3260 7 +3611 1 +83 6 +2147 6 +1444 1 +3128 4 +2620 8 +1805 8 +432 5 +1134 3 +3839 6 +3958 6 +859 1 +3553 10 +1860 10 +266 3 +3831 9 +489 8 +3482 5 +1726 5 +2778 10 +3276 1 +588 4 +1106 6 +3010 10 +1904 10 +2911 1 +1270 5 +1933 7 +1668 3 +2371 2 +1368 2 +1935 2 +754 6 +948 7 +4086 9 +1736 6 +2621 6 +3620 5 +3147 9 +2652 7 +3169 6 +1000 8 +3131 10 +3956 10 +3640 2 +1964 8 +2045 5 +3052 7 +360 5 +420 7 +3965 4 +2531 9 +1693 4 +1793 6 +3131 4 +3668 8 +3973 2 +1992 1 +858 6 +2315 3 +2248 4 +3981 5 +212 7 +2446 6 +1943 2 +2335 3 +1932 6 +2896 9 +360 7 +4019 6 +3330 10 +1234 6 +1792 7 +3785 5 +735 10 +343 9 +1244 9 +32 8 +2145 9 +2048 3 +2638 6 +2376 3 +1678 6 +1517 1 +3968 5 +1278 4 +2850 8 +384 5 +3305 4 +1696 8 +231 9 +3208 9 +2345 9 +3380 8 +105 8 +2586 4 +909 7 +762 1 +2857 6 +3035 6 +1202 7 +8 8 +1402 1 +1382 9 +3977 4 +860 1 +1392 10 +2480 10 +1663 2 +218 2 +2324 8 +3023 2 +3539 5 +1883 10 +3576 9 +258 10 +793 9 +2534 4 +967 10 +2851 4 +732 3 +3340 10 +139 7 +1777 4 +4067 4 +1892 4 +1651 6 +1054 9 +1563 5 +349 3 +1987 6 +4087 7 +1945 5 +1990 4 +1095 10 +2507 2 +2146 6 +2975 4 +2503 9 +4011 2 +2523 1 +3597 6 +2361 6 +2883 7 +4058 5 +2580 5 +672 5 +2903 3 +3705 7 +3364 7 +498 3 +3776 6 +1210 9 +260 6 +48 10 +1825 2 +3355 6 +2966 10 +958 10 +2739 3 +571 8 +2246 5 +1647 8 +107 4 +2268 7 +3306 7 +2320 3 +3845 7 +4052 7 +3121 5 +3152 8 +1457 9 +1899 4 +2679 3 +2272 4 +761 1 +1511 9 +3331 9 +2836 3 +1161 8 +1409 1 +151 2 +4039 5 +2306 10 +3518 1 +2878 1 +3216 1 +2136 3 +3066 1 +2002 8 +1853 7 +2803 8 +3575 3 +2766 10 +140 2 +2380 7 +1638 7 +954 7 +1200 8 +2932 2 +1346 5 +1628 9 +1527 2 +2214 6 +0 10 +3101 6 +3820 1 +2960 8 +3712 2 +3644 2 +186 2 +4003 2 +1005 7 +1048 10 +47 3 +1204 5 +1305 7 +311 7 +3553 5 +2177 9 +2134 4 +2156 6 +3213 6 +1712 3 +4077 4 +1002 5 +3338 9 +3790 3 +210 3 +1744 8 +2771 6 +3089 9 +2018 6 +3079 2 +539 6 +62 1 +287 7 +1220 7 +2632 9 +806 2 +2889 10 +2385 10 +1006 8 +1598 7 +672 10 +654 10 +2968 5 +2954 3 +2647 4 +1433 9 +869 9 +2516 9 +2641 4 +1410 1 +2263 4 +1278 2 +3487 1 +4044 8 +3472 8 +3228 4 +2269 6 +4083 10 +3930 9 +1976 1 +1729 3 +2474 1 +1162 6 +3393 2 +3206 10 +3661 6 +370 7 +1080 3 +169 1 +981 9 +2977 7 +1833 2 +3547 4 +1495 9 +1016 8 +2064 7 +2971 6 +3397 8 +348 8 +627 5 +3026 5 +3692 6 +3596 3 +1235 1 +651 2 +2084 7 +2432 5 +136 4 +4040 8 +820 8 +1265 9 +3425 3 +328 2 +340 1 +3161 7 +3849 5 +3448 2 +3869 8 +2734 1 +1776 7 +1113 2 +3366 9 +2128 1 +2368 5 +1645 5 +468 2 +458 1 +214 4 +1181 2 +3903 10 +343 5 +1483 1 +2450 10 +3092 5 +221 10 +3226 7 +4064 10 +3592 8 +1327 8 +758 6 +2094 7 +1110 5 +2272 8 +722 5 +3483 9 +384 6 +395 5 +1219 2 +2729 6 +2917 7 +2913 6 +2956 10 +1940 1 +4057 2 +1357 10 +712 6 +2062 4 +1233 9 +3567 1 +81 6 +346 5 +3885 8 +3340 7 +4041 2 +2606 5 +3324 2 +171 3 +3975 1 +816 6 +1556 9 +1761 3 +1811 7 +4042 8 +3559 5 +3349 5 +2184 10 +1882 1 +2481 6 +148 5 +367 2 +34 4 +813 5 +1284 3 +668 10 +3340 2 +2051 7 +1805 2 +2500 8 +3417 4 +1497 2 +2223 8 +1964 1 +3321 3 +1006 9 +1753 4 +2029 9 +3651 1 +746 8 +2755 6 +119 4 +2076 5 +1177 4 +2112 5 +2475 9 +933 6 +2400 8 +1364 3 +1998 1 +412 4 +2651 8 +2481 7 +772 4 +557 2 +3258 9 +531 1 +3685 9 +793 8 +1235 8 +3974 10 +987 2 +3499 7 +625 3 +2313 6 +3913 2 +2427 5 +3794 2 +1380 7 +2446 5 +3385 9 +133 2 +24 4 +1239 6 +1955 2 +1911 1 +150 3 +4015 2 +3292 6 +1926 3 +243 3 +3738 6 +3500 4 +687 9 +1642 9 +767 5 +1266 6 +3112 6 +3385 10 +3271 1 +3338 1 +2876 5 +4054 10 +2204 3 +1925 8 +3738 8 +192 1 +1907 5 +851 8 +3311 6 +107 5 +3225 10 +3890 5 +363 3 +2629 9 +2460 3 +399 5 +3622 5 +3672 7 +620 3 +1437 5 +3439 8 +2697 3 +3867 4 +995 1 +2512 9 +1818 1 +2488 10 +705 8 +2226 3 +334 4 +2080 3 +3440 3 +874 8 +1353 10 +2539 9 +3699 8 +627 6 +2928 5 +2244 1 +3730 9 +135 2 +3463 4 +2835 5 +1197 6 +3428 8 +1321 9 +718 6 +3813 10 +3435 4 +2379 7 +3080 2 +3083 6 +3480 1 +1848 10 +1903 7 +2182 7 +2115 7 +643 1 +2700 6 +3730 9 +2113 3 +511 3 +2279 1 +3577 6 +1012 9 +444 1 +1395 7 +232 6 +553 8 +3936 6 +3674 10 +779 7 +566 1 +1341 3 +1673 8 +1165 4 +2998 10 +658 10 +2941 6 +3713 10 +250 10 +3088 8 +1136 1 +1677 9 +2568 4 +825 6 +1363 7 +3803 10 +2531 4 +3493 6 +1263 3 +2768 1 +3134 6 +3503 5 +2271 4 +909 8 +2723 7 +3863 10 +850 1 +3385 2 +3789 3 +115 9 +3542 4 +1523 9 +2715 5 +1936 4 +541 10 +1673 1 +1365 4 +3649 5 +862 4 +1903 1 +3088 2 +2062 8 +2391 5 +2111 5 +2398 3 +677 3 +2665 1 +2741 9 +1309 1 +1217 8 +1124 3 +2501 2 +3134 3 +2086 4 +2115 3 +2170 5 +3180 6 +1963 8 +2031 3 +1489 5 +2129 2 +3046 7 +1148 10 +1152 3 +1231 1 +478 9 +904 10 +760 6 +1973 10 +271 1 +1450 9 +1904 2 +4028 3 +3952 4 +4031 2 +998 6 +3397 6 +1798 2 +1243 9 +669 3 +1103 8 +2561 9 +1336 2 +1898 10 +3757 6 +71 8 +2191 3 +955 1 +1181 10 +1097 2 +607 6 +3789 8 +2397 3 +3731 7 +590 10 +3673 1 +3001 2 +3464 6 +2933 5 +1798 7 +864 6 +3376 7 +2628 9 +2012 8 +1778 9 +4004 10 +2607 1 +2224 8 +3822 6 +1640 6 +962 1 +1156 10 +2197 2 +2335 6 +3502 3 +3850 1 +94 4 +2836 1 +3545 2 +3568 2 +147 5 +3812 9 +2883 2 +158 3 +764 8 +382 2 +3227 10 +1902 9 +693 1 +2808 6 +2778 3 +3224 7 +748 7 +3291 10 +1098 10 +202 10 +3440 3 +1715 5 +1676 5 +544 2 +2446 2 +2419 4 +2003 10 +345 5 +2569 8 +3645 9 +3442 3 +3336 5 +2466 8 +3894 9 +618 6 +2501 5 +1284 7 +2334 9 +3551 4 +222 4 +1225 7 +3703 3 +169 1 +1279 7 +1323 4 +3785 2 +1942 3 +2301 10 +1616 8 +2266 8 +3885 2 +1626 1 +552 7 +1040 9 +3796 1 +1145 2 +3568 3 +2973 1 +2361 4 +1690 5 +3478 9 +2362 1 +2586 7 +2335 6 +552 5 +1042 7 +998 7 +2295 4 +3080 3 +3340 7 +539 10 +445 7 +2453 3 +3289 10 +2697 10 +1077 5 +452 3 +3538 3 +2971 7 +2351 8 +648 4 +2591 9 +1177 6 +45 7 +120 3 +662 2 +744 1 +2748 7 +2016 5 +3566 4 +3063 2 +935 3 +2375 8 +3382 9 +3709 3 +3150 1 +2717 7 +667 5 +1362 2 +3286 6 +2738 5 +298 4 +324 8 +1649 10 +2800 8 +1823 6 +206 3 +2642 1 +710 10 +2488 5 +2058 8 +2183 5 +3690 1 +2807 3 +3797 4 +3972 10 +1086 5 +2752 2 +1000 7 +2083 8 +2655 2 +1328 5 +251 9 +582 5 +216 6 +2669 6 +1021 7 +1870 5 +2365 7 +1388 4 +236 2 +146 2 +3013 10 +1503 7 +3728 8 +1029 1 +3445 3 +3721 3 +629 10 +2488 5 +2878 10 +322 1 +845 8 +915 6 +3599 10 +315 4 +346 5 +3467 2 +1438 2 +3752 6 +2755 4 +2422 1 +3026 4 +170 4 +1402 1 +2791 8 +143 3 +364 9 +2751 1 +3433 8 +1617 10 +2479 1 +1790 4 +1386 3 +496 6 +2842 9 +381 9 +1309 2 +2860 6 +3872 4 +3481 3 +4042 1 +2633 2 +568 7 +3264 1 +1935 5 +1879 5 +3712 8 +3549 7 +1303 3 +3758 7 +557 8 +528 1 +2361 4 +3533 7 +1118 2 +1233 10 +1692 10 +565 10 +112 9 +2924 4 +306 9 +1062 2 +771 2 +422 4 +3627 6 +3759 7 +98 2 +3618 1 +2167 1 +3920 2 +3831 10 +3358 2 +285 8 +663 7 +2211 6 +1940 10 +2724 10 +2462 5 +3231 7 +4059 1 +655 4 +3209 4 +1967 2 +16 2 +2907 6 +1247 2 +423 9 +2550 8 +2504 8 +3717 6 +638 10 +3612 9 +251 8 +1957 2 +2920 8 +1126 2 +4066 6 +3226 9 +367 2 +121 9 +1582 8 +1083 2 +523 9 +2216 7 +365 2 +1006 3 +200 7 +2057 6 +2091 1 +1604 10 +468 9 +1648 10 +1240 1 +2192 8 +2788 9 +309 3 +2429 1 +943 6 +2749 7 +2008 7 +3065 3 +3963 9 +3473 2 +1899 4 +282 4 +621 1 +1027 6 +4082 2 +336 3 +3997 10 +337 10 +1187 2 +2267 1 +3160 9 +1307 5 +1026 7 +1905 10 +1233 6 +3477 7 +623 9 +1811 4 +2416 9 +749 8 +2941 7 +4067 2 +2988 9 +2802 9 +3350 10 +2006 9 +1948 8 +2569 9 +1043 10 +227 4 +2570 4 +208 9 +504 4 +2605 6 +1583 1 +2863 7 +2535 2 +1898 5 +2526 4 +1958 3 +750 10 +1144 4 +3770 10 +2773 1 +579 1 +298 9 +2876 5 +124 8 +3938 6 +2761 6 +1497 9 +2385 3 +28 5 +1902 1 +2215 1 +2232 4 +691 4 +3335 3 +1653 9 +2574 5 +905 9 +2089 1 +4054 2 +322 4 +1428 9 +3986 7 +3064 1 +1395 10 +199 1 +1969 8 +647 6 +2922 2 +3846 6 +3710 1 +2717 7 +872 6 +3434 9 +2872 5 +3901 5 +3798 1 +3308 2 +1375 5 +2324 5 +3747 1 +1766 10 +4054 1 +3359 8 +3596 1 +598 5 +1763 5 +834 2 +2993 6 +2178 8 +1166 5 +1497 7 +3001 2 +3940 1 +3314 7 +2921 9 +3621 2 +322 10 +3712 10 +1826 9 +2031 3 +300 2 +1676 9 +2713 10 +3797 4 +3538 5 +1714 8 +1573 6 +461 4 +2638 8 +3952 8 +2699 3 +782 4 +2420 9 +1389 6 +3213 9 +2469 8 +268 5 +1800 3 +3283 9 +2168 6 +2790 1 +2303 5 +1537 9 +2811 9 +2176 1 +4047 4 +4057 8 +2859 4 +715 7 +3273 8 +522 7 +2281 3 +3620 4 +1318 8 +2615 8 +247 7 +3388 4 +2357 9 +1736 4 +2903 10 +3366 2 +530 5 +4067 7 +1515 5 +1257 3 +284 9 +2575 8 +810 6 +1111 1 +912 3 +2310 5 +1689 6 +605 1 +1094 3 +1493 8 +1956 1 +2774 2 +1818 4 +717 8 +3409 7 +3451 6 +2795 10 +2000 9 +867 10 +1618 10 +3671 8 +2327 7 +3069 3 +3664 7 +3641 8 +1703 4 +1593 10 +2346 4 +2062 2 +2366 7 +2835 9 +3325 5 +1489 6 +3933 7 +622 6 +195 4 +2799 2 +691 2 +426 1 +1178 8 +2160 1 +3000 9 +3391 6 +1186 9 +3507 10 +2895 10 +1630 9 +3024 3 +2015 9 +2312 5 +252 4 +1032 10 +386 8 +1337 9 +4041 8 +67 8 +4058 2 +2072 8 +1684 8 +1896 6 +1753 4 +398 7 +749 1 +729 7 +2602 10 +2766 8 +2777 5 +717 7 +1261 2 +1327 4 +806 9 +2775 6 +1071 7 +669 4 +547 7 +2400 6 +3094 3 +3333 5 +1094 9 +2456 5 +2750 2 +3026 8 +2710 9 +3808 8 +1996 10 +3515 3 +3116 4 +600 6 +1129 10 +2806 7 +1133 4 +3239 4 +3498 8 +3927 3 +3119 6 +645 10 +3976 7 +3000 7 +1941 8 +2398 2 +804 3 +2801 9 +131 5 +3908 1 +3488 6 +2652 9 +514 6 +3429 8 +1486 2 +2305 2 +3119 6 +3841 8 +400 6 +3821 10 +1439 9 +3818 5 +3814 6 +3004 2 +2864 7 +2671 5 +2987 4 +3497 1 +2841 10 +3223 10 +2353 7 +2602 2 +2515 10 +2764 6 +3647 6 +301 8 +3496 1 +2796 1 +507 7 +3450 4 +1967 3 +1302 1 +1883 7 +1472 3 +764 7 +1242 10 +3043 2 +2329 3 +313 6 +2454 1 +595 10 +2469 7 +2829 1 +672 4 +2318 10 +3829 3 +306 9 +2391 6 +186 8 +922 9 +498 10 +2596 4 +4041 7 +3766 3 +2092 1 +1106 5 +1029 1 +760 9 +629 7 +2972 7 +49 10 +1723 1 +1100 10 +1552 8 +2948 7 +3257 6 +1219 9 +1558 1 +2476 5 +1419 8 +3284 8 +3402 6 +872 2 +905 9 +1830 6 +3549 6 +430 8 +2495 5 +1579 5 +2147 6 +3292 4 +1639 9 +1331 2 +2285 3 +1700 6 +3407 4 +1553 9 +667 4 +3829 7 +1023 8 +999 3 +2571 8 +1483 6 +4059 9 +2 2 +3736 4 +3863 6 +1784 10 +3006 6 +1101 9 +1805 7 +141 2 +4044 6 +646 6 +1909 1 +463 8 +4083 8 +3321 2 +1316 4 +2416 4 +768 10 +2575 9 +0 2 +946 3 +2547 9 +716 8 +876 2 +567 4 +429 3 +3650 3 +1392 2 +222 10 +3304 3 +1999 8 +3132 5 +2022 5 +762 9 +520 3 +218 10 +3536 7 +1025 7 +3440 10 +1655 8 +2431 4 +1081 8 +2069 3 +617 3 +2451 6 +3468 4 +2915 8 +509 6 +3601 1 +3734 1 +1848 10 +3266 5 +1321 4 +3339 1 +3907 3 +605 4 +2670 5 +3700 5 +1465 5 +230 9 +1647 6 +1121 8 +1702 10 +1313 3 +3437 7 +687 2 +394 4 +3413 7 +3785 1 +3701 7 +2420 1 +1439 2 +3617 1 +2377 7 +828 10 +1584 5 +2105 10 +613 4 +1703 9 +1085 2 +3265 7 +2187 10 +65 1 +478 9 +1802 2 +548 9 +173 9 +1609 10 +2362 1 +2078 8 +3227 8 +1351 3 +1476 4 +4030 3 +77 8 +1429 3 +2230 1 +2267 4 +3761 7 +2482 3 +3695 2 +2715 10 +1950 8 +3214 3 +191 2 +1426 1 +4025 9 +2288 1 +651 1 +3778 8 +3558 2 +3037 4 +2204 6 +1067 3 +3070 9 +1484 8 +3005 3 +1059 1 +3446 3 +4014 4 +3870 8 +547 8 +2775 6 +3845 8 +1804 4 +2908 1 +218 5 +3093 3 +89 7 +3684 6 +3658 9 +833 7 +1967 6 +161 4 +670 4 +2866 3 +117 8 +3446 3 +2549 1 +1795 3 +2873 8 +1846 1 +751 8 +701 4 +1463 6 +3840 2 +877 4 +1676 6 +1189 4 +2423 10 +2994 3 +227 9 +1188 5 +3373 3 +513 8 +1689 10 +1156 6 +2272 9 +785 10 +2816 1 +25 3 +3238 8 +2060 2 +2353 2 +1282 2 +2330 5 +2565 4 +124 4 +1431 2 +1046 2 +20 3 +1129 3 +3634 7 +1691 9 +2914 1 +1649 4 +2172 2 +237 7 +683 3 +491 4 +334 8 +2083 10 +3861 6 +2302 2 +3605 8 +4050 2 +2811 1 +445 5 +1032 8 +2550 3 +3586 7 +291 7 +333 3 +2188 10 +593 7 +3659 7 +1753 4 +1055 2 +2025 4 +42 1 +3533 3 +778 10 +3235 8 +3881 5 +167 2 +2373 7 +4031 6 +1238 5 +1384 10 +146 5 +2762 5 +95 6 +2201 3 +2946 7 +1187 7 +3056 5 +2049 6 +1761 4 +511 8 +1501 3 +2194 4 +514 2 +1275 5 +2585 9 +1824 4 +2886 6 +1378 1 +1310 3 +3751 8 +1893 6 +2449 5 +1366 2 +1640 8 +1890 2 +3838 9 +3109 8 +311 9 +2731 4 +3516 4 +4013 3 +2313 10 +2471 7 +3221 3 +3547 7 +1578 5 +2093 8 +3201 7 +3212 2 +406 5 +442 5 +2052 2 +3781 7 +3699 5 +571 6 +2319 7 +252 1 +2511 8 +2334 8 +3676 10 +3033 5 +462 7 +3261 4 +116 6 +3862 4 +1353 3 +138 4 +2869 9 +3701 5 +1123 1 +2054 4 +1928 6 +2355 5 +614 1 +2389 7 +2568 7 +3382 10 +967 4 +1844 6 +2337 4 +370 5 +749 3 +3739 3 +2660 9 +330 5 +3931 9 +2422 6 +47 5 +1672 1 +532 5 +2381 1 +153 8 +1234 10 +611 8 +1299 1 +3473 1 +3457 3 +1313 3 +557 8 +1826 8 +1328 9 +2872 10 +724 6 +3361 4 +1470 5 +2960 5 +2399 2 +3695 3 +2674 6 +2528 1 +1879 5 +3290 5 +722 4 +458 8 +3622 6 +2228 6 +2952 9 +259 9 +4081 10 +806 9 +3096 5 +1874 1 +2058 3 +2194 2 +1318 1 +3759 10 +3080 10 +1509 3 +1823 2 +2253 1 +4087 4 +3684 5 +1961 7 +965 9 +605 5 +3052 10 +274 2 +3743 9 +3707 5 +2463 6 +2156 10 +3623 5 +1155 10 +3838 2 +4078 1 +2192 2 +3102 3 +1773 1 +3948 9 +2377 8 +2888 5 +2136 3 +2060 5 +896 8 +3079 9 +1040 2 +1130 7 +3937 6 +3076 6 +3555 3 +1160 10 +502 10 +1344 8 +37 3 +1474 6 +2152 6 +3943 6 +2839 6 +3575 5 +841 1 +1645 4 +403 3 +3421 2 +2622 3 +2038 7 +1854 8 +1215 9 +2510 3 +3126 5 +2836 2 +205 10 +2493 5 +2828 7 +2832 1 +1147 7 +2746 2 +3423 1 +996 5 +3615 8 +2340 4 +3044 2 +2626 6 +1859 3 +2203 9 +2429 1 +3878 1 +1973 3 +3902 1 +1947 6 +1431 3 +954 9 +2126 9 +1750 5 +3783 7 +609 4 +3544 9 +3000 2 +3231 9 +230 5 +1005 4 +2676 3 +1779 8 +126 7 +3815 9 +1502 8 +3379 7 +239 10 +1746 8 +3556 1 +585 8 +128 4 +2657 8 +3755 6 +792 1 +3560 10 +1089 6 +1759 1 +2366 10 +3763 9 +3904 4 +3946 4 +2756 6 +1744 8 +1094 4 +2773 9 +2866 10 +473 2 +3495 1 +2644 6 +2988 4 +580 6 +3062 9 +1291 8 +3403 1 +2381 8 +3605 4 +2384 4 +2624 6 +2276 5 +3504 6 +1794 3 +984 10 +2298 4 +1741 5 +3294 1 +1427 6 +550 5 +1140 3 +3464 5 +3081 8 +2807 3 +2306 1 +1334 1 +2968 4 +300 7 +3997 5 +3240 9 +1294 8 +3015 7 +3973 6 +3172 7 +2599 10 +4076 10 +925 8 +4002 8 +1115 2 +2096 6 +2261 3 +1707 4 +496 6 +2034 5 +728 1 +1528 4 +1093 1 +1655 4 +2484 7 +2747 7 +1296 9 +3705 8 +2130 5 +2688 6 +3843 1 +3428 6 +563 9 +1196 2 +2313 8 +389 10 +2293 2 +2089 9 +1327 1 +2247 1 +1018 7 +422 3 +2384 2 +529 3 +805 9 +1418 4 +2608 5 +2303 1 +3074 1 +2861 6 +2880 3 +1415 3 +1745 1 +3101 2 +3574 1 +2530 7 +3120 1 +2466 2 +3287 6 +1071 7 +642 1 +50 1 +2096 3 +1810 4 +3897 6 +1711 4 +2236 10 +3087 1 +1523 3 +428 6 +3090 2 +752 5 +1303 6 +791 2 +3772 5 +3060 3 +276 2 +3836 6 +1636 5 +3260 9 +298 9 +761 7 +3539 10 +3033 2 +2710 5 +548 10 +2236 10 +752 9 +3956 3 +3436 4 +1190 1 +2438 8 +1635 10 +2186 5 +2279 7 +2011 2 +3246 9 +166 8 +3613 5 +2767 3 +3310 10 +3182 5 +761 6 +81 3 +1125 9 +2079 9 +2713 6 +2949 8 +1109 6 +1802 6 +3473 5 +3316 7 +1995 1 +2101 1 +3781 8 +375 6 +3845 4 +905 6 +2920 1 +2864 10 +2161 3 +2636 5 +3050 5 +1001 5 +577 1 +455 9 +279 5 +964 4 +3290 1 +3165 6 +3941 7 +663 9 +878 4 +3683 2 +1732 1 +2821 3 +626 4 +955 3 +3228 9 +1125 2 +176 8 +3467 1 +2231 1 +493 1 +1354 9 +3457 7 +489 5 +2915 6 +169 7 +2606 2 +3155 7 +1887 7 +805 8 +1201 1 +2784 7 +1515 7 +3404 2 +3131 5 +688 4 +2514 1 +1177 5 +1221 2 +1488 4 +3282 9 +3540 9 +615 6 +1572 9 +2183 8 +1206 5 +2648 5 +129 4 +73 7 +834 6 +1421 1 +3000 3 +1743 8 +3202 7 +3561 10 +254 3 +2436 2 +633 4 +2914 4 +3341 3 +2957 9 +2326 8 +3617 2 +3928 7 +2087 6 +1948 4 +3483 7 +3571 2 +445 10 +3758 6 +2060 8 +1411 3 +3633 10 +2902 3 +2883 1 +2072 9 +122 3 +3060 1 +3294 1 +1679 10 +2728 1 +2040 6 +662 10 +180 10 +1269 7 +1840 8 +2469 10 +3559 5 +2778 6 +2144 10 +2363 3 +2205 4 +2284 7 +400 8 +1167 3 +2692 8 +3226 8 +1845 4 +2370 7 +202 1 +2413 6 +32 10 +878 5 +946 5 +3493 6 +1605 4 +1332 6 +941 6 +3075 6 +2886 2 +917 8 +3930 4 +3052 9 +2986 7 +3234 3 +1216 10 +2660 2 +1263 4 +4093 10 +4015 9 +1480 7 +1227 8 +518 7 +1476 6 +2073 9 +77 6 +1061 10 +3768 1 +1034 1 +3905 3 +1328 7 +2601 8 +970 9 +2644 1 +2034 10 +720 8 +1749 3 +1298 5 +2304 10 +377 5 +3482 1 +2233 7 +3569 10 +605 8 +2151 10 +3546 4 +1699 3 +3277 1 +2573 2 +1318 3 +1096 3 +669 3 +1930 10 +620 10 +3123 4 +870 10 +1238 3 +2084 3 +2368 3 +966 9 +199 6 +3942 6 +2792 1 +569 8 +165 1 +1571 7 +2859 6 +1567 2 +3782 4 +932 9 +2540 3 +3627 1 +745 7 +2420 4 +3761 7 +3870 9 +1642 3 +1394 10 +3151 5 +1286 6 +3902 9 +1126 6 +2171 3 +2645 2 +651 3 +1339 5 +3791 7 +3945 9 +1769 6 +1692 2 +1338 10 +732 10 +2410 7 +713 6 +136 10 +2966 3 +458 2 +1204 8 +1698 4 +2628 9 +1680 7 +1361 2 +579 6 +1948 4 +3507 10 +4019 10 +3171 7 +536 10 +407 7 +1526 2 +1468 8 +3874 8 +3144 8 +499 4 +1453 3 +524 3 +2746 1 +184 6 +1811 1 +52 9 +3121 1 +1357 10 +1017 9 +2192 2 +2987 6 +1137 3 +242 7 +2761 9 +2075 10 +3275 5 +1061 8 +2137 8 +660 10 +1996 5 +163 2 +1761 4 +2318 2 +3570 5 +2478 3 +966 4 +3212 10 +2345 9 +3321 5 +1807 1 +3326 4 +2135 2 +3927 8 +2992 4 +556 4 +1623 4 +1523 7 +920 3 +526 6 +3249 1 +3437 1 +3043 8 +2877 7 +3945 4 +294 8 +289 6 +2722 7 +3440 3 +3979 1 +3144 1 +1985 3 +3975 9 +3826 8 +136 3 +3342 2 +3679 6 +3088 5 +446 2 +2292 4 +3041 10 +2656 3 +3513 6 +1280 1 +2610 9 +2661 4 +422 6 +54 2 +2021 5 +3864 2 +254 10 +1542 1 +1647 4 +3368 1 +3790 5 +3016 7 +3277 4 +1189 3 +969 4 +656 5 +3823 6 +4081 4 +393 7 +3358 1 +2825 9 +3544 1 +680 6 +1429 10 +1347 2 +3018 6 +2662 2 +3516 3 +4074 3 +3215 7 +3970 7 +1252 1 +1594 6 +1729 2 +3765 7 +637 8 +751 7 +2482 4 +733 2 +3850 10 +2449 4 +1382 5 +185 10 +83 4 +3644 8 +2661 1 +1712 4 +533 3 +35 2 +3955 4 +3133 4 +3064 10 +3728 10 +1492 2 +1234 10 +2203 2 +705 3 +321 2 +386 5 +1639 9 +1725 8 +823 9 +934 1 +1222 4 +862 8 +2665 4 +2998 4 +2214 5 +2306 3 +3735 7 +3509 5 +139 7 +398 4 +411 3 +3341 4 +1300 1 +38 9 +1877 5 +1392 5 +1156 4 +3161 1 +3027 3 +2939 10 +721 7 +3238 9 +2148 9 +1675 6 +1853 5 +1912 7 +251 6 +3098 4 +1352 3 +630 5 +3370 1 +65 10 +2325 8 +3688 8 +606 6 +1510 2 +3982 1 +3867 10 +888 10 +2874 7 +2560 7 +2199 2 +1996 5 +2965 4 +879 8 +3151 2 +1253 2 +1275 3 +1155 1 +2036 10 +3880 3 +3907 6 +283 6 +3319 7 +3543 7 +3446 9 +810 1 +2069 9 +2928 4 +191 8 +1380 10 +582 10 +425 6 +235 4 +1995 6 +677 1 +3967 9 +879 5 +3179 3 +3038 7 +1785 8 +1906 10 +4095 3 +3679 9 +2749 7 +1069 3 +188 3 +3307 2 +629 9 +2304 5 +2244 5 +1247 4 +2603 1 +3044 9 +2567 8 +3285 2 +3387 10 +2907 1 +471 10 +2077 9 +3257 10 +536 6 +1722 6 +599 4 +3487 10 +1150 7 +694 8 +1787 4 +3202 6 +3354 5 +2059 4 +1700 1 +2012 7 +1176 6 +2306 5 +2052 5 +2118 1 +1998 3 +457 2 +201 4 +264 3 +1911 6 +3168 4 +720 8 +3410 4 +2493 5 +1687 10 +660 2 +3167 3 +339 6 +1547 10 +716 3 +1095 9 +784 7 +444 1 +446 7 +2945 4 +1198 4 +2037 8 +326 7 +3370 3 +1448 10 +1007 5 +3943 6 +423 3 +101 3 +2099 3 +1 10 +2841 2 +2516 1 +4060 6 +2563 5 +1963 8 +3989 3 +1397 9 +2786 8 +3013 4 +428 1 +1830 5 +2502 3 +1496 7 +770 9 +1737 8 +2612 9 +2542 3 +3154 9 +3661 5 +1271 10 +558 4 +866 7 +365 4 +3517 3 +830 8 +455 3 +3380 8 +886 4 +1429 8 +200 3 +3908 8 +648 3 +91 3 +791 5 +3998 8 +3420 7 +3604 9 +1988 4 +1927 7 +1738 3 +3145 4 +4017 1 +3732 1 +1345 9 +1469 10 +2896 4 +358 10 +1905 5 +2025 6 +52 5 +2466 1 +1332 4 +706 4 +3153 2 +2509 10 +3789 4 +2525 6 +2994 9 +3386 9 +2353 2 +1970 8 +3150 10 +697 10 +3628 4 +3735 1 +2902 1 +2916 8 +1131 6 +2449 7 +2256 2 +1037 8 +873 10 +2524 9 +3729 7 +3510 9 +912 8 +1351 5 +3213 7 +116 6 +2781 9 +3781 7 +987 9 +224 2 +2170 7 +2957 10 +3753 8 +2546 1 +2295 6 +2162 5 +228 8 +2825 8 +471 3 +1198 2 +3532 1 +301 1 +1597 5 +569 4 +1366 5 +920 8 +1937 3 +3212 1 +2528 8 +2803 3 +961 1 +2705 3 +3672 7 +2234 9 +174 2 +854 9 +2816 5 +2280 2 +3101 2 +549 4 +2064 1 +117 9 +507 1 +1728 1 +1150 5 +3312 8 +746 8 +163 4 +1436 3 +2183 5 +3464 2 +3702 2 +1428 9 +262 1 +3486 6 +3200 10 +2428 7 +507 5 +1275 8 +3160 8 +3044 6 +3909 1 +1829 5 +2082 6 +600 4 +2011 8 +3697 8 +1983 4 +1083 10 +2200 10 +662 2 +3974 4 +2660 5 +3007 2 +2732 10 +658 8 +1607 5 +1726 5 +2072 7 +1318 9 +2327 6 +683 4 +1417 5 +4019 2 +2298 10 +2468 5 +2484 1 +640 5 +909 1 +3383 1 +733 8 +171 1 +1525 1 +3995 3 +3358 1 +1303 3 +1440 8 +2982 5 +250 3 +3681 3 +3585 7 +1668 7 +4028 10 +3734 9 +1486 10 +809 1 +2895 8 +3498 1 +1937 9 +3426 5 +4067 8 +3358 1 +2379 1 +660 3 +2233 5 +209 2 +2433 7 +2579 10 +3888 5 +3581 10 +2047 10 +3382 4 +312 10 +564 6 +750 10 +2459 7 +3991 10 +3691 6 +1776 7 +553 5 +794 2 +1928 2 +4032 5 +169 8 +2668 2 +3603 6 +3673 7 +3554 1 +3810 4 +1202 10 +1714 2 +3415 9 +4059 7 +3495 1 +3524 7 +1430 4 +1176 4 +4055 1 +1189 1 +3876 8 +3357 1 +1489 4 +1174 1 +470 3 +396 3 +3206 2 +1713 6 +3938 2 +223 7 +825 7 +3377 4 +4002 5 +2301 7 +3428 4 +3796 3 +553 7 +733 2 +1313 8 +3271 2 +616 6 +2533 7 +3916 6 +1280 8 +1655 6 +1439 3 +336 6 +4030 4 +3584 6 +1626 5 +1568 10 +2000 1 +1621 4 +326 9 +262 9 +1494 4 +3936 9 +345 5 +2071 8 +2090 4 +246 5 +2059 2 +2962 7 +2860 10 +3029 7 +1136 1 +2354 7 +2352 7 +2727 1 +385 10 +3312 9 +4075 5 +3319 7 +2917 8 +1577 9 +3490 4 +1629 1 +1123 1 +380 6 +1411 4 +1559 1 +3765 7 +408 2 +1422 8 +200 4 +1164 4 +3994 7 +1547 7 +3982 1 +188 1 +1065 7 +893 3 +400 6 +824 4 +1566 2 +1471 10 +3063 10 +1623 10 +3839 10 +2209 4 +1860 5 +3279 10 +4000 4 +3763 7 +1994 10 +1841 10 +3347 5 +58 7 +3053 10 +2020 3 +1465 10 +475 2 +3230 2 +1539 5 +1206 8 +3910 7 +3428 3 +915 4 +2602 2 +1036 7 +2873 3 +3426 2 +3789 9 +3867 10 +2420 7 +268 6 +16 10 +4072 2 +2510 4 +1975 9 +4075 6 +1680 1 +2231 6 +3514 6 +305 7 +629 5 +1157 4 +4079 8 +3085 6 +3667 1 +2830 3 +1419 5 +1535 1 +3703 7 +3475 9 +2563 5 +1847 6 +749 8 +2222 2 +3356 1 +1830 7 +1053 9 +3040 3 +907 5 +342 7 +2002 7 +2554 8 +796 5 +2960 8 +288 4 +4091 5 +537 1 +3772 4 +2944 8 +2436 5 +193 5 +4017 7 +3813 9 +1315 6 +354 9 +2268 2 +1458 3 +1338 7 +703 7 +1389 9 +3459 5 +2492 2 +1306 2 +3739 7 +3081 7 +655 2 +343 2 +2127 6 +368 7 +1965 3 +2220 4 +2810 1 +1996 10 +2980 4 +1073 9 +489 5 +2625 10 +3867 4 +3131 5 +2048 5 +802 8 +320 10 +2852 1 +3911 7 +3585 4 +1991 8 +4002 8 +2146 1 +2301 2 +595 8 +3298 9 +1043 6 +74 8 +3826 9 +3145 5 +2067 8 +2972 1 +3083 3 +2167 8 +277 7 +1423 2 +30 4 +835 8 +2595 6 +928 2 +3105 7 +2777 7 +3550 7 +749 2 +2206 6 +3923 5 +1227 9 +2410 6 +1069 3 +1539 8 +691 5 +1029 10 +759 7 +3185 1 +2948 7 +2047 1 +3145 3 +2602 10 +678 4 +1535 3 +3244 2 +2659 4 +1859 7 +1721 6 +976 2 +3808 3 +2188 10 +1352 4 +1887 2 +1073 4 +1462 3 +3347 9 +342 7 +1147 5 +3310 2 +2879 10 +1247 9 +1796 10 +1271 6 +1227 8 +2907 9 +3342 7 +3470 5 +3974 10 +3227 7 +24 8 +1290 5 +3966 3 +1480 6 +818 9 +110 7 +368 3 +2331 3 +2793 7 +1056 8 +87 9 +2185 8 +2437 5 +3128 10 +2431 1 +1472 7 +736 10 +625 2 +2524 8 +2896 6 +523 10 +3900 2 +39 8 +29 7 +3419 10 +1473 2 +3676 3 +1270 9 +1607 5 +2863 10 +2489 1 +185 9 +1366 10 +2688 8 +2721 2 +1557 4 +901 1 +3999 8 +463 2 +338 1 +975 7 +2213 9 +3579 4 +1871 3 +2407 6 +2121 5 +1883 9 +2673 2 +932 10 +1189 8 +55 9 +3505 2 +1278 10 +3984 1 +138 8 +3847 4 +44 9 +1128 8 +524 8 +3695 8 +858 8 +3998 9 +692 4 +3851 5 +1613 10 +3202 4 +2119 4 +1521 1 +2611 7 +3324 6 +426 1 +1362 1 +1218 7 +1994 6 +3575 6 +1661 8 +64 2 +3758 10 +2322 9 +3765 3 +596 1 +342 4 +2811 9 +166 6 +3821 8 +2317 7 +1582 3 +3898 2 +388 8 +403 4 +2876 4 +3466 9 +1479 2 +2638 10 +778 1 +2175 5 +26 1 +658 3 +590 2 +1065 6 +4014 1 +3093 8 +3340 1 +3835 6 +1366 5 +2207 2 +3634 10 +284 1 +1490 5 +2578 5 +574 10 +3098 5 +2438 6 +739 4 +350 8 +3544 9 +657 7 +2999 1 +2611 10 +2105 8 +3416 7 +952 4 +3886 3 +3437 2 +1740 6 +3627 4 +2275 7 +2992 8 +974 9 +3900 8 +4 10 +3258 5 +1439 9 +3007 6 +1782 4 +1625 8 +414 1 +1805 4 +2885 9 +363 10 +2635 8 +715 6 +87 3 +2050 1 +513 1 +2020 10 +2294 4 +3713 3 +3611 8 +640 7 +2474 6 +782 2 +432 3 +2424 9 +2661 6 +919 8 +2453 7 +1694 8 +560 10 +1311 5 +3812 8 +1185 6 +3277 8 +2681 3 +3695 8 +2804 10 +836 2 +2331 7 +799 5 +2602 3 +119 9 +467 5 +3483 4 +706 4 +2544 8 +2491 10 +2124 6 +3472 5 +2085 10 +3649 1 +1534 2 +1163 7 +2186 9 +1385 7 +914 4 +2603 8 +950 4 +3991 4 +1647 1 +2278 8 +385 5 +2320 3 +3261 8 +2689 7 +915 4 +1615 2 +2722 4 +1011 4 +882 1 +2544 7 +3906 3 +102 1 +3270 2 +2172 8 +461 10 +1626 3 +16 4 +686 6 +838 1 +2327 4 +299 2 +1070 3 +3076 7 +2740 3 +1730 7 +3560 8 +3786 2 +977 4 +520 2 +2333 8 +835 7 +3915 3 +876 3 +273 4 +2967 7 +1563 8 +1852 8 +3721 3 +3859 8 +1528 1 +1475 8 +3293 9 +3165 8 +3501 9 +2396 3 +3608 9 +2272 6 +2165 8 +3257 9 +2610 4 +1163 1 +3509 3 +1916 3 +3182 3 +2371 4 +2451 1 +3350 1 +2898 3 +2300 5 +1668 3 +2103 10 +1699 6 +601 5 +1613 2 +1192 5 +2242 5 +1992 4 +1000 2 +941 10 +1213 10 +3913 1 +3555 2 +1632 8 +2423 2 +227 8 +764 3 +2619 7 +3879 5 +179 1 +3913 9 +2466 4 +535 4 +2936 7 +1864 8 +2765 7 +3059 4 +1189 4 +2223 3 +2341 5 +2939 2 +3941 6 +3223 9 +1994 9 +3308 1 +3122 9 +1325 5 +1739 3 +1566 10 +50 6 +695 10 +2593 9 +13 3 +1030 4 +2702 10 +1909 9 +779 6 +3447 3 +3263 1 +1277 9 +1509 1 +3466 7 +2193 7 +1238 10 +482 1 +1026 2 +3504 5 +43 7 +1116 6 +3103 10 +3342 9 +3338 2 +727 9 +623 10 +831 9 +97 3 +926 3 +3812 1 +3470 8 +266 7 +3445 8 +2394 3 +979 7 +1050 4 +2067 2 +3617 3 +412 2 +1346 7 +3277 10 +548 1 +80 5 +3596 9 +3072 1 +2583 5 +1878 4 +307 3 +225 8 +920 8 +3260 5 +3237 4 +1813 3 +337 7 +85 3 +2357 8 +2327 4 +369 10 +924 10 +4089 1 +2310 9 +3379 2 +591 1 +2988 5 +1490 6 +4028 5 +538 7 +168 4 +2168 4 +350 9 +3798 2 +535 1 +1859 4 +2186 8 +4011 5 +3635 6 +1262 1 +2529 4 +1050 6 +2014 9 +2269 6 +3534 10 +2635 8 +1490 4 +979 4 +2981 4 +3493 9 +3085 2 +107 3 +3336 8 +270 3 +1920 8 +1398 1 +1968 4 +1477 1 +244 6 +3898 1 +1176 2 +1237 7 +3657 4 +3846 1 +3963 1 +1973 9 +223 8 +2640 8 +2148 8 +3957 8 +1940 6 +391 6 +2694 5 +2599 10 +2327 6 +1905 10 +762 5 +1770 1 +1145 4 +833 9 +420 1 +970 3 +551 4 +919 2 +1839 6 +2596 4 +991 10 +1659 10 +1917 10 +1809 5 +1835 5 +197 7 +1199 5 +120 6 +1531 1 +1847 3 +3539 7 +1262 5 +1683 8 +5 1 +3279 6 +1075 1 +199 5 +3986 7 +1648 9 +3929 9 +1898 1 +3873 5 +3550 5 +2803 7 +2429 8 +1000 5 +2265 9 +460 2 +2657 1 +687 3 +61 2 +1399 9 +1496 8 +952 3 +3675 7 +3212 1 +1912 7 +3953 2 +1041 8 +1579 10 +2090 5 +2472 10 +2296 6 +1064 8 +534 6 +669 1 +445 3 +2713 5 +1119 8 +1021 6 +3815 2 +2857 2 +2602 3 +3713 9 +2803 2 +3275 8 +959 5 +1625 9 +2189 4 +248 6 +2983 7 +3182 4 +696 2 +3458 6 +2456 10 +314 5 +3712 7 +2531 3 +3989 3 +1422 5 +1620 7 +170 4 +3562 5 +2963 7 +2518 7 +3555 2 +729 7 +3397 7 +245 7 +200 2 +169 10 +2027 8 +313 2 +386 6 +1107 3 +133 3 +323 3 +1767 2 +1878 8 +2341 2 +2469 2 +3722 4 +497 6 +1572 8 +3332 5 +3172 6 +1846 7 +3105 5 +2239 10 +3140 5 +2168 9 +1318 3 +3639 10 +1989 9 +1165 3 +2288 3 +1654 9 +1272 5 +1434 2 +1465 3 +378 5 +2543 8 +3443 7 +2578 6 +1590 5 +3397 6 +457 10 +2220 8 +3763 7 +3461 5 +87 9 +2351 3 +2952 6 +4072 1 +1095 1 +1502 6 +1006 9 +2466 1 +3924 10 +3303 5 +3884 1 +332 10 +1288 4 +331 3 +1055 1 +3754 5 +2886 8 +2959 8 +4087 6 +2734 2 +1949 10 +1009 4 +4041 4 +1906 3 +1317 7 +363 1 +1212 9 +3142 3 +1817 5 +2246 10 +3563 5 +2756 5 +63 9 +3101 4 +3782 7 +2576 7 +3221 10 +1074 7 +1683 5 +3955 2 +3645 8 +1078 2 +4021 4 +968 6 +4093 4 +1355 2 +2889 8 +1407 4 +2986 7 +864 4 +1861 6 +2654 2 +3886 1 +1707 4 +2580 10 +751 9 +750 10 +445 8 +1055 6 +2636 1 +193 6 +2010 8 +2950 3 +3717 1 +2744 6 +450 2 +3456 10 +3531 9 +3257 10 +2757 10 +1168 6 +4041 5 +1529 9 +3601 5 +2412 7 +2878 10 +3562 3 +185 5 +2563 8 +1384 7 +513 6 +1563 3 +681 2 +1639 3 +2177 1 +2432 6 +1291 1 +3617 6 +2337 7 +2274 7 +288 6 +3436 5 +3898 2 +56 7 +215 10 +2701 7 +3097 9 +855 1 +1753 5 +1794 10 +2737 4 +3033 7 +2635 3 +1103 7 +4051 5 +2734 3 +2594 8 +3391 4 +1836 10 +3074 1 +418 10 +3174 6 +5 5 +1850 8 +1737 7 +2913 2 +3168 10 +3044 9 +935 5 +3529 1 +3447 10 +658 4 +2834 5 +3690 9 +988 6 +1784 6 +2519 3 +690 7 +2426 4 +3790 9 +2893 10 +3717 3 +3165 6 +1435 9 +3512 10 +3094 6 +2585 6 +586 1 +1464 1 +2347 8 +2402 3 +4045 6 +88 2 +3054 2 +1431 6 +3923 1 +4063 4 +1475 5 +4034 9 +2639 9 +3836 8 +2603 1 +3079 9 +1162 5 +902 8 +3504 9 +3122 10 +1886 10 +1466 2 +512 7 +2840 8 +1431 4 +2923 9 +1925 1 +219 4 +1482 3 +1919 5 +662 10 +308 10 +2537 2 +3087 1 +1711 6 +2778 6 +530 1 +2722 4 +1949 1 +1259 4 +3334 7 +3745 3 +2895 8 +3042 7 +2625 10 +1071 3 +3360 1 +1526 7 +1847 5 +1362 2 +4024 1 +1717 2 +105 5 +3761 3 +3243 8 +346 2 +2754 8 +3591 1 +3572 9 +414 1 +969 1 +2714 9 +3558 3 +2297 5 +1720 4 +3720 8 +3150 4 +4073 8 +3303 2 +2692 1 +3429 5 +701 7 +170 6 +2121 2 +502 7 +2172 1 +3261 4 +1617 6 +2151 6 +778 10 +2683 1 +2626 8 +2822 3 +1594 8 +1728 3 +3762 10 +1846 4 +1900 2 +3599 10 +528 5 +1458 2 +44 3 +1305 8 +1733 5 +88 9 +1782 8 +3755 1 +1702 2 +4083 10 +3911 9 +3894 7 +3036 2 +1522 4 +3683 10 +1559 8 +687 1 +1649 2 +283 9 +3725 1 +1026 9 +234 9 +549 9 +1874 1 +3716 6 +2385 8 +1511 7 +340 10 +329 4 +3227 4 +3500 4 +3021 8 +3928 9 +3675 10 +2745 10 +4024 9 +104 10 +4067 7 +2514 4 +1982 2 +1922 8 +2539 9 +3064 2 +1065 6 +2145 4 +2365 8 +679 3 +631 10 +3391 3 +2604 3 +3610 4 +3968 5 +600 4 +922 1 +802 1 +1838 9 +3124 4 +2142 8 +1262 10 +1685 3 +2353 10 +2134 5 +525 3 +1139 4 +2110 8 +1900 8 +1330 8 +1132 5 +1346 3 +2477 3 +297 4 +2994 9 +709 1 +705 10 +3144 2 +659 6 +3842 1 +355 9 +1783 9 +1655 8 +833 6 +1879 7 +1793 9 +840 2 +2880 7 +1100 8 +1240 5 +28 3 +524 4 +3320 2 +3918 10 +3232 10 +3721 4 +2752 1 +3469 9 +119 6 +40 3 +1196 2 +153 7 +1412 1 +1023 4 +2199 6 +4020 1 +3339 1 +267 3 +534 5 +1809 10 +443 1 +3047 4 +1530 5 +999 9 +187 3 +682 6 +2101 1 +231 8 +1843 9 +4 7 +1252 7 +2628 6 +2873 7 +3224 9 +3350 2 +2356 3 +3838 10 +2271 8 +154 6 +4091 1 +1366 3 +1692 8 +255 6 +3856 3 +1769 9 +937 4 +2600 4 +1079 10 +2209 4 +1333 4 +838 6 +1543 3 +1424 4 +3972 3 +1069 10 +3741 6 +2895 4 +3091 6 +416 8 +2310 1 +3449 5 +980 1 +1137 4 +3295 1 +2537 10 +358 10 +1877 6 +3183 9 +729 9 +1705 10 +1596 8 +3885 9 +3740 2 +3226 9 +1116 5 +3267 8 +1188 10 +2489 8 +3964 10 +2518 5 +1513 7 +1431 6 +1797 3 +1423 9 +921 10 +3562 2 +1955 10 +1122 7 +3990 3 +3960 5 +1562 4 +1258 4 +490 4 +2236 2 +3664 4 +1782 6 +2973 3 +2473 6 +273 9 +784 9 +2434 2 +494 8 +1196 7 +1416 10 +1631 1 +518 9 +1756 9 +3957 7 +1900 4 +2754 9 +3777 1 +53 10 +2003 5 +4001 8 +268 1 +3237 7 +808 4 +595 5 +1617 1 +1093 1 +2162 10 +2289 8 +134 8 +1671 1 +758 2 +698 4 +1203 9 +1715 8 +2787 5 +3170 4 +3987 8 +4067 10 +1519 7 +2314 4 +1213 2 +3345 2 +3304 1 +3792 9 +3340 5 +2579 6 +307 9 +1753 6 +3547 10 +1761 3 +2886 3 +3110 10 +1389 10 +961 4 +2207 3 +2827 4 +362 4 +816 1 +127 6 +2450 10 +3879 5 +3620 9 +472 2 +946 5 +1408 8 +2322 1 +762 5 +3162 3 +1389 8 +781 6 +1851 3 +3896 10 +790 3 +3365 2 +2820 8 +3210 5 +2584 9 +626 3 +298 2 +1770 1 +219 2 +2076 1 +3885 3 +65 6 +326 6 +4068 3 +2359 7 +1967 10 +3458 8 +2498 5 +3206 6 +1216 1 +196 2 +218 6 +1272 3 +1691 10 +2849 10 +3830 7 +1267 7 +3000 1 +1946 8 +3059 8 +3379 3 +2818 10 +1316 1 +3641 7 +16 4 +633 1 +3907 6 +610 10 +2836 2 +2250 7 +3507 6 +389 9 +3438 2 +1448 7 +1073 9 +3074 8 +3004 1 +3705 6 +3537 2 +2689 8 +2070 8 +2138 7 +2334 3 +3404 2 +1043 1 +3487 2 +908 5 +276 3 +2628 4 +794 3 +2567 2 +135 7 +1559 5 +3642 1 +3973 4 +2905 4 +48 6 +1530 5 +3659 6 +3210 1 +2520 9 +871 1 +1138 3 +1548 3 +336 2 +3684 1 +248 8 +1258 10 +3858 1 +100 8 +3501 10 +3897 10 +295 6 +634 3 +4079 10 +484 5 +1548 7 +3748 9 +1562 3 +0 7 +2139 7 +4024 2 +3352 6 +2749 3 +791 3 +365 3 +3835 10 +2872 6 +2305 4 +938 8 +207 10 +2934 2 +1847 1 +3662 5 +31 10 +3231 7 +2673 2 +1268 10 +2885 5 +912 10 +1940 4 +3632 6 +690 1 +1182 3 +1392 6 +2486 4 +2463 4 +1059 3 +1403 1 +2056 2 +1248 10 +649 7 +1937 5 +3522 6 +3588 9 +3004 4 +1324 5 +1440 10 +694 9 +325 6 +2231 3 +1159 9 +2821 7 +351 4 +1955 6 +3836 4 +142 9 +3406 8 +3108 7 +2828 4 +2230 1 +3395 10 +1428 6 +3546 2 +1741 9 +2505 3 +869 8 +2601 4 +2991 10 +2413 5 +1260 3 +3700 9 +1916 6 +3677 5 +2240 8 +663 8 +1068 1 +151 9 +2250 8 +1435 6 +3274 10 +3595 1 +939 1 +3649 4 +3862 1 +3945 1 +1515 1 +4066 3 +3597 2 +509 2 +3024 1 +2732 1 +2575 3 +1563 2 +3899 1 +251 8 +3423 8 +1755 5 +222 1 +2286 1 +3037 3 +3884 2 +3108 4 +560 4 +1031 4 +2828 10 +3025 1 +3672 8 +2637 5 +2769 10 +2879 10 +2525 10 +950 8 +3348 9 +3913 3 +1365 8 +583 6 +2070 5 +2147 6 +3622 7 +2350 10 +1 1 +2998 1 +3268 6 +2171 5 +2428 5 +1500 4 +4086 2 +3881 9 +2854 1 +2452 7 +1137 5 +1811 2 +3475 7 +573 4 +499 5 +3365 2 +1496 3 +620 7 +1178 9 +471 7 +3491 9 +3427 4 +3926 2 +1732 3 +3207 3 +3701 8 +3904 6 +584 3 +2269 3 +1809 8 +198 9 +2839 1 +2380 3 +3147 4 +3633 4 +3938 5 +422 1 +2110 7 +938 10 +2953 3 +2375 9 +2152 10 +2116 7 +3214 1 +3381 9 +3935 9 +749 10 +93 5 +375 2 +3235 7 +2273 5 +661 6 +1081 6 +2591 10 +2980 4 +3576 9 +2685 6 +89 7 +3791 5 +1324 3 +799 7 +3817 2 +3597 8 +2069 8 +1208 5 +181 9 +2470 4 +305 3 +3769 7 +684 7 +3530 1 +3045 6 +1786 10 +2674 10 +3354 3 +1024 7 +3725 10 +2067 4 +3786 6 +2834 3 +1481 9 +1026 8 +433 6 +891 9 +2960 9 +2241 2 +3283 10 +3755 5 +3801 2 +2694 8 +2519 8 +3572 8 +929 8 +1920 1 +1490 6 +2965 10 +2134 6 +4094 9 +1676 6 +3291 2 +1468 6 +2697 4 +2374 2 +2226 10 +3168 1 +1341 10 +2267 5 +383 8 +1830 9 +516 5 +3775 6 +2244 5 +1994 8 +322 10 +931 4 +1239 1 +3771 3 +1065 3 +2158 1 +302 9 +1232 2 +27 5 +2198 5 +1175 3 +259 7 +1041 6 +441 9 +2057 6 +4025 7 +2997 6 +2612 3 +1795 10 +1736 6 +470 8 +2139 10 +2292 5 +3877 5 +2182 9 +522 6 +414 4 +3480 9 +2813 6 +3846 9 +2364 8 +3167 1 +3545 5 +91 10 +3297 3 +1043 5 +1361 6 +3509 10 +169 6 +487 9 +4011 2 +2829 3 +2796 7 +834 7 +1501 6 +2302 2 +678 3 +406 5 +2282 9 +1730 10 +3180 7 +2823 9 +1364 2 +2150 1 +568 9 +504 10 +3665 1 +667 1 +2582 8 +3717 9 +1298 4 +3866 6 +2818 8 +2768 5 +1045 6 +3522 3 +1155 5 +2573 7 +4050 4 +1652 1 +1452 5 +436 5 +3847 3 +3607 4 +3792 10 +97 4 +1770 3 +1013 2 +1344 7 +522 2 +2092 10 +920 10 +22 4 +1869 5 +2956 3 +963 7 +783 7 +612 1 +1417 10 +2938 2 +2513 1 +3969 8 +1965 8 +3341 3 +963 6 +2776 2 +776 6 +3961 10 +1083 5 +352 1 +2796 2 +2380 3 +3073 1 +1922 8 +3254 4 +1611 1 +2675 9 +2014 9 +1642 6 +209 2 +1987 4 +3961 2 +2989 4 +228 2 +3609 6 +3115 2 +1281 10 +1868 7 +3282 9 +105 5 +2738 3 +2689 10 +1562 5 +787 3 +287 6 +1355 1 +2487 4 +2232 8 +444 8 +2134 5 +1247 8 +1801 3 +2057 1 +1704 2 +3722 8 +3354 6 +3517 7 +1958 8 +2941 5 +341 4 +842 6 +648 9 +3942 8 +3992 1 +3825 3 +2476 9 +3122 9 +2830 9 +3434 10 +3584 6 +1944 5 +1334 5 +2300 9 +676 7 +744 7 +3021 8 +868 8 +2813 4 +82 9 +492 1 +1642 1 +3024 1 +2654 5 +727 8 +3168 1 +930 7 +2031 1 +1202 6 +1500 9 +1101 4 +1638 8 +2348 8 +1172 3 +1112 9 +1455 10 +361 7 +169 5 +2766 8 +1046 2 +3022 5 +3446 4 +2985 2 +2579 6 +1243 8 +2563 9 +3524 9 +1332 3 +872 5 +3511 7 +3603 7 +67 1 +3095 2 +1451 6 +2152 9 +1188 6 +155 1 +2701 10 +2184 9 +1547 7 +3630 1 +111 9 +1875 5 +1778 8 +789 9 +1594 5 +2222 2 +682 7 +25 3 +1114 7 +3784 10 +1524 10 +2182 9 +1933 8 +2809 3 +1038 9 +1370 5 +1205 9 +435 10 +3227 7 +1956 9 +1989 8 +3017 10 +1766 5 +19 3 +3860 5 +1692 10 +1392 5 +1466 6 +536 2 +3076 2 +682 6 +123 7 +1928 10 +1195 5 +1706 10 +1416 3 +2377 3 +2701 2 +2497 4 +2006 4 +4042 7 +3047 10 +2885 4 +787 5 +3125 10 +3153 1 +2396 8 +4022 2 +68 3 +471 9 +1151 2 +2424 10 +2315 10 +2647 6 +923 7 +1568 3 +1455 3 +1732 2 +1619 8 +2236 10 +3652 2 +921 3 +435 6 +520 8 +3827 10 +3811 9 +1808 2 +3463 1 +2904 1 +46 6 +3775 9 +1976 7 +1712 4 +180 2 +3792 4 +20 1 +217 4 +1728 2 +1379 6 +2227 7 +319 8 +4018 6 +672 5 +1396 6 +3473 8 +899 9 +801 2 +1054 10 +2683 10 +2972 4 +1341 2 +1574 2 +2958 9 +670 6 +2150 5 +3907 8 +2075 6 +209 3 +222 6 +1025 1 +1429 8 +1835 2 +138 10 +1879 10 +3717 2 +954 10 +1109 2 +1252 7 +2263 9 +1175 3 +2932 7 +1711 3 +2417 8 +2768 3 +3771 3 +60 5 +636 9 +4044 10 +3915 7 +3548 3 +1739 9 +3539 1 +996 10 +3690 2 +200 1 +944 3 +1825 2 +2821 1 +1539 3 +3258 4 +2918 2 +3429 5 +1695 6 +3019 7 +888 5 +1786 4 +1168 10 +2416 4 +930 9 +3907 1 +784 8 +1125 6 +3627 3 +1924 6 +100 1 +505 8 +1406 10 +1392 1 +2097 3 +1945 2 +3977 9 +3696 1 +3151 6 +1128 8 +1013 8 +3398 10 +3087 1 +3777 3 +1149 8 +463 6 +2299 6 +324 5 +1905 4 +2079 4 +3758 1 +900 4 +2406 7 +1115 9 +19 9 +502 6 +1055 4 +1612 6 +3175 10 +502 10 +952 2 +1090 10 +3677 8 +2921 3 +201 10 +934 2 +687 1 +697 6 +658 10 +1937 9 +1498 6 +3684 5 +2529 7 +2345 6 +2650 5 +756 9 +3051 7 +1827 5 +2805 3 +429 3 +1311 2 +1630 1 +906 10 +3972 2 +2267 9 +2787 3 +2854 8 +969 8 +3208 5 +1617 7 +1257 2 +2686 1 +3185 1 +624 4 +2806 1 +3 9 +2281 10 +1088 7 +3706 8 +86 3 +2751 6 +419 8 +934 4 +735 7 +1050 4 +2650 8 +2974 7 +3507 2 +3378 3 +655 3 +3938 10 +3890 5 +2810 6 +107 1 +402 10 +102 3 +2569 10 +1917 4 +2016 8 +484 1 +849 7 +2184 2 +2664 2 +1443 1 +620 5 +232 7 +1912 2 +3987 3 +2452 10 +1971 3 +3443 3 +1406 3 +1527 8 +3127 9 +3006 2 +1573 8 +2734 6 +2642 6 +3673 4 +3856 7 +1311 9 +3227 3 +2793 10 +104 9 +275 4 +3607 6 +236 10 +1099 5 +2699 9 +1543 3 +3014 4 +2147 10 +263 5 +2195 7 +2457 1 +3089 9 +633 7 +5 8 +1026 7 +1727 6 +3000 7 +2407 7 +2481 4 +969 1 +790 4 +2650 8 +2250 6 +3364 4 +2342 6 +2125 1 +3487 5 +3962 8 +775 10 +120 3 +2409 7 +1693 1 +730 7 +2123 3 +1081 3 +3430 7 +1039 1 +136 5 +1774 1 +1909 6 +3608 2 +2798 9 +2919 10 +1248 10 +3346 3 +1630 4 +2171 8 +3063 10 +2248 7 +446 3 +1885 5 +2906 9 +840 2 +3376 5 +950 7 +1795 7 +3019 7 +3991 5 +3399 2 +2402 8 +1872 9 +2271 9 +2391 4 +3594 3 +3902 1 +2192 10 +759 2 +2296 7 +1765 10 +380 10 +3552 2 +2086 2 +500 9 +1761 10 +3501 4 +3029 1 +89 4 +1115 7 +1058 10 +189 9 +3543 9 +2984 10 +4076 3 +3110 5 +469 4 +736 5 +3463 1 +2013 10 +3046 4 +3498 2 +1238 1 +522 1 +2127 8 +978 4 +729 1 +377 3 +386 7 +1383 9 +2361 4 +2909 3 +2145 2 +1077 10 +2420 9 +1968 5 +2732 6 +3160 9 +1420 7 +1166 4 +3797 4 +3500 1 +1842 5 +3906 4 +1545 1 +659 7 +1255 8 +2148 5 +2412 5 +4032 9 +3519 7 +2829 3 +3433 4 +1189 8 +2520 9 +699 10 +2471 1 +1493 5 +3088 5 +672 9 +2447 10 +2021 10 +3618 1 +427 8 +1215 8 +1756 1 +1354 8 +1478 4 +991 3 +586 10 +3611 2 +2232 7 +3246 3 +3589 5 +2253 1 +1119 3 +781 1 +2485 6 +2108 7 +3947 10 +2229 6 +868 1 +2127 8 +2896 3 +920 7 +4081 4 +3772 5 +568 6 +1216 3 +3173 4 +1450 3 +4033 1 +2249 1 +3957 10 +3035 1 +1729 1 +3325 5 +1007 10 +2506 3 +3994 2 +823 5 +3192 6 +86 3 +386 3 +4008 1 +2620 4 +1866 2 +3206 3 +3073 10 +825 1 +35 8 +2494 7 +1293 10 +3960 2 +1139 4 +2794 1 +33 6 +115 4 +957 5 +293 3 +2879 8 +309 6 +2931 1 +2406 4 +97 8 +2860 8 +1381 1 +3990 5 +1016 4 +1753 3 +871 4 +3896 7 +930 5 +1331 10 +223 3 +1192 9 +1507 4 +3316 9 +2379 4 +803 1 +1127 3 +2200 9 +1403 2 +3959 9 +926 6 +1050 1 +3988 7 +245 3 +3801 7 +2001 9 +516 6 +1583 8 +3727 7 +1131 5 +722 1 +181 6 +3062 2 +2831 9 +75 3 +1255 4 +2148 5 +573 9 +1622 1 +3778 8 +765 8 +1693 4 +758 4 +2215 9 +2774 2 +2932 1 +1038 10 +992 9 +1914 2 +1493 7 +713 10 +1508 6 +3977 8 +3845 8 +895 10 +2137 3 +1989 6 +3691 7 +1555 4 +2778 4 +1204 3 +2078 8 +2235 9 +956 5 +3698 10 +1343 8 +3365 5 +644 10 +4054 8 +2758 8 +1965 6 +857 6 +1702 9 +2673 2 +1519 8 +1494 4 +747 3 +631 1 +2729 9 +859 7 +1461 7 +3917 1 +2298 10 +3868 4 +1318 10 +2140 5 +2033 7 +1176 8 +2504 1 +2810 4 +2413 8 +1947 7 +3616 10 +2610 4 +738 2 +3708 8 +1749 5 +807 1 +412 6 +562 4 +1296 2 +666 1 +3297 10 +3071 1 +3072 10 +1305 7 +492 9 +88 10 +253 10 +2293 7 +3578 9 +3010 3 +1103 6 +806 2 +1956 8 +1767 7 +3676 9 +3808 10 +1456 10 +1549 1 +3459 6 +2544 6 +3331 5 +3148 4 +3730 1 +1873 2 +3367 2 +14 4 +1136 7 +3946 9 +1644 3 +2633 6 +4002 3 +930 3 +4034 7 +3655 4 +2217 10 +1375 8 +848 8 +2156 9 +1357 10 +2487 10 +818 7 +2854 5 +338 2 +1786 7 +48 10 +952 6 +478 2 +4026 5 +2973 1 +2365 10 +1676 3 +101 9 +3287 10 +3129 1 +50 6 +2367 5 +329 7 +2130 1 +3216 8 +2411 9 +718 9 +119 9 +1261 2 +2742 4 +2537 7 +2015 3 +568 9 +1695 1 +1033 4 +1387 1 +377 2 +769 9 +3557 7 +3682 4 +2298 10 +2092 8 +2861 9 +4058 9 +3866 8 +2392 5 +730 5 +1367 4 +1270 6 +1394 4 +1280 7 +3716 9 +3628 2 +3724 3 +2152 5 +3150 7 +1816 4 +3361 7 +3881 2 +2687 3 +1196 8 +520 1 +1285 5 +122 3 +1325 8 +2277 7 +1756 2 +1950 4 +943 5 +3063 9 +3271 5 +667 1 +1585 4 +1869 6 +3748 1 +1021 4 +2974 2 +3761 4 +2004 6 +2236 7 +103 4 +3308 3 +3345 7 +1268 9 +3402 9 +2054 5 +3611 7 +1457 8 +2644 5 +3963 1 +460 1 +4003 5 +1750 4 +772 8 +148 2 +543 9 +3123 5 +1880 10 +2289 10 +3171 10 +2273 10 +3375 3 +2209 6 +2851 2 +1316 3 +3785 6 +3668 8 +678 4 +3604 7 +3133 10 +1967 5 +254 6 +2175 9 +2619 10 +3425 8 +1921 2 +1895 7 +2781 7 +747 5 +3027 8 +1582 10 +2156 2 +1705 2 +142 10 +2922 9 +87 9 +2535 6 +2624 3 +2596 3 +3152 3 +1758 1 +1642 5 +1274 5 +2318 3 +2609 9 +1795 10 +993 8 +839 7 +700 10 +2971 2 +3278 1 +3266 1 +2900 4 +1841 5 +2338 4 +2353 7 +2718 8 +2117 4 +955 7 +1663 2 +2930 8 +1405 8 +1751 1 +1847 5 +2888 5 +619 2 +1495 10 +1827 3 +2583 4 +4059 2 +2441 10 +471 8 +3001 5 +489 6 +2922 8 +3143 1 +1190 9 +235 1 +3849 8 +1391 9 +2917 8 +3836 9 +3760 3 +878 4 +1067 9 +3887 7 +2617 9 +2885 6 +1647 5 +776 9 +1986 9 +2081 1 +3772 4 +2516 3 +2760 10 +65 9 +942 2 +223 9 +3817 9 +977 7 +1654 5 +2963 7 +2599 7 +1756 8 +1715 10 +947 2 +1532 6 +65 6 +3133 10 +583 4 +2094 4 +724 9 +2191 10 +1467 10 +3013 9 +1477 3 +382 9 +1461 1 +3658 7 +2626 9 +3200 1 +3371 6 +4079 5 +3058 3 +605 6 +2811 7 +3553 1 +1942 7 +3466 4 +940 7 +660 8 +2888 5 +3090 6 +1810 2 +2963 1 +3239 7 +2303 3 +1670 10 +496 7 +211 3 +1320 5 +3672 10 +2720 2 +3976 4 +1718 7 +3166 5 +3829 1 +215 6 +2918 9 +472 10 +2736 2 +794 1 +2494 1 +1493 3 +261 6 +1956 3 +146 6 +928 9 +3493 10 +2533 8 +1941 9 +2098 1 +4090 2 +1157 5 +3283 5 +2744 1 +1239 9 +3837 2 +1011 2 +1635 5 +30 9 +1449 5 +3137 2 +3188 8 +3621 6 +1270 9 +148 9 +1486 8 +3255 1 +1833 8 +3170 5 +1359 3 +3614 6 +926 8 +3692 6 +174 8 +3870 8 +3559 9 +1444 3 +1781 8 +994 2 +839 3 +1880 6 +3972 4 +1959 4 +1299 7 +3647 2 +2337 1 +1985 4 +1648 7 +705 1 +1994 6 +1005 5 +811 1 +3310 7 +464 5 +424 6 +385 10 +653 5 +1669 3 +3109 4 +875 8 +1144 2 +954 10 +1703 5 +327 1 +3600 8 +3006 1 +519 6 +1298 8 +3093 5 +1932 3 +1953 7 +10 6 +3606 1 +2383 3 +2947 9 +3537 3 +2803 7 +2514 4 +775 5 +3214 4 +1961 8 +366 3 +1582 9 +1287 6 +2457 3 +1072 2 +2354 4 +2110 3 +1718 8 +1585 6 +3362 7 +875 1 +114 3 +179 6 +174 4 +1479 3 +2347 7 +1574 6 +131 8 +2819 1 +4066 6 +554 5 +3660 1 +3713 8 +1722 4 +2032 7 +4040 4 +2327 1 +3218 9 +2304 4 +1208 2 +1272 7 +3973 2 +2546 8 +1244 7 +167 10 +1252 9 +4012 8 +1738 4 +3182 2 +3331 7 +1971 5 +2011 2 +60 7 +2230 6 +311 9 +3097 3 +3544 1 +396 1 +1450 5 +1281 9 +3761 1 +1315 8 +775 8 +3120 7 +683 1 +2369 7 +245 4 +40 1 +3887 5 +648 6 +3911 8 +1811 9 +2978 10 +2214 6 +1200 3 +662 10 +3517 5 +1484 9 +2694 1 +1649 4 +3097 1 +3759 7 +3353 7 +2757 5 +2043 8 +2335 7 +2178 8 +266 5 +2378 3 +3650 3 +3902 10 +3780 2 +442 3 +1348 5 +3576 4 +3674 1 +5 6 +2134 10 +525 1 +2398 8 +667 6 +1302 3 +2670 4 +3730 7 +3069 1 +1588 8 +2017 3 +3600 5 +847 1 +1333 5 +167 7 +1901 7 +3950 6 +1703 2 +2472 10 +2305 7 +3644 10 +838 9 +3468 2 +1665 7 +1863 2 +2069 10 +803 1 +2941 10 +3930 6 +1134 3 +112 4 +1901 7 +2829 9 +4032 2 +3564 7 +2334 4 +860 3 +549 1 +1721 5 +2537 1 +2876 7 +93 1 +2836 5 +2078 3 +70 5 +722 3 +623 1 +3732 8 +2760 8 +3092 8 +3557 5 +1105 7 +2407 1 +2697 7 +3798 6 +1644 9 +1985 8 +3751 6 +3006 3 +28 9 +2503 3 +3489 10 +14 5 +2102 7 +2773 7 +835 5 +858 7 +3046 6 +2470 7 +2434 4 +784 8 +2623 8 +1409 9 +1491 6 +1584 4 +477 7 +3550 2 +3638 7 +3988 7 +970 8 +1608 4 +2364 3 +2241 4 +3477 3 +3306 1 +1007 9 +3152 7 +1584 1 +1692 1 +3136 7 +1298 9 +1255 1 +1786 3 +300 7 +3535 9 +910 8 +3595 3 +826 1 +2153 8 +556 6 +1466 8 +2361 3 +3294 7 +1322 2 +2067 8 +252 9 +1180 7 +2591 9 +1597 7 +2285 10 +1746 10 +1650 7 +549 2 +626 8 +3492 6 +331 5 +2286 5 +3405 7 +2605 10 +3475 7 +4 10 +2768 8 +1310 6 +1797 3 +589 3 +1515 5 +3233 9 +2344 7 +2541 2 +1787 7 +4045 7 +2420 1 +1966 4 +1472 2 +1069 1 +1283 7 +858 7 +596 4 +976 10 +1710 7 +333 1 +1013 7 +4034 1 +539 7 +4080 5 +3437 8 +2147 2 +159 6 +2971 3 +2139 9 +1591 8 +53 6 +2390 5 +1148 4 +2909 2 +1482 3 +3832 4 +525 2 +2189 3 +2575 4 +1690 7 +3861 10 +3784 7 +1114 4 +2781 2 +1732 8 +128 6 +1399 2 +3284 2 +2348 3 +3542 9 +1330 9 +1386 4 +1547 7 +2263 4 +1135 6 +1884 1 +3998 5 +1497 7 +2167 3 +368 1 +2138 3 +4037 5 +2597 9 +2724 3 +2630 4 +1723 1 +1748 8 +2450 2 +3249 4 +1424 1 +3584 8 +4089 8 +2332 3 +2750 2 +1749 4 +3349 2 +1757 2 +519 5 +638 10 +294 7 +368 3 +3166 8 +1629 3 +1503 10 +3487 6 +2064 8 +3065 8 +745 5 +291 7 +3601 6 +1104 1 +3720 10 +2689 8 +639 9 +637 10 +3459 6 +684 5 +157 1 +2870 2 +3527 10 +2917 4 +808 8 +3481 3 +3827 7 +2632 10 +1721 7 +3048 8 +680 1 +80 8 +439 2 +2997 9 +2375 5 +3000 7 +23 3 +1671 6 +1170 5 +2412 4 +1315 3 +1559 5 +3466 3 +128 9 +2235 4 +1234 8 +130 7 +2290 5 +1172 3 +988 4 +3293 6 +3955 5 +3742 2 +3341 5 +1981 3 +3863 1 +1455 5 +3057 2 +2747 2 +894 10 +506 9 +3800 3 +3837 1 +3078 5 +1080 2 +2605 8 +2867 3 +2190 8 +3406 10 +1964 3 +1570 3 +3135 6 +273 2 +3114 8 +556 9 +3506 8 +3403 4 +1560 3 +1661 2 +2350 8 +401 2 +800 10 +3005 1 +3493 1 +1726 2 +3423 10 +2471 7 +2887 5 +3444 8 +3666 6 +315 5 +1658 6 +1531 8 +1046 8 +3627 6 +3978 7 +3622 4 +1222 3 +2234 8 +2044 3 +178 2 +783 10 +1162 4 +3791 1 +2718 2 +3112 9 +2532 1 +1030 5 +1084 6 +805 10 +4067 2 +2768 2 +1309 5 +3937 1 +3020 3 +3393 5 +2259 4 +2650 2 +2210 7 +3125 1 +2915 6 +2796 9 +2357 1 +2228 7 +3486 3 +1937 6 +2562 7 +2534 5 +3545 9 +390 8 +695 7 +320 10 +2230 7 +764 4 +1925 6 +2854 7 +1803 7 +2432 5 +44 6 +763 9 +1233 9 +3689 4 +2286 9 +1247 3 +2391 4 +3349 6 +541 3 +3030 5 +2707 9 +2244 5 +2029 7 +3454 3 +1038 6 +2677 7 +3681 6 +2450 6 +2275 8 +1788 6 +3029 6 +2 3 +3667 1 +2126 5 +310 9 +1042 9 +4090 8 +3951 6 +3556 6 +3841 8 +3691 7 +1078 4 +1289 9 +2909 2 +2206 4 +3091 1 +1624 9 +1681 4 +437 8 +3112 9 +2679 9 +921 7 +1320 7 +2201 8 +425 7 +2930 2 +67 6 +1225 9 +933 5 +3952 5 +3123 1 +615 7 +3958 7 +1579 4 +3453 6 +944 7 +1351 1 +537 3 +1799 4 +2370 1 +2540 7 +1640 9 +3705 3 +1689 1 +302 3 +255 9 +613 2 +2241 9 +465 2 +1907 7 +251 1 +3398 6 +3306 7 +2646 9 +3697 7 +2996 10 +1177 6 +2513 5 +573 2 +383 9 +1723 6 +2759 2 +1603 1 +1701 10 +1969 2 +3900 2 +2828 4 +696 7 +2191 10 +3280 7 +3241 6 +1950 9 +0 1 +3352 5 +3994 8 +2041 4 +1157 10 +1108 1 +1533 5 +3628 6 +402 6 +377 6 +3321 4 +1876 7 +2851 8 +2439 8 +2134 5 +1246 1 +2580 1 +254 3 +276 9 +1739 1 +2001 8 +1303 8 +3666 3 +43 5 +350 9 +1619 1 +2449 3 +3991 4 +3133 4 +2754 2 +2808 2 +1103 7 +1933 1 +66 8 +3431 3 +1685 4 +781 10 +615 5 +1513 5 +230 1 +395 4 +2410 5 +3608 6 +2031 6 +3742 3 +868 2 +1367 6 +3929 6 +714 1 +1885 7 +3334 5 +334 5 +1331 4 +3245 5 +2617 1 +2360 4 +692 6 +2537 1 +2088 2 +2656 9 +607 2 +2924 1 +2619 6 +3043 4 +278 6 +1781 2 +1913 5 +1933 5 +2976 8 +3063 6 +1946 6 +608 6 +1187 7 +4070 8 +199 4 +1766 8 +455 6 +2961 1 +581 8 +2428 8 +3609 7 +3068 5 +3723 10 +3046 9 +227 7 +523 2 +1078 4 +2307 10 +513 8 +3658 1 +2901 4 +34 8 +2467 1 +2915 8 +3072 7 +3147 10 +1228 8 +1023 7 +2446 4 +1128 5 +398 3 +4016 5 +305 5 +274 2 +1020 5 +1036 4 +3663 10 +3575 10 +1579 2 +1479 6 +3604 2 +2575 3 +716 4 +2443 4 +1533 5 +3364 8 +66 2 +2500 3 +3487 9 +2246 10 +150 7 +4006 9 +4040 4 +2430 3 +4087 9 +1824 4 +11 4 +3395 6 +1865 7 +2906 6 +1713 5 +3445 1 +3127 5 +2756 6 +2413 6 +340 1 +3958 4 +2097 10 +428 5 +2381 2 +1517 10 +1242 10 +1686 6 +1966 1 +3688 3 +2135 7 +2223 10 +1379 8 +3244 3 +3215 7 +3005 4 +790 1 +1388 7 +391 7 +2936 9 +1950 7 +1586 3 +210 1 +1433 1 +3135 8 +1670 1 +1243 3 +1335 5 +163 6 +1191 5 +3350 7 +213 6 +4045 9 +3476 10 +462 9 +3248 4 +3436 3 +1127 6 +1658 5 +1347 4 +2932 5 +2007 10 +1002 6 +1304 3 +2334 3 +192 2 +1257 9 +2227 1 +3308 1 +2814 3 +305 3 +4038 7 +2605 8 +209 7 +1887 7 +3522 1 +2492 4 +3894 7 +3459 6 +3142 10 +3991 1 +3256 3 +220 2 +1541 3 +2844 3 +3940 1 +3425 6 +1313 4 +2499 5 +3559 9 +343 2 +3789 5 +3440 10 +708 10 +1613 5 +4054 10 +729 10 +2120 4 +1730 6 +2600 10 +786 1 +3192 9 +3450 4 +2610 6 +1284 6 +37 5 +2563 4 +2821 6 +2018 1 +1970 4 +3072 10 +1158 6 +904 10 +936 4 +1861 1 +1580 8 +2758 6 +1760 2 +1345 8 +2884 1 +2442 1 +3824 6 +323 3 +3813 10 +3198 2 +3754 10 +3437 6 +3739 5 +3834 8 +2605 10 +2936 2 +1880 5 +3439 3 +2012 2 +2602 9 +2743 6 +1670 7 +1107 9 +577 8 +1446 6 +1641 8 +4044 8 +1785 10 +4063 3 +963 3 +2360 7 +2143 4 +631 5 +2770 8 +2246 1 +2591 7 +1715 7 +2399 7 +865 3 +248 10 +2736 4 +3382 2 +2004 10 +2353 10 +3988 7 +461 4 +3776 6 +3037 8 +3479 2 +2953 9 +431 5 +3361 9 +2087 6 +829 5 +1176 5 +1509 1 +64 9 +1950 6 +70 5 +2499 10 +1530 9 +3704 8 +2965 1 +1674 5 +541 6 +2724 1 +614 1 +2173 9 +528 9 +750 5 +2849 5 +4054 6 +2821 7 +2071 3 +3121 9 +3567 1 +2906 5 +2923 9 +854 6 +3856 3 +782 4 +531 3 +36 10 +1231 4 +1810 3 +3397 8 +3603 2 +3463 4 +1604 1 +3527 9 +3197 3 +1486 10 +2829 5 +4009 1 +1532 7 +1175 9 +2229 4 +758 10 +1525 6 +3036 3 +1694 3 +999 1 +1823 4 +913 8 +3362 6 +2952 9 +3089 7 +753 10 +2687 7 +1754 7 +1881 1 +1237 6 +3456 10 +3011 4 +3430 6 +31 6 +951 9 +3084 8 +2250 6 +448 6 +3423 4 +2852 5 +2908 9 +4023 3 +3381 8 +4050 7 +747 3 +749 6 +1208 9 +2120 4 +2983 2 +446 4 +262 9 +2805 5 +857 8 +2171 4 +1242 8 +3981 7 +2653 6 +2283 10 +1543 10 +23 1 +1594 5 +4005 5 +1599 5 +2883 3 +3549 2 +460 5 +1017 2 +2773 8 +1935 1 +2083 8 +125 6 +1009 7 +2563 1 +254 1 +2960 10 +2676 1 +1954 10 +3727 5 +1390 6 +2767 6 +1238 8 +1064 5 +3526 5 +3394 4 +2459 4 +3292 8 +557 4 +1915 2 +2885 4 +522 5 +1848 5 +2737 3 +3946 7 +1737 5 +2257 7 +3592 4 +2320 1 +3302 10 +3434 4 +3461 7 +3007 8 +2558 10 +1675 5 +2523 1 +723 7 +3009 5 +1337 3 +3338 7 +1106 5 +2530 5 +2830 4 +2189 4 +74 10 +3974 10 +802 6 +3327 9 +982 1 +3260 3 +1319 1 +1198 6 +658 2 +2103 5 +4028 8 +47 4 +3675 2 +3015 10 +2475 10 +2789 1 +3871 8 +4089 6 +2461 5 +63 1 +1527 8 +1007 8 +3740 6 +2447 3 +3136 4 +1291 2 +975 6 +114 8 +3956 1 +1561 2 +1581 5 +3008 1 +862 5 +3916 9 +2829 2 +3533 9 +859 5 +3800 5 +2568 3 +1853 3 +1491 9 +2359 3 +2750 2 +2781 10 +2605 9 +2696 4 +2885 10 +976 8 +205 5 +1297 9 +2274 1 +1614 8 +1070 1 +780 7 +2903 3 +2126 3 +2811 8 +2572 3 +403 4 +541 3 +3383 2 +596 3 +3481 3 +794 7 +2605 7 +2808 9 +2253 3 +57 5 +3523 9 +649 9 +305 3 +3719 2 +2525 9 +3789 4 +1490 2 +3408 1 +825 4 +1038 4 +752 6 +597 4 +631 8 +3349 5 +3790 6 +3775 6 +393 7 +871 3 +1862 10 +2850 7 +1909 4 +3082 7 +670 4 +191 7 +1737 3 +639 2 +4018 8 +1718 8 +311 7 +4081 7 +176 10 +92 9 +849 2 +3130 5 +1542 9 +2422 5 +3978 9 +2606 3 +2164 1 +2940 10 +1223 8 +1207 7 +2067 4 +1123 6 +1777 1 +1010 4 +2333 4 +3535 1 +1159 2 +3640 10 +3455 10 +870 3 +1666 10 +4002 4 +3374 7 +574 9 +794 10 +1852 1 +3033 9 +3344 7 +1505 9 +1418 7 +1254 2 +1426 6 +1210 5 +1344 7 +3439 2 +190 6 +2310 3 +3417 1 +3218 1 +3767 3 +2740 3 +3469 5 +1222 2 +2083 5 +1295 9 +380 1 +4024 2 +2008 7 +2146 8 +42 3 +742 5 +2040 3 +258 5 +3952 7 +2113 9 +2801 4 +2245 9 +2645 4 +406 10 +11 1 +3805 8 +4021 1 +3852 1 +4009 9 +1355 7 +681 2 +3999 1 +3860 7 +3918 2 +1491 1 +879 3 +79 8 +2761 1 +2495 1 +3212 9 +1934 8 +2688 6 +225 1 +3301 1 +3774 5 +1241 2 +1866 9 +1305 7 +802 6 +873 2 +1863 6 +181 9 +2133 10 +963 4 +2507 9 +3048 10 +10 4 +3178 8 +1307 6 +3644 6 +3295 4 +3342 1 +612 7 +1626 4 +3110 4 +1001 9 +3538 8 +3001 3 +1299 9 +3974 4 +1072 4 +3947 10 +1275 6 +883 2 +1872 8 +2996 8 +1726 1 +2986 9 +3383 10 +3697 10 +2214 7 +1144 1 +3011 10 +122 6 +1989 4 +253 2 +3604 2 +436 7 +3439 9 +3014 9 +1132 5 +2497 5 +1760 7 +3698 5 +3682 8 +2715 8 +2697 6 +2802 3 +274 3 +1324 8 +1397 8 +443 5 +1475 9 +3836 5 +1105 2 +2007 3 +1085 9 +1553 4 +2404 1 +582 6 +955 8 +523 1 +3553 9 +2322 8 +1896 7 +151 8 +2408 5 +1242 2 +3562 4 +1487 4 +1034 4 +1626 2 +1391 6 +341 3 +382 8 +2302 6 +612 8 +2868 8 +3886 9 +564 5 +30 10 +3082 1 +3902 10 +2355 1 +2595 5 +1375 10 +432 10 +2434 1 +2049 2 +3927 6 +2082 10 +3262 6 +2287 7 +1298 8 +2777 8 +2651 9 +2951 8 +1161 7 +0 2 +2067 9 +1207 9 +933 9 +3419 6 +1057 6 +1544 9 +3706 1 +1799 3 +2420 7 +1256 3 +2686 6 +940 1 +3258 2 +3531 9 +2370 2 +2615 3 +409 3 +3640 1 +170 1 +918 3 +1854 3 +3581 5 +1183 7 +139 10 +2701 5 +3094 8 +2015 8 +2730 10 +3635 8 +3753 1 +1954 8 +2684 3 +874 7 +2279 6 +1426 4 +1043 8 +555 9 +1957 7 +529 2 +150 5 +3874 6 +1143 4 +3684 9 +990 2 +2689 5 +3365 7 +1868 1 +3312 1 +924 6 +2338 8 +502 2 +1681 9 +3819 8 +784 10 +3578 6 +3793 8 +3022 2 +3336 1 +330 3 +1699 1 +1706 3 +467 5 +3085 5 +1614 8 +850 5 +729 5 +1346 9 +2587 9 +3329 8 +931 7 +3438 9 +94 2 +414 10 +1055 9 +2744 9 +2746 3 +3793 3 +3996 3 +459 3 +1391 1 +421 3 +2880 5 +3881 4 +306 6 +3279 6 +238 8 +2838 8 +202 1 +1912 8 +783 10 +1079 8 +3410 3 +3103 3 +780 8 +1387 9 +3247 5 +441 7 +3453 1 +229 10 +4071 5 +351 3 +1242 6 +4071 5 +284 5 +2495 10 +3582 6 +193 7 +3878 7 +1835 7 +3920 10 +366 3 +161 8 +3202 7 +1568 9 +509 3 +2408 7 +1331 5 +1072 4 +3296 8 +2598 2 +759 10 +2490 1 +2180 9 +1852 5 +2030 8 +2465 4 +1911 5 +3244 3 +2681 3 +717 7 +2784 4 +3661 9 +3235 8 +2862 1 +1307 9 +334 1 +1703 4 +106 9 +243 6 +549 4 +1384 1 +339 4 +3729 10 +848 1 +104 7 +1213 6 +2601 5 +1153 4 +1457 2 +126 7 +1842 8 +2111 2 +1553 4 +433 8 +1721 7 +893 9 +2502 3 +4031 7 +3887 2 +3853 6 +3518 8 +1580 8 +1625 9 +3938 1 +2220 10 +1079 6 +3787 4 +3303 4 +3085 2 +1625 4 +4088 9 +147 4 +1678 8 +438 2 +28 6 +2776 6 +3305 10 +55 6 +3237 8 +468 6 +2505 3 +168 5 +2744 7 +3060 5 +1359 7 +1126 5 +1796 2 +3179 2 +2160 7 +2788 6 +741 5 +2774 3 +2626 5 +1023 1 +326 9 +1254 5 +729 7 +497 10 +1630 5 +2799 7 +2377 4 +584 8 +2909 3 +2738 8 +3993 9 +1646 8 +2446 3 +1681 9 +2129 3 +1006 9 +873 4 +2022 7 +3591 10 +3020 6 +1004 8 +122 10 +2016 6 +951 3 +3229 3 +891 1 +1945 5 +2096 6 +3140 8 +146 5 +1885 10 +430 1 +2179 6 +1376 2 +3049 8 +3672 7 +4058 5 +1300 6 +2697 4 +481 3 +1491 5 +3664 2 +2914 6 +2428 1 +2025 10 +3740 5 +3495 5 +3522 6 +204 4 +1433 9 +3559 5 +3491 8 +775 9 +163 8 +4026 3 +1105 2 +2158 8 +2307 4 +3052 8 +1218 7 +1409 9 +2749 3 +1983 5 +3082 1 +2100 9 +410 8 +3202 2 +2886 2 +2837 5 +2042 6 +1712 9 +1585 7 +831 10 +141 7 +1485 4 +1380 8 +3328 4 +2552 9 +3442 10 +28 4 +3295 5 +448 7 +716 5 +3798 7 +916 8 +4084 7 +617 5 +4088 2 +1303 2 +230 5 +189 2 +2141 10 +2471 7 +3445 7 +3267 9 +3805 2 +1588 9 +113 9 +2365 9 +189 1 +156 5 +3652 10 +3773 8 +67 1 +249 6 +573 7 +3179 8 +4062 5 +2733 6 +1974 9 +3021 9 +3017 5 +279 3 +3550 4 +923 8 +2035 8 +395 4 +4089 8 +2537 5 +1923 6 +890 5 +1996 4 +3414 7 +2303 3 +1100 2 +1671 4 +1092 2 +466 6 +2381 9 +3742 1 +1047 7 +1071 3 +4085 9 +3150 4 +2563 2 +595 2 +3896 8 +3174 8 +3984 2 +1752 10 +531 7 +73 7 +1139 7 +2312 7 +263 8 +1994 10 +1441 9 +2464 10 +2079 4 +3827 8 +820 2 +3448 10 +148 1 +3872 9 +3197 6 +680 9 +3229 3 +1794 8 +3952 6 +3950 6 +2566 5 +2126 4 +1666 2 +3131 2 +2469 9 +2005 3 +1953 3 +3515 2 +1273 6 +648 8 +1925 10 +1655 10 +1907 2 +3675 6 +811 6 +779 2 +1842 1 +2046 1 +3744 3 +1956 8 +529 5 +3925 6 +2731 10 +3582 7 +843 4 +3598 7 +944 6 +879 5 +1180 5 +542 6 +3156 4 +2067 3 +411 10 +1626 6 +3324 5 +4093 7 +2506 7 +2458 8 +2468 10 +2396 8 +2503 9 +2367 10 +3787 6 +2803 2 +4077 2 +1523 5 +2728 1 +446 6 +2513 3 +3613 10 +1775 2 +3457 3 +3930 4 +1573 1 +2969 2 +863 8 +3207 2 +1758 5 +3306 4 +3130 2 +1330 7 +3733 4 +2304 9 +58 6 +1102 10 +2276 4 +1318 10 +72 8 +1817 9 +1224 2 +2639 1 +451 9 +401 9 +2464 6 +560 9 +1965 4 +287 10 +1940 7 +24 6 +1946 10 +3108 9 +778 7 +1854 9 +3398 1 +2151 3 +2923 5 +2725 9 +3378 8 +1374 7 +845 3 +688 5 +983 3 +1179 3 +3101 9 +517 3 +2542 3 +2735 10 +1047 1 +1644 8 +1361 10 +2310 9 +2434 1 +3206 3 +535 7 +102 6 +404 10 +3868 5 +3149 5 +2435 6 +251 7 +2300 10 +1969 7 +598 7 +923 5 +1468 8 +476 10 +2255 4 +828 2 +3250 8 +885 2 +1345 9 +1474 6 +3764 1 +502 8 +71 6 +967 9 +3653 10 +3014 4 +3569 7 +2820 4 +1316 6 +1736 3 +2992 3 +2360 8 +591 2 +832 5 +3902 10 +2303 3 +791 4 +1749 6 +958 8 +2051 10 +2864 3 +2891 4 +241 4 +1918 10 +331 5 +1104 9 +1243 2 +535 10 +2948 8 +2058 8 +2574 5 +2316 9 +2937 5 +1369 2 +1267 6 +1738 6 +1366 10 +2937 5 +2859 6 +566 8 +3383 4 +3538 2 +1572 9 +62 3 +3980 8 +2111 4 +1024 8 +1804 9 +2077 6 +1541 9 +229 4 +3343 5 +90 7 +945 1 +2381 4 +371 4 +2661 2 +3672 6 +3246 6 +2902 8 +3771 5 +3020 6 +3744 3 +1319 6 +3197 6 +2389 10 +46 6 +1502 9 +28 1 +2857 7 +331 5 +1607 2 +2794 10 +495 8 +2281 6 +880 4 +847 10 +3205 8 +4019 5 +1949 8 +3477 6 +1990 8 +344 5 +2752 8 +2034 3 +3588 7 +1771 5 +505 9 +2026 1 +1222 8 +933 2 +188 1 +2132 5 +3767 9 +3484 4 +2768 5 +1482 6 +1943 10 +1640 8 +2812 5 +3279 6 +3959 7 +2610 1 +2045 9 +433 1 +529 2 +873 10 +1385 1 +1994 8 +744 7 +2665 9 +3311 6 +211 7 +1250 1 +529 6 +759 10 +3624 8 +1505 4 +773 7 +1594 1 +3429 9 +1466 9 +2224 6 +136 3 +3932 4 +4086 8 +32 5 +3534 7 +245 3 +3196 7 +1338 9 +1794 1 +3218 10 +284 4 +1747 6 +3710 7 +3343 8 +2297 5 +2521 4 +3802 10 +3643 10 +591 2 +4093 3 +1801 2 +1185 8 +2421 9 +1381 2 +1205 5 +330 2 +3644 5 +1504 4 +3281 9 +3169 9 +2191 6 +3037 3 +3072 6 +1778 5 +221 8 +362 10 +3549 8 +834 5 +2804 7 +204 10 +3044 6 +3720 1 +3166 8 +1170 2 +3210 2 +444 6 +2219 8 +2214 5 +2229 8 +2406 2 +2538 9 +1531 8 +1341 4 +4000 5 +1662 9 +330 6 +3485 6 +1474 7 +2921 1 +773 10 +3340 8 +432 6 +1283 6 +2487 6 +1041 1 +3626 7 +2177 5 +610 8 +2025 2 +2665 2 +1007 10 +882 9 +421 8 +895 4 +1596 2 +1170 9 +386 1 +863 10 +1216 2 +3614 4 +2822 3 +1816 3 +2434 9 +3923 8 +2717 7 +2002 1 +1745 8 +1417 10 +446 10 +396 7 +517 9 +534 9 +2942 6 +1256 7 +4068 10 +911 5 +2907 2 +1927 4 +776 3 +3477 1 +785 4 +2842 2 +760 9 +3268 6 +3425 1 +1723 9 +1879 5 +660 4 +415 4 +1791 2 +811 6 +248 5 +236 2 +287 10 +1817 4 +2630 2 +2992 2 +1950 6 +3474 5 +1824 1 +3571 2 +2758 5 +3343 7 +1821 2 +2972 6 +1291 2 +2746 7 +408 9 +4042 10 +526 4 +3311 1 +2222 2 +3155 1 +3408 5 +3727 9 +3716 7 +1321 4 +172 6 +534 2 +1827 4 +1560 1 +2654 2 +2937 3 +3102 1 +2640 9 +3527 8 +2810 8 +746 1 +3423 9 +694 9 +41 6 +20 5 +1888 2 +2831 3 +1597 6 +12 9 +2351 4 +550 10 +1688 5 +4070 3 +3345 4 +15 9 +242 6 +2823 4 +2870 6 +3587 3 +612 3 +3067 4 +1665 5 +3909 7 +3483 9 +710 5 +1307 9 +459 5 +3370 10 +3711 6 +491 3 +1938 2 +2272 2 +2118 2 +255 10 +129 5 +1726 6 +2144 10 +3655 1 +3228 1 +19 7 +608 9 +2167 9 +3599 10 +729 9 +3547 8 +2491 1 +3318 4 +815 7 +3745 8 +1743 3 +3102 5 +3946 7 +289 3 +3352 8 +4042 4 +3943 7 +3786 1 +2910 8 +2412 7 +3851 8 +3896 10 +1297 8 +1075 8 +3520 5 +717 4 +2416 9 +3535 2 +1494 3 +3614 4 +327 3 +3272 7 +3078 7 +1952 3 +928 8 +1322 1 +2563 3 +1412 5 +623 8 +458 6 +3754 8 +2197 10 +481 8 +3081 2 +2712 6 +2057 1 +915 6 +3583 9 +2544 3 +2841 5 +3389 1 +2732 8 +393 4 +2141 6 +2216 1 +2541 6 +1211 5 +3478 10 +525 1 +2292 3 +2483 7 +696 9 +2828 1 +915 5 +1047 1 +1755 6 +2524 6 +2721 10 +1936 8 +764 10 +2789 7 +3012 3 +1266 10 +4085 8 +3797 2 +2110 8 +2170 10 +688 4 +974 5 +2386 8 +1075 7 +3606 7 +3612 2 +2545 5 +1956 7 +3552 5 +3585 1 +110 10 +163 4 +699 1 +798 5 +1452 10 +3588 10 +1014 5 +1249 1 +3817 9 +866 10 +3177 10 +276 7 +2056 1 +1787 8 +4024 4 +3284 10 +2852 9 +994 10 +3106 7 +445 2 +970 9 +1140 10 +493 4 +1433 9 +3762 2 +3608 3 +887 7 +1315 2 +2146 8 +3944 1 +2345 1 +1994 5 +279 6 +784 2 +137 6 +3041 3 +755 6 +2503 4 +2778 3 +3646 9 +2580 4 +2147 4 +1542 3 +2530 6 +2357 7 +1586 10 +503 2 +3471 4 +1166 9 +3133 8 +2226 9 +483 8 +3475 6 +1640 3 +3188 10 +1548 6 +3520 5 +965 1 +3348 1 +189 10 +3796 9 +3653 1 +3804 6 +371 1 +3046 8 +2189 2 +2543 5 +3253 2 +225 3 +2033 7 +2182 10 +1975 10 +373 4 +137 4 +1033 4 +3898 8 +129 6 +101 10 +3114 9 +3741 10 +415 1 +752 1 +1383 10 +3232 3 +3534 6 +2786 6 +1320 7 +3762 9 +3929 9 +1238 1 +3353 7 +3911 7 +189 9 +1872 3 +3941 3 +3292 1 +2412 9 +1105 3 +1231 9 +963 3 +1098 4 +3351 6 +3409 4 +75 9 +365 6 +4088 2 +570 4 +3450 7 +490 6 +3582 3 +1764 5 +1658 9 +1235 5 +389 6 +1015 3 +1108 8 +4009 7 +1420 10 +4007 3 +1191 4 +3350 10 +805 6 +855 3 +2683 6 +564 3 +1640 10 +3632 7 +1769 6 +295 10 +2004 5 +3962 4 +3720 7 +833 6 +2054 9 +351 3 +3162 6 +3564 8 +1557 5 +2737 2 +2530 8 +1694 10 +3637 9 +1107 2 +1243 3 +474 1 +835 10 +3981 4 +3722 8 +52 5 +2942 3 +3461 9 +3959 10 +4080 1 +3554 6 +1633 7 +1591 7 +2656 7 +540 2 +2305 8 +842 7 +3146 10 +1251 3 +2403 2 +835 5 +773 2 +3458 7 +3165 4 +433 1 +2319 2 +184 10 +3171 4 +1316 2 +3103 5 +195 9 +3694 4 +2688 10 +1936 2 +848 6 +3991 7 +3714 7 +16 10 +2050 4 +1957 4 +1813 7 +3883 3 +3129 10 +1555 7 +882 1 +3957 1 +1613 10 +2381 3 +1205 6 +96 4 +3400 2 +2476 1 +3132 6 +648 5 +2613 9 +307 6 +3069 2 +340 1 +4033 7 +3613 3 +3821 6 +3658 7 +588 10 +3796 5 +1901 1 +2932 8 +533 9 +2864 1 +2976 6 +4058 5 +4000 6 +52 7 +2606 1 +1784 1 +973 9 +1337 6 +1521 6 +2273 9 +50 9 +877 4 +1265 2 +3981 9 +772 3 +2543 10 +2910 10 +148 1 +929 3 +3817 10 +1356 9 +2603 10 +3064 10 +236 3 +1714 4 +2242 6 +2907 4 +1879 10 +2685 8 +2129 1 +495 9 +3688 3 +2593 6 +1157 2 +1048 7 +3763 5 +2224 6 +3561 4 +2035 3 +1208 2 +1515 1 +611 7 +2020 2 +2615 10 +889 2 +3331 2 +2320 2 +2471 4 +3194 7 +2715 2 +3911 3 +2493 3 +2034 4 +2575 8 +2170 3 +1348 6 +1592 5 +3146 3 +1064 1 +1493 3 +724 6 +907 1 +3502 3 +3672 7 +299 4 +2517 3 +3487 6 +3732 2 +964 2 +819 2 +1960 3 +2892 7 +2993 6 +1101 9 +1240 7 +1560 9 +741 6 +1046 9 +2287 4 +502 8 +1311 6 +3071 8 +2469 6 +2760 1 +2553 9 +1073 7 +3543 2 +2323 1 +2572 7 +2027 6 +655 10 +575 7 +2066 10 +1236 3 +1411 1 +684 3 +1738 2 +1257 5 +2553 3 +2663 7 +3251 4 +1204 9 +1806 1 +3003 8 +762 6 +3163 7 +1754 7 +4040 9 +2394 2 +2892 3 +637 1 +1310 6 +697 3 +3016 2 +3237 7 +1357 7 +1590 7 +646 1 +4003 10 +3500 8 +960 6 +1841 7 +1620 7 +1396 3 +137 4 +2583 3 +3340 8 +2116 3 +4047 9 +2384 2 +2503 2 +2827 5 +1135 6 +346 7 +3504 3 +3738 8 +1658 2 +2218 6 +3144 2 +1604 1 +2074 1 +1379 3 +667 4 +1595 2 +2635 8 +992 3 +876 10 +1063 3 +3065 10 +1445 9 +2430 2 +2090 9 +123 3 +3695 1 +3168 5 +2053 8 +281 6 +899 8 +1603 4 +3085 4 +583 9 +3737 8 +1113 1 +3894 10 +781 9 +1529 6 +242 6 +1746 6 +859 7 +557 5 +4039 2 +2021 5 +3493 9 +2449 6 +502 5 +2792 10 +2028 10 +1299 6 +2347 5 +2662 5 +4015 8 +2272 8 +3546 3 +3687 2 +2466 6 +1312 7 +2764 9 +3068 4 +2422 2 +1196 9 +3139 6 +904 7 +1365 6 +214 2 +700 2 +449 6 +3611 3 +3476 8 +4069 10 +2743 1 +1171 3 +4075 10 +2356 8 +3758 8 +2310 10 +1809 9 +1628 6 +3410 3 +968 9 +3434 6 +314 7 +2523 1 +3429 9 +1426 10 +961 10 +1711 5 +403 3 +3823 7 +554 2 +3537 9 +3062 3 +360 7 +3181 7 +86 4 +3597 10 +3837 3 +3963 4 +3378 10 +2796 2 +2759 9 +273 8 +1666 6 +3315 1 +3729 6 +3574 7 +1220 9 +2887 9 +2860 5 +3324 6 +1048 9 +111 1 +3535 5 +195 3 +1970 7 +1497 10 +1656 8 +2179 8 +625 8 +1339 1 +571 2 +443 2 +1193 2 +309 1 +255 4 +2777 10 +1767 3 +2491 6 +1554 1 +3238 7 +2368 8 +2160 5 +2638 5 +2201 3 +2405 2 +968 8 +224 5 +2132 10 +1030 2 +373 9 +1363 3 +1169 10 +2470 8 +3607 7 +3155 7 +1502 6 +3687 9 +2833 5 +3829 1 +3777 10 +2998 5 +182 1 +1398 1 +3701 6 +1395 4 +341 4 +1627 1 +1747 9 +3265 6 +2489 8 +3944 6 +2359 7 +157 6 +2268 2 +1250 1 +2574 3 +4020 10 +1196 5 +82 10 +1647 2 +4038 10 +1089 3 +492 3 +3633 8 +1657 6 +517 5 +1698 6 +1222 8 +3172 4 +2166 2 +2571 6 +1656 5 +1343 3 +1362 9 +3554 9 +2941 2 +2767 10 +3191 7 +3471 6 +2537 8 +912 2 +1923 7 +685 5 +2697 3 +4048 4 +2929 6 +2271 4 +1786 6 +1470 10 +132 6 +4013 10 +1369 9 +1577 3 +894 6 +1411 2 +2049 6 +3885 7 +3098 8 +3958 8 +2841 3 +3300 4 +2503 10 +2301 7 +2377 2 +1867 9 +3131 9 +485 7 +3578 7 +1263 4 +2950 9 +1461 9 +950 4 +3771 8 +1189 10 +3455 7 +81 2 +1035 6 +3512 10 +3572 6 +2891 5 +2564 4 +1776 7 +3028 4 +829 7 +2937 8 +4088 9 +183 2 +623 2 +675 2 +441 1 +1852 8 +2703 6 +2825 6 +463 3 +303 9 +2953 8 +2093 5 +2215 3 +1619 9 +2906 8 +1180 3 +3956 1 +2573 6 +3032 3 +294 5 +2959 2 +177 7 +2688 7 +2499 1 +4038 1 +3699 3 +3859 7 +1459 6 +1642 1 +3293 2 +109 5 +772 3 +3819 6 +37 1 +1604 8 +1271 6 +3470 1 +2858 10 +2757 10 +1798 1 +992 1 +980 4 +645 7 +1328 5 +4002 10 +2225 10 +1932 7 +537 9 +1114 3 +3522 4 +911 10 +2633 10 +3001 8 +2258 1 +3882 1 +3206 9 +18 8 +3612 2 +1648 10 +1319 2 +3573 4 +359 7 +499 4 +3158 10 +695 6 +3165 10 +2167 2 +3646 4 +2764 2 +2407 9 +2155 7 +1448 6 +1667 1 +3127 1 +135 7 +1264 2 +764 6 +506 5 +3105 8 +937 5 +4010 2 +2231 9 +1652 2 +769 2 +2574 7 +607 6 +1594 8 +651 9 +338 5 +3642 7 +3371 1 +3527 3 +138 5 +3833 3 +870 7 +2520 4 +3068 3 +1661 9 +43 10 +3234 4 +3111 6 +1625 9 +2898 8 +3525 1 +2530 3 +2917 7 +2001 7 +1175 10 +4027 9 +222 7 +2333 7 +1872 3 +2005 2 +1496 8 +2605 2 +3973 1 +2975 9 +2649 7 +1952 10 +3835 9 +3390 10 +2487 5 +3693 8 +3397 7 +176 7 +2214 3 +3599 2 +2217 1 +57 4 +1659 7 +1751 3 +3714 3 +2875 10 +1594 3 +3245 7 +1577 6 +75 5 +2430 2 +2506 9 +674 3 +1033 6 +2185 3 +1284 10 +2220 6 +3269 7 +1917 1 +2666 8 +2274 4 +3643 8 +1942 9 +3126 3 +2317 7 +2505 8 +1705 1 +854 2 +1642 9 +2639 5 +612 2 +1006 3 +56 9 +1023 2 +384 6 +3366 8 +455 1 +2153 6 +1079 7 +2176 4 +1206 9 +4081 6 +1285 2 +4094 2 +1142 10 +1307 3 +3587 4 +2844 7 +3226 7 +2457 3 +2921 6 +3132 2 +345 1 +649 4 +4065 10 +3693 3 +3563 5 +513 9 +1167 2 +33 2 +153 4 +3185 8 +1873 5 +1702 1 +3799 10 +756 7 +801 9 +3801 2 +827 3 +472 7 +1096 8 +268 3 +2160 8 +2931 4 +3145 5 +555 3 +3863 6 +2106 10 +2336 1 +1444 5 +3832 2 +131 7 +275 7 +679 9 +599 3 +1184 6 +1464 6 +2622 4 +248 6 +1312 4 +2100 8 +3531 7 +1235 6 +342 10 +2477 7 +247 2 +1424 6 +2989 6 +2123 7 +2465 6 +2203 1 +1443 10 +1773 3 +2058 3 +3027 10 +1329 7 +3578 7 +731 4 +632 5 +2656 3 +2901 5 +343 6 +2157 9 +596 3 +163 5 +3700 8 +2955 8 +2670 4 +3695 1 +3428 5 +727 6 +3111 7 +1253 6 +1870 8 +2787 6 +909 9 +1820 9 +3830 3 +3126 6 +3118 5 +3670 7 +3757 8 +3454 7 +2750 5 +2097 4 +3445 4 +1166 7 +3947 4 +3770 5 +2125 4 +2132 10 +3089 7 +250 10 +2423 4 +1737 7 +2687 1 +2502 2 +919 2 +2354 9 +3074 7 +2245 3 +2155 3 +3640 4 +1670 1 +82 1 +116 10 +2480 5 +2174 9 +2497 4 +1910 3 +3481 8 +957 10 +3011 3 +3902 9 +1144 2 +3894 10 +2668 3 +2266 9 +1738 1 +3002 6 +3280 6 +988 10 +3073 8 +1148 5 +3624 8 +3011 3 +442 3 +2771 5 +265 8 +1151 9 +676 3 +110 3 +1421 4 +2040 5 +281 8 +2145 3 +1174 3 +1546 5 +367 6 +413 1 +238 7 +1650 9 +937 6 +1036 10 +905 5 +2108 2 +2969 9 +2356 5 +1495 3 +1575 1 +52 5 +1737 2 +1457 1 +573 2 +3489 1 +3301 5 +2585 5 +3978 4 +3945 4 +2554 8 +1266 6 +1736 6 +2138 1 +870 4 +4036 10 +924 10 +547 3 +943 3 +3859 4 +1390 5 +2047 8 +1852 2 +2780 3 +2684 5 +1665 10 +613 4 +1398 7 +3509 7 +1605 9 +740 1 +243 7 +2659 2 +899 6 +1406 1 +579 2 +3301 8 +2814 7 +467 1 +2460 3 +3172 7 +3746 5 +3238 2 +1272 2 +3292 9 +796 9 +151 4 +3114 9 +1102 4 +4072 7 +3927 5 +930 1 +3501 3 +3166 2 +571 7 +4062 2 +1367 2 +112 7 +2477 5 +860 4 +1057 9 +2105 10 +3283 5 +47 1 +3477 5 +891 8 +553 4 +2510 7 +285 1 +1484 8 +4022 2 +1414 8 +134 1 +1085 4 +2299 2 +2428 8 +1288 5 +1487 4 +1354 7 +1115 8 +1920 1 +615 8 +2485 5 +2692 9 +709 1 +893 7 +2945 3 +118 9 +1232 8 +3262 7 +1332 5 +2284 5 +2410 7 +3191 5 +3808 6 +3573 2 +2134 1 +1291 8 +2215 8 +4017 2 +13 9 +3263 8 +3875 10 +493 8 +864 2 +179 8 +2933 7 +663 9 +2633 7 +1485 6 +2004 2 +178 9 +3816 3 +678 6 +3019 7 +2792 10 +83 7 +3328 3 +77 2 +2991 6 +1643 4 +780 8 +2627 6 +3422 10 +4085 8 +593 1 +1798 6 +1606 6 +1045 7 +2765 5 +3186 2 +2260 8 +3972 7 +1132 5 +1900 10 +1759 6 +2290 9 +1212 4 +698 7 +511 1 +3331 7 +1185 6 +2565 1 +481 5 +896 7 +3301 7 +3907 7 +1014 5 +3916 1 +3628 3 +897 5 +1626 7 +1935 10 +1200 7 +3970 8 +3287 6 +927 2 +385 5 +1665 7 +2625 3 +1068 5 +3819 1 +2727 1 +1770 10 +3401 4 +1035 5 +3934 7 +1747 10 +3304 5 +1699 3 +739 10 +2396 3 +438 2 +3852 10 +2536 8 +619 8 +3535 3 +3758 3 +3889 1 +2887 6 +1720 9 +906 7 +3930 2 +3424 8 +2388 2 +1193 8 +2670 6 +3415 6 +3748 5 +1005 2 +3621 1 +2117 6 +3173 1 +3138 4 +3527 6 +790 3 +1633 5 +1725 10 +1700 8 +895 4 +3164 10 +3433 1 +165 1 +554 8 +1332 3 +1330 7 +1063 9 +2077 7 +875 9 +1378 1 +3839 9 +1907 3 +3274 8 +1444 4 +3809 1 +1834 7 +447 10 +13 6 +353 1 +2807 10 +3759 2 +1007 10 +3404 7 +1943 4 +1538 5 +1627 5 +2355 7 +1113 6 +578 9 +3056 3 +4034 8 +1812 7 +1388 9 +662 5 +2030 10 +24 7 +1600 10 +3051 7 +1495 1 +3155 4 +2911 7 +3017 3 +3764 7 +3561 7 +2259 8 +1092 9 +1312 5 +2132 10 +1929 10 +1297 3 +164 4 +1759 3 +2554 5 +3570 9 +2073 7 +68 8 +3225 1 +1222 9 +3001 8 +189 10 +3512 8 +3954 1 +4007 10 +498 9 +3559 7 +4052 3 +4066 5 +3914 10 +214 6 +149 4 +3949 7 +1491 7 +1783 1 +39 9 +1576 2 +3915 6 +1422 3 +2488 3 +3578 5 +939 10 +2467 1 +3742 10 +3990 3 +1156 3 +638 8 +308 5 +414 9 +2119 5 +2310 6 +491 8 +1948 9 +3551 1 +197 8 +2189 4 +2492 4 +2503 10 +3930 9 +3180 3 +1251 3 +1713 6 +203 10 +79 6 +2020 8 +2585 2 +2096 3 +1790 2 +2869 6 +1174 6 +2765 9 +1261 3 +2399 5 +637 10 +2318 5 +2306 5 +3370 7 +3379 1 +1732 5 +1503 10 +3555 8 +2024 8 +3905 6 +3491 5 +197 9 +340 1 +192 10 +1165 6 +3663 2 +2625 4 +2784 5 +3138 10 +3624 2 +3707 4 +2747 3 +96 8 +3822 6 +2740 7 +4083 7 +3339 8 +2041 10 +3050 7 +3165 7 +3096 9 +1375 1 +658 3 +3089 7 +586 9 +737 9 +2962 8 +3511 4 +2051 8 +1653 10 +2080 4 +1883 8 +2251 3 +1934 6 +1480 9 +3874 6 +276 9 +3255 8 +1860 4 +376 1 +71 7 +3753 2 +80 2 +3707 6 +1065 4 +978 2 +34 9 +1967 3 +964 2 +2802 8 +497 2 +793 1 +3976 9 +276 1 +3541 7 +2997 6 +444 10 +1180 10 +3008 1 +4091 10 +2304 4 +2965 6 +3270 5 +2441 4 +2822 5 +657 6 +2631 8 +1358 10 +1783 3 +3165 3 +1865 1 +3323 6 +375 3 +3779 5 +2505 3 +1645 10 +957 3 +1491 3 +1214 5 +3670 3 +2193 1 +720 2 +3241 10 +3819 8 +2112 4 +3301 10 +1264 4 +3937 3 +3991 9 +2233 9 +2788 8 +2477 5 +2449 6 +3996 10 +1614 6 +1843 1 +2732 4 +2658 2 +1930 9 +1400 2 +3464 10 +3043 7 +1099 6 +1698 1 +2485 9 +904 9 +3305 1 +161 10 +3368 3 +2575 3 +2376 2 +3414 10 +2415 2 +2241 3 +1118 3 +672 2 +973 3 +63 2 +3909 10 +2730 10 +2677 8 +2879 7 +434 8 +3328 1 +372 4 +3892 9 +3724 3 +1471 1 +1378 6 +3369 9 +244 7 +3068 4 +864 7 +1521 6 +2038 2 +3124 2 +1781 4 +2580 6 +324 1 +1703 1 +1230 2 +2407 6 +3972 9 +1775 6 +3082 4 +2442 8 +159 1 +971 1 +1686 8 +1022 10 +166 3 +3153 3 +3406 10 +1865 8 +1902 8 +2309 8 +78 1 +1521 7 +3207 10 +3637 2 +2802 7 +2388 4 +2204 2 +1263 9 +3758 7 +210 1 +2319 9 +561 4 +3534 9 +3902 2 +3460 8 +3392 4 +2231 10 +3718 9 +3019 5 +1126 9 +563 4 +1770 1 +1615 8 +2212 3 +3923 4 +745 5 +1638 9 +2814 6 +2652 1 +1114 8 +3194 5 +2302 9 +2308 8 +1040 4 +1210 4 +1632 2 +1359 3 +2478 9 +2613 5 +1037 7 +588 4 +602 3 +4014 7 +2961 4 +2047 9 +2435 1 +200 7 +1265 3 +278 3 +1610 4 +3825 10 +3239 6 +1101 2 +1300 4 +645 3 +180 5 +987 10 +626 9 +1288 6 +4017 3 +1451 10 +3465 6 +639 9 +830 3 +3332 1 +2983 10 +3702 5 +3877 10 +1450 4 +1003 5 +1545 5 +85 9 +1838 4 +788 8 +3927 10 +1056 8 +2778 6 +3679 3 +1002 8 +3338 5 +796 5 +2418 2 +3877 6 +279 8 +2305 8 +3895 4 +3515 1 +2818 4 +667 8 +2259 1 +2268 1 +2727 8 +1497 2 +777 6 +2200 7 +2456 5 +2856 7 +1571 5 +990 10 +1046 3 +3554 2 +3317 2 +2117 2 +49 4 +3251 5 +1138 4 +1020 6 +359 10 +2453 9 +2468 2 +1970 7 +3781 8 +339 10 +707 9 +1294 7 +3950 1 +846 8 +3362 9 +1275 3 +2627 5 +2665 3 +2785 8 +2626 5 +733 9 +1160 1 +3159 6 +143 9 +2164 2 +3928 2 +1972 2 +3856 7 +3888 7 +3983 8 +1829 10 +37 6 +255 3 +1327 9 +2513 10 +1368 2 +744 8 +709 9 +3809 9 +2173 5 +2777 2 +961 3 +421 1 +875 7 +1552 6 +1624 7 +3938 4 +1100 2 +631 1 +235 10 +1125 1 +168 10 +3547 7 +2353 10 +3006 10 +763 5 +2716 3 +2657 6 +3549 9 +214 6 +3547 7 +3270 6 +436 10 +3474 8 +3223 6 +4019 3 +4083 4 +1913 8 +422 4 +707 9 +2853 3 +1850 4 +596 4 +3455 10 +1307 3 +3706 8 +1441 10 +3879 8 +3858 3 +472 9 +1711 7 +3057 7 +1080 9 +498 5 +2332 9 +1374 2 +1178 1 +1673 7 +3260 5 +2625 8 +1925 7 +1769 8 +100 10 +3527 10 +3042 7 +3425 8 +3027 6 +1279 3 +2027 3 +469 8 +17 2 +2782 9 +341 5 +129 6 +2538 8 +325 8 +3066 3 +4047 6 +90 1 +1170 1 +496 8 +3767 3 +738 6 +978 4 +1727 9 +2483 9 +2017 6 +657 4 +2139 3 +775 10 +2472 9 +2787 8 +1504 3 +543 1 +1331 2 +1313 1 +554 4 +3997 6 +2823 8 +1521 10 +1342 2 +3175 5 +2162 3 +2970 2 +1781 9 +121 5 +1868 10 +1220 5 +1315 7 +3619 1 +729 7 +1148 2 +167 4 +915 10 +2197 9 +1387 1 +558 4 +3475 5 +803 7 +1223 8 +2789 2 +2020 8 +121 2 +926 3 +368 5 +1726 5 +261 4 +3162 3 +2490 10 +3168 3 +3301 10 +3438 5 +1498 8 +1912 8 +2145 9 +3118 4 +3638 1 +1186 10 +734 3 +2438 1 +2923 4 +1900 7 +2894 8 +3372 2 +759 8 +2318 1 +2312 7 +551 2 +2008 7 +3030 8 +960 8 +212 9 +470 9 +4042 1 +115 3 +3981 1 +2901 6 +227 2 +3460 6 +3819 8 +2974 2 +945 4 +3000 9 +2475 1 +2146 10 +1307 6 +1835 4 +3016 9 +111 6 +1804 3 +1492 10 +213 6 +578 4 +1962 7 +538 2 +3498 7 +1504 5 +3276 1 +29 10 +1751 4 +3691 8 +3940 7 +3590 5 +904 7 +1308 5 +2836 9 +2607 2 +3977 4 +3483 5 +914 7 +3591 8 +2957 2 +1456 6 +1058 4 +156 10 +1229 8 +723 4 +323 10 +1036 8 +1588 7 +1119 2 +2304 2 +1258 6 +2374 3 +1511 6 +3309 8 +2197 4 +1922 1 +2663 6 +1672 7 +3887 5 +3053 6 +1402 1 +548 8 +1584 1 +2087 3 +2285 1 +2296 2 +2219 7 +352 7 +1082 2 +1095 7 +3190 3 +2965 2 +1491 4 +3628 2 +678 1 +989 7 +3992 8 +2804 9 +3427 10 +2437 8 +354 3 +3931 2 +2727 6 +3545 6 +3365 5 +1510 7 +2345 10 +127 9 +3498 10 +636 5 +1057 7 +178 4 +912 10 +1125 9 +3365 5 +84 3 +938 7 +1288 7 +1381 1 +1918 4 +2141 4 +780 8 +3992 8 +588 1 +469 10 +3797 1 +3704 4 +3692 6 +1990 4 +891 1 +4079 7 +547 9 +1882 5 +3816 10 +926 8 +2927 10 +2006 7 +2486 2 +3632 3 +1220 2 +2238 10 +3433 9 +1246 2 +3886 4 +3922 3 +218 8 +2179 2 +3334 1 +193 8 +1378 10 +3579 7 +1791 7 +3787 4 +873 7 +2528 9 +518 6 +212 9 +3299 9 +3114 10 +379 1 +2024 7 +681 2 +3421 8 +399 10 +3187 5 +1665 4 +1808 6 +1987 5 +1748 4 +1625 9 +385 10 +987 9 +3359 7 +2821 6 +2169 4 +3375 9 +3512 9 +3189 7 +1068 8 +3790 4 +3807 2 +22 8 +1287 6 +3718 9 +2858 6 +2126 10 +4011 5 +3800 10 +2661 2 +1947 8 +3834 2 +303 2 +2622 3 +3913 1 +1811 4 +61 5 +3661 5 +2741 6 +3856 9 +1455 8 +1637 6 +3822 1 +849 10 +1107 9 +4017 7 +1863 9 +835 10 +1701 3 +2071 9 +1073 6 +3155 9 +3832 10 +643 4 +530 1 +353 1 +1161 1 +350 1 +2528 8 +3713 9 +880 9 +2421 10 +3781 1 +2390 9 +2151 6 +245 2 +2899 6 +3547 9 +2772 5 +2134 1 +1827 4 +1552 10 +3487 4 +900 3 +273 5 +1946 1 +3128 2 +3301 9 +3175 5 +934 10 +1779 3 +1199 9 +1233 5 +2228 7 +2105 1 +479 8 +3535 1 +1742 2 +2390 7 +3399 2 +1660 7 +849 3 +1652 9 +3332 8 +174 4 +2965 9 +1165 8 +2794 8 +1638 2 +2881 8 +2527 3 +1570 2 +2307 5 +979 2 +2832 6 +3507 8 +3430 1 +3962 7 +140 7 +3207 2 +3306 10 +582 10 +2746 8 +81 4 +2122 4 +1226 6 +1454 7 +354 5 +1664 2 +2109 1 +1697 3 +2452 4 +2398 1 +2224 2 +1679 6 +2330 1 +2358 3 +2942 10 +3842 2 +1411 2 +353 9 +1879 2 +1117 6 +255 1 +2495 8 +1126 9 +1947 6 +3705 6 +270 10 +1351 2 +2900 1 +3427 7 +742 2 +1158 4 +2501 1 +868 10 +3810 5 +449 2 +2496 5 +972 4 +3187 9 +291 4 +2278 3 +1057 2 +1471 10 +3238 2 +1171 6 +1463 3 +2833 3 +2529 10 +2831 3 +567 10 +2484 4 +973 1 +3606 5 +154 7 +2688 3 +1188 5 +1853 4 +3407 6 +710 1 +1598 10 +6 4 +2315 9 +3218 10 +577 3 +2530 9 +2622 4 +4048 1 +1208 1 +2226 4 +1064 9 +2499 10 +3998 7 +496 5 +1751 7 +4021 7 +2966 9 +684 3 +3805 7 +2747 2 +1818 7 +2879 3 +3599 6 +2593 5 +2186 10 +3511 10 +1100 1 +1821 6 +3472 4 +2858 7 +2920 5 +173 2 +3517 4 +3322 9 +3410 4 +2233 7 +392 9 +2204 7 +3584 3 +356 5 +2406 3 +906 9 +2577 6 +2631 6 +444 3 +2593 9 +2065 8 +53 8 +661 2 +2175 8 +365 9 +1178 9 +2179 5 +2548 2 +4022 7 +1486 2 +3648 5 +1654 3 +2129 1 +3787 1 +3637 2 +980 8 +3142 1 +2176 1 +847 2 +659 7 +2132 1 +3193 6 +70 4 +3333 7 +3145 4 +1512 5 +292 4 +1357 6 +1603 4 +64 10 +4048 3 +1027 8 +3850 2 +3056 4 +1658 8 +3884 7 +2822 10 +2949 6 +1058 1 +2301 8 +3666 1 +1829 3 +3148 8 +2784 4 +281 8 +3434 1 +2237 1 +2413 6 +805 2 +1900 7 +669 5 +2412 5 +2964 8 +3704 3 +468 8 +3184 5 +3394 3 +3059 1 +632 3 +843 8 +1157 2 +2788 3 +1339 7 +2516 9 +650 1 +1764 2 +3082 10 +1718 5 +2034 7 +1360 4 +4023 7 +1123 6 +424 3 +1087 1 +1181 1 +2253 1 +531 2 +1485 6 +572 3 +3615 8 +839 2 +2062 2 +1142 8 +1175 5 +3997 2 +2481 3 +3086 5 +3060 4 +3474 1 +1045 1 +1009 8 +2648 3 +2472 8 +2130 3 +362 3 +1695 4 +3669 8 +3233 8 +1840 7 +3803 3 +3042 3 +882 10 +3123 1 +3752 8 +3475 2 +3648 4 +583 10 +1334 6 +612 6 +163 1 +3764 5 +1912 3 +1816 10 +2696 3 +842 6 +257 1 +4033 6 +3039 3 +2051 7 +1188 5 +2949 7 +255 9 +3385 1 +1189 2 +3189 9 +1669 2 +1227 2 +2908 7 +1812 8 +2435 4 +1842 9 +1452 2 +2649 6 +1876 6 +770 5 +2038 9 +3784 10 +1738 2 +2144 6 +214 4 +618 4 +539 2 +2360 6 +350 4 +307 4 +807 5 +1564 7 +3877 2 +3824 10 +1023 3 +2440 9 +2700 8 +2239 4 +2076 4 +3086 9 +3480 5 +2189 10 +3143 5 +3434 4 +2389 8 +3170 4 +1231 7 +1376 8 +554 7 +2525 10 +2580 8 +4069 5 +319 4 +1771 5 +2893 7 +3742 6 +1438 7 +1010 1 +726 6 +3146 9 +2214 7 +351 3 +2878 7 +1791 9 +1475 7 +1457 6 +2583 8 +1730 10 +116 9 +2972 6 +3886 9 +1110 6 +1906 10 +1406 8 +2044 2 +1333 1 +3736 5 +1384 10 +1298 3 +2877 3 +1274 4 +1711 5 +3467 9 +925 5 +504 1 +3689 6 +3026 4 +1071 3 +586 10 +2394 2 +315 2 +2946 7 +747 8 +51 4 +2317 3 +692 9 +3653 10 +3718 10 +2106 8 +3031 1 +1970 4 +1763 3 +3037 4 +1116 6 +1784 1 +3486 1 +551 2 +3451 8 +3809 2 +2572 5 +3576 1 +3229 1 +151 5 +723 3 +1748 9 +519 3 +2762 3 +2266 2 +121 7 +1905 10 +2294 9 +629 9 +2232 10 +1590 2 +2437 6 +1092 10 +1153 3 +2067 2 +1825 10 +1631 1 +103 1 +129 8 +2731 10 +1265 5 +2754 10 +3176 2 +2385 8 +1620 3 +444 4 +1231 7 +1496 1 +3681 10 +2951 3 +3148 10 +172 10 +1414 9 +3775 9 +2671 4 +697 1 +3632 5 +2440 5 +3099 2 +350 6 +3080 10 +1314 8 +2759 4 +2801 3 +3304 4 +2912 4 +2351 1 +940 6 +2725 2 +3543 9 +3971 3 +1649 3 +550 7 +125 1 +1696 9 +2743 8 +2277 1 +543 2 +1262 7 +550 7 +920 4 +2277 10 +2466 10 +2648 6 +2442 7 +1983 1 +1438 2 +2167 1 +2256 10 +183 6 +2832 8 +2037 1 +2829 7 +284 3 +138 8 +1758 1 +2109 8 +1146 5 +3817 10 +799 8 +325 4 +706 10 +1790 6 +445 2 +1734 6 +123 8 +2187 2 +1960 7 +75 2 +359 8 +802 5 +1384 3 +1140 4 +2396 5 +4087 7 +2680 7 +3182 8 +3436 6 +899 7 +1437 4 +1502 2 +2046 9 +452 9 +3709 5 +1733 9 +1547 2 +1729 10 +3826 7 +1387 8 +185 3 +513 9 +3068 10 +306 2 +1585 3 +1244 6 +977 1 +1751 8 +1350 7 +1112 8 +2683 2 +3677 6 +1196 2 +100 4 +4058 3 +897 6 +1915 7 +927 2 +480 2 +892 1 +3033 10 +2510 7 +2915 4 +1296 7 +2536 1 +255 6 +2584 1 +98 5 +1922 3 +1547 6 +3939 6 +3795 10 +3628 6 +2484 8 +661 3 +3160 1 +1991 2 +607 9 +1305 1 +1910 6 +3274 4 +2755 4 +2570 2 +2550 5 +3805 3 +3987 3 +1123 5 +1105 3 +3047 9 +3404 1 +684 8 +3036 5 +3368 8 +2208 1 +2049 1 +1761 1 +1416 10 +1559 2 +2246 5 +612 1 +92 10 +1815 5 +926 5 +1552 8 +438 8 +2828 7 +1502 9 +2894 7 +3200 4 +2227 9 +2483 7 +3918 5 +3274 3 +2318 6 +1762 2 +2416 1 +2081 6 +3583 6 +2357 8 +1319 2 +657 3 +4073 7 +1517 5 +3633 10 +1945 8 +2331 5 +3289 6 +763 5 +3895 6 +1698 3 +1658 3 +31 8 +2042 6 +2543 8 +413 8 +831 3 +2182 2 +3657 2 +3790 4 +2894 9 +1186 9 +3197 2 +1102 4 +1728 5 +689 8 +1189 6 +2347 1 +2034 9 +1046 8 +2342 3 +3731 8 +3407 5 +1307 4 +1156 5 +1946 5 +2779 8 +743 6 +334 8 +1101 9 +1831 4 +1158 8 +3068 2 +954 4 +3810 2 +467 7 +37 8 +339 1 +74 7 +2022 4 +419 1 +615 5 +1498 6 +548 10 +1759 2 +1873 2 +3670 4 +2614 9 +1278 1 +908 9 +1115 6 +2677 5 +1732 3 +3546 4 +3924 1 +2665 1 +1387 2 +3622 6 +1333 8 +1977 10 +4051 5 +2720 5 +2555 3 +607 6 +3498 4 +799 2 +3439 1 +1422 8 +3862 6 +959 1 +4029 2 +47 4 +2013 5 +3339 10 +2797 8 +3463 10 +1923 7 +2693 7 +276 5 +3223 2 +3887 6 +4060 1 +3765 3 +3480 6 +565 5 +3616 10 +3576 5 +2612 9 +4049 9 +762 5 +551 9 +1439 10 +2131 4 +544 10 +2124 7 +896 1 +163 4 +4021 5 +3887 4 +2329 4 +1714 8 +1209 5 +2238 5 +2096 10 +517 10 +2526 4 +2825 7 +2802 6 +3625 2 +255 6 +3419 7 +2404 9 +1538 6 +3235 2 +2416 9 +30 3 +3790 6 +977 10 +590 8 +535 9 +542 9 +553 3 +3670 5 +1373 6 +123 7 +735 9 +1218 9 +2397 8 +2703 9 +2846 9 +827 9 +491 1 +2986 10 +3797 3 +2170 2 +1397 3 +1185 2 +49 3 +1207 9 +3167 1 +466 7 +1659 4 +3479 9 +874 8 +3136 2 +1377 9 +879 2 +2961 4 +4020 10 +642 1 +2826 5 +3641 8 +3631 5 +1084 7 +324 8 +1660 6 +3774 10 +1663 6 +3907 1 +4027 1 +290 5 +963 6 +2344 7 +3325 9 +87 10 +1110 10 +1760 1 +825 9 +3647 9 +1213 5 +849 7 +1494 5 +3980 6 +922 8 +586 10 +1807 1 +3755 6 +2477 9 +302 5 +2174 9 +340 3 +2047 10 +1973 9 +3168 5 +2419 1 +3039 1 +4020 9 +2298 5 +1796 4 +3313 6 +542 4 +2913 2 +2069 4 +2407 1 +3566 7 +2190 10 +381 6 +2826 6 +2811 3 +305 2 +608 5 +3637 10 +617 2 +994 7 +1737 5 +761 4 +3223 2 +4070 3 +897 4 +2223 9 +2796 1 +2449 5 +1933 10 +450 9 +516 6 +1468 4 +2999 2 +3656 1 +3197 5 +2286 1 +3695 7 +3210 6 +2723 10 +930 2 +796 8 +2608 2 +3529 10 +2512 5 +3975 10 +1475 10 +1425 9 +2602 2 +2782 9 +1919 5 +1362 9 +214 3 +1476 4 +3714 4 +47 5 +1776 5 +714 5 +2815 2 +716 8 +1040 9 +415 1 +1683 5 +3396 1 +876 7 +2724 6 +1825 4 +2314 10 +3581 2 +2430 4 +282 6 +862 6 +2300 10 +2698 8 +3704 9 +1554 6 +939 10 +3315 9 +1561 3 +838 5 +2454 8 +2397 6 +1186 4 +1103 4 +2363 7 +698 5 +684 4 +3117 2 +2500 4 +3798 4 +4080 2 +2324 2 +739 6 +505 7 +2872 4 +476 7 +2891 10 +3213 10 +3634 4 +147 2 +282 3 +25 10 +2759 6 +465 1 +528 4 +2579 8 +2013 5 +3811 3 +694 4 +1180 6 +791 5 +3556 4 +3981 2 +3378 5 +3526 7 +2021 3 +2459 10 +3528 10 +3855 10 +3024 1 +3266 8 +1298 5 +2308 1 +236 7 +3047 5 +1001 7 +3633 3 +105 7 +2072 2 +2751 2 +1806 8 +4014 9 +720 4 +1813 1 +3026 4 +648 6 +2818 5 +1021 9 +1180 9 +1859 4 +1921 5 +1925 3 +477 5 +3051 9 +3474 4 +2718 10 +695 2 +2738 3 +181 9 +2138 4 +1474 9 +3440 10 +2442 10 +3753 7 +541 3 +1271 9 +2280 4 +1212 2 +3028 8 +3066 10 +3241 5 +1439 2 +3323 9 +3958 10 +2619 5 +4056 6 +3306 2 +2598 4 +1865 10 +300 8 +3693 7 +2055 4 +710 7 +2292 7 +3443 1 +498 8 +3295 3 +1591 1 +2208 6 +4032 7 +1800 5 +352 3 +780 2 +1835 2 +65 9 +956 2 +2303 3 +1494 8 +2362 7 +272 3 +2916 3 +2190 1 +633 4 +1862 2 +806 8 +3214 7 +15 10 +789 3 +1854 9 +575 2 +1241 8 +3633 7 +2771 7 +1776 7 +2664 1 +2994 9 +1300 8 +2878 4 +1185 9 +3652 2 +990 3 +205 5 +3316 5 +3237 9 +2604 4 +441 2 +241 8 +805 4 +3357 5 +1179 8 +2796 10 +3949 2 +530 9 +2938 6 +165 8 +3716 1 +3697 6 +3085 1 +29 8 +2242 9 +1622 9 +877 9 +1876 8 +329 2 +508 6 +3600 10 +1514 7 +3301 10 +1829 1 +2099 3 +2960 3 +3851 6 +1275 9 +2714 6 +2747 7 +294 10 +1226 5 +3453 2 +3326 8 +263 2 +2873 10 +3305 2 +417 10 +141 4 +1773 6 +3875 7 +2042 6 +2796 10 +1964 8 +2719 4 +2902 3 +2893 7 +239 10 +344 6 +2385 8 +472 9 +239 5 +2319 5 +2847 2 +2649 8 +3116 1 +347 6 +1848 3 +3705 4 +3340 8 +751 3 +695 9 +1393 7 +2153 1 +2148 1 +1848 4 +659 4 +2177 1 +2038 10 +2754 5 +1465 9 +3122 5 +2960 3 +1113 2 +3649 3 +3225 6 +2647 9 +1474 6 +2094 4 +740 1 +2325 5 +1224 7 +3048 4 +457 6 +2720 4 +3779 6 +2298 10 +1805 7 +1752 7 +3417 3 +3801 4 +2776 4 +2012 6 +3307 3 +2844 7 +2872 1 +957 4 +2252 4 +3174 9 +3675 1 +2599 8 +2037 6 +3173 9 +3304 3 +3000 5 +696 1 +3583 10 +2956 5 +899 7 +1427 7 +2211 10 +3065 2 +3351 3 +797 10 +1283 7 +120 8 +3194 3 +729 4 +2692 10 +3422 7 +2526 8 +3354 9 +790 3 +259 1 +55 3 +505 5 +68 8 +540 1 +3416 8 +3584 3 +1268 7 +729 2 +1840 3 +2573 2 +3843 3 +3823 9 +2592 8 +3453 4 +2886 3 +1236 5 +1562 6 +2156 7 +613 4 +2763 7 +912 1 +585 7 +2341 2 +754 7 +1028 1 +2006 4 +1767 5 +1965 3 +3078 8 +3587 2 +1418 2 +1086 9 +2082 9 +1415 7 +790 5 +3031 5 +1441 10 +3496 7 +966 1 +3562 5 +2816 8 +938 3 +2216 1 +1150 5 +1925 1 +1068 6 +2860 2 +1014 7 +469 6 +2987 5 +473 1 +3009 9 +917 10 +2700 10 +3394 3 +2324 8 +736 7 +2990 7 +3043 9 +896 8 +1146 1 +1360 10 +3906 6 +348 7 +3786 8 +1004 5 +2974 3 +558 9 +2854 5 +2777 7 +173 7 +3332 4 +450 7 +2464 9 +1195 9 +3235 7 +3336 2 +2254 6 +818 3 +3798 1 +810 8 +3606 2 +3025 6 +778 6 +977 7 +3549 2 +4015 3 +2736 7 +3550 6 +3889 4 +2921 5 +3176 3 +4 6 +1305 4 +4040 1 +1225 1 +3314 6 +1222 9 +1197 8 +3932 5 +3991 6 +493 7 +2644 7 +241 8 +562 5 +1097 3 +2632 6 +2480 3 +3129 5 +3096 2 +3585 8 +655 9 +2600 6 +491 4 +2467 2 +495 9 +3969 6 +3467 10 +45 2 +602 3 +763 6 +1876 10 +1188 8 +3089 4 +2316 1 +3761 10 +228 1 +3596 9 +215 1 +546 2 +1716 7 +1940 4 +2585 2 +1780 7 +262 5 +2560 7 +1845 6 +86 1 +1080 4 +1350 10 +606 9 +1391 7 +2634 8 +127 10 +2256 3 +2794 9 +2617 3 +1509 10 +2103 6 +1893 2 +238 5 +135 10 +3003 2 +2917 10 +3425 2 +2607 2 +2136 3 +2216 5 +1414 2 +1484 9 +3474 6 +3871 3 +78 1 +1613 4 +892 10 +3655 9 +3129 6 +832 9 +2100 5 +4092 3 +2112 1 +2649 2 +676 10 +3347 10 +424 9 +860 4 +3666 4 +1185 1 +1872 1 +1811 10 +213 9 +144 4 +3984 8 +3748 4 +1716 2 +2523 9 +482 4 +2002 1 +1501 6 +3333 5 +1641 9 +1867 7 +3138 10 +330 4 +3154 7 +710 3 +2139 1 +3269 3 +1694 3 +1437 5 +2333 4 +3433 4 +4 5 +2452 7 +3848 10 +944 7 +1822 7 +4025 6 +3936 9 +1309 10 +1496 1 +3341 6 +1435 3 +803 6 +3276 4 +971 8 +774 3 +2286 8 +1316 10 +3276 1 +797 5 +503 3 +4020 8 +2517 1 +452 6 +2644 10 +2338 9 +3013 10 +997 5 +3485 3 +556 2 +1037 5 +3610 9 +211 4 +4015 10 +831 10 +1715 3 +1365 7 +1098 2 +487 10 +111 1 +2022 10 +3957 7 +1276 1 +3879 9 +3127 2 +1973 9 +3891 10 +2944 6 +3106 2 +3939 3 +386 7 +1665 10 +2078 9 +1125 10 +1577 7 +3543 7 +853 3 +3798 8 +3801 7 +3169 6 +2880 1 +1540 10 +1518 7 +2083 9 +1616 9 +2814 7 +1787 8 +3727 4 +3708 6 +2186 7 +1693 8 +1577 10 +2225 3 +2065 4 +1931 7 +1138 1 +3381 3 +2675 1 +1153 1 +1507 4 +347 7 +1773 9 +2601 3 +133 1 +3813 10 +3061 1 +163 7 +168 3 +2578 3 +4076 2 +734 2 +999 6 +1907 2 +3972 4 +493 10 +870 1 +1613 7 +2118 7 +1742 9 +1165 9 +2074 10 +3320 3 +874 1 +2703 3 +1014 8 +1310 5 +3038 8 +2369 9 +984 9 +3684 4 +961 4 +1278 2 +1791 3 +3968 9 +1462 6 +2801 4 +146 6 +3717 8 +3445 10 +941 4 +1709 8 +3112 2 +3192 7 +3353 4 +2564 8 +639 6 +2140 7 +4056 4 +854 4 +719 9 +780 10 +2091 7 +2748 7 +1123 6 +773 4 +2572 8 +3240 6 +3156 9 +1985 4 +2845 2 +3011 2 +1830 9 +2768 7 +1079 8 +23 5 +1702 8 +3920 7 +2925 6 +2318 7 +3833 2 +1659 4 +164 9 +455 1 +3237 6 +3397 7 +1751 9 +1247 8 +3951 8 +659 5 +2424 6 +894 8 +4082 7 +2904 10 +3148 5 +444 8 +331 3 +3653 4 +166 4 +1331 7 +2053 8 +3411 6 +1266 7 +3971 1 +67 10 +866 9 +479 2 +2452 3 +434 5 +1926 2 +2563 3 +2434 5 +2808 7 +3612 4 +509 1 +146 5 +112 5 +726 1 +5 7 +1767 9 +213 5 +2630 6 +914 3 +2248 3 +295 3 +3251 10 +3771 3 +2556 5 +3851 3 +1227 4 +1444 10 +2455 4 +3500 9 +2382 4 +3745 1 +4040 10 +239 2 +3552 2 +1812 1 +404 9 +879 6 +593 2 +2620 8 +960 9 +2935 5 +3247 10 +923 1 +3362 4 +2746 4 +563 3 +228 9 +3501 6 +699 6 +72 7 +2701 2 +1265 3 +350 3 +213 1 +3267 7 +2167 4 +2325 1 +2896 8 +3789 9 +1296 4 +2459 3 +3485 3 +3459 7 +2028 10 +3655 4 +1965 9 +1673 6 +1843 10 +3491 5 +1532 9 +2204 4 +1427 10 +2541 2 +1947 5 +3718 6 +1105 5 +2498 3 +3322 6 +1985 5 +434 5 +2948 5 +1763 9 +248 2 +1467 7 +1719 4 +263 7 +3514 8 +2057 4 +1461 6 +993 10 +417 4 +1400 7 +1956 8 +3824 6 +964 10 +3822 8 +3459 8 +3676 1 +2537 6 +2853 7 +3629 1 +2855 8 +1975 1 +1607 1 +855 5 +1423 7 +1692 7 +1080 3 +28 9 +86 4 +3955 8 +2773 6 +1108 7 +55 6 +3905 7 +3796 7 +3143 8 +3808 8 +1687 5 +2304 1 +1328 6 +1150 9 +323 10 +2591 9 +2083 8 +1145 9 +3254 7 +2660 6 +2134 6 +317 2 +3971 6 +268 4 +155 10 +1067 6 +2810 7 +3214 3 +717 2 +3692 4 +3479 2 +2901 5 +2943 6 +1958 2 +3965 10 +1896 2 +1538 1 +2294 5 +3815 7 +1433 8 +2680 7 +1012 9 +191 8 +238 8 +3300 5 +514 10 +1643 8 +3348 8 +3547 7 +2874 8 +3090 3 +305 1 +3842 6 +3085 4 +2127 10 +3843 10 +3473 7 +2005 8 +1809 5 +3217 1 +2968 1 +3422 7 +76 3 +3216 4 +1470 1 +3350 2 +221 2 +382 4 +1982 10 +244 1 +1795 1 +1951 8 +1818 4 +393 9 +1339 2 +442 8 +479 9 +2304 1 +1068 5 +827 7 +2639 6 +2554 6 +1999 6 +4078 6 +1905 10 +3957 3 +2424 7 +1143 5 +486 1 +2832 6 +157 10 +4082 9 +1143 10 +649 5 +2647 9 +3693 2 +3595 4 +1778 9 +2170 9 +3830 2 +259 10 +1417 2 +1061 1 +2146 10 +1642 9 +463 8 +2849 5 +2323 5 +3355 5 +2378 2 +990 8 +2692 10 +879 7 +1674 8 +261 7 +3914 10 +1842 2 +887 4 +4036 7 +227 8 +1592 6 +720 1 +1761 6 +1326 6 +2286 10 +386 9 +2863 6 +78 6 +3986 9 +307 10 +445 9 +3940 7 +529 5 +939 4 +1459 4 +966 4 +3798 9 +683 2 +1323 8 +313 10 +3093 6 +420 2 +1586 10 +1256 5 +1726 5 +1772 1 +1464 6 +3980 10 +2147 2 +3727 8 +641 8 +1577 10 +1207 8 +4035 4 +562 2 +2492 8 +72 4 +1535 6 +2706 1 +2845 9 +1676 4 +730 3 +1964 9 +3894 9 +2393 6 +2790 2 +869 7 +1139 10 +1784 1 +2365 7 +1750 1 +88 1 +3565 5 +1199 6 +2526 4 +3472 9 +1295 1 +2082 1 +2587 5 +3150 3 +1238 1 +2562 8 +3926 5 +2277 10 +1317 10 +764 4 +1292 3 +2153 3 +3582 2 +1921 9 +256 6 +1318 1 +1202 1 +177 4 +1154 9 +2986 9 +3936 6 +3273 5 +290 6 +1024 10 +2780 4 +3986 5 +516 10 +249 3 +2905 10 +2844 8 +2862 7 +2524 1 +2837 5 +3402 8 +3161 10 +2999 9 +2960 10 +3824 3 +2495 10 +1385 2 +1335 8 +813 10 +1090 5 +3901 7 +1055 6 +656 9 +2570 4 +3329 5 +569 9 +2055 2 +2018 5 +306 7 +323 3 +2866 5 +2095 1 +3068 4 +3174 3 +571 4 +1682 3 +1345 2 +2909 1 +656 9 +1484 4 +3164 2 +2571 10 +3966 10 +3340 10 +3728 8 +7 2 +2608 4 +2421 7 +2362 1 +3003 10 +3149 2 +903 4 +3827 6 +1493 7 +1841 2 +858 8 +1451 1 +3172 3 +1973 1 +3439 3 +2296 3 +1634 2 +2457 1 +532 10 +1046 2 +3357 2 +2972 8 +825 9 +3344 4 +3911 4 +1051 4 +574 7 +3352 3 +534 4 +3882 1 +2328 7 +517 7 +3393 4 +1929 2 +1767 10 +733 5 +2664 1 +1410 5 +444 6 +1540 6 +968 9 +2640 6 +1875 8 +1901 9 +3463 6 +3969 6 +351 2 +3927 9 +909 8 +1050 7 +2546 1 +3510 4 +249 1 +3123 6 +163 3 +549 1 +3607 10 +1638 7 +3195 6 +3973 1 +104 5 +3502 9 +3134 9 +2764 1 +2263 9 +3943 7 +52 3 +849 1 +1057 2 +1287 5 +3156 5 +1769 7 +3908 3 +1059 1 +1455 4 +2934 2 +25 1 +2676 4 +3981 6 +3527 7 +1243 4 +1259 2 +3833 8 +1258 3 +772 6 +1262 7 +1837 7 +3722 5 +1901 7 +3677 10 +613 2 +3232 3 +776 10 +1169 3 +2073 2 +839 2 +617 8 +1811 5 +3395 1 +1528 3 +1681 2 +2428 4 +1405 4 +3810 3 +3260 6 +3019 9 +844 1 +74 10 +102 10 +3149 9 +1048 10 +808 9 +36 2 +2902 6 +2605 5 +1523 2 +2765 6 +1940 6 +3654 5 +3120 9 +2253 5 +1651 5 +757 6 +1246 9 +3442 2 +1811 4 +213 3 +3163 8 +3938 9 +405 2 +3465 10 +2497 9 +3963 4 +2858 3 +2911 1 +2586 4 +4093 9 +283 9 +3429 5 +74 6 +2552 8 +837 6 +3303 5 +727 7 +3844 5 +3646 2 +1480 10 +190 7 +1495 9 +2341 7 +2280 5 +3956 4 +3860 5 +2735 2 +2861 7 +2927 1 +2012 5 +477 7 +99 5 +3191 4 +813 3 +3000 8 +3213 5 +1658 5 +450 8 +869 3 +3025 7 +1170 2 +3437 6 +3514 5 +2433 5 +1333 6 +2050 7 +949 8 +2985 1 +3727 5 +889 9 +1630 3 +3443 4 +737 7 +1991 8 +1580 5 +3192 2 +2548 1 +968 7 +151 2 +535 7 +3856 5 +1164 10 +411 8 +1538 1 +2929 5 +1978 2 +58 10 +844 4 +1501 9 +1059 5 +2496 7 +343 2 +2893 8 +3966 7 +2075 1 +3105 10 +756 8 +1687 1 +3754 4 +3947 3 +3306 10 +1523 7 +3955 9 +6 9 +1945 1 +1488 10 +2653 8 +3688 8 +2749 8 +3167 8 +79 2 +1526 2 +1585 7 +2095 5 +768 1 +1069 4 +3216 6 +1781 3 +2165 3 +2393 5 +1828 4 +2526 1 +1814 2 +1977 9 +313 2 +1930 7 +3803 3 +2629 5 +452 9 +353 8 +961 9 +880 1 +2662 7 +3725 4 +1329 5 +1008 10 +763 5 +2644 8 +4013 5 +2516 7 +3550 5 +3797 7 +833 6 +3309 4 +2095 2 +439 1 +3984 2 +2296 7 +2670 4 +3352 8 +1106 7 +2232 3 +3932 4 +3922 10 +1295 4 +1182 4 +594 9 +815 1 +527 3 +3211 10 +1929 9 +1906 5 +280 1 +464 5 +2700 1 +2133 9 +3273 8 +4053 2 +2384 2 +2509 5 +1247 1 +3745 2 +910 1 +1524 5 +2412 6 +1260 3 +3277 2 +2078 2 +1625 10 +3767 10 +1966 1 +2711 10 +2454 7 +196 1 +1331 5 +659 1 +118 2 +3428 1 +749 9 +826 2 +2708 6 +1021 5 +407 2 +149 7 +3176 3 +3310 3 +3951 1 +2425 5 +1010 6 +119 9 +2677 8 +3760 8 +3345 8 +2116 6 +1001 5 +730 2 +1085 1 +2347 7 +2704 7 +3235 4 +3178 9 +2172 6 +1846 5 +2144 3 +1166 6 +1492 6 +3283 5 +3655 8 +1124 2 +64 1 +212 2 +1912 1 +1218 9 +1051 1 +996 6 +3157 5 +3308 2 +1891 1 +1235 6 +937 1 +1820 1 +597 1 +3382 1 +1882 1 +4090 3 +1612 2 +1884 1 +1009 4 +2989 7 +196 4 +1635 8 +3632 4 +253 9 +2051 1 +1045 9 +2473 9 +2292 7 +936 5 +1725 4 +327 5 +665 8 +2335 7 +2937 9 +2483 6 +3251 4 +407 3 +1280 2 +3407 10 +3574 10 +3480 7 +238 4 +3999 6 +618 4 +3899 5 +1123 9 +1492 7 +2447 8 +1335 3 +826 9 +2229 4 +3643 10 +2979 5 +4025 1 +2136 2 +2100 2 +1338 8 +2546 7 +3854 10 +1368 9 +2271 5 +2977 5 +1645 2 +1515 9 +236 2 +2812 8 +175 9 +627 6 +2281 2 +1236 2 +36 10 +2909 3 +3086 8 +3846 1 +1818 1 +332 5 +2912 9 +869 9 +3898 4 +1285 3 +172 6 +812 2 +2672 10 +2888 7 +1850 3 +3499 8 +1832 1 +1431 8 +2801 1 +1080 10 +443 6 +3893 5 +185 3 +2316 6 +50 6 +3849 9 +1137 2 +2962 2 +4079 10 +4014 3 +1702 3 +4055 9 +971 7 +2515 7 +2299 3 +1150 9 +2989 9 +626 3 +1572 7 +2233 5 +1392 5 +1257 3 +415 4 +598 3 +109 2 +3403 6 +3411 9 +1894 4 +678 2 +461 6 +2764 10 +3142 5 +2613 8 +2219 3 +3810 8 +3510 9 +1744 7 +3700 8 +1986 2 +2106 3 +756 2 +2888 1 +1485 8 +1857 8 +1187 9 +355 7 +3227 3 +4019 3 +2485 8 +2139 9 +3517 3 +3665 10 +3618 2 +3358 1 +1591 9 +1886 4 +746 5 +1721 10 +2471 2 +3938 9 +2506 2 +257 6 +3861 3 +3588 4 +3619 4 +2627 4 +2528 10 +1881 1 +283 5 +108 5 +583 1 +852 9 +3783 10 +1538 10 +3931 5 +545 8 +3042 1 +1533 9 +1555 2 +3840 5 +1863 9 +530 7 +1842 10 +3966 10 +699 2 +3960 2 +1644 4 +2685 1 +1162 6 +1059 6 +3406 3 +2804 10 +1028 1 +3754 2 +3937 2 +4020 10 +2036 4 +1653 6 +449 10 +739 1 +2067 3 +681 3 +296 3 +1138 9 +474 7 +365 1 +1211 1 +2919 4 +223 8 +3724 7 +3490 6 +3310 4 +1509 2 +2406 5 +3450 9 +3188 3 +2492 4 +3031 3 +3321 1 +2125 10 +4070 4 +2449 6 +1269 7 +3132 1 +733 10 +120 3 +2009 7 +4013 5 +17 10 +2805 7 +2016 6 +3240 7 +2478 8 +3622 8 +1511 8 +1567 6 +2208 10 +2421 6 +3722 8 +2612 1 +1459 5 +863 6 +3812 10 +2234 2 +1230 7 +3000 2 +1165 9 +472 1 +2724 2 +18 1 +915 10 +3744 8 +2865 4 +520 1 +2297 9 +3469 8 +3748 6 +3301 8 +1674 6 +1260 4 +677 9 +2398 4 +3377 6 +1748 1 +2111 2 +2876 7 +3086 1 +1776 2 +3505 7 +2367 7 +3830 8 +3390 3 +2124 8 +3984 7 +2916 10 +2396 10 +1677 4 +3013 6 +3362 10 +1284 2 +3097 5 +2508 1 +2664 5 +721 5 +3878 2 +3689 9 +1648 7 +2708 4 +3937 7 +3415 10 +2761 3 +1848 4 +3019 4 +2555 3 +111 6 +3243 6 +3377 9 +1007 2 +3769 3 +75 1 +1195 8 +3968 1 +1205 5 +3756 2 +1689 7 +2596 7 +2909 10 +3807 2 +2871 6 +891 5 +3409 10 +1890 9 +3724 9 +3611 6 +1052 1 +1946 7 +1375 3 +3432 3 +3178 8 +2517 1 +3172 3 +3873 8 +1527 4 +1220 5 +85 6 +3112 7 +2539 6 +980 5 +1022 2 +1934 10 +58 10 +1859 7 +143 3 +706 2 +776 6 +4088 7 +2987 8 +1736 2 +501 7 +416 5 +3276 7 +77 7 +133 8 +3566 8 +3177 7 +587 3 +2859 10 +656 4 +2130 8 +2668 9 +1738 1 +2399 10 +2485 4 +3758 8 +1255 3 +2870 8 +3970 9 +2660 1 +2949 8 +582 10 +3207 2 +2460 6 +1037 2 +2300 8 +1438 4 +4064 2 +1513 3 +47 4 +494 6 +206 7 +1883 5 +1907 2 +736 4 +4037 3 +3008 7 +2975 10 +2136 4 +3351 1 +1895 4 +2824 5 +1546 8 +1755 6 +3513 5 +3462 5 +1907 3 +3329 5 +1296 3 +2762 9 +2642 9 +82 6 +2056 5 +3469 9 +605 6 +3834 3 +1662 8 +2204 5 +2231 7 +146 4 +2484 6 +3002 1 +1163 3 +624 6 +3993 2 +2431 3 +1430 9 +1017 7 +3450 2 +3416 3 +3215 4 +2245 4 +2873 1 +2984 9 +439 6 +1604 8 +2761 6 +3029 1 +3048 4 +1137 10 +1633 9 +227 4 +1271 2 +2495 4 +1169 9 +1108 9 +2174 10 +760 1 +1547 4 +3924 9 +604 7 +3079 6 +885 2 +2456 3 +1240 5 +1766 4 +1145 8 +2033 5 +243 9 +741 9 +1280 8 +268 7 +1348 10 +2468 6 +1947 2 +3334 6 +2374 8 +1100 3 +1003 2 +1812 1 +1689 7 +2109 2 +869 10 +2552 9 +2960 5 +2530 9 +1542 8 +136 1 +106 1 +3308 3 +3104 1 +618 8 +2468 3 +274 9 +2516 2 +2462 10 +167 9 +1544 3 +24 3 +3147 10 +1578 3 +1684 10 +1813 3 +5 1 +3684 4 +597 4 +14 4 +3326 2 +3728 1 +3867 3 +1580 3 +2587 10 +258 10 +669 1 +3150 1 +2015 7 +3335 4 +233 9 +2223 3 +1279 1 +2399 8 +1167 10 +764 6 +243 10 +3235 10 +2591 7 +1599 3 +359 9 +2827 4 +3682 1 +1980 8 +3899 7 +2449 1 +1698 3 +2179 4 +827 1 +725 10 +1837 9 +994 6 +1699 3 +2040 10 +1349 5 +3794 6 +1975 3 +899 9 +1515 2 +2600 10 +786 1 +1387 3 +2082 5 +3476 8 +821 6 +3768 2 +3541 4 +3394 9 +101 1 +1668 4 +3432 2 +1090 6 +2710 7 +2464 4 +783 4 +1648 6 +1163 6 +3060 8 +1299 8 +387 10 +3744 6 +86 1 +3529 8 +1085 2 +478 5 +2557 1 +1208 8 +3767 4 +3163 2 +3179 4 +2419 6 +4022 9 +945 6 +2826 7 +2412 3 +2783 7 +2515 10 +3818 5 +42 8 +2945 10 +659 2 +612 4 +2484 10 +507 4 +2027 10 +509 7 +1775 7 +219 10 +3733 5 +1724 3 +2606 3 +270 5 +3653 1 +446 9 +2719 7 +4095 9 +2103 8 +2007 6 +3257 7 +859 1 +3995 6 +2388 6 +1915 5 +3262 8 +2459 6 +2279 6 +3530 2 +2919 8 +2965 6 +34 2 +2017 5 +1253 7 +3971 4 +2495 7 +2716 9 +1389 4 +4077 1 +1104 4 +1028 4 +3428 5 +1546 4 +299 6 +3312 6 +1072 5 +2479 4 +2192 1 +2238 1 +3105 10 +1571 6 +1337 2 +2908 10 +1875 2 +1750 5 +401 7 +1336 1 +391 3 +2926 6 +1003 8 +4024 3 +3327 10 +1976 7 +83 7 +2317 4 +1943 9 +2391 3 +1602 2 +3199 10 +814 5 +1774 1 +3056 9 +3815 3 +1400 3 +646 5 +1686 4 +490 2 +2353 2 +277 3 +2074 9 +3402 8 +3429 9 +2517 5 +1931 5 +1980 8 +2791 1 +3549 2 +2698 4 +2777 6 +3019 4 +4079 9 +792 5 +1955 5 +3295 9 +1284 7 +3477 1 +1507 8 +1621 2 +392 2 +3275 7 +928 7 +2196 8 +303 3 +1769 5 +1724 1 +3960 1 +3209 6 +3037 1 +1241 10 +3146 4 +782 10 +2661 5 +2943 8 +3586 6 +340 9 +2135 7 +1911 9 +2699 6 +95 8 +3039 2 +2367 7 +2958 5 +3882 9 +3449 8 +243 10 +552 9 +2760 8 +2455 10 +3781 10 +947 3 +2362 3 +1366 5 +2659 1 +1249 6 +2635 6 +1623 7 +3472 1 +2849 5 +1229 4 +2687 10 +1355 2 +1584 9 +3270 2 +3116 9 +2472 2 +2153 9 +3907 7 +621 2 +3047 5 +3107 6 +3363 7 +3685 2 +1547 1 +979 7 +974 3 +2389 3 +2831 8 +2506 3 +1606 3 +1470 5 +1346 4 +591 10 +1795 1 +1332 7 +4040 6 +297 8 +1954 4 +3511 6 +1782 7 +1520 9 +2969 5 +2671 9 +3977 7 +2638 4 +3619 7 +786 3 +3257 3 +763 4 +2652 6 +155 10 +599 1 +3494 7 +552 3 +3219 3 +1255 3 +1876 6 +3060 1 +900 6 +2407 3 +1507 1 +792 8 +1845 10 +2111 2 +2230 5 +2385 6 +2740 6 +2447 9 +911 1 +2998 4 +1109 4 +869 5 +1662 6 +4048 9 +914 8 +2359 10 +216 6 +378 8 +2837 1 +3926 10 +3501 3 +3393 6 +4007 1 +1902 4 +3258 5 +538 4 +2889 5 +2581 8 +2136 9 +719 5 +2366 6 +1234 6 +2322 10 +3818 3 +1252 1 +1789 6 +1990 9 +2398 1 +1553 6 +2756 9 +473 1 +3485 7 +3505 6 +1284 3 +2581 5 +1242 6 +1747 1 +942 9 +1096 3 +1135 3 +1890 1 +1320 8 +1667 1 +1116 2 +3184 7 +939 9 +3598 3 +526 4 +1118 1 +1665 1 +1227 10 +1265 4 +3687 10 +2978 10 +2239 2 +815 3 +2967 7 +1659 8 +3103 4 +1883 1 +3833 8 +1532 7 +643 7 +617 3 +3370 8 +3932 8 +747 4 +2065 4 +3693 10 +2748 8 +2243 1 +1536 4 +3248 9 +1416 4 +3548 5 +2847 3 +2237 4 +1162 6 +3825 5 +2114 10 +3252 6 +1964 9 +3489 3 +562 8 +202 1 +1575 3 +200 2 +3315 9 +1280 3 +2739 3 +1078 7 +3897 2 +1554 5 +1255 7 +1343 4 +1977 5 +1749 6 +2750 3 +2046 9 +3983 10 +3405 7 +922 5 +1938 2 +3494 6 +3635 2 +3980 3 +2397 8 +3953 1 +60 7 +1387 6 +362 3 +2219 2 +1653 10 +1805 10 +3002 8 +2108 6 +3855 7 +171 5 +3775 4 +1388 4 +709 4 +699 10 +1828 5 +3516 8 +312 4 +2154 10 +2842 7 +1965 3 +1431 9 +1067 8 +3379 9 +3313 4 +1866 9 +886 3 +3556 9 +3018 10 +179 8 +3483 6 +2181 7 +265 8 +2894 4 +760 9 +112 6 +2990 9 +850 4 +2042 10 +3815 5 +2783 10 +675 3 +2881 8 +677 6 +1226 4 +3428 5 +359 5 +579 3 +1254 6 +1816 6 +570 7 +3744 4 +44 9 +3334 5 +3261 8 +1909 6 +2931 1 +1659 3 +492 7 +1073 4 +887 2 +841 2 +2602 2 +3509 8 +603 10 +1714 4 +1821 3 +809 9 +224 1 +3666 3 +3812 6 +3970 3 +3649 6 +50 3 +3019 4 +337 5 +2172 7 +1856 3 +3381 3 +2345 5 +2569 8 +1495 1 +143 4 +822 3 +1152 4 +325 6 +1158 4 +969 1 +2245 7 +4003 2 +1184 8 +1384 7 +2700 5 +638 2 +2678 5 +318 9 +285 4 +266 6 +4054 4 +2122 6 +2459 1 +3677 8 +2581 6 +1368 8 +2160 3 +3780 4 +620 1 +2793 4 +457 7 +3707 3 +857 5 +2506 9 +99 10 +1180 9 +2180 9 +1890 7 +4050 3 +1183 5 +2802 1 +3624 2 +1006 6 +2492 5 +1166 5 +3142 7 +543 7 +2801 3 +2949 10 +1413 8 +2872 6 +2388 10 +1403 6 +2665 8 +2479 9 +3318 7 +110 8 +3980 6 +738 10 +3142 10 +1171 10 +790 10 +3130 10 +964 8 +606 8 +2039 1 +3452 8 +1297 5 +3460 2 +3782 6 +1166 9 +4016 10 +2143 1 +4041 10 +2028 9 +3978 6 +3559 7 +1250 5 +2541 9 +2820 7 +1870 1 +560 3 +819 7 +1609 7 +2502 9 +390 10 +1708 3 +118 1 +521 6 +3816 6 +3859 4 +1345 6 +2919 9 +2643 7 +1412 5 +1989 10 +2703 6 +2515 1 +2868 3 +3693 7 +455 7 +1093 2 +2679 2 +2363 9 +3000 1 +2765 5 +290 7 +1684 7 +3626 6 +3971 5 +1148 6 +2333 3 +747 9 +2110 2 +3879 6 +2762 9 +2628 2 +1588 3 +1640 5 +2527 8 +1003 6 +3761 8 +2203 1 +941 5 +1764 10 +1998 7 +1486 5 +1778 9 +1418 6 +337 1 +3546 9 +362 5 +2899 7 +3449 4 +3803 8 +950 7 +1249 8 +2378 9 +99 10 +1556 4 +2744 2 +3619 2 +2238 9 +3069 9 +3224 7 +1837 7 +2342 1 +1946 9 +4086 6 +1742 9 +1820 1 +1183 10 +1308 4 +3928 6 +1287 9 +3580 8 +44 1 +2977 6 +1350 9 +1425 7 +1066 2 +2408 9 +1575 2 +2153 5 +3102 4 +135 9 +2758 3 +3540 9 +2125 2 +3796 5 +1795 4 +2676 8 +2096 10 +1415 9 +1715 7 +698 4 +3273 7 +1510 4 +2942 7 +2997 9 +2941 7 +2202 3 +4062 10 +590 1 +3500 5 +627 10 +2489 2 +581 3 +1042 8 +1675 6 +43 7 +131 2 +3194 2 +819 4 +1607 7 +3809 1 +2648 8 +3470 2 +2942 9 +2001 5 +1924 7 +3722 5 +222 9 +3344 5 +3909 2 +2361 2 +2594 4 +1451 9 +3194 6 +1582 4 +120 9 +2885 1 +2690 5 +1055 3 +2236 2 +3249 2 +1360 7 +2533 9 +1395 8 +3741 7 +1236 4 +2317 1 +1469 10 +3676 5 +1420 7 +1500 5 +2717 6 +2934 2 +2777 9 +1271 6 +1889 1 +1360 4 +1969 2 +1 8 +1097 2 +285 2 +3900 9 +98 6 +2889 8 +1734 3 +1370 4 +3999 2 +2008 2 +3511 9 +978 6 +3747 7 +1106 8 +804 3 +2414 6 +1744 1 +3141 4 +2357 5 +2289 7 +628 6 +2054 3 +1367 8 +1695 2 +4061 4 +1786 5 +3531 7 +33 5 +742 1 +2882 7 +2326 9 +3730 8 +2581 5 +309 10 +1523 5 +2461 9 +1090 10 +245 9 +1961 8 +3826 4 +54 4 +1745 10 +505 6 +2734 4 +2879 7 +1429 9 +1780 10 +3763 8 +2085 2 +3185 5 +2030 3 +2534 4 +919 4 +2008 5 +2816 5 +27 10 +416 3 +2021 5 +243 10 +40 8 +2354 7 +1027 7 +4095 2 +2714 8 +470 10 +588 4 +772 2 +3791 7 +3294 5 +835 5 +449 8 +3746 3 +3762 4 +1143 1 +3125 7 +3422 8 +1590 4 +685 9 +4014 7 +1522 1 +2477 1 +214 7 +1584 3 +519 8 +906 5 +1375 1 +1575 2 +893 9 +3991 2 +4075 3 +2622 7 +153 7 +3756 6 +3697 7 +1795 10 +595 8 +629 9 +2880 9 +1810 5 +588 8 +2662 2 +1139 10 +569 5 +1782 2 +3787 7 +3767 1 +1391 3 +627 8 +2146 8 +2783 6 +2053 9 +1052 3 +1296 7 +634 10 +705 6 +2795 4 +2854 2 +1760 1 +3363 10 +1466 5 +56 5 +851 1 +2764 7 +1497 3 +1736 5 +1941 6 +2446 10 +241 2 +229 10 +3804 6 +3108 5 +1487 9 +3061 1 +858 5 +2141 9 +2349 4 +3767 9 +1256 4 +1550 6 +3940 3 +1370 8 +1105 10 +3710 8 +1315 6 +2278 9 +997 2 +214 7 +2548 6 +2822 7 +1375 9 +2782 7 +3766 9 +581 7 +876 5 +3832 4 +2883 5 +2986 7 +4065 7 +3648 8 +145 1 +1937 4 +4011 3 +1086 10 +3544 8 +1886 10 +237 7 +3133 2 +364 3 +819 1 +781 5 +2542 5 +2604 7 +2559 6 +3899 10 +3298 2 +966 5 +395 9 +3784 1 +4078 8 +2710 3 +4042 7 +3175 10 +2684 9 +3774 7 +383 2 +3091 6 +4046 1 +3959 8 +3781 1 +2175 6 +740 6 +411 5 +1898 6 +2382 8 +547 8 +3019 3 +523 6 +283 9 +3178 3 +1883 7 +2690 1 +3197 8 +1920 4 +146 7 +3725 7 +1329 2 +917 9 +1706 7 +3474 6 +1181 6 +2814 4 +3708 7 +1462 4 +878 7 +269 4 +3182 2 +2670 3 +2691 10 +2122 9 +2636 7 +1210 10 +3383 4 +1149 2 +653 3 +1396 1 +2248 5 +3643 1 +1201 2 +2968 5 +2970 8 +175 5 +1271 10 +2576 10 +2053 1 +1152 4 +2494 4 +1518 8 +3679 3 +41 9 +948 3 +3693 10 +140 9 +1344 2 +4017 4 +1112 4 +1346 7 +715 6 +2235 3 +775 5 +3889 4 +366 5 +1064 2 +890 10 +2363 3 +3281 4 +1309 10 +3842 9 +2127 1 +1367 5 +1636 1 +3201 9 +823 4 +708 9 +1983 9 +1512 3 +2129 2 +501 7 +1491 6 +3694 4 +2763 10 +2142 8 +4078 10 +3497 3 +880 2 +2604 7 +3884 5 +336 2 +2806 2 +1601 10 +1318 8 +189 1 +3017 6 +2059 10 +53 9 +340 1 +804 1 +508 9 +2675 10 +2330 8 +3161 10 +2351 5 +1687 1 +1371 3 +2029 5 +2386 6 +131 3 +986 10 +666 5 +2479 2 +3762 3 +1889 6 +120 8 +171 10 +2181 7 +2300 7 +1117 2 +3836 3 +1859 9 +2446 2 +842 5 +2529 2 +1749 4 +1705 8 +757 7 +664 6 +3193 2 +82 3 +1006 9 +2332 1 +3011 5 +4090 7 +2689 7 +1373 4 +2161 4 +3314 10 +1193 5 +1015 8 +2770 7 +2225 6 +621 5 +128 4 +137 7 +2432 6 +2231 2 +2693 3 +1964 9 +654 4 +943 10 +995 8 +2439 7 +2169 6 +662 5 +832 7 +1131 1 +1045 5 +3220 9 +506 2 +2067 4 +915 7 +658 6 +3416 6 +1950 8 +2760 3 +2297 7 +4051 10 +1467 1 +2248 2 +2795 2 +1615 9 +772 4 +3245 4 +288 7 +834 5 +3795 4 +2689 2 +2726 3 +2606 10 +1767 5 +72 10 +2680 4 +2656 4 +2325 6 +3643 8 +3035 8 +1738 8 +684 3 +3832 8 +3728 1 +2275 10 +3107 10 +685 3 +3846 4 +1982 3 +1690 1 +2032 6 +1210 8 +1781 2 +3382 2 +2247 1 +690 1 +3735 1 +1611 1 +2958 1 +3543 2 +3484 7 +3383 4 +1395 1 +2098 9 +1474 5 +89 6 +509 7 +1644 4 +600 8 +462 10 +59 4 +946 6 +2324 6 +2871 1 +996 6 +1638 2 +323 7 +3103 6 +2134 7 +1541 5 +2401 4 +1727 6 +3397 8 +1731 5 +3671 1 +3651 8 +3635 6 +2892 2 +2833 8 +2641 8 +3525 2 +3738 2 +3686 10 +3111 2 +278 4 +1384 10 +548 3 +3772 7 +3536 6 +481 5 +3748 10 +4052 7 +572 7 +2653 7 +3797 4 +3867 10 +1799 1 +2206 3 +1947 4 +870 4 +1611 6 +2400 6 +438 10 +2292 2 +2975 2 +2863 3 +3747 10 +3738 2 +1865 4 +2427 6 +3084 6 +4044 4 +1387 6 +3262 1 +693 7 +1125 10 +797 5 +1355 9 +957 6 +3781 10 +2182 1 +1077 10 +70 9 +930 7 +3118 5 +1067 2 +926 7 +3068 5 +2984 3 +2713 7 +3882 1 +3359 4 +2119 6 +692 10 +3093 10 +3144 3 +1783 10 +2775 8 +732 5 +2138 4 +291 5 +830 8 +3752 5 +3154 7 +613 10 +1945 10 +1703 7 +3138 4 +3954 8 +3963 5 +1989 6 +3506 2 +2544 8 +556 8 +3623 6 +1378 1 +1324 9 +21 6 +164 10 +1064 8 +1277 5 +3024 2 +3754 8 +2917 2 +3126 10 +2715 9 +50 3 +495 2 +2961 1 +921 3 +2361 7 +43 8 +2014 10 +568 3 +2542 1 +1475 2 +2515 10 +2829 4 +672 9 +3836 1 +607 4 +744 8 +2107 7 +3118 8 +885 10 +800 10 +1649 8 +772 2 +3713 10 +2800 7 +1421 9 +2111 1 +367 3 +1137 4 +2645 10 +1226 4 +1095 8 +3364 10 +2810 8 +3614 8 +767 4 +3589 1 +340 5 +2647 5 +3762 7 +2526 6 +844 2 +2353 10 +1499 2 +1824 8 +4043 8 +1580 9 +2023 8 +581 7 +2697 9 +3806 7 +3330 2 +2796 4 +106 7 +1667 6 +3121 9 +491 8 +1080 6 +959 9 +961 2 +3875 9 +1256 4 +2327 2 +3024 5 +3579 8 +635 1 +4051 8 +364 9 +737 5 +1404 5 +3039 4 +1559 5 +3169 3 +3517 6 +2128 4 +3883 4 +1955 1 +983 4 +1682 3 +2348 3 +445 9 +949 1 +1529 1 +3623 8 +836 1 +464 6 +2192 2 +3156 2 +2592 10 +648 6 +763 6 +1012 3 +3458 1 +3242 4 +2700 1 +3724 10 +3058 10 +432 3 +2621 10 +1386 1 +3954 8 +713 3 +3324 5 +3680 9 +3210 9 +3257 4 +2281 4 +2674 1 +3355 8 +3129 1 +1323 3 +3924 10 +337 6 +1993 4 +1410 5 +3095 2 +3873 10 +3867 4 +3841 9 +1699 9 +2316 7 +2441 1 +1398 5 +1372 8 +3995 4 +2726 7 +861 9 +1707 7 +3939 10 +776 1 +1101 9 +2112 6 +2337 1 +1129 3 +109 1 +2993 5 +1271 7 +1855 5 +1510 6 +2564 9 +1272 1 +2118 5 +746 5 +598 6 +1460 1 +3752 4 +2891 2 +841 9 +2446 10 +1140 10 +540 1 +3855 5 +2087 4 +2580 2 +1335 2 +1649 7 +4039 5 +3382 10 +477 10 +1215 5 +2158 1 +1163 9 +614 8 +3517 3 +2429 3 +3744 5 +342 9 +3027 1 +2399 6 +3211 4 +917 8 +513 10 +1910 1 +2413 1 +25 9 +605 7 +689 7 +273 9 +2299 8 +720 2 +1356 4 +1476 8 +3038 8 +1046 1 +638 5 +3954 7 +3113 5 +2904 3 +2826 7 +366 2 +1060 1 +3101 4 +3623 1 +1046 6 +1648 8 +2319 10 +2580 7 +2740 7 +2132 8 +77 8 +1541 7 +431 1 +2630 6 +1872 7 +1048 9 +3717 2 +1889 7 +2224 4 +1570 1 +3920 3 +2350 1 +1044 10 +873 9 +1551 10 +3882 1 +2499 2 +2603 6 +2066 10 +843 8 +3173 1 +2002 7 +1935 3 +1349 6 +2279 9 +3933 8 +4052 6 +1380 3 +3553 5 +3262 1 +1718 10 +2127 5 +3522 8 +218 2 +3081 6 +2212 8 +1414 4 +217 6 +3319 10 +4093 9 +60 2 +1841 9 +2929 3 +465 2 +3793 6 +1815 6 +3592 3 +649 1 +1222 9 +3654 9 +1126 9 +1883 3 +2413 6 +3066 10 +784 2 +403 6 +2530 8 +2289 4 +3445 1 +3904 1 +1237 6 +1146 4 +2062 10 +1773 2 +483 7 +389 10 +3913 9 +3234 4 +2214 5 +3441 4 +3730 3 +1729 5 +20 3 +1698 6 +2113 1 +2545 9 +1532 9 +3480 2 +3967 10 +202 1 +3625 10 +906 1 +2771 9 +1194 4 +3498 10 +2758 2 +1058 1 +2733 3 +1833 8 +3340 8 +2451 3 +597 8 +3409 9 +3920 5 +2411 4 +3056 6 +181 9 +2203 2 +893 2 +2040 9 +1594 1 +1887 6 +2415 7 +2968 8 +1160 4 +54 1 +2270 7 +3801 8 +3270 4 +2981 6 +1512 6 +2325 6 +2816 3 +3150 7 +4048 2 +2805 8 +3535 7 +3593 10 +3500 10 +3281 2 +1360 10 +3597 4 +2721 4 +343 10 +258 4 +1255 9 +1939 8 +2824 1 +1726 3 +3129 7 +2754 1 +1694 2 +1952 8 +4061 2 +89 3 +1078 9 +2207 1 +771 4 +3160 6 +2529 10 +1275 10 +3569 7 +2421 7 +1878 8 +221 5 +2530 5 +2271 10 +1718 5 +2790 3 +1023 5 +1544 8 +1108 5 +191 1 +2823 8 +3379 8 +289 2 +1688 5 +4060 3 +2126 9 +3701 2 +1720 5 +2772 6 +3700 2 +2136 8 +1689 7 +3815 4 +224 2 +1875 2 +2927 5 +1911 7 +1582 3 +1257 5 +434 1 +457 1 +2981 4 +198 8 +3030 3 +3133 9 +2475 8 +3167 4 +690 6 +1754 8 +2109 6 +35 1 +3007 6 +1491 7 +2420 3 +2540 1 +3714 3 +1454 4 +2217 8 +2945 8 +3523 3 +2892 4 +2897 6 +1730 5 +4003 4 +2276 8 +3587 7 +3226 6 +0 7 +916 4 +903 8 +3079 5 +1591 3 +1633 1 +1316 2 +3577 8 +2644 7 +893 2 +77 4 +140 7 +2672 6 +1022 6 +1499 2 +1639 10 +1104 1 +737 2 +1403 8 +159 2 +1386 9 +1607 8 +277 10 +2007 7 +1950 3 +6 7 +3642 10 +897 2 +2337 8 +2005 9 +1552 10 +2996 9 +2807 3 +3706 3 +2722 7 +738 3 +3131 4 +769 5 +839 9 +579 3 +376 3 +127 7 +2292 9 +2064 6 +293 3 +2664 7 +3159 1 +1316 3 +3741 10 +2200 2 +3235 8 +1615 6 +3673 2 +2027 1 +2041 3 +2158 9 +502 3 +3259 6 +2920 9 +2991 9 +750 5 +595 10 +77 4 +3058 10 +21 2 +2507 2 +1414 7 +2714 7 +2649 1 +2054 8 +2386 10 +2074 4 +3972 9 +1599 3 +984 3 +910 2 +1353 7 +103 8 +1232 2 +1963 3 +3550 5 +1089 3 +83 8 +2172 8 +2716 8 +2012 4 +3828 4 +3398 8 +60 3 +3319 5 +258 3 +2440 10 +1001 6 +1323 7 +3974 5 +3416 9 +2292 3 +3393 7 +3653 10 +826 8 +165 2 +2911 3 +2145 10 +3586 7 +2063 1 +3343 4 +429 1 +1006 10 +3920 10 +3762 8 +3335 5 +911 2 +2266 7 +3226 4 +3291 8 +2664 9 +2491 5 +3306 8 +3442 1 +1825 10 +640 6 +1598 8 +3616 1 +3793 3 +2566 10 +1866 7 +2764 6 +2351 7 +1548 9 +322 4 +2280 1 +3559 8 +1545 9 +3684 3 +1570 7 +3097 8 +858 6 +3959 6 +1860 1 +2740 2 +1148 9 +3830 1 +2356 8 +2609 4 +1264 2 +3457 5 +413 5 +327 4 +1687 1 +749 1 +1883 9 +1180 10 +337 5 +498 7 +28 9 +1865 1 +3618 1 +1249 9 +1827 7 +1126 6 +725 5 +3055 5 +1678 4 +803 4 +1274 4 +892 1 +1335 1 +17 1 +2755 8 +1539 8 +263 10 +3628 2 +1536 6 +3625 2 +2750 8 +1723 3 +754 2 +1215 1 +2468 5 +1915 7 +2581 5 +2083 2 +2500 6 +1408 1 +3553 7 +491 7 +2703 10 +3716 10 +2080 6 +3910 6 +2597 1 +2884 10 +2393 2 +3050 6 +353 3 +2432 3 +1449 8 +1730 9 +3401 8 +2603 3 +3666 5 +3757 7 +3451 6 +2631 3 +3513 4 +2051 3 +249 6 +100 8 +3249 1 +2676 8 +3349 2 +595 9 +260 3 +1321 2 +613 1 +609 6 +733 9 +3565 3 +2844 5 +1077 4 +1335 5 +56 6 +1635 1 +749 8 +3556 7 +3628 10 +707 3 +1128 9 +4037 8 +2115 9 +500 9 +205 7 +3402 6 +3212 4 +2871 5 +3626 10 +2295 1 +1035 10 +576 2 +804 6 +3995 8 +444 1 +172 7 +426 3 +2358 6 +790 2 +354 6 +707 6 +821 5 +3885 2 +1713 8 +3784 6 +3039 8 +558 8 +3662 4 +1602 6 +3633 5 +3148 7 +2544 1 +2897 2 +1868 8 +2020 5 +4075 9 +3637 8 +3963 6 +2467 10 +2682 8 +86 8 +3390 2 +3339 4 +1037 7 +89 10 +2146 5 +1745 6 +3121 6 +2060 1 +3569 6 +357 4 +1103 1 +111 1 +3413 2 +1193 8 +563 5 +2826 8 +3744 7 +375 6 +1013 6 +1568 6 +2868 3 +1608 7 +1941 10 +968 6 +3423 8 +2918 7 +1782 6 +2209 1 +167 1 +2760 8 +1729 10 +1217 4 +2875 2 +2347 7 +1611 7 +2309 3 +119 2 +723 10 +3352 8 +4079 1 +1694 7 +1800 7 +2296 4 +2053 3 +2343 1 +3538 8 +1106 1 +240 3 +3200 10 +538 6 +2704 9 +3566 4 +3644 7 +3603 3 +2059 10 +1172 1 +3726 8 +2693 2 +1746 9 +220 3 +1058 1 +2733 5 +346 1 +3561 8 +2016 7 +1905 7 +1291 2 +794 3 +2621 1 +2879 7 +1422 8 +3040 5 +966 6 +346 3 +4074 8 +3107 3 +250 6 +1903 7 +1823 7 +1941 3 +1193 8 +656 3 +3856 10 +3578 9 +1671 3 +1408 1 +3973 4 +1335 5 +2952 3 +3572 1 +567 7 +2517 3 +3453 4 +3350 10 +2637 9 +3576 9 +3449 2 +1793 1 +3411 3 +2143 7 +1627 10 +1174 7 +342 6 +850 5 +2827 5 +1367 3 +2783 8 +364 3 +1103 6 +3247 3 +2149 3 +2201 3 +2631 5 +4090 3 +3626 7 +1042 2 +972 6 +1913 4 +143 10 +2251 5 +1762 5 +2310 4 +2592 8 +1443 4 +1123 3 +716 9 +3583 7 +2524 5 +3119 10 +23 9 +1015 6 +3945 4 +4069 3 +3508 4 +3067 9 +693 1 +262 8 +2509 6 +2148 6 +2193 9 +1492 6 +2472 6 +895 8 +2772 10 +400 2 +786 2 +2090 1 +2208 3 +479 9 +356 4 +2267 8 +1695 8 +792 9 +2903 5 +3171 6 +1243 9 +2349 2 +3895 10 +491 10 +3972 7 +713 2 +3522 4 +2937 8 +1718 7 +1770 8 +807 5 +3955 1 +270 9 +2996 1 +647 5 +1867 7 +3583 1 +3476 10 +1452 10 +3630 10 +1799 4 +711 10 +1450 10 +3530 6 +635 10 +2022 7 +495 8 +3385 10 +1741 7 +1236 2 +643 5 +4066 5 +3752 6 +875 9 +3582 1 +2377 7 +2184 10 +3864 5 +1079 3 +3044 10 +3813 2 +3966 9 +629 5 +2299 6 +1582 2 +1480 5 +3984 1 +1689 1 +1082 2 +3190 8 +646 1 +1348 5 +589 7 +1961 2 +2145 6 +1364 2 +2677 1 +188 1 +2570 4 +2986 4 +3024 1 +223 2 +3571 7 +2605 6 +919 8 +479 6 +1142 2 +199 8 +2507 4 +3255 9 +1555 3 +1862 4 +1569 8 +4003 2 +969 8 +2461 5 +678 7 +1907 9 +1502 3 +2990 4 +1026 5 +3877 6 +2041 9 +3876 1 +301 7 +432 3 +2509 6 +928 6 +1432 2 +3112 6 +3095 4 +1818 5 +2142 5 +3986 1 +32 7 +1349 4 +2403 1 +1060 5 +1802 7 +555 9 +4018 4 +3565 7 +2161 10 +2194 4 +3926 7 +2095 9 +3729 3 +217 7 +352 10 +2548 8 +3679 6 +2553 3 +1063 10 +1533 2 +3447 6 +1027 10 +712 6 +1118 5 +3083 10 +873 9 +3612 4 +2727 5 +729 1 +1895 3 +2700 9 +4078 6 +4089 7 +3265 7 +1583 1 +3546 5 +2689 2 +1640 4 +3344 7 +134 4 +3114 3 +2242 4 +2980 1 +1594 4 +3626 4 +3225 8 +3137 4 +1634 1 +2588 7 +3933 1 +844 1 +1466 2 +3288 9 +3192 1 +1987 2 +2357 6 +16 5 +2817 10 +128 2 +1160 10 +2992 10 +2502 5 +3972 9 +2395 3 +1275 7 +625 4 +907 2 +2265 7 +3172 4 +3225 7 +77 3 +2146 2 +2817 2 +3845 9 +3691 8 +600 8 +611 2 +417 7 +2645 10 +75 9 +711 1 +564 4 +151 4 +3541 8 +3038 3 +3912 9 +3342 3 +9 9 +1553 10 +3576 6 +1170 4 +98 6 +2700 6 +3086 3 +2591 2 +413 7 +2521 8 +3016 7 +1118 7 +4000 10 +1018 8 +722 10 +3952 1 +3646 7 +3920 4 +448 7 +3415 2 +2990 2 +984 5 +1211 5 +1659 8 +1928 3 +1319 2 +774 3 +3266 8 +752 7 +2279 10 +2854 6 +2941 9 +3060 2 +2874 1 +3549 1 +3379 8 +751 7 +3009 5 +3099 2 +233 1 +3321 3 +1889 4 +2192 9 +3140 3 +1338 2 +1980 1 +3517 6 +1434 1 +1576 9 +3398 10 +1951 8 +3785 2 +3229 10 +497 7 +1914 9 +82 7 +2467 10 +1546 10 +3857 9 +1230 9 +266 3 +1664 6 +3702 4 +480 8 +3512 5 +123 5 +3271 7 +3467 3 +3861 9 +455 8 +1743 9 +2004 2 +726 7 +4059 6 +2982 10 +681 3 +3533 6 +2857 3 +2731 10 +3075 10 +217 1 +2691 9 +2311 9 +30 1 +2142 2 +3943 6 +1285 2 +1664 5 +3455 5 +3493 3 +467 4 +1220 3 +439 7 +2905 8 +718 10 +795 6 +2965 8 +2864 1 +2547 8 +2790 6 +832 9 +1498 1 +1664 10 +1942 8 +878 6 +2726 6 +1088 10 +174 8 +25 10 +3262 8 +1573 6 +3861 3 +2993 1 +3965 1 +2892 6 +1820 6 +339 7 +157 3 +2762 7 +76 5 +3179 9 +1356 9 +686 2 +3302 3 +3262 6 +2467 6 +500 10 +3046 10 +736 2 +649 3 +2925 10 +3501 5 +238 6 +1303 1 +913 9 +693 3 +2173 3 +1814 8 +3080 7 +3560 4 +3904 2 +1921 9 +2389 7 +2600 8 +2192 10 +1275 8 +3306 6 +287 10 +3722 4 +363 3 +240 10 +602 7 +1671 3 +1677 7 +789 10 +2319 1 +2771 1 +585 10 +91 3 +2105 7 +3282 2 +3942 9 +2825 3 +26 9 +3405 8 +3732 1 +1612 10 +983 5 +1469 9 +2819 2 +2995 10 +890 2 +3616 8 +814 3 +2376 4 +3578 4 +3499 8 +3319 8 +2801 3 +3953 6 +3239 2 +870 5 +2468 8 +2992 2 +3429 3 +2117 10 +1945 6 +1143 1 +469 5 +2804 9 +2309 9 +2124 4 +1763 6 +3604 3 +3640 1 +2045 8 +2531 5 +2763 3 +2395 1 +2323 2 +1081 10 +2078 10 +1731 2 +364 9 +1714 9 +578 7 +1469 6 +1905 10 +129 2 +389 1 +94 8 +2873 9 +1124 6 +824 2 +3386 5 +1700 2 +3658 9 +2415 8 +1264 5 +4028 8 +1663 8 +1435 10 +4002 5 +3274 6 +2072 1 +3006 2 +376 10 +3595 9 +3275 10 +1755 1 +548 4 +232 5 +3179 3 +1100 7 +772 8 +3330 5 +3967 3 +1494 7 +1770 4 +2269 8 +896 2 +1058 8 +1698 8 +3801 9 +1633 6 +667 9 +2153 9 +3867 1 +3617 4 +415 2 +671 3 +1993 1 +3368 1 +2161 3 +3957 3 +1938 4 +3215 10 +12 4 +1450 4 +3852 3 +3372 9 +1514 5 +2308 8 +1153 2 +422 5 +1824 10 +1575 1 +3979 9 +3026 2 +3162 6 +3247 3 +1939 5 +191 9 +2677 8 +3849 3 +3871 9 +1269 4 +2867 10 +2521 1 +110 7 +2569 6 +3901 9 +1302 1 +1441 2 +150 3 +4029 10 +1336 6 +243 8 +3365 10 +3901 9 +1297 2 +3664 5 +3507 7 +1263 8 +3142 10 +2079 3 +642 1 +2478 3 +3766 10 +2993 9 +3337 5 +2224 7 +1444 4 +2939 7 +1226 2 +866 1 +957 4 +3813 9 +982 4 +2114 1 +247 7 +2946 3 +744 6 +923 4 +3534 4 +2790 7 +2840 4 +1963 8 +916 6 +592 4 +2187 5 +1236 5 +2522 7 +139 1 +3331 5 +1705 6 +683 10 +3383 3 +2377 10 +523 3 +3815 9 +3822 3 +541 8 +2128 1 +431 3 +1719 4 +3104 6 +2394 1 +1679 6 +1341 1 +1555 10 +2818 6 +1818 2 +3978 6 +3784 5 +211 8 +28 3 +2160 6 +2290 8 +1029 1 +500 4 +664 9 +964 10 +1349 10 +260 6 +3889 1 +224 9 +3846 1 +3442 3 +1542 4 +1834 10 +137 6 +1918 4 +3657 4 +16 5 +3626 10 +762 5 +1907 10 +1306 6 +976 5 +31 9 +2618 5 +643 2 +2273 4 +1515 8 +196 4 +754 10 +1134 8 +892 3 +1800 9 +1698 8 +2326 8 +4061 4 +370 3 +3209 3 +3852 9 +2499 8 +195 5 +1606 4 +2600 9 +1248 10 +3417 8 +691 6 +3882 9 +2000 5 +3657 10 +1219 8 +1453 5 +1806 8 +2896 6 +10 4 +2545 6 +3165 7 +3882 2 +2855 10 +3935 1 +3647 9 +71 8 +3790 1 +1891 8 +514 2 +3790 6 +2152 5 +3046 2 +594 8 +2930 6 +2927 10 +1739 1 +2559 7 +3408 2 +1081 3 +771 10 +506 3 +3537 6 +2946 8 +3995 7 +1245 7 +2097 5 +3222 9 +137 1 +3918 9 +1969 5 +1077 4 +527 2 +317 7 +1836 3 +1238 9 +582 6 +2554 4 +2292 2 +1106 7 +1709 5 +3980 2 +2134 9 +3310 1 +3476 9 +132 4 +3924 6 +3875 2 +2794 1 +3632 1 +728 2 +3674 1 +3873 9 +3649 4 +1185 7 +2722 3 +485 10 +272 6 +1181 5 +3942 6 +4013 5 +65 10 +3027 7 +2131 2 +390 9 +82 2 +2018 1 +3598 5 +2083 9 +1188 4 +1583 2 +736 8 +2779 7 +2101 3 +1522 8 +674 5 +3751 2 +1947 3 +4044 9 +2536 9 +191 8 +3053 9 +2025 1 +2984 4 +33 1 +1426 2 +514 7 +2972 5 +3109 4 +3106 6 +2568 2 +2309 7 +3966 7 +2344 5 +1173 5 +1885 5 +2939 7 +3867 1 +3595 4 +4083 5 +1132 2 +2868 1 +950 5 +3194 4 +2220 5 +3917 4 +580 10 +1304 10 +1540 5 +3223 10 +825 3 +1436 4 +3907 1 +2911 9 +15 3 +3371 5 +1200 3 +1092 10 +916 8 +668 7 +4035 6 +2062 7 +1581 9 +804 2 +3293 9 +2459 7 +2831 10 +2755 10 +2931 4 +3780 10 +4013 1 +1060 6 +3093 6 +238 6 +440 1 +85 5 +375 8 +622 3 +803 2 +2099 10 +2261 7 +2677 10 +2598 8 +1134 3 +3503 2 +1761 6 +2114 10 +278 4 +2703 8 +1153 7 +818 5 +3369 4 +144 5 +1992 1 +2033 2 +1942 2 +44 9 +3582 10 +354 10 +4004 1 +3363 5 +2129 1 +3445 7 +1353 7 +46 6 +1934 2 +3555 9 +2423 2 +1947 8 +3976 7 +3853 9 +124 4 +3854 9 +1633 5 +102 10 +3302 7 +1801 9 +423 4 +1740 1 +2919 2 +404 10 +2831 9 +2348 10 +2235 1 +1242 7 +2536 10 +2623 10 +655 5 +634 4 +218 9 +757 5 +1516 10 +3683 1 +1746 4 +3826 2 +2137 6 +191 4 +2889 6 +1793 3 +3265 7 +2244 4 +1057 8 +1190 8 +1085 9 +286 6 +644 10 +3189 6 +3934 1 +1957 3 +34 4 +1837 6 +3480 7 +2206 1 +747 2 +1688 3 +2107 6 +3892 1 +3119 1 +2198 8 +2862 7 +1662 1 +1857 8 +1132 6 +3316 3 +1877 1 +3550 2 +2671 7 +190 10 +1450 1 +2910 10 +1173 1 +3742 6 +1907 7 +2345 8 +580 8 +0 2 +1920 7 +2737 3 +1030 2 +2061 9 +2704 7 +3309 4 +1204 1 +777 1 +81 10 +906 10 +1049 4 +3803 9 +3684 9 +1256 6 +1970 9 +2133 3 +1968 1 +1532 2 +2992 1 +3285 10 +829 2 +156 8 +2882 10 +120 8 +499 10 +1962 3 +2202 7 +4015 8 +2883 6 +327 4 +2502 9 +8 6 +1896 6 +2862 1 +1220 4 +3890 4 +58 3 +2273 1 +2074 10 +3090 5 +200 6 +2522 2 +624 1 +592 5 +1190 4 +3879 9 +84 6 +1193 10 +1612 2 +3239 7 +254 2 +3689 5 +2560 10 +422 3 +3726 10 +617 6 +3673 3 +3806 4 +143 10 +1326 9 +952 5 +211 4 +3346 10 +2984 3 +80 3 +2045 1 +371 9 +2921 4 +1924 5 +2656 8 +3435 9 +3882 6 +1410 4 +967 4 +3102 1 +2018 10 +1122 9 +3656 10 +653 2 +1418 4 +1107 3 +2603 6 +3792 7 +721 6 +3489 10 +1092 9 +1186 8 +3296 5 +2136 2 +2847 5 +1660 3 +417 2 +3312 9 +1811 8 +2537 6 +2928 10 +1383 5 +2939 2 +2065 9 +1781 7 +3544 6 +1042 6 +342 10 +2704 9 +2433 6 +194 4 +2000 9 +2886 9 +1010 2 +2869 2 +1508 9 +157 3 +2606 4 +1790 4 +2353 6 +1723 9 +429 5 +3385 5 +2976 2 +409 7 +585 3 +3346 4 +3500 8 +636 4 +478 5 +921 2 +2642 4 +3195 5 +3676 8 +3798 1 +1651 7 +16 6 +228 4 +1168 8 +2865 7 +726 8 +839 10 +3906 1 +2140 9 +3875 1 +636 9 +4087 1 +1551 6 +3299 6 +1899 9 +3215 9 +2406 1 +3391 2 +4087 1 +1259 4 +3409 7 +450 7 +2905 3 +1733 6 +647 1 +2220 10 +1894 2 +744 8 +189 7 +2138 5 +2569 1 +2941 4 +1627 6 +234 3 +3382 9 +3326 9 +283 4 +3659 10 +3223 3 +1083 2 +21 5 +3083 6 +98 7 +3288 7 +198 2 +3577 3 +1638 1 +2968 7 +251 9 +2460 1 +2706 3 +1224 8 +1773 7 +995 5 +770 7 +1972 6 +1375 8 +3830 9 +754 2 +2173 8 +627 7 +1797 6 +3883 6 +1402 5 +1736 6 +3818 6 +1851 6 +3316 7 +2677 7 +663 6 +593 3 +2773 6 +2694 1 +1355 6 +2838 4 +1222 7 +4049 4 +2128 1 +1802 9 +1112 8 +1812 4 +3774 4 +1166 8 +725 4 +2677 7 +2281 9 +1746 4 +2493 7 +641 8 +11 5 +1462 4 +2250 10 +166 2 +2528 10 +961 7 +263 10 +3339 3 +2827 4 +1732 9 +2883 7 +859 7 +861 2 +3158 2 +561 2 +12 3 +4009 3 +1000 8 +1035 2 +2937 1 +629 6 +4084 6 +633 2 +2601 6 +2352 6 +1079 3 +438 7 +3352 1 +3240 8 +2414 6 +2520 7 +3806 1 +1134 5 +1567 4 +2601 6 +827 5 +2418 5 +1640 8 +934 6 +2003 2 +1361 9 +977 7 +3833 6 +3506 1 +1192 1 +857 5 +1151 7 +21 10 +3669 7 +3653 8 +2881 1 +1425 2 +3634 8 +2023 2 +1825 4 +3340 9 +377 8 +3265 8 +1108 10 +2393 5 +3781 1 +316 2 +1475 10 +2501 1 +232 3 +3331 4 +1765 3 +2788 1 +3280 3 +2253 10 +2090 7 +3222 7 +2724 1 +1265 2 +3847 3 +855 7 +1994 8 +3149 10 +1469 6 +2450 4 +2419 7 +946 4 +2779 8 +711 10 +3970 3 +229 5 +782 9 +2264 9 +3732 6 +3980 8 +770 4 +2639 7 +2716 10 +3583 8 +3474 1 +2085 5 +1121 2 +2257 2 +3388 2 +1328 7 +916 3 +2169 2 +2166 10 +3003 7 +2230 8 +2713 4 +176 8 +869 8 +1994 1 +912 2 +313 4 +3754 6 +2763 4 +714 6 +3634 5 +3327 4 +1620 9 +2297 1 +231 9 +1057 3 +1101 2 +1041 4 +691 3 +2083 10 +485 7 +3271 10 +1475 4 +3822 1 +3339 7 +3785 9 +3305 10 +1931 3 +3387 10 +3887 7 +3685 10 +3844 3 +1839 9 +2068 5 +170 3 +3234 9 +3413 1 +317 6 +1483 5 +2165 8 +3199 6 +3312 6 +1195 5 +1172 8 +896 1 +58 10 +3517 3 +1279 4 +653 6 +1822 7 +2863 8 +1141 8 +3424 9 +3958 3 +655 6 +404 5 +294 2 +186 6 +3461 4 +1354 7 +3243 1 +3536 5 +3069 3 +3268 6 +1595 10 +2915 9 +3721 9 +2327 4 +3800 9 +2860 7 +2215 2 +3780 7 +3230 4 +46 1 +370 6 +866 5 +2080 3 +3315 1 +1324 5 +1029 3 +3766 4 +1751 6 +1476 2 +986 8 +2803 1 +2111 4 +2338 2 +3724 5 +1879 4 +1931 10 +2497 10 +1532 10 +2527 4 +3131 10 +1814 9 +1523 1 +3901 7 +2319 4 +2899 9 +1437 3 +1660 7 +585 10 +3484 7 +2269 8 +738 6 +2207 9 +2969 4 +1485 4 +211 6 +2838 4 +3531 6 +2513 9 +3864 6 +2400 7 +1134 10 +454 10 +3850 9 +208 9 +1813 1 +3291 10 +3528 6 +3959 8 +1339 8 +3506 3 +3121 6 +761 2 +22 1 +364 1 +2628 8 +3881 2 +2965 1 +2716 4 +2487 7 +2730 9 +3318 6 +629 6 +1007 6 +435 4 +1478 5 +3141 2 +1374 8 +678 2 +1904 1 +1834 1 +1269 7 +3504 10 +2939 8 +2599 2 +1427 3 +3212 8 +3345 2 +3406 7 +1938 1 +989 4 +3785 1 +934 1 +437 6 +881 4 +122 4 +3791 1 +2000 7 +1631 7 +1329 7 +164 3 +3300 5 +3287 9 +3086 3 +2094 8 +804 7 +2223 3 +595 3 +530 8 +1273 5 +786 5 +2472 7 +740 2 +2264 7 +673 9 +2361 7 +1326 1 +547 1 +2008 3 +1050 8 +1852 3 +2884 3 +602 9 +937 2 +2085 3 +516 7 +2260 5 +2234 5 +1887 10 +2430 4 +2722 7 +1956 4 +2459 1 +2905 9 +3195 6 +3568 2 +597 7 +167 2 +2975 8 +812 7 +2980 8 +2173 1 +1286 9 +414 10 +2575 9 +3431 2 +218 5 +509 4 +599 8 +2253 2 +2425 8 +1903 7 +1882 3 +3459 6 +3750 8 +3879 7 +3658 4 +93 3 +2907 10 +4093 5 +4046 10 +2553 3 +628 5 +353 4 +2955 6 +1148 4 +1622 10 +421 5 +1751 5 +3036 2 +465 6 +771 4 +2380 5 +1939 9 +3015 7 +1858 8 +268 8 +2522 1 +3363 6 +1936 8 +1255 3 +3555 2 +2728 6 +4022 1 +299 2 +3805 10 +2651 5 +1905 4 +1401 5 +454 9 +814 10 +2090 8 +2793 10 +568 9 +3842 5 +2281 3 +2515 4 +1920 8 +1894 5 +1752 8 +306 3 +3519 2 +3708 4 +213 4 +2748 10 +588 8 +1499 2 +2297 5 +3789 2 +126 9 +681 1 +3899 1 +1572 10 +475 7 +625 10 +1258 4 +1460 5 +2488 5 +481 7 +2448 9 +820 3 +2882 10 +3490 1 +2711 3 +644 10 +31 3 +2255 1 +2522 9 +627 8 +22 10 +2711 7 +1282 10 +2480 1 +3949 3 +2798 2 +1383 9 +2992 5 +1491 2 +1989 5 +2155 2 +3580 3 +1215 5 +2340 8 +1715 3 +3344 5 +3397 5 +1089 8 +2778 10 +3895 1 +321 10 +958 6 +3883 5 +1945 1 +3373 3 +1180 6 +1698 4 +3567 7 +3144 9 +783 5 +2923 7 +3221 10 +2758 8 +3915 8 +1535 2 +3194 3 +1792 9 +572 9 +3530 10 +2444 5 +2855 2 +768 7 +1914 7 +821 5 +1860 1 +2994 7 +2926 3 +3594 4 +1054 9 +406 8 +2511 8 +3791 4 +220 1 +2195 6 +242 9 +42 4 +1349 7 +2944 3 +1880 2 +1480 6 +1805 10 +2634 5 +3381 3 +1064 5 +3218 8 +3391 10 +3118 10 +330 1 +2075 1 +2774 10 +3123 9 +983 3 +2024 4 +3016 7 +425 9 +3109 5 +899 1 +2521 1 +4000 1 +2850 2 +3023 7 +2190 2 +3453 9 +4093 7 +3034 7 +747 8 +2485 3 +2066 9 +2052 1 +3465 3 +2692 4 +2116 2 +546 3 +448 4 +2518 2 +3365 1 +1695 9 +253 6 +164 5 +2151 7 +3215 6 +837 7 +553 9 +2582 3 +2285 5 +592 7 +1127 5 +482 8 +2803 9 +652 5 +3119 1 +1567 3 +1987 5 +379 2 +1883 10 +3841 8 +4038 6 +453 6 +2498 8 +224 8 +629 2 +411 5 +3853 10 +3104 2 +405 3 +1898 4 +1693 3 +109 2 +469 2 +496 4 +217 7 +632 7 +1710 6 +125 10 +1567 2 +2568 7 +2245 9 +3151 7 +2354 2 +1887 5 +1005 2 +2726 7 +1361 7 +1381 3 +1383 3 +3041 6 +2252 1 +346 4 +759 5 +2045 9 +2877 8 +2281 7 +2373 1 +3292 4 +657 4 +988 6 +3893 6 +1043 9 +788 8 +1341 4 +664 9 +1247 10 +3285 7 +2839 10 +670 10 +593 10 +3427 3 +238 7 +3747 8 +2380 5 +146 2 +2775 10 +2790 1 +2458 7 +791 9 +4028 6 +3665 5 +1495 5 +2756 2 +1237 9 +2449 4 +1139 6 +3249 10 +2747 9 +1513 8 +4050 1 +3195 1 +1455 9 +3482 6 +2337 4 +1523 2 +1430 6 +1146 5 +1655 8 +4057 6 +1455 5 +191 7 +1671 7 +2028 5 +3530 10 +395 9 +2020 4 +3583 7 +950 5 +1105 9 +816 10 +2189 7 +2677 4 +9 2 +483 10 +1606 1 +2663 10 +2964 1 +1523 8 +3645 8 +7 1 +729 2 +185 9 +1680 6 +3629 4 +3886 9 +1507 8 +2202 10 +1123 4 +1048 8 +2469 8 +2455 9 +1450 3 +4064 10 +2044 6 +180 9 +2370 7 +3996 10 +398 9 +1462 1 +1442 10 +3583 1 +2750 9 +1643 4 +2951 6 +79 7 +421 3 +2778 4 +3693 2 +1015 8 +773 3 +3014 1 +1025 10 +3488 9 +3026 3 +3108 9 +3945 4 +62 9 +590 7 +2486 7 +1035 6 +3525 3 +1705 2 +2160 4 +873 10 +4040 1 +1300 10 +442 2 +3648 8 +2035 5 +3611 10 +3103 5 +447 7 +1494 7 +1342 8 +3676 6 +1441 2 +2882 3 +3626 7 +3349 2 +979 4 +960 9 +2272 8 +2477 6 +1631 2 +2462 10 +1635 1 +3521 4 +1538 10 +915 2 +1891 1 +356 2 +3373 9 +81 8 +900 7 +3236 4 +3149 6 +83 8 +890 6 +1643 8 +714 1 +4041 6 +365 6 +1457 7 +1521 2 +2580 5 +2290 9 +471 7 +1491 5 +1655 2 +2727 5 +3081 3 +2307 2 +3816 6 +1678 9 +1613 1 +1890 7 +3107 1 +217 9 +863 10 +1852 6 +554 9 +567 2 +3700 3 +3559 4 +3870 4 +3695 2 +276 7 +2593 5 +1009 8 +329 7 +1381 9 +2848 2 +3548 10 +2045 4 +512 3 +2469 3 +791 3 +1518 10 +4088 10 +997 1 +4045 10 +825 10 +1449 7 +3425 2 +2816 10 +3579 7 +1068 9 +653 8 +1616 6 +2336 6 +1459 10 +3783 5 +2128 3 +2882 5 +2405 2 +200 4 +1164 9 +2094 10 +1884 8 +1645 7 +1624 2 +2066 7 +1488 4 +1136 3 +2658 10 +2102 3 +1189 7 +3775 3 +1370 7 +3049 5 +272 10 +2760 10 +954 2 +3127 3 +2438 8 +2670 3 +3395 4 +274 9 +2558 5 +1144 7 +2557 5 +647 2 +2018 1 +1909 2 +2846 7 +467 10 +2055 8 +3092 7 +1822 3 +3765 8 +336 2 +610 10 +362 8 +3569 3 +1180 1 +3754 9 +1901 5 +1909 6 +884 3 +2760 10 +74 3 +635 4 +1752 10 +2238 3 +663 4 +3229 2 +1013 3 +1376 3 +1501 4 +2606 2 +3462 1 +326 3 +305 8 +846 9 +990 2 +3598 10 +3582 8 +3796 6 +1731 1 +3279 6 +3472 9 +60 7 +1910 8 +2982 7 +3372 10 +2114 10 +541 7 +294 8 +2316 5 +3760 1 +1284 4 +2374 5 +2717 1 +1313 8 +932 5 +3137 2 +1373 7 +4088 5 +1820 4 +2512 7 +2813 6 +2251 4 +1727 10 +704 6 +483 10 +3281 9 +1622 2 +1284 3 +1293 1 +3241 7 +1508 10 +696 2 +2944 4 +3889 5 +1075 10 +1680 8 +1084 9 +2060 10 +2892 7 +900 5 +2589 7 +1025 4 +3950 6 +953 1 +455 2 +1016 7 +1344 7 +2688 8 +467 9 +2597 9 +2859 8 +2643 8 +3544 6 +1000 8 +225 4 +1473 9 +2134 2 +26 10 +623 7 +2449 9 +479 2 +3936 1 +935 7 +1490 7 +885 7 +437 7 +3937 1 +1729 4 +3078 7 +2020 6 +330 9 +4064 10 +1392 10 +2589 2 +4080 5 +2785 9 +2570 9 +3420 7 +2709 2 +261 1 +2595 8 +2383 8 +1986 1 +991 5 +3796 7 +63 6 +2499 6 +2323 2 +3772 3 +960 1 +1186 1 +3358 3 +2414 8 +940 7 +3606 7 +802 1 +1913 5 +2900 10 +2078 1 +864 2 +3210 3 +4023 7 +3678 9 +1792 10 +3996 5 +2024 4 +2605 7 +2645 3 +1420 5 +3328 9 +2147 9 +2813 2 +1841 3 +3458 9 +777 5 +3564 2 diff --git a/tests/opencl/lbm/main.cc b/tests/opencl/lbm/main.cc index 4f376c8b1..2da743510 100644 --- a/tests/opencl/lbm/main.cc +++ b/tests/opencl/lbm/main.cc @@ -46,7 +46,7 @@ static float* read_output_file(const char* filename, int size) { return NULL; } // Read the float data - if (fread(floats, sizeof(float), size, file) != size) { + if (fread(floats, sizeof(float), size, file) != (size_t)size) { fclose(file); free(floats); perror("Error reading floats from file"); @@ -128,6 +128,7 @@ int main(int nArgs, char *arg[]) { MAIN_initialize(¶m, &prm); for (t = 1; t <= param.nTimeSteps; t++) { + pb_SwitchToTimer(&timers, pb_TimerID_KERNEL); OpenCL_LBM_performStreamCollide(&prm, OpenCL_srcGrid, OpenCL_dstGrid); pb_SwitchToTimer(&timers, pb_TimerID_COMPUTE); @@ -198,9 +199,9 @@ void MAIN_printInfo(const MAIN_Param *param) { "\tsimulation type: %s\n" "\tobstacle file : %s\n\n", SIZE_X, SIZE_Y, SIZE_Z, 1e-6 * SIZE_X * SIZE_Y * SIZE_Z, - param->nTimeSteps, param->resultFilename, "store", "lid-driven cavity", - (param->obstacleFilename == NULL) ? "" - : param->obstacleFilename); + param->nTimeSteps, ((param->resultFilename == NULL) ? "" : param->resultFilename), "store", "lid-driven cavity", + ((param->obstacleFilename == NULL) ? "" : param->obstacleFilename) + ); } /*############################################################################*/ @@ -316,7 +317,7 @@ void OpenCL_initialize(struct pb_Parameters *p, OpenCL_Param *prm) { // read kernel binary from file uint8_t *kernel_bin = NULL; size_t kernel_size; - cl_int binary_status = 0; + //cl_int binary_status = 0; clStatus = read_kernel_file("kernel.cl", &kernel_bin, &kernel_size); CHECK_ERROR("read_kernel_file") diff --git a/tests/regression/Makefile b/tests/regression/Makefile index 56b63d1e1..f170c7335 100644 --- a/tests/regression/Makefile +++ b/tests/regression/Makefile @@ -15,6 +15,7 @@ all: $(MAKE) -C sgemmx $(MAKE) -C conv3x $(MAKE) -C sgemm2x + $(MAKE) -C stencil3d run-simx: $(MAKE) -C basic run-simx @@ -30,6 +31,7 @@ run-simx: $(MAKE) -C sgemmx run-simx $(MAKE) -C conv3x run-simx $(MAKE) -C sgemm2x run-simx + $(MAKE) -C stencil3d run-simx run-rtlsim: $(MAKE) -C basic run-rtlsim @@ -45,21 +47,7 @@ run-rtlsim: $(MAKE) -C sgemmx run-rtlsim $(MAKE) -C conv3x run-rtlsim $(MAKE) -C sgemm2x run-rtlsim - -run-opae: - $(MAKE) -C basic run-opae - $(MAKE) -C demo run-opae - $(MAKE) -C dogfood run-opae - $(MAKE) -C mstress run-opae - $(MAKE) -C io_addr run-opae - $(MAKE) -C printf run-opae - $(MAKE) -C diverge run-opae - $(MAKE) -C sort run-opae - $(MAKE) -C fence run-opae - $(MAKE) -C vecaddx run-opae - $(MAKE) -C sgemmx run-opae - $(MAKE) -C conv3x run-opae - $(MAKE) -C sgemm2x run-opae + $(MAKE) -C stencil3d run-rtlsim clean: $(MAKE) -C basic clean @@ -74,4 +62,5 @@ clean: $(MAKE) -C vecaddx clean $(MAKE) -C sgemmx clean $(MAKE) -C conv3x clean - $(MAKE) -C sgemm2x clean \ No newline at end of file + $(MAKE) -C sgemm2x clean + $(MAKE) -C stencil3d clean \ No newline at end of file diff --git a/tests/regression/stencil3d/Makefile b/tests/regression/stencil3d/Makefile new file mode 100644 index 000000000..c4aacdb94 --- /dev/null +++ b/tests/regression/stencil3d/Makefile @@ -0,0 +1,14 @@ +ROOT_DIR := $(realpath ../../..) +include $(ROOT_DIR)/config.mk + +PROJECT := stencil3d + +SRC_DIR := $(VORTEX_HOME)/tests/regression/$(PROJECT) + +SRCS := $(SRC_DIR)/main.cpp + +VX_SRCS := $(SRC_DIR)/kernel.cpp + +OPTS ?= -n32-b2 # 32x32x32 matrix and block size of 2x2x2 + +include ../common.mk \ No newline at end of file diff --git a/tests/regression/stencil3d/common.h b/tests/regression/stencil3d/common.h new file mode 100644 index 000000000..2c4a8ea00 --- /dev/null +++ b/tests/regression/stencil3d/common.h @@ -0,0 +1,18 @@ +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#ifndef TYPE +#define TYPE float +#endif + +typedef struct +{ + uint32_t grid_dim[3]; + uint32_t block_dim[3]; + uint32_t size; + uint32_t block_size; + uint64_t A_addr; + uint64_t B_addr; +} kernel_arg_t; + +#endif \ No newline at end of file diff --git a/tests/regression/stencil3d/kernel.cpp b/tests/regression/stencil3d/kernel.cpp new file mode 100644 index 000000000..48e2468ab --- /dev/null +++ b/tests/regression/stencil3d/kernel.cpp @@ -0,0 +1,58 @@ +#include +#include "common.h" + +void kernel_body(kernel_arg_t *arg) +{ + auto A = reinterpret_cast(arg->A_addr); + auto B = reinterpret_cast(arg->B_addr); + auto size = arg->size; // Assuming 'size' now represents one dimension of a cubic space. + + // Calculate global column, row, and depth indices using both block and thread indices + int col = blockIdx.x * blockDim.x + threadIdx.x; + int row = blockIdx.y * blockDim.y + threadIdx.y; + int dep = blockIdx.z * blockDim.z + threadIdx.z; + + TYPE sum = 0; + int count = 0; + + // Stencil kernel size is assumed to be 3x3x3 + for (int dz = -1; dz <= 1; ++dz) + { + for (int dy = -1; dy <= 1; ++dy) + { + for (int dx = -1; dx <= 1; ++dx) + { + // Compute the neighbor's index, handling boundary conditions manually + int nz = dep + dz; + int ny = row + dy; + int nx = col + dx; + + // Clamp the indices to be within the boundary of the array + if (nz < 0) {nz = 0;} + else if (nz >= size){ + nz = size - 1;} + if (ny < 0) { + ny = 0; } + else if (ny >= size){ + ny = size - 1;} + if (nx < 0) { + nx = 0;} + else if (nx >= size){ + nx = size - 1;} + + // Add the neighbor's value to sum + sum += A[nz * size * size + ny * size + nx]; + count++; + } + } + } + + // Compute the average of the sum of neighbors and write to the output array + B[dep * size * size + row * size + col] = sum / count; +} + +int main() +{ + auto arg = (kernel_arg_t *)csr_read(VX_CSR_MSCRATCH); + return vx_spawn_threads(3, arg->grid_dim, arg->block_dim, (vx_kernel_func_cb)kernel_body, arg); +} \ No newline at end of file diff --git a/tests/regression/stencil3d/main.cpp b/tests/regression/stencil3d/main.cpp new file mode 100644 index 000000000..a47f94710 --- /dev/null +++ b/tests/regression/stencil3d/main.cpp @@ -0,0 +1,328 @@ + +#include +#include +#include +#include +#include +#include "common.h" + +#define FLOAT_ULP 6 + +#define RT_CHECK(_expr) \ + do \ + { \ + int _ret = _expr; \ + if (0 == _ret) \ + break; \ + printf("Error: '%s' returned %d!\n", #_expr, (int)_ret); \ + cleanup(); \ + exit(-1); \ + } while (false) + +/////////////////////////////////////////////////////////////////////////////// + +template +class Comparator +{ +}; + +template <> +class Comparator +{ +public: + static const char *type_str() + { + return "integer"; + } + static int generate() + { + return rand(); + } + static bool compare(int a, int b, int index, int errors) + { + if (a != b) + { + if (errors < 100) + { + printf("*** error: [%d] expected=%d, actual=%d\n", index, a, b); + } + return false; + } + return true; + } +}; + +template <> +class Comparator +{ +private: + union Float_t + { + float f; + int i; + }; + +public: + static const char *type_str() + { + return "float"; + } + static float generate() + { + return static_cast(rand()) / RAND_MAX; + } + static bool compare(float a, float b, int index, int errors) + { + union fi_t + { + float f; + int32_t i; + }; + fi_t fa, fb; + fa.f = a; + fb.f = b; + auto d = std::abs(fa.i - fb.i); + if (d > FLOAT_ULP) + { + if (errors < 100) + { + printf("*** error: [%d] expected=%f, actual=%f\n", index, a, b); + } + return false; + } + return true; + } +}; + +static void stencil_cpu(TYPE *out, const TYPE *in, uint32_t width, uint32_t height, uint32_t depth) +{ + // We'll need to handle boundary conditions. Let's assume we use boundary replication. + for (uint32_t z = 0; z < depth; z++) + { + for (uint32_t y = 0; y < height; y++) + { + for (uint32_t x = 0; x < width; x++) + { + TYPE sum = 0; + int count = 0; + + // Iterate over the neighborhood + for (int dz = -1; dz <= 1; dz++) + { + for (int dy = -1; dy <= 1; dy++) + { + for (int dx = -1; dx <= 1; dx++) + { + // Compute the neighbor's index + int nx = (int)x + dx; + int ny = (int)y + dy; + int nz = (int)z + dz; + + // Check bounds and replicate the boundary values + if (nx < 0) + { + nx = 0; + } + else if (nx >= (int)width) + { + nx = width - 1; + } + if (ny < 0) + { + ny = 0; + } + else if (ny >= (int)height) + { + ny = height - 1; + } + if (nz < 0) + { + nz = 0; + } + else if (nz >= (int)depth) + { + nz = depth - 1; + } + + // Sum up the values + sum += in[nz * width * height + ny * width + nx]; + count++; + } + } + } + + // Write the averaged value to the output array + out[z * width * height + y * width + x] = sum / count; + } + } + } +} + +const char *kernel_file = "kernel.vxbin"; +uint32_t size = 64; +uint32_t block_size = 2; + +vx_device_h device = nullptr; +vx_buffer_h A_buffer = nullptr; +vx_buffer_h B_buffer = nullptr; +vx_buffer_h krnl_buffer = nullptr; +vx_buffer_h args_buffer = nullptr; +kernel_arg_t kernel_arg = {}; + +static void show_usage() +{ + std::cout << "Vortex Test." << std::endl; + std::cout << "Usage: [-k: kernel] [-n matrix_size] [-b:block_size] [-h: help]" << std::endl; +} + +static void parse_args(int argc, char **argv) +{ + int c; + while ((c = getopt(argc, argv, "n:t:k:h?")) != -1) + { + switch (c) + { + case 'n': + size = atoi(optarg); + break; + case 'b': + block_size = atoi(optarg); + break; + case 'k': + kernel_file = optarg; + break; + case 'h': + case '?': + { + show_usage(); + exit(0); + } + break; + default: + show_usage(); + exit(-1); + } + } +} + +void cleanup() +{ + if (device) + { + vx_mem_free(A_buffer); + vx_mem_free(B_buffer); + vx_mem_free(krnl_buffer); + vx_mem_free(args_buffer); + vx_dev_close(device); + } +} + +int main(int argc, char *argv[]) +{ + // parse command arguments + parse_args(argc, argv); + + if ((size / block_size) * block_size != size) + { + printf("Error: matrix size %d must be a multiple of block size %d\n", size, block_size); + return -1; + } + + std::srand(50); + + // open device connection + std::cout << "open device connection" << std::endl; + RT_CHECK(vx_dev_open(&device)); + + uint32_t size_cubed = size * size * size; + uint32_t buf_size = size_cubed * sizeof(TYPE); + + std::cout << "data type: " << Comparator::type_str() << std::endl; + std::cout << "matrix size: " << size << "x" << size << std::endl; + std::cout << "block size: " << block_size << "x" << block_size << std::endl; + + kernel_arg.grid_dim[0] = size / block_size; + kernel_arg.grid_dim[1] = size / block_size; + kernel_arg.grid_dim[2] = size / block_size; + kernel_arg.block_dim[0] = block_size; + kernel_arg.block_dim[1] = block_size; + kernel_arg.block_dim[2] = block_size; + kernel_arg.size = size; + kernel_arg.block_size = block_size; + + // allocate device memory + std::cout << "allocate device memory" << std::endl; + RT_CHECK(vx_mem_alloc(device, buf_size, VX_MEM_READ, &A_buffer)); + RT_CHECK(vx_mem_address(A_buffer, &kernel_arg.A_addr)); + RT_CHECK(vx_mem_alloc(device, buf_size, VX_MEM_WRITE, &B_buffer)); + RT_CHECK(vx_mem_address(B_buffer, &kernel_arg.B_addr)); + + std::cout << "A_addr=0x" << std::hex << kernel_arg.A_addr << std::endl; + std::cout << "B_addr=0x" << std::hex << kernel_arg.B_addr << std::endl; + + // allocate host buffers + std::cout << "allocate host buffers" << std::endl; + std::vector h_A(size_cubed); + std::vector h_B(size_cubed); + + // generate source data + for (uint32_t i = 0; i < size_cubed; ++i) + { + h_A[i] = Comparator::generate(); + } + + // upload source buffer0 + std::cout << "upload source buffer0" << std::endl; + RT_CHECK(vx_copy_to_dev(A_buffer, h_A.data(), 0, buf_size)); + + // upload program + std::cout << "upload program" << std::endl; + RT_CHECK(vx_upload_kernel_file(device, kernel_file, &krnl_buffer)); + + // upload kernel argument + std::cout << "upload kernel argument" << std::endl; + RT_CHECK(vx_upload_bytes(device, &kernel_arg, sizeof(kernel_arg_t), &args_buffer)); + + // start device + std::cout << "start device" << std::endl; + RT_CHECK(vx_start(device, krnl_buffer, args_buffer)); + + // wait for completion + std::cout << "wait for completion" << std::endl; + RT_CHECK(vx_ready_wait(device, VX_MAX_TIMEOUT)); + + // download destination buffer + std::cout << "download destination buffer" << std::endl; + RT_CHECK(vx_copy_from_dev(h_B.data(), B_buffer, 0, buf_size)); + + // verify result + std::cout << "verify result" << std::endl; + int errors = 0; + { + std::vector h_ref(size_cubed); + stencil_cpu(h_ref.data(), h_A.data(), size, size, size); + + for (uint32_t i = 0; i < h_ref.size(); ++i) + { + if (!Comparator::compare(h_B[i], h_ref[i], i, errors)) + { + ++errors; + } + } + } + + // cleanup + std::cout << "cleanup" << std::endl; + cleanup(); + + if (errors != 0) + { + std::cout << "Found " << std::dec << errors << " errors!" << std::endl; + std::cout << "FAILED!" << std::endl; + return errors; + } + + std::cout << "PASSED!" << std::endl; + + return 0; +} diff --git a/third_party/Makefile b/third_party/Makefile index 711b3ed6b..a2f74264e 100644 --- a/third_party/Makefile +++ b/third_party/Makefile @@ -5,12 +5,12 @@ fpnew: softfloat: SPECIALIZE_TYPE=RISCV SOFTFLOAT_OPTS="-fPIC -DSOFTFLOAT_ROUND_ODD -DINLINE_LEVEL=5 -DSOFTFLOAT_FAST_DIV32TO16 -DSOFTFLOAT_FAST_DIV64TO32" $(MAKE) -C softfloat/build/Linux-x86_64-GCC -ramulator: - cd ramulator && git apply ../../miscs/patches/ramulator.patch 2> /dev/null; true - $(MAKE) -C ramulator libramulator.a +ramulator/libramulator.so: + cd ramulator && mkdir -p build && cd build && cmake .. && make -j4 +ramulator: ramulator/libramulator.so clean: $(MAKE) -C softfloat/build/Linux-x86_64-GCC clean - $(MAKE) -C ramulator clean + rm -rf ramulator/build ramulator/libramulator.so .PHONY: all fpnew softfloat ramulator \ No newline at end of file diff --git a/third_party/ramulator b/third_party/ramulator index 214f63584..e62c84a6f 160000 --- a/third_party/ramulator +++ b/third_party/ramulator @@ -1 +1 @@ -Subproject commit 214f635845214adf030367939655d172ef0fed5f +Subproject commit e62c84a6f0e06566ba6e182d308434b4532068a5 From daec55ae95b5739c9d2534e31be27a2950185c3b Mon Sep 17 00:00:00 2001 From: jaewon-lee-github Date: Thu, 12 Sep 2024 11:24:37 -0400 Subject: [PATCH 69/75] change the ci version --- .github/workflows/ci.yml | 22 +++++++++++----------- configure | 2 -- hw/rtl/VX_config.vh | 2 +- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6009e0c37..474b1af00 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,13 +21,13 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: submodules: recursive - name: Cache Toolchain Directory id: cache-toolchain - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: tools key: ${{ runner.os }}-toolchain-v0.1 @@ -36,7 +36,7 @@ jobs: - name: Cache Third Party Directory id: cache-thirdparty - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: third_party key: ${{ runner.os }}-thirdparty-v0.1 @@ -175,7 +175,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install Dependencies run: | @@ -183,7 +183,7 @@ jobs: - name: Cache Toolchain Directory id: cache-toolchain - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: tools key: ${{ runner.os }}-toolchain-v0.1 @@ -192,7 +192,7 @@ jobs: - name: Cache Third Party Directory id: cache-thirdparty - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: third_party key: ${{ runner.os }}-thirdparty-v0.1 @@ -210,7 +210,7 @@ jobs: make tests -s > /dev/null - name: Upload Build Artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: build-${{ matrix.xlen }}-vm path: build${{ matrix.xlen }}-vm @@ -226,7 +226,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install Dependencies run: | @@ -234,7 +234,7 @@ jobs: - name: Cache Toolchain Directory id: cache-toolchain - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: tools key: ${{ runner.os }}-toolchain-v0.1 @@ -243,7 +243,7 @@ jobs: - name: Cache Third Party Directory id: cache-thirdparty - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: third_party key: ${{ runner.os }}-thirdparty-v0.1 @@ -251,7 +251,7 @@ jobs: ${{ runner.os }}-thirdparty- - name: Download Build Artifact - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: build-${{ matrix.xlen }}-vm path: build${{ matrix.xlen }}-vm diff --git a/configure b/configure index c8f932488..f2e4781ef 100755 --- a/configure +++ b/configure @@ -177,5 +177,3 @@ SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) THIRD_PARTY_DIR=$SCRIPT_DIR/third_party copy_files "$SCRIPT_DIR" "$CURRENT_DIR" - -echo "VM Enable: "$VM_ENABLE diff --git a/hw/rtl/VX_config.vh b/hw/rtl/VX_config.vh index 6b6a0ad86..3826918f4 100644 --- a/hw/rtl/VX_config.vh +++ b/hw/rtl/VX_config.vh @@ -217,7 +217,7 @@ `ifndef IO_COUT_ADDR `define IO_COUT_ADDR `IO_BASE_ADDR `endif -`define IO_COUT_SIZE 64 +`define IO_COUT_SIZE `MEM_BLOCK_SIZE `ifndef IO_MPM_ADDR `define IO_MPM_ADDR (`IO_COUT_ADDR + `IO_COUT_SIZE) From 0a48d98bc12b60e65a22469cb61d4b428c9e05f3 Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Fri, 13 Sep 2024 09:39:28 -0400 Subject: [PATCH 70/75] Update README.md It has the instruction about the other branch(Vortex_vm). --- README.md | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 4322f06bc..ec8d10bd5 100644 --- a/README.md +++ b/README.md @@ -59,20 +59,17 @@ sudo apt-get install git ``` ### Configure your build folder ```sh - # - # By default, the toolchain default install location is the /opt folder and can be overridden by setting --tooldir. - # This is the example for volvo server mkdir build - mkdir out - export OUT_DIR=`pwd`/out cd build - # Run the following to disble virtual memory feature in compilation - ../configure --xlen=32 --tooldir=/software/vortex-toolchain-2024-2024-08-09 --prefix=$OUT_DIR - # Run the following instead to enable virtual memory feature in compilation - ../configure --xlen=32 --tooldir=/software/vortex-toolchain-2024-2024-08-09 --prefix=$OUT_DIR --vm_enable=1 + # for 32bit + ../configure --xlen=32 --tooldir=$HOME/tools + # for 64bit + ../configure --xlen=64 --tooldir=$HOME/tools ``` ### Install prebuilt toolchain - # We will use the precomipled tools in volvo toolchanin directory +```sh + ./ci/toolchain_install.sh --all +``` ### set environment variables ```sh # should always run before using the toolchain! @@ -82,7 +79,6 @@ sudo apt-get install git ```sh make -s ``` - ### Quick demo running vecadd OpenCL kernel on 2 cores ```sh ./ci/blackbox.sh --cores=2 --app=vecadd From e5f2442353982eed40d9c0d3fc5e803fb2cf5141 Mon Sep 17 00:00:00 2001 From: jaewon-lee-github Date: Fri, 20 Sep 2024 08:58:11 -0400 Subject: [PATCH 71/75] Update Virtual Memory testing --- .github/workflows/ci.yml | 139 ++++++--------------------------------- Makefile.in | 8 --- ci/regression.sh.in | 19 ++---- ci/toolchain_env.sh.in | 4 +- config.mk.in | 2 - configure | 7 +- kernel/Makefile | 4 -- runtime/simx/Makefile | 6 +- runtime/simx/vortex.cpp | 3 +- sim/simx/Makefile | 4 -- tests/kernel/common.mk | 4 +- 11 files changed, 34 insertions(+), 166 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 474b1af00..9af9352e3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -62,111 +62,7 @@ jobs: run: | make -C third_party > /dev/null - # build: - # runs-on: ubuntu-20.04 - # needs: setup - # strategy: - # matrix: - # xlen: [32, 64] - - # steps: - # - name: Checkout code - # uses: actions/checkout@v2 - - # - name: Install Dependencies - # run: | - # sudo bash ./ci/system_updates.sh - - # - name: Cache Toolchain Directory - # id: cache-toolchain - # uses: actions/cache@v2 - # with: - # path: tools - # key: ${{ runner.os }}-toolchain-v0.1 - # restore-keys: | - # ${{ runner.os }}-toolchain- - - # - name: Cache Third Party Directory - # id: cache-thirdparty - # uses: actions/cache@v2 - # with: - # path: third_party - # key: ${{ runner.os }}-thirdparty-v0.1 - # restore-keys: | - # ${{ runner.os }}-thirdparty- - - # - name: Run Build - # run: | - # TOOLDIR=$PWD/tools - # mkdir -p build${{ matrix.xlen }} - # cd build${{ matrix.xlen }} - # ../configure --tooldir=$TOOLDIR --xlen=${{ matrix.xlen }} - # source ci/toolchain_env.sh - # make software -s > /dev/null - # make tests -s > /dev/null - - # - name: Upload Build Artifact - # uses: actions/upload-artifact@v2 - # with: - # name: build-${{ matrix.xlen }} - # path: build${{ matrix.xlen }} - - # tests: - # runs-on: ubuntu-20.04 - # needs: build - # strategy: - # matrix: - # name: [regression, opencl, config1, config2, debug, stress] - # xlen: [32, 64] - - # steps: - # - name: Checkout code - # uses: actions/checkout@v2 - - # - name: Install Dependencies - # run: | - # sudo bash ./ci/system_updates.sh - - # - name: Cache Toolchain Directory - # id: cache-toolchain - # uses: actions/cache@v2 - # with: - # path: tools - # key: ${{ runner.os }}-toolchain-v0.1 - # restore-keys: | - # ${{ runner.os }}-toolchain- - - # - name: Cache Third Party Directory - # id: cache-thirdparty - # uses: actions/cache@v2 - # with: - # path: third_party - # key: ${{ runner.os }}-thirdparty-v0.1 - # restore-keys: | - # ${{ runner.os }}-thirdparty- - - # - name: Download Build Artifact - # uses: actions/download-artifact@v2 - # with: - # name: build-${{ matrix.xlen }} - # path: build${{ matrix.xlen }} - - # - name: Run tests - # run: | - # cd build${{ matrix.xlen }} - # source ci/toolchain_env.sh - # chmod -R +x . # Ensure all files have executable permissions - # if [ "${{ matrix.name }}" == "regression" ]; then - # ./ci/regression.sh --unittest - # ./ci/regression.sh --isa - # ./ci/regression.sh --kernel - # ./ci/regression.sh --synthesis - # ./ci/regression.sh --regression - # else - # ./ci/regression.sh --${{ matrix.name }} - # fi - - build_vm: + build: runs-on: ubuntu-20.04 needs: setup strategy: @@ -202,9 +98,9 @@ jobs: - name: Run Build run: | TOOLDIR=$PWD/tools - mkdir -p build${{ matrix.xlen }}-vm - cd build${{ matrix.xlen }}-vm - ../configure --tooldir=$TOOLDIR --xlen=${{ matrix.xlen }} --vm_enable=1 + mkdir -p build${{ matrix.xlen }} + cd build${{ matrix.xlen }} + ../configure --tooldir=$TOOLDIR --xlen=${{ matrix.xlen }} source ci/toolchain_env.sh make software -s > /dev/null make tests -s > /dev/null @@ -212,12 +108,12 @@ jobs: - name: Upload Build Artifact uses: actions/upload-artifact@v4 with: - name: build-${{ matrix.xlen }}-vm - path: build${{ matrix.xlen }}-vm + name: build-${{ matrix.xlen }} + path: build${{ matrix.xlen }} - test_vm: + test: runs-on: ubuntu-20.04 - needs: build_vm + needs: build strategy: fail-fast: false matrix: @@ -253,19 +149,26 @@ jobs: - name: Download Build Artifact uses: actions/download-artifact@v4 with: - name: build-${{ matrix.xlen }}-vm - path: build${{ matrix.xlen }}-vm - + name: build-${{ matrix.xlen }} + path: build${{ matrix.xlen }} - name: Run tests run: | - cd build${{ matrix.xlen }}-vm + cd build${{ matrix.xlen }} source ci/toolchain_env.sh chmod -R +x . # Ensure all files have executable permissions - ./ci/regression.sh --vm + if [ "${{ matrix.name }}" == "regression" ]; then + ./ci/regression.sh --unittest + ./ci/regression.sh --isa + ./ci/regression.sh --kernel + ./ci/regression.sh --synthesis + ./ci/regression.sh --regression + else + ./ci/regression.sh --${{ matrix.name }} + fi complete: runs-on: ubuntu-20.04 - needs: test_vm + needs: test steps: - name: Check Completion diff --git a/Makefile.in b/Makefile.in index bfe944998..264738aca 100644 --- a/Makefile.in +++ b/Makefile.in @@ -2,14 +2,6 @@ include config.mk .PHONY: build software tests -vm: - $(MAKE) -C $(VORTEX_HOME)/third_party - $(MAKE) -C hw - $(MAKE) -C sim simx - $(MAKE) -C kernel - $(MAKE) -C runtime vm - $(MAKE) -C tests - all: $(MAKE) -C $(VORTEX_HOME)/third_party $(MAKE) -C hw diff --git a/ci/regression.sh.in b/ci/regression.sh.in index 9ba65cfee..afd23c9ff 100755 --- a/ci/regression.sh.in +++ b/ci/regression.sh.in @@ -129,23 +129,11 @@ opencl() vm(){ echo "begin vm tests..." - make -C sim/simx - make -C runtime/simx - - make -C tests/kernel run-simx + CONFIGS="-DVM_ENABLE" make -C sim/simx + CONFIGS="-DVM_ENABLE" make -C runtime/simx - # Regression tests - make -C tests/regression run-simx - - # test global barrier - CONFIGS="-DGBAR_ENABLE" ./ci/blackbox.sh --driver=simx --app=dogfood --args="-n1 -tgbar" --cores=2 - - # test local barrier - ./ci/blackbox.sh --driver=simx --app=dogfood --args="-n1 -tbar" - - # OpenCL tests make -C tests/opencl run-simx - ./ci/blackbox.sh --driver=simx --app=lbm --warps=8 + make -C tests/regression run-simx echo "vm tests done!" } @@ -415,6 +403,7 @@ while [ "$1" != "" ]; do tests+=("regression") tests+=("opencl") tests+=("cache") + tests+=("vm") tests+=("config1") tests+=("config2") tests+=("debug") diff --git a/ci/toolchain_env.sh.in b/ci/toolchain_env.sh.in index be140d28d..dc50389a9 100755 --- a/ci/toolchain_env.sh.in +++ b/ci/toolchain_env.sh.in @@ -16,8 +16,8 @@ TOOLDIR=${TOOLDIR:=@TOOLDIR@} -# export VERILATOR_ROOT=$TOOLDIR/verilator -# export PATH=$VERILATOR_ROOT/bin:$PATH +export VERILATOR_ROOT=$TOOLDIR/verilator +export PATH=$VERILATOR_ROOT/bin:$PATH export SV2V_PATH=$TOOLDIR/sv2v export PATH=$SV2V_PATH/bin:$PATH diff --git a/config.mk.in b/config.mk.in index 8ec052094..be369b56e 100644 --- a/config.mk.in +++ b/config.mk.in @@ -35,5 +35,3 @@ VORTEX_RT_PATH ?= $(VORTEX_HOME)/runtime VORTEX_KN_PATH ?= $(VORTEX_HOME)/kernel THIRD_PARTY_DIR ?= $(VORTEX_HOME)/third_party - -VM_ENABLE ?= @VM_ENABLE@ \ No newline at end of file diff --git a/configure b/configure index f2e4781ef..62975784b 100755 --- a/configure +++ b/configure @@ -63,7 +63,7 @@ copy_files() { filename_no_ext="${filename%.in}" dest_file="$dest_dir/$filename_no_ext" mkdir -p "$dest_dir" - sed "s|@VORTEX_HOME@|$SCRIPT_DIR|g; s|@XLEN@|$XLEN|g; s|@TOOLDIR@|$TOOLDIR|g; s|@OSVERSION@|$OSVERSION|g; s|@INSTALLDIR@|$PREFIX|g; s|@VM_ENABLE@|$VM_ENABLE|g" "$file" > "$dest_file" + sed "s|@VORTEX_HOME@|$SCRIPT_DIR|g; s|@XLEN@|$XLEN|g; s|@TOOLDIR@|$TOOLDIR|g; s|@OSVERSION@|$OSVERSION|g; s|@INSTALLDIR@|$PREFIX|g" "$file" > "$dest_file" # apply permissions to bash scripts read -r firstline < "$dest_file" if [[ "$firstline" =~ ^#!.*bash ]]; then @@ -114,7 +114,6 @@ default_xlen=32 default_tooldir=$HOME/tools default_osversion=$(detect_osversion) default_prefix=$CURRENT_DIR -default_vm=0 # load default configuration parameters from existing config.mk if [ -f "config.mk" ]; then @@ -127,7 +126,6 @@ if [ -f "config.mk" ]; then TOOLDIR\ ?*) default_tooldir=${value//\?=/} ;; OSVERSION\ ?*) default_osversion=${value//\?=/} ;; PREFIX\ ?*) default_prefix=${value//\?=/} ;; - VM_ENABLE\ ?*) default_vm=${value//\?=/} ;; esac done < config.mk fi @@ -137,7 +135,6 @@ XLEN=${XLEN:=$default_xlen} TOOLDIR=${TOOLDIR:=$default_tooldir} OSVERSION=${OSVERSION:=$default_osversion} PREFIX=${PREFIX:=$default_prefix} -VM_ENABLE=${VM_ENABLE:=$default_vm} # parse command line arguments usage() { @@ -146,7 +143,6 @@ usage() { echo " --tooldir= Set the TOOLDIR path (default: $HOME/tools)" echo " --osversion= Set the OS Version (default: $(detect_osversion))" echo " --prefix= Set installation directory" - echo " --vm_enable= Enable Virtual Memory support (default: 0)" exit 1 } while [[ "$#" -gt 0 ]]; do @@ -155,7 +151,6 @@ while [[ "$#" -gt 0 ]]; do --tooldir=*) TOOLDIR="${1#*=}" ;; --osversion=*) OSVERSION="${1#*=}" ;; --prefix=*) PREFIX="${1#*=}" ;; - --vm_enable=*) VM_ENABLE="${1#*=}" ;; -h|--help) usage ;; *) echo "Unknown parameter passed: $1"; usage ;; esac diff --git a/kernel/Makefile b/kernel/Makefile index 16d279fa0..201ebc200 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -32,10 +32,6 @@ CFLAGS += -O3 -mcmodel=medany -fno-exceptions -fdata-sections -ffunction-section CFLAGS += -I$(INC_DIR) -I$(ROOT_DIR)/hw CFLAGS += -DXLEN_$(XLEN) -ifeq ($(VM_ENABLE), 1) -CFLAGS += -DVM_ENABLE -endif - PROJECT := libvortex SRCS = $(SRC_DIR)/vx_start.S $(SRC_DIR)/vx_syscalls.c $(SRC_DIR)/vx_print.S $(SRC_DIR)/tinyprintf.c $(SRC_DIR)/vx_print.c $(SRC_DIR)/vx_spawn.c $(SRC_DIR)/vx_serial.S $(SRC_DIR)/vx_perf.c diff --git a/runtime/simx/Makefile b/runtime/simx/Makefile index 31ab483e7..89ad5dd3a 100644 --- a/runtime/simx/Makefile +++ b/runtime/simx/Makefile @@ -10,10 +10,6 @@ CXXFLAGS += -I$(INC_DIR) -I../common -I$(ROOT_DIR)/hw -I$(SIM_DIR)/simx -I$(COMM CXXFLAGS += $(CONFIGS) CXXFLAGS += -DXLEN_$(XLEN) -ifeq ($(VM_ENABLE), 1) -CXXFLAGS += -DVM_ENABLE -endif - LDFLAGS += -shared -pthread LDFLAGS += -L$(DESTDIR) -lsimx @@ -46,4 +42,4 @@ clean-runtime: clean: clean-driver clean-runtime -.PHONY: all driver clean-driver clean-runtime clean \ No newline at end of file +.PHONY: all driver clean-driver clean-runtime clean diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index 1c8f47eaf..c2d04400e 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -56,7 +56,8 @@ public: { // attach memory module processor_.attach_ram(&ram_); -#ifdef VM_ENABLE +#ifdef VM_ENABLE + //std::cout << "***VM ENABLED!!***"<< std::endl; CHECK_ERR(init_VM(), ); #endif } diff --git a/sim/simx/Makefile b/sim/simx/Makefile index 33120b13c..31fde7023 100644 --- a/sim/simx/Makefile +++ b/sim/simx/Makefile @@ -14,10 +14,6 @@ CXXFLAGS += -I$(THIRD_PARTY_DIR)/ramulator/src CXXFLAGS += -DXLEN_$(XLEN) CXXFLAGS += $(CONFIGS) -ifeq ($(VM_ENABLE), 1) -CXXFLAGS += -DVM_ENABLE -endif - LDFLAGS += $(THIRD_PARTY_DIR)/softfloat/build/Linux-x86_64-GCC/softfloat.a LDFLAGS += -Wl,-rpath,$(THIRD_PARTY_DIR)/ramulator -L$(THIRD_PARTY_DIR)/ramulator -lramulator diff --git a/tests/kernel/common.mk b/tests/kernel/common.mk index e3f6b472b..cd0d2c409 100644 --- a/tests/kernel/common.mk +++ b/tests/kernel/common.mk @@ -2,8 +2,10 @@ ROOT_DIR := $(realpath ../../..) ifeq ($(XLEN),64) CFLAGS += -march=rv64imafd -mabi=lp64d +STARTUP_ADDR ?= 0x180000000 else CFLAGS += -march=rv32imaf -mabi=ilp32f +STARTUP_ADDR ?= 0x80000000 endif LLVM_CFLAGS += --sysroot=$(RISCV_SYSROOT) @@ -29,7 +31,7 @@ CFLAGS += -DXLEN_$(XLEN) -DNDEBUG LIBC_LIB += -L$(LIBC_VORTEX)/lib -lm -lc LIBC_LIB += $(LIBCRT_VORTEX)/lib/baremetal/libclang_rt.builtins-riscv$(XLEN).a -LDFLAGS += -Wl,-Bstatic,--gc-sections,-T,$(VORTEX_KN_PATH)/scripts/link$(XLEN).ld,--defsym=STARTUP_ADDR=0x80000000 $(ROOT_DIR)/kernel/libvortex.a $(LIBC_LIB) +LDFLAGS += -Wl,-Bstatic,--gc-sections,-T,$(VORTEX_KN_PATH)/scripts/link$(XLEN).ld,--defsym=STARTUP_ADDR=$(STARTUP_ADDR) $(ROOT_DIR)/kernel/libvortex.a $(LIBC_LIB) all: $(PROJECT).elf $(PROJECT).bin $(PROJECT).dump From 9902856221685fb735a82a3b50cbb550a515c143 Mon Sep 17 00:00:00 2001 From: jaewon-lee-github Date: Fri, 20 Sep 2024 09:05:54 -0400 Subject: [PATCH 72/75] VERILATOR --- ci/toolchain_env.sh.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/toolchain_env.sh.in b/ci/toolchain_env.sh.in index dc50389a9..2c7373237 100755 --- a/ci/toolchain_env.sh.in +++ b/ci/toolchain_env.sh.in @@ -16,8 +16,8 @@ TOOLDIR=${TOOLDIR:=@TOOLDIR@} -export VERILATOR_ROOT=$TOOLDIR/verilator -export PATH=$VERILATOR_ROOT/bin:$PATH +#export VERILATOR_ROOT=$TOOLDIR/verilator +#export PATH=$VERILATOR_ROOT/bin:$PATH export SV2V_PATH=$TOOLDIR/sv2v export PATH=$SV2V_PATH/bin:$PATH From 9cc00108350f7dc6fb9fa28a155eb0ad6e73cde6 Mon Sep 17 00:00:00 2001 From: jaewon-lee-github Date: Fri, 20 Sep 2024 09:19:17 -0400 Subject: [PATCH 73/75] change verilator path --- ci/toolchain_env.sh.in | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ci/toolchain_env.sh.in b/ci/toolchain_env.sh.in index 2c7373237..9c3387c13 100755 --- a/ci/toolchain_env.sh.in +++ b/ci/toolchain_env.sh.in @@ -15,9 +15,7 @@ # limitations under the License. TOOLDIR=${TOOLDIR:=@TOOLDIR@} - -#export VERILATOR_ROOT=$TOOLDIR/verilator -#export PATH=$VERILATOR_ROOT/bin:$PATH +export PATH=$TOOLDIR/verilator/bin:$PATH export SV2V_PATH=$TOOLDIR/sv2v export PATH=$SV2V_PATH/bin:$PATH From 4383631543e61919f5ac6c35d740c1b3480f2387 Mon Sep 17 00:00:00 2001 From: jaewon-lee-github Date: Fri, 20 Sep 2024 09:58:50 -0400 Subject: [PATCH 74/75] Add BARE mode test and print out VM info --- ci/regression.sh.in | 10 +++++++--- runtime/simx/vortex.cpp | 8 +++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/ci/regression.sh.in b/ci/regression.sh.in index afd23c9ff..281635793 100755 --- a/ci/regression.sh.in +++ b/ci/regression.sh.in @@ -129,9 +129,13 @@ opencl() vm(){ echo "begin vm tests..." - CONFIGS="-DVM_ENABLE" make -C sim/simx - CONFIGS="-DVM_ENABLE" make -C runtime/simx - + make -C sim/simx clean && CONFIGS="-DVM_ENABLE" make -C sim/simx + make -C runtime/simx clean && CONFIGS="-DVM_ENABLE" make -C runtime/simx + make -C tests/opencl run-simx + make -C tests/regression run-simx + + make -C sim/simx clean && CONFIGS="-DVM_ENABLE -DVM_ADDR_MODE=BARE" make -C sim/simx + make -C runtime/simx clean && CONFIGS="-DVM_ENABLE -DVM_ADDR_MODE=BARE" make -C runtime/simx make -C tests/opencl run-simx make -C tests/regression run-simx diff --git a/runtime/simx/vortex.cpp b/runtime/simx/vortex.cpp index c2d04400e..673d73aa0 100644 --- a/runtime/simx/vortex.cpp +++ b/runtime/simx/vortex.cpp @@ -57,7 +57,7 @@ public: // attach memory module processor_.attach_ram(&ram_); #ifdef VM_ENABLE - //std::cout << "***VM ENABLED!!***"<< std::endl; + std::cout << "*** VM ENABLED!! ***"<< std::endl; CHECK_ERR(init_VM(), ); #endif } @@ -433,6 +433,12 @@ public: uint64_t pt_addr = 0; // Reserve space for PT DBGPRINT("[RT:init_VM] Initialize VM\n"); + DBGPRINT("* VM_ADDR_MODE=0x%lx", VM_ADDR_MODE); + DBGPRINT("* PAGE_TABLE_BASE_ADDR=0x%lx", PAGE_TABLE_BASE_ADDR); + DBGPRINT("* PT_LEVEL=0x%lx", PT_LEVEL); + DBGPRINT("* PT_SIZE=0x%lx", PT_SIZE); + DBGPRINT("* PTE_SIZE=0x%lx", PTE_SIZE); + DBGPRINT("* TLB_SIZE=0x%lx", TLB_SIZE); CHECK_ERR(mem_reserve(PAGE_TABLE_BASE_ADDR, PT_SIZE_LIMIT, VX_MEM_READ_WRITE), { return err; }); From 5ab13559e0d03d7329e028fc34a5fee15b18761f Mon Sep 17 00:00:00 2001 From: Jaewon Lee Date: Fri, 20 Sep 2024 10:08:53 -0400 Subject: [PATCH 75/75] Update README.md --- README.md | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 4322f06bc..ec8d10bd5 100644 --- a/README.md +++ b/README.md @@ -59,20 +59,17 @@ sudo apt-get install git ``` ### Configure your build folder ```sh - # - # By default, the toolchain default install location is the /opt folder and can be overridden by setting --tooldir. - # This is the example for volvo server mkdir build - mkdir out - export OUT_DIR=`pwd`/out cd build - # Run the following to disble virtual memory feature in compilation - ../configure --xlen=32 --tooldir=/software/vortex-toolchain-2024-2024-08-09 --prefix=$OUT_DIR - # Run the following instead to enable virtual memory feature in compilation - ../configure --xlen=32 --tooldir=/software/vortex-toolchain-2024-2024-08-09 --prefix=$OUT_DIR --vm_enable=1 + # for 32bit + ../configure --xlen=32 --tooldir=$HOME/tools + # for 64bit + ../configure --xlen=64 --tooldir=$HOME/tools ``` ### Install prebuilt toolchain - # We will use the precomipled tools in volvo toolchanin directory +```sh + ./ci/toolchain_install.sh --all +``` ### set environment variables ```sh # should always run before using the toolchain! @@ -82,7 +79,6 @@ sudo apt-get install git ```sh make -s ``` - ### Quick demo running vecadd OpenCL kernel on 2 cores ```sh ./ci/blackbox.sh --cores=2 --app=vecadd