Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 40 additions & 20 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -1,39 +1,59 @@
BasedOnStyle: LLVM

# ---- Indentation ----
IndentWidth: 4
TabWidth: 4
UseTab: Never

# Keep namespaces flush-left (no indent inside)
# Do NOT indent inside namespaces
NamespaceIndentation: None

# Braces
# Indent access specifiers (public / private)
IndentAccessModifiers: true
AccessModifierOffset: -2

# Indent case labels inside switch
IndentCaseLabels: true

# ---- Line length ----
ColumnLimit: 110

# ---- Braces & control flow ----
BreakBeforeBraces: Attach
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AllowShortBlocksOnASingleLine: Never
AllowShortFunctionsOnASingleLine: Empty

# Constructor initializer list formatting
ConstructorInitializerIndentWidth: 4
BreakConstructorInitializers: AfterColon
ConstructorInitializerAllOnOneLineOrOnePerLine: false
# ---- Alignment ----
AlignAfterOpenBracket: Align
AlignOperands: Align
AlignTrailingComments: true

# Pointer and reference alignment
# ---- Spacing ----
SpaceBeforeParens: ControlStatements
SpacesInParentheses: false
SpacesInSquareBrackets: false

# ---- Pointers / references ----
PointerAlignment: Left
ReferenceAlignment: Left
DerivePointerAlignment: false

# Column limit
ColumnLimit: 120
# ---- Constructors ----
BreakConstructorInitializers: AfterColon
ConstructorInitializerIndentWidth: 4

# Spaces
SpaceBeforeParens: ControlStatements
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpacesInAngles: false
SpaceBeforeAssignmentOperators: true
# ---- Templates / lists ----
AlwaysBreakTemplateDeclarations: Yes
Cpp11BracedListStyle: true

# Indent access specifiers (public:, private:) 1 level
AccessModifierOffset: -4
# ---- Includes ----
SortIncludes: true
IncludeBlocks: Preserve

# Indent case labels inside switch
IndentCaseLabels: true
# --- Horizontal spacing is not allowed
AllowShortCaseLabelsOnASingleLine: false
AllowAllArgumentsOnNextLine: false
BinPackArguments: false
BinPackParameters: false
249 changes: 249 additions & 0 deletions STYLES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
# C++ Style Guide

This project follows an LLVM-inspired C++ style, tuned for emulator and
systems programming.

Consistency and clarity are prioritized over cleverness.

---

## Formatting

Formatting is enforced via `clang-format`.

- Base style: LLVM
- Indentation: **2 spaces**
- Tabs: **never**
- Brace style: K&R (opening brace on same line)
- Column limit: ~110 characters
- Access specifiers (`public`, `private`) are indented for readability,
especially when multiple classes exist in one file.

### Formatting commands

