Skip to content

Commit 5588729

Browse files
committed
Fleshing out architecture.
1 parent c97a7db commit 5588729

File tree

3 files changed

+121
-6
lines changed

3 files changed

+121
-6
lines changed

Architecture/CPU.md

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# Windfish CPU
2+
3+
At its core, Windfish defines a protocol-based representation of an abstract CPU's instruction set that supports bi-directional coding between binary and semantic representations of the instructions.
4+
5+
### Defining the shape of an instruction
6+
7+
Implementing a CPU starts by implementing the `InstructionSpec` protocol, typically as an enum. The `InstructionSpec` type defines both the potential shape of an instruction and the assembly language names of the instructions. In the example below, we define an instruction specification that is able to represent four different types of operations, most accepting one or more operands:
8+
9+
```swift
10+
enum Spec: CPU.InstructionSpec {
11+
typealias WidthType = UInt16
12+
13+
case nop
14+
case cp(Numeric)
15+
case ld(Numeric, Numeric)
16+
case call(Condition? = nil, Numeric)
17+
18+
enum Numeric: Hashable {
19+
case imm8
20+
case imm16
21+
case a
22+
case arg(Int)
23+
}
24+
25+
enum Condition: Hashable {
26+
case nz
27+
case z
28+
}
29+
}
30+
```
31+
32+
This specification allows us to represent any of the following instructions:
33+
34+
```swift
35+
.nop
36+
.cp(.a)
37+
.cp(.imm8)
38+
.ld(.a, .imm8)
39+
.call(nil, .imm16)
40+
.call(.z, .imm16)
41+
```
42+
43+
### Defining an instruction set
44+
45+
Instruction specifications can be used to create an instruction table where each index maps to the binary value of a corresponding instruction specification:
46+
47+
```swift
48+
static let table: [Instruction.Spec] = [
49+
/* 0x00 */ .nop,
50+
/* 0x01 */ .ld(.a, .imm8),
51+
/* 0x02 */ .ld(.a, .imm16),
52+
/* 0x03 */ .call(.nz, .imm16),
53+
/* 0x04 */ .call(nil, .imm16),
54+
]
55+
```
56+
57+
This table is then stored within an `InstructionSet`:
58+
59+
```swift
60+
struct InstructionSet: CPU.InstructionSet {
61+
typealias InstructionType = Instruction
62+
63+
static let table: [Instruction.Spec] = [
64+
/* 0x00 */ .nop,
65+
/* 0x01 */ .ld(.a, .imm8),
66+
/* 0x02 */ .ld(.a, .imm16),
67+
/* 0x03 */ .call(.nz, .imm16),
68+
/* 0x04 */ .call(nil, .imm16),
69+
]
70+
static var prefixTables: [Instruction.Spec: [Instruction.Spec]] = []
71+
}
72+
```
73+
74+
The `InstructionSet` type defines common methods for working with an instruction set including the ability to compute the width of an instruction and converting the instruction's opcode to byte and assembly representations.
75+
76+
```swift
77+
struct InstructionSet: CPU.InstructionSet {
78+
// ...
79+
80+
static var widths: [Instruction.Spec : InstructionWidth<UInt16>] = {
81+
return computeAllWidths()
82+
}()
83+
84+
static var opcodeBytes: [Instruction.Spec : [UInt8]] = {
85+
return computeAllOpcodeBytes()
86+
}()
87+
88+
static var opcodeStrings: [Instruction.Spec : String] = {
89+
return computeAllOpcodeStrings()
90+
}()
91+
}
92+
```
93+
94+
### Defining an instruction
95+
96+
Instruction specifications form the basis by which real instructions are represented. A real instruction consists of both an instruction specification and any optional immediate values associated with the instruction.
97+
98+
```swift
99+
struct Instruction: CPU.Instruction {
100+
let spec: Spec
101+
let immediate: ImmediateValue?
102+
103+
enum ImmediateValue: CPU.InstructionImmediate {
104+
case imm8(UInt8)
105+
case imm16(UInt16)
106+
}
107+
}
108+
```
109+
110+
For example, `.ld(.a, .imm8)` would be initialized with a 1-byte `.imm8` value. The initialization of an instruction like this would look like so:
111+
112+
```swift
113+
let instruction = Instruction(spec: .ld(.a, .imm8), immediate: .imm8(127))
114+
```

Architecture/README.md

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
# Windfish architecture
22

33
The Windfish architecture is broken up into several Swift modules.
4-
Before diving into a module, let's establish the high level architectural details.
54

65
## Overview
76

8-
Windfish is written in Swift.
9-
Thus far it has primarily been tested on MacOS.
10-
Linux and Windows support has yet to be verified (https://github.com/jverkoey/windfish/issues/59).
7+
Windfish is written in Swift and has primarily been tested on MacOS.
8+
Linux and Windows support has yet to be verified ([see project](https://github.com/jverkoey/windfish/projects/5)).
119

1210
At its core, Windfish provides an abstract representation of a CPU's instruction set via the `CPU` module.
1311
Windfish currently only supports the [LR35902 instruction set](https://github.com/lmmendes/game-boy-opcodes) for the original Gameboy.
14-
Other instruction sets could theoretically be supported in the future (https://github.com/jverkoey/windfish/projects/2).
12+
Other instruction sets could theoretically be supported in the future ([see project](https://github.com/jverkoey/windfish/projects/2)).
13+
14+
Concrete implementations of CPU's instruction set are provided as separate modules.
15+
For example, the `LR35902` module provides a concrete implementation of the LR35902 instruction set.
1516

1617
## Modules
1718

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,4 @@ Features of the IDE:
4040

4141
## Learn more
4242

43-
[Learn more about the Windfish architecture](lib/README.md).
43+
[Learn more about the Windfish architecture](Architecture/README.md).

0 commit comments

Comments
 (0)