21
									
								
								include/bus.hh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								include/bus.hh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "memory.hh"
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
class Bus {
 | 
			
		||||
  public:
 | 
			
		||||
    Bus(Memory& memory);
 | 
			
		||||
 | 
			
		||||
    uint8_t read_byte(size_t address);
 | 
			
		||||
    void write_byte(size_t address, uint8_t byte);
 | 
			
		||||
 | 
			
		||||
    uint16_t read_halfword(size_t address);
 | 
			
		||||
    void write_halfword(size_t address, uint16_t halfword);
 | 
			
		||||
 | 
			
		||||
    uint32_t read_word(size_t address);
 | 
			
		||||
    void write_word(size_t address, uint32_t word);
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    std::shared_ptr<Memory> memory;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										55
									
								
								include/cpu/cpu.hh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								include/cpu/cpu.hh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "bus.hh"
 | 
			
		||||
#include "instruction.hh"
 | 
			
		||||
#include "psr.hh"
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
using std::size_t;
 | 
			
		||||
 | 
			
		||||
class Cpu {
 | 
			
		||||
  public:
 | 
			
		||||
    Cpu(Bus& bus);
 | 
			
		||||
    void step();
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    static constexpr size_t GPR_COUNT = 16;
 | 
			
		||||
 | 
			
		||||
    static constexpr size_t GPR_FIQ_FIRST     = 8;
 | 
			
		||||
    static constexpr size_t GPR_SVC_FIRST     = 13;
 | 
			
		||||
    static constexpr size_t GPR_ABT_FIRST     = 13;
 | 
			
		||||
    static constexpr size_t GPR_IRQ_FIRST     = 13;
 | 
			
		||||
    static constexpr size_t GPR_UND_FIRST     = 13;
 | 
			
		||||
    static constexpr size_t GPR_SYS_USR_FIRST = 8;
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<Bus> bus;
 | 
			
		||||
    std::array<uint32_t, GPR_COUNT> gpr; // general purpose registers
 | 
			
		||||
 | 
			
		||||
    Psr cpsr; // current program status register
 | 
			
		||||
    Psr spsr; // status program status register
 | 
			
		||||
 | 
			
		||||
    uint32_t& pc = gpr[15];
 | 
			
		||||
 | 
			
		||||
    struct {
 | 
			
		||||
        std::array<uint32_t, GPR_COUNT - GPR_FIQ_FIRST - 1> fiq;
 | 
			
		||||
        std::array<uint32_t, GPR_COUNT - GPR_SVC_FIRST - 1> svc;
 | 
			
		||||
        std::array<uint32_t, GPR_COUNT - GPR_ABT_FIRST - 1> abt;
 | 
			
		||||
        std::array<uint32_t, GPR_COUNT - GPR_IRQ_FIRST - 1> irq;
 | 
			
		||||
        std::array<uint32_t, GPR_COUNT - GPR_UND_FIRST - 1> und;
 | 
			
		||||
 | 
			
		||||
        // visible registers before the mode switch
 | 
			
		||||
        std::array<uint32_t, GPR_COUNT - GPR_SYS_USR_FIRST> old;
 | 
			
		||||
    } gpr_banked; // banked general purpose registers
 | 
			
		||||
 | 
			
		||||
    struct {
 | 
			
		||||
        Psr fiq;
 | 
			
		||||
        Psr svc;
 | 
			
		||||
        Psr abt;
 | 
			
		||||
        Psr irq;
 | 
			
		||||
        Psr und;
 | 
			
		||||
    } spsr_banked; // banked saved program status registers
 | 
			
		||||
 | 
			
		||||
    void chg_mode(const Mode to);
 | 
			
		||||
    void exec_arm(const ArmInstruction instruction);
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										132
									
								
								include/cpu/instruction.hh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								include/cpu/instruction.hh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,132 @@
 | 
			
		||||
#include "cpu/utility.hh"
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <variant>
 | 
			
		||||
 | 
			
		||||
template<class... Ts>
 | 
			
		||||
struct overloaded : Ts... {
 | 
			
		||||
    using Ts::operator()...;
 | 
			
		||||
};
 | 
			
		||||
template<class... Ts>
 | 
			
