libsidplayfp 3.0.0
SystemROMBanks.h
1/*
2 * This file is part of libsidplayfp, a SID player engine.
3 *
4 * Copyright 2012-2026 Leandro Nini <drfiemost@users.sourceforge.net>
5 * Copyright 2010 Antti Lankila
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22#ifndef SYSTEMROMBANKS_H
23#define SYSTEMROMBANKS_H
24
25#include <algorithm>
26#include <iterator>
27#include <cstdint>
28#include <cstring>
29
30#include "Bank.h"
31#include "c64/CPU/opcodes.h"
32
33#include "sidcxx11.h"
34
35namespace libsidplayfp
36{
37
41template <int N>
42class romBank : public Bank
43{
44 static_assert((N > 0) && ((N & (N - 1)) == 0), "N must be a power of two");
45
46protected:
48 uint8_t rom[N];
49
50protected:
51 ~romBank() = default;
52
56 inline void setVal(uint_least16_t address, uint8_t val) { rom[address & (N-1)] = val; }
57 inline void setVal16(uint_least16_t address, uint_least16_t val)
58 {
59 endian_little16(getPtr(address), val);
60 }
61
65 inline uint8_t getVal(uint_least16_t address) const { return rom[address & (N-1)]; }
66 inline uint_least16_t getVal16(uint_least16_t address)
67 {
68 return endian_little16(getPtr(address));
69 }
70
74 inline uint8_t* getPtr(uint_least16_t address) { return &rom[address & (N-1)]; }
75
76public:
80 virtual void set(const uint8_t* source) { if (source != nullptr) std::memcpy(rom, source, N); }
81
85 void poke(uint_least16_t, uint8_t) override {}
86
90 uint8_t peek(uint_least16_t address) override { return rom[address & (N-1)]; }
91};
92
98class KernalRomBank final : public romBank<0x2000>
99{
100private:
101 uint_least16_t resetVector; // 0xfffc-0xfffd
102
103private:
104 uint8_t save_regs[5] =
105 {
106 PHAn,
107 TXAn,
108 PHAn,
109 TYAn,
110 PHAn
111 };
112
113 uint8_t restore_regs[5] =
114 {
115 PLAn,
116 TAYn,
117 PLAn,
118 TAXn,
119 PLAn
120 };
121
122 // https://sta.c64.org/cbm64krnfunc.html
123 uint16_t kernal_functions[78] =
124 {
125 // address real address
126 0xFF81, 0xFF5B, // SCINIT
127 0xFF84, 0xFDA3, // IOINIT
128 0xFF87, 0xFD50, // RAMTAS
129 0xFF8A, 0xFD15, // RESTOR
130 0xFF8D, 0xFD1A, // VECTOR
131 0xFF90, 0xFE18, // SETMSG
132 0xFF93, 0xEDB9, // LSTNSA
133 0xFF96, 0xEDC7, // TALKSA
134 0xFF99, 0xFE25, // MEMTOP
135 0xFF9C, 0xFE34, // MEMBOT
136 0xFF9F, 0xEA87, // SCNKEY
137 0xFFA2, 0xFE21, // SETTMO
138 0xFFA5, 0xEE13, // IECIN.
139 0xFFA8, 0xEDDD, // IECOUT
140 0xFFAB, 0xEDEF, // UNTALK
141 0xFFAE, 0xEDFE, // UNLSTN
142 0xFFB1, 0xED0C, // LISTEN
143 0xFFB4, 0xED09, // TALK
144 0xFFB7, 0xFE07, // READST
145 0xFFBA, 0xFE00, // SETLFS
146 0xFFBD, 0xFDF9, // SETNAM
147 0xFFC0, 0xF34A, // OPEN
148 0xFFC3, 0xF291, // CLOSE
149 0xFFC6, 0xF20E, // CHKIN
150 0xFFC9, 0xF250, // CHKOUT
151 0xFFCC, 0xF333, // CLRCHN
152 0xFFCF, 0xF157, // CHRIN
153 0xFFD2, 0xF1CA, // CHROUT
154 0xFFD5, 0xF49E, // LOAD
155 0xFFD8, 0xF5DD, // SAVE
156 0xFFDB, 0xF6E4, // SETTIM
157 0xFFDE, 0xF6DD, // RDTIM
158 0xFFE1, 0xF6ED, // STOP
159 0xFFE4, 0xF13E, // GETIN
160 0xFFE7, 0xF32F, // CLALL
161 0xFFEA, 0xF69B, // UDTIM
162 0xFFED, 0xE505, // SCREEN
163 0xFFF0, 0xE50A, // PLOT
164 0xFFF3, 0xE500, // IOBASE
165 };
166
167 void fill(uint_least16_t address, const uint8_t data[5])
168 {
169 std::memcpy(getPtr(address), data, 5);
170 }
171
172public:
173 void set(const uint8_t* kernal) override
174 {
175 romBank<0x2000>::set(kernal);
176
177 if (kernal == nullptr)
178 {
179 std::fill(std::begin(rom), std::end(rom), NOPn);
180
181 // IRQ routine
182 setVal(0xea31, JMPw);
183 setVal16(0xea32, 0xea7e);
184
185 setVal(0xea7e, NOPa); // Clear IRQ
186 setVal16(0xea7f, 0xdc0d);
187 fill(0xea81, restore_regs);
188 setVal(0xea86, RTIn); // Return from interrupt
189
190 // Reset
191 setVal(0xfce2, 0x02); // Halt
192
193 // NMI entry point
194 setVal(0xfe43, SEIn);
195 setVal(0xfe44, JMPi); // Jump to NMI routine (Default: $FE47)
196 setVal16(0xfe45, 0x0318);
197
198 // NMI routine
199 fill(0xfe47, save_regs);
200
201 fill(0xfebc, restore_regs);
202 setVal(0xfec1, RTIn);
203
204 // IRQ entry point
205 fill(0xff48, save_regs);
206 setVal(0xff4d, JMPi); // Jump to IRQ routine (Default: $EA31)
207 setVal16(0xff4e, 0x0314);
208
209 // Hardware vectors
210 setVal16(0xfffa, 0xfe43); // NMI vector
211 setVal16(0xfffc, 0xfce2); // RESET vector
212 setVal16(0xfffe, 0xff48); // IRQ/BRK vector
213
214 // Standard KERNAL functions called by some unclean rips
215 for (auto addr: kernal_functions)
216 setVal(addr, RTSn);
217 }
218
219 // Backup Reset Vector
220 resetVector = getVal16(0xfffc);
221 }
222
223 void reset()
224 {
225 // Restore original Reset Vector
226 setVal16(0xfffc, resetVector);
227 }
228
234 void installResetHook(uint_least16_t addr)
235 {
236 setVal16(0xfffc, addr);
237 }
238};
239
245class BasicRomBank final : public romBank<0x2000>
246{
247private:
248 uint8_t trap[3];
249 uint8_t subTune[11];
250
251public:
252 void set(const uint8_t* basic) override
253 {
255
256 // Backup BASIC Warm Start
257 std::memcpy(trap, getPtr(0xa7ae), sizeof(trap));
258
259 std::memcpy(subTune, getPtr(0xbf53), sizeof(subTune));
260 }
261
262 void reset()
263 {
264 // Restore original BASIC Warm Start
265 std::memcpy(getPtr(0xa7ae), trap, sizeof(trap));
266
267 std::memcpy(getPtr(0xbf53), subTune, sizeof(subTune));
268 }
269
275 void installTrap(uint_least16_t addr)
276 {
277 setVal(0xa7ae, JMPw);
278 setVal16(0xa7af, addr);
279 }
280
281 void setSubtune(uint8_t tune)
282 {
283 setVal(0xbf53, LDAb);
284 setVal(0xbf54, tune);
285 setVal(0xbf55, STAa);
286 setVal16(0xbf56, 0x030c);
287 setVal(0xbf58, JSRw);
288 setVal16(0xbf59, 0xa82c);
289 setVal(0xbf5b, JMPw);
290 setVal16(0xbf5c, 0xa7b1);
291 }
292};
293
299class CharacterRomBank final : public romBank<0x1000> {};
300
301}
302
303#endif
Definition Bank.h:36
Definition SystemROMBanks.h:246
void set(const uint8_t *basic) override
Definition SystemROMBanks.h:252
void installTrap(uint_least16_t addr)
Definition SystemROMBanks.h:275
Definition SystemROMBanks.h:299
Definition SystemROMBanks.h:99
void installResetHook(uint_least16_t addr)
Definition SystemROMBanks.h:234
void set(const uint8_t *kernal) override
Definition SystemROMBanks.h:173
Definition SystemROMBanks.h:43
uint8_t peek(uint_least16_t address) override
Definition SystemROMBanks.h:90
uint8_t getVal(uint_least16_t address) const
Definition SystemROMBanks.h:65
uint8_t * getPtr(uint_least16_t address)
Definition SystemROMBanks.h:74
virtual void set(const uint8_t *source)
Definition SystemROMBanks.h:80
void poke(uint_least16_t, uint8_t) override
Definition SystemROMBanks.h:85
uint8_t rom[N]
The ROM array.
Definition SystemROMBanks.h:48
void setVal(uint_least16_t address, uint8_t val)
Definition SystemROMBanks.h:56