1 module nes.mapper3;
2 
3 import std.conv;
4 import std.format;
5 
6 import nes.cartridge;
7 import nes.mapper;
8 
9 class Mapper3 : Mapper {
10     this(Cartridge cartridge) {
11         this.cart = cartridge;
12         this.chrBank = 0;
13         this.prgBank1 = 0;
14 
15         auto prgBanks = cast(int)(cartridge.prg.length / 0x4000);
16 
17         this.prgBank2 = prgBanks - 1;
18     }
19 
20     void step() {
21     }
22 
23     ubyte read(ushort address) {
24         if (address < 0x2000) {
25             auto index = this.chrBank * 0x2000 + cast(int)address;
26             return this.cart.chr[index];
27         }
28         else if (address >= 0xC000) {
29             auto index = this.prgBank2 * 0x4000 + cast(int)(address - 0xC000);
30             return this.cart.prg[index];
31         }
32         else if (address >= 0x8000) {
33             auto index = this.prgBank1 * 0x4000 + cast(int)(address - 0x8000);
34             return this.cart.prg[index];
35         }
36         else if (address >= 0x6000) {
37             auto index = cast(int)address - 0x6000;
38             return this.cart.sram[index];
39         }
40         else {
41             throw new MapperException(format("unhandled mapper3 read at address: 0x%04X", address));
42         }
43     }
44 
45     void write(ushort address, ubyte value) {
46         if (address < 0x2000) {
47             auto index = this.chrBank * 0x2000 + cast(int)address;
48             this.cart.chr[index] = value;
49         }
50         else if (address >= 0x8000) {
51             this.chrBank = cast(int)(value & 3);
52         }
53         else if (address >= 0x6000) {
54             auto index = cast(int)address - 0x6000;
55             this.cart.sram[index] = value;
56         }
57         else {
58             throw new MapperException(format("unhandled mapper3 write at address: 0x%04X", address));
59         }
60     }
61 
62     void save(string[string] state) {
63         state["mapper3.chrBank"] = to!string(this.chrBank);
64         state["mapper3.prgBank1"] = to!string(this.prgBank1);
65         state["mapper3.prgBank2"] = to!string(this.prgBank2);
66     }
67 
68     void load(string[string] state) {
69         this.chrBank = to!int(state["mapper3.chrBank"]);
70         this.prgBank1 = to!int(state["mapper3.prgBank1"]);
71         this.prgBank2 = to!int(state["mapper3.prgBank2"]);
72     }
73 
74     private:
75         Cartridge cart;
76         int chrBank;
77         int prgBank1;
78         int prgBank2;
79 }