diff --git a/src/vendor/libqboy/gbgpu.cpp b/src/vendor/libqboy/gbgpu.cpp index ced866e..a7da808 100644 --- a/src/vendor/libqboy/gbgpu.cpp +++ b/src/vendor/libqboy/gbgpu.cpp @@ -1,382 +1,382 @@ -#include "gbgpu.h" - -gbgpu::gbgpu(z80mmu *mmu) { - this->mmu = mmu; - reset(); -} - -void gbgpu::reset() { - mode = 0; - modeclock = 0; - line = 0; - scanlinetransfered = false; - registers.resize(_GBGPU_VREGSIZE, 0); - - for (int i = 0; i < 4; ++i) { - pallete_bg[i] = pallete_obj0[i] = pallete_obj1[i] = 255; - } - - for (int y = 0; y < _GBGPU_H; ++y) { - for (int x = 0; x < _GBGPU_W; ++x) { - for (int c = 0; c < 4; ++c) { - screen_buffer[y][x][c] = 255; - } - } - } -} - -#include - -void gbgpu::step(int z80m) { - preprocessram(); - - updated = false; - if (!lcd_on()) return; - modeclock += z80m; - - switch (mode) { - case 2: - if (modeclock >= 20) { - modeclock -= 20; - mode = 3; - scanlinetransfered = false; - } - break; - case 3: - if (modeclock >= 12 && !scanlinetransfered) { - renderscan(); - scanlinetransfered = true; - } - if (modeclock >= 43) { - modeclock -= 43; - mode = 0; - } - break; - case 0: - if (modeclock >= 51) { - modeclock -= 51; - ++line; - if (line == 144) { - mode = 1; - updated = true; - } else { - mode = 2; - } - } - break; - case 1: - if (modeclock >= 114) { - modeclock -= 114; - - // stay 10 iterations in this loop, but increase line the first 9 times - if (line == 153) { - mode = 2; - line = 0; - } - - if (mode == 1) { - ++line; - } - } - break; - } - postprocessram(); -} - -quint8 *gbgpu::getLCD() { - return &screen_buffer[0][0][0]; -} - -bool gbgpu::is_updated() { - return updated; -} - -bool gbgpu::lcd_on() { - return registers[0] & 0x80; -} - -bool gbgpu::bg_on() { - return registers[0] & 0x01; -} - -bool gbgpu::win_on() { - return registers[0] & 0x20; -} - -bool gbgpu::sprite_large() { - return registers[0] & 0x04; -} - -quint16 gbgpu::bg_mapbase() { - if (registers[0] & 0x08) { - return _GBGPU_VRAMBASE + 0x1C00; - } else { - return _GBGPU_VRAMBASE + 0x1800; - } -} - -quint16 gbgpu::win_mapbase() { - if (registers[0] & 0x40) { - return _GBGPU_VRAMBASE + 0x1C00; - } else { - return _GBGPU_VRAMBASE + 0x1800; - } -} - -bool gbgpu::tileset1() { - return registers[0] & 0x10; -} - -bool gbgpu::sprite_on() { - return registers[0] & 0x02; -} - -quint8 gbgpu::yscroll() { - return registers[2]; -} - -quint8 gbgpu::xscroll() { - return registers[3]; -} - -quint8 gbgpu::winypos() { - return registers[10]; -} - -quint8 gbgpu::winxpos() { - return registers[11]; -} - -quint8 gbgpu::linecmp() { - return registers[5]; -} - -void gbgpu::preprocessram() { - std::vector newregisters(_GBGPU_VREGSIZE, 0); - - for (int i = 0; i < _GBGPU_VREGSIZE; ++i) { - newregisters[i] = mmu->readbyte(_GBGPU_VREGBASE + i); - } - - if (newregisters[6] != 0) { - quint16 baseaddr = newregisters[6]; - baseaddr <<= 8; - for(quint8 i = 0; i < 0xA0; ++i) { - mmu->writebyte(_GBGPU_VOAMBASE + i, mmu->readbyte(baseaddr + i)); - } - mmu->writebyte(_GBGPU_VREGBASE + 6, 0); - } - - if (newregisters[7] != registers[7]) { - for(int i = 0; i < 4; ++i) { - switch((newregisters[7] >> (2*i)) & 3) { - case 0: pallete_bg[i] = 255; break; - case 1: pallete_bg[i] = 192; break; - case 2: pallete_bg[i] = 96; break; - case 3: pallete_bg[i] = 0; break; - } - } - } - - if (newregisters[8] != registers[8]) { - for(int i = 0; i < 4; ++i) { - switch((newregisters[8] >> (2*i)) & 3) { - case 0: pallete_obj0[i] = 255; break; - case 1: pallete_obj0[i] = 192; break; - case 2: pallete_obj0[i] = 96; break; - case 3: pallete_obj0[i] = 0; break; - } - } - } - - if (newregisters[9] != registers[9]) { - for(int i = 0; i < 4; ++i) { - switch((newregisters[9] >> (2*i)) & 3) { - case 0: pallete_obj1[i] = 255; break; - case 1: pallete_obj1[i] = 192; break; - case 2: pallete_obj1[i] = 96; break; - case 3: pallete_obj1[i] = 0; break; - } - } - } - - registers = newregisters; - oldmode = mode; - oldline = line; -} - -void gbgpu::postprocessram() { - mmu->writebyte(_GBGPU_VREGBASE + 4, line); - - quint8 vreg1 = registers[1]; - vreg1 &= 0xF8; - vreg1 |= (line == linecmp() ? 4 : 0) | (mode & 0x3); - - mmu->writebyte(_GBGPU_VREGBASE + 1, vreg1); - - bool lcdstat = false; - if (line != oldline) { - if ((vreg1 & 0x40) && line == linecmp()) lcdstat = true; - } - if (mode != oldmode) { - if ((vreg1 & 0x20) && mode == 2) lcdstat = true; - if ((vreg1 & 0x10) && mode == 1) lcdstat = true; - if ((vreg1 & 0x08) && mode == 0) lcdstat = true; - } - - if (lcdstat || updated) { - quint8 int_flags = mmu->readbyte(0xFF0F); - int_flags |= (lcdstat ? 0x2 : 0) | (updated ? 0x1 : 0); - mmu->writebyte(0xFF0F, int_flags); - } -} - -void gbgpu::renderscan() { - drawbackground(); - drawwindow(); - drawsprites(); -} - -void gbgpu::drawbackground() { - if (!bg_on()) return; - - int bgx = xscroll(); - int bgy = yscroll() + line; - quint16 mapbase = bg_mapbase(); - - int tiley = (bgy >> 3) & 31; - int tilex; - - for (int x = 0;x < _GBGPU_W; ++x, ++bgx) { - tilex = (bgx >> 3) & 31; - - quint16 tileaddress = 0; - if (tileset1()) { - quint8 tilenr = mmu->readbyte(mapbase + tiley * 32 + tilex); - tileaddress = 0x8000 + tilenr * 16; - } else { - // Signed! - qint8 tilenr = mmu->readbyte(mapbase + tiley * 32 + tilex); - tileaddress = 0x9000 + tilenr * 16; - } - - quint8 byte1 = mmu->readbyte(tileaddress + ((bgy & 0x07) * 2)); - quint8 byte2 = mmu->readbyte(tileaddress + ((bgy & 0x07) * 2) + 1); - - quint8 xbit = bgx & 0x07; - quint8 colnr = 0; - colnr |= (byte1 & (0x01 << (7 - xbit))) ? 0x1 : 0; - colnr |= (byte2 & (0x01 << (7 - xbit))) ? 0x2 : 0; - quint8 colour = pallete_bg[colnr]; - - setcolour(x, colour); - } -} - -void gbgpu::drawwindow() { - if (!win_on()) return; - int winy = line - winypos(); - if (winy < 0) return; - - int winx = - (winxpos() - 7); - quint16 mapbase = win_mapbase(); - - int tiley = (winy >> 3) & 31; - int tilex; - - for (int x = 0; x < _GBGPU_W; ++x, ++winx) { - if (winx < 0) continue; - tilex = (winx >> 3) & 31; - - quint16 tileaddress = 0; - if (tileset1()) { - quint8 tilenr = mmu->readbyte(mapbase + tiley * 32 + tilex); - tileaddress = 0x8000 + tilenr * 16; - } else { - // Signed! - qint8 tilenr = static_cast(mmu->readbyte(mapbase + tiley * 32 + tilex)); - tileaddress = 0x9000 + tilenr * 16; - } - - quint8 byte1 = mmu->readbyte(tileaddress + ((winy & 0x07) * 2)); - quint8 byte2 = mmu->readbyte(tileaddress + ((winy & 0x07) * 2) + 1); - - quint8 xbit = winx % 8; - quint8 colnr = 0; - colnr |= (byte1 & (0x80 >> xbit)) ? 0x1 : 0; - colnr |= (byte2 & (0x80 >> xbit)) ? 0x2 : 0; - quint8 colour = pallete_bg[colnr]; - - setcolour(x, colour); - } -} - -void gbgpu::drawsprites() { - if (!sprite_on()) return; - - int spriteheight = sprite_large() ? 16 : 8; - - int numsprites = 0; - std::vector spritey(40); - std::vector spritex(40); - std::vector spritetile(40); - std::vector spriteflags(40); - - for (int i = 0; i < 40; ++i) { - quint16 spriteaddr = _GBGPU_VOAMBASE + i*4; - - spritey[i] = mmu->readbyte(spriteaddr + 0) - 16; - spritex[i] = mmu->readbyte(spriteaddr + 1) - 8; - spritetile[i] = mmu->readbyte(spriteaddr + 2) & (spriteheight == 16 ? 0xFE : 0xFF); - spriteflags[i].byte = mmu->readbyte(spriteaddr + 3); - - if (line >= spritey[i] && line < spritey[i] + spriteheight) - numsprites++; - } - - - - for (int i = 39; i >= 0; --i) { - if (line < spritey[i] || line >= spritey[i] + spriteheight) - continue; - - if (numsprites-- > 10) continue; - - if (spritex[i] < -7 || spritex[i] >= _GBGPU_W) - continue; - - int tiley = line - spritey[i]; - if (spriteflags[i].flags.yflip) - tiley = (spriteheight - 1) - tiley; - - quint16 tileaddress = 0x8000 + spritetile[i] * 16 + tiley * 2; - quint8 byte1 = mmu->readbyte(tileaddress); - quint8 byte2 = mmu->readbyte(tileaddress + 1); - - for (int x = 0; x < 8; ++x) { - if (spritex[i] + x < 0 || spritex[i] + x >= _GBGPU_W) - continue; - - int colnr = 0; - colnr |= (byte1 & (0x01 << (spriteflags[i].flags.xflip ? x : 7 - x))) ? 1 : 0; - colnr |= (byte2 & (0x01 << (spriteflags[i].flags.xflip ? x : 7 - x))) ? 2 : 0; - - // colnr 0 is always transparant - if (colnr == 0) continue; - // if belowbg, then only draw on bg[0] - if (spriteflags[i].flags.belowbg && getcolour(spritex[i] + x) != pallete_bg[0]) continue; - - int colour = spriteflags[i].flags.pal1 ? pallete_obj1[colnr] : pallete_obj0[colnr]; - - setcolour(spritex[i] + x, colour); - } - } -} - -void gbgpu::setcolour(int x, quint8 value) { - screen_buffer[line][x][0] = screen_buffer[line][x][1] = screen_buffer[line][x][2] = value; -} - -quint8 gbgpu::getcolour(int x) { - return screen_buffer[line][x][0]; -} +#include "gbgpu.h" + +gbgpu::gbgpu(z80mmu *mmu) { + this->mmu = mmu; + reset(); +} + +void gbgpu::reset() { + mode = 0; + modeclock = 0; + line = 0; + scanlinetransfered = false; + registers.resize(_GBGPU_VREGSIZE, 0); + + for (int i = 0; i < 4; ++i) { + pallete_bg[i] = pallete_obj0[i] = pallete_obj1[i] = 255; + } + + for (int y = 0; y < _GBGPU_H; ++y) { + for (int x = 0; x < _GBGPU_W; ++x) { + for (int c = 0; c < 4; ++c) { + screen_buffer[y][x][c] = 255; + } + } + } +} + +#include + +void gbgpu::step(int z80m) { + preprocessram(); + + updated = false; + if (!lcd_on()) return; + modeclock += z80m; + + switch (mode) { + case 2: + if (modeclock >= 20) { + modeclock -= 20; + mode = 3; + scanlinetransfered = false; + } + break; + case 3: + if (modeclock >= 12 && !scanlinetransfered) { + renderscan(); + scanlinetransfered = true; + } + if (modeclock >= 43) { + modeclock -= 43; + mode = 0; + } + break; + case 0: + if (modeclock >= 51) { + modeclock -= 51; + ++line; + if (line == 144) { + mode = 1; + updated = true; + } else { + mode = 2; + } + } + break; + case 1: + if (modeclock >= 114) { + modeclock -= 114; + + // stay 10 iterations in this loop, but increase line the first 9 times + if (line == 153) { + mode = 2; + line = 0; + } + + if (mode == 1) { + ++line; + } + } + break; + } + postprocessram(); +} + +quint8 *gbgpu::getLCD() { + return &screen_buffer[0][0][0]; +} + +bool gbgpu::is_updated() { + return updated; +} + +bool gbgpu::lcd_on() { + return registers[0] & 0x80; +} + +bool gbgpu::bg_on() { + return registers[0] & 0x01; +} + +bool gbgpu::win_on() { + return registers[0] & 0x20; +} + +bool gbgpu::sprite_large() { + return registers[0] & 0x04; +} + +quint16 gbgpu::bg_mapbase() { + if (registers[0] & 0x08) { + return _GBGPU_VRAMBASE + 0x1C00; + } else { + return _GBGPU_VRAMBASE + 0x1800; + } +} + +quint16 gbgpu::win_mapbase() { + if (registers[0] & 0x40) { + return _GBGPU_VRAMBASE + 0x1C00; + } else { + return _GBGPU_VRAMBASE + 0x1800; + } +} + +bool gbgpu::tileset1() { + return registers[0] & 0x10; +} + +bool gbgpu::sprite_on() { + return registers[0] & 0x02; +} + +quint8 gbgpu::yscroll() { + return registers[2]; +} + +quint8 gbgpu::xscroll() { + return registers[3]; +} + +quint8 gbgpu::winypos() { + return registers[10]; +} + +quint8 gbgpu::winxpos() { + return registers[11]; +} + +quint8 gbgpu::linecmp() { + return registers[5]; +} + +void gbgpu::preprocessram() { + std::vector newregisters(_GBGPU_VREGSIZE, 0); + + for (int i = 0; i < _GBGPU_VREGSIZE; ++i) { + newregisters[i] = mmu->readbyte(_GBGPU_VREGBASE + i); + } + + if (newregisters[6] != 0) { + quint16 baseaddr = newregisters[6]; + baseaddr <<= 8; + for(quint8 i = 0; i < 0xA0; ++i) { + mmu->writebyte(_GBGPU_VOAMBASE + i, mmu->readbyte(baseaddr + i)); + } + mmu->writebyte(_GBGPU_VREGBASE + 6, 0); + } + + if (newregisters[7] != registers[7]) { + for(int i = 0; i < 4; ++i) { + switch((newregisters[7] >> (2*i)) & 3) { + case 0: pallete_bg[i] = 255; break; + case 1: pallete_bg[i] = 192; break; + case 2: pallete_bg[i] = 96; break; + case 3: pallete_bg[i] = 0; break; + } + } + } + + if (newregisters[8] != registers[8]) { + for(int i = 0; i < 4; ++i) { + switch((newregisters[8] >> (2*i)) & 3) { + case 0: pallete_obj0[i] = 255; break; + case 1: pallete_obj0[i] = 192; break; + case 2: pallete_obj0[i] = 96; break; + case 3: pallete_obj0[i] = 0; break; + } + } + } + + if (newregisters[9] != registers[9]) { + for(int i = 0; i < 4; ++i) { + switch((newregisters[9] >> (2*i)) & 3) { + case 0: pallete_obj1[i] = 255; break; + case 1: pallete_obj1[i] = 192; break; + case 2: pallete_obj1[i] = 96; break; + case 3: pallete_obj1[i] = 0; break; + } + } + } + + registers = newregisters; + oldmode = mode; + oldline = line; +} + +void gbgpu::postprocessram() { + mmu->writebyte(_GBGPU_VREGBASE + 4, line); + + quint8 vreg1 = registers[1]; + vreg1 &= 0xF8; + vreg1 |= (line == linecmp() ? 4 : 0) | (mode & 0x3); + + mmu->writebyte(_GBGPU_VREGBASE + 1, vreg1); + + bool lcdstat = false; + if (line != oldline) { + if ((vreg1 & 0x40) && line == linecmp()) lcdstat = true; + } + if (mode != oldmode) { + if ((vreg1 & 0x20) && mode == 2) lcdstat = true; + if ((vreg1 & 0x10) && mode == 1) lcdstat = true; + if ((vreg1 & 0x08) && mode == 0) lcdstat = true; + } + + if (lcdstat || updated) { + quint8 int_flags = mmu->readbyte(0xFF0F); + int_flags |= (lcdstat ? 0x2 : 0) | (updated ? 0x1 : 0); + mmu->writebyte(0xFF0F, int_flags); + } +} + +void gbgpu::renderscan() { + drawbackground(); + drawwindow(); + drawsprites(); +} + +void gbgpu::drawbackground() { + if (!bg_on()) return; + + int bgx = xscroll(); + int bgy = yscroll() + line; + quint16 mapbase = bg_mapbase(); + + int tiley = (bgy >> 3) & 31; + int tilex; + + for (int x = 0;x < _GBGPU_W; ++x, ++bgx) { + tilex = (bgx >> 3) & 31; + + quint16 tileaddress = 0; + if (tileset1()) { + quint8 tilenr = mmu->readbyte(mapbase + tiley * 32 + tilex); + tileaddress = 0x8000 + tilenr * 16; + } else { + // Signed! + qint8 tilenr = mmu->readbyte(mapbase + tiley * 32 + tilex); + tileaddress = 0x9000 + tilenr * 16; + } + + quint8 byte1 = mmu->readbyte(tileaddress + ((bgy & 0x07) * 2)); + quint8 byte2 = mmu->readbyte(tileaddress + ((bgy & 0x07) * 2) + 1); + + quint8 xbit = bgx & 0x07; + quint8 colnr = 0; + colnr |= (byte1 & (0x01 << (7 - xbit))) ? 0x1 : 0; + colnr |= (byte2 & (0x01 << (7 - xbit))) ? 0x2 : 0; + quint8 colour = pallete_bg[colnr]; + + setcolour(x, colour); + } +} + +void gbgpu::drawwindow() { + if (!win_on()) return; + int winy = line - winypos(); + if (winy < 0) return; + + int winx = - (winxpos() - 7); + quint16 mapbase = win_mapbase(); + + int tiley = (winy >> 3) & 31; + int tilex; + + for (int x = 0; x < _GBGPU_W; ++x, ++winx) { + if (winx < 0) continue; + tilex = (winx >> 3) & 31; + + quint16 tileaddress = 0; + if (tileset1()) { + quint8 tilenr = mmu->readbyte(mapbase + tiley * 32 + tilex); + tileaddress = 0x8000 + tilenr * 16; + } else { + // Signed! + qint8 tilenr = static_cast(mmu->readbyte(mapbase + tiley * 32 + tilex)); + tileaddress = 0x9000 + tilenr * 16; + } + + quint8 byte1 = mmu->readbyte(tileaddress + ((winy & 0x07) * 2)); + quint8 byte2 = mmu->readbyte(tileaddress + ((winy & 0x07) * 2) + 1); + + quint8 xbit = winx % 8; + quint8 colnr = 0; + colnr |= (byte1 & (0x80 >> xbit)) ? 0x1 : 0; + colnr |= (byte2 & (0x80 >> xbit)) ? 0x2 : 0; + quint8 colour = pallete_bg[colnr]; + + setcolour(x, colour); + } +} + +void gbgpu::drawsprites() { + if (!sprite_on()) return; + + int spriteheight = sprite_large() ? 16 : 8; + + int numsprites = 0; + std::vector spritey(40); + std::vector spritex(40); + std::vector spritetile(40); + std::vector spriteflags(40); + + for (int i = 0; i < 40; ++i) { + quint16 spriteaddr = _GBGPU_VOAMBASE + i*4; + + spritey[i] = mmu->readbyte(spriteaddr + 0) - 16; + spritex[i] = mmu->readbyte(spriteaddr + 1) - 8; + spritetile[i] = mmu->readbyte(spriteaddr + 2) & (spriteheight == 16 ? 0xFE : 0xFF); + spriteflags[i].byte = mmu->readbyte(spriteaddr + 3); + + if (line >= spritey[i] && line < spritey[i] + spriteheight) + numsprites++; + } + + + + for (int i = 39; i >= 0; --i) { + if (line < spritey[i] || line >= spritey[i] + spriteheight) + continue; + + if (numsprites-- > 10) continue; + + if (spritex[i] < -7 || spritex[i] >= _GBGPU_W) + continue; + + int tiley = line - spritey[i]; + if (spriteflags[i].flags.yflip) + tiley = (spriteheight - 1) - tiley; + + quint16 tileaddress = 0x8000 + spritetile[i] * 16 + tiley * 2; + quint8 byte1 = mmu->readbyte(tileaddress); + quint8 byte2 = mmu->readbyte(tileaddress + 1); + + for (int x = 0; x < 8; ++x) { + if (spritex[i] + x < 0 || spritex[i] + x >= _GBGPU_W) + continue; + + int colnr = 0; + colnr |= (byte1 & (0x01 << (spriteflags[i].flags.xflip ? x : 7 - x))) ? 1 : 0; + colnr |= (byte2 & (0x01 << (spriteflags[i].flags.xflip ? x : 7 - x))) ? 2 : 0; + + // colnr 0 is always transparant + if (colnr == 0) continue; + // if belowbg, then only draw on bg[0] + if (spriteflags[i].flags.belowbg && getcolour(spritex[i] + x) != pallete_bg[0]) continue; + + int colour = spriteflags[i].flags.pal1 ? pallete_obj1[colnr] : pallete_obj0[colnr]; + + setcolour(spritex[i] + x, colour); + } + } +} + +void gbgpu::setcolour(int x, quint8 value) { + screen_buffer[line][x][0] = screen_buffer[line][x][1] = screen_buffer[line][x][2] = value; +} + +quint8 gbgpu::getcolour(int x) { + return screen_buffer[line][x][0]; +} diff --git a/src/vendor/libqboy/gbgpu.h b/src/vendor/libqboy/gbgpu.h index 1d3117a..09b26f3 100644 --- a/src/vendor/libqboy/gbgpu.h +++ b/src/vendor/libqboy/gbgpu.h @@ -1,75 +1,75 @@ -#ifndef GBGPU_H -#define GBGPU_H - -#include "libqboy_global.h" -#include "z80mmu.h" -#include - -const int _GBGPU_W = 160; -const int _GBGPU_H = 144; -const int _GBGPU_VRAMBASE = 0x8000; -const int _GBGPU_VREGBASE = 0xFF40; -const int _GBGPU_VREGSIZE = 0xC; -const int _GBGPU_VOAMBASE = 0xFE00; - -union gbgpu_oamflags { - struct { - quint8 reserved : 4; - bool pal1 : 1; - bool xflip : 1; - bool yflip : 1; - bool belowbg : 1; - } flags; - quint8 byte; -}; - -class gbgpu { -public: - gbgpu(z80mmu *mmu); - void reset(); - void step(int z80m); - bool is_updated(); - quint8 *getLCD(); -private: - z80mmu *mmu; - quint8 screen_buffer[_GBGPU_H][_GBGPU_W][4]; - - int mode; - int modeclock; - int line; - bool scanlinetransfered; - int oldmode; - int oldline; - - bool updated; - - quint8 pallete_bg[4], pallete_obj0[4], pallete_obj1[4]; - std::vector registers; - - bool lcd_on(); - bool bg_on(); - bool win_on(); - quint16 bg_mapbase(); - quint16 win_mapbase(); - bool tileset1(); - bool sprite_on(); - bool sprite_large(); - quint8 yscroll(); - quint8 xscroll(); - quint8 linecmp(); - quint8 winxpos(); - quint8 winypos(); - - - void renderscan(); - void drawbackground(); - void drawwindow(); - void drawsprites(); - void updatebuffer(); - void preprocessram(); - void postprocessram(); - void setcolour(int x, quint8 value); - quint8 getcolour(int x); -}; - -#endif // GBGPU_H +#ifndef GBGPU_H +#define GBGPU_H + +#include "libqboy_global.h" +#include "z80mmu.h" +#include + +const int _GBGPU_W = 160; +const int _GBGPU_H = 144; +const int _GBGPU_VRAMBASE = 0x8000; +const int _GBGPU_VREGBASE = 0xFF40; +const int _GBGPU_VREGSIZE = 0xC; +const int _GBGPU_VOAMBASE = 0xFE00; + +union gbgpu_oamflags { + struct { + quint8 reserved : 4; + bool pal1 : 1; + bool xflip : 1; + bool yflip : 1; + bool belowbg : 1; + } flags; + quint8 byte; +}; + +class gbgpu { +public: + gbgpu(z80mmu *mmu); + void reset(); + void step(int z80m); + bool is_updated(); + quint8 *getLCD(); +private: + z80mmu *mmu; + quint8 screen_buffer[_GBGPU_H][_GBGPU_W][4]; + + int mode; + int modeclock; + int line; + bool scanlinetransfered; + int oldmode; + int oldline; + + bool updated; + + quint8 pallete_bg[4], pallete_obj0[4], pallete_obj1[4]; + std::vector registers; + + bool lcd_on(); + bool bg_on(); + bool win_on(); + quint16 bg_mapbase(); + quint16 win_mapbase(); + bool tileset1(); + bool sprite_on(); + bool sprite_large(); + quint8 yscroll(); + quint8 xscroll(); + quint8 linecmp(); + quint8 winxpos(); + quint8 winypos(); + + + void renderscan(); + void drawbackground(); + void drawwindow(); + void drawsprites(); + void updatebuffer(); + void preprocessram(); + void postprocessram(); + void setcolour(int x, quint8 value); + quint8 getcolour(int x); +}; + +#endif // GBGPU_H diff --git a/src/vendor/libqboy/gbkeypad.cpp b/src/vendor/libqboy/gbkeypad.cpp index 9da6027..951dd68 100644 --- a/src/vendor/libqboy/gbkeypad.cpp +++ b/src/vendor/libqboy/gbkeypad.cpp @@ -1,58 +1,58 @@ -#include "gbkeypad.h" - -gbkeypad::gbkeypad(z80mmu *mmu) { - this->mmu = mmu; - reset(); -} - -void gbkeypad::step() { - quint8 mem = mmu->readbyte(_GBKEYPAD_MEMADDR); - mem &= 0x30; - if (mem & 0x10) mem |= row0; - if (mem & 0x20) mem |= row1; - mmu->writebyte(_GBKEYPAD_MEMADDR, mem); - - if (interrupt) { - mmu->writebyte(0xFF0F, mmu->readbyte(0xFF0F) | 0x10); - } - interrupt = false; -} - -void gbkeypad::keydown(GBKeypadKey key) { - switch (key) { - case GBKeypadKey_RIGHT: row1 &= 0xE; break; - case GBKeypadKey_LEFT: row1 &= 0xD; break; - case GBKeypadKey_UP: row1 &= 0xB; break; - case GBKeypadKey_DOWN: row1 &= 0x7; break; - case GBKeypadKey_A: row0 &= 0xE; break; - case GBKeypadKey_B: row0 &= 0xD; break; - case GBKeypadKey_SELECT: row0 &= 0xB; break; - case GBKeypadKey_START: row0 &= 0x7; break; - case GBKeypadKey_NONE: - default: - break; - } - interrupt = true; -} - -void gbkeypad::keyup(GBKeypadKey key) { - switch (key) { - case GBKeypadKey_RIGHT: row1 |= 0x1; break; - case GBKeypadKey_LEFT: row1 |= 0x2; break; - case GBKeypadKey_UP: row1 |= 0x4; break; - case GBKeypadKey_DOWN: row1 |= 0x8; break; - case GBKeypadKey_A: row0 |= 0x1; break; - case GBKeypadKey_B: row0 |= 0x2; break; - case GBKeypadKey_SELECT: row0 |= 0x4; break; - case GBKeypadKey_START: row0 |= 0x8; break; - case GBKeypadKey_NONE: - default: - break; - } -} - -void gbkeypad::reset() { - row0 = row1 = 0x0F; - column = 0x30; - interrupt = false; -} +#include "gbkeypad.h" + +gbkeypad::gbkeypad(z80mmu *mmu) { + this->mmu = mmu; + reset(); +} + +void gbkeypad::step() { + quint8 mem = mmu->readbyte(_GBKEYPAD_MEMADDR); + mem &= 0x30; + if (mem & 0x10) mem |= row0; + if (mem & 0x20) mem |= row1; + mmu->writebyte(_GBKEYPAD_MEMADDR, mem); + + if (interrupt) { + mmu->writebyte(0xFF0F, mmu->readbyte(0xFF0F) | 0x10); + } + interrupt = false; +} + +void gbkeypad::keydown(GBKeypadKey key) { + switch (key) { + case GBKeypadKey_RIGHT: row1 &= 0xE; break; + case GBKeypadKey_LEFT: row1 &= 0xD; break; + case GBKeypadKey_UP: row1 &= 0xB; break; + case GBKeypadKey_DOWN: row1 &= 0x7; break; + case GBKeypadKey_A: row0 &= 0xE; break; + case GBKeypadKey_B: row0 &= 0xD; break; + case GBKeypadKey_SELECT: row0 &= 0xB; break; + case GBKeypadKey_START: row0 &= 0x7; break; + case GBKeypadKey_NONE: + default: + break; + } + interrupt = true; +} + +void gbkeypad::keyup(GBKeypadKey key) { + switch (key) { + case GBKeypadKey_RIGHT: row1 |= 0x1; break; + case GBKeypadKey_LEFT: row1 |= 0x2; break; + case GBKeypadKey_UP: row1 |= 0x4; break; + case GBKeypadKey_DOWN: row1 |= 0x8; break; + case GBKeypadKey_A: row0 |= 0x1; break; + case GBKeypadKey_B: row0 |= 0x2; break; + case GBKeypadKey_SELECT: row0 |= 0x4; break; + case GBKeypadKey_START: row0 |= 0x8; break; + case GBKeypadKey_NONE: + default: + break; + } +} + +void gbkeypad::reset() { + row0 = row1 = 0x0F; + column = 0x30; + interrupt = false; +} diff --git a/src/vendor/libqboy/gbkeypad.h b/src/vendor/libqboy/gbkeypad.h index 6a2cfae..4d14aca 100644 --- a/src/vendor/libqboy/gbkeypad.h +++ b/src/vendor/libqboy/gbkeypad.h @@ -1,35 +1,35 @@ -#ifndef GBKEYPAD_H -#define GBKEYPAD_H - -#include "libqboy_global.h" -#include "z80mmu.h" - -enum GBKeypadKey { - GBKeypadKey_RIGHT, - GBKeypadKey_LEFT, - GBKeypadKey_UP, - GBKeypadKey_DOWN, - GBKeypadKey_A, - GBKeypadKey_B, - GBKeypadKey_SELECT, - GBKeypadKey_START, - GBKeypadKey_NONE -}; - -const int _GBKEYPAD_MEMADDR = 0xFF00; - -class gbkeypad { -public: - gbkeypad(z80mmu *mmu); - void reset(); - void keyup(GBKeypadKey key); - void keydown(GBKeypadKey key); - void step(); -private: - z80mmu *mmu; - quint8 row0, row1; - quint8 column; - bool interrupt; -}; - -#endif // GBKEYPAD_H +#ifndef GBKEYPAD_H +#define GBKEYPAD_H + +#include "libqboy_global.h" +#include "z80mmu.h" + +enum GBKeypadKey { + GBKeypadKey_RIGHT, + GBKeypadKey_LEFT, + GBKeypadKey_UP, + GBKeypadKey_DOWN, + GBKeypadKey_A, + GBKeypadKey_B, + GBKeypadKey_SELECT, + GBKeypadKey_START, + GBKeypadKey_NONE +}; + +const int _GBKEYPAD_MEMADDR = 0xFF00; + +class gbkeypad { +public: + gbkeypad(z80mmu *mmu); + void reset(); + void keyup(GBKeypadKey key); + void keydown(GBKeypadKey key); + void step(); +private: + z80mmu *mmu; + quint8 row0, row1; + quint8 column; + bool interrupt; +}; + +#endif // GBKEYPAD_H diff --git a/src/vendor/libqboy/libqboy.cpp b/src/vendor/libqboy/libqboy.cpp index 4c76d20..4b8669d 100644 --- a/src/vendor/libqboy/libqboy.cpp +++ b/src/vendor/libqboy/libqboy.cpp @@ -1,45 +1,45 @@ -#include "libqboy.h" - -libqboy::libqboy() : cpu(&mmu), timer(&mmu), gpu(&mmu), keypad(&mmu) { - reset(); -} - -void libqboy::reset() { - mmu.reset(); - gpu.reset(); - timer.reset(); - keypad.reset(); - cpu.reset(); -} - -void libqboy::loadgame(std::string filename) { - mmu.load(filename); -} - -quint8 *libqboy::getLCD() { - return gpu.getLCD(); -} - -void libqboy::cycle() { - cpu.cycle(); - gpu.step(cpu.get_m()); - keypad.step(); - timer.step(cpu.get_m()); -} - -int libqboy::get_elapsed_time() { - return cpu.get_m(); -} - -void libqboy::keyup(GBKeypadKey key) { - keypad.keyup(key); -} - - -void libqboy::keydown(GBKeypadKey key) { - keypad.keydown(key); -} - -bool libqboy::refresh_screen() { - return gpu.is_updated(); -} +#include "libqboy.h" + +libqboy::libqboy() : cpu(&mmu), timer(&mmu), gpu(&mmu), keypad(&mmu) { + reset(); +} + +void libqboy::reset() { + mmu.reset(); + gpu.reset(); + timer.reset(); + keypad.reset(); + cpu.reset(); +} + +void libqboy::loadgame(std::string filename) { + mmu.load(filename); +} + +quint8 *libqboy::getLCD() { + return gpu.getLCD(); +} + +void libqboy::cycle() { + cpu.cycle(); + gpu.step(cpu.get_m()); + keypad.step(); + timer.step(cpu.get_m()); +} + +int libqboy::get_elapsed_time() { + return cpu.get_m(); +} + +void libqboy::keyup(GBKeypadKey key) { + keypad.keyup(key); +} + + +void libqboy::keydown(GBKeypadKey key) { + keypad.keydown(key); +} + +bool libqboy::refresh_screen() { + return gpu.is_updated(); +} diff --git a/src/vendor/libqboy/libqboy.h b/src/vendor/libqboy/libqboy.h index d2cef13..e724afc 100644 --- a/src/vendor/libqboy/libqboy.h +++ b/src/vendor/libqboy/libqboy.h @@ -1,33 +1,33 @@ -#ifndef LIBQBOY_H -#define LIBQBOY_H - -#include "libqboy_global.h" - -#include "z80.h" -#include "z80mmu.h" -#include "gbgpu.h" -#include "gbkeypad.h" -#include "z80timer.h" - -#include - -class LIBQBOYSHARED_EXPORT libqboy { -public: - libqboy(); - void reset(); - quint8 *getLCD(); - void loadgame(std::string filename); - void cycle(); - bool refresh_screen(); - int get_elapsed_time(); - void keyup(GBKeypadKey key); - void keydown(GBKeypadKey key); -private: - z80 cpu; - z80mmu mmu; - z80timer timer; - gbgpu gpu; - gbkeypad keypad; -}; - -#endif // LIBQBOY_H +#ifndef LIBQBOY_H +#define LIBQBOY_H + +#include "libqboy_global.h" + +#include "z80.h" +#include "z80mmu.h" +#include "gbgpu.h" +#include "gbkeypad.h" +#include "z80timer.h" + +#include + +class LIBQBOYSHARED_EXPORT libqboy { +public: + libqboy(); + void reset(); + quint8 *getLCD(); + void loadgame(std::string filename); + void cycle(); + bool refresh_screen(); + int get_elapsed_time(); + void keyup(GBKeypadKey key); + void keydown(GBKeypadKey key); +private: + z80 cpu; + z80mmu mmu; + z80timer timer; + gbgpu gpu; + gbkeypad keypad; +}; + +#endif // LIBQBOY_H diff --git a/src/vendor/libqboy/libqboy.pro b/src/vendor/libqboy/libqboy.pro index aac5f7c..78bf129 100644 --- a/src/vendor/libqboy/libqboy.pro +++ b/src/vendor/libqboy/libqboy.pro @@ -1,39 +1,39 @@ -QT -= gui - -TARGET = qboy -TEMPLATE = lib - -DEFINES += LIBQBOY_LIBRARY - -linux-oe-g++ { - CONFIG -= debug - CONFIG += release -} - -SOURCES += libqboy.cpp \ - z80.cpp \ - z80alu.cpp \ - z80mmu.cpp \ - z80register.cpp \ - gbgpu.cpp \ - gbkeypad.cpp \ - z80timer.cpp \ - z80mbc.cpp - -HEADERS += libqboy.h\ - libqboy_global.h \ - z80.h \ - z80alu.h \ - z80mmu.h \ - z80register.h \ - gbgpu.h \ - gbkeypad.h \ - z80timer.h \ - z80mbc.h - -linux-oe-g++ { - target.path = /opt/usr/lib -}else{ - target.path = /usr/lib -} -INSTALLS += target +QT -= gui + +TARGET = qboy +TEMPLATE = lib + +DEFINES += LIBQBOY_LIBRARY + +linux-oe-g++ { + CONFIG -= debug + CONFIG += release +} + +SOURCES += libqboy.cpp \ + z80.cpp \ + z80alu.cpp \ + z80mmu.cpp \ + z80register.cpp \ + gbgpu.cpp \ + gbkeypad.cpp \ + z80timer.cpp \ + z80mbc.cpp + +HEADERS += libqboy.h\ + libqboy_global.h \ + z80.h \ + z80alu.h \ + z80mmu.h \ + z80register.h \ + gbgpu.h \ + gbkeypad.h \ + z80timer.h \ + z80mbc.h + +linux-oe-g++ { + target.path = /opt/usr/lib +}else{ + target.path = /usr/lib +} +INSTALLS += target diff --git a/src/vendor/libqboy/libqboy_global.h b/src/vendor/libqboy/libqboy_global.h index 872d698..d541856 100644 --- a/src/vendor/libqboy/libqboy_global.h +++ b/src/vendor/libqboy/libqboy_global.h @@ -1,12 +1,12 @@ -#ifndef LIBQBOY_GLOBAL_H -#define LIBQBOY_GLOBAL_H - -#include - -#if defined(LIBQBOY_LIBRARY) -# define LIBQBOYSHARED_EXPORT Q_DECL_EXPORT -#else -# define LIBQBOYSHARED_EXPORT Q_DECL_IMPORT -#endif - -#endif // LIBQBOY_GLOBAL_H +#ifndef LIBQBOY_GLOBAL_H +#define LIBQBOY_GLOBAL_H + +#include + +#if defined(LIBQBOY_LIBRARY) +# define LIBQBOYSHARED_EXPORT Q_DECL_EXPORT +#else +# define LIBQBOYSHARED_EXPORT Q_DECL_IMPORT +#endif + +#endif // LIBQBOY_GLOBAL_H diff --git a/src/vendor/libqboy/z80.h b/src/vendor/libqboy/z80.h index 2d13622..8722918 100644 --- a/src/vendor/libqboy/z80.h +++ b/src/vendor/libqboy/z80.h @@ -1,108 +1,108 @@ -#ifndef Z80_H -#define Z80_H - -#include "libqboy_global.h" -#include "z80mmu.h" -#include "z80alu.h" -#include "z80register.h" - -enum Direction { - Direction_LEFT, - Direction_RIGHT -}; - -class z80 { -public: - z80(z80mmu *mmu); - void reset(); - void cycle(); - int get_m(); - bool is_halted(); -private: - unsigned int last_m; - bool interrupt_enable; - - z80mmu *mmu; - z80alu alu; - z80register af, bc, de, hl, sp, pc; - bool halted; - - bool handle_interrupt(); - quint8 getbytearg(); - quint16 getwordarg(); - quint8 getbyteregisterval(int code); - void setbyteregisterval(int code, quint8 val); - quint16 getwordregisterval(int code, bool lastsp); - void setwordregisterval(int code, bool lastsp, quint16 val); - void pushstack(quint16 val); - quint16 popstack(); - void addticks(int m); - - bool jumpcond(int arg); - - void call(quint8 opcode); - void call_extended(); - - void op_nop(); - void op_ld_r_r(int arg1, int arg2); - void op_ld_r_n(int arg); - void op_ld_a_ss(int arg); - void op_ld_a_hl(int arg); - void op_ld_dd_nn(int arg); - void op_ld_sp_hl(); - void op_push_qq(int arg); - void op_pop_qq(int arg); - void op_add_r(int arg, bool withcarry); - void op_add_n(bool withcarry); - void op_sub_r(int arg, bool withcarry); - void op_sub_n(bool withcarry); - void op_and_r(int arg); - void op_and_n(); - void op_or_r(int arg); - void op_or_n(); - void op_xor_r(int arg); - void op_xor_n(); - void op_cp_r(int arg); - void op_cp_n(); - void op_inc_r(int arg); - void op_dec_r(int arg); - void op_cpl(); - void op_ccf(); - void op_scf(); - void op_halt(); - void op_di(); - void op_ei(); - void op_add16_rr(int arg); - void op_inc16_rr(int arg); - void op_dec16_rr(int arg); - void op_rdca(Direction dir); - void op_rda(Direction dir); - void op_rdc_r(int arg, Direction dir); - void op_rd_r(int arg, Direction dir); - void op_sda(int arg, Direction dir); - void op_srl(int arg); - void op_bit(quint8 bit, int arg); - void op_set(quint8 bit, int arg); - void op_res(quint8 bit, int arg); - void op_jump(); - void op_jump_cond(int arg); - void op_jump_rel(int arg); - void op_jump_hl(); - void op_call(); - void op_call_cond(int arg); - void op_ret(); - void op_ret_cond(int arg); - void op_reti(); - void op_rst_p(int arg); - void op_rst_int(int address); - void op_ld_mm_sp(); - void op_ld_a_n(int arg); - void op_ld_sp_sn(); - void op_ld_hl_sp_sn(); - void op_ld_a_c(int arg); - void op_ld_a_nn(int arg); - void op_swap(int arg); - void op_daa(); -}; - -#endif // Z80_H +#ifndef Z80_H +#define Z80_H + +#include "libqboy_global.h" +#include "z80mmu.h" +#include "z80alu.h" +#include "z80register.h" + +enum Direction { + Direction_LEFT, + Direction_RIGHT +}; + +class z80 { +public: + z80(z80mmu *mmu); + void reset(); + void cycle(); + int get_m(); + bool is_halted(); +private: + unsigned int last_m; + bool interrupt_enable; + + z80mmu *mmu; + z80alu alu; + z80register af, bc, de, hl, sp, pc; + bool halted; + + bool handle_interrupt(); + quint8 getbytearg(); + quint16 getwordarg(); + quint8 getbyteregisterval(int code); + void setbyteregisterval(int code, quint8 val); + quint16 getwordregisterval(int code, bool lastsp); + void setwordregisterval(int code, bool lastsp, quint16 val); + void pushstack(quint16 val); + quint16 popstack(); + void addticks(int m); + + bool jumpcond(int arg); + + void call(quint8 opcode); + void call_extended(); + + void op_nop(); + void op_ld_r_r(int arg1, int arg2); + void op_ld_r_n(int arg); + void op_ld_a_ss(int arg); + void op_ld_a_hl(int arg); + void op_ld_dd_nn(int arg); + void op_ld_sp_hl(); + void op_push_qq(int arg); + void op_pop_qq(int arg); + void op_add_r(int arg, bool withcarry); + void op_add_n(bool withcarry); + void op_sub_r(int arg, bool withcarry); + void op_sub_n(bool withcarry); + void op_and_r(int arg); + void op_and_n(); + void op_or_r(int arg); + void op_or_n(); + void op_xor_r(int arg); + void op_xor_n(); + void op_cp_r(int arg); + void op_cp_n(); + void op_inc_r(int arg); + void op_dec_r(int arg); + void op_cpl(); + void op_ccf(); + void op_scf(); + void op_halt(); + void op_di(); + void op_ei(); + void op_add16_rr(int arg); + void op_inc16_rr(int arg); + void op_dec16_rr(int arg); + void op_rdca(Direction dir); + void op_rda(Direction dir); + void op_rdc_r(int arg, Direction dir); + void op_rd_r(int arg, Direction dir); + void op_sda(int arg, Direction dir); + void op_srl(int arg); + void op_bit(quint8 bit, int arg); + void op_set(quint8 bit, int arg); + void op_res(quint8 bit, int arg); + void op_jump(); + void op_jump_cond(int arg); + void op_jump_rel(int arg); + void op_jump_hl(); + void op_call(); + void op_call_cond(int arg); + void op_ret(); + void op_ret_cond(int arg); + void op_reti(); + void op_rst_p(int arg); + void op_rst_int(int address); + void op_ld_mm_sp(); + void op_ld_a_n(int arg); + void op_ld_sp_sn(); + void op_ld_hl_sp_sn(); + void op_ld_a_c(int arg); + void op_ld_a_nn(int arg); + void op_swap(int arg); + void op_daa(); +}; + +#endif // Z80_H diff --git a/src/vendor/libqboy/z80alu.cpp b/src/vendor/libqboy/z80alu.cpp index 01d0ed5..645cdf5 100644 --- a/src/vendor/libqboy/z80alu.cpp +++ b/src/vendor/libqboy/z80alu.cpp @@ -1,226 +1,226 @@ -#include "z80alu.h" - -void z80alu::setregisters(z80register *afregister, z80register *hlregister) { - af = afregister; - hl = hlregister; -} - -void z80alu::add(quint8 b, bool withcarry) { - quint8 a = af->gethi(); - quint8 carry = (withcarry && af->getflag('c')) ? 1 : 0; - quint8 res = a + b + carry; - - af->setflag('z', res == 0); - af->setflag('h', (a & 0x0F) + (b & 0x0F) + carry > 0x0F); - af->setflag('n', false); - af->setflag('c', a > 0xFF - b - carry); - - af->sethi(res); -} - -void z80alu::sub(quint8 b, bool withcarry) { - quint8 a = af->gethi(); - quint8 carry = (withcarry && af->getflag('c')) ? 1 : 0; - quint8 res = a - (b + carry); - - af->setflag('z', res == 0); - af->setflag('h', (a & 0x0F) < (b & 0x0F) + carry); - af->setflag('n', true); - af->setflag('c', a < b + carry); - - af->sethi(res); -} - -void z80alu::land(quint8 b) { - quint8 a = af->gethi(); - quint8 res = a & b; - - af->setflag('z', res == 0); - af->setflag('h', true); - af->setflag('n', false); - af->setflag('c', false); - - af->sethi(res); -} - -void z80alu::lor(quint8 b) { - quint8 a = af->gethi(); - quint8 res = a | b; - - af->setflag('z', res == 0); - af->setflag('h', false); - af->setflag('n', false); - af->setflag('c', false); - - af->sethi(res); -} - -void z80alu::lxor(quint8 b) { - quint8 a = af->gethi(); - quint8 res = a ^ b; - - af->setflag('z', res == 0); - af->setflag('h', false); - af->setflag('n', false); - af->setflag('c', false); - - af->sethi(res); -} - -void z80alu::cp(quint8 b) { - quint8 a = af->gethi(); - sub(b, false); - af->sethi(a); -} - -quint8 z80alu::inc(quint8 a) { - quint8 res = a + 1; - - af->setflag('z', res == 0); - af->setflag('h', (a & 0x0F) + 1 > 0x0F); - af->setflag('n', false); - - return res; -} - -quint8 z80alu::dec(quint8 a) { - quint8 res = a - 1; - - af->setflag('z', res == 0); - af->setflag('h', (a & 0x0F) == 0); - af->setflag('n', true); - - return res; -} - -void z80alu::cpl() { - af->sethi(~af->gethi()); - af->setflag('h', true); - af->setflag('n', true); -} - -void z80alu::ccf() { - af->setflag('c', !af->getflag('c')); - af->setflag('h', false); - af->setflag('n', false); -} - -void z80alu::scf() { - af->setflag('c', true); - af->setflag('h', false); - af->setflag('n', false); -} - -void z80alu::add16(quint16 b) { - quint16 a = hl->getfull(); - quint16 res = a + b; - - af->setflag('h', (a & 0x07FF) + (b & 0x07FF) > 0x07FF); - af->setflag('n', false); - af->setflag('c', a > 0xFFFF - b); - - hl->setfull(res); -} - -quint16 z80alu::add16mixed(quint16 a, qint8 b) { - quint16 other = (quint16) (((qint16)(b << 8)) >> 8); - - af->setflag('z', false); - af->setflag('n', false); - af->setflag('h', (a & 0x000F) + (other & 0x000F) > 0x000F); - af->setflag('c', (a & 0x00FF) + (other & 0x00FF) > 0x00FF); - - return a + other; -} - -quint8 z80alu::rr(quint8 val) { - quint8 carry = val & 1; - quint8 result = (val >> 1) | (af->getflag('c') ? 0x80 : 0); - - setregistersaftershift(result, carry); - return result; -} - -quint8 z80alu::rrc(quint8 val) { - quint8 carry = val & 1; - quint8 result = (val >> 1) | (carry << 7); - - setregistersaftershift(result, carry); - return result; -} - -quint8 z80alu::rl(quint8 val) { - quint8 carry = val & 0x80; - quint8 result = (val << 1) | (af->getflag('c') ? 1 : 0); - - setregistersaftershift(result, carry); - return result; -} - -quint8 z80alu::rlc(quint8 val) { - quint8 carry = val & 0x80; - quint8 result = (val << 1) | (carry >> 7); - - setregistersaftershift(result, carry); - return result; -} - -quint8 z80alu::sla(quint8 val) { - quint8 carry = val & 0x80; - quint8 result = val << 1; - - setregistersaftershift(result, carry); - return result; -} - -// This is a signed shift right -quint8 z80alu::sra(quint8 val) { - quint8 carry = val & 1; - -#if (-2 >> 1) == -1 - quint8 result = ((qint8)val) >> 1; -#else - quint8 result = (val >> 1) | (val & 0x80); -#endif - - setregistersaftershift(result, carry); - return result; -} - -quint8 z80alu::srl(quint8 val) { - quint8 carry = val & 1; - quint8 result = val >> 1; - - setregistersaftershift(result, carry); - return result; -} - -void z80alu::daa() { - quint8 a = af->gethi(); - quint16 adjust = af->getflag('c') ? 0x60 : 0x00; - if(af->getflag('h')) - adjust |= 0x06; - if(!af->getflag('n')) { - if((a & 0x0F) > 0x09) - adjust |= 0x06; - if(a > 0x99) - adjust |= 0x60; - a += adjust; - } else { - a -= adjust; - } - - af->setflag('c', adjust >= 0x60); - af->setflag('h', false); - af->setflag('z', a == 0); - - af->sethi(a); -} - -void z80alu::setregistersaftershift(quint8 result, quint8 carry) { - af->setflag('h', false); - af->setflag('n', false); - - af->setflag('z', result == 0); - af->setflag('c', carry != 0); -} +#include "z80alu.h" + +void z80alu::setregisters(z80register *afregister, z80register *hlregister) { + af = afregister; + hl = hlregister; +} + +void z80alu::add(quint8 b, bool withcarry) { + quint8 a = af->gethi(); + quint8 carry = (withcarry && af->getflag('c')) ? 1 : 0; + quint8 res = a + b + carry; + + af->setflag('z', res == 0); + af->setflag('h', (a & 0x0F) + (b & 0x0F) + carry > 0x0F); + af->setflag('n', false); + af->setflag('c', a > 0xFF - b - carry); + + af->sethi(res); +} + +void z80alu::sub(quint8 b, bool withcarry) { + quint8 a = af->gethi(); + quint8 carry = (withcarry && af->getflag('c')) ? 1 : 0; + quint8 res = a - (b + carry); + + af->setflag('z', res == 0); + af->setflag('h', (a & 0x0F) < (b & 0x0F) + carry); + af->setflag('n', true); + af->setflag('c', a < b + carry); + + af->sethi(res); +} + +void z80alu::land(quint8 b) { + quint8 a = af->gethi(); + quint8 res = a & b; + + af->setflag('z', res == 0); + af->setflag('h', true); + af->setflag('n', false); + af->setflag('c', false); + + af->sethi(res); +} + +void z80alu::lor(quint8 b) { + quint8 a = af->gethi(); + quint8 res = a | b; + + af->setflag('z', res == 0); + af->setflag('h', false); + af->setflag('n', false); + af->setflag('c', false); + + af->sethi(res); +} + +void z80alu::lxor(quint8 b) { + quint8 a = af->gethi(); + quint8 res = a ^ b; + + af->setflag('z', res == 0); + af->setflag('h', false); + af->setflag('n', false); + af->setflag('c', false); + + af->sethi(res); +} + +void z80alu::cp(quint8 b) { + quint8 a = af->gethi(); + sub(b, false); + af->sethi(a); +} + +quint8 z80alu::inc(quint8 a) { + quint8 res = a + 1; + + af->setflag('z', res == 0); + af->setflag('h', (a & 0x0F) + 1 > 0x0F); + af->setflag('n', false); + + return res; +} + +quint8 z80alu::dec(quint8 a) { + quint8 res = a - 1; + + af->setflag('z', res == 0); + af->setflag('h', (a & 0x0F) == 0); + af->setflag('n', true); + + return res; +} + +void z80alu::cpl() { + af->sethi(~af->gethi()); + af->setflag('h', true); + af->setflag('n', true); +} + +void z80alu::ccf() { + af->setflag('c', !af->getflag('c')); + af->setflag('h', false); + af->setflag('n', false); +} + +void z80alu::scf() { + af->setflag('c', true); + af->setflag('h', false); + af->setflag('n', false); +} + +void z80alu::add16(quint16 b) { + quint16 a = hl->getfull(); + quint16 res = a + b; + + af->setflag('h', (a & 0x07FF) + (b & 0x07FF) > 0x07FF); + af->setflag('n', false); + af->setflag('c', a > 0xFFFF - b); + + hl->setfull(res); +} + +quint16 z80alu::add16mixed(quint16 a, qint8 b) { + quint16 other = (quint16) (((qint16)(b << 8)) >> 8); + + af->setflag('z', false); + af->setflag('n', false); + af->setflag('h', (a & 0x000F) + (other & 0x000F) > 0x000F); + af->setflag('c', (a & 0x00FF) + (other & 0x00FF) > 0x00FF); + + return a + other; +} + +quint8 z80alu::rr(quint8 val) { + quint8 carry = val & 1; + quint8 result = (val >> 1) | (af->getflag('c') ? 0x80 : 0); + + setregistersaftershift(result, carry); + return result; +} + +quint8 z80alu::rrc(quint8 val) { + quint8 carry = val & 1; + quint8 result = (val >> 1) | (carry << 7); + + setregistersaftershift(result, carry); + return result; +} + +quint8 z80alu::rl(quint8 val) { + quint8 carry = val & 0x80; + quint8 result = (val << 1) | (af->getflag('c') ? 1 : 0); + + setregistersaftershift(result, carry); + return result; +} + +quint8 z80alu::rlc(quint8 val) { + quint8 carry = val & 0x80; + quint8 result = (val << 1) | (carry >> 7); + + setregistersaftershift(result, carry); + return result; +} + +quint8 z80alu::sla(quint8 val) { + quint8 carry = val & 0x80; + quint8 result = val << 1; + + setregistersaftershift(result, carry); + return result; +} + +// This is a signed shift right +quint8 z80alu::sra(quint8 val) { + quint8 carry = val & 1; + +#if (-2 >> 1) == -1 + quint8 result = ((qint8)val) >> 1; +#else + quint8 result = (val >> 1) | (val & 0x80); +#endif + + setregistersaftershift(result, carry); + return result; +} + +quint8 z80alu::srl(quint8 val) { + quint8 carry = val & 1; + quint8 result = val >> 1; + + setregistersaftershift(result, carry); + return result; +} + +void z80alu::daa() { + quint8 a = af->gethi(); + quint16 adjust = af->getflag('c') ? 0x60 : 0x00; + if(af->getflag('h')) + adjust |= 0x06; + if(!af->getflag('n')) { + if((a & 0x0F) > 0x09) + adjust |= 0x06; + if(a > 0x99) + adjust |= 0x60; + a += adjust; + } else { + a -= adjust; + } + + af->setflag('c', adjust >= 0x60); + af->setflag('h', false); + af->setflag('z', a == 0); + + af->sethi(a); +} + +void z80alu::setregistersaftershift(quint8 result, quint8 carry) { + af->setflag('h', false); + af->setflag('n', false); + + af->setflag('z', result == 0); + af->setflag('c', carry != 0); +} diff --git a/src/vendor/libqboy/z80alu.h b/src/vendor/libqboy/z80alu.h index 459fb19..d729c07 100644 --- a/src/vendor/libqboy/z80alu.h +++ b/src/vendor/libqboy/z80alu.h @@ -1,36 +1,36 @@ -#ifndef Z80ALU_H -#define Z80ALU_H - -#include "libqboy_global.h" -#include "z80register.h" - -class z80alu { -public: - void setregisters(z80register *afregister, z80register *hlregister); - void add(quint8 val, bool withcarry); - void sub(quint8 val, bool withcarry); - void land(quint8 val); - void lor(quint8 val); - void lxor(quint8 val); - void cp(quint8 val); - quint8 inc(quint8 val); - quint8 dec(quint8 val); - void cpl(); - void ccf(); - void scf(); - void add16(quint16 val); - quint16 add16mixed(quint16 a, qint8 other); - quint8 rr(quint8 val); - quint8 rrc(quint8 val); - quint8 rl(quint8 val); - quint8 rlc(quint8 val); - quint8 sla(quint8 val); - quint8 sra(quint8 val); - quint8 srl(quint8 val); - void daa(); -private: - z80register *af, *hl; - void setregistersaftershift(quint8 result, quint8 carry); -}; - -#endif // Z80ALU_H +#ifndef Z80ALU_H +#define Z80ALU_H + +#include "libqboy_global.h" +#include "z80register.h" + +class z80alu { +public: + void setregisters(z80register *afregister, z80register *hlregister); + void add(quint8 val, bool withcarry); + void sub(quint8 val, bool withcarry); + void land(quint8 val); + void lor(quint8 val); + void lxor(quint8 val); + void cp(quint8 val); + quint8 inc(quint8 val); + quint8 dec(quint8 val); + void cpl(); + void ccf(); + void scf(); + void add16(quint16 val); + quint16 add16mixed(quint16 a, qint8 other); + quint8 rr(quint8 val); + quint8 rrc(quint8 val); + quint8 rl(quint8 val); + quint8 rlc(quint8 val); + quint8 sla(quint8 val); + quint8 sra(quint8 val); + quint8 srl(quint8 val); + void daa(); +private: + z80register *af, *hl; + void setregistersaftershift(quint8 result, quint8 carry); +}; + +#endif // Z80ALU_H diff --git a/src/vendor/libqboy/z80mbc.cpp b/src/vendor/libqboy/z80mbc.cpp index 2c14d09..f2e0dac 100644 --- a/src/vendor/libqboy/z80mbc.cpp +++ b/src/vendor/libqboy/z80mbc.cpp @@ -1,321 +1,321 @@ -#include "z80mbc.h" - -#include -#include - -z80mbc0::z80mbc0(const std::vector &rom) { - this->rom = rom; - ram.resize(0x2000); -} - -quint8 z80mbc0::readROM(quint16 address) { - return rom[address]; -} - -quint8 z80mbc0::readRAM(quint16 address) { - return ram[address]; -} - -void z80mbc0::writeROM(quint16, quint8) {} - -void z80mbc0::writeRAM(quint16 address, quint8 value) { - ram[address] = value; -} - -/********************************/ - -z80mbc1::z80mbc1(const std::vector &rom) { - this->rom = rom; - ram.resize(0x10000); - rombank = 1; - rambank = 0; - extram_on = false; - ram_mode = false; -} - -quint8 z80mbc1::readROM(quint16 address) { - if (address < 0x4000) return rom[address]; - address &= 0x3FFF; - int the_rombank = (ram_mode) ? rombank & 0x1F : rombank; - return rom[the_rombank * 0x4000 | address]; -} - -quint8 z80mbc1::readRAM(quint16 address) { - if (!extram_on || !ram_mode) return 0; - address &= 0x1FFF; - return ram[rambank * 0x2000 | address]; -} - -void z80mbc1::writeROM(quint16 address, quint8 value) { - switch (address & 0xF000) { - case 0x0000: - case 0x1000: - extram_on = (value == 0x0A); - break; - case 0x2000: - case 0x3000: - value &= 0x1F; - if (value == 0) value = 1; - rombank = (rombank & 0x60) | value; - break; - case 0x4000: - case 0x5000: - value &= 0x03; - if (ram_mode) { - rambank = value; - } else { - rombank = (value << 5) | (rombank & 0x1F); - } - break; - case 0x6000: - case 0x7000: - ram_mode = value & 1; - break; - } -} - -void z80mbc1::writeRAM(quint16 address, quint8 value) { - if (!extram_on || !ram_mode) return; - if (!ram_mode) rambank = 0; - address &= 0x1FFF; - ram[rambank * 0x2000 | address] = value; -} - -/********************************/ - -z80mbc3::z80mbc3(const std::vector &rom) { - this->rom = rom; - - int ramsize = 0; - switch (rom[0x0149]) { - case 0x00: - ramsize = 0; break; - case 0x01: - ramsize = 0x800; break; // 2 kB - case 0x02: - ramsize = 0x2000; break; // 8 kB - case 0x03: - ramsize = 0x8000; break; // 32 kB - } - - ram.resize(ramsize); - rtc.resize(5); - rombank = 1; - rambank = 0; - extram_on = false; - rtc_lock = false; -} - -quint8 z80mbc3::readROM(quint16 address) { - if (address < 0x4000) return rom[address]; - address &= 0x3FFF; - return rom[rombank * 0x4000 + (int)address]; -} - -quint8 z80mbc3::readRAM(quint16 address) { - if (extram_on == false) return 0; - if (rambank <= 3) { - address &= 0x1FFF; - return ram[rambank * 0x2000 + (int)address]; - } else { - return rtc[rambank - 0x08]; - } -} - -void z80mbc3::writeROM(quint16 address, quint8 value) { - switch (address & 0xF000) { - case 0x0000: - case 0x1000: - extram_on = (value == 0x0A); - break; - case 0x2000: - case 0x3000: - value &= 0x7F; - rombank = (value == 0x00) ? 0x01 : value; - break; - case 0x4000: - case 0x5000: - rambank = value; - break; - case 0x6000: - case 0x7000: - switch (value) { - case 0x00: - rtc_lock = false; - break; - case 0x01: - if (rtc_lock == false) calc_rtcregs(); - rtc_lock = true; - break; - } - break; - } -} - -void z80mbc3::writeRAM(quint16 address, quint8 value) { - if (extram_on == false) return; - - if (rambank <= 3) { - address &= 0x1FFF; - ram[rambank * 0x2000 + (int)address] = value; - } else { - rtc[rambank - 0x8] = value; - calc_rtczero(); - } -} - -void z80mbc3::save(std::string filename) { - std::ofstream fout(filename.c_str(), std::ios_base::out | std::ios_base::binary); - - char head[] = "GB_MBC"; - fout.write(head, sizeof head); - fout.write(reinterpret_cast(&rom[0x0147]), 1); - - for (int i = 0; i < 5; ++i) { - fout.write(reinterpret_cast(&rtc[i]), 1); - } - quint64 rtc = rtczero; - fout.write(reinterpret_cast(&rtc), 8); - - for (unsigned i = 0; i < ram.size(); ++i) { - fout.write(reinterpret_cast(&ram[i]), 1); - } - fout.close(); -} - -void z80mbc3::load(std::string filename) { - std::ifstream fin(filename.c_str(), std::ios_base::in | std::ios_base::binary); - if (!fin.is_open()) return; - - char head[7]; - char ver; - - fin.read(head, 7); - fin.read(&ver, 1); - if (strcmp(head, "GB_MBC") != 0) { - fin.close(); - return; - } - - - char byte; - rtc.clear(); - for (int i = 0; i < 5; ++i) { - fin.read(&byte, 1); - rtc.push_back(byte); - } - quint64 rtc; - fin.read(reinterpret_cast(&rtc), 8); - rtczero = rtc; - - ram.clear(); - while (fin.read(&byte, 1)) { - ram.push_back(byte); - } - fin.close(); - - - calc_rtcregs(); -} - -void z80mbc3::calc_rtczero() { - time_t difftime = time(NULL); - long long days; - difftime -= rtc[0]; - difftime -= rtc[1] * 60; - difftime -= rtc[2] * 3600; - days = rtc[4] & 0x1; - days = days << 8 | rtc[3]; - difftime -= days * 3600 * 24; - rtczero = difftime; -} - -void z80mbc3::calc_rtcregs() { - if (rtc[4] & 0x40) { - return; - } - - time_t difftime = time(NULL) - rtczero; - rtc[0] = difftime % 60; - rtc[1] = (difftime / 60) % 60; - rtc[2] = (difftime / 3600) % 24; - long long days = (difftime / (3600*24)); - rtc[3] = days & 0xFF; - rtc[4] = (rtc[4] & 0xFE) | ((days >> 8) & 0x1); - - if (days >= 512) { - rtc[4] |= 0x80; - calc_rtczero(); - } -} - -/********************************/ - -z80mbc5::z80mbc5(const std::vector &rom) { - this->rom = rom; - ram.resize(0x20000); - rombank = 1; - rambank = 0; - extram_on = false; -} - -quint8 z80mbc5::readROM(quint16 address) { - if (address < 0x4000) return rom[address]; - address &= 0x3FFF; - - return rom[rombank * 0x4000 | address]; -} - -quint8 z80mbc5::readRAM(quint16 address) { - if (!extram_on) return 0; - - address &= 0x1FFF; - return ram[rambank * 0x2000 | address]; -} - -void z80mbc5::writeROM(quint16 address, quint8 value) { - switch (address & 0xF000) { - case 0x0000: - case 0x1000: - extram_on = (value == 0x0A); - break; - case 0x2000: - rombank = (rombank & 0x100) | (value); - break; - case 0x3000: - value &= 0x1; - rombank = (rombank & 0xFF) | (((int)value) << 8); - break; - case 0x4000: - case 0x5000: - rambank = value & 0x0F; - break; - } -} - -void z80mbc5::writeRAM(quint16 address, quint8 value) { - if (!extram_on) return; - - address &= 0x1FFF; - ram[rambank * 0x2000 | address] = value; -} - -void z80mbc5::save(std::string filename) { - std::ofstream fout(filename.c_str(), std::ios_base::out | std::ios_base::binary); - for (unsigned i = 0; i < ram.size(); ++i) { - fout.write((char*)&ram[i], 1); - } - fout.close(); -} - -void z80mbc5::load(std::string filename) { - std::ifstream fin(filename.c_str(), std::ios_base::in | std::ios_base::binary); - if (!fin.is_open()) return; - - char byte; - ram.clear(); - while (fin.read(&byte, 1)) { - ram.push_back(byte); - } - fin.close(); -} +#include "z80mbc.h" + +#include +#include + +z80mbc0::z80mbc0(const std::vector &rom) { + this->rom = rom; + ram.resize(0x2000); +} + +quint8 z80mbc0::readROM(quint16 address) { + return rom[address]; +} + +quint8 z80mbc0::readRAM(quint16 address) { + return ram[address]; +} + +void z80mbc0::writeROM(quint16, quint8) {} + +void z80mbc0::writeRAM(quint16 address, quint8 value) { + ram[address] = value; +} + +/********************************/ + +z80mbc1::z80mbc1(const std::vector &rom) { + this->rom = rom; + ram.resize(0x10000); + rombank = 1; + rambank = 0; + extram_on = false; + ram_mode = false; +} + +quint8 z80mbc1::readROM(quint16 address) { + if (address < 0x4000) return rom[address]; + address &= 0x3FFF; + int the_rombank = (ram_mode) ? rombank & 0x1F : rombank; + return rom[the_rombank * 0x4000 | address]; +} + +quint8 z80mbc1::readRAM(quint16 address) { + if (!extram_on || !ram_mode) return 0; + address &= 0x1FFF; + return ram[rambank * 0x2000 | address]; +} + +void z80mbc1::writeROM(quint16 address, quint8 value) { + switch (address & 0xF000) { + case 0x0000: + case 0x1000: + extram_on = (value == 0x0A); + break; + case 0x2000: + case 0x3000: + value &= 0x1F; + if (value == 0) value = 1; + rombank = (rombank & 0x60) | value; + break; + case 0x4000: + case 0x5000: + value &= 0x03; + if (ram_mode) { + rambank = value; + } else { + rombank = (value << 5) | (rombank & 0x1F); + } + break; + case 0x6000: + case 0x7000: + ram_mode = value & 1; + break; + } +} + +void z80mbc1::writeRAM(quint16 address, quint8 value) { + if (!extram_on || !ram_mode) return; + if (!ram_mode) rambank = 0; + address &= 0x1FFF; + ram[rambank * 0x2000 | address] = value; +} + +/********************************/ + +z80mbc3::z80mbc3(const std::vector &rom) { + this->rom = rom; + + int ramsize = 0; + switch (rom[0x0149]) { + case 0x00: + ramsize = 0; break; + case 0x01: + ramsize = 0x800; break; // 2 kB + case 0x02: + ramsize = 0x2000; break; // 8 kB + case 0x03: + ramsize = 0x8000; break; // 32 kB + } + + ram.resize(ramsize); + rtc.resize(5); + rombank = 1; + rambank = 0; + extram_on = false; + rtc_lock = false; +} + +quint8 z80mbc3::readROM(quint16 address) { + if (address < 0x4000) return rom[address]; + address &= 0x3FFF; + return rom[rombank * 0x4000 + (int)address]; +} + +quint8 z80mbc3::readRAM(quint16 address) { + if (extram_on == false) return 0; + if (rambank <= 3) { + address &= 0x1FFF; + return ram[rambank * 0x2000 + (int)address]; + } else { + return rtc[rambank - 0x08]; + } +} + +void z80mbc3::writeROM(quint16 address, quint8 value) { + switch (address & 0xF000) { + case 0x0000: + case 0x1000: + extram_on = (value == 0x0A); + break; + case 0x2000: + case 0x3000: + value &= 0x7F; + rombank = (value == 0x00) ? 0x01 : value; + break; + case 0x4000: + case 0x5000: + rambank = value; + break; + case 0x6000: + case 0x7000: + switch (value) { + case 0x00: + rtc_lock = false; + break; + case 0x01: + if (rtc_lock == false) calc_rtcregs(); + rtc_lock = true; + break; + } + break; + } +} + +void z80mbc3::writeRAM(quint16 address, quint8 value) { + if (extram_on == false) return; + + if (rambank <= 3) { + address &= 0x1FFF; + ram[rambank * 0x2000 + (int)address] = value; + } else { + rtc[rambank - 0x8] = value; + calc_rtczero(); + } +} + +void z80mbc3::save(std::string filename) { + std::ofstream fout(filename.c_str(), std::ios_base::out | std::ios_base::binary); + + char head[] = "GB_MBC"; + fout.write(head, sizeof head); + fout.write(reinterpret_cast(&rom[0x0147]), 1); + + for (int i = 0; i < 5; ++i) { + fout.write(reinterpret_cast(&rtc[i]), 1); + } + quint64 rtc = rtczero; + fout.write(reinterpret_cast(&rtc), 8); + + for (unsigned i = 0; i < ram.size(); ++i) { + fout.write(reinterpret_cast(&ram[i]), 1); + } + fout.close(); +} + +void z80mbc3::load(std::string filename) { + std::ifstream fin(filename.c_str(), std::ios_base::in | std::ios_base::binary); + if (!fin.is_open()) return; + + char head[7]; + char ver; + + fin.read(head, 7); + fin.read(&ver, 1); + if (strcmp(head, "GB_MBC") != 0) { + fin.close(); + return; + } + + + char byte; + rtc.clear(); + for (int i = 0; i < 5; ++i) { + fin.read(&byte, 1); + rtc.push_back(byte); + } + quint64 rtc; + fin.read(reinterpret_cast(&rtc), 8); + rtczero = rtc; + + ram.clear(); + while (fin.read(&byte, 1)) { + ram.push_back(byte); + } + fin.close(); + + + calc_rtcregs(); +} + +void z80mbc3::calc_rtczero() { + time_t difftime = time(NULL); + long long days; + difftime -= rtc[0]; + difftime -= rtc[1] * 60; + difftime -= rtc[2] * 3600; + days = rtc[4] & 0x1; + days = days << 8 | rtc[3]; + difftime -= days * 3600 * 24; + rtczero = difftime; +} + +void z80mbc3::calc_rtcregs() { + if (rtc[4] & 0x40) { + return; + } + + time_t difftime = time(NULL) - rtczero; + rtc[0] = difftime % 60; + rtc[1] = (difftime / 60) % 60; + rtc[2] = (difftime / 3600) % 24; + long long days = (difftime / (3600*24)); + rtc[3] = days & 0xFF; + rtc[4] = (rtc[4] & 0xFE) | ((days >> 8) & 0x1); + + if (days >= 512) { + rtc[4] |= 0x80; + calc_rtczero(); + } +} + +/********************************/ + +z80mbc5::z80mbc5(const std::vector &rom) { + this->rom = rom; + ram.resize(0x20000); + rombank = 1; + rambank = 0; + extram_on = false; +} + +quint8 z80mbc5::readROM(quint16 address) { + if (address < 0x4000) return rom[address]; + address &= 0x3FFF; + + return rom[rombank * 0x4000 | address]; +} + +quint8 z80mbc5::readRAM(quint16 address) { + if (!extram_on) return 0; + + address &= 0x1FFF; + return ram[rambank * 0x2000 | address]; +} + +void z80mbc5::writeROM(quint16 address, quint8 value) { + switch (address & 0xF000) { + case 0x0000: + case 0x1000: + extram_on = (value == 0x0A); + break; + case 0x2000: + rombank = (rombank & 0x100) | (value); + break; + case 0x3000: + value &= 0x1; + rombank = (rombank & 0xFF) | (((int)value) << 8); + break; + case 0x4000: + case 0x5000: + rambank = value & 0x0F; + break; + } +} + +void z80mbc5::writeRAM(quint16 address, quint8 value) { + if (!extram_on) return; + + address &= 0x1FFF; + ram[rambank * 0x2000 | address] = value; +} + +void z80mbc5::save(std::string filename) { + std::ofstream fout(filename.c_str(), std::ios_base::out | std::ios_base::binary); + for (unsigned i = 0; i < ram.size(); ++i) { + fout.write((char*)&ram[i], 1); + } + fout.close(); +} + +void z80mbc5::load(std::string filename) { + std::ifstream fin(filename.c_str(), std::ios_base::in | std::ios_base::binary); + if (!fin.is_open()) return; + + char byte; + ram.clear(); + while (fin.read(&byte, 1)) { + ram.push_back(byte); + } + fin.close(); +} diff --git a/src/vendor/libqboy/z80mbc.h b/src/vendor/libqboy/z80mbc.h index 8f45f72..8c195b5 100644 --- a/src/vendor/libqboy/z80mbc.h +++ b/src/vendor/libqboy/z80mbc.h @@ -1,85 +1,85 @@ -#ifndef Z80MBC_H -#define Z80MBC_H - -#include "libqboy_global.h" - -#include -#include -#include - - -class z80mbc { -public: - virtual ~z80mbc() {} - virtual quint8 readROM(quint16 address) = 0; - virtual quint8 readRAM(quint16 address) = 0; - virtual void writeROM(quint16 address, quint8 value) = 0; - virtual void writeRAM(quint16 address, quint8 value) = 0; - virtual void save(std::string) {} - virtual void load(std::string) {} -}; - -class z80mbc0 : public z80mbc { -public: - z80mbc0(const std::vector &rom); - quint8 readROM(quint16 address); - quint8 readRAM(quint16 address); - void writeROM(quint16 address, quint8 value); - void writeRAM(quint16 address, quint8 value); -protected: - std::vector rom, ram; -}; - -class z80mbc1 : public z80mbc { -public: - z80mbc1(const std::vector &rom); - quint8 readROM(quint16 address); - quint8 readRAM(quint16 address); - void writeROM(quint16 address, quint8 value); - void writeRAM(quint16 address, quint8 value); -protected: - std::vector rom, ram; - int rombank; - int rambank; - bool extram_on; - bool ram_mode; -}; - -class z80mbc3 : public z80mbc { -public: - z80mbc3(const std::vector &rom); - quint8 readROM(quint16 address); - quint8 readRAM(quint16 address); - void writeROM(quint16 address, quint8 value); - void writeRAM(quint16 address, quint8 value); - void save(std::string filename); - void load(std::string filename); -protected: - std::vector rom, ram, rtc; - int rombank; - int rambank; - bool extram_on; - bool rtc_lock; - time_t rtczero; - - void calc_rtczero(); - void calc_rtcregs(); -}; - -class z80mbc5 : public z80mbc { -public: - z80mbc5(const std::vector &rom); - quint8 readROM(quint16 address); - quint8 readRAM(quint16 address); - void writeROM(quint16 address, quint8 value); - void writeRAM(quint16 address, quint8 value); - void save(std::string filename); - void load(std::string filename); -protected: - std::vector rom, ram; - int rombank; - int rambank; - bool extram_on; -}; - -#endif // Z80MBC_H +#ifndef Z80MBC_H +#define Z80MBC_H + +#include "libqboy_global.h" + +#include +#include +#include + + +class z80mbc { +public: + virtual ~z80mbc() {} + virtual quint8 readROM(quint16 address) = 0; + virtual quint8 readRAM(quint16 address) = 0; + virtual void writeROM(quint16 address, quint8 value) = 0; + virtual void writeRAM(quint16 address, quint8 value) = 0; + virtual void save(std::string) {} + virtual void load(std::string) {} +}; + +class z80mbc0 : public z80mbc { +public: + z80mbc0(const std::vector &rom); + quint8 readROM(quint16 address); + quint8 readRAM(quint16 address); + void writeROM(quint16 address, quint8 value); + void writeRAM(quint16 address, quint8 value); +protected: + std::vector rom, ram; +}; + +class z80mbc1 : public z80mbc { +public: + z80mbc1(const std::vector &rom); + quint8 readROM(quint16 address); + quint8 readRAM(quint16 address); + void writeROM(quint16 address, quint8 value); + void writeRAM(quint16 address, quint8 value); +protected: + std::vector rom, ram; + int rombank; + int rambank; + bool extram_on; + bool ram_mode; +}; + +class z80mbc3 : public z80mbc { +public: + z80mbc3(const std::vector &rom); + quint8 readROM(quint16 address); + quint8 readRAM(quint16 address); + void writeROM(quint16 address, quint8 value); + void writeRAM(quint16 address, quint8 value); + void save(std::string filename); + void load(std::string filename); +protected: + std::vector rom, ram, rtc; + int rombank; + int rambank; + bool extram_on; + bool rtc_lock; + time_t rtczero; + + void calc_rtczero(); + void calc_rtcregs(); +}; + +class z80mbc5 : public z80mbc { +public: + z80mbc5(const std::vector &rom); + quint8 readROM(quint16 address); + quint8 readRAM(quint16 address); + void writeROM(quint16 address, quint8 value); + void writeRAM(quint16 address, quint8 value); + void save(std::string filename); + void load(std::string filename); +protected: + std::vector rom, ram; + int rombank; + int rambank; + bool extram_on; +}; + +#endif // Z80MBC_H diff --git a/src/vendor/libqboy/z80mmu.cpp b/src/vendor/libqboy/z80mmu.cpp index befad6d..23b928d 100644 --- a/src/vendor/libqboy/z80mmu.cpp +++ b/src/vendor/libqboy/z80mmu.cpp @@ -1,193 +1,193 @@ -#include "z80mmu.h" - -#include -#include - -z80mmu::z80mmu() { - mbc = 0; - reset(); -} - -z80mmu::~z80mmu() { - if (mbc != 0) mbc->save(savefilename); -} - -void z80mmu::reset() { - wram.resize(0x2000, 0); - vram.resize(0x2000, 0); - voam.resize(0xA0, 0); - zram.resize(0x100, 0); - if (mbc != 0) delete mbc; - mbc = 0; - - zram[0x05] = 0; - zram[0x06] = 0; - zram[0x07] = 0; - zram[0x40] = 0x91; - zram[0x42] = 0; - zram[0x43] = 0; - zram[0x45] = 0; - zram[0x47] = 0xFC; - zram[0x48] = 0xFF; - zram[0x49] = 0xFF; - zram[0x4A] = 0; - zram[0x4B] = 0; - zram[0x0F] = 0; - zram[0xFF] = 0; -} - -void z80mmu::load(std::string filename) { - char byte; - std::vector rom; - std::ifstream fin(filename.c_str(), std::ios_base::in | std::ios_base::binary); - - if (!fin.is_open()) return; - - while (fin.read(&byte, 1)) { - rom.push_back(byte); - } - fin.close(); - - savefilename = filename; - savefilename.append(".gbsave"); - - quint8 mbctype = rom[0x0147]; - switch (mbctype) { - case 0x0: - mbc = new z80mbc0(rom); - break; - case 0x1: case 0x2: case 0x3: - mbc = new z80mbc1(rom); - break; - case 0xF: case 0x10: case 0x11: case 0x12: case 0x13: - mbc = new z80mbc3(rom); - break; - case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: - mbc = new z80mbc5(rom); - break; - default: - assert(false && "MBC not supported"); - break; - } - - mbc->load(savefilename); -} - -quint8 z80mmu::readbyte(quint16 address) { - switch(address & 0xF000) { - // ROM bank 0 - case 0x0000: - case 0x1000: - case 0x2000: - case 0x3000: - // ROM bank 1 - case 0x4000: - case 0x5000: - case 0x6000: - case 0x7000: - return mbc->readROM(address); - - // VRAM - case 0x8000: case 0x9000: - return vram[address & 0x1FFF]; - - // External RAM - case 0xA000: case 0xB000: - return mbc->readRAM(address); - - // Work RAM and echo - case 0xC000: case 0xD000: case 0xE000: - return wram[address & 0x1FFF]; - - // Everything else - case 0xF000: - switch(address & 0x0F00) { - // Echo RAM - case 0x000: case 0x100: case 0x200: case 0x300: - case 0x400: case 0x500: case 0x600: case 0x700: - case 0x800: case 0x900: case 0xA00: case 0xB00: - case 0xC00: case 0xD00: - return wram[address & 0x1FFF]; - - // OAM - case 0xE00: - return address < 0xFEA0 ? voam[address & 0xFF] : 0; - - // Zeropage RAM, I/O - case 0xF00: - return zram[address & 0xFF]; - - } - } - - return 0; -} - -quint16 z80mmu::readword(quint16 address) { - quint16 ret; - ret = readbyte(address + 1); - ret <<= 8; - ret |= readbyte(address); - return ret; -} - -void z80mmu::writebyte(quint16 address, quint8 value) { - switch(address & 0xF000) { - // bios and ROM bank 0 - case 0x0000: - case 0x1000: - case 0x2000: - case 0x3000: - // ROM bank 1 - case 0x4000: - case 0x5000: - case 0x6000: - case 0x7000: - mbc->writeROM(address, value); - break; - - // VRAM - case 0x8000: case 0x9000: - vram[address & 0x1FFF] = value; - break; - - // External RAM - case 0xA000: case 0xB000: - mbc->writeRAM(address, value); - break; - - // Work RAM and echo - case 0xC000: case 0xD000: case 0xE000: - wram[address & 0x1FFF] = value; - break; - - // Everything else - case 0xF000: - switch(address & 0x0F00) { - // Echo RAM - case 0x000: case 0x100: case 0x200: case 0x300: - case 0x400: case 0x500: case 0x600: case 0x700: - case 0x800: case 0x900: case 0xA00: case 0xB00: - case 0xC00: case 0xD00: - wram[address & 0x1FFF] = value; - break; - - // OAM - case 0xE00: - if(address < 0xFEA0) voam[address & 0xFF] = value; - break; - - // Zeropage RAM, I/O - case 0xF00: - zram[address & 0xFF] = value; - break; - } - - break; - } -} - -void z80mmu::writeword(quint16 address, quint16 value) { - writebyte(address, value & 0xFF); - writebyte(address + 1, value >> 8); -} +#include "z80mmu.h" + +#include +#include + +z80mmu::z80mmu() { + mbc = 0; + reset(); +} + +z80mmu::~z80mmu() { + if (mbc != 0) mbc->save(savefilename); +} + +void z80mmu::reset() { + wram.resize(0x2000, 0); + vram.resize(0x2000, 0); + voam.resize(0xA0, 0); + zram.resize(0x100, 0); + if (mbc != 0) delete mbc; + mbc = 0; + + zram[0x05] = 0; + zram[0x06] = 0; + zram[0x07] = 0; + zram[0x40] = 0x91; + zram[0x42] = 0; + zram[0x43] = 0; + zram[0x45] = 0; + zram[0x47] = 0xFC; + zram[0x48] = 0xFF; + zram[0x49] = 0xFF; + zram[0x4A] = 0; + zram[0x4B] = 0; + zram[0x0F] = 0; + zram[0xFF] = 0; +} + +void z80mmu::load(std::string filename) { + char byte; + std::vector rom; + std::ifstream fin(filename.c_str(), std::ios_base::in | std::ios_base::binary); + + if (!fin.is_open()) return; + + while (fin.read(&byte, 1)) { + rom.push_back(byte); + } + fin.close(); + + savefilename = filename; + savefilename.append(".gbsave"); + + quint8 mbctype = rom[0x0147]; + switch (mbctype) { + case 0x0: + mbc = new z80mbc0(rom); + break; + case 0x1: case 0x2: case 0x3: + mbc = new z80mbc1(rom); + break; + case 0xF: case 0x10: case 0x11: case 0x12: case 0x13: + mbc = new z80mbc3(rom); + break; + case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: + mbc = new z80mbc5(rom); + break; + default: + assert(false && "MBC not supported"); + break; + } + + mbc->load(savefilename); +} + +quint8 z80mmu::readbyte(quint16 address) { + switch(address & 0xF000) { + // ROM bank 0 + case 0x0000: + case 0x1000: + case 0x2000: + case 0x3000: + // ROM bank 1 + case 0x4000: + case 0x5000: + case 0x6000: + case 0x7000: + return mbc->readROM(address); + + // VRAM + case 0x8000: case 0x9000: + return vram[address & 0x1FFF]; + + // External RAM + case 0xA000: case 0xB000: + return mbc->readRAM(address); + + // Work RAM and echo + case 0xC000: case 0xD000: case 0xE000: + return wram[address & 0x1FFF]; + + // Everything else + case 0xF000: + switch(address & 0x0F00) { + // Echo RAM + case 0x000: case 0x100: case 0x200: case 0x300: + case 0x400: case 0x500: case 0x600: case 0x700: + case 0x800: case 0x900: case 0xA00: case 0xB00: + case 0xC00: case 0xD00: + return wram[address & 0x1FFF]; + + // OAM + case 0xE00: + return address < 0xFEA0 ? voam[address & 0xFF] : 0; + + // Zeropage RAM, I/O + case 0xF00: + return zram[address & 0xFF]; + + } + } + + return 0; +} + +quint16 z80mmu::readword(quint16 address) { + quint16 ret; + ret = readbyte(address + 1); + ret <<= 8; + ret |= readbyte(address); + return ret; +} + +void z80mmu::writebyte(quint16 address, quint8 value) { + switch(address & 0xF000) { + // bios and ROM bank 0 + case 0x0000: + case 0x1000: + case 0x2000: + case 0x3000: + // ROM bank 1 + case 0x4000: + case 0x5000: + case 0x6000: + case 0x7000: + mbc->writeROM(address, value); + break; + + // VRAM + case 0x8000: case 0x9000: + vram[address & 0x1FFF] = value; + break; + + // External RAM + case 0xA000: case 0xB000: + mbc->writeRAM(address, value); + break; + + // Work RAM and echo + case 0xC000: case 0xD000: case 0xE000: + wram[address & 0x1FFF] = value; + break; + + // Everything else + case 0xF000: + switch(address & 0x0F00) { + // Echo RAM + case 0x000: case 0x100: case 0x200: case 0x300: + case 0x400: case 0x500: case 0x600: case 0x700: + case 0x800: case 0x900: case 0xA00: case 0xB00: + case 0xC00: case 0xD00: + wram[address & 0x1FFF] = value; + break; + + // OAM + case 0xE00: + if(address < 0xFEA0) voam[address & 0xFF] = value; + break; + + // Zeropage RAM, I/O + case 0xF00: + zram[address & 0xFF] = value; + break; + } + + break; + } +} + +void z80mmu::writeword(quint16 address, quint16 value) { + writebyte(address, value & 0xFF); + writebyte(address + 1, value >> 8); +} diff --git a/src/vendor/libqboy/z80mmu.h b/src/vendor/libqboy/z80mmu.h index b8ddf2c..8eef464 100644 --- a/src/vendor/libqboy/z80mmu.h +++ b/src/vendor/libqboy/z80mmu.h @@ -1,27 +1,27 @@ -#ifndef MMU_H -#define MMU_H - -#include "libqboy_global.h" -#include "z80mbc.h" - -#include -#include - -class z80mmu { -public: - z80mmu(); - ~z80mmu(); - void reset(); - void load(std::string filename); - quint8 readbyte(quint16 address); - quint16 readword(quint16 address); - void writebyte(quint16 address, quint8 value); - void writeword(quint16 address, quint16 value); - -private: - z80mbc *mbc; - std::vector wram, vram, voam, zram; - std::string savefilename; -}; - -#endif // MMU_H +#ifndef MMU_H +#define MMU_H + +#include "libqboy_global.h" +#include "z80mbc.h" + +#include +#include + +class z80mmu { +public: + z80mmu(); + ~z80mmu(); + void reset(); + void load(std::string filename); + quint8 readbyte(quint16 address); + quint16 readword(quint16 address); + void writebyte(quint16 address, quint8 value); + void writeword(quint16 address, quint16 value); + +private: + z80mbc *mbc; + std::vector wram, vram, voam, zram; + std::string savefilename; +}; + +#endif // MMU_H diff --git a/src/vendor/libqboy/z80register.cpp b/src/vendor/libqboy/z80register.cpp index 7b9fbdf..557cc8f 100644 --- a/src/vendor/libqboy/z80register.cpp +++ b/src/vendor/libqboy/z80register.cpp @@ -1,70 +1,70 @@ -#include "z80register.h" - -z80register::z80register() { - reset(); -} - -void z80register::setaf() { - lomask = 0xF0; -} - -void z80register::reset() { - data.full = 0; - lomask = 0xFF; -} - -void z80register::setfull(quint16 val) { - data.full = val; - data.part.lo &= lomask; -} - -void z80register::setlo(quint8 val) { - data.part.lo = val; - data.part.lo &= lomask; -} - -void z80register::sethi(quint8 val) { - data.part.hi = val; -} - -quint16 z80register::getfull() { - return data.full; -} - -quint8 z80register::getlo() { - return data.part.lo; -} - -quint8 z80register::gethi() { - return data.part.hi; -} - -bool z80register::getflag(char type) { - int bit = getflagmask(type); - return data.part.lo & bit; -} - -void z80register::setflag(char type, bool val) { - int bit = getflagmask(type); - if (val) data.part.lo |= bit; - else data.part.lo &= ~bit; -} - -void z80register::operator+=(qint16 val) { - data.full += val; -} - -void z80register::operator-=(qint16 val) { - data.full -= val; -} - -int z80register::getflagmask(char type) { - switch (type) { - case 'c': return (1 << 4); - case 'h': return (1 << 5); - case 'n': return (1 << 6); - case 'z': return (1 << 7); - default: return 0; - } -} - +#include "z80register.h" + +z80register::z80register() { + reset(); +} + +void z80register::setaf() { + lomask = 0xF0; +} + +void z80register::reset() { + data.full = 0; + lomask = 0xFF; +} + +void z80register::setfull(quint16 val) { + data.full = val; + data.part.lo &= lomask; +} + +void z80register::setlo(quint8 val) { + data.part.lo = val; + data.part.lo &= lomask; +} + +void z80register::sethi(quint8 val) { + data.part.hi = val; +} + +quint16 z80register::getfull() { + return data.full; +} + +quint8 z80register::getlo() { + return data.part.lo; +} + +quint8 z80register::gethi() { + return data.part.hi; +} + +bool z80register::getflag(char type) { + int bit = getflagmask(type); + return data.part.lo & bit; +} + +void z80register::setflag(char type, bool val) { + int bit = getflagmask(type); + if (val) data.part.lo |= bit; + else data.part.lo &= ~bit; +} + +void z80register::operator+=(qint16 val) { + data.full += val; +} + +void z80register::operator-=(qint16 val) { + data.full -= val; +} + +int z80register::getflagmask(char type) { + switch (type) { + case 'c': return (1 << 4); + case 'h': return (1 << 5); + case 'n': return (1 << 6); + case 'z': return (1 << 7); + default: return 0; + } +} + diff --git a/src/vendor/libqboy/z80register.h b/src/vendor/libqboy/z80register.h index 421997c..fb330cc 100644 --- a/src/vendor/libqboy/z80register.h +++ b/src/vendor/libqboy/z80register.h @@ -1,34 +1,34 @@ -#ifndef Z80REGISTER_H -#define Z80REGISTER_H - -#include "libqboy_global.h" - -class z80register { -public: - z80register(); - void setaf(); - void reset(); - void setfull(quint16 val); - void setlo(quint8 val); - void sethi(quint8 val); - quint16 getfull(); - quint8 getlo(); - quint8 gethi(); - bool getflag(char type); - void setflag(char type, bool val); - - void operator+=(qint16 val); - void operator-=(qint16 val); -private: - union { - struct part_s { - quint8 lo; - quint8 hi; - } part; - quint16 full; - } data; - int lomask; - int getflagmask(char type); -}; - -#endif // Z80REGISTER_H +#ifndef Z80REGISTER_H +#define Z80REGISTER_H + +#include "libqboy_global.h" + +class z80register { +public: + z80register(); + void setaf(); + void reset(); + void setfull(quint16 val); + void setlo(quint8 val); + void sethi(quint8 val); + quint16 getfull(); + quint8 getlo(); + quint8 gethi(); + bool getflag(char type); + void setflag(char type, bool val); + + void operator+=(qint16 val); + void operator-=(qint16 val); +private: + union { + struct part_s { + quint8 lo; + quint8 hi; + } part; + quint16 full; + } data; + int lomask; + int getflagmask(char type); +}; + +#endif // Z80REGISTER_H diff --git a/src/vendor/libqboy/z80timer.cpp b/src/vendor/libqboy/z80timer.cpp index a900a6d..64f2825 100644 --- a/src/vendor/libqboy/z80timer.cpp +++ b/src/vendor/libqboy/z80timer.cpp @@ -1,59 +1,59 @@ -#include "z80timer.h" - -z80timer::z80timer(z80mmu *mmu) { - this->mmu = mmu; - reset(); -} - -void z80timer::reset() { - internal_counter = 0; -} - -void z80timer::step(int z80m) { - bool interrupt = false; - quint8 divider, counter, modulo, control; - - divider = mmu->readbyte(0xFF04); - counter = mmu->readbyte(0xFF05); - modulo = mmu->readbyte(0xFF06); - control = mmu->readbyte(0xFF07); - - int step = 0; - switch (control & 0x3) { - case 0: - step = 256; break; - case 1: - step = 4; break; - case 2: - step = 16; break; - case 3: - step = 64; break; - } - - internal_counter %= 256; - - for (int i = 0; i < z80m; ++i) { - internal_counter++; - if (internal_counter % _Z80TIMER_DIVIDER_STEP == 0) { - divider++; - } - - if ((control & 0x4) == 0) continue; - - if (internal_counter % step == 0) { - counter++; - if (counter == 0) { - counter = modulo; - interrupt = true; - } - } - } - - mmu->writebyte(0xFF04, divider); - mmu->writebyte(0xFF05, counter); - mmu->writebyte(0xFF06, modulo); - - if (interrupt) { - mmu->writebyte(0xFF0F, mmu->readbyte(0xFF0F) | 0x04); - } -} +#include "z80timer.h" + +z80timer::z80timer(z80mmu *mmu) { + this->mmu = mmu; + reset(); +} + +void z80timer::reset() { + internal_counter = 0; +} + +void z80timer::step(int z80m) { + bool interrupt = false; + quint8 divider, counter, modulo, control; + + divider = mmu->readbyte(0xFF04); + counter = mmu->readbyte(0xFF05); + modulo = mmu->readbyte(0xFF06); + control = mmu->readbyte(0xFF07); + + int step = 0; + switch (control & 0x3) { + case 0: + step = 256; break; + case 1: + step = 4; break; + case 2: + step = 16; break; + case 3: + step = 64; break; + } + + internal_counter %= 256; + + for (int i = 0; i < z80m; ++i) { + internal_counter++; + if (internal_counter % _Z80TIMER_DIVIDER_STEP == 0) { + divider++; + } + + if ((control & 0x4) == 0) continue; + + if (internal_counter % step == 0) { + counter++; + if (counter == 0) { + counter = modulo; + interrupt = true; + } + } + } + + mmu->writebyte(0xFF04, divider); + mmu->writebyte(0xFF05, counter); + mmu->writebyte(0xFF06, modulo); + + if (interrupt) { + mmu->writebyte(0xFF0F, mmu->readbyte(0xFF0F) | 0x04); + } +} diff --git a/src/vendor/libqboy/z80timer.h b/src/vendor/libqboy/z80timer.h index 6762e5d..674c496 100644 --- a/src/vendor/libqboy/z80timer.h +++ b/src/vendor/libqboy/z80timer.h @@ -1,19 +1,19 @@ -#ifndef Z80TIMER_H -#define Z80TIMER_H - -#include "libqboy_global.h" -#include "z80mmu.h" - -const int _Z80TIMER_DIVIDER_STEP = 64; - -class z80timer { -public: - z80timer(z80mmu *mmu); - void reset(); - void step(int z80m); -private: - z80mmu *mmu; - int internal_counter; -}; - -#endif // Z80TIMER_H +#ifndef Z80TIMER_H +#define Z80TIMER_H + +#include "libqboy_global.h" +#include "z80mmu.h" + +const int _Z80TIMER_DIVIDER_STEP = 64; + +class z80timer { +public: + z80timer(z80mmu *mmu); + void reset(); + void step(int z80m); +private: + z80mmu *mmu; + int internal_counter; +}; + +#endif // Z80TIMER_H