├── Tube64 ├── Game │ ├── defs.h │ ├── misc.cpp │ ├── trig.cpp │ ├── tube.cpp │ ├── DSEG4.h │ ├── Type.h │ ├── misc.h │ ├── in_al_60h.c │ └── DSEG3.h ├── bin │ ├── tube64 │ ├── DSEG3.bin │ ├── DSEG4.bin │ ├── SDL2.dll │ ├── DATA │ │ ├── 3DS.BAK │ │ ├── 3DOBS.DAT │ │ ├── GLASS.DAT │ │ ├── LOGO.DAT │ │ ├── LOGO.TAB │ │ ├── TEX00.DAT │ │ ├── TEX01.DAT │ │ ├── 3DFACES.DAT │ │ ├── 3DPOINTS.DAT │ │ ├── BLOCKS.DAT │ │ ├── HISCORE.DAT │ │ ├── LEV00000.DAT │ │ ├── LEV00001.DAT │ │ ├── LEV00002.DAT │ │ ├── LEV00003.DAT │ │ ├── TABLES.DAT │ │ ├── TUNNEL.DAT │ │ ├── PAL.PAL │ │ └── JONTY.ASC │ ├── tube64.exe │ ├── SOUND │ │ ├── DRUM.BNK │ │ ├── INST.BNK │ │ ├── HMIDET.386 │ │ ├── HMIDRV.386 │ │ ├── HMIMDRV.386 │ │ ├── S822-0.DAT │ │ ├── S822-0.TAB │ │ ├── MUSICF-0.DAT │ │ └── MUSICF-0.TAB │ └── tube.cfg ├── Music │ ├── HMP.cpp │ ├── fmopl.c │ ├── fmopl.h │ ├── opl3.c │ ├── MPU401.c │ ├── dbopl.cpp │ ├── hmpfile.c │ ├── HMP.H │ ├── hmpfile.h │ ├── hmpopl.h │ ├── opl3.h │ ├── dbopl.h │ └── hmpopl.c ├── Sound │ ├── SB16.H │ └── SB16.cpp ├── tlsf │ ├── allocator.h │ ├── allocator.cpp │ ├── tlsf.h │ └── tlsf.c ├── build64-windows.bat └── build64-linux.sh ├── README.md └── LICENSE /Tube64/Game/defs.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/Game/defs.h -------------------------------------------------------------------------------- /Tube64/bin/tube64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/tube64 -------------------------------------------------------------------------------- /Tube64/Game/misc.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/Game/misc.cpp -------------------------------------------------------------------------------- /Tube64/Game/trig.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/Game/trig.cpp -------------------------------------------------------------------------------- /Tube64/Game/tube.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/Game/tube.cpp -------------------------------------------------------------------------------- /Tube64/Music/HMP.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/Music/HMP.cpp -------------------------------------------------------------------------------- /Tube64/Music/fmopl.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/Music/fmopl.c -------------------------------------------------------------------------------- /Tube64/Music/fmopl.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/Music/fmopl.h -------------------------------------------------------------------------------- /Tube64/Music/opl3.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/Music/opl3.c -------------------------------------------------------------------------------- /Tube64/Sound/SB16.H: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/Sound/SB16.H -------------------------------------------------------------------------------- /Tube64/bin/DSEG3.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/DSEG3.bin -------------------------------------------------------------------------------- /Tube64/bin/DSEG4.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/DSEG4.bin -------------------------------------------------------------------------------- /Tube64/bin/SDL2.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/SDL2.dll -------------------------------------------------------------------------------- /Tube64/Music/MPU401.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/Music/MPU401.c -------------------------------------------------------------------------------- /Tube64/Music/dbopl.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/Music/dbopl.cpp -------------------------------------------------------------------------------- /Tube64/Music/hmpfile.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/Music/hmpfile.c -------------------------------------------------------------------------------- /Tube64/Sound/SB16.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/Sound/SB16.cpp -------------------------------------------------------------------------------- /Tube64/bin/DATA/3DS.BAK: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/DATA/3DS.BAK -------------------------------------------------------------------------------- /Tube64/bin/tube64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/tube64.exe -------------------------------------------------------------------------------- /Tube64/bin/DATA/3DOBS.DAT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/DATA/3DOBS.DAT -------------------------------------------------------------------------------- /Tube64/bin/DATA/GLASS.DAT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/DATA/GLASS.DAT -------------------------------------------------------------------------------- /Tube64/bin/DATA/LOGO.DAT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/DATA/LOGO.DAT -------------------------------------------------------------------------------- /Tube64/bin/DATA/LOGO.TAB: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/DATA/LOGO.TAB -------------------------------------------------------------------------------- /Tube64/bin/DATA/TEX00.DAT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/DATA/TEX00.DAT -------------------------------------------------------------------------------- /Tube64/bin/DATA/TEX01.DAT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/DATA/TEX01.DAT -------------------------------------------------------------------------------- /Tube64/bin/SOUND/DRUM.BNK: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/SOUND/DRUM.BNK -------------------------------------------------------------------------------- /Tube64/bin/SOUND/INST.BNK: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/SOUND/INST.BNK -------------------------------------------------------------------------------- /Tube64/bin/DATA/3DFACES.DAT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/DATA/3DFACES.DAT -------------------------------------------------------------------------------- /Tube64/bin/DATA/3DPOINTS.DAT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/DATA/3DPOINTS.DAT -------------------------------------------------------------------------------- /Tube64/bin/DATA/BLOCKS.DAT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/DATA/BLOCKS.DAT -------------------------------------------------------------------------------- /Tube64/bin/DATA/HISCORE.DAT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/DATA/HISCORE.DAT -------------------------------------------------------------------------------- /Tube64/bin/DATA/LEV00000.DAT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/DATA/LEV00000.DAT -------------------------------------------------------------------------------- /Tube64/bin/DATA/LEV00001.DAT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/DATA/LEV00001.DAT -------------------------------------------------------------------------------- /Tube64/bin/DATA/LEV00002.DAT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/DATA/LEV00002.DAT -------------------------------------------------------------------------------- /Tube64/bin/DATA/LEV00003.DAT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/DATA/LEV00003.DAT -------------------------------------------------------------------------------- /Tube64/bin/DATA/TABLES.DAT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/DATA/TABLES.DAT -------------------------------------------------------------------------------- /Tube64/bin/DATA/TUNNEL.DAT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/DATA/TUNNEL.DAT -------------------------------------------------------------------------------- /Tube64/bin/SOUND/HMIDET.386: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/SOUND/HMIDET.386 -------------------------------------------------------------------------------- /Tube64/bin/SOUND/HMIDRV.386: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/SOUND/HMIDRV.386 -------------------------------------------------------------------------------- /Tube64/bin/SOUND/HMIMDRV.386: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/SOUND/HMIMDRV.386 -------------------------------------------------------------------------------- /Tube64/bin/SOUND/S822-0.DAT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/SOUND/S822-0.DAT -------------------------------------------------------------------------------- /Tube64/bin/SOUND/S822-0.TAB: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/SOUND/S822-0.TAB -------------------------------------------------------------------------------- /Tube64/bin/SOUND/MUSICF-0.DAT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rep-stosw/tube64/HEAD/Tube64/bin/SOUND/MUSICF-0.DAT -------------------------------------------------------------------------------- /Tube64/bin/SOUND/MUSICF-0.TAB: -------------------------------------------------------------------------------- 1 | TUBE.HMPZTUBE2.HMP Z -------------------------------------------------------------------------------- /Tube64/bin/tube.cfg: -------------------------------------------------------------------------------- 1 | Music (0 - MIDI, 1 - Adlib): 2 | 1 3 | 4 | MIDI IO: 5 | 0x330 6 | 7 | Adlib IO: 8 | 0x388 9 | 10 | SB16 IO: 11 | 0x220 12 | 13 | SB16 IRQ: 14 | 5 15 | 16 | SB16 HDMA: 17 | 5 18 | 19 | Screen Scale: 20 | 1 21 | 22 | -------------------------------------------------------------------------------- /Tube64/Game/DSEG4.h: -------------------------------------------------------------------------------- 1 | //Variables 2 | #define word_1A5502 (*(i16 *)(DSEG4+0x00000502)) 3 | #define word_1A5504 (*(i16 *)(DSEG4+0x00000504)) 4 | #define word_1A5506 (*(i16 *)(DSEG4+0x00000506)) 5 | #define word_1A5508 (*(i16 *)(DSEG4+0x00000508)) 6 | #define word_1A550A (*(i16 *)(DSEG4+0x0000050A)) 7 | 8 | //Arrays 9 | #define word_1A5300 ((i16 *)(DSEG4+0x00000300)) 10 | -------------------------------------------------------------------------------- /Tube64/Music/HMP.H: -------------------------------------------------------------------------------- 1 | #ifndef _HMP_H_ 2 | #define _HMP_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include "Type.h" 9 | 10 | extern u8 MusicMode; 11 | 12 | void MY_OpenMusic(unsigned int a4); 13 | void MY_FreeMusic(void); 14 | void MY_StartMusic(short a1, unsigned char a2); 15 | void MY_StopMusic(void); 16 | 17 | #ifdef __cplusplus 18 | } 19 | #endif 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /Tube64/tlsf/allocator.h: -------------------------------------------------------------------------------- 1 | #ifndef _ALLOCATOR_H_ 2 | #define _ALLOCATOR_H_ 3 | 4 | #if defined(__cplusplus) 5 | extern "C" { 6 | #endif 7 | 8 | extern char *HEAP_MEMORY; 9 | extern uintptr_t BASE64; 10 | 11 | void Allocator_Init(void); 12 | void Allocator_DeInit(void); 13 | 14 | void *Malloc(size_t size); 15 | void Free(void *ptr); 16 | void *Calloc(size_t num,size_t size); 17 | void *Realloc(void *ptr,size_t newsize); 18 | 19 | #if defined(__cplusplus) 20 | }; 21 | #endif 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /Tube64/Game/Type.h: -------------------------------------------------------------------------------- 1 | #ifndef _TYPE_H_ 2 | #define _TYPE_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #define IO volatile 9 | 10 | #define i8 char 11 | #define i16 short int 12 | #define i32 int 13 | #define i64 long long 14 | 15 | #define u8 unsigned char 16 | #define u16 unsigned short int 17 | #define u32 unsigned int 18 | #define u64 unsigned long long 19 | 20 | #define s8 signed char 21 | #define s16 signed short int 22 | #define s32 signed int 23 | #define s64 signed long long 24 | 25 | #ifdef __cplusplus 26 | } 27 | #endif 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![logo](https://user-images.githubusercontent.com/88702500/131208084-aa793cc4-2f1c-48a4-8819-586c376180df.png) 2 | 3 | ![s5_result](https://user-images.githubusercontent.com/88702500/131208173-4758d8b1-0629-48b9-a53e-1b4c90115a90.png) 4 | 5 | 64-bit version of DOS game Tube (Bullfrog, 1994) 6 | 7 | For detailed description please, see my previous repository: https://github.com/rep-stosw/tube-game-dos 8 | 9 | Releases for Windows and Linux: https://github.com/rep-stosw/tube64/tree/main/Tube64/bin 10 | 11 | Gameplay: https://www.youtube.com/watch?v=dgaLhOj14e8 12 | 13 | Play game in browser: https://clobberasm.itch.io/tube 14 | 15 | Tech discussion: https://gamedev.ru/flame/forum/?id=262348&page=8&m=5430353#m119 16 | -------------------------------------------------------------------------------- /Tube64/Game/misc.h: -------------------------------------------------------------------------------- 1 | #ifndef _LOW_LEVEL_H_ 2 | #define _LOW_LEVEL_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #include 10 | 11 | #include "Type.h" 12 | 13 | /* 14 | bit shifts left 15 | */ 16 | #define SHL6 * (1<< 6) /*<< 6*/ 17 | #define SHL8 * (1<< 8) /*<< 8*/ 18 | #define SHL16 * (1<<16) /*<< 16*/ 19 | #define OSHL8 *=(1<< 8) /*<<= 8*/ 20 | #define OSHL16 *=(1<<16) /*<<=16*/ 21 | 22 | extern uintptr_t DSEG3; 23 | extern uintptr_t DSEG4; 24 | 25 | extern char *MINIBuf; 26 | 27 | void LoadDSEG(void); 28 | void FreeDSEG(void); 29 | 30 | u32 FileSize(FILE *f); 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /Tube64/bin/DATA/PAL.PAL: -------------------------------------------------------------------------------- 1 | $""   2 |  3 | 4 |        5 |  ???:::666111,,,(((###     6 |   7 |       8 |      9 |          10 | 11 | 12 | 13 | 14 |      15 |  16 |  17 |  18 |   19 |  20 | 21 |   % +-02 5+):10<87? !$(!,"%0')3+-702;57?: $*02357$$9));..=44?::444&&&0(!  22 |       23 |  24 |  25 |   26 |  27 |   !&)*!-%0" #(-/!2& 5+ 80;5????%??2???26331./(-"+)"  28 |  29 | $ -------------------------------------------------------------------------------- /Tube64/Music/hmpfile.h: -------------------------------------------------------------------------------- 1 | #ifndef _HMPFILE_H 2 | #define _HMPFILE_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #define HMP_TRACKS 32 9 | #define HMP_BUFFERS 4 10 | #define HMP_BUFSIZE 1024 11 | 12 | typedef struct hmp_event { 13 | unsigned int delta; 14 | unsigned char msg[3]; 15 | const unsigned char *data; 16 | unsigned int datalen; 17 | int trk; 18 | } hmp_event; 19 | 20 | typedef struct hmp_track { 21 | const unsigned char *data; 22 | unsigned int len; 23 | const unsigned char *cur; 24 | unsigned int left; 25 | unsigned int cur_time; 26 | int prio; 27 | } hmp_track; 28 | 29 | typedef struct hmp_file { 30 | int num_trks; 31 | hmp_track trks[HMP_TRACKS]; 32 | unsigned int cur_time; 33 | int tempo; 34 | int loop; 35 | } hmp_file; 36 | 37 | 38 | #define HMP_INVALID_FILE -1 39 | #define HMP_OUT_OF_MEM -2 40 | #define HMP_MM_ERR -3 41 | #define HMP_EOF 1 42 | 43 | hmp_file *hmp_open(const void *data, int size, int dev, int loop); 44 | int hmp_init(hmp_file *hmp, const void *data, int size, int dev, int loop); 45 | int hmp_play(hmp_file *hmp); 46 | void hmp_close(hmp_file *hmp); 47 | void hmp_reset_tracks(struct hmp_file *hmp); 48 | int hmp_get_event(hmp_file *hmp, hmp_event *ev); 49 | 50 | #ifdef __cplusplus 51 | } 52 | #endif 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /Tube64/bin/DATA/JONTY.ASC: -------------------------------------------------------------------------------- 1 | Ambient light color: Red=0.039216 Green=0.039216 Blue=0.039216 2 | 3 | Named object: "Object01" 4 | Tri-mesh, Vertices: 6 Faces: 8 5 | Vertex list: 6 | Vertex 0: X: 81.762436 Y: 30.797184 Z: 111.148399 7 | Vertex 1: X: -69.043846 Y: 116.002716 Z: 111.148392 8 | Vertex 2: X: -219.850113 Y: 30.797176 Z: 111.148399 9 | Vertex 3: X: -69.043839 Y: -54.40836 Z: 111.148415 10 | Vertex 4: X: -69.043839 Y: 30.797203 Z: 214.370239 11 | Vertex 5: X: -69.043839 Y: 30.797171 Z: 0.000002 12 | Face list: 13 | Face 0: A:5 B:1 C:0 AB:1 BC:1 CA:1 14 | Smoothing: 1 15 | Face 1: A:5 B:2 C:1 AB:1 BC:1 CA:1 16 | Smoothing: 1 17 | Face 2: A:5 B:3 C:2 AB:1 BC:1 CA:1 18 | Smoothing: 1 19 | Face 3: A:5 B:0 C:3 AB:1 BC:1 CA:1 20 | Smoothing: 1 21 | Face 4: A:0 B:1 C:4 AB:1 BC:1 CA:1 22 | Smoothing: 1 23 | Face 5: A:1 B:2 C:4 AB:1 BC:1 CA:1 24 | Smoothing: 1 25 | Face 6: A:2 B:3 C:4 AB:1 BC:1 CA:1 26 | Smoothing: 1 27 | Face 7: A:3 B:0 C:4 AB:1 BC:1 CA:1 28 | Smoothing: 1 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | Page 1 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /Tube64/Game/in_al_60h.c: -------------------------------------------------------------------------------- 1 | /* 2 | SDL scancode to keyboard scancode 3 | */ 4 | u8 in_al_60h[41]= 5 | { 6 | /* SCANCODE_KEY_A */ 0x1E, 7 | /* SCANCODE_KEY_B */ 0x30, 8 | /* SCANCODE_KEY_C */ 0x2E, 9 | /* SCANCODE_KEY_D */ 0x20, 10 | /* SCANCODE_KEY_E */ 0x12, 11 | /* SCANCODE_KEY_F */ 0x21, 12 | /* SCANCODE_KEY_G */ 0x22, 13 | /* SCANCODE_KEY_H */ 0x23, 14 | /* SCANCODE_KEY_I */ 0x17, 15 | /* SCANCODE_KEY_J */ 0x24, 16 | /* SCANCODE_KEY_K */ 0x25, 17 | /* SCANCODE_KEY_L */ 0x26, 18 | /* SCANCODE_KEY_M */ 0x32, 19 | /* SCANCODE_KEY_N */ 0x31, 20 | /* SCANCODE_KEY_O */ 0x18, 21 | /* SCANCODE_KEY_P */ 0x19, 22 | /* SCANCODE_KEY_Q */ 0x10, 23 | /* SCANCODE_KEY_R */ 0x13, 24 | /* SCANCODE_KEY_S */ 0x1F, 25 | /* SCANCODE_KEY_T */ 0x14, 26 | /* SCANCODE_KEY_U */ 0x16, 27 | /* SCANCODE_KEY_V */ 0x2F, 28 | /* SCANCODE_KEY_W */ 0x11, 29 | /* SCANCODE_KEY_X */ 0x2D, 30 | /* SCANCODE_KEY_Y */ 0x15, 31 | /* SCANCODE_KEY_Z */ 0x2C, 32 | 33 | /* SCANCODE_KEY_1 */ 0x02, 34 | /* SCANCODE_KEY_2 */ 0x03, 35 | /* SCANCODE_KEY_3 */ 0x04, 36 | /* SCANCODE_KEY_4 */ 0x05, 37 | /* SCANCODE_KEY_5 */ 0x06, 38 | /* SCANCODE_KEY_6 */ 0x07, 39 | /* SCANCODE_KEY_7 */ 0x08, 40 | /* SCANCODE_KEY_8 */ 0x09, 41 | /* SCANCODE_KEY_9 */ 0x0A, 42 | /* SCANCODE_KEY_0 */ 0x0B, 43 | 44 | /* SCANCODE_RETURN */ 0x1C, 45 | /* SCANCODE_ESCAPE */ 0x01, 46 | /* SCANCODE_BACKSPACE */ 0x0E, 47 | /* SCANCODE_TAB */ 0x0F, 48 | /* SCANCODE_SPACE */ 0x39, 49 | }; 50 | -------------------------------------------------------------------------------- /Tube64/tlsf/allocator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "tlsf.h" 8 | 9 | #include "allocator.h" 10 | 11 | #define HEAP_MEMORY_SIZE 0x400000 /* 4 MB */ 12 | 13 | char *HEAP_MEMORY=NULL; 14 | 15 | uintptr_t BASE64; 16 | 17 | tlsf_t tlsf=NULL; 18 | 19 | void Allocator_Init(void) 20 | { 21 | #ifdef __linux__ 22 | 23 | HEAP_MEMORY=(char*)memalign(HEAP_MEMORY_SIZE,HEAP_MEMORY_SIZE); 24 | 25 | #else 26 | 27 | HEAP_MEMORY=(char*)__mingw_aligned_malloc(HEAP_MEMORY_SIZE,HEAP_MEMORY_SIZE); 28 | 29 | #endif 30 | 31 | BASE64=((uintptr_t)HEAP_MEMORY)&0xFFFFFFFF00000000; 32 | 33 | memset(HEAP_MEMORY,0,HEAP_MEMORY_SIZE); 34 | 35 | tlsf=tlsf_create_with_pool((void*)HEAP_MEMORY,HEAP_MEMORY_SIZE); 36 | } 37 | 38 | void Allocator_DeInit(void) 39 | { 40 | #ifdef __linux__ 41 | 42 | free(HEAP_MEMORY); 43 | 44 | #else 45 | 46 | __mingw_aligned_free(HEAP_MEMORY); 47 | 48 | #endif 49 | } 50 | 51 | void *Malloc(size_t size) 52 | { 53 | // printf("===> malloc\n"); 54 | if(!size) 55 | { 56 | return NULL; 57 | } 58 | 59 | return tlsf_malloc(tlsf,size); 60 | } 61 | 62 | void Free(void *ptr) 63 | { 64 | // printf("===> free\n"); 65 | if(ptr)tlsf_free(tlsf,ptr); 66 | } 67 | 68 | void *Calloc(size_t num,size_t size) 69 | { 70 | size_t ns=num*size; 71 | void *r=Malloc(ns); 72 | if(r)memset(r,0,ns); 73 | return r; 74 | } 75 | 76 | void *Realloc(void *ptr,size_t newsize) 77 | { 78 | return tlsf_realloc(tlsf,ptr,newsize); 79 | } 80 | 81 | -------------------------------------------------------------------------------- /Tube64/Music/hmpopl.h: -------------------------------------------------------------------------------- 1 | #ifndef HMPOPL_H_ 2 | #define HMPOPL_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | typedef void (*hmpopl_write_callback)(/*void *data,*/ int index, int reg, int val); 10 | 11 | struct oplins { 12 | uint8_t op0_freq; 13 | uint8_t op0_vol; 14 | uint8_t op0_attdec; 15 | uint8_t op0_sustrel; 16 | uint8_t chfb; 17 | uint8_t op1_freq; 18 | uint8_t op1_vol; 19 | uint8_t op1_attdec; 20 | uint8_t op1_sustrel; 21 | uint8_t flags; 22 | uint8_t op0_ws; 23 | uint8_t op1_ws; 24 | }; 25 | 26 | struct hmpopl { 27 | hmpopl_write_callback write; 28 | // void *write_data; 29 | struct oplins melodic[128]; 30 | struct oplins drum[128]; 31 | 32 | int v_velo[9]; 33 | int v_ch[9]; 34 | int v_note[9]; 35 | 36 | int op_basevol[32]; 37 | int op_sustrel[32]; 38 | 39 | int ch_pan[16]; 40 | int ch_vol[16]; 41 | int ch_prog[16]; 42 | int ch_sust[16]; 43 | int ch_pitch[16]; 44 | int ch_pitched[16]; 45 | int ch_pitchrng[16]; 46 | int ch_sust_idx[16]; 47 | 48 | uint8_t ch_sustnotes[16][32]; 49 | 50 | uint8_t oplreg_key[9]; 51 | uint8_t oplreg_fnum[9]; 52 | }; 53 | 54 | typedef struct hmpopl hmpopl; 55 | hmpopl *hmpopl_new(); 56 | void hmpopl_done(hmpopl *h); 57 | int hmpopl_set_bank(hmpopl *h, const void *data, int size, int isdrum); 58 | //void hmpopl_set_song(hmpopl *h, const void *data, int size); 59 | void hmpopl_set_write_callback(hmpopl *h, hmpopl_write_callback c/*, void *data*/); 60 | void hmpopl_play_midi(hmpopl *h, int event, int ch, int param1, int param2); 61 | void hmpopl_start(hmpopl *h); 62 | void hmpopl_reset(hmpopl *h); 63 | 64 | #ifdef __cplusplus 65 | } 66 | #endif 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /Tube64/tlsf/tlsf.h: -------------------------------------------------------------------------------- 1 | #ifndef INCLUDED_tlsf 2 | #define INCLUDED_tlsf 3 | 4 | /* 5 | ** Two Level Segregated Fit memory allocator, version 3.1. 6 | ** Written by Matthew Conte 7 | ** http://tlsf.baisoku.org 8 | ** 9 | ** Based on the original documentation by Miguel Masmano: 10 | ** http://www.gii.upv.es/tlsf/main/docs 11 | ** 12 | ** This implementation was written to the specification 13 | ** of the document, therefore no GPL restrictions apply. 14 | ** 15 | ** Copyright (c) 2006-2016, Matthew Conte 16 | ** All rights reserved. 17 | ** 18 | ** Redistribution and use in source and binary forms, with or without 19 | ** modification, are permitted provided that the following conditions are met: 20 | ** * Redistributions of source code must retain the above copyright 21 | ** notice, this list of conditions and the following disclaimer. 22 | ** * Redistributions in binary form must reproduce the above copyright 23 | ** notice, this list of conditions and the following disclaimer in the 24 | ** documentation and/or other materials provided with the distribution. 25 | ** * Neither the name of the copyright holder nor the 26 | ** names of its contributors may be used to endorse or promote products 27 | ** derived from this software without specific prior written permission. 28 | ** 29 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 30 | ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 31 | ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 32 | ** DISCLAIMED. IN NO EVENT SHALL MATTHEW CONTE BE LIABLE FOR ANY 33 | ** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 34 | ** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 35 | ** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 36 | ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | */ 40 | 41 | #include 42 | 43 | #if defined(__cplusplus) 44 | extern "C" { 45 | #endif 46 | 47 | /* tlsf_t: a TLSF structure. Can contain 1 to N pools. */ 48 | /* pool_t: a block of memory that TLSF can manage. */ 49 | typedef void* tlsf_t; 50 | typedef void* pool_t; 51 | 52 | /* Create/destroy a memory pool. */ 53 | tlsf_t tlsf_create(void* mem); 54 | tlsf_t tlsf_create_with_pool(void* mem, size_t bytes); 55 | void tlsf_destroy(tlsf_t tlsf); 56 | pool_t tlsf_get_pool(tlsf_t tlsf); 57 | 58 | /* Add/remove memory pools. */ 59 | pool_t tlsf_add_pool(tlsf_t tlsf, void* mem, size_t bytes); 60 | void tlsf_remove_pool(tlsf_t tlsf, pool_t pool); 61 | 62 | /* malloc/memalign/realloc/free replacements. */ 63 | void* tlsf_malloc(tlsf_t tlsf, size_t bytes); 64 | void* tlsf_memalign(tlsf_t tlsf, size_t align, size_t bytes); 65 | void* tlsf_realloc(tlsf_t tlsf, void* ptr, size_t size); 66 | void tlsf_free(tlsf_t tlsf, void* ptr); 67 | 68 | /* Returns internal block size, not original request size */ 69 | size_t tlsf_block_size(void* ptr); 70 | 71 | /* Overheads/limits of internal structures. */ 72 | size_t tlsf_size(void); 73 | size_t tlsf_align_size(void); 74 | size_t tlsf_block_size_min(void); 75 | size_t tlsf_block_size_max(void); 76 | size_t tlsf_pool_overhead(void); 77 | size_t tlsf_alloc_overhead(void); 78 | 79 | /* Debugging. */ 80 | typedef void (*tlsf_walker)(void* ptr, size_t size, int used, void* user); 81 | void tlsf_walk_pool(pool_t pool, tlsf_walker walker, void* user); 82 | /* Returns nonzero if any internal consistency check fails. */ 83 | int tlsf_check(tlsf_t tlsf); 84 | int tlsf_check_pool(pool_t pool); 85 | 86 | #if defined(__cplusplus) 87 | }; 88 | #endif 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /Tube64/build64-windows.bat: -------------------------------------------------------------------------------- 1 | @echo Clear... 2 | 3 | del bin\tube64.exe 4 | del *.o 5 | del *.map 6 | cls 7 | 8 | :COMPILE 9 | 10 | @echo Compile... 11 | 12 | g++ -m64 -Ofast -DNDEBUG -ffunction-sections -fdata-sections -fno-rtti -ftree-vectorize -fno-math-errno -fmax-errors=1 -fomit-frame-pointer -ffast-math -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -Wall -Wno-unused-variable -Wno-unused-but-set-variable -Wno-parentheses -Wno-maybe-uninitialized -Wno-unused-result -Wno-format-security -c Game/tube.cpp -IGame -IMusic -ISound -Itlsf -fsigned-char 13 | g++ -m64 -Ofast -DNDEBUG -ffunction-sections -fdata-sections -fno-rtti -ftree-vectorize -fno-math-errno -fmax-errors=1 -fomit-frame-pointer -ffast-math -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -Wall -Wno-unused-variable -Wno-unused-but-set-variable -Wno-parentheses -Wno-maybe-uninitialized -Wno-unused-result -c Game/trig.cpp -IGame -IMusic -ISound -Itlsf 14 | g++ -m64 -Ofast -DNDEBUG -ffunction-sections -fdata-sections -fno-rtti -ftree-vectorize -fno-math-errno -fmax-errors=1 -fomit-frame-pointer -ffast-math -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -Wall -Wno-unused-variable -Wno-unused-but-set-variable -Wno-parentheses -Wno-maybe-uninitialized -Wno-unused-result -c Game/misc.cpp -IGame -IMusic -ISound -Itlsf 15 | 16 | g++ -m64 -Ofast -DNDEBUG -ffunction-sections -fdata-sections -fno-rtti -ftree-vectorize -fno-math-errno -fmax-errors=1 -fomit-frame-pointer -ffast-math -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -Wall -Wno-unused-variable -Wno-unused-but-set-variable -Wno-parentheses -Wno-maybe-uninitialized -Wno-unused-result -D_OPL3_ -c Music/HMP.cpp -IGame -IMusic -ISound -Itlsf 17 | g++ -m64 -Ofast -DNDEBUG -ffunction-sections -fdata-sections -fno-rtti -ftree-vectorize -fno-math-errno -fmax-errors=1 -fomit-frame-pointer -ffast-math -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -Wall -Wno-unused-variable -Wno-unused-but-set-variable -Wno-parentheses -Wno-maybe-uninitialized -Wno-unused-result -D_OPL3_ -c Sound/SB16.cpp -IGame -IMusic -ISound -Itlsf 18 | 19 | gcc -m64 -Ofast -DNDEBUG -ffunction-sections -fdata-sections -ftree-vectorize -fno-math-errno -fmax-errors=1 -fomit-frame-pointer -ffast-math -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -Wall -Wno-unused-variable -Wno-unused-but-set-variable -Wno-parentheses -Wno-maybe-uninitialized -Wno-unused-result -c Music/hmpfile.c -IGame -IMusic -ISound -Itlsf 20 | gcc -m64 -Ofast -DNDEBUG -ffunction-sections -fdata-sections -ftree-vectorize -fno-math-errno -fmax-errors=1 -fomit-frame-pointer -ffast-math -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -Wall -Wno-unused-variable -Wno-unused-but-set-variable -Wno-parentheses -Wno-maybe-uninitialized -Wno-unused-result -c Music/hmpopl.c -IGame -IMusic -ISound -Itlsf 21 | gcc -m64 -Ofast -DNDEBUG -ffunction-sections -fdata-sections -ftree-vectorize -fno-math-errno -fmax-errors=1 -fomit-frame-pointer -ffast-math -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -Wall -Wno-unused-variable -Wno-unused-but-set-variable -Wno-parentheses -Wno-maybe-uninitialized -Wno-unused-result -c Music/opl3.c -o opl.o -IGame -IMusic -ISound -Itlsf 22 | 23 | gcc -m64 -Ofast -DNDEBUG -ffunction-sections -fdata-sections -ftree-vectorize -fno-math-errno -fmax-errors=1 -fomit-frame-pointer -ffast-math -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -Wall -Wno-unused-variable -Wno-unused-but-set-variable -Wno-parentheses -Wno-maybe-uninitialized -Wno-unused-result -c tlsf/tlsf.c 24 | g++ -m64 -Ofast -DNDEBUG -ffunction-sections -fdata-sections -fno-rtti -ftree-vectorize -fno-math-errno -fmax-errors=1 -fomit-frame-pointer -ffast-math -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -Wall -Wno-unused-variable -Wno-unused-but-set-variable -Wno-parentheses -Wno-maybe-uninitialized -Wno-unused-result -c tlsf/allocator.cpp 25 | 26 | :LINK 27 | 28 | @echo Link... 29 | 30 | g++ -m64 -Ofast -DNDEBUG -o bin/tube64.exe tube.o trig.o misc.o opl.o hmpopl.o hmpfile.o HMP.o SB16.o tlsf.o allocator.o -static-libstdc++ -static-libgcc -lmingw32 -lSDL2main -lSDL2 -lwinmm -mwindows -Xlinker -Map=tube.map -Wl,--strip-all -Wl,--gc-sections 31 | 32 | pause 33 | exit 34 | -------------------------------------------------------------------------------- /Tube64/build64-linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | clear 4 | 5 | #if false; then 6 | 7 | rm -f *.o 8 | rm -f *.map 9 | rm -f bin/tube64 10 | 11 | #echo 'Press any key...' 12 | #read -rsn1 13 | 14 | echo 'Compile tube...' 15 | g++ -m64 -Ofast -DNDEBUG -ffunction-sections -fdata-sections -fno-rtti -ftree-vectorize -fno-math-errno -fmax-errors=1 -fomit-frame-pointer -ffast-math -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -Wall -Wno-unused-variable -Wno-unused-but-set-variable -Wno-parentheses -Wno-maybe-uninitialized -Wno-unused-result -Wno-format-security -c Game/tube.cpp -IGame -IMusic -ISound -Itlsf -fsigned-char 16 | g++ -m64 -Ofast -DNDEBUG -ffunction-sections -fdata-sections -fno-rtti -ftree-vectorize -fno-math-errno -fmax-errors=1 -fomit-frame-pointer -ffast-math -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -Wall -Wno-unused-variable -Wno-unused-but-set-variable -Wno-parentheses -Wno-maybe-uninitialized -Wno-unused-result -c Game/trig.cpp -IGame -IMusic -ISound -Itlsf 17 | g++ -m64 -Ofast -DNDEBUG -ffunction-sections -fdata-sections -fno-rtti -ftree-vectorize -fno-math-errno -fmax-errors=1 -fomit-frame-pointer -ffast-math -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -Wall -Wno-unused-variable -Wno-unused-but-set-variable -Wno-parentheses -Wno-maybe-uninitialized -Wno-unused-result -c Game/misc.cpp -IGame -IMusic -ISound -Itlsf 18 | 19 | g++ -m64 -Ofast -DNDEBUG -ffunction-sections -fdata-sections -fno-rtti -ftree-vectorize -fno-math-errno -fmax-errors=1 -fomit-frame-pointer -ffast-math -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -Wall -Wno-unused-variable -Wno-unused-but-set-variable -Wno-parentheses -Wno-maybe-uninitialized -Wno-unused-result -D_OPL3_ -c Music/HMP.cpp -IGame -IMusic -ISound -Itlsf 20 | g++ -m64 -Ofast -DNDEBUG -ffunction-sections -fdata-sections -fno-rtti -ftree-vectorize -fno-math-errno -fmax-errors=1 -fomit-frame-pointer -ffast-math -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -Wall -Wno-unused-variable -Wno-unused-but-set-variable -Wno-parentheses -Wno-maybe-uninitialized -Wno-unused-result -D_OPL3_ -c Sound/SB16.cpp -IGame -IMusic -ISound -Itlsf 21 | 22 | gcc -m64 -Ofast -DNDEBUG -ffunction-sections -fdata-sections -ftree-vectorize -fno-math-errno -fmax-errors=1 -fomit-frame-pointer -ffast-math -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -Wall -Wno-unused-variable -Wno-unused-but-set-variable -Wno-parentheses -Wno-maybe-uninitialized -Wno-unused-result -c Music/hmpfile.c -IGame -IMusic -ISound -Itlsf 23 | gcc -m64 -Ofast -DNDEBUG -ffunction-sections -fdata-sections -ftree-vectorize -fno-math-errno -fmax-errors=1 -fomit-frame-pointer -ffast-math -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -Wall -Wno-unused-variable -Wno-unused-but-set-variable -Wno-parentheses -Wno-maybe-uninitialized -Wno-unused-result -c Music/hmpopl.c -IGame -IMusic -ISound -Itlsf 24 | gcc -m64 -Ofast -DNDEBUG -ffunction-sections -fdata-sections -ftree-vectorize -fno-math-errno -fmax-errors=1 -fomit-frame-pointer -ffast-math -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -Wall -Wno-unused-variable -Wno-unused-but-set-variable -Wno-parentheses -Wno-maybe-uninitialized -Wno-unused-result -c Music/opl3.c -o opl.o -IGame -IMusic -ISound -Itlsf 25 | 26 | gcc -m64 -Ofast -DNDEBUG -ffunction-sections -fdata-sections -ftree-vectorize -fno-math-errno -fmax-errors=1 -fomit-frame-pointer -ffast-math -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -Wall -Wno-unused-variable -Wno-unused-but-set-variable -Wno-parentheses -Wno-maybe-uninitialized -Wno-unused-result -c tlsf/tlsf.c 27 | g++ -m64 -Ofast -DNDEBUG -ffunction-sections -fdata-sections -fno-rtti -ftree-vectorize -fno-math-errno -fmax-errors=1 -fomit-frame-pointer -ffast-math -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -Wall -Wno-unused-variable -Wno-unused-but-set-variable -Wno-parentheses -Wno-maybe-uninitialized -Wno-unused-result -c tlsf/allocator.cpp 28 | 29 | #fi 30 | 31 | echo 'Link tube...' 32 | g++ -m64 -Ofast -DNDEBUG -o bin/tube64 tube.o trig.o misc.o opl.o hmpopl.o hmpfile.o HMP.o SB16.o tlsf.o allocator.o -static-libstdc++ -static-libgcc -lSDL2 -lasound -Xlinker -Map=tube.map -Wl,--strip-all -Wl,--gc-sections 33 | 34 | chmod +x bin/tube64 35 | 36 | -------------------------------------------------------------------------------- /Tube64/Music/opl3.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2013-2018 Alexey Khokholov (Nuke.YKT) 3 | // 4 | // This program is free software; you can redistribute it and/or 5 | // modify it under the terms of the GNU General Public License 6 | // as published by the Free Software Foundation; either version 2 7 | // of the License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // 15 | // Nuked OPL3 emulator. 16 | // Thanks: 17 | // MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh): 18 | // Feedback and Rhythm part calculation information. 19 | // forums.submarine.org.uk(carbon14, opl3): 20 | // Tremolo and phase generator calculation information. 21 | // OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): 22 | // OPL2 ROMs. 23 | // siliconpr0n.org(John McMaster, digshadow): 24 | // YMF262 and VRC VII decaps and die shots. 25 | // 26 | // version: 1.8 27 | // 28 | 29 | #ifndef OPL_OPL3_H 30 | #define OPL_OPL3_H 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | #include 37 | 38 | #define OPL_WRITEBUF_SIZE 1024 39 | #define OPL_WRITEBUF_DELAY 2 40 | 41 | typedef uintptr_t Bitu; 42 | typedef intptr_t Bits; 43 | typedef uint64_t Bit64u; 44 | typedef int64_t Bit64s; 45 | typedef uint32_t Bit32u; 46 | typedef int32_t Bit32s; 47 | typedef uint16_t Bit16u; 48 | typedef int16_t Bit16s; 49 | typedef uint8_t Bit8u; 50 | typedef int8_t Bit8s; 51 | 52 | typedef struct _opl3_slot opl3_slot; 53 | typedef struct _opl3_channel opl3_channel; 54 | typedef struct _opl3_chip opl3_chip; 55 | 56 | struct _opl3_slot { 57 | opl3_channel *channel; 58 | opl3_chip *chip; 59 | Bit16s out; 60 | Bit16s fbmod; 61 | Bit16s *mod; 62 | Bit16s prout; 63 | Bit16s eg_rout; 64 | Bit16s eg_out; 65 | Bit8u eg_inc; 66 | Bit8u eg_gen; 67 | Bit8u eg_rate; 68 | Bit8u eg_ksl; 69 | Bit8u *trem; 70 | Bit8u reg_vib; 71 | Bit8u reg_type; 72 | Bit8u reg_ksr; 73 | Bit8u reg_mult; 74 | Bit8u reg_ksl; 75 | Bit8u reg_tl; 76 | Bit8u reg_ar; 77 | Bit8u reg_dr; 78 | Bit8u reg_sl; 79 | Bit8u reg_rr; 80 | Bit8u reg_wf; 81 | Bit8u key; 82 | Bit32u pg_reset; 83 | Bit32u pg_phase; 84 | Bit16u pg_phase_out; 85 | Bit8u slot_num; 86 | }; 87 | 88 | struct _opl3_channel { 89 | opl3_slot *slots[2]; 90 | opl3_channel *pair; 91 | opl3_chip *chip; 92 | Bit16s *out[4]; 93 | Bit8u chtype; 94 | Bit16u f_num; 95 | Bit8u block; 96 | Bit8u fb; 97 | Bit8u con; 98 | Bit8u alg; 99 | Bit8u ksv; 100 | Bit16u cha, chb; 101 | Bit8u ch_num; 102 | }; 103 | 104 | typedef struct _opl3_writebuf { 105 | Bit64u time; 106 | Bit16u reg; 107 | Bit8u data; 108 | } opl3_writebuf; 109 | 110 | struct _opl3_chip { 111 | opl3_channel channel[18]; 112 | opl3_slot slot[36]; 113 | Bit16u timer; 114 | Bit64u eg_timer; 115 | Bit8u eg_timerrem; 116 | Bit8u eg_state; 117 | Bit8u eg_add; 118 | Bit8u newm; 119 | Bit8u nts; 120 | Bit8u rhy; 121 | Bit8u vibpos; 122 | Bit8u vibshift; 123 | Bit8u tremolo; 124 | Bit8u tremolopos; 125 | Bit8u tremoloshift; 126 | Bit32u noise; 127 | Bit16s zeromod; 128 | Bit32s mixbuff[2]; 129 | Bit8u rm_hh_bit2; 130 | Bit8u rm_hh_bit3; 131 | Bit8u rm_hh_bit7; 132 | Bit8u rm_hh_bit8; 133 | Bit8u rm_tc_bit3; 134 | Bit8u rm_tc_bit5; 135 | //OPL3L 136 | Bit32s rateratio; 137 | Bit32s samplecnt; 138 | Bit16s oldsamples[2]; 139 | Bit16s samples[2]; 140 | 141 | Bit64u writebuf_samplecnt; 142 | Bit32u writebuf_cur; 143 | Bit32u writebuf_last; 144 | Bit64u writebuf_lasttime; 145 | opl3_writebuf writebuf[OPL_WRITEBUF_SIZE]; 146 | }; 147 | 148 | void OPL3_Generate(opl3_chip *chip, Bit16s *buf); 149 | void OPL3_GenerateResampled(opl3_chip *chip, /*Bit16s*/ signed int *buf); 150 | void OPL3_Reset(opl3_chip *chip, Bit32u samplerate); 151 | void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v); 152 | void OPL3_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v); 153 | void OPL3_GenerateStream(opl3_chip *chip, /*Bit16s*/ signed int *sndptr, Bit32u numsamples); 154 | 155 | #ifdef __cplusplus 156 | } 157 | #endif 158 | 159 | #endif 160 | -------------------------------------------------------------------------------- /Tube64/Music/dbopl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2002-2010 The DOSBox Team 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 | */ 18 | #undef RELEASE 19 | 20 | /* BEGIN MIDIPLAY GLUE */ 21 | #include 22 | typedef unsigned long Bitu; 23 | typedef signed long Bits; 24 | typedef unsigned Bit32u; 25 | typedef int Bit32s; 26 | typedef unsigned short Bit16u; 27 | typedef signed short Bit16s; 28 | typedef unsigned char Bit8u; 29 | typedef signed char Bit8s; 30 | #define INLINE inline 31 | #define GCC_UNLIKELY(x) __builtin_expect((x),0) 32 | #define GCC_LIKELY(x) __builtin_expect((x),1) 33 | /* END MIDIPLAY GLUE */ 34 | 35 | //Use 8 handlers based on a small logatirmic wavetabe and an exponential table for volume 36 | #define WAVE_HANDLER 10 37 | //Use a logarithmic wavetable with an exponential table for volume 38 | #define WAVE_TABLELOG 11 39 | //Use a linear wavetable with a multiply table for volume 40 | #define WAVE_TABLEMUL 12 41 | 42 | //Select the type of wave generator routine 43 | #define DBOPL_WAVE WAVE_TABLEMUL 44 | 45 | namespace DBOPL { 46 | 47 | struct Chip; 48 | struct Operator; 49 | struct Channel; 50 | 51 | #if (DBOPL_WAVE == WAVE_HANDLER) 52 | typedef Bits ( DB_FASTCALL *WaveHandler) ( Bitu i, Bitu volume ); 53 | #endif 54 | 55 | typedef Bits ( DBOPL::Operator::*VolumeHandler) ( ); 56 | typedef Channel* ( DBOPL::Channel::*SynthHandler) ( Chip* chip, Bit32u samples, Bit32s* output ); 57 | 58 | //Different synth modes that can generate blocks of data 59 | typedef enum { 60 | sm2AM, 61 | sm2FM, 62 | sm3AM, 63 | sm3FM, 64 | sm4Start, 65 | sm3FMFM, 66 | sm3AMFM, 67 | sm3FMAM, 68 | sm3AMAM, 69 | sm6Start, 70 | sm2Percussion, 71 | sm3Percussion, 72 | } SynthMode; 73 | 74 | //Shifts for the values contained in chandata variable 75 | enum { 76 | SHIFT_KSLBASE = 16, 77 | SHIFT_KEYCODE = 24, 78 | }; 79 | 80 | struct Operator { 81 | public: 82 | //Masks for operator 20 values 83 | enum { 84 | MASK_KSR = 0x10, 85 | MASK_SUSTAIN = 0x20, 86 | MASK_VIBRATO = 0x40, 87 | MASK_TREMOLO = 0x80, 88 | }; 89 | 90 | typedef enum { 91 | OFF, 92 | RELEASE, 93 | SUSTAIN, 94 | DECAY, 95 | ATTACK, 96 | } State; 97 | 98 | VolumeHandler volHandler; 99 | 100 | #if (DBOPL_WAVE == WAVE_HANDLER) 101 | WaveHandler waveHandler; //Routine that generate a wave 102 | #else 103 | Bit16s* waveBase; 104 | Bit32u waveMask; 105 | Bit32u waveStart; 106 | #endif 107 | Bit32u waveIndex; //WAVE_BITS shifted counter of the frequency index 108 | Bit32u waveAdd; //The base frequency without vibrato 109 | Bit32u waveCurrent; //waveAdd + vibratao 110 | 111 | Bit32u chanData; //Frequency/octave and derived data coming from whatever channel controls this 112 | Bit32u freqMul; //Scale channel frequency with this, TODO maybe remove? 113 | Bit32u vibrato; //Scaled up vibrato strength 114 | Bit32s sustainLevel; //When stopping at sustain level stop here 115 | Bit32s totalLevel; //totalLevel is added to every generated volume 116 | Bit32u currentLevel; //totalLevel + tremolo 117 | Bit32s volume; //The currently active volume 118 | 119 | Bit32u attackAdd; //Timers for the different states of the envelope 120 | Bit32u decayAdd; 121 | Bit32u releaseAdd; 122 | Bit32u rateIndex; //Current position of the evenlope 123 | 124 | Bit8u rateZero; //Bits for the different states of the envelope having no changes 125 | Bit8u keyOn; //Bitmask of different values that can generate keyon 126 | //Registers, also used to check for changes 127 | Bit8u reg20, reg40, reg60, reg80, regE0; 128 | //Active part of the envelope we're in 129 | Bit8u state; 130 | //0xff when tremolo is enabled 131 | Bit8u tremoloMask; 132 | //Strength of the vibrato 133 | Bit8u vibStrength; 134 | //Keep track of the calculated KSR so we can check for changes 135 | Bit8u ksr; 136 | private: 137 | void SetState( Bit8u s ); 138 | void UpdateAttack( const Chip* chip ); 139 | void UpdateRelease( const Chip* chip ); 140 | void UpdateDecay( const Chip* chip ); 141 | public: 142 | void UpdateAttenuation(); 143 | void UpdateRates( const Chip* chip ); 144 | void UpdateFrequency( ); 145 | 146 | void Write20( const Chip* chip, Bit8u val ); 147 | void Write40( const Chip* chip, Bit8u val ); 148 | void Write60( const Chip* chip, Bit8u val ); 149 | void Write80( const Chip* chip, Bit8u val ); 150 | void WriteE0( const Chip* chip, Bit8u val ); 151 | 152 | bool Silent() const; 153 | void Prepare( const Chip* chip ); 154 | 155 | void KeyOn( Bit8u mask); 156 | void KeyOff( Bit8u mask); 157 | 158 | template< State state> 159 | Bits TemplateVolume( ); 160 | 161 | Bit32s RateForward( Bit32u add ); 162 | Bitu ForwardWave(); 163 | Bitu ForwardVolume(); 164 | 165 | Bits GetSample( Bits modulation ); 166 | Bits GetWave( Bitu index, Bitu vol ); 167 | public: 168 | Operator(); 169 | }; 170 | 171 | struct Channel { 172 | Operator op[2]; 173 | inline Operator* Op( Bitu index ) { 174 | return &( ( this + (index >> 1) )->op[ index & 1 ]); 175 | } 176 | SynthHandler synthHandler; 177 | Bit32u chanData; //Frequency/octave and derived values 178 | Bit32s old[2]; //Old data for feedback 179 | 180 | Bit8u feedback; //Feedback shift 181 | Bit8u regB0; //Register values to check for changes 182 | Bit8u regC0; 183 | //This should correspond with reg104, bit 6 indicates a Percussion channel, bit 7 indicates a silent channel 184 | Bit8u fourMask; 185 | Bit8s maskLeft; //Sign extended values for both channel's panning 186 | Bit8s maskRight; 187 | 188 | //Forward the channel data to the operators of the channel 189 | void SetChanData( const Chip* chip, Bit32u data ); 190 | //Change in the chandata, check for new values and if we have to forward to operators 191 | void UpdateFrequency( const Chip* chip, Bit8u fourOp ); 192 | void WriteA0( const Chip* chip, Bit8u val ); 193 | void WriteB0( const Chip* chip, Bit8u val ); 194 | void WriteC0( const Chip* chip, Bit8u val ); 195 | void ResetC0( const Chip* chip ); 196 | 197 | //call this for the first channel 198 | template< bool opl3Mode > 199 | void GeneratePercussion( Chip* chip, Bit32s* output ); 200 | 201 | //Generate blocks of data in specific modes 202 | template 203 | Channel* BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output ); 204 | Channel(); 205 | }; 206 | 207 | struct Chip { 208 | //This is used as the base counter for vibrato and tremolo 209 | Bit32u lfoCounter; 210 | Bit32u lfoAdd; 211 | 212 | 213 | Bit32u noiseCounter; 214 | Bit32u noiseAdd; 215 | Bit32u noiseValue; 216 | 217 | //Frequency scales for the different multiplications 218 | Bit32u freqMul[16]; 219 | //Rates for decay and release for rate of this chip 220 | Bit32u linearRates[76]; 221 | //Best match attack rates for the rate of this chip 222 | Bit32u attackRates[76]; 223 | 224 | //18 channels with 2 operators each 225 | Channel chan[18]; 226 | 227 | Bit8u reg104; 228 | Bit8u reg08; 229 | Bit8u reg04; 230 | Bit8u regBD; 231 | Bit8u vibratoIndex; 232 | Bit8u tremoloIndex; 233 | Bit8s vibratoSign; 234 | Bit8u vibratoShift; 235 | Bit8u tremoloValue; 236 | Bit8u vibratoStrength; 237 | Bit8u tremoloStrength; 238 | //Mask for allowed wave forms 239 | Bit8u waveFormMask; 240 | //0 or -1 when enabled 241 | Bit8s opl3Active; 242 | 243 | //Return the maximum amount of samples before and LFO change 244 | Bit32u ForwardLFO( Bit32u samples ); 245 | Bit32u ForwardNoise(); 246 | 247 | void WriteBD( Bit8u val ); 248 | void WriteReg(Bit32u reg, Bit8u val ); 249 | 250 | Bit32u WriteAddr( Bit32u port, Bit8u val ); 251 | 252 | void GenerateBlock2( Bitu samples, Bit32s* output ); 253 | void GenerateBlock3( Bitu samples, Bit32s* output ); 254 | 255 | void Generate( Bit32u samples ); 256 | void Setup( Bit32u r ); 257 | 258 | Chip(); 259 | }; 260 | 261 | struct Handler { 262 | DBOPL::Chip chip; 263 | Bit32u WriteAddr( Bit32u port, Bit8u val ); 264 | void WriteReg( Bit32u addr, Bit8u val ); 265 | void Generate( void(*AddSamples_m32)(Bitu,Bit32s*), 266 | void(*AddSamples_s32)(Bitu,Bit32s*), 267 | Bitu samples ); 268 | void Init( Bitu rate ); 269 | }; 270 | 271 | 272 | }; //Namespace 273 | -------------------------------------------------------------------------------- /Tube64/Game/DSEG3.h: -------------------------------------------------------------------------------- 1 | //Variables 2 | #define unk_2B3E5E (*(UA*)(DSEG3+0x00094E5E)) 3 | #define byte_2B37FA (*(char *)(DSEG3+0x000947FA)) 4 | #define IInkey (*(char *)(DSEG3+0x00094ECD)) 5 | #define oinkey (*(char *)(DSEG3+0x00094ECC)) 6 | #define hiscore_lookup (*(char *)(DSEG3+0x00000976)) 7 | #define on_anims (*(char *)(DSEG3+0x000154B8)) 8 | #define word_21F94A (*(i16 *)(DSEG3+0x0000094A)) 9 | #define no_players (*(char *)(DSEG3+0x0000094C)) 10 | #define temp_no_players (*(char *)(DSEG3+0x0000094D)) 11 | #define game_mode (*(char *)(DSEG3+0x0000094F)) 12 | #define level_no (*(char *)(DSEG3+0x00000950)) 13 | #define hiscore_ticks (*(signed char *)(DSEG3+0x00000951)) 14 | #define fading (*(char *)(DSEG3+0x00000952)) 15 | #define ascii (*(char *)(DSEG3+0x00000953)) 16 | #define bodge (*(char *)(DSEG3+0x00000954)) 17 | #define cheat_on (*(char *)(DSEG3+0x00000955)) 18 | #define game_pause (*(char *)(DSEG3+0x00000956)) 19 | #define level_start (*(char *)(DSEG3+0x00000957)) 20 | #define quit_game (*(char *)(DSEG3+0x00000959)) 21 | #define file_error (*(char *)(DSEG3+0x0000095B)) 22 | #define race_finished (*(char *)(DSEG3+0x0000095C)) 23 | #define bonus_game (*(char *)(DSEG3+0x0000095D)) 24 | #define byte_220A58 (*(char *)(DSEG3+0x00001A58)) 25 | #define byte_220C44 (*(char *)(DSEG3+0x00001C44)) 26 | #define word_220C4A (*(i16 *)(DSEG3+0x00001C4A)) 27 | #define dword_220C4C (*(int *)(DSEG3+0x00001C4C)) 28 | #define vec_screen (*(int *)(DSEG3+0x00001C50)) 29 | #define vec_map (*(int *)(DSEG3+0x00001C54)) 30 | #define vec_screen_width (*(int *)(DSEG3+0x00001C58)) 31 | #define vec_window_width (*(int *)(DSEG3+0x00001C5C)) 32 | #define vec_window_height (*(int *)(DSEG3+0x00001C60)) 33 | #define vec_colour (*(char *)(DSEG3+0x00004964)) 34 | #define vec_mode (*(char *)(DSEG3+0x00004965)) 35 | #define dword_226168 (*(int *)(DSEG3+0x00007168)) 36 | #define dword_22616C (*(int *)(DSEG3+0x0000716C)) 37 | #define KeyboardInstalled (*(char *)(DSEG3+0x00007180)) 38 | #define GlassMap (*(int *)(DSEG3+0x000071F4)) 39 | #define fade_started (*(char *)(DSEG3+0x000071F8)) 40 | #define DrawFlags (*(i16 *)(DSEG3+0x000071FC)) 41 | #define Network (*(int *)(DSEG3+0x00007284)) 42 | #define dword_22628C (*(int *)(DSEG3+0x0000728C)) 43 | #define dword_226290 (*(int *)(DSEG3+0x00007290)) 44 | #define dword_226294 (*(int *)(DSEG3+0x00007294)) 45 | #define SoundAble (*(char *)(DSEG3+0x000076B0)) 46 | #define SoundActive (*(char *)(DSEG3+0x000076B1)) 47 | #define MusicAble (*(char *)(DSEG3+0x00007999)) 48 | #define MusicActive (*(char *)(DSEG3+0x0000799A)) 49 | #define dword_22D444 (*(int *)(DSEG3+0x0000E444)) 50 | #define dword_22D448 (*(int *)(DSEG3+0x0000E448)) 51 | #define word_22D44E (*(i16 *)(DSEG3+0x0000E44E)) 52 | #define word_22D450 (*(i16 *)(DSEG3+0x0000E450)) 53 | #define word_22D452 (*(i16 *)(DSEG3+0x0000E452)) 54 | #define byte_22D454 (*(char *)(DSEG3+0x0000E454)) 55 | #define byte_22D455 (*(char *)(DSEG3+0x0000E455)) 56 | #define dword_22ED90 (*(int *)(DSEG3+0x0000FD90)) 57 | #define colour_lookup (*(char *)(DSEG3+0x0000FDA0)) 58 | #define byte_22EDA1 (*(char *)(DSEG3+0x0000FDA1)) 59 | #define byte_22EDA2 (*(char *)(DSEG3+0x0000FDA2)) 60 | #define byte_22EDA3 (*(char *)(DSEG3+0x0000FDA3)) 61 | #define byte_22EDA4 (*(char *)(DSEG3+0x0000FDA4)) 62 | #define byte_22EDA5 (*(char *)(DSEG3+0x0000FDA5)) 63 | #define byte_22EDA6 (*(char *)(DSEG3+0x0000FDA6)) 64 | #define byte_22EDA7 (*(char *)(DSEG3+0x0000FDA7)) 65 | #define dword_256744 (*(int *)(DSEG3+0x00037744)) 66 | #define word_25679A (*(i16 *)(DSEG3+0x0003779A)) 67 | #define word_25679C (*(i16 *)(DSEG3+0x0003779C)) 68 | #define word_25679E (*(i16 *)(DSEG3+0x0003779E)) 69 | #define byte_2567B0 (*(char *)(DSEG3+0x000377B0)) 70 | #define byte_2567B1 (*(char *)(DSEG3+0x000377B1)) 71 | #define end_time (*(int *)(DSEG3+0x000377B8)) 72 | #define glob_value3 (*(int *)(DSEG3+0x000377BC)) 73 | #define bonus (*(int *)(DSEG3+0x000377C4)) 74 | #define seed (*(int *)(DSEG3+0x000377C8)) 75 | #define logo_data (*(int *)(DSEG3+0x000377CC)) 76 | #define fade_offset (*(int *)(DSEG3+0x000377D0)) 77 | #define turn (*(int *)(DSEG3+0x000377D8)) 78 | #define start_time (*(int *)(DSEG3+0x000377E4)) 79 | #define glass_map (*(int *)(DSEG3+0x000377F4)) 80 | #define effect_list (*(int *)(DSEG3+0x000377F8)) 81 | #define tube_graphics (*(int *)(DSEG3+0x000377FC)) 82 | #define fade_out (*(int *)(DSEG3+0x00037800)) 83 | #define high_scores (*(int *)(DSEG3+0x00037804)) 84 | #define plotat (*(int *)(DSEG3+0x0003780C)) 85 | #define level (*(int *)(DSEG3+0x00037810)) 86 | #define logo_end (*(int *)(DSEG3+0x00037B1C)) 87 | #define logo (*(int *)(DSEG3+0x00037B20)) 88 | #define hi_look (*(int *)(DSEG3+0x00037B24)) 89 | #define block_data (*(int *)(DSEG3+0x00037B2C)) 90 | #define palette (*(int *)(DSEG3+0x00037B30)) 91 | #define byte_256B35 (*(char *)(DSEG3+0x00037B35)) 92 | #define byte_256B39 (*(char *)(DSEG3+0x00037B39)) 93 | #define byte_256B3B (*(char *)(DSEG3+0x00037B3B)) 94 | #define fade_width (*(i16 *)(DSEG3+0x00037B44)) 95 | #define fade_height (*(i16 *)(DSEG3+0x00037B46)) 96 | #define joyy (*(i16 *)(DSEG3+0x00037B48)) 97 | #define joyx (*(i16 *)(DSEG3+0x00037B4A)) 98 | #define buttons (*(char *)(DSEG3+0x00037B4F)) 99 | #define blk_collision (*(char *)(DSEG3+0x00037B50)) 100 | #define tabgen (*(char *)(DSEG3+0x00037B51)) 101 | #define dword_256B60 (*(int *)(DSEG3+0x00037B60)) 102 | #define selected_object (*(int *)(DSEG3+0x00080660)) 103 | #define no_tmaps (*(int *)(DSEG3+0x00080664)) 104 | #define no_point3ds (*(int *)(DSEG3+0x00080668)) 105 | #define no_face3ds (*(int *)(DSEG3+0x0008066C)) 106 | #define no_object3ds (*(int *)(DSEG3+0x00080670)) 107 | #define tube_scroll_x (*(int *)(DSEG3+0x00080674)) 108 | #define tube_scroll_y (*(int *)(DSEG3+0x00080678)) 109 | #define scroll_x (*(int *)(DSEG3+0x0008067C)) 110 | #define scroll_y (*(int *)(DSEG3+0x00080680)) 111 | #define byte_2B37D1 (*(char *)(DSEG3+0x000947D1)) 112 | #define byte_2B37D2 (*(char *)(DSEG3+0x000947D2)) 113 | #define byte_2B37D3 (*(char *)(DSEG3+0x000947D3)) 114 | #define byte_2B37D7 (*(char *)(DSEG3+0x000947D7)) 115 | #define byte_2B37D8 (*(char *)(DSEG3+0x000947D8)) 116 | #define byte_2B37D9 (*(char *)(DSEG3+0x000947D9)) 117 | #define byte_2B37DA (*(char *)(DSEG3+0x000947DA)) 118 | #define byte_2B37DB (*(char *)(DSEG3+0x000947DB)) 119 | #define byte_2B37DD (*(char *)(DSEG3+0x000947DD)) 120 | #define byte_2B37E0 (*(char *)(DSEG3+0x000947E0)) 121 | #define byte_2B37E6 (*(char *)(DSEG3+0x000947E6)) 122 | #define byte_2B37E8 (*(char *)(DSEG3+0x000947E8)) 123 | #define byte_2B37E9 (*(char *)(DSEG3+0x000947E9)) 124 | #define byte_2B37EC (*(char *)(DSEG3+0x000947EC)) 125 | #define byte_2B37EE (*(char *)(DSEG3+0x000947EE)) 126 | #define byte_2B3806 (*(char *)(DSEG3+0x00094806)) 127 | #define byte_2B3809 (*(char *)(DSEG3+0x00094809)) 128 | #define byte_2B3812 (*(char *)(DSEG3+0x00094812)) 129 | #define Inkey (*(char *)(DSEG3+0x00094850)) 130 | #define Shift (*(char *)(DSEG3+0x00094851)) 131 | #define fade_count (*(i16 *)(DSEG3+0x00094E60)) 132 | #define GraphicsWindowBottom (*(int *)(DSEG3+0x00094E70)) 133 | #define GraphicsWindowRight (*(int *)(DSEG3+0x00094E74)) 134 | #define GraphicsWindowLeft (*(int *)(DSEG3+0x00094E7C)) 135 | #define ScreenHeight (*(int *)(DSEG3+0x00094E84)) 136 | #define WScreen (*(int *)(DSEG3+0x00094E88)) 137 | #define GraphicsWindowHeight (*(int *)(DSEG3+0x00094E8C)) 138 | #define GraphicsWindowWidth (*(int *)(DSEG3+0x00094E90)) 139 | #define GraphicsWindowTop (*(int *)(DSEG3+0x00094E98)) 140 | #define ScreenWidth (*(int *)(DSEG3+0x00094EA8)) 141 | #define OldVideoMode (*(i16 *)(DSEG3+0x00094EAC)) 142 | #define ScreenMode (*(i16 *)(DSEG3+0x00094EAE)) 143 | #define word_2B3ECA (*(i16 *)(DSEG3+0x00094ECA)) 144 | #define MemoryArenas (*(int *)(DSEG3+0x00095B60)) 145 | #define MemoryAvailable (*(int *)(DSEG3+0x00096D60)) 146 | #define dword_2B5D64 (*(int *)(DSEG3+0x00096D64)) 147 | #define dword_2B5D68 (*(int *)(DSEG3+0x00096D68)) 148 | #define dword_2B5D6C (*(unsigned int *)(DSEG3+0x00096D6C)) 149 | #define dword_2B5D70 (*(int *)(DSEG3+0x00096D70)) 150 | #define BaseAddress (*(int *)(DSEG3+0x00096FF0)) 151 | #define IRQ (*(int *)(DSEG3+0x00096FF4)) 152 | #define DMA (*(int *)(DSEG3+0x00097064)) 153 | #define Music (*(int *)(DSEG3+0x000970B0)) 154 | #define MusicBaseAddress (*(int *)(DSEG3+0x000970B4)) 155 | #define polyscans (*(int *)(DSEG3+0x00001C64)) 156 | 157 | //Arrays 158 | #define byte_2A26BC ((char *)(DSEG3+0x000836BC)) 159 | #define byte_256994 ((char *)(DSEG3+0x00037994)) 160 | #define byte_21FDDA ((char *)(DSEG3+0x00000DDA)) 161 | #define byte_21FB06 ((char *)(DSEG3+0x00000B06)) 162 | #define byte_21FAC0 ((char *)(DSEG3+0x00000AC0)) 163 | #define byte_21FAE4 ((char *)(DSEG3+0x00000AE4)) 164 | #define byte_21FA68 ((char *)(DSEG3+0x00000A68)) 165 | #define byte_21FA2A ((char *)(DSEG3+0x00000A2A)) 166 | #define byte_21FB1A ((char *)(DSEG3+0x00000B1A)) 167 | #define byte_21FB2E ((char *)(DSEG3+0x00000B2E)) 168 | #define byte_21FB76 ((char *)(DSEG3+0x00000B76)) 169 | #define byte_21FBDE ((char *)(DSEG3+0x00000BDE)) 170 | #define byte_21FC38 ((char *)(DSEG3+0x00000C38)) 171 | #define unk_21FC42 ((char *)(DSEG3+0x00000C42)) 172 | #define byte_21FCCC ((char *)(DSEG3+0x00000CCC)) 173 | #define byte_21FE6C ((char *)(DSEG3+0x00000E6C)) 174 | #define dword_2B3F68 ((int *)(DSEG3+0x00094F68)) 175 | #define byte_2B4B70 ((char *)(DSEG3+0x00095B70)) 176 | #define byte_2B4B71 ((char *)(DSEG3+0x00095B71)) 177 | #define dword_2B3F64 ((int *)(DSEG3+0x00094F64)) 178 | #define word_25677C ((i16 *)(DSEG3+0x0003777C)) 179 | #define word_2314BC ((i16 *)(DSEG3+0x000124BC)) 180 | #define bullets ((char *)(DSEG3+0x00016F48)) 181 | #define asc_21F11C ((char *)(DSEG3+0x0000011C)) 182 | #define aDataLev05dDat ((char *)(DSEG3+0x000001C4)) 183 | #define aCongratulation ((char *)(DSEG3+0x000000D0)) 184 | #define aDataTex02dDat ((char *)(DSEG3+0x00000250)) 185 | #define musicboard ((char *)(DSEG3+0x000970C0)) 186 | #define soundboard ((char *)(DSEG3+0x00097000)) 187 | #define polypoints ((char *)(DSEG3+0x0007A0A0)) 188 | #define KeyOn ((char *)(DSEG3+0x000947D0)) 189 | #define to_pal ((char *)(DSEG3+0x00094B60)) 190 | #define aTables ((char *)(DSEG3+0x00000004)) 191 | #define aDebug ((char *)(DSEG3+0x0000000C)) 192 | #define aJty ((char *)(DSEG3+0x00000118)) 193 | #define aCongratulation_0 ((char *)(DSEG3+0x00000128)) 194 | #define aCongratulation_1 ((char *)(DSEG3+0x00000158)) 195 | #define aCongratulation_2 ((char *)(DSEG3+0x00000188)) 196 | #define aDataHiscoreDat ((char *)(DSEG3+0x000001D8)) 197 | #define aDataTunnelDat ((char *)(DSEG3+0x000001EC)) 198 | #define aDataTablesDat ((char *)(DSEG3+0x00000208)) 199 | #define aData3dobsDat ((char *)(DSEG3+0x00000218)) 200 | #define aData3dpointsDa ((char *)(DSEG3+0x00000228)) 201 | #define aData3dfacesDat ((char *)(DSEG3+0x0000023C)) 202 | #define aBfMusic ((char *)(DSEG3+0x00000324)) 203 | #define aNone ((char *)(DSEG3+0x00000364)) 204 | #define aBfSound ((char *)(DSEG3+0x0000036C)) 205 | #define aNone_0 ((char *)(DSEG3+0x000003A4)) 206 | #define myvx ((i16 *)(DSEG3+0x00000940)) 207 | #define byte_21F942 ((char *)(DSEG3+0x00000942)) 208 | #define vx ((s16 *)(DSEG3+0x00000944)) 209 | #define byte_21F946 ((char *)(DSEG3+0x00000946)) 210 | #define vy ((s16 *)(DSEG3+0x00000948)) 211 | #define new_ship_pitch ((char *)(DSEG3+0x0000095E)) 212 | #define current_ship_pitch ((char *)(DSEG3+0x00000960)) 213 | #define swamp_blocks ((i16 *)(DSEG3+0x00000A2C)) 214 | #define ice_blocks ((i16 *)(DSEG3+0x00000A6A)) 215 | #define death_blocks ((i16 *)(DSEG3+0x00000AC2)) 216 | #define jump_blocks ((i16 *)(DSEG3+0x00000AE6)) 217 | #define arrow_up_blocks ((i16 *)(DSEG3+0x00000B08)) 218 | #define arrow_down_blocks ((i16 *)(DSEG3+0x00000B1C)) 219 | #define arrow_left_blocks ((i16 *)(DSEG3+0x00000B30)) 220 | #define arrow_right_blocks ((i16 *)(DSEG3+0x00000B78)) 221 | #define reverse_all_blocks ((i16 *)(DSEG3+0x00000BE0)) 222 | #define reverse_x_blocks ((i16 *)(DSEG3+0x00000C3A)) 223 | #define reverse_y_blocks ((i16 *)(DSEG3+0x00000C44)) 224 | #define solid_blocks ((i16 *)(DSEG3+0x00000CCE)) 225 | #define hit_blocks ((i16 *)(DSEG3+0x00000DDC)) 226 | #define word_21FDDE ((i16 *)(DSEG3+0x00000DDE)) 227 | #define contact_blocks ((i16 *)(DSEG3+0x00000E6E)) 228 | #define anim_order_1 ((i16 *)(DSEG3+0x00000E70)) 229 | #define byte_220A59 ((char *)(DSEG3+0x00001A59)) 230 | #define startup_files ((char *)(DSEG3+0x00001A64)) 231 | #define word_220C48 ((i16 *)(DSEG3+0x00001C48)) 232 | #define sintable ((int *)(DSEG3+0x00004968)) 233 | #define costable ((int *)(DSEG3+0x00005168)) 234 | #define inkey_asckey ((char *)(DSEG3+0x00007181)) 235 | #define dword_226298 ((int *)(DSEG3+0x00007298)) 236 | #define music_table ((char *)(DSEG3+0x000072D4)) 237 | #define SoundInfoDirectory ((char *)(DSEG3+0x000073A4)) 238 | #define SoundInfoFile ((char *)(DSEG3+0x00007408)) 239 | #define anim_blks ((i16 *)(DSEG3+0x0000FDA8)) 240 | #define dword_22EDAA ((int *)(DSEG3+0x0000FDAA)) 241 | #define word_22EDAE ((i16 *)(DSEG3+0x0000FDAE)) 242 | #define word_22EDB0 ((i16 *)(DSEG3+0x0000FDB0)) 243 | #define anim_addresses ((int *)(DSEG3+0x000124B8)) 244 | #define dword_2344BC ((int *)(DSEG3+0x000154BC)) 245 | #define aliens ((int *)(DSEG3+0x00016138)) 246 | #define word_23513C ((i16 *)(DSEG3+0x0001613C)) 247 | #define word_23513E ((i16 *)(DSEG3+0x0001613E)) 248 | #define word_235140 ((i16 *)(DSEG3+0x00016140)) 249 | #define word_235142 ((i16 *)(DSEG3+0x00016142)) 250 | #define word_235144 ((i16 *)(DSEG3+0x00016144)) 251 | #define word_235146 ((i16 *)(DSEG3+0x00016146)) 252 | #define byte_235148 ((char *)(DSEG3+0x00016148)) 253 | #define byte_235150 ((char *)(DSEG3+0x00016150)) 254 | #define byte_235152 ((char *)(DSEG3+0x00016152)) 255 | #define byte_235153 ((char *)(DSEG3+0x00016153)) 256 | #define byte_235F58 ((char *)(DSEG3+0x00016F58)) 257 | #define tunnelmap ((char *)(DSEG3+0x00017740)) 258 | #define the_score ((unsigned int *)(DSEG3+0x00037740)) 259 | #define old_score ((int *)(DSEG3+0x00037748)) 260 | #define players ((int *)(DSEG3+0x00037778)) 261 | #define unk_25677E ((char *)(DSEG3+0x0003777E)) 262 | #define byte_25677F ((char *)(DSEG3+0x0003777F)) 263 | #define dword_256780 ((int *)(DSEG3+0x00037780)) 264 | #define dword_256784 ((int *)(DSEG3+0x00037784)) 265 | #define byte_256788 ((char *)(DSEG3+0x00037788)) 266 | #define byte_256789 ((char *)(DSEG3+0x00037789)) 267 | #define byte_25678A ((char *)(DSEG3+0x0003778A)) 268 | #define byte_25678B ((char *)(DSEG3+0x0003778B)) 269 | #define byte_25678C ((char *)(DSEG3+0x0003778C)) 270 | #define dword_25678D ((int *)(DSEG3+0x0003778D)) 271 | #define dword_256791 ((int *)(DSEG3+0x00037791)) 272 | #define byte_256795 ((char *)(DSEG3+0x00037795)) 273 | #define level_line ((u16 *)(DSEG3+0x000377DC)) 274 | #define scrollpos ((s16 *)(DSEG3+0x000377E8)) 275 | #define word_2567EA ((i16 *)(DSEG3+0x000377EA)) 276 | #define joysy ((i16 *)(DSEG3+0x000377EC)) 277 | #define word_2567EE ((i16 *)(DSEG3+0x000377EE)) 278 | #define joysx ((i16 *)(DSEG3+0x000377F0)) 279 | #define draw_items ((int *)(DSEG3+0x00037814)) 280 | #define wins ((char *)(DSEG3+0x00037B34)) 281 | #define scrollsave ((signed char *)(DSEG3+0x00037B36)) 282 | #define game_over_flag ((char *)(DSEG3+0x00037B38)) 283 | #define laps ((char *)(DSEG3+0x00037B3A)) 284 | #define lastscroll ((char *)(DSEG3+0x00037B3C)) 285 | #define unk_256B3D ((char *)(DSEG3+0x00037B3D)) 286 | #define flicker ((char *)(DSEG3+0x00037B3E)) 287 | #define no_lives ((char *)(DSEG3+0x00037B40)) 288 | #define byte_256B41 ((char *)(DSEG3+0x00037B41)) 289 | #define xbuttons ((char *)(DSEG3+0x00037B42)) 290 | #define tmaps ((int *)(DSEG3+0x00037B70)) 291 | #define face3ds ((char *)(DSEG3+0x00037BB0)) 292 | #define object3ds ((char *)(DSEG3+0x0005C5A0)) 293 | #define point3ds ((char *)(DSEG3+0x0005CBE0)) 294 | #define sts ((u32 *)(DSEG3+0x0007FE60)) 295 | #define dword_29F690 ((int *)(DSEG3+0x00080690)) 296 | #define byte_29F698 ((char *)(DSEG3+0x00080698)) 297 | #define dword_29F69C ((int *)(DSEG3+0x0008069C)) 298 | #define dword_29F6A4 ((int *)(DSEG3+0x000806A4)) 299 | #define dword_29F6AC ((int *)(DSEG3+0x000806AC)) 300 | #define dword_29F6B4 ((int *)(DSEG3+0x000806B4)) 301 | #define tables_start ((char *)(DSEG3+0x000806BC)) 302 | #define byte_29F6DC ((char *)(DSEG3+0x000806DC)) 303 | #define ghost ((char *)(DSEG3+0x000846BC)) 304 | #define word_2B37C0 ((i16 *)(DSEG3+0x000947C0)) 305 | #define from ((char *)(DSEG3+0x00094860)) 306 | #define MemoryBlocks ((int *)(DSEG3+0x00094F60)) 307 | #define dword_2B4B64 ((int *)(DSEG3+0x00095B64)) 308 | #define dword_2B4B68 ((int *)(DSEG3+0x00095B68)) 309 | #define dword_2B4B6C ((int *)(DSEG3+0x00095B6C)) 310 | #define MusicType ((char *)(DSEG3+0x0009713A)) 311 | 312 | //Pointers 313 | #define hiscore_second ((char *)(DSEG3+0x00000982)) 314 | #define array_list ((i16 *)(DSEG3+0x000019BC)) 315 | 316 | //Addresses 317 | #define anim_order_2 (DSEG3+0x00000ec2) 318 | #define anim_order_3 (DSEG3+0x00000f14) 319 | #define anim_order_4 (DSEG3+0x00000f66) 320 | #define anim_order_5 (DSEG3+0x00000fb8) 321 | #define anim_order_6 (DSEG3+0x0000103e) 322 | #define anim_order_7 (DSEG3+0x000010c4) 323 | #define anim_order_8 (DSEG3+0x0000114a) 324 | #define anim_order_9 (DSEG3+0x000011d0) 325 | #define anim_order_10 (DSEG3+0x00001256) 326 | #define anim_order_11 (DSEG3+0x000012dc) 327 | #define anim_order_12 (DSEG3+0x00001362) 328 | #define anim_order_13 (DSEG3+0x000013e8) 329 | #define anim_order_14 (DSEG3+0x0000146e) 330 | #define anim_order_15 (DSEG3+0x000014f4) 331 | #define anim_order_16 (DSEG3+0x0000157a) 332 | #define anim_order_17 (DSEG3+0x00001600) 333 | #define anim_order_18 (DSEG3+0x00001686) 334 | #define anim_order_19 (DSEG3+0x0000170c) 335 | #define anim_order_20 (DSEG3+0x00001792) 336 | #define anim_order_21 (DSEG3+0x00001818) 337 | #define anim_order_22 (DSEG3+0x00001842) 338 | #define anim_order_23 (DSEG3+0x0000186c) 339 | #define anim_order_24 (DSEG3+0x00001896) 340 | #define anim_order_25 (DSEG3+0x000018c0) 341 | #define anim_order_26 (DSEG3+0x000018ea) 342 | #define anim_order_27 (DSEG3+0x00001914) 343 | #define anim_order_28 (DSEG3+0x00001922) 344 | #define anim_order_29 (DSEG3+0x00001930) 345 | #define anim_order_30 (DSEG3+0x0000193e) 346 | #define anim_order_31 (DSEG3+0x0000194c) 347 | #define anim_order_32 (DSEG3+0x0000195a) 348 | #define anim_order_33 (DSEG3+0x00001968) 349 | #define anim_order_34 (DSEG3+0x00001976) 350 | #define anim_order_35 (DSEG3+0x00001984) 351 | #define anim_order_36 (DSEG3+0x00001992) 352 | #define anim_order_37 (DSEG3+0x000019a0) 353 | #define anim_order_38 (DSEG3+0x000019ae) 354 | -------------------------------------------------------------------------------- /Tube64/Music/hmpopl.c: -------------------------------------------------------------------------------- 1 | #ifndef NOALLOC 2 | #include 3 | #endif 4 | #include 5 | #include 6 | 7 | #include "hmpopl.h" 8 | //int opl_log = 0; 9 | 10 | static int v_op[][2] = {{0, 3}, {1, 4}, {2, 5}, {8, 0xb}, {9, 0xc}, {0xa, 0xd}, {0x10, 0x13}, {0x11, 0x14}, {0x12, 0x15} }; 11 | 12 | static int velvol_vol[] = { 13 | 0x3F, 0x3A, 0x35, 0x30, 0x2C, 0x29, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1D, 0x1C, 14 | 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0E, 0x0D, 15 | 0x0D, 0x0C, 0x0C, 0x0B, 0x0B, 0x0A, 0x0A, 0x09, 0x09, 0x08, 0x08, 0x07, 0x07, 0x06, 0x06, 0x06, 16 | 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0x00}; 17 | 18 | static int notefnum[] = { 19 | 0,0,0,0,0,0,0,0,0,0,0,0, 20 | 343, 363, 385, 408, 432, 458, 485, 514, 544, 577, 611, 21 | 647, 1367, 1387, 1409, 1432, 1456, 1482, 1509, 1538, 22 | 1568, 1601, 1635, 1671, 2391, 2411, 2433, 2456, 2480, 23 | 2506, 2533, 2562, 2592, 2625, 2659, 2695, 3415, 3435, 24 | 3457, 3480, 3504, 3530, 3557, 3586, 3616, 3649, 3683, 25 | 3719, 4439, 4459, 4481, 4504, 4528, 4554, 4581, 4610, 26 | 4640, 4673, 4707, 4743, 5463, 5483, 5505, 5528, 5552, 27 | 5578, 5605, 5634, 5664, 5697, 5731, 5767, 6487, 6507, 28 | 6529, 6552, 6576, 6602, 6629, 6658, 6688, 6721, 6755, 29 | 6791, 7511, 7531, 7553, 7576, 7600, 7626, 7653, 7682, 30 | 7712, 7745, 7779, 7815, 7854, 7863, 7938, 7984, 8032, 31 | 8084 32 | }; 33 | static int octfnum[] = { 324, 306, 289, 272, 257, 248, 229, 216, 204, 193, 182, 172 }; 34 | 35 | #pragma pack(push,1) 36 | 37 | struct bnkins { 38 | uint8_t field_00; 39 | uint8_t field_01; 40 | uint8_t op0_ksl; 41 | uint8_t op0_fmult; 42 | uint8_t feedback; 43 | uint8_t op0_attack; 44 | uint8_t op0_sustain; 45 | uint8_t op0_envgain; 46 | uint8_t op0_decay; 47 | uint8_t op0_release; 48 | uint8_t op0_outlevel; 49 | uint8_t op0_am; 50 | uint8_t op0_vib; 51 | uint8_t op0_ksr; 52 | uint8_t con; 53 | uint8_t op1_ksl; 54 | uint8_t op1_fmult; 55 | uint8_t field_11; 56 | uint8_t op1_attack; 57 | uint8_t op1_sustain; 58 | uint8_t op1_envgain; 59 | uint8_t op1_decay; 60 | uint8_t op1_release; 61 | uint8_t op1_outlevel; 62 | uint8_t op1_am; 63 | uint8_t op1_vib; 64 | uint8_t op1_ksr; 65 | uint8_t field_1b; 66 | uint8_t op0_ws; 67 | uint8_t op1_ws; 68 | }; 69 | //} __attribute__((packed)); 70 | 71 | struct bnkhdr { 72 | uint8_t major; 73 | uint8_t minor; 74 | char sig[6]; 75 | uint16_t num_ins; 76 | uint16_t num_used; 77 | uint32_t offset_name; 78 | uint32_t offset_data; 79 | uint8_t pad[8]; 80 | }; 81 | //} __attribute__((packed)); 82 | 83 | struct bnkdesc { 84 | uint16_t index; 85 | uint8_t flags; 86 | char name[9]; 87 | }; 88 | //} __attribute__((packed)); 89 | 90 | #pragma pack(pop) 91 | 92 | enum oplri { 93 | oplri_connsel = 0x04, 94 | oplri_new = 0x05, 95 | oplri_freq = 0x20, 96 | oplri_vol = 0x40, 97 | oplri_attdec = 0x60, 98 | oplri_sustrel = 0x80, 99 | oplri_fnum = 0xa0, 100 | oplri_key = 0xb0, 101 | oplri_drum = 0xbd, 102 | oplri_chfb = 0xc0, 103 | oplri_ws = 0xe0 104 | }; 105 | 106 | static void parsebnk(struct oplins *ins, const struct bnkins *bnk) { 107 | ins->op0_freq = (bnk->op0_am << 7) | (bnk->op0_vib << 6) | (bnk->op0_envgain << 5) | (bnk->op0_ksr << 4) | 108 | bnk->op0_fmult; 109 | ins->op0_vol = (bnk->op0_ksl << 6) | bnk->op0_outlevel; 110 | ins->op0_attdec = (bnk->op0_attack << 4) | bnk->op0_decay; 111 | ins->op0_sustrel = (bnk->op0_sustain << 4) | bnk->op0_release; 112 | ins->chfb = bnk->con | (bnk->feedback << 1); 113 | ins->op1_freq = (bnk->op1_am << 7) | (bnk->op1_vib << 6) | (bnk->op1_envgain << 5) | (bnk->op1_ksr << 4) | 114 | bnk->op1_fmult; 115 | ins->op1_vol = (bnk->op1_ksl << 6) | bnk->op1_outlevel; 116 | ins->op1_attdec = (bnk->op1_attack << 4) | bnk->op1_decay; 117 | ins->op1_sustrel = (bnk->op1_sustain << 4) | bnk->op1_release; 118 | ins->op0_ws = bnk->op0_ws; 119 | ins->op1_ws = bnk->op1_ws; 120 | } 121 | 122 | //extern int printf(const char *format, ...); 123 | static int loadbnk(struct oplins *ins, const void *data, int size) { 124 | const struct bnkhdr *bnkhdr = data; 125 | const struct bnkdesc *bnkdesc; 126 | const struct bnkins *bnkins; 127 | int num, i; 128 | if (size < sizeof(bnkhdr)) 129 | return -1; 130 | if (memcmp(bnkhdr->sig, "ADLIB-", 6) && 131 | memcmp(bnkhdr->sig, "AMLIB-", 6) && 132 | memcmp(bnkhdr->sig, "ANLIB-", 6)) 133 | return -1; 134 | num = bnkhdr->num_ins; 135 | if (memcmp(bnkhdr->sig, "AMLIB-", 6) && num == 128 && size == 5404) 136 | num--; 137 | if (size < bnkhdr->offset_name + num * sizeof(bnkdesc) || size < bnkhdr->offset_data) 138 | return -1; 139 | bnkdesc = (const struct bnkdesc *)((const uint8_t *)data + bnkhdr->offset_name); 140 | bnkins = (const struct bnkins *)((const uint8_t *)data + bnkhdr->offset_data); 141 | for (i = 0; i < num; i++) { 142 | int idx = bnkdesc[i].index; 143 | if (bnkhdr->offset_data + (idx + 1) * sizeof(bnkins) > size) 144 | return -1; 145 | parsebnk(&ins[i], &bnkins[idx]); 146 | ins[i].flags = bnkdesc[i].flags; 147 | } 148 | /* 149 | printf("loaded %d ins\n", num); 150 | printf("0{f=%02x v=%02x ad=%02x sr=%02x cf=%02x} 1{f=%02x 151 | uint8_t op0_freq; 152 | uint8_t op0_vol; 153 | uint8_t op0_attdec; 154 | uint8_t op0_sustrel; 155 | uint8_t chfb; 156 | uint8_t op1_freq; 157 | uint8_t op1_vol; 158 | uint8_t op1_attdec; 159 | uint8_t op1_sustrel; 160 | uint8_t flags; 161 | uint8_t op0_ws; 162 | uint8_t op1_ws; 163 | 164 | */ 165 | return 0; 166 | } 167 | 168 | #ifndef opl_write 169 | static void opl_write(hmpopl *h, int idx, int reg, int val) { 170 | //if (opl_log) 171 | // //printf("%d.%02x = %02x\n", idx, reg, val); 172 | h->write(/*h->write_data,*/ idx, reg, val); 173 | } 174 | #endif 175 | 176 | static void opl_write_both(hmpopl *h, int reg, int val) { 177 | opl_write(h, 0, reg, val); 178 | opl_write(h, 1, reg, val); 179 | } 180 | 181 | static void opl_write_both_rev(hmpopl *h, int reg, int val) { 182 | opl_write(h, 1, reg, val); 183 | opl_write(h, 0, reg, val); 184 | } 185 | 186 | static void opl_init(hmpopl *h) { 187 | opl_write(h, 1, oplri_new, 1); 188 | opl_write(h, 1, oplri_connsel, 0); 189 | } 190 | 191 | static void opl_clear(hmpopl *h) { 192 | int v; 193 | for (v = 0; v < 9; v++) { 194 | h->oplreg_key[v] = 0; 195 | opl_write_both(h, oplri_key + v, h->oplreg_key[v]); 196 | } 197 | opl_write(h, 0, oplri_drum, 0); 198 | } 199 | 200 | static void v_noteoff(hmpopl *h, int v) { 201 | if (!h->v_note[v]) 202 | return; 203 | h->oplreg_key[v] &= ~0x20; 204 | opl_write_both(h, oplri_key + v, h->oplreg_key[v]); 205 | h->v_note[v] = 0; 206 | return; 207 | } 208 | 209 | static void v_noteoffon(hmpopl *h, int v, int fnum) { 210 | h->oplreg_fnum[v] = fnum & 0xff; 211 | if (v <= 5) // reproduce array overflow bug 212 | h->op_sustrel[v + 0x10] = h->oplreg_fnum[v]; 213 | h->oplreg_key[v] = (fnum >> 8) | 0x20; 214 | opl_write_both(h, oplri_fnum + v, h->oplreg_fnum[v]); 215 | opl_write_both(h, oplri_key + v, h->oplreg_key[v] & ~0x20); 216 | opl_write_both(h, oplri_key + v, h->oplreg_key[v]); 217 | } 218 | 219 | static void v_noteon(hmpopl *h, int v, int fnum) { 220 | h->oplreg_fnum[v] = fnum & 0xff; 221 | if (v <= 5) // reproduce array overflow bug 222 | h->op_sustrel[v + 0x10] = h->oplreg_fnum[v]; 223 | h->oplreg_key[v] = (fnum >> 8) | 0x20; 224 | opl_write_both(h, oplri_fnum + v, h->oplreg_fnum[v]); 225 | opl_write_both(h, oplri_key + v, h->oplreg_key[v]); 226 | } 227 | 228 | static void v_alloff(hmpopl *h) { 229 | int v; 230 | opl_write(h, 0, 0xbd, 0); 231 | for (v = 0; v < 9; v++) 232 | opl_write_both(h, oplri_key + v, h->oplreg_key[v] & 0xdf); 233 | for (v = 0; v < 9; v++) 234 | opl_write_both(h, oplri_vol + v_op[v][1], 0xff); 235 | } 236 | 237 | static void opl_done(hmpopl *h) { 238 | opl_write(h, 1, oplri_new, 0); 239 | } 240 | 241 | static int calcvol(hmpopl *h, int op, int velvol) { 242 | int volreg = h->op_basevol[op] & 0x3f; 243 | int nvol = (64 - velvol_vol[velvol >> 1]) << 1; 244 | nvol = (64 - volreg) * nvol; 245 | nvol = (8192 - nvol) >> 7; 246 | return (h->op_basevol[op] & 0xc0) | nvol; 247 | } 248 | 249 | static int v_get_velvol(hmpopl *h, int v) { 250 | int vol = h->ch_vol[h->v_ch[v]]; 251 | return (((vol << 7) / 127) * h->v_velo[v]) >> 7; 252 | } 253 | 254 | static void v_setvelvol(hmpopl *h, int v, int subop, int velvol, int nopan, int revpan) { 255 | int op = v_op[v][subop]; 256 | int volreg = calcvol(h, op, velvol); 257 | if (nopan) { 258 | opl_write_both(h, 0x40 + op, volreg); 259 | } else if ((h->ch_pan[h->v_ch[v]] < 64) ^ revpan) 260 | opl_write(h, 0, 0x40 + op, volreg); 261 | else 262 | opl_write(h, 1, 0x40 + op, volreg); 263 | } 264 | 265 | static void v_setins(hmpopl *h, int v, struct oplins *ins) { 266 | int op = v_op[v][0]; 267 | int op1 = v_op[v][1]; 268 | h->op_sustrel[op] = ins->op0_sustrel; 269 | h->op_sustrel[op1] = ins->op1_sustrel; 270 | h->op_basevol[op] = ins->op0_vol; 271 | h->op_basevol[op1] = ins->op1_vol; 272 | 273 | //opl_log = 1; 274 | opl_write_both(h, oplri_freq + op, ins->op0_freq); 275 | opl_write_both(h, oplri_vol + op, ins->op0_vol); 276 | opl_write_both(h, oplri_attdec + op, ins->op0_attdec); 277 | opl_write_both(h, oplri_sustrel + op, ins->op0_sustrel); 278 | 279 | opl_write(h, 0, oplri_chfb + v, (ins->chfb & 0x1f) | 0x20); 280 | opl_write(h, 1, oplri_chfb + v, (ins->chfb & 0x1f) | 0x10); 281 | 282 | opl_write_both(h, oplri_ws + op, ins->op0_ws); 283 | 284 | opl_write_both(h, oplri_freq + op1, ins->op1_freq); 285 | opl_write_both(h, oplri_attdec + op1, ins->op1_attdec); 286 | opl_write_both(h, oplri_sustrel + op1, ins->op1_sustrel); 287 | opl_write_both(h, oplri_ws + op1, ins->op1_ws); 288 | //opl_log = 0; 289 | } 290 | 291 | 292 | static void ch_setpan(hmpopl *h, int ch, int pan) { 293 | int v; 294 | h->ch_pan[ch] = pan; 295 | int abspan = pan; 296 | if (abspan >= 64) 297 | abspan = 127 - abspan; 298 | abspan *= 2; 299 | for (v = 0; v < 9; v++) { 300 | if (!h->v_note[v] || h->v_ch[v] != ch) 301 | continue; 302 | int velvol = (v_get_velvol(h, v) * abspan) >> 7; 303 | v_setvelvol(h, v, 1, velvol, 0, 1); 304 | if (h->melodic[h->ch_prog[ch]].chfb & 1) 305 | v_setvelvol(h, v, 0, velvol, 0, 1); 306 | } 307 | } 308 | 309 | static void v_setvol(hmpopl *h, int v) { 310 | int velvol = v_get_velvol(h, v); 311 | if (h->melodic[h->ch_prog[h->v_ch[v]]].chfb & 1) 312 | v_setvelvol(h, v, 0, velvol, 0, 0); 313 | v_setvelvol(h, v, 1, velvol, 0, 0); 314 | } 315 | 316 | static void ch_setvol(hmpopl *h, int ch, int vol) { 317 | int v; 318 | if (ch >= 16) 319 | return; 320 | h->ch_vol[ch] = vol; 321 | for (v = 0; v < 9; v++) 322 | if (h->v_note[v] && h->v_ch[v] == ch) 323 | v_setvol(h, v); 324 | 325 | ch_setpan(h, ch, h->ch_pan[ch]); 326 | } 327 | 328 | static void ch_noteoff(hmpopl *h, int ch, int note, int velo) { 329 | int v; 330 | if (h->ch_sust[ch] && h->ch_sust_idx[ch] < 32) { 331 | h->ch_sustnotes[ch][h->ch_sust_idx[ch]++] = note; 332 | return; 333 | } 334 | for (v = 0; v < 9; v++) 335 | if (h->v_note[v] == note && h->v_ch[v] == ch) 336 | v_noteoff(h, v); 337 | } 338 | 339 | static int pitchnote_to_fnum(int pitch, int note, int rng) { 340 | int noteinoct = note % 12; 341 | int fnumbl = notefnum[note]; 342 | int fbl = fnumbl & 0x1c00; 343 | int fnum = fnumbl & 0x3ff; 344 | if (pitch < 64) { 345 | int pitchofs = ((63 - pitch) * 1000) >> 6; 346 | int fnumrng = fnumbl - notefnum[note - rng]; 347 | if (fnumrng > 719) 348 | fnumrng = (fnum - octfnum[rng - 1]) & 0x3ff; 349 | return fnumbl - (fnumrng * pitchofs) / 1000; 350 | } else { 351 | int pitchofs = ((pitch - 64) * 1000) >> 6; 352 | int fnumrng = notefnum[note + rng] - fnumbl; 353 | if (fnumrng > 719) { 354 | fbl += 0x400; 355 | fnum = octfnum[11 - noteinoct]; 356 | fnumbl = fnum | fbl; 357 | fnumrng = notefnum[note + rng] - fnumbl; 358 | } 359 | return fnumbl + (fnumrng * pitchofs) / 1000; 360 | } 361 | } 362 | 363 | static void v_noteon_setvol(hmpopl *h, int v) { 364 | int op0 = v_op[v][0], op1 = v_op[v][1]; 365 | if (h->melodic[h->ch_prog[h->v_ch[v]]].chfb & 1) 366 | opl_write_both_rev(h, oplri_vol + op0, calcvol(h, op0, v_get_velvol(h, v))); 367 | opl_write_both_rev(h, oplri_vol + op1, calcvol(h, op1, v_get_velvol(h, v))); 368 | } 369 | 370 | static int findvoice(hmpopl *h, int orgch) { 371 | int v, ch; 372 | for (v = 0; v < 9; v++) 373 | if (!h->v_note[v]) 374 | return v; 375 | 376 | for (ch = 0; ch < 16; ch++) 377 | if (!h->ch_pitched[ch]) 378 | for (v = 0; v < 9; v++) 379 | if (h->v_ch[v] == ch) 380 | return v; 381 | 382 | return orgch >= 9 ? orgch - 9 : orgch; 383 | } 384 | 385 | static void ch_noteondrum(hmpopl *h, int ch, int note, int velo) { 386 | int v = findvoice(h, ch); 387 | int i; 388 | v_noteoff(h, v); 389 | h->v_ch[v] = ch; 390 | for (i = 0; i < 5; i++) { 391 | opl_write_both(h, oplri_sustrel + v_op[v][1], h->op_sustrel[v_op[v][1]] | 0x0f); 392 | opl_write_both(h, oplri_sustrel + v_op[v][0], h->op_sustrel[v_op[v][0]] | 0x0f); 393 | } 394 | v_setins(h, v, &h->drum[note]); 395 | h->v_velo[v] = velo; 396 | v_noteon_setvol(h, v); 397 | h->v_note[v] = note; 398 | ch_setpan(h, ch, h->ch_pan[ch]); 399 | v_noteoffon(h, v, notefnum[h->drum[note].flags]); 400 | } 401 | 402 | static void ch_noteon(hmpopl *h, int ch, int note, int velo) { 403 | int i; 404 | if (!velo) { 405 | ch_noteoff(h, ch, note, 0); 406 | return; 407 | } 408 | if (ch == 9) { 409 | ch_noteondrum(h, ch, note, velo); 410 | return; 411 | } 412 | int v = findvoice(h, ch); 413 | v_noteoff(h, v); 414 | h->v_ch[v] = ch; 415 | for (i = 0; i < 5; i++) { 416 | opl_write_both(h, oplri_sustrel + v_op[v][1], h->op_sustrel[v_op[v][1]] | 0x0f); 417 | opl_write_both(h, oplri_sustrel + v_op[v][0], h->op_sustrel[v_op[v][0]] | 0x0f); 418 | } 419 | v_setins(h, v, &h->melodic[h->ch_prog[ch]]); 420 | h->v_velo[v] = velo; 421 | v_noteon_setvol(h, v); 422 | 423 | h->v_note[v] = note; 424 | ch_setpan(h, ch, h->ch_pan[ch]); 425 | v_noteoffon(h, v, notefnum[note]); 426 | if (h->ch_pitched[ch]) 427 | v_noteon(h, v, pitchnote_to_fnum(h->ch_pitch[ch], note, h->ch_pitchrng[ch])); 428 | } 429 | 430 | static void ch_reset(hmpopl *h, int ch) { 431 | h->ch_vol[ch] = 127; 432 | h->ch_sust[ch] = 0; 433 | h->ch_pitch[ch] = 64; 434 | h->ch_pitchrng[ch] = 2; 435 | } 436 | 437 | static void initdata(hmpopl *h) { 438 | int v, ch; 439 | for (v = 0; v < 9; v++) { 440 | h->v_note[v] = 0; 441 | h->v_ch[v] = 0; 442 | h->v_velo[v] = 127; 443 | //h->oplreg_key[v] = 0; 444 | //h->oplreg_fnum[v] = 0; 445 | } 446 | for (ch = 0; ch < 16; ch++) { 447 | h->ch_pitch[ch] = 64; 448 | h->ch_prog[ch] = 0; 449 | h->ch_pitched[ch] = 0; 450 | h->ch_vol[ch] = 127; 451 | h->ch_pan[ch] = 64; 452 | //ch_volset[ch] = 0; 453 | //ch_panset[ch] = 0; 454 | h->ch_sust_idx[ch] = 0; 455 | h->ch_pitchrng[ch] = 2; 456 | //h->ch_sust[ch] = 0; 457 | } 458 | //memset(h->op_basevol, 0, sizeof(h->op_basevol)); 459 | //memset(h->op_sustrel, 0, sizeof(h->op_sustrel)); 460 | //memset(h->ch_sustnotes, 0, sizeof(h->ch_sustnotes)); 461 | } 462 | 463 | static void ch_setprog(hmpopl *h, int ch, int prog) { 464 | h->ch_prog[ch] = prog; 465 | } 466 | 467 | static void ch_setsust(hmpopl *h, int ch, int sust) { 468 | h->ch_sust[ch] = sust; 469 | if (!sust) 470 | while (h->ch_sust_idx[ch]) 471 | ch_noteoff(h, ch, h->ch_sustnotes[ch][--h->ch_sust_idx[ch]], 0); 472 | } 473 | 474 | static void ch_setpitch(hmpopl *h, int ch, int pitch) { 475 | int v; 476 | if (ch == 9) 477 | return; 478 | h->ch_pitch[ch] = pitch; 479 | h->ch_pitched[ch] = 1; 480 | for (v = 0; v < 9; v++) 481 | if (h->v_note[v] && h->v_ch[v] == ch) 482 | v_noteon(h, v, pitchnote_to_fnum(pitch, h->v_note[v], h->ch_pitchrng[ch])); 483 | } 484 | 485 | static void ch_cntr(hmpopl *h, int ch, int cntr, int param) { 486 | switch (cntr) { 487 | case 0x40: 488 | ch_setsust(h, ch, param); 489 | break; 490 | case 0x79: 491 | ch_reset(h, ch); 492 | break; 493 | case 0x7b: 494 | v_alloff(h); 495 | break; 496 | case 0x66: 497 | h->ch_pitchrng[ch] = param; 498 | break; 499 | case 0x7: 500 | ch_setvol(h, ch, param); 501 | break; 502 | case 0x0a: 503 | ch_setpan(h, ch, param); 504 | break; 505 | } 506 | } 507 | 508 | void hmpopl_play_midi(hmpopl *h, int event, int ch, int param1, int param2) { 509 | if (ch < 0 || ch >= 16) 510 | return; 511 | switch (event) { 512 | case 8: 513 | ch_noteoff(h, ch, param1, param2); 514 | break; 515 | case 9: 516 | ch_noteon(h, ch, param1, param2); 517 | break; 518 | case 0xb: 519 | ch_cntr(h, ch, param1, param2); 520 | break; 521 | case 0xc: 522 | ch_setprog(h, ch, param1); 523 | break; 524 | case 0xe: 525 | ch_setpitch(h, ch, param2); 526 | break; 527 | } 528 | } 529 | 530 | 531 | #ifndef NOALLOC 532 | hmpopl *hmpopl_new(void) { 533 | return calloc(1, sizeof(hmpopl)); 534 | } 535 | 536 | void hmpopl_done(hmpopl *h) { 537 | #ifndef opl_write 538 | if (h->write) 539 | #endif 540 | opl_done(h); 541 | free(h); 542 | } 543 | #endif 544 | 545 | int hmpopl_set_bank(hmpopl *h, const void *data, int size, int isdrum) { 546 | return loadbnk(isdrum ? h->drum : h->melodic, data, size); 547 | } 548 | 549 | //void hmpopl_set_song(hmpopl *h, const void *data, int size, int dofree) { 550 | //} 551 | 552 | void hmpopl_set_write_callback(hmpopl *h, hmpopl_write_callback c/*, void *data*/) { 553 | h->write = c; 554 | // h->write_data = data; 555 | } 556 | 557 | void hmpopl_start(hmpopl *h) { 558 | opl_init(h); 559 | opl_clear(h); 560 | opl_clear(h); 561 | initdata(h); 562 | } 563 | 564 | void hmpopl_reset(hmpopl *h) { 565 | opl_clear(h); 566 | initdata(h); 567 | } 568 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /Tube64/tlsf/tlsf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "tlsf.h" 9 | 10 | #if defined(__cplusplus) 11 | #define tlsf_decl inline 12 | #else 13 | #define tlsf_decl static 14 | #endif 15 | 16 | /* 17 | ** Architecture-specific bit manipulation routines. 18 | ** 19 | ** TLSF achieves O(1) cost for malloc and free operations by limiting 20 | ** the search for a free block to a free list of guaranteed size 21 | ** adequate to fulfill the request, combined with efficient free list 22 | ** queries using bitmasks and architecture-specific bit-manipulation 23 | ** routines. 24 | ** 25 | ** Most modern processors provide instructions to count leading zeroes 26 | ** in a word, find the lowest and highest set bit, etc. These 27 | ** specific implementations will be used when available, falling back 28 | ** to a reasonably efficient generic implementation. 29 | ** 30 | ** NOTE: TLSF spec relies on ffs/fls returning value 0..31. 31 | ** ffs/fls return 1-32 by default, returning 0 for error. 32 | */ 33 | 34 | /* 35 | ** Detect whether or not we are building for a 32- or 64-bit (LP/LLP) 36 | ** architecture. There is no reliable portable method at compile-time. 37 | */ 38 | #if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) \ 39 | || defined (_WIN64) || defined (__LP64__) || defined (__LLP64__) 40 | #define TLSF_64BIT 41 | #endif 42 | 43 | /* 44 | ** gcc 3.4 and above have builtin support, specialized for architecture. 45 | ** Some compilers masquerade as gcc; patchlevel test filters them out. 46 | */ 47 | #if defined (__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) \ 48 | && defined (__GNUC_PATCHLEVEL__) 49 | 50 | #if defined (__SNC__) 51 | /* SNC for Playstation 3. */ 52 | 53 | tlsf_decl int tlsf_ffs(unsigned int word) 54 | { 55 | const unsigned int reverse = word & (~word + 1); 56 | const int bit = 32 - __builtin_clz(reverse); 57 | return bit - 1; 58 | } 59 | 60 | #else 61 | 62 | tlsf_decl int tlsf_ffs(unsigned int word) 63 | { 64 | return __builtin_ffs(word) - 1; 65 | } 66 | 67 | #endif 68 | 69 | tlsf_decl int tlsf_fls(unsigned int word) 70 | { 71 | const int bit = word ? 32 - __builtin_clz(word) : 0; 72 | return bit - 1; 73 | } 74 | 75 | #elif defined (_MSC_VER) && (_MSC_VER >= 1400) && (defined (_M_IX86) || defined (_M_X64)) 76 | /* Microsoft Visual C++ support on x86/X64 architectures. */ 77 | 78 | #include 79 | 80 | #pragma intrinsic(_BitScanReverse) 81 | #pragma intrinsic(_BitScanForward) 82 | 83 | tlsf_decl int tlsf_fls(unsigned int word) 84 | { 85 | unsigned long index; 86 | return _BitScanReverse(&index, word) ? index : -1; 87 | } 88 | 89 | tlsf_decl int tlsf_ffs(unsigned int word) 90 | { 91 | unsigned long index; 92 | return _BitScanForward(&index, word) ? index : -1; 93 | } 94 | 95 | #elif defined (_MSC_VER) && defined (_M_PPC) 96 | /* Microsoft Visual C++ support on PowerPC architectures. */ 97 | 98 | #include 99 | 100 | tlsf_decl int tlsf_fls(unsigned int word) 101 | { 102 | const int bit = 32 - _CountLeadingZeros(word); 103 | return bit - 1; 104 | } 105 | 106 | tlsf_decl int tlsf_ffs(unsigned int word) 107 | { 108 | const unsigned int reverse = word & (~word + 1); 109 | const int bit = 32 - _CountLeadingZeros(reverse); 110 | return bit - 1; 111 | } 112 | 113 | #elif defined (__ARMCC_VERSION) 114 | /* RealView Compilation Tools for ARM */ 115 | 116 | tlsf_decl int tlsf_ffs(unsigned int word) 117 | { 118 | const unsigned int reverse = word & (~word + 1); 119 | const int bit = 32 - __clz(reverse); 120 | return bit - 1; 121 | } 122 | 123 | tlsf_decl int tlsf_fls(unsigned int word) 124 | { 125 | const int bit = word ? 32 - __clz(word) : 0; 126 | return bit - 1; 127 | } 128 | 129 | #elif defined (__ghs__) 130 | /* Green Hills support for PowerPC */ 131 | 132 | #include 133 | 134 | tlsf_decl int tlsf_ffs(unsigned int word) 135 | { 136 | const unsigned int reverse = word & (~word + 1); 137 | const int bit = 32 - __CLZ32(reverse); 138 | return bit - 1; 139 | } 140 | 141 | tlsf_decl int tlsf_fls(unsigned int word) 142 | { 143 | const int bit = word ? 32 - __CLZ32(word) : 0; 144 | return bit - 1; 145 | } 146 | 147 | #else 148 | /* Fall back to generic implementation. */ 149 | 150 | tlsf_decl int tlsf_fls_generic(unsigned int word) 151 | { 152 | int bit = 32; 153 | 154 | if (!word) bit -= 1; 155 | if (!(word & 0xffff0000)) { word <<= 16; bit -= 16; } 156 | if (!(word & 0xff000000)) { word <<= 8; bit -= 8; } 157 | if (!(word & 0xf0000000)) { word <<= 4; bit -= 4; } 158 | if (!(word & 0xc0000000)) { word <<= 2; bit -= 2; } 159 | if (!(word & 0x80000000)) { word <<= 1; bit -= 1; } 160 | 161 | return bit; 162 | } 163 | 164 | /* Implement ffs in terms of fls. */ 165 | tlsf_decl int tlsf_ffs(unsigned int word) 166 | { 167 | return tlsf_fls_generic(word & (~word + 1)) - 1; 168 | } 169 | 170 | tlsf_decl int tlsf_fls(unsigned int word) 171 | { 172 | return tlsf_fls_generic(word) - 1; 173 | } 174 | 175 | #endif 176 | 177 | /* Possibly 64-bit version of tlsf_fls. */ 178 | #if defined (TLSF_64BIT) 179 | tlsf_decl int tlsf_fls_sizet(size_t size) 180 | { 181 | int high = (int)(size >> 32); 182 | int bits = 0; 183 | if (high) 184 | { 185 | bits = 32 + tlsf_fls(high); 186 | } 187 | else 188 | { 189 | bits = tlsf_fls((int)size & 0xffffffff); 190 | 191 | } 192 | return bits; 193 | } 194 | #else 195 | #define tlsf_fls_sizet tlsf_fls 196 | #endif 197 | 198 | #undef tlsf_decl 199 | 200 | /* 201 | ** Constants. 202 | */ 203 | 204 | /* Public constants: may be modified. */ 205 | enum tlsf_public 206 | { 207 | /* log2 of number of linear subdivisions of block sizes. Larger 208 | ** values require more memory in the control structure. Values of 209 | ** 4 or 5 are typical. 210 | */ 211 | SL_INDEX_COUNT_LOG2 = 5, 212 | }; 213 | 214 | /* Private constants: do not modify. */ 215 | enum tlsf_private 216 | { 217 | #if defined (TLSF_64BIT) 218 | /* All allocation sizes and addresses are aligned to 8 bytes. */ 219 | ALIGN_SIZE_LOG2 = 3, 220 | #else 221 | /* All allocation sizes and addresses are aligned to 4 bytes. */ 222 | ALIGN_SIZE_LOG2 = 2, 223 | #endif 224 | ALIGN_SIZE = (1 << ALIGN_SIZE_LOG2), 225 | 226 | /* 227 | ** We support allocations of sizes up to (1 << FL_INDEX_MAX) bits. 228 | ** However, because we linearly subdivide the second-level lists, and 229 | ** our minimum size granularity is 4 bytes, it doesn't make sense to 230 | ** create first-level lists for sizes smaller than SL_INDEX_COUNT * 4, 231 | ** or (1 << (SL_INDEX_COUNT_LOG2 + 2)) bytes, as there we will be 232 | ** trying to split size ranges into more slots than we have available. 233 | ** Instead, we calculate the minimum threshold size, and place all 234 | ** blocks below that size into the 0th first-level list. 235 | */ 236 | 237 | #if defined (TLSF_64BIT) 238 | /* 239 | ** TODO: We can increase this to support larger sizes, at the expense 240 | ** of more overhead in the TLSF structure. 241 | */ 242 | FL_INDEX_MAX = 32, 243 | #else 244 | FL_INDEX_MAX = 30, 245 | #endif 246 | SL_INDEX_COUNT = (1 << SL_INDEX_COUNT_LOG2), 247 | FL_INDEX_SHIFT = (SL_INDEX_COUNT_LOG2 + ALIGN_SIZE_LOG2), 248 | FL_INDEX_COUNT = (FL_INDEX_MAX - FL_INDEX_SHIFT + 1), 249 | 250 | SMALL_BLOCK_SIZE = (1 << FL_INDEX_SHIFT), 251 | }; 252 | 253 | /* 254 | ** Cast and min/max macros. 255 | */ 256 | 257 | #define tlsf_cast(t, exp) ((t) (exp)) 258 | #define tlsf_min(a, b) ((a) < (b) ? (a) : (b)) 259 | #define tlsf_max(a, b) ((a) > (b) ? (a) : (b)) 260 | 261 | /* 262 | ** Set assert macro, if it has not been provided by the user. 263 | */ 264 | #if !defined (tlsf_assert) 265 | //#define tlsf_assert assert 266 | #define tlsf_assert(...) 267 | #endif 268 | 269 | /* 270 | ** Static assertion mechanism. 271 | */ 272 | 273 | #define _tlsf_glue2(x, y) x ## y 274 | #define _tlsf_glue(x, y) _tlsf_glue2(x, y) 275 | #define tlsf_static_assert(exp) \ 276 | typedef char _tlsf_glue(static_assert, __LINE__) [(exp) ? 1 : -1] 277 | 278 | /* This code has been tested on 32- and 64-bit (LP/LLP) architectures. */ 279 | tlsf_static_assert(sizeof(int) * CHAR_BIT == 32); 280 | tlsf_static_assert(sizeof(size_t) * CHAR_BIT >= 32); 281 | tlsf_static_assert(sizeof(size_t) * CHAR_BIT <= 64); 282 | 283 | /* SL_INDEX_COUNT must be <= number of bits in sl_bitmap's storage type. */ 284 | tlsf_static_assert(sizeof(unsigned int) * CHAR_BIT >= SL_INDEX_COUNT); 285 | 286 | /* Ensure we've properly tuned our sizes. */ 287 | tlsf_static_assert(ALIGN_SIZE == SMALL_BLOCK_SIZE / SL_INDEX_COUNT); 288 | 289 | /* 290 | ** Data structures and associated constants. 291 | */ 292 | 293 | /* 294 | ** Block header structure. 295 | ** 296 | ** There are several implementation subtleties involved: 297 | ** - The prev_phys_block field is only valid if the previous block is free. 298 | ** - The prev_phys_block field is actually stored at the end of the 299 | ** previous block. It appears at the beginning of this structure only to 300 | ** simplify the implementation. 301 | ** - The next_free / prev_free fields are only valid if the block is free. 302 | */ 303 | typedef struct block_header_t 304 | { 305 | /* Points to the previous physical block. */ 306 | struct block_header_t* prev_phys_block; 307 | 308 | /* The size of this block, excluding the block header. */ 309 | size_t size; 310 | 311 | /* Next and previous free blocks. */ 312 | struct block_header_t* next_free; 313 | struct block_header_t* prev_free; 314 | } block_header_t; 315 | 316 | /* 317 | ** Since block sizes are always at least a multiple of 4, the two least 318 | ** significant bits of the size field are used to store the block status: 319 | ** - bit 0: whether block is busy or free 320 | ** - bit 1: whether previous block is busy or free 321 | */ 322 | static const size_t block_header_free_bit = 1 << 0; 323 | static const size_t block_header_prev_free_bit = 1 << 1; 324 | 325 | /* 326 | ** The size of the block header exposed to used blocks is the size field. 327 | ** The prev_phys_block field is stored *inside* the previous free block. 328 | */ 329 | static const size_t block_header_overhead = sizeof(size_t); 330 | 331 | /* User data starts directly after the size field in a used block. */ 332 | static const size_t block_start_offset = 333 | offsetof(block_header_t, size) + sizeof(size_t); 334 | 335 | /* 336 | ** A free block must be large enough to store its header minus the size of 337 | ** the prev_phys_block field, and no larger than the number of addressable 338 | ** bits for FL_INDEX. 339 | */ 340 | static const size_t block_size_min = 341 | sizeof(block_header_t) - sizeof(block_header_t*); 342 | static const size_t block_size_max = tlsf_cast(size_t, 1) << FL_INDEX_MAX; 343 | 344 | 345 | /* The TLSF control structure. */ 346 | typedef struct control_t 347 | { 348 | /* Empty lists point at this block to indicate they are free. */ 349 | block_header_t block_null; 350 | 351 | /* Bitmaps for free lists. */ 352 | unsigned int fl_bitmap; 353 | unsigned int sl_bitmap[FL_INDEX_COUNT]; 354 | 355 | /* Head of free lists. */ 356 | block_header_t* blocks[FL_INDEX_COUNT][SL_INDEX_COUNT]; 357 | } control_t; 358 | 359 | /* A type used for casting when doing pointer arithmetic. */ 360 | typedef ptrdiff_t tlsfptr_t; 361 | 362 | /* 363 | ** block_header_t member functions. 364 | */ 365 | 366 | static size_t block_size(const block_header_t* block) 367 | { 368 | return block->size & ~(block_header_free_bit | block_header_prev_free_bit); 369 | } 370 | 371 | static void block_set_size(block_header_t* block, size_t size) 372 | { 373 | const size_t oldsize = block->size; 374 | block->size = size | (oldsize & (block_header_free_bit | block_header_prev_free_bit)); 375 | } 376 | 377 | static int block_is_last(const block_header_t* block) 378 | { 379 | return block_size(block) == 0; 380 | } 381 | 382 | static int block_is_free(const block_header_t* block) 383 | { 384 | return tlsf_cast(int, block->size & block_header_free_bit); 385 | } 386 | 387 | static void block_set_free(block_header_t* block) 388 | { 389 | block->size |= block_header_free_bit; 390 | } 391 | 392 | static void block_set_used(block_header_t* block) 393 | { 394 | block->size &= ~block_header_free_bit; 395 | } 396 | 397 | static int block_is_prev_free(const block_header_t* block) 398 | { 399 | return tlsf_cast(int, block->size & block_header_prev_free_bit); 400 | } 401 | 402 | static void block_set_prev_free(block_header_t* block) 403 | { 404 | block->size |= block_header_prev_free_bit; 405 | } 406 | 407 | static void block_set_prev_used(block_header_t* block) 408 | { 409 | block->size &= ~block_header_prev_free_bit; 410 | } 411 | 412 | static block_header_t* block_from_ptr(const void* ptr) 413 | { 414 | return tlsf_cast(block_header_t*, 415 | tlsf_cast(unsigned char*, ptr) - block_start_offset); 416 | } 417 | 418 | static void* block_to_ptr(const block_header_t* block) 419 | { 420 | return tlsf_cast(void*, 421 | tlsf_cast(unsigned char*, block) + block_start_offset); 422 | } 423 | 424 | /* Return location of next block after block of given size. */ 425 | static block_header_t* offset_to_block(const void* ptr, size_t size) 426 | { 427 | return tlsf_cast(block_header_t*, tlsf_cast(tlsfptr_t, ptr) + size); 428 | } 429 | 430 | /* Return location of previous block. */ 431 | static block_header_t* block_prev(const block_header_t* block) 432 | { 433 | tlsf_assert(block_is_prev_free(block) && "previous block must be free"); 434 | return block->prev_phys_block; 435 | } 436 | 437 | /* Return location of next existing block. */ 438 | static block_header_t* block_next(const block_header_t* block) 439 | { 440 | block_header_t* next = offset_to_block(block_to_ptr(block), 441 | block_size(block) - block_header_overhead); 442 | tlsf_assert(!block_is_last(block)); 443 | return next; 444 | } 445 | 446 | /* Link a new block with its physical neighbor, return the neighbor. */ 447 | static block_header_t* block_link_next(block_header_t* block) 448 | { 449 | block_header_t* next = block_next(block); 450 | next->prev_phys_block = block; 451 | return next; 452 | } 453 | 454 | static void block_mark_as_free(block_header_t* block) 455 | { 456 | /* Link the block to the next block, first. */ 457 | block_header_t* next = block_link_next(block); 458 | block_set_prev_free(next); 459 | block_set_free(block); 460 | } 461 | 462 | static void block_mark_as_used(block_header_t* block) 463 | { 464 | block_header_t* next = block_next(block); 465 | block_set_prev_used(next); 466 | block_set_used(block); 467 | } 468 | 469 | static size_t align_up(size_t x, size_t align) 470 | { 471 | tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two"); 472 | return (x + (align - 1)) & ~(align - 1); 473 | } 474 | 475 | static size_t align_down(size_t x, size_t align) 476 | { 477 | tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two"); 478 | return x - (x & (align - 1)); 479 | } 480 | 481 | static void* align_ptr(const void* ptr, size_t align) 482 | { 483 | const tlsfptr_t aligned = 484 | (tlsf_cast(tlsfptr_t, ptr) + (align - 1)) & ~(align - 1); 485 | tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two"); 486 | return tlsf_cast(void*, aligned); 487 | } 488 | 489 | /* 490 | ** Adjust an allocation size to be aligned to word size, and no smaller 491 | ** than internal minimum. 492 | */ 493 | static size_t adjust_request_size(size_t size, size_t align) 494 | { 495 | size_t adjust = 0; 496 | if (size) 497 | { 498 | const size_t aligned = align_up(size, align); 499 | 500 | /* aligned sized must not exceed block_size_max or we'll go out of bounds on sl_bitmap */ 501 | if (aligned < block_size_max) 502 | { 503 | adjust = tlsf_max(aligned, block_size_min); 504 | } 505 | } 506 | return adjust; 507 | } 508 | 509 | /* 510 | ** TLSF utility functions. In most cases, these are direct translations of 511 | ** the documentation found in the white paper. 512 | */ 513 | 514 | static void mapping_insert(size_t size, int* fli, int* sli) 515 | { 516 | int fl, sl; 517 | if (size < SMALL_BLOCK_SIZE) 518 | { 519 | /* Store small blocks in first list. */ 520 | fl = 0; 521 | sl = tlsf_cast(int, size) / (SMALL_BLOCK_SIZE / SL_INDEX_COUNT); 522 | } 523 | else 524 | { 525 | fl = tlsf_fls_sizet(size); 526 | sl = tlsf_cast(int, size >> (fl - SL_INDEX_COUNT_LOG2)) ^ (1 << SL_INDEX_COUNT_LOG2); 527 | fl -= (FL_INDEX_SHIFT - 1); 528 | } 529 | *fli = fl; 530 | *sli = sl; 531 | } 532 | 533 | /* This version rounds up to the next block size (for allocations) */ 534 | static void mapping_search(size_t size, int* fli, int* sli) 535 | { 536 | if (size >= SMALL_BLOCK_SIZE) 537 | { 538 | const size_t round = (1 << (tlsf_fls_sizet(size) - SL_INDEX_COUNT_LOG2)) - 1; 539 | size += round; 540 | } 541 | mapping_insert(size, fli, sli); 542 | } 543 | 544 | static block_header_t* search_suitable_block(control_t* control, int* fli, int* sli) 545 | { 546 | int fl = *fli; 547 | int sl = *sli; 548 | 549 | /* 550 | ** First, search for a block in the list associated with the given 551 | ** fl/sl index. 552 | */ 553 | unsigned int sl_map = control->sl_bitmap[fl] & (~0U << sl); 554 | if (!sl_map) 555 | { 556 | /* No block exists. Search in the next largest first-level list. */ 557 | const unsigned int fl_map = control->fl_bitmap & (~0U << (fl + 1)); 558 | if (!fl_map) 559 | { 560 | /* No free blocks available, memory has been exhausted. */ 561 | return 0; 562 | } 563 | 564 | fl = tlsf_ffs(fl_map); 565 | *fli = fl; 566 | sl_map = control->sl_bitmap[fl]; 567 | } 568 | tlsf_assert(sl_map && "internal error - second level bitmap is null"); 569 | sl = tlsf_ffs(sl_map); 570 | *sli = sl; 571 | 572 | /* Return the first block in the free list. */ 573 | return control->blocks[fl][sl]; 574 | } 575 | 576 | /* Remove a free block from the free list.*/ 577 | static void remove_free_block(control_t* control, block_header_t* block, int fl, int sl) 578 | { 579 | block_header_t* prev = block->prev_free; 580 | block_header_t* next = block->next_free; 581 | tlsf_assert(prev && "prev_free field can not be null"); 582 | tlsf_assert(next && "next_free field can not be null"); 583 | next->prev_free = prev; 584 | prev->next_free = next; 585 | 586 | /* If this block is the head of the free list, set new head. */ 587 | if (control->blocks[fl][sl] == block) 588 | { 589 | control->blocks[fl][sl] = next; 590 | 591 | /* If the new head is null, clear the bitmap. */ 592 | if (next == &control->block_null) 593 | { 594 | control->sl_bitmap[fl] &= ~(1U << sl); 595 | 596 | /* If the second bitmap is now empty, clear the fl bitmap. */ 597 | if (!control->sl_bitmap[fl]) 598 | { 599 | control->fl_bitmap &= ~(1U << fl); 600 | } 601 | } 602 | } 603 | } 604 | 605 | /* Insert a free block into the free block list. */ 606 | static void insert_free_block(control_t* control, block_header_t* block, int fl, int sl) 607 | { 608 | block_header_t* current = control->blocks[fl][sl]; 609 | tlsf_assert(current && "free list cannot have a null entry"); 610 | tlsf_assert(block && "cannot insert a null entry into the free list"); 611 | block->next_free = current; 612 | block->prev_free = &control->block_null; 613 | current->prev_free = block; 614 | 615 | tlsf_assert(block_to_ptr(block) == align_ptr(block_to_ptr(block), ALIGN_SIZE) 616 | && "block not aligned properly"); 617 | /* 618 | ** Insert the new block at the head of the list, and mark the first- 619 | ** and second-level bitmaps appropriately. 620 | */ 621 | control->blocks[fl][sl] = block; 622 | control->fl_bitmap |= (1U << fl); 623 | control->sl_bitmap[fl] |= (1U << sl); 624 | } 625 | 626 | /* Remove a given block from the free list. */ 627 | static void block_remove(control_t* control, block_header_t* block) 628 | { 629 | int fl, sl; 630 | mapping_insert(block_size(block), &fl, &sl); 631 | remove_free_block(control, block, fl, sl); 632 | } 633 | 634 | /* Insert a given block into the free list. */ 635 | static void block_insert(control_t* control, block_header_t* block) 636 | { 637 | int fl, sl; 638 | mapping_insert(block_size(block), &fl, &sl); 639 | insert_free_block(control, block, fl, sl); 640 | } 641 | 642 | static int block_can_split(block_header_t* block, size_t size) 643 | { 644 | return block_size(block) >= sizeof(block_header_t) + size; 645 | } 646 | 647 | /* Split a block into two, the second of which is free. */ 648 | static block_header_t* block_split(block_header_t* block, size_t size) 649 | { 650 | /* Calculate the amount of space left in the remaining block. */ 651 | block_header_t* remaining = 652 | offset_to_block(block_to_ptr(block), size - block_header_overhead); 653 | 654 | const size_t remain_size = block_size(block) - (size + block_header_overhead); 655 | 656 | tlsf_assert(block_to_ptr(remaining) == align_ptr(block_to_ptr(remaining), ALIGN_SIZE) 657 | && "remaining block not aligned properly"); 658 | 659 | tlsf_assert(block_size(block) == remain_size + size + block_header_overhead); 660 | block_set_size(remaining, remain_size); 661 | tlsf_assert(block_size(remaining) >= block_size_min && "block split with invalid size"); 662 | 663 | block_set_size(block, size); 664 | block_mark_as_free(remaining); 665 | 666 | return remaining; 667 | } 668 | 669 | /* Absorb a free block's storage into an adjacent previous free block. */ 670 | static block_header_t* block_absorb(block_header_t* prev, block_header_t* block) 671 | { 672 | tlsf_assert(!block_is_last(prev) && "previous block can't be last"); 673 | /* Note: Leaves flags untouched. */ 674 | prev->size += block_size(block) + block_header_overhead; 675 | block_link_next(prev); 676 | return prev; 677 | } 678 | 679 | /* Merge a just-freed block with an adjacent previous free block. */ 680 | static block_header_t* block_merge_prev(control_t* control, block_header_t* block) 681 | { 682 | if (block_is_prev_free(block)) 683 | { 684 | block_header_t* prev = block_prev(block); 685 | tlsf_assert(prev && "prev physical block can't be null"); 686 | tlsf_assert(block_is_free(prev) && "prev block is not free though marked as such"); 687 | block_remove(control, prev); 688 | block = block_absorb(prev, block); 689 | } 690 | 691 | return block; 692 | } 693 | 694 | /* Merge a just-freed block with an adjacent free block. */ 695 | static block_header_t* block_merge_next(control_t* control, block_header_t* block) 696 | { 697 | block_header_t* next = block_next(block); 698 | tlsf_assert(next && "next physical block can't be null"); 699 | 700 | if (block_is_free(next)) 701 | { 702 | tlsf_assert(!block_is_last(block) && "previous block can't be last"); 703 | block_remove(control, next); 704 | block = block_absorb(block, next); 705 | } 706 | 707 | return block; 708 | } 709 | 710 | /* Trim any trailing block space off the end of a block, return to pool. */ 711 | static void block_trim_free(control_t* control, block_header_t* block, size_t size) 712 | { 713 | tlsf_assert(block_is_free(block) && "block must be free"); 714 | if (block_can_split(block, size)) 715 | { 716 | block_header_t* remaining_block = block_split(block, size); 717 | block_link_next(block); 718 | block_set_prev_free(remaining_block); 719 | block_insert(control, remaining_block); 720 | } 721 | } 722 | 723 | /* Trim any trailing block space off the end of a used block, return to pool. */ 724 | static void block_trim_used(control_t* control, block_header_t* block, size_t size) 725 | { 726 | tlsf_assert(!block_is_free(block) && "block must be used"); 727 | if (block_can_split(block, size)) 728 | { 729 | /* If the next block is free, we must coalesce. */ 730 | block_header_t* remaining_block = block_split(block, size); 731 | block_set_prev_used(remaining_block); 732 | 733 | remaining_block = block_merge_next(control, remaining_block); 734 | block_insert(control, remaining_block); 735 | } 736 | } 737 | 738 | static block_header_t* block_trim_free_leading(control_t* control, block_header_t* block, size_t size) 739 | { 740 | block_header_t* remaining_block = block; 741 | if (block_can_split(block, size)) 742 | { 743 | /* We want the 2nd block. */ 744 | remaining_block = block_split(block, size - block_header_overhead); 745 | block_set_prev_free(remaining_block); 746 | 747 | block_link_next(block); 748 | block_insert(control, block); 749 | } 750 | 751 | return remaining_block; 752 | } 753 | 754 | static block_header_t* block_locate_free(control_t* control, size_t size) 755 | { 756 | int fl = 0, sl = 0; 757 | block_header_t* block = 0; 758 | 759 | if (size) 760 | { 761 | mapping_search(size, &fl, &sl); 762 | 763 | /* 764 | ** mapping_search can futz with the size, so for excessively large sizes it can sometimes wind up 765 | ** with indices that are off the end of the block array. 766 | ** So, we protect against that here, since this is the only callsite of mapping_search. 767 | ** Note that we don't need to check sl, since it comes from a modulo operation that guarantees it's always in range. 768 | */ 769 | if (fl < FL_INDEX_COUNT) 770 | { 771 | block = search_suitable_block(control, &fl, &sl); 772 | } 773 | } 774 | 775 | if (block) 776 | { 777 | tlsf_assert(block_size(block) >= size); 778 | remove_free_block(control, block, fl, sl); 779 | } 780 | 781 | return block; 782 | } 783 | 784 | static void* block_prepare_used(control_t* control, block_header_t* block, size_t size) 785 | { 786 | void* p = 0; 787 | if (block) 788 | { 789 | tlsf_assert(size && "size must be non-zero"); 790 | block_trim_free(control, block, size); 791 | block_mark_as_used(block); 792 | p = block_to_ptr(block); 793 | } 794 | return p; 795 | } 796 | 797 | /* Clear structure and point all empty lists at the null block. */ 798 | static void control_construct(control_t* control) 799 | { 800 | int i, j; 801 | 802 | control->block_null.next_free = &control->block_null; 803 | control->block_null.prev_free = &control->block_null; 804 | 805 | control->fl_bitmap = 0; 806 | for (i = 0; i < FL_INDEX_COUNT; ++i) 807 | { 808 | control->sl_bitmap[i] = 0; 809 | for (j = 0; j < SL_INDEX_COUNT; ++j) 810 | { 811 | control->blocks[i][j] = &control->block_null; 812 | } 813 | } 814 | } 815 | 816 | /* 817 | ** Debugging utilities. 818 | */ 819 | 820 | typedef struct integrity_t 821 | { 822 | int prev_status; 823 | int status; 824 | } integrity_t; 825 | 826 | #define tlsf_insist(x) { tlsf_assert(x); if (!(x)) { status--; } } 827 | 828 | static void integrity_walker(void* ptr, size_t size, int used, void* user) 829 | { 830 | block_header_t* block = block_from_ptr(ptr); 831 | integrity_t* integ = tlsf_cast(integrity_t*, user); 832 | const int this_prev_status = block_is_prev_free(block) ? 1 : 0; 833 | const int this_status = block_is_free(block) ? 1 : 0; 834 | const size_t this_block_size = block_size(block); 835 | 836 | int status = 0; 837 | (void)used; 838 | tlsf_insist(integ->prev_status == this_prev_status && "prev status incorrect"); 839 | tlsf_insist(size == this_block_size && "block size incorrect"); 840 | 841 | integ->prev_status = this_status; 842 | integ->status += status; 843 | } 844 | 845 | int tlsf_check(tlsf_t tlsf) 846 | { 847 | int i, j; 848 | 849 | control_t* control = tlsf_cast(control_t*, tlsf); 850 | int status = 0; 851 | 852 | /* Check that the free lists and bitmaps are accurate. */ 853 | for (i = 0; i < FL_INDEX_COUNT; ++i) 854 | { 855 | for (j = 0; j < SL_INDEX_COUNT; ++j) 856 | { 857 | const int fl_map = control->fl_bitmap & (1U << i); 858 | const int sl_list = control->sl_bitmap[i]; 859 | const int sl_map = sl_list & (1U << j); 860 | const block_header_t* block = control->blocks[i][j]; 861 | 862 | /* Check that first- and second-level lists agree. */ 863 | if (!fl_map) 864 | { 865 | tlsf_insist(!sl_map && "second-level map must be null"); 866 | } 867 | 868 | if (!sl_map) 869 | { 870 | tlsf_insist(block == &control->block_null && "block list must be null"); 871 | continue; 872 | } 873 | 874 | /* Check that there is at least one free block. */ 875 | tlsf_insist(sl_list && "no free blocks in second-level map"); 876 | tlsf_insist(block != &control->block_null && "block should not be null"); 877 | 878 | while (block != &control->block_null) 879 | { 880 | int fli, sli; 881 | tlsf_insist(block_is_free(block) && "block should be free"); 882 | tlsf_insist(!block_is_prev_free(block) && "blocks should have coalesced"); 883 | tlsf_insist(!block_is_free(block_next(block)) && "blocks should have coalesced"); 884 | tlsf_insist(block_is_prev_free(block_next(block)) && "block should be free"); 885 | tlsf_insist(block_size(block) >= block_size_min && "block not minimum size"); 886 | 887 | mapping_insert(block_size(block), &fli, &sli); 888 | tlsf_insist(fli == i && sli == j && "block size indexed in wrong list"); 889 | block = block->next_free; 890 | } 891 | } 892 | } 893 | 894 | return status; 895 | } 896 | 897 | #undef tlsf_insist 898 | 899 | static void default_walker(void* ptr, size_t size, int used, void* user) 900 | { 901 | (void)user; 902 | printf("\t%p %s size: %x (%p)\n", ptr, used ? "used" : "free", (unsigned int)size, block_from_ptr(ptr)); 903 | } 904 | 905 | void tlsf_walk_pool(pool_t pool, tlsf_walker walker, void* user) 906 | { 907 | tlsf_walker pool_walker = walker ? walker : default_walker; 908 | block_header_t* block = 909 | offset_to_block(pool, -(int)block_header_overhead); 910 | 911 | while (block && !block_is_last(block)) 912 | { 913 | pool_walker( 914 | block_to_ptr(block), 915 | block_size(block), 916 | !block_is_free(block), 917 | user); 918 | block = block_next(block); 919 | } 920 | } 921 | 922 | size_t tlsf_block_size(void* ptr) 923 | { 924 | size_t size = 0; 925 | if (ptr) 926 | { 927 | const block_header_t* block = block_from_ptr(ptr); 928 | size = block_size(block); 929 | } 930 | return size; 931 | } 932 | 933 | int tlsf_check_pool(pool_t pool) 934 | { 935 | /* Check that the blocks are physically correct. */ 936 | integrity_t integ = { 0, 0 }; 937 | tlsf_walk_pool(pool, integrity_walker, &integ); 938 | 939 | return integ.status; 940 | } 941 | 942 | /* 943 | ** Size of the TLSF structures in a given memory block passed to 944 | ** tlsf_create, equal to the size of a control_t 945 | */ 946 | size_t tlsf_size(void) 947 | { 948 | return sizeof(control_t); 949 | } 950 | 951 | size_t tlsf_align_size(void) 952 | { 953 | return ALIGN_SIZE; 954 | } 955 | 956 | size_t tlsf_block_size_min(void) 957 | { 958 | return block_size_min; 959 | } 960 | 961 | size_t tlsf_block_size_max(void) 962 | { 963 | return block_size_max; 964 | } 965 | 966 | /* 967 | ** Overhead of the TLSF structures in a given memory block passed to 968 | ** tlsf_add_pool, equal to the overhead of a free block and the 969 | ** sentinel block. 970 | */ 971 | size_t tlsf_pool_overhead(void) 972 | { 973 | return 2 * block_header_overhead; 974 | } 975 | 976 | size_t tlsf_alloc_overhead(void) 977 | { 978 | return block_header_overhead; 979 | } 980 | 981 | pool_t tlsf_add_pool(tlsf_t tlsf, void* mem, size_t bytes) 982 | { 983 | block_header_t* block; 984 | block_header_t* next; 985 | 986 | const size_t pool_overhead = tlsf_pool_overhead(); 987 | const size_t pool_bytes = align_down(bytes - pool_overhead, ALIGN_SIZE); 988 | 989 | if (((ptrdiff_t)mem % ALIGN_SIZE) != 0) 990 | { 991 | printf("tlsf_add_pool: Memory must be aligned by %u bytes.\n", 992 | (unsigned int)ALIGN_SIZE); 993 | return 0; 994 | } 995 | 996 | if (pool_bytes < block_size_min || pool_bytes > block_size_max) 997 | { 998 | #if defined (TLSF_64BIT) 999 | printf("tlsf_add_pool: Memory size must be between 0x%x and 0x%x00 bytes.\n", 1000 | (unsigned int)(pool_overhead + block_size_min), 1001 | (unsigned int)((pool_overhead + block_size_max) / 256)); 1002 | #else 1003 | printf("tlsf_add_pool: Memory size must be between %u and %u bytes.\n", 1004 | (unsigned int)(pool_overhead + block_size_min), 1005 | (unsigned int)(pool_overhead + block_size_max)); 1006 | #endif 1007 | return 0; 1008 | } 1009 | 1010 | /* 1011 | ** Create the main free block. Offset the start of the block slightly 1012 | ** so that the prev_phys_block field falls outside of the pool - 1013 | ** it will never be used. 1014 | */ 1015 | block = offset_to_block(mem, -(tlsfptr_t)block_header_overhead); 1016 | block_set_size(block, pool_bytes); 1017 | block_set_free(block); 1018 | block_set_prev_used(block); 1019 | block_insert(tlsf_cast(control_t*, tlsf), block); 1020 | 1021 | /* Split the block to create a zero-size sentinel block. */ 1022 | next = block_link_next(block); 1023 | block_set_size(next, 0); 1024 | block_set_used(next); 1025 | block_set_prev_free(next); 1026 | 1027 | return mem; 1028 | } 1029 | 1030 | void tlsf_remove_pool(tlsf_t tlsf, pool_t pool) 1031 | { 1032 | control_t* control = tlsf_cast(control_t*, tlsf); 1033 | block_header_t* block = offset_to_block(pool, -(int)block_header_overhead); 1034 | 1035 | int fl = 0, sl = 0; 1036 | 1037 | tlsf_assert(block_is_free(block) && "block should be free"); 1038 | tlsf_assert(!block_is_free(block_next(block)) && "next block should not be free"); 1039 | tlsf_assert(block_size(block_next(block)) == 0 && "next block size should be zero"); 1040 | 1041 | mapping_insert(block_size(block), &fl, &sl); 1042 | remove_free_block(control, block, fl, sl); 1043 | } 1044 | 1045 | /* 1046 | ** TLSF main interface. 1047 | */ 1048 | 1049 | #if _DEBUG 1050 | int test_ffs_fls() 1051 | { 1052 | /* Verify ffs/fls work properly. */ 1053 | int rv = 0; 1054 | rv += (tlsf_ffs(0) == -1) ? 0 : 0x1; 1055 | rv += (tlsf_fls(0) == -1) ? 0 : 0x2; 1056 | rv += (tlsf_ffs(1) == 0) ? 0 : 0x4; 1057 | rv += (tlsf_fls(1) == 0) ? 0 : 0x8; 1058 | rv += (tlsf_ffs(0x80000000) == 31) ? 0 : 0x10; 1059 | rv += (tlsf_ffs(0x80008000) == 15) ? 0 : 0x20; 1060 | rv += (tlsf_fls(0x80000008) == 31) ? 0 : 0x40; 1061 | rv += (tlsf_fls(0x7FFFFFFF) == 30) ? 0 : 0x80; 1062 | 1063 | #if defined (TLSF_64BIT) 1064 | rv += (tlsf_fls_sizet(0x80000000) == 31) ? 0 : 0x100; 1065 | rv += (tlsf_fls_sizet(0x100000000) == 32) ? 0 : 0x200; 1066 | rv += (tlsf_fls_sizet(0xffffffffffffffff) == 63) ? 0 : 0x400; 1067 | #endif 1068 | 1069 | if (rv) 1070 | { 1071 | printf("test_ffs_fls: %x ffs/fls tests failed.\n", rv); 1072 | } 1073 | return rv; 1074 | } 1075 | #endif 1076 | 1077 | tlsf_t tlsf_create(void* mem) 1078 | { 1079 | #if _DEBUG 1080 | if (test_ffs_fls()) 1081 | { 1082 | return 0; 1083 | } 1084 | #endif 1085 | 1086 | if (((tlsfptr_t)mem % ALIGN_SIZE) != 0) 1087 | { 1088 | printf("tlsf_create: Memory must be aligned to %u bytes.\n", 1089 | (unsigned int)ALIGN_SIZE); 1090 | return 0; 1091 | } 1092 | 1093 | control_construct(tlsf_cast(control_t*, mem)); 1094 | 1095 | return tlsf_cast(tlsf_t, mem); 1096 | } 1097 | 1098 | tlsf_t tlsf_create_with_pool(void* mem, size_t bytes) 1099 | { 1100 | tlsf_t tlsf = tlsf_create(mem); 1101 | tlsf_add_pool(tlsf, (char*)mem + tlsf_size(), bytes - tlsf_size()); 1102 | return tlsf; 1103 | } 1104 | 1105 | void tlsf_destroy(tlsf_t tlsf) 1106 | { 1107 | /* Nothing to do. */ 1108 | (void)tlsf; 1109 | } 1110 | 1111 | pool_t tlsf_get_pool(tlsf_t tlsf) 1112 | { 1113 | return tlsf_cast(pool_t, (char*)tlsf + tlsf_size()); 1114 | } 1115 | 1116 | void* tlsf_malloc(tlsf_t tlsf, size_t size) 1117 | { 1118 | control_t* control = tlsf_cast(control_t*, tlsf); 1119 | const size_t adjust = adjust_request_size(size, ALIGN_SIZE); 1120 | block_header_t* block = block_locate_free(control, adjust); 1121 | return block_prepare_used(control, block, adjust); 1122 | } 1123 | 1124 | void* tlsf_memalign(tlsf_t tlsf, size_t align, size_t size) 1125 | { 1126 | control_t* control = tlsf_cast(control_t*, tlsf); 1127 | const size_t adjust = adjust_request_size(size, ALIGN_SIZE); 1128 | 1129 | /* 1130 | ** We must allocate an additional minimum block size bytes so that if 1131 | ** our free block will leave an alignment gap which is smaller, we can 1132 | ** trim a leading free block and release it back to the pool. We must 1133 | ** do this because the previous physical block is in use, therefore 1134 | ** the prev_phys_block field is not valid, and we can't simply adjust 1135 | ** the size of that block. 1136 | */ 1137 | const size_t gap_minimum = sizeof(block_header_t); 1138 | const size_t size_with_gap = adjust_request_size(adjust + align + gap_minimum, align); 1139 | 1140 | /* 1141 | ** If alignment is less than or equals base alignment, we're done. 1142 | ** If we requested 0 bytes, return null, as tlsf_malloc(0) does. 1143 | */ 1144 | const size_t aligned_size = (adjust && align > ALIGN_SIZE) ? size_with_gap : adjust; 1145 | 1146 | block_header_t* block = block_locate_free(control, aligned_size); 1147 | 1148 | /* This can't be a static assert. */ 1149 | tlsf_assert(sizeof(block_header_t) == block_size_min + block_header_overhead); 1150 | 1151 | if (block) 1152 | { 1153 | void* ptr = block_to_ptr(block); 1154 | void* aligned = align_ptr(ptr, align); 1155 | size_t gap = tlsf_cast(size_t, 1156 | tlsf_cast(tlsfptr_t, aligned) - tlsf_cast(tlsfptr_t, ptr)); 1157 | 1158 | /* If gap size is too small, offset to next aligned boundary. */ 1159 | if (gap && gap < gap_minimum) 1160 | { 1161 | const size_t gap_remain = gap_minimum - gap; 1162 | const size_t offset = tlsf_max(gap_remain, align); 1163 | const void* next_aligned = tlsf_cast(void*, 1164 | tlsf_cast(tlsfptr_t, aligned) + offset); 1165 | 1166 | aligned = align_ptr(next_aligned, align); 1167 | gap = tlsf_cast(size_t, 1168 | tlsf_cast(tlsfptr_t, aligned) - tlsf_cast(tlsfptr_t, ptr)); 1169 | } 1170 | 1171 | if (gap) 1172 | { 1173 | tlsf_assert(gap >= gap_minimum && "gap size too small"); 1174 | block = block_trim_free_leading(control, block, gap); 1175 | } 1176 | } 1177 | 1178 | return block_prepare_used(control, block, adjust); 1179 | } 1180 | 1181 | void tlsf_free(tlsf_t tlsf, void* ptr) 1182 | { 1183 | /* Don't attempt to free a NULL pointer. */ 1184 | if (ptr) 1185 | { 1186 | control_t* control = tlsf_cast(control_t*, tlsf); 1187 | block_header_t* block = block_from_ptr(ptr); 1188 | tlsf_assert(!block_is_free(block) && "block already marked as free"); 1189 | block_mark_as_free(block); 1190 | block = block_merge_prev(control, block); 1191 | block = block_merge_next(control, block); 1192 | block_insert(control, block); 1193 | } 1194 | } 1195 | 1196 | /* 1197 | ** The TLSF block information provides us with enough information to 1198 | ** provide a reasonably intelligent implementation of realloc, growing or 1199 | ** shrinking the currently allocated block as required. 1200 | ** 1201 | ** This routine handles the somewhat esoteric edge cases of realloc: 1202 | ** - a non-zero size with a null pointer will behave like malloc 1203 | ** - a zero size with a non-null pointer will behave like free 1204 | ** - a request that cannot be satisfied will leave the original buffer 1205 | ** untouched 1206 | ** - an extended buffer size will leave the newly-allocated area with 1207 | ** contents undefined 1208 | */ 1209 | void* tlsf_realloc(tlsf_t tlsf, void* ptr, size_t size) 1210 | { 1211 | control_t* control = tlsf_cast(control_t*, tlsf); 1212 | void* p = 0; 1213 | 1214 | /* Zero-size requests are treated as free. */ 1215 | if (ptr && size == 0) 1216 | { 1217 | tlsf_free(tlsf, ptr); 1218 | } 1219 | /* Requests with NULL pointers are treated as malloc. */ 1220 | else if (!ptr) 1221 | { 1222 | p = tlsf_malloc(tlsf, size); 1223 | } 1224 | else 1225 | { 1226 | block_header_t* block = block_from_ptr(ptr); 1227 | block_header_t* next = block_next(block); 1228 | 1229 | const size_t cursize = block_size(block); 1230 | const size_t combined = cursize + block_size(next) + block_header_overhead; 1231 | const size_t adjust = adjust_request_size(size, ALIGN_SIZE); 1232 | 1233 | tlsf_assert(!block_is_free(block) && "block already marked as free"); 1234 | 1235 | /* 1236 | ** If the next block is used, or when combined with the current 1237 | ** block, does not offer enough space, we must reallocate and copy. 1238 | */ 1239 | if (adjust > cursize && (!block_is_free(next) || adjust > combined)) 1240 | { 1241 | p = tlsf_malloc(tlsf, size); 1242 | if (p) 1243 | { 1244 | const size_t minsize = tlsf_min(cursize, size); 1245 | memcpy(p, ptr, minsize); 1246 | tlsf_free(tlsf, ptr); 1247 | } 1248 | } 1249 | else 1250 | { 1251 | /* Do we need to expand to the next block? */ 1252 | if (adjust > cursize) 1253 | { 1254 | block_merge_next(control, block); 1255 | block_mark_as_used(block); 1256 | } 1257 | 1258 | /* Trim the resulting block and return the original pointer. */ 1259 | block_trim_used(control, block, adjust); 1260 | p = ptr; 1261 | } 1262 | } 1263 | 1264 | return p; 1265 | } 1266 | --------------------------------------------------------------------------------