Format a single file:
```bash
clang-format -i path/to/file.cpp
````

Format multiple files:

```bash
clang-format -i src/**/*.cpp include/**/*.h
```

Format only changed lines:

```bash
git clang-format
```

---

## Naming Conventions

### Namespaces

* **PascalCase**

```cpp
namespace GameBoy
namespace Cartridge
namespace CPU
```

---

### Types (classes, structs, enums)

* **PascalCase**

```cpp
class MBC1;
struct RomHeader;
enum class CartridgeType;
```

---

### Functions

* **snake_case**

```cpp
validate_rom_file(...)
clamp_rom_bank_(...)
```

---

### Variables

* **snake_case**

```cpp
rom_size_code
ram_enabled
```

---

### Member Variables

* **snake_case with trailing underscore**

```cpp
rom_bank_low5_
ram_enabled_
```

---

### Constants

* **ALL_CAPS with underscores**
* Prefer `constexpr` over macros

```cpp
constexpr uint16_t ROM_BEGIN = 0x0100;
constexpr uint16_t HEADER_CHECKSUM_OFFSET = 0x014D;
```

---

### Enums

* Always use `enum class`
* Specify underlying type when relevant

```cpp
enum class MBCType : uint8_t {
ROM_ONLY = 0x00,
MBC1 = 0x01,
};
```

---

## C++ Language Rules

### Constructors

* Use `explicit` for all domain objects

```cpp
explicit MBC1(const std::vector<uint8_t>& rom,
std::vector<uint8_t>& ram);
```

---

### Polymorphism

* Use `override` for **every** overridden virtual function
* Use `final` for leaf classes
* Base destructors must be virtual

---

### Copy / Move Semantics

* Hardware-like identity objects (CPU, MBC, MMU, PPU) must not be copied or moved

```cpp
MBC(const MBC&) = delete;
MBC& operator=(const MBC&) = delete;
MBC(MBC&&) = delete;
MBC& operator=(MBC&&) = delete;
```

---

### Ownership

* Use `std::unique_ptr` for ownership
* Avoid raw `new` / `delete`
* Use references or raw pointers **only** for non-owning access

---

## Comments

### Philosophy

* Code explains **what**
* Comments explain **why**

---

### Hardware Behavior

Hardware-specific logic **must be commented** and should reference
authoritative sources (e.g., Pan Docs).

```cpp
// Pan Docs §Cartridge Header:
// Bytes 0x0134–0x014C are used for header checksum computation.
```

---

### Address Ranges

Always document address ranges explicitly.

```cpp
// ROM bank select register (0x2000–0x3FFF).
```

---

### Algorithms

Use short block comments for non-trivial logic.

```cpp
// Header checksum algorithm:
// 1. Iterate bytes 0x0134–0x014C
// 2. Subtract each byte and 1 from accumulator
// 3. Result must equal byte at 0x014D
```

---

### File Headers

Each `.cpp` file should start with a short header:

```cpp
// rom-validation.cpp
// Cartridge ROM header validation.
// Created by William Kiem Lafond on 2025-09-17.
```

Keep file headers factual and brief.

---

### Avoid

* Commenting obvious code
* Large prose blocks
* Stale comments (e.g., "last modified by")

---

## Includes

* Headers must be self-contained
* Do not use `using namespace` in headers
* Prefer forward declarations where reasonable

---

## General Principles

* Make illegal states unrepresentable
* Prefer early returns
* Prefer table-driven logic for hot paths
* Optimize for readability before micro-optimizations
53 changes: 26 additions & 27 deletions include/helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,31 @@
#include <sstream>

namespace Gameboy {
/*
* Message helper for formatting one arugment.
*
* Examples:
* msg("PC = ", pc);
*/
template <typename T>
static std::string msg(const char* prefix, T value) {
std::ostringstream oss;
oss << prefix << value;
return oss.str();
}

/*
* Message helper that formats one argue in the middle as well as the end.
*
* Examples:
* msg("I am ", 21, " years and ", 3.0/4.0);
* msg("Bank ", bank, " selected: ", romBank);
*/
template <typename A, typename B>
static std::string msg(const char* prefix, A a,
const char* mid, B b) {
std::ostringstream oss;
oss << prefix << a << mid << b;
return oss.str();
}
/*
* Message helper for formatting one arugment.
*
* Examples:
* msg("PC = ", pc);
*/
template <typename T>
static std::string msg(const char* prefix, T value) {
std::ostringstream oss;
oss << prefix << value;
return oss.str();
}

/*
* Message helper that formats one argue in the middle as well as the end.
*
* Examples:
* msg("I am ", 21, " years and ", 3.0/4.0);
* msg("Bank ", bank, " selected: ", romBank);
*/
template <typename A, typename B>
static std::string msg(const char* prefix, A a, const char* mid, B b) {
std::ostringstream oss;
oss << prefix << a << mid << b;
return oss.str();
}

} // namespace Gameboy
2 changes: 1 addition & 1 deletion include/units.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ namespace GameBoy::units {

static constexpr std::size_t KiB = 1024;
static constexpr std::size_t MiB = 1024 * KiB;
}
} // namespace GameBoy::units
Loading
Loading