initial commit, stripped-down version of gba-sprite-engine
parent
62dbfddd6b
commit
27e6a9065c
|
@ -1,4 +1,83 @@
|
|||
CMakeLists.txt.user
|
||||
.DS_Store
|
||||
build/
|
||||
.idea/
|
||||
|
||||
# Created by https://www.gitignore.io/api/clion,cmake
|
||||
|
||||
### CLion ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
### CLion Patch ###
|
||||
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
||||
|
||||
# *.iml
|
||||
# modules.xml
|
||||
# .idea/misc.xml
|
||||
# *.ipr
|
||||
|
||||
# Sonarlint plugin
|
||||
.idea/sonarlint
|
||||
|
||||
### CMake ###
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CMakeScripts
|
||||
|
@ -8,4 +87,42 @@ cmake_install.cmake
|
|||
install_manifest.txt
|
||||
compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
_deps
|
||||
|
||||
|
||||
# End of https://www.gitignore.io/api/clion,cmake
|
||||
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
#VisualStudio code
|
||||
.vscode
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
cmake_minimum_required(VERSION 3.12)
|
||||
|
||||
# use the GBA cross-compiler.
|
||||
# WARNING: CMAKE_AR and RANLIB didn't use find_program() to scan the PATH yet.
|
||||
# If using CMake < 3.12, consider using an absolute path. https://gitlab.kitware.com/cmake/cmake/merge_requests/1720
|
||||
SET(CMAKE_SYSTEM_NAME Generic)
|
||||
SET(CMAKE_GENERATOR "Unix Makefiles")
|
||||
SET(CMAKE_C_COMPILER arm-none-eabi-gcc)
|
||||
SET(CMAKE_CXX_COMPILER arm-none-eabi-g++)
|
||||
SET(CMAKE_OBJCOPY arm-none-eabi-objcopy)
|
||||
SET(CMAKE_AR arm-none-eabi-ar CACHE FILEPATH "Archiver")
|
||||
SET(CMAKE_RANLIB arm-none-eabi-ranlib)
|
||||
|
||||
SET(BASE_CMAKE_LINK_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
|
||||
SET(CMAKE_EXE_LINKER_FLAGS "${BASE_CMAKE_LINK_FLAGS} -mthumb-interwork -mthumb -specs=gba.specs")
|
||||
|
||||
SET(CMAKE_CXX_STANDARD 11)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-narrowing -O3")
|
||||
set(CMAKE_VERBOSE_MAKEFILE on)
|
||||
|
||||
project(gba-bitmap-engine-project VERSION 0.1 LANGUAGES CXX)
|
||||
|
||||
# Must use GNUInstallDirs to install libraries into correct locations on all platforms.
|
||||
include(GNUInstallDirs)
|
||||
|
||||
add_subdirectory(engine)
|
||||
|
||||
# this should be a part of the engine CMakeLists.txt file but cross-compiling and gtest doesn't work
|
||||
add_subdirectory(test)
|
||||
|
||||
add_subdirectory(demos/demo1-wireframes)
|
|
@ -0,0 +1,5 @@
|
|||
## A high-level object-oriented Game Boy Advance bitmap 3D software engine
|
||||
|
||||
Engine layout: stripped-down version of [https://github.com/wgroeneveld/gba-sprite-engine/](https://github.com/wgroeneveld/gba-sprite-engine/)
|
||||
|
||||
**Work in progress**, using mode4 to create a software 3D engine from scratch.
|
|
@ -0,0 +1,13 @@
|
|||
project(wireframes)
|
||||
|
||||
add_executable(${PROJECT_NAME}.elf
|
||||
src/main.cpp
|
||||
src/wirescene.cpp
|
||||
src/wirescene.h
|
||||
)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}.elf gba-bitmap-engine)
|
||||
|
||||
add_custom_command(TARGET ${PROJECT_NAME}.elf POST_BUILD
|
||||
COMMAND ${CMAKE_OBJCOPY} -v -O binary ${PROJECT_NAME}.elf ${PROJECT_NAME}.gba
|
||||
)
|
|
@ -0,0 +1,19 @@
|
|||
#include <libgba-sprite-engine/scene.h>
|
||||
#include <libgba-sprite-engine/gba_engine.h>
|
||||
#include <libgba-sprite-engine/palette/palette_manager.h>
|
||||
|
||||
#include "wirescene.h"
|
||||
|
||||
int main() {
|
||||
std::shared_ptr<GBAEngine> engine(new GBAEngine());
|
||||
|
||||
WireScene* startScene = new WireScene(engine);
|
||||
engine->setScene(startScene);
|
||||
|
||||
while (true) {
|
||||
engine->update();
|
||||
engine->delay(1000);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 02/08/18.
|
||||
//
|
||||
|
||||
#include <libgba-sprite-engine/gba/tonc_memdef.h>
|
||||
#include <libgba-sprite-engine/gba_engine.h>
|
||||
#include "wirescene.h"
|
||||
|
||||
|
||||
const unsigned short pal[3] __attribute__((aligned(4))) = {
|
||||
0x0000, 0xFFFF, 0x3AE2
|
||||
};
|
||||
|
||||
void WireScene::load() {
|
||||
foregroundPalette = std::unique_ptr<ForegroundPaletteManager>(new ForegroundPaletteManager());
|
||||
backgroundPalette = std::unique_ptr<BackgroundPaletteManager>(new BackgroundPaletteManager(pal, sizeof(pal)));
|
||||
}
|
||||
|
||||
void WireScene::tick(u16 keys) {
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// Created by Wouter Groeneveld on 02/08/18.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_SAMPLE_START_SCENE_H
|
||||
#define GBA_SPRITE_ENGINE_SAMPLE_START_SCENE_H
|
||||
|
||||
#include <libgba-sprite-engine/scene.h>
|
||||
|
||||
class WireScene : public Scene {
|
||||
private:
|
||||
|
||||
public:
|
||||
|
||||
WireScene(std::shared_ptr<GBAEngine> engine) : Scene(engine) {}
|
||||
|
||||
void load() override;
|
||||
void tick(u16 keys) override;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //GBA_SPRITE_ENGINE_SAMPLE_START_SCENE_H
|
|
@ -0,0 +1,22 @@
|
|||
project(gba-bitmap-engine)
|
||||
set_property(SOURCE src/gba/sin_lut.s PROPERTY LANGUAGE C)
|
||||
set_property(SOURCE src/gba/tonc_bios.s PROPERTY LANGUAGE C)
|
||||
set_source_files_properties(src/gba/tonc_bios.s PROPERTIES COMPILE_FLAGS "-x assembler-with-cpp")
|
||||
|
||||
add_library(${PROJECT_NAME}
|
||||
src/palette/palette_manager.cpp
|
||||
src/palette/combined_palette.cpp
|
||||
src/gba/sin_lut.s
|
||||
src/gba/tonc_bios.s
|
||||
src/gba_engine.cpp
|
||||
src/sound_control.cpp src/scene.cpp src/timer.cpp include/libgba-sprite-engine/gbavector.h src/gbavector.cpp)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
PRIVATE src)
|
||||
|
||||
install(TARGETS ${PROJECT_NAME} EXPORT GbaSpriteEngineTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
|
@ -0,0 +1,132 @@
|
|||
//
|
||||
// tonc_asminc.h : header file with goodies for assembly.
|
||||
//
|
||||
//! \file tonc_asminc.h
|
||||
//! \author J Vijn
|
||||
//! \date 20081019 - 20120519
|
||||
//
|
||||
/* === NOTES ===
|
||||
* Cleaned up the macros so that they work with comma-directives as well.
|
||||
* For use in assembly only!
|
||||
*/
|
||||
|
||||
#ifndef TONC_ASMINC_H
|
||||
#define TONC_ASMINC_H
|
||||
|
||||
#if !__ASSEMBLER__
|
||||
#error This header file is for use in assembly only!
|
||||
#endif // /asm only
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// MACROS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
#define DEF_SIZE(_name) .size _name, .-_name
|
||||
|
||||
//! \name Section definitions for assembly.
|
||||
//\{
|
||||
|
||||
#define CSEC_TEXT .text //!< Standard code section directive.
|
||||
#define CSEC_EWRAM .section .ewram , "ax", %progbits //!< EWRAM code section directive.
|
||||
#define CSEC_IWRAM .section .iwram, "ax", %progbits //!< IWRAM code section directive.
|
||||
|
||||
#define DSEC_DATA .data //<! Standard data section directive.
|
||||
#define DSEC_ROM .section .rodata //!< ROM data section directive.
|
||||
#define DSEC_BSS .section .bss //!< Uninited data (RAM) section directive.
|
||||
#define DSEC_SBSS .section .sbss //!< Uninited data (DTCM?) section directive.
|
||||
|
||||
#define ARM_FUNC .arm //!< Indicates an ARM function.
|
||||
#define THUMB_FUNC .thumb_func //!< Indicates a Thumb function.
|
||||
|
||||
//# NOTE: because these use commas, I can't pass them through CPP macros.
|
||||
//# Yes, this is stupid, but do you have a better idea?
|
||||
|
||||
#undef CSEC_EWRAM
|
||||
.macro CSEC_EWRAM
|
||||
.section .ewram , "ax", %progbits
|
||||
.endm
|
||||
|
||||
#undef CSEC_IWRAM
|
||||
.macro CSEC_IWRAM
|
||||
.section .iwram , "ax", %progbits
|
||||
.endm
|
||||
|
||||
//\}
|
||||
|
||||
|
||||
//! \name Function definition macros.
|
||||
//\{
|
||||
|
||||
//! Start an assembly function.
|
||||
/*!
|
||||
\param _name Name of function.
|
||||
\param _section Section to place function in (like .text)
|
||||
*/
|
||||
#define BEGIN_FUNC(_name, _section, _iset) \
|
||||
_section; \
|
||||
_iset; \
|
||||
.align 2; \
|
||||
.global _name; \
|
||||
.type _name STT_FUNC; \
|
||||
_name:
|
||||
|
||||
//! End of a function.
|
||||
#define END_FUNC(_name) DEF_SIZE(_name)
|
||||
|
||||
//! Begin an ARM function
|
||||
/*!
|
||||
\param _name Name of function.
|
||||
\param _section Section to place function in (like .text)
|
||||
*/
|
||||
#define BEGIN_FUNC_ARM(_name, _section) BEGIN_FUNC(_name, _section, ARM_FUNC)
|
||||
|
||||
//! Begin a THUMB function.
|
||||
/*!
|
||||
\param _name Name of function.
|
||||
\param _section Section to place function in (like .text)
|
||||
*/
|
||||
#define BEGIN_FUNC_THUMB(_name, _section) BEGIN_FUNC(_name, _section, THUMB_FUNC)
|
||||
//\}
|
||||
|
||||
//! \name Data definition macros.
|
||||
//\{
|
||||
#define BEGIN_SYMBOL(_name, _section) \
|
||||
_section; \
|
||||
.align; \
|
||||
.global _name; \
|
||||
_name:
|
||||
|
||||
#define END_SYMBOL(_name) DEF_SIZE(_name)
|
||||
//\}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// CONSTANTS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
//! \name TSurface member offsets.
|
||||
//\{
|
||||
#define TSRF_data 0
|
||||
#define TSRF_pitch 4
|
||||
#define TSRF_width 8
|
||||
#define TSRF_height 10
|
||||
#define TSRF_bpp 12
|
||||
#define TSRF_type 13
|
||||
#define TSRF_palSize 14
|
||||
#define TSRF_pal 16
|
||||
//\}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// GLOBALS
|
||||
// --------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------
|
||||
// PROTOTYPES
|
||||
// --------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------
|
||||
// INLINES
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
#endif // /TONC_ASMINC_H
|
||||
|
||||
// EOF
|
|
@ -0,0 +1,355 @@
|
|||
//
|
||||
// BIOS call functions
|
||||
// MODIFIED by Wouter Groeneveld: extern "C" - no C++ name mangling, can't find assembly methods!
|
||||
//
|
||||
//! \file tonc_bios.h
|
||||
//! \author J Vijn
|
||||
//! \date 20060508 - 20070208
|
||||
//
|
||||
// === NOTES ===
|
||||
//
|
||||
// Pretty much copied verbatim from Pern and dkARM's libgba
|
||||
// (which in turn is copied from CowBite Spec (which got its info from
|
||||
// GBATek))
|
||||
//
|
||||
//
|
||||
// === NOTES ===
|
||||
// * Make SURE your data is aligned to 32bit boundaries. Defining data
|
||||
// as u32 (and I do mean define; not merely cast) ensures this. Either
|
||||
// that or use __attribute__(( aligned(4) ))
|
||||
// * There is a large (70 cycle in and out) overhead for SWIs. If you
|
||||
// know what they do, consider creating replacement code
|
||||
// * div by 0 locks up GBA.
|
||||
// * Cpu(Fast)Set's count is in chunks, not bytes. CpuFastSet REQUIRES
|
||||
// n*32 byte data
|
||||
// * SoftReset is funky with interrupts on.
|
||||
// * VBlankIntrWait is your friend. If you have a VBlank isr that clears
|
||||
// REG_IFBIOS as well. Use this instead of REG_VCOUNT polling for
|
||||
// VSync.
|
||||
// * I haven't tested many of these functions. The ones that are have a
|
||||
// plus (+) behind their numbers.
|
||||
// * I've switched to the standard BIOS names.
|
||||
|
||||
#ifndef TONC_BIOS
|
||||
#define TONC_BIOS
|
||||
|
||||
#include "tonc_types.h"
|
||||
|
||||
/*!
|
||||
\addtogroup grpBios
|
||||
\brief Interfaces and constants for the GBA BIOS routines.
|
||||
|
||||
For details, see
|
||||
<a href="http://www.coranac.com/tonc/text/keys.htm">tonc:keys</a>
|
||||
and especially
|
||||
<a href="http://nocash.emubase.de/gbatek.htm#biosfunctions">gbatek:bios</a>.
|
||||
|
||||
\note While the speeds of the routines are fair, there
|
||||
is a large overhead in calling the functions.
|
||||
*/
|
||||
|
||||
/*! \defgroup grpBiosDef BIOS informalities
|
||||
\ingroup grpBios
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// CONSTANTS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
//! \name SoftReset flags
|
||||
//\{
|
||||
#define ROM_RESTART 0x00 //!< Restart from ROM entry point.
|
||||
#define RAM_RESTART 0x01 //!< Restart from RAM entry point.
|
||||
//\}
|
||||
|
||||
//! \name RegisterRamReset flags
|
||||
//\{
|
||||
#define RESET_EWRAM 0x0001 //!< Clear 256K on-board WRAM
|
||||
#define RESET_IWRAM 0x0002 //!< Clear 32K in-chip WRAM
|
||||
#define RESET_PALETTE 0x0004 //!< Clear Palette
|
||||
#define RESET_VRAM 0x0008 //!< Clear VRAM
|
||||
#define RESET_OAM 0x0010 //!< Clear OAM. does NOT disable OBJs!
|
||||
#define RESET_REG_SIO 0x0020 //!< Switches to general purpose mode
|
||||
#define RESET_REG_SOUND 0x0040 //!< Reset Sound registers
|
||||
#define RESET_REG 0x0080 //!< All other registers
|
||||
|
||||
//#define RESET_REG_VIDEO 0x0100 //!< video regs, 00h-60h (non standard!)
|
||||
//#define RESET_REG_DMA 0x0200 //!< DMA regs, B0h-100h (non standard!)
|
||||
//#define RESET_REG_TIMER 0x0400 //!< Timer regs (100h-110h) (non standard!)
|
||||
|
||||
#define RESET_MEM_MASK 0x001F
|
||||
#define RESET_REG_MASK 0x00E0
|
||||
|
||||
#define RESET_GFX 0x001C //!< Clear all gfx-related memory
|
||||
|
||||
//\}
|
||||
|
||||
//! \name Cpu(Fast)Set flags
|
||||
//\{
|
||||
#define CS_CPY 0 //!< Copy mode
|
||||
#define CS_FILL (1<<24) //!< Fill mode
|
||||
#define CS_CPY16 0 //!< Copy in halfwords
|
||||
#define CS_CPY32 (1<<26) //!< Copy words
|
||||
#define CS_FILL32 (5<<24) //!< Fill words
|
||||
|
||||
#define CFS_CPY CS_CPY //!< Copy words
|
||||
#define CFS_FILL CS_FILL //!< Fill words
|
||||
//\}
|
||||
|
||||
//! \name ObjAffineSet P-element offsets
|
||||
//\{
|
||||
#define BG_AFF_OFS 2 //!< BgAffineDest offsets
|
||||
#define OBJ_AFF_OFS 8 //!< ObjAffineDest offsets
|
||||
//\}
|
||||
|
||||
//! \name Decompression routines
|
||||
#define BUP_ALL_OFS (1<<31)
|
||||
|
||||
#define LZ_TYPE 0x00000010
|
||||
#define LZ_SIZE_MASK 0xFFFFFF00
|
||||
#define LZ_SIZE_SHIFT 8
|
||||
|
||||
#define HUF_BPP_MASK 0x0000000F
|
||||
#define HUF_TYPE 0x00000020
|
||||
#define HUF_SIZE_MASK 0xFFFFFF00
|
||||
#define HUF_SIZE_SHIFT 8
|
||||
|
||||
#define RL_TYPE 0x00000030
|
||||
#define RL_SIZE_MASK 0xFFFFFF00
|
||||
#define RL_SIZE_SHIFT 8
|
||||
|
||||
#define DIF_8 0x00000001
|
||||
#define DIF_16 0x00000002
|
||||
#define DIF_TYPE 0x00000080
|
||||
#define DIF_SIZE_MASK 0xFFFFFF00
|
||||
#define DIF_SIZE_SHIFT 8
|
||||
//\}
|
||||
|
||||
//! \name Multiboot modes
|
||||
//\{
|
||||
#define MBOOT_NORMAL 0x00
|
||||
#define MBOOT_MULTI 0x01
|
||||
#define MBOOT_FAST 0x02
|
||||
//\}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// MACROS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
//! BIOS calls from C
|
||||
/*! You can use this macro in a C BIOS-call wrapper. The wrapper
|
||||
* should declare the flags, then this call will do the rest.
|
||||
* \param x Number of swi call (THUMB number)
|
||||
* \note It checks the __thumb__ \#define to see whether we're
|
||||
* in ARM or THUMB mode and fixes the swi number accordingly.
|
||||
* Huzzah for the C proprocessor!
|
||||
* \deprecated This macro will not work properly for functions that have IO.
|
||||
*/
|
||||
#if defined ( __thumb__ )
|
||||
#define swi_call(x) __asm("swi\t"#x ::: "r0", "r1", "r2", "r3")
|
||||
#else
|
||||
#define swi_call(x) __asm("swi\t"#x"<<16" ::: "r0", "r1", "r2", "r3")
|
||||
#endif
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// CLASSES
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
// --- affine function 0x0E and 0x0F ---
|
||||
|
||||
/*
|
||||
* Notational convention: postfix underscore is 2d vector
|
||||
*
|
||||
* p_ = (px, py) = texture coordinates
|
||||
* q_ = (qx, qy) = screen coordinates
|
||||
* P = | pa pb | = affine matrix
|
||||
* | pc pd |
|
||||
* d_ = (dx, dy) = background displacement
|
||||
*
|
||||
* Then:
|
||||
*
|
||||
* (1) p_ = P*q_ + d_
|
||||
*
|
||||
* For transformation around a different point
|
||||
* (texture point p0_ and screen point q0_), do
|
||||
*
|
||||
* (2) p_ - p0_ = P*(q_-q0_)
|
||||
*
|
||||
* Subtracting eq 2 from eq1 we immediately find:
|
||||
*
|
||||
* (3) _d = p0_ - P*q0_
|
||||
*
|
||||
* For the special case of a texture->screen scale-then-rotate
|
||||
* transformation with
|
||||
* s_ = (sx, sy) = inverse scales (s>1 shrinks)
|
||||
* a = alpha = Counter ClockWise (CCW) angle
|
||||
*
|
||||
* (4) P = | sx*cos(a) -sx*sin(a) |
|
||||
* | sy*sin(a) sy*cos(a) |
|
||||
*
|
||||
*
|
||||
* ObjAffineSet takes a and s_ as input and gives P
|
||||
* BgAffineSet does that and fills in d_ as well
|
||||
*
|
||||
*/
|
||||
|
||||
// affine types in tonc_types.h
|
||||
|
||||
//! BitUpPack ( for swi 10h)
|
||||
typedef struct BUP
|
||||
{
|
||||
u16 src_len; //!< source length (bytes)
|
||||
u8 src_bpp; //!< source bitdepth (1,2,4,8)
|
||||
u8 dst_bpp; //!< destination bitdepth (1,2,4,8,16,32)
|
||||
u32 dst_ofs; //!< {0-30}: added offset {31}: zero-data offset flag
|
||||
} BUP;
|
||||
|
||||
//! Multiboot struct
|
||||
typedef struct
|
||||
{
|
||||
u32 reserved1[5];
|
||||
u8 handshake_data;
|
||||
u8 padding;
|
||||
u16 handshake_timeout;
|
||||
u8 probe_count;
|
||||
u8 client_data[3];
|
||||
u8 palette_data;
|
||||
u8 response_bit;
|
||||
u8 client_bit;
|
||||
u8 reserved2;
|
||||
u8 *boot_srcp;
|
||||
u8 *boot_endp;
|
||||
u8 *masterp;
|
||||
u8 *reserved3[3];
|
||||
u32 system_work2[4];
|
||||
u8 sendflag;
|
||||
u8 probe_target_bit;
|
||||
u8 check_wait;
|
||||
u8 server_type;
|
||||
} MultiBootParam;
|
||||
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// BASIC BIOS ROUTINES
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
/*! \defgroup grpBiosMain BIOS functions
|
||||
* \ingroup grpBios
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
//! \name Reset functions
|
||||
//\{
|
||||
extern "C" void SoftReset(void);
|
||||
extern "C" void RegisterRamReset(u32 flags);
|
||||
//\}
|
||||
|
||||
//! \name Halt functions
|
||||
//\{
|
||||
extern "C" void Halt(void);
|
||||
extern "C" void Stop(void);
|
||||
extern "C" void IntrWait(u32 flagClear, u32 irq);
|
||||
extern "C" void VBlankIntrWait(void);
|
||||
//\}
|
||||
|
||||
|
||||
//! \name Math functions
|
||||
//\{
|
||||
extern "C" s32 Div(s32 num, s32 den);
|
||||
extern "C" s32 DivArm(s32 den, s32 num);
|
||||
extern "C" u32 Sqrt(u32 num);
|
||||
extern "C" s16 ArcTan(s16 dydx);
|
||||
extern "C" s16 ArcTan2(s16 x, s16 y);
|
||||
//\}
|
||||
|
||||
//! \name Memory copiers/fillers
|
||||
//\{
|
||||
// Technically, these are misnomers. The convention is that
|
||||
// xxxset is used for fills (comp memset, strset). Or perhaps
|
||||
// the C library functions are misnomers, since set can be applied
|
||||
// to both copies and fills.
|
||||
extern "C" void CpuSet(const void *src, void *dst, u32 mode);
|
||||
extern "C" void CpuFastSet(const void *src, void *dst, u32 mode);
|
||||
//\}
|
||||
|
||||
extern "C" u32 BiosCheckSum(void);
|
||||
|
||||
|
||||
//! \name Rot/scale functions
|
||||
//\{
|
||||
// These functions are misnomers, because ObjAffineSet is merely
|
||||
// a special case of/precursor to BgAffineSet. Results from either
|
||||
// can be used for both objs and bgs. Oh well.
|
||||
extern "C" void ObjAffineSet(const ObjAffineSource *src, void *dst, s32 num, s32 offset);
|
||||
extern "C" void BgAffineSet(const BgAffineSource *src, BgAffineDest *dst, s32 num);
|
||||
//\}
|
||||
|
||||
//! \name Decompression (see GBATek for format details)
|
||||
//\{
|
||||
extern "C" void BitUnPack(const void *src, void *dst, const BUP *bup);
|
||||
extern "C" void LZ77UnCompWram(const void *src, void *dst);
|
||||
extern "C" void LZ77UnCompVram(const void *src, void *dst);
|
||||
extern "C" void HuffUnComp(const void *src, void *dst);
|
||||
extern "C" void RLUnCompWram(const void *src, void *dst);
|
||||
extern "C" void RLUnCompVram(const void *src, void *dst);
|
||||
extern "C" void Diff8bitUnFilterWram(const void *src, void *dst);
|
||||
extern "C" void Diff8bitUnFilterVram(const void *src, void *dst);
|
||||
extern "C" void Diff16bitUnFilter(const void *src, void *dst);
|
||||
//\}
|
||||
|
||||
//! \name Sound Functions
|
||||
//\{
|
||||
// (I have even less of a clue what these do than for the others ---
|
||||
extern "C" void SoundBias(u32 bias);
|
||||
extern "C" void SoundDriverInit(void *src);
|
||||
extern "C" void SoundDriverMode(u32 mode);
|
||||
extern "C" void SoundDriverMain(void);
|
||||
extern "C" void SoundDriverVSync(void);
|
||||
extern "C" void SoundChannelClear(void);
|
||||
extern "C" u32 MidiKey2Freq(void *wa, u8 mk, u8 fp);
|
||||
extern "C" void SoundDriverVSyncOff(void);
|
||||
extern "C" void SoundDriverVSyncOn(void);
|
||||
//\}
|
||||
|
||||
//! \name Multiboot handshake
|
||||
//\{
|
||||
extern "C" int MultiBoot(MultiBootParam* mb, u32 mode);
|
||||
//\}
|
||||
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
/*! \defgroup grpBiosEx More BIOS functions
|
||||
* \ingroup grpBios
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
//\{
|
||||
|
||||
// You can find these in swi_ex.s
|
||||
extern "C" void VBlankIntrDelay(u32 count);
|
||||
extern "C" int DivSafe(int num, int den);
|
||||
extern "C" int Mod(int num, int den);
|
||||
extern "C" u32 DivAbs(int num, int den);
|
||||
extern "C" int DivArmMod(int den, int num);
|
||||
extern "C" u32 DivArmAbs(int den, int num);
|
||||
extern "C" void CpuFastFill(u32 wd, void *dst, u32 count);
|
||||
|
||||
#define DivMod Mod
|
||||
//\}
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
#endif // TONC_BIOS
|
|
@ -0,0 +1,573 @@
|
|||
//
|
||||
// Core functionality
|
||||
//
|
||||
//! \file tonc_core.h
|
||||
//! \author J Vijn
|
||||
//! \date 20060508 - 20080128
|
||||
//
|
||||
/* === NOTES ===
|
||||
* Contents: bits, random, dma, timer
|
||||
* 20080129,jv: added tonccpy/set routines.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef TONC_CORE
|
||||
#define TONC_CORE
|
||||
|
||||
#include "tonc_memmap.h"
|
||||
#include "tonc_memdef.h"
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// BITS and BITFIELDS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
/*! \defgroup grpCoreBit Bit(field) macros
|
||||
\ingroup grpCore
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
//! \name Simple bit macros
|
||||
//\{
|
||||
|
||||
//! Create value with bit \a n set
|
||||
#define BIT(n) ( 1<<(n) )
|
||||
|
||||
//! Shift \a a by \a n
|
||||
#define BIT_SHIFT(a, n) ( (a)<<(n) )
|
||||
|
||||
//! Create a bitmask \a len bits long
|
||||
#define BIT_MASK(len) ( BIT(len)-1 )
|
||||
|
||||
//! Set the \a flag bits in \a word
|
||||
#define BIT_SET(y, flag) ( y |= (flag) )
|
||||
|
||||
//! Clear the \a flag bits in \a word
|
||||
#define BIT_CLEAR(y, flag) ( y &= ~(flag) )
|
||||
|
||||
//! Flip the \a flag bits in \a word
|
||||
#define BIT_FLIP(y, flag) ( y ^= (flag) )
|
||||
|
||||
//! Test whether all the \a flag bits in \a word are set
|
||||
#define BIT_EQ(y, flag) ( ((y)&(flag)) == (flag) )
|
||||
|
||||
|
||||
|
||||
//! Create a bitmask of length \a len starting at bit \a shift.
|
||||
#define BF_MASK(shift, len) ( BIT_MASK(len)<<(shift) )
|
||||
|
||||
|
||||
//! Retrieve a bitfield mask of length \a starting at bit \a shift from \a y.
|
||||
#define _BF_GET(y, shift, len) ( ((y)>>(shift))&BIT_MASK(len) )
|
||||
|
||||
//! Prepare a bitmask for insertion or combining.
|
||||
#define _BF_PREP(x, shift, len) ( ((x)&BIT_MASK(len))<<(shift) )
|
||||
|
||||
//! Insert a new bitfield value \a x into \a y.
|
||||
#define _BF_SET(y, x, shift, len) \
|
||||
( y= ((y) &~ BF_MASK(shift, len)) | _BF_PREP(x, shift, len) )
|
||||
|
||||
//\}
|
||||
|
||||
|
||||
/*! \name some EVIL bit-field operations, >:)
|
||||
* These allow you to mimic bitfields with macros. Most of the
|
||||
* bitfields in the registers have <i>foo</i>_SHIFT and
|
||||
* <i>foo</i>_SHIFT macros indicating the mask and shift values
|
||||
* of the bitfield named <i>foo</i> in a variable.
|
||||
* These macros let you prepare, get and set the bitfields.
|
||||
*/
|
||||
//\{
|
||||
|
||||
//! Prepare a named bit-field for for insterion or combination.
|
||||
#define BFN_PREP(x, name) ( ((x)<<name##_SHIFT) & name##_MASK )
|
||||
|
||||
//! Get the value of a named bitfield from \a y. Equivalent to (var=) y.name
|
||||
#define BFN_GET(y, name) ( ((y) & name##_MASK)>>name##_SHIFT )
|
||||
|
||||
//! Set a named bitfield in \a y to \a x. Equivalent to y.name= x.
|
||||
#define BFN_SET(y, x, name) (y = ((y)&~name##_MASK) | BFN_PREP(x,name) )
|
||||
|
||||
//! Compare a named bitfield to named literal \a x.
|
||||
#define BFN_CMP(y, x, name) ( ((y)&name##_MASK) == (x) )
|
||||
|
||||
|
||||
//! Massage \a x for use in bitfield \a name with pre-shifted \a x
|
||||
#define BFN_PREP2(x, name) ( (x) & name##_MASK )
|
||||
|
||||
//! Get the value of bitfield \a name from \a y, but don't down-shift
|
||||
#define BFN_GET2(y, name) ( (y) & name##_MASK )
|
||||
|
||||
//! Set bitfield \a name from \a y to \a x with pre-shifted \a x
|
||||
#define BFN_SET2(y,x,name) ( y = ((y)&~name##_MASK) | BFN_PREP2(x,name) )
|
||||
|
||||
//\}
|
||||
|
||||
INLINE u32 bf_get(u32 y, uint shift, uint len);
|
||||
INLINE u32 bf_merge(u32 y, u32 x, uint shift, uint len);
|
||||
INLINE u32 bf_clamp(int x, uint len);
|
||||
|
||||
INLINE int bit_tribool(u32 x, uint plus, uint minus);
|
||||
INLINE u32 ROR(u32 x, uint ror);
|
||||
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
/*! \defgroup grpData Data routines
|
||||
\ingroup grpCore
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
//! Get the number of elements in an array
|
||||
#define countof(_array) ( sizeof(_array)/sizeof(_array[0]) )
|
||||
|
||||
//! Align \a x to the next multiple of \a width.
|
||||
INLINE uint align(uint x, uint width);
|
||||
|
||||
//! \name Copying and filling routines
|
||||
//\{
|
||||
|
||||
//! Simplified copier for GRIT-exported data.
|
||||
#define GRIT_CPY(dst, name) memcpy16(dst, name, name##Len/2)
|
||||
|
||||
|
||||
// Base memcpy/set replacements.
|
||||
void *tonccpy(void *dst, const void *src, uint size);
|
||||
|
||||
void *__toncset(void *dst, u32 fill, uint size);
|
||||
INLINE void *toncset(void *dst, u8 src, uint count);
|
||||
INLINE void *toncset16(void *dst, u16 src, uint count);
|
||||
INLINE void *toncset32(void *dst, u32 src, uint count);
|
||||
|
||||
|
||||
// Fast memcpy/set
|
||||
void memset16(void *dst, u16 hw, uint hwcount);
|
||||
void memcpy16(void *dst, const void* src, uint hwcount);
|
||||
|
||||
IWRAM_CODE void memset32(void *dst, u32 wd, uint wcount);
|
||||
IWRAM_CODE void memcpy32(void *dst, const void* src, uint wcount);
|
||||
|
||||
|
||||
//! Fastfill for halfwords, analogous to memset()
|
||||
/*! Uses <code>memset32()</code> if \a hwcount>5
|
||||
* \param dst Destination address.
|
||||
* \param hw Source halfword (not address).
|
||||
* \param hwcount Number of halfwords to fill.
|
||||
* \note \a dst <b>must</b> be halfword aligned.
|
||||
* \note \a r0 returns as \a dst + \a hwcount*2.
|
||||
*/
|
||||
void memset16(void *dst, u16 hw, uint hwcount);
|
||||
|
||||
//! \brief Copy for halfwords.
|
||||
/*! Uses <code>memcpy32()</code> if \a hwn>6 and
|
||||
\a src and \a dst are aligned equally.
|
||||
\param dst Destination address.
|
||||
\param src Source address.
|
||||
\param hwcount Number of halfwords to fill.
|
||||
\note \a dst and \a src <b>must</b> be halfword aligned.
|
||||
\note \a r0 and \a r1 return as
|
||||
\a dst + \a hwcount*2 and \a src + \a hwcount*2.
|
||||
*/
|
||||
void memcpy16(void *dst, const void* src, uint hwcount);
|
||||
|
||||
|
||||
//! Fast-fill by words, analogous to memset()
|
||||
/*! Like CpuFastSet(), only without the requirement of
|
||||
32byte chunks and no awkward store-value-in-memory-first issue.
|
||||
\param dst Destination address.
|
||||
\param wd Fill word (not address).
|
||||
\param wdcount Number of words to fill.
|
||||
\note \a dst <b>must</b> be word aligned.
|
||||
\note \a r0 returns as \a dst + \a wdcount*4.
|
||||
*/
|
||||
IWRAM_CODE void memset32(void *dst, u32 wd, uint wdcount);
|
||||
|
||||
|
||||
//! \brief Fast-copy by words.
|
||||
/*! Like CpuFastFill(), only without the requirement of 32byte chunks
|
||||
\param dst Destination address.
|
||||
\param src Source address.
|
||||
\param wdcount Number of words.
|
||||
\note \a src and \a dst <b>must</b> be word aligned.
|
||||
\note \a r0 and \a r1 return as
|
||||
\a dst + \a wdcount*4 and \a src + \a wdcount*4.
|
||||
*/
|
||||
IWRAM_CODE void memcpy32(void *dst, const void* src, uint wdcount);
|
||||
|
||||
//\}
|
||||
|
||||
|
||||
/*! \name Repeated-value creators
|
||||
These function take a hex-value and duplicate it to all fields,
|
||||
like 0x88 -> 0x88888888.
|
||||
*/
|
||||
//\{
|
||||
INLINE u16 dup8(u8 x);
|
||||
INLINE u32 dup16(u16 x);
|
||||
INLINE u32 quad8(u8 x);
|
||||
INLINE u32 octup(u8 x);
|
||||
//\}
|
||||
|
||||
//! \name Packing routines.
|
||||
//\{
|
||||
INLINE u16 bytes2hword(u8 b0, u8 b1);
|
||||
INLINE u32 bytes2word(u8 b0, u8 b1, u8 b2, u8 b3);
|
||||
INLINE u32 hword2word(u16 h0, u16 h1);
|
||||
//\}
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DMA
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
/*! \addtogroup grpDma */
|
||||
/*! \{ */
|
||||
|
||||
//! General purpose DMA transfer macro
|
||||
/*! \param _dst Destination address.
|
||||
\param _src Source address.
|
||||
\param count Number of transfers.
|
||||
\param ch DMA channel.
|
||||
\param mode DMA mode.
|
||||
*/
|
||||
#define DMA_TRANSFER(_dst, _src, count, ch, mode) \
|
||||
do { \
|
||||
REG_DMA[ch].cnt= 0; \
|
||||
REG_DMA[ch].src= (const void*)(_src); \
|
||||
REG_DMA[ch].dst= (void*)(_dst); \
|
||||
REG_DMA[ch].cnt= (count) | (mode); \
|
||||
} while(0)
|
||||
|
||||
|
||||
INLINE void dma_cpy(void *dst, const void *src, uint count, uint ch, u32 mode);
|
||||
INLINE void dma_fill(void *dst, volatile u32 src, uint count, uint ch, u32 mode);
|
||||
|
||||
INLINE void dma3_cpy(void *dst, const void *src, uint size);
|
||||
INLINE void dma3_fill(void *dst, volatile u32 src, uint size);
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// TIMER
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
INLINE void profile_start(void);
|
||||
INLINE uint profile_stop(void);
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// TONE GENERATOR
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NOTE_C=0, NOTE_CIS, NOTE_D, NOTE_DIS,
|
||||
NOTE_E, NOTE_F, NOTE_FIS, NOTE_G,
|
||||
NOTE_GIS, NOTE_A, NOTE_BES, NOTE_B
|
||||
} eSndNoteId;
|
||||
|
||||
extern const uint __snd_rates[12];
|
||||
|
||||
//! Gives the period of a note for the tone-gen registers.
|
||||
/*! GBA sound range: 8 octaves: [-2, 5]; 8*12= 96 notes (kinda).
|
||||
* \param note ID (range: [0,11>). See eSndNoteId.
|
||||
* \param oct octave (range [-2,4)>).
|
||||
*/
|
||||
#define SND_RATE(note, oct) ( 2048-(__snd_rates[note]>>(4+(oct))) )
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// MISC
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
/*! \defgroup grpCoreMisc Miscellaneous routines
|
||||
* \ingroup grpCore
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
#define STR(x) #x
|
||||
|
||||
//! Create text string from a literal
|
||||
#define XSTR(x) STR(x)
|
||||
|
||||
|
||||
//! \name Inline assembly
|
||||
//\{
|
||||
|
||||
//! Assembly comment
|
||||
#define ASM_CMT(str) asm volatile("@# " str)
|
||||
|
||||
//! No$gba breakpoint
|
||||
#define ASM_BREAK() asm volatile("\tmov\t\tr11, r11")
|
||||
|
||||
//! No-op; wait a bit.
|
||||
#define ASM_NOP() asm volatile("\tnop")
|
||||
|
||||
//\}
|
||||
|
||||
|
||||
//! \name Sector checking
|
||||
//\{
|
||||
|
||||
u32 octant(int x, int y);
|
||||
u32 octant_rot(int x0, int y0);
|
||||
|
||||
//\}
|
||||
|
||||
//! \name Random numbers
|
||||
//\{
|
||||
|
||||
#define QRAN_SHIFT 15
|
||||
#define QRAN_MASK ((1<<QRAN_SHIFT)-1)
|
||||
#define QRAN_MAX QRAN_MASK
|
||||
|
||||
int sqran(int seed);
|
||||
INLINE int qran(void);
|
||||
INLINE int qran_range(int min, int max);
|
||||
|
||||
//\}
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// GLOBALS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
extern const u8 oam_sizes[3][4][2];
|
||||
extern const BG_AFFINE bg_aff_default;
|
||||
extern COLOR *vid_page;
|
||||
|
||||
extern int __qran_seed;
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// INLINES
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
// --- Bit and bitfields -----------------------------------------------
|
||||
|
||||
|
||||
//! Get \a len long bitfield from \a y, starting at \a shift.
|
||||
/*! \param y Value containing bitfield.
|
||||
\param shift Bitfield Start;
|
||||
\param len Length of bitfield.
|
||||
\return Bitfield between bits \a shift and \a shift + \a length.
|
||||
*/
|
||||
INLINE u32 bf_get(u32 y, uint shift, uint len)
|
||||
{ return (y>>shift) & ( (1<<len)-1 ); }
|
||||
|
||||
//! Merge \a x into an \a len long bitfield from \a y, starting at \a shift.
|
||||
/*! \param y Value containing bitfield.
|
||||
\param x Value to merge (will be masked to fit).
|
||||
\param shift Bitfield Start;
|
||||
\param len Length of bitfield.
|
||||
\return Result of merger: (y&~M) | (x<<s & M)
|
||||
\note Does \e not write the result back into \a y (Because pure C
|
||||
does't have references, that's why)
|
||||
*/
|
||||
INLINE u32 bf_merge(u32 y, u32 x, uint shift, uint len)
|
||||
{
|
||||
u32 mask= ((u32)(1<<len)-1);
|
||||
return (y &~ (mask<<shift)) | (x & mask)<<shift;
|
||||
}
|
||||
|
||||
//! Clamp \a to within the range allowed by \a len bits
|
||||
INLINE u32 bf_clamp(int x, uint len)
|
||||
{
|
||||
u32 y=x>>len;
|
||||
if(y)
|
||||
x= (~y)>>(32-len);
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
//! Gives a tribool (-1, 0, or +1) depending on the state of some bits.
|
||||
/*! Looks at the \a plus and \a minus bits of \a flags, and subtracts
|
||||
their status to give a +1, -1 or 0 result. Useful for direction flags.
|
||||
\param flags Value with bit-flags.
|
||||
\param plus Bit number for positive result.
|
||||
\param minus Bit number for negative result.
|
||||
\return <b>+1</b> if \a plus bit is set but \a minus bit isn't<br>
|
||||
<b>-1</b> if \a minus bit is set and \a plus bit isn't<br>
|
||||
<b>0</b> if neither or both are set.
|
||||
*/
|
||||
INLINE int bit_tribool(u32 flags, uint plus, uint minus)
|
||||
{ return ((flags>>plus)&1) - ((flags>>minus)&1); }
|
||||
|
||||
|
||||
//! Rotate bits right. Yes, this does lead to a ror instruction.
|
||||
INLINE u32 ROR(u32 x, uint ror)
|
||||
{ return (x<<(32-ror)) | (x>>ror); }
|
||||
|
||||
|
||||
// --- Data -----------------------------------------------------------
|
||||
|
||||
INLINE uint align(uint x, uint width)
|
||||
{ return (x+width-1)/width*width; }
|
||||
|
||||
|
||||
//! VRAM-safe memset, byte version. Size in bytes.
|
||||
INLINE void *toncset(void *dst, u8 src, uint count)
|
||||
{ return __toncset(dst, quad8(src), count); }
|
||||
|
||||
//! VRAM-safe memset, halfword version. Size in hwords.
|
||||
INLINE void *toncset16(void *dst, u16 src, uint count)
|
||||
{ return __toncset(dst, src|src<<16, count*2); }
|
||||
|
||||
//! VRAM-safe memset, word version. Size in words.
|
||||
INLINE void *toncset32(void *dst, u32 src, uint count)
|
||||
{ return __toncset(dst, src, count*4); }
|
||||
|
||||
|
||||
|
||||
//! Duplicate a byte to form a halfword: 0x12 -> 0x1212.
|
||||
INLINE u16 dup8(u8 x) { return x|(x<<8); }
|
||||
|
||||
//! Duplicate a halfword to form a word: 0x1234 -> 0x12341234.
|
||||
INLINE u32 dup16(u16 x) { return x|(x<<16); }
|
||||
|
||||
//! Quadruple a byte to form a word: 0x12 -> 0x12121212.
|
||||
INLINE u32 quad8(u8 x) { return x*0x01010101; }
|
||||
|
||||
//! Octuple a nybble to form a word: 0x1 -> 0x11111111
|
||||
INLINE u32 octup(u8 x) { return x*0x11111111; }
|
||||
|
||||
|
||||
//! Pack 2 bytes into a word. Little-endian order.
|
||||
INLINE u16 bytes2hword(u8 b0, u8 b1)
|
||||
{ return b0 | b1<<8; }
|
||||
|
||||
//! Pack 4 bytes into a word. Little-endian order.
|
||||
INLINE u32 bytes2word(u8 b0, u8 b1, u8 b2, u8 b3)
|
||||
{ return b0 | b1<<8 | b2<<16 | b3<<24; }
|
||||
|
||||
INLINE u32 hword2word(u16 h0, u16 h1)
|
||||
{ return h0 | h1<<16; }
|
||||
|
||||
|
||||
// --- DMA ------------------------------------------------------------
|
||||
|
||||
/*! \addtogroup grpDma */
|
||||
/*! \{ */
|
||||
|
||||
//! Generic DMA copy routine.
|
||||
/*! \param dst Destination address.
|
||||
* \param src Source address.
|
||||
* \param count Number of copies to perform.
|
||||
* \param ch DMA channel.
|
||||
* \param mode DMA transfer mode.
|
||||
* \note \a count is the number of copies, not the size in bytes.
|
||||
*/
|
||||
INLINE void dma_cpy(void *dst, const void *src, uint count, uint ch, u32 mode)
|
||||
{
|
||||
REG_DMA[ch].cnt= 0;
|
||||
REG_DMA[ch].src= src;
|
||||
REG_DMA[ch].dst= dst;
|
||||
REG_DMA[ch].cnt= mode | count;
|
||||
}
|
||||
|
||||
//! Generic DMA fill routine.
|
||||
/*! \param dst Destination address.
|
||||
* \param src Source value.
|
||||
* \param count Number of copies to perform.
|
||||
* \param ch DMA channel.
|
||||
* \param mode DMA transfer mode.
|
||||
* \note \a count is the number of copies, not the size in bytes.
|
||||
*/
|
||||
INLINE void dma_fill(void *dst, volatile u32 src, uint count, uint ch, u32 mode)
|
||||
{
|
||||
REG_DMA[ch].cnt= 0;
|
||||
REG_DMA[ch].src= (const void*)&src;
|
||||
REG_DMA[ch].dst= dst;
|
||||
REG_DMA[ch].cnt= count | mode | DMA_SRC_FIXED;
|
||||
}
|
||||
|
||||
//! Specific DMA copier, using channel 3, word transfers.
|
||||
/*! \param dst Destination address.
|
||||
* \param src Source address.
|
||||
* \param size Number of bytes to copy
|
||||
* \note \a size is the number of bytes
|
||||
*/
|
||||
INLINE void dma3_cpy(void *dst, const void *src, uint size)
|
||||
{ dma_cpy(dst, src, size/4, 3, DMA_CPY32); }
|
||||
|
||||
//! Specific DMA filler, using channel 3, word transfers.
|
||||
/*! \param dst Destination address.
|
||||
* \param src Source value.
|
||||
* \param size Number of bytes to copy
|
||||
* \note \a size is the number of bytes
|
||||
*/
|
||||
INLINE void dma3_fill(void *dst, volatile u32 src, uint size)
|
||||
{ dma_fill(dst, src, size/4, 3, DMA_FILL32); }
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// --- Random ---------------------------------------------------------
|
||||
|
||||
//! Quick (and very dirty) pseudo-random number generator
|
||||
/*! \return random in range [0,8000h>
|
||||
*/
|
||||
INLINE int qran(void)
|
||||
{
|
||||
__qran_seed= 1664525*__qran_seed+1013904223;
|
||||
return (__qran_seed>>16) & QRAN_MAX;
|
||||
}
|
||||
|
||||
|
||||
//! Ranged random number
|
||||
/*! \return random in range [\a min, \a max>
|
||||
* \note (max-min) must be lower than 8000h
|
||||
*/
|
||||
INLINE int qran_range(int min, int max)
|
||||
{ return (qran()*(max-min)>>QRAN_SHIFT)+min; }
|
||||
|
||||
|
||||
// --- Timer ----------------------------------------------------------
|
||||
|
||||
/*! \addtogroup grpTimer */
|
||||
/*! \{ */
|
||||
|
||||
//! Start a profiling run
|
||||
/*! \note Routine uses timers 3 and 3; if you're already using these
|
||||
* somewhere, chaos is going to ensue.
|
||||
*/
|
||||
INLINE void profile_start(void)
|
||||
{
|
||||
REG_TM2D= 0; REG_TM3D= 0;
|
||||
REG_TM2CNT= 0; REG_TM3CNT= 0;
|
||||
REG_TM3CNT= TM_ENABLE | TM_CASCADE;
|
||||
REG_TM2CNT= TM_ENABLE;
|
||||
}
|
||||
|
||||
//! Stop a profiling run and return the time since its start.
|
||||
/*! \return 32bit cycle count
|
||||
*/
|
||||
INLINE uint profile_stop(void)
|
||||
{
|
||||
REG_TM2CNT= 0;
|
||||
return (REG_TM3D<<16)|REG_TM2D;
|
||||
}
|
||||
|
||||
/*! \} /addtogroup */
|
||||
|
||||
|
||||
#endif // TONC_CORE
|
||||
|
|
@ -0,0 +1,573 @@
|
|||
//
|
||||
// Core functionality
|
||||
//
|
||||
//! \file tonc_core.h
|
||||
//! \author J Vijn
|
||||
//! \date 20060508 - 20080128
|
||||
//
|
||||
/* === NOTES ===
|
||||
* Contents: bits, random, dma, timer
|
||||
* 20080129,jv: added tonccpy/set routines.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef TONC_CORE_STUB
|
||||
#define TONC_CORE_STUB
|
||||
|
||||
#include "tonc_memmap.h"
|
||||
#include "tonc_memdef.h"
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// BITS and BITFIELDS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
/*! \defgroup grpCoreBit Bit(field) macros
|
||||
\ingroup grpCore
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
//! \name Simple bit macros
|
||||
//\{
|
||||
|
||||
//! Create value with bit \a n set
|
||||
#define BIT(n) ( 1<<(n) )
|
||||
|
||||
//! Shift \a a by \a n
|
||||
#define BIT_SHIFT(a, n) ( (a)<<(n) )
|
||||
|
||||
//! Create a bitmask \a len bits long
|
||||
#define BIT_MASK(len) ( BIT(len)-1 )
|
||||
|
||||
//! Set the \a flag bits in \a word
|
||||
#define BIT_SET(y, flag) ( y |= (flag) )
|
||||
|
||||
//! Clear the \a flag bits in \a word
|
||||
#define BIT_CLEAR(y, flag) ( y &= ~(flag) )
|
||||
|
||||
//! Flip the \a flag bits in \a word
|
||||
#define BIT_FLIP(y, flag) ( y ^= (flag) )
|
||||
|
||||
//! Test whether all the \a flag bits in \a word are set
|
||||
#define BIT_EQ(y, flag) ( ((y)&(flag)) == (flag) )
|
||||
|
||||
|
||||
|
||||
//! Create a bitmask of length \a len starting at bit \a shift.
|
||||
#define BF_MASK(shift, len) ( BIT_MASK(len)<<(shift) )
|
||||
|
||||
|
||||
//! Retrieve a bitfield mask of length \a starting at bit \a shift from \a y.
|
||||
#define _BF_GET(y, shift, len) ( ((y)>>(shift))&BIT_MASK(len) )
|
||||
|
||||
//! Prepare a bitmask for insertion or combining.
|
||||
#define _BF_PREP(x, shift, len) ( ((x)&BIT_MASK(len))<<(shift) )
|
||||
|
||||
//! Insert a new bitfield value \a x into \a y.
|
||||
#define _BF_SET(y, x, shift, len) \
|
||||
( y= ((y) &~ BF_MASK(shift, len)) | _BF_PREP(x, shift, len) )
|
||||
|
||||
//\}
|
||||
|
||||
|
||||
/*! \name some EVIL bit-field operations, >:)
|
||||
* These allow you to mimic bitfields with macros. Most of the
|
||||
* bitfields in the registers have <i>foo</i>_SHIFT and
|
||||
* <i>foo</i>_SHIFT macros indicating the mask and shift values
|
||||
* of the bitfield named <i>foo</i> in a variable.
|
||||
* These macros let you prepare, get and set the bitfields.
|
||||
*/
|
||||
//\{
|
||||
|
||||
//! Prepare a named bit-field for for insterion or combination.
|
||||
#define BFN_PREP(x, name) ( ((x)<<name##_SHIFT) & name##_MASK )
|
||||
|
||||
//! Get the value of a named bitfield from \a y. Equivalent to (var=) y.name
|
||||
#define BFN_GET(y, name) ( ((y) & name##_MASK)>>name##_SHIFT )
|
||||
|
||||
//! Set a named bitfield in \a y to \a x. Equivalent to y.name= x.
|
||||
#define BFN_SET(y, x, name) (y = ((y)&~name##_MASK) | BFN_PREP(x,name) )
|
||||
|
||||
//! Compare a named bitfield to named literal \a x.
|
||||
#define BFN_CMP(y, x, name) ( ((y)&name##_MASK) == (x) )
|
||||
|
||||
|
||||
//! Massage \a x for use in bitfield \a name with pre-shifted \a x
|
||||
#define BFN_PREP2(x, name) ( (x) & name##_MASK )
|
||||
|
||||
//! Get the value of bitfield \a name from \a y, but don't down-shift
|
||||
#define BFN_GET2(y, name) ( (y) & name##_MASK )
|
||||
|
||||
//! Set bitfield \a name from \a y to \a x with pre-shifted \a x
|
||||
#define BFN_SET2(y,x,name) ( y = ((y)&~name##_MASK) | BFN_PREP2(x,name) )
|
||||
|
||||
//\}
|
||||
|
||||
INLINE u32 bf_get(u32 y, uint shift, uint len);
|
||||
INLINE u32 bf_merge(u32 y, u32 x, uint shift, uint len);
|
||||
INLINE u32 bf_clamp(int x, uint len);
|
||||
|
||||
INLINE int bit_tribool(u32 x, uint plus, uint minus);
|
||||
INLINE u32 ROR(u32 x, uint ror);
|
||||
|
||||
|
||||
/*! \} */
|
||||
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
|
||||
/*! \defgroup grpData Data routines
|
||||
\ingroup grpCore
|
||||
*/
|
||||
/*! \{ */
|
||||
|
||||
//! Get the number of elements in an array
|
||||
#define countof(_array) ( sizeof(_array)/sizeof(_array[0]) )
|
||||
|
||||
//! Align \a x to the next multiple of \a width.
|
||||
INLINE uint align(uint x, uint width);
|
||||
|
||||
//! \name Copying and filling routines
|
||||
//\{
|
||||
|
||||
//! Simplified copier for GRIT-exported data.
|
||||
#define GRIT_CPY(dst, name) memcpy16(dst, name, name##Len/2)
|
||||
|
||||
|
||||
// Base memcpy/set replacements.
|
||||
void *tonccpy(void *dst, const void *src, uint size);
|
||||
|
||||
void *__toncset(void *dst, u32 fill, uint size);
|
||||
INLINE void *toncset(void *dst, u8 src, uint count);
|
||||
INLINE void *toncset16(void *dst, u16 src, uint count);
|
||||
INLINE void *toncset32(void *dst, u32 src, uint count);
|
||||
|
||||
|
||||
// Fast memcpy/set
|
||||
void memset16(void *dst, u16 hw, uint hwcount);
|
||||
void memcpy16(void *dst, const void* src, uint hwcount);
|
||||
|
||||
void memset32(void *dst, u32 wd, uint wcount);
|
||||
void memcpy32(void *dst, const void* src, uint wcount);
|
||||
|
||||
|
||||
//! Fastfill for halfwords, analogous to memset()
|
||||
/*! Uses <code>memset32()</code> if \a hwcount>5
|
||||
* \param dst Destination address.
|
||||
* \param hw Source halfword (not address).
|
||||
* \param hwcount Number of halfwords to fill.
|
||||
* \note \a dst <b>must</b> be halfword aligned.
|
||||
* \note \a r0 returns as \a dst + \a hwcount*2.
|
||||
*/
|
||||
void memset16(void *dst, u16 hw, uint hwcount);
|
||||
|
||||
//! \brief Copy for halfwords.
|
||||
/*! Uses <code>memcpy32()</code> if \a hwn>6 and
|
||||
\a src and \a dst are aligned equally.
|
||||
\param dst Destination address.
|
||||
\param src Source address.
|
||||
\param hwcount Number of halfwords to fill.
|
||||
\note \a dst and \a src <b>must</b> be halfword aligned.
|
||||
\note \a r0 and \a r1 return as
|
||||
\a dst + \a hwcount*2 and \a src + \a hwcount*2.
|
||||
*/
|
||||
void memcpy16(void *dst, const void* src, uint hwcount);
|
||||
|
||||
|
||||
//! Fast-fill by words, analogous to memset()
|
||||
/*! Like CpuFastSet(), only without the requirement of
|
||||
32byte chunks and no awkward store-value-in-memory-first issue.
|
||||
\param dst Destination address.
|
||||
\param wd Fill word (not address).
|
||||
\param wdcount Number of words to fill.
|
||||
\note \a dst <b>must</b> be word aligned.
|
||||
\note \a r0 returns as \a dst + \a wdcount*4.
|
||||
*/
|
||||
void memset32(void *dst, u32 wd, uint wdcount);
|
||||
|
||||
|
||||
//! \brief Fast-copy by words.
|
||||
/*! Like CpuFastFill(), only without the requirement of 32byte chunks
|
||||
\param dst Destination address.
|
||||
\param src Source address.
|
||||
\param wdcount Number of words.
|
||||
\note \a src and \a dst <b>must</b> be word aligned.
|
||||
\note \a r0 and \a r1 return as
|
||||
\a dst + \a wdcount*4 and \a src + \a wdcount*4.
|
||||
*/
|
||||
void memcpy32(void *dst, const void* src, uint wdcount);
|
||||
|
||||
//\}
|
||||
|
||||
|
||||
/*! \name Repeated-value creators
|
||||
These function take a hex-value and duplicate it to all fields,
|
||||
like 0x88 -> 0x88888888.
|
||||
*/
|
||||
//\{
|
||||
INLINE u16 dup8(u8 x);
|
||||
INLINE u32 dup16(u16 x);
|
||||
INLINE u32 quad8(u8 x);
|
||||
INLINE u32 octup(u8 x);
|
||||
//\}
|
||||
|
||||
//! \name Packing routines.
|
||||
//\{
|
||||
INLINE u16 bytes2hword(u8 b0, u8 b1);
|
||||
INLINE u32 bytes2word(u8 b0, u8 b1, u8 b2, u8 b3);
|
||||
INLINE u32 hword2word(u16 h0, u16 h1);
|
||||
//\}
|
||||
|
||||
/*! \} */
|
||||