		||||
overloaded(Ts...) -> overloaded<Ts...>;
 | 
			
		||||
 | 
			
		||||
class ArmInstruction {
 | 
			
		||||
  public:
 | 
			
		||||
    ArmInstruction() = delete;
 | 
			
		||||
    ArmInstruction(uint32_t insn);
 | 
			
		||||
 | 
			
		||||
    auto get_condition() const { return condition; }
 | 
			
		||||
    auto get_data() const { return data; }
 | 
			
		||||
 | 
			
		||||
    std::string disassemble();
 | 
			
		||||
 | 
			
		||||
    struct BranchAndExchange {
 | 
			
		||||
        uint8_t rn;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct Branch {
 | 
			
		||||
        bool link;
 | 
			
		||||
        uint32_t offset;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct Multiply {
 | 
			
		||||
        uint8_t rm;
 | 
			
		||||
        uint8_t rs;
 | 
			
		||||
        uint8_t rn;
 | 
			
		||||
        uint8_t rd;
 | 
			
		||||
        bool set;
 | 
			
		||||
        bool acc;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct MultiplyLong {
 | 
			
		||||
        uint8_t rm;
 | 
			
		||||
        uint8_t rs;
 | 
			
		||||
        uint8_t rdlo;
 | 
			
		||||
        uint8_t rdhi;
 | 
			
		||||
        bool set;
 | 
			
		||||
        bool acc;
 | 
			
		||||
        bool uns;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct SingleDataSwap {
 | 
			
		||||
        uint8_t rm;
 | 
			
		||||
        uint8_t rd;
 | 
			
		||||
        uint8_t rn;
 | 
			
		||||
        bool byte;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct SingleDataTransfer {
 | 
			
		||||
        std::variant<uint16_t, Shift> offset;
 | 
			
		||||
        uint8_t rd;
 | 
			
		||||
        uint8_t rn;
 | 
			
		||||
        bool load;
 | 
			
		||||
        bool write;
 | 
			
		||||
        bool byte;
 | 
			
		||||
        bool up;
 | 
			
		||||
        bool pre;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct HalfwordTransfer {
 | 
			
		||||
        uint8_t offset;
 | 
			
		||||
        bool half;
 | 
			
		||||
        bool sign;
 | 
			
		||||
        uint8_t rd;
 | 
			
		||||
        uint8_t rn;
 | 
			
		||||
        bool load;
 | 
			
		||||
        bool write;
 | 
			
		||||
        bool byte;
 | 
			
		||||
        bool imm;
 | 
			
		||||
        bool up;
 | 
			
		||||
        bool pre;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct CoprocessorDataTransfer {
 | 
			
		||||
        uint8_t offset;
 | 
			
		||||
        uint8_t cpn;
 | 
			
		||||
        uint8_t crd;
 | 
			
		||||
        uint8_t rn;
 | 
			
		||||
        bool load;
 | 
			
		||||
        bool write;
 | 
			
		||||
        bool len;
 | 
			
		||||
        bool up;
 | 
			
		||||
        bool pre;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct CoprocessorDataOperation {
 | 
			
		||||
        uint8_t crm;
 | 
			
		||||
        uint8_t cp;
 | 
			
		||||
        uint8_t cpn;
 | 
			
		||||
        uint8_t crd;
 | 
			
		||||
        uint8_t crn;
 | 
			
		||||
        uint8_t cp_opc;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct CoprocessorRegisterTransfer {
 | 
			
		||||
        uint8_t crm;
 | 
			
		||||
        uint8_t cp;
 | 
			
		||||
        uint8_t cpn;
 | 
			
		||||
        uint8_t rd;
 | 
			
		||||
        uint8_t crn;
 | 
			
		||||
        bool load;
 | 
			
		||||
        uint8_t cp_opc;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct Undefined {};
 | 
			
		||||
    struct SoftwareInterrupt {};
 | 
			
		||||
 | 
			
		||||
    using InstructionData = std::variant<BranchAndExchange,
 | 
			
		||||
                                         Branch,
 | 
			
		||||
                                         Multiply,
 | 
			
		||||
                                         MultiplyLong,
 | 
			
		||||
                                         SingleDataSwap,
 | 
			
		||||
                                         SingleDataTransfer,
 | 
			
		||||
                                         HalfwordTransfer,
 | 
			
		||||
                                         CoprocessorDataTransfer,
 | 
			
		||||
                                         CoprocessorDataOperation,
 | 
			
		||||
                                         CoprocessorRegisterTransfer,
 | 
			
		||||
                                         Undefined,
 | 
			
		||||
                                         SoftwareInterrupt>;
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    Condition condition;
 | 
			
		||||
    InstructionData data;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										52
									
								
								include/cpu/psr.hh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								include/cpu/psr.hh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "utility.hh"
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
class Psr {
 | 
			
		||||
  public:
 | 
			
		||||
    // clear the reserved bits i.e, [8:27]
 | 
			
		||||
    Psr(uint32_t raw);
 | 
			
		||||
 | 
			
		||||
    // Mode : [4:0]
 | 
			
		||||
    Mode mode() const;
 | 
			
		||||
    void set_mode(Mode mode);
 | 
			
		||||
 | 
			
		||||
    // State : [5]
 | 
			
		||||
    State state() const;
 | 
			
		||||
    void set_state(State state);
 | 
			
		||||
 | 
			
		||||
#define GET_SET_NTH_BIT_FUNCTIONS(name)                                        \
 | 
			
		||||
    bool name() const;                                                         \
 | 
			
		||||
    void set_##name(bool val);
 | 
			
		||||
 | 
			
		||||
    // FIQ disable : [6]
 | 
			
		||||
    GET_SET_NTH_BIT_FUNCTIONS(fiq_disabled)
 | 
			
		||||
 | 
			
		||||
    // IRQ disable : [7]
 | 
			
		||||
    GET_SET_NTH_BIT_FUNCTIONS(irq_disabled)
 | 
			
		||||
 | 
			
		||||
    // Reserved bits : [27:8]
 | 
			
		||||
 | 
			
		||||
    // Overflow flag : [28]
 | 
			
		||||
    GET_SET_NTH_BIT_FUNCTIONS(v)
 | 
			
		||||
 | 
			
		||||
    // Carry flag : [29]
 | 
			
		||||
    GET_SET_NTH_BIT_FUNCTIONS(c)
 | 
			
		||||
 | 
			
		||||
    // Zero flag : [30]
 | 
			
		||||
    GET_SET_NTH_BIT_FUNCTIONS(z)
 | 
			
		||||
 | 
			
		||||
    // Negative flag : [30]
 | 
			
		||||
    GET_SET_NTH_BIT_FUNCTIONS(n)
 | 
			
		||||
 | 
			
		||||
#undef GET_SET_NTH_BIT_FUNCTIONS
 | 
			
		||||
 | 
			
		||||
    bool condition(Condition cond) const;
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    static constexpr uint32_t PSR_CLEAR_RESERVED = 0xf00000ff;
 | 
			
		||||
    static constexpr uint32_t PSR_CLEAR_MODE     = 0x0b00000;
 | 
			
		||||
 | 
			
		||||
    uint32_t psr;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										93
									
								
								include/cpu/utility.hh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								include/cpu/utility.hh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,93 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <fmt/ostream.h>
 | 
			
		||||
#include <ostream>
 | 
			
		||||
 | 
			
		||||
static constexpr size_t ARM_INSTRUCTION_SIZE   = 4;
 | 
			
		||||
static constexpr size_t THUMB_INSTRUCTION_SIZE = 2;
 | 
			
		||||
 | 
			
		||||
enum class Mode {
 | 
			
		||||
    /* M[4:0] in PSR */
 | 
			
		||||
    User       = 0b10000,
 | 
			
		||||
    Fiq        = 0b10001,
 | 
			
		||||
    Irq        = 0b10010,
 | 
			
		||||
    Supervisor = 0b10011,
 | 
			
		||||
    Abort      = 0b10111,
 | 
			
		||||
    Undefined  = 0b11011,
 | 
			
		||||
    System     = 0b11111,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class State {
 | 
			
		||||
    Arm   = 0,
 | 
			
		||||
    Thumb = 1
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class Condition {
 | 
			
		||||
    EQ = 0b0000,
 | 
			
		||||
    NE = 0b0001,
 | 
			
		||||
    CS = 0b0010,
 | 
			
		||||
    CC = 0b0011,
 | 
			
		||||
    MI = 0b0100,
 | 
			
		||||
    PL = 0b0101,
 | 
			
		||||
    VS = 0b0110,
 | 
			
		||||
    VC = 0b0111,
 | 
			
		||||
    HI = 0b1000,
 | 
			
		||||
    LS = 0b1001,
 | 
			
		||||
    GE = 0b1010,
 | 
			
		||||
    LT = 0b1011,
 | 
			
		||||
    GT = 0b1100,
 | 
			
		||||
    LE = 0b1101,
 | 
			
		||||
    AL = 0b1110
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// https://fmt.dev/dev/api.html#std-ostream-support
 | 
			
		||||
std::ostream&
 | 
			
		||||
operator<<(std::ostream& os, const Condition cond);
 | 
			
		||||
template<>
 | 
			
		||||
struct fmt::formatter<Condition> : ostream_formatter {};
 | 
			
		||||
 | 
			
		||||
enum class OpCode {
 | 
			
		||||
    AND = 0b0000,
 | 
			
		||||
    EOR = 0b0001,
 | 
			
		||||
    SUB = 0b0010,
 | 
			
		||||
    RSB = 0b0011,
 | 
			
		||||
    ADD = 0b0100,
 | 
			
		||||
    ADC = 0b0101,
 | 
			
		||||
    SBC = 0b0110,
 | 
			
		||||
    RSC = 0b0111,
 | 
			
		||||
    TST = 0b1000,
 | 
			
		||||
    TEQ = 0b1001,
 | 
			
		||||
    CMP = 0b1010,
 | 
			
		||||
    CMN = 0b1011,
 | 
			
		||||
    ORR = 0b1100,
 | 
			
		||||
    MOV = 0b1101,
 | 
			
		||||
    BIC = 0b1110,
 | 
			
		||||
    MVN = 0b1111
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class ShiftType {
 | 
			
		||||
    LSL = 0b00,
 | 
			
		||||
    LSR = 0b01,
 | 
			
		||||
    ASR = 0b10,
 | 
			
		||||
    ROR = 0b11
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ShiftData {
 | 
			
		||||
    ShiftType type;
 | 
			
		||||
    bool immediate;
 | 
			
		||||
    uint8_t operand;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Shift {
 | 
			
		||||
    uint8_t rm;
 | 
			
		||||
    ShiftData data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
uint32_t
 | 
			
		||||
eval_shift(ShiftType shift_type, uint32_t value, uint8_t amount, bool& carry);
 | 
			
		||||
 | 
			
		||||
// https://fmt.dev/dev/api.html#std-ostream-support
 | 
			
		||||
std::ostream&
 | 
			
		||||
operator<<(std::ostream& os, const ShiftType cond);
 | 
			
		||||
template<>
 | 
			
		||||
struct fmt::formatter<ShiftType> : ostream_formatter {};
 | 
			
		||||
							
								
								
									
										44
									
								
								include/header.hh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								include/header.hh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
struct Header {
 | 
			
		||||
    enum class UniqueCode {
 | 
			
		||||
        Old,        // old games
 | 
			
		||||
        New,        // new games
 | 
			
		||||
        Newer,      // unused (newer games)
 | 
			
		||||
        Famicom,    // NES
 | 
			
		||||
        YoshiKoro,  // acceleration sensor
 | 
			
		||||
        Ereader,    // dot code scanner
 | 
			
		||||
        Warioware,  // rumble and z-axis gyro
 | 
			
		||||
        Boktai,     // RTC and solar sensor
 | 
			
		||||
        DrillDozer, // rumble
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    enum class I18n {
 | 
			
		||||
        Japan,
 | 
			
		||||
        Europe,
 | 
			
		||||
        French,
 | 
			
		||||
        Spanish,
 | 
			
		||||
        Usa,
 | 
			
		||||
        German,
 | 
			
		||||
        Italian
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    enum class BootMode {
 | 
			
		||||
        Joybus,
 | 
			
		||||
        Normal,
 | 
			
		||||
        Multiplay
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    uint32_t entrypoint;
 | 
			
		||||
    std::string title;
 | 
			
		||||
    std::string title_code;
 | 
			
		||||
    UniqueCode unique_code;
 | 
			
		||||
    I18n i18n;
 | 
			
		||||
    uint8_t version;
 | 
			
		||||
    BootMode multiboot;
 | 
			
		||||
    uint32_t multiboot_entrypoint;
 | 
			
		||||
    uint8_t slave_id;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										64
									
								
								include/memory.hh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								include/memory.hh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "header.hh"
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
class Memory {
 | 
			
		||||
  public:
 | 
			
		||||
    static constexpr size_t BIOS_SIZE = 1024 * 16;
 | 
			
		||||
 | 
			
		||||
    Memory(std::array<uint8_t, BIOS_SIZE>&& bios,
 | 
			
		||||
           std::vector<uint8_t>&& rom) noexcept;
 | 
			
		||||
 | 
			
		||||
    uint8_t read(size_t address) const;
 | 
			
		||||
    void write(size_t address, uint8_t byte);
 | 
			
		||||
 | 
			
		||||
    uint16_t read_halfword(size_t address) const;
 | 
			
		||||
    void write_halfword(size_t address, uint16_t halfword);
 | 
			
		||||
 | 
			
		||||
    uint32_t read_word(size_t address) const;
 | 
			
		||||
    void write_word(size_t address, uint32_t word);
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
#define MEMORY_REGION(name, start, end)                                        \
 | 
			
		||||
    static constexpr size_t name##_START = start;                              \
 | 
			
		||||
    static constexpr size_t name##_END   = end;
 | 
			
		||||
 | 
			
		||||
#define DECL_MEMORY(name, ident, start, end)                                   \
 | 
			
		||||
    MEMORY_REGION(name, start, end)                                            \
 | 
			
		||||
    std::array<uint8_t, name##_END - name##_START + 1> ident;
 | 
			
		||||
 | 
			
		||||
    MEMORY_REGION(BIOS, 0x00000000, 0x00003FFF)
 | 
			
		||||
    std::array<uint8_t, BIOS_SIZE> bios;
 | 
			
		||||
    static_assert(BIOS_END - BIOS_START + 1 == BIOS_SIZE);
 | 
			
		||||
 | 
			
		||||
    // board working RAM
 | 
			
		||||
    DECL_MEMORY(BOARD_WRAM, board_wram, 0x02000000, 0x0203FFFF)
 | 
			
		||||
 | 
			
		||||
    // chip working RAM
 | 
			
		||||
    DECL_MEMORY(CHIP_WRAM, chip_wram, 0x03000000, 0x03007FFF)
 | 
			
		||||
 | 
			
		||||
    // palette RAM
 | 
			
		||||
    DECL_MEMORY(PALETTE_RAM, palette_ram, 0x05000000, 0x050003FF)
 | 
			
		||||
 | 
			
		||||
    // video RAM
 | 
			
		||||
    DECL_MEMORY(VRAM, vram, 0x06000000, 0x06017FFF)
 | 
			
		||||
 | 
			
		||||
    // OAM OBJ attributes
 | 
			
		||||
    DECL_MEMORY(OAM_OBJ_ATTR, oam_obj_attr, 0x07000000, 0x070003FF)
 | 
			
		||||
 | 
			
		||||
#undef DECL_MEMORY
 | 
			
		||||
 | 
			
		||||
    MEMORY_REGION(ROM_0, 0x08000000, 0x09FFFFFF)
 | 
			
		||||
    MEMORY_REGION(ROM_1, 0x0A000000, 0x0BFFFFFF)
 | 
			
		||||
    MEMORY_REGION(ROM_2, 0x0C000000, 0x0DFFFFFF)
 | 
			
		||||
 | 
			
		||||
#undef MEMORY_REGION
 | 
			
		||||
 | 
			
		||||
    std::vector<uint8_t> rom;
 | 
			
		||||
    Header header;
 | 
			
		||||
    void parse_header();
 | 
			
		||||
};
 | 
			
		||||
		Reference in New Issue
	
	Block a user