├── .gitconfig ├── tools ├── include │ ├── unwindows.hpp │ ├── glerror.hpp │ ├── al_engine.hpp │ └── gl_engine.hpp ├── src │ ├── glerror.cpp │ └── al_engine.cpp ├── config_main.hpp.in ├── tda_view.cpp └── CMakeLists.txt ├── asm ├── tr3200 │ ├── beep.ffi │ ├── clock.ffi │ ├── hello.ffi │ ├── hwn.asm │ ├── hwn.ffi │ ├── hwn.lst │ ├── test.ffi │ ├── type1.ffi │ ├── floppy.ffi │ ├── random.ffi │ ├── random.asm │ ├── random.lst │ ├── beep.asm │ ├── beep.lst │ ├── hello.asm │ ├── clock.asm │ └── floppy.asm └── dcpu16n │ ├── hello.ffi │ ├── hello.asm │ └── hello.lst ├── assets ├── EC1271-8x8.png ├── EC1272-8x8.png ├── shaders │ ├── basic_fs.frag │ ├── basic_texture.frag │ ├── basic_vs.vert │ ├── mvp_template.vert │ └── retro_texture.frag └── CMakeLists.txt ├── .gitmodules ├── travis ├── install_cmake.sh └── install_deps.sh ├── .editorconfig ├── include ├── dcpu16n │ ├── dis_dcpu16n.hpp │ └── dcpu16n.hpp ├── devices │ ├── rom_palette.inc │ ├── rtc.hpp │ ├── rng.hpp │ ├── beeper.hpp │ ├── nvram.hpp │ ├── timer.hpp │ ├── dummy_device.hpp │ ├── debug_serial_console.hpp │ ├── media.hpp │ └── m5fdd.hpp ├── types.hpp ├── vc.hpp ├── tr3200 │ ├── dis_tr3200.hpp │ └── tr3200.hpp ├── vc_dll.hpp.in ├── auxiliar.hpp ├── enum_and_ctrl_blk.hpp ├── addr_listener.hpp ├── device_factory.hpp ├── cpu.hpp └── device.hpp ├── prebuild.ps1 ├── .gitignore ├── cmake ├── FindOpenAL.cmake ├── FindALURE.cmake ├── FindGTEST_MAIN.cmake ├── GetGitRevisionDescription.cmake.in ├── FindGTEST.cmake ├── Platform.cmake ├── FindGLFW3.cmake ├── FindGLEW.cmake ├── package.cmake.in ├── FindGLM.cmake ├── LoadLibraries.cmake └── GetGitRevisionDescription.cmake ├── src ├── dcpu16n │ ├── dcpu16n_macros.hpp │ └── dis_dcpu16n.cpp ├── vs_fix.hpp ├── config.hpp.in ├── tr3200 │ ├── tr3200_cycles.inc │ ├── tr3200_opcodes.hpp │ └── tr3200_macros.hpp ├── auxiliar.cpp ├── devices │ ├── beeper.cpp │ ├── rtc.cpp │ ├── gkeyb.cpp │ ├── rng.cpp │ ├── nvram.cpp │ └── tda.cpp ├── device_factory.cpp └── enum_and_ctrl_blk.cpp ├── call_Uncrustify.sh ├── appveyor.yml ├── tests ├── device_factory_test.cpp ├── gkeyb_test.cpp ├── CMakeLists.txt └── benchmark.cpp ├── bench_FX4200.txt ├── .travis.yml └── call_Uncrustify.cfg /.gitconfig: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tools/include/unwindows.hpp: -------------------------------------------------------------------------------- 1 | 2 | #undef MOD_SHIFT 3 | -------------------------------------------------------------------------------- /asm/tr3200/beep.ffi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trillek-team/trillek-vcomputer-module/HEAD/asm/tr3200/beep.ffi -------------------------------------------------------------------------------- /asm/tr3200/clock.ffi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trillek-team/trillek-vcomputer-module/HEAD/asm/tr3200/clock.ffi -------------------------------------------------------------------------------- /asm/tr3200/hello.ffi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trillek-team/trillek-vcomputer-module/HEAD/asm/tr3200/hello.ffi -------------------------------------------------------------------------------- /asm/tr3200/hwn.asm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trillek-team/trillek-vcomputer-module/HEAD/asm/tr3200/hwn.asm -------------------------------------------------------------------------------- /asm/tr3200/hwn.ffi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trillek-team/trillek-vcomputer-module/HEAD/asm/tr3200/hwn.ffi -------------------------------------------------------------------------------- /asm/tr3200/hwn.lst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trillek-team/trillek-vcomputer-module/HEAD/asm/tr3200/hwn.lst -------------------------------------------------------------------------------- /asm/tr3200/test.ffi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trillek-team/trillek-vcomputer-module/HEAD/asm/tr3200/test.ffi -------------------------------------------------------------------------------- /asm/tr3200/type1.ffi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trillek-team/trillek-vcomputer-module/HEAD/asm/tr3200/type1.ffi -------------------------------------------------------------------------------- /asm/dcpu16n/hello.ffi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trillek-team/trillek-vcomputer-module/HEAD/asm/dcpu16n/hello.ffi -------------------------------------------------------------------------------- /asm/tr3200/floppy.ffi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trillek-team/trillek-vcomputer-module/HEAD/asm/tr3200/floppy.ffi -------------------------------------------------------------------------------- /asm/tr3200/random.ffi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trillek-team/trillek-vcomputer-module/HEAD/asm/tr3200/random.ffi -------------------------------------------------------------------------------- /assets/EC1271-8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trillek-team/trillek-vcomputer-module/HEAD/assets/EC1271-8x8.png -------------------------------------------------------------------------------- /assets/EC1272-8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trillek-team/trillek-vcomputer-module/HEAD/assets/EC1272-8x8.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "doc/specs"] 2 | path = doc/specs 3 | url = https://github.com/trillek-team/trillek-computer.git 4 | -------------------------------------------------------------------------------- /assets/shaders/basic_fs.frag: -------------------------------------------------------------------------------- 1 | // Basic Fragment Shader 2 | #version 140 3 | 4 | precision highp float; // needed only for version 1.30 5 | 6 | in vec3 ex_Color; 7 | 8 | out vec4 out_Color; 9 | 10 | void main(void) { 11 | out_Color.xyz = ex_Color.xyz; 12 | out_Color.w = 1.0; 13 | } 14 | -------------------------------------------------------------------------------- /travis/install_cmake.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [ ! -d "$HOME/cmake/bin" ]; then 6 | #Download CMake 3.2 7 | wget http://www.cmake.org/files/v3.2/cmake-3.2.3-Linux-x86_64.tar.gz 8 | mkdir -p $HOME/cmake 9 | tar zxf cmake-3.2.3-Linux-x86_64.tar.gz -C $HOME/cmake --strip-components=1 10 | else 11 | echo "CMake - Using cached directory"; 12 | fi 13 | 14 | -------------------------------------------------------------------------------- /assets/shaders/basic_texture.frag: -------------------------------------------------------------------------------- 1 | // Basic Fragment Shader that uses textures 2 | #version 140 3 | 4 | precision highp float; // needed only for version 1.30 5 | 6 | in vec3 ex_Color; 7 | in vec2 ex_UV; 8 | 9 | out vec4 out_Color; 10 | 11 | uniform sampler2D texture0; 12 | 13 | void main(void) { 14 | out_Color.xyz = ex_Color * texture( texture0, ex_UV ).rgb; 15 | out_Color.w = 1.0; 16 | } 17 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | # Unix-style newlines with a newline ending every file 5 | # with 4 spaces indent 6 | [*] 7 | end_of_line = lf 8 | insert_final_newline = true 9 | charset = utf-8 10 | indent_style = space 11 | indent_size = 4 12 | 13 | # If we need finetuning the rules for other files, we can add they here 14 | 15 | # Adecuate charset for asebmly files 16 | [*.{asm,ainc}] 17 | charset = ISO-8859-15 18 | 19 | -------------------------------------------------------------------------------- /assets/shaders/basic_vs.vert: -------------------------------------------------------------------------------- 1 | // Basic Vertex Shader Template with Model, View, Project matrixes 2 | #version 140 3 | 4 | in vec3 in_Position; 5 | in vec3 in_Color; 6 | in vec2 in_UV; 7 | 8 | uniform mat4 in_Model; 9 | uniform mat4 in_View; 10 | uniform mat4 in_Proj; 11 | 12 | out vec3 ex_Color; 13 | out vec2 ex_UV; 14 | 15 | void main(void) { 16 | gl_Position = in_Proj * (in_View * (in_Model * vec4(in_Position, 1.0))); 17 | ex_Color = vec3(in_Color); 18 | ex_UV = in_UV; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /asm/tr3200/random.asm: -------------------------------------------------------------------------------- 1 | ; tests the embedded RNG device 2 | 3 | .ORG 0x100000 ; This a ROM image 4 | 5 | MOV %R8, 0x789 6 | 7 | STORE 0x11E040, %R8 8 | 9 | LOAD %R1, 0x11E040 10 | LOAD %R2, 0x11E040 11 | LOAD %R3, 0x11E040 12 | 13 | STORE 0x11E040, %R8 14 | 15 | LOADW %R5, 0x11E040 16 | LOADW %R6, 0x11E040 17 | LOADW %R7, 0x11E040 18 | 19 | STORE 0x11E040, %R8 20 | 21 | LOADB %R9, 0x11E040 22 | LOADB %R10, 0x11E040 23 | LOADB %Y, 0x11E040 24 | 25 | end: 26 | SLEEP 27 | JMP end ; Looks that WaveAsm not like to have a label like an instruction 28 | 29 | -------------------------------------------------------------------------------- /include/dcpu16n/dis_dcpu16n.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /** 3 | * Trillek Virtual Computer - dis_dcpu16n.hpp 4 | * OnLine dis-assembly of DCPU-16N machine code 5 | */ 6 | 7 | #include "dcpu16n/dcpu16n.hpp" 8 | 9 | #include 10 | 11 | namespace trillek { 12 | namespace computer { 13 | 14 | /** 15 | * Disassemble one instruction of DCPU-16N code to a humman readable string 16 | * @param vc VComputer to read from 17 | * @param pc 24 bit address to read instruction from 18 | */ 19 | DECLDIR 20 | std::string DisassemblyDCPU16N(const VComputer& vc, DWord pc); 21 | 22 | } // computer 23 | } // trillek 24 | -------------------------------------------------------------------------------- /include/devices/rom_palette.inc: -------------------------------------------------------------------------------- 1 | // Default palette for TDA 2 | 3 | // Little Endian -> RGBA in little endian is 0xAABBGGRR 4 | //AABBGGRR 5 | 0xFF000000, // Black 6 | 0xFFEFDCB2, // Light Blue 7 | 0xFFF2A231, // Mid Blue 8 | 0xFFFF0000, // Blue 9 | 0xFF32261B, // Dark Blue 10 | 0xFF27CEA3, // Light Green 11 | 0xFF1A8944, // Green 12 | 0xFF4E482F, // Swamp Green 13 | 0xFF6BE2F7, // Yellow 14 | 0xFF3189EB, // Copper 15 | 0xFF2264A4, // Brown 16 | 0xFF2B3C49, // Dark Brown 17 | 0xFF8B6FE0, // Pink 18 | 0xFF3326BE, // Red 19 | 0xFF9D9D9D, // Gray 20 | 0xFFFFFFFF // White 21 | 22 | -------------------------------------------------------------------------------- /assets/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Shaders 2 | 3 | # Vertex Shaders 4 | configure_file(shaders/basic_vs.vert ${CMAKE_CURRENT_BINARY_DIR}/shaders/basic_vs.vert COPYONLY) 5 | configure_file(shaders/mvp_template.vert ${CMAKE_CURRENT_BINARY_DIR}/shaders/mvp_template.vert COPYONLY) 6 | 7 | # Fragment Shaders 8 | configure_file(shaders/basic_fs.frag ${CMAKE_CURRENT_BINARY_DIR}/shaders/basic_fs.frag COPYONLY) 9 | configure_file(shaders/basic_texture.frag ${CMAKE_CURRENT_BINARY_DIR}/shaders/basic_texture.frag COPYONLY) 10 | configure_file(shaders/retro_texture.frag ${CMAKE_CURRENT_BINARY_DIR}/shaders/retro_texture.frag COPYONLY) 11 | 12 | -------------------------------------------------------------------------------- /prebuild.ps1: -------------------------------------------------------------------------------- 1 | # PowerShell script to install all dependencies 2 | # 3 | # Use choco & nuget to grab glew and glfw 4 | 5 | new-item lib -type directory 6 | new-item lib\x86 -type directory 7 | new-item lib\x86\Debug -type directory 8 | new-item lib\include -type directory 9 | new-item lib\include\glm -type directory 10 | new-item build -type director 11 | 12 | pushd 13 | 14 | #Start-FileDownload 'http://cpu.zardoz.es/trillek-win32-lib.zip' 15 | Start-FileDownload 'https://github.com/trillek-team/trillek-vcomputer-module/releases/download/v0.5.0/trillek-win32-lib.zip' 16 | 7z -y x trillek-win32-lib.zip 17 | 18 | popd 19 | -------------------------------------------------------------------------------- /tools/include/glerror.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Trillek Virtual Computer - glerror.hpp 3 | * Function/macros to debug OpenGL code 4 | */ 5 | 6 | #ifndef __TR_GL_ERROR_HPP_ 7 | #define __TR_GL_ERROR_HPP_ 1 8 | 9 | namespace trillek { 10 | /** 11 | * Check if there is a OpenGL error and display it 12 | * @param file Source file 13 | * @param line Source line 14 | */ 15 | void tr_check_gl_error(const char *file, int line); 16 | } // End of namespace trillek 17 | 18 | #ifndef NDEBUG 19 | /** 20 | * Usage 21 | * [... some opengl calls] 22 | * glCheckError(); 23 | */ 24 | #define check_gl_error() trillek::tr_check_gl_error(__FILE__,__LINE__) 25 | 26 | #else 27 | 28 | #define check_gl_error() 29 | 30 | #endif 31 | 32 | #endif // __TR_GL_ERROR_HPP_ 33 | 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Compiled Dynamic libraries 8 | *.so 9 | *.dylib 10 | 11 | # Compiled Static libraries 12 | *.lai 13 | *.la 14 | *.a 15 | 16 | # VStudio & Windows stuff 17 | *.sln 18 | *.suo 19 | *.vcxproj 20 | *.vcxproj.filters 21 | *.dir 22 | *.sdf 23 | Testing/**/* 24 | Win32/**/* 25 | 26 | # Other stuff 27 | *.pyc 28 | *.orig 29 | install_manifest.txt 30 | 31 | #CMakeFiles 32 | Makefile 33 | cmake_install.cmake 34 | CTestTestfile.cmake 35 | CMakeCache.txt 36 | CMakeFiles/ 37 | 38 | #build folder from cmake/premake 39 | build/ 40 | 41 | # vim/kate/nano backup files 42 | *.swp 43 | *.*~ 44 | 45 | # Generated config files in include 46 | config.hpp 47 | config_main.hpp 48 | include/vc_dll.hpp 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /include/types.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Basic types used by the Virtual Computer 3 | * \file types.hpp 4 | * \copyright LGPL v3 5 | */ 6 | #ifndef __TR_TYPES_HPP_ 7 | #define __TR_TYPES_HPP_ 1 8 | 9 | #include 10 | #include // std::size_t 11 | 12 | namespace trillek { 13 | 14 | typedef uint64_t QWord; /// unsigned Quad Word data 15 | typedef uint32_t DWord; /// unsigned Double Word data 16 | typedef uint16_t Word; /// unsigned Word data 17 | typedef uint8_t Byte; /// unsigned Byte data 18 | 19 | typedef int64_t SQWord; /// signed Quad Word 20 | typedef int32_t SDWord; /// signed Double Word 21 | typedef int16_t SWord; /// signed Word 22 | typedef int8_t SByte; /// signed Byte 23 | 24 | } // End of namespace trillek 25 | 26 | #endif // __TR_TYPES_HPP_ 27 | -------------------------------------------------------------------------------- /cmake/FindOpenAL.cmake: -------------------------------------------------------------------------------- 1 | # FindOpenAL.cmake 2 | # 3 | # Copyright (c) 2013, Meisaka Yukara 4 | 5 | include(FindPackageHandleStandardArgs) 6 | 7 | find_path(OPENAL_INCLUDE_DIR 8 | NAMES al.h alc.h 9 | PATH_SUFFIXES AL 10 | ) 11 | if (NOT OPENAL_INCLUDE_DIR) 12 | message(WARNING "Could not find the OpenAL headers" ) 13 | endif (NOT OPENAL_INCLUDE_DIR) 14 | 15 | FIND_LIBRARY(OPENAL_LIBRARY 16 | NAMES OpenAL al openal OpenAL32 libopenal libopenal.so 17 | HINTS 18 | ENV OPENALDIR 19 | PATH_SUFFIXES x86 x64 amd64 lib64 20 | ) 21 | if (NOT OPENAL_LIBRARY) 22 | message(WARNING "Could not find the OpenAL library" ) 23 | endif (NOT OPENAL_LIBRARY) 24 | SET(OPENAL_LIBRARIES ${OPENAL_LIBRARY}) 25 | 26 | find_package_handle_standard_args(OPENAL DEFAULT_MSG OPENAL_INCLUDE_DIR OPENAL_LIBRARY) 27 | mark_as_advanced(OPENAL_INCLUDE_DIR OPENAL_LIBRARY) 28 | 29 | -------------------------------------------------------------------------------- /include/vc.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Virtual Computer Main header 3 | * \file vc.hpp 4 | * \copyright LGPL v3 5 | * 6 | * A header that includes the needed headers to create a virtual computer and 7 | * run it. 8 | * 9 | * One Header to rule them all, One Header to find them, 10 | * One Header to bring them all and in the darkness bind them 11 | * In the Land of Mordor where the Shadows lie. 12 | */ 13 | #ifndef __VC_HPP_ 14 | #define __VC_HPP_ 1 15 | 16 | #include "types.hpp" 17 | #include "vcomputer.hpp" 18 | 19 | // VM CPUs 20 | #include "tr3200/tr3200.hpp" 21 | #include "dcpu16n/dcpu16n.hpp" 22 | 23 | // Devices 24 | #include "devices/tda.hpp" 25 | #include "devices/gkeyb.hpp" 26 | #include "devices/m5fdd.hpp" 27 | #include "devices/debug_serial_console.hpp" 28 | 29 | // Misc 30 | #include "auxiliar.hpp" 31 | 32 | #endif // __VC_HPP_ 33 | -------------------------------------------------------------------------------- /assets/shaders/mvp_template.vert: -------------------------------------------------------------------------------- 1 | // Basic Vertex Shader Template with Model, View, Project matrixes 2 | #version 140 3 | 4 | in vec3 in_Position; 5 | in vec3 in_Color; 6 | in vec3 in_Normal; 7 | 8 | in vec2 in_UV; 9 | 10 | uniform mat4 in_Model; 11 | uniform mat4 in_View; 12 | uniform mat4 in_Proj; 13 | 14 | out vec3 ex_Color; 15 | out vec3 ex_Normal; 16 | out vec2 ex_UV; 17 | 18 | void main(void) { 19 | vec3 normalDirection = normalize(mat3(in_Model) * in_Normal); 20 | vec3 lightDirection = normalize(vec3(-in_View[3].xyz * mat3(in_View) - (in_Model * vec4(in_Position, 1.0)).xyz )); // Light comes from camera 21 | 22 | gl_Position = in_Proj * (in_View * (in_Model * vec4(in_Position, 1.0))); 23 | ex_Color = vec3(1.0, 1.0, 1.0) * vec3(in_Color) * max(0.1, dot(normalDirection, lightDirection)); 24 | ex_Normal = (in_Model * vec4(in_Normal, 0)).xyz; 25 | ex_UV = in_UV; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /cmake/FindALURE.cmake: -------------------------------------------------------------------------------- 1 | # FindAlure.cmake 2 | # 3 | # Copyright (c) 2013, Meisaka Yukara, Luis Panadero Guardeño 4 | 5 | include(FindPackageHandleStandardArgs) 6 | 7 | find_path(ALURE_INCLUDE_DIR 8 | NAMES alure.h 9 | PATHS /usr/include /usr/local/include /sw/include /opt/local/include 10 | PATH_SUFFIXES AL OpenAL 11 | ) 12 | 13 | if (NOT ALURE_INCLUDE_DIR) 14 | message(WARNING "Could not find the Alure headers" ) 15 | endif (NOT ALURE_INCLUDE_DIR) 16 | 17 | FIND_LIBRARY(ALURE_LIBRARY 18 | NAMES ALURE ALURE32 Alure alure libalure libalure.so 19 | PATH_SUFFIXES x86 lib64 x64 20 | ) 21 | 22 | if (NOT ALURE_LIBRARY) 23 | message(WARNING "Could not find the Alure library" ) 24 | endif (NOT ALURE_LIBRARY) 25 | SET(ALURE_LIBRARIES ${ALURE_LIBRARY}) 26 | 27 | find_package_handle_standard_args(ALURE DEFAULT_MSG ALURE_INCLUDE_DIR ALURE_LIBRARY) 28 | mark_as_advanced(ALURE_INCLUDE_DIR ALURE_LIBRARY) 29 | 30 | -------------------------------------------------------------------------------- /include/tr3200/dis_tr3200.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief TR3200 CPU online dis-assembler 3 | * \file dis_tr3200.hpp 4 | * \copyright LGPL v3 5 | * 6 | */ 7 | #ifndef __DISTR3200_HPP_ 8 | #define __DISTR3200_HPP_ 1 9 | 10 | #include "tr3200.hpp" 11 | 12 | #include 13 | 14 | namespace trillek { 15 | namespace computer { 16 | 17 | /** 18 | * Disassembly one instruction of TR3200 code to a humman redable text 19 | * \param vc Virtual computer instance 20 | * \param pc Address to dissamble 21 | */ 22 | DECLDIR 23 | std::string DisassemblyTR3200 (const VComputer& vc, DWord pc); 24 | 25 | /** 26 | * Disassembly one instruction of TR3200 code to a humman redable text 27 | * \param data Ptr. to TR3200 machine code 28 | * \param size Size of data to read. Must be >= 8 29 | */ 30 | DECLDIR 31 | std::string DisassemblyTR3200 (const Byte* data, std::size_t size); 32 | } // End of namespace computer 33 | } // End of namespace trillek 34 | 35 | #endif // __DISTR3200_HPP_ 36 | -------------------------------------------------------------------------------- /include/vc_dll.hpp.in: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Virtual Computer macro for Windows DLLs 3 | * \file vc_dll.hpp 4 | * \copyright LGPL v3 5 | * 6 | * A little macro to put the necesary Visual Studio stff to generate correct 7 | * DLLs 8 | */ 9 | 10 | #ifndef __VC_DLL_HPP_ 11 | #define __VC_DLL_HPP_ 1 12 | 13 | // Note that to link against a dinamic lib on windows, would be necesary to 14 | // add a BUILD_DLL_VCOMPUTER definition to the proyect 15 | #ifdef BUILD_DLL_VCOMPUTER 16 | # if defined(_MSC_VER) 17 | // DLL library on Windows, need special stuff 18 | 19 | # if defined DLL_EXPORT 20 | # define DECLDIR __declspec(dllexport) 21 | # else 22 | # define DECLDIR __declspec(dllimport) 23 | # endif 24 | 25 | # else // *nix not need something special 26 | # define DECLDIR 27 | # endif // if defined(_MSC_VER) 28 | 29 | #else // Static library, not need special stuff 30 | # define DECLDIR 31 | #endif // BUILD_DLL_VCOMPUTER 32 | 33 | #endif // __VC_DLL_HPP_ 34 | 35 | -------------------------------------------------------------------------------- /src/dcpu16n/dcpu16n_macros.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Macros used by DCPU16N implementation 3 | * \file dcpu16n_macros.hpp 4 | * \copyright The MIT License (MIT) 5 | * 6 | */ 7 | 8 | #ifndef __DCPU16N_MACROS_HPP__ 9 | #define __DCPU16N_MACROS_HPP__ 10 | 11 | #define DCPU16N_PHASE_OPFETCH 0 12 | #define DCPU16N_PHASE_NWAFETCH 1 13 | #define DCPU16N_PHASE_NWBFETCH 2 14 | #define DCPU16N_PHASE_UAREAD 3 15 | #define DCPU16N_PHASE_ACUFETCH 4 16 | #define DCPU16N_PHASE_UBREAD 5 17 | #define DCPU16N_PHASE_BCUFETCH 6 18 | #define DCPU16N_PHASE_EXEC 7 19 | #define DCPU16N_PHASE_UAWRITE 8 20 | #define DCPU16N_PHASE_ACUWRITE 9 21 | #define DCPU16N_PHASE_UBWRITE 10 22 | #define DCPU16N_PHASE_BCUWRITE 11 23 | #define DCPU16N_PHASE_EXECW 12 24 | #define DCPU16N_PHASE_SLEEP 13 25 | #define DCPU16N_PHASE_EXECSKIP 14 26 | #define DCPU16N_PHASE_EXECJMP 15 27 | #define DCPU16N_PHASE_EXECRFI 16 28 | #define DCPU16N_PHASE_MARKSKIP 17 29 | #define DCPU16N_PHASE_INTERRUPT 18 30 | 31 | #endif // ifndef __DCPU16N_MACROS_HPP__ 32 | -------------------------------------------------------------------------------- /cmake/FindGTEST_MAIN.cmake: -------------------------------------------------------------------------------- 1 | # Find gtest_main 2 | # Find the gtest_main library 3 | # 4 | # GTEST_MAIN_LIBRARIES - List of libraries when using gtest_main. 5 | # GTEST_MAIN_FOUND - True if gtest_main found. 6 | # 7 | # Based on the FindSOIL.cmake module. 8 | 9 | IF (GTEST_MAIN_INCLUDE_DIR) 10 | # Already in cache, be silent 11 | SET(GTEST_MAIN_FIND_QUIETLY TRUE) 12 | ENDIF (GTEST_MAIN_INCLUDE_DIR) 13 | 14 | 15 | FIND_LIBRARY( GTEST_MAIN_LIBRARY 16 | NAMES gtest_main 17 | HINTS 18 | $ENV{GTEST_ROOT} 19 | ${GTEST_ROOT} 20 | PATHS /usr/lib /usr/lib64 /usr/lib32 /usr/local/lib 21 | PATH_SUFFIXES x86 x64 amd64 lib64) 22 | 23 | # Per-recommendation 24 | SET(GTEST_MAIN_LIBRARIES "${GTEST_MAIN_LIBRARY}") 25 | 26 | # handle the QUIETLY and REQUIRED arguments and set GTEST_FOUND to TRUE if 27 | # all listed variables are TRUE 28 | INCLUDE(FindPackageHandleStandardArgs) 29 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTEST_MAIN DEFAULT_MSG GTEST_MAIN_LIBRARIES ) 30 | 31 | MARK_AS_ADVANCED( GTEST_MAIN_LIBRARY ) 32 | -------------------------------------------------------------------------------- /asm/tr3200/random.lst: -------------------------------------------------------------------------------- 1 | 3 00100000 .ORG 0x100000 2 | 5 00100000 MOV %R8,0x789 8907A040 3 | 7 00100004 STORE 0x11E040,%R8 0000E04840E01100 4 | 9 0010000c LOAD %R1,0x11E040 0000C44540E01100 5 | 10 00100014 LOAD %R2,0x11E040 0000C84540E01100 6 | 11 0010001c LOAD %R3,0x11E040 0000CC4540E01100 7 | 13 00100024 STORE 0x11E040,%R8 0000E04840E01100 8 | 15 0010002c LOADW %R5,0x11E040 0000D44640E01100 9 | 16 00100034 LOADW %R6,0x11E040 0000D84640E01100 10 | 17 0010003c LOADW %R7,0x11E040 0000DC4640E01100 11 | 19 00100044 STORE 0x11E040,%R8 0000E04840E01100 12 | 21 0010004c LOADB %R9,0x11E040 0000E44740E01100 13 | 22 00100054 LOADB %R10,0x11E040 0000E84740E01100 14 | 23 0010005c LOADB %Y,0x11E040 0000EC4740E01100 15 | 25 00100064 end: 16 | 26 00100064 SLEEP 00000000 17 | 27 00100068 JMP end 19008425 18 | Symbols: 19 | 00100064 end 20 | -------------------------------------------------------------------------------- /include/auxiliar.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Virtual Computer Auxiliar functions 3 | * \file auxiliar.hpp 4 | * \copyright LGPL v3 5 | * 6 | * Some auxiliar functions and methods 7 | */ 8 | #ifndef __AUXILIAR_HPP_ 9 | #define __AUXILIAR_HPP_ 1 10 | 11 | #include "types.hpp" 12 | #include "vc_dll.hpp" 13 | #include 14 | #include 15 | 16 | namespace trillek { 17 | namespace computer { 18 | 19 | /** 20 | * Load a raw binary file as ROM 21 | * \param[in] filename Binary file with the ROM 22 | * \param[out] rom buffer were to write it 23 | * \return Read size or negative value if fails 24 | */ 25 | DECLDIR int LoadROM (const std::string& filename, Byte* rom); 26 | 27 | /** 28 | * Load a raw binary file as ROM 29 | * \param[in] stream Input stream with the binary data 30 | * \param[out] rom buffer were to write it 31 | * \return Read size or negative value if fails 32 | */ 33 | DECLDIR int LoadROM (std::istream& stream, Byte* rom); 34 | 35 | } // end of namespace computer 36 | } // end of namespace trillek 37 | 38 | #endif // __AUXILIAR_HPP_ 39 | -------------------------------------------------------------------------------- /src/vs_fix.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Fix or hides VS2012 warings and errors 3 | * \file vs_fix.hpp 4 | * \copyright LGPL v3 5 | * 6 | * VStudio pragmas and fix 7 | * Use ONLY on the .cpp files 8 | */ 9 | #ifndef __VSFIX_HPP_ 10 | #define __VSFIX_HPP_ 1 11 | 12 | // MS Visual C++ stuff 13 | #if defined(_MSC_VER) 14 | // VC++ C compiler support : C89 thanks microsoft ! 15 | #define snprintf _snprintf 16 | #define log2(x) ( std::log(x) / std::log(2) ) 17 | 18 | // Get bored of theses warnings 19 | #pragma warning(disable : 4333) // Shift warning exceeding output var size, 20 | // data loss 21 | #pragma warning(disable : 4018) // Compare of signed and unsigned with auto 22 | // conversion 23 | #pragma warning(disable : 4244) // Conversion of variables with data loss 24 | #pragma warning(disable : 4800) // forcing value to bool 'true/false' 25 | #pragma warning(disable : 4996) // _snprintf is not secure.... 26 | 27 | #endif // if defined(_MSC_VER) 28 | 29 | #endif // __VSFIX_HPP_ 30 | -------------------------------------------------------------------------------- /include/devices/rtc.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Virtual Computer Real Time Clock 3 | * \file rtc.hpp 4 | * \copyright LGPL v3 5 | * 6 | * Implementation of embedded RTC device 7 | */ 8 | #ifndef __RTC_HPP_ 9 | #define __RTC_HPP_ 1 10 | 11 | #include "../types.hpp" 12 | #include "../addr_listener.hpp" 13 | 14 | #include 15 | 16 | namespace trillek { 17 | namespace computer { 18 | 19 | class RTC : public AddrListener { 20 | public: 21 | 22 | virtual Byte ReadB (DWord addr); 23 | virtual Word ReadW (DWord addr); 24 | virtual DWord ReadDW (DWord addr); 25 | 26 | virtual void WriteB (DWord addr, Byte val); 27 | virtual void WriteW (DWord addr, Word val); 28 | virtual void WriteDW (DWord addr, DWord val); 29 | 30 | private: 31 | 32 | static const int EPOCH_YEAR_OFFSET = 1900 + 0; // TODO Change this depending 33 | // of the game 34 | // history/background 35 | }; 36 | 37 | } // End of namespace computer 38 | } // End of namespace trillek 39 | 40 | #endif // __RTC_HPP_ 41 | -------------------------------------------------------------------------------- /include/devices/rng.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Virtual Computer Random Number Generator 3 | * \file rng.hpp 4 | * \copyright LGPL v3 5 | * 6 | * Implementation of embedded RNG device 7 | */ 8 | #ifndef __RNG_HPP_ 9 | #define __RNG_HPP_ 1 10 | 11 | #include "../types.hpp" 12 | #include "../addr_listener.hpp" 13 | 14 | #include 15 | 16 | namespace trillek { 17 | namespace computer { 18 | 19 | class RNG : public AddrListener { 20 | public: 21 | 22 | RNG(); 23 | virtual ~RNG(); 24 | 25 | virtual Byte ReadB (DWord addr); 26 | virtual Word ReadW (DWord addr); 27 | virtual DWord ReadDW (DWord addr); 28 | 29 | virtual void WriteB (DWord addr, Byte val); 30 | virtual void WriteW (DWord addr, Word val); 31 | virtual void WriteDW (DWord addr, DWord val); 32 | 33 | void Reset (); 34 | 35 | private: 36 | 37 | std::uniform_int_distribution distribution; 38 | std::mt19937 engine; 39 | DWord seed; 40 | bool blockGenerate; 41 | DWord number; 42 | }; 43 | 44 | } // End of namespace computer 45 | } // End of namespace trillek 46 | 47 | #endif // __RNG_HPP_ 48 | -------------------------------------------------------------------------------- /travis/install_deps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | if [ ! -d "$HOME/lib/$COMPILER/glfw-lib/lib" ]; then 6 | # No ppa for GLFW3 at this time. Compiling by hand! 7 | git clone --depth=100 https://github.com/glfw/glfw.git 8 | pushd glfw 9 | CMAKE_CXX_FLAGS=-fPIC CMAKE_C_FLAGS=-fPIC cmake -DCMAKE_INSTALL_PREFIX=$HOME/lib/$COMPILER/glfw-lib -DBUILD_SHARED_LIBS:bool=true . && make && make install 10 | popd 11 | else 12 | echo "GLFW - Using cached directory"; 13 | fi 14 | 15 | if [ ! -d "$HOME/lib/$COMPILER/glm/glm-0.9.5.3" ]; then 16 | #Download GLM 9.5 from github 17 | wget https://github.com/g-truc/glm/archive/0.9.5.3.zip 18 | unzip 0.9.5.3.zip -d $HOME/lib/$COMPILER/glm 19 | else 20 | echo "GLM - Using cached directory"; 21 | fi 22 | 23 | if [ ! -d "$HOME/lib/$COMPILER/googletest-release-1.7.0/include" ]; then 24 | # Download GTest 25 | wget https://github.com/google/googletest/archive/release-1.7.0.zip 26 | unzip release-1.7.0 -d $HOME/lib/$COMPILER 27 | cd $HOME/lib/$COMPILER/googletest-release-1.7.0 28 | cmake . && make 29 | else 30 | echo "Google Test - Using cached directory"; 31 | fi 32 | 33 | -------------------------------------------------------------------------------- /call_Uncrustify.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ ! -n "$1" ]; then 4 | echo "Syntax is: recurse.sh dirname filesuffix" 5 | echo "Syntax is: recurse.sh filename" 6 | echo "Example: recurse.sh temp cpp" 7 | exit 1 8 | fi 9 | 10 | if [ -d "$1" ]; then 11 | #echo "Dir ${1} exists" 12 | if [ -n "$2" ]; then 13 | filesuffix=$2 14 | else 15 | filesuffix="*" 16 | fi 17 | 18 | #echo "Filtering files using suffix ${filesuffix}" 19 | 20 | file_list=`find ${1} -name "*.${filesuffix}" -type f` 21 | for file2indent in $file_list 22 | do 23 | echo "Indenting file $file2indent" 24 | #!/bin/bash 25 | uncrustify -f "$file2indent" -c "./call_Uncrustify.cfg" -o indentoutput.tmp 26 | mv indentoutput.tmp "$file2indent" 27 | 28 | done 29 | else 30 | if [ -f "$1" ]; then 31 | echo "Indenting one file $1" 32 | #!/bin/bash 33 | uncrustify -f "$1" -c "./call_Uncrustify.cfg" -o indentoutput.tmp 34 | mv indentoutput.tmp "$1" 35 | 36 | else 37 | echo "ERROR: As parameter given directory or file does not exist!" 38 | echo "Syntax is: call_Uncrustify.sh dirname filesuffix" 39 | echo "Syntax is: call_Uncrustify.sh filename" 40 | echo "Example: call_Uncrustify.sh temp cpp" 41 | exit 1 42 | fi 43 | fi 44 | -------------------------------------------------------------------------------- /src/config.hpp.in: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Virtual Computer confgiration file 3 | * \file config.hpp.in 4 | * \copyright LGPL v3 5 | * 6 | * This file is procesed by CMake to setup the apropiated macros of configuration 7 | */ 8 | 9 | #ifndef __VCOMP_CONFIG_HPP_ 10 | #define __VCOMP_CONFIG_HPP_ 1 11 | 12 | namespace trillek { 13 | namespace computer { 14 | 15 | #ifdef __VCOMP_NO_EXTERN_ 16 | const unsigned MajorVersion = @VCOMP_VERSION_MAJOR@; /// Major version 17 | const unsigned MinorVersion = @VCOMP_VERSION_MINOR@; /// Minor version 18 | const unsigned PatchVersion = @VCOMP_VERSION_PATCH@; /// patch/revision version 19 | const char* Build = "@VCOMP_BUILD@"; /// Build (git refspecvar & hash ) 20 | #else 21 | extern const unsigned MajorVersion; 22 | extern const unsigned MinorVersion; 23 | extern const unsigned PatchVersion; 24 | extern const char* Build; 25 | #endif 26 | 27 | } // namespace computer 28 | } // namespace trillek 29 | 30 | // Visual doing all different... 31 | #ifdef _DEBUG 32 | #define DEBUG 33 | #endif 34 | 35 | /// Break Points functionality ? 36 | #define BRKPOINTS @BRKPOINTS_ENABLED@ 37 | #if BRKPOINTS == 0 38 | #undef BRKPOINTS 39 | #endif 40 | 41 | #endif // __VCOMP_CONFIG_HPP_ 42 | 43 | -------------------------------------------------------------------------------- /asm/tr3200/beep.asm: -------------------------------------------------------------------------------- 1 | ; Test beep in TR3200 ASM 2 | .ORG 0x100000 ; This a ROM image, so jumps need to know the real address 3 | 4 | MOV %sp, 0x020000 ; Sets Stack Pointer to the end of the 128KiB RAM 5 | 6 | ;****************************************************************************** 7 | 8 | MOV %r0, 932 ; BIOS like beep 9 | STOREW 0x11E020, %r0 10 | 11 | MOV %r1, 0 12 | wait_loop0: 13 | ADD %r0, %r0, 0 ; NOP 14 | ADD %r1, %r1, 1 15 | IFL %r1, 8000 16 | RJMP wait_loop0 17 | 18 | MOV %r0, 0 ; Stop sound 19 | STOREW 0x11E020, %r0 20 | 21 | MOV %r1, 0 22 | wait_loop1: 23 | ADD %r0, %r0, 0 ; NOP 24 | ADD %r1, %r1, 1 25 | IFL %r1, 8000 26 | RJMP wait_loop1 27 | 28 | ; for f=600hz to 500hz step 10hz 29 | ; sound f 30 | ; delay 31 | 32 | MOV %r0, 600 33 | begin: 34 | STOREW 0x11E020, %r0 35 | 36 | MOV %r1, 0 37 | wait_loop2: 38 | ADD %r0, %r0, 0 ; NOP 39 | ADD %r1, %r1, 1 40 | IFL %r1, 1000 41 | RJMP wait_loop2 42 | 43 | SUB %r0, %r0, 10 44 | IFL %r0, 500 45 | RJMP again 46 | RJMP begin 47 | 48 | again: 49 | MOV %r0, 600 50 | RJMP begin 51 | 52 | SLEEP 53 | 54 | 55 | -------------------------------------------------------------------------------- /tools/src/glerror.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | #include "glerror.hpp" 5 | #include "config_main.hpp" 6 | 7 | #include 8 | #include 9 | 10 | namespace trillek { 11 | 12 | void tr_check_gl_error(const char *file, int line) { 13 | #ifndef NDEBUG 14 | GLenum err (glGetError()); 15 | unsigned count =0; 16 | while(err!=GL_NO_ERROR) { 17 | std::string error; 18 | 19 | switch(err) { 20 | case GL_INVALID_OPERATION: 21 | error="INVALID_OPERATION"; 22 | break; 23 | case GL_INVALID_ENUM: 24 | error="INVALID_ENUM"; 25 | break; 26 | case GL_INVALID_VALUE: 27 | error="INVALID_VALUE"; 28 | break; 29 | case GL_OUT_OF_MEMORY: 30 | error="OUT_OF_MEMORY"; 31 | break; 32 | case GL_INVALID_FRAMEBUFFER_OPERATION: 33 | error="INVALID_FRAMEBUFFER_OPERATION"; 34 | break; 35 | default: 36 | error="UNKNOW_ERROR"; 37 | } 38 | std::cerr << "#" << count << " " << err << ": GL_" << error.c_str() 39 | << " - " << file << ":" << line << std::endl; 40 | err=glGetError(); 41 | count++; 42 | } 43 | #endif 44 | } 45 | } // End of namespace trillek 46 | 47 | -------------------------------------------------------------------------------- /include/devices/beeper.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Virtual Computer embeded device Beeper 3 | * \file beeper.hpp 4 | * \copyright LGPL v3 5 | * 6 | */ 7 | #ifndef __BEEPER_HPP_ 8 | #define __BEEPER_HPP_ 1 9 | 10 | #include "../types.hpp" 11 | #include "../addr_listener.hpp" 12 | 13 | #include 14 | 15 | namespace trillek { 16 | namespace computer { 17 | 18 | /** 19 | * Implements a embed beeper on the Virtual Computer 20 | */ 21 | class Beeper : public AddrListener { 22 | public: 23 | 24 | DECLDIR Beeper(); 25 | DECLDIR virtual ~Beeper(); 26 | 27 | virtual Byte ReadB (DWord addr); 28 | virtual Word ReadW (DWord addr); 29 | virtual DWord ReadDW (DWord addr); 30 | 31 | virtual void WriteB (DWord addr, Byte val); 32 | virtual void WriteW (DWord addr, Word val); 33 | virtual void WriteDW (DWord addr, DWord val); 34 | 35 | void Reset (); 36 | 37 | /** 38 | * /brief Assing a function to be called when Freq is changed 39 | * /param f_changed function to be called 40 | */ 41 | DECLDIR void SetFreqChangedCB(std::function f_changed); 42 | 43 | private: 44 | 45 | DWord freq; 46 | 47 | std::function f_changed; 48 | }; 49 | 50 | } // End of namespace computer 51 | } // End of namespace trillek 52 | 53 | #endif // __BEEPER_HPP_ 54 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | 2 | # version format 3 | version: 0.6.0 {branch}-{build} 4 | 5 | # branches to build 6 | branches: 7 | # blacklist 8 | except: 9 | - gh-pages 10 | 11 | #---------------------------------# 12 | # environment configuration # 13 | #---------------------------------# 14 | 15 | # Operating system (build VM template) 16 | os: Windows Server 2012 17 | 18 | # scripts that are called at very beginning, before repo cloning 19 | init: 20 | - git config --global core.autocrlf input 21 | 22 | # clone directory 23 | clone_folder: c:\projects\trillek-vcomputer-module 24 | 25 | # scripts that run after cloning repository 26 | install: 27 | - cmd: cd c:\projects\trillek-vcomputer-module\ 28 | - ps: c:\projects\trillek-vcomputer-module\prebuild.ps1 29 | 30 | # build Configuration, i.e. Debug, Release, etc. 31 | configuration: Debug 32 | 33 | build_script: 34 | - cmd: cd c:\projects\trillek-vcomputer-module\ 35 | - ps: c:\projects\trillek-vcomputer-module\build.ps1 36 | 37 | test_script: 38 | - cmd: cd c:\projects\trillek-vcomputer-module\bin\Debug 39 | - cmd: dir 40 | - cmd: unit_test.exe 41 | 42 | on_success: 43 | - cmd: cd c:\projects\trillek-vcomputer-module\ 44 | - cmd: msbuild PACKAGE.vcxproj /p:Configuration=Debug /verbosity:minimal /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" 45 | -------------------------------------------------------------------------------- /cmake/GetGitRevisionDescription.cmake.in: -------------------------------------------------------------------------------- 1 | # 2 | # Internal file for GetGitRevisionDescription.cmake 3 | # 4 | # Requires CMake 2.6 or newer (uses the 'function' command) 5 | # 6 | # Original Author: 7 | # 2009-2010 Ryan Pavlik 8 | # http://academic.cleardefinition.com 9 | # Iowa State University HCI Graduate Program/VRAC 10 | # 11 | # Copyright Iowa State University 2009-2010. 12 | # Distributed under the Boost Software License, Version 1.0. 13 | # (See accompanying file LICENSE_1_0.txt or copy at 14 | # http://www.boost.org/LICENSE_1_0.txt) 15 | 16 | set(HEAD_HASH) 17 | 18 | file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) 19 | 20 | string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) 21 | if(HEAD_CONTENTS MATCHES "ref") 22 | # named branch 23 | string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") 24 | if(EXISTS "@GIT_DIR@/${HEAD_REF}") 25 | configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) 26 | elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}") 27 | configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) 28 | set(HEAD_HASH "${HEAD_REF}") 29 | endif() 30 | else() 31 | # detached HEAD 32 | configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) 33 | endif() 34 | 35 | if(NOT HEAD_HASH) 36 | file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) 37 | string(STRIP "${HEAD_HASH}" HEAD_HASH) 38 | endif() 39 | -------------------------------------------------------------------------------- /cmake/FindGTEST.cmake: -------------------------------------------------------------------------------- 1 | # Find gtest 2 | # Find the gtest includes and library 3 | # 4 | # GTEST_INCLUDE_DIRS - where to find gtest/gtest.h, etc. 5 | # GTEST_LIBRARIES - List of libraries when using gtest. 6 | # GTEST_FOUND - True if gtest found. 7 | # 8 | # Based on the FindSOIL.cmake module. 9 | 10 | IF (GTEST_INCLUDE_DIR) 11 | # Already in cache, be silent 12 | SET(GTEST_FIND_QUIETLY TRUE) 13 | ENDIF (GTEST_INCLUDE_DIR) 14 | 15 | FIND_PATH( GTEST_INCLUDE_DIR 16 | NAMES gtest/gtest.h 17 | HINTS 18 | $ENV{GTEST_ROOT}/include 19 | ${GTEST_ROOT}/include 20 | PATHS /usr/install 21 | PATH_SUFFIXES gtest-1.7.0/include gtest-1.7.0) 22 | 23 | FIND_LIBRARY( GTEST_LIBRARY 24 | NAMES gtest 25 | HINTS 26 | $ENV{GTEST_ROOT} 27 | ${GTEST_ROOT} 28 | PATHS /usr/lib /usr/lib64 /usr/lib32 /usr/local/lib 29 | PATH_SUFFIXES x86 x64 amd64 lib64) 30 | 31 | # Per-recommendation 32 | SET(GTEST_INCLUDE_DIRS "${GTEST_INCLUDE_DIR}") 33 | SET(GTEST_LIBRARIES "${GTEST_LIBRARY}") 34 | 35 | # handle the QUIETLY and REQUIRED arguments and set GTEST_FOUND to TRUE if 36 | # all listed variables are TRUE 37 | INCLUDE(FindPackageHandleStandardArgs) 38 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTEST DEFAULT_MSG GTEST_LIBRARIES GTEST_INCLUDE_DIRS) 39 | 40 | include_directories("${GTEST_INCLUDE_DIRS}") 41 | MARK_AS_ADVANCED( GTEST_LIBRARY GTEST_INCLUDE_DIR ) 42 | -------------------------------------------------------------------------------- /src/tr3200/tr3200_cycles.inc: -------------------------------------------------------------------------------- 1 | // Look-uptable for cycle counts in function of OpCode 2 | // v 0.4.2 3 | // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, 4 | 1, 4, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x1X 5 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x1X 6 | 3, 3, 3, 3, 3, 3, 4, 3, 4, 6, 1, 1, 1, 1, 1, 1, // 0x2X 7 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x3X 8 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 1, 1, 1, // 0x4X 9 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x5X 10 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x6X 11 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, // 0x7X 12 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 20, // 0x8X 13 | 30, 25, 35, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, // 0x9X 14 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xAX 15 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xBX 16 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xCX 17 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xDX 18 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xEX 19 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xFX 20 | 21 | -------------------------------------------------------------------------------- /cmake/Platform.cmake: -------------------------------------------------------------------------------- 1 | if (CMAKE_HOST_APPLE) 2 | set(trillek_vcomputer_modulue_SEARCH_PATHS 3 | /usr 4 | /Applications/Xcode.app/Contents/Developer/Platforms.MacOSX.platform/Developer/SDKs 5 | /Library/Frameworks 6 | /usr/local 7 | /opt/local 8 | ) 9 | INCLUDE_DIRECTORIES(/usr/include) 10 | INCLUDE_DIRECTORIES(/usr/local/include) 11 | else (CMAKE_HOST_APPLE) 12 | # OS X is a Unix, but it's not a normal Unix as far as search paths go. 13 | if (CMAKE_HOST_UNIX) 14 | set(trillek_vcomputer_modulue_SEARCH_PATHS 15 | /usr 16 | /usr/local 17 | /opt/local 18 | ) 19 | endif (CMAKE_HOST_UNIX) 20 | endif (CMAKE_HOST_APPLE) 21 | 22 | #------------------------------------------------------------------------------ 23 | # VS201x stuff 24 | 25 | # If we are on windows add in the local search directories as well. 26 | IF (WIN32 AND NOT MINGW) # Windows 27 | SET(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} ${CMAKE_SOURCE_DIR}/lib/include/) 28 | INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/lib/include/") 29 | IF (CMAKE_CL_64) 30 | LINK_DIRECTORIES("${CMAKE_SOURCE_DIR}/lib/x64/debug" "${CMAKE_SOURCE_DIR}/lib/x64/release") 31 | SET(CMAKE_LIBRARY_PATH ${CMAKE_SOURCE_DIR}/lib/x64/debug ${CMAKE_SOURCE_DIR}/lib/x64/release) 32 | ELSE (CMAKE_CL_64) 33 | LINK_DIRECTORIES("${CMAKE_SOURCE_DIR}/lib/x86/debug" "${CMAKE_SOURCE_DIR}/lib/x86/release") 34 | SET(CMAKE_LIBRARY_PATH ${CMAKE_SOURCE_DIR}/lib/x86/debug ${CMAKE_SOURCE_DIR}/lib/x86/release) 35 | ENDIF (CMAKE_CL_64) 36 | ENDIF (WIN32 AND NOT MINGW) 37 | -------------------------------------------------------------------------------- /src/auxiliar.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Virtual Computer Auxiliar functions 3 | * \file auxiliar.cpp 4 | * \copyright LGPL v3 5 | * 6 | * Some auciliar functions and methods 7 | */ 8 | 9 | #include "auxiliar.hpp" 10 | 11 | #include "vcomputer.hpp" 12 | #include "vs_fix.hpp" 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | namespace trillek { 19 | namespace computer { 20 | 21 | int LoadROM (const std::string& filename, Byte* rom) { 22 | assert(rom != nullptr); 23 | 24 | int count; 25 | try { 26 | std::fstream f(filename, std::ios::in | std::ios::binary); 27 | if ( !f.is_open() ) { 28 | return -1; 29 | } 30 | count = LoadROM(f, rom); 31 | 32 | } 33 | catch (...) { 34 | count = -1; 35 | } 36 | 37 | return count; 38 | } // LoadROM 39 | 40 | 41 | int LoadROM (std::istream& stream, Byte* rom) { 42 | assert(rom != nullptr); 43 | 44 | int count; 45 | try { 46 | size_t size; 47 | 48 | auto begin = stream.tellg(); 49 | stream.seekg (0, std::ios::end); 50 | auto end = stream.tellg(); 51 | stream.seekg (0, std::ios::beg); 52 | 53 | size = end - begin; 54 | size = size > (MAX_ROM_SIZE) ? (MAX_ROM_SIZE) : size; 55 | 56 | stream.read(reinterpret_cast(rom), size); 57 | count = size; 58 | } 59 | catch (...) { 60 | count = -1; 61 | } 62 | 63 | return count; 64 | } // LoadROM 65 | 66 | } // end of namespace computer 67 | } // end of namespace trillek 68 | -------------------------------------------------------------------------------- /tools/config_main.hpp.in: -------------------------------------------------------------------------------- 1 | /** 2 | * Trillek Virtual Computer - config_main.hpp 3 | * Compilation time generated stuff related to version, OS, etc... 4 | * Used by main executable 5 | */ 6 | 7 | #ifndef ___CONFIG_MAIN_HPP__ 8 | #define ___CONFIG_MAIN_HPP__ 1 9 | 10 | // OpenGL stuff 11 | #define GLFW3_ENABLE @GLFW3_ENABLE@ 12 | #if GLFW3_ENABLE == 0 13 | #undef GLFW3_ENABLE 14 | #else 15 | #ifdef __APPLE__ 16 | #include 17 | #define GLFW_INCLUDE_GLCOREARB 18 | #include 19 | // Needed so we can disable retina support for our window. 20 | #define GLFW_EXPOSE_NATIVE_COCOA 1 21 | #define GLFW_EXPOSE_NATIVE_NSGL 1 22 | #include 23 | // We can't just include objc/runtime.h and objc/message.h because glfw is too forward thinking for its own good. 24 | typedef void* SEL; 25 | extern "C" id objc_msgSend(id self, SEL op, ...); 26 | extern "C" SEL sel_getUid(const char *str); 27 | 28 | #else 29 | #include 30 | 31 | #ifndef __unix 32 | #include 33 | #endif 34 | #include 35 | #endif 36 | 37 | #ifndef GLM_FORCE_RADIANS 38 | #define GLM_FORCE_RADIANS // Removes anoying messages of depracated angles on degress 39 | #endif 40 | #include 41 | #include 42 | 43 | #endif 44 | 45 | // OpenAL stuff 46 | #define OPENAL_ENABLE @OPENAL_ENABLE@ 47 | #if OPENAL_ENABLE == 0 48 | #undef OPENAL_ENABLE 49 | #endif 50 | 51 | #endif // ___CONFIG_MAIN_HPP__ 52 | -------------------------------------------------------------------------------- /include/devices/nvram.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Virtual Computer Random No Volatile RAM (NVRAM) 3 | * \file nvram.hpp 4 | * \copyright LGPL v3 5 | * 6 | * Implementation of NVRAM 7 | */ 8 | #ifndef __NVRAM_HPP_ 9 | #define __NVRAM_HPP_ 1 10 | 11 | #include "../types.hpp" 12 | #include "../addr_listener.hpp" 13 | 14 | #include 15 | #include 16 | 17 | namespace trillek { 18 | namespace computer { 19 | 20 | class NVRAM : public AddrListener { 21 | public: 22 | 23 | NVRAM(); 24 | virtual ~NVRAM(); 25 | 26 | virtual Byte ReadB (DWord addr); 27 | virtual Word ReadW (DWord addr); 28 | virtual DWord ReadDW (DWord addr); 29 | 30 | virtual void WriteB (DWord addr, Byte val); 31 | virtual void WriteW (DWord addr, Word val); 32 | virtual void WriteDW (DWord addr, DWord val); 33 | 34 | void Reset (); 35 | 36 | /** 37 | * Returns true if there is a unsaved change on NVRAM 38 | */ 39 | bool isDirty(); 40 | 41 | /** 42 | * Fills NVRAM with data from a input stream 43 | * \param stream Stream were to read the data 44 | * \return True if read data from the strean 45 | */ 46 | bool Load (std::istream& stream); 47 | 48 | /** 49 | * Saves NVRAM data to a output stream 50 | * \param stream Stream were to write the data 51 | * \return True if writed data to the stream 52 | */ 53 | bool Save (std::ostream& stream); 54 | 55 | const static DWord BaseAddress = 0x11F000; 56 | private: 57 | 58 | Byte eprom[256]; 59 | bool dirty; 60 | }; 61 | 62 | } // End of namespace computer 63 | } // End of namespace trillek 64 | 65 | 66 | 67 | #endif // __NVRAM_HPP_ 68 | -------------------------------------------------------------------------------- /cmake/FindGLFW3.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Try to find GLFW library and include path. 3 | # Once done this will define 4 | # 5 | # GLFW3_FOUND 6 | # GLFW3_INCLUDE_PATH 7 | # GLFW3_LIBRARY 8 | # 9 | 10 | IF(WIN32) 11 | FIND_PATH( GLFW3_INCLUDE_PATH GLFW/glfw3.h 12 | $ENV{PROGRAMFILES}/GLFW/include 13 | ${GLFW_ROOT_DIR}/include 14 | DOC "The directory where GLFW/glfw3.h resides") 15 | 16 | FIND_LIBRARY( GLFW3_LIBRARY 17 | NAMES glfw3 glfw3dll 18 | PATHS 19 | $ENV{PROGRAMFILES}/GLFW/lib 20 | ${GLFW_ROOT_DIR}/lib 21 | PATH_SUFFIXES x64 amd64 22 | DOC "The GLFW library") 23 | IF(NOT GLFW3_DEBUG_LIBRARY AND GLFW3_LIBRARY) 24 | SET(GLFW3_DEBUG_LIBRARY ${GLFW3_LIBRARY}) 25 | ENDIF() 26 | ELSE(WIN32) 27 | FIND_PATH( GLFW3_INCLUDE_PATH GLFW/glfw3.h 28 | /usr/include 29 | /usr/local/include 30 | /sw/include 31 | /opt/local/include 32 | ${GLFW_ROOT_DIR}/include 33 | DOC "The directory where GLFW/glfw3.h resides") 34 | IF(APPLE) 35 | # For the case where GLFW is installed in a non-standard lib path such as /opt or /sw 36 | INCLUDE_DIRECTORIES( "${GLFW3_INCLUDE_PATH}" ) 37 | ENDIF(APPLE) 38 | 39 | FIND_LIBRARY( GLFW3_LIBRARY 40 | NAMES libglfw.so libglfw.so.3 libglfw.so.3.0 glfw.3 glfw3 41 | PATHS 42 | /usr/lib64 43 | /usr/lib 44 | /usr/local/lib64 45 | /usr/local/lib 46 | /sw/lib 47 | /opt/local/lib 48 | ${GLFW_ROOT_DIR}/lib 49 | DOC "The GLFW library") 50 | 51 | ENDIF(WIN32) 52 | 53 | set(GLFW3_INCLUDE_PATH ${GLFW3_INCLUDE_PATH}) 54 | set(GLFW3_LIBRARIES "${GLFW3_LIBRARY}") 55 | 56 | INCLUDE(FindPackageHandleStandardArgs) 57 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLFW3 DEFAULT_MESSAGE GLFW3_LIBRARIES GLFW3_INCLUDE_PATH) 58 | 59 | mark_as_advanced(GLFW3_LIBRARIES GLFW3_INCLUDE_PATH GLFW3_LIBRARY GLFW3_DEBUG_LIBRARY) 60 | -------------------------------------------------------------------------------- /tests/device_factory_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "device_factory.hpp" 6 | #include "device.hpp" 7 | 8 | class TestDevice : public trillek::computer::Device 9 | { 10 | public: 11 | TestDevice() { 12 | vcomp = nullptr; 13 | } 14 | 15 | void Reset() {} 16 | void SendCMD(trillek::Word) {} 17 | 18 | trillek::Byte DevType() const override {return 1; } 19 | trillek::Byte DevSubType() const override {return 2;} 20 | trillek::Byte DevID() const override {return 3;} 21 | trillek::DWord DevVendorID() const override {return 4;} 22 | 23 | void GetState(void*, std::size_t&) const override {} 24 | bool SetState(const void *ptr, std::size_t size) override {return true;} 25 | 26 | static Device* CreateNew() { return new TestDevice(); } 27 | }; 28 | 29 | TEST(DeviceFactory, DefaultDevices) 30 | { 31 | trillek::computer::registerDefaultDevices(); 32 | 33 | std::shared_ptr tda = trillek::computer::DeviceFactory::GetInstance()->CreateDevice(0x0E, 0x01, 0x01, 0x1C6C8B36); 34 | 35 | ASSERT_TRUE(tda.get() != nullptr); 36 | 37 | trillek::computer::DeviceFactory::Destroy(); 38 | } 39 | 40 | TEST(DeviceFactory, GlobalTest) 41 | { 42 | trillek::computer::DeviceFactory::GetInstance()->RegisterNewDevice(trillek::computer::DeviceRecord(1, 2, 3, 4, &TestDevice::CreateNew)); 43 | 44 | std::shared_ptr test_dev = trillek::computer::DeviceFactory::GetInstance()->CreateDevice(1, 2, 3, 4); 45 | ASSERT_TRUE(test_dev.get() != nullptr); 46 | trillek::computer::DeviceFactory::GetInstance()->UnregisterDevice(1, 2, 3, 4); 47 | std::shared_ptr test_dev2 = trillek::computer::DeviceFactory::GetInstance()->CreateDevice(1, 2, 3, 4); 48 | ASSERT_TRUE(test_dev2 == nullptr); 49 | } 50 | -------------------------------------------------------------------------------- /tests/gkeyb_test.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Unit tests of Generic keyboard device 3 | */ 4 | #include "devices/gkeyb.hpp" 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | // Check if E register returns buffer size 13 | TEST(GKeyboard, E_reg) { 14 | using namespace trillek::computer::gkeyboard; 15 | 16 | GKeyboardDev gk; 17 | gk.Reset(); 18 | 19 | ASSERT_EQ(0, gk.E()); 20 | 21 | gk.SendKeyEvent ( SCANCODES::SCAN_MINUS, '-', 0 ); 22 | ASSERT_EQ(1, gk.E()); 23 | 24 | gk.SendKeyEvent ( SCANCODES::SCAN_SPACE, ' ', 0 ); 25 | ASSERT_EQ(2, gk.E()); 26 | 27 | } 28 | 29 | // Check if sending and pulling an event, works 30 | TEST(GKeyboard, SEND_PULL_event) { 31 | using namespace trillek::computer::gkeyboard; 32 | 33 | GKeyboardDev gk; 34 | gk.Reset(); 35 | 36 | for (unsigned c=0; c < 255; c++) { 37 | for (unsigned status=0; status <= 7; status++) { 38 | // We use a fake scan code but allow to test more rich value set 39 | gk.SendKeyEvent ( 0xFFFF ^ c, c, status ); 40 | ASSERT_EQ(1, gk.E()); 41 | 42 | gk.SendCMD(0x0001); 43 | ASSERT_EQ(0, gk.E()) << "PULL-KEY failed to removed a event from buffer"; 44 | ASSERT_EQ(c, gk.A()) << "Key Code mismatch"; 45 | ASSERT_EQ(0xFFFF ^c, gk.B()) << "ScanCode mismatch"; 46 | ASSERT_EQ(status, gk.C()) << "Status bits mismatch"; 47 | } 48 | } 49 | } 50 | 51 | // Check if sending and pulling an event, works 52 | TEST(GKeyboard, Fill_buffer) { 53 | using namespace trillek::computer::gkeyboard; 54 | 55 | GKeyboardDev gk; 56 | gk.Reset(); 57 | 58 | for (unsigned i=0; i < BSIZE; i++) { 59 | gk.SendKeyEvent ( SCANCODES::SCAN_MINUS, '-', 0 ); 60 | ASSERT_EQ(i+1, gk.E()); 61 | } 62 | 63 | gk.SendKeyEvent ( SCANCODES::SCAN_SPACE, ' ', 0 ); 64 | ASSERT_EQ(BSIZE, gk.E()) << "Buffer bigger that BSIZE (= 64)"; 65 | 66 | } 67 | 68 | -------------------------------------------------------------------------------- /bench_FX4200.txt: -------------------------------------------------------------------------------- 1 | ~/R/t/build (master) $ ./benchmark ../asm/tr3200/test.ffi ../asm/tr3200/hello.ffi ../asm/tr3200/type1.ffi ../asm/tr3200/clock.ffi 2 | Opening file ../asm/tr3200/test.ffi 3 | Read 1046 bytes and stored in ROM 4 | Opening file ../asm/tr3200/hello.ffi 5 | Read 481 bytes and stored in ROM 6 | Opening file ../asm/tr3200/type1.ffi 7 | Read 1328 bytes and stored in ROM 8 | Opening file ../asm/tr3200/clock.ffi 9 | Read 740 bytes and stored in ROM 10 | Runing : 11 | ~1% @ 1MHz 12 | ~10% @ 0.5MHz 13 | ~20% @ 0.2MHz 14 | ~59% @ 0.1MHz 15 | ~10% @ 0.01MHz 16 | Randomizing every CPU! 17 | Executing a random number of cycles from 1 to 255 18 | Running 1000 CPUs ! 19 | Running 50000 cycles in 46.000000 ms Ttick 0.000920 ms Tclk 0.001000 ms Speed of 108.695652 % 20 | Running 50000 cycles in 40.000000 ms Ttick 0.000800 ms Tclk 0.001000 ms Speed of 125.000000 % 21 | Running 50000 cycles in 41.000000 ms Ttick 0.000820 ms Tclk 0.001000 ms Speed of 121.951220 % 22 | Running 50000 cycles in 41.000000 ms Ttick 0.000820 ms Tclk 0.001000 ms Speed of 121.951220 % 23 | Running 50000 cycles in 42.000000 ms Ttick 0.000840 ms Tclk 0.001000 ms Speed of 119.047619 % 24 | Running 50000 cycles in 41.000000 ms Ttick 0.000820 ms Tclk 0.001000 ms Speed of 121.951220 % 25 | Running 50000 cycles in 41.000000 ms Ttick 0.000820 ms Tclk 0.001000 ms Speed of 121.951220 % 26 | Running 50000 cycles in 41.000000 ms Ttick 0.000820 ms Tclk 0.001000 ms Speed of 121.951220 % 27 | Running 50000 cycles in 41.000000 ms Ttick 0.000820 ms Tclk 0.001000 ms Speed of 121.951220 % 28 | Running 50000 cycles in 41.000000 ms Ttick 0.000820 ms Tclk 0.001000 ms Speed of 121.951220 % 29 | Running 50000 cycles in 41.000000 ms Ttick 0.000820 ms Tclk 0.001000 ms Speed of 121.951220 % 30 | Running 50000 cycles in 41.000000 ms Ttick 0.000820 ms Tclk 0.001000 ms Speed of 121.951220 % 31 | Running 50000 cycles in 41.000000 ms Ttick 0.000820 ms Tclk 0.001000 ms Speed of 121.951220 % 32 | 33 | -------------------------------------------------------------------------------- /include/devices/timer.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Virtual Computer Timer 3 | * \file timer.hpp 4 | * \copyright LGPL v3 5 | * 6 | * Implementation of Timer embed device 7 | */ 8 | #ifndef __TIMER_HPP_ 9 | #define __TIMER_HPP_ 1 10 | 11 | #include "../types.hpp" 12 | #include "../addr_listener.hpp" 13 | 14 | namespace trillek { 15 | namespace computer { 16 | 17 | class Timer : public AddrListener { 18 | 19 | public: 20 | 21 | Timer (); 22 | virtual ~Timer(); 23 | 24 | virtual Byte ReadB (DWord addr); 25 | virtual Word ReadW (DWord addr); 26 | virtual DWord ReadDW (DWord addr); 27 | 28 | virtual void WriteB (DWord addr, Byte val); 29 | virtual void WriteW (DWord addr, Word val); 30 | virtual void WriteDW (DWord addr, DWord val); 31 | 32 | void Reset (); 33 | 34 | /** 35 | * Executes N Device clock cycles. 36 | * Here resides the code that is executed every Device Clock tick. 37 | * @param n Number of clock ticks executing 38 | * @param delta Number milliseconds since the last call 39 | */ 40 | void Tick (unsigned n = 1, const double delta = 0); 41 | 42 | /** 43 | * Checks if the device is trying to generate an interrupt 44 | * @param msg The interrupt message will be writen here 45 | * @return True if is generating a new interrupt 46 | */ 47 | bool DoesInterrupt (Word& msg); 48 | 49 | /** 50 | * Informs to the device that his generated interrupt was accepted by the 51 | **CPU 52 | */ 53 | void IACK (); 54 | 55 | DWord tmr0; /// Timer 0 56 | DWord tmr1; /// Timer 1 57 | 58 | DWord re0; /// Reload value of Timer 0 59 | DWord re1; /// Reload value of Timer 1 60 | 61 | Byte cfg; /// Config byte of PIT 62 | 63 | bool do_int_tmr0; /// Try to thorow interrupt of TMR0 ? 64 | bool do_int_tmr1; /// Try to thorow interrupt of TMR1 ? 65 | }; 66 | 67 | } // End of namespace computer 68 | } // End of namespace trillek 69 | 70 | #endif // __TIMER_HPP_ 71 | -------------------------------------------------------------------------------- /include/enum_and_ctrl_blk.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Enumeration and Control/status address Block 3 | * \file enum_and_ctrl_blk.hpp 4 | * \copyright LGPL v3 5 | * 6 | */ 7 | #ifndef __ENUMANDCTROLBLK_HPP_ 8 | #define __ENUMANDCTROLBLK_HPP_ 1 9 | 10 | #include "types.hpp" 11 | #include "vc_dll.hpp" 12 | 13 | #include "device.hpp" 14 | #include "addr_listener.hpp" 15 | 16 | #include 17 | #include 18 | 19 | namespace trillek { 20 | namespace computer { 21 | 22 | /** 23 | * An specialized Address Listener used by VComputer to implement 24 | * Enumeration and Control registers in a slot 25 | */ 26 | class DECLDIR EnumAndCtrlBlk : public AddrListener { 27 | public: 28 | 29 | /** 30 | * Builds the Enumeartion and Control register block for a device plugged 31 | * in slot XX 32 | */ 33 | EnumAndCtrlBlk (unsigned slot, Device* dev); 34 | 35 | virtual ~EnumAndCtrlBlk () { 36 | } 37 | 38 | /** 39 | * Returns the address Range used by this register block 40 | */ 41 | Range GetRange () const; 42 | 43 | Byte ReadB (DWord addr); 44 | Word ReadW (DWord addr); 45 | DWord ReadDW (DWord addr); 46 | 47 | void WriteB (DWord addr, Byte val); 48 | void WriteW (DWord addr, Word val); 49 | void WriteDW (DWord addr, DWord val); 50 | 51 | private: 52 | 53 | unsigned slot; /// Slot number 54 | Device* dev; /// Ptr to the device 55 | 56 | DWord cmd; /// Buffer used when a byte write hapens in CMD 57 | DWord a; /// Buffer used when a byte write hapens in A 58 | DWord b; /// Buffer used when a byte write hapens in B 59 | DWord c; /// Buffer used when a byte write hapens in C 60 | DWord d; /// Buffer used when a byte write hapens in D 61 | DWord e; /// Buffer used when a byte write hapens in E 62 | }; 63 | 64 | typedef std::tuple, EnumAndCtrlBlk*, int32_t> device_t; /// Storage of a device 65 | 66 | } // End of namespace computer 67 | } // End of namespace trillek 68 | 69 | #endif // __ENUMANDCTROLBLK_HPP_ 70 | -------------------------------------------------------------------------------- /asm/tr3200/beep.lst: -------------------------------------------------------------------------------- 1 | 2 00100000 .ORG 0x100000 2 | 4 00100000 MOV %sp,0x020000 0000F44000000200 3 | 8 00100008 MOV %r0,932 A4038040 4 | 9 0010000c STOREW 0x11E020,%r0 0000C04920E01100 5 | 11 00100014 MOV %r1,0 00008440 6 | 12 00100018 wait_loop0: 7 | 13 00100018 ADD %r0,%r0,0 00008084 8 | 14 0010001c ADD %r1,%r1,1 01408484 9 | 15 00100020 IFL %r1,8000 401F8472 10 | 16 00100024 RJMP wait_loop0 FCFFBF27 11 | 18 00100028 MOV %r0,0 00008040 12 | 19 0010002c STOREW 0x11E020,%r0 0000C04920E01100 13 | 21 00100034 MOV %r1,0 00008440 14 | 22 00100038 wait_loop1: 15 | 23 00100038 ADD %r0,%r0,0 00008084 16 | 24 0010003c ADD %r1,%r1,1 01408484 17 | 25 00100040 IFL %r1,8000 401F8472 18 | 26 00100044 RJMP wait_loop1 FCFFBF27 19 | 32 00100048 MOV %r0,600 58028040 20 | 33 0010004c begin: 21 | 34 0010004c STOREW 0x11E020,%r0 0000C04920E01100 22 | 36 00100054 MOV %r1,0 00008440 23 | 37 00100058 wait_loop2: 24 | 38 00100058 ADD %r0,%r0,0 00008084 25 | 39 0010005c ADD %r1,%r1,1 01408484 26 | 40 00100060 IFL %r1,1000 E8038472 27 | 41 00100064 RJMP wait_loop2 FCFFBF27 28 | 43 00100068 SUB %r0,%r0,10 0A008086 29 | 44 0010006c IFL %r0,500 F4018072 30 | 45 00100070 RJMP again 01008027 31 | 46 00100074 RJMP begin F5FFBF27 32 | 48 00100078 again: 33 | 49 00100078 MOV %r0,600 58028040 34 | 50 0010007c RJMP begin F3FFBF27 35 | 52 00100080 SLEEP 00000000 36 | Symbols: 37 | 00100058 wait_loop2 38 | 00100018 wait_loop0 39 | 00100038 wait_loop1 40 | 0010004c begin 41 | 00100078 again 42 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | sudo: false 4 | 5 | cache: 6 | directories: 7 | - $HOME/lib 8 | 9 | matrix: 10 | include: 11 | - os: linux 12 | compiler: gcc 13 | addons: 14 | apt: 15 | sources: ['ubuntu-toolchain-r-test'] 16 | packages: 17 | - gcc-7 18 | - g++-7 19 | - libx11-dev 20 | - libgl1-mesa-dev 21 | - xorg-dev 22 | - libglu1-mesa-dev 23 | - libglew-dev 24 | - libopenal-dev 25 | env: COMPILER=g++-7 26 | 27 | - os: linux 28 | compiler: clang 29 | addons: 30 | apt: 31 | sources: 32 | - ubuntu-toolchain-r-test 33 | - llvm-toolchain-trusty-7 34 | packages: 35 | - clang-7 36 | - libx11-dev 37 | - libgl1-mesa-dev 38 | - xorg-dev 39 | - libglu1-mesa-dev 40 | - libglew-dev 41 | - libopenal-dev 42 | env: COMPILER=clang++-7 43 | 44 | before_install: 45 | - git submodule update --init 46 | - export CXX="$COMPILER" 47 | - ${CXX} --version 48 | - echo $LANG 49 | - echo $LC_ALL 50 | - cmake --version 51 | - ./travis/install_deps.sh 52 | - export GLFW_ROOT_DIR=$HOME/lib/$COMPILER/glfw-lib 53 | - export GLM_ROOT_DIR=$HOME/lib/$COMPILER/glm 54 | - export GTEST_ROOT=$HOME/lib/$COMPILER/googletest-release-1.7.0 55 | 56 | install: 57 | 58 | before_script: 59 | - mkdir -p build 60 | - cd build 61 | - cmake -DCMAKE_BUILD_TYPE=Debug .. 62 | 63 | script: 64 | - make 65 | - cd bin 66 | - ./unit_test 67 | - cd .. 68 | - make package 69 | 70 | notifications: 71 | irc: 72 | channels: 73 | - "chat.freenode.net#trillek" 74 | on_success: change 75 | on_failure: always 76 | -------------------------------------------------------------------------------- /include/addr_listener.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Defines an interface for Address Listeners 3 | * \file AddrListener.hpp 4 | * \copyright LGPL v3 5 | * 6 | */ 7 | #ifndef __ADDRLISTENER_HPP_ 8 | #define __ADDRLISTENER_HPP_ 1 9 | 10 | #include "types.hpp" 11 | #include "vc_dll.hpp" 12 | 13 | #include 14 | 15 | namespace trillek { 16 | namespace computer { 17 | 18 | /** 19 | * Interface for a Address Listener 20 | */ 21 | class DECLDIR AddrListener { 22 | public: 23 | 24 | virtual ~AddrListener() { 25 | } 26 | 27 | virtual Byte ReadB (DWord addr) = 0; 28 | virtual Word ReadW (DWord addr) = 0; 29 | virtual DWord ReadDW (DWord addr) = 0; 30 | 31 | virtual void WriteB (DWord addr, Byte val) = 0; 32 | virtual void WriteW (DWord addr, Word val) = 0; 33 | virtual void WriteDW (DWord addr, DWord val) = 0; 34 | }; 35 | 36 | /** 37 | * Range of 24bit addresses/address 38 | * Used to store/search an AddrListener stored in a tree 39 | */ 40 | struct DECLDIR Range { 41 | DWord start; 42 | DWord end; 43 | 44 | /** 45 | * Build a Range for listening/search a single address 46 | * Must be a 24 bit address 47 | * @param addr Address 48 | */ 49 | Range (DWord addr) : start(addr), end(addr) { 50 | assert(addr <= 0xFFFFFF); 51 | } 52 | 53 | /** 54 | * Build a Range for listening a range of addresses. 55 | * Must be a 24 bit address and start <= end 56 | * @param start Begin address 57 | * @param end End address 58 | */ 59 | Range (DWord start, DWord end) : start(start & 0xFFFFFF), end(end & 0xFFFFFF) { 60 | assert (start <= end); 61 | assert (end <= 0xFFFFFF); 62 | } 63 | 64 | /** 65 | * Comparation operator required by std::map 66 | * We forbid overlaping ranges, so comparing two ranges for weak ordering is 67 | **easy 68 | */ 69 | bool operator<(const Range& other) const { 70 | return (end < other.start); 71 | } 72 | }; 73 | 74 | } // End of namespace computer 75 | } // End of namespace trillek 76 | 77 | #endif // __ADDRLISTENER_HPP_ 78 | -------------------------------------------------------------------------------- /tools/include/al_engine.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /*! 3 | * \brief OpenAL/Alure Stuff of the test/toy emulator 4 | * \file al_engine.hpp 5 | * \copyright LGPL v3 6 | * 7 | * OpenAL Stuff of the test/toy emulator. 8 | */ 9 | 10 | #include "config_main.hpp" 11 | 12 | #include 13 | 14 | #ifdef OPENAL_ENABLE 15 | 16 | #ifdef __APPLE__ 17 | #include 18 | #include 19 | #include 20 | #else 21 | #include 22 | #include 23 | #include 24 | #endif 25 | 26 | 27 | #include "types.hpp" 28 | 29 | #include "Blip_Buffer.h" 30 | 31 | namespace AlEngine { 32 | 33 | const static unsigned AL_BUFFERS = 4; 34 | const static unsigned SR = 44100; //! Sampling rate 35 | 36 | class AlEngine { 37 | public: 38 | AlEngine(); 39 | 40 | ~AlEngine(); 41 | 42 | bool Init(); 43 | void Shutdown(); 44 | 45 | void Tone(trillek::Word freq); 46 | 47 | void Update(); 48 | 49 | void Play(); 50 | void Pause(); 51 | void Stop(); 52 | 53 | void Test(); 54 | 55 | void MasterGain(float gain); 56 | float MasterGain() const; 57 | 58 | private: 59 | 60 | 61 | float gain; /// Master volumen 62 | 63 | bool initiated; /// Flag to know if we properly initialized all 64 | bool source_created; /// Flag to know if we create sound source 65 | 66 | ALuint beep_source; /// Source point of the sound 67 | 68 | alureStream* stream; /// Alure Sound stream 69 | 70 | // Position of the source sound. 71 | const static ALfloat SourcePos[]; 72 | 73 | // Velocity of the source sound. 74 | const static ALfloat SourceVel[]; 75 | 76 | // Position of the listener. 77 | const static ALfloat ListenerPos[]; 78 | 79 | // Velocity of the listener. 80 | const static ALfloat ListenerVel[]; 81 | 82 | // Orientation of the listener. (first 3 elements are "at", second 3 are "up") 83 | const static ALfloat ListenerOri[]; 84 | 85 | 86 | }; 87 | 88 | } // End of Namespace AlEngine 89 | 90 | #endif 91 | 92 | -------------------------------------------------------------------------------- /cmake/FindGLEW.cmake: -------------------------------------------------------------------------------- 1 | # - Find the OpenGL Extension Wrangler Library (GLEW) 2 | # This module defines the following variables: 3 | # GLEW_INCLUDE_DIRS - include directories for GLEW 4 | # GLEW_LIBRARIES - libraries to link against GLEW 5 | # GLEW_FOUND - true IF GLEW has been found and can be used 6 | 7 | #============================================================================= 8 | # Copyright 2012 Benjamin Eikel 9 | # 10 | # Distributed under the OSI-approved BSD License (the "License"); 11 | # see accompanying file Copyright.txt for details. 12 | # 13 | # This software is distributed WITHOUT ANY WARRANTY; without even the 14 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15 | # See the License for more information. 16 | #============================================================================= 17 | # (To distribute this file outside of CMake, substitute the full 18 | # License text for the above reference.) 19 | 20 | find_path(GLEW_INCLUDE_DIR GL/glew.h) 21 | IF(USE_STATIC_GLEW) 22 | SET(GLEW_DEBUG_NAMES glew32sd) 23 | SET(GLEW_NAMES glew32s) 24 | add_definitions(-DGLEW_STATIC) 25 | ELSE(USE_STATIC_GLEW) 26 | SET(GLEW_DEBUG_NAMES glew32d) 27 | SET(GLEW_NAMES GLEW glew32 glew) 28 | ENDIF(USE_STATIC_GLEW) 29 | 30 | # Reset the variables so that find_library will rescan in case we changed from static to none (or vice versa). 31 | UNSET(GLEW_LIBRARY) 32 | UNSET(GLEW_DEBUG_LIBRARY) 33 | 34 | FIND_LIBRARY(GLEW_LIBRARY NAMES ${GLEW_NAMES} PATH_SUFFIXES x86 x64 amd64 lib64) 35 | FIND_LIBRARY(GLEW_DEBUG_LIBRARY NAMES ${GLEW_DEBUG_NAMES} PATH_SUFFIXES x86 x64 amd64 lib64) 36 | 37 | IF(NOT GLEW_DEBUG_LIBRARY AND GLEW_LIBRARY) 38 | SET(GLEW_DEBUG_LIBRARY ${GLEW_LIBRARY}) 39 | ENDIF(NOT GLEW_DEBUG_LIBRARY AND GLEW_LIBRARY) 40 | 41 | SET(GLEW_INCLUDE_DIRS ${GLEW_INCLUDE_DIR}) 42 | SET(GLEW_LIBRARIES debug ${GLEW_DEBUG_LIBRARY} optimized ${GLEW_LIBRARY}) 43 | 44 | INCLUDE(FindPackageHandleStandardArgs) 45 | FIND_PACKAGE_HANDLE_STANDARD_ARGS( GLEW 46 | DEFAULT_MSG 47 | GLEW_LIBRARIES 48 | GLEW_INCLUDE_DIR 49 | ) 50 | 51 | MARK_AS_ADVANCED(GLEW_INCLUDE_DIR GLEW_LIBRARY GLEW_DEBUG_LIBRARY) 52 | -------------------------------------------------------------------------------- /cmake/package.cmake.in: -------------------------------------------------------------------------------- 1 | # Per-generator CPack configuration file. See CPACK_PROJECT_CONFIG_FILE documented at 2 | # http://www.cmake.org/cmake/help/v2.8.12/cpack.html#variable:CPACK_PROJECT_CONFIG_FILE 3 | # 4 | # All common CPACK_* variables are set in CMakeLists.txt already. This file only 5 | # overrides some of these to provide package generator specific settings. 6 | 7 | # whether package contains all development files or only runtime files 8 | set (DEVEL @INSTALL_HEADERS@) 9 | 10 | # ------------------------------------------------------------------------------ 11 | # Mac OS X package 12 | if (CPACK_GENERATOR MATCHES "PackageMaker|DragNDrop") 13 | 14 | set (CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}") 15 | if (DEVEL) 16 | set (CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-devel") 17 | endif () 18 | set (CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-${CPACK_PACKAGE_VERSION}") 19 | 20 | # ------------------------------------------------------------------------------ 21 | # Debian package 22 | elseif (CPACK_GENERATOR MATCHES "DEB") 23 | 24 | set (CPACK_PACKAGE_FILE_NAME "lib${CPACK_PACKAGE_NAME}") 25 | if (DEVEL) 26 | set (CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-dev") 27 | else () 28 | set (CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}0") 29 | endif () 30 | set (CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}_${CPACK_PACKAGE_VERSION}-1_${CPACK_PACKAGE_ARCHITECTURE}") 31 | 32 | set (CPACK_DEBIAN_PACKAGE_DEPENDS) 33 | set (CPACK_DEBIAN_PACKAGE_SECTION "devel") 34 | set (CPACK_DEBIAN_PACKAGE_PRIORITY "optional") 35 | set (CPACK_DEBIAN_PACKAGE_HOMEPAGE "${CPACK_RPM_PACKAGE_URL}") 36 | set (CPACK_DEBIAN_PACKAGE_MAINTAINER "${CPACK_PACKAGE_VENDOR}") 37 | set (CPACK_DEBIAN_PACKAGE_ARCHITECTURE "${CPACK_PACKAGE_ARCHITECTURE}") 38 | 39 | # ------------------------------------------------------------------------------ 40 | # RPM package 41 | elseif (CPACK_GENERATOR MATCHES "RPM") 42 | 43 | set (CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}") 44 | if (DEVEL) 45 | set (CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-devel") 46 | endif () 47 | set (CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-${CPACK_PACKAGE_VERSION}-1.${CPACK_PACKAGE_ARCHITECTURE}") 48 | 49 | endif () 50 | -------------------------------------------------------------------------------- /asm/tr3200/hello.asm: -------------------------------------------------------------------------------- 1 | ; Hello World in TR3200 ASM 2 | .ORG 0x100000 ; This a ROM image, so jumps need to know the real address 3 | 4 | MOV %sp, 0x20000 ; Sets Stack Pointer to the end of the 128KiB RAM 5 | 6 | ; Code to find the first TDA plugged device 7 | MOV %r10, 0x10FF00 8 | begin_search_tda: 9 | ADD %r10, %r10, 0x100 10 | IFEQ %r10, 0x112100 ; Not found any TDA device 11 | JMP end 12 | 13 | LOADB %r0, %r10 14 | IFNEQ %r0, 0xFF ; Device Present ? 15 | JMP begin_search_tda 16 | 17 | ADD %r1, %r10, 1 18 | LOADB %r0, %r1 19 | IFNEQ %r0, 0x0E ; Is a Graphics device ? 20 | JMP begin_search_tda 21 | 22 | ADD %r1, %r10, 2 23 | LOADB %r0, %r1 24 | IFNEQ %r0, 0x01 ; Is TDA compatible ? 25 | JMP begin_search_tda 26 | 27 | end_search_tda: 28 | ; Configure TDA to use a text buffer in 0x001000 29 | ADD %r0, %r10, 0x0A 30 | 31 | MOV %r1, 0x001000 32 | STORE %r0, %r1 ; Set B:A to point to 0x001000 33 | 34 | ADD %r0, %r10, 0x08 35 | MOV %r1, 0 36 | STOREW %r0, %r1 ; Send command to point Text buffer to B:A address 37 | 38 | ; Clears the screen 39 | MOV %r0, 0x001000 40 | MOV %r1, 0xB0 ; Dark brown paper, Black Ink 41 | CALL clr_screen 42 | 43 | MOV %r1, 0xF0FD 44 | ADD %r0, %r10, 0x10 ; Activate cursor with blink 45 | STOREW %r0, %r1 46 | 47 | MOV %r1, 0x010A 48 | ADD %r0, %r10, 0x12 ; Cursor at Col 10, Row 1 49 | STOREW %r0, %r1 50 | 51 | ; Prints the string 52 | MOV %r1, 0x001000 ; %r1 ptr to text buffer 53 | MOV %r0, string ; %r0 ptr to string 54 | MOV %r2, 0x4F ; Dark blue paper, White Ink 55 | CALL print 56 | 57 | ; Prints the string at Rom 3, Column 3 58 | MOV %r0, 3 ; Row 3 59 | MOV %r1, 3 ; Column 3 60 | CALL get_offset_from_row_col 61 | ADD %r1, %r0, 0x001000 ; Adds the offset to the ptr to text buffer 62 | 63 | MOV %r0, string ; %r0 ptr to string 64 | MOV %r2, 0x78 ; Swamp paper, Yellow Ink 65 | CALL print 66 | 67 | end: 68 | SLEEP ; End of program 69 | 70 | 71 | .include "BROM.ainc" 72 | 73 | 74 | ;****************************************************************************** 75 | ; Const Data 76 | string: .DB "Hello world!", 0 ; ASCIIz string 77 | 78 | ;****************************************************************************** 79 | ; RAM data 80 | .ORG 0 81 | ; Nothing... 82 | -------------------------------------------------------------------------------- /src/devices/beeper.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * \brief Virtual Computer embeded device Beeper 3 | * \file beeper.hpp 4 | * \copyright LGPL v3 5 | * 6 | */ 7 | 8 | #include "devices/beeper.hpp" 9 | #include "vs_fix.hpp" 10 | 11 | namespace trillek { 12 | namespace computer { 13 | 14 | Beeper::Beeper () : freq(0), f_changed(nullptr) { 15 | } 16 | 17 | Beeper::~Beeper () { 18 | } 19 | 20 | Byte Beeper::ReadB (DWord addr) { 21 | if (addr == 0x11E020) { 22 | // LSB 23 | return freq; 24 | } 25 | else { 26 | // MSB 27 | return freq >> 8; 28 | } 29 | } 30 | 31 | Word Beeper::ReadW (DWord addr) { 32 | if (addr == 0x11E020) { 33 | return freq; 34 | } 35 | else { 36 | // Only MSB 37 | return freq >> 8; 38 | } 39 | } 40 | 41 | DWord Beeper::ReadDW (DWord addr) { 42 | if (addr == 0x11E020) { 43 | return freq; 44 | } 45 | else { 46 | // Only MSB 47 | return freq >> 8; 48 | } 49 | } 50 | 51 | void Beeper::WriteB (DWord addr, Byte val) { 52 | if (addr == 0x11E020) { 53 | // LSB 54 | freq &= 0xFF00; 55 | freq |= val; 56 | } 57 | else { 58 | // MSB 59 | freq &= 0x00FF; 60 | freq |= val << 8; 61 | } 62 | 63 | if (f_changed) { 64 | f_changed(freq); 65 | } 66 | } // WriteB 67 | 68 | void Beeper::WriteW (DWord addr, Word val) { 69 | if (addr == 0x11E020) { 70 | freq = val; 71 | } 72 | else { 73 | // Only affects MSB 74 | freq &= 0x00FF; 75 | freq |= (val & 0xFF) << 8; 76 | } 77 | 78 | if (f_changed) { 79 | f_changed(freq); 80 | } 81 | } // WriteW 82 | 83 | void Beeper::WriteDW (DWord addr, DWord val) { 84 | if (addr == 0x11E020) { 85 | freq = val; 86 | } 87 | else { 88 | // Only affects MSB 89 | freq &= 0x00FF; 90 | freq |= (val & 0xFF) << 8; 91 | } 92 | 93 | if (f_changed) { 94 | f_changed(freq); 95 | } 96 | } // WriteDW 97 | 98 | void Beeper::Reset () { 99 | freq = 0; 100 | if (f_changed) { 101 | f_changed(0); 102 | } 103 | } 104 | 105 | void Beeper::SetFreqChangedCB (std::function f_changed) { 106 | this->f_changed = f_changed; 107 | } 108 | 109 | } // End of namespace computer 110 | } // End of namespace trillek 111 | -------------------------------------------------------------------------------- /include/device_factory.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __DEVICE_FACTORY_HPP__ 2 | #define __DEVICE_FACTORY_HPP__ 1 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "types.hpp" 9 | #include "vc_dll.hpp" 10 | 11 | #include "device.hpp" 12 | 13 | namespace trillek { 14 | namespace computer { 15 | 16 | void DECLDIR registerDefaultDevices(); 17 | 18 | struct DECLDIR DeviceRecord 19 | { 20 | Byte devType; 21 | Byte devSubType; 22 | Byte devID; 23 | DWord vendorID; 24 | std::function creator; ///Pointer to a function to invoke when this device must be instanciated. 25 | 26 | DeviceRecord(Byte devType, Byte devSubType, Byte devId, DWord vendorID, std::function creator); 27 | bool deviceMatch(Byte devType, Byte devSubType, Byte devId, DWord vendorID) const; 28 | }; 29 | 30 | /** 31 | * \class DeviceFactory Given a device type, sub type, device id and vendor id, 32 | * this class return a new corresponding Device. Devices must be registred in 33 | * order to be created through this class. 34 | */ 35 | class DECLDIR DeviceFactory 36 | { 37 | std::list< DeviceRecord > d_deviceTemplates; ///A vector of all available devices template 38 | 39 | static DeviceFactory* d_instance; 40 | 41 | DeviceFactory()=default; 42 | DeviceFactory(const DeviceFactory& other)=delete; 43 | ~DeviceFactory()=default; 44 | 45 | void operator=(const DeviceFactory&)=delete; 46 | 47 | public: 48 | 49 | /** 50 | * Return the current instance of the device factory. 51 | * If none exists, create a new one. 52 | */ 53 | static DeviceFactory* GetInstance(); 54 | 55 | /** 56 | * Destroy the factory if exists. 57 | */ 58 | static void Destroy(); 59 | 60 | /** 61 | * Add a new device to the list of registred device template. 62 | */ 63 | void RegisterNewDevice(const DeviceRecord& rec); 64 | 65 | /** 66 | * Given a device type, sub type, device id and vendor id, construct a new 67 | * corresponding Device. If the corresponding record is not found, return a 68 | * nullptr. 69 | * 70 | *The factory does not own the returned pointer anymore 71 | */ 72 | std::shared_ptr CreateDevice(Byte devType, Byte devSubType, Byte devId, DWord devVendorId); 73 | 74 | /** 75 | * Remove a device from the list of registred device template. 76 | */ 77 | void UnregisterDevice(Byte devType, Byte devSubType, Byte devId, DWord devVendorId); 78 | }; 79 | 80 | } 81 | } 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /src/device_factory.cpp: -------------------------------------------------------------------------------- 1 | #include "device_factory.hpp" 2 | #include "device.hpp" 3 | #include 4 | 5 | #include "devices/gkeyb.hpp" 6 | #include "devices/tda.hpp" 7 | #include "devices/m5fdd.hpp" 8 | 9 | namespace trillek { 10 | namespace computer { 11 | 12 | void registerDefaultDevices() 13 | { 14 | DeviceFactory::GetInstance()->RegisterNewDevice(DeviceRecord(3, 1, 1, 0, &gkeyboard::GKeyboardDev::CreateNew)); 15 | DeviceFactory::GetInstance()->RegisterNewDevice(DeviceRecord(0x0E, 0x01, 0x01, 0x1C6C8B36, &tda::TDADev::CreateNew)); 16 | DeviceFactory::GetInstance()->RegisterNewDevice(DeviceRecord(0x08, 0x01, 0x01, 0x1EB37E91, &m5fdd::M5FDD::CreateNew)); 17 | } 18 | 19 | DeviceRecord::DeviceRecord(Byte devType, Byte devSubType, Byte devId, DWord vendorID, std::function creator) : devType(devType), devSubType(devSubType), devID(devId), vendorID(vendorID), creator(creator) {} 20 | 21 | bool DeviceRecord::deviceMatch(Byte devType, Byte devSubType, Byte devId, DWord vendorID) const 22 | { 23 | return (this->devType == devType && 24 | this->devSubType == devSubType && 25 | this->devID == devId && 26 | this->vendorID == vendorID); 27 | } 28 | 29 | DeviceFactory* DeviceFactory::d_instance = nullptr; 30 | 31 | DeviceFactory* DeviceFactory::GetInstance() 32 | { 33 | if(!d_instance) 34 | { 35 | d_instance = new DeviceFactory(); 36 | } 37 | 38 | return d_instance; 39 | } 40 | 41 | void DeviceFactory::Destroy() 42 | { 43 | if(d_instance) 44 | { 45 | delete d_instance; 46 | d_instance = nullptr; 47 | } 48 | } 49 | 50 | void DeviceFactory::RegisterNewDevice(const DeviceRecord &rec) 51 | { 52 | d_deviceTemplates.push_back(rec); 53 | } 54 | 55 | std::shared_ptr DeviceFactory::CreateDevice(Byte devType, Byte devSubType, Byte devId, DWord devVendorId) 56 | { 57 | auto it = std::find_if(d_deviceTemplates.begin(), d_deviceTemplates.end(), [devType, devSubType, devId, devVendorId](const DeviceRecord& d) 58 | { 59 | return d.deviceMatch(devType, devSubType, devId, devVendorId); 60 | }); 61 | 62 | return std::shared_ptr((it == d_deviceTemplates.end() ? nullptr : (*it).creator())); 63 | } 64 | 65 | void DeviceFactory::UnregisterDevice(Byte devType, Byte devSubType, Byte devId, DWord devVendorId) 66 | { 67 | d_deviceTemplates.remove_if([devType, devSubType, devId, devVendorId] (const DeviceRecord& o) 68 | { 69 | return o.deviceMatch(devType, devSubType, devId, devVendorId); 70 | }); 71 | } 72 | 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/devices/rtc.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Virtual Computer Real Time Clock 3 | * \file rtc.cpp 4 | * \copyright LGPL v3 5 | * 6 | * Implementation of embedded RTC device 7 | */ 8 | 9 | #include "devices/rtc.hpp" 10 | #include "vs_fix.hpp" 11 | 12 | namespace trillek { 13 | namespace computer { 14 | 15 | Byte RTC::ReadB(DWord addr) { 16 | 17 | std::time_t t = std::time(NULL); 18 | struct tm* clock = std::gmtime(&t); 19 | 20 | switch (addr) 21 | { 22 | case 0x11E030: 23 | return clock->tm_sec; 24 | 25 | case 0x11E031: 26 | return clock->tm_min; 27 | 28 | case 0x11E032: 29 | return clock->tm_hour; 30 | 31 | case 0x11E033: 32 | return clock->tm_mday; 33 | 34 | case 0x11E034: 35 | return clock->tm_mon; 36 | 37 | case 0x11E035: 38 | return clock->tm_year + EPOCH_YEAR_OFFSET; 39 | 40 | case 0x11E036: 41 | return (clock->tm_year + EPOCH_YEAR_OFFSET) >> 8; 42 | 43 | default: 44 | return 0; 45 | } // switch 46 | } // ReadB 47 | 48 | Word RTC::ReadW(DWord addr) { 49 | 50 | std::time_t t = std::time(NULL); 51 | struct tm* clock = std::gmtime(&t); 52 | 53 | switch (addr) 54 | { 55 | case 0x11E030: 56 | return (clock->tm_sec << 8) + clock->tm_min; 57 | 58 | case 0x11E032: 59 | return (clock->tm_hour << 8) + clock->tm_mday; 60 | 61 | case 0x11E034: 62 | return (clock->tm_mon << 8) + (Byte)(clock->tm_year + EPOCH_YEAR_OFFSET); 63 | 64 | case 0x11E036: 65 | return (Byte)( (clock->tm_year + EPOCH_YEAR_OFFSET) >> 8 ); 66 | 67 | default: 68 | return this->ReadB(addr) | (this->ReadB(addr + 1) << 8); 69 | } // switch 70 | } // ReadW 71 | 72 | DWord RTC::ReadDW(DWord addr) { 73 | 74 | std::time_t t = std::time(NULL); 75 | struct tm* clock = std::gmtime(&t); 76 | 77 | switch (addr) 78 | { 79 | case 0x11E030: 80 | return (clock->tm_sec << 24) + (clock->tm_min << 16) + (clock->tm_hour << 8) + clock->tm_mday; 81 | 82 | case 0x11E034: 83 | return (clock->tm_mon << 24) + ( (clock->tm_year + EPOCH_YEAR_OFFSET) << 8 ); 84 | 85 | default: 86 | return this->ReadW(addr) | (this->ReadW(addr + 2) << 16); 87 | } 88 | } // ReadDW 89 | 90 | void RTC::WriteB(DWord addr, Byte val) { 91 | } 92 | 93 | void RTC::WriteW(DWord addr, Word val) { 94 | } 95 | 96 | void RTC::WriteDW(DWord addr, DWord val) { 97 | } 98 | 99 | } // namespace computer 100 | } // namespace trillek 101 | -------------------------------------------------------------------------------- /asm/dcpu16n/hello.asm: -------------------------------------------------------------------------------- 1 | 2 | .org 0x0000 ; Start of ROM 3 | 4 | ; device info table 5 | devtablelen .equ 0x2000 6 | devtabledat .equ 0x2002 7 | timehs .equ 0x2400 8 | timem .equ 0x2402 9 | 10 | set i,0 11 | set j,0 12 | set [devtablelen],j 13 | set j, devtabledat 14 | scanloop: ; read through all devices 15 | hwr i,a 16 | and a,0xff 17 | ife a,0xff ; when we find one 18 | jsr checkdev ; check it 19 | swp i 20 | add i,1 ; next index 21 | ifg i,31 ; end of search? 22 | set pc,endscan ; continue 23 | swp i 24 | set pc,scanloop 25 | 26 | checkdev: 27 | set [j], i ; save the index of the device 28 | add j,2 ; because... just because... 29 | add [devtablelen],1 30 | set c,i ; get info of device type 31 | add c,2 32 | hwr c,x 33 | add c,2 34 | hwr c,y 35 | add c,2 36 | hwr c,z 37 | and x,0xff00 38 | ife x,0x0100 ; ID 0x01 (TDA) 39 | ife y,0x8B36 ; Nya 40 | ife z,0x1c6c ; Nya 41 | set pc,monitor 42 | set pc,pop 43 | 44 | monitor: ; got a monitor to setup 45 | swp c 46 | and c,0xf0 47 | bor c,0x1106 ; IO section to page 0x6 48 | mmw c ; map memory page 49 | set c,i 50 | and c,0x0f00 51 | bor c,0x6000 52 | ; at this point C holds the base address 53 | ; of the monitor device (TDA) IO mapped in page 0x6 54 | ; setup the monitor 55 | set [c+0xA],0xA000 56 | set [c+0xC],0 57 | set [c+0x8],0 ; map the TDA to 0x00:A000 in memory 58 | set pc,pop ; we should be good now 59 | 60 | endscan: ; done scanning hardware 61 | set a, 0x7D00 62 | set i, 0 63 | set j, 0xA000 64 | clearloop: ; wipe the screen 65 | sti [j], a ; remember: STI is word based (goes up by two octets) 66 | ifl i, 2400 67 | set pc, clearloop 68 | set i, histring 69 | set j, 0xA000 70 | add j, 1226 ; about the middle of buffer 71 | set a,0x4E4E 72 | disploop: 73 | set b,[i] 74 | ife b,0 75 | set pc,timerstart ; done at end of string 76 | byt.l 77 | bor b,a 78 | sti [j],b 79 | set pc, disploop 80 | 81 | timerstart: 82 | mmw 0x11EE 83 | set [0xE004], 0xC350 ; half second 84 | byt.h 85 | set [0xE010], 3 86 | ias timerisr 87 | timerloop: 88 | slp 89 | set pc,timerloop 90 | 91 | timerisr: 92 | add [timehs], 1 93 | ifg [timehs], 18 94 | add [timem], 1 95 | set c, 0x3E00 96 | set i, 0xA25A 97 | set a, [timehs] 98 | shr a, 1 99 | ifn ex, 0 100 | set [i+2],'.'+0x3E00 101 | ife ex, 0 102 | set [i+2],' '+0x3E00 103 | set x, '0' 104 | cout: 105 | set b,a 106 | mod b,10 107 | set y,x 108 | add y,b 109 | bor y,c 110 | set [i], y 111 | sub i,2 112 | dvi a,10 113 | ifn a,0 114 | set pc, cout 115 | rfi 116 | 117 | histring: 118 | .dw 'H','e','l','l','o',' ','W','o','r','l','d','!',0 119 | -------------------------------------------------------------------------------- /include/devices/dummy_device.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief DummyDevice for testing 3 | * \file dummy_device.hpp 4 | * \copyright LGPL v3 5 | * 6 | */ 7 | #ifndef __DUMMYDEVICE_HPP_ 8 | #define __DUMMYDEVICE_HPP_ 1 9 | 10 | #include "../vcomputer.hpp" 11 | 12 | namespace trillek { 13 | namespace computer { 14 | 15 | /** 16 | * DummyDevice for testing 17 | */ 18 | class DummyDevice : public Device { 19 | public: 20 | 21 | DummyDevice () { 22 | } 23 | 24 | virtual ~DummyDevice() { 25 | } 26 | 27 | virtual void Reset () { 28 | a = b = c = d = e = 0; 29 | } 30 | 31 | /** 32 | * Sends (writes to CMD register) a command to the device 33 | * @param cmd Command value to send 34 | */ 35 | virtual void SendCMD (Word cmd) { 36 | a = cmd; 37 | } 38 | 39 | virtual void A (Word cmd) { 40 | a = cmd; 41 | } 42 | 43 | virtual void B (Word cmd) { 44 | b = cmd; 45 | } 46 | 47 | virtual void C (Word cmd) { 48 | c = cmd; 49 | } 50 | 51 | virtual void D (Word cmd) { 52 | d = cmd; 53 | } 54 | 55 | virtual void E (Word cmd) { 56 | e = cmd; 57 | } 58 | 59 | virtual Word A () { 60 | return a; 61 | } 62 | 63 | virtual Word B () { 64 | return b; 65 | } 66 | 67 | virtual Word C () { 68 | return c; 69 | } 70 | 71 | virtual Word D () { 72 | return d; 73 | } 74 | 75 | virtual Word E () { 76 | return e; 77 | } 78 | 79 | /** 80 | * Device Type 81 | */ 82 | virtual Byte DevType() const { 83 | return 0; 84 | } 85 | 86 | /** 87 | * Device SubType 88 | */ 89 | virtual Byte DevSubType() const { 90 | return 1; 91 | } 92 | 93 | /** 94 | * Device ID 95 | */ 96 | virtual Byte DevID() const { 97 | return 0x5A; 98 | } 99 | 100 | /** 101 | * Device Vendor ID 102 | */ 103 | virtual DWord DevVendorID() const { 104 | return 0xBEEF55AA; 105 | } 106 | 107 | virtual void GetState (void* ptr, std::size_t& size) const { 108 | } 109 | 110 | virtual bool SetState (const void* ptr, std::size_t size) { 111 | return true; 112 | } 113 | 114 | /** 115 | * Create a new device. 116 | * \return The newly created Device 117 | */ 118 | static Device* CreateNew() { return new DummyDevice; } 119 | 120 | Word a, b, c, d, e; 121 | }; 122 | 123 | } // End of namespace computer 124 | } // End of namespace trillek 125 | 126 | #endif // __DUMMYDEVICE_HPP_ 127 | -------------------------------------------------------------------------------- /cmake/FindGLM.cmake: -------------------------------------------------------------------------------- 1 | # FindGLM - attempts to locate the glm matrix/vector library. 2 | # 3 | # This module defines the following variables (on success): 4 | # GLM_INCLUDE_DIRS - where to find glm/glm.hpp 5 | # GLM_FOUND - if the library was successfully located 6 | # 7 | # It is trying a few standard installation locations, but can be customized 8 | # with the following variables: 9 | # GLM_ROOT_DIR - root directory of a glm installation 10 | # Headers are expected to be found in either: 11 | # /glm/glm.hpp OR 12 | # /include/glm/glm.hpp 13 | # This variable can either be a cmake or environment 14 | # variable. Note however that changing the value 15 | # of the environment varible will NOT result in 16 | # re-running the header search and therefore NOT 17 | # adjust the variables set by this module. 18 | 19 | #============================================================================= 20 | # Copyright 2012 Carsten Neumann 21 | # 22 | # Distributed under the OSI-approved BSD License (the "License"); 23 | # see accompanying file Copyright.txt for details. 24 | # 25 | # This software is distributed WITHOUT ANY WARRANTY; without even the 26 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 27 | # See the License for more information. 28 | #============================================================================= 29 | # (To distribute this file outside of CMake, substitute the full 30 | # License text for the above reference.) 31 | 32 | # default search dirs 33 | SET(_glm_HEADER_SEARCH_DIRS 34 | "/usr/include" 35 | "/usr/local/include") 36 | 37 | # check environment variable 38 | SET(_glm_ENV_ROOT_DIR "$ENV{GLM_ROOT_DIR}") 39 | 40 | IF(NOT GLM_ROOT_DIR AND _glm_ENV_ROOT_DIR) 41 | SET(GLM_ROOT_DIR "${_glm_ENV_ROOT_DIR}") 42 | ENDIF(NOT GLM_ROOT_DIR AND _glm_ENV_ROOT_DIR) 43 | 44 | # put user specified location at beginning of search 45 | IF(GLM_ROOT_DIR) 46 | SET(_glm_HEADER_SEARCH_DIRS "${GLM_ROOT_DIR}" 47 | "${GLM_ROOT_DIR}/include" 48 | ${_glm_HEADER_SEARCH_DIRS}) 49 | ENDIF(GLM_ROOT_DIR) 50 | 51 | # locate header 52 | FIND_PATH(GLM_INCLUDE_DIR "glm/glm.hpp" 53 | PATHS ${_glm_HEADER_SEARCH_DIRS}) 54 | 55 | INCLUDE(FindPackageHandleStandardArgs) 56 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLM DEFAULT_MSG 57 | GLM_INCLUDE_DIR) 58 | 59 | IF(GLM_FOUND) 60 | SET(GLM_INCLUDE_DIRS "${GLM_INCLUDE_DIR}") 61 | 62 | MESSAGE(STATUS "GLM_INCLUDE_DIR = ${GLM_INCLUDE_DIR}") 63 | ENDIF(GLM_FOUND) 64 | -------------------------------------------------------------------------------- /src/tr3200/tr3200_opcodes.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief OpCodes of TR3200 CPU v0.10 3 | * \file TR3200_opcodes.hpp 4 | * \copyright LGPL v3 5 | * 6 | * OpCodes of TR3200 CPU v0.4.2 7 | * @see https://github.com/trillek-team/trillek-computer/blob/master/TR3200.md 8 | */ 9 | #ifndef __TR3200_OPCODES_HPP_ 10 | #define __TR3200_OPCODES_HPP_ 1 11 | 12 | namespace trillek { 13 | namespace computer { 14 | 15 | // 3 Parameters OpCodes ******************************************************* 16 | 17 | /** 18 | * 3 parameters OpCodes 19 | */ 20 | enum P3_OPCODE { 21 | AND = 0x80, 22 | OR = 0x81, 23 | XOR = 0x82, 24 | BITC = 0x83, 25 | 26 | ADD = 0x84, 27 | ADDC = 0x85, 28 | SUB = 0x86, 29 | SUBB = 0x87, 30 | RSB = 0x88, 31 | RSBB = 0x89, 32 | 33 | LLS = 0x8A, 34 | RLS = 0x8B, 35 | ARS = 0x8C, 36 | ROTL = 0x8D, 37 | ROTR = 0x8E, 38 | 39 | MUL = 0x8F, 40 | SMUL = 0x90, 41 | DIV = 0x91, 42 | SDIV = 0x92, 43 | 44 | LOAD = 0x93, 45 | LOADW = 0x94, 46 | LOADB = 0x95, 47 | 48 | STORE = 0x96, 49 | STOREW = 0x97, 50 | STOREB = 0x98, 51 | }; 52 | 53 | // 2 Parameters OpCodes ******************************************************* 54 | 55 | /** 56 | * 2 parameter OpCodes 57 | */ 58 | enum P2_OPCODE { 59 | MOV = 0x40, 60 | SWP = 0x41, 61 | 62 | NOT = 0x42, 63 | 64 | SIGXB = 0x43, 65 | SIGXW = 0x44, 66 | 67 | LOAD2 = 0x45, 68 | LOADW2 = 0x46, 69 | LOADB2 = 0x47, 70 | 71 | STORE2 = 0x48, 72 | STOREW2 = 0x49, 73 | STOREB2 = 0x4A, 74 | 75 | JMP2 = 0x4B, 76 | CALL2 = 0x4C, 77 | 78 | IFEQ = 0x70, 79 | IFNEQ = 0x71, 80 | 81 | IFL = 0x72, 82 | IFSL = 0x73, 83 | IFLE = 0x74, 84 | IFSLE = 0x75, 85 | 86 | IFG = 0x76, 87 | IFSG = 0x77, 88 | IFGE = 0x78, 89 | IFSGE = 0x79, 90 | 91 | IFBITS = 0x7A, 92 | IFCLEAR = 0x7B, 93 | 94 | }; 95 | 96 | // 1 Parameter OpCodes ******************************************************** 97 | 98 | /** 99 | * 1 Parameter OpCodes 100 | */ 101 | enum P1_OPCODE { 102 | 103 | XCHGB = 0x20, 104 | XCHGW = 0x21, 105 | 106 | GETPC = 0x22, 107 | 108 | POP = 0x23, 109 | PUSH = 0x24, 110 | 111 | JMP = 0x25, 112 | CALL = 0x26, 113 | 114 | RJMP = 0x27, 115 | RCALL = 0x28, 116 | 117 | INT = 0x29, 118 | }; 119 | 120 | // 0 Parameters OpCodes ******************************************************** 121 | 122 | /** 123 | * 0 Paramaters OpCodes 124 | */ 125 | enum NP_OPCODE { 126 | SLEEP = 0x00, 127 | 128 | RET = 0x01, 129 | RFI = 0x02, 130 | }; 131 | 132 | } // End of namespace computer 133 | } // End of namespace trillek 134 | 135 | #endif // __TR3200_OPCODES_HPP_ 136 | -------------------------------------------------------------------------------- /cmake/LoadLibraries.cmake: -------------------------------------------------------------------------------- 1 | # -*- cmake -*- 2 | 3 | 4 | # Returns: 5 | # LIB_${LIB_NAME}_DIR - the directory into which the source was installed. 6 | # LIB_ERR - the error string - if not set, then no problems were found. 7 | # LIB_RESULT - the result code of the last thing to process - useful when LIB_ERR is set. 8 | function("load_library_source_from_web" LIB_NAME LIB_DIR LIB_URL LIB_MD5) 9 | # Create local variables 10 | get_filename_component(LIB_ARCHIVE ${LIB_URL} NAME) # Extract the file name and prepend the download path 11 | set(LIB_ARCHIVE "${LIBS_DOWNLOAD_PATH}/${LIB_ARCHIVE}") 12 | set(LIB_INSTALL_DIR "${LIBS_SOURCE_PATH}/${LIB_DIR}") 13 | 14 | # These two error reports are not unset 15 | set(LIB_ERR "") 16 | set(LIB_RESULT "") 17 | 18 | # Don't download if already downloaded 19 | if(EXISTS "${LIB_ARCHIVE}") 20 | message("Not redownloading library '${LIB_NAME}' archive.") 21 | else(EXISTS "${LIB_ARCHIVE}") 22 | # Download the library 23 | 24 | set(CHECK_MD5) 25 | 26 | if(${LIB_MD5}) 27 | set(CHECK_MD5 "EXPECTED_MD5 \"${LIB_MD5}\"") 28 | endif(${LIB_MD5}) 29 | 30 | message("Downloading library '${LIB_NAME}' archive...") 31 | file(DOWNLOAD ${LIB_URL} ${LIB_ARCHIVE} STATUS LIB_RESULT SHOW_PROGRESS 32 | ${CHECK_MD5} 33 | ) 34 | 35 | unset(CHECK_MD5) 36 | 37 | if(NOT "${LIB_RESULT}" MATCHES "^0;") 38 | set(LIB_ERR "Download of '${LIB_NAME}' archive failed!") 39 | return() 40 | endif(NOT "${LIB_RESULT}" MATCHES "^0;") 41 | 42 | message("Download of library '${LIB_NAME}' archive complete.") 43 | endif(EXISTS "${LIB_ARCHIVE}") 44 | 45 | # Prepare the directory 46 | execute_process( 47 | COMMAND cmake -E make_directory "${LIB_INSTALL_DIR}" 48 | ) 49 | 50 | if("${LIB_${LIB_NAME}_ALREADY_EXTRACTED}") 51 | message("Library '${LIB_NAME}' has indicated that it already has been extracted, set LIB_${LIB_NAME}_ALREADY_EXTRACTED to off/false to force.") 52 | else("${LIB_${LIB_NAME}_ALREADY_EXTRACTED}") 53 | # Extract the library 54 | message("Extracting library '${LIB_NAME}' archive...") 55 | execute_process( 56 | COMMAND cmake -E tar xf "${LIB_ARCHIVE}" 57 | WORKING_DIRECTORY "${LIB_INSTALL_DIR}" 58 | RESULT_VARIABLE LIB_RESULT 59 | ) 60 | 61 | if(NOT ${LIB_RESULT} MATCHES "^0") 62 | set(LIB_ERR "Extraction of '${LIB_NAME}' archive failed!") 63 | return() 64 | endif(NOT ${LIB_RESULT} MATCHES "^0") 65 | message("Extraction of library '${LIB_NAME}' archive complete.") 66 | 67 | set(LIB_${LIB_NAME}_ALREADY_EXTRACTED 1 CACHE BOOL 68 | "Library has already been extracted. True will prevent the library from being extracted again, while false will force a re-extraction of the library from disk." 69 | FORCE 70 | ) 71 | endif("${LIB_${LIB_NAME}_ALREADY_EXTRACTED}") 72 | 73 | # Create exported variables 74 | set(LIB_${LIB_NAME}_DIR "${LIB_INSTALL_DIR}" PARENT_SCOPE) 75 | 76 | unset(LIB_ARCHIVE) 77 | unset(LIB_INSTALL_DIR) 78 | endfunction("load_library_source_from_web") 79 | 80 | 81 | -------------------------------------------------------------------------------- /include/cpu.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief CPU base class 3 | * \file cpu.hpp 4 | * \copyright LGPL v3 5 | * 6 | * Defines a base "interface" for CPUs to the Virtual Computer 7 | */ 8 | #ifndef __ICPU_HPP_ 9 | #define __ICPU_HPP_ 1 10 | 11 | #include "types.hpp" 12 | #include "vc_dll.hpp" 13 | 14 | namespace trillek { 15 | namespace computer { 16 | 17 | class VComputer; 18 | 19 | /** 20 | * Interface that must be implemented by any CPU that will be used by the 21 | * Virtual Computer. 22 | * Derived class constructors must set vcomp == nullptr. 23 | */ 24 | class DECLDIR ICPU { 25 | public: 26 | 27 | ICPU() : vcomp(nullptr) { 28 | } 29 | 30 | virtual ~ICPU() { 31 | } 32 | 33 | /** 34 | * Sets the VComputer pointer 35 | * This method must be only called by VComputer itself 36 | * @param vcomp VComputer pointer or nullptr 37 | */ 38 | void SetVComputer (computer::VComputer* _vcomp) { 39 | this->vcomp = _vcomp; 40 | } 41 | 42 | /** 43 | * Returns CPU clock speed in Hz 44 | */ 45 | virtual unsigned Clock () = 0; 46 | 47 | /** 48 | * Resets CPU insternal state 49 | */ 50 | virtual void Reset () = 0; 51 | 52 | /** 53 | * Executes a singe instrucction of the CPU 54 | * @return Number of CPU cycles used 55 | */ 56 | virtual unsigned Step () = 0; 57 | 58 | /** 59 | * Executes one or more CPU clock cycles 60 | * @param n Number of cycles (default=1) 61 | */ 62 | virtual void Tick (unsigned n = 1) = 0; 63 | 64 | /** 65 | * Sends an interrupt to the CPU. 66 | * @param msg Interrupt message 67 | * @return True if the CPU accepts the interrupt 68 | */ 69 | virtual bool SendInterrupt (Word msg) = 0; 70 | 71 | /** 72 | * Checks if the CPU is generating an trap 73 | * 74 | * ICPU implementation does nothing. 75 | * \param[out] msg The interrupt message will be writen here 76 | * \return True if is generating a new interrupt 77 | */ 78 | virtual bool DoesTrap(Word& msg) = 0; 79 | /** 80 | * Writes a copy of CPU state in a chunk of memory pointer by ptr. 81 | * @param ptr Pointer were to write 82 | * @param size Size of the chunk of memory were can write. If is 83 | * sucesfull, it will be set to the size of the write data. 84 | */ 85 | virtual void GetState (void* ptr, std::size_t& size) const = 0; 86 | 87 | /** 88 | * Sets the CPU state. 89 | * @param ptr Pointer were read the state information 90 | * @param size Size of the chunk of memory were will read. 91 | * @return True if can read the State data from the pointer. 92 | */ 93 | virtual bool SetState (const void* ptr, std::size_t size) = 0; 94 | 95 | protected: 96 | 97 | computer::VComputer* vcomp; /// Ptr to the Virtual Computer 98 | }; 99 | 100 | } // End of namespace computer 101 | } // End of namespace trillek 102 | 103 | #endif // __ICPU_HPP_ 104 | -------------------------------------------------------------------------------- /tools/include/gl_engine.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | /*! 3 | * \brief OpenGL Stuff of the test/toy emulator 4 | * \file gl_engine.hpp 5 | * \copyright LGPL v3 6 | * 7 | * OpenGL Stuff of the test/toy emulator. 8 | */ 9 | 10 | #include "os.hpp" 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #ifdef GLFW3_ENABLE 18 | 19 | class GlEngine { 20 | public: 21 | GlEngine () { 22 | winWidth = 0; 23 | winHeight = 0; 24 | 25 | vertexSource = nullptr; 26 | fragmentSource = nullptr; 27 | 28 | yaw = 0; 29 | pith = 0; 30 | zoom = 4.7f; 31 | 32 | frame_count = 0; 33 | t_acu = 0; 34 | 35 | vertShaderFile = "basic_vs.vert"; 36 | fragShaderFile = "retro_texture.frag"; 37 | this->pbo = 0; 38 | } 39 | 40 | ~GlEngine () { 41 | // RAII 42 | if (vertexSource != nullptr) { 43 | delete[] vertexSource; 44 | } 45 | 46 | if (fragmentSource != nullptr) { 47 | delete[] fragmentSource; 48 | } 49 | } 50 | 51 | void setVertexShaderFile (const std::string& file) { 52 | this->vertShaderFile = file; 53 | } 54 | void setFragmentShaderFile (const std::string& file) { 55 | this->fragShaderFile = file; 56 | } 57 | 58 | //! Init OpenGL 59 | int initGL(OS::OS& os); 60 | 61 | //! Sets the Painter function of screen texture 62 | void SetTextureCB (std::function painter); 63 | 64 | /*! 65 | * Updates the whole screen 66 | * \param os 67 | * \param delta delta in seconds 68 | */ 69 | void UpdScreen (OS::OS& os, const double delta); 70 | 71 | private: 72 | unsigned winWidth; 73 | unsigned winHeight; 74 | 75 | //bool capture_keyboard = false; 76 | 77 | GLuint screenTex; // ID of screen Texture 78 | GLuint tex_pbo[2];// IDs of the screen texture PBO 79 | size_t pbo; 80 | 81 | // Handler of shader program 82 | GLuint shaderProgram; 83 | 84 | // Ptrs to source doe of shaders 85 | GLchar* vertexSource; 86 | GLchar* fragmentSource; 87 | 88 | // Handlers of the shader programs 89 | GLuint vertexShader; 90 | GLuint fragmentShader; 91 | 92 | // Handles for uniform inputs to the shader 93 | GLuint modelId; 94 | GLuint viewId; 95 | GLuint projId; 96 | GLuint timeId; 97 | 98 | static const unsigned int sh_in_Position; 99 | static const unsigned int sh_in_Color; 100 | static const unsigned int sh_in_UV; 101 | 102 | static const GLsizei N_VERTICES; 103 | 104 | GLuint vao, vbo[3]; // vbo = {vdata, color, uv} 105 | static const float vdata[]; 106 | static const float color_data[]; 107 | static const float uv_data[]; 108 | 109 | glm::mat4 proj, view, model; //! MVP Matrixes 110 | 111 | // Camera position 112 | float yaw; 113 | float pith; 114 | float zoom; 115 | 116 | float frame_count; //! Count frames 117 | double t_acu; //! Acumulated time 118 | 119 | std::function painter; //! Function that paints screen texture 120 | 121 | std::string vertShaderFile; 122 | std::string fragShaderFile; 123 | }; 124 | 125 | #endif 126 | 127 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Unit Tests 2 | # idea take from : http://mifrosu.blogspot.com.es/2013/02/cmake-and-google-test-framework.html 3 | 4 | FILE(GLOB unit_test_files_src 5 | "*_test.cpp" 6 | ) 7 | 8 | # Links agains the static version if is enabled 9 | IF(BUILD_STATIC_VCOMPUTER) 10 | SET(VM_LINK_LIBS 11 | VCOMPUTER_STATIC 12 | ) 13 | ELSEIF(BUILD_DYNAMIC_VCOMPUTER) 14 | SET(VM_LINK_LIBS 15 | VCOMPUTER 16 | ) 17 | ENDIF(BUILD_STATIC_VCOMPUTER) 18 | 19 | FIND_PACKAGE(GTEST) 20 | FIND_PACKAGE(GTEST_MAIN) 21 | IF(NOT GTEST_FOUND AND DEFINED ENV{GTEST_ROOT}) 22 | # FindGTEST could fail if gtest is not compiled 23 | ADD_SUBDIRECTORY($ENV{GTEST_ROOT} ${CMAKE_CURRENT_BINARY_DIR}/gtest) 24 | ENDIF(NOT GTEST_FOUND AND DEFINED ENV{GTEST_ROOT}) 25 | 26 | 27 | IF(GTEST_FOUND) 28 | message(" ... using gtest found by FindGTest") 29 | FIND_PACKAGE(Threads REQUIRED) 30 | 31 | set(test_EXECUTABLE unit_test) 32 | 33 | include_directories( unit_test 34 | ${VCOMPUTER_INCLUDE_DIRS} 35 | ${GTEST_INCLUDE_DIRS} 36 | ) 37 | 38 | add_executable( unit_test 39 | ${unit_test_files_src} 40 | ) 41 | 42 | target_link_libraries( unit_test 43 | ${VM_LINK_LIBS} 44 | ${GTEST_LIBRARIES} 45 | ${GTEST_MAIN_LIBRARIES} 46 | ${CMAKE_THREAD_LIBS_INIT} 47 | ) 48 | 49 | add_test(unit_tests ../unit_test) 50 | 51 | ELSEIF(DEFINED ENV{GTEST_ROOT}) # Note we omit the $ here! 52 | message(" ... using gtest found in $ENV{GTEST_ROOT}") 53 | FIND_PACKAGE(Threads REQUIRED) 54 | 55 | set(test_EXECUTABLE unit_test) 56 | 57 | include_directories( unit_test 58 | ${VCOMPUTER_INCLUDE_DIRS} 59 | $ENV{GTEST_ROOT}/include 60 | $ENV{GTEST_ROOT} 61 | ) 62 | 63 | add_executable( unit_test 64 | ${unit_test_files_src} 65 | ) 66 | 67 | 68 | target_link_libraries( unit_test 69 | ${VM_LINK_LIBS} 70 | gtest 71 | gtest_main 72 | ${CMAKE_THREAD_LIBS_INIT} 73 | ) 74 | 75 | add_test(unit_tests ../unit_test) 76 | 77 | ELSEIF(GTEST_ROOT) 78 | message(" ... using gtest in ${GTEST_ROOT}") 79 | FIND_PACKAGE(Threads REQUIRED) 80 | 81 | set(test_EXECUTABLE unit_test) 82 | 83 | include_directories( unit_test 84 | ${VCOMPUTER_INCLUDE_DIRS} 85 | ${GTEST_ROOT}/include 86 | ${GTEST_ROOT} 87 | ) 88 | 89 | add_executable( unit_test 90 | ${unit_test_files_src} 91 | ) 92 | 93 | 94 | target_link_libraries( unit_test 95 | ${VM_LINK_LIBS} 96 | gtest 97 | gtest_main 98 | ${CMAKE_THREAD_LIBS_INIT} 99 | ) 100 | 101 | add_test(unit_tests ../unit_test) 102 | 103 | ELSE() 104 | message(STATUS "findGTest failed and GTEST_ROOT is not defined. You must tell CMake where to find the gtest source. For example : 105 | GTEST_ROOT=path/gtest-1.6.0 ; 106 | export GTEST_ROOT ") 107 | set(GTEST_ROOT "" CACHE PATH "GTest root path") 108 | endif() 109 | 110 | # Benchmark executable 111 | add_executable( benchmark 112 | benchmark.cpp 113 | ) 114 | 115 | include_directories( benchmark 116 | ${VCOMPUTER_INCLUDE_DIRS} 117 | ) 118 | 119 | target_link_libraries( benchmark 120 | ${VM_LINK_LIBS} 121 | ) 122 | 123 | -------------------------------------------------------------------------------- /src/tr3200/tr3200_macros.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief TR3200 CPU Macros 3 | * \file ITR3200_macros.hpp 4 | * \copyright LGPL v3 5 | * 6 | * Macros used by TR3200 cpu implementation 7 | */ 8 | #ifndef __TR3200_MACROS_HPP_ 9 | #define __TR3200_MACROS_HPP_ 1 10 | 11 | // Alias to special registers 12 | #define RY (11) 13 | #define BP (12) 14 | #define SP (13) 15 | #define IA (14) 16 | #define FLAGS (15) 17 | 18 | // Instrucction types 19 | #define IS_P3(x) ( ( (x) & 0x80000000 ) == 0x80000000 ) 20 | #define IS_P2(x) ( ( (x) & 0xC0000000 ) == 0x40000000 ) 21 | #define IS_P1(x) ( ( (x) & 0xE0000000 ) == 0x20000000 ) 22 | #define IS_NP(x) ( ( (x) & 0xE0000000 ) == 0x00000000 ) 23 | 24 | // Instruction OpCode 25 | #define GET_OP_CODE(x) ( ( (x) >> 24 ) & 0xFF ) 26 | 27 | // Instrucction sub-type 28 | #define IS_BRANCH(x) ( ( (x) >= 0x70 ) && ( (x) <= 0x7B ) ) 29 | 30 | // Uses immediate value (M bit) ? 31 | #define HAVE_IMMEDIATE(x) ( ( (x) & 0x00800000) != 0 ) 32 | // Uses next dword as literal 33 | #define IS_BIG_LITERAL(x) ( ( (x) & 0x00C00000) == 0x00C00000) 34 | 35 | // Extract operands 36 | // Register 37 | #define GRD(x) ( ( (x) >> 18 ) & 0x0F ) 38 | #define GRS(x) ( ( (x) >> 14 ) & 0x0F ) 39 | #define GRN(x) ( (x) & 0x0F ) 40 | // Short immediate valie 41 | #define LIT14(x) ( (x) & 0x3FFF ) 42 | #define LIT18(x) ( (x) & 0x3FFFF ) 43 | #define LIT22(x) ( (x) & 0x3FFFFF ) 44 | 45 | // Macros for ALU operations 46 | #define CARRY_BIT(x) ( ( ( (x) >> 32 ) & 0x1 ) == 1 ) 47 | #define DW_SIGN_BIT(x) ( ( (x) >> 31 ) & 0x1 ) 48 | #define W_SIGN_BIT(x) ( ( (x) >> 15 ) & 0x1 ) 49 | #define B_SIGN_BIT(x) ( ( (x) >> 7 ) & 0x1 ) 50 | 51 | // Extend sign of an short immediate value 52 | #define NEG_LIT14(x) ( (x) | 0xFFFFC000) 53 | #define NEG_LIT18(x) ( (x) | 0xFFFC0000) 54 | #define NEG_LIT22(x) ( (x) | 0xFFC00000) 55 | #define SIGN_LIT14(x) ( ( (x) >> 13 ) & 0x1 ) 56 | #define SIGN_LIT18(x) ( ( (x) >> 17 ) & 0x1 ) 57 | #define SIGN_LIT22(x) ( ( (x) >> 21 ) & 0x1 ) 58 | 59 | // Operation in Flags bits 60 | #define GET_CF(x) ( (x) & 0x1 ) 61 | #define SET_ON_CF(x) (x |= 0x1) 62 | #define SET_OFF_CF(x) (x &= 0xFFFFFFFE) 63 | 64 | #define GET_OF(x) ( ( (x) & 0x2 ) >> 1 ) 65 | #define SET_ON_OF(x) (x |= 0x2) 66 | #define SET_OFF_OF(x) (x &= 0xFFFFFFFD) 67 | 68 | #define GET_DE(x) ( ( (x) & 0x4 ) >> 2 ) 69 | #define SET_ON_DE(x) (x |= 0x4) 70 | #define SET_OFF_DE(x) (x &= 0xFFFFFFFB) 71 | 72 | #define GET_IF(x) ( ( (x) & 0x8 ) >> 3 ) 73 | #define SET_ON_IF(x) (x |= 0x8) 74 | #define SET_OFF_IF(x) (x &= 0xFFFFFFF7) 75 | 76 | // Enable bits that change what does the CPU 77 | #define GET_EI(x) ( ( (x) & 0x100 ) >> 8 ) 78 | #define SET_ON_EI(x) (x |= 0x100) 79 | #define SET_OFF_EI(x) (x &= 0xFFFFFEFF) 80 | 81 | #define GET_ESS(x) ( ( (x) & 0x200 ) >> 9 ) 82 | #define SET_ON_ESS(x) (x |= 0x200) 83 | #define SET_OFF_ESS(x) (x &= 0xFFFFFDFF) 84 | 85 | // Internal alias to Y Flags and IA registers 86 | #define REG_Y r[RY] 87 | #define REG_IA r[IA] 88 | #define REG_FLAGS r[FLAGS] 89 | 90 | #endif // __TR3200_MACROS_HPP_ 91 | -------------------------------------------------------------------------------- /src/devices/gkeyb.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Virtual Computer generic keyboard 3 | * \file gkeyb.cpp 4 | * \copyright LGPL v3 5 | * 6 | * Generic Western/Latin Keyboard 7 | * @see https://github.com/trillek-team/trillek-computer/blob/master/Keyboard.md 8 | */ 9 | 10 | #include "devices/gkeyb.hpp" 11 | #include "vs_fix.hpp" 12 | 13 | namespace trillek { 14 | namespace computer { 15 | namespace gkeyboard { 16 | 17 | GKeyboardDev::GKeyboardDev () : int_msg(0), do_int(false) { 18 | keybuffer.clear(); 19 | } 20 | 21 | GKeyboardDev::~GKeyboardDev() { 22 | } 23 | 24 | void GKeyboardDev::Reset () { 25 | a = 0; 26 | b = 0; 27 | c = 0; 28 | 29 | keybuffer.clear(); 30 | 31 | int_msg = 0; 32 | do_int = false; 33 | } 34 | 35 | bool GKeyboardDev::DoesInterrupt(Word& msg) { 36 | if (do_int && int_msg != 0x0000) { 37 | msg = int_msg; 38 | return true; 39 | } 40 | return false; 41 | } 42 | 43 | /** 44 | * Sends (writes to CMD register) a command to the device 45 | * @param cmd Command value to send 46 | */ 47 | void GKeyboardDev::SendCMD (Word cmd) { 48 | switch (cmd) { 49 | case 0x0000: // CLR_BUFFER 50 | keybuffer.clear(); 51 | break; 52 | 53 | case 0x0001: // PULL_KEY 54 | if ( !keybuffer.empty() ) { 55 | // keyevent = ((status & 7) << 24) | (keycode << 16) | scancode; 56 | auto tmp = keybuffer.front(); 57 | keybuffer.pop_front(); 58 | c = tmp >> 24; 59 | b = tmp & 0xFFFF; 60 | a = (tmp >> 16) & 0xFF; 61 | } 62 | else { 63 | a = b = c = 0; 64 | } 65 | break; 66 | 67 | case 0x0002: // PUSH_KEY 68 | if (keybuffer.size() < BSIZE) { 69 | DWord keyevent = ( (c & 7) << 24 ) | ( (a & 0xFF) << 16 ) | b; 70 | keybuffer.push_front(keyevent); 71 | } 72 | break; 73 | 74 | case 0x0003: // SET_INT 75 | int_msg = a; 76 | break; 77 | 78 | default: 79 | break; 80 | } // switch 81 | } // SendCMD 82 | 83 | void GKeyboardDev::IACK () { 84 | do_int = false; // Acepted, so we can forgot now of sending it again 85 | } 86 | 87 | void GKeyboardDev::GetState (void* ptr, std::size_t& size) const { 88 | if ( ptr != nullptr && size >= sizeof(GKeyboardState) ) { 89 | auto state = (GKeyboardState*) ptr; 90 | 91 | state->a = this->a; 92 | state->b = this->b; 93 | state->c = this->c; 94 | 95 | const std::deque& tmp = this->keybuffer; 96 | state->keybuffer = tmp; // Copy 97 | 98 | state->int_msg = this->int_msg; 99 | state->do_int = this->do_int; 100 | } 101 | } // GetState 102 | 103 | bool GKeyboardDev::SetState (const void* ptr, std::size_t size) { 104 | if ( ptr != nullptr && size >= sizeof(GKeyboardState) ) { 105 | // Sanity check 106 | auto state = (const GKeyboardState*) ptr; 107 | 108 | this->a = state->a; 109 | this->b = state->b; 110 | this->c = state->c; 111 | 112 | const std::deque& tmp = state->keybuffer; 113 | this->keybuffer = tmp; // Copy 114 | 115 | this->int_msg = state->int_msg; 116 | this->do_int = state->do_int; 117 | 118 | return true; 119 | } 120 | 121 | return false; 122 | } // SetState 123 | 124 | 125 | } // End of namespace gkeyboard 126 | } // End of namespace computer 127 | } // End of namespace trillek 128 | -------------------------------------------------------------------------------- /src/devices/rng.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Virtual Computer Random Number Generator 3 | * \file rng.cpp 4 | * \copyright LGPL v3 5 | * 6 | * Implementation of embedded RNG device 7 | */ 8 | 9 | #include "devices/rng.hpp" 10 | #include "vs_fix.hpp" 11 | 12 | namespace trillek { 13 | namespace computer { 14 | 15 | RNG::RNG() { 16 | distribution = std::uniform_int_distribution(0); 17 | engine = std::mt19937(); 18 | 19 | seed = engine.default_seed; 20 | blockGenerate = false; 21 | } 22 | 23 | RNG::~RNG() { 24 | } 25 | 26 | void RNG::Reset() { 27 | seed = engine.default_seed; 28 | engine.seed(engine.default_seed); 29 | } 30 | 31 | Byte RNG::ReadB(DWord addr) { 32 | 33 | if (!blockGenerate) { 34 | number = distribution(engine); 35 | } 36 | 37 | switch (addr) 38 | { 39 | case 0x11E040: 40 | return (Byte)(number); 41 | 42 | case 0x11E041: 43 | return (Byte)(number >> 8); 44 | 45 | case 0x11E042: 46 | return (Byte)(number >> 16); 47 | 48 | case 0x11E043: 49 | return (Byte)(number >> 24); 50 | 51 | default: 52 | return 0; 53 | } // switch 54 | } // ReadB 55 | 56 | Word RNG::ReadW(DWord addr) { 57 | 58 | if (!blockGenerate) { 59 | number = distribution(engine); 60 | } 61 | 62 | switch (addr) 63 | { 64 | case 0x11E040: 65 | return (Word)(number); 66 | 67 | case 0x11E042: 68 | return (Word)(number >> 16); 69 | 70 | default: 71 | blockGenerate = true; 72 | Word value = this->ReadB(addr) | (this->ReadB(addr + 1) << 8); 73 | blockGenerate = false; 74 | return value; 75 | } // switch 76 | } // ReadW 77 | 78 | DWord RNG::ReadDW(DWord addr) { 79 | 80 | number = distribution(engine); 81 | 82 | switch (addr) { 83 | case 0x11E040: 84 | return number; 85 | break; 86 | 87 | default: 88 | blockGenerate = true; 89 | DWord value = this->ReadW(addr) | (this->ReadW(addr + 2) << 16); 90 | blockGenerate = false; 91 | return value; 92 | } // switch 93 | } // ReadDW 94 | 95 | void RNG::WriteB(DWord addr, Byte val) { 96 | 97 | switch (addr) 98 | { 99 | case 0x11E040: 100 | seed = (seed & 0xFFFFFF00) | val << 0; 101 | break; 102 | 103 | case 0x11E041: 104 | seed = (seed & 0xFFFF00FF) | val << 8; 105 | break; 106 | 107 | case 0x11E042: 108 | seed = (seed & 0xFF00FFFF) | val << 16; 109 | break; 110 | 111 | case 0x11E043: 112 | seed = (seed & 0x00FFFFFF) | val << 24; 113 | break; 114 | 115 | default: 116 | return; 117 | } // switch 118 | 119 | engine.seed(seed); 120 | } // WriteB 121 | 122 | void RNG::WriteW(DWord addr, Word val) { 123 | switch (addr) { 124 | case 0x11E040: 125 | seed = (seed & 0xFFFFFF00) | val << 0; 126 | break; 127 | 128 | case 0x11E042: 129 | seed = (seed & 0xFF00FFFF) | val << 16; 130 | break; 131 | 132 | default: 133 | this->WriteB(addr, val); 134 | this->WriteB(addr + 1, val >> 8); 135 | } // switch 136 | 137 | engine.seed(seed); 138 | } // WriteW 139 | 140 | void RNG::WriteDW(DWord addr, DWord val) { 141 | switch (addr) { 142 | case 0x11E040: 143 | seed = (seed & 0xFFFFFF00) | val << 0; 144 | break; 145 | 146 | default: 147 | this->WriteW(addr, val); 148 | this->WriteW(addr + 2, val >> 16); 149 | } 150 | 151 | engine.seed(seed); 152 | } // WriteDW 153 | 154 | } // End of namespace computer 155 | } // End of namespace trillek 156 | -------------------------------------------------------------------------------- /tools/tda_view.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Trillek Virtual Computer - tda_view.cpp 3 | * Tool that visualizes a image of a TDA screen using a stored TDA state 4 | * 5 | * \copyright LGPL v3 6 | */ 7 | #include "os.hpp" 8 | #include "devices/tda.hpp" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #if WIN32 24 | #include 25 | #include 26 | #include 27 | #include 28 | #pragma comment(lib, "comsuppw") 29 | #endif 30 | 31 | #include "gl_engine.hpp" 32 | 33 | int main (int argc, char* argv[]) { 34 | using namespace trillek; 35 | using namespace trillek::computer::tda; 36 | GlEngine gl; 37 | 38 | // TODO load screen from a file 39 | 40 | OS::OS glfwos; 41 | if (!glfwos.InitializeWindow(1024, 768, "TDA screen dump viewer")) { 42 | std::clog << "Failed creating the window or context."; 43 | return -1; 44 | } 45 | 46 | if ( gl.initGL(glfwos) != 0) { 47 | std::clog << "Error initiating OpenGL\n"; 48 | return -1; 49 | } 50 | 51 | std::printf("Initiated OpenGL\n"); 52 | 53 | // Test screen 54 | TDAScreen screen; 55 | screen.txt_buffer[0] = 0x0F00 | 'H'; 56 | screen.txt_buffer[1] = 0x1F00 | 'e'; 57 | screen.txt_buffer[2] = 0x2F00 | 'l'; 58 | screen.txt_buffer[3] = 0x3F00 | 'l'; 59 | screen.txt_buffer[4] = 0x4F00 | 'o'; 60 | screen.txt_buffer[5] = 0x5F00 | ' '; 61 | screen.txt_buffer[6] = 0x6F00 | 'w'; 62 | screen.txt_buffer[7] = 0x7F00 | 'o'; 63 | screen.txt_buffer[8] = 0x8F00 | 'r'; 64 | screen.txt_buffer[9] = 0x9F00 | 'l'; 65 | screen.txt_buffer[10] = 0xAF00 | 'd'; 66 | screen.txt_buffer[11] = 0xBF00 | '!'; 67 | 68 | screen.cursor = true; 69 | screen.cur_col = 20; 70 | screen.cur_row = 0; 71 | screen.cur_start = 5; 72 | screen.cur_end = 7; 73 | screen.cur_color = 15; 74 | 75 | for (unsigned i= 40; i < WIDTH_CHARS*HEIGHT_CHARS; i++ ) { 76 | Byte fg = i % 16; 77 | Byte bg = (15 - i) % 16; 78 | screen.txt_buffer[i] = (bg << 12) | (fg << 8) | ((i-40) % 256); 79 | } 80 | 81 | // Function to update texture from TDAScreen object 82 | gl.SetTextureCB ([&screen] (void* tdata) { 83 | // Update Texture callback 84 | DWord* tex = (DWord*)tdata; 85 | TDAtoRGBATexture(screen, tex); // Write the texture to the PBO buffer 86 | }); 87 | 88 | using namespace std::chrono; 89 | auto clock = high_resolution_clock::now(); 90 | double delta; // Time delta in seconds 91 | 92 | bool loop = true; 93 | while ( loop) { 94 | glfwos.UpdateCounter(); 95 | // Calcs delta time 96 | 97 | auto oldClock = clock; 98 | clock = high_resolution_clock::now(); 99 | delta = duration_cast(clock - oldClock).count(); 100 | 101 | if (glfwos.Closing()) { 102 | loop = false; 103 | continue; 104 | } 105 | // Ugly hack 106 | for(unsigned long i=0; i < 10000000 ; i++) { 107 | ; 108 | } 109 | 110 | gl.UpdScreen (glfwos, delta); 111 | } 112 | 113 | // Cleanup all the things we bound and allocated 114 | /* 115 | glUseProgram(0); 116 | glDisableVertexAttribArray(sh_in_Position); 117 | glDisableVertexAttribArray(sh_in_Color); 118 | glDisableVertexAttribArray(sh_in_UV); 119 | /*glDetachShader(shaderprogram, vertexshader); 120 | glDetachShader(shaderprogram, fragmentshader); 121 | glDeleteProgram(shaderprogram); 122 | glDeleteShader(vertexshader); 123 | glDeleteShader(fragmentshader);*/ /* 124 | glDeleteBuffers(3, vbo); 125 | glDeleteVertexArrays(1, &vao); 126 | */ 127 | glfwos.Terminate(); 128 | return 0; 129 | } 130 | 131 | 132 | -------------------------------------------------------------------------------- /assets/shaders/retro_texture.frag: -------------------------------------------------------------------------------- 1 | // Basic Fragment Shader that generates a Scanline/TV effect 2 | // Based on : 3 | // https://github.com/tacoe/detroit/blob/master/arthur/scanlines.glsl 4 | // http://pastebin.com/sTk3EUAp 5 | // https://gitorious.org/bsnes/bsnes/source/4246a6b0eb664d00ed3cac186d113cca4701911e:shaders/GLSL/Curvature.shader#L20 6 | // http://pastebin.com/TcPdyik0 7 | #version 140 8 | 9 | precision highp float; // needed only for version 1.30 10 | 11 | // Base Color/Tint of the screen thing 12 | //in vec3 ex_Color; 13 | // UV coord of the screen thing 14 | in vec2 ex_UV; 15 | 16 | out vec4 out_Color; 17 | 18 | // width of a pixel in texture units, 19 | // should be set to 1 / width, 1 / height. 20 | uniform vec2 pixelSize = vec2(1.0/(320.0), 1.0/(240.0) ); 21 | 22 | // how sharp the bilinear filter is, 0 - 1 23 | const float sharpness = 0.75; 24 | 25 | // How many are misalign the color beams 26 | const float misalign = 0.4; 27 | 28 | // how much a scanline should darken its line, 0-1 29 | const float scanIntensity = 0.1; 30 | 31 | // amount of noise, 0-1 (a little goes a long way) 32 | const float noise = 0.075; 33 | 34 | // Monitor curvature 35 | const float distortion = 0.08; 36 | 37 | // Flicker intesity 38 | //const float flicker = 0.025; 39 | 40 | // Time depedent FX 41 | uniform float time = 0.0; 42 | 43 | // Screen texture 44 | uniform sampler2D texture0; 45 | 46 | // how much to boost the brightness of pixels to compensate for scanlines, 0-1 47 | // 0 = no increase, 1 = double brightness 48 | uniform float brightness = 0.0; 49 | 50 | // Calcs new UV coords to reproduce a curvature distorsion 51 | vec2 barrelDistortion(vec2 coord) { 52 | vec2 cc = coord - 0.5; 53 | float dist = dot(cc, cc) * distortion; 54 | return coord + cc * (1.0 - dist) * dist; 55 | } 56 | 57 | void main(void) { 58 | // Apply curvature fx 59 | vec2 uv = barrelDistortion(ex_UV); 60 | if ( (uv.x <0.0 || uv.x > 1.0) || (uv.y <0.0 || uv.y > 1.0)) { 61 | // Ignore fragments that are outside of the screen 62 | discard; 63 | return; 64 | } 65 | 66 | // Precalculate misalign in function of horizontal pos 67 | float mis = misalign * pixelSize.x * (misalign + (1.0 - misalign)*2 * abs(uv.x - 0.5)); 68 | 69 | // Precalculate bilinear filter things 70 | float xInc = pixelSize.x * (1.0 - sharpness) / 2.0; 71 | float yInc = pixelSize.y * (1.0 - sharpness) / 2.0; 72 | vec3 middle[4]; 73 | vec2 uvs[4]; 74 | uvs[0] = uv + vec2(-xInc, -yInc); 75 | uvs[1] = uv + vec2(xInc, -yInc); 76 | uvs[2] = uv + vec2(-xInc, yInc); 77 | uvs[3] = uv + vec2(xInc, yInc); 78 | 79 | for (int i=0; i < 4; i++) { 80 | middle[i] = texture(texture0, uvs[i] ).rgb; 81 | 82 | // Generate color border (misaligment) 83 | vec3 col; 84 | col.r = texture(texture0,vec2(uvs[i].x + mis ,uvs[i].y)).x; 85 | col.g = texture(texture0,vec2(uvs[i].x ,uvs[i].y)).y; 86 | col.b = texture(texture0,vec2(uvs[i].x - mis ,uvs[i].y)).z; 87 | middle[i] = middle[i]*0.2 + col*0.8; 88 | 89 | // scanlines 90 | if (scanIntensity > 0.0 && mod(uvs[i].y, pixelSize.y ) > (pixelSize.y/2)) { 91 | middle[i].r = max(middle[i].r - scanIntensity, 0); 92 | middle[i].g = max(middle[i].g - scanIntensity, 0); 93 | middle[i].b = max(middle[i].b - scanIntensity, 0); 94 | }; 95 | 96 | } 97 | 98 | // Apply bilinear filter over the composed image of orig texture + color misalign + scanline 99 | vec3 result = (middle[0] + middle[1] + middle[2] + middle[3]) * 0.25; 100 | 101 | // noise 102 | result = result + noise * fract(sin(dot(uv.xy , vec2(12.9898 + time, 78.233 + tan(time)))) * 43758.5453); 103 | 104 | // contrast curve 105 | //result.xyz = clamp(0.5*result.xyz + 0.5*result.xyz * 1.2*result.xyz, 0.0 , 1.0); 106 | 107 | //flickering (semi-randomized) 108 | // result *= 1.0 - flicker * fract(sin(dot(vec2(1.0) , vec2(12.9898 + time, 78.233 + tan(time)))) * 43758.5453); 109 | 110 | out_Color.xyz = result * (1.0 + brightness); 111 | out_Color.w = 1.0; 112 | 113 | } 114 | -------------------------------------------------------------------------------- /include/dcpu16n/dcpu16n.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Class definitions for the DCPU-16N CPU 3 | * \file dcpu16n.hpp 4 | * \copyright The MIT License (MIT) 5 | * 6 | */ 7 | 8 | #ifndef __DCPU16N_HPP__ 9 | #define __DCPU16N_HPP__ 10 | 11 | #include "../cpu.hpp" 12 | #include "../vcomputer.hpp" 13 | 14 | namespace trillek { 15 | namespace computer { 16 | 17 | class DECLDIR DCPU16N : public ICPU { 18 | public: 19 | 20 | DCPU16N(unsigned clock = 100000); 21 | virtual ~DCPU16N(); 22 | 23 | /** 24 | * Returns CPU clock speed in Hz 25 | */ 26 | virtual unsigned Clock() { 27 | return this->cpu_clock; 28 | } 29 | 30 | /** 31 | * Resets the CPU state 32 | */ 33 | virtual void Reset (); 34 | 35 | /** 36 | * Executes a single CPU instruction 37 | * \return Number of CPU cycles used 38 | */ 39 | unsigned Step (); 40 | 41 | /** 42 | * Executes one or more CPU clock cycles 43 | * \param n Number of cycles (default=1) 44 | */ 45 | void Tick (unsigned n = 1); 46 | 47 | /** 48 | * Sends an interrupt to the CPU. 49 | * \param msg Interrupt message 50 | * \return True if the CPU accepts the interrupt 51 | */ 52 | bool SendInterrupt (Word msg); 53 | 54 | /** 55 | * Checks if the CPU is generating an trap 56 | * 57 | * ICPU implementation does nothing. 58 | * \param[out] msg The interrupt message will be writen here 59 | * \return True if is generating a new interrupt 60 | */ 61 | virtual bool DoesTrap(Word& msg); 62 | 63 | /** 64 | * Writes a copy of CPU state in a chunk of memory pointer by ptr. 65 | * @param ptr Pointer where to write 66 | * @param size Size of the chunk of memory where we can write. If 67 | * successful, it will be set to the size of the written data. 68 | */ 69 | virtual void GetState (void* ptr, std::size_t& size) const; 70 | 71 | /** 72 | * Sets the CPU state. 73 | * @param ptr Pointer were read the state information 74 | * @param size Size of the chunk of memory were will read. 75 | * @return True if can read the State data from the pointer. 76 | */ 77 | virtual bool SetState (const void* ptr, std::size_t size); 78 | 79 | protected: 80 | 81 | // I/O Interface for opcodes 82 | Word IORead(Word); 83 | void IOWrite(Word, Word); 84 | 85 | unsigned int cpu_clock; // CPU clock speed 86 | 87 | // CPU Core 88 | Word r[8]; 89 | Word pc; 90 | Word sp; 91 | Word ex; 92 | Word ia; 93 | 94 | // EMU 95 | DWord emu[16]; 96 | 97 | // Interrupt 98 | Word iqp; 99 | Word iqe; 100 | Word iqc; 101 | Word intq[256]; 102 | 103 | // hardware status 104 | unsigned phase; 105 | unsigned phasenext; 106 | unsigned pwrdraw; 107 | unsigned wait_cycles; 108 | unsigned last_cycles; 109 | 110 | // Internal use registers 111 | Word acu; 112 | DWord aca; 113 | Word bcu; 114 | DWord bca; 115 | Word opcl; 116 | Word wrt; 117 | Word fetchh; 118 | 119 | // Status flags 120 | bool addradd; 121 | bool addrdec; 122 | bool bytemode; 123 | bool bytehigh; 124 | bool skip; 125 | bool fire; 126 | bool qint; 127 | 128 | }; 129 | 130 | struct DCPU16NState { 131 | // CPU Core 132 | Word r[8]; 133 | Word pc; 134 | Word sp; 135 | Word ex; 136 | Word ia; 137 | // status flags 138 | bool addradd; 139 | bool addrdec; 140 | bool bytemode; 141 | bool bytehigh; 142 | bool skip; 143 | bool fire; 144 | bool qint; 145 | // hardware status 146 | unsigned phase; 147 | unsigned phasenext; 148 | unsigned pwrdraw; 149 | unsigned wait_cycles; 150 | unsigned last_cycles; 151 | // EMU 152 | DWord emu[16]; 153 | // Interrupt 154 | Word iqp; 155 | Word iqe; 156 | Word iqc; 157 | Word intq[256]; 158 | // Internal use registers 159 | Word acu; 160 | DWord aca; 161 | Word bcu; 162 | DWord bca; 163 | Word opcl; 164 | Word wrt; 165 | Word fetchh; 166 | }; 167 | 168 | } // computer 169 | } // trillek 170 | 171 | #endif 172 | -------------------------------------------------------------------------------- /src/devices/nvram.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Virtual Computer NVRAM 3 | * \file rng.cpp 4 | * \copyright LGPL v3 5 | * 6 | * Implementation of No Volatile RAM (NVRAM) 7 | */ 8 | 9 | #include "devices/nvram.hpp" 10 | #include "vs_fix.hpp" 11 | 12 | #include 13 | #include 14 | 15 | namespace trillek { 16 | namespace computer { 17 | 18 | NVRAM::NVRAM() : dirty(false) { 19 | } 20 | 21 | NVRAM::~NVRAM() { 22 | } 23 | 24 | void NVRAM::Reset() { 25 | } 26 | 27 | Byte NVRAM::ReadB(DWord addr) { 28 | 29 | if (addr < BaseAddress || addr >= BaseAddress + 256) { 30 | return 0; 31 | } 32 | 33 | addr -= BaseAddress; 34 | assert (addr < 256); 35 | 36 | return eprom[addr]; 37 | 38 | } // ReadB 39 | 40 | Word NVRAM::ReadW(DWord addr) { 41 | 42 | if (addr < BaseAddress || addr >= BaseAddress + 256) { 43 | return 0; 44 | } 45 | 46 | addr -= BaseAddress; 47 | assert (addr < 256); 48 | 49 | if (addr == 255) { 50 | return eprom[addr]; 51 | } else { 52 | return eprom[addr] | (eprom[addr+1] << 8); 53 | } 54 | 55 | } // ReadW 56 | 57 | DWord NVRAM::ReadDW(DWord addr) { 58 | 59 | if (addr < BaseAddress || addr >= BaseAddress + 256) { 60 | return 0; 61 | } 62 | 63 | addr -= BaseAddress; 64 | assert (addr < 256); 65 | 66 | if (addr == 253) { 67 | return eprom[addr] | (eprom[addr+1] << 8) | (eprom[addr+2] << 16); 68 | } else if (addr == 254) { 69 | return eprom[addr] | (eprom[addr+1] << 8) ; 70 | } else if (addr == 255) { 71 | return eprom[addr]; 72 | } else { 73 | return eprom[addr] | (eprom[addr+1] << 8) | (eprom[addr+2] << 16) | (eprom[addr+2] << 24); 74 | } 75 | 76 | } // ReadDW 77 | 78 | void NVRAM::WriteB(DWord addr, Byte val) { 79 | 80 | if (addr < BaseAddress || addr >= BaseAddress + 256) { 81 | return ; 82 | } 83 | 84 | addr -= BaseAddress; 85 | assert (addr < 256); 86 | 87 | eprom[addr] = val; 88 | dirty = true; 89 | } // WriteB 90 | 91 | void NVRAM::WriteW(DWord addr, Word val) { 92 | if (addr < BaseAddress || addr >= BaseAddress + 256) { 93 | return ; 94 | } 95 | 96 | addr -= BaseAddress; 97 | assert (addr < 256); 98 | 99 | if (addr == 255) { 100 | eprom[addr] = val; 101 | } else { 102 | eprom[addr] = val; 103 | eprom[addr+1] = val >> 8; 104 | } 105 | dirty = true; 106 | } // WriteW 107 | 108 | void NVRAM::WriteDW(DWord addr, DWord val) { 109 | if (addr < BaseAddress || addr >= BaseAddress + 256) { 110 | return ; 111 | } 112 | 113 | addr -= BaseAddress; 114 | assert (addr < 256); 115 | 116 | if (addr == 253) { 117 | eprom[addr] = val; 118 | eprom[addr+1] = val >> 8; 119 | eprom[addr+2] = val >> 16; 120 | } else if (addr == 254) { 121 | eprom[addr] = val; 122 | eprom[addr+1] = val >> 8; 123 | } else if (addr == 255) { 124 | eprom[addr] = val; 125 | } else { 126 | eprom[addr] = val; 127 | eprom[addr+1] = val >> 8; 128 | eprom[addr+2] = val >> 16; 129 | eprom[addr+3] = val >> 24; 130 | } 131 | dirty = true; 132 | } // WriteDW 133 | 134 | bool NVRAM::isDirty() { 135 | return dirty; 136 | } 137 | 138 | bool NVRAM::Load (std::istream& stream) { 139 | if (stream.good() && ! stream.eof()) { 140 | try { 141 | stream.read(reinterpret_cast(eprom), 256); 142 | } catch (std::exception&) { 143 | return false; 144 | } 145 | dirty = false; 146 | return stream.gcount() == 256; 147 | } 148 | return false; 149 | } // Load 150 | 151 | bool NVRAM::Save (std::ostream& stream) { 152 | if (stream.good() && ! stream.eof()) { 153 | try { 154 | stream.write(reinterpret_cast(eprom), 256); 155 | } catch (std::exception&) { 156 | return false; 157 | } 158 | dirty = false; 159 | return true; 160 | } 161 | return false; 162 | } 163 | 164 | } // End of namespace computer 165 | } // End of namespace trillek 166 | 167 | -------------------------------------------------------------------------------- /asm/dcpu16n/hello.lst: -------------------------------------------------------------------------------- 1 | 2 00000000 .org 0000 2 | 5 00000000 devtablelen .equ 2000 3 | 6 00000000 devtabledat .equ 2002 4 | 7 00000000 timehs .equ 2400 5 | 8 00000000 timem .equ 2402 6 | 10 00000000 set i,0 C184 7 | 11 00000002 set j,0 E184 8 | 12 00000004 set [devtablelen],j C11F0020 9 | 13 00000008 set j,devtabledat E17C0220 10 | 14 0000000c scanloop 11 | 15 0000000c hwr i,a DD00 12 | 16 0000000e and a,ff 0A7CFF00 13 | 17 00000012 ife a,ff 127CFF00 14 | 18 00000016 jsr checkdev 207C2A00 15 | 19 0000001a swp i A01A 16 | 20 0000001c add i,1 C288 17 | 21 0000001e ifg i,31 D47C1F00 18 | 22 00000022 set pc,endscan 817F7C00 19 | 23 00000026 swp i A01A 20 | 24 00000028 set pc,scanloop 81B7 21 | 26 0000002a checkdev 22 | 27 0000002a set [j],i E119 23 | 28 0000002c add j,2 E28C 24 | 29 0000002e add [devtablelen],1 C28B0020 25 | 30 00000032 set c,i 4118 26 | 31 00000034 add c,2 428C 27 | 32 00000036 hwr c,x 5D0C 28 | 33 00000038 add c,2 428C 29 | 34 0000003a hwr c,y 5D10 30 | 35 0000003c add c,2 428C 31 | 36 0000003e hwr c,z 5D14 32 | 37 00000040 and x,ff00 6A7C00FF 33 | 38 00000044 ife x,0100 727C0001 34 | 39 00000048 ife y,8B36 927C368B 35 | 40 0000004c ife z,1c6c B27C6C1C 36 | 41 00000050 set pc,monitor 817F5600 37 | 42 00000054 set pc,pop 8163 38 | 44 00000056 monitor 39 | 45 00000056 swp c A00A 40 | 46 00000058 and c,f0 4A7CF000 41 | 47 0000005c bor c,1106 4B7C0611 42 | 48 00000060 mmw c 000A 43 | 49 00000062 set c,i 4118 44 | 50 00000064 and c,0f00 4A7C000F 45 | 51 00000068 bor c,6000 4B7C0060 46 | 55 0000006c set [c+A],A000 417E00A00A00 47 | 56 00000072 set [c+C],0 41860C00 48 | 57 00000076 set [c+8],0 41860800 49 | 58 0000007a set pc,pop 8163 50 | 60 0000007c endscan 51 | 61 0000007c set a,7D00 017C007D 52 | 62 00000080 set i,0 C184 53 | 63 00000082 set j,A000 E17C00A0 54 | 64 00000086 clearloop 55 | 65 00000086 sti [j],a FE01 56 | 66 00000088 ifl i,2400 D67C6009 57 | 67 0000008c set pc,clearloop 817F8600 58 | 68 00000090 set i,histring C17C1201 59 | 69 00000094 set j,A000 E17C00A0 60 | 70 00000098 add j,1226 E27CCA04 61 | 71 0000009c set a,4E4E 017C4E4E 62 | 72 000000a0 disploop 63 | 73 000000a0 set b,[i] 2138 64 | 74 000000a2 ife b,0 3284 65 | 75 000000a4 set pc,timerstart 817FB200 66 | 76 000000a8 byt.l 0010 67 | 77 000000aa bor b,a 2B00 68 | 78 000000ac sti [j],b FE05 69 | 79 000000ae set pc,disploop 817FA000 70 | 81 000000b2 timerstart 71 | 82 000000b2 mmw 11EE 007EEE11 72 | 83 000000b6 set [E004],C350 C17F50C304E0 73 | 84 000000bc byt.h 0090 74 | 85 000000be set [E010],3 C19310E0 75 | 86 000000c2 ias timerisr 407DCC00 76 | 87 000000c6 timerloop 77 | 88 000000c6 slp 0004 78 | 89 000000c8 set pc,timerloop 817FC600 79 | 91 000000cc timerisr 80 | 92 000000cc add [timehs],1 C28B0024 81 | 93 000000d0 ifg [timehs],18 D4CF0024 82 | 94 000000d4 add [timem],1 C28B0224 83 | 95 000000d8 set c,3E00 417C003E 84 | 96 000000dc set i,A25A C17C5AA2 85 | 97 000000e0 set a,[timehs] 01780024 86 | 98 000000e4 shr a,1 0D88 87 | 99 000000e6 ifn ex,0 B387 88 | 100 000000e8 set [i+2],.+3E00 C17E2E3E0200 89 | 101 000000ee ife ex,0 B287 90 | 102 000000f0 set [i+2], +3E00 C17E203E0200 91 | 103 000000f6 set x,0 617C3000 92 | 104 000000fa cout 93 | 105 000000fa set b,a 2100 94 | 106 000000fc mod b,10 28AC 95 | 107 000000fe set y,x 810C 96 | 108 00000100 add y,b 8204 97 | 109 00000102 bor y,c 8B08 98 | 110 00000104 set [i],y C111 99 | 111 00000106 sub i,2 C38C 100 | 112 00000108 dvi a,10 07AC 101 | 113 0000010a ifn a,0 1384 102 | 114 0000010c set pc,cout 817FFA00 103 | 115 00000110 rfi 6085 104 | 117 00000112 histring 105 | 118 00000112 .dw H,e,l,l,o, ,W,o,r,l,d,!,0 4800 6500 6C00 6C00 6F00 2000 5700 6F00 7200 6C00 6400 2100 0000 106 | Symbols: 107 | 0000002a checkdev 108 | 00002402 timem 109 | 0000007c endscan 110 | 000000cc timerisr 111 | 00002400 timehs 112 | 00000056 monitor 113 | 0000000c scanloop 114 | 00000086 clearloop 115 | 00002000 devtablelen 116 | 000000fa cout 117 | 000000c6 timerloop 118 | 000000b2 timerstart 119 | 00002002 devtabledat 120 | 000000a0 disploop 121 | 00000112 histring 122 | -------------------------------------------------------------------------------- /include/tr3200/tr3200.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief TR3200 CPU 3 | * \file tr3200.hpp 4 | * \copyright LGPL v3 5 | * 6 | * Implementation of the TR3200 CPU 7 | */ 8 | #ifndef __TR3200_HPP_ 9 | #define __TR3200_HPP_ 1 10 | 11 | #include "../cpu.hpp" 12 | #include "../vcomputer.hpp" 13 | 14 | namespace trillek { 15 | namespace computer { 16 | 17 | /** 18 | * Implementation of TR3200 CPU for Trillek's virtual computer 19 | */ 20 | class DECLDIR TR3200 : public ICPU { 21 | public: 22 | 23 | /** 24 | * Builds a TR3200 CPU 25 | * @param clock CPU clock speed 26 | */ 27 | TR3200(unsigned clock = 100000); 28 | 29 | virtual ~TR3200(); 30 | 31 | /** 32 | * Returns CPU clock speed in Hz 33 | */ 34 | virtual unsigned Clock() { 35 | return this->cpu_clock; 36 | } 37 | 38 | /** 39 | * Resets the CPU state 40 | */ 41 | virtual void Reset (); 42 | 43 | /** 44 | * Executes a singe instrucction of the CPU 45 | * @return Number of CPU cycles used 46 | */ 47 | unsigned Step (); 48 | 49 | /** 50 | * Executes one or more CPU clock cycles 51 | * @param n Number of cycles (default=1) 52 | */ 53 | void Tick (unsigned n = 1); 54 | 55 | /** 56 | * Sends an interrupt to the CPU. 57 | * @param msg Interrupt message 58 | * @return True if the CPU accepts the interrupt 59 | */ 60 | bool SendInterrupt (Word msg); 61 | 62 | /** 63 | * Checks if the CPU is generating an trap 64 | * 65 | * ICPU implementation does nothing. 66 | * \param[out] msg The interrupt message will be writen here 67 | * \return True if is generating a new interrupt 68 | */ 69 | virtual bool DoesTrap(Word& msg); 70 | 71 | /** 72 | * Writes a copy of CPU state in a chunk of memory pointer by ptr. 73 | * @param ptr Pointer were to write 74 | * @param size Size of the chunk of memory were can write. If is 75 | * sucesfull, it will be set to the size of the write data. 76 | */ 77 | virtual void GetState (void* ptr, std::size_t& size) const; 78 | 79 | /** 80 | * Sets the CPU state. 81 | * @param ptr Pointer were read the state information 82 | * @param size Size of the chunk of memory were will read. 83 | * @return True if can read the State data from the pointer. 84 | */ 85 | virtual bool SetState (const void* ptr, std::size_t size); 86 | 87 | static unsigned const TR3200_NGPRS = 16; /// Total number of CPU registers 88 | 89 | protected: 90 | 91 | unsigned cpu_clock; /// CPU clock speed 92 | 93 | DWord r[TR3200_NGPRS]; /// Registers 94 | DWord pc; /// Program Counter 95 | 96 | unsigned wait_cycles; /// Nº of cycles that need to finish the actual 97 | // instruction 98 | 99 | Word int_msg; /// Interrupt message 100 | 101 | bool interrupt; /// Is atending an interrupt ? 102 | bool step_mode; /// Is in step mode execution ? 103 | bool skiping; /// Is skiping an instruction ? 104 | bool sleeping; /// Is sleping the CPU ? 105 | 106 | /** 107 | * Does the real work of executing a instrucction 108 | * @param Numvber of cycles tha requires to execute an instrucction 109 | */ 110 | virtual unsigned RealStep (); 111 | 112 | /** 113 | * Process if an interrupt is waiting 114 | */ 115 | void ProcessInterrupt (); 116 | }; 117 | 118 | /** 119 | * Structure that stores the TR3200 CPU state in any moment 120 | */ 121 | struct TR3200State { 122 | DWord r[TR3200::TR3200_NGPRS]; /// Registers 123 | DWord pc; /// Program Counter 124 | 125 | unsigned wait_cycles; /// Nº of cycles that need to finish the actual 126 | // instruction 127 | 128 | Word int_msg; /// Interrupt message 129 | 130 | bool interrupt; /// Is atending an interrupt ? 131 | bool step_mode; /// Is in step mode execution ? 132 | bool skiping; /// Is skiping an instruction ? 133 | bool sleeping; /// Is sleping the CPU ? 134 | }; 135 | 136 | } // End of namespace computer 137 | } // End of namespace trillek 138 | 139 | #endif // __TR3200_HPP_ 140 | -------------------------------------------------------------------------------- /include/devices/debug_serial_console.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Debug Serial Console 3 | * \file debug_serial_console.hpp 4 | * \copyright LGPL v3 5 | * 6 | * Debug Serial Console for debuing the Virtual Computer 7 | */ 8 | #ifndef __DEBUGSERIALCONSOLE_HPP_ 9 | #define __DEBUGSERIALCONSOLE_HPP_ 1 10 | 11 | #include "../vcomputer.hpp" 12 | 13 | #include 14 | 15 | namespace trillek { 16 | namespace computer { 17 | 18 | /** 19 | * Serial Console for debuing 20 | */ 21 | class DECLDIR DebugSerialConsole : public Device { 22 | public: 23 | 24 | DebugSerialConsole () { 25 | } 26 | 27 | virtual ~DebugSerialConsole () { 28 | } 29 | 30 | virtual void Reset () { 31 | a = 0; 32 | int_msg = 0; 33 | do_int = false; 34 | } 35 | 36 | bool DoesInterrupt (Word& msg) { 37 | if (do_int && int_msg != 0x0000) { 38 | msg = int_msg; 39 | return true; 40 | } 41 | return false; 42 | } 43 | 44 | void IACK () { 45 | do_int = false; // Acepted, so we can forgot now of sending it again 46 | } 47 | 48 | /** 49 | * Sends (writes to CMD register) a command to the device 50 | * @param cmd Command value to send 51 | */ 52 | virtual void SendCMD (Word cmd) { 53 | switch (cmd) { 54 | case 0x0000: // READ_WORD 55 | if (onRead != nullptr) { 56 | a = onRead(); 57 | } 58 | else { 59 | a = 0; 60 | } 61 | break; 62 | 63 | case 0x0001: // SEND_WORD 64 | if (onWrite != nullptr) { 65 | onWrite(a); 66 | } 67 | break; 68 | 69 | case 0x0002: // SET_RXINT 70 | int_msg = a; 71 | break; 72 | 73 | default: 74 | break; 75 | } // switch 76 | } // SendCMD 77 | 78 | virtual void A (Word val) { 79 | a = val; 80 | } 81 | 82 | virtual Word A () { 83 | return a; 84 | } 85 | 86 | /** 87 | * Device Type 88 | */ 89 | virtual Byte DevType() const { 90 | return 0x02; 91 | } 92 | 93 | /** 94 | * Device SubType 95 | */ 96 | virtual Byte DevSubType() const { 97 | return 0xFF; 98 | } 99 | 100 | /** 101 | * Device ID 102 | */ 103 | virtual Byte DevID() const { 104 | return 0x01; 105 | } 106 | 107 | /** 108 | * Device Vendor ID 109 | */ 110 | virtual DWord DevVendorID() const { 111 | return 0x00000000; 112 | } 113 | 114 | virtual void GetState (void* ptr, std::size_t& size) const { 115 | } 116 | 117 | virtual bool SetState (const void* ptr, std::size_t size) { 118 | return true; 119 | } 120 | 121 | // Extenal API 122 | 123 | /** 124 | * Asigns a Callback callable element executed when software ask to the 125 | * device for a new wordt to read 126 | * @param cb callable element that returns a Word 127 | */ 128 | void OnRead (std::function cb) { 129 | this->onRead = cb; 130 | } 131 | 132 | /** 133 | * Asigns a Callback callable element executed when software sends to the 134 | * device a new wordt 135 | * @param cb callable element that gets a Word 136 | */ 137 | void OnWrite (std::function cb) { 138 | this->onWrite = cb; 139 | } 140 | 141 | /** 142 | * Sends a interrupt when the external code needs to indicate to the 143 | * software that there is a word ready to be read 144 | */ 145 | void RX_Ready() { 146 | do_int = int_msg != 0x0000; 147 | } 148 | 149 | /** 150 | * Create a new device. 151 | * \return The newly created Device 152 | */ 153 | static Device* CreateNew() { return new DebugSerialConsole; } 154 | 155 | protected: 156 | 157 | Word a; 158 | 159 | Word int_msg; 160 | bool do_int; 161 | 162 | std::function onRead; /// Callback when the computer try to 163 | // read a byte from the serial console 164 | std::function onWrite; /// Callback when the computer try to 165 | // write a byte to the serial console 166 | }; 167 | 168 | } // End of namespace computer 169 | } // End of namespace trillek 170 | 171 | #endif // __DEBUGSERIALCONSOLE_HPP_ 172 | -------------------------------------------------------------------------------- /call_Uncrustify.cfg: -------------------------------------------------------------------------------- 1 | tok_split_gte=false 2 | utf8_byte=true 3 | utf8_force=false 4 | indent_cmt_with_tabs=false 5 | indent_align_string=true 6 | indent_braces=false 7 | indent_braces_no_func=false 8 | indent_braces_no_class=false 9 | indent_braces_no_struct=false 10 | indent_brace_parent=false 11 | indent_namespace=false 12 | indent_extern=true 13 | indent_class=true 14 | indent_class_colon=false 15 | indent_else_if=false 16 | indent_var_def_cont=false 17 | indent_func_call_param=true 18 | indent_func_def_param=true 19 | indent_func_proto_param=true 20 | indent_func_class_param=true 21 | indent_func_ctor_var_param=true 22 | indent_template_param=false 23 | indent_func_param_double=false 24 | indent_relative_single_line_comments=false 25 | indent_col1_comment=false 26 | indent_access_spec_body=false 27 | indent_paren_nl=false 28 | indent_comma_paren=false 29 | indent_bool_paren=false 30 | indent_first_bool_expr=false 31 | indent_square_nl=false 32 | indent_preserve_sql=false 33 | indent_align_assign=true 34 | sp_balance_nested_parens=true 35 | align_keep_tabs=false 36 | align_with_tabs=false 37 | align_on_tabstop=false 38 | align_number_left=true 39 | align_func_params=false 40 | align_same_func_call_params=false 41 | align_var_def_colon=false 42 | align_var_def_attribute=false 43 | align_var_def_inline=false 44 | align_right_cmt_mix=false 45 | align_on_operator=false 46 | align_mix_var_proto=false 47 | align_single_line_func=false 48 | align_single_line_brace=false 49 | align_nl_cont=false 50 | align_left_shift=true 51 | align_oc_decl_colon=false 52 | nl_collapse_empty_body=false 53 | nl_assign_leave_one_liners=false 54 | nl_class_leave_one_liners=false 55 | nl_enum_leave_one_liners=false 56 | nl_getset_leave_one_liners=false 57 | nl_func_leave_one_liners=false 58 | nl_if_leave_one_liners=false 59 | nl_multi_line_cond=false 60 | nl_multi_line_define=false 61 | nl_before_case=true 62 | nl_after_case=true 63 | nl_after_return=false 64 | nl_after_semicolon=true 65 | nl_after_brace_open=true 66 | nl_after_brace_open_cmt=true 67 | nl_after_vbrace_open=false 68 | nl_after_vbrace_open_empty=false 69 | nl_after_brace_close=false 70 | nl_after_vbrace_close=false 71 | nl_define_macro=false 72 | nl_squeeze_ifdef=false 73 | nl_ds_struct_enum_cmt=false 74 | nl_ds_struct_enum_close_brace=false 75 | nl_create_if_one_liner=false 76 | nl_create_for_one_liner=false 77 | nl_create_while_one_liner=false 78 | ls_for_split_full=true 79 | ls_func_split_full=true 80 | nl_after_multiline_comment=false 81 | eat_blanks_after_open_brace=false 82 | eat_blanks_before_close_brace=true 83 | mod_full_brace_if_chain=false 84 | mod_pawn_semicolon=false 85 | mod_full_paren_if_bool=false 86 | mod_remove_extra_semicolon=false 87 | mod_sort_import=false 88 | mod_sort_using=false 89 | mod_sort_include=false 90 | mod_move_case_break=false 91 | mod_remove_empty_return=false 92 | cmt_indent_multi=true 93 | cmt_c_group=false 94 | cmt_c_nl_start=false 95 | cmt_c_nl_end=false 96 | cmt_cpp_group=false 97 | cmt_cpp_nl_start=false 98 | cmt_cpp_nl_end=false 99 | cmt_cpp_to_c=false 100 | cmt_star_cont=true 101 | cmt_multi_check_last=true 102 | cmt_insert_before_preproc=false 103 | pp_indent_at_level=false 104 | pp_region_indent_code=false 105 | pp_if_indent_code=false 106 | pp_define_at_level=false 107 | indent_columns=4 108 | indent_switch_case=0 109 | indent_case_brace=0 110 | indent_access_spec=-4 111 | align_var_def_star_style=0 112 | align_var_def_amp_style=0 113 | align_assign_span=1 114 | align_right_cmt_span=2 115 | align_right_cmt_at_col=1 116 | nl_end_of_file_min=1 117 | nl_func_var_def_blk=1 118 | code_width=120 119 | nl_max=3 120 | nl_after_func_proto_group=2 121 | nl_after_func_body=2 122 | nl_after_func_body_class=2 123 | nl_after_func_body_one_liner=2 124 | nl_after_class=2 125 | nl_after_access_spec=2 126 | mod_add_long_function_closebrace_comment=10 127 | mod_add_long_switch_closebrace_comment=10 128 | mod_add_long_ifdef_endif_comment=8 129 | mod_add_long_ifdef_else_comment=8 130 | cmt_width=80 131 | newlines=auto 132 | utf8_bom=remove 133 | indent_with_tabs=0 134 | sp_arith=ignore 135 | sp_assign=add 136 | sp_after_assign=add 137 | sp_bool=add 138 | sp_compare=add 139 | sp_after_comma=add 140 | sp_type_func=add 141 | sp_func_proto_paren=add 142 | sp_else_brace=add 143 | sp_catch_brace=add 144 | sp_finally_brace=add 145 | nl_end_of_file=force 146 | nl_brace_else=add 147 | nl_brace_finally=add 148 | nl_brace_catch=add 149 | nl_brace_brace=add 150 | pos_arith=lead 151 | pos_assign=lead 152 | pos_comma=trail 153 | mod_full_brace_do=add 154 | mod_full_brace_for=add 155 | mod_full_brace_if=add 156 | mod_full_brace_while=add 157 | pp_indent=ignore 158 | pp_space=ignore 159 | -------------------------------------------------------------------------------- /cmake/GetGitRevisionDescription.cmake: -------------------------------------------------------------------------------- 1 | # - Returns a version string from Git 2 | # 3 | # These functions force a re-configure on each git commit so that you can 4 | # trust the values of the variables in your build system. 5 | # 6 | # get_git_head_revision( [ ...]) 7 | # 8 | # Returns the refspec and sha hash of the current head revision 9 | # 10 | # git_describe( [ ...]) 11 | # 12 | # Returns the results of git describe on the source tree, and adjusting 13 | # the output so that it tests false if an error occurs. 14 | # 15 | # git_get_exact_tag( [ ...]) 16 | # 17 | # Returns the results of git describe --exact-match on the source tree, 18 | # and adjusting the output so that it tests false if there was no exact 19 | # matching tag. 20 | # 21 | # Requires CMake 2.6 or newer (uses the 'function' command) 22 | # 23 | # Original Author: 24 | # 2009-2010 Ryan Pavlik 25 | # http://academic.cleardefinition.com 26 | # Iowa State University HCI Graduate Program/VRAC 27 | # 28 | # Copyright Iowa State University 2009-2010. 29 | # Distributed under the Boost Software License, Version 1.0. 30 | # (See accompanying file LICENSE_1_0.txt or copy at 31 | # http://www.boost.org/LICENSE_1_0.txt) 32 | 33 | if(__get_git_revision_description) 34 | return() 35 | endif() 36 | set(__get_git_revision_description YES) 37 | 38 | # We must run the following at "include" time, not at function call time, 39 | # to find the path to this module rather than the path to a calling list file 40 | get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) 41 | 42 | function(get_git_head_revision _refspecvar _hashvar) 43 | set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") 44 | set(GIT_DIR "${GIT_PARENT_DIR}/.git") 45 | while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories 46 | set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}") 47 | get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH) 48 | if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT) 49 | # We have reached the root directory, we are not in git 50 | set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE) 51 | set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE) 52 | return() 53 | endif() 54 | set(GIT_DIR "${GIT_PARENT_DIR}/.git") 55 | endwhile() 56 | # check if this is a submodule 57 | if(NOT IS_DIRECTORY ${GIT_DIR}) 58 | file(READ ${GIT_DIR} submodule) 59 | string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule}) 60 | get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH) 61 | get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE) 62 | endif() 63 | set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") 64 | if(NOT EXISTS "${GIT_DATA}") 65 | file(MAKE_DIRECTORY "${GIT_DATA}") 66 | endif() 67 | 68 | if(NOT EXISTS "${GIT_DIR}/HEAD") 69 | return() 70 | endif() 71 | set(HEAD_FILE "${GIT_DATA}/HEAD") 72 | configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY) 73 | 74 | configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" 75 | "${GIT_DATA}/grabRef.cmake" 76 | @ONLY) 77 | include("${GIT_DATA}/grabRef.cmake") 78 | 79 | set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE) 80 | set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE) 81 | endfunction() 82 | 83 | function(git_describe _var) 84 | if(NOT GIT_FOUND) 85 | find_package(Git QUIET) 86 | endif() 87 | get_git_head_revision(refspec hash) 88 | if(NOT GIT_FOUND) 89 | set(${_var} "GIT-NOTFOUND" PARENT_SCOPE) 90 | return() 91 | endif() 92 | if(NOT hash) 93 | set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) 94 | return() 95 | endif() 96 | 97 | # TODO sanitize 98 | #if((${ARGN}" MATCHES "&&") OR 99 | # (ARGN MATCHES "||") OR 100 | # (ARGN MATCHES "\\;")) 101 | # message("Please report the following error to the project!") 102 | # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") 103 | #endif() 104 | 105 | #message(STATUS "Arguments to execute_process: ${ARGN}") 106 | 107 | execute_process(COMMAND 108 | "${GIT_EXECUTABLE}" 109 | describe 110 | ${hash} 111 | ${ARGN} 112 | WORKING_DIRECTORY 113 | "${CMAKE_SOURCE_DIR}" 114 | RESULT_VARIABLE 115 | res 116 | OUTPUT_VARIABLE 117 | out 118 | ERROR_QUIET 119 | OUTPUT_STRIP_TRAILING_WHITESPACE) 120 | if(NOT res EQUAL 0) 121 | set(out "${out}-${res}-NOTFOUND") 122 | endif() 123 | 124 | set(${_var} "${out}" PARENT_SCOPE) 125 | endfunction() 126 | 127 | function(git_get_exact_tag _var) 128 | git_describe(out --exact-match ${ARGN}) 129 | set(${_var} "${out}" PARENT_SCOPE) 130 | endfunction() 131 | -------------------------------------------------------------------------------- /include/device.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Base class for Devices 3 | * \file device.hpp 4 | * \copyright LGPL v3 5 | * 6 | * Defines a base interface for all Devices in the Virtual Computer 7 | */ 8 | #ifndef __IDEVICE_HPP_ 9 | #define __IDEVICE_HPP_ 1 10 | 11 | #include "types.hpp" 12 | #include "vc_dll.hpp" 13 | 14 | namespace trillek { 15 | namespace computer { 16 | 17 | class VComputer; 18 | 19 | /** 20 | * \class Device 21 | * Interface that must be implemente by any Device that will be used by the 22 | * Virtual Computer. 23 | * Derived class constructors should set vcomp == nullptr. 24 | */ 25 | class DECLDIR Device { 26 | public: 27 | 28 | virtual ~Device() { 29 | } 30 | 31 | /** 32 | * Sets the VComputer pointer 33 | * This method must be only called by VComputer itself 34 | * \param[in] vcomp VComputer pointer or nullptr 35 | * \sa VComputer 36 | */ 37 | virtual void SetVComputer (VComputer* _vcomp) { 38 | this->vcomp = _vcomp; 39 | } 40 | 41 | /** 42 | * Resets device internal state 43 | * Called by VComputer 44 | */ 45 | virtual void Reset () = 0; 46 | 47 | /** 48 | * Sends (writes to CMD register) a command to the device 49 | * \param cmd Command value to send 50 | */ 51 | virtual void SendCMD (Word) = 0; 52 | 53 | virtual void A (Word) { 54 | } /// Set A register value 55 | 56 | virtual void B (Word) { 57 | } /// Set B register value 58 | 59 | virtual void C (Word) { 60 | } /// Set C register value 61 | 62 | virtual void D (Word) { 63 | } /// Set D register value 64 | 65 | virtual void E (Word) { 66 | } /// Set E register value 67 | 68 | virtual Word A () { 69 | return 0; 70 | } /// Return A register value 71 | 72 | virtual Word B () { 73 | return 0; 74 | } /// Return B register value 75 | 76 | virtual Word C () { 77 | return 0; 78 | } /// Return C register value 79 | 80 | virtual Word D () { 81 | return 0; 82 | } /// Return D register value 83 | 84 | virtual Word E () { 85 | return 0; 86 | } /// Return E register value 87 | 88 | /** 89 | * Device Type 90 | */ 91 | virtual Byte DevType () const = 0; 92 | 93 | /** 94 | * Device SubType 95 | */ 96 | virtual Byte DevSubType () const = 0; 97 | 98 | /** 99 | * Device ID 100 | */ 101 | virtual Byte DevID () const = 0; 102 | 103 | /** 104 | * Device Vendor ID 105 | */ 106 | virtual DWord DevVendorID () const = 0; 107 | 108 | /** 109 | * Return if the device does something each Device Clock cycle. 110 | * Few devices really need to do this, so IDevice implementation 111 | * returns false. 112 | */ 113 | virtual bool IsSyncDev() const { 114 | return false; 115 | } 116 | 117 | /** 118 | * Executes N Device clock cycles. 119 | * 120 | * Here resides the code that is executed every Device Clock tick. 121 | * IDevice implementation does nothing. 122 | * \param n Number of clock cycles to be executed 123 | * \param delta Number milliseconds since the last call 124 | */ 125 | virtual void Tick (unsigned, const double) { 126 | } 127 | 128 | /** 129 | * Checks if the device is trying to generate an interrupt 130 | * 131 | * IDevice implementation does nothing. 132 | * \param[out] msg The interrupt message will be writen here 133 | * \return True if is generating a new interrupt 134 | */ 135 | virtual bool DoesInterrupt(Word&) { 136 | return false; 137 | } 138 | 139 | /** 140 | * Informs to the device that his generated interrupt was accepted by the 141 | **CPU 142 | * 143 | * IDevice implementation does nothing. 144 | */ 145 | virtual void IACK () { 146 | } 147 | 148 | /** 149 | * Writes a copy of Device state in a chunk of memory pointer by ptr. 150 | * \param[out] ptr Pointer were to write 151 | * \param[in,out] size Size of the chunk of memory were can write. If is 152 | * sucesfull, it will be set to the size of the write data. 153 | */ 154 | virtual void GetState (void* ptr, std::size_t& size) const = 0; 155 | 156 | /** 157 | * Sets the Device state. 158 | * \param ptr[in] Pointer were read the state information 159 | * \param size Size of the chunk of memory were will read. 160 | * \return True if can read the State data from the pointer. 161 | */ 162 | virtual bool SetState (const void* ptr, std::size_t size) = 0; 163 | 164 | protected: 165 | 166 | VComputer* vcomp; /// Ptr to the Virtual Computer 167 | }; 168 | 169 | } // End of namespace computer 170 | } // End of namespace trillek 171 | 172 | #endif // __IDEVICE_HPP_ 173 | 174 | -------------------------------------------------------------------------------- /src/dcpu16n/dis_dcpu16n.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Trillek Virtual Computer - DisDCPU16N.cpp 3 | * OnLine dis-assembly of DCPU-16N machine code 4 | * 5 | * Implementation of the DCPU-16N CPU v0.8 6 | * @see https://gist.github.com/Meisaka/8800367 7 | */ 8 | 9 | #include "dcpu16n/dis_dcpu16n.hpp" 10 | #include "vs_fix.hpp" 11 | 12 | #include 13 | 14 | namespace trillek { 15 | namespace computer { 16 | 17 | static const char *DCPU16N_OPCN[] = { 18 | "---", "SET", "ADD", "SUB", "MUL", "MLI", "DIV", "DVI", 19 | "MOD", "MDI", "AND", "BOR", "XOR", "SHR", "ASR", "SHL", 20 | "IFB", "IFC", "IFE", "IFN", "IFG", "IFA", "IFL", "IFU", 21 | "???", "???", "ADX", "SBX", "HWW", "HWR", "STI", "STD" 22 | }; 23 | 24 | static const char *DCPU16N_OPCS[] = { 25 | "---", "JSR", "BSR", "???", "???", "NEG", "???", "HCF", 26 | "INT", "IAG", "IAS", "RFI", "IAQ", "???", "???", "???", 27 | "MMW", "MMR", "???", "???", "SXB", "SWP", "???", "???", 28 | "???", "???", "???", "???", "???", "???", "???", "???" 29 | }; 30 | 31 | static const char *DCPU16N_OPCI[] = { 32 | "HLT", "SLP", "???", "???", "BYT", "???", "???", "???", 33 | "???", "???", "???", "???", "???", "???", "???", "???", 34 | "SKP", "???", "???", "???", "???", "???", "???", "???", 35 | "???", "???", "???", "???", "???", "???", "???", "???" 36 | }; 37 | 38 | struct DCPU16N_DisInfo { 39 | const char *pre; 40 | const char *suf; 41 | bool fetch; 42 | }; 43 | 44 | const DCPU16N_DisInfo DCPU16N_Operand[] = { 45 | { "A", "", false }, { "B", "", false }, { "C", "", false }, 46 | { "X", "", false }, { "Y", "", false }, { "Z", "", false }, 47 | { "I", "", false }, { "J", "", false }, 48 | { "[A]", "", false }, { "[B]", "", false }, { "[C]", "", false }, 49 | { "[X]", "", false }, { "[Y]", "", false }, { "[Z]", "", false }, 50 | { "[I]", "", false }, { "[J]", "", false }, 51 | { "[A+", "]", true }, { "[B+", "]", true }, { "[C+", "]", true }, 52 | { "[X+", "]", true }, { "[Y+", "]", true }, { "[Z+", "]", true }, 53 | { "[I+", "]", true }, { "[J+", "]", true }, 54 | { "[SP++]", "[--SP]", false }, { "[SP]", "", false }, 55 | { "[SP+", "]", true }, { "SP", "", false }, 56 | { "PC", "", false }, { "EX", "", false }, 57 | { "[", "]", true }, { "", "", true } 58 | }; 59 | 60 | std::string DisassemblyDCPU16N(const VComputer& vc, DWord pc) { 61 | Word opc = ( ((Word)vc.ReadB(pc + 1)) << 8 ) 62 | | (Word)vc.ReadB(pc); 63 | Word opta, optb; 64 | Word opa, opb; 65 | #define BUF_SIZE (32) 66 | char buf[BUF_SIZE] = { 0, }; 67 | std::string obja, objb; 68 | if((opc & 0x001f) != 0 || (opc & 0x03e0) != 0) { 69 | opta = opc >> 10; 70 | if(opta & 0x20) { 71 | snprintf(buf, BUF_SIZE, "%d", ((int)opta) - 33); 72 | obja.assign(buf); 73 | } 74 | else if(opta == 0x18) { 75 | obja.assign(DCPU16N_Operand[0x18].suf); 76 | } 77 | else { 78 | obja.assign(DCPU16N_Operand[opta & 0x1f].pre); 79 | if(DCPU16N_Operand[opta & 0x1f].fetch) { 80 | pc += 2; 81 | opa = ( ((Word)vc.ReadB(pc + 1)) << 8 ) 82 | | (Word)vc.ReadB(pc); 83 | snprintf(buf, BUF_SIZE, "0x%04X", opa); 84 | obja.append(buf); 85 | } 86 | obja.append(DCPU16N_Operand[opta & 0x1f].suf); 87 | } 88 | } 89 | if((opc & 0x001f) != 0) { 90 | optb = (opc >> 5) & 0x01f; 91 | if(optb == 0x18) { 92 | objb.assign(DCPU16N_Operand[0x18].pre); 93 | } 94 | else { 95 | objb.assign(DCPU16N_Operand[optb & 0x1f].pre); 96 | if(DCPU16N_Operand[optb & 0x1f].fetch) { 97 | pc += 2; 98 | opb = ( ((Word)vc.ReadB(pc + 1)) << 8 ) 99 | | (Word)vc.ReadB(pc); 100 | snprintf(buf, BUF_SIZE, "0x%04X", opb); 101 | objb.append(buf); 102 | } 103 | objb.append(DCPU16N_Operand[optb & 0x1f].suf); 104 | } 105 | } 106 | std::string opname; 107 | if((opc & 0x001f) != 0) { 108 | opname.assign(DCPU16N_OPCN[opc & 0x1f]); 109 | opname.append(" "); 110 | opname.append(objb); 111 | opname.append(","); 112 | opname.append(obja); 113 | } 114 | else if((opc & 0x03e0) != 0) { 115 | opname.assign(DCPU16N_OPCS[(opc >> 5) & 0x1f]); 116 | opname.append(" "); 117 | opname.append(obja); 118 | } 119 | else { 120 | opname.assign(DCPU16N_OPCI[(opc >> 10) & 0x1f]); 121 | if(opc & 0x8000) { 122 | opname.append(" 1"); 123 | } 124 | else { 125 | opname.append(" 0"); 126 | } 127 | } 128 | return opname; 129 | } 130 | 131 | } // namespace computer 132 | } // namespace trillek 133 | 134 | -------------------------------------------------------------------------------- /tests/benchmark.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Trillek Virtual Computer - benchmark.cpp 3 | * Basic benchmark for Virtual Computer lib 4 | * Allow to see how many virtual computer can run in a single thread 5 | */ 6 | #include "vc.hpp" 7 | #include "devices/dummy_device.hpp" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | #define NCPUS 1000 25 | 26 | int n_cpus = NCPUS; 27 | 28 | int main(int argc, char* argv[]) { 29 | using namespace trillek; 30 | using namespace trillek::computer; 31 | 32 | 33 | if (argc < 2) { 34 | std::printf("Usage: %s binary_files [number of cpus] [seed]\n", argv[0]); 35 | return -1; 36 | 37 | } 38 | 39 | 40 | unsigned seed = std::time(0); 41 | if (std::atoi(argv[argc-1]) > 0 && std::atoi(argv[argc-2]) > 0) { // cpus + seed 42 | n_cpus = std::atoi(argv[argc-2]); 43 | seed = (unsigned) std::atoi(argv[argc-1]); 44 | argc--; argc--; 45 | 46 | } else if (std::atoi(argv[argc-1]) > 0 ) { // Only number of cpus 47 | n_cpus = std::atoi(argv[argc-1]); 48 | argc--; 49 | } 50 | 51 | std::srand(seed); 52 | 53 | unsigned troms = argc -1; 54 | Byte **rom = new Byte*[troms]; 55 | size_t *rom_size = new size_t[troms]; 56 | 57 | for (unsigned i=0; i< troms; i++) { 58 | rom[i] = new Byte[32*1024]; 59 | 60 | std::printf("Opening file %s\n", argv[1 + i]); 61 | int size = LoadROM(argv[1+ i], rom[i]); 62 | if (size < 0) { 63 | std::fprintf(stderr, "An error hapen when was reading the file %s\n", argv[1]); 64 | return -1; 65 | } 66 | 67 | std::printf("Read %u bytes and stored in ROM\n", size); 68 | rom_size[i] = size; 69 | } 70 | 71 | std::printf("Seed : %d\n", seed); 72 | std::printf("Runing :\n~1%% @ 1MHz\n~10%% @ 0.5MHz\n~20%% @ 0.2MHz\n~59%% @ 0.1MHz\n~10%% @ 0.01MHz\n"); 73 | VComputer *vc = new VComputer[n_cpus]; 74 | for (auto i=0; i< n_cpus; i++) { 75 | // Add CPU 76 | unsigned cpu_clk = std::rand() % 100; 77 | if (cpu_clk <= 1 ) { // ~1% -> 1 Mhz 78 | cpu_clk = 1000000; 79 | } else if (cpu_clk <= 11 ) { // ~10% -> 0.5 MHz 80 | cpu_clk = 500000; 81 | } else if (cpu_clk <= 21 ) { // ~10% -> 10 KHz 82 | cpu_clk = 10000; 83 | } else if (cpu_clk <= 41 ) { // ~20% -> 200 KHz 84 | cpu_clk = 200000; 85 | } else { // ~59% -> 100 KHz 86 | cpu_clk = 100000; 87 | } 88 | std::unique_ptr cpu(new TR3200(cpu_clk)); 89 | vc[i].SetCPU(std::move(cpu)); 90 | 91 | // Add ROM 92 | auto rom_ptr = rom[i % troms]; 93 | auto rom_s = rom_size[i % troms]; 94 | vc[i].SetROM(rom_ptr, rom_s); 95 | 96 | // Add devices 97 | auto gcard = std::make_shared(); 98 | vc[i].AddDevice(5, gcard); 99 | 100 | auto gk = std::make_shared(); 101 | vc[i].AddDevice(4, gcard); 102 | 103 | auto ddev = std::make_shared(); 104 | vc[i].AddDevice(10, ddev); 105 | 106 | // Powering itt 107 | vc[i].On(); 108 | } 109 | 110 | std::cout << "Randomizing every CPU!\nExecuting a random number of cycles from 1 to 255\n"; 111 | for (auto i=0; i< n_cpus; i++) { 112 | vc[i].Tick((std::rand() % 255) + 1); 113 | } 114 | 115 | std::cout << "Running " << n_cpus << " CPUs !\n"; 116 | unsigned ticks = 50000; // 0.05 seconds 117 | unsigned long ticks_count = 0; 118 | 119 | using namespace std::chrono; 120 | auto clock = high_resolution_clock::now(); 121 | double delta; 122 | 123 | auto oldClock = clock; 124 | clock = high_resolution_clock::now(); 125 | delta = duration_cast(clock - oldClock).count(); 126 | 127 | while ( 1) { 128 | 129 | for (auto i=0; i< n_cpus; i++) { 130 | vc[i].Tick(ticks, delta / 1000.0 ); 131 | } 132 | 133 | ticks_count += ticks; 134 | 135 | auto oldClock = clock; 136 | clock = high_resolution_clock::now(); 137 | delta = duration_cast(clock - oldClock).count(); 138 | 139 | 140 | // Speed info 141 | if (ticks_count > 800000) { 142 | std::printf("Running %u cycles in %f ms ", ticks, delta); 143 | double ttick = delta / ticks; 144 | double tclk = 1000.0 / 1000000.0; // Base clock 1Mhz 145 | std::printf("Ttick %f ms ", ttick); 146 | std::printf("Tclk %f ms ", tclk); 147 | std::printf("Speed of %f %% \n", 100.0f * (tclk / ttick) ); 148 | ticks_count -= 200000; 149 | } 150 | //ticks = (vm[0].Clock() * delta * 0.000001) + 0.5f; // Rounding bug in VS 151 | 152 | } 153 | 154 | 155 | // Free ROMs 156 | for (unsigned i=0; i< troms; i++) { 157 | delete[] rom[i]; 158 | } 159 | 160 | return 0; 161 | } 162 | 163 | 164 | -------------------------------------------------------------------------------- /asm/tr3200/clock.asm: -------------------------------------------------------------------------------- 1 | ; Simple Clock program in TR3200 ASM 2 | .ORG 0x100000 ; This a ROM image, so jumps need to know the real address 3 | 4 | MOV %sp, 0x020000 ; Sets Stack Pointer to the end of the 128KiB RAM 5 | 6 | ;****************************************************************************** 7 | ; Code to find the first TDA plugged device 8 | MOV %r10, 0x10FF00 9 | begin_search_tda: 10 | ADD %r10, %r10, 0x100 11 | IFEQ %r10, 0x112100 ; Not found any TDA device 12 | JMP end_search_tda 13 | 14 | LOADB %r0, %r10 15 | IFNEQ %r0, 0xFF ; Device Present ? 16 | JMP begin_search_tda 17 | 18 | ADD %r1, %r10, 1 19 | LOADB %r0, %r1 20 | IFNEQ %r0, 0x0E ; Is a Graphics device ? 21 | JMP begin_search_tda 22 | 23 | ADD %r1, %r10, 2 24 | LOADB %r0, %r1 25 | IFNEQ %r0, 0x01 ; Is TDA compatible ? 26 | JMP begin_search_tda 27 | 28 | end_search_tda: 29 | IFEQ %r10, 0x112100 30 | JMP crash ; Not found, so type on what ? 31 | STORE TDA_base_dev, %r10 ; We put in the var that we don't found anything 32 | 33 | IFEQ %r10, 0xFFFFFFFF 34 | JMP crash ; We skips print code 35 | 36 | ; Configure TDA to use a text buffer in 0x001000 37 | ADD %r0, %r10, 0x0A 38 | 39 | MOV %r1, 0x001000 40 | STORE %r0, %r1 ; Set B:A to point to 0x001000 41 | 42 | ADD %r0, %r10, 0x08 43 | MOV %r1, 0 44 | STOREW %r0, %r1 ; Send command to point Text buffer to B:A address 45 | 46 | ; Clears the screen 47 | MOV %r0, 0x001000 48 | MOV %r1, 0x48 ; Dark blue paper, Yellow Ink 49 | CALL clr_screen 50 | 51 | ;****************************************************************************** 52 | 53 | ; Config interrupts (sets the Vector Table entry for TMR0) 54 | MOV %ia, vtable ; IA points to the vector table 55 | MOV %r0, tmr0_isr 56 | MOV %r1, 0x01 ; Interrupt message LSB (0x0001 for TMR0) 57 | LLS %r1, %r1, 2 ; x4 as each entry needs four bytes 58 | 59 | ADD %r1, %r1, %ia ; vtable[%r1] (STORE %ia + %r1, %r0 ) 60 | STORE %r1, %r0 ; vtable[%r1] = tmr0_isr function address 61 | 62 | MOV %flags, 0x100 ; And enable interrupts 63 | 64 | ; Sets TMR0 reload value 65 | MOV %r0, 100000 66 | STORE 0x11E004, %r0 67 | 68 | ; Enables TMR0 and enables his interrupt 69 | MOV %r0, 3 70 | STOREB 0x11E010, %r0 71 | ; With 100000 reload value, the TMR0 will undeflow every second, because 72 | ; 100000 ticks at 100KHz of device clock, it's 1 second. 73 | 74 | ; Pre print the ':'s 75 | ; Calc offset of were we desired to rpint 76 | MOV %r0, 14 ; Row 14 77 | MOV %r1, 18 ; Column 18 78 | CALL get_offset_from_row_col 79 | ADD %r1, %r0, 0x001000 ; %r1 points were we disred to write 80 | MOV %r0, str_dots 81 | MOV %r2, 0x4F ; Dark blue paper, White ink 82 | CALL print 83 | 84 | ;****************************************************************************** 85 | loop: 86 | ; Print the clok 87 | 88 | ; *** Secs 89 | ; Calc offset of were we desired to rpint 90 | MOV %r0, 14 ; Row 14 91 | MOV %r1, 22 ; Column 22 92 | CALL get_offset_from_row_col 93 | ADD %r1, %r0, 0x001000 ; %r1 points were we disred to write 94 | 95 | ; Print secs 96 | LOADB %r0, sec 97 | MOV %r2, 0x48 ; Dark blue paper, Yellow ink 98 | CALL print_hex_b 99 | 100 | ; *** Minutes 101 | ; Calc offset of were we desired to rpint 102 | MOV %r0, 14 ; Row 14 103 | MOV %r1, 19 ; Column 19 104 | CALL get_offset_from_row_col 105 | ADD %r1, %r0, 0x001000 ; %r1 points were we disred to write 106 | 107 | LOADB %r0, min 108 | MOV %r2, 0x48 ; Dark blue paper, Yellow ink 109 | CALL print_hex_b 110 | 111 | ; *** Hours 112 | ; Calc offset of were we desired to rpint 113 | MOV %r0, 14 ; Row 14 114 | MOV %r1, 16 ; Column 16 115 | CALL get_offset_from_row_col 116 | ADD %r1, %r0, 0x001000 ; %r1 points were we disred to write 117 | 118 | LOADB %r0, hour 119 | MOV %r2, 0x48 ; Dark blue paper, Yellow ink 120 | CALL print_hex_b 121 | 122 | SLEEP ; Hey we not need to reprint every time, only when we wake up! 123 | 124 | ;LOADB %r0, sec 125 | ;ADD %r0, %r0, 1 126 | ;STOREB sec, %r0 127 | JMP loop 128 | 129 | ;****************************************************************************** 130 | tmr0_isr: 131 | ; TMR0 interrupt Increase the time counter 132 | LOADB %r0, sec 133 | ADD %r0, %r0, 1 134 | STOREB sec, %r0 135 | 136 | IFL %r0, 60 ; Only increase min if sec >= 60, so we end the rutine 137 | RFI 138 | 139 | MOV %r0, 0 ; sec >= 60 -> sec = 0; min++; 140 | STOREB sec, %r0 141 | 142 | LOADB %r0, min 143 | ADD %r0, %r0, 1 144 | STOREB min, %r0 145 | 146 | IFL %r0, 60 ; Only increase hour if min >= 60, so we end the rutine 147 | RFI 148 | 149 | MOV %r0, 0 ; min >= 60 -> min = 0; hour++; 150 | STOREB min, %r0 151 | 152 | LOADB %r0, hour 153 | ADD %r0, %r0, 1 154 | STOREB hour, %r0 155 | 156 | IFL %r0, 24 ;If hour >= 24 then hour = 0 157 | RFI 158 | 159 | MOV %r0, 0 160 | STOREB hour, %r0 161 | 162 | RFI 163 | 164 | :crash 165 | SLEEP 166 | JMP crash 167 | 168 | .include "BROM.ainc" 169 | 170 | ;****************************************************************************** 171 | ; Const data 172 | str_dots: .DB ": :",0 ;ASCIIZ string 173 | 174 | ;****************************************************************************** 175 | ; RAM data 176 | 177 | .ORG 0x0 178 | vtable: .DB 0 ; Interrupt vector table 179 | 180 | .ORG 0x400 ; Our variables 181 | 182 | sec: .DB 0 183 | min: .DB 0 184 | hour: .DW 0 185 | 186 | :TDA_base_dev .DW 0 187 | 188 | -------------------------------------------------------------------------------- /src/enum_and_ctrl_blk.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Enumeration and Control/status address Block 3 | * \file enum_and_ctrl_blk.cpp 4 | * \copyright LGPL v3 5 | * 6 | * An specialized Address Listener used by VComputer to implement 7 | * Enumeration and Control registers in a slot 8 | */ 9 | 10 | #include "vcomputer.hpp" 11 | #include "enum_and_ctrl_blk.hpp" 12 | #include "vs_fix.hpp" 13 | 14 | #include 15 | 16 | namespace trillek { 17 | namespace computer { 18 | 19 | EnumAndCtrlBlk::EnumAndCtrlBlk (unsigned slot, Device* dev) : 20 | slot(slot), dev(dev) { 21 | assert (slot < MAX_N_DEVICES); 22 | assert (dev != nullptr); 23 | } 24 | 25 | Range EnumAndCtrlBlk::GetRange () const { 26 | DWord start = 0x110000 | (slot<<8); 27 | DWord end = start + EnumCtrlBlkSize; 28 | 29 | return Range(start, end); 30 | } 31 | 32 | Byte EnumAndCtrlBlk::ReadB (DWord addr) { 33 | addr -= 0x110000 | (slot<<8); 34 | switch (addr) { 35 | // Enumeration stuff 36 | case 0: 37 | return 0xFF; // Presence byte 38 | break; 39 | 40 | case 1: 41 | return dev->DevType(); 42 | break; 43 | 44 | case 2: 45 | return dev->DevSubType(); 46 | break; 47 | 48 | case 3: 49 | return dev->DevID(); 50 | break; 51 | 52 | case 4: 53 | return dev->DevVendorID(); 54 | break; 55 | 56 | case 5: 57 | return dev->DevVendorID() >> 8; 58 | break; 59 | 60 | case 6: 61 | return dev->DevVendorID() >> 16; 62 | break; 63 | 64 | case 7: 65 | return dev->DevVendorID() >> 24; 66 | break; 67 | 68 | // Control and status stuff 69 | case 8: 70 | return 0; 71 | break; 72 | 73 | case 9: 74 | return 0; 75 | break; 76 | 77 | case 0x0A: 78 | return dev->A(); 79 | break; 80 | 81 | case 0x0B: 82 | return dev->A() >> 8; 83 | break; 84 | 85 | case 0x0C: 86 | return dev->B(); 87 | break; 88 | 89 | case 0x0D: 90 | return dev->B() >> 8; 91 | break; 92 | 93 | case 0x0E: 94 | return dev->C(); 95 | break; 96 | 97 | case 0x0F: 98 | return dev->C() >> 8; 99 | break; 100 | 101 | case 0x10: 102 | return dev->D(); 103 | break; 104 | 105 | case 0x11: 106 | return dev->D() >> 8; 107 | break; 108 | 109 | case 0x12: 110 | return dev->E(); 111 | break; 112 | 113 | case 0x13: 114 | return dev->E() >> 8; 115 | break; 116 | 117 | default: 118 | return 0; 119 | } // switch 120 | } // ReadB 121 | 122 | Word EnumAndCtrlBlk::ReadW (DWord addr) { 123 | return this->ReadB(addr) | (this->ReadB(addr+1) << 8); 124 | // TODO Improve this in the aligned cases 125 | } 126 | 127 | DWord EnumAndCtrlBlk::ReadDW (DWord addr) { 128 | return this->ReadW(addr) | (this->ReadW(addr+2) << 16); 129 | } 130 | 131 | void EnumAndCtrlBlk::WriteB (DWord addr, Byte val) { 132 | addr -= 0x110000 | (slot<<8); 133 | switch (addr) { 134 | // Control and status stuff 135 | // NOTE: Only the MSB byte write send the command as wll be usually the 136 | // last write value 137 | case 8: // Cmd 138 | cmd = (cmd & 0xFF00) | val; 139 | //dev->SendCMD(cmd); 140 | break; 141 | 142 | case 9: 143 | cmd = (cmd & 0x00FF) | (val << 8); 144 | dev->SendCMD(cmd); 145 | break; 146 | 147 | case 0x0A: // A reg 148 | a = (a & 0xFF00) | val; 149 | //dev->A(a); 150 | break; 151 | 152 | case 0x0B: 153 | a = (a & 0x00FF) | (val << 8); 154 | dev->A(a); 155 | break; 156 | 157 | case 0x0C: // B reg 158 | b = (b & 0xFF00) | val; 159 | //dev->B(b); 160 | break; 161 | 162 | case 0x0D: 163 | b = (b & 0x00FF) | (val << 8); 164 | dev->B(b); 165 | break; 166 | 167 | case 0x0E: // C reg 168 | c = (c & 0xFF00) | val; 169 | //dev->C(c); 170 | break; 171 | 172 | case 0x0F: 173 | c = (c & 0x00FF) | (val << 8); 174 | dev->C(c); 175 | break; 176 | 177 | case 0x10: // D reg 178 | d = (d & 0xFF00) | val; 179 | //dev->D(d); 180 | break; 181 | 182 | case 0x11: 183 | d = (d & 0x00FF) | (val << 8); 184 | dev->D(d); 185 | break; 186 | 187 | case 0x12: // E reg 188 | e = (e & 0xFF00) | val; 189 | //dev->E(e); 190 | break; 191 | 192 | case 0x13: 193 | e = (e & 0x00FF) | (val << 8); 194 | dev->E(e); 195 | break; 196 | 197 | default: 198 | break; 199 | } // switch 200 | } // WriteB 201 | 202 | void EnumAndCtrlBlk::WriteW (DWord addr, Word val) { 203 | switch (addr) { 204 | // Control and status stuff 205 | case 8: // Cmd 206 | cmd = val; 207 | dev->SendCMD(val); 208 | break; 209 | 210 | case 0x0A: // A reg 211 | a = val; 212 | dev->A(val); 213 | break; 214 | 215 | case 0x0C: // B reg 216 | b = val; 217 | dev->B(val); 218 | break; 219 | 220 | case 0x0E: // C reg 221 | c = val; 222 | dev->C(val); 223 | break; 224 | 225 | case 0x10: // D reg 226 | d = val; 227 | dev->D(val); 228 | break; 229 | 230 | case 0x12: // E reg 231 | e = val; 232 | dev->E(val); 233 | break; 234 | 235 | default: 236 | this->WriteB(addr, val); 237 | this->WriteB(addr+1, val >> 8); 238 | } // switch 239 | } // WriteW 240 | 241 | void EnumAndCtrlBlk::WriteDW (DWord addr, DWord val) { 242 | this->WriteW(addr, val); 243 | this->WriteW(addr+2, val >> 16); 244 | } 245 | 246 | } // End of namespace computer 247 | } // End of namespace trillek 248 | -------------------------------------------------------------------------------- /asm/tr3200/floppy.asm: -------------------------------------------------------------------------------- 1 | .ORG 0x100000 ; This a ROM image 2 | 3 | vector_table .equ 0x10000 4 | 5 | MOV %SP, 0x020000 ; Sets Stack Pointer to the end of the 128KiB RAM 6 | MOV %IA, vector_table ; IA points to the vector table 7 | MOV %FLAGS, 0x100 ; Enable interrupts 8 | 9 | ; Code to find the first TDA plugged device 10 | MOV %r10, 0x10FF00 11 | begin_search_tda: 12 | ADD %r10, %r10, 0x100 13 | IFEQ %r10, 0x112100 ; Not found any TDA device 14 | JMP end_search_tda 15 | 16 | LOADB %r0, %r10 17 | IFNEQ %r0, 0xFF ; Device Present ? 18 | JMP begin_search_tda 19 | 20 | ADD %r1, %r10, 1 21 | LOADB %r0, %r1 22 | IFNEQ %r0, 0x0E ; Is a Graphics device ? 23 | JMP begin_search_tda 24 | 25 | ADD %r1, %r10, 2 26 | LOADB %r0, %r1 27 | IFNEQ %r0, 0x01 ; Is TDA compatible ? 28 | JMP begin_search_tda 29 | 30 | end_search_tda: 31 | IFEQ %r10, 0x112100 32 | MOV %r10, 0xFFFFFFFF ; We put in the var TDA base address 33 | 34 | STORE TDA_base_dev, %r10 ; We put in the var that we don't found anything 35 | 36 | IFEQ %r10, 0xFFFFFFFF 37 | JMP end ; We skips print code 38 | 39 | ; Configure TDA to use a text buffer in 0x002000 40 | ADD %r0, %r10, 0x0A 41 | 42 | MOV %r1, 0x002000 43 | STORE %r0, %r1 ; Set B:A to point to 0x001000 44 | 45 | ADD %r0, %r10, 0x08 46 | MOV %r1, 0 47 | STOREW %r0, %r1 ; Send command to point Text buffer to B:A address 48 | 49 | ; Clears the screen 50 | MOV %r0, 0x002000 51 | MOV %r1, 0x40 ; Dark brown paper, Black Ink 52 | CALL clr_screen 53 | 54 | 55 | 56 | mov %r0, int_m5fdd 57 | mov %r1, 8 ; 2 * 4 58 | store %r1, vector_table, %r0 59 | ;------------------------------------------------------------------------------ 60 | 61 | MOV %R5, 0x110000 62 | ADD %R5, %R5, 0x000600 63 | 64 | ; is present? 65 | MOV %R10, 0 66 | LOADB %R0, %R5, 0x0 67 | IFNEQ %R0, 0xFF 68 | JMP crash 69 | 70 | ; read type 71 | MOV %R10, 1 72 | LOADB %R0, %R5, 0x01 73 | IFNEQ %R0, 0x08 74 | JMP crash 75 | 76 | ; read subtype 77 | MOV %R10, 2 78 | LOADB %R0, %R5, 0x02 79 | IFNEQ %R0, 0x01 80 | JMP crash 81 | 82 | ; read id 83 | MOV %R10, 3 84 | LOADB %R0, %R5, 0x03 85 | IFNEQ %R0, 0x01 86 | JMP crash 87 | 88 | ; read builder ID 89 | MOV %R10, 4 90 | LOAD %R0, %R5, 0x04 91 | IFNEQ %R0, 0x1EB37E91 92 | JMP crash 93 | 94 | ; read status code 95 | MOV %R10, 5 96 | LOADW %R0, %R5, 0x10 97 | IFNEQ %R0, 0x01 98 | JMP crash 99 | 100 | ; read error code 101 | MOV %R10, 6 102 | LOADW %R0, %R5, 0x12 103 | IFNEQ %R0, 0x00 104 | JMP crash 105 | 106 | ;--- initial state verified --- 107 | 108 | ; query media 109 | MOV %R10, 7 110 | MOV %R1, 0x0003 111 | STOREW %R5, 0x8, %R1 112 | LOADW %R0, %R5, 0x0A ;reg A 113 | IFNEQ %R0, 0x280 114 | JMP crash 115 | LOADW %R0, %R5, 0x0C ;reg B 116 | IFNEQ %R0, 0x0228 117 | JMP crash 118 | LOADW %R0, %R5, 0x0E ;reg C 119 | IFNEQ %R0, 0x0809 120 | JMP crash 121 | 122 | ; set up interrupts 123 | MOV %R1, 0x02 124 | STOREW %R5, 0x0A, %R1 ; reg A 125 | MOV %R1, 0x00 126 | STOREW %R5, 0x08, %R1 ; cmd 127 | 128 | ; generate data 129 | mov %r0, 0 130 | mov %r1, data 131 | genLoop: 132 | storeb %r1, %r0, %r0 133 | add %r0, %r0, 1 134 | ifle %r0, 0x1ff 135 | jmp genLoop 136 | 137 | ; store data in first sector 138 | MOV %R10, 8 139 | MOV %R1, data 140 | STOREW %R5, 0x0A, %R1 ;A = 0x1000 141 | MOV %R1, 0x00 142 | STOREW %R5, 0x0C, %R1 ;B = 0x0 143 | MOV %R1, 0x0001 144 | STOREW %R5, 0x0E, %R1 ;C = 1 -> CHS = 0:0:1 145 | MOV %R1, 0x0002 146 | STOREW %R5, 0x08, %R1 ;CMD = 0x2 147 | 148 | _sleep1: 149 | SLEEP 150 | LOADW %R6, %R5, 0x10 151 | IFNEQ %R6, 0x0001 152 | JMP _sleep1 153 | 154 | ; read data back into another place in RAM 155 | MOV %R10, 9 156 | MOV %R1, 0x6000 157 | STOREW %R5, 0x0A, %R1 ; A = 0x6000 158 | MOV %R1, 0x00 159 | STOREW %R5, 0x0C, %R1 ; B = 0x0 160 | MOV %R1, 0x0001 161 | STOREW %R5, 0x0E, %R1 ; C = 1 -> CHS = 0:0:1 162 | MOV %R1, 0x0001 163 | STOREW %R5, 0x08, %R1 ; CMD = 0x1 164 | 165 | _sleep2: 166 | SLEEP 167 | LOADW %R6, %R5, 0x10 168 | IFNEQ %R6, 0x0001 169 | JMP _sleep2 170 | 171 | ; store data in second sector 172 | MOV %R10, 10 173 | MOV %R1, data 174 | STOREW %R5, 0x0A, %R1 ;A = 0x1000 175 | MOV %R1, 0x00 176 | STOREW %R5, 0x0C, %R1 ;B = 0x0 177 | MOV %R1, 0x0002 178 | STOREW %R5, 0x0E, %R1 ;C = 1 -> CHS = 0:0:2 179 | MOV %R1, 0x0002 180 | STOREW %R5, 0x08, %R1 181 | 182 | _sleep3: 183 | SLEEP 184 | LOADW %R6, %R5, 0x10 185 | IFNEQ %R6, 0x0001 186 | JMP _sleep3 187 | 188 | push %r10 189 | 190 | ;****************************************************************************** 191 | print_state: 192 | 193 | ; Prints the apropiated string 194 | load %r1, failed 195 | mov %r0, string01 ; %r0 ptr to ok string 196 | ifeq %r1, 1 197 | mov %r0, string02 ; %r0 ptr to fail string 198 | MOV %r1, 0x002000 ; %r1 ptr to text buffer 199 | MOV %r0, string01 ; %r0 ptr to string 200 | MOV %r2, 0x45 ; Dark blue paper, Light Green Ink 201 | CALL print 202 | 203 | end: 204 | SLEEP 205 | JMP end 206 | 207 | ; Something failed 208 | crash: 209 | mov %r1, 1 210 | storew failed, %r1 211 | jmp print_state 212 | 213 | ; Interrupt handler 214 | int_m5fdd: 215 | MOV %R9, %R0 216 | RFI 217 | 218 | ;------------------------------------------------------------------------------ 219 | LIB_memcmp: ;int memcmp ( const void * ptr1, const void * ptr2, size_t num ); 220 | ; %R0 -> ptr1 221 | ; %R1 -> ptr2 222 | ; %R2 -> num 223 | PUSH %R3 224 | PUSH %R4 225 | PUSH %R5 226 | 227 | MOV %R4, 0 228 | MOV %R3, -1 229 | _memcmp_loop: 230 | ADD %R3, %R3, 1 231 | IFLE %R2, %R3 232 | RJMP _memcmp_loop_end 233 | LOADB %R4, %R0, %R3 234 | LOADB %R5, %R0, %R3 235 | SUB %R4, %R4, %R5 236 | IFEQ %R4, 0 237 | RJMP _memcmp_loop 238 | _memcmp_loop_end: 239 | MOV %R0, %R4 240 | 241 | PUSH %R5 242 | PUSH %R4 243 | PUSH %R3 244 | RET 245 | 246 | .include "BROM.ainc" 247 | 248 | ;****************************************************************************** 249 | ; Const Data 250 | string01: .DB "Disk filled with data on sector 0 and 1. Check with an hex editor.", 0 251 | string02: .DB "Fail.", 0 252 | 253 | ;****************************************************************************** 254 | ; RAM data 255 | .ORG 0x0 256 | :failed .dw 0 257 | :TDA_base_dev .dw 0 258 | :data .db 0 259 | 260 | 261 | -------------------------------------------------------------------------------- /include/devices/media.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Virtual Computer Generic Media image class 3 | * \file media.hpp 4 | * \copyright LGPL v3 5 | * 6 | */ 7 | #ifndef __DISK_HPP_ 8 | #define __DISK_HPP_ 1 9 | 10 | #include "../vcomputer.hpp" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace trillek { 18 | namespace computer { 19 | 20 | static const int HEADER_SIZE = 11; /// Size on bytes of the file header 21 | static const char HEADER_MAGIC[3] = { 22 | /// Magic "number" to identify the file 23 | 'V', 'C', 'D' 24 | }; 25 | 26 | /** 27 | * Media image file class 28 | */ 29 | enum class DiskType : Byte 30 | { 31 | FLOPPY = 'F' 32 | }; 33 | 34 | /** 35 | * Media image file descriptor 36 | */ 37 | struct DiskDescriptor 38 | { 39 | DiskType TypeDisk; /// Type of disk 40 | bool writeProtect; /// Disk is write protected 41 | uint8_t NumSides; /// Total sides of floppy 42 | uint8_t TracksPerSide; /// number of tracks per side 43 | uint8_t SectorsPerTrack; /// number of sectors per track 44 | uint16_t BytesPerSector; /// number of bytes per sector 45 | }; 46 | 47 | enum class ERRORS : Byte 48 | { 49 | NONE = 0, // No error 50 | NO_MEDIA = 2, // Disk file is not open 51 | PROTECTED = 3, // Disk is write protected 52 | BAD_SECTOR = 5 // Sector is bad 53 | }; 54 | 55 | 56 | /*! 57 | * Converts CHS addressing to LBA (raw sector count from 0) that 58 | * expectes Media class 59 | * \param track Track/Cylinder 60 | * \param head Header 61 | * \param sector Sector, counting from 1 62 | * \param descriptor Media descriptor 63 | * \return raw sector number or -1 if is a not valid CHS value 64 | */ 65 | DECLDIR int32_t CHStoLBA(uint8_t track, uint8_t head, uint8_t sector, const DiskDescriptor& descriptor); 66 | 67 | /** 68 | * Generic class that represent a media image, and allows to save/read the disk 69 | * image data from a file 70 | */ 71 | class Media { 72 | public: 73 | 74 | /** 75 | * Opens a media file 76 | * @param filename Filename were the floppy data is stored 77 | */ 78 | DECLDIR Media(const std::string& filename); 79 | 80 | /** 81 | * Creates a new media file 82 | * @param filename Filename were the floppy data is stored 83 | * @param info Pointer to media descriptor. Media takes the ownership of it 84 | */ 85 | DECLDIR Media(const std::string& filename, DiskDescriptor* info); 86 | 87 | /** 88 | * Creates a new media file 89 | * @param filename Filename were the floppy data is stored 90 | * @param info Media Descriptor. Does a copy from it 91 | */ 92 | DECLDIR Media(const std::string& filename, const DiskDescriptor& info); 93 | 94 | /** 95 | * closes a floppy disk file and destroys this container 96 | */ 97 | DECLDIR virtual ~Media(); 98 | 99 | /** 100 | * Return if the disk is valid 101 | */ 102 | DECLDIR bool isValid() const { 103 | return datafile.is_open() && datafile.good(); 104 | } 105 | 106 | /** 107 | * Return info about the disk 108 | */ 109 | DECLDIR const DiskDescriptor* getDescriptor() { 110 | return Info.get(); 111 | } 112 | 113 | /** 114 | * Total number of tracks of this floppy 115 | */ 116 | DECLDIR uint16_t getTotalTracks() const { 117 | return Info->NumSides * Info->TracksPerSide; 118 | } 119 | 120 | /** 121 | * Total number of sectors of this floppy 122 | */ 123 | DECLDIR uint16_t getTotalSectors() const { 124 | return Info->NumSides * Info->TracksPerSide * Info->SectorsPerTrack; 125 | } 126 | 127 | /** 128 | * The exponent of the number of bytes per sector 129 | * 512 = 2^9, return 9 130 | * to reverse this: 1 << 9 = 2^9 = 512 131 | */ 132 | DECLDIR uint8_t getBytesExponent() const; 133 | 134 | /** 135 | * Return if is write protected 136 | */ 137 | DECLDIR bool isProtected() const { 138 | return Info->writeProtect; 139 | } 140 | 141 | /** 142 | * sets write protection of disk 143 | */ 144 | DECLDIR void setWriteProtected(bool state) { 145 | Info->writeProtect = state; 146 | } 147 | 148 | /** 149 | * See if that sector is bad 150 | * Return True if is a bad sector 151 | */ 152 | DECLDIR bool isSectorBad(uint16_t sector) const; 153 | 154 | /** 155 | * Change the bad sector flag of a particular sector 156 | * @param sector Desired sector 157 | * @param state True to damage these particular sector 158 | */ 159 | DECLDIR ERRORS setSectorBad(uint16_t sector, bool state); 160 | 161 | /** 162 | * Try to write data at the desired sector 163 | * @param sector Desired sector to be written 164 | * @param data Sector buffer to be written to the disk 165 | * @param dryRun Only check for errors, the disk is untouched 166 | * @return NONE, NO_MEDIA, BAD_SECTOR, PROTECTED 167 | */ 168 | DECLDIR ERRORS writeSector(uint16_t sector, std::vector* data, bool dryRun = false); 169 | 170 | /** 171 | * Try to write data at the desired sector 172 | * @param sector Desired sector to be written 173 | * @param data Sector buffer to be written to the disk 174 | * @param data_size Size of the array with the sector data to write 175 | * @param dryRun Only check for errors, the disk is untouched 176 | * @return NONE, NO_MEDIA, BAD_SECTOR, PROTECTED 177 | */ 178 | DECLDIR ERRORS writeSector(uint16_t sector, const uint8_t* data, size_t data_size, bool dryRun = false); 179 | 180 | /** 181 | * Try to read data at the desired sector 182 | * @param sector Desired sector to be written 183 | * @param data Sector buffer to be written to the disk 184 | * @return NONE, NO_MEDIA, BAD_SECTOR 185 | */ 186 | DECLDIR ERRORS readSector(uint16_t sector, std::vector* data); 187 | 188 | /** 189 | * Returns the filename 190 | */ 191 | DECLDIR const std::string getFilename() const { 192 | return filename; 193 | } 194 | 195 | private: 196 | void createMedia(const std::string& filename, DiskDescriptor* info); 197 | void writeHeader(); 198 | int readHeader(); 199 | void writeBitmap(); 200 | void readBitmap(); 201 | void makeOffsets(); 202 | void upgradeMedia(char to_version); 203 | 204 | char HEADER_VERSION; 205 | size_t offset_sectors; 206 | size_t offset_bitmap; 207 | 208 | std::string filename; /// file name of disk file 209 | std::fstream datafile; /// disk file on host 210 | 211 | std::vector badSectors; /// Bitmap of bad sectors 212 | std::unique_ptr Info; /// disk metrics 213 | }; 214 | 215 | } // End of namespace computer 216 | } // End of namespace trillek 217 | 218 | #endif // __DISK_HPP_ 219 | -------------------------------------------------------------------------------- /tools/src/al_engine.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * \brief OpenAL Stuff of the test/toy emulator 3 | * \file alengine.cpp 4 | * \copyright LGPL v3 5 | * 6 | * OpenAL Stuff of the test/toy emulator. 7 | */ 8 | 9 | #include "al_engine.hpp" 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #ifdef OPENAL_ENABLE 17 | namespace AlEngine { 18 | 19 | volatile trillek::Word beep_freq; /// Beep freq 20 | double offset; /// Signal phase 21 | double sign; /// Square wave sign 22 | 23 | // Blip Buffer stuff 24 | Blip_Buffer blipbuf; //! Blip Buffer 25 | Blip_Synth synth; //! Synthetizer of Blip Buffer 26 | // to generate a signal, use synth.update (time in blip_buffer clock rate cycles, amplitude) with amplite <= 20/2 27 | ALuint StreamCB (void* userdata, ALubyte* data, ALuint bytes); 28 | 29 | 30 | // Position of the source sound. 31 | const ALfloat AlEngine::SourcePos[] = { 0.0, 0.0, 0.0 }; 32 | 33 | // Velocity of the source sound. 34 | const ALfloat AlEngine::SourceVel[] = { 0.0, 0.0, 0.0 }; 35 | 36 | // Position of the listener. 37 | const ALfloat AlEngine::ListenerPos[] = { 0.0, 0.0, 0.0 }; 38 | 39 | // Velocity of the listener. 40 | const ALfloat AlEngine::ListenerVel[] = { 0.0, 0.0, 0.0 }; 41 | 42 | // Orientation of the listener. (first 3 elements are "at", second 3 are "up") 43 | const ALfloat AlEngine::ListenerOri[] = { 0.0, 0.0, -1.0, 0.0, 1.0, 0.0 }; 44 | 45 | AlEngine::AlEngine () : 46 | gain(1.0f), initiated(false), source_created(false), stream(nullptr) { 47 | 48 | } 49 | 50 | AlEngine::~AlEngine () { 51 | // RAII ! 52 | Shutdown(); 53 | } 54 | 55 | bool AlEngine::Init () { 56 | if (!alureInitDevice(NULL, NULL)) { 57 | std::fprintf(stderr, "Failed to open OpenAL device: %s\n", alureGetErrorString()); 58 | return false; 59 | } 60 | 61 | alListenerf(AL_GAIN, gain); 62 | 63 | // Set the source of the audio 64 | alGenSources(1, &beep_source); 65 | if (alGetError() != AL_NO_ERROR) { 66 | Shutdown(); 67 | return false; 68 | } 69 | 70 | source_created = true; 71 | alSourcef (beep_source, AL_PITCH, 1.0f ); 72 | alSourcef (beep_source, AL_GAIN, 1.0f ); 73 | alSourcefv(beep_source, AL_POSITION, SourcePos); 74 | alSourcefv(beep_source, AL_VELOCITY, SourceVel); 75 | alSourcei (beep_source, AL_LOOPING, false ); 76 | 77 | // Set listener parameters 78 | alListenerfv(AL_POSITION, ListenerPos); 79 | alListenerfv(AL_VELOCITY, ListenerVel); 80 | alListenerfv(AL_ORIENTATION, ListenerOri); 81 | 82 | // Init Blip Buffer with a buffer of 500ms 83 | if ( blipbuf.set_sample_rate( SR, 1000 / 4 ) ) { 84 | std::fprintf(stderr, "Failed to create Blip Buffer! Our of Memory\n"); 85 | Shutdown(); 86 | return false; 87 | } 88 | blipbuf.clock_rate( blipbuf.sample_rate() ); 89 | 90 | blipbuf.bass_freq(300); // Equalization like a TV speaker 91 | synth.treble_eq( -8.0f ); // Synthetize Equalization 92 | 93 | synth.volume (0.30); 94 | synth.output (&blipbuf); 95 | 96 | beep_freq = 0; 97 | offset = 0; 98 | sign = 1; 99 | 100 | stream = alureCreateStreamFromCallback (StreamCB, nullptr, AL_FORMAT_MONO16, SR, SR/2, 0, nullptr); 101 | if (!stream) { 102 | Shutdown(); 103 | return false; 104 | } 105 | 106 | initiated = true; 107 | return true; 108 | } 109 | 110 | void AlEngine::Shutdown () { 111 | if (source_created) { 112 | alDeleteSources(1, &beep_source); 113 | source_created = false; 114 | } 115 | if (stream) { 116 | alureDestroyStream(stream, 0, nullptr); 117 | stream = nullptr; 118 | } 119 | 120 | alureShutdownDevice(); 121 | initiated = false; 122 | std::fprintf(stderr, "OpenAL closed\n"); 123 | } 124 | 125 | void AlEngine::Tone(trillek::Word freq) { 126 | if (initiated) { 127 | beep_freq = freq; 128 | } 129 | } 130 | 131 | void AlEngine::Update () { 132 | if (initiated) { 133 | alureUpdate(); 134 | } 135 | } 136 | 137 | void AlEngine::Play () { 138 | if (initiated) { 139 | if (!alurePlaySourceStream(beep_source, stream, AL_BUFFERS, 0, nullptr, nullptr)) { 140 | std::fprintf(stderr, "Failed to play stream: %s\n", alureGetErrorString()); 141 | } 142 | } 143 | } 144 | 145 | void AlEngine::Pause () { 146 | if (initiated) { 147 | alurePauseSource(beep_source); 148 | } 149 | } 150 | 151 | void AlEngine::Stop () { 152 | if (initiated) { 153 | alureStopSource(beep_source, AL_FALSE); 154 | } 155 | } 156 | 157 | void AlEngine::Test() { 158 | if (initiated) { 159 | beep_freq = 937; 160 | std::fprintf(stderr, "OpenAL Test begin\n"); 161 | if (!alurePlaySourceStream(beep_source, stream, 3, 0, nullptr, nullptr)) { 162 | std::fprintf(stderr, "Failed to play stream: %s\n", alureGetErrorString()); 163 | } 164 | alureUpdate(); 165 | alureSleep(0.1f); 166 | alureUpdate(); 167 | alureSleep(0.1f); 168 | alureUpdate(); 169 | alureSleep(0.1f); 170 | alureUpdate(); 171 | alureSleep(0.1f); 172 | alureUpdate(); 173 | alureSleep(0.1f); 174 | 175 | alureStopSource(beep_source, AL_FALSE); 176 | std::fprintf(stderr, "OpenAL Test end\n"); 177 | } 178 | } 179 | 180 | void AlEngine::MasterGain (float gain) { 181 | assert (gain >= 0); 182 | if (initiated) { 183 | alListenerf(AL_GAIN, gain); 184 | } 185 | this->gain = gain; 186 | } 187 | 188 | float AlEngine::MasterGain () const { 189 | return gain; 190 | } 191 | 192 | // Callback called when Alure needs more data to ffed a buffer 193 | ALuint StreamCB (void* userdata, ALubyte *data, ALuint bytes) { 194 | size_t lenght = bytes / 2; // Lenght in "samples" 195 | 196 | if (beep_freq > 0) { 197 | double period = SR / (2* beep_freq); // How many samples need to do a half cycle. 198 | 199 | unsigned const amplitude = 9; 200 | while (offset < lenght) { 201 | sign = - sign; 202 | synth.update (offset, amplitude * sign); 203 | offset += period; 204 | } 205 | blipbuf.end_frame(lenght); 206 | offset -= lenght; // adjust time to new frame 207 | } else { 208 | blipbuf.end_frame(lenght); 209 | offset = 0; 210 | } 211 | 212 | ALuint out = 2 * blipbuf.read_samples ((blip_sample_t*) data, lenght ); // return bytes! 213 | //std::fprintf(stderr, "Generating! %u\n", out); 214 | return out; 215 | } 216 | 217 | 218 | } // End of Namespace AlEngine 219 | 220 | #endif 221 | 222 | -------------------------------------------------------------------------------- /include/devices/m5fdd.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Mackapar 5.25" Floppy Drive 3 | * \file m5fdd.hpp 4 | * \copyright LGPL v3 5 | * 6 | * 5.25" Floppy Drive 7 | * Implement specs v0.2.3 8 | */ 9 | #ifndef __M5FDD_HPP_ 10 | #define __M5FDD_HPP_ 1 11 | 12 | #include "../vcomputer.hpp" 13 | 14 | #include "media.hpp" 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | namespace trillek { 21 | namespace computer { 22 | namespace m5fdd { 23 | 24 | /** 25 | * M35 Floppy Drive commands 26 | */ 27 | enum class COMMANDS : uint16_t { 28 | SET_INTERRUPT = 0x0, 29 | READ_SECTOR = 0x1, 30 | WRITE_SECTOR = 0x2, 31 | QUERY_MEDIA = 0x3, 32 | }; 33 | 34 | /** 35 | * M35 Floppy Drive status codes 36 | */ 37 | enum class STATE_CODES : uint16_t { 38 | NO_MEDIA = 0, /// There's no floppy in the drive 39 | READY = 1, /// The drive is ready to accept commands 40 | READY_WP = 2, /// Same as ready, but the floppy is Write Protected 41 | BUSY = 3, /// The drive is busy either reading or writing a sector 42 | }; 43 | 44 | /** 45 | * M35 Floppy Device error codes 46 | * This is a superset of Disk ERROR enum 47 | */ 48 | enum class ERROR_CODES : uint16_t { 49 | NONE = 0, /// No error since the last poll 50 | BUSY = 1, /// Drive is busy performing a action 51 | NO_MEDIA = 2, /// Attempted to read or write without a floppy 52 | PROTECTED = 3, /// Attempted to write to a protected floppy 53 | EJECT = 4, /// The floppy was ejected while was reading/writing 54 | BAD_SECTOR = 5, /// The requested sector is broken, the data on it is lost 55 | BAD_CHS = 6, /// The CHS value is not valid. Check QUERY_MEDIA 56 | 57 | BROKEN = 0xFFFF /// There's been some major software/hardware problem. 58 | /// Try to do a hard reset the device. 59 | }; 60 | 61 | /** 62 | * 5.25" floppy drive 63 | */ 64 | class M5FDD : public Device { 65 | public: 66 | 67 | DECLDIR M5FDD(); 68 | DECLDIR virtual ~M5FDD(); 69 | 70 | /*! 71 | * Resets device internal state 72 | * Called by VComputer 73 | */ 74 | DECLDIR virtual void Reset(); 75 | 76 | /** 77 | * Sends (writes to CMD register) a command to the device 78 | * @param cmd Command value to send 79 | */ 80 | virtual void SendCMD(Word cmd); 81 | 82 | virtual void A(Word val) { 83 | a = val; 84 | } 85 | 86 | virtual void B(Word val) { 87 | b = val; 88 | } 89 | 90 | virtual void C(Word val) { 91 | c = val; 92 | } 93 | 94 | virtual Word A() { 95 | return a; 96 | } 97 | 98 | virtual Word B() { 99 | return b; 100 | } 101 | 102 | virtual Word C() { 103 | return c; 104 | } 105 | 106 | virtual Word D() { 107 | return static_cast(state); 108 | } 109 | 110 | virtual Word E() { 111 | return static_cast(error); 112 | } 113 | 114 | /** 115 | * Device Type 116 | */ 117 | virtual Byte DevType() const { 118 | return 0x08; // Mass Storage Device 119 | } 120 | 121 | /** 122 | * Device SubType 123 | */ 124 | virtual Byte DevSubType() const { 125 | return 0x01; // Floppy Drive 126 | } 127 | 128 | /** 129 | * Device ID 130 | */ 131 | virtual Byte DevID() const { 132 | return 0x01; // Mackapar 5.25" Floppy Drive 133 | } 134 | 135 | /** 136 | * Device Vendor ID 137 | */ 138 | virtual DWord DevVendorID() const { 139 | return 0x1EB37E91; // Mackapar Media 140 | } 141 | 142 | /*! 143 | * Return if the device does something each Device Clock cycle. 144 | * Few devices really need to do this, so IDevice implementation 145 | * returns false. 146 | */ 147 | virtual bool IsSyncDev() const { 148 | return true; 149 | } 150 | 151 | /*! 152 | * Executes N Device clock cycles. 153 | * 154 | * Here resides the code that is executed every Device Clock tick. 155 | * IDevice implementation does nothing. 156 | * \param n Number of clock cycles to be executed 157 | * \param delta Number milliseconds since the last call 158 | */ 159 | virtual void Tick (unsigned n = 1, const double delta = 0); 160 | 161 | /*! 162 | * Checks if the device is trying to generate an interrupt 163 | * 164 | * IDevice implementation does nothing. 165 | * \param[out] msg The interrupt message will be written here 166 | * \return True if is generating a new interrupt 167 | */ 168 | virtual bool DoesInterrupt (Word& msg); 169 | 170 | /*! 171 | * Informs to the device that his generated interrupt was accepted by the 172 | **CPU 173 | * 174 | * IDevice implementation does nothing. 175 | */ 176 | virtual void IACK (); 177 | 178 | /*! 179 | * Writes a copy of Device state in a chunk of memory pointer by ptr. 180 | * \param[out] ptr Pointer were to write 181 | * \param[in,out] size Size of the chunk of memory were can write. If is 182 | * successful, it will be set to the size of the write data. 183 | */ 184 | DECLDIR virtual void GetState(void* ptr, std::size_t& size) const { 185 | } 186 | 187 | /*! 188 | * Sets the Device state. 189 | * \param ptr[in] Pointer were read the state information 190 | * \param size Size of the chunk of memory were will read. 191 | * \return True if can read the State data from the pointer. 192 | */ 193 | DECLDIR virtual bool SetState(const void* ptr, std::size_t size) { 194 | return true; 195 | } 196 | 197 | //---------------------------------------------------- 198 | 199 | /** 200 | * @brief Inserts a floppy in the unit 201 | * If there is a floppy disk previously inserted, this is ejected 202 | * @param floppy Floppy disk 203 | */ 204 | DECLDIR void insertFloppy(std::shared_ptr floppy); 205 | 206 | /** 207 | * @brief Ejects the floppy actually inserted if is there one 208 | */ 209 | DECLDIR void ejectFloppy(); 210 | 211 | /** 212 | * Create a new device. 213 | * \return The newly created Device 214 | */ 215 | static Device* CreateNew() { return new M5FDD(); } 216 | 217 | private: 218 | 219 | /** 220 | * Moves the head to the desired position 221 | */ 222 | void setSector (uint8_t track, uint8_t head, uint8_t sector); 223 | 224 | std::shared_ptr floppy; /// Floppy inserted 225 | std::vector sectorBuffer; // buffer of sector being accessed 226 | STATE_CODES state; /// Floppy drive actual status 227 | ERROR_CODES error; /// Floppy drive actual error state 228 | 229 | bool writing; /// is the drive reading or writing? 230 | unsigned curHead; /// current head 231 | unsigned curTrack; /// current track the head is at 232 | unsigned curSector; /// current sector the head is at 233 | unsigned curPosition; /// current DMA position inside of the sector 234 | unsigned busyCycles; /// Device Cycles that the device will be busy 235 | DWord dmaLocation; /// RAM Location for the DMA transfer 236 | 237 | uint16_t msg; /// Msg to send if need to trigger a interrupt 238 | bool pendingInterrupt; /// Must launch a interrupt from device to CPU ? 239 | DWord a, b, c, d; /// Data registers 240 | }; 241 | 242 | } // End of namespace m5ffd 243 | } // End of namespace computer 244 | } // End of namespace trillek 245 | 246 | #endif // __M5FDD_HPP_ 247 | -------------------------------------------------------------------------------- /src/devices/tda.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \brief Virtual Computer Text Display Adapter 3 | * \file tda.cpp 4 | * \copyright LGPL v3 5 | * 6 | * Nya Elektriska Text Display Adapter 7 | * @see https://github.com/trillek-team/trillek-computer/blob/master/TDA.md 8 | */ 9 | 10 | #include "devices/tda.hpp" 11 | #include "vs_fix.hpp" 12 | 13 | #include 14 | #include 15 | 16 | namespace trillek { 17 | namespace computer { 18 | namespace tda { 19 | 20 | void TDAtoRGBATexture (const TDAScreen& screen, DWord* texture) { 21 | static unsigned frames = 0; 22 | TDAtoRGBATexture(screen, texture, frames); 23 | } 24 | 25 | void TDAtoBGRATexture (const TDAScreen& screen, DWord* texture) { 26 | static unsigned frames = 0; 27 | TDAtoBGRATexture(screen, texture, frames); 28 | } 29 | 30 | void TDAtoRGBATexture (const TDAScreen& screen, DWord* texture, unsigned& frames) { 31 | assert(texture != nullptr); 32 | 33 | const Byte* font = ROM_FONT; 34 | if (screen.user_font) { 35 | font = (Byte*) screen.font_buffer; 36 | } 37 | 38 | // TODO Rewrite this to be more efficient and cache friendly, as now 39 | // writes "jumping" in the output texture 40 | 41 | // Reads one by one each character of the text buffer 42 | for (unsigned row = 0; row < HEIGHT_CHARS; row++) { 43 | for (unsigned col = 0; col < WIDTH_CHARS; col++) { 44 | 45 | std::size_t addr = col + (WIDTH_CHARS * row); 46 | Byte c = screen.txt_buffer[addr]; // character 47 | 48 | // Get Ink (fg) and Paper (bg) colors 49 | DWord fg = (screen.txt_buffer[addr] >> 8) & 0x0F; // Bits 8-11 50 | DWord bg = (screen.txt_buffer[addr] >> 12)& 0x0F; // bits 12-15 51 | 52 | // Paint the texture 53 | Byte pixels; 54 | for (unsigned y = 0; y < 8; y++) { 55 | pixels = font[c*8 + y]; 56 | for (unsigned x = 0; x < 8; x++) { 57 | addr = x + col*8 + ( 40*8 * (y + row*8) ); // Addres of the 58 | // pixel in the 59 | // buffer 60 | if ( ( pixels & ( 1 << (7-x) ) ) != 0 ) { 61 | // Active, uses the Ink (fg) 62 | texture[addr] = PALETTE[fg]; 63 | } 64 | else { 65 | // Unactive, uses the Paper (bg) 66 | texture[addr] = PALETTE[bg]; 67 | } 68 | } 69 | } 70 | } 71 | } // End for 72 | 73 | if ( screen.cursor) { 74 | if (frames++ < 8) { 75 | // Draw the cursor only when is necesary 76 | if (screen.cur_start <= screen.cur_end) { 77 | unsigned char col = screen.cur_col; 78 | unsigned char row = screen.cur_row; 79 | DWord color = PALETTE[screen.cur_color]; // Color 80 | if (row < 30 && col < 40) { 81 | // Paints the cursor 82 | std::size_t addr = col + (WIDTH_CHARS * row); 83 | for (unsigned y = screen.cur_start ; y <= screen.cur_end; y++) { 84 | for (unsigned x = 0; x < 8; x++) { 85 | addr = x + col*8 + ( 40*8 * (y + row*8) ); // Addres of the 86 | // pixel in the 87 | // buffer 88 | texture[addr] = color; 89 | } 90 | } 91 | } 92 | } 93 | } else if (frames++ < 16) { 94 | // Do nothing 95 | } else { 96 | frames = 0; // Reset it 97 | } 98 | } 99 | 100 | } // TDAtoRGBATexture 101 | 102 | void TDAtoBGRATexture (const TDAScreen& screen, DWord* texture, unsigned& frames) { 103 | assert(texture != nullptr); 104 | TDAtoRGBATexture (screen, texture, frames); 105 | 106 | // We interchanged B and R components 107 | for (unsigned i=0; i < 320*240 ; i++) { 108 | DWord g_a = texture[i] & 0xFF00FF00; 109 | DWord red = texture[i] & 0x000000FF; 110 | DWord blue = texture[i] & 0x00FF0000; 111 | texture[i] = g_a | (red << 16) | (blue >> 16); 112 | } 113 | } // TDAtoBGRATexture 114 | TDADev::TDADev () : buffer_ptr(0), font_ptr(0), vsync_msg(0), do_vsync(false), 115 | cursor(false), blink(false) { 116 | } 117 | 118 | TDADev::~TDADev() { 119 | } 120 | 121 | void TDADev::Reset () { 122 | this->buffer_ptr = 0; 123 | this->font_ptr = 0; 124 | this->vsync_msg = 0; 125 | this->a = 0; 126 | this->b = 0; 127 | this->d = 0; 128 | this->e = 0; 129 | this->do_vsync = false; 130 | this->cursor = false; 131 | this->blink = false; 132 | } 133 | 134 | void TDADev::SendCMD (Word cmd) { 135 | DWord tmp; 136 | 137 | switch (cmd) { 138 | case 0x0000: // Map Buffer 139 | tmp = ( (b << 16) | a ); 140 | if ( tmp + TXT_BUFFER_SIZE < vcomp->RamSize() ) { 141 | buffer_ptr = tmp; 142 | } 143 | break; 144 | 145 | case 0x0001: // Map Font 146 | tmp = ( (b << 16) | a ); 147 | if ( tmp + FONT_BUFFER_SIZE <= vcomp->RamSize() ) { 148 | font_ptr = tmp; 149 | } 150 | else if ( tmp - 0x100000 + FONT_BUFFER_SIZE <= vcomp->RomSize()) { 151 | font_ptr = tmp; 152 | } 153 | break; 154 | 155 | case 0x0002: // Set Int 156 | vsync_msg = a; 157 | break; 158 | 159 | default: 160 | break; 161 | } // switch 162 | } // SendCMD 163 | 164 | bool TDADev::DoesInterrupt(Word& msg) { 165 | if (do_vsync && vsync_msg != 0x0000) { 166 | msg = vsync_msg; 167 | return true; 168 | } 169 | return false; 170 | } 171 | 172 | void TDADev::IACK () { 173 | do_vsync = false; // Acepted, so we can forgot now of sending it again 174 | } 175 | 176 | bool TDADev::IsSyncDev() const { 177 | return false; 178 | } 179 | 180 | void TDADev::GetState (void* ptr, std::size_t& size) const { 181 | if ( ptr != nullptr && size >= sizeof(TDAState) ) { 182 | auto state = (TDAState*) ptr; 183 | state->buffer_ptr = this->buffer_ptr; 184 | state->font_ptr = this->font_ptr; 185 | state->vsync_msg = this->vsync_msg; 186 | state->a = this->a; 187 | state->b = this->b; 188 | state->d = this->d; 189 | state->e = this->e; 190 | 191 | state->do_vsync = this->do_vsync; 192 | } 193 | } // GetState 194 | 195 | bool TDADev::SetState (const void* ptr, std::size_t size) { 196 | if ( ptr != nullptr && size >= sizeof(TDAState) ) { 197 | // Sanity check 198 | auto state = (const TDAState*) ptr; 199 | this->buffer_ptr = state->buffer_ptr; 200 | this->font_ptr = state->font_ptr; 201 | this->vsync_msg = state->vsync_msg; 202 | this->a = state->a; 203 | this->b = state->b; 204 | this->d = state->d; 205 | this->e = state->e; 206 | 207 | this->do_vsync = state->do_vsync; 208 | 209 | return true; 210 | } 211 | 212 | return false; 213 | } // SetState 214 | 215 | } // End of namespace tda 216 | } // End of namespace computer 217 | } // End of namespace trillek 218 | -------------------------------------------------------------------------------- /tools/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Options 2 | 3 | CMAKE_DEPENDENT_OPTION(BUILD_TOOLS_SCREEN "Build Trillek VCOMPUTER tools with virtual screen" ON 4 | "BUILD_TOOLS_VCOMPUTER" OFF) 5 | CMAKE_DEPENDENT_OPTION(BUILD_TOOLS_AUDIO "Build Trillek VCOMPUTER tools with audio" ON 6 | "BUILD_TOOLS_VCOMPUTER" OFF) 7 | 8 | # Give these some dummy values and if the platform is LINUX or OSX they will be set accordingly. 9 | SET(X11_LIBRARIES "") 10 | SET(OSX_LIBRARIES "") 11 | 12 | # FIND GLFW3 AND OPENGL libs 13 | FIND_PACKAGE(GLFW3) 14 | IF (NOT GLFW3_FOUND) 15 | MESSAGE(WARNING "GLFW3 not found! toy emulator will not display screen and virtual keyboard") 16 | SET (GLFW3_ENABLE 0) 17 | ELSE (NOT GLFW3_FOUND) 18 | SET (GLFW3_ENABLE 1) 19 | ENDIF (NOT GLFW3_FOUND) 20 | 21 | FIND_PACKAGE(OpenGL) 22 | IF (NOT OPENGL_FOUND) 23 | MESSAGE(WARNING "OpenGL not found! toy emulator will not display screen and virtual keyboard") 24 | SET (GLFW3_ENABLE 0) 25 | ENDIF (NOT OPENGL_FOUND) 26 | 27 | FIND_PACKAGE(GLEW) 28 | IF(NOT GLEW_FOUND) 29 | MESSAGE(WARNING "GLEW not found! toy emulator will not display screen and virtual keyboard") 30 | SET (GLFW3_ENABLE 0) 31 | ENDIF(NOT GLEW_FOUND) 32 | 33 | FIND_PACKAGE(GLM) 34 | IF(NOT GLM_FOUND) 35 | MESSAGE(WARNING "GLM not found! toy emulator will not display screen and virtual keyboard") 36 | SET (GLFW3_ENABLE 0) 37 | ELSE() 38 | # Force using radians as degrees is deprecated 39 | # Bullet is built using doubles 40 | ADD_DEFINITIONS(-DGLM_FORCE_RADIANS -DBT_USE_DOUBLE_PRECISION) 41 | ENDIF(NOT GLM_FOUND) 42 | 43 | FIND_PACKAGE(OpenAL) 44 | IF(NOT OPENAL_FOUND) 45 | MESSAGE(WARNING "OpenAL not found! toy emulator will not be hable to play the beeper") 46 | SET (OPENAL_ENABLE 0) 47 | ELSE (NOT OPENAL_FOUND) 48 | 49 | FIND_PACKAGE(ALURE) 50 | IF(NOT ALURE_FOUND) 51 | MESSAGE(WARNING "ALure not found! toy emulator will not be hable to play the beeper") 52 | SET (OPENAL_ENABLE 0) 53 | ELSE(NOT ALURE_FOUND) 54 | SET (OPENAL_ENABLE 1) 55 | ENDIF(NOT ALURE_FOUND) 56 | 57 | ENDIF(NOT OPENAL_FOUND) 58 | 59 | IF (NOT BUILD_TOOLS_SCREEN) 60 | SET(GLFW3_ENABLE 0) 61 | ENDIF (NOT BUILD_TOOLS_SCREEN) 62 | 63 | IF (NOT BUILD_TOOLS_AUDIO) 64 | SET(OPENAL_ENABLE 0) 65 | ENDIF (NOT BUILD_TOOLS_AUDIO) 66 | # Main executable 67 | 68 | # Main executable config file 69 | CONFIGURE_FILE (./config_main.hpp.in 70 | "${PROJECT_BINARY_DIR}/config_main.hpp" 71 | ) 72 | 73 | # Setup include and libs to be used in main/vm 74 | SET(VM_INCLUDE_DIRS 75 | ${VCOMPUTER_INCLUDE_DIRS} 76 | "${CMAKE_CURRENT_SOURCE_DIR}/include/" 77 | ) 78 | 79 | # Links agains the static version if is enabled 80 | IF(BUILD_STATIC_VCOMPUTER) 81 | SET(VM_LINK_LIBS 82 | VCOMPUTER_STATIC 83 | ) 84 | ELSEIF(BUILD_DYNAMIC_VCOMPUTER) 85 | SET(VM_LINK_LIBS 86 | VCOMPUTER 87 | ) 88 | ENDIF(BUILD_STATIC_VCOMPUTER) 89 | 90 | SET(MEDIA_INCLUDE_DIRS 91 | ${VM_INCLUDE_DIRS} 92 | ) 93 | SET(MEDIA_LINK_LIBS 94 | ${VM_LINK_LIBS} 95 | ) 96 | 97 | # If we have OpenGL / GLFW3 / GLM / GLEW libs 98 | IF (GLFW3_ENABLE EQUAL 1) 99 | IF (NOT APPLE) # X11 and GLEW are not needed on OSX. 100 | FIND_PACKAGE(X11) 101 | SET(USE_STATIC_GLEW CACHE BOOL "Build against GLEW static (default no)") 102 | FIND_PACKAGE(GLEW REQUIRED) # We find GLEW here as OSX doesn't need it. 103 | ENDIF (NOT APPLE) 104 | 105 | IF (APPLE) # Mac OSX 106 | SET(GLEW_LIBRARY "") # Set a dummy value for GLEW. 107 | 108 | SET(CMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS macosx) 109 | 110 | # Need the 10.7 SDK or later. 111 | EXECUTE_PROCESS(COMMAND xcodebuild -sdk macosx -version SDKVersion OUTPUT_VARIABLE OSX_SDK_VERSION) 112 | IF (NOT (OSX_SDK_VERSION VERSION_GREATER 10.7 OR OSX_SDK_VERSION VERSION_EQUAL 10.7)) 113 | MESSAGE(FATAL_ERROR "The installed version of Xcode does not support the 10.7 SDK or later. Please upgrade Xcode and try again.") 114 | ENDIF (NOT (OSX_SDK_VERSION VERSION_GREATER 10.7 OR OSX_SDK_VERSION VERSION_EQUAL 10.7)) 115 | 116 | # Configure the project to use the correct SDK. 117 | IF (XCODE_VERSION) 118 | SET(CMAKE_OSX_SYSROOT macosx) 119 | ELSE (XCODE_VERSION) 120 | # Non-Xcode generators need the full path. 121 | EXECUTE_PROCESS(COMMAND xcodebuild -sdk macosx -version Path | head -n 1 OUTPUT_VARIABLE CMAKE_OSX_SYSROOT) 122 | STRING(REGEX REPLACE "(\r?\n)+$" "" CMAKE_OSX_SYSROOT "${CMAKE_OSX_SYSROOT}") 123 | ENDIF (XCODE_VERSION) 124 | 125 | # Can deploy back to 10.7, the first OS X to support the GL Core. 126 | SET(CMAKE_OSX_DEPLOYMENT_TARGET 10.7) 127 | 128 | # Need Core Foundation and libobjc. 129 | SET(OSX_LIBRARIES "-framework CoreFoundation /usr/lib/libobjc.dylib") 130 | ENDIF (APPLE) 131 | 132 | MESSAGE(STATUS "vc executable have Virtual Screen enabled") 133 | # Some auxiliar libs 134 | FILE(GLOB TOOL_OTHER_SRC 135 | "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp" 136 | "${CMAKE_CURRENT_SOURCE_DIR}/include/devices/*.hpp" 137 | ) 138 | 139 | SET(MEDIA_INCLUDE_DIRS 140 | ${MEDIA_INCLUDE_DIRS} 141 | ${OPENGL_INCLUDE_DIR} 142 | ${GLEW_INCLUDE_DIR} 143 | ${GLM_INCLUDE_DIR} 144 | ${GLFW3_INCLUDE_PATH} 145 | ) 146 | 147 | SET(MEDIA_LINK_LIBS 148 | ${X11_LIBRARIES} 149 | ${OSX_LIBRARIES} 150 | ${MEDIA_LINK_LIBS} 151 | ${OPENGL_LIBRARIES} 152 | ${GLEW_LIBRARIES} 153 | ${GLM_LIBRARIES} 154 | ${GLFW3_LIBRARIES} 155 | ) 156 | 157 | # TDA VIEWER Can only be build with OpenGL stuff 158 | ADD_EXECUTABLE( tda_view 159 | ./tda_view.cpp 160 | ./src/gl_engine.cpp 161 | ./src/glerror.cpp 162 | ) 163 | SET(TARGETS ${TARGETS} "tda_view") 164 | 165 | INCLUDE_DIRECTORIES( tda_view 166 | ${MEDIA_INCLUDE_DIRS} 167 | ) 168 | 169 | TARGET_LINK_LIBRARIES( tda_view 170 | ${MEDIA_LINK_LIBS} 171 | ) 172 | 173 | ENDIF (GLFW3_ENABLE EQUAL 1) 174 | 175 | # If we have OpenAL 176 | IF (OPENAL_ENABLE EQUAL 1) 177 | MESSAGE(STATUS "vc executable have Sound enabled") 178 | 179 | SET(MEDIA_INCLUDE_DIRS 180 | ${MEDIA_INCLUDE_DIRS} 181 | ${OPENAL_INCLUDE_DIR} 182 | ${ALURE_INCLUDE_DIR} 183 | ) 184 | 185 | SET(MEDIA_LINK_LIBS 186 | ${MEDIA_LINK_LIBS} 187 | ${OPENAL_LIBRARIES} 188 | ${ALURE_LIBRARIES} 189 | ) 190 | 191 | ENDIF (OPENAL_ENABLE EQUAL 1) 192 | 193 | # Main executable 194 | ADD_EXECUTABLE( vc 195 | ./main.cpp 196 | ${TOOL_OTHER_SRC} 197 | ) 198 | SET(TARGETS ${TARGETS} "vc") 199 | 200 | INCLUDE_DIRECTORIES( vc 201 | ${MEDIA_INCLUDE_DIRS} 202 | ) 203 | 204 | TARGET_LINK_LIBRARIES( vc 205 | ${MEDIA_LINK_LIBS} 206 | ) 207 | 208 | #pbm2font tool 209 | ADD_EXECUTABLE( pbm2tdafont 210 | ./pbm2font.cpp 211 | ) 212 | SET(TARGETS ${TARGETS} "pbm2tdafont") 213 | 214 | INCLUDE_DIRECTORIES( pbm2tdafont 215 | ${VM_INCLUDE_DIRS} 216 | ) 217 | TARGET_LINK_LIBRARIES( pbm2tdafont 218 | ${VM_LINK_LIBS} 219 | ) 220 | 221 | # makedisk executable 222 | ADD_EXECUTABLE( maketrdisk 223 | ./makedisk.cpp 224 | ) 225 | SET(TARGETS ${TARGETS} "maketrdisk") 226 | 227 | INCLUDE_DIRECTORIES( maketrdisk 228 | ${VM_INCLUDE_DIRS} 229 | ) 230 | 231 | TARGET_LINK_LIBRARIES( maketrdisk 232 | ${VM_LINK_LIBS} 233 | ) 234 | 235 | INSTALL(CODE "MESSAGE(\"Installing tools\")") 236 | INSTALL(TARGETS ${TARGETS} 237 | COMPONENT toolsbin 238 | RUNTIME DESTINATION bin 239 | ) 240 | 241 | --------------------------------------------------------------------------------