Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serial over Unix sockets #66

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ set(HEADERS
source/util/frame_executor.h
source/util/stream_utils.h
source/util/membuf.h
source/util/interrupt_type.h
source/util/os_specific.h
source/palette/dmg_palette.h
source/exception/state_exception.h
Expand Down
5 changes: 4 additions & 1 deletion core/source/controllers/serial.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,17 @@

#include <memory>
#include <util/typedefs.h>
#include <functional>

namespace FunkyBoy::Controller {

class SerialController {
public:
virtual ~SerialController() = default;

virtual void sendByte(u8 data) = 0;
virtual void setup(std::function<void(u8_fast)> bitReceived) = 0;
virtual void transferByte() = 0;
virtual void setByte(u8_fast byte) = 0;
};

typedef std::shared_ptr<SerialController> SerialControllerPtr;
Expand Down
10 changes: 9 additions & 1 deletion core/source/controllers/serial_null.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@

using namespace FunkyBoy::Controller;

void SerialControllerVoid::sendByte(FunkyBoy::u8 data) {
void SerialControllerVoid::setup(std::function<void(u8_fast)> bitReceived) {
// Do nothing
}

void SerialControllerVoid::setByte(FunkyBoy::u8_fast byte) {
// Do nothing
}

void SerialControllerVoid::transferByte() {

}
4 changes: 3 additions & 1 deletion core/source/controllers/serial_null.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ namespace FunkyBoy::Controller {

class SerialControllerVoid: public SerialController {
public:
void sendByte(u8 data) override;
void setup(std::function<void(u8_fast)> bitReceived) override;
void transferByte() override;
void setByte(u8_fast byte) override;
};

}
Expand Down
10 changes: 2 additions & 8 deletions core/source/emulator/cpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ ret_code CPU::doCycle(Memory &memory) {
ret_code result = FB_RET_SUCCESS;

if (instrContext.cpuState == CPUState::RUNNING) {
memory.doDMA(); // TODO: Implement delay of 2 clocks
memory.onTick(); // TODO: Implement delay of 2 clocks

auto op = *operands;

Expand Down Expand Up @@ -225,10 +225,6 @@ inline memory_address getInterruptStartAddress(InterruptType type) {
return 0x0040 + (static_cast<u8>(type) * 0x8);
}

inline u8 getInterruptBitMask(InterruptType type) {
return 1u << static_cast<u8>(type);
}

void CPU::doJoypad() {
u8_fast oldP1 = ioRegisters.getP1() & 0b00001111u;
u8_fast newP1 = ioRegisters.updateJoypad() & 0b00001111u;
Expand Down Expand Up @@ -351,9 +347,7 @@ void CPU::doTimers(Memory &memory, u8 clocks) {
}

void CPU::requestInterrupt(InterruptType type) {
//fprintf(stdout, "#req int %d\n", type);
u8 &_if = ioRegisters.getIF();
_if |= getInterruptBitMask(type);
ioRegisters.requestInterrupt(type);
}

void CPU::setProgramCounter(u16 offset) {
Expand Down
9 changes: 1 addition & 8 deletions core/source/emulator/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <iostream>
#include <util/testing.h>
#include <util/debug.h>
#include <util/interrupt_type.h>
#include <operands/instruction_context.h>
#include <operands/debug.h>
#include <emulator/gb_type.h>
Expand All @@ -34,14 +35,6 @@

namespace FunkyBoy {

enum InterruptType {
VBLANK = 0,
LCD_STAT = 1,
TIMER = 2,
SERIAL = 3,
JOYPAD = 4
};

class CPU {
private:
io_registers ioRegisters;
Expand Down
13 changes: 13 additions & 0 deletions core/source/emulator/io_registers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@
#include <exception/read_exception.h>
#include <util/stream_utils.h>

namespace FunkyBoy {

inline u8 getInterruptBitMask(InterruptType type) {
return 1u << static_cast<u8>(type);
}

}

using namespace FunkyBoy;

#define FB_HW_IO_BYTES 128
Expand Down Expand Up @@ -173,6 +181,11 @@ u8_fast io_registers::updateJoypad() {
return val;
}

void io_registers::requestInterrupt(InterruptType type) {
u8 &_if = getIF();
_if |= getInterruptBitMask(type);
}

void io_registers::serialize(std::ostream &ostream) const {
ostream.write(reinterpret_cast<const char*>(hwIO), FB_HW_IO_BYTES);
ostream.put(*inputsDPad & 0xffu);
Expand Down
14 changes: 14 additions & 0 deletions core/source/emulator/io_registers.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include <util/typedefs.h>
#include <util/testing.h>
#include <util/interrupt_type.h>
#include <controllers/controllers.h>
#include <util/gpumode.h>

Expand Down Expand Up @@ -71,6 +72,8 @@
#define __FB_REG_OFFSET_WAVE_RAM_START (FB_REG_WAVE_RAM_START - 0xFF00)

#define __FB_REG_OFFSET_P1 (FB_REG_P1 - 0xFF00)
#define __FB_REG_OFFSET_SB (FB_REG_SB - 0xFF00)
#define __FB_REG_OFFSET_SC (FB_REG_SC - 0xFF00)
#define __FB_REG_OFFSET_DIV (FB_REG_DIV - 0xFF00)
#define __FB_REG_OFFSET_TIMA (FB_REG_TIMA - 0xFF00)
#define __FB_REG_OFFSET_TMA (FB_REG_TMA - 0xFF00)
Expand Down Expand Up @@ -132,14 +135,25 @@ namespace FunkyBoy {

u8_fast updateJoypad();

void requestInterrupt(InterruptType type);

inline u8 *getWaveRAM() {
return hwIO + __FB_REG_OFFSET_WAVE_RAM_START;
}


inline u8 &getP1() {
return *(hwIO + __FB_REG_OFFSET_P1);
}

inline u8 &getSB() {
return *(hwIO + __FB_REG_OFFSET_SB);
}

inline u8 &getSC() {
return *(hwIO + __FB_REG_OFFSET_SC);
}

inline u8_fast getDIV() {
return *sys_counter >> 8;
}
Expand Down
51 changes: 42 additions & 9 deletions core/source/memory/memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ Memory::Memory(
#ifdef FB_USE_AUTOSAVE
, cartridgeRAMWritten(false)
#endif
, serialTransferClocks(-2)
, receivedByte(-1)
{
internalRam = new u8[FB_INTERNAL_RAM_SIZE]{};
hram = new u8[FB_HRAM_SIZE]{};
Expand Down Expand Up @@ -109,6 +111,12 @@ void Memory::init() {
}

void Memory::loadROM(std::istream &stream, bool strictSizeCheck) {
controllers->getSerial()->setup([&](u8_fast data) {
std::cout << "Received data: " << (data & 0xFFFF) << std::endl;
receivedByte = data;
serialTransferClocks = 7;
});

if (!stream.good()) {
#ifdef FB_DEBUG
fprintf(stderr, "Stream is not readable\n");
Expand Down Expand Up @@ -488,9 +496,11 @@ void Memory::write8BitsTo(memory_address offset, u8 val) {
if (offset < 0xFF80) {
// IO registers

if (offset == FB_REG_SC) {
if (val == 0x81) {
controllers->getSerial()->sendByte(read8BitsAt(FB_REG_SB));
if (offset == FB_REG_SB) {
controllers->getSerial()->setByte(val);
} else if (offset == FB_REG_SC) {
if ((val & 0b10000001) == 0b10000001) {
controllers->getSerial()->transferByte();
}
} else if (offset == FB_REG_DMA) {
dmaStarted = true;
Expand Down Expand Up @@ -519,14 +529,37 @@ void Memory::write8BitsTo(memory_address offset, u8 val) {
}
}

void Memory::doDMA() {
if (!dmaStarted) {
return;
void Memory::onTick() {
if (dmaStarted) {
ppuMemory.getOAMByte(dmaLsb) = read8BitsAt(Util::compose16Bits(dmaLsb, dmaMsb));
if (++dmaLsb > 0x9F) {
dmaStarted = false;
}
}
ppuMemory.getOAMByte(dmaLsb) = read8BitsAt(Util::compose16Bits(dmaLsb, dmaMsb));
if (++dmaLsb > 0x9F) {
dmaStarted = false;
if (serialTransferClocks > -2) {
if (serialTransferClocks == -1 || (serialTransferClocks > -1 && --serialTransferClocks == -1)) {
handleReceivedByte();
}
}
}

void Memory::handleReceivedByte() {
if (receivedByte < 0) {
return;
}

/*u8 &sb = ioRegisters.getSB();
sb = (sb << 1) | (receivedByte & 0b1);*/
ioRegisters.getSB() = receivedByte;

u8 &sc = ioRegisters.getSC();
sc &= 0b01111111;

receivedByte = -1;
serialTransferClocks = -2;

fprintf(stdout, "[INTR] Serial\n");
ioRegisters.requestInterrupt(InterruptType::SERIAL);
}

void Memory::serialize(std::ostream &ostream) const {
Expand Down
7 changes: 6 additions & 1 deletion core/source/memory/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ namespace FunkyBoy {
// Do not free these pointers, they are proxies to the ones above:
u8 *dynamicRamBank;

int serialTransferClocks;
int_fast16_t receivedByte;

void handleReceivedByte();

test_public:
u8 *rom;
u8 *cram;
Expand Down Expand Up @@ -102,7 +107,7 @@ namespace FunkyBoy {

void write8BitsTo(memory_address offset, u8 val);

void doDMA();
void onTick();

inline u8 getIE() {
return interruptEnableRegister;
Expand Down
32 changes: 32 additions & 0 deletions core/source/util/interrupt_type.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* Copyright 2021 Michel Kremer (kremi151)
*
* Licensed under the Apache License, Version 2.0 (the License);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef FB_CORE_INTERRUPT_TYPE_H
#define FB_CORE_INTERRUPT_TYPE_H

namespace FunkyBoy {

enum InterruptType {
VBLANK = 0,
LCD_STAT = 1,
TIMER = 2,
SERIAL = 3,
JOYPAD = 4
};

}

#endif //FB_CORE_INTERRUPT_TYPE_H
45 changes: 40 additions & 5 deletions platform-sdl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ set(HEADERS
source/controllers/audio_sdl.h
source/ui/native_ui.h
source/window/window.h
source/cli/config.h
)

set(DARWIN_SOURCES
Expand Down Expand Up @@ -71,15 +72,47 @@ elseif(OS_LINUX)
message(FATAL_ERROR "X11 was not found")
endif()

# Check whether we can use sys/socket.h
string(CONFIGURE [[
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>

int main() {
sockaddr addr;
sockaddr_in sockaddr;
return 0;
}
]] code @ONLY)
check_cxx_source_compiles("${code}" CAN_COMPILE_BSD_SOCKET_API_H)
if (CAN_COMPILE_BSD_SOCKET_API_H)
set(SOURCES
${SOURCES}
source/sockets/bsd_common.cpp
source/sockets/bsd_server.cpp
source/sockets/bsd_client.cpp
source/sockets/socket_exception.cpp
)
set(HEADERS
${HEADERS}
source/sockets/socket_interface.h
source/sockets/bsd_common.h
source/sockets/bsd_server.h
source/sockets/bsd_client.h
source/sockets/socket_exception.h
)
endif()

if (OS_MACOS)
add_executable(fb_sdl MACOSX_BUNDLE ${SOURCES} ${HEADERS})

set_target_properties(fb_sdl PROPERTIES
BUNDLE True
MACOSX_BUNDLE_GUI_IDENTIFIER lu.kremi151.funkyboy.sdl
MACOSX_BUNDLE_BUNDLE_NAME ${FB_NAME}
MACOSX_BUNDLE_BUNDLE_VERSION ${FB_VERSION_MAJOR}.${FB_VERSION_MINOR}.${FB_VERSION_PATCH}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${FB_VERSION}
BUNDLE True
MACOSX_BUNDLE_GUI_IDENTIFIER lu.kremi151.funkyboy.sdl
MACOSX_BUNDLE_BUNDLE_NAME ${FB_NAME}
MACOSX_BUNDLE_BUNDLE_VERSION ${FB_VERSION_MAJOR}.${FB_VERSION_MINOR}.${FB_VERSION_PATCH}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${FB_VERSION}
)
else()
add_executable(fb_sdl ${SOURCES} ${HEADERS})
Expand All @@ -104,6 +137,8 @@ if (OS_MACOS)
set_source_files_properties(${DARWIN_SOURCES} PROPERTIES COMPILE_FLAGS "-x objective-c++")
endif()

target_compile_definitions(fb_sdl PUBLIC -DFB_HAS_SOCKETS=$<BOOL:${CAN_COMPILE_BSD_SOCKET_API_H}>)

target_link_libraries(fb_sdl fb_core ${FB_EXTERNAL_LIBS})

fb_use_autosave(fb_core)
Expand Down
Loading