| /* | |
| * Copyright (c) 2021 Huawei International | |
| * Copyright (c) 2023 Google LLC | |
| * All rights reserved | |
| * | |
| * The license below extends only to copyright in the software and shall | |
| * not be construed as granting a license to any other intellectual | |
| * property including but not limited to intellectual property relating | |
| * to a hardware implementation of the functionality of the software | |
| * licensed hereunder. You may use the software subject to the license | |
| * terms below provided that you ensure that this notice is replicated | |
| * unmodified and in its entirety in all distributions of the software, | |
| * modified or unmodified, in source code or in binary form. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions are | |
| * met: redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer; | |
| * redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution; | |
| * neither the name of the copyright holders nor the names of its | |
| * contributors may be used to endorse or promote products derived from | |
| * this software without specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| #ifndef __DEV_RISCV_PLIC_HH__ | |
| #define __DEV_RISCV_PLIC_HH__ | |
| #include <bitset> | |
| #include <map> | |
| #include "arch/riscv/interrupts.hh" | |
| #include "dev/io_device.hh" | |
| #include "dev/reg_bank.hh" | |
| #include "mem/packet.hh" | |
| #include "mem/packet_access.hh" | |
| #include "params/Plic.hh" | |
| #include "params/PlicBase.hh" | |
| #include "sim/system.hh" | |
| namespace gem5 | |
| { | |
| using namespace RiscvISA; | |
| /** | |
| * NOTE: | |
| * This implementation of CLINT is based on | |
| * the SiFive U54MC datasheet: | |
| * https://sifive.cdn.prismic.io/sifive/fab000f6- | |
| * 0e07-48d0-9602-e437d5367806_sifive_U54MC_rtl_ | |
| * full_20G1.03.00_manual.pdf | |
| */ | |
| /** | |
| * PLIC Latency Model | |
| * MMIO changed (aside from threshold) | |
| * => update internal states | |
| * => calculate new output | |
| * => schedule update (3 cycles delay) | |
| * => update output & schedule next update | |
| * => update xEIP lines | |
| * | |
| * threshold changed | |
| * => update xEIP lines | |
| * | |
| * This ensures cycle-accurate values for | |
| * MMIO accesses and xEIP lines | |
| * | |
| * NOTE: | |
| * check pending bit when returning maxID | |
| * to avoid claiming by multiple contexts. | |
| * Note that pending bits are not propagated | |
| * through the 3-cycle delay. | |
| * | |
| * TODO: | |
| * - Enforce access control (e.g. avoid S mode | |
| * writing to M mode registers) | |
| */ | |
| struct PlicOutput | |
| { | |
| std::vector<uint32_t> maxID; | |
| std::vector<uint32_t> maxPriority; | |
| }; | |
| class PlicBase : public BasicPioDevice | |
| { | |
| public: | |
| typedef PlicBaseParams Params; | |
| PlicBase(const Params ¶ms) : | |
| BasicPioDevice(params, params.pio_size) | |
| {} | |
| // Interrupt interface to send signal to PLIC | |
| virtual void post(int src_id) = 0; | |
| // Interrupt interface to clear signal to PLIC | |
| virtual void clear(int src_id) = 0; | |
| }; | |
| class Plic : public PlicBase | |
| { | |
| // Params | |
| protected: | |
| System *system; | |
| // Number of interrupt sources | |
| int nSrc; | |
| /** | |
| * Number of 32-bit pending registers needed | |
| * = ceil(nSrc / 32) | |
| */ | |
| int nSrc32; | |
| /** | |
| * Number of interrupt contexts | |
| * = nThread * 2 | |
| * e.g. context 0 => thread 0 M mode | |
| * context 1 => thread 0 S mode | |
| * This is based on SiFive U54MC datasheet | |
| */ | |
| int nContext; | |
| public: | |
| typedef PlicParams Params; | |
| Plic(const Params ¶ms); | |
| // External API | |
| public: | |
| /** | |
| * Interrupt interface | |
| */ | |
| void post(int src_id) override; | |
| void clear(int src_id) override; | |
| /** | |
| * SimObject functions | |
| */ | |
| void init() override; | |
| void serialize(CheckpointOut &cp) const override; | |
| void unserialize(CheckpointIn &cp) override; | |
| protected: | |
| /** | |
| * PioDevice funcitons | |
| */ | |
| Tick read(PacketPtr pkt) override; | |
| Tick write(PacketPtr pkt) override; | |
| // Register bank | |
| private: | |
| /** | |
| * MMIO Registers | |
| * | |
| * Priority (0-7): | |
| * - memory map: 0x0000000 - 0x0000FFC | |
| * (1024 sources, 32 bits each) | |
| * - gem5: vector<uint32_t> | |
| * (index: source_id, size: n_src) | |
| * | |
| * ... reserved[0] | |
| * | |
| * Pending: | |
| * - memory map: 0x0001000 - 0x0001080 | |
| * (1024 sources, 1 bit each) | |
| * - gem5: vector<bitset<32>> | |
| * (index: addr_offset, size: ceil(n_src/32)) | |
| * | |
| * ... reserved[1] | |
| * | |
| * Enable: | |
| * - memory map: 0x0002000 - 0x01F2000 | |
| * (15872 contexts, 1024 sources, 1 bit each) | |
| * - gem5: vector<vector<bitset<32>>> | |
| * (index: [context_id addr_offset], size: [n_context, ceil(n_src/32)]) | |
| * ... reserved[2] | |
| * | |
| * Threshold: | |
| * - memory map: 0x0200000 - 0x3FFFFFC | |
| * (15872 contexts, 32-bit each, 0x1000 byte spacing) | |
| * - gem5: vector<uint32_t> | |
| * (index: context_id, size: n_context) | |
| * | |
| * Claim / Complete: | |
| * - memory map: 0x0200004 - 0x3FFFFFC | |
| * (15872 contexts, 32-bit each, 0x1000 byte spacing) | |
| * - gem5: getter / setter functions | |
| * | |
| * ... reserved[3] | |
| */ | |
| class PlicRegisters: public RegisterBankLE | |
| { | |
| public: | |
| const Addr pendingStart = 0x1000; | |
| const Addr enableStart = 0x2000; | |
| const Addr thresholdStart = 0x0200000; | |
| const Addr enablePadding = 0x80; | |
| const Addr thresholdPadding = 0x1000; | |
| const Addr maxBankSize = 0x4000000; | |
| std::vector<Register32> priority; | |
| std::vector<Register32> pending; | |
| std::vector<std::vector<Register32>> enable; | |
| std::vector<Register32> threshold; | |
| std::vector<Register32> claim; | |
| std::vector<RegisterRaz> enable_holes; | |
| std::vector<RegisterRaz> claim_holes; | |
| std::vector<RegisterRaz> reserved; | |
| PlicRegisters(const std::string &name, Addr base, Plic* plic) : | |
| RegisterBankLE(name, base), | |
| plic(plic) {} | |
| Plic* plic; | |
| void init(); | |
| } registers; | |
| using Register32 = PlicRegisters::Register32; | |
| /** | |
| * Register read / write callbacks | |
| */ | |
| void writePriority(Register32& reg, const uint32_t& data, | |
| const int src_id); | |
| void writeEnable(Register32& reg, const uint32_t& data, | |
| const int src32_id, const int context_id); | |
| void writeThreshold(Register32& reg, const uint32_t& data, | |
| const int context_id); | |
| uint32_t readClaim(Register32& reg, const int context_id); | |
| void writeClaim(Register32& reg, const uint32_t& data, | |
| const int context_id); | |
| // Latency Model | |
| private: | |
| // Internal states | |
| // per-source pending * priority | |
| std::vector<uint32_t> pendingPriority; | |
| // per-context, per-source pendingPriority * enable | |
| std::vector<std::vector<uint32_t>> effPriority; | |
| // per-context last-claimed id | |
| std::vector<uint32_t> lastID; | |
| PlicOutput output; | |
| /** | |
| * Trigger: | |
| * - Plic::post | |
| * - Plic::clear | |
| * - Plic::write | |
| * | |
| * Task: | |
| * - calculate new output | |
| * - schedule next update event and/or | |
| * add new output to outputQueue | |
| */ | |
| void propagateOutput(); | |
| std::map<Tick, PlicOutput> outputQueue; | |
| EventFunctionWrapper update; | |
| /** | |
| * Trigger: | |
| * - Plic::update event | |
| * | |
| * Task: | |
| * - set current output to new output | |
| * - schedule next update event (if any) | |
| */ | |
| void updateOutput(); | |
| /** | |
| * Trigger: | |
| * - Plic::update event | |
| * - Plic::write | |
| * | |
| * Task: | |
| * - update xEIP lines based on new | |
| * output and threshold | |
| */ | |
| void updateInt(); | |
| }; | |
| } // namespace gem5 | |
| #endif // __DEV_RISCV_PLIC_HH__ |