diff --git a/.gitignore b/.gitignore index e9ebc7d..674985d 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,7 @@ rom/ dumpinfo testserial wonderswan + +# Build folder +cmake-*/ +build*/ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..9a4e00b --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "external/portaudio"] + path = external/portaudio + url = https://git.assembla.com/portaudio.git +[submodule "external/glfw"] + path = external/glfw + url = https://github.com/glfw/glfw.git diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..62f718b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,38 @@ +dist: bionic +language: c +os: + - linux +# - osx +#matrix: +# allow_failures: +# - os: osx + +addons: + apt: + packages: + - libsdl1.2debian + - libsdl1.2-dev + +compiler: + - clang + - gcc + +script: + - make + - mkdir build + - cd build + - cmake .. + - make + +cache: + directories: + - '$HOME/.sonar/cache' + +#before_install: +# - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi +# - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install glew; fi + +#install: true + +#after_success: +# - bash <(curl -s https://codecov.io/bash) diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..ea3f693 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,43 @@ +cmake_minimum_required(VERSION 3.1) + +# External cmake modules +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/external/cmake ${CMAKE_MODULE_PATH}) + +project("NewOswan") + +include(GetGitRevisionDescription) +git_describe(VERSION --tags --dirty=-dirty) + +# Include GLFW3 +set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE) +set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE) +set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) +add_subdirectory("external/glfw") +find_package(OpenGL REQUIRED) + +include_directories(${OPENGL_INCLUDE_DIR}) + +option(WARN_AS_ERROR "Enable warning as error" OFF) + +set(COMP_FLAGS "-march=native -Wall -Wextra -Wno-unused-parameter -Wno-unused-result -Wno-write-strings") +if (WARN_AS_ERROR) + set(COMP_FLAGS "${COMP_FLAGS} -Werror") +endif() + +set(CMAKE_C_FLAGS ${COMP_FLAGS}) +set(CMAKE_CXX_FLAGS ${COMP_FLAGS}) + +message("-- Building version ${VERSION}") + +add_executable(wonderswan main.cpp) + +set_property(TARGET wonderswan PROPERTY CXX_STANDARD 98) + +target_compile_definitions(wonderswan PUBLIC VERSION="${VERSION}") +target_include_directories(wonderswan PUBLIC source) + +add_subdirectory(source) + +target_link_libraries(wonderswan wswan glfw ${OPENGL_glu_LIBRARY} ${OPENGL_gl_LIBRARY}) + +add_executable(dumpinfo dumpinfo.c) \ No newline at end of file diff --git a/Makefile b/Makefile index b69208f..62f72a7 100644 --- a/Makefile +++ b/Makefile @@ -16,12 +16,13 @@ OBJS = $(wonderswan_CXX_SRCS:.cpp=.o) all: wonderswan dumpinfo -CXX = g++ -CXXFLAGS = -g -O2 `sdl-config --cflags` -Wall -Werror -std=c++98 -Wno-write-strings +# CXX = g++ +CXXFLAGS = -g -O2 `sdl-config --cflags` -Wall -std=c++98 -Wno-write-strings -Wno-unused-result OPTIONS = -D_REENTRANT -I. -DVERSION=\"`git describe --tags --long --dirty`\" LIBRARY_PATH = -LIBS = -g $(LIBRARY_PATH) `sdl-config --libs` +SDL_LIBS = `sdl-config --libs` +LIBS = -g $(LIBRARY_PATH) $(SDL_LIBS) ALLCFLAGS = $(CFLAGS) $(CEXTRA) $(OPTIONS) $(ALLFLAGS) ALLCXXFLAGS=$(CXXFLAGS) $(CXXEXTRA) $(OPTIONS) $(ALLFLAGS) @@ -53,4 +54,4 @@ dumpinfo: dumpinfo.o $(CXX) $(LIBS) -o $@ $(<) wonderswan: $(OBJS) - $(CXX) $(LIBS) -o $@ $(OBJS) + $(CXX) -o $@ $(OBJS) $(LIBS) diff --git a/external/cmake/GetGitRevisionDescription.cmake b/external/cmake/GetGitRevisionDescription.cmake new file mode 100644 index 0000000..0a6cb5f --- /dev/null +++ b/external/cmake/GetGitRevisionDescription.cmake @@ -0,0 +1,168 @@ +# - Returns a version string from Git +# +# These functions force a re-configure on each git commit so that you can +# trust the values of the variables in your build system. +# +# get_git_head_revision( [ ...]) +# +# Returns the refspec and sha hash of the current head revision +# +# git_describe( [ ...]) +# +# Returns the results of git describe on the source tree, and adjusting +# the output so that it tests false if an error occurs. +# +# git_get_exact_tag( [ ...]) +# +# Returns the results of git describe --exact-match on the source tree, +# and adjusting the output so that it tests false if there was no exact +# matching tag. +# +# git_local_changes() +# +# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes. +# Uses the return code of "git diff-index --quiet HEAD --". +# Does not regard untracked files. +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +if(__get_git_revision_description) + return() +endif() +set(__get_git_revision_description YES) + +# We must run the following at "include" time, not at function call time, +# to find the path to this module rather than the path to a calling list file +get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) + +function(get_git_head_revision _refspecvar _hashvar) + set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + set(GIT_DIR "${GIT_PARENT_DIR}/.git") + while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories + set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}") + get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH) + if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT) + # We have reached the root directory, we are not in git + set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE) + set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE) + return() + endif() + set(GIT_DIR "${GIT_PARENT_DIR}/.git") + endwhile() + # check if this is a submodule + if(NOT IS_DIRECTORY ${GIT_DIR}) + file(READ ${GIT_DIR} submodule) + string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule}) + get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH) + get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE) + endif() + set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") + if(NOT EXISTS "${GIT_DATA}") + file(MAKE_DIRECTORY "${GIT_DATA}") + endif() + + if(NOT EXISTS "${GIT_DIR}/HEAD") + return() + endif() + set(HEAD_FILE "${GIT_DATA}/HEAD") + configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY) + + configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" + "${GIT_DATA}/grabRef.cmake" + @ONLY) + include("${GIT_DATA}/grabRef.cmake") + + set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE) + set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE) +endfunction() + +function(git_describe _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + get_git_head_revision(refspec hash) + if(NOT GIT_FOUND) + set(${_var} "GIT-NOTFOUND" PARENT_SCOPE) + return() + endif() + if(NOT hash) + set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) + return() + endif() + + # TODO sanitize + #if((${ARGN}" MATCHES "&&") OR + # (ARGN MATCHES "||") OR + # (ARGN MATCHES "\\;")) + # message("Please report the following error to the project!") + # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") + #endif() + + #message(STATUS "Arguments to execute_process: ${ARGN}") + + execute_process(COMMAND + "${GIT_EXECUTABLE}" + describe + #${hash} + ${ARGN} + WORKING_DIRECTORY + "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE + res + OUTPUT_VARIABLE + out + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT res EQUAL 0) + set(out "${out}-${res}-NOTFOUND") + endif() + + set(${_var} "${out}" PARENT_SCOPE) +endfunction() + +function(git_get_exact_tag _var) + git_describe(out --exact-match ${ARGN}) + set(${_var} "${out}" PARENT_SCOPE) +endfunction() + +function(git_local_changes _var) + if(NOT GIT_FOUND) + find_package(Git QUIET) + endif() + get_git_head_revision(refspec hash) + if(NOT GIT_FOUND) + set(${_var} "GIT-NOTFOUND" PARENT_SCOPE) + return() + endif() + if(NOT hash) + set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) + return() + endif() + + execute_process(COMMAND + "${GIT_EXECUTABLE}" + diff-index --quiet HEAD -- + WORKING_DIRECTORY + "${CMAKE_CURRENT_SOURCE_DIR}" + RESULT_VARIABLE + res + OUTPUT_VARIABLE + out + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(res EQUAL 0) + set(${_var} "CLEAN" PARENT_SCOPE) + else() + set(${_var} "DIRTY" PARENT_SCOPE) + endif() +endfunction() diff --git a/external/cmake/GetGitRevisionDescription.cmake.in b/external/cmake/GetGitRevisionDescription.cmake.in new file mode 100644 index 0000000..6d8b708 --- /dev/null +++ b/external/cmake/GetGitRevisionDescription.cmake.in @@ -0,0 +1,41 @@ +# +# Internal file for GetGitRevisionDescription.cmake +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +set(HEAD_HASH) + +file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) + +string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) +if(HEAD_CONTENTS MATCHES "ref") + # named branch + string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") + if(EXISTS "@GIT_DIR@/${HEAD_REF}") + configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) + else() + configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY) + file(READ "@GIT_DATA@/packed-refs" PACKED_REFS) + if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}") + set(HEAD_HASH "${CMAKE_MATCH_1}") + endif() + endif() +else() + # detached HEAD + configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) +endif() + +if(NOT HEAD_HASH) + file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) + string(STRIP "${HEAD_HASH}" HEAD_HASH) +endif() diff --git a/external/glfw b/external/glfw new file mode 160000 index 0000000..0ef149c --- /dev/null +++ b/external/glfw @@ -0,0 +1 @@ +Subproject commit 0ef149c8f2451fbc8e866834675a075cfc295b6c diff --git a/external/portaudio b/external/portaudio new file mode 160000 index 0000000..c5d2c51 --- /dev/null +++ b/external/portaudio @@ -0,0 +1 @@ +Subproject commit c5d2c51bd6fe354d0ee1119ba932bfebd3ebfacc diff --git a/main.cpp b/main.cpp index 5665cd6..52fca57 100644 --- a/main.cpp +++ b/main.cpp @@ -15,8 +15,6 @@ #include #include #include -#include "SDL.h" -#include "source/SDLptc.h" #include "source/log.h" #include "source/rom.h" #include "source/nec/nec.h" @@ -123,9 +121,6 @@ int ws_mk_ieppath() int main(int argc, char *argv[]) { - atexit(SDL_Quit); - SDL_Init(SDL_INIT_TIMER); - if (!log_init(LOG_PATH)) { printf("Warning: cannot open log file %s\n",LOG_PATH); diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt new file mode 100644 index 0000000..1fdb108 --- /dev/null +++ b/source/CMakeLists.txt @@ -0,0 +1,10 @@ +set(SOURCES audio.cpp emulate.cpp gpu.cpp io.cpp log.cpp memory.cpp rom.cpp ws.cpp) +set(HEADERS audio.h emulate.h gpu.h ieeprom.h initialIo.h io.h log.h memory.h rom.h ws.h) + +add_library(wswan ${SOURCES} ${HEADERS}) + +target_link_libraries(wswan nec_v30 glfw ${OPENGL_glu_LIBRARY} ${OPENGL_gl_LIBRARY}) + +target_include_directories(wswan PUBLIC .) + +add_subdirectory(nec) \ No newline at end of file diff --git a/source/SDLptc.h b/source/SDLptc.h deleted file mode 100644 index bdee461..0000000 --- a/source/SDLptc.h +++ /dev/null @@ -1,314 +0,0 @@ - -/* Some simple emulation classes to get PTC code running on SDL */ - -#include -#include -#include - -#include "SDL.h" - -#define randomize() srand(time(NULL)) -#define random(max) (rand()%(max)) - -#ifndef stricmp -#define stricmp strcasecmp -#endif - -class Error -{ - -public: - Error(const char *message) - { - strcpy(_message, message); - } - - void report(void) - { - printf("Error: %s\n", _message); - } - -private: - - char _message[1024]; -}; - -class Area -{ - -public: - Area(int left, int top, int right, int bottom) - { - _left = left; - _top = top; - _right = right; - _bottom = bottom; - } - - int left(void) const - { - return(_left); - } - int right(void) const - { - return(_right); - } - int top(void) const - { - return(_top); - } - int bottom(void) const - { - return(_bottom); - } - int width(void) const - { - return(_right-_left); - } - int height(void) const - { - return(_bottom-_top); - } - -private: - int _left, _top, _right, _bottom; -}; - - -class Format -{ - -public: - Format(int bpp, int maskR = 0, int maskG = 0, int maskB = 0) - { - _bpp = bpp; - _maskR = maskR; - _maskG = maskG; - _maskB = maskB; - } - - Uint8 BPP(void) const - { - return(_bpp); - } - Uint32 MaskR(void) const - { - return(_maskR); - } - Uint32 MaskG(void) const - { - return(_maskG); - } - Uint32 MaskB(void) const - { - return(_maskB); - } - -private: - Uint8 _bpp; - Uint32 _maskR, _maskG, _maskB; -}; - -class Surface -{ - -public: - Surface(int w, int h, const Format &format) - { - surface = SDL_AllocSurface(SDL_SWSURFACE, w, h, format.BPP(), - format.MaskR(),format.MaskG(),format.MaskB(),0); - - if ( surface == NULL ) - { - throw Error(SDL_GetError()); - } - - nupdates = 0; - is_console = 0; - } - Surface(void) - { - nupdates = 0; - is_console = 1; - } - virtual ~Surface() - { - if ( ! is_console ) - { - SDL_FreeSurface(surface); - } - } - - virtual int width(void) - { - return surface->w; - } - virtual int height(void) - { - return surface->h; - } - virtual int pitch(void) - { - return surface->pitch; - } - - virtual void palette(int32_t *pcolors) - { - SDL_Color colors[256]; - - for ( int i=0; i<256; ++i ) - { - colors[i].r = (pcolors[i]>>16)&0xFF; - colors[i].g = (pcolors[i]>>8)&0xFF; - colors[i].b = (pcolors[i]>>0)&0xFF; - } - - SDL_SetColors(surface, colors, 0, 256); - } - - virtual void *lock(void) - { - if ( SDL_MUSTLOCK(surface) ) - { - while ( SDL_LockSurface(surface) < 0 ) - { - SDL_Delay(10); - } - } - - return (Uint8 *)surface->pixels; - } - - virtual void unlock(void) - { - if ( SDL_MUSTLOCK(surface) ) - { - SDL_UnlockSurface(surface); - } - } - - virtual void copy(Surface &dst, - const Area &srcarea, const Area &dstarea) - { - SDL_Rect srcrect, dstrect; - srcrect.x = srcarea.left(); - srcrect.y = srcarea.top(); - srcrect.w = srcarea.width(); - srcrect.h = srcarea.height(); - dstrect.x = dstarea.left(); - dstrect.y = dstarea.top(); - dstrect.w = dstarea.width(); - dstrect.h = dstarea.height(); - SDL_BlitSurface(surface, &srcrect, dst.surface, &dstrect); - dst.updates[dst.nupdates++] = dstrect; - } - virtual void copy(Surface &dst) - { - SDL_Rect srcrect, dstrect; - srcrect.x = 0; - srcrect.y = 0; - srcrect.w = surface->w; - srcrect.h = surface->h; - dstrect.x = 0; - dstrect.y = 0; - dstrect.w = surface->w; - dstrect.h = surface->h; - SDL_LowerBlit(surface, &srcrect, dst.surface, &dstrect); - dst.updates[dst.nupdates++] = dstrect; - } - - virtual void update(void) - { - SDL_UpdateRects(surface, nupdates, updates); - nupdates = 0; - } - -protected: - SDL_Surface *surface; - int nupdates; - SDL_Rect updates[1]; /* Definitely increase this.. */ - int is_console; -}; - -class Console : public Surface -{ - int fullscreen; -public: - Console() : Surface() - { - fullscreen=0; - } - ~Console() - { - - SDL_Quit(); - } - void close(void) - { - SDL_Quit(); - } - void option(char *option) - { - if (!stricmp(option,"fullscreen output")) - { - fullscreen=1; - } - else if (!stricmp(option,"windowed output")) - { - fullscreen=0; - } - } - void open(const char *title, int width, int height, const Format &format) - { - uint32_t flags; - - if ( SDL_InitSubSystem(SDL_INIT_VIDEO|SDL_INIT_JOYSTICK) < 0 ) - { - throw Error(SDL_GetError()); - } - - flags = (SDL_HWSURFACE|SDL_HWPALETTE); - - if (fullscreen) - { - flags|=SDL_FULLSCREEN; - } - - surface = SDL_SetVideoMode(width, height, 0, flags); - - if ( surface == NULL ) - { - throw Error(SDL_GetError()); - } - - SDL_WM_SetCaption(title, title); - } - - int key(void) - { - SDL_Event event; - int keyevent; - - keyevent = 0; - - while ( SDL_PollEvent(&event) ) - { - /* Real key events trigger this function */ - if ( event.type == SDL_KEYDOWN ) - { - keyevent = 1; - } - - /* So do quit events -- let the app know about it */ - if ( event.type == SDL_QUIT ) - { - keyevent = 1; - } - } - - return(keyevent); - } - -private: - -}; diff --git a/source/audio.cpp b/source/audio.cpp index 120713f..739a4c9 100644 --- a/source/audio.cpp +++ b/source/audio.cpp @@ -29,8 +29,6 @@ #include "io.h" #include "audio.h" -#include "SDL.h" - #define SNDP ws_ioRam[0x80] #define SNDV ws_ioRam[0x88] #define SNDSWP ws_ioRam[0x8C] @@ -91,6 +89,7 @@ int RandData[BUFSIZEN]; int CntSwp=0; int PcmWrPos=0; +/* const long TblChVol[16]= // n/15 n=0~15 { -10000,-2352,-1750,-1398,-1148,-954,-796,-662, @@ -101,6 +100,7 @@ const long TblMainVol[4]= // 1,1/2,1/4,1/8 { 0,-602,-1204,-1806 }; +*/ //////////////////////////////////////////////////////////////////////////////// // seal audio specific @@ -142,7 +142,6 @@ void ws_audio_init(void) ws_audio_log=0; //ws_audio_seal_init(); ws_audio_reset(); - SDL_PauseAudio(0); } //////////////////////////////////////////////////////////////////////////////// // diff --git a/source/emulate.cpp b/source/emulate.cpp index 1d57121..9557a79 100644 --- a/source/emulate.cpp +++ b/source/emulate.cpp @@ -19,9 +19,16 @@ #include /* Error number definitions */ #include /* POSIX terminal control definitions */ #include +#include + +#define GLFW_INCLUDE_GLEXT +#define GL_SILENCE_DEPRECATION +#include +/* "Apple" fix */ +#ifndef GL_TEXTURE_RECTANGLE +#define GL_TEXTURE_RECTANGLE GL_TEXTURE_RECTANGLE_EXT +#endif -#include "SDL.h" -#include "SDLptc.h" #include "log.h" #include "io.h" #include "ws.h" @@ -32,336 +39,308 @@ #include "audio.h" #include "memory.h" -SDL_Joystick *joystick=NULL; char app_window_title[256]; int app_gameRunning=0; int app_terminate=0; int app_fullscreen=0; -SDL_Event app_input_event; int app_rotated=0; int ws_key_esc = 0; +/* Open GL stuffs */ +typedef struct GLWindow_t GLWindow; +struct KeyArray +{ + uint8_t lastState; + uint8_t curState; + uint8_t debounced; + GLFWwindow *window; +}; +struct GLWindow_t +{ + struct KeyArray keyArray[512]; + GLFWwindow *windows; + uint8_t *videoMemory; + GLuint videoTexture; + int WIDTH; + int HEIGHT; +}; +static GLWindow mainWindow; +static int window_num = 0; +static void ShowScreen(GLWindow *g, int w, int h) +{ + glBindTexture(GL_TEXTURE_RECTANGLE, g->videoTexture); + + // glTexSubImage2D is faster when not using a texture range + glTexSubImage2D(GL_TEXTURE_RECTANGLE, 0, 0, 0, w, h, + GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, g->videoMemory); + glBegin(GL_QUADS); + + glTexCoord2f(0.0f, 0.0f); + glVertex2f(-1.0f, 1.0f); + + glTexCoord2f(0.0f, h); + glVertex2f(-1.0f, -1.0f); + + glTexCoord2f(w, h); + glVertex2f(1.0f, -1.0f); + + glTexCoord2f(w, 0.0f); + glVertex2f(1.0f, 1.0f); + glEnd(); + + glFlush(); +} +static void GLWindowInitEx(GLWindow *g, int w, int h) +{ + g->WIDTH = w; + g->HEIGHT = h; + g->videoTexture = window_num++; +} +static void setupGL(GLWindow *g, int w, int h) +{ + g->videoMemory = (uint8_t *)malloc(w * h * sizeof(uint16_t)); + memset(g->videoMemory, 0, w * h * sizeof(uint16_t)); + //Tell OpenGL how to convert from coordinates to pixel values + glViewport(0, 0, w, h); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glClearColor(1.0f, 0.f, 1.0f, 1.0f); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glDisable(GL_TEXTURE_2D); + glEnable(GL_TEXTURE_RECTANGLE); + glBindTexture(GL_TEXTURE_RECTANGLE, g->videoTexture); + + // glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_NV_EXT, 0, NULL); + + // glTexParameteri(GL_TEXTURE_RECTANGLE_NV_EXT, GL_TEXTURE_STORAGE_HINT_APPLE , GL_STORAGE_CACHED_APPLE); + // glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); + glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + + glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, g->videoMemory); + + glDisable(GL_DEPTH_TEST); +} +void restoreGL(GLWindow *g) +{ + //Tell OpenGL how to convert from coordinates to pixel values + glViewport(0, 0, g->WIDTH, g->HEIGHT); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glClearColor(1.0f, 0.f, 1.0f, 1.0f); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glDisable(GL_TEXTURE_2D); + glEnable(GL_TEXTURE_RECTANGLE); + glDisable(GL_DEPTH_TEST); +} +static void kbHandler(GLFWwindow *window, int key, int scan, int action, int mod) +{ + struct KeyArray *keyArray; + + keyArray = (struct KeyArray *)glfwGetWindowUserPointer(window); + + keyArray[key].lastState = keyArray[key].curState; + if (action == GLFW_RELEASE) + { + keyArray[key].curState = GLFW_RELEASE; + } + else + { + keyArray[key].curState = GLFW_PRESS; + } + keyArray[key].debounced |= (keyArray[key].lastState == GLFW_RELEASE) && (keyArray[key].curState == GLFW_PRESS); + keyArray[key].window = window; + /*printf("key:%d, state:%d debounce:%d, laststate:%d\n", key, keyArray[key].curState, + keyArray[key].debounced, keyArray[key].lastState);*/ +} +static void sizeHandler(GLFWwindow *window, int xs, int ys) +{ + glfwMakeContextCurrent(window); + glViewport(0, 0, xs, ys); + ShowScreen(&mainWindow, 244, 144); +} +static void error_callback(int error, const char *description) +{ + puts(description); +} +static void initDisplay(GLWindow *g) +{ + int h = g->HEIGHT; + int w = g->WIDTH; + + /// Initialize GLFW + glfwInit(); + + glfwSetErrorCallback(error_callback); + + // Open screen OpenGL window + if (!(g->windows = glfwCreateWindow(g->WIDTH, g->HEIGHT, "Main", NULL, NULL))) + { + glfwTerminate(); + fprintf(stderr, "Window creation error...\n"); + abort(); + } + + glfwSetWindowAspectRatio(g->windows, 244, 144); + + glfwMakeContextCurrent(g->windows); + setupGL(g, g->WIDTH, g->HEIGHT); + + glfwSwapInterval(1); // We need vsync + + glfwGetWindowSize(g->windows, &w, &h); + + glfwSetWindowUserPointer(g->windows, g->keyArray); + + glfwSetKeyCallback(g->windows, kbHandler); + glfwSetWindowSizeCallback(g->windows, sizeHandler); +} +static void clearScreen(GLWindow *g) +{ + memset(g->videoMemory, 0, sizeof(uint8_t) * g->WIDTH * g->HEIGHT * 4); +} +static void updateScreen(GLWindow *g) +{ + /* Update windows code */ + glfwMakeContextCurrent(g->windows); + ShowScreen(g, g->WIDTH, g->HEIGHT); + glfwSwapBuffers(g->windows); + glfwPollEvents(); +} +uint64_t getTicks() +{ + struct timeval curTime; + uint64_t ticks; + /* Get datetime */ + gettimeofday(&curTime, NULL); + + ticks = (curTime.tv_sec* 1000) + curTime.tv_usec / 1000; + + return ticks; +} + +static inline int getKeyState(int key) +{ + return mainWindow.keyArray[key].curState; +} static void read_keys() { - static int testJoystick=1; + ws_key_start=0; + ws_key_x4=0; + ws_key_x2=0; + ws_key_x1=0; + ws_key_x3=0; + ws_key_y4=0; + ws_key_y2=0; + ws_key_y1=0; + ws_key_y3=0; + ws_key_button_a=0; + ws_key_button_b=0; - if (testJoystick==1) - { - testJoystick=0; - fprintf(log_get(),"%i joysticks were found.\n\n", SDL_NumJoysticks() ); - fprintf(log_get(),"The names of the joysticks are:\n"); - - for(int tti=0; tti < SDL_NumJoysticks(); tti++ ) - { - fprintf(log_get()," %s\n", SDL_JoystickName(tti)); - } - - SDL_JoystickEventState(SDL_ENABLE); - joystick = SDL_JoystickOpen(0); - } - else - { - if (joystick!=NULL) - { - SDL_JoystickClose(0); - SDL_JoystickEventState(SDL_ENABLE); - joystick = SDL_JoystickOpen(0); - } - } - - while ( SDL_PollEvent(&app_input_event) ) - { - if ( app_input_event.type == SDL_QUIT ) - { - ws_key_esc = 1; - } - } - - if (joystick) - { - if (SDL_JoystickGetButton(joystick,0)) - { - ws_key_start=1; - } - else - { - ws_key_start=0; - } - - if (SDL_JoystickGetButton(joystick,1)) - { - ws_key_button_a=1; - } - else - { - ws_key_button_a=0; - } - - if (SDL_JoystickGetButton(joystick,2)) - { - ws_key_button_b=1; - } - else - { - ws_key_button_b=0; - } - - - if (SDL_JoystickGetAxis(joystick,0)<-7000) - { - ws_key_x4=1; - } - else - { - ws_key_x4=0; - } - - if (SDL_JoystickGetAxis(joystick,0)>7000) - { - ws_key_x2=1; - } - else - { - ws_key_x2=0; - } - - if (SDL_JoystickGetAxis(joystick,1)<-7000) - { - ws_key_x1=1; - } - else - { - ws_key_x1=0; - } - - if (SDL_JoystickGetAxis(joystick,1)>7000) - { - ws_key_x3=1; - } - else - { - ws_key_x3=0; - } - ws_key_y4=0; - ws_key_y2=0; - ws_key_y1=0; - ws_key_y3=0; - } - else - { - ws_key_start=0; - ws_key_x4=0; - ws_key_x2=0; - ws_key_x1=0; - ws_key_x3=0; - ws_key_y4=0; - ws_key_y2=0; - ws_key_y1=0; - ws_key_y3=0; - ws_key_button_a=0; - ws_key_button_b=0; - } - - uint8_t *keystate = SDL_GetKeyState(NULL); - - if ( keystate[SDLK_e]) + if (getKeyState(GLFW_KEY_E)) { dump_memory(); } - if ( keystate[SDLK_r]) + if (getKeyState(GLFW_KEY_R)) { printf("Boop\n"); ws_reset(); } - if ( keystate[SDLK_ESCAPE] ) + if (getKeyState(GLFW_KEY_ESCAPE)) { ws_key_esc = 1; } - if ( keystate[SDLK_UP] ) + if ( getKeyState(GLFW_KEY_UP)) { ws_key_x1=1; } - if ( keystate[SDLK_DOWN] ) + if ( getKeyState(GLFW_KEY_DOWN)) { ws_key_x3=1; } - if ( keystate[SDLK_RIGHT] ) + if (getKeyState(GLFW_KEY_RIGHT)) { ws_key_x2=1; } - if ( keystate[SDLK_LEFT] ) + if (getKeyState(GLFW_KEY_LEFT)) { ws_key_x4=1; } - if (keystate[SDLK_RETURN]) + if (getKeyState(GLFW_KEY_ENTER)) { ws_key_start=1; } - if (keystate[SDLK_c]) + if (getKeyState(GLFW_KEY_C)) { ws_key_button_a=1; } - if (keystate[SDLK_x]) + if (getKeyState(GLFW_KEY_X)) { ws_key_button_b=1; } - if (keystate[SDLK_w]) + if (getKeyState(GLFW_KEY_W)) { ws_key_y1=1; } - if (keystate[SDLK_a]) + if (getKeyState(GLFW_KEY_A)) { ws_key_y4=1; } - if (keystate[SDLK_s]) + if (getKeyState(GLFW_KEY_S)) { ws_key_y3=1; } - if (keystate[SDLK_d]) + if (getKeyState(GLFW_KEY_D)) { ws_key_y2=1; } - if (keystate[SDLK_o]) + if (getKeyState(GLFW_KEY_O)) { ws_cyclesByLine+=10; } - if (keystate[SDLK_l]) + if (getKeyState(GLFW_KEY_L)) { ws_cyclesByLine-=10; } - } -//////////////////////////////////////////////////////////////////////////////// -// -//////////////////////////////////////////////////////////////////////////////// -// -// -// -// -// -// -// -//////////////////////////////////////////////////////////////////////////////// -static void ws_drawDoubledScanline(int16_t *vs, int16_t *backbuffer_alias) -{ - register int32_t *vs_alias = (int32_t *)vs; - register int32_t data; - - for (int pixel = 0 ; pixel < 224 ; pixel += 8) - { - data = *backbuffer_alias++; - data |= (data << 16); - *vs_alias++ = data; - data = *backbuffer_alias++; - data |= (data << 16); - *vs_alias++ = data; - data = *backbuffer_alias++; - data |= (data << 16); - *vs_alias++ = data; - data = *backbuffer_alias++; - data |= (data << 16); - *vs_alias++ = data; - data = *backbuffer_alias++; - data |= (data << 16); - *vs_alias++ = data; - data = *backbuffer_alias++; - data |= (data << 16); - *vs_alias++ = data; - data = *backbuffer_alias++; - data |= (data << 16); - *vs_alias++ = data; - data = *backbuffer_alias++; - data |= (data << 16); - *vs_alias++ = data; - } -} - -//////////////////////////////////////////////////////////////////////////////// -// -//////////////////////////////////////////////////////////////////////////////// -// -// -// -// -// -// -// -//////////////////////////////////////////////////////////////////////////////// -static void ws_drawDoubledRotatedScanline(int16_t *vs, int16_t *backbuffer_alias) -{ - register int32_t *vs_alias = (int32_t *)vs; - register int32_t data; - - for (int pixel = 0 ; pixel < 144 ; pixel += 8) - { - data = *backbuffer_alias++; - data |= (data << 16); - *vs_alias++ = data; - data = *backbuffer_alias++; - data |= (data << 16); - *vs_alias++ = data; - data = *backbuffer_alias++; - data |= (data << 16); - *vs_alias++ = data; - data = *backbuffer_alias++; - data |= (data << 16); - *vs_alias++ = data; - data = *backbuffer_alias++; - data |= (data << 16); - *vs_alias++ = data; - data = *backbuffer_alias++; - data |= (data << 16); - *vs_alias++ = data; - data = *backbuffer_alias++; - data |= (data << 16); - *vs_alias++ = data; - data = *backbuffer_alias++; - data |= (data << 16); - *vs_alias++ = data; - } -} -//////////////////////////////////////////////////////////////////////////////// -// -//////////////////////////////////////////////////////////////////////////////// -// -// -// -// -// -// -// -//////////////////////////////////////////////////////////////////////////////// -void ws_rotate_backbuffer(int16_t *backbuffer) -{ - static int16_t temp[224*144]; - - memcpy(temp,backbuffer,224*144*2); - - for (int line=0; line<144; line++) - for (int column=0; column<224; column++) - { - backbuffer[line+((223-column)<<7)+((223-column)<<4)]=temp[column+(line<<7)+(line<<6)+(line<<5)]; - } -} //////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////// @@ -379,182 +358,67 @@ void ws_emulate(void) int i = 0; double dTime = 0.0, dNormalLast = 0.0, dTemp; - int32_t surfacePitch; -// 15 bits RGB555 - Format format(16, 0x007c00, 0x00003e0, 0x0000001f); - Console console; - Surface *surface; + // 15 bits RGB555 + //Format format(16, 0x007c00, 0x00003e0, 0x0000001f); + GLWindowInitEx(&mainWindow, 224, 144); + initDisplay(&mainWindow); + clearScreen(&mainWindow); + updateScreen(&mainWindow); + int16_t *backBuffer = (int16_t *)mainWindow.videoMemory; - if (app_rotated) + + dNormalLast = (double)getTicks(); + + while (1) { - surface = new Surface(144 * 2, 224 * 2, format); - int16_t *backbuffer = (int16_t *)malloc(224 * 144 * sizeof(int16_t)); - memset(backbuffer, 0x00, 224 * 144 * sizeof(int16_t)); - surfacePitch = (surface->pitch() >> 1); - dNormalLast = (double)SDL_GetTicks(); + dTemp = getTicks(); + dTime = dTemp - dNormalLast; - console.open(app_window_title, 144 * 2, 224 * 2, format); - while (1) + nCount = (int32_t)(dTime * 0.07547); // does this calculation make sense? + + if (nCount <= 0) + { + /* Sleep for 2ms */ + usleep(2000); + } // No need to do anything for a bit + else { - dTemp = (double)SDL_GetTicks(); - dTime = dTemp - dNormalLast; + dNormalLast += nCount * (1 / 0.07547); - nCount = (int32_t)(dTime * 0.07547); // does this calculation make sense? - - if (nCount <= 0) + if (nCount > 10) { - SDL_Delay(2); - } // No need to do anything for a bit - else - { - - dNormalLast += nCount * (1 / 0.07547); - - if (nCount > 10) - { - nCount = 10; - } - - read_keys(); - - if (ws_key_esc) - { - console.close(); - - app_terminate = 1; - - if ((ws_rom_path != NULL) || (app_terminate)) - { - break; - } - - console.open(app_window_title, 144 * 2, 224 * 2, format); - - } - - - for (i = 0 ; i < nCount - 1 ; i++) - { - while (!ws_executeLine(backbuffer, 0)) - { - } - } - - while (!ws_executeLine(backbuffer, 1)) - { - } - - - ws_rotate_backbuffer(backbuffer); - - int16_t *vs = (int16_t *)surface->lock(); - int16_t *backbuffer_alias = backbuffer; - - for (int line = 0 ; line < 224 ; line++) - { - ws_drawDoubledRotatedScanline(vs, backbuffer_alias); - vs += surfacePitch; - ws_drawDoubledRotatedScanline(vs, backbuffer_alias); - vs += surfacePitch; - backbuffer_alias += 144; - } - - surface->unlock(); - surface->copy(console); - console.update(); + nCount = 10; } - } - console.close(); - delete surface; + read_keys(); - } - else - { - surface = new Surface(224 * 2, 144 * 2, format); - int16_t *backbuffer = (int16_t *)malloc(224 * 144 * sizeof(int16_t)); - memset(backbuffer, 0x00, 224 * 144 * sizeof(int16_t)); - surfacePitch = (surface->pitch() >> 1); - - dNormalLast = (double)SDL_GetTicks(); - - console.open(app_window_title, 224 * 2, 144 * 2, format); - - while (1) - { - - dTemp = (double)SDL_GetTicks(); - dTime = dTemp - dNormalLast; - - - nCount = (int32_t)(dTime * 0.07547); // does this calculation make sense? - - if (nCount <= 0) + if (ws_key_esc) { - SDL_Delay(2); - } // No need to do anything for a bit - else - { - - dNormalLast += nCount * (1 / 0.07547); + app_terminate = 1; - if (nCount > 10) + if ((ws_rom_path != NULL) || (app_terminate)) { - nCount = 10; + break; } - - read_keys(); - - if (ws_key_esc) - { - console.close(); - - app_terminate = 1; - - if ((ws_rom_path != NULL) || (app_terminate)) - { - break; - } - - console.open(app_window_title, 224 * 2, 144 * 2, format); - - } - - - for (i = 0 ; i < nCount - 1 ; i++) - { - while (!ws_executeLine(backbuffer, 0)) - { - } - } - - while (!ws_executeLine(backbuffer, 1)) - { - } - - int16_t *vs = (int16_t *)surface->lock(); - int16_t *backbuffer_alias = backbuffer; - - for (int line = 0 ; line < 144 ; line++) - { - ws_drawDoubledScanline(vs, backbuffer_alias); - vs += surfacePitch; - ws_drawDoubledScanline(vs, backbuffer_alias); - vs += surfacePitch; - backbuffer_alias += 224; - } - - surface->unlock(); - surface->copy(console); - console.update(); } - } - console.close(); - delete surface; + + for (i = 0 ; i < nCount - 1 ; i++) + { + while (!ws_executeLine(backBuffer, 0)) + { + } + } + + while (!ws_executeLine(backBuffer, 1)) + { + } + + updateScreen(&mainWindow); + } } } diff --git a/source/emulate.h b/source/emulate.h index 296a9c1..339e8ff 100644 --- a/source/emulate.h +++ b/source/emulate.h @@ -21,7 +21,6 @@ extern char app_window_title[256]; extern int app_gameRunning; extern int app_terminate; extern int app_fullscreen; -extern SDL_Event app_input_event; extern int app_rotated; diff --git a/source/io.cpp b/source/io.cpp index 71e3bfa..9191c79 100644 --- a/source/io.cpp +++ b/source/io.cpp @@ -29,10 +29,13 @@ #include "audio.h" #include "memory.h" +//#define IO_DUMP + extern uint8_t *externalEeprom; extern uint32_t romAddressMask; extern uint16_t *internalEeprom; extern nec_Regs I; +extern uint64_t nec_monotonicCycles; enum { @@ -86,6 +89,8 @@ uint8_t ws_key_flipped; int rtcDataRegisterReadCount=0; +FILE *ioLogFp = NULL; + //////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////// @@ -139,6 +144,10 @@ void ws_io_init(void) ws_io_reset(); ws_key_flipped=0; + +#ifdef IO_DUMP + ioLogFp = fopen("iodump.csv", "wt"); +#endif } //////////////////////////////////////////////////////////////////////////////// // @@ -172,6 +181,10 @@ void ws_io_done(void) { free(ws_ioRam); } + +#ifdef IO_DUMP + fclose(ioLogFp); +#endif } /* Serial port */ @@ -329,6 +342,7 @@ uint8_t cpu_readport(uint8_t port) int w1,w2; uint8_t retVal = 0; +/* if (port > 0x100) { port &= 0xFF; @@ -337,7 +351,7 @@ uint8_t cpu_readport(uint8_t port) return 0x00; } } - +*/ switch (port) { @@ -581,6 +595,10 @@ uint8_t cpu_readport(uint8_t port) exit: + if (ioLogFp) + { + fprintf(ioLogFp, "%ld, R, %02X, %02X\n", nec_monotonicCycles, port, retVal); + } return retVal; } //////////////////////////////////////////////////////////////////////////////// @@ -599,6 +617,11 @@ void cpu_writeport(uint32_t port,uint8_t value) int unknown_io_port=0; + if (ioLogFp) + { + fprintf(ioLogFp, "%ld, W, %02X, %02X\n", nec_monotonicCycles, port, value); + } + if (port > 0x100) { port &= 0xFF; @@ -1046,6 +1069,7 @@ void cpu_writeport(uint32_t port,uint8_t value) } fflush(stdout); } + break; case 0xca: if(value==0x15) diff --git a/source/memory.cpp b/source/memory.cpp index 5504577..931a77a 100644 --- a/source/memory.cpp +++ b/source/memory.cpp @@ -252,7 +252,7 @@ char *load_file(char *filename) fstat(fd, &FileStat); - printf("Trying to load %s, size = %lu...\n",filename, FileStat.st_size); + printf("Trying to load %s, size = %lu...\n",filename, (unsigned long)FileStat.st_size); ret_ptr = (char *)mmap(NULL, FileStat.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); @@ -284,7 +284,7 @@ char *create_file(char *filename, uint32_t size) char buf[] = { 0 }; printf("Trying to create %s, size = %u...\n",filename, size); - fd = open(filename, O_CREAT | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_TRUNC); + fd = open(filename, O_CREAT | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH | O_TRUNC, 0644); fchmod(fd, 0644); close(fd); sync(); diff --git a/source/nec/CMakeLists.txt b/source/nec/CMakeLists.txt new file mode 100644 index 0000000..4ff600e --- /dev/null +++ b/source/nec/CMakeLists.txt @@ -0,0 +1,4 @@ +set(SOURCES nec.cpp) +set(HEADERS nec.h necea.h necinstr.h necintrf.h necmodrm.h) + +add_library(nec_v30 ${SOURCES} ${HEADERS}) \ No newline at end of file diff --git a/source/nec/nec.cpp b/source/nec/nec.cpp index 2e42fc7..c7f64b1 100644 --- a/source/nec/nec.cpp +++ b/source/nec/nec.cpp @@ -38,6 +38,7 @@ /* cpu state */ /***************************************************************************/ +uint64_t nec_monotonicCycles; int nec_ICount; nec_Regs I; @@ -65,6 +66,7 @@ void nec_reset (void *param) unsigned int i,j,c; BREGS reg_name[8]= { AL, CL, DL, BL, AH, CH, DH, BH }; + nec_monotonicCycles = 0; memset( &I, 0, sizeof(I) ); @@ -3889,7 +3891,7 @@ void nec_set_reg(int regnum, uint32_t val) } } -char *instructionsName[256] = +const char *instructionsName[256] = { "ADD ", "ADD ", "ADD ", "ADD ", "ADD ", "ADD ", "PUSH", "POP ", "OR ", "OR ", "OR ", "OR ", "OR ", "OR ", "PUSH", "----", "ADC ", "ADC ", "ADC ", "ADC ", "ADC ", "ADC ", "PUSH", "POP ", "SBB ", "SBB ", "SBB ", "SBB ", "SBB ", "SBB ", "PUSH", "POP ", @@ -3912,7 +3914,7 @@ char *instructionsName[256] = int nec_execute(int cycles) { - + int done; nec_ICount=cycles; // cpu_type=V30; @@ -3938,6 +3940,10 @@ int nec_execute(int cycles) // nec_ICount++; } - return cycles - nec_ICount; + done = cycles - nec_ICount; + + nec_monotonicCycles += done; + + return done; } diff --git a/source/ws.cpp b/source/ws.cpp index 49e5365..6a40147 100644 --- a/source/ws.cpp +++ b/source/ws.cpp @@ -191,6 +191,7 @@ int ws_executeLine(int16_t *framebuffer, int renderLine) // update scanline register ws_ioRam[2]=ws_gpu_scanline; + /* Why twice like that and random cycle count???? */ ws_cycles=nec_execute((ws_cyclesByLine>>1)+(rand()&7)); ws_cycles+=nec_execute((ws_cyclesByLine>>1)+(rand()&7)); @@ -459,7 +460,7 @@ int ws_saveState(char *statepath) } } - int fp=open(newPath, O_RDWR|O_CREAT); + int fp=open(newPath, O_RDWR|O_CREAT, 0644); delete newPath; if (fp==-